summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlibdlo <libdlo@displaylink.com>2009-05-10 00:03:42 +0000
committerlibdlo <libdlo@displaylink.com>2009-05-10 00:03:42 +0000
commitc7e74685292a2da02d887bdc2491459cf8fef093 (patch)
tree057cbd523ac90af4265a709cc33ae678a504f0c2
Pre-configure test of all source files
-rw-r--r--Guide-v104.pdfbin0 -> 127485 bytes
-rw-r--r--HowToBuild.txt362
-rw-r--r--LICENSE437
-rw-r--r--Makefile.am4
-rw-r--r--README111
-rw-r--r--configure.ac37
-rw-r--r--docs/Doxyfile1243
-rw-r--r--docs/imgs/READ_ME.txt2
-rw-r--r--docs/imgs/libdlo.drawbin0 -> 1276 bytes
-rw-r--r--docs/imgs/libdlo.gifbin0 -> 13673 bytes
-rw-r--r--include/dlo_base.h57
-rw-r--r--include/dlo_data.h707
-rw-r--r--include/dlo_defs.h158
-rw-r--r--include/dlo_grfx.h93
-rw-r--r--include/dlo_mode.h127
-rw-r--r--include/dlo_structs.h92
-rw-r--r--include/dlo_usb.h134
-rw-r--r--include/libdlo.h766
-rw-r--r--src/Makefile.am36
-rw-r--r--src/dlo_grfx.c835
-rw-r--r--src/dlo_mode.c926
-rw-r--r--src/dlo_usb.c528
-rw-r--r--src/libdlo.c902
-rw-r--r--test/Makefile.am1
-rw-r--r--test/test1/Makefile.am1
-rw-r--r--test/test1/images/test08.bmpbin0 -> 8078 bytes
-rw-r--r--test/test1/images/test16.bmpbin0 -> 14054 bytes
-rw-r--r--test/test1/images/test24.bmpbin0 -> 21054 bytes
-rw-r--r--test/test1/images/test32.bmpbin0 -> 28054 bytes
-rw-r--r--test/test1/src/Makefile.am2
-rw-r--r--test/test1/src/test1.c937
31 files changed, 8498 insertions, 0 deletions
diff --git a/Guide-v104.pdf b/Guide-v104.pdf
new file mode 100644
index 0000000..dfa6f7e
--- /dev/null
+++ b/Guide-v104.pdf
Binary files differ
diff --git a/HowToBuild.txt b/HowToBuild.txt
new file mode 100644
index 0000000..58333ba
--- /dev/null
+++ b/HowToBuild.txt
@@ -0,0 +1,362 @@
+
+Build environment for the DisplayLink Open Source Software (libdlo)
+===================================================================
+
+This short document explains the layout of the libdlo build environment, the
+prerequisites, how to build the main demonstration library (libdlo) and some
+notes about specific issues which may be found on various platforms.
+
+
+LAYOUT
+------
+
+This build structure in intended to function on a wide range of platforms and
+will build for a broad selection of hardware targets. It has been tested on a
+number of host build systems, including but not limited to:
+
+ * Fedora Linux (10)
+ * Debian Linux (4 and 5)
+ * SuSE Linux (9.2)
+ * Ubuntu Linux (8.04 and 8.10)
+ * CentOS Linux (5.2)
+ * Mac OS X (Leopard)
+
+The build structure can include builds for multiple platforms
+simultaneously. It does this by separating the source code from any
+intermediate object code and built binaries. By default, the MACHTYPE
+environment variable is used as the name of the target platform but this can
+easily be overridden.
+
+When a component, such as libdlo is built, a directory structure is created
+within that component which will contain lists of dependencies, objects and
+binaries, e.g.
+
+ lib/libdlo/build/i686-suse-linux/
+
+Note: one exception to the above is the third-party libraries such as libusb
+which do not normally support this method of building (they simply lump all
+source and binaries into the same directory). These need to be cleaned
+between each build for a new target.
+
+The root level of the build structure contains the following files and
+directories:
+
+ docs - contains general libdlo build information
+ fixperms.sh - script to fix up permissions of files in the build
+ lib - contains all of the libraries and sources
+ Makefile - the main build Makefile
+ makefiles - a collection of submakefiles
+ mkall.sh - script which builds all of the libdlo components
+ mkclean.sh - script which cleans all of the libdlo components
+ test - contains libdlo test programs and their source
+
+The lib directory contains the source code to libdlo itself and any
+associated third party libraries which it uses, currently only libusb. The
+third party libraries are included unmodified from their public released
+version - as such, they do not necessarily conform to the conventions of the
+libdlo build as a whole.
+
+The main Makefile includes a list of the libraries which comprise the libdlo
+build structure, along with their locations in the build. It also includes a
+list of test programs and their locations. If you add a new library or test
+program, this file should be updated.
+
+Note: if you add a library to the build, you will also need to modify the
+submakefile:
+
+ makefiles/common.mk
+
+to tell the build where to find the library binary (the .a file) when that
+component has built as well as adding the library directory to the global
+include path (INCLUDES) within that file.
+
+A libdlo component, such as libdlo or a test program, is structured as
+follows:
+
+ Makefile - the submakefile for that component
+ mkclean.sh - script to clean the component
+ mklib.sh or mktest.sh - script to build the component
+ build - directory of binaries created by build process
+ include - option directory containing header files
+ src - source directory structure (may include nested subdirs)
+
+The src directory (and any nested subdirectories) must contain a submakefile
+called:
+
+ module.mk
+
+which simply includes a list of the source files in that directory. This
+allows other files to be placed in there which will not be included in the
+build (such as documentation, or anything else).
+
+For more information, simply take a look at the files and components
+themselves; they have comments throughout.
+
+
+PRE-REQUISITES
+--------------
+
+This build system is primarily aimed at flavours of Linux and UNIX. However,
+it should be reasonably straight-forward to adapt it to function on any
+platform which supports the GCC toolchain.
+
+It makes heavy use of some advanced features of GNU Make so may require a
+little more work to port it to a platform which does not support the GCC
+toolchain, but that should still be possible.
+
+The libdlo sources are self-documenting. You can use the Doxygen tool to
+generate or update this set of documentation by running the
+lib/libdlo/mkdox.sh script.
+
+Finally, the libdlo assumes the presence of some fairly standard command line
+tools and commands such as:
+
+ * echo
+ * mkdir
+ * rm
+ * sed
+
+although these can be modified to use equivalent commands/tools on other
+platforms.
+
+
+PACKAGES
+--------
+
+The following operating systems have been tested with the libdlo build and these
+packages have been identified as being required (those marked with a * are
+the minimal packages with others that should be pulled in as dependencies).
+
+Ubuntu 8.10 requires the following additional packages to be installed:
+
+* g++
+ g++-4.3
+ libstdc++6-4.3-dev
+
+Debian 5 requires the following additional packages to be installed:
+
+* make 3.81-5
+* gcc
+ binutils
+ gcc-4.3
+ libc6-dev
+ libgomp1
+ linux-libc-dev
+* g++
+ g++-4.3
+ libstdc++6-4.3-dev
+
+Fedora 10 requires the following additional packages to be installed:
+
+* gcc-4.3.2-7
+ binutils-2.18.50.0.9-8
+ glibc-devel-2.9-3
+ glibc-headers-2.9-3
+ kernel-headers-2.6.27.19-170.2.35.fc10
+ libgomp-4.3.2-7
+* gcc-c++-4.3.2-7
+ libstdc++-devel-4.3.2-7
+
+CentOS 5.2 requires the following additional packages to be installed:
+
+* gcc 4.1.2-42.el5
+ glibc-devel 2.5-24.el5_2.2
+ glibc-headers 2.5.24.el5_2.2
+ kernel-headers 2.6.18-92.1.22.el5
+ libgomp 4.1.2-42.el5
+* gcc-c++ 4.1.2-42.el5
+ libstdc++-devel 4.1.2-42.el5
+
+openSuSE 11.1 requires the following additional packages to be installed:
+
+* gcc
+ gcc43
+ glibc-devel
+ linux-kernel-headers
+* gcc-c++
+ gcc43-c++
+ libstdc++43-devel
+
+
+HOW TO BUILD
+------------
+
+In addition to the package information given above, an example of what you
+need to do in order to get a build environment up and running is outlined
+below. This is for an Ubuntu 8.04 distribution but other flavours of Linux
+should work in a similar way:
+
+ * Install GCC using the package manager - you can use the command line or
+ the Synaptic Package Manager which comes with Ubuntu - search for 'gcc'
+ and install it along with any dependencies.
+
+ * Install the 'build-essential' package
+
+ * Install the 'doxygen' package - used only to generate documentation
+
+ * Install the 'graphviz' package - used by Doxygen to generate images
+
+The libdlo can be installed somewhere (e.g. in your home directory) in a way
+which does not modify its internal directory structure. Then follow the
+instructions below to do a build.
+
+Once the build structure is installed into your chosen location and you are
+happy that your GGC installation also works (try "gcc --version" on the
+command line), you should ensure that the build structure extracted from its
+archive with the correct permissions. To assist with this, there is a script
+in the root of the build which should be run:
+
+ # ./fixperms.sh
+
+You should only need to run this once. If it's not executable for some
+reason, you will need to make it so with:
+
+ # chmod u+x fixperms.sh
+
+Next, you need to create a small submakefile for the target platform that you
+are building for. Normally, this will be the same as the build machine while
+you are setting up the build process. If you look inside:
+
+ makefiles/target/
+
+you will find a selection of submakefiles which have already been created.
+You need to ensure that there is one which matches your machine type. Type:
+
+ # echo $MACHTYPE
+
+to find out what this is. If you don't have this environment variable set up,
+just pick a name that seems about right (this can be one of the ones already
+used), e.g.
+
+ i386-redhat-linux-gnu
+ i486-pc-linux-gnu
+ i586-suse-linux
+ i686-suse-linux
+
+then copy an existing submakefile using your MACHTYPE, e.g.
+
+ # cd makefiles/target
+ # cp i686-suse-linux.mk $MACHTYPE.mk
+ # cd ../..
+
+or if don't have a MACHTYPE environment variable and you've opted to use one
+of the pre-existing ones, you need to edit the file:
+
+ mkall.sh
+
+to have a hard-wired MACHTYPE rather than getting from the environment
+variable.
+
+Note: to build a debug version or some other libdlo build variant, you can put
+compilation flags into the target makefile, such as:
+
+ CFLAGS += -DDEBUG
+
+Now you should be ready to start the build process. It is a good idea to
+clean the build first:
+
+ # ./mkclean.sh
+
+Then start a build:
+
+ # ./mkall.sh
+
+This will automatically configure and build all of the libdlo components before
+linking them together into the libdlo library binary.
+
+ # ls -l lib/libdlo/build/*/libdlo.a
+
+
+SPECIFIC ISSUES
+---------------
+
+Some operating systems and build environments may throw up specific build
+problems which are due to the multitude of minor differences that can exist
+between systems. Below are a couple of examples of problems which might be
+experienced:
+
+Issue:
+
+ Running a program with libdlo on Linux returns an error such as
+
+ "Error 19 'error sending control message: Operation not permitted'"
+
+Detail:
+
+ Because of the way libdlo interacts with the USB stack, the executable
+ must be run with root privaliges.
+
+Resolution:
+
+ Run the executable as root (or via sudo).
+
+
+Issue:
+
+ libusb fails to build with libtool errors.
+
+Detail:
+
+ One user was finding issues building the libusb part of the libdlo package on
+ Fedora Linux, using libtool version 1.5.16. The error messages included
+ lines stating:
+
+ libtool: compile: unable to infer tagged configuration
+ libtool: compile: specify a tag with '--tag'
+
+Reolution:
+
+ Modify the libusb Makefile definition of LIBTOOL to include:
+
+ --tag=CC
+
+ at the end of the line.
+
+
+Issue:
+
+ test1 fails to link on Mac OS.
+
+Detail:
+
+ The build of the test program fails at the link stage with lots of errors
+ of the form:
+
+ "_IOServiceMatching", referenced from:
+ _usb_setup_iterator in libusb.a(darwin.o)
+
+ culminating with the message:
+
+ ld: symbol(s) not found
+
+Reolution:
+
+ This is due to Mac OS using a slightly unusual style of OS headers and
+ libraries, called Frameworks, which are not included in the linker flags in
+ a normal UNIX/Linux build.
+
+ The work-around is to modify the line in makefiles/exe.mk from:
+
+ @$(LINK.c) -o $@ $^
+
+ to something along the lines of:
+
+ $(LINK.c) -Wl,-framework -Wl,CoreFoundation -Wl,-framework -Wl,IOKit -o $@ $^
+
+--
+DisplayLink Open Source Software (libdlo)
+Copyright (C) 2009, DisplayLink
+www.displaylink.com
+
+This library is free software; you can redistribute it and/or modify it under
+the terms of the GNU Library General Public License as published by the Free
+Software Foundation; LGPL version 2, dated June 1991.
+
+This library 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 Library General Public License for more
+details.
+
+You should have received a copy of the GNU Library General Public License
+along with this library; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..e29ffae
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,437 @@
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..4de2bae
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,4 @@
+SUBDIRS=src \
+ test \
+ docs
+dist_doc_DATA = README \ No newline at end of file
diff --git a/README b/README
new file mode 100644
index 0000000..6dd89ae
--- /dev/null
+++ b/README
@@ -0,0 +1,111 @@
+
+libdlo Quick Start Guide
+========================
+
+Introduction
+------------
+
+This guide will help you to get started with the basics of building and
+testing the libdlo software as quickly as possible. Because it skips over
+various details, you may find the odd issue. In that case, you are directed
+to read the more comprehensive instructions in the docs/HowToBuild.txt file.
+
+We will assume that you have unpacked the libdlo sources into your user's home
+directory within an 'dlo' subdirectory (e.g. '~/dlo' or '/home/<user>/dlo').
+This document is therefor ~/dlo/QuickStart.txt.
+
+
+Before you build
+----------------
+
+Before you start building the libdlo, you will need the sources for libusb:
+
+* Install the libusb sources from http://libusb.wiki.sourceforge.net/ into
+ ~/dlo/lib/libusb/ - this software is Open Source (LGPL or BSD licensed)
+
+This should leave you with all of the libusb source files in ~/dlo/lib/libusb
+so that you have files such as ~/dlo/lib/libusb/Makefile (and lots of
+others!). The main build process assumes this location for the sources so
+will fail if they are not there.
+
+
+Building everything
+-------------------
+
+To start the build process from a shell prompt (as the user who's home
+directory the libdlo is installed into):
+
+ $ cd ~/dlo
+ $ make clean
+ $ make all
+
+This will ensure the build environment is cleaned and then build the
+following:
+
+* The libusb library for static linking
+
+* The libdlo (libdlo) library for static linking
+
+* A test program (test1) - statically linked to both libusb and libdlo
+
+Note: sometimes (when rebuilding things) there will be errors from the
+building of one component (e.g. libdlo), perhaps because of a mistake when
+editing a source file, but the build may appear to complete - because the old
+libdlo.a library file was still lying around. In this case, your test
+program will appear not to include the edits you just made.
+
+To avoid this, check carefully through the output of the build process or
+make sure you do each build from clean.
+
+
+Testing the built components
+----------------------------
+
+If the build completed without errors, you should find that the test1
+binary file has been created as ~/dlo/test/test1/build/*/test1. In order
+to do anything useful with this, you will need to plug in a DisplayLink
+device, then:
+
+ $ cd ~/dlo/test/test1 <- test1 assumes location of resources so you
+ MUST cd to this location for it to work!!
+ $ sudo ./build/*/test1 <- because libusb needs to talk to the usb device,
+ you MUST run the test program as root - or do
+ the required chmod magic to the USB device node
+
+If all goes correctly, you should see a series of simple graphical tests
+on the display attached to your DislpayLink device.
+
+
+Building the Doxygen documentation
+----------------------------------
+
+The libdlo library sources are comprehensively documented using the Doxygen
+tool (which you will need to install, along with its dependencies). To build
+this documentation, do the following:
+
+ $ cd ~/dlo/lib/libdlo/doxygen
+
+and the resulting documents will be (re)built, with the index page being:
+
+ ~/dlo/lib/libdlo/docs/html/index.html
+
+
+Common problems
+---------------
+
+A more comprehensive treatment can be found in the docs/HowToBuild.txt file
+but an overview of common problems is given here:
+
+* You haven't got the right build packages installed on your system
+
+* You forgot to install the libusb sources
+
+* Your parent environment doesn't export the MACHTYPE variable
+
+* There is no ~/dlo/makefiles/target makefile for your MACHTYPE
+
+* You didn't cd into the test/test1 directory to run the test harness
+
+* You didn't run the test harness as root
+
+* The DisplayLink device is not assigned to your development VM correctly
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..d5cd6f2
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,37 @@
+# -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ([2.63])
+AC_INIT([libdlo], [1.0.0], [libdlo@displaylink.com])
+AC_CONFIG_SRCDIR([src/dlo_grfx.c])
+AC_CONFIG_HEADERS([config.h])
+
+# Checks for programs.
+AC_PROG_CC
+
+# Checks for libraries.
+
+# Checks for header files.
+AC_CHECK_HEADERS([stdint.h stdlib.h string.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_HEADER_STDBOOL
+AC_C_INLINE
+AC_TYPE_INT32_T
+AC_TYPE_SIZE_T
+AC_TYPE_UINT16_T
+AC_TYPE_UINT32_T
+AC_TYPE_UINT64_T
+AC_TYPE_UINT8_T
+
+# Checks for library functions.
+AC_FUNC_MALLOC
+AC_FUNC_REALLOC
+AC_CHECK_FUNCS([gettimeofday strchr])
+
+AC_CONFIG_FILES([Makefile
+ src/Makefile
+ test/Makefile
+ test/test1/Makefile
+ test/test1/src/Makefile])
+AC_OUTPUT
diff --git a/docs/Doxyfile b/docs/Doxyfile
new file mode 100644
index 0000000..04671a7
--- /dev/null
+++ b/docs/Doxyfile
@@ -0,0 +1,1243 @@
+# Doxyfile 1.5.1
+#
+# DisplayLink Open Source Software (libdlo)
+# Copyright (C) 2009, DisplayLink
+# www.displaylink.com
+#
+# This library is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Library General Public License as published by the Free
+# Software Foundation; LGPL version 2, dated June 1991.
+#
+# This library 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 Library General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Library General Public License
+# along with this library; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = "DisplayLink Open Source Software (libdlo)"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = docs
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian,
+# Italian, Japanese, Japanese-en (Japanese with English messages), Korean,
+# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian,
+# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to
+# include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from the
+# version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = src include
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py
+
+FILE_PATTERNS =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH = imgs/
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code. Otherwise they will link to the documentstion.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = YES
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a call dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+
+CALL_GRAPH = YES
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a caller dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+
+CALLER_GRAPH = YES
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that a graph may be further truncated if the graph's
+# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH
+# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default),
+# the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, which results in a white background.
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
diff --git a/docs/imgs/READ_ME.txt b/docs/imgs/READ_ME.txt
new file mode 100644
index 0000000..be24f67
--- /dev/null
+++ b/docs/imgs/READ_ME.txt
@@ -0,0 +1,2 @@
+The source file for the GIF image is libdlo.draw, which is RISC OS drawfile
+format. See www.riscosopen.org.
diff --git a/docs/imgs/libdlo.draw b/docs/imgs/libdlo.draw
new file mode 100644
index 0000000..b6a0d13
--- /dev/null
+++ b/docs/imgs/libdlo.draw
Binary files differ
diff --git a/docs/imgs/libdlo.gif b/docs/imgs/libdlo.gif
new file mode 100644
index 0000000..352d02d
--- /dev/null
+++ b/docs/imgs/libdlo.gif
Binary files differ
diff --git a/include/dlo_base.h b/include/dlo_base.h
new file mode 100644
index 0000000..3ce2ba4
--- /dev/null
+++ b/include/dlo_base.h
@@ -0,0 +1,57 @@
+/** @file dlo_base.h
+ *
+ * @brief Global header file for the core functions of libdlo.
+ *
+ * This file defines anything which is not a part of the API that libdlo publishes
+ * up to software using the library (in libdlo.h). It is intended that any functions,
+ * variables and structures defined herein are only for internal use by the libdlo
+ * sources.
+ *
+ * DisplayLink Open Source Software (libdlo)
+ * Copyright (C) 2009, DisplayLink
+ * www.displaylink.com
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by the Free
+ * Software Foundation; LGPL version 2, dated June 1991.
+ *
+ * This library 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 Library General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef DLO_BASE_H
+#define DLO_BASE_H /**< Avoid multiple inclusion. */
+
+#include "dlo_structs.h"
+
+
+/** Claim and initialise a new device structure.
+ *
+ * @param type Device type.
+ * @param serial Pointer to serial number string for the device (assumed to be unique to each device).
+ *
+ * @return Pointer to new @a dlo_device_t structure or NULL if failed.
+ */
+extern dlo_device_t *dlo_new_device(const dlo_devtype_t type, const char * const serial);
+
+
+/** Given a unique ID for a device, see if we have it in our device list @a dev_list.
+ *
+ * @param serial Pointer to serial number string for the device (assumed to be unique to each device).
+ *
+ * @return Pointer to @a dlo_device_t structure or NULL if not in @a dev_list.
+ *
+ * A side-effect of this call is to update the @a dev->check variable to the current value
+ * of @a check_state so that any devices on @a dev_list which weren't added or looked-up by
+ * the end of an enumeration call can be spotted.
+ */
+extern dlo_device_t *dlo_device_lookup(const char * const serial);
+
+
+#endif
diff --git a/include/dlo_data.h b/include/dlo_data.h
new file mode 100644
index 0000000..dd7fa90
--- /dev/null
+++ b/include/dlo_data.h
@@ -0,0 +1,707 @@
+/** @file dlo_data.h
+ *
+ * @brief Hard-wired screen mode-related data blocks.
+ *
+ * DisplayLink Open Source Software (libdlo)
+ * Copyright (C) 2009, DisplayLink
+ * www.displaylink.com
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by the Free
+ * Software Foundation; LGPL version 2, dated June 1991.
+ *
+ * This library 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 Library General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef DLO_DLODATA_H
+#define DLO_DLODATA_H /**< Avoid multiple inclusion. */
+
+
+/** Screen mode 640x480 (at 60 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_640_480_60_24_0 "" \
+ "\x79\x7C\xAD\x97\xAD\xFE\x4B\xDE\x1A\x2F\xA2\x94\x2C\xD5\xD3\x5C"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_640_480_60_24_0 "" \
+ "\xE5\xDF\xC0\x52\x4F\xE1\xE6\xB4\xE3\xED\xC4\x21\x5E\x56\xC2\x53" \
+ "\x35\x1C\xE8\xF2\xDF\xEF\x7F\x37\xF5\xA5\x4B\x56\xEB\xED\x34\x7B" \
+ "\xFB\x89\xA3\x17\xE4\x69\xFF\x39\xD2\xAE\x09\xB6\xC0\xBE\x4D\xBC" \
+ "\x84\x6D\x99\xDA\x6B\x28\xBD\xE1\x0E\xC2\xDD\xB0\xDB\x63\xAE\x27" \
+ "\x17\x9C\xD6\xD8\xCC\xC5\x44\xFD\x1C\xEF\x49\x9B\xE8\x69\x69\xCA" \
+ "\xA5\x9E\xC5\x6B\xF9\x71\xC1\x1B\x8F\x8C\x41\x6B\xC4\xBE\x2A\x6F" \
+ "\x56\x82\x37\xC8\x83\x92\x27\x20\x08\x62\x76\x24\x41\xEE\x38\x33" \
+ "\x20\x5C\xAA\xA7\x04\x95\xFA\x8F\xE9\xBA\xEE\xD4\x6C\x8F\x82\x42" \
+ "\x4E\x0F\xB3\xFC\x5D\x25\x9D\x33\xB4\x6F\xBF\x54\xB7\xEB\x16\xF3" \
+ "\xE9\x7C"
+
+/** Screen mode 640x480 (at 73 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_640_480_73_24_0 "" \
+ "\xA7\xA6\x78\x54\xA4\xC3\x33\xBF\xF3\xD5\x53\x1F\xAA\x27\x7B\x91"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_640_480_73_24_0 "" \
+ "\x61\x1A\x38\x7B\x68\x45\x20\x90\x34\x5D\x1D\x6C\x9D\xC4\xA6\x0E" \
+ "\xA3\xEA\x7F\xD9\x70\xAD\xE5\x53\xBE\xB4\x0B\xEC\xB5\xE4\xA1\xAC" \
+ "\x5D\x7D\x06\x9A\x97\xE8\x3D\xFC\x7E\x81\x02\x07\xB1\x30\xC1\xAB" \
+ "\x9C\xC3\x08\xEA\x79\xAA\xBD\x8F\xC1\x2B\xAA\x69\xD5\x17\xF3\x60" \
+ "\x3B\x9F\x86\x86\x2C\x88\x02\x3F\x60\xF4\xA9\xFC\xD6\x8D\x41\x2E" \
+ "\xDE\x64\x6F\xA2\x1F\x33\xB2\x76\x95\xF9\x89\xCC\x71\xEC\x00\x5E" \
+ "\xFC\x9F\xC6\x32\xE3\xAB\x8D\xCA\xC6\x3D\xC9\x4E\xD2\xD5\x83\x7B" \
+ "\x2F\x0C\x78\xE7\x3E\xE3\xEE\xD6\xCB\x95\x54\x02\x83\x46\x01\x78" \
+ "\x1B\x33\xF7\x12\x47\x16\x05\xAF\x99\x56\x87\xF9\xFA\x3F\x93\x0C" \
+ "\x79\xA6"
+
+/** Screen mode 640x480 (at 75 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_640_480_75_24_0 "" \
+ "\xBC\xD1\x26\x61\x95\x59\x20\x88\x2E\x73\xA7\xD9\x9A\x22\x6A\xFB"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_640_480_75_24_0 "" \
+ "\xAA\xCE\xFB\xD4\xC3\x07\xC1\xBF\xAD\xA3\xEF\xA9\x2B\x77\xBD\x5D" \
+ "\x03\xBE\x67\xF4\x99\xA1\xA3\x53\x25\x5B\x50\x6D\x0C\x3A\xA7\x4C" \
+ "\xB0\x86\x04\x60\x01\x8C\xED\xBC\x5A\xF9\x3A\x0E\x1B\x10\xFF\x55" \
+ "\x8B\x23\xAC\xDE\xEA\xB2\x2E\x8B\x02\x4E\xF1\x67\x9C\x85\x5D\x3B" \
+ "\xE1\xC1\xAC\x3B\x26\xE2\xC3\x13\x25\xF4\xCC\xBC\xF0\xD9\x1F\x27" \
+ "\x0C\xF0\x42\x6C\x18\x3B\x20\xC6\x29\xD7\x6C\x0A\x4B\xDC\x44\x3C" \
+ "\x46\xDB\x6E\x78\xEB\xAB\x7A\xF5\x63\xE2\xAD\x77\x03\xA0\x9F\xCB" \
+ "\x22\x4D\x03\x66\x0B\xF8\xE7\x26\xA4\x15\xF4\xF9\x13\xE7\x14\x97" \
+ "\xF1\x98\xD0\x8B\x4E\xDB\xA5\xC6\x4E\x74\x19\x2C\xB2\x97\x55\xA4" \
+ "\x0E\x61"
+
+/** Screen mode 640x480 (at 85 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_640_480_85_24_0 "" \
+ "\x6D\x0D\x6A\x02\x66\x8A\x8A\x94\xFD\x31\x6D\x98\x53\xD7\x93\x25"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_640_480_85_24_0 "" \
+ "\xC6\x8C\x42\x4C\x95\xDA\xB4\x2F\xBD\xD9\x9E\x7C\x8F\x7B\x69\xA8" \
+ "\x1B\xDA\x06\x96\x23\x9E\x94\xE2\xC2\xE9\xBB\xD3\x13\x6B\x9B\x21" \
+ "\xC1\x4E\xD8\x3F\x81\x49\x6E\xD1\xAF\xB2\x4E\x8C\x24\x1A\xA8\xB6" \
+ "\x4E\x11\x75\xB3\xE6\xC9\x3D\x36\x9A\xCC\x3B\xAA\x1F\xC4\x97\xD5" \
+ "\x4A\x9D\xAA\xE0\x04\xF0\xB6\x2C\xBD\xE4\x41\x19\xF8\xA2\x77\x7C" \
+ "\x46\x9D\x3A\xBD\x73\xC0\x64\x70\x84\x2B\xD7\x11\xF3\x43\xB5\xFB" \
+ "\xE9\x0B\xB3\x4B\x2B\x80\x98\xEF\xDC\xDA\x46\xD6\xEC\xBD\x0B\x4D" \
+ "\x64\x20\xF7\x17\x17\x33\x75\xB5\x30\x26\xDD\x0A\xA0\x99\x23\x11" \
+ "\xF1\xDE\x80\xB0\xD6\xB0\xB7\x5A\xA9\xBD\x6D\x29\x42\x74\x75\x73" \
+ "\xC5\x27"
+
+/** Screen mode 720x400 (at 70 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_720_400_70_24_0 "" \
+ "\x9C\xC5\x1C\x02\x4F\xA6\x97\x4D\xD7\x04\xE5\x2A\xDC\x78\x4F\x24"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_720_400_70_24_0 "" \
+ "\xC4\x2C\x84\x13\xDD\xB8\x82\xCB\x62\xA3\x40\xFA\x41\x8B\x5E\x1B" \
+ "\x74\x02\x11\xDD\x90\xB8\x14\x51\xE1\x28\x7E\x3B\x42\x6A\x6B\x9C" \
+ "\x7E\x4B\xFC\x8A\x19\x8D\xF4\x23\xB4\x98\x96\x55\x68\x8F\xDA\x88" \
+ "\x9C\xE0\x20\x5D\xB5\x9F\x34\x9B\xB2\xCF\x10\x6B\x2D\x66\x63\x0B" \
+ "\xDE\x3C\xC4\x90\x3C\xB4\x23\xF9\x5C\x93\x6F\x43\x29\x20\x54\x90" \
+ "\x94\xB8\x78\xED\x33\xC7\xDD\x8B\xAA\xD0\xF6\xDC\x78\xEB\x50\x23" \
+ "\x83\x00\x6F\x42\x83\x58\xD7\x1C\xA0\xDF\x41\x9E\x69\xB5\xA4\x3A" \
+ "\x31\x79\xCB\xDF\x59\x5E\x76\xFB\x89\x32\x2B\x00\xE5\xDF\x16\x52" \
+ "\x4F\xE1\xCC\xB7\xE3\xED\xEE\xC1\x5E\x56\xDF\x4E\x35\x1C\x14\x99" \
+ "\xDF\x6F"
+
+/** Screen mode 720x400 (at 85 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_720_400_85_24_0 "" \
+ "\x4E\xEB\x46\x9D\x91\xDD\xEA\x68\xE2\xCF\x92\xBE\x47\xE1\xE2\x7C"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_720_400_85_24_0 "" \
+ "\xE6\x20\x16\xD8\xFE\x44\x88\xBF\x44\x7B\xBE\x98\xA3\xC9\x56\x4E" \
+ "\xBC\x98\x6B\x8B\xCD\x50\xB0\xB8\x4D\x95\x32\xF7\xB8\xDE\x45\x3D" \
+ "\x87\xD4\x13\xBF\x42\xE6\xC5\x86\x4E\x9D\xD7\x11\xD6\x1F\x1E\x11" \
+ "\x55\x5E\xD5\x2E\xFE\x02\xD4\xB0\xDC\x10\xA0\x45\x44\x00\x2E\x0B" \
+ "\x4C\x7B\x47\x1B\x06\x16\x20\x18\x6D\xED\x65\xC9\xC0\x11\xDD\x76" \
+ "\x78\x8E\x2D\x5D\xD7\x5E\xF7\x6E\x17\x75\x14\x74\xA8\x4D\xFC\x6F" \
+ "\x47\x50\x69\x15\x01\x3D\x92\xF5\x1D\xF6\x03\x4A\x89\xC5\x2D\x1E" \
+ "\x3A\xBB\x25\x83\x3A\xFD\x72\xBD\xA2\x96\x61\x84\x45\x5F\x19\x21" \
+ "\xB5\xBC\x3A\xF4\x7E\xFA\xBF\x0A\x5E\x82\xC8\xF6\x26\x4D\xA4\x06" \
+ "\xD9\x97"
+
+/** Screen mode 800x480 (at 60 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_800_480_60_24_0 "" \
+ "\x7A\x12\x36\x0B\xEF\x21\x74\xD1\xF0\x06\x8F\x38\xE8\x71\xB4\xCE"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_800_480_60_24_0 "" \
+ "\x78\x67\x19\xF3\xB3\xD6\x5D\x7B\x4C\xCA\x26\x78\x41\x19\x19\xAC" \
+ "\xFF\x38\xB3\x10\x71\x89\x6A\xEC\xA8\xC1\x4F\x1F\x77\x86\x5D\x7E" \
+ "\xCE\xAF\x65\x7D\xFC\x30\x51\x67\x1F\x48\x30\x8E\x7A\x4B\x8A\xD4" \
+ "\xCB\x62\x45\x58\x5C\x22\x1D\x56\x6E\x2F\x60\xE2\x06\x6D\xA1\xE3" \
+ "\x82\x5F\x67\x95\x7A\x9F\x87\x43\xD8\x33\xEF\x0B\x5A\xDA\x09\x4F" \
+ "\xD7\x25\x6F\xBC\xF8\xC7\x09\x9C\x12\xC3\xA7\x6F\xE7\xED\xA8\x70" \
+ "\x8C\xB9\x65\x53\xDD\xA6\x7D\xDE\xD9\x4F\xDD\xD4\x6F\x28\xD6\x14" \
+ "\xDC\x2D\x41\x53\x33\xD9\x0A\x86\x11\x3C\x41\x5A\x56\x48\xF9\x85" \
+ "\x2B\x2F\x22\x66\x20\x39\xDA\xA1\x50\xCB\x5A\x58\x7D\x97\xFA\x2C" \
+ "\x64\x9D"
+
+/** Screen mode 800x600 (at 56 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_800_600_56_24_0 "" \
+ "\x19\xFC\x59\x09\x1D\xCD\xDA\x0D\xD3\x6A\x45\xBB\xDB\xF9\x8A\x57"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_800_600_56_24_0 "" \
+ "\xD7\x63\xD3\x78\x60\xAC\x0F\xFE\xF5\x0A\xC7\xF0\x17\x0E\x9C\x6C" \
+ "\x47\xFF\xF5\x36\xFD\xDE\x22\xE6\xA1\x80\x4F\x0D\x90\x72\xE6\xAD" \
+ "\x49\x95\x4B\xD4\x6A\x31\xF9\x6E\x6F\x6E\x93\xF5\x44\x46\x7A\x84" \
+ "\xD4\x10\x51\x7A\xE1\xDF\x48\x32\x9D\x0E\x59\xD9\x0B\x57\x45\x7C" \
+ "\x58\xF6\x72\x8D\xAF\x91\x7F\xBE\xE8\x2F\x3A\x7F\x3D\xF5\xD6\x39" \
+ "\x1E\xB8\xB2\x1D\x7F\x6F\x60\xBC\x0F\xF8\xAD\x43\x76\xFA\x75\x19" \
+ "\xFB\x5D\xA4\xCD\xF7\x38\x5F\x11\xD4\x56\x11\x9E\x79\xB4\x4A\x4D" \
+ "\x7A\xC7\x03\xAC\xFB\xB4\x4F\x98\x93\xB0\xDC\xE2\x8F\xE9\x05\xB2" \
+ "\x90\xE0\x8D\x41\xC2\xAF\xC5\xEE\x8B\x00\x90\x7C\x26\x87\x54\x4A" \
+ "\x71\x2A"
+
+/** Screen mode 800x600 (at 60 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_800_600_60_24_0 "" \
+ "\x02\x18\xF5\x1F\xE5\xCF\x2C\xB9\x39\x72\x74\x15\x6B\xFE\x6C\x71"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_800_600_60_24_0 "" \
+ "\xC0\x2C\xFF\x8C\x0F\x57\x30\xD7\x8A\x19\xCE\xB2\x47\x2B\xE3\xFA" \
+ "\xEE\x8F\x95\xF7\xA7\x78\x44\x39\x29\x78\xF4\x0C\xB7\x3F\xF8\xD4" \
+ "\xFA\xAD\x2C\xB8\xF2\x1C\xBB\x16\x10\xCC\xF5\xD5\x53\x6C\x2E\x4E" \
+ "\xEF\xB5\xF5\x81\x0A\xE1\x8F\x32\xC5\xB9\x96\xAB\x8C\xC2\xE3\xA7" \
+ "\x32\x14\x76\xD5\x63\xC1\x8E\xD6\xCF\x95\x1B\x0C\x51\xA9\x88\xEB" \
+ "\xF3\x89\x40\xB7\x41\xB6\x87\x10\x03\xDB\x09\xFE\xCD\xFF\x2A\x7C" \
+ "\xB1\x76\x8C\x27\x04\xA8\x09\x3B\x9E\x63\xDE\xE0\x31\xC8\x9B\x5E" \
+ "\x1E\x51\x5A\xB3\x1B\xE7\xEE\xAE\x54\x47\xBB\xF0\x9F\xAE\xBB\xF6" \
+ "\x43\x35\x57\xAE\x87\x8C\x88\x8B\x61\x61\x47\xA9\x87\xF7\xC3\x86" \
+ "\x8E\x53"
+
+/** Screen mode 800x600 (at 72 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_800_600_72_24_0 "" \
+ "\x81\x59\xC0\x67\x29\xEC\x20\x62\x5E\x94\x77\xCA\x93\xE3\x3B\xA5"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_800_600_72_24_0 "" \
+ "\x3B\xD9\x26\xBF\xB4\xE3\x00\x22\x87\x3D\xCD\xDE\x26\x6E\x71\x13" \
+ "\x15\x22\xFB\xA0\x3F\x4B\xE1\x33\xED\x36\x15\x71\x8E\xB6\x3A\xE5" \
+ "\x69\x27\xF8\x8E\xBA\x43\x42\xC3\xB8\x6F\x25\xCD\xC0\xDB\x35\xE6" \
+ "\xD0\x33\x02\xF8\xFF\x05\x73\x60\x06\x50\x6D\xB0\xF5\x86\x68\xC3" \
+ "\x27\xD8\xB4\x63\x88\x6D\x0E\x55\x1C\x18\x76\xDF\x37\x0D\x50\x62" \
+ "\xD0\x82\x75\x66\xB8\x0A\x40\x2D\x94\x85\xB1\x04\x44\x1E\xD1\xCA" \
+ "\xF7\x97\xD8\x21\x28\xB5\xBE\x91\xC5\xC2\x1F\x48\x63\x70\xED\x4F" \
+ "\x88\x9A\x02\xD0\xC3\x7C\x7A\x6A\x42\x11\xD7\xEA\x91\xF9\xCE\xAC" \
+ "\xA3\x03\x8E\xBE\x14\x25\x74\x4B\xE5\x0B\x37\xEA\x5C\xB0\xA9\xD5" \
+ "\xE5\x95"
+
+/** Screen mode 800x600 (at 75 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_800_600_75_24_0 "" \
+ "\x3F\xDB\xEE\x68\xC7\x0E\xCA\x26\xA3\x42\xF0\x36\x25\x2B\xDB\x48"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_800_600_75_24_0 "" \
+ "\xB5\x2E\xA8\x75\xF5\xC0\x36\xD8\xBF\xB3\xA8\x4F\x6F\xA4\x68\x06" \
+ "\xEC\xFB\x44\x53\xFC\x4B\xC2\x44\xF0\xFA\x20\x47\xC0\xC5\xDE\xB1" \
+ "\x6B\xDF\x89\x24\xD1\xA6\xE1\x86\xAE\x7F\x19\xA5\x56\xE7\x52\xBC" \
+ "\xD7\xCC\xAF\xED\x9C\x4F\xAF\x77\x49\x7C\x99\xA9\x0E\xB9\x41\xAE" \
+ "\x34\xD1\xB3\x33\xAD\x12\x91\xFC\x6C\x78\x85\xD5\x91\x6B\xB2\x1E" \
+ "\x28\x39\x15\x41\xF5\x14\x35\x9E\xAC\xE2\x0C\x9C\x69\x5C\x76\x86" \
+ "\x55\xF1\x41\x36\x02\xE1\x6C\xAA\x60\x66\xE4\x1F\x5D\xB7\xED\x16" \
+ "\x3F\x55\x21\x57\x56\xDA\xB3\x00\xA0\x15\x8F\x26\xC1\x08\xA6\x8B" \
+ "\x19\x22\x5E\xD2\x48\x7B\x18\xA6\xD4\xF9\x9D\xD4\x85\x57\x05\xD9" \
+ "\xC6\x31"
+
+/** Screen mode 800x600 (at 85 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_800_600_85_24_0 "" \
+ "\x51\x11\x2B\x19\x1F\xF6\x3F\xC2\x38\x2F\xF8\x5D\x5A\xD3\xA6\x0D"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_800_600_85_24_0 "" \
+ "\x87\x1E\x1B\x28\xEA\x5B\xFA\xAB\x66\xC6\x43\x53\xC7\x3A\x77\xF4" \
+ "\x08\x95\x51\x50\x9E\x8A\x19\x38\x55\x40\x3C\x31\x45\xEE\x59\xBA" \
+ "\xF2\xB3\x3C\xFD\xEC\x2F\x58\xED\xEF\x1A\x7F\xDB\xF6\x02\x25\xCA" \
+ "\x79\xCF\xC2\x7C\x95\x75\x30\xBB\x41\x3A\x3E\x27\x33\x0D\x37\x48" \
+ "\x02\x6D\xDB\x86\x50\xB0\xCA\xAA\x92\x25\x08\xB7\xDE\x93\x51\x87" \
+ "\xC0\x57\x8C\xA1\xE0\xE5\x38\xC1\x30\x97\x82\x6B\xE7\x96\x37\xA5" \
+ "\x63\x0B\x79\xB8\x67\x28\x25\x60\x79\xF2\x1D\x98\xE2\xAC\x2E\x1B" \
+ "\x1C\x7D\x3C\x9B\x63\x53\xFD\x73\x44\xAF\x8D\xDE\xB0\x98\xCD\x6E" \
+ "\xBA\x60\x48\xC2\x74\x5A\x8E\x9A\xB3\x3F\x9A\x2B\x28\x42\x66\x93" \
+ "\x1A\x26"
+
+/** Screen mode 848x480 (at 60 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_848_480_60_24_0 "" \
+ "\x06\x53\xBC\x25\x49\xFB\xE8\x81\x2A\xE0\xDF\x85\xB4\x85\x92\x4C"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_848_480_60_24_0 "" \
+ "\x27\x9E\x14\x5B\x10\x06\x0C\xE8\xFB\xD1\x12\x84\xC7\xEE\x60\x2E" \
+ "\x1B\xC4\xE1\xE0\x98\x72\x13\xE1\xEC\x4A\x2D\xC2\xBB\x44\xEB\xCC" \
+ "\x62\x2F\xE6\xC1\x71\x5D\x71\xD9\xBB\x90\xF3\xCC\x71\x7E\x5B\x71" \
+ "\x77\xA5\x78\xCF\x02\x9A\xE7\xDF\x8F\xD4\xEE\xCF\xE7\x39\xA7\x75" \
+ "\x9F\xE8\xCD\xCE\xDB\x5E\x7F\x61\x60\x45\xC6\x97\x91\x82\x6A\xFD" \
+ "\x4C\xB1\xAB\xAA\xAE\xAB\x13\x92\x45\xB6\xFD\x8F\xD1\x34\xB8\x34" \
+ "\x25\x45\xA5\xD7\xB7\xD6\x3E\x05\x9E\x25\x8E\xC5\xA9\xA3\x89\xC7" \
+ "\xF9\x98\x2E\xB6\xEB\x04\xCE\x79\x9F\x01\x3F\x3C\xBF\xD6\xF8\xDA" \
+ "\x3B\xFA\xDB\xA1\x78\xD6\xA2\x3D\xF4\xD9\x69\x37\xDE\x1F\x1C\x70" \
+ "\xF0\x01"
+
+/** Screen mode 1024x768 (at 60 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_1024_768_60_24_0 "" \
+ "\xB6\xF8\xFC\x00\xF3\xE4\x81\x1E\xC5\x60\xA3\x79\xE5\x35\xC5\x15"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_1024_768_60_24_0 "" \
+ "\xDD\x2A\x3A\x49\xE9\x99\xE3\xC8\xA0\xBA\x23\x3A\x3D\xEB\x21\xE4" \
+ "\xA5\x54\x25\x0D\x51\xCC\xE6\x52\xA7\xD7\xCD\xFA\xD5\x9B\x5B\x41" \
+ "\x0B\x49\xAB\xC6\xE3\x1A\xF2\x87\x81\x32\xF0\x3E\x40\x00\x51\x40" \
+ "\x9E\x94\xF1\x22\xEE\xAC\xB2\xA2\x6B\x4D\xC4\x41\x5A\x9C\x45\x62" \
+ "\x4F\x4E\x61\xDB\x1F\x0E\x79\x66\xE2\x20\x83\x9E\x2C\xAB\x28\x38" \
+ "\xAC\xC1\x22\x81\xA5\x69\xFD\xFB\x26\x15\xF9\xC9\xFA\x90\xF2\x66" \
+ "\x85\xC5\xAA\xA6\x4D\x8B\xC8\xA6\x03\x32\xDF\x98\xA9\x77\x9E\x57" \
+ "\xEA\xC9\x9E\x29\xED\xFC\xC4\x78\x26\x0B\x2E\xC2\x41\x7C\x4A\xA3" \
+ "\xAB\x66\x01\xA0\xE5\xA4\x8B\x80\xA0\x53\xE5\x5D\x59\x63\x62\xE8" \
+ "\xFE\x6B"
+
+/** Screen mode 1024x768 (at 70 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_1024_768_70_24_0 "" \
+ "\x2B\x71\x0C\x1F\x55\x8E\x3D\x1A\xEE\xE0\x93\xD4\x15\x58\xE9\x00"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_1024_768_70_24_0 "" \
+ "\xE9\x15\xBC\xBE\x90\x6C\x07\x34\xF2\x79\xCA\x43\x44\x92\x65\x9A" \
+ "\xC7\x41\xE9\x56\xE7\x27\x4A\x9C\x24\x04\x40\x97\xF5\xFD\xFF\x99" \
+ "\xC8\x6A\xA0\xF3\x32\xE3\x4E\x40\xBC\xA5\xAE\x37\xBA\x89\xB0\xDD" \
+ "\x10\xD2\x10\x76\xE8\x80\xAF\x15\xC1\x16\x65\x80\xA2\xCE\xFD\x14" \
+ "\x66\xD8\xAA\x83\x7C\xD6\xE2\xF2\x26\x36\xD5\xF2\x36\xA5\x7F\x4D" \
+ "\xF6\x21\x14\x58\xB5\xFA\x54\x07\xE6\x91\x93\xB9\xB9\x4B\xB5\x0C" \
+ "\xD6\xAE\x6C\x2D\x12\x51\xED\x13\x6C\xD7\x07\x15\x6D\x88\x10\x62" \
+ "\x94\x4F\x77\xB7\xEC\xA3\xD4\xAD\xDF\xCC\x76\x2D\x39\x90\xEE\xB1" \
+ "\x98\x09\xA2\x28\x03\xF8\x1F\x1C\x01\xCA\xAA\xC0\xC2\x92\xDE\xD8" \
+ "\xFC\x59"
+
+/** Screen mode 1024x768 (at 75 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_1024_768_75_24_0 "" \
+ "\x10\xFC\xF8\x65\x8A\x35\x80\x78\x15\x13\x4C\x2A\x6C\x35\x2B\x74"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_1024_768_75_24_0 "" \
+ "\xE6\xB2\x51\x5B\x75\x7E\x2A\xBC\xA5\x4A\xC0\xC0\xEA\x20\x67\xCC" \
+ "\x89\x74\x5D\x3B\x7D\xB4\x29\x82\xA8\x28\x97\x86\x13\x0E\xE3\xCC" \
+ "\x95\x10\x43\x65\x15\x64\xA0\xF9\xA7\x20\xFE\x61\x0A\xFF\x6E\xEC" \
+ "\x7E\x55\x17\x4F\xA2\x61\x77\x7E\x9A\x3B\x04\xFF\xC0\xA0\xAE\x82" \
+ "\x3F\x81\x1A\xEB\x45\x8B\x37\x99\xA6\xED\xB1\x66\x78\x02\x8C\xB3" \
+ "\xE7\x88\xD5\x57\xD8\xE7\xFD\x7F\x49\x8B\xBE\xC6\xD1\xDD\x60\xB5" \
+ "\x41\xCD\x1B\x3E\xEC\x69\x18\xE9\x77\x71\x7F\x0E\x11\xCB\x47\x82" \
+ "\x89\x2C\xCA\x54\x5E\x33\x9C\x60\x61\x42\x55\xB4\x4B\xC2\x9C\x37" \
+ "\xFD\x37\xD4\x47\xC5\x08\xDF\x14\xCB\xCD\xD9\xCD\xA0\xC1\x42\x21" \
+ "\xD2\xD9"
+
+/** Screen mode 1024x768 (at 85 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_1024_768_85_24_0 "" \
+ "\x02\x10\x92\x8C\x45\x12\x05\x5A\x25\x51\x85\x91\x87\xB0\x05\x8C"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_1024_768_85_24_0 "" \
+ "\xA7\xC9\xD0\x6E\x6E\x77\xDA\xD3\x25\xEA\x3B\xA4\x4B\x35\x88\x4E" \
+ "\x22\x53\xC4\x82\xB0\x14\x40\x54\x8A\xB6\x42\xF2\xBB\xC8\x4B\x24" \
+ "\x52\xF9\xC3\x37\xBE\xCF\x99\x01\x5A\x56\xB2\xA8\xE7\xF3\x53\x7B" \
+ "\x37\x55\xFE\x97\xF3\x05\xFF\xC0\x71\x60\xBB\xD9\xCC\x49\xFA\x73" \
+ "\x2C\x39\x72\x25\x27\xFB\x83\x7D\x44\x58\x86\x5D\x6F\xFC\xCF\xD4" \
+ "\xCF\x7C\xC1\x33\x35\x21\x30\x70\xA8\x36\x60\xBB\xA8\xE2\x74\x05" \
+ "\xBB\xB3\xC5\x60\xBD\x4B\xC0\x6C\x04\x41\xD2\xE6\xFA\xEB\x67\x02" \
+ "\x6A\x77\x82\x4D\xF7\x05\xAC\xA8\xA3\x8F\x21\xCA\x24\xF3\x53\x52" \
+ "\x2A\x99\xEA\xE5\xBD\x76\x3C\x85\x73\x98\xD8\x46\xA7\xAC\xA8\xB7" \
+ "\x3A\xA9"
+
+/** Screen mode 1152x864 (at 75 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_1152_864_75_24_0 "" \
+ "\xAE\xFE\x44\xF3\x10\x49\x4E\x35\x9B\xD3\xC7\x22\x83\xCC\xAE\x40"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_1152_864_75_24_0 "" \
+ "\x65\xB5\xCB\x8E\x46\x49\x3E\xFB\x60\x91\xC1\x32\x82\xD3\xCA\x2F" \
+ "\x4A\x49\xB1\xA8\x17\xA1\x12\x37\xBB\x1C\x5F\x69\x41\xA8\x72\xB2" \
+ "\xB8\x37\x9C\x7E\xE3\x5C\xA2\xD3\x19\x59\xE2\x75\xA7\xC9\x25\xBB" \
+ "\x6E\x77\xD1\x2D\x25\xEA\x36\x43\x4B\x35\x87\xB3\x22\x53\xC9\xB5" \
+ "\xB0\x14\x4B\x1D\x8A\xB6\x57\x78\xBB\xC8\x5C\x3B\x52\xF9\xD6\x3C" \
+ "\xBE\xCF\x82\xCB\x5A\x56\xAF\x2E\xE7\xF3\x4C\x85\x37\x55\xE3\x91" \
+ "\xF3\x05\xE4\x3C\x71\x60\xAE\xB6\xCC\x49\xEF\x6A\x2C\x39\x61\x75" \
+ "\x27\xFB\xB0\x7D\x44\x58\xB3\x32\x6F\xFC\xF8\xBF\xCF\x7C\xFB\xCC" \
+ "\x35\x21\x0E\x8B\xA8\x36\x5E\xC4\xA8\xE2\x7D\xFC\xBB\xB3\x2D\x9C" \
+ "\xBD\xCB"
+
+/** Screen mode 1280x768 (at 60 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_1280_768_60_24_0 "" \
+ "\x73\x9D\x25\x83\xE6\x73\xB8\x81\x46\x7F\xA3\xC9\x4C\x52\x09\xB4"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_1280_768_60_24_0 "" \
+ "\xB0\x52\xEB\x22\x12\xDD\x55\x65\x5C\x01\x38\xD9\xA2\x1A\xE6\x1F" \
+ "\x75\x89\x16\x6E\x7A\x2E\xFC\x28\x9F\x3C\xD0\xE6\xC8\x0F\xD9\xCE" \
+ "\x66\xBD\xDA\xE1\x28\x88\x61\x5B\xB2\x1B\x03\x5B\x3E\x37\xD7\x54" \
+ "\xD8\xC4\xCA\xBC\x85\xBE\x2E\x50\xA2\x39\xC1\xB1\xB9\xBC\x92\xA9" \
+ "\x09\xCA\x4D\xFA\x67\x4D\x55\x1E\x2D\xAC\x8C\xBB\x76\x81\xEE\xEE" \
+ "\x14\xEF\xBC\xD8\x4D\xB6\x0B\xB0\x74\xEB\xDF\xDB\xF4\x30\xB8\xF2" \
+ "\xBA\x97\x4A\x67\xAB\x3E\x84\x6B\xC6\x23\x2E\x3A\x69\x39\x04\x67" \
+ "\x01\xAF\xEE\xE6\x96\xCC\x9E\xFF\x68\xF4\x6A\x0F\x73\x52\x1E\x0A" \
+ "\x0F\x11\x4A\xE8\x12\x72\xF6\x0E\xA0\xE2\x8A\xC3\x1E\x6C\x49\xA5" \
+ "\x6C\xBE"
+
+/** Screen mode 1280x1024 (at 60 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_1280_1024_60_24_0 "" \
+ "\x6A\xF0\x37\x50\x63\xEF\xD2\xA9\x6F\x75\x72\xBB\xC7\x7B\x6F\x1A"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_1280_1024_60_24_0 "" \
+ "\x23\x4A\x78\x7C\xD1\xB8\x0E\x6B\x15\x93\x96\x77\x78\x44\xCC\x16" \
+ "\x7F\xE3\xD7\x39\x3F\x2E\x99\xD2\xB9\x68\x8E\xC4\x1A\x9B\xF4\x35" \
+ "\x61\xB5\x48\x5C\x94\xA6\x84\xB2\x88\x2B\x47\x84\x84\x73\x7F\x2C" \
+ "\xD0\xC4\x3D\x5D\x20\x61\x4A\xB1\x73\x4C\xDD\x6A\xB4\xFD\xE9\x94" \
+ "\x3C\xD1\x44\x0A\x08\xCD\xF5\xE5\xBD\x0D\x99\xCD\x9C\x2A\xC9\x06" \
+ "\x1D\x22\x1C\xB1\x9A\x94\x95\x65\x3C\x43\x19\x73\x83\xF7\x51\x1F" \
+ "\x5C\x3C\xE1\x59\xD5\xC3\xF2\x27\x28\xCE\x22\x7B\x2A\x70\x04\xE4" \
+ "\xD9\xFE\x8A\x6E\x28\x27\xC5\x40\x4E\xF8\x83\x5B\x82\x41\xA6\x62" \
+ "\xC1\x73\x3A\x5C\xF6\x90\x43\x39\xF2\xF5\x74\x80\x74\x44\xBD\xB1" \
+ "\x08\x53"
+
+/** Screen mode 1280x1024 (at 75 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_1280_1024_75_24_0 "" \
+ "\xDB\xCF\xE1\x3F\xBE\xB3\xE8\x2D\x29\x5B\xE8\xF0\xD6\x57\x0B\xFF"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_1280_1024_75_24_0 "" \
+ "\xBA\x89\x45\x90\x10\xD2\x1B\x50\xE8\x80\xA2\xE9\xC1\x16\x6A\x6D" \
+ "\xA2\xCE\xF0\xD4\x66\xD8\xA1\x18\x7C\xD6\xF7\xD8\x26\x36\xC2\x7E" \
+ "\x36\xA5\x6A\x9A\xF6\x21\x0F\xF3\xB5\xFA\x49\x07\xE6\x91\x8C\x4B" \
+ "\xB9\x4B\xA8\x0C\xD6\xAE\x77\xD1\x12\x51\xF8\x21\x6C\xD7\x12\xED" \
+ "\x6D\x88\x03\x5D\x94\x4F\x44\xB7\xEC\xA3\xE1\x3F\xDF\xCC\x41\x85" \
+ "\x39\x90\xD4\x4E\x98\x09\x9C\xD3\x03\xF8\x21\xE3\x01\xCA\xA3\x39" \
+ "\xC2\x92\x36\x23\xFC\xD9\x99\x08\x7B\xC0\x9C\xCE\x21\xF4\xBA\xBE" \
+ "\x22\x36\x9C\xB4\xE4\x4A\xFB\xC1\x1E\x9B\xAC\xFF\xB3\x5A\xD4\x0D" \
+ "\x7C\x1C\x28\xBB\x8E\x8B\xD8\x8E\x1E\xFE\xEE\xD9\xE7\x04\x99\x20" \
+ "\xE8\xB1"
+
+/** Screen mode 1280x1024 (at 85 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_1280_1024_85_24_0 "" \
+ "\xE4\xE9\xAF\xA2\x9D\x98\xD0\xC6\xF3\xB8\xB6\xC9\x10\xC1\xC8\xA6"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_1280_1024_85_24_0 "" \
+ "\x93\xB0\x06\xA2\x8F\xE9\x2C\xB3\x90\xE0\xA6\x66\xC2\xAF\xEC\x00" \
+ "\x8B\x00\x8C\x0B\x26\x87\xAF\x8A\x71\xAA\x43\x0F\x64\xF4\xC5\xF3" \
+ "\x04\x62\xE6\x7A\x36\xDE\xFA\x1A\x19\x93\x12\xD1\x0F\x74\x12\xAF" \
+ "\x46\x2C\x4D\x23\x34\xCF\x57\x3B\x16\xFE\x0B\xDC\x42\xDB\x0C\x80" \
+ "\x39\x44\xDF\x0C\x8B\x58\x28\xB3\x05\x00\x2F\xB9\xB8\xC0\xB6\xA1" \
+ "\x3C\x38\x80\xA1\x6C\x45\x4F\xF1\xE6\xB2\xBB\xA4\x75\x7E\x3C\x44" \
+ "\xA5\x4A\xD6\x28\xEA\x20\x7D\x78\x89\x74\x45\x97\x7D\xB4\x31\xB5" \
+ "\xA8\x28\xB1\xB0\x13\x0E\xC1\xCC\x95\x10\x61\x62\x15\x64\x81\x4A" \
+ "\xA7\x20\xDD\x3A\x0A\xFF\x4F\x39\x7E\x55\x03\xB0\xA2\x61\x84\x7E" \
+ "\x9A\xBB"
+
+/** Screen mode 1280x768 (at 75 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_1280_768_75_24_0 "" \
+ "\x87\x94\x88\x24\x2C\x58\xEA\x1F\x10\xA1\xE9\x20\x62\xB1\xC6\x43"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_1280_768_75_24_0 "" \
+ "\x20\x5C\x76\xA7\x04\x95\xDE\x8B\xE9\xBA\xCA\x66\x6C\x8F\xA9\x5B" \
+ "\x4E\x0F\x9A\xCA\x5D\x25\xB2\x6C\xB4\x6F\xA5\xE4\xB7\xEB\xEF\x58" \
+ "\xE9\xFC\x9C\xD2\xF4\xE4\xB1\x47\xA9\xC6\xE4\xF6\xAD\xC6\x9C\x38" \
+ "\x7F\x29\x2F\x59\x97\x93\xA6\x07\x91\x33\x1A\x1F\x0B\xBE\x9D\xE7" \
+ "\x3C\x7E\xCC\x60\xF4\x2E\x59\x92\x01\x7B\xCB\xB2\x85\x9D\x18\xA7" \
+ "\x6E\x0C\x56\xFF\xCA\x58\x32\xAB\xF1\xBB\xC7\x6B\x82\xEE\x11\x9C" \
+ "\x3D\x90\xAB\x2D\x4A\xE6\x22\x30\xEB\x42\xA1\xA6\x07\x6A\x14\x4F" \
+ "\x58\x1F\x86\xDF\xCB\x19\xF5\x7F\xB3\x90\x28\x41\xD4\xA1\x1C\x1B" \
+ "\xA6\xD0\x45\x85\x0F\xDB\xBB\xA1\xBA\xCF\xF5\xAB\x88\xB9\xF6\x32" \
+ "\x0F\xC9"
+
+/** Screen mode 1280x768 (at 85 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_1280_768_85_24_0 "" \
+ "\x74\xE4\x58\xA1\x3C\x43\xC0\x4D\xE4\xA9\x6D\x46\x5B\x34\x89\xE5"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_1280_768_85_24_0 "" \
+ "\x5B\xA6\xDC\x6E\xE2\xD7\xAD\xE3\xF3\xCF\x02\x6D\xD9\xDD\x83\xEB" \
+ "\xE4\x12\x6B\xC6\x3D\x1C\x18\x54\x7A\x30\x1A\x0C\x24\xD0\x54\x05" \
+ "\xE6\xAC\x4E\x76\xCE\x92\xA5\x1D\x8B\xE9\x5E\x53\x42\x0F\x1F\x9C" \
+ "\x2A\x15\x6B\xB1\x8D\xA0\x3E\x8E\xBC\x0A\x22\xB2\x46\x6A\x18\x18" \
+ "\xAC\xA4\x46\x5D\xF1\x37\x62\xE3\xB2\x38\x33\xFD\xF2\x02\x46\xF2" \
+ "\xAB\x20\x68\x60\x7D\xCF\xA6\xE3\x47\x9A\x9B\xA7\xA9\x80\xAB\x54" \
+ "\x35\xAD\x93\xFB\x98\xE0\x48\x7D\x67\x70\x91\x3B\x5A\x75\x8F\x97" \
+ "\x2B\xC6\xF3\x34\x44\xB1\x6B\x60\x0B\x74\x46\x54\x94\xC3\xDD\xC0" \
+ "\xDC\x75\xFF\x99\x10\x5E\x90\x26\xD8\x56\x99\x1E\x0E\x84\x7F\x8B" \
+ "\x43\x88"
+
+/** Screen mode 1280x800 (at 60 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_1280_800_60_24_0 "" \
+ "\x59\xFF\xC3\x96\x42\x84\xE3\x26\x2D\x50\x6C\x88\x84\xF6\x6E\x2A"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_1280_800_60_24_0 "" \
+ "\x55\x5E\x21\x5E\xFE\x02\xD8\x84\xDC\x10\xAC\xF6\x44\x00\x22\x46" \
+ "\x4C\x7B\x4B\xCC\x06\x16\x34\xFC\x6D\xED\x71\x58\xC0\x11\xC9\xA4" \
+ "\x78\x8E\x39\xC3\xD7\x5E\xEB\x67\x17\x75\x08\x14\xA8\x4D\xE0\x5C" \
+ "\x47\x50\x75\x35\x01\x3D\x86\x42\x1D\xF6\x15\x09\x89\xC5\x3F\xFA" \
+ "\x3A\xBB\x09\x86\x3A\xFD\x46\xB8\xA2\x96\x55\x2B\x45\x5F\x22\x94" \
+ "\xB5\xBC\x03\x09\x7E\xFA\x80\x25\x5E\x82\xC2\x09\x26\x4D\x4D\x33" \
+ "\xD9\x17\x66\x3C\x4C\xAF\x47\x81\x15\x47\x9B\x39\x6B\x15\x62\x30" \
+ "\x79\x1B\xFD\x3B\x86\x24\xA8\xD1\x47\xC2\x1C\x97\x8A\x07\x01\x66" \
+ "\xFC\xC7\x4C\xF9\xC0\x2C\x2B\x8C\x0F\x57\x2F\xD6\x8A\x19\x30\x6D" \
+ "\x47\xAB"
+
+/** Screen mode 1280x960 (at 60 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_1280_960_60_24_0 "" \
+ "\x42\xAB\xE3\x84\x2F\xC6\xAA\x5D\x17\x17\xE5\x9B\x0D\x53\xC5\xA6"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_1280_960_60_24_0 "" \
+ "\x3D\xAD\x8C\xC7\x3D\x3F\x34\x45\xB6\x05\x97\xE1\x57\x34\xEA\x4E" \
+ "\x1E\xDD\xDA\x98\x2B\x31\xEB\xEF\x9B\xD5\x73\xB1\x7E\x68\xD5\xCC" \
+ "\xD5\xB8\x72\xBD\xC7\x7C\x2D\x07\x90\xFE\x49\xD7\x79\x43\x63\x49" \
+ "\xA5\xA3\x12\x82\x8E\xA8\xD7\x6C\xD2\xCB\x75\x03\x94\xE0\xD2\x9E" \
+ "\x10\x40\x53\xD7\x63\xBA\x11\x24\x20\x27\x07\xE4\xEB\x27\xD0\x8A" \
+ "\x53\x34\x80\x2D\xCC\x32\x7F\x27\xC3\x8B\x74\x36\x9D\x75\xDD\x82" \
+ "\xE4\xE5\x40\xA2\xE2\x78\x3D\x48\x0F\x2C\xB4\x64\x65\xAB\xCF\x2E" \
+ "\xFD\xA5\x9A\xC0\x4E\x32\x72\x1D\x2A\xFC\x9D\xC7\xE9\x28\xA5\x57" \
+ "\xE7\xB5\x23\x44\xAF\x3E\xCC\xF4\x14\xCC\x98\x3A\x81\x83\x69\xFE" \
+ "\x07\x8F"
+
+/** Screen mode 1280x960 (at 85 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_1280_960_85_24_0 "" \
+ "\xF6\x75\x37\x25\x3C\xE1\x82\x53\xF8\x68\xEE\x05\xBB\xB4\xAB\xBC"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_1280_960_85_24_0 "" \
+ "\x58\x1F\x5A\xDF\xCB\x19\xD1\x74\xB3\x90\x0C\x65\xD4\xA1\x37\xD5" \
+ "\xA6\xD0\x6C\xF7\x0F\xDB\x94\x9E\xBA\xCF\xEF\x01\x88\xB9\x0F\x2B" \
+ "\x0F\x49\xD0\x81\x31\xF5\x40\x7E\x69\x88\x7E\x59\x46\xA0\xEC\xCF" \
+ "\x04\x19\x75\x02\xD9\x6C\xE2\x12\xA3\x1D\x4E\x73\xAF\xC9\xD6\x37" \
+ "\xCB\xA8\xB1\xEE\xF4\x9F\x36\x0C\x46\x74\xE0\x54\x17\x48\xDC\xCE" \
+ "\xDF\x94\xF7\x1D\x1A\x17\x46\xE8\x51\x63\x7F\xD7\x5B\x34\x72\x14" \
+ "\x69\xED\x18\xE2\x12\xFE\x65\xB9\x90\x34\xAB\xFE\xD1\xFE\x42\x25" \
+ "\x8D\xF8\xA6\x73\x9F\x8D\x9E\xE1\x8F\x00\xD1\xE3\xF4\x68\x30\xA9" \
+ "\x99\x10\xE2\xC7\x62\x54\x55\x6F\x9E\xEF\x7A\xD7\x01\x1E\x5D\x87" \
+ "\xD1\x43"
+
+/** Screen mode 1360x768 (at 60 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_1360_768_60_24_0 "" \
+ "\x84\x36\xDB\xC0\x18\x5D\x13\x10\xC5\x02\x16\x81\xB6\xC1\x3D\xA6"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_1360_768_60_24_0 "" \
+ "\x99\xDA\xC7\x8E\xCA\xE9\x49\xCB\xB6\xB4\xF8\x21\x10\x3B\xC1\x42" \
+ "\x8C\x08\x1E\x52\x9A\xA9\x4A\x17\x4B\x9A\x07\x0A\xDE\xB0\x6D\x89" \
+ "\x0C\x62\x11\x38\x93\x01\x9E\x33\xC8\xE6\x0E\x17\x02\x35\x69\x2B" \
+ "\x73\x37\x44\xD3\x5B\x4F\xF7\xC0\x86\x5F\x1E\x9D\xA8\x70\x2B\x3C" \
+ "\x30\x89\x7F\x65\x5C\x7A\xB6\x36\x4D\xA8\xE9\xFB\xCF\x07\x5F\x65" \
+ "\xDA\x93\x2B\x98\x12\xB8\x39\xBD\x08\x5F\xB7\x99\x36\x37\x3C\x9E" \
+ "\x7D\x1B\xB2\xA7\x54\xCB\x26\xC7\xAF\x78\xAC\x03\x8C\xA7\x89\xE4" \
+ "\x66\x4A\xC1\x04\xF7\xEC\x74\xFB\xC7\x07\x9F\x81\x7F\x4C\x75\x5E" \
+ "\xC3\xCD\x1B\xF7\x05\x1E\xF2\xB7\x03\x2C\x3C\xA4\x12\x9B\xFA\xA0" \
+ "\xC4\xEA"
+
+/** Screen mode 1366x768 (at 60 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_1366_768_60_24_0 "" \
+ "\x6E\xF3\xC9\x86\x50\xDD\x97\x16\xDF\xAD\x97\x95\x6E\xD4\x3B\x46"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_1366_768_60_24_0 "" \
+ "\x2A\x70\xE7\xB0\xD9\xFE\xA9\x6F\x28\x27\xE0\x53\x4E\xF8\xA4\x45" \
+ "\x82\x41\x8C\x7D\xC1\x73\x14\xE9\xF6\x90\x6D\xAA\xF2\xF5\x6D\xE0" \
+ "\x74\x44\x45\x0E\x08\xD3\x0A\x6A\x06\xE1\x06\x5B\xB2\x89\x47\x47" \
+ "\xB5\x0D\x74\x4F\x39\xF5\xB3\xA5\xCC\x57\x1E\x01\x97\xD5\xF4\xE4" \
+ "\x09\x58\x0A\x79\xEC\x77\xF7\x4B\xCC\x9D\xF2\xB1\x3F\x68\xDF\x67" \
+ "\x21\x03\x8A\x8D\xFD\x52\x92\x9A\x91\x56\x7A\x3A\x5F\xE0\x1E\x6D" \
+ "\xA8\x53\x1A\x61\xFC\xBC\xE1\x2E\x2F\x9E\x07\xFE\xB5\xD9\x74\x92" \
+ "\x2A\xA4\x2C\x08\xCA\xAF\x3D\xFB\x2E\xDF\xCE\xE9\xF7\xF2\x9E\x05" \
+ "\x7C\xEB\x17\x1E\x51\xEF\xE1\x09\x6B\xE2\x5E\xD4\xA6\x7F\x18\x15" \
+ "\xF3\xB8"
+
+/** Screen mode 1400x1050 (at 60 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_1400_1050_60_24_0 "" \
+ "\x95\xCB\x91\xE5\xA8\x28\xFB\x87\xD5\x92\x1C\x44\x66\x57\x8A\x98"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_1400_1050_60_24_0 "" \
+ "\xC6\x8C\x42\x4C\x95\xDA\xB4\x2F\xBD\xD9\x9E\xAD\x8F\x7B\x69\x15" \
+ "\x1B\xDA\x06\x79\x23\x9E\x94\xF2\xC2\xE9\xBB\x34\x13\x6B\x9B\xB2" \
+ "\xC1\x4E\xD8\x69\x81\x49\x6E\x64\xAF\xB2\x4E\x69\x24\x1A\xA8\xBB" \
+ "\x4E\x11\x75\x38\xE6\xC9\x3D\xE9\x9A\xCC\x3B\xAA\x1F\xC4\x97\xD5" \
+ "\x4A\x9D\xAA\xE7\x04\xF0\xB6\xD4\xBD\xE4\x41\xCF\xF8\xA2\x77\x0B" \
+ "\x46\x9D\x3A\xBD\x73\xC0\x64\x76\x84\x2B\xD7\x11\xF3\x43\xB5\xF6" \
+ "\xE9\x0B\xB3\x4E\x2B\x80\x98\x15\xDC\xDA\x46\xE8\xEC\xBD\x0B\x0E" \
+ "\x64\x20\xF7\x17\x17\x33\x75\xBA\x30\x26\xDD\xFA\xA0\x99\x23\x11" \
+ "\xF1\xDE\x80\xB7\xD6\xB0\xB7\xA2\xA9\xBD\x6D\x29\x42\x74\x75\x73" \
+ "\xC5\x27"
+
+/** Screen mode 1400x1050 (at 60 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_1400_1050_60_24_1 "" \
+ "\xCB\xA2\x00\x73\xCB\xFC\xFB\xA0\x8E\x17\xE4\xF5\x6F\x6F\x8D\x1D"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_1400_1050_60_24_1 "" \
+ "\xDA\x01\x80\xE4\x99\x82\x8F\x40\xE9\x6E\xDD\xA6\x7F\xDE\x19\xFC" \
+ "\x48\xF7\x90\x61\xE4\x2F\xA3\x72\x4A\xC5\x17\xBE\x27\x77\x35\x6A" \
+ "\x74\x8E\xB5\x45\xA0\x6E\x3D\x58\x2E\xBA\x9A\xB6\xA3\xAC\x26\xD4" \
+ "\xE8\xC6\xF8\xE3\x59\x7D\x76\x1C\x45\x07\x8A\x82\x96\x3B\x8B\x45" \
+ "\xB7\x90\x79\xDB\x06\x4E\x97\x7F\x4E\x6A\xF0\xE7\x09\x7B\x3F\x05" \
+ "\x20\x42\x7D\xAC\xBF\x79\x4D\x42\xC7\x19\x48\x2A\xC4\xA0\xCD\x9B" \
+ "\xED\x6E\xB0\xF7\xAD\x31\xB1\xDB\xA0\x4D\x06\x41\xE2\x8F\x06\x63" \
+ "\xD0\x48\xB5\xD5\x10\xB7\x47\x7D\xBC\xDE\x1D\x05\x55\x3B\x8F\x78" \
+ "\xAA\x5C\x69\x52\x48\x3D\x48\xC5\x4C\x92\x8F\x48\x62\x9E\x71\xDC" \
+ "\x36\xD2"
+
+/** Screen mode 1400x1050 (at 75 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_1400_1050_75_24_0 "" \
+ "\x8E\x2F\xD0\x59\x2B\xCB\xFA\xB9\xE2\xDE\xAE\x51\x4D\x3C\x6E\x4D"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_1400_1050_75_24_0 "" \
+ "\x25\xF4\x22\x48\xF0\xD9\x0D\xA9\x0C\xF0\x50\x5D\x18\x3B\x36\x2D" \
+ "\x29\xD7\x7A\x1D\x4B\xDC\x56\xA2\x46\xDB\x7C\x33\xEB\xAB\x64\xBB" \
+ "\x63\xE2\xB1\x4C\x03\xA0\x8B\xBB\x22\x4D\x29\x10\x0B\xF8\xC9\x3F" \
+ "\xA4\x15\xDA\xCB\x13\xE7\x31\xF7\xF1\x98\xF7\x76\x4E\xDB\x80\xB9" \
+ "\x4E\x74\x09\x29\xB2\x97\xBA\x23\x0E\xE1\xE9\x69\x17\x56\x3B\xD0" \
+ "\x64\x78\x70\x27\x34\xB4\xD0\xE9\xF9\x4C\x0F\xF1\xF8\x55\x4C\x12" \
+ "\x99\xF9\x07\x97\x06\xDC\xD8\x9E\xC5\x50\x58\x3B\xE8\x4A\x4F\x12" \
+ "\x69\xAB\x7C\xDA\x8A\x95\x4B\xEF\x77\xFD\xE1\x0F\x21\x1D\x57\x86" \
+ "\x46\xBE\x2B\x5A\xBF\xF5\xD2\xBF\xF7\xCF\x67\xEC\x0B\x32\xCC\x90" \
+ "\x0C\x28"
+
+/** Screen mode 1400x1050 (at 85 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_1400_1050_85_24_0 "" \
+ "\x66\xC2\x92\x91\x8D\x8C\x4A\x6F\x6A\xF9\xC1\xB8\x35\x2F\x05\xD7"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_1400_1050_85_24_0 "" \
+ "\x73\x98\x38\x46\xA7\xAC\x57\x49\x3A\x29\x40\xA6\xB1\xC7\xF6\xC8" \
+ "\x43\xA7\x39\x93\x0C\xB6\x05\xD3\x80\x50\x23\x08\xCE\x1E\x0B\x6B" \
+ "\xBB\x3F\x75\xCE\x8D\x9D\xF5\x67\xCB\xD3\x28\x29\x1B\x2D\x30\x40" \
+ "\xFC\xFA\xA2\x75\xB7\xF5\x02\xC2\x52\x10\x11\x2A\xDA\x47\x21\x20" \
+ "\x01\xE9\x92\xD8\x0E\xA7\xB8\x11\x8F\x3D\x2A\xDB\x83\xB1\x05\x48" \
+ "\xC4\x57\xF7\x3E\x32\x0A\x8A\xDD\xD8\x2D\x0C\x33\xE1\x36\x8A\x6E" \
+ "\xF9\x86\xFD\x46\x50\xE8\x75\x5F\xB1\xA2\x97\xA1\x17\xF9\xBD\x70" \
+ "\x98\x9B\xEC\xAF\x88\xC2\xB2\x15\xE0\xFB\xEE\x3A\x8B\x7B\x39\xAE" \
+ "\xC9\x35\x9D\x58\xCB\x24\x35\xE4\xC4\x49\x1C\x35\x89\xE6\xE6\xE7" \
+ "\xF6\x0E"
+
+/* DL160 modes... */
+
+/** Screen mode 1600x1200 (at 60 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_1600_1200_60_24_0 "" \
+ "\x3C\x79\x81\x0F\xF2\xAB\x85\xC7\x3A\xE8\xEB\xCB\xF3\x32\x12\x9C"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_1600_1200_60_24_0 "" \
+ "\x85\x2C\x9A\xF4\x29\x03\x6E\x4C\x58\x8D\xE3\x93\x40\x23\x71\xD2" \
+ "\x52\xA1\x70\x77\x9D\x48\x00\xDC\x93\x3C\x5C\x80\xBF\x3F\x0F\xF8" \
+ "\x5F\x72\x48\x38\x23\x69\xA7\x4A\x1D\x8D\x8E\x55\x66\x77\x27\xBF" \
+ "\x80\x35\x55\x7A\x9A\x40\x9A\xDD\x2F\x12\xB1\xFD\x85\x0F\x43\x23" \
+ "\xE5\x36\xE8\x05\x2B\x69\x48\x1E\xB8\x52\xF2\xFF\xB7\x02\x23\x0A" \
+ "\x8D\x74\x36\xFB\xAF\x5B\x8B\x2D\x40\x92\x09\x17\x15\xAE\x4E\xFF" \
+ "\x0F\x9D\xD7\x9E\x22\xA4\xE0\x87\x6F\x70\x66\x58\xFF\xAA\xEB\x8B" \
+ "\xFA\xB3\xEF\x84\x49\xF0\x10\xE7\x3E\x6F\x4F\x24\xFB\x43\x7D\x3B" \
+ "\x4C\xD4\xEA\x75\xFA\xF5\xB7\xFF\xD1\x9B\x39\x77\xD9\xA6\xE1\x5E" \
+ "\x0B\x20"
+
+/** Screen mode 1920x1080 (at 60 Hz, 24 bpp).
+ */
+#define DLO_MODE_ENABLE_1920_1080_60_24_0 "" \
+ "\xC1\xCA\xC3\xB3\x75\x48\x7A\xAF\x30\x65\x7B\x24\x97\x8D\xC0\x64"
+
+/** Mode data.
+ */
+#define DLO_MODE_DATA_1920_1080_60_24_0 "" \
+ "\x0D\x58\x81\xE3\x3E\x98\x55\x00\x24\x27\x6C\x99\x39\xC8\x72\xD8" \
+ "\xBB\x8E\x1E\xA2\xCA\x92\xD2\xAB\x59\x06\xE0\x65\xAA\xB5\x9D\xAC" \
+ "\x2C\xB5\xDA\x17\x17\x2D\xBE\x19\x8B\xCA\x76\x3D\x8E\x3A\x96\x8F" \
+ "\x59\xF1\xD1\xA6\x75\xD1\xAE\xB7\x59\xA9\x60\xA4\x56\x56\x39\x8E" \
+ "\x90\xC3\x80\x58\x0E\x9A\x77\x00\xF8\xE4\x24\x74\xDE\xF6\x29\x34" \
+ "\x94\x09\x17\x73\x74\xC8\xF6\xC0\x38\x05\x32\xD7\xC9\x73\xF1\x99" \
+ "\x53\x4F\x1B\x04\x23\x80\x6F\x08\x79\x05\x22\x2F\x3D\xC8\x17\x9D" \
+ "\x69\x61\x8C\x96\x22\x28\x7C\x4F\x5F\xA6\x7D\xF1\x30\x38\x36\xFE" \
+ "\x1B\x75\xA7\x2C\xDF\x7D\x17\x33\x7E\x9F\xF3\xFC\x0A\xDC\xB3\xDB" \
+ "\xB2\xE0"
+
+/** Data to send after a mode change.
+ */
+#define DLO_MODE_POSTAMBLE "\x57\xCD\xDC\xA7\x1C\x88\x5E\x15\x60\xFE\xC6\x97\x16\x3D\x47\xF2"
+
+/** Number of entries in the @a dlo_mode_data array.
+ */
+#define DLO_MODE_DATA_NUM (35u)
+
+/** Lowest mode number supported by the DL120.
+ */
+#define DLO_DL120_MODES (2u)
+
+
+#endif
diff --git a/include/dlo_defs.h b/include/dlo_defs.h
new file mode 100644
index 0000000..08baf21
--- /dev/null
+++ b/include/dlo_defs.h
@@ -0,0 +1,158 @@
+/** @file dlo_defs.h
+ *
+ * @brief This file defines common macros and so on for the DisplayLink libdlo library.
+ *
+ * DisplayLink Open Source Software (libdlo)
+ * Copyright (C) 2009, DisplayLink
+ * www.displaylink.com
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by the Free
+ * Software Foundation; LGPL version 2, dated June 1991.
+ *
+ * This library 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 Library General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef DLO_DLOCOMMON_H
+#define DLO_DLOCOMMON_H /**< Avoid multiple inclusion. */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#ifdef DEBUG
+
+/** Assert that a given expression evaluates to a non-zero number.
+ *
+ * @param expr The expression to test.
+ */
+#define ASSERT(expr) if (!(expr)) { printf("<%s:%u>\n Assertion '%s' failed.\n", __FILE__, __LINE__, #expr); exit(1); }
+
+/** Variadic debugging printf() implementation.
+ *
+ * @param fmt Format string for printed output.
+ */
+#define DPRINTF(fmt, ...) printf(fmt, ##__VA_ARGS__)
+
+#else
+
+/** Non-debug assert - does nothing.
+ *
+ * @param expr The expression to test.
+ */
+#define ASSERT(expr)
+
+/** Non-debug printf - does nothing.
+ *
+ * @param fmt Format string for printed output.
+ */
+#define DPRINTF(fmt, ...)
+
+#endif
+
+/** Get a couple of required attributes into a handy format. */
+#if __GNUC__ >= 3
+
+/* Check for portable attribute definitions and create them if they are missing */
+#ifndef inline
+#define inline inline __attribute__ ((always_inline))
+#endif
+#ifndef __packed
+#define __packed __attribute__ ((packed))
+#endif
+
+#else
+
+/* Toolchain is too old or doesn't support the attributes we need */
+#ifndef inline
+#define inline TOOLCHAIN_ERROR_NO_INLINE
+#endif
+#ifndef __packed
+#define __packed TOOLCHAIN_ERROR_NO_PACKED
+#endif
+
+#endif
+
+/** Read an unsigned 32 bit value from the address given (may be unaligned). */
+#define RD_L(ptr) (*(__packed uint32_t *)(ptr))
+
+/** Read an unsigned 16 bit value from the address given (may be unaligned). */
+#define RD_S(ptr) (*(__packed uint16_t *)(ptr))
+
+/** Read an unsigned byte from the address given. */
+#define RD_B(ptr) (*(uint8_t *)(ptr))
+
+/** Surpress warnings about unused variables. */
+#define IGNORE(x) do { (void) (x); } while (0)
+
+/** Record the line and source file associated with a particular type of error event. */
+#define REC_ERR() { snprintf(&err_file[0], 1024, "%s", __FILE__); err_line = __LINE__; }
+
+/** If a called function (cmd) returns an error code, return the error code from the calling function. */
+#define ERR(cmd) do { dlo_retcode_t __err = (cmd); if (__err != dlo_ok) return __err; } while(0)
+
+/** If a usb_ function call returns an error code, return an error and store the code in the @a usberr global. */
+#define UERR(cmd) do { usberr = (cmd); if (usberr < 0) return usb_error_grab(); } while (0)
+
+/** If a memory-allocating call returns NULL, return with a memory allocation error code. */
+#define NERR(ptr) do { if (!(ptr)) { REC_ERR(); return dlo_err_memory; } } while (0)
+
+/** If a function call (cmd) returns an error code, jump to the "error" label. Requires variable declaration: dlo_retcode_t err; */
+#define ERR_GOTO(cmd) do { err = (cmd); if (err != dlo_ok) goto error; } while(0)
+
+/** If a usb_ function call returns an error code, jump to the "error" label and store the usb error code in the @a usberr global. */
+#define UERR_GOTO(cmd) do { usberr = (cmd); if (usberr < 0) { err = usb_error_grab(); goto error; } } while(0)
+
+/** If a memory-allocating call returns NULL, jump to the "error" label with a memory allocation error code. */
+#define NERR_GOTO(ptr) do { if (!(ptr)) { REC_ERR(); err = dlo_err_memory; goto error; } } while(0)
+
+/** Return the size of a hash-defined string, excluding the terminator (unlike strlen(), it does count null bytes in the string). */
+#define DSIZEOF(str) (sizeof(str) - 1)
+
+/** Swap two integer values (assumes they are the same size). */
+#define SWAP(a, b) do { (a) = (a) ^ (b); (b) = (a) ^ (b); (a) = (a) ^ (b); } while (0)
+
+/** Magic macro for calling functions from pointer tables (after first checking the device structure pointer and the function pointer). */
+#define CALL(dev, fn, ...) dev ? ( dev->fn ? dev->fn(dev, ##__VA_ARGS__) : dlo_err_unsupported ) : dlo_err_bad_device
+
+/** Number of bytes per 16 bpp pixel! */
+#define BYTES_PER_16BPP (2)
+
+/** Number of bytes per 8 bpp pixel! */
+#define BYTES_PER_8BPP (1)
+
+/** Convert a framebuffer pixel format into a number of bytes per pixel. */
+#define FORMAT_TO_BYTES_PER_PIXEL(fmt) ((unsigned int)fmt > 1023u ? 1 : ((fmt) & DLO_PIXFMT_BYPP_MSK) >> DLO_PIXFMT_BYPP_SFT)
+
+/** Default buffer size for sending commands to the device. */
+#define BUF_SIZE (64*1024u)
+
+/** Threshold (bytes away from being full) for flushing the command buffer before adding any more commands to it. */
+#define BUF_HIGH_WATER_MARK (1*1024u)
+
+/** A 16 bits per pixel colour number (not normally used outside libdlo). */
+typedef uint16_t dlo_col16_t;
+
+/** An 8 bits per pixel colour number (2_rrrggbbb - not normally used outside libdlo). */
+typedef uint8_t dlo_col8_t;
+
+/** Integer used to store error number for last failed call to a dlo_usb_ function. */
+extern int32_t usberr;
+
+/** Integer used to store error number for last failed call to a dlo_eth_ function. */
+extern int32_t etherr;
+
+/** Source file name for the last recorded error event. */
+extern char err_file[1024];
+
+/** Source line number for last recorded error event. */
+extern uint32_t err_line;
+
+
+#endif
diff --git a/include/dlo_grfx.h b/include/dlo_grfx.h
new file mode 100644
index 0000000..15ce3b9
--- /dev/null
+++ b/include/dlo_grfx.h
@@ -0,0 +1,93 @@
+/** @file dlo_grfx.h
+ *
+ * @brief This file defines the external API of the DisplayLink libdlo graphics functions.
+ *
+ * This API is used by clients of the Bitmap Manager (e.g. other parts of libdlo) to access its
+ * features. It is intended that all implementation details are abstracted-away by this interface.
+ *
+ * DisplayLink Open Source Software (libdlo)
+ * Copyright (C) 2009, DisplayLink
+ * www.displaylink.com
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by the Free
+ * Software Foundation; LGPL version 2, dated June 1991.
+ *
+ * This library 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 Library General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef DLO_GRFX_H
+#define DLO_GRFX_H /**< Avoid multiple inclusion. */
+
+#include "dlo_structs.h"
+
+
+#define WRITE_RAW8 "\xAF\x60" /**< 8 bit raw write command. */
+#define WRITE_RL8 "\xAF\x61" /**< 8 bit run length write command. */
+#define WRITE_COPY8 "\xAF\x62" /**< 8 bit copy command. */
+#define WRITE_RAW16 "\xAF\x68" /**< 16 bit raw write command. */
+#define WRITE_RL16 "\xAF\x69" /**< 16 bit run length write command. */
+#define WRITE_COPY16 "\xAF\x6A" /**< 16 bit copy command. */
+
+
+/** Initialise the graphics primitive routines.
+ *
+ * @param flags Initialisation flags word (unused flags ignored).
+ *
+ * @return Return code, zero for no error.
+ */
+extern dlo_retcode_t dlo_grfx_init(const dlo_init_t flags);
+
+
+/** Finalisation call for graphics primitive routines.
+ *
+ * @param flags Finalisation flags word (unused flags ignored).
+ *
+ * @return Return code, zero for no error.
+ */
+extern dlo_retcode_t dlo_grfx_final(const dlo_final_t flags);
+
+
+/** Plot a filled rectangle into the specified device.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ * @param area Struct pointer: area within device memory to fill.
+ * @param col Colour of filled rectangle.
+ *
+ * @return Return code, zero for no error.
+ */
+extern dlo_retcode_t dlo_grfx_fill_rect(dlo_device_t * const dev, const dlo_area_t * const area, const dlo_col32_t col);
+
+
+/** Copy a rectangular area within the device from one location to another.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ * @param src_area Struct pointer: area within device memory to copy from.
+ * @param dest_area Struct pointer: area within device memory to copy to.
+ * @param overlap true if rectangles overlap or false if not.
+ *
+ * @return Return code, zero for no error.
+ */
+extern dlo_retcode_t dlo_grfx_copy_rect(dlo_device_t * const dev, const dlo_area_t * const src_area, const dlo_area_t * const dest_area, const bool overlap);
+
+
+/** Copy (and translate pixel formats) a rectangular area from host memory into the device.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ * @param flags Flags word indicating special behaviour (unused flags should be zero).
+ * @param fbuf Struct pointer: area within host memory to copy from.
+ * @param area Struct pointer: area within device memory to copy into.
+ *
+ * @return Return code, zero for no error.
+ */
+extern dlo_retcode_t dlo_grfx_copy_host_bmp(dlo_device_t * const dev, const dlo_bmpflags_t flags, const dlo_fbuf_t const *fbuf, const dlo_area_t * const area);
+
+
+#endif
diff --git a/include/dlo_mode.h b/include/dlo_mode.h
new file mode 100644
index 0000000..822cd0a
--- /dev/null
+++ b/include/dlo_mode.h
@@ -0,0 +1,127 @@
+/** @file dlo_mode.h
+ *
+ * @brief Definitions for the screen mode-related functions.
+ *
+ * These functions have been separated-out into a distinct compilation unit so that
+ * it would be possible to build a distribution of the DisplayLink library which
+ * inludes the object(s) associated with this unit as pre-built binaries (i.e.
+ * without the dlo_mode.c source file included).
+ *
+ * DisplayLink Open Source Software (libdlo)
+ * Copyright (C) 2009, DisplayLink
+ * www.displaylink.com
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by the Free
+ * Software Foundation; LGPL version 2, dated June 1991.
+ *
+ * This library 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 Library General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef DLO_MODE_H
+#define DLO_MODE_H /**< Avoid multiple inclusion. */
+
+#include "dlo_structs.h"
+
+
+/** Size of an EDID structure, as read from a device (bytes).
+ */
+#define EDID_STRUCT_SZ (128)
+
+
+/** An undefined mode number. Used to indicate a failed look-up or an unknown mode.
+ */
+#define DLO_INVALID_MODE ((dlo_modenum_t)-1)
+
+
+/** Initialise the screen mode handling functions.
+ *
+ * @param flags Initialisation flags word (unused flags ignored).
+ *
+ * @return Return code, zero for no error.
+ */
+extern dlo_retcode_t dlo_mode_init(const dlo_init_t flags);
+
+
+/** Finalisation call for the screen mode handling functions.
+ *
+ * @param flags Finalisation flags word (unused flags ignored).
+ *
+ * @return Return code, zero for no error.
+ */
+extern dlo_retcode_t dlo_mode_final(const dlo_final_t flags);
+
+
+/** Return a block of mode information for a given mode number.
+ *
+ * @param num Mode number for best match to the supplied bitmap.
+ *
+ * @return Pointer to mode information block (in static workspace), or NULL if error.
+ */
+extern dlo_mode_t *dlo_mode_from_number(const dlo_modenum_t num);
+
+
+/** Select a display mode given a set of parameters.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ * @param width Width of desired display (pixels).
+ * @param height Hieght of desired display (pixels) - zero to select first available.
+ * @param refresh Desired refresh rate (Hz) - zero to select first available.
+ * @param bpp Colour depth (bits per pixel) - zero to select first available.
+ *
+ * @return Return code, zero for no error.
+ *
+ * Will find the best match it can from the VESA timings, given the parameters specified.
+ * If no matching mode can be found, an error will be returned and the device's screen
+ * mode will not be changed.
+ */
+extern dlo_modenum_t dlo_mode_lookup(dlo_device_t * const dev, const uint16_t width, const uint16_t height, const uint8_t refresh, uint8_t bpp);
+
+
+/** Perform a mode change into the specified mode number.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ * @param desc Pointer to mode description structure.
+ * @param mode Mode number for best match to the mode descriptor (or @a DLO_INVALID_MODE if not known).
+ *
+ * @return Return code, zero for no error.
+ *
+ * This call will change the screen mode into the specified mode number (if one was given)
+ * or look for one which matches the specified mode description. Chaging mode does not imply
+ * clearing the screen!
+ *
+ * Note: this call will cause any buffered commands to be sent to the device.
+ */
+extern dlo_retcode_t dlo_mode_change(dlo_device_t * const dev, const dlo_mode_t * const desc, dlo_modenum_t mode);
+
+
+/** Parse the EDID structure read from a display device and build a list of supported modes.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ * @param ptr Pointer to EDID structure.
+ * @param size Size of EDID structure (bytes).
+ *
+ * @return Return code, zero for no error.
+ *
+ * This call updates the @a dlo_device_t structure by constructing a list of supported
+ * modes. Any modes which were not supplied in the EDID structure will be refused for
+ * that device.
+ */
+extern dlo_retcode_t dlo_mode_parse_edid(dlo_device_t * const dev, const uint8_t * const ptr, const size_t size);
+
+
+/** Reset the supported modes array for a device to include all of the default VESA mode timings.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ */
+extern void use_default_modes(dlo_device_t * const dev);
+
+
+#endif
diff --git a/include/dlo_structs.h b/include/dlo_structs.h
new file mode 100644
index 0000000..d639a59
--- /dev/null
+++ b/include/dlo_structs.h
@@ -0,0 +1,92 @@
+/** @file dlo_structs.h
+ *
+ * @brief This file defines all of the internal structures used by libdlo.
+ *
+ * DisplayLink Open Source Software (libdlo)
+ * Copyright (C) 2009, DisplayLink
+ * www.displaylink.com
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by the Free
+ * Software Foundation; LGPL version 2, dated June 1991.
+ *
+ * This library 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 Library General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef DLO_STRUCTS_H
+#define DLO_STRUCTS_H /**< Avoid multiple inclusion. */
+
+#include "libdlo.h"
+#include "dlo_data.h"
+
+
+/** Structure holding all of the information specific to a particular device.
+ */
+typedef struct dlo_device_s dlo_device_t;
+
+
+/** A mode number used to index a specific mode from the list defined in dlo_mode_data.c.
+ */
+typedef uint32_t dlo_modenum_t;
+
+
+/** Structure used internally by dlo_usb.c (stored as dev->cnct in @a dlo_device_t structure).
+ *
+ * This is required to keep track of which USB device a given @a dlo_device_t structure
+ * represents so that our various functions can do their stuff with libusb.
+ */
+typedef struct dlo_usb_dev_s
+{
+ struct usb_device *udev; /**< Pointer to USB device structure for given device. */
+ usb_dev_handle *uhand; /**< USB device handle (once device is "opened"). */
+} dlo_usb_dev_t; /**< A struct @a dlo_usb_dev_s. */
+
+
+/** An internal representation of a viewport within the DisplayLink device.
+ *
+ * An area is generated from a viewport and a rectangle within that viewport (which
+ * has no parts lying outside but may cover the complete extent of the viewport). It
+ * has a base address for both the 16 bpp component of a pixel's colour and the 8 bpp
+ * fine detail component. It also requires a stride in the case where the rectangle
+ * didn't fully occupy the horizontal extent of the viewport.
+ */
+typedef struct dlo_area_s
+{
+ dlo_view_t view; /**< Viewport information (normalised to a specific rectangle within a viewport). */
+ dlo_ptr_t base8; /**< The base address of the 8 bpp fine detail colour information. */
+ uint32_t stride; /**< The stride (pixels) from one pixel in the area to the one directly below. */
+} dlo_area_t; /**< A struct @a dlo_area_s. */
+
+
+/** Structure holding all of the information specific to a particular device.
+ */
+struct dlo_device_s
+{
+ dlo_device_t *prev; /**< Pointer to previous node on device list. */
+ dlo_device_t *next; /**< Pointer to next node on device list. */
+ dlo_devtype_t type; /**< Type of DisplayLink device. */
+ char *serial; /**< Pointer to device serial number string. */
+ bool claimed; /**< Has the device been claimed by someone? */
+ bool check; /**< Flag is toggled for each enumeration to spot dead nodes in device list. */
+ uint32_t timeout; /**< Timeout for bulk communications (milliseconds). */
+ uint32_t memory; /**< Total size of storage in the device (bytes). */
+ char *buffer; /**< Pointer to the base of the command buffer. */
+ char *bufptr; /**< Pointer to the first free byte in the command buffer. */
+ char *bufend; /**< Pointer to the byte after the end byte of the command buffer. */
+ dlo_usb_dev_t *cnct; /**< Private word for connection specific data or structure pointer. */
+ dlo_mode_t mode; /**< Current display mode information. */
+ dlo_ptr_t base8; /**< Pointer to the base of the 8bpp segment (if any). */
+ bool low_blank; /**< The current raster screen mode has reduced blanking. */
+ dlo_mode_t native; /**< Mode number of the display's native screen mode (if any). */
+ dlo_modenum_t supported[DLO_MODE_DATA_NUM]; /**< Array of supported mode numbers. */
+};
+
+
+#endif
diff --git a/include/dlo_usb.h b/include/dlo_usb.h
new file mode 100644
index 0000000..744375d
--- /dev/null
+++ b/include/dlo_usb.h
@@ -0,0 +1,134 @@
+/** @file dlo_usb.h
+ *
+ * @brief Header file for the USB-specific connectivity functions.
+ *
+ * This file defines the API between the libdlo.c and the USB driver implementation. This
+ * example implementation uses libusb but it should be simple to replace dlo_usb.c with
+ * some alternative implementation.
+ *
+ * DisplayLink Open Source Software (libdlo)
+ * Copyright (C) 2009, DisplayLink
+ * www.displaylink.com
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by the Free
+ * Software Foundation; LGPL version 2, dated June 1991.
+ *
+ * This library 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 Library General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef DLO_USB_H
+#define DLO_USB_H /**< Avoid multiple inclusion. */
+
+#include "usb.h"
+#include "dlo_structs.h"
+
+
+/** Return the meaning of the last USB-related error as a human-readable string.
+ *
+ * @return Pointer to error message string (zero-terminated).
+ */
+extern char * dlo_usb_strerror(void);
+
+
+/** Initialise the USB communications routines.
+ *
+ * @param flags Initialisation flags word (unused flags ignored).
+ *
+ * @return Return code, zero for no error.
+ */
+extern dlo_retcode_t dlo_usb_init(const dlo_init_t flags);
+
+
+/** Finalisation call for USB communications routines.
+ *
+ * @param flags Finalisation flags word (unused flags ignored).
+ *
+ * @return Return code, zero for no error.
+ */
+extern dlo_retcode_t dlo_usb_final(const dlo_final_t flags);
+
+
+/** Update or create nodes on the device list for any DisplayLink devices found.
+ *
+ * @param init Is this the first call to the enumeration function?
+ *
+ * @return Return code, zero for no error.
+ *
+ * This call will look for any DisplayLink devices which use the particular connection
+ * implementation and either add nodes onto the device list or update nodes if they are
+ * already present.
+ *
+ * Once enumeration is complete for all connection types, any nodes on the list which
+ * haven't just been added or updated are removed (as the correponding device can no
+ * longer be found).
+ */
+extern dlo_retcode_t dlo_usb_enumerate(const bool init);
+
+
+/** Open a connection to the specified device.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ *
+ * @return Return code, zero for no error.
+ */
+extern dlo_retcode_t dlo_usb_open(dlo_device_t * const dev);
+
+
+/** Close the connection with a specified device.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ *
+ * @return Return code, zero for no error.
+ */
+extern dlo_retcode_t dlo_usb_close(dlo_device_t * const dev);
+
+
+/** Select the input channel in the specified device.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ * @param buf Pointer to the buffer containing the channel information.
+ * @param size Size of the buffer (bytes).
+ *
+ * @return Return code, zero for no error.
+ */
+extern dlo_retcode_t dlo_usb_chan_sel(const dlo_device_t * const dev, const char * const buf, const size_t size);
+
+
+/** Switch to the default input channel in the specified device.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ *
+ * @return Return code, zero for no error.
+ */
+extern dlo_retcode_t dlo_usb_std_chan(const dlo_device_t * const dev);
+
+
+/** Flush the command buffer contents to the specified device.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ *
+ * @return Return code, zero for no error.
+ */
+extern dlo_retcode_t dlo_usb_write(dlo_device_t * const dev);
+
+
+/** Write the contents of a specified command buffer to the specified device.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ * @param buf Pointer to the buffer containing commands to write.
+ * @param size Size of the buffer (bytes).
+ *
+ * @return Return code, zero for no error.
+ */
+extern dlo_retcode_t dlo_usb_write_buf(dlo_device_t * const dev, char * buf, size_t size);
+
+
+#endif
diff --git a/include/libdlo.h b/include/libdlo.h
new file mode 100644
index 0000000..9713a00
--- /dev/null
+++ b/include/libdlo.h
@@ -0,0 +1,766 @@
+/** @file libdlo.h
+ *
+ * @brief This file defines the high-level API for the DisplayLink libdlo library.
+ *
+ * It is a simplified abstraction layer to allow programs to talk to DisplayLink
+ * compatible devices.
+ *
+ * DisplayLink Open Source Software (libdlo)
+ * Copyright (C) 2009, DisplayLink
+ * www.displaylink.com
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by the Free
+ * Software Foundation; LGPL version 2, dated June 1991.
+ *
+ * This library 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 Library General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/** @mainpage DisplayLink Open Source Software (libdlo)
+ * @anchor dlppdoxygenmain
+ *
+ * This documentation covers the DisplayLink Open Source Software (libdlo) library (libdlo).
+ * It covers the following items:
+ *
+ * @li File by file information
+ * @li Function by function information
+ * @li Global variables, defines and structures
+ *
+ * <hr>
+ *
+ * <b>Overview</b>
+ *
+ * <p>
+ * This library is stuctured as illustrated below, in order to help clarify the major
+ * functional areas and simplify the task of porting or reimplementing these functions
+ * to other platforms. At the very least, it should serve as a reference implementation
+ * which can be replaced in its entirety.
+ * </p>
+ *
+ * @image html libdlo.gif "libdlo internal structure"
+ *
+ * <p>
+ * All communications with libdlo are through the API published in libdlo.h. This API
+ * allows third party software to find DisplayLink devices, connect to them, perform
+ * graphical operations and then disconnect as required. There are a number of graphical
+ * primitives available, including rectangle plotting and copying (rectangular) areas of
+ * screen.
+ * </p>
+ *
+ * <hr>
+ * <b>Implementation Notes: Functions</b>
+ *
+ * <p>
+ * There are primarily three types of function used within all of the libdlo sources:
+ * </p>
+ *
+ * @li A void function or non-error returning function
+ * @li A pointer-returning function
+ * @li A function returning a return code
+ *
+ * <p>
+ * Void and non-error returning functions are used in situations where there is no
+ * possibility or an error being raised or where there would be no value in returning it.
+ * Examples might include functions which simply perform a computation or those which
+ * dispose of a structure and are expected to fail silently.
+ * </p>
+ *
+ * <p>
+ * Pointer returning functions will conventionally return a NULL pointer if there is
+ * an error. Normally the error will be due to memory allocation failure (out of
+ * memory) but this is not always the case. As a NULL pointer it not very informative
+ * about the nature of the failure, the use of pointer-returning functions within
+ * libdlo has been kept to a minimum.
+ * </p>
+ *
+ * <p>
+ * The majority of functions return an code of type @a dlo_retcode_t to indicate
+ * success or the nature of failure. All return codes have an associated textual string
+ * so they can be decoded in a human-readable format by calling @c dlo_strerror().
+ * </p>
+ *
+ * <hr>
+ * <b>Implementation Notes: Error Handling</b>
+ *
+ * <p>
+ * In order to keep the handling of errors consistent, there are a number of handy
+ * macros defined in dlo_defs.h. There are a few which collect any non-zero return
+ * value from a given function call and return it from the calling function (there
+ * is also a version of this call which checks for NULL pointer returns and converts
+ * it into an memory allocation failure return code). These macros are:
+ * </p>
+ *
+ * @li @c ERR()
+ * @li @c NERR()
+ * @li @c UERR()
+ *
+ * <p>
+ * A second set of macros are defined which, instead of returning a return code from
+ * the calling function, they store the error in a local variable "err" and jump to
+ * a label called "error". This allows the function to perform whatever tidy-up
+ * operations it needs to before returning "err". These macros are:
+ * </p>
+ *
+ * @li @c ERR_GOTO()
+ * @li @c NERR_GOTO()
+ * @li @c UERR_GOTO()
+ *
+ * <p>
+ * Both of these sets of macros are used throughout the libdlo sources in order to
+ * make the handling of errors consistent.
+ * </p>
+ *
+ * <hr>
+ * Copyright &copy; 2008, DisplayLink
+ * All rights reserved.
+ */
+
+#ifndef DLO_LIBDLO_H
+#define DLO_LIBDLO_H /**< Avoid multiple inclusion. */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include "usb.h"
+
+
+#if 0
+#define dlo_malloc my_malloc
+#define dlo_realloc my_realloc
+#define dlo_free my_free
+
+/** Alternative malloc routine.
+ *
+ * @param size As per @c malloc().
+ *
+ * @return As per @c malloc().
+ */
+extern void *my_malloc(size_t size);
+
+/** Alternative realloc routine.
+ *
+ * @param blk As per @c realloc().
+ * @param size As per @c realloc().
+ *
+ * @return As per @c realloc().
+ */
+extern void *my_realloc(void *blk, size_t size);
+
+/** Alternative free routine.
+ *
+ * @param blk As per @c free().
+ */
+extern void my_free(void *blk);
+
+/** Return total size of allocated blocks.
+ *
+ * @return Size of all current allocations (bytes).
+ */
+extern uint32_t my_used(void);
+#endif
+
+
+/** Allow the use of the standard C library @a malloc() function to be overridden.
+ */
+#ifndef dlo_malloc
+#define dlo_malloc malloc
+#endif
+
+/** Allow the use of the standard C library @a realloc() function to be overridden.
+ */
+#ifndef dlo_realloc
+#define dlo_realloc realloc
+#endif
+
+/** Allow the use of the standard C library @a free() function to be overridden.
+ */
+#ifndef dlo_free
+#define dlo_free free
+#endif
+
+/** Allow the use of the standard C library @a memset() function to be overridden.
+ */
+#ifndef dlo_memset
+#define dlo_memset (void) memset
+#endif
+
+/** Allow the use of the standard C library @a memcpy() function to be overridden.
+ */
+#ifndef dlo_memcpy
+#define dlo_memcpy (void) memcpy
+#endif
+
+/** Allow the use of the standard C library @a memmove() function to be overridden.
+ */
+#ifndef dlo_memmove
+#define dlo_memmove (void) memmove
+#endif
+
+
+/** An opaque device handle. */
+typedef void *dlo_dev_t;
+
+
+/** Return codes used within the libdlo sources. Note: libdlo will never return top-bit-set return
+ * codes so these can safely be allocated within your own programs for your own purposes.
+ *
+ * Return code 0x00000000 represents a successful return without error or warning.
+ * Return codes in the range 0x00000001..0x0FFFFFFF represent an error condition.
+ * Return codes in the range 0x10000000..0x7FFFFFFF represent a warning.
+ * Return codes in the range 0x80000000..0xFFFFFFFF are free for caller allocation.
+ */
+typedef enum
+{
+ /* Success... */
+ dlo_ok = 0u, /**< Successful. */
+ /* Errors... */
+ dlo_err_memory = 1u, /**< A memory claim operation failed; out of memory. */
+ dlo_err_bad_area, /**< An invalid area was specified (e.g. of zero width or height). */
+ dlo_err_bad_col, /**< Unsupported colour depth. */
+ dlo_err_bad_device, /**< Unknown device - has been disconnected or powered down. */
+ dlo_err_bad_fbuf, /**< Null pointer passed as local bitmap data. */
+ dlo_err_bad_fmt, /**< Unsupported bitmap pixel format. */
+ dlo_err_bad_mode, /**< Call to @c set_mode() failed due to unsupported mode parameters. */
+ dlo_err_bad_view, /**< Invalid viewport specified (is screen mode set up?). */
+ dlo_err_big_scrape, /**< Bitmap is too wide for copy buffer.*/
+ dlo_err_buf_full, /**< Command buffer is full. */
+ dlo_err_claimed, /**< Device cannot be claimed - it's already been claimed. */
+ dlo_err_edid_fail, /**< EDID communication with monitor failed. */
+ dlo_err_iic_op, /**< An IIC operation with the device failed. */
+ dlo_err_not_root, /**< Executable should be run as root (e.g. using 'su root' or 'sudo'). */
+ dlo_err_open, /**< Attempt to open a connection to the device failed. */
+ dlo_err_overlap, /**< Source and destination viewports cannot overlap (unless the same). */
+ dlo_err_reenum, /**< Reenumeration required before device can be claimed. */
+ dlo_err_unclaimed, /**< Device cannot be written to: unclaimed. */
+ dlo_err_unsupported, /**< Requested feature is not supported. */
+ dlo_err_usb, /**< A USB-related error: call @c dlo_usb_strerror() for further info. */
+ /* Warnings... */
+ dlo_warn_dl160_mode = 0x10000000u, /**< This screen mode may not display correctly on DL120 devices. */
+ /* User return codes... */
+ dlo_user_example = 0x80000000 /**< Return codes 0x80000000 to 0xFFFFFFFF are free for user allocation. */
+} dlo_retcode_t; /**< Return codes. Used to indicate the success or otherwise of a call to the library. */
+
+
+/** A 32 bits per pixel colour number (0x00bbggrr, little endian). Note: most significant byte is undefined. */
+typedef uint32_t dlo_col32_t;
+
+
+/** Return a 32 bpp colour number when given the three RGB components. */
+#define DLO_RGB(red,grn,blu) (dlo_col32_t)(((red) & 0xFF) | (((grn) & 0xFF) << 8) | (((blu) & 0xFF) << 16))
+
+/** Set the red component (0..255) of a 32 bpp colour. */
+#define DLO_RGB_SETRED(col,red) (dlo_col32_t)(((col) & ~0xFF) | ((red) & 0xFF))
+
+/** Set the green component (0..255) of a 32 bpp colour. */
+#define DLO_RGB_SETGRN(col,grn) (dlo_col32_t)(((col) & ~0xFF00) | (((grn) & 0xFF) << 8))
+
+/** Set the blue component (0..255) of a 32 bpp colour. */
+#define DLO_RGB_SETBLU(col,blu) (dlo_col32_t)(((col) & ~0xFF0000) | (((blu) & 0xFF) << 16))
+
+/** Read the red component (0..255) of a 32 bpp colour. */
+#define DLO_RGB_GETRED(col) (uint8_t)((col) & 0xFF)
+
+/** Read the green component (0..255) of a 32 bpp colour. */
+#define DLO_RGB_GETGRN(col) (uint8_t)(((col) >> 8) & 0xFF)
+
+/** Read the blue component (0..255) of a 32 bpp colour. */
+#define DLO_RGB_GETBLU(col) (uint8_t)(((col) >> 16) & 0xFF)
+
+
+/** Types of DisplayLink device. */
+typedef enum
+{
+ dlo_dev_unknown = 0, /**< Unknown device type. */
+ dlo_dev_base = 0xB, /**< Base platform. */
+ dlo_dev_alex = 0xF, /**< Alex chipset. */
+ dlo_dev_ollie = 0xF1 /**< Ollie chipset. */
+} dlo_devtype_t; /**< A struct @a dlo_devtype_s. */
+
+
+/** A structure containing information about a specific device. */
+typedef struct dlo_devinfo_s
+{
+ dlo_dev_t uid; /**< Unique ID for referencing the device. */
+ char *serial; /**< Pointer to serial number string for device. */
+ dlo_devtype_t type; /**< Device type. */
+ bool claimed; /**< Flag indicating whether someone has claimed the device. */
+} dlo_devinfo_t; /**< A struct @a dlo_devinfo_s. */
+
+
+/** A list of devices, as returned by the enumeration call. */
+typedef struct dlo_devlist_s dlo_devlist_t;
+
+/** A list of devices, as returned by the enumeration call. */
+struct dlo_devlist_s
+{
+ dlo_devlist_t *next; /**< Pointer to next node in the device list (or NULL). */
+ dlo_devinfo_t dev; /**< Device information structure. */
+}; /**< A struct @a dlo_devlist_s. */
+
+
+/** Flags word for the initialisation function (no flags defined at present). */
+typedef struct dlo_init_s
+{
+ unsigned undef :1; /**< Undefined flag (placeholder). */
+} dlo_init_t; /**< A struct @a dlo_init_s. */
+
+
+/** Flags word for the finalisation function (no flags defined at present). */
+typedef struct dlo_final_s
+{
+ unsigned undef :1; /**< Undefined flag (placeholder). */
+} dlo_final_t; /**< A struct @a dlo_final_s. */
+
+
+/** Flags word to configure the device connection (no flags defined at present). */
+typedef struct dlo_claim_s
+{
+ unsigned undef :1; /**< Undefined flag (placeholder). */
+} dlo_claim_t; /**< A struct @a dlo_claim_s. */
+
+
+/** Flags word to configure the @c dlo_copy_host_bmp() call. */
+typedef struct dlo_bmpflags_s
+{
+ unsigned v_flip :1; /**< Vertically flip the bitmap during the copy. */
+} dlo_bmpflags_t; /**< A struct @a dlo_bmpflags_s. */
+
+
+/** Shift (bits) for position of bytes-per-pixel data in pixel format word.
+ */
+#define DLO_PIXFMT_BYPP_SFT (6u)
+
+/** Bit mask for extracting bytes-per-pixel data from pixel format word.
+ */
+#define DLO_PIXFMT_BYPP_MSK (0x7 << DLO_PIXFMT_BYPP_SFT)
+
+/** Shift (bits) for position of red/blue swap flag in pixel format word.
+ */
+#define DLO_PIXFMT_SWP_SFT (9u)
+
+/** Shift (bits) for position of pointer data (most significant bits).
+ */
+#define DLO_PIXFMT_PTR_SFT (10u)
+
+/** Maximum number of pixel format variations.
+ */
+#define DLO_PIXFMT_MAX (1u << DLO_PIXFMT_PTR_SFT)
+
+/** Pixel format has one byte per pixel.
+ */
+#define DLO_PIXFMT_1BYPP (1u << DLO_PIXFMT_BYPP_SFT)
+
+/** Pixel format has two bytes per pixel.
+ */
+#define DLO_PIXFMT_2BYPP (2u << DLO_PIXFMT_BYPP_SFT)
+
+/** Pixel format has three bytes per pixel.
+ */
+#define DLO_PIXFMT_3BYPP (3u << DLO_PIXFMT_BYPP_SFT)
+
+/** Pixel format has four bytes per pixel.
+ */
+#define DLO_PIXFMT_4BYPP (4u << DLO_PIXFMT_BYPP_SFT)
+
+/** Pixel format has red and blue colour components reversed.
+ */
+#define DLO_PIXFMT_SWP (1u << DLO_PIXFMT_SWP_SFT)
+
+/** Supported source pixel format information (e.g. bits per pixel, colour component order, etc).
+ *
+ * Each value in this enum encodes the pixel RGB vs BGR colour component order and
+ * the number of bytes per pixel. There is one function for reading each pixel format
+ * (but the RGB vs BGR is passed in as a flag) and the bytes per pixel is required to
+ * advance the pixel pointer in a framebuffer after a pixel has been read.
+ *
+ * Bits 0..5 contain the pixel format code
+ * Bits 6..8 contain the number of bytes per pixel
+ * Bit 9 contains the swap flag for RGB vs BGR
+ * Bits 10.. if non-zero, then the pixel format is actually a pointer to an 8 bit LUT
+ *
+ * The pixel format can also simply be a pointer to a 256 entry LUT of dlo_col32_t
+ * colours in the case where the local framebuffer contains 8bpp bitmap data which
+ * uses a palette. Simply cast the LUT pointer to a dlo_pixfmt_t (this assumes that
+ * your LUT isn't stored in the bottom 1KB of the logical address space!). E.g.
+ *
+ * static dlo_col32_t mylut[256]; // this is the palette for my 8bpp bitmap
+ * static dlo_pixfmt_t mypixfmt = (dlo_pixfmt_t)mylut;
+ */
+typedef enum
+{
+ dlo_pixfmt_bgr323 = 0 | DLO_PIXFMT_1BYPP, /**< 8 bit per pixel 2_bbbggrrr. */
+ dlo_pixfmt_rgb323 = 0 | DLO_PIXFMT_1BYPP | DLO_PIXFMT_SWP, /**< 8 bit per pixel 2_rrrggbbb. */
+ dlo_pixfmt_bgr565 = 1 | DLO_PIXFMT_2BYPP, /**< 16 bit per pixel 2_bbbbbggggggrrrrr. */
+ dlo_pixfmt_rgb565 = 1 | DLO_PIXFMT_2BYPP | DLO_PIXFMT_SWP, /**< 16 bit per pixel 2_rrrrrggggggbbbbb. */
+ dlo_pixfmt_sbgr1555 = 2 | DLO_PIXFMT_2BYPP, /**< 16 bit per pixel 2_Sbbbbbgggggrrrrr (S is supremacy/transparancy bit). */
+ dlo_pixfmt_srgb1555 = 2 | DLO_PIXFMT_2BYPP | DLO_PIXFMT_SWP, /**< 16 bit per pixel 2_Srrrrrgggggbbbbb (S is supremacy/transparancy bit). */
+ dlo_pixfmt_bgr888 = 3 | DLO_PIXFMT_3BYPP, /**< 24 bit per pixel 0xbbggrr. */
+ dlo_pixfmt_rgb888 = 3 | DLO_PIXFMT_3BYPP | DLO_PIXFMT_SWP, /**< 24 bit per pixel 0xrrggbb. */
+ dlo_pixfmt_abgr8888 = 4 | DLO_PIXFMT_4BYPP, /**< 32 bit per pixel 0xaabbggrr. */
+ dlo_pixfmt_argb8888 = 4 | DLO_PIXFMT_4BYPP | DLO_PIXFMT_SWP /**< 32 bit per pixel 0xaarrggbb. */
+ /* Any value greater than 1023 is assumed to be a pointer to: dlo_col32_t palette[256]
+ * for translating paletted 8 bits per pixel data into colour numbers.
+ */
+} dlo_pixfmt_t; /**< A struct @a dlo_pixfmt_s. */
+
+
+/** A local (host-resident) bitmap or framebuffer. */
+typedef struct dlo_fbuf_s
+{
+ uint16_t width; /**< Width (pixels). */
+ uint16_t height; /**< Height (pixels). */
+ dlo_pixfmt_t fmt; /**< Pixel format (e.g. bits per pixel, colour component order, etc). */
+ void *base; /**< Base address in host memory. */
+ uint32_t stride; /**< Stride (pixels) from a pixel to the one directly below. */
+} dlo_fbuf_t; /**< A struct @a dlo_fbuf_s. */
+
+
+/** An pointer to a location in the DisplayLink device logical memory map. */
+typedef uint32_t dlo_ptr_t;
+
+
+/** A viewport (bitmap) in a contiguous block of device memory.
+ *
+ * A viewport describes the contents of a contiguous block of device memory (of which there
+ * is normally 16 MB available). It represents a rectangular bitmap which may be large
+ * enough to use as a screen mode or of any other non-zero size.
+ *
+ * It is the responsibility of the caller to organise one or more viewports in the device
+ * memory and use the @c dlo_set_mode() call to determine which is visible on the screen
+ * at any given time.
+ *
+ * When a device is first claimed, the EDID data for any connected display will be
+ * read. If successful, then an initial screen mode is set up using the native mode timings
+ * of the display. This will result in an initial viewport being defined at base address 0.
+ * Details of the initial viewport can be discovered by the caller using the
+ * @c dlo_get_mode() call. If no initial mode was set up by libdlo, then the caller must do
+ * so by making an appropriate call to @c dlo_set_mode().
+ *
+ * Setting the screen mode does not result in the screen being cleared; the caller must make
+ * a call to @c dlo_fill_rect() to achieve this, e.g.
+ *
+ * dlo_fill_rect(uid, NULL, NULL, DLO_RGB(0,0,0))
+ *
+ * to clear the whole of the viewport for the current screen mode to black.
+ *
+ * Overlapping viewports should be avoided because they do not include the concept of a
+ * 'stride' (to get from one pixel to the pixel immediately below). They must also have a
+ * base address which starts on a two byte boundary. Aside from these constraints, viewports
+ * can be arranged at any locations within the device memory.
+ *
+ * The caller should not assume anything about the format of the pixels stored in the device
+ * memory or how pixels are arranged within a given viewport's address range. It is safe to
+ * assume that the pixels will require three bytes each (in a 24 bpp viewport) so a viewport
+ * which is 1280 x 1024 pixels in size, starting at base address 0x000000 in the device
+ * memory will end at address 1280*1024*3 = 0x3C0000.
+ *
+ * Thus, the caller may set up two screen banks by maintaining two viewports of the same
+ * dimensions, one starting at base address 0x000000 (for example) and another starting at
+ * base address 0x3C0000 (assuming they are 1280x1024 pixels in size). These two banks can
+ * be plotted to independently of each other and displayed using the @c dlo_set_mode() call.
+ */
+typedef struct dlo_view_s
+{
+ uint16_t width; /**< Width (pixels). */
+ uint16_t height; /**< Height (pixels). */
+ uint8_t bpp; /**< Colour depth (bits per pixel). */
+ dlo_ptr_t base; /**< Base address in the device memory. */
+} dlo_view_t; /**< A struct @a dlo_view_s. */
+
+
+/** Descriptor for reading or setting the current screen mode. */
+typedef struct dlo_mode_s
+{
+ dlo_view_t view; /**< The @a dlo_view_t associated with the screen mode. */
+ uint8_t refresh; /**< Refresh rate (Hz). */
+} dlo_mode_t; /**< A struct @a dlo_mode_s. */
+
+
+/** Co-ordinates of a point/pixel relative to the origin, top-left, of a given @a dlo_view_t. */
+typedef struct dlo_dot_s
+{
+ int32_t x; /**< X co-ordinate of the dot, pixels from left edge of screen (+ve is right). */
+ int32_t y; /**< Y co-ordinate of the dot, pixels down from top edge of screen (-ve is up). */
+} dlo_dot_t; /**< A struct @a dlo_dot_s. */
+
+
+/** A rectangle relative to a given @a dlo_view_t. */
+typedef struct dlo_rect_s
+{
+ dlo_dot_t origin; /**< Origin co-ordinates (top-left of the rectangle). */
+ uint16_t width; /**< Width (pixels) of rectangle (all pixels from origin.x to origin.x+width-1 inclusive). */
+ uint16_t height; /**< Height (pixels) of rectangle (all pixels from origin.y to origin.x+height-1 inclusive). */
+} dlo_rect_t; /**< A struct @a dlo_rect_s. */
+
+
+/** Return the meaning of the specified return code as a human-readable string.
+ *
+ * @param err Return code.
+ *
+ * @return Pointer to zero-terminated (error) message string.
+ *
+ * The string is held in libdlo's static workspace so no attempt should be made
+ * by the caller to free it.
+ */
+extern const char *dlo_strerror(const dlo_retcode_t err);
+
+
+/** Initialisation call for libdlo.
+ *
+ * @param flags Initialisation flags word (unused flags should be zero).
+ *
+ * @return Return code, zero for no error.
+ *
+ * This function must be called by libdlo users before any other functions
+ * are called or they may result in undefined behaviour. It will ignore any
+ * flag bits which it does not currently understand.
+ *
+ * The @a vsn value indicates the library API version number. As the API
+ * defined within this header file is evolved, the API version number will
+ * be incremented.
+ */
+extern dlo_retcode_t dlo_init(const dlo_init_t flags);
+
+
+/** Finalisation call for libdlo.
+ *
+ * @param flags Finalisation flags word (unused flags should be zero).
+ *
+ * @return Return code, zero for no error.
+ *
+ * This function should be called when a program no longer needs to use libdlo
+ * (e.g. when it exits) in order to free up any system resources which have been
+ * claimed by this library. It will ignore any flag bits which it does not
+ * currently understand.
+ */
+extern dlo_retcode_t dlo_final(const dlo_final_t flags);
+
+
+/** Map the caller's pointer to a udev structure from libusb to a unique ID in libdlo.
+ *
+ * @param udev Pointer to USB device structure for given device (from libusb).
+ *
+ * @return Unique ID of the corresponding device for libdlo calls.
+ *
+ * This call is intended for use by a caller that has already used libusb in order
+ * to identify a particular device that they want to connect to.
+ */
+extern dlo_dev_t dlo_lookup_device(struct usb_device *udev);
+
+
+/** Enumerate all connected DisplayLink-compatible devices.
+ *
+ * @return Pointer to linked list of device information structures (or NULL if none).
+ *
+ * This function will return a pointer to one or more @a devlist_t structures if
+ * there are any active DisplayLink compatible devices connected to the computer.
+ * It will return a NULL pointer if none are found or if there was an error during
+ * the enumeration process.
+ *
+ * It is the caller's responsibility to free the memory associated with this list
+ * by calling the @c dlo_free() function on each list item (but not for any
+ * strings pointed to by items in the list, as these strings are maintained by
+ * libdlo).
+ */
+extern dlo_devlist_t *dlo_enumerate_devices(void);
+
+
+/** Claim the specified device.
+ *
+ * @param uid Unique ID of the device to claim.
+ * @param flags Flags word describing how the device is to be accessed.
+ * @param timeout Timeout in milliseconds (zero for infinite).
+ *
+ * @return Unique ID of the claimed device (or NULL if failed).
+ *
+ * Before accessing a device, it should be claimed in order to avoid clashes
+ * where multiple programs are trying to write to the same device (however,
+ * abstraction of that sort would be implemented above this API).
+ *
+ * If the device is connected to a display which supports the EDID standard, then
+ * this call will also attempt to set up the display mode to the native resolution
+ * of the display - equivalent to a call to @c dlo_set_mode(). It will not clear
+ * the screen contents; you should call @c dlo_fill_rect() for that.
+ *
+ * It is possible to specify a @a timeout value for this call. If a non-zero timeout
+ * is specified, the same value will be used for any further calls to the device.
+ * Passing in a zero timeout means that libdlo should use its default timeouts.
+ * The @a timeout value is only used for specific transactions with the device; in
+ * some special cases libdlo will still use its own internal timeout values.
+ *
+ * Devices should be released with a call to @c release_device() when they are no
+ * longer required.
+ */
+extern dlo_dev_t dlo_claim_device(const dlo_dev_t uid, const dlo_claim_t flags, const uint32_t timeout);
+
+
+/** Claim the first available (unclaimed) device.
+ *
+ * @param flags Flags word describing how the device is to be accessed.
+ * @param timeout Timeout in milliseconds (zero for infinite).
+ *
+ * @return Unique ID of the claimed device (or NULL if failed).
+ *
+ * This call performs a very similar function to @c dlo_claim_device() except
+ * that it performs the enumeration of connected devices on behalf of the caller
+ * and returns the unique ID of the first available (unclaimed device). This
+ * device is claimed automatically.
+ *
+ * If no unclaimed devices are found, or if the claim operation itself fails in
+ * some way, the function will return a device handle of zero.
+ */
+extern dlo_dev_t dlo_claim_first_device(const dlo_claim_t flags, const uint32_t timeout);
+
+
+/** Release the specified device.
+ *
+ * @param uid Unique ID of the device to release.
+ *
+ * @return Return code, zero for no error.
+ *
+ * When a program is no longer interested in using a device which it earlier had
+ * claimed, it should release it with this call. This should still be called even
+ * in the case where communications with a device have failed (because the error
+ * may have been temporary). You can ignore errors from this call if you wish.
+ */
+extern dlo_retcode_t dlo_release_device(const dlo_dev_t uid);
+
+
+/** Given the device unique ID, return the associated device information structure.
+ *
+ * @param uid Unique ID of the device to access.
+ *
+ * @return Pointer to device information structure.
+ *
+ * Note: the caller should not attempt to free the returned structure as it is
+ * maintained by libdlo.
+ */
+extern dlo_devinfo_t *dlo_device_info(const dlo_dev_t uid);
+
+
+/** Set the screen mode by selecting the best matching mode available.
+ *
+ * @param uid Unique ID of the device to access.
+ * @param mode Mode descriptor structure pointer.
+ *
+ * @return Return code, zero for no error.
+ *
+ * This function will select a screen mode from the list of those supported by
+ * the specified device (if the display connected to a device supports EDID,
+ * then the supported mode list will be derived from the EDID information).
+ *
+ * The @a mode parameter describes the desired mode parameters, some of which
+ * are optional and may be left as zero/NULL:
+ *
+ * @li width in pixels (always required)
+ * @li height in pixels (or zero to use first available of specified width)
+ * @li colour depth in bits per pixel (currently, only 24 is supported)
+ * @li base address in the device memory (of the origin of the mode's viewport)
+ * @li refresh rate, in Hz (or zero to select the first available)
+ *
+ * This call will not cause the screen area to be cleared to a 'background'
+ * colour.
+ */
+extern dlo_retcode_t dlo_set_mode(const dlo_dev_t uid, const dlo_mode_t * const mode);
+
+
+/** Returns a block of information about the current screen mode.
+ *
+ * @param uid Unique ID of the device to access (or zero).
+ *
+ * @return Pointer to a mode description structure.
+ *
+ * This function will return a pointer to a structure describing the current
+ * screen mode for the specified device. Note: if no mode has been set since
+ * the device was claimed, this structure will be initialised to contain all
+ * zeros.
+ *
+ * Note: the caller should not attempt to free the returned structure as it
+ * is maintained by libdlo.
+ */
+extern dlo_mode_t *dlo_get_mode(const dlo_dev_t uid);
+
+
+/** Plot a filled rectangle into the specified device.
+ *
+ * @param uid Unique ID of the device to access.
+ * @param view Struct pointer: the destination viewport.
+ * @param rec Struct pointer: co-ordinates of rectangle to plot (relative to viewport).
+ * @param col Colour of filled rectangle.
+ *
+ * @return Return code, zero for no error.
+ *
+ * Plot a filled rectangle in the specified colour into a viewport on the device. The
+ * rectangle specified is relative to the viewport's origin and will be clipped if any
+ * parts of it lie outside of the viewport's extent. Setting both @a view and @a rec to
+ * NULL will effectively clear the current screen to the specified colour.
+ *
+ * If @a view is NULL, then the current visible screen is used as the destination viewport.
+ * If @a rec is NULL, then the whole of the destination viewport is filled.
+ */
+extern dlo_retcode_t dlo_fill_rect(const dlo_dev_t uid,
+ const dlo_view_t * const view, const dlo_rect_t * const rec,
+ const dlo_col32_t col);
+
+
+/** Copy a rectangular area within the device from one location to another.
+ *
+ * @param uid Unique ID of the device to access.
+ * @param src_view Struct pointer: source viewport.
+ * @param src_rec Struct pointer: co-ordinates of rectangle to copy (relative to source viewport).
+ * @param dest_view Struct pointer: destination viewport.
+ * @param dest_pos Struct pointer: origin of copy destination (relative to destination viewport).
+ *
+ * @return Return code, zero for no error.
+ *
+ * Copy a rectangular area of pixels from one location in the device to another. The source
+ * and destination rectangles may lie in the same viewport or different viewports - it is up
+ * to the caller to maintain their own list of how the device memory is organised in terms of
+ * viewports.
+ *
+ * The source and destination viewports must not reference overlapping memory regions in the
+ * device, except in the case where both viewports describe exactly the same memory region.
+ * There are no constraints relating to whether or not source and destination rectangles
+ * overlap.
+ *
+ * If @a src_view is NULL, then the current visible screen is used as the source viewport.
+ * If @a src_rec is NULL, then the whole of the source viewport is used as the source rectangle.
+ * If @a dest_view is NULL, then the current visible screen is used as the destination viewport.
+ * If @a dest_pos is NULL, then the origin (top-left) of the destination viewport is used.
+ */
+extern dlo_retcode_t dlo_copy_rect(const dlo_dev_t uid,
+ const dlo_view_t * const src_view, const dlo_rect_t * const src_rec,
+ const dlo_view_t * const dest_view, const dlo_dot_t * const dest_pos);
+
+
+/** Copy (and translate pixel formats) a rectangular area from host memory into the device.
+ *
+ * @param uid Unique ID of the device to access.
+ * @param flags Flags word indicating special behaviour (unused flags should be zero).
+ * @param fbuf Struct pointer: information about source bitmap in host memory.
+ * @param dest_view Struct pointer: destination viewport.
+ * @param dest_pos Struct pointer: origin of copy destination (relative to destination viewport).
+ *
+ * @return Return code, zero for no error.
+ *
+ * Transfer a bitmap held in the host memory to the device. The bitmap is treated as a rectangular
+ * area of pixels, possibly within a larger bitmap/framebuffer and will be plotted at the desired
+ * co-ordinates relative to the origin of the specified viewport. If any part of the bitmap falls
+ * outside of the viewport's extent, the region will be clipped.
+ *
+ * If @a dest_view is NULL, then the current visible screen is used as the destination viewport.
+ * If @a dest_pos is NULL, then the origin (top-left) of the destination viewport is used.
+ */
+extern dlo_retcode_t dlo_copy_host_bmp(const dlo_dev_t uid, const dlo_bmpflags_t flags,
+ const dlo_fbuf_t * const fbuf,
+ const dlo_view_t * const dest_view, const dlo_dot_t * const dest_pos);
+
+
+#endif
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..0de0683
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,36 @@
+
+rootlibdir = $(exec_prefix)/$(libdir_name)
+rootlib_LTLIBRARIES = \
+ libdlo.la
+
+include_HEADERS = \
+ libdlo.h
+
+libdlo_la_SOURCES = \
+ dlo_base.h \
+ dlo_data.h \
+ dlo_defs.h \
+ dlo_grfx.h \
+ dlo_mode.h \
+ dlo_structs.h \
+ dlo_usb.h \
+ dlo_grfx.c \
+ dlo_mode.c \
+ dlo_usb.c \
+ libdlo.c
+
+libdlo_la_LDFLAGS = \
+ -version-info $(LIBDLO_LT_CURRENT):$(LIBDLO_LT_REVISION):$(LIBDLO_LT_AGE) \
+ -export-symbols exported_symbols
+
+pkgconfigdir = $(prefix)/$(libdir_name)/pkgconfig
+pkgconfig_DATA = libdlo.pc
+
+EXTRA_DIST = \
+ exported_symbols
+
+# keep autotools from complaining there is no NEWS file
+AUTOMAKE_OPTIONS = foreign
+
+ACLOCAL_AMFLAGS = -I m4
+
diff --git a/src/dlo_grfx.c b/src/dlo_grfx.c
new file mode 100644
index 0000000..3e9008a
--- /dev/null
+++ b/src/dlo_grfx.c
@@ -0,0 +1,835 @@
+/** @file dlo_grfx.c
+ *
+ * @brief This file implements the graphics primitive operations.
+ *
+ * DisplayLink Open Source Software (libdlo)
+ * Copyright (C) 2009, DisplayLink
+ * www.displaylink.com
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by the Free
+ * Software Foundation; LGPL version 2, dated June 1991.
+ *
+ * This library 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 Library General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <string.h>
+#include "dlo_defs.h"
+#include "dlo_grfx.h"
+#include "dlo_usb.h"
+
+
+/* File-scope defines ------------------------------------------------------------------*/
+
+
+/** Maximum number of pixels that can be supplied to a raw write command. */
+#define RAW_MAX_PIXELS (256)
+
+/** Maximum number of pixels that will fit into the scrape buffer. */
+#define SCRAPE_MAX_PIXELS (2048)
+
+/** Simple wrapper around the @c dlo_free() call to first check the pointer and zero it after the free. */
+#define FREE(ptr) { if (ptr) { dlo_free(ptr); ptr = NULL; } }
+
+/** Return red/green component of a 16 bpp colour number. */
+#define DLO_RG16(red, grn) (uint8_t)((((red) & 0xF8) | ((grn) >> 5)) & 0xFF)
+
+/** Return green/blue component of a 16 bpp colour number. */
+#define DLO_GB16(grn, blu) (uint8_t)(((((grn) & 0x1C) << 3) | ((blu) >> 3)) & 0xFF)
+
+/** Return 8 bpp colour number from red, green and blue components. */
+#define DLO_RGB8(red, grn, blu) ((((red) << 5) | (((grn) & 3) << 3) | ((blu) & 7)) & 0xFF)
+
+
+/* File-scope inline functions ---------------------------------------------------------*/
+
+
+/** Build a "plot horizontal line" command in a buffer.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ * @param base Destination address in device for start of line.
+ * @param remain Line length.
+ * @param col Colour of point to plot.
+ *
+ * @return Return code, zero for no error.
+ */
+inline dlo_retcode_t cmd_hline16(dlo_device_t * const dev, const dlo_ptr_t base, const uint32_t remain, const dlo_col16_t col)
+{
+ if (dev->bufend - dev->bufptr < 9)
+ return dlo_err_buf_full;
+
+ *(dev->bufptr)++ = WRITE_RL16[0];
+ *(dev->bufptr)++ = WRITE_RL16[1];
+ *(dev->bufptr)++ = (char)(base >> 16);
+ *(dev->bufptr)++ = (char)(base >> 8);
+ *(dev->bufptr)++ = (char)base;
+ *(dev->bufptr)++ = (char)remain;
+ *(dev->bufptr)++ = (char)remain;
+ *(dev->bufptr)++ = (char)(col >> 8);
+ *(dev->bufptr)++ = (char)col;
+
+ return dlo_ok;
+}
+
+
+
+/** Build a "plot horizontal line" command in a buffer for fine detail colour space.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ * @param base Destination address in device for start of line.
+ * @param remain Line length.
+ * @param col Colour of point to plot.
+ *
+ * @return Return code, zero for no error.
+ */
+inline dlo_retcode_t cmd_hline8(dlo_device_t * const dev, const dlo_ptr_t base, const uint32_t remain, const dlo_col8_t col)
+{
+ if (dev->bufend - dev->bufptr < 8)
+ return dlo_err_buf_full;
+
+ *(dev->bufptr)++ = WRITE_RL8[0];
+ *(dev->bufptr)++ = WRITE_RL8[1];
+ *(dev->bufptr)++ = (char)(base >> 16);
+ *(dev->bufptr)++ = (char)(base >> 8);
+ *(dev->bufptr)++ = (char)base;
+ *(dev->bufptr)++ = (char)remain;
+ *(dev->bufptr)++ = (char)remain;
+ *(dev->bufptr)++ = (char)col;
+
+ return dlo_ok;
+}
+
+
+/** Build a "copy horizontal line" command in a buffer.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ * @param src Source address in device for start of copy.
+ * @param len Copy length.
+ * @param dest Destination address in device for copy.
+ *
+ * @return Return code, zero for no error.
+ */
+inline dlo_retcode_t cmd_copy16(dlo_device_t * const dev, const dlo_ptr_t src, const uint32_t len, const dlo_ptr_t dest)
+{
+ if (dev->bufend - dev->bufptr < 9)
+ return dlo_err_buf_full;
+
+ *(dev->bufptr)++ = WRITE_COPY16[0];
+ *(dev->bufptr)++ = WRITE_COPY16[1];
+ *(dev->bufptr)++ = (char)(dest >> 16);
+ *(dev->bufptr)++ = (char)(dest >> 8);
+ *(dev->bufptr)++ = (char)dest;
+ *(dev->bufptr)++ = len == 256 ? '\0' : (char)len;
+ *(dev->bufptr)++ = (char)(src >> 16);
+ *(dev->bufptr)++ = (char)(src >> 8);
+ *(dev->bufptr)++ = (char)src;
+
+ return dlo_ok;
+}
+
+
+/** Build a "copy horizontal line" command in a buffer for fine detail colour space.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ * @param src Source address in device for start of copy.
+ * @param len Copy length.
+ * @param dest Destination address in device for copy.
+ *
+ * @return Return code, zero for no error.
+ */
+inline dlo_retcode_t cmd_copy8(dlo_device_t * const dev, const dlo_ptr_t src, const uint32_t len, const dlo_ptr_t dest)
+{
+ if (dev->bufend - dev->bufptr < 9)
+ return dlo_err_buf_full;
+
+ *(dev->bufptr)++ = WRITE_COPY8[0];
+ *(dev->bufptr)++ = WRITE_COPY8[1];
+ *(dev->bufptr)++ = (char)(dest >> 16);
+ *(dev->bufptr)++ = (char)(dest >> 8);
+ *(dev->bufptr)++ = (char)dest;
+ *(dev->bufptr)++ = len == 256 ? '\0' : (char)len;
+ *(dev->bufptr)++ = (char)(src >> 16);
+ *(dev->bufptr)++ = (char)(src >> 8);
+ *(dev->bufptr)++ = (char)src;
+
+ return dlo_ok;
+}
+
+
+/* Ensure the inline functions get compiled somewhere in case they cannot be inlined */
+extern dlo_retcode_t cmd_hline16(dlo_device_t * const dev, const dlo_ptr_t base, const uint32_t remain, const dlo_col16_t col);
+extern dlo_retcode_t cmd_hline8( dlo_device_t * const dev, const dlo_ptr_t base, const uint32_t remain, const dlo_col8_t col);
+extern dlo_retcode_t cmd_copy16( dlo_device_t * const dev, const dlo_ptr_t src, const uint32_t len, const dlo_ptr_t dest);
+extern dlo_retcode_t cmd_copy8( dlo_device_t * const dev, const dlo_ptr_t src, const uint32_t len, const dlo_ptr_t dest);
+
+
+/* File-scope types --------------------------------------------------------------------*/
+
+
+/** Function pointer for functions to convert a pixel into a colour number.
+ *
+ * @param ptr Pointer to pixel.
+ * @param swap Flag to indicate red and blue components need to be swapped.
+ *
+ * @return Colour number for read pixel.
+ */
+typedef dlo_col32_t (*read_pixel_t) (const uint8_t * const ptr, const bool swap);
+
+
+/* File-scope variables ----------------------------------------------------------------*/
+
+
+/** Look-up table of function pointers for a specified pixel format.
+ */
+static read_pixel_t fmt_to_fn[DLO_PIXFMT_MAX];
+
+
+/** Standard look-up table for converting 8 bpp pixels in bgr323 format into colour numbers.
+ */
+static dlo_col32_t lut8bpp[256];
+
+
+/** Look-up table to use when reading 8 bpp pixels - required by @c read_pixel_323().
+ */
+static dlo_col32_t *lut = lut8bpp;
+
+
+/** Pointer to an array for storing a stripe of 16bpp pixel information.
+ */
+static dlo_col16_t *stripe16 = NULL;
+
+
+/** Pointer to an array for storing a stripe of 8bpp pixel information.
+ */
+static dlo_col8_t *stripe8 = NULL;
+
+
+/* External-scope variables ------------------------------------------------------------*/
+
+
+/* File-scope function declarations ----------------------------------------------------*/
+
+
+/** Plot a section of horizontal line in the specified colour at 24 bpp.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ * @param base16 Base address of destination 16 bpp pixel data.
+ * @param base8 Base address of destination 8 bpp pixel data.
+ * @param len Length of the line (pixels).
+ * @param col Colour of the line.
+ *
+ * @return Return code, zero for no error.
+ */
+static dlo_retcode_t hline_24bpp(dlo_device_t * const dev, dlo_ptr_t base16, dlo_ptr_t base8, const uint32_t len, const dlo_col32_t col);
+
+
+/** Copy a section of horizontal line from one location to another at 24 bpp.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ * @param src_base16 Base address of source 16 bpp pixel data.
+ * @param dest_base16 Base address of destination 16 bpp pixel data.
+ * @param src_base8 Base address of source 8 bpp pixel data.
+ * @param dest_base8 Base address of destination 8 bpp pixel data.
+ * @param len Length of the line (pixels).
+ *
+ * @return Return code, zero for no error.
+ */
+static dlo_retcode_t copy_24bpp(dlo_device_t * const dev, dlo_ptr_t src_base16, dlo_ptr_t dest_base16, dlo_ptr_t src_base8, dlo_ptr_t dest_base8, const uint32_t len);
+
+
+/** Scrape a horizontal line of host-resident pixels at 24 bpp into the device.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ * @param rdpx Pointer to the pixel reading function.
+ * @param bypp Bytes per pixel of the source pixels.
+ * @param swap Flag: swap the red/blue component order.
+ * @param src_base Base address of the source.
+ * @param dest_base16 Base address of destination 16 bpp pixel data.
+ * @param dest_base8 Base address of destination 8 bpp pixel data.
+ * @param width Width of the scrape (pixels).
+ *
+ * @return Return code, zero for no error.
+ */
+static dlo_retcode_t scrape_24bpp(dlo_device_t * const dev, const read_pixel_t rdpx, const uint32_t bypp, const bool swap,
+ const uint8_t *src_base, dlo_ptr_t dest_base16, dlo_ptr_t dest_base8, const uint32_t width);
+
+
+/** Dump the contents of the scrape buffers as a horizontal pixel row at 24 bpp.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ * @param base16 Base address of destination 16 bpp pixel data.
+ * @param base8 Base address of destination 8 bpp pixel data.
+ * @param width Width of the scrape (pixels).
+ *
+ * @return Return code, zero for no error.
+ */
+static dlo_retcode_t cmd_stripe24(dlo_device_t * const dev, dlo_ptr_t base16, dlo_ptr_t base8, const uint32_t width);
+
+
+/** Given a 32 bpp colour number, return an 8 bpp colour number.
+ *
+ * @param col 32 bpp colour number.
+ *
+ * @return 8 bpp colour number.
+ */
+static dlo_col8_t rgb8(dlo_col32_t col);
+
+
+/** Given a 32 bpp colour number, return a 16 bpp colour number.
+ *
+ * @param col 32 bpp colour number.
+ *
+ * @return 16 bpp colour number.
+ */
+static dlo_col16_t rgb16(dlo_col32_t col);
+
+
+/** Dummy pixel reading function for an uninitialised entry.
+ *
+ * @param ptr Pointer to pixel.
+ * @param swap Flag to indicate red and blue components need to be swapped.
+ *
+ * @return Colour number for read pixel.
+ */
+static dlo_col32_t read_pixel_NULL(const uint8_t * const ptr, const bool swap);
+
+
+/** Read an 8 bpp pixel in 323 format.
+ *
+ * @param ptr Pointer to pixel.
+ * @param swap Flag to indicate red and blue components need to be swapped.
+ *
+ * @return Colour number for read pixel.
+ */
+static dlo_col32_t read_pixel_323(const uint8_t * const ptr, const bool swap);
+
+
+/** Read a 16 bpp pixel in 565 format.
+ *
+ * @param ptr Pointer to pixel.
+ * @param swap Flag to indicate red and blue components need to be swapped.
+ *
+ * @return Colour number for read pixel.
+ */
+static dlo_col32_t read_pixel_565(const uint8_t * const ptr, const bool swap);
+
+
+/** Read a 16 bpp pixel in 1555 format.
+ *
+ * @param ptr Pointer to pixel.
+ * @param swap Flag to indicate red and blue components need to be swapped.
+ *
+ * @return Colour number for read pixel.
+ */
+static dlo_col32_t read_pixel_1555(const uint8_t * const ptr, const bool swap);
+
+
+/** Read a 24 bpp pixel in 888 format.
+ *
+ * @param ptr Pointer to pixel.
+ * @param swap Flag to indicate red and blue components need to be swapped.
+ *
+ * @return Colour number for read pixel.
+ */
+static dlo_col32_t read_pixel_888(const uint8_t * const ptr, const bool swap);
+
+
+/** Read a 32 bpp pixel in 8888 format.
+ *
+ * @param ptr Pointer to pixel.
+ * @param swap Flag to indicate red and blue components need to be swapped.
+ *
+ * @return Colour number for read pixel.
+ */
+static dlo_col32_t read_pixel_8888(const uint8_t * const ptr, const bool swap);
+
+
+/* Public function definitions ---------------------------------------------------------*/
+
+
+dlo_retcode_t dlo_grfx_init(const dlo_init_t flags)
+{
+ uint32_t i;
+ uint8_t red, grn, blu;
+ uint8_t red8, grn8, blu8;
+
+ stripe16 = malloc(SCRAPE_MAX_PIXELS * sizeof(dlo_col16_t));
+ NERR(stripe16);
+ stripe8 = malloc(SCRAPE_MAX_PIXELS * sizeof(dlo_col8_t));
+ NERR(stripe8);
+
+ /* Initialise the default look-up table for 8 bpp in bgr323 format */
+ for (red = 0; red < 8; red++)
+ for (grn = 0; grn < 4; grn++)
+ for (blu = 0; blu < 8; blu++)
+ {
+ uint8_t idx = red + (grn << 3) + (blu << 5);
+
+ red8 = (red << 5) | (red << 2) | (red >> 1);
+ grn8 = (grn << 6) | (grn << 4) | (grn << 2) | grn;
+ blu8 = (blu << 5) | (blu << 2) | (blu >> 1);
+ lut8bpp[idx] = DLO_RGB(red8, grn8, blu8);
+ }
+
+ /* Initialise the look-up table of pixel formats to pixel reading functions */
+ for (i = 0; i < DLO_PIXFMT_MAX; i++)
+ fmt_to_fn[i] = read_pixel_NULL;
+ fmt_to_fn[dlo_pixfmt_bgr323] = read_pixel_323;
+ fmt_to_fn[dlo_pixfmt_rgb323] = read_pixel_323;
+ fmt_to_fn[dlo_pixfmt_bgr565] = read_pixel_565;
+ fmt_to_fn[dlo_pixfmt_rgb565] = read_pixel_565;
+ fmt_to_fn[dlo_pixfmt_sbgr1555] = read_pixel_1555;
+ fmt_to_fn[dlo_pixfmt_srgb1555] = read_pixel_1555;
+ fmt_to_fn[dlo_pixfmt_bgr888] = read_pixel_888;
+ fmt_to_fn[dlo_pixfmt_rgb888] = read_pixel_888;
+ fmt_to_fn[dlo_pixfmt_abgr8888] = read_pixel_8888;
+ fmt_to_fn[dlo_pixfmt_argb8888] = read_pixel_8888;
+
+ return dlo_ok;
+}
+
+
+dlo_retcode_t dlo_grfx_final(const dlo_final_t flags)
+{
+ FREE(stripe16);
+ FREE(stripe8);
+
+ return dlo_ok;
+}
+
+
+dlo_retcode_t dlo_grfx_fill_rect(dlo_device_t * const dev, const dlo_area_t * const area, const dlo_col32_t col)
+{
+ dlo_ptr_t base16, base8;
+ uint32_t end;
+
+ ASSERT(dev && area)
+ ASSERT(area->view.width && area->view.height);
+
+ /* Only 24 bpp is supported */
+ if (area->view.bpp != 24)
+ return dlo_err_bad_col;
+
+ /* Compute some useful values */
+ base16 = area->view.base;
+ base8 = area->base8;
+ end = base16 + (BYTES_PER_16BPP * area->stride * area->view.height);
+
+ /* Plot the rectangle, one pixel row at a time */
+ for (; base16 < end; base16 += BYTES_PER_16BPP * area->stride)
+ {
+ ERR(hline_24bpp(dev, base16, base8, area->view.width, col));
+ base8 += BYTES_PER_8BPP * area->stride;
+ }
+ return dlo_usb_write(dev);
+}
+
+
+dlo_retcode_t dlo_grfx_copy_rect(dlo_device_t * const dev, const dlo_area_t * const src_area, const dlo_area_t * const dest_area, const bool overlap)
+{
+ dlo_ptr_t src_base16, src_base8;
+ dlo_ptr_t dest_base16, dest_base8;
+ uint32_t end;
+
+ ASSERT(dev && src_area && dest_area);
+ ASSERT(src_area->view.width && src_area->view.height);
+ ASSERT(src_area->view.width == dest_area->view.width && src_area->view.height == dest_area->view.height);
+ ASSERT(src_area->view.bpp == dest_area->view.bpp);
+
+ /* Only 24 bpp is supported */
+ if (src_area->view.bpp != 24)
+ return dlo_err_bad_col;
+
+ /* Quick exit if we're copying to and from the same location */
+ if (src_area->view.base == dest_area->view.base)
+ return dlo_ok;
+
+ /* Compute some useful values */
+ if (src_area->view.base < dest_area->view.base)
+ {
+ uint32_t y;
+
+ src_base16 = src_area->view.base + (BYTES_PER_16BPP * src_area->stride * src_area->view.height);
+ src_base8 = src_area->base8 + (BYTES_PER_8BPP * src_area->stride * src_area->view.height);
+ dest_base16 = dest_area->view.base + (BYTES_PER_16BPP * dest_area->stride * dest_area->view.height);
+ dest_base8 = dest_area->base8 + (BYTES_PER_8BPP * dest_area->stride * dest_area->view.height);
+
+ /* Copy the rectangle, one pixel row at a time */
+ for (y = src_area->view.height; y > 0; y--)
+ {
+ src_base16 -= BYTES_PER_16BPP * src_area->stride;
+ src_base8 -= BYTES_PER_8BPP * src_area->stride;
+ dest_base16 -= BYTES_PER_16BPP * dest_area->stride;
+ dest_base8 -= BYTES_PER_8BPP * dest_area->stride;
+ ERR(copy_24bpp(dev, src_base16, dest_base16, src_base8, dest_base8, src_area->view.width));
+// if (overlap)
+// ERR(dlo_usb_write(dev));
+ }
+ }
+ else
+ {
+ src_base16 = src_area->view.base;
+ src_base8 = src_area->base8;
+ dest_base16 = dest_area->view.base;
+ dest_base8 = dest_area->base8;
+ end = src_base16 + (BYTES_PER_16BPP * src_area->stride * src_area->view.height);
+
+ /* Copy the rectangle, one pixel row at a time */
+ for (; src_base16 < end; src_base16 += BYTES_PER_16BPP * src_area->stride)
+ {
+ ERR(copy_24bpp(dev, src_base16, dest_base16, src_base8, dest_base8, src_area->view.width));
+ src_base8 += BYTES_PER_8BPP * src_area->stride;
+ dest_base16 += BYTES_PER_16BPP * dest_area->stride;
+ dest_base8 += BYTES_PER_8BPP * dest_area->stride;
+// if (overlap)
+// ERR(dlo_usb_write(dev));
+ }
+ }
+ return dlo_usb_write(dev);
+}
+
+
+dlo_retcode_t dlo_grfx_copy_host_bmp(dlo_device_t * const dev, const dlo_bmpflags_t flags, const dlo_fbuf_t const *fbuf, const dlo_area_t * const area)
+{
+ uint8_t *src_base;
+ uint8_t *end;
+ dlo_ptr_t dest_base16, dest_base8;
+ uint32_t bypp;
+ read_pixel_t rdpx;
+ bool swap;
+
+ ASSERT(dev && fbuf && area);
+ ASSERT(fbuf->width && fbuf->height && fbuf->base && fbuf->stride);
+ ASSERT(fbuf->width == area->view.width && fbuf->height == area->view.height)
+
+ /* Only 24 bpp is supported */
+ if (area->view.bpp != 24)
+ return dlo_err_bad_col;
+
+ /* Get a pixel reading function pointer for the fbuf */
+ if (fbuf->fmt >> DLO_PIXFMT_PTR_SFT)
+ {
+ bypp = 1;
+ rdpx = read_pixel_323;
+ swap = false;
+ lut = (dlo_col32_t *)fbuf->fmt;
+ }
+ else
+ {
+ if ((int)fbuf->fmt > (int)dlo_pixfmt_argb8888)
+ return dlo_err_bad_fmt;
+
+ bypp = FORMAT_TO_BYTES_PER_PIXEL(fbuf->fmt);
+ rdpx = fmt_to_fn[fbuf->fmt];
+ swap = fbuf->fmt & DLO_PIXFMT_SWP ? true : false;
+ lut = lut8bpp; /* For unpaletted bitmaps, the LUT is our standard colour palette */
+ }
+
+ /* Check that a row from the bitmap will fit into the scrape buffers */
+ if (fbuf->width > SCRAPE_MAX_PIXELS)
+ return dlo_err_big_scrape;
+
+ /* Set up the destination pointers in the device memory */
+ dest_base16 = area->view.base;
+ dest_base8 = area->base8;
+
+ /* Either copy down or up the bitmap, depending upon whether we are doing a vertical flip */
+ if (flags.v_flip)
+ {
+ src_base = (uint8_t *)fbuf->base + (bypp * fbuf->stride * (area->view.height - 1));
+ end = (uint8_t *)fbuf->base;
+
+ for (; src_base >= end; src_base -= bypp * fbuf->stride)
+ {
+ ERR(scrape_24bpp(dev, rdpx, bypp, swap, src_base, dest_base16, dest_base8, fbuf->width));
+ dest_base16 += BYTES_PER_16BPP * area->stride;
+ dest_base8 += BYTES_PER_8BPP * area->stride;
+ }
+ }
+ else
+ {
+ src_base = (uint8_t *)fbuf->base;
+ end = src_base + (bypp * fbuf->stride * area->view.height);
+
+ for (; src_base < end; src_base += bypp * fbuf->stride)
+ {
+ ERR(scrape_24bpp(dev, rdpx, bypp, swap, src_base, dest_base16, dest_base8, fbuf->width));
+ dest_base16 += BYTES_PER_16BPP * area->stride;
+ dest_base8 += BYTES_PER_8BPP * area->stride;
+ }
+ }
+ return dlo_usb_write(dev);
+}
+
+
+/* File-scope function definitions -----------------------------------------------------*/
+
+
+static dlo_retcode_t hline_24bpp(dlo_device_t * const dev, dlo_ptr_t base16, dlo_ptr_t base8, const uint32_t len, const dlo_col32_t col)
+{
+ dlo_col16_t col16 = rgb16(col);
+ dlo_col8_t col8 = rgb8(col);
+ uint32_t rem = len % 256;
+
+ /* Flush the command buffer if it's getting full */
+ if (dev->bufend - dev->bufptr < BUF_HIGH_WATER_MARK)
+ ERR(dlo_usb_write(dev));
+
+ /* Is this a short line segment? */
+ if (len < 256)
+ {
+ ERR(cmd_hline16(dev, base16, len, col16));
+ ERR(cmd_hline8( dev, base8, len, col8));
+ }
+ else
+ {
+ /* Longer line segments require a few commands to complete */
+ uint32_t roff16 = base16 + (BYTES_PER_16BPP * (len - rem));
+ uint32_t roff8 = base8 + (BYTES_PER_8BPP * (len - rem));
+
+ for (; base16 < roff16; base16 += BYTES_PER_16BPP * 256)
+ {
+ ERR(cmd_hline16(dev, base16, 0, col16));
+ ERR(cmd_hline8( dev, base8, 0, col8));
+ base8 += BYTES_PER_8BPP * 256;
+ }
+ if (rem)
+ {
+ ERR(cmd_hline16(dev, roff16, rem, col16));
+ ERR(cmd_hline8( dev, roff8, rem, col8));
+ }
+ }
+ return dlo_ok;
+}
+
+
+static dlo_retcode_t copy_24bpp(dlo_device_t * const dev, dlo_ptr_t src_base16, dlo_ptr_t dest_base16, dlo_ptr_t src_base8, dlo_ptr_t dest_base8, const uint32_t len)
+{
+ uint32_t rem = len % 256;
+
+ /* Flush the command buffer if it's getting full */
+ if (dev->bufend - dev->bufptr < BUF_HIGH_WATER_MARK)
+ ERR(dlo_usb_write(dev));
+
+ /* Is this a short line segment? */
+ if (len < 256)
+ {
+ ERR(cmd_copy16(dev, src_base16, len, dest_base16));
+ ERR(cmd_copy8( dev, src_base8, len, dest_base8));
+ }
+ else
+ {
+ /* Longer line segments require a few commands to complete */
+ uint32_t src_roff16 = src_base16 + (BYTES_PER_16BPP * (len - rem));
+ uint32_t dest_roff16 = dest_base16 + (BYTES_PER_16BPP * (len - rem));
+ uint32_t src_roff8 = src_base8 + (BYTES_PER_8BPP * (len - rem));
+ uint32_t dest_roff8 = dest_base8 + (BYTES_PER_8BPP * (len - rem));
+
+ for (; src_base16 < src_roff16; src_base16 += BYTES_PER_16BPP * 256)
+ {
+ ERR(cmd_copy16(dev, src_base16, 0, dest_base16));
+ ERR(cmd_copy8( dev, src_base8, 0, dest_base8));
+ dest_base16 += BYTES_PER_16BPP * 256;
+ src_base8 += BYTES_PER_8BPP * 256;
+ dest_base8 += BYTES_PER_8BPP * 256;
+ }
+ if (rem)
+ {
+ ERR(cmd_copy16(dev, src_roff16, rem, dest_roff16));
+ ERR(cmd_copy8( dev, src_roff8, rem, dest_roff8));
+ }
+ }
+ return dlo_ok;
+}
+
+
+static dlo_retcode_t scrape_24bpp(dlo_device_t * const dev, const read_pixel_t rdpx, const uint32_t bypp, const bool swap,
+ const uint8_t *src_base, dlo_ptr_t dest_base16, dlo_ptr_t dest_base8, const uint32_t width)
+{
+ const uint8_t *end = src_base + (bypp * width);
+ dlo_col16_t *ptr_col16 = stripe16;
+ dlo_col8_t *ptr_col8 = stripe8;
+
+ /* Read a stripe from the source bitmap into the internal colour format */
+ for (; src_base < end; src_base += bypp)
+ {
+ dlo_col32_t col = rdpx(src_base, swap);
+
+ *ptr_col16++ = rgb16(col);
+ *ptr_col8++ = rgb8(col);
+ }
+ return cmd_stripe24(dev, dest_base16, dest_base8, width);
+}
+
+
+static dlo_retcode_t cmd_stripe24(dlo_device_t * const dev, dlo_ptr_t base16, dlo_ptr_t base8, const uint32_t width)
+{
+ dlo_col16_t *ptr_col16 = stripe16;
+ dlo_col8_t *ptr_col8 = stripe8;
+ dlo_ptr_t end = base16 + (BYTES_PER_16BPP * width);
+ uint32_t rem = width;
+ uint32_t pix;
+
+ /* Flush the command buffer if it's getting full */
+ if (dev->bufend - dev->bufptr < BUF_HIGH_WATER_MARK)
+ ERR(dlo_usb_write(dev));
+
+ for (; base16 < end; base16 += BYTES_PER_16BPP * RAW_MAX_PIXELS)
+ {
+ *(dev->bufptr)++ = WRITE_RAW16[0];
+ *(dev->bufptr)++ = WRITE_RAW16[1];
+ *(dev->bufptr)++ = (char)(base16 >> 16);
+ *(dev->bufptr)++ = (char)(base16 >> 8);
+ *(dev->bufptr)++ = (char)(base16 & 0xFF);
+ *(dev->bufptr)++ = rem >= RAW_MAX_PIXELS ? 0 : rem;
+
+ for (pix = 0; pix < (rem >= RAW_MAX_PIXELS ? RAW_MAX_PIXELS : rem); pix++)
+ {
+ dlo_col16_t col = *ptr_col16++;
+
+ *(dev->bufptr)++ = (char)(col >> 8);
+ *(dev->bufptr)++ = (char)(col & 0xFF);
+ }
+ rem -= RAW_MAX_PIXELS;
+ }
+
+ end = base8 + (BYTES_PER_8BPP * width);
+
+ for (; base8 < end; base8 += BYTES_PER_8BPP * RAW_MAX_PIXELS)
+ {
+ *(dev->bufptr)++ = WRITE_RAW8[0];
+ *(dev->bufptr)++ = WRITE_RAW8[1];
+ *(dev->bufptr)++ = (char)(base8 >> 16);
+ *(dev->bufptr)++ = (char)(base8 >> 8);
+ *(dev->bufptr)++ = (char)(base8 & 0xFF);
+ *(dev->bufptr)++ = rem >= RAW_MAX_PIXELS ? 0 : rem;
+
+ for (pix = 0; pix < (rem >= RAW_MAX_PIXELS ? RAW_MAX_PIXELS : rem); pix++)
+ *(dev->bufptr)++ = (char)(*ptr_col8++);
+
+ rem -= RAW_MAX_PIXELS;
+ }
+ return dlo_ok;
+}
+
+
+static dlo_col32_t read_pixel_NULL(const uint8_t * const ptr, const bool swap)
+{
+ DPRINTF("grfx: WARNING: unknown dlo_pixfmt_t doesn't map to a read_pixel_*() function\n");
+ return DLO_RGB(0, 0, 0);
+}
+
+
+static dlo_col32_t read_pixel_323(const uint8_t * const ptr, const bool swap)
+{
+ dlo_col32_t col = lut[*ptr];
+
+ if (swap)
+ {
+ uint8_t red, grn, blu;
+
+ red = DLO_RGB_GETRED(col);
+ grn = DLO_RGB_GETGRN(col);
+ blu = DLO_RGB_GETBLU(col);
+ return DLO_RGB(blu, grn, red);
+ }
+ return col;
+}
+
+
+static dlo_col32_t read_pixel_565(const uint8_t * const ptr, const bool swap)
+{
+ dlo_col32_t col;
+ uint16_t *pix = (uint16_t *)ptr;
+ uint8_t red, grn, blu;
+
+ col = *pix;
+ red = (col & 0x001F) << 3;
+ grn = (col & 0x07E0) >> 3;
+ blu = (col & 0xF800) >> 8;
+ red = red | (red >> 5);
+ grn = grn | (grn >> 5);
+ blu = blu | (blu >> 5);
+
+ return swap ? DLO_RGB(blu, grn, red) : DLO_RGB(red, grn, blu);
+}
+
+
+static dlo_col32_t read_pixel_1555(const uint8_t * const ptr, const bool swap)
+{
+ dlo_col32_t col;
+ uint16_t *pix = (uint16_t *)ptr;
+ uint8_t red, grn, blu;
+
+ col = *pix;
+ red = (col & 0x001F) << 3;
+ grn = (col & 0x03E0) >> 2;
+ blu = (col & 0x7C00) >> 7;
+ red = red | (red >> 5);
+ grn = grn | (grn >> 5);
+ blu = blu | (blu >> 5);
+
+ return swap ? DLO_RGB(blu, grn, red) : DLO_RGB(red, grn, blu);
+}
+
+
+static dlo_col32_t read_pixel_888(const uint8_t * const ptr, const bool swap)
+{
+ uint8_t red, grn, blu;
+
+ red = ptr[0];
+ grn = ptr[1];
+ blu = ptr[2];
+
+ return swap ? DLO_RGB(blu, grn, red) : DLO_RGB(red, grn, blu);
+}
+
+
+static dlo_col32_t read_pixel_8888(const uint8_t * const ptr, const bool swap)
+{
+ dlo_col32_t col;
+ uint32_t *pix = (uint32_t *)ptr;
+
+ col = (dlo_col32_t) *pix;
+
+ if (swap)
+ {
+ uint8_t red, grn, blu;
+
+ red = DLO_RGB_GETRED(col);
+ grn = DLO_RGB_GETGRN(col);
+ blu = DLO_RGB_GETBLU(col);
+ return DLO_RGB(blu, grn, red);
+ }
+ return col;
+}
+
+
+static dlo_col8_t rgb8(dlo_col32_t col)
+{
+ uint8_t red = DLO_RGB_GETRED(col);
+ uint8_t grn = DLO_RGB_GETGRN(col);
+ uint8_t blu = DLO_RGB_GETBLU(col);
+
+ return DLO_RGB8(red, grn, blu);
+}
+
+
+static dlo_col16_t rgb16(dlo_col32_t col)
+{
+ uint8_t red = DLO_RGB_GETRED(col);
+ uint8_t grn = DLO_RGB_GETGRN(col);
+ uint8_t blu = DLO_RGB_GETBLU(col);
+
+ return (DLO_RG16(red, grn) << 8) + DLO_GB16(grn, blu);
+}
+
+
+/* End of file -------------------------------------------------------------------------*/
diff --git a/src/dlo_mode.c b/src/dlo_mode.c
new file mode 100644
index 0000000..68d27a4
--- /dev/null
+++ b/src/dlo_mode.c
@@ -0,0 +1,926 @@
+/** @file dlo_mode.c
+ *
+ * @brief Implementation of the screen mode-related functions.
+ *
+ * See dlo_mode.h for more information.
+ *
+ * DisplayLink Open Source Software (libdlo)
+ * Copyright (C) 2009, DisplayLink
+ * www.displaylink.com
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by the Free
+ * Software Foundation; LGPL version 2, dated June 1991.
+ *
+ * This library 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 Library General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "dlo_defs.h"
+#include "dlo_mode.h"
+#include "dlo_data.h"
+#include "dlo_usb.h"
+
+
+/* File-scope defines ------------------------------------------------------------------*/
+
+
+/** Pre-defined EDID header used to check that data read from a device is valid.
+ */
+const uint8_t header[8] =
+{
+ 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00
+};
+
+/** Constant used for deciding if a host is big- or little endian.
+ */
+const uint32_t endian = 1;
+
+/** Unlock video registers command.
+ */
+#define WRITE_VIDREG_LOCK "\xAF\x20\xFF\x00"
+
+/** Lock video registers command.
+ */
+#define WRITE_VIDREG_UNLOCK "\xAF\x20\xFF\xFF\xAF\xA0"
+
+/** Return non-zero if the host is big endian or zero if the host is little endian.
+ */
+#define IS_BIGENDIAN() ((*(char*)&endian) == '\0')
+
+/** Convert a 32 bit little endian value into a host byte-order value.
+ *
+ * @param val Little-endian 32 bit value to convert.
+ *
+ * @return Value in host byte order.
+ */
+#define LETOHL(val) (IS_BIGENDIAN() ? swap_endian_l(val) : val)
+
+/** Convert a 16 bit little endian value into a host byte-order value.
+ *
+ * @param val Little-endian 16 bit value to convert.
+ *
+ * @return Value in host byte order.
+ */
+#define LETOHS(val) (IS_BIGENDIAN() ? swap_endian_s(val) : val)
+
+/** Initialise a @a dlo_mode_data array entry.
+ *
+ * @param idx Array index.
+ * @param mwidth Mode width (pixels).
+ * @param mheight Mode height (pixels).
+ * @param mrefresh Mode refresh rate (Hz).
+ * @param mbpp Mode colour depth (bits per pixel).
+ */
+#define init_mode(idx, mwidth, mheight, mrefresh, mbpp) \
+{ \
+ dlo_mode_data[idx].width = mwidth; \
+ dlo_mode_data[idx].height = mheight; \
+ dlo_mode_data[idx].refresh = mrefresh; \
+ dlo_mode_data[idx].bpp = mbpp; \
+ dlo_mode_data[idx].data = DLO_MODE_DATA_##mwidth##_##mheight##_##mrefresh##_##mbpp##_0; \
+ dlo_mode_data[idx].data_sz = DSIZEOF(DLO_MODE_DATA_##mwidth##_##mheight##_##mrefresh##_##mbpp##_0); \
+ dlo_mode_data[idx].mode_en = DLO_MODE_ENABLE_##mwidth##_##mheight##_##mrefresh##_##mbpp##_0; \
+ dlo_mode_data[idx].mode_en_sz = DSIZEOF(DLO_MODE_ENABLE_##mwidth##_##mheight##_##mrefresh##_##mbpp##_0); \
+ dlo_mode_data[idx].low_blank = false; \
+}
+
+
+/* External-scope inline functions -----------------------------------------------------*/
+
+
+/** Swap the endianness of a long (four byte) integer.
+ *
+ * @param val Integer to alter.
+ *
+ * @return Value with swapped endianness.
+ */
+inline uint32_t swap_endian_l(uint32_t val)
+{
+ return ((val & 0xFF) << 24) | ((val & 0xFF00) << 8) | ((val & 0xFF0000) >> 8) | (( val >> 24) & 0xFF);
+}
+
+
+/** Swap the endianness of a short (two byte) integer.
+ *
+ * @param val Integer to alter.
+ *
+ * @return Value with swapped endianness.
+ */
+inline uint16_t swap_endian_s(uint16_t val)
+{
+ return ((val >> 8) & 0xFF) | ((val << 8) & 0xFF00);
+}
+
+
+extern uint32_t swap_endian_l(uint32_t val);
+extern uint16_t swap_endian_s(uint16_t val);
+
+
+/* File-scope types --------------------------------------------------------------------*/
+
+
+/** Structure to hold information about a specific screen mode.
+ */
+typedef struct dlo_mode_data_s
+{
+ uint16_t width; /**< Width (pixels). */
+ uint16_t height; /**< Height (pixels). */
+ uint8_t refresh; /**< Refresh rate (Hz). */
+ uint8_t bpp; /**< Colour depth (bits per pixel). */
+ char *data; /**< Block of mode data. */
+ size_t data_sz; /**< Size of mode data block (bytes). */
+ char *mode_en; /**< Block of mode enable data. */
+ size_t mode_en_sz; /**< Size of mode enable data block (bytes). */
+ bool low_blank; /**< Screen mode has reduced blanking. */
+} dlo_mode_data_t; /**< A struct @a dlo_mode_data_s. */
+
+
+/** Established timing information, derived from EDID.
+ */
+typedef struct est_timing_s
+{
+ uint16_t width; /**< Width of mode (pixels). */
+ uint16_t height; /**< Height of mode (pixels). */
+ uint8_t refresh; /**< Mode refresh rate (Hz). */
+} est_timing_t; /**< A struct @a est_timings_s. */
+
+
+/** Vendor/product information.
+ */
+typedef struct edid_prod_id_s
+{
+ uint16_t manuf_name; /**< ID manufacturer code. */
+ uint16_t prod_code; /**< ID product code. */
+ uint32_t serial_num; /**< ID serial number. */
+ uint8_t manuf_wk; /**< Week of manufacture. */
+ uint8_t manuf_yr; /**< Year of manufacture. */
+} edid_prod_id_t; /**< A struct @a edid_prod_id_s. */
+
+
+/** EDID structure information.
+ */
+typedef struct edid_struct_vsn_s
+{
+ uint8_t number; /**< Version number. */
+ uint8_t revision; /**< Revision number. */
+} edid_struct_vsn_t; /**< A struct @a edid_struct_vsn_s. */
+
+
+/** Basic dislpay parameters/features.
+ */
+typedef struct edid_basic_params_s
+{
+ uint8_t input_def; /**< Video input definition. */
+ uint8_t max_horiz_sz; /**< Maximum horizontal image size (cm). */
+ uint8_t max_vert_sz; /**< Maximum vertical image size (cm). */
+ float gamma; /**< Display transfer characteristic (gamma). */
+ uint8_t features; /**< Feature support. */
+} edid_basic_params_t; /**< A struct @a edid_basic_params_s. */
+
+
+/** Colour characteristics.
+ */
+typedef struct edid_colours_s
+{
+ uint16_t red_grn_low; /**< Red/green low bits. */
+ uint16_t blu_wht_low; /**< Blue/white low bits. */
+ uint16_t red_x; /**< Red-x (bits 9-2). */
+ uint16_t red_y; /**< Red-y (bits 9-2). */
+ uint16_t grn_x; /**< Green-x (bits 9-2). */
+ uint16_t grn_y; /**< Green-y (bits 9-2). */
+ uint16_t blu_x; /**< Blue-x (bits 9-2). */
+ uint16_t blu_y; /**< Blue-y (bits 9-2). */
+ uint16_t wht_x; /**< White-x (bits 9-2). */
+ uint16_t wht_y; /**< White-y (bits 9-2). */
+} edid_colours_t; /**< A struct @a edid_colours_s. */
+
+
+/** Established timings.
+ */
+typedef struct edid_est_timings_s
+{
+ uint8_t timings[2]; /**< Bitfields of established timings. */
+ uint8_t resvd; /**< Manufacturer's reserved timings. */
+} edid_est_timings_t; /**< A struct @a edid_est_timings_s. */
+
+
+/** Standard timing identification.
+ */
+typedef struct edid_std_timing_s
+{
+ uint16_t timing_id[8]; /**< Standard timing identification. */
+} edid_std_timing_t; /**< A struct @a edid_std_timing_s. */
+
+
+/** Detailed timing description.
+ */
+typedef struct edid_detail_s
+{
+ bool is_detail; /**< Flag is set to true - the structure is an @a edid_detail_t. */
+ float pixclk; /**< Timing parameter. */
+ uint32_t hactl; /**< Timing parameter. */
+ uint32_t hblankl; /**< Timing parameter. */
+ uint32_t hactblankh; /**< Timing parameter. */
+ uint32_t vactl; /**< Timing parameter. */
+ uint32_t vblankl; /**< Timing parameter. */
+ uint32_t vactblankh; /**< Timing parameter. */
+ uint32_t hsyncoffl; /**< Timing parameter. */
+ uint32_t hsyncwl; /**< Timing parameter. */
+ uint32_t vsyncoffvsyncwl; /**< Timing parameter. */
+ uint32_t synch; /**< Timing parameter. */
+ uint32_t hsizel; /**< Timing parameter. */
+ uint32_t vsizel; /**< Timing parameter. */
+ uint32_t hvsizeh; /**< Timing parameter. */
+ uint8_t hbord; /**< Timing parameter. */
+ uint8_t vbord; /**< Timing parameter. */
+ uint8_t flags; /**< Timing parameter. */
+} edid_detail_t; /**< A struct @a edid_detail_s. */
+
+
+/** Monitor descriptor.
+ */
+typedef struct edid_monitor_desc_s
+{
+ bool is_detail; /**< Flag is set to false - the structure is not an @a edid_detail_t. */
+ uint8_t unknown[18]; /**< Contents of block are unknown. */
+} edid_monitor_desc_t; /**< A struct @a edid_monitor_desc_s. */
+
+
+/** A timing description block may be either a @a edid_detail_t or a @a edid_monitor_desc_t.
+ */
+typedef union edid_timing_desc_u
+{
+ edid_detail_t detail; /**< Either a detailed timing description. */
+ edid_monitor_desc_t desc; /**< Or a monitor descriptor. */
+} edid_timing_desc_t; /**< A struct @a edid_timing_desc_s. */
+
+
+/** An EDID extension block.
+ */
+typedef struct edid_ext_block_s
+{
+ uint8_t unknown[128]; /**< Contents of block are unknown. */
+} edid_ext_block_t; /**< A struct @a edid_ext_block_s. */
+
+
+/** An EDID structure.
+ */
+typedef struct edid_format_s
+{
+ edid_prod_id_t product; /**< Vendor/product information. */
+ edid_struct_vsn_t version; /**< EDID structure information. */
+ edid_basic_params_t basic; /**< Basic dislpay parameters/features. */
+ edid_colours_t colours; /**< Colour characteristics. */
+ edid_est_timings_t est_timings; /**< Established timings. */
+ edid_std_timing_t std_timings; /**< Standard timing identification. */
+ edid_timing_desc_t timings[4]; /**< Timing descriptions. */
+ uint8_t ext_blocks; /**< Number of extension blocks. */
+} edid_format_t; /**< A struct @a edid_format_s. */
+
+
+/* External scope variables ------------------------------------------------------------*/
+
+
+/* File-scope variables ----------------------------------------------------------------*/
+
+
+/** Array of hard-wired screen mode definitions.
+ */
+static dlo_mode_data_t dlo_mode_data[DLO_MODE_DATA_NUM];
+
+
+/** Mode information corresponding with flag bits in EDID establisted timings bytes.
+ */
+const est_timing_t est_timings[24] =
+{
+ { 800, 600, 60 }, /* bit 0 */
+ { 800, 600, 56 }, /* bit 1 */
+ { 640, 480, 75 }, /* bit 2 */
+ { 640, 480, 72 }, /* bit 3 */
+ { 640, 480, 67 }, /* bit 4 */
+ { 640, 480, 60 }, /* bit 5 */
+ { 720, 400, 88 }, /* bit 6 */
+ { 720, 400, 70 }, /* bit 7 */
+ { 1280, 1024, 75 }, /* bit 8 */
+ { 1024, 768, 75 }, /* bit 9 */
+ { 1024, 768, 70 }, /* bit 10 */
+ { 1024, 768, 60 }, /* bit 11 */
+ { 1024, 768, 87 }, /* bit 12 */
+ { 832, 624, 75 }, /* bit 13 */
+ { 800, 600, 75 }, /* bit 14 */
+ { 800, 600, 72 }, /* bit 15 */
+ { 0, 0, 0 }, /* bit 16 */
+ { 0, 0, 0 }, /* bit 17 */
+ { 0, 0, 0 }, /* bit 18 */
+ { 0, 0, 0 }, /* bit 19 */
+ { 0, 0, 0 }, /* bit 20 */
+ { 0, 0, 0 }, /* bit 21 */
+ { 0, 0, 0 }, /* bit 22 */
+ { 1152, 870, 75 } /* bit 23 */
+};
+
+
+/* File-scope function declarations ----------------------------------------------------*/
+
+
+/** Append a video register setting command onto the specified char block.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ * @param reg Register number (0..255).
+ * @param val Value to set (byte).
+ *
+ * @return Return code, zero for no error.
+ */
+static dlo_retcode_t vreg(dlo_device_t * const dev, uint8_t reg, uint8_t val);
+
+
+/** Append a video register setting command onto the specified char block.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ * @param reg Register number (0..255).
+ * @param val Value to set (byte).
+ *
+ * @return Return code, zero for no error.
+ */
+static dlo_retcode_t vbuf(dlo_device_t * const dev, const char * const buf, size_t len);
+
+
+/** Check an EDID checksum to see if it is invalid.
+ *
+ * @param ptr Pointer to base of EDID structure data.
+ * @param size Size of data (bytes).
+ *
+ * @return true if checksum is incorrect, false if OK.
+ */
+static bool bad_edid_checksum(const uint8_t * const ptr, const size_t size);
+
+
+/** Parse an EDID detailed timing descriptor/mode descriptor.
+ *
+ * @param desc Pointer to descriptor structure to initialise.
+ * @param ptr Pointer to base of descriptor in EDID data to parse.
+ */
+static void parse_edid_detail_desc(edid_timing_desc_t * const desc, const uint8_t * const ptr);
+
+
+/** Parse EDID colour characteristics.
+ *
+ * @param cols Pointer to colour structure to initialise.
+ * @param ptr Pointer to base of colour characteristics block to parse from EDID data.
+ */
+static void parse_edid_colours(edid_colours_t * const cols, const uint8_t * const ptr);
+
+
+/** Look for a mode definition amongst the list of known modes.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ * @param width Width of desired display (pixels).
+ * @param height Hieght of desired display (pixels) - zero to select first available.
+ * @param refresh Desired refresh rate (Hz) - zero to select first available.
+ * @param bpp Colour depth (bits per pixel) - zero to select first available.
+ *
+ * @return Mode number of the best matching mode definition (or @a DLO_INVALID_MODE if none found).
+ */
+static dlo_modenum_t get_mode_number(dlo_device_t * const dev, const uint16_t width, const uint16_t height, const uint8_t refresh, const uint8_t bpp);
+
+
+/** Given a bitmap and a mode number, set the current screen mode.
+ *
+ * @param bmp Bitmap to set as the current rastered display mode.
+ * @param mode Mode number for best match to the supplied bitmap.
+ *
+ * @return Return code, zero for no error.
+ */
+static dlo_retcode_t mode_select(dlo_device_t * const dev, const dlo_mode_t * const desc, const dlo_modenum_t mode);
+
+
+/** Look up the specified mode and add to the supported list if found.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ * @param idx Index - incrememnted if the mode was found.
+ * @param width Width of the mode to look for (pixels).
+ * @param height Height of the mode to look for (pixels).
+ * @param refresh Refresh rate of the mode to look for (Hz).
+ *
+ * @return Updated index (as @a idx if mode not found, else incremented by one).
+ */
+static uint16_t add_supported(dlo_device_t * const dev, uint16_t idx, const uint16_t width, const uint16_t height, const uint8_t refresh);
+
+
+/** Build a list of supported modes, based upon the supplied EDID information.
+ *
+ * @param dev Device to update.
+ * @param edid Pointer to structure holding parsed EDID information.
+ *
+ * @return Return code, zero for no error.
+ */
+static dlo_retcode_t lookup_edid_modes(dlo_device_t * const dev, const edid_format_t * const edid);
+
+
+/** Program the base addresses of the video display in the device.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ * @param base Address of the base of the 16 bpp segment.
+ * @param base8 Address of the base of the 8 bpp segment.
+ *
+ * @return Return code, zero for no error.
+ *
+ * Note: this call first will cause any buffered commands to be sent to the device then
+ * the set base commands are sent. The buffer to that device is thus flushed.
+ */
+static dlo_retcode_t set_base(dlo_device_t * const dev, const dlo_ptr_t base, const dlo_ptr_t base8);
+
+
+/* Public function definitions ---------------------------------------------------------*/
+
+
+dlo_retcode_t dlo_mode_init(const dlo_init_t flags)
+{
+ init_mode(0, 1920, 1080, 60, 24);
+ init_mode(1, 1600, 1200, 60, 24);
+ init_mode(2, 1400, 1050, 85, 24);
+ init_mode(3, 1400, 1050, 75, 24);
+ init_mode(4, 1400, 1050, 60, 24);
+ init_mode(5, 1400, 1050, 60, 24);
+ init_mode(6, 1366, 768, 60, 24);
+ init_mode(7, 1360, 768, 60, 24);
+ init_mode(8, 1280, 960, 85, 24);
+ init_mode(9, 1280, 960, 60, 24);
+ init_mode(10, 1280, 800, 60, 24);
+ init_mode(11, 1280, 768, 85, 24);
+ init_mode(12, 1280, 768, 75, 24);
+ init_mode(13, 1280, 1024, 85, 24);
+ init_mode(14, 1280, 1024, 75, 24);
+ init_mode(15, 1280, 1024, 60, 24);
+ init_mode(16, 1280, 768, 60, 24);
+ init_mode(17, 1152, 864, 75, 24);
+ init_mode(18, 1024, 768, 85, 24);
+ init_mode(19, 1024, 768, 75, 24);
+ init_mode(20, 1024, 768, 70, 24);
+ init_mode(21, 1024, 768, 60, 24);
+ init_mode(22, 848, 480, 60, 24);
+ init_mode(23, 800, 600, 85, 24);
+ init_mode(24, 800, 600, 75, 24);
+ init_mode(25, 800, 600, 72, 24);
+ init_mode(26, 800, 600, 60, 24);
+ init_mode(27, 800, 600, 56, 24);
+ init_mode(28, 800, 480, 60, 24);
+ init_mode(29, 720, 400, 85, 24);
+ init_mode(30, 720, 400, 70, 24);
+ init_mode(31, 640, 480, 85, 24);
+ init_mode(32, 640, 480, 75, 24);
+ init_mode(33, 640, 480, 73, 24);
+ init_mode(34, 640, 480, 60, 24);
+
+ return dlo_ok;
+}
+
+
+dlo_retcode_t dlo_mode_final(const dlo_final_t flags)
+{
+ return dlo_ok;
+}
+
+
+dlo_mode_t *dlo_mode_from_number(const dlo_modenum_t num)
+{
+ static dlo_mode_t mode;
+
+ if (num < DLO_MODE_DATA_NUM)
+ {
+ mode.view.width = dlo_mode_data[num].width;
+ mode.view.height = dlo_mode_data[num].height;
+ mode.view.bpp = dlo_mode_data[num].bpp;
+ mode.view.base = 0;
+ mode.refresh = dlo_mode_data[num].refresh;
+ return &mode;
+ }
+ return NULL;
+}
+
+
+dlo_modenum_t dlo_mode_lookup(dlo_device_t * const dev, const uint16_t width, const uint16_t height, const uint8_t refresh, uint8_t bpp)
+{
+ /* Check that the requested screen mode is supported */
+ //DPRINTF("mode: lookup: %ux%u @ %u Hz, %u bpp\n", width, height, refresh, bpp);
+ return bpp != 24 ? DLO_INVALID_MODE : get_mode_number(dev, width, height, refresh, bpp);
+}
+
+
+dlo_retcode_t dlo_mode_change(dlo_device_t * const dev, const dlo_mode_t * const desc, dlo_modenum_t mode)
+{
+ /* If no mode number was specified on entry, try looking one up for the supplied bitmap */
+ if (mode == DLO_INVALID_MODE)
+ mode = get_mode_number(dev, desc->view.width, desc->view.height, 0, desc->view.bpp);
+
+ /* Change mode or return an error */
+ return mode_select(dev, desc, mode);
+}
+
+
+dlo_retcode_t dlo_mode_parse_edid(dlo_device_t * const dev, const uint8_t * const ptr, const size_t size)
+{
+ static edid_format_t edid;
+ uint32_t i;
+
+ /* Copy the header bytes straight into our structure (assumes the structure is correct size!) */
+ ASSERT(EDID_STRUCT_SZ == size);
+ if (memcmp(header, ptr, sizeof(header)))
+ return dlo_err_edid_fail;
+
+ if (bad_edid_checksum(ptr, size))
+ return dlo_err_edid_fail;
+
+#if (defined(DEBUG) && 0) /* If you really want this verbose debug output, change the 0 to a 1 */
+ uint32_t j;
+ /* Parse the vendor/product information */
+ for (j = 0; j < 128; j += 8)
+ {
+ DPRINTF("mode: edid: raw: ");
+ for (i = 0; i < 8; i++)
+ DPRINTF("%02X=%02X ", i + j, RD_B(ptr + i + j));
+ DPRINTF("\n");
+ }
+#endif
+
+ edid.product.manuf_name = LETOHS(RD_S(ptr + 0x08));
+ edid.product.prod_code = LETOHS(RD_S(ptr + 0x0A));
+ edid.product.serial_num = LETOHL(RD_L(ptr + 0x0C));
+ edid.product.manuf_wk = RD_B(ptr + 0x10);
+ edid.product.manuf_yr = RD_B(ptr + 0x11);
+ //DPRINTF("mode: edid: manuf &%X prod &%X serial &%X wk %u yr %u\n",
+ // edid.product.manuf_name, edid.product.prod_code, edid.product.serial_num,
+ // edid.product.manuf_wk, edid.product.manuf_yr + 1990);
+
+ /* Parse the EDID structure information */
+ edid.version.number = RD_B(ptr + 0x12);
+ edid.version.revision = RD_B(ptr + 0x13);
+ //DPRINTF("edid: version &%02X revision &%02X\n", edid.version.number, edid.version.revision);
+
+ /* Parse the basic dislpay parameters/features */
+ edid.basic.input_def = RD_B(ptr + 0x14);
+ edid.basic.max_horiz_sz = RD_B(ptr + 0x15);
+ edid.basic.max_vert_sz = RD_B(ptr + 0x16);
+ edid.basic.gamma = (100.0 + RD_B(ptr + 0x17)) / 100.0;
+ edid.basic.features = RD_B(ptr + 0x18);
+
+ /* Parse the colour characteristics */
+ parse_edid_colours(&(edid.colours), ptr + 0x19);
+
+ /* Parse the established timings */
+ edid.est_timings.timings[0] = RD_B(ptr + 0x23);
+ edid.est_timings.timings[1] = RD_B(ptr + 0x24);
+ edid.est_timings.resvd = RD_B(ptr + 0x25);
+
+ /* Parse the bits at the end of the EDID structure */
+ edid.ext_blocks = RD_B(ptr + 0x7E);
+
+ /* Parse all of the standard timing identification */
+ for (i = 0; i < sizeof(edid.std_timings.timing_id); i++)
+ edid.std_timings.timing_id[i] = RD_B(ptr + 0x26 + i);
+
+ /* Parse all of the detailed timing descriptions (or monitor descriptors) */
+ for (i = 0; i < 4; i++)
+ parse_edid_detail_desc(&(edid.timings[i]), ptr + 0x36 + (i * 0x12));
+
+ return lookup_edid_modes(dev, &edid);
+}
+
+
+void use_default_modes(dlo_device_t * const dev)
+{
+ uint32_t i;
+
+ for (i = 0; i < DLO_MODE_DATA_NUM; i++)
+ dev->supported[i] = (dlo_modenum_t)i;
+}
+
+
+/* File-scope function definitions -----------------------------------------------------*/
+
+
+static dlo_retcode_t vreg(dlo_device_t * const dev, uint8_t reg, uint8_t val)
+{
+ if (dev->bufend - dev->bufptr < 4)
+ return dlo_err_buf_full;
+
+ *(dev->bufptr)++ = '\xAF';
+ *(dev->bufptr)++ = '\x20';
+ *(dev->bufptr)++ = reg;
+ *(dev->bufptr)++ = val;
+
+ return dlo_ok;
+}
+
+
+static dlo_retcode_t vbuf(dlo_device_t * const dev, const char * buf, size_t len)
+{
+ if (dev->bufend - dev->bufptr < len)
+ return dlo_err_buf_full;
+
+ while (len--)
+ *(dev->bufptr)++ = *buf++;
+
+ return dlo_ok;
+}
+
+
+static dlo_modenum_t get_mode_number(dlo_device_t * const dev, const uint16_t width, const uint16_t height, const uint8_t refresh, const uint8_t bpp)
+{
+ dlo_modenum_t idx;
+ uint32_t num;
+
+ /* Look for all matching modes in our array of video timing structures.
+ *
+ * Note: if we don't have EDID data for the monitor attached to the device
+ * we simply look through all the modes we have, rather than only looking
+ * at the supported modes list.
+ */
+ for (idx = 0; idx < DLO_MODE_DATA_NUM; idx++)
+ {
+ /* Read the mode number from the device's supported modes array */
+ num = dev->supported[idx];
+ if (num == DLO_INVALID_MODE)
+ break;
+
+ /* This sequence of if statements looks odd, take care if you decide to 'optimise' it! */
+ if (dlo_mode_data[num].width != width)
+ continue;
+ if (bpp && dlo_mode_data[num].bpp != bpp)
+ continue;
+ if (height && dlo_mode_data[num].height != height)
+ continue;
+ if (refresh && dlo_mode_data[num].refresh != refresh)
+ continue;
+
+ /* If we're satisfied with the tests above, then return the mode number */
+ return num;
+ }
+
+ /* No matches found, return an invalid mode number */
+ return DLO_INVALID_MODE;
+}
+
+
+static dlo_retcode_t mode_select(dlo_device_t * const dev, const dlo_mode_t * const desc, const dlo_modenum_t mode)
+{
+ if (mode >= DLO_MODE_DATA_NUM || mode == DLO_INVALID_MODE)
+ return dlo_err_bad_mode;
+
+ /* Base address must be aligned to a two byte boundary */
+ if (desc->view.base & 1)
+ return dlo_err_bad_mode;
+
+ /* Flush the command buffer */
+ if (dlo_ok != dlo_usb_write(dev))
+ return DLO_INVALID_MODE;
+
+ dev->mode.view.base = desc->view.base;
+ dev->base8 = desc->view.base + (BYTES_PER_16BPP * desc->view.width * desc->view.height);
+ ERR(set_base(dev, dev->mode.view.base, dev->base8));
+
+ /* Only change mode if the new raster bitmap's characteristics differ from the current.
+ *
+ * Note: don't compare reduced blanking flag because if the rest is the same, we can use the
+ * same blanking type. However, there's an outside chance that the low_blank hint was changed
+ * since entering the current mode in which case you may well want a mode change to happen but
+ * we'll just hope that never happens (seems like a very unlikely scenario).
+ */
+ if (desc->view.width != dev->mode.view.width ||
+ desc->view.height != dev->mode.view.height ||
+ desc->view.bpp != dev->mode.view.bpp)
+ {
+ ERR(dlo_usb_chan_sel(dev, dlo_mode_data[mode].mode_en, dlo_mode_data[mode].mode_en_sz));
+ ERR(dlo_usb_write_buf(dev, dlo_mode_data[mode].data, dlo_mode_data[mode].data_sz));
+ ERR(dlo_usb_chan_sel(dev, DLO_MODE_POSTAMBLE, DSIZEOF(DLO_MODE_POSTAMBLE)));
+ }
+
+ /* Update the device with the new mode details */
+ dev->mode = *desc;
+ dev->mode.refresh = dlo_mode_data[mode].refresh;
+ dev->low_blank = dlo_mode_data[mode].low_blank;
+
+ //DPRINTF("mode: select: %ux%u @ %u Hz %u bpp (base &%X base8 &%X low? %s)\n",
+ // dev->mode.view.width, dev->mode.view.height, dev->mode.refresh, dev->mode.view.bpp,
+ // dev->mode.view.base, dev->base8, dev->low_blank ? "yes" : "no");
+
+ /* Flush the command buffer */
+ ERR(dlo_usb_write(dev));
+
+ /* Return a warning for DL160 modes */
+ return (mode < DLO_DL120_MODES) ? dlo_warn_dl160_mode : dlo_ok;
+}
+
+
+static uint16_t add_supported(dlo_device_t * const dev, uint16_t idx, const uint16_t width, const uint16_t height, const uint8_t refresh)
+{
+ dlo_modenum_t num;
+
+ num = get_mode_number(dev, width, height, refresh, 24);
+ if (num != DLO_INVALID_MODE)
+ dev->supported[idx++] = num;
+
+// DPRINTF("mode: add_supt: %ux%u @ %u Hz, %u bpp = num %u\n", width, height, refresh, 24, (int)num);
+
+ return idx;
+}
+
+
+static dlo_retcode_t lookup_edid_modes(dlo_device_t * const dev, const edid_format_t * const edid)
+{
+ uint32_t timings, bit;
+ uint32_t idx = 0;
+
+ /* Clear the native mode information for the device */
+ (void) dlo_memset(&dev->native, 0, sizeof(dlo_mode_t));
+
+ /* Add mode numbers for any supported established timing modes */
+ timings = edid->est_timings.timings[0] | (edid->est_timings.timings[1] << 8) | (edid->est_timings.resvd << 16);
+ for (bit = 0; bit < 24; bit++)
+ {
+ if (est_timings[bit].width)
+ idx = add_supported(dev, idx, est_timings[bit].width, est_timings[bit].height, est_timings[bit].refresh);
+ }
+
+ /* Add further support from the detailed timing descriptions */
+ for (timings = 0; timings < 4; timings++)
+ {
+ const edid_detail_t * const detail = &(edid->timings[timings].detail);
+
+ if (detail->is_detail)
+ {
+ uint8_t hz;
+
+ for (hz = 50; hz < 100; hz++)
+ {
+ uint32_t prev = idx;
+ uint32_t width = detail->hactl + ((detail->hactblankh & 0xF0) << 4);
+ uint32_t height = detail->vactl + ((detail->vactblankh & 0xF0) << 4);
+
+ idx = add_supported(dev, idx, width, height, hz);
+
+ /* Have we added a mode definition for the native resolution reported by the display? */
+ if (idx != prev)
+ {
+ dlo_modenum_t num = dev->supported[prev];
+
+ dev->native.view.base = 0;
+ dev->native.view.width = dlo_mode_data[num].width;
+ dev->native.view.height = dlo_mode_data[num].height;
+ dev->native.view.bpp = dlo_mode_data[num].bpp;
+ dev->native.refresh = dlo_mode_data[num].refresh;
+ DPRINTF("mode: lookup: native mode %u (%ux%u @ %u bpp, %uHz base &%X)\n",
+ num,
+ dev->native.view.width,
+ dev->native.view.height,
+ dev->native.view.bpp,
+ dev->native.refresh,
+ (int)dev->native.view.base);
+ }
+ }
+ }
+ }
+
+ /* Fill any remaining array entries with the invalid mode constant */
+ while (idx < DLO_MODE_DATA_NUM - 1)
+ dev->supported[idx++] = DLO_INVALID_MODE;
+
+ return dlo_ok;
+}
+
+
+static dlo_retcode_t set_base(dlo_device_t * const dev, const dlo_ptr_t base, const dlo_ptr_t base8)
+{
+ //DPRINTF("mode: set_base: base=&%X base8=&%X\n", base, base8);
+ ERR(vbuf(dev, WRITE_VIDREG_LOCK, DSIZEOF(WRITE_VIDREG_LOCK)));
+ ERR(vreg(dev, 0x20, base >> 16));
+ ERR(vreg(dev, 0x21, base >> 8));
+ ERR(vreg(dev, 0x22, base));
+ ERR(vreg(dev, 0x26, base8 >> 16));
+ ERR(vreg(dev, 0x27, base8 >> 8));
+ ERR(vreg(dev, 0x28, base8));
+ ERR(vbuf(dev, WRITE_VIDREG_UNLOCK, DSIZEOF(WRITE_VIDREG_UNLOCK)));
+ ERR(dlo_usb_write(dev));
+
+ return dlo_ok;
+}
+
+
+static bool bad_edid_checksum(const uint8_t * const ptr, const size_t size)
+{
+ uint32_t i;
+ uint8_t csum = 0;
+
+ for (i = 0; i < size; i++)
+ csum += ptr[i];
+
+ return 0 != csum;
+}
+
+
+static void parse_edid_detail_desc(edid_timing_desc_t * const desc, const uint8_t * const ptr)
+{
+ if (RD_B(ptr) || RD_B(ptr + 1) || RD_B(ptr + 2))
+ {
+ //DPRINTF("edid: found timing detail (&%04X)\n", LETOHS(RD_S(ptr)));
+ desc->detail.is_detail = true;
+ desc->detail.pixclk = (float)LETOHS(RD_S(ptr)) / 100.0;
+ desc->detail.hactl = RD_B(ptr + 0x02);
+ desc->detail.hblankl = RD_B(ptr + 0x03);
+ desc->detail.hactblankh = RD_B(ptr + 0x04);
+ desc->detail.vactl = RD_B(ptr + 0x05);
+ desc->detail.vblankl = RD_B(ptr + 0x06);
+ desc->detail.vactblankh = RD_B(ptr + 0x07);
+ desc->detail.hsyncoffl = RD_B(ptr + 0x08);
+ desc->detail.hsyncwl = RD_B(ptr + 0x09);
+ desc->detail.vsyncoffvsyncwl = RD_B(ptr + 0x0A);
+ desc->detail.synch = RD_B(ptr + 0x0B);
+ desc->detail.hsizel = RD_B(ptr + 0x0C);
+ desc->detail.vsizel = RD_B(ptr + 0x0D);
+ desc->detail.hvsizeh = RD_B(ptr + 0x0E);
+ desc->detail.hbord = RD_B(ptr + 0x0F);
+ desc->detail.vbord = RD_B(ptr + 0x10);
+ desc->detail.flags = RD_B(ptr + 0x11);
+
+ //DPRINTF("edid: Pixel Clock: %f MHz\n", (float)desc->detail.pixclk);
+ //DPRINTF("edid: H Active pixels: %d\n", desc->detail.hactl + ((desc->detail.hactblankh & 0xF0) << 4));
+ //DPRINTF("edid: H Blank pixels: %d\n", desc->detail.hblankl + ((desc->detail.hactblankh & 0x0F) << 8));
+ //DPRINTF("edid: V Active pixels: %d\n", desc->detail.vactl + ((desc->detail.vactblankh & 0xF0) << 4));
+ //DPRINTF("edid: V Blank pixels: %d\n", desc->detail.vblankl + ((desc->detail.vactblankh & 0x0F) << 8));
+ //DPRINTF("edid: H Sync Off: %d\n", desc->detail.hsyncoffl + ((desc->detail.synch & 0xC0) << 2));
+ //DPRINTF("edid: H Sync Width: %d\n", desc->detail.hsyncwl + ((desc->detail.synch & 0x30) << 4));
+ //DPRINTF("edid: V Sync Off: %d\n", (desc->detail.vsyncoffvsyncwl >> 4) + ((desc->detail.synch & 0x0C) << 6));
+ //DPRINTF("edid: V Sync Width: %d\n", (desc->detail.vsyncoffvsyncwl & 0xF) + ((desc->detail.synch & 0x03) << 8));
+ //DPRINTF("edid: H size: %d mm\n", desc->detail.hsizel + ((desc->detail.hvsizeh & 0xF0) << 4));
+ //DPRINTF("edid: V size: %d mm\n", desc->detail.vsizel + ((desc->detail.hvsizeh & 0x0F) << 8));
+ }
+ else
+ {
+ /* It's a mode descriptor - ignore for now */
+ //DPRINTF("edid: found a mode descriptor type &%02X\n", RD_B(ptr+3));
+ desc->desc.is_detail = false;
+ switch (RD_B(ptr+3))
+ {
+ case 0xFC:
+ case 0xFE:
+ case 0xFF:
+ {
+ char buf[14];
+ char *chr;
+
+ snprintf(buf, 13, "%s", ptr + 5);
+ buf[13] = '\0';
+ chr = strchr(buf, '\n');
+ if (chr)
+ *chr = '\0';
+ //DPRINTF("edid: monitor string '%s'\n", buf);
+ break;
+ }
+ default:
+ {
+ //uint32_t i;
+ //DPRINTF("edid: ");
+ //for (i = 0; i < 0x12; i++)
+ // DPRINTF("%02X ", RD_B(ptr+i));
+ //DPRINTF("\n");
+ }
+ }
+ }
+}
+
+static void parse_edid_colours(edid_colours_t * const cols, const uint8_t * const ptr)
+{
+ /* Read the raw data */
+ cols->red_grn_low = RD_B(ptr + 0x19);
+ cols->blu_wht_low = RD_B(ptr + 0x1A);
+ cols->red_x = RD_B(ptr + 0x1B);
+ cols->red_y = RD_B(ptr + 0x1C);
+ cols->grn_x = RD_B(ptr + 0x1D);
+ cols->grn_y = RD_B(ptr + 0x1E);
+ cols->blu_x = RD_B(ptr + 0x1F);
+ cols->blu_y = RD_B(ptr + 0x20);
+ cols->wht_x = RD_B(ptr + 0x21);
+ cols->wht_y = RD_B(ptr + 0x22);
+
+ /* Do the expansion */
+ cols->red_x = ((cols->red_grn_low & 0xC0) >> 6) + (cols->red_x << 2);
+ cols->red_y = ((cols->red_grn_low & 0x30) >> 4) + (cols->red_y << 2);
+ cols->grn_x = ((cols->red_grn_low & 0x0C) >> 2) + (cols->grn_x << 2);
+ cols->grn_y = ((cols->red_grn_low & 0x03) >> 0) + (cols->grn_y << 2);
+ cols->blu_x = ((cols->blu_wht_low & 0xC0) >> 6) + (cols->blu_x << 2);
+ cols->blu_y = ((cols->blu_wht_low & 0x40) >> 4) + (cols->blu_y << 2);
+ cols->wht_x = ((cols->blu_wht_low & 0x0C) >> 2) + (cols->wht_y << 2);
+ cols->wht_y = ((cols->blu_wht_low & 0x03) >> 0) + (cols->wht_y << 2);
+}
+
+
+/* End of file -------------------------------------------------------------------------*/
diff --git a/src/dlo_usb.c b/src/dlo_usb.c
new file mode 100644
index 0000000..fe5965f
--- /dev/null
+++ b/src/dlo_usb.c
@@ -0,0 +1,528 @@
+/** @file dlo_usb.c
+ *
+ * @brief Implements the USB-specific connectivity functions.
+ *
+ * DisplayLink Open Source Software (libdlo)
+ * Copyright (C) 2009, DisplayLink
+ * www.displaylink.com
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by the Free
+ * Software Foundation; LGPL version 2, dated June 1991.
+ *
+ * This library 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 Library General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <string.h>
+#include "netinet/in.h"
+#include "error.h" /* from libusb */
+#include "dlo_defs.h"
+#include "dlo_usb.h"
+#include "dlo_base.h"
+#include "dlo_mode.h"
+
+
+/* File-scope defines ------------------------------------------------------------------*/
+
+
+#define NR_USB_REQUEST_STATUS_DW (0x06) /**< USB control message: request type. */
+#define NR_USB_REQUEST_CHANNEL (0x12) /**< USB control message: request type. */
+#define NR_USB_REQUEST_I2C_SUB_IO (0x02) /**< USB control message: request type. */
+
+/** USB VendorID for a DisplayLink device.
+ */
+#define VENDORID_DISPLAYLINK (0x17E9)
+
+/** Number of milliseconds to wait before timing-out a USB control message.
+ */
+#define CTRL_TIMEOUT (100u)
+
+/** Number of milliseconds to wait before timing-out channel selection message.
+ */
+#define CHANSEL_TIMEOUT (5000u)
+
+/** Number of milliseconds to wait before timing-out a USB bulk transfer.
+ */
+#define WRITE_TIMEOUT (10000u)
+
+/** Number of milliseconds to wait before timing-out a request for the device type.
+ */
+#define ID_TIMEOUT (1000u)
+
+/** Byte sequence to send to the device to select the default communication channel.
+ */
+#define STD_CHANNEL "\x57\xCD\xDC\xA7\x1C\x88\x5E\x15\x60\xFE\xC6\x97\x16\x3D\x47\xF2"
+
+
+/* File-scope types --------------------------------------------------------------------*/
+
+
+/* External scope variables ------------------------------------------------------------*/
+
+
+int32_t usberr = 0;
+
+
+/* File-scope variables ----------------------------------------------------------------*/
+
+
+/** Pointer to a copy of the last error message string read out of libusb (or NULL).
+ */
+static char *usb_err_str = NULL;
+
+
+/* File-scope function declarations ----------------------------------------------------*/
+
+
+/** Connect to a device, read information about it and then disconnect again.
+ *
+ * @param dev USB device structure pointer.
+ *
+ * @return Return code, zero for no error.
+ */
+static dlo_retcode_t check_device(struct usb_device *dev);
+
+
+/** Attempt to read the EDID structure from the monitor attached to the specified device.
+ *
+ * @param dev Device structure pointer.
+ * @param uhand USB device handle.
+ *
+ * @return Return code, zero for no error.
+ */
+static dlo_retcode_t read_edid(dlo_device_t * const dev, usb_dev_handle *uhand);
+
+
+/** Make a note of any error returned by libusb.
+ *
+ * @return Return code to indicate a USB-related error.
+ *
+ * Often, by the time we have returned from a function, the error code stored in libusb
+ * has been lost because our tidy-up code will call more libusb functions after an error
+ * is spotted. As such, this function is called automatically by the @c UERR() and
+ * @c UERR_GOTO() macros in order to make a note of the error number and message from
+ * libusb at the moment the error is caught. This information is stored locally for
+ * retrieval by @c dlo_usb_strerror().
+ */
+static dlo_retcode_t usb_error_grab(void);
+
+
+/* Public function definitions ---------------------------------------------------------*/
+
+
+char *dlo_usb_strerror(void)
+{
+ /* These two are published by libusb */
+ usb_error_type = USB_ERROR_TYPE_ERRNO;
+ usb_error_errno = usberr;
+ DPRINTF("usb: error lookup %d\n", usberr);
+ return usb_err_str;
+}
+
+
+dlo_retcode_t dlo_usb_init(const dlo_init_t flags)
+{
+ /* Initialise libusb */
+ //DPRINTF("usb: init\n");
+ usb_init();
+
+ /* Add nodes onto the device list for any DisplayLink devices we find */
+ //DPRINTF("usb: init: enum\n");
+ ERR(dlo_usb_enumerate(true));
+
+ return dlo_ok;
+}
+
+
+dlo_retcode_t dlo_usb_final(const dlo_final_t flags)
+{
+ if (usb_err_str)
+ dlo_free(usb_err_str);
+
+ return dlo_ok;
+}
+
+
+dlo_retcode_t dlo_usb_enumerate(const bool init)
+{
+ struct usb_bus *bus;
+ struct usb_device *dev = NULL;
+ int32_t db = usb_find_busses();
+ int32_t dd = usb_find_devices();
+
+ /* We should do this even if it looks like there are no changes on the bus because
+ * an open() call might call the above functions just to check it's safe to use the
+ * USB device structure pointer. Yuck!
+ *
+ * If this isn't the first enumeration and there are no changes on the bus, don't touch the list
+ *
+ * if (!init && !db && !dd)
+ * return dlo_ok;
+ */
+ IGNORE(db);
+ IGNORE(dd);
+
+ /* Look for all DisplayLink devices on the USB busses */
+ for (bus = usb_busses; bus; bus = bus->next)
+ for (dev = bus->devices; dev; dev = dev->next)
+ ERR(check_device(dev)); /* Check to see if it's a DisplayLink device. If it is, add to or update the dev_list */
+
+ return dlo_ok;
+}
+
+
+dlo_retcode_t dlo_usb_open(dlo_device_t * const dev)
+{
+ dlo_retcode_t err;
+ usb_dev_handle *uhand;
+ int32_t db = usb_find_busses();
+ int32_t dd = usb_find_devices();
+
+ /* Do we trust the USB device pointer? Not if the structures may have changed under us... */
+ if (db || dd)
+ return dlo_err_reenum;
+
+ /* Open the device */
+ uhand = usb_open(dev->cnct->udev);
+ //DPRINTF("usb: open: uhand &%X\n", (int)uhand);
+
+ if (!uhand)
+ return dlo_err_open;
+
+ /* Store the USB device handle in our dev->cnct word */
+ dev->cnct->uhand = uhand;
+
+ /* Establish the connection with the device */
+ //DPRINTF("usb: open: setting config...\n");
+ UERR(usb_set_configuration(uhand, 1));
+
+ //DPRINTF("usb: open: claiming iface...\n");
+ UERR(usb_claim_interface(uhand, 0));
+
+ /* Mark the device as claimed */
+ dev->claimed = true;
+
+ /* Allocate a buffer to hold commands before they are sent to the device */
+ if (!dev->buffer)
+ {
+ //DPRINTF("usb: open: alloc buffer...\n");
+ dev->buffer = dlo_malloc(BUF_SIZE);
+ NERR(dev->buffer);
+ dev->bufptr = dev->buffer;
+ dev->bufend = dev->buffer + BUF_SIZE;
+ }
+ //DPRINTF("usb: open: buffer &%X, &%X, &%X\n", (int)dev->buffer, (int)dev->bufptr, (int)dev->bufend);
+
+ /* Use the default timeout if none was specified */
+ if (!dev->timeout)
+ dev->timeout = WRITE_TIMEOUT;
+ //DPRINTF("usb: open: timeout %u ms\n", dev->timeout);
+
+ /* Initialise the supported modes array for this device to include all our pre-defined modes */
+ use_default_modes(dev);
+
+ /* Attempt to read the EDID information, to refine the supported modes array contents */
+ err = read_edid(dev, uhand);
+#ifdef DEBUG
+ if (err != dlo_ok)
+ DPRINTF("usb: open: edid error %u '%s'\n", (int)err, dlo_strerror(err));
+#endif
+
+ return dlo_ok;
+}
+
+
+dlo_retcode_t dlo_usb_close(dlo_device_t * const dev)
+{
+ if (dev->claimed)
+ {
+ if (dev->buffer)
+ {
+ dlo_free(dev->buffer);
+ dev->buffer = NULL;
+ dev->bufptr = NULL;
+ dev->bufend = NULL;
+ }
+ dev->claimed = false;
+ UERR(usb_release_interface(dev->cnct->uhand, 0));
+ UERR(usb_close(dev->cnct->uhand));
+ }
+ return dlo_ok;
+}
+
+
+dlo_retcode_t dlo_usb_chan_sel(const dlo_device_t * const dev, const char * const buf, const size_t size)
+{
+ if (size)
+ UERR(usb_control_msg(/* handle */ dev->cnct->uhand,
+ /* requestType */ USB_TYPE_VENDOR,
+ /* request */ NR_USB_REQUEST_CHANNEL,
+ /* value */ 0,
+ /* index */ 0,
+ /* bytes */ (char *)buf,
+ /* size */ size,
+ /* timeout */ CHANSEL_TIMEOUT));
+ return dlo_ok;
+}
+
+
+dlo_retcode_t dlo_usb_std_chan(const dlo_device_t * const dev)
+{
+ dlo_retcode_t err;
+
+ ASSERT(strlen(STD_CHANNEL) == 16);
+ err = dlo_usb_chan_sel(dev, STD_CHANNEL, DSIZEOF(STD_CHANNEL));
+
+ return err;
+}
+
+
+dlo_retcode_t dlo_usb_write(dlo_device_t * const dev)
+{
+ dlo_retcode_t err = dlo_usb_write_buf(dev, dev->buffer, dev->bufptr - dev->buffer);
+
+ dev->bufptr = dev->buffer;
+
+ return err;
+}
+
+
+dlo_retcode_t dlo_usb_write_buf(dlo_device_t * const dev, char * buf, size_t size)
+{
+#ifdef DEBUG_DUMP
+ static char outfile[64];
+ static uint32_t outnum = 0;
+ FILE *out = NULL;
+#endif
+
+ if (!dev->claimed)
+ return dlo_err_unclaimed;
+
+ if (!size)
+ return dlo_ok;
+
+#ifdef WRITE_BUF_BODGE
+ /* If the buffer to write is fewer than 513 bytes in size, copy into 513 byte buffer and pad with zeros */
+ if (size < WRITE_BUF_BODGE)
+ {
+ dlo_retcode_t err;
+ uint32_t rem = WRITE_BUF_BODGE - size;
+ char *cpy = dlo_malloc(WRITE_BUF_BODGE);
+
+ NERR(cpy);
+ dlo_memcpy(cpy, buf, size);
+ dlo_memset(cpy + size, 0, rem);
+ err = dlo_usb_write_buf(dev, cpy, size + rem);
+ dlo_free(cpy);
+
+ return err;
+ }
+#endif
+
+ while (size)
+ {
+ size_t num = size > BUF_SIZE ? BUF_SIZE : size;
+
+#ifdef DEBUG_DUMP
+ (void) snprintf(outfile, sizeof(outfile), "dump/%02X/bulk%03X.dat", outnum & 0xFF, outnum >> 8);
+ outnum++;
+ out = fopen(outfile, "wb");
+ if (out)
+ {
+ (void) fwrite(buf, num, 1, out);
+ (void) fclose(out);
+ out = NULL;
+ }
+#endif
+
+ UERR(usb_bulk_write(/* handle */ dev->cnct->uhand,
+ /* endpoint */ 1,
+ /* bytes */ buf,
+ /* size */ num,
+ /* timeout */ dev->timeout));
+ buf += num;
+ size -= num;
+ }
+ return dlo_ok;
+}
+
+
+/* File-scope function definitions -----------------------------------------------------*/
+
+
+static dlo_retcode_t usb_error_grab(void)
+{
+ char *str = usb_strerror();
+
+ /* If we have a previous USB error message stored, free it */
+ if (usb_err_str)
+ dlo_free(usb_err_str);
+
+ if (str)
+ {
+ /* Allocate memory for the new error message and store that */
+ usb_err_str = dlo_malloc(1 + strlen(str));
+ if (usb_err_str)
+ strcpy(usb_err_str, str);
+ }
+
+ /* Always return the generic USB error code */
+ return dlo_err_usb;
+}
+
+
+static dlo_retcode_t check_device(struct usb_device *udev)
+{
+ static char string[255];
+ usb_dev_handle *uhand = usb_open(udev);
+ dlo_retcode_t err = dlo_ok;
+ dlo_device_t *dev = NULL;
+ bool not_root = false;
+ uint8_t buf[4];
+ dlo_devtype_t type;
+
+ //DPRINTF("usb: check: check dev &%X\n", (int)dev);
+
+ if (!uhand)
+ return dlo_err_open;
+
+ //DPRINTF("usb: check: uhand &%X vendorID &%X\n", (int)uhand, udev->descriptor.idVendor);
+
+ /* Reject devices that don't have the DisplayLink VendorID */
+ if (udev->descriptor.idVendor != VENDORID_DISPLAYLINK)
+ {
+ UERR(usb_close(uhand));
+ return dlo_ok;
+ }
+ //DPRINTF("usb: check: get type\n");
+
+ /* Ask the device for some status information */
+ not_root = true; /* Special case error handling here */
+ UERR_GOTO(usb_control_msg(/* handle */ uhand,
+ /* requestType */ USB_ENDPOINT_IN | USB_TYPE_VENDOR,
+ /* request */ NR_USB_REQUEST_STATUS_DW,
+ /* value */ 0,
+ /* index */ 0,
+ /* bytes */ (char *)buf,
+ /* size */ sizeof(buf),
+ /* timeout */ ID_TIMEOUT));
+ not_root = false; /* Back to normal error handling */
+ //DPRINTF("usb: check: type buf[3] = &%X\n", buf[3]);
+
+ /* Determine what type of device we are connected to */
+ switch ((buf[3] >> 4) & 0xF)
+ {
+ case dlo_dev_base:
+ type = dlo_dev_base;
+ break;
+ case dlo_dev_alex:
+ type = dlo_dev_alex;
+ break;
+ default:
+ if (buf[3] == dlo_dev_ollie)
+ type = dlo_dev_ollie;
+ else
+ type = dlo_dev_unknown;
+ }
+
+ /* Read the device serial number as a string */
+ UERR_GOTO(usb_get_string_simple(uhand, udev->descriptor.iSerialNumber, string, sizeof(string)));
+ //DPRINTF("usb: check: type &%X serial '%s'\n", (int)type, string);
+
+ /* See if this device is already in our device list */
+ dev = dlo_device_lookup(string);
+ if (dev)
+ {
+ /* Use this opportunity to update the USB device structure pointer, just in
+ * case it has moved.
+ */
+ dev->cnct->udev = udev;
+ //DPRINTF("usb: check: already in list\n");
+ }
+ else
+ {
+ /* Add a new device to the device list */
+ //DPRINTF("usb: check: create new device\n");
+ dev = dlo_new_device(type, string);
+ NERR_GOTO(dev);
+
+ /* It's not. Create and initialise a new list node for the device */
+ dev->cnct = (dlo_usb_dev_t *)dlo_malloc(sizeof(dlo_usb_dev_t));
+ NERR_GOTO(dev->cnct);
+ dev->cnct->udev = udev;
+ dev->cnct->uhand = NULL;
+ }
+ //DPRINTF("usb: check: dlpp node &%X\n", (int)dev);
+
+ /* Close our temporary handle for the device. If this errors, we'll have a duff entry in
+ * the device list but at least the list integrity will be OK.
+ */
+ UERR_GOTO(usb_close(uhand));
+
+ return dlo_ok;
+
+error:
+ /* Free our dev->cnct USB information structure */
+ if (dev->cnct)
+ dlo_free(dev->cnct);
+ dev->cnct = NULL;
+
+ /* Close our temporary handle for the device */
+ (void) usb_close(uhand);
+
+ /* If the executable wasn't run as root, this is where it normally falls over.
+ * So we'll special case that particular error to help indicate this problem.
+ */
+ if (not_root)
+ return dlo_err_not_root;
+
+ return err;
+}
+
+
+static dlo_retcode_t read_edid(dlo_device_t * const dev, usb_dev_handle *uhand)
+{
+ dlo_retcode_t err;
+ uint32_t i;
+ uint8_t buf[2];
+ uint8_t *edid;
+
+ /* Allocate a buffer to hold the EDID structure */
+ edid = dlo_malloc(EDID_STRUCT_SZ);
+ NERR(edid);
+
+ /* Attempt to read the EDID structure from the device */
+ for (i = 0; i < EDID_STRUCT_SZ; i++)
+ {
+ UERR_GOTO(usb_control_msg(/* handle */ uhand,
+ /* requestType */ USB_ENDPOINT_IN | USB_TYPE_VENDOR,
+ /* request */ NR_USB_REQUEST_I2C_SUB_IO,
+ /* value */ i << 8,
+ /* index */ 0xA1,
+ /* bytes */ (char *)buf,
+ /* size */ sizeof(buf),
+ /* timeout */ dev->timeout));
+ if (buf[0])
+ ERR_GOTO(dlo_err_iic_op);
+ //DPRINTF("usb: edid[%u]=&%02X\n", i, buf[1]);
+ edid[i] = buf[1];
+ }
+
+ /* Supply the prospective EDID structure to the parser */
+ ERR_GOTO(dlo_mode_parse_edid(dev, edid, EDID_STRUCT_SZ));
+
+error:
+ dlo_free(edid);
+
+ return err;
+}
+
+
+/* End of file -------------------------------------------------------------------------*/
diff --git a/src/libdlo.c b/src/libdlo.c
new file mode 100644
index 0000000..2ddb3b6
--- /dev/null
+++ b/src/libdlo.c
@@ -0,0 +1,902 @@
+/** @file libdlo.c
+ *
+ * @brief This file implements the high-level API for the DisplayLink libdlo library.
+ *
+ * DisplayLink Open Source Software (libdlo)
+ * Copyright (C) 2009, DisplayLink
+ * www.displaylink.com
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by the Free
+ * Software Foundation; LGPL version 2, dated June 1991.
+ *
+ * This library 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 Library General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <string.h>
+#include "dlo_defs.h"
+#include "dlo_grfx.h"
+#include "dlo_mode.h"
+#include "dlo_usb.h"
+
+
+/* File-scope defines ------------------------------------------------------------------*/
+
+
+/** Structure to hold information about how a rectangle may have been clipped
+ */
+typedef struct clip_s
+{
+ uint32_t left; /**< Number of pixels clipped from left edge. */
+ uint32_t right; /**< Number of pixels clipped from right edge. */
+ uint32_t below; /**< Number of pixels clipped from bottom edge. */
+ uint32_t above; /**< Number of pixels clipped from top edge. */
+} clip_t; /**< A struct @a clip_s. */
+
+
+/** Return value from function to check source and destination viewports in the rectangle copy function.
+ */
+typedef enum
+{
+ vstat_good_view = 0, /**< Viewports are both good, not overlapping. */
+ vstat_good_overlap, /**< Viewports are both the same. */
+ vstat_bad_view, /**< Something is wrong with one or other viewport. */
+ vstat_bad_overlap /**< Viewports overlap but are not identical. */
+} vstat_t;
+
+
+/* File-scope inline functions ---------------------------------------------------------*/
+
+
+/* File-scope types --------------------------------------------------------------------*/
+
+
+/* External-scope variables ------------------------------------------------------------*/
+
+
+char err_file[1024] = { '\0' };
+
+
+uint32_t err_line = 0;
+
+
+/* File-scope variables ----------------------------------------------------------------*/
+
+
+/** Pointer to the head node in the device list.
+ */
+static dlo_device_t *dev_list = NULL;
+
+
+/** Flag is toggled at each enumeration to spot removed devices.
+ */
+static bool check_state = false;
+
+
+/* File-scope function declarations ----------------------------------------------------*/
+
+
+/** Check that the specified device (pointer) corresponds to a current list node.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ *
+ * @return true if the device is in the device list, else false.
+ *
+ * This is a less-than-perfect test because although the device structure may have
+ * been removed from the list, a new device structure may have been allocated into
+ * the same address at some later point.
+ *
+ * Ideally, this library should hold structures which themselves point to a device
+ * structure and include a flag saying whether the pointer is still valid (which is
+ * cleared when the device structure is freed). The UID passed into dlo calls would
+ * be a pointer to this (small) structure. The (small) structures are leaked so that
+ * it is possible to spot stale pointers from the caller.
+ */
+static bool valid_device(const dlo_device_t * const dev);
+
+
+/** Remove the specified device from the device list.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ *
+ * @return Return code, zero for no error.
+ *
+ * This call will delink the specified device structure from the device list
+ * and free any resources associated with the device (including "releasing"
+ * the device).
+ *
+ * NOTE: the @a dev_list variable is updated as a side-effect of this function.
+ */
+static dlo_retcode_t remove_device(dlo_device_t *dev);
+
+
+/** Initialise an area structure based upon a viewport and rectangle within it.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ * @param view Pointer to the viewport structure (may be NULL).
+ * @param rec Pointer to a rectangle structure (may be NULL).
+ * @param area Pointer to area structure to initialise from @a view and @a rec.
+ * @param clip Pointer to list of offsets that the source rectangle was clipped by.
+ *
+ * @return true if the area still has extent, false if it was clipped to nothing.
+ *
+ * Given a viewport and rectangle within that viewport, calculate the corresponding area
+ * structure by clipping the rectangle as required so that no part of it lies outside of
+ * the viewport.
+ *
+ * Where the viewport is NULL on entry, the viewport for the current display screen is
+ * used. Where the rectangle is NULL on entry, the whole of the viewport is used.
+ *
+ * This call also updates the contents of the @a clip structure as a side-effect to
+ * indicate how many pixels were clipped from each edge of the rectangle in order to
+ * arrive at the output area. This is useful if another rectangle needs to be clipped
+ * to match the output rectangle.
+ */
+static bool sanitise_view_rect(const dlo_device_t * const dev, const dlo_view_t * const view, const dlo_rect_t * const rec, dlo_area_t * const area, clip_t * const clip);
+
+
+/** For the rectangle copy, check that overlapping rectangles have exactly the same viewport.
+ *
+ * @param dev Pointer to @a dlo_device_t structure.
+ * @param src_view Pointer to source viewport structure.
+ * @param dest_view Pointer to destination viewport structure.
+ *
+ * @return true if they don't overlap, or do overlap and are identical. Else returns false.
+ */
+static vstat_t check_overlaps(const dlo_device_t * const dev, const dlo_view_t * const src_view, const dlo_view_t * const dest_view);
+
+
+/* Public function definitions ---------------------------------------------------------*/
+
+
+#if 0
+static uint32_t total_alloc = 0;
+
+void *my_malloc(size_t size)
+{
+ uint32_t *blk = malloc(size + sizeof(uint32_t));
+
+ if (blk)
+ {
+ *blk = size;
+ total_alloc += size;
+ blk++;
+ }
+ DPRINTF("alloc: malloc &%X is %u bytes (total %u)\n", (uint32_t)blk, size, total_alloc);
+
+ return (void *)blk;
+}
+
+
+void *my_realloc(void *blk, size_t size)
+{
+ uint32_t *myblk = (uint32_t *)blk;
+
+ if (myblk)
+ {
+ myblk--;
+ if (size)
+ {
+ myblk = realloc(myblk, size + sizeof(uint32_t));
+ if (myblk)
+ {
+ total_alloc -= *myblk;
+ total_alloc += size;
+ *myblk = size;
+ myblk++;
+ }
+ }
+ else
+ {
+ /* Free a block */
+ total_alloc -= *myblk;
+ myblk = realloc(myblk, 0);
+ }
+ }
+ else
+ {
+ /* Claim a new block */
+ myblk = realloc(NULL, size + sizeof(uint32_t));
+ if (myblk)
+ {
+ *myblk = size;
+ total_alloc += size;
+ myblk++;
+ }
+ }
+ DPRINTF("alloc: realloc &%X to %u bytes (total %u)\n", (uint32_t)myblk, size, total_alloc);
+
+ return (void *)myblk;
+}
+
+
+void my_free(void *blk)
+{
+ uint32_t *myblk = (uint32_t *)blk;
+
+ myblk--;
+ total_alloc -= *myblk;
+ free(myblk);
+
+ DPRINTF("alloc: free &%X (total %u)\n", (uint32_t)blk, total_alloc);
+}
+
+
+uint32_t my_used(void)
+{
+ return total_alloc;
+}
+#endif
+
+
+const char *dlo_strerror(const dlo_retcode_t err)
+{
+ static char str[1024];
+ char *msg;
+
+ switch (err)
+ {
+ /* Success... */
+ case dlo_ok: return "Successful";
+ /* Errors... */
+ case dlo_err_memory: break;
+ case dlo_err_bad_area: return "An invalid area was specified (e.g. of zero width or height)";
+ case dlo_err_bad_col: return "Unsupported colour depth";
+ case dlo_err_bad_device: return "Unknown device, possibly disconnected or powered down";
+ case dlo_err_bad_fbuf: return "Null pointer passed as local bitmap data";
+ case dlo_err_bad_fmt: return "Unsupported bitmap pixel format";
+ case dlo_err_bad_mode: return "Call to dlo_set_mode() failed due to unsupported mode parameters";
+ case dlo_err_bad_view: return "Invalid viewport specified (is screen mode set up?)";
+ case dlo_err_big_scrape: return "Bitmap is too wide for copy buffer";
+ case dlo_err_buf_full: return "Command buffer is full";
+ case dlo_err_claimed: return "Device is already claimed";
+ case dlo_err_edid_fail: return "Attempt to access EDID information failed";
+ case dlo_err_iic_op: return "IIC operation with device failed";
+ case dlo_err_not_root: return "Executable should be run as root (e.g. using 'su root' or 'sudo')";
+ case dlo_err_open: return "Attempt to open connection to device failed";
+ case dlo_err_overlap: return "Source and destination viewports cannot overlap (unless the same)";
+ case dlo_err_reenum: return "Reenumeration required before device can be claimed";
+ case dlo_err_unclaimed: return "Device cannot be written to: unclaimed";
+ case dlo_err_unsupported: return "Requested feature is not supported";
+ case dlo_err_usb: return dlo_usb_strerror();
+ /* Warnings... */
+ case dlo_warn_dl160_mode: return "This screen mode may not display correctly on DL120 devices";
+ default: return "Unknown error";
+ }
+
+ /* Memory allocation errors should have more information associated with them */
+ msg = "A memory claim operation failed; out of memory";
+ if (err_file[0])
+ snprintf(&str[0], sizeof(str), "%s:%u: %s", &err_file[0], err_line, msg);
+ else
+ snprintf(&str[0], sizeof(str), "%s", msg);
+ err_file[0] = '\0';
+ err_line = 0;
+ return str;
+}
+
+
+dlo_retcode_t dlo_init(const dlo_init_t flags)
+{
+ /* Initialise the graphics primitives */
+ DPRINTF("dlo: grfx_init\n");
+ ERR(dlo_grfx_init(flags));
+
+ /* Initialise the screen mode timings array */
+ DPRINTF("dlo: mode_init\n");
+ ERR(dlo_mode_init(flags));
+
+ /* Initialise the USB comms code and function pointer table */
+ DPRINTF("dlo: usb_init\n");
+ ERR(dlo_usb_init(flags));
+
+ return dlo_ok;
+}
+
+
+dlo_retcode_t dlo_final(const dlo_final_t flags)
+{
+ /* Free all claimed structures */
+ while (dev_list)
+ {
+ (void) remove_device(dev_list);
+ }
+
+ ERR(dlo_grfx_final(flags));
+ ERR(dlo_mode_final(flags));
+ ERR(dlo_usb_final(flags));
+
+ return dlo_ok;
+}
+
+
+dlo_devlist_t *dlo_enumerate_devices(void)
+{
+ dlo_devlist_t *out = NULL;
+ dlo_device_t *dev;
+ dlo_retcode_t err;
+ uint32_t num;
+
+ check_state = !check_state;
+
+ /* Check USB for all DisplayLink devices that we can find. If there is an error returned,
+ * then it is likely that the devlist could become out of step with reality. For that
+ * reason, after any error, we throw away all unclaimed devices from the devlist to try to
+ * minimise the chances.
+ */
+ // DPRINTF("dlo: enum: enumerating USB devices\n");
+ ERR_GOTO(dlo_usb_enumerate(false));
+
+ /* Remove all devices which weren't updated or added during this enumeration and
+ * build the list of device information to return. Note: if a dlo_malloc() call
+ * fails during this operation, we note it and continue otherwise the dev_list could
+ * get out of step with reality.
+ */
+ dev = dev_list;
+ out = NULL;
+ num = 0;
+ while (dev)
+ {
+ dlo_device_t *next = dev->next;
+
+ if (dev->check == check_state)
+ {
+ dlo_devlist_t *tmp = (dlo_devlist_t *)dlo_malloc(sizeof(dlo_devlist_t));
+
+ /* Add a node to the output list */
+ if (tmp)
+ {
+ tmp->next = out;
+ tmp->dev.uid = (dlo_dev_t)dev;
+ tmp->dev.serial = dev->serial;
+ tmp->dev.type = dev->type;
+ tmp->dev.claimed = dev->claimed;
+ out = tmp;
+ num++;
+ }
+ else
+ err = dlo_err_memory;
+ }
+ else
+ {
+ // DPRINTF("dlo: enum: removed device &%X (%s)\n", (int)dev, dev->serial);
+ (void) remove_device(dev);
+ }
+ dev = next;
+ }
+
+ /* Return pointer to output list if operation was successful */
+ if (!err)
+ {
+ // DPRINTF("dlo: enum: return list of %u entries\n", num);
+ return out;
+ }
+
+error:
+ DPRINTF("dlo: enum: error &%X (usberr &%X)\n", err, usberr);
+
+ /* Throw the output list away */
+ while (out)
+ {
+ dlo_devlist_t *next = out->next;
+
+ dlo_free(out);
+ out = next;
+ }
+
+ /* Remove all unclaimed devices from our list */
+ dev = dev_list;
+ while (dev)
+ {
+ dlo_device_t *next = dev->next;
+
+ if (!dev->claimed)
+ (void) remove_device(dev);
+ dev = next;
+ }
+ return NULL;
+}
+
+
+dlo_dev_t dlo_claim_device(const dlo_dev_t uid, const dlo_claim_t flags, const uint32_t timeout)
+{
+ dlo_device_t *dev = (dlo_device_t *)uid;
+ dlo_retcode_t err;
+
+ if (!dev)
+ ERR_GOTO(dlo_err_bad_device);
+
+ /* Confirm that the device structure pointer still exists */
+ if (!valid_device(dev))
+ ERR_GOTO(dlo_err_bad_device);
+
+ /* Return error if device has already been claimed */
+ if (dev->claimed)
+ ERR_GOTO(dlo_err_claimed);
+
+ dev->timeout = timeout;
+
+ /* Attempt to open a connection to the device */
+ err = dlo_usb_open(dev);
+ while (err == dlo_err_reenum)
+ {
+ /* If the USB bus devices have changed, do the enumeration again */
+ dlo_devlist_t *out = dlo_enumerate_devices();
+
+ /* Throw the output list away */
+ while (out)
+ {
+ dlo_devlist_t *next = out->next;
+
+ dlo_free(out);
+ out = next;
+ }
+
+ /* Confirm that the device structure pointer still exists */
+ if (!valid_device(dev))
+ ERR_GOTO(dlo_err_bad_device);
+
+ /* Now try opening the connection again */
+ err = dlo_usb_open(dev);
+ }
+ /* Any other errors from opening the connection get returned to the caller */
+ ERR_GOTO(err);
+
+ /* Select the standard output channel */
+ ERR_GOTO(dlo_usb_std_chan(dev));
+
+ /* Attempt to change mode into the native resolution of the display (if we have one) */
+ if (dev->native.view.width)
+ ERR_GOTO(dlo_mode_change(dev, &dev->native, DLO_INVALID_MODE));
+
+ return uid;
+
+error:
+ DPRINTF("dlo: claim: error %u '%s'\n", (int)err, dlo_strerror(err));
+
+ return (dlo_dev_t)0;
+}
+
+
+dlo_dev_t dlo_claim_first_device(const dlo_claim_t flags, const uint32_t timeout)
+{
+ dlo_devlist_t *node;
+ dlo_devlist_t *next;
+ dlo_dev_t uid = 0;
+
+ /* Look for a DisplayLink device to connect to - note the first one which is unclaimed */
+ node = dlo_enumerate_devices();
+ while (node)
+ {
+ dlo_device_t *dev = (dlo_device_t *)node->dev.uid;
+
+ if (!uid && !dev->claimed)
+ uid = node->dev.uid;
+
+ /* Free this list node and move on to the next one */
+ next = node->next;
+ dlo_free(node);
+ node = next;
+ }
+ return uid ? dlo_claim_device(uid, flags, timeout) : (dlo_dev_t)0;
+}
+
+
+dlo_retcode_t dlo_release_device(const dlo_dev_t uid)
+{
+ dlo_device_t *dev = (dlo_device_t *)uid;
+
+ return dev ? dlo_usb_close(dev) : dlo_err_bad_device;
+}
+
+
+dlo_devinfo_t *dlo_device_info(const dlo_dev_t uid)
+{
+ static dlo_devinfo_t info;
+ dlo_device_t *dev = (dlo_device_t *)uid;
+
+ if (!dev)
+ return NULL;
+
+ info.uid = uid;
+ info.serial = dev->serial;
+ info.type = dev->type;
+ info.claimed = dev->claimed;
+
+ return &info;
+}
+
+
+dlo_retcode_t dlo_set_mode(const dlo_dev_t uid, const dlo_mode_t * const desc)
+{
+ dlo_device_t *dev = (dlo_device_t *)uid;
+ dlo_modenum_t num;
+
+ if (!dev)
+ return dlo_err_bad_device;
+
+ /* See if we can provide a mode which matches the required parameters */
+ num = dlo_mode_lookup(dev, desc->view.width, desc->view.height, desc->refresh, desc->view.bpp);
+ DPRINTF("dlo: set_mode: lookup %d\n", (int32_t)num);
+
+ return num == DLO_INVALID_MODE ? dlo_err_bad_mode : dlo_mode_change(dev, desc, num);
+}
+
+
+dlo_mode_t *dlo_get_mode(const dlo_dev_t uid)
+{
+ dlo_device_t *dev = (dlo_device_t *)uid;
+
+ return dev ? &(dev->mode) : NULL;
+}
+
+
+dlo_retcode_t dlo_fill_rect(const dlo_dev_t uid, const dlo_view_t * const view, const dlo_rect_t * const rec, const dlo_col32_t col)
+{
+ static clip_t clip;
+ static dlo_area_t area;
+ dlo_device_t * const dev = (dlo_device_t *)uid;
+
+ if (!dev)
+ return dlo_err_bad_device;
+
+ /* Clip the rectangle to its viewport edges */
+ if (!sanitise_view_rect(dev, view, rec, &area, &clip))
+ return dlo_ok;
+
+ return dlo_grfx_fill_rect(dev, &area, col);
+}
+
+
+dlo_retcode_t dlo_copy_rect(const dlo_dev_t uid,
+ const dlo_view_t * const src_view, const dlo_rect_t * const src_rec,
+ const dlo_view_t * const dest_view, const dlo_dot_t * const dest_pos)
+{
+ static clip_t clip;
+ static dlo_area_t src_area;
+ static dlo_area_t dest_area;
+ static dlo_rect_t dest_rec;
+ dlo_device_t * const dev = (dlo_device_t *)uid;
+ bool overlap = false;
+
+ if (!dev)
+ return dlo_err_bad_device;
+
+ /* Check to see if (and how) the source and destination viewports overlap */
+ switch (check_overlaps(dev, src_view, dest_view))
+ {
+ case vstat_good_view:
+ break;
+ case vstat_bad_view:
+ return dlo_err_bad_view;
+ case vstat_bad_overlap:
+ return dlo_err_overlap;
+ default:
+ {
+ DPRINTF("dlo: copy_rec: src_view == dest_view... overlap? ");
+ overlap = (dest_pos->x + src_rec->width > src_rec->origin.x) &&
+ (dest_pos->y + src_rec->height > src_rec->origin.y) &&
+ (dest_pos->x < src_rec->origin.x + src_rec->width) &&
+ (dest_pos->y < src_rec->origin.y + src_rec->height);
+ DPRINTF("%s\n", overlap ? "yes" : "no");
+ }
+ }
+
+ /* Clip the source rectangle to its viewport edges */
+ if (!sanitise_view_rect(dev, src_view, src_rec, &src_area, &clip))
+ return dlo_ok;
+
+ /* Clip the destination rectangle by the same amounts as we needed to clip the source */
+ dest_rec.origin.x = dest_pos ? dest_pos->x + clip.left : clip.left;
+ dest_rec.origin.y = dest_pos ? dest_pos->y + clip.below : clip.below;
+ dest_rec.width = src_area.view.width;
+ dest_rec.height = src_area.view.height;
+
+ /* Further clip the destination rectangle to its viewport edges */
+ if (!sanitise_view_rect(dev, dest_view, &dest_rec, &dest_area, &clip))
+ return dlo_ok;
+
+ /* Further clip the source area by the same amounts as we needed to clip the destination */
+ src_area.view.base += (BYTES_PER_16BPP * clip.left) + (BYTES_PER_16BPP * clip.below * src_area.stride);
+ src_area.base8 += (BYTES_PER_8BPP * clip.left) + (BYTES_PER_8BPP * clip.below * src_area.stride);
+ src_area.view.width = dest_area.view.width;
+ src_area.view.height = dest_area.view.height;
+
+ return dlo_grfx_copy_rect(dev, &src_area, &dest_area, overlap);
+}
+
+
+dlo_retcode_t dlo_copy_host_bmp(const dlo_dev_t uid, const dlo_bmpflags_t flags,
+ const dlo_fbuf_t * const fbuf,
+ const dlo_view_t * const dest_view, const dlo_dot_t * const dest_pos)
+{
+ static clip_t clip;
+ static dlo_area_t dest_area;
+ static dlo_rect_t dest_rec;
+ static dlo_fbuf_t src_fbuf;
+ dlo_device_t * const dev = (dlo_device_t *)uid;
+ uint32_t off;
+
+ /* Do some sanity checks */
+ if (!dev)
+ return dlo_err_bad_device;
+
+ if (!fbuf)
+ return dlo_err_bad_fbuf;
+
+ if (!fbuf->width || !fbuf->height)
+ return dlo_ok;
+
+ /* Clip the destination rectangle to its viewport edges */
+ src_fbuf = *fbuf;
+ dest_rec.origin.x = dest_pos ? dest_pos->x : 0;
+ dest_rec.origin.y = dest_pos ? dest_pos->y : 0;
+ dest_rec.width = src_fbuf.width;
+ dest_rec.height = src_fbuf.height;
+ if (!sanitise_view_rect(dev, dest_view, &dest_rec, &dest_area, &clip))
+ return dlo_ok;
+
+ /* Update the source framebuffer information if the destination was clipped */
+ off = clip.left + (clip.below * src_fbuf.stride);
+ off *= FORMAT_TO_BYTES_PER_PIXEL(src_fbuf.fmt);
+ src_fbuf.base = (void *)((unsigned long)src_fbuf.base + (unsigned long)off);
+ src_fbuf.width -= clip.left + clip.right;
+ src_fbuf.height -= clip.below + clip.above;
+
+ return dlo_grfx_copy_host_bmp(dev, flags, &src_fbuf, &dest_area);
+}
+
+
+dlo_device_t *dlo_new_device(const dlo_devtype_t type, const char * const serial)
+{
+ dlo_device_t *dev = (dlo_device_t *)dlo_malloc(sizeof(dlo_device_t));
+ char *str = NULL;
+ dlo_retcode_t err;
+
+ NERR_GOTO(dev);
+
+ /* Copy the serial number string and keep a pointer to it */
+ str = dlo_malloc(1 + strlen(serial));
+ NERR_GOTO(str);
+ dev->serial = str;
+ strcpy(dev->serial, serial);
+
+ /* Link into the device list structure */
+ dev->prev = NULL;
+ dev->next = dev_list;
+ dev_list = dev;
+ dev->claimed = false;
+
+ /* Defaults are for an "Alex" device via USB */
+ dev->type = type;
+ dev->check = check_state;
+ dev->timeout = 0;
+
+ /* Mode-dependent attributes and function pointers */
+ dev->mode.view.width = 0;
+ dev->mode.view.height = 0;
+ dev->mode.view.bpp = 0;
+ dev->mode.refresh = 0;
+ dev->mode.view.base = 0;
+ dev->base8 = 0;
+ dev->low_blank = false;
+
+ /* Device-dependent attributes */
+ dev->buffer = NULL;
+
+ /* Connection-dependent attributes.
+ *
+ * It is up to the communications code (re)initialise this values to something which
+ * makes sense to it.
+ */
+ dev->cnct = NULL;
+
+ /* Set up some feature flags based upon what we know about DisplayLink device types.
+ *
+ * NOTE: this section will probably become more refined as more features are added
+ * to libdlo. Currently, it assumes all devices are the same.
+ */
+ dev->memory = 16 * 1024 * 1024;
+
+ DPRINTF("dlo: new_device: initialised &%X\n", (int)dev);
+
+ return dev;
+
+error:
+ if (str)
+ dlo_free(str);
+ if (dev)
+ dlo_free(dev);
+
+ return NULL;
+}
+
+
+dlo_device_t *dlo_device_lookup(const char * const serial)
+{
+ dlo_device_t *dev = dev_list;
+
+ DPRINTF("dlo: lookup: '%s' dev_list &%X\n", serial, (int)dev_list);
+
+ while (dev)
+ {
+ DPRINTF("dlo: lookup: dev &%X serial '%s'\n", (int)dev, dev->serial);
+ if (0 == strcmp(dev->serial, serial))
+ {
+ dev->check = check_state;
+ return dev;
+ }
+ dev = dev->next;
+ }
+ return NULL;
+}
+
+
+/* File-scope function definitions -----------------------------------------------------*/
+
+
+static bool valid_device(const dlo_device_t * const dev)
+{
+ dlo_device_t *node = dev_list;
+
+ while (node)
+ {
+ if (node == dev)
+ return true;
+ node = node->next;
+ }
+ return false;
+}
+
+
+static dlo_retcode_t remove_device(dlo_device_t *dev)
+{
+ dlo_retcode_t err;
+ dlo_device_t *prev = dev->prev;
+ dlo_device_t *next = dev->next;
+
+ /* Delink the device from the device list */
+ if (prev)
+ prev->next = next;
+ else
+ dev_list = next;
+ if (next)
+ next->prev = prev;
+
+ /* Disconnect from the device (if connected) */
+ if (dev->claimed)
+ err = dlo_usb_close(dev);
+ else
+ err = dlo_ok;
+
+ /* Free the structure (and associated data) even if there was an error */
+ if (dev->serial)
+ dlo_free(dev->serial);
+ dlo_free(dev);
+
+ return err;
+}
+
+
+static bool sanitise_view_rect(const dlo_device_t * const dev, const dlo_view_t * const view, const dlo_rect_t * const rec, dlo_area_t * const area, clip_t * const clip)
+{
+ static dlo_rect_t my_rec;
+ const dlo_view_t * const my_view = view ? view : &(dev->mode.view);
+ uint32_t pix_off;
+
+ /* Exit here if my_view is still NULL (i.e. no screen mode is set up yet) */
+ if (!my_view)
+ return false;
+
+ /* Default the rectangle to the whole of the the view, if none was specified */
+ if (rec)
+ my_rec = *rec;
+ else
+ {
+ my_rec.origin.x = 0;
+ my_rec.origin.y = 0;
+ my_rec.width = my_view->width;
+ my_rec.height = my_view->height;
+ }
+
+ /* Exit here if the source rectangle is never going to appear in the viewport */
+ if (my_rec.origin.x + (int32_t)my_rec.width < 0 || my_rec.origin.y + (int32_t)my_rec.height < 0)
+ return false;
+ if (my_rec.origin.x >= (int32_t)my_view->width || my_rec.origin.y >= (int32_t)my_view->height)
+ return false;
+
+ /* Initialise the clip structure to empty */
+ clip->left = 0;
+ clip->right = 0;
+ clip->below = 0;
+ clip->above = 0;
+
+ /* Now clip the rectangle to lie within the viewport */
+ if (my_rec.origin.x + (int32_t)my_rec.width > (int32_t)my_view->width)
+ {
+ clip->right = my_rec.width - (my_view->width - my_rec.origin.x);
+ my_rec.width = my_view->width - my_rec.origin.x;
+ }
+ if (my_rec.origin.y + (int32_t)my_rec.height > (int32_t)my_view->height)
+ {
+ clip->above = my_rec.height - (my_view->height - my_rec.origin.y);
+ my_rec.height = my_view->height - my_rec.origin.y;
+ }
+ if (my_rec.origin.x < 0)
+ {
+ clip->left = -my_rec.origin.x;
+ my_rec.width += my_rec.origin.x;
+ my_rec.origin.x = 0;
+ }
+ if (my_rec.origin.y < 0)
+ {
+ clip->below = -my_rec.origin.y;
+ my_rec.height += my_rec.origin.y;
+ my_rec.origin.y = 0;
+ }
+
+ /* Exit here if we've clipped the rectangle away to nothing */
+ if (!my_rec.width || !my_rec.height)
+ return false;
+
+ /* Create the clipped area structure */
+ pix_off = my_rec.origin.x + (my_rec.origin.y * my_view->width);
+ area->view.width = my_rec.width;
+ area->view.height = my_rec.height;
+ area->view.bpp = my_view->bpp;
+ area->view.base = my_view->base + (BYTES_PER_16BPP * pix_off);
+ area->base8 = my_view->base + (BYTES_PER_16BPP * my_view->width * my_view->height) + pix_off;
+ area->stride = my_view->width;
+
+ return true;
+}
+
+
+static vstat_t check_overlaps(const dlo_device_t * const dev, const dlo_view_t * const src_view, const dlo_view_t * const dest_view)
+{
+ const dlo_view_t * const src = src_view ? src_view : &(dev->mode.view);
+ const dlo_view_t * const dest = dest_view ? dest_view : &(dev->mode.view);
+ dlo_ptr_t src_end;
+ dlo_ptr_t dest_end;
+
+ /* If no display mode is set up, we should stop here to avoid null dereferences */
+ if (!src || !dest)
+ return vstat_bad_view;
+
+ /* If base addresses are the same, the other attributes must also be the same */
+ if (src->base == dest->base)
+ {
+ return (src->width == dest->width &&
+ src->height == dest->height &&
+ src->bpp == dest->bpp) ? vstat_good_overlap : vstat_bad_overlap;
+ }
+
+ /* Ensure we're happy with the source bits per pixel */
+ if (src->bpp != 16 && src->bpp != 24)
+ return vstat_bad_view;
+
+ /* Ensure we're happy with the destination bits per pixel */
+ if (dest->bpp != 16 && dest->bpp != 24)
+ return vstat_bad_view;
+
+ /* Compute the end addresses of both views */
+ src_end = src->base + (BYTES_PER_16BPP * src->width * src->height);
+ dest_end = dest->base + (BYTES_PER_16BPP * dest->width * dest->height);
+ if (src->bpp == 24)
+ src_end += BYTES_PER_8BPP * src->width * src->height;
+ if (dest->bpp == 24)
+ dest_end += BYTES_PER_8BPP * dest->width * dest->height;
+
+ /* Any overlap in address range means we have a problem */
+ return (dest_end <= src->base || dest->base >= src_end) ? vstat_good_view : vstat_bad_overlap;
+}
+
+
+/* End of file -------------------------------------------------------------------------*/
diff --git a/test/Makefile.am b/test/Makefile.am
new file mode 100644
index 0000000..97b919a
--- /dev/null
+++ b/test/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = test1 \ No newline at end of file
diff --git a/test/test1/Makefile.am b/test/test1/Makefile.am
new file mode 100644
index 0000000..f963eff
--- /dev/null
+++ b/test/test1/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = src \ No newline at end of file
diff --git a/test/test1/images/test08.bmp b/test/test1/images/test08.bmp
new file mode 100644
index 0000000..36ac1eb
--- /dev/null
+++ b/test/test1/images/test08.bmp
Binary files differ
diff --git a/test/test1/images/test16.bmp b/test/test1/images/test16.bmp
new file mode 100644
index 0000000..3b5f15d
--- /dev/null
+++ b/test/test1/images/test16.bmp
Binary files differ
diff --git a/test/test1/images/test24.bmp b/test/test1/images/test24.bmp
new file mode 100644
index 0000000..6599069
--- /dev/null
+++ b/test/test1/images/test24.bmp
Binary files differ
diff --git a/test/test1/images/test32.bmp b/test/test1/images/test32.bmp
new file mode 100644
index 0000000..f70a93d
--- /dev/null
+++ b/test/test1/images/test32.bmp
Binary files differ
diff --git a/test/test1/src/Makefile.am b/test/test1/src/Makefile.am
new file mode 100644
index 0000000..cb2d0f2
--- /dev/null
+++ b/test/test1/src/Makefile.am
@@ -0,0 +1,2 @@
+bin_PROGRAMS = test1
+test1_SOURCES = test1.c \ No newline at end of file
diff --git a/test/test1/src/test1.c b/test/test1/src/test1.c
new file mode 100644
index 0000000..9c1b2ea
--- /dev/null
+++ b/test/test1/src/test1.c
@@ -0,0 +1,937 @@
+/** @file test1.c
+ *
+ * @brief This file demonstrates basic graphics primitive features of libdlo.
+ *
+ * DisplayLink Open Source Software (libdlo)
+ * Copyright (C) 2009, DisplayLink
+ * www.displaylink.com
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library General Public License as published by the Free
+ * Software Foundation; LGPL version 2, dated June 1991.
+ *
+ * This library 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 Library General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include "sys/time.h"
+#include "libdlo.h"
+#include "dlo_defs.h"
+
+
+/** Default horizontal resolution we will use for tests (pixels).
+ */
+#define SCREEN_X (1280)
+
+/** Default vertical resolution we will use for tests (pixels).
+ */
+#define SCREEN_Y (1024)
+
+/** Default screen refresh rate we will use for tests (Hz).
+ */
+#define SCREEN_RATE (0)
+
+/** Default screen colour depth we will use for tests (bits per pixel).
+ */
+#define SCREEN_BPP (24)
+
+/** Number of random dots to plot.
+ */
+#define NUM_DOTS (299)
+
+/** Number of random rectangles to plot.
+ */
+#define NUM_RECTS (99)
+
+/** Number of steps (gradient) in colour blended rectangles.
+ */
+#define NUM_GRAD (99)
+
+/** Division factor for scale of central rectangle.
+ */
+#define MID_REC_DIV (5)
+
+/** Windows BMP magic ID bytes.
+ */
+#define BMP_MAGIC (0x4D42)
+
+/** Given a bits per pixel value, return the bytes per pixel.
+ */
+#define BYTES_PER_PIXEL(bpp) (unsigned int)(((bpp) + 7) / 8)
+
+/** Horizontal subdivision of the screen for overlapping rectangle copy tests.
+ */
+#define ZONE_X (SCREEN_X / 3)
+
+/** Vertical subdivision of the screen for overlapping rectangle copy tests.
+ */
+#define ZONE_Y (SCREEN_Y / 3)
+
+/** Horizontal size of the rectangle to copy in the overlapping rectangle copy tests.
+ */
+#define COPY_X (ZONE_X / 2)
+
+/** Vertical size of the rectangle to copy in the overlapping rectangle copy tests.
+ */
+#define COPY_Y (ZONE_Y / 2)
+
+/** Size of a component of a rectangle copy offset (horizontal or vertical).
+ */
+#define STEP (80)
+
+
+/** Array of offsets for overlapping rectangle copy test.
+ */
+const dlo_dot_t overlap[9] =
+{
+ { -STEP, -STEP },
+ { 0, -STEP },
+ { STEP, -STEP },
+ { -STEP, 0 },
+ { 0, 0 },
+ { STEP, 0 },
+ { -STEP, STEP },
+ { 0, STEP },
+ { STEP, STEP }
+};
+
+
+/** The main header block from a Windows BMP file.
+ */
+typedef struct __packed bmp_header_s
+{
+ uint16_t magic; /**< Magic ID bytes for Windows BMP format. */
+ uint32_t file_sz; /**< Total bitmap file size (bytes). */
+ uint16_t reserved1; /**< Unused. */
+ uint16_t reserved2; /**< Unused. */
+ uint32_t pix_offset; /**< Offset from start of file to start of pixel data (bytes). */
+} bmp_header_t; /**< A struct @a bmp_header_s. */
+
+
+/** The DIB header block from a Windows BMP file.
+ */
+typedef struct __packed dib_header_s
+{
+ uint32_t dib_hdr_sz; /**< Size of the DIB header block (bytes). */
+ uint32_t width; /**< Width of the bitmap (pixels). */
+ uint32_t height; /**< Height of the bitmap (pixels). */
+ uint16_t col_planes; /**< Number of colour planes. */
+ uint16_t bpp; /**< Bits per pixel. */
+ uint32_t compression; /**< Compression, pixel format. */
+ uint32_t raw_size; /**< Size of the raw pixel data. */
+ uint32_t x_pix_meter; /**< Horizontal resolution (pixels per meter). */
+ uint32_t y_pix_meter; /**< Vertical resolution (pixels per meter). */
+ uint32_t pal_entries; /**< Number of palette entries. */
+ uint32_t imp_cols; /**< Important colours (ignored). */
+} dib_header_t; /**< A struct @a dib_header_s. */
+
+
+/** A Windows BMP file.
+ */
+typedef struct __packed bmp_s
+{
+ bmp_header_t hdr; /**< Windows BMP header block. */
+ dib_header_t dib; /**< DIB header block. */
+ uint8_t data[]; /**< Pixel data. */
+} bmp_t; /**< A struct @a bmp_s. */
+
+
+/** Report an error and exit.
+ *
+ * @param str Pointer to the error message string.
+ */
+static void my_error(const char * const str)
+{
+ printf("test: ERROR: %s\n", str);
+ exit(1);
+}
+
+
+/** Return the microsecond time, as an unsigned 64 bit integer.
+ *
+ * @return Number of microseconds since the start of the Epoch.
+ */
+static uint64_t now(void)
+{
+ static struct timeval unix_time = { 0 };
+ static struct timeval *unix_time_ptr = &unix_time;
+
+ gettimeofday(unix_time_ptr, NULL);
+ return ((uint64_t)unix_time.tv_sec * 1000000ll) + (uint64_t)unix_time.tv_usec;
+}
+
+
+/** Pause execution for the specified number of centiseconds.
+ *
+ * @param from Time to start the pause interval.
+ * @param millisec Number of milliseconds to pause for.
+ */
+static void wait_ms(const uint64_t from, const uint64_t millisec)
+{
+ uint64_t to = from + (millisec * 1000);
+
+ while (to > now()) ;
+}
+
+
+/** Plot a rectangular outline in the specified colour.
+ *
+ * @param uid Unique ID of the device.
+ * @param view Viewport for plot destination.
+ * @param rec Rectangle co-ordinates within the viewport.
+ * @param col Colour of rectangle.
+ *
+ * @return Return code, zero for no error.
+ */
+static dlo_retcode_t box(const dlo_dev_t uid, const dlo_view_t * const view, const dlo_rect_t * const rec, const dlo_col32_t col)
+{
+ dlo_rect_t line;
+
+ line.origin.x = rec->origin.x;
+ line.origin.y = rec->origin.y;
+ line.width = rec->width;
+ line.height = 1;
+ ERR(dlo_fill_rect(uid, view, &line, col));
+
+ line.width = 1;
+ line.height = rec->height;
+ ERR(dlo_fill_rect(uid, view, &line, col));
+
+ line.origin.y += line.height - 1;
+ line.width = rec->width;
+ line.height = 1;
+ ERR(dlo_fill_rect(uid, view, &line, col));
+
+ line.origin.x += line.width;
+ line.origin.y = rec->origin.y;
+ line.width = 1;
+ line.height = rec->height;
+ ERR(dlo_fill_rect(uid, view, &line, col));
+
+ return dlo_ok;
+}
+
+
+/** Test the basic graphics primitives (filled rectangle and rectangle copy).
+ *
+ * @param uid Unique ID of the device.
+ *
+ * @return Return code, zero for no error.
+ */
+static dlo_retcode_t basic_grfx_test(const dlo_dev_t uid)
+{
+ dlo_mode_t mode;
+ dlo_mode_t *mode_info;
+ dlo_devinfo_t *dev_info;
+ dlo_view_t *view;
+ dlo_rect_t rec;
+ dlo_dot_t dot;
+ uint32_t i;
+ uint64_t start;
+
+ /* Read some information on the device */
+ dev_info = dlo_device_info(uid);
+ NERR(dev_info);
+ printf("test: device info: uid &%X\n", (int)dev_info->uid);
+ printf("test: device info: serial '%s'\n", dev_info->serial);
+ printf("test: device info: type &%X\n", (uint32_t)dev_info->type);
+
+ /* Read current mode information (if we're already in the display's native mode) */
+ mode_info = dlo_get_mode(uid);
+ NERR(mode_info);
+ printf("test: native mode info...\n");
+ printf(" %ux%u @ %u Hz %u bpp base &%X\n", mode_info->view.width, mode_info->view.height, mode_info->refresh, mode_info->view.bpp, (int)mode_info->view.base);
+
+ /* Select a fairly standard mode */
+ printf("test: set_mode...\n");
+ mode.view.width = SCREEN_X;
+ mode.view.height = SCREEN_Y;
+ mode.view.bpp = SCREEN_BPP;
+ mode.view.base = 0;
+ mode.refresh = SCREEN_RATE;
+ ERR(dlo_set_mode(uid, &mode));
+
+ /* Read current mode information */
+ mode_info = dlo_get_mode(uid);
+ NERR(mode_info);
+ printf("test: mode info...\n");
+ printf(" %ux%u @ %u Hz %u bpp base &%X\n", mode_info->view.width, mode_info->view.height, mode_info->refresh, mode_info->view.bpp, (int)mode_info->view.base);
+ view = &(mode_info->view);
+
+ /* Clear screen */
+ printf("test: cls...");
+ start = now();
+ ERR(dlo_fill_rect(uid, NULL, NULL, DLO_RGB(0, 0, 0)));
+ printf(" took %u ms\n", (uint32_t)(now() - start) / 1000);
+
+ /* Plot some random white dots */
+ printf("test: random white dots...");
+ start = now();
+ rec.width = 1;
+ rec.height = 1;
+ for (i = 0; i < NUM_DOTS; i++)
+ {
+ rec.origin.x = rand() % view->width;
+ rec.origin.y = rand() % view->height;
+ ERR(dlo_fill_rect(uid, view, &rec, DLO_RGB(0xFF, 0xFF, 0xFF)));
+ }
+ printf(" took %u ms\n", (uint32_t)(now() - start) / 1000);
+
+ /* Plot random filled rectangles */
+ printf("test: random rectangles...");
+ start = now();
+ for (i = 0; i < NUM_RECTS; i++)
+ {
+ rec.width = rand() % (view->width / 4);
+ rec.height = rand() % (view->height / 4);
+ rec.origin.x = (rand() % (uint32_t)(1.25 * view->width)) - (view->width / 8);
+ rec.origin.y = (rand() % (uint32_t)(1.25 * view->height)) - (view->height / 8);
+ ERR(dlo_fill_rect(uid, view, &rec, DLO_RGB(rand() % 0xFF, rand() % 0xFF, rand() % 0xFF)));
+ }
+ printf(" took %u ms\n", (uint32_t)(now() - start) / 1000);
+
+ /* Plot a set of rectangles, one over the other (colour gradient) */
+ printf("test: central rectangles...");
+ start = now();
+ for (i = 0; i < NUM_GRAD; i++)
+ {
+ dlo_col32_t col = DLO_RGB((i*3) % 256, (i*5) % 256, 255 - ((i*7) % 256));
+
+ rec.width = (view->width / MID_REC_DIV) - 2*i;
+ rec.height = (view->height / MID_REC_DIV) - 2*i;
+ rec.origin.x = i + (view->width / 2) - (view->width / MID_REC_DIV / 2);
+ rec.origin.y = i + (view->height / 2) - (view->height/ MID_REC_DIV / 2);
+ ERR(dlo_fill_rect(uid, view, &rec, col));
+ }
+ printf(" took %u ms\n", (uint32_t)(now() - start) / 1000);
+
+ /* Plot the outline of the box we're going to copy */
+ printf("test: white box outline...");
+ start = now();
+ rec.width = view->width / MID_REC_DIV;
+ rec.height = view->height / MID_REC_DIV;
+ rec.origin.x = (view->width / 2) - (rec.width / 2);
+ rec.origin.y = (view->height / 2) - (rec.height / 2);
+ ERR(box(uid, view, &rec, DLO_RGB(0xFF, 0xFF, 0xFF)));
+ printf(" took %u ms\n", (uint32_t)(now() - start) / 1000);
+
+ /* Copy a rectangle from the centre of the screen to other locations */
+ printf("test: copy central box...");
+ start = now();
+ rec.origin.x++;
+ rec.origin.y++;
+ rec.width -= 2;
+ rec.height -= 2;
+ dot.x = 8;
+ dot.y = 8;
+ ERR(dlo_copy_rect(uid, view, &rec, view, &dot));
+ dot.x = view->width - 8 - rec.width;
+ ERR(dlo_copy_rect(uid, view, &rec, view, &dot));
+ dot.y = view->height - 8 - rec.height;
+ ERR(dlo_copy_rect(uid, view, &rec, view, &dot));
+ dot.x = 8;
+ ERR(dlo_copy_rect(uid, view, &rec, view, &dot));
+ printf(" took %u ms\n", (uint32_t)(now() - start) / 1000);
+
+ /* Check that basic clipping works */
+ printf("test: copy central box (off edges of viewport)...");
+ start = now();
+ dot.x = -(rec.width / 2);
+ dot.y = (view->height / 2) - (rec.height / 2) - 32;
+ ERR(dlo_copy_rect(uid, view, &rec, view, &dot));
+ dot.x += view->width;
+ dot.y += 64;
+ ERR(dlo_copy_rect(uid, view, &rec, view, &dot));
+ dot.x = (view->width / 2) - (rec.width / 2) - 128;
+ dot.y = -(rec.height / 2);
+ ERR(dlo_copy_rect(uid, view, &rec, view, &dot));
+ dot.x += 256;
+ dot.y += view->height;
+ ERR(dlo_copy_rect(uid, view, &rec, view, &dot));
+ printf(" took %u ms\n", (uint32_t)(now() - start) / 1000);
+
+ return dlo_ok;
+}
+
+
+/** Plot a few coloured rectangles one above another.
+ *
+ * @param uid Unique ID of the device.
+ * @param inrec Input rectangle (the outer bounding box of the design).
+ *
+ * @return Return code, zero for no error.
+ */
+static dlo_retcode_t squares(const dlo_dev_t uid, const dlo_rect_t * const inrec)
+{
+ dlo_rect_t rec = *inrec;
+
+ /* Plot the outer (red) rectangle */
+ ERR(dlo_fill_rect(uid, NULL, &rec, DLO_RGB(0xCC, 0, 0)));
+
+ /* Plot the middle (white) rectangle */
+ rec.origin.x += 20;
+ rec.origin.y += 20;
+ rec.width -= 40;
+ rec.height -= 40;
+ ERR(dlo_fill_rect(uid, NULL, &rec, DLO_RGB(0xCC, 0xCC, 0xCC)));
+
+ /* Plot the inner (blue) rectangle */
+ rec.origin.x += 20;
+ rec.origin.y += 20;
+ rec.width -= 40;
+ rec.height -= 40;
+
+ return dlo_fill_rect(uid, NULL, &rec, DLO_RGB(0, 0, 0xCC));
+}
+
+
+/** Test copying rectangles to and from overlapping regions (in various directions).
+ *
+ * @param uid Unique ID of the device.
+ *
+ * @return Return code, zero for no error.
+ */
+static dlo_retcode_t overlap_test(const dlo_dev_t uid)
+{
+ dlo_rect_t rec;
+ dlo_dot_t mid, dot;
+ uint32_t idx = 0;
+
+ /* Clear screen to black */
+ ERR(dlo_fill_rect(uid, NULL, NULL, DLO_RGB(0, 0, 0)));
+
+ rec.width = COPY_X;
+ rec.height = COPY_Y;
+ for (mid.y = ZONE_Y / 2; mid.y < SCREEN_Y; mid.y += ZONE_Y)
+ {
+ for (mid.x = ZONE_X / 2; mid.x < SCREEN_X; mid.x += ZONE_X)
+ {
+ rec.origin.x = mid.x - (COPY_X / 2);
+ rec.origin.y = mid.y - (COPY_Y / 2);
+ dot.x = rec.origin.x + overlap[idx].x;
+ dot.y = rec.origin.y + overlap[idx].y;
+ idx++;
+ ERR(squares(uid, &rec));
+ ERR(dlo_copy_rect(uid, NULL, &rec, NULL, &dot));
+ }
+ }
+ return dlo_ok;
+}
+
+
+/** Convert a bits per pixel value into a bytes per pixel value.
+ *
+ * @param bpp Bits per pixel.
+ *
+ * @return Bytes per pixel.
+ */
+static uint8_t bpp_to_bytes(const uint32_t bpp)
+{
+ return (uint8_t)((bpp + 7) / 8);
+}
+
+
+/** Test the use of viewports as screen banks (ensure clipping is working).
+ *
+ * @param uid Unique ID of the device.
+ *
+ * @return Return code, zero for no error.
+ *
+ * Create three viewports (screen banks) and switch the display between them.
+ * While we're at it, test the filled rectangle plotting clips correctly and
+ * doesn't overflow into surrounding screen banks or off the edges of the
+ * screen.
+ */
+static dlo_retcode_t viewport_test(const dlo_dev_t uid)
+{
+ dlo_mode_t mode;
+ dlo_mode_t *desc;
+ dlo_view_t view[3];
+ dlo_rect_t rec;
+ uint32_t i;
+ uint64_t start;
+
+ /* Read current mode information */
+ desc = dlo_get_mode(uid);
+ NERR(desc);
+
+ /* Create three viewports - each representing a screen bank */
+ view[0] = desc->view;
+ view[1] = view[0];
+ view[1].base = view[0].base + (view[1].width * view[1].height * bpp_to_bytes(view[1].bpp));
+ view[2] = view[1];
+ view[2].base = view[1].base + (view[2].width * view[2].height * bpp_to_bytes(view[2].bpp));
+
+ /* Clear screens to different colours */
+ printf("test: cls (three banks)...");
+ start = now();
+ ERR(dlo_fill_rect(uid, NULL, NULL, DLO_RGB(0, 0, 0xFF)));
+ ERR(dlo_fill_rect(uid, &view[1], NULL, DLO_RGB(0, 0xFF, 0)));
+ ERR(dlo_fill_rect(uid, &view[2], NULL, DLO_RGB(0xFF, 0, 0)));
+ printf(" took %u ms\n", (uint32_t)(now() - start) / 1000);
+
+ /* Plot a couple of rectangles in each bank to test the clipping */
+ printf("test: plot crosses (three banks)...");
+ start = now();
+ rec.width = view[0].width / 8;
+ rec.height = view[0].height * 1.5;
+ rec.origin.x = (view[0].width / 2) - (rec.width / 2);
+ rec.origin.y = -(view[0].height / 4);
+ ERR(dlo_fill_rect(uid, NULL, &rec, DLO_RGB(0, 0xFF, 0xFF)));
+ ERR(dlo_fill_rect(uid, &view[1], &rec, DLO_RGB(0xFF, 0xFF, 0)));
+ ERR(dlo_fill_rect(uid, &view[2], &rec, DLO_RGB(0xFF, 0, 0xFF)));
+ rec.width = view[0].width * 1.5;
+ rec.height = view[0].height / 8;
+ rec.origin.x = -(view[0].width / 4);
+ rec.origin.y = (view[0].height / 2) - (rec.height / 2);
+ ERR(dlo_fill_rect(uid, NULL, &rec, DLO_RGB(0, 0xFF, 0xFF)));
+ ERR(dlo_fill_rect(uid, &view[1], &rec, DLO_RGB(0xFF, 0xFF, 0)));
+ ERR(dlo_fill_rect(uid, &view[2], &rec, DLO_RGB(0xFF, 0, 0xFF)));
+ printf(" took %u ms\n", (uint32_t)(now() - start) / 1000);
+
+ /* Switch through the screen banks */
+ for (i = 1; i < 4; i++)
+ {
+ wait_ms(now(), 1000);
+
+ printf("test: switching to screen bank %u...\n", i % 3);
+ mode.view.width = view[i % 3].width;
+ mode.view.height = view[i % 3].height;
+ mode.view.bpp = view[i % 3].bpp;
+ mode.view.base = view[i % 3].base;
+ mode.refresh = 0;
+ ERR(dlo_set_mode(uid, &mode));
+ }
+
+ return dlo_ok;
+}
+
+
+/** Load a Windows BMP file into memory.
+ *
+ * @param bmpfile Pointer to the filename.
+ *
+ * @return Pointer to the loaded bitmap's structure (or NULL if failed).
+ *
+ * Load a bitmap from a file and create a @a dlo_fbuf_t structure to suit.
+ * If the bitmap has a palette, we need to swap the red/blue order of the
+ * colour components in order to convert the palette entries into
+ * @a dlo_col32_t values.
+ */
+static bmp_t *load_bmp(const char * const bmpfile)
+{
+ long int size;
+ bmp_t *bmp;
+ FILE *fp;
+
+ fp = fopen(bmpfile, "rb");
+ if (!fp)
+ return NULL;
+
+ if (fseek(fp, 0, SEEK_END))
+ return NULL;
+
+ size = ftell(fp);
+ if (size == -1L)
+ return NULL;
+
+ if (fseek(fp, 0, SEEK_SET))
+ return NULL;
+
+ bmp = malloc(size);
+ if (!bmp)
+ return NULL;
+
+ if (1 != fread(bmp, size, 1, fp))
+ goto error;
+
+ if (bmp->hdr.magic != BMP_MAGIC)
+ goto error;
+
+ /* If there is a palette, we need to reverse the RGB component order */
+ if (bmp->dib.pal_entries)
+ {
+ dlo_col32_t *palette;
+ uint32_t i;
+
+ palette = (dlo_col32_t *)((unsigned long)bmp + sizeof(bmp_header_t) + sizeof(dib_header_t));
+
+ for (i = 0; i < bmp->dib.pal_entries; i++)
+ {
+ dlo_col32_t col = palette[i];
+
+ palette[i] = DLO_RGB(DLO_RGB_GETBLU(col), DLO_RGB_GETGRN(col), DLO_RGB_GETRED(col));
+ }
+ }
+ return bmp;
+
+error:
+ free(bmp);
+
+ return NULL;
+}
+
+
+/** Given a bitmap pointer, check various aspects of it and return a framebuffer structure pointer.
+ *
+ * @param bmp Pointer to a loaded bitmap structure.
+ *
+ * @return Pointer to a framebuffer structure associated with the bitmap.
+ *
+ * NOTE: the bitmap plotting code requires some special-case Windows BMP format
+ * bitmaps as input; they must include a DIB header (very common) and their width
+ * must be such that they don't require any padding bytes at the end of each pixel
+ * row.
+ *
+ * The padding issue could be fixed very simply by calling the dlo_copy_host_bmp()
+ * for each pixel row individually but for the sake of a simple demo, we impose
+ * the constraint and make only one call to dlo_copy_host_bmp() here.
+ */
+static dlo_fbuf_t *bmp_to_fbuf(const bmp_t * const bmp)
+{
+ static dlo_fbuf_t fbuf;
+
+ printf("bmp->hdr.magic %04X\n"
+ "bmp->hdr.file_sz %08X (%u)\n"
+ "bmp->hdr.reserved1 %04X\n"
+ "bmp->hdr.reserved2 %04X\n"
+ "bmp->hdr.pix_offset %08X\n"
+ "bmp->dib.dib_hdr_sz %08X\n"
+ "bmp->dib.width %08X (%u)\n"
+ "bmp->dib.height %08X (%u)\n"
+ "bmp->dib.col_planes %04X\n"
+ "bmp->dib.bpp %04X (%u)\n"
+ "bmp->dib.compression %08X\n"
+ "bmp->dib.raw_size %08X (%u)\n"
+ "bmp->dib.x_pix_meter %08X\n"
+ "bmp->dib.y_pix_meter %08X\n"
+ "bmp->dib.pal_entries %08X (%u)\n"
+ "bmp->dib.imp_cols %08X\n",
+ bmp->hdr.magic,
+ bmp->hdr.file_sz, bmp->hdr.file_sz,
+ bmp->hdr.reserved1,
+ bmp->hdr.reserved2,
+ bmp->hdr.pix_offset,
+ bmp->dib.dib_hdr_sz,
+ bmp->dib.width, bmp->dib.width,
+ bmp->dib.height, bmp->dib.height,
+ bmp->dib.col_planes,
+ bmp->dib.bpp, bmp->dib.bpp,
+ bmp->dib.compression,
+ bmp->dib.raw_size, bmp->dib.raw_size,
+ bmp->dib.x_pix_meter,
+ bmp->dib.y_pix_meter,
+ bmp->dib.pal_entries, bmp->dib.pal_entries,
+ bmp->dib.imp_cols);
+
+ if (bmp->dib.compression)
+ my_error("Unsupported bitmap compression mode");
+ if (bmp->dib.col_planes != 1)
+ my_error("Unsupported bitmap colour plane specification");
+ if ((bmp->dib.width * BYTES_PER_PIXEL(bmp->dib.bpp)) & 3)
+ my_error("Bitmap width must be whole multiple of four bytes (no padding)");
+
+ fbuf.width = bmp->dib.width;
+ fbuf.height = bmp->dib.height;
+ fbuf.base = bmp->hdr.pix_offset + (uint8_t *)bmp;
+ fbuf.stride = fbuf.width;
+ switch (bmp->dib.bpp)
+ {
+ case 8:
+ {
+ fbuf.fmt = (dlo_pixfmt_t)(sizeof(bmp_header_t) + sizeof(dib_header_t) + (uint8_t *)bmp);
+ if (bmp->dib.pal_entries != 256)
+ my_error("Unsupported bitmap palette size");
+ break;
+ }
+ case 16:
+ {
+ fbuf.fmt = dlo_pixfmt_srgb1555;
+ break;
+ }
+ case 24:
+ {
+ fbuf.fmt = dlo_pixfmt_rgb888;
+ break;
+ }
+ case 32:
+ {
+ fbuf.fmt = dlo_pixfmt_argb8888;
+ break;
+ }
+ default:
+ my_error("Unsupported bitmap colour depth");
+ }
+ return &fbuf;
+}
+
+
+/** Run some tests involving the loading, scraping and plotting of a bitmap.
+ *
+ * @param uid Unique ID of the device.
+ * @param bmpfile Pointer to a Windows BMP filename.
+ *
+ * @return Return code, zero for no error.
+ *
+ * Load a bitmap, clear the screen and plot the bitmap at the centre of the
+ * screen as well as off each edge of the screen.
+ */
+static dlo_retcode_t bitmap_test(const dlo_dev_t uid, const bool cross, const char * const bmpfile)
+{
+ dlo_bmpflags_t flags = { 0 };
+ dlo_retcode_t err;
+ dlo_mode_t *desc;
+ dlo_fbuf_t *fbuf;
+ dlo_view_t view;
+ dlo_dot_t dot;
+ bmp_t *bmp;
+
+ printf("\ntest: bitmap file '%s'\n", bmpfile);
+
+ /* Read current mode information */
+ desc = dlo_get_mode(uid);
+ NERR(desc);
+ view = desc->view;
+
+ /* Clear screen to black */
+ ERR(dlo_fill_rect(uid, NULL, NULL, DLO_RGB(0, 0, 0)));
+
+ /* Load the Windows BMP bitmap file into memory */
+ bmp = load_bmp(bmpfile);
+ NERR(bmp);
+
+ /* Initialise a dlo_fbuf structure from our loaded bitmap file */
+ fbuf = bmp_to_fbuf(bmp);
+ NERR_GOTO(fbuf);
+
+ /* Test plotting of bitmap in centre of screen */
+ dot.x = (view.width / 2) - (fbuf->width / 2);
+ dot.y = (view.height / 2) - (fbuf->height / 2);
+ flags.v_flip = 1;
+ ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, NULL, &dot));
+
+ /* Now a few plots that lie a little off the edges of the screen */
+ flags.v_flip = 0;
+ if (cross)
+ {
+ dot.y = -fbuf->height / 2;
+ ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, NULL, &dot));
+ dot.y += view.height;
+ ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, NULL, &dot));
+ dot.x = -fbuf->width / 2;
+ dot.y = (view.height / 2) - (fbuf->height / 2);
+ ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, NULL, &dot));
+ dot.x += view.width;
+ ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, NULL, &dot));
+ }
+ else
+ {
+ dot.x = -fbuf->width / 2;
+ dot.y = -fbuf->height / 2;
+ ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, NULL, &dot));
+ dot.y += view.height;
+ ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, NULL, &dot));
+ dot.x += view.width;
+ ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, NULL, &dot));
+ dot.y -= view.height;
+ ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, NULL, &dot));
+ }
+
+ /* Discard the bitmap */
+ free(bmp);
+
+ return dlo_ok;
+
+error:
+ free(bmp);
+ return err;
+}
+
+
+/** Run some screen scraping tests with a set of input bitmaps.
+ *
+ * @param uid Unique ID of the device.
+ *
+ * @return Return code, zero for no error.
+ *
+ * This test sequence checks that the @c dlo_copy_host_bmp() call works correctly for
+ * a number of source pixel formats by loading some different bitmaps and scraping
+ * directly from them (using their palette where required).
+ */
+static dlo_retcode_t scrape_tests(const dlo_dev_t uid)
+{
+ ERR(bitmap_test(uid, false, "images/test08.bmp"));
+
+ wait_ms(now(), 1000);
+ ERR(bitmap_test(uid, true, "images/test16.bmp"));
+
+ wait_ms(now(), 1000);
+ ERR(bitmap_test(uid, false, "images/test24.bmp"));
+
+ wait_ms(now(), 1000);
+ return bitmap_test(uid, true, "images/test32.bmp");
+}
+
+
+/** Test the clipping of bitmaps relative to other screen banks.
+ *
+ * @param uid Unique ID of the device.
+ *
+ * @return Return code, zero for no error.
+ *
+ * The point of this test is to plot lots of bitmaps in random positions (some
+ * completely off-screen) into the middle of three screen banks. We switch between
+ * each bank to check that the bitmaps only appear on the middle one and haven't
+ * spilled over into the surrounding memory.
+ */
+static dlo_retcode_t bmp_clip_test(const dlo_dev_t uid)
+{
+ dlo_bmpflags_t flags = { 0 };
+ dlo_retcode_t err;
+ dlo_mode_t mode;
+ dlo_mode_t *desc;
+ dlo_fbuf_t *fbuf;
+ dlo_view_t view[3];
+ dlo_dot_t dot;
+ bmp_t *bmp;
+ uint32_t i;
+
+ /* Read current mode information */
+ desc = dlo_get_mode(uid);
+ NERR(desc);
+
+ /* Create three viewports - each representing a screen bank */
+ view[0] = desc->view;
+ view[1] = view[0];
+ view[1].base = view[0].base + (view[1].width * view[1].height * bpp_to_bytes(view[1].bpp));
+ view[2] = view[1];
+ view[2].base = view[1].base + (view[2].width * view[2].height * bpp_to_bytes(view[2].bpp));
+
+ /* Clear screen banks */
+ wait_ms(now(), 2000);
+ ERR(dlo_fill_rect(uid, NULL, NULL, DLO_RGB(0, 0, 0x50)));
+ ERR(dlo_fill_rect(uid, &view[1], NULL, DLO_RGB(0, 0, 0)));
+ ERR(dlo_fill_rect(uid, &view[2], NULL, DLO_RGB(0, 0x50, 0)));
+
+ /* Load the Windows BMP bitmap file into memory */
+ bmp = load_bmp("images/test08.bmp");
+ NERR(bmp);
+
+ /* Initialise a dlo_fbuf structure from our loaded bitmap file */
+ fbuf = bmp_to_fbuf(bmp);
+ NERR_GOTO(fbuf);
+
+ /* Plot lots of bitmaps into the second screen bank */
+ for (i = 0; i < 399; i++)
+ {
+ flags.v_flip = rand() % 2;
+ dot.x = -fbuf->width + (rand() % (view[1].width + fbuf->width));
+ dot.y = -fbuf->height + (rand() % (view[1].height + fbuf->height));
+ ERR_GOTO(dlo_copy_host_bmp(uid, flags, fbuf, &view[1], &dot));
+ }
+
+ /* Switch to middle bank */
+ wait_ms(now(), 2000);
+ mode.view.width = view[1].width;
+ mode.view.height = view[1].height;
+ mode.view.bpp = view[1].bpp;
+ mode.view.base = view[1].base;
+ mode.refresh = 0;
+ ERR_GOTO(dlo_set_mode(uid, &mode));
+
+ /* Switch to third bank */
+ wait_ms(now(), 2000);
+ mode.view.width = view[2].width;
+ mode.view.height = view[2].height;
+ mode.view.bpp = view[2].bpp;
+ mode.view.base = view[2].base;
+ mode.refresh = 0;
+ ERR_GOTO(dlo_set_mode(uid, &mode));
+
+ /* Switch to middle bank */
+ wait_ms(now(), 2000);
+ mode.view.width = view[1].width;
+ mode.view.height = view[1].height;
+ mode.view.bpp = view[1].bpp;
+ mode.view.base = view[1].base;
+ mode.refresh = 0;
+ ERR_GOTO(dlo_set_mode(uid, &mode));
+
+ /* Discard the bitmap */
+ free(bmp);
+
+ return dlo_ok;
+
+error:
+ free(bmp);
+ return err;
+}
+
+
+/**********************************************************************/
+int main(int argc, char *argv[])
+{
+ dlo_init_t ini_flags = { 0 };
+ dlo_final_t fin_flags = { 0 };
+ dlo_claim_t cnf_flags = { 0 };
+ dlo_retcode_t err;
+ dlo_dev_t uid = 0;
+
+ IGNORE(argc);
+ IGNORE(argv);
+
+ /* Initialise the random number generator with the microsecond time as a seed */
+ srand((unsigned int)now());
+
+ /* Initialise libdlo */
+ printf("test: init...\n");
+ ERR_GOTO(dlo_init(ini_flags));
+
+ /* Look for a DisplayLink device to connect to */
+ uid = dlo_claim_first_device(cnf_flags, 0);
+
+ /* If we found one, perform some tests with it */
+ if (uid)
+ {
+ printf("\ntest: basic graphics tests...\n");
+ ERR_GOTO(basic_grfx_test(uid));
+ wait_ms(now(), 3000);
+
+ printf("\test: overlapping copy tests...\n");
+ ERR_GOTO(overlap_test(uid));
+
+ wait_ms(now(), 3000);
+
+ printf("\ntest: viewport tests...\n");
+ ERR_GOTO(viewport_test(uid));
+
+ printf("\ntest: screen scraping tests...\n");
+ ERR_GOTO(scrape_tests(uid));
+
+ printf("test: bitmap clipping test...\n");
+ ERR_GOTO(bmp_clip_test(uid));
+
+ printf("test: release &%X...\n", (uintptr_t)uid);
+ ERR_GOTO(dlo_release_device(uid));
+ }
+
+ /* Finalise libdlo, free up resources */
+ printf("test: final...\n");
+ ERR_GOTO(dlo_final(fin_flags));
+ printf("test: finished.\n");
+ return 0;
+
+error:
+ printf("test: error %u '%s'\n", (int)err, dlo_strerror(err));
+ return 0;
+}