[libsigrok] 01/12: Import Upstream version 0.3.0

Zoltan Gyarmati zgyarmati-guest at moszumanska.debian.org
Wed Mar 29 21:34:52 UTC 2017


This is an automated email from the git hooks/post-receive script.

zgyarmati-guest pushed a commit to branch master
in repository libsigrok.

commit f657e933daa017b7e028e105d38f299d2f0619f6
Author: Zoltan Gyarmati <Zoltan Gyarmati mr.zoltan.gyarmati at gmail.com>
Date:   Sun Feb 26 20:04:10 2017 +0100

    Import Upstream version 0.3.0
---
 AUTHORS                                     |     7 +
 COPYING                                     |   674 +
 ChangeLog                                   | 18209 ++++++++++++++++++++++++++
 Doxyfile                                    |  2320 ++++
 HACKING                                     |   188 +
 INSTALL                                     |   370 +
 Makefile.am                                 |   365 +
 Makefile.in                                 |  2711 ++++
 NEWS                                        |   497 +
 README                                      |   112 +
 README.devices                              |   364 +
 aclocal.m4                                  |  1587 +++
 autostuff/ar-lib                            |   270 +
 autostuff/compile                           |   347 +
 autostuff/config.guess                      |  1558 +++
 autostuff/config.sub                        |  1791 +++
 autostuff/depcomp                           |   791 ++
 autostuff/install-sh                        |   527 +
 autostuff/libtool.m4                        |  7997 +++++++++++
 autostuff/ltmain.sh                         |  9661 ++++++++++++++
 autostuff/ltoptions.m4                      |   384 +
 autostuff/ltsugar.m4                        |   123 +
 autostuff/ltversion.m4                      |    23 +
 autostuff/lt~obsolete.m4                    |    98 +
 autostuff/missing                           |   215 +
 autostuff/test-driver                       |   139 +
 backend.c                                   |   399 +
 config.h.in                                 |   196 +
 configure                                   | 17330 ++++++++++++++++++++++++
 configure.ac                                |   651 +
 contrib/gnuplot_chronovu_la8.gpi            |    47 +
 contrib/gnuplot_rigol_ds1xx2.gpi            |    37 +
 contrib/gnuplot_usbeedx16.gpi               |    62 +
 contrib/gnuplot_usbeedx8.gpi                |    47 +
 contrib/gnuplot_usbeesx.gpi                 |    47 +
 contrib/sigrok-logo-notext.png              |   Bin 0 -> 8637 bytes
 contrib/z60_libsigrok.rules                 |   188 +
 device.c                                    |   530 +
 error.c                                     |   137 +
 hardware/agilent-dmm/agilent-dmm.h          |    80 +
 hardware/agilent-dmm/api.c                  |   280 +
 hardware/agilent-dmm/sched.c                |   474 +
 hardware/appa-55ii/api.c                    |   290 +
 hardware/appa-55ii/protocol.c               |   320 +
 hardware/appa-55ii/protocol.h               |    62 +
 hardware/asix-sigma/asix-sigma.c            |  1540 +++
 hardware/asix-sigma/asix-sigma.h            |   211 +
 hardware/atten-pps3xxx/api.c                |   517 +
 hardware/atten-pps3xxx/protocol.c           |   165 +
 hardware/atten-pps3xxx/protocol.h           |   102 +
 hardware/brymen-bm86x/api.c                 |   312 +
 hardware/brymen-bm86x/protocol.c            |   343 +
 hardware/brymen-bm86x/protocol.h            |    48 +
 hardware/brymen-dmm/api.c                   |   262 +
 hardware/brymen-dmm/parser.c                |   288 +
 hardware/brymen-dmm/protocol.c              |   260 +
 hardware/brymen-dmm/protocol.h              |    88 +
 hardware/cem-dt-885x/api.c                  |   432 +
 hardware/cem-dt-885x/protocol.c             |   838 ++
 hardware/cem-dt-885x/protocol.h             |   143 +
 hardware/center-3xx/api.c                   |   289 +
 hardware/center-3xx/protocol.c              |   256 +
 hardware/center-3xx/protocol.h              |    84 +
 hardware/chronovu-la/api.c                  |   549 +
 hardware/chronovu-la/protocol.c             |   521 +
 hardware/chronovu-la/protocol.h             |   141 +
 hardware/colead-slm/api.c                   |   241 +
 hardware/colead-slm/protocol.c              |   233 +
 hardware/colead-slm/protocol.h              |    54 +
 hardware/common/dmm/es519xx.c               |   828 ++
 hardware/common/dmm/fs9721.c                |   445 +
 hardware/common/dmm/fs9922.c                |   384 +
 hardware/common/dmm/m2110.c                 |    70 +
 hardware/common/dmm/metex14.c               |   343 +
 hardware/common/dmm/rs9lcd.c                |   437 +
 hardware/common/ezusb.c                     |   136 +
 hardware/common/scpi.c                      |   750 ++
 hardware/common/scpi_serial.c               |   240 +
 hardware/common/scpi_tcp.c                  |   280 +
 hardware/common/scpi_usbtmc_libusb.c        |   583 +
 hardware/common/scpi_visa.c                 |   174 +
 hardware/common/scpi_vxi.c                  |   238 +
 hardware/common/serial.c                    |   885 ++
 hardware/common/usb.c                       |   269 +
 hardware/common/vxi.h                       |   342 +
 hardware/common/vxi_clnt.c                  |   265 +
 hardware/common/vxi_xdr.c                   |   428 +
 hardware/conrad-digi-35-cpu/api.c           |   229 +
 hardware/conrad-digi-35-cpu/protocol.c      |    63 +
 hardware/conrad-digi-35-cpu/protocol.h      |    40 +
 hardware/demo/demo.c                        |   780 ++
 hardware/fluke-dmm/api.c                    |   321 +
 hardware/fluke-dmm/fluke-dmm.h              |    69 +
 hardware/fluke-dmm/fluke.c                  |   536 +
 hardware/fx2lafw/api.c                      |   608 +
 hardware/fx2lafw/protocol.c                 |   617 +
 hardware/fx2lafw/protocol.h                 |   115 +
 hardware/gmc-mh-1x-2x/api.c                 |   618 +
 hardware/gmc-mh-1x-2x/protocol.c            |  1547 +++
 hardware/gmc-mh-1x-2x/protocol.h            |   135 +
 hardware/hameg-hmo/api.c                    |   805 ++
 hardware/hameg-hmo/protocol.c               |   741 ++
 hardware/hameg-hmo/protocol.h               |   115 +
 hardware/hantek-dso/api.c                   |   976 ++
 hardware/hantek-dso/dso.c                   |   787 ++
 hardware/hantek-dso/dso.h                   |   219 +
 hardware/ikalogic-scanalogic2/api.c         |   528 +
 hardware/ikalogic-scanalogic2/protocol.c    |   758 ++
 hardware/ikalogic-scanalogic2/protocol.h    |   239 +
 hardware/ikalogic-scanaplus/api.c           |   438 +
 hardware/ikalogic-scanaplus/protocol.c      |   370 +
 hardware/ikalogic-scanaplus/protocol.h      |    64 +
 hardware/kecheng-kc-330b/api.c              |   575 +
 hardware/kecheng-kc-330b/protocol.c         |   338 +
 hardware/kecheng-kc-330b/protocol.h         |   104 +
 hardware/lascar-el-usb/api.c                |   489 +
 hardware/lascar-el-usb/protocol.c           |   656 +
 hardware/lascar-el-usb/protocol.h           |    80 +
 hardware/mic-985xx/api.c                    |   291 +
 hardware/mic-985xx/protocol.c               |   234 +
 hardware/mic-985xx/protocol.h               |    87 +
 hardware/norma-dmm/api.c                    |   305 +
 hardware/norma-dmm/protocol.c               |   426 +
 hardware/norma-dmm/protocol.h               |    79 +
 hardware/openbench-logic-sniffer/api.c      |   599 +
 hardware/openbench-logic-sniffer/protocol.c |   507 +
 hardware/openbench-logic-sniffer/protocol.h |   120 +
 hardware/rigol-ds/api.c                     |  1039 ++
 hardware/rigol-ds/protocol.c                |   812 ++
 hardware/rigol-ds/protocol.h                |   155 +
 hardware/saleae-logic16/api.c               |   829 ++
 hardware/saleae-logic16/protocol.c          |   819 ++
 hardware/saleae-logic16/protocol.h          |    88 +
 hardware/serial-dmm/api.c                   |   632 +
 hardware/serial-dmm/protocol.c              |   195 +
 hardware/serial-dmm/protocol.h              |   146 +
 hardware/sysclk-lwla/api.c                  |   612 +
 hardware/sysclk-lwla/lwla.c                 |   237 +
 hardware/sysclk-lwla/lwla.h                 |   122 +
 hardware/sysclk-lwla/protocol.c             |   985 ++
 hardware/sysclk-lwla/protocol.h             |   263 +
 hardware/teleinfo/api.c                     |   288 +
 hardware/teleinfo/protocol.c                |   237 +
 hardware/teleinfo/protocol.h                |    61 +
 hardware/tondaj-sl-814/api.c                |   224 +
 hardware/tondaj-sl-814/protocol.c           |   208 +
 hardware/tondaj-sl-814/protocol.h           |    52 +
 hardware/uni-t-dmm/api.c                    |   425 +
 hardware/uni-t-dmm/protocol.c               |   315 +
 hardware/uni-t-dmm/protocol.h               |   102 +
 hardware/uni-t-ut32x/api.c                  |   384 +
 hardware/uni-t-ut32x/protocol.c             |   240 +
 hardware/uni-t-ut32x/protocol.h             |    71 +
 hardware/victor-dmm/api.c                   |   447 +
 hardware/victor-dmm/protocol.c              |   298 +
 hardware/victor-dmm/protocol.h              |    49 +
 hardware/zeroplus-logic-cube/analyzer.c     |   663 +
 hardware/zeroplus-logic-cube/analyzer.h     |   118 +
 hardware/zeroplus-logic-cube/api.c          |   835 ++
 hardware/zeroplus-logic-cube/gl_usb.c       |   152 +
 hardware/zeroplus-logic-cube/gl_usb.h       |    45 +
 hardware/zeroplus-logic-cube/protocol.c     |   139 +
 hardware/zeroplus-logic-cube/protocol.h     |    58 +
 hwdriver.c                                  |   796 ++
 input/binary.c                              |   151 +
 input/chronovu_la8.c                        |   206 +
 input/csv.c                                 |   868 ++
 input/input.c                               |    76 +
 input/vcd.c                                 |   546 +
 input/wav.c                                 |   204 +
 libsigrok-internal.h                        |   616 +
 libsigrok.h                                 |   975 ++
 libsigrok.pc.in                             |    15 +
 log.c                                       |   302 +
 output/analog.c                             |   268 +
 output/ascii.c                              |   261 +
 output/binary.c                             |    49 +
 output/bits.c                               |   245 +
 output/chronovu_la8.c                       |   190 +
 output/csv.c                                |   220 +
 output/gnuplot.c                            |   224 +
 output/hex.c                                |   260 +
 output/ols.c                                |   157 +
 output/output.c                             |   120 +
 output/vcd.c                                |   269 +
 proto.h                                     |   163 +
 session.c                                   |   835 ++
 session_driver.c                            |   337 +
 session_file.c                              |   504 +
 std.c                                       |   291 +
 strutil.c                                   |   644 +
 tests/check_core.c                          |   183 +
 tests/check_driver_all.c                    |    96 +
 tests/check_input_all.c                     |    48 +
 tests/check_input_binary.c                  |   335 +
 tests/check_main.c                          |    49 +
 tests/check_output_all.c                    |    48 +
 tests/check_strutil.c                       |   191 +
 tests/check_version.c                       |    93 +
 tests/lib.c                                 |   231 +
 tests/lib.h                                 |    52 +
 version.c                                   |   147 +
 version.h                                   |    69 +
 version.h.in                                |    69 +
 204 files changed, 127875 insertions(+)

diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..28c1b20
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,7 @@
+-------------------------------------------------------------------------------
+AUTHORS
+-------------------------------------------------------------------------------
+
+Please check the source code files and/or git history and/or ChangeLog for
+a list of all authors and contributors.
+
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, 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
+them 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 prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If 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 convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU 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
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "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 PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..a42baf6
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,18209 @@
+commit 8f54ac8be1768261e113cb15fcdf81013f712674
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue May 6 23:01:26 2014 +0200
+
+    Doxyfile/Doxyfile_internal: Bump version number to 0.3.0.
+
+commit 4133caab1d2467a582850a3713ee083827364c8b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue May 6 23:00:08 2014 +0200
+
+    configure.ac: Bump package version to 0.3.0.
+
+commit 85ca913cae0d9514949db8f638ecb4ef7bca706e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue May 6 22:59:00 2014 +0200
+
+    configure.ac: Bump libtool/library version from 1:2:0 to 2:0:0.
+    
+    The libtool current:revision:age numbers change from 1:2:0 to 2:0:0.
+    
+    Details:
+    http://www.gnu.org/software/libtool/manual/libtool.html#Updating-version-info
+    
+    This changes the library filename (e.g. on Linux) from libsigrok.so.1.0.2
+    to libsigrok.so.2.0.0, the SONAME (+symlink) becomes libsigrok.so.2.
+
+commit 8f8289dc1dc4532d33cda04141c8080f6dda00f5
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue May 6 09:00:00 2014 +0200
+
+    NEWS: Add list of user-visible changes so far.
+
+commit ace218f9223c39a3eb6738e36f4b89fae5142673
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue May 6 20:18:54 2014 +0200
+
+    Rename SR_T_CHAR to SR_T_STRING.
+    
+    This is more correct and less confusing.
+
+commit 05238d2830c1cc2217d9e2c6d64203914e7fa95b
+Author: Martin Ling <martin-git at earth.li>
+Date:   Mon May 5 00:38:58 2014 +0100
+
+    rigol-ds: Quick hack to fix bug #354.
+
+commit a9af7b1b8bc76e1c25df7b97c51ce88f4428b9d7
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun May 4 22:04:37 2014 +0200
+
+    README: Mention missing dependency 'librevisa'.
+
+commit f897acaee82d5bc3c511da14167fbbd7951cbf3d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun May 4 20:57:38 2014 +0200
+
+    log.c: Avoid using the same name for a variable and enum.
+
+commit 4711724141f9073af8b2493c3fc6a643d5c77cbe
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun May 4 20:51:05 2014 +0200
+
+    Add/update Doxygen @since tags.
+
+commit 768579456c7800e462a404c2c28af1e306989fd8
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun May 4 19:58:56 2014 +0200
+
+    libsigrok.h: Add some missing enum names for consistency.
+
+commit 6b2d33856f15d2ea6642aa4643805ab8ca24f638
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun May 4 11:48:17 2014 -0700
+
+    asix-sigma: Don't set invalid configuration options.
+
+commit f0554946600a7db68f9ef33d25646f17562bf284
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun May 4 17:55:46 2014 +0200
+
+    doxygen: Updated Doxyfile to doxygen 1.8.6.
+
+commit 8c21897f59b4b78e1caade7cf7b11318b11b3f8b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun May 4 17:44:05 2014 +0200
+
+    Unhook the Link Instruments MSO-19 from the build for now.
+    
+    This driver is neither working nor has it been in a compiling state for
+    a long time, so unhook it from the build until it is fixed and works.
+    
+    The files (api.c and protocol.[ch]) are still in git, but won't end up in
+    released tarballs and they don't get built (neither git nor tarballs).
+    
+    This also allows us to drop the otherwise unneeded dependency on libudev.
+    When the MSO-19 driver comes back, it should be in a form that doesn't
+    require the inherently Linux-only libudev anyway. See also:
+    http://sigrok.org/bugzilla/show_bug.cgi?id=65
+
+commit 2fa222c78b522f6f23e8930f5a8c0bbc134fcc5c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun May 4 17:38:09 2014 +0200
+
+    Drop obsolete Linux-only usbtmc backend.
+    
+    We're now using a portable libusb-based (userspace) backend which should
+    in theory work on any OS with libusb support.
+
+commit e311f770159244725a33a412a9f9ef6eda9126c3
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun May 4 17:35:47 2014 +0200
+
+    README.devices: Various updates and fixes.
+
+commit 71422cb6eb8be34f6fca8a3be7ebe10fe1bea319
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun May 4 16:57:58 2014 +0200
+
+    Drop left-overs of the removed alsa driver.
+
+commit 144f6660d004d60264a57db7150ed90e5f68ea77
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat May 3 22:14:01 2014 +0200
+
+    Don't define names ending with _t (POSIX reserved).
+    
+    Avoid defining any names ending in _t, those are generally reserved
+    for POSIX usage. For details see:
+    
+    http://pubs.opengroup.org/onlinepubs/007904975/functions/xsh_chap02_02.html
+    http://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html
+
+commit 999f6730c66fafc76fe32f7090cc740d901a2226
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun May 4 00:35:24 2014 -0700
+
+    asix-sigma: Disable sample-limited capture for now.
+    
+    This is not really supported yet in the driver.
+
+commit fb2e6de774816b4298dcc9eed66d2d9282d53cab
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun May 4 00:34:24 2014 -0700
+
+    asix-sigma: Publish capture ratio correctly.
+
+commit b9a53103cf1f66a09cde1b5887d3290c579c5d43
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat May 3 21:22:38 2014 +0200
+
+    saleae-logic16: Minor whitespace fixes, cosmetics.
+
+commit 1b822521f77f8ec61405cc662a4fa19579e90398
+Author: Marcus Comstedt <marcus at mc.pp.se>
+Date:   Fri Apr 25 21:27:49 2014 +0200
+
+    saleae-logic16: Use unitsize 1 if none of channels 8-15 are used.
+
+commit 2db959063b073b87cfb45a433f2a422b594731b0
+Author: Marcus Comstedt <marcus at mc.pp.se>
+Date:   Fri Apr 25 21:07:16 2014 +0200
+
+    saleae-logic16: Don't send more samples than requested.
+    
+    This fixes bug #350.
+
+commit 831d7c70eb901788d6fa7551807644b1130cce32
+Author: Martin Ling <martin-git at earth.li>
+Date:   Tue Apr 15 21:26:26 2014 +0100
+
+    Add SR_CONF_DEVICE_MODE and SR_CONF_TEST_MODE config keys.
+
+commit e826239c85a18ce554e5011a99b51b4e71ef48ef
+Author: Martin Ling <martin-git at earth.li>
+Date:   Tue Apr 15 21:16:20 2014 +0100
+
+    fx2lafw: Allow matching USB descriptor strings as well as VID/PID.
+
+commit 1c48000dc7aa38c8e4fae9fbc5848be570c94366
+Author: Martin Ling <martin-git at earth.li>
+Date:   Tue Apr 15 11:23:51 2014 +0100
+
+    fx2lafw: tidy up config_set().
+
+commit a920a7d899be7aabcf7cc70c671b15e628c3d51f
+Author: Martin Ling <martin-git at earth.li>
+Date:   Tue Apr 15 11:03:59 2014 +0100
+
+    fx2lafw: implement config_get for SR_CONF_LIMIT_SAMPLES and tidy up.
+
+commit a54edb1dfb44c863618779d42b03090de8711961
+Author: Martin Ling <martin-git at earth.li>
+Date:   Mon Apr 14 21:32:01 2014 +0100
+
+    fx2lafw: pass sdi to command functions.
+
+commit 23b886bc40eaf14cc44c00cf9dba85404ddc267f
+Author: Marek Vasut <marex at denx.de>
+Date:   Fri Apr 25 18:03:47 2014 +0200
+
+    asix-sigma: Init cur_sample_rate
+    
+    Init the cur_sample_rate to 200kHz. This is now the default sample
+    rate for the ASIX Sigma if no other is specified by -c samplerate=N
+    on the command line. Without this change, the driver would crash on
+    SIGFPE because a division by zero would happen.
+    
+    Signed-off-by: Marek Vasut <marex at denx.de>
+
+commit 1e23158b933e2c7d818d95fbbc45cb21cbff7065
+Author: Marek Vasut <marex at denx.de>
+Date:   Mon Apr 21 01:44:36 2014 +0200
+
+    asix-sigma: Fix the trigger handling
+    
+    Due to the recent changes in the sigma driver, the trigger handling got
+    broken. Fix this by properly calculating and propagating the fact that
+    the trigger happened.
+    
+    Signed-off-by: Marek Vasut <marex at denx.de>
+
+commit 23239b5c84aec17d5d5ae0885a59517f61259c9f
+Author: Marek Vasut <marex at denx.de>
+Date:   Mon Apr 21 01:29:52 2014 +0200
+
+    asix-sigma: Pull out cluster decoding
+    
+    Pull out the code for decoding the DRAM clusters into separate function.
+    This shall improve readability some more.
+    
+    Signed-off-by: Marek Vasut <marex at denx.de>
+
+commit a16a6391b5cc1479d791c8b760352a937b9d3770
+Author: Marek Vasut <marex at denx.de>
+Date:   Mon Apr 21 01:14:54 2014 +0200
+
+    asix-sigma: Exterminate passing lastts and lastsample
+    
+    These two values can pulled out from devc->state, so there really is
+    no need to pass them as function argument when we already pass the
+    devc.
+    
+    Signed-off-by: Marek Vasut <marex at denx.de>
+
+commit 5fc01191eb13c21e4b0ae1ee117f723d48b2d10d
+Author: Marek Vasut <marex at denx.de>
+Date:   Sun Apr 20 03:10:05 2014 +0200
+
+    asix-sigma: Rework decode_chunk_ts()
+    
+    This function could have never returned correct data. Rework the decoding
+    logic according to the Sigma documentation. This patch also fixes the
+    handling of partial DRAM lines and partial DRAM clusters.
+    
+    While at it, do not allocate megabytes of data on stack, just allocate 2KiB
+    which is plenty for all the work this function needs to do.
+    
+    Signed-off-by: Marek Vasut <marex at denx.de>
+
+commit 46641facd4ad8de4a93910d7089c7b289b412443
+Author: Marek Vasut <marex at denx.de>
+Date:   Sun Apr 20 22:58:34 2014 +0200
+
+    asix-sigma: Suspend support for trailing DRAM lines
+    
+    The support for trailing DRAM lines was broken. This patch starts
+    rework of support for this, but in order to do that, we need to
+    rework decode_chunk_ts() a little first.
+    
+    This patch adjusts the decode_chunk_ts() a little to receive the
+    total amount of events in DRAM line instead of some nonsense value.
+    This patch temporarily removes the support for the trailing DRAM
+    lines until the decode_chunk_ts() is fixed to cope with this, so
+    yes, this patch introduces breakage!
+    
+    Signed-off-by: Marek Vasut <marex at denx.de>
+
+commit 3628074d09723f20fa1b0a2026d6300ff69242c3
+Author: Marek Vasut <marex at denx.de>
+Date:   Sun Apr 20 22:45:25 2014 +0200
+
+    asix-sigma: Properly fetch timestamp in decode_chunk_ts()
+    
+    Instead of this ad-hoc readout voodoo, use proper function to read
+    the timestemp. One which will not break even on big-endian machines.
+    
+    Signed-off-by: Marek Vasut <marex at denx.de>
+
+commit f41a4cae4966fb0237211d163a7afc581e29cbd7
+Author: Marek Vasut <marex at denx.de>
+Date:   Sun Apr 20 22:40:38 2014 +0200
+
+    asix-sigma: Use proper structure for DRAM lines
+    
+    Use proper structure instead of plain buffer of uint8_t for the contents
+    of DRAM in download_capture(). This is beneficial as we can interpret the
+    contents easily.
+    
+    Signed-off-by: Marek Vasut <marex at denx.de>
+
+commit 3513d965699c663c329955f1a96f79fce73dcc6e
+Author: Marek Vasut <marex at denx.de>
+Date:   Sun Apr 20 22:36:55 2014 +0200
+
+    asix-sigma: Introduce function to read DRAM cluster timestamp
+    
+    Introduce helper function which returns the timestamp of DRAM cluster
+    and use it in download_capture().
+    
+    Signed-off-by: Marek Vasut <marex at denx.de>
+
+commit e69ad48e084138c72b5cb5a419efed628c0996bc
+Author: Marek Vasut <marex at denx.de>
+Date:   Sun Apr 20 22:28:33 2014 +0200
+
+    asix-sigma: Unify calling of decode_chunk_ts()
+    
+    Clean up the way decode_chunk_ts() is called a little. Introduce a variable
+    which will not be -1 only in case a trigger happened on the particular DRAM
+    line.
+    
+    Signed-off-by: Marek Vasut <marex at denx.de>
+
+commit c6648b663c717f85d05e928102127b0024d22984
+Author: Marek Vasut <marex at denx.de>
+Date:   Sun Apr 20 22:19:11 2014 +0200
+
+    asix-sigma: Rework download_capture() to support more than 32 lines
+    
+    In the current configuration, the download capture used 32KiB buffer
+    for samples. This was the upper limit this function could download
+    from the Sigma. Even the sigma_read_dram() was only called once to
+    read up-to 32 DRAM line from address 0x0 in the DRAM.
+    
+    This patch reworks the function to call sigma_read_dram() in a loop
+    in case there is need to download more than 32 DRAM lines of data
+    from Sigma. The data are then correctly passed for decoding to the
+    decoding function.
+    
+    Signed-off-by: Marek Vasut <marex at denx.de>
+
+commit fd830beb6751a966a0f12a9ca48a8550bbe5bbba
+Author: Marek Vasut <marex at denx.de>
+Date:   Sun Apr 20 21:34:36 2014 +0200
+
+    asix-sigma: Remove stack-based alloc in download_capture()
+    
+    Avoid allocating 32KiB of data on stack in download_capture(). Instead,
+    do a glib-variant of calloc(1, ) to allocate the data for the samples
+    which will be downloaded. This avoids explosions of stack on systems
+    with tight stack limits.
+    
+    Furthermore, define structures describing the organisation of Sigma's
+    DRAM memory and start using those instead of ad-hoc preprocessor macros
+    defining the sizes of various structures in memory.
+    
+    Signed-off-by: Marek Vasut <marex at denx.de>
+
+commit 462fe786641df67e99d67f0f7031e7ca76430981
+Author: Marek Vasut <marex at denx.de>
+Date:   Sun Apr 20 20:50:10 2014 +0200
+
+    asix-sigma: Localize variables
+    
+    The trigger position, stop position and chunk in which the trigger happened
+    are no longer needed in the global scope. Make those variables local to the
+    download_capture() function.
+    
+    Signed-off-by: Marek Vasut <marex at denx.de>
+
+commit 6057d9fa54fc0c4023e4324cc9540db71ab6cfe7
+Author: Marek Vasut <marex at denx.de>
+Date:   Sun Apr 20 20:45:40 2014 +0200
+
+    asix-sigma: Move all register I/O into download_capture()
+    
+    Move all the register I/O that is necessary to do the download of samples
+    from Sigma into download_capture() function. This makes the downloading
+    code contained a bit more again.
+    
+    Signed-off-by: Marek Vasut <marex at denx.de>
+
+commit 00c8650877a169a04f309f5ecccf7b1b67c75987
+Author: Marek Vasut <marex at denx.de>
+Date:   Sun Apr 20 20:40:00 2014 +0200
+
+    asix-sigma: Clearly separate the sample download
+    
+    Reorder the sigma_capture_mode() function so that the part which handles
+    the download of samples from Sigma is clearly separated from the tests if
+    the download should be started.
+    
+    Signed-off-by: Marek Vasut <marex at denx.de>
+
+commit d405193074b11296e33acb56945978c08f2f4f98
+Author: Marek Vasut <marex at denx.de>
+Date:   Sun Apr 20 20:30:16 2014 +0200
+
+    asix-sigma: Pull out the CAPTURE mode handler
+    
+    Pull out the code handling the Sigma which is in CAPTURE mode into
+    a separate function. This is so we can start reworking this entire
+    code easily soon.
+    
+    Signed-off-by: Marek Vasut <marex at denx.de>
+
+commit 58d6f20748e6b33677da3b4a388ac3b8fcaa12f7
+Author: Marek Vasut <marex at denx.de>
+Date:   Sun Apr 20 19:57:02 2014 +0200
+
+    asix-sigma: Read position only in CAPTURE state
+    
+    Check the position of ForceStop and Trigger events only in case we
+    are in CAPTURE state, it's useless to do this unconditionally when
+    receive_data() is called.
+    
+    Signed-off-by: Marek Vasut <marex at denx.de>
+
+commit 011f1091fa6d85aef3c36758bd090809f2fde0c9
+Author: Marek Vasut <marex at denx.de>
+Date:   Sun Apr 20 19:49:44 2014 +0200
+
+    asix-sigma: Decrypt the LA mode switch sequence
+    
+    Decode the logic mode start sequence into a series of FPGA instructions
+    instead and get rid of this sequence of magic numbers.
+    
+    Signed-off-by: Marek Vasut <marex at denx.de>
+
+commit 1c2736f90912b58df18595d474e5c917c7ecd195
+Author: Marek Vasut <marex at denx.de>
+Date:   Sun Apr 20 19:41:23 2014 +0200
+
+    asix-sigma: Encode the opcodes as hex values
+    
+    Just encode the opcodes as hexadecimal values. This makes for better
+    readability when mapping the communication dump with the sigma to the
+    code.
+    
+    Signed-off-by: Marek Vasut <marex at denx.de>
+
+commit 64fe661b87c119079516b9ba7b395bdd8af14994
+Author: Marek Vasut <marex at denx.de>
+Date:   Sun Apr 20 19:36:40 2014 +0200
+
+    asix-sigma: Pull out the logic-mode switching
+    
+    Pull out the code which switches Sigma from the FPGA programming mode
+    into Logic-Analyzer mode into separate function. Also, given the reply
+    is only ever 3-byte long, do not allocate 32 byte big buffer, but only
+    a 3-byte long one.
+    
+    Signed-off-by: Marek Vasut <marex at denx.de>
+
+commit 29b66a2eb0ffac181c2d7b0c0d7868e5344fc272
+Author: Marek Vasut <marex at denx.de>
+Date:   Sun Apr 20 19:29:52 2014 +0200
+
+    asix-sigma: Squash yoda-condition in upload_firmware()
+    
+    Signed-off-by: Marek Vasut <marex at denx.de>
+
+commit a80226bbb9966e8692a6d8b63c63e0630831041f
+Author: Marek Vasut <marex at denx.de>
+Date:   Sun Apr 20 19:27:43 2014 +0200
+
+    asix-sigma: Move the sigma_fw_2_bitbang()
+    
+    Move the sigma_fw_2_bitbang() function closer to the upload_firmware()
+    function so there's not such a horrible mess in the file.
+    
+    Signed-off-by: Marek Vasut <marex at denx.de>
+
+commit d485d4436177b04e305f1e6c880edf62755380e0
+Author: Marek Vasut <marex at denx.de>
+Date:   Sun Apr 20 19:19:33 2014 +0200
+
+    asix-sigma: Cleanup the bit2bitbang
+    
+    Rework the bit2bitbang function. Remarkable changes are:
+    - The function was renamed to sigma_fw_2_bitbang()
+    - We use glib function calls to work with the file
+    - We mmap the file containing firmware instead of opening the file
+      and then reading it into a buffer.
+    - The magic firmware transformation is now type-safe.
+    - Documentation and comments were added where applicable.
+    
+    Signed-off-by: Marek Vasut <marex at denx.de>
+
+commit 8bbf7627df3706fd1fee6d094c09a010dcda9b1a
+Author: Marek Vasut <marex at denx.de>
+Date:   Sun Apr 20 17:58:35 2014 +0200
+
+    asix-sigma: Weed out in-condition assignments
+    
+    Remove all those if ((ret = foo(bar)) < 0) constructs from upload_firmware()
+    function. This is just a confusing programming practice, kill it. While at it,
+    replace all the uses of &devc->ftdic with plain ftdic , which is defined at
+    the begining.
+    
+    Signed-off-by: Marek Vasut <marex at denx.de>
+
+commit 499b17e9c043e1ec92e71095289d63f09b981eea
+Author: Marek Vasut <marex at denx.de>
+Date:   Sun Apr 20 17:49:29 2014 +0200
+
+    asix-sigma: Fix firmware path construction
+    
+    The code silently assumed the firmware path can be no longer than 128 bytes.
+    This doesn't scale. This patch fixes it in such a way that it completely
+    rips out the run-time computation of firmware path and instead replaces it
+    with compile-time computation. It's true this makes the library grow by a
+    couple bytes, but makes the code cleaner.
+    
+    Signed-off-by: Marek Vasut <marex at denx.de>
+
+commit d5fa188ac93149cb75340d615a1815cbca1f852b
+Author: Marek Vasut <marex at denx.de>
+Date:   Sun Apr 20 17:18:31 2014 +0200
+
+    asix-sigma: Cleanup FPGA initialization
+    
+    Rework the pre-firmware-upload FPGA initialization sequence so it matches
+    the documentation. Also, since this sequence is documented in a separate
+    section, wrap it into separate function.
+    
+    Signed-off-by: Marek Vasut <marex at denx.de>
+
+commit 790c7ccc884df9503ec84d61825d5c016bec02e1
+Author: Marek Vasut <marex at denx.de>
+Date:   Sun Apr 20 17:02:05 2014 +0200
+
+    asix-sigma: Remove NUM_CHANNELS macro
+    
+    The NUM_CHANNELS macro is inflexible, since in 100MHz and 200MHz modes
+    we don't support 16 channels. Moreover, it's only used to limit the size
+    of array of channel labels, which can be done in much cleaner way.
+    
+    Signed-off-by: Marek Vasut <marex at denx.de>
+
+commit b1648dea88d378d814bc7168c1ad6247677f65cc
+Author: Marek Vasut <marex at denx.de>
+Date:   Sun Apr 20 16:53:13 2014 +0200
+
+    asix-sigma: Document sampling rate table
+    
+    Add comments to the sampling rate table explaining how the frequencies
+    are selected and where do those numbers come from.
+    
+    Signed-off-by: Marek Vasut <marex at denx.de>
+
+commit 6868626bd3c62aa04daae24b268665092b6c3bd8
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Apr 2 15:22:49 2014 +0200
+
+    asix-sigma: Acquisition fixes.
+
+commit 6cb45d96c802190aef675e96c6037ee6ab0a8622
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Apr 30 07:40:56 2014 -0700
+
+    output/vcd: Support getting samplerate from meta packets.
+
+commit 83023573d9a3c0fc1d5823d4dc5f9e85b72084d9
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Apr 29 14:00:47 2014 -0700
+
+    output/gnuplot: Support getting samplerate from meta packets.
+
+commit 0f3d8c89673f7044852434073bb0c4f7a2c97deb
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 28 19:09:32 2014 -0700
+
+    output/csv: Support getting samplerate from meta packets.
+
+commit 787e9bc970386c543a16560eff236fd97fcd3357
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 28 15:11:17 2014 -0700
+
+    output/ascii: Support getting samplerate from meta packets.
+
+commit 7bcbbfae3e0262ed25693adb7aa1f0b864722827
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 28 15:06:36 2014 -0700
+
+    output/hex: Support getting samplerate from meta packets.
+
+commit 35159a6b28adfbed14d10b745668bee47b5b8c1a
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 28 14:54:47 2014 -0700
+
+    output/bits: Support getting samplerate from meta packets.
+
+commit 7ea458625c34c9c1c7da8431e8af55b9a6f3759c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Apr 25 19:34:41 2014 +0200
+
+    session: Show unitsize of the received data.
+
+commit bdf6c50c9338c10fe174df0fec386df0632614c0
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Apr 25 18:44:21 2014 +0200
+
+    Don't include NO_LOG_WRAPPERS in the Doxygen output.
+
+commit 2ad1deb89d9f459752687a03c3d0539d122ea354
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Apr 25 18:40:59 2014 +0200
+
+    Don't include LOG_PREFIX in the Doxygen output.
+    
+    (files in hardware/, input/, and output/ don't need this since none of
+    those directories contain API stuff and are thus not included in the
+    list of input files for Doxygen at all).
+
+commit 4f10853e67056297fe71c8645608c371cb8907e2
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Apr 18 19:11:47 2014 +0100
+
+    configure.ac: Separate library flags from other CFLAGS.
+
+commit e958f9217c5ac3880a63b0bba9c9393f985af700
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Apr 18 19:13:13 2014 +0100
+
+    Give type names to all enumerations.
+
+commit d72b0cc8985644cd79fb772e9affaf1c111c87e6
+Author: Martin Ling <martin-git at earth.li>
+Date:   Mon Apr 21 02:17:03 2014 +0100
+
+    Remove orphaned prototype for sr_filter_channels from proto.h.
+
+commit 06b5d7f70dc121da80a2a0b71b06d2d4b4c170f3
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Apr 24 21:04:23 2014 +0200
+
+    fx2lafw: Don't send more samples than requested.
+    
+    It's the new law.
+
+commit b0ccd64d021ae7c9dbcebc8413dc2ebe94099f68
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Apr 22 18:08:40 2014 +0200
+
+    WIP
+
+commit bda100ec0f99166ff391a4f4b44662a6eed5641b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 21 23:35:26 2014 +0200
+
+    output/ascii/bits/hex: Remove stray g_free().
+
+commit 1e1dac0c0707f73a4c86e27cd02bb90515550354
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 21 14:46:49 2014 +0200
+
+    ols: Allow disabling all channels.
+    
+    This fixed bug 316.
+
+commit dba3e6826e3d37309ed49dd77cde346b369bc5a9
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Apr 20 22:51:09 2014 +0200
+
+    output: Introduce output module API wrappers.
+
+commit 7e7b7fb7d323f7600958bf29025ca089a15829e3
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Apr 19 13:37:53 2014 +0200
+
+    Removed ALSA driver.
+    
+    This driver has been unmaintained for years, and was never good code
+    to begin with. It's also questionable whether it was ever useful,
+    particularly with the demo driver now supporting various analog
+    signalling.
+
+commit 3b15586812e47e885ed69e3cd1188b1ccf25f807
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Apr 19 13:34:46 2014 +0200
+
+    Removed obsolete sr_filter_channels().
+
+commit 44559b2c3bfa2c892242097e3aba871a11f943eb
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Apr 19 13:28:17 2014 +0200
+
+    Remove obsolete output API.
+
+commit 6f64ebb22306d1436becd9da4fb3761c99462810
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Apr 19 12:34:30 2014 +0200
+
+    output/ascii: Rewrite for new output API.
+
+commit 8d3af2e868c4fcfb0119ec74c541fb5d04a10fce
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Apr 19 12:31:50 2014 +0200
+
+    output/hex: Rewrite for new output API.
+
+commit dbd0aeff352c93d6091f141550683966504a72d5
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Apr 19 12:25:02 2014 +0200
+
+    output/bits: Rewrite for new output API.
+    
+    This also fixes the performance problems in the old module.
+
+commit 71e16f47e3b02a4d2a8208ab02ee183ac6162137
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Apr 17 14:40:47 2014 +0200
+
+    output/binary: Use new output API.
+
+commit d42eb9d89938d5ec079fe004ccc4ab5128c5d85a
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Apr 17 14:10:49 2014 +0200
+
+    output/chronovu_la8: Use new output API.
+    
+    This somewhat naively copies whatever it gets into the output, regardless
+    of how many channels are in there, or which ones are enabled. Not sure
+    what the best way to deal with that is, but for now you have to feed it
+    a channel setup the Chronovu software can read.
+
+commit 2a035e539ab0f1f96fd90f64ac5a654056040971
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Apr 16 20:02:39 2014 +0200
+
+    output/csv: Use the logic stream's unitsize.
+    
+    This also fixes the channel index, instead of counting on the logic
+    data being arranged according to enabled channels only.
+
+commit 2b78ffea549eafb3835c8e58390008cc5f0ca24c
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Apr 16 15:29:53 2014 +0200
+
+    output/vcd: Use the logic stream's unitsize.
+    
+    Also code cleanup and some memory leaks fixed.
+
+commit b240ee0856349d72d30ad75f010a079338b76baa
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Apr 16 15:26:10 2014 +0200
+
+    output/gnuplot: Use new output API.
+
+commit 1458018224d98bfc080c571e2145f816afbcac39
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Apr 13 18:59:08 2014 +0200
+
+    .gitignore: Add test-suite.log.
+
+commit 55f98c65332cf08ff3f87480f07f8419fe49fab6
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Apr 2 18:29:36 2014 +0200
+
+    sr_dev_inst_new(): Use NULL (not "") if version unknown/nonexisting.
+    
+    Unify the whole code-base to use NULL there, not a mix of "" and NULL.
+
+commit cfe01d0607a65bf4e17e3a8d15e4c0f2b20fb55c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Apr 2 18:23:23 2014 +0200
+
+    chronovu-la: Show errors other than "device not found".
+    
+    This can be useful for the user to see, e.g. for permission related
+    issues (device is there, but cannot be accessed).
+
+commit 958326f8c685667239127a59ef883e7bceb63ac0
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Apr 5 13:35:49 2014 +0200
+
+    configure.ac: Clearly mark required and optional libs.
+
+commit 99af83b7380ef7d8d48e15616b8910062890e7d3
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sun Apr 6 22:47:44 2014 +0200
+
+    rigol-ds: fix long memory depth setting on DS1000
+
+commit f589a6d49971194737910faa11236012eed22c5a
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sun Apr 6 22:47:44 2014 +0200
+
+    scpi_usbtmc_libusb: disable all clear_halt for Rigol DS1000
+
+commit 50e6311a1b76ead9e082d99bdea91c1cba08fd4e
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sun Apr 6 01:31:12 2014 +0200
+
+    scpi_usbtmc_libusb: disable bulk_out clear_halt for Rigol DS1000
+    
+    fix hangup issue with Rigol firmware version 00.02.02.02.00
+
+commit eb28f1b7b2c89a9986e799adcfffe2e2fc9c72b6
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sat Apr 5 17:42:33 2014 +0200
+
+    fx2lafw: fix possible use of uninitialized variable (gcc-4.9 warning fix)
+    
+    hardware/fx2lafw/protocol.c: In function 'fx2lafw_command_start_acquisition':
+    hardware/fx2lafw/protocol.c:113:7: warning: 'cmd.flags' may be used uninitialized in this function [-Wmaybe-uninitialized]
+       (cmd.flags & CMD_START_FLAGS_CLK_48MHZ) ? "48" : "30");
+           ^
+
+commit 38d32464973b828bf327b9271ef4b0437d85c9f2
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Apr 2 09:37:29 2014 +0200
+
+    Various drivers: Expose SR_CONF_TRIGGER_TYPE.
+    
+    Without this, sigrok-cli --show (for example) will not show the
+    supported trigger types.
+
+commit 69bdcd8bb44f3368d473da4f9ad5069778b139e7
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Apr 2 09:29:23 2014 +0200
+
+    chronovu-la: LA16 has fewer max. samples than LA8.
+    
+    Each LA16 sample is 16bits wide (LA8 samples are 8 bits wide). Adapt the
+    number returned for SR_CONF_LIMIT_SAMPLES in config_list() accordingly.
+
+commit 05266f36a5d4cd9371983bb5f659266489327af2
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 1 23:23:23 2014 +0200
+
+    chronovu-la: Fix byte order for LA16 samples sent to the bus.
+
+commit b0efc84e12c97afc59ae53225a4e59c2fa9459ef
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 1 22:41:02 2014 +0200
+
+    chronovu-la: Document that streaming is not possible.
+    
+    This closes bug #261.
+
+commit 7b3567126c22622180d82463f4f848606d52d2cd
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 1 21:47:11 2014 +0200
+
+    Rename 'chronovu-la8' driver to 'chronovu-la'.
+    
+    The driver now also supports the LA16 device (and possibly others in the
+    future).
+
+commit 00910580bb73862856cd3f09d20934f086b3fac0
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Mar 31 01:26:07 2014 +0200
+
+    la8: Add support for the ChronoVu LA16.
+    
+    The ChronoVu LA16 is a new logic analyzer from ChronoVu with some
+    differences in features compared to the LA8, e.g.
+    
+     - Supports 16 channels (instead of 8).
+     - Max. 200MHz samplerate (instead of 100MHz).
+     - Supports state triggering (low and high channel value) and edge triggering
+       (rising or falling edge), the LA8 only supports state triggering.
+    
+    This driver now supports both the LA8 and LA16, but it needed a few
+    changes:
+    
+     - Add support for detecting multiple device instances at all.
+     - Add support for both LA8 and/or LA16 devices being detected.
+     - Add a device profile struct for LA8-/LA16-specific device properties.
+     - Move the samplerates list to devc (it's different for LA8 and LA16).
+     - Split scan() into two functions, one for scanning, one for adding a device.
+     - Expand some variables and fields from uint8_t to uint16_t in order to
+       support 16 channels.
+     - Update the samplerate related functions to support the LA16's 200MHz.
+     - Various other minor updates in order to better handle both device types.
+     - Various error handling improvements and simplifications.
+     - Also, replace time() with g_get_monotonic_time() everywhere.
+    
+    This also fixes bug #247 (which was related to incorrect handling of
+    resources during scan and open of the device, which was exposed by
+    PulseView allowing multiple consecutive scan/close/open calls).
+
+commit b172c1301e183646fbe9a2b7e096d9c7ee8e2458
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Mar 30 22:40:27 2014 +0200
+
+    la8: Cleanups, cosmetics, simplifications.
+    
+    Also, make some LA8 references more generic in preparation of
+    LA16 support.
+
+commit 9503583268cb322dc67b0e11d928739cbdcdb342
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Mar 25 21:38:47 2014 +0100
+
+    demo: Fix typos.
+
+commit 8bd3daa48ad3c5e043fc9f468144f9a455ad80ce
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Mar 25 21:35:31 2014 +0100
+
+    Various drivers: Drop some unneeded lines.
+
+commit 0bcfc9dcd83e3bf8200a268782fddad1f15f17a7
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Mar 27 15:13:24 2014 +0100
+
+    rigol-ds: Don't close SCPI handle we didn't open.
+
+commit 5d336f1130ddc2faaeabd7ed6ec602904054bfb8
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Tue Mar 25 23:09:57 2014 +0100
+
+    rigol-ds: Add the TRIGGER_SLOPE entry to config_get() and config_list()
+
+commit 61e77667de34752838a8b0d29b5bfcb14b6b95a1
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Mar 25 09:26:05 2014 +0100
+
+    hameg-hmo: Change some PG_/pg_ names to CG_/cg_.
+    
+    This fixes parts of bug #259.
+
+commit fca75cbb741ae756bf50eaf1cdc6d4d53fcc60cd
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Mar 24 16:11:45 2014 +0100
+
+    A few more random 'probe' to 'channel' changes.
+    
+    This fixes parts of bug #259.
+
+commit f3ca73edd29a48f8cc19755df629ab2bc9478eea
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Mar 24 16:05:42 2014 +0100
+
+    Rename a few more API calls with 'probe' in their name.
+    
+    This fixes parts of bug #259.
+
+commit 3f239f0803b9fbc073dd7abe9fc7b2a0c606fbb6
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Mar 24 22:39:42 2014 +0100
+
+    Rename various *PROBE* macros to *CHANNEL*.
+    
+    This fixes parts of bug #259.
+
+commit 56d0d24535700fb53e47a25ad5c73d34697695fa
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Mar 24 21:36:04 2014 +0100
+
+    Rename sr_probe_new() to sr_channel_new().
+    
+    This fixes parts of bug #259.
+
+commit ba7dd8bbb8168cba432a844259a3e239aa5f36d7
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Mar 24 21:34:20 2014 +0100
+
+    Replace 'probe' with 'channel' in most places.
+    
+    Also, consistently use 'ch' for channel variables. This matches how we
+    consistently use sdi, devc, and so on all over the code-base.
+    
+    This fixes parts of bug #259.
+
+commit 91aea754aaed0f0f2a6fc4b2b875f0d0b7c01f8e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Mar 20 21:58:57 2014 +0100
+
+    Rename 'struct sr_probe' to 'struct sr_channel' everywhere.
+    
+    This fixes parts of bug #259.
+
+commit 53b4680fceab9351fc87b8c5b34854733f5fdac0
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Mar 20 21:58:01 2014 +0100
+
+    Consistently use 'cg' for channel group variables.
+    
+    This matches how we consistently use sdi, devc, and so on all over
+    the code-base.
+    
+    This fixes parts of bug #259.
+
+commit a68bf88e3a6ba0184f1d6aea4ce26b9a2950a513
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Mar 14 21:21:09 2014 +0100
+
+    Replace channel_group.probes with channel_group.channels.
+    
+    This fixes parts of bug #259.
+
+commit 40fd0264f907cf99a92d8192a11cde4499ba4652
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Mar 14 21:22:29 2014 +0100
+
+    Replace some 'pg' with 'cg'.
+    
+    (since 'probe groups' are now called 'channel groups')
+    
+    This fixes parts of bug #259.
+
+commit 660e398fe9f5fc608787f8fd75a9df8aac61026f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Mar 14 21:09:37 2014 +0100
+
+    Replace 'probe group' with 'channel group' everywhere.
+    
+    The name 'probe' (and thus 'probe group') is a relic from the times when
+    sigrok was mostly about logic analyzers. Nowadays we support a lot more
+    device types where 'probe' is not really a good term and 'channel' is
+    much better suited.
+    
+    This fixes parts of bug #259.
+
+commit 3fd2dca2072fb0b205db22df8b686917a3298e99
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Tue Mar 25 17:44:38 2014 +0100
+
+    hameg-hmo: Add missing cases in config_get().
+
+commit bbabdaf1e2802aeef7d48fab4b0dc3507a69ffe9
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Tue Mar 25 17:44:37 2014 +0100
+
+    hameg-hmo: Add the TRIGGER_SLOPE entry to config_list().
+
+commit 422a1c0d58249497b982f9dbd42632e5fc2b4a79
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Tue Mar 25 17:44:36 2014 +0100
+
+    hameg-hmo: Fix the logic for the horizontal trigger position in config_set()
+    
+    This patch fixes the logic calculating the trigger position as well as the
+    (hopefully) last remaining locale issue.
+
+commit e83437ae206dea1bce85c8b46f7c56ebb9667bda
+Author: Matthias Heidbrink <m-sourcetree at heidbrink.biz>
+Date:   Mon Mar 24 21:50:07 2014 +0100
+
+    serial-dmm: Implemented support for Voltcraft M-3650CR (driver voltcraft-m3650cr).
+
+commit 1656e47def5422a5273f023d542d4d6a72668b42
+Author: Matthias Heidbrink <m-sourcetree at heidbrink.biz>
+Date:   Mon Mar 24 17:42:52 2014 +0100
+
+    serial-dmm: Implemented support for Voltcraft ME-42 (driver voltcraft-me42).
+
+commit 36cf5b544537730719ca5f9098cbe0a57618ddd7
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Mar 20 00:04:45 2014 +0100
+
+    Makefile.am: Add missing vxi.h.
+    
+    If it's not listed as SOURCE, it won't end up in the tarball and a build
+    from tarball would thus break.
+
+commit 67bd805523f52030a6459786388ce3385be00501
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Mar 19 23:04:55 2014 +0100
+
+    Switch to a non-recursive automake setup.
+    
+    Instead of >= 44 Makefile.am's we now only have one top-level
+    Makefile.am, and use the 'subdir-objects' automake option to
+    handle the build via non-recursive (auto)make.
+    
+    This has the advantage of fewer (boilerplate or other) files and less
+    clutter in general, as well as performance advantages since the new
+    setup can build many files in parallel (with 'make -j'), not only 2 or 3
+    files within the same (e.g. hardware/xxxx/* subdirectory) and also since
+    we no longer need to build intermediate libtool helper libs per subdirectory.
+    
+    A quick, non-scientific test build on a quad-core laptop with 'make -j 4'
+    yields a build time reduction from 35s to 19s.
+    
+    All autotools features that worked before are still intact without any
+    regressions, including the Make targets 'install', 'uninstall', 'check',
+    'dist', 'clean', 'distclean' and so on, as well as all the usual portability
+    handling (build works on any OS, with any Make implementation such as
+    GNU Make or BSD Make, with any shell such as sh/ksh/zsh/bash/dash, etc. etc.)
+    and features such as out-of-tree build support, cross-compile support,
+    testsuite support (also with colored output), "silent make rules", etc. etc.
+
+commit 9ad05e6cd28e5a4c7cc4f38d2dcb561a14bb5563
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Mar 11 19:46:39 2014 +0100
+
+    scpi_usbtmc_libusb.c: Fix two error checks.
+    
+    Two error checks had a missing "ret = ", which lead to an incorrect
+    value being passed to libusb_error_name().
+    
+    Also, lower the level for those messages from sr_err() to sr_dbg()
+    since they're not fatal.
+
+commit d8cbd659ce2e24428c7e403eeebd50ad4a992caa
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Mar 11 19:41:51 2014 +0100
+
+    scpi_usbtmc_libusb.c: Consistently check for < 0 (libusb calls).
+
+commit a84f6ad38984dd8cee2e41a1f35a4ddf373d2dfd
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Mar 5 20:48:54 2014 +0100
+
+    Fix 'aquisition' typo in a few places.
+
+commit 846fb172db5d5688b98dce24def523f25d8a76ac
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sun Mar 9 23:09:47 2014 +0100
+
+    brymen-bm86x: disable driver when libusb is not present
+
+commit 7f7f6a2e0c4f611c2096e5bc079ab5f5b674aefc
+Author: Matthias Heidbrink <m-sourcetree at heidbrink.biz>
+Date:   Sat Mar 8 11:04:27 2014 +0100
+
+    gmc-mh-1x-2x: Whitespace fixes (cosmetic).
+
+commit dc05dd606999c1b5e73d8548145b3b32d209d29c
+Author: Matthias Heidbrink <m-sourcetree at heidbrink.biz>
+Date:   Sat Mar 8 10:56:16 2014 +0100
+
+    visa: Fixed missing header warnings/uninitialized variable.
+
+commit d1d3b7dff9881acfce0923be9e66b3bddaa48221
+Author: Matthias Heidbrink <m-sourcetree at heidbrink.biz>
+Date:   Sat Mar 8 10:50:21 2014 +0100
+
+    gmc-mh-1x-2x: Cosmetic fixes for Metrahit 25S.
+
+commit c6c63b08af0f73b60de6726c9d5aea50d20d83d2
+Author: Matthias Heidbrink <m-sourcetree at heidbrink.biz>
+Date:   Sat Mar 8 10:40:38 2014 +0100
+
+    gmc-mh-1x-2x: Fixed 300 µA range scaling.
+
+commit 0bc3ab92e66ee08486e25a9a95b1300e2654fd28
+Author: Fabio <sigrok at maconnect.ch>
+Date:   Wed Mar 5 10:04:17 2014 +0100
+
+    Fluke189 support
+    
+    I can confirm that the 189 uses the same "QM" command as the 187:
+    <-- QM\r
+    --> QM,+03.225 mV AC
+
+commit 8c9d4d67f8678a5c6819428170d5611a4c3f1dc3
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Fri Feb 28 19:51:57 2014 +0100
+
+    Fixed session_driver so that it can run more than one session.
+
+commit 0ab702601d6b855f162340da9a19b1885ee16253
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Feb 28 13:11:46 2014 +0100
+
+    brymen-bm86x: Remove std_dev_clear() wrapper.
+
+commit 1b950bc79c2b8036191ace947543229c75748689
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Feb 28 13:08:53 2014 +0100
+
+    configure.ac: Move Brymen BM86X snippet to correct place.
+
+commit ecaa89af0e01f9c3f585e82eb849bf616bff22cf
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Wed Feb 19 15:09:03 2014 +0100
+
+    brymen-bm86x: actual driver implementation
+
+commit 8d9c8554a53d3c22305558e6064a6a4873e83fe1
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sat Feb 8 22:40:36 2014 +0100
+
+    brymen-bm86x: Initial driver skeleton.
+
+commit 8bbdd364d3355ee5e39b4573910f7b300ecf6d09
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Wed Feb 26 00:29:55 2014 +0100
+
+    session: Always read a whole number of samples.
+
+commit a66307424e7a14df8f53e04d5ff77436dbaa830f
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Feb 26 21:37:18 2014 +0100
+
+    Remove std_dev_clear() wrappers from drivers.
+
+commit 824fba03415058388108378dadb30b2efcb499a2
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Feb 26 21:35:33 2014 +0100
+
+    session: Implement dev_clear().
+
+commit 8102cee4d495c7402a7ca70ec40414312129c1f2
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Feb 26 21:25:07 2014 +0100
+
+    device: sr_dev_clear() now always works.
+    
+    If the driver does not provide a dev_clear() function, the wrapper
+    now calls std_dev_clear() instead.
+
+commit 0294a409b80f21c8197fa4533fd9819f8274a381
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Feb 12 15:13:41 2014 +0100
+
+    conrad-digi-35-cpu: Add missing Makefile.am, minor cosmetics.
+
+commit c6a2843a58a398d0095291c2a1f397b419d164f4
+Author: Matthias Heidbrink <m-sourcetree at heidbrink.biz>
+Date:   Sat Feb 8 14:26:26 2014 +0100
+
+    conrad-digi-35-cpu: Implemented driver.
+
+commit 823b4e5817af106e88ab4be2bdb999ac9d1ee50b
+Author: Matthias Heidbrink <m-sourcetree at heidbrink.biz>
+Date:   Wed Feb 5 19:50:46 2014 +0100
+
+    conrad-digi-35-cpu: Initial driver framework.
+
+commit a90061e5d1d3f60e4dccd9a408ad53269cc7d7cd
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Feb 12 15:04:54 2014 +0100
+
+    gmc-mh-1x-2x: Shorten driver names a bit.
+
+commit fadd07072b283f7040036a1050e23e7af43f1324
+Author: Matthias Heidbrink <m-sigrok at heidbrink.biz>
+Date:   Sun Feb 9 18:13:49 2014 +0100
+
+    gmc-mh-1x-2x: Support for interface SI232-II with driver gmc-mh-2x-bd232.
+
+commit c90beca7801b16e46ffd4d74c9dd21b02a045ab5
+Author: Matthias Heidbrink <m-sigrok at heidbrink.biz>
+Date:   Wed Feb 5 14:59:02 2014 +0100
+
+    gmc-mh-1x-2x: Added new driver gmc-mh-2x-bd232.
+
+commit 67eb6bcbe607fdc745d34a30123c5a6ad81cad72
+Author: Matthias Heidbrink <m-sigrok at heidbrink.biz>
+Date:   Wed Feb 5 14:46:10 2014 +0100
+
+    hwdriver.c: Update/extend some Doxygen comments.
+
+commit 6392d5992b12cf2b51d7f6704c4d23f3a2d4a294
+Author: Matthias Heidbrink <m-sigrok at heidbrink.biz>
+Date:   Wed Feb 5 14:40:40 2014 +0100
+
+    gmc-mh-1x-2x: Cleanup, docs, minor fixes.
+
+commit 813aab691b255580d3247b9fec7ab3f7b4fc8a18
+Author: Matthias Heidbrink <m-sigrok at heidbrink.biz>
+Date:   Wed Feb 5 14:32:21 2014 +0100
+
+    Update/extend some Doxygen comments.
+
+commit d8b6b28b803ceabef12ac9ccc3f760d0ade70512
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Fri Feb 7 20:20:20 2014 +0100
+
+    scpi_visa: Add missing callback parameter.
+    
+    (scpi_visa_dev_inst_new): Fix serious compiler warning due to
+    missing drvc parameter in prototype.
+
+commit 52f6951c4e15900d4c617d886d8f8298706c9684
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Feb 7 19:42:27 2014 +0100
+
+    scpi_usbtmc_libusb: Consistent libusb error handling.
+
+commit ed840c8612a42506e7c28cca83b4586d9bd79471
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Feb 7 19:01:45 2014 +0100
+
+    scpi: Disable scpi_usbtmc in favor of scpi_usbtmc_libusb for now.
+    
+    Having both in the list will "find" the same device twice.
+
+commit 2a0f6924d2c8f3b203560ba0086e9d297855677a
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Tue Feb 4 23:19:02 2014 +0100
+
+    usb: remove unused sr_usb_find_usbtmc()
+
+commit 20ed3ceee71d97ca594931a537d035503e6d6ec4
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Fri Jan 17 10:49:00 2014 +0100
+
+    scpi: add a libusb based implementation of usbtmc
+
+commit ca28abd6a55c87c3c17fe839b3515ce1e5f121a5
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sun Feb 2 21:50:14 2014 +0100
+
+    hameg-hmo: use the new scpi scan API
+
+commit 9d3ae01b377d73ae3ba0f45715bcd1138d2c28d9
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sun Feb 2 21:49:57 2014 +0100
+
+    rigol-ds: use the new scpi scan API
+
+commit b541f8376d8fadb1377e3140c3d79304f5d680ec
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sun Feb 2 21:47:45 2014 +0100
+
+    scpi: add a generic scan API and implement it in usbtmc and serial transport
+    
+    note that sr_usb_find_serial() is copied from the hameg-hmo driver
+
+commit 17bdda58686a208424520b64f9324eba259ff535
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Fri Jan 17 10:47:42 2014 +0100
+
+    scpi: add a struct drv_context parameter to scpi_dev_inst_new()
+
+commit ea2d6d994f28c11b7b3d0232bd1a3dbbbf67a401
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sun Feb 2 21:33:09 2014 +0100
+
+    libsigrok-internal.h: endian neutral helper macro to write 8/16/32 bits integer to unaligned memory
+
+commit a4f9c35b23e120195269f5387df6dffaabe344dc
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sun Feb 2 21:29:34 2014 +0100
+
+    libsigrok-internal.h: add helper macro to read 8 bits integer
+    matching the 16 and 32 bits one
+
+commit 6e94eb4142c59a92db4e6db3e715607aed30cda9
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sun Feb 2 21:46:20 2014 +0100
+
+    rigol-ds: apply :KEY:LOCK DISABLE only to DS1K
+
+commit 3918fbb0cf65df317390643f2bb143716b8d0a60
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sun Feb 2 21:44:26 2014 +0100
+
+    rigol-ds: properly end WAIT_TRIGGER event handling
+
+commit 83dbd9f09caa400b09fdb699a34f728f1a33b58a
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sun Feb 2 22:09:01 2014 +0100
+
+    rigol-ds: properly deal with dev_close() getting called multiple times
+
+commit b84b7ee73d67273871d03ede6e7de89f187ef929
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Feb 2 16:21:33 2014 -0800
+
+    Fix building without librevisa.
+
+commit fb9e91aed45a45c80014951e1dbd01c5d3e60c5b
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Wed Feb 5 00:56:49 2014 +0100
+
+    output/vcd: Extend output stream to last sample.
+    
+    (receive): Write a dummy timestamp after the last sample
+    to indicate the length of the sampled stream.
+
+commit 4f2dad42f44e4de1e5a7eea79d27f4ee3284ac46
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Wed Feb 5 00:25:32 2014 +0100
+
+    input/vcd: Remove debug output from inner loops.
+    
+    (parse_contents): Do not call sr_dbg() on every signal change.
+    This would be excessive even for sr_spew().
+    (read_until): Do not call ftell() just to be able to show some
+    number in a debug message later on.
+
+commit cd1b0e8f7921afc84d582eb4d95ce673912943dd
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Mon Feb 3 01:54:20 2014 +0100
+
+    input/vcd: Avoid truncation of shift to 32 bits.
+    
+    (parse_contents): Cast constant 1 to uint64_t before shifting left.
+    Also fix whitespace errors.
+
+commit 7ad4e2b80b47aab7be54f1efd084b4df7eb1d6b0
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Feb 3 00:24:13 2014 +0100
+
+    scpi_visa.c: Minor cosmetics.
+
+commit 1fb2312f99a27d552cbd13df7827eb366bcc3122
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sat Feb 1 10:01:05 2014 +0000
+
+    Add librevisa SCPI backend.
+
+commit 191c7e5f4b3f189270ebeed3b92da4cdc594118b
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Thu Jan 30 22:11:10 2014 +0100
+
+    vcd: Remove bogus $dumpvars and $dumpoff commands.
+    
+    These commands are superfluous and do not seem to make sense in
+    the context they were used.  Also, $dumpvars was missing an $end,
+    and $dumpoff was used without any content.
+
+commit 2b6363b433683dfc9bedb678dfe854a56b776d4d
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Thu Jan 30 21:57:49 2014 +0100
+
+    vcd: Output timestamp only once per change.
+    
+    Avoid writing a new timestamp for every changed signal if multiple
+    signals change state simultaneously.  Also, keep signal transitions
+    on the same line with their timestamp to make the output easier to
+    inspect in a text editor.  (VCD does not care whether newlines or
+    spaces are used to separate tokens.)
+
+commit 563080a8d1f1737578a313b89995a9da6ec1077c
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Thu Jan 30 20:49:36 2014 +0100
+
+    vcd: Fix output for more than 8 channels.
+    
+    (receive): Use probe index for sample byte selection too, not just
+    for bit selection.  Also simplify the indexing expressions a bit.
+    This fixes the problem of incorrect output for probes indices 8 to
+    31.
+    Also, use double rather than float in the timestamp calculation,
+    and format the result directly as floating point number rather than
+    converting it back to uint64_t.
+    Additionally, make sure that the state of all signals is written
+    for the very first sample in the stream.  This fixes the problem
+    that signals would be displayed as indeterminate until the first
+    change.
+    (context.samplecount): Make the sample counter part of the context
+    struct, rather than keeping it as a global static.
+
+commit a6c12f3f70fe301051b7de4ae144db926ebeac9c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Jan 30 17:52:44 2014 +0100
+
+    Drop unneeded comments.
+
+commit 85d8aa496e49363b0088359aaa1f90fdb4f30c43
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Jan 30 17:48:10 2014 +0100
+
+    sr_probe->index is no longer deprecated (for now).
+
+commit 7d4874c1b63c169d1847e93c0d221a16d662dd53
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Jan 30 17:02:34 2014 +0100
+
+    configure.ac: Only check for things we actually use.
+    
+    Drop checks where we don't use the result (yet). We might bring back
+    some of those once we start actually using the result in the code.
+
+commit 6358f0a9568848be734a8a94ad7f510e04a4503f
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Thu Jan 30 00:31:42 2014 +0100
+
+    sysclk-lwla: Implement SR_CONF_CLOCK_EDGE setting.
+
+commit 860bc59b0ff598f37f23a1882bf5822ef7c86382
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Wed Jan 29 20:53:51 2014 +0100
+
+    hwdriver: Add SR_CONF_CLOCK_EDGE option.
+    
+    Allow the edge of an external clock input to be configured by
+    means of an SR_CONF_CLOCK_EDGE configuration setting.  This is
+    a string option with the same format as SR_CONF_TRIGGER_SLOPE.
+
+commit 625763e2c2b69f79b950ad0b0cd8b779500f5d95
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Jan 30 11:58:07 2014 +0100
+
+    ols: Code cleanup and more debug output.
+
+commit 016e72f30e21fbec6a1097318ab36877b2c140af
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Jan 29 08:22:02 2014 +0100
+
+    ols: Fix endianness problems in protocol.
+
+commit e6e54bd2537ac423977f5574292f2cb987ce8629
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Sun Jan 26 21:42:22 2014 +0100
+
+    sysclk-lwla: Add support for external trigger input.
+    
+    Implement the configuration setting TRIGGER_SOURCE with the
+    choices CH (logic channels) and TRG (external trigger input).
+    Also implement the TRIGGER_SLOPE setting for selecting the
+    edge to trigger on (rising or falling).
+
+commit e0df15d43600737fe225f5c68dbdbcf84d5fa326
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Sun Jan 26 20:28:59 2014 +0100
+
+    sysclk-lwla: Simplify and optimize word extraction.
+    
+    It turns out that all LWLA protocol responses consist either
+    of 32-bit units or of 32-bit units combined into 64-bit units.
+    Thus it makes sense to double the basic unit size for reading
+    from 16 bit to 32 bit.
+    We cannot do the same for command messages though, as those
+    actually do use 16-bit quantities in some places, and 32-bit
+    arguments are not always aligned to 32-bit boundaries.
+    
+    (acquisition_state.xfer_buf_in): Change unit type to uint32_t,
+    and update related macros and code accordingly.
+    (LWLA_TO_UINT32): New macro to replace LWLA_READ32, operating
+    directly on 32-bit values instead of pointers to 16-bit units.
+    Make use of a compiler-recognized idiom for bitwise rotation
+    to efficiently swap the 16-bit halves of a 32-bit word.
+    (LWLA_TO_UINT16): New macro to replace LWLA_READ16.
+    (LWLA_READ64): Remove unused macro.
+    (LWLA_WORD_[0123]): Slightly simplify 16-bit word extraction.
+
+commit 5413df19528c96c6fba3ee4cc61ec3dfe01047cb
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Sat Jan 25 23:27:40 2014 +0100
+
+    sysclk-lwla: Limit use of SR_ERR_ARG to user-supplied arguments.
+    
+    The return code SR_ERR_ARG is intended for reporting unsupported
+    or inapplicable device configuration settings and is not a hard
+    error.  In order to indicate failure of internal sanity checks,
+    use SR_ERR_BUG instead.
+
+commit 1c873c114cdf67b2cffa78293611d8f8f275bab8
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Tue Jan 28 17:13:00 2014 +0100
+
+    scpi: Limit the log message in get_string() to 70 characters.
+
+commit 9d156555a557aa079056d42fbc9ddd12338e842e
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Sun Jan 26 21:30:57 2014 +0100
+
+    demo: Cast to double while calculating the pattern frequency.
+    
+    Without the cast non integer frequencies weren't possible (e.g. with a sampling
+    frequency of 50Hz we would end up with a signal frequency of 2Hz instead of
+    2.5Hz). The result were signals which had an incorrect number of samples per
+    period.
+    
+    BugLink: http://sigrok.org/bugzilla/show_bug.cgi?id=297
+
+commit 464d49360a02c6b378ebaf5ef38f4bb4536dd5ee
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jan 27 21:19:41 2014 +0100
+
+    rigol-ds: Deal with dev_close() getting called multiple times.
+
+commit ca9b9f4834f106ba8387cf962a216425e0476de5
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Mon Jan 27 00:22:01 2014 +0100
+
+    hwdriver: Change TRIGGER_SLOPE setting to string type.
+    
+    Drivers interpreted the uint64 values to the SR_CONF_TRIGGER_SLOPE
+    configuration setting in different ways.  In order to orthogonalize
+    the API, change the type of the setting to a string with the same
+    format as uses for logic probes.
+
+commit fe90fbb7829ac745d59be37e61fa55e45b251a4e
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Jan 25 21:20:29 2014 +0100
+
+    demo: Require sample limit.
+
+commit c2066c2104f46bd88b40a6dc2f0051fe1272ff8a
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Sat Jan 25 02:21:19 2014 +0100
+
+    sysclk-lwla: Load bitstream files in RBF format.
+    
+    Modify the bitstream loading routine to work directly with the
+    Raw Binary Files (.rbf) generated by Altera tools.  Previously,
+    a custom format was used which was basically an RBF preceded by
+    a 4-byte header specifying the transfer length.
+
+commit 7f4975b4401a1e8de61e356b5b272fc00b658260
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Jan 25 20:39:50 2014 +0100
+
+    demo: Keep separate counters for logic and analog sources.
+    
+    Since they have different internal buffer sizes, their output counters
+    are not in sync. See bug 295.
+
+commit aa48adf96059aa882da4dc8738d6a1e13068d2ae
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Jan 25 12:44:00 2014 +0100
+
+    Properly publish samplerate when loading session file.
+
+commit 3a841040800101909c95a9a9f95d0b0ab19b3b7c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Jan 23 22:45:08 2014 +0100
+
+    sr file format: Bump version to 2.
+    
+    The *.sr (libsigrok session) file format has changed since the last
+    libsigrok release. Frontends using older libsigrok versions will not
+    be able to read *.sr files created by frontends using the new file format.
+    
+    Thus, bump the version number of the file format to 2.
+    
+    Current libsigrok will read both version 1 and version 2 files
+    correctly, and always write version 2 files.
+
+commit fe0d9caa88a1b6207de6760e75086007601e1169
+Author: Martin Ling <martin-git at earth.li>
+Date:   Thu Jan 23 10:13:54 2014 +0000
+
+    rigol-ds: Fix a couple of compile warnings.
+
+commit e36aae989cc9f747f5a0880bfae6a378d7e31e23
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Jan 23 23:11:34 2014 +0100
+
+    output/csv: Drop last separators as needed.
+
+commit ee38c8ba3e49fa3b8af6d2fd83396b3dd4b109a7
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Thu Jan 23 02:35:51 2014 +0100
+
+    sysclk-lwla: Implement config_commit() callback.
+    
+    Move pre-acquisition hardware setup to the new config_commit()
+    callback.  At the moment, the only setting applied at commit
+    time is switching the clock source, which involves uploading
+    a new bitstream to the FPGA.
+
+commit 43db343618e81d03aa8531b4a4ed96c250a29991
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Thu Jan 23 02:27:58 2014 +0100
+
+    sysclk-lwla: Implement config_probe_set() callback.
+    
+    Move setup of channels and trigger masks to the new probe
+    configuration callback.  Although the actual hardware setup
+    still happens just before acquisition, the new approach
+    already has the advantage that invalid settings are caught
+    early.
+    Also, it turns out that the LWLA1034 allows triggering on
+    channels which are not enabled for data acquisition.  This
+    feature is now supported as well.
+
+commit 50cad98d1ba595d6e2da900dbe212b293a058189
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Thu Jan 23 01:24:29 2014 +0100
+
+    sysclk-lwla: Do not reset drv_context.instances on scan.
+    
+    Apparently, frontends may call scan() more than once to accumulate
+    multiple devices, so do not reset the instance list pointer at the
+    start of each scan.  Also, number devices continuously across scans.
+
+commit 99c76642aa8d3c75bef4ef3927b4c4cf45461892
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Thu Jan 23 01:10:31 2014 +0100
+
+    sysclk-lwla: Advertise SR_CONF_CONN option.
+
+commit 4472867a9f17101c7849f26fff9dcce7010f7ac7
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Jan 22 08:15:12 2014 +0000
+
+    rigol-ds: Don't run rigol_ds_block_wait() code unless supported.
+
+commit aff00e40880184c9f9d4a934d83af0cf052ed70c
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Jan 22 08:13:27 2014 +0000
+
+    rigol-ds: Fix partial read handling in header parser.
+
+commit 8943049cd411e194c77ca4ffed434a43af525f03
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Jan 22 07:41:34 2014 +0000
+
+    scpi_serial: Reimplement to allow scpi_read_complete() to work correctly.
+
+commit 824eb2acfd1a9047f4044370c6375a79d7e2c7b2
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Jan 22 05:07:20 2014 +0000
+
+    rigol-ds: Fix divide by zero when no analog probes selected.
+
+commit 7d63347e9083648abd82bdeb49435ec1f7a98a44
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Jan 22 04:57:48 2014 +0000
+
+    rigol-ds: Stop capture cleanly on read errors.
+
+commit ae3a1913665dcdd721c88a46bc93c5e86747b519
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Jan 22 04:50:38 2014 +0000
+
+    rigol-ds: Improve protocol debugging output, abort on read errors.
+
+commit 2b399703d10dedfbed1f6b13070e0c3f5fd9938b
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Jan 22 04:49:57 2014 +0000
+
+    rigol-ds: Only protocol v3 adds trailing linefeeds to data blocks.
+
+commit a849c43a5070fce7b39d31383d4b370872e40a2b
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Jan 22 04:48:33 2014 +0000
+
+    scpi_usbtmc: Improve debugging output.
+
+commit 569d4dbd3e4c6cef0456c2afcc9a1e3d995d96ee
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Jan 22 04:08:00 2014 +0000
+
+    rigol-ds: Overhaul vendor/series/model info and protocol variants.
+
+commit e086b750fabe4247c5d88a37fa6927f907213d75
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Jan 22 00:25:32 2014 +0000
+
+    rigol-ds: Overhaul VS5000 and DS1000 support.
+    
+    This change moves the handling of series differences out to the points in the
+    code where they actually matter, unifying the overall structure of the code.
+    
+    It also adds new VS5000/DS1000 series equivalents for commands that were
+    previously only implemented on the later models.
+    
+    After this change, trigger waiting and the 'Memory' data source are supported
+    on the VS5000/DS1000 series.
+
+commit 38354d9d9eb7d63ee10ee42636b0ce0075536cf4
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Jan 22 00:22:41 2014 +0000
+
+    rigol-ds: Use common rigol_ds_config_set() function throughout.
+
+commit cf9f4bc5b0bf5ceef6ccfff7bdbf6b4ac2fd7486
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Jan 22 00:14:42 2014 +0000
+
+    scpi: Log responses received by sr_scpi_get_string().
+
+commit 32f09bfd9e2eaa6b909a672f779b74c53838120e
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Jan 23 01:09:16 2014 +0100
+
+    ols: Don't reduce sample count just because it's not a multiple of 4.
+
+commit 54da58ca9b9bde79d1b22e5254d7e396ff024fea
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Jan 22 02:44:52 2014 +0100
+
+    output/csv: Drop extra separator on every line.
+
+commit e96cf218c08d474fca0285113ad334823a60a3b9
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Jan 22 02:34:56 2014 +0100
+
+    output/csv: Get rid of 64-probe limit.
+
+commit 4829d37d6ad74c9368784b3cf3cae6f1a0a651c4
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Jan 22 01:14:26 2014 +0100
+
+    output/csv: Use new output API.
+
+commit 2b36d6c64e16c4b4efdffacd61d6fbc0c1b7ef91
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jan 21 18:25:50 2014 +0100
+
+    demo: Cycle through all available patterns for default analog probes.
+
+commit 03aa381efbb3fe3cb3fec8e7f2229b22bae58c56
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jan 21 18:19:57 2014 +0100
+
+    demo: Probe indexes should be unique, even if the types are different.
+
+commit eca2f8521333b7d259cc110e025d915b50aa384c
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jan 21 18:16:52 2014 +0100
+
+    Don't mention non-logic probes in session file metadata.
+    
+    They don't get saved anyway, and are very confusing to clients.
+
+commit 22c196883d50849ac3a6ed3bffa98e43b6155069
+Author: Martin Ling <martin-git at earth.li>
+Date:   Tue Jan 21 16:51:01 2014 +0000
+
+    rigol-ds: Disable key lock when closing device.
+
+commit 933e63a13bcedc7d4a003605449e54241e25f4eb
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jan 21 17:02:27 2014 +0100
+
+    brymen-dmm: Make protocol parser locale-independent.
+
+commit fe9d5abefcebb3a382d990e069d93c28e9541e35
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jan 21 16:43:49 2014 +0100
+
+    agilent-dmm: Make protocol parser locale-independent.
+
+commit 357e341d9a9e8f3834fe82c5ff4141f67c29d2d2
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jan 21 16:33:34 2014 +0100
+
+    fluke-dmm: Make protocol parsers locale-independent.
+
+commit d2cd06e7e96054973efe3b68565e66cdedeb5efe
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jan 21 14:47:05 2014 +0100
+
+    Make sure to delete temporary metadata file after use.
+    
+    Fixes bug 276.
+
+commit ac2926b37be8c569c5ca7f163a9219b08805fdd2
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jan 21 14:03:27 2014 +0100
+
+    std: Fix caller prefix output.
+
+commit 10d309c8abe03fa242409a6db398b4705cf6cf3d
+Author: Martin Ling <martin-git at earth.li>
+Date:   Tue Jan 21 02:23:38 2014 +0000
+
+    rigol-ds: DS1000 series still needs the stupid delay.
+
+commit 32b7cd4f02a8f84a860ee57911dd71191fc96987
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Mon Jan 20 23:04:49 2014 +0100
+
+    session: Auto-commit settings before acquisition.
+    
+    (sr_session_start): Just before starting acquisition on
+    a device, call sr_config_commit() to apply pending config
+    changes to the hardware device.
+    (sr_session_dev_add): Ditto.  Also, return an error code
+    if starting acquisition failed.
+
+commit 8dd0b290eb6ce6ebf9bde8b9a52785adb45b16f7
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jan 21 12:54:24 2014 +0100
+
+    rigol-ds: On DS1000 with firmware < 0.2.4, use legacy protocol.
+    
+    Apparently the ASCII header containing length was only added in version
+    0.2.4.
+
+commit fcdebbe89cca239c2270bea97ee709d26c51ae3b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jan 20 19:08:10 2014 +0100
+
+    rigol-ds: Shorten vendor name.
+
+commit 67d6f6fca2b85f2ef6a7e03383ebdcd2ce877eab
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jan 20 19:07:48 2014 +0100
+
+    agilent-dmm: Shorten vendor name.
+
+commit 6d16fdfb1328ba46edf0734b2b1ae62b1c26fb05
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jan 20 18:16:25 2014 +0100
+
+    ols: Add option to turn test patterns off again.
+
+commit 2a854d71392d2d22c59ec975ca11eb72ab81061d
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Sun Jan 19 20:39:11 2014 +0100
+
+    hwdriver: Introduce sr_config_commit() API call.
+    
+    (sr_dev_driver.config_probe_set): New optional callback enabling
+    drivers to be notified upon changes to probe settings.
+    (sr_dev_probe_enable, sr_dev_trigger_set): Invoke new driver
+    callback on changes.
+    (sr_dev_driver.config_commit): New optional callback allowing
+    drivers to defer application of configuration settings until
+    an explicit call to config_commit().
+    (sr_config_commit): New public wrapper function.
+
+commit 2b0e4a468a522770f27959d07efdd7b23e70a509
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sun Jan 19 23:28:40 2014 +0100
+
+    rigol-ds: add support for more keys in config_get()
+
+commit 72ecba02f44079e96a2708f3ac9ac847c85edb03
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sun Jan 19 23:26:26 2014 +0100
+
+    rigol-ds: use appropriately defined NUM_VDIV constant
+
+commit 8e06edf5282647deb9ddcc9ffad5bd6f94ae6f6a
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sun Jan 19 23:24:58 2014 +0100
+
+    rigol-ds: add more valid timebases for DS2302
+
+commit 889ef4a01cbf50d381cda0a1331b794a2c6d26c8
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sun Jan 19 14:46:59 2014 +0100
+
+    rigol-ds: fix set_cfg() calls with float parameters to avoid locale issues
+
+commit f76c24f6fdf09075a68197659df35eb1530e3004
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Jan 17 15:07:15 2014 +0000
+
+    rigol-ds: Send FRAME_BEGIN and FRAME_END per frame, not per channel.
+
+commit bac11aeb1b4f90e434ce05ee89ab1976a2a2b742
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Jan 17 14:46:10 2014 +0000
+
+    rigol-ds: Cleanup and fix check for short data blocks.
+
+commit 51bfe5363a89f7547810ed02868207a6f6be35b5
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Jan 17 14:22:09 2014 +0000
+
+    rigol-ds: Use *OPC? command rather than delay to await completion.
+
+commit 7788579e66d1bb7b3db8d3360c11f6407f596fee
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Jan 17 14:17:50 2014 +0000
+
+    scpi: Remove redundant newline removal in sr_scpi_get_hw_id().
+
+commit 334fbc2ac0ced005d558710e48ca660eaf9dcac5
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Jan 17 14:10:36 2014 +0000
+
+    rigol-ds: Use standard sr_scpi_get functions, remove internal versions.
+
+commit d03dfac6b9c07812c0b7b21858b247088d5605aa
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Jan 17 13:43:34 2014 +0000
+
+    scpi: Strip trailing newlines in sr_scpi_get_string().
+
+commit 470140fc0dff26e40000c8858c32dd84760df14a
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Jan 17 02:56:45 2014 +0000
+
+    rigol-ds: DS1000 series actually use IEEE488.2 data block format.
+
+commit d22250a96adbef6dbae44cd8e346cb5f31a3f872
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Jan 17 02:56:01 2014 +0000
+
+    rigol-ds: Correct digital waveform block sizes.
+
+commit 3ed7a40c753128d73875282cd318e1c8d96b360a
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Jan 17 02:27:29 2014 +0000
+
+    rigol-ds: Check SCPI read is complete after reading expected block length.
+
+commit 904fd29b7255958f499719f4b7f8f653596e33c6
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Jan 17 00:46:16 2014 +0000
+
+    rigol-ds: Update which channels are enabled after making changes.
+
+commit f0de2dd0fa67b61e755b04657b132282acc1c9a0
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jan 19 17:18:59 2014 +0100
+
+    Remove SR_CONF_MAX_UNCOMPRESSED_SAMPLES again.
+    
+    The maximum sample size that can be set on a device is now published
+    by sr_config_list(SR_CONF_LIMIT_SAMPLES). This returns a tuple of
+    uint64_t representing minimum and maximum number of samples.
+
+commit 9497f49ef8ce9136775c77386a79256806ee1c02
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Sat Jan 18 18:13:40 2014 +0100
+
+    sysclk-lwla: Improve message log output.
+    
+    Report settings at acquisition start as informational messages.
+    Print a message when the the trigger condition has been met.
+    Demote some other messages from information to debug, and use
+    the %zu format for printing size_t values.
+
+commit 2cfd16a31672be2ef8227dcda407e8cc5a24607f
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Sat Jan 18 17:36:23 2014 +0100
+
+    sysclk-lwla: Streamline packet output logic.
+    
+    (process_sample_data): When expanding run-length samples into
+    session packets, calculate the number of samples to write in
+    advance while honoring all constraints.  This is cleaner than
+    checking constraints within the expansion loop.  Also, the new
+    logic always fills up packets exactly to whatever limit applies
+    first, thereby removing the need for truncation after the fact.
+
+commit 29d587670df54e6dce281e942d1da0c0ee5a74f3
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Sat Jan 18 16:08:39 2014 +0100
+
+    sysclk-lwla: Implement SR_CONF_LIMIT_MSEC.
+    
+    Allow the acquisition to be constrained by time in addition to
+    a sample count limit.  Since the LWLA protocol actually provides
+    only a duration natively, implement the sample count limit on top
+    of the new duration limit.
+    
+    With this change, limiting an acquisition in external clock mode
+    should finally work properly.
+
+commit 17794067f96fd2b6f55b49bfcc2ce08e6edf57e5
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Jan 17 20:41:56 2014 +0100
+
+    tests: Fix a few warnings.
+    
+    Fix a bunch of "no previous prototype for ..." warnings exposed
+    by -Wmissing-prototypes.
+
+commit 2438b737ae644ce156d5ad808439358821234191
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Jan 15 01:51:04 2014 +0100
+
+    demo: Bring analog square wave amplitude into line with other patterns.
+
+commit 9f54e0e84f93ca4773994d4ee3c2cf3d8989790b
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Tue Jan 14 23:03:10 2014 +0100
+
+    demo: Add analog sawtooth pattern.
+
+commit 091c9621275fed7b0a418b644de46efec709d47b
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Tue Jan 14 23:03:09 2014 +0100
+
+    demo: Add triangle pattern.
+
+commit 4374219bc8c26997bb5c13c57f0babe3a61cd47e
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Tue Jan 14 23:03:08 2014 +0100
+
+    demo: Implement sine wave pattern.
+    
+    This adds sine wave generation capabilities for the analog channels in the demo
+    driver. The frequency of the sine wave depends on the configured sample rate of
+    the demo device. The frequency of the sine wave is always 20 times smaller than
+    the sample rate, in other words we always have 20 samples per period.
+
+commit e196cb6193421ec8de4f026a1bf22c14f623b3f3
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jan 17 12:11:52 2014 +0100
+
+    uni-t-ut32x: Fix typo that prevents usage with multiple devices.
+
+commit c2b394d56220de371280ff6e2b83559e1b1d27b6
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Jan 17 01:57:09 2014 +0100
+
+    rigol-ds: Minor whitespace fixes.
+
+commit 04e8e01ec6e5f293cde7d53e63fd29f0740af4a3
+Author: Martin Ling <martin-git at earth.li>
+Date:   Thu Jan 16 23:25:59 2014 +0000
+
+    rigol-ds: Enable/disable LA pod when (de)selecting digital channels.
+
+commit 51b294cd013db9d4d15f713c9ed576c343e685d6
+Author: Martin Ling <martin-git at earth.li>
+Date:   Thu Jan 16 18:57:45 2014 +0000
+
+    rigol-ds: Reset num_frames to zero in dev_acquisition_start.
+
+commit b751cf7a82ff04973e9525b42bb3e21ab88a1ab8
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Jan 15 17:06:46 2014 +0000
+
+    rigol-ds: Make sure to always send SR_DF_END at end of capture.
+
+commit 4914dd4b9a9e38b72aa351a0322e812c9d6a0384
+Author: Martin Ling <martin-git at earth.li>
+Date:   Tue Jan 14 21:27:58 2014 +0000
+
+    rigol-ds: Calculate effective samplerate.
+
+commit 5415e6024766fb9cd130782415eabcfe243bb3aa
+Author: Martin Ling <martin-git at earth.li>
+Date:   Tue Jan 14 21:21:31 2014 +0000
+
+    rigol-ds: Separate function to compute analog frame size.
+
+commit c1bcb8cc633cc69ce4a872f59ec2b686bc00bd04
+Author: Martin Ling <martin-git at earth.li>
+Date:   Tue Jan 14 20:55:20 2014 +0000
+
+    rigol-ds: Advertise SR_CONF_LIMIT_FRAMES support.
+
+commit 969edf63068d19260381274cfa4fecf6a390345b
+Author: Martin Ling <martin-git at earth.li>
+Date:   Tue Jan 14 20:48:17 2014 +0000
+
+    rigol-ds: Fix check for probe group validity.
+
+commit 55eb33dbf8cec9d7871187fe08d834180203b484
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Jan 17 00:37:58 2014 +0100
+
+    hameg-hmo: Fix two compiler warnings on Windows.
+    
+      CC       libsigrok_hw_hameg_hmo_la-protocol.lo
+    api.c: In function 'auto_find_usb':
+    api.c:70:39: warning: unused parameter 'vendor_id' [-Wunused-parameter]
+     static GSList *auto_find_usb(uint16_t vendor_id, uint16_t product_id)
+                                           ^
+    api.c:70:59: warning: unused parameter 'product_id' [-Wunused-parameter]
+     static GSList *auto_find_usb(uint16_t vendor_id, uint16_t product_id)
+                                                               ^
+
+commit dcc94340bd4c17f74c57a9ec9a2d8d9c1f06dd9f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Jan 17 00:26:30 2014 +0100
+
+    usb: Fix two compiler warnings on Windows.
+    
+      CC       libsigrok_hw_common_la-usb.lo
+    usb.c:241:18: warning: no previous prototype for 'usb_thread'
+    [-Wmissing-prototypes]
+     SR_PRIV gpointer usb_thread(gpointer data)
+                      ^
+    usb.c:256:13: warning: no previous prototype for 'usb_callback'
+    [-Wmissing-prototypes]
+     SR_PRIV int usb_callback(int fd, int revents, void *cb_data)
+                 ^
+
+commit c06c24d2d321c4adb2274402857b8811485c40ac
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Thu Jan 16 19:42:27 2014 +0100
+
+    hameg-hmo: Silence warning about format security.
+    
+    The command for fetching the sample rate while in single shot mode doesn't take
+    an argument so the snprintf here is redundant.
+
+commit ef1a346b0b69a6ef74c75f6eb61ac5742b67b5c2
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Thu Jan 16 19:55:00 2014 +0100
+
+    hameg-hmo: Reset the number of acquired frames in acquisition stop.
+
+commit ccf146182522391d6506dcb3944d305e8906101c
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Thu Jan 16 15:28:58 2014 +0100
+
+    hameg-hmo: Expose more options with config_get().
+    
+    This patch exposes the TRIGGER_SOURCE and COUPLING options via config_get().
+
+commit eff1ee0321166b7017765f91f5833fdf69e30d1b
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Thu Jan 16 15:28:57 2014 +0100
+
+    hameg-hmo: Advertise the frame limit option.
+
+commit 23e1ea7a7d862a8f5173dd12c62d6a4b2e7e9015
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Thu Jan 16 15:28:56 2014 +0100
+
+    hameg-hmo: Update the sample rate when the channel states or the timebase change.
+    
+    The sample rate on the Hameg scopes changes depending on the number of channels
+    turned on and on the current timebase.
+    
+    Update the sample rate if any of the above change.
+
+commit 14a2f74d9a5d696baab59cda426604f1750d17ba
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Thu Jan 16 15:28:55 2014 +0100
+
+    hameg-hmo: Add support for sample rate fetching.
+
+commit c09392d092f4b4c8d979b968bacb9f9056dc45e6
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Thu Jan 16 15:28:54 2014 +0100
+
+    scpi: Add CMD_GET_SAMPLE_RATE to the command enum.
+
+commit 8de2dc3b2e6ee1cb2df31db567e59f197623007c
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Thu Jan 16 15:28:53 2014 +0100
+
+    hameg-hmo: Change the way vdiv and timebase are saved.
+    
+    The current vertical division setting (per channel) and the timebase are stored
+    as a floating point number. This is suboptimal since clients expect us to send
+    this information to them in form of a rational number.
+    
+    Store only the index of the current setting since all the supported settings are
+    already stored inside of an array.
+
+commit 66e3219dbd086dc57087281f10fdefbe060ee5c8
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Thu Jan 16 15:28:52 2014 +0100
+
+    hameg-hmo: Send the DF_END packet in acquisition_stop()
+    
+    The DF_END packet was send out after all configured frames were fetched, but
+    devices may stop the acquisition at any point in time and an DF_END will not be
+    send out in this case.
+    
+    Send the DF_END packet inside of acquisition_stop() so this can't happen.
+
+commit 68e3d070144375fc01c54f0295a6c9acf726d9cc
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Thu Jan 16 15:28:51 2014 +0100
+
+    hameg-hmo: Close the device after initial scan.
+    
+    The device is after a scan left open and clients that don't call unconditionally
+    dev_open() will never fetch the initial device state.
+    
+    Close the device after the scan so clients know they need to open it.
+
+commit 965b463d9825c2a72a3a1cfcc10e1a23ccc768aa
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Thu Jan 16 15:28:50 2014 +0100
+
+    hameg-hmo: Handle floating point numbers while ignoring the locale.
+
+commit 13dbd151fee223b0cff563fbee81d31e786494e8
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Thu Jan 16 15:28:49 2014 +0100
+
+    scpi: Use sr_atof_ascii() instead of sr_atof().
+
+commit 9806c2d573a3fde4c26a38eaab265c7a78962e94
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Thu Jan 16 15:28:48 2014 +0100
+
+    strutil: Add function to parse floating point numbers while ignoring the locale.
+    
+    Most of the supported gear uses the ANSI C locale for communication, and if the
+    client sets up an incompatible locale parsing would fail.
+    
+    This function ignores the client's locale and parses floating point numbers
+    using the ANSI C locale. This function should be always used when parsing
+    floating point numbers coming from the instrument.
+
+commit 92b68bb5d6e5ca97990d223daaa3c74e4bbf4333
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Thu Jan 16 02:53:41 2014 +0100
+
+    device: Pass sdi as an function argument to config_list in dev_has_option()
+    
+    With drivers that support multiple devices we need to know the device model
+    while listing options. That information is most of the time saved in the private
+    part of the dev_inst structure.
+    
+    Pass the pointer to the dev_inst structure as an function argument so we have
+    access to this information.
+
+commit 580f309948b1540a32cb1fd787ae3599c68cae4b
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Thu Jan 16 02:53:40 2014 +0100
+
+    strutil: Correctly parse floating point frequencies in parse_size_string().
+    
+    parse_size_string() incorrectly parses a real number, e.g. 1.5 kHz ends up
+    being 1Hz.
+    
+    This patch fixes parse_size_string() to take the fractional part as well into
+    account. The fractional part is parsed as an double precision floating point
+    number while ignoring the locale.
+
+commit 0b92c32cb87f48d5f378b64c787a6f25b65915ad
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Wed Jan 15 11:09:06 2014 +0100
+
+    sysclk-lwla: Make use of the probe index again.
+    
+    (configure_probes): sr_probe::index has been un-deprecated,
+    so use it instead of relying on the list order.
+
+commit d02d475442d80ed7b51449526afd5c54ac843d1d
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Wed Jan 15 02:51:08 2014 +0100
+
+    sysclk-lwla: Bypass divider in external clock mode.
+    
+    (lwla_setup_acquisition): Set the clock divider bypass
+    flag to 1 for the external clock modes as well.
+    (capture_setup): Set the clock divide count to 0 if an
+    external clock source is selected.
+
+commit 313c7a7da20cb6d8e5e962844ed47d57460ff978
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Wed Jan 15 01:12:39 2014 +0100
+
+    sysclk-lwla: Utility functions clean-up and semantic fixes.
+    
+    (lwla_send_bitstream): Unref the mapped file earlier in order
+    to simplify the error handling.
+    (lwla_receive_reply): Do not treat a reply buffer length of
+    zero as silent no-op.  That logic was left over from an earlier
+    iteration, before the distinction between reply buffer size and
+    expected read length was introduced.
+
+commit 60e2fa0a03f689bf1e04f38e91473b8c231c4e26
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Wed Jan 15 00:59:08 2014 +0100
+
+    sysclk-lwla: Remove unused dev_context::next_state.
+
+commit 945e4343e2be4ad9e70e1a995182988b2331e0bd
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Wed Jan 15 00:52:26 2014 +0100
+
+    sysclk-lwla: Avoid warning due to bogus range check.
+    
+    (lwla_set_clock_source): Checking whether an enum value is greater
+    than or equal to zero apparently results in a warning with some
+    compilers.  Assign the enum to an unsigned variable to avoid this,
+    and return SR_ERR_BUG if the range is exceeded, as this indicates
+    a bug in the driver code itself.
+
+commit 9e2bf9d204d153de65dd98445d9d91819198196f
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Tue Jan 14 23:30:02 2014 +0100
+
+    configure: add -Wmissing-prototypes compiler option
+    
+    This should avoid introduction SR_PRIV functions when static would be enough.
+
+commit 8a2aaffa02d333219ba9159b581a2a7482e5185f
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Tue Jan 14 23:29:17 2014 +0100
+
+    remove unused static functions
+
+commit d87c1766f2968d121cea9d913b06dc3493adfd9e
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Tue Jan 14 23:16:55 2014 +0100
+
+    change a bunch of functions from SR_PRIV to static
+    
+    None of those functions are called across compilation units.
+
+commit 8162cad7e0727fc31d797afacfed4c23dd97aca0
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Tue Jan 14 23:38:23 2014 +0100
+
+    move function declarations to the appropriate header
+
+commit 2588e50c63d08245547e9947e67b4247f9102b19
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Tue Jan 14 23:24:47 2014 +0100
+
+    es519xx: add missing declarations for es519xx_2400_11b_altfn
+
+commit 365cca8aca560bdc3c5443a732e8d2620821a450
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Tue Jan 14 22:59:33 2014 +0100
+
+    gnuplot: proper error message when using gnuplot output without logic probe
+
+commit ad7621d4451cdd3c29f92c9c0e42428e92b4ba3a
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Tue Jan 14 22:56:55 2014 +0100
+
+    add udev rule for the Rigol DS2000 series
+
+commit 1f98295dfa0e303e05b0472cb025c03d3b0cb42b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jan 14 19:52:26 2014 +0100
+
+    sysclk-lwla: Fix probe name issue.
+    
+    The g_ascii_formatd() function expects the "format" argument to start
+    with a '%' character, e.g. it should be "%f" or such (this is not
+    clearly documented in the glib API docs, but visible from the source code).
+    
+    The usage of "CH%f" for example will trigger an assertion and thus make the
+    LWLA device unusable in practice (e.g. in PulseView on Windows no probenames
+    would be shown, and sampling wouldn't work).
+    
+    Example:
+      GLib-CRITICAL **: g_ascii_formatd: assertion 'format[0] == '%'' failed
+    
+    (not exposed in all glib versions or builds of glib on all distros
+    apparently, some may need G_MESSAGES_DEBUG=all or other measures)
+    
+    From the glib g_ascii_formatd() code:
+      g_return_val_if_fail (format[0] == '%', NULL);
+    
+    We now use g_snprintf() instead for simplicity. This has been tested to
+    fix this specific issue (i.e. the probenames now do show up in PulseView).
+    
+    This closes bug #270.
+
+commit 2379783d85a90bc2930f7eaff348c91b2d60d015
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jan 14 19:46:05 2014 +0100
+
+    configure.ac: Don't build sysclk-lwla if libusb-1.0 is not found.
+
+commit 87283d98c996db225444cf0c80e19099edb6fe61
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jan 14 19:36:28 2014 +0100
+
+    configure.ac: Move sysclk-lwla chunk to correct location.
+
+commit 7ebe9b9e7e8649fa592527d7cba2cf49804c3652
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Tue Jan 14 01:43:02 2014 +0100
+
+    sysclk-lwla: Honor SR_CONF_CONN at scan time.
+
+commit 8a3ddd8815aea40a2efd5987e754df1ec1322337
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Tue Jan 14 01:28:00 2014 +0100
+
+    sysclk-lwla: Fix calculation of the running sample count.
+    
+    Field 7 of the status response is actually a duration in
+    milliseconds at all samplerates but 125 MHz.
+
+commit 5874e88d83cabbec62e36c37e9016fab983d957b
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Mon Jan 13 22:57:59 2014 +0100
+
+    sysclk-lwla: Implement support for the LWLA1034.
+
+commit aeaad0b0b5db53f3d600359834b2738422feaeaf
+Author: Daniel Elstner <daniel.kitta at gmail.com>
+Date:   Mon Jan 13 22:49:55 2014 +0100
+
+    sysclk-lwla: Initial driver skeleton.
+
+commit bfaf112b689cba3ae5b3a73133fcdf7e45653550
+Author: Martin Ling <martin-git at earth.li>
+Date:   Tue Jan 14 18:25:08 2014 +0000
+
+    rigol-ds: Use correct digital channel numbers when fetching config.
+
+commit a4eb4b296da9818ffb04bb8023d43f6a006a81ca
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jan 14 00:05:24 2014 +0100
+
+    cem-dt-885x: Don't use char as signed type.
+
+commit 613c11084915ac24de9bd0355a7479ece9adfa35
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Tue Jan 14 00:17:44 2014 +0100
+
+    scpi: properly check for HAVE_RPC (which is always defined)
+
+commit d993d8d39d739d84f4927d251a826142a6a946a8
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Mon Jan 13 23:40:55 2014 +0100
+
+    rigol-ds: remove lonely break
+
+commit a31b2ccbd8db3716d2b13971a8519631e06727fa
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Mon Jan 13 23:38:32 2014 +0100
+
+    rigol-ds: prevent config_list() to return empty g_variant
+    
+    This fixes the following glib message:
+    $ ./sigrok-cli -d rigol-ds --show
+    [...]
+    g_variant_builder_end: assertion '!GVSB(builder)->uniform_item_types || GVSB(builder)->prev_item_type != NULL || g_variant_type_is_definite (GVSB(builder)->type)' failed
+
+commit 69d83be9bf4b6aa7e6cabdf5ce1b6452182fa55b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jan 13 22:22:40 2014 +0100
+
+    Use PRIu64 for format in pretty-printer.
+    
+    Thanks to Marcus Comstedt for the fix.
+
+commit 02820f07955badeb2da144a5cc678733a8fd4750
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Mon Jan 13 22:49:57 2014 +0100
+
+    rigol-ds: does not depend on libserialport
+
+commit a44a804bc6756605bcfbc3e9bff1066896303a9e
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Mon Jan 13 22:49:21 2014 +0100
+
+    scpi_usbtmc: does not depend on libserialport
+
+commit 138c0652f8a24b531ee2bec9a72d623431c48bca
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Mon Jan 13 12:54:24 2014 +0100
+
+    udev: Add the Rigol DG4000 series to the udev rules
+
+commit e22aa87808624c86ec52ea8d57d0a6f35c9e018e
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jan 13 02:10:11 2014 +0100
+
+    atten-pps3xxx: Fix options reporting.
+
+commit fe997353bf0c66425997bb84a0ad1041faf2a60e
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jan 13 02:05:39 2014 +0100
+
+    atten-pps3xxx: Fix output channel mode get.
+
+commit 2388ae860c369171d8728539ce2e9aab5810896b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jan 12 23:31:23 2014 +0100
+
+    demo: Properly handle logic vs. analog when setting the pattern.
+
+commit 7a1da33198c0c4d9f982a147e5a49a128446eca8
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jan 12 22:36:39 2014 +0100
+
+    demo: Split supported device options by probe group.
+
+commit dc3b3be5cb633695e700b895bc3d15deb83d722d
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sun Jan 12 18:46:24 2014 +0100
+
+    scpi_vxi: ensure the vxi link was properly opened before closing it
+
+commit 104ed125532596a43f2d95d9a5d05bd6d51b9afa
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sun Jan 12 00:38:08 2014 +0100
+
+    scpi_tcp: split into scpi_tcp_raw and scpi_tcp_rigol
+    
+    The current implementation is renamed to tcp-rigol as it seems to be
+    a Rigol proprietary protocol used only on Rigol VS5000 series.
+    
+    A new tcp-raw implementation is introduced which simply carries raw SCPI
+    commands over TCP. It is probably a much more common protocol and it is
+    at least available on Rigol DS2000 series on port 5555.
+
+commit f754c1469188a5e1a82c98532cb21b334530a91a
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sun Jan 12 00:05:02 2014 +0100
+
+    scpi: make the scpi_dev_inst_new more generic
+
+commit c3515cea44f7c3044fa56570e8d3225148c36a8f
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sat Jan 11 17:56:15 2014 +0100
+
+    scpi: factorize dev_inst_new calls out of individual drivers
+
+commit d5876cfb4a51140e449e37e35937795ad43368f7
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Thu Jan 9 23:44:35 2014 +0100
+
+    scpi: add VXI transport support
+
+commit c84b6ab81cfd7ac6b5cde43e6a50ac2dd3fdb520
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Tue Jan 7 23:28:28 2014 +0100
+
+    import VXI RPC Language description
+    
+    along with the corresponding rpcgen generated source code files
+
+commit 1c183900d2ee1416a0281871928e4064797ee528
+Author: Marc Schink <sigrok-dev at marcschink.de>
+Date:   Sat Jan 11 13:55:26 2014 +0100
+
+    configure.ac: Disable atten-pps3xxx driver if libserialport is not found.
+
+commit 45357ce64f07a3ac7d3faf99d9a0966694980e2e
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sat Jan 11 17:48:53 2014 +0100
+
+    std: use #ifdef rather than #if where the constant may not be defined
+
+commit ab988ecb237c6aa8510eaa4a53e4e3d1ba78fd9b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jan 10 02:10:51 2014 +0100
+
+    atten-pps3xxx: Push configured settings even without acquisition.
+
+commit 81c9e1a0647f3329eb61d2592e937051a17ecdd4
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jan 10 02:09:49 2014 +0100
+
+    atten-pps3xxx: Use configured values to construct packet.
+    
+    This used the values previously received from the device, not very useful.
+
+commit 33c40990fd099c3230fdac51f84a1be7ce2e88e7
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Jan 8 21:18:19 2014 +0100
+
+    atten-pps3xxx: Full support for the PPS3203T-3S.
+
+commit 471607f0244e93cd67097760431a0dd3d39152eb
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Jan 8 21:15:45 2014 +0100
+
+    Add config keys for programmable power supplies.
+
+commit fa0d6afe19c3a545f3f940933ed079966525d142
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jan 5 13:12:01 2014 +0100
+
+    atten-pps3xxx: Initial driver skeleton.
+
+commit 14563512ec720cbdfb792cff169d6bb4cde8ca6f
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Jan 9 16:28:29 2014 +0100
+
+    chronovu-la8: Publish SR_CONF_MAX_UNCOMPRESSED_SAMPLES.
+
+commit 0b9b3c41c2768c5fda73b3e38b3483278bcab202
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Jan 9 16:27:56 2014 +0100
+
+    ikalogic-scanalogic2: List all keys in device options.
+
+commit f649fe8f8e6e2406e5187bd19a8e6641358ae010
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Jan 9 16:26:58 2014 +0100
+
+    zeroplus-logic-cube: List all keys in device options.
+
+commit 67055d4c184c8ff1db5f296608ac5c77f80ac437
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Jan 9 14:30:20 2014 +0100
+
+    zeroplus-logic-cube: Publish SR_CONF_MAX_UNCOMPRESSED_SAMPLES.
+
+commit c2b988bd4a1986c15a0ffc8a38b3aa56d1a68c89
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Jan 9 14:00:53 2014 +0100
+
+    ikalogic-scanalogic2: Publish SR_CONF_MAX_UNCOMPRESSED_SAMPLES.
+
+commit 7730e4f002d6ae85fa2945e8a5752c639bfb0899
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Jan 9 13:08:32 2014 +0100
+
+    Add support for SR_CONF_MAX_UNCOMPRESSED_SAMPLES.
+
+commit d86e0b11c7dabcf8fbbb9f692a070f9679f0ea18
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Jan 9 12:36:05 2014 +0100
+
+    Add SR_CONF_MAX_UNCOMPRESSED_SAMPLES.
+
+commit a769b9f357f9f298f015664044ee6c48651affc2
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jan 7 12:52:23 2014 +0100
+
+    Add sr_session_save_init().
+    
+    This allows a frontend to initialize a session file, providing the
+    required samplerate and probe names, without having a proper
+    struct sr_dev_inst handy.
+    
+    sr_session_append() is then used to add captured data to the session
+    file, as usual.
+    
+    The existing sr_session_save() function works the same way as always.
+
+commit 311622f69e35a1c82d76ece9995daf14d94c191f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Jan 6 20:53:12 2014 +0100
+
+    serial-dmm: Drop unused DMM_COUNT.
+
+commit ec5186f9360f307ced6083137fc99f931aaae1a1
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Jan 6 20:44:44 2014 +0100
+
+    hardware/common/dmm: Fix debug output level.
+    
+    Most messages from the DMM parsers are not hard errors, lower to
+    sr_dbg() so that the sigrok-cli output doesn't get cluttered (by default)
+    with debug output such as:
+    
+     P1: 0.001100 V DC AUTO
+     sr: fs9721: Sync nibble in byte 0 (0x00) is invalid.
+     P1: 0.001100 V DC AUTO
+    
+    (using -l 4 or -l 5 will still allow the user to see such messages)
+
+commit 2710cb53fd4e56eb0ffe0b76657a67cce932c734
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Jan 6 18:08:55 2014 +0100
+
+    serial-dmm: Support the Tenma 72-7745 via UT-D02 cable.
+    
+    (it was already supported in uni-t-dmm via UT-D04 cable)
+
+commit d9e79c512289201a76e55435c09d7d7e68a1cf1b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Jan 6 17:20:35 2014 +0100
+
+    Add support for the Tenma 72-7750 (UNI-T UT60G rebadge).
+
+commit 4104ef810e56cd68ccfd66919a24e9e8c572ef58
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Jan 3 22:32:16 2014 +0100
+
+    Add initial support for the UNI-T UT60G.
+
+commit 1267f128acc0464d195abdb89de9c126259e7b83
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 4 00:18:29 2014 +0100
+
+    README.devices: Cosmetics, consistency fixes, updates.
+
+commit 48d3238e66bac0958fbec316db837aa3a8a1075a
+Author: Matthias Heidbrink <m-sourcetree at heidbrink.biz>
+Date:   Fri Jan 3 14:37:39 2014 +0100
+
+    serial: Improved docs.
+
+commit 8ae157d976d9825f77c46b1cfa9ecaeacad25436
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Fri Jan 3 17:50:16 2014 +0100
+
+    scpi_usbtmc: fix reading of blocks bigger than the 2048 bytes buffer
+
+commit a53278de01008e1ea04f06d6ae3a32de37d1797c
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Wed Jan 1 18:24:45 2014 +0100
+
+    rigol-ds: fix waveform reception on DS2000 series
+    
+    The ":WAV:DATA?" scpi command must be sent before calling
+    sr_scpi_read_begin().
+
+commit 036d378a628213f71afd24e9de475eacd592ca32
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Wed Jan 1 18:23:48 2014 +0100
+
+    rigol-ds: add a few more DS2000 models to the supported list
+
+commit 7142d6b9d5d65749e0cedfcff9025dffe38c76c2
+Author: Russ Dill <Russ.Dill at gmail.com>
+Date:   Mon Dec 2 23:29:04 2013 -0800
+
+    zeroplus: Add voltage threshold support
+    
+    It doesn't currently mesh well with libsigrok, but at least the support is there.
+
+commit 42ceb77726b6314fc999cf3664114820eaeddba9
+Author: Russ Dill <Russ.Dill at gmail.com>
+Date:   Mon Dec 30 07:12:49 2013 -0800
+
+    zeroplus: Major rework of sample buffer processing
+    
+    The sample buffer is a still a bit of a mystery, but this should help.
+    The variables in play:
+    
+    triggerbar/ramsize_trigger - These two variables added together indicate
+    how many samples we want captured. ramsize_trigger - triggerbar
+    indicades how many samples must be captured. The ratio between the two
+    is determined by capture ratio.
+    
+    memory_size - This indicates the number of samples in the circular
+    capture buffer. stop_address, now_address, and trigger_address are
+    pointers within the zeroplus that wrap based on this size.
+    
+    now_address - The address that the zeroplus was about to write to when
+    it finished capturing, and now the address that will be read from when
+    reads are done from the capture buffer
+    
+    stop_address - The address that the zeroplus last wrote to when it
+    completed capture.
+    
+    trigger_address - The sample address for which the trigger occured.
+    
+    status - This one is a bit tricky. Some testing has shown that if the
+    zeroplus has captured memory_size or less samples, the STATUS_READY bit
+    is set. For all captures generated with more samples than this,
+    STATUS_READY was cleared. However, boundary conditions are difficult to
+    test and values such as, memory_size + 1 have not been tested. We use
+    this to determine if the capture has wrapped through the sample buffer.
+    
+    More testing is required, but this improves behavior in a number of
+    cases, specifically capturing sample amounts that are not a power of 2
+    of the sample buffer size. Before, random data was passed to libsigrok.
+    
+    Signed-off-by: Russ Dill <Russ.Dill at gmail.com>
+
+commit a864a05b25d150214978f51e21b724d912648129
+Author: Russ Dill <Russ.Dill at gmail.com>
+Date:   Mon Dec 30 07:04:42 2013 -0800
+
+    zeroplus: Add getters for memory configuration
+    
+    This is needed at capture readback time to determine how many samples to read
+    in.
+    
+    Signed-off-by: Russ Dill <Russ.Dill at gmail.com>
+
+commit aad031928e5457ea8f7e4452401d55dcb8cb4cf1
+Author: Russ Dill <Russ.Dill at gmail.com>
+Date:   Tue Dec 31 16:25:51 2013 -0800
+
+    zeroplus: Modify analyzer_read_start to just prep for bulk reads.
+    
+    Let the capture loop manage which samples are thrown out rather
+    than throwing out two here.
+    
+    Signed-off-by: Russ Dill <Russ.Dill at gmail.com>
+
+commit bc059b42a26bbfa1d64bbf617abe4d440bdc57c5
+Author: Russ Dill <Russ.Dill at gmail.com>
+Date:   Mon Dec 30 06:59:55 2013 -0800
+
+    zeroplus: Always set DONT_CARE_TRIGGERBAR to 1
+    
+    Experimentation with the windows driver has found no situation where
+    this is set to anything other than 1. The zerominus software also never
+    sets this to anything other than one. Revert the code change made in
+    0ab0cb942f.
+    
+    Signed-off-by: Russ Dill <Russ.Dill at gmail.com>
+
+commit 4c1433d172e974f8b47ade71ef5e9557ba77a9f5
+Author: Russ Dill <Russ.Dill at gmail.com>
+Date:   Mon Dec 2 22:00:30 2013 -0800
+
+    zeroplus: Ignore capture ratio if there is no trigger
+    
+    If there is no trigger, don't try to capture anything before it. There
+    won't be any because we trigger immediately.
+    
+    Signed-off-by: Russ Dill <Russ.Dill at gmail.com>
+
+commit 05f853b5c3b8d1666ad1adecf5321c61801bda5e
+Author: Russ Dill <Russ.Dill at gmail.com>
+Date:   Mon Dec 30 07:05:17 2013 -0800
+
+    zeroplus: Add missing config_get for SR_CONF_CAPTURE_RATIO
+    
+    Without this, latest pulseview gets an assert and dies.
+    
+    Signed-off-by: Russ Dill <Russ.Dill at gmail.com>
+
+commit 5db0c668fa691f44be6caf173ad64b4765d06a29
+Author: Russ Dill <Russ.Dill at gmail.com>
+Date:   Mon Dec 2 21:25:10 2013 -0800
+
+    zeroplus: Support all 32 channels of 32 channel models
+    
+    This will need some additional work when support is added for compression
+    modes since group D is disabled for RLE compression and C and D are
+    disabled for "double" compression.
+    
+    Signed-off-by: Russ Dill <Russ.Dill at gmail.com>
+
+commit 1d4a28392800bde47c51334bea45060a45fd7450
+Author: Matthias Heidbrink <m-sourcetree at heidbrink.biz>
+Date:   Thu Jan 2 19:38:52 2014 +0100
+
+    gmc_mh_1x_2x: Fixed sign and AC/DC for current measurements with Metrahit <= 16.
+
+commit 124c548de85346ff7ff9c6776a963b911559faac
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Jan 2 14:25:06 2014 +0100
+
+    serial-dmm: Increase timeout when scanning for DMMs.
+    
+    We have to wait a bit longer than 1s for a valid DMM packet to arrive,
+    since for various DMMs some modes (Hz/% for example) the packets will
+    arrive a lot less often than in other modes. If the waiting period is
+    too short detection of the DMM will fail.
+
+commit 7fb5f0a0f5daf0666fded59abf8be63a7fcece46
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Jan 2 02:48:13 2014 +0100
+
+    serial-dmm: Drop obsolete function prototypes.
+
+commit d327972b9720b4c69b3aaca895416121757806e0
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Jan 2 01:34:21 2014 +0100
+
+    Add initial support for the V&A VA40B multimeter.
+
+commit 641d8f276ce52e84903a3d918187cf4d74c7dda4
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Jan 1 17:38:05 2014 +0100
+
+    output/analog: Add missing space (consistency).
+
+commit 79bc9924d70d6c785c3ab28d35ac67f4a3601e1d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Jan 1 16:40:36 2014 +0100
+
+    uni-t-dmm: Fix incorrect order which breaks UT61B/C.
+
+commit 7cb69b1870f507cf235e22463e9201427fb2f5d6
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Jan 1 15:25:39 2014 +0100
+
+    Add support for the UNI-T UT61B multimeter.
+
+commit 162a48bfc7e94598fb15911001f84f8b1c1bd77b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Dec 31 19:22:16 2013 +0100
+
+    teleinfo: Fix a compiler warning (clang).
+    
+      CC       libsigrok_hw_teleinfo_la-protocol.lo
+    protocol.c:62:41: warning: missing field 'num_samples' initializer
+          [-Wmissing-field-initializers]
+            struct sr_datafeed_analog analog = { 0 };
+                                                   ^
+
+commit 42f2f8a533e33ab77e737fbd880ef6e06bdb2b93
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Dec 31 19:21:04 2013 +0100
+
+    gmc-mh-1x-2x: Fix compiler warning (clang).
+    
+      CC       libsigrok_hw_gmc_mh_1x_2x_la-protocol.lo
+    protocol.c:133:32: warning: equality comparison with extraneous
+    parentheses
+          [-Wparentheses-equality]
+                            } else if ((devc->scale1000 == 2)) {
+                                        ~~~~~~~~~~~~~~~~^~~~
+    protocol.c:133:32: note: remove extraneous parentheses around the
+    comparison to
+          silence this warning
+                            } else if ((devc->scale1000 == 2)) {
+                                       ~                ^   ~
+
+commit 35b904a7924472522b1675427e9a630c2189a94f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Dec 31 19:20:51 2013 +0100
+
+    es519xx.c: Fix a few compiler warnings (clang).
+    
+      CC       libsigrok_hw_common_dmm_la-es519xx.lo
+    es519xx.c:632:33: warning: missing field 'is_voltage' initializer
+          [-Wmissing-field-initializers]
+            struct es519xx_info info = { 0 };
+                                           ^
+    es519xx.c:659:33: warning: missing field 'is_voltage' initializer
+          [-Wmissing-field-initializers]
+            struct es519xx_info info = { 0 };
+                                           ^
+    es519xx.c:688:33: warning: missing field 'is_voltage' initializer
+          [-Wmissing-field-initializers]
+            struct es519xx_info info = { 0 };
+                                           ^
+    es519xx.c:717:33: warning: missing field 'is_voltage' initializer
+          [-Wmissing-field-initializers]
+            struct es519xx_info info = { 0 };
+                                           ^
+    es519xx.c:746:33: warning: missing field 'is_voltage' initializer
+          [-Wmissing-field-initializers]
+            struct es519xx_info info = { 0 };
+                                           ^
+    es519xx.c:773:33: warning: missing field 'is_voltage' initializer
+          [-Wmissing-field-initializers]
+            struct es519xx_info info = { 0 };
+                                           ^
+    es519xx.c:800:33: warning: missing field 'is_voltage' initializer
+          [-Wmissing-field-initializers]
+            struct es519xx_info info = { 0 };
+                                           ^
+    7 warnings generated.
+
+commit 79a1176b3f027f0d29628d98a69c9e97864ed052
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Mon Dec 30 19:23:54 2013 +0100
+
+    fix endian neutral helper macro to return an integer type
+
+commit 264c99eda2084659492c18e0e7d0e662319053d9
+Author: Martin Ling <martin-git at earth.li>
+Date:   Mon Dec 30 04:00:41 2013 +0100
+
+    ols: Use serial source management wrappers.
+
+commit 9f5d4c3cc31bf6dd3ceac62dc8f5266c5f1189cf
+Author: Martin Ling <martin-git at earth.li>
+Date:   Mon Dec 30 03:54:55 2013 +0100
+
+    ols: Mark all serial calls as blocking or nonblocking.
+
+commit 9a47421157a3881265daef50ffd11df9f444d1d9
+Author: Martin Ling <martin-git at earth.li>
+Date:   Mon Dec 30 03:52:17 2013 +0100
+
+    Add blocking and nonblocking versions of serial_read and serial_write.
+
+commit cb410697fb0bab583624cb31db05185206c75bbb
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Thu Oct 3 23:35:33 2013 +0200
+
+    remove the es51922 protocol parser, superseded by the es519xx protocol parser
+
+commit d97824e52e3367115860b60c10a5dbb63187f032
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Thu Oct 3 23:30:18 2013 +0200
+
+    switch the UNI-T UT61E driver to the new es519xx parser
+
+commit 29bad967a437f3e14a01b043ccca483e890346bc
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sun Dec 29 17:15:42 2013 +0100
+
+    es519xx: correctly handle the VAHZ function
+    
+    This handles the frequency and duty cycle display in voltage or current mode.
+
+commit c3e871dc8e7df18a49a0ac244b86c9f8cb488c82
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sun Dec 29 17:14:37 2013 +0100
+
+    es519xx: apply the proper fixed factor in duty cycle mode
+
+commit e1f9f1e1f2c64e9501ba2ef79670b5e26f220ffe
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sun Dec 29 17:07:42 2013 +0100
+
+    es519xx: fix switching between frequency and duty cycle mode on 14 bytes chips
+    
+    Here is what the datasheet says about this:
+      "If judge bit is 1, it means frequency mode. If judge bit is 0,
+       it means duty cycle mode."
+    But this is plain wrong. Reality proves this is the other way around.
+
+commit 4d2630e63a6456ab84d0968fbd8f1c319f034c46
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sun Dec 29 17:04:19 2013 +0100
+
+    es519xx: correctly handle the voltage factor in diode mode
+
+commit a7c01629f6e96a79912977ed7262841cedf4ddfa
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sun Dec 29 16:59:30 2013 +0100
+
+    es519xx: fix continuity mode handling
+    
+    Depending on the chip, the limit value for the buzzer is between 25 and 35 Ω,
+    so this code set the limit for continuity to 25 Ω to be on the safe side.
+
+commit 5f985df23cb2a15d498d60fec8a4e5d14e38a7c0
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Dec 29 17:35:51 2013 +0100
+
+    Add support for the UNI-T UT61C multimeter.
+
+commit 683fd1613735d0e86c3b14c18b11d22492cee88a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Dec 29 14:17:10 2013 +0100
+
+    fx2lafw: Fix incorrect unitsize when a trigger fires.
+    
+    The unitsize was always being set to 2, regardless of whether an fx2lafw
+    device with 8 or 16 probes was used.
+    
+    This fixes bug #182.
+
+commit 87b545fba4d537a255dffcf2d8053908e3847480
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Dec 29 14:09:34 2013 +0100
+
+    fx2lafw: Minor cleanups.
+
+commit 0709197deb6cfb5189a2402df23bbda6961793ce
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Dec 29 13:20:09 2013 +0100
+
+    rigol-ds: Correct usage of NUM_TIMEBASE and NUM_VDIV config keys.
+
+commit bc7b7eb196b7e3f15bed857ee8b3533c0d899b3f
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Dec 29 13:13:04 2013 +0100
+
+    scpi: Strip trailing newline from *IDN response if present.
+
+commit b178c79d35be85a3980248061655f15ca2fa85f5
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Dec 29 12:33:10 2013 +0100
+
+    victor-dmm: Fix MIN/MAX always being reported.
+    
+    This fixes bug #228.
+
+commit 8b2d41edb3fe095a71f1cb416fff4abf1402a8c0
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Dec 27 23:52:23 2013 +0100
+
+    demo: Analog probe support.
+
+commit c07f60e73dba95479c96650a94db77c3639639ce
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Dec 24 11:27:40 2013 +0100
+
+    demo: User-configurable number of probes.
+    
+    The sigrok and incremental patterns repeat every 8 probes, shifted by
+    one probe.
+
+commit bf90d4c666cac50308577741e64d7cd42dbaad8d
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Dec 23 00:01:59 2013 +0100
+
+    Add config keys for setting the number of analog probes.
+    
+    This is primarily of use in the demo driver, but this patch also
+    takes in the logic probe setting config key used only by the
+    session driver so far.
+
+commit 3699a8a1ff68a2f5f781c6ae74946adc8bc82673
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Dec 29 10:57:38 2013 +0100
+
+    Skip analog probes in logic-only output formats.
+
+commit 05c644ea081f5973fcbb2429318b808b931edfe3
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Dec 29 02:36:49 2013 +0100
+
+    Revise SCPI read API to allow backend-independent data handling.
+
+commit b76eca818a66c5bb5b409c44e46ac0f5d851b0ce
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Dec 29 01:48:40 2013 +0100
+
+    Add udev rule for Agilent DSO1000 series.
+
+commit 227a0981c0da72df610306fe2eb4ca1cd26453f5
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Dec 29 01:39:49 2013 +0100
+
+    rigol-ds: Support the rest of the DSO1000 range.
+
+commit 821fbcadcc18c0e88fa7d78156dadae4aa466b89
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Dec 29 01:34:58 2013 +0100
+
+    rigol-ds: Support 4 analog channels.
+
+commit 0d9f5a12cb32758b739d4c816964d186fc6a8b54
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Dec 29 00:35:09 2013 +0100
+
+    rigol-ds: Use correct live waveform size for Agilent DSO1000 series.
+
+commit 10afee13a3a08b4852d4214bc6d9f0ff468b1ce6
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Dec 29 00:27:11 2013 +0100
+
+    rigol-ds: Add support for Agilent DSO1014A.
+
+commit 77c16c04639f0657bcb12e4b9f5201875f975b8a
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Dec 29 00:26:54 2013 +0100
+
+    scpi: Log IDN? result.
+
+commit 32c426d204e6133b19db486504beffd33a6f6548
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Dec 28 21:00:46 2013 +0100
+
+    Add config keys for upcoming RF demodulator drivers.
+    
+    Langford driver will be first.
+
+commit 07ccb2b3f1beda0f2bbb7cdbb830975b7bc739f2
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Dec 27 23:28:17 2013 +0100
+
+    rigol-ds: Fix rigol_ds_channel_start() for digital channels.
+
+commit 9e4b7d98337658d02a1789b0b8a11939eb6ef087
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Dec 27 23:24:40 2013 +0100
+
+    rigol-ds: Use correct analog frame size for VS5000 series.
+
+commit 6396b0a76bea8cf85f5501685bb77c776f0598a7
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Dec 27 23:19:55 2013 +0100
+
+    rigol-ds: Use set_cfg wrapper for capture setup commands.
+
+commit 1fed20cb387550e858a48a59a2c42e96b7b01541
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Dec 27 23:13:21 2013 +0100
+
+    rigol-ds: Select channels before issuing RUN command.
+
+commit 48460c6f3e46be7c60ab9ea5271ca773bce7d60e
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Dec 27 19:50:48 2013 +0100
+
+    rigol-ds: Unify partial read handling.
+
+commit f80a0bf232b19009dece9517542717d4ea087390
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Dec 27 18:56:59 2013 +0100
+
+    rigol-ds: Unify code for counting expected incoming bytes.
+
+commit 677f85d00bacfce05ad50ec2e9f6d7c47a761a43
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Dec 27 17:03:13 2013 +0100
+
+    rigol-ds: Use rigol_ds_channel_start() function for legacy protocol too.
+
+commit 0d87bd93eb5323b3bb325814a786efe3e336618d
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Dec 27 15:59:25 2013 +0100
+
+    rigol-ds: Rename and document some confusingly named variables.
+
+commit c36923b03b343bcdbda55e5167a36e1c63b527a7
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Fri Dec 27 17:29:03 2013 +0100
+
+    asix-sigma: fix incorrect pointer cast (non-aligned memory and endiannes issue)
+    
+    This fixes the following warning:
+    
+    asix-sigma.c: In function 'receive_data':
+    asix-sigma.c:1064:4: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
+        devc->state.lastts = *(uint16_t *) buf - 1;
+        ^
+
+commit 9ee78f234739be21bceb9caef1894dfaab39b8df
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Dec 27 17:27:52 2013 +0100
+
+    appa-55ii: Don't use _t suffix for a typedef.
+    
+    Names ending with _t are reserved for POSIX.
+    
+    http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html
+    (last line in table 2)
+
+commit 53cd1c78f56c533652c8bc15f6823f3e92303606
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Dec 27 16:00:25 2013 +0100
+
+    hameg-hmo: Support DC LINE coupling.
+
+commit df823ac4445ed6f708136e208c8b8bd4930f4a9e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Dec 27 16:18:28 2013 +0100
+
+    Doxygen fixes: Hide private stuff, document some structs.
+
+commit 00f24b9fd89e9edb34cf2cfd270020c8a40817be
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Dec 27 15:50:27 2013 +0100
+
+    Doxyfile/Doxyfile_internal: Ignore doxy/* when creating docs.
+
+commit 170fbcb3f769e89a9f1d1d2394986dbc5a78ec21
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Dec 27 15:36:22 2013 +0100
+
+    Doxyfile/Doxyfile_internal: Update to same 1.8.5 template, sync them.
+    
+    This also makes the diff from Doxyfile to Doxyfile_internal more readable.
+    
+    Also, put public API docs into doxy/html-api/, private stuff into
+    doxy/html-internal/.
+
+commit b95dd7619d2add244c3173cad4c5ac53849171bc
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Dec 27 13:05:54 2013 +0100
+
+    log prefixes: Cosmetics, consistency fixes, typo fixes.
+
+commit 3544f848e0d7f67af8e11ce7ec344b34cd797df3
+Author: Martin Ling <martin-git at earth.li>
+Date:   Mon Dec 23 03:38:35 2013 +0000
+
+    Centralise duplicated logging helper defines.
+
+commit dafafb0e9429fcc9185df1c861184ce79defb7ee
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Dec 27 00:35:42 2013 +0100
+
+    teleinfo: Minor cleanups.
+
+commit 76b4d4f422060718673da16fee6ab054d505ab7d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Dec 27 00:22:19 2013 +0100
+
+    appa-55ii: Minor cosmetics, whitespace fixes.
+
+commit 27fd2eaacb46c28c40dae8db6db762eb4e15aa60
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Dec 26 13:15:46 2013 +0100
+
+    gmc-mh-1x-2x: Use standard API callback names for now.
+    
+    If multiple functions need to be differentiated later, we can bring
+    back more specific names.
+
+commit 873e0c1295b78022ef95f7dd537fa2557f72c681
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Dec 26 13:02:02 2013 +0100
+
+    gmc-mh-1x-2x: Don't put driver-specific things in sr/SR namespace.
+
+commit 3a6095d0058bb9989ec393295ced1718bde96a69
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Dec 26 12:55:54 2013 +0100
+
+    gmc-mh-1x-2x: Use 'di' variable to match other drivers.
+
+commit ec29a878e0ca0b18969b00274744d0788234b54d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Dec 26 12:52:29 2013 +0100
+
+    gmc-mh-1x-2x: Fix two compiler warnings.
+
+commit fc348b770a2a9354cdf407f7501c5098b63e4bd7
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Dec 26 12:51:18 2013 +0100
+
+    gmc-mh-1x-2x: Cosmetics, whitespace, cleanups.
+
+commit 7574e58c1a9f2c9665d9680a8b02ac30f407cdbc
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Dec 23 01:53:30 2013 +0100
+
+    appa-55ii: Coding style fixes.
+
+commit 81a9ab725f9ce9125c9bc22bc5ebd2903c26bc35
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Thu Dec 12 00:22:32 2013 +0100
+
+    appa-55ii: driver implementation with Live and Memory data source support
+
+commit 5e7a8e57d4c042b4a4673e9f9cef19306a8b861b
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sun Dec 1 01:13:44 2013 +0100
+
+    appa-55ii: Initial driver skeleton.
+
+commit e28ef28a3c9a5cd2c86e4ab4de2516ab82d91082
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Thu Dec 12 00:20:47 2013 +0100
+
+    endian neutral helper macro to read 16/32 bits integer from unaligned memory
+
+commit f5027ca481d91fc92ec878d2eec2b6b446d3b7de
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Thu Dec 12 00:18:00 2013 +0100
+
+    add support for AVG mqflag
+
+commit 61c39f54bbcae7bdde86ddb11b2fd0ff308d319b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Dec 22 18:46:45 2013 +0100
+
+    demo: Code cleanup.
+
+commit 34ea7f9695794ea4654b26dd4aa6b79cdee90b71
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Dec 22 17:38:24 2013 +0000
+
+    Windows usb: don't try to resume thread if shut down in callback.
+
+commit 6640324f7f2730dc5a120af90a849b8d8fee52fa
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Dec 22 17:27:13 2013 +0000
+
+    usb: Enforce that there can only be one USB event source for now.
+
+commit b5328e1dfaf8a03ce503ab89abed0d83c58a7bb2
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Dec 22 17:10:57 2013 +0000
+
+    Windows usb: Unlock mutex when shutting down wait thread.
+
+commit 589edd9b81bce493de73075c9cdd6a5928ed3f59
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Dec 22 14:50:11 2013 +0000
+
+    Winsock2.h must be included before anything that includes Winsock.h.
+
+commit 5321ac6b5296cad499d6b27a8b3f04cef6611165
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Dec 22 07:16:56 2013 +0000
+
+    Implement usb_source_add and usb_source_remove for Windows.
+
+commit 6c60facc190a03c50aa66d4b1d17c825fec5d20e
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sat Dec 21 23:03:24 2013 +0000
+
+    Use common usb_source_add and usb_source_remove functions.
+
+commit ba1949f583de322e74f43eb880529155a763a84f
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Dec 20 17:45:46 2013 +0000
+
+    Use new libserialport event set API to make GPollFDs for serial sources.
+
+commit 17e9317b247844ac09539a20e76e9e2548d64b13
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Dec 19 10:45:36 2013 +0100
+
+    Bump minimum libusb version to 1.0.16
+    
+    This gets us the libusb version checking mechanism itself, hopefully
+    making this sort of thing easier in future.
+    
+    Also hotplug, device tree traversal, and lots of fixes.
+
+commit 95ecc765463462938200cf5cbcffba663f893c29
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Dec 19 00:31:26 2013 +0100
+
+    bbcgm-m2110: Minor cosmetics.
+
+commit 825da8b20f8eb879cd6b3e7911b4aa7b35a5b9ed
+Author: Matthias Heidbrink <m-sourcetree at heidbrink.biz>
+Date:   Wed Dec 18 23:37:42 2013 +0100
+
+    serial-dmm: Add BBC Goerz Metrawatt M2110 DMM driver.
+
+commit 5d03743096a1e850c6ccbb1eb902705a62604e80
+Author: Matthias Heidbrink <m-sourcetree at heidbrink.biz>
+Date:   Wed Dec 18 23:33:45 2013 +0100
+
+    serial-dmm: Commented struct dmm_info.
+
+commit e9a6213976eca51006e8459a5e3f062a88aee719
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Mon Dec 9 14:35:29 2013 +0100
+
+    hameg-hmo: Move the declaration of the driver info out of protocol.h
+    
+    This fixes duplicate symbol error on Mac OS X.
+    
+    BugLink: http://sigrok.org/bugzilla/show_bug.cgi?id=216
+
+commit cb7b165b3dc073c49729173132a37203e9d98838
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Dec 17 17:46:24 2013 +0100
+
+    serial.c: Show both error code and error message.
+    
+    This is helpful in many cases, e.g. when trying to identify which of the
+    16000 system error codes from
+    
+      http://msdn.microsoft.com/en-us/library/ms681381%28VS.85%29.aspx
+    
+    has been encountered (which is not trivial if you only have an,
+    e.g. German, string message alone).
+
+commit 2eb84c983584490153fe2bcbf10cc7ceaf46d033
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Dec 16 10:24:32 2013 +0100
+
+    Doxygen: Consistently use @ notation everywhere.
+
+commit 9d122af8f0c243278cc5edd79aae234aaa34984d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Dec 10 18:18:58 2013 +0100
+
+    Drop superfluous \n in some debug messages.
+
+commit a582788653a34479c1523290cb9343e445085d71
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Dec 10 17:39:31 2013 +0100
+
+    Fix a few #include guard names.
+
+commit 865730188c64765fd40fc45f28aed7fa5771550f
+Author: Martin Ling <martin-git at earth.li>
+Date:   Tue Dec 17 16:25:13 2013 +0000
+
+    python: Use OrderedDict for input formats.
+
+commit 772b21d42566f5ccf79075bfdf65a4e0e323f74b
+Author: Martin Ling <martin-git at earth.li>
+Date:   Tue Dec 17 16:10:08 2013 +0000
+
+    python: Split up Device class and add InputFileDevice class.
+
+commit 01e9ff61c2b32cd607c71c55b72b729851a19abc
+Author: Martin Ling <martin-git at earth.li>
+Date:   Tue Dec 17 13:11:43 2013 +0000
+
+    python: Give config keys an auto lowercase name if they have none defined.
+
+commit cad0acef5d21fefc4c5dd4c284d91f7be3f7deeb
+Author: Martin Ling <martin-git at earth.li>
+Date:   Tue Dec 17 13:01:35 2013 +0000
+
+    python: Add ConfigKey.info and ConfigKey.<id> shortcuts.
+
+commit 14e8eb33539dedf7760efff3165b3a0a1e09edbd
+Author: Martin Ling <martin-git at earth.li>
+Date:   Tue Dec 17 13:01:11 2013 +0000
+
+    python: ConfigInfo: return None from constructor if not available.
+
+commit 8593c8e30dcf9155d15b0bce7d943bf7fc82582d
+Author: Martin Ling <martin-git at earth.li>
+Date:   Tue Dec 17 12:47:49 2013 +0000
+
+    python: Add ConfigInfo and DataType classes.
+
+commit 409d85b3ac23c2915413c97354533f1d05f7dd9e
+Author: Martin Ling <martin-git at earth.li>
+Date:   Tue Dec 17 00:42:33 2013 +0000
+
+    python: Finish output format support.
+
+commit f0e764de7babf8004169732749040d9a2fc4ad71
+Author: Martin Ling <martin-git at earth.li>
+Date:   Mon Dec 16 02:11:42 2013 +0000
+
+    python: Finish input format support.
+
+commit a64198c8ea721c3a7867e9a753f1a761b89769c9
+Author: Martin Ling <martin-git at earth.li>
+Date:   Mon Dec 16 01:21:39 2013 +0000
+
+    python: Add initial support for input and output formats.
+
+commit 945e23a57dc5e639c96fd00294f735848f8d463e
+Author: Martin Ling <martin-git at earth.li>
+Date:   Mon Dec 16 18:09:57 2013 +0000
+
+    python: fix setting device/probe group configuration.
+
+commit 4e5c64e35855885987b065e5923d0339d818680b
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Dec 15 20:02:05 2013 +0000
+
+    python: whitespace fix.
+
+commit 5f9c4c8a34e6c1d122d36efd2e8263f0456541bd
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Dec 11 10:49:01 2013 +0100
+
+    Detect non-existent file before libzip does.
+
+commit 1e7134dc8cff3f28a312e41c997ed488fb071e96
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Dec 11 00:33:11 2013 +0100
+
+    std: Don't build serial helpers without libserialport present.
+
+commit 98582bf53f61043e6918be291648f8f6dfb5f6b4
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Dec 9 22:49:12 2013 +0100
+
+    Make API docs more consistent, avoid tabs to line up comments.
+
+commit 5483bb8349d361be62ae5197b871afa6c8520c36
+Author: Matthias Heidbrink <m-sigrok at heidbrink.biz>
+Date:   Fri Nov 22 21:08:49 2013 +0100
+
+    doxygen: Created Doxyfile_internal to extract „everything“ that is possible into a separate directory doxy/html-internal.
+
+commit 04cb915716ecdc1ee26440b4c09bc2f2de183631
+Author: Matthias Heidbrink <m-sigrok at heidbrink.biz>
+Date:   Fri Nov 22 20:40:52 2013 +0100
+
+    Improved doxygen docs.
+
+commit 86fa0ef594dbe6492eb781d5b7f17722edbbf586
+Author: Matthias Heidbrink <m-sigrok at heidbrink.biz>
+Date:   Fri Nov 22 14:08:04 2013 +0100
+
+    doxygen: Updated Doxyfile to doxygen 1.8.5.
+
+commit 854434de0bc581f16f87f85595f473ee41ca9e0c
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Dec 7 21:36:27 2013 +0100
+
+    Use std_serial_dev_open().
+
+commit 23dc6661667b05a91b01ab6a6fa425aa57af6daf
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Dec 7 20:26:15 2013 +0100
+
+    std: Add std_serial_dev_open().
+
+commit d43b090816f61e77d8054084e85202de1a1ebeb7
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Dec 7 20:39:55 2013 +0100
+
+    std: Standardize function name.
+    
+    std_dev_acquisition_stop_serial() is now std_serial_dev_acquisition_stop().
+
+commit 37fa80b4be4808958340b56dc62265e2d4f14e85
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sat Dec 7 19:42:35 2013 +0000
+
+    Disable OLS driver on Windows.
+
+commit b6eb8252e545f358d359d4aa7a01073f10f1cd00
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sat Dec 7 19:35:50 2013 +0000
+
+    Remove now-unused fd field from struct sr_serial_dev_inst.
+
+commit bf72f649999a6e8741ffee1ca2850db4d478f9f8
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sat Dec 7 19:35:13 2013 +0000
+
+    ols: Get fd from sp_get_port_handle() rather than serial struct.
+
+commit 64ecf7ee52aecdf225f4e45240025a4a734e351a
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sat Dec 7 19:29:16 2013 +0000
+
+    Eliminate internal usage of serial->fd in serial.c.
+
+commit a0a4c0fb09cac1105ad03325d7232a8f492f181c
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sat Dec 7 19:19:20 2013 +0000
+
+    Use sp_get_port_handle to get an fd for adding/removing serial sources.
+
+commit af473e0eb2db5475bdc1da6a87edb828d163c015
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sat Dec 7 19:17:49 2013 +0000
+
+    brymen-dmm: Use port name instead of fd in debug message.
+
+commit 6936af3292b6a76a4ef5521fd8ea752333f13ae8
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sat Dec 7 19:16:30 2013 +0000
+
+    Use sdi->status instead of serial->fd to tell if port needs closing.
+
+commit bf2c987fdef6787a5ce826ed9d98a70f52a1ff96
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sat Dec 7 18:47:43 2013 +0000
+
+    Use std_serial_dev_close() to replace matching dev_close functions.
+
+commit 043e899a5155dcdc353abc20006424973d8e2ed0
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sat Dec 7 18:41:09 2013 +0000
+
+    Add std_serial_dev_close() function.
+
+commit 7faa3e8821735e063e17fcad326c68aae14fe907
+Author: Martin Ling <martin-git at earth.li>
+Date:   Mon Dec 2 13:06:08 2013 +0000
+
+    Route sr_source_remove for all serial devices through a wrapper.
+
+commit abc4b3356d184401cb62aaa521d1c80ebd7d6f0f
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sat Nov 30 12:54:02 2013 +0000
+
+    Route sr_source_add for all serial devices through a serial_source_add wrapper.
+
+commit b4936bae0a4b2e8527324416faf81704e53216d2
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sat Dec 7 17:54:33 2013 +0000
+
+    rigol-ds: close SCPI device after using for scan.
+
+commit 721fc2272ea1e7f3036eca570380bafe40146859
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sat Dec 7 16:11:27 2013 +0000
+
+    scpi_serial: Iterate serial_write as necessary to send full commands.
+
+commit bb9d6116f828c4790334d98c65414dcef660d169
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Dec 7 18:50:12 2013 +0100
+
+    filter.c: Work around const warning.
+
+commit 764e7bbfec52f0530f1f965879b0d81a7fc9acb2
+Author: Marcus Comstedt <marcus at mc.pp.se>
+Date:   Sat Dec 7 17:09:06 2013 +0100
+
+    filter.c: Fix endianness bug in sr_filter_probes
+
+commit c1e45c6511eb4e9023095fc364913db85a092651
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Dec 7 15:50:25 2013 +0100
+
+    Minor whitespace fix.
+    
+    Really just for testing some git hooks.
+
+commit c3e2b08dc9a252ada9b9a51ae47ea588135944e1
+Author: Marvin Schmidt <marv at exherbo.org>
+Date:   Tue Nov 26 08:50:52 2013 +0100
+
+    Fix test failure
+    
+    The GError object has to initialized to NULL before being passed to
+    g_file_set_contents or it will throw the following critical warning
+    
+    GLib-CRITICAL **: g_file_set_contents: assertion 'error == NULL || *error == NULL' failed
+    
+    and return FALSE, which leads to failed assertion and subsequently
+    to the test failing
+
+commit 0f4a4350579604c874e1ad4b741f9b059f3585f3
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Dec 6 03:20:48 2013 +0000
+
+    scpi_tcp: must define _WIN32_WINNT to 0x0501 or higher to get getaddrinfo().
+
+commit 1c6736ab862815db0530cb01ba83e1556e2a55d8
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Dec 6 02:26:58 2013 +0000
+
+    Link against the ws2_32 library on Windows.
+
+commit 789840741cc680908754531a3fcb59d313276677
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Dec 6 01:55:04 2013 +0000
+
+    rigol-ds: Enable for non-Linux, as it now supports other transports.
+
+commit 987a053084b521f3f2af7beb2da68a24a24da363
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Dec 6 01:14:55 2013 +0000
+
+    scpi_tcp: Fix building on Windows.
+
+commit b9a5614dbf88d0046e4c1f22e1b8b7666c4f52f8
+Author: Russ Dill <Russ.Dill at gmail.com>
+Date:   Mon Dec 2 22:00:30 2013 -0800
+
+    zeroplus: Rework triggerbar/trigger address logic
+    
+    This reworks the triggerbar/trigger address logic to match the values sent
+    by the windows app for all models (The zerominus tool was used to reprogram
+    the USB device ID on a single device). Additionally, the DONT_CARE_TRIGGERBAR
+    register is always set by the windows app and does not seem to indicate that
+    these registers are "don't care"'s.
+
+commit c38e64c7425aaf82f8a49b702cae764c403d2acd
+Author: Russ Dill <Russ.Dill at gmail.com>
+Date:   Mon Dec 2 21:57:46 2013 -0800
+
+    zeroplus: Clip sampling sizes larger that our sample memory
+    
+    Otherwise, we'll return a non-sensical result for our memory_size
+    enumeration.
+
+commit 3e43da1f70d48aba917026074d46ca4c91e43bf1
+Author: Russ Dill <Russ.Dill at gmail.com>
+Date:   Mon Dec 2 21:57:04 2013 -0800
+
+    zeroplus: Add support for additional memory sizes
+    
+    The zeroplus can have up to a 8M SRAM. Avoid some extensive if/else
+    blocks by noting that all sizes except the first are related by their power
+    of 2.
+
+commit e93fb98b8ab4f9aea905c027b69d08ceb64befc5
+Author: Russ Dill <Russ.Dill at gmail.com>
+Date:   Mon Dec 2 21:51:53 2013 -0800
+
+    zeroplus: Rename max_memory_size to max_sample_depth
+    
+    This private variable is measured in samples, not bytes. Avoid confusion
+    by renaming it.
+
+commit d20844e28b82704aaf0a5929d7078f57b6c59f5a
+Author: Russ Dill <Russ.Dill at gmail.com>
+Date:   Mon Dec 2 21:47:14 2013 -0800
+
+    zeroplus: Just wait until not busy on data capture
+    
+    While captures using a trigger do set the STATUS_READY bit, immediate
+    captures do not set the STATUS_READY bit, they just clear the STATUS_BUSY
+    bit. This was confirmed with packet captures using the "official" driver/app.
+
+commit 60cc6f85795315d3257a55cc257bdc3e511b6f45
+Author: Russ Dill <Russ.Dill at gmail.com>
+Date:   Mon Dec 2 21:25:10 2013 -0800
+
+    zeroplus: Add usb IDs for 32 channel models, but only use 16 channels
+    
+    The code needs some work to support 32 channels. Until then, support
+    the 32 channel models, but only allow the use of 16 channels.
+
+commit 7cf1a98d733b97656ef1b28259d5cd2b4190a104
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Dec 5 00:21:15 2013 +0100
+
+    rigol-ds: Minor error reporting fix.
+
+commit 91e406b9210b2b2c009e9ef8662d2634e5b6e997
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Dec 5 00:16:11 2013 +0100
+
+    scpi/usbtmc: Prototype fixes.
+
+commit bc03a7cc2ccadeb5951525fae708bd3f840836b0
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Dec 5 00:09:34 2013 +0100
+
+    scpi/serial: Use stubs for all SCPI functions.
+    
+    Avoids some gcc warnings, since the SCPI prototypes don't exactly
+    match serial_*.
+
+commit 962af1a379f2c1715b22f0779ed3ebc6f0d8c2ec
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Dec 4 21:38:05 2013 +0000
+
+    rigol-ds: Support VS5000 series devices.
+
+commit b8705e99e45224941d43f10438d69726d8f2d85b
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Dec 4 21:32:47 2013 +0000
+
+    scpi_tcp: Adjust to observed protocol for Rigol VS5000 series.
+
+commit 3520422fc761d50830a45a43cd7d34cca589ad1b
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Dec 4 20:42:22 2013 +0000
+
+    rigol-ds: Support TCP connection.
+
+commit 08a359138b3e363ecbba6396a939c48eeab31f92
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Dec 4 20:23:14 2013 +0000
+
+    Add implementation for SCPI over TCP.
+
+commit 56868b5d6b7401f3916df1468b537bd0d04087f5
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Dec 4 13:08:49 2013 +0000
+
+    rigol-ds: Handle partial analog frame reads.
+    
+    Reading a frame over the DS1xx2 RS232 connection now sometimes works,
+    but most of the time stalls part way through with g_poll showing the
+    fd as not ready.
+
+commit 9dfeb81b09377cd5413c7ccd448fca2e77615084
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Dec 4 13:03:23 2013 +0000
+
+    scpi_serial: Flush buffers after opening port.
+
+commit 0dc7b43eb77865aae515039734d76d27ad156c6e
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Dec 4 12:49:38 2013 +0000
+
+    rigol-ds: Support RS232 connection.
+    
+    Probing tested OK over RS232 for DS1052E and DS1102D. Capture needs work.
+
+commit 4d7a9a14a3cfeb4cba2a9996ac1e11d9cecf70fa
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Dec 4 10:55:32 2013 +0000
+
+    rigol-ds: Eliminate fixed-size buffer in set_cfg.
+
+commit 87c410830d9967d9eea73ae18bef12e668b94e92
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Dec 4 10:53:51 2013 +0000
+
+    Add sr_scpi_send_variadic() function.
+
+commit 17b5b202640c1ea5de09b0685a5ed6635f2e06df
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Dec 4 10:25:15 2013 +0000
+
+    Replace rigol_ds_send() function with sr_scpi_send().
+
+commit 504f40a5749b34f2d0932868188e7d94da929be4
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Dec 4 10:24:52 2013 +0000
+
+    Make sr_scpi_send() take printf-style arguments.
+
+commit 1ef513807124f5c3f3706896fa943e9adf10ef30
+Author: Martin Ling <martin-git at earth.li>
+Date:   Tue Dec 3 23:31:32 2013 +0000
+
+    Only scpi_serial.c functions need HAVE_LIBSERIALPORT, not scpi.c.
+
+commit 4b4474ed6a4701e28961569eb777052d0b74673d
+Author: Martin Ling <martin-git at earth.li>
+Date:   Tue Dec 3 23:29:20 2013 +0000
+
+    Remove SR_INST_USBTMC which is no longer used.
+
+commit ae1bc1cc2631f5d56cdffb4d4426f0c2bdd30500
+Author: Martin Ling <martin-git at earth.li>
+Date:   Tue Dec 3 23:19:40 2013 +0000
+
+    Port rigol-ds driver to use common SCPI functions.
+
+commit a1ff9c1897262faa3b284ea5bb82593c45de70d0
+Author: Martin Ling <martin-git at earth.li>
+Date:   Tue Dec 3 22:56:32 2013 +0000
+
+    Add sr_scpi_read() operation for reading arbitrary data.
+
+commit 31034792da84daa5163b7d72bb98664c65aa7cc0
+Author: Martin Ling <martin-git at earth.li>
+Date:   Tue Dec 3 22:25:33 2013 +0000
+
+    Implement SCPI over USBTMC.
+
+commit 23f43dff15abf5202d81f36e062b0ae5b0ca01cd
+Author: Martin Ling <martin-git at earth.li>
+Date:   Tue Dec 3 20:40:19 2013 +0000
+
+    Make SCPI functions device independent, with separate serial backend.
+
+commit 8d558c7a9fd96f60077fc2b176576846f5089110
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Dec 3 17:16:59 2013 +0100
+
+    strutil.c: Don't expose sr_atox() as API calls for now.
+
+commit 082972e8c5deb48eba5c2b558e451dea1005e23f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Dec 3 17:13:50 2013 +0100
+
+    hameg-hmo: Reduce unnecessarily high nesting level.
+
+commit 719eff68ad03b4acaea87e227eda361ef2e299be
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Dec 3 16:58:34 2013 +0100
+
+    hameg-hmo: Use hmo_ prefix for driver-local SR_PRIV functions.
+
+commit 89280b1a4c0675b1383ccc6a5a63e8a2a6add05e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Dec 3 16:48:21 2013 +0100
+
+    hameg-hmo: Minor cosmetics, coding-style fixes.
+
+commit d5976d8be5ee72a89e82b4a3baeae6eba48a8d3a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Dec 3 16:08:59 2013 +0100
+
+    scpi.c: Minor cleanups, cosmetics.
+
+commit c6e35004cb7b5de7c2e9cff785d08589daf96e7e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Dec 3 15:48:02 2013 +0100
+
+    configure.ac: Don't build hameg-hmo if libserialport is not found.
+
+commit 582b3d21d39526b602f3611ae0082eacfad8e11e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Dec 3 15:37:36 2013 +0100
+
+    configure.ac: Move Hameg HMO AM_CONDITIONAL to the correct place.
+
+commit 13f2b9d789fdc7130c0f31b88319bd0f3445109a
+Author: poljar (Damir Jelić) <poljarinho at gmail.com>
+Date:   Fri Oct 25 18:15:00 2013 +0200
+
+    hameg-hmo: Add initial working driver version.
+    
+    This patch adds initial support for Hameg's HMO oscilloscopes. It currently
+    supports only the HMO compact series (70MHz-200MHz).
+
+commit 06a3e78adb41974ed759b39812ba1f83fd21a5aa
+Author: poljar (Damir Jelić) <poljarinho at gmail.com>
+Date:   Tue Oct 15 20:45:14 2013 +0200
+
+    hameg-hmo: Initial driver skeleton.
+
+commit 1bd9e678ac2c00c4b6336ed2506c28cdcfe3a25c
+Author: poljar (Damir Jelić) <poljarinho at gmail.com>
+Date:   Fri Oct 25 18:13:20 2013 +0200
+
+    serial: Add function to extract serial options.
+    
+    This patch adds a function for a common operation of all serial based drivers.
+    It extracts the serial options from the options linked list that is passed down
+    to every hardware driver.
+
+commit 1a323dd887e655ac76133af1f018e3eeabd174e2
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Mon Nov 18 16:13:12 2013 +0100
+
+    scpi: Add function to fetch uint8_t.
+    
+    This patch adds a function to read and parse a SCPI response which contains a
+    comma separated list of unsignet 8-bit integer numbers (e.g "1,0,64").
+    
+    This is particularly useful if the instrument sends digital measurement data
+    in this format.
+
+commit 8acbb89a1dd38f15e53c5a46c226c074db5c4efa
+Author: poljar (Damir Jelić) <poljarinho at gmail.com>
+Date:   Fri Nov 1 20:40:04 2013 +0100
+
+    scpi: Add function to get an array of floats.
+    
+    This patch adds a function to read and parse a SCPI response which contains a
+    comma-separated list of floating-point numbers (e.g. "1.0e-5,2.0e-4,3.0e-3").
+    
+    This is particularly useful if the instrument sends analog measurement
+    data in this format.
+
+commit f5922adef5a866bd1c292436f1c4bc6b93103aef
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Sat Nov 9 12:49:08 2013 +0100
+
+    scpi: Add a function to read and wait on a *OPC? reply.
+    
+    The SCPI standard specifies the "*OPC?" command (Operation complete query) which
+    queries the instrument for its operative state. When all pending operations are
+    complete, the instrument responds with a "1".
+    
+    Some manufacturers block before completing all operations and don't respond
+    with anything and some of them respond with a "0". This function handles both
+    cases uniformly.
+
+commit d730f70e06653c60d65c668cce02f358decce991
+Author: poljar (Damir Jelić) <poljarinho at gmail.com>
+Date:   Fri Nov 1 19:27:44 2013 +0100
+
+    scpi: Add more functions (getting int/bool/float/double).
+    
+    This patch adds helper functions to read an SCPI response and parse the response
+    as an integer, boolean, floating-point or double-precision floating-point number.
+
+commit aa1e3b400b95b7f16716bfd65a2ebbf870e42fa5
+Author: poljar (Damir Jelić) <poljarinho at gmail.com>
+Date:   Fri Nov 1 19:25:32 2013 +0100
+
+    scpi: Add function to strictly parse bool strings.
+    
+    This patch adds a function that is similar to sr_parse_boolstring but its
+    matching rules are more strict.
+
+commit 7b9d73203163daa70273f0adfa854a1dc01f08f0
+Author: poljar (Damir Jelić) <poljarinho at gmail.com>
+Date:   Tue Oct 29 12:15:47 2013 +0100
+
+    scpi: Add helper functions for SCPI communication.
+    
+    The Standard Commands for Programmable Instruments (SCPI) defines a standard
+    for syntax and commands to use in controlling programmable test and measurement
+    devices.
+    
+    SCPI documentation:
+    	http://www.ivifoundation.org/docs/scpi-99.pdf
+    
+    This patch adds helper functions for sending SCPI commands, reading a SCPI
+    response and reading and parsing a SCPI "*IDN?" response.
+
+commit 9e4f8cf93b465fb34b35b083935f45ba5427045e
+Author: poljar (Damir Jelić) <poljarinho at gmail.com>
+Date:   Fri Nov 1 18:40:06 2013 +0100
+
+    strutil: Add helper functions: string to number.
+    
+    This patch adds helper functions for converting a string to different number
+    formats (double, long, float, int).
+    
+    These functions are exposed in the public API.
+
+commit 3ba7b61ab23ff61f112206601b8a57a5c5545ae3
+Author: Dan Horák <dan at danny.cz>
+Date:   Sun Dec 1 22:07:18 2013 +0100
+
+    define correct variable for the unified Rigol driver
+
+commit 66a435766721dd6ecdbce7b31a2f43c2e0752a12
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Dec 1 19:30:35 2013 +0100
+
+    serial-dmm: No error message upon 0 new bytes.
+
+commit 9647ce694b1f76cc7196420bb9932e4ff6c8b349
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Nov 27 01:43:49 2013 +0000
+
+    Use new libserialport blocking/nonblocking API calls.
+
+commit 016f2e005ddbc604594c863dca8a89212bf46a5c
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Nov 29 17:32:55 2013 +0100
+
+    Fix memory leak when loading session files.
+
+commit b3916147a505681a9c9612bbc2261c281d57b576
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Nov 29 01:40:50 2013 +0000
+
+    rigol-ds: Fix duplicated "LA" probe group.
+
+commit ae67644fe5340d9c6e450fb0443178af356e0647
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Nov 29 00:48:42 2013 +0000
+
+    Create & use new sr_usbtmc_dev_inst for Rigol DS driver.
+
+commit babab6225b44eeeb73aa62e281d50636ec170bd5
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Nov 29 00:14:54 2013 +0000
+
+    DS2000 sample memory capture patches from Mathias Grimmberger.
+
+commit 355de5a1101076d29c8d1c223c1b07b2bb6b06b3
+Author: Martin Ling <martin-git at earth.li>
+Date:   Thu Nov 7 23:13:30 2013 +0000
+
+    Fix handling second channel on DS2000 series.
+    
+    Patch from Mathias Grimmberger.
+
+commit 6ff1394ed1be4700123e9c6165128eb39f294648
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Nov 1 21:49:05 2013 +0000
+
+    rigol-ds: brown paper bag, using timebases instead of vdivs.
+
+commit 7cc1a55091fc06c1c616c8d11c42abeb412cb994
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Nov 1 21:32:33 2013 +0000
+
+    rigol-ds: fix calls to config_list with NULL sdi/devc.
+
+commit bafd489094c42e626ee0b1964893a308751c50b7
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Nov 1 11:05:49 2013 +0000
+
+    rigol-ds: Add support for DS2xx2 series.
+    
+    Based on patch by Mathias Grimmberger <mgri at zaphod.sax.de>.
+
+commit 3086efdd73885820da142ce8c36053bbc3cf0e5f
+Author: Martin Ling <martin-git at earth.li>
+Date:   Thu Oct 31 17:31:39 2013 +0000
+
+    Rename rigol-ds1xx2 driver to rigol-ds.
+
+commit 6c57446d415dfb21bea448513bd61a17867a64f8
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Nov 26 22:20:30 2013 +0100
+
+    Don't accept over 64 probes.
+    
+    The code is limited to 64 probes for now, so don't accept setting
+    the probe limit to higher than that.
+    
+    See bug 194.
+
+commit e4c8a4d7cb00c26d55a8600011ab22a33d4ab95a
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Nov 26 22:11:48 2013 +0100
+
+    input/vcd: Coding style fixes.
+
+commit 34539700795f6ef4879105818cf8ed4e7336d6c1
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Nov 26 16:59:04 2013 +0100
+
+    output/csv: Fix wrong cast.
+
+commit c4d85a4026cd9c593521a635b1e477aac15eb86a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Nov 26 16:29:43 2013 +0100
+
+    serial.c: Re-enable serial_read() error reporting.
+    
+    libserialport now returns 0 (not SP_ERR_FAIL) as return value when a
+    non-blocking read would return EAGAIN.
+    
+    This fixes bug #188.
+
+commit 25b66c3c61629d2c679d3c1b6dea9e4a0c9f1a1e
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sat Nov 23 21:00:28 2013 +0000
+
+    Use new libserialport opaque configuration structure.
+
+commit 3182932d360303df459abce20dbe093ce9c453e8
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sat Nov 23 20:48:15 2013 +0000
+
+    Use accessor for new libserialport opaque port structure.
+
+commit 067b3836b2720866444e400e2f67562c68b981f4
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Nov 26 01:50:21 2013 +0100
+
+    gmc-mh-1x-2x driver depends on libserialport
+
+commit 79b9a237bdf974c826d222086424bc1edb089976
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Nov 23 15:24:40 2013 +0100
+
+    uni-t-dmm: Drop unnecessary DMM count.
+
+commit 5e1f7c890d099ba47fca543936417a94f989445f
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Nov 23 12:50:33 2013 +0100
+
+    uni-t-dmm: Add support for the Tenma 72-7745.
+    
+    This is a rebadged UNI-T UT60E.
+
+commit a147c7b416c51d115708dce56f096cf1fe8bfb06
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Nov 22 20:03:03 2013 +0100
+
+    hantek-dso: config_list(): Only SR_CONF_BUFFERSIZE needs sdi.
+
+commit 7c07a1783e62dc76bce6238fb3a54160aefedbc3
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Nov 22 19:56:20 2013 +0100
+
+    ols: config_list(): Handle SR_CONF_PATTERN_MODE.
+    
+    SR_CONF_PATTERN_MODE was not handled in config_list(), yielding
+    non-working OLS support in PulseView (due to an assert), and a missing
+    pattern list in sigrok-cli's --show output.
+    
+    This fixes bug #184.
+
+commit 330af0ec899c3b5f0fd6943941d1785faba4dcb1
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Nov 22 15:13:04 2013 +0100
+
+    Update to 3-digit libserialport package version format.
+
+commit e2b238210187e40ad434f659e68d604ed5f523d4
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Nov 22 15:02:12 2013 +0100
+
+    Make struct sr_session opaque.
+    
+    The fields of this structure should not be used directly by frontends
+    (and none of the current ones do). Thus, make the struct opaque and hide
+    its contents from the API.
+
+commit f57924179d08dee9d24099233ffbee2123613a22
+Author: Matthias Heidbrink <m-sigrok at heidbrink.biz>
+Date:   Thu Nov 21 15:47:09 2013 +0100
+
+    gmc_mh_1x_2x: Completed driver for Metrahit 1x/2x
+    
+    This driver supports devices with “RS232“ interface (Metrahit 16I,
+    18S, Siemens B1105 tested, 29S incomplete).
+
+commit 367983a7443d12d85243215bdc83f6cbdd82daeb
+Author: Matthias Heidbrink <m-sigrok at heidbrink.biz>
+Date:   Tue Nov 19 22:30:34 2013 +0100
+
+    Added SR_MQ_TIME and SR_MQFLAG_DURATION.
+
+commit a970522b6d0551360f66ed08b10104f25cc0537c
+Author: Matthias Heidbrink <m-sigrok at heidbrink.biz>
+Date:   Tue Nov 19 22:26:53 2013 +0100
+
+    serial: Allow 5 and 6 data bits.
+
+commit 7b4edcb654d6b36da4369bac3688ad77f6132766
+Author: Matthias Heidbrink <m-sigrok at heidbrink.biz>
+Date:   Tue Nov 19 17:49:23 2013 +0100
+
+    gmc_mh_1x_2x: Inital driver skeleton.
+
+commit 13cd8197eb1980cae4c5676ef88717c2cc9164b0
+Author: Martin Ling <martin-git at earth.li>
+Date:   Thu Nov 21 17:33:02 2013 +0000
+
+    Update for libserialport v0.1 API.
+
+commit c4650aca12630038fa034e2c0a2915073bdceedf
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Nov 20 22:06:01 2013 +0100
+
+    Suppress compile warning
+
+commit 8c273ac57ce34d5a8c8b5093413564af69968041
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Tue Nov 19 12:03:20 2013 +0100
+
+    output/text: Fix memory leak of internal state buffers.
+    
+    The text output module keeps buffers for internal state, upon receiving a DF_END
+    packet it frees the internal context but the buffers are never freed.
+    
+    This adds a text_cleanup() helper function and registers it as the cleanup
+    function within all the text output modules.
+
+commit 61bab807f4b85660c07b1ac62a3ae2b35b333e5e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Nov 20 00:42:08 2013 +0100
+
+    DT4000ZC/TP4000ZC: Force DTR=1 on the serial port.
+    
+    This fixes the driver e.g. on NetBSD.
+
+commit 4403c39fe4c681352d1bac7efc1725f4eecb6215
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Nov 19 23:22:46 2013 +0100
+
+    ols: Always open serial port in nonblocking mode.
+    
+    The scan() function was opening the port in non-blocking mode, the dev_open()
+    function however was not using the SERIAL_NONBLOCK flag. This led to hangs
+    in certain situations.
+    
+    This fixes the OLS e.g. on NetBSD.
+
+commit 1a54044299c0da7bc894bf429fa306b236c10b68
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Nov 19 20:09:59 2013 +0100
+
+    serial.c: Minor cosmetic fix.
+
+commit a82635f252167ccfb3c5e3e698439af62adca29c
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Nov 15 00:26:45 2013 +0000
+
+    Use new sp_port_config fields.
+
+commit e385e2ed90d9f66ed72124c8c4c9a04f771fe5e1
+Author: Martin Ling <martin-git at earth.li>
+Date:   Thu Nov 14 18:52:57 2013 +0000
+
+    serial: Use new sp_set_config instead of sp_set_params.
+
+commit 066d42b1c803e3b78b7d34df1f1516f729f81085
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Tue Nov 19 01:08:19 2013 +0100
+
+    serial: Fix leak in serial_open.
+    
+    A new sp_port is created every time we call serial_open (sp_get_port_by_name
+    implicitly creates one for us), so free it every time we call serial_close.
+
+commit 90c7f4e92d020a50b17bb64484209b6e5805003b
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Tue Nov 19 01:08:18 2013 +0100
+
+    device: Fix leak if probe groups are created.
+
+commit 1130e4229b2df4b9f308761928d44747cd568aee
+Author: poljar (Damir Jelić) <poljar at poljar.org>
+Date:   Fri Nov 15 16:54:55 2013 +0100
+
+    rigol-ds1xx2: Send a SR_DF_END packet before acquisition stop.
+    
+    Without a SR_DF_END samples could be cached in the internal buffer of an output
+    module and never flushed, therefore they would be missing in the final output.
+    
+    By sending a SR_DF_END packet we force the output to be flushed.
+
+commit 449cc16bb279e5d3322846ce6bd390e867e71ccb
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Nov 15 12:23:09 2013 +0100
+
+    serial.c: Temporary quickfix until a libserialport fix is done.
+
+commit dc99135322eef1926da9aff7c9013154efbf3f3c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Nov 15 09:48:34 2013 +0100
+
+    libsigrok-internal.h: Fix libserialport.h name.
+
+commit 26e0361cc61e8a2236f6667f3e2ac4edd3dc68d2
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Nov 13 22:43:26 2013 +0100
+
+    uni-t-dmm: Drop unused packet_request callback.
+
+commit c4f2dfd0f0df07e6e2b10e33c46c9c457c9c5016
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Nov 13 19:56:13 2013 +0100
+
+    configure.ac: libserialport is optional.
+    
+    Disable drivers that need serial port support if libserialport is not found.
+    
+    Also, disable building various other serial port related code in that case.
+
+commit 0dcb0c981eccf8df444a9ab0d49dcacf791930f7
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Nov 13 19:35:27 2013 +0100
+
+    README: Document new libserialport requirement.
+
+commit 6a76efebc1f4d7dab7b1ec0819c2ac06b123f36b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Nov 13 19:09:46 2013 +0100
+
+    serial.c: Fix a few return values.
+
+commit a0dfaa6c4c34fd37e4ea5294960526145e043e4c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Nov 13 19:04:54 2013 +0100
+
+    serial.c: Cosmetics, coding-style.
+
+commit 0d4405ce5e9373d2dcd90a9188b79d79eaafae5d
+Author: Martin Ling <martin-git at earth.li>
+Date:   Mon Nov 4 12:54:27 2013 +0000
+
+    Update for renamed libserialport header file.
+
+commit f2b830f71df551e68f85eace38b01f4c741da328
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Nov 3 23:10:17 2013 +0000
+
+    Fix silly copy-paste error.
+
+commit c9bc57b6bc0c13d7bf4fef60db3030f88eeebda5
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Nov 3 22:53:04 2013 +0000
+
+    Update to new libserialport API.
+
+commit a9bce5a56199e44d4e2ec42d7aab7f57f386d55a
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Oct 27 15:51:24 2013 +0000
+
+    Use libserialport for serial port access.
+
+commit 3220827c57d6c3970b925303000dca095d6cf900
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Nov 11 07:53:52 2013 +0100
+
+    error.c: Add SR_ERR_PROBE_GROUP handling.
+
+commit a0dc461d7b2a345bd0e28e87e7bbf343825f0182
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Nov 11 07:42:51 2013 +0100
+
+    doxygen: Fix/improve 'struct sr_probe_group' documentation.
+
+commit 57d0a2e195c6dac9e00bf6af3aa35bc394500b15
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Nov 10 23:22:18 2013 +0100
+
+    unittests: Update for probe-groups changes.
+
+commit 58f433696301321bda26431789abb2ba05e56dde
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Nov 3 14:16:10 2013 +0100
+
+    rigol-ds1xx2: Unbreak listing of _VDIV and _COUPLING
+
+commit 5f77dffc027b22a80998ac3037b87546004c6bca
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Nov 3 14:15:35 2013 +0100
+
+    rigol-ds1xx2: Unbreak listing of SR_CONF_DEVICE_OPTIONS
+
+commit be60a9e4a97ab68a140511afca83db1f202e7a0e
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Nov 3 14:13:59 2013 +0100
+
+    rigol-ds1xx2: Better error reporting when probe groups are required
+
+commit 78bcc55afa19dc2d8432afccf2fb78a0114db509
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Nov 3 14:11:43 2013 +0100
+
+    rigol-ds1xx2: Minor coding style fixes
+
+commit bdc955bc0628afc643e672ba1493a6bd6c3d8ce5
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Nov 3 14:04:15 2013 +0100
+
+    Add SR_ERR_PROBE_GROUP, denoting a probe group requirement
+
+commit d3c74a6fb05118e32ad421443251b7b3288918f9
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Oct 31 23:58:33 2013 +0100
+
+    probe_groups: API changes required to implement probe groups.
+
+commit ba358ffd83810fe0c03248992b9076fb435f7b4b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Oct 31 22:53:22 2013 +0100
+
+    rigol-ds1xx2: fix bitrot in device cleanup code
+
+commit e43fdd8d4f207046939c67d5f60481b42ca35650
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Apr 28 22:11:43 2013 +0200
+
+    rigol-ds1xx2: Don't assume valid sdi
+
+commit 57ecdbd74245dab0b14b43e4ed5a470e50e63e42
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Apr 28 22:11:05 2013 +0200
+
+    Update API documentation
+
+commit 45311368de0e860711cded2718c85f6e06c2d613
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Apr 28 13:05:27 2013 +0200
+
+    rigol-ds1xx2: Skip obsolete fields
+
+commit af54bac90a98e3ab0c34b00e91bd31775f84e51f
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Apr 21 16:02:12 2013 +0100
+
+    python: Map probe group configuration to ProbeGroup attributes.
+
+commit 417e9f3ab427ceb61bde663e357b67dfdac09371
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Apr 21 15:46:48 2013 +0100
+
+    python: Add classes for probes and probe groups.
+
+commit f48e0249b45592811598c493b08a1fbf5219b659
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Apr 21 14:48:56 2013 +0100
+
+    rigol-ds1xx2: implement probe group specific options.
+
+commit 3d3a601e803d4fe10e2f633b5f0e06104dcf9017
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Apr 21 13:44:34 2013 +0100
+
+    rigol-ds1xx2: create probe groups.
+
+commit 5150ef336b69bfece769eef746f522270d6de90b
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Apr 21 21:07:16 2013 +0100
+
+    probe_groups: Add a name field to sr_probe_group.
+
+commit 909cc050bf96ce7b26e5431cccfe44cc95c62842
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Apr 21 21:05:03 2013 +0100
+
+    probe_groups: initialise sdi->probe_groups to NULL.
+
+commit 54e7a3d0d7bd80c993db9ff37b4a38ed38af7b0a
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Apr 21 21:11:32 2013 +0100
+
+    probe_groups: Update Python bindings for API change.
+
+commit 5daed4bc6d984a4e03881bcc7fe9104e930a18e1
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Apr 21 00:45:01 2013 +0200
+
+    Use priv for consistency
+
+commit 8f996b89481670219c7576e2c68b128a0a2ce026
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sat Apr 20 01:00:49 2013 +0100
+
+    probe_groups: API changes required to implement probe groups.
+
+commit 8dce54f7aa9eed362f2c9e41412c6b71ba1a32b6
+Author: Dan Horák <dan at danny.cz>
+Date:   Mon Nov 4 10:53:36 2013 +0100
+
+    update udev rules
+    
+    With usbtmc driver being classified under usbmisc in newer kernels the udev rules
+    need an update.
+
+commit 360079e78efaa44142458dde329042b97da68a87
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Nov 3 23:34:21 2013 +0100
+
+    configure.ac: Bump libtool/library version from 1:1:0 to 1:2:0.
+    
+    The libtool current:revision:age numbers change from 1:1:0 to 1:2:0
+    (i.e., revision is increased) since the library source code has changed,
+    but no interfaces were added or changed or removed.
+    
+    Details:
+    http://www.gnu.org/software/libtool/manual/libtool.html#Updating-version-info
+    
+    This changes the library filename (e.g. on Linux) from libsigrok.so.1.0.1
+    to libsigrok.so.1.0.2, but the SONAME (+symlink) remains the same
+    (libsigrok.so.1) since this release is API- and ABI-compatible with the last.
+
+commit 3f6549307bba0483a20e1f434aab5ae95005117e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Nov 3 23:32:23 2013 +0100
+
+    configure.ac: Bump package version to 0.2.2.
+
+commit 8e2da1a650dade6529668d4b22e906ccec172b17
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Nov 3 19:23:00 2013 +0100
+
+    NEWS: Update for upcoming 0.2.2 release.
+
+commit d69d26429f33b7ae15b786fcc73e644bbb153a60
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Nov 4 00:18:47 2013 +0100
+
+    output/analog: SR_UNIT_REVOLUTIONS_PER_MINUTE: Add missing break.
+
+commit 21d464a7e53efc9ac9810d9301a12b6a56fdb061
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Nov 4 00:46:45 2013 +0100
+
+    contrib/z60_libsigrok.rules: Also mention UNI-T UT325.
+    
+    The same USB/HID based IC is used in the UNI-T UT-D04 cable (for various
+    multimeters) and the UNI-T UT325 thermometer.
+
+commit 8823146edff2f539fba48da807e011d94f1321f4
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Nov 4 00:41:56 2013 +0100
+
+    contrib/z60_libsigrok.rules: Add entry for the Saleae Logic16.
+
+commit 5724a20af7a6449204d79972c6804d6c9b34b3f8
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Nov 3 23:28:55 2013 +0100
+
+    configure.ac: Fix list sorting (cosmetic).
+
+commit 122d33d47d17fd56c6306190b7066d8819b43145
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Nov 3 23:28:03 2013 +0100
+
+    configure.ac: Move a teleinfo snippet to the correct place.
+    
+    This breaks some configure use-cases otherwise.
+
+commit 9b2f03bbd2e5d5a6efe056645b34e17ace9d8b90
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Nov 3 18:18:44 2013 +0100
+
+    README.devices: uni-t-dmm devices need VID/PID now.
+
+commit 5fa12e93e3f1cf2825591e76e1f63d974fec9cc2
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Nov 3 17:30:42 2013 +0100
+
+    README.devices: Updates.
+
+commit 53f05fa80f1f9d7657f1173f24d9d1e2b740a312
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Nov 3 16:08:38 2013 +0100
+
+    doxygen: @since tags document only last API change.
+    
+    If a function existed before but the API changed, the @since
+    tag only reflects the release of the last API change.
+
+commit ef1020f9cba528b542968b32fe662241e96e6119
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Nov 3 16:06:15 2013 +0100
+
+    HACKING: Updates, some additions.
+
+commit b775d753e3874d69ee342b1d6c0961a6f1494f18
+Author: Dan Horák <dan at danny.cz>
+Date:   Sat Nov 2 16:47:11 2013 +0100
+
+    rigol-ds1xx2: detect Rigol DS1xx2 with upgraded bandwith
+    
+    The bandwith in Rigol DS1xx2D/E scopes can be upgraded to 150 MHz in software.
+    So detect also scopes with the upgraded bandwith.
+    
+    using libsigrok-0.2.1 + this change + commit da970d24ec (required for newer kernels):
+    
+    [dan at eagle sigrok]$ sigrok-cli --scan -d rigol-ds1xx2 -l 5
+    sr: libsigrok loglevel set to 5.
+    sr: Sanity-checking all drivers.
+    sr: Sanity-checking all input modules.
+    sr: Sanity-checking all output modules.
+    srd: libsigrokdecode loglevel set to 5.
+    sr: hwdriver: Initializing driver 'rigol-ds1xx2'.
+    sr: serial: Opening serial port '/dev/usbtmc0' (flags 1).
+    sr: serial: Opened serial port '/dev/usbtmc0' (fd 7).
+    sr: serial: Wrote 5/5 bytes (fd 7).
+    sr: serial: Closing serial port /dev/usbtmc0 (fd 7).
+    sr: rigol-ds1xx2: response: /dev/usbtmc0 [Rigol Technologies,DS1152D,DS1EU150XXXXXX,00.04.01.00.02]
+    sr: hwdriver: Scan of 'rigol-ds1xx2' found 1 devices.
+    The following devices were found:
+    rigol-ds1xx2 - Rigol Technologies DS1152D 00.04.01.00.02 with 18 probes: CH1 CH2 D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 D11 D12 D13 D14 D15
+
+commit 3a8cad91374739ec7143b94894f14435c1d09426
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Oct 31 13:47:30 2013 +0100
+
+    metex14: Handle a few missing cases for overflow.
+
+commit 88f544f27e56e8cd4a022d3de1f37153b941d158
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Oct 29 20:31:24 2013 +0100
+
+    Add support for the Metex M-4650CR.
+    
+    (the Voltcraft M-4650CR is a rebadged Metex M-4650CR)
+
+commit 2b83d7fee11dddba7603e180c3528b14ff8aba0e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Oct 29 18:10:10 2013 +0100
+
+    Add support for the Voltcraft M-4650CR.
+
+commit 4a35548bbee613149fa4fbfa3dd9eaacb7511376
+Author: Marc Schink <sigrok-dev at marcschink.de>
+Date:   Wed Oct 23 10:13:53 2013 +0200
+
+    Initial Comma-separated values (CSV) input support.
+
+commit 6bf4273ee8bb6477ba55e0540e370547bd804641
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Oct 28 22:59:32 2013 +0100
+
+    Fix two FreeBSD build issues related to libusb-1.0.
+    
+    FreeBSD's libusb-1.0 compatible library has a few differences compared
+    to the "normal" libusb-1.0 from libusb.org which we have to work around.
+    
+    LIBUSB_CLASS_APPLICATION doesn't exist in FreeBSD's libusb, and
+    libusb_handle_events_timeout_completed() doesn't exist either.
+    The latter is basically libusb_handle_events_timeout() with an extra
+    (unused by us) parameter, so the workaround is relatively simple.
+    
+    This fixes bug #185.
+
+commit 71185b48a114a8278e8baac04f5053ae046fdbcf
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Mar 13 09:46:08 2013 +0100
+
+    Unit tests for 'binary' input format & version APIs.
+
+commit e790bd5cda9ccf99474b2d4998d3dd4e204416ea
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Oct 25 20:10:01 2013 +0200
+
+    norma-dmm: Minor cosmetics, coding-style, consistency fixes.
+    
+    Also, add a missing "%" in an sr_err() and a missing parameter in
+    another sr_err().
+
+commit f8e76e2e74bf09024af50d68a0e90a558be126b9
+Author: Matthias Heidbrink <m-sigrok at heidbrink.biz>
+Date:   Thu Oct 17 10:57:18 2013 +0200
+
+    norma dmm: Implemented driver.
+
+commit bfd48770fc18dae79d140120e6af3b7ac4bdb2ee
+Author: Matthias Heidbrink <m-sigrok at heidbrink.biz>
+Date:   Thu Oct 17 10:57:17 2013 +0200
+
+    norma dmm: Initial driver skeleton.
+
+commit 1477a9a6dc4f470cb91c64c71c139825e8329adb
+Author: Matthias Heidbrink <m-sigrok at heidbrink.biz>
+Date:   Thu Oct 17 10:57:16 2013 +0200
+
+    std.c: Changed return value of std_dev_acquisition_stop_serial() for non-active device to SR_ERR_DEV_CLOSED for consistency with other functions.
+
+commit 50a9aba21b912b44559290ece466b46aaa8840cf
+Author: Matthias Heidbrink <m-sigrok at heidbrink.biz>
+Date:   Thu Oct 17 10:57:14 2013 +0200
+
+    serial: Removed flag OPOST (turn off all output processing).
+
+commit a510d55571a970fd90e6aca30771dd34bcc73296
+Author: Matthias Heidbrink <m-sigrok at heidbrink.biz>
+Date:   Thu Oct 17 10:57:13 2013 +0200
+
+    serial: Added flags CLOCAL (ignore modem status lines) and CREAD (start receiver).
+
+commit 1b943b6d8b81be8b91216525a56007c5bdef43df
+Author: Matthias Heidbrink <m-sigrok at heidbrink.biz>
+Date:   Thu Oct 17 10:57:12 2013 +0200
+
+    serial: Added flag IXANY (any char will restart) to XON/XOFF handshaking.
+
+commit 0c30b35fce5777592ff781ec9660b7e46f0af9c6
+Author: Sean Young <sean at mess.org>
+Date:   Sun Oct 13 12:36:02 2013 +0100
+
+    saleae-logic16: claim device before using it
+    
+    The kernel warns:
+    
+    [ 7461.925685] usb 2-4: usbfs: process 11303 (sigrok-cli) did not claim interface 0 before use
+
+commit 5542bee61b0e18e9ae3fa6edb361b8ed1bb77425
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Thu Oct 3 21:20:18 2013 +0200
+
+    teleinfo: actual parser implementation
+
+commit 8e796cb438a80c6bcab5d44afaae0c74d757b673
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Mon Sep 23 22:02:02 2013 +0200
+
+    teleinfo: Initial driver skeleton.
+
+commit 45315d0460aa9d66b520f80dbd0dee66e48df12d
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Thu Oct 10 22:28:35 2013 +0200
+
+    add energy meter device type and related units
+
+commit c02dc3e26141a13554828be9a4ffa2def857d2b3
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Oct 23 18:41:13 2013 +0200
+
+    metex14: Add support for pF (picofarad).
+    
+    This is used on some Metex DMMs.
+
+commit ee6cb5a417713a3080d03be44643b47131d59e2e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Oct 23 18:07:54 2013 +0200
+
+    metex14: Use case-insensitive string compares.
+    
+    This allows some other DMMs to be supported that use e.g. "kOhm" vs.
+    "KOhm", and so on.
+
+commit 1a807c13fcf4bc015fb22311c70292e9c51bb5f9
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Oct 20 14:45:20 2013 +0200
+
+    metex14: Support DMMs with slightly different protocol.
+    
+    This adds support for DMMs with 5 digits in the protocol (instead of 4)
+    and some more whitespace variants.
+
+commit 71f1302b4b4b712149303d235876146e8d1d9af5
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Sep 29 17:43:28 2013 +0200
+
+    metex14: Support DMMs with whitespace differences.
+    
+    Most Metex DMMs use e.g. "  mV" as unit field, others use "mV  ",
+    though. Support these (and other) whitespace variants by stripping all
+    spaces and only comparing non-space characters.
+
+commit bfb926c1d2e248336dd57a5ab63cf503cb2b00b7
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Thu Oct 10 23:11:06 2013 +0200
+
+    es519xx: restore correct packet size
+
+commit b21d7eebe24093269e78f84fb13e03f492abc502
+Author: Matthias Heidbrink <m-sigrok at heidbrink.biz>
+Date:   Thu Oct 17 10:57:15 2013 +0200
+
+    serial: Changed order of flags PARENB and PARODD in deletion to same order as in setting (cosmetic).
+
+commit 8819bf5a960c37561e2bbbffa2685ec477938083
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Oct 16 18:10:29 2013 +0200
+
+    Bump libzip requirement to >= 0.10.
+    
+    We now use zip_int64_t and zip_get_num_entries() for example, which
+    requires at least libzip 0.10. This version was released in 03/2012,
+    which is old enough that we don't necessarily have to do a work-around
+    for older versions. Thus, simply bump the requirement to >= 0.10.
+
+commit 568dcacc1a43f5bfb5a103e6e9b6a5ad50ea2d08
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Oct 16 10:40:38 2013 +0200
+
+    Better error reporting on session start failure
+
+commit df6b0f99af1c2f4be963a7fb388e21a718cce6f3
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Fri Oct 11 01:36:52 2013 +0200
+
+    ISO-TECH IDM103N: remove the useless -ser postfix
+
+commit 94e9021b3ee2d18ef0480c6fa95f0d950cf12eb9
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Sat Oct 12 17:25:29 2013 +0200
+
+    es519xx: correct initialization of es519xx_info structure
+
+commit 93d719cde6dbd3cc79b035b223e5a0d4ab5926cb
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Oct 7 00:24:44 2013 +0200
+
+    es519xx: Fix incorrect packet size, and a typo.
+
+commit 72e1672fc9267cd34fe9e6b174a80ec6aae420d8
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Oct 6 14:59:10 2013 +0200
+
+    es519xx: Cosmetics, coding style, minor fixes.
+
+commit de737bfc11f37ecaf9e028ba17fceafe510fc68c
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Thu Oct 3 22:10:25 2013 +0200
+
+    add ISO-TECH IDM103N serial-dmm driver
+
+commit c01bdebc575cc3abdba30610afa374f0364b0b94
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Thu Oct 3 22:00:22 2013 +0200
+
+    add cyrustek es519xx generic protocol parser
+
+commit 87532f23a4dbfb6ae1454cbea4566725d5a7555c
+Author: Aurelien Jacobs <aurel at gnuage.org>
+Date:   Thu Oct 3 21:37:14 2013 +0200
+
+    output/analog: add revolutions per minute unit
+
+commit 2f9376117c804898eaf75c3efebdbd97b6d89695
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Sep 7 14:48:38 2013 +0200
+
+    fx2lafw: Organize driver into api.c / protocol.[ch].
+    
+    This now matches the naming conventions of the other drivers.
+
+commit fbf07e020995b2d50ef337a2c629b2b8997dd047
+Author: Daniel Thompson <daniel at redfelineninja.org.uk>
+Date:   Fri Oct 4 08:34:05 2013 +0100
+
+    agilent-dmm: Fix SEGV during incomplete reply from meter.
+    
+    If buf contains exactly the string "Agilent Technologies" (for example if
+    there are bugs in the timeout logic or serial driver causing the reply from
+    the meter to be abridged) then this code will SEGV. This is because tokens[1]
+    is NULL but only tokens[2] and tokens[3] (both of which are undefined) are
+    NULL checked.
+    
+    Can be trivially corrected by NULL checking tokens[1] as well.
+    
+    Signed-off-by: Daniel Thompson <daniel at redfelineninja.org.uk>
+
+commit 5715e84fe3335e519148d7f6252b046598a982a8
+Author: Daniel Thompson <daniel at redfelineninja.org.uk>
+Date:   Thu Sep 19 16:39:24 2013 +0100
+
+    serial: Only sleep when no characters are received.
+    
+    g_usleep(XX) sleeps for *at least* XX microseconds but may sleep for
+    longers (on older kernels the sleep will typically be 10000us). Thus
+    byte receive loops containing an unconditional sleep will perform
+    very poorly (for example it causes the scan in agilent-dmm to timeout
+    prematurely).
+    
+    Even on modern kernels serial_readline() has a 2ms sleep per byte which
+    means it will read at a maximum rate of half a character per millisecond
+    (~4800baud).
+    
+    This is fixed by only sleeping when read() returns no data.
+    
+    Signed-off-by: Daniel Thompson <daniel at redfelineninja.org.uk>
+
+commit 1b142b78274d74563a084299a01ef1a92206356f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Sep 24 09:25:32 2013 +0200
+
+    README.devices: Various updates and additions.
+
+commit ba26f45d1d0472597aa257eb1aaff61834ab7e5a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Sep 24 09:20:15 2013 +0200
+
+    configure.ac: Don't build uni-t-ut32x if libusb-1.0 is not found.
+
+commit 45c0841b2576fab58e7e059fd7fb839c740ba758
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Sep 24 09:16:44 2013 +0200
+
+    uni-t-ut32x: Shorten dev_list().
+
+commit 1ca48e29d436ccbd2a8faefd388840ca6de7aebf
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Sep 24 09:02:38 2013 +0200
+
+    Makefile.am: Add missing HACKING file.
+
+commit d5c5ea2a29d1a7063e26327b87fa820dc1babd16
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Sep 24 09:00:16 2013 +0200
+
+    libsigrok.h: Fix enum entries order.
+    
+    New enum items must be added at the bottom of the respective "category"
+    within the enum in order to not change any numbers (i.e. break the ABI).
+
+commit 72a08bccffe5a73376113e07287327e4f89d270f
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Sep 25 11:51:38 2013 +0200
+
+    Minor documentation fixes
+
+commit 5451816fd1676eab2942aba8cec6188451772760
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Sep 21 17:44:49 2013 +0200
+
+    When adding a device instance to a running session, start acquisition on it
+
+commit f438e0c923a114d7fd34fe0729ecd6891cb262f4
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Sep 18 13:28:07 2013 +0200
+
+    Add sr_session_append(): add captured data to an existing session file
+    
+    This extends the session file format to contain logic data files named
+    either "logic-1" as before, or "logic-1-1", "logic-1-2", ...
+    representing chronologically ordered chunks of captured data.
+    
+    The chunks are transparently concatenated together by sr_session_load().
+
+commit 6ebe003985ac566fb2a35f1c5df8207dc9947d01
+Author: Matt Ranostay <mranostay at gmail.com>
+Date:   Fri Sep 6 22:27:46 2013 -0700
+
+    ols: fixed demux mode disable noise filter
+    
+    Demux flag wasn't getting set off if one non-demux sample was ran
+    beforehand.
+    
+    Signed-off-by: Matt Ranostay <mranostay at gmail.com>
+
+commit 6a53bde6716ce761af11e2bf34527ece629d0c21
+Author: Matt Ranostay <mranostay at gmail.com>
+Date:   Thu Sep 5 23:38:59 2013 -0700
+
+    ols: Moved FLAG_FILTER to demux check
+    
+    Demux mode was having filter mode set which it doesn't
+    support per FPGA demon core docs.
+    
+    Signed-off-by: Matt Ranostay <mranostay at gmail.com>
+
+commit 4ac4595ad08e58a3f1e6310fffb34624ce6f4c07
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Sep 4 09:36:47 2013 +0200
+
+    configure.ac: Properly use $HW_ENABLED_DEFAULT everywhere.
+    
+    Otherwise --enable-all-drivers / --disable-all-drivers doesn't work
+    correctly.
+
+commit c542391f8243e9307950820fa8dc3fad6fec3600
+Author: Matt Ranostay <mranostay at gmail.com>
+Date:   Tue Sep 3 20:47:10 2013 -0700
+
+    proto: Add missing prototype in proto.h
+    
+    Add missing prototype sr_session_dev_list that was
+    breaking the Pulseview build.
+    
+    Signed-off-by: Matt Ranostay <mranostay at gmail.com>
+
+commit 2bb311b482d587a7d20c35bf54f084bc0011d72d
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Sep 2 14:24:32 2013 +0200
+
+    New API function sr_session_dev_list()
+    
+    This exposes the list of devices added to the session. In the case of
+    loading a session from file, these struct sr_dev_inst are otherwise
+    not exposed to the frontend. See bug 145.
+
+commit fa93154fe6cb0962c1a1551dacb6619a7b3f4810
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Sep 2 14:23:42 2013 +0200
+
+    Properly initialize session
+
+commit e52bb9be8351b8c4f960d998a62dfbd05b8fa637
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Sep 1 13:10:54 2013 +0200
+
+    Voltcraft VC-830: Fix diode mode handling.
+    
+    This DMM is not using the standard bits in the FS9922 protocol/structure
+    to indicate the "volt" and "diode mode" flags. Instead, it only sets the
+    user-defined bit "z1" to indicate both "diode mode" and "volt".
+    
+    This fixes #142.
+
+commit a6ed50f4055b9377d1ebe9e4b886ae357acc578e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Sep 1 13:40:17 2013 +0200
+
+    es51922/fs9721/fs9922/metex14: Use diode MQFLAG.
+    
+    This fixes #141.
+
+commit 98494dc8a393f6e1b73fddb1e59aa3a3f590d764
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Sep 1 13:41:02 2013 +0200
+
+    fs9922: Fix typo.
+
+commit 045e9a99186396694fb10f3155a7fb868705ecb8
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Aug 30 16:34:39 2013 +0200
+
+    serial.c: Drop unneeded <glob.h>.
+    
+    This is no longer used, and also it is not available on Android and thus
+    breaks cross-compilation for Android.
+    
+    Thanks Marcus Comstedt <marcus at mc.pp.se> for reporting.
+
+commit e6523173cff4b39e78566495786e43f0917c860f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Aug 30 08:57:09 2013 +0200
+
+    output/analog: Support all known MQFLAGs.
+
+commit b1de040700de67dd41a881922f21a691c3aec77e
+Author: Matt Ranostay <mranostay at gmail.com>
+Date:   Thu Aug 29 00:06:53 2013 -0700
+
+    ols: fixed channel limit check
+    
+    For demux mode we half the channels. Previous check method broke
+    the OLS randomly and but it in a bad state.
+    
+    Signed-off-by: Matt Ranostay <mranostay at gmail.com>
+
+commit da970d24ecfcf67f89a9532f3a53ade8cb1131ed
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Aug 30 13:57:15 2013 +0200
+
+    rigol-ds1xx2: newer Linux kernels have USBTMC in /sys/class/usbmisc
+
+commit f51acd69d74b007281f6016e466d026d61a375f3
+Author: Matt Ranostay <mranostay at gmail.com>
+Date:   Tue Aug 27 22:17:05 2013 -0700
+
+    ols: combine demux samples
+    
+    demux mode allows DDR sampling which disables group 2 & 3
+    and thus samples group 0 & 1 to sample on rising and falling of
+    the clock.
+    
+    Signed-off-by: Matt Ranostay <mranostay at gmail.com>
+
+commit 7b0a57fd1c1d1b658864b81df2357849ccc4715c
+Author: Matt Ranostay <mranostay at gmail.com>
+Date:   Tue Aug 27 21:19:56 2013 -0700
+
+    ols: add swap channels feature
+    
+    Allow channel groups to be swapped. This is useful
+    for demux at 200mhz with the unbuffered channels.
+    
+    Signed-off-by: Matt Ranostay <mranostay at gmail.com>
+
+commit de524099823d7a7b9aeae3e87e79c14cfc809fd6
+Author: Matt Ranostay <mranostay at gmail.com>
+Date:   Tue Aug 27 21:19:55 2013 -0700
+
+    ols: Display noise filter flag
+    
+    Show if noise filter is on. This is important to be
+    sure is off for demux mode.
+    
+    Signed-off-by: Matt Ranostay <mranostay at gmail.com>
+
+commit 00d04d3b0eca2898409fe78b33c1bbf177cd8504
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Aug 27 00:33:20 2013 +0200
+
+    ols: Fix RLE count handling
+    
+    The high bit of the sample, denoting this is a count, was not getting
+    properly cleared. This resulted in an inevitably negative count, and
+    corruption of the sample buffer before it was transferred to the
+    frontend.
+
+commit abb39e6b8c9f2d512920dce440c0d8dd7a9a90f0
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Aug 26 23:42:09 2013 +0200
+
+    ols: Properly initialize entire single-sample buffer before start
+    
+    The single sample buffer, up to 4 bytes long, was not getting initialized
+    on (every) acquisition start, only after the first full sample was in.
+    This caused the first sample to potentially hold garbage.
+
+commit eb1b610b1281bd83cb4dbd02b2eccdf4888bb093
+Author: Matt Ranostay <mranostay at gmail.com>
+Date:   Sat Aug 24 22:01:15 2013 -0700
+
+    ols: add external clock support
+    
+    Add external clock support that allows you to use the tracing
+    targets bus clock line for sampling.
+    
+    Signed-off-by: Matt Ranostay <mranostay at gmail.com>
+
+commit 967760a8937e997ba9d7b729442f882947be154e
+Author: Matt Ranostay <mranostay at gmail.com>
+Date:   Sat Aug 24 22:00:52 2013 -0700
+
+    ols: add test mode support
+    
+    ols allows both external and internal test patterns at ~20khz
+    which are helpful for unit tests and demos.
+    
+    pattern=internal -> route pattern internally to all 32 pins
+                          (input otherwise disabled)
+    
+    pattern=external -> generates pattern on unbuffered pins 16:31
+                          (which can be looped back to the buffered pins 0:15)
+    
+    Signed-off-by: Matt Ranostay <mranostay at gmail.com>
+
+commit 503133bb5fcf9304d9bd93c023bc9c6c20c3aa0b
+Author: Matt Ranostay <mranostay at gmail.com>
+Date:   Fri Aug 23 21:42:51 2013 -0700
+
+    ols: fixed parallel stage triggers
+    
+    Stage count was always getting incremented one more than
+    actual stages, and this caused a extra stage with zero'ed data
+    probe lines to have the start bit field.
+    
+    Signed-off-by: Matt Ranostay <mranostay at gmail.com>
+
+commit d0107565c1e61e7b705fb9c0c84c72490da57d8f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Aug 21 11:41:21 2013 +0200
+
+    saleae-logic16: Drop unneeded NUM_PROBES.
+
+commit 87b537ced00b56ec7c8b3cfb9ea375a5501017d2
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Aug 21 11:37:40 2013 +0200
+
+    saleae-logic16: Shorten dev_list() implementation.
+
+commit 96484e22b46af66216d1e0357c6e3478494d416c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Aug 21 02:02:41 2013 +0200
+
+    saleae-logic16: Whitespace fixes, cosmetics.
+
+commit 186dde8d724c19fc62eb7c0d5dcabfd98579d7ee
+Author: Marcus Comstedt <marcus at mc.pp.se>
+Date:   Mon Aug 5 18:34:47 2013 +0200
+
+    saleae-logic16: Cleanup the prime_fpga function
+    
+    The driver should now work on any Logic16.
+
+commit fec7aa6a44fdd3ed835bd2b15ea5cf63beecda10
+Author: Marcus Comstedt <marcus at mc.pp.se>
+Date:   Mon Aug 5 12:05:40 2013 +0200
+
+    saleae-logic16: Update copyright blurbs.
+    
+    Copied copyright lines from fx2lafw driver, since much of the code is
+    taken from there.
+
+commit db11d7d2d05c9e38978ae92920d96b61cf982d14
+Author: Marcus Comstedt <marcus at mc.pp.se>
+Date:   Sun Aug 4 16:20:07 2013 +0200
+
+    saleae-logic16: Add voltage threshold conf.
+
+commit b117363ad7510e300501612c0cda23b81adeccc5
+Author: Marcus Comstedt <marcus at mc.pp.se>
+Date:   Sun Aug 4 14:28:04 2013 +0200
+
+    saleae-logic16: Declare confs.
+
+commit 7b5daad45c6526f6eed368e30d262dcbe610b7f5
+Author: Marcus Comstedt <marcus at mc.pp.se>
+Date:   Sun Aug 4 13:46:35 2013 +0200
+
+    saleae-logic16: Implemented acquisition.
+
+commit 15abcf0f5888dab4c077af6600fab219342af830
+Author: Marcus Comstedt <marcus at mc.pp.se>
+Date:   Sat Aug 3 00:35:44 2013 +0200
+
+    saleae-logic16: Initialize the FPGA.
+    
+    The map_eeprom_data function is currently unknown.  The map entries
+    provided were observed via bus-snooping of the vendor software on my
+    device.  Other devices may need additional values.
+
+commit 5eea4305ad108b8549257170985688004e65d00b
+Author: Marcus Comstedt <marcus at mc.pp.se>
+Date:   Fri Aug 2 21:02:00 2013 +0200
+
+    saleae-logic16: Reworked scan/open to handle FW upload.
+    
+    The new code is based on code from the fx2lafw driver.
+
+commit f6a21fa50c3276eab4aacf61cae4ecfb16a98e73
+Author: Marcus Comstedt <marcus at mc.pp.se>
+Date:   Wed Jul 31 16:53:35 2013 +0200
+
+    saleae-logic16: Detect the hardware.
+
+commit 6383365795b8f9a3408315f8726fa75fa25e19d1
+Author: Marcus Comstedt <marcus at mc.pp.se>
+Date:   Wed Jul 31 11:44:57 2013 +0200
+
+    configure.ac: Fix build when libusb-1.0 not available.
+    
+    The Saleae Logic16 needs libusb-1.0, thus disable this driver when
+    libusb-1.0 cannot be found.
+
+commit c463dcf06cdeb7f6ec0d2bafda707cce3a486bf0
+Author: Marcus Comstedt <marcus at mc.pp.se>
+Date:   Sun Jul 21 12:30:32 2013 +0200
+
+    saleae-logic16: Initial driver skeleton.
+
+commit 56e76981bc5e8e8d138275ad215e96d8ab4939af
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Aug 11 10:52:43 2013 +0200
+
+    uni-t-dmm: Require conn parameter for scan
+    
+    Since the uni-t-ut32x series handles devices with the same USB VID.PID,
+    which is linked to the WCH CH9325 USB/HID-UART interface chip, this
+    driver can no longer assume it can handle anything with this VID.PID.
+
+commit d6ff054ae58f1423282d52c37ac9e76296163504
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Aug 11 10:44:03 2013 +0200
+
+    uni-t-ut32x: Full acquisition support
+
+commit 6513f97fbe18ba1f4a093e882b0d19284234b8b3
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Aug 9 22:39:15 2013 +0200
+
+    uni-t-ut32x: Flesh out driver
+
+commit 3877dde43a08c23e37a6d944321005320bdcf784
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Aug 9 00:29:04 2013 +0200
+
+    uni-t-ut32x: Initial driver skeleton.
+
+commit 4a8bbed76d127663e62d83f6a3ac5b7e315e5f00
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Jul 22 19:48:15 2013 +0200
+
+    center-3xx: Initial Center 309 / Voltcraft K204 support.
+
+commit 4433145f481d077570b371b466e98b17a77ec7e2
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Jul 19 09:35:48 2013 +0200
+
+    center-3xx: Initial driver skeleton.
+
+commit fc1bb735e4ce1fd4e8a109b50d2fd698dec39aac
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Aug 8 19:39:50 2013 +0200
+
+    Doxyfile: Set version to "unreleased development snapshot".
+
+commit f6b59690146fc45050cef965a6be1590b47852b9
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Aug 7 01:08:37 2013 +0200
+
+    Bump package version to 0.2.1, libtool version to 1:1:0.
+    
+    The last release (0.2.0) had the libtool version (current:revision:age)
+    set to 1:0:0. Since this release doesn't add/change/remove any
+    interfaces, only 'revision' is increased, resulting in 1:1:0.
+    
+    http://www.gnu.org/software/libtool/manual/libtool.html#Updating-version-info
+    
+    Frontends using libsigrok don't need to be recompiled or relinked.
+
+commit b11df97ad5650e17f336373b5170b4ff02e4e2aa
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Aug 6 22:32:46 2013 +0200
+
+    Doxyfile: Change version to 0.2.1.
+
+commit f93c89b2140e1f1b67f7822887322376a9b92448
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Aug 6 22:31:18 2013 +0200
+
+    NEWS: Add entries for the upcoming 0.2.1 release.
+
+commit 6cda4600c14e20e8849a071413bf70890979eadb
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Aug 7 00:40:51 2013 +0200
+
+    README.devices: Minor documentation updates.
+
+commit 1861be0baf8792e48e0bc009a20074210b2c1370
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Aug 7 00:34:06 2013 +0200
+
+    Make sr_session_iteration() static.
+    
+    This function is not used outside of session.c at the moment, so make
+    it static for now.
+
+commit cdc30138c54a781c83a0b125e26216b6799cb045
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Aug 7 00:28:40 2013 +0200
+
+    udev rules: Add missing IKALOGIC ScanaPLUS entry.
+
+commit ce95428cca4ee7f8263389dd44a02d228d2be88e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Aug 7 00:22:14 2013 +0200
+
+    Consistent use of "IKALOGIC" spelling.
+    
+    The company name is written all-caps pretty consistently on the
+    vendor website and docs, so use that spelling everywhere.
+
+commit b07b42f319488d821d23c3310133872df70987c5
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Aug 7 00:18:36 2013 +0200
+
+    Cosmetics, typos.
+
+commit 059f36325e456e71a66beab929ee04e9d43475eb
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Aug 7 00:03:14 2013 +0200
+
+    unittests: Comment out a testcase.
+    
+    The boundary test-case with SR_GHZ(18446744073ULL) currently fails, but
+    that is not practically relevant so comment it out for now, until we add
+    a proper fix.
+
+commit 094e6b815972240fbc210f8c5ef2eaa8c989fbc0
+Author: Peter Stuge <peter at stuge.se>
+Date:   Tue Jun 4 02:20:57 2013 +0200
+
+    Format decimals correctly in sr_si_string_u64()
+    
+    The function previously formatted 1004 as 1.4 k and 1004000 as 1.4 M.
+    The function now formats 1004 as 1.004 k, 1004000 as 1.004 M and
+    1004000000 as 1.004 G.
+    
+    Fixes #73.
+
+commit ba253f2bb97b7a69ad8b486f411d8d81d33792a4
+Author: Paul Sokolovsky <pfalcon at users.sourceforge.net>
+Date:   Mon Jun 3 22:23:57 2013 +0300
+
+    Fix sr_si_string_u64() test cases.
+    
+    The function shall format 1004 as 1.004 k, 1004000 as 1.004 M and
+    1004000000 as 1.004 G.
+    
+    References #73.
+
+commit e11a1ebaccd6232227cdbec24e2b2654940f1138
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Aug 6 21:45:27 2013 +0200
+
+    alsa: Fix double-free issue.
+    
+    This fixes bug #129.
+
+commit 4d7ddff75b8c23fc8d5355c480df029b130cec0c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Aug 6 23:25:18 2013 +0200
+
+    uni-t-dmm: Fix UT61E bug related to the UNI-T UD-D04 cable.
+    
+    This fixes bug #136.
+
+commit ee2cc2d4dc42d833f549f476dd93654c0c674cec
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Aug 5 14:52:44 2013 +0200
+
+    ikalogic-scanaplus: Don't build if libftdi was not found.
+
+commit 37d80736ab601a2e6fb9bf846c9790c3cac8d8ac
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Aug 5 13:34:10 2013 +0200
+
+    kecheng-kc-330b: Don't build if libusb-1.0 was not found.
+
+commit 1a0c33822077e5c8a13d1a98961c6b9090181427
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Aug 5 13:19:21 2013 +0200
+
+    .gitignore: Add some files from the testsuite.
+
+commit 59142ae17756417781018cf81f5a69ba6654f3b2
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Aug 5 13:16:31 2013 +0200
+
+    Disable mso-19 per default, mark experimental.
+    
+    This driver is not yet in a really usable or working state, it'll be
+    re-enabled by default when we're sure it works properly.
+
+commit c51bbdec345b0d7e1c9013e0a1bea2586cf6daa7
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Aug 5 12:59:23 2013 +0200
+
+    Drop nexus-osciprime skeleton for now.
+    
+    This is mostly just a skeleton driver framework at the moment, we'll
+    bring it back when the driver is fully implemented.
+
+commit c93ebace3053de2ca37a280fec5e0f7ca036df08
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Aug 2 01:02:03 2013 +0200
+
+    uni-t-dmm: Drop DMM table (comment).
+    
+    This info is in the wiki already, no need to duplicate in the code.
+
+commit faf720246ae6ec17e9ac47ee28c0320c1cfbd956
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Aug 1 19:14:49 2013 +0200
+
+    ols: Workaround for mac os X stray events
+
+commit ce4d26ddf96ceb62ada8ccd25347976ac5e4029f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Jul 31 13:09:48 2013 +0200
+
+    Various cosmetics, whitespace, consistency fixes.
+
+commit 1663ebe27f95a297c36dd8e9e494dec1fe9c6be7
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Jul 31 12:31:47 2013 +0200
+
+    udev rules file: Only list supported devices.
+    
+    The udev rules file should only list devices that are actually supported
+    by a driver in the current libsigrok version. Thus, drop all entries for
+    devices which will get support later on (at which point the respective udev
+    rule will be re-added again).
+    
+    Also, add a few missing entries.
+
+commit d1056603a00b92d12170e6e7d3da33473147c5f5
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Jul 31 12:22:06 2013 +0200
+
+    udev rules file: Drop URLs and lsusb.
+    
+    The URLs to vendor webpages and the full lsusb are in the wiki
+    already, no need to duplicate them here.
+
+commit f6eb2cb555aa79d57a20a754df66e83d897be668
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Jul 18 15:06:06 2013 +0200
+
+    Make sr_session_iteration() private
+
+commit 2b691be80654ca0cba58576c907c2c3e02e1f680
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Jul 17 22:17:17 2013 +0200
+
+    serial-dmm/uni-t-dmm: Drop Tecpel DMM-8060.
+    
+    The Tecpel DMM-8060 was added since we assumed it would be a rebadged
+    Voltcraft VC-820 (since we know the Tecpel DMM-8061 is a rebadged VC-840).
+    
+    However, according to the vendor webpage it doesn't have PC connectivity
+    at all, so drop it for now (until someone can confirm that it does or does
+    not actually have RS232/USB connectivity).
+
+commit e84e0096db5eb2b00300abe5e40487b190dd291d
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jul 16 17:18:20 2013 +0200
+
+    Fix build
+
+commit b979d0c9cbf3a697c0ac4b06031ffb18b5f60006
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jul 16 17:17:54 2013 +0200
+
+    kecheng-kc-330b: Code cleanup
+
+commit d406dccd6a7486d3a2913338d4d023aa93322de3
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jul 16 15:58:46 2013 +0200
+
+    lascar-el-usb: Don't close device after acquisition
+
+commit 85ed4ab3bae4e5a6fbc741c4c8f8e2d9923e9594
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jul 16 15:58:11 2013 +0200
+
+    kecheng-kc-330b: Acquisition from stored logs
+
+commit b483be7456fbc2e29efa50a49f6e8d60a8107527
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jul 15 14:14:28 2013 +0200
+
+    Add sr_session_iteration() API function
+
+commit f336618c3d1dc766da1c9f8ba46b322de9c746fa
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jun 25 22:00:29 2013 +0200
+
+    kecheng-kc-330b: Check device status before acquisition
+    
+    Can't really count on it either way though, the device is just
+    too flaky to conclude whether it's going to work or not, regardless
+    of the status returned.
+
+commit df03552894dc80e2de6f818622936663c5b05946
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jun 25 14:09:01 2013 +0200
+
+    kecheng-kc-330b: Live SPL acquisition
+
+commit bc7be4a9f4940dd9708208bddab87bd190ef816f
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jun 24 13:24:43 2013 +0200
+
+    kecheng-kc-330b: Implement all SR_CONF options
+
+commit c8bab81c5c862868ea8bf7e72d240c8fc24627e7
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jun 21 15:58:08 2013 +0200
+
+    Add Kecheng KC-330B
+
+commit a8806f032cb0fe3d86d9c75ed7069d6bdf6c78ea
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jun 21 15:57:48 2013 +0200
+
+    kecheng-kc-330b: Flesh out driver, add scan functionality
+
+commit ed759a08351394a060ad9352bf2617d41bdeea28
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Jun 20 21:31:31 2013 +0200
+
+    kecheng-kc-330b: Initial driver skeleton.
+
+commit ab4bb6eb7c6d7ab2eb212088a764fb696726c8dc
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jun 4 15:32:20 2013 +0200
+
+    ikalogic-scanaplus: Initial driver implementation.
+
+commit fdf4a1f5a0a04046ec014786b4a8fce125e1163c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Jun 21 17:15:10 2013 +0200
+
+    ikalogic-scanaplus: Initial driver skeleton.
+
+commit a7a163a795c9ad8cb06b5fe5458d7c98c405bf5a
+Author: Florian Knodt <git at adlerweb.info>
+Date:   Fri Jul 5 14:02:50 2013 +0200
+
+    Support for UNI-T UT60A/E multimeters via RS232 or USB
+
+commit fb8d593cfea094dd50d74873c8c00445eb0a040f
+Author: Marc Schink <sigrok-dev at marcschink.de>
+Date:   Tue Jul 2 21:52:23 2013 +0200
+
+    Use GET_REPORT request for device to host transfer.
+
+commit f05e7b7a9bf32388afc5dad77448621164887b7c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jun 22 17:12:38 2013 +0200
+
+    error.c: Simplify and shorten.
+
+commit 45bb47a7f7ea3062b7df1e505fb6687f63d6c1e0
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jun 22 17:05:57 2013 +0200
+
+    README.devices: Minor updates.
+
+commit c134574938ef5746775ac62e10025da34d83ae47
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jun 22 16:53:13 2013 +0200
+
+    uni-t-dmm: Add support for the Voltcraft VC-830.
+
+commit 6045b91aa43bd824db528e2cc52d93ebf8a819d4
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jun 22 16:48:00 2013 +0200
+
+    serial-dmm: Add support for the Voltcraft VC-830.
+
+commit 32be5b22462fa271c8837694d7f242a0bda2f2f7
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Jun 21 15:18:33 2013 +0200
+
+    configure.ac: Move an AM_CONDITIONAL to the correct location.
+
+commit 1f36a6c6852d175b5b0ad37bd5da8da039cc2896
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Jun 21 15:11:36 2013 +0200
+
+    configure.ac: Fix build when libusb-1.0 not available.
+    
+    The IKALOGIC Scanalogic2 needs libusb-1.0, thus disable this driver when
+    libusb-1.0 cannot be found.
+
+commit cea26f6e9f1a58f28a4b790756a2f95dcf0eaa9d
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Jun 20 14:35:34 2013 +0200
+
+    cem-dt-885x: Support for retrieving stored samples
+
+commit 662172d4f4eaada1b4a107317ca085c80ff38954
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Jun 19 12:23:30 2013 +0200
+
+    cem-dt-885x: Support for SR_CONF_DATA_SOURCE
+    
+    This device can do both live and memory-based acquisition.
+
+commit 6caeef6ee5795232b78c8986619f8919e2b09c8c
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Jun 19 12:18:00 2013 +0200
+
+    Add SR_CONF key for data source
+
+commit 4c22355f046fefff812042ef9764199df17fb809
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jun 17 15:46:14 2013 +0200
+
+    cem-dt-885x: Support for powering off the device
+
+commit 32de50b7f3f0155589d90b273cac6b0c3dcfeec6
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jun 17 11:54:37 2013 +0200
+
+    Add SR_CONF key for powering off a device
+
+commit f157b2eebb8523792bd085eeb8fb3632b5d4c172
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jun 17 01:26:25 2013 +0200
+
+    cem-dt-885x: Support for sound pressure level measurement range
+
+commit 8417ebad122cfade0f9ae6db6cbd8e7249156753
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jun 17 01:25:41 2013 +0200
+
+    Add SR_CONF key for sound pressure level measurement range
+
+commit 0cd9107dfb6fc36d816fd93a7b45dc2e0a990578
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jun 16 13:23:58 2013 +0200
+
+    cem-dt-885x: Fix datalog on/off setting in max/min hold mode
+    
+    As it turns out, the device randomly decides to send no logging state
+    info when max hold or min hold mode is enabled.
+
+commit a90e480cdc808d0c91eecc6b5078e745a751882b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jun 16 12:14:09 2013 +0200
+
+    cem-dt-885x: Support for max/min hold modes
+
+commit 9fd6bc205433eae242960e9e976d28ac0fd20254
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jun 16 12:12:20 2013 +0200
+
+    Add SR_CONF keys for max/min hold modes
+
+commit 1487ce4fbc0368058d16d42666fd8703e976f072
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Jun 15 13:00:41 2013 +0200
+
+    cem-dt-885x: Support for changing time weighting
+
+commit be73391982fc49c9eab45f6863eaca08e76a8b48
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Jun 15 12:17:55 2013 +0200
+
+    cem-dt-885x: Support for changing frequency weighting
+
+commit fd8854c4d030288be1007a4f81e0ba1228a9dbac
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Jun 15 12:09:31 2013 +0200
+
+    Add SR_CONF keys for sound pressure level time and frequency weighting
+
+commit e1af0e85b9b48b309f3552bceeed81d356735a33
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Jun 13 14:33:15 2013 +0200
+
+    cem-dt-885x: Support for turning data logging on/off
+
+commit 3e62166ed3d0a2763b3627b5434b599a4b65c479
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Jun 13 14:23:06 2013 +0200
+
+    Add SR_ERR_TIMEOUT
+
+commit 5f2a4aff4bbea36044203e700901973520f285a1
+Author: Florian Steinhardt <mail at floriansteinhardt.de>
+Date:   Tue Jun 11 20:35:57 2013 +0200
+
+    added Voltcraft M-3650D Multimeter
+
+commit 14cf708fef6d1dfd371923c7749f8cecd8a896a2
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Jun 12 16:04:23 2013 +0200
+
+    cem-dt-885x: Send last measurement at normal rate in hold mode
+    
+    The device only sends the "hold" token otherwise, which clashes somewhat
+    with other devices. This makes the device more predictable for frontends.
+
+commit bc1143280f7ca878e1309a1d1c0899275ff32d27
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Jun 12 15:45:37 2013 +0200
+
+    cem-dt-885x: Hold off measurements in max/min hold mode
+
+commit e37c4b3959052691a9e9d9ec4cfcdf0f8c6e36e1
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Jun 12 13:10:56 2013 +0200
+
+    cem-dt-885x: Live SPL acquisition
+
+commit 7fb8279c9b7e1e7f564725970bbafff74f5d2394
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jun 11 23:33:25 2013 +0200
+
+    cem-dt-885x: Flesh out driver, add scan functionality
+
+commit 8fa9368eb41c7cb040a9eaef34aecc9f8a9e6d7e
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Jun 8 01:12:10 2013 +0200
+
+    cem-dt-885x: Initial driver skeleton.
+
+commit 28083961fbbd7ff76ee1199d3aebde21dded77ab
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jun 11 18:55:47 2013 +0200
+
+    scanalogic2: Only print actual state changes in the log.
+
+commit 9526f2d4f80968e9b2d00442fd4705d6902db589
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jun 11 18:55:47 2013 +0200
+
+    scanalogic2: Replace %i with %s where needed.
+
+commit 79914b3a62adb1b0b054d23c2721ce80eb7ba9ea
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jun 11 18:55:47 2013 +0200
+
+    scanalogic2: Shorten a few function name prefixes.
+    
+    The driver-private helper functions in protocol.c can have a shorter
+    prefix to make the code look nicer.
+
+commit c824eb6323282def1cb7d6cf03b6c00c7a060810
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jun 11 18:55:47 2013 +0200
+
+    scanalogic2: Cosmetics, whitespace, typos, etc.
+
+commit e52e712d05419e4387704262a07e00904b2acbed
+Author: Marc Schink <sigrok-dev at marcschink.de>
+Date:   Mon Jun 10 10:10:13 2013 +0200
+
+    Initial driver for IKALOGIC Scanalogic-2
+
+commit 16e76baec9b1df806e46d4da61269375924ab950
+Author: Marc Schink <sigrok-dev at marcschink.de>
+Date:   Fri Jun 7 20:34:40 2013 +0200
+
+    ikalogic-scanalogic2: Initial driver skeleton.
+
+commit eea49cf10d4cf5b990dcf24b4ead2977a5f36a6e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Jun 2 16:54:31 2013 +0200
+
+    ols/link-mso19: Consistency fixes.
+    
+    Use the same setup/ordering/naming for the cleanup/dev_clear functions
+    as all other drivers do.
+
+commit 1c2d542df2bad5a719863d5c5cb38334c80e2ac6
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Jun 2 16:43:26 2013 +0200
+
+    demo: Use std_dev_clear().
+
+commit 3b412e3a305cf06ac9bbb91ca5025d1712617b71
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 31 16:09:57 2013 +0200
+
+    s/clear_instances/dev_clear/.
+    
+    Consistently use the same name for the dev_clear() API callback
+    everywhere.
+
+commit f6beaac55ca58c406d6621038abe57c16a47e87f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 31 15:46:57 2013 +0200
+
+    std: Drop hw_ from function names.
+    
+    The per-driver API calls no longer have a hw_ prefix (e.g. hw_init()
+    became init() and so on), so drop the 'hw_' from the std versions
+    for those API callbacks too.
+
+commit 3678cf73fea3c7903eb8887d8bb0dec61cb09e6e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 31 15:33:58 2013 +0200
+
+    asix-sigma: Use std_dev_clear().
+
+commit c43cf4d40e2b73d992c73c340a887888f05595e0
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 31 15:28:43 2013 +0200
+
+    alsa: Use std_dev_clear().
+
+commit fa85f376301dd43232032867f8df834e746060c6
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 31 15:19:53 2013 +0200
+
+    rigol-ds1xx2: Use std_dev_clear().
+
+commit dec6c583a2d8097ef3214b5d37432ef8edfbfb3a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 31 15:18:47 2013 +0200
+
+    hantek-dso: Simplify cleanup().
+
+commit 658636f1c934b5b865efd0b4a8202603c577dd0b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 31 15:18:22 2013 +0200
+
+    nexus-osciprime: Use std_dev_clear().
+
+commit c9d622a4208813966ab5ae40a444fe136c7b2cea
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 31 14:25:33 2013 +0200
+
+    lascar-el-usb: Use std_dev_clear().
+
+commit 771bd216fad9ad09666b4a41712e7fcb33ed6d9e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 31 14:20:34 2013 +0200
+
+    fluke-dmm: Use std_dev_clear().
+
+commit 732899f8cf87798b61d67a1c28e4bb4d46146cae
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 31 14:17:38 2013 +0200
+
+    colead-slm: Use std_dev_clear().
+
+commit 676c28a846ed8854c35e4d9b8914ff9a0f5a9b26
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 31 14:13:20 2013 +0200
+
+    agilent-dmm: Use std_dev_clear().
+
+commit 8d18d266f5cff373287e7bb122fa63581a4f88af
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 31 14:10:59 2013 +0200
+
+    victor-dmm: Use std_dev_clear().
+
+commit 40bbc64293f7a93cc25e594801315c6990b3bb03
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 31 14:00:30 2013 +0200
+
+    brymen-dmm: Use std_dev_clear().
+
+commit adf33ecce5e0bc2dff53087b01da6d5baaa89ee3
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue May 21 20:54:42 2013 +0200
+
+    csv output: Fix incorrect ordering of the probes.
+    
+    The comment for the CSV output module says probes are ordered e.g.
+    0,1,2,3, but the actual values were in the 3,2,1,0 order.
+    
+    We're fixing this by making the order of the probe values 0,1,2,3 too
+    for now, but this will become a configurable option later on.
+    
+    Thanks Patrick Servello <patrick.servello at gmail.com> for the patch.
+
+commit ee8ddd8f5aadee71749882ba897c29e3c12fe1ed
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 10 20:59:42 2013 +0200
+
+    Always link against the math library.
+    
+    This fixes bug #115.
+
+commit 96ea73db236ce6c0146f9a33c280b7cbcdc500cb
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 10 20:31:25 2013 +0200
+
+    session_driver: Fix return codes, cosmetics.
+
+commit 6078d2c99619233173d4536b74258c15e6be73ba
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 10 19:37:54 2013 +0200
+
+    Use consistent API callback function names.
+    
+    This now matches what the 'new-driver' tool generates.
+
+commit 8111446ae005bb4feb8859dd2cd12f46ec4d6050
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 10 19:16:25 2013 +0200
+
+    zeroplus: Properly set inst_type to SR_INST_USB.
+
+commit d6445cb0da6e6406f6cbf24f89bd570850d44fb1
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 10 19:06:47 2013 +0200
+
+    zeroplus: Use std_dev_clear().
+
+commit 8dca646ef9f045751353aa0929c7be25a29fcb2e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 10 18:59:46 2013 +0200
+
+    uni-t-dmm: Use std_dev_clear().
+
+commit 3f0513bac1eaed3273398b362c35c1494fe94850
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 10 18:53:42 2013 +0200
+
+    serial-dmm: Use std_dev_clear().
+
+commit 97900799618d9d529f69eeed94d28349bc671d8d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 10 18:40:13 2013 +0200
+
+    chronovu-la8: Use std_dev_clear().
+
+commit decfe89d4e8c0902c1ca56933f2da30b97e9fa72
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 10 18:30:32 2013 +0200
+
+    Drop some lines that are no longer needed.
+
+commit 0bdb4f2e4aae1f9589897fc4b47cd012e9a25e49
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 10 17:56:53 2013 +0200
+
+    tondaj-sl-814: Use std_dev_clear().
+
+commit 25e7adada7a398542eeca703d23972a9eb81cc7a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 10 17:54:53 2013 +0200
+
+    mic-985xx: Use std_dev_clear().
+
+commit 2a052cc4d68acac9ac4847adba219d418df628f1
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 8 19:49:23 2013 +0200
+
+    Use consistent naming for internal libtool helper libs.
+    
+    This now also matches what the 'new-driver' tool generates.
+
+commit 9e165e742fcaf247fe36644192194e59a02698aa
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 8 19:33:30 2013 +0200
+
+    Use consistent HW_ name prefixes everywhere.
+    
+    Older drivers used LA_* previously, we now use HW_* everywhere though.
+
+commit 576ff5b0ba72cf9d682cf62736b4b9dc2048647d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun May 5 17:14:20 2013 +0200
+
+    device.c: Add missing @since markers.
+    
+    Also, add Doxygen comments for functions which don't have any yet.
+
+commit 01169de39195e2e54e4534504b60ed2408129b81
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 8 16:41:18 2013 +0200
+
+    Doxyfile: Set version to "unreleased development snapshot".
+
+commit 7ab89f4827d516313cafc9b7b9670ee99dc9c584
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 8 16:40:45 2013 +0200
+
+    Re-enable link-mso19 and nexus-osciprime drivers.
+
+commit 9dc7a75e3d4bc4078b23c62626c359e5a9e73b57
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon May 6 20:44:26 2013 +0200
+
+    fx2lafw: Fix memory leak
+
+commit 03f4de8cf298b6ca8510f49377c2e8e43cc88516
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon May 6 00:42:18 2013 +0200
+
+    ols: Code cleanup
+    
+    This also fixes a memory leak.
+
+commit a006798b9979ed3b8a2803927727dfbd870277f7
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon May 6 00:40:17 2013 +0200
+
+    Fix various memory leaks
+
+commit 12a33563b9cfd14c6dbf23d89c644f4ba16d304f
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon May 6 00:36:50 2013 +0200
+
+    std: Fix memory leak, code cleanup
+
+commit 26aec7fdc4c5d1f3e7ec6c373b16b6605b4a6e38
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Apr 25 19:01:54 2013 +0200
+
+    Drop link-mso19/nexus-osciprime in preparation for release.
+    
+    These two drivers are currently unfinished and don't work, so disable
+    and "unhook" them for now in preparation of the next libsigrok release.
+    
+    They're still in the git repository, but not hooked up to the build
+    system, so that they won't get detected or built, and also don't end up
+    in the release tarball.
+    
+    Since link-mso19 is the only driver that currently requires libudev,
+    drop any reference to that, too.
+    
+    It should be relatively easy to apply this patch in reverse after the
+    release to bring back both drivers.
+
+commit a4fdbbe1c2d9e95982c48aea46773affd6812ec8
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat May 4 15:55:11 2013 +0200
+
+    Doxyfile: Set version number to 0.2.0.
+
+commit 7c3e7b43067d14fc717a0bf825e57ed959032771
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat May 4 15:22:45 2013 +0200
+
+    udev rules file: Add entry for the ZEROPLUS LAP-16128U.
+
+commit 048e8babf73565721707dd9e9ecf4f915941d23e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat May 4 15:17:50 2013 +0200
+
+    NEWS: Minor update.
+
+commit 6941f84568b0e362decdc25e6aecaf304dc670bb
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat May 4 15:12:20 2013 +0200
+
+    Fix libsigrok lib version (current:revision:age).
+    
+    The last release (libsigrok 0.1.1) had a lib version of 0:0:0.
+    
+    This release thus gets 1:0:0 according to the libtool manual guidelines.
+
+commit c5ffac414899eb7f0e187b8eb9d61e381d40f0a6
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat May 4 00:07:34 2013 +0200
+
+    uni-t-dmm: Add missing SR_CONF_LIMIT_MSEC support.
+
+commit 29a27196a13de2ffd9b671185e4b464b9db9b549
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 3 21:59:32 2013 +0200
+
+    s/DRIVER_LOG_DOMAIN/LOG_PREFIX/.
+    
+    This is more correct anyway, and also a bit shorter and more readable.
+
+commit 06c45a66f76f986cd845a05fdee36956b1339621
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 3 14:03:49 2013 +0200
+
+    Minor whitespace fixes.
+
+commit e6b2b4df9dcfaf9eb6fa10f94e0aa5e039230e21
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu May 2 23:37:23 2013 +0200
+
+    README.devices: Document how to make some DMMs log.
+
+commit 456dfd9f704885c8ffbeb5dd1c2b281d27fff053
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu May 2 19:03:47 2013 +0200
+
+    NEWS: Various updates and minor fixes.
+
+commit a0c7e23ad871c0e77dd8632c76f87bec1c6fd002
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu May 2 17:37:55 2013 +0200
+
+    Fix the build when libusb is not available.
+    
+    Thanks Simon Richter <Simon.Richter at hogyros.de> for reporting.
+
+commit 3a277f3b2b01da3d7d1e26ddbb30471db68fc11c
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed May 1 14:54:44 2013 +0200
+
+    Deal with uninitialized drivers
+
+commit c2fa697afa86a8e6f37bef13acb5b8532714274e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 1 03:16:47 2013 +0200
+
+    serial-dmm: Add Tecpel DMM-8060 support.
+
+commit b38e08fbb7b6fec5ff22495f13f039b1f7218361
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 1 03:13:15 2013 +0200
+
+    serial-dmm: Add Tecpel DMM-8061 support.
+
+commit 4554314c4f72d8df69b7236cb19d15a00fdceaeb
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 1 03:04:46 2013 +0200
+
+    uni-t-dmm: Add Tecpel DMM-8060 support.
+    
+    This is _very_ likely to be a rebadged Voltcraft VC-820, treating as such.
+
+commit b6bad47c91a7cbc19571cbe49918a0612ad2babe
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 1 03:00:08 2013 +0200
+
+    uni-t-dmm: Add Tecpel DMM-8061 support.
+
+commit 2451a20ff5137d178ed4a02ee04076c6eae97235
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 1 02:10:56 2013 +0200
+
+    fs9721: Factor out common code from serial-dmm.
+    
+    These functions are FS9721 specific (and DMM specific), and can be used
+    from various drivers (e.g. serial-dmm or uni-t-dmm or possibly others).
+
+commit 48535594664cc5d55db428cd8ca5ffba328be05a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 1 01:56:30 2013 +0200
+
+    uni-t-dmm/serial-dmm: Handle Voltcraft VC-840 temperature.
+
+commit ad00a54da6a17c881881d2ed7a3f3fe41170fa26
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 1 01:02:46 2013 +0200
+
+    fs9922: Fix beep mode.
+
+commit 649a4cd672e5ea14707c4591dd0426fdd87ddd5a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 1 01:00:54 2013 +0200
+
+    fs9922: Fix diode mode parsing.
+
+commit 767aae30edce24c9e5b8b6e083653b2f68dbc922
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 30 20:28:29 2013 +0200
+
+    uni-t-dmm: Fix incorrect UNI-T UT61D baudrate.
+
+commit 695d0e1efa819dc98914ce1baec388c8734e98a7
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 30 20:27:04 2013 +0200
+
+    uni-t-dmm: Add support for the Voltcraft VC-840.
+    
+    This DMM is already supported via the serial-dmm driver when using the
+    RS232 cable. The uni-t-dmm support makes it usable with the USB/HID
+    cable too.
+
+commit bbef5e326de1669b039413d8753fceda7281e936
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Apr 29 20:23:21 2013 +0200
+
+    uni-t-dmm: Add support for the UNI-T UT61E.
+    
+    This DMM is already supported via the serial-dmm driver when using the
+    RS232 cable. The uni-t-dmm support makes it usable with the USB/HID
+    cable too.
+
+commit ae3a59de62e5912d68d8738a78a4403146cbfda5
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Apr 29 20:15:02 2013 +0200
+
+    serial-dmm: Add support for the UNI-T UT61D.
+    
+    This DMM is already supported via the uni-t-dmm driver when using the
+    USB/HID cable. The serial-dmm support makes it usable with the RS232
+    cable too.
+
+commit 3ece1dff6ce9d29021215a1aa4a4ae8cff25aa49
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Apr 28 08:13:15 2013 +0200
+
+    uni-t-dmm: Use sr_dev_inst to store connection handle.
+
+commit d9a7c349ed731f826b166c12f6d03dbd973cc0ec
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Apr 28 08:01:51 2013 +0200
+
+    brymen-dmm: Use sr_dev_inst to store connection handle.
+
+commit af51a7718eb22e9630107af814db6ae9f179a969
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Apr 30 16:03:37 2013 +0200
+
+    output: Use sr_config_get() wrapper
+    
+    This obviates the need for a valid driver, and thus makes converting
+    from any (non-sr) input format to any output format possible; the only
+    thing missing is the samplerate.
+    
+    Fixes bug 105.
+
+commit 0a7da5f8c9f1c6656672152ad48d76b5a4cd7ecd
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Apr 30 09:55:44 2013 +0200
+
+    fx2lafw: Keep track of our own libusb fds
+
+commit 037286445116d0f4f7f9b16a4a7353f3be207ff0
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Apr 30 00:04:39 2013 +0200
+
+    Don't remove stray source from the session after stopping
+    
+    It's up to the drivers and frontends to remove the sources they
+    added to the session.
+    
+    Also don't tell the driver about a forced session stop more than
+    once, because it's sloppy.
+    
+    Fixes bug 62.
+
+commit 2a67abfe349f26f0cc9d34e36f48b250cb9cac50
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 29 19:02:26 2013 +0200
+
+    fx2lafw: Properly initialize operational state before acquisition
+
+commit 0f75d6f5a9b5d9d479dc03d67a8c828f99dce8f0
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 29 12:39:26 2013 +0200
+
+    ols: Don't close serial port after acquisition is done
+
+commit 681803dfdeeaae66c48d6c45da194be0c6789deb
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Apr 28 22:35:42 2013 +0200
+
+    Don't try to close devices when removing them from the session
+    
+    That's the frontend's job.
+
+commit 115f82939661da6ad2d26d5ceca709bbc0ad25b5
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Apr 22 21:57:51 2013 +0200
+
+    NEWS: Add most important items since last release.
+
+commit a5e44c3247ae64ab1a65e7c6ebe6d66c6ab0a0a1
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Apr 24 19:14:52 2013 +0200
+
+    tondaj-sl-814: Use sr_dev_inst to store connection handle.
+
+commit 44f91e29509125a54cfd975689e6d10379645f08
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Apr 27 19:06:27 2013 +0200
+
+    unittests: Disable a broken test for now.
+
+commit 50c604f50bf33e68ac67caa8ebad20b87b3aacc1
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Apr 27 18:27:32 2013 +0200
+
+    Don't automatically clear known instances from USB drivers on scan
+    
+    This invalidates previously returned sr_dev_inst pointers, which a
+    frontend may be holding. It's the frontend's responsibility to clear
+    the list of instances a driver keeps track of by calling
+    
+    	sr_dev_clear(driver);
+    
+    if it wants a completely new scan done.
+
+commit c2523f221364c0df51b8093693a246a713633912
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Apr 27 18:24:50 2013 +0200
+
+    Explicitly initialize all struct parameters on init
+
+commit 17f63de642c3cb613f91eabd2e19ebed6785f755
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Apr 27 17:29:46 2013 +0200
+
+    Fix output API receive() function
+    
+    This changes the new output API's recv() to receive(), and has it
+    return an integer status code. The output of the function, if any,
+    is stored in a new parameter as a pointer to a newly allocated GString.
+    
+    All output modules using this API have been adjusted.
+
+commit 9c48c2e91ecdb4b0ce364f55084e8f882b7a3bf1
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Apr 26 23:20:33 2013 +0100
+
+    Remove SR_MAX_NUM_PROBES, which is now no longer used.
+
+commit a1be7b6c3f1f00644bdae96317f14b99fe31cf3d
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Apr 26 23:16:30 2013 +0100
+
+    vcd output: Replace fixed length array of indices with GArray.
+
+commit d601c0e9b37be9174c8a4447aa05aeb7be82be73
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Apr 26 23:00:51 2013 +0100
+
+    vcd output: Eliminate unnecessary array of probe names.
+
+commit 90f680ff006e5ae2fd4935bd885a14bd9927fd99
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Apr 26 22:50:09 2013 +0100
+
+    gnuplot: Eliminate fixed-size header buffer based on max probes.
+
+commit deb09083385deab1a8afc2a585200de043444464
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Apr 26 22:29:41 2013 +0100
+
+    gnuplot: Remove unnecessary array of probe names.
+
+commit 1c5b099a1312ae64307fb7d9a0030643936a3636
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Apr 26 22:26:14 2013 +0100
+
+    csv: Remove unnecessary array of probe names.
+
+commit 91a44f50f0817b32c869f9623b86a6e698ba8e19
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Apr 26 22:20:05 2013 +0100
+
+    chronovu-l8: remove unused array of probe names.
+
+commit d53e4e8d92242488642211f441dacba29937104d
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Apr 26 22:14:57 2013 +0100
+
+    text: Use a GSList of enabled probe names, not an array.
+
+commit db9679afc9f46bdf038efabd3ac69983d15f89cf
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Apr 26 20:52:25 2013 +0100
+
+    vcd input: Use a GSList rather than fixed size array of probes.
+
+commit b050fc481bf8fc2a55277cc3fc3b62121932e1bb
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sat Apr 27 00:13:02 2013 +0100
+
+    vcd output: fix for big-endian architectures.
+
+commit 9c178ffa50da5bd6978d26989b79936dc341f308
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Apr 26 23:57:44 2013 +0100
+
+    gnuplot: fix for big-endian architectures.
+
+commit 3292535c878ec82756c122facddf61bbd81bec18
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Apr 27 14:24:47 2013 +0200
+
+    output/ols: Use new API
+    
+    This now properly supports samplerate changes coming in from
+    SR_DF_META packets, and also fixes bug 99.
+
+commit 409a811b8c078341185badadda8f4be380a5f88d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Apr 27 10:49:52 2013 +0200
+
+    error.c: Add SR_ERR_DEV_CLOSED.
+
+commit 3a581560f1288b4cecc4ab885c85ac7603dd21db
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Apr 26 21:35:18 2013 +0100
+
+    ascii: fix for big-endian architectures.
+
+commit ddb292571d03ee2e13100d749edcf0dceed5d9a2
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Apr 26 21:22:36 2013 +0100
+
+    bits: Remove unused code.
+
+commit 9275d232089be359ad6ffe3a7b65d6230ff912b3
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Apr 26 21:17:36 2013 +0100
+
+    hex: fix for big-endian architectures.
+
+commit 542dbd185b2e01e61df8a70a2ab850f5cfe03271
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Apr 26 21:14:00 2013 +0100
+
+    bits: fix for big-endian architectures.
+
+commit b9470914d045f05e445e9f25a3b4f0cc79bc6681
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Apr 26 22:17:41 2013 +0200
+
+    Remove sr_rational
+
+commit bc653a56781de54f90e9fb08b39e6c9a596cc6af
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 26 23:39:24 2013 +0100
+
+    uni-t-dmm: Do proper detection of packets in the stream.
+    
+    Also, various fixups in the driver.
+
+commit c8852687778a33b9de218af800eec4ae7e3848a6
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Dec 19 19:01:54 2012 +0100
+
+    uni-t-dmm: Make driver more similar to serial-dmm.
+
+commit 7381251e33611b6c06f3adedfcf2e1943453670e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Apr 26 19:56:02 2013 +0200
+
+    common/dmm: Drop obsolete *is_packet_start() functions.
+
+commit 913abe83214f68d1743c555aa3fbe112db48a0cb
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Dec 19 22:47:26 2012 +0100
+
+    fs9922: Use common DMM API.
+    
+    Use the same functions and structs as the other DMM protocol parsers
+    in hardware/common/dmm. Among other things, this allows the functions
+    to be used from drivers in a generic way, e.g. in serial-dmm, uni-t-dmm,
+    and possibly other drivers.
+
+commit 6d0369591b7b30009bf497a5bb285afc7f431ad8
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Apr 26 13:35:19 2013 +0200
+
+    README: Add "Copyright and license" section.
+
+commit 695f32d89d678b20896e34affc74b4363b686387
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Apr 26 10:47:34 2013 +0200
+
+    Bring back link-mso19/nexus-osciprime for now.
+    
+    This patch will be re-introduced later.
+
+commit 9d1164f9a12c218def0e898e4d28fcd55f2fa8cd
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Apr 25 19:01:54 2013 +0200
+
+    Drop link-mso19/nexus-osciprime in preparation for release.
+    
+    These two drivers are currently unfinished and don't work, so disable
+    and "unhook" them for now in preparation of the next libsigrok release.
+    
+    They're still in the git repository, but not hooked up to the build
+    system, so that they won't get detected or built, and also don't end up
+    in the release tarball.
+    
+    Since link-mso19 is the only driver that currently requires libudev,
+    drop any reference to that, too.
+    
+    It should be relatively easy to apply this patch in reverse after the
+    release to bring back both drivers.
+
+commit 8d3764aacad94d4bf44cbfdfd4a45dad995eeb33
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Apr 25 17:42:20 2013 +0200
+
+    README.devices: Fix typo.
+
+commit 0e77b7cab31186b35d461e7d4ad3ce8a577857ee
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Apr 25 00:15:49 2013 +0200
+
+    python: Add Session.open_device().
+
+commit 57dd5e63ecc6cad49f31f94ed0ef9a5336330c4a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Apr 24 23:43:56 2013 +0200
+
+    python: sr_config's value field is called 'data'.
+
+commit 3124e80bfe6189d52c5aec9a8c1cacb6ee852b91
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Apr 24 17:48:04 2013 +0100
+
+    python: Support keyword arguments to scan()
+
+commit f245b7669e7ffb7591dc1b1b7087e4352738c84d
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Apr 24 17:47:40 2013 +0100
+
+    python: Add a ConfigKey class.
+
+commit 05cfe1147a9f85d9d3db41d6025c708898a66be9
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Apr 24 14:47:07 2013 +0100
+
+    python: Add conversion functions to/from GSList *
+
+commit bd7bfe8c5140d459092f93f9ffc3130a487f5d58
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Apr 24 23:06:50 2013 +0200
+
+    Open virtual device before loading file
+
+commit e73ffd4238c6d1be58d3fcdcf7f100200f033856
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Apr 23 15:14:42 2013 +0200
+
+    Enforce open device before config_set()/dev_acquisition_start()
+
+commit efdecf4c0553ce00ea2a6365212f5fe305496fed
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Apr 23 00:21:57 2013 +0200
+
+    Add sr_dev_open()/sr_dev_close()
+    
+    Frontends will be required to open a device before using
+    sr_config_set() or starting acquisition.
+
+commit 46a743c1fa77b1b68ada2b642c095b4f9034edce
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Apr 24 19:07:46 2013 +0200
+
+    Whitespace fixes
+    
+    Damn editor.
+
+commit a31a4d371f3c3925a9d3a0eefa472147e7b36748
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Apr 24 03:05:25 2013 +0200
+
+    fx2lafw: Minor cleanup
+
+commit 294dbac724d5b36acea17366057bb81c70a265bb
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Apr 24 03:04:12 2013 +0200
+
+    hantek-dso: Support conn scan parameter
+
+commit cc9fd2d29c5ff4ab2509b6bb5b33a16304fafa55
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Apr 24 02:09:49 2013 +0200
+
+    rigol-ds1xx2: Code cleanup
+
+commit 9bd4c95606668bdc58a6df3c30bcd91f288a4ea9
+Author: Martin Ling <martin-git at earth.li>
+Date:   Mon Apr 22 16:12:06 2013 +0100
+
+    rigol-ds1xx2: Use common serial code.
+
+commit ca55277ca8bed14dd569b793dc578212898bb1fb
+Author: Martin Ling <martin-git at earth.li>
+Date:   Mon Apr 22 14:59:55 2013 +0100
+
+    rigol-ds1xx2: Accept SR_CONF_CONN.
+
+commit 886bd5e05686617c928be2d600ce91ed298a2331
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 23 23:06:02 2013 +0200
+
+    mic-985xx: Use sr_dev_inst to store connection handle.
+
+commit 31e537725096d578e12923b811d2da79187363e4
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 23 22:54:02 2013 +0200
+
+    Fix minor warning with some compilers.
+
+commit 50985c2019b2b5a6ce394589d89ee925b4f5e3a9
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 23 22:24:30 2013 +0200
+
+    GPL headers: Use correct project name.
+
+commit 1e1bfcd0fef7c397b3d8fc6cd244263e6828a5da
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 23 19:07:15 2013 +0200
+
+    serial-dmm: Use sr_dev_inst to store connection handle.
+
+commit 625cc7834a26333b77f4a43f3c74b4aba3f41627
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Apr 23 10:05:48 2013 +0200
+
+    More python build stuff to ignore
+
+commit f99e32affc3a18a2a6b45c988bc440013a8b2e4e
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 22 15:55:06 2013 +0200
+
+    sr_dev_inst_*() -> sr_dev_*()
+
+commit 609bfd753c4a813791a6f678f545940c6d331c20
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 22 15:00:04 2013 +0200
+
+    zeroplus-logic-cube: Use sr_dev_inst to store connection handle
+
+commit 459a0f2623686472b134735ae37a52f0d61d715e
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 22 13:40:40 2013 +0200
+
+    ols: Use sr_dev_inst to store connection handle
+
+commit 2e5b73c00c7329c9b6ef7bf8f626a22884eac5c0
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 22 13:33:31 2013 +0200
+
+    ols: Fix stack clobbering at start of acquisition
+    
+    This off-by-one was clobbering the stack since introduced in a803c0db4d58.
+    However it only set one bit, and that generally appears to have been set
+    already, so this rarely affected anything. But when it did, it affected
+    a pointer, causing a segfault.
+
+commit 919681f0e8b4681b2af64db72abc1945f3b4adb2
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 22 01:07:35 2013 +0200
+
+    fluke-dmm: Use sr_dev_inst to store connection handle
+
+commit aa7066353c9a54d90695fca3b303e1476dd772fd
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 22 00:27:11 2013 +0200
+
+    colead-slm: Use sr_dev_inst to store connection handle
+
+commit fb3a15059938770a064fb7d35a813cfa20d8e363
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Apr 21 21:44:31 2013 +0200
+
+    agilent-dmm: Use sr_dev_inst to store connection handle
+
+commit e31d410d26c7377de83d46c1ce80525e2dc7d23b
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Apr 21 20:42:22 2013 +0100
+
+    rigol-ds1xx2: fix delay time.
+
+commit 1e2bd8af128529d686fb1ac449334a21b74d4fc0
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Apr 21 19:52:09 2013 +0100
+
+    python: fix Fraction -> GVariant tuple conversion.
+
+commit d2e0b1fa71b90faf1f7e77b72627868baf5e9135
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Apr 21 13:17:40 2013 +0100
+
+    rigol-ds1xx2: better error handling in hw_scan.
+
+commit 8bb2981df075082071b3edf2426a3444109726f0
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Apr 19 21:19:54 2013 +0200
+
+    victor-dmm: Allow configuration before the device is opened
+
+commit 522a34343f78eb55ff7213e34ff3e002867dbad3
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Apr 20 13:43:48 2013 +0200
+
+    Drop obsolete g_match_info_unref() workaround.
+    
+    We hard-depend on glib >= 2.32.0 now anyway, so this is no longer needed.
+
+commit ac070c7744471350e38836a58dd565750d96ce7f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Apr 19 20:19:14 2013 +0200
+
+    Add initial, lowlevel Ruby bindings.
+
+commit 91bea31f6bff799f90fc21201312505d37441981
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Apr 19 17:41:44 2013 +0100
+
+    python: unify pkg-config calls in setup.py.
+
+commit 0cd466ccd8f1149883f535868650d4236d0b7ab4
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Apr 19 17:30:44 2013 +0100
+
+    python: Use --cflags-only-I to get includes in setup.py.
+
+commit 9bbd6a6a0d8747538db2e1ef03e52e4fdcadfaa2
+Author: Martin Ling <martin-git at earth.li>
+Date:   Fri Apr 19 16:57:13 2013 +0100
+
+    python: Add classes for values of API enums.
+
+commit 816aed6c9157721c7123f1f29fe01f353278af22
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Apr 19 13:15:51 2013 +0200
+
+    python: Add a Log class to control libsigrok logging.
+
+commit 0021b077416c09dc72bef411e3768bbe87afdf56
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Apr 19 11:58:40 2013 +0200
+
+    python: config_get() now returns SR_ERR_NA.
+
+commit ac046ef8cf64098fc20030fe60b345cd563f72f8
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Apr 18 22:48:09 2013 +0200
+
+    victor-dmm: Support SR_CONF_CONN
+
+commit 0f1506497b615b3c935b9a7bce9af85390a09d24
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Apr 18 22:30:10 2013 +0200
+
+    lascar-el-usb: Support SR_CONF_CONN
+
+commit e2033d491753c5746ddbc0b8f29a5aa56c297ac3
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Apr 18 21:37:38 2013 +0200
+
+    hantek-dso: Consistently return SR_ERR_ARG if sdi is needed
+
+commit 38ab8dbec8b1944e06dd3a809229b106c5e628df
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Apr 18 21:36:25 2013 +0200
+
+    fx2lafw: Consistently return SR_ERR_ARG if sdi is needed
+
+commit c2ec42ce938bc38bfd72ca3959611baab326530a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Apr 18 17:45:17 2013 +0200
+
+    python: Add further properties to Analog class.
+
+commit 15574a3cecc14dcbed38464317e37ac9cfe2d220
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Apr 17 17:48:39 2013 +0100
+
+    python: Add Analog class.
+
+commit 624f5b4c1e329e74d6bb6e7fc0fce27945506567
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Apr 18 01:21:57 2013 +0200
+
+    hantek-dso: Support config_get(SR_CONF_CONN)
+
+commit 89befd46a8a12b0ba7867e73f7aec77a7dfc0add
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Apr 18 01:15:37 2013 +0200
+
+    fx2lafw: Support config_get(SR_CONF_CONN)
+    
+    This generates a bus.address conn string which can be used to
+    uniquely identify the given sr_dev_inst.
+
+commit 3bc55222c8503703ac76bc61fb9a5d2c101f0ed7
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Apr 17 17:26:46 2013 +0200
+
+    python: Add missing license headers.
+
+commit 08d59537c353c6980c5e9a0f8b0039f2ab5b0ba5
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Apr 17 15:38:33 2013 +0100
+
+    python: fix cdata to work with Python 3.x.
+
+commit 1cad2115477176001f44cbe8a46a3c74e650f866
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Apr 17 15:37:58 2013 +0100
+
+    python: Fix syntax to support Python 3.x.
+
+commit d8f6e041aa109f328612f6d7301411abde9e5134
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Apr 17 14:30:31 2013 +0100
+
+    python: Add high level API.
+
+commit a8d162f6d33f2d5112193d6539a08e9b7beac4d7
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Apr 17 14:03:38 2013 +0100
+
+    swig: Wrap additional GVariant operations.
+
+commit cccb59914799002df75299ec98da132fcccfaac0
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Apr 17 14:01:19 2013 +0100
+
+    python: Release GIL during libsigrok calls.
+
+commit a25932e08c6b7424fec07bb2295fadd613294075
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Apr 17 13:59:30 2013 +0100
+
+    python: Adding callback can fail, and refcount must be incremented.
+
+commit 0220626994c6bac7bce967fe6dc8804667cce03e
+Author: Martin Ling <martin-git at earth.li>
+Date:   Wed Apr 17 03:50:27 2013 +0100
+
+    python: use setuptools and put bindings into sigrok.core.lowlevel.
+
+commit d0eec1eea17c62d731e44fc0b3b436b78d0df718
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Apr 17 01:08:18 2013 +0200
+
+    hantek-dso: Mark connection as USB
+
+commit 949b3dc0916eed68ba6f3878300feb61ad858014
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Apr 17 00:49:18 2013 +0200
+
+    hantek-dso: Use std_dev_clear()
+
+commit 72f9d6dc5e4fb4bcc33c70e601f643d0ce5d1f3e
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Apr 17 00:42:06 2013 +0200
+
+    fx2lafw: No device context internals to clear
+
+commit ae5859fff08a8ccc8cba081d7500f75cc46114f7
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Apr 17 00:41:01 2013 +0200
+
+    Allow for sdi->priv helper function in std_dev_clear
+
+commit c118080b1db555c1eb226ea783fc186602c20315
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Apr 16 23:15:34 2013 +0200
+
+    hantek-dso: Store USB connection in sr_dev_inst
+
+commit 9bb2f327a9dd482f609b10e34f72e57816cd4531
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 16 22:19:00 2013 +0200
+
+    Python bindings: Small fix for Python 3 support.
+
+commit 415e6389ce2d57e9559a04f0e3523d111843a618
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 16 15:42:45 2013 +0200
+
+    chronovu-la8: Fix incorrect 0Hz samplerate being reported.
+    
+    This closes bug #93.
+
+commit 250a78c7d5d049edd8c4f792f9eee56eae773a0b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Apr 16 17:55:56 2013 +0200
+
+    fx2lafw: Use standard dev_clear() instead
+
+commit 49f00e13f72d11a9cac8523e0c1506dde138f218
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Apr 16 17:53:21 2013 +0200
+
+    Add driver helper std_dev_clear()
+
+commit 9e2e98640ac2b12545f4923a143d06d3896f8435
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Oct 1 03:03:24 2012 +0200
+
+    sr: add conn to sdi, for storing a ptr to device-specific connection info
+    
+    What's in conn depends on the long-ignored inst_type field.
+
+commit 0223135bfb6771d7749fa39cff64a78c7a84a674
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 16 12:54:11 2013 +0200
+
+    error.c: Add missing SR_ERR_ARG and SR_ERR_NA.
+
+commit 85222791a9f3722c1cf659cfd4e4144314dbeec0
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 16 12:48:58 2013 +0200
+
+    Doxygen: Add missing parameter docs.
+
+commit 63c290b9840d459a9dac5073b71db43688cc94e9
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 16 12:45:38 2013 +0200
+
+    Doxygen: Exclude bindings/.
+
+commit 1a64618a2f46bf4374a673dcfc413dce8771fe89
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 16 12:43:42 2013 +0200
+
+    Doxygen: Set SHOW_NAMESPACES=no.
+    
+    Since this is a C project, a "Namespaces" page is not really useful.
+
+commit 9fb5f2dfa6bcded8082677ed3b915ff6b880cfab
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Apr 13 18:58:11 2013 +0200
+
+    Doxygen: Add @since markers.
+    
+    Add @since tags to some (not all yet) public API functions, to document
+    in which release they were added (and/or in which release there were
+    API changes).
+    
+    Document the @since usage in HACKING.
+    
+    Also, add Doxygen docs for the functions in version.c.
+
+commit 22f8cb54d18bf4abd5a7513a509539f15570784c
+Author: Martin Ling <martin-git at earth.li>
+Date:   Tue Apr 16 03:33:56 2013 +0100
+
+    swig: wrap g_variant_new_uint64.
+
+commit d962ed92a118a8bc9d98e00f7a218a4cc9c71e69
+Author: Martin Ling <martin-git at earth.li>
+Date:   Tue Apr 16 03:11:48 2013 +0100
+
+    swig: include cdata interface.
+
+commit 966fcbe3e34de14b163987550d17b00dc84bf82e
+Author: Martin Ling <martin-git at earth.li>
+Date:   Tue Apr 16 03:02:52 2013 +0100
+
+    swig: add function to cast from void * to struct sr_datafeed_logic *
+
+commit 0849c7d3104efc098aa282d7e8b841506c386ea3
+Author: Martin Ling <martin-git at earth.li>
+Date:   Tue Apr 16 02:55:39 2013 +0100
+
+    python: support datafeed callbacks implemented in python.
+
+commit ab0340c804c31a146977907e90d7b1d012f401a1
+Author: Martin Ling <martin-git at earth.li>
+Date:   Tue Apr 16 02:55:11 2013 +0100
+
+    swig: use standard wrappers for integer types.
+
+commit 2726474a619e5d9a9bfcf797a5e306f4496a4545
+Author: Martin Ling <martin-git at earth.li>
+Date:   Mon Apr 15 21:08:55 2013 +0100
+
+    Add a void *cb_data parameter to datafeed callbacks.
+
+commit bd6fbf628abef9fab5293e016ad11e1a1ac4a0a9
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Apr 16 02:33:03 2013 +0200
+
+    drivers: return SR_ERR_NA on unsupported config key
+    
+    Fixes bug 89.
+
+commit f02121f8d2623a7b8cbc87b75cf529e0a9cfd7d5
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 16 00:58:29 2013 +0200
+
+    Python bindings: Fix reported libsigrok version.
+    
+    Use 'pkg-config --modversion libsigrok' to get the libsigrok package
+    version. 'pkg-config --version libsigrok' ignores the argument and just
+    reports the version of pkg-config itself.
+
+commit 8dc93c841f73dd2dbb252c1be42701a5e03d2f26
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 16 00:57:00 2013 +0200
+
+    Python bindings: Cosmetics.
+
+commit 7aafb892746356c9089a2ba91188bfa51c68cea2
+Author: Martin Ling <martin-git at earth.li>
+Date:   Mon Apr 15 23:05:38 2013 +0100
+
+    Tell SWIG that gpointer is really void *.
+
+commit 758b01adcbbc2cd4c077281ad06c7bb2ac414391
+Author: Martin Ling <martin-git at earth.li>
+Date:   Mon Apr 15 20:01:07 2013 +0100
+
+    Add SWIG interface file and build script for Python bindings.
+
+commit 72cd99b876eb2185358bc108b488585c956f3dc7
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Apr 16 00:23:34 2013 +0200
+
+    ols: Report when a device doesn't support metadata
+    
+    Not an error, but it does mean it's either a really old or really
+    basic device, and will help us to debug people's problems with
+    these.
+    
+    Fixes bug 92.
+
+commit 754b5ff2b48fc2fda3771940aa9d98108ae4f6af
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 15 23:50:16 2013 +0200
+
+    fx2lafw: Support conn scan parameter
+    
+    This takes a USB specification. Fixes bug 82.
+
+commit 1eb0a0df666e8ed117c9b3d3c65291367cbb961f
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 15 23:47:04 2013 +0200
+
+    usb: Fix bus.address format detection
+
+commit e5d15bd2a2eb8c34ee7bc9db1e70ba0741215097
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 15 20:05:43 2013 +0200
+
+    ols: Allow configuration before the device is opened
+
+commit a7be14ada20d594c5338613a73788e8f89c0d9d5
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 15 18:45:38 2013 +0200
+
+    rigol-ds1xx2: Don't assume there's a valid sdi
+
+commit bf256783599262b94c4b3be3797f4576053d96e1
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 15 18:28:16 2013 +0200
+
+    ols: Properly initialize operational state before start
+
+commit e45ad6e24ff1a3873d551f9ed08acb3ffd0d1d0d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Apr 15 12:27:55 2013 +0200
+
+    demo: Fix compiler warning, cosmetics.
+
+commit 1d166757694b259bbcca205ced91ac69e8a5ef7e
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 15 01:30:24 2013 +0200
+
+    lascar-el-usb: Use two probes for temp/humidity loggers
+
+commit 2150a69b7633ebd1bcf13f645c026506f3dfe03b
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sun Apr 14 19:19:35 2013 +0100
+
+    demo: Unref the IO channel when it is no longer used
+
+commit ed20a42803c8b4e79b259ae03298dec88f2299f5
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sun Apr 14 18:52:02 2013 +0100
+
+    demo: Free dev_contexts
+
+commit a76842947faadad98572f011cb20f3220998f71b
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sun Apr 14 17:00:47 2013 +0100
+
+    demo: Moved demo configuration variables into dev_context
+
+commit 33c6e4c5a428115965f980e88e6415fb782658e9
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Sat Feb 2 00:50:00 2013 -0600
+
+    session: Make sr_session_stop thread-safe
+    
+    With the sigrok session running in a worker thread, if sr_session_stop is called
+    from another thread, it shuts down the pollfds used by the hardware drivers,
+    without ensuring that the sigrok event loop is no longer using those pollfds.
+    
+    On the demo driver, this involves shutting down the GIOChannels, causing a
+    segfault when the sigrok event loop tries to use them. This is evident when
+    using the Stop button in PulseView, while the session is running.
+    
+    This isn't a problem with just the demo driver; any driver's resources may be
+    freed by sr_session_stop concurrently with the sigrok session running.
+    
+    To solve this problem, we don't touch the session itself in sr_session_stop().
+    Instead, we mark it for decommissioning and return. The session polls this flag,
+    and shuts itself down when requested.
+    
+    This fixes bug 4.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 33ef757383896959651c48744fabb417729424dc
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sun Apr 14 15:46:15 2013 +0100
+
+    demo: Keep a pointer to dev_context in sr_dev_inst and vice-versa
+
+commit e053204700fa0a9151e6efb54eae9dc5a73e3ccd
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sat Apr 13 16:43:16 2013 +0100
+
+    demo: Only one GIOChannel is needed
+
+commit bbd7ef0f18df94232bafe6606c6d37eaad9ffd80
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sat Apr 13 16:08:52 2013 +0100
+
+    demo: Fixed glitching in increment signal
+
+commit f0b6ae19a8e6ae7050cde3e1fa0a3ce46b9b5f66
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sat Mar 16 08:43:36 2013 +0000
+
+    alsa: Set the probe index
+
+commit 9e5670d0ab63af4353003bf879b0aa5e1a6919f8
+Author: Jan Luebbe <jluebbe at debian.org>
+Date:   Sat Apr 13 23:27:07 2013 +0200
+
+    zeroplus-logic-cube: add USB ID for LAP-16128U
+
+commit 6bb192bc05f976a5660e35c9507450a573679296
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Apr 14 02:21:55 2013 +0100
+
+    rigol-ds1xx2: support digital channels.
+
+commit a789b61087f156f3f5b38de6c56c7744fde2c3eb
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sat Apr 13 22:25:41 2013 +0100
+
+    rigol-ds1xx2: doesn't actually support SR_CONF_LIMIT_SAMPLES
+
+commit ee7e9bee5d943261d866f92cb8b81584e290df01
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Apr 14 01:58:35 2013 +0100
+
+    rigol-ds1xx2: fix handling of partial frames.
+
+commit 4c7aca66defecb82245d2fd8b62b3ff70049982a
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Apr 14 16:44:49 2013 +0200
+
+    ignore test leftovers
+
+commit 0c05591abf6b313aebb1f717903c5cc337f58329
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Apr 14 00:36:05 2013 +0200
+
+    ols: Support get/set/list on all device options
+    
+    Where it makes sense: _LOGIC_ANALYZER and _TRIGGER_TYPE don't have much
+    use for all of them.
+
+commit 8f35be72b46769b3b51e9c91a131eaf6c256ac1a
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Apr 12 19:42:44 2013 +0200
+
+    rigol-ds1xx2: Use g_usleep() for portability
+
+commit 406569ddeadbbbc73c9fefb92b855e03fc107987
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Apr 12 18:47:06 2013 +0200
+
+    Bump glib requirement to >= 2.32.0.
+    
+    This is now required, e.g. due to the usage of g_variant_new_fixed_array().
+
+commit 169dbe8577c2f7570f61799a064f95b39b3b6fe3
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Apr 12 18:44:28 2013 +0200
+
+    rigol-ds1xx2: Whitespace, minor fix.
+    
+    Return SR_ERR_MALLOC for failed malloc, not SR_ERR.
+
+commit 34e4c273916d8fd246ca6aefbff05528f92391fc
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Apr 12 17:59:38 2013 +0200
+
+    unittests: Adapt to new GVariant system.
+
+commit ff08a52a0fb66abb471fa0bfe0369300c313778f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Apr 12 17:45:01 2013 +0200
+
+    Fix two minor compiler warnings.
+
+commit ba6568c5adcbb2075964c582bf2939b46f729b12
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Apr 11 18:49:24 2013 +0200
+
+    output/vcd: Use selected probes, not lowest-numbered ones
+    
+    Thanks to Andrew Bardsley for the patch.
+
+commit 254dd102e84a6f9e5a62be5172bb94cbca3da4e8
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Apr 11 16:06:55 2013 +0200
+
+    rigol-ds1xx2: Support for all channels, proper defaults
+    
+    Since this driver supports devices with a control panel and display,
+    we take the defaults from the device -- not a set of sensible
+    defaults as usual.
+
+commit 88e429c97f4fa482f8897c4795ad14f0afa96b56
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 8 12:01:00 2013 +0200
+
+    rigol-ds1xx2: fix channel numbers
+    
+    Copyright bump, too.
+
+commit a3df166f02201abe253b6fd4ee416394dace9e5e
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 8 01:12:42 2013 +0200
+
+    rigol-ds1xx2: better debugging
+
+commit 75d8a4e5766cccdcd7f017093fa822e7218749b8
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 8 00:38:58 2013 +0200
+
+    rigol-ds1xx2: properly send frame begin/end packets
+
+commit 7991784841727d39a6f71ffa4ccdc1fc86af9f98
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 8 00:37:50 2013 +0200
+
+    hantek-dso: Support SR_CONF_NUM_TIMEBASE/SR_CONF_NUM_VDIV
+
+commit d62d7ad151e2b50484bc6bf36c94b9657ed6a500
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 8 00:37:12 2013 +0200
+
+    rigol-ds1xx2: Support SR_CONF_NUM_TIMEBASE/SR_CONF_NUM_VDIV
+
+commit 2efa699fda95b6d2d722d41407ca741cdbfe709c
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 8 00:29:37 2013 +0200
+
+    Add SR_CONF keys to report the number of timebases and vdivs
+    
+    Number of timebases is needed to properly interpret a frame's worth
+    of samples. Number of vertical divisions isn't, but may nevertheless
+    be interesting for a frontend that wants to reproduce the scope's
+    native display.
+
+commit d8284802ca6bbdf19e7ff0ae9bcc5b6e111056c0
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Apr 7 22:51:45 2013 +0200
+
+    use driver callbacks directly
+
+commit 861c447bfb020a59ac9d197c4a74a4e8ea3998bf
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Apr 7 21:51:26 2013 +0200
+
+    rigol-ds1xx2: SR_CONF_TIMEBASE and _VDIVS lists are now an array of tuples
+
+commit 6cefe516aacc215fa8d144e9da09e69cfb1e5ff6
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Apr 7 21:50:42 2013 +0200
+
+    return SR_ERR_ARG if a driver doesn't implement sr_config_*()
+
+commit 82b904b173f1443c4d6bdebdf1a7f0dda01c4982
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Apr 7 21:28:54 2013 +0200
+
+    Add Rigol DS1052E/1102E VID:PID
+
+commit 3973ee26f58efa469657c57d23a285273f316c35
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Apr 7 21:02:18 2013 +0200
+
+    hantek-dso: SR_CONF_TIMEBASE and _VDIVS lists are now an array of tuples
+
+commit 034accb512e43172ee292d1585870db9e2477ed0
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Apr 2 20:54:44 2013 +0200
+
+    hantek-dso: move buffer sizes to device context
+    
+    There are only two sizes for every device: 10k and the complete
+    per-channel buffer size. This can be doubled if one channel is disabled.
+
+commit fe9ac252502fbb90badc84367eea75d6ab027686
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 1 16:53:14 2013 +0200
+
+    ols: Get rid of gcc warnings
+
+commit 1bec72d2ac388bd78c1c4e573431170c4ed97f8c
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Mar 31 21:31:49 2013 +0200
+
+    chronovu-la8: Adjust to GVariant-based sr_config_* functions
+
+commit afdf6d6a20a0d5ac7c3f9b84d1af4f782eda3177
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Mar 31 21:28:33 2013 +0200
+
+    tondaj-sl-814: Adjust to GVariant-based sr_config_* functions
+
+commit 7d93a62ea3b7c8853603fa267bb8b1320dde4b69
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Mar 31 21:28:33 2013 +0200
+
+    uni-t-dmm: Adjust to GVariant-based sr_config_* functions
+
+commit ede25f4e6f9dbf84629c0058f91014a8bab59a56
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Mar 31 21:28:33 2013 +0200
+
+    serial-dmm: Adjust to GVariant-based sr_config_* functions
+
+commit f6a0ac9f6217f808d02f1c64a49c7ead3afb06e1
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Mar 31 21:25:51 2013 +0200
+
+    rigol-ds1xx2: Adjust to GVariant-based sr_config_* functions
+
+commit 2c2be401897895c0a343dfd461adcfffbee950a6
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Mar 31 21:25:51 2013 +0200
+
+    mic-985xx: Adjust to GVariant-based sr_config_* functions
+
+commit a9ed6877f7c5e920a5ba065324be9587f3c1ffaf
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Mar 31 21:25:51 2013 +0200
+
+    link-mso19: Adjust to GVariant-based sr_config_* functions
+
+commit 510b3e692a61239bfa1c6794218acd80e5ba28ef
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Mar 31 20:55:39 2013 +0200
+
+    brymen-dmm: Adjust to GVariant-based sr_config_* functions
+
+commit 2c9c0df86eaf9b64cf0ba7537b3c3c84f2da4686
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Mar 31 20:55:39 2013 +0200
+
+    asix-sigma: Adjust to GVariant-based sr_config_* functions
+
+commit aa0dbd683c58c9dd342140a4080d2aa0b95c5bb3
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Mar 31 20:55:39 2013 +0200
+
+    alsa: Adjust to GVariant-based sr_config_* functions
+
+commit 3316e149d0dd03e65aca72183bc15eb839e392c6
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Mar 31 20:47:01 2013 +0200
+
+    zeroplus-logic-cube: fix samplerate setting
+
+commit e0e150672af8b52f7931ad827bdfb85773cfb4bb
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Mar 31 10:27:15 2013 +0200
+
+    sr_voltage_string(): deprecate struct sr_rational
+
+commit 8386096f013a2735553d5066ed2b96f519c12a76
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Mar 30 19:48:38 2013 +0100
+
+    zeroplus-logic-cube: Adjust to GVariant-based sr_config_* functions
+
+commit c8733a2bbb876496e3c6eb9e95084d9d5fb7e834
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Mar 30 19:48:38 2013 +0100
+
+    nexus-osciprime: Adjust to GVariant-based sr_config_* functions
+
+commit e44ac12a29c39cb873968a8fd4c02b3e05316b3b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Mar 30 19:48:38 2013 +0100
+
+    agilent-dmm: Adjust to GVariant-based sr_config_* functions
+
+commit a59b4eef5576f1c32d1d4a0968be05eb17c865f9
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Mar 30 19:29:44 2013 +0100
+
+    victor-dmm: Adjust to GVariant-based sr_config_* functions
+
+commit 70424328c10640f0c1db0ab6334723658c043470
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Mar 30 19:29:44 2013 +0100
+
+    fluke-dmm: Adjust to GVariant-based sr_config_* functions
+
+commit dccda194dbd202eb0274f479b51152400ff9de88
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Mar 30 19:29:44 2013 +0100
+
+    colead-slm: Adjust to GVariant-based sr_config_* functions
+
+commit 7faf69da10e743820ef54d7f3c11cdcc06fc9b1a
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Mar 30 19:08:29 2013 +0100
+
+    lascar-el-usb: Adjust to GVariant-based sr_config_* functions
+
+commit d40073113bc1c09f3924cac275791e53905bbab5
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Mar 30 15:47:01 2013 +0100
+
+    hantek-dso: Small debug fix
+
+commit 86bb3f4a865a7eed9f0537f01356231cf7d86012
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Mar 30 15:24:37 2013 +0100
+
+    hantek-dso: deprecate struct sr_rational
+
+commit e48a54629242584b7b2508d657815730ad80cbfe
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Mar 30 15:23:44 2013 +0100
+
+    input/vcd: deprecate struct sr_rational
+
+commit 76e107d68c010ee3aaede5a1eec2893f82062184
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Mar 30 14:41:01 2013 +0100
+
+    sr_parse_(period|voltage): deprecate struct sr_rational
+
+commit d00088ca6daf91270f8c2f063167eedf2644bb8f
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Mar 26 22:02:45 2013 +0100
+
+    demo: Adjust to GVariant-based sr_config_* functions
+
+commit f627afd65b5b544b1c10345bddf1b3a490fb8c93
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Mar 26 21:38:32 2013 +0100
+
+    hantek-dso: Adjust to GVariant-based sr_config_* functions
+
+commit 38f1e846a81a4fee1a28c0f3547c4ac821b0f882
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Mar 25 20:41:28 2013 +0100
+
+    struct sr_samplerates is now obsolete
+    
+    sr_config_get() of SR_CONF_SAMPLERATE now returns a GVARIANT_TYPE_DICTIONARY.
+    This dictionary contains a single key-value pair. Possible values for the key:
+    
+     - "samplerates": the value is an array of GVARIANT_TYPE_UINT64 representing
+       all valid samplerates.
+     - "samplerate-steps": the value is an array of GVARIANT_TYPE_UINT64 with
+       exactly three members, which represent the lowest samplerate, highest
+       samplerate, and the minimum step, respectively.
+
+commit aeea0572202fa20093534a8e97da87c324151932
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Mar 25 20:40:40 2013 +0100
+
+    ols: allow for disabling of RLE as well
+
+commit e46aa4f611da95cc705279c199f0e662b39eed1b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Mar 25 20:40:15 2013 +0100
+
+    ols: Adjust to GVariant-based sr_config_* functions
+
+commit d6836bf129adc8efbd826b8ea04246167987e0cc
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Mar 25 20:30:56 2013 +0100
+
+    fx2lafw: Adjust to GVariant-based sr_config_* functions
+
+commit 8e34ca86fb54ec1c841724900006868e29b180fa
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Mar 25 20:29:45 2013 +0100
+
+    Add SR_CONF_TRIGGER_TYPE config_info list
+
+commit ec4063b83c9b8a0693b9837787306dd5405e076b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Mar 25 20:27:26 2013 +0100
+
+    input/output modules: Adjust to GVariant-based sr_config_* functions
+
+commit 722db131a45dbc84aaa27cf65467a11552a32548
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Mar 25 20:23:13 2013 +0100
+
+    Add sr_config_free()
+    
+    Due to struct sr_config now containing a GVariant, this needs to be
+    cleaned up after use properly. This is a helper function for that.
+
+commit 003595ac375fac61ed9ef45b13119c80e7c1ade3
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Mar 25 20:21:10 2013 +0100
+
+    Adjust to GVariant-based sr_config_* functions
+
+commit bc1c2f001a3b8499052348ec45155313153b2194
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Mar 25 15:38:44 2013 +0100
+
+    Use GVariant for sr_config_*() functions
+    
+    sr_config_get() provides a GVariant owned by the caller, so it must be
+    released with g_variant_unref() when done.
+    
+    sr_config_set() takes a GVariant from the caller which may be floating;
+    it will be properly sunk and release after use by this function. Thus
+    the output of g_variant_new_*() may be used as an argument.
+    
+    sr_config_list() also provides a GVariant owned by the caller, to be
+    unreferenced when done.
+    
+    sr_config_make() can take a floating reference.
+
+commit 13d8e03c4f9fb6fe9c5f682ab957173effe42d43
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Mar 24 11:21:00 2013 +0100
+
+    Bump copyright year
+
+commit 2e542814cb97a9937f9e4cace367ffdb7a2231cc
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 9 19:52:38 2013 +0200
+
+    configure.ac: Fix checks for cross-compiles.
+    
+    When checking architecture-specific things, always check $host, i.e. the
+    architecture we're building _for_, not the one we happen to build _on_.
+    
+    E.g. when cross-compiling _for_ Android (or Windows or others) it's important
+    to check for Android in $host; whether we happen to cross-compile _on_ a Linux
+    or Windows or OpenBSD or FreeBSD machine ($build) doesn't matter, only the
+    fact that we compile _for_ Android is important for most checks.
+
+commit bbe6e336b3baf86b43f88185f25eab424cbd61f6
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 9 18:50:34 2013 +0200
+
+    vcd output: Build fix for Windows/MinGW.
+    
+    On Windows/MinGW 'recv' seems to be already defined in windows.h/winsock2.h.
+    
+    Use 'receive' instead, for now, otherwise we get an error:
+    
+    vcd.c:147:17: error: conflicting types for 'recv'
+
+commit 6bad8487243cb5e86979b801069f9656f627480f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 9 18:47:31 2013 +0200
+
+    configure.ac: Print $host and $build.
+    
+    In the configure summary at the end also print the architecture we're
+    building on ($build) and the target host we build for ($host). The two are
+    not necessarily the same, e.g. in the case of cross-compiles.
+
+commit 6e772cbe802327ed79cdaae9d366fed1ec6b081c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 9 18:08:16 2013 +0200
+
+    configure.ac: Mention required lib versions.
+    
+    In the summary output at the end of a configure run, explicitly mention
+    which versions of which libraries are required, and also the version which
+    pkg-config has found.
+
+commit 63cbeaeb597450a52086ff23839f5dbf8989a8a2
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 9 17:58:37 2013 +0200
+
+    configure.ac: Only enable rigol-ds1xx2 on Linux.
+
+commit e4fad80b8534a05e7318bc4f9e0e688ae04d3ea2
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 9 10:03:58 2013 +0200
+
+    configure.ac: Cosmetics for the list of drivers.
+    
+    Use the canonical driver name (all-lowercase, e.g. "serial-dmm") in the
+    list of enabled/disabled drivers that configure prints after a run.
+    
+    It's common to many drivers that they support multiple devices, so
+    printing one device name (e.g. "ChronoVu LA8") is seldom really correct.
+    E.g. the agilent-dmm, asix-sigma, brymen-dmm, colead-slm, fluke-dmm,
+    fx2lafw, hantek-dso, lascar-el-usb, mic-985xx, openbench-logic-sniffer,
+    rigol-ds1xx2, uni-t-dmm, victor-dmm, and zeroplus-logic-cube drivers
+    all support more than just one device.
+    
+    So, just print the driver name instead which is more correct anyway
+    since it's specifically a list of enabled/disabled drivers.
+
+commit ccf35720c0494f4102fba8ee0a44ce1d3b67fc10
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Apr 8 15:56:54 2013 +0200
+
+    configure.ac: Improve a libusb-1.0 related check.
+    
+    Don't rely on the "heuristic" that 'libusb_CFLAGS' will be non-empty if
+    libusb-1.0 was found, but rather use the proper method of checking the
+    variable 'have_libusb1_0' which pkg-config will set to "yes"/"no"
+    depending on whether it finds the library.
+
+commit 3fd1d0ee1c6e8f9d1c6e30c16add1cc4253662bb
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Apr 8 15:40:57 2013 +0200
+
+    configure.ac: Improve USB/EZUSB/serial checks.
+    
+     - If libusb-1.0 is not found, do not compile in ezusb.c and usb.c since
+       they require libusb.h. The respective hardware drivers that use
+       libusb-1.0, and usb.c and/or ezusb.c will be excluded from the build
+       elsewhere in configure.ac. Rename NEED_EZUSB to NEED_USB.
+    
+     - Drop the NEED_SERIAL check and always compile in serial.c. This is a
+       very small chunk of code, it does not depend on any external
+       libraries that might be missing, and it compiles on all architectures.
+       Thus there's no need to conditionally include or exclude it.
+
+commit ae4c3d0431571346f489be3a370a9bb431a6ec59
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 9 12:32:30 2013 +0200
+
+    configure.ac: Fix the order of some entries.
+    
+    In order for lib autodetection and disabling of drivers (which require
+    libs that cannot be found) to work, the order of AC_ARG_ENABLEs,
+    AM_CONDITIONALs, and AC_DEFINEs needs to be changed.
+    
+    All drivers start out enabled or disabled (depending on whether
+    the --disable-drivers option was supplied or not). Then, any driver can
+    be enabled or disabled explicitly via --enable-<drivername> or the
+    resp. --disable-<drivername> option. Finally, pkg-config checks for all
+    libraries are performed, and all drivers which require a library that
+    cannot be found are disabled explicitly (regardless of any
+    --enable-<drivername> option that might have been supplied).
+
+commit aba692624593131b9f1ea7cd63d1f88b9e09b668
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Apr 8 14:46:13 2013 +0200
+
+    configure.ac: Improve pkg-config related checks.
+    
+    Until now, we checked for certain (optional) libraries via pkg-config and
+    the configure script would abort if any of them was not found, even
+    though they were optional. It was up to the user to then figure out which
+    combination of --disable-<drivername> switches were required for his
+    specific OS (and set of installed libs) to get a working configure run.
+    
+    Only if the user already specified enough --disable-<drivername>
+    switches beforehand, so that all drivers which require a missing library
+    were disabled, would the configure run not check for that specific lib
+    (and would thus not fail).
+    
+    With this change, we now always unconditionally check for all libs
+    (required and optional) via pkg-config. However, whether an (optional) lib
+    is found or not, configure will not abort. Instead, it'll just disable
+    all drivers which need a lib that cannot be found.
+    
+    The user will no longer have to supply --disable-<drivername> parameters
+    in order to get a working build.
+
+commit 3f98bf7017341f70ceb92f98b976d972254c3ba0
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Apr 7 14:14:16 2013 +0200
+
+    Fix kernel driver attached check
+    
+    The check is really only broken on darwin, but useful on all other
+    platforms, even if only Linux can actually detach a driver.
+
+commit 8c971b6e5c6fa0242d786b3c85aabedf2d9ad432
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Apr 2 14:33:17 2013 +0200
+
+    hantek-dso: cosmetics
+
+commit 67b5fba8cac632ab2ec60a3e115ff9016e900114
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Apr 6 19:28:48 2013 +0200
+
+    Doxygen: Exclude std.c and tests/*.
+    
+    These don't contain any public API functions or macros and thus should
+    not appear in the ("public API" version of) the Doxygen docs.
+
+commit c27e5f1e82819cad599b95a24bf9f617abd6fafb
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Apr 6 19:25:03 2013 +0200
+
+    Doxygen: Properly document and handle version.h.
+
+commit ca0938c50b4bf5d010d6140f64542f8307d8ea17
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Apr 6 19:18:37 2013 +0200
+
+    Doxygen: Fix a few warnings.
+
+commit 7b78b2f78fbd8309fd9898c4940b82328a2c39af
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Apr 2 14:18:59 2013 +0200
+
+    hantek-dso: use per-device firmware filenames
+
+commit 3ebce226a2672ea4f0788f5f2a222586148aabc1
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Mar 17 16:50:51 2013 +0100
+
+    s/sr_config_make/sr_config_new/.
+    
+    This matches the naming of other/similar functions better.
+
+commit 333bf022e3ab268fb575ec61ccf0c0f17213647c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Mar 12 21:40:03 2013 +0100
+
+    rigol-ds1xx2: Use ARRAY_SIZE.
+
+commit 3864648bb6ebf24106898a1296bc106daa55e964
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Wed Mar 20 20:36:56 2013 -0500
+
+    serial-dmm: Add support for RadioShack 22-805
+    
+    Protocol-wise, this is identical to the 22-168, except that it communicates at
+    600 baud instead of 1200 baud.
+
+commit 5a7587cd03d81e84a8e4538a1ec9ab36f3a077c2
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Mar 19 22:07:21 2013 +0100
+
+    set proper build defaults for brymen-dmm and mic-985xx drivers
+
+commit cc840ab618ede3d642a1f8d07c353ba91b96e22c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Mar 17 15:07:50 2013 +0100
+
+    serial.c: FreeBSD and OpenBSD don't have OFILL either.
+
+commit 22ca5aa68b55ffc9f33c6fe0138c460b0b2f8f94
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Mar 17 13:22:22 2013 +0100
+
+    configure.ac: Add 'color-tests' (colorized 'make check').
+
+commit 57981a0716a5d9bec807cad8289d091893de0919
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Mar 17 13:19:57 2013 +0100
+
+    configure.ac: Drop std-options, unneeded.
+    
+    The automake 'std-options' option checks whether all installed tools
+    and scripts have a --help and --version CLI option. This check is not
+    needed for libsigrok though, since it doesn't install any tools.
+
+commit 9d67e248cab789314d758e5ee20a7b47eef69fe5
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Mar 17 13:07:59 2013 +0100
+
+    Don't make README.devices executable.
+
+commit ba642e8678906a27015755f8ca04ca7f73195036
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Mar 17 12:53:08 2013 +0100
+
+    README: Refer to INSTALL and new Building wiki page.
+
+commit 898c562fd3b33b07d030ea7f57eb09cd49efe69b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Mar 17 12:58:26 2013 +0100
+
+    autotools: Don't use "foreign" option.
+    
+    This adds INSTALL and allows for a few more sanity checks being done.
+
+commit 8e77bc20b92574076683d861687b63b416d3e965
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Mar 16 21:50:35 2013 +0100
+
+    lascar-el-usb: push samplerate before data log
+
+commit 7231a14590840ffdbb77c1cc076d7dcafa3ee673
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Mar 16 20:17:41 2013 +0100
+
+    add SR_CONF_SAMPLE_INTERVAL
+    
+    Expresses the time between samples, in milliseconds. This can be used
+    for devices with a samplerate > 1 second, such as dataloggers, which
+    cannot be expressed with SR_CONF_SAMPLERATE.
+
+commit c77ed446f2c08e2906883023c85feafa19a0ec10
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Mar 13 10:33:17 2013 +0100
+
+    Add initial README.devices file.
+
+commit bb203cde9d42df0430e64cb5d2b604c9d68b5639
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Mar 12 23:00:58 2013 +0100
+
+    configure.ac: Add missing AM_PROG_CC_C_O.
+
+commit 361d15110ce355dd69099d95ac8c9716e45b3173
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Mar 11 16:36:40 2013 +0100
+
+    lascar-el-usb: support for SR_CONF_DATALOG
+
+commit e6551ea640f113a9f7cd6bfaaf3a8d0689c71edf
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Mar 11 16:35:18 2013 +0100
+
+    add SR_CONF_DATALOG
+
+commit 985727626183bf1517a9046f4eb40c732e566b8f
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Mar 11 15:28:41 2013 +0100
+
+    ols: use ptr to int dereference for SR_T_BOOL
+    
+    This mad ptr to int casting has to go.
+
+commit 218e629fa48e2efb970b018d8d2ff8ccfa2d9a2c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Mar 10 17:13:15 2013 +0100
+
+    sr_init(): Sanity-check input/output modules.
+
+commit 0b4b41eed84be29e21b0e65c8072b546b4fdd37e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Mar 9 12:20:17 2013 +0100
+
+    Add missing ULL suffixes to SR_MHZ() et al.
+    
+    This fixes bug #72.
+
+commit 79bb0e97d53526ef6deb491ea9c7698ed6e90631
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Mar 7 09:37:42 2013 +0100
+
+    Add a testsuite for libsigrok.
+    
+    This adds a suite of unit tests for libsigrok. It uses the 'Check'
+    tool/library (apt-get install check) to run the tests.
+    
+    The configure tool tries to find libcheck. If it succeeds, a
+    "make check" will run all tests. Otherwise, none of the tests will
+    be built and "make check" will not run any tests.
+    
+    This also means that users who don't have 'check' installed will still
+    be able to build and install libsigrok just fine.
+
+commit d5585e32dd856b09d78acab2aac3ba6c78ad7752
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Mar 6 23:14:00 2013 +0100
+
+    output/vcd: use new API
+
+commit 2474d87e8c9b1133017a06c9ef0896626267e95b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Mar 3 21:17:48 2013 +0100
+
+    demo: sync get/set options
+
+commit a819da9c258bd1f295604e4078c84ca0bab2de04
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Mar 3 18:02:24 2013 +0100
+
+    Drop deprecated sr_session_halt().
+    
+    This has been deprecated in favor of sr_session_stop() since a while.
+    
+    None of the current frontends use sr_session_halt() anymore, neither
+    does libsigrok.
+
+commit 365f04d61f54908013021be83450d38fff67964f
+Author: lelazary <lelazary at yahoo.com>
+Date:   Tue Jan 8 08:27:52 2013 -0800
+
+    mso-19: Initial analog probe support (unfinished).
+    
+     - Added the analog probe (unfinished).
+    
+     - Reset trigger to state to 0 before capture, just incase the scope is in
+       the middle of a capture.
+
+commit 5952553f569f82b878717b9d97053690014604c9
+Author: lelazary <lelazary at yahoo.com>
+Date:   Tue Jan 8 08:00:57 2013 -0800
+
+    mso-19: Fixed warning.
+
+commit 07e1aad5c4d53ee1028613312061f261f1a7800a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Feb 22 15:12:32 2013 +0100
+
+    doxygen: Add more output format docs.
+    
+    This is largely taken from the respective wiki page (with some updates
+    and improvements), which will be removed in favor of the doxygen docs.
+
+commit 8368734386f3bce5c568258b830c002d2581dfc6
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Feb 21 21:27:27 2013 +0100
+
+    doxygen: Add more input format docs.
+    
+    This is largely taken from the respective wiki page (with some updates
+    and improvements), which will be removed in favor of the doxygen docs.
+
+commit 1d36b4d27f737dfcd6e232bc9d9538bd64bf1afb
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Feb 21 15:20:50 2013 +0100
+
+    input: new WAV file module
+
+commit 543d45c581658851b41af42ebdbc476ccf3d88d3
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Feb 21 14:48:43 2013 +0100
+
+    input: feed the filename to the module's init() function
+    
+    This is essential if a format contains e.g. the number of probes; the
+    init() function needs to initialize the sr_dev_inst struct, but needs
+    access to the file to properly add the probes to it.
+
+commit ff17e6ba5094d590926a2aa8130220a341fc2c04
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Feb 11 18:23:17 2013 +0100
+
+    mic985xx: Add missing memset().
+
+commit 6f3e5335adc5ba4488c5f7dcb791f929c20f2049
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Feb 9 16:13:03 2013 +0100
+
+    mic-985xx: Add support for the MIC 98581.
+    
+    This device only supports temperature measurements, no humidity.
+
+commit be6db330f86707c5eadf2a3f20903860dbadaabf
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Feb 10 17:06:38 2013 +0100
+
+    hantek-dso: minor fixes
+
+commit 8421ffa44dc9b0ca89c554c40be39dcc151e7495
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Feb 10 16:49:23 2013 +0100
+
+    asix-sigma: don't try to free static storage
+
+commit d5a669a9e0319531595a8a45b6c21f0c316a24f1
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Feb 4 13:36:23 2013 +0100
+
+    properly deal with decimals
+
+commit cd2f0fe22c35dcf3b010411ff6f123701be2a2d6
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Feb 1 23:45:32 2013 +0100
+
+    Add/use std_hw_dev_acquisition_stop_serial().
+
+commit 17548571cc836edaf45e4707e74f6537605fc924
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Feb 8 23:13:33 2013 +0100
+
+    zeroplus: Only report supported samplerates.
+    
+    The currently supported model LAP-C(16032) doesn't support the
+    samplerates 150MHz and 200MHz which some of the other models have.
+    
+    Thus, do not report these samplerates to the frontends. E.g. sigrok-cli
+    should not show them via --show and GUIs should not list them in their
+    "Samplerates" drop-down.
+
+commit e495a676ebda71cdcc39904ee28174ccba7ce2ae
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Feb 8 22:18:55 2013 +0100
+
+    zeroplus: Cosmetics, small fixes, drop unneeded stuff.
+
+commit 58c5f2ed1785ead87d1398c28b5dbe60ba4610dd
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Feb 7 22:09:39 2013 +0100
+
+    zeroplus: Split into api.c and protocol.c.
+
+commit c7142604a2d29ca58f6e4d7cba070a329030e60b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Feb 7 09:16:28 2013 +0100
+
+    session.c: Drop left-over 'session: ' prefix.
+    
+    This is added automatically now.
+
+commit 3e9b7f9c776221c2c6b0d9f51b48db31383a4b03
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Feb 7 09:11:26 2013 +0100
+
+    Rename session_dev_id to cb_data everywhere.
+    
+    We use 'cb_data' in all drivers these days, make the few remaining ones
+    that use 'session_dev_id' consistent.
+
+commit 6fab7b8f5365c7be69be4a755910945b6113dd8f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Feb 6 22:35:24 2013 +0100
+
+    Driver struct cleanups.
+    
+     - Explicitly list .config_get in all drivers for consistency, and set it
+       to NULL if unused (whether or not a driver implements it is optional).
+    
+     - List all 'struct sr_dev_driver' entries in the same order in all drivers.
+    
+     - Move the check whether .config_set/.config_list exist (i.e., are non-NULL)
+       into sanity_check_all_drivers().
+
+commit 4afdfd4628e9955af02a3ea619ecdfe469f9a9e2
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Feb 6 19:57:32 2013 +0100
+
+    Add and use std_session_send_df_header().
+    
+    This is a small helper function which sends the SR_DF_HEADER packet that
+    drivers usually emit in their hw_dev_acquisition_start() API callback.
+    It simplifies and shortens the hw_dev_acquisition_start() functions
+    quite a bit.
+    
+    It also simplifies the input modules which send an SR_DF_HEADER packet, too.
+    
+    This patch also automatically removes some unneeded malloc/free in some
+    drivers for the 'packet' and 'header' structs used for SR_DF_HEADER.
+
+commit 961009b0c4002717c669a0cdcafb0fcf29f5ea1b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Feb 1 22:58:54 2013 +0100
+
+    hw_dev_close(): Move common checks to wrapper.
+    
+    Check the relevant arguments for != NULL before calling the actual
+    driver-specific function, so that the driver can safely assume those
+    arguments are non-NULL. This removes the need to duplicate these
+    checks in every driver.
+
+commit 0e94d524c19fe89c564243421d37c17818f87631
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Feb 2 19:52:26 2013 +0100
+
+    Shorten/simplify hw_dev_list() implementations.
+
+commit 7c8a9e1e0fada5d726bce638cf4d36147ed4ebbf
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Feb 2 12:22:18 2013 +0100
+
+    serial-dmm: Drop unneeded g_try_malloc0().
+
+commit bf6f8399fc3515c0e3827a17b2fc21f4a9211a0f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Feb 2 12:14:26 2013 +0100
+
+    Make 'struct rs9lcd_info' non-empty.
+    
+    Empty structs can be an issue (compiler-dependent), so add a dummy entry
+    for this one.
+
+commit c5d6f5cc1c0069a5141c5c76f7e17dd592427138
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Feb 2 11:35:20 2013 +0100
+
+    brymen-dmm: Cosmetics, coding-style, consistency.
+    
+    Also, name the driver "brymen-bm857" in preparation to doing "subdrivers"
+    for other Brymen models later (similar to serial-dmm).
+
+commit 943e94f567a386e3cf754cfe7f4e15893622a95d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Feb 2 11:19:03 2013 +0100
+
+    brymen-dmm: Use std_hw_init().
+
+commit 601fb67cc4977d7e04e20916bde52147b35df970
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Mon Nov 26 17:09:05 2012 -0600
+
+    brymen-dmm: Add support for Brymen BM857
+    
+    This patch might also work for a number of other Brymen models
+    -- 859(a), 867, 869---
+    including their respective rebadges from Greenlee, Extech, and Amprobe.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 20cbc7854dc0a375e23fea2ca7e7feee3d3ac701
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Wed Nov 21 21:20:39 2012 -0600
+
+    brymen-dmm: Initial driver skeleton.
+
+commit 0cd8e23140612703406a57316bb0a507fb8f1994
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Jan 30 18:21:07 2013 +0100
+
+    Initial driver implementation for MIC 98583.
+    
+    This is a USB/serial (Prolific) based temperature and humidity logger.
+
+commit 7ec5b54955118d8c1ee003a02c3334f1a0046457
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Jan 30 16:58:01 2013 +0100
+
+    mic-985xx: Initial driver skeleton.
+
+commit 6d1161142dfce461c8e54c09d821443c68916df8
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Jan 28 17:43:04 2013 +0100
+
+    zeroplus: Use message logging helpers.
+
+commit c4227fc637431113ba92092ddbda86461703c06c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jan 29 12:55:00 2013 +0100
+
+    device: Cosmetics.
+
+commit d3b38ad389a6186e2822d62b20b9f0d9d9e7c21c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jan 29 12:55:00 2013 +0100
+
+    Drivers: Explicitly list sr_samplerates fields.
+    
+    This makes it a bit easier to understand which value means what, just
+    from looking at the driver code.
+
+commit 063e7aef6d41d4c44591ff93672079998bf9622f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jan 29 12:55:00 2013 +0100
+
+    Factor out common hw_init() driver code.
+    
+    Most drivers do pretty much the same things in their hw_init()
+    right now, so factor out that code to std_hw_init() in std.c.
+
+commit 4b97c74e0b5c19ad0ee04620b618461248ab69d7
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Jan 28 20:00:54 2013 +0100
+
+    sr_driver_scan(): Improve checks.
+    
+    Check the relevant arguments for != NULL before calling the actual
+    driver-specific function, so that the driver can safely assume those
+    arguments are non-NULL. This removes the need to duplicate these
+    checks in every driver.
+    
+    Also, do some minor whitespace and consistency improvements.
+
+commit c0eea11c4535e071c72b357fa7e2d1288104c134
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Jan 28 19:36:16 2013 +0100
+
+    sr_driver_init(): Improve checks.
+    
+    Check the relevant arguments for != NULL before calling the actual
+    driver-specific function, so that the driver can safely assume those
+    arguments are non-NULL. This removes the need to duplicate these
+    checks in every driver.
+    
+    Also, change one SR_ERR to the more correct SR_ERR_MALLOC, and assign
+    sr_ctx in the rigol-ds1xx2's hw_init() function, like all the other
+    drivers do.
+
+commit bd36d826d4b9916034c6268919e2a72a0d7ea000
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jan 29 12:55:00 2013 +0100
+
+    hwdriver: Use message logging helpers.
+
+commit a421dc1d7b24bb7b8f2127b6c07df6b68eb5001f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jan 29 12:55:00 2013 +0100
+
+    session: Use message logging helpers.
+
+commit cbc6f3b25331bc4acca1eff9a5e60786e2efd2f8
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jan 29 12:05:00 2013 +0100
+
+    hantek-dso: Use message logging helpers.
+
+commit 140185af6c2b73a2b940012269f893962cbecd52
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Mon Jan 28 20:28:03 2013 +0000
+
+    Check sr_config_set value argument is not NULL
+
+commit 4c961f5ed5e127aae75e48cd4369dc25439f24d4
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Mon Jan 28 20:26:37 2013 +0000
+
+    Made sr_config_list driver argument a const pointer
+
+commit 9fd504b9eb37502b4cd2d5d105f9f24ad1b5adf9
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Mon Jan 28 20:25:56 2013 +0000
+
+    Made sr_config_get driver argument a const pointer
+
+commit 7d4abe5a77b39c11b2187e1768339fcd11b0b763
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Jan 27 01:23:01 2013 +0100
+
+    serial.c: NetBSD doesn't have OFILL.
+
+commit cbadb856d6d833f2822cf63e4884abb409da6172
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Jan 26 01:18:19 2013 +0100
+
+    Code cleanup.
+
+commit 41bad9283d5bf869cfdf3d54373bec4dc51eaf16
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jan 25 20:41:49 2013 +0100
+
+    Remove sr_driver_hwcap_exists().
+
+commit 4d15e5c9077a543a452a976933286c705c2e7088
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jan 25 16:20:40 2013 +0100
+
+    Rename sr_dev_has_hwcap() to sr_dev_has_option().
+
+commit 6a4710fac267c07cc146b2a3cd23204b08bea552
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jan 25 16:05:48 2013 +0100
+
+    drivers: Trim unused config_get() calls
+    
+    None of the driver config_get/set/list calls are required.
+
+commit ddd9b41f5af2c5f1719439546a378d91ceef6c30
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jan 25 15:48:44 2013 +0100
+
+    Rename sr_info_get() to sr_config_get().
+
+commit 358d050d7a2a1729d8200eaa8ffc16318e47958b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jan 25 15:38:57 2013 +0100
+
+    Rename sr_dev_config_set() to sr_config_set()
+
+commit aeba33ba219c4944b880be0b0687b7798b152ab0
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jan 25 15:16:39 2013 +0100
+
+    Header cleanup.
+
+commit 0d485e30c607b22b5f328512327e4e0fafc6cbb7
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jan 25 15:09:20 2013 +0100
+
+    Deprecate SR_DI_HWOPTS.
+    
+    This is replaced by SR_CONF_SCAN_OPTIONS.
+
+commit 9a6517d14b1248855cde0d88ec9519f99184cc77
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jan 25 15:01:49 2013 +0100
+
+    Deprecate SR_DI_HWCAPS.
+    
+    This is replaced by SR_CONF_DEVICE_OPTIONS.
+
+commit c50277a6ec09fb35de3a6e0f2ae3401bc72a1526
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jan 25 11:52:27 2013 +0100
+
+    Deprecate SR_DI_TRIGGER_TYPES.
+    
+    This is replaced by SR_CONF_TRIGGER_TYPE.
+
+commit 328bafabd4781e416e3d711dabd8c4c43f219794
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jan 25 11:25:32 2013 +0100
+
+    Deprecate SR_DI_TRIGGER_SOURCES.
+    
+    This is replaced by SR_CONF_TRIGGER_SOURCE.
+
+commit 41f5bd09b0d3c5f9232ff20d076f76cc41acad32
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jan 25 11:22:20 2013 +0100
+
+    Deprecate SR_DI_TIMEBASES.
+    
+    This is replaced by SR_CONF_TIMEBASE.
+
+commit 6e1fbcc41b9d5e627faa704a31ca150715b09861
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jan 25 11:19:12 2013 +0100
+
+    Deprecate SR_DI_FILTERS.
+    
+    This is replaced by SR_CONF_FILTER.
+
+commit e4f2b2adc17bf0ab6dfa38b7511caf5a5dcfa7fd
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jan 25 11:13:49 2013 +0100
+
+    Deprecate SR_DI_VDIVS.
+    
+    This is replaced by SR_CONF_VDIV.
+
+commit 2a7b113d1382aef08d63778042589177c9b04347
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jan 25 11:04:27 2013 +0100
+
+    Deprecate SR_DI_COUPLING.
+    
+    This is replaced by SR_CONF_COUPLING.
+
+commit 6d1ceffa9557bf5cd0315949de5791e76e18bdc4
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jan 25 10:58:37 2013 +0100
+
+    Deprecate SR_DI_BUFFERSIZES.
+    
+    This is replaced by SR_CONF_BUFFERSIZE.
+
+commit dd96ea98793ed089f1b0a7dd31f417774f14ad80
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jan 25 03:38:44 2013 +0100
+
+    Deprecate SR_DI_PATTERNS.
+    
+    This is replaced by SR_CONF_PATTERN_MODE.
+
+commit 123e13138385055003cb6bc09e74df783df5af85
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jan 25 03:17:36 2013 +0100
+
+    Deprecate SR_DI_CUR_SAMPLERATE.
+    
+    This is replaced by SR_CONF_SAMPLERATE.
+
+commit fbec8bd2f3ead02358df65240c2cf786c8267f54
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jan 25 02:39:58 2013 +0100
+
+    deprecate SR_DI_SAMPLERATES
+    
+    This is replaced by a call to config_list() with id SR_CONF_SAMPLERATE.
+
+commit a1c743fc51d7b49c769fb525fe4b89985a9468c9
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jan 25 02:32:05 2013 +0100
+
+    drivers: implement config_list()
+
+commit c5fb502f9773ecf6df83a32ab82bcd1b70fa857f
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jan 25 01:24:42 2013 +0100
+
+    New driver API function: config_list()
+    
+    This takes an sr_config key and returns a list of possible values for
+    that key to be submitted with config_set(). The format of the list and
+    its contents is dependent on the key.
+    
+    This will replace the SR_DI_* keys that returned such a list before,
+    such as SR_DI_SAMPLERATES.
+
+commit 035a1078fda93cf1da37d19b3a1d95311b99b00f
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Jan 24 19:19:09 2013 +0100
+
+    drivers: rename and reorganize config get/set
+    
+    The driver API calls info_get() and dev_config_set() have been renamed
+    to config_get() and config_set(), respectively.
+
+commit 69e19dd7691f86ac001469d1b319e1358e0d9778
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Jan 23 03:40:44 2013 +0100
+
+    Always interleave analog data with all enabled probes.
+    
+    The new "probes" field in sr_datafeed_analog contains a copy
+    of all enabled struct sr_probe.
+
+commit b1a051544d502f15a1da05682e625755563b86c2
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Jan 23 02:32:58 2013 +0100
+
+    serial: more serial processing flags to turn off
+
+commit 08a9260ba4413bbdee0bfcc8a9c4544500fdb241
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jan 22 11:18:18 2013 +0100
+
+    Header cleanup: remove unused structs.
+
+commit 431ec7ca4abc85810c2553646e6b6af13138b65e
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jan 21 23:40:09 2013 +0100
+
+    uni-t-dmm: use new sr_config struct
+
+commit 1953564a96798bc298d1c94eb90c129adbde1c9e
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jan 21 23:22:47 2013 +0100
+
+    Rename SR_HWOPT_* and SR_HWCAP_* to SR_CONF_*
+
+commit c89c1c9c211a197f24de7bfd32ecbc873dd66818
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jan 21 21:58:19 2013 +0100
+
+    Unify all SR_HWOPT_* and SR_HWCAP_* enums.
+    
+    Only two functions remain for accessing meta info on the keys:
+    sr_config_info_get() and sr_config_info_name_get().
+
+commit 63b9e16e7e1564acd8bac9956bd65a4999ae0581
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jan 20 16:38:28 2013 +0100
+
+    No need to send a metapacket when loading a sigrok file.
+
+commit c71bac3b98ace917533db91e682712105c3ccf45
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jan 20 16:37:23 2013 +0100
+
+    Adjust session debugging to the new SR_DF_META packets.
+
+commit fbf394c61766e51627033b4e95c8f9ae034c7dc1
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jan 20 16:36:35 2013 +0100
+
+    Deprecate SR_HWOPT_MODEL
+    
+    This was only ever used for the defunct genericdmm driver.
+
+commit 083d64f94f6c619ca427c2544b2c08b2929a8051
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jan 20 16:35:25 2013 +0100
+
+    Use new struct sr_config_info for option metadata
+
+commit 4c0e310ca305ba776aa70d8062f467ac246c910b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jan 20 16:34:38 2013 +0100
+
+    Add small helper for creating struct sr_config
+
+commit 72e435ab94ac8838626da034ccbcfa9424add8ef
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jan 20 16:33:24 2013 +0100
+
+    Adjust option helpers to new sr_config struct
+
+commit 2df1e81970b38bd4edb6e219ad295c8a83315797
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jan 20 15:45:09 2013 +0100
+
+    Use new SR_DF_META packet.
+    
+    Since input modules determine a samplerate by reading from their
+    file format (or having it overridden with an option), they need
+    to pass this up to the frontend.
+
+commit d8e3685c47088c3219c004885d1be3c34c6503a6
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Jan 19 13:20:34 2013 +0100
+
+    free USB config descriptor after use
+
+commit 1987b8d63e748f0813dc6a4630e99686e4fe1728
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jan 6 17:41:30 2013 +0100
+
+    drivers: use new sr_config struct
+    
+    Sending an SR_DF_META packet at the start of every stream is not
+    mandatory; the frontend should ask for what it needs, and any extra
+    information the driver wants to send will come in due time.
+
+commit 9a5693a5acf677c47285307235b9d47bcc3b932e
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jan 6 16:37:41 2013 +0100
+
+    unify sr_datafeed_meta_* into one struct containing sr_config
+    
+    struct sr_config is the new name for sr_hwopt. Its companion meta
+    struct, sr_hwcap_option, was renamed sr_config_info.
+
+commit 86c02e6554061bf84b5fb7893e5837d26534a6d8
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Jan 21 01:47:30 2013 +0100
+
+    serial.c: Fix copy-paste error.
+    
+    Thanks Bert Vermeulen for reporting.
+
+commit 9d8fde40c3cc852e2d0b2d337609b247310ce277
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Jan 21 01:45:02 2013 +0100
+
+    uni-t-dmm: Quickfix for UNI-T UT61D.
+    
+    This is a temporary fix only, since a major rework of uni-t-dmm is being
+    done at the moment, soon to be merged.
+
+commit 5edc02c77c3576a47ee85241f32785cdf0fdddf8
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 19 22:00:39 2013 +0100
+
+    Add missing "ULL" suffixes.
+    
+    These numbers are larger than 32bit, mark them as ULL to avoid compile
+    failures on 32bit systems.
+
+commit 73365eaed046b2242a3080cfd282edfa266b1d2f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Jan 20 19:57:04 2013 +0100
+
+    uni-t-dmm: Expose hwopts.
+
+commit 388f9d3e25da89df1fb01412688339b6de54e14e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Jan 20 19:55:33 2013 +0100
+
+    uni-t-dmm: Fix scanning, properly use new sr_usb_find().
+
+commit 4ebd48b352a28add68d54d509b291688e1df601b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Jan 20 18:48:02 2013 +0100
+
+    Remove non-error hw_info_get() messages.
+    
+    Currently hw_info_get() can receive requests for entries (info_id) that
+    the specific driver doesn't support. That is (right now) a valid
+    use-case and not an error (might change later, though).
+    
+    Thus, for now, don't output messages for such requests at all (certainly
+    not as sr_err() where they show up in e.g. sigrok-cli output per default).
+
+commit a978eda2c958967518508e4cc461e960e96a0170
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Jan 20 18:47:35 2013 +0100
+
+    udev: Add UNI-T UT-D04 multimeter cable entry.
+
+commit 7d39e2105f6da82f4f90a87d081c1bf5cc30968d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 19 21:20:56 2013 +0100
+
+    configure.ac: Drop AC_PROG_CXX.
+    
+    We don't need a C++ compiler for libsigrok, so don't check for one.
+    
+    This would cause a build failure on all systems where there is a C compiler
+    but no C++ compiler installed.
+
+commit 294245ecf280ce72bffa40586d68195aa5980b6d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 19 19:13:52 2013 +0100
+
+    README: Document alsa (optional) library.
+
+commit b97cbca6c9c715619c8a5a9d6f5de267ff061175
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 19 15:55:22 2013 +0100
+
+    serial.c: OpenBSD doesn't have B460800.
+
+commit 262dd3e47da1af2233ffd659cda81769f53b4012
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Jan 16 01:31:46 2013 +0100
+
+    configure.ac: Drop gthread check, no longer used.
+    
+    We no longer use gthread (its only user was the 'demo' driver), so drop
+    the 'configure' check for it.
+    
+    The libsigrok.pc pkg-config file is still correct, since the 'configure'
+    result propagates there automatically.
+
+commit 3d6de074a445fbd3ac0adfa2bc28e3fd283df681
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Jan 16 00:02:24 2013 +0100
+
+    alsa: Silence ALSA scanning process.
+    
+    Errors while opening or configuring ALSA devices during scan for devices
+    should not be shown by default (i.e., no sr_err() usage). Non-working
+    or non-accessible devices (due to permissions or other reasons) will
+    simply not show up in frontends. Use sr_dbg() instead of sr_err().
+
+commit 6b8d6f93bb8df26ea04624009e2715cb6766b4f5
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jan 15 17:20:57 2013 +0100
+
+    Get rid of obsolete SR_DI_NUM_PROBES and SR_DI_PROBE_NAMES.
+    
+    Frontends should use the probe list in the device's sr_dev_inst
+    to get this information.
+
+commit bd58d8f3ece91443d5e98a7e99fd740767ed6222
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Jan 14 11:13:58 2013 +0100
+
+    Makefile.am: Fix typo in 'ChangeLog' target.
+
+commit 8a22e8c0ff4e43ceae154c908c75a3e06bf26cc6
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jan 14 00:59:46 2013 +0100
+
+    cosmetics
+
+commit dbf2482ec11affee1a6137be1544cc5463359174
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jan 14 00:52:55 2013 +0100
+
+    add --disable-all-drivers option
+    
+    Can be overridden by driver --enable options to build only those drivers.
+
+commit 512bb890df8363e800025b3b63ebac429c139aa0
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jan 13 22:42:21 2013 +0100
+
+    rigol-ds1xx2: More selective Rigol DS1xx2 scan
+    
+    Patch submitted by Martin Ling.
+
+commit 5635705c8330d243ec566e15373eb47eb5b0fd9c
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jan 13 18:07:05 2013 +0100
+
+    cleanup of obsolete definition
+
+commit 18bc270461d656460db8a167c10d390fe665f3b9
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jan 8 02:51:03 2013 +0100
+
+    sr_session_save(): don't use datastore
+
+commit 6936ee4206817dbf07fdb8524172bdb46d21c5c0
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jan 7 02:10:33 2013 +0100
+
+    remove datastore functionality
+    
+    Keeping a copy of acquired data is up to the frontend, not libsigrok.
+
+commit 305de92e9d50bcabaa055d43dc27fec1c2e97cc1
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jan 7 01:52:02 2013 +0100
+
+    use a dynamically expanding probe list
+
+commit cbc80f8f8afe28ff825449deffcc5aca7b51d7b8
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Sun Jan 6 09:31:30 2013 -0600
+
+    fx2lafw: Say if chip is old FX2 or FX2LP
+    
+    Look at the extracted REVID, and print out if it is an FX2 (non-LP), or FX2LP.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit a24e9d0484c09f972dcb31952a1ab1559bbcdedb
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jan 8 03:12:01 2013 +0100
+
+    link-mso19: Use more portable g_htons().
+    
+    Not all systems provide <arpa/inet.h> and/or htons(). Use portable and
+    always available g_htons() from glib instead.
+
+commit 753d722f340465f5bebb175c378b579296ebbd54
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jan 8 03:02:53 2013 +0100
+
+    link-mso19: Fix a bunch of compiler warnings.
+
+commit 00b44ccb8b2482c2c4c7e832ed11f7460f289e15
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jan 8 02:48:49 2013 +0100
+
+    link-mso19: Fix white-space, cosmetics, coding-style.
+    
+    Fix the bare minumum of whitespace/indentation/coding-style via
+    automatic 'indent' run, followed by some minor manual fixes.
+    Some more fixes and cleanups might follow later.
+
+commit f48cef7897ecda093a7d8b37b2bfeb1868c529af
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jan 8 02:30:40 2013 +0100
+
+    link-mso19: Fix (C) lines.
+    
+    Bring back the original (C) lines from before the split into api.c
+    and protocol.[ch].
+    
+    Add "Copyright (C) 2013 Lior Elazary <lelazary at yahoo.com>" since there
+    were nontrivial changes to those files.
+
+commit 8472ae868ec05533bb00b368b4c5140e24c0409b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jan 8 01:27:11 2013 +0100
+
+    configure.ac: Enable Link Instruments MSO-19.
+    
+    This driver now compiles again and (partially) seems to work, so enable it.
+
+commit eb913174ab1fa7decaab3dd64eec0a0a42a2391a
+Author: lelazary <lelazary at yahoo.com>
+Date:   Mon Jan 7 07:49:31 2013 -0800
+
+    Added limit samples Eveything seems to work find up to 1024 samples
+
+commit 087a9161fffa0cabe8aa37cf3358d88bcd72fb21
+Author: lelazary <lelazary at yahoo.com>
+Date:   Sun Jan 6 09:46:01 2013 -0800
+
+    Rewrote the trigger config. Added trigger position and trigger slope
+
+commit 5a24e89ca463ba7acb465f4bc9953e2da9c09e45
+Author: lelazary <lelazary at yahoo.com>
+Date:   Sat Jan 5 18:12:45 2013 -0800
+
+    Eveything seems to work now except for triggers.
+
+commit 4db2aaffe7b47b15e6ad7e4e11281d62bbd598c8
+Author: lelazary <lelazary at yahoo.com>
+Date:   Sat Jan 5 09:29:00 2013 -0800
+
+    More cleanup. Communication with mso19 is working, but its not triggering. Need to check why.
+
+commit 26ddb5bacaf2a0918ef73b253d25afb1ffb744b1
+Author: lelazary <lelazary at yahoo.com>
+Date:   Sat Jan 5 09:00:52 2013 -0800
+
+    Added flow control to serial configuration to support xon/xoff for link-mso19
+
+commit 4b719338ccf3add3f872e8cd7549bddf818c4360
+Author: lelazary <lelazary at yahoo.com>
+Date:   Fri Jan 4 17:22:15 2013 -0800
+
+    Added missing mso functions
+
+commit def5c35c4c4a4f62ffc8800a1e2d7154e8fc4bd3
+Author: lelazary <lelazary at yahoo.com>
+Date:   Fri Jan 4 17:05:17 2013 -0800
+
+    Removing the old link-mso19 files and changing makefile
+
+commit df92e5cf6b1caad0d1d43eb890d84af1ef79cd18
+Author: lelazary <lelazary at yahoo.com>
+Date:   Fri Jan 4 17:03:20 2013 -0800
+
+    Rewrote the link-mso19.c into api and protocol. Still need to test and cleanup some more
+
+commit 26e6ef346d0d188932f6774d52134d8d48e38ab4
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Jan 3 19:17:51 2013 +0100
+
+    Add gnuplot_rigol_ds1xx2.gpi gnuplot script.
+    
+    This is a very simple gnuplot script for testing the Rigol DS1xx2 driver.
+    It currently has various issues and limitations (e.g. only one channel
+    is displayed, the scaling is not usable, and so on) to be fixed later.
+
+commit 29d957ceae3bd9ac5b72cd0e58a5910932bd1768
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Jan 3 19:04:11 2013 +0100
+
+    rigol-ds1xx2: Cosmetics, whitespace.
+
+commit fb6e5ba8c7da4cc16eda03e3ffd0a97780655442
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Dec 30 15:29:00 2012 +0100
+
+    rigol-ds1xx2: Autoprobe for usbtmc devices on Linux.
+
+commit 4e108ace13f2dc577e2855e44dfc685b9cfd6204
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Dec 30 14:17:08 2012 +0100
+
+    rigol-ds1xx2: Fix setting trigger parameters.
+
+commit 542843f76f4b2f780bf9ae6265f1a76841297d8a
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Dec 30 14:06:58 2012 +0100
+
+    rigol-ds1xx2: Assorted parameter setting fixes.
+
+commit e0b7d23ce884f03ecb693943c5bd822879c68d65
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sun Dec 30 04:17:56 2012 +0100
+
+    rigol-ds1xx2: First working version.
+    
+    Currently hardcoded to use /dev/usbtmc1. Analog data readout works.
+
+commit f4816ac6cc2403558276ada44d3e14eb4a9b3d15
+Author: Martin Ling <martin-git at earth.li>
+Date:   Sat Dec 29 22:22:10 2012 +0100
+
+    rigol-ds1xx2: Initial driver skeleton.
+
+commit aeabd30820bd3b685fb0bac83d1dc4a7faa32287
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Jan 3 02:15:27 2013 +0100
+
+    ols: Implement SR_DI_HWOPTS.
+
+commit 986fde755d6bec3dfbf6d2bf4768ca359fc05174
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Dec 26 01:53:50 2012 +0100
+
+    serial-dmm: Add UNI-T UT61E support (UT-D02 cable).
+
+commit fe0c0b98c6d10290cbd2b461e3cb17404b0ba457
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Nov 7 19:10:36 2012 +0100
+
+    Add Cyrustek ES51922 DMM chip parser.
+
+commit 21d3d4ee871ee84a5ba598b21e9a1bdeaa9db5e3
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jan 1 00:33:05 2013 +0100
+
+    alsa: Add some more samplerates.
+    
+    Add some more samplerates that seem to be supported by some devices
+    (found via random grepping of alsa and kernel sources).
+
+commit a1b9a9bf44b33ee9f3a6ac5ae59a1ced1e2c3281
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Dec 31 23:31:48 2012 +0100
+
+    alsa: Add missing % for PRIu64.
+
+commit 52ba6e05d59d6b2199214aed14330f213e79a593
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Dec 31 23:31:31 2012 +0100
+
+    alsa: Improved error reporting.
+
+commit 721ecf3d97aa6e84e6d61b3c25023e9177895025
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Dec 31 22:54:17 2012 +0100
+
+    alsa: Cosmetics, coding style, typos.
+
+commit 65faa197ae4c607c9c127af99af6c8e5b6acd7b3
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Wed Dec 26 12:11:33 2012 -0600
+
+    alsa: Find supported samplerates during device scan
+    
+    Since we are using the 'hw' interface of ALSA, we don't have the luxury of
+    samplerate conversion, given by the 'plughw' interface. If we try to set a
+    samplerate that is not supported, ALSA will just throw an error.
+    
+    We can test for the supported samplerates, and create a list of supported
+    samplerates, then limit the selection to only those values. The frontend can
+    query the list of supported samplerates.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 729850c9e7dfa2c08c11a025d5a54b8e8e803f3c
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Sun Dec 23 12:57:37 2012 -0600
+
+    alsa: Fix sample acquisition and send normalized values
+    
+    The alsa driver requested signed 16-bit integers from ALSA, but casted them to
+    to an unsigned 16bit before finally casting them to a float. The end result was
+    that half of the wave would be clipped off.
+    We also requested data in little endian format. ALSA can be instructed to send
+    data with the correct endianness for the platform, without needing to worry
+    about what that is.
+    
+    This patch attempts three points, which, together, fix the acquisition:
+    1) Request data from ALSA without specifying endianness; ALSA will handle the
+    endianness.
+    2) Simplify the int16_t to float loop by using straightforward indexes.
+    3) Normalize every value before sending it on the session bus.
+    
+    NOTE: If testing with PulseView, it will appear as if sigrok is sending all
+    zeroes. sigrok is sending correct data, but since the data is normalized,
+    PulseView will incorrectly plot it as a straight line.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 6944b2d02f23cf562574d3d1b37a2d698bdbde4e
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Thu Dec 20 13:47:09 2012 -0600
+
+    alsa: Scan all soundcards and create a sigrok device per input
+    
+    The alsa driver only works with device "default". This limits the driver's
+    scope to whatever device ALSA deems to be "default". It is desirable to have
+    access to all ALSA devices from sigrok.
+    
+    Change the alsa device scan so that:
+    Each alsa device (not alsa card) gets its own sigrok device
+    For example,
+        hw:1,0 == sigrok device 0
+        hw:1,1 == sigrok device 1
+        hw:2,0 == sigrok device 2
+        hw:2,1 == sigrok device 3
+        hw:2,2 == sigrok device 4
+        [...]
+    
+    We don't currently look at alsa subdevices. We only use subdevice 0.
+    Every input device will have its own channels (left, right, etc). Each of
+    those channels gets mapped to a different sigrok probe. A device with 4
+    channels will have 4 probes from sigrok's perspective.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 0d6ff1039447c35fa8b423ee02468e62a5064cab
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Wed Dec 26 20:14:54 2012 -0600
+
+    alsa: Do not use snd_pcm_hw_params_set_rate_near()
+    
+    snd_pcm_hw_params_set_rate_near() will try to use the samplerate closest to the
+    given value, potentially starting the acquisition with a different samplerate
+    than the one specified.
+    
+    Instead, use snd_pcm_hw_params_set_rate(). It will return an error if the
+    samplerate is not supported by the hardware, which is arguably better than
+    collecting data with a different samplerate than the one specified.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit cbc8cbd8bbd664043c349133818e0ab41422c751
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Mon Dec 31 15:14:49 2012 -0600
+
+    rs9lcd: Add missing 'break;'
+    
+    A break was missing for "case MODE_AMP_WIDTH:" in sr_rs9lcd_parse().
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit f4abaa9f6b37d07bd565c74a60139d641e86b1d1
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Dec 31 21:21:39 2012 +0100
+
+    asix-sigma: Fix two compiler warnings.
+    
+    asix-sigma.c:648:9: warning: 'ret' may be used uninitialized in this
+    function [-Wmaybe-uninitialized]
+    
+    asix-sigma.c:1337:20: warning: 'triggerselect' may be used uninitialized
+    in this function [-Wmaybe-uninitialized]
+
+commit b7c3e8499c9dc499874876efdf5fb499368d6f10
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Dec 31 21:05:11 2012 +0100
+
+    session: Fix compiler warning.
+    
+    session.c:258:6: warning: 'ret' may be used uninitialized in this
+    function [-Wmaybe-uninitialized]
+
+commit 6375e1c3eba6243bcaa28f0eee5452cc6f9ae2fd
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Dec 31 21:03:45 2012 +0100
+
+    victor-dmm: Fix compiler warning.
+    
+    protocol.c:106:10: warning: 'factor' may be used uninitialized in this
+    function [-Wmaybe-uninitialized]
+
+commit f057272cac1baeead056502c29faeef83323b0bc
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Dec 31 21:02:14 2012 +0100
+
+    nexus-osciprime: Fix compiler warning.
+    
+    protocol.c:26:46: warning: unused parameter 'fd' [-Wunused-parameter]
+
+commit 811155da461851e8a7f75df898a301a7db48c667
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Dec 31 21:01:53 2012 +0100
+
+    uni-t-dmm: Fix compiler warning.
+    
+    protocol.c:84:5: warning: 'ret' may be used uninitialized in this
+    function [-Wmaybe-uninitialized]
+
+commit 6e9d545cf4f546cbdb8a7ecd16d26e7d5e767a0b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Dec 31 20:58:14 2012 +0100
+
+    rs9lcd: Fix compiler warning.
+    
+    rs9lcd.c:289:19: warning: 'rawval' may be used uninitialized in this
+    function [-Wmaybe-uninitialized]
+
+commit 9116262931773877e4dd279336ebb2be8f182c05
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Dec 30 01:44:58 2012 +0100
+
+    add USBTMC device search helper
+
+commit 80bc663296dade5d21e74fbbc5259b4f1b069fff
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Dec 29 11:19:19 2012 +0100
+
+    tondaj-sl-814: remove unneeded debugging
+
+commit 2239728c43aa12bcac66613bb4c84e745836d19d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Dec 28 17:13:20 2012 +0100
+
+    ols: Add missing 'extern'.
+
+commit d40a8d1455d3e08a17d1f9d96ee59e1826c7d8e1
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Dec 28 16:46:21 2012 +0100
+
+    added VID:PIDs for all Hantek DSO-2xxx/5xxx
+
+commit bdd7618cd1f0645e3446814a9438965863d859f6
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Dec 28 11:22:16 2012 +0100
+
+    configure.ac: Fix CFLAGS settings.
+    
+    Don't override/overwrite CFLAGS in configure.ac, but rather amend it
+    with (currently) "-Wall -Wextra -fvisibility=hidden".
+    
+    This properly allows users/packagers to do things like:
+    
+     ./configure (this will default to using "-g -O2" additionally)
+    
+     CFLAGS="-g -O2" ./configure (same as above)
+    
+     CFLAGS="" ./configure (no additional flags)
+    
+     CFLAGS="-g -O0" ./configure (disable optimization, e.g. for valgrind use)
+    
+     etc. etc.
+
+commit 14766619703e5b16acee2ebef569751ea90009bb
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Dec 19 22:50:07 2012 +0100
+
+    serial-dmm: Rename VOLTCRAFT_VC820 to VOLTCRAFT_VC820_SER.
+    
+    This matches the _ser suffix of the other functions/variables for this
+    device ("ser" denotes that it is used with the serial UNI-T UT-D02 cable
+    as opposed the USB/HID based cables which are handled by the uni-t-dmm driver).
+    
+    But more importantly, the _SER suffix for the enum value will prevent
+    name clashes later, when the uni-t-dmm driver gets a VOLTCRAFT_VC820 enum.
+    
+    Do the same for VOLTCRAFT_VC840.
+
+commit 35e199da505f5b8fadffa58875aaca70a8fde4f2
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Dec 26 01:29:27 2012 +0100
+
+    Fix limit_samples check in various drivers.
+    
+    Check whether a sample limit was actually set (> 0) before checking if
+    that sample limit is reached. This also fixes continuous acquisition mode
+    for drivers which have that.
+
+commit 786934010365a0b33aa8a32a7dc62a2975dba4c7
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Dec 26 00:12:52 2012 +0100
+
+    Shorten probe_names[] arrays everywhere.
+    
+    Also, NULL-terminate all of them.
+
+commit df36acb36a141e81eec0e6c5bd2734f86dd52597
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Dec 26 00:01:37 2012 +0100
+
+    nexus-osciprime: suppress warnings
+
+commit f9b9bd632faf4d5651c31a51026f6cbd219256e4
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Sun Dec 23 12:48:48 2012 -0600
+
+    serial-dmm: Handle time-limited acquisition
+    
+    Implement SR_HWCAP_LIMIT_MSEC capability, to allow acquisition to automatically
+    stop after a specified amount of time.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 47eda193b2ce105ce50ddd284c99d813dacc49a7
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Tue Dec 25 16:21:24 2012 -0600
+
+    rs9lcd: Fix segfault with unusual modes.
+    
+    Some unusual modes required re-parsing the value. Instead of assigning the
+    re-parsed value to *floatval, it was reassigned directly to *analog->data;
+    however, analog->data is not initialized at this point, causing a segfault.
+    This situation was created when moving the radioshack-dmm code to serial-dmm,
+    with the segfault not being observed at that time.
+    
+    Do not write directly to analog->data, but instead use the intermediate
+    variable rawval.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 0853d5e627cc8ec493e52197fc8e9b3175701128
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Tue Dec 25 15:40:30 2012 -0600
+
+    rs9lcd: Convenience fixes
+    
+    Convert bit masks from hardcoded hex values to bit shifts. For example 0x80
+    becomes (1 << 7). This also fixes a typo error in the definition of INFO_DIODE.
+    
+    Add comments explaining that some case values in sr_rs9lcd_parse() are meant to
+    fall through without a 'break;', and explain some of the unusual modes.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit a97a3d708930a62bbc296785664b0d2677b233b2
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Dec 25 19:13:20 2012 +0100
+
+    added Nexus-Computing OsciPrime VID:PID
+
+commit 523dfc2497c8e7c765ea423ec9d638feba9ed73d
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Dec 25 19:09:12 2012 +0100
+
+    nexus-osciprime: basic scanning functionality
+    
+    Unfortunately the device doesn't have an EEPROM on board at all, and so
+    initially enumerates with the default Cypress FX2 VID:PID (04b4:8613).
+    Since we already support using plain FX2* as basic logic analyzers using
+    the fx2lafw firmware, we cannot support that same VID:PID for the
+    OsciPrime. Therefore a USB conn is required for the initial scan.
+    
+    However, once the firmware is uploaded the device re-enumerates as
+    04b4:1004, which we do detect for scanning automatically.
+    
+    Thus, the OsciPrime driver requires one scan with conn parameter to get
+    the firmware uploaded, but it will then keep working until powered off.
+
+commit 35a078bce5cff9b8ff221a9930d271ec90e20ec4
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Dec 24 20:11:38 2012 +0100
+
+    nexus-osciprime: Initial driver skeleton.
+
+commit 2f1e5c7cb7ca72b6ebde7015191486ebfc0ffc70
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Dec 24 20:27:45 2012 +0100
+
+    fluke-dmm: Properly handle continuous mode
+    
+    Same bug+fix as commit d55c89f523e74a2f629bb23e8fd9bf6db7e3758a
+
+commit f1f7e62d6df766f4a65d7854ae2dd745c623c863
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Wed Dec 19 04:15:18 2012 -0600
+
+    session.c: Remove all remaining sources on sr_session_stop
+    
+    Some sources may not be necessarily associated with a device. The best example
+    is the anykey pollfd from sigrok-cli. sr_session_stop only removes sources
+    associated with hardware devices via dev_acquisition_stop. Sources such as
+    anykey are not removed, and thus session->num_sources will not get to 0. As a
+    result, we may get into situations where the event loop enters an infinite
+    state.
+    
+    To prevent this, all we have to do is remove any active sources that are still
+    present after dev_acquisition_stop has been called for all devices.
+    
+    This fixes bug 14.
+
+commit dc890b8f9fa01895d3849e7d5ab8be1146f07b9e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Dec 24 16:57:55 2012 +0100
+
+    asix-sigma: Quickfix for an ASIX SIGMA issue.
+    
+    It's not entirely clear whether this is the right fix, but we're merging
+    it for now, pending later review.
+    
+    See also: http://sigrok.org/bugzilla/show_bug.cgi?id=26
+
+commit b36e715395d220b7542b6038af3742e85e7bab92
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Tue Dec 11 20:51:53 2012 +0000
+
+    fx2lafw: Tidied probe_names
+
+commit 0aba65da9f4031ca6eb7d0c268e4d06b0d0bfa06
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Dec 23 20:41:27 2012 +0100
+
+    ols: Split into api.c and protocol.[ch].
+    
+    Also, drop various no longer needed #include files.
+
+commit a567547e205eca58065f21aa5b1502a34ba315b3
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Dec 23 19:09:11 2012 +0100
+
+    ols: Use logging helper macro.
+
+commit 11fb7110f46a76a4b078896f0e6c9396bf828189
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Dec 24 11:00:55 2012 +0100
+
+    fluke-dmm: 190 series scopemeter support
+    
+    199B only for now.
+
+commit 4cea0ff7febe335aa4607e544561710963d5e5af
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Dec 24 10:59:41 2012 +0100
+
+    fluke-dmm: parser cleanup
+
+commit 9fa09680277cdc1f7f0792bedefff256ad9694ec
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Dec 24 10:56:54 2012 +0100
+
+    fluke-dmm: adapt scanner to accomodate 190 series scopemeters
+
+commit d4b11de09a42710c1c043693d5bda0fc8bc72f90
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Dec 24 10:40:04 2012 +0100
+
+    fluke-dmm: make poll timeout configurable
+    
+    Defaulted to 1s before, but a simple "QM" command on a 199B in scope
+    mode takes 1.7s to come through.
+
+commit d92faf6cacf7088bd241bb8f0b1adc48082e85fb
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Dec 23 18:54:24 2012 +0100
+
+    serial: more debug cleanup
+
+commit 49aaa0bc68c1bf77cd81989c40e471fe7bd161ec
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Dec 20 10:41:48 2012 +0100
+
+    serial: get rid of overly verbose spew
+    
+    It just made spew-level logging unusable; the way sigrok async comms work
+    guarantees most of it was a false error.
+
+commit 9cd9f6b71c35c0203b7e8997ce9425d0dc6e0f4d
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Thu Dec 20 11:33:49 2012 -0600
+
+    alsa: Split into api.c and protocol.c
+    
+    This is the driver model agreed upon for all drivers.
+    
+    As a result of the split, a devc->num_probes field had to be added in order to
+    reduce the interdependence between api.c and protocol.c .
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit acac8fc3500bc1f1e9e43c1508638488d91b2f86
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Wed Dec 19 21:39:38 2012 -0600
+
+    device.c: Fix memory leak in sr_serial_dev_inst_free
+    
+    sr_serial_dev_inst_free() freed all members of sr_serial_dev_inst, but did not
+    free the struct itself, as expected from a free_*() function. This inadvertently
+    caused a memory leak in every place sr_serial_dev_inst is used.
+    
+    Free the struct itself
+    
+    +	g_free(serial);
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit d55c89f523e74a2f629bb23e8fd9bf6db7e3758a
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Sat Dec 22 16:00:44 2012 -0600
+
+    serial-dmm: Properly handle continuous mode
+    
+    serial-dmm does not check if a sample limit is actually in place before deciding
+    to stop acquisition. Since the sample limit is set at 0 by default, operating
+    in continuous mode will cause acquisition to stop before even sending the first
+    sample.
+    
+    Check to make sure we actually are in a sample-limited mode before stopping for
+    this reason.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 17dfb2c32c6686630fd95b2f25e554fa01f8ebd1
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Dec 22 01:33:03 2012 +0100
+
+    configure.ac: Improve check for libusb-1.0.
+    
+    PKG_CHECK_MODULES() checks for libusb-1.0 via pkg-config already, no
+    need to use a "manual" additional check via AC_CHECK_LIB() just to set
+    HAVE_LIBUSB_1_0 in config.h.
+    
+    This helps with cross-compiling setups, among other things.
+
+commit 0254651dcba4b8c34d35845083250586ecf964ed
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Dec 17 19:39:13 2012 +0100
+
+    alsa: Update to latest APIs/conventions.
+    
+    The alsa driver was out of date wrt APIs and libsigrok conventions in
+    general, and wasn't compiling.
+    
+    This fixes the compile and updates it to _basically_ work with the current
+    state of analog support in libsigrok.
+    
+    This is not finished/full support for ALSA analog sampling yet, though,
+    various TODOs remain that will be addressed later.
+
+commit bf53457d1ddea58d1cb7e4feea83ad0cc1d63031
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Thu Dec 13 21:07:53 2012 +0000
+
+    Pass sr_datafeed_packets and payloads with const pointers
+    
+    This patch marks packet structures and their payloads as const.
+    This indicates to packet receivers that modifications to these are
+    not allowed. In general all pointers should be marked const unless
+    modification of the referenced data is explicitly allowed.
+
+commit 16d6e56d124dcedf7273212bbfab1aed6ac7e7aa
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Dec 18 02:25:17 2012 +0100
+
+    hardware/agilent-dmm/Makefile.am: Fix typo.
+
+commit 4f9bf9a202d331b0f2ec088d73d72808e1a934b4
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Mon Dec 17 02:04:35 2012 -0600
+
+    chronovu-la8: Fix memory leak in hw_scan
+    
+    Hardware scanning creates an ftdi_context before attempting to locate devices
+    based on PID/VID. If no devices are detected, execution jumps to cleanup. The
+    context is freed with free(), instead of ftdi_free().
+    
+    We cannot assume that the libftdi context is stored in a contiguous memory
+    region, and thus cannot use a simple free. Case in point, this situation is
+    identified by valgrind as a "definitely lost" memory leak.
+    
+    Use ftdi_free() instead of a simple free() in hw_scan(). Valgrind no longer
+    complains about a memory leak in this area.
+    
+    clear_instances() does not need any modification, as it correctly uses
+    ftdi_free().
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit c0bf69c29b138d18ee9f542985664eeaeeb47a0a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Dec 18 01:30:34 2012 +0100
+
+    fx2lafw: Fix int64_t printing.
+
+commit b99457f09c90ce7fbb0de1793088dd53a59a0d07
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Dec 18 01:26:58 2012 +0100
+
+    fx2lafw: Various cosmetics, typo fixes, etc.
+
+commit a873c5940cc6d2d8f54f2dfdac3a98c4a3d302ee
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Dec 18 00:52:39 2012 +0100
+
+    Consistently use 'di' as variable name.
+    
+    Use 'di' consistently in all drivers as the name for a local, static
+    pointer to the respective driver's 'struct sr_dev_driver'.
+
+commit 443a14d81f44772076aefdb2b252657d6abc0d29
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Thu Dec 6 15:55:14 2012 -0600
+
+    fx2lafw: Print device failed to renumerate error
+    
+    commit 378abfeac6cc94d88dc82b8481dec9c9f691f3da tried to solve a bug where
+    the fx2lafw driver would print "Device came back" even if a timeout had occured.
+    
+    It solved that issue, but inadvertently introduced a new bug:
+    "Device came back" would be printed even if no firmware upload was performed.
+    This is counterintuitive, as the device is only reset when a firmware upload is
+    performed.
+    
+    There are three cases:
+    i)   Firmware upload was successful
+    ii)  Firmware upload failed
+    iii) Firmware upload was NOT needed
+    
+    Each case warrants a separate message from the driver. Print the
+    following messages depending on the outcome:
+    
+    i)   "Device came back"
+    ii)  "Device failed to renumerate"
+    iii) "Firmware upload was not needed."
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit f427daefb01cdaf578dc8b9fa5f59c5525439289
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Thu Dec 13 15:08:05 2012 -0600
+
+    fx2lafw: Use DRIVER_LOG_DOMAIN for log messages
+    
+    Use the new DRIVER_LOG_DOMAIN mechanism, where explicitly writing
+    the driver name in the message string is no longer required.
+    
+    Thus:
+    
+    - sr_err("fx2lafw: Something bad happened.");
+    
+    becomes:
+    
+    + sr_err("Something bad happened.");
+    
+    In either case, the log output is the same.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 006dbe55878ec7499e58a130c27f6c4297ada54b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Dec 16 22:27:04 2012 +0100
+
+    serial_stream_detect(): Drop unneeded sr_spew().
+
+commit 54d112218713b34491cd65454abad340ff19a393
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Dec 16 22:17:48 2012 +0100
+
+    serial-dmm: Add Voltcraft VC-840 (UT-D02) support.
+    
+    This works with the UNI-T UT-D02 (RS232) cable. For the USB/HID
+    based cable (UNI-T UT-D04), the uni-t-dmm driver must be used.
+    
+    Note: This is untested, but should work just fine for all settings, with
+    the possible exception of temperature (testers needed!)
+
+commit 40830061eb3a1327c1a8c76758e84b252e1950a8
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Dec 16 22:03:28 2012 +0100
+
+    serial-dmm: Add Voltcraft VC-820 (UT-D02) support.
+    
+    This works with the UNI-T UT-D02 (RS232) cable. For the USB/HID
+    based cable (UNI-T UT-D04), the uni-t-dmm driver must be used.
+
+commit 16b7b79005aaf0ab67d207ca11989f62d983ce62
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Dec 16 21:28:26 2012 +0100
+
+    serial-dmm: Eliminate unneeded "subdriver" field.
+    
+    Just use the 'int dmm' + wrapper method that is used for all other
+    functions which need this information. There is no real need to
+    special-case the hw_dev_acquisition_start() API call here.
+
+commit 22f54192358620f24fc2df2ea6e8f578fee24b81
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Dec 16 21:23:49 2012 +0100
+
+    serial-dmm: Cosmetics, documentation fixes.
+
+commit 6aed917b133d44199500cdffc0d2f7998add3fb6
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Dec 16 23:06:15 2012 +0100
+
+    lascar-el-usb: fix sample limit parameter
+
+commit 801c7800c6260a2e12aa2618263a717334946eb8
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Sat Dec 15 11:03:10 2012 -0600
+
+    linsigrok.h: Document meaning of SR_UNIT_CONCENTRATION
+    
+    Having concentration as a unit is vague, as it can be expressed in
+    many ways. In the context of sigrok, concentration means a normalized
+    number from 0 to 1.
+    
+    Document its meaning.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 6787f4049a0c05ffb438fc1718f1fe9840be5a41
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Dec 16 18:48:20 2012 +0100
+
+    lascar-el-usb: support for EL-USB-2*
+
+commit ef4344e7f44fe8b67fdbf1cebf2b1a6d7edbfe77
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Dec 16 18:38:44 2012 +0100
+
+    add relative humidity MQ
+
+commit 7249d7833b69c1d753b18112891870d8aeda3d69
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Dec 15 22:50:33 2012 +0100
+
+    analog: support ppm output
+
+commit 7f00750ca4ed224b3880058847e6398f30cbb8f7
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Dec 15 22:49:40 2012 +0100
+
+    lascar-el-usb: properly submit CO concentration as a PPM value
+
+commit b0c95747e1e7ffa7ca9e8ca4a9bdda781469750a
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Dec 15 22:34:40 2012 +0100
+
+    lascar-el-usb: add config saver
+
+commit b6506d5e03e67c5029525d36016936cf9c858720
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Dec 15 11:15:30 2012 +0100
+
+    lascar-el-usb: EL-USB-CO300 support
+    
+    Works the same way as the EL-USB-CO, but with the more sensitive sensor,
+    so should work out of the box.
+
+commit 521a0cd3577db0ec2763493d95d2ffa479568a3a
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Dec 15 11:07:18 2012 +0100
+
+    cosmetics
+
+commit 4f3bd685e695790ff578d17d0ed95c00784e58fa
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Dec 15 10:50:22 2012 +0100
+
+    add MQ/units for carbon monoxide concentration
+
+commit 6aa1eb4ea33e1aeeef772cd234f140464eea3fe2
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Dec 15 04:06:51 2012 +0100
+
+    lascar-el-usb: generic EL-USB support + EL-USB-CO support
+
+commit c5f1a021b82f3c2c56df2a0860bb6f9776e1076b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Dec 9 15:19:39 2012 +0100
+
+    usb: strip overly verbose debugging
+
+commit 9ec7ff94ed08aecc9c8898b00c797fd2621438c4
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Dec 9 14:40:12 2012 +0100
+
+    victor-dmm: free in the right order
+
+commit e7f378fd1ab895259cda8b0545663b39c7bc16f0
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Dec 9 14:39:17 2012 +0100
+
+    usb: strip useless code
+
+commit e7ed87a469cb3c997ec2e98bc2c39d4284d86252
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Thu Dec 13 12:35:06 2012 -0600
+
+    serial-dmm: Use dummy info struct for rs9lcd parser
+    
+    The rs9lcd parser, which is used for the RadioShack 22-812 does not use its
+    *info parameter, and therefore did not have a rs9lcd_info struct declared.
+    
+    With recent re-factoring of the receive data callbacks, it became necessary to
+    pass a struct pointer. This made the RECV_DATA macro look like:
+    
+    - RECV_DATA(RADIOSHACK_22_812, metex14)
+    
+    giving the wrong impression that the RadioShack 22-182 uses the
+    metex14 protocol, which is not the case.
+    
+    Create a dummy rs9lcd_info struct, and correctly identify the parser
+    as rs9lcd in the RECV_DATA macro:
+    
+    + RECV_DATA(RADIOSHACK_22_812, rs9lcd)
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit c69049091ec6e1383805064d3c472264384ffb57
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Thu Dec 13 11:08:38 2012 -0600
+
+    libsigrok.h: Don't store subdriver in sr_dev_driver
+    
+    Not all drivers use subdrivers. The only reason the subdriver field was
+    introduced was to accomodate the model of serial-dmm.
+    
+    The sr_dev_driver struct is available to the frontend. Exposing the subdriver
+    field creates the problem of exposing knowledge of libsigrok's internal driver
+    layout, even though the drivers are designed to be a flat list to the frontend.
+    
+    Store the subdriver in the dev_context struct of serial-dmm.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit d128bf12b27432988cc5a0bf7d6ec3fca0696b0b
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Thu Dec 13 10:53:28 2012 -0600
+
+    serial-dmm: Remove global sr_dev_driver *di alias
+    
+    The global *di alias was used to keep track of the driver context.
+    It caused issues with trying to use several subdrivers at once, so
+    its use was obsoleted.
+    
+    The correct context is preserved through different mechanisms, either
+    the *sdi pointer, or wrappers which pass the correct context.
+    
+    The *di alias is no longer used, so remove it.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 3098b3902d1794831be010ebff0484caf845de60
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Thu Dec 13 08:58:01 2012 -0600
+
+    serial-dmm: Simplify wrapper layout
+    
+    Wrappers for hw_init, hw_cleanup, clear_instances, and hw_scan are needed for
+    each subdriver due to the nature of serial-dmm. These wrappers are implemented
+    as macros, in order to reduce the number of lines of code.
+    
+    For each of those functions, we have a separate wrapper list, then we connect
+    them together in a first-class driver using a DRV macro, and yet another list
+    (the DRV list).
+    
+    Instead of declaring those wrappers in separate lists, include them in the DRV
+    macro. This approach reduces the number of macro lists from five to just one.
+    
+    From the perspective of adding a new subdriver, this also greatly reduces the
+    number of places needed to hook in a new device.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit fd9b2b865ac4e3f12305744753c0759c34c056c4
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Dec 13 01:54:13 2012 +0100
+
+    serial-dmm: Add per-driver clear_instances() wrappers.
+
+commit 0c23677d0bc04a024c382aef64e5146887bdcb1b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Dec 13 01:47:02 2012 +0100
+
+    serial-dmm: Add per-driver hw_cleanup() wrappers.
+
+commit ca4b130943e266f545ae8ba89528f285831540cd
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Dec 13 01:41:34 2012 +0100
+
+    serial-dmm: Add per-driver hw_dev_list() wrappers.
+
+commit ea4c6c2311f2c31ccf6863b13a815918ccee974b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Dec 13 01:27:31 2012 +0100
+
+    serial-dmm: Add per-driver hw_scan() wrappers.
+
+commit dccfe015868b5f1a5a5996983164d135ec561596
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Dec 13 01:19:17 2012 +0100
+
+    serial-dmm: Use a macro for receive_data() wrappers.
+
+commit f1437c6814c693bd624211c5b644951cf16139f2
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Dec 13 00:59:42 2012 +0100
+
+    serial-dmm: Use a macro for driver struct simplification.
+
+commit 06b7a8af7e2e4b7baf28f4fa710a7dd00765f18a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Dec 11 17:06:04 2012 +0100
+
+    serial-dmm: Simplify code a bit.
+    
+    Store/use the receive_data() function and a pointer to the driver struct
+    in the dmms[] array. Use a ".subdriver" entry in the driver struct.
+    Use a macro to simplify hw_init() wrappers.
+
+commit 5b389efcfeff17b0f7466597706c898ad65eb6a9
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Sun Dec 9 13:15:24 2012 -0600
+
+    serial-dmm: Avoid duplicate symbol error
+    
+    Declare dmm_info dmms as extern in protocol.h to prevent duplicate
+    symbol error from the linker.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 378abfeac6cc94d88dc82b8481dec9c9f691f3da
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Thu Dec 6 21:31:37 2012 +0000
+
+    fx2lafw: Don't say "Device came back" when it didn't
+
+commit 26be4ebef369e465eb5f13ee7bbab71b62e455f6
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Wed Dec 5 15:16:52 2012 -0600
+
+    serial-dmm: Fix segfault when no device is used
+    
+    di was initialized as NULL. If no device covered by this driver
+    is used, di remains NULL. This causes a segmentation fault when
+    calling clear_instances().
+    
+    Check for di being NULL.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 63c07e48c627684f04d70e7dea2baf7c72ff2a41
+Author: Peter Stuge <peter at stuge.se>
+Date:   Sat Nov 3 08:29:26 2012 +0100
+
+    backend.c: Return a sigrok error in sr_init() on libusb_init() errors
+
+commit 123d97b17715204c58b795b8e6cbecc55725e5d3
+Author: Peter Stuge <peter at stuge.se>
+Date:   Sat Nov 3 08:27:48 2012 +0100
+
+    backend.c: Fix memory leak in sr_init() error path
+    
+    Commit 785b9ff290cbdb86e7d0b0280c33b43faf9c0518 added libusb init into
+    sr_init() which can generate an error. In this case, the already
+    allocated struct sr_context would have leaked.
+
+commit 1740429d7045385866caafb0d2cbe302e7c74604
+Author: Peter Stuge <peter at stuge.se>
+Date:   Wed Dec 5 01:23:49 2012 +0100
+
+    hardware: A few further USB error message fixups
+
+commit d4928d7102c6b2f9f7aa51a1b98669bf148fff80
+Author: Peter Stuge <peter at stuge.se>
+Date:   Tue Dec 4 21:11:25 2012 +0100
+
+    hardware: Call libusb_error_name() in all USB-related error messages
+
+commit 851d5b2274f138d58be42adbbe584d9a4c4dfe01
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Dec 4 23:58:26 2012 +0100
+
+    lascar-el-usb: add scanning functionality
+
+commit 402704445e081ef7737081885496169f91af7ab9
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Dec 4 23:58:03 2012 +0100
+
+    add thermometer and hygrometer HWCAPs
+
+commit 7ae6a75826be6d7ddd885947630ecb26ba9fa1a5
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Dec 4 23:25:11 2012 +0100
+
+    usb: sr_usb_find() uses standardized connection string to find a USB device
+
+commit 5ea1e54ab54542803d531bd714b09b54fbaab408
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Dec 4 23:11:40 2012 +0100
+
+    add VID:PID for generic SILabs F32x USBXpress chips
+    
+    Used in Lascar EL-USB series devices
+
+commit d458a0ac290c4be4cad19c22e143748a5ddff0e6
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Tue Dec 4 13:31:49 2012 -0600
+
+    ezusb: Use DRIVER_LOG_DOMAIN for debug output
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit f4284934354bff761a74eee545e5a4b7911a8e8c
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Mon Dec 3 19:39:58 2012 -0600
+
+    tondaj-sl-814: Fix unused parameter warning
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit d4abb463a749cd3d614e98c7fe7f5d28ad69475d
+Author: Peter Stuge <peter at stuge.se>
+Date:   Mon Dec 3 03:33:24 2012 +0100
+
+    hardware: Make USB drivers use the libusb_context in struct sr_context
+
+commit 1ebe4b4e6926eb1288ce77b179a92bc670eb9eca
+Author: Peter Stuge <peter at stuge.se>
+Date:   Mon Dec 3 02:49:36 2012 +0100
+
+    hw_init(): Save struct sr_context * parameter in struct drv_context
+
+commit 34f06b903e3529a73feb7a6e74fae934a999f821
+Author: Peter Stuge <peter at stuge.se>
+Date:   Mon Dec 3 02:47:55 2012 +0100
+
+    Add a struct sr_context * parameter to hw_init()
+
+commit 44fc870c9cc5c0e53b47b9d7fa3dffe81731ee3c
+Author: Peter Stuge <peter at stuge.se>
+Date:   Mon Dec 3 02:42:57 2012 +0100
+
+    Add a struct sr_context * parameter to sr_driver_init()
+    
+    Since the public API is changed, this commit also bumps the libtool
+    version component SR_LIB_VERSION_CURRENT in configure.ac.
+
+commit 73496bb57138dcd1aad4800c8c9ffc6484ca9d8a
+Author: Peter Stuge <peter at stuge.se>
+Date:   Mon Dec 3 01:34:23 2012 +0100
+
+    alsa: Remove unused and unprovided hw_init() parameter `devname'
+
+commit 46697e38b286541e0e5aa354d35a6f4564855fa6
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Nov 27 17:40:14 2012 +0100
+
+    lascar-el-usb: Initial driver skeleton.
+
+commit 162b735218b906d5a41e8da69ea15b76d267f1fd
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Dec 2 21:58:34 2012 +0100
+
+    Remove some radioshack-dmm leftovers.
+
+commit ea088bb6930c617b2d615ee47c9442b27f449c43
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Sun Dec 2 13:34:51 2012 -0600
+
+    serial.c: Be more verbose about failing to parse parameter string
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 21829e6708ce1167e2d7d5d370166cafe328f092
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Sun Dec 2 13:15:21 2012 -0600
+
+    radioshack-dmm: Integrate into serial-dmm
+    
+    Use the infrastructure of serial-dmm to handle the RadioShack 22-812,
+    and completely remove radioshack-dmm.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 05f134abc2641e6e4d3a22a8dda19460819af16e
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Sun Dec 2 12:58:30 2012 -0600
+
+    radioshack-dmm: Separate protocol parser from driver
+    
+    Move the parsing part of radioshack-dmm into a separate protocol
+    parser, following the model from hardware/common/dmm.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit ae95ffebfa0d8c0992332b33631a26d898957b34
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Sun Dec 2 12:43:37 2012 -0600
+
+    radioshack-dmm: Fix opening of serial port.
+    
+    During scan the serial port is opened with SERIAL_RDONLY | SERIAL_NONBLOCK,
+    which works fine, but when acquisition starts, it is opened only with
+    SERIAL_RDONLY. On Linux, if cdc_acm can make a claim to the USB to serial
+    converter, opening the port will fail.
+    
+    Open port with SERIAL_RDONLY | SERIAL_NONBLOCK.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit d5ce233fe16a68e6522538c226a91e63628521dd
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Sun Dec 2 09:17:46 2012 -0600
+
+    serial-dmm: Add RadioShack 22-168 support.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit eebb606762218d7e87a18721bad0d47892e220e9
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Dec 2 17:21:13 2012 +0100
+
+    demo: Add missing dev_clear() API call.
+
+commit 55a6daf59f85449d99a62b0a3b6010980125d38d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Nov 11 23:54:49 2012 +0100
+
+    sr_init(): Add driver sanity checks.
+    
+    After sr_init() has successfully run, we can be sure that all drivers
+    define all the API calls, so we don't have to do these checks later
+    in the individual API functions / wrappers.
+    
+    If there are one or more drivers with missing API functions (or driver
+    name / longname, and so on), sr_init() will fail. This helps catch this
+    kind of developer error early on.
+
+commit 3a18cf625e6f611041554d81c178b29cec19b484
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Dec 2 16:11:42 2012 +0100
+
+    serial-dmm: Drop accidentally committed file.
+
+commit 7f64e88fa99d54f22a999e7461e4f13c70f0aa8c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Dec 2 16:09:31 2012 +0100
+
+    Reduce glib minimum version to 2.28.0 again.
+    
+    We no longer use g_thread_try_new() which is only available since 2.32.0.
+
+commit 3b20367381bcd955e604c40d05f489f2221c036a
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Sat Dec 1 18:07:10 2012 -0600
+
+    demo: Do not use a separate thread for generating data
+    
+    We already have an event-based mechanism in place. Using a thread just
+    adds unneeded complexity, especially for a driver designed not for
+    performance, but for providing a testbed to frontends.
+    Generate the data in the event handler, not in a separate thread.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit d4bd66a0c7196fb44f6f22036e3ea452ad5870df
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Dec 2 01:32:57 2012 +0100
+
+    serial-dmm: Add PCE PCE-DM32 support.
+
+commit a376ffea49411cca09b358f3677938612c79afaf
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Dec 2 01:02:16 2012 +0100
+
+    serial-dmm: Add PeakTech 4370 support.
+
+commit a53da08254a5adcc15c925014eb1083fb067f3b6
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Dec 2 00:40:15 2012 +0100
+
+    serial-dmm: Add Metex M-3640D support.
+
+commit 9871215c83f70a2008272de03268291445ed59c3
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Dec 2 00:36:37 2012 +0100
+
+    metex14: Add dB mode and hFE mode support.
+    
+    This is found e.g. on the Metex M-3640D DMM.
+
+commit 6dca2f16eedfbcaa0ea4e45c7d58bbf596fa1012
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Dec 1 23:32:39 2012 +0100
+
+    serial-dmm: Add V&A VA18B support.
+
+commit 5887c9cc1af1d4798d61b338d66b573b1273f9c4
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Dec 1 23:04:00 2012 +0100
+
+    serial-dmm: Add MASTECH MAS345 support.
+
+commit f0ac4929d3aaa83e32b0be0637ae1f22040ea724
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Dec 1 22:45:45 2012 +0100
+
+    serial-dmm: Add PeakTech 3410 support.
+
+commit ce3777ada98c5099d2867653f25239b85cf55708
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Dec 2 14:22:15 2012 +0100
+
+    serial-dmm: Add Metex ME-31 support.
+
+commit f086b83011b1282f62f0058872f333aef4bf9daa
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Dec 1 19:53:05 2012 +0100
+
+    serial-dmm: Add Digitek DT4000ZC support.
+
+commit e90cf076aa6854ad3f312179a121bafc4c6e9a22
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Dec 1 20:48:03 2012 +0100
+
+    metex14: Add sr_metex14_packet_request().
+
+commit 8f46911e4252bddb680fb9adc603ea2640f1724e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Dec 1 20:11:40 2012 +0100
+
+    metex14: Fix 'is_ol' handling.
+    
+    Thanks to Bert Vermeulen for the reminder.
+
+commit 2477fb95693aeeeab04323618ba18b1ebdbc3eb2
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Fri Nov 30 13:15:44 2012 -0600
+
+    metex14: Parse microamp (uA) values.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 3ebc9b59a2e2b96ad95dbfdf3218c3b3b00940ef
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Fri Nov 30 13:11:04 2012 -0600
+
+    metex14: Fix parsing of measurement flags.
+    
+    strcmp(buf + 9, "  mA") does not work because buf is CR-terminated,
+    while "  mA" is NUL-terminated.
+    
+    Drop ambiguities arising from the termination of the strings, and
+    only compare the characters we care about, using strncmp().
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit e82d7dbc202794dc30abdb4e50cfb4507f49025e
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Fri Nov 30 12:40:17 2012 -0600
+
+    metex14: Print contents of received packet.
+    
+    The packet is an ASCII string. We can simply print the raw packet data.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 76b55dfa8a5318a0495d3f2cfb29d6cd229ce5dc
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Fri Nov 30 12:29:22 2012 -0600
+
+    metex14: Fix parsing of spaces.
+    
+    When the parser found a space, it treated it as an invalid digit
+    and discarded the whole packet. This behavior was incorrect on
+    2000 count devices, where the first digit can be sent as a space
+    rather than a '0'.
+    
+    Convert spaces to '0' and parse them as usual.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 21a7f2692e09269edd872bca4e25a9d06b67c0e5
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Dec 1 19:35:19 2012 +0100
+
+    Rename tekpower-dmm to serial-dmm.
+    
+    This is now a generic driver for multiple DMM "subdrivers" that use simple
+    serial port protocols.
+
+commit 729b01f98838b50263511ec135754d741698659b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Dec 1 19:28:36 2012 +0100
+
+    tekpower-dmm: Generalize & first-class TP4000ZC driver.
+    
+    Prepare the tekpower-dmm driver to be able to support various simple
+    serial port based DMMs.
+    
+    Also, make a 'tekpower-tp4000zc' "first-class" driver which is currently
+    the only user of this generic driver.
+
+commit 1fbab466268bf6975c0709d5554ce2192a21ef6c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Dec 1 19:01:07 2012 +0100
+
+    metex14: Pass 'info' as a void pointer.
+    
+    This is done so that the function prototype of all sr_*_parse() DMM
+    functions is the same, which will be needed later.
+
+commit 93357bc3ce484c2e46a9999d4464ce2d5cc976b6
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Dec 1 18:50:35 2012 +0100
+
+    fs9721: Pass 'info' as a void pointer.
+    
+    This is done so that the function prototype of all sr_*_parse() DMM
+    functions is the same, which will be needed later.
+
+commit d84fc9cb3b9fede9234603f95c1467f95686c1a7
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Nov 28 17:14:42 2012 +0100
+
+    tekpower-dmm: Drop unneeded g_try_malloc().
+
+commit 5ddb0cc7d4850375a9ef741012d229ead9a91490
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Dec 2 14:10:27 2012 +0100
+
+    serial: Don't hardcode parity and stop bits on Windows.
+
+commit 5ae35c29a7010cd018e43d04a809e1c60b7b72fa
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Dec 2 13:56:13 2012 +0100
+
+    serial: Full baudrate support on Windows/MinGW.
+
+commit 39e5d79826cd2c1991007faf1a6cde05af995aa9
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Dec 2 13:41:49 2012 +0100
+
+    serial: RTS/DTR support on Windows/MinGW.
+
+commit a54dd31e380ca4b469a20e41a0023d1dd9ec3c99
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Dec 2 12:45:54 2012 +0100
+
+    serial: Use OS-independent flags for serial port opening.
+    
+    Add SERIAL_RDWR, SERIAL_RDONLY, and SERIAL_NONBLOCK (for now), which are
+    mapped to the respective OS-specific mechanism in serial_open().
+
+commit 0f84cda05d808f2e1c93ee14c4223be85fb9ef84
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Dec 1 22:34:53 2012 +0100
+
+    serial: Fix Windows build.
+
+commit c216d62307a000c75265594a34e8fefee7ba9efc
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Sat Dec 1 12:49:15 2012 -0600
+
+    demo: Properly stop acquisition after reaching our sample quota
+    
+    The demo driver was using sr_session_source_add_channel() to add
+    a poll source, but was relying on sr_session_run_poll() to call
+    sr_session_source_remove(). This, coupled with the design of the
+    driver caused errors once the samples were collected.
+    
+    The error stream was most likely related to failing to properly close
+    one of the channels.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 49145a63c73e212e43f1ec901bfb4fe9f99e3caf
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Sat Dec 1 12:03:45 2012 -0600
+
+    demo: Be more verbose about starting/stopping acquisition
+    
+    This is the first step in fixing the demo driver: figuring out what is
+    being called and what is not _and_ have it show up in the logs.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 71caaad46bf285681d4921db796b81746324ff29
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Nov 27 00:50:51 2012 +0100
+
+    serial: allow for extra rts and dtr options in conn string
+    
+    Options in addition to the usual "9600/8n1" syntax start with a
+    slash, and take the form of key=value, where different options are
+    also separated by slashes. For example:
+    
+    	"9600/8n1/rts=0/dtr=1"
+    
+    This sets RTS low and DTR high.
+
+commit 700dcd5caa1d7569469cd7823add6ffd2ed5a2ee
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Nov 26 17:01:15 2012 +0100
+
+    serial: Initial code for setting DTR/RTS.
+    
+    Currently disabled until option parsing is in place.
+
+commit 6b7ace4832b3b574399098de2ad4f4bd0f35a14e
+Author: Petteri Aimonen <jpa at git.mail.kapsi.fi>
+Date:   Thu Nov 22 23:15:27 2012 +0200
+
+    Add compress option to input/vcd.
+
+commit 904735876118f0ff00ae34e1dbdb80dba752bf2d
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Wed Nov 21 19:33:55 2012 -0600
+
+    radioshack-dmm: Be more verbose with packet checks
+    
+    Add sr_spew() messages to state why the packet was found to be invalid.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 2ecc5d432fd17127fd221ca4940f9617569911d1
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Wed Nov 21 19:30:26 2012 -0600
+
+    radioshack-dmm: Check for valid mode before calculating checksum
+    
+    The packet mode byte is akin to a signature. If that is invalid, there's
+    no point in calculating the checksum, so check the mode first.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 54be7c005ed9f1f0eab80d1d1de528c8e8d7ce49
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Wed Nov 21 19:19:58 2012 -0600
+
+    radioshack-dmm: Improve serial detection
+    
+    For device detection, use serial_stream_detect() instead of
+    serial_readline() + custom logic.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 551c3d8ce36bebe02765c76ee4d04f4e700d61b2
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Wed Nov 21 19:18:21 2012 -0600
+
+    serial.c: Sanitize serial_stream_detect
+    
+    Print the timeout in miliseconds, not microseconds.
+    Only calculate elapsed time once oer loop.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 8be8746951e5538147370d9871a4c1ed0268db52
+Author: Petteri Aimonen <jpa at git.mail.kapsi.fi>
+Date:   Wed Nov 21 17:03:49 2012 +0200
+
+    Improve compatibility with various kinds of VCD files.
+
+commit 0157808d740ec11f3a94f2d147b4429bd2a9954d
+Author: Petteri Aimonen <jpa at git.mail.kapsi.fi>
+Date:   Wed Nov 21 16:28:55 2012 +0200
+
+    Add downsample and skip parameters to input/vcd.
+
+commit 61a429c963fb21c3d8cb8e9166d621526724b714
+Author: Petteri Aimonen <jpa at git.mail.kapsi.fi>
+Date:   Tue Nov 20 22:24:17 2012 +0200
+
+    VCD data parsing
+
+commit 99eaa20695b2e6c41721072c84215331bbd3f3bf
+Author: Petteri Aimonen <jpa at git.mail.kapsi.fi>
+Date:   Tue Nov 20 21:03:06 2012 +0200
+
+    Beginnings of VCD input module.
+    
+    File header parsing implemented.
+    Data parsing not yet implemented.
+
+commit 8c012adbc15fcb00aee23f472b08b108d46b818b
+Author: Petteri Aimonen <jpa at git.mail.kapsi.fi>
+Date:   Tue Nov 20 21:02:14 2012 +0200
+
+    Add support for fs and ps to sr_parse_period.
+    
+    These time units are used in VCD files.
+
+commit ac913e5c3522fcf5a5633eaa8e19f6579dda554c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Nov 14 18:38:26 2012 +0100
+
+    Add Metex 14-byte ASCII protocol parser.
+
+commit 90165efe55de692e6329d0820d867d0887db5663
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Nov 16 15:26:17 2012 +0100
+
+    ols: if no serial port specified, this driver is not used.
+
+commit 766456be1c144b0985807279ffd697a395083cae
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Nov 14 18:35:37 2012 +0100
+
+    Move serial_stream_detect() to serial.c.
+
+commit e42b82a66f4a16dcc17ccf018637daa7a1a0df51
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Nov 14 18:29:27 2012 +0100
+
+    configure.ac: Update NEED_SERIAL list.
+
+commit 4da1a800df3ce7776b3a533308dabf484fae9a34
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Nov 14 18:20:13 2012 +0100
+
+    serial: Compile-fix for Windows/MinGW.
+
+commit 6bef68a7e1abd472753e16e2188aadd36650c163
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Nov 5 23:25:59 2012 +0100
+
+    tekpower-dmm: Cosmetics.
+
+commit 2546b05c801c90a84fb2e6690d8c253c6576b4ab
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Fri Nov 2 10:53:06 2012 -0500
+
+    tekpower-dmm: Improve serial detection.
+    
+    Serial detection was using serial_readline, which stripped carriage
+    return from the packets. This made for a very unreliable detection
+    mechanism.
+    
+    Switch to a timeout-based detection mechanism that parses the data
+    as it comes in. This also allows us to stop parsing once we found
+    our first valid packet.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit bda8fc98b1eae0fbd7c57b9da705bfce4384756a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Nov 14 15:18:02 2012 +0100
+
+    Drop obsolete genericdmm driver.
+
+commit d35afa87c9e6d40d34154a784b62deeaffc3ad80
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Nov 12 12:50:42 2012 +0100
+
+    tekpower-dmm: use new serial API
+
+commit 401476daaf3006c0362bdeb7ee99f1d9b9b78809
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Nov 12 12:41:10 2012 +0100
+
+    radioshack-dmm: use new serial API
+
+commit 19ee7dff78f7195bfc82f14ef659751cdd0f6476
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Nov 12 03:00:32 2012 +0100
+
+    tondaj-sl-814: use new serial API
+
+commit f306ca61f65cb703b38e447bbd3dbea3ff9c57c0
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Nov 12 02:48:04 2012 +0100
+
+    colead-slm: use new serial API
+
+commit 109a3ba4137874373b249fee90055373e13a2a1a
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Nov 12 02:25:37 2012 +0100
+
+    agilent-dmm: use new serial API
+
+commit 58d03f034f0d85a2840ed0bc9ea66506b5a1fa1b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Nov 12 02:25:17 2012 +0100
+
+    fluke-dmm: use new serial API
+
+commit 530f201eb8280b343529747107c15e91c2ab0623
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Nov 12 02:24:47 2012 +0100
+
+    ols: use new serial API
+
+commit 299bdb249ecaa9f42900a8f1a0fa0404d619c27a
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Nov 11 20:38:47 2012 +0100
+
+    serial: revamp internal API
+    
+    The only thing to get passed around now is the struct sr_serial_dev_inst
+    pointer. This should make things more portable as well.
+
+commit de6e0eca95f5d89e12b0940f2ecf59ab563cb725
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Nov 11 19:40:14 2012 +0100
+
+    sigma/la8/demo: s/SR_PROBE_ANALOG/SR_PROBE_LOGIC/.
+
+commit 472bbb464bf9522ed757826ec590aaf8bab087b5
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Nov 11 13:17:44 2012 +0100
+
+    alsa: Use message logging helpers.
+
+commit a0a23863daecce5b7aaff352ad2bc5f47eb9bd0b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Nov 11 13:11:58 2012 +0100
+
+    output/gnuplot: Drop obsolete code.
+
+commit 121c18854a4327aedbc46378638d1bb20d67b2d8
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Nov 11 13:10:29 2012 +0100
+
+    contrib/Makefile.am: Add missing files.
+
+commit a885ce3ee9ed770594d5b231f6dec0b740bba03b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Nov 11 12:44:16 2012 +0100
+
+    Various subsystems: Use message logging helpers.
+
+commit a944a84b17c5f5544b45e27dc07d7f60a4fd6ba8
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Nov 11 09:36:21 2012 +0100
+
+    Output modules: Use message logging helpers.
+
+commit 8e7f1cfd99a37d21ebe3365067cd21b76e866d1c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Nov 11 09:20:08 2012 +0100
+
+    Input modules: Use message logging helpers.
+
+commit 64d33dc28e0e815cade56feb65f26a3d36421a96
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Nov 11 09:30:42 2012 +0100
+
+    All drivers: Drop unneeded comments.
+
+commit fa7730623a82bd1703b0d91adb97693e29b2a70c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Nov 11 09:28:30 2012 +0100
+
+    victor-dmm: Cosmetics.
+
+commit 5df7b201563f46b5620a027c59cb054f8887966b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Nov 11 03:27:51 2012 +0100
+
+    serial: avoid Cyrillic conversion specifiers
+
+commit fe1c50fba6b96400d9cc83c852a59f9ac9f2f148
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Nov 11 03:10:29 2012 +0100
+
+    ols: fix device discovery
+
+commit a99e0d2a0c9d1bb4db5623ba50f83486238ee793
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Fri Nov 9 19:52:45 2012 -0600
+
+    ols: Do not randomly probe serial ports
+    
+    ols driver used to probe a series of available serial ports obtained
+    by regexp matching of common serial port names.
+    There are a number of problems with this approach:
+    1. It will probe all serial devices, including devices that do not
+    like to be probed, potentially causing them to act up.
+    2. It will try to probe serial ports which may already be opened in
+    other applications for other purposes.
+    3. It assumes the naming of the serial ports is set in stone, and
+    creates an unnecessary OS-specific list.
+    4. It produces unnecessary debug output even when an OLS device is
+    not connected.
+    5. etc...
+    
+    Do not implicitly probe serial ports. Only probe the port specified
+    by the frontend, if any; otherwise, just quit.
+    Also get rid of all functionality in serial.c which was designed
+    specifically for random probing.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 2244356d1069c5b13fe3b728a421750900deaafe
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Nov 11 02:11:49 2012 +0100
+
+    comment fix
+
+commit 56eb9f95ba8828aa643eb836e62d3d7c9a0bdd33
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Nov 10 19:39:37 2012 +0100
+
+    link-mso19: Use message logging helpers.
+
+commit 92bcedf6e861a11d0b46d2bf5bc7c221b20baa7b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Nov 10 18:24:05 2012 +0100
+
+    demo: Use message logging helpers.
+
+commit e98b7f1be0a97207b9a0b4d7c9a8d397fb542eb1
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Nov 10 18:19:30 2012 +0100
+
+    hantek-dso: Use message logging helpers.
+
+commit 47f4f073e0a7fe68a55001180c3c9092551f2108
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Nov 10 13:42:00 2012 +0100
+
+    asix-sigma: Use message logging helpers.
+
+commit 936e27f19712572d5a1c506dc0ef59aad8743fc4
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Nov 10 13:32:46 2012 +0100
+
+    radioshack-dmm: Use new file naming conventions.
+
+commit 4e172b8f8d725667d632484f340b1eec47597097
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Nov 10 13:30:02 2012 +0100
+
+    radioshack-dmm: Move some stuff out of .h file.
+    
+    Most of the enums and #defines are not needed in multiple files, just
+    put them in the respective .c file where they're used.
+
+commit ba6383f85574e4e374a141ca88979db86fe2893d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Nov 10 12:51:57 2012 +0100
+
+    radioshack-dmm: Cosmetics, coding-style, cleanups.
+    
+    Also, drop some uneeded code and simplify some parts.
+
+commit 302c4b5ab54625f3f94af3efe3ee3acf9cea8114
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Nov 10 01:42:32 2012 +0100
+
+    serial: Deduplicate log messages a bit.
+
+commit c073af80f89d8bce8675068d084c96e0cf37bb4f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Nov 9 03:40:53 2012 +0100
+
+    Add initial Tondaj SL-814 protocol handling.
+
+commit aa2af32432b3410421a89303ef48cc990ff39db9
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Nov 9 03:33:05 2012 +0100
+
+    tondaj-sl-814: Initial driver skeleton.
+
+commit 63f7cb9791d2b5fbd32a897e94790c9a6def8462
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Nov 7 01:25:10 2012 +0100
+
+    agilent-dmm: use standard serial_readline()
+
+commit 318dd53c7093aa2ea26e0d246b23ffeb77b46707
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Nov 7 01:24:23 2012 +0100
+
+    serial_readline() now terminates on and strips CR and/or LF
+
+commit b87f8504dc82eab0155263887662ac14c252414d
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Nov 7 01:23:24 2012 +0100
+
+    g_get_monotonic_time() takes a signed int64
+
+commit 74ac7d7f735011012fb942577e38ddfe64738c8d
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Nov 7 00:46:30 2012 +0100
+
+    agilent-dmm: no need to specify a serialcomm scan parameter
+    
+    It's always 9600/8n1 anyway.
+
+commit 33e8a3c5258d9ac92841cf47abd1e1f7528d640b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Nov 7 00:39:46 2012 +0100
+
+    chronovu-la8: not a bug if an unused driver gets asked to clean up
+
+commit ff945683664a916566289f9bdbb371dfba6f3176
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Nov 6 19:37:33 2012 +0100
+
+    victor-dmm: add protocol decoder
+
+commit 642e9d623cebda60d53d13cf637c42eab8df3c73
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Nov 6 19:32:53 2012 +0100
+
+    more deconstifying sr_dev_inst for dev_acquisition_stop()
+
+commit 7a36037546aaf11b91ff5d63fbd571e15407e357
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Nov 6 15:14:34 2012 +0100
+
+    victor-dmm: add basic USB driver skeleton
+
+commit 69b07d14db24055d23bbb4c4cc718ec073ece0b7
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Nov 6 15:02:37 2012 +0100
+
+    allow for intermediate stage in stopping acquisition
+    
+    In the case of USB drivers, a driver's dev_acquisition_stop() cannot
+    simply remove its fd sources from the session and close its devices:
+    a USB transfer might still be underway, and it needs to be finished
+    (and its memory freed) properly.
+    
+    An sr_dev_inst->status value is added: SR_ST_STOPPING, which should
+    be set when the driver's dev_acquisition_stop() is called, and acts
+    as a marker for the USB event handler to wind up its operations.
+    
+    In order for dev_acquisition_stop() to be able to set the sdi status,
+    however, it needs to be unconstified.
+
+commit ac3898d2d09f54862522967f10487a0708df810c
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Nov 2 20:47:06 2012 +0100
+
+    victor-dmm: Initial driver skeleton.
+
+commit 0ab0cb942f59e2232921c10d79ed43cad6cf3153
+Author: Toshiaki Yoshida <yoshida at mpc.net>
+Date:   Mon Nov 5 16:06:14 2012 +0900
+
+    zeroplus-logic-cube: Fix samplerate and trigger
+    
+     - Default to 1MHz.
+       The default sample rate is the lowest frequency (100Hz),
+       but it takes a very long time until 128K memory is full.
+    
+     - Fix the 1MHz setting.
+    
+     - Use samplerate list.
+    
+     - Fix 10MHz frequency.
+    
+     - Fix trigger.
+    
+     - Change the size of memory according to the number of samples.
+    
+     - Add pre-trigger (capture ratio) setting.
+    
+     - Fix the first acquisition after power on.
+
+commit 41d9427f27f8d175fb0a0259c4e4507ca818b616
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Nov 2 23:44:09 2012 +0100
+
+    uni-t-dmm: Use new USB helper functions.
+
+commit 0c632d36be4b7b34addadf0649fea95173fe0f9a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Nov 2 21:04:21 2012 +0100
+
+    genericdmm: Factor out USB functions.
+    
+    Move sr_usb_connect() and sr_usb_open() to hardware/common/usb.c in a
+    slightly more generic form and add more error checks and logging.
+    
+    Let genericdmm use the new/moved functions.
+
+commit 538ac9a91e5efb65e3c28d5a9af16c6fcfd63872
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Nov 2 20:43:49 2012 +0100
+
+    colead-slm: fix sloppy driver context handling
+
+commit f18297a5fd88f09a9e1a1330777f6db6dfe8999a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Nov 2 19:05:53 2012 +0100
+
+    HACKING: Document enum setup.
+
+commit 24d04d1e3de61cc3f1f12c3091bf393ee2dac8de
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Fri Nov 2 11:56:56 2012 -0500
+
+    Avoid future ABI breakage by hardcoding enum values.
+    
+    Whenever we added a field to the enums in libsigrok.h, we were running
+    the risk of breaking ABI compatibility. Any reordering of existing values
+    or the addition of entries other than at the bottom of the list would
+    cause an ABI breakage.
+    
+    By hardcoding the values we ensure that any added field will have an
+    unused value, and will not take a value previously used by a different
+    flag. By doing this, we avoid confusing frontends compiled with an
+    earlier API.
+    
+    We use 10000 as the first entry of each enum, and each "category" gets
+    an explicit number (10000, 20000, 30000, and so on).
+    
+    Also avoid making the first value of an enum zero. A value of zero is
+    used as terminator item in some lists.
+    
+    Remove explicit "DUMMY" (terminator) enum entries, they're not needed.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 83e3c368c67d6bbc86015fc47a7f7e39160b3baa
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Nov 2 18:49:00 2012 +0100
+
+    serial: Output successful open and the FD.
+
+commit 20af610683e4d7fc22deaa26e7b92730057405cd
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Nov 2 18:44:52 2012 +0100
+
+    serial: Fix two segfaults.
+
+commit c485db908ae2c8f3f85eb70c2a5f86bcc2cab975
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Nov 2 18:35:08 2012 +0100
+
+    serial: Fix some sr_err() items.
+
+commit 43d8eaf601416ff5f06eca4d1433cb4381821081
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Nov 2 18:16:58 2012 +0100
+
+    genericdmm: Drop left-over entry.
+
+commit 441b80035e0f64e4149ae9d85f2d96fee6cde5bd
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Nov 2 18:05:18 2012 +0100
+
+    genericdmm: Drop some dead code.
+
+commit b19f4622b6a1d21b00bd93d99e10bb4565ed7af0
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Nov 2 15:58:54 2012 +0100
+
+    serial: More error-checking & logging, add baudrates.
+    
+    This mostly affects the non-Windows code so far, the rest will follow.
+
+commit d7c776b9ff604bc05ff59ca69539e2179180f5df
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Nov 2 15:57:21 2012 +0100
+
+    serial: Add missing "break"s.
+    
+    This would otherwise cause bugs when e.g. asking for 2 stopbits.
+
+commit a8d09e13264be77bcf1fe53202880ce4c26e39f9
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Nov 2 15:21:43 2012 +0100
+
+    colead-slm: SL-5868P support
+
+commit fc19c288b5ee32618a10f73fda7475b9a5a8ac6d
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Nov 2 15:20:10 2012 +0100
+
+    add support for sound pressure level measurements
+
+commit 258eeb77b88852b743e08a751455a2c1965e4db1
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Nov 2 15:19:01 2012 +0100
+
+    output/analog: add support for sound pressure level
+
+commit bde4f4296d8d7a3653c93fc7034e6f7c019e1255
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Nov 1 23:38:10 2012 +0100
+
+    analog: if no MQ unit was set of recognized, just print the value
+
+commit 4d729ddcaf395de1d04af93dd5ea569cfbc17de4
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Oct 29 22:33:47 2012 +0100
+
+    colead-slm: Initial driver skeleton.
+
+commit 8c1adf3738b68912ab8cf4308341b82dbc83056a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Nov 1 15:58:09 2012 +0100
+
+    Rework FS9721 parser.
+    
+    Merge parts of the tekpower-dmm code (the chip of the TekPower
+    TP4000ZC seems to be an FS9721_LP3 too) and rework parts of the functions.
+    
+    Adapt the tekpower-dmm and uni-t-dmm code accordingly.
+
+commit be5c1d3b52a4c774bdd182ba54225a234d55336f
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Mon Oct 29 23:42:10 2012 -0500
+
+    tekpower-dmm: Use generic fs9721 parser
+    
+    Replace the parser with the fs9721 parser, which is just an adapted
+    version of this parser.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit db7d0626c918209db0ba5dc6e896232c8c2e4f6c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Oct 30 20:30:25 2012 +0100
+
+    Remove 'float' output module.
+    
+    This has been replaced by the 'analog' output module.
+
+commit 886a52b6fbffb0fd06849c928cf9fd31a0d4657b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Oct 30 20:20:22 2012 +0100
+
+    Return SR_ERR_MALLOC upon allocation errors.
+    
+    Add some TODOs.
+
+commit 6f22a8ef2ccf7091324b41b553632695507215a7
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Oct 30 19:59:21 2012 +0100
+
+    Factor out serial_readline() to serial.c.
+    
+    Only one (slightly different) variant remains in agilent-dmm, this will
+    be merged soon too, though.
+
+commit 2980cc249494ac8335296fae7beac52fb078b22b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Oct 30 18:56:04 2012 +0100
+
+    genericdmm/victor-dmm: Use message logging helpers.
+
+commit dccbd0ede0013318da866ae941c64e23ad3e2027
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Oct 30 18:52:20 2012 +0100
+
+    radioshack-dmm: Use message logging helpers.
+
+commit 38d326e879c6e1bb7d4a11682c262ca838a7dde5
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Oct 30 18:50:15 2012 +0100
+
+    agilent-dmm: Use message logging helpers.
+
+commit 31d84da3a22cc6fc9b2226ab3863e9235a3d5b87
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Oct 30 18:48:33 2012 +0100
+
+    fluke-dmm: Use message logging helpers.
+
+commit 6ac5f8922e63d1f584a69969190af0389a88d812
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Oct 30 14:23:05 2012 +0100
+
+    uni-t-dmm: Simplify subdriver setup.
+    
+    So far, it seems we can make this work with just hw_init() needing to
+    be subdriver-specific (it will point 'di' to the respective per-subdriver
+    entry), the rest of the API functions can then use a strcmp() on di->name to
+    learn which subdriver they belong to.
+
+commit fdbcb86dba17eec8e1492736adf1aec45e746c00
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Oct 30 13:11:27 2012 +0100
+
+    Draft: Make UT61D and VC-820 "first-class" drivers.
+    
+    The 'uni-t-dmm' driver/directory will not appear as a "driver" to
+    frontends anymore, it's just an internal thing.
+    
+    The frontends will see a uni-t-ut61d and voltcraft-vc820 driver now,
+    with the correct names and parsers etc. attached to them.
+    
+    This is not fully finished yet, but it's a start (and works mostly):
+    
+      $ sigrok-cli -D
+      The following devices were found:
+      UNI-T UT61D with 1 probe: P1
+      Voltcraft VC-820 with 1 probe: P1
+    
+      $ sigrok-cli --driver voltcraft-vc820 -D
+      The following devices were found:
+      Voltcraft VC-820 with 1 probe: P1
+    
+      $ sigrok-cli --driver uni-t-ut61d -D
+      The following devices were found:
+      UNI-T UT61D with 1 probe: P1
+    
+      # Now attaching a UNI-T UT61D device via USB.
+    
+      $ sigrok-cli --driver uni-t-ut61d --samples 3 -O analog
+      P1: -0.017800 V DC
+      P1: -0.017600 V DC
+      P1: -0.017700 V DC
+    
+      # Now attaching a Voltcraft VC-820 device via USB instead.
+    
+      $ sigrok-cli --driver voltcraft-vc820 --samples 3 -O analog
+      P1: -0.319200 V DC
+      P1: -0.319300 V DC
+      P1: -0.319300 V DC
+
+commit 4ca378df8874b8e0bfd323c725c019c3968c0e1e
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Oct 29 22:10:05 2012 +0100
+
+    don't use deprecated g_thread_init/_create
+
+commit 7445ed9158294e39ec697f54944e19a4b9636a6a
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Oct 29 22:08:34 2012 +0100
+
+    require glib version >= 2.32
+    
+    This allows us to do away with a few deprecated g_thread functions
+    in demo.c which throw deprecation warnings since glib 2.32.0.
+
+commit 015f1508ad57e1ace60965952389a0b83c271178
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Oct 29 15:20:17 2012 +0100
+
+    uni-t-dmm: Voltcraft VC-820 draft support.
+    
+    This is commented out so far, will be implemented properly soon.
+
+commit 6c701476ad76c648e9b367ac340c2dd0063e4ed0
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Oct 29 12:02:05 2012 +0100
+
+    Add protocol parser for FS9721_LP3/FS9721B.
+    
+    The Fortune Semiconductor FS9721_LP3 and FS9721B/Q100 DMM chips are very
+    similar and the protocol looks identical.
+    
+    Tested on a Voltcraft VC-820 (FS9721_LP3) with the uni-t-dmm driver
+    (needs some small changes, tbd).
+
+commit a28dac0a7307f222e8e145ccc8188519206d0c4c
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Oct 29 11:54:20 2012 +0100
+
+    fluke-dmm: code cleanup
+
+commit 2c04dede20e1e69420d872878e8d04792333626c
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Oct 29 11:50:34 2012 +0100
+
+    Fluke 287/289: support for dBu/dBV measurement units
+
+commit 79081ec80c79801c439a1a3756cf5426af0739b8
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Oct 27 22:41:50 2012 +0200
+
+    Initial support for UNI-T DMMs.
+    
+    This is not yet fully finished, but works for most use-cases.
+    
+    Tested with a UNI-T UT61D using the UT-D04 USB/HID cable (new version).
+
+commit 45e080b60b2526fd9723dd822215294f973bff2a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Oct 27 22:21:07 2012 +0200
+
+    la8: Rename driver.[ch] to protocol.[ch].
+
+commit f3a35908ef0d9fd56ec170d7f1bafff50c3432e2
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Oct 27 21:27:15 2012 +0200
+
+    la8: Adapt to new driver conventions.
+
+commit 9eb2bb960181302893e7c9032dbaba7763132174
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Oct 27 21:07:39 2012 +0200
+
+    configure.ac: Cosmetics.
+
+commit bbabddbd64d07811120230203d453c65ac53ce57
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Oct 27 21:03:02 2012 +0200
+
+    tekpower-dmm: Cosmetics, coding-style, consistency fixes.
+
+commit 7dc55d930f87433fb35ebf6f18f767eddb7e8a17
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Sat Oct 20 20:39:37 2012 -0500
+
+    Add support for the TekPower TP4000ZC DMM.
+    
+    Also known as Digitek DT4000ZC.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 2bba3dd3a836f4a6d497709d321557a48e6425a3
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Oct 25 23:42:20 2012 +0200
+
+    HACKING: "Adding a new hardware driver" chapter.
+
+commit d36777dbf5f61027e404076f1564d769bfc5f3ad
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Wed Oct 24 16:48:41 2012 -0500
+
+    .gitignore: (Trivial) Ignore KDevelop project files
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 6f669a68e77a8a8fe4e62d66851cd894d72538dd
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Oct 24 02:51:17 2012 +0200
+
+    configure.ac: Small consistency fixes.
+
+commit 545f9786390a89b8bb6868907afa555fc0a6ece4
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Oct 24 00:41:21 2012 +0200
+
+    config.h usage cleanups.
+    
+     - Drop config.h #include from files that don't actually use any of
+       its contents (at the moment).
+    
+     - Add comment for those that do need it.
+
+commit afe2f28e65f3c3d9b510f101d6cd76c59794cd17
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Oct 22 02:32:53 2012 +0200
+
+    Doxygen: Explain init/shutdown, add small example.
+
+commit 1f345a21d24e52f482a06da9e434f751abdff203
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Oct 22 01:21:20 2012 +0200
+
+    Doxygen: libsigrok.h: Explain #include file usage.
+
+commit a02d77bce91771faf3581beed7af747d9f046c72
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Oct 22 01:13:36 2012 +0200
+
+    Doxygen: Various fixes in libsigrok.h.
+
+commit 393fb9cb18c5746d8567c9cf74b872804043345a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Oct 22 00:30:12 2012 +0200
+
+    Doxygen: Add @file items for the relevant files.
+    
+    These short descriptions are shown in the "Files" section of the
+    Doxygen output.
+
+commit 777e2035d8293b4636f6bf37afd92e18ced3720e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Oct 21 23:43:41 2012 +0200
+
+    Doxygen: Fix grouping of session_file.c functions.
+    
+    s/@ingroup/@addtogroup/ and s/grp_device/grp_session/.
+
+commit 6b2d8d3e5c4762cdafd847f9613d3f7b855927ab
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Oct 21 23:24:42 2012 +0200
+
+    Doxygen: TODO cleanup, use @todo where needed.
+    
+    Turn TODOs which should be user-visible into @todo so that Doxygen
+    shows them in the function docs, and also on the special "Todo List" page.
+    
+    Those TODOs that should not be in the Doxygen docs are moved out of the
+    /** */ comment blocks.
+    
+    Also fix some comments/items, and remove some obsolete ones.
+
+commit 3c0839d52475605d61ce385eda95f824fc448c88
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Oct 21 17:49:22 2012 +0200
+
+    Doxygen: Various improvements in libsigrok.h.
+    
+     - Turn SR_OK/SR_ERR_* and SR_LOG_* into proper enums.
+    
+     - Use /**< Foo. */ for Doxygen comments that are on the same line as
+       the (e.g.) enum entry they document. If the comment is not on the
+       same line (but rather directly above the enum entry) a simple
+       /** Foo. */ comment is sufficient.
+    
+     - Use /** */ instead of /* */ in some places, so that Doxygen actually uses
+       the respective comments.
+    
+     - Various smaller cosmetic fixes or cleanups.
+
+commit 9c5332d2915ba374775196b7e3624857d320b60a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Oct 21 16:52:56 2012 +0200
+
+    Doxygen: Fix a bunch of warnings and outdated docs.
+
+commit f21193fa03c7fe1ff6708e22d7aeb318b5539191
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Oct 21 16:36:23 2012 +0200
+
+    Doxygen: Move error handling stuff to error.c.
+    
+    Also, add an overview mini-section to the main page instead.
+
+commit 7b870c38e3040fec1165a623ae3986e4fb342218
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Oct 21 16:13:36 2012 +0200
+
+    Doxygen: Initial groups and topic short descriptions.
+
+commit b4bd70889f3009f5d836a9bf701725a6aceac039
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Oct 19 10:07:22 2012 +0200
+
+    Doxygen: Mark non-public stuff for exclusion.
+    
+     - /** @private */ can be used for functions, and /** @cond PRIVATE */ and
+       /** @endcond */ for variables or #defines.
+    
+     - Document the above in HACKING.
+
+commit 5b30cca719b737fed96c00e1b7a5094770d9d815
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Oct 19 10:06:45 2012 +0200
+
+    Doxygen: Add initial main page documentation section.
+
+commit d5f1d5382d2b2cb8999fefaf4e6e7af8067d110f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Oct 19 10:01:45 2012 +0200
+
+    Doxyfile: Various additions/improvements.
+    
+     - Show a short project description, the libsigrok version (x.y.z or
+       "unreleased development snapshot"), and the sigrok logo in the
+       Doxygen output.
+    
+     - Ignore a bunch of files and directories which don't contain public
+       libsigrok API anyway.
+    
+     - Remove the SR_API prefix from the Doxygen output (all
+       functions/symbols in the output are part of the public API anyway).
+    
+     - Various changes of settings to get nicer and more useful output.
+
+commit e61b4fa0d0f905ee6eb4aa7655ee8189b155dfbf
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Oct 19 00:30:31 2012 +0200
+
+    Doxygen: Add sigrok logo PNG for use by Doxygen.
+
+commit c63eac737c173cfb7d4ffd939a68f8ae8801b513
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Oct 18 22:51:16 2012 +0200
+
+    Doxyfile: Update to what doxygen 1.8.1.2 generates.
+    
+    The new version has a number of neat improvements/features we could use.
+
+commit 296821683df6ed064f036205c968e80549429456
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Oct 22 11:54:40 2012 +0200
+
+    Makefile.am: Add missing backslash.
+
+commit 8e2d43cc97438e092e1df3ad344c64032b56564e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Oct 22 10:17:38 2012 +0200
+
+    backend.c: Revert accidentally committed test code.
+
+commit 589a10135a5b811e16bdbc73b276d13884c27fa4
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Oct 21 01:34:34 2012 +0200
+
+    clean up autoconf/autobuild scripts
+
+commit d11d606626a2ce9359ed2b5395fe4b998604da92
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Oct 21 22:41:39 2012 +0200
+
+    We now require libusb >= 1.0.9.
+    
+    This is due to the use of libusb_error_name().
+
+commit c46762a285d7c844a771f5c1f0ad2447a00906b3
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Oct 21 22:40:43 2012 +0200
+
+    sr_init/sr_exit: Improve docs, add error checks.
+
+commit 785b9ff290cbdb86e7d0b0280c33b43faf9c0518
+Author: Peter Stuge <peter at stuge.se>
+Date:   Sun Oct 21 20:23:36 2012 +0200
+
+    Add and init libusb_context * in struct sr_context when using libusb-1.0
+    
+    This allows hardware drivers to use a common libusb_context.
+
+commit b8072700c1bc7d13ba004fd897668b56cec4ac62
+Author: Peter Stuge <peter at stuge.se>
+Date:   Sun Oct 21 20:23:14 2012 +0200
+
+    Add a struct sr_context * parameter to sr_init() and sr_exit()
+
+commit 026c822d8c6d39a2b0e976b02c16bb991431700b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Oct 19 10:35:11 2012 +0200
+
+    Move 'struct drv_context' to sigrok-internal.h.
+    
+    It's not meant to be visible to frontends.
+
+commit 7c41dc477402c09141c5d478dff493f8efb81264
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Fri Oct 19 20:40:50 2012 -0500
+
+    radioshack-dmm: Implement support for "LOGIC" mode
+    
+    LOGIC mode sends the following data:
+         V < 0 : actual voltage
+    0 <= V < 1 : LOW
+    1 <= V < 2 : actual voltage
+    2 <= V     : HIGH
+    
+    We follow the same idea, and set our unit to BOOLEAN for the crazy
+    case (HIGH or LOW).
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit dfd8f56ef4a0ee1c353db5078d6d7d8b901ec21b
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Fri Oct 19 20:31:19 2012 -0500
+
+    libsigrok: (Trivial) fix packet type in datafeed_dump
+    
+    datafeed_dump would print SR_DF_META_LOGIC when a SR_DF_META_ANALOG
+    was recieved. Fix that.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 0f7083019449c1d88a5916bae766f3e51f7f8373
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Fri Oct 19 17:50:20 2012 -0500
+
+    libsigrok: (Trivial) Add support for 2400 baud
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 777bbd5b98873ec20c58613e4dbb48a1836174bd
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Oct 18 22:43:03 2012 +0200
+
+    add SR_HWOPT_* documentation
+
+commit fe31f8b9f9b743bf47794842b70e56e3b2dda883
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Oct 16 23:32:39 2012 +0200
+
+    fluke-dmm: add support for Fluke 187
+
+commit 796a79eb75e35fe47becfbf62a840464efbbe96a
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Oct 16 23:31:18 2012 +0200
+
+    analog: add pretty-printer for dBu and dBV
+
+commit 6b8692346358362f4b7b004059c62c23f4889410
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Oct 16 23:28:04 2012 +0200
+
+    add SR_UNIT_DECIBEL_VOLT (dBu)
+
+commit d713e561814558d9f07c4186aef35a23df8b8445
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Oct 16 14:03:40 2012 +0200
+
+    analog: sane printing of very small and negative values
+
+commit 8ed262509f6f5e5a3b9a45ae6d116b1c36c750d7
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Oct 16 14:48:39 2012 +0200
+
+    HACKING: Cosmetics.
+
+commit 6aff0d16df34c60dada92486db0554ad32e08422
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Oct 16 12:08:01 2012 +0200
+
+    Build fix for Windows/MinGW.
+    
+    On Window/MinGW 'recv' seems to be already defined in some headers.
+    Use 'receive' instead, for now.
+
+commit a2353f6051004634f67505987749d56edbfdfb41
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Oct 16 11:24:03 2012 +0200
+
+    Re-add HACKING file after repo split.
+
+commit be8dbf3ab24348fe5cc619eca6a63464e72e6aa2
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Tue Oct 16 01:23:50 2012 -0500
+
+    radioshack-dmm: (Trivial) Convenience fixes
+    
+    While testing the new radioshack-dmm driver with pulseview, I found
+    a few inconvenients.
+    
+    1. Print an info message when a port is probed, and when a device is
+    found. This makes it easy to tell if and where the driver is looking.
+    
+    2. num_samples was not reset after the first aquisition, so the
+    second aquisition would quit right away. Reset num_samples at start
+    of a new aquisition.
+    
+    3. There's no need to  open the serial port RW, so change O_RDWR to
+    O_RDONLY when opening the port.
+    
+    These changes are too trivial to split into different patches.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 7b0a85c81c6bce43ced9bf59d99b3584fd1498d8
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Oct 15 18:25:48 2012 +0200
+
+    radioshack-dmm: build fixes
+
+commit d375b3c3ec01c246dbf6f0827c33aafc0953431b
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Mon Oct 15 01:17:32 2012 -0500
+
+    radioshack-dmm: Add support for Radioshack 22-812 DMM
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit b82a17d370a74dc7d4788f343f0ef050490e057f
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Mon Oct 15 01:14:04 2012 -0500
+
+    libsigrok.h: Add measured quantity and units used by Radioshack 22-812
+    
+    The Radioshack 22-812 can measure parameters such as transistor gain,
+    dbm, etc. Add those to libsigrok.h.
+    
+    The SR_UNIT_UNITLESS is for quantities that do not have units. Any
+    ratio or gain are just factors, whic do not have units. Specifically,
+    a transistor's gain, or hFE, is a unitless quantity.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit e8e9dcdd705c64a8ac1c04bc04d91e1a371e76c8
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Mon Oct 15 01:12:53 2012 -0500
+
+    serial: (Trivial) add support for 4800 baud
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 5fef6b9d6cd17f89a05f8e7a02a8c523e6a2632d
+Author: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+Date:   Mon Oct 15 01:11:39 2012 -0500
+
+    .qitignore: Ignore KDE backup files
+    
+    *.kate-swp files can become annoying, so ignore them.
+    
+    Signed-off-by: Alexandru Gagniuc <mr.nuke.me at gmail.com>
+
+commit 2b98e0aaab7e83c30fb1f690318584aa0f85b50a
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Oct 15 11:32:36 2012 +0200
+
+    analog: support AC+DC unit modifier
+
+commit 17ff11240ee1ed8afd504b84a99990969a75544b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Oct 8 23:56:06 2012 +0200
+
+    don't accept numbers as probe identifiers in trigger string
+    
+    Only the probe name, as supplied by the device driver, is accepted.
+
+commit 33df15f14440397bb8358fbf0939588c1b410e0c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Oct 11 23:46:30 2012 +0200
+
+    Quick workaround for g_match_info_unref().
+
+commit 4a1c927fd6c47831b984d9d7f4757408cf6fb800
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Oct 10 23:08:32 2012 +0200
+
+    README: Add status, update URL, small fixes.
+
+commit a5b2293fa84c076236fd3a6c7202ad4996ba16fd
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Oct 8 18:52:36 2012 +0200
+
+    updated URLs and description
+
+commit c750b9b1944723532b2924fd305573c26927d2fb
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Oct 8 15:53:00 2012 +0200
+
+    restore pre-split ignores
+
+commit a2e222d24fdca68fbf34031baa889ca3ebf23e1a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Sep 27 23:29:33 2012 +0200
+
+    sr: struct drv_context is global now.
+
+commit d38d2ef0ce0e4ec49369e6cbfac616d9b1065c38
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Sep 25 19:38:59 2012 +0200
+
+    fluke-dmm: support for all basic 287 functionality
+
+commit 96b3b3d56834f7c07a4760cfa3444b516c819de3
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Sep 25 19:34:53 2012 +0200
+
+    sr: add support for conductance measurements in Siemens
+
+commit aa839a5c4fb3d994c7254da403eef8beab2880ba
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Sep 25 18:33:42 2012 +0200
+
+    sr: add support for pulse width measurements
+
+commit f46a36ad801bc96754183e8aa1cc2a8c0583ae33
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Sep 23 00:03:24 2012 +0200
+
+    fluke-dmm: definitely use CR as line terminator
+
+commit acd29accb3a458ab6a494e3f6c42dacc56a4c7a8
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Sep 22 23:52:23 2012 +0200
+
+    fluke-dmm: add Fluke 287 to supported list
+
+commit fb9d3bf9cc0cafbd3caedcd54831219a533ef7fb
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Sep 22 23:50:51 2012 +0200
+
+    sr: always turn off ICRNL on serial ports
+    
+    It does rather screw with protocols that use CR.
+
+commit d3f8f1415c5c707edc1c78377f30875604e9b8c1
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Sep 17 16:31:15 2012 +0200
+
+    fluke-dmm: flesh out the driver API
+
+commit 4129832014ddb8330bd3f4a91e7c69ce6eb6b0cc
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Sep 17 15:40:41 2012 +0200
+
+    fluke-dmm: auto-discover serial bitrate if not provided
+
+commit bc41e012e6eda6277cbbeb5933c82c3d74a5ce69
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Sep 16 21:27:06 2012 +0200
+
+    fluke-dmm: don't log anything if no conn params given
+
+commit fb480d578e423cd0f5702d1251e3cdccb990c9fb
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Sep 16 21:07:17 2012 +0200
+
+    fluke-dmm: fix discovery
+
+commit 5c51e09868ea24c0eb77908aa3a9d585a46a3158
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Sep 16 14:07:21 2012 +0200
+
+    sr: turn off canonical mode and echo ion serial ports by default
+
+commit e7edd64f4573b786a8a1ab00e837d9e56cc69480
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Sep 15 18:28:43 2012 +0200
+
+    fluke-dmm: build fixes
+
+commit 4f958423d17c4c264ae02884888615df28c60f3d
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Sep 11 20:11:13 2012 +0200
+
+    fluke-dmm: basic scan functionality
+
+commit 883a2e9e71d4d0f84d9f8df6a6a5e754052bad8a
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Sep 10 22:31:29 2012 +0200
+
+    fluke-dmm: initial driver skeleton
+
+commit c2016fa0eb1d0eb1b9ebf8af4556f6d606614f61
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Sep 16 23:43:47 2012 +0200
+
+    agilent-dmm: don't log anything if no conn params given
+
+commit e9022f596d9a6d35919445f3aa6394061b3e6681
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Sep 11 21:27:26 2012 +0200
+
+    sr: make struct drv_context global
+
+commit f5cfe894eca22fc40dac721566a727cae8d8454c
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Sep 11 21:20:50 2012 +0200
+
+    fx2lafw: use default libusb context
+
+commit 19b0cce3125f08f961886fb312219c7c6f496ffc
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Sep 11 21:16:16 2012 +0200
+
+    hantek-dso: use default libusb context
+
+commit 7c1cb432b8afc14f63d984aaebd0239c74376c74
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Sep 10 22:14:37 2012 +0200
+
+    sr: enable genericdmm and agilent-dmm drivers by default
+
+commit b186aa78b8302942c8853c9aed40e3e5eaba8e34
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Sep 10 21:27:50 2012 +0200
+
+    agilent-dmm: fix model identifiers
+
+commit 8c0152f29b7892bb3f131e92c55ecd60a29ece5a
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Sep 10 01:00:48 2012 +0200
+
+    agilent-dmm: tentative support for all U123x and U125x models
+    
+    Only tested on U1233A, but it just might work.
+    
+    The U125x protocol decoding only supports voltage, current, resistance,
+    capacitance and diode measurements for now.
+
+commit a4394fb3d9362cc686d6f8a05d2bc0b219903069
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Sep 10 00:13:26 2012 +0200
+
+    agilent-dmm: code cleanup
+    
+    This should make it easier to support other Agilent U12xx models
+
+commit e066c32a252f4e5cd881a270adb98b004e688427
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Sep 9 22:49:07 2012 +0200
+
+    agilent-dmm: fix AC/DC mode detection
+
+commit f2e86bbfa64f328feb063ea2b79110a0ec1716e1
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Sep 9 22:48:22 2012 +0200
+
+    agilent-dmm: make parser deal with input better
+
+commit 81599cc55b8f22fe4ef78e7bd4bdb6958d458c64
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Sep 8 14:53:49 2012 +0200
+
+    agilent-dmm: remove IDN check at 1Hz, we just don't need it.
+    
+    Some debug message cleanup.
+
+commit 161a8a272699a7b818ddab01043838f07d7cf6eb
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Sep 8 13:24:48 2012 +0200
+
+    sr: add new analog output module
+    
+    This outputs text representation of SR_DF_ANALOG packets. Unlike the
+    float module however, it also outputs the standard abbreviations of
+    SI units corresponding to the packet's MQ and unit.
+    
+    It also makes an effort to multiply or divide the floating point value
+    as needed to the nearest multiple or fraction, and inserts the
+    appropriate SI prefix to match.
+
+commit e6b021f3775295bb3cbf7fa523281bfd64eaa39a
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Sep 8 03:06:45 2012 +0200
+
+    agilent-dmm: support for submodes
+
+commit f45b75901436310684b5fbb567269bc44d08c2d4
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Sep 8 02:31:08 2012 +0200
+
+    sr: add recv/cleanup calls to output module API
+    
+    The new output module callbacks will be init, recv and cleanup. The
+    existing data  and event callbacks still work, but will be phased out
+    as existing modules get converted.
+    
+    The recv() callback gets a copy of every packet on the session bus,
+    and thus has visibility of all metadata, allowing it to properly
+    output any acquired data.
+
+commit 69a74024902eecd3fc9ebd4f64fdef6ae460d0d7
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Sep 8 02:28:41 2012 +0200
+
+    genericdmm/victor-70c: fix resistance and frequency measurements
+
+commit 4cc9aea15b2d76930f565e810e0520918e2cc7bd
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sat Jul 7 09:32:00 2012 +0100
+
+    sr: Refactored sr_samplerate_string into a more general function: sr_si_string_u64
+
+commit b863fb1b9d486867ab1fc5e0f62fb42321080b5a
+Author: Lars-Peter Clausen <lars at metafoo.de>
+Date:   Sun Sep 2 19:02:42 2012 +0200
+
+    sr: session_driver: Remove source on completion
+    
+    Remove the session source once we are done loading the file, otherwise we'll
+    spin forever in sr_session_run.
+    
+    Reported-by: Joel Holdsworth <joel at airwebreathe.org.uk>
+    Signed-off-by: Lars-Peter Clausen <lars at metafoo.de>
+
+commit 40578aa487f6624db787289e4f254af14deee102
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Sep 2 15:41:19 2012 +0200
+
+    sr: output up to 12 significant digits for floats
+
+commit c0d93341cb6f409f53f5d9d47058e1efb1cd2d8b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Sep 2 15:39:56 2012 +0200
+
+    generic-dmm: cosmetics
+
+commit f6b8ffa6c0eb94fa59c0e09f3c4d8bed071167d0
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Sep 2 15:13:00 2012 +0200
+
+    genericdmm/victor-70c: warn if detaching kernel driver fails
+
+commit e93cdf428c6383b9868d08bdae07ff775bedd0c0
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Sep 2 15:11:52 2012 +0200
+
+    sr: mostly finished Agilent DMM driver
+
+commit 792fc686581a9412364d06be2e05dfe4d4014ed1
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Sep 2 15:02:24 2012 +0200
+
+    serial: add serial_set_paramstr()
+
+commit f38b9763fa5ba8f4b481718b245e1258a307d2a6
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Sep 2 15:01:23 2012 +0200
+
+    serial: fix flow control setting
+
+commit 6a6e23abf5e28471f368b225c96c1b0cb8797191
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Sep 2 15:00:02 2012 +0200
+
+    serial: set speed in both directions
+
+commit 6ac0db19f36ada4cfccf19bbd48ebdb4665bc9ff
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Sep 2 11:58:29 2012 +0200
+
+    sr: add new agilent-dmm driver (Agilent U12xxA multimeters)
+
+commit b84c13d700eff9eceb12463b0ed17f5b984b2582
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Aug 18 16:22:36 2012 +0200
+
+    genericdmm: Victor 70C multimeter support
+
+commit 3c6ce226dec2ee70c044d844ffbb3845f07baf7e
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Aug 18 16:21:21 2012 +0200
+
+    genericdmm: finish basic USB support
+
+commit 606a07b670270b4bcf0bfa4ffcf67dfd1cfedad3
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Aug 18 14:34:29 2012 +0200
+
+    sr: corrected VID for Victor 70C
+
+commit 02e864d0bf866b045abf04a696ad555959f1b171
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Aug 18 14:33:51 2012 +0200
+
+    sr: added mqflags field to sr_datafeed_analog
+
+commit edb000eb2f78aff4ea805ffc25a07792bedcea90
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Aug 18 14:26:43 2012 +0200
+
+    sr: add fahrenheit and boolean MQ units
+
+commit 64591be2f25055d4c9f55689f641334a54613746
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Aug 18 14:25:21 2012 +0200
+
+    sr: add continuity MQ
+
+commit 811deee4af9f600ae0c457a74d3877c4f68f2f37
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Aug 6 00:59:25 2012 +0200
+
+    sr/drivers: add API calls sr_dev_inst_list() and sr_dev_inst_clear()
+    
+    These are used to list the device instances currently known to the driver,
+    and clear that list.
+    
+    Drivers that don't necessarily clear their list of instances on every scan,
+    such as genericdmm, need to provide these to the frontend to keep instance
+    management sane.
+
+commit 014359e3293ef0cdc61fbde4f63dc0a9da98179d
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Aug 5 18:56:12 2012 +0200
+
+    sr/drivers: obsolete SR_HWCAP_PROBECONFIG
+    
+    Since probes now live in a struct sr_dev_inst owned by the driver, it
+    already knows about them. Instead of a frontend telling the driver to
+    configure probes, all driver now do this just before starting acquisition.
+
+commit a56f1480949e84e94dad2afcdf9f758988a4aff9
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Aug 5 15:53:04 2012 +0200
+
+    sr: new API call sr_dev_config_set()
+    
+    This is a wrapper around the driver dev_config_set() call, to avoid
+    frontends needing visibility into drivers.
+
+commit 15cb43d67cee5d7381c9cbcf0a355329a5cabfd1
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Aug 5 03:18:07 2012 +0200
+
+    sr: replace published static option data with API calls
+    
+    To find a driver or device option by name,  the sr_drvopt_name_get() and
+    sr_devopt_name_get() calls are now available. This was the only reason the
+    driver and device struct sr_hwcap_option arrays were published.
+
+commit 3cf91809a5aca7462f0fc9c3ca6fb9a7ebdf92d2
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Aug 4 14:35:40 2012 +0200
+
+    sr: rename sr_hw_hwcap_get() to sr_devopt_get()
+
+commit fabe59b326c8ed17582f54d5525b278b6712085b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Aug 4 12:21:02 2012 +0200
+
+    sr: drivers using sr_usb_dev_inst_new() must free it properly as well
+    
+    sr_usb_dev_inst_free() doesn't really do anything, but it might one
+    day.
+
+commit d3cff734e550430027f195317650a6c0e7c81fa3
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Aug 4 12:03:05 2012 +0200
+
+    sr: properly free probes when freeing their device instance
+
+commit 228b2cccaf2773efa81891273e2cf32ce6f14b2f
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Aug 3 14:19:00 2012 +0200
+
+    asix-sigma: fix double free
+
+commit 8012ae1e3b40a88bbe20deaded7d66942a82380e
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Aug 3 14:18:02 2012 +0200
+
+    chronovu-la8: fix double free
+
+commit afc88319384053b3f2ca4b17706c10ded9c7174b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Aug 3 13:50:31 2012 +0200
+
+    chronovu-la8: code cleanup
+
+commit 7021f98596fdd0ca744e9ffa2ab73979f65125a3
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Aug 3 10:17:31 2012 +0200
+
+    chronovu-la8: remove session source when done
+
+commit 503c4afbb43da85723d1a40bf985b88f7a4bc3c7
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Aug 3 10:12:54 2012 +0200
+
+    asix-sigma: remove session source when done
+
+commit 7fd3e8596192316cacd0d22d52f287df2c12d437
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Aug 3 10:09:02 2012 +0200
+
+    demo: remove sources from session when done
+
+commit a3508e33f9e4e54331d086b37272e7c55faf11d8
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Aug 3 01:05:40 2012 +0200
+
+    hantek-dso: remove sources from session when done
+
+commit 26bf9d56c079889cd493376b341ab75acee795f7
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Aug 3 01:05:01 2012 +0200
+
+    ols: remove serial source from session when done
+
+commit 2cbeb2b7fb5791dd765ab6eee180ee053cc20b1c
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Aug 3 01:04:05 2012 +0200
+
+    sr: drivers should remove their sources from the session when done
+
+commit 310e9e9be4e4421f0171d47dfdb5fc299d6f749c
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Aug 3 01:01:38 2012 +0200
+
+    zeroplus: use driver-private storage for instances
+
+commit fefc4b858e8db2b1c569dd302af1b30c1a4bce4f
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Aug 3 00:09:33 2012 +0200
+
+    ols: use driver-private storage for instances
+
+commit 301a5e4c4ade2f640eeb532195e6e84dee81783c
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Aug 2 23:54:11 2012 +0200
+
+    genericdmm: use driver-private storage for instances
+
+commit b4750a3a938ff5be295095b05e27c0f7a7cd2bbe
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Aug 2 23:53:31 2012 +0200
+
+    demo: use driver-private storage for instances
+
+commit b9636cf4dcd07fa215bcfdb265913baa848227ab
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Aug 2 23:51:47 2012 +0200
+
+    fx2lafw: minor cleanup
+
+commit cf1ebd544652274923e808c93f7e88292acc2f11
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Aug 2 21:54:21 2012 +0200
+
+    chronovu-la8: don't try to clean up unless we've initialized
+
+commit b32503cccdf88769619dc9a2ca3566d06040c1b4
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Aug 2 21:42:37 2012 +0200
+
+    asix-sigma: properly init driver-private storage
+
+commit 1644fb2473e0c2f0dd81464f885c9212f413657e
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Aug 2 21:35:25 2012 +0200
+
+    chronovu-la8: use driver-private storage for instances
+
+commit 0e1357e8960734e4b599979511c7f9a51fb611a8
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Aug 2 21:20:41 2012 +0200
+
+    asix-sigma: use driver-private storage for instances
+
+commit dc9dbe949a2c195ec0c5afff34bec3cc03a5613b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Aug 1 00:42:19 2012 +0200
+
+    fx2lafw: use driver-private storage for instances and libusb_context
+
+commit 269971ddce18664a2ad06b7e2f56dcad70d155bb
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jul 30 00:24:26 2012 +0200
+
+    hantek-dso: use driver-private storage for instances and libusb_context
+
+commit c259726a161411a7fe955dd139fce374635ddf7c
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jul 30 00:22:26 2012 +0200
+
+    sr: driver struct gets a more generic *priv instead of GSList *instances
+    
+    It's up to the driver to keep its GSList of struct sr_dev_inst * in there.
+    Anything else the driver wants to keep driver-global should also go in
+    there, such as libusb_context.
+
+commit ef2345bc29fc8b3bc31e5d89e028be31c7b39428
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 29 15:21:08 2012 +0200
+
+    sr: build: hantek-dso driver requires libusb as well
+
+commit e8d3d6c84378481b5c0b53236e2fb09288e211b1
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 29 03:01:57 2012 +0200
+
+    sr: properly initialize and check on device instance driver field
+
+commit aee878fa2efb8483bf93fa3bb03508357fc713a8
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 29 03:01:02 2012 +0200
+
+    sr: fix initialization for output from driverless devices
+
+commit 6f57fd96949e4290933ac175c6c82d56965f7665
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Jul 25 00:33:38 2012 +0200
+
+    sr: remove obsolete SR_DI_INST
+
+commit 48a486cd3ed51cfefce271224541502f4388c225
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Jul 25 00:20:06 2012 +0200
+
+    sr: code organization cleanup
+    
+    Device-specific functions (public and private) go in device.c,
+    more general driver-related code in hwdriver.c
+
+commit 87ca93c5043899e3c30edb7e09fadef3ee67d810
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jul 24 19:10:09 2012 +0200
+
+    sr/drivers: add proper probe list to instances of all drivers
+
+commit b35c829306b86dbeeeecf14de7fe30a05a88c914
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jul 24 17:13:25 2012 +0200
+
+    sr/drivers: fix off-by-one if frontend-initiated probe configuration
+
+commit d6a8df467de03fe211dea7a0c91f63ceb22c5480
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jul 24 15:42:51 2012 +0200
+
+    sr: remove obsolete sr_dev_inst_get() call
+
+commit 47a98b6e2c241f225f78044f0237dc77d235ce6b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jul 24 13:06:15 2012 +0200
+
+    sr: remove obsolete driver API call dev_info_get()
+
+commit a2e464604ca19c1a41b8e94625971eb3818c9090
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jul 23 15:09:19 2012 +0200
+
+    sr: cosmetic changes
+
+commit c1864d5589749a881d661ab3abfd09cdbb96253d
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jul 23 15:08:44 2012 +0200
+
+    sr: better file version check
+    
+    Still not really used though.
+
+commit 056be0719f0c1a05cde6fc2483b50e024708fdac
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jul 23 15:06:49 2012 +0200
+
+    sr: sr_session_save() now takes sdi and datastore parameters
+    
+    This means it's restricted to saving one device's capture per file, for
+    now.
+
+commit fb381e4d713fcd3fdec99b4deff3a75e809df825
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jul 23 14:55:43 2012 +0200
+
+    sr: fix session loading for 0-numbered probes
+    
+    They're still numbered starting from 1 in the current version (1)
+    of the sigrok file format, we just work around that for now.
+
+commit 31fc1fbce399ac89d07093886301b9b4971f56f9
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jul 23 02:58:56 2012 +0200
+
+    sr: fix sr_parse_triggerstring() to use probe numbers starting from 0
+
+commit 1907d2c928e328209f6d8832f73e369d28db5ab1
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jul 23 02:57:17 2012 +0200
+
+    sr: fix sr_filter_probes() to use probe numbers starting from 0
+    
+    The probelist parameter is now terminated with -1, since 0 is a valid
+    probe number.
+
+commit a5f2e70712827c48a095204ef48c7cf1a0193ed0
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 22 20:06:13 2012 +0200
+
+    sr: comments/docs
+
+commit 37e8b4c4f7eaa6132a25448bccc690ac764f9a63
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 22 20:05:36 2012 +0200
+
+    sr: change sr_dev_probe_name_set() to use sdi
+
+commit a10ddf9ba04429d6762171a3bbbac12a7717ef59
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 22 19:44:20 2012 +0200
+
+    sr: remove dead/obsolete code
+
+commit 2ac2e629fc2ba2e89351d3ce337e0de9e034c540
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 22 15:32:35 2012 +0200
+
+    sr: cosmetic changes
+
+commit de4d3f99d9e76c5a51916d3bcfef89423055d43f
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 22 15:31:56 2012 +0200
+
+    sr: change session API/code to use sdi
+
+commit c06b0d13b5b6bc7b059f397111f4ff661d1bbcbc
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 22 15:19:53 2012 +0200
+
+    sr: remove obsolete dev_status_get() API call from session driver
+
+commit c7ee3ddb948b2ff36acbbe79ecc812b477ff5708
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 22 15:15:26 2012 +0200
+
+    sr: cosmetic changes
+
+commit ff14f01b208faf9b26212c907d162de72d1ab538
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 22 15:05:47 2012 +0200
+
+    sr: change sr_datafeed_callback_t to use sdi
+
+commit a5b35a167a32ffbaee1ce9c0de8501f781f733d1
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 22 14:33:28 2012 +0200
+
+    sr: convert sr_dev_has_hwcap() to use sdi
+
+commit 92ae7984834778dc7da128159d8e90024318909d
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 22 14:28:40 2012 +0200
+
+    sr: convert sr_parse_triggerstring() to use sdi
+
+commit 9e90dcba9ce9d8f4a56b0225f146a1f1f055d213
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 22 12:37:59 2012 +0200
+
+    sr/drivers: remove driver API call dev_status_get()
+    
+    It's obsolete: no frontend ever used it, and neither did libsigrok.
+    The sdi->status field is only used internally by some drivers, and
+    should probably be moved to the driver-specific context structs.
+
+commit 5d9ed643e9dddbdb43e8917cff197346bdc930e7
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 22 12:35:57 2012 +0200
+
+    ols: change driver dev_acquisition_start/_stop calls to use sdi
+    
+    ...yeah, forgot OLS.
+
+commit be5bf44d281cc0a85992666803afdd7dafcefaf9
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 22 12:23:59 2012 +0200
+
+    sr: add sr_dev_probe_enable(), abstraction wrapper around device probes
+
+commit 4d684427397079d4627cce3fd624cd7c05b2d4b1
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 22 12:18:34 2012 +0200
+
+    sr: convert session load/save code to use sr_dev_inst
+
+commit c4a1de59f80efead2ebdd8109110ff8632c1838e
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 22 11:49:00 2012 +0200
+
+    genericdmm: cosmetic change
+
+commit 3f848bb7a9c248447ddd3af6964089cd713b9c5a
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 22 02:09:58 2012 +0200
+
+    zeroplus: comment out 32-probe models for now
+
+commit 428edbe13de32b4349af56c9fb3569d63a54e4c8
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 22 02:08:59 2012 +0200
+
+    zeroplus-logic-cube: fix scan to correctly find model
+
+commit 3ffb6964a1585b5f6ffa0747c089a1cd557e4feb
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Jul 21 22:41:58 2012 +0200
+
+    sr/drivers: change driver dev_acquisition_start/_stop calls to use sdi
+
+commit 25a0f108f4512ade836fed128c3ad649dedcb788
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Jul 21 22:04:47 2012 +0200
+
+    sr/drivers: change driver dev_open/dev_close calls to use sdi
+
+commit 58453e5876ffae9153e9f4ddc2ad8dc244c7f26d
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Jul 21 19:11:49 2012 +0200
+
+    sr: change sr_dev_trigger_set() to use sdi
+
+commit 5c3c1241d2e2b5d456865e876490492d76174257
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jul 20 21:37:36 2012 +0200
+
+    sr: change input/output modules to use struct sr_dev_inst *
+
+commit 6f4b1868e8ec8c132878d8b6d558f4af054cbd91
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jul 16 03:52:14 2012 +0200
+
+    sr/drivers: use sr_dev_inst instead of device index for dev_config_set()
+    
+    All driver API calls using device index as a parameter will instead use a
+    const struct sr_dev_inst.
+
+commit 9c4311c524cd2eea8ce2c80b1029c936769107db
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 15 19:24:10 2012 +0200
+
+    chronovu-la8: adjust to multi-vid/pid patch
+
+commit 387014de6355545d95958ec2666836318c2b3902
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 15 04:33:38 2012 +0200
+
+    sr: use new info_get API call in session driver
+
+commit 444adea232d24951b056fd4d7e061608dfabef7f
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 15 04:33:10 2012 +0200
+
+    zeroplus-logic-cube: don't use deprecated hwcap_get_all() driver API call
+
+commit 2ca4465b3d66d3b763e664c419b542a3d1c1baad
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 15 04:32:53 2012 +0200
+
+    ols: don't use deprecated hwcap_get_all() driver API call
+
+commit 2ce9f04629e93c4d202608dec6fa72d52aa44c6c
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 15 04:32:37 2012 +0200
+
+    hantek-dso: don't use deprecated hwcap_get_all() driver API call
+
+commit cbd798f4002c1abccaa20ebe874c0aa45060bb0e
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 15 04:32:21 2012 +0200
+
+    fx2lafw: don't use deprecated hwcap_get_all() driver API call
+
+commit 46c7a4daa772df5853e62f384b123bf1f3d96753
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 15 04:31:58 2012 +0200
+
+    demo: don't use deprecated hwcap_get_all() driver API call
+
+commit 7566601c21fd748827065ca120b88a6a141c922e
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 15 04:31:37 2012 +0200
+
+    chronovu-la8: don't use deprecated hwcap_get_all() driver API call
+
+commit b2b5445c304ee2a6fe352e9b33f1e695a6760da5
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 15 04:31:22 2012 +0200
+
+    asix-sigma: don't use deprecated hwcap_get_all() driver API call
+
+commit 2efc5948b6c2c436e339e333994ec7cc96db62be
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 15 04:08:49 2012 +0200
+
+    ols: scan fix
+
+commit b0c8d7ac7f698f75aeb1c4b201c90360bae009e8
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 15 04:08:21 2012 +0200
+
+    hantek-dso: scan/info_get fixes
+
+commit 7dfcf010a0331359529f52f7a09d6d324d96284f
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 15 04:07:51 2012 +0200
+
+    demo: scan/info_get fixes
+
+commit cfe8a84dd7b5a22e6a225d6b078bde6d0ad8fde4
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 15 04:07:34 2012 +0200
+
+    chronovu-la8: scan/info_get fixes
+
+commit d7bbecfdb9bcec55a0eb067853df85d8fd326f84
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 15 04:06:57 2012 +0200
+
+    asix-sigma: scan/info_get fixes
+
+commit 626409abfb93a09ba74a0714de75fcde9381bea9
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 15 03:53:09 2012 +0200
+
+    zeroplus-logic-cube: use new driver info_get() API call
+
+commit dddfb3dbf058a5a8f789cc4988ac3c6da836e267
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 15 03:52:57 2012 +0200
+
+    ols: use new driver info_get() API call
+
+commit 0b79bcbb9d2e52fdd722088e0c525d14579cec6b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 15 03:52:45 2012 +0200
+
+    hantek-dso: use new driver info_get() API call
+
+commit dfb0fa1a669fb2a78fdee88d9896efc1998d7cee
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 15 03:52:37 2012 +0200
+
+    demo: use new driver info_get() API call
+
+commit 6a2761fd9921830f3724f3d153eee4ad98dbc6b1
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 15 03:52:22 2012 +0200
+
+    chronovu-la8: use new driver info_get() API call
+
+commit 4147960558ae0d8964e8344faa3515a8ec4d9efb
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 15 03:52:04 2012 +0200
+
+    asix-sigma: use new driver info_get() API call
+
+commit eec944c5b8e4885e61faf3ab318be6007f221fd9
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Jul 14 16:14:01 2012 +0200
+
+    asix-sigma: don't attempt to free static struct
+    
+    Added more debugging as well.
+
+commit 067d07166b8637a4146058b4fb4da2d628b34c37
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Jul 14 15:49:30 2012 +0200
+
+    demo: use new scan API
+
+commit 7da6f9d54a6acb699116848141d6ae1650a8dc98
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Jul 14 13:00:47 2012 +0200
+
+    zeroplus-logic-cube: init and scan fixes
+    
+    libusb context needs to be initialized only once, not ever scan.
+    Every scan invalidates the last one, so clean up any previous run's
+    results first.
+
+commit 4ca38984459adfeaf6a94c2163be855fe41aec59
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Jul 14 12:45:07 2012 +0200
+
+    zeroplus-logic-cube: use new scan API
+
+commit 39cfdd75f9f2ee050968cbe0efdf208fa8d8d9e0
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Jul 14 12:28:45 2012 +0200
+
+    hantek-dso: use new scan API
+
+commit 0448d11097b057606f7f643b0f0537706d95afa7
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Jul 14 12:28:15 2012 +0200
+
+    asix-sigma: use new scan API + fixes
+    
+    Now freeing FTDI context and driver-private context.
+
+commit c4f3ed4bb075eb3b2015b0cacbf4a8cf4e29d7a4
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Jul 14 12:27:02 2012 +0200
+
+    chronovu-la8: use new scan API + fixes
+    
+    Now freeing FTDI context and driver-private context.
+
+commit f8c617cf4c6b649d3456f1ca7082f6cfb6dac76d
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jul 13 22:18:01 2012 +0200
+
+    hantek-dso: instance list fix
+
+commit 10e5cbede89976eeed3237d985da065238962dfe
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jul 13 22:16:37 2012 +0200
+
+    ols: use new scan API
+
+commit ed300b9f6a1d87eb35465ac998e1fc20690852a7
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jul 13 14:18:27 2012 +0200
+
+    asix-sigma: use driver struct-based device instance list
+
+commit 765ef2f725a11aa9598bfc621136f93666a1bc86
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jul 13 14:15:54 2012 +0200
+
+    chronovu-la8: use driver struct-based device instance list
+
+commit dcf03d6dbdba67eb92ee887de1bc72816a3cd01b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jul 13 13:47:27 2012 +0200
+
+    demo: use driver struct-based device instance list
+
+commit 327565470858432ba926643b0a4c4bb6f33e53e0
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jul 13 13:43:41 2012 +0200
+
+    zeroplus-logic-cube: use driver struct-based device instance list
+
+commit 982947f7a221c4dbd2ea2fe9ecb4405ea8c2156a
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jul 13 13:37:35 2012 +0200
+
+    hantek-dso: use driver struct-based device instance list
+
+commit e5e81856b4821932481ff4f349b7557e84038a04
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jul 13 13:26:30 2012 +0200
+
+    ols: use driver struct-based device instance list
+
+commit d6db79a48cf813af1afa8e6243863cd62d1110d8
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jul 13 02:37:17 2012 +0200
+
+    genericdmm: device scan fixes
+
+commit f1a14ea7ab390e3d873631eaf0f0f915031b8e6f
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jul 13 02:34:58 2012 +0200
+
+    genericdmm: don't use deprecated hwcap_get_all() driver API call
+
+commit 6910bf6bf61320f4ab55c670187d404656183a1b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jul 13 02:34:10 2012 +0200
+
+    genericdmm: use new driver info_get() API call
+
+commit a27999e65768dcf38366e1844b97b3b8ea243dd2
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jul 13 02:31:16 2012 +0200
+
+    fx2lafw: don't use deprecated hwcap_get_all() driver API call
+
+commit c5e82ca5e3ba7cd154c0e8afc19859564fc36dab
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jul 13 02:30:42 2012 +0200
+
+    fx2lafw: device scan fixes
+
+commit f69b47f0f88aba6738635ae0ab3c37ccc235a0f9
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jul 13 02:30:09 2012 +0200
+
+    fx2lafw: a device scan always invalidates any previous scans
+
+commit 6e9339aae20afeef872eeb806c4bcc043e210dd0
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jul 13 02:28:07 2012 +0200
+
+    fx2lafw: use new driver info_get() API call
+
+commit be34a1c74688351fdeb7482fda28f49aa762a831
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jul 13 02:08:27 2012 +0200
+
+    sr: deprecate driver API call hwcap_get_all()
+    
+    This is now handled with a call to info_get(SR_DI_HWCAPS). This brings
+    it in line with the new driver opts: info_get(SR_DI_HWOPTS).
+
+commit df12380181f0af94fca382cd2ae6425bb1b51f73
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Jul 12 22:41:57 2012 +0200
+
+    sr: new sr_info_get() API call, wrapper for driver info_get()
+    
+    This will replace sr_dev_info_get(), the wrapper for driver dev_info_get()
+
+commit f92f4eab23165aefa271d87cc0e60cbb8e24d154
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Jul 12 21:34:30 2012 +0200
+
+    sr: add new driver API call info_get()
+    
+    This will replace dev_info_get(), and will be used to fetch both
+    driver and device instance-specific information. The sr_dev_inst
+    argument is NULL in case of a driver info fetch. In line with the
+    libsigrok wrapper, this function returns an error code, using the
+    supplied void ** to return the requested data.
+
+commit 9e41fdba4080de96fde23f00415056f51d79b469
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Jul 12 21:00:18 2012 +0200
+
+    sr: add driver field to sr_dev_inst, to bring it on a par with sr_dev.
+
+commit 8bfdc8c4a5fc4bee4b59838bd57c6762ea0cb206
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Jul 12 20:54:45 2012 +0200
+
+    sr: split driver options into separate list
+
+commit 3a0fe4023d1dd02051c126fffead6de631840974
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 8 23:49:04 2012 +0200
+
+    genericdmm: use new scan API
+
+commit bbb40871c88bbb622a275785d4aaf1e5e5a927f9
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 8 23:48:04 2012 +0200
+
+    genericdmm: more flexible device discovery
+
+commit 75337758d8e88e01d9ac46669cd8a76d0b8b0ca5
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 8 23:33:48 2012 +0200
+
+    genericdmm: use driver struct-based device instance list
+
+commit a8cc8e44b942031746c18aa95bf02cc66043269c
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 8 19:07:38 2012 +0200
+
+    fx2lafw: use driver struct-based device instance list
+
+commit 06717a8a605d03eb87e768119758ba8e9e47cb0b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 8 19:06:23 2012 +0200
+
+    fx2lafw: use new instance-based probe list
+
+commit 3a7a22cb07937fcecef8b17b25e9638245f7f8c1
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 8 19:03:36 2012 +0200
+
+    fx2lafw: use new init/scan API
+
+commit dd34b8d3c4da18f8cf339c5bb8f0d6268f3d13f6
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 8 16:40:54 2012 +0200
+
+    sr: add GSList of instances to the driver struct
+    
+    This gives the driver a private place to keep its instances, without
+    polluting the global namespace.
+
+commit 47211d65b4fdaca58694a51cdbf1ba8ee4270ee9
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 8 16:37:39 2012 +0200
+
+    sr: add probe list to device instance
+    
+    There is no point in libsigrok copying probe lists around. The driver now
+    builds a list of probes according to the model device it found, and will
+    make that available to a frontend. The frontend thus has a reference of
+    what the driver has, including default names, and doesn't need libsigrok
+    to provide an unnecessary level of abstraction.
+    
+    The sr_probe_new() library-private function is a helper for drivers.
+
+commit 80bf04263528998feb17cedc5b7aa9668dbc8d4d
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 8 16:25:23 2012 +0200
+
+    sr: split driver init into init() and scan()
+    
+    init() now only does whatever administrative stuff it needs (typically not
+    much), and returns an error code.
+    
+    scan() can be called multiple times during the life of an application, and
+    returns a GSList of struct sr_dev_inst * of devices found during that scan.
+    The instances are a copy of the ones stored in the driver's own instance
+    list, to be freed by the caller with g_slist_free() only.
+    
+    The scan() call can be passed a GSList of struct sr_hwopt *, to direct the
+    scanning.
+
+commit b159add3d9e3804f7806e82b01374fa099610668
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 8 14:56:54 2012 +0200
+
+    sr: move SR_HWOPT into its own enum, and create struct sr_hwopt
+    
+    SR_HWOPT_* entries are driver options, not device instance parameters, so
+    they will never be mixed together.
+    
+    Also, driver options are always passed in a GSList, where the data field
+    is a struct sr_hwopt.
+
+commit 633b2fac75c59c550cb1245cb75caa3ceef57b3d
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 8 04:17:56 2012 +0200
+
+    genericdmm: better subdriver API arguments
+
+commit 1ef445b3d696c91b6734eaafbfb5478d6506d5ee
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 8 04:15:51 2012 +0200
+
+    genericdmm/fs9922: no initialization needed
+
+commit 7fc754a0db73b473fb5c70f59165b43dc682bf1a
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 8 04:09:55 2012 +0200
+
+    genericdmm: allow for default options in DMM profiles
+    
+    Much better than the special-cased USB vid.pid
+
+commit 7356a55db8e1f0aa27abb8f3cd05bca848c4c2a0
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 8 04:01:04 2012 +0200
+
+    genericdmm: use vid.pid as USB conn spec
+    
+    : is just too hard for the CLI
+
+commit db1352007db0d7a263a6a4c2837e65fd6de4dc8f
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 8 03:59:58 2012 +0200
+
+    genericdmm: fix header guard
+
+commit 61136ea6035778f2894a1e32b78f94a0640a5a91
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Jul 5 11:27:48 2012 +0200
+
+    sr: add new driver API call: scan()
+    
+    This changes the semantics of the init() call as well. That now only
+    initializes the driver -- an administrative affair, no hardware gets
+    touched during this call. It returns a standard SR_OK or SR_ERR* code.
+    
+    The scan() call does a discovery run for devices it knows, and returns
+    the number found. It can be called at any time.
+
+commit 40dda2c3a509e9e031078427e32249e2ebc33ec5
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jul 3 12:55:46 2012 +0200
+
+    sr: remove unused argument from hardware driver function init()
+    
+    It was actually used in one way: the session file loaded abused it for
+    passing in the filename -- something it definitely wasn't intended for.
+    This now uses the proper way to pass arguments to a driver: the new
+    SR_HWCAP_SESSIONFILE.
+    
+    The OLS driver could also use it as an indication of the serial port to
+    use instead of actively probing all serial ports on the system, but there
+    wasn't any frontend code that passed in such a parameter, making it
+    entirely useless. That will soon be handled differently with the new
+    scan() API call, regardless.
+
+commit 0d012ede9d54c6c5c276be52778483fd020c40d7
+Author: Ivan Fedorov <oxyum at oxyum.ru>
+Date:   Fri Aug 3 01:31:36 2012 +0400
+
+    sr: fix gnuplot script for USBee DX and clones
+    
+     - Now channels order is right
+     - Added 16bit version
+
+commit 0e8d0e24d00dcf6dd661e4fb15cedf79ce45c248
+Author: Ivan Fedorov <oxyum at oxyum.ru>
+Date:   Thu Aug 2 23:49:00 2012 +0400
+
+    sr: fx2lafw: Add 16bit support for USBee DX and clones
+    
+    gnuplot script support only 8 channels
+
+commit c19298d1413e2783bf723f5eb4ee098d9b8f159b
+Author: Ivan Fedorov <oxyum at oxyum.ru>
+Date:   Wed Aug 1 00:11:40 2012 +0400
+
+    sr: add gnuplot script for USBee DX and clones
+
+commit c9166745f23889e1c5abb010513733c829c00d1b
+Author: Ivan Fedorov <oxyum at oxyum.ru>
+Date:   Wed Aug 1 00:11:33 2012 +0400
+
+    sr: fx2lafw: Add basic support for USBee DX and clones
+
+commit 0d1297a2916c18457735a51fdab9ee2c914a4599
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 29 02:45:40 2012 +0200
+
+    sr: always use uint64_t for samplerate
+
+commit b04781bb2ba910d17b0bc11b499b1be352faa9cc
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 29 02:15:34 2012 +0200
+
+    sr: extra checks for properly handling driverless devices
+
+commit 3dafb92bde1533cc81a61e2dc0f7d3732873c7ed
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 29 02:13:22 2012 +0200
+
+    sr: fix struct sr_input for parameter passing
+
+commit c506a6a688877793752d23e43d692c49d0f52dd2
+Author: Tomaž Šolc <tomaz.solc at tablix.org>
+Date:   Wed Jul 4 16:29:13 2012 +0200
+
+    Allow setting samplerate when reading binary files
+    
+    I had a binary file that I needed to decode using UART decoder. UART
+    decoder needs to know the sample rate for the data, but currently it's
+    not possible to pass parameters to input formats and so the "binary"
+    file format always sets the samplerate to 0.
+    
+    This patch adds the possibility to append a colon-separated list of
+    key=value options to the -I argument, in the same way -d supports it.
+    Also, it makes the "binary" format support the "samplerate" option.
+    
+    I included the GHashTable containing input format options directly in
+    the sr_input struct. I'm not sure if that's the right way to do it. I
+    saw that -d uses a much more elaborate system with device capabilities
+    and typed options, but that seemed like an overkill for input formats.
+
+commit d67b663e21de64261847c7e68de3ba37883c48b7
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jul 24 00:50:02 2012 +0200
+
+    sr: chronovu-la8: fix segfault on discovery
+    
+    If the uninitialized value didn't happen to contain 0, and there
+    is no Chronovu LA8 connected, the la8_close() causes a segfault
+    in libftdi.
+
+commit 74e5f12d3d9643cb0e8ba57ced4ee80b6393cb11
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Jul 15 00:34:27 2012 +0200
+
+    sr: la8: Support for newer USB VID/PID of the device.
+    
+    Thanks to Jerry Jacobs for the patch!
+
+commit 43be303c84d328437e594111b94f278270817a86
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Jul 12 21:39:18 2012 +0200
+
+    sr: la8: Drop useless cast.
+
+commit b5a8e848256f54b32ca988be5a1ec2db5048873a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Jul 12 21:30:49 2012 +0200
+
+    sr: Add sr_strerror() and sr_strerror_name().
+
+commit 9ffbde0e84ef6c711be4edbe3076e8c805efad63
+Author: Lars-Peter Clausen <lars at metafoo.de>
+Date:   Thu Jul 5 21:15:09 2012 +0200
+
+    sr: session: Deprecate sr_session_halt()
+    
+    sr_session_halt() in its current state is kind of useless and even dangerous.
+    All it will do is mark the session as not running, but wont signal the devices
+    to stop to capture data. This is not so much of a problem with the blocking
+    sr_session_run(), but once there is support for asynchronous data acquisition by
+    attaching the session sources to the applications mainloop sr_session_halt()
+    basically becomes a no-op. sr_session_stop() already does what needs to be done,
+    marking the session as not running and signal the devices to stop acquisition,
+    so make sr_session_halt() an alias for sr_session_stop() and deprecate its
+    usage.
+    
+    Signed-off-by: Lars-Peter Clausen <lars at metafoo.de>
+
+commit 9213ad012accac3dbfbc6b72d6e99228e87740a4
+Author: Lars-Peter Clausen <lars at metafoo.de>
+Date:   Thu Jul 5 21:15:08 2012 +0200
+
+    sr: session: Do not cleanup the driver state in sr_session_stop()
+    
+    By cleaning up the driver state all devices will become inaccessible, which
+    means that is neither possible to query any information from it (like sample
+    rate) and it is also not possible to restart data acquisition.
+    
+    sr_session_save() tries to query the sample rate from the device, as a result
+    calling sr_session_save() after calling sr_session_stop() - which is for example
+    done by sigrok-cli - will cause a segfault. This patch resolves the issue.
+    
+    Signed-off-by: Lars-Peter Clausen <lars at metafoo.de>
+
+commit ed229aaa8ff66116967f75112be953940d4a3149
+Author: Lars-Peter Clausen <lars at metafoo.de>
+Date:   Thu Jul 5 21:15:07 2012 +0200
+
+    sr: session: Close a device when it is removed from a session
+    
+    A device is opened when it is added to a session, in the same fashion it should
+    be closed again when it is removed from a session.
+    
+    Also remove all still attached devices from a session when the session is
+    destroyed.
+    
+    Signed-off-by: Lars-Peter Clausen <lars at metafoo.de>
+
+commit 615183ea163f805af8589576c173769b4adba7f1
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Jul 11 12:57:15 2012 +0200
+
+    sr: Drop mastech-va18b, code will be in genericdmm.
+
+commit 28b9dd18611da8e16038d62d58195bdef91552eb
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Jul 11 12:36:13 2012 +0200
+
+    sr: fix conditional build for ezusb and serial helpers
+
+commit b7e941113f2e4d534e109f4aeb8b0dc4cda36598
+Author: Lars-Peter Clausen <lars at metafoo.de>
+Date:   Fri Jul 6 23:23:31 2012 +0200
+
+    sr: session: Moves sources to session struct
+    
+    The sources really belong to the session, so move them into the session struct.
+    
+    Signed-off-by: Lars-Peter Clausen <lars at metafoo.de>
+
+commit e6e8f8e0531805a9215eebcb0d4d270a5afa6a8d
+Author: Lars-Peter Clausen <lars at metafoo.de>
+Date:   Fri Jul 6 23:23:30 2012 +0200
+
+    sr: demodevice: Make read channel non-blocking
+    
+    Both pipe channels are currently configured as blocking. We read from the pipe
+    in receive_data. Since the channel is configured as blocking we'll block in
+    receive_data until all data has been received. receive_data will be called from
+    the mainloop, so as consequence the mainloop will be blocked until the demo
+    device has finished sampling. This is not so much of a problem if we are
+    sampling in blocking mode (using sr_session_run()) and the demo device is the
+    only device in the session, but it will fail badly for all other configurations
+    (e.g. multiple devices or async sampling).
+    
+    Signed-off-by: Lars-Peter Clausen <lars at metafoo.de>
+
+commit 93b03d091abb947fdf78e57f864313571fb903ab
+Author: Lars-Peter Clausen <lars at metafoo.de>
+Date:   Fri Jul 6 23:23:29 2012 +0200
+
+    sr: session: Realloc correct array for pollfds in _sr_session_source_remove
+    
+    Commit 7149ad7c ("sr: session: Keep a global pollfd array") contained a small
+    copy paste error. This patch fixes it.
+    
+    Signed-off-by: Lars-Peter Clausen <lars at metafoo.de>
+
+commit e7d087bf0e35ff97abae8bdd0c50e400c87b4b4d
+Author: Lars-Peter Clausen <lars at metafoo.de>
+Date:   Thu Jul 5 21:38:36 2012 +0200
+
+    sr: fx2lafw: Free transfers in reverse order
+    
+    Free the USB transfers in the reverse order of which they were submitted. This
+    will avoid that while transfer 0 is cancelledd transfer 1 is started by the
+    host controller, and so on.
+    
+    Reported-by: Peter Stuge <peter at stuge.se>
+    Signed-off-by: Lars-Peter Clausen <lars at metafoo.de>
+
+commit 1a895c6185f67ec7a90e624fd47af625ac6f9e0a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Jul 5 01:47:44 2012 +0200
+
+    sr: Minor cosmetics.
+
+commit 249ae2be8f0e5132d601ab431ac8783b5b1c7439
+Author: Lars-Peter Clausen <lars at metafoo.de>
+Date:   Sat Jun 30 20:54:45 2012 +0200
+
+    sr: session/demo: Remove Windows specific hack
+    
+    The session and demo device code contain a hack to make the demo device work on
+    Windows. This was neccessary since polling on windows requires special handling
+    and we can not just pass in the raw fd to poll.
+    
+    With the previous patches which added support for non-fd based event sources
+    this hack is no longer required. The patch moves the GIOChannels used by the
+    demo device to the demo device context and uses sr_session_source_add_channel
+    to register a source for the channels instead of using the raw pipe fds.
+    
+    Signed-off-by: Lars-Peter Clausen <lars at metafoo.de>
+
+commit aac0ea256327bdff8f2a98bf62c7ac6a42dd1e44
+Author: Lars-Peter Clausen <lars at metafoo.de>
+Date:   Sat Jun 30 20:54:44 2012 +0200
+
+    sr: session: Add support for GPollFD or GIOChannel based sources
+    
+    A raw file descriptor to poll on is not always available, this patch adds
+    support for adding a source for a GIOChannel or GPollFD.
+    
+    Signed-off-by: Lars-Peter Clausen <lars at metafoo.de>
+
+commit 0687dfcde9eeebc2ee5fdc93af4a9a322ce9d071
+Author: Lars-Peter Clausen <lars at metafoo.de>
+Date:   Sat Jun 30 20:54:43 2012 +0200
+
+    sr: session: Keep a global pollfd array
+    
+    Currently we keep a file descriptor for each source and construct a pollfd array
+    from these during each loop iteration in sr_session_run(). This patch modifies
+    the code to keep a global pollfd array which is only modified when a source is
+    added or removed. On one hand this gets rid of the constant constructing and
+    subsequent freeing of the pollfd array in sr_session_run(), on the other hand it
+    will allow us to implement support for non-fd based pollfds.
+    
+    Signed-off-by: Lars-Peter Clausen <lars at metafoo.de>
+
+commit 2bccd322bc40a2ebe41a9d3f1c4b12cd52cb2595
+Author: Lars-Peter Clausen <lars at metafoo.de>
+Date:   Sat Jun 30 20:54:42 2012 +0200
+
+    sr: session: Use realloc to resize source array
+    
+    Use realloc to resize the source array when adding or removing a source. This
+    makes the code a bit smaller. In the remove function we now check whether the fd
+    is valid before doing anything else and if it is not simply do nothing. If it is
+    valid use memove to move the elements following the source one element down in
+    the array. Only after that has been done the array is re-allocated.
+    
+    Signed-off-by: Lars-Peter Clausen <lars at metafoo.de>
+
+commit 45c59c8bdd01954f9214fe7b869d92c55415d109
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Jul 5 00:55:07 2012 +0200
+
+    sr: moved sigrok.h so libsigrok/libsigrok.h
+    
+    All frontends will have to include <libsigrok/libsigrok.h> from now on.
+    This header includes proto.h and version.h, both installed from the
+    distribution into $INCLUDE/libsigrok/ as well.
+    
+    The only dynamically changed header is now version.h, which has both
+    libsigrok and libtool compile-time versions in it.
+
+commit 8489264f1e3ef07ba8f1143ed62fa88d90980f94
+Author: Lars-Peter Clausen <lars at metafoo.de>
+Date:   Tue Jul 3 23:59:12 2012 +0200
+
+    sr: demodevice: Reset sample limit when setting time limit and vice versa
+    
+    Only one limit should be active at a time. Make sure that the sample limit is
+    disabled when a time limit is set and vice versa.
+    
+    Signed-off-by: Lars-Peter Clausen <lars at metafoo.de>
+
+commit 25f5d66a7752379abe454da0705df4ed15ce6426
+Author: Lars-Peter Clausen <lars at metafoo.de>
+Date:   Tue Jul 3 23:58:40 2012 +0200
+
+    sr: fx2lafw: Fix potential leaks in acquisition_start error paths
+    
+    Call abort_acquisition if starting sampling fails in acquisition_start, this
+    will ensure that all already allocated resources are being freed again.
+    
+    Signed-off-by: Lars-Peter Clausen <lars at metafoo.de>
+
+commit c03f045004a340bd418206cbd02eaefcede91a5b
+Author: Lars-Peter Clausen <lars at metafoo.de>
+Date:   Tue Jul 3 23:58:39 2012 +0200
+
+    sr: fx2lafw: Do not start a new acquisition if the old is still running
+    
+    This may happen if the acquisition_start is called right after calling
+    acquisition_stop and not all transfers have been freed or on repeated calls to
+    acquisition_start. If it happens we'll enter an undefined state and all kind of
+    strange behavior may occur, so error out in such a case.
+    
+    Signed-off-by: Lars-Peter Clausen <lars at metafoo.de>
+
+commit 0caa1ef0cb0b2231e232a7d1681e4e13fe838035
+Author: Lars-Peter Clausen <lars at metafoo.de>
+Date:   Tue Jul 3 23:58:38 2012 +0200
+
+    sr: fx2lafw: Abort pending transfers when sampling is stopped
+    
+    The recent reworks of the fx2lafw made sure that the total buffer size is large
+    enough hold 500ms of data. This was done to improve performance and stability.
+    That the timeout value for a transfer was also increased to over 500ms, a side
+    effect of this is that when sampling is stopped there will be a additional delay
+    of 500ms. This is because the driver waits for all transfers to be freed
+    before it sends a SR_DF_END packet. Once sampling has stopped this will only
+    happen once a transfer times out. This patch cancels all pending transfers when
+    sampling is stopped, this will cause them to be freed almost immediately and the
+    additional delay will disappear.
+    
+    Also make sure, that if we know, that we just have received the last transfer to
+    not resubmit this transfer again.
+    
+    Signed-off-by: Lars-Peter Clausen <lars at metafoo.de>
+
+commit ca3d84cca1d2f7427f8c5266717cb787d2346e16
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 1 22:37:15 2012 +0200
+
+    sr: add genericdmm driver
+
+commit 45edd0b204b4166f2f590bf130b97ff90896a99f
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 1 22:33:57 2012 +0200
+
+    sr: add HWCAP type SR_T_KEYVALUE (char **)
+
+commit f8c1fcda46584c3550a198625e0b5f0a58794b6e
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 1 22:31:31 2012 +0200
+
+    sr: use proper definitions for parity setting
+    
+    ols driver fixed to use these as well.
+
+commit 5d4fb4fc0d4dd4fc323d5ecf862502ec317692de
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 1 15:29:57 2012 +0200
+
+    fx2lafw: enable driver build by default
+
+commit 163f0523f6b26c0728153b5eafcf7a1b15645375
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Jun 28 22:57:03 2012 +0200
+
+    sr: Mastech VA18B: Partial protocol supports (WIP).
+    
+    Disable the driver for now, as it's not usable for the general public, yet.
+
+commit 99f5d45eccaf11ab72bfc8aeff6a07aa412d35b8
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Jun 28 01:47:38 2012 +0200
+
+    sr: hantek-dso: Fix copy-paste error.
+
+commit 2769eed9917aeb6e549b90be4925a4c192a92309
+Author: Lars-Peter Clausen <lars at metafoo.de>
+Date:   Mon Jun 25 23:51:38 2012 +0200
+
+    sr: fx2lafw: Move empty_transfer_count to device ctx
+    
+    If one device is failing it should not affect the transfers of other devices.
+    
+    Signed-off-by: Lars-Peter Clausen <lars at metafoo.de>
+
+commit 5af666a94e67e8a18c0dfa1f4314e1c3e93aa993
+Author: Lars-Peter Clausen <lars at metafoo.de>
+Date:   Mon Jun 25 22:15:59 2012 +0200
+
+    sr: fx2lafw: Calculate buffer size and timeout based on sample rate
+    
+    Currently timeout and buffer size are hard-coded in the fx2lafw driver which is
+    non-optimal if we want to get good results at both high and low sample rates.
+    
+    The timeout is hard-coded to 40ms, which doesn't work well when sampling at
+    a low sample rate. E.g. at 20kHz filling all available buffer space alone takes
+    6 seconds. So naturally we'll see a lot of transfers timeout in this case.
+    
+    The buffer size is hard-coded to 4096 bytes, which does not work well with high
+    sample rates. E.g. at 24MHz these 4096 bytes are enough space for 0.17ms of
+    data. The total buffer size is enough for about 5ms of data. Sooner or later the
+    application won't be able to resubmit a transfer within this time span and the
+    device will abort data acquisition. Usually this happens within the first few
+    seconds of sampling.
+    
+    This patch adds a few new helper functions which calculate the buffer size and
+    timeout based on the current sample rate.
+    
+    The buffer size is chosen to be large enough to hold about 10ms of data and it
+    also must be a multiple of 512 bytes since the firmware will send us the data
+    in 512 byte chunks.
+    
+    The timeout is set to the time it would take to fill the whole available buffer
+    space plus a 25% headroom to accommodate for jitter. This is more than enough,
+    but there is no need to make the timeout a tight deadline, since it is only
+    meant as a last resort in case the device stops submitting data. And in this
+    case data acquisition will be aborted anyway.
+    
+    The patch also limits the the number of transfers so that the total buffer
+    space is not much more of 500ms. This will ensure that we do not have to
+    wait too long when aborting data acquisition.
+    
+    This patch also significantly reduces the number of context switches when
+    sampling at a higher sample rate. On my system for example the CPU load of
+    sigrok-cli when sampling at 24MHz goes down from ~25% to 3-4%.
+    
+    Signed-off-by: Lars-Peter Clausen <lars at metafoo.de>
+
+commit 7ce737a77c0d29276cdda4f3670c1ef41173bb9c
+Author: Lars-Peter Clausen <lars at metafoo.de>
+Date:   Sun Jun 24 16:45:08 2012 +0200
+
+    sr: fx2lafw: Handle the transfer's status
+    
+    While errors are usually already implicitly caught by looking at the packet
+    length field there is one error status which is worth special handling. If the
+    device has been removed there is not really a chance to recover from this error
+    so data acquisition can be stopped immediately.
+    
+    Signed-off-by: Lars-Peter Clausen <lars at metafoo.de>
+
+commit 17dff8a1e6faaec02ed99715f2914b15b4cab82e
+Author: Lars-Peter Clausen <lars at metafoo.de>
+Date:   Sun Jun 24 12:19:09 2012 +0200
+
+    sr: fx2lafw: Avoid unnecessary alloc/free combo
+    
+    In receive_transfer for each completed transfer a new buffer is allocated and
+    the old one is freed. We can avoid this by simply reusing the buffer for the
+    next transfer. This is possible if we only resubmit the transfer after all
+    processing on the data buffer has been done. A new buffer is only allocated if
+    the size of the old one is not 4096 bytes.
+    
+    Signed-off-by: Lars-Peter Clausen <lars at metafoo.de>
+
+commit f855de7575915a8b3a07ed32ff7ec6b431777317
+Author: Lars-Peter Clausen <lars at metafoo.de>
+Date:   Sun Jun 24 12:08:59 2012 +0200
+
+    sr: fx2lafw: Properly free transfer
+    
+    When freeing a transfer we also have to free the transfer buffer. We also have
+    to keep track of the number of allocated transfers and if the freed transfer was
+    the last one stop acquisition. This patch introduces a helper function which
+    takes care of all of this.
+    
+    Signed-off-by: Lars-Peter Clausen <lars at metafoo.de>
+
+commit bd47acabe33813acb7dd6a4ebf155418072b08b7
+Author: Lars-Peter Clausen <lars at metafoo.de>
+Date:   Sun Jun 24 12:04:35 2012 +0200
+
+    sr: fx2lafw: Allocate header and packet struct on the stack
+    
+    The header and packet struct are only used in the scope of this function and
+    they are freed at the end of it. Also these structs are rather small, so they
+    can safely be allocated on the stack. By doing so memory leaks on the error
+    paths are avoided.
+    
+    Signed-off-by: Lars-Peter Clausen <lars at metafoo.de>
+
+commit 0c156e06c55a5b69385778fb00292d5866660a7f
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Wed Jun 27 21:39:26 2012 +0100
+
+    fx2lafw: Made libusb_claim_interface error messages more informative
+
+commit 88a13f30bdcad5de468221ef06e7dbc8859c3d8b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Jun 27 19:36:30 2012 +0200
+
+    hantek-dso: add profiles for all five models in the series
+    
+    Also cleaned up profile struct, and use the new firmware filenames.
+
+commit 3b6c19303db9da2d70a65880fa85883273b17a5a
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Jun 27 01:02:39 2012 +0200
+
+    fx2lafw: fix broken firmware upload timeout
+    
+    Also corner case error init.
+
+commit fc8fe3e3141f998dd97004c4379cb4d3acbd62a9
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Jun 27 00:55:15 2012 +0200
+
+    hantek-dso: get rid of broken GTV_TO_MSEC firmware upload timeout
+
+commit e749a8cb50029b6275a32a60c351d65f14fdf601
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jun 26 23:26:55 2012 +0200
+
+    hantek-dso: start sending the frame only from the trigger point
+    
+    Samples received before the trigger point are stored. From the
+    trigger point on, every chunk received from the device is sent
+    up the session bus. After the device has finished sending, the
+    stored samples are transmitted.
+
+commit fa114e4ab1ef0d30bb3cce8f926e43d66df9f787
+Author: Lars-Peter Clausen <lars at metafoo.de>
+Date:   Thu Jun 21 19:54:29 2012 +0200
+
+    sr: fx2lafw: Set correct unitsize for trigger buffer
+    
+    Commit 88b75eb719 ("fx2lafw: Added device caps and added support for wide
+    sampling") increased the size of the trigger buffer from 8 to 16 bit, but forgot
+    to adjust the unitsize logic packet which is used to send the contents of the
+    trigger buffer. This patch sets the unitsize to sizeof() of the trigger buffer.
+    
+    Signed-off-by: Lars-Peter Clausen <lars at metafoo.de>
+
+commit e05a174be2f9142471ad94a1af2b3722efd9c6ae
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jun 24 18:57:37 2012 +0200
+
+    hantek-dso: fix triggerpoint conversion
+
+commit f3ab43a8fbc39fe786718a7a3f5528acb3150aa7
+Author: Lars-Peter Clausen <lars at metafoo.de>
+Date:   Thu Jun 21 10:30:38 2012 +0200
+
+    sr: fx2lafw: Fix multistage trigger
+    
+    Multistage triggers currently do no work, because there is a return statement
+    in the middle of the trigger detector which will be hit as soon as the first
+    stage in a multistage trigger matches. This patch removes the return statement
+    so that the trigger detector can continue to try to match the next stage. In
+    order for this to work we also make sure that the trigger stage is only reset
+    if the current sample does not match.
+    
+    Signed-off-by: Lars-Peter Clausen <lars at metafoo.de>
+
+commit e21e846330070e102b24e08605b76b362020f500
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Jun 23 01:17:36 2012 +0200
+
+    sr/srd/cli: require glib version >= 2.28
+    
+    Needed for g_get_monotonic_time(). Thanks to Tomaž Šolc.
+
+commit eabf24035b29020085f01dd6e5a2f3c7075db23e
+Author: Lars-Peter Clausen <lars at metafoo.de>
+Date:   Thu Jun 21 10:30:39 2012 +0200
+
+    sr: fx2lafw: Fix memory leaks in receive_transfer
+    
+    There are a few memory leaks in the receive_transfer transfer function. The most
+    serve of them is that a sample buffer is not freed if the triggered has not
+    matched yet, which causes a sigrok process which is waiting for a trigger to
+    consume several megabytes of memory within seconds. The other leaks are on the
+    error paths in that function.
+    
+    Signed-off-by: Lars-Peter Clausen <lars at metafoo.de>
+
+commit 9edfee3ee31bc6cd7657392f2c9ac28ccf7a7dce
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Jun 21 23:59:27 2012 +0200
+
+    sr: ols: Fix incorrect comment.
+
+commit eb1f1eb407965e72d31372b472b17989d3a2f3c8
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Jun 20 19:56:54 2012 +0200
+
+    sr: Unfinished Mastech VA18B (DMM) support.
+
+commit b908f067f25f7c307e46ba05a23fd3cc5187379f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Jun 21 22:36:13 2012 +0200
+
+    sr: chronovu-la8: Split code into api.c and driver.c.
+    
+    We should generally use api.c for API related functions and put the other
+    functions (mostly hardware-specific low-level code) into other C file(s)
+    for better readability.
+
+commit 9956f2851fb97a4b4090cedcde6f4b83cb08e971
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Jun 20 23:55:23 2012 +0200
+
+    sr: analog: Add MQ and UNIT enums.
+    
+    MQ is the measured quantity, e.g. voltage, current, temperature.
+    
+    UNIT is the unit in which these quantities are measured, e.g. volt,
+    ampere, celsius, kelvin, etc. etc.
+    
+    The same MQ can be specified in different UNITs by the driver, depending
+    on what the hardware reports. Conversion is left to the frontends.
+
+commit c13536fa9c5ec756ff169423d43fc14b10be8cfa
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jun 19 23:33:50 2012 +0200
+
+    sr: backend/zeroplus: Improve debug output.
+
+commit d27e406e13d1247a7839698d3643b8ebae7143af
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jun 19 02:05:28 2012 +0200
+
+    sr: new output format 'float', just floating point values
+    
+    Also outputs FRAME-BEGIN and FRAME-END, if present in the stream.
+
+commit cdea754ae59dda3974b1c00cae2be1e72a539176
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jun 19 02:04:18 2012 +0200
+
+    sr: remove unused code
+
+commit 4368827aefc3488ae6b7b375590bbad1dd4d73fc
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jun 19 01:06:02 2012 +0200
+
+    sr: only handling analog voltage units for now
+
+commit 6e6eeff47a93e48b31ef5d16feb707e8725dbbd3
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jun 18 23:09:37 2012 +0200
+
+    hantek-dso: capturestate packet also contains the trigger point
+    
+    Not yet used, but it's the key to knowing where in the frame to
+    start displaying; the frame is used as a circular buffer, and what
+    is sent is effectively a snapshot.
+
+commit a217bcdf104e757db9713ea767ee5709b137084b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jun 18 23:05:02 2012 +0200
+
+    hantek-dso: relays now set properly
+    
+    They appear to be arranged to switch on/off a hierarchical series of
+    devices that attenuate the channel by an order of magnitude.
+
+commit 384c28d9e74791a753bd25e471d20d970ab2346b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Jun 13 18:58:24 2012 +0200
+
+    sr: hantek-dso: Use portable g_ntohs() function.
+    
+    The ntohs() from <arpa/inet.h> is not available on MinGW/Windows. There
+    are ways to work around this, but as we use glib already, using g_ntohs()
+    is the best option anyway.
+
+commit c5841b28092ad9366cef5d512ddb10d6a34c9c0a
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jun 5 18:17:01 2012 +0200
+
+    hantek-dso: calculate voltage based on vdiv setting
+
+commit a10c805636c7252cbd22582fc6360afc080ca48f
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jun 5 18:16:23 2012 +0200
+
+    hantek-dso: default to DC coupling
+
+commit 1d97091e713d110a79f754472ea97f9286512567
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jun 5 18:15:58 2012 +0200
+
+    hantek-dso: fix CH2 vdiv setting
+
+commit 019d56633a81a240c6df4813c778cfb08bc130a6
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jun 5 18:15:04 2012 +0200
+
+    sr: add udev entry for Victor 70C multimeter
+
+commit 0026228ad01838dccaf761d17d97bda9bbbb7e72
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jun 5 18:14:23 2012 +0200
+
+    sr: fix udev rules for Hantek DSO-2090
+
+commit aff5a729abfaa016555f5d4a6a1e2c953405179d
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jun 5 17:37:28 2012 +0200
+
+    sr: add unit field to sr_df_analog packet
+
+commit 62bb8840e193cc73702b9e586882555bc18a8c61
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Jun 1 01:12:09 2012 +0200
+
+    sr: hantek-dso: Consistency renames, constification.
+
+commit 0236ab687fbbb0e68bd27791a6cd849fc5321cd3
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Jun 1 00:23:47 2012 +0200
+
+    cli/gtk/qt: Now all require libsigrok >= 0.2.0 (API changes).
+
+commit 63298404df6e4d8a4bd7358ad55e4076b4bf2993
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Jun 1 00:16:42 2012 +0200
+
+    sr: Increase pkg version to 0.2.0, increase lib version.
+
+commit 0a88ec3d9c97d20a26f2c0d8813ce7ba075421f6
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu May 31 22:46:28 2012 +0200
+
+    sr: fx2lafw: Use gboolean, cosmetics, fix gcc warning.
+
+commit af36b8096942a704afa7e858fcd8fc8e15b92e09
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu May 31 22:43:12 2012 +0200
+
+    hantek-dso: Update to constified libsigrok API.
+
+commit 88ff66c2c910f32b92faa6c4815f60cec47577c4
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu May 31 22:40:41 2012 +0200
+
+    hantek-dso: Quickfix for build issue (will be removed later).
+
+commit f4575b6549ded99ec5380b4d6fafa899f5cb65ae
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Thu May 10 16:34:24 2012 +0100
+
+    fx2lafw: Added a check to limit the sample rate during 16-bit sampling
+
+commit d1ddc7a9a8a7226fcb1f8b5a360c275684e77e9a
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Mon May 7 16:01:10 2012 +0100
+
+    fx2lafw: Added device caps and added support for wide sampling
+
+commit a533743dd1680bb53f29b6a01cccbc5380027e77
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Mon May 7 15:07:06 2012 +0100
+
+    sr: Made sample rate lists const
+
+commit 1b79df2f57012926927983a8e2829004f0eee4fa
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Mon May 7 15:02:02 2012 +0100
+
+    sr: Made the dev_config_set parameter a const pointer
+
+commit b7f578bef53ff0e645ca0cae3f9781f577b7367a
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Mon May 7 13:35:56 2012 +0100
+
+    sr: Made the dev_info_get return value const
+
+commit 915f7cc87a8dce688ab99fc67005ef77e0d028a2
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Mon May 7 13:57:43 2012 +0100
+
+    sr: Made hwcap const
+
+commit 2715c0b86bafed70dc1d3737b59750570951f507
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun May 20 01:14:37 2012 +0200
+
+    hantek-dso: hopefully handle endianness in voltage setting
+
+commit 4a090d722d7d3f2d1011fc5ff1c9a39c809f07bd
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun May 20 01:11:09 2012 +0200
+
+    hantek-dso: enable SR_HWCAP_COUPLING
+
+commit b58fbd99c8944a3ba584540aa7ceb34b5451fa3a
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu May 17 03:17:09 2012 +0200
+
+    hantek-dso: support for SR_HWCAP_COUPLING
+
+commit e1c8b2abfbc5a0aa75cf6fbd8f88e45a8df0fd5b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu May 17 03:16:01 2012 +0200
+
+    sr: support for SR_HWCAP_COUPLING and SR_DI_COUPLING
+
+commit 313deed219c39a902e6b7c39cf519c3476b9798d
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu May 17 02:03:12 2012 +0200
+
+    hantek-dso: support SR_HWCAP_VDIV
+
+commit bd8db307da41b3ca0f5401015f92e833e1db658e
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu May 17 01:55:59 2012 +0200
+
+    sr: support for SR_HWCAP_VDIV and SR_DI_VDIVS
+
+commit 79afc8cac4912f5e1025c608a10b05506a191be9
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu May 17 01:54:57 2012 +0200
+
+    sr: add voltage parser and prettyprinter
+
+commit c1e486185ec4e4a894419f8d287c55ffb6282979
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed May 16 02:07:51 2012 +0200
+
+    sr: use SR_T_RATIONAL_PERIOD (new-style types)
+    
+    SR_T_<type>_<parsehint>
+
+commit ebb781a69f1128fab5a9eedd39a548cba8ceccbb
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue May 15 22:41:00 2012 +0200
+
+    hantek-dso: support for SR_HWCAP_FILTER
+
+commit 3c4976c9c4b9dd09204c7c3797f1122e4b641631
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue May 15 22:39:32 2012 +0200
+
+    sr: support for SR_HWCAP_FILTER and SR_DI_FILTERS
+
+commit a370ef19161cee7016b7d24a2b9cef95b1191f6d
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue May 15 20:56:29 2012 +0200
+
+    hantek-dso: support for setting all CMD_SET_TRIGGER_SAMPLERATE params
+
+commit 76f4c61086b314e66e92dd571f37defd3f714554
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue May 15 20:46:14 2012 +0200
+
+    sr: add period parser
+
+commit 0fe11789961861a68d2de45136a7869f9b8c1717
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue May 15 20:45:46 2012 +0200
+
+    sr: add support for sr_rational and various HWCAPs and DIs
+
+commit bc79e906a0911b4218b42b63b2f27fb0016c59da
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon May 14 02:33:37 2012 +0200
+
+    hantek-dso: proper protocol implementation of trigger/samplerate setting
+
+commit 6e71ef3b6f27c3f3e1c5d5dc4e2f60caf54fc818
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue May 1 20:35:04 2012 +0200
+
+    hantek-dso: fix channel selection
+
+commit ae88b97ba28ba098a54ec11af99bb195e6f9ab32
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 30 22:29:31 2012 +0200
+
+    hantek-dso: delimit frames with SR_DF_FRAME_* packets
+
+commit 6ea7669c9dc3dd59ad88869e29f5411114196f34
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 30 19:55:06 2012 +0200
+
+    support for frame begin/end packets
+
+commit 3b533202c8b32fbe785906e9930959aae077aeff
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 23 01:05:58 2012 +0200
+
+    sr: initial support for Hantek 2xxx/5200 USB oscilloscopes
+
+commit f366e86c68071fa7888259aa3963b213caa81b51
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Apr 22 20:06:19 2012 +0200
+
+    sr: change all drivers to use SR_DF_META_LOGIC
+
+commit ee7489d23449a3f5a81777fbdb3309dfe22bcecd
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Apr 22 18:11:31 2012 +0200
+
+    sr: SR_DF_ANALOG type, and meta types for analog+logic
+
+commit 7e41e319d9a76da527eaa6e2708e4909ffd0d971
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 30 23:31:03 2012 +0200
+
+    sr: fx2lafw: Forgot to add (C) line to fx2lafw.h in recent commit.
+
+commit 0a8c0c324e16e4848498309dbb2efd27b4c812a9
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 30 23:15:23 2012 +0200
+
+    sr: fx2lafw: Only check for correct major FW version.
+    
+    Changes in the minor version number are OK, as those should never
+    contain any incompatible/API changes.
+
+commit 8fdecced96a1e849f5474e57aeca456dd265d9b9
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 30 22:55:03 2012 +0200
+
+    sr: Consistently use ZEROPLUS spelling.
+    
+    This is the version used throughout their website, let's use it.
+
+commit 921634ec10feb88dd2110d10d8b1914eaa742fb6
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 30 22:42:19 2012 +0200
+
+    sr: Fix typos.
+
+commit cf94c8167bdd520e43cda5cdc9ef1ebf301b814d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 30 22:40:59 2012 +0200
+
+    sr: fx2lafw: Add (C) line from old saleae driver it's based on.
+
+commit f9a33a4720403e7db4d69cb698b18dd724e16db7
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 30 22:23:36 2012 +0200
+
+    sr: README: Add section about firmware files.
+
+commit 537096739ee5b841f9f51a864f785cf7c4b56864
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 30 21:48:40 2012 +0200
+
+    sr: udev file: Minor fixes/additions.
+
+commit 02df29f0db42ae2f475df83e4cbe2d18994f7f53
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 30 21:36:28 2012 +0200
+
+    sr: NEWS: Minor updates/fixes.
+
+commit 2f3a6df8e4f34c8902002de4dcc3fda94f195ae0
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 30 09:26:15 2012 +0200
+
+    sr: Increase version number to 0.1.1.
+
+commit 5c4252cd8b7fafa9b37492c50a53f9165cd0e18d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 30 09:25:11 2012 +0200
+
+    sr: Update NEWS in preparation of upcoming 0.1.1 release.
+
+commit f60fdf6ebe26a6b8693e515ed1eeedb906b7a17f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 30 09:24:01 2012 +0200
+
+    sr: fx2lafw: s/MAX_RENUM_DELAY/MAX_RENUM_DELAY_MS/.
+
+commit e8bd58ffd2615ab2fbb0a963f359a705c584e4e1
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 30 09:10:41 2012 +0200
+
+    sr: fx2lafw: Fix a firmware upload bug on 32bit systems.
+    
+    The glib GTimeVal data type (and some functions using it) will be faded
+    out from glib sooner or later, so it's not a good idea to use them anyway.
+    
+    In this specific case GTimeVal.tv_sec was overflowing, leading a check in
+    libsigrok to fail, and thus to FX2 firmware upload errors, i.e.
+    non-working fx2lafw devices.
+    
+      http://thread.gmane.org/gmane.comp.debugging.sigrok.devel/166
+    
+    The root cause is that GTimeVal.tv_sec is a 'glong' (8 bytes on 64bit
+    systems, but only 4 on 32bit systems).
+    
+    We now use an int64_t (and g_get_monotonic_time() instead of the more
+    problematics g_get_current_time() which uses a GTimeVal).
+    
+    This has been verified to fix the issue on a 32bit system.
+    
+    Other uses of GTimeVal in libsigrok will be removed in a later release.
+    
+    Also, drop unneeded GTV_TO_MSEC.
+
+commit 36423d04e5411d9cd744bc6421f099b5d2c02730
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 30 02:27:30 2012 +0200
+
+    sr: input/chronovu_la8.c: Add missing #include.
+    
+    This fixes a compiler warning.
+
+commit fb6f1978ed490a4cc80125e93239abfdad55e4b7
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 30 00:00:33 2012 +0200
+
+    sr: New default firmware dir: $prefix/share/sigrok-firmware.
+    
+    We no longer expect firmware files to be in the
+    $prefix/share/libsigrok/firmware directory, as that would require an
+    additional (distro) package 'sigrok-firmware' or the like to install
+    files into another package's (libsigrok) path, which can be problematic.
+    
+    The current 'sigrok-firmware' repo's "make install" will already install
+    all files into $prefix/share/sigrok-firmware.
+
+commit c09584085ed0307ba05f3ebf88dcf54ce86aec07
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue May 29 20:30:15 2012 +0200
+
+    sr/srd/cli/gtk: ChangeLog -> MAINTAINERCLEANFILES.
+    
+    If the (generated) ChangeLog file is marked for DISTCLEANFILES, it'll be
+    removed whenever "make distclean" is called (and is then gone forever if
+    you use the tarballs, for example).
+
+commit 3217b032053d6eb89ca31b01968715813bcbe1bb
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue May 29 00:21:21 2012 +0200
+
+    sr: la8 in: Files must be exactly 8388613 bytes.
+    
+    All ChronoVu LA8 files (*.kdt extension usually) are exactly 8388613
+    bytes in size (8MB + 5 bytes). Check this, when trying to autodetect the
+    file format, to reduce the likelihood of 'chronovu-la8' being
+    autodetected on all binary files (instead of 'binary').
+
+commit 9f05304e4e1b842f875cfdaccf9e93cae0012937
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon May 28 23:40:12 2012 +0200
+
+    sr: ARMFLY AX-Pro is supported by fx2lafw (LA only).
+
+commit 432e5e95f53cd61160c1013921743267d84a7dd2
+Author: Pekka Nikander <pekka.nikander at senseg.com>
+Date:   Fri May 11 19:23:21 2012 +0300
+
+    sr/srd/cli: Fix compiling with Homebrew.
+    
+    Add ACLOCAL_DIR setting and AM_PROG_AR macro for compiling with Homebrew
+    under Mac OS X.
+    
+    Applies essentially the same change to
+    {libsigrok,libsigrokdecode,sigrok-cli}/{autogen.sh,configure.ac}
+    
+    It may be that the same fix is needed for the other autogen.sh and/or
+    configure.ac files, but that hasn't been tested and therefore not in
+    this commit.
+
+commit 40cd2b545d4d6ddb0dce7b54bfc8f9be5b77444a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu May 10 21:27:17 2012 +0200
+
+    NEWS: Add some news items.
+
+commit 37dc0b16a6d6aca8f98b4baee24028f3714f91d4
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 11 00:19:01 2012 +0200
+
+    fx2lafw: Cosmetics.
+
+commit dc68c660d566424e9d83b19959a79d40e599c71c
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Mon May 7 16:44:25 2012 +0100
+
+    fx2lafw: Added a gpif delay debug message
+
+commit 79dc64985f7e50943562169aebd7eefbd6e13490
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Mon May 7 16:42:50 2012 +0100
+
+    fx2lafw: Added support for 20kHz and 25kHz sampling
+
+commit 897c1a2ee5c7397a4ab281a5c83f8f5c34ea0aa1
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Mon May 7 12:40:52 2012 +0100
+
+    fx2lafw: Added support for 100kHz and 50kHz sampling
+
+commit 1e94408ae515157a9f27898b7b4c181e2aef980a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun May 6 19:54:46 2012 +0200
+
+    sr: fx2lafw: Get/display FX2 REVID.
+
+commit 1663e4706cd966fcaed40d067ceea4b613e8125d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun May 6 17:13:49 2012 +0200
+
+    sr: fx2lafw: Braintechnology USB-LPS support.
+
+commit 6352d030dfd11fb63a1beedd0e24b3e28be1a961
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 2 19:02:03 2012 +0200
+
+    sr: We support both SIGMA and SIGMA2.
+    
+    Also, a few minor coding-style fixes etc.
+
+commit b5f6fcb1ac98a83747c778262a7cc91f6884e9e4
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue May 1 19:09:06 2012 +0200
+
+    sr: udev: Add Ideofy LA-08 entry.
+
+commit 18a98412ec2ed644922b6fff44485318454975ab
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue May 1 19:05:09 2012 +0200
+
+    sr: udev: Add Velleman PCSU1000 entry.
+
+commit 1c41873612df34b90ec3ddaaf3f2d2e30dfc98e7
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue May 1 19:03:44 2012 +0200
+
+    sr: udev: Fix alphabetical order.
+
+commit 585a9ec4a2076ca0ea23ef244d94521ea86316f8
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue May 1 19:00:28 2012 +0200
+
+    sr: udev: Add Robomotic BugLogic 3.
+
+commit 6b73d9a598747b70436010f0cb27061d5dd93618
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Apr 27 01:28:47 2012 +0200
+
+    fx2lafw: use iManufacturer/iProduct fields to identify our firmware
+    
+    It's more deterministic than the endpoint profile check we did before. Which
+    was also broken.
+
+commit 6752905e6be19617d83c48a6db5a20b8e932308b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Apr 26 23:18:05 2012 +0200
+
+    sr: zeroplus: Fix segfault, add debug output.
+    
+    There are various ZEROPLUS models with different probe numbers. For now
+    hardcode to 16 (for the popular LAP-C(16032)). This will need to be
+    fixed in a dynamic way later.
+    
+    This fixes a segfault due to only 16 probe-names being defined, but the
+    drivers returning 32 as probecount.
+    
+    Also, add some additional debug output.
+
+commit 993526f82421d3954b1032bfc1affb208916ebeb
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 23 15:31:41 2012 +0200
+
+    sr: don't use deprecated glib functions
+    
+    As of the recent glib 2.32 release, these produce deprecation warnings
+    at compile time.
+
+commit 42cdeef6268a2fa28a42e472324c5122410847d0
+Author: Håvard Espeland <haavares at ifi.uio.no>
+Date:   Mon Apr 23 13:36:17 2012 +0200
+
+    sigma: Fix segfault when no Sigma present.
+
+commit 868501fa46bfb3c43bf4906e57587ef24463641c
+Author: Håvard Espeland <haavares at ifi.uio.no>
+Date:   Sun Apr 22 15:10:46 2012 +0200
+
+    sigma: Bump copyright notice.
+
+commit e210c6c09003cbd4cfada74c42466ad407c73ad8
+Author: Håvard Espeland <haavares at ifi.uio.no>
+Date:   Sun Apr 22 14:31:40 2012 +0200
+
+    sr: Remove zlib dependency.
+    
+    No longer needed by Sigma driver.
+
+commit e3fff420dac8ba489674cf685529b3647fca185b
+Author: Håvard Espeland <haavares at ifi.uio.no>
+Date:   Sun Apr 22 14:24:02 2012 +0200
+
+    sigma: Add support for SIGMA2 (req. new firmware).
+
+commit 3c36c403faf9ed06741aaeb8fbbaa10a18871a3c
+Author: Håvard Espeland <haavares at ifi.uio.no>
+Date:   Sun Apr 22 13:08:16 2012 +0200
+
+    sigma: Use heap for datafeed packet and header.
+
+commit 805919b042386043f3f2fde8c13ca276a99e088c
+Author: Håvard Espeland <haavares at ifi.uio.no>
+Date:   Sun Apr 22 13:05:10 2012 +0200
+
+    sigma: Fix bugs in receive_data callback.
+    
+    - Poll data position on Sigma for every iteration.
+    - Return TRUE when no data ready.
+
+commit 934cde02b80791943a023c2b4949fc5de43d5081
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Apr 19 00:55:29 2012 +0200
+
+    fx2lafw: supported_samplerates[] should be 0-terminated.
+
+commit f488762a17a3dce8a513aabcc0475f7382ec19bd
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Wed Apr 18 22:28:52 2012 +0100
+
+    fx2lafw: Added support for default Cypess FX2 without EEPROM
+
+commit 824b1a8f5cc6073f6d6505d0efa74d67f4da0fb7
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Wed Apr 18 19:17:25 2012 +0100
+
+    sr: Deleted the saleae-logic driver, fx2lafw has superceded it.
+
+commit d56ee26599fa6dd560613adc14a4a28575063d5e
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Wed Apr 18 19:10:15 2012 +0100
+
+    sr: Disable saleae-logic driver by default and enable fx2lafw
+
+commit 9304d576507db12f4072f427bcf1ce1645debce3
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Wed Apr 18 19:07:30 2012 +0100
+
+    fx2lafw: Added slower sample rates
+
+commit fefd54a0cdd4b2d30c36e53ea2ecdce6ff4b96ea
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 17 00:12:33 2012 +0200
+
+    sr: Initial 0.1.0 release.
+
+commit 69e70c233ef6186131369ad596a96a2632bdcf85
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Apr 16 23:16:00 2012 +0200
+
+    sr/srd: SR_API/SRD_API/etc. is a no-op on MinGW.
+    
+    This avoids warnings on a MinGW build. The feature depends on ELF files,
+    but MinGW/Windows uses PE files.
+
+commit 787c43905d6f61c08d3b66a4a09dc12038120861
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Apr 15 20:33:45 2012 +0200
+
+    sr: Add functions to query sr version(s).
+
+commit 0aeb0ccd5572a08c088e7903321a5998374f42e6
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Apr 7 17:40:52 2012 +0200
+
+    sr: sr_err() et. al. don't need trailing \n.
+
+commit bf978d355345a7cc3ae7dc6199cc25952aaa182f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Apr 7 17:35:14 2012 +0200
+
+    sr: sr_parse_triggerstring docs/improvements.
+    
+    Also fix smaller typos and cosmetics.
+
+commit 44dfd483db9e594acc809b9d76eb910a9b53165d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 10 22:32:31 2012 +0200
+
+    sr: fx2lafw: Cosmetics.
+
+commit 13bf7eccbb08214c3d6d53da5b5b6a269a64a779
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Tue Apr 10 18:27:24 2012 +0100
+
+    fx2lafw: Added command to verify firmware version
+
+commit 6fbe5e6081b0f83fa97f0097bc87a21a45c48481
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sun Apr 8 17:19:52 2012 +0100
+
+    fx2lafw: Safer use of libusb_get_device_list
+
+commit 105492034465fcdddfe89c916ed6da3242d39901
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Mar 31 12:09:37 2012 +0200
+
+    sr/srd: Fix 'make distcheck'.
+
+commit da90fb2a01523e3277ed849297646614dce9a15d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Mar 31 12:05:20 2012 +0200
+
+    sr/srd: Add ChangeLog to ignore list, it's generated.
+
+commit 2e26e0aa0b7ccbdb461fdf71dde59e0400ba50ee
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Mar 31 11:57:46 2012 +0200
+
+    sr: Disable fx2lafw driver again (for now).
+    
+    After some more testing, it will probably be enabled by default and will
+    replace/deprecate the Saleae Logic driver at some point.
+
+commit c5d83a5a72b70b88cd1aa3299499b8b5389a0da3
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Mar 31 11:37:08 2012 +0200
+
+    sr: Add NEWS file.
+
+commit 6dddd902244f314eba721a0d8804731ea9c9912d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Mar 31 11:28:24 2012 +0200
+
+    sr: SR_PACKAGE_VERSION_* for consistency.
+    
+    No need to use the LIBSIGROK_ prefix here when we use SR_ everywhere
+    else. Also, better distinction between package version and lib version.
+
+commit da68656857cc0c70faa582d954c3b0bf5b6a1dbc
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Mar 29 08:55:12 2012 +0200
+
+    sr: fx2lafw: Consistency fixes.
+
+commit 01c3e9dbd5bd583012fc1f46237bf4fde784d209
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Mar 28 21:55:48 2012 +0200
+
+    sr: s/_clear/_remove_all/ for consistency.
+
+commit 054e67090641e0a56a7e55789a3882ca138a0b11
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Mar 28 20:00:13 2012 +0200
+
+    sr: out: Use uint8_t (not char) for buffers.
+
+commit 69cfcfc8f0f3f4358714d706268fc05aaa70ca23
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Mar 28 18:52:17 2012 +0200
+
+    sr: Make wrappers honor return values.
+
+commit 0fc12d66f1cf0fa46d075f9a9f8b691a325f39b9
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Mar 28 02:32:52 2012 +0200
+
+    sr: Generate ChangeLog from git upon 'make dist'.
+
+commit 7ae2f9d56fed0e53ad3dab25de65504acc3022a0
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Mar 25 22:02:19 2012 +0200
+
+    sr: fx2lafw: Cosmetics.
+
+commit b04902b6469d4aed32e69125167f7ff71992fcba
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Mar 25 15:23:31 2012 +0200
+
+    sr: fx2lafw: Use SR_PRIV where needed.
+
+commit 30da9658ad908864f78e3a99366f7787a80dcc43
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Mar 25 15:21:56 2012 +0200
+
+    sr: fx2lafw: command.h: Add missing include guards.
+
+commit f4a9e5c0aa81738d26e7893d6cf47ebdb4a91047
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Mar 25 15:20:55 2012 +0200
+
+    sr: fx2lafw: Cosmetics.
+
+commit 94c26b08fdc2568a33e176b895c63048a4b66464
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sun Mar 25 19:39:06 2012 +0100
+
+    sr: Build ezusb.c for fx2lafw as well as saleae-logic
+
+commit ec888f62fe4298229e6ed0865937d74476715bf7
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sun Mar 25 18:53:54 2012 +0100
+
+    salae: Only terminate session after all transfers have been aborted
+
+commit 3e6292b2967db0b86281988ebf816317956a8a51
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sun Mar 25 18:52:30 2012 +0100
+
+    fx2lafw: Made finish_acquisition a static function
+
+commit 590b9f9a91a703ceea4c430566735d05a2acf82b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Mar 24 22:32:47 2012 +0100
+
+    sr: Fix some samplerate fields.
+
+commit 85a77720c678d1bb37c1445755ea2b38c658ca36
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Mar 24 19:42:26 2012 +0100
+
+    sr: sigrok.h: Add version macros.
+
+commit 4937b2355156f954d6fc3c1daf258d3825582743
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Mar 24 10:03:36 2012 +0100
+
+    sr: Rename sigrok.h. to sigrok.h.in, needed soon.
+
+commit cb61e9f7c3cfa2e3c9eee0bd221f47dd95f34073
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sat Mar 24 10:04:36 2012 +0000
+
+    fx2lafw: Only terminate session after all transfers have been aborted
+
+commit 24125e05202626c9fea3f056ecc5d008f544970b
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sat Mar 24 10:07:22 2012 +0000
+
+    fx2lafw: Removed a line of redundant code
+
+commit 6c6781b6a7559b66645ec4dbebaf6dca0246cb5e
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Wed Mar 21 20:42:41 2012 +0000
+
+    fx2lafw: Imported software triggering from fx2lafw
+
+commit 97fbf6704e5876f3cfbc519f05acaa2af65a6ff0
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Mar 21 23:42:19 2012 +0100
+
+    sr: udev: Add missing Hantek DSO-2090 entry.
+
+commit 8a6b5b50e1555744374781f0a438c8965f501e98
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Mar 21 22:33:51 2012 +0100
+
+    sr/srd: Remove API warnings from READMEs.
+    
+    We'll have a libsigrok and a libsigrokdecode release soon. After that,
+    any API changes must be properly documented and reflected in the
+    SO version (and package version) numbers of the libs.
+
+commit 2f8701d112cc1c4b61b36fe4c7096431833a8c9d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Mar 21 22:29:41 2012 +0100
+
+    sr: Various fixes in the udev file.
+
+commit 2e7cb0040a64062cb4b13fdff72995f4b5dc8769
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Mar 21 19:58:56 2012 +0100
+
+    cli: Fix -V/-h output a bit.
+    
+    Options and their defaults should not be documented there, but rather in
+    the manpage or such.
+
+commit b5750520bb0e2726ad6248e23f52a854535bc9a2
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Mar 21 19:45:46 2012 +0100
+
+    sr: Enable fx2lafw driver per default.
+
+commit 8ec95d22822ed5ebf4b6aeaff654608ad0225073
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Mar 21 19:28:43 2012 +0100
+
+    sr/srd: Small fixes, constifications, doc updates.
+
+commit a4d39856788e2182e53fa6a0f0a05f3867f31fc0
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Mar 21 18:40:25 2012 +0100
+
+    sr/cli/gtk/qt: Fix package version numbers / docs.
+    
+    The next (and first) libsigrok release will be called 0.1.0.
+    
+    The next (and first) libsigrokdecode release will be called 0.1.0.
+    
+    The next sigrok-cli release will be called 0.3.0 (as we already had a 0.1
+    and 0.2 release of sigrok-cli; those did not yet use the libs, though).
+    
+    sigrok-gtk and sigrok-qt didn't have any releases yet, so their version
+    numbers are set to 0.1.0.
+    
+    Also, consistently use three numbers/digits for our version numbers.
+
+commit eb0a373189e0e1f346b6807b692c2ea0bdaa57b8
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Mar 20 18:09:18 2012 +0100
+
+    sr/cli: s/patternmode/pattern/ in a few places.
+
+commit ebc347388240e025181265f7d3d63a22f7bd5da9
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Mar 20 17:51:18 2012 +0100
+
+    sr: s/err/ret/ for consistency.
+    
+    We use ret, err, error, and others for return codes of functions.
+    Standardize on 'ret' for consistency reasons for now.
+
+commit d6eb0c333c8424d151637c18e1a1aef849d5fb31
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Mar 18 12:57:34 2012 +0100
+
+    sr: Fix handling of virtual devices.
+    
+    I.e., handling of sessions which use input from files (not from actual
+    logic analyzer hardware).
+
+commit 21b50ee1831602bd6c1f223fb200e2c298885aa3
+Merge: 9289e27 ecc16ed
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Mar 16 00:04:51 2012 +0100
+
+    Merge remote-tracking branch 'joel/public'
+
+commit ecc16ed07052ef399c36d36456aa943fcf81190c
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Wed Mar 14 22:56:15 2012 +0000
+
+    fx2lafw: Upped NUM_SIMUL_TRANSFERS to 32
+
+commit 9289e273bb6dfe9e8e46b5598830d4fb293175fc
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Mar 14 22:22:32 2012 +0100
+
+    sr: session_driver: Naming consistency fixes.
+    
+    Use 'receive_data()', and 'cb_data' as all the other drivers do.
+
+commit 455b26edba718bd2dd2a33cb713d0ab077b4fd32
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Mar 14 22:09:52 2012 +0100
+
+    sr: demo: s/struct databag/struct context/.
+
+commit ab331b679c417282616efa7d05d456868fd42933
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Mar 14 22:08:31 2012 +0100
+
+    sr: demo: s/mydata/ctx/.
+
+commit 4101f961e8a414ae17b16c0feb1e10fd07d08d52
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Mar 14 20:02:48 2012 +0100
+
+    sr: s/SR_{USB,SERIAL}_INST/SR_INST_{USB,SERIAL}/.
+
+commit 4502e869210005559d9f1a0e66f1e6954e6368c0
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Mon Mar 12 21:49:34 2012 +0000
+
+    fx2lafw: Added CWAV USBee SX to the device list
+
+commit 0ca21631dda3d948f8a67de5d48a2198b1efa425
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Mon Mar 12 21:38:25 2012 +0000
+
+    fx2lafw: Corrected a comment
+
+commit 93a9f3daaf7fb679660f44c67ffa0ea1171e67b1
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Mon Mar 12 21:36:17 2012 +0000
+
+    fx2lafw: Added Saleae Logic (and clones) to the device list
+
+commit f8b07fc6c37cc40dbcc3c6bc607d6e3137b532e4
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Mon Mar 12 21:31:43 2012 +0000
+
+    fx2lafw: Moved firmware path into fx2lafw_profile
+
+commit 4679d14db3fcc6e8990b916e0c175848af52f464
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Mon Mar 12 21:06:45 2012 +0000
+
+    fx2lafw: Made fx2lafw profiles const
+
+commit 6ccfadaf667a615c00526a7fb9df0500f35cc0e3
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Mon Mar 12 21:04:53 2012 +0000
+
+    fx2lafw: Made string pointers constant
+
+commit 17b6c75a899bb5fb2b8b841b60e3e9fb52ca3e30
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Mon Mar 12 21:03:13 2012 +0000
+
+    fx2lafw: Added ESLA201A to device list
+
+commit 017375d17ebddce8f986568a476018593c8b5ffc
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sun Mar 11 19:00:52 2012 +0000
+
+    fx2lafw: Send start command after bulk transfer have been set up
+
+commit 13d0d2698c97a60cbb73423ffb78846347309c11
+Author: Matt Ranostay <mranostay at gmail.com>
+Date:   Thu Mar 8 22:26:30 2012 -0800
+
+    ols: fixed *ctx null dereferences that would SEGFAULT on probing for a OLS or attempting to read from it.
+    
+    Signed-off-by: Matt Ranostay <mranostay at gmail.com>
+
+commit 9031ce63f3cee037ffc3e565cf324cafe38522f5
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sun Mar 4 18:02:44 2012 +0000
+
+    fx2lafw: Corrected check_conf_profile checks
+
+commit dba024420f934ff10f18eebbaad1f4e97c739259
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sun Mar 4 14:10:44 2012 +0000
+
+    fx2lafw: Implemented control of sample rates
+
+commit f92994fd9174bc423e58c21eda83633afc9513da
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sun Mar 4 14:10:05 2012 +0000
+
+    fx2lafw: Ensure default sample rate is set
+
+commit d98c4e35ce3187a8d4618a6c26ce35de636d7b91
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sat Mar 3 18:09:29 2012 +0000
+
+    fx2lafw: Removed CMD_STOP and renumbered commands
+
+commit 2e526f4a6a96bca01c81620ff820aa39e356977f
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sat Mar 3 15:22:51 2012 +0000
+
+    fx2lafw: Moved num_samples into context struct
+
+commit 266784d5947137040b4a72d0e00dc97c0c8b40ba
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sat Mar 3 15:18:19 2012 +0000
+
+    saleae-logic: Moved num_samples into context struct
+
+commit 19ccdf696c3b96459495fadbef56a6c607e87583
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sat Mar 3 14:57:57 2012 +0000
+
+    fx2lafw: Removed CMD_SET_SAMPLERATE
+
+commit f6582cd7bf62bc945ecadda09123fde6c3676107
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Thu Mar 1 20:34:20 2012 +0000
+
+    fx2lafw: Implemented initial support for start capture
+
+commit 3f8d59721634e1d69251078c254caef81effc62c
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Thu Mar 1 19:47:47 2012 +0000
+
+    sr: Added device IDs for CWAV USBee AX to udev rules
+
+commit 74fcfb806d5b66ae4372b982f7836be12328e664
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Thu Mar 1 19:45:08 2012 +0000
+
+    fx2lafw: Devices now retain the same PID/VID after fw load
+
+commit e318664793525543f7001371aee8cad79102266d
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Wed Feb 29 22:47:05 2012 +0000
+
+    fx2lafw: Implemented SR_HWCAP_PROBECONFIG and SR_HWCAP_LIMIT_SAMPLES
+
+commit c8f2c9dda4027fe723aabccb4265629c374afcd9
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sun Mar 4 14:34:16 2012 +0000
+
+    fx2lafw: Fixed a compiler error, and made cv_data consistent with saleae-logic.c
+
+commit 0abee5076fd7751bd77d0fee940d617a1a40ea34
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Mar 4 15:08:11 2012 +0100
+
+    sr: Fix some TODOs, improve comments/docs.
+
+commit b5118d6c013c4b5ae7ae146166750b3e392c4a14
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Mar 3 14:13:21 2012 +0100
+
+    sr/srd: s/handler/callback/.
+    
+    We should consistently use the same name for the same thing.
+
+commit 3cd3a20b350ed1e86675aee067f60ac5a2f576b1
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Mar 3 09:56:49 2012 +0100
+
+    sr: More callback param renames.
+    
+    Start/stop acquisition callbacks: Consistently name the 'void *' parameter
+    cb_data for now. The per-device-instance device pointer is called
+    'session_dev_id' everywhere for now, but this should be renamed to
+    something more clear.
+
+commit 1f9813eb6cf2fa3b6511af46b19270feb9484c1e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Feb 29 22:32:34 2012 +0100
+
+    sr: Name all callback data 'cb_data'.
+
+commit 31ccebc4925d245fed02545415ce3ee14055d897
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Feb 29 22:08:45 2012 +0100
+
+    sr: s/sr_session_bus/sr_session_send/.
+
+commit d08490aabaa66b547c8299b757f62ff5319dbf0b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Feb 29 21:56:24 2012 +0100
+
+    sr/srd: Consistency fixes for callbacks.
+    
+     - Callback function pointer typedefs end with _t.
+    
+     - Variables holding callback functions are named 'cb' everywhere.
+
+commit cfe064d8e74d86ab6a65779663ca1fb82e36260a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Feb 29 19:56:15 2012 +0100
+
+    sr/cli/gtk/qt: s/hw/driver/ in some places.
+
+commit c496ac97a83aa33dd2add8074c454b7dc1b08fe6
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Feb 29 19:32:39 2012 +0100
+
+    sr: sr_hw_has_hwcap(): More docs, error checks.
+
+commit 2f8cf274094b945bc2e4d51fefb0408867b39cac
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Feb 29 19:17:36 2012 +0100
+
+    sr: s/sr_dev_probe_name/sr_dev_probe_name_set/.
+
+commit 7b8ca864a00010d64172820bb82b30cb5f2d0009
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Feb 29 19:11:09 2012 +0100
+
+    sr: datastore: More error checks.
+
+commit c30b417f719e20f9f1d29fd8fa72c24278af3a0c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Feb 28 23:53:17 2012 +0100
+
+    sr: Rename hwplugin.c to hwdriver.c.
+
+commit c09f0b578c0e9c03590cb814f66004bb3f6815ff
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Feb 28 23:52:30 2012 +0100
+
+    sr/cli/gtk/qt/: s/plugin/driver/.
+
+commit 2285cf9bc519edb88eccbe3bf2ddd6888e54cdf2
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Feb 28 17:47:02 2012 +0100
+
+    sr: code cleanup
+
+commit d261dbbfcc7317f2fd9aa9c08473dc4a7b6b2b30
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Feb 28 01:09:29 2012 +0100
+
+    sr: Fix/document probe names.
+
+commit 6c39d99a2809c0065b8bd547c426a08f42445e92
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Feb 27 23:55:06 2012 +0100
+
+    sr: fx2lafw: Consistent #include guard naming.
+
+commit f9a69557d276ee27d551eb9ef68f2700324613b4
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Feb 27 23:53:44 2012 +0100
+
+    sr: fx2lafw: Use gboolean consistenly.
+
+commit 772a0e615397b63f5d5c9af1d25475e9e5dbe76b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Feb 27 23:40:38 2012 +0100
+
+    fx2lafw: Small consistency fixes.
+
+commit be4b99e897827b46c396a8c83cee0ce1c19d3afe
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Feb 27 23:26:05 2012 +0100
+
+    fx2lafw: Compile fix.
+
+commit 5da939028db118a2e1445184b8d8406ecdcc9850
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Mon Feb 27 19:34:24 2012 +0000
+
+    fx2lafw: Implemented hw_dev_acquisition_stop
+
+commit 610dbb70914da9be34d9ac3f0c90a50356275277
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Mon Feb 27 19:32:58 2012 +0000
+
+    fx2lafw: Implemented hw_dev_acquisition_start
+
+commit 7cb621d418281f64144048e6257055b1b25b5da9
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Mon Feb 27 19:21:08 2012 +0000
+
+    fx2lafw: Basic implementation of hw_dev_config_set with SR_HWCAP_LIMIT_SAMPLES
+
+commit 62bc70e412e073580576fe8fda7c7bc7c9e2e30e
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Mon Feb 27 19:02:52 2012 +0000
+
+    fx2lafw: Added more to hw_cleanup
+
+commit f1898235e85c884cca985e797848930a6b52139a
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Mon Feb 27 19:00:22 2012 +0000
+
+    fx2lafw: Implemented hw_dev_close
+
+commit 43125c69937d1599985c281de956f630c00525d6
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sun Feb 26 12:39:40 2012 +0000
+
+    fx2lafw: Implemented hw_dev_open
+
+commit 7f6a3b43ad9e26a2928672927960bcc02a2c7510
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sun Feb 26 12:18:05 2012 +0000
+
+    sr: Moved GTV_TO_MSEC to sigrok-internal.h
+
+commit b1eeb67e926ddaddc11e8a509692fdcaf3e2226e
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sat Feb 25 11:58:55 2012 +0000
+
+    fx2lafw: Implemented firmware upload
+
+commit cdfdd71101b04f13663b19b0ceffcdf63628dc36
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Mon Feb 27 19:42:08 2012 +0000
+
+    fx2lafw: Renamed fx2lafw_dev to ctx in hw_dev_info_get
+
+commit 90282c82bce6cb108be2123d2393ce058c7aefdd
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Mon Feb 27 19:41:10 2012 +0000
+
+    fx2lafw: Renamed fx2lafw_dev to ctx in hw_init
+
+commit cac0bbaafd0813bfdbfef1c7e235c5c886618354
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Mon Feb 27 20:50:00 2012 +0000
+
+    fx2lafw: Renamed dev_insts variable in hw_init
+
+commit c69e35a7147ca0c1554c8ba13a9210fafb6f9796
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Feb 27 22:27:33 2012 +0100
+
+    sr: sr_samplerate_string: Allow 3.15Hz etc. as output.
+    
+    This is required for some hardware, e.g. ChronoVu LA8, where
+    33.333333 MHz or 2.439024 MHz are valid samplerates. This is because the
+    hardware takes a sampleperiod (in nanoseconds) as input, not a
+    samplerate (in Hz).
+
+commit aae2fed675fc63aae58569a03c71201dc449344b
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sat Feb 11 17:41:22 2012 +0000
+
+    fx2lafw: Implemented hw_get_status
+
+commit 8b35f474832e486116d72a76657fc75e95d4db3c
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sat Feb 11 17:39:39 2012 +0000
+
+    fx2lafw: Exposed capabilities data
+
+commit 187b358232aa90de8ee12df915506f839a98f2ad
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sat Feb 11 16:08:47 2012 +0000
+
+    fx2lafw: Added probing for fx2lafw devices
+
+commit f302a082567d10f90cd20fca5a7abd68d7267d96
+Author: Joel Holdsworth <joel at airwebreathe.org.uk>
+Date:   Sat Feb 11 12:08:49 2012 +0000
+
+    fx2lafw: Added empty hardware module for fx2lafw
+
+commit 04254c3f833fd048668507fcd925b290c55664d6
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Feb 23 21:54:07 2012 +0100
+
+    sr: la8: Improve comments and messages a bit.
+
+commit 050e9219d6bca0d6f986dca07fc2c501295c5bde
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Feb 22 21:48:30 2012 +0100
+
+    sr: No need for dynamic hardware driver registration.
+    
+    We don't need or allow run-time registration of hardware
+    drivers/plugins, they're added at compile-time.
+
+commit 47671b0f26cc6b3e7cf16257f458eadefe623d9f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Feb 22 19:53:27 2012 +0100
+
+    sr: la8: Remove some unneeded checks.
+
+commit ea9cfed7a55260ab97f57150b57c42a28c3a85a7
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Feb 18 18:07:42 2012 +0100
+
+    sr: Consistent ctx name for per-dev-inst context.
+
+commit 6b3dfec8dee898726b7b606cdd230bf8bd73bcbc
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Feb 18 12:17:56 2012 +0100
+
+    sr: Fix incorrectly renamed functions.
+
+commit ee61b340da0bf4f0eb728c375459388c6a7bfd84
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Feb 18 12:16:49 2012 +0100
+
+    sr: Remove unneeded temp. variable use.
+
+commit a9a245b428cb9645d73044f6741818d2499efefc
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Feb 18 12:11:15 2012 +0100
+
+    sr: s/config_set/dev_config_set/.
+    
+    This functions is per-device-instance, so use dev_ as prefix as with
+    the other ones.
+
+commit 69040b7c8ff82aef2ad712b7881492d0fa4c86a8
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Feb 18 12:03:49 2012 +0100
+
+    sr: s/acquisition_*/dev_acquisition_*/.
+    
+    These functions are per-device-instance, so use dev_ as prefix as with
+    the other ones.
+
+commit e7eb703fff0167897f7e094e2edbf7d5798857ea
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Feb 18 11:57:43 2012 +0100
+
+    sr: opendev/closedev -> dev_open/dev_close.
+
+commit 8105505d064ca8cc32799c119c5526fb337a5660
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Feb 18 11:46:51 2012 +0100
+
+    sr: s/st*_acquisition/acquisition_st*/.
+
+commit 5097b0d0912165429aceddb5febbf68467b623f5
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Feb 18 11:41:21 2012 +0100
+
+    sr/cli/gtk/qt: s/get_dev_info/dev_info_get/.
+
+commit a7d05fcb388f142012035a0ed31bcf74d42bbe73
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Feb 18 00:31:35 2012 +0100
+
+    sr/cli/gtk/qt: s/configuration/config/.
+
+commit ffedd0bf5d3abb1eae86db68e336285eddf41778
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Feb 18 00:17:18 2012 +0100
+
+    sr/cli/gtk: s/capability/hwcap/.
+
+commit 1d9a8a5fe1458d4b1ecd250161a7962988359350
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Feb 17 23:55:27 2012 +0100
+
+    sr/cli/gtk: A few more s/instance/inst/.
+
+commit bb7ef79377ae617e1275373e0b631beb7f909d73
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Feb 17 22:25:01 2012 +0100
+
+    sr/cli/gtk/qt: s/device/dev/ in many places.
+    
+    Also, a few s/instance/inst/ occurences.
+
+commit d68e2d1a21ac5c3f24d88b7689f98764e4d57c30
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Feb 17 21:02:52 2012 +0100
+
+    sr: Some more s/device_instance/dev_inst/.
+
+commit 44dae539254e324e0330e194f9c775be3d761503
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Feb 17 20:44:19 2012 +0100
+
+    sr: Random cosmetics, fix/amend Doxygen comments.
+
+commit 7b48d6e104fd461b0c12519b70dbd1c6c72824e1
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Feb 17 19:40:01 2012 +0100
+
+    sr: Prefix log messages with subsystem string.
+
+commit 93a04e3be9cdaa276d9e7fe14da053483b567b74
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Feb 15 03:18:48 2012 +0100
+
+    sr: rename all sr_hwplugin(s)_* functions to sr_hw_*
+
+commit 9fc6aa0a566d093b36cdbdad46e0cbdc116ff538
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Feb 14 13:18:17 2012 +0100
+
+    sr: la8: remove debug output when no device is found
+
+commit 341ce41545cab2bda88230c8434f36c64eadd8a1
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Feb 14 12:26:22 2012 +0100
+
+    sr: don't free driver-specific per-device struct in drivers
+    
+    sr_dev_inst_free() takes care of that.
+
+commit da1466d677afadcb17b12ebc1223ab0bdafe21db
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Feb 14 00:23:51 2012 +0100
+
+    sr: rename more functions to sr_thing_action format
+    
+    Also improved the interface to find capabilities in a hardware plugin.
+
+commit d3683c42e74fa61c21fc0f1bf360ae201fc4b1d1
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Feb 13 15:31:59 2012 +0100
+
+    sr: rename all sr_device_instance_* functions to sr_dev_inst_*
+
+commit c532476aa7b9a4afb1f32d5b634348d3e825d6bb
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Feb 13 15:23:16 2012 +0100
+
+    sr: rename hwplugin functions to sr_thing_action format
+
+commit e0c25ac99c64f024e30d84c96e3ec48b44fda8d5
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Feb 13 19:49:09 2012 +0100
+
+    sr: Add missing #include, fixes warning.
+
+commit 57ab7d9f925c0f93ec711c4e6914881e5ff5dfd9
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Feb 12 20:52:42 2012 +0100
+
+    sr: cleanup callback: Return int.
+
+commit 3010f21c9170e9f235d49bc7b333d17677c70e5c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Feb 12 13:31:58 2012 +0100
+
+    sr: stop_acquisition callback: Return int.
+
+commit c73d2ea421c2b425c3f0ae33bce2bfd0c448ca5f
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Feb 13 14:31:51 2012 +0100
+
+    sr: adjust copyright year
+
+commit 031685005b022b98b5b1604cc6226c0cc2b959f8
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Feb 13 14:00:47 2012 +0100
+
+    sr: rename all sr_device_* functions to sr_dev_*
+
+commit a1645fcd81ed4be71d29380218acb078789a6268
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Feb 13 03:36:32 2012 +0100
+
+    sr: more API cleanup and documentation
+
+commit b2ff95063a845ec7130d97fc3d8e9c65fe45f902
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Feb 13 02:16:32 2012 +0100
+
+    sr: whitespace cleanup
+
+commit 996b0c7234c5cc420181b57370f6ba264aee24d2
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Feb 13 02:13:51 2012 +0100
+
+    sr: clean up public/private split in headers
+
+commit 18beaeff948f5730e1ffbc1a50e8b86c7673f084
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Feb 13 00:08:23 2012 +0100
+
+    sr: cleaned up session bus debug helper
+
+commit bb08ee2e534a7fca22cff2f8d963d64441b6d65a
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Feb 12 23:57:43 2012 +0100
+
+    sr: public/private API cleanup in hwplugin
+
+commit 6cfa474a809a56e1ea59f7356570a9fb4b6f2a3e
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Feb 12 22:36:19 2012 +0100
+
+    sr: rm unused sr_device_clear() and sr_device_probe_clear()
+
+commit 040ae8be943b499b5e786e4861ed1109ae4ebcce
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Feb 12 20:43:20 2012 +0100
+
+    sr: sigrok.h is no longer generated
+
+commit 133a37bfba1a7e1423716b2b872d3bb82a2e64d9
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Feb 11 20:06:46 2012 +0100
+
+    Use g_try_malloc/g_free/g_strdup consistently.
+    
+    Avoid plain malloc()/free() in sr/srd, especially in the API calls.
+    Also avoid g_malloc*() in favor of g_try_malloc*().
+    
+    Use g_strdup() instead of strdup() so that we can use g_free()
+    consistently everywhere.
+    
+    Exceptions: Stuff that is allocated via other libs (not using glib),
+    should also be properly free'd using the respective free-ing function
+    (instead of g_free()). Examples: Stuff allocated by libusb, libftdi, etc.
+    
+    Also, use sr_err() instead of sr_warn() for actual errors. sr_warn() is
+    meant for non-fatal/uncritical warnings.
+
+commit cd853ff0b2b0ad2643d65e73159661e1a3c6bc66
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Feb 11 00:39:25 2012 +0100
+
+    sr: chronovu-la8: Add missing <stdlib.h> #include.
+
+commit 8c4b60039390eac40fe24c191e89edfd39eac8b8
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Feb 11 00:38:48 2012 +0100
+
+    sr: asix: Change a free() to g_free() as it should be.
+    
+    This also fixes a compiler warning (on FreeBSD at least).
+
+commit 44b6aafdb748d961547bb80d5b0a0511f35d9702
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Feb 11 00:34:16 2012 +0100
+
+    sr: FreeBSD has zlib, but no pkg-config file for it.
+
+commit bf3f06c9c2a73b7c30862daab1e2731768ba6abc
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Feb 11 00:20:23 2012 +0100
+
+    sr: MinGW/Mac: No libusb_detach_kernel_driver() support.
+
+commit 12f3e8741b5ae651569ca65b94f22a4dc154da7a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Feb 8 22:08:55 2012 +0100
+
+    sr: Doxygen comments for loglevels.
+
+commit 0ae67ff784db96268d4dae4b7ac896a78828746d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Feb 8 22:04:13 2012 +0100
+
+    sr: Implement proper logging framework.
+    
+    This is pretty much identical to the current libsigrokdecode API/framework.
+
+commit d38cd6c1f6f3f23b2f659be2d189f56c7592b805
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Feb 7 23:50:47 2012 +0100
+
+    sr: saleae: Fix typo.
+
+commit 003f9bebf9f97225b08383573544c1ece7239aea
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Feb 7 23:49:51 2012 +0100
+
+    sr: saleae: Support more recent firmwares.
+
+commit c32cc2504b471deab0f511037f843234c726c461
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Feb 6 23:50:22 2012 +0100
+
+    sr: udev file: Add QuantAsylum QA100, Rigol VS5202D.
+
+commit 657832184893c8a5e3b28ebf71109956a4a57246
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Feb 6 22:46:22 2012 +0100
+
+    sr: s/z60_sigrok.rules/z60_libsigrok.rules/.
+
+commit 7c1d391c8b33bf76f7c6617fe9d5174e16a04f95
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Feb 4 10:56:51 2012 +0100
+
+    sr: input/output: Mark more symbols with SR_PRIV.
+
+commit 0f8522bf74af8abfe8601e978b2e0d0e40b1a124
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Feb 4 10:41:30 2012 +0100
+
+    Project-wide consistent naming for #include guards.
+    
+    Document the naming scheme in HACKING.
+
+commit 5c64390e5ac8a0052d8b7eeb49c781d86027c814
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Feb 4 10:10:43 2012 +0100
+
+    sr/cli/gtk: Remove analog left-overs from API.
+    
+    This will come back in some form or another later, but for now
+    don't clutter the API with non-working stuff. Removing stuff from APIs
+    is not possible without breaking the API, adding stuff later is simpler.
+
+commit e7ee300a12391640ff499eaa4d54089fe7e825f2
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Feb 5 13:37:02 2012 +0100
+
+    sr: zeroplus: Drop unused global variable.
+
+commit 3d2efd7d15f1e35b4080c4632dd94376ae824fa2
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Feb 5 13:36:03 2012 +0100
+
+    sr: Compile fix for Windows/MinGW.
+
+commit dff75c0df1be07db2e63ef242e843c925779bddb
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Feb 5 12:54:44 2012 +0100
+
+    autogen.sh: aclocal support for Windows XP/Vista/7.
+
+commit ca070ed9a0237e5cea10e5dd974e06da62de890d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Feb 2 21:15:04 2012 +0100
+
+    sr: Make more symbols private via static/SR_PRIV.
+    
+    Additional zeroplus fixes:
+    
+     - Remove unneeded function prototypes from .h files.
+    
+     - Remove unused variables and/or use standard libusb #defines instead.
+    
+     - Remove unused GL_* error code #defines.
+
+commit 185ae2c5c9ada0353b43e3736e838bbc8e370cb4
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Feb 2 21:08:33 2012 +0100
+
+    sr: zeroplus: Remove unused gl_open()/gl_close().
+    
+    Merge the missing function calls into zeroplus.c's init functions.
+
+commit 1a081ca67d63a0bd933a3d715792d85afd437296
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Feb 1 23:40:35 2012 +0100
+
+    sr: Mark API functions with SR_API/SR_PRIV.
+    
+    Use SR_API to mark public API symbols, and SR_PRIV for private symbols.
+    
+    Variables and functions marked 'static' are private already and don't
+    need SR_PRIV. However, functions which are not static (because they need
+    to be used in other libsigrok-internal files) but are also not meant to
+    be part of the public libsigrok API, must use SR_PRIV.
+    
+    This uses the 'visibility' feature of gcc (requires gcc >= 4.0).
+    
+    Details: http://gcc.gnu.org/wiki/Visibility
+
+commit 0146970797e809555b2feea9fdbc3933f9e24e8b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Feb 1 02:59:41 2012 +0100
+
+    sr: remove unused time/duration fields from datafeed packets
+
+commit 69890f7399f086c38670961dc72166f00de89af6
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Jan 29 23:06:10 2012 +0100
+
+    sr: Eliminate usb/serial instances from API.
+    
+    The API should be generic and only provide sr_device_instance_new() and
+    friends, but not sr_usb_device_instance_new(), sr_serial_device_instance_new(),
+    or others for other device types we may have in the future. The
+    frontends shouldn't have to know or care about this implementation detail.
+    
+    This also fixes the problem that parts of sigrok.h contained
+    '#ifdef HAVE_LIBUSB_1_0' and such, which is even less desirable for the API.
+    
+    The usb/serial instance specifics are now private, and each driver that
+    needs them keeps a pointer in its driver-specific context.
+
+commit c31e9ef49b84b61a353168956882140e2b5a93bb
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jan 31 01:54:08 2012 +0100
+
+    sr: zp: Add missing <string.h> #include.
+
+commit fd9836bfab434ed227b685d184e266d3cbc4f6c8
+Author: Anatoly Sokolov <aesok at post.ru>
+Date:   Sun Jan 29 16:56:06 2012 +0400
+
+    Add sr_device_get_info
+
+commit bf43ea2317d35a3bc774a9c7e1cf6ff9b6204736
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Jan 29 19:14:25 2012 +0100
+
+    sr: zeroplus: Use device-specific context.
+    
+    Make the zeroplus driver use a "struct zp" with per-device-instance
+    data (such as samplerate, trigger settings, and so on), like the other
+    drivers do.
+    
+    Also, add a few more error checks.
+
+commit ae32d7d759f5722f9d82a2da8ec4bbdebcfd029b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Jan 29 12:47:53 2012 +0100
+
+    sr: la8: Fix typo.
+
+commit 73017cf914b014ff3366de981035ca23ac72a0be
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 28 23:29:28 2012 +0100
+
+    sr: zeroplus: Fix a segfault.
+
+commit ef7228ba49ddaced0f1972a4788ff2fdb8dcd57d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 28 21:26:56 2012 +0100
+
+    Update/enforce/document our build requirements.
+
+commit fb93625d1afbe0bc2648b550102c100949066fbd
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 28 19:42:04 2012 +0100
+
+    sr: sigrok.h.in: Set SR_HWCAP_DUMMY to 0 explicitly.
+
+commit 660ef7d730969a401b3d64dc624138567dbbdb7a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 28 19:40:05 2012 +0100
+
+    sr: sigrok.h.in: Drop obsolete 'GSList *analyzers'.
+
+commit a4cfb10f7fcb5dd5c7df403bff0787bb6b1c1949
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 28 19:23:09 2012 +0100
+
+    sr: Drop analog left-overs from sigrok.h.
+    
+    For now, there's no analog/scope support in sigrok yet (will be added
+    later), so remove any such items from the public API (sigrok.h).
+    
+    Having '#if defined(HAVE_LA_ALSA)' in sigrok.h is a bug anyway, the API
+    must not have anything device-dependent in general, and sigrok.h
+    specifically must not have any #ifdefs for specific hardware.
+
+commit a141db8c4acb98c01dbc0a73f82111ee56f1050a
+Author: Anatoly Sokolov <aesok at post.ru>
+Date:   Sat Jan 21 18:34:11 2012 +0400
+
+    add SR_HWCAP_DEMO_DEVICE capability
+
+commit f020a99773d1431ee58090e9515dc19b10e7463f
+Author: Renato Caldas <rmsc at fe.up.pt>
+Date:   Thu Jan 12 11:50:50 2012 +0000
+
+    link-mso19: Fixed led toggling (the bit masking was not being proprly done).
+
+commit e084a8042ea0bccb306e39725de73546138e1adf
+Author: Renato Caldas <rmsc at fe.up.pt>
+Date:   Wed Jan 18 16:03:39 2012 +0000
+
+    link-mso19: Prevent double free errors when freeing sdi->priv.
+
+commit 357285a944b514bb4498f16b6318829516e33e1a
+Author: Renato Caldas <rmsc at fe.up.pt>
+Date:   Wed Jan 18 12:09:36 2012 +0000
+
+    link-mso19: Add debug messages.
+
+commit a29360733d32e8479147178774d6a72e62f4e56c
+Author: Renato Caldas <rmsc at fe.up.pt>
+Date:   Tue Jan 17 13:41:38 2012 +0000
+
+    link-mso19: Properly initialize the protocol trigger block
+
+commit a84671913ef320d10607f9c8aabaf6bc3563099b
+Author: Renato Caldas <rmsc at fe.up.pt>
+Date:   Tue Jan 17 13:16:41 2012 +0000
+
+    link-mso19: Added new register definitions and renamed variables to reflect new findings.
+
+commit 80aa5f23d1225776a7db0fc6faa763bb5c141dcf
+Author: Renato Caldas <rmsc at fe.up.pt>
+Date:   Sat Jan 14 12:46:27 2012 +0000
+
+    link-mso19: Added struct definitions for the pattern generator config and the protocol trigger config.
+
+commit 66410a8617185da7abf4ca21da99e934b22351bb
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Jan 19 00:32:02 2012 +0100
+
+    sr: g_free()/g_string_free() can handle NULL input.
+
+commit af1c793dfe27b622a48dd213c4d42bc012e81965
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jan 15 23:14:45 2012 +0100
+
+    clean up some dead code
+
+commit 8f81fe87287eba2113c3db9d2f894314b70afd19
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jan 10 22:16:41 2012 +0100
+
+    sr: s/g_message/sr_dbg/.
+    
+    libsigrok should only use sr_*() for debug output.
+
+commit 8c76be539e8098c08f69f56053077211001ed52b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jan 8 22:05:00 2012 +0100
+
+    clean up drivers at the end of a session, and fix session file init.
+
+commit e0508e67998b6b2b5cdd65b4b094b50c07386385
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 7 17:08:54 2012 +0100
+
+    sr: session: Make most functions return int.
+    
+    This allows us to return error codes etc.
+    
+    Add a little more error handling.
+
+commit b3b21462914d6ed89c85f3da27d46744b863f800
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 7 14:15:10 2012 +0100
+
+    More .gitignore files cleanup.
+
+commit db4b455beeeb4ad632b4e394402b83a4305a40fc
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Jan 7 02:13:05 2012 +0100
+
+    remove obsolete libsigrokdecode struct
+
+commit 8ff6afc95d2a9213b8a583e88e9e1b4eb59aad17
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Jan 6 16:20:28 2012 +0100
+
+    sr: Consistently use 512kB as default chunk size.
+
+commit 1190dcf713a458d99c612f8f41c2d28e666aabfb
+Author: Renato Caldas <rmsc at fe.up.pt>
+Date:   Fri Jan 6 11:07:37 2012 +0000
+
+    Added "autostuff" to the .gitignore.
+
+commit 446a037205a7488b424bde90d1b633f00640ef12
+Author: Renato Caldas <rmsc at fe.up.pt>
+Date:   Fri Jan 6 00:04:29 2012 +0000
+
+    session: Fixed error reporting.
+
+commit 42eb54fb62b84adb5aaa4bf9144752e46ade54ea
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Jan 6 01:05:55 2012 +0100
+
+    mso-19: Fix whitespace.
+
+commit d88b9393241e250590333326a4f8d19b53b4bdc6
+Author: Renato Caldas <rmsc at fe.up.pt>
+Date:   Thu Jan 5 23:37:54 2012 +0000
+
+    link-mso19: fixed segmentation fault.
+
+commit e42ef08dba163e8c9ef933347732d9e8c58ab399
+Author: Renato Caldas <rmsc at fe.up.pt>
+Date:   Thu Jan 5 19:42:06 2012 +0000
+
+    link-mso19: Updated to the current structs (fixed compilation).
+
+commit 0c8dc7b4160c47a21925e22da7c1be73e4c3a39a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Jan 4 16:45:53 2012 +0100
+
+    udev: Add missing USB IDs for some devices.
+
+commit 8e43129c10669d767d7eb17e786f38b70d799e60
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Jan 4 15:26:41 2012 +0100
+
+    A few more fixes for configure.ac files.
+    
+    Add missing checks and quotes, remove superfluous checks, etc.
+
+commit dd8b5f565f60d536104b30bee8aadf4ea333aa7c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Jan 4 02:50:26 2012 +0100
+
+    sr/srd: Add Doxyfile to the tarball.
+
+commit 4abf8dd0a540db8c8f5af5e6bd78c6eb7b473d9f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Jan 4 02:41:33 2012 +0100
+
+    srd: Show config summary, libs, and Python info.
+
+commit 45aed0721c687a29bb394bff10cc129dab0f11c2
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Jan 4 00:49:21 2012 +0100
+
+    sr: configure.ac: Print more summary info.
+    
+     - Package version (major.minor.micro)
+    
+     - Library version (current:revision:age)
+    
+     - Installation prefix (usually /usr/local)
+    
+     - Detected libraries and their versions (only for pkg-config libs)
+
+commit 3af71f0da646de1e61ccbed2e85e3fca9798565c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Jan 4 00:05:43 2012 +0100
+
+    sr: configure.ac: Fix version number magic.
+
+commit d8521c939f19b08cb991df7d0731fa358381d61c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jan 3 21:55:48 2012 +0100
+
+    Put most autotools files into autostuff/.
+    
+    This yields a slightly more "tidy" top-level directory.
+
+commit 8e190238d7b33ebb9f1baa2a28a37ffd041f7334
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jan 3 20:06:36 2012 +0100
+
+    sr: Put files into .../share/libsigrok.
+
+commit 0da5b6a9f5a119ab485ed3dba08aeb4a3ad2c8f4
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jan 3 20:01:02 2012 +0100
+
+    sr: Remove useless filename prefixes.
+
+commit cd315a80d87a24a19a7846497d74c5ca85d494a0
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jan 3 19:56:01 2012 +0100
+
+    sr/srd: Fix left-over #includes.
+    
+    The libs themselves should use #include "sigrok.h" etc., while the
+    frontends must use #include <sigrok.h> and so on.
+
+commit 3b7c8f54fcf4c6de1ec67d11a9ec8975a2ddbb57
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Jan 2 14:25:52 2012 +0100
+
+    sr: Drop some obsolete and commented out code.
+
+commit 9f45fb3aea9aa628ec2323bac8f2c354f5f3983c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Jan 2 14:15:25 2012 +0100
+
+    sr: session: Add docs and some error checks.
+
+commit 13177edbdf23200001fcc141f61419beb93962b6
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Dec 30 22:38:25 2011 +0100
+
+    Split README, add appropriate ones per-project.
+
+commit f928befdadd7b9a50ded5fe730a0aeec06b1ed09
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Dec 30 22:12:37 2011 +0100
+
+    Update/fix .gitignore files.
+
+commit db8ae7b941a31b2bc64e14d60a1e962fd2b2dc38
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Dec 30 10:50:00 2011 +0100
+
+    sr/srd: Remove/fix non-applicable autotools stuff.
+
+commit 826938d81e2e5bf592fbed82523081fcb7fdf85e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Dec 30 10:42:39 2011 +0100
+
+    sr/srd: Move some files to their resp. dirs.
+
+commit 5e59cfbfc736aab9e79caef4ab6bdcbc500e254f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Dec 29 13:05:24 2011 +0100
+
+    Move most contrib/ stuff to libsigrok.
+    
+    The udev rules file is libsigrok-specific, the gnuplot files too.
+    
+    The nsis files stay in the top-level contrib/ for now, they're not
+    really part of any of the (sub-)projects, but rather are used to create
+    a single Windows .exe installer for all of them.
+
+commit c37d2b1ba12b62d63590509879bf58adf842896d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Dec 29 19:50:14 2011 +0100
+
+    probe names: Fix cosmetics, add docs, fix off-by-one.
+
+commit 464d12c72aa8d83acccccbbc0bc755fbb9d542c0
+Author: Kristoffer Sjöberg <ksjoberg at q1.se>
+Date:   Thu Dec 29 17:04:31 2011 +0100
+
+    Move the probe naming to the creator of the device, and let each driver name its own probes.
+
+commit 2d83e0f963b39104ba065c61ef22456adcf15a8d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Dec 28 23:11:52 2011 +0100
+
+    Fix outdated ezusb_install_firmware() prototype.
+
+commit b7f09cf86dd57a59dc1bdece2cac9e4a176900b1
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Dec 28 23:07:08 2011 +0100
+
+    libsigrok: Fix #includes.
+    
+    In the lib, we should only #include "sigrok.h" or "sigrok-internal.h",
+    but not the (possibly installed and thus different/older versions) via
+    <sigrok.h> or <sigrok-internal.h>.
+    
+    Frontends should of course use <sigrok.h> and <sigrok-internal.h>.
+
+commit a0ecd83bc6e07ea412db5cd0108d50d89e36df8f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Dec 28 22:55:21 2011 +0100
+
+    Make more variables/functions static and non-global.
+    
+    The 'GSList *devices' from device.c was actually really global (i.e.,
+    listed in sigrok.h), which is now fixed.
+
+commit c5d660ae244babd4afc7863ba23f66d31af6e29e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Dec 28 21:38:56 2011 +0100
+
+    Drop unused 'global' struct/variable.
+    
+    The libs shouldn't have any (externally visible) globals anyway.
+
+commit 155d1012f138fa94980c33a0e42b50ca0922ddce
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Dec 28 21:37:37 2011 +0100
+
+    sigrok-proto.h: Drop obsolete prototype, move other one.
+
+commit 08d4cc1d146478aa9f6032fc65142293df822726
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Dec 28 21:34:37 2011 +0100
+
+    device: Make some parameters const.
+
+commit 0e3b143994797cd4685526b9a739089fe83385cf
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Dec 28 17:16:33 2011 +0100
+
+    device: Change some functions to return int.
+    
+    The callers of these functions are yet to be changed so that they
+    actually check the return values and handle errors appropriately.
+
+commit 94799bc4dc6ab1ba64cdb7f0fb350d63d4fcee66
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Dec 28 16:19:15 2011 +0100
+
+    device: Add Doxygen comments, improve error handling.
+    
+     - Add Doxygen comments for all functions (some TODOs remain).
+    
+     - Check return code of more functions, handle invalid input.
+
+commit cb1e389c72ead8cf6eb440f3194f5056d86069ec
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Dec 15 03:31:31 2011 +0100
+
+    make time/duration work, at least when loading from a session file
+    
+    PD decode() call now takes 3 arguments: timeoffset, duration, data
+    as per the current API specification.
+
+commit 15278f3e9cf4c4a4a6c331e042f9935709343c82
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Dec 25 19:59:15 2011 +0100
+
+    datastore.c: Improve error handling and docs.
+    
+     - Add Doxygen comments for all functions (some TODOs remain).
+    
+     - Check for invalid input parameters (such as NULL pointers etc).
+    
+     - Return SR_ERR_ARG upon invalid input parameters.
+    
+     - Make sr_datastore_put() return int instead of void, so we can pass
+       an error code (SR_OK, SR_ERR_MALLOC, and so on) to the caller.
+
+commit 7a6ec0c376cec9e41a12a876edea34fecaf5c2aa
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Dec 23 15:26:54 2011 +0100
+
+    sr_filter_probes(): Check for too many probes.
+    
+    Return SR_ERR_ARG if the number of enabled probes is higher than the
+    requested unit size supports.
+
+commit 488a13b110d3563194dd63e087e295a4aa114002
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Dec 22 14:10:16 2011 +0100
+
+    Improve sr_filter_probes error handling and docs.
+    
+     - Much more elaborate doxygen comments for the function and its
+       parameters, allowed input values, and so on.
+    
+     - Make 'probelist' const, the function doesn't modify it.
+    
+     - Check for invalid inputs such as NULL pointers.
+    
+     - Use g_try_malloc() and g_free() for the output buffer. Document who
+       is expected to g_free() the buffer.
+
+commit 25a605d187e9661757a1e5d4bd15fac2b533c296
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Dec 4 18:33:29 2011 +0100
+
+    libsigrok: Quickfix for a segfault in ChronoVu LA8.
+
+commit 276585ff209d02ea058f09820881ed536e48e3bb
+Author: Gareth McMullin <gareth at blacksphere.co.nz>
+Date:   Mon Nov 28 21:52:35 2011 +1300
+
+    srd: Pass samplerate to decoder in metadata.
+
+commit f64c14141b0c90fa78cacbc502dd2a41239376fd
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Nov 27 19:31:25 2011 +0100
+
+    fix CLI size string specification
+    
+    accept "hz" as optional qualifier but nothing else
+    properly return an error instead of quietly returning zero size
+
+commit cb93f8a927e6fb2cb1d89176766c5c9c398db5c3
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Nov 24 22:57:48 2011 +0100
+
+    Other method to avoid "unused var" compiler warnings.
+    
+    The '(void)varname' method is nicer than 'varname = varname' and also
+    prevents warnings when compiling sigrok with clang instead of gcc.
+
+commit cc8a7d250cf7daff452ce376224c9853529204ca
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Nov 24 22:42:02 2011 +0100
+
+    Add missing #includes to avoid clang warnings.
+
+commit e7bad06355ea218d83e6df1d1137e67a58513b35
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Nov 20 03:16:33 2011 +0100
+
+    la8: device not found during init() scan is not an error
+    
+    fix some hardware plugin semantics
+
+commit e48846b1d211ce88e5ad427c034e0a2fb43bbe37
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Nov 19 16:19:24 2011 +0100
+
+    libsigrok: glib-2.0 is a hard requirement.
+
+commit 4d436e71ba6059b217a3d90775033e850944ad42
+Author: Gareth McMullin <gareth at blacksphere.co.nz>
+Date:   Sat Nov 19 13:41:41 2011 +1300
+
+    Changed SR_T_NULL to SR_T_BOOL and adjusted RLE option.
+
+commit 6bb5c5fadfe011ae7797138fb9e9ade32edb0caf
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Nov 17 23:00:33 2011 +0100
+
+    Consistently use __func__ instead of __FUNCTION__.
+    
+    The __func__ form is standardized and more portable.
+
+commit a562c3a2e5e54dbb7e0553422ac0e0c845b180ad
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Nov 17 22:54:17 2011 +0100
+
+    libsigrok: Use sr_err() et al instead of printf.
+
+commit 805e9640ff4a28dc470afb0b4f3b02aece44179b
+Author: Gareth McMullin <gareth at blacksphere.co.nz>
+Date:   Thu Nov 17 21:18:46 2011 +1300
+
+    Fixed a crash when loading a second session file.
+
+commit 48ca6b54b0a5e7b0cd5f34fa4066523a1a3cc3a3
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Nov 15 22:46:57 2011 +0100
+
+    sigrok.h: Remove SIGROK_*VERSION #defines again.
+    
+    These version numbers represent the sigrok version (i.e., the version
+    of the tarball, such as "sigrok-0.2.0.tar.gz"), but _not_ the libsigrok
+    (libtool) library/API/ABI versions. Thus, they should not be in
+    libsigrok's include file (sigrok.h).
+
+commit 719c5a934c7705466a449854b876b9962eb4cb5e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Nov 15 21:05:40 2011 +0100
+
+    Fix some compiler warnings.
+
+commit 300007323ec5963e211b75d2e0d957721dea35fa
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Nov 15 01:11:27 2011 +0100
+
+    libsigrok.pc: Add Required.private field entries.
+    
+    The "Required.private:" field in pkg-config .pc files is used for
+    declaring that we need the listed libs (pkg-config packages) for
+    static linking, but not for dynamic linking.
+    I.e., the "Required.private:" field should be used for libs which we
+    use internally in libsigrok, but which we do not "expose" ourselves.
+    
+    For now all libs are listed as "Required.private:" instead of
+    "Required:", but this may not be entirely correct and needs to be
+    checked carefully at some later date.
+
+commit 5c582d9f61fa7dad2a5cf07e1f464b6b6ffb1e28
+Author: Gareth McMullin <gareth at blacksphere.co.nz>
+Date:   Sun Nov 6 11:44:25 2011 +1300
+
+    Remove IO source if callback returns FALSE.
+
+commit 52f28f821f8923f52fce5b76909c00015231e299
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Apr 29 19:27:32 2011 +0200
+
+    sigrok.h: Add SIGROK_{MAJOR,MINOR,MICRO,}_VERSION #defines.
+
+commit 7583b99dbb2310ce2e34fd435c42634dec940ad6
+Author: Gareth McMullin <gareth at blacksphere.co.nz>
+Date:   Sun Oct 30 14:25:24 2011 +1300
+
+    OLS: Calculate actual sample rate used.
+
+commit baf1d71477ea5c1dea449bc9ce72b39d02751934
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Oct 30 02:10:32 2011 +0200
+
+    ols: Minor whitespace and coding style fixes.
+
+commit 3a4d09c0de68c3ae9f287d243967431b8e3de0b7
+Author: Gareth McMullin <gareth at blacksphere.co.nz>
+Date:   Sat Oct 29 15:57:17 2011 +1300
+
+    Run-Length Encoding support for the OLS.
+
+commit 221304219ef861c14a44017eb025631bbd2fa05c
+Author: Gareth McMullin <gareth at blacksphere.co.nz>
+Date:   Sat Oct 29 15:21:16 2011 +1300
+
+    Prevent reading past end of OLS hardware buffer.
+
+commit 9a751023136a058dadf008a4ff983351947cc0df
+Author: Jerry <jerry at xor-gate.org>
+Date:   Mon Jun 20 23:43:44 2011 +0200
+
+    Mac OS X build fixes
+
+commit a634574eae69c9e712d5dbec8b97809840876c5f
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jun 20 11:43:34 2011 +0200
+
+    saleae-logic: fix timing on packets when triggering is used
+
+commit 7d2afd6c954e4b1507b494c5c0d469c2ecf59cb2
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jun 20 11:42:43 2011 +0200
+
+    better session bus logging
+
+commit 9c939c5132d82575cc1ce8f8fef5b6c4289aec5b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jun 19 14:28:50 2011 +0200
+
+    use new datafeed packet format
+
+commit 38ab3ee79db2a08dd1f01fff08b7474093a48ce5
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jun 19 02:35:23 2011 +0200
+
+    new datafeed packet format
+    
+    struct sr_datafeed_packet now has timeoffset and duration fields,
+    expressed in picoseconds (1/10^12 seconds)
+    length and unitsize are now in a separate struct sr_datafeed_logic
+
+commit 60eb1eb5820be30671729c08b371b0ab3c14c860
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jun 19 00:55:36 2011 +0200
+
+    fix parameter type
+
+commit 8e49cebd10a1f34e9d5cdafeebc4c59a5c3c563c
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jun 12 18:07:15 2011 +0200
+
+    whitespace
+
+commit 6d754b6d3a8f843cd5254617674f484cac9b12db
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jun 12 18:04:19 2011 +0200
+
+    support for multiple FX2 devices
+
+commit e53c830f33d08633db4eb560f08d2518ff26ad9e
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jun 5 02:08:08 2011 +0200
+
+    saleae-logic: use new logging system
+
+commit e10d6e32e4d8766e12b752da6d1806944b0ee85e
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Jun 4 23:20:00 2011 +0200
+
+    saleae-logic: support for other FX2 devices (bare FX2)
+    
+    This enables support for devices that have a different VID/PID
+    than the Saleae Logic, and yet another after firmware upload.
+    
+    After firmware upload is checked every 100ms whether it came back,
+    instead of always waiting for 2 seconds.
+    
+    If the kernel attaches a driver to a device we know, detact it first.
+
+commit 8722c31e26ecebfc75035a566d4d72d07761ef14
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Apr 4 05:13:29 2011 +0200
+
+    better cleanup of device/plugin resources
+
+commit 896a19fd65790093b60ece2d1bdd36caba74eaf8
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon May 9 00:59:41 2011 +0200
+
+    LA8: Remove trailing whitespace.
+
+commit d1175d5f7e184dff420038a801113f1d3c8a6ee8
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon May 9 00:54:59 2011 +0200
+
+    LA8: Use sr_spew() where appropriate.
+
+commit f36cbf60cbd43be46ede083265549068db21f4b6
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon May 9 00:52:55 2011 +0200
+
+    LA8: Improve trigger support and debug output.
+
+commit 06dd80d424a511736e0c61492bd618a5c3e65cff
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun May 8 20:26:22 2011 +0200
+
+    Add sr_spew/SR_LOG_SPEW for even more debug output.
+    
+    This is meant for really extensive debug output which can slow down
+    operation significantly and should thus only be enabled if really needed.
+
+commit a76983fd207554de93adabfd33d2abf8d0f3662a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun May 8 20:20:26 2011 +0200
+
+    LA8: Eliminate magic numbers.
+
+commit 4d7b525ae9c0a85097280e77b9c158e9c4c8c6e5
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun May 8 20:09:22 2011 +0200
+
+    LA8: Add trigger point support.
+    
+    Report trigger point/position via SR_DF_TRIGGER packet.
+
+commit 5a9660dd4e4977b9c3a86fe895e0b714e64a44a1
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 6 20:38:48 2011 +0200
+
+    demo: Use memset(), might be faster.
+
+commit c03ed397330b031fa5f63a5dd548e05c2c2d6923
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 6 20:34:12 2011 +0200
+
+    demo: Add all-low/all-high pattern support.
+    
+    Also, improve error handling a bit.
+
+commit c8f4624d9b265f63bc880df28bd9b1a7e29f1488
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu May 5 13:02:48 2011 +0200
+
+    demo: s/genmode/pattern/.
+
+commit 0d31276b05643407ba4a4a9e3f0f95e259c8baa2
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 4 22:37:12 2011 +0200
+
+    demo: Rename GENMODE_DEFAULT to GENMODE_SIGROK.
+    
+    Also, add (Doxygen) comments for the currently supported patterns that
+    the demo device/driver can generate.
+
+commit e88dadd77cd9fcb4fc0e85eeb6c41155847529ad
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 4 22:26:55 2011 +0200
+
+    Improve (Doxygen) comments for HWCAP entries.
+
+commit 68c12597efda33a30b6152cbac4b805604f3e671
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 4 20:05:33 2011 +0200
+
+    demo: Eliminate unneeded tmp_u64.
+
+commit d3b1b51cbef3edfeefbc5b9edfdd8423c6d5e8e0
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 4 19:46:33 2011 +0200
+
+    LA8: Free memory from g_*alloc*() via g_freee().
+
+commit 340cfac0f0629aa3ee84a0a4db53381d04079fe3
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 4 19:44:25 2011 +0200
+
+    log messages: Use device name, not vendor name.
+    
+    There can be multiple devices from the same vendor, obviously.
+
+commit 697785d1aedc0bf385ea21074d83d61b11d8ce29
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 4 19:34:12 2011 +0200
+
+    libsigrok: closedev() now has a return code.
+    
+    This is useful to allow frontends to react upon close failures in a
+    way they see fit (e.g. a popup in the GUI, or error message in the CLI).
+    They can also still ignore the error if they want, of course.
+
+commit 1352eeddd4d164b58f2233ae109432b73faab539
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 4 19:03:01 2011 +0200
+
+    libsigrok/cli: Implement loglevel support.
+    
+    libsigrok can now be told at which loglevel to work, i.e., how many
+    debug/error/warning output to generate. You can also query the current
+    loglevel.
+    
+    In sigrok-cli it is now possible to set the loglevel via -l. For example:
+    
+     - Disable all output: sigrok-cli -l 0
+     - Only show errors: sigrok-cli -l 1
+     - Show errors, warnings, info, and debug messages: sigrok-cli -l 4
+
+commit 548b08e55cf05aeb8f57b26b29035c3fb153f0f5
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue May 3 19:18:43 2011 +0200
+
+    Drop unneeded skeleton files.
+    
+    They're not too useful as they mostly consist of a list of function names,
+    and that list is already available in the respective struct. The wiki
+    API docs and the code in the various hardware/output drivers serve as
+    useful examples already, no need for additional files.
+
+commit 86f5e3d826fc9059e110f07221cb1a30652ceac2
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue May 3 19:15:54 2011 +0200
+
+    libsigrok: Rename open/close to opendev/closedev.
+
+commit 6f42226475bea46cebd348c1c7556cf9a6fce118
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon May 2 01:40:16 2011 +0200
+
+    demo: Add some more debug output.
+
+commit 02604ed6def368edd782bae3c43c7de86111691e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 26 23:56:00 2011 +0200
+
+    Initial support for CSV as output format.
+
+commit f38bdf5678d35a1493c17a5c260fc1120d93bd93
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 26 17:27:34 2011 +0200
+
+    Change left-over SIGROK_* to SR_*.
+
+commit 4362438f1e2da14d04678327c403f9d75c4c0a48
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Apr 25 00:16:47 2011 +0200
+
+    LA8: Shrink mangled_buf from 8MB to 4KB.
+    
+    It's not necessary to have an 8MB buffer. Also, make it static, don't
+    use malloc() here.
+
+commit da0918aae0d43ab25cb72ddf8773831f0364ebdb
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Apr 24 22:53:27 2011 +0200
+
+    ASIX: Small consistency fixes.
+
+commit 4bc5fd4568350e3d4025ea72158a8a611650a912
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Apr 24 22:50:04 2011 +0200
+
+    LA8: Eliminate unused num_probes variable.
+
+commit 309397702f747ea6326492d841a31fddd2d76a9f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Apr 24 22:48:45 2011 +0200
+
+    LA8: Replace some sr_warn() with sr_err().
+
+commit ecaf59db8d79286b69a489273f4262901c0588f8
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Apr 17 10:11:52 2011 +0200
+
+    LA8: probeconfig/trigger support.
+    
+    This should make proper trigger support work for ChronoVu LA8.
+
+commit 4af22da5950cf490f2300199dfacd705e1d220b3
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 19 00:27:29 2011 +0200
+
+    Fix two small warnings.
+
+commit e519ba8645b56f6c9eaaf69d6357a1efa8df501e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 19 00:14:15 2011 +0200
+
+    Hardware drivers: Use names for struct entries.
+
+commit c0a4b9716d32811d9b2320884d3bd0e599feedcf
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Apr 17 14:51:54 2011 +0200
+
+    ols: Always use glib's memory allocation functions.
+
+commit ecad043fd0c05ba307c3730438c1547a5dbe2608
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Apr 17 10:22:10 2011 +0200
+
+    MSO19: Always use glib's memory allocation functions.
+
+commit 27a3a6fe4b767414318c84a08c0cbe2c5a64e4b7
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Apr 16 17:23:04 2011 +0200
+
+    demo: Always use glib's memory allocation functions.
+
+commit c548332c21acc2588114214b38eaa3237fc3f8b3
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Apr 16 16:07:28 2011 +0200
+
+    serial.c: Use g_try_malloc().
+
+commit 12ad53f5a6390e95ea0451ab3bd2c18574294aa3
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Apr 16 16:04:32 2011 +0200
+
+    ASIX Sigma: Improve error handling a bit.
+
+commit 92b3101cfc71581a273e667f185b18be0f0c364f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Apr 16 15:58:26 2011 +0200
+
+    alsa: Always use glib's memory allocation functions.
+
+commit 2e82a17b5ae9d204c57b99db93f1063787f6c3d5
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Apr 16 14:24:58 2011 +0200
+
+    LA8: Always use glib's memory allocation functions.
+
+commit b53738baf76219237e0a6629905981d7a1f2508e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Apr 16 14:17:51 2011 +0200
+
+    Replace g_malloc{0,} with g_try_malloc{0,}.
+    
+    The g_malloc()/g_malloc0() versions exit/segfault if not enough memory
+    is available, which is not a good thing in libsigrok.
+    
+    Instead, we use the g_try_malloc()/g_try_malloc0() variants, which
+    return NULL if not enough memory is available, so that the caller can
+    handle the error properly.
+
+commit 50959ddcdc455c930397fbc9f85c3a745ff45fda
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Apr 15 21:49:22 2011 +0200
+
+    gnuplot output: Optimize by only storing changes.
+    
+    Only output new lines in gnuplot output if there have been changes in
+    the samples (similar to what VCD does). As long as the first and last
+    sample are output, the resulting plot looks OK.
+    
+    This reduces the size of the output file from roughly 200MB to just 60KB
+    in one specific test setup (depends on the number of probes and on the
+    signal, of course). The time and CPU load required to generate the gnuplot
+    output and the resulting plot (PNG or other) is also drastically reduced
+    from multiple minutes to roughly 30 seconds (again, depends on various
+    things).
+    
+    Thanks Ken Mobley of ChronoVu for the report.
+
+commit 15f2d0c0f2e39bc4338b0781b581aced0fca8e0c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Apr 15 20:47:26 2011 +0200
+
+    Don't close/reset the FTDI device too often.
+    
+    Only call la8_close_usb_reset_sequencer() in hw_closedev(), it's not
+    needed in hw_stop_acquisition().
+    
+    Thanks Ken Mobley of ChronoVu for the report.
+
+commit 2f5c8c9696f4a4a8ca7e3c7e6e7d2766a4927026
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Apr 15 20:05:45 2011 +0200
+
+    LA8: free() sample buffers in hw_closedev().
+    
+    Thanks Ken Mobley of ChronoVu for the report.
+
+commit b08024a8363c7a019bebc05a25e2689e774326e8
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Apr 14 09:46:53 2011 +0200
+
+    libsigrok: Introduce sr_dbg/sr_info/sr_warn/sr_err.
+    
+    We should use these (internal) functions in libsigrok exclusively from
+    now on, i.e. no more use of glib's g_debug() etc.
+    
+    These functions are only for libsigrok, the frontends use whatever
+    logging mechanism is suitable there.
+
+commit 83e9d586385097b957774d150a718ebaa7fcc3c9
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Apr 11 00:21:19 2011 +0200
+
+    Add chronovu-la8 input file format support.
+
+commit 8c48f17944a224787aa430b3b3dc5f8709ccb700
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Apr 10 23:33:43 2011 +0200
+
+    Add chronovu-la8 output file format.
+
+commit 20ebd1fe1d9314f421cfdfc925eba6eee498ce80
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Apr 10 16:46:05 2011 +0200
+
+    gnuplot output: More error checks.
+
+commit cdb3573ceba61b02b80f7fc979d166db5b6ff3bc
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Apr 6 21:51:36 2011 +0200
+
+    input/output formats: s/extension/id/.
+    
+    The struct entry 'extension' is not really a (filename) extension, but
+    rather a unique ID used for input or output formats, e.g. in the sigrok
+    CLI or GUI interface. Thus, rename it accordingly.
+
+commit 8703f512a7c0e05f5fc3a5bc36f9e81afee71da3
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Apr 6 20:01:31 2011 +0200
+
+    LA8: Use the new SR_ERR_ARG macro.
+
+commit f7d2982d42e876d8814cba203570a45284c79658
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Apr 6 19:53:31 2011 +0200
+
+    Add SR_ERR_ARG #define.
+    
+    Changing the number of SR_ERR_SAMPLERATE is not a problem ATM, as we
+    never had a public release of libsigrok, i.e. nobody relies on the API yet.
+
+commit 819184ee68f1fda1ebc5b0a5f6aed403ecc27403
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Apr 6 19:51:11 2011 +0200
+
+    Binary output: Add more error checks.
+
+commit d494a4aa9dcbd90126d86757d16fa3e0f0a419f3
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Apr 6 19:42:49 2011 +0200
+
+    input/output formats: Explicit struct member names.
+    
+    This makes it immediately clear what an entry is supposed to be, no
+    need to look it up in some header file.
+
+commit f4314d7e0611917bdc7713dbffe17559490666d6
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Apr 4 19:40:30 2011 +0200
+
+    Add initial support for the ChronoVu LA8.
+
+commit 8a7b47cdfae4a4a95e92958beab41a4985e8f8e3
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Apr 3 23:18:46 2011 +0200
+
+    Revert temporary changes for 0.2 release.
+
+commit 2f3aab0ee9797700238656218208a6ab17a607b3
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Apr 3 22:38:35 2011 +0200
+
+    Disable some stuff which should not be in 0.2.
+    
+    Disable decoders, disable lib building.
+
+commit 847c21bc65343fa1197aa8455012d06a887e6626
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Apr 3 20:15:12 2011 +0200
+
+    Hook up output/text directory with autotools.
+    
+    This is needed for 'make distcheck' to work.
+    
+    Also, add missing text.h to the list of source files.
+
+commit 4fe9a6da79561d82f2c88c39e222ae86c5507900
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Apr 3 06:15:45 2011 +0200
+
+    OLS driver overhaul
+    
+    support for metadata in recent versions of the FPGA code
+    moved constants and structs out to separate header file
+    got rid of all device instance-specific globals
+
+commit f437ea3fe2cada77634eb3a06d34abf680b9c092
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Mar 17 14:53:06 2011 +0100
+
+    small warning fix
+
+commit 4487177c795db2393fd7e4a3c7b46b56345dc8e1
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Feb 14 05:55:01 2011 +0100
+
+    output_ols: disabled cursors don't really need to be listed
+
+commit 82957b65b111437ebe445b7f165719eec2d4e147
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Mar 25 13:44:16 2011 +0100
+
+    ASIX Sigma: Fix firmware loading bug.
+    
+    When no firmware file is found, return the right error code so sigrok
+    doesn't continue running with no firmware loaded.
+    
+    Thanks Martin Stensgård <mastensg at ping.uio.no> for the patch!
+
+commit 8bb416becf64c5095dc7f553a7899fbe9ebc28e0
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Feb 22 23:20:22 2011 +0100
+
+    Kill unused functions (avoid namespace pollution).
+
+commit 120b259ea8f17b74deca3ba4b71e78771539bde8
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Feb 22 23:13:34 2011 +0100
+
+    Drop obsolete vcd_header.
+
+commit d078d2e5f3842b1915ffa9961654f3aa4ed88e17
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Feb 22 23:12:41 2011 +0100
+
+    Make some more items 'static'.
+
+commit 25b4fb85572d0c86d9ccab2a48524f4dd9bef43c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Feb 22 23:01:29 2011 +0100
+
+    Add doxygen comment to sr_filter_probes().
+
+commit cd009d55619181e2fa7e7112f32fe85e4b49cf14
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Feb 22 18:13:32 2011 +0100
+
+    sr_exit(): Return int to be able to report errors.
+
+commit f5a443f27ad0e99f8f0f93867a1f298d7a6a327a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Feb 22 18:08:41 2011 +0100
+
+    Make DATASTORE_CHUNKSIZE private.
+
+commit c91404191e6b31ffe40edd8de469876a02c81d57
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Feb 22 18:05:16 2011 +0100
+
+    Add SR_HZ macro for consistency.
+
+commit 59df0c77e2906323290544ea62801831818ec096
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Feb 22 17:57:03 2011 +0100
+
+    Add SR_ prefix to the KHZ/MHZ/GHZ macros.
+
+commit 9688b443f65c7779a07b0e3ef2b9f9721ff742cd
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Feb 20 18:39:47 2011 +0100
+
+    Add SR_ prefix for MAX_NUM_PROBES/MAX_PROBENAME_LEN.
+
+commit 4cea9eb20dc8d816a67c57d111a3a4529d452e4d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Feb 20 18:29:05 2011 +0100
+
+    Make ARRAY_SIZE/ARRAY_AND_SIZE private.
+    
+    This is not libsigrok-specific and should not be part of our API.
+
+commit 54ac5277c5e462f1778300b9bc3fdd4709ecb2dc
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Feb 20 18:24:25 2011 +0100
+
+    Constify some more 'char *' parameters.
+
+commit 809c5f2011198a064a2e5e4028f19e63eb532ec1
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Feb 20 14:20:15 2011 +0100
+
+    Add sr_ prefix for analog stuff some structs.
+
+commit a887e3da9714cdfc4ee2eed37e0aa40cf7a5aaea
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Feb 20 14:14:13 2011 +0100
+
+    Add sr_ prefix to receive_data_callback typedef.
+    
+    Also, drop obsolete add_source() prototype from sigrok-cli.h.
+
+commit 13b0573369841c1e26834734699b0f34f35428eb
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Feb 20 14:09:15 2011 +0100
+
+    Add sr_ prefix to datafeed_callback typedef.
+
+commit e5551f657d6f16ec752cbbd1c879827387fd0063
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Feb 20 14:04:12 2011 +0100
+
+    Drop obsolete source_callback_*().
+
+commit c25d2039de05250357f5a215e2cfcf703fbc6625
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Feb 20 13:58:21 2011 +0100
+
+    Add sr_ prefix to filter_probes().
+
+commit 8225e92175c64909eddaecf8bd512049acf653a2
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Feb 20 13:53:13 2011 +0100
+
+    Constify a few more 'char *' parameters.
+
+commit 8233ff53ae7c6e120af4784bc61a036882d5c234
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Feb 20 13:27:08 2011 +0100
+
+    Make load_hwplugins() private.
+
+commit ee4b6342afe8e42c0be481109b9b97e27cbb846a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Feb 20 13:24:26 2011 +0100
+
+    Add sr_ prefix to list_hwplugins().
+
+commit 6f1be0a2d40b3998abd8d10b5479e4538bc4ff1e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Feb 20 13:19:27 2011 +0100
+
+    Add sr_ prefix to session_{add,remove}.
+
+commit 77b454421a2aa7d52873f036e5ba5f8030fe29a3
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Feb 20 13:08:44 2011 +0100
+
+    Disable analog bits/gnuplot output for now.
+
+commit 29cbfeaf5c6a5e9112a6830a8fe4b584b33daf2a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Feb 15 19:38:46 2011 +0100
+
+    Mark some private stuff 'static'.
+
+commit a65de0309b0629d8a5f744f4be7bad67fdd5c34e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Feb 15 19:24:52 2011 +0100
+
+    Add sr_ prefix for hwcap structs/functions.
+
+commit a46d35febf4096df1af6189770bc5c1f91908ff5
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Feb 20 21:00:32 2011 +0100
+
+    Drop prototype for non-existant make_metadata().
+
+commit 218557b85a308adc6ac533eb3f33d3dee17c13f8
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Feb 13 11:27:52 2011 +0100
+
+    Quickfix for a segfault with file input via -i.
+    
+    Stuff like
+    
+      ./bin/sigrok-cli -i rnd.dd -a transitioncounter
+    
+    would segfault (rnd.dd consists of random bytes) because device->plugin
+    was NULL and was being dereferenced.
+    
+    Thanks Olivier Fauchon <olivier at aixmarseille.com> for reporting.
+
+commit 305bde4d42ac801312743cc05671de214f6501fd
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Feb 12 06:18:16 2011 +0100
+
+    implement version 1.3 of the OLS output format, now streaming
+
+commit 4bfbf9fce71f91b3e7b7e968d436f7c436fc9648
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Feb 12 03:24:23 2011 +0100
+
+    demo: forgot second part of samplerate support
+
+commit e5d1717e6d436b4f529c00dd5cede669e74a1e58
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Feb 9 00:07:29 2011 +0100
+
+    Saleae: Make more private stuff static.
+
+commit ba0b1dc639d13caf9c9f564828dc82a55c771913
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Feb 8 23:46:29 2011 +0100
+
+    Doxygen config files: Initial configuration.
+
+commit df66e48b0c794cc91fbf5a3ceb8c9a8f3ada3458
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Feb 8 23:00:49 2011 +0100
+
+    Add doxygen config files for both libs.
+
+commit 03dbc020cde2f0d9857ffcfc273eed5f504a4860
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Feb 8 21:50:27 2011 +0100
+
+    Rename probe_find() to sr_device_probe_find().
+
+commit dfcc0bf9d3b56c06daa1c4eec923ad21bf13dcd3
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Feb 8 21:47:50 2011 +0100
+
+    strutil.c: Fix typo, add some (API) docs/comments.
+
+commit c49111295f0b2e50044923897d99ca84f65b75db
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Feb 8 21:22:10 2011 +0100
+
+    Add sr_ prefix for datastore API functions.
+
+commit 2bf4aca64ad435a09359662446762840ac55db1d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Feb 8 18:19:38 2011 +0100
+
+    Add sr_ prefix for device related API functions.
+
+commit 60679b18e6940d20ee36fa77ea7411b67cbb9c2a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Feb 8 18:07:19 2011 +0100
+
+    Add sr_ prefix to 'struct samplerates'.
+
+commit 8a2efef2d5900cb3dd935af92a0e22528660c4be
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Feb 8 18:00:49 2011 +0100
+
+    Add sr_ prefix to session related API functions.
+
+commit 2872d21ebc4e9554f685551e4915f193357f13d9
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Feb 8 17:50:29 2011 +0100
+
+    Add sr_ prefix for 'struct session'.
+
+commit 1afe89897cf100b1a3a5896184ddaca5705681cc
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Feb 8 17:47:38 2011 +0100
+
+    Add sr_ prefix for 'struct probe'.
+
+commit 3bbd9849e9dc5fdc9fe18a4394abe4d4b43ac9d4
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Feb 6 02:14:57 2011 +0100
+
+    Fix warnings: g_fopen() needs <glib/gstdio.h>.
+
+commit 868d8cefec0d27bc5afed4fe1e906c7b68665cf6
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Feb 5 20:03:17 2011 +0100
+
+    Use glib's g_fopen() instead of fopen().
+
+commit 45fdfa307de68cc5209142cc6bae13a3be274949
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Feb 4 23:52:16 2011 +0100
+
+    MinGW: Use "b" in all fopen() calls.
+    
+    This is required for proper operation on Windows/MinGW, and doesn't
+    affect other OSes, most POSIX systems simply ignore the "b".
+
+commit 0f33365007d72e3f114938a61b9c426b6f5e48c6
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Feb 4 20:11:17 2011 +0100
+
+    Revert FIRMWARE_DIR / DECODERS_DIR method for now.
+    
+    There were several issues with the other method, revert for now.
+
+commit d81d29333e255a236b029860683f4bfadd1c15e3
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Feb 4 06:28:49 2011 +0100
+
+    demo: support setting sample rate
+
+commit 904e0b589ebfbfa5ced62b0fab50a204d8d8a4b5
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Feb 1 18:27:12 2011 +0100
+
+    ols: default to 200KHz samplerate
+
+commit a9f54bcd7b83baf465e5096f604470cacb4951bf
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Feb 2 13:13:13 2011 +0100
+
+    MinGW: Build fixes.
+
+commit 22b02383442ec55a11cc6dd2b4c467d1de0b5bd2
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Feb 2 10:25:52 2011 +0100
+
+    Fix build when no libusb-LA is compiled.
+    
+    Until now the build would break if the user doesn't enable at least one
+    of the libusb1.0-based LAs. I.e., you could not compile only OLS, or
+    only the demo driver.
+
+commit cddd1c5f4739e43365a48a9d17e49cb105d929c7
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Feb 1 06:51:34 2011 +0100
+
+    demo: stored-pattern generator now keeps state
+
+commit 6e738600eb4b98f76ca6f0d7d38da7e7a2acd0ca
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Feb 1 06:13:32 2011 +0100
+
+    output_ols: now fully compliant with spec
+
+commit 3a285098170ee6d5c7eab3fd94606e61a4fbaa19
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Feb 1 02:33:54 2011 +0100
+
+    don't just assume a device has a samplerate setting
+
+commit 4a1b18f86d71ce814ec65b5273c1fdc4ac224735
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Feb 1 01:41:33 2011 +0100
+
+    don't force .sigrok extension when saving session file
+
+commit b8c2f85f561a3e2738b621a0d42e0c066c1fcee9
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Feb 1 00:06:32 2011 +0100
+
+    session_driver: remove unneeded callbacks
+
+commit dd56a9320d3ecb8f9054600f118a219f0de4ec9f
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jan 31 23:44:18 2011 +0100
+
+    fix device probe adding
+
+commit 7d6588743503514c9de5c4fc8a511e9b0bdad7e6
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jan 31 22:34:14 2011 +0100
+
+    implement session loading based on a virtual device driver
+
+commit 40f5ddac0125b1a7c9b2625dda631f3c0ba24a4b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jan 31 22:29:40 2011 +0100
+
+    move samplerate/period printers and parsers into libsigrok
+
+commit a59606dfff0fa324e0003904a8eb72d7159c3c1f
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jan 30 21:57:45 2011 +0100
+
+    remove dead code
+
+commit 9f4bc44e3a4442eb2b4a1fc2bdfeefc2e2bad425
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Jan 31 14:14:28 2011 +0100
+
+    MinGW: Build fix.
+
+commit 01d9dc35ad8ba6817170ac9cca6c7e4fce989b78
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Jan 30 19:22:13 2011 +0100
+
+    Consistently use _exit prefix for functions.
+
+commit 5a2326a71b3a7d3bc6b367a7a3dfa6f137f5f0ec
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Jan 30 17:58:41 2011 +0100
+
+    SR_ prefix for all public enums.
+
+commit 6c29007211e3a35bb90db53cd22042f04fbe4e44
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Jan 30 16:44:26 2011 +0100
+
+    Prefixes for *_device_instance.
+
+commit 5c2d46d1dbfa636fb3cdbeaffdc0e9ca77c66ee1
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Jan 30 16:19:42 2011 +0100
+
+    Prefix device structs with sr_.
+
+commit 9f8274a544865838f880c4849c28b6129141cf99
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 29 17:10:24 2011 +0100
+
+    Add a field for the full name of a device.
+    
+    Also, show this long/full name in 'sigrok-cli -V'.
+
+commit b9c735a275512ce82da7f66275c7cb62eaf66b60
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 29 17:03:26 2011 +0100
+
+    Prefix datafeed structs with sr_.
+
+commit d32d961d17e3c7f409912062e5c336c19b6ef270
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 29 16:57:35 2011 +0100
+
+    get_sr_device_instance() -> sr_get_device_instance().
+
+commit a00ba012288726678e1a270961c8d4f46f3dbd33
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 29 16:43:45 2011 +0100
+
+    Change all sigrok_ prefixes to sr_.
+
+commit f50f3f40d9238b0c50be67e52bc132aadfcf2050
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 29 16:36:57 2011 +0100
+
+    Add sr_ prefix to input/output structs.
+
+commit e46b8fb154ba90ffec9c1f805399dfa819e736f9
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 29 16:23:12 2011 +0100
+
+    Change SIGROK_ prefix to SR_.
+
+commit 544a458212dc972b663e67cd522ba54cbd8a00de
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jan 30 02:40:55 2011 +0100
+
+    move session main loop stuff into libsigrok (session_run)
+
+commit ff35879bb7374a430ef89633df273288d42d4988
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Jan 27 23:17:47 2011 +0100
+
+    Fix some compiler warnings.
+
+commit aa4b110766256f010af198e1e5f2ca64055403df
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jan 24 07:46:16 2011 +0100
+
+    fix session saving and input file loading
+    
+    cli: -i option now properly takes the -o option into account,
+    so sigrok can now be used for protocol conversion with just
+    those two options.
+
+commit e54bcdc5d17daf9a0641763bc33f5c8a723c4cbb
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jan 24 02:49:14 2011 +0100
+
+    cli: don't initialize and scan for hardware unless needed
+    
+    If the -d <plugin> option is used, only initialize the specified plugin.
+
+commit eeebceea31bacfbe05ba6d7cbcf21de03910329a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Jan 23 19:53:50 2011 +0100
+
+    Introduce proper libtool versioning for the libs.
+
+commit da6923732120b9f169c5991000ecabd15c05ffc0
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Jan 23 18:21:58 2011 +0100
+
+    Build fix.
+
+commit 108a5bfbba72882d1bc903a0ae54d0a883ff0824
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jan 23 05:32:37 2011 +0100
+
+    fix compile warning on 32-bit platforms
+
+commit 070befcd1c4786645a9191b96885dd62490b0d41
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jan 23 05:32:13 2011 +0100
+
+    restore demo driver to working state
+
+commit 47697369b552515d76930951e75cf84b5a16953a
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jan 23 04:58:32 2011 +0100
+
+    cli: revamp option syntax
+    
+    for device (-d) and format (-f), the syntax is:
+    
+      <thing>:key=value:key2=value2
+
+commit cdbc51d97d027c3889aad43c9d9ed3344cfb5a91
+Author: Daniel Ribeiro <drwyrm at gmail.com>
+Date:   Sat Jan 22 12:23:34 2011 -0200
+
+    alsa: hide a few compiler warnings
+
+commit 58330ab892c64461a73471a197fd8816630944a9
+Author: Daniel Ribeiro <drwyrm at gmail.com>
+Date:   Sat Jan 22 12:21:04 2011 -0200
+
+    finish alsa driver implementation
+    
+    Yes, it works now.
+
+commit 6ea7e23526b6be4d6c762b1136e361e4d3caccf6
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Jan 22 14:18:31 2011 +0100
+
+    Revert "re-enable filter and datastore for DF_LOGIC"
+    
+    This reverts commit 23da86dfc0a89c7ab951fea31a318a493830eb69.
+
+commit 97554432e8d8bcf7f5af2dd770bcf752c9cd7d75
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Jan 21 22:59:18 2011 +0100
+
+    split output_text into more manageable pieces
+
+commit 921a4c741fee27ee2f248971f9ee309a1551f981
+Author: Daniel Ribeiro <drwyrm at gmail.com>
+Date:   Sat Jan 22 01:01:53 2011 -0200
+
+    fix copynpaste glitch
+
+commit 6ed4f0443730685b6a4a00b316384d751aa787e3
+Author: Daniel Ribeiro <drwyrm at gmail.com>
+Date:   Sat Jan 22 00:57:27 2011 -0200
+
+    initial version of alsa plugin.
+    
+    It does NOT work yet.
+
+commit cfd8b10a2e2e4cd710d148ec5d2e11e18d583414
+Author: Daniel Ribeiro <drwyrm at gmail.com>
+Date:   Fri Jan 21 22:02:32 2011 -0200
+
+    alphabetical order
+
+commit 5819184b229d5d33ccb8e5ed5f7d715f501fedb5
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Jan 21 21:04:01 2011 +0100
+
+    Remove duplicate FIRMWARE_DIR includes.
+    
+    We use AC_DEFINE_UNQUOTED in configure.ac now to put the FIRMWARE_DIR #define
+    in the config.h file, which is included where we need the #define.
+
+commit 62eeeb171bd9a05d167990373e33bc1f956cbfee
+Author: Daniel Ribeiro <drwyrm at gmail.com>
+Date:   Fri Jan 21 18:04:09 2011 -0200
+
+    re-enable filter and datastore for DF_LOGIC
+    
+    This definitely isn't the proper fix, but it should allow DF_LOGIC
+    and DF_ANALOG to coexist.
+
+commit 81bbdf6a6a2a8651e3c1ab3a7f714a851da77141
+Author: Daniel Ribeiro <drwyrm at gmail.com>
+Date:   Fri Jan 21 16:11:44 2011 -0200
+
+    add incomplete DF_ANALOG support to output_gnuplot.c
+    
+    RAW->Voltage conversion is not implemented yet, its hardcoded for
+    signed 16bit conversion.
+
+commit 8038e90aefdbddd68a9775aea4f588bdd89894fe
+Author: Daniel Ribeiro <drwyrm at gmail.com>
+Date:   Fri Jan 21 12:52:12 2011 -0200
+
+    add a sine wave to demo.c
+
+commit c3579621d569f4b1ef3c21c7e2ed3bdc855c617b
+Author: Daniel Ribeiro <drwyrm at gmail.com>
+Date:   Fri Jan 21 11:25:50 2011 -0200
+
+    reduce analog_sample sizes.
+    
+    To save resources, reduce the max ADC resolution and max probes
+    per device. Just increase when needed.
+    
+    Soft limit: 256 probes, 16bit adc
+    Hard limit: 2^64 probes, 64 bit adc
+
+commit 764f887f7bfe480690fdc90ccadadfc1f9b42c03
+Author: Daniel Ribeiro <drwyrm at gmail.com>
+Date:   Fri Jan 21 01:30:56 2011 -0200
+
+    change demo.c to output analog packets
+    
+    You need to #define DEMO_ANALOG to generate DF_ANALOG packets.
+
+commit 6eb0e3ea9528e91ef1e44e224fe9d6b05e31596f
+Author: Daniel Ribeiro <drwyrm at gmail.com>
+Date:   Fri Jan 21 01:19:50 2011 -0200
+
+    change output_text.c to support analog
+    
+    Only the "bits" output format was converted.
+    Analog values, are scaled down to A-Z letters.
+
+commit 48d783e4b5e557b6b7beee3907f0e8bd88741426
+Author: Daniel Ribeiro <drwyrm at gmail.com>
+Date:   Fri Jan 21 01:14:53 2011 -0200
+
+    introduce analog_sample datafeed packet
+    
+    These structs define the packet format used to exchange data using
+    the DF_ANALOG packet type.
+
+commit f3163a6c2ee7a1d7ec6865f11cfcf52b07dc31f5
+Author: Daniel Ribeiro <drwyrm at gmail.com>
+Date:   Thu Jan 20 20:10:43 2011 -0200
+
+    make output_analog.c = output_text.c
+
+commit f95fd1aaf3830c4d1f451b4b15c56169c9e95b35
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Jan 20 23:23:06 2011 +0100
+
+    Install an empty firmware/ directory.
+    
+    This reduces the hassle for the users (and distro packages) a bit, you
+    only need to copy files into there now.
+
+commit a00b530c644076f04a8505bc3644d2dceb3f6ed7
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Jan 20 23:00:59 2011 +0100
+
+    lib headers: Add 'extern "C"' for C++ usage.
+
+commit bffed4fc107358b11ab007ef2cdef851572680ef
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Jan 20 00:39:59 2011 +0100
+
+    Re-enable stuff we temporarily disabled for 0.1.
+
+commit 07c81bfad119a4ea66c76cc830506ce3b381b4c5
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Jan 19 23:55:03 2011 +0100
+
+    Disable Link Instruments MSO-19 for 0.1.
+
+commit 26ce0bbfd88121831c651c8042e3c843ccd5d2c2
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Jan 19 23:47:21 2011 +0100
+
+    demo: Small indentation fix.
+
+commit 1924f59f4b788046f5eaf7ef3272a14c79a7c6f3
+Author: Håvard Espeland <gus at ping.uio.no>
+Date:   Wed Jan 19 23:14:17 2011 +0100
+
+    Demo: Obery samplerate and fix race condition.
+
+commit 576790ff7b7e888eeefa79239ffed6d8550c1160
+Author: Bert Vermeulen <bert at slab.local>
+Date:   Wed Jan 19 22:47:55 2011 +0100
+
+    disable MSO-19 specific stuff for 0.1 release
+
+commit c70fce6ba6f061f1fbd4dbdf08e5d2ffa0168f6a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Jan 19 19:20:44 2011 +0100
+
+    Don't install libs and headers in the 0.1 release.
+    
+    The library APIs are not yet usable or finalized, so don't expose the
+    libs for now. Instead, only install sigrok-cli, the manpages, and
+    the decoders.
+
+commit 058b70353dd462ab13f3badb43f2fea697161bd7
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Jan 19 01:16:19 2011 +0100
+
+    Move more non-public headers to sigrok-internal.h.
+
+commit 01bd1ed396f33efc7126703210f44c4b5730d064
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jan 18 00:08:11 2011 +0100
+
+    Fix compiler warning.
+
+commit 32c0551ba66452acc24c9dc163ade3a637b1c7f2
+Author: Håvard Espeland <gus at ping.uio.no>
+Date:   Tue Jan 18 23:17:55 2011 +0100
+
+    output_vcd: Make timestamp work on 32-bit machine.
+
+commit 94ba4bd6897d87af2ca45acc0505139d04785d44
+Author: Håvard Espeland <gus at ping.uio.no>
+Date:   Tue Jan 18 23:12:57 2011 +0100
+
+    Sigma: Update set_configuration to reflect API.
+
+commit 7c70c53843766003b881ca2c47f2c4bb454a3360
+Author: Håvard Espeland <gus at ping.uio.no>
+Date:   Tue Jan 18 22:39:46 2011 +0100
+
+    Sigma: Set default samplerate to 200 KHz.
+
+commit 5b5ea7c6d25bb42de09b61d0a070d78252f2367b
+Author: Håvard Espeland <gus at ping.uio.no>
+Date:   Tue Jan 18 22:24:23 2011 +0100
+
+    Sigma: Only send trigger packet if enabled.
+    
+    The Sigma hardware emits a default trigger event.
+
+commit abda62ced8a9cdbb13be49a503d6bc6a8a8f8f2e
+Author: Håvard Espeland <gus at ping.uio.no>
+Date:   Tue Jan 18 22:17:43 2011 +0100
+
+    Sigma: Never send empty packets.
+
+commit afa8f8449aa6c04980a9d4639a901079a2afedc9
+Author: Håvard Espeland <gus at ping.uio.no>
+Date:   Tue Jan 18 22:14:36 2011 +0100
+
+    output_text: Mark trigger at correct position.
+    
+    ASCII output does not separate groups of samples with
+    and must be handled separately.
+
+commit 6ef7a8cb5d2f035734dd504d99b267a118b2dade
+Author: Håvard Espeland <gus at ping.uio.no>
+Date:   Tue Jan 18 22:13:50 2011 +0100
+
+    output_text: Fix ASCII edge case.
+
+commit d4f228d094d53c95bdf4dd42525a271db716928d
+Author: Håvard Espeland <gus at ping.uio.no>
+Date:   Mon Jan 17 22:56:14 2011 +0100
+
+    output_text: Add ASCII output.
+
+commit b9cc36296b6e08d194a2b8e6c1adeb010af9a630
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jan 17 02:20:52 2011 +0100
+
+    demo driver: support time limit
+
+commit 574ce4988ac771ea39e3423c196019555e81df8a
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jan 17 02:18:02 2011 +0100
+
+    refuse to set sample limit under 4 (protocol can't handle it)
+    
+    also a bit of whitespace mangling.
+
+commit b33e7d7058a5a092eea7b8bce18cf95d70e5ff5a
+Author: Håvard Espeland <haavares at ifi.uio.no>
+Date:   Sun Jan 16 17:55:51 2011 +0100
+
+    output_vcd: Emit timestamps as time, not sample num.
+
+commit 08b488b84896d0e29c401c67f7bda7fed968f9ca
+Author: Håvard Espeland <haavares at ifi.uio.no>
+Date:   Sun Jan 16 17:34:49 2011 +0100
+
+    output_vcd: Remember samples between packets.
+    
+    Fixes two bugs in vcd output:
+    1) Waveform did not match original input when viewed in gtkwave.
+    2) No vcd output when using 1 MHz sampling on Sigma.
+
+commit 88c51afe876b6d6ba115f8152d89b9564ee00e4f
+Author: Håvard Espeland <haavares at ifi.uio.no>
+Date:   Sun Jan 16 17:03:25 2011 +0100
+
+    Sigma: Support for decoding partial chunks.
+    
+    Samples are stored in chunks and the last samples do not fill up
+    a complete chunk. This patch adds support for decoding partial
+    chunks.
+
+commit 10c471ab131bd766c9207e05e485fd2467ba7d5b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Jan 16 14:18:26 2011 +0100
+
+    Fix warnings.
+
+commit d35aaf0256aa646af0f23035932271579ca65a3d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Jan 16 14:12:52 2011 +0100
+
+    demo: Use GIOChannels, makes it work on MinGW.
+
+commit fbf1ff5d2268c0fbf35b6210afa11da351b9b2ba
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jan 16 04:34:45 2011 +0100
+
+    clean up output_vcd module
+    
+    use self-expanding strings, better standards conformance
+
+commit 98b8cbc17e03119fcaa735a4bc2f0451000ab54f
+Author: Håvard Espeland <haavares at ifi.uio.no>
+Date:   Sat Jan 15 20:01:00 2011 +0100
+
+    Sigma: Limit number of edge triggers to 1.
+    
+    Actually, Sigma supports 2 rising/falling triggers,
+    but they are ORed and the current trigger syntax
+    does not permit ORed triggers.
+
+commit 31facdd3c5ca0c118d1216ce65c468db130bb751
+Author: Håvard Espeland <haavares at ifi.uio.no>
+Date:   Sat Jan 15 19:19:49 2011 +0100
+
+    Sigma: Download samples from partial chunks.
+
+commit ab224f7b61ee1d3cf46fff172e4d97c856031593
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 15 18:18:09 2011 +0100
+
+    Initial support for the OLS output format.
+    
+    This is the file format for the OpenBench Logic Sniffer "Alternative" client.
+    Details: https://github.com/jawi/ols/wiki/OLS-data-file-format
+    
+    This is work-in-progress.
+    Currently the number of samples is hardcoded to 10000. Also, this will
+    require a real logic analyzer as input at the moment, and will not yet
+    work with the "demo" driver.
+
+commit 9d7ab9ba3b5208e99bc7fd33c6a831fe21a427f3
+Author: Håvard Espeland <haavares at ifi.uio.no>
+Date:   Sat Jan 15 18:24:01 2011 +0100
+
+    output_text: Allocate more memory for output
+    
+    The trigger line was forgotten. Allocate 512 bytes extra.
+
+commit 9996570987d362a324384ed041040e884628853e
+Author: Håvard Espeland <haavares at ifi.uio.no>
+Date:   Sat Jan 15 17:02:18 2011 +0100
+
+    Sigma: Move sigma state to device specific struct
+    
+    Thanks to Daniel Ribeiro for contributing this patch. Some
+    modifications were done.
+    
+    Not tested on multiple Sigmas, because of lack of hardware.
+
+commit 3aa403e858a490aee17c23c11d3a09cdd4eb324d
+Author: Håvard Espeland <haavares at ifi.uio.no>
+Date:   Sat Jan 15 16:10:57 2011 +0100
+
+    output_text: Allocate enough memory for output
+
+commit 858fb11c5e26009861b8b7aef7c07b701d2cda5a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 15 15:44:21 2011 +0100
+
+    Drop unused debug.c.
+    
+    Even if we'd use it, it probably belongs into the frontend, not libsigrok.
+
+commit 484760d1a8a26ba830b3d63d1451dc30985babd1
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 15 15:43:25 2011 +0100
+
+    Cosmetics.
+
+commit aa0b6b208e2ecaa7e56b020c204b6c3e702fb4ca
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 15 15:43:03 2011 +0100
+
+    sigrok-proto.h: Sort the prototypes, fix comments.
+
+commit 1483577eed7ac27b8107b1b76e1adc5369745c29
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 15 15:06:58 2011 +0100
+
+    Start moving private stuff to sigrok-internal.h.
+    
+    This is work-in-progress, unfinished.
+
+commit f7606f9b75b1b4b2324635426f3cc52feda1e3aa
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Jan 15 15:21:54 2011 +0100
+
+    fix hex output
+
+commit c2bd92ec0867eff49ee58b557d6fb9aec2b63357
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 15 14:41:57 2011 +0100
+
+    Slightly more consistent #include-guard naming.
+
+commit 917e0e71d53cb0a0ac7965cb4f36791b14f7e5ff
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Jan 15 14:28:03 2011 +0100
+
+    added example code for generating a stored pattern
+
+commit 9be9893eed4acf03533d1a2fb63719de6eb10753
+Author: Håvard Espeland <haavares at ifi.uio.no>
+Date:   Sat Jan 15 14:03:08 2011 +0100
+
+    Sigma: Check state in hw_closedev
+    
+    If the device is closed without previously running hw_openedev
+    the driver crashes (happens in cleanup). This patch checks
+    if the device has been opened.
+
+commit 02440dd88c93b049bdd71039ef036af1c8812189
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 15 13:06:04 2011 +0100
+
+    demo: Cosmetics, constify.
+
+commit e15f48c268877632086e9cd0bb16356cd58cde5f
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Jan 15 05:12:41 2011 +0100
+
+    cleaned up demo driver
+    
+    removed unused samplerate
+    added patternmode (random and incremental)
+
+commit 925dbf9f97c18628ead7cb5a93f95052b48ca0e4
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Jan 15 05:11:40 2011 +0100
+
+    add new HWCAP patternmode
+
+commit 63570167d67cacab2ac56eaabb6219c7593bca9e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 15 03:44:19 2011 +0100
+
+    Cosmetics for the -D output.
+
+commit 17e1afcb81b8581091fcb660c2e61f05c75e00b5
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Jan 13 23:50:34 2011 +0100
+
+    Whitespace and consistency fixes.
+    
+    Also, drop a <poll.h> #include. It's unused anyway, and breaks the build
+    on MinGW/Windows as there is no poll.h there.
+
+commit 9ab95e54083b62c060cddd1e2762529c762d90be
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Jan 13 02:05:39 2011 +0100
+
+    make output modules a bit more crashproof
+    
+    the event handler in output modules is now optional.
+
+commit 2507648e63d7b9807808d2e74b168821e94d893d
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Jan 13 01:26:23 2011 +0100
+
+    use us instead of µs in periods (VCD can't handle it)
+
+commit 2119ab0364b6a161091a89a7018be14d49bdc7b3
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Jan 12 00:43:00 2011 +0100
+
+    MinGW/Windows: Serial port portability fixes.
+    
+    Add serial_read()/serial_write() which have different implementations on
+    MinGW/Windows.
+    
+    Add some more error code handling and documentation.
+
+commit ba3d481bb78a3bdb009c8d0aed3885a0a0192a04
+Author: Olivier Fauchon <olivier at aixmarseille.com>
+Date:   Wed Jan 12 00:25:15 2011 +0100
+
+    add ontinuous mode for demo driver
+
+commit 13a12913507682c319aaa890d897670bc8457adb
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jan 11 23:58:41 2011 +0100
+
+    fully implement input_binary module
+
+commit 78ed6420358cd83bb74208e80cbcd7c068713769
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Jan 11 23:49:32 2011 +0100
+
+    code cleanup
+
+commit a61b0e6a35fdf06c98a2304e186a3a17c9fbf8d8
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jan 11 22:17:33 2011 +0100
+
+    configure: Add --enable-demo option.
+
+commit 1fdb75e14528abd62ebe727537512c741a5759da
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Jan 11 01:25:10 2011 +0100
+
+    MinGW: Quickfix to make serial.c/ols.c compile.
+    
+    Note: It does NOT actually work, yet, it only compiles!
+
+commit 74b9b43836a55debd1e5c27637021ef505f6e7aa
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jan 10 22:17:52 2011 +0100
+
+    cli: support --continuous option for continuous sampling
+
+commit 8a839354c122b533181fe02da82d0110a44911cf
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Jan 10 23:20:37 2011 +0100
+
+    Cosmetics, whitespace, consistency fixes.
+
+commit fc96e6f8c8591c15930ff3dfe9e14303b29e70aa
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Jan 10 22:49:38 2011 +0100
+
+    demo: Add missing copyright line.
+
+commit 2566bd4884bf33518488504575ba62e99ef43a7b
+Merge: 01cf881 882e207
+Author: Daniel Ribeiro <drwyrm at gmail.com>
+Date:   Mon Jan 10 15:58:05 2011 -0200
+
+    Merge branch 'master' of git://sigrok.git.sourceforge.net/gitroot/sigrok/sigrok
+
+commit 01cf8814949f4786da4a1be79a74030a691be152
+Author: Daniel Ribeiro <drwyrm at gmail.com>
+Date:   Mon Jan 10 15:15:51 2011 -0200
+
+    Add incomplete mso-19 plugin
+    
+    * Both Analog and Logic capture works.
+    * Analog values are raw ADC, still useless.
+    * Triggers aren't implemented.
+    * Pattern Generator not implemented.
+    * Everything is broken. :)
+
+commit 3677f3ec3f76ec3efc8aea97a1b050f6949d773d
+Author: Daniel Ribeiro <drwyrm at gmail.com>
+Date:   Mon Jan 10 15:14:26 2011 -0200
+
+    Add HZ_TO_NS macro
+
+commit c2616fb9faca19945154974884a0816359cec1df
+Author: Daniel Ribeiro <drwyrm at gmail.com>
+Date:   Mon Jan 10 15:12:38 2011 -0200
+
+    update plugins and cli to use new DF_HEADER
+
+commit 921e753f7e2bef9590b1e344200b736a0faa18cc
+Author: Daniel Ribeiro <drwyrm at gmail.com>
+Date:   Mon Jan 10 15:08:43 2011 -0200
+
+    Support for analog probes
+    
+    Add a field to the probe struct to store the probe type.
+    Change DF_HEADER to report the quantity of each type of probe.
+
+commit ac4a2ea45a9320e87ec03cd820bf80c96eb65b21
+Author: Daniel Ribeiro <drwyrm at gmail.com>
+Date:   Mon Jan 10 15:05:14 2011 -0200
+
+    serial.c: fix parity != none
+    
+    The flag write was wrong
+
+commit 882e2075bb51496e5eb9548b98204b90a4b60a82
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jan 10 13:47:24 2011 +0100
+
+    finish split of sigrok.h
+
+commit 10509bc2e445b20f90d2ce05561dfbb873180872
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jan 10 13:44:11 2011 +0100
+
+    split off prototypes into their own header file
+
+commit 655756e01d929607f67a9d576222917c72513b4b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jan 10 12:39:53 2011 +0100
+
+    cli: new option to list output modules
+
+commit 43275b4712b0ad5baea1c7d71fdb710249a46681
+Merge: e006af1 9d4bde7
+Author: Daniel Ribeiro <drwyrm at gmail.com>
+Date:   Mon Jan 10 02:36:50 2011 -0200
+
+    Merge branch 'master' of git://sigrok.git.sourceforge.net/gitroot/sigrok/sigrok
+
+commit 9d4bde70fc2a46bae172ab1851f3aff9e3f9b3b5
+Author: Daniel Ribeiro <drwyrm at gmail.com>
+Date:   Mon Jan 10 02:21:07 2011 -0200
+
+    Finish serial_set_params implementation
+    
+    Adds the most common baud rates and support bits, parity, stopbits
+    and flocontrol settings.
+
+commit e006af1116adb76014e77db718bb8673137a8bf5
+Merge: 1ff7712 9b36e36
+Author: Daniel Ribeiro <drwyrm at gmail.com>
+Date:   Mon Jan 10 02:28:59 2011 -0200
+
+    Merge branch 'master' of git://sigrok.git.sourceforge.net/gitroot/sigrok/sigrok
+
+commit 9b36e360f3c23c3287e6e10acb0b57479c5d19ad
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jan 10 05:27:22 2011 +0100
+
+    output_analog: allow samples per line arg (default analog10)
+
+commit 1ff7712c93fb61e7710de6c2b4241652445f368e
+Author: Daniel Ribeiro <drwyrm at gmail.com>
+Date:   Mon Jan 10 02:21:07 2011 -0200
+
+    Finish serial_set_params implementation
+    
+    Adds the most common baud rates and support bits, parity, stopbits
+    and flocontrol settings.
+
+commit 1437e8934bd01167f2126616c7e8b44ca342cd27
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Jan 10 05:13:46 2011 +0100
+
+    add DF_ANALOG, and an analog output module
+    
+    Samples in DF_ANALOG packets are fixed in length to sizeof(double).
+
+commit f0411b1d170aa60c3aa79b12e88f53b225ea350d
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jan 9 23:22:48 2011 +0100
+
+    output modules now register the DF type they can use
+
+commit 8d6725506115e97665be8ef35dbaaf694ba72a93
+Author: Daniel Ribeiro <drwyrm at gmail.com>
+Date:   Sun Jan 9 03:50:45 2011 -0200
+
+    Add a per-instance pointer storage for hardware plugins.
+    
+    We need this to properly support more than one device connected
+    at the same time.
+
+commit dfa4b731da66ddf05ff04943bf0d385aa440c3ac
+Author: Daniel Ribeiro <drwyrm at gmail.com>
+Date:   Sun Jan 9 03:48:39 2011 -0200
+
+    Add ARRAY_AND_SIZE macro
+    
+    Just a handy macro
+
+commit 4c046c6bcc392666405154853faf7dc2522aa1d9
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jan 9 06:32:38 2011 +0100
+
+    change all DF_LOGIC* to a single DF_LOGIC type
+    
+    The datafeed packet has a new field 'unitsize' to denote the number of
+    bytes per sample in the payload.
+
+commit af812219f655b286f5a2a0146846d9b97e25435c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 8 20:06:32 2011 +0100
+
+    Only build specific source files if needed.
+
+commit 7c17ac6cc4ecc30a1df1848ef3a3e0827351090c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 8 19:15:39 2011 +0100
+
+    Only build hardware drivers if they're enabled.
+
+commit 5096c6a6c1f2efb01d5efdebb26e282296c2910e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 8 19:01:07 2011 +0100
+
+    demo driver: Small cleanups, error handling.
+
+commit 85b5af068776cca18c704a101d6d56be1ec236b6
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 8 18:29:10 2011 +0100
+
+    Make the demo driver work.
+    
+    When initialized, the driver starts a thread that generates signal data.
+    This data is written to a pipe (write file descriptor).
+    The other end of the pipe (read file descriptor), is connected to the
+    main polling code, like any other driver.
+    
+    Note: This patch adds a new dependency on libgthread.
+    
+    At the moment, you can list the driver's device:
+    
+    $ ./cli/sigrok-cli -D
+    The following devices were found:
+    ID  Device
+    0   Sigrok project Demo Driver v1.0 with 8 probes
+    
+    And use it for random signal generation:
+    
+    $ /opt/sigrok/bin/sigrok-cli -d 0 --samples 50 -f bits -p 1-8
+    sigrok 0.1pre2
+    Acquisition with 8/8 probes at 0 Hz
+    1:10111100 11010110 00001011 00011110 00111010 11110100 10
+    2:11010110 00111111 01001010 11111101 11010011 00010010 11
+    3:11000101 01000001 10100011 10100100 10110000 11110011 00
+    4:00100111 11110100 10011101 01100111 00100101 01001110 10
+    5:00011100 00101100 10111000 11001101 01011101 01011011 01
+    6:10110101 10111110 10010110 10111000 11011010 10000100 11
+    7:11111111 01001111 11110110 11010010 10000101 01001111 00
+    8:01000101 01111110 01010111 00000111 00010010 00000101 11
+    
+    The next step is to make demo driver customisable (per-probe signal clock,
+    reference sample signals : serial, I2C, CAN...).
+    
+    Thanks Olivier Fauchon <olivier at aixmarseille.com> for the patch.
+
+commit d4ae8eaa7c09e31ef246b7d56008a0aa21db9f0d
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat Jan 8 15:48:39 2011 +0100
+
+    fix buffer size, various error checks
+
+commit 2a3f9541a4bece23b25e1b255c0fab31ba5a751b
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Jan 6 00:51:29 2011 +0100
+
+    add sigrok_period_string(), MAX_NUM_PROBES
+
+commit 5e2ddeb098b677faca5d044f3523f5f6f3382d90
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 8 03:51:31 2011 +0100
+
+    Fix two more compiler warnings noticed on amd64.
+
+commit 340f6e7aeaf0c6cbbb27c5b535787bd09407994b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat Jan 8 03:32:25 2011 +0100
+
+    Fix out-of-tree build.
+    
+    Use libtool "noinst" local helper libs and use one Makefile.am per
+    subdir, which is the usual/preferred method. These helper libraries are
+    purely local and will not be installed.
+    
+    This also fixes out-of-tree builds of sigrok, i.e. building in a
+    directory other than the sigrok source directory, e.g.
+    
+     $ cd /home/user
+     $ git clone ...sigrok
+     $ cd sigrok
+     $ ./autogen.sh
+     $ mkdir /tmp/foo
+     $ cd /tmp/foo
+     $ /home/user/sigrok/configure
+     $ make
+     $ make install
+    
+    This will place all build results (.o files, .la files, etc) in the
+    local build directory (/tmp/foo) instead of the source directory
+    (/home/user/sigrok in this example). The installation directory is
+    selected via the --prefix configure option (/usr/local per default).
+
+commit 757b8c628a5b64f8b6b166044b1b3ac1ccf797dc
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Jan 7 19:55:25 2011 +0100
+
+    Cosmetics, whitespace, simplifications.
+    
+    Reduce code nesting a bit, constify some strings.
+
+commit 6239c175c1b967b577f760032d326322dd4c4576
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Jan 6 19:16:47 2011 +0100
+
+    Initial, unfinished demo/simulation hardware driver.
+
+commit 339729131d5acd50147e26ec238db569e273a459
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Dec 29 01:22:58 2010 +0100
+
+    proper fix for output_text corner cases
+    limit probe names to 32 chars
+
+commit e6ac9ac808b900287a80ea44d9c661703e3a101c
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Dec 29 00:02:30 2010 +0100
+
+    consistent debug msgs, rename sump to ols
+
+commit ee5f5e81adc83e68c9af2c9305b0ddcb813d2b4a
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Tue Dec 28 21:59:07 2010 +0100
+
+    fix corner cases/memory management (cli->text out)
+
+commit a5e18535ad897084b9a67dbee19bcc1ebd21ae7a
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Mon Dec 27 23:44:50 2010 +0100
+
+    don't turn on/off libusb debugging
+
+commit f0551a6543206a0970410481b8e36bbfa6a609ea
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Aug 12 06:04:44 2010 +0200
+
+    oops, fix serial_flush()
+
+commit 06d64eb880876bd8a81c249e7b2f690eb03e12c1
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Aug 12 06:02:25 2010 +0200
+
+    add serial_flush()
+
+commit e1aac2319a1e0f5e7d263b5fd50a62c8b42fe22e
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Aug 12 05:49:00 2010 +0200
+
+    increase length of datafeed packets to uint64_t
+
+commit a143e4e5ddb4743867b7578e0599a566c2c82c07
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Aug 12 04:57:09 2010 +0200
+
+    don't push configuration to device until acq time
+
+commit f0d1b53e56045bc15fe156c3f6e855dfc91037be
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Aug 11 18:37:09 2010 +0200
+
+    OLS: fix multi-channel capture
+
+commit edc508d49cacf2ff7ff38dec5cb49ec317f4a39f
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Wed Aug 11 04:04:20 2010 +0200
+
+    add debug logging (set SIGROK_DEBUG=2 to see)
+
+commit a803c0db4d5887c29b8c79626bfcc452845cfed2
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Aug 5 03:54:33 2010 +0200
+
+    OLS: fix triggers, sample order, capture ratio
+
+commit 3245dfcb629ced90a2570dc04db99f59af60b888
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Aug 5 03:52:32 2010 +0200
+
+    define pre/post-trigger capture ratio option
+
+commit b5698bd71e96561ba08a481abaa9c64ee687bda2
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Jul 18 21:57:27 2010 +0200
+
+    saleae logic: fix triggers after style changes
+
+commit c4fffe1e9606e3e63a4cd0b760a37beb1f122cc5
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Jul 14 22:09:21 2010 +0200
+
+    hwplugin.c: Add missing config.h #include.
+    
+    This fixes a bug where no LA would be found or displayed in lists such
+    as 'sigrok-cli -H' or 'sigrok-cli -D'.
+    
+    Thanks Forrest Voight for spotting the bug.
+
+commit 960a75e4741edf7d3481339897328f0ea712e2c0
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Jun 25 01:11:11 2010 +0200
+
+    Only build hardware plugins if requested by user.
+    
+    Per default all plugins will be built, though. The user can override
+    this via the --disable-la-xxxx options.
+
+commit 5b907f9b07b0559f7230e827e5d02589d307e727
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon May 31 11:34:10 2010 +0200
+
+    Add per-LA --enable-XXXX configure options.
+
+commit 38ba2522516b481fa3619bdec56d1e2a4b7a5f45
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu May 27 01:51:55 2010 +0200
+
+    Use 'kHz' (not 'KHz') consistently.
+
+commit 49d0ce50d0e43c1a10dc2863afd20185051819aa
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 19 00:38:14 2010 +0200
+
+    Simplifications and small fixes.
+
+commit 5013f07422b5a62386f68d1663011d5ba885f1ef
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed May 19 00:23:27 2010 +0200
+
+    skeleton.c: Update to latest prototypes.
+
+commit 2458ea651409c8252d33dba5b5cfe9313f3e4899
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sat May 15 23:30:17 2010 +0200
+
+    use flexible sample limit specification (k/m/g)
+    
+    HWCAP_LIMIT_SAMPLES is now passed to the driver as *uint64
+
+commit 989938f6cd5f9bf76f42e29ab39eca4570e430e2
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon May 17 23:59:56 2010 +0200
+
+    Cosmetics: Reduce nesting level a bit.
+
+commit 9a5c6dcf498b8dfebb8beb848ee6db6b59b173e5
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 14 14:24:05 2010 +0200
+
+    Factor out opendev2/opendev3.
+
+commit 5e59f476152a343619f473c37f2b06e2b6ef15d3
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 14 13:12:06 2010 +0200
+
+    opendev2/opendev3: Don't depend on global vars.
+
+commit 28fc6de055eae2d6ba97206bb636f28e12fd68a9
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri May 14 13:07:03 2010 +0200
+
+    Cosmetics.
+
+commit d658e348a89c5dd3d248abdbbdf5423465a2d344
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue May 11 18:07:54 2010 +0200
+
+    pkg-config: Add (semi-generated) libsigrok.pc.
+
+commit 1ebdb3fdc3e28d138046539d9a38610254d9c00a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue May 11 17:13:35 2010 +0200
+
+    Drop unused and obsolete gmodule stuff.
+
+commit 5b15b41e623e755e31cdc699f9d542d69d7e61c7
+Author: Peter Stuge <peter at stuge.se>
+Date:   Sun May 9 23:11:08 2010 +0200
+
+    sump/ols: Wait 10ms for hw response to make pl2303 reliable
+
+commit 71dda1065642b33d4c82d514bcaf28e2d2b8729c
+Author: Peter Stuge <peter at stuge.se>
+Date:   Sun May 9 23:04:24 2010 +0200
+
+    serial: Remove unneccesary nesting
+
+commit fbe2f7945d70500f6db374956a36d7bb131b09d5
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun May 9 21:05:15 2010 +0200
+
+    VCD: Optimizations and fixes.
+
+commit 086eac7c7bef114dd96c6ddb639fa2fa35f9182b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun May 9 20:52:36 2010 +0200
+
+    VCD/Gnuplot: Fix incorrect sample counter.
+
+commit 114fb93f67f8748352ad4f851afeab31df2f0385
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun May 9 20:27:11 2010 +0200
+
+    Gnuplot: Nicer output formatting.
+
+commit fdebec21082fdc7bb2642e717565bdbc8b98f287
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun May 9 19:36:43 2010 +0200
+
+    filter.c: Error handling, code simplification.
+
+commit 5f8c4cb3633cdde636c497cf7ec4eb79e30e32f6
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun May 9 15:52:56 2010 +0200
+
+    Gnuplot: Improve column/probe name display.
+    
+    This fixes incorrect probe name display if the user explicitly named
+    probes via '-p 1=CLK' etc.
+
+commit e734b81a685c9a1bcb4bd899ba162f5c7769b2d1
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun May 9 15:38:33 2010 +0200
+
+    output_text: More error handling.
+
+commit caf62e22c4dad949c8b1282e621e2dbf47daac30
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun May 9 15:12:10 2010 +0200
+
+    output_gnuplot: Simplify event().
+
+commit d20ba6490ac948783435c72340d3e37b67cd6a62
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun May 9 15:11:47 2010 +0200
+
+    output_binary: Code simplifications.
+
+commit 1e32053cd0a8e42e628cf832d81360b96c8de97d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun May 9 15:02:17 2010 +0200
+
+    Gnuplot quickfix: Increase malloc()'ed size.
+
+commit 5cca9adbf27252349729cdb1e1c6ca0a526561b1
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun May 9 14:54:16 2010 +0200
+
+    VCD/Gnuplot: Store time/date in output.
+
+commit 607b58de58f22baa026d24ac7b8e0ae123c9ede0
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun May 9 14:42:46 2010 +0200
+
+    VCD/Gnuplot: Cosmetics, code simplifications.
+
+commit a821069b3411e127512dc2c436a76d25fdac0a5a
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun May 9 14:35:02 2010 +0200
+
+    Gnuplot output: More error handling.
+
+commit 2aebf78d9d10eb838b2fe58683d7af06015cd214
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun May 9 13:32:58 2010 +0200
+
+    datastore_new(): Use int as return value.
+
+commit 33247d6acf94bb9119ba7e1a8239b474bdcfa430
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun May 9 13:25:03 2010 +0200
+
+    Datastore: More error checking.
+
+commit 6b5e3ceefcdee5e942b9cbff5c697016dacee774
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat May 8 16:09:25 2010 +0200
+
+    VCD: Improve error handling/checking.
+    
+    Check malloc()/calloc() return values and so on. Also, add missing
+    free() calls and some TODOs. Simplify some code.
+
+commit d2b36a10d72133feeea3610bdc81a484b6f8fc72
+Author: Bert Vermeulen <bert at rogue.biot.com>
+Date:   Wed May 5 22:06:38 2010 -0700
+
+    output_text: always print sigrok version
+
+commit c9c1c6458c15958d19d8cbac50f2e301479892a1
+Author: Bert Vermeulen <bert at rogue.biot.com>
+Date:   Wed May 5 21:43:25 2010 -0700
+
+    output_binary: rm TODO item
+    
+    Yes, disabled probes are stripped by the filter before the
+    output module even gets data.
+
+commit 7aae74622ecf04f51d5b7df650ea8bd98baa0fcf
+Author: Bert Vermeulen <bert at rogue.biot.com>
+Date:   Wed May 5 19:56:48 2010 -0700
+
+    output: if device has no plugin, don't report samplerate
+
+commit db91a1c3c1e798610542b9749191fc89f15c5ccd
+Author: Bert Vermeulen <bert at rogue.biot.com>
+Date:   Wed May 5 19:55:58 2010 -0700
+
+    input: use dummy device when loading from file
+
+commit 873080cc03a7c7889ef775a4584d1036b1d1315f
+Author: Bert Vermeulen <bert at rogue.biot.com>
+Date:   Wed May 5 19:54:19 2010 -0700
+
+    allow devices without a plugin
+    
+    this is needed to support file loading: we want a device struct
+    so we can enumerate probes from the file, but there is no plugin
+    since the data come in from a device.
+
+commit e273a9040e10c1297c758fe35eb522bd5470e708
+Author: Håvard Espeland <gus at ping.uio.no>
+Date:   Tue May 4 19:44:39 2010 +0200
+
+    Output: Fix invalid pointer dereferencing in vcd and gnuplot.
+
+commit bdfc7a89745a0fae422806c883cbd946f16eace3
+Author: Håvard Espeland <gus at ping.uio.no>
+Date:   Mon May 3 21:35:02 2010 +0200
+
+    Sigma: Small cleanups.
+
+commit 36b1c8e61b277aabc84d181992795447e7339e5d
+Author: Håvard Espeland <gus at ping.uio.no>
+Date:   Mon May 3 21:30:37 2010 +0200
+
+    Sigma: Use software trigger to pinpoint exact sample.
+
+commit 6aac77375bb6f9545475d8d4d5e565f896b28be0
+Author: Håvard Espeland <gus at ping.uio.no>
+Date:   Mon May 3 19:04:10 2010 +0200
+
+    Sigma: Add state machine for tracking Sigma status.
+
+commit a42aec7f6e61b83fcd00e20827b31cc0ee3852d0
+Author: Håvard Espeland <gus at ping.uio.no>
+Date:   Mon May 3 15:06:43 2010 +0200
+
+    Sigma: Merge storage of rise/fall triggers.
+
+commit 4ae1f451363013d2f0fff180942e5b140e39f049
+Author: Håvard Espeland <gus at ping.uio.no>
+Date:   Sun May 2 19:21:05 2010 +0200
+
+    Sigma: Minor cleanups.
+
+commit 11fc8d9d938c2e254c62a40f569a964db79a489e
+Author: Håvard Espeland <gus at ping.uio.no>
+Date:   Sun May 2 19:12:36 2010 +0200
+
+    Sigma: Set capture ratio correctly.
+
+commit c53d793f037878992a40c37aa4c0f5f5a3d1c2d8
+Author: Håvard Espeland <gus at ping.uio.no>
+Date:   Sun May 2 14:58:59 2010 +0200
+
+    Sigma: 50 MHZ falling/rising edge trigger support.
+    
+    Falling/rising edge and value/mask triggers can be combined, e.g.:
+      --triggers 1=0,2=r,3=1,4=1
+
+commit f758d0744de812ded8938d06a5a72df3f8dd84c1
+Author: Håvard Espeland <gus at ping.uio.no>
+Date:   Sun May 2 12:59:33 2010 +0200
+
+    Sigma: Fix simple trigger LUT calculation.
+
+commit ee492173a1834514dadbec95388c8a0f00e8af64
+Author: Håvard Espeland <gus at ping.uio.no>
+Date:   Sat May 1 22:38:43 2010 +0200
+
+    Sigma: Value/mask trigger support in 50 MHz mode.
+
+commit eec5275e2f3dfa1b9bb51a1b054dc7d8bd3bac20
+Author: Håvard Espeland <gus at ping.uio.no>
+Date:   Sat May 1 14:22:22 2010 +0200
+
+    Sigma: Small cleanups.
+
+commit e65679b15e16d4b898ebdc1456018b9a8d364b1b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sat May 1 02:41:37 2010 +0200
+
+    Saleae: Rename firmware file to saleae-logic.fw.
+    
+    This is done for consistency with the ASIX SIGMA firmware file names,
+    and also for brevity.
+
+commit 34e4813f2e8b75981ed92d625c5fd55146a35e66
+Author: Bert Vermeulen <bert at rogue.biot.com>
+Date:   Fri Apr 30 15:54:39 2010 -0700
+
+    inout module infrastructure + binary input module
+
+commit 5045c217e69d6bbb5ca52c75799a4d64c72bfafd
+Author: Håvard Espeland <gus at ping.uio.no>
+Date:   Fri Apr 30 22:18:55 2010 +0200
+
+    cli: Show trigger event in bits plugin.
+
+commit 57bbf56b8420e75bcad45b417c0d36c0a55a3910
+Author: Håvard Espeland <gus at ping.uio.no>
+Date:   Fri Apr 30 22:18:10 2010 +0200
+
+    Sigma: Add triggers support for 100 and 200 MHz.
+
+commit ed09fd07f7122dd9ade0f15a2b885f33abed86e9
+Author: Håvard Espeland <gus at ping.uio.no>
+Date:   Fri Apr 30 23:51:57 2010 +0200
+
+    Sigma: Minor cleanup and add more samplesrates.
+
+commit 9ddb2a125d0cc01f76acc43670c4609cc4a7b49b
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Apr 29 00:32:44 2010 +0200
+
+    Sigma: Small cosmetic fixes.
+
+commit edca2c5c2261ef4d6862d97e6d28d5a1c148a2f1
+Author: Håvard Espeland <gus at ping.uio.no>
+Date:   Wed Apr 28 22:45:13 2010 +0200
+
+    Sigma: Support for low samplerates
+    
+    Lowest samplerate supported in driver is 250 KHz
+
+commit f78898e947a52e1713f6b2eef66d473e1dfcd7bf
+Author: Håvard Espeland <gus at ping.uio.no>
+Date:   Wed Apr 28 21:21:19 2010 +0200
+
+    Sigma: Support 50 and 200 MHz modes
+
+commit a8116d764ba3fc33bb6719f9e47ba1a5069981d1
+Author: Håvard Espeland <gus at ping.uio.no>
+Date:   Wed Apr 28 21:20:27 2010 +0200
+
+    Sigma: Rename firmware files
+
+commit e8397563a219d07179aa273d30396c3c21fb91ba
+Author: Håvard Espeland <gus at ping.uio.no>
+Date:   Wed Apr 28 20:01:15 2010 +0200
+
+    Sigma: Upload 50, 100 or 200 MHz firmware
+
+commit f6564c8d1933921ee9e34e93effeef8cee4cc3ba
+Author: Håvard Espeland <gus at ping.uio.no>
+Date:   Wed Apr 28 19:48:59 2010 +0200
+
+    Sigma: Move upload firmware into a function
+
+commit fefa18001aa343a476e3742de3ac946ae7ff2709
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Apr 28 00:17:28 2010 +0200
+
+    ASIX SIGMA: Coding style fixes (via indent mostly).
+    
+    Also, end all/most comments with full stop and avoid variable/array
+    definitions in the middle of functions.
+
+commit 204b1629bd4ef6b61c297fd830a3dae9edafc388
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 27 22:46:59 2010 +0200
+
+    asix-sigma.h: Add missing license header.
+
+commit 911f18341b4def1c3184702c555b163de83a0f71
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 27 22:44:15 2010 +0200
+
+    ASIX Sigma: Use common license header format.
+
+commit 28a35d8ab35483b6d50e5b8404542cc11875fa5d
+Author: Håvard Espeland <gus at ping.uio.no>
+Date:   Tue Apr 27 21:43:24 2010 +0200
+
+    This commit adds initial support for the Asix Sigma Logic Analyzer. Currently, only 200 MHz is supported, and only with software trigger. Firmware for the device will be distributed separately, with permission from the vendor.
+    
+    Signed-off-by: Håvard Espeland <gus at ping.uio.no>
+
+commit 926b866cb624cebf2efca098088dba11afa8ae96
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Apr 22 03:39:02 2010 +0200
+
+    Win: Fix compile, serial port code (unfinished).
+
+commit 9601818842c469339038e85b3c110b66d1a31d4b
+Author: Bert Vermeulen <bert at rogue.biot.com>
+Date:   Sun Apr 18 10:57:13 2010 -0700
+
+    simplify code for unused features
+
+commit eee4890f2fac030ea77a31a3c6c478b4cb628011
+Author: Bert Vermeulen <bert at rogue.biot.com>
+Date:   Sat Apr 17 23:07:00 2010 -0700
+
+    fix broken samplerate calculation
+
+commit 9c48090a8816949bccdec612edc165897fe8ce58
+Author: Bert Vermeulen <bert at rogue.biot.com>
+Date:   Sat Apr 17 22:09:33 2010 -0700
+
+    fix double DF_END and libusb timeout
+
+commit 9a4988343fe72bf2e7e5364dbdaa4ce0d4d6c59d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Apr 15 23:24:44 2010 +0200
+
+    Oops, bugfixes.
+
+commit 408e719989d0b4d4408439bf84b87edea8ce85d6
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Apr 15 23:21:30 2010 +0200
+
+    Refactoring and code simplifications.
+
+commit fed16f06e236f3f2ccc25a63ca7ec7a020124fdc
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Apr 15 22:59:43 2010 +0200
+
+    Saleae/Zeroplus: Coding style fixes.
+
+commit 43fc7885d31c1f6af0715b583a9d153ba59eda5c
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Apr 15 22:16:35 2010 +0200
+
+    OLS: Coding style fixes.
+
+commit 986f7270bf871046e5cf1f154b6ed6226f63c7a5
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Apr 15 20:55:57 2010 +0200
+
+    hardware/common: Coding style fixes.
+
+commit 99c1fc59ed59785d44610ac07556143cb1617f01
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Apr 15 20:36:04 2010 +0200
+
+    output: Coding style fixes.
+
+commit 62c820258238485d3352f4a68a65d299b136b792
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Apr 15 20:16:53 2010 +0200
+
+    libsigrok: More coding style fixes.
+
+commit 1b452b8510922bac08db87f8ea769515c795e22f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Apr 15 20:07:16 2010 +0200
+
+    libsigrok: Coding style fixes.
+
+commit d86dc674a204bec034730f303f69cf61984fd819
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Thu Apr 15 19:49:14 2010 +0200
+
+    Fix insufficient braces in KHZ() et al.
+
+commit fdd20b52391b9d491b37fb7d3e157ea5db098062
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 13 00:34:20 2010 +0200
+
+    Add ARRAY_SIZE helper.
+
+commit 02076d69f9505bc20ce0e9f67fa131054d8baeab
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Apr 12 23:21:12 2010 +0200
+
+    Rename "bin" output module to "bits" everywhere.
+
+commit 1c5b9d302c410cdd1cba441f618e0e3f7afa137d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Apr 12 21:22:58 2010 +0200
+
+    Add raw binary output format.
+    
+    Also, rename the "bin" format to "bits" for now to avoid confusion.
+
+commit afc8e4deb68271ba7696e38cc02053b97cfc1a19
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Apr 9 22:18:46 2010 +0200
+
+    Fix all warnings and re-enable -Wextra.
+
+commit 86c5e279085a05c19d1d071831411fb617816ded
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Apr 9 21:20:22 2010 +0200
+
+    zeroplus: Fix compiler warnings.
+
+commit 08cfe6a2b755367eba4098195557f4e8e426eea4
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Apr 9 21:16:11 2010 +0200
+
+    Factor out trigger_helper() to reduce nesting.
+
+commit edf60d0575d039229da3676867a5eb094d0c3c5e
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Apr 9 20:44:51 2010 +0200
+
+    Factor out common ezusb_upload_firmware().
+
+commit 9d2933fbe9719df679cde8fbffde8c191d6a56d3
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Apr 9 20:36:29 2010 +0200
+
+    ezusb.c: Coding style fixes.
+
+commit 904299164f5718109fea2b23bc34e1522c548db4
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Apr 9 20:31:43 2010 +0200
+
+    sl_open_device(): Refactoring to reduce nesting.
+
+commit f6958dabcd0ce8e2613ee6b958bef7c80b9f9e18
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Apr 9 19:25:29 2010 +0200
+
+    Simplify code by reducing nesting level.
+
+commit 6f5f21f996cb06b518739440e7983fa61d61aea1
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Apr 9 19:04:36 2010 +0200
+
+    Coding style fixes, aided by 'indent'.
+    
+    The following shell alias can be used:
+    
+      alias INDENT='indent -npro -kr -i8 -ts8 -sob -l80 -ss -ncs'
+
+commit d02a535e05513ba8d2d4a82b49180d60ef410e1c
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Fri Apr 9 05:15:27 2010 +0200
+
+    move posix-specific serial port comms to serial.c
+
+commit 54dc4bc703f7797a71129ee92412999d6ea64458
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Apr 8 16:58:07 2010 +0200
+
+    switch to SIGROK_ERR
+
+commit 6937bb757e577ba3cf4036d24cc9852159182f47
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Apr 8 16:49:39 2010 +0200
+
+    various fixes, basic acquisition works
+
+commit 54b38f64aa25d1cceebf1b31bcee0f11d67e432c
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Apr 8 16:44:13 2010 +0200
+
+    use strdup() instead of g_strdup()
+
+commit 37aea2d35c981239e630254fe74f0a411bbc34cb
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Thu Apr 8 16:42:22 2010 +0200
+
+    better buffer size calculation
+
+commit d2cd86ac26a00a95cb0497ba5cb807d4587b67ce
+Author: Bert Vermeulen <bert at biot.com>
+Date:   Sun Apr 4 20:51:04 2010 +0200
+
+    fix off-by-one error
+
+commit 25e7d9b115e5ea08be2d92ffe286aa1bf95778f4
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Wed Apr 7 19:43:41 2010 +0200
+
+    Factor out common sigrok_samplerate_string().
+
+commit bc010c054be68082451dd56e586f03038ec7fb45
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 6 15:02:14 2010 +0200
+
+    VCD output: Handle disabled probes correctly.
+
+commit e2ad47b5b0ad98fc99579d4cd9ebee7db2a03d82
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 6 14:38:47 2010 +0200
+
+    Gnuplot output format support.
+
+commit 2b3414a497f639233c824bc930cecf5f17b5a79d
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Tue Apr 6 01:29:32 2010 +0200
+
+    libsigrokdecode: Add initial return code list.
+
+commit e31b636df6651ae17f9bb28c51157a51fc92c421
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Apr 5 16:41:54 2010 +0200
+
+    Start unification of libsigrok return codes.
+    
+    We have SIGROK_OK for functions calls where no errors occured. All
+    error code names start with SIGROK_ERR and are globally unique,
+    negative values.
+    
+    The value SIGROK_ERR is a generic/unspecified error code, all others,
+    such as SIGROK_ERR_MALLOC, refer to a specific error condition.
+    
+    This commit renames the old SIGROK_NOK etc.
+
+commit 5a8fda158bd9cc040b36fb3b016808c59ccf89f3
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Apr 5 16:20:09 2010 +0200
+
+    Allow output_format.init() to return errors.
+
+commit 4c100f3244ad816070fe2e30713705e109d5b4fb
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Mon Apr 5 15:31:39 2010 +0200
+
+    More consistent spelling of "samplerate".
+
+commit 4c9ffa83cf5b63445a1463af18a910a8cc786e31
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Sun Apr 4 13:19:20 2010 +0200
+
+    Initial Value Change Dump (VCD) output support.
+
+commit a695d6c0751494a07493d809520d1ead9b281e7f
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Apr 2 20:26:48 2010 +0200
+
+    Rename libbackend to libsigrok.
+
+commit a1bb33afbde769156ad4bef7a60579da64aebbb7
+Author: Uwe Hermann <uwe at hermann-uwe.de>
+Date:   Fri Apr 2 20:18:27 2010 +0200
+
+    Start of code base layout restructuring.
diff --git a/Doxyfile b/Doxyfile
new file mode 100644
index 0000000..a42748b
--- /dev/null
+++ b/Doxyfile
@@ -0,0 +1,2320 @@
+# Doxyfile 1.8.6
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single 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
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = "libsigrok"
+
+# 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         = "0.3.0"
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          = "sigrok hardware access and backend library"
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
+
+PROJECT_LOGO           = contrib/sigrok-logo-notext.png
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. 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       = doxy
+
+# 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 causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = YES
+
+# 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.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES 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.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES 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.
+# The default value is: YES.
+
+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 and 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.
+# The default value is: NO.
+
+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.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES 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
+# The default value is: YES.
+
+FULL_PATH_NAMES        = YES
+
+# 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.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+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 list of 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.
+# The default value is: NO.
+
+SHORT_NAMES            = YES
+
+# 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-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_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 behavior. 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 behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+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.
+# The default value is: NO.
+
+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.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that act 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                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# 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.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
+# (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# 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);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# 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.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES 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.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# 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 respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+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. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = NO
+
+# 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 only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO 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.
+# The default value is: NO.
+
+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 these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+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 these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+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 these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+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 then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+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.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES 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.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = 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 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.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = 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.
+# The default value is: YES.
+
+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.
+# The default value is: YES.
+
+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.
+# The default value is: YES.
+
+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.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have 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 value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+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.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = NO
+
+# 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. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. Do not use file names with spaces, bibtex cannot handle them. See
+# also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag 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.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag 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.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = YES
+
+# 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)
+# The default value is: $file:$line: $text.
+
+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 standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is 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.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = .
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (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, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS          =
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# 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.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                = config.h libsigrok-internal.h session_driver.c std.c
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+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/*
+
+#
+# Ignore the following files and directories (see also EXCLUDE above):
+#  - config.h: Non-public stuff, the file doesn't get installed.
+#  - libsigrok-internal.h: Non-public stuff, the file doesn't get installed.
+#  - session_driver.c: Special driver for "virtual" devices, non-public.
+#  - std.c: Non-public helpers, no public API stuff in there.
+#  - hardware/*: Only driver-specific stuff, no public API stuff in there.
+#  - input/*: Only input.c contains public API, everything else doesn't.
+#  - output/*: Only output.c contains public API, everything else doesn't.
+#  - tests/*: Unit tests, no public API stuff in there.
+#  - bindings/*: Language bindings, no public API stuff in there.
+#  - doxy/*: Potentially already generated docs, should not be scanned.
+#
+EXCLUDE_PATTERNS       = */hardware/* */input/* */output/* */tests/*
+EXCLUDE_PATTERNS      += */bindings/*
+EXCLUDE_PATTERNS      += */doxy/*
+INPUT                 += input/input.c output/output.c
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# 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.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# 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.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+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 information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# 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 that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES 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 documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = 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.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES 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.
+# See also: Section \class.
+# The default value is: YES.
+
+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.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+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 a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
+
+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.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html-api
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+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 left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
+# defined cascading style sheet that is included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet file to the output directory. For an example
+# see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = YES
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# 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.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# 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.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# 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).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# 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.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value 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
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 1
+
+# 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.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavours of web server based searching depending on the
+# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
+# searching and an index file used by the script. When EXTERNAL_SEARCH is
+# enabled the indexing and searching needs to be provided by external tools. See
+# the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
+
+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.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+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.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+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 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+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. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will
+# replace them by respectively the title of the page, the current date and time,
+# only the current date, the version number of doxygen, the project name (see
+# PROJECT_NAME), or the project number (see PROJECT_NUMBER).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). 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.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# 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.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# 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 too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+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.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+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.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+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 some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+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.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+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. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+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 value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+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.
+# The default value is: NO.
+
+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.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify a XML schema, which can be used by a
+# validating XML parser to check the syntax of the XML files.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify a XML DTD, which can be used by a
+# validating XML parser to check the syntax of the XML files.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+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.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://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.
+# The default value is: NO.
+
+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.
+# The default value is: NO.
+
+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.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+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.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+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.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+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 only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = YES
+
+# 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.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = YES
+
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+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.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+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.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+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 e.g.
+# 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.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+# This gets rid of the SR_API function prefix in the Doxygen output.
+PREDEFINED             = SR_API=
+
+# 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 that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all refrences to 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.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. 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. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have an 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. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
+
+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.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# 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.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = NO
+
+# 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 (see:
+# http://www.graphviz.org/), 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 value is: NO.
+
+HAVE_DOT               = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font n the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is 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 CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is 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.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+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.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES 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.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES 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.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is 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.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = YES
+
+# If the CALLER_GRAPH tag is 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.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = YES
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is 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.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = NO
+
+# The DOT_PATH tag 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.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+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).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# 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 the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# 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).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+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.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = YES
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES
diff --git a/HACKING b/HACKING
new file mode 100644
index 0000000..0e818c2
--- /dev/null
+++ b/HACKING
@@ -0,0 +1,188 @@
+-------------------------------------------------------------------------------
+HACKING
+-------------------------------------------------------------------------------
+
+Coding style
+------------
+
+This project is programmed using the Linux kernel coding style, see
+http://lxr.linux.no/linux/Documentation/CodingStyle for details.
+
+Please use the same style for any code contributions, thanks!
+
+
+Contributions
+-------------
+
+ - Patches should be sent to the development mailinglist at
+   sigrok-devel at lists.sourceforge.net (please subscribe to the list first).
+
+   https://lists.sourceforge.net/lists/listinfo/sigrok-devel
+
+ - Alternatively, you can also clone the git repository and let us know
+   from where to pull/review your changes. You can use gitorious.org,
+   github.com, or any other public git hosting site.
+
+
+Adding a new hardware driver
+----------------------------
+
+The simple, scripted way (recommended):
+---------------------------------------
+
+Use the 'new-driver' script from the sigrok-util repo:
+
+ $ git clone git://sigrok.org/sigrok-util
+ $ cd sigrok-util/source
+ $ ./new-driver "Tondaj SL-814"
+
+The example above generates a patch file against the current libsigrok
+development git tree which adds a simple "stub" driver for your device
+(the Tondaj SL-814 sound level meter in this case).
+
+You can apply it like this:
+
+ $ cd libsigrok
+ $ git am 0001-tondaj-sl-814-Initial-driver-skeleton.patch
+
+You can now edit the files in the hardware/tondaj-sl-814 directory as needed
+and implement your driver based on the skeleton files there. That means your
+patch submission later will consist of at least two patches: the initial one
+adding the skeleton driver, and one or more additional patches that actually
+implement the respective driver code.
+
+
+The manual way:
+---------------
+
+This is a rough overview of what you need to do in order to add a new driver
+(using the Tondaj SL-814 device as example). It's basically what the
+'new-driver' script (see above) does for you:
+
+ - configure.ac:
+   - Add an --enable-tondaj-sl-814 option.
+   - Add "hardware/tondaj-sl-814/Makefile" to the AC_CONFIG_FILES list.
+   - Add and entry for the device in the "Enabled hardware drivers" list
+     at the bottom of the file.
+ - hardware/Makefile.am: Add "tondaj-sl-814" to the SUBDIRS variable.
+ - hwdriver.c: Add a tondaj_sl_814_driver_info entry in two places.
+ - hardware/tondaj-sl-814/ directory: Add the following files:
+   Makefile.am, api.c, protocol.c, protocol.h
+
+See existing drivers or the 'new-driver' output for the details.
+
+
+Random notes
+------------
+
+ - Don't do variable declarations in compound statements, only at the
+   beginning of a function.
+
+ - Generally avoid assigning values to variables at declaration time,
+   especially so for complex and/or run-time dependent values.
+
+ - Consistently use g_try_malloc() / g_try_malloc0(). Do not use standard
+   malloc()/calloc() if it can be avoided (sometimes other libs such
+   as libftdi can return malloc()'d memory, for example).
+
+ - Always properly match allocations with the proper *free() functions. If
+   glib's g_try_malloc()/g_try_malloc0() was used, use g_free() to free the
+   memory. Otherwise use standard free(). Never use the wrong function!
+
+ - Never use g_malloc() or g_malloc0(). These functions do not return NULL
+   if not enough memory is available but rather lead to an exit() or segfault
+   instead. This behaviour is not acceptable for libraries.
+   Use g_try_malloc()/g_try_malloc0() instead and check the return value.
+
+ - You should never print any messages (neither to stdout nor stderr nor
+   elsewhere) "manually" via e.g. printf() or g_log() or similar functions.
+   Only sr_err()/sr_warn()/sr_info()/sr_dbg()/sr_spew() should be used.
+
+ - Use glib's gboolean / TRUE / FALSE for boolean types consistently.
+   Do not use <stdbool.h> and its true / false, and do not invent private
+   definitions for this either.
+
+ - Consistently use the same naming convention for #include guards in headers:
+   <PROJECTNAME>_<PATH_TO_FILE>_<FILE>
+   This ensures that all #include guards are always unique and consistent.
+   Examples: LIBSIGROK_LIBSIGROK_H, LIBSIGROK_HARDWARE_MIC_985XX_PROTOCOL_H
+
+ - Consistently use the same naming convention for API functions:
+   <libprefix>_<groupname>_<action>().
+
+   Examples:
+     sr_log_loglevel_set(), sr_log_loglevel_get(), sr_log_handler_set(),
+     sr_log_handler_set_default(), and so on.
+   Or:
+     sr_session_new(), sr_session_destroy(), sr_session_load(), and so on.
+
+   Getter/setter function names should usually end with "_get" or "_set".
+   Functions creating new "objects" should end with "_new".
+   Functions destroying "objects" should end with "_destroy".
+   Functions adding or removing items (e.g. from lists) should end with
+   either "_add" or "_remove".
+   Functions operating on all items from a list (not on only one of them),
+   should end with "_all", e.g. "_remove_all", "_get_all", and so on.
+   Use "_remove_all" in favor of "_clear" for consistency.
+
+ - All enums should generally use an explicit start number of 10000.
+   If there are multiple "categories" in the enum entries, each category
+   should be 10000 entries apart from the next one. The start of categories
+   are thus 10000, 20000, 30000, and so on.
+
+   Adding items to an enum MUST always append to a "category", never add
+   items in the middle of a category. The order of items MUST NOT be changed.
+   Any of the above would break the ABI.
+
+   The enum item 0 is special and is used as terminator in some lists, thus
+   enums should not use this for "valid" entries (and start at 10000 instead).
+
+
+Doxygen
+-------
+
+ - In Doxygen comments, put an empty line between the block of @param lines
+   and the final @return line. The @param lines themselves (if there is more
+   than one) are not separated by empty lines.
+
+ - Mark private functions (SR_PRIV) with /** @private */, so that Doxygen
+   doesn't include them in the output. Functions that are "static" anyway
+   don't need to be marked like this.
+
+ - Mark private variables/#defines with /** @cond PRIVATE */ and
+   /** @endcond */, so that Doxygen doesn't include them in the output.
+   Variables that are "static" don't need to be marked like this.
+
+ - Mark all public API functions (SR_API) with a @since tag which indicates
+   in which release the respective function was added (e.g. "@since 0.1.0").
+
+   If the function has existed before, but its API changed later, the @since
+   tag should mention only the release when the API last changed.
+
+   Example: The sr_foo() call was added in 0.1.0, but the API changed in
+   the later 0.2.0 release. The docs should read "@since 0.2.0" in that case.
+
+   Non-public functions (static ones, and those marked SR_PRIV) don't need
+   to have @since markers.
+
+   The @since tag should be the last one, i.e. it should come after @param,
+   @return, @see, and so on.
+
+
+Testsuite
+---------
+
+You can run the libsigrok testsuite using:
+
+ $ make check
+
+
+Release engineering
+-------------------
+
+See
+
+ http://sigrok.org/wiki/Developers/Release_process
+
+for a list of items that need to be done when releasing a new tarball.
+
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..2099840
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,370 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation,
+Inc.
+
+   Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved.  This file is offered as-is,
+without warranty of any kind.
+
+Basic Installation
+==================
+
+   Briefly, the shell command `./configure && make && make install'
+should configure, build, and install this package.  The following
+more-detailed instructions are generic; see the `README' file for
+instructions specific to this package.  Some packages provide this
+`INSTALL' file but do not implement all of the features documented
+below.  The lack of an optional feature in a given package is not
+necessarily a bug.  More recommendations for GNU packages can be found
+in *note Makefile Conventions: (standards)Makefile Conventions.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+   It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring.  Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'.  You need `configure.ac' if
+you want to change it or regenerate `configure' using a newer version
+of `autoconf'.
+
+   The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.
+
+     Running `configure' might take a while.  While running, it prints
+     some messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package, generally using the just-built uninstalled binaries.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.  When installing into a prefix owned by root, it is
+     recommended that the package be configured and built as a regular
+     user, and only the `make install' phase executed with root
+     privileges.
+
+  5. Optionally, type `make installcheck' to repeat any self-tests, but
+     this time using the binaries in their final installed location.
+     This target does not install anything.  Running this target as a
+     regular user, particularly if the prior `make install' required
+     root privileges, verifies that the installation completed
+     correctly.
+
+  6. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+  7. Often, you can also type `make uninstall' to remove the installed
+     files again.  In practice, not all packages have tested that
+     uninstallation works correctly, even though it is required by the
+     GNU Coding Standards.
+
+  8. Some packages, particularly those that use Automake, provide `make
+     distcheck', which can by used by developers to test that all other
+     targets like `make install' and `make uninstall' work correctly.
+     This target is generally not run by end users.
+
+Compilers and Options
+=====================
+
+   Some systems require unusual options for compilation or linking that
+the `configure' script does not know about.  Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+   You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here
+is an example:
+
+     ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+   *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+   You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you can use GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.  This
+is known as a "VPATH" build.
+
+   With a non-GNU `make', it is safer to compile the package for one
+architecture at a time in the source code directory.  After you have
+installed the package for one architecture, use `make distclean' before
+reconfiguring for another architecture.
+
+   On MacOS X 10.5 and later systems, you can create libraries and
+executables that work on multiple system types--known as "fat" or
+"universal" binaries--by specifying multiple `-arch' options to the
+compiler but only a single `-arch' option to the preprocessor.  Like
+this:
+
+     ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+                 CPP="gcc -E" CXXCPP="g++ -E"
+
+   This is not guaranteed to produce working output in all cases, you
+may have to build one architecture at a time and combine the results
+using the `lipo' tool if you have problems.
+
+Installation Names
+==================
+
+   By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc.  You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX', where PREFIX must be an
+absolute file name.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.  In general, the
+default for these options is expressed in terms of `${prefix}', so that
+specifying just `--prefix' will affect all of the other directory
+specifications that were not explicitly provided.
+
+   The most portable way to affect installation locations is to pass the
+correct locations to `configure'; however, many packages provide one or
+both of the following shortcuts of passing variable assignments to the
+`make install' command line to change installation locations without
+having to reconfigure or recompile.
+
+   The first method involves providing an override variable for each
+affected directory.  For example, `make install
+prefix=/alternate/directory' will choose an alternate location for all
+directory configuration variables that were expressed in terms of
+`${prefix}'.  Any directories that were specified during `configure',
+but not in terms of `${prefix}', must each be overridden at install
+time for the entire installation to be relocated.  The approach of
+makefile variable overrides for each directory variable is required by
+the GNU Coding Standards, and ideally causes no recompilation.
+However, some platforms have known limitations with the semantics of
+shared libraries that end up requiring recompilation when using this
+method, particularly noticeable in packages that use GNU Libtool.
+
+   The second method involves providing the `DESTDIR' variable.  For
+example, `make install DESTDIR=/alternate/directory' will prepend
+`/alternate/directory' before all installation names.  The approach of
+`DESTDIR' overrides is not required by the GNU Coding Standards, and
+does not work on platforms that have drive letters.  On the other hand,
+it does better at avoiding recompilation issues, and works well even
+when some directory options were not specified in terms of `${prefix}'
+at `configure' time.
+
+Optional Features
+=================
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+   Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+   Some packages offer the ability to configure how verbose the
+execution of `make' will be.  For these packages, running `./configure
+--enable-silent-rules' sets the default to minimal output, which can be
+overridden with `make V=1'; while running `./configure
+--disable-silent-rules' sets the default to verbose, which can be
+overridden with `make V=0'.
+
+Particular systems
+==================
+
+   On HP-UX, the default C compiler is not ANSI C compatible.  If GNU
+CC is not installed, it is recommended to use the following options in
+order to use an ANSI C compiler:
+
+     ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
+
+and if that doesn't work, install pre-built binaries of GCC for HP-UX.
+
+   HP-UX `make' updates targets which have the same time stamps as
+their prerequisites, which makes it generally unusable when shipped
+generated files such as `configure' are involved.  Use GNU `make'
+instead.
+
+   On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
+parse its `<wchar.h>' header file.  The option `-nodtk' can be used as
+a workaround.  If GNU CC is not installed, it is therefore recommended
+to try
+
+     ./configure CC="cc"
+
+and if that doesn't work, try
+
+     ./configure CC="cc -nodtk"
+
+   On Solaris, don't put `/usr/ucb' early in your `PATH'.  This
+directory contains several dysfunctional programs; working variants of
+these programs are available in `/usr/bin'.  So, if you need `/usr/ucb'
+in your `PATH', put it _after_ `/usr/bin'.
+
+   On Haiku, software installed for all users goes in `/boot/common',
+not `/usr/local'.  It is recommended to use the following options:
+
+     ./configure --prefix=/boot/common
+
+Specifying the System Type
+==========================
+
+   There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on.  Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+     CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+     OS
+     KERNEL-OS
+
+   See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+   If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+   If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+   If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+   Variables not defined in a site shell script can be set in the
+environment passed to `configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'.  For example:
+
+     ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf limitation.  Until the limitation is lifted, you can use
+this workaround:
+
+     CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+   `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+     Print a summary of all of the options to `configure', and exit.
+
+`--help=short'
+`--help=recursive'
+     Print a summary of the options unique to this package's
+     `configure', and exit.  The `short' variant lists options used
+     only in the top level, while the `recursive' variant lists options
+     also present in any nested packages.
+
+`--version'
+`-V'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally `config.cache'.  FILE defaults to `/dev/null' to
+     disable caching.
+
+`--config-cache'
+`-C'
+     Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`--prefix=DIR'
+     Use DIR as the installation prefix.  *note Installation Names::
+     for more details, including other options available for fine-tuning
+     the installation locations.
+
+`--no-create'
+`-n'
+     Run the configure checks, but stop before creating any output
+     files.
+
+`configure' also accepts some other, not widely useful, options.  Run
+`configure --help' for more details.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..0bda213
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,365 @@
+##
+## This file is part of the libsigrok project.
+##
+## Copyright (C) 2010-2012 Bert Vermeulen <bert at biot.com>
+## Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me at gmail.com>
+##
+## This program is free software: you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program.  If not, see <http://www.gnu.org/licenses/>.
+##
+
+ACLOCAL_AMFLAGS = -I autostuff
+
+AM_CPPFLAGS = -DFIRMWARE_DIR='"$(FIRMWARE_DIR)"'
+
+lib_LTLIBRARIES = libsigrok.la
+
+# Backend files
+libsigrok_la_SOURCES = \
+	backend.c \
+	device.c \
+	session.c \
+	session_file.c \
+	session_driver.c \
+	hwdriver.c \
+	strutil.c \
+	log.c \
+	version.c \
+	error.c \
+	std.c
+
+# Input formats
+libsigrok_la_SOURCES += \
+	input/binary.c \
+	input/chronovu_la8.c \
+	input/csv.c \
+	input/input.c \
+	input/vcd.c \
+	input/wav.c
+
+# Output formats
+libsigrok_la_SOURCES += \
+	output/output.c \
+	output/analog.c \
+	output/ascii.c \
+	output/bits.c \
+	output/binary.c \
+	output/csv.c \
+	output/chronovu_la8.c \
+	output/gnuplot.c \
+	output/hex.c \
+	output/ols.c \
+	output/vcd.c
+
+# Hardware (common files)
+libsigrok_la_SOURCES += \
+	hardware/common/scpi.c \
+	hardware/common/scpi_tcp.c
+if NEED_RPC
+libsigrok_la_SOURCES += \
+	hardware/common/scpi_vxi.c \
+	hardware/common/vxi_clnt.c \
+	hardware/common/vxi_xdr.c \
+	hardware/common/vxi.h
+endif
+if NEED_SERIAL
+libsigrok_la_SOURCES += \
+	hardware/common/serial.c \
+	hardware/common/scpi_serial.c
+endif
+if NEED_USB
+libsigrok_la_SOURCES += \
+	hardware/common/ezusb.c \
+	hardware/common/usb.c \
+	hardware/common/scpi_usbtmc_libusb.c
+endif
+if NEED_VISA
+libsigrok_la_SOURCES += \
+	hardware/common/scpi_visa.c
+endif
+
+# Hardware (DMM parsers)
+libsigrok_la_SOURCES += \
+	hardware/common/dmm/es519xx.c \
+	hardware/common/dmm/fs9721.c \
+	hardware/common/dmm/fs9922.c \
+	hardware/common/dmm/m2110.c \
+	hardware/common/dmm/metex14.c \
+	hardware/common/dmm/rs9lcd.c
+
+# Hardware drivers
+if HW_AGILENT_DMM
+libsigrok_la_SOURCES += \
+	hardware/agilent-dmm/api.c \
+	hardware/agilent-dmm/agilent-dmm.h \
+	hardware/agilent-dmm/sched.c
+endif
+if HW_APPA_55II
+libsigrok_la_SOURCES += \
+	hardware/appa-55ii/protocol.h \
+	hardware/appa-55ii/protocol.c \
+	hardware/appa-55ii/api.c
+endif
+if HW_ASIX_SIGMA
+libsigrok_la_SOURCES += \
+	hardware/asix-sigma/asix-sigma.h \
+	hardware/asix-sigma/asix-sigma.c
+endif
+if HW_ATTEN_PPS3XXX
+libsigrok_la_SOURCES += \
+	hardware/atten-pps3xxx/protocol.h \
+	hardware/atten-pps3xxx/protocol.c \
+	hardware/atten-pps3xxx/api.c
+endif
+if HW_BRYMEN_BM86X
+libsigrok_la_SOURCES += \
+	hardware/brymen-bm86x/protocol.h \
+	hardware/brymen-bm86x/protocol.c \
+	hardware/brymen-bm86x/api.c
+endif
+if HW_BRYMEN_DMM
+libsigrok_la_SOURCES += \
+	hardware/brymen-dmm/parser.c \
+	hardware/brymen-dmm/protocol.h \
+	hardware/brymen-dmm/protocol.c \
+	hardware/brymen-dmm/api.c
+endif
+if HW_CEM_DT_885X
+libsigrok_la_SOURCES += \
+	hardware/cem-dt-885x/protocol.h \
+	hardware/cem-dt-885x/protocol.c \
+	hardware/cem-dt-885x/api.c
+endif
+if HW_CENTER_3XX
+libsigrok_la_SOURCES += \
+	hardware/center-3xx/protocol.h \
+	hardware/center-3xx/protocol.c \
+	hardware/center-3xx/api.c
+endif
+if HW_CHRONOVU_LA
+libsigrok_la_SOURCES += \
+	hardware/chronovu-la/protocol.h \
+	hardware/chronovu-la/protocol.c \
+	hardware/chronovu-la/api.c
+endif
+if HW_COLEAD_SLM
+libsigrok_la_SOURCES += \
+	hardware/colead-slm/protocol.h \
+	hardware/colead-slm/protocol.c \
+	hardware/colead-slm/api.c
+endif
+if HW_CONRAD_DIGI_35_CPU
+libsigrok_la_SOURCES += \
+	hardware/conrad-digi-35-cpu/protocol.h \
+	hardware/conrad-digi-35-cpu/protocol.c \
+	hardware/conrad-digi-35-cpu/api.c
+endif
+if HW_DEMO
+libsigrok_la_SOURCES += \
+	hardware/demo/demo.c
+endif
+if HW_FLUKE_DMM
+libsigrok_la_SOURCES += \
+	hardware/fluke-dmm/fluke-dmm.h \
+	hardware/fluke-dmm/fluke.c \
+	hardware/fluke-dmm/api.c
+endif
+if HW_FX2LAFW
+libsigrok_la_SOURCES += \
+	hardware/fx2lafw/protocol.h \
+	hardware/fx2lafw/protocol.c \
+	hardware/fx2lafw/api.c
+endif
+if HW_GMC_MH_1X_2X
+libsigrok_la_SOURCES += \
+	hardware/gmc-mh-1x-2x/protocol.h \
+	hardware/gmc-mh-1x-2x/protocol.c \
+	hardware/gmc-mh-1x-2x/api.c
+endif
+if HW_HAMEG_HMO
+libsigrok_la_SOURCES += \
+	hardware/hameg-hmo/protocol.h \
+	hardware/hameg-hmo/protocol.c \
+	hardware/hameg-hmo/api.c
+endif
+if HW_HANTEK_DSO
+libsigrok_la_SOURCES += \
+	hardware/hantek-dso/dso.h \
+	hardware/hantek-dso/dso.c \
+	hardware/hantek-dso/api.c
+endif
+if HW_IKALOGIC_SCANALOGIC2
+libsigrok_la_SOURCES += \
+	hardware/ikalogic-scanalogic2/protocol.h \
+	hardware/ikalogic-scanalogic2/protocol.c \
+	hardware/ikalogic-scanalogic2/api.c
+endif
+if HW_IKALOGIC_SCANAPLUS
+libsigrok_la_SOURCES += \
+	hardware/ikalogic-scanaplus/protocol.h \
+	hardware/ikalogic-scanaplus/protocol.c \
+	hardware/ikalogic-scanaplus/api.c
+endif
+if HW_KECHENG_KC_330B
+libsigrok_la_SOURCES += \
+	hardware/kecheng-kc-330b/protocol.h \
+	hardware/kecheng-kc-330b/protocol.c \
+	hardware/kecheng-kc-330b/api.c
+endif
+if HW_LASCAR_EL_USB
+libsigrok_la_SOURCES += \
+	hardware/lascar-el-usb/protocol.h \
+	hardware/lascar-el-usb/protocol.c \
+	hardware/lascar-el-usb/api.c
+endif
+if HW_MIC_985XX
+libsigrok_la_SOURCES += \
+	hardware/mic-985xx/protocol.h \
+	hardware/mic-985xx/protocol.c \
+	hardware/mic-985xx/api.c
+endif
+if HW_NORMA_DMM
+libsigrok_la_SOURCES += \
+	hardware/norma-dmm/protocol.h \
+	hardware/norma-dmm/protocol.c \
+	hardware/norma-dmm/api.c
+endif
+if HW_OLS
+libsigrok_la_SOURCES += \
+	hardware/openbench-logic-sniffer/protocol.h \
+	hardware/openbench-logic-sniffer/protocol.c \
+	hardware/openbench-logic-sniffer/api.c
+endif
+if HW_RIGOL_DS
+libsigrok_la_SOURCES += \
+	hardware/rigol-ds/protocol.h \
+	hardware/rigol-ds/protocol.c \
+	hardware/rigol-ds/api.c
+endif
+if HW_SALEAE_LOGIC16
+libsigrok_la_SOURCES += \
+	hardware/saleae-logic16/protocol.h \
+	hardware/saleae-logic16/protocol.c \
+	hardware/saleae-logic16/api.c
+endif
+if HW_SERIAL_DMM
+libsigrok_la_SOURCES += \
+	hardware/serial-dmm/protocol.h \
+	hardware/serial-dmm/protocol.c \
+	hardware/serial-dmm/api.c
+endif
+if HW_SYSCLK_LWLA
+libsigrok_la_SOURCES += \
+	hardware/sysclk-lwla/lwla.h \
+	hardware/sysclk-lwla/lwla.c \
+	hardware/sysclk-lwla/protocol.h \
+	hardware/sysclk-lwla/protocol.c \
+	hardware/sysclk-lwla/api.c
+endif
+if HW_TELEINFO
+libsigrok_la_SOURCES += \
+	hardware/teleinfo/protocol.h \
+	hardware/teleinfo/protocol.c \
+	hardware/teleinfo/api.c
+endif
+if HW_TONDAJ_SL_814
+libsigrok_la_SOURCES += \
+	hardware/tondaj-sl-814/protocol.h \
+	hardware/tondaj-sl-814/protocol.c \
+	hardware/tondaj-sl-814/api.c
+endif
+if HW_UNI_T_DMM
+libsigrok_la_SOURCES += \
+	hardware/uni-t-dmm/protocol.h \
+	hardware/uni-t-dmm/protocol.c \
+	hardware/uni-t-dmm/api.c
+endif
+if HW_UNI_T_UT32X
+libsigrok_la_SOURCES += \
+	hardware/uni-t-ut32x/protocol.h \
+	hardware/uni-t-ut32x/protocol.c \
+	hardware/uni-t-ut32x/api.c
+endif
+if HW_VICTOR_DMM
+libsigrok_la_SOURCES += \
+	hardware/victor-dmm/protocol.h \
+	hardware/victor-dmm/protocol.c \
+	hardware/victor-dmm/api.c
+endif
+if HW_ZEROPLUS_LOGIC_CUBE
+libsigrok_la_SOURCES += \
+	hardware/zeroplus-logic-cube/analyzer.c \
+	hardware/zeroplus-logic-cube/analyzer.h \
+	hardware/zeroplus-logic-cube/gl_usb.h \
+	hardware/zeroplus-logic-cube/gl_usb.c \
+	hardware/zeroplus-logic-cube/protocol.h \
+	hardware/zeroplus-logic-cube/protocol.c \
+	hardware/zeroplus-logic-cube/api.c
+endif
+
+libsigrok_la_LIBADD = $(LIBOBJS)
+
+libsigrok_la_LDFLAGS = $(SR_LIB_LDFLAGS)
+
+library_includedir = $(includedir)/libsigrok
+library_include_HEADERS = libsigrok.h proto.h version.h
+noinst_HEADERS = libsigrok-internal.h
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libsigrok.pc
+
+EXTRA_DIST = \
+	Doxyfile \
+	HACKING \
+	README.devices \
+	contrib/gnuplot_chronovu_la8.gpi \
+	contrib/gnuplot_rigol_ds1xx2.gpi \
+	contrib/gnuplot_usbeesx.gpi \
+	contrib/gnuplot_usbeedx8.gpi \
+	contrib/gnuplot_usbeedx16.gpi \
+	contrib/sigrok-logo-notext.png \
+	contrib/z60_libsigrok.rules
+
+if HAVE_CHECK
+
+TESTS = tests/check_main
+
+check_PROGRAMS = ${TESTS}
+
+tests_check_main_SOURCES = \
+	libsigrok.h \
+	tests/lib.c \
+	tests/lib.h \
+	tests/check_main.c \
+	tests/check_core.c \
+	tests/check_input_all.c \
+	tests/check_input_binary.c \
+	tests/check_output_all.c \
+	tests/check_strutil.c \
+	tests/check_version.c \
+	tests/check_driver_all.c
+
+tests_check_main_CFLAGS = @check_CFLAGS@
+
+tests_check_main_LDADD = $(top_builddir)/libsigrok.la @check_LIBS@
+
+endif
+
+MAINTAINERCLEANFILES = ChangeLog
+
+.PHONY: ChangeLog
+ChangeLog:
+	git --git-dir $(top_srcdir)/.git log > ChangeLog || touch ChangeLog
+
+dist-hook: ChangeLog
+
diff --git a/Makefile.in b/Makefile.in
new file mode 100644
index 0000000..2bb50f2
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,2711 @@
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+ at SET_MAKE@
+
+
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+  case $${target_option-} in \
+      ?) ;; \
+      *) echo "am__make_running_with_option: internal error: invalid" \
+              "target option '$${target_option-}' specified" >&2; \
+         exit 1;; \
+  esac; \
+  has_opt=no; \
+  sane_makeflags=$$MAKEFLAGS; \
+  if $(am__is_gnu_make); then \
+    sane_makeflags=$$MFLAGS; \
+  else \
+    case $$MAKEFLAGS in \
+      *\\[\ \	]*) \
+        bs=\\; \
+        sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+          | sed "s/$$bs$$bs[$$bs $$bs	]*//g"`;; \
+    esac; \
+  fi; \
+  skip_next=no; \
+  strip_trailopt () \
+  { \
+    flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+  }; \
+  for flg in $$sane_makeflags; do \
+    test $$skip_next = yes && { skip_next=no; continue; }; \
+    case $$flg in \
+      *=*|--*) continue;; \
+        -*I) strip_trailopt 'I'; skip_next=yes;; \
+      -*I?*) strip_trailopt 'I';; \
+        -*O) strip_trailopt 'O'; skip_next=yes;; \
+      -*O?*) strip_trailopt 'O';; \
+        -*l) strip_trailopt 'l'; skip_next=yes;; \
+      -*l?*) strip_trailopt 'l';; \
+      -[dEDm]) skip_next=yes;; \
+      -[JT]) skip_next=yes;; \
+    esac; \
+    case $$flg in \
+      *$$target_option*) has_opt=yes; break;; \
+    esac; \
+  done; \
+  test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+ at NEED_RPC_TRUE@am__append_1 = \
+ at NEED_RPC_TRUE@	hardware/common/scpi_vxi.c \
+ at NEED_RPC_TRUE@	hardware/common/vxi_clnt.c \
+ at NEED_RPC_TRUE@	hardware/common/vxi_xdr.c \
+ at NEED_RPC_TRUE@	hardware/common/vxi.h
+
+ at NEED_SERIAL_TRUE@am__append_2 = \
+ at NEED_SERIAL_TRUE@	hardware/common/serial.c \
+ at NEED_SERIAL_TRUE@	hardware/common/scpi_serial.c
+
+ at NEED_USB_TRUE@am__append_3 = \
+ at NEED_USB_TRUE@	hardware/common/ezusb.c \
+ at NEED_USB_TRUE@	hardware/common/usb.c \
+ at NEED_USB_TRUE@	hardware/common/scpi_usbtmc_libusb.c
+
+ at NEED_VISA_TRUE@am__append_4 = \
+ at NEED_VISA_TRUE@	hardware/common/scpi_visa.c
+
+
+# Hardware drivers
+ at HW_AGILENT_DMM_TRUE@am__append_5 = \
+ at HW_AGILENT_DMM_TRUE@	hardware/agilent-dmm/api.c \
+ at HW_AGILENT_DMM_TRUE@	hardware/agilent-dmm/agilent-dmm.h \
+ at HW_AGILENT_DMM_TRUE@	hardware/agilent-dmm/sched.c
+
+ at HW_APPA_55II_TRUE@am__append_6 = \
+ at HW_APPA_55II_TRUE@	hardware/appa-55ii/protocol.h \
+ at HW_APPA_55II_TRUE@	hardware/appa-55ii/protocol.c \
+ at HW_APPA_55II_TRUE@	hardware/appa-55ii/api.c
+
+ at HW_ASIX_SIGMA_TRUE@am__append_7 = \
+ at HW_ASIX_SIGMA_TRUE@	hardware/asix-sigma/asix-sigma.h \
+ at HW_ASIX_SIGMA_TRUE@	hardware/asix-sigma/asix-sigma.c
+
+ at HW_ATTEN_PPS3XXX_TRUE@am__append_8 = \
+ at HW_ATTEN_PPS3XXX_TRUE@	hardware/atten-pps3xxx/protocol.h \
+ at HW_ATTEN_PPS3XXX_TRUE@	hardware/atten-pps3xxx/protocol.c \
+ at HW_ATTEN_PPS3XXX_TRUE@	hardware/atten-pps3xxx/api.c
+
+ at HW_BRYMEN_BM86X_TRUE@am__append_9 = \
+ at HW_BRYMEN_BM86X_TRUE@	hardware/brymen-bm86x/protocol.h \
+ at HW_BRYMEN_BM86X_TRUE@	hardware/brymen-bm86x/protocol.c \
+ at HW_BRYMEN_BM86X_TRUE@	hardware/brymen-bm86x/api.c
+
+ at HW_BRYMEN_DMM_TRUE@am__append_10 = \
+ at HW_BRYMEN_DMM_TRUE@	hardware/brymen-dmm/parser.c \
+ at HW_BRYMEN_DMM_TRUE@	hardware/brymen-dmm/protocol.h \
+ at HW_BRYMEN_DMM_TRUE@	hardware/brymen-dmm/protocol.c \
+ at HW_BRYMEN_DMM_TRUE@	hardware/brymen-dmm/api.c
+
+ at HW_CEM_DT_885X_TRUE@am__append_11 = \
+ at HW_CEM_DT_885X_TRUE@	hardware/cem-dt-885x/protocol.h \
+ at HW_CEM_DT_885X_TRUE@	hardware/cem-dt-885x/protocol.c \
+ at HW_CEM_DT_885X_TRUE@	hardware/cem-dt-885x/api.c
+
+ at HW_CENTER_3XX_TRUE@am__append_12 = \
+ at HW_CENTER_3XX_TRUE@	hardware/center-3xx/protocol.h \
+ at HW_CENTER_3XX_TRUE@	hardware/center-3xx/protocol.c \
+ at HW_CENTER_3XX_TRUE@	hardware/center-3xx/api.c
+
+ at HW_CHRONOVU_LA_TRUE@am__append_13 = \
+ at HW_CHRONOVU_LA_TRUE@	hardware/chronovu-la/protocol.h \
+ at HW_CHRONOVU_LA_TRUE@	hardware/chronovu-la/protocol.c \
+ at HW_CHRONOVU_LA_TRUE@	hardware/chronovu-la/api.c
+
+ at HW_COLEAD_SLM_TRUE@am__append_14 = \
+ at HW_COLEAD_SLM_TRUE@	hardware/colead-slm/protocol.h \
+ at HW_COLEAD_SLM_TRUE@	hardware/colead-slm/protocol.c \
+ at HW_COLEAD_SLM_TRUE@	hardware/colead-slm/api.c
+
+ at HW_CONRAD_DIGI_35_CPU_TRUE@am__append_15 = \
+ at HW_CONRAD_DIGI_35_CPU_TRUE@	hardware/conrad-digi-35-cpu/protocol.h \
+ at HW_CONRAD_DIGI_35_CPU_TRUE@	hardware/conrad-digi-35-cpu/protocol.c \
+ at HW_CONRAD_DIGI_35_CPU_TRUE@	hardware/conrad-digi-35-cpu/api.c
+
+ at HW_DEMO_TRUE@am__append_16 = \
+ at HW_DEMO_TRUE@	hardware/demo/demo.c
+
+ at HW_FLUKE_DMM_TRUE@am__append_17 = \
+ at HW_FLUKE_DMM_TRUE@	hardware/fluke-dmm/fluke-dmm.h \
+ at HW_FLUKE_DMM_TRUE@	hardware/fluke-dmm/fluke.c \
+ at HW_FLUKE_DMM_TRUE@	hardware/fluke-dmm/api.c
+
+ at HW_FX2LAFW_TRUE@am__append_18 = \
+ at HW_FX2LAFW_TRUE@	hardware/fx2lafw/protocol.h \
+ at HW_FX2LAFW_TRUE@	hardware/fx2lafw/protocol.c \
+ at HW_FX2LAFW_TRUE@	hardware/fx2lafw/api.c
+
+ at HW_GMC_MH_1X_2X_TRUE@am__append_19 = \
+ at HW_GMC_MH_1X_2X_TRUE@	hardware/gmc-mh-1x-2x/protocol.h \
+ at HW_GMC_MH_1X_2X_TRUE@	hardware/gmc-mh-1x-2x/protocol.c \
+ at HW_GMC_MH_1X_2X_TRUE@	hardware/gmc-mh-1x-2x/api.c
+
+ at HW_HAMEG_HMO_TRUE@am__append_20 = \
+ at HW_HAMEG_HMO_TRUE@	hardware/hameg-hmo/protocol.h \
+ at HW_HAMEG_HMO_TRUE@	hardware/hameg-hmo/protocol.c \
+ at HW_HAMEG_HMO_TRUE@	hardware/hameg-hmo/api.c
+
+ at HW_HANTEK_DSO_TRUE@am__append_21 = \
+ at HW_HANTEK_DSO_TRUE@	hardware/hantek-dso/dso.h \
+ at HW_HANTEK_DSO_TRUE@	hardware/hantek-dso/dso.c \
+ at HW_HANTEK_DSO_TRUE@	hardware/hantek-dso/api.c
+
+ at HW_IKALOGIC_SCANALOGIC2_TRUE@am__append_22 = \
+ at HW_IKALOGIC_SCANALOGIC2_TRUE@	hardware/ikalogic-scanalogic2/protocol.h \
+ at HW_IKALOGIC_SCANALOGIC2_TRUE@	hardware/ikalogic-scanalogic2/protocol.c \
+ at HW_IKALOGIC_SCANALOGIC2_TRUE@	hardware/ikalogic-scanalogic2/api.c
+
+ at HW_IKALOGIC_SCANAPLUS_TRUE@am__append_23 = \
+ at HW_IKALOGIC_SCANAPLUS_TRUE@	hardware/ikalogic-scanaplus/protocol.h \
+ at HW_IKALOGIC_SCANAPLUS_TRUE@	hardware/ikalogic-scanaplus/protocol.c \
+ at HW_IKALOGIC_SCANAPLUS_TRUE@	hardware/ikalogic-scanaplus/api.c
+
+ at HW_KECHENG_KC_330B_TRUE@am__append_24 = \
+ at HW_KECHENG_KC_330B_TRUE@	hardware/kecheng-kc-330b/protocol.h \
+ at HW_KECHENG_KC_330B_TRUE@	hardware/kecheng-kc-330b/protocol.c \
+ at HW_KECHENG_KC_330B_TRUE@	hardware/kecheng-kc-330b/api.c
+
+ at HW_LASCAR_EL_USB_TRUE@am__append_25 = \
+ at HW_LASCAR_EL_USB_TRUE@	hardware/lascar-el-usb/protocol.h \
+ at HW_LASCAR_EL_USB_TRUE@	hardware/lascar-el-usb/protocol.c \
+ at HW_LASCAR_EL_USB_TRUE@	hardware/lascar-el-usb/api.c
+
+ at HW_MIC_985XX_TRUE@am__append_26 = \
+ at HW_MIC_985XX_TRUE@	hardware/mic-985xx/protocol.h \
+ at HW_MIC_985XX_TRUE@	hardware/mic-985xx/protocol.c \
+ at HW_MIC_985XX_TRUE@	hardware/mic-985xx/api.c
+
+ at HW_NORMA_DMM_TRUE@am__append_27 = \
+ at HW_NORMA_DMM_TRUE@	hardware/norma-dmm/protocol.h \
+ at HW_NORMA_DMM_TRUE@	hardware/norma-dmm/protocol.c \
+ at HW_NORMA_DMM_TRUE@	hardware/norma-dmm/api.c
+
+ at HW_OLS_TRUE@am__append_28 = \
+ at HW_OLS_TRUE@	hardware/openbench-logic-sniffer/protocol.h \
+ at HW_OLS_TRUE@	hardware/openbench-logic-sniffer/protocol.c \
+ at HW_OLS_TRUE@	hardware/openbench-logic-sniffer/api.c
+
+ at HW_RIGOL_DS_TRUE@am__append_29 = \
+ at HW_RIGOL_DS_TRUE@	hardware/rigol-ds/protocol.h \
+ at HW_RIGOL_DS_TRUE@	hardware/rigol-ds/protocol.c \
+ at HW_RIGOL_DS_TRUE@	hardware/rigol-ds/api.c
+
+ at HW_SALEAE_LOGIC16_TRUE@am__append_30 = \
+ at HW_SALEAE_LOGIC16_TRUE@	hardware/saleae-logic16/protocol.h \
+ at HW_SALEAE_LOGIC16_TRUE@	hardware/saleae-logic16/protocol.c \
+ at HW_SALEAE_LOGIC16_TRUE@	hardware/saleae-logic16/api.c
+
+ at HW_SERIAL_DMM_TRUE@am__append_31 = \
+ at HW_SERIAL_DMM_TRUE@	hardware/serial-dmm/protocol.h \
+ at HW_SERIAL_DMM_TRUE@	hardware/serial-dmm/protocol.c \
+ at HW_SERIAL_DMM_TRUE@	hardware/serial-dmm/api.c
+
+ at HW_SYSCLK_LWLA_TRUE@am__append_32 = \
+ at HW_SYSCLK_LWLA_TRUE@	hardware/sysclk-lwla/lwla.h \
+ at HW_SYSCLK_LWLA_TRUE@	hardware/sysclk-lwla/lwla.c \
+ at HW_SYSCLK_LWLA_TRUE@	hardware/sysclk-lwla/protocol.h \
+ at HW_SYSCLK_LWLA_TRUE@	hardware/sysclk-lwla/protocol.c \
+ at HW_SYSCLK_LWLA_TRUE@	hardware/sysclk-lwla/api.c
+
+ at HW_TELEINFO_TRUE@am__append_33 = \
+ at HW_TELEINFO_TRUE@	hardware/teleinfo/protocol.h \
+ at HW_TELEINFO_TRUE@	hardware/teleinfo/protocol.c \
+ at HW_TELEINFO_TRUE@	hardware/teleinfo/api.c
+
+ at HW_TONDAJ_SL_814_TRUE@am__append_34 = \
+ at HW_TONDAJ_SL_814_TRUE@	hardware/tondaj-sl-814/protocol.h \
+ at HW_TONDAJ_SL_814_TRUE@	hardware/tondaj-sl-814/protocol.c \
+ at HW_TONDAJ_SL_814_TRUE@	hardware/tondaj-sl-814/api.c
+
+ at HW_UNI_T_DMM_TRUE@am__append_35 = \
+ at HW_UNI_T_DMM_TRUE@	hardware/uni-t-dmm/protocol.h \
+ at HW_UNI_T_DMM_TRUE@	hardware/uni-t-dmm/protocol.c \
+ at HW_UNI_T_DMM_TRUE@	hardware/uni-t-dmm/api.c
+
+ at HW_UNI_T_UT32X_TRUE@am__append_36 = \
+ at HW_UNI_T_UT32X_TRUE@	hardware/uni-t-ut32x/protocol.h \
+ at HW_UNI_T_UT32X_TRUE@	hardware/uni-t-ut32x/protocol.c \
+ at HW_UNI_T_UT32X_TRUE@	hardware/uni-t-ut32x/api.c
+
+ at HW_VICTOR_DMM_TRUE@am__append_37 = \
+ at HW_VICTOR_DMM_TRUE@	hardware/victor-dmm/protocol.h \
+ at HW_VICTOR_DMM_TRUE@	hardware/victor-dmm/protocol.c \
+ at HW_VICTOR_DMM_TRUE@	hardware/victor-dmm/api.c
+
+ at HW_ZEROPLUS_LOGIC_CUBE_TRUE@am__append_38 = \
+ at HW_ZEROPLUS_LOGIC_CUBE_TRUE@	hardware/zeroplus-logic-cube/analyzer.c \
+ at HW_ZEROPLUS_LOGIC_CUBE_TRUE@	hardware/zeroplus-logic-cube/analyzer.h \
+ at HW_ZEROPLUS_LOGIC_CUBE_TRUE@	hardware/zeroplus-logic-cube/gl_usb.h \
+ at HW_ZEROPLUS_LOGIC_CUBE_TRUE@	hardware/zeroplus-logic-cube/gl_usb.c \
+ at HW_ZEROPLUS_LOGIC_CUBE_TRUE@	hardware/zeroplus-logic-cube/protocol.h \
+ at HW_ZEROPLUS_LOGIC_CUBE_TRUE@	hardware/zeroplus-logic-cube/protocol.c \
+ at HW_ZEROPLUS_LOGIC_CUBE_TRUE@	hardware/zeroplus-logic-cube/api.c
+
+ at HAVE_CHECK_TRUE@TESTS = tests/check_main$(EXEEXT)
+ at HAVE_CHECK_TRUE@check_PROGRAMS = $(am__EXEEXT_1)
+subdir = .
+DIST_COMMON = INSTALL NEWS README AUTHORS ChangeLog \
+	$(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+	$(top_srcdir)/configure $(am__configure_deps) \
+	$(srcdir)/config.h.in $(srcdir)/version.h.in \
+	$(srcdir)/libsigrok.pc.in $(top_srcdir)/autostuff/depcomp \
+	$(library_include_HEADERS) $(noinst_HEADERS) \
+	$(top_srcdir)/autostuff/test-driver COPYING autostuff/ar-lib \
+	autostuff/compile autostuff/config.guess autostuff/config.sub \
+	autostuff/depcomp autostuff/install-sh autostuff/missing \
+	autostuff/ltmain.sh $(top_srcdir)/autostuff/ar-lib \
+	$(top_srcdir)/autostuff/compile \
+	$(top_srcdir)/autostuff/config.guess \
+	$(top_srcdir)/autostuff/config.sub \
+	$(top_srcdir)/autostuff/install-sh \
+	$(top_srcdir)/autostuff/ltmain.sh \
+	$(top_srcdir)/autostuff/missing
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/autostuff/libtool.m4 \
+	$(top_srcdir)/autostuff/ltoptions.m4 \
+	$(top_srcdir)/autostuff/ltsugar.m4 \
+	$(top_srcdir)/autostuff/ltversion.m4 \
+	$(top_srcdir)/autostuff/lt~obsolete.m4 \
+	$(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES = version.h libsigrok.pc
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+    $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+    *) f=$$p;; \
+  esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+  srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+  for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+  for p in $$list; do echo "$$p $$p"; done | \
+  sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+  $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+    if (++n[$$2] == $(am__install_max)) \
+      { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+    END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+  sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+  sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+  test -z "$$files" \
+    || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+    || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+         $(am__cd) "$$dir" && rm -f $$files; }; \
+  }
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgconfigdir)" \
+	"$(DESTDIR)$(library_includedir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+libsigrok_la_DEPENDENCIES = $(LIBOBJS)
+am__libsigrok_la_SOURCES_DIST = backend.c device.c session.c \
+	session_file.c session_driver.c hwdriver.c strutil.c log.c \
+	version.c error.c std.c input/binary.c input/chronovu_la8.c \
+	input/csv.c input/input.c input/vcd.c input/wav.c \
+	output/output.c output/analog.c output/ascii.c output/bits.c \
+	output/binary.c output/csv.c output/chronovu_la8.c \
+	output/gnuplot.c output/hex.c output/ols.c output/vcd.c \
+	hardware/common/scpi.c hardware/common/scpi_tcp.c \
+	hardware/common/scpi_vxi.c hardware/common/vxi_clnt.c \
+	hardware/common/vxi_xdr.c hardware/common/vxi.h \
+	hardware/common/serial.c hardware/common/scpi_serial.c \
+	hardware/common/ezusb.c hardware/common/usb.c \
+	hardware/common/scpi_usbtmc_libusb.c \
+	hardware/common/scpi_visa.c hardware/common/dmm/es519xx.c \
+	hardware/common/dmm/fs9721.c hardware/common/dmm/fs9922.c \
+	hardware/common/dmm/m2110.c hardware/common/dmm/metex14.c \
+	hardware/common/dmm/rs9lcd.c hardware/agilent-dmm/api.c \
+	hardware/agilent-dmm/agilent-dmm.h \
+	hardware/agilent-dmm/sched.c hardware/appa-55ii/protocol.h \
+	hardware/appa-55ii/protocol.c hardware/appa-55ii/api.c \
+	hardware/asix-sigma/asix-sigma.h \
+	hardware/asix-sigma/asix-sigma.c \
+	hardware/atten-pps3xxx/protocol.h \
+	hardware/atten-pps3xxx/protocol.c hardware/atten-pps3xxx/api.c \
+	hardware/brymen-bm86x/protocol.h \
+	hardware/brymen-bm86x/protocol.c hardware/brymen-bm86x/api.c \
+	hardware/brymen-dmm/parser.c hardware/brymen-dmm/protocol.h \
+	hardware/brymen-dmm/protocol.c hardware/brymen-dmm/api.c \
+	hardware/cem-dt-885x/protocol.h \
+	hardware/cem-dt-885x/protocol.c hardware/cem-dt-885x/api.c \
+	hardware/center-3xx/protocol.h hardware/center-3xx/protocol.c \
+	hardware/center-3xx/api.c hardware/chronovu-la/protocol.h \
+	hardware/chronovu-la/protocol.c hardware/chronovu-la/api.c \
+	hardware/colead-slm/protocol.h hardware/colead-slm/protocol.c \
+	hardware/colead-slm/api.c \
+	hardware/conrad-digi-35-cpu/protocol.h \
+	hardware/conrad-digi-35-cpu/protocol.c \
+	hardware/conrad-digi-35-cpu/api.c hardware/demo/demo.c \
+	hardware/fluke-dmm/fluke-dmm.h hardware/fluke-dmm/fluke.c \
+	hardware/fluke-dmm/api.c hardware/fx2lafw/protocol.h \
+	hardware/fx2lafw/protocol.c hardware/fx2lafw/api.c \
+	hardware/gmc-mh-1x-2x/protocol.h \
+	hardware/gmc-mh-1x-2x/protocol.c hardware/gmc-mh-1x-2x/api.c \
+	hardware/hameg-hmo/protocol.h hardware/hameg-hmo/protocol.c \
+	hardware/hameg-hmo/api.c hardware/hantek-dso/dso.h \
+	hardware/hantek-dso/dso.c hardware/hantek-dso/api.c \
+	hardware/ikalogic-scanalogic2/protocol.h \
+	hardware/ikalogic-scanalogic2/protocol.c \
+	hardware/ikalogic-scanalogic2/api.c \
+	hardware/ikalogic-scanaplus/protocol.h \
+	hardware/ikalogic-scanaplus/protocol.c \
+	hardware/ikalogic-scanaplus/api.c \
+	hardware/kecheng-kc-330b/protocol.h \
+	hardware/kecheng-kc-330b/protocol.c \
+	hardware/kecheng-kc-330b/api.c \
+	hardware/lascar-el-usb/protocol.h \
+	hardware/lascar-el-usb/protocol.c hardware/lascar-el-usb/api.c \
+	hardware/mic-985xx/protocol.h hardware/mic-985xx/protocol.c \
+	hardware/mic-985xx/api.c hardware/norma-dmm/protocol.h \
+	hardware/norma-dmm/protocol.c hardware/norma-dmm/api.c \
+	hardware/openbench-logic-sniffer/protocol.h \
+	hardware/openbench-logic-sniffer/protocol.c \
+	hardware/openbench-logic-sniffer/api.c \
+	hardware/rigol-ds/protocol.h hardware/rigol-ds/protocol.c \
+	hardware/rigol-ds/api.c hardware/saleae-logic16/protocol.h \
+	hardware/saleae-logic16/protocol.c \
+	hardware/saleae-logic16/api.c hardware/serial-dmm/protocol.h \
+	hardware/serial-dmm/protocol.c hardware/serial-dmm/api.c \
+	hardware/sysclk-lwla/lwla.h hardware/sysclk-lwla/lwla.c \
+	hardware/sysclk-lwla/protocol.h \
+	hardware/sysclk-lwla/protocol.c hardware/sysclk-lwla/api.c \
+	hardware/teleinfo/protocol.h hardware/teleinfo/protocol.c \
+	hardware/teleinfo/api.c hardware/tondaj-sl-814/protocol.h \
+	hardware/tondaj-sl-814/protocol.c hardware/tondaj-sl-814/api.c \
+	hardware/uni-t-dmm/protocol.h hardware/uni-t-dmm/protocol.c \
+	hardware/uni-t-dmm/api.c hardware/uni-t-ut32x/protocol.h \
+	hardware/uni-t-ut32x/protocol.c hardware/uni-t-ut32x/api.c \
+	hardware/victor-dmm/protocol.h hardware/victor-dmm/protocol.c \
+	hardware/victor-dmm/api.c \
+	hardware/zeroplus-logic-cube/analyzer.c \
+	hardware/zeroplus-logic-cube/analyzer.h \
+	hardware/zeroplus-logic-cube/gl_usb.h \
+	hardware/zeroplus-logic-cube/gl_usb.c \
+	hardware/zeroplus-logic-cube/protocol.h \
+	hardware/zeroplus-logic-cube/protocol.c \
+	hardware/zeroplus-logic-cube/api.c
+am__dirstamp = $(am__leading_dot)dirstamp
+ at NEED_RPC_TRUE@am__objects_1 = hardware/common/scpi_vxi.lo \
+ at NEED_RPC_TRUE@	hardware/common/vxi_clnt.lo \
+ at NEED_RPC_TRUE@	hardware/common/vxi_xdr.lo
+ at NEED_SERIAL_TRUE@am__objects_2 = hardware/common/serial.lo \
+ at NEED_SERIAL_TRUE@	hardware/common/scpi_serial.lo
+ at NEED_USB_TRUE@am__objects_3 = hardware/common/ezusb.lo \
+ at NEED_USB_TRUE@	hardware/common/usb.lo \
+ at NEED_USB_TRUE@	hardware/common/scpi_usbtmc_libusb.lo
+ at NEED_VISA_TRUE@am__objects_4 = hardware/common/scpi_visa.lo
+ at HW_AGILENT_DMM_TRUE@am__objects_5 = hardware/agilent-dmm/api.lo \
+ at HW_AGILENT_DMM_TRUE@	hardware/agilent-dmm/sched.lo
+ at HW_APPA_55II_TRUE@am__objects_6 = hardware/appa-55ii/protocol.lo \
+ at HW_APPA_55II_TRUE@	hardware/appa-55ii/api.lo
+ at HW_ASIX_SIGMA_TRUE@am__objects_7 = hardware/asix-sigma/asix-sigma.lo
+ at HW_ATTEN_PPS3XXX_TRUE@am__objects_8 =  \
+ at HW_ATTEN_PPS3XXX_TRUE@	hardware/atten-pps3xxx/protocol.lo \
+ at HW_ATTEN_PPS3XXX_TRUE@	hardware/atten-pps3xxx/api.lo
+ at HW_BRYMEN_BM86X_TRUE@am__objects_9 =  \
+ at HW_BRYMEN_BM86X_TRUE@	hardware/brymen-bm86x/protocol.lo \
+ at HW_BRYMEN_BM86X_TRUE@	hardware/brymen-bm86x/api.lo
+ at HW_BRYMEN_DMM_TRUE@am__objects_10 = hardware/brymen-dmm/parser.lo \
+ at HW_BRYMEN_DMM_TRUE@	hardware/brymen-dmm/protocol.lo \
+ at HW_BRYMEN_DMM_TRUE@	hardware/brymen-dmm/api.lo
+ at HW_CEM_DT_885X_TRUE@am__objects_11 =  \
+ at HW_CEM_DT_885X_TRUE@	hardware/cem-dt-885x/protocol.lo \
+ at HW_CEM_DT_885X_TRUE@	hardware/cem-dt-885x/api.lo
+ at HW_CENTER_3XX_TRUE@am__objects_12 = hardware/center-3xx/protocol.lo \
+ at HW_CENTER_3XX_TRUE@	hardware/center-3xx/api.lo
+ at HW_CHRONOVU_LA_TRUE@am__objects_13 =  \
+ at HW_CHRONOVU_LA_TRUE@	hardware/chronovu-la/protocol.lo \
+ at HW_CHRONOVU_LA_TRUE@	hardware/chronovu-la/api.lo
+ at HW_COLEAD_SLM_TRUE@am__objects_14 = hardware/colead-slm/protocol.lo \
+ at HW_COLEAD_SLM_TRUE@	hardware/colead-slm/api.lo
+ at HW_CONRAD_DIGI_35_CPU_TRUE@am__objects_15 = hardware/conrad-digi-35-cpu/protocol.lo \
+ at HW_CONRAD_DIGI_35_CPU_TRUE@	hardware/conrad-digi-35-cpu/api.lo
+ at HW_DEMO_TRUE@am__objects_16 = hardware/demo/demo.lo
+ at HW_FLUKE_DMM_TRUE@am__objects_17 = hardware/fluke-dmm/fluke.lo \
+ at HW_FLUKE_DMM_TRUE@	hardware/fluke-dmm/api.lo
+ at HW_FX2LAFW_TRUE@am__objects_18 = hardware/fx2lafw/protocol.lo \
+ at HW_FX2LAFW_TRUE@	hardware/fx2lafw/api.lo
+ at HW_GMC_MH_1X_2X_TRUE@am__objects_19 =  \
+ at HW_GMC_MH_1X_2X_TRUE@	hardware/gmc-mh-1x-2x/protocol.lo \
+ at HW_GMC_MH_1X_2X_TRUE@	hardware/gmc-mh-1x-2x/api.lo
+ at HW_HAMEG_HMO_TRUE@am__objects_20 = hardware/hameg-hmo/protocol.lo \
+ at HW_HAMEG_HMO_TRUE@	hardware/hameg-hmo/api.lo
+ at HW_HANTEK_DSO_TRUE@am__objects_21 = hardware/hantek-dso/dso.lo \
+ at HW_HANTEK_DSO_TRUE@	hardware/hantek-dso/api.lo
+ at HW_IKALOGIC_SCANALOGIC2_TRUE@am__objects_22 = hardware/ikalogic-scanalogic2/protocol.lo \
+ at HW_IKALOGIC_SCANALOGIC2_TRUE@	hardware/ikalogic-scanalogic2/api.lo
+ at HW_IKALOGIC_SCANAPLUS_TRUE@am__objects_23 = hardware/ikalogic-scanaplus/protocol.lo \
+ at HW_IKALOGIC_SCANAPLUS_TRUE@	hardware/ikalogic-scanaplus/api.lo
+ at HW_KECHENG_KC_330B_TRUE@am__objects_24 =  \
+ at HW_KECHENG_KC_330B_TRUE@	hardware/kecheng-kc-330b/protocol.lo \
+ at HW_KECHENG_KC_330B_TRUE@	hardware/kecheng-kc-330b/api.lo
+ at HW_LASCAR_EL_USB_TRUE@am__objects_25 =  \
+ at HW_LASCAR_EL_USB_TRUE@	hardware/lascar-el-usb/protocol.lo \
+ at HW_LASCAR_EL_USB_TRUE@	hardware/lascar-el-usb/api.lo
+ at HW_MIC_985XX_TRUE@am__objects_26 = hardware/mic-985xx/protocol.lo \
+ at HW_MIC_985XX_TRUE@	hardware/mic-985xx/api.lo
+ at HW_NORMA_DMM_TRUE@am__objects_27 = hardware/norma-dmm/protocol.lo \
+ at HW_NORMA_DMM_TRUE@	hardware/norma-dmm/api.lo
+ at HW_OLS_TRUE@am__objects_28 =  \
+ at HW_OLS_TRUE@	hardware/openbench-logic-sniffer/protocol.lo \
+ at HW_OLS_TRUE@	hardware/openbench-logic-sniffer/api.lo
+ at HW_RIGOL_DS_TRUE@am__objects_29 = hardware/rigol-ds/protocol.lo \
+ at HW_RIGOL_DS_TRUE@	hardware/rigol-ds/api.lo
+ at HW_SALEAE_LOGIC16_TRUE@am__objects_30 =  \
+ at HW_SALEAE_LOGIC16_TRUE@	hardware/saleae-logic16/protocol.lo \
+ at HW_SALEAE_LOGIC16_TRUE@	hardware/saleae-logic16/api.lo
+ at HW_SERIAL_DMM_TRUE@am__objects_31 = hardware/serial-dmm/protocol.lo \
+ at HW_SERIAL_DMM_TRUE@	hardware/serial-dmm/api.lo
+ at HW_SYSCLK_LWLA_TRUE@am__objects_32 = hardware/sysclk-lwla/lwla.lo \
+ at HW_SYSCLK_LWLA_TRUE@	hardware/sysclk-lwla/protocol.lo \
+ at HW_SYSCLK_LWLA_TRUE@	hardware/sysclk-lwla/api.lo
+ at HW_TELEINFO_TRUE@am__objects_33 = hardware/teleinfo/protocol.lo \
+ at HW_TELEINFO_TRUE@	hardware/teleinfo/api.lo
+ at HW_TONDAJ_SL_814_TRUE@am__objects_34 =  \
+ at HW_TONDAJ_SL_814_TRUE@	hardware/tondaj-sl-814/protocol.lo \
+ at HW_TONDAJ_SL_814_TRUE@	hardware/tondaj-sl-814/api.lo
+ at HW_UNI_T_DMM_TRUE@am__objects_35 = hardware/uni-t-dmm/protocol.lo \
+ at HW_UNI_T_DMM_TRUE@	hardware/uni-t-dmm/api.lo
+ at HW_UNI_T_UT32X_TRUE@am__objects_36 =  \
+ at HW_UNI_T_UT32X_TRUE@	hardware/uni-t-ut32x/protocol.lo \
+ at HW_UNI_T_UT32X_TRUE@	hardware/uni-t-ut32x/api.lo
+ at HW_VICTOR_DMM_TRUE@am__objects_37 = hardware/victor-dmm/protocol.lo \
+ at HW_VICTOR_DMM_TRUE@	hardware/victor-dmm/api.lo
+ at HW_ZEROPLUS_LOGIC_CUBE_TRUE@am__objects_38 = hardware/zeroplus-logic-cube/analyzer.lo \
+ at HW_ZEROPLUS_LOGIC_CUBE_TRUE@	hardware/zeroplus-logic-cube/gl_usb.lo \
+ at HW_ZEROPLUS_LOGIC_CUBE_TRUE@	hardware/zeroplus-logic-cube/protocol.lo \
+ at HW_ZEROPLUS_LOGIC_CUBE_TRUE@	hardware/zeroplus-logic-cube/api.lo
+am_libsigrok_la_OBJECTS = backend.lo device.lo session.lo \
+	session_file.lo session_driver.lo hwdriver.lo strutil.lo \
+	log.lo version.lo error.lo std.lo input/binary.lo \
+	input/chronovu_la8.lo input/csv.lo input/input.lo input/vcd.lo \
+	input/wav.lo output/output.lo output/analog.lo output/ascii.lo \
+	output/bits.lo output/binary.lo output/csv.lo \
+	output/chronovu_la8.lo output/gnuplot.lo output/hex.lo \
+	output/ols.lo output/vcd.lo hardware/common/scpi.lo \
+	hardware/common/scpi_tcp.lo $(am__objects_1) $(am__objects_2) \
+	$(am__objects_3) $(am__objects_4) \
+	hardware/common/dmm/es519xx.lo hardware/common/dmm/fs9721.lo \
+	hardware/common/dmm/fs9922.lo hardware/common/dmm/m2110.lo \
+	hardware/common/dmm/metex14.lo hardware/common/dmm/rs9lcd.lo \
+	$(am__objects_5) $(am__objects_6) $(am__objects_7) \
+	$(am__objects_8) $(am__objects_9) $(am__objects_10) \
+	$(am__objects_11) $(am__objects_12) $(am__objects_13) \
+	$(am__objects_14) $(am__objects_15) $(am__objects_16) \
+	$(am__objects_17) $(am__objects_18) $(am__objects_19) \
+	$(am__objects_20) $(am__objects_21) $(am__objects_22) \
+	$(am__objects_23) $(am__objects_24) $(am__objects_25) \
+	$(am__objects_26) $(am__objects_27) $(am__objects_28) \
+	$(am__objects_29) $(am__objects_30) $(am__objects_31) \
+	$(am__objects_32) $(am__objects_33) $(am__objects_34) \
+	$(am__objects_35) $(am__objects_36) $(am__objects_37) \
+	$(am__objects_38)
+libsigrok_la_OBJECTS = $(am_libsigrok_la_OBJECTS)
+AM_V_lt = $(am__v_lt_ at AM_V@)
+am__v_lt_ = $(am__v_lt_ at AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 = 
+libsigrok_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(libsigrok_la_LDFLAGS) $(LDFLAGS) -o $@
+ at HAVE_CHECK_TRUE@am__EXEEXT_1 = tests/check_main$(EXEEXT)
+am__tests_check_main_SOURCES_DIST = libsigrok.h tests/lib.c \
+	tests/lib.h tests/check_main.c tests/check_core.c \
+	tests/check_input_all.c tests/check_input_binary.c \
+	tests/check_output_all.c tests/check_strutil.c \
+	tests/check_version.c tests/check_driver_all.c
+ at HAVE_CHECK_TRUE@am_tests_check_main_OBJECTS =  \
+ at HAVE_CHECK_TRUE@	tests/tests_check_main-lib.$(OBJEXT) \
+ at HAVE_CHECK_TRUE@	tests/tests_check_main-check_main.$(OBJEXT) \
+ at HAVE_CHECK_TRUE@	tests/tests_check_main-check_core.$(OBJEXT) \
+ at HAVE_CHECK_TRUE@	tests/tests_check_main-check_input_all.$(OBJEXT) \
+ at HAVE_CHECK_TRUE@	tests/tests_check_main-check_input_binary.$(OBJEXT) \
+ at HAVE_CHECK_TRUE@	tests/tests_check_main-check_output_all.$(OBJEXT) \
+ at HAVE_CHECK_TRUE@	tests/tests_check_main-check_strutil.$(OBJEXT) \
+ at HAVE_CHECK_TRUE@	tests/tests_check_main-check_version.$(OBJEXT) \
+ at HAVE_CHECK_TRUE@	tests/tests_check_main-check_driver_all.$(OBJEXT)
+tests_check_main_OBJECTS = $(am_tests_check_main_OBJECTS)
+ at HAVE_CHECK_TRUE@tests_check_main_DEPENDENCIES =  \
+ at HAVE_CHECK_TRUE@	$(top_builddir)/libsigrok.la
+tests_check_main_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+	$(tests_check_main_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
+	-o $@
+AM_V_P = $(am__v_P_ at AM_V@)
+am__v_P_ = $(am__v_P_ at AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_ at AM_V@)
+am__v_GEN_ = $(am__v_GEN_ at AM_DEFAULT_V@)
+am__v_GEN_0 = @echo "  GEN     " $@;
+am__v_GEN_1 = 
+AM_V_at = $(am__v_at_ at AM_V@)
+am__v_at_ = $(am__v_at_ at AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 = 
+DEFAULT_INCLUDES = -I. at am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/autostuff/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_ at AM_V@)
+am__v_CC_ = $(am__v_CC_ at AM_DEFAULT_V@)
+am__v_CC_0 = @echo "  CC      " $@;
+am__v_CC_1 = 
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_ at AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_ at AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo "  CCLD    " $@;
+am__v_CCLD_1 = 
+SOURCES = $(libsigrok_la_SOURCES) $(tests_check_main_SOURCES)
+DIST_SOURCES = $(am__libsigrok_la_SOURCES_DIST) \
+	$(am__tests_check_main_SOURCES_DIST)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+DATA = $(pkgconfig_DATA)
+HEADERS = $(library_include_HEADERS) $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \
+	$(LISP)config.h.in
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates.  Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+  BEGIN { nonempty = 0; } \
+  { items[$$0] = 1; nonempty = 1; } \
+  END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique.  This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+  list='$(am__tagged_files)'; \
+  unique=`for i in $$list; do \
+    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+  done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+CSCOPE = cscope
+AM_RECURSIVE_TARGETS = cscope check recheck
+am__tty_colors_dummy = \
+  mgn= red= grn= lgn= blu= brg= std=; \
+  am__color_tests=no
+am__tty_colors = { \
+  $(am__tty_colors_dummy); \
+  if test "X$(AM_COLOR_TESTS)" = Xno; then \
+    am__color_tests=no; \
+  elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+    am__color_tests=yes; \
+  elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+    am__color_tests=yes; \
+  fi; \
+  if test $$am__color_tests = yes; then \
+    red=''; \
+    grn=''; \
+    lgn=''; \
+    blu=''; \
+    mgn=''; \
+    brg=''; \
+    std=''; \
+  fi; \
+}
+am__recheck_rx = ^[ 	]*:recheck:[ 	]*
+am__global_test_result_rx = ^[ 	]*:global-test-result:[ 	]*
+am__copy_in_global_log_rx = ^[ 	]*:copy-in-global-log:[ 	]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+  recheck = 1; \
+  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+    { \
+      if (rc < 0) \
+        { \
+          if ((getline line2 < ($$0 ".log")) < 0) \
+	    recheck = 0; \
+          break; \
+        } \
+      else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+        { \
+          recheck = 0; \
+          break; \
+        } \
+      else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+        { \
+          break; \
+        } \
+    }; \
+  if (recheck) \
+    print $$0; \
+  close ($$0 ".trs"); \
+  close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+  print "fatal: making $@: " msg | "cat >&2"; \
+  exit 1; \
+} \
+function rst_section(header) \
+{ \
+  print header; \
+  len = length(header); \
+  for (i = 1; i <= len; i = i + 1) \
+    printf "="; \
+  printf "\n\n"; \
+} \
+{ \
+  copy_in_global_log = 1; \
+  global_test_result = "RUN"; \
+  while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+    { \
+      if (rc < 0) \
+         fatal("failed to read from " $$0 ".trs"); \
+      if (line ~ /$(am__global_test_result_rx)/) \
+        { \
+          sub("$(am__global_test_result_rx)", "", line); \
+          sub("[ 	]*$$", "", line); \
+          global_test_result = line; \
+        } \
+      else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+        copy_in_global_log = 0; \
+    }; \
+  if (copy_in_global_log) \
+    { \
+      rst_section(global_test_result ": " $$0); \
+      while ((rc = (getline line < ($$0 ".log"))) != 0) \
+      { \
+        if (rc < 0) \
+          fatal("failed to read from " $$0 ".log"); \
+        print line; \
+      }; \
+      printf "\n"; \
+    }; \
+  close ($$0 ".trs"); \
+  close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/   &   /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this.  Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+  --color-tests "$$am__color_tests" \
+  --enable-hard-errors "$$am__enable_hard_errors" \
+  --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test.  Creates the
+# directory for the log if needed.  Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log.  Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT.  Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup);					\
+$(am__vpath_adj_setup) $(am__vpath_adj)			\
+$(am__tty_colors);					\
+srcdir=$(srcdir); export srcdir;			\
+case "$@" in						\
+  */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;;	\
+    *) am__odir=.;; 					\
+esac;							\
+test "x$$am__odir" = x"." || test -d "$$am__odir" 	\
+  || $(MKDIR_P) "$$am__odir" || exit $$?;		\
+if test -f "./$$f"; then dir=./;			\
+elif test -f "$$f"; then dir=;				\
+else dir="$(srcdir)/"; fi;				\
+tst=$$dir$$f; log='$@'; 				\
+if test -n '$(DISABLE_HARD_ERRORS)'; then		\
+  am__enable_hard_errors=no; 				\
+else							\
+  am__enable_hard_errors=yes; 				\
+fi; 							\
+case " $(XFAIL_TESTS) " in				\
+  *[\ \	]$$f[\ \	]* | *[\ \	]$$dir$$f[\ \	]*) \
+    am__expect_failure=yes;;				\
+  *)							\
+    am__expect_failure=no;;				\
+esac; 							\
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed).  The result is saved in the shell variable
+# '$bases'.  This honors runtime overriding of TESTS and TEST_LOGS.  Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+  bases='$(TEST_LOGS)'; \
+  bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+  bases=`echo $$bases`
+RECHECK_LOGS = $(TEST_LOGS)
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_DRIVER = $(SHELL) $(top_srcdir)/autostuff/test-driver
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+  case '$@' in \
+    */*) \
+      case '$*' in \
+        */*) b='$*';; \
+          *) b=`echo '$@' | sed 's/\.log$$//'`; \
+       esac;; \
+    *) \
+      b='$*';; \
+  esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT at .log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/autostuff/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+	$(TEST_LOG_FLAGS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+  if test -d "$(distdir)"; then \
+    find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
+      && rm -rf "$(distdir)" \
+      || { sleep 5 && rm -rf "$(distdir)"; }; \
+  else :; fi
+am__post_remove_distdir = $(am__remove_distdir)
+DIST_ARCHIVES = $(distdir).tar.gz
+GZIP_ENV = --best
+DIST_TARGETS = dist-gzip
+distuninstallcheck_listfiles = find . -type f -print
+am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
+  | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AM_LIBTOOLFLAGS = @AM_LIBTOOLFLAGS@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FIRMWARE_DIR = @FIRMWARE_DIR@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_COMPILE_RESOURCES = @GLIB_COMPILE_RESOURCES@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEFLAGS = @MAKEFLAGS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SR_LIB_LDFLAGS = @SR_LIB_LDFLAGS@
+SR_LIB_VERSION = @SR_LIB_VERSION@
+SR_LIB_VERSION_AGE = @SR_LIB_VERSION_AGE@
+SR_LIB_VERSION_CURRENT = @SR_LIB_VERSION_CURRENT@
+SR_LIB_VERSION_REVISION = @SR_LIB_VERSION_REVISION@
+SR_PACKAGE_VERSION = @SR_PACKAGE_VERSION@
+SR_PACKAGE_VERSION_MAJOR = @SR_PACKAGE_VERSION_MAJOR@
+SR_PACKAGE_VERSION_MICRO = @SR_PACKAGE_VERSION_MICRO@
+SR_PACKAGE_VERSION_MINOR = @SR_PACKAGE_VERSION_MINOR@
+SR_PKGLIBS = @SR_PKGLIBS@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+check_CFLAGS = @check_CFLAGS@
+check_LIBS = @check_LIBS@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libftdi_CFLAGS = @libftdi_CFLAGS@
+libftdi_LIBS = @libftdi_LIBS@
+librevisa_CFLAGS = @librevisa_CFLAGS@
+librevisa_LIBS = @librevisa_LIBS@
+libserialport_CFLAGS = @libserialport_CFLAGS@
+libserialport_LIBS = @libserialport_LIBS@
+libusb_CFLAGS = @libusb_CFLAGS@
+libusb_LIBS = @libusb_LIBS@
+libzip_CFLAGS = @libzip_CFLAGS@
+libzip_LIBS = @libzip_LIBS@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+ACLOCAL_AMFLAGS = -I autostuff
+AM_CPPFLAGS = -DFIRMWARE_DIR='"$(FIRMWARE_DIR)"'
+lib_LTLIBRARIES = libsigrok.la
+
+# Backend files
+
+# Input formats
+
+# Output formats
+
+# Hardware (common files)
+
+# Hardware (DMM parsers)
+libsigrok_la_SOURCES = backend.c device.c session.c session_file.c \
+	session_driver.c hwdriver.c strutil.c log.c version.c error.c \
+	std.c input/binary.c input/chronovu_la8.c input/csv.c \
+	input/input.c input/vcd.c input/wav.c output/output.c \
+	output/analog.c output/ascii.c output/bits.c output/binary.c \
+	output/csv.c output/chronovu_la8.c output/gnuplot.c \
+	output/hex.c output/ols.c output/vcd.c hardware/common/scpi.c \
+	hardware/common/scpi_tcp.c $(am__append_1) $(am__append_2) \
+	$(am__append_3) $(am__append_4) hardware/common/dmm/es519xx.c \
+	hardware/common/dmm/fs9721.c hardware/common/dmm/fs9922.c \
+	hardware/common/dmm/m2110.c hardware/common/dmm/metex14.c \
+	hardware/common/dmm/rs9lcd.c $(am__append_5) $(am__append_6) \
+	$(am__append_7) $(am__append_8) $(am__append_9) \
+	$(am__append_10) $(am__append_11) $(am__append_12) \
+	$(am__append_13) $(am__append_14) $(am__append_15) \
+	$(am__append_16) $(am__append_17) $(am__append_18) \
+	$(am__append_19) $(am__append_20) $(am__append_21) \
+	$(am__append_22) $(am__append_23) $(am__append_24) \
+	$(am__append_25) $(am__append_26) $(am__append_27) \
+	$(am__append_28) $(am__append_29) $(am__append_30) \
+	$(am__append_31) $(am__append_32) $(am__append_33) \
+	$(am__append_34) $(am__append_35) $(am__append_36) \
+	$(am__append_37) $(am__append_38)
+libsigrok_la_LIBADD = $(LIBOBJS)
+libsigrok_la_LDFLAGS = $(SR_LIB_LDFLAGS)
+library_includedir = $(includedir)/libsigrok
+library_include_HEADERS = libsigrok.h proto.h version.h
+noinst_HEADERS = libsigrok-internal.h
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libsigrok.pc
+EXTRA_DIST = \
+	Doxyfile \
+	HACKING \
+	README.devices \
+	contrib/gnuplot_chronovu_la8.gpi \
+	contrib/gnuplot_rigol_ds1xx2.gpi \
+	contrib/gnuplot_usbeesx.gpi \
+	contrib/gnuplot_usbeedx8.gpi \
+	contrib/gnuplot_usbeedx16.gpi \
+	contrib/sigrok-logo-notext.png \
+	contrib/z60_libsigrok.rules
+
+ at HAVE_CHECK_TRUE@tests_check_main_SOURCES = \
+ at HAVE_CHECK_TRUE@	libsigrok.h \
+ at HAVE_CHECK_TRUE@	tests/lib.c \
+ at HAVE_CHECK_TRUE@	tests/lib.h \
+ at HAVE_CHECK_TRUE@	tests/check_main.c \
+ at HAVE_CHECK_TRUE@	tests/check_core.c \
+ at HAVE_CHECK_TRUE@	tests/check_input_all.c \
+ at HAVE_CHECK_TRUE@	tests/check_input_binary.c \
+ at HAVE_CHECK_TRUE@	tests/check_output_all.c \
+ at HAVE_CHECK_TRUE@	tests/check_strutil.c \
+ at HAVE_CHECK_TRUE@	tests/check_version.c \
+ at HAVE_CHECK_TRUE@	tests/check_driver_all.c
+
+ at HAVE_CHECK_TRUE@tests_check_main_CFLAGS = @check_CFLAGS@
+ at HAVE_CHECK_TRUE@tests_check_main_LDADD = $(top_builddir)/libsigrok.la @check_LIBS@
+MAINTAINERCLEANFILES = ChangeLog
+all: config.h
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs
+am--refresh: Makefile
+	@:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \
+	      $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \
+	$(am__cd) $(top_srcdir) && \
+	  $(AUTOMAKE) --gnu Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    echo ' $(SHELL) ./config.status'; \
+	    $(SHELL) ./config.status;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	$(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+	$(am__cd) $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+	$(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+$(am__aclocal_m4_deps):
+
+config.h: stamp-h1
+	@test -f $@ || rm -f stamp-h1
+	@test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+	@rm -f stamp-h1
+	cd $(top_builddir) && $(SHELL) ./config.status config.h
+$(srcdir)/config.h.in:  $(am__configure_deps) 
+	($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+	rm -f stamp-h1
+	touch $@
+
+distclean-hdr:
+	-rm -f config.h stamp-h1
+version.h: $(top_builddir)/config.status $(srcdir)/version.h.in
+	cd $(top_builddir) && $(SHELL) ./config.status $@
+libsigrok.pc: $(top_builddir)/config.status $(srcdir)/libsigrok.pc.in
+	cd $(top_builddir) && $(SHELL) ./config.status $@
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+	@$(NORMAL_INSTALL)
+	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+	list2=; for p in $$list; do \
+	  if test -f $$p; then \
+	    list2="$$list2 $$p"; \
+	  else :; fi; \
+	done; \
+	test -z "$$list2" || { \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+	}
+
+uninstall-libLTLIBRARIES:
+	@$(NORMAL_UNINSTALL)
+	@list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+	for p in $$list; do \
+	  $(am__strip_dir) \
+	  echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+	  $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+	done
+
+clean-libLTLIBRARIES:
+	-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+	@list='$(lib_LTLIBRARIES)'; \
+	locs=`for p in $$list; do echo $$p; done | \
+	      sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+	      sort -u`; \
+	test -z "$$locs" || { \
+	  echo rm -f $${locs}; \
+	  rm -f $${locs}; \
+	}
+input/$(am__dirstamp):
+	@$(MKDIR_P) input
+	@: > input/$(am__dirstamp)
+input/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) input/$(DEPDIR)
+	@: > input/$(DEPDIR)/$(am__dirstamp)
+input/binary.lo: input/$(am__dirstamp) input/$(DEPDIR)/$(am__dirstamp)
+input/chronovu_la8.lo: input/$(am__dirstamp) \
+	input/$(DEPDIR)/$(am__dirstamp)
+input/csv.lo: input/$(am__dirstamp) input/$(DEPDIR)/$(am__dirstamp)
+input/input.lo: input/$(am__dirstamp) input/$(DEPDIR)/$(am__dirstamp)
+input/vcd.lo: input/$(am__dirstamp) input/$(DEPDIR)/$(am__dirstamp)
+input/wav.lo: input/$(am__dirstamp) input/$(DEPDIR)/$(am__dirstamp)
+output/$(am__dirstamp):
+	@$(MKDIR_P) output
+	@: > output/$(am__dirstamp)
+output/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) output/$(DEPDIR)
+	@: > output/$(DEPDIR)/$(am__dirstamp)
+output/output.lo: output/$(am__dirstamp) \
+	output/$(DEPDIR)/$(am__dirstamp)
+output/analog.lo: output/$(am__dirstamp) \
+	output/$(DEPDIR)/$(am__dirstamp)
+output/ascii.lo: output/$(am__dirstamp) \
+	output/$(DEPDIR)/$(am__dirstamp)
+output/bits.lo: output/$(am__dirstamp) \
+	output/$(DEPDIR)/$(am__dirstamp)
+output/binary.lo: output/$(am__dirstamp) \
+	output/$(DEPDIR)/$(am__dirstamp)
+output/csv.lo: output/$(am__dirstamp) output/$(DEPDIR)/$(am__dirstamp)
+output/chronovu_la8.lo: output/$(am__dirstamp) \
+	output/$(DEPDIR)/$(am__dirstamp)
+output/gnuplot.lo: output/$(am__dirstamp) \
+	output/$(DEPDIR)/$(am__dirstamp)
+output/hex.lo: output/$(am__dirstamp) output/$(DEPDIR)/$(am__dirstamp)
+output/ols.lo: output/$(am__dirstamp) output/$(DEPDIR)/$(am__dirstamp)
+output/vcd.lo: output/$(am__dirstamp) output/$(DEPDIR)/$(am__dirstamp)
+hardware/common/$(am__dirstamp):
+	@$(MKDIR_P) hardware/common
+	@: > hardware/common/$(am__dirstamp)
+hardware/common/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/common/$(DEPDIR)
+	@: > hardware/common/$(DEPDIR)/$(am__dirstamp)
+hardware/common/scpi.lo: hardware/common/$(am__dirstamp) \
+	hardware/common/$(DEPDIR)/$(am__dirstamp)
+hardware/common/scpi_tcp.lo: hardware/common/$(am__dirstamp) \
+	hardware/common/$(DEPDIR)/$(am__dirstamp)
+hardware/common/scpi_vxi.lo: hardware/common/$(am__dirstamp) \
+	hardware/common/$(DEPDIR)/$(am__dirstamp)
+hardware/common/vxi_clnt.lo: hardware/common/$(am__dirstamp) \
+	hardware/common/$(DEPDIR)/$(am__dirstamp)
+hardware/common/vxi_xdr.lo: hardware/common/$(am__dirstamp) \
+	hardware/common/$(DEPDIR)/$(am__dirstamp)
+hardware/common/serial.lo: hardware/common/$(am__dirstamp) \
+	hardware/common/$(DEPDIR)/$(am__dirstamp)
+hardware/common/scpi_serial.lo: hardware/common/$(am__dirstamp) \
+	hardware/common/$(DEPDIR)/$(am__dirstamp)
+hardware/common/ezusb.lo: hardware/common/$(am__dirstamp) \
+	hardware/common/$(DEPDIR)/$(am__dirstamp)
+hardware/common/usb.lo: hardware/common/$(am__dirstamp) \
+	hardware/common/$(DEPDIR)/$(am__dirstamp)
+hardware/common/scpi_usbtmc_libusb.lo:  \
+	hardware/common/$(am__dirstamp) \
+	hardware/common/$(DEPDIR)/$(am__dirstamp)
+hardware/common/scpi_visa.lo: hardware/common/$(am__dirstamp) \
+	hardware/common/$(DEPDIR)/$(am__dirstamp)
+hardware/common/dmm/$(am__dirstamp):
+	@$(MKDIR_P) hardware/common/dmm
+	@: > hardware/common/dmm/$(am__dirstamp)
+hardware/common/dmm/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/common/dmm/$(DEPDIR)
+	@: > hardware/common/dmm/$(DEPDIR)/$(am__dirstamp)
+hardware/common/dmm/es519xx.lo: hardware/common/dmm/$(am__dirstamp) \
+	hardware/common/dmm/$(DEPDIR)/$(am__dirstamp)
+hardware/common/dmm/fs9721.lo: hardware/common/dmm/$(am__dirstamp) \
+	hardware/common/dmm/$(DEPDIR)/$(am__dirstamp)
+hardware/common/dmm/fs9922.lo: hardware/common/dmm/$(am__dirstamp) \
+	hardware/common/dmm/$(DEPDIR)/$(am__dirstamp)
+hardware/common/dmm/m2110.lo: hardware/common/dmm/$(am__dirstamp) \
+	hardware/common/dmm/$(DEPDIR)/$(am__dirstamp)
+hardware/common/dmm/metex14.lo: hardware/common/dmm/$(am__dirstamp) \
+	hardware/common/dmm/$(DEPDIR)/$(am__dirstamp)
+hardware/common/dmm/rs9lcd.lo: hardware/common/dmm/$(am__dirstamp) \
+	hardware/common/dmm/$(DEPDIR)/$(am__dirstamp)
+hardware/agilent-dmm/$(am__dirstamp):
+	@$(MKDIR_P) hardware/agilent-dmm
+	@: > hardware/agilent-dmm/$(am__dirstamp)
+hardware/agilent-dmm/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/agilent-dmm/$(DEPDIR)
+	@: > hardware/agilent-dmm/$(DEPDIR)/$(am__dirstamp)
+hardware/agilent-dmm/api.lo: hardware/agilent-dmm/$(am__dirstamp) \
+	hardware/agilent-dmm/$(DEPDIR)/$(am__dirstamp)
+hardware/agilent-dmm/sched.lo: hardware/agilent-dmm/$(am__dirstamp) \
+	hardware/agilent-dmm/$(DEPDIR)/$(am__dirstamp)
+hardware/appa-55ii/$(am__dirstamp):
+	@$(MKDIR_P) hardware/appa-55ii
+	@: > hardware/appa-55ii/$(am__dirstamp)
+hardware/appa-55ii/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/appa-55ii/$(DEPDIR)
+	@: > hardware/appa-55ii/$(DEPDIR)/$(am__dirstamp)
+hardware/appa-55ii/protocol.lo: hardware/appa-55ii/$(am__dirstamp) \
+	hardware/appa-55ii/$(DEPDIR)/$(am__dirstamp)
+hardware/appa-55ii/api.lo: hardware/appa-55ii/$(am__dirstamp) \
+	hardware/appa-55ii/$(DEPDIR)/$(am__dirstamp)
+hardware/asix-sigma/$(am__dirstamp):
+	@$(MKDIR_P) hardware/asix-sigma
+	@: > hardware/asix-sigma/$(am__dirstamp)
+hardware/asix-sigma/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/asix-sigma/$(DEPDIR)
+	@: > hardware/asix-sigma/$(DEPDIR)/$(am__dirstamp)
+hardware/asix-sigma/asix-sigma.lo:  \
+	hardware/asix-sigma/$(am__dirstamp) \
+	hardware/asix-sigma/$(DEPDIR)/$(am__dirstamp)
+hardware/atten-pps3xxx/$(am__dirstamp):
+	@$(MKDIR_P) hardware/atten-pps3xxx
+	@: > hardware/atten-pps3xxx/$(am__dirstamp)
+hardware/atten-pps3xxx/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/atten-pps3xxx/$(DEPDIR)
+	@: > hardware/atten-pps3xxx/$(DEPDIR)/$(am__dirstamp)
+hardware/atten-pps3xxx/protocol.lo:  \
+	hardware/atten-pps3xxx/$(am__dirstamp) \
+	hardware/atten-pps3xxx/$(DEPDIR)/$(am__dirstamp)
+hardware/atten-pps3xxx/api.lo: hardware/atten-pps3xxx/$(am__dirstamp) \
+	hardware/atten-pps3xxx/$(DEPDIR)/$(am__dirstamp)
+hardware/brymen-bm86x/$(am__dirstamp):
+	@$(MKDIR_P) hardware/brymen-bm86x
+	@: > hardware/brymen-bm86x/$(am__dirstamp)
+hardware/brymen-bm86x/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/brymen-bm86x/$(DEPDIR)
+	@: > hardware/brymen-bm86x/$(DEPDIR)/$(am__dirstamp)
+hardware/brymen-bm86x/protocol.lo:  \
+	hardware/brymen-bm86x/$(am__dirstamp) \
+	hardware/brymen-bm86x/$(DEPDIR)/$(am__dirstamp)
+hardware/brymen-bm86x/api.lo: hardware/brymen-bm86x/$(am__dirstamp) \
+	hardware/brymen-bm86x/$(DEPDIR)/$(am__dirstamp)
+hardware/brymen-dmm/$(am__dirstamp):
+	@$(MKDIR_P) hardware/brymen-dmm
+	@: > hardware/brymen-dmm/$(am__dirstamp)
+hardware/brymen-dmm/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/brymen-dmm/$(DEPDIR)
+	@: > hardware/brymen-dmm/$(DEPDIR)/$(am__dirstamp)
+hardware/brymen-dmm/parser.lo: hardware/brymen-dmm/$(am__dirstamp) \
+	hardware/brymen-dmm/$(DEPDIR)/$(am__dirstamp)
+hardware/brymen-dmm/protocol.lo: hardware/brymen-dmm/$(am__dirstamp) \
+	hardware/brymen-dmm/$(DEPDIR)/$(am__dirstamp)
+hardware/brymen-dmm/api.lo: hardware/brymen-dmm/$(am__dirstamp) \
+	hardware/brymen-dmm/$(DEPDIR)/$(am__dirstamp)
+hardware/cem-dt-885x/$(am__dirstamp):
+	@$(MKDIR_P) hardware/cem-dt-885x
+	@: > hardware/cem-dt-885x/$(am__dirstamp)
+hardware/cem-dt-885x/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/cem-dt-885x/$(DEPDIR)
+	@: > hardware/cem-dt-885x/$(DEPDIR)/$(am__dirstamp)
+hardware/cem-dt-885x/protocol.lo:  \
+	hardware/cem-dt-885x/$(am__dirstamp) \
+	hardware/cem-dt-885x/$(DEPDIR)/$(am__dirstamp)
+hardware/cem-dt-885x/api.lo: hardware/cem-dt-885x/$(am__dirstamp) \
+	hardware/cem-dt-885x/$(DEPDIR)/$(am__dirstamp)
+hardware/center-3xx/$(am__dirstamp):
+	@$(MKDIR_P) hardware/center-3xx
+	@: > hardware/center-3xx/$(am__dirstamp)
+hardware/center-3xx/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/center-3xx/$(DEPDIR)
+	@: > hardware/center-3xx/$(DEPDIR)/$(am__dirstamp)
+hardware/center-3xx/protocol.lo: hardware/center-3xx/$(am__dirstamp) \
+	hardware/center-3xx/$(DEPDIR)/$(am__dirstamp)
+hardware/center-3xx/api.lo: hardware/center-3xx/$(am__dirstamp) \
+	hardware/center-3xx/$(DEPDIR)/$(am__dirstamp)
+hardware/chronovu-la/$(am__dirstamp):
+	@$(MKDIR_P) hardware/chronovu-la
+	@: > hardware/chronovu-la/$(am__dirstamp)
+hardware/chronovu-la/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/chronovu-la/$(DEPDIR)
+	@: > hardware/chronovu-la/$(DEPDIR)/$(am__dirstamp)
+hardware/chronovu-la/protocol.lo:  \
+	hardware/chronovu-la/$(am__dirstamp) \
+	hardware/chronovu-la/$(DEPDIR)/$(am__dirstamp)
+hardware/chronovu-la/api.lo: hardware/chronovu-la/$(am__dirstamp) \
+	hardware/chronovu-la/$(DEPDIR)/$(am__dirstamp)
+hardware/colead-slm/$(am__dirstamp):
+	@$(MKDIR_P) hardware/colead-slm
+	@: > hardware/colead-slm/$(am__dirstamp)
+hardware/colead-slm/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/colead-slm/$(DEPDIR)
+	@: > hardware/colead-slm/$(DEPDIR)/$(am__dirstamp)
+hardware/colead-slm/protocol.lo: hardware/colead-slm/$(am__dirstamp) \
+	hardware/colead-slm/$(DEPDIR)/$(am__dirstamp)
+hardware/colead-slm/api.lo: hardware/colead-slm/$(am__dirstamp) \
+	hardware/colead-slm/$(DEPDIR)/$(am__dirstamp)
+hardware/conrad-digi-35-cpu/$(am__dirstamp):
+	@$(MKDIR_P) hardware/conrad-digi-35-cpu
+	@: > hardware/conrad-digi-35-cpu/$(am__dirstamp)
+hardware/conrad-digi-35-cpu/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/conrad-digi-35-cpu/$(DEPDIR)
+	@: > hardware/conrad-digi-35-cpu/$(DEPDIR)/$(am__dirstamp)
+hardware/conrad-digi-35-cpu/protocol.lo:  \
+	hardware/conrad-digi-35-cpu/$(am__dirstamp) \
+	hardware/conrad-digi-35-cpu/$(DEPDIR)/$(am__dirstamp)
+hardware/conrad-digi-35-cpu/api.lo:  \
+	hardware/conrad-digi-35-cpu/$(am__dirstamp) \
+	hardware/conrad-digi-35-cpu/$(DEPDIR)/$(am__dirstamp)
+hardware/demo/$(am__dirstamp):
+	@$(MKDIR_P) hardware/demo
+	@: > hardware/demo/$(am__dirstamp)
+hardware/demo/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/demo/$(DEPDIR)
+	@: > hardware/demo/$(DEPDIR)/$(am__dirstamp)
+hardware/demo/demo.lo: hardware/demo/$(am__dirstamp) \
+	hardware/demo/$(DEPDIR)/$(am__dirstamp)
+hardware/fluke-dmm/$(am__dirstamp):
+	@$(MKDIR_P) hardware/fluke-dmm
+	@: > hardware/fluke-dmm/$(am__dirstamp)
+hardware/fluke-dmm/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/fluke-dmm/$(DEPDIR)
+	@: > hardware/fluke-dmm/$(DEPDIR)/$(am__dirstamp)
+hardware/fluke-dmm/fluke.lo: hardware/fluke-dmm/$(am__dirstamp) \
+	hardware/fluke-dmm/$(DEPDIR)/$(am__dirstamp)
+hardware/fluke-dmm/api.lo: hardware/fluke-dmm/$(am__dirstamp) \
+	hardware/fluke-dmm/$(DEPDIR)/$(am__dirstamp)
+hardware/fx2lafw/$(am__dirstamp):
+	@$(MKDIR_P) hardware/fx2lafw
+	@: > hardware/fx2lafw/$(am__dirstamp)
+hardware/fx2lafw/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/fx2lafw/$(DEPDIR)
+	@: > hardware/fx2lafw/$(DEPDIR)/$(am__dirstamp)
+hardware/fx2lafw/protocol.lo: hardware/fx2lafw/$(am__dirstamp) \
+	hardware/fx2lafw/$(DEPDIR)/$(am__dirstamp)
+hardware/fx2lafw/api.lo: hardware/fx2lafw/$(am__dirstamp) \
+	hardware/fx2lafw/$(DEPDIR)/$(am__dirstamp)
+hardware/gmc-mh-1x-2x/$(am__dirstamp):
+	@$(MKDIR_P) hardware/gmc-mh-1x-2x
+	@: > hardware/gmc-mh-1x-2x/$(am__dirstamp)
+hardware/gmc-mh-1x-2x/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/gmc-mh-1x-2x/$(DEPDIR)
+	@: > hardware/gmc-mh-1x-2x/$(DEPDIR)/$(am__dirstamp)
+hardware/gmc-mh-1x-2x/protocol.lo:  \
+	hardware/gmc-mh-1x-2x/$(am__dirstamp) \
+	hardware/gmc-mh-1x-2x/$(DEPDIR)/$(am__dirstamp)
+hardware/gmc-mh-1x-2x/api.lo: hardware/gmc-mh-1x-2x/$(am__dirstamp) \
+	hardware/gmc-mh-1x-2x/$(DEPDIR)/$(am__dirstamp)
+hardware/hameg-hmo/$(am__dirstamp):
+	@$(MKDIR_P) hardware/hameg-hmo
+	@: > hardware/hameg-hmo/$(am__dirstamp)
+hardware/hameg-hmo/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/hameg-hmo/$(DEPDIR)
+	@: > hardware/hameg-hmo/$(DEPDIR)/$(am__dirstamp)
+hardware/hameg-hmo/protocol.lo: hardware/hameg-hmo/$(am__dirstamp) \
+	hardware/hameg-hmo/$(DEPDIR)/$(am__dirstamp)
+hardware/hameg-hmo/api.lo: hardware/hameg-hmo/$(am__dirstamp) \
+	hardware/hameg-hmo/$(DEPDIR)/$(am__dirstamp)
+hardware/hantek-dso/$(am__dirstamp):
+	@$(MKDIR_P) hardware/hantek-dso
+	@: > hardware/hantek-dso/$(am__dirstamp)
+hardware/hantek-dso/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/hantek-dso/$(DEPDIR)
+	@: > hardware/hantek-dso/$(DEPDIR)/$(am__dirstamp)
+hardware/hantek-dso/dso.lo: hardware/hantek-dso/$(am__dirstamp) \
+	hardware/hantek-dso/$(DEPDIR)/$(am__dirstamp)
+hardware/hantek-dso/api.lo: hardware/hantek-dso/$(am__dirstamp) \
+	hardware/hantek-dso/$(DEPDIR)/$(am__dirstamp)
+hardware/ikalogic-scanalogic2/$(am__dirstamp):
+	@$(MKDIR_P) hardware/ikalogic-scanalogic2
+	@: > hardware/ikalogic-scanalogic2/$(am__dirstamp)
+hardware/ikalogic-scanalogic2/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/ikalogic-scanalogic2/$(DEPDIR)
+	@: > hardware/ikalogic-scanalogic2/$(DEPDIR)/$(am__dirstamp)
+hardware/ikalogic-scanalogic2/protocol.lo:  \
+	hardware/ikalogic-scanalogic2/$(am__dirstamp) \
+	hardware/ikalogic-scanalogic2/$(DEPDIR)/$(am__dirstamp)
+hardware/ikalogic-scanalogic2/api.lo:  \
+	hardware/ikalogic-scanalogic2/$(am__dirstamp) \
+	hardware/ikalogic-scanalogic2/$(DEPDIR)/$(am__dirstamp)
+hardware/ikalogic-scanaplus/$(am__dirstamp):
+	@$(MKDIR_P) hardware/ikalogic-scanaplus
+	@: > hardware/ikalogic-scanaplus/$(am__dirstamp)
+hardware/ikalogic-scanaplus/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/ikalogic-scanaplus/$(DEPDIR)
+	@: > hardware/ikalogic-scanaplus/$(DEPDIR)/$(am__dirstamp)
+hardware/ikalogic-scanaplus/protocol.lo:  \
+	hardware/ikalogic-scanaplus/$(am__dirstamp) \
+	hardware/ikalogic-scanaplus/$(DEPDIR)/$(am__dirstamp)
+hardware/ikalogic-scanaplus/api.lo:  \
+	hardware/ikalogic-scanaplus/$(am__dirstamp) \
+	hardware/ikalogic-scanaplus/$(DEPDIR)/$(am__dirstamp)
+hardware/kecheng-kc-330b/$(am__dirstamp):
+	@$(MKDIR_P) hardware/kecheng-kc-330b
+	@: > hardware/kecheng-kc-330b/$(am__dirstamp)
+hardware/kecheng-kc-330b/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/kecheng-kc-330b/$(DEPDIR)
+	@: > hardware/kecheng-kc-330b/$(DEPDIR)/$(am__dirstamp)
+hardware/kecheng-kc-330b/protocol.lo:  \
+	hardware/kecheng-kc-330b/$(am__dirstamp) \
+	hardware/kecheng-kc-330b/$(DEPDIR)/$(am__dirstamp)
+hardware/kecheng-kc-330b/api.lo:  \
+	hardware/kecheng-kc-330b/$(am__dirstamp) \
+	hardware/kecheng-kc-330b/$(DEPDIR)/$(am__dirstamp)
+hardware/lascar-el-usb/$(am__dirstamp):
+	@$(MKDIR_P) hardware/lascar-el-usb
+	@: > hardware/lascar-el-usb/$(am__dirstamp)
+hardware/lascar-el-usb/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/lascar-el-usb/$(DEPDIR)
+	@: > hardware/lascar-el-usb/$(DEPDIR)/$(am__dirstamp)
+hardware/lascar-el-usb/protocol.lo:  \
+	hardware/lascar-el-usb/$(am__dirstamp) \
+	hardware/lascar-el-usb/$(DEPDIR)/$(am__dirstamp)
+hardware/lascar-el-usb/api.lo: hardware/lascar-el-usb/$(am__dirstamp) \
+	hardware/lascar-el-usb/$(DEPDIR)/$(am__dirstamp)
+hardware/mic-985xx/$(am__dirstamp):
+	@$(MKDIR_P) hardware/mic-985xx
+	@: > hardware/mic-985xx/$(am__dirstamp)
+hardware/mic-985xx/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/mic-985xx/$(DEPDIR)
+	@: > hardware/mic-985xx/$(DEPDIR)/$(am__dirstamp)
+hardware/mic-985xx/protocol.lo: hardware/mic-985xx/$(am__dirstamp) \
+	hardware/mic-985xx/$(DEPDIR)/$(am__dirstamp)
+hardware/mic-985xx/api.lo: hardware/mic-985xx/$(am__dirstamp) \
+	hardware/mic-985xx/$(DEPDIR)/$(am__dirstamp)
+hardware/norma-dmm/$(am__dirstamp):
+	@$(MKDIR_P) hardware/norma-dmm
+	@: > hardware/norma-dmm/$(am__dirstamp)
+hardware/norma-dmm/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/norma-dmm/$(DEPDIR)
+	@: > hardware/norma-dmm/$(DEPDIR)/$(am__dirstamp)
+hardware/norma-dmm/protocol.lo: hardware/norma-dmm/$(am__dirstamp) \
+	hardware/norma-dmm/$(DEPDIR)/$(am__dirstamp)
+hardware/norma-dmm/api.lo: hardware/norma-dmm/$(am__dirstamp) \
+	hardware/norma-dmm/$(DEPDIR)/$(am__dirstamp)
+hardware/openbench-logic-sniffer/$(am__dirstamp):
+	@$(MKDIR_P) hardware/openbench-logic-sniffer
+	@: > hardware/openbench-logic-sniffer/$(am__dirstamp)
+hardware/openbench-logic-sniffer/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/openbench-logic-sniffer/$(DEPDIR)
+	@: > hardware/openbench-logic-sniffer/$(DEPDIR)/$(am__dirstamp)
+hardware/openbench-logic-sniffer/protocol.lo:  \
+	hardware/openbench-logic-sniffer/$(am__dirstamp) \
+	hardware/openbench-logic-sniffer/$(DEPDIR)/$(am__dirstamp)
+hardware/openbench-logic-sniffer/api.lo:  \
+	hardware/openbench-logic-sniffer/$(am__dirstamp) \
+	hardware/openbench-logic-sniffer/$(DEPDIR)/$(am__dirstamp)
+hardware/rigol-ds/$(am__dirstamp):
+	@$(MKDIR_P) hardware/rigol-ds
+	@: > hardware/rigol-ds/$(am__dirstamp)
+hardware/rigol-ds/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/rigol-ds/$(DEPDIR)
+	@: > hardware/rigol-ds/$(DEPDIR)/$(am__dirstamp)
+hardware/rigol-ds/protocol.lo: hardware/rigol-ds/$(am__dirstamp) \
+	hardware/rigol-ds/$(DEPDIR)/$(am__dirstamp)
+hardware/rigol-ds/api.lo: hardware/rigol-ds/$(am__dirstamp) \
+	hardware/rigol-ds/$(DEPDIR)/$(am__dirstamp)
+hardware/saleae-logic16/$(am__dirstamp):
+	@$(MKDIR_P) hardware/saleae-logic16
+	@: > hardware/saleae-logic16/$(am__dirstamp)
+hardware/saleae-logic16/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/saleae-logic16/$(DEPDIR)
+	@: > hardware/saleae-logic16/$(DEPDIR)/$(am__dirstamp)
+hardware/saleae-logic16/protocol.lo:  \
+	hardware/saleae-logic16/$(am__dirstamp) \
+	hardware/saleae-logic16/$(DEPDIR)/$(am__dirstamp)
+hardware/saleae-logic16/api.lo:  \
+	hardware/saleae-logic16/$(am__dirstamp) \
+	hardware/saleae-logic16/$(DEPDIR)/$(am__dirstamp)
+hardware/serial-dmm/$(am__dirstamp):
+	@$(MKDIR_P) hardware/serial-dmm
+	@: > hardware/serial-dmm/$(am__dirstamp)
+hardware/serial-dmm/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/serial-dmm/$(DEPDIR)
+	@: > hardware/serial-dmm/$(DEPDIR)/$(am__dirstamp)
+hardware/serial-dmm/protocol.lo: hardware/serial-dmm/$(am__dirstamp) \
+	hardware/serial-dmm/$(DEPDIR)/$(am__dirstamp)
+hardware/serial-dmm/api.lo: hardware/serial-dmm/$(am__dirstamp) \
+	hardware/serial-dmm/$(DEPDIR)/$(am__dirstamp)
+hardware/sysclk-lwla/$(am__dirstamp):
+	@$(MKDIR_P) hardware/sysclk-lwla
+	@: > hardware/sysclk-lwla/$(am__dirstamp)
+hardware/sysclk-lwla/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/sysclk-lwla/$(DEPDIR)
+	@: > hardware/sysclk-lwla/$(DEPDIR)/$(am__dirstamp)
+hardware/sysclk-lwla/lwla.lo: hardware/sysclk-lwla/$(am__dirstamp) \
+	hardware/sysclk-lwla/$(DEPDIR)/$(am__dirstamp)
+hardware/sysclk-lwla/protocol.lo:  \
+	hardware/sysclk-lwla/$(am__dirstamp) \
+	hardware/sysclk-lwla/$(DEPDIR)/$(am__dirstamp)
+hardware/sysclk-lwla/api.lo: hardware/sysclk-lwla/$(am__dirstamp) \
+	hardware/sysclk-lwla/$(DEPDIR)/$(am__dirstamp)
+hardware/teleinfo/$(am__dirstamp):
+	@$(MKDIR_P) hardware/teleinfo
+	@: > hardware/teleinfo/$(am__dirstamp)
+hardware/teleinfo/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/teleinfo/$(DEPDIR)
+	@: > hardware/teleinfo/$(DEPDIR)/$(am__dirstamp)
+hardware/teleinfo/protocol.lo: hardware/teleinfo/$(am__dirstamp) \
+	hardware/teleinfo/$(DEPDIR)/$(am__dirstamp)
+hardware/teleinfo/api.lo: hardware/teleinfo/$(am__dirstamp) \
+	hardware/teleinfo/$(DEPDIR)/$(am__dirstamp)
+hardware/tondaj-sl-814/$(am__dirstamp):
+	@$(MKDIR_P) hardware/tondaj-sl-814
+	@: > hardware/tondaj-sl-814/$(am__dirstamp)
+hardware/tondaj-sl-814/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/tondaj-sl-814/$(DEPDIR)
+	@: > hardware/tondaj-sl-814/$(DEPDIR)/$(am__dirstamp)
+hardware/tondaj-sl-814/protocol.lo:  \
+	hardware/tondaj-sl-814/$(am__dirstamp) \
+	hardware/tondaj-sl-814/$(DEPDIR)/$(am__dirstamp)
+hardware/tondaj-sl-814/api.lo: hardware/tondaj-sl-814/$(am__dirstamp) \
+	hardware/tondaj-sl-814/$(DEPDIR)/$(am__dirstamp)
+hardware/uni-t-dmm/$(am__dirstamp):
+	@$(MKDIR_P) hardware/uni-t-dmm
+	@: > hardware/uni-t-dmm/$(am__dirstamp)
+hardware/uni-t-dmm/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/uni-t-dmm/$(DEPDIR)
+	@: > hardware/uni-t-dmm/$(DEPDIR)/$(am__dirstamp)
+hardware/uni-t-dmm/protocol.lo: hardware/uni-t-dmm/$(am__dirstamp) \
+	hardware/uni-t-dmm/$(DEPDIR)/$(am__dirstamp)
+hardware/uni-t-dmm/api.lo: hardware/uni-t-dmm/$(am__dirstamp) \
+	hardware/uni-t-dmm/$(DEPDIR)/$(am__dirstamp)
+hardware/uni-t-ut32x/$(am__dirstamp):
+	@$(MKDIR_P) hardware/uni-t-ut32x
+	@: > hardware/uni-t-ut32x/$(am__dirstamp)
+hardware/uni-t-ut32x/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/uni-t-ut32x/$(DEPDIR)
+	@: > hardware/uni-t-ut32x/$(DEPDIR)/$(am__dirstamp)
+hardware/uni-t-ut32x/protocol.lo:  \
+	hardware/uni-t-ut32x/$(am__dirstamp) \
+	hardware/uni-t-ut32x/$(DEPDIR)/$(am__dirstamp)
+hardware/uni-t-ut32x/api.lo: hardware/uni-t-ut32x/$(am__dirstamp) \
+	hardware/uni-t-ut32x/$(DEPDIR)/$(am__dirstamp)
+hardware/victor-dmm/$(am__dirstamp):
+	@$(MKDIR_P) hardware/victor-dmm
+	@: > hardware/victor-dmm/$(am__dirstamp)
+hardware/victor-dmm/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/victor-dmm/$(DEPDIR)
+	@: > hardware/victor-dmm/$(DEPDIR)/$(am__dirstamp)
+hardware/victor-dmm/protocol.lo: hardware/victor-dmm/$(am__dirstamp) \
+	hardware/victor-dmm/$(DEPDIR)/$(am__dirstamp)
+hardware/victor-dmm/api.lo: hardware/victor-dmm/$(am__dirstamp) \
+	hardware/victor-dmm/$(DEPDIR)/$(am__dirstamp)
+hardware/zeroplus-logic-cube/$(am__dirstamp):
+	@$(MKDIR_P) hardware/zeroplus-logic-cube
+	@: > hardware/zeroplus-logic-cube/$(am__dirstamp)
+hardware/zeroplus-logic-cube/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) hardware/zeroplus-logic-cube/$(DEPDIR)
+	@: > hardware/zeroplus-logic-cube/$(DEPDIR)/$(am__dirstamp)
+hardware/zeroplus-logic-cube/analyzer.lo:  \
+	hardware/zeroplus-logic-cube/$(am__dirstamp) \
+	hardware/zeroplus-logic-cube/$(DEPDIR)/$(am__dirstamp)
+hardware/zeroplus-logic-cube/gl_usb.lo:  \
+	hardware/zeroplus-logic-cube/$(am__dirstamp) \
+	hardware/zeroplus-logic-cube/$(DEPDIR)/$(am__dirstamp)
+hardware/zeroplus-logic-cube/protocol.lo:  \
+	hardware/zeroplus-logic-cube/$(am__dirstamp) \
+	hardware/zeroplus-logic-cube/$(DEPDIR)/$(am__dirstamp)
+hardware/zeroplus-logic-cube/api.lo:  \
+	hardware/zeroplus-logic-cube/$(am__dirstamp) \
+	hardware/zeroplus-logic-cube/$(DEPDIR)/$(am__dirstamp)
+
+libsigrok.la: $(libsigrok_la_OBJECTS) $(libsigrok_la_DEPENDENCIES) $(EXTRA_libsigrok_la_DEPENDENCIES) 
+	$(AM_V_CCLD)$(libsigrok_la_LINK) -rpath $(libdir) $(libsigrok_la_OBJECTS) $(libsigrok_la_LIBADD) $(LIBS)
+
+clean-checkPROGRAMS:
+	@list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+	echo " rm -f" $$list; \
+	rm -f $$list || exit $$?; \
+	test -n "$(EXEEXT)" || exit 0; \
+	list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+	echo " rm -f" $$list; \
+	rm -f $$list
+tests/$(am__dirstamp):
+	@$(MKDIR_P) tests
+	@: > tests/$(am__dirstamp)
+tests/$(DEPDIR)/$(am__dirstamp):
+	@$(MKDIR_P) tests/$(DEPDIR)
+	@: > tests/$(DEPDIR)/$(am__dirstamp)
+tests/tests_check_main-lib.$(OBJEXT): tests/$(am__dirstamp) \
+	tests/$(DEPDIR)/$(am__dirstamp)
+tests/tests_check_main-check_main.$(OBJEXT): tests/$(am__dirstamp) \
+	tests/$(DEPDIR)/$(am__dirstamp)
+tests/tests_check_main-check_core.$(OBJEXT): tests/$(am__dirstamp) \
+	tests/$(DEPDIR)/$(am__dirstamp)
+tests/tests_check_main-check_input_all.$(OBJEXT):  \
+	tests/$(am__dirstamp) tests/$(DEPDIR)/$(am__dirstamp)
+tests/tests_check_main-check_input_binary.$(OBJEXT):  \
+	tests/$(am__dirstamp) tests/$(DEPDIR)/$(am__dirstamp)
+tests/tests_check_main-check_output_all.$(OBJEXT):  \
+	tests/$(am__dirstamp) tests/$(DEPDIR)/$(am__dirstamp)
+tests/tests_check_main-check_strutil.$(OBJEXT): tests/$(am__dirstamp) \
+	tests/$(DEPDIR)/$(am__dirstamp)
+tests/tests_check_main-check_version.$(OBJEXT): tests/$(am__dirstamp) \
+	tests/$(DEPDIR)/$(am__dirstamp)
+tests/tests_check_main-check_driver_all.$(OBJEXT):  \
+	tests/$(am__dirstamp) tests/$(DEPDIR)/$(am__dirstamp)
+
+tests/check_main$(EXEEXT): $(tests_check_main_OBJECTS) $(tests_check_main_DEPENDENCIES) $(EXTRA_tests_check_main_DEPENDENCIES) tests/$(am__dirstamp)
+	@rm -f tests/check_main$(EXEEXT)
+	$(AM_V_CCLD)$(tests_check_main_LINK) $(tests_check_main_OBJECTS) $(tests_check_main_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+	-rm -f hardware/agilent-dmm/*.$(OBJEXT)
+	-rm -f hardware/agilent-dmm/*.lo
+	-rm -f hardware/appa-55ii/*.$(OBJEXT)
+	-rm -f hardware/appa-55ii/*.lo
+	-rm -f hardware/asix-sigma/*.$(OBJEXT)
+	-rm -f hardware/asix-sigma/*.lo
+	-rm -f hardware/atten-pps3xxx/*.$(OBJEXT)
+	-rm -f hardware/atten-pps3xxx/*.lo
+	-rm -f hardware/brymen-bm86x/*.$(OBJEXT)
+	-rm -f hardware/brymen-bm86x/*.lo
+	-rm -f hardware/brymen-dmm/*.$(OBJEXT)
+	-rm -f hardware/brymen-dmm/*.lo
+	-rm -f hardware/cem-dt-885x/*.$(OBJEXT)
+	-rm -f hardware/cem-dt-885x/*.lo
+	-rm -f hardware/center-3xx/*.$(OBJEXT)
+	-rm -f hardware/center-3xx/*.lo
+	-rm -f hardware/chronovu-la/*.$(OBJEXT)
+	-rm -f hardware/chronovu-la/*.lo
+	-rm -f hardware/colead-slm/*.$(OBJEXT)
+	-rm -f hardware/colead-slm/*.lo
+	-rm -f hardware/common/*.$(OBJEXT)
+	-rm -f hardware/common/*.lo
+	-rm -f hardware/common/dmm/*.$(OBJEXT)
+	-rm -f hardware/common/dmm/*.lo
+	-rm -f hardware/conrad-digi-35-cpu/*.$(OBJEXT)
+	-rm -f hardware/conrad-digi-35-cpu/*.lo
+	-rm -f hardware/demo/*.$(OBJEXT)
+	-rm -f hardware/demo/*.lo
+	-rm -f hardware/fluke-dmm/*.$(OBJEXT)
+	-rm -f hardware/fluke-dmm/*.lo
+	-rm -f hardware/fx2lafw/*.$(OBJEXT)
+	-rm -f hardware/fx2lafw/*.lo
+	-rm -f hardware/gmc-mh-1x-2x/*.$(OBJEXT)
+	-rm -f hardware/gmc-mh-1x-2x/*.lo
+	-rm -f hardware/hameg-hmo/*.$(OBJEXT)
+	-rm -f hardware/hameg-hmo/*.lo
+	-rm -f hardware/hantek-dso/*.$(OBJEXT)
+	-rm -f hardware/hantek-dso/*.lo
+	-rm -f hardware/ikalogic-scanalogic2/*.$(OBJEXT)
+	-rm -f hardware/ikalogic-scanalogic2/*.lo
+	-rm -f hardware/ikalogic-scanaplus/*.$(OBJEXT)
+	-rm -f hardware/ikalogic-scanaplus/*.lo
+	-rm -f hardware/kecheng-kc-330b/*.$(OBJEXT)
+	-rm -f hardware/kecheng-kc-330b/*.lo
+	-rm -f hardware/lascar-el-usb/*.$(OBJEXT)
+	-rm -f hardware/lascar-el-usb/*.lo
+	-rm -f hardware/mic-985xx/*.$(OBJEXT)
+	-rm -f hardware/mic-985xx/*.lo
+	-rm -f hardware/norma-dmm/*.$(OBJEXT)
+	-rm -f hardware/norma-dmm/*.lo
+	-rm -f hardware/openbench-logic-sniffer/*.$(OBJEXT)
+	-rm -f hardware/openbench-logic-sniffer/*.lo
+	-rm -f hardware/rigol-ds/*.$(OBJEXT)
+	-rm -f hardware/rigol-ds/*.lo
+	-rm -f hardware/saleae-logic16/*.$(OBJEXT)
+	-rm -f hardware/saleae-logic16/*.lo
+	-rm -f hardware/serial-dmm/*.$(OBJEXT)
+	-rm -f hardware/serial-dmm/*.lo
+	-rm -f hardware/sysclk-lwla/*.$(OBJEXT)
+	-rm -f hardware/sysclk-lwla/*.lo
+	-rm -f hardware/teleinfo/*.$(OBJEXT)
+	-rm -f hardware/teleinfo/*.lo
+	-rm -f hardware/tondaj-sl-814/*.$(OBJEXT)
+	-rm -f hardware/tondaj-sl-814/*.lo
+	-rm -f hardware/uni-t-dmm/*.$(OBJEXT)
+	-rm -f hardware/uni-t-dmm/*.lo
+	-rm -f hardware/uni-t-ut32x/*.$(OBJEXT)
+	-rm -f hardware/uni-t-ut32x/*.lo
+	-rm -f hardware/victor-dmm/*.$(OBJEXT)
+	-rm -f hardware/victor-dmm/*.lo
+	-rm -f hardware/zeroplus-logic-cube/*.$(OBJEXT)
+	-rm -f hardware/zeroplus-logic-cube/*.lo
+	-rm -f input/*.$(OBJEXT)
+	-rm -f input/*.lo
+	-rm -f output/*.$(OBJEXT)
+	-rm -f output/*.lo
+	-rm -f tests/*.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/backend.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/device.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/error.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/hwdriver.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/log.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/session.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/session_driver.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/session_file.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/std.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/strutil.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/version.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/agilent-dmm/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/agilent-dmm/$(DEPDIR)/sched.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/appa-55ii/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/appa-55ii/$(DEPDIR)/protocol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/asix-sigma/$(DEPDIR)/asix-sigma.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/atten-pps3xxx/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/atten-pps3xxx/$(DEPDIR)/protocol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/brymen-bm86x/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/brymen-bm86x/$(DEPDIR)/protocol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/brymen-dmm/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/brymen-dmm/$(DEPDIR)/parser.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/brymen-dmm/$(DEPDIR)/protocol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/cem-dt-885x/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/cem-dt-885x/$(DEPDIR)/protocol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/center-3xx/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/center-3xx/$(DEPDIR)/protocol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/chronovu-la/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/chronovu-la/$(DEPDIR)/protocol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/colead-slm/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/colead-slm/$(DEPDIR)/protocol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/common/$(DEPDIR)/ezusb.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/common/$(DEPDIR)/scpi.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/common/$(DEPDIR)/scpi_serial.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/common/$(DEPDIR)/scpi_tcp.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/common/$(DEPDIR)/scpi_usbtmc_libusb.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/common/$(DEPDIR)/scpi_visa.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/common/$(DEPDIR)/scpi_vxi.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/common/$(DEPDIR)/serial.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/common/$(DEPDIR)/usb.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/common/$(DEPDIR)/vxi_clnt.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/common/$(DEPDIR)/vxi_xdr.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/common/dmm/$(DEPDIR)/es519xx.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/common/dmm/$(DEPDIR)/fs9721.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/common/dmm/$(DEPDIR)/fs9922.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/common/dmm/$(DEPDIR)/m2110.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/common/dmm/$(DEPDIR)/metex14.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/common/dmm/$(DEPDIR)/rs9lcd.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/conrad-digi-35-cpu/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/conrad-digi-35-cpu/$(DEPDIR)/protocol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/demo/$(DEPDIR)/demo.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/fluke-dmm/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/fluke-dmm/$(DEPDIR)/fluke.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/fx2lafw/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/fx2lafw/$(DEPDIR)/protocol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/gmc-mh-1x-2x/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/gmc-mh-1x-2x/$(DEPDIR)/protocol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/hameg-hmo/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/hameg-hmo/$(DEPDIR)/protocol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/hantek-dso/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/hantek-dso/$(DEPDIR)/dso.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/ikalogic-scanalogic2/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/ikalogic-scanalogic2/$(DEPDIR)/protocol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/ikalogic-scanaplus/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/ikalogic-scanaplus/$(DEPDIR)/protocol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/kecheng-kc-330b/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/kecheng-kc-330b/$(DEPDIR)/protocol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/lascar-el-usb/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/lascar-el-usb/$(DEPDIR)/protocol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/mic-985xx/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/mic-985xx/$(DEPDIR)/protocol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/norma-dmm/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/norma-dmm/$(DEPDIR)/protocol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/openbench-logic-sniffer/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/openbench-logic-sniffer/$(DEPDIR)/protocol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/rigol-ds/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/rigol-ds/$(DEPDIR)/protocol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/saleae-logic16/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/saleae-logic16/$(DEPDIR)/protocol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/serial-dmm/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/serial-dmm/$(DEPDIR)/protocol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/sysclk-lwla/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/sysclk-lwla/$(DEPDIR)/lwla.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/sysclk-lwla/$(DEPDIR)/protocol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/teleinfo/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/teleinfo/$(DEPDIR)/protocol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/tondaj-sl-814/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/tondaj-sl-814/$(DEPDIR)/protocol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/uni-t-dmm/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/uni-t-dmm/$(DEPDIR)/protocol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/uni-t-ut32x/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/uni-t-ut32x/$(DEPDIR)/protocol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/victor-dmm/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/victor-dmm/$(DEPDIR)/protocol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/zeroplus-logic-cube/$(DEPDIR)/analyzer.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/zeroplus-logic-cube/$(DEPDIR)/api.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/zeroplus-logic-cube/$(DEPDIR)/gl_usb.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at hardware/zeroplus-logic-cube/$(DEPDIR)/protocol.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at input/$(DEPDIR)/binary.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at input/$(DEPDIR)/chronovu_la8.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at input/$(DEPDIR)/csv.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at input/$(DEPDIR)/input.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at input/$(DEPDIR)/vcd.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at input/$(DEPDIR)/wav.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at output/$(DEPDIR)/analog.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at output/$(DEPDIR)/ascii.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at output/$(DEPDIR)/binary.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at output/$(DEPDIR)/bits.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at output/$(DEPDIR)/chronovu_la8.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at output/$(DEPDIR)/csv.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at output/$(DEPDIR)/gnuplot.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at output/$(DEPDIR)/hex.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at output/$(DEPDIR)/ols.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at output/$(DEPDIR)/output.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at output/$(DEPDIR)/vcd.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at tests/$(DEPDIR)/tests_check_main-check_core.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at tests/$(DEPDIR)/tests_check_main-check_driver_all.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at tests/$(DEPDIR)/tests_check_main-check_input_all.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at tests/$(DEPDIR)/tests_check_main-check_input_binary.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at tests/$(DEPDIR)/tests_check_main-check_main.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at tests/$(DEPDIR)/tests_check_main-check_output_all.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at tests/$(DEPDIR)/tests_check_main-check_strutil.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at tests/$(DEPDIR)/tests_check_main-check_version.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at tests/$(DEPDIR)/tests_check_main-lib.Po at am__quote@
+
+.c.o:
+ at am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+ at am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+ at am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+ at am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+ at am__fastdepCC_TRUE@	$(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+ at am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ at am__fastdepCC_TRUE@	$(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+ at am__fastdepCC_TRUE@	$(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+ at am__fastdepCC_TRUE@	$(am__mv) $$depbase.Tpo $$depbase.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+tests/tests_check_main-lib.o: tests/lib.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -MT tests/tests_check_main-lib.o -MD -MP -MF tests/$(DEPDIR)/tests_check_main-lib.Tpo -c -o tests/tests_check_main-lib.o `test -f 'tests/lib.c' || echo '$(srcdir)/'`tests/lib.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) tests/$(DEPDIR)/tests_check_main-lib.Tpo tests/$(DEPDIR)/tests_check_main-lib.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='tests/lib.c' object='tests/tests_check_main-lib.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -c -o tests/tests_check_main-lib.o `test -f 'tests/lib.c' || echo '$(srcdir)/'`tests/lib.c
+
+tests/tests_check_main-lib.obj: tests/lib.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -MT tests/tests_check_main-lib.obj -MD -MP -MF tests/$(DEPDIR)/tests_check_main-lib.Tpo -c -o tests/tests_check_main-lib.obj `if test -f 'tests/lib.c'; then $(CYGPATH_W) 'tests/lib.c'; else $(CYGPATH_W) '$(srcdir)/tests/lib.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) tests/$(DEPDIR)/tests_check_main-lib.Tpo tests/$(DEPDIR)/tests_check_main-lib.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='tests/lib.c' object='tests/tests_check_main-lib.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -c -o tests/tests_check_main-lib.obj `if test -f 'tests/lib.c'; then $(CYGPATH_W) 'tests/lib.c'; else $(CYGPATH_W) '$(srcdir)/tests/lib.c'; fi`
+
+tests/tests_check_main-check_main.o: tests/check_main.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -MT tests/tests_check_main-check_main.o -MD -MP -MF tests/$(DEPDIR)/tests_check_main-check_main.Tpo -c -o tests/tests_check_main-check_main.o `test -f 'tests/check_main.c' || echo '$(srcdir)/'`tests/check_main.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) tests/$(DEPDIR)/tests_check_main-check_main.Tpo tests/$(DEPDIR)/tests_check_main-check_main.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='tests/check_main.c' object='tests/tests_check_main-check_main.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -c -o tests/tests_check_main-check_main.o `test -f 'tests/check_main.c' || echo '$(srcdir)/'`tests/check_main.c
+
+tests/tests_check_main-check_main.obj: tests/check_main.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -MT tests/tests_check_main-check_main.obj -MD -MP -MF tests/$(DEPDIR)/tests_check_main-check_main.Tpo -c -o tests/tests_check_main-check_main.obj `if test -f 'tests/check_main.c'; then $(CYGPATH_W) 'tests/check_main.c'; else $(CYGPATH_W) '$(srcdir)/tests/check_main.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) tests/$(DEPDIR)/tests_check_main-check_main.Tpo tests/$(DEPDIR)/tests_check_main-check_main.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='tests/check_main.c' object='tests/tests_check_main-check_main.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -c -o tests/tests_check_main-check_main.obj `if test -f 'tests/check_main.c'; then $(CYGPATH_W) 'tests/check_main.c'; else $(CYGPATH_W) '$(srcdir)/tests/check_main.c'; fi`
+
+tests/tests_check_main-check_core.o: tests/check_core.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -MT tests/tests_check_main-check_core.o -MD -MP -MF tests/$(DEPDIR)/tests_check_main-check_core.Tpo -c -o tests/tests_check_main-check_core.o `test -f 'tests/check_core.c' || echo '$(srcdir)/'`tests/check_core.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) tests/$(DEPDIR)/tests_check_main-check_core.Tpo tests/$(DEPDIR)/tests_check_main-check_core.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='tests/check_core.c' object='tests/tests_check_main-check_core.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -c -o tests/tests_check_main-check_core.o `test -f 'tests/check_core.c' || echo '$(srcdir)/'`tests/check_core.c
+
+tests/tests_check_main-check_core.obj: tests/check_core.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -MT tests/tests_check_main-check_core.obj -MD -MP -MF tests/$(DEPDIR)/tests_check_main-check_core.Tpo -c -o tests/tests_check_main-check_core.obj `if test -f 'tests/check_core.c'; then $(CYGPATH_W) 'tests/check_core.c'; else $(CYGPATH_W) '$(srcdir)/tests/check_core.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) tests/$(DEPDIR)/tests_check_main-check_core.Tpo tests/$(DEPDIR)/tests_check_main-check_core.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='tests/check_core.c' object='tests/tests_check_main-check_core.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -c -o tests/tests_check_main-check_core.obj `if test -f 'tests/check_core.c'; then $(CYGPATH_W) 'tests/check_core.c'; else $(CYGPATH_W) '$(srcdir)/tests/check_core.c'; fi`
+
+tests/tests_check_main-check_input_all.o: tests/check_input_all.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -MT tests/tests_check_main-check_input_all.o -MD -MP -MF tests/$(DEPDIR)/tests_check_main-check_input_all.Tpo -c -o tests/tests_check_main-check_input_all.o `test -f 'tests/check_input_all.c' || echo '$(srcdir)/'`tests/check_input_all.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) tests/$(DEPDIR)/tests_check_main-check_input_all.Tpo tests/$(DEPDIR)/tests_check_main-check_input_all.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='tests/check_input_all.c' object='tests/tests_check_main-check_input_all.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -c -o tests/tests_check_main-check_input_all.o `test -f 'tests/check_input_all.c' || echo '$(srcdir)/'`tests/check_input_all.c
+
+tests/tests_check_main-check_input_all.obj: tests/check_input_all.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -MT tests/tests_check_main-check_input_all.obj -MD -MP -MF tests/$(DEPDIR)/tests_check_main-check_input_all.Tpo -c -o tests/tests_check_main-check_input_all.obj `if test -f 'tests/check_input_all.c'; then $(CYGPATH_W) 'tests/check_input_all.c'; else $(CYGPATH_W) '$(srcdir)/tests/check_input_all.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) tests/$(DEPDIR)/tests_check_main-check_input_all.Tpo tests/$(DEPDIR)/tests_check_main-check_input_all.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='tests/check_input_all.c' object='tests/tests_check_main-check_input_all.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -c -o tests/tests_check_main-check_input_all.obj `if test -f 'tests/check_input_all.c'; then $(CYGPATH_W) 'tests/check_input_all.c'; else $(CYGPATH_W) '$(srcdir)/tests/check_input_all.c'; fi`
+
+tests/tests_check_main-check_input_binary.o: tests/check_input_binary.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -MT tests/tests_check_main-check_input_binary.o -MD -MP -MF tests/$(DEPDIR)/tests_check_main-check_input_binary.Tpo -c -o tests/tests_check_main-check_input_binary.o `test -f 'tests/check_input_binary.c' || echo '$(srcdir)/'`tests/check_input_binary.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) tests/$(DEPDIR)/tests_check_main-check_input_binary.Tpo tests/$(DEPDIR)/tests_check_main-check_input_binary.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='tests/check_input_binary.c' object='tests/tests_check_main-check_input_binary.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -c -o tests/tests_check_main-check_input_binary.o `test -f 'tests/check_input_binary.c' || echo '$(srcdir)/'`tests/check_input_binary.c
+
+tests/tests_check_main-check_input_binary.obj: tests/check_input_binary.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -MT tests/tests_check_main-check_input_binary.obj -MD -MP -MF tests/$(DEPDIR)/tests_check_main-check_input_binary.Tpo -c -o tests/tests_check_main-check_input_binary.obj `if test -f 'tests/check_input_binary.c'; then $(CYGPATH_W) 'tests/check_input_binary.c'; else $(CYGPATH_W) '$(srcdir)/tests/check_input_binary.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) tests/$(DEPDIR)/tests_check_main-check_input_binary.Tpo tests/$(DEPDIR)/tests_check_main-check_input_binary.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='tests/check_input_binary.c' object='tests/tests_check_main-check_input_binary.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -c -o tests/tests_check_main-check_input_binary.obj `if test -f 'tests/check_input_binary.c'; then $(CYGPATH_W) 'tests/check_input_binary.c'; else $(CYGPATH_W) '$(srcdir)/tests/check_input_binary.c'; fi`
+
+tests/tests_check_main-check_output_all.o: tests/check_output_all.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -MT tests/tests_check_main-check_output_all.o -MD -MP -MF tests/$(DEPDIR)/tests_check_main-check_output_all.Tpo -c -o tests/tests_check_main-check_output_all.o `test -f 'tests/check_output_all.c' || echo '$(srcdir)/'`tests/check_output_all.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) tests/$(DEPDIR)/tests_check_main-check_output_all.Tpo tests/$(DEPDIR)/tests_check_main-check_output_all.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='tests/check_output_all.c' object='tests/tests_check_main-check_output_all.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -c -o tests/tests_check_main-check_output_all.o `test -f 'tests/check_output_all.c' || echo '$(srcdir)/'`tests/check_output_all.c
+
+tests/tests_check_main-check_output_all.obj: tests/check_output_all.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -MT tests/tests_check_main-check_output_all.obj -MD -MP -MF tests/$(DEPDIR)/tests_check_main-check_output_all.Tpo -c -o tests/tests_check_main-check_output_all.obj `if test -f 'tests/check_output_all.c'; then $(CYGPATH_W) 'tests/check_output_all.c'; else $(CYGPATH_W) '$(srcdir)/tests/check_output_all.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) tests/$(DEPDIR)/tests_check_main-check_output_all.Tpo tests/$(DEPDIR)/tests_check_main-check_output_all.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='tests/check_output_all.c' object='tests/tests_check_main-check_output_all.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -c -o tests/tests_check_main-check_output_all.obj `if test -f 'tests/check_output_all.c'; then $(CYGPATH_W) 'tests/check_output_all.c'; else $(CYGPATH_W) '$(srcdir)/tests/check_output_all.c'; fi`
+
+tests/tests_check_main-check_strutil.o: tests/check_strutil.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -MT tests/tests_check_main-check_strutil.o -MD -MP -MF tests/$(DEPDIR)/tests_check_main-check_strutil.Tpo -c -o tests/tests_check_main-check_strutil.o `test -f 'tests/check_strutil.c' || echo '$(srcdir)/'`tests/check_strutil.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) tests/$(DEPDIR)/tests_check_main-check_strutil.Tpo tests/$(DEPDIR)/tests_check_main-check_strutil.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='tests/check_strutil.c' object='tests/tests_check_main-check_strutil.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -c -o tests/tests_check_main-check_strutil.o `test -f 'tests/check_strutil.c' || echo '$(srcdir)/'`tests/check_strutil.c
+
+tests/tests_check_main-check_strutil.obj: tests/check_strutil.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -MT tests/tests_check_main-check_strutil.obj -MD -MP -MF tests/$(DEPDIR)/tests_check_main-check_strutil.Tpo -c -o tests/tests_check_main-check_strutil.obj `if test -f 'tests/check_strutil.c'; then $(CYGPATH_W) 'tests/check_strutil.c'; else $(CYGPATH_W) '$(srcdir)/tests/check_strutil.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) tests/$(DEPDIR)/tests_check_main-check_strutil.Tpo tests/$(DEPDIR)/tests_check_main-check_strutil.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='tests/check_strutil.c' object='tests/tests_check_main-check_strutil.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -c -o tests/tests_check_main-check_strutil.obj `if test -f 'tests/check_strutil.c'; then $(CYGPATH_W) 'tests/check_strutil.c'; else $(CYGPATH_W) '$(srcdir)/tests/check_strutil.c'; fi`
+
+tests/tests_check_main-check_version.o: tests/check_version.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -MT tests/tests_check_main-check_version.o -MD -MP -MF tests/$(DEPDIR)/tests_check_main-check_version.Tpo -c -o tests/tests_check_main-check_version.o `test -f 'tests/check_version.c' || echo '$(srcdir)/'`tests/check_version.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) tests/$(DEPDIR)/tests_check_main-check_version.Tpo tests/$(DEPDIR)/tests_check_main-check_version.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='tests/check_version.c' object='tests/tests_check_main-check_version.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -c -o tests/tests_check_main-check_version.o `test -f 'tests/check_version.c' || echo '$(srcdir)/'`tests/check_version.c
+
+tests/tests_check_main-check_version.obj: tests/check_version.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -MT tests/tests_check_main-check_version.obj -MD -MP -MF tests/$(DEPDIR)/tests_check_main-check_version.Tpo -c -o tests/tests_check_main-check_version.obj `if test -f 'tests/check_version.c'; then $(CYGPATH_W) 'tests/check_version.c'; else $(CYGPATH_W) '$(srcdir)/tests/check_version.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) tests/$(DEPDIR)/tests_check_main-check_version.Tpo tests/$(DEPDIR)/tests_check_main-check_version.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='tests/check_version.c' object='tests/tests_check_main-check_version.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -c -o tests/tests_check_main-check_version.obj `if test -f 'tests/check_version.c'; then $(CYGPATH_W) 'tests/check_version.c'; else $(CYGPATH_W) '$(srcdir)/tests/check_version.c'; fi`
+
+tests/tests_check_main-check_driver_all.o: tests/check_driver_all.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -MT tests/tests_check_main-check_driver_all.o -MD -MP -MF tests/$(DEPDIR)/tests_check_main-check_driver_all.Tpo -c -o tests/tests_check_main-check_driver_all.o `test -f 'tests/check_driver_all.c' || echo '$(srcdir)/'`tests/check_driver_all.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) tests/$(DEPDIR)/tests_check_main-check_driver_all.Tpo tests/$(DEPDIR)/tests_check_main-check_driver_all.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='tests/check_driver_all.c' object='tests/tests_check_main-check_driver_all.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -c -o tests/tests_check_main-check_driver_all.o `test -f 'tests/check_driver_all.c' || echo '$(srcdir)/'`tests/check_driver_all.c
+
+tests/tests_check_main-check_driver_all.obj: tests/check_driver_all.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -MT tests/tests_check_main-check_driver_all.obj -MD -MP -MF tests/$(DEPDIR)/tests_check_main-check_driver_all.Tpo -c -o tests/tests_check_main-check_driver_all.obj `if test -f 'tests/check_driver_all.c'; then $(CYGPATH_W) 'tests/check_driver_all.c'; else $(CYGPATH_W) '$(srcdir)/tests/check_driver_all.c'; fi`
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) tests/$(DEPDIR)/tests_check_main-check_driver_all.Tpo tests/$(DEPDIR)/tests_check_main-check_driver_all.Po
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='tests/check_driver_all.c' object='tests/tests_check_main-check_driver_all.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(tests_check_main_CFLAGS) $(CFLAGS) -c -o tests/tests_check_main-check_driver_all.obj `if test -f 'tests/check_driver_all.c'; then $(CYGPATH_W) 'tests/check_driver_all.c'; else $(CYGPATH_W) '$(srcdir)/tests/check_driver_all.c'; fi`
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+	-rm -rf hardware/agilent-dmm/.libs hardware/agilent-dmm/_libs
+	-rm -rf hardware/appa-55ii/.libs hardware/appa-55ii/_libs
+	-rm -rf hardware/asix-sigma/.libs hardware/asix-sigma/_libs
+	-rm -rf hardware/atten-pps3xxx/.libs hardware/atten-pps3xxx/_libs
+	-rm -rf hardware/brymen-bm86x/.libs hardware/brymen-bm86x/_libs
+	-rm -rf hardware/brymen-dmm/.libs hardware/brymen-dmm/_libs
+	-rm -rf hardware/cem-dt-885x/.libs hardware/cem-dt-885x/_libs
+	-rm -rf hardware/center-3xx/.libs hardware/center-3xx/_libs
+	-rm -rf hardware/chronovu-la/.libs hardware/chronovu-la/_libs
+	-rm -rf hardware/colead-slm/.libs hardware/colead-slm/_libs
+	-rm -rf hardware/common/.libs hardware/common/_libs
+	-rm -rf hardware/common/dmm/.libs hardware/common/dmm/_libs
+	-rm -rf hardware/conrad-digi-35-cpu/.libs hardware/conrad-digi-35-cpu/_libs
+	-rm -rf hardware/demo/.libs hardware/demo/_libs
+	-rm -rf hardware/fluke-dmm/.libs hardware/fluke-dmm/_libs
+	-rm -rf hardware/fx2lafw/.libs hardware/fx2lafw/_libs
+	-rm -rf hardware/gmc-mh-1x-2x/.libs hardware/gmc-mh-1x-2x/_libs
+	-rm -rf hardware/hameg-hmo/.libs hardware/hameg-hmo/_libs
+	-rm -rf hardware/hantek-dso/.libs hardware/hantek-dso/_libs
+	-rm -rf hardware/ikalogic-scanalogic2/.libs hardware/ikalogic-scanalogic2/_libs
+	-rm -rf hardware/ikalogic-scanaplus/.libs hardware/ikalogic-scanaplus/_libs
+	-rm -rf hardware/kecheng-kc-330b/.libs hardware/kecheng-kc-330b/_libs
+	-rm -rf hardware/lascar-el-usb/.libs hardware/lascar-el-usb/_libs
+	-rm -rf hardware/mic-985xx/.libs hardware/mic-985xx/_libs
+	-rm -rf hardware/norma-dmm/.libs hardware/norma-dmm/_libs
+	-rm -rf hardware/openbench-logic-sniffer/.libs hardware/openbench-logic-sniffer/_libs
+	-rm -rf hardware/rigol-ds/.libs hardware/rigol-ds/_libs
+	-rm -rf hardware/saleae-logic16/.libs hardware/saleae-logic16/_libs
+	-rm -rf hardware/serial-dmm/.libs hardware/serial-dmm/_libs
+	-rm -rf hardware/sysclk-lwla/.libs hardware/sysclk-lwla/_libs
+	-rm -rf hardware/teleinfo/.libs hardware/teleinfo/_libs
+	-rm -rf hardware/tondaj-sl-814/.libs hardware/tondaj-sl-814/_libs
+	-rm -rf hardware/uni-t-dmm/.libs hardware/uni-t-dmm/_libs
+	-rm -rf hardware/uni-t-ut32x/.libs hardware/uni-t-ut32x/_libs
+	-rm -rf hardware/victor-dmm/.libs hardware/victor-dmm/_libs
+	-rm -rf hardware/zeroplus-logic-cube/.libs hardware/zeroplus-logic-cube/_libs
+	-rm -rf input/.libs input/_libs
+	-rm -rf output/.libs output/_libs
+	-rm -rf tests/.libs tests/_libs
+
+distclean-libtool:
+	-rm -f libtool config.lt
+install-pkgconfigDATA: $(pkgconfig_DATA)
+	@$(NORMAL_INSTALL)
+	@list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \
+	fi; \
+	for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \
+	  $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \
+	done
+
+uninstall-pkgconfigDATA:
+	@$(NORMAL_UNINSTALL)
+	@list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+	files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+	dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir)
+install-library_includeHEADERS: $(library_include_HEADERS)
+	@$(NORMAL_INSTALL)
+	@list='$(library_include_HEADERS)'; test -n "$(library_includedir)" || list=; \
+	if test -n "$$list"; then \
+	  echo " $(MKDIR_P) '$(DESTDIR)$(library_includedir)'"; \
+	  $(MKDIR_P) "$(DESTDIR)$(library_includedir)" || exit 1; \
+	fi; \
+	for p in $$list; do \
+	  if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+	  echo "$$d$$p"; \
+	done | $(am__base_list) | \
+	while read files; do \
+	  echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(library_includedir)'"; \
+	  $(INSTALL_HEADER) $$files "$(DESTDIR)$(library_includedir)" || exit $$?; \
+	done
+
+uninstall-library_includeHEADERS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(library_include_HEADERS)'; test -n "$(library_includedir)" || list=; \
+	files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+	dir='$(DESTDIR)$(library_includedir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+	$(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	set x; \
+	here=`pwd`; \
+	$(am__define_uniq_tagged_files); \
+	shift; \
+	if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  if test $$# -gt 0; then \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      "$$@" $$unique; \
+	  else \
+	    $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	      $$unique; \
+	  fi; \
+	fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+	$(am__define_uniq_tagged_files); \
+	test -z "$(CTAGS_ARGS)$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && $(am__cd) $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) "$$here"
+cscope: cscope.files
+	test ! -s cscope.files \
+	  || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS)
+clean-cscope:
+	-rm -f cscope.files
+cscope.files: clean-cscope cscopelist
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+	list='$(am__tagged_files)'; \
+	case "$(srcdir)" in \
+	  [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+	  *) sdir=$(subdir)/$(srcdir) ;; \
+	esac; \
+	for i in $$list; do \
+	  if test -f "$$i"; then \
+	    echo "$(subdir)/$$i"; \
+	  else \
+	    echo "$$sdir/$$i"; \
+	  fi; \
+	done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+	-rm -f cscope.out cscope.in.out cscope.po.out cscope.files
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'.  Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+	rm -f $< $@
+	$(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+	@:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+	@$(am__set_TESTS_bases); \
+	am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+	redo_bases=`for i in $$bases; do \
+	              am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+	            done`; \
+	if test -n "$$redo_bases"; then \
+	  redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+	  redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+	  if $(am__make_dryrun); then :; else \
+	    rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+	  fi; \
+	fi; \
+	if test -n "$$am__remaking_logs"; then \
+	  echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+	       "recursion detected" >&2; \
+	else \
+	  am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+	fi; \
+	if $(am__make_dryrun); then :; else \
+	  st=0;  \
+	  errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+	  for i in $$redo_bases; do \
+	    test -f $$i.trs && test -r $$i.trs \
+	      || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+	    test -f $$i.log && test -r $$i.log \
+	      || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+	  done; \
+	  test $$st -eq 0 || exit 1; \
+	fi
+	@$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+	ws='[ 	]'; \
+	results=`for b in $$bases; do echo $$b.trs; done`; \
+	test -n "$$results" || results=/dev/null; \
+	all=`  grep "^$$ws*:test-result:"           $$results | wc -l`; \
+	pass=` grep "^$$ws*:test-result:$$ws*PASS"  $$results | wc -l`; \
+	fail=` grep "^$$ws*:test-result:$$ws*FAIL"  $$results | wc -l`; \
+	skip=` grep "^$$ws*:test-result:$$ws*SKIP"  $$results | wc -l`; \
+	xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+	xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+	error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+	if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+	  success=true; \
+	else \
+	  success=false; \
+	fi; \
+	br='==================='; br=$$br$$br$$br$$br; \
+	result_count () \
+	{ \
+	    if test x"$$1" = x"--maybe-color"; then \
+	      maybe_colorize=yes; \
+	    elif test x"$$1" = x"--no-color"; then \
+	      maybe_colorize=no; \
+	    else \
+	      echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+	    fi; \
+	    shift; \
+	    desc=$$1 count=$$2; \
+	    if test $$maybe_colorize = yes && test $$count -gt 0; then \
+	      color_start=$$3 color_end=$$std; \
+	    else \
+	      color_start= color_end=; \
+	    fi; \
+	    echo "$${color_start}# $$desc $$count$${color_end}"; \
+	}; \
+	create_testsuite_report () \
+	{ \
+	  result_count $$1 "TOTAL:" $$all   "$$brg"; \
+	  result_count $$1 "PASS: " $$pass  "$$grn"; \
+	  result_count $$1 "SKIP: " $$skip  "$$blu"; \
+	  result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+	  result_count $$1 "FAIL: " $$fail  "$$red"; \
+	  result_count $$1 "XPASS:" $$xpass "$$red"; \
+	  result_count $$1 "ERROR:" $$error "$$mgn"; \
+	}; \
+	{								\
+	  echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" |	\
+	    $(am__rst_title);						\
+	  create_testsuite_report --no-color;				\
+	  echo;								\
+	  echo ".. contents:: :depth: 2";				\
+	  echo;								\
+	  for b in $$bases; do echo $$b; done				\
+	    | $(am__create_global_log);					\
+	} >$(TEST_SUITE_LOG).tmp || exit 1;				\
+	mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG);			\
+	if $$success; then						\
+	  col="$$grn";							\
+	 else								\
+	  col="$$red";							\
+	  test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG);		\
+	fi;								\
+	echo "$${col}$$br$${std}"; 					\
+	echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}";	\
+	echo "$${col}$$br$${std}"; 					\
+	create_testsuite_report --maybe-color;				\
+	echo "$$col$$br$$std";						\
+	if $$success; then :; else					\
+	  echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}";		\
+	  if test -n "$(PACKAGE_BUGREPORT)"; then			\
+	    echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}";	\
+	  fi;								\
+	  echo "$$col$$br$$std";					\
+	fi;								\
+	$$success || exit 1
+
+check-TESTS:
+	@list='$(RECHECK_LOGS)';           test -z "$$list" || rm -f $$list
+	@list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+	@set +e; $(am__set_TESTS_bases); \
+	log_list=`for i in $$bases; do echo $$i.log; done`; \
+	trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+	log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+	exit $$?;
+recheck: all $(check_PROGRAMS)
+	@test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+	@set +e; $(am__set_TESTS_bases); \
+	bases=`for i in $$bases; do echo $$i; done \
+	         | $(am__list_recheck_tests)` || exit 1; \
+	log_list=`for i in $$bases; do echo $$i.log; done`; \
+	log_list=`echo $$log_list`; \
+	$(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+	        am__force_recheck=am--force-recheck \
+	        TEST_LOGS="$$log_list"; \
+	exit $$?
+tests/check_main.log: tests/check_main$(EXEEXT)
+	@p='tests/check_main$(EXEEXT)'; \
+	b='tests/check_main'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+	@p='$<'; \
+	$(am__set_b); \
+	$(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
+ at am__EXEEXT_TRUE@.test$(EXEEXT).log:
+ at am__EXEEXT_TRUE@	@p='$<'; \
+ at am__EXEEXT_TRUE@	$(am__set_b); \
+ at am__EXEEXT_TRUE@	$(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+ at am__EXEEXT_TRUE@	--log-file $$b.log --trs-file $$b.trs \
+ at am__EXEEXT_TRUE@	$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+ at am__EXEEXT_TRUE@	"$$tst" $(AM_TESTS_FD_REDIRECT)
+
+distdir: $(DISTFILES)
+	@case `sed 15q $(srcdir)/NEWS` in \
+	*"$(VERSION)"*) : ;; \
+	*) \
+	  echo "NEWS not updated; not releasing" 1>&2; \
+	  exit 1;; \
+	esac
+	$(am__remove_distdir)
+	test -d "$(distdir)" || mkdir "$(distdir)"
+	@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+	list='$(DISTFILES)'; \
+	  dist_files=`for file in $$list; do echo $$file; done | \
+	  sed -e "s|^$$srcdirstrip/||;t" \
+	      -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+	case $$dist_files in \
+	  */*) $(MKDIR_P) `echo "$$dist_files" | \
+			   sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+			   sort -u` ;; \
+	esac; \
+	for file in $$dist_files; do \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  if test -d $$d/$$file; then \
+	    dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+	    if test -d "$(distdir)/$$file"; then \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+	      find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+	    fi; \
+	    cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+	  else \
+	    test -f "$(distdir)/$$file" \
+	    || cp -p $$d/$$file "$(distdir)/$$file" \
+	    || exit 1; \
+	  fi; \
+	done
+	$(MAKE) $(AM_MAKEFLAGS) \
+	  top_distdir="$(top_distdir)" distdir="$(distdir)" \
+	  dist-hook
+	-test -n "$(am__skip_mode_fix)" \
+	|| find "$(distdir)" -type d ! -perm -755 \
+		-exec chmod u+rwx,go+rx {} \; -o \
+	  ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+	  ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+	  ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
+	|| chmod -R a+r "$(distdir)"
+dist-gzip: distdir
+	tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+	$(am__post_remove_distdir)
+
+dist-bzip2: distdir
+	tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
+	$(am__post_remove_distdir)
+
+dist-lzip: distdir
+	tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz
+	$(am__post_remove_distdir)
+
+dist-xz: distdir
+	tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
+	$(am__post_remove_distdir)
+
+dist-tarZ: distdir
+	@echo WARNING: "Support for shar distribution archives is" \
+	               "deprecated." >&2
+	@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+	tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+	$(am__post_remove_distdir)
+
+dist-shar: distdir
+	@echo WARNING: "Support for distribution archives compressed with" \
+		       "legacy program 'compress' is deprecated." >&2
+	@echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+	shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+	$(am__post_remove_distdir)
+
+dist-zip: distdir
+	-rm -f $(distdir).zip
+	zip -rq $(distdir).zip $(distdir)
+	$(am__post_remove_distdir)
+
+dist dist-all:
+	$(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:'
+	$(am__post_remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration.  Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+	case '$(DIST_ARCHIVES)' in \
+	*.tar.gz*) \
+	  GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
+	*.tar.bz2*) \
+	  bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
+	*.tar.lz*) \
+	  lzip -dc $(distdir).tar.lz | $(am__untar) ;;\
+	*.tar.xz*) \
+	  xz -dc $(distdir).tar.xz | $(am__untar) ;;\
+	*.tar.Z*) \
+	  uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+	*.shar.gz*) \
+	  GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
+	*.zip*) \
+	  unzip $(distdir).zip ;;\
+	esac
+	chmod -R a-w $(distdir)
+	chmod u+w $(distdir)
+	mkdir $(distdir)/_build $(distdir)/_inst
+	chmod a-w $(distdir)
+	test -d $(distdir)/_build || exit 0; \
+	dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+	  && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+	  && am__cwd=`pwd` \
+	  && $(am__cd) $(distdir)/_build \
+	  && ../configure \
+	    $(AM_DISTCHECK_CONFIGURE_FLAGS) \
+	    $(DISTCHECK_CONFIGURE_FLAGS) \
+	    --srcdir=.. --prefix="$$dc_install_base" \
+	  && $(MAKE) $(AM_MAKEFLAGS) \
+	  && $(MAKE) $(AM_MAKEFLAGS) dvi \
+	  && $(MAKE) $(AM_MAKEFLAGS) check \
+	  && $(MAKE) $(AM_MAKEFLAGS) install \
+	  && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+	  && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+	  && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+	        distuninstallcheck \
+	  && chmod -R a-w "$$dc_install_base" \
+	  && ({ \
+	       (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+	       && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+	            distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+	      } || { rm -rf "$$dc_destdir"; exit 1; }) \
+	  && rm -rf "$$dc_destdir" \
+	  && $(MAKE) $(AM_MAKEFLAGS) dist \
+	  && rm -rf $(DIST_ARCHIVES) \
+	  && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
+	  && cd "$$am__cwd" \
+	  || exit 1
+	$(am__post_remove_distdir)
+	@(echo "$(distdir) archives ready for distribution: "; \
+	  list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+	  sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
+distuninstallcheck:
+	@test -n '$(distuninstallcheck_dir)' || { \
+	  echo 'ERROR: trying to run $@ with an empty' \
+	       '$$(distuninstallcheck_dir)' >&2; \
+	  exit 1; \
+	}; \
+	$(am__cd) '$(distuninstallcheck_dir)' || { \
+	  echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \
+	  exit 1; \
+	}; \
+	test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \
+	   || { echo "ERROR: files left after uninstall:" ; \
+	        if test -n "$(DESTDIR)"; then \
+	          echo "  (check DESTDIR support)"; \
+	        fi ; \
+	        $(distuninstallcheck_listfiles) ; \
+	        exit 1; } >&2
+distcleancheck: distclean
+	@if test '$(srcdir)' = . ; then \
+	  echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+	  exit 1 ; \
+	fi
+	@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+	  || { echo "ERROR: files left in build directory after distclean:" ; \
+	       $(distcleancheck_listfiles) ; \
+	       exit 1; } >&2
+check-am: all-am
+	$(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+	$(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(DATA) $(HEADERS) config.h
+installdirs:
+	for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(library_includedir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	if test -z '$(STRIP)'; then \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	      install; \
+	else \
+	  $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	    install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	    "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+	fi
+mostlyclean-generic:
+	-test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+	-test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+	-test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+	-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+	-rm -f hardware/agilent-dmm/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/agilent-dmm/$(am__dirstamp)
+	-rm -f hardware/appa-55ii/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/appa-55ii/$(am__dirstamp)
+	-rm -f hardware/asix-sigma/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/asix-sigma/$(am__dirstamp)
+	-rm -f hardware/atten-pps3xxx/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/atten-pps3xxx/$(am__dirstamp)
+	-rm -f hardware/brymen-bm86x/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/brymen-bm86x/$(am__dirstamp)
+	-rm -f hardware/brymen-dmm/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/brymen-dmm/$(am__dirstamp)
+	-rm -f hardware/cem-dt-885x/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/cem-dt-885x/$(am__dirstamp)
+	-rm -f hardware/center-3xx/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/center-3xx/$(am__dirstamp)
+	-rm -f hardware/chronovu-la/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/chronovu-la/$(am__dirstamp)
+	-rm -f hardware/colead-slm/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/colead-slm/$(am__dirstamp)
+	-rm -f hardware/common/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/common/$(am__dirstamp)
+	-rm -f hardware/common/dmm/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/common/dmm/$(am__dirstamp)
+	-rm -f hardware/conrad-digi-35-cpu/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/conrad-digi-35-cpu/$(am__dirstamp)
+	-rm -f hardware/demo/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/demo/$(am__dirstamp)
+	-rm -f hardware/fluke-dmm/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/fluke-dmm/$(am__dirstamp)
+	-rm -f hardware/fx2lafw/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/fx2lafw/$(am__dirstamp)
+	-rm -f hardware/gmc-mh-1x-2x/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/gmc-mh-1x-2x/$(am__dirstamp)
+	-rm -f hardware/hameg-hmo/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/hameg-hmo/$(am__dirstamp)
+	-rm -f hardware/hantek-dso/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/hantek-dso/$(am__dirstamp)
+	-rm -f hardware/ikalogic-scanalogic2/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/ikalogic-scanalogic2/$(am__dirstamp)
+	-rm -f hardware/ikalogic-scanaplus/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/ikalogic-scanaplus/$(am__dirstamp)
+	-rm -f hardware/kecheng-kc-330b/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/kecheng-kc-330b/$(am__dirstamp)
+	-rm -f hardware/lascar-el-usb/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/lascar-el-usb/$(am__dirstamp)
+	-rm -f hardware/mic-985xx/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/mic-985xx/$(am__dirstamp)
+	-rm -f hardware/norma-dmm/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/norma-dmm/$(am__dirstamp)
+	-rm -f hardware/openbench-logic-sniffer/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/openbench-logic-sniffer/$(am__dirstamp)
+	-rm -f hardware/rigol-ds/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/rigol-ds/$(am__dirstamp)
+	-rm -f hardware/saleae-logic16/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/saleae-logic16/$(am__dirstamp)
+	-rm -f hardware/serial-dmm/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/serial-dmm/$(am__dirstamp)
+	-rm -f hardware/sysclk-lwla/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/sysclk-lwla/$(am__dirstamp)
+	-rm -f hardware/teleinfo/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/teleinfo/$(am__dirstamp)
+	-rm -f hardware/tondaj-sl-814/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/tondaj-sl-814/$(am__dirstamp)
+	-rm -f hardware/uni-t-dmm/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/uni-t-dmm/$(am__dirstamp)
+	-rm -f hardware/uni-t-ut32x/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/uni-t-ut32x/$(am__dirstamp)
+	-rm -f hardware/victor-dmm/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/victor-dmm/$(am__dirstamp)
+	-rm -f hardware/zeroplus-logic-cube/$(DEPDIR)/$(am__dirstamp)
+	-rm -f hardware/zeroplus-logic-cube/$(am__dirstamp)
+	-rm -f input/$(DEPDIR)/$(am__dirstamp)
+	-rm -f input/$(am__dirstamp)
+	-rm -f output/$(DEPDIR)/$(am__dirstamp)
+	-rm -f output/$(am__dirstamp)
+	-rm -f tests/$(DEPDIR)/$(am__dirstamp)
+	-rm -f tests/$(am__dirstamp)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \
+	clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
+	-rm -rf ./$(DEPDIR) hardware/agilent-dmm/$(DEPDIR) hardware/appa-55ii/$(DEPDIR) hardware/asix-sigma/$(DEPDIR) hardware/atten-pps3xxx/$(DEPDIR) hardware/brymen-bm86x/$(DEPDIR) hardware/brymen-dmm/$(DEPDIR) hardware/cem-dt-885x/$(DEPDIR) hardware/center-3xx/$(DEPDIR) hardware/chronovu-la/$(DEPDIR) hardware/colead-slm/$(DEPDIR) hardware/common/$(DEPDIR) hardware/common/dmm/$(DEPDIR) hardware/conrad-digi-35-cpu/$(DEPDIR) hardware/demo/$(DEPDIR) hardware/fluke-dmm/$(DEPDIR) hardware/fx2lafw/ [...]
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-hdr distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-library_includeHEADERS install-pkgconfigDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -f $(am__CONFIG_DISTCLEAN_FILES)
+	-rm -rf $(top_srcdir)/autom4te.cache
+	-rm -rf ./$(DEPDIR) hardware/agilent-dmm/$(DEPDIR) hardware/appa-55ii/$(DEPDIR) hardware/asix-sigma/$(DEPDIR) hardware/atten-pps3xxx/$(DEPDIR) hardware/brymen-bm86x/$(DEPDIR) hardware/brymen-dmm/$(DEPDIR) hardware/cem-dt-885x/$(DEPDIR) hardware/center-3xx/$(DEPDIR) hardware/chronovu-la/$(DEPDIR) hardware/colead-slm/$(DEPDIR) hardware/common/$(DEPDIR) hardware/common/dmm/$(DEPDIR) hardware/conrad-digi-35-cpu/$(DEPDIR) hardware/demo/$(DEPDIR) hardware/fluke-dmm/$(DEPDIR) hardware/fx2lafw/ [...]
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-libLTLIBRARIES \
+	uninstall-library_includeHEADERS uninstall-pkgconfigDATA
+
+.MAKE: all check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--refresh check check-TESTS \
+	check-am clean clean-checkPROGRAMS clean-cscope clean-generic \
+	clean-libLTLIBRARIES clean-libtool cscope cscopelist-am ctags \
+	ctags-am dist dist-all dist-bzip2 dist-gzip dist-hook \
+	dist-lzip dist-shar dist-tarZ dist-xz dist-zip distcheck \
+	distclean distclean-compile distclean-generic distclean-hdr \
+	distclean-libtool distclean-tags distcleancheck distdir \
+	distuninstallcheck dvi dvi-am html html-am info info-am \
+	install install-am install-data install-data-am install-dvi \
+	install-dvi-am install-exec install-exec-am install-html \
+	install-html-am install-info install-info-am \
+	install-libLTLIBRARIES install-library_includeHEADERS \
+	install-man install-pdf install-pdf-am install-pkgconfigDATA \
+	install-ps install-ps-am install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	recheck tags tags-am uninstall uninstall-am \
+	uninstall-libLTLIBRARIES uninstall-library_includeHEADERS \
+	uninstall-pkgconfigDATA
+
+
+.PHONY: ChangeLog
+ChangeLog:
+	git --git-dir $(top_srcdir)/.git log > ChangeLog || touch ChangeLog
+
+dist-hook: ChangeLog
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..b9aa277
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,497 @@
+0.3.0 (2014-05-06)
+------------------
+
+Note: This release DOES change the libsigrok API. That means it is NOT
+      backwards-compatible and frontends will need updates.
+
+ * New supported hardware:
+   - Logic analyzers:
+     - ChronoVu LA16
+     - Sysclk LWLA1034
+   - Oscilloscopes:
+     - Agilent DSO1000 series (various models)
+     - Hameg HMO compact series (various models)
+     - Rigol DS2000 series (various models)
+     - Rigol VS5000 series (various models)
+   - Multimeters:
+     - BBC Goerz Metrawatt M2110
+     - Brymen BM869
+     - Fluke 189
+     - Gossen Metrawatt MetraHIT 1x/2x series (various models)
+     - Tenma 72-7745 (rebadged UNI-T UT60E)
+     - Tenma 72-7750 (rebadged UNI-T UT60G)
+     - UNI-T UT60G
+     - UNI-T UT61B
+     - UNI-T UT61C
+     - V&A VA40B
+     - Voltcraft M-3650CR
+     - Voltcraft ME-42
+   - Thermometers:
+     - APPA 55II
+   - Programmable power supplies:
+     - Atten PPS3000 series (various models, tested on PPS3203T-3S).
+     - Conrad DIGI 35 CPU
+ * Add support for channel groups.
+ * Add generic SCPI backend code which can be used via various transports:
+   - Serial ports
+   - USBTMC
+   - TCP/RAW
+   - TCP/Rigol (Rigol-VS5000 series specific)
+   - VXI
+   - librevisa
+ * udev rules file: Add entries for newly supported hardware.
+ * New config keys:
+   - SR_CONF_DEMODULATOR
+   - SR_CONF_CENTER_FREQUENCY
+   - SR_CONF_NUM_LOGIC_CHANNELS
+   - SR_CONF_NUM_ANALOG_CHANNELS
+   - SR_CONF_CLOCK_EDGE
+   - SR_CONF_POWER_SUPPLY
+   - SR_CONF_OUTPUT_VOLTAGE
+   - SR_CONF_OUTPUT_VOLTAGE_MAX
+   - SR_CONF_OUTPUT_CURRENT
+   - SR_CONF_OUTPUT_CURRENT_MAX
+   - SR_CONF_OUTPUT_ENABLED
+   - SR_CONF_OUTPUT_CHANNEL
+   - SR_CONF_OVER_VOLTAGE_PROTECTION
+   - SR_CONF_OVER_CURRENT_PROTECTION
+   - SR_CONF_DEVICE_MODE
+   - SR_CONF_TEST_MODE
+ * New config info types:
+   - SR_T_INT32
+ * New measurement quantity keys:
+   - SR_MQ_TIME
+ * New measurement quantity flags:
+   - SR_MQFLAG_DURATION
+   - SR_MQFLAG_AVG
+ * New device instance types:
+   - SR_INST_SCPI
+ * New error codes:
+   - SR_ERR_CHANNEL_GROUP
+ ∗ The SR_T_CHAR config type has been renamed to SR_T_STRING.
+ * New build dependencies:
+   - libserialport >= 0.1.0 (optional).
+     - All drivers that talk to serial ports now require libserialport.
+     - If libserialport is not found, those drivers will not be built.
+   - librevisa >= 0.0.20130812 (optional, only used by some drivers).
+ * Dropped build dependecies:
+   - libasound2 is no longer required (only the removed alsa driver used it).
+   - libudev is no longer required (only the removed link-mso19 driver used it).
+ * Serial port handling code:
+   - Add support for 5/6 data bits and non-standard baud rates.
+   - Fix an issue related to nonblocking reads (bug #188).
+   - Fix an 'invalid arguments' condition causing problems (bug #192).
+ * alsa: This driver was removed (also fixes bugs #28, #61, #96, #114).
+ * asix-sigma:
+   - Publish SR_CONF_CAPTURE_RATIO correctly (bugs #287, #291).
+   - Don't set invalid config options (bug #86).
+   - Various other bugfixes.
+ * cem-dt-885x: Fix a code portability issue (bug #267).
+ * chronovu-la:
+   - Rename the 'chronovu-la8' driver to 'chronovu-la'.
+   - Add support for the ChronoVu LA16.
+   - Fix a segfault when doing multiple acquisitions on an LA8 (bug #247).
+   - Document that streaming is not possible for LA8/LA16 (bug #261).
+ * demo:
+   - Add support for analog channels (bug #11).
+   - Make the number of channels user-configurable.
+   - Add per-channel-group options.
+   - Implement analog sample patterns: sine, triangle, sawtooth.
+   - Fix a samplerate related issue with rates >= 50kHz (bugs #294, #295).
+   - Fix an issue causing data glitches every 40ms (bug #297).
+   - Fix an issue related to channel group handling (bug #262).
+ * digitek-dt4000zc: Fix driver on NetBSD due to missing DTR=1 (bug #189).
+ * fx2lafw:
+   - Fix incorrect unitsize when a trigger fires (bug #182).
+   - Implement config_get() for SR_CONF_LIMIT_SAMPLES.
+   - Don't send more samples than requested to the session bus.
+ * gmc-mh-1x-2x:
+   - Add new (sub)driver 'gmc-mh-2x-bd232'.
+   - Add support for the SI232-II interface.
+ * hameg-hmo:
+   - Fix a build issue on Mac OS X (bug #216).
+   - Various fixes related to frame limit, samplerate, options, etc.
+ * link-mso19: Drop unfinished driver for now (until it starts working).
+ * openbench-logic-sniffer:
+   - Fix a serial port related issue/hang, seen on (e.g.) NetBSD.
+   - Fix an SR_CONF_PATTERN_MODE related problem (bugs #184, #190).
+   - Fix a serial (non)blocking mode issue (bug #231).
+   - Temporarily disable the driver on Windows (needs portability fixes).
+   - Fix an endianness issue in the protocol handling (bug #135).
+   - Fix a sampling issue when (samples % 4) != 0 (bug #200).
+   - Fix an issue occuring when all channels were disabled (bugs #316, #347).
+   - Add an option to turn test patterns off again (bug #293).
+ * rigol-ds:
+   - Rename the 'rigol-ds1xx2' driver to 'rigol-ds'.
+   - Add support for more models and unify the driver code (bug #212).
+   - Add support for RS232 connectivity (previously only USBTMC worked).
+   - Enable the driver on non-Linux platforms since all transports the driver
+     uses are provided by cross-platform code/libs now (e.g. serial, USBTMC).
+   - Add support for 4 channels (required by some models).
+   - Add support for channel groups.
+   - Advertise SR_CONF_LIMIT_FRAMES support.
+   - Fix an issue with SR_DF_END sending.
+   - Enable/disable LA pod when (de)selecting digital channels.
+   - Disable key lock when closing device.
+   - Work around issues due to DS1000 specific protocol changes (bug #283).
+   - Fix incorrect digital channel numbers on some models (bug #269).
+   - Fix an issue with partial data reads (bugs #220, #209, #207).
+ * saleae-logic16:
+   - Fix an issue related to USB device claiming (bug #159).
+   - Don't send more samples than requested to the session bus (bug #350).
+   - Use unitsize 1 (not 2) if none of channels 8-15 are used.
+ * serial-dmm: Fix some parse issues by increasing a timeout.
+ * sysclk-lwla: Fix a sampling issue related to a glib API call (bug #270).
+ * uni-t-ut32x: Fix typo which prevented usage with multiple devices.
+ * victor-dmm: Fix MIN/MAX always being reported (bug #228).
+ * zeroplus-logic-cube:
+   - Add support for 32-channel models and additional memory sizes.
+   - Fix a frontend issue due to missing SR_CONF_CAPTURE_RATIO.
+   - Fix an issue causing pre-trigger garbage data to be sent (bug #222).
+   - Add initial voltage threshold support.
+ * Various drivers:
+   - Expose missing SR_CONF_TRIGGER_TYPE.
+   - Report max. possible number of samples (bugs #197, #258, #263).
+ * Output modules:
+   - Skip analog channels in logic-only output formats.
+   - Remove the obolete output module API, add wrapper calls for the new one.
+   - Stop using the obsolete output API (bugs #288, #47, #48).
+   - Properly receive and handle samplerate metadata (bug #46).
+ * input/vcd: Abort with an error upon > 64 channels (bug #194).
+ * output/vcd:
+   - Fix output for more than 8 channels.
+   - Output timestamp only once per change.
+   - Minor whitespace changes of output files to make them more readable.
+   - Remove bogus $dumpvars and $dumpoff commands.
+   - Various bugfixes and portability fixes.
+ * output/csv:
+   - Remove a 64-channel limit (bug #193).
+   - Fix an issue resulting in incorrect trailing commas (bug #230).
+   - Fix an issue where all timestamps would be zero (bug #35).
+ * Rename 'probe' to 'channel' in all places, since libsigrok supports a lot
+   of gear where 'channel' fits better (bug #259).
+ * Change TRIGGER_SLOPE from SR_T_UINT64 to SR_T_STRING.
+ * Windows support improvements:
+   - Use libserialport (+other backend code) to fix serial devices (bug #91).
+   - Add serial source addition/removal backend code (bug #206).
+   - Add backend code for properly supporting USB based devices.
+ * Fix various memory leaks in the backend code.
+ * Fix some incorrect parsing of floating point numbers in the strutil code.
+ * Fix various endianness issues in backend code and drivers (bug #266).
+ * Fix a few issues related to incorrect parsing with non-ANSI-C locales
+   (bugs #271, #272, #273, #274).
+ * Fix an issue related to data being sent to the libsigrok session which
+   was not a multiple of the unit/sample size (bugs, #289, #290).
+ * Drop the es51922 DMM parser (replaced by the generic es519xx parser).
+ * libsigrok session files:
+   - The libsigrok session file format (for *.sr files) has changed, and the
+     file format 'version' field is bumped to 2. Older libsigrok versions will
+     not be able to handle version 2 files, but new libsigrok versions can
+     handle both version 1 and version 2 files. New libsigrok versions will
+     always write/output version 2 files.
+   - Fix an issue resulting in left-over temporary files (bug #276).
+   - Fix an issue with analog probes (unsupported) in *.sr files (bug #277).
+   - Fix an issue with missing samplerate from session files (bug #275).
+ * Improved API documentation.
+ * Major API changes (overview):
+   - Change various function/macro names related to the probe->channel rename.
+   - Change various functions due to the new channel group feature.
+   - All enums in the public API now have names (e.g. 'enum sr_mqflag').
+   - The lib no longer defineѕ names with _t suffix (POSIX reserved).
+   - New API calls:
+      - sr_session_dev_list()
+      - sr_session_save_init()
+      - sr_session_append()
+      - sr_config_commit()
+      - sr_output_new()
+      - sr_output_send()
+      - sr_output_free()
+   - Obsoleted and removed API calls:
+      - sr_filter_channels()
+   - 'struct sr_session' is now opaque (contents shouldn't be used directly).
+   - Please see the Doxygen API documentation for further details.
+ * Build system:
+   - Switch to a non-recursive automake setup (fewer files, faster builds).
+   - configure: Clearly mark required and optional libs.
+
+0.2.2 (2013-11-04)
+------------------
+
+Note: This release does NOT change the libsigrok API. While new config keys,
+      config info types, and unit codes have been added (additional enum
+      entries / numbers), no existing interfaces were added/changed/removed.
+      Frontends should continue to work fine without recompiling or relinking.
+
+ * New supported hardware:
+   - Logic analyzers:
+     - Saleae Logic16
+   - Thermometers:
+     - Center 309
+     - UNI-T UT325
+     - Voltcraft K204
+   - Multimeters:
+     - ISOTECH IDM103N
+     - Metex M-4650CR
+     - Norma DM950
+     - Voltcraft M-4650CR
+   - Energy meters:
+     - EDF Teleinfo
+ * New config keys:
+   - SR_CONF_VOLTAGE_THRESHOLD
+   - SR_CONF_EXTERNAL_CLOCK
+   - SR_CONF_SWAP
+   - SR_CONF_ENERGYMETER
+ * New config info types:
+   - SR_T_DOUBLE_RANGE
+ * New units:
+   - SR_UNIT_REVOLUTIONS_PER_MINUTE
+   - SR_UNIT_VOLT_AMPERE
+   - SR_UNIT_WATT
+   - SR_UNIT_WATT_HOUR
+ * New input modules:
+   - csv (comma-separated values)
+ * Bump required libzip version to >= 0.10.
+ * uni-t-dmm: This driver now requires the specification of the USB VID/PID
+   of the cable that is used. Example for sigrok-cli:
+    - Old: sigrok-cli --driver voltcraft-vc820 ...
+    - New: sigrok-cli --driver voltcraft-vc820:conn=1a86.e008 ...
+ * openbench-logic-sniffer:
+   - Initial test pattern support (SR_CONF_PATTERN_MODE).
+   - Initial external clock support (SR_CONF_EXTERNAL_CLOCK).
+   - Initial channel swap support (SR_CONF_SWAP).
+   - Various minor fixes and improvements.
+ * When a frontend adds a device instance to a running session, start
+   acquisition on it. This helps with the collectd use-case where devices
+   can be removed and added dynamically while a session is running.
+ * rigol-ds1xx2: Support newer Linux kernels with USBTMC in /sys/class/usbmisc.
+ * rigol-ds1xx2: Also detect the Rigol DS1152E/DS1152D.
+ * agilent-dmm: Fix a segfault happening in certain cases.
+ * output/analog: Support all currently known MQFLAGs.
+ * Fix a minor compile issue due to an incorrect #include.
+ * Fix two compile issues on FreeBSD (bug #185).
+ * es519xx: New generic parser for various Cyrustek DMM ICs.
+ * es51922/fs9721/fs9922/metex14: Use diode MQFLAG (bug #141).
+ * voltcraft-vc830: Fix diode mode handling (bug #142).
+ * Add the missing HACKING file to the tarball.
+ * README.devices: Updates/notes for newly added devices.
+
+0.2.1 (2013-08-07)
+------------------
+
+Note: This release does NOT change the libsigrok API. While new config keys,
+      config info types, and error codes have been added (additional enum
+      entries / numbers), no existing interfaces were added/changed/removed.
+      Frontends should continue to work fine without recompiling or relinking.
+
+ * New supported hardware:
+   - Logic analyzers:
+     - IKALOGIC Scanalogic-2
+     - IKALOGIC ScanaPLUS
+   - Sound level meters:
+     - CEM DT-8852
+     - Kecheng KC-330B
+   - Multimeters:
+     - UNI-T UT60A
+     - UNI-T UT60E
+     - Voltcraft M-3650D
+     - Voltcraft VC-830
+ * Drop the Tecpel DMM-8060 (doesn't have PC connectivity).
+ * New config keys:
+   - SR_CONF_SPL_WEIGHT_FREQ
+   - SR_CONF_SPL_WEIGHT_TIME
+   - SR_CONF_SPL_MEASUREMENT_RANGE
+   - SR_CONF_HOLD_MIN
+   - SR_CONF_HOLD_MAX
+   - SR_CONF_POWER_OFF
+   - SR_CONF_DATA_SOURCE
+ * New config info types:
+   - SR_T_UINT64_RANGE
+ * New error codes:
+   - SR_ERR_TIMEOUT
+ * Always link against libm, the math library (bug #115).
+ * Fix a bug in sr_si_string_u64() at al (bug #73).
+ * output/csv: Fix incorrect probe order.
+ * alsa: Fix a double-free issue (bug #129).
+ * zeroplus-logic-cube: Fix a bug in the driver cleanup code.
+ * ikalogic-scanalogic2: Use GET_REPORT (bug #130).
+ * uni-t-dmm: Fix a bug breaking the UNI-T UT61E (bug #136).
+ * Various internal consistency fixes and code cleanups.
+ * Improved Doxygen documentation.
+ * Fixed various memory leaks.
+
+0.2.0 (2013-05-04)
+------------------
+
+Note: This release DOES change the libsigrok API. That means it is NOT
+      backwards-compatible and frontends will need updates.
+
+ * Support for analog sources (oscilloscopes, DMMs, data loggers) was added.
+ * New supported hardware:
+   - Logic analyzers:
+     - CWAV USBee DX
+     - ZEROPLUS LAP-16128U
+   - Oscilloscopes:
+     - Hantek DSO-2090 (USB scope)
+     - Rigol DS1052D
+     - Rigol DS1052E
+     - Rigol DS1102D
+     - Rigol DS1102E
+   - Multimeters:
+     - Agilent U1231A
+     - Agilent U1232A
+     - Agilent U1233A
+     - Brymen BM857
+     - Digitek DT4000ZC
+     - Fluke 187
+     - Fluke 189
+     - Fluke 287
+     - Fluke 289
+     - Fluke ScopeMeter 199B
+     - MASTECH MAS345
+     - Metex ME-31
+     - Metex M-3640D
+     - PCE PCE-DM32
+     - PeakTech 3410
+     - PeakTech 4370
+     - RadioShack 22-168
+     - RadioShack 22-805
+     - RadioShack 22-812
+     - Tecpel DMM-8060
+     - Tecpel DMM-8061
+     - TekPower TP4000ZC
+     - UNI-T UT61D
+     - UNI-T UT61E
+     - V&A VA18B
+     - Victor 70C
+     - Victor 86C
+     - Voltcraft VC-820
+     - Voltcraft VC-840
+   - Sound level meters:
+     - Colead SL-5868P
+     - Tondaj SL-814
+   - Temperature/humidity/CO loggers:
+     - Lascar EL-USB and EL-USB CO series (various models)
+     - MIC 98581
+     - MIC 98583
+ * The limitation of max. 64 digital probes has been removed in many places.
+ * Added generic DMM protocol parsers usable for various DMMs, over various
+   cables and/or transports (e.g. same protocol over serial or USB/HID):
+   - Cyrustek ES51922 binary protocol.
+   - Fortune Semiconductor FS9721_LP3/FS9721B binary protocol.
+   - Fortune Semiconductor FS9922-DMM3/DMM4 binary protocol.
+   - Metex 14-byte ASCII protocol.
+   - RadioShack 22-812 binary protocol.
+ * zeroplus-logic-cube driver:
+   - Fix acquisition at some specific samplerates. Only report valid ones.
+   - Default to a samplerate of 1MHz.
+   - Fix trigger code.
+   - Add pre-trigger (capture ratio) setting.
+   - Add support for the ZEROPLUS LAP-16128U.
+ * fx2lafw driver:
+   - Add support for the CWAV USBee DX. This requires the latest version of
+     the fx2lafw firmware files.
+   - Add support for wide sampling (i.e. 16 probes instead of just 8).
+   - Fix multi-stage (software) triggers.
+   - Fix various memory leaks, firmware upload timeout bugs, and other issues.
+   - Various performance and memory usage improvements in the driver.
+ * chronovu-la8 driver:
+   - Add support for newer LA8 versions with USB VID/PID 0403:8867.
+ * demo driver:
+   - Various bugfixes when setting time/sample limits.
+ * openbench-logic-sniffer driver:
+   - Don't try to scan all available serial ports for OLS devices. Instead,
+     the serial port to use now has to be specified by the user.
+   - Allow disabling RLE.
+ * udev rules file: Add many new entries for additional devices.
+ * New output formats:
+   - analog: Prints analog values and their unit (e.g. from scopes or DMMs).
+ * New input formats:
+   - vcd: Value Change Dump format
+   - wav: Waveform audio file format (for analog data)
+ * 'binary' input format: Add support for a 'samplerate' option.
+ * API related changes:
+   - There is generated Doxygen API documentation now.
+   - The header that frontends should include is: <libsigrok/libsigrok.h>.
+     There are other headers which are installed, but those are not meant to
+     be included directly by the frontends.
+   - There were numerous API changes, additions and removals, too many to list
+     here. Please check the source code or Doxygen API documentation for the
+     current set of API functions.
+ * Serial port code:
+    - Various improvements and fixes related to multiple parameters such as
+      directions, baudrate, flow control, and others.
+    - Add support for more baudrates (e.g. very low ones such as 600/1200)
+      that are used in some devices.
+    - Add support for setting DTR/RTS.
+ * gnuplot files: Add sample files for CWAV USBee DX (for 8/16 bit sampling).
+ * Documentation updates:
+   - Add a README.devices file which contains various notes for users of
+     libsigrok about device- and/or driver-specific issues.
+   - Update README, HACKING, and other documents.
+   - Updated build dependencies list.
+     - The following libs are needed in more recent versions now:
+       - glib (required): Now must be >= 2.32.0.
+       - libusb-1.0 (optional): Now must be >= 1.0.9.
+     - The following new libs were added as (optional) dependencies:
+       - libasound / alsa-lib (optional): >= 1.0
+       - check (optional, only needed for unit tests): >= 0.9.4
+ * Portability:
+   - Various compile fixes for Windows, FreeBSD/NetBSD/OpenBSD, and Mac OS X.
+   - Simplify/allow/fix cross-compilation of libsigrok.
+   - Various bugfixes for 32bit systems.
+   - Various endianness fixes.
+ * configure:
+    - Add a --disable-all-drivers option. This can be overridden by
+      additional --enable-<drivername> options to selectively enable only some.
+    - Improve autodetection of libraries, and only enable drivers for which
+      all required libraries were found.
+ * Add a test suite for libsigrok with a few unit tests (the list will grow).
+
+0.1.1 (2012-05-30)
+------------------
+
+Note: This release does NOT change the libsigrok API.
+
+ * The 'saleae-logic' driver (which depends on the Saleae firmware), has
+   been replaced with the new 'fx2lafw' driver, which uses an open-source
+   firmware for Cypress FX2 chips which is also named 'fx2lafw'.
+   Details: http://sigrok.org/wiki/Fx2lafw
+   This new driver (+ firmware) currently supports the following devices:
+     - ARMFLY AX-Pro
+     - Braintechnology USB-LPS
+     - EE Electronics ESLA100
+     - EE Electronics ESLA201A
+     - Robomotic MiniLogic
+     - Robomotic BugLogic 3
+     - Saleae Logic
+     - USBee AX
+     - USBee SX
+     - All Cypress FX2 eval boards with stock Cypress VID/PID, including:
+       - Lcsoft Mini Board
+       - Braintechnology USB Interface V2.x
+   Only acquisition with 8 probes is supported so far. Support for 16 probes
+   and support for analog signal acquisition (on devices which have these
+   capabilities) will be added later.
+ * ASIX SIGMA driver:
+   - Add support for the ASIX SIGMA2. This requires the latest version of
+     the SIGMA/SIGMA2 firmware files.
+     Details: http://sigrok.org/wiki/Firmware
+   - Various bugfixes.
+ * ZEROPLUS Logic Cube LAP-C (16032): Fix a segfault.
+ * udev file: Add entries for Robomotic BugLogic 3, Velleman PCSU1000,
+   Ideofy LA-08, ARMFLY AX-Pro, and Braintechnology USB Interface V2.x.
+ * The zlib dependency has been removed (no longer needed).
+ * Fix compiling with "Homebrew" (Mac OS X).
+ * libsigrok now expects firmware files in $prefix/share/sigrok-firmware by
+   default (was $prefix/share/libsigrok/firmware before).
+ * Fix a Makefile.am bug which caused the generated ChangeLog files being
+   accidentally deleted upon 'make distclean'.
+ * ChronoVu LA8 input file format: Improve autodetection of the file format.
+   We now only accept files of the size 8388613 bytes (all LA8 files have
+   exactly this amount of bytes).
+
+0.1.0 (2012-04-17)
+------------------
+
+ * Initial release.
+
diff --git a/README b/README
new file mode 100644
index 0000000..556ab3f
--- /dev/null
+++ b/README
@@ -0,0 +1,112 @@
+-------------------------------------------------------------------------------
+README
+-------------------------------------------------------------------------------
+
+The sigrok project aims at creating a portable, cross-platform,
+Free/Libre/Open-Source signal analysis software suite that supports various
+device types (such as logic analyzers, oscilloscopes, multimeters, and more).
+
+libsigrok is a shared library written in C which provides the basic API
+for talking to hardware and reading/writing the acquired data into various
+input/output file formats.
+
+
+Status
+------
+
+libsigrok is in a usable state and has had official tarball releases.
+
+While the API can change from release to release, this will always be
+properly documented and reflected in the package version number and
+in the shared library / libtool / .so-file version numbers.
+
+However, there are _NO_ guarantees at all for stable APIs in git snapshots!
+Distro packagers should only use released tarballs (no git snapshots).
+
+
+Requirements
+------------
+
+ - git
+ - gcc (>= 4.0)
+ - make
+ - autoconf >= 2.63
+ - automake >= 1.11
+ - libtool
+ - pkg-config >= 0.22
+ - libglib >= 2.32.0
+ - libzip >= 0.10
+ - libserialport >= 0.1.0 (optional, used by some drivers)
+ - librevisa >= 0.0.20130812 (optional, used by some drivers)
+ - libusb-1.0 >= 1.0.16 (optional, used by some drivers)
+ - libftdi >= 0.16 (optional, used by some drivers)
+ - check >= 0.9.4 (optional, only needed to run unit tests)
+
+
+Building and installing
+-----------------------
+
+In order to get the libsigrok source code and build it, run:
+
+ $ git clone git://sigrok.org/libsigrok
+ $ cd libsigrok
+ $ ./autogen.sh
+ $ ./configure
+ $ make
+
+For installing libsigrok:
+
+ $ make install
+
+See INSTALL or the following wiki page for more (OS-specific) instructions:
+
+ http://sigrok.org/wiki/Building
+
+
+Device-specific issues
+----------------------
+
+Please check README.devices for some notes and hints about device- or
+driver-specific issues to be aware of.
+
+
+Firmware
+--------
+
+Some devices supported by libsigrok need a firmware to be uploaded before the
+device can be used. See README.devices for details.
+
+
+Copyright and license
+---------------------
+
+libsigrok is licensed under the terms of the GNU General Public License
+(GPL), version 3 or later.
+
+While some individual source code files are licensed under the GPLv2+, and
+some files are licensed under the GPLv3+, this doesn't change the fact that
+the library as a whole is licensed under the terms of the GPLv3+.
+
+Please see the individual source files for the full list of copyright holders.
+
+
+Mailing lists
+-------------
+
+There are two mailing lists for sigrok/libsigrok:
+
+ https://lists.sourceforge.net/lists/listinfo/sigrok-devel
+ https://lists.sourceforge.net/lists/listinfo/sigrok-commits
+
+
+IRC
+---
+
+You can find the sigrok developers in the #sigrok IRC channel on Freenode.
+
+
+Website
+-------
+
+ http://sigrok.org/wiki/Libsigrok
+
diff --git a/README.devices b/README.devices
new file mode 100644
index 0000000..db651fa
--- /dev/null
+++ b/README.devices
@@ -0,0 +1,364 @@
+-------------------------------------------------------------------------------
+README.devices
+-------------------------------------------------------------------------------
+
+This README contains various notes for users of libsigrok (or frontends
+that are based on libsigrok) about device- and/or driver-specific issues.
+
+
+Firmware
+--------
+
+Some devices supported by libsigrok need a firmware to be uploaded every time
+the device is connected to the PC (usually via USB), before it can be used.
+
+The default location where libsigrok expects the firmware files is:
+
+  $prefix/share/sigrok-firmware
+
+($prefix is usually /usr/local or /usr, depending on your ./configure options)
+
+For further information see the section below and also:
+
+  http://sigrok.org/wiki/Firmware
+
+
+Per-driver firmware requirements
+--------------------------------
+
+The following drivers/devices require a firmware upload upon connection:
+
+ - asix-sigma: The ASIX SIGMA and SIGMA2 require various firmware files,
+   depending on the settings used. These files are available from our
+   'sigrok-firmware' repository/project under a license which allows us
+   to redistribute them.
+
+ - fx2lafw: Logic analyzers based on the Cypress FX2(LP) chip need the
+   firmware files from the 'sigrok-firmware-fx2lafw' repository/project.
+   The firmware is written from scratch and licensed under the GNU GPLv2+.
+
+ - hantek-dso: The Hantek DSO-2090 (and other supported models of the same
+   series of Hantek PC oscilloscopes) need firmware files.
+   These can be extracted from the vendor's Windows drivers using a tool
+   from our 'sigrok-util' repository/project.
+
+ - saleae-logic16: The Saleae Logic16 needs a firmware file for the
+   Cypress FX2 chip in the device, as well as two FPGA bitstream files.
+   These can be extracted from the vendor's Linux application using a tool
+   from our 'sigrok-util' repository/project.
+
+ - sysclk-lwla: The Sysclk LWLA1034 requires various bitstream files.
+   These files are available from our 'sigrok-firmware' repository/project
+   under a license which allows us to redistribute them.
+
+The following drivers/devices do not need any firmware upload:
+
+ - agilent-dmm
+ - appa-55ii
+ - atten-pps3xxx
+ - brymen-bm86x
+ - brymen-dmm
+ - cem-dt-885x
+ - center-3xx (including all subdrivers)
+ - chronovu-la
+ - colead-slm
+ - conrad-digi-35-cpu
+ - demo
+ - fluke-dmm
+ - gmc-mh-1x-2x (including all subdrivers)
+ - hameg-hmo
+ - ikalogic-scanalogic2
+ - ikalogic-scanaplus
+ - kecheng-kc-330b
+ - lascar-el-usb
+ - link-mso19
+ - mic-985xx (including all subdrivers)
+ - norma-dmm
+ - openbench-logic-sniffer
+ - rigol-ds
+ - serial-dmm (including all subdrivers)
+ - teleinfo
+ - tondaj-sl-814
+ - uni-t-dmm (including all subdrivers)
+ - uni-t-ut32x
+ - victor-dmm
+ - zeroplus-logic-cube
+
+
+Specifying serial ports
+-----------------------
+
+Many devices supported by libsigrok use serial port based cables (real RS232
+or USB-to-serial ones) to connect to a PC.
+
+For all these devices, you need to specify the serial port they are connected
+to (e.g. using the 'conn' option in sigrok-cli). It is not possible to scan
+for such devices without specifying a serial port.
+
+Example:
+
+ $ sigrok-cli --driver <somedriver>:conn=/dev/ttyUSB0 ...
+
+The following drivers/devices require a serial port specification:
+
+ - agilent-dmm
+ - appa-55ii
+ - atten-pps3xxx
+ - brymen-dmm
+ - cem-dt-885x
+ - center-3xx (including all subdrivers)
+ - colead-slm
+ - conrad-digi-35-cpu
+ - fluke-dmm
+ - gmc-mh-1x-2x (including all subdrivers)
+ - hameg-hmo
+ - link-mso19
+ - mic-985xx (including all subdrivers)
+ - norma-dmm
+ - openbench-logic-sniffer
+ - rigol-ds (for RS232; not required for USBTMC or TCP)
+ - serial-dmm (including all subdrivers)
+ - teleinfo
+ - tondaj-sl-814
+
+The following drivers/devices do not require a serial port specification:
+
+ - asix-sigma
+ - brymen-bm86x
+ - chronovu-la
+ - demo
+ - fx2lafw
+ - hantek-dso
+ - ikalogic-scanalogic2
+ - ikalogic-scanaplus
+ - kecheng-kc-330b
+ - lascar-el-usb
+ - rigol-ds (USBTMC or TCP)
+ - saleae-logic16
+ - sysclk-lwla
+ - uni-t-dmm (including all subdrivers)
+ - uni-t-ut32x
+ - victor-dmm
+ - zeroplus-logic-cube
+
+
+Specifiying serial port parameters
+----------------------------------
+
+Every serial device's driver has default serial port parameters like baud
+rate, number of data bits, stop bits and handshake status. If a device requires
+different parameters, pass them as option "serialcomm" with the driver name.
+See libsigrok docs for the function serial_set_paramstr() for complete specs.
+
+Example:
+
+ $ sigrok-cli --driver <somedriver>:conn=<someconn>:serialcomm=9600/7n1/dtr=1
+
+
+Permissions of serial port based devices
+----------------------------------------
+
+When using devices supported by libsigrok that use serial port based cables
+(real RS232 or USB-to-serial ones) to connect to a PC, you need to ensure
+that the user running the libsigrok frontend has (read/write) permissions to
+access the serial port device (e.g. /dev/ttyS0, /dev/ttyUSB0, and so on).
+
+You can use 'chmod' to apply permissions as you see fit, and/or 'chown' to
+change the owner of the serial port device to a certain user or group.
+
+For USB-to-serial based devices, we recommended using our udev rules file
+(see below for details).
+
+
+Permissions for USB devices (udev rules file)
+---------------------------------------------
+
+When using USB-based devices supported by libsigrok, the user running the
+libsigrok frontend (e.g. sigrok-cli) has to have (read/write) permissions
+for the respective USB device.
+
+On Linux, this is accomplished using either 'chmod' (not recommended) or
+using the udev rules file shipped with libsigrok (recommended).
+
+The file is available in contrib/z60_libsigrok.rules. It contains entries
+for all libsigrok-supported (USB-based) devices and changes their group
+to 'plugdev' and the permissions to '664'.
+
+When using a libsigrok package from your favorite Linux distribution, the
+packager will have already taken care of properly installing the udev file
+in the correct (distro-specific) place, and you don't have to do anything.
+The packager might also have adapted 'plugdev' and '664' as needed.
+
+If you're building from source, you need to copy the file to the place
+where your distro expects such files. This is beyond the scope of this README,
+but generally the location could be e.g. /etc/udev/rules.d, or maybe
+/lib/udev/rules.d, or something else. Afterwards you might have to restart
+udev, e.g. via '/etc/init.d/udev restart' or similar, and you'll have to
+re-attach your device via USB.
+
+Please consult the udev docs of your distro for details.
+
+
+Cypress FX2 based devices
+-------------------------
+
+Devices using the Cypress FX2(LP) chip without any specific USB VID/PID will
+be enumerated with VID/PID 04b4:8613 (the default for "unconfigured FX2").
+These are usually "FX2 eval boards" (that can also be used as LAs, though).
+
+On Linux, the 'usbtest' driver will usually grab such devices, and they will
+thus not be usable by libsigrok (and frontends).
+
+You can fix this by running 'rmmod usbtest' as root before using the device.
+
+
+UNI-T DMM (and rebranded models) cables
+---------------------------------------
+
+UNI-T multimeters (and rebranded devices, e.g. some Voltcraft models) can
+ship with different PC connectivity cables:
+
+ - UT-D04 (USB/HID cable with Hoitek HE2325U chip, USB VID/PID 04fa:2490)
+ - UT-D04 (USB/HID cable with WCH CH9325 chip, USB VID/PID 1a86:e008)
+ - UT-D02 (RS232 cable)
+
+The above cables are all physically compatible (same IR connector shape)
+with all/most currently known UNI-T multimeters. For example, you can
+use either of the UT-D04 USB/HID cables or the UT-D02 RS232 cable with
+the UNI-T UT61D multimeter.
+
+When using the UT-D02 RS232 cable with any of the supported UNI-T DMMs,
+you have to use the respective driver with a '-ser' drivername suffix
+(internally all of these models are handled by the 'serial-dmm' driver).
+
+You also need to specify the serial port via the 'conn' option, e.g.
+/dev/ttyUSB0 (attached via a USB-to-serial cable) or /dev/ttyS0 (actual
+RS232 port) on Linux (see above).
+
+Finally, the user running the frontend (e.g. sigrok-cli) also needs
+permissions to access the respective serial port (see above).
+
+Examples (sigrok-cli):
+
+ $ sigrok-cli --driver uni-t-ut61e-ser:conn=/dev/ttyUSB0 ...
+ $ sigrok-cli --driver voltcraft-vc820-ser:conn=/dev/ttyS0 ...
+
+When using any of the UT-D04 USB/HID cables you have to use the respective
+driver _without_ the '-ser' drivername suffix (internally all of these models
+are handled by the 'uni-t-dmm' driver).
+
+You also need to specify the USB vendor/device IDs of the cable.
+Autodetection is not possible here, since various other products use the
+USB VID/PID of those cables too, and there is no way to distinguish them.
+
+Since the UT-D04 cables are USB based (but don't use a USB-to-serial chip)
+there is no need to specify a serial port via 'conn', of course.
+However, the user running the frontend does also need to have permissions
+to access the respective USB device (see above).
+
+Examples (sigrok-cli):
+
+ $ sigrok-cli --driver uni-t-ut61e:conn=1a86.e008 ...
+ $ sigrok-cli --driver voltcraft-vc820:conn=04fa.2490 ...
+
+
+UNI-T UT-D04 cable issue on Linux
+---------------------------------
+
+The UNI-T UT-D04 cable with Hoitek HE2325U (or WCH CH9325) chip seems to have
+a very specific problem on Linux. Apparently it requires to be put into
+suspend (and woken up again) before it is usable. This seems to be a
+Linux-only issue, Windows is not affected by this since apparently the
+Windows kernel does this for every USB device, always.
+
+Thus, if you want to use any of the UNI-T DMMs with this specific cable,
+you'll have to run the following script (as root) once, every time you attach
+the cable via USB. The script was written by Ralf Burger.
+
+See also: http://erste.de/UT61/index.html
+
+  #!/bin/bash
+  for dat in /sys/bus/usb/devices/*; do
+    if test -e $dat/manufacturer; then
+      grep "WCH.CN" $dat/manufacturer > /dev/null && echo auto > ${dat}/power/level && echo 0 > ${dat}/power/autosuspend
+    fi
+  done
+
+
+Enabling multimeter / data logger measurement output
+----------------------------------------------------
+
+Some multimeters or data loggers will not start outputting measurement data
+unless a certain action has been performed by the user beforehand. This is
+usually mentioned in the vendor manual of the respective device, but here's
+a short list for convenience:
+
+ - BBC Goertz Metrawatt M2110: Briefly press the "Start/Reset" button on the
+   interface panel on top.
+ - Digitek DT4000ZC: Briefly press the "RS232" button.
+ - Gossen Metrawatt Metrahit 1x/2x devices, driver gmc-mh-1x-2x-rs232:
+   - Power on the device with the "DATA" button pressed.
+   - Metrahit 2x devices must be configured for the respective interface type.
+ - Gossen Metrawatt Metrahit 2x devices, driver gmc-mh-2x-bd232:
+   - 'BD232' interface:
+      The multimeter must be configured for the respective interface type.
+   - 'SI232-II' interface ("PC Mode"):
+      The multimeter must be configured for interface type 'BD232' (all),
+      'SI232 online' (28-29S) or 'SI232 store' (22-26x). The interface must
+      be configured to the same baud rate as the host (default 9600).
+      Multimeter and interface must be configured to the same address.
+ - Norma DM950: If the interface doesn't work (e.g. USB-RS232 converter), power
+   on the device with "FUNC" pressed (to power the interface from the DMM).
+ - PCE PCE-DM32: Briefly press the "RS232" button.
+ - RadioShack 22-812: Press and hold "SELECT" and "RANGE" together.
+ - TekPower TP4000ZC: Briefly press the "RS232" button.
+ - Tenma 72-7750: Briefly press the "RS232C" button.
+ - UNI-T UT60G: Briefly press the "RS232C" button.
+ - UNI-T UT61B/C/D: Press the "REL/RS232/USB" button for roughly 1 second.
+ - UNI-T UT325: Briefly press the "SEND" button (as per manual). However, it
+   appears that in practice you don't have to press the button (at least on
+   some versions of the device), simply connect the device via USB.
+ - V&A VA18B/VA40B: Keep the "Hz/DUTY" key pressed while powering on the DMM.
+ - Victor 70C/86C: Press the "REL/RS232" button for roughly 1 second.
+ - Voltcraft VC-830: Press the "REL/PC" button for roughly 2 seconds.
+
+
+ChronoVu LA8/LA16 USB VID/PIDs
+------------------------------
+
+The ChronoVu LA8/LA16 logic analyzer is available in two revisions. Previously,
+the device shipped with a USB VID/PID of 0403:6001, which is the standard ID
+for FTDI FT232 USB chips.
+
+Since this made it hard to distinguish the LA8/LA16 from any other device
+with this FTDI chip connected to the PC, the vendor later shipped the
+device with a USB VID/PID of 0403:8867.
+
+The 'chronovu-la' driver in libsigrok supports both VID/PID pairs and
+automatically finds devices with either VID/PID pair.
+
+
+OLS
+---
+
+The Dangerous Prototypes Openbench Logic Sniffer (OLS) logic analyzer
+driver in libsigrok assumes a somewhat recent firmware has been flashed onto
+the OLS (it doesn't need a firmware upload every time it's attached via USB,
+since the firmware is stored in the device permanently).
+
+The most recent firmware version that is tested is 3.07.
+
+If you use any older firmware and your OLS is not found or is not working
+properly, please upgrade to at least this firmware version. Check the
+Dangerous Prototypes wiki for firmware upgrade instructions:
+
+ http://dangerousprototypes.com/docs/Logic_Sniffer_upgrade_procedure
+
+Also, you need to specify a serial port for the OLS in the frontends, e.g.
+using the 'conn' option in sigrok-cli, and you also need to have the
+permissions to access the serial port (see above).
+
+Example:
+
+ $ sigrok-cli --driver ols:conn=/dev/ttyACM0 ...
+
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644
index 0000000..9a85aac
--- /dev/null
+++ b/aclocal.m4
@@ -0,0 +1,1587 @@
+# generated automatically by aclocal 1.14.1 -*- Autoconf -*-
+
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
+m4_ifndef([AC_AUTOCONF_VERSION],
+  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],,
+[m4_warning([this file was generated for autoconf 2.69.
+You have another version of autoconf.  It may work, but is not guaranteed to.
+If you have problems, you may need to regenerate the build system entirely.
+To do so, use the procedure documented by the package, typically 'autoreconf'.])])
+
+# Configure paths for GLIB
+# Owen Taylor     1997-2001
+
+dnl AM_PATH_GLIB_2_0([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, MODULES]]]])
+dnl Test for GLIB, and define GLIB_CFLAGS and GLIB_LIBS, if gmodule, gobject,
+dnl gthread, or gio is specified in MODULES, pass to pkg-config
+dnl
+AC_DEFUN([AM_PATH_GLIB_2_0],
+[dnl 
+dnl Get the cflags and libraries from pkg-config
+dnl
+AC_ARG_ENABLE(glibtest, [  --disable-glibtest      do not try to compile and run a test GLIB program],
+		    , enable_glibtest=yes)
+
+  pkg_config_args=glib-2.0
+  for module in . $4
+  do
+      case "$module" in
+         gmodule) 
+             pkg_config_args="$pkg_config_args gmodule-2.0"
+         ;;
+         gmodule-no-export) 
+             pkg_config_args="$pkg_config_args gmodule-no-export-2.0"
+         ;;
+         gobject) 
+             pkg_config_args="$pkg_config_args gobject-2.0"
+         ;;
+         gthread) 
+             pkg_config_args="$pkg_config_args gthread-2.0"
+         ;;
+         gio*) 
+             pkg_config_args="$pkg_config_args $module-2.0"
+         ;;
+      esac
+  done
+
+  PKG_PROG_PKG_CONFIG([0.16])
+
+  no_glib=""
+
+  if test "x$PKG_CONFIG" = x ; then
+    no_glib=yes
+    PKG_CONFIG=no
+  fi
+
+  min_glib_version=ifelse([$1], ,2.0.0,$1)
+  AC_MSG_CHECKING(for GLIB - version >= $min_glib_version)
+
+  if test x$PKG_CONFIG != xno ; then
+    ## don't try to run the test against uninstalled libtool libs
+    if $PKG_CONFIG --uninstalled $pkg_config_args; then
+	  echo "Will use uninstalled version of GLib found in PKG_CONFIG_PATH"
+	  enable_glibtest=no
+    fi
+
+    if $PKG_CONFIG --atleast-version $min_glib_version $pkg_config_args; then
+	  :
+    else
+	  no_glib=yes
+    fi
+  fi
+
+  if test x"$no_glib" = x ; then
+    GLIB_GENMARSHAL=`$PKG_CONFIG --variable=glib_genmarshal glib-2.0`
+    GOBJECT_QUERY=`$PKG_CONFIG --variable=gobject_query glib-2.0`
+    GLIB_MKENUMS=`$PKG_CONFIG --variable=glib_mkenums glib-2.0`
+    GLIB_COMPILE_RESOURCES=`$PKG_CONFIG --variable=glib_compile_resources gio-2.0`
+
+    GLIB_CFLAGS=`$PKG_CONFIG --cflags $pkg_config_args`
+    GLIB_LIBS=`$PKG_CONFIG --libs $pkg_config_args`
+    glib_config_major_version=`$PKG_CONFIG --modversion glib-2.0 | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+    glib_config_minor_version=`$PKG_CONFIG --modversion glib-2.0 | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+    glib_config_micro_version=`$PKG_CONFIG --modversion glib-2.0 | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+    if test "x$enable_glibtest" = "xyes" ; then
+      ac_save_CFLAGS="$CFLAGS"
+      ac_save_LIBS="$LIBS"
+      CFLAGS="$CFLAGS $GLIB_CFLAGS"
+      LIBS="$GLIB_LIBS $LIBS"
+dnl
+dnl Now check if the installed GLIB is sufficiently new. (Also sanity
+dnl checks the results of pkg-config to some extent)
+dnl
+      rm -f conf.glibtest
+      AC_TRY_RUN([
+#include <glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int 
+main ()
+{
+  unsigned int major, minor, micro;
+
+  fclose (fopen ("conf.glibtest", "w"));
+
+  if (sscanf("$min_glib_version", "%u.%u.%u", &major, &minor, &micro) != 3) {
+     printf("%s, bad version string\n", "$min_glib_version");
+     exit(1);
+   }
+
+  if ((glib_major_version != $glib_config_major_version) ||
+      (glib_minor_version != $glib_config_minor_version) ||
+      (glib_micro_version != $glib_config_micro_version))
+    {
+      printf("\n*** 'pkg-config --modversion glib-2.0' returned %d.%d.%d, but GLIB (%d.%d.%d)\n", 
+             $glib_config_major_version, $glib_config_minor_version, $glib_config_micro_version,
+             glib_major_version, glib_minor_version, glib_micro_version);
+      printf ("*** was found! If pkg-config was correct, then it is best\n");
+      printf ("*** to remove the old version of GLib. You may also be able to fix the error\n");
+      printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n");
+      printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n");
+      printf("*** required on your system.\n");
+      printf("*** If pkg-config was wrong, set the environment variable PKG_CONFIG_PATH\n");
+      printf("*** to point to the correct configuration files\n");
+    } 
+  else if ((glib_major_version != GLIB_MAJOR_VERSION) ||
+	   (glib_minor_version != GLIB_MINOR_VERSION) ||
+           (glib_micro_version != GLIB_MICRO_VERSION))
+    {
+      printf("*** GLIB header files (version %d.%d.%d) do not match\n",
+	     GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
+      printf("*** library (version %d.%d.%d)\n",
+	     glib_major_version, glib_minor_version, glib_micro_version);
+    }
+  else
+    {
+      if ((glib_major_version > major) ||
+        ((glib_major_version == major) && (glib_minor_version > minor)) ||
+        ((glib_major_version == major) && (glib_minor_version == minor) && (glib_micro_version >= micro)))
+      {
+        return 0;
+       }
+     else
+      {
+        printf("\n*** An old version of GLIB (%u.%u.%u) was found.\n",
+               glib_major_version, glib_minor_version, glib_micro_version);
+        printf("*** You need a version of GLIB newer than %u.%u.%u. The latest version of\n",
+	       major, minor, micro);
+        printf("*** GLIB is always available from ftp://ftp.gtk.org.\n");
+        printf("***\n");
+        printf("*** If you have already installed a sufficiently new version, this error\n");
+        printf("*** probably means that the wrong copy of the pkg-config shell script is\n");
+        printf("*** being found. The easiest way to fix this is to remove the old version\n");
+        printf("*** of GLIB, but you can also set the PKG_CONFIG environment to point to the\n");
+        printf("*** correct copy of pkg-config. (In this case, you will have to\n");
+        printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n");
+        printf("*** so that the correct libraries are found at run-time))\n");
+      }
+    }
+  return 1;
+}
+],, no_glib=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+     fi
+  fi
+  if test "x$no_glib" = x ; then
+     AC_MSG_RESULT(yes (version $glib_config_major_version.$glib_config_minor_version.$glib_config_micro_version))
+     ifelse([$2], , :, [$2])     
+  else
+     AC_MSG_RESULT(no)
+     if test "$PKG_CONFIG" = "no" ; then
+       echo "*** A new enough version of pkg-config was not found."
+       echo "*** See http://www.freedesktop.org/software/pkgconfig/"
+     else
+       if test -f conf.glibtest ; then
+        :
+       else
+          echo "*** Could not run GLIB test program, checking why..."
+          ac_save_CFLAGS="$CFLAGS"
+          ac_save_LIBS="$LIBS"
+          CFLAGS="$CFLAGS $GLIB_CFLAGS"
+          LIBS="$LIBS $GLIB_LIBS"
+          AC_TRY_LINK([
+#include <glib.h>
+#include <stdio.h>
+],      [ return ((glib_major_version) || (glib_minor_version) || (glib_micro_version)); ],
+        [ echo "*** The test program compiled, but did not run. This usually means"
+          echo "*** that the run-time linker is not finding GLIB or finding the wrong"
+          echo "*** version of GLIB. If it is not finding GLIB, you'll need to set your"
+          echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+          echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+          echo "*** is required on your system"
+	  echo "***"
+          echo "*** If you have an old version installed, it is best to remove it, although"
+          echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" ],
+        [ echo "*** The test program failed to compile or link. See the file config.log for the"
+          echo "*** exact error that occured. This usually means GLIB is incorrectly installed."])
+          CFLAGS="$ac_save_CFLAGS"
+          LIBS="$ac_save_LIBS"
+       fi
+     fi
+     GLIB_CFLAGS=""
+     GLIB_LIBS=""
+     GLIB_GENMARSHAL=""
+     GOBJECT_QUERY=""
+     GLIB_MKENUMS=""
+     GLIB_COMPILE_RESOURCES=""
+     ifelse([$3], , :, [$3])
+  fi
+  AC_SUBST(GLIB_CFLAGS)
+  AC_SUBST(GLIB_LIBS)
+  AC_SUBST(GLIB_GENMARSHAL)
+  AC_SUBST(GOBJECT_QUERY)
+  AC_SUBST(GLIB_MKENUMS)
+  AC_SUBST(GLIB_COMPILE_RESOURCES)
+  rm -f conf.glibtest
+])
+
+# pkg.m4 - Macros to locate and utilise pkg-config.            -*- Autoconf -*-
+# serial 1 (pkg-config-0.24)
+# 
+# Copyright © 2004 Scott James Remnant <scott at netsplit.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# PKG_PROG_PKG_CONFIG([MIN-VERSION])
+# ----------------------------------
+AC_DEFUN([PKG_PROG_PKG_CONFIG],
+[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
+m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
+m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$])
+AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
+AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
+AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+	AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
+fi
+if test -n "$PKG_CONFIG"; then
+	_pkg_min_version=m4_default([$1], [0.9.0])
+	AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
+	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+		AC_MSG_RESULT([yes])
+	else
+		AC_MSG_RESULT([no])
+		PKG_CONFIG=""
+	fi
+fi[]dnl
+])# PKG_PROG_PKG_CONFIG
+
+# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+#
+# Check to see whether a particular set of modules exists.  Similar
+# to PKG_CHECK_MODULES(), but does not set variables or print errors.
+#
+# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+# only at the first occurence in configure.ac, so if the first place
+# it's called might be skipped (such as if it is within an "if", you
+# have to call PKG_CHECK_EXISTS manually
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_EXISTS],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+if test -n "$PKG_CONFIG" && \
+    AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
+  m4_default([$2], [:])
+m4_ifvaln([$3], [else
+  $3])dnl
+fi])
+
+# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
+# ---------------------------------------------
+m4_define([_PKG_CONFIG],
+[if test -n "$$1"; then
+    pkg_cv_[]$1="$$1"
+ elif test -n "$PKG_CONFIG"; then
+    PKG_CHECK_EXISTS([$3],
+                     [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes ],
+		     [pkg_failed=yes])
+ else
+    pkg_failed=untried
+fi[]dnl
+])# _PKG_CONFIG
+
+# _PKG_SHORT_ERRORS_SUPPORTED
+# -----------------------------
+AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi[]dnl
+])# _PKG_SHORT_ERRORS_SUPPORTED
+
+
+# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+# [ACTION-IF-NOT-FOUND])
+#
+#
+# Note that if there is a possibility the first call to
+# PKG_CHECK_MODULES might not happen, you should be sure to include an
+# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
+#
+#
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_MODULES],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
+AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
+
+pkg_failed=no
+AC_MSG_CHECKING([for $1])
+
+_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
+_PKG_CONFIG([$1][_LIBS], [libs], [$2])
+
+m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
+and $1[]_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.])
+
+if test $pkg_failed = yes; then
+   	AC_MSG_RESULT([no])
+        _PKG_SHORT_ERRORS_SUPPORTED
+        if test $_pkg_short_errors_supported = yes; then
+	        $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
+        else 
+	        $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
+
+	m4_default([$4], [AC_MSG_ERROR(
+[Package requirements ($2) were not met:
+
+$$1_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+_PKG_TEXT])[]dnl
+        ])
+elif test $pkg_failed = untried; then
+     	AC_MSG_RESULT([no])
+	m4_default([$4], [AC_MSG_FAILURE(
+[The pkg-config script could not be found or is too old.  Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+_PKG_TEXT
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl
+        ])
+else
+	$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
+	$1[]_LIBS=$pkg_cv_[]$1[]_LIBS
+        AC_MSG_RESULT([yes])
+	$3
+fi[]dnl
+])# PKG_CHECK_MODULES
+
+# Copyright (C) 2002-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+# (This private macro should not be called outside this file.)
+AC_DEFUN([AM_AUTOMAKE_VERSION],
+[am__api_version='1.14'
+dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+dnl require some minimum version.  Point them to the right macro.
+m4_if([$1], [1.14.1], [],
+      [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
+])
+
+# _AM_AUTOCONF_VERSION(VERSION)
+# -----------------------------
+# aclocal traces this macro to find the Autoconf version.
+# This is a private macro too.  Using m4_define simplifies
+# the logic in aclocal, which can simply ignore this definition.
+m4_define([_AM_AUTOCONF_VERSION], [])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
+# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+[AM_AUTOMAKE_VERSION([1.14.1])dnl
+m4_ifndef([AC_AUTOCONF_VERSION],
+  [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
+
+# Copyright (C) 2011-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_AR([ACT-IF-FAIL])
+# -------------------------
+# Try to determine the archiver interface, and trigger the ar-lib wrapper
+# if it is needed.  If the detection of archiver interface fails, run
+# ACT-IF-FAIL (default is to abort configure with a proper error message).
+AC_DEFUN([AM_PROG_AR],
+[AC_BEFORE([$0], [LT_INIT])dnl
+AC_BEFORE([$0], [AC_PROG_LIBTOOL])dnl
+AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([ar-lib])dnl
+AC_CHECK_TOOLS([AR], [ar lib "link -lib"], [false])
+: ${AR=ar}
+
+AC_CACHE_CHECK([the archiver ($AR) interface], [am_cv_ar_interface],
+  [AC_LANG_PUSH([C])
+   am_cv_ar_interface=ar
+   AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int some_variable = 0;]])],
+     [am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&AS_MESSAGE_LOG_FD'
+      AC_TRY_EVAL([am_ar_try])
+      if test "$ac_status" -eq 0; then
+        am_cv_ar_interface=ar
+      else
+        am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&AS_MESSAGE_LOG_FD'
+        AC_TRY_EVAL([am_ar_try])
+        if test "$ac_status" -eq 0; then
+          am_cv_ar_interface=lib
+        else
+          am_cv_ar_interface=unknown
+        fi
+      fi
+      rm -f conftest.lib libconftest.a
+     ])
+   AC_LANG_POP([C])])
+
+case $am_cv_ar_interface in
+ar)
+  ;;
+lib)
+  # Microsoft lib, so override with the ar-lib wrapper script.
+  # FIXME: It is wrong to rewrite AR.
+  # But if we don't then we get into trouble of one sort or another.
+  # A longer-term fix would be to have automake use am__AR in this case,
+  # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something
+  # similar.
+  AR="$am_aux_dir/ar-lib $AR"
+  ;;
+unknown)
+  m4_default([$1],
+             [AC_MSG_ERROR([could not determine $AR interface])])
+  ;;
+esac
+AC_SUBST([AR])dnl
+])
+
+# AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to '$srcdir/foo'.  In other projects, it is set to
+# '$srcdir', '$srcdir/..', or '$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory.  The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run.  This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+#    fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+#    fails if $ac_aux_dir is absolute,
+#    fails when called from a subdirectory in a VPATH build with
+#          a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir.  In an in-source build this is usually
+# harmless because $srcdir is '.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir.  That would be:
+#   am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+#   MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH.  The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[dnl Rely on autoconf to set up CDPATH properly.
+AC_PREREQ([2.50])dnl
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+])
+
+# AM_CONDITIONAL                                            -*- Autoconf -*-
+
+# Copyright (C) 1997-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ([2.52])dnl
+ m4_if([$1], [TRUE],  [AC_FATAL([$0: invalid condition: $1])],
+       [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])dnl
+AC_SUBST([$1_FALSE])dnl
+_AM_SUBST_NOTMAKE([$1_TRUE])dnl
+_AM_SUBST_NOTMAKE([$1_FALSE])dnl
+m4_define([_AM_COND_VALUE_$1], [$2])dnl
+if $2; then
+  $1_TRUE=
+  $1_FALSE='#'
+else
+  $1_TRUE='#'
+  $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+  AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+
+# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery.  Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+m4_if([$1], [CC],   [depcc="$CC"   am_compiler_list=],
+      [$1], [CXX],  [depcc="$CXX"  am_compiler_list=],
+      [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+      [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'],
+      [$1], [UPC],  [depcc="$UPC"  am_compiler_list=],
+      [$1], [GCJ],  [depcc="$GCJ"  am_compiler_list='gcc3 gcc'],
+                    [depcc="$$1"   am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+               [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named 'D' -- because '-MD' means "put the output
+  # in D".
+  rm -rf conftest.dir
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_$1_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+  fi
+  am__universal=false
+  m4_case([$1], [CC],
+    [case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac],
+    [CXX],
+    [case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac])
+
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+      # Solaris 10 /bin/sh.
+      echo '/* dummy */' > sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    # We check with '-c' and '-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle '-M -o', and we need to detect this.  Also, some Intel
+    # versions had trouble with output in subdirs.
+    am__obj=sub/conftest.${OBJEXT-o}
+    am__minus_obj="-o $am__obj"
+    case $depmode in
+    gcc)
+      # This depmode causes a compiler race in universal mode.
+      test "$am__universal" = false || continue
+      ;;
+    nosideeffect)
+      # After this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested.
+      if test "x$enable_dependency_tracking" = xyes; then
+	continue
+      else
+	break
+      fi
+      ;;
+    msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+      # This compiler won't grok '-c -o', but also, the minuso test has
+      # not run yet.  These depmodes are late enough in the game, and
+      # so weak that their functioning should not be impacted.
+      am__obj=conftest.${OBJEXT-o}
+      am__minus_obj=
+      ;;
+    none) break ;;
+    esac
+    if depmode=$depmode \
+       source=sub/conftest.c object=$am__obj \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_$1_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES.
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE([dependency-tracking], [dnl
+AS_HELP_STRING(
+  [--enable-dependency-tracking],
+  [do not reject slow dependency extractors])
+AS_HELP_STRING(
+  [--disable-dependency-tracking],
+  [speeds up one-time build])])
+if test "x$enable_dependency_tracking" != xno; then
+  am_depcomp="$ac_aux_dir/depcomp"
+  AMDEPBACKSLASH='\'
+  am__nodep='_no'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
+AC_SUBST([am__nodep])dnl
+_AM_SUBST_NOTMAKE([am__nodep])dnl
+])
+
+# Generate code to set up dependency tracking.              -*- Autoconf -*-
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[{
+  # Older Autoconf quotes --file arguments for eval, but not when files
+  # are listed without --file.  Let's play safe and only enable the eval
+  # if we detect the quoting.
+  case $CONFIG_FILES in
+  *\'*) eval set x "$CONFIG_FILES" ;;
+  *)   set x $CONFIG_FILES ;;
+  esac
+  shift
+  for mf
+  do
+    # Strip MF so we end up with the name of the file.
+    mf=`echo "$mf" | sed -e 's/:.*$//'`
+    # Check whether this is an Automake generated Makefile or not.
+    # We used to match only the files named 'Makefile.in', but
+    # some people rename them; so instead we look at the file content.
+    # Grep'ing the first line is not enough: some people post-process
+    # each Makefile.in and add a new line on top of each file to say so.
+    # Grep'ing the whole file is not good either: AIX grep has a line
+    # limit of 2048, but all sed's we know have understand at least 4000.
+    if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+      dirpart=`AS_DIRNAME("$mf")`
+    else
+      continue
+    fi
+    # Extract the definition of DEPDIR, am__include, and am__quote
+    # from the Makefile without running 'make'.
+    DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+    test -z "$DEPDIR" && continue
+    am__include=`sed -n 's/^am__include = //p' < "$mf"`
+    test -z "$am__include" && continue
+    am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+    # Find all dependency output files, they are included files with
+    # $(DEPDIR) in their names.  We invoke sed twice because it is the
+    # simplest approach to changing $(DEPDIR) to its actual value in the
+    # expansion.
+    for file in `sed -n "
+      s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+	 sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
+      # Make sure the directory exists.
+      test -f "$dirpart/$file" && continue
+      fdir=`AS_DIRNAME(["$file"])`
+      AS_MKDIR_P([$dirpart/$fdir])
+      # echo "creating $dirpart/$file"
+      echo '# dummy' > "$dirpart/$file"
+    done
+  done
+}
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled.  FIXME.  This creates each '.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+     [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+     [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Do all the work for Automake.                             -*- Autoconf -*-
+
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This macro actually does too much.  Some checks are only needed if
+# your package does certain things.  But this isn't really a big deal.
+
+dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O.
+m4_define([AC_PROG_CC],
+m4_defn([AC_PROG_CC])
+[_AM_PROG_CC_C_O
+])
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out.  PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition.  After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.65])dnl
+dnl Autoconf wants to disallow AM_ names.  We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+  # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+  # is not polluted with repeated "-I."
+  AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
+  # test to see if srcdir already configured
+  if test -f $srcdir/config.status; then
+    AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+  fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+  if (cygpath --version) >/dev/null 2>/dev/null; then
+    CYGPATH_W='cygpath -w'
+  else
+    CYGPATH_W=echo
+  fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[AC_DIAGNOSE([obsolete],
+             [$0: two- and three-arguments forms are deprecated.])
+m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
+m4_if(
+  m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]),
+  [ok:ok],,
+  [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package])
+ AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}])
+AM_MISSING_PROG([AUTOCONF], [autoconf])
+AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}])
+AM_MISSING_PROG([AUTOHEADER], [autoheader])
+AM_MISSING_PROG([MAKEINFO], [makeinfo])
+AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+# For better backward compatibility.  To be removed once Automake 1.9.x
+# dies out for good.  For more background, see:
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
+AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
+# We need awk for the "check" target.  The system "awk" is bad on
+# some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+	      [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+			     [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+		  [_AM_DEPENDENCIES([CC])],
+		  [m4_define([AC_PROG_CC],
+			     m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+		  [_AM_DEPENDENCIES([CXX])],
+		  [m4_define([AC_PROG_CXX],
+			     m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+		  [_AM_DEPENDENCIES([OBJC])],
+		  [m4_define([AC_PROG_OBJC],
+			     m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJCXX],
+		  [_AM_DEPENDENCIES([OBJCXX])],
+		  [m4_define([AC_PROG_OBJCXX],
+			     m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl
+])
+AC_REQUIRE([AM_SILENT_RULES])dnl
+dnl The testsuite driver may need to know about EXEEXT, so add the
+dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen.  This
+dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below.
+AC_CONFIG_COMMANDS_PRE(dnl
+[m4_provide_if([_AM_COMPILER_EXEEXT],
+  [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
+
+# POSIX will say in a future version that running "rm -f" with no argument
+# is OK; and we want to be able to make that assumption in our Makefile
+# recipes.  So use an aggressive probe to check that the usage we want is
+# actually supported "in the wild" to an acceptable degree.
+# See automake bug#10828.
+# To make any issue more visible, cause the running configure to be aborted
+# by default if the 'rm' program in use doesn't match our expectations; the
+# user can still override this though.
+if rm -f && rm -fr && rm -rf; then : OK; else
+  cat >&2 <<'END'
+Oops!
+
+Your 'rm' program seems unable to run without file operands specified
+on the command line, even when the '-f' option is present.  This is contrary
+to the behaviour of most rm programs out there, and not conforming with
+the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
+
+Please tell bug-automake at gnu.org about your system, including the value
+of your $PATH and any error possibly output before this message.  This
+can help us improve future automake versions.
+
+END
+  if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
+    echo 'Configuration will proceed anyway, since you have set the' >&2
+    echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
+    echo >&2
+  else
+    cat >&2 <<'END'
+Aborting the configuration process, to ensure you take notice of the issue.
+
+You can download and install GNU coreutils to get an 'rm' implementation
+that behaves properly: <http://www.gnu.org/software/coreutils/>.
+
+If you want to complete the configuration process using your problematic
+'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
+to "yes", and re-run configure.
+
+END
+    AC_MSG_ERROR([Your 'rm' program is bad, sorry.])
+  fi
+fi
+])
+
+dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion.  Do not
+dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
+dnl mangled by Autoconf and run in a shell conditional statement.
+m4_define([_AC_COMPILER_EXEEXT],
+m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated.  The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_arg=$1
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+  case $_am_header in
+    $_am_arg | $_am_arg:* )
+      break ;;
+    * )
+      _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+  esac
+done
+echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+if test x"${install_sh}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+  *)
+    install_sh="\${SHELL} $am_aux_dir/install-sh"
+  esac
+fi
+AC_SUBST([install_sh])])
+
+# Copyright (C) 2003-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot.  For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+  am__leading_dot=.
+else
+  am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# Check to see how 'make' treats includes.	            -*- Autoconf -*-
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+	@echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from 'make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+  am__include=include
+  am__quote=
+  _am_result=GNU
+  ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+   echo '.include "confinc"' > confmf
+   case `$am_make -s -f confmf 2> /dev/null` in #(
+   *the\ am__doit\ target*)
+     am__include=.include
+     am__quote="\""
+     _am_result=BSD
+     ;;
+   esac
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# Fake the existence of programs that GNU maintainers use.  -*- Autoconf -*-
+
+# Copyright (C) 1997-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it is modern enough.
+# If it is, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([missing])dnl
+if test x"${MISSING+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+  *)
+    MISSING="\${SHELL} $am_aux_dir/missing" ;;
+  esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+  am_missing_run="$MISSING "
+else
+  am_missing_run=
+  AC_MSG_WARN(['missing' script is too old or missing])
+fi
+])
+
+# Helper functions for option handling.                     -*- Autoconf -*-
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# --------------------
+# Set option NAME.  Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), [1])])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_CC_C_O
+# ---------------
+# Like AC_PROG_CC_C_O, but changed for automake.  We rewrite AC_PROG_CC
+# to automatically call this.
+AC_DEFUN([_AM_PROG_CC_C_O],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([compile])dnl
+AC_LANG_PUSH([C])dnl
+AC_CACHE_CHECK(
+  [whether $CC understands -c and -o together],
+  [am_cv_prog_cc_c_o],
+  [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])])
+  # Make sure it works both with $CC and with simple cc.
+  # Following AC_PROG_CC_C_O, we do the test twice because some
+  # compilers refuse to overwrite an existing .o file with -o,
+  # though they will create one.
+  am_cv_prog_cc_c_o=yes
+  for am_i in 1 2; do
+    if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \
+         && test -f conftest2.$ac_objext; then
+      : OK
+    else
+      am_cv_prog_cc_c_o=no
+      break
+    fi
+  done
+  rm -f core conftest*
+  unset am_i])
+if test "$am_cv_prog_cc_c_o" != yes; then
+   # Losing compiler, so override with the script.
+   # FIXME: It is wrong to rewrite CC.
+   # But if we don't then we get into trouble of one sort or another.
+   # A longer-term fix would be to have automake use am__CC in this case,
+   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+   CC="$am_aux_dir/compile $CC"
+fi
+AC_LANG_POP([C])])
+
+# For backward compatibility.
+AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_RUN_LOG(COMMAND)
+# -------------------
+# Run COMMAND, save the exit status in ac_status, and log it.
+# (This has been adapted from Autoconf's _AC_RUN_LOG macro.)
+AC_DEFUN([AM_RUN_LOG],
+[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD
+   ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD
+   ac_status=$?
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   (exit $ac_status); }])
+
+# Check to make sure that the build environment is sane.    -*- Autoconf -*-
+
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name.  Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+  *[[\\\"\#\$\&\'\`$am_lf]]*)
+    AC_MSG_ERROR([unsafe absolute working directory name]);;
+esac
+case $srcdir in
+  *[[\\\"\#\$\&\'\`$am_lf\ \	]]*)
+    AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   am_has_slept=no
+   for am_try in 1 2; do
+     echo "timestamp, slept: $am_has_slept" > conftest.file
+     set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+     if test "$[*]" = "X"; then
+	# -L didn't work.
+	set X `ls -t "$srcdir/configure" conftest.file`
+     fi
+     if test "$[*]" != "X $srcdir/configure conftest.file" \
+	&& test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+	# If neither matched, then we have a broken ls.  This can happen
+	# if, for instance, CONFIG_SHELL is bash and it inherits a
+	# broken ls alias from the environment.  This has actually
+	# happened.  Such a system could not be considered "sane".
+	AC_MSG_ERROR([ls -t appears to fail.  Make sure there is not a broken
+  alias in your environment])
+     fi
+     if test "$[2]" = conftest.file || test $am_try -eq 2; then
+       break
+     fi
+     # Just in case.
+     sleep 1
+     am_has_slept=yes
+   done
+   test "$[2]" = conftest.file
+   )
+then
+   # Ok.
+   :
+else
+   AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT([yes])
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+  ( sleep 1 ) &
+  am_sleep_pid=$!
+fi
+AC_CONFIG_COMMANDS_PRE(
+  [AC_MSG_CHECKING([that generated files are newer than configure])
+   if test -n "$am_sleep_pid"; then
+     # Hide warnings about reused PIDs.
+     wait $am_sleep_pid 2>/dev/null
+   fi
+   AC_MSG_RESULT([done])])
+rm -f conftest.file
+])
+
+# Copyright (C) 2009-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SILENT_RULES([DEFAULT])
+# --------------------------
+# Enable less verbose build rules; with the default set to DEFAULT
+# ("yes" being less verbose, "no" or empty being verbose).
+AC_DEFUN([AM_SILENT_RULES],
+[AC_ARG_ENABLE([silent-rules], [dnl
+AS_HELP_STRING(
+  [--enable-silent-rules],
+  [less verbose build output (undo: "make V=1")])
+AS_HELP_STRING(
+  [--disable-silent-rules],
+  [verbose build output (undo: "make V=0")])dnl
+])
+case $enable_silent_rules in @%:@ (((
+  yes) AM_DEFAULT_VERBOSITY=0;;
+   no) AM_DEFAULT_VERBOSITY=1;;
+    *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);;
+esac
+dnl
+dnl A few 'make' implementations (e.g., NonStop OS and NextStep)
+dnl do not support nested variable expansions.
+dnl See automake bug#9928 and bug#10237.
+am_make=${MAKE-make}
+AC_CACHE_CHECK([whether $am_make supports nested variables],
+   [am_cv_make_support_nested_variables],
+   [if AS_ECHO([['TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+	@$(TRUE)
+.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then
+  am_cv_make_support_nested_variables=yes
+else
+  am_cv_make_support_nested_variables=no
+fi])
+if test $am_cv_make_support_nested_variables = yes; then
+  dnl Using '$V' instead of '$(V)' breaks IRIX make.
+  AM_V='$(V)'
+  AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+  AM_V=$AM_DEFAULT_VERBOSITY
+  AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AC_SUBST([AM_V])dnl
+AM_SUBST_NOTMAKE([AM_V])dnl
+AC_SUBST([AM_DEFAULT_V])dnl
+AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl
+AC_SUBST([AM_DEFAULT_VERBOSITY])dnl
+AM_BACKSLASH='\'
+AC_SUBST([AM_BACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
+])
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor 'install' (even GNU) is that you can't
+# specify the program used to strip binaries.  This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in "make install-strip", and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip".  However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be 'maybe'.
+if test "$cross_compiling" != no; then
+  AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Copyright (C) 2006-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_AM_SUBST_NOTMAKE])
+
+# AM_SUBST_NOTMAKE(VARIABLE)
+# --------------------------
+# Public sister of _AM_SUBST_NOTMAKE.
+AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
+
+# Check how to create a tarball.                            -*- Autoconf -*-
+
+# Copyright (C) 2004-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of 'v7', 'ustar', or 'pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+#     tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+#     $(am__untar) < result.tar
+#
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility.  Yes, it's still used
+# in the wild :-(  We should find a proper way to deprecate it ...
+AC_SUBST([AMTAR], ['$${TAR-tar}'])
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+
+m4_if([$1], [v7],
+  [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'],
+
+  [m4_case([$1],
+    [ustar],
+     [# The POSIX 1988 'ustar' format is defined with fixed-size fields.
+      # There is notably a 21 bits limit for the UID and the GID.  In fact,
+      # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343
+      # and bug#13588).
+      am_max_uid=2097151 # 2^21 - 1
+      am_max_gid=$am_max_uid
+      # The $UID and $GID variables are not portable, so we need to resort
+      # to the POSIX-mandated id(1) utility.  Errors in the 'id' calls
+      # below are definitely unexpected, so allow the users to see them
+      # (that is, avoid stderr redirection).
+      am_uid=`id -u || echo unknown`
+      am_gid=`id -g || echo unknown`
+      AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format])
+      if test $am_uid -le $am_max_uid; then
+         AC_MSG_RESULT([yes])
+      else
+         AC_MSG_RESULT([no])
+         _am_tools=none
+      fi
+      AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format])
+      if test $am_gid -le $am_max_gid; then
+         AC_MSG_RESULT([yes])
+      else
+        AC_MSG_RESULT([no])
+        _am_tools=none
+      fi],
+
+  [pax],
+    [],
+
+  [m4_fatal([Unknown tar format])])
+
+  AC_MSG_CHECKING([how to create a $1 tar archive])
+
+  # Go ahead even if we have the value already cached.  We do so because we
+  # need to set the values for the 'am__tar' and 'am__untar' variables.
+  _am_tools=${am_cv_prog_tar_$1-$_am_tools}
+
+  for _am_tool in $_am_tools; do
+    case $_am_tool in
+    gnutar)
+      for _am_tar in tar gnutar gtar; do
+        AM_RUN_LOG([$_am_tar --version]) && break
+      done
+      am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+      am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+      am__untar="$_am_tar -xf -"
+      ;;
+    plaintar)
+      # Must skip GNU tar: if it does not support --format= it doesn't create
+      # ustar tarball either.
+      (tar --version) >/dev/null 2>&1 && continue
+      am__tar='tar chf - "$$tardir"'
+      am__tar_='tar chf - "$tardir"'
+      am__untar='tar xf -'
+      ;;
+    pax)
+      am__tar='pax -L -x $1 -w "$$tardir"'
+      am__tar_='pax -L -x $1 -w "$tardir"'
+      am__untar='pax -r'
+      ;;
+    cpio)
+      am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+      am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+      am__untar='cpio -i -H $1 -d'
+      ;;
+    none)
+      am__tar=false
+      am__tar_=false
+      am__untar=false
+      ;;
+    esac
+
+    # If the value was cached, stop now.  We just wanted to have am__tar
+    # and am__untar set.
+    test -n "${am_cv_prog_tar_$1}" && break
+
+    # tar/untar a dummy directory, and stop if the command works.
+    rm -rf conftest.dir
+    mkdir conftest.dir
+    echo GrepMe > conftest.dir/file
+    AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+    rm -rf conftest.dir
+    if test -s conftest.tar; then
+      AM_RUN_LOG([$am__untar <conftest.tar])
+      AM_RUN_LOG([cat conftest.dir/file])
+      grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+    fi
+  done
+  rm -rf conftest.dir
+
+  AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+  AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
+m4_include([autostuff/libtool.m4])
+m4_include([autostuff/ltoptions.m4])
+m4_include([autostuff/ltsugar.m4])
+m4_include([autostuff/ltversion.m4])
+m4_include([autostuff/lt~obsolete.m4])
diff --git a/autostuff/ar-lib b/autostuff/ar-lib
new file mode 100755
index 0000000..fe2301e
--- /dev/null
+++ b/autostuff/ar-lib
@@ -0,0 +1,270 @@
+#! /bin/sh
+# Wrapper for Microsoft lib.exe
+
+me=ar-lib
+scriptversion=2012-03-01.08; # UTC
+
+# Copyright (C) 2010-2013 Free Software Foundation, Inc.
+# Written by Peter Rosin <peda at lysator.liu.se>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake at gnu.org> or send patches to
+# <automake-patches at gnu.org>.
+
+
+# func_error message
+func_error ()
+{
+  echo "$me: $1" 1>&2
+  exit 1
+}
+
+file_conv=
+
+# func_file_conv build_file
+# Convert a $build file to $host form and store it in $file
+# Currently only supports Windows hosts.
+func_file_conv ()
+{
+  file=$1
+  case $file in
+    / | /[!/]*) # absolute file, and not a UNC file
+      if test -z "$file_conv"; then
+	# lazily determine how to convert abs files
+	case `uname -s` in
+	  MINGW*)
+	    file_conv=mingw
+	    ;;
+	  CYGWIN*)
+	    file_conv=cygwin
+	    ;;
+	  *)
+	    file_conv=wine
+	    ;;
+	esac
+      fi
+      case $file_conv in
+	mingw)
+	  file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
+	  ;;
+	cygwin)
+	  file=`cygpath -m "$file" || echo "$file"`
+	  ;;
+	wine)
+	  file=`winepath -w "$file" || echo "$file"`
+	  ;;
+      esac
+      ;;
+  esac
+}
+
+# func_at_file at_file operation archive
+# Iterate over all members in AT_FILE performing OPERATION on ARCHIVE
+# for each of them.
+# When interpreting the content of the @FILE, do NOT use func_file_conv,
+# since the user would need to supply preconverted file names to
+# binutils ar, at least for MinGW.
+func_at_file ()
+{
+  operation=$2
+  archive=$3
+  at_file_contents=`cat "$1"`
+  eval set x "$at_file_contents"
+  shift
+
+  for member
+  do
+    $AR -NOLOGO $operation:"$member" "$archive" || exit $?
+  done
+}
+
+case $1 in
+  '')
+     func_error "no command.  Try '$0 --help' for more information."
+     ;;
+  -h | --h*)
+    cat <<EOF
+Usage: $me [--help] [--version] PROGRAM ACTION ARCHIVE [MEMBER...]
+
+Members may be specified in a file named with @FILE.
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "$me, version $scriptversion"
+    exit $?
+    ;;
+esac
+
+if test $# -lt 3; then
+  func_error "you must specify a program, an action and an archive"
+fi
+
+AR=$1
+shift
+while :
+do
+  if test $# -lt 2; then
+    func_error "you must specify a program, an action and an archive"
+  fi
+  case $1 in
+    -lib | -LIB \
+    | -ltcg | -LTCG \
+    | -machine* | -MACHINE* \
+    | -subsystem* | -SUBSYSTEM* \
+    | -verbose | -VERBOSE \
+    | -wx* | -WX* )
+      AR="$AR $1"
+      shift
+      ;;
+    *)
+      action=$1
+      shift
+      break
+      ;;
+  esac
+done
+orig_archive=$1
+shift
+func_file_conv "$orig_archive"
+archive=$file
+
+# strip leading dash in $action
+action=${action#-}
+
+delete=
+extract=
+list=
+quick=
+replace=
+index=
+create=
+
+while test -n "$action"
+do
+  case $action in
+    d*) delete=yes  ;;
+    x*) extract=yes ;;
+    t*) list=yes    ;;
+    q*) quick=yes   ;;
+    r*) replace=yes ;;
+    s*) index=yes   ;;
+    S*)             ;; # the index is always updated implicitly
+    c*) create=yes  ;;
+    u*)             ;; # TODO: don't ignore the update modifier
+    v*)             ;; # TODO: don't ignore the verbose modifier
+    *)
+      func_error "unknown action specified"
+      ;;
+  esac
+  action=${action#?}
+done
+
+case $delete$extract$list$quick$replace,$index in
+  yes,* | ,yes)
+    ;;
+  yesyes*)
+    func_error "more than one action specified"
+    ;;
+  *)
+    func_error "no action specified"
+    ;;
+esac
+
+if test -n "$delete"; then
+  if test ! -f "$orig_archive"; then
+    func_error "archive not found"
+  fi
+  for member
+  do
+    case $1 in
+      @*)
+        func_at_file "${1#@}" -REMOVE "$archive"
+        ;;
+      *)
+        func_file_conv "$1"
+        $AR -NOLOGO -REMOVE:"$file" "$archive" || exit $?
+        ;;
+    esac
+  done
+
+elif test -n "$extract"; then
+  if test ! -f "$orig_archive"; then
+    func_error "archive not found"
+  fi
+  if test $# -gt 0; then
+    for member
+    do
+      case $1 in
+        @*)
+          func_at_file "${1#@}" -EXTRACT "$archive"
+          ;;
+        *)
+          func_file_conv "$1"
+          $AR -NOLOGO -EXTRACT:"$file" "$archive" || exit $?
+          ;;
+      esac
+    done
+  else
+    $AR -NOLOGO -LIST "$archive" | sed -e 's/\\/\\\\/g' | while read member
+    do
+      $AR -NOLOGO -EXTRACT:"$member" "$archive" || exit $?
+    done
+  fi
+
+elif test -n "$quick$replace"; then
+  if test ! -f "$orig_archive"; then
+    if test -z "$create"; then
+      echo "$me: creating $orig_archive"
+    fi
+    orig_archive=
+  else
+    orig_archive=$archive
+  fi
+
+  for member
+  do
+    case $1 in
+    @*)
+      func_file_conv "${1#@}"
+      set x "$@" "@$file"
+      ;;
+    *)
+      func_file_conv "$1"
+      set x "$@" "$file"
+      ;;
+    esac
+    shift
+    shift
+  done
+
+  if test -n "$orig_archive"; then
+    $AR -NOLOGO -OUT:"$archive" "$orig_archive" "$@" || exit $?
+  else
+    $AR -NOLOGO -OUT:"$archive" "$@" || exit $?
+  fi
+
+elif test -n "$list"; then
+  if test ! -f "$orig_archive"; then
+    func_error "archive not found"
+  fi
+  $AR -NOLOGO -LIST "$archive" || exit $?
+fi
diff --git a/autostuff/compile b/autostuff/compile
new file mode 100755
index 0000000..531136b
--- /dev/null
+++ b/autostuff/compile
@@ -0,0 +1,347 @@
+#! /bin/sh
+# Wrapper for compilers which do not understand '-c -o'.
+
+scriptversion=2012-10-14.11; # UTC
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Written by Tom Tromey <tromey at cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake at gnu.org> or send patches to
+# <automake-patches at gnu.org>.
+
+nl='
+'
+
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent tools from complaining about whitespace usage.
+IFS=" ""	$nl"
+
+file_conv=
+
+# func_file_conv build_file lazy
+# Convert a $build file to $host form and store it in $file
+# Currently only supports Windows hosts. If the determined conversion
+# type is listed in (the comma separated) LAZY, no conversion will
+# take place.
+func_file_conv ()
+{
+  file=$1
+  case $file in
+    / | /[!/]*) # absolute file, and not a UNC file
+      if test -z "$file_conv"; then
+	# lazily determine how to convert abs files
+	case `uname -s` in
+	  MINGW*)
+	    file_conv=mingw
+	    ;;
+	  CYGWIN*)
+	    file_conv=cygwin
+	    ;;
+	  *)
+	    file_conv=wine
+	    ;;
+	esac
+      fi
+      case $file_conv/,$2, in
+	*,$file_conv,*)
+	  ;;
+	mingw/*)
+	  file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
+	  ;;
+	cygwin/*)
+	  file=`cygpath -m "$file" || echo "$file"`
+	  ;;
+	wine/*)
+	  file=`winepath -w "$file" || echo "$file"`
+	  ;;
+      esac
+      ;;
+  esac
+}
+
+# func_cl_dashL linkdir
+# Make cl look for libraries in LINKDIR
+func_cl_dashL ()
+{
+  func_file_conv "$1"
+  if test -z "$lib_path"; then
+    lib_path=$file
+  else
+    lib_path="$lib_path;$file"
+  fi
+  linker_opts="$linker_opts -LIBPATH:$file"
+}
+
+# func_cl_dashl library
+# Do a library search-path lookup for cl
+func_cl_dashl ()
+{
+  lib=$1
+  found=no
+  save_IFS=$IFS
+  IFS=';'
+  for dir in $lib_path $LIB
+  do
+    IFS=$save_IFS
+    if $shared && test -f "$dir/$lib.dll.lib"; then
+      found=yes
+      lib=$dir/$lib.dll.lib
+      break
+    fi
+    if test -f "$dir/$lib.lib"; then
+      found=yes
+      lib=$dir/$lib.lib
+      break
+    fi
+    if test -f "$dir/lib$lib.a"; then
+      found=yes
+      lib=$dir/lib$lib.a
+      break
+    fi
+  done
+  IFS=$save_IFS
+
+  if test "$found" != yes; then
+    lib=$lib.lib
+  fi
+}
+
+# func_cl_wrapper cl arg...
+# Adjust compile command to suit cl
+func_cl_wrapper ()
+{
+  # Assume a capable shell
+  lib_path=
+  shared=:
+  linker_opts=
+  for arg
+  do
+    if test -n "$eat"; then
+      eat=
+    else
+      case $1 in
+	-o)
+	  # configure might choose to run compile as 'compile cc -o foo foo.c'.
+	  eat=1
+	  case $2 in
+	    *.o | *.[oO][bB][jJ])
+	      func_file_conv "$2"
+	      set x "$@" -Fo"$file"
+	      shift
+	      ;;
+	    *)
+	      func_file_conv "$2"
+	      set x "$@" -Fe"$file"
+	      shift
+	      ;;
+	  esac
+	  ;;
+	-I)
+	  eat=1
+	  func_file_conv "$2" mingw
+	  set x "$@" -I"$file"
+	  shift
+	  ;;
+	-I*)
+	  func_file_conv "${1#-I}" mingw
+	  set x "$@" -I"$file"
+	  shift
+	  ;;
+	-l)
+	  eat=1
+	  func_cl_dashl "$2"
+	  set x "$@" "$lib"
+	  shift
+	  ;;
+	-l*)
+	  func_cl_dashl "${1#-l}"
+	  set x "$@" "$lib"
+	  shift
+	  ;;
+	-L)
+	  eat=1
+	  func_cl_dashL "$2"
+	  ;;
+	-L*)
+	  func_cl_dashL "${1#-L}"
+	  ;;
+	-static)
+	  shared=false
+	  ;;
+	-Wl,*)
+	  arg=${1#-Wl,}
+	  save_ifs="$IFS"; IFS=','
+	  for flag in $arg; do
+	    IFS="$save_ifs"
+	    linker_opts="$linker_opts $flag"
+	  done
+	  IFS="$save_ifs"
+	  ;;
+	-Xlinker)
+	  eat=1
+	  linker_opts="$linker_opts $2"
+	  ;;
+	-*)
+	  set x "$@" "$1"
+	  shift
+	  ;;
+	*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
+	  func_file_conv "$1"
+	  set x "$@" -Tp"$file"
+	  shift
+	  ;;
+	*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
+	  func_file_conv "$1" mingw
+	  set x "$@" "$file"
+	  shift
+	  ;;
+	*)
+	  set x "$@" "$1"
+	  shift
+	  ;;
+      esac
+    fi
+    shift
+  done
+  if test -n "$linker_opts"; then
+    linker_opts="-link$linker_opts"
+  fi
+  exec "$@" $linker_opts
+  exit 1
+}
+
+eat=
+
+case $1 in
+  '')
+     echo "$0: No command.  Try '$0 --help' for more information." 1>&2
+     exit 1;
+     ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand '-c -o'.
+Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file 'INSTALL'.
+
+Report bugs to <bug-automake at gnu.org>.
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "compile $scriptversion"
+    exit $?
+    ;;
+  cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
+    func_cl_wrapper "$@"      # Doesn't return...
+    ;;
+esac
+
+ofile=
+cfile=
+
+for arg
+do
+  if test -n "$eat"; then
+    eat=
+  else
+    case $1 in
+      -o)
+	# configure might choose to run compile as 'compile cc -o foo foo.c'.
+	# So we strip '-o arg' only if arg is an object.
+	eat=1
+	case $2 in
+	  *.o | *.obj)
+	    ofile=$2
+	    ;;
+	  *)
+	    set x "$@" -o "$2"
+	    shift
+	    ;;
+	esac
+	;;
+      *.c)
+	cfile=$1
+	set x "$@" "$1"
+	shift
+	;;
+      *)
+	set x "$@" "$1"
+	shift
+	;;
+    esac
+  fi
+  shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+  # If no '-o' option was seen then we might have been invoked from a
+  # pattern rule where we don't need one.  That is ok -- this is a
+  # normal compilation that the losing compiler can handle.  If no
+  # '.c' file was seen then we are probably linking.  That is also
+  # ok.
+  exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use '[/\\:.-]' here to ensure that we don't use the same name
+# that we are using for the .o file.  Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
+while true; do
+  if mkdir "$lockdir" >/dev/null 2>&1; then
+    break
+  fi
+  sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+  test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
+elif test -f "${cofile}bj"; then
+  test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/autostuff/config.guess b/autostuff/config.guess
new file mode 100755
index 0000000..b79252d
--- /dev/null
+++ b/autostuff/config.guess
@@ -0,0 +1,1558 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright 1992-2013 Free Software Foundation, Inc.
+
+timestamp='2013-06-10'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program.  This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+#
+# Originally written by Per Bothner.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+#
+# Please send patches with a ChangeLog entry to config-patches at gnu.org.
+
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches at gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright 1992-2013 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help" >&2
+       exit 1 ;;
+    * )
+       break ;;
+  esac
+done
+
+if test $# != 0; then
+  echo "$me: too many arguments$help" >&2
+  exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,)    echo "int x;" > $dummy.c ;
+	for c in cc gcc c89 c99 ; do
+	  if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+	     CC_FOR_BUILD="$c"; break ;
+	  fi ;
+	done ;
+	if test x"$CC_FOR_BUILD" = x ; then
+	  CC_FOR_BUILD=no_compiler_found ;
+	fi
+	;;
+ ,,*)   CC_FOR_BUILD=$CC ;;
+ ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi at noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+	PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+case "${UNAME_SYSTEM}" in
+Linux|GNU|GNU/*)
+	# If the system lacks a compiler, then just pick glibc.
+	# We could probably try harder.
+	LIBC=gnu
+
+	eval $set_cc_for_build
+	cat <<-EOF > $dummy.c
+	#include <features.h>
+	#if defined(__UCLIBC__)
+	LIBC=uclibc
+	#elif defined(__dietlibc__)
+	LIBC=dietlibc
+	#else
+	LIBC=gnu
+	#endif
+	EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+	;;
+esac
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+    *:NetBSD:*:*)
+	# NetBSD (nbsd) targets should (where applicable) match one or
+	# more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
+	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
+	# switched to ELF, *-*-netbsd* would select the old
+	# object file format.  This provides both forward
+	# compatibility and a consistent mechanism for selecting the
+	# object file format.
+	#
+	# Note: NetBSD doesn't particularly care about the vendor
+	# portion of the name.  We always set it to "unknown".
+	sysctl="sysctl -n hw.machine_arch"
+	UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+	    /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+	case "${UNAME_MACHINE_ARCH}" in
+	    armeb) machine=armeb-unknown ;;
+	    arm*) machine=arm-unknown ;;
+	    sh3el) machine=shl-unknown ;;
+	    sh3eb) machine=sh-unknown ;;
+	    sh5el) machine=sh5le-unknown ;;
+	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+	esac
+	# The Operating System including object format, if it has switched
+	# to ELF recently, or will in the future.
+	case "${UNAME_MACHINE_ARCH}" in
+	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+		eval $set_cc_for_build
+		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+			| grep -q __ELF__
+		then
+		    # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+		    # Return netbsd for either.  FIX?
+		    os=netbsd
+		else
+		    os=netbsdelf
+		fi
+		;;
+	    *)
+		os=netbsd
+		;;
+	esac
+	# The OS release
+	# Debian GNU/NetBSD machines have a different userland, and
+	# thus, need a distinct triplet. However, they do not need
+	# kernel version information, so it can be replaced with a
+	# suitable tag, in the style of linux-gnu.
+	case "${UNAME_VERSION}" in
+	    Debian*)
+		release='-gnu'
+		;;
+	    *)
+		release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+		;;
+	esac
+	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+	# contains redundant information, the shorter form:
+	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+	echo "${machine}-${os}${release}"
+	exit ;;
+    *:Bitrig:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
+	exit ;;
+    *:OpenBSD:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+	exit ;;
+    *:ekkoBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+	exit ;;
+    *:SolidBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+	exit ;;
+    macppc:MirBSD:*:*)
+	echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    *:MirBSD:*:*)
+	echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+	exit ;;
+    alpha:OSF1:*:*)
+	case $UNAME_RELEASE in
+	*4.0)
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+		;;
+	*5.*)
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+		;;
+	esac
+	# According to Compaq, /usr/sbin/psrinfo has been available on
+	# OSF/1 and Tru64 systems produced since 1995.  I hope that
+	# covers most systems running today.  This code pipes the CPU
+	# types through head -n 1, so we only detect the type of CPU 0.
+	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+	case "$ALPHA_CPU_TYPE" in
+	    "EV4 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV4.5 (21064)")
+		UNAME_MACHINE="alpha" ;;
+	    "LCA4 (21066/21068)")
+		UNAME_MACHINE="alpha" ;;
+	    "EV5 (21164)")
+		UNAME_MACHINE="alphaev5" ;;
+	    "EV5.6 (21164A)")
+		UNAME_MACHINE="alphaev56" ;;
+	    "EV5.6 (21164PC)")
+		UNAME_MACHINE="alphapca56" ;;
+	    "EV5.7 (21164PC)")
+		UNAME_MACHINE="alphapca57" ;;
+	    "EV6 (21264)")
+		UNAME_MACHINE="alphaev6" ;;
+	    "EV6.7 (21264A)")
+		UNAME_MACHINE="alphaev67" ;;
+	    "EV6.8CB (21264C)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8AL (21264B)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.8CX (21264D)")
+		UNAME_MACHINE="alphaev68" ;;
+	    "EV6.9A (21264/EV69A)")
+		UNAME_MACHINE="alphaev69" ;;
+	    "EV7 (21364)")
+		UNAME_MACHINE="alphaev7" ;;
+	    "EV7.9 (21364A)")
+		UNAME_MACHINE="alphaev79" ;;
+	esac
+	# A Pn.n version is a patched version.
+	# A Vn.n version is a released version.
+	# A Tn.n version is a released field test version.
+	# A Xn.n version is an unreleased experimental baselevel.
+	# 1.2 uses "1.2" for uname -r.
+	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+	exitcode=$?
+	trap '' 0
+	exit $exitcode ;;
+    Alpha\ *:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# Should we change UNAME_MACHINE based on the output of uname instead
+	# of the specific Alpha model?
+	echo alpha-pc-interix
+	exit ;;
+    21064:Windows_NT:50:3)
+	echo alpha-dec-winnt3.5
+	exit ;;
+    Amiga*:UNIX_System_V:4.0:*)
+	echo m68k-unknown-sysv4
+	exit ;;
+    *:[Aa]miga[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-amigaos
+	exit ;;
+    *:[Mm]orph[Oo][Ss]:*:*)
+	echo ${UNAME_MACHINE}-unknown-morphos
+	exit ;;
+    *:OS/390:*:*)
+	echo i370-ibm-openedition
+	exit ;;
+    *:z/VM:*:*)
+	echo s390-ibm-zvmoe
+	exit ;;
+    *:OS400:*:*)
+	echo powerpc-ibm-os400
+	exit ;;
+    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+	echo arm-acorn-riscix${UNAME_RELEASE}
+	exit ;;
+    arm*:riscos:*:*|arm*:RISCOS:*:*)
+	echo arm-unknown-riscos
+	exit ;;
+    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+	echo hppa1.1-hitachi-hiuxmpp
+	exit ;;
+    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+	# akee at wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+	if test "`(/bin/universe) 2>/dev/null`" = att ; then
+		echo pyramid-pyramid-sysv3
+	else
+		echo pyramid-pyramid-bsd
+	fi
+	exit ;;
+    NILE*:*:*:dcosx)
+	echo pyramid-pyramid-svr4
+	exit ;;
+    DRS?6000:unix:4.0:6*)
+	echo sparc-icl-nx6
+	exit ;;
+    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+	case `/usr/bin/uname -p` in
+	    sparc) echo sparc-icl-nx7; exit ;;
+	esac ;;
+    s390x:SunOS:*:*)
+	echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4H:SunOS:5.*:*)
+	echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+	echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+	echo i386-pc-auroraux${UNAME_RELEASE}
+	exit ;;
+    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+	eval $set_cc_for_build
+	SUN_ARCH="i386"
+	# If there is a compiler, see if it is configured for 64-bit objects.
+	# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+	# This test works for both compilers.
+	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+	    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		grep IS_64BIT_ARCH >/dev/null
+	    then
+		SUN_ARCH="x86_64"
+	    fi
+	fi
+	echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:6*:*)
+	# According to config.sub, this is the proper way to canonicalize
+	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
+	# it's likely to be more like Solaris than SunOS4.
+	echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    sun4*:SunOS:*:*)
+	case "`/usr/bin/arch -k`" in
+	    Series*|S4*)
+		UNAME_RELEASE=`uname -v`
+		;;
+	esac
+	# Japanese Language versions have a version number like `4.1.3-JL'.
+	echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+	exit ;;
+    sun3*:SunOS:*:*)
+	echo m68k-sun-sunos${UNAME_RELEASE}
+	exit ;;
+    sun*:*:4.2BSD:*)
+	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+	case "`/bin/arch`" in
+	    sun3)
+		echo m68k-sun-sunos${UNAME_RELEASE}
+		;;
+	    sun4)
+		echo sparc-sun-sunos${UNAME_RELEASE}
+		;;
+	esac
+	exit ;;
+    aushp:SunOS:*:*)
+	echo sparc-auspex-sunos${UNAME_RELEASE}
+	exit ;;
+    # The situation for MiNT is a little confusing.  The machine name
+    # can be virtually everything (everything which is not
+    # "atarist" or "atariste" at least should have a processor
+    # > m68000).  The system name ranges from "MiNT" over "FreeMiNT"
+    # to the lowercase version "mint" (or "freemint").  Finally
+    # the system name "TOS" denotes a system which is actually not
+    # MiNT.  But MiNT is downward compatible to TOS, so this should
+    # be no problem.
+    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+	echo m68k-atari-mint${UNAME_RELEASE}
+	exit ;;
+    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+	echo m68k-milan-mint${UNAME_RELEASE}
+	exit ;;
+    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+	echo m68k-hades-mint${UNAME_RELEASE}
+	exit ;;
+    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+	echo m68k-unknown-mint${UNAME_RELEASE}
+	exit ;;
+    m68k:machten:*:*)
+	echo m68k-apple-machten${UNAME_RELEASE}
+	exit ;;
+    powerpc:machten:*:*)
+	echo powerpc-apple-machten${UNAME_RELEASE}
+	exit ;;
+    RISC*:Mach:*:*)
+	echo mips-dec-mach_bsd4.3
+	exit ;;
+    RISC*:ULTRIX:*:*)
+	echo mips-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    VAX*:ULTRIX*:*:*)
+	echo vax-dec-ultrix${UNAME_RELEASE}
+	exit ;;
+    2020:CLIX:*:* | 2430:CLIX:*:*)
+	echo clipper-intergraph-clix${UNAME_RELEASE}
+	exit ;;
+    mips:*:*:UMIPS | mips:*:*:RISCos)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h>  /* for printf() prototype */
+	int main (int argc, char *argv[]) {
+#else
+	int main (argc, argv) int argc; char *argv[]; {
+#endif
+	#if defined (host_mips) && defined (MIPSEB)
+	#if defined (SYSTYPE_SYSV)
+	  printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_SVR4)
+	  printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+	#endif
+	#if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+	  printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+	#endif
+	#endif
+	  exit (-1);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c &&
+	  dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+	  SYSTEM_NAME=`$dummy $dummyarg` &&
+	    { echo "$SYSTEM_NAME"; exit; }
+	echo mips-mips-riscos${UNAME_RELEASE}
+	exit ;;
+    Motorola:PowerMAX_OS:*:*)
+	echo powerpc-motorola-powermax
+	exit ;;
+    Motorola:*:4.3:PL8-*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+	echo powerpc-harris-powermax
+	exit ;;
+    Night_Hawk:Power_UNIX:*:*)
+	echo powerpc-harris-powerunix
+	exit ;;
+    m88k:CX/UX:7*:*)
+	echo m88k-harris-cxux7
+	exit ;;
+    m88k:*:4*:R4*)
+	echo m88k-motorola-sysv4
+	exit ;;
+    m88k:*:3*:R3*)
+	echo m88k-motorola-sysv3
+	exit ;;
+    AViiON:dgux:*:*)
+	# DG/UX returns AViiON for all architectures
+	UNAME_PROCESSOR=`/usr/bin/uname -p`
+	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+	then
+	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+	       [ ${TARGET_BINARY_INTERFACE}x = x ]
+	    then
+		echo m88k-dg-dgux${UNAME_RELEASE}
+	    else
+		echo m88k-dg-dguxbcs${UNAME_RELEASE}
+	    fi
+	else
+	    echo i586-dg-dgux${UNAME_RELEASE}
+	fi
+	exit ;;
+    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
+	echo m88k-dolphin-sysv3
+	exit ;;
+    M88*:*:R3*:*)
+	# Delta 88k system running SVR3
+	echo m88k-motorola-sysv3
+	exit ;;
+    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+	echo m88k-tektronix-sysv3
+	exit ;;
+    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+	echo m68k-tektronix-bsd
+	exit ;;
+    *:IRIX*:*:*)
+	echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+	exit ;;
+    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+	echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
+	exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
+    i*86:AIX:*:*)
+	echo i386-ibm-aix
+	exit ;;
+    ia64:AIX:*:*)
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:2:3)
+	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+		eval $set_cc_for_build
+		sed 's/^		//' << EOF >$dummy.c
+		#include <sys/systemcfg.h>
+
+		main()
+			{
+			if (!__power_pc())
+				exit(1);
+			puts("powerpc-ibm-aix3.2.5");
+			exit(0);
+			}
+EOF
+		if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+		then
+			echo "$SYSTEM_NAME"
+		else
+			echo rs6000-ibm-aix3.2.5
+		fi
+	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+		echo rs6000-ibm-aix3.2.4
+	else
+		echo rs6000-ibm-aix3.2
+	fi
+	exit ;;
+    *:AIX:*:[4567])
+	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+		IBM_ARCH=rs6000
+	else
+		IBM_ARCH=powerpc
+	fi
+	if [ -x /usr/bin/oslevel ] ; then
+		IBM_REV=`/usr/bin/oslevel`
+	else
+		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+	fi
+	echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+	exit ;;
+    *:AIX:*:*)
+	echo rs6000-ibm-aix
+	exit ;;
+    ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+	echo romp-ibm-bsd4.4
+	exit ;;
+    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
+	echo romp-ibm-bsd${UNAME_RELEASE}   # 4.3 with uname added to
+	exit ;;                             # report: romp-ibm BSD 4.3
+    *:BOSX:*:*)
+	echo rs6000-bull-bosx
+	exit ;;
+    DPX/2?00:B.O.S.:*:*)
+	echo m68k-bull-sysv3
+	exit ;;
+    9000/[34]??:4.3bsd:1.*:*)
+	echo m68k-hp-bsd
+	exit ;;
+    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+	echo m68k-hp-bsd4.4
+	exit ;;
+    9000/[34678]??:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	case "${UNAME_MACHINE}" in
+	    9000/31? )            HP_ARCH=m68000 ;;
+	    9000/[34]?? )         HP_ARCH=m68k ;;
+	    9000/[678][0-9][0-9])
+		if [ -x /usr/bin/getconf ]; then
+		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+		    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+		    case "${sc_cpu_version}" in
+		      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+		      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+		      532)                      # CPU_PA_RISC2_0
+			case "${sc_kernel_bits}" in
+			  32) HP_ARCH="hppa2.0n" ;;
+			  64) HP_ARCH="hppa2.0w" ;;
+			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
+			esac ;;
+		    esac
+		fi
+		if [ "${HP_ARCH}" = "" ]; then
+		    eval $set_cc_for_build
+		    sed 's/^		//' << EOF >$dummy.c
+
+		#define _HPUX_SOURCE
+		#include <stdlib.h>
+		#include <unistd.h>
+
+		int main ()
+		{
+		#if defined(_SC_KERNEL_BITS)
+		    long bits = sysconf(_SC_KERNEL_BITS);
+		#endif
+		    long cpu  = sysconf (_SC_CPU_VERSION);
+
+		    switch (cpu)
+			{
+			case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+			case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+			case CPU_PA_RISC2_0:
+		#if defined(_SC_KERNEL_BITS)
+			    switch (bits)
+				{
+				case 64: puts ("hppa2.0w"); break;
+				case 32: puts ("hppa2.0n"); break;
+				default: puts ("hppa2.0"); break;
+				} break;
+		#else  /* !defined(_SC_KERNEL_BITS) */
+			    puts ("hppa2.0"); break;
+		#endif
+			default: puts ("hppa1.0"); break;
+			}
+		    exit (0);
+		}
+EOF
+		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+		    test -z "$HP_ARCH" && HP_ARCH=hppa
+		fi ;;
+	esac
+	if [ ${HP_ARCH} = "hppa2.0w" ]
+	then
+	    eval $set_cc_for_build
+
+	    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+	    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
+	    # generating 64-bit code.  GNU and HP use different nomenclature:
+	    #
+	    # $ CC_FOR_BUILD=cc ./config.guess
+	    # => hppa2.0w-hp-hpux11.23
+	    # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+	    # => hppa64-hp-hpux11.23
+
+	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+		grep -q __LP64__
+	    then
+		HP_ARCH="hppa2.0w"
+	    else
+		HP_ARCH="hppa64"
+	    fi
+	fi
+	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+	exit ;;
+    ia64:HP-UX:*:*)
+	HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+	echo ia64-hp-hpux${HPUX_REV}
+	exit ;;
+    3050*:HI-UX:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <unistd.h>
+	int
+	main ()
+	{
+	  long cpu = sysconf (_SC_CPU_VERSION);
+	  /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+	     true for CPU_PA_RISC1_0.  CPU_IS_PA_RISC returns correct
+	     results, however.  */
+	  if (CPU_IS_PA_RISC (cpu))
+	    {
+	      switch (cpu)
+		{
+		  case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+		  case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+		  default: puts ("hppa-hitachi-hiuxwe2"); break;
+		}
+	    }
+	  else if (CPU_IS_HP_MC68K (cpu))
+	    puts ("m68k-hitachi-hiuxwe2");
+	  else puts ("unknown-hitachi-hiuxwe2");
+	  exit (0);
+	}
+EOF
+	$CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+		{ echo "$SYSTEM_NAME"; exit; }
+	echo unknown-hitachi-hiuxwe2
+	exit ;;
+    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+	echo hppa1.1-hp-bsd
+	exit ;;
+    9000/8??:4.3bsd:*:*)
+	echo hppa1.0-hp-bsd
+	exit ;;
+    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+	echo hppa1.0-hp-mpeix
+	exit ;;
+    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+	echo hppa1.1-hp-osf
+	exit ;;
+    hp8??:OSF1:*:*)
+	echo hppa1.0-hp-osf
+	exit ;;
+    i*86:OSF1:*:*)
+	if [ -x /usr/sbin/sysversion ] ; then
+	    echo ${UNAME_MACHINE}-unknown-osf1mk
+	else
+	    echo ${UNAME_MACHINE}-unknown-osf1
+	fi
+	exit ;;
+    parisc*:Lites*:*:*)
+	echo hppa1.1-hp-lites
+	exit ;;
+    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+	echo c1-convex-bsd
+	exit ;;
+    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit ;;
+    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+	echo c34-convex-bsd
+	exit ;;
+    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+	echo c38-convex-bsd
+	exit ;;
+    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+	echo c4-convex-bsd
+	exit ;;
+    CRAY*Y-MP:*:*:*)
+	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*[A-Z]90:*:*:*)
+	echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+	      -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+	      -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*TS:*:*:*)
+	echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*T3E:*:*:*)
+	echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    CRAY*SV1:*:*:*)
+	echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    *:UNICOS/mp:*:*)
+	echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+	exit ;;
+    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+	FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+	FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+	echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
+    5000:UNIX_System_V:4.*:*)
+	FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+	FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+	echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
+    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+	exit ;;
+    sparc*:BSD/OS:*:*)
+	echo sparc-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:BSD/OS:*:*)
+	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+	exit ;;
+    *:FreeBSD:*:*)
+	UNAME_PROCESSOR=`/usr/bin/uname -p`
+	case ${UNAME_PROCESSOR} in
+	    amd64)
+		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    *)
+		echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	esac
+	exit ;;
+    i*:CYGWIN*:*)
+	echo ${UNAME_MACHINE}-pc-cygwin
+	exit ;;
+    *:MINGW64*:*)
+	echo ${UNAME_MACHINE}-pc-mingw64
+	exit ;;
+    *:MINGW*:*)
+	echo ${UNAME_MACHINE}-pc-mingw32
+	exit ;;
+    i*:MSYS*:*)
+	echo ${UNAME_MACHINE}-pc-msys
+	exit ;;
+    i*:windows32*:*)
+	# uname -m includes "-pc" on this system.
+	echo ${UNAME_MACHINE}-mingw32
+	exit ;;
+    i*:PW*:*)
+	echo ${UNAME_MACHINE}-pc-pw32
+	exit ;;
+    *:Interix*:*)
+	case ${UNAME_MACHINE} in
+	    x86)
+		echo i586-pc-interix${UNAME_RELEASE}
+		exit ;;
+	    authenticamd | genuineintel | EM64T)
+		echo x86_64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	    IA64)
+		echo ia64-unknown-interix${UNAME_RELEASE}
+		exit ;;
+	esac ;;
+    [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+	echo i${UNAME_MACHINE}-pc-mks
+	exit ;;
+    8664:Windows_NT:*)
+	echo x86_64-pc-mks
+	exit ;;
+    i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+	# How do we know it's Interix rather than the generic POSIX subsystem?
+	# It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+	# UNAME_MACHINE based on the output of uname instead of i386?
+	echo i586-pc-interix
+	exit ;;
+    i*:UWIN*:*)
+	echo ${UNAME_MACHINE}-pc-uwin
+	exit ;;
+    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+	echo x86_64-unknown-cygwin
+	exit ;;
+    p*:CYGWIN*:*)
+	echo powerpcle-unknown-cygwin
+	exit ;;
+    prep*:SunOS:5.*:*)
+	echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+	exit ;;
+    *:GNU:*:*)
+	# the GNU system
+	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	exit ;;
+    *:GNU/*:*:*)
+	# other systems with GNU libc and userland
+	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
+	exit ;;
+    i*86:Minix:*:*)
+	echo ${UNAME_MACHINE}-pc-minix
+	exit ;;
+    aarch64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    aarch64_be:Linux:*:*)
+	UNAME_MACHINE=aarch64_be
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    alpha:Linux:*:*)
+	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+	  EV5)   UNAME_MACHINE=alphaev5 ;;
+	  EV56)  UNAME_MACHINE=alphaev56 ;;
+	  PCA56) UNAME_MACHINE=alphapca56 ;;
+	  PCA57) UNAME_MACHINE=alphapca56 ;;
+	  EV6)   UNAME_MACHINE=alphaev6 ;;
+	  EV67)  UNAME_MACHINE=alphaev67 ;;
+	  EV68*) UNAME_MACHINE=alphaev68 ;;
+	esac
+	objdump --private-headers /bin/sh | grep -q ld.so.1
+	if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    arc:Linux:*:* | arceb:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    arm*:Linux:*:*)
+	eval $set_cc_for_build
+	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+	    | grep -q __ARM_EABI__
+	then
+	    echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	else
+	    if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+		| grep -q __ARM_PCS_VFP
+	    then
+		echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
+	    else
+		echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
+	    fi
+	fi
+	exit ;;
+    avr32*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    cris:Linux:*:*)
+	echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+	exit ;;
+    crisv32:Linux:*:*)
+	echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+	exit ;;
+    frv:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    hexagon:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    i*86:Linux:*:*)
+	echo ${UNAME_MACHINE}-pc-linux-${LIBC}
+	exit ;;
+    ia64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    m32r*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    m68*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    mips:Linux:*:* | mips64:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef ${UNAME_MACHINE}
+	#undef ${UNAME_MACHINE}el
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=${UNAME_MACHINE}el
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=${UNAME_MACHINE}
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
+	;;
+    or1k:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    or32:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    padre:Linux:*:*)
+	echo sparc-unknown-linux-${LIBC}
+	exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+	echo hppa64-unknown-linux-${LIBC}
+	exit ;;
+    parisc:Linux:*:* | hppa:Linux:*:*)
+	# Look for CPU level
+	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+	  PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
+	  PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
+	  *)    echo hppa-unknown-linux-${LIBC} ;;
+	esac
+	exit ;;
+    ppc64:Linux:*:*)
+	echo powerpc64-unknown-linux-${LIBC}
+	exit ;;
+    ppc:Linux:*:*)
+	echo powerpc-unknown-linux-${LIBC}
+	exit ;;
+    ppc64le:Linux:*:*)
+	echo powerpc64le-unknown-linux-${LIBC}
+	exit ;;
+    ppcle:Linux:*:*)
+	echo powerpcle-unknown-linux-${LIBC}
+	exit ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+	echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
+	exit ;;
+    sh64*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    sh*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    tile*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    vax:Linux:*:*)
+	echo ${UNAME_MACHINE}-dec-linux-${LIBC}
+	exit ;;
+    x86_64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    xtensa*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    i*86:DYNIX/ptx:4*:*)
+	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+	# earlier versions are messed up and put the nodename in both
+	# sysname and nodename.
+	echo i386-sequent-sysv4
+	exit ;;
+    i*86:UNIX_SV:4.2MP:2.*)
+	# Unixware is an offshoot of SVR4, but it has its own version
+	# number series starting with 2...
+	# I am not positive that other SVR4 systems won't match this,
+	# I just have to hope.  -- rms.
+	# Use sysv4.2uw... so that sysv4* matches it.
+	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+	exit ;;
+    i*86:OS/2:*:*)
+	# If we were able to find `uname', then EMX Unix compatibility
+	# is probably installed.
+	echo ${UNAME_MACHINE}-pc-os2-emx
+	exit ;;
+    i*86:XTS-300:*:STOP)
+	echo ${UNAME_MACHINE}-unknown-stop
+	exit ;;
+    i*86:atheos:*:*)
+	echo ${UNAME_MACHINE}-unknown-atheos
+	exit ;;
+    i*86:syllable:*:*)
+	echo ${UNAME_MACHINE}-pc-syllable
+	exit ;;
+    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+	echo i386-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    i*86:*DOS:*:*)
+	echo ${UNAME_MACHINE}-pc-msdosdjgpp
+	exit ;;
+    i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+	UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+		echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+	else
+		echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+	fi
+	exit ;;
+    i*86:*:5:[678]*)
+	# UnixWare 7.x, OpenUNIX and OpenServer 6.
+	case `/bin/uname -X | grep "^Machine"` in
+	    *486*)	     UNAME_MACHINE=i486 ;;
+	    *Pentium)	     UNAME_MACHINE=i586 ;;
+	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+	esac
+	echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+	exit ;;
+    i*86:*:3.2:*)
+	if test -f /usr/options/cb.name; then
+		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+		echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+	elif /bin/uname -X 2>/dev/null >/dev/null ; then
+		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+		(/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+			&& UNAME_MACHINE=i586
+		(/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+			&& UNAME_MACHINE=i686
+		echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+	else
+		echo ${UNAME_MACHINE}-pc-sysv32
+	fi
+	exit ;;
+    pc:*:*:*)
+	# Left here for compatibility:
+	# uname -m prints for DJGPP always 'pc', but it prints nothing about
+	# the processor, so we play safe by assuming i586.
+	# Note: whatever this is, it MUST be the same as what config.sub
+	# prints for the "djgpp" host, or else GDB configury will decide that
+	# this is a cross-build.
+	echo i586-pc-msdosdjgpp
+	exit ;;
+    Intel:Mach:3*:*)
+	echo i386-pc-mach3
+	exit ;;
+    paragon:*:*:*)
+	echo i860-intel-osf1
+	exit ;;
+    i860:*:4.*:*) # i860-SVR4
+	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+	  echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+	else # Add other i860-SVR4 vendors below as they are discovered.
+	  echo i860-unknown-sysv${UNAME_RELEASE}  # Unknown i860-SVR4
+	fi
+	exit ;;
+    mini*:CTIX:SYS*5:*)
+	# "miniframe"
+	echo m68010-convergent-sysv
+	exit ;;
+    mc68k:UNIX:SYSTEM5:3.51m)
+	echo m68k-convergent-sysv
+	exit ;;
+    M680?0:D-NIX:5.3:*)
+	echo m68k-diab-dnix
+	exit ;;
+    M68*:*:R3V[5678]*:*)
+	test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+	OS_REL=''
+	test -r /etc/.relid \
+	&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	  && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4; exit; } ;;
+    NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+	OS_REL='.3'
+	test -r /etc/.relid \
+	    && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	    && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+	/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+	    && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+	echo m68k-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    mc68030:UNIX_System_V:4.*:*)
+	echo m68k-atari-sysv4
+	exit ;;
+    TSUNAMI:LynxOS:2.*:*)
+	echo sparc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    rs6000:LynxOS:2.*:*)
+	echo rs6000-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+	echo powerpc-unknown-lynxos${UNAME_RELEASE}
+	exit ;;
+    SM[BE]S:UNIX_SV:*:*)
+	echo mips-dde-sysv${UNAME_RELEASE}
+	exit ;;
+    RM*:ReliantUNIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    RM*:SINIX-*:*:*)
+	echo mips-sni-sysv4
+	exit ;;
+    *:SINIX-*:*:*)
+	if uname -p 2>/dev/null >/dev/null ; then
+		UNAME_MACHINE=`(uname -p) 2>/dev/null`
+		echo ${UNAME_MACHINE}-sni-sysv4
+	else
+		echo ns32k-sni-sysv
+	fi
+	exit ;;
+    PENTIUM:*:4.0*:*)	# Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+			# says <Richard.M.Bartel at ccMail.Census.GOV>
+	echo i586-unisys-sysv4
+	exit ;;
+    *:UNIX_System_V:4*:FTX*)
+	# From Gerald Hewes <hewes at openmarket.com>.
+	# How about differentiating between stratus architectures? -djm
+	echo hppa1.1-stratus-sysv4
+	exit ;;
+    *:*:*:FTX*)
+	# From seanf at swdc.stratus.com.
+	echo i860-stratus-sysv4
+	exit ;;
+    i*86:VOS:*:*)
+	# From Paul.Green at stratus.com.
+	echo ${UNAME_MACHINE}-stratus-vos
+	exit ;;
+    *:VOS:*:*)
+	# From Paul.Green at stratus.com.
+	echo hppa1.1-stratus-vos
+	exit ;;
+    mc68*:A/UX:*:*)
+	echo m68k-apple-aux${UNAME_RELEASE}
+	exit ;;
+    news*:NEWS-OS:6*:*)
+	echo mips-sony-newsos6
+	exit ;;
+    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+	if [ -d /usr/nec ]; then
+		echo mips-nec-sysv${UNAME_RELEASE}
+	else
+		echo mips-unknown-sysv${UNAME_RELEASE}
+	fi
+	exit ;;
+    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
+	echo powerpc-be-beos
+	exit ;;
+    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
+	echo powerpc-apple-beos
+	exit ;;
+    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
+	echo i586-pc-beos
+	exit ;;
+    BePC:Haiku:*:*)	# Haiku running on Intel PC compatible.
+	echo i586-pc-haiku
+	exit ;;
+    x86_64:Haiku:*:*)
+	echo x86_64-unknown-haiku
+	exit ;;
+    SX-4:SUPER-UX:*:*)
+	echo sx4-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-5:SUPER-UX:*:*)
+	echo sx5-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-6:SUPER-UX:*:*)
+	echo sx6-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-7:SUPER-UX:*:*)
+	echo sx7-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8:SUPER-UX:*:*)
+	echo sx8-nec-superux${UNAME_RELEASE}
+	exit ;;
+    SX-8R:SUPER-UX:*:*)
+	echo sx8r-nec-superux${UNAME_RELEASE}
+	exit ;;
+    Power*:Rhapsody:*:*)
+	echo powerpc-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Rhapsody:*:*)
+	echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+	exit ;;
+    *:Darwin:*:*)
+	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+	eval $set_cc_for_build
+	if test "$UNAME_PROCESSOR" = unknown ; then
+	    UNAME_PROCESSOR=powerpc
+	fi
+	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+	    if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		grep IS_64BIT_ARCH >/dev/null
+	    then
+		case $UNAME_PROCESSOR in
+		    i386) UNAME_PROCESSOR=x86_64 ;;
+		    powerpc) UNAME_PROCESSOR=powerpc64 ;;
+		esac
+	    fi
+	fi
+	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+	exit ;;
+    *:procnto*:*:* | *:QNX:[0123456789]*:*)
+	UNAME_PROCESSOR=`uname -p`
+	if test "$UNAME_PROCESSOR" = "x86"; then
+		UNAME_PROCESSOR=i386
+		UNAME_MACHINE=pc
+	fi
+	echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+	exit ;;
+    *:QNX:*:4*)
+	echo i386-pc-qnx
+	exit ;;
+    NEO-?:NONSTOP_KERNEL:*:*)
+	echo neo-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    NSE-*:NONSTOP_KERNEL:*:*)
+	echo nse-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    NSR-?:NONSTOP_KERNEL:*:*)
+	echo nsr-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    *:NonStop-UX:*:*)
+	echo mips-compaq-nonstopux
+	exit ;;
+    BS2000:POSIX*:*:*)
+	echo bs2000-siemens-sysv
+	exit ;;
+    DS/*:UNIX_System_V:*:*)
+	echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+	exit ;;
+    *:Plan9:*:*)
+	# "uname -m" is not consistent, so use $cputype instead. 386
+	# is converted to i386 for consistency with other x86
+	# operating systems.
+	if test "$cputype" = "386"; then
+	    UNAME_MACHINE=i386
+	else
+	    UNAME_MACHINE="$cputype"
+	fi
+	echo ${UNAME_MACHINE}-unknown-plan9
+	exit ;;
+    *:TOPS-10:*:*)
+	echo pdp10-unknown-tops10
+	exit ;;
+    *:TENEX:*:*)
+	echo pdp10-unknown-tenex
+	exit ;;
+    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+	echo pdp10-dec-tops20
+	exit ;;
+    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+	echo pdp10-xkl-tops20
+	exit ;;
+    *:TOPS-20:*:*)
+	echo pdp10-unknown-tops20
+	exit ;;
+    *:ITS:*:*)
+	echo pdp10-unknown-its
+	exit ;;
+    SEI:*:*:SEIUX)
+	echo mips-sei-seiux${UNAME_RELEASE}
+	exit ;;
+    *:DragonFly:*:*)
+	echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+	exit ;;
+    *:*VMS:*:*)
+	UNAME_MACHINE=`(uname -p) 2>/dev/null`
+	case "${UNAME_MACHINE}" in
+	    A*) echo alpha-dec-vms ; exit ;;
+	    I*) echo ia64-dec-vms ; exit ;;
+	    V*) echo vax-dec-vms ; exit ;;
+	esac ;;
+    *:XENIX:*:SysV)
+	echo i386-pc-xenix
+	exit ;;
+    i*86:skyos:*:*)
+	echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+	exit ;;
+    i*86:rdos:*:*)
+	echo ${UNAME_MACHINE}-pc-rdos
+	exit ;;
+    i*86:AROS:*:*)
+	echo ${UNAME_MACHINE}-pc-aros
+	exit ;;
+    x86_64:VMkernel:*:*)
+	echo ${UNAME_MACHINE}-unknown-esx
+	exit ;;
+esac
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+     I don't know....  */
+  printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+  printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+	"4"
+#else
+	""
+#endif
+	); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+  printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+  printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+  int version;
+  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+  if (version < 4)
+    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+  else
+    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+  exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+  printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+  printf ("ns32k-encore-mach\n"); exit (0);
+#else
+  printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+  printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+  printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+  printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+    struct utsname un;
+
+    uname(&un);
+
+    if (strncmp(un.version, "V2", 2) == 0) {
+	printf ("i386-sequent-ptx2\n"); exit (0);
+    }
+    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+	printf ("i386-sequent-ptx1\n"); exit (0);
+    }
+    printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+#  include <sys/param.h>
+#  if defined (BSD)
+#   if BSD == 43
+      printf ("vax-dec-bsd4.3\n"); exit (0);
+#   else
+#    if BSD == 199006
+      printf ("vax-dec-bsd4.3reno\n"); exit (0);
+#    else
+      printf ("vax-dec-bsd\n"); exit (0);
+#    endif
+#   endif
+#  else
+    printf ("vax-dec-bsd\n"); exit (0);
+#  endif
+# else
+    printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+  printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+  exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+	{ echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+    case `getsysinfo -f cpu_type` in
+    c1*)
+	echo c1-convex-bsd
+	exit ;;
+    c2*)
+	if getsysinfo -f scalar_acc
+	then echo c32-convex-bsd
+	else echo c2-convex-bsd
+	fi
+	exit ;;
+    c34*)
+	echo c34-convex-bsd
+	exit ;;
+    c38*)
+	echo c38-convex-bsd
+	exit ;;
+    c4*)
+	echo c4-convex-bsd
+	exit ;;
+    esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches at gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo               = `(hostinfo) 2>/dev/null`
+/bin/universe          = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch              = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM  = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/autostuff/config.sub b/autostuff/config.sub
new file mode 100755
index 0000000..9633db7
--- /dev/null
+++ b/autostuff/config.sub
@@ -0,0 +1,1791 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright 1992-2013 Free Software Foundation, Inc.
+
+timestamp='2013-08-10'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program.  This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+
+
+# Please send patches with a ChangeLog entry to config-patches at gnu.org.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support.  The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+#	CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+       $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+  -h, --help         print this help, then exit
+  -t, --time-stamp   print date of last modification, then exit
+  -v, --version      print version number, then exit
+
+Report bugs and patches to <config-patches at gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright 1992-2013 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+  case $1 in
+    --time-stamp | --time* | -t )
+       echo "$timestamp" ; exit ;;
+    --version | -v )
+       echo "$version" ; exit ;;
+    --help | --h* | -h )
+       echo "$usage"; exit ;;
+    -- )     # Stop option processing
+       shift; break ;;
+    - )	# Use stdin as input.
+       break ;;
+    -* )
+       echo "$me: invalid option $1$help"
+       exit 1 ;;
+
+    *local*)
+       # First pass through any local machine types.
+       echo $1
+       exit ;;
+
+    * )
+       break ;;
+  esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+    exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+    exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+  nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
+  linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+  knetbsd*-gnu* | netbsd*-gnu* | \
+  kopensolaris*-gnu* | \
+  storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  android-linux)
+    os=-linux-android
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
+    ;;
+  *)
+    basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+    if [ $basic_machine != $1 ]
+    then os=`echo $1 | sed 's/.*-/-/'`
+    else os=; fi
+    ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work.  We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+	-sun*os*)
+		# Prevent following clause from handling this invalid input.
+		;;
+	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+	-apple | -axis | -knuth | -cray | -microblaze*)
+		os=
+		basic_machine=$1
+		;;
+	-bluegene*)
+		os=-cnk
+		;;
+	-sim | -cisco | -oki | -wec | -winbond)
+		os=
+		basic_machine=$1
+		;;
+	-scout)
+		;;
+	-wrs)
+		os=-vxworks
+		basic_machine=$1
+		;;
+	-chorusos*)
+		os=-chorusos
+		basic_machine=$1
+		;;
+	-chorusrdb)
+		os=-chorusrdb
+		basic_machine=$1
+		;;
+	-hiux*)
+		os=-hiuxwe2
+		;;
+	-sco6)
+		os=-sco5v6
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5)
+		os=-sco3.2v5
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco4)
+		os=-sco3.2v4
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2.[4-9]*)
+		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco3.2v[4-9]*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco5v6*)
+		# Don't forget version if it is 3.2v4 or newer.
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-sco*)
+		os=-sco3.2v2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-udk*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-isc)
+		os=-isc2.2
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-clix*)
+		basic_machine=clipper-intergraph
+		;;
+	-isc*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+		;;
+	-lynx*178)
+		os=-lynxos178
+		;;
+	-lynx*5)
+		os=-lynxos5
+		;;
+	-lynx*)
+		os=-lynxos
+		;;
+	-ptx*)
+		basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+		;;
+	-windowsnt*)
+		os=`echo $os | sed -e 's/windowsnt/winnt/'`
+		;;
+	-psos*)
+		os=-psos
+		;;
+	-mint | -mint[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+	# Recognize the basic CPU types without company name.
+	# Some are omitted here because they have special meanings below.
+	1750a | 580 \
+	| a29k \
+	| aarch64 | aarch64_be \
+	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+	| am33_2.0 \
+	| arc | arceb \
+	| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
+	| avr | avr32 \
+	| be32 | be64 \
+	| bfin \
+	| c4x | c8051 | clipper \
+	| d10v | d30v | dlx | dsp16xx \
+	| epiphany \
+	| fido | fr30 | frv \
+	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+	| hexagon \
+	| i370 | i860 | i960 | ia64 \
+	| ip2k | iq2000 \
+	| le32 | le64 \
+	| lm32 \
+	| m32c | m32r | m32rle | m68000 | m68k | m88k \
+	| maxq | mb | microblaze | microblazeel | mcore | mep | metag \
+	| mips | mipsbe | mipseb | mipsel | mipsle \
+	| mips16 \
+	| mips64 | mips64el \
+	| mips64octeon | mips64octeonel \
+	| mips64orion | mips64orionel \
+	| mips64r5900 | mips64r5900el \
+	| mips64vr | mips64vrel \
+	| mips64vr4100 | mips64vr4100el \
+	| mips64vr4300 | mips64vr4300el \
+	| mips64vr5000 | mips64vr5000el \
+	| mips64vr5900 | mips64vr5900el \
+	| mipsisa32 | mipsisa32el \
+	| mipsisa32r2 | mipsisa32r2el \
+	| mipsisa64 | mipsisa64el \
+	| mipsisa64r2 | mipsisa64r2el \
+	| mipsisa64sb1 | mipsisa64sb1el \
+	| mipsisa64sr71k | mipsisa64sr71kel \
+	| mipsr5900 | mipsr5900el \
+	| mipstx39 | mipstx39el \
+	| mn10200 | mn10300 \
+	| moxie \
+	| mt \
+	| msp430 \
+	| nds32 | nds32le | nds32be \
+	| nios | nios2 | nios2eb | nios2el \
+	| ns16k | ns32k \
+	| open8 \
+	| or1k | or32 \
+	| pdp10 | pdp11 | pj | pjl \
+	| powerpc | powerpc64 | powerpc64le | powerpcle \
+	| pyramid \
+	| rl78 | rx \
+	| score \
+	| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+	| sh64 | sh64le \
+	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+	| spu \
+	| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
+	| ubicom32 \
+	| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
+	| we32k \
+	| x86 | xc16x | xstormy16 | xtensa \
+	| z8k | z80)
+		basic_machine=$basic_machine-unknown
+		;;
+	c54x)
+		basic_machine=tic54x-unknown
+		;;
+	c55x)
+		basic_machine=tic55x-unknown
+		;;
+	c6x)
+		basic_machine=tic6x-unknown
+		;;
+	m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip)
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+		;;
+	ms1)
+		basic_machine=mt-unknown
+		;;
+
+	strongarm | thumb | xscale)
+		basic_machine=arm-unknown
+		;;
+	xgate)
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	xscaleeb)
+		basic_machine=armeb-unknown
+		;;
+
+	xscaleel)
+		basic_machine=armel-unknown
+		;;
+
+	# We use `pc' rather than `unknown'
+	# because (1) that's what they normally are, and
+	# (2) the word "unknown" tends to confuse beginning users.
+	i*86 | x86_64)
+	  basic_machine=$basic_machine-pc
+	  ;;
+	# Object if more than one company name word.
+	*-*-*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+	# Recognize the basic CPU types with company name.
+	580-* \
+	| a29k-* \
+	| aarch64-* | aarch64_be-* \
+	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
+	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+	| avr-* | avr32-* \
+	| be32-* | be64-* \
+	| bfin-* | bs2000-* \
+	| c[123]* | c30-* | [cjt]90-* | c4x-* \
+	| c8051-* | clipper-* | craynv-* | cydra-* \
+	| d10v-* | d30v-* | dlx-* \
+	| elxsi-* \
+	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+	| h8300-* | h8500-* \
+	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+	| hexagon-* \
+	| i*86-* | i860-* | i960-* | ia64-* \
+	| ip2k-* | iq2000-* \
+	| le32-* | le64-* \
+	| lm32-* \
+	| m32c-* | m32r-* | m32rle-* \
+	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+	| m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
+	| microblaze-* | microblazeel-* \
+	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+	| mips16-* \
+	| mips64-* | mips64el-* \
+	| mips64octeon-* | mips64octeonel-* \
+	| mips64orion-* | mips64orionel-* \
+	| mips64r5900-* | mips64r5900el-* \
+	| mips64vr-* | mips64vrel-* \
+	| mips64vr4100-* | mips64vr4100el-* \
+	| mips64vr4300-* | mips64vr4300el-* \
+	| mips64vr5000-* | mips64vr5000el-* \
+	| mips64vr5900-* | mips64vr5900el-* \
+	| mipsisa32-* | mipsisa32el-* \
+	| mipsisa32r2-* | mipsisa32r2el-* \
+	| mipsisa64-* | mipsisa64el-* \
+	| mipsisa64r2-* | mipsisa64r2el-* \
+	| mipsisa64sb1-* | mipsisa64sb1el-* \
+	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
+	| mipsr5900-* | mipsr5900el-* \
+	| mipstx39-* | mipstx39el-* \
+	| mmix-* \
+	| mt-* \
+	| msp430-* \
+	| nds32-* | nds32le-* | nds32be-* \
+	| nios-* | nios2-* | nios2eb-* | nios2el-* \
+	| none-* | np1-* | ns16k-* | ns32k-* \
+	| open8-* \
+	| orion-* \
+	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
+	| pyramid-* \
+	| rl78-* | romp-* | rs6000-* | rx-* \
+	| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+	| sparclite-* \
+	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
+	| tahoe-* \
+	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+	| tile*-* \
+	| tron-* \
+	| ubicom32-* \
+	| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
+	| vax-* \
+	| we32k-* \
+	| x86-* | x86_64-* | xc16x-* | xps100-* \
+	| xstormy16-* | xtensa*-* \
+	| ymp-* \
+	| z8k-* | z80-*)
+		;;
+	# Recognize the basic CPU types without company name, with glob match.
+	xtensa*)
+		basic_machine=$basic_machine-unknown
+		;;
+	# Recognize the various machine names and aliases which stand
+	# for a CPU type and a company and sometimes even an OS.
+	386bsd)
+		basic_machine=i386-unknown
+		os=-bsd
+		;;
+	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+		basic_machine=m68000-att
+		;;
+	3b*)
+		basic_machine=we32k-att
+		;;
+	a29khif)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	abacus)
+		basic_machine=abacus-unknown
+		;;
+	adobe68k)
+		basic_machine=m68010-adobe
+		os=-scout
+		;;
+	alliant | fx80)
+		basic_machine=fx80-alliant
+		;;
+	altos | altos3068)
+		basic_machine=m68k-altos
+		;;
+	am29k)
+		basic_machine=a29k-none
+		os=-bsd
+		;;
+	amd64)
+		basic_machine=x86_64-pc
+		;;
+	amd64-*)
+		basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	amdahl)
+		basic_machine=580-amdahl
+		os=-sysv
+		;;
+	amiga | amiga-*)
+		basic_machine=m68k-unknown
+		;;
+	amigaos | amigados)
+		basic_machine=m68k-unknown
+		os=-amigaos
+		;;
+	amigaunix | amix)
+		basic_machine=m68k-unknown
+		os=-sysv4
+		;;
+	apollo68)
+		basic_machine=m68k-apollo
+		os=-sysv
+		;;
+	apollo68bsd)
+		basic_machine=m68k-apollo
+		os=-bsd
+		;;
+	aros)
+		basic_machine=i386-pc
+		os=-aros
+		;;
+	aux)
+		basic_machine=m68k-apple
+		os=-aux
+		;;
+	balance)
+		basic_machine=ns32k-sequent
+		os=-dynix
+		;;
+	blackfin)
+		basic_machine=bfin-unknown
+		os=-linux
+		;;
+	blackfin-*)
+		basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	bluegene*)
+		basic_machine=powerpc-ibm
+		os=-cnk
+		;;
+	c54x-*)
+		basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	c55x-*)
+		basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	c6x-*)
+		basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	c90)
+		basic_machine=c90-cray
+		os=-unicos
+		;;
+	cegcc)
+		basic_machine=arm-unknown
+		os=-cegcc
+		;;
+	convex-c1)
+		basic_machine=c1-convex
+		os=-bsd
+		;;
+	convex-c2)
+		basic_machine=c2-convex
+		os=-bsd
+		;;
+	convex-c32)
+		basic_machine=c32-convex
+		os=-bsd
+		;;
+	convex-c34)
+		basic_machine=c34-convex
+		os=-bsd
+		;;
+	convex-c38)
+		basic_machine=c38-convex
+		os=-bsd
+		;;
+	cray | j90)
+		basic_machine=j90-cray
+		os=-unicos
+		;;
+	craynv)
+		basic_machine=craynv-cray
+		os=-unicosmp
+		;;
+	cr16 | cr16-*)
+		basic_machine=cr16-unknown
+		os=-elf
+		;;
+	crds | unos)
+		basic_machine=m68k-crds
+		;;
+	crisv32 | crisv32-* | etraxfs*)
+		basic_machine=crisv32-axis
+		;;
+	cris | cris-* | etrax*)
+		basic_machine=cris-axis
+		;;
+	crx)
+		basic_machine=crx-unknown
+		os=-elf
+		;;
+	da30 | da30-*)
+		basic_machine=m68k-da30
+		;;
+	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+		basic_machine=mips-dec
+		;;
+	decsystem10* | dec10*)
+		basic_machine=pdp10-dec
+		os=-tops10
+		;;
+	decsystem20* | dec20*)
+		basic_machine=pdp10-dec
+		os=-tops20
+		;;
+	delta | 3300 | motorola-3300 | motorola-delta \
+	      | 3300-motorola | delta-motorola)
+		basic_machine=m68k-motorola
+		;;
+	delta88)
+		basic_machine=m88k-motorola
+		os=-sysv3
+		;;
+	dicos)
+		basic_machine=i686-pc
+		os=-dicos
+		;;
+	djgpp)
+		basic_machine=i586-pc
+		os=-msdosdjgpp
+		;;
+	dpx20 | dpx20-*)
+		basic_machine=rs6000-bull
+		os=-bosx
+		;;
+	dpx2* | dpx2*-bull)
+		basic_machine=m68k-bull
+		os=-sysv3
+		;;
+	ebmon29k)
+		basic_machine=a29k-amd
+		os=-ebmon
+		;;
+	elxsi)
+		basic_machine=elxsi-elxsi
+		os=-bsd
+		;;
+	encore | umax | mmax)
+		basic_machine=ns32k-encore
+		;;
+	es1800 | OSE68k | ose68k | ose | OSE)
+		basic_machine=m68k-ericsson
+		os=-ose
+		;;
+	fx2800)
+		basic_machine=i860-alliant
+		;;
+	genix)
+		basic_machine=ns32k-ns
+		;;
+	gmicro)
+		basic_machine=tron-gmicro
+		os=-sysv
+		;;
+	go32)
+		basic_machine=i386-pc
+		os=-go32
+		;;
+	h3050r* | hiux*)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	h8300hms)
+		basic_machine=h8300-hitachi
+		os=-hms
+		;;
+	h8300xray)
+		basic_machine=h8300-hitachi
+		os=-xray
+		;;
+	h8500hms)
+		basic_machine=h8500-hitachi
+		os=-hms
+		;;
+	harris)
+		basic_machine=m88k-harris
+		os=-sysv3
+		;;
+	hp300-*)
+		basic_machine=m68k-hp
+		;;
+	hp300bsd)
+		basic_machine=m68k-hp
+		os=-bsd
+		;;
+	hp300hpux)
+		basic_machine=m68k-hp
+		os=-hpux
+		;;
+	hp3k9[0-9][0-9] | hp9[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k2[0-9][0-9] | hp9k31[0-9])
+		basic_machine=m68000-hp
+		;;
+	hp9k3[2-9][0-9])
+		basic_machine=m68k-hp
+		;;
+	hp9k6[0-9][0-9] | hp6[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hp9k7[0-79][0-9] | hp7[0-79][0-9])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k78[0-9] | hp78[0-9])
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+		# FIXME: really hppa2.0-hp
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][13679] | hp8[0-9][13679])
+		basic_machine=hppa1.1-hp
+		;;
+	hp9k8[0-9][0-9] | hp8[0-9][0-9])
+		basic_machine=hppa1.0-hp
+		;;
+	hppa-next)
+		os=-nextstep3
+		;;
+	hppaosf)
+		basic_machine=hppa1.1-hp
+		os=-osf
+		;;
+	hppro)
+		basic_machine=hppa1.1-hp
+		os=-proelf
+		;;
+	i370-ibm* | ibm*)
+		basic_machine=i370-ibm
+		;;
+	i*86v32)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv32
+		;;
+	i*86v4*)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv4
+		;;
+	i*86v)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-sysv
+		;;
+	i*86sol2)
+		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+		os=-solaris2
+		;;
+	i386mach)
+		basic_machine=i386-mach
+		os=-mach
+		;;
+	i386-vsta | vsta)
+		basic_machine=i386-unknown
+		os=-vsta
+		;;
+	iris | iris4d)
+		basic_machine=mips-sgi
+		case $os in
+		    -irix*)
+			;;
+		    *)
+			os=-irix4
+			;;
+		esac
+		;;
+	isi68 | isi)
+		basic_machine=m68k-isi
+		os=-sysv
+		;;
+	m68knommu)
+		basic_machine=m68k-unknown
+		os=-linux
+		;;
+	m68knommu-*)
+		basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	m88k-omron*)
+		basic_machine=m88k-omron
+		;;
+	magnum | m3230)
+		basic_machine=mips-mips
+		os=-sysv
+		;;
+	merlin)
+		basic_machine=ns32k-utek
+		os=-sysv
+		;;
+	microblaze*)
+		basic_machine=microblaze-xilinx
+		;;
+	mingw64)
+		basic_machine=x86_64-pc
+		os=-mingw64
+		;;
+	mingw32)
+		basic_machine=i686-pc
+		os=-mingw32
+		;;
+	mingw32ce)
+		basic_machine=arm-unknown
+		os=-mingw32ce
+		;;
+	miniframe)
+		basic_machine=m68000-convergent
+		;;
+	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+		basic_machine=m68k-atari
+		os=-mint
+		;;
+	mips3*-*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+		;;
+	mips3*)
+		basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+		;;
+	monitor)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	morphos)
+		basic_machine=powerpc-unknown
+		os=-morphos
+		;;
+	msdos)
+		basic_machine=i386-pc
+		os=-msdos
+		;;
+	ms1-*)
+		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+		;;
+	msys)
+		basic_machine=i686-pc
+		os=-msys
+		;;
+	mvs)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+	nacl)
+		basic_machine=le32-unknown
+		os=-nacl
+		;;
+	ncr3000)
+		basic_machine=i486-ncr
+		os=-sysv4
+		;;
+	netbsd386)
+		basic_machine=i386-unknown
+		os=-netbsd
+		;;
+	netwinder)
+		basic_machine=armv4l-rebel
+		os=-linux
+		;;
+	news | news700 | news800 | news900)
+		basic_machine=m68k-sony
+		os=-newsos
+		;;
+	news1000)
+		basic_machine=m68030-sony
+		os=-newsos
+		;;
+	news-3600 | risc-news)
+		basic_machine=mips-sony
+		os=-newsos
+		;;
+	necv70)
+		basic_machine=v70-nec
+		os=-sysv
+		;;
+	next | m*-next )
+		basic_machine=m68k-next
+		case $os in
+		    -nextstep* )
+			;;
+		    -ns2*)
+		      os=-nextstep2
+			;;
+		    *)
+		      os=-nextstep3
+			;;
+		esac
+		;;
+	nh3000)
+		basic_machine=m68k-harris
+		os=-cxux
+		;;
+	nh[45]000)
+		basic_machine=m88k-harris
+		os=-cxux
+		;;
+	nindy960)
+		basic_machine=i960-intel
+		os=-nindy
+		;;
+	mon960)
+		basic_machine=i960-intel
+		os=-mon960
+		;;
+	nonstopux)
+		basic_machine=mips-compaq
+		os=-nonstopux
+		;;
+	np1)
+		basic_machine=np1-gould
+		;;
+	neo-tandem)
+		basic_machine=neo-tandem
+		;;
+	nse-tandem)
+		basic_machine=nse-tandem
+		;;
+	nsr-tandem)
+		basic_machine=nsr-tandem
+		;;
+	op50n-* | op60c-*)
+		basic_machine=hppa1.1-oki
+		os=-proelf
+		;;
+	openrisc | openrisc-*)
+		basic_machine=or32-unknown
+		;;
+	os400)
+		basic_machine=powerpc-ibm
+		os=-os400
+		;;
+	OSE68000 | ose68000)
+		basic_machine=m68000-ericsson
+		os=-ose
+		;;
+	os68k)
+		basic_machine=m68k-none
+		os=-os68k
+		;;
+	pa-hitachi)
+		basic_machine=hppa1.1-hitachi
+		os=-hiuxwe2
+		;;
+	paragon)
+		basic_machine=i860-intel
+		os=-osf
+		;;
+	parisc)
+		basic_machine=hppa-unknown
+		os=-linux
+		;;
+	parisc-*)
+		basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=-linux
+		;;
+	pbd)
+		basic_machine=sparc-tti
+		;;
+	pbb)
+		basic_machine=m68k-tti
+		;;
+	pc532 | pc532-*)
+		basic_machine=ns32k-pc532
+		;;
+	pc98)
+		basic_machine=i386-pc
+		;;
+	pc98-*)
+		basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium | p5 | k5 | k6 | nexgen | viac3)
+		basic_machine=i586-pc
+		;;
+	pentiumpro | p6 | 6x86 | athlon | athlon_*)
+		basic_machine=i686-pc
+		;;
+	pentiumii | pentium2 | pentiumiii | pentium3)
+		basic_machine=i686-pc
+		;;
+	pentium4)
+		basic_machine=i786-pc
+		;;
+	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+		basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumpro-* | p6-* | 6x86-* | athlon-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+		basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pentium4-*)
+		basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	pn)
+		basic_machine=pn-gould
+		;;
+	power)	basic_machine=power-ibm
+		;;
+	ppc | ppcbe)	basic_machine=powerpc-unknown
+		;;
+	ppc-* | ppcbe-*)
+		basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppcle | powerpclittle | ppc-le | powerpc-little)
+		basic_machine=powerpcle-unknown
+		;;
+	ppcle-* | powerpclittle-*)
+		basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64)	basic_machine=powerpc64-unknown
+		;;
+	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+		basic_machine=powerpc64le-unknown
+		;;
+	ppc64le-* | powerpc64little-*)
+		basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	ps2)
+		basic_machine=i386-ibm
+		;;
+	pw32)
+		basic_machine=i586-unknown
+		os=-pw32
+		;;
+	rdos | rdos64)
+		basic_machine=x86_64-pc
+		os=-rdos
+		;;
+	rdos32)
+		basic_machine=i386-pc
+		os=-rdos
+		;;
+	rom68k)
+		basic_machine=m68k-rom68k
+		os=-coff
+		;;
+	rm[46]00)
+		basic_machine=mips-siemens
+		;;
+	rtpc | rtpc-*)
+		basic_machine=romp-ibm
+		;;
+	s390 | s390-*)
+		basic_machine=s390-ibm
+		;;
+	s390x | s390x-*)
+		basic_machine=s390x-ibm
+		;;
+	sa29200)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	sb1)
+		basic_machine=mipsisa64sb1-unknown
+		;;
+	sb1el)
+		basic_machine=mipsisa64sb1el-unknown
+		;;
+	sde)
+		basic_machine=mipsisa32-sde
+		os=-elf
+		;;
+	sei)
+		basic_machine=mips-sei
+		os=-seiux
+		;;
+	sequent)
+		basic_machine=i386-sequent
+		;;
+	sh)
+		basic_machine=sh-hitachi
+		os=-hms
+		;;
+	sh5el)
+		basic_machine=sh5le-unknown
+		;;
+	sh64)
+		basic_machine=sh64-unknown
+		;;
+	sparclite-wrs | simso-wrs)
+		basic_machine=sparclite-wrs
+		os=-vxworks
+		;;
+	sps7)
+		basic_machine=m68k-bull
+		os=-sysv2
+		;;
+	spur)
+		basic_machine=spur-unknown
+		;;
+	st2000)
+		basic_machine=m68k-tandem
+		;;
+	stratus)
+		basic_machine=i860-stratus
+		os=-sysv4
+		;;
+	strongarm-* | thumb-*)
+		basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	sun2)
+		basic_machine=m68000-sun
+		;;
+	sun2os3)
+		basic_machine=m68000-sun
+		os=-sunos3
+		;;
+	sun2os4)
+		basic_machine=m68000-sun
+		os=-sunos4
+		;;
+	sun3os3)
+		basic_machine=m68k-sun
+		os=-sunos3
+		;;
+	sun3os4)
+		basic_machine=m68k-sun
+		os=-sunos4
+		;;
+	sun4os3)
+		basic_machine=sparc-sun
+		os=-sunos3
+		;;
+	sun4os4)
+		basic_machine=sparc-sun
+		os=-sunos4
+		;;
+	sun4sol2)
+		basic_machine=sparc-sun
+		os=-solaris2
+		;;
+	sun3 | sun3-*)
+		basic_machine=m68k-sun
+		;;
+	sun4)
+		basic_machine=sparc-sun
+		;;
+	sun386 | sun386i | roadrunner)
+		basic_machine=i386-sun
+		;;
+	sv1)
+		basic_machine=sv1-cray
+		os=-unicos
+		;;
+	symmetry)
+		basic_machine=i386-sequent
+		os=-dynix
+		;;
+	t3e)
+		basic_machine=alphaev5-cray
+		os=-unicos
+		;;
+	t90)
+		basic_machine=t90-cray
+		os=-unicos
+		;;
+	tile*)
+		basic_machine=$basic_machine-unknown
+		os=-linux-gnu
+		;;
+	tx39)
+		basic_machine=mipstx39-unknown
+		;;
+	tx39el)
+		basic_machine=mipstx39el-unknown
+		;;
+	toad1)
+		basic_machine=pdp10-xkl
+		os=-tops20
+		;;
+	tower | tower-32)
+		basic_machine=m68k-ncr
+		;;
+	tpf)
+		basic_machine=s390x-ibm
+		os=-tpf
+		;;
+	udi29k)
+		basic_machine=a29k-amd
+		os=-udi
+		;;
+	ultra3)
+		basic_machine=a29k-nyu
+		os=-sym1
+		;;
+	v810 | necv810)
+		basic_machine=v810-nec
+		os=-none
+		;;
+	vaxv)
+		basic_machine=vax-dec
+		os=-sysv
+		;;
+	vms)
+		basic_machine=vax-dec
+		os=-vms
+		;;
+	vpp*|vx|vx-*)
+		basic_machine=f301-fujitsu
+		;;
+	vxworks960)
+		basic_machine=i960-wrs
+		os=-vxworks
+		;;
+	vxworks68)
+		basic_machine=m68k-wrs
+		os=-vxworks
+		;;
+	vxworks29k)
+		basic_machine=a29k-wrs
+		os=-vxworks
+		;;
+	w65*)
+		basic_machine=w65-wdc
+		os=-none
+		;;
+	w89k-*)
+		basic_machine=hppa1.1-winbond
+		os=-proelf
+		;;
+	xbox)
+		basic_machine=i686-pc
+		os=-mingw32
+		;;
+	xps | xps100)
+		basic_machine=xps100-honeywell
+		;;
+	xscale-* | xscalee[bl]-*)
+		basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
+		;;
+	ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	z8k-*-coff)
+		basic_machine=z8k-unknown
+		os=-sim
+		;;
+	z80-*-coff)
+		basic_machine=z80-unknown
+		os=-sim
+		;;
+	none)
+		basic_machine=none-none
+		os=-none
+		;;
+
+# Here we handle the default manufacturer of certain CPU types.  It is in
+# some cases the only manufacturer, in others, it is the most popular.
+	w89k)
+		basic_machine=hppa1.1-winbond
+		;;
+	op50n)
+		basic_machine=hppa1.1-oki
+		;;
+	op60c)
+		basic_machine=hppa1.1-oki
+		;;
+	romp)
+		basic_machine=romp-ibm
+		;;
+	mmix)
+		basic_machine=mmix-knuth
+		;;
+	rs6000)
+		basic_machine=rs6000-ibm
+		;;
+	vax)
+		basic_machine=vax-dec
+		;;
+	pdp10)
+		# there are many clones, so DEC is not a safe bet
+		basic_machine=pdp10-unknown
+		;;
+	pdp11)
+		basic_machine=pdp11-dec
+		;;
+	we32k)
+		basic_machine=we32k-att
+		;;
+	sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+		basic_machine=sh-unknown
+		;;
+	sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+		basic_machine=sparc-sun
+		;;
+	cydra)
+		basic_machine=cydra-cydrome
+		;;
+	orion)
+		basic_machine=orion-highlevel
+		;;
+	orion105)
+		basic_machine=clipper-highlevel
+		;;
+	mac | mpw | mac-mpw)
+		basic_machine=m68k-apple
+		;;
+	pmac | pmac-mpw)
+		basic_machine=powerpc-apple
+		;;
+	*-unknown)
+		# Make sure to match an already-canonicalized machine name.
+		;;
+	*)
+		echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+		exit 1
+		;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+	*-digital*)
+		basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+		;;
+	*-commodore*)
+		basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+		;;
+	*)
+		;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+	# First match some system type aliases
+	# that might get confused with valid system types.
+	# -solaris* is a basic system type, with this one exception.
+	-auroraux)
+		os=-auroraux
+		;;
+	-solaris1 | -solaris1.*)
+		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+		;;
+	-solaris)
+		os=-solaris2
+		;;
+	-svr4*)
+		os=-sysv4
+		;;
+	-unixware*)
+		os=-sysv4.2uw
+		;;
+	-gnu/linux*)
+		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+		;;
+	# First accept the basic system types.
+	# The portable systems comes first.
+	# Each alternative MUST END IN A *, to match a version number.
+	# -sysv* is not here because it comes later, after sysvr4.
+	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+	      | -sym* | -kopensolaris* | -plan9* \
+	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+	      | -aos* | -aros* \
+	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+	      | -bitrig* | -openbsd* | -solidbsd* \
+	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+	      | -chorusos* | -chorusrdb* | -cegcc* \
+	      | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+	      | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
+	      | -linux-newlib* | -linux-musl* | -linux-uclibc* \
+	      | -uxpv* | -beos* | -mpeix* | -udk* \
+	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
+	# Remember, each alternative MUST END IN *, to match a version number.
+		;;
+	-qnx*)
+		case $basic_machine in
+		    x86-* | i*86-*)
+			;;
+		    *)
+			os=-nto$os
+			;;
+		esac
+		;;
+	-nto-qnx*)
+		;;
+	-nto*)
+		os=`echo $os | sed -e 's|nto|nto-qnx|'`
+		;;
+	-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+	      | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+		;;
+	-mac*)
+		os=`echo $os | sed -e 's|mac|macos|'`
+		;;
+	-linux-dietlibc)
+		os=-linux-dietlibc
+		;;
+	-linux*)
+		os=`echo $os | sed -e 's|linux|linux-gnu|'`
+		;;
+	-sunos5*)
+		os=`echo $os | sed -e 's|sunos5|solaris2|'`
+		;;
+	-sunos6*)
+		os=`echo $os | sed -e 's|sunos6|solaris3|'`
+		;;
+	-opened*)
+		os=-openedition
+		;;
+	-os400*)
+		os=-os400
+		;;
+	-wince*)
+		os=-wince
+		;;
+	-osfrose*)
+		os=-osfrose
+		;;
+	-osf*)
+		os=-osf
+		;;
+	-utek*)
+		os=-bsd
+		;;
+	-dynix*)
+		os=-bsd
+		;;
+	-acis*)
+		os=-aos
+		;;
+	-atheos*)
+		os=-atheos
+		;;
+	-syllable*)
+		os=-syllable
+		;;
+	-386bsd)
+		os=-bsd
+		;;
+	-ctix* | -uts*)
+		os=-sysv
+		;;
+	-nova*)
+		os=-rtmk-nova
+		;;
+	-ns2 )
+		os=-nextstep2
+		;;
+	-nsk*)
+		os=-nsk
+		;;
+	# Preserve the version number of sinix5.
+	-sinix5.*)
+		os=`echo $os | sed -e 's|sinix|sysv|'`
+		;;
+	-sinix*)
+		os=-sysv4
+		;;
+	-tpf*)
+		os=-tpf
+		;;
+	-triton*)
+		os=-sysv3
+		;;
+	-oss*)
+		os=-sysv3
+		;;
+	-svr4)
+		os=-sysv4
+		;;
+	-svr3)
+		os=-sysv3
+		;;
+	-sysvr4)
+		os=-sysv4
+		;;
+	# This must come after -sysvr4.
+	-sysv*)
+		;;
+	-ose*)
+		os=-ose
+		;;
+	-es1800*)
+		os=-ose
+		;;
+	-xenix)
+		os=-xenix
+		;;
+	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+		os=-mint
+		;;
+	-aros*)
+		os=-aros
+		;;
+	-zvmoe)
+		os=-zvmoe
+		;;
+	-dicos*)
+		os=-dicos
+		;;
+	-nacl*)
+		;;
+	-none)
+		;;
+	*)
+		# Get rid of the `-' at the beginning of $os.
+		os=`echo $os | sed 's/[^-]*-//'`
+		echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+		exit 1
+		;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system.  Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+	score-*)
+		os=-elf
+		;;
+	spu-*)
+		os=-elf
+		;;
+	*-acorn)
+		os=-riscix1.2
+		;;
+	arm*-rebel)
+		os=-linux
+		;;
+	arm*-semi)
+		os=-aout
+		;;
+	c4x-* | tic4x-*)
+		os=-coff
+		;;
+	c8051-*)
+		os=-elf
+		;;
+	hexagon-*)
+		os=-elf
+		;;
+	tic54x-*)
+		os=-coff
+		;;
+	tic55x-*)
+		os=-coff
+		;;
+	tic6x-*)
+		os=-coff
+		;;
+	# This must come before the *-dec entry.
+	pdp10-*)
+		os=-tops20
+		;;
+	pdp11-*)
+		os=-none
+		;;
+	*-dec | vax-*)
+		os=-ultrix4.2
+		;;
+	m68*-apollo)
+		os=-domain
+		;;
+	i386-sun)
+		os=-sunos4.0.2
+		;;
+	m68000-sun)
+		os=-sunos3
+		;;
+	m68*-cisco)
+		os=-aout
+		;;
+	mep-*)
+		os=-elf
+		;;
+	mips*-cisco)
+		os=-elf
+		;;
+	mips*-*)
+		os=-elf
+		;;
+	or1k-*)
+		os=-elf
+		;;
+	or32-*)
+		os=-coff
+		;;
+	*-tti)	# must be before sparc entry or we get the wrong os.
+		os=-sysv3
+		;;
+	sparc-* | *-sun)
+		os=-sunos4.1.1
+		;;
+	*-be)
+		os=-beos
+		;;
+	*-haiku)
+		os=-haiku
+		;;
+	*-ibm)
+		os=-aix
+		;;
+	*-knuth)
+		os=-mmixware
+		;;
+	*-wec)
+		os=-proelf
+		;;
+	*-winbond)
+		os=-proelf
+		;;
+	*-oki)
+		os=-proelf
+		;;
+	*-hp)
+		os=-hpux
+		;;
+	*-hitachi)
+		os=-hiux
+		;;
+	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+		os=-sysv
+		;;
+	*-cbm)
+		os=-amigaos
+		;;
+	*-dg)
+		os=-dgux
+		;;
+	*-dolphin)
+		os=-sysv3
+		;;
+	m68k-ccur)
+		os=-rtu
+		;;
+	m88k-omron*)
+		os=-luna
+		;;
+	*-next )
+		os=-nextstep
+		;;
+	*-sequent)
+		os=-ptx
+		;;
+	*-crds)
+		os=-unos
+		;;
+	*-ns)
+		os=-genix
+		;;
+	i370-*)
+		os=-mvs
+		;;
+	*-next)
+		os=-nextstep3
+		;;
+	*-gould)
+		os=-sysv
+		;;
+	*-highlevel)
+		os=-bsd
+		;;
+	*-encore)
+		os=-bsd
+		;;
+	*-sgi)
+		os=-irix
+		;;
+	*-siemens)
+		os=-sysv4
+		;;
+	*-masscomp)
+		os=-rtu
+		;;
+	f30[01]-fujitsu | f700-fujitsu)
+		os=-uxpv
+		;;
+	*-rom68k)
+		os=-coff
+		;;
+	*-*bug)
+		os=-coff
+		;;
+	*-apple)
+		os=-macos
+		;;
+	*-atari*)
+		os=-mint
+		;;
+	*)
+		os=-none
+		;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer.  We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+	*-unknown)
+		case $os in
+			-riscix*)
+				vendor=acorn
+				;;
+			-sunos*)
+				vendor=sun
+				;;
+			-cnk*|-aix*)
+				vendor=ibm
+				;;
+			-beos*)
+				vendor=be
+				;;
+			-hpux*)
+				vendor=hp
+				;;
+			-mpeix*)
+				vendor=hp
+				;;
+			-hiux*)
+				vendor=hitachi
+				;;
+			-unos*)
+				vendor=crds
+				;;
+			-dgux*)
+				vendor=dg
+				;;
+			-luna*)
+				vendor=omron
+				;;
+			-genix*)
+				vendor=ns
+				;;
+			-mvs* | -opened*)
+				vendor=ibm
+				;;
+			-os400*)
+				vendor=ibm
+				;;
+			-ptx*)
+				vendor=sequent
+				;;
+			-tpf*)
+				vendor=ibm
+				;;
+			-vxsim* | -vxworks* | -windiss*)
+				vendor=wrs
+				;;
+			-aux*)
+				vendor=apple
+				;;
+			-hms*)
+				vendor=hitachi
+				;;
+			-mpw* | -macos*)
+				vendor=apple
+				;;
+			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+				vendor=atari
+				;;
+			-vos*)
+				vendor=stratus
+				;;
+		esac
+		basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+		;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/autostuff/depcomp b/autostuff/depcomp
new file mode 100755
index 0000000..4ebd5b3
--- /dev/null
+++ b/autostuff/depcomp
@@ -0,0 +1,791 @@
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2013-05-30.07; # UTC
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva at dcc.unicamp.br>.
+
+case $1 in
+  '')
+    echo "$0: No command.  Try '$0 --help' for more information." 1>&2
+    exit 1;
+    ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+  depmode     Dependency tracking mode.
+  source      Source file read by 'PROGRAMS ARGS'.
+  object      Object file output by 'PROGRAMS ARGS'.
+  DEPDIR      directory where to store dependencies.
+  depfile     Dependency file to output.
+  tmpdepfile  Temporary file to use when outputting dependencies.
+  libtool     Whether libtool is used (yes/no).
+
+Report bugs to <bug-automake at gnu.org>.
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "depcomp $scriptversion"
+    exit $?
+    ;;
+esac
+
+# Get the directory component of the given path, and save it in the
+# global variables '$dir'.  Note that this directory component will
+# be either empty or ending with a '/' character.  This is deliberate.
+set_dir_from ()
+{
+  case $1 in
+    */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
+      *) dir=;;
+  esac
+}
+
+# Get the suffix-stripped basename of the given path, and save it the
+# global variable '$base'.
+set_base_from ()
+{
+  base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
+}
+
+# If no dependency file was actually created by the compiler invocation,
+# we still have to create a dummy depfile, to avoid errors with the
+# Makefile "include basename.Plo" scheme.
+make_dummy_depfile ()
+{
+  echo "#dummy" > "$depfile"
+}
+
+# Factor out some common post-processing of the generated depfile.
+# Requires the auxiliary global variable '$tmpdepfile' to be set.
+aix_post_process_depfile ()
+{
+  # If the compiler actually managed to produce a dependency file,
+  # post-process it.
+  if test -f "$tmpdepfile"; then
+    # Each line is of the form 'foo.o: dependency.h'.
+    # Do two passes, one to just change these to
+    #   $object: dependency.h
+    # and one to simply output
+    #   dependency.h:
+    # which is needed to avoid the deleted-header problem.
+    { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
+      sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
+    } > "$depfile"
+    rm -f "$tmpdepfile"
+  else
+    make_dummy_depfile
+  fi
+}
+
+# A tabulation character.
+tab='	'
+# A newline character.
+nl='
+'
+# Character ranges might be problematic outside the C locale.
+# These definitions help.
+upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
+lower=abcdefghijklmnopqrstuvwxyz
+digits=0123456789
+alpha=${upper}${lower}
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+  echo "depcomp: Variables source, object and depmode must be set" 1>&2
+  exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+  sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Avoid interferences from the environment.
+gccflag= dashmflag=
+
+# Some modes work just like other modes, but use different flags.  We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write.  Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+  # HP compiler uses -M and no extra arg.
+  gccflag=-M
+  depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+  # This is just like dashmstdout with a different argument.
+  dashmflag=-xM
+  depmode=dashmstdout
+fi
+
+cygpath_u="cygpath -u -f -"
+if test "$depmode" = msvcmsys; then
+  # This is just like msvisualcpp but w/o cygpath translation.
+  # Just convert the backslash-escaped backslashes to single forward
+  # slashes to satisfy depend.m4
+  cygpath_u='sed s,\\\\,/,g'
+  depmode=msvisualcpp
+fi
+
+if test "$depmode" = msvc7msys; then
+  # This is just like msvc7 but w/o cygpath translation.
+  # Just convert the backslash-escaped backslashes to single forward
+  # slashes to satisfy depend.m4
+  cygpath_u='sed s,\\\\,/,g'
+  depmode=msvc7
+fi
+
+if test "$depmode" = xlc; then
+  # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
+  gccflag=-qmakedep=gcc,-MF
+  depmode=gcc
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want.  Yay!  Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff.  Hmm.
+## Unfortunately, FreeBSD c89 acceptance of flags depends upon
+## the command line argument order; so add the flags where they
+## appear in depend2.am.  Note that the slowdown incurred here
+## affects only configure: in makefiles, %FASTDEP% shortcuts this.
+  for arg
+  do
+    case $arg in
+    -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
+    *)  set fnord "$@" "$arg" ;;
+    esac
+    shift # fnord
+    shift # $arg
+  done
+  "$@"
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  mv "$tmpdepfile" "$depfile"
+  ;;
+
+gcc)
+## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
+## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
+## (see the conditional assignment to $gccflag above).
+## There are various ways to get dependency output from gcc.  Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+##   up in a subdir.  Having to rename by hand is ugly.
+##   (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+##   -MM, not -M (despite what the docs say).  Also, it might not be
+##   supported by the other compilers which use the 'gcc' depmode.
+## - Using -M directly means running the compiler twice (even worse
+##   than renaming).
+  if test -z "$gccflag"; then
+    gccflag=-MD,
+  fi
+  "$@" -Wp,"$gccflag$tmpdepfile"
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  # The second -e expression handles DOS-style file names with drive
+  # letters.
+  sed -e 's/^[^:]*: / /' \
+      -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the "deleted header file" problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header).  We avoid this by adding
+## dummy dependencies for each header file.  Too bad gcc doesn't do
+## this for us directly.
+## Some versions of gcc put a space before the ':'.  On the theory
+## that the space means something, we add a space to the output as
+## well.  hp depmode also adds that space, but also prefixes the VPATH
+## to the object.  Take care to not repeat it in the output.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly.  Breaking it into two sed invocations is a workaround.
+  tr ' ' "$nl" < "$tmpdepfile" \
+    | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
+    | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+hp)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+sgi)
+  if test "$libtool" = yes; then
+    "$@" "-Wp,-MDupdate,$tmpdepfile"
+  else
+    "$@" -MDupdate "$tmpdepfile"
+  fi
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+
+  if test -f "$tmpdepfile"; then  # yes, the sourcefile depend on other files
+    echo "$object : \\" > "$depfile"
+    # Clip off the initial element (the dependent).  Don't try to be
+    # clever and replace this with sed code, as IRIX sed won't handle
+    # lines with more than a fixed number of characters (4096 in
+    # IRIX 6.2 sed, 8192 in IRIX 6.5).  We also remove comment lines;
+    # the IRIX cc adds comments like '#:fec' to the end of the
+    # dependency line.
+    tr ' ' "$nl" < "$tmpdepfile" \
+      | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
+      | tr "$nl" ' ' >> "$depfile"
+    echo >> "$depfile"
+    # The second pass generates a dummy entry for each header file.
+    tr ' ' "$nl" < "$tmpdepfile" \
+      | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+      >> "$depfile"
+  else
+    make_dummy_depfile
+  fi
+  rm -f "$tmpdepfile"
+  ;;
+
+xlc)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+aix)
+  # The C for AIX Compiler uses -M and outputs the dependencies
+  # in a .u file.  In older versions, this file always lives in the
+  # current directory.  Also, the AIX compiler puts '$object:' at the
+  # start of each line; $object doesn't have directory information.
+  # Version 6 uses the directory in both cases.
+  set_dir_from "$object"
+  set_base_from "$object"
+  if test "$libtool" = yes; then
+    tmpdepfile1=$dir$base.u
+    tmpdepfile2=$base.u
+    tmpdepfile3=$dir.libs/$base.u
+    "$@" -Wc,-M
+  else
+    tmpdepfile1=$dir$base.u
+    tmpdepfile2=$dir$base.u
+    tmpdepfile3=$dir$base.u
+    "$@" -M
+  fi
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+    exit $stat
+  fi
+
+  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+  do
+    test -f "$tmpdepfile" && break
+  done
+  aix_post_process_depfile
+  ;;
+
+tcc)
+  # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
+  # FIXME: That version still under development at the moment of writing.
+  #        Make that this statement remains true also for stable, released
+  #        versions.
+  # It will wrap lines (doesn't matter whether long or short) with a
+  # trailing '\', as in:
+  #
+  #   foo.o : \
+  #    foo.c \
+  #    foo.h \
+  #
+  # It will put a trailing '\' even on the last line, and will use leading
+  # spaces rather than leading tabs (at least since its commit 0394caf7
+  # "Emit spaces for -MD").
+  "$@" -MD -MF "$tmpdepfile"
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
+  # We have to change lines of the first kind to '$object: \'.
+  sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
+  # And for each line of the second kind, we have to emit a 'dep.h:'
+  # dummy dependency, to avoid the deleted-header problem.
+  sed -n -e 's|^  *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+## The order of this option in the case statement is important, since the
+## shell code in configure will try each of these formats in the order
+## listed in this file.  A plain '-MD' option would be understood by many
+## compilers, so we must ensure this comes after the gcc and icc options.
+pgcc)
+  # Portland's C compiler understands '-MD'.
+  # Will always output deps to 'file.d' where file is the root name of the
+  # source file under compilation, even if file resides in a subdirectory.
+  # The object file name does not affect the name of the '.d' file.
+  # pgcc 10.2 will output
+  #    foo.o: sub/foo.c sub/foo.h
+  # and will wrap long lines using '\' :
+  #    foo.o: sub/foo.c ... \
+  #     sub/foo.h ... \
+  #     ...
+  set_dir_from "$object"
+  # Use the source, not the object, to determine the base name, since
+  # that's sadly what pgcc will do too.
+  set_base_from "$source"
+  tmpdepfile=$base.d
+
+  # For projects that build the same source file twice into different object
+  # files, the pgcc approach of using the *source* file root name can cause
+  # problems in parallel builds.  Use a locking strategy to avoid stomping on
+  # the same $tmpdepfile.
+  lockdir=$base.d-lock
+  trap "
+    echo '$0: caught signal, cleaning up...' >&2
+    rmdir '$lockdir'
+    exit 1
+  " 1 2 13 15
+  numtries=100
+  i=$numtries
+  while test $i -gt 0; do
+    # mkdir is a portable test-and-set.
+    if mkdir "$lockdir" 2>/dev/null; then
+      # This process acquired the lock.
+      "$@" -MD
+      stat=$?
+      # Release the lock.
+      rmdir "$lockdir"
+      break
+    else
+      # If the lock is being held by a different process, wait
+      # until the winning process is done or we timeout.
+      while test -d "$lockdir" && test $i -gt 0; do
+        sleep 1
+        i=`expr $i - 1`
+      done
+    fi
+    i=`expr $i - 1`
+  done
+  trap - 1 2 13 15
+  if test $i -le 0; then
+    echo "$0: failed to acquire lock after $numtries attempts" >&2
+    echo "$0: check lockdir '$lockdir'" >&2
+    exit 1
+  fi
+
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  # Each line is of the form `foo.o: dependent.h',
+  # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+  # Do two passes, one to just change these to
+  # `$object: dependent.h' and one to simply `dependent.h:'.
+  sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+  # Some versions of the HPUX 10.20 sed can't process this invocation
+  # correctly.  Breaking it into two sed invocations is a workaround.
+  sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
+    | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+hp2)
+  # The "hp" stanza above does not work with aCC (C++) and HP's ia64
+  # compilers, which have integrated preprocessors.  The correct option
+  # to use with these is +Maked; it writes dependencies to a file named
+  # 'foo.d', which lands next to the object file, wherever that
+  # happens to be.
+  # Much of this is similar to the tru64 case; see comments there.
+  set_dir_from  "$object"
+  set_base_from "$object"
+  if test "$libtool" = yes; then
+    tmpdepfile1=$dir$base.d
+    tmpdepfile2=$dir.libs/$base.d
+    "$@" -Wc,+Maked
+  else
+    tmpdepfile1=$dir$base.d
+    tmpdepfile2=$dir$base.d
+    "$@" +Maked
+  fi
+  stat=$?
+  if test $stat -ne 0; then
+     rm -f "$tmpdepfile1" "$tmpdepfile2"
+     exit $stat
+  fi
+
+  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
+  do
+    test -f "$tmpdepfile" && break
+  done
+  if test -f "$tmpdepfile"; then
+    sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
+    # Add 'dependent.h:' lines.
+    sed -ne '2,${
+               s/^ *//
+               s/ \\*$//
+               s/$/:/
+               p
+             }' "$tmpdepfile" >> "$depfile"
+  else
+    make_dummy_depfile
+  fi
+  rm -f "$tmpdepfile" "$tmpdepfile2"
+  ;;
+
+tru64)
+  # The Tru64 compiler uses -MD to generate dependencies as a side
+  # effect.  'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
+  # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+  # dependencies in 'foo.d' instead, so we check for that too.
+  # Subdirectories are respected.
+  set_dir_from  "$object"
+  set_base_from "$object"
+
+  if test "$libtool" = yes; then
+    # Libtool generates 2 separate objects for the 2 libraries.  These
+    # two compilations output dependencies in $dir.libs/$base.o.d and
+    # in $dir$base.o.d.  We have to check for both files, because
+    # one of the two compilations can be disabled.  We should prefer
+    # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+    # automatically cleaned when .libs/ is deleted, while ignoring
+    # the former would cause a distcleancheck panic.
+    tmpdepfile1=$dir$base.o.d          # libtool 1.5
+    tmpdepfile2=$dir.libs/$base.o.d    # Likewise.
+    tmpdepfile3=$dir.libs/$base.d      # Compaq CCC V6.2-504
+    "$@" -Wc,-MD
+  else
+    tmpdepfile1=$dir$base.d
+    tmpdepfile2=$dir$base.d
+    tmpdepfile3=$dir$base.d
+    "$@" -MD
+  fi
+
+  stat=$?
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+    exit $stat
+  fi
+
+  for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+  do
+    test -f "$tmpdepfile" && break
+  done
+  # Same post-processing that is required for AIX mode.
+  aix_post_process_depfile
+  ;;
+
+msvc7)
+  if test "$libtool" = yes; then
+    showIncludes=-Wc,-showIncludes
+  else
+    showIncludes=-showIncludes
+  fi
+  "$@" $showIncludes > "$tmpdepfile"
+  stat=$?
+  grep -v '^Note: including file: ' "$tmpdepfile"
+  if test $stat -ne 0; then
+    rm -f "$tmpdepfile"
+    exit $stat
+  fi
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  # The first sed program below extracts the file names and escapes
+  # backslashes for cygpath.  The second sed program outputs the file
+  # name when reading, but also accumulates all include files in the
+  # hold buffer in order to output them again at the end.  This only
+  # works with sed implementations that can handle large buffers.
+  sed < "$tmpdepfile" -n '
+/^Note: including file:  *\(.*\)/ {
+  s//\1/
+  s/\\/\\\\/g
+  p
+}' | $cygpath_u | sort -u | sed -n '
+s/ /\\ /g
+s/\(.*\)/'"$tab"'\1 \\/p
+s/.\(.*\) \\/\1:/
+H
+$ {
+  s/.*/'"$tab"'/
+  G
+  p
+}' >> "$depfile"
+  echo >> "$depfile" # make sure the fragment doesn't end with a backslash
+  rm -f "$tmpdepfile"
+  ;;
+
+msvc7msys)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+#nosideeffect)
+  # This comment above is used by automake to tell side-effect
+  # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout, regardless of -o.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  # Remove '-o $object'.
+  IFS=" "
+  for arg
+  do
+    case $arg in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    *)
+      set fnord "$@" "$arg"
+      shift # fnord
+      shift # $arg
+      ;;
+    esac
+  done
+
+  test -z "$dashmflag" && dashmflag=-M
+  # Require at least two characters before searching for ':'
+  # in the target name.  This is to cope with DOS-style filenames:
+  # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
+  "$@" $dashmflag |
+    sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
+  rm -f "$depfile"
+  cat < "$tmpdepfile" > "$depfile"
+  # Some versions of the HPUX 10.20 sed can't process this sed invocation
+  # correctly.  Breaking it into two sed invocations is a workaround.
+  tr ' ' "$nl" < "$tmpdepfile" \
+    | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
+    | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+dashXmstdout)
+  # This case only exists to satisfy depend.m4.  It is never actually
+  # run, as this mode is specially recognized in the preamble.
+  exit 1
+  ;;
+
+makedepend)
+  "$@" || exit $?
+  # Remove any Libtool call
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+  # X makedepend
+  shift
+  cleared=no eat=no
+  for arg
+  do
+    case $cleared in
+    no)
+      set ""; shift
+      cleared=yes ;;
+    esac
+    if test $eat = yes; then
+      eat=no
+      continue
+    fi
+    case "$arg" in
+    -D*|-I*)
+      set fnord "$@" "$arg"; shift ;;
+    # Strip any option that makedepend may not understand.  Remove
+    # the object too, otherwise makedepend will parse it as a source file.
+    -arch)
+      eat=yes ;;
+    -*|$object)
+      ;;
+    *)
+      set fnord "$@" "$arg"; shift ;;
+    esac
+  done
+  obj_suffix=`echo "$object" | sed 's/^.*\././'`
+  touch "$tmpdepfile"
+  ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+  rm -f "$depfile"
+  # makedepend may prepend the VPATH from the source file name to the object.
+  # No need to regex-escape $object, excess matching of '.' is harmless.
+  sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
+  # Some versions of the HPUX 10.20 sed can't process the last invocation
+  # correctly.  Breaking it into two sed invocations is a workaround.
+  sed '1,2d' "$tmpdepfile" \
+    | tr ' ' "$nl" \
+    | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
+    | sed -e 's/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile" "$tmpdepfile".bak
+  ;;
+
+cpp)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  # Remove '-o $object'.
+  IFS=" "
+  for arg
+  do
+    case $arg in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    *)
+      set fnord "$@" "$arg"
+      shift # fnord
+      shift # $arg
+      ;;
+    esac
+  done
+
+  "$@" -E \
+    | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+             -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+    | sed '$ s: \\$::' > "$tmpdepfile"
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  cat < "$tmpdepfile" >> "$depfile"
+  sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+msvisualcpp)
+  # Important note: in order to support this mode, a compiler *must*
+  # always write the preprocessed file to stdout.
+  "$@" || exit $?
+
+  # Remove the call to Libtool.
+  if test "$libtool" = yes; then
+    while test "X$1" != 'X--mode=compile'; do
+      shift
+    done
+    shift
+  fi
+
+  IFS=" "
+  for arg
+  do
+    case "$arg" in
+    -o)
+      shift
+      ;;
+    $object)
+      shift
+      ;;
+    "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+        set fnord "$@"
+        shift
+        shift
+        ;;
+    *)
+        set fnord "$@" "$arg"
+        shift
+        shift
+        ;;
+    esac
+  done
+  "$@" -E 2>/dev/null |
+  sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
+  rm -f "$depfile"
+  echo "$object : \\" > "$depfile"
+  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
+  echo "$tab" >> "$depfile"
+  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+  rm -f "$tmpdepfile"
+  ;;
+
+msvcmsys)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
+none)
+  exec "$@"
+  ;;
+
+*)
+  echo "Unknown depmode $depmode" 1>&2
+  exit 1
+  ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/autostuff/install-sh b/autostuff/install-sh
new file mode 100755
index 0000000..377bb86
--- /dev/null
+++ b/autostuff/install-sh
@@ -0,0 +1,527 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2011-11-20.07; # UTC
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# 'make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+nl='
+'
+IFS=" ""	$nl"
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit=${DOITPROG-}
+if test -z "$doit"; then
+  doit_exec=exec
+else
+  doit_exec=$doit
+fi
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+chgrpprog=${CHGRPPROG-chgrp}
+chmodprog=${CHMODPROG-chmod}
+chownprog=${CHOWNPROG-chown}
+cmpprog=${CMPPROG-cmp}
+cpprog=${CPPROG-cp}
+mkdirprog=${MKDIRPROG-mkdir}
+mvprog=${MVPROG-mv}
+rmprog=${RMPROG-rm}
+stripprog=${STRIPPROG-strip}
+
+posix_glob='?'
+initialize_posix_glob='
+  test "$posix_glob" != "?" || {
+    if (set -f) 2>/dev/null; then
+      posix_glob=
+    else
+      posix_glob=:
+    fi
+  }
+'
+
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+chgrpcmd=
+chmodcmd=$chmodprog
+chowncmd=
+mvcmd=$mvprog
+rmcmd="$rmprog -f"
+stripcmd=
+
+src=
+dst=
+dir_arg=
+dst_arg=
+
+copy_on_change=false
+no_target_directory=
+
+usage="\
+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+   or: $0 [OPTION]... SRCFILES... DIRECTORY
+   or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+   or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+     --help     display this help and exit.
+     --version  display version info and exit.
+
+  -c            (ignored)
+  -C            install only if different (preserve the last data modification time)
+  -d            create directories instead of installing files.
+  -g GROUP      $chgrpprog installed files to GROUP.
+  -m MODE       $chmodprog installed files to MODE.
+  -o USER       $chownprog installed files to USER.
+  -s            $stripprog installed files.
+  -t DIRECTORY  install into DIRECTORY.
+  -T            report an error if DSTFILE is a directory.
+
+Environment variables override the default commands:
+  CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
+  RMPROG STRIPPROG
+"
+
+while test $# -ne 0; do
+  case $1 in
+    -c) ;;
+
+    -C) copy_on_change=true;;
+
+    -d) dir_arg=true;;
+
+    -g) chgrpcmd="$chgrpprog $2"
+	shift;;
+
+    --help) echo "$usage"; exit $?;;
+
+    -m) mode=$2
+	case $mode in
+	  *' '* | *'	'* | *'
+'*	  | *'*'* | *'?'* | *'['*)
+	    echo "$0: invalid mode: $mode" >&2
+	    exit 1;;
+	esac
+	shift;;
+
+    -o) chowncmd="$chownprog $2"
+	shift;;
+
+    -s) stripcmd=$stripprog;;
+
+    -t) dst_arg=$2
+	# Protect names problematic for 'test' and other utilities.
+	case $dst_arg in
+	  -* | [=\(\)!]) dst_arg=./$dst_arg;;
+	esac
+	shift;;
+
+    -T) no_target_directory=true;;
+
+    --version) echo "$0 $scriptversion"; exit $?;;
+
+    --)	shift
+	break;;
+
+    -*)	echo "$0: invalid option: $1" >&2
+	exit 1;;
+
+    *)  break;;
+  esac
+  shift
+done
+
+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
+  # When -d is used, all remaining arguments are directories to create.
+  # When -t is used, the destination is already specified.
+  # Otherwise, the last argument is the destination.  Remove it from $@.
+  for arg
+  do
+    if test -n "$dst_arg"; then
+      # $@ is not empty: it contains at least $arg.
+      set fnord "$@" "$dst_arg"
+      shift # fnord
+    fi
+    shift # arg
+    dst_arg=$arg
+    # Protect names problematic for 'test' and other utilities.
+    case $dst_arg in
+      -* | [=\(\)!]) dst_arg=./$dst_arg;;
+    esac
+  done
+fi
+
+if test $# -eq 0; then
+  if test -z "$dir_arg"; then
+    echo "$0: no input file specified." >&2
+    exit 1
+  fi
+  # It's OK to call 'install-sh -d' without argument.
+  # This can happen when creating conditional directories.
+  exit 0
+fi
+
+if test -z "$dir_arg"; then
+  do_exit='(exit $ret); exit $ret'
+  trap "ret=129; $do_exit" 1
+  trap "ret=130; $do_exit" 2
+  trap "ret=141; $do_exit" 13
+  trap "ret=143; $do_exit" 15
+
+  # Set umask so as not to create temps with too-generous modes.
+  # However, 'strip' requires both read and write access to temps.
+  case $mode in
+    # Optimize common cases.
+    *644) cp_umask=133;;
+    *755) cp_umask=22;;
+
+    *[0-7])
+      if test -z "$stripcmd"; then
+	u_plus_rw=
+      else
+	u_plus_rw='% 200'
+      fi
+      cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+    *)
+      if test -z "$stripcmd"; then
+	u_plus_rw=
+      else
+	u_plus_rw=,u+rw
+      fi
+      cp_umask=$mode$u_plus_rw;;
+  esac
+fi
+
+for src
+do
+  # Protect names problematic for 'test' and other utilities.
+  case $src in
+    -* | [=\(\)!]) src=./$src;;
+  esac
+
+  if test -n "$dir_arg"; then
+    dst=$src
+    dstdir=$dst
+    test -d "$dstdir"
+    dstdir_status=$?
+  else
+
+    # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+    # might cause directories to be created, which would be especially bad
+    # if $src (and thus $dsttmp) contains '*'.
+    if test ! -f "$src" && test ! -d "$src"; then
+      echo "$0: $src does not exist." >&2
+      exit 1
+    fi
+
+    if test -z "$dst_arg"; then
+      echo "$0: no destination specified." >&2
+      exit 1
+    fi
+    dst=$dst_arg
+
+    # If destination is a directory, append the input filename; won't work
+    # if double slashes aren't ignored.
+    if test -d "$dst"; then
+      if test -n "$no_target_directory"; then
+	echo "$0: $dst_arg: Is a directory" >&2
+	exit 1
+      fi
+      dstdir=$dst
+      dst=$dstdir/`basename "$src"`
+      dstdir_status=0
+    else
+      # Prefer dirname, but fall back on a substitute if dirname fails.
+      dstdir=`
+	(dirname "$dst") 2>/dev/null ||
+	expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	     X"$dst" : 'X\(//\)[^/]' \| \
+	     X"$dst" : 'X\(//\)$' \| \
+	     X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
+	echo X"$dst" |
+	    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+		   s//\1/
+		   q
+		 }
+		 /^X\(\/\/\)[^/].*/{
+		   s//\1/
+		   q
+		 }
+		 /^X\(\/\/\)$/{
+		   s//\1/
+		   q
+		 }
+		 /^X\(\/\).*/{
+		   s//\1/
+		   q
+		 }
+		 s/.*/./; q'
+      `
+
+      test -d "$dstdir"
+      dstdir_status=$?
+    fi
+  fi
+
+  obsolete_mkdir_used=false
+
+  if test $dstdir_status != 0; then
+    case $posix_mkdir in
+      '')
+	# Create intermediate dirs using mode 755 as modified by the umask.
+	# This is like FreeBSD 'install' as of 1997-10-28.
+	umask=`umask`
+	case $stripcmd.$umask in
+	  # Optimize common cases.
+	  *[2367][2367]) mkdir_umask=$umask;;
+	  .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+	  *[0-7])
+	    mkdir_umask=`expr $umask + 22 \
+	      - $umask % 100 % 40 + $umask % 20 \
+	      - $umask % 10 % 4 + $umask % 2
+	    `;;
+	  *) mkdir_umask=$umask,go-w;;
+	esac
+
+	# With -d, create the new directory with the user-specified mode.
+	# Otherwise, rely on $mkdir_umask.
+	if test -n "$dir_arg"; then
+	  mkdir_mode=-m$mode
+	else
+	  mkdir_mode=
+	fi
+
+	posix_mkdir=false
+	case $umask in
+	  *[123567][0-7][0-7])
+	    # POSIX mkdir -p sets u+wx bits regardless of umask, which
+	    # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+	    ;;
+	  *)
+	    tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+	    trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+	    if (umask $mkdir_umask &&
+		exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
+	    then
+	      if test -z "$dir_arg" || {
+		   # Check for POSIX incompatibilities with -m.
+		   # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+		   # other-writable bit of parent directory when it shouldn't.
+		   # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+		   ls_ld_tmpdir=`ls -ld "$tmpdir"`
+		   case $ls_ld_tmpdir in
+		     d????-?r-*) different_mode=700;;
+		     d????-?--*) different_mode=755;;
+		     *) false;;
+		   esac &&
+		   $mkdirprog -m$different_mode -p -- "$tmpdir" && {
+		     ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
+		     test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+		   }
+		 }
+	      then posix_mkdir=:
+	      fi
+	      rmdir "$tmpdir/d" "$tmpdir"
+	    else
+	      # Remove any dirs left behind by ancient mkdir implementations.
+	      rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
+	    fi
+	    trap '' 0;;
+	esac;;
+    esac
+
+    if
+      $posix_mkdir && (
+	umask $mkdir_umask &&
+	$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+      )
+    then :
+    else
+
+      # The umask is ridiculous, or mkdir does not conform to POSIX,
+      # or it failed possibly due to a race condition.  Create the
+      # directory the slow way, step by step, checking for races as we go.
+
+      case $dstdir in
+	/*) prefix='/';;
+	[-=\(\)!]*) prefix='./';;
+	*)  prefix='';;
+      esac
+
+      eval "$initialize_posix_glob"
+
+      oIFS=$IFS
+      IFS=/
+      $posix_glob set -f
+      set fnord $dstdir
+      shift
+      $posix_glob set +f
+      IFS=$oIFS
+
+      prefixes=
+
+      for d
+      do
+	test X"$d" = X && continue
+
+	prefix=$prefix$d
+	if test -d "$prefix"; then
+	  prefixes=
+	else
+	  if $posix_mkdir; then
+	    (umask=$mkdir_umask &&
+	     $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+	    # Don't fail if two instances are running concurrently.
+	    test -d "$prefix" || exit 1
+	  else
+	    case $prefix in
+	      *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+	      *) qprefix=$prefix;;
+	    esac
+	    prefixes="$prefixes '$qprefix'"
+	  fi
+	fi
+	prefix=$prefix/
+      done
+
+      if test -n "$prefixes"; then
+	# Don't fail if two instances are running concurrently.
+	(umask $mkdir_umask &&
+	 eval "\$doit_exec \$mkdirprog $prefixes") ||
+	  test -d "$dstdir" || exit 1
+	obsolete_mkdir_used=true
+      fi
+    fi
+  fi
+
+  if test -n "$dir_arg"; then
+    { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+    { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+      test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+  else
+
+    # Make a couple of temp file names in the proper directory.
+    dsttmp=$dstdir/_inst.$$_
+    rmtmp=$dstdir/_rm.$$_
+
+    # Trap to clean up those temp files at exit.
+    trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+    # Copy the file name to the temp name.
+    (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+    # and set any options; do chmod last to preserve setuid bits.
+    #
+    # If any of these fail, we abort the whole thing.  If we want to
+    # ignore errors from any of these, just make sure not to ignore
+    # errors from the above "$doit $cpprog $src $dsttmp" command.
+    #
+    { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
+    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
+    { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
+    { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+    # If -C, don't bother to copy if it wouldn't change the file.
+    if $copy_on_change &&
+       old=`LC_ALL=C ls -dlL "$dst"	2>/dev/null` &&
+       new=`LC_ALL=C ls -dlL "$dsttmp"	2>/dev/null` &&
+
+       eval "$initialize_posix_glob" &&
+       $posix_glob set -f &&
+       set X $old && old=:$2:$4:$5:$6 &&
+       set X $new && new=:$2:$4:$5:$6 &&
+       $posix_glob set +f &&
+
+       test "$old" = "$new" &&
+       $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
+    then
+      rm -f "$dsttmp"
+    else
+      # Rename the file to the real destination.
+      $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+      # The rename failed, perhaps because mv can't rename something else
+      # to itself, or perhaps because mv is so ancient that it does not
+      # support -f.
+      {
+	# Now remove or move aside any old file at destination location.
+	# We try this two ways since rm can't unlink itself on some
+	# systems and the destination file might be busy for other
+	# reasons.  In this case, the final cleanup might fail but the new
+	# file should still install successfully.
+	{
+	  test ! -f "$dst" ||
+	  $doit $rmcmd -f "$dst" 2>/dev/null ||
+	  { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+	    { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+	  } ||
+	  { echo "$0: cannot unlink or rename $dst" >&2
+	    (exit 1); exit 1
+	  }
+	} &&
+
+	# Now rename the file to the real destination.
+	$doit $mvcmd "$dsttmp" "$dst"
+      }
+    fi || exit 1
+
+    trap '' 0
+  fi
+done
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/autostuff/libtool.m4 b/autostuff/libtool.m4
new file mode 100644
index 0000000..d7c043f
--- /dev/null
+++ b/autostuff/libtool.m4
@@ -0,0 +1,7997 @@
+# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+#
+#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+#                 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+#                 Foundation, Inc.
+#   Written by Gordon Matzigkeit, 1996
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+m4_define([_LT_COPYING], [dnl
+#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+#                 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+#                 Foundation, Inc.
+#   Written by Gordon Matzigkeit, 1996
+#
+#   This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING.  If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+])
+
+# serial 57 LT_INIT
+
+
+# LT_PREREQ(VERSION)
+# ------------------
+# Complain and exit if this libtool version is less that VERSION.
+m4_defun([LT_PREREQ],
+[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1,
+       [m4_default([$3],
+		   [m4_fatal([Libtool version $1 or higher is required],
+		             63)])],
+       [$2])])
+
+
+# _LT_CHECK_BUILDDIR
+# ------------------
+# Complain if the absolute build directory name contains unusual characters
+m4_defun([_LT_CHECK_BUILDDIR],
+[case `pwd` in
+  *\ * | *\	*)
+    AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;;
+esac
+])
+
+
+# LT_INIT([OPTIONS])
+# ------------------
+AC_DEFUN([LT_INIT],
+[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT
+AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+AC_BEFORE([$0], [LT_LANG])dnl
+AC_BEFORE([$0], [LT_OUTPUT])dnl
+AC_BEFORE([$0], [LTDL_INIT])dnl
+m4_require([_LT_CHECK_BUILDDIR])dnl
+
+dnl Autoconf doesn't catch unexpanded LT_ macros by default:
+m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl
+m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl
+dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4
+dnl unless we require an AC_DEFUNed macro:
+AC_REQUIRE([LTOPTIONS_VERSION])dnl
+AC_REQUIRE([LTSUGAR_VERSION])dnl
+AC_REQUIRE([LTVERSION_VERSION])dnl
+AC_REQUIRE([LTOBSOLETE_VERSION])dnl
+m4_require([_LT_PROG_LTMAIN])dnl
+
+_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}])
+
+dnl Parse OPTIONS
+_LT_SET_OPTIONS([$0], [$1])
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+_LT_SETUP
+
+# Only expand once:
+m4_define([LT_INIT])
+])# LT_INIT
+
+# Old names:
+AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT])
+AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
+dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
+
+
+# _LT_CC_BASENAME(CC)
+# -------------------
+# Calculate cc_basename.  Skip known compiler wrappers and cross-prefix.
+m4_defun([_LT_CC_BASENAME],
+[for cc_temp in $1""; do
+  case $cc_temp in
+    compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+    distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+    \-*) ;;
+    *) break;;
+  esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+])
+
+
+# _LT_FILEUTILS_DEFAULTS
+# ----------------------
+# It is okay to use these file commands and assume they have been set
+# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'.
+m4_defun([_LT_FILEUTILS_DEFAULTS],
+[: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+])# _LT_FILEUTILS_DEFAULTS
+
+
+# _LT_SETUP
+# ---------
+m4_defun([_LT_SETUP],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
+
+_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl
+dnl
+_LT_DECL([], [host_alias], [0], [The host system])dnl
+_LT_DECL([], [host], [0])dnl
+_LT_DECL([], [host_os], [0])dnl
+dnl
+_LT_DECL([], [build_alias], [0], [The build system])dnl
+_LT_DECL([], [build], [0])dnl
+_LT_DECL([], [build_os], [0])dnl
+dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+dnl
+AC_REQUIRE([AC_PROG_LN_S])dnl
+test -z "$LN_S" && LN_S="ln -s"
+_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl
+dnl
+AC_REQUIRE([LT_CMD_MAX_LEN])dnl
+_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl
+_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
+dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl
+m4_require([_LT_CMD_RELOAD])dnl
+m4_require([_LT_CHECK_MAGIC_METHOD])dnl
+m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl
+m4_require([_LT_CMD_OLD_ARCHIVE])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_WITH_SYSROOT])dnl
+
+_LT_CONFIG_LIBTOOL_INIT([
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+])
+if test -n "${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+
+_LT_CHECK_OBJDIR
+
+m4_require([_LT_TAG_COMPILER])dnl
+
+case $host_os in
+aix3*)
+  # AIX sometimes has problems with the GCC collect2 program.  For some
+  # reason, if we set the COLLECT_NAMES environment variable, the problems
+  # vanish in a puff of smoke.
+  if test "X${COLLECT_NAMES+set}" != Xset; then
+    COLLECT_NAMES=
+    export COLLECT_NAMES
+  fi
+  ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+_LT_CC_BASENAME([$compiler])
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+    _LT_PATH_MAGIC
+  fi
+  ;;
+esac
+
+# Use C for the default configuration in the libtool script
+LT_SUPPORTED_TAG([CC])
+_LT_LANG_C_CONFIG
+_LT_LANG_DEFAULT_CONFIG
+_LT_CONFIG_COMMANDS
+])# _LT_SETUP
+
+
+# _LT_PREPARE_SED_QUOTE_VARS
+# --------------------------
+# Define a few sed substitution that help us do robust quoting.
+m4_defun([_LT_PREPARE_SED_QUOTE_VARS],
+[# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\([["`\\]]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+])
+
+# _LT_PROG_LTMAIN
+# ---------------
+# Note that this code is called both from `configure', and `config.status'
+# now that we use AC_CONFIG_COMMANDS to generate libtool.  Notably,
+# `config.status' has no value for ac_aux_dir unless we are using Automake,
+# so we pass a copy along to make sure it has a sensible value anyway.
+m4_defun([_LT_PROG_LTMAIN],
+[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
+_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
+ltmain="$ac_aux_dir/ltmain.sh"
+])# _LT_PROG_LTMAIN
+
+
+## ------------------------------------- ##
+## Accumulate code for creating libtool. ##
+## ------------------------------------- ##
+
+# So that we can recreate a full libtool script including additional
+# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
+# in macros and then make a single call at the end using the `libtool'
+# label.
+
+
+# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS])
+# ----------------------------------------
+# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL_INIT],
+[m4_ifval([$1],
+          [m4_append([_LT_OUTPUT_LIBTOOL_INIT],
+                     [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_INIT])
+
+
+# _LT_CONFIG_LIBTOOL([COMMANDS])
+# ------------------------------
+# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL],
+[m4_ifval([$1],
+          [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS],
+                     [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS])
+
+
+# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS])
+# -----------------------------------------------------
+m4_defun([_LT_CONFIG_SAVE_COMMANDS],
+[_LT_CONFIG_LIBTOOL([$1])
+_LT_CONFIG_LIBTOOL_INIT([$2])
+])
+
+
+# _LT_FORMAT_COMMENT([COMMENT])
+# -----------------------------
+# Add leading comment marks to the start of each line, and a trailing
+# full-stop to the whole comment if one is not present already.
+m4_define([_LT_FORMAT_COMMENT],
+[m4_ifval([$1], [
+m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])],
+              [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.])
+)])
+
+
+
+## ------------------------ ##
+## FIXME: Eliminate VARNAME ##
+## ------------------------ ##
+
+
+# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?])
+# -------------------------------------------------------------------
+# CONFIGNAME is the name given to the value in the libtool script.
+# VARNAME is the (base) name used in the configure script.
+# VALUE may be 0, 1 or 2 for a computed quote escaped value based on
+# VARNAME.  Any other value will be used directly.
+m4_define([_LT_DECL],
+[lt_if_append_uniq([lt_decl_varnames], [$2], [, ],
+    [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name],
+	[m4_ifval([$1], [$1], [$2])])
+    lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3])
+    m4_ifval([$4],
+	[lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])])
+    lt_dict_add_subkey([lt_decl_dict], [$2],
+	[tagged?], [m4_ifval([$5], [yes], [no])])])
+])
+
+
+# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION])
+# --------------------------------------------------------
+m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])])
+
+
+# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_tag_varnames],
+[_lt_decl_filter([tagged?], [yes], $@)])
+
+
+# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..])
+# ---------------------------------------------------------
+m4_define([_lt_decl_filter],
+[m4_case([$#],
+  [0], [m4_fatal([$0: too few arguments: $#])],
+  [1], [m4_fatal([$0: too few arguments: $#: $1])],
+  [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)],
+  [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)],
+  [lt_dict_filter([lt_decl_dict], $@)])[]dnl
+])
+
+
+# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...])
+# --------------------------------------------------
+m4_define([lt_decl_quote_varnames],
+[_lt_decl_filter([value], [1], $@)])
+
+
+# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_dquote_varnames],
+[_lt_decl_filter([value], [2], $@)])
+
+
+# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_varnames_tagged],
+[m4_assert([$# <= 2])dnl
+_$0(m4_quote(m4_default([$1], [[, ]])),
+    m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]),
+    m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))])
+m4_define([_lt_decl_varnames_tagged],
+[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])])
+
+
+# lt_decl_all_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_all_varnames],
+[_$0(m4_quote(m4_default([$1], [[, ]])),
+     m4_if([$2], [],
+	   m4_quote(lt_decl_varnames),
+	m4_quote(m4_shift($@))))[]dnl
+])
+m4_define([_lt_decl_all_varnames],
+[lt_join($@, lt_decl_varnames_tagged([$1],
+			lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl
+])
+
+
+# _LT_CONFIG_STATUS_DECLARE([VARNAME])
+# ------------------------------------
+# Quote a variable value, and forward it to `config.status' so that its
+# declaration there will have the same value as in `configure'.  VARNAME
+# must have a single quote delimited value for this to work.
+m4_define([_LT_CONFIG_STATUS_DECLARE],
+[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`'])
+
+
+# _LT_CONFIG_STATUS_DECLARATIONS
+# ------------------------------
+# We delimit libtool config variables with single quotes, so when
+# we write them to config.status, we have to be sure to quote all
+# embedded single quotes properly.  In configure, this macro expands
+# each variable declared with _LT_DECL (and _LT_TAGDECL) into:
+#
+#    <var>='`$ECHO "$<var>" | $SED "$delay_single_quote_subst"`'
+m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
+    [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAGS
+# ----------------
+# Output comment and list of tags supported by the script
+m4_defun([_LT_LIBTOOL_TAGS],
+[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
+available_tags="_LT_TAGS"dnl
+])
+
+
+# _LT_LIBTOOL_DECLARE(VARNAME, [TAG])
+# -----------------------------------
+# Extract the dictionary values for VARNAME (optionally with TAG) and
+# expand to a commented shell variable setting:
+#
+#    # Some comment about what VAR is for.
+#    visible_name=$lt_internal_name
+m4_define([_LT_LIBTOOL_DECLARE],
+[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1],
+					   [description])))[]dnl
+m4_pushdef([_libtool_name],
+    m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl
+m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])),
+    [0], [_libtool_name=[$]$1],
+    [1], [_libtool_name=$lt_[]$1],
+    [2], [_libtool_name=$lt_[]$1],
+    [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl
+m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
+])
+
+
+# _LT_LIBTOOL_CONFIG_VARS
+# -----------------------
+# Produce commented declarations of non-tagged libtool config variables
+# suitable for insertion in the LIBTOOL CONFIG section of the `libtool'
+# script.  Tagged libtool config variables (even for the LIBTOOL CONFIG
+# section) are produced by _LT_LIBTOOL_TAG_VARS.
+m4_defun([_LT_LIBTOOL_CONFIG_VARS],
+[m4_foreach([_lt_var],
+    m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)),
+    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAG_VARS(TAG)
+# -------------------------
+m4_define([_LT_LIBTOOL_TAG_VARS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames),
+    [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])])
+
+
+# _LT_TAGVAR(VARNAME, [TAGNAME])
+# ------------------------------
+m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
+
+
+# _LT_CONFIG_COMMANDS
+# -------------------
+# Send accumulated output to $CONFIG_STATUS.  Thanks to the lists of
+# variables for single and double quote escaping we saved from calls
+# to _LT_DECL, we can put quote escaped variables declarations
+# into `config.status', and then the shell code to quote escape them in
+# for loops in `config.status'.  Finally, any additional code accumulated
+# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
+m4_defun([_LT_CONFIG_COMMANDS],
+[AC_PROVIDE_IFELSE([LT_OUTPUT],
+	dnl If the libtool generation code has been placed in $CONFIG_LT,
+	dnl instead of duplicating it all over again into config.status,
+	dnl then we will have config.status run $CONFIG_LT later, so it
+	dnl needs to know what name is stored there:
+        [AC_CONFIG_COMMANDS([libtool],
+            [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])],
+    dnl If the libtool generation code is destined for config.status,
+    dnl expand the accumulated commands and init code now:
+    [AC_CONFIG_COMMANDS([libtool],
+        [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])])
+])#_LT_CONFIG_COMMANDS
+
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT],
+[
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+_LT_CONFIG_STATUS_DECLARATIONS
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$[]1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_quote_varnames); do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[[\\\\\\\`\\"\\\$]]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+# Double-quote double-evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_dquote_varnames); do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[[\\\\\\\`\\"\\\$]]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+_LT_OUTPUT_LIBTOOL_INIT
+])
+
+# _LT_GENERATED_FILE_INIT(FILE, [COMMENT])
+# ------------------------------------
+# Generate a child script FILE with all initialization necessary to
+# reuse the environment learned by the parent script, and make the
+# file executable.  If COMMENT is supplied, it is inserted after the
+# `#!' sequence but before initialization text begins.  After this
+# macro, additional text can be appended to FILE to form the body of
+# the child script.  The macro ends with non-zero status if the
+# file could not be fully written (such as if the disk is full).
+m4_ifdef([AS_INIT_GENERATED],
+[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])],
+[m4_defun([_LT_GENERATED_FILE_INIT],
+[m4_require([AS_PREPARE])]dnl
+[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl
+[lt_write_fail=0
+cat >$1 <<_ASEOF || lt_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+$2
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$1 <<\_ASEOF || lt_write_fail=1
+AS_SHELL_SANITIZE
+_AS_PREPARE
+exec AS_MESSAGE_FD>&1
+_ASEOF
+test $lt_write_fail = 0 && chmod +x $1[]dnl
+m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT
+
+# LT_OUTPUT
+# ---------
+# This macro allows early generation of the libtool script (before
+# AC_OUTPUT is called), incase it is used in configure for compilation
+# tests.
+AC_DEFUN([LT_OUTPUT],
+[: ${CONFIG_LT=./config.lt}
+AC_MSG_NOTICE([creating $CONFIG_LT])
+_LT_GENERATED_FILE_INIT(["$CONFIG_LT"],
+[# Run this file to recreate a libtool stub with the current configuration.])
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+lt_cl_silent=false
+exec AS_MESSAGE_LOG_FD>>config.log
+{
+  echo
+  AS_BOX([Running $as_me.])
+} >&AS_MESSAGE_LOG_FD
+
+lt_cl_help="\
+\`$as_me' creates a local libtool stub from the current configuration,
+for use in further configure time tests before the real libtool is
+generated.
+
+Usage: $[0] [[OPTIONS]]
+
+  -h, --help      print this help, then exit
+  -V, --version   print version number, then exit
+  -q, --quiet     do not print progress messages
+  -d, --debug     don't remove temporary files
+
+Report bugs to <bug-libtool at gnu.org>."
+
+lt_cl_version="\
+m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
+m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
+configured by $[0], generated by m4_PACKAGE_STRING.
+
+Copyright (C) 2011 Free Software Foundation, Inc.
+This config.lt script is free software; the Free Software Foundation
+gives unlimited permision to copy, distribute and modify it."
+
+while test $[#] != 0
+do
+  case $[1] in
+    --version | --v* | -V )
+      echo "$lt_cl_version"; exit 0 ;;
+    --help | --h* | -h )
+      echo "$lt_cl_help"; exit 0 ;;
+    --debug | --d* | -d )
+      debug=: ;;
+    --quiet | --q* | --silent | --s* | -q )
+      lt_cl_silent=: ;;
+
+    -*) AC_MSG_ERROR([unrecognized option: $[1]
+Try \`$[0] --help' for more information.]) ;;
+
+    *) AC_MSG_ERROR([unrecognized argument: $[1]
+Try \`$[0] --help' for more information.]) ;;
+  esac
+  shift
+done
+
+if $lt_cl_silent; then
+  exec AS_MESSAGE_FD>/dev/null
+fi
+_LTEOF
+
+cat >>"$CONFIG_LT" <<_LTEOF
+_LT_OUTPUT_LIBTOOL_COMMANDS_INIT
+_LTEOF
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+AC_MSG_NOTICE([creating $ofile])
+_LT_OUTPUT_LIBTOOL_COMMANDS
+AS_EXIT(0)
+_LTEOF
+chmod +x "$CONFIG_LT"
+
+# configure is writing to config.log, but config.lt does its own redirection,
+# appending to config.log, which fails on DOS, as config.log is still kept
+# open by configure.  Here we exec the FD to /dev/null, effectively closing
+# config.log, so it can be properly (re)opened and appended to by config.lt.
+lt_cl_success=:
+test "$silent" = yes &&
+  lt_config_lt_args="$lt_config_lt_args --quiet"
+exec AS_MESSAGE_LOG_FD>/dev/null
+$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
+exec AS_MESSAGE_LOG_FD>>config.log
+$lt_cl_success || AS_EXIT(1)
+])# LT_OUTPUT
+
+
+# _LT_CONFIG(TAG)
+# ---------------
+# If TAG is the built-in tag, create an initial libtool script with a
+# default configuration from the untagged config vars.  Otherwise add code
+# to config.status for appending the configuration named by TAG from the
+# matching tagged config vars.
+m4_defun([_LT_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_CONFIG_SAVE_COMMANDS([
+  m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
+  m4_if(_LT_TAG, [C], [
+    # See if we are running on zsh, and set the options which allow our
+    # commands through without removal of \ escapes.
+    if test -n "${ZSH_VERSION+set}" ; then
+      setopt NO_GLOB_SUBST
+    fi
+
+    cfgfile="${ofile}T"
+    trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+    $RM "$cfgfile"
+
+    cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+_LT_COPYING
+_LT_LIBTOOL_TAGS
+
+# ### BEGIN LIBTOOL CONFIG
+_LT_LIBTOOL_CONFIG_VARS
+_LT_LIBTOOL_TAG_VARS
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+  case $host_os in
+  aix3*)
+    cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program.  For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+  COLLECT_NAMES=
+  export COLLECT_NAMES
+fi
+_LT_EOF
+    ;;
+  esac
+
+  _LT_PROG_LTMAIN
+
+  # We use sed instead of cat because bash on DJGPP gets confused if
+  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
+  # text mode, it properly converts lines to CR/LF.  This bash problem
+  # is reportedly fixed, but why not run on old versions too?
+  sed '$q' "$ltmain" >> "$cfgfile" \
+     || (rm -f "$cfgfile"; exit 1)
+
+  _LT_PROG_REPLACE_SHELLFNS
+
+   mv -f "$cfgfile" "$ofile" ||
+    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+  chmod +x "$ofile"
+],
+[cat <<_LT_EOF >> "$ofile"
+
+dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded
+dnl in a comment (ie after a #).
+# ### BEGIN LIBTOOL TAG CONFIG: $1
+_LT_LIBTOOL_TAG_VARS(_LT_TAG)
+# ### END LIBTOOL TAG CONFIG: $1
+_LT_EOF
+])dnl /m4_if
+],
+[m4_if([$1], [], [
+    PACKAGE='$PACKAGE'
+    VERSION='$VERSION'
+    TIMESTAMP='$TIMESTAMP'
+    RM='$RM'
+    ofile='$ofile'], [])
+])dnl /_LT_CONFIG_SAVE_COMMANDS
+])# _LT_CONFIG
+
+
+# LT_SUPPORTED_TAG(TAG)
+# ---------------------
+# Trace this macro to discover what tags are supported by the libtool
+# --tag option, using:
+#    autoconf --trace 'LT_SUPPORTED_TAG:$1'
+AC_DEFUN([LT_SUPPORTED_TAG], [])
+
+
+# C support is built-in for now
+m4_define([_LT_LANG_C_enabled], [])
+m4_define([_LT_TAGS], [])
+
+
+# LT_LANG(LANG)
+# -------------
+# Enable libtool support for the given language if not already enabled.
+AC_DEFUN([LT_LANG],
+[AC_BEFORE([$0], [LT_OUTPUT])dnl
+m4_case([$1],
+  [C],			[_LT_LANG(C)],
+  [C++],		[_LT_LANG(CXX)],
+  [Go],			[_LT_LANG(GO)],
+  [Java],		[_LT_LANG(GCJ)],
+  [Fortran 77],		[_LT_LANG(F77)],
+  [Fortran],		[_LT_LANG(FC)],
+  [Windows Resource],	[_LT_LANG(RC)],
+  [m4_ifdef([_LT_LANG_]$1[_CONFIG],
+    [_LT_LANG($1)],
+    [m4_fatal([$0: unsupported language: "$1"])])])dnl
+])# LT_LANG
+
+
+# _LT_LANG(LANGNAME)
+# ------------------
+m4_defun([_LT_LANG],
+[m4_ifdef([_LT_LANG_]$1[_enabled], [],
+  [LT_SUPPORTED_TAG([$1])dnl
+  m4_append([_LT_TAGS], [$1 ])dnl
+  m4_define([_LT_LANG_]$1[_enabled], [])dnl
+  _LT_LANG_$1_CONFIG($1)])dnl
+])# _LT_LANG
+
+
+m4_ifndef([AC_PROG_GO], [
+############################################################
+# NOTE: This macro has been submitted for inclusion into   #
+#  GNU Autoconf as AC_PROG_GO.  When it is available in    #
+#  a released version of Autoconf we should remove this    #
+#  macro and use it instead.                               #
+############################################################
+m4_defun([AC_PROG_GO],
+[AC_LANG_PUSH(Go)dnl
+AC_ARG_VAR([GOC],     [Go compiler command])dnl
+AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl
+_AC_ARG_VAR_LDFLAGS()dnl
+AC_CHECK_TOOL(GOC, gccgo)
+if test -z "$GOC"; then
+  if test -n "$ac_tool_prefix"; then
+    AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo])
+  fi
+fi
+if test -z "$GOC"; then
+  AC_CHECK_PROG(GOC, gccgo, gccgo, false)
+fi
+])#m4_defun
+])#m4_ifndef
+
+
+# _LT_LANG_DEFAULT_CONFIG
+# -----------------------
+m4_defun([_LT_LANG_DEFAULT_CONFIG],
+[AC_PROVIDE_IFELSE([AC_PROG_CXX],
+  [LT_LANG(CXX)],
+  [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_F77],
+  [LT_LANG(F77)],
+  [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_FC],
+  [LT_LANG(FC)],
+  [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])])
+
+dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal
+dnl pulling things in needlessly.
+AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+  [LT_LANG(GCJ)],
+  [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+    [LT_LANG(GCJ)],
+    [AC_PROVIDE_IFELSE([LT_PROG_GCJ],
+      [LT_LANG(GCJ)],
+      [m4_ifdef([AC_PROG_GCJ],
+	[m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])])
+       m4_ifdef([A][M_PROG_GCJ],
+	[m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])])
+       m4_ifdef([LT_PROG_GCJ],
+	[m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])])
+
+AC_PROVIDE_IFELSE([AC_PROG_GO],
+  [LT_LANG(GO)],
+  [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])])
+
+AC_PROVIDE_IFELSE([LT_PROG_RC],
+  [LT_LANG(RC)],
+  [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])])
+])# _LT_LANG_DEFAULT_CONFIG
+
+# Obsolete macros:
+AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
+AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
+AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
+AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
+AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
+dnl AC_DEFUN([AC_LIBTOOL_F77], [])
+dnl AC_DEFUN([AC_LIBTOOL_FC], [])
+dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
+dnl AC_DEFUN([AC_LIBTOOL_RC], [])
+
+
+# _LT_TAG_COMPILER
+# ----------------
+m4_defun([_LT_TAG_COMPILER],
+[AC_REQUIRE([AC_PROG_CC])dnl
+
+_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
+_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
+_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
+_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+])# _LT_TAG_COMPILER
+
+
+# _LT_COMPILER_BOILERPLATE
+# ------------------------
+# Check for compiler boilerplate output or warnings with
+# the simple compiler test code.
+m4_defun([_LT_COMPILER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+])# _LT_COMPILER_BOILERPLATE
+
+
+# _LT_LINKER_BOILERPLATE
+# ----------------------
+# Check for linker boilerplate output or warnings with
+# the simple link test code.
+m4_defun([_LT_LINKER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+])# _LT_LINKER_BOILERPLATE
+
+# _LT_REQUIRED_DARWIN_CHECKS
+# -------------------------
+m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
+  case $host_os in
+    rhapsody* | darwin*)
+    AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
+    AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
+    AC_CHECK_TOOL([LIPO], [lipo], [:])
+    AC_CHECK_TOOL([OTOOL], [otool], [:])
+    AC_CHECK_TOOL([OTOOL64], [otool64], [:])
+    _LT_DECL([], [DSYMUTIL], [1],
+      [Tool to manipulate archived DWARF debug symbol files on Mac OS X])
+    _LT_DECL([], [NMEDIT], [1],
+      [Tool to change global to local symbols on Mac OS X])
+    _LT_DECL([], [LIPO], [1],
+      [Tool to manipulate fat objects and archives on Mac OS X])
+    _LT_DECL([], [OTOOL], [1],
+      [ldd/readelf like tool for Mach-O binaries on Mac OS X])
+    _LT_DECL([], [OTOOL64], [1],
+      [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4])
+
+    AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
+      [lt_cv_apple_cc_single_mod=no
+      if test -z "${LT_MULTI_MODULE}"; then
+	# By default we will add the -single_module flag. You can override
+	# by either setting the environment variable LT_MULTI_MODULE
+	# non-empty at configure time, or by adding -multi_module to the
+	# link flags.
+	rm -rf libconftest.dylib*
+	echo "int foo(void){return 1;}" > conftest.c
+	echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD
+	$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+	  -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+        _lt_result=$?
+	# If there is a non-empty error log, and "single_module"
+	# appears in it, assume the flag caused a linker warning
+        if test -s conftest.err && $GREP single_module conftest.err; then
+	  cat conftest.err >&AS_MESSAGE_LOG_FD
+	# Otherwise, if the output was created with a 0 exit code from
+	# the compiler, it worked.
+	elif test -f libconftest.dylib && test $_lt_result -eq 0; then
+	  lt_cv_apple_cc_single_mod=yes
+	else
+	  cat conftest.err >&AS_MESSAGE_LOG_FD
+	fi
+	rm -rf libconftest.dylib*
+	rm -f conftest.*
+      fi])
+
+    AC_CACHE_CHECK([for -exported_symbols_list linker flag],
+      [lt_cv_ld_exported_symbols_list],
+      [lt_cv_ld_exported_symbols_list=no
+      save_LDFLAGS=$LDFLAGS
+      echo "_main" > conftest.sym
+      LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+      AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+	[lt_cv_ld_exported_symbols_list=yes],
+	[lt_cv_ld_exported_symbols_list=no])
+	LDFLAGS="$save_LDFLAGS"
+    ])
+
+    AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load],
+      [lt_cv_ld_force_load=no
+      cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD
+      $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD
+      echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
+      $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
+      echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD
+      $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD
+      cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD
+      $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+      _lt_result=$?
+      if test -s conftest.err && $GREP force_load conftest.err; then
+	cat conftest.err >&AS_MESSAGE_LOG_FD
+      elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then
+	lt_cv_ld_force_load=yes
+      else
+	cat conftest.err >&AS_MESSAGE_LOG_FD
+      fi
+        rm -f conftest.err libconftest.a conftest conftest.c
+        rm -rf conftest.dSYM
+    ])
+    case $host_os in
+    rhapsody* | darwin1.[[012]])
+      _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+    darwin1.*)
+      _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+    darwin*) # darwin 5.x on
+      # if running on 10.5 or later, the deployment target defaults
+      # to the OS version, if on x86, and 10.4, the deployment
+      # target defaults to 10.4. Don't you love it?
+      case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+	10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
+	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+	10.[[012]]*)
+	  _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+	10.*)
+	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+      esac
+    ;;
+  esac
+    if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+      _lt_dar_single_mod='$single_module'
+    fi
+    if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+      _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+    else
+      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+    fi
+    if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+      _lt_dsymutil='~$DSYMUTIL $lib || :'
+    else
+      _lt_dsymutil=
+    fi
+    ;;
+  esac
+])
+
+
+# _LT_DARWIN_LINKER_FEATURES([TAG])
+# ---------------------------------
+# Checks for linker and compiler features on darwin
+m4_defun([_LT_DARWIN_LINKER_FEATURES],
+[
+  m4_require([_LT_REQUIRED_DARWIN_CHECKS])
+  _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+  _LT_TAGVAR(hardcode_direct, $1)=no
+  _LT_TAGVAR(hardcode_automatic, $1)=yes
+  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+  if test "$lt_cv_ld_force_load" = "yes"; then
+    _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+    m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes],
+                  [FC],  [_LT_TAGVAR(compiler_needs_object, $1)=yes])
+  else
+    _LT_TAGVAR(whole_archive_flag_spec, $1)=''
+  fi
+  _LT_TAGVAR(link_all_deplibs, $1)=yes
+  _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined"
+  case $cc_basename in
+     ifort*) _lt_dar_can_shared=yes ;;
+     *) _lt_dar_can_shared=$GCC ;;
+  esac
+  if test "$_lt_dar_can_shared" = "yes"; then
+    output_verbose_link_cmd=func_echo_all
+    _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+    _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+    _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+    _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+    m4_if([$1], [CXX],
+[   if test "$lt_cv_apple_cc_single_mod" != "yes"; then
+      _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
+      _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
+    fi
+],[])
+  else
+  _LT_TAGVAR(ld_shlibs, $1)=no
+  fi
+])
+
+# _LT_SYS_MODULE_PATH_AIX([TAGNAME])
+# ----------------------------------
+# Links a minimal program and checks the executable
+# for the system default hardcoded library path. In most cases,
+# this is /usr/lib:/lib, but when the MPI compilers are used
+# the location of the communication and MPI libs are included too.
+# If we don't find anything, use the default library path according
+# to the aix ld manual.
+# Store the results from the different compilers for each TAGNAME.
+# Allow to override them for all tags through lt_cv_aix_libpath.
+m4_defun([_LT_SYS_MODULE_PATH_AIX],
+[m4_require([_LT_DECL_SED])dnl
+if test "${lt_cv_aix_libpath+set}" = set; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])],
+  [AC_LINK_IFELSE([AC_LANG_PROGRAM],[
+  lt_aix_libpath_sed='[
+      /Import File Strings/,/^$/ {
+	  /^0/ {
+	      s/^0  *\([^ ]*\) *$/\1/
+	      p
+	  }
+      }]'
+  _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
+    _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi],[])
+  if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
+    _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib"
+  fi
+  ])
+  aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])
+fi
+])# _LT_SYS_MODULE_PATH_AIX
+
+
+# _LT_SHELL_INIT(ARG)
+# -------------------
+m4_define([_LT_SHELL_INIT],
+[m4_divert_text([M4SH-INIT], [$1
+])])# _LT_SHELL_INIT
+
+
+
+# _LT_PROG_ECHO_BACKSLASH
+# -----------------------
+# Find how we can fake an echo command that does not interpret backslash.
+# In particular, with Autoconf 2.60 or later we add some code to the start
+# of the generated configure script which will find a shell with a builtin
+# printf (which we can use as an echo command).
+m4_defun([_LT_PROG_ECHO_BACKSLASH],
+[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+AC_MSG_CHECKING([how to print strings])
+# Test print first, because it will be a builtin if present.
+if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
+   test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='printf %s\n'
+else
+  # Use this function as a fallback that always works.
+  func_fallback_echo ()
+  {
+    eval 'cat <<_LTECHO_EOF
+$[]1
+_LTECHO_EOF'
+  }
+  ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO "$*" 
+}
+
+case "$ECHO" in
+  printf*) AC_MSG_RESULT([printf]) ;;
+  print*) AC_MSG_RESULT([print -r]) ;;
+  *) AC_MSG_RESULT([cat]) ;;
+esac
+
+m4_ifdef([_AS_DETECT_SUGGESTED],
+[_AS_DETECT_SUGGESTED([
+  test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || (
+    ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+    ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+    ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+    PATH=/empty FPATH=/empty; export PATH FPATH
+    test "X`printf %s $ECHO`" = "X$ECHO" \
+      || test "X`print -r -- $ECHO`" = "X$ECHO" )])])
+
+_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
+_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes])
+])# _LT_PROG_ECHO_BACKSLASH
+
+
+# _LT_WITH_SYSROOT
+# ----------------
+AC_DEFUN([_LT_WITH_SYSROOT],
+[AC_MSG_CHECKING([for sysroot])
+AC_ARG_WITH([sysroot],
+[  --with-sysroot[=DIR] Search for dependent libraries within DIR
+                        (or the compiler's sysroot if not specified).],
+[], [with_sysroot=no])
+
+dnl lt_sysroot will always be passed unquoted.  We quote it here
+dnl in case the user passed a directory name.
+lt_sysroot=
+case ${with_sysroot} in #(
+ yes)
+   if test "$GCC" = yes; then
+     lt_sysroot=`$CC --print-sysroot 2>/dev/null`
+   fi
+   ;; #(
+ /*)
+   lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
+   ;; #(
+ no|'')
+   ;; #(
+ *)
+   AC_MSG_RESULT([${with_sysroot}])
+   AC_MSG_ERROR([The sysroot must be an absolute path.])
+   ;;
+esac
+
+ AC_MSG_RESULT([${lt_sysroot:-no}])
+_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl
+[dependent libraries, and in which our libraries should be installed.])])
+
+# _LT_ENABLE_LOCK
+# ---------------
+m4_defun([_LT_ENABLE_LOCK],
+[AC_ARG_ENABLE([libtool-lock],
+  [AS_HELP_STRING([--disable-libtool-lock],
+    [avoid locking (might break parallel builds)])])
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.$ac_objext` in
+      *ELF-32*)
+	HPUX_IA64_MODE="32"
+	;;
+      *ELF-64*)
+	HPUX_IA64_MODE="64"
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+*-*-irix6*)
+  # Find out which ABI we are using.
+  echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    if test "$lt_cv_prog_gnu_ld" = yes; then
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -melf32bsmip"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -melf32bmipn32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -melf64bmip"
+	;;
+      esac
+    else
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -32"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -n32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -64"
+	  ;;
+      esac
+    fi
+  fi
+  rm -rf conftest*
+  ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.o` in
+      *32-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_i386_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    case `/usr/bin/file conftest.o` in
+	      *x86-64*)
+		LD="${LD-ld} -m elf32_x86_64"
+		;;
+	      *)
+		LD="${LD-ld} -m elf_i386"
+		;;
+	    esac
+	    ;;
+	  powerpc64le-*)
+	    LD="${LD-ld} -m elf32lppclinux"
+	    ;;
+	  powerpc64-*)
+	    LD="${LD-ld} -m elf32ppclinux"
+	    ;;
+	  s390x-*linux*)
+	    LD="${LD-ld} -m elf_s390"
+	    ;;
+	  sparc64-*linux*)
+	    LD="${LD-ld} -m elf32_sparc"
+	    ;;
+	esac
+	;;
+      *64-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_x86_64_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    LD="${LD-ld} -m elf_x86_64"
+	    ;;
+	  powerpcle-*)
+	    LD="${LD-ld} -m elf64lppc"
+	    ;;
+	  powerpc-*)
+	    LD="${LD-ld} -m elf64ppc"
+	    ;;
+	  s390*-*linux*|s390*-*tpf*)
+	    LD="${LD-ld} -m elf64_s390"
+	    ;;
+	  sparc*-*linux*)
+	    LD="${LD-ld} -m elf64_sparc"
+	    ;;
+	esac
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  SAVE_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -belf"
+  AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+    [AC_LANG_PUSH(C)
+     AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+     AC_LANG_POP])
+  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+    CFLAGS="$SAVE_CFLAGS"
+  fi
+  ;;
+*-*solaris*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if AC_TRY_EVAL(ac_compile); then
+    case `/usr/bin/file conftest.o` in
+    *64-bit*)
+      case $lt_cv_prog_gnu_ld in
+      yes*)
+        case $host in
+        i?86-*-solaris*)
+          LD="${LD-ld} -m elf_x86_64"
+          ;;
+        sparc*-*-solaris*)
+          LD="${LD-ld} -m elf64_sparc"
+          ;;
+        esac
+        # GNU ld 2.21 introduced _sol2 emulations.  Use them if available.
+        if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
+          LD="${LD-ld}_sol2"
+        fi
+        ;;
+      *)
+	if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+	  LD="${LD-ld} -64"
+	fi
+	;;
+      esac
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+esac
+
+need_locks="$enable_libtool_lock"
+])# _LT_ENABLE_LOCK
+
+
+# _LT_PROG_AR
+# -----------
+m4_defun([_LT_PROG_AR],
+[AC_CHECK_TOOLS(AR, [ar], false)
+: ${AR=ar}
+: ${AR_FLAGS=cru}
+_LT_DECL([], [AR], [1], [The archiver])
+_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive])
+
+AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file],
+  [lt_cv_ar_at_file=no
+   AC_COMPILE_IFELSE([AC_LANG_PROGRAM],
+     [echo conftest.$ac_objext > conftest.lst
+      lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD'
+      AC_TRY_EVAL([lt_ar_try])
+      if test "$ac_status" -eq 0; then
+	# Ensure the archiver fails upon bogus file names.
+	rm -f conftest.$ac_objext libconftest.a
+	AC_TRY_EVAL([lt_ar_try])
+	if test "$ac_status" -ne 0; then
+          lt_cv_ar_at_file=@
+        fi
+      fi
+      rm -f conftest.* libconftest.a
+     ])
+  ])
+
+if test "x$lt_cv_ar_at_file" = xno; then
+  archiver_list_spec=
+else
+  archiver_list_spec=$lt_cv_ar_at_file
+fi
+_LT_DECL([], [archiver_list_spec], [1],
+  [How to feed a file listing to the archiver])
+])# _LT_PROG_AR
+
+
+# _LT_CMD_OLD_ARCHIVE
+# -------------------
+m4_defun([_LT_CMD_OLD_ARCHIVE],
+[_LT_PROG_AR
+
+AC_CHECK_TOOL(STRIP, strip, :)
+test -z "$STRIP" && STRIP=:
+_LT_DECL([], [STRIP], [1], [A symbol stripping program])
+
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+test -z "$RANLIB" && RANLIB=:
+_LT_DECL([], [RANLIB], [1],
+    [Commands used to install an old-style archive])
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+  case $host_os in
+  openbsd*)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
+    ;;
+  *)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
+    ;;
+  esac
+  old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
+fi
+
+case $host_os in
+  darwin*)
+    lock_old_archive_extraction=yes ;;
+  *)
+    lock_old_archive_extraction=no ;;
+esac
+_LT_DECL([], [old_postinstall_cmds], [2])
+_LT_DECL([], [old_postuninstall_cmds], [2])
+_LT_TAGDECL([], [old_archive_cmds], [2],
+    [Commands used to build an old-style archive])
+_LT_DECL([], [lock_old_archive_extraction], [0],
+    [Whether to use a lock for old archive extraction])
+])# _LT_CMD_OLD_ARCHIVE
+
+
+# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#		[OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([_LT_COMPILER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+   m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$3"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       $2=yes
+     fi
+   fi
+   $RM conftest*
+])
+
+if test x"[$]$2" = xyes; then
+    m4_if([$5], , :, [$5])
+else
+    m4_if([$6], , :, [$6])
+fi
+])# _LT_COMPILER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [])
+
+
+# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+#                  [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------
+# Check whether the given linker option works
+AC_DEFUN([_LT_LINKER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+  [$2=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS $3"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&AS_MESSAGE_LOG_FD
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         $2=yes
+       fi
+     else
+       $2=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS="$save_LDFLAGS"
+])
+
+if test x"[$]$2" = xyes; then
+    m4_if([$4], , :, [$4])
+else
+    m4_if([$5], , :, [$5])
+fi
+])# _LT_LINKER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [])
+
+
+# LT_CMD_MAX_LEN
+#---------------
+AC_DEFUN([LT_CMD_MAX_LEN],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+# find the maximum length of command line arguments
+AC_MSG_CHECKING([the maximum length of command line arguments])
+AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
+  i=0
+  teststring="ABCD"
+
+  case $build_os in
+  msdosdjgpp*)
+    # On DJGPP, this test can blow up pretty badly due to problems in libc
+    # (any single argument exceeding 2000 bytes causes a buffer overrun
+    # during glob expansion).  Even if it were fixed, the result of this
+    # check would be larger than it should be.
+    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
+    ;;
+
+  gnu*)
+    # Under GNU Hurd, this test is not required because there is
+    # no limit to the length of command line arguments.
+    # Libtool will interpret -1 as no limit whatsoever
+    lt_cv_sys_max_cmd_len=-1;
+    ;;
+
+  cygwin* | mingw* | cegcc*)
+    # On Win9x/ME, this test blows up -- it succeeds, but takes
+    # about 5 minutes as the teststring grows exponentially.
+    # Worse, since 9x/ME are not pre-emptively multitasking,
+    # you end up with a "frozen" computer, even though with patience
+    # the test eventually succeeds (with a max line length of 256k).
+    # Instead, let's just punt: use the minimum linelength reported by
+    # all of the supported platforms: 8192 (on NT/2K/XP).
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  mint*)
+    # On MiNT this can take a long time and run out of memory.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  amigaos*)
+    # On AmigaOS with pdksh, this test takes hours, literally.
+    # So we just punt and use a minimum line length of 8192.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+    # This has been around since 386BSD, at least.  Likely further.
+    if test -x /sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+    elif test -x /usr/sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+    else
+      lt_cv_sys_max_cmd_len=65536	# usable default for all BSDs
+    fi
+    # And add a safety zone
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    ;;
+
+  interix*)
+    # We know the value 262144 and hardcode it with a safety zone (like BSD)
+    lt_cv_sys_max_cmd_len=196608
+    ;;
+
+  os2*)
+    # The test takes a long time on OS/2.
+    lt_cv_sys_max_cmd_len=8192
+    ;;
+
+  osf*)
+    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+    # nice to cause kernel panics so lets avoid the loop below.
+    # First set a reasonable default.
+    lt_cv_sys_max_cmd_len=16384
+    #
+    if test -x /sbin/sysconfig; then
+      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+        *1*) lt_cv_sys_max_cmd_len=-1 ;;
+      esac
+    fi
+    ;;
+  sco3.2v5*)
+    lt_cv_sys_max_cmd_len=102400
+    ;;
+  sysv5* | sco5v6* | sysv4.2uw2*)
+    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+    if test -n "$kargmax"; then
+      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[	 ]]//'`
+    else
+      lt_cv_sys_max_cmd_len=32768
+    fi
+    ;;
+  *)
+    lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+    if test -n "$lt_cv_sys_max_cmd_len" && \
+	test undefined != "$lt_cv_sys_max_cmd_len"; then
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    else
+      # Make teststring a little bigger before we do anything with it.
+      # a 1K string should be a reasonable start.
+      for i in 1 2 3 4 5 6 7 8 ; do
+        teststring=$teststring$teststring
+      done
+      SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+      # If test is not a shell built-in, we'll probably end up computing a
+      # maximum length that is only half of the actual maximum length, but
+      # we can't tell.
+      while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \
+	         = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+	      test $i != 17 # 1/2 MB should be enough
+      do
+        i=`expr $i + 1`
+        teststring=$teststring$teststring
+      done
+      # Only check the string length outside the loop.
+      lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+      teststring=
+      # Add a significant safety factor because C++ compilers can tack on
+      # massive amounts of additional arguments before passing them to the
+      # linker.  It appears as though 1/2 is a usable value.
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+    fi
+    ;;
+  esac
+])
+if test -n $lt_cv_sys_max_cmd_len ; then
+  AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
+else
+  AC_MSG_RESULT(none)
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+_LT_DECL([], [max_cmd_len], [0],
+    [What is the maximum length of a command?])
+])# LT_CMD_MAX_LEN
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [])
+
+
+# _LT_HEADER_DLFCN
+# ----------------
+m4_defun([_LT_HEADER_DLFCN],
+[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl
+])# _LT_HEADER_DLFCN
+
+
+# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
+#                      ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
+# ----------------------------------------------------------------
+m4_defun([_LT_TRY_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "$cross_compiling" = yes; then :
+  [$4]
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<_LT_EOF
+[#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else
+        {
+	  if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
+          else puts (dlerror ());
+	}
+      /* dlclose (self); */
+    }
+  else
+    puts (dlerror ());
+
+  return status;
+}]
+_LT_EOF
+  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) $1 ;;
+      x$lt_dlneed_uscore) $2 ;;
+      x$lt_dlunknown|x*) $3 ;;
+    esac
+  else :
+    # compilation failed
+    $3
+  fi
+fi
+rm -fr conftest*
+])# _LT_TRY_DLOPEN_SELF
+
+
+# LT_SYS_DLOPEN_SELF
+# ------------------
+AC_DEFUN([LT_SYS_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "x$enable_dlopen" != xyes; then
+  enable_dlopen=unknown
+  enable_dlopen_self=unknown
+  enable_dlopen_self_static=unknown
+else
+  lt_cv_dlopen=no
+  lt_cv_dlopen_libs=
+
+  case $host_os in
+  beos*)
+    lt_cv_dlopen="load_add_on"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ;;
+
+  mingw* | pw32* | cegcc*)
+    lt_cv_dlopen="LoadLibrary"
+    lt_cv_dlopen_libs=
+    ;;
+
+  cygwin*)
+    lt_cv_dlopen="dlopen"
+    lt_cv_dlopen_libs=
+    ;;
+
+  darwin*)
+  # if libdl is installed we need to link against it
+    AC_CHECK_LIB([dl], [dlopen],
+		[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
+    lt_cv_dlopen="dyld"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ])
+    ;;
+
+  *)
+    AC_CHECK_FUNC([shl_load],
+	  [lt_cv_dlopen="shl_load"],
+      [AC_CHECK_LIB([dld], [shl_load],
+	    [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"],
+	[AC_CHECK_FUNC([dlopen],
+	      [lt_cv_dlopen="dlopen"],
+	  [AC_CHECK_LIB([dl], [dlopen],
+		[lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
+	    [AC_CHECK_LIB([svld], [dlopen],
+		  [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
+	      [AC_CHECK_LIB([dld], [dld_link],
+		    [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"])
+	      ])
+	    ])
+	  ])
+	])
+      ])
+    ;;
+  esac
+
+  if test "x$lt_cv_dlopen" != xno; then
+    enable_dlopen=yes
+  else
+    enable_dlopen=no
+  fi
+
+  case $lt_cv_dlopen in
+  dlopen)
+    save_CPPFLAGS="$CPPFLAGS"
+    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+    save_LDFLAGS="$LDFLAGS"
+    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+    save_LIBS="$LIBS"
+    LIBS="$lt_cv_dlopen_libs $LIBS"
+
+    AC_CACHE_CHECK([whether a program can dlopen itself],
+	  lt_cv_dlopen_self, [dnl
+	  _LT_TRY_DLOPEN_SELF(
+	    lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
+	    lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
+    ])
+
+    if test "x$lt_cv_dlopen_self" = xyes; then
+      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+      AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
+	  lt_cv_dlopen_self_static, [dnl
+	  _LT_TRY_DLOPEN_SELF(
+	    lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
+	    lt_cv_dlopen_self_static=no,  lt_cv_dlopen_self_static=cross)
+      ])
+    fi
+
+    CPPFLAGS="$save_CPPFLAGS"
+    LDFLAGS="$save_LDFLAGS"
+    LIBS="$save_LIBS"
+    ;;
+  esac
+
+  case $lt_cv_dlopen_self in
+  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+  *) enable_dlopen_self=unknown ;;
+  esac
+
+  case $lt_cv_dlopen_self_static in
+  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+  *) enable_dlopen_self_static=unknown ;;
+  esac
+fi
+_LT_DECL([dlopen_support], [enable_dlopen], [0],
+	 [Whether dlopen is supported])
+_LT_DECL([dlopen_self], [enable_dlopen_self], [0],
+	 [Whether dlopen of programs is supported])
+_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0],
+	 [Whether dlopen of statically linked programs is supported])
+])# LT_SYS_DLOPEN_SELF
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [])
+
+
+# _LT_COMPILER_C_O([TAGNAME])
+# ---------------------------
+# Check to see if options -c and -o are simultaneously supported by compiler.
+# This macro does not hard code the compiler like AC_PROG_CC_C_O.
+m4_defun([_LT_COMPILER_C_O],
+[m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
+  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
+  [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&AS_MESSAGE_LOG_FD
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+     fi
+   fi
+   chmod u+w . 2>&AS_MESSAGE_LOG_FD
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+])
+_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1],
+	[Does compiler simultaneously support -c and -o options?])
+])# _LT_COMPILER_C_O
+
+
+# _LT_COMPILER_FILE_LOCKS([TAGNAME])
+# ----------------------------------
+# Check to see if we can do hard links to lock some files if needed
+m4_defun([_LT_COMPILER_FILE_LOCKS],
+[m4_require([_LT_ENABLE_LOCK])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_COMPILER_C_O([$1])
+
+hard_links="nottested"
+if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
+  # do not overwrite the value of need_locks provided by the user
+  AC_MSG_CHECKING([if we can lock with hard links])
+  hard_links=yes
+  $RM conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  AC_MSG_RESULT([$hard_links])
+  if test "$hard_links" = no; then
+    AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?])
+])# _LT_COMPILER_FILE_LOCKS
+
+
+# _LT_CHECK_OBJDIR
+# ----------------
+m4_defun([_LT_CHECK_OBJDIR],
+[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
+[rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+  lt_cv_objdir=.libs
+else
+  # MS-DOS does not allow filenames that begin with a dot.
+  lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null])
+objdir=$lt_cv_objdir
+_LT_DECL([], [objdir], [0],
+         [The name of the directory that contains temporary libtool files])dnl
+m4_pattern_allow([LT_OBJDIR])dnl
+AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/",
+  [Define to the sub-directory in which libtool stores uninstalled libraries.])
+])# _LT_CHECK_OBJDIR
+
+
+# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME])
+# --------------------------------------
+# Check hardcoding attributes.
+m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
+[AC_MSG_CHECKING([how to hardcode library paths into programs])
+_LT_TAGVAR(hardcode_action, $1)=
+if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
+   test -n "$_LT_TAGVAR(runpath_var, $1)" ||
+   test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
+
+  # We can hardcode non-existent directories.
+  if test "$_LT_TAGVAR(hardcode_direct, $1)" != no &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
+     test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then
+    # Linking always hardcodes the temporary library directory.
+    _LT_TAGVAR(hardcode_action, $1)=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    _LT_TAGVAR(hardcode_action, $1)=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  _LT_TAGVAR(hardcode_action, $1)=unsupported
+fi
+AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
+
+if test "$_LT_TAGVAR(hardcode_action, $1)" = relink ||
+   test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+     test "$enable_shared" = no; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+_LT_TAGDECL([], [hardcode_action], [0],
+    [How to hardcode a shared library path into an executable])
+])# _LT_LINKER_HARDCODE_LIBPATH
+
+
+# _LT_CMD_STRIPLIB
+# ----------------
+m4_defun([_LT_CMD_STRIPLIB],
+[m4_require([_LT_DECL_EGREP])
+striplib=
+old_striplib=
+AC_MSG_CHECKING([whether stripping libraries is possible])
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  AC_MSG_RESULT([yes])
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+  case $host_os in
+  darwin*)
+    if test -n "$STRIP" ; then
+      striplib="$STRIP -x"
+      old_striplib="$STRIP -S"
+      AC_MSG_RESULT([yes])
+    else
+      AC_MSG_RESULT([no])
+    fi
+    ;;
+  *)
+    AC_MSG_RESULT([no])
+    ;;
+  esac
+fi
+_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
+_LT_DECL([], [striplib], [1])
+])# _LT_CMD_STRIPLIB
+
+
+# _LT_SYS_DYNAMIC_LINKER([TAG])
+# -----------------------------
+# PORTME Fill in your ld.so characteristics
+m4_defun([_LT_SYS_DYNAMIC_LINKER],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_OBJDUMP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+AC_MSG_CHECKING([dynamic linker characteristics])
+m4_if([$1],
+	[], [
+if test "$GCC" = yes; then
+  case $host_os in
+    darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+    *) lt_awk_arg="/^libraries:/" ;;
+  esac
+  case $host_os in
+    mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;;
+    *) lt_sed_strip_eq="s,=/,/,g" ;;
+  esac
+  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+  case $lt_search_path_spec in
+  *\;*)
+    # if the path contains ";" then we assume it to be the separator
+    # otherwise default to the standard path separator (i.e. ":") - it is
+    # assumed that no part of a normal pathname contains ";" but that should
+    # okay in the real world where ";" in dirpaths is itself problematic.
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+    ;;
+  *)
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+    ;;
+  esac
+  # Ok, now we have the path, separated by spaces, we can step through it
+  # and add multilib dir if necessary.
+  lt_tmp_lt_search_path_spec=
+  lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+  for lt_sys_path in $lt_search_path_spec; do
+    if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+    else
+      test -d "$lt_sys_path" && \
+	lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+    fi
+  done
+  lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+  lt_foo="";
+  lt_count=0;
+  for (lt_i = NF; lt_i > 0; lt_i--) {
+    if ($lt_i != "" && $lt_i != ".") {
+      if ($lt_i == "..") {
+        lt_count++;
+      } else {
+        if (lt_count == 0) {
+          lt_foo="/" $lt_i lt_foo;
+        } else {
+          lt_count--;
+        }
+      }
+    }
+  }
+  if (lt_foo != "") { lt_freq[[lt_foo]]++; }
+  if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
+}'`
+  # AWK program above erroneously prepends '/' to C:/dos/paths
+  # for these hosts.
+  case $host_os in
+    mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+      $SED 's,/\([[A-Za-z]]:\),\1,g'` ;;
+  esac
+  sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi])
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='${libname}${release}${shared_ext}$major'
+  ;;
+
+aix[[4-9]]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test "$host_cpu" = ia64; then
+    # AIX 5 supports IA64
+    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line `#! .'.  This would cause the generated library to
+    # depend on `.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[[01]] | aix4.[[01]].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+	   echo ' yes '
+	   echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+	:
+      else
+	can_build_shared=no
+      fi
+      ;;
+    esac
+    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    if test "$aix_use_runtimelinking" = yes; then
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    else
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='${libname}${release}.a $libname.a'
+      soname_spec='${libname}${release}${shared_ext}$major'
+    fi
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  case $host_cpu in
+  powerpc)
+    # Since July 2007 AmigaOS4 officially supports .so libraries.
+    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    ;;
+  m68k)
+    library_names_spec='$libname.ixlibrary $libname.a'
+    # Create ${libname}_ixlibrary.a entries in /sys/libs.
+    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+    ;;
+  esac
+  ;;
+
+beos*)
+  library_names_spec='${libname}${shared_ext}'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi[[45]]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+  version_type=windows
+  shrext_cmds=".dll"
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$cc_basename in
+  yes,*)
+    # gcc
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname~
+      chmod a+x \$dldir/$dlname~
+      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+      fi'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+m4_if([$1], [],[
+      sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
+      ;;
+    mingw* | cegcc*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    esac
+    dynamic_linker='Win32 ld.exe'
+    ;;
+
+  *,cl*)
+    # Native MSVC
+    libname_spec='$name'
+    soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+    library_names_spec='${libname}.dll.lib'
+
+    case $build_os in
+    mingw*)
+      sys_lib_search_path_spec=
+      lt_save_ifs=$IFS
+      IFS=';'
+      for lt_path in $LIB
+      do
+        IFS=$lt_save_ifs
+        # Let DOS variable expansion print the short 8.3 style file name.
+        lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+        sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+      done
+      IFS=$lt_save_ifs
+      # Convert to MSYS style.
+      sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'`
+      ;;
+    cygwin*)
+      # Convert to unix form, then to dos form, then back to unix form
+      # but this time dos style (no spaces!) so that the unix form looks
+      # like /cygdrive/c/PROGRA~1:/cygdr...
+      sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+      sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+      sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      ;;
+    *)
+      sys_lib_search_path_spec="$LIB"
+      if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then
+        # It is most probably a Windows format PATH.
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      # FIXME: find the short name or the path components, as spaces are
+      # common. (e.g. "Program Files" -> "PROGRA~1")
+      ;;
+    esac
+
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+    dynamic_linker='Win32 link.exe'
+    ;;
+
+  *)
+    # Assume MSVC wrapper
+    library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    dynamic_linker='Win32 ld.exe'
+    ;;
+  esac
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+  soname_spec='${libname}${release}${major}$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+m4_if([$1], [],[
+  sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd* | dragonfly*)
+  # DragonFly does not have aout.  When/if they implement a new
+  # versioning mechanism, adjust this.
+  if test -x /usr/bin/objformat; then
+    objformat=`/usr/bin/objformat`
+  else
+    case $host_os in
+    freebsd[[23]].*) objformat=aout ;;
+    *) objformat=elf ;;
+    esac
+  fi
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2.*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.[[01]]* | freebsdelf3.[[01]]*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
+  freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  *) # from 4.6 on, and DragonFly
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+haiku*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  dynamic_linker="$host_os runtime_loader"
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case $host_cpu in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    if test "X$HPUX_IA64_MODE" = X32; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+    fi
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  hppa*64*)
+    shrext_cmds='.sl'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+  postinstall_cmds='chmod 555 $lib'
+  # or fails outright, so override atomically:
+  install_override_mode=555
+  ;;
+
+interix[[3-9]]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+	if test "$lt_cv_prog_gnu_ld" = yes; then
+		version_type=linux # correct to gnu/linux during the next big refactor
+	else
+		version_type=irix
+	fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+
+  # Some binutils ld are patched to set DT_RUNPATH
+  AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath],
+    [lt_cv_shlibpath_overrides_runpath=no
+    save_LDFLAGS=$LDFLAGS
+    save_libdir=$libdir
+    eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
+	 LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
+    AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+      [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
+	 [lt_cv_shlibpath_overrides_runpath=yes])])
+    LDFLAGS=$save_LDFLAGS
+    libdir=$save_libdir
+    ])
+  shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # Append ld.so.conf contents to the search path
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+netbsdelf*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='NetBSD ld.elf_so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+*nto* | *qnx*)
+  version_type=qnx
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='ldqnx.so'
+  ;;
+
+openbsd*)
+  version_type=sunos
+  sys_lib_dlsearch_path_spec="/usr/lib"
+  need_lib_prefix=no
+  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+  case $host_os in
+    openbsd3.3 | openbsd3.3.*)	need_version=yes ;;
+    *)				need_version=no  ;;
+  esac
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    case $host_os in
+      openbsd2.[[89]] | openbsd2.[[89]].*)
+	shlibpath_overrides_runpath=no
+	;;
+      *)
+	shlibpath_overrides_runpath=yes
+	;;
+      esac
+  else
+    shlibpath_overrides_runpath=yes
+  fi
+  ;;
+
+os2*)
+  libname_spec='$name'
+  shrext_cmds=".dll"
+  need_lib_prefix=no
+  library_names_spec='$libname${shared_ext} $libname.a'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=LIBPATH
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  ;;
+
+rdos*)
+  dynamic_linker=no
+  ;;
+
+solaris*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test "$with_gnu_ld" = yes; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec ;then
+    version_type=linux # correct to gnu/linux during the next big refactor
+    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+    soname_spec='$libname${shared_ext}.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  version_type=freebsd-elf
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  if test "$with_gnu_ld" = yes; then
+    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+  else
+    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+    case $host_os in
+      sco3.2v5*)
+        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+	;;
+    esac
+  fi
+  sys_lib_dlsearch_path_spec='/usr/lib'
+  ;;
+
+tpf*)
+  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+uts4*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+AC_MSG_RESULT([$dynamic_linker])
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+  sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+  sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+_LT_DECL([], [variables_saved_for_relink], [1],
+    [Variables whose values should be saved in libtool wrapper scripts and
+    restored at link time])
+_LT_DECL([], [need_lib_prefix], [0],
+    [Do we need the "lib" prefix for modules?])
+_LT_DECL([], [need_version], [0], [Do we need a version for libraries?])
+_LT_DECL([], [version_type], [0], [Library versioning type])
+_LT_DECL([], [runpath_var], [0],  [Shared library runtime path variable])
+_LT_DECL([], [shlibpath_var], [0],[Shared library path variable])
+_LT_DECL([], [shlibpath_overrides_runpath], [0],
+    [Is shlibpath searched before the hard-coded library search path?])
+_LT_DECL([], [libname_spec], [1], [Format of library name prefix])
+_LT_DECL([], [library_names_spec], [1],
+    [[List of archive names.  First name is the real one, the rest are links.
+    The last name is the one that the linker finds with -lNAME]])
+_LT_DECL([], [soname_spec], [1],
+    [[The coded name of the library, if different from the real name]])
+_LT_DECL([], [install_override_mode], [1],
+    [Permission mode override for installation of shared libraries])
+_LT_DECL([], [postinstall_cmds], [2],
+    [Command to use after installation of a shared archive])
+_LT_DECL([], [postuninstall_cmds], [2],
+    [Command to use after uninstallation of a shared archive])
+_LT_DECL([], [finish_cmds], [2],
+    [Commands used to finish a libtool library installation in a directory])
+_LT_DECL([], [finish_eval], [1],
+    [[As "finish_cmds", except a single script fragment to be evaled but
+    not shown]])
+_LT_DECL([], [hardcode_into_libs], [0],
+    [Whether we should hardcode library paths into libraries])
+_LT_DECL([], [sys_lib_search_path_spec], [2],
+    [Compile-time system search path for libraries])
+_LT_DECL([], [sys_lib_dlsearch_path_spec], [2],
+    [Run-time system search path for libraries])
+])# _LT_SYS_DYNAMIC_LINKER
+
+
+# _LT_PATH_TOOL_PREFIX(TOOL)
+# --------------------------
+# find a file program which can recognize shared library
+AC_DEFUN([_LT_PATH_TOOL_PREFIX],
+[m4_require([_LT_DECL_EGREP])dnl
+AC_MSG_CHECKING([for $1])
+AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+[case $MAGIC_CMD in
+[[\\/*] |  ?:[\\/]*])
+  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD="$MAGIC_CMD"
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+dnl $ac_dummy forces splitting on constant user-supplied paths.
+dnl POSIX.2 word splitting is done only on the output of word expansions,
+dnl not every word.  This closes a longstanding sh security hole.
+  ac_dummy="m4_if([$2], , $PATH, [$2])"
+  for ac_dir in $ac_dummy; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/$1; then
+      lt_cv_path_MAGIC_CMD="$ac_dir/$1"
+      if test -n "$file_magic_test_file"; then
+	case $deplibs_check_method in
+	"file_magic "*)
+	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+	    $EGREP "$file_magic_regex" > /dev/null; then
+	    :
+	  else
+	    cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool at gnu.org
+
+_LT_EOF
+	  fi ;;
+	esac
+      fi
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  ;;
+esac])
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+  AC_MSG_RESULT($MAGIC_CMD)
+else
+  AC_MSG_RESULT(no)
+fi
+_LT_DECL([], [MAGIC_CMD], [0],
+	 [Used to examine libraries when file_magic_cmd begins with "file"])dnl
+])# _LT_PATH_TOOL_PREFIX
+
+# Old name:
+AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
+
+
+# _LT_PATH_MAGIC
+# --------------
+# find a file program which can recognize a shared library
+m4_defun([_LT_PATH_MAGIC],
+[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+  if test -n "$ac_tool_prefix"; then
+    _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
+  else
+    MAGIC_CMD=:
+  fi
+fi
+])# _LT_PATH_MAGIC
+
+
+# LT_PATH_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([LT_PATH_LD],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PROG_ECHO_BACKSLASH])dnl
+
+AC_ARG_WITH([gnu-ld],
+    [AS_HELP_STRING([--with-gnu-ld],
+	[assume the C compiler uses GNU ld @<:@default=no@:>@])],
+    [test "$withval" = no || with_gnu_ld=yes],
+    [with_gnu_ld=no])dnl
+
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  AC_MSG_CHECKING([for ld used by $CC])
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [[\\/]]* | ?:[[\\/]]*)
+      re_direlt='/[[^/]][[^/]]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+	ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  AC_MSG_CHECKING([for GNU ld])
+else
+  AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some variants of GNU ld only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+	test "$with_gnu_ld" != no && break
+	;;
+      *)
+	test "$with_gnu_ld" != yes && break
+	;;
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+else
+  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+  AC_MSG_RESULT($LD)
+else
+  AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+_LT_PATH_LD_GNU
+AC_SUBST([LD])
+
+_LT_TAGDECL([], [LD], [1], [The linker used to build libraries])
+])# LT_PATH_LD
+
+# Old names:
+AU_ALIAS([AM_PROG_LD], [LT_PATH_LD])
+AU_ALIAS([AC_PROG_LD], [LT_PATH_LD])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_LD], [])
+dnl AC_DEFUN([AC_PROG_LD], [])
+
+
+# _LT_PATH_LD_GNU
+#- --------------
+m4_defun([_LT_PATH_LD_GNU],
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# _LT_PATH_LD_GNU
+
+
+# _LT_CMD_RELOAD
+# --------------
+# find reload flag for linker
+#   -- PORTME Some linkers may need a different reload flag.
+m4_defun([_LT_CMD_RELOAD],
+[AC_CACHE_CHECK([for $LD option to reload object files],
+  lt_cv_ld_reload_flag,
+  [lt_cv_ld_reload_flag='-r'])
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    if test "$GCC" != yes; then
+      reload_cmds=false
+    fi
+    ;;
+  darwin*)
+    if test "$GCC" = yes; then
+      reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+    else
+      reload_cmds='$LD$reload_flag -o $output$reload_objs'
+    fi
+    ;;
+esac
+_LT_TAGDECL([], [reload_flag], [1], [How to create reloadable object files])dnl
+_LT_TAGDECL([], [reload_cmds], [2])dnl
+])# _LT_CMD_RELOAD
+
+
+# _LT_CHECK_MAGIC_METHOD
+# ----------------------
+# how to check for library dependencies
+#  -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_MAGIC_METHOD],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+AC_CACHE_CHECK([how to recognize dependent libraries],
+lt_cv_deplibs_check_method,
+[lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[[4-9]]*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+beos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+bsdi[[45]]*)
+  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
+  lt_cv_file_magic_cmd='/usr/bin/file -L'
+  lt_cv_file_magic_test_file=/shlib/libc.so
+  ;;
+
+cygwin*)
+  # func_win32_libid is a shell function defined in ltmain.sh
+  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+  lt_cv_file_magic_cmd='func_win32_libid'
+  ;;
+
+mingw* | pw32*)
+  # Base MSYS/MinGW do not provide the 'file' command needed by
+  # func_win32_libid shell function, so use a weaker test based on 'objdump',
+  # unless we find 'file', for example because we are cross-compiling.
+  # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
+  if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
+    lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+    lt_cv_file_magic_cmd='func_win32_libid'
+  else
+    # Keep this pattern in sync with the one in func_win32_libid.
+    lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
+    lt_cv_file_magic_cmd='$OBJDUMP -f'
+  fi
+  ;;
+
+cegcc*)
+  # use the weaker test based on 'objdump'. See mingw*.
+  lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+  lt_cv_file_magic_cmd='$OBJDUMP -f'
+  ;;
+
+darwin* | rhapsody*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+freebsd* | dragonfly*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    case $host_cpu in
+    i*86 )
+      # Not sure whether the presence of OpenBSD here was a mistake.
+      # Let's accept both of them until this is cleared up.
+      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
+      lt_cv_file_magic_cmd=/usr/bin/file
+      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+      ;;
+    esac
+  else
+    lt_cv_deplibs_check_method=pass_all
+  fi
+  ;;
+
+haiku*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+hpux10.20* | hpux11*)
+  lt_cv_file_magic_cmd=/usr/bin/file
+  case $host_cpu in
+  ia64*)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+    ;;
+  hppa*64*)
+    [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]']
+    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+    ;;
+  *)
+    lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library'
+    lt_cv_file_magic_test_file=/usr/lib/libc.sl
+    ;;
+  esac
+  ;;
+
+interix[[3-9]]*)
+  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+  lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $LD in
+  *-32|*"-32 ") libmagic=32-bit;;
+  *-n32|*"-n32 ") libmagic=N32;;
+  *-64|*"-64 ") libmagic=64-bit;;
+  *) libmagic=never-match;;
+  esac
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+netbsd* | netbsdelf*-gnu)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
+  fi
+  ;;
+
+newos6*)
+  lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
+  lt_cv_file_magic_cmd=/usr/bin/file
+  lt_cv_file_magic_test_file=/usr/lib/libnls.so
+  ;;
+
+*nto* | *qnx*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+openbsd*)
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+  fi
+  ;;
+
+osf3* | osf4* | osf5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+rdos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+solaris*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv4 | sysv4.3*)
+  case $host_vendor in
+  motorola)
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+    ;;
+  ncr)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  sequent)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
+    ;;
+  sni)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
+    lt_cv_file_magic_test_file=/lib/libc.so
+    ;;
+  siemens)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  pc)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  esac
+  ;;
+
+tpf*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+esac
+])
+
+file_magic_glob=
+want_nocaseglob=no
+if test "$build" = "$host"; then
+  case $host_os in
+  mingw* | pw32*)
+    if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
+      want_nocaseglob=yes
+    else
+      file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"`
+    fi
+    ;;
+  esac
+fi
+
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+_LT_DECL([], [deplibs_check_method], [1],
+    [Method to check whether dependent libraries are shared objects])
+_LT_DECL([], [file_magic_cmd], [1],
+    [Command to use when deplibs_check_method = "file_magic"])
+_LT_DECL([], [file_magic_glob], [1],
+    [How to find potential files when deplibs_check_method = "file_magic"])
+_LT_DECL([], [want_nocaseglob], [1],
+    [Find potential files using nocaseglob when deplibs_check_method = "file_magic"])
+])# _LT_CHECK_MAGIC_METHOD
+
+
+# LT_PATH_NM
+# ----------
+# find the pathname to a BSD- or MS-compatible name lister
+AC_DEFUN([LT_PATH_NM],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
+[if test -n "$NM"; then
+  # Let the user override the test.
+  lt_cv_path_NM="$NM"
+else
+  lt_nm_to_check="${ac_tool_prefix}nm"
+  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+    lt_nm_to_check="$lt_nm_to_check nm"
+  fi
+  for lt_tmp_nm in $lt_nm_to_check; do
+    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+      IFS="$lt_save_ifs"
+      test -z "$ac_dir" && ac_dir=.
+      tmp_nm="$ac_dir/$lt_tmp_nm"
+      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+	# Check to see if the nm accepts a BSD-compat flag.
+	# Adding the `sed 1q' prevents false positives on HP-UX, which says:
+	#   nm: unknown option "B" ignored
+	# Tru64's nm complains that /dev/null is an invalid object file
+	case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+	*/dev/null* | *'Invalid file or object type'*)
+	  lt_cv_path_NM="$tmp_nm -B"
+	  break
+	  ;;
+	*)
+	  case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+	  */dev/null*)
+	    lt_cv_path_NM="$tmp_nm -p"
+	    break
+	    ;;
+	  *)
+	    lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+	    continue # so that we can try to find one that supports BSD flags
+	    ;;
+	  esac
+	  ;;
+	esac
+      fi
+    done
+    IFS="$lt_save_ifs"
+  done
+  : ${lt_cv_path_NM=no}
+fi])
+if test "$lt_cv_path_NM" != "no"; then
+  NM="$lt_cv_path_NM"
+else
+  # Didn't find any BSD compatible name lister, look for dumpbin.
+  if test -n "$DUMPBIN"; then :
+    # Let the user override the test.
+  else
+    AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :)
+    case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+    *COFF*)
+      DUMPBIN="$DUMPBIN -symbols"
+      ;;
+    *)
+      DUMPBIN=:
+      ;;
+    esac
+  fi
+  AC_SUBST([DUMPBIN])
+  if test "$DUMPBIN" != ":"; then
+    NM="$DUMPBIN"
+  fi
+fi
+test -z "$NM" && NM=nm
+AC_SUBST([NM])
+_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
+
+AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
+  [lt_cv_nm_interface="BSD nm"
+  echo "int some_variable = 0;" > conftest.$ac_ext
+  (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
+  (eval "$ac_compile" 2>conftest.err)
+  cat conftest.err >&AS_MESSAGE_LOG_FD
+  (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
+  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+  cat conftest.err >&AS_MESSAGE_LOG_FD
+  (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD)
+  cat conftest.out >&AS_MESSAGE_LOG_FD
+  if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+    lt_cv_nm_interface="MS dumpbin"
+  fi
+  rm -f conftest*])
+])# LT_PATH_NM
+
+# Old names:
+AU_ALIAS([AM_PROG_NM], [LT_PATH_NM])
+AU_ALIAS([AC_PROG_NM], [LT_PATH_NM])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_NM], [])
+dnl AC_DEFUN([AC_PROG_NM], [])
+
+# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+# --------------------------------
+# how to determine the name of the shared library
+# associated with a specific link library.
+#  -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+m4_require([_LT_DECL_DLLTOOL])
+AC_CACHE_CHECK([how to associate runtime and link libraries],
+lt_cv_sharedlib_from_linklib_cmd,
+[lt_cv_sharedlib_from_linklib_cmd='unknown'
+
+case $host_os in
+cygwin* | mingw* | pw32* | cegcc*)
+  # two different shell functions defined in ltmain.sh
+  # decide which to use based on capabilities of $DLLTOOL
+  case `$DLLTOOL --help 2>&1` in
+  *--identify-strict*)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
+    ;;
+  *)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
+    ;;
+  esac
+  ;;
+*)
+  # fallback: assume linklib IS sharedlib
+  lt_cv_sharedlib_from_linklib_cmd="$ECHO"
+  ;;
+esac
+])
+sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
+test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
+
+_LT_DECL([], [sharedlib_from_linklib_cmd], [1],
+    [Command to associate shared and link libraries])
+])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+
+
+# _LT_PATH_MANIFEST_TOOL
+# ----------------------
+# locate the manifest tool
+m4_defun([_LT_PATH_MANIFEST_TOOL],
+[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :)
+test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
+AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool],
+  [lt_cv_path_mainfest_tool=no
+  echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD
+  $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
+  cat conftest.err >&AS_MESSAGE_LOG_FD
+  if $GREP 'Manifest Tool' conftest.out > /dev/null; then
+    lt_cv_path_mainfest_tool=yes
+  fi
+  rm -f conftest*])
+if test "x$lt_cv_path_mainfest_tool" != xyes; then
+  MANIFEST_TOOL=:
+fi
+_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl
+])# _LT_PATH_MANIFEST_TOOL
+
+
+# LT_LIB_M
+# --------
+# check for math library
+AC_DEFUN([LT_LIB_M],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case $host in
+*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*)
+  # These system don't have libm, or don't need it
+  ;;
+*-ncr-sysv4.3*)
+  AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+  AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
+  ;;
+*)
+  AC_CHECK_LIB(m, cos, LIBM="-lm")
+  ;;
+esac
+AC_SUBST([LIBM])
+])# LT_LIB_M
+
+# Old name:
+AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_CHECK_LIBM], [])
+
+
+# _LT_COMPILER_NO_RTTI([TAGNAME])
+# -------------------------------
+m4_defun([_LT_COMPILER_NO_RTTI],
+[m4_require([_LT_TAG_COMPILER])dnl
+
+_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+
+if test "$GCC" = yes; then
+  case $cc_basename in
+  nvcc*)
+    _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;;
+  *)
+    _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;;
+  esac
+
+  _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
+    lt_cv_prog_compiler_rtti_exceptions,
+    [-fno-rtti -fno-exceptions], [],
+    [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
+fi
+_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
+	[Compiler flag to turn off builtin functions])
+])# _LT_COMPILER_NO_RTTI
+
+
+# _LT_CMD_GLOBAL_SYMBOLS
+# ----------------------
+m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+AC_MSG_CHECKING([command to parse $NM output from $compiler object])
+AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
+[
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[[BCDEGRST]]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+  symcode='[[BCDT]]'
+  ;;
+cygwin* | mingw* | pw32* | cegcc*)
+  symcode='[[ABCDGISTW]]'
+  ;;
+hpux*)
+  if test "$host_cpu" = ia64; then
+    symcode='[[ABCDEGRST]]'
+  fi
+  ;;
+irix* | nonstopux*)
+  symcode='[[BCDEGRST]]'
+  ;;
+osf*)
+  symcode='[[BCDEGQRST]]'
+  ;;
+solaris*)
+  symcode='[[BDRT]]'
+  ;;
+sco3.2v5*)
+  symcode='[[DT]]'
+  ;;
+sysv4.2uw2*)
+  symcode='[[DT]]'
+  ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+  symcode='[[ABDT]]'
+  ;;
+sysv4)
+  symcode='[[DFNSTU]]'
+  ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+  symcode='[[ABCDGIRSTW]]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/  {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/  {\"lib\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+  opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+  ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+  symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+  # Write the raw and C identifiers.
+  if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+    # Fake it for dumpbin and say T for any non-static function
+    # and D for any global variable.
+    # Also find C++ and __fastcall symbols from MSVC++,
+    # which start with @ or ?.
+    lt_cv_sys_global_symbol_pipe="$AWK ['"\
+"     {last_section=section; section=\$ 3};"\
+"     /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
+"     /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+"     \$ 0!~/External *\|/{next};"\
+"     / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+"     {if(hide[section]) next};"\
+"     {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+"     {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+"     s[1]~/^[@?]/{print s[1], s[1]; next};"\
+"     s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+"     ' prfx=^$ac_symprfx]"
+  else
+    lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[	 ]]\($symcode$symcode*\)[[	 ]][[	 ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+  fi
+  lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
+
+  # Check to see that the pipe works correctly.
+  pipe_works=no
+
+  rm -f conftest*
+  cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+  if AC_TRY_EVAL(ac_compile); then
+    # Now try to grab the symbols.
+    nlist=conftest.nm
+    if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then
+      # Try sorting and uniquifying the output.
+      if sort "$nlist" | uniq > "$nlist"T; then
+	mv -f "$nlist"T "$nlist"
+      else
+	rm -f "$nlist"T
+      fi
+
+      # Make sure that we snagged all the symbols we need.
+      if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+	if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+	  cat <<_LT_EOF > conftest.$ac_ext
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
+/* DATA imports from DLLs on WIN32 con't be const, because runtime
+   relocations are performed -- see ld's documentation on pseudo-relocs.  */
+# define LT@&t at _DLSYM_CONST
+#elif defined(__osf__)
+/* This system does not cope well with relocations in const data.  */
+# define LT@&t at _DLSYM_CONST
+#else
+# define LT@&t at _DLSYM_CONST const
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+	  # Now generate the symbol file.
+	  eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+	  cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols.  */
+LT@&t at _DLSYM_CONST struct {
+  const char *name;
+  void       *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[[]] =
+{
+  { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+	  $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+	  cat <<\_LT_EOF >> conftest.$ac_ext
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+	  # Now try linking the two files.
+	  mv conftest.$ac_objext conftstm.$ac_objext
+	  lt_globsym_save_LIBS=$LIBS
+	  lt_globsym_save_CFLAGS=$CFLAGS
+	  LIBS="conftstm.$ac_objext"
+	  CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
+	  if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
+	    pipe_works=yes
+	  fi
+	  LIBS=$lt_globsym_save_LIBS
+	  CFLAGS=$lt_globsym_save_CFLAGS
+	else
+	  echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
+	fi
+      else
+	echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
+      fi
+    else
+      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
+    fi
+  else
+    echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
+    cat conftest.$ac_ext >&5
+  fi
+  rm -rf conftest* conftst*
+
+  # Do not use the global_symbol_pipe unless it works.
+  if test "$pipe_works" = yes; then
+    break
+  else
+    lt_cv_sys_global_symbol_pipe=
+  fi
+done
+])
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+  lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+  AC_MSG_RESULT(failed)
+else
+  AC_MSG_RESULT(ok)
+fi
+
+# Response file support.
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+  nm_file_list_spec='@'
+elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then
+  nm_file_list_spec='@'
+fi
+
+_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
+    [Take the output of nm and produce a listing of raw symbols and C names])
+_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
+    [Transform the output of nm in a proper C declaration])
+_LT_DECL([global_symbol_to_c_name_address],
+    [lt_cv_sys_global_symbol_to_c_name_address], [1],
+    [Transform the output of nm in a C name address pair])
+_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
+    [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
+    [Transform the output of nm in a C name address pair when lib prefix is needed])
+_LT_DECL([], [nm_file_list_spec], [1],
+    [Specify filename containing input files for $NM])
+]) # _LT_CMD_GLOBAL_SYMBOLS
+
+
+# _LT_COMPILER_PIC([TAGNAME])
+# ---------------------------
+m4_defun([_LT_COMPILER_PIC],
+[m4_require([_LT_TAG_COMPILER])dnl
+_LT_TAGVAR(lt_prog_compiler_wl, $1)=
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+_LT_TAGVAR(lt_prog_compiler_static, $1)=
+
+m4_if([$1], [CXX], [
+  # C++ specific cases for pic, static, wl, etc.
+  if test "$GXX" = yes; then
+    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+    case $host_os in
+    aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the `-m68020' flag to GCC prevents building anything better,
+            # like `-m68040'.
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+    mingw* | cygwin* | os2* | pw32* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      m4_if([$1], [GCJ], [],
+	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      ;;
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
+    *djgpp*)
+      # DJGPP does not support shared libraries at all
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+      ;;
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)=
+      ;;
+    interix[[3-9]]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	;;
+      esac
+      ;;
+    *qnx* | *nto*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+    *)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+  else
+    case $host_os in
+      aix[[4-9]]*)
+	# All AIX code is PIC.
+	if test "$host_cpu" = ia64; then
+	  # AIX 5 now supports IA64 processor
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	else
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+	fi
+	;;
+      chorus*)
+	case $cc_basename in
+	cxch68*)
+	  # Green Hills C++ Compiler
+	  # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+	  ;;
+	esac
+	;;
+      mingw* | cygwin* | os2* | pw32* | cegcc*)
+	# This hack is so that the source file can tell whether it is being
+	# built for inclusion in a dll (and should export symbols for example).
+	m4_if([$1], [GCJ], [],
+	  [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+	;;
+      dgux*)
+	case $cc_basename in
+	  ec++*)
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    ;;
+	  ghcx*)
+	    # Green Hills C++ Compiler
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      freebsd* | dragonfly*)
+	# FreeBSD uses GNU C++
+	;;
+      hpux9* | hpux10* | hpux11*)
+	case $cc_basename in
+	  CC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+	    if test "$host_cpu" != ia64; then
+	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	    fi
+	    ;;
+	  aCC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+	    case $host_cpu in
+	    hppa*64*|ia64*)
+	      # +Z the default
+	      ;;
+	    *)
+	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	      ;;
+	    esac
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      interix*)
+	# This is c89, which is MS Visual C++ (no shared libs)
+	# Anyone wants to do a port?
+	;;
+      irix5* | irix6* | nonstopux*)
+	case $cc_basename in
+	  CC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    # CC pic flag -KPIC is the default.
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+	case $cc_basename in
+	  KCC*)
+	    # KAI C++ Compiler
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	    ;;
+	  ecpc* )
+	    # old Intel C++ for x86_64 which still supported -KPIC.
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+	    ;;
+	  icpc* )
+	    # Intel C++, used to be incompatible with GCC.
+	    # ICC 10 doesn't accept -KPIC any more.
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+	    ;;
+	  pgCC* | pgcpp*)
+	    # Portland Group C++ compiler
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    ;;
+	  cxx*)
+	    # Compaq C++
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    ;;
+	  xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*)
+	    # IBM XL 8.0, 9.0 on PPC and BlueGene
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+	    ;;
+	  *)
+	    case `$CC -V 2>&1 | sed 5q` in
+	    *Sun\ C*)
+	      # Sun C++ 5.9
+	      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+	      ;;
+	    esac
+	    ;;
+	esac
+	;;
+      lynxos*)
+	;;
+      m88k*)
+	;;
+      mvs*)
+	case $cc_basename in
+	  cxx*)
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      netbsd* | netbsdelf*-gnu)
+	;;
+      *qnx* | *nto*)
+        # QNX uses GNU C++, but need to define -shared option too, otherwise
+        # it will coredump.
+        _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+        ;;
+      osf3* | osf4* | osf5*)
+	case $cc_basename in
+	  KCC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+	    ;;
+	  RCC*)
+	    # Rational C++ 2.4.1
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  cxx*)
+	    # Digital/Compaq C++
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    # Make sure the PIC flag is empty.  It appears that all Alpha
+	    # Linux and Compaq Tru64 Unix objects are PIC.
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      psos*)
+	;;
+      solaris*)
+	case $cc_basename in
+	  CC* | sunCC*)
+	    # Sun C++ 4.2, 5.x and Centerline C++
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+	    ;;
+	  gcx*)
+	    # Green Hills C++ Compiler
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      sunos4*)
+	case $cc_basename in
+	  CC*)
+	    # Sun C++ 4.x
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    ;;
+	  lcc*)
+	    # Lucid
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+	case $cc_basename in
+	  CC*)
+	    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	    ;;
+	esac
+	;;
+      tandem*)
+	case $cc_basename in
+	  NCC*)
+	    # NonStop-UX NCC 3.20
+	    _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      vxworks*)
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+	;;
+    esac
+  fi
+],
+[
+  if test "$GCC" = yes; then
+    _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+    _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+    case $host_os in
+      aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the `-m68020' flag to GCC prevents building anything better,
+            # like `-m68040'.
+            _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      m4_if([$1], [GCJ], [],
+	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+      ;;
+
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)=
+      ;;
+
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+	# +Z the default
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	;;
+      esac
+      ;;
+
+    interix[[3-9]]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+
+    msdosdjgpp*)
+      # Just because we use GCC doesn't mean we suddenly get shared libraries
+      # on systems that don't support them.
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      enable_shared=no
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+      fi
+      ;;
+
+    *)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+      ;;
+    esac
+
+    case $cc_basename in
+    nvcc*) # Cuda Compiler Driver 2.2
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker '
+      if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+        _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)"
+      fi
+      ;;
+    esac
+  else
+    # PORTME Check for flag to pass linker flags through the system compiler.
+    case $host_os in
+    aix*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      else
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+      fi
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      m4_if([$1], [GCJ], [],
+	[_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+      ;;
+
+    hpux9* | hpux10* | hpux11*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case $host_cpu in
+      hppa*64*|ia64*)
+	# +Z the default
+	;;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+	;;
+      esac
+      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # PIC (with -KPIC) is the default.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+      case $cc_basename in
+      # old Intel for x86_64 which still supported -KPIC.
+      ecc*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+        ;;
+      # icc used to be incompatible with GCC.
+      # ICC 10 doesn't accept -KPIC any more.
+      icc* | ifort*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+        ;;
+      # Lahey Fortran 8.1.
+      lf95*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='--static'
+	;;
+      nagfor*)
+	# NAG Fortran compiler
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	;;
+      pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+        # Portland Group compilers (*not* the Pentium gcc compiler,
+	# which looks to be a dead project)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+        ;;
+      ccc*)
+        _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+        # All Alpha code is PIC.
+        _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+        ;;
+      xl* | bgxl* | bgf* | mpixl*)
+	# IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+	;;
+      *)
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*)
+	  # Sun Fortran 8.3 passes all unrecognized flags to the linker
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
+	  ;;
+	*Sun\ F* | *Sun*Fortran*)
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+	  ;;
+	*Sun\ C*)
+	  # Sun C 5.9
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	  ;;
+        *Intel*\ [[CF]]*Compiler*)
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+	  ;;
+	*Portland\ Group*)
+	  _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	  _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+	  _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+	  ;;
+	esac
+	;;
+      esac
+      ;;
+
+    newsos6)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+      ;;
+
+    osf3* | osf4* | osf5*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      # All OSF/1 code is PIC.
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    rdos*)
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+      ;;
+
+    solaris*)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      case $cc_basename in
+      f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
+      *)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
+      esac
+      ;;
+
+    sunos4*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    sysv4 | sysv4.2uw2* | sysv4.3*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec ;then
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      fi
+      ;;
+
+    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    unicos*)
+      _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      ;;
+
+    uts4*)
+      _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+      _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+      ;;
+
+    *)
+      _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+      ;;
+    esac
+  fi
+])
+case $host_os in
+  # For platforms which do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+    ;;
+  *)
+    _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t at m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])"
+    ;;
+esac
+
+AC_CACHE_CHECK([for $compiler option to produce PIC],
+  [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)],
+  [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)])
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+  _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works],
+    [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)],
+    [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t at m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [],
+    [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in
+     "" | " "*) ;;
+     *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;;
+     esac],
+    [_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+     _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
+fi
+_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1],
+	[Additional compiler flags for building library objects])
+
+_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1],
+	[How to pass a linker flag through the compiler])
+#
+# Check to make sure the static flag actually works.
+#
+wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\"
+_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
+  _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1),
+  $lt_tmp_static_flag,
+  [],
+  [_LT_TAGVAR(lt_prog_compiler_static, $1)=])
+_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1],
+	[Compiler flag to prevent dynamic linking])
+])# _LT_COMPILER_PIC
+
+
+# _LT_LINKER_SHLIBS([TAGNAME])
+# ----------------------------
+# See if the linker supports building shared libraries.
+m4_defun([_LT_LINKER_SHLIBS],
+[AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+m4_require([_LT_PATH_MANIFEST_TOOL])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+m4_if([$1], [CXX], [
+  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+  case $host_os in
+  aix[[4-9]]*)
+    # If we're using GNU nm, then we don't want the "-C" option.
+    # -C means demangle to AIX nm, but means don't demangle with GNU nm
+    # Also, AIX nm treats weak defined symbols like other global defined
+    # symbols, whereas GNU nm marks them as "W".
+    if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+    else
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+    fi
+    ;;
+  pw32*)
+    _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
+    ;;
+  cygwin* | mingw* | cegcc*)
+    case $cc_basename in
+    cl*)
+      _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+      ;;
+    *)
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+      _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+      ;;
+    esac
+    ;;
+  linux* | k*bsd*-gnu | gnu*)
+    _LT_TAGVAR(link_all_deplibs, $1)=no
+    ;;
+  *)
+    _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+    ;;
+  esac
+], [
+  runpath_var=
+  _LT_TAGVAR(allow_undefined_flag, $1)=
+  _LT_TAGVAR(always_export_symbols, $1)=no
+  _LT_TAGVAR(archive_cmds, $1)=
+  _LT_TAGVAR(archive_expsym_cmds, $1)=
+  _LT_TAGVAR(compiler_needs_object, $1)=no
+  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+  _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+  _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  _LT_TAGVAR(hardcode_automatic, $1)=no
+  _LT_TAGVAR(hardcode_direct, $1)=no
+  _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+  _LT_TAGVAR(hardcode_libdir_separator, $1)=
+  _LT_TAGVAR(hardcode_minus_L, $1)=no
+  _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+  _LT_TAGVAR(inherit_rpath, $1)=no
+  _LT_TAGVAR(link_all_deplibs, $1)=unknown
+  _LT_TAGVAR(module_cmds, $1)=
+  _LT_TAGVAR(module_expsym_cmds, $1)=
+  _LT_TAGVAR(old_archive_from_new_cmds, $1)=
+  _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)=
+  _LT_TAGVAR(thread_safe_flag_spec, $1)=
+  _LT_TAGVAR(whole_archive_flag_spec, $1)=
+  # include_expsyms should be a list of space-separated symbols to be *always*
+  # included in the symbol list
+  _LT_TAGVAR(include_expsyms, $1)=
+  # exclude_expsyms can be an extended regexp of symbols to exclude
+  # it will be wrapped by ` (' and `)$', so one must not match beginning or
+  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+  # as well as any symbol that contains `d'.
+  _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+  # platforms (ab)use it in PIC code, but their linkers get confused if
+  # the symbol is explicitly referenced.  Since portable code cannot
+  # rely on this symbol name, it's probably fine to never include it in
+  # preloaded symbol tables.
+  # Exclude shared library initialization/finalization symbols.
+dnl Note also adjust exclude_expsyms for C++ above.
+  extract_expsyms_cmds=
+
+  case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test "$GCC" != yes; then
+      with_gnu_ld=no
+    fi
+    ;;
+  interix*)
+    # we just hope/assume this is gcc and not c89 (= MSVC++)
+    with_gnu_ld=yes
+    ;;
+  openbsd*)
+    with_gnu_ld=no
+    ;;
+  linux* | k*bsd*-gnu | gnu*)
+    _LT_TAGVAR(link_all_deplibs, $1)=no
+    ;;
+  esac
+
+  _LT_TAGVAR(ld_shlibs, $1)=yes
+
+  # On some targets, GNU ld is compatible enough with the native linker
+  # that we're better off using the native interface for both.
+  lt_use_gnu_ld_interface=no
+  if test "$with_gnu_ld" = yes; then
+    case $host_os in
+      aix*)
+	# The AIX port of GNU ld has always aspired to compatibility
+	# with the native linker.  However, as the warning in the GNU ld
+	# block says, versions before 2.19.5* couldn't really create working
+	# shared libraries, regardless of the interface used.
+	case `$LD -v 2>&1` in
+	  *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+	  *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;;
+	  *\ \(GNU\ Binutils\)\ [[3-9]]*) ;;
+	  *)
+	    lt_use_gnu_ld_interface=yes
+	    ;;
+	esac
+	;;
+      *)
+	lt_use_gnu_ld_interface=yes
+	;;
+    esac
+  fi
+
+  if test "$lt_use_gnu_ld_interface" = yes; then
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    wlarc='${wl}'
+
+    # Set some defaults for GNU ld with shared library support. These
+    # are reset later if shared libraries are not supported. Putting them
+    # here allows them to be overridden if necessary.
+    runpath_var=LD_RUN_PATH
+    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+      _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+    else
+      _LT_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+    supports_anon_versioning=no
+    case `$LD -v 2>&1` in
+      *GNU\ gold*) supports_anon_versioning=yes ;;
+      *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+      *\ 2.11.*) ;; # other 2.11 versions
+      *) supports_anon_versioning=yes ;;
+    esac
+
+    # See if GNU ld supports shared libraries.
+    case $host_os in
+    aix[[3-9]]*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test "$host_cpu" != ia64; then
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support.  If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            _LT_TAGVAR(archive_expsym_cmds, $1)=''
+        ;;
+      m68k)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes
+        ;;
+      esac
+      ;;
+
+    beos*)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	# Joseph Beckenbach <jrb3 at best.com> says some releases of gcc
+	# support --undefined.  This deserves some investigation.  FIXME
+	_LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+      # as there is no search path for DLLs.
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_TAGVAR(always_export_symbols, $1)=no
+      _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+      _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+      _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+
+      if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	# If the export-symbols file already is a .def file (1st line
+	# is EXPORTS), use it as is; otherwise, prepend...
+	_LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	  cp $export_symbols $output_objdir/$soname.def;
+	else
+	  echo EXPORTS > $output_objdir/$soname.def;
+	  cat $export_symbols >> $output_objdir/$soname.def;
+	fi~
+	$CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    haiku*)
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    interix[[3-9]]*)
+      _LT_TAGVAR(hardcode_direct, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+      # Instead, shared libraries are loaded at an image base (0x10000000 by
+      # default) and relocated if they conflict, which is a slow very memory
+      # consuming and fragmenting process.  To avoid this, we pick a random,
+      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      ;;
+
+    gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+      tmp_diet=no
+      if test "$host_os" = linux-dietlibc; then
+	case $cc_basename in
+	  diet\ *) tmp_diet=yes;;	# linux-dietlibc with static linking (!diet-dyn)
+	esac
+      fi
+      if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+	 && test "$tmp_diet" = no
+      then
+	tmp_addflag=' $pic_flag'
+	tmp_sharedflag='-shared'
+	case $cc_basename,$host_cpu in
+        pgcc*)				# Portland Group C compiler
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  tmp_addflag=' $pic_flag'
+	  ;;
+	pgf77* | pgf90* | pgf95* | pgfortran*)
+					# Portland Group f77 and f90 compilers
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  tmp_addflag=' $pic_flag -Mnomain' ;;
+	ecc*,ia64* | icc*,ia64*)	# Intel C compiler on ia64
+	  tmp_addflag=' -i_dynamic' ;;
+	efc*,ia64* | ifort*,ia64*)	# Intel Fortran compiler on ia64
+	  tmp_addflag=' -i_dynamic -nofor_main' ;;
+	ifc* | ifort*)			# Intel Fortran compiler
+	  tmp_addflag=' -nofor_main' ;;
+	lf95*)				# Lahey Fortran 8.1
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)=
+	  tmp_sharedflag='--shared' ;;
+	xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+	  tmp_sharedflag='-qmkshrobj'
+	  tmp_addflag= ;;
+	nvcc*)	# Cuda Compiler Driver 2.2
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  _LT_TAGVAR(compiler_needs_object, $1)=yes
+	  ;;
+	esac
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ C*)			# Sun C 5.9
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  _LT_TAGVAR(compiler_needs_object, $1)=yes
+	  tmp_sharedflag='-G' ;;
+	*Sun\ F*)			# Sun Fortran 8.3
+	  tmp_sharedflag='-G' ;;
+	esac
+	_LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+        if test "x$supports_anon_versioning" = xyes; then
+          _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+	    cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+	    echo "local: *; };" >> $output_objdir/$libname.ver~
+	    $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+        fi
+
+	case $cc_basename in
+	xlf* | bgf* | bgxlf* | mpixlf*)
+	  # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
+	  if test "x$supports_anon_versioning" = xyes; then
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+	      cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+	      echo "local: *; };" >> $output_objdir/$libname.ver~
+	      $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+	  fi
+	  ;;
+	esac
+      else
+        _LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    netbsd* | netbsdelf*-gnu)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+	wlarc=
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      fi
+      ;;
+
+    solaris*)
+      if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+      elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+      case `$LD -v 2>&1` in
+        *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+	;;
+	*)
+	  # For security reasons, it is highly recommended that you always
+	  # use absolute paths for naming shared libraries, and exclude the
+	  # DT_RUNPATH tag from executables and libraries.  But doing so
+	  # requires that you compile everything twice, which is a pain.
+	  if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+	  else
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	  fi
+	;;
+      esac
+      ;;
+
+    sunos4*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      wlarc=
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+    esac
+
+    if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then
+      runpath_var=
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+      _LT_TAGVAR(whole_archive_flag_spec, $1)=
+    fi
+  else
+    # PORTME fill in a description of your system's linker (not GNU ld)
+    case $host_os in
+    aix3*)
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_TAGVAR(always_export_symbols, $1)=yes
+      _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+	# Neither direct hardcoding nor static linking is supported with a
+	# broken collect2.
+	_LT_TAGVAR(hardcode_direct, $1)=unsupported
+      fi
+      ;;
+
+    aix[[4-9]]*)
+      if test "$host_cpu" = ia64; then
+	# On IA64, the linker does run time linking by default, so we don't
+	# have to do anything special.
+	aix_use_runtimelinking=no
+	exp_sym_flag='-Bexport'
+	no_entry_flag=""
+      else
+	# If we're using GNU nm, then we don't want the "-C" option.
+	# -C means demangle to AIX nm, but means don't demangle with GNU nm
+	# Also, AIX nm treats weak defined symbols like other global
+	# defined symbols, whereas GNU nm marks them as "W".
+	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+	  _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	else
+	  _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	fi
+	aix_use_runtimelinking=no
+
+	# Test if we are trying to use run time linking or normal
+	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
+	# need to do runtime linking.
+	case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+	  for ld_flag in $LDFLAGS; do
+	  if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+	    aix_use_runtimelinking=yes
+	    break
+	  fi
+	  done
+	  ;;
+	esac
+
+	exp_sym_flag='-bexport'
+	no_entry_flag='-bnoentry'
+      fi
+
+      # When large executables or shared objects are built, AIX ld can
+      # have problems creating the table of contents.  If linking a library
+      # or program results in "error TOC overflow" add -mminimal-toc to
+      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+      _LT_TAGVAR(archive_cmds, $1)=''
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+      if test "$GCC" = yes; then
+	case $host_os in aix4.[[012]]|aix4.[[012]].*)
+	# We only want to do this on AIX 4.2 and lower, the check
+	# below for broken collect2 doesn't work under 4.3+
+	  collect2name=`${CC} -print-prog-name=collect2`
+	  if test -f "$collect2name" &&
+	   strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+	  then
+	  # We have reworked collect2
+	  :
+	  else
+	  # We have old collect2
+	  _LT_TAGVAR(hardcode_direct, $1)=unsupported
+	  # It fails to find uninstalled libraries when the uninstalled
+	  # path is not listed in the libpath.  Setting hardcode_minus_L
+	  # to unsupported forces relinking
+	  _LT_TAGVAR(hardcode_minus_L, $1)=yes
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+	  _LT_TAGVAR(hardcode_libdir_separator, $1)=
+	  fi
+	  ;;
+	esac
+	shared_flag='-shared'
+	if test "$aix_use_runtimelinking" = yes; then
+	  shared_flag="$shared_flag "'${wl}-G'
+	fi
+	_LT_TAGVAR(link_all_deplibs, $1)=no
+      else
+	# not using gcc
+	if test "$host_cpu" = ia64; then
+	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	# chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+	else
+	  if test "$aix_use_runtimelinking" = yes; then
+	    shared_flag='${wl}-G'
+	  else
+	    shared_flag='${wl}-bM:SRE'
+	  fi
+	fi
+      fi
+
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+      # It seems that -bexpall does not export symbols beginning with
+      # underscore (_), so it is better to generate a list of symbols to export.
+      _LT_TAGVAR(always_export_symbols, $1)=yes
+      if test "$aix_use_runtimelinking" = yes; then
+	# Warning - without using the other runtime loading flags (-brtl),
+	# -berok will link without error, but may produce a broken library.
+	_LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+        # Determine the default libpath from the value encoded in an
+        # empty executable.
+        _LT_SYS_MODULE_PATH_AIX([$1])
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+      else
+	if test "$host_cpu" = ia64; then
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+	  _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+	  _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+	else
+	 # Determine the default libpath from the value encoded in an
+	 # empty executable.
+	 _LT_SYS_MODULE_PATH_AIX([$1])
+	 _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+	  # Warning - without using the other run time loading flags,
+	  # -berok will link without error, but may produce a broken library.
+	  _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+	  _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+	  if test "$with_gnu_ld" = yes; then
+	    # We only use this code for GNU lds that support --whole-archive.
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	  else
+	    # Exported symbols can be pulled into shared objects from archives
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+	  fi
+	  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+	  # This is similar to how AIX traditionally builds its shared libraries.
+	  _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+	fi
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            _LT_TAGVAR(archive_expsym_cmds, $1)=''
+        ;;
+      m68k)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes
+        ;;
+      esac
+      ;;
+
+    bsdi[[45]]*)
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      case $cc_basename in
+      cl*)
+	# Native MSVC
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	_LT_TAGVAR(always_export_symbols, $1)=yes
+	_LT_TAGVAR(file_list_spec, $1)='@'
+	# Tell ltmain to make .lib files, not .a files.
+	libext=lib
+	# Tell ltmain to make .dll files, not .so files.
+	shrext_cmds=".dll"
+	# FIXME: Setting linknames here is a bad hack.
+	_LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
+	_LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	    sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
+	  else
+	    sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
+	  fi~
+	  $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+	  linknames='
+	# The linker will not automatically build a static lib if we build a DLL.
+	# _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+	_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+	_LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+	_LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
+	# Don't use ranlib
+	_LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
+	_LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
+	  lt_tool_outputfile="@TOOL_OUTPUT@"~
+	  case $lt_outputfile in
+	    *.exe|*.EXE) ;;
+	    *)
+	      lt_outputfile="$lt_outputfile.exe"
+	      lt_tool_outputfile="$lt_tool_outputfile.exe"
+	      ;;
+	  esac~
+	  if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
+	    $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+	    $RM "$lt_outputfile.manifest";
+	  fi'
+	;;
+      *)
+	# Assume MSVC wrapper
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	# Tell ltmain to make .lib files, not .a files.
+	libext=lib
+	# Tell ltmain to make .dll files, not .so files.
+	shrext_cmds=".dll"
+	# FIXME: Setting linknames here is a bad hack.
+	_LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+	# The linker will automatically build a .lib file if we build a DLL.
+	_LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+	# FIXME: Should let the user specify the lib program.
+	_LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
+	_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+	;;
+      esac
+      ;;
+
+    darwin* | rhapsody*)
+      _LT_DARWIN_LINKER_FEATURES($1)
+      ;;
+
+    dgux*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+    # support.  Future versions do this automatically, but an explicit c++rt0.o
+    # does not break anything, and helps significantly (at the cost of a little
+    # extra space).
+    freebsd2.2*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+    freebsd2.*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+    freebsd* | dragonfly*)
+      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    hpux9*)
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+      ;;
+
+    hpux10*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      if test "$with_gnu_ld" = no; then
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+	_LT_TAGVAR(hardcode_libdir_separator, $1)=:
+	_LT_TAGVAR(hardcode_direct, $1)=yes
+	_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	# hardcode_minus_L: Not really in the search PATH,
+	# but as the default location of the library.
+	_LT_TAGVAR(hardcode_minus_L, $1)=yes
+      fi
+      ;;
+
+    hpux11*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+	case $host_cpu in
+	hppa*64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	esac
+      else
+	case $host_cpu in
+	hppa*64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	m4_if($1, [], [
+	  # Older versions of the 11.00 compiler do not understand -b yet
+	  # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+	  _LT_LINKER_OPTION([if $CC understands -b],
+	    _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b],
+	    [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
+	    [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])],
+	  [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
+	  ;;
+	esac
+      fi
+      if test "$with_gnu_ld" = no; then
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+	_LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	case $host_cpu in
+	hppa*64*|ia64*)
+	  _LT_TAGVAR(hardcode_direct, $1)=no
+	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	  ;;
+	*)
+	  _LT_TAGVAR(hardcode_direct, $1)=yes
+	  _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+
+	  # hardcode_minus_L: Not really in the search PATH,
+	  # but as the default location of the library.
+	  _LT_TAGVAR(hardcode_minus_L, $1)=yes
+	  ;;
+	esac
+      fi
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	# Try to use the -exported_symbol ld option, if it does not
+	# work, assume that -exports_file does not work either and
+	# implicitly export all symbols.
+	# This should be the same for all languages, so no per-tag cache variable.
+	AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol],
+	  [lt_cv_irix_exported_symbol],
+	  [save_LDFLAGS="$LDFLAGS"
+	   LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+	   AC_LINK_IFELSE(
+	     [AC_LANG_SOURCE(
+	        [AC_LANG_CASE([C], [[int foo (void) { return 0; }]],
+			      [C++], [[int foo (void) { return 0; }]],
+			      [Fortran 77], [[
+      subroutine foo
+      end]],
+			      [Fortran], [[
+      subroutine foo
+      end]])])],
+	      [lt_cv_irix_exported_symbol=yes],
+	      [lt_cv_irix_exported_symbol=no])
+           LDFLAGS="$save_LDFLAGS"])
+	if test "$lt_cv_irix_exported_symbol" = yes; then
+          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+	fi
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(inherit_rpath, $1)=yes
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    netbsd* | netbsdelf*-gnu)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    newsos6)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *nto* | *qnx*)
+      ;;
+
+    openbsd*)
+      if test -f /usr/libexec/ld.so; then
+	_LT_TAGVAR(hardcode_direct, $1)=yes
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	_LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	else
+	  case $host_os in
+	   openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
+	     _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+	     _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	     ;;
+	   *)
+	     _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	     _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	     ;;
+	  esac
+	fi
+      else
+	_LT_TAGVAR(ld_shlibs, $1)=no
+      fi
+      ;;
+
+    os2*)
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+      _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+      _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+      ;;
+
+    osf3*)
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+	_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      ;;
+
+    osf4* | osf5*)	# as osf3* with the addition of -msym flag
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+      else
+	_LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+	$CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+	# Both c and cxx compiler support -rpath directly
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+      fi
+      _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+      ;;
+
+    solaris*)
+      _LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
+      if test "$GCC" = yes; then
+	wlarc='${wl}'
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+      else
+	case `$CC -V 2>&1` in
+	*"Compilers 5.0"*)
+	  wlarc=''
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+	  ;;
+	*)
+	  wlarc='${wl}'
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+	  ;;
+	esac
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      case $host_os in
+      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+      *)
+	# The compiler driver will combine and reorder linker options,
+	# but understands `-z linker_flag'.  GCC discards it without `$wl',
+	# but is careful enough not to reorder.
+	# Supported since Solaris 2.6 (maybe 2.5.1?)
+	if test "$GCC" = yes; then
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+	else
+	  _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+	fi
+	;;
+      esac
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      ;;
+
+    sunos4*)
+      if test "x$host_vendor" = xsequent; then
+	# Use $CC to link under sequent, because it throws in some extra .o
+	# files that make .init and .fini sections work.
+	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_direct, $1)=yes
+      _LT_TAGVAR(hardcode_minus_L, $1)=yes
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv4)
+      case $host_vendor in
+	sni)
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true???
+	;;
+	siemens)
+	  ## LD is ld it makes a PLAMLIB
+	  ## CC just makes a GrossModule.
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
+	  _LT_TAGVAR(hardcode_direct, $1)=no
+        ;;
+	motorola)
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
+	;;
+      esac
+      runpath_var='LD_RUN_PATH'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    sysv4.3*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	_LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	runpath_var=LD_RUN_PATH
+	hardcode_runpath_var=yes
+	_LT_TAGVAR(ld_shlibs, $1)=yes
+      fi
+      ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6*)
+      # Note: We can NOT use -z defs as we might desire, because we do not
+      # link with -lc, and that would cause any symbols used from libc to
+      # always be unresolved, which means just about no library would
+      # ever link correctly.  If we're not using GNU ld we use -z text
+      # though, which does catch some bad symbols but isn't as heavy-handed
+      # as -z defs.
+      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+      _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+      _LT_TAGVAR(link_all_deplibs, $1)=yes
+      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	_LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    uts4*)
+      _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      ;;
+
+    *)
+      _LT_TAGVAR(ld_shlibs, $1)=no
+      ;;
+    esac
+
+    if test x$host_vendor = xsni; then
+      case $host in
+      sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym'
+	;;
+      esac
+    fi
+  fi
+])
+AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
+
+_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl
+_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl
+_LT_DECL([], [extract_expsyms_cmds], [2],
+    [The commands to extract the exported symbol list from a shared archive])
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in
+x|xyes)
+  # Assume -lc should be added
+  _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+
+  if test "$enable_shared" = yes && test "$GCC" = yes; then
+    case $_LT_TAGVAR(archive_cmds, $1) in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      AC_CACHE_CHECK([whether -lc should be explicitly linked in],
+	[lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1),
+	[$RM conftest*
+	echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+	if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+	  soname=conftest
+	  lib=conftest
+	  libobjs=conftest.$ac_objext
+	  deplibs=
+	  wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
+	  pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
+	  compiler_flags=-v
+	  linker_flags=-v
+	  verstring=
+	  output_objdir=.
+	  libname=conftest
+	  lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
+	  _LT_TAGVAR(allow_undefined_flag, $1)=
+	  if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
+	  then
+	    lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+	  else
+	    lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+	  fi
+	  _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
+	else
+	  cat conftest.err 1>&5
+	fi
+	$RM conftest*
+	])
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)
+      ;;
+    esac
+  fi
+  ;;
+esac
+
+_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0],
+    [Whether or not to add -lc for building shared libraries])
+_LT_TAGDECL([allow_libtool_libs_with_static_runtimes],
+    [enable_shared_with_static_runtimes], [0],
+    [Whether or not to disallow shared libs when runtime libs are static])
+_LT_TAGDECL([], [export_dynamic_flag_spec], [1],
+    [Compiler flag to allow reflexive dlopens])
+_LT_TAGDECL([], [whole_archive_flag_spec], [1],
+    [Compiler flag to generate shared objects directly from archives])
+_LT_TAGDECL([], [compiler_needs_object], [1],
+    [Whether the compiler copes with passing no objects directly])
+_LT_TAGDECL([], [old_archive_from_new_cmds], [2],
+    [Create an old-style archive from a shared archive])
+_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2],
+    [Create a temporary old-style archive to link instead of a shared archive])
+_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive])
+_LT_TAGDECL([], [archive_expsym_cmds], [2])
+_LT_TAGDECL([], [module_cmds], [2],
+    [Commands used to build a loadable module if different from building
+    a shared archive.])
+_LT_TAGDECL([], [module_expsym_cmds], [2])
+_LT_TAGDECL([], [with_gnu_ld], [1],
+    [Whether we are building with GNU ld or not])
+_LT_TAGDECL([], [allow_undefined_flag], [1],
+    [Flag that allows shared libraries with undefined symbols to be built])
+_LT_TAGDECL([], [no_undefined_flag], [1],
+    [Flag that enforces no undefined symbols])
+_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
+    [Flag to hardcode $libdir into a binary during linking.
+    This must work even if $libdir does not exist])
+_LT_TAGDECL([], [hardcode_libdir_separator], [1],
+    [Whether we need a single "-rpath" flag with a separated argument])
+_LT_TAGDECL([], [hardcode_direct], [0],
+    [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+    DIR into the resulting binary])
+_LT_TAGDECL([], [hardcode_direct_absolute], [0],
+    [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+    DIR into the resulting binary and the resulting library dependency is
+    "absolute", i.e impossible to change by setting ${shlibpath_var} if the
+    library is relocated])
+_LT_TAGDECL([], [hardcode_minus_L], [0],
+    [Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+    into the resulting binary])
+_LT_TAGDECL([], [hardcode_shlibpath_var], [0],
+    [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+    into the resulting binary])
+_LT_TAGDECL([], [hardcode_automatic], [0],
+    [Set to "yes" if building a shared library automatically hardcodes DIR
+    into the library and all subsequent libraries and executables linked
+    against it])
+_LT_TAGDECL([], [inherit_rpath], [0],
+    [Set to yes if linker adds runtime paths of dependent libraries
+    to runtime path list])
+_LT_TAGDECL([], [link_all_deplibs], [0],
+    [Whether libtool must link a program against all its dependency libraries])
+_LT_TAGDECL([], [always_export_symbols], [0],
+    [Set to "yes" if exported symbols are required])
+_LT_TAGDECL([], [export_symbols_cmds], [2],
+    [The commands to list exported symbols])
+_LT_TAGDECL([], [exclude_expsyms], [1],
+    [Symbols that should not be listed in the preloaded symbols])
+_LT_TAGDECL([], [include_expsyms], [1],
+    [Symbols that must always be exported])
+_LT_TAGDECL([], [prelink_cmds], [2],
+    [Commands necessary for linking programs (against libraries) with templates])
+_LT_TAGDECL([], [postlink_cmds], [2],
+    [Commands necessary for finishing linking programs])
+_LT_TAGDECL([], [file_list_spec], [1],
+    [Specify filename containing input files])
+dnl FIXME: Not yet implemented
+dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1],
+dnl    [Compiler flag to generate thread safe objects])
+])# _LT_LINKER_SHLIBS
+
+
+# _LT_LANG_C_CONFIG([TAG])
+# ------------------------
+# Ensure that the configuration variables for a C compiler are suitably
+# defined.  These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_C_CONFIG],
+[m4_require([_LT_DECL_EGREP])dnl
+lt_save_CC="$CC"
+AC_LANG_PUSH(C)
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+_LT_TAG_COMPILER
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+  _LT_COMPILER_NO_RTTI($1)
+  _LT_COMPILER_PIC($1)
+  _LT_COMPILER_C_O($1)
+  _LT_COMPILER_FILE_LOCKS($1)
+  _LT_LINKER_SHLIBS($1)
+  _LT_SYS_DYNAMIC_LINKER($1)
+  _LT_LINKER_HARDCODE_LIBPATH($1)
+  LT_SYS_DLOPEN_SELF
+  _LT_CMD_STRIPLIB
+
+  # Report which library types will actually be built
+  AC_MSG_CHECKING([if libtool supports shared libraries])
+  AC_MSG_RESULT([$can_build_shared])
+
+  AC_MSG_CHECKING([whether to build shared libraries])
+  test "$can_build_shared" = "no" && enable_shared=no
+
+  # On AIX, shared libraries and static libraries use the same namespace, and
+  # are all built from PIC.
+  case $host_os in
+  aix3*)
+    test "$enable_shared" = yes && enable_static=no
+    if test -n "$RANLIB"; then
+      archive_cmds="$archive_cmds~\$RANLIB \$lib"
+      postinstall_cmds='$RANLIB $lib'
+    fi
+    ;;
+
+  aix[[4-9]]*)
+    if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+      test "$enable_shared" = yes && enable_static=no
+    fi
+    ;;
+  esac
+  AC_MSG_RESULT([$enable_shared])
+
+  AC_MSG_CHECKING([whether to build static libraries])
+  # Make sure either enable_shared or enable_static is yes.
+  test "$enable_shared" = yes || enable_static=yes
+  AC_MSG_RESULT([$enable_static])
+
+  _LT_CONFIG($1)
+fi
+AC_LANG_POP
+CC="$lt_save_CC"
+])# _LT_LANG_C_CONFIG
+
+
+# _LT_LANG_CXX_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a C++ compiler are suitably
+# defined.  These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_CXX_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PATH_MANIFEST_TOOL])dnl
+if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+    ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+    (test "X$CXX" != "Xg++"))) ; then
+  AC_PROG_CXXCPP
+else
+  _lt_caught_CXX_error=yes
+fi
+
+AC_LANG_PUSH(C++)
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(compiler_needs_object, $1)=no
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the CXX compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_caught_CXX_error" != yes; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="int some_variable = 0;"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC=$CC
+  lt_save_CFLAGS=$CFLAGS
+  lt_save_LD=$LD
+  lt_save_GCC=$GCC
+  GCC=$GXX
+  lt_save_with_gnu_ld=$with_gnu_ld
+  lt_save_path_LD=$lt_cv_path_LD
+  if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+    lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+  else
+    $as_unset lt_cv_prog_gnu_ld
+  fi
+  if test -n "${lt_cv_path_LDCXX+set}"; then
+    lt_cv_path_LD=$lt_cv_path_LDCXX
+  else
+    $as_unset lt_cv_path_LD
+  fi
+  test -z "${LDCXX+set}" || LD=$LDCXX
+  CC=${CXX-"c++"}
+  CFLAGS=$CXXFLAGS
+  compiler=$CC
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+
+  if test -n "$compiler"; then
+    # We don't want -fno-exception when compiling C++ code, so set the
+    # no_builtin_flag separately
+    if test "$GXX" = yes; then
+      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+    else
+      _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+    fi
+
+    if test "$GXX" = yes; then
+      # Set up default GNU C++ configuration
+
+      LT_PATH_LD
+
+      # Check if GNU C++ uses GNU ld as the underlying linker, since the
+      # archiving commands below assume that GNU ld is being used.
+      if test "$with_gnu_ld" = yes; then
+        _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+        _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+        # If archive_cmds runs LD, not CC, wlarc should be empty
+        # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+        #     investigate it a little bit more. (MM)
+        wlarc='${wl}'
+
+        # ancient GNU ld didn't support --whole-archive et. al.
+        if eval "`$CC -print-prog-name=ld` --help 2>&1" |
+	  $GREP 'no-whole-archive' > /dev/null; then
+          _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+        else
+          _LT_TAGVAR(whole_archive_flag_spec, $1)=
+        fi
+      else
+        with_gnu_ld=no
+        wlarc=
+
+        # A generic and very simple default shared library creation
+        # command for GNU C++ for the case where it uses the native
+        # linker, instead of GNU ld.  If possible, this setting should
+        # overridden to take advantage of the native linker features on
+        # the platform it is being used on.
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+      fi
+
+      # Commands to make compiler produce verbose output that lists
+      # what "hidden" libraries, object files and flags are used when
+      # linking a shared library.
+      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+    else
+      GXX=no
+      with_gnu_ld=no
+      wlarc=
+    fi
+
+    # PORTME: fill in a description of your system's C++ link characteristics
+    AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+    _LT_TAGVAR(ld_shlibs, $1)=yes
+    case $host_os in
+      aix3*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+      aix[[4-9]]*)
+        if test "$host_cpu" = ia64; then
+          # On IA64, the linker does run time linking by default, so we don't
+          # have to do anything special.
+          aix_use_runtimelinking=no
+          exp_sym_flag='-Bexport'
+          no_entry_flag=""
+        else
+          aix_use_runtimelinking=no
+
+          # Test if we are trying to use run time linking or normal
+          # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+          # need to do runtime linking.
+          case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+	    for ld_flag in $LDFLAGS; do
+	      case $ld_flag in
+	      *-brtl*)
+	        aix_use_runtimelinking=yes
+	        break
+	        ;;
+	      esac
+	    done
+	    ;;
+          esac
+
+          exp_sym_flag='-bexport'
+          no_entry_flag='-bnoentry'
+        fi
+
+        # When large executables or shared objects are built, AIX ld can
+        # have problems creating the table of contents.  If linking a library
+        # or program results in "error TOC overflow" add -mminimal-toc to
+        # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+        # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+        _LT_TAGVAR(archive_cmds, $1)=''
+        _LT_TAGVAR(hardcode_direct, $1)=yes
+        _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+        _LT_TAGVAR(link_all_deplibs, $1)=yes
+        _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+        if test "$GXX" = yes; then
+          case $host_os in aix4.[[012]]|aix4.[[012]].*)
+          # We only want to do this on AIX 4.2 and lower, the check
+          # below for broken collect2 doesn't work under 4.3+
+	  collect2name=`${CC} -print-prog-name=collect2`
+	  if test -f "$collect2name" &&
+	     strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+	  then
+	    # We have reworked collect2
+	    :
+	  else
+	    # We have old collect2
+	    _LT_TAGVAR(hardcode_direct, $1)=unsupported
+	    # It fails to find uninstalled libraries when the uninstalled
+	    # path is not listed in the libpath.  Setting hardcode_minus_L
+	    # to unsupported forces relinking
+	    _LT_TAGVAR(hardcode_minus_L, $1)=yes
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=
+	  fi
+          esac
+          shared_flag='-shared'
+	  if test "$aix_use_runtimelinking" = yes; then
+	    shared_flag="$shared_flag "'${wl}-G'
+	  fi
+        else
+          # not using gcc
+          if test "$host_cpu" = ia64; then
+	  # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	  # chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+          else
+	    if test "$aix_use_runtimelinking" = yes; then
+	      shared_flag='${wl}-G'
+	    else
+	      shared_flag='${wl}-bM:SRE'
+	    fi
+          fi
+        fi
+
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+        # It seems that -bexpall does not export symbols beginning with
+        # underscore (_), so it is better to generate a list of symbols to
+	# export.
+        _LT_TAGVAR(always_export_symbols, $1)=yes
+        if test "$aix_use_runtimelinking" = yes; then
+          # Warning - without using the other runtime loading flags (-brtl),
+          # -berok will link without error, but may produce a broken library.
+          _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+          # Determine the default libpath from the value encoded in an empty
+          # executable.
+          _LT_SYS_MODULE_PATH_AIX([$1])
+          _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+          _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+        else
+          if test "$host_cpu" = ia64; then
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+	    _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+          else
+	    # Determine the default libpath from the value encoded in an
+	    # empty executable.
+	    _LT_SYS_MODULE_PATH_AIX([$1])
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+	    # Warning - without using the other run time loading flags,
+	    # -berok will link without error, but may produce a broken library.
+	    _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+	    _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+	    if test "$with_gnu_ld" = yes; then
+	      # We only use this code for GNU lds that support --whole-archive.
+	      _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	    else
+	      # Exported symbols can be pulled into shared objects from archives
+	      _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+	    fi
+	    _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+	    # This is similar to how AIX traditionally builds its shared
+	    # libraries.
+	    _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+          fi
+        fi
+        ;;
+
+      beos*)
+	if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	  _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	  # Joseph Beckenbach <jrb3 at best.com> says some releases of gcc
+	  # support --undefined.  This deserves some investigation.  FIXME
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	else
+	  _LT_TAGVAR(ld_shlibs, $1)=no
+	fi
+	;;
+
+      chorus*)
+        case $cc_basename in
+          *)
+	  # FIXME: insert proper C++ library support
+	  _LT_TAGVAR(ld_shlibs, $1)=no
+	  ;;
+        esac
+        ;;
+
+      cygwin* | mingw* | pw32* | cegcc*)
+	case $GXX,$cc_basename in
+	,cl* | no,cl*)
+	  # Native MSVC
+	  # hardcode_libdir_flag_spec is actually meaningless, as there is
+	  # no search path for DLLs.
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+	  _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	  _LT_TAGVAR(always_export_symbols, $1)=yes
+	  _LT_TAGVAR(file_list_spec, $1)='@'
+	  # Tell ltmain to make .lib files, not .a files.
+	  libext=lib
+	  # Tell ltmain to make .dll files, not .so files.
+	  shrext_cmds=".dll"
+	  # FIXME: Setting linknames here is a bad hack.
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	      $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
+	    else
+	      $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
+	    fi~
+	    $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+	    linknames='
+	  # The linker will not automatically build a static lib if we build a DLL.
+	  # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+	  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+	  # Don't use ranlib
+	  _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
+	  _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
+	    lt_tool_outputfile="@TOOL_OUTPUT@"~
+	    case $lt_outputfile in
+	      *.exe|*.EXE) ;;
+	      *)
+		lt_outputfile="$lt_outputfile.exe"
+		lt_tool_outputfile="$lt_tool_outputfile.exe"
+		;;
+	    esac~
+	    func_to_tool_file "$lt_outputfile"~
+	    if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
+	      $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+	      $RM "$lt_outputfile.manifest";
+	    fi'
+	  ;;
+	*)
+	  # g++
+	  # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+	  # as there is no search path for DLLs.
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+	  _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+	  _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+	  _LT_TAGVAR(always_export_symbols, $1)=no
+	  _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+
+	  if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	    # If the export-symbols file already is a .def file (1st line
+	    # is EXPORTS), use it as is; otherwise, prepend...
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	      cp $export_symbols $output_objdir/$soname.def;
+	    else
+	      echo EXPORTS > $output_objdir/$soname.def;
+	      cat $export_symbols >> $output_objdir/$soname.def;
+	    fi~
+	    $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	  else
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	  fi
+	  ;;
+	esac
+	;;
+      darwin* | rhapsody*)
+        _LT_DARWIN_LINKER_FEATURES($1)
+	;;
+
+      dgux*)
+        case $cc_basename in
+          ec++*)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          ghcx*)
+	    # Green Hills C++ Compiler
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+        esac
+        ;;
+
+      freebsd2.*)
+        # C++ shared libraries reported to be fairly broken before
+	# switch to ELF
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      freebsd-elf*)
+        _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+        ;;
+
+      freebsd* | dragonfly*)
+        # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+        # conventions
+        _LT_TAGVAR(ld_shlibs, $1)=yes
+        ;;
+
+      haiku*)
+        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+        _LT_TAGVAR(link_all_deplibs, $1)=yes
+        ;;
+
+      hpux9*)
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+        _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+        _LT_TAGVAR(hardcode_direct, $1)=yes
+        _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+				             # but as the default
+				             # location of the library.
+
+        case $cc_basename in
+          CC*)
+            # FIXME: insert proper C++ library support
+            _LT_TAGVAR(ld_shlibs, $1)=no
+            ;;
+          aCC*)
+            _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+            # Commands to make compiler produce verbose output that lists
+            # what "hidden" libraries, object files and flags are used when
+            # linking a shared library.
+            #
+            # There doesn't appear to be a way to prevent this compiler from
+            # explicitly linking system object files so we need to strip them
+            # from the output so that they don't get included in the library
+            # dependencies.
+            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+            ;;
+          *)
+            if test "$GXX" = yes; then
+              _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+            else
+              # FIXME: insert proper C++ library support
+              _LT_TAGVAR(ld_shlibs, $1)=no
+            fi
+            ;;
+        esac
+        ;;
+
+      hpux10*|hpux11*)
+        if test $with_gnu_ld = no; then
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+	  _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+          case $host_cpu in
+            hppa*64*|ia64*)
+              ;;
+            *)
+	      _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+              ;;
+          esac
+        fi
+        case $host_cpu in
+          hppa*64*|ia64*)
+            _LT_TAGVAR(hardcode_direct, $1)=no
+            _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+            ;;
+          *)
+            _LT_TAGVAR(hardcode_direct, $1)=yes
+            _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+            _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+					         # but as the default
+					         # location of the library.
+            ;;
+        esac
+
+        case $cc_basename in
+          CC*)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          aCC*)
+	    case $host_cpu in
+	      hppa*64*)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	      ia64*)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	      *)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	        ;;
+	    esac
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+	    ;;
+          *)
+	    if test "$GXX" = yes; then
+	      if test $with_gnu_ld = no; then
+	        case $host_cpu in
+	          hppa*64*)
+	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	          ia64*)
+	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	          *)
+	            _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	            ;;
+	        esac
+	      fi
+	    else
+	      # FIXME: insert proper C++ library support
+	      _LT_TAGVAR(ld_shlibs, $1)=no
+	    fi
+	    ;;
+        esac
+        ;;
+
+      interix[[3-9]]*)
+	_LT_TAGVAR(hardcode_direct, $1)=no
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	# Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+	# Instead, shared libraries are loaded at an image base (0x10000000 by
+	# default) and relocated if they conflict, which is a slow very memory
+	# consuming and fragmenting process.  To avoid this, we pick a random,
+	# 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+	# time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+	_LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+	;;
+      irix5* | irix6*)
+        case $cc_basename in
+          CC*)
+	    # SGI C++
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -ar", where "CC" is the IRIX C++ compiler.  This is
+	    # necessary to make sure instantiated templates are included
+	    # in the archive.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+	    ;;
+          *)
+	    if test "$GXX" = yes; then
+	      if test "$with_gnu_ld" = no; then
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	      else
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib'
+	      fi
+	    fi
+	    _LT_TAGVAR(link_all_deplibs, $1)=yes
+	    ;;
+        esac
+        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+        _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+        _LT_TAGVAR(inherit_rpath, $1)=yes
+        ;;
+
+      linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+        case $cc_basename in
+          KCC*)
+	    # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	    # KCC will only create a shared library if the output file
+	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
+	    # to its proper name (with version) after linking.
+	    _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+	    ;;
+	  icpc* | ecpc* )
+	    # Intel C++
+	    with_gnu_ld=yes
+	    # version 8.0 and above of icpc choke on multiply defined symbols
+	    # if we add $predep_objects and $postdep_objects, however 7.1 and
+	    # earlier do not add the objects themselves.
+	    case `$CC -V 2>&1` in
+	      *"Version 7."*)
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+		_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+		;;
+	      *)  # Version 8.0 or newer
+	        tmp_idyn=
+	        case $host_cpu in
+		  ia64*) tmp_idyn=' -i_dynamic';;
+		esac
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+		_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+		;;
+	    esac
+	    _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	    ;;
+          pgCC* | pgcpp*)
+            # Portland Group C++ compiler
+	    case `$CC -V` in
+	    *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*)
+	      _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+		compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+	      _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+		$AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+		$RANLIB $oldlib'
+	      _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
+		rm -rf $tpldir~
+		$CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+		$CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+	      ;;
+	    *) # Version 6 and above use weak symbols
+	      _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+	      ;;
+	    esac
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+            ;;
+	  cxx*)
+	    # Compaq C++
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname  -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+	    runpath_var=LD_RUN_PATH
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
+	    ;;
+	  xl* | mpixl* | bgxl*)
+	    # IBM XL 8.0 on PPC, with GNU ld
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	    if test "x$supports_anon_versioning" = xyes; then
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+		cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+		echo "local: *; };" >> $output_objdir/$libname.ver~
+		$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+	    fi
+	    ;;
+	  *)
+	    case `$CC -V 2>&1 | sed 5q` in
+	    *Sun\ C*)
+	      # Sun C++ 5.9
+	      _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+	      _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	      _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
+	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	      _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	      _LT_TAGVAR(compiler_needs_object, $1)=yes
+
+	      # Not sure whether something based on
+	      # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+	      # would be better.
+	      output_verbose_link_cmd='func_echo_all'
+
+	      # Archives containing C++ object files must be created using
+	      # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+	      # necessary to make sure instantiated templates are included
+	      # in the archive.
+	      _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+	      ;;
+	    esac
+	    ;;
+	esac
+	;;
+
+      lynxos*)
+        # FIXME: insert proper C++ library support
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	;;
+
+      m88k*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+	;;
+
+      mvs*)
+        case $cc_basename in
+          cxx*)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+	  *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+	esac
+	;;
+
+      netbsd*)
+        if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	  _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable  -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+	  wlarc=
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	  _LT_TAGVAR(hardcode_direct, $1)=yes
+	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	fi
+	# Workaround some broken pre-1.5 toolchains
+	output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+	;;
+
+      *nto* | *qnx*)
+        _LT_TAGVAR(ld_shlibs, $1)=yes
+	;;
+
+      openbsd2*)
+        # C++ shared libraries are fairly broken
+	_LT_TAGVAR(ld_shlibs, $1)=no
+	;;
+
+      openbsd*)
+	if test -f /usr/libexec/ld.so; then
+	  _LT_TAGVAR(hardcode_direct, $1)=yes
+	  _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	  _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	  if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+	    _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+	    _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+	  fi
+	  output_verbose_link_cmd=func_echo_all
+	else
+	  _LT_TAGVAR(ld_shlibs, $1)=no
+	fi
+	;;
+
+      osf3* | osf4* | osf5*)
+        case $cc_basename in
+          KCC*)
+	    # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+	    # KCC will only create a shared library if the output file
+	    # ends with ".so" (or ".sl" for HP-UX), so rename the library
+	    # to its proper name (with version) after linking.
+	    _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	    # Archives containing C++ object files must be created using
+	    # the KAI C++ compiler.
+	    case $host in
+	      osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;;
+	      *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;;
+	    esac
+	    ;;
+          RCC*)
+	    # Rational C++ 2.4.1
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          cxx*)
+	    case $host in
+	      osf3*)
+	        _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+		;;
+	      *)
+	        _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	        _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+	          echo "-hidden">> $lib.exp~
+	          $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp  `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~
+	          $RM $lib.exp'
+	        _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+		;;
+	    esac
+
+	    _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	    # Commands to make compiler produce verbose output that lists
+	    # what "hidden" libraries, object files and flags are used when
+	    # linking a shared library.
+	    #
+	    # There doesn't appear to be a way to prevent this compiler from
+	    # explicitly linking system object files so we need to strip them
+	    # from the output so that they don't get included in the library
+	    # dependencies.
+	    output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+	    ;;
+	  *)
+	    if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+	      _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+	      case $host in
+	        osf3*)
+	          _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+		  ;;
+	        *)
+	          _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+		  ;;
+	      esac
+
+	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+	      _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+	      # Commands to make compiler produce verbose output that lists
+	      # what "hidden" libraries, object files and flags are used when
+	      # linking a shared library.
+	      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+	    else
+	      # FIXME: insert proper C++ library support
+	      _LT_TAGVAR(ld_shlibs, $1)=no
+	    fi
+	    ;;
+        esac
+        ;;
+
+      psos*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      sunos4*)
+        case $cc_basename in
+          CC*)
+	    # Sun C++ 4.x
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          lcc*)
+	    # Lucid
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+        esac
+        ;;
+
+      solaris*)
+        case $cc_basename in
+          CC* | sunCC*)
+	    # Sun C++ 4.2, 5.x and Centerline C++
+            _LT_TAGVAR(archive_cmds_need_lc,$1)=yes
+	    _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag}  -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	      $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	    _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+	    _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	    case $host_os in
+	      solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+	      *)
+		# The compiler driver will combine and reorder linker options,
+		# but understands `-z linker_flag'.
+	        # Supported since Solaris 2.6 (maybe 2.5.1?)
+		_LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+	        ;;
+	    esac
+	    _LT_TAGVAR(link_all_deplibs, $1)=yes
+
+	    output_verbose_link_cmd='func_echo_all'
+
+	    # Archives containing C++ object files must be created using
+	    # "CC -xar", where "CC" is the Sun C++ compiler.  This is
+	    # necessary to make sure instantiated templates are included
+	    # in the archive.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+	    ;;
+          gcx*)
+	    # Green Hills C++ Compiler
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+	    # The C++ compiler must be used to create the archive.
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+	    ;;
+          *)
+	    # GNU C++ compiler with Solaris linker
+	    if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+	      _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
+	      if $CC --version | $GREP -v '^2\.7' > /dev/null; then
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+	        _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+		  $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	        # Commands to make compiler produce verbose output that lists
+	        # what "hidden" libraries, object files and flags are used when
+	        # linking a shared library.
+	        output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+	      else
+	        # g++ 2.7 appears to require `-G' NOT `-shared' on this
+	        # platform.
+	        _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+	        _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+		  $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+	        # Commands to make compiler produce verbose output that lists
+	        # what "hidden" libraries, object files and flags are used when
+	        # linking a shared library.
+	        output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+	      fi
+
+	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
+	      case $host_os in
+		solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+		*)
+		  _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+		  ;;
+	      esac
+	    fi
+	    ;;
+        esac
+        ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+      _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+      _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+      _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+      runpath_var='LD_RUN_PATH'
+
+      case $cc_basename in
+        CC*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+      esac
+      ;;
+
+      sysv5* | sco3.2v5* | sco5v6*)
+	# Note: We can NOT use -z defs as we might desire, because we do not
+	# link with -lc, and that would cause any symbols used from libc to
+	# always be unresolved, which means just about no library would
+	# ever link correctly.  If we're not using GNU ld we use -z text
+	# though, which does catch some bad symbols but isn't as heavy-handed
+	# as -z defs.
+	_LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+	_LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+	_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+	_LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+	_LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+	_LT_TAGVAR(link_all_deplibs, $1)=yes
+	_LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+	runpath_var='LD_RUN_PATH'
+
+	case $cc_basename in
+          CC*)
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~
+	      '"$_LT_TAGVAR(old_archive_cmds, $1)"
+	    _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~
+	      '"$_LT_TAGVAR(reload_cmds, $1)"
+	    ;;
+	  *)
+	    _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	    ;;
+	esac
+      ;;
+
+      tandem*)
+        case $cc_basename in
+          NCC*)
+	    # NonStop-UX NCC 3.20
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+          *)
+	    # FIXME: insert proper C++ library support
+	    _LT_TAGVAR(ld_shlibs, $1)=no
+	    ;;
+        esac
+        ;;
+
+      vxworks*)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+
+      *)
+        # FIXME: insert proper C++ library support
+        _LT_TAGVAR(ld_shlibs, $1)=no
+        ;;
+    esac
+
+    AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+    test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+    _LT_TAGVAR(GCC, $1)="$GXX"
+    _LT_TAGVAR(LD, $1)="$LD"
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_SYS_HIDDEN_LIBDEPS($1)
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  CC=$lt_save_CC
+  CFLAGS=$lt_save_CFLAGS
+  LDCXX=$LD
+  LD=$lt_save_LD
+  GCC=$lt_save_GCC
+  with_gnu_ld=$lt_save_with_gnu_ld
+  lt_cv_path_LDCXX=$lt_cv_path_LD
+  lt_cv_path_LD=$lt_save_path_LD
+  lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+  lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+fi # test "$_lt_caught_CXX_error" != yes
+
+AC_LANG_POP
+])# _LT_LANG_CXX_CONFIG
+
+
+# _LT_FUNC_STRIPNAME_CNF
+# ----------------------
+# func_stripname_cnf prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+#
+# This function is identical to the (non-XSI) version of func_stripname,
+# except this one can be used by m4 code that may be executed by configure,
+# rather than the libtool script.
+m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl
+AC_REQUIRE([_LT_DECL_SED])
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])
+func_stripname_cnf ()
+{
+  case ${2} in
+  .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+  *)  func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+  esac
+} # func_stripname_cnf
+])# _LT_FUNC_STRIPNAME_CNF
+
+# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
+# ---------------------------------
+# Figure out "hidden" library dependencies from verbose
+# compiler output when linking a shared library.
+# Parse the compiler output and extract the necessary
+# objects, libraries and library flags.
+m4_defun([_LT_SYS_HIDDEN_LIBDEPS],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl
+# Dependencies to place before and after the object being linked:
+_LT_TAGVAR(predep_objects, $1)=
+_LT_TAGVAR(postdep_objects, $1)=
+_LT_TAGVAR(predeps, $1)=
+_LT_TAGVAR(postdeps, $1)=
+_LT_TAGVAR(compiler_lib_search_path, $1)=
+
+dnl we can't use the lt_simple_compile_test_code here,
+dnl because it contains code intended for an executable,
+dnl not a library.  It's possible we should let each
+dnl tag define a new lt_????_link_test_code variable,
+dnl but it's only used here...
+m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF
+int a;
+void foo (void) { a = 0; }
+_LT_EOF
+], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF
+class Foo
+{
+public:
+  Foo (void) { a = 0; }
+private:
+  int a;
+};
+_LT_EOF
+], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF
+      subroutine foo
+      implicit none
+      integer*4 a
+      a=0
+      return
+      end
+_LT_EOF
+], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF
+      subroutine foo
+      implicit none
+      integer a
+      a=0
+      return
+      end
+_LT_EOF
+], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF
+public class foo {
+  private int a;
+  public void bar (void) {
+    a = 0;
+  }
+};
+_LT_EOF
+], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF
+package foo
+func foo() {
+}
+_LT_EOF
+])
+
+_lt_libdeps_save_CFLAGS=$CFLAGS
+case "$CC $CFLAGS " in #(
+*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;;
+*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;;
+*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;;
+esac
+
+dnl Parse the compiler output and extract the necessary
+dnl objects, libraries and library flags.
+if AC_TRY_EVAL(ac_compile); then
+  # Parse the compiler output and extract the necessary
+  # objects, libraries and library flags.
+
+  # Sentinel used to keep track of whether or not we are before
+  # the conftest object file.
+  pre_test_object_deps_done=no
+
+  for p in `eval "$output_verbose_link_cmd"`; do
+    case ${prev}${p} in
+
+    -L* | -R* | -l*)
+       # Some compilers place space between "-{L,R}" and the path.
+       # Remove the space.
+       if test $p = "-L" ||
+          test $p = "-R"; then
+	 prev=$p
+	 continue
+       fi
+
+       # Expand the sysroot to ease extracting the directories later.
+       if test -z "$prev"; then
+         case $p in
+         -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;;
+         -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;;
+         -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;;
+         esac
+       fi
+       case $p in
+       =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
+       esac
+       if test "$pre_test_object_deps_done" = no; then
+	 case ${prev} in
+	 -L | -R)
+	   # Internal compiler library paths should come after those
+	   # provided the user.  The postdeps already come after the
+	   # user supplied libs so there is no need to process them.
+	   if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
+	     _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
+	   else
+	     _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
+	   fi
+	   ;;
+	 # The "-l" case would never come before the object being
+	 # linked, so don't bother handling this case.
+	 esac
+       else
+	 if test -z "$_LT_TAGVAR(postdeps, $1)"; then
+	   _LT_TAGVAR(postdeps, $1)="${prev}${p}"
+	 else
+	   _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}"
+	 fi
+       fi
+       prev=
+       ;;
+
+    *.lto.$objext) ;; # Ignore GCC LTO objects
+    *.$objext)
+       # This assumes that the test object file only shows up
+       # once in the compiler output.
+       if test "$p" = "conftest.$objext"; then
+	 pre_test_object_deps_done=yes
+	 continue
+       fi
+
+       if test "$pre_test_object_deps_done" = no; then
+	 if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
+	   _LT_TAGVAR(predep_objects, $1)="$p"
+	 else
+	   _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
+	 fi
+       else
+	 if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
+	   _LT_TAGVAR(postdep_objects, $1)="$p"
+	 else
+	   _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
+	 fi
+       fi
+       ;;
+
+    *) ;; # Ignore the rest.
+
+    esac
+  done
+
+  # Clean up.
+  rm -f a.out a.exe
+else
+  echo "libtool.m4: error: problem compiling $1 test program"
+fi
+
+$RM -f confest.$objext
+CFLAGS=$_lt_libdeps_save_CFLAGS
+
+# PORTME: override above test on systems where it is broken
+m4_if([$1], [CXX],
+[case $host_os in
+interix[[3-9]]*)
+  # Interix 3.5 installs completely hosed .la files for C++, so rather than
+  # hack all around it, let's just trust "g++" to DTRT.
+  _LT_TAGVAR(predep_objects,$1)=
+  _LT_TAGVAR(postdep_objects,$1)=
+  _LT_TAGVAR(postdeps,$1)=
+  ;;
+
+linux*)
+  case `$CC -V 2>&1 | sed 5q` in
+  *Sun\ C*)
+    # Sun C++ 5.9
+
+    # The more standards-conforming stlport4 library is
+    # incompatible with the Cstd library. Avoid specifying
+    # it if it's in CXXFLAGS. Ignore libCrun as
+    # -library=stlport4 depends on it.
+    case " $CXX $CXXFLAGS " in
+    *" -library=stlport4 "*)
+      solaris_use_stlport4=yes
+      ;;
+    esac
+
+    if test "$solaris_use_stlport4" != yes; then
+      _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+    fi
+    ;;
+  esac
+  ;;
+
+solaris*)
+  case $cc_basename in
+  CC* | sunCC*)
+    # The more standards-conforming stlport4 library is
+    # incompatible with the Cstd library. Avoid specifying
+    # it if it's in CXXFLAGS. Ignore libCrun as
+    # -library=stlport4 depends on it.
+    case " $CXX $CXXFLAGS " in
+    *" -library=stlport4 "*)
+      solaris_use_stlport4=yes
+      ;;
+    esac
+
+    # Adding this requires a known-good setup of shared libraries for
+    # Sun compiler versions before 5.6, else PIC objects from an old
+    # archive will be linked into the output, leading to subtle bugs.
+    if test "$solaris_use_stlport4" != yes; then
+      _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+    fi
+    ;;
+  esac
+  ;;
+esac
+])
+
+case " $_LT_TAGVAR(postdeps, $1) " in
+*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+esac
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=
+if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
+fi
+_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
+    [The directories searched by this compiler when creating a shared library])
+_LT_TAGDECL([], [predep_objects], [1],
+    [Dependencies to place before and after the objects being linked to
+    create a shared library])
+_LT_TAGDECL([], [postdep_objects], [1])
+_LT_TAGDECL([], [predeps], [1])
+_LT_TAGDECL([], [postdeps], [1])
+_LT_TAGDECL([], [compiler_lib_search_path], [1],
+    [The library search path used internally by the compiler when linking
+    a shared library])
+])# _LT_SYS_HIDDEN_LIBDEPS
+
+
+# _LT_LANG_F77_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a Fortran 77 compiler are
+# suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_F77_CONFIG],
+[AC_LANG_PUSH(Fortran 77)
+if test -z "$F77" || test "X$F77" = "Xno"; then
+  _lt_disable_F77=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the F77 compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_F77" != yes; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="\
+      subroutine t
+      return
+      end
+"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code="\
+      program t
+      end
+"
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC="$CC"
+  lt_save_GCC=$GCC
+  lt_save_CFLAGS=$CFLAGS
+  CC=${F77-"f77"}
+  CFLAGS=$FFLAGS
+  compiler=$CC
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+  GCC=$G77
+  if test -n "$compiler"; then
+    AC_MSG_CHECKING([if libtool supports shared libraries])
+    AC_MSG_RESULT([$can_build_shared])
+
+    AC_MSG_CHECKING([whether to build shared libraries])
+    test "$can_build_shared" = "no" && enable_shared=no
+
+    # On AIX, shared libraries and static libraries use the same namespace, and
+    # are all built from PIC.
+    case $host_os in
+      aix3*)
+        test "$enable_shared" = yes && enable_static=no
+        if test -n "$RANLIB"; then
+          archive_cmds="$archive_cmds~\$RANLIB \$lib"
+          postinstall_cmds='$RANLIB $lib'
+        fi
+        ;;
+      aix[[4-9]]*)
+	if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+	  test "$enable_shared" = yes && enable_static=no
+	fi
+        ;;
+    esac
+    AC_MSG_RESULT([$enable_shared])
+
+    AC_MSG_CHECKING([whether to build static libraries])
+    # Make sure either enable_shared or enable_static is yes.
+    test "$enable_shared" = yes || enable_static=yes
+    AC_MSG_RESULT([$enable_static])
+
+    _LT_TAGVAR(GCC, $1)="$G77"
+    _LT_TAGVAR(LD, $1)="$LD"
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  GCC=$lt_save_GCC
+  CC="$lt_save_CC"
+  CFLAGS="$lt_save_CFLAGS"
+fi # test "$_lt_disable_F77" != yes
+
+AC_LANG_POP
+])# _LT_LANG_F77_CONFIG
+
+
+# _LT_LANG_FC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for a Fortran compiler are
+# suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_FC_CONFIG],
+[AC_LANG_PUSH(Fortran)
+
+if test -z "$FC" || test "X$FC" = "Xno"; then
+  _lt_disable_FC=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for fc test sources.
+ac_ext=${ac_fc_srcext-f}
+
+# Object file extension for compiled fc test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the FC compiler isn't working.  Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_FC" != yes; then
+  # Code to be used in simple compile tests
+  lt_simple_compile_test_code="\
+      subroutine t
+      return
+      end
+"
+
+  # Code to be used in simple link tests
+  lt_simple_link_test_code="\
+      program t
+      end
+"
+
+  # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+  _LT_TAG_COMPILER
+
+  # save warnings/boilerplate of simple test code
+  _LT_COMPILER_BOILERPLATE
+  _LT_LINKER_BOILERPLATE
+
+  # Allow CC to be a program name with arguments.
+  lt_save_CC="$CC"
+  lt_save_GCC=$GCC
+  lt_save_CFLAGS=$CFLAGS
+  CC=${FC-"f95"}
+  CFLAGS=$FCFLAGS
+  compiler=$CC
+  GCC=$ac_cv_fc_compiler_gnu
+
+  _LT_TAGVAR(compiler, $1)=$CC
+  _LT_CC_BASENAME([$compiler])
+
+  if test -n "$compiler"; then
+    AC_MSG_CHECKING([if libtool supports shared libraries])
+    AC_MSG_RESULT([$can_build_shared])
+
+    AC_MSG_CHECKING([whether to build shared libraries])
+    test "$can_build_shared" = "no" && enable_shared=no
+
+    # On AIX, shared libraries and static libraries use the same namespace, and
+    # are all built from PIC.
+    case $host_os in
+      aix3*)
+        test "$enable_shared" = yes && enable_static=no
+        if test -n "$RANLIB"; then
+          archive_cmds="$archive_cmds~\$RANLIB \$lib"
+          postinstall_cmds='$RANLIB $lib'
+        fi
+        ;;
+      aix[[4-9]]*)
+	if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+	  test "$enable_shared" = yes && enable_static=no
+	fi
+        ;;
+    esac
+    AC_MSG_RESULT([$enable_shared])
+
+    AC_MSG_CHECKING([whether to build static libraries])
+    # Make sure either enable_shared or enable_static is yes.
+    test "$enable_shared" = yes || enable_static=yes
+    AC_MSG_RESULT([$enable_static])
+
+    _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu"
+    _LT_TAGVAR(LD, $1)="$LD"
+
+    ## CAVEAT EMPTOR:
+    ## There is no encapsulation within the following macros, do not change
+    ## the running order or otherwise move them around unless you know exactly
+    ## what you are doing...
+    _LT_SYS_HIDDEN_LIBDEPS($1)
+    _LT_COMPILER_PIC($1)
+    _LT_COMPILER_C_O($1)
+    _LT_COMPILER_FILE_LOCKS($1)
+    _LT_LINKER_SHLIBS($1)
+    _LT_SYS_DYNAMIC_LINKER($1)
+    _LT_LINKER_HARDCODE_LIBPATH($1)
+
+    _LT_CONFIG($1)
+  fi # test -n "$compiler"
+
+  GCC=$lt_save_GCC
+  CC=$lt_save_CC
+  CFLAGS=$lt_save_CFLAGS
+fi # test "$_lt_disable_FC" != yes
+
+AC_LANG_POP
+])# _LT_LANG_FC_CONFIG
+
+
+# _LT_LANG_GCJ_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Java Compiler compiler
+# are suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_GCJ_CONFIG],
+[AC_REQUIRE([LT_PROG_GCJ])dnl
+AC_LANG_SAVE
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GCJ-"gcj"}
+CFLAGS=$GCJFLAGS
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)="$LD"
+_LT_CC_BASENAME([$compiler])
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+  _LT_COMPILER_NO_RTTI($1)
+  _LT_COMPILER_PIC($1)
+  _LT_COMPILER_C_O($1)
+  _LT_COMPILER_FILE_LOCKS($1)
+  _LT_LINKER_SHLIBS($1)
+  _LT_LINKER_HARDCODE_LIBPATH($1)
+
+  _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_GCJ_CONFIG
+
+
+# _LT_LANG_GO_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Go compiler
+# are suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_GO_CONFIG],
+[AC_REQUIRE([LT_PROG_GO])dnl
+AC_LANG_SAVE
+
+# Source file extension for Go test sources.
+ac_ext=go
+
+# Object file extension for compiled Go test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="package main; func main() { }"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='package main; func main() { }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GOC-"gccgo"}
+CFLAGS=$GOFLAGS
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)="$LD"
+_LT_CC_BASENAME([$compiler])
+
+# Go did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+  _LT_COMPILER_NO_RTTI($1)
+  _LT_COMPILER_PIC($1)
+  _LT_COMPILER_C_O($1)
+  _LT_COMPILER_FILE_LOCKS($1)
+  _LT_LINKER_SHLIBS($1)
+  _LT_LINKER_HARDCODE_LIBPATH($1)
+
+  _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_GO_CONFIG
+
+
+# _LT_LANG_RC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for the Windows resource compiler
+# are suitably defined.  These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_RC_CONFIG],
+[AC_REQUIRE([LT_PROG_RC])dnl
+AC_LANG_SAVE
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="$lt_simple_compile_test_code"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=
+CC=${RC-"windres"}
+CFLAGS=
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+
+if test -n "$compiler"; then
+  :
+  _LT_CONFIG($1)
+fi
+
+GCC=$lt_save_GCC
+AC_LANG_RESTORE
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_RC_CONFIG
+
+
+# LT_PROG_GCJ
+# -----------
+AC_DEFUN([LT_PROG_GCJ],
+[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
+  [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
+    [AC_CHECK_TOOL(GCJ, gcj,)
+      test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
+      AC_SUBST(GCJFLAGS)])])[]dnl
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_GCJ], [])
+
+
+# LT_PROG_GO
+# ----------
+AC_DEFUN([LT_PROG_GO],
+[AC_CHECK_TOOL(GOC, gccgo,)
+])
+
+
+# LT_PROG_RC
+# ----------
+AC_DEFUN([LT_PROG_RC],
+[AC_CHECK_TOOL(RC, windres,)
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_RC], [])
+
+
+# _LT_DECL_EGREP
+# --------------
+# If we don't have a new enough Autoconf to choose the best grep
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_EGREP],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_REQUIRE([AC_PROG_FGREP])dnl
+test -z "$GREP" && GREP=grep
+_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
+_LT_DECL([], [EGREP], [1], [An ERE matcher])
+_LT_DECL([], [FGREP], [1], [A literal string matcher])
+dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
+AC_SUBST([GREP])
+])
+
+
+# _LT_DECL_OBJDUMP
+# --------------
+# If we don't have a new enough Autoconf to choose the best objdump
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_OBJDUMP],
+[AC_CHECK_TOOL(OBJDUMP, objdump, false)
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper])
+AC_SUBST([OBJDUMP])
+])
+
+# _LT_DECL_DLLTOOL
+# ----------------
+# Ensure DLLTOOL variable is set.
+m4_defun([_LT_DECL_DLLTOOL],
+[AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])
+AC_SUBST([DLLTOOL])
+])
+
+# _LT_DECL_SED
+# ------------
+# Check for a fully-functional sed program, that truncates
+# as few characters as possible.  Prefer GNU sed if found.
+m4_defun([_LT_DECL_SED],
+[AC_PROG_SED
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
+_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
+    [Sed that helps us avoid accidentally triggering echo(1) options like -n])
+])# _LT_DECL_SED
+
+m4_ifndef([AC_PROG_SED], [
+############################################################
+# NOTE: This macro has been submitted for inclusion into   #
+#  GNU Autoconf as AC_PROG_SED.  When it is available in   #
+#  a released version of Autoconf we should remove this    #
+#  macro and use it instead.                               #
+############################################################
+
+m4_defun([AC_PROG_SED],
+[AC_MSG_CHECKING([for a sed that does not truncate output])
+AC_CACHE_VAL(lt_cv_path_SED,
+[# Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for lt_ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
+        lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+      fi
+    done
+  done
+done
+IFS=$as_save_IFS
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+  test ! -f $lt_ac_sed && continue
+  cat /dev/null > conftest.in
+  lt_ac_count=0
+  echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+  # Check for GNU sed and select it if it is found.
+  if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+    lt_cv_path_SED=$lt_ac_sed
+    break
+  fi
+  while true; do
+    cat conftest.in conftest.in >conftest.tmp
+    mv conftest.tmp conftest.in
+    cp conftest.in conftest.nl
+    echo >>conftest.nl
+    $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+    cmp -s conftest.out conftest.nl || break
+    # 10000 chars as input seems more than enough
+    test $lt_ac_count -gt 10 && break
+    lt_ac_count=`expr $lt_ac_count + 1`
+    if test $lt_ac_count -gt $lt_ac_max; then
+      lt_ac_max=$lt_ac_count
+      lt_cv_path_SED=$lt_ac_sed
+    fi
+  done
+done
+])
+SED=$lt_cv_path_SED
+AC_SUBST([SED])
+AC_MSG_RESULT([$SED])
+])#AC_PROG_SED
+])#m4_ifndef
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_SED], [])
+
+
+# _LT_CHECK_SHELL_FEATURES
+# ------------------------
+# Find out whether the shell is Bourne or XSI compatible,
+# or has some other useful features.
+m4_defun([_LT_CHECK_SHELL_FEATURES],
+[AC_MSG_CHECKING([whether the shell understands some XSI constructs])
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+  test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \
+      = c,a/b,b/c, \
+    && eval 'test $(( 1 + 1 )) -eq 2 \
+    && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
+  && xsi_shell=yes
+AC_MSG_RESULT([$xsi_shell])
+_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell'])
+
+AC_MSG_CHECKING([whether the shell understands "+="])
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \
+    >/dev/null 2>&1 \
+  && lt_shell_append=yes
+AC_MSG_RESULT([$lt_shell_append])
+_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append'])
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  lt_unset=unset
+else
+  lt_unset=false
+fi
+_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+    # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+  lt_SP2NL='tr \040 \012'
+  lt_NL2SP='tr \015\012 \040\040'
+  ;;
+ *) # EBCDIC based system
+  lt_SP2NL='tr \100 \n'
+  lt_NL2SP='tr \r\n \100\100'
+  ;;
+esac
+_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl
+_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
+])# _LT_CHECK_SHELL_FEATURES
+
+
+# _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY)
+# ------------------------------------------------------
+# In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and
+# '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY.
+m4_defun([_LT_PROG_FUNCTION_REPLACE],
+[dnl {
+sed -e '/^$1 ()$/,/^} # $1 /c\
+$1 ()\
+{\
+m4_bpatsubsts([$2], [$], [\\], [^\([	 ]\)], [\\\1])
+} # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+])
+
+
+# _LT_PROG_REPLACE_SHELLFNS
+# -------------------------
+# Replace existing portable implementations of several shell functions with
+# equivalent extended shell implementations where those features are available..
+m4_defun([_LT_PROG_REPLACE_SHELLFNS],
+[if test x"$xsi_shell" = xyes; then
+  _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl
+    case ${1} in
+      */*) func_dirname_result="${1%/*}${2}" ;;
+      *  ) func_dirname_result="${3}" ;;
+    esac])
+
+  _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl
+    func_basename_result="${1##*/}"])
+
+  _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl
+    case ${1} in
+      */*) func_dirname_result="${1%/*}${2}" ;;
+      *  ) func_dirname_result="${3}" ;;
+    esac
+    func_basename_result="${1##*/}"])
+
+  _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl
+    # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+    # positional parameters, so assign one to ordinary parameter first.
+    func_stripname_result=${3}
+    func_stripname_result=${func_stripname_result#"${1}"}
+    func_stripname_result=${func_stripname_result%"${2}"}])
+
+  _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl
+    func_split_long_opt_name=${1%%=*}
+    func_split_long_opt_arg=${1#*=}])
+
+  _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl
+    func_split_short_opt_arg=${1#??}
+    func_split_short_opt_name=${1%"$func_split_short_opt_arg"}])
+
+  _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl
+    case ${1} in
+      *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
+      *)    func_lo2o_result=${1} ;;
+    esac])
+
+  _LT_PROG_FUNCTION_REPLACE([func_xform], [    func_xform_result=${1%.*}.lo])
+
+  _LT_PROG_FUNCTION_REPLACE([func_arith], [    func_arith_result=$(( $[*] ))])
+
+  _LT_PROG_FUNCTION_REPLACE([func_len], [    func_len_result=${#1}])
+fi
+
+if test x"$lt_shell_append" = xyes; then
+  _LT_PROG_FUNCTION_REPLACE([func_append], [    eval "${1}+=\\${2}"])
+
+  _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl
+    func_quote_for_eval "${2}"
+dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \
+    eval "${1}+=\\\\ \\$func_quote_for_eval_result"])
+
+  # Save a `func_append' function call where possible by direct use of '+='
+  sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \
+    && mv -f "$cfgfile.tmp" "$cfgfile" \
+      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+  test 0 -eq $? || _lt_function_replace_fail=:
+else
+  # Save a `func_append' function call even when '+=' is not available
+  sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \
+    && mv -f "$cfgfile.tmp" "$cfgfile" \
+      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+  test 0 -eq $? || _lt_function_replace_fail=:
+fi
+
+if test x"$_lt_function_replace_fail" = x":"; then
+  AC_MSG_WARN([Unable to substitute extended shell functions in $ofile])
+fi
+])
+
+# _LT_PATH_CONVERSION_FUNCTIONS
+# -----------------------------
+# Determine which file name conversion functions should be used by
+# func_to_host_file (and, implicitly, by func_to_host_path).  These are needed
+# for certain cross-compile configurations and native mingw.
+m4_defun([_LT_PATH_CONVERSION_FUNCTIONS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_MSG_CHECKING([how to convert $build file names to $host format])
+AC_CACHE_VAL(lt_cv_to_host_file_cmd,
+[case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
+        ;;
+    esac
+    ;;
+  *-*-cygwin* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_noop
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
+        ;;
+    esac
+    ;;
+  * ) # unhandled hosts (and "normal" native builds)
+    lt_cv_to_host_file_cmd=func_convert_file_noop
+    ;;
+esac
+])
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+AC_MSG_RESULT([$lt_cv_to_host_file_cmd])
+_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd],
+         [0], [convert $build file names to $host format])dnl
+
+AC_MSG_CHECKING([how to convert $build file names to toolchain format])
+AC_CACHE_VAL(lt_cv_to_tool_file_cmd,
+[#assume ordinary cross tools, or native build.
+lt_cv_to_tool_file_cmd=func_convert_file_noop
+case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
+        ;;
+    esac
+    ;;
+esac
+])
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+AC_MSG_RESULT([$lt_cv_to_tool_file_cmd])
+_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd],
+         [0], [convert $build files to toolchain format])dnl
+])# _LT_PATH_CONVERSION_FUNCTIONS
diff --git a/autostuff/ltmain.sh b/autostuff/ltmain.sh
new file mode 100644
index 0000000..bb5fa02
--- /dev/null
+++ b/autostuff/ltmain.sh
@@ -0,0 +1,9661 @@
+
+# libtool (GNU libtool) 2.4.2
+# Written by Gordon Matzigkeit <gord at gnu.ai.mit.edu>, 1996
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006,
+# 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions.  There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING.  If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html,
+# or obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# Usage: $progname [OPTION]... [MODE-ARG]...
+#
+# Provide generalized library-building support services.
+#
+#       --config             show all configuration variables
+#       --debug              enable verbose shell tracing
+#   -n, --dry-run            display commands without modifying any files
+#       --features           display basic configuration information and exit
+#       --mode=MODE          use operation mode MODE
+#       --preserve-dup-deps  don't remove duplicate dependency libraries
+#       --quiet, --silent    don't print informational messages
+#       --no-quiet, --no-silent
+#                            print informational messages (default)
+#       --no-warn            don't display warning messages
+#       --tag=TAG            use configuration variables from tag TAG
+#   -v, --verbose            print more informational messages than default
+#       --no-verbose         don't print the extra informational messages
+#       --version            print version information
+#   -h, --help, --help-all   print short, long, or detailed help message
+#
+# MODE must be one of the following:
+#
+#         clean              remove files from the build directory
+#         compile            compile a source file into a libtool object
+#         execute            automatically set library path, then run a program
+#         finish             complete the installation of libtool libraries
+#         install            install libraries or executables
+#         link               create a library or an executable
+#         uninstall          remove libraries from an installed directory
+#
+# MODE-ARGS vary depending on the MODE.  When passed as first option,
+# `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that.
+# Try `$progname --help --mode=MODE' for a more detailed description of MODE.
+#
+# When reporting a bug, please describe a test case to reproduce it and
+# include the following information:
+#
+#         host-triplet:	$host
+#         shell:		$SHELL
+#         compiler:		$LTCC
+#         compiler flags:		$LTCFLAGS
+#         linker:		$LD (gnu? $with_gnu_ld)
+#         $progname:	(GNU libtool) 2.4.2 Debian-2.4.2-1.7
+#         automake:	$automake_version
+#         autoconf:	$autoconf_version
+#
+# Report bugs to <bug-libtool at gnu.org>.
+# GNU libtool home page: <http://www.gnu.org/software/libtool/>.
+# General help using GNU software: <http://www.gnu.org/gethelp/>.
+
+PROGRAM=libtool
+PACKAGE=libtool
+VERSION="2.4.2 Debian-2.4.2-1.7"
+TIMESTAMP=""
+package_revision=1.3337
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+
+# NLS nuisances: We save the old values to restore during execute mode.
+lt_user_locale=
+lt_safe_locale=
+for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+do
+  eval "if test \"\${$lt_var+set}\" = set; then
+          save_$lt_var=\$$lt_var
+          $lt_var=C
+	  export $lt_var
+	  lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\"
+	  lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\"
+	fi"
+done
+LC_ALL=C
+LANGUAGE=C
+export LANGUAGE LC_ALL
+
+$lt_unset CDPATH
+
+
+# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
+# is ksh but when the shell is invoked as "sh" and the current value of
+# the _XPG environment variable is not equal to 1 (one), the special
+# positional parameter $0, within a function call, is the name of the
+# function.
+progpath="$0"
+
+
+
+: ${CP="cp -f"}
+test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'}
+: ${MAKE="make"}
+: ${MKDIR="mkdir"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+: ${SHELL="${CONFIG_SHELL-/bin/sh}"}
+: ${Xsed="$SED -e 1s/^X//"}
+
+# Global variables:
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+EXIT_MISMATCH=63  # $? = 63 is used to indicate version mismatch to missing.
+EXIT_SKIP=77	  # $? = 77 is used to indicate a skipped test to automake.
+
+exit_status=$EXIT_SUCCESS
+
+# Make sure IFS has a sensible default
+lt_nl='
+'
+IFS=" 	$lt_nl"
+
+dirname="s,/[^/]*$,,"
+basename="s,^.*/,,"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE.  If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+    func_dirname_result=`$ECHO "${1}" | $SED "$dirname"`
+    if test "X$func_dirname_result" = "X${1}"; then
+      func_dirname_result="${3}"
+    else
+      func_dirname_result="$func_dirname_result${2}"
+    fi
+} # func_dirname may be replaced by extended shell implementation
+
+
+# func_basename file
+func_basename ()
+{
+    func_basename_result=`$ECHO "${1}" | $SED "$basename"`
+} # func_basename may be replaced by extended shell implementation
+
+
+# func_dirname_and_basename file append nondir_replacement
+# perform func_basename and func_dirname in a single function
+# call:
+#   dirname:  Compute the dirname of FILE.  If nonempty,
+#             add APPEND to the result, otherwise set result
+#             to NONDIR_REPLACEMENT.
+#             value returned in "$func_dirname_result"
+#   basename: Compute filename of FILE.
+#             value retuned in "$func_basename_result"
+# Implementation must be kept synchronized with func_dirname
+# and func_basename. For efficiency, we do not delegate to
+# those functions but instead duplicate the functionality here.
+func_dirname_and_basename ()
+{
+    # Extract subdirectory from the argument.
+    func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"`
+    if test "X$func_dirname_result" = "X${1}"; then
+      func_dirname_result="${3}"
+    else
+      func_dirname_result="$func_dirname_result${2}"
+    fi
+    func_basename_result=`$ECHO "${1}" | $SED -e "$basename"`
+} # func_dirname_and_basename may be replaced by extended shell implementation
+
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+# func_strip_suffix prefix name
+func_stripname ()
+{
+    case ${2} in
+      .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+      *)  func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+    esac
+} # func_stripname may be replaced by extended shell implementation
+
+
+# These SED scripts presuppose an absolute path with a trailing slash.
+pathcar='s,^/\([^/]*\).*$,\1,'
+pathcdr='s,^/[^/]*,,'
+removedotparts=':dotsl
+		s@/\./@/@g
+		t dotsl
+		s,/\.$,/,'
+collapseslashes='s@/\{1,\}@/@g'
+finalslash='s,/*$,/,'
+
+# func_normal_abspath PATH
+# Remove doubled-up and trailing slashes, "." path components,
+# and cancel out any ".." path components in PATH after making
+# it an absolute path.
+#             value returned in "$func_normal_abspath_result"
+func_normal_abspath ()
+{
+  # Start from root dir and reassemble the path.
+  func_normal_abspath_result=
+  func_normal_abspath_tpath=$1
+  func_normal_abspath_altnamespace=
+  case $func_normal_abspath_tpath in
+    "")
+      # Empty path, that just means $cwd.
+      func_stripname '' '/' "`pwd`"
+      func_normal_abspath_result=$func_stripname_result
+      return
+    ;;
+    # The next three entries are used to spot a run of precisely
+    # two leading slashes without using negated character classes;
+    # we take advantage of case's first-match behaviour.
+    ///*)
+      # Unusual form of absolute path, do nothing.
+    ;;
+    //*)
+      # Not necessarily an ordinary path; POSIX reserves leading '//'
+      # and for example Cygwin uses it to access remote file shares
+      # over CIFS/SMB, so we conserve a leading double slash if found.
+      func_normal_abspath_altnamespace=/
+    ;;
+    /*)
+      # Absolute path, do nothing.
+    ;;
+    *)
+      # Relative path, prepend $cwd.
+      func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath
+    ;;
+  esac
+  # Cancel out all the simple stuff to save iterations.  We also want
+  # the path to end with a slash for ease of parsing, so make sure
+  # there is one (and only one) here.
+  func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+        -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"`
+  while :; do
+    # Processed it all yet?
+    if test "$func_normal_abspath_tpath" = / ; then
+      # If we ascended to the root using ".." the result may be empty now.
+      if test -z "$func_normal_abspath_result" ; then
+        func_normal_abspath_result=/
+      fi
+      break
+    fi
+    func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \
+        -e "$pathcar"`
+    func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+        -e "$pathcdr"`
+    # Figure out what to do with it
+    case $func_normal_abspath_tcomponent in
+      "")
+        # Trailing empty path component, ignore it.
+      ;;
+      ..)
+        # Parent dir; strip last assembled component from result.
+        func_dirname "$func_normal_abspath_result"
+        func_normal_abspath_result=$func_dirname_result
+      ;;
+      *)
+        # Actual path component, append it.
+        func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent
+      ;;
+    esac
+  done
+  # Restore leading double-slash if one was found on entry.
+  func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result
+}
+
+# func_relative_path SRCDIR DSTDIR
+# generates a relative path from SRCDIR to DSTDIR, with a trailing
+# slash if non-empty, suitable for immediately appending a filename
+# without needing to append a separator.
+#             value returned in "$func_relative_path_result"
+func_relative_path ()
+{
+  func_relative_path_result=
+  func_normal_abspath "$1"
+  func_relative_path_tlibdir=$func_normal_abspath_result
+  func_normal_abspath "$2"
+  func_relative_path_tbindir=$func_normal_abspath_result
+
+  # Ascend the tree starting from libdir
+  while :; do
+    # check if we have found a prefix of bindir
+    case $func_relative_path_tbindir in
+      $func_relative_path_tlibdir)
+        # found an exact match
+        func_relative_path_tcancelled=
+        break
+        ;;
+      $func_relative_path_tlibdir*)
+        # found a matching prefix
+        func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir"
+        func_relative_path_tcancelled=$func_stripname_result
+        if test -z "$func_relative_path_result"; then
+          func_relative_path_result=.
+        fi
+        break
+        ;;
+      *)
+        func_dirname $func_relative_path_tlibdir
+        func_relative_path_tlibdir=${func_dirname_result}
+        if test "x$func_relative_path_tlibdir" = x ; then
+          # Have to descend all the way to the root!
+          func_relative_path_result=../$func_relative_path_result
+          func_relative_path_tcancelled=$func_relative_path_tbindir
+          break
+        fi
+        func_relative_path_result=../$func_relative_path_result
+        ;;
+    esac
+  done
+
+  # Now calculate path; take care to avoid doubling-up slashes.
+  func_stripname '' '/' "$func_relative_path_result"
+  func_relative_path_result=$func_stripname_result
+  func_stripname '/' '/' "$func_relative_path_tcancelled"
+  if test "x$func_stripname_result" != x ; then
+    func_relative_path_result=${func_relative_path_result}/${func_stripname_result}
+  fi
+
+  # Normalisation. If bindir is libdir, return empty string,
+  # else relative path ending with a slash; either way, target
+  # file name can be directly appended.
+  if test ! -z "$func_relative_path_result"; then
+    func_stripname './' '' "$func_relative_path_result/"
+    func_relative_path_result=$func_stripname_result
+  fi
+}
+
+# The name of this program:
+func_dirname_and_basename "$progpath"
+progname=$func_basename_result
+
+# Make sure we have an absolute path for reexecution:
+case $progpath in
+  [\\/]*|[A-Za-z]:\\*) ;;
+  *[\\/]*)
+     progdir=$func_dirname_result
+     progdir=`cd "$progdir" && pwd`
+     progpath="$progdir/$progname"
+     ;;
+  *)
+     save_IFS="$IFS"
+     IFS=${PATH_SEPARATOR-:}
+     for progdir in $PATH; do
+       IFS="$save_IFS"
+       test -x "$progdir/$progname" && break
+     done
+     IFS="$save_IFS"
+     test -n "$progdir" || progdir=`pwd`
+     progpath="$progdir/$progname"
+     ;;
+esac
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed="${SED}"' -e 1s/^X//'
+sed_quote_subst='s/\([`"$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution that turns a string into a regex matching for the
+# string literally.
+sed_make_literal_regex='s,[].[^$\\*\/],\\&,g'
+
+# Sed substitution that converts a w32 file name or path
+# which contains forward slashes, into one that contains
+# (escaped) backslashes.  A very naive implementation.
+lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
+
+# Re-`\' parameter expansions in output of double_quote_subst that were
+# `\'-ed in input to the same.  If an odd number of `\' preceded a '$'
+# in input to double_quote_subst, that '$' was protected from expansion.
+# Since each input `\' is now two `\'s, look for any number of runs of
+# four `\'s followed by two `\'s and then a '$'.  `\' that '$'.
+bs='\\'
+bs2='\\\\'
+bs4='\\\\\\\\'
+dollar='\$'
+sed_double_backslash="\
+  s/$bs4/&\\
+/g
+  s/^$bs2$dollar/$bs&/
+  s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g
+  s/\n//g"
+
+# Standard options:
+opt_dry_run=false
+opt_help=false
+opt_quiet=false
+opt_verbose=false
+opt_warning=:
+
+# func_echo arg...
+# Echo program name prefixed message, along with the current mode
+# name if it has been set yet.
+func_echo ()
+{
+    $ECHO "$progname: ${opt_mode+$opt_mode: }$*"
+}
+
+# func_verbose arg...
+# Echo program name prefixed message in verbose mode only.
+func_verbose ()
+{
+    $opt_verbose && func_echo ${1+"$@"}
+
+    # A bug in bash halts the script if the last line of a function
+    # fails when set -e is in force, so we need another command to
+    # work around that:
+    :
+}
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO "$*"
+}
+
+# func_error arg...
+# Echo program name prefixed message to standard error.
+func_error ()
+{
+    $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2
+}
+
+# func_warning arg...
+# Echo program name prefixed warning message to standard error.
+func_warning ()
+{
+    $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2
+
+    # bash bug again:
+    :
+}
+
+# func_fatal_error arg...
+# Echo program name prefixed message to standard error, and exit.
+func_fatal_error ()
+{
+    func_error ${1+"$@"}
+    exit $EXIT_FAILURE
+}
+
+# func_fatal_help arg...
+# Echo program name prefixed message to standard error, followed by
+# a help hint, and exit.
+func_fatal_help ()
+{
+    func_error ${1+"$@"}
+    func_fatal_error "$help"
+}
+help="Try \`$progname --help' for more information."  ## default
+
+
+# func_grep expression filename
+# Check whether EXPRESSION matches any line of FILENAME, without output.
+func_grep ()
+{
+    $GREP "$1" "$2" >/dev/null 2>&1
+}
+
+
+# func_mkdir_p directory-path
+# Make sure the entire path to DIRECTORY-PATH is available.
+func_mkdir_p ()
+{
+    my_directory_path="$1"
+    my_dir_list=
+
+    if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then
+
+      # Protect directory names starting with `-'
+      case $my_directory_path in
+        -*) my_directory_path="./$my_directory_path" ;;
+      esac
+
+      # While some portion of DIR does not yet exist...
+      while test ! -d "$my_directory_path"; do
+        # ...make a list in topmost first order.  Use a colon delimited
+	# list incase some portion of path contains whitespace.
+        my_dir_list="$my_directory_path:$my_dir_list"
+
+        # If the last portion added has no slash in it, the list is done
+        case $my_directory_path in */*) ;; *) break ;; esac
+
+        # ...otherwise throw away the child directory and loop
+        my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"`
+      done
+      my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'`
+
+      save_mkdir_p_IFS="$IFS"; IFS=':'
+      for my_dir in $my_dir_list; do
+	IFS="$save_mkdir_p_IFS"
+        # mkdir can fail with a `File exist' error if two processes
+        # try to create one of the directories concurrently.  Don't
+        # stop in that case!
+        $MKDIR "$my_dir" 2>/dev/null || :
+      done
+      IFS="$save_mkdir_p_IFS"
+
+      # Bail out if we (or some other process) failed to create a directory.
+      test -d "$my_directory_path" || \
+        func_fatal_error "Failed to create \`$1'"
+    fi
+}
+
+
+# func_mktempdir [string]
+# Make a temporary directory that won't clash with other running
+# libtool processes, and avoids race conditions if possible.  If
+# given, STRING is the basename for that directory.
+func_mktempdir ()
+{
+    my_template="${TMPDIR-/tmp}/${1-$progname}"
+
+    if test "$opt_dry_run" = ":"; then
+      # Return a directory name, but don't create it in dry-run mode
+      my_tmpdir="${my_template}-$$"
+    else
+
+      # If mktemp works, use that first and foremost
+      my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null`
+
+      if test ! -d "$my_tmpdir"; then
+        # Failing that, at least try and use $RANDOM to avoid a race
+        my_tmpdir="${my_template}-${RANDOM-0}$$"
+
+        save_mktempdir_umask=`umask`
+        umask 0077
+        $MKDIR "$my_tmpdir"
+        umask $save_mktempdir_umask
+      fi
+
+      # If we're not in dry-run mode, bomb out on failure
+      test -d "$my_tmpdir" || \
+        func_fatal_error "cannot create temporary directory \`$my_tmpdir'"
+    fi
+
+    $ECHO "$my_tmpdir"
+}
+
+
+# func_quote_for_eval arg
+# Aesthetically quote ARG to be evaled later.
+# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT
+# is double-quoted, suitable for a subsequent eval, whereas
+# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters
+# which are still active within double quotes backslashified.
+func_quote_for_eval ()
+{
+    case $1 in
+      *[\\\`\"\$]*)
+	func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;;
+      *)
+        func_quote_for_eval_unquoted_result="$1" ;;
+    esac
+
+    case $func_quote_for_eval_unquoted_result in
+      # Double-quote args containing shell metacharacters to delay
+      # word splitting, command substitution and and variable
+      # expansion for a subsequent eval.
+      # Many Bourne shells cannot handle close brackets correctly
+      # in scan sets, so we specify it separately.
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+        func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\""
+        ;;
+      *)
+        func_quote_for_eval_result="$func_quote_for_eval_unquoted_result"
+    esac
+}
+
+
+# func_quote_for_expand arg
+# Aesthetically quote ARG to be evaled later; same as above,
+# but do not quote variable references.
+func_quote_for_expand ()
+{
+    case $1 in
+      *[\\\`\"]*)
+	my_arg=`$ECHO "$1" | $SED \
+	    -e "$double_quote_subst" -e "$sed_double_backslash"` ;;
+      *)
+        my_arg="$1" ;;
+    esac
+
+    case $my_arg in
+      # Double-quote args containing shell metacharacters to delay
+      # word splitting and command substitution for a subsequent eval.
+      # Many Bourne shells cannot handle close brackets correctly
+      # in scan sets, so we specify it separately.
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+        my_arg="\"$my_arg\""
+        ;;
+    esac
+
+    func_quote_for_expand_result="$my_arg"
+}
+
+
+# func_show_eval cmd [fail_exp]
+# Unless opt_silent is true, then output CMD.  Then, if opt_dryrun is
+# not true, evaluate CMD.  If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.
+func_show_eval ()
+{
+    my_cmd="$1"
+    my_fail_exp="${2-:}"
+
+    ${opt_silent-false} || {
+      func_quote_for_expand "$my_cmd"
+      eval "func_echo $func_quote_for_expand_result"
+    }
+
+    if ${opt_dry_run-false}; then :; else
+      eval "$my_cmd"
+      my_status=$?
+      if test "$my_status" -eq 0; then :; else
+	eval "(exit $my_status); $my_fail_exp"
+      fi
+    fi
+}
+
+
+# func_show_eval_locale cmd [fail_exp]
+# Unless opt_silent is true, then output CMD.  Then, if opt_dryrun is
+# not true, evaluate CMD.  If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.  Use the saved locale for evaluation.
+func_show_eval_locale ()
+{
+    my_cmd="$1"
+    my_fail_exp="${2-:}"
+
+    ${opt_silent-false} || {
+      func_quote_for_expand "$my_cmd"
+      eval "func_echo $func_quote_for_expand_result"
+    }
+
+    if ${opt_dry_run-false}; then :; else
+      eval "$lt_user_locale
+	    $my_cmd"
+      my_status=$?
+      eval "$lt_safe_locale"
+      if test "$my_status" -eq 0; then :; else
+	eval "(exit $my_status); $my_fail_exp"
+      fi
+    fi
+}
+
+# func_tr_sh
+# Turn $1 into a string suitable for a shell variable name.
+# Result is stored in $func_tr_sh_result.  All characters
+# not in the set a-zA-Z0-9_ are replaced with '_'. Further,
+# if $1 begins with a digit, a '_' is prepended as well.
+func_tr_sh ()
+{
+  case $1 in
+  [0-9]* | *[!a-zA-Z0-9_]*)
+    func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'`
+    ;;
+  * )
+    func_tr_sh_result=$1
+    ;;
+  esac
+}
+
+
+# func_version
+# Echo version message to standard output and exit.
+func_version ()
+{
+    $opt_debug
+
+    $SED -n '/(C)/!b go
+	:more
+	/\./!{
+	  N
+	  s/\n# / /
+	  b more
+	}
+	:go
+	/^# '$PROGRAM' (GNU /,/# warranty; / {
+        s/^# //
+	s/^# *$//
+        s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/
+        p
+     }' < "$progpath"
+     exit $?
+}
+
+# func_usage
+# Echo short help message to standard output and exit.
+func_usage ()
+{
+    $opt_debug
+
+    $SED -n '/^# Usage:/,/^#  *.*--help/ {
+        s/^# //
+	s/^# *$//
+	s/\$progname/'$progname'/
+	p
+    }' < "$progpath"
+    echo
+    $ECHO "run \`$progname --help | more' for full usage"
+    exit $?
+}
+
+# func_help [NOEXIT]
+# Echo long help message to standard output and exit,
+# unless 'noexit' is passed as argument.
+func_help ()
+{
+    $opt_debug
+
+    $SED -n '/^# Usage:/,/# Report bugs to/ {
+	:print
+        s/^# //
+	s/^# *$//
+	s*\$progname*'$progname'*
+	s*\$host*'"$host"'*
+	s*\$SHELL*'"$SHELL"'*
+	s*\$LTCC*'"$LTCC"'*
+	s*\$LTCFLAGS*'"$LTCFLAGS"'*
+	s*\$LD*'"$LD"'*
+	s/\$with_gnu_ld/'"$with_gnu_ld"'/
+	s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/
+	s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/
+	p
+	d
+     }
+     /^# .* home page:/b print
+     /^# General help using/b print
+     ' < "$progpath"
+    ret=$?
+    if test -z "$1"; then
+      exit $ret
+    fi
+}
+
+# func_missing_arg argname
+# Echo program name prefixed message to standard error and set global
+# exit_cmd.
+func_missing_arg ()
+{
+    $opt_debug
+
+    func_error "missing argument for $1."
+    exit_cmd=exit
+}
+
+
+# func_split_short_opt shortopt
+# Set func_split_short_opt_name and func_split_short_opt_arg shell
+# variables after splitting SHORTOPT after the 2nd character.
+func_split_short_opt ()
+{
+    my_sed_short_opt='1s/^\(..\).*$/\1/;q'
+    my_sed_short_rest='1s/^..\(.*\)$/\1/;q'
+
+    func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"`
+    func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"`
+} # func_split_short_opt may be replaced by extended shell implementation
+
+
+# func_split_long_opt longopt
+# Set func_split_long_opt_name and func_split_long_opt_arg shell
+# variables after splitting LONGOPT at the `=' sign.
+func_split_long_opt ()
+{
+    my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q'
+    my_sed_long_arg='1s/^--[^=]*=//'
+
+    func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"`
+    func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"`
+} # func_split_long_opt may be replaced by extended shell implementation
+
+exit_cmd=:
+
+
+
+
+
+magic="%%%MAGIC variable%%%"
+magic_exe="%%%MAGIC EXE variable%%%"
+
+# Global variables.
+nonopt=
+preserve_args=
+lo2o="s/\\.lo\$/.${objext}/"
+o2lo="s/\\.${objext}\$/.lo/"
+extracted_archives=
+extracted_serial=0
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end.  This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+    eval "${1}=\$${1}\${2}"
+} # func_append may be replaced by extended shell implementation
+
+# func_append_quoted var value
+# Quote VALUE and append to the end of shell variable VAR, separated
+# by a space.
+func_append_quoted ()
+{
+    func_quote_for_eval "${2}"
+    eval "${1}=\$${1}\\ \$func_quote_for_eval_result"
+} # func_append_quoted may be replaced by extended shell implementation
+
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+    func_arith_result=`expr "${@}"`
+} # func_arith may be replaced by extended shell implementation
+
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+    func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len`
+} # func_len may be replaced by extended shell implementation
+
+
+# func_lo2o object
+func_lo2o ()
+{
+    func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"`
+} # func_lo2o may be replaced by extended shell implementation
+
+
+# func_xform libobj-or-source
+func_xform ()
+{
+    func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'`
+} # func_xform may be replaced by extended shell implementation
+
+
+# func_fatal_configuration arg...
+# Echo program name prefixed message to standard error, followed by
+# a configuration failure hint, and exit.
+func_fatal_configuration ()
+{
+    func_error ${1+"$@"}
+    func_error "See the $PACKAGE documentation for more information."
+    func_fatal_error "Fatal configuration error."
+}
+
+
+# func_config
+# Display the configuration for all the tags in this script.
+func_config ()
+{
+    re_begincf='^# ### BEGIN LIBTOOL'
+    re_endcf='^# ### END LIBTOOL'
+
+    # Default configuration.
+    $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath"
+
+    # Now print the configurations for the tags.
+    for tagname in $taglist; do
+      $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath"
+    done
+
+    exit $?
+}
+
+# func_features
+# Display the features supported by this script.
+func_features ()
+{
+    echo "host: $host"
+    if test "$build_libtool_libs" = yes; then
+      echo "enable shared libraries"
+    else
+      echo "disable shared libraries"
+    fi
+    if test "$build_old_libs" = yes; then
+      echo "enable static libraries"
+    else
+      echo "disable static libraries"
+    fi
+
+    exit $?
+}
+
+# func_enable_tag tagname
+# Verify that TAGNAME is valid, and either flag an error and exit, or
+# enable the TAGNAME tag.  We also add TAGNAME to the global $taglist
+# variable here.
+func_enable_tag ()
+{
+  # Global variable:
+  tagname="$1"
+
+  re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$"
+  re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$"
+  sed_extractcf="/$re_begincf/,/$re_endcf/p"
+
+  # Validate tagname.
+  case $tagname in
+    *[!-_A-Za-z0-9,/]*)
+      func_fatal_error "invalid tag name: $tagname"
+      ;;
+  esac
+
+  # Don't test for the "default" C tag, as we know it's
+  # there but not specially marked.
+  case $tagname in
+    CC) ;;
+    *)
+      if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then
+	taglist="$taglist $tagname"
+
+	# Evaluate the configuration.  Be careful to quote the path
+	# and the sed script, to avoid splitting on whitespace, but
+	# also don't use non-portable quotes within backquotes within
+	# quotes we have to do it in 2 steps:
+	extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"`
+	eval "$extractedcf"
+      else
+	func_error "ignoring unknown tag $tagname"
+      fi
+      ;;
+  esac
+}
+
+# func_check_version_match
+# Ensure that we are using m4 macros, and libtool script from the same
+# release of libtool.
+func_check_version_match ()
+{
+  if test "$package_revision" != "$macro_revision"; then
+    if test "$VERSION" != "$macro_version"; then
+      if test -z "$macro_version"; then
+        cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from an older release.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+      else
+        cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from $PACKAGE $macro_version.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+      fi
+    else
+      cat >&2 <<_LT_EOF
+$progname: Version mismatch error.  This is $PACKAGE $VERSION, revision $package_revision,
+$progname: but the definition of this LT_INIT comes from revision $macro_revision.
+$progname: You should recreate aclocal.m4 with macros from revision $package_revision
+$progname: of $PACKAGE $VERSION and run autoconf again.
+_LT_EOF
+    fi
+
+    exit $EXIT_MISMATCH
+  fi
+}
+
+
+# Shorthand for --mode=foo, only valid as the first argument
+case $1 in
+clean|clea|cle|cl)
+  shift; set dummy --mode clean ${1+"$@"}; shift
+  ;;
+compile|compil|compi|comp|com|co|c)
+  shift; set dummy --mode compile ${1+"$@"}; shift
+  ;;
+execute|execut|execu|exec|exe|ex|e)
+  shift; set dummy --mode execute ${1+"$@"}; shift
+  ;;
+finish|finis|fini|fin|fi|f)
+  shift; set dummy --mode finish ${1+"$@"}; shift
+  ;;
+install|instal|insta|inst|ins|in|i)
+  shift; set dummy --mode install ${1+"$@"}; shift
+  ;;
+link|lin|li|l)
+  shift; set dummy --mode link ${1+"$@"}; shift
+  ;;
+uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u)
+  shift; set dummy --mode uninstall ${1+"$@"}; shift
+  ;;
+esac
+
+
+
+# Option defaults:
+opt_debug=:
+opt_dry_run=false
+opt_config=false
+opt_preserve_dup_deps=false
+opt_features=false
+opt_finish=false
+opt_help=false
+opt_help_all=false
+opt_silent=:
+opt_warning=:
+opt_verbose=:
+opt_silent=false
+opt_verbose=false
+
+
+# Parse options once, thoroughly.  This comes as soon as possible in the
+# script to make things like `--version' happen as quickly as we can.
+{
+  # this just eases exit handling
+  while test $# -gt 0; do
+    opt="$1"
+    shift
+    case $opt in
+      --debug|-x)	opt_debug='set -x'
+			func_echo "enabling shell trace mode"
+			$opt_debug
+			;;
+      --dry-run|--dryrun|-n)
+			opt_dry_run=:
+			;;
+      --config)
+			opt_config=:
+func_config
+			;;
+      --dlopen|-dlopen)
+			optarg="$1"
+			opt_dlopen="${opt_dlopen+$opt_dlopen
+}$optarg"
+			shift
+			;;
+      --preserve-dup-deps)
+			opt_preserve_dup_deps=:
+			;;
+      --features)
+			opt_features=:
+func_features
+			;;
+      --finish)
+			opt_finish=:
+set dummy --mode finish ${1+"$@"}; shift
+			;;
+      --help)
+			opt_help=:
+			;;
+      --help-all)
+			opt_help_all=:
+opt_help=': help-all'
+			;;
+      --mode)
+			test $# = 0 && func_missing_arg $opt && break
+			optarg="$1"
+			opt_mode="$optarg"
+case $optarg in
+  # Valid mode arguments:
+  clean|compile|execute|finish|install|link|relink|uninstall) ;;
+
+  # Catch anything else as an error
+  *) func_error "invalid argument for $opt"
+     exit_cmd=exit
+     break
+     ;;
+esac
+			shift
+			;;
+      --no-silent|--no-quiet)
+			opt_silent=false
+func_append preserve_args " $opt"
+			;;
+      --no-warning|--no-warn)
+			opt_warning=false
+func_append preserve_args " $opt"
+			;;
+      --no-verbose)
+			opt_verbose=false
+func_append preserve_args " $opt"
+			;;
+      --silent|--quiet)
+			opt_silent=:
+func_append preserve_args " $opt"
+        opt_verbose=false
+			;;
+      --verbose|-v)
+			opt_verbose=:
+func_append preserve_args " $opt"
+opt_silent=false
+			;;
+      --tag)
+			test $# = 0 && func_missing_arg $opt && break
+			optarg="$1"
+			opt_tag="$optarg"
+func_append preserve_args " $opt $optarg"
+func_enable_tag "$optarg"
+			shift
+			;;
+
+      -\?|-h)		func_usage				;;
+      --help)		func_help				;;
+      --version)	func_version				;;
+
+      # Separate optargs to long options:
+      --*=*)
+			func_split_long_opt "$opt"
+			set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"}
+			shift
+			;;
+
+      # Separate non-argument short options:
+      -\?*|-h*|-n*|-v*)
+			func_split_short_opt "$opt"
+			set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"}
+			shift
+			;;
+
+      --)		break					;;
+      -*)		func_fatal_help "unrecognized option \`$opt'" ;;
+      *)		set dummy "$opt" ${1+"$@"};	shift; break  ;;
+    esac
+  done
+
+  # Validate options:
+
+  # save first non-option argument
+  if test "$#" -gt 0; then
+    nonopt="$opt"
+    shift
+  fi
+
+  # preserve --debug
+  test "$opt_debug" = : || func_append preserve_args " --debug"
+
+  case $host in
+    *cygwin* | *mingw* | *pw32* | *cegcc*)
+      # don't eliminate duplications in $postdeps and $predeps
+      opt_duplicate_compiler_generated_deps=:
+      ;;
+    *)
+      opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps
+      ;;
+  esac
+
+  $opt_help || {
+    # Sanity checks first:
+    func_check_version_match
+
+    if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
+      func_fatal_configuration "not configured to build any kind of library"
+    fi
+
+    # Darwin sucks
+    eval std_shrext=\"$shrext_cmds\"
+
+    # Only execute mode is allowed to have -dlopen flags.
+    if test -n "$opt_dlopen" && test "$opt_mode" != execute; then
+      func_error "unrecognized option \`-dlopen'"
+      $ECHO "$help" 1>&2
+      exit $EXIT_FAILURE
+    fi
+
+    # Change the help message to a mode-specific one.
+    generic_help="$help"
+    help="Try \`$progname --help --mode=$opt_mode' for more information."
+  }
+
+
+  # Bail if the options were screwed
+  $exit_cmd $EXIT_FAILURE
+}
+
+
+
+
+## ----------- ##
+##    Main.    ##
+## ----------- ##
+
+# func_lalib_p file
+# True iff FILE is a libtool `.la' library or `.lo' object file.
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_lalib_p ()
+{
+    test -f "$1" &&
+      $SED -e 4q "$1" 2>/dev/null \
+        | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1
+}
+
+# func_lalib_unsafe_p file
+# True iff FILE is a libtool `.la' library or `.lo' object file.
+# This function implements the same check as func_lalib_p without
+# resorting to external programs.  To this end, it redirects stdin and
+# closes it afterwards, without saving the original file descriptor.
+# As a safety measure, use it only where a negative result would be
+# fatal anyway.  Works if `file' does not exist.
+func_lalib_unsafe_p ()
+{
+    lalib_p=no
+    if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then
+	for lalib_p_l in 1 2 3 4
+	do
+	    read lalib_p_line
+	    case "$lalib_p_line" in
+		\#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;;
+	    esac
+	done
+	exec 0<&5 5<&-
+    fi
+    test "$lalib_p" = yes
+}
+
+# func_ltwrapper_script_p file
+# True iff FILE is a libtool wrapper script
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_script_p ()
+{
+    func_lalib_p "$1"
+}
+
+# func_ltwrapper_executable_p file
+# True iff FILE is a libtool wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_executable_p ()
+{
+    func_ltwrapper_exec_suffix=
+    case $1 in
+    *.exe) ;;
+    *) func_ltwrapper_exec_suffix=.exe ;;
+    esac
+    $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1
+}
+
+# func_ltwrapper_scriptname file
+# Assumes file is an ltwrapper_executable
+# uses $file to determine the appropriate filename for a
+# temporary ltwrapper_script.
+func_ltwrapper_scriptname ()
+{
+    func_dirname_and_basename "$1" "" "."
+    func_stripname '' '.exe' "$func_basename_result"
+    func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper"
+}
+
+# func_ltwrapper_p file
+# True iff FILE is a libtool wrapper script or wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_p ()
+{
+    func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1"
+}
+
+
+# func_execute_cmds commands fail_cmd
+# Execute tilde-delimited COMMANDS.
+# If FAIL_CMD is given, eval that upon failure.
+# FAIL_CMD may read-access the current command in variable CMD!
+func_execute_cmds ()
+{
+    $opt_debug
+    save_ifs=$IFS; IFS='~'
+    for cmd in $1; do
+      IFS=$save_ifs
+      eval cmd=\"$cmd\"
+      func_show_eval "$cmd" "${2-:}"
+    done
+    IFS=$save_ifs
+}
+
+
+# func_source file
+# Source FILE, adding directory component if necessary.
+# Note that it is not necessary on cygwin/mingw to append a dot to
+# FILE even if both FILE and FILE.exe exist: automatic-append-.exe
+# behavior happens only for exec(3), not for open(2)!  Also, sourcing
+# `FILE.' does not work on cygwin managed mounts.
+func_source ()
+{
+    $opt_debug
+    case $1 in
+    */* | *\\*)	. "$1" ;;
+    *)		. "./$1" ;;
+    esac
+}
+
+
+# func_resolve_sysroot PATH
+# Replace a leading = in PATH with a sysroot.  Store the result into
+# func_resolve_sysroot_result
+func_resolve_sysroot ()
+{
+  func_resolve_sysroot_result=$1
+  case $func_resolve_sysroot_result in
+  =*)
+    func_stripname '=' '' "$func_resolve_sysroot_result"
+    func_resolve_sysroot_result=$lt_sysroot$func_stripname_result
+    ;;
+  esac
+}
+
+# func_replace_sysroot PATH
+# If PATH begins with the sysroot, replace it with = and
+# store the result into func_replace_sysroot_result.
+func_replace_sysroot ()
+{
+  case "$lt_sysroot:$1" in
+  ?*:"$lt_sysroot"*)
+    func_stripname "$lt_sysroot" '' "$1"
+    func_replace_sysroot_result="=$func_stripname_result"
+    ;;
+  *)
+    # Including no sysroot.
+    func_replace_sysroot_result=$1
+    ;;
+  esac
+}
+
+# func_infer_tag arg
+# Infer tagged configuration to use if any are available and
+# if one wasn't chosen via the "--tag" command line option.
+# Only attempt this if the compiler in the base compile
+# command doesn't match the default compiler.
+# arg is usually of the form 'gcc ...'
+func_infer_tag ()
+{
+    $opt_debug
+    if test -n "$available_tags" && test -z "$tagname"; then
+      CC_quoted=
+      for arg in $CC; do
+	func_append_quoted CC_quoted "$arg"
+      done
+      CC_expanded=`func_echo_all $CC`
+      CC_quoted_expanded=`func_echo_all $CC_quoted`
+      case $@ in
+      # Blanks in the command may have been stripped by the calling shell,
+      # but not from the CC environment variable when configure was run.
+      " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+      " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;;
+      # Blanks at the start of $base_compile will cause this to fail
+      # if we don't check for them as well.
+      *)
+	for z in $available_tags; do
+	  if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
+	    # Evaluate the configuration.
+	    eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
+	    CC_quoted=
+	    for arg in $CC; do
+	      # Double-quote args containing other shell metacharacters.
+	      func_append_quoted CC_quoted "$arg"
+	    done
+	    CC_expanded=`func_echo_all $CC`
+	    CC_quoted_expanded=`func_echo_all $CC_quoted`
+	    case "$@ " in
+	    " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+	    " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*)
+	      # The compiler in the base compile command matches
+	      # the one in the tagged configuration.
+	      # Assume this is the tagged configuration we want.
+	      tagname=$z
+	      break
+	      ;;
+	    esac
+	  fi
+	done
+	# If $tagname still isn't set, then no tagged configuration
+	# was found and let the user know that the "--tag" command
+	# line option must be used.
+	if test -z "$tagname"; then
+	  func_echo "unable to infer tagged configuration"
+	  func_fatal_error "specify a tag with \`--tag'"
+#	else
+#	  func_verbose "using $tagname tagged configuration"
+	fi
+	;;
+      esac
+    fi
+}
+
+
+
+# func_write_libtool_object output_name pic_name nonpic_name
+# Create a libtool object file (analogous to a ".la" file),
+# but don't create it if we're doing a dry run.
+func_write_libtool_object ()
+{
+    write_libobj=${1}
+    if test "$build_libtool_libs" = yes; then
+      write_lobj=\'${2}\'
+    else
+      write_lobj=none
+    fi
+
+    if test "$build_old_libs" = yes; then
+      write_oldobj=\'${3}\'
+    else
+      write_oldobj=none
+    fi
+
+    $opt_dry_run || {
+      cat >${write_libobj}T <<EOF
+# $write_libobj - a libtool object file
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object=$write_lobj
+
+# Name of the non-PIC object
+non_pic_object=$write_oldobj
+
+EOF
+      $MV "${write_libobj}T" "${write_libobj}"
+    }
+}
+
+
+##################################################
+# FILE NAME AND PATH CONVERSION HELPER FUNCTIONS #
+##################################################
+
+# func_convert_core_file_wine_to_w32 ARG
+# Helper function used by file name conversion functions when $build is *nix,
+# and $host is mingw, cygwin, or some other w32 environment. Relies on a
+# correctly configured wine environment available, with the winepath program
+# in $build's $PATH.
+#
+# ARG is the $build file name to be converted to w32 format.
+# Result is available in $func_convert_core_file_wine_to_w32_result, and will
+# be empty on error (or when ARG is empty)
+func_convert_core_file_wine_to_w32 ()
+{
+  $opt_debug
+  func_convert_core_file_wine_to_w32_result="$1"
+  if test -n "$1"; then
+    # Unfortunately, winepath does not exit with a non-zero error code, so we
+    # are forced to check the contents of stdout. On the other hand, if the
+    # command is not found, the shell will set an exit code of 127 and print
+    # *an error message* to stdout. So we must check for both error code of
+    # zero AND non-empty stdout, which explains the odd construction:
+    func_convert_core_file_wine_to_w32_tmp=`winepath -w "$1" 2>/dev/null`
+    if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then
+      func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" |
+        $SED -e "$lt_sed_naive_backslashify"`
+    else
+      func_convert_core_file_wine_to_w32_result=
+    fi
+  fi
+}
+# end: func_convert_core_file_wine_to_w32
+
+
+# func_convert_core_path_wine_to_w32 ARG
+# Helper function used by path conversion functions when $build is *nix, and
+# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly
+# configured wine environment available, with the winepath program in $build's
+# $PATH. Assumes ARG has no leading or trailing path separator characters.
+#
+# ARG is path to be converted from $build format to win32.
+# Result is available in $func_convert_core_path_wine_to_w32_result.
+# Unconvertible file (directory) names in ARG are skipped; if no directory names
+# are convertible, then the result may be empty.
+func_convert_core_path_wine_to_w32 ()
+{
+  $opt_debug
+  # unfortunately, winepath doesn't convert paths, only file names
+  func_convert_core_path_wine_to_w32_result=""
+  if test -n "$1"; then
+    oldIFS=$IFS
+    IFS=:
+    for func_convert_core_path_wine_to_w32_f in $1; do
+      IFS=$oldIFS
+      func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f"
+      if test -n "$func_convert_core_file_wine_to_w32_result" ; then
+        if test -z "$func_convert_core_path_wine_to_w32_result"; then
+          func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result"
+        else
+          func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result"
+        fi
+      fi
+    done
+    IFS=$oldIFS
+  fi
+}
+# end: func_convert_core_path_wine_to_w32
+
+
+# func_cygpath ARGS...
+# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when
+# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2)
+# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or
+# (2), returns the Cygwin file name or path in func_cygpath_result (input
+# file name or path is assumed to be in w32 format, as previously converted
+# from $build's *nix or MSYS format). In case (3), returns the w32 file name
+# or path in func_cygpath_result (input file name or path is assumed to be in
+# Cygwin format). Returns an empty string on error.
+#
+# ARGS are passed to cygpath, with the last one being the file name or path to
+# be converted.
+#
+# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH
+# environment variable; do not put it in $PATH.
+func_cygpath ()
+{
+  $opt_debug
+  if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then
+    func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null`
+    if test "$?" -ne 0; then
+      # on failure, ensure result is empty
+      func_cygpath_result=
+    fi
+  else
+    func_cygpath_result=
+    func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'"
+  fi
+}
+#end: func_cygpath
+
+
+# func_convert_core_msys_to_w32 ARG
+# Convert file name or path ARG from MSYS format to w32 format.  Return
+# result in func_convert_core_msys_to_w32_result.
+func_convert_core_msys_to_w32 ()
+{
+  $opt_debug
+  # awkward: cmd appends spaces to result
+  func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null |
+    $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"`
+}
+#end: func_convert_core_msys_to_w32
+
+
+# func_convert_file_check ARG1 ARG2
+# Verify that ARG1 (a file name in $build format) was converted to $host
+# format in ARG2. Otherwise, emit an error message, but continue (resetting
+# func_to_host_file_result to ARG1).
+func_convert_file_check ()
+{
+  $opt_debug
+  if test -z "$2" && test -n "$1" ; then
+    func_error "Could not determine host file name corresponding to"
+    func_error "  \`$1'"
+    func_error "Continuing, but uninstalled executables may not work."
+    # Fallback:
+    func_to_host_file_result="$1"
+  fi
+}
+# end func_convert_file_check
+
+
+# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH
+# Verify that FROM_PATH (a path in $build format) was converted to $host
+# format in TO_PATH. Otherwise, emit an error message, but continue, resetting
+# func_to_host_file_result to a simplistic fallback value (see below).
+func_convert_path_check ()
+{
+  $opt_debug
+  if test -z "$4" && test -n "$3"; then
+    func_error "Could not determine the host path corresponding to"
+    func_error "  \`$3'"
+    func_error "Continuing, but uninstalled executables may not work."
+    # Fallback.  This is a deliberately simplistic "conversion" and
+    # should not be "improved".  See libtool.info.
+    if test "x$1" != "x$2"; then
+      lt_replace_pathsep_chars="s|$1|$2|g"
+      func_to_host_path_result=`echo "$3" |
+        $SED -e "$lt_replace_pathsep_chars"`
+    else
+      func_to_host_path_result="$3"
+    fi
+  fi
+}
+# end func_convert_path_check
+
+
+# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG
+# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT
+# and appending REPL if ORIG matches BACKPAT.
+func_convert_path_front_back_pathsep ()
+{
+  $opt_debug
+  case $4 in
+  $1 ) func_to_host_path_result="$3$func_to_host_path_result"
+    ;;
+  esac
+  case $4 in
+  $2 ) func_append func_to_host_path_result "$3"
+    ;;
+  esac
+}
+# end func_convert_path_front_back_pathsep
+
+
+##################################################
+# $build to $host FILE NAME CONVERSION FUNCTIONS #
+##################################################
+# invoked via `$to_host_file_cmd ARG'
+#
+# In each case, ARG is the path to be converted from $build to $host format.
+# Result will be available in $func_to_host_file_result.
+
+
+# func_to_host_file ARG
+# Converts the file name ARG from $build format to $host format. Return result
+# in func_to_host_file_result.
+func_to_host_file ()
+{
+  $opt_debug
+  $to_host_file_cmd "$1"
+}
+# end func_to_host_file
+
+
+# func_to_tool_file ARG LAZY
+# converts the file name ARG from $build format to toolchain format. Return
+# result in func_to_tool_file_result.  If the conversion in use is listed
+# in (the comma separated) LAZY, no conversion takes place.
+func_to_tool_file ()
+{
+  $opt_debug
+  case ,$2, in
+    *,"$to_tool_file_cmd",*)
+      func_to_tool_file_result=$1
+      ;;
+    *)
+      $to_tool_file_cmd "$1"
+      func_to_tool_file_result=$func_to_host_file_result
+      ;;
+  esac
+}
+# end func_to_tool_file
+
+
+# func_convert_file_noop ARG
+# Copy ARG to func_to_host_file_result.
+func_convert_file_noop ()
+{
+  func_to_host_file_result="$1"
+}
+# end func_convert_file_noop
+
+
+# func_convert_file_msys_to_w32 ARG
+# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic
+# conversion to w32 is not available inside the cwrapper.  Returns result in
+# func_to_host_file_result.
+func_convert_file_msys_to_w32 ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    func_convert_core_msys_to_w32 "$1"
+    func_to_host_file_result="$func_convert_core_msys_to_w32_result"
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_msys_to_w32
+
+
+# func_convert_file_cygwin_to_w32 ARG
+# Convert file name ARG from Cygwin to w32 format.  Returns result in
+# func_to_host_file_result.
+func_convert_file_cygwin_to_w32 ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    # because $build is cygwin, we call "the" cygpath in $PATH; no need to use
+    # LT_CYGPATH in this case.
+    func_to_host_file_result=`cygpath -m "$1"`
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_cygwin_to_w32
+
+
+# func_convert_file_nix_to_w32 ARG
+# Convert file name ARG from *nix to w32 format.  Requires a wine environment
+# and a working winepath. Returns result in func_to_host_file_result.
+func_convert_file_nix_to_w32 ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    func_convert_core_file_wine_to_w32 "$1"
+    func_to_host_file_result="$func_convert_core_file_wine_to_w32_result"
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_nix_to_w32
+
+
+# func_convert_file_msys_to_cygwin ARG
+# Convert file name ARG from MSYS to Cygwin format.  Requires LT_CYGPATH set.
+# Returns result in func_to_host_file_result.
+func_convert_file_msys_to_cygwin ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    func_convert_core_msys_to_w32 "$1"
+    func_cygpath -u "$func_convert_core_msys_to_w32_result"
+    func_to_host_file_result="$func_cygpath_result"
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_msys_to_cygwin
+
+
+# func_convert_file_nix_to_cygwin ARG
+# Convert file name ARG from *nix to Cygwin format.  Requires Cygwin installed
+# in a wine environment, working winepath, and LT_CYGPATH set.  Returns result
+# in func_to_host_file_result.
+func_convert_file_nix_to_cygwin ()
+{
+  $opt_debug
+  func_to_host_file_result="$1"
+  if test -n "$1"; then
+    # convert from *nix to w32, then use cygpath to convert from w32 to cygwin.
+    func_convert_core_file_wine_to_w32 "$1"
+    func_cygpath -u "$func_convert_core_file_wine_to_w32_result"
+    func_to_host_file_result="$func_cygpath_result"
+  fi
+  func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_nix_to_cygwin
+
+
+#############################################
+# $build to $host PATH CONVERSION FUNCTIONS #
+#############################################
+# invoked via `$to_host_path_cmd ARG'
+#
+# In each case, ARG is the path to be converted from $build to $host format.
+# The result will be available in $func_to_host_path_result.
+#
+# Path separators are also converted from $build format to $host format.  If
+# ARG begins or ends with a path separator character, it is preserved (but
+# converted to $host format) on output.
+#
+# All path conversion functions are named using the following convention:
+#   file name conversion function    : func_convert_file_X_to_Y ()
+#   path conversion function         : func_convert_path_X_to_Y ()
+# where, for any given $build/$host combination the 'X_to_Y' value is the
+# same.  If conversion functions are added for new $build/$host combinations,
+# the two new functions must follow this pattern, or func_init_to_host_path_cmd
+# will break.
+
+
+# func_init_to_host_path_cmd
+# Ensures that function "pointer" variable $to_host_path_cmd is set to the
+# appropriate value, based on the value of $to_host_file_cmd.
+to_host_path_cmd=
+func_init_to_host_path_cmd ()
+{
+  $opt_debug
+  if test -z "$to_host_path_cmd"; then
+    func_stripname 'func_convert_file_' '' "$to_host_file_cmd"
+    to_host_path_cmd="func_convert_path_${func_stripname_result}"
+  fi
+}
+
+
+# func_to_host_path ARG
+# Converts the path ARG from $build format to $host format. Return result
+# in func_to_host_path_result.
+func_to_host_path ()
+{
+  $opt_debug
+  func_init_to_host_path_cmd
+  $to_host_path_cmd "$1"
+}
+# end func_to_host_path
+
+
+# func_convert_path_noop ARG
+# Copy ARG to func_to_host_path_result.
+func_convert_path_noop ()
+{
+  func_to_host_path_result="$1"
+}
+# end func_convert_path_noop
+
+
+# func_convert_path_msys_to_w32 ARG
+# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic
+# conversion to w32 is not available inside the cwrapper.  Returns result in
+# func_to_host_path_result.
+func_convert_path_msys_to_w32 ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # Remove leading and trailing path separator characters from ARG.  MSYS
+    # behavior is inconsistent here; cygpath turns them into '.;' and ';.';
+    # and winepath ignores them completely.
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
+    func_to_host_path_result="$func_convert_core_msys_to_w32_result"
+    func_convert_path_check : ";" \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_convert_path_msys_to_w32
+
+
+# func_convert_path_cygwin_to_w32 ARG
+# Convert path ARG from Cygwin to w32 format.  Returns result in
+# func_to_host_file_result.
+func_convert_path_cygwin_to_w32 ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # See func_convert_path_msys_to_w32:
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"`
+    func_convert_path_check : ";" \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_convert_path_cygwin_to_w32
+
+
+# func_convert_path_nix_to_w32 ARG
+# Convert path ARG from *nix to w32 format.  Requires a wine environment and
+# a working winepath.  Returns result in func_to_host_file_result.
+func_convert_path_nix_to_w32 ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # See func_convert_path_msys_to_w32:
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
+    func_to_host_path_result="$func_convert_core_path_wine_to_w32_result"
+    func_convert_path_check : ";" \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+  fi
+}
+# end func_convert_path_nix_to_w32
+
+
+# func_convert_path_msys_to_cygwin ARG
+# Convert path ARG from MSYS to Cygwin format.  Requires LT_CYGPATH set.
+# Returns result in func_to_host_file_result.
+func_convert_path_msys_to_cygwin ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # See func_convert_path_msys_to_w32:
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
+    func_cygpath -u -p "$func_convert_core_msys_to_w32_result"
+    func_to_host_path_result="$func_cygpath_result"
+    func_convert_path_check : : \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" : "$1"
+  fi
+}
+# end func_convert_path_msys_to_cygwin
+
+
+# func_convert_path_nix_to_cygwin ARG
+# Convert path ARG from *nix to Cygwin format.  Requires Cygwin installed in a
+# a wine environment, working winepath, and LT_CYGPATH set.  Returns result in
+# func_to_host_file_result.
+func_convert_path_nix_to_cygwin ()
+{
+  $opt_debug
+  func_to_host_path_result="$1"
+  if test -n "$1"; then
+    # Remove leading and trailing path separator characters from
+    # ARG. msys behavior is inconsistent here, cygpath turns them
+    # into '.;' and ';.', and winepath ignores them completely.
+    func_stripname : : "$1"
+    func_to_host_path_tmp1=$func_stripname_result
+    func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
+    func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result"
+    func_to_host_path_result="$func_cygpath_result"
+    func_convert_path_check : : \
+      "$func_to_host_path_tmp1" "$func_to_host_path_result"
+    func_convert_path_front_back_pathsep ":*" "*:" : "$1"
+  fi
+}
+# end func_convert_path_nix_to_cygwin
+
+
+# func_mode_compile arg...
+func_mode_compile ()
+{
+    $opt_debug
+    # Get the compilation command and the source file.
+    base_compile=
+    srcfile="$nonopt"  #  always keep a non-empty value in "srcfile"
+    suppress_opt=yes
+    suppress_output=
+    arg_mode=normal
+    libobj=
+    later=
+    pie_flag=
+
+    for arg
+    do
+      case $arg_mode in
+      arg  )
+	# do not "continue".  Instead, add this to base_compile
+	lastarg="$arg"
+	arg_mode=normal
+	;;
+
+      target )
+	libobj="$arg"
+	arg_mode=normal
+	continue
+	;;
+
+      normal )
+	# Accept any command-line options.
+	case $arg in
+	-o)
+	  test -n "$libobj" && \
+	    func_fatal_error "you cannot specify \`-o' more than once"
+	  arg_mode=target
+	  continue
+	  ;;
+
+	-pie | -fpie | -fPIE)
+          func_append pie_flag " $arg"
+	  continue
+	  ;;
+
+	-shared | -static | -prefer-pic | -prefer-non-pic)
+	  func_append later " $arg"
+	  continue
+	  ;;
+
+	-no-suppress)
+	  suppress_opt=no
+	  continue
+	  ;;
+
+	-Xcompiler)
+	  arg_mode=arg  #  the next one goes into the "base_compile" arg list
+	  continue      #  The current "srcfile" will either be retained or
+	  ;;            #  replaced later.  I would guess that would be a bug.
+
+	-Wc,*)
+	  func_stripname '-Wc,' '' "$arg"
+	  args=$func_stripname_result
+	  lastarg=
+	  save_ifs="$IFS"; IFS=','
+	  for arg in $args; do
+	    IFS="$save_ifs"
+	    func_append_quoted lastarg "$arg"
+	  done
+	  IFS="$save_ifs"
+	  func_stripname ' ' '' "$lastarg"
+	  lastarg=$func_stripname_result
+
+	  # Add the arguments to base_compile.
+	  func_append base_compile " $lastarg"
+	  continue
+	  ;;
+
+	*)
+	  # Accept the current argument as the source file.
+	  # The previous "srcfile" becomes the current argument.
+	  #
+	  lastarg="$srcfile"
+	  srcfile="$arg"
+	  ;;
+	esac  #  case $arg
+	;;
+      esac    #  case $arg_mode
+
+      # Aesthetically quote the previous argument.
+      func_append_quoted base_compile "$lastarg"
+    done # for arg
+
+    case $arg_mode in
+    arg)
+      func_fatal_error "you must specify an argument for -Xcompile"
+      ;;
+    target)
+      func_fatal_error "you must specify a target with \`-o'"
+      ;;
+    *)
+      # Get the name of the library object.
+      test -z "$libobj" && {
+	func_basename "$srcfile"
+	libobj="$func_basename_result"
+      }
+      ;;
+    esac
+
+    # Recognize several different file suffixes.
+    # If the user specifies -o file.o, it is replaced with file.lo
+    case $libobj in
+    *.[cCFSifmso] | \
+    *.ada | *.adb | *.ads | *.asm | \
+    *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \
+    *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup)
+      func_xform "$libobj"
+      libobj=$func_xform_result
+      ;;
+    esac
+
+    case $libobj in
+    *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;;
+    *)
+      func_fatal_error "cannot determine name of library object from \`$libobj'"
+      ;;
+    esac
+
+    func_infer_tag $base_compile
+
+    for arg in $later; do
+      case $arg in
+      -shared)
+	test "$build_libtool_libs" != yes && \
+	  func_fatal_configuration "can not build a shared library"
+	build_old_libs=no
+	continue
+	;;
+
+      -static)
+	build_libtool_libs=no
+	build_old_libs=yes
+	continue
+	;;
+
+      -prefer-pic)
+	pic_mode=yes
+	continue
+	;;
+
+      -prefer-non-pic)
+	pic_mode=no
+	continue
+	;;
+      esac
+    done
+
+    func_quote_for_eval "$libobj"
+    test "X$libobj" != "X$func_quote_for_eval_result" \
+      && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"'	 &()|`$[]' \
+      && func_warning "libobj name \`$libobj' may not contain shell special characters."
+    func_dirname_and_basename "$obj" "/" ""
+    objname="$func_basename_result"
+    xdir="$func_dirname_result"
+    lobj=${xdir}$objdir/$objname
+
+    test -z "$base_compile" && \
+      func_fatal_help "you must specify a compilation command"
+
+    # Delete any leftover library objects.
+    if test "$build_old_libs" = yes; then
+      removelist="$obj $lobj $libobj ${libobj}T"
+    else
+      removelist="$lobj $libobj ${libobj}T"
+    fi
+
+    # On Cygwin there's no "real" PIC flag so we must build both object types
+    case $host_os in
+    cygwin* | mingw* | pw32* | os2* | cegcc*)
+      pic_mode=default
+      ;;
+    esac
+    if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then
+      # non-PIC code in shared libraries is not supported
+      pic_mode=default
+    fi
+
+    # Calculate the filename of the output object if compiler does
+    # not support -o with -c
+    if test "$compiler_c_o" = no; then
+      output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext}
+      lockfile="$output_obj.lock"
+    else
+      output_obj=
+      need_locks=no
+      lockfile=
+    fi
+
+    # Lock this critical section if it is needed
+    # We use this script file to make the link, it avoids creating a new file
+    if test "$need_locks" = yes; then
+      until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+	func_echo "Waiting for $lockfile to be removed"
+	sleep 2
+      done
+    elif test "$need_locks" = warn; then
+      if test -f "$lockfile"; then
+	$ECHO "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$opt_dry_run || $RM $removelist
+	exit $EXIT_FAILURE
+      fi
+      func_append removelist " $output_obj"
+      $ECHO "$srcfile" > "$lockfile"
+    fi
+
+    $opt_dry_run || $RM $removelist
+    func_append removelist " $lockfile"
+    trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15
+
+    func_to_tool_file "$srcfile" func_convert_file_msys_to_w32
+    srcfile=$func_to_tool_file_result
+    func_quote_for_eval "$srcfile"
+    qsrcfile=$func_quote_for_eval_result
+
+    # Only build a PIC object if we are building libtool libraries.
+    if test "$build_libtool_libs" = yes; then
+      # Without this assignment, base_compile gets emptied.
+      fbsd_hideous_sh_bug=$base_compile
+
+      if test "$pic_mode" != no; then
+	command="$base_compile $qsrcfile $pic_flag"
+      else
+	# Don't build PIC code
+	command="$base_compile $qsrcfile"
+      fi
+
+      func_mkdir_p "$xdir$objdir"
+
+      if test -z "$output_obj"; then
+	# Place PIC objects in $objdir
+	func_append command " -o $lobj"
+      fi
+
+      func_show_eval_locale "$command"	\
+          'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE'
+
+      if test "$need_locks" = warn &&
+	 test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+	$ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$opt_dry_run || $RM $removelist
+	exit $EXIT_FAILURE
+      fi
+
+      # Just move the object if needed, then go on to compile the next one
+      if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
+	func_show_eval '$MV "$output_obj" "$lobj"' \
+	  'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+      fi
+
+      # Allow error messages only from the first compilation.
+      if test "$suppress_opt" = yes; then
+	suppress_output=' >/dev/null 2>&1'
+      fi
+    fi
+
+    # Only build a position-dependent object if we build old libraries.
+    if test "$build_old_libs" = yes; then
+      if test "$pic_mode" != yes; then
+	# Don't build PIC code
+	command="$base_compile $qsrcfile$pie_flag"
+      else
+	command="$base_compile $qsrcfile $pic_flag"
+      fi
+      if test "$compiler_c_o" = yes; then
+	func_append command " -o $obj"
+      fi
+
+      # Suppress compiler output if we already did a PIC compilation.
+      func_append command "$suppress_output"
+      func_show_eval_locale "$command" \
+        '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE'
+
+      if test "$need_locks" = warn &&
+	 test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+	$ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together.  If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+	$opt_dry_run || $RM $removelist
+	exit $EXIT_FAILURE
+      fi
+
+      # Just move the object if needed
+      if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
+	func_show_eval '$MV "$output_obj" "$obj"' \
+	  'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+      fi
+    fi
+
+    $opt_dry_run || {
+      func_write_libtool_object "$libobj" "$objdir/$objname" "$objname"
+
+      # Unlock the critical section if it was locked
+      if test "$need_locks" != no; then
+	removelist=$lockfile
+        $RM "$lockfile"
+      fi
+    }
+
+    exit $EXIT_SUCCESS
+}
+
+$opt_help || {
+  test "$opt_mode" = compile && func_mode_compile ${1+"$@"}
+}
+
+func_mode_help ()
+{
+    # We need to display help for each of the modes.
+    case $opt_mode in
+      "")
+        # Generic help is extracted from the usage comments
+        # at the start of this file.
+        func_help
+        ;;
+
+      clean)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
+
+Remove files from the build directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm').  RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, object or program, all the files associated
+with it are deleted. Otherwise, only FILE itself is deleted using RM."
+        ;;
+
+      compile)
+      $ECHO \
+"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+  -o OUTPUT-FILE    set the output file name to OUTPUT-FILE
+  -no-suppress      do not suppress compiler output for multiple passes
+  -prefer-pic       try to build PIC objects only
+  -prefer-non-pic   try to build non-PIC objects only
+  -shared           do not build a \`.o' file suitable for static linking
+  -static           only build a \`.o' file suitable for static linking
+  -Wc,FLAG          pass FLAG directly to the compiler
+
+COMPILE-COMMAND is a command to be used in creating a \`standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix \`.c' with the
+library object suffix, \`.lo'."
+        ;;
+
+      execute)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+  -dlopen FILE      add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to \`-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+        ;;
+
+      finish)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges.  Use
+the \`--dry-run' option if you just want to see what would be executed."
+        ;;
+
+      install)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command.  The first component should be
+either the \`install' or \`cp' program.
+
+The following components of INSTALL-COMMAND are treated specially:
+
+  -inst-prefix-dir PREFIX-DIR  Use PREFIX-DIR as a staging area for installation
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+        ;;
+
+      link)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+  -all-static       do not do any dynamic linking at all
+  -avoid-version    do not add a version suffix if possible
+  -bindir BINDIR    specify path to binaries directory (for systems where
+                    libraries must be found in the PATH setting at runtime)
+  -dlopen FILE      \`-dlpreopen' FILE if it cannot be dlopened at runtime
+  -dlpreopen FILE   link in FILE and add its symbols to lt_preloaded_symbols
+  -export-dynamic   allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+  -export-symbols SYMFILE
+                    try to export only the symbols listed in SYMFILE
+  -export-symbols-regex REGEX
+                    try to export only the symbols matching REGEX
+  -LLIBDIR          search LIBDIR for required installed libraries
+  -lNAME            OUTPUT-FILE requires the installed library libNAME
+  -module           build a library that can dlopened
+  -no-fast-install  disable the fast-install mode
+  -no-install       link a not-installable executable
+  -no-undefined     declare that a library does not refer to external symbols
+  -o OUTPUT-FILE    create OUTPUT-FILE from the specified objects
+  -objectlist FILE  Use a list of object files found in FILE to specify objects
+  -precious-files-regex REGEX
+                    don't remove output files matching REGEX
+  -release RELEASE  specify package release information
+  -rpath LIBDIR     the created library will eventually be installed in LIBDIR
+  -R[ ]LIBDIR       add LIBDIR to the runtime path of programs and libraries
+  -shared           only do dynamic linking of libtool libraries
+  -shrext SUFFIX    override the standard shared library file extension
+  -static           do not do any dynamic linking of uninstalled libtool libraries
+  -static-libtool-libs
+                    do not do any dynamic linking of libtool libraries
+  -version-info CURRENT[:REVISION[:AGE]]
+                    specify library version info [each variable defaults to 0]
+  -weak LIBNAME     declare that the target provides the LIBNAME interface
+  -Wc,FLAG
+  -Xcompiler FLAG   pass linker-specific FLAG directly to the compiler
+  -Wl,FLAG
+  -Xlinker FLAG     pass linker-specific FLAG directly to the linker
+  -XCClinker FLAG   pass link-specific FLAG to the compiler driver (CC)
+
+All other options (arguments beginning with \`-') are ignored.
+
+Every other argument is treated as a filename.  Files ending in \`.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
+only library objects (\`.lo' files) may be specified, and \`-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
+using \`ar' and \`ranlib', or on Windows using \`lib'.
+
+If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
+is created, otherwise an executable program is created."
+        ;;
+
+      uninstall)
+        $ECHO \
+"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm').  RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+        ;;
+
+      *)
+        func_fatal_help "invalid operation mode \`$opt_mode'"
+        ;;
+    esac
+
+    echo
+    $ECHO "Try \`$progname --help' for more information about other modes."
+}
+
+# Now that we've collected a possible --mode arg, show help if necessary
+if $opt_help; then
+  if test "$opt_help" = :; then
+    func_mode_help
+  else
+    {
+      func_help noexit
+      for opt_mode in compile link execute install finish uninstall clean; do
+	func_mode_help
+      done
+    } | sed -n '1p; 2,$s/^Usage:/  or: /p'
+    {
+      func_help noexit
+      for opt_mode in compile link execute install finish uninstall clean; do
+	echo
+	func_mode_help
+      done
+    } |
+    sed '1d
+      /^When reporting/,/^Report/{
+	H
+	d
+      }
+      $x
+      /information about other modes/d
+      /more detailed .*MODE/d
+      s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/'
+  fi
+  exit $?
+fi
+
+
+# func_mode_execute arg...
+func_mode_execute ()
+{
+    $opt_debug
+    # The first argument is the command name.
+    cmd="$nonopt"
+    test -z "$cmd" && \
+      func_fatal_help "you must specify a COMMAND"
+
+    # Handle -dlopen flags immediately.
+    for file in $opt_dlopen; do
+      test -f "$file" \
+	|| func_fatal_help "\`$file' is not a file"
+
+      dir=
+      case $file in
+      *.la)
+	func_resolve_sysroot "$file"
+	file=$func_resolve_sysroot_result
+
+	# Check to see that this really is a libtool archive.
+	func_lalib_unsafe_p "$file" \
+	  || func_fatal_help "\`$lib' is not a valid libtool archive"
+
+	# Read the libtool library.
+	dlname=
+	library_names=
+	func_source "$file"
+
+	# Skip this library if it cannot be dlopened.
+	if test -z "$dlname"; then
+	  # Warn if it was a shared library.
+	  test -n "$library_names" && \
+	    func_warning "\`$file' was not linked with \`-export-dynamic'"
+	  continue
+	fi
+
+	func_dirname "$file" "" "."
+	dir="$func_dirname_result"
+
+	if test -f "$dir/$objdir/$dlname"; then
+	  func_append dir "/$objdir"
+	else
+	  if test ! -f "$dir/$dlname"; then
+	    func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'"
+	  fi
+	fi
+	;;
+
+      *.lo)
+	# Just add the directory containing the .lo file.
+	func_dirname "$file" "" "."
+	dir="$func_dirname_result"
+	;;
+
+      *)
+	func_warning "\`-dlopen' is ignored for non-libtool libraries and objects"
+	continue
+	;;
+      esac
+
+      # Get the absolute pathname.
+      absdir=`cd "$dir" && pwd`
+      test -n "$absdir" && dir="$absdir"
+
+      # Now add the directory to shlibpath_var.
+      if eval "test -z \"\$$shlibpath_var\""; then
+	eval "$shlibpath_var=\"\$dir\""
+      else
+	eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+      fi
+    done
+
+    # This variable tells wrapper scripts just to set shlibpath_var
+    # rather than running their programs.
+    libtool_execute_magic="$magic"
+
+    # Check if any of the arguments is a wrapper script.
+    args=
+    for file
+    do
+      case $file in
+      -* | *.la | *.lo ) ;;
+      *)
+	# Do a test to see if this is really a libtool program.
+	if func_ltwrapper_script_p "$file"; then
+	  func_source "$file"
+	  # Transform arg to wrapped name.
+	  file="$progdir/$program"
+	elif func_ltwrapper_executable_p "$file"; then
+	  func_ltwrapper_scriptname "$file"
+	  func_source "$func_ltwrapper_scriptname_result"
+	  # Transform arg to wrapped name.
+	  file="$progdir/$program"
+	fi
+	;;
+      esac
+      # Quote arguments (to preserve shell metacharacters).
+      func_append_quoted args "$file"
+    done
+
+    if test "X$opt_dry_run" = Xfalse; then
+      if test -n "$shlibpath_var"; then
+	# Export the shlibpath_var.
+	eval "export $shlibpath_var"
+      fi
+
+      # Restore saved environment variables
+      for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+      do
+	eval "if test \"\${save_$lt_var+set}\" = set; then
+                $lt_var=\$save_$lt_var; export $lt_var
+	      else
+		$lt_unset $lt_var
+	      fi"
+      done
+
+      # Now prepare to actually exec the command.
+      exec_cmd="\$cmd$args"
+    else
+      # Display what would be done.
+      if test -n "$shlibpath_var"; then
+	eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\""
+	echo "export $shlibpath_var"
+      fi
+      $ECHO "$cmd$args"
+      exit $EXIT_SUCCESS
+    fi
+}
+
+test "$opt_mode" = execute && func_mode_execute ${1+"$@"}
+
+
+# func_mode_finish arg...
+func_mode_finish ()
+{
+    $opt_debug
+    libs=
+    libdirs=
+    admincmds=
+
+    for opt in "$nonopt" ${1+"$@"}
+    do
+      if test -d "$opt"; then
+	func_append libdirs " $opt"
+
+      elif test -f "$opt"; then
+	if func_lalib_unsafe_p "$opt"; then
+	  func_append libs " $opt"
+	else
+	  func_warning "\`$opt' is not a valid libtool archive"
+	fi
+
+      else
+	func_fatal_error "invalid argument \`$opt'"
+      fi
+    done
+
+    if test -n "$libs"; then
+      if test -n "$lt_sysroot"; then
+        sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"`
+        sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;"
+      else
+        sysroot_cmd=
+      fi
+
+      # Remove sysroot references
+      if $opt_dry_run; then
+        for lib in $libs; do
+          echo "removing references to $lt_sysroot and \`=' prefixes from $lib"
+        done
+      else
+        tmpdir=`func_mktempdir`
+        for lib in $libs; do
+	  sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \
+	    > $tmpdir/tmp-la
+	  mv -f $tmpdir/tmp-la $lib
+	done
+        ${RM}r "$tmpdir"
+      fi
+    fi
+
+    if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+      for libdir in $libdirs; do
+	if test -n "$finish_cmds"; then
+	  # Do each command in the finish commands.
+	  func_execute_cmds "$finish_cmds" 'admincmds="$admincmds
+'"$cmd"'"'
+	fi
+	if test -n "$finish_eval"; then
+	  # Do the single finish_eval.
+	  eval cmds=\"$finish_eval\"
+	  $opt_dry_run || eval "$cmds" || func_append admincmds "
+       $cmds"
+	fi
+      done
+    fi
+
+    # Exit here if they wanted silent mode.
+    $opt_silent && exit $EXIT_SUCCESS
+
+    if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+      echo "----------------------------------------------------------------------"
+      echo "Libraries have been installed in:"
+      for libdir in $libdirs; do
+	$ECHO "   $libdir"
+      done
+      echo
+      echo "If you ever happen to want to link against installed libraries"
+      echo "in a given directory, LIBDIR, you must either use libtool, and"
+      echo "specify the full pathname of the library, or use the \`-LLIBDIR'"
+      echo "flag during linking and do at least one of the following:"
+      if test -n "$shlibpath_var"; then
+	echo "   - add LIBDIR to the \`$shlibpath_var' environment variable"
+	echo "     during execution"
+      fi
+      if test -n "$runpath_var"; then
+	echo "   - add LIBDIR to the \`$runpath_var' environment variable"
+	echo "     during linking"
+      fi
+      if test -n "$hardcode_libdir_flag_spec"; then
+	libdir=LIBDIR
+	eval flag=\"$hardcode_libdir_flag_spec\"
+
+	$ECHO "   - use the \`$flag' linker flag"
+      fi
+      if test -n "$admincmds"; then
+	$ECHO "   - have your system administrator run these commands:$admincmds"
+      fi
+      if test -f /etc/ld.so.conf; then
+	echo "   - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
+      fi
+      echo
+
+      echo "See any operating system documentation about shared libraries for"
+      case $host in
+	solaris2.[6789]|solaris2.1[0-9])
+	  echo "more information, such as the ld(1), crle(1) and ld.so(8) manual"
+	  echo "pages."
+	  ;;
+	*)
+	  echo "more information, such as the ld(1) and ld.so(8) manual pages."
+	  ;;
+      esac
+      echo "----------------------------------------------------------------------"
+    fi
+    exit $EXIT_SUCCESS
+}
+
+test "$opt_mode" = finish && func_mode_finish ${1+"$@"}
+
+
+# func_mode_install arg...
+func_mode_install ()
+{
+    $opt_debug
+    # There may be an optional sh(1) argument at the beginning of
+    # install_prog (especially on Windows NT).
+    if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
+       # Allow the use of GNU shtool's install command.
+       case $nonopt in *shtool*) :;; *) false;; esac; then
+      # Aesthetically quote it.
+      func_quote_for_eval "$nonopt"
+      install_prog="$func_quote_for_eval_result "
+      arg=$1
+      shift
+    else
+      install_prog=
+      arg=$nonopt
+    fi
+
+    # The real first argument should be the name of the installation program.
+    # Aesthetically quote it.
+    func_quote_for_eval "$arg"
+    func_append install_prog "$func_quote_for_eval_result"
+    install_shared_prog=$install_prog
+    case " $install_prog " in
+      *[\\\ /]cp\ *) install_cp=: ;;
+      *) install_cp=false ;;
+    esac
+
+    # We need to accept at least all the BSD install flags.
+    dest=
+    files=
+    opts=
+    prev=
+    install_type=
+    isdir=no
+    stripme=
+    no_mode=:
+    for arg
+    do
+      arg2=
+      if test -n "$dest"; then
+	func_append files " $dest"
+	dest=$arg
+	continue
+      fi
+
+      case $arg in
+      -d) isdir=yes ;;
+      -f)
+	if $install_cp; then :; else
+	  prev=$arg
+	fi
+	;;
+      -g | -m | -o)
+	prev=$arg
+	;;
+      -s)
+	stripme=" -s"
+	continue
+	;;
+      -*)
+	;;
+      *)
+	# If the previous option needed an argument, then skip it.
+	if test -n "$prev"; then
+	  if test "x$prev" = x-m && test -n "$install_override_mode"; then
+	    arg2=$install_override_mode
+	    no_mode=false
+	  fi
+	  prev=
+	else
+	  dest=$arg
+	  continue
+	fi
+	;;
+      esac
+
+      # Aesthetically quote the argument.
+      func_quote_for_eval "$arg"
+      func_append install_prog " $func_quote_for_eval_result"
+      if test -n "$arg2"; then
+	func_quote_for_eval "$arg2"
+      fi
+      func_append install_shared_prog " $func_quote_for_eval_result"
+    done
+
+    test -z "$install_prog" && \
+      func_fatal_help "you must specify an install program"
+
+    test -n "$prev" && \
+      func_fatal_help "the \`$prev' option requires an argument"
+
+    if test -n "$install_override_mode" && $no_mode; then
+      if $install_cp; then :; else
+	func_quote_for_eval "$install_override_mode"
+	func_append install_shared_prog " -m $func_quote_for_eval_result"
+      fi
+    fi
+
+    if test -z "$files"; then
+      if test -z "$dest"; then
+	func_fatal_help "no file or destination specified"
+      else
+	func_fatal_help "you must specify a destination"
+      fi
+    fi
+
+    # Strip any trailing slash from the destination.
+    func_stripname '' '/' "$dest"
+    dest=$func_stripname_result
+
+    # Check to see that the destination is a directory.
+    test -d "$dest" && isdir=yes
+    if test "$isdir" = yes; then
+      destdir="$dest"
+      destname=
+    else
+      func_dirname_and_basename "$dest" "" "."
+      destdir="$func_dirname_result"
+      destname="$func_basename_result"
+
+      # Not a directory, so check to see that there is only one file specified.
+      set dummy $files; shift
+      test "$#" -gt 1 && \
+	func_fatal_help "\`$dest' is not a directory"
+    fi
+    case $destdir in
+    [\\/]* | [A-Za-z]:[\\/]*) ;;
+    *)
+      for file in $files; do
+	case $file in
+	*.lo) ;;
+	*)
+	  func_fatal_help "\`$destdir' must be an absolute directory name"
+	  ;;
+	esac
+      done
+      ;;
+    esac
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic="$magic"
+
+    staticlibs=
+    future_libdirs=
+    current_libdirs=
+    for file in $files; do
+
+      # Do each installation.
+      case $file in
+      *.$libext)
+	# Do the static libraries later.
+	func_append staticlibs " $file"
+	;;
+
+      *.la)
+	func_resolve_sysroot "$file"
+	file=$func_resolve_sysroot_result
+
+	# Check to see that this really is a libtool archive.
+	func_lalib_unsafe_p "$file" \
+	  || func_fatal_help "\`$file' is not a valid libtool archive"
+
+	library_names=
+	old_library=
+	relink_command=
+	func_source "$file"
+
+	# Add the libdir to current_libdirs if it is the destination.
+	if test "X$destdir" = "X$libdir"; then
+	  case "$current_libdirs " in
+	  *" $libdir "*) ;;
+	  *) func_append current_libdirs " $libdir" ;;
+	  esac
+	else
+	  # Note the libdir as a future libdir.
+	  case "$future_libdirs " in
+	  *" $libdir "*) ;;
+	  *) func_append future_libdirs " $libdir" ;;
+	  esac
+	fi
+
+	func_dirname "$file" "/" ""
+	dir="$func_dirname_result"
+	func_append dir "$objdir"
+
+	if test -n "$relink_command"; then
+	  # Determine the prefix the user has applied to our future dir.
+	  inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"`
+
+	  # Don't allow the user to place us outside of our expected
+	  # location b/c this prevents finding dependent libraries that
+	  # are installed to the same prefix.
+	  # At present, this check doesn't affect windows .dll's that
+	  # are installed into $libdir/../bin (currently, that works fine)
+	  # but it's something to keep an eye on.
+	  test "$inst_prefix_dir" = "$destdir" && \
+	    func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir"
+
+	  if test -n "$inst_prefix_dir"; then
+	    # Stick the inst_prefix_dir data into the link command.
+	    relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
+	  else
+	    relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
+	  fi
+
+	  func_warning "relinking \`$file'"
+	  func_show_eval "$relink_command" \
+	    'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"'
+	fi
+
+	# See the names of the shared library.
+	set dummy $library_names; shift
+	if test -n "$1"; then
+	  realname="$1"
+	  shift
+
+	  srcname="$realname"
+	  test -n "$relink_command" && srcname="$realname"T
+
+	  # Install the shared library and build the symlinks.
+	  func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \
+	      'exit $?'
+	  tstripme="$stripme"
+	  case $host_os in
+	  cygwin* | mingw* | pw32* | cegcc*)
+	    case $realname in
+	    *.dll.a)
+	      tstripme=""
+	      ;;
+	    esac
+	    ;;
+	  esac
+	  if test -n "$tstripme" && test -n "$striplib"; then
+	    func_show_eval "$striplib $destdir/$realname" 'exit $?'
+	  fi
+
+	  if test "$#" -gt 0; then
+	    # Delete the old symlinks, and create new ones.
+	    # Try `ln -sf' first, because the `ln' binary might depend on
+	    # the symlink we replace!  Solaris /bin/ln does not understand -f,
+	    # so we also need to try rm && ln -s.
+	    for linkname
+	    do
+	      test "$linkname" != "$realname" \
+		&& func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })"
+	    done
+	  fi
+
+	  # Do each command in the postinstall commands.
+	  lib="$destdir/$realname"
+	  func_execute_cmds "$postinstall_cmds" 'exit $?'
+	fi
+
+	# Install the pseudo-library for information purposes.
+	func_basename "$file"
+	name="$func_basename_result"
+	instname="$dir/$name"i
+	func_show_eval "$install_prog $instname $destdir/$name" 'exit $?'
+
+	# Maybe install the static library, too.
+	test -n "$old_library" && func_append staticlibs " $dir/$old_library"
+	;;
+
+      *.lo)
+	# Install (i.e. copy) a libtool object.
+
+	# Figure out destination file name, if it wasn't already specified.
+	if test -n "$destname"; then
+	  destfile="$destdir/$destname"
+	else
+	  func_basename "$file"
+	  destfile="$func_basename_result"
+	  destfile="$destdir/$destfile"
+	fi
+
+	# Deduce the name of the destination old-style object file.
+	case $destfile in
+	*.lo)
+	  func_lo2o "$destfile"
+	  staticdest=$func_lo2o_result
+	  ;;
+	*.$objext)
+	  staticdest="$destfile"
+	  destfile=
+	  ;;
+	*)
+	  func_fatal_help "cannot copy a libtool object to \`$destfile'"
+	  ;;
+	esac
+
+	# Install the libtool object if requested.
+	test -n "$destfile" && \
+	  func_show_eval "$install_prog $file $destfile" 'exit $?'
+
+	# Install the old object if enabled.
+	if test "$build_old_libs" = yes; then
+	  # Deduce the name of the old-style object file.
+	  func_lo2o "$file"
+	  staticobj=$func_lo2o_result
+	  func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?'
+	fi
+	exit $EXIT_SUCCESS
+	;;
+
+      *)
+	# Figure out destination file name, if it wasn't already specified.
+	if test -n "$destname"; then
+	  destfile="$destdir/$destname"
+	else
+	  func_basename "$file"
+	  destfile="$func_basename_result"
+	  destfile="$destdir/$destfile"
+	fi
+
+	# If the file is missing, and there is a .exe on the end, strip it
+	# because it is most likely a libtool script we actually want to
+	# install
+	stripped_ext=""
+	case $file in
+	  *.exe)
+	    if test ! -f "$file"; then
+	      func_stripname '' '.exe' "$file"
+	      file=$func_stripname_result
+	      stripped_ext=".exe"
+	    fi
+	    ;;
+	esac
+
+	# Do a test to see if this is really a libtool program.
+	case $host in
+	*cygwin* | *mingw*)
+	    if func_ltwrapper_executable_p "$file"; then
+	      func_ltwrapper_scriptname "$file"
+	      wrapper=$func_ltwrapper_scriptname_result
+	    else
+	      func_stripname '' '.exe' "$file"
+	      wrapper=$func_stripname_result
+	    fi
+	    ;;
+	*)
+	    wrapper=$file
+	    ;;
+	esac
+	if func_ltwrapper_script_p "$wrapper"; then
+	  notinst_deplibs=
+	  relink_command=
+
+	  func_source "$wrapper"
+
+	  # Check the variables that should have been set.
+	  test -z "$generated_by_libtool_version" && \
+	    func_fatal_error "invalid libtool wrapper script \`$wrapper'"
+
+	  finalize=yes
+	  for lib in $notinst_deplibs; do
+	    # Check to see that each library is installed.
+	    libdir=
+	    if test -f "$lib"; then
+	      func_source "$lib"
+	    fi
+	    libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test
+	    if test -n "$libdir" && test ! -f "$libfile"; then
+	      func_warning "\`$lib' has not been installed in \`$libdir'"
+	      finalize=no
+	    fi
+	  done
+
+	  relink_command=
+	  func_source "$wrapper"
+
+	  outputname=
+	  if test "$fast_install" = no && test -n "$relink_command"; then
+	    $opt_dry_run || {
+	      if test "$finalize" = yes; then
+	        tmpdir=`func_mktempdir`
+		func_basename "$file$stripped_ext"
+		file="$func_basename_result"
+	        outputname="$tmpdir/$file"
+	        # Replace the output file specification.
+	        relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'`
+
+	        $opt_silent || {
+	          func_quote_for_expand "$relink_command"
+		  eval "func_echo $func_quote_for_expand_result"
+	        }
+	        if eval "$relink_command"; then :
+	          else
+		  func_error "error: relink \`$file' with the above command before installing it"
+		  $opt_dry_run || ${RM}r "$tmpdir"
+		  continue
+	        fi
+	        file="$outputname"
+	      else
+	        func_warning "cannot relink \`$file'"
+	      fi
+	    }
+	  else
+	    # Install the binary that we compiled earlier.
+	    file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"`
+	  fi
+	fi
+
+	# remove .exe since cygwin /usr/bin/install will append another
+	# one anyway
+	case $install_prog,$host in
+	*/usr/bin/install*,*cygwin*)
+	  case $file:$destfile in
+	  *.exe:*.exe)
+	    # this is ok
+	    ;;
+	  *.exe:*)
+	    destfile=$destfile.exe
+	    ;;
+	  *:*.exe)
+	    func_stripname '' '.exe' "$destfile"
+	    destfile=$func_stripname_result
+	    ;;
+	  esac
+	  ;;
+	esac
+	func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?'
+	$opt_dry_run || if test -n "$outputname"; then
+	  ${RM}r "$tmpdir"
+	fi
+	;;
+      esac
+    done
+
+    for file in $staticlibs; do
+      func_basename "$file"
+      name="$func_basename_result"
+
+      # Set up the ranlib parameters.
+      oldlib="$destdir/$name"
+      func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
+      tool_oldlib=$func_to_tool_file_result
+
+      func_show_eval "$install_prog \$file \$oldlib" 'exit $?'
+
+      if test -n "$stripme" && test -n "$old_striplib"; then
+	func_show_eval "$old_striplib $tool_oldlib" 'exit $?'
+      fi
+
+      # Do each command in the postinstall commands.
+      func_execute_cmds "$old_postinstall_cmds" 'exit $?'
+    done
+
+    test -n "$future_libdirs" && \
+      func_warning "remember to run \`$progname --finish$future_libdirs'"
+
+    if test -n "$current_libdirs"; then
+      # Maybe just do a dry run.
+      $opt_dry_run && current_libdirs=" -n$current_libdirs"
+      exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs'
+    else
+      exit $EXIT_SUCCESS
+    fi
+}
+
+test "$opt_mode" = install && func_mode_install ${1+"$@"}
+
+
+# func_generate_dlsyms outputname originator pic_p
+# Extract symbols from dlprefiles and create ${outputname}S.o with
+# a dlpreopen symbol table.
+func_generate_dlsyms ()
+{
+    $opt_debug
+    my_outputname="$1"
+    my_originator="$2"
+    my_pic_p="${3-no}"
+    my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'`
+    my_dlsyms=
+
+    if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+      if test -n "$NM" && test -n "$global_symbol_pipe"; then
+	my_dlsyms="${my_outputname}S.c"
+      else
+	func_error "not configured to extract global symbols from dlpreopened files"
+      fi
+    fi
+
+    if test -n "$my_dlsyms"; then
+      case $my_dlsyms in
+      "") ;;
+      *.c)
+	# Discover the nlist of each of the dlfiles.
+	nlist="$output_objdir/${my_outputname}.nm"
+
+	func_show_eval "$RM $nlist ${nlist}S ${nlist}T"
+
+	# Parse the name list into a source file.
+	func_verbose "creating $output_objdir/$my_dlsyms"
+
+	$opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\
+/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */
+/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4))
+#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
+#endif
+
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
+/* DATA imports from DLLs on WIN32 con't be const, because runtime
+   relocations are performed -- see ld's documentation on pseudo-relocs.  */
+# define LT_DLSYM_CONST
+#elif defined(__osf__)
+/* This system does not cope well with relocations in const data.  */
+# define LT_DLSYM_CONST
+#else
+# define LT_DLSYM_CONST const
+#endif
+
+/* External symbol declarations for the compiler. */\
+"
+
+	if test "$dlself" = yes; then
+	  func_verbose "generating symbol list for \`$output'"
+
+	  $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist"
+
+	  # Add our own program objects to the symbol list.
+	  progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+	  for progfile in $progfiles; do
+	    func_to_tool_file "$progfile" func_convert_file_msys_to_w32
+	    func_verbose "extracting global C symbols from \`$func_to_tool_file_result'"
+	    $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'"
+	  done
+
+	  if test -n "$exclude_expsyms"; then
+	    $opt_dry_run || {
+	      eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
+	      eval '$MV "$nlist"T "$nlist"'
+	    }
+	  fi
+
+	  if test -n "$export_symbols_regex"; then
+	    $opt_dry_run || {
+	      eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
+	      eval '$MV "$nlist"T "$nlist"'
+	    }
+	  fi
+
+	  # Prepare the list of exported symbols
+	  if test -z "$export_symbols"; then
+	    export_symbols="$output_objdir/$outputname.exp"
+	    $opt_dry_run || {
+	      $RM $export_symbols
+	      eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+	      case $host in
+	      *cygwin* | *mingw* | *cegcc* )
+                eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+                eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"'
+	        ;;
+	      esac
+	    }
+	  else
+	    $opt_dry_run || {
+	      eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
+	      eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
+	      eval '$MV "$nlist"T "$nlist"'
+	      case $host in
+	        *cygwin* | *mingw* | *cegcc* )
+	          eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+	          eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
+	          ;;
+	      esac
+	    }
+	  fi
+	fi
+
+	for dlprefile in $dlprefiles; do
+	  func_verbose "extracting global C symbols from \`$dlprefile'"
+	  func_basename "$dlprefile"
+	  name="$func_basename_result"
+          case $host in
+	    *cygwin* | *mingw* | *cegcc* )
+	      # if an import library, we need to obtain dlname
+	      if func_win32_import_lib_p "$dlprefile"; then
+	        func_tr_sh "$dlprefile"
+	        eval "curr_lafile=\$libfile_$func_tr_sh_result"
+	        dlprefile_dlbasename=""
+	        if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then
+	          # Use subshell, to avoid clobbering current variable values
+	          dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"`
+	          if test -n "$dlprefile_dlname" ; then
+	            func_basename "$dlprefile_dlname"
+	            dlprefile_dlbasename="$func_basename_result"
+	          else
+	            # no lafile. user explicitly requested -dlpreopen <import library>.
+	            $sharedlib_from_linklib_cmd "$dlprefile"
+	            dlprefile_dlbasename=$sharedlib_from_linklib_result
+	          fi
+	        fi
+	        $opt_dry_run || {
+	          if test -n "$dlprefile_dlbasename" ; then
+	            eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"'
+	          else
+	            func_warning "Could not compute DLL name from $name"
+	            eval '$ECHO ": $name " >> "$nlist"'
+	          fi
+	          func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+	          eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe |
+	            $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'"
+	        }
+	      else # not an import lib
+	        $opt_dry_run || {
+	          eval '$ECHO ": $name " >> "$nlist"'
+	          func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+	          eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+	        }
+	      fi
+	    ;;
+	    *)
+	      $opt_dry_run || {
+	        eval '$ECHO ": $name " >> "$nlist"'
+	        func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+	        eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+	      }
+	    ;;
+          esac
+	done
+
+	$opt_dry_run || {
+	  # Make sure we have at least an empty file.
+	  test -f "$nlist" || : > "$nlist"
+
+	  if test -n "$exclude_expsyms"; then
+	    $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+	    $MV "$nlist"T "$nlist"
+	  fi
+
+	  # Try sorting and uniquifying the output.
+	  if $GREP -v "^: " < "$nlist" |
+	      if sort -k 3 </dev/null >/dev/null 2>&1; then
+		sort -k 3
+	      else
+		sort +2
+	      fi |
+	      uniq > "$nlist"S; then
+	    :
+	  else
+	    $GREP -v "^: " < "$nlist" > "$nlist"S
+	  fi
+
+	  if test -f "$nlist"S; then
+	    eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"'
+	  else
+	    echo '/* NONE */' >> "$output_objdir/$my_dlsyms"
+	  fi
+
+	  echo >> "$output_objdir/$my_dlsyms" "\
+
+/* The mapping between symbol names and symbols.  */
+typedef struct {
+  const char *name;
+  void *address;
+} lt_dlsymlist;
+extern LT_DLSYM_CONST lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[];
+LT_DLSYM_CONST lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[] =
+{\
+  { \"$my_originator\", (void *) 0 },"
+
+	  case $need_lib_prefix in
+	  no)
+	    eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms"
+	    ;;
+	  *)
+	    eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms"
+	    ;;
+	  esac
+	  echo >> "$output_objdir/$my_dlsyms" "\
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt_${my_prefix}_LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+	} # !$opt_dry_run
+
+	pic_flag_for_symtable=
+	case "$compile_command " in
+	*" -static "*) ;;
+	*)
+	  case $host in
+	  # compiling the symbol table file with pic_flag works around
+	  # a FreeBSD bug that causes programs to crash when -lm is
+	  # linked before any other PIC object.  But we must not use
+	  # pic_flag when linking with -static.  The problem exists in
+	  # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+	  *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
+	    pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;;
+	  *-*-hpux*)
+	    pic_flag_for_symtable=" $pic_flag"  ;;
+	  *)
+	    if test "X$my_pic_p" != Xno; then
+	      pic_flag_for_symtable=" $pic_flag"
+	    fi
+	    ;;
+	  esac
+	  ;;
+	esac
+	symtab_cflags=
+	for arg in $LTCFLAGS; do
+	  case $arg in
+	  -pie | -fpie | -fPIE) ;;
+	  *) func_append symtab_cflags " $arg" ;;
+	  esac
+	done
+
+	# Now compile the dynamic symbol file.
+	func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?'
+
+	# Clean up the generated files.
+	func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"'
+
+	# Transform the symbol file into the correct name.
+	symfileobj="$output_objdir/${my_outputname}S.$objext"
+	case $host in
+	*cygwin* | *mingw* | *cegcc* )
+	  if test -f "$output_objdir/$my_outputname.def"; then
+	    compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+	    finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+	  else
+	    compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	    finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	  fi
+	  ;;
+	*)
+	  compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	  finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+	  ;;
+	esac
+	;;
+      *)
+	func_fatal_error "unknown suffix for \`$my_dlsyms'"
+	;;
+      esac
+    else
+      # We keep going just in case the user didn't refer to
+      # lt_preloaded_symbols.  The linker will fail if global_symbol_pipe
+      # really was required.
+
+      # Nullify the symbol file.
+      compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"`
+      finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"`
+    fi
+}
+
+# func_win32_libid arg
+# return the library type of file 'arg'
+#
+# Need a lot of goo to handle *both* DLLs and import libs
+# Has to be a shell function in order to 'eat' the argument
+# that is supplied when $file_magic_command is called.
+# Despite the name, also deal with 64 bit binaries.
+func_win32_libid ()
+{
+  $opt_debug
+  win32_libid_type="unknown"
+  win32_fileres=`file -L $1 2>/dev/null`
+  case $win32_fileres in
+  *ar\ archive\ import\ library*) # definitely import
+    win32_libid_type="x86 archive import"
+    ;;
+  *ar\ archive*) # could be an import, or static
+    # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD.
+    if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null |
+       $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then
+      func_to_tool_file "$1" func_convert_file_msys_to_w32
+      win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" |
+	$SED -n -e '
+	    1,100{
+		/ I /{
+		    s,.*,import,
+		    p
+		    q
+		}
+	    }'`
+      case $win32_nmres in
+      import*)  win32_libid_type="x86 archive import";;
+      *)        win32_libid_type="x86 archive static";;
+      esac
+    fi
+    ;;
+  *DLL*)
+    win32_libid_type="x86 DLL"
+    ;;
+  *executable*) # but shell scripts are "executable" too...
+    case $win32_fileres in
+    *MS\ Windows\ PE\ Intel*)
+      win32_libid_type="x86 DLL"
+      ;;
+    esac
+    ;;
+  esac
+  $ECHO "$win32_libid_type"
+}
+
+# func_cygming_dll_for_implib ARG
+#
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+# Invoked by eval'ing the libtool variable
+#    $sharedlib_from_linklib_cmd
+# Result is available in the variable
+#    $sharedlib_from_linklib_result
+func_cygming_dll_for_implib ()
+{
+  $opt_debug
+  sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"`
+}
+
+# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs
+#
+# The is the core of a fallback implementation of a
+# platform-specific function to extract the name of the
+# DLL associated with the specified import library LIBNAME.
+#
+# SECTION_NAME is either .idata$6 or .idata$7, depending
+# on the platform and compiler that created the implib.
+#
+# Echos the name of the DLL associated with the
+# specified import library.
+func_cygming_dll_for_implib_fallback_core ()
+{
+  $opt_debug
+  match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"`
+  $OBJDUMP -s --section "$1" "$2" 2>/dev/null |
+    $SED '/^Contents of section '"$match_literal"':/{
+      # Place marker at beginning of archive member dllname section
+      s/.*/====MARK====/
+      p
+      d
+    }
+    # These lines can sometimes be longer than 43 characters, but
+    # are always uninteresting
+    /:[	 ]*file format pe[i]\{,1\}-/d
+    /^In archive [^:]*:/d
+    # Ensure marker is printed
+    /^====MARK====/p
+    # Remove all lines with less than 43 characters
+    /^.\{43\}/!d
+    # From remaining lines, remove first 43 characters
+    s/^.\{43\}//' |
+    $SED -n '
+      # Join marker and all lines until next marker into a single line
+      /^====MARK====/ b para
+      H
+      $ b para
+      b
+      :para
+      x
+      s/\n//g
+      # Remove the marker
+      s/^====MARK====//
+      # Remove trailing dots and whitespace
+      s/[\. \t]*$//
+      # Print
+      /./p' |
+    # we now have a list, one entry per line, of the stringified
+    # contents of the appropriate section of all members of the
+    # archive which possess that section. Heuristic: eliminate
+    # all those which have a first or second character that is
+    # a '.' (that is, objdump's representation of an unprintable
+    # character.) This should work for all archives with less than
+    # 0x302f exports -- but will fail for DLLs whose name actually
+    # begins with a literal '.' or a single character followed by
+    # a '.'.
+    #
+    # Of those that remain, print the first one.
+    $SED -e '/^\./d;/^.\./d;q'
+}
+
+# func_cygming_gnu_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is a GNU/binutils-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_gnu_implib_p ()
+{
+  $opt_debug
+  func_to_tool_file "$1" func_convert_file_msys_to_w32
+  func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'`
+  test -n "$func_cygming_gnu_implib_tmp"
+}
+
+# func_cygming_ms_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is an MS-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_ms_implib_p ()
+{
+  $opt_debug
+  func_to_tool_file "$1" func_convert_file_msys_to_w32
+  func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'`
+  test -n "$func_cygming_ms_implib_tmp"
+}
+
+# func_cygming_dll_for_implib_fallback ARG
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+#
+# This fallback implementation is for use when $DLLTOOL
+# does not support the --identify-strict option.
+# Invoked by eval'ing the libtool variable
+#    $sharedlib_from_linklib_cmd
+# Result is available in the variable
+#    $sharedlib_from_linklib_result
+func_cygming_dll_for_implib_fallback ()
+{
+  $opt_debug
+  if func_cygming_gnu_implib_p "$1" ; then
+    # binutils import library
+    sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"`
+  elif func_cygming_ms_implib_p "$1" ; then
+    # ms-generated import library
+    sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"`
+  else
+    # unknown
+    sharedlib_from_linklib_result=""
+  fi
+}
+
+
+# func_extract_an_archive dir oldlib
+func_extract_an_archive ()
+{
+    $opt_debug
+    f_ex_an_ar_dir="$1"; shift
+    f_ex_an_ar_oldlib="$1"
+    if test "$lock_old_archive_extraction" = yes; then
+      lockfile=$f_ex_an_ar_oldlib.lock
+      until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+	func_echo "Waiting for $lockfile to be removed"
+	sleep 2
+      done
+    fi
+    func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \
+		   'stat=$?; rm -f "$lockfile"; exit $stat'
+    if test "$lock_old_archive_extraction" = yes; then
+      $opt_dry_run || rm -f "$lockfile"
+    fi
+    if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
+     :
+    else
+      func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib"
+    fi
+}
+
+
+# func_extract_archives gentop oldlib ...
+func_extract_archives ()
+{
+    $opt_debug
+    my_gentop="$1"; shift
+    my_oldlibs=${1+"$@"}
+    my_oldobjs=""
+    my_xlib=""
+    my_xabs=""
+    my_xdir=""
+
+    for my_xlib in $my_oldlibs; do
+      # Extract the objects.
+      case $my_xlib in
+	[\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;;
+	*) my_xabs=`pwd`"/$my_xlib" ;;
+      esac
+      func_basename "$my_xlib"
+      my_xlib="$func_basename_result"
+      my_xlib_u=$my_xlib
+      while :; do
+        case " $extracted_archives " in
+	*" $my_xlib_u "*)
+	  func_arith $extracted_serial + 1
+	  extracted_serial=$func_arith_result
+	  my_xlib_u=lt$extracted_serial-$my_xlib ;;
+	*) break ;;
+	esac
+      done
+      extracted_archives="$extracted_archives $my_xlib_u"
+      my_xdir="$my_gentop/$my_xlib_u"
+
+      func_mkdir_p "$my_xdir"
+
+      case $host in
+      *-darwin*)
+	func_verbose "Extracting $my_xabs"
+	# Do not bother doing anything if just a dry run
+	$opt_dry_run || {
+	  darwin_orig_dir=`pwd`
+	  cd $my_xdir || exit $?
+	  darwin_archive=$my_xabs
+	  darwin_curdir=`pwd`
+	  darwin_base_archive=`basename "$darwin_archive"`
+	  darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true`
+	  if test -n "$darwin_arches"; then
+	    darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'`
+	    darwin_arch=
+	    func_verbose "$darwin_base_archive has multiple architectures $darwin_arches"
+	    for darwin_arch in  $darwin_arches ; do
+	      func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+	      $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}"
+	      cd "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+	      func_extract_an_archive "`pwd`" "${darwin_base_archive}"
+	      cd "$darwin_curdir"
+	      $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}"
+	    done # $darwin_arches
+            ## Okay now we've a bunch of thin objects, gotta fatten them up :)
+	    darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u`
+	    darwin_file=
+	    darwin_files=
+	    for darwin_file in $darwin_filelist; do
+	      darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP`
+	      $LIPO -create -output "$darwin_file" $darwin_files
+	    done # $darwin_filelist
+	    $RM -rf unfat-$$
+	    cd "$darwin_orig_dir"
+	  else
+	    cd $darwin_orig_dir
+	    func_extract_an_archive "$my_xdir" "$my_xabs"
+	  fi # $darwin_arches
+	} # !$opt_dry_run
+	;;
+      *)
+        func_extract_an_archive "$my_xdir" "$my_xabs"
+	;;
+      esac
+      my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP`
+    done
+
+    func_extract_archives_result="$my_oldobjs"
+}
+
+
+# func_emit_wrapper [arg=no]
+#
+# Emit a libtool wrapper script on stdout.
+# Don't directly open a file because we may want to
+# incorporate the script contents within a cygwin/mingw
+# wrapper executable.  Must ONLY be called from within
+# func_mode_link because it depends on a number of variables
+# set therein.
+#
+# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR
+# variable will take.  If 'yes', then the emitted script
+# will assume that the directory in which it is stored is
+# the $objdir directory.  This is a cygwin/mingw-specific
+# behavior.
+func_emit_wrapper ()
+{
+	func_emit_wrapper_arg1=${1-no}
+
+	$ECHO "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting.  It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='$sed_quote_subst'
+
+# Be Bourne compatible
+if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then
+  emulate sh
+  NULLCMD=:
+  # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+  # install mode needs the following variables:
+  generated_by_libtool_version='$macro_version'
+  notinst_deplibs='$notinst_deplibs'
+else
+  # When we are sourced in execute mode, \$file and \$ECHO are already set.
+  if test \"\$libtool_execute_magic\" != \"$magic\"; then
+    file=\"\$0\""
+
+    qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"`
+    $ECHO "\
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+    ECHO=\"$qECHO\"
+  fi
+
+# Very basic option parsing. These options are (a) specific to
+# the libtool wrapper, (b) are identical between the wrapper
+# /script/ and the wrapper /executable/ which is used only on
+# windows platforms, and (c) all begin with the string "--lt-"
+# (application programs are unlikely to have options which match
+# this pattern).
+#
+# There are only two supported options: --lt-debug and
+# --lt-dump-script. There is, deliberately, no --lt-help.
+#
+# The first argument to this parsing function should be the
+# script's $0 value, followed by "$@".
+lt_option_debug=
+func_parse_lt_options ()
+{
+  lt_script_arg0=\$0
+  shift
+  for lt_opt
+  do
+    case \"\$lt_opt\" in
+    --lt-debug) lt_option_debug=1 ;;
+    --lt-dump-script)
+        lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\`
+        test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=.
+        lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\`
+        cat \"\$lt_dump_D/\$lt_dump_F\"
+        exit 0
+      ;;
+    --lt-*)
+        \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2
+        exit 1
+      ;;
+    esac
+  done
+
+  # Print the debug banner immediately:
+  if test -n \"\$lt_option_debug\"; then
+    echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2
+  fi
+}
+
+# Used when --lt-debug. Prints its arguments to stdout
+# (redirection is the responsibility of the caller)
+func_lt_dump_args ()
+{
+  lt_dump_args_N=1;
+  for lt_arg
+  do
+    \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\"
+    lt_dump_args_N=\`expr \$lt_dump_args_N + 1\`
+  done
+}
+
+# Core function for launching the target application
+func_exec_program_core ()
+{
+"
+  case $host in
+  # Backslashes separate directories on plain windows
+  *-*-mingw | *-*-os2* | *-cegcc*)
+    $ECHO "\
+      if test -n \"\$lt_option_debug\"; then
+        \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2
+        func_lt_dump_args \${1+\"\$@\"} 1>&2
+      fi
+      exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
+"
+    ;;
+
+  *)
+    $ECHO "\
+      if test -n \"\$lt_option_debug\"; then
+        \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2
+        func_lt_dump_args \${1+\"\$@\"} 1>&2
+      fi
+      exec \"\$progdir/\$program\" \${1+\"\$@\"}
+"
+    ;;
+  esac
+  $ECHO "\
+      \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2
+      exit 1
+}
+
+# A function to encapsulate launching the target application
+# Strips options in the --lt-* namespace from \$@ and
+# launches target application with the remaining arguments.
+func_exec_program ()
+{
+  case \" \$* \" in
+  *\\ --lt-*)
+    for lt_wr_arg
+    do
+      case \$lt_wr_arg in
+      --lt-*) ;;
+      *) set x \"\$@\" \"\$lt_wr_arg\"; shift;;
+      esac
+      shift
+    done ;;
+  esac
+  func_exec_program_core \${1+\"\$@\"}
+}
+
+  # Parse options
+  func_parse_lt_options \"\$0\" \${1+\"\$@\"}
+
+  # Find the directory that this script lives in.
+  thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\`
+  test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+  # Follow symbolic links until we get to the real thisdir.
+  file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\`
+  while test -n \"\$file\"; do
+    destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\`
+
+    # If there was a directory component, then change thisdir.
+    if test \"x\$destdir\" != \"x\$file\"; then
+      case \"\$destdir\" in
+      [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
+      *) thisdir=\"\$thisdir/\$destdir\" ;;
+      esac
+    fi
+
+    file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\`
+    file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\`
+  done
+
+  # Usually 'no', except on cygwin/mingw when embedded into
+  # the cwrapper.
+  WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1
+  if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then
+    # special case for '.'
+    if test \"\$thisdir\" = \".\"; then
+      thisdir=\`pwd\`
+    fi
+    # remove .libs from thisdir
+    case \"\$thisdir\" in
+    *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;;
+    $objdir )   thisdir=. ;;
+    esac
+  fi
+
+  # Try to get the absolute directory name.
+  absdir=\`cd \"\$thisdir\" && pwd\`
+  test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+	if test "$fast_install" = yes; then
+	  $ECHO "\
+  program=lt-'$outputname'$exeext
+  progdir=\"\$thisdir/$objdir\"
+
+  if test ! -f \"\$progdir/\$program\" ||
+     { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\
+       test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+    file=\"\$\$-\$program\"
+
+    if test ! -d \"\$progdir\"; then
+      $MKDIR \"\$progdir\"
+    else
+      $RM \"\$progdir/\$file\"
+    fi"
+
+	  $ECHO "\
+
+    # relink executable if necessary
+    if test -n \"\$relink_command\"; then
+      if relink_command_output=\`eval \$relink_command 2>&1\`; then :
+      else
+	$ECHO \"\$relink_command_output\" >&2
+	$RM \"\$progdir/\$file\"
+	exit 1
+      fi
+    fi
+
+    $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+    { $RM \"\$progdir/\$program\";
+      $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+    $RM \"\$progdir/\$file\"
+  fi"
+	else
+	  $ECHO "\
+  program='$outputname'
+  progdir=\"\$thisdir/$objdir\"
+"
+	fi
+
+	$ECHO "\
+
+  if test -f \"\$progdir/\$program\"; then"
+
+	# fixup the dll searchpath if we need to.
+	#
+	# Fix the DLL searchpath if we need to.  Do this before prepending
+	# to shlibpath, because on Windows, both are PATH and uninstalled
+	# libraries must come first.
+	if test -n "$dllsearchpath"; then
+	  $ECHO "\
+    # Add the dll search path components to the executable PATH
+    PATH=$dllsearchpath:\$PATH
+"
+	fi
+
+	# Export our shlibpath_var if we have one.
+	if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+	  $ECHO "\
+    # Add our own library path to $shlibpath_var
+    $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+    # Some systems cannot cope with colon-terminated $shlibpath_var
+    # The second colon is a workaround for a bug in BeOS R4 sed
+    $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\`
+
+    export $shlibpath_var
+"
+	fi
+
+	$ECHO "\
+    if test \"\$libtool_execute_magic\" != \"$magic\"; then
+      # Run the actual program with our arguments.
+      func_exec_program \${1+\"\$@\"}
+    fi
+  else
+    # The program doesn't exist.
+    \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2
+    \$ECHO \"This script is just a wrapper for \$program.\" 1>&2
+    \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2
+    exit 1
+  fi
+fi\
+"
+}
+
+
+# func_emit_cwrapperexe_src
+# emit the source code for a wrapper executable on stdout
+# Must ONLY be called from within func_mode_link because
+# it depends on a number of variable set therein.
+func_emit_cwrapperexe_src ()
+{
+	cat <<EOF
+
+/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
+   Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+
+   The $output program cannot be directly executed until all the libtool
+   libraries that it depends on are installed.
+
+   This wrapper executable should never be moved out of the build directory.
+   If it is, it will not operate correctly.
+*/
+EOF
+	    cat <<"EOF"
+#ifdef _MSC_VER
+# define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef _MSC_VER
+# include <direct.h>
+# include <process.h>
+# include <io.h>
+#else
+# include <unistd.h>
+# include <stdint.h>
+# ifdef __CYGWIN__
+#  include <io.h>
+# endif
+#endif
+#include <malloc.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+/* declarations of non-ANSI functions */
+#if defined(__MINGW32__)
+# ifdef __STRICT_ANSI__
+int _putenv (const char *);
+# endif
+#elif defined(__CYGWIN__)
+# ifdef __STRICT_ANSI__
+char *realpath (const char *, char *);
+int putenv (char *);
+int setenv (const char *, const char *, int);
+# endif
+/* #elif defined (other platforms) ... */
+#endif
+
+/* portability defines, excluding path handling macros */
+#if defined(_MSC_VER)
+# define setmode _setmode
+# define stat    _stat
+# define chmod   _chmod
+# define getcwd  _getcwd
+# define putenv  _putenv
+# define S_IXUSR _S_IEXEC
+# ifndef _INTPTR_T_DEFINED
+#  define _INTPTR_T_DEFINED
+#  define intptr_t int
+# endif
+#elif defined(__MINGW32__)
+# define setmode _setmode
+# define stat    _stat
+# define chmod   _chmod
+# define getcwd  _getcwd
+# define putenv  _putenv
+#elif defined(__CYGWIN__)
+# define HAVE_SETENV
+# define FOPEN_WB "wb"
+/* #elif defined (other platforms) ... */
+#endif
+
+#if defined(PATH_MAX)
+# define LT_PATHMAX PATH_MAX
+#elif defined(MAXPATHLEN)
+# define LT_PATHMAX MAXPATHLEN
+#else
+# define LT_PATHMAX 1024
+#endif
+
+#ifndef S_IXOTH
+# define S_IXOTH 0
+#endif
+#ifndef S_IXGRP
+# define S_IXGRP 0
+#endif
+
+/* path handling portability macros */
+#ifndef DIR_SEPARATOR
+# define DIR_SEPARATOR '/'
+# define PATH_SEPARATOR ':'
+#endif
+
+#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \
+  defined (__OS2__)
+# define HAVE_DOS_BASED_FILE_SYSTEM
+# define FOPEN_WB "wb"
+# ifndef DIR_SEPARATOR_2
+#  define DIR_SEPARATOR_2 '\\'
+# endif
+# ifndef PATH_SEPARATOR_2
+#  define PATH_SEPARATOR_2 ';'
+# endif
+#endif
+
+#ifndef DIR_SEPARATOR_2
+# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+#else /* DIR_SEPARATOR_2 */
+# define IS_DIR_SEPARATOR(ch) \
+	(((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+#endif /* DIR_SEPARATOR_2 */
+
+#ifndef PATH_SEPARATOR_2
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR)
+#else /* PATH_SEPARATOR_2 */
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2)
+#endif /* PATH_SEPARATOR_2 */
+
+#ifndef FOPEN_WB
+# define FOPEN_WB "w"
+#endif
+#ifndef _O_BINARY
+# define _O_BINARY 0
+#endif
+
+#define XMALLOC(type, num)      ((type *) xmalloc ((num) * sizeof(type)))
+#define XFREE(stale) do { \
+  if (stale) { free ((void *) stale); stale = 0; } \
+} while (0)
+
+#if defined(LT_DEBUGWRAPPER)
+static int lt_debug = 1;
+#else
+static int lt_debug = 0;
+#endif
+
+const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */
+
+void *xmalloc (size_t num);
+char *xstrdup (const char *string);
+const char *base_name (const char *name);
+char *find_executable (const char *wrapper);
+char *chase_symlinks (const char *pathspec);
+int make_executable (const char *path);
+int check_executable (const char *path);
+char *strendzap (char *str, const char *pat);
+void lt_debugprintf (const char *file, int line, const char *fmt, ...);
+void lt_fatal (const char *file, int line, const char *message, ...);
+static const char *nonnull (const char *s);
+static const char *nonempty (const char *s);
+void lt_setenv (const char *name, const char *value);
+char *lt_extend_str (const char *orig_value, const char *add, int to_end);
+void lt_update_exe_path (const char *name, const char *value);
+void lt_update_lib_path (const char *name, const char *value);
+char **prepare_spawn (char **argv);
+void lt_dump_script (FILE *f);
+EOF
+
+	    cat <<EOF
+volatile const char * MAGIC_EXE = "$magic_exe";
+const char * LIB_PATH_VARNAME = "$shlibpath_var";
+EOF
+
+	    if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+              func_to_host_path "$temp_rpath"
+	      cat <<EOF
+const char * LIB_PATH_VALUE   = "$func_to_host_path_result";
+EOF
+	    else
+	      cat <<"EOF"
+const char * LIB_PATH_VALUE   = "";
+EOF
+	    fi
+
+	    if test -n "$dllsearchpath"; then
+              func_to_host_path "$dllsearchpath:"
+	      cat <<EOF
+const char * EXE_PATH_VARNAME = "PATH";
+const char * EXE_PATH_VALUE   = "$func_to_host_path_result";
+EOF
+	    else
+	      cat <<"EOF"
+const char * EXE_PATH_VARNAME = "";
+const char * EXE_PATH_VALUE   = "";
+EOF
+	    fi
+
+	    if test "$fast_install" = yes; then
+	      cat <<EOF
+const char * TARGET_PROGRAM_NAME = "lt-$outputname"; /* hopefully, no .exe */
+EOF
+	    else
+	      cat <<EOF
+const char * TARGET_PROGRAM_NAME = "$outputname"; /* hopefully, no .exe */
+EOF
+	    fi
+
+
+	    cat <<"EOF"
+
+#define LTWRAPPER_OPTION_PREFIX         "--lt-"
+
+static const char *ltwrapper_option_prefix = LTWRAPPER_OPTION_PREFIX;
+static const char *dumpscript_opt       = LTWRAPPER_OPTION_PREFIX "dump-script";
+static const char *debug_opt            = LTWRAPPER_OPTION_PREFIX "debug";
+
+int
+main (int argc, char *argv[])
+{
+  char **newargz;
+  int  newargc;
+  char *tmp_pathspec;
+  char *actual_cwrapper_path;
+  char *actual_cwrapper_name;
+  char *target_name;
+  char *lt_argv_zero;
+  intptr_t rval = 127;
+
+  int i;
+
+  program_name = (char *) xstrdup (base_name (argv[0]));
+  newargz = XMALLOC (char *, argc + 1);
+
+  /* very simple arg parsing; don't want to rely on getopt
+   * also, copy all non cwrapper options to newargz, except
+   * argz[0], which is handled differently
+   */
+  newargc=0;
+  for (i = 1; i < argc; i++)
+    {
+      if (strcmp (argv[i], dumpscript_opt) == 0)
+	{
+EOF
+	    case "$host" in
+	      *mingw* | *cygwin* )
+		# make stdout use "unix" line endings
+		echo "          setmode(1,_O_BINARY);"
+		;;
+	      esac
+
+	    cat <<"EOF"
+	  lt_dump_script (stdout);
+	  return 0;
+	}
+      if (strcmp (argv[i], debug_opt) == 0)
+	{
+          lt_debug = 1;
+          continue;
+	}
+      if (strcmp (argv[i], ltwrapper_option_prefix) == 0)
+        {
+          /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX
+             namespace, but it is not one of the ones we know about and
+             have already dealt with, above (inluding dump-script), then
+             report an error. Otherwise, targets might begin to believe
+             they are allowed to use options in the LTWRAPPER_OPTION_PREFIX
+             namespace. The first time any user complains about this, we'll
+             need to make LTWRAPPER_OPTION_PREFIX a configure-time option
+             or a configure.ac-settable value.
+           */
+          lt_fatal (__FILE__, __LINE__,
+		    "unrecognized %s option: '%s'",
+                    ltwrapper_option_prefix, argv[i]);
+        }
+      /* otherwise ... */
+      newargz[++newargc] = xstrdup (argv[i]);
+    }
+  newargz[++newargc] = NULL;
+
+EOF
+	    cat <<EOF
+  /* The GNU banner must be the first non-error debug message */
+  lt_debugprintf (__FILE__, __LINE__, "libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\n");
+EOF
+	    cat <<"EOF"
+  lt_debugprintf (__FILE__, __LINE__, "(main) argv[0]: %s\n", argv[0]);
+  lt_debugprintf (__FILE__, __LINE__, "(main) program_name: %s\n", program_name);
+
+  tmp_pathspec = find_executable (argv[0]);
+  if (tmp_pathspec == NULL)
+    lt_fatal (__FILE__, __LINE__, "couldn't find %s", argv[0]);
+  lt_debugprintf (__FILE__, __LINE__,
+                  "(main) found exe (before symlink chase) at: %s\n",
+		  tmp_pathspec);
+
+  actual_cwrapper_path = chase_symlinks (tmp_pathspec);
+  lt_debugprintf (__FILE__, __LINE__,
+                  "(main) found exe (after symlink chase) at: %s\n",
+		  actual_cwrapper_path);
+  XFREE (tmp_pathspec);
+
+  actual_cwrapper_name = xstrdup (base_name (actual_cwrapper_path));
+  strendzap (actual_cwrapper_path, actual_cwrapper_name);
+
+  /* wrapper name transforms */
+  strendzap (actual_cwrapper_name, ".exe");
+  tmp_pathspec = lt_extend_str (actual_cwrapper_name, ".exe", 1);
+  XFREE (actual_cwrapper_name);
+  actual_cwrapper_name = tmp_pathspec;
+  tmp_pathspec = 0;
+
+  /* target_name transforms -- use actual target program name; might have lt- prefix */
+  target_name = xstrdup (base_name (TARGET_PROGRAM_NAME));
+  strendzap (target_name, ".exe");
+  tmp_pathspec = lt_extend_str (target_name, ".exe", 1);
+  XFREE (target_name);
+  target_name = tmp_pathspec;
+  tmp_pathspec = 0;
+
+  lt_debugprintf (__FILE__, __LINE__,
+		  "(main) libtool target name: %s\n",
+		  target_name);
+EOF
+
+	    cat <<EOF
+  newargz[0] =
+    XMALLOC (char, (strlen (actual_cwrapper_path) +
+		    strlen ("$objdir") + 1 + strlen (actual_cwrapper_name) + 1));
+  strcpy (newargz[0], actual_cwrapper_path);
+  strcat (newargz[0], "$objdir");
+  strcat (newargz[0], "/");
+EOF
+
+	    cat <<"EOF"
+  /* stop here, and copy so we don't have to do this twice */
+  tmp_pathspec = xstrdup (newargz[0]);
+
+  /* do NOT want the lt- prefix here, so use actual_cwrapper_name */
+  strcat (newargz[0], actual_cwrapper_name);
+
+  /* DO want the lt- prefix here if it exists, so use target_name */
+  lt_argv_zero = lt_extend_str (tmp_pathspec, target_name, 1);
+  XFREE (tmp_pathspec);
+  tmp_pathspec = NULL;
+EOF
+
+	    case $host_os in
+	      mingw*)
+	    cat <<"EOF"
+  {
+    char* p;
+    while ((p = strchr (newargz[0], '\\')) != NULL)
+      {
+	*p = '/';
+      }
+    while ((p = strchr (lt_argv_zero, '\\')) != NULL)
+      {
+	*p = '/';
+      }
+  }
+EOF
+	    ;;
+	    esac
+
+	    cat <<"EOF"
+  XFREE (target_name);
+  XFREE (actual_cwrapper_path);
+  XFREE (actual_cwrapper_name);
+
+  lt_setenv ("BIN_SH", "xpg4"); /* for Tru64 */
+  lt_setenv ("DUALCASE", "1");  /* for MSK sh */
+  /* Update the DLL searchpath.  EXE_PATH_VALUE ($dllsearchpath) must
+     be prepended before (that is, appear after) LIB_PATH_VALUE ($temp_rpath)
+     because on Windows, both *_VARNAMEs are PATH but uninstalled
+     libraries must come first. */
+  lt_update_exe_path (EXE_PATH_VARNAME, EXE_PATH_VALUE);
+  lt_update_lib_path (LIB_PATH_VARNAME, LIB_PATH_VALUE);
+
+  lt_debugprintf (__FILE__, __LINE__, "(main) lt_argv_zero: %s\n",
+		  nonnull (lt_argv_zero));
+  for (i = 0; i < newargc; i++)
+    {
+      lt_debugprintf (__FILE__, __LINE__, "(main) newargz[%d]: %s\n",
+		      i, nonnull (newargz[i]));
+    }
+
+EOF
+
+	    case $host_os in
+	      mingw*)
+		cat <<"EOF"
+  /* execv doesn't actually work on mingw as expected on unix */
+  newargz = prepare_spawn (newargz);
+  rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz);
+  if (rval == -1)
+    {
+      /* failed to start process */
+      lt_debugprintf (__FILE__, __LINE__,
+		      "(main) failed to launch target \"%s\": %s\n",
+		      lt_argv_zero, nonnull (strerror (errno)));
+      return 127;
+    }
+  return rval;
+EOF
+		;;
+	      *)
+		cat <<"EOF"
+  execv (lt_argv_zero, newargz);
+  return rval; /* =127, but avoids unused variable warning */
+EOF
+		;;
+	    esac
+
+	    cat <<"EOF"
+}
+
+void *
+xmalloc (size_t num)
+{
+  void *p = (void *) malloc (num);
+  if (!p)
+    lt_fatal (__FILE__, __LINE__, "memory exhausted");
+
+  return p;
+}
+
+char *
+xstrdup (const char *string)
+{
+  return string ? strcpy ((char *) xmalloc (strlen (string) + 1),
+			  string) : NULL;
+}
+
+const char *
+base_name (const char *name)
+{
+  const char *base;
+
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+  /* Skip over the disk name in MSDOS pathnames. */
+  if (isalpha ((unsigned char) name[0]) && name[1] == ':')
+    name += 2;
+#endif
+
+  for (base = name; *name; name++)
+    if (IS_DIR_SEPARATOR (*name))
+      base = name + 1;
+  return base;
+}
+
+int
+check_executable (const char *path)
+{
+  struct stat st;
+
+  lt_debugprintf (__FILE__, __LINE__, "(check_executable): %s\n",
+                  nonempty (path));
+  if ((!path) || (!*path))
+    return 0;
+
+  if ((stat (path, &st) >= 0)
+      && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
+    return 1;
+  else
+    return 0;
+}
+
+int
+make_executable (const char *path)
+{
+  int rval = 0;
+  struct stat st;
+
+  lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n",
+                  nonempty (path));
+  if ((!path) || (!*path))
+    return 0;
+
+  if (stat (path, &st) >= 0)
+    {
+      rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR);
+    }
+  return rval;
+}
+
+/* Searches for the full path of the wrapper.  Returns
+   newly allocated full path name if found, NULL otherwise
+   Does not chase symlinks, even on platforms that support them.
+*/
+char *
+find_executable (const char *wrapper)
+{
+  int has_slash = 0;
+  const char *p;
+  const char *p_next;
+  /* static buffer for getcwd */
+  char tmp[LT_PATHMAX + 1];
+  int tmp_len;
+  char *concat_name;
+
+  lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n",
+                  nonempty (wrapper));
+
+  if ((wrapper == NULL) || (*wrapper == '\0'))
+    return NULL;
+
+  /* Absolute path? */
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+  if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':')
+    {
+      concat_name = xstrdup (wrapper);
+      if (check_executable (concat_name))
+	return concat_name;
+      XFREE (concat_name);
+    }
+  else
+    {
+#endif
+      if (IS_DIR_SEPARATOR (wrapper[0]))
+	{
+	  concat_name = xstrdup (wrapper);
+	  if (check_executable (concat_name))
+	    return concat_name;
+	  XFREE (concat_name);
+	}
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+    }
+#endif
+
+  for (p = wrapper; *p; p++)
+    if (*p == '/')
+      {
+	has_slash = 1;
+	break;
+      }
+  if (!has_slash)
+    {
+      /* no slashes; search PATH */
+      const char *path = getenv ("PATH");
+      if (path != NULL)
+	{
+	  for (p = path; *p; p = p_next)
+	    {
+	      const char *q;
+	      size_t p_len;
+	      for (q = p; *q; q++)
+		if (IS_PATH_SEPARATOR (*q))
+		  break;
+	      p_len = q - p;
+	      p_next = (*q == '\0' ? q : q + 1);
+	      if (p_len == 0)
+		{
+		  /* empty path: current directory */
+		  if (getcwd (tmp, LT_PATHMAX) == NULL)
+		    lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+                              nonnull (strerror (errno)));
+		  tmp_len = strlen (tmp);
+		  concat_name =
+		    XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+		  memcpy (concat_name, tmp, tmp_len);
+		  concat_name[tmp_len] = '/';
+		  strcpy (concat_name + tmp_len + 1, wrapper);
+		}
+	      else
+		{
+		  concat_name =
+		    XMALLOC (char, p_len + 1 + strlen (wrapper) + 1);
+		  memcpy (concat_name, p, p_len);
+		  concat_name[p_len] = '/';
+		  strcpy (concat_name + p_len + 1, wrapper);
+		}
+	      if (check_executable (concat_name))
+		return concat_name;
+	      XFREE (concat_name);
+	    }
+	}
+      /* not found in PATH; assume curdir */
+    }
+  /* Relative path | not found in path: prepend cwd */
+  if (getcwd (tmp, LT_PATHMAX) == NULL)
+    lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+              nonnull (strerror (errno)));
+  tmp_len = strlen (tmp);
+  concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+  memcpy (concat_name, tmp, tmp_len);
+  concat_name[tmp_len] = '/';
+  strcpy (concat_name + tmp_len + 1, wrapper);
+
+  if (check_executable (concat_name))
+    return concat_name;
+  XFREE (concat_name);
+  return NULL;
+}
+
+char *
+chase_symlinks (const char *pathspec)
+{
+#ifndef S_ISLNK
+  return xstrdup (pathspec);
+#else
+  char buf[LT_PATHMAX];
+  struct stat s;
+  char *tmp_pathspec = xstrdup (pathspec);
+  char *p;
+  int has_symlinks = 0;
+  while (strlen (tmp_pathspec) && !has_symlinks)
+    {
+      lt_debugprintf (__FILE__, __LINE__,
+		      "checking path component for symlinks: %s\n",
+		      tmp_pathspec);
+      if (lstat (tmp_pathspec, &s) == 0)
+	{
+	  if (S_ISLNK (s.st_mode) != 0)
+	    {
+	      has_symlinks = 1;
+	      break;
+	    }
+
+	  /* search backwards for last DIR_SEPARATOR */
+	  p = tmp_pathspec + strlen (tmp_pathspec) - 1;
+	  while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+	    p--;
+	  if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+	    {
+	      /* no more DIR_SEPARATORS left */
+	      break;
+	    }
+	  *p = '\0';
+	}
+      else
+	{
+	  lt_fatal (__FILE__, __LINE__,
+		    "error accessing file \"%s\": %s",
+		    tmp_pathspec, nonnull (strerror (errno)));
+	}
+    }
+  XFREE (tmp_pathspec);
+
+  if (!has_symlinks)
+    {
+      return xstrdup (pathspec);
+    }
+
+  tmp_pathspec = realpath (pathspec, buf);
+  if (tmp_pathspec == 0)
+    {
+      lt_fatal (__FILE__, __LINE__,
+		"could not follow symlinks for %s", pathspec);
+    }
+  return xstrdup (tmp_pathspec);
+#endif
+}
+
+char *
+strendzap (char *str, const char *pat)
+{
+  size_t len, patlen;
+
+  assert (str != NULL);
+  assert (pat != NULL);
+
+  len = strlen (str);
+  patlen = strlen (pat);
+
+  if (patlen <= len)
+    {
+      str += len - patlen;
+      if (strcmp (str, pat) == 0)
+	*str = '\0';
+    }
+  return str;
+}
+
+void
+lt_debugprintf (const char *file, int line, const char *fmt, ...)
+{
+  va_list args;
+  if (lt_debug)
+    {
+      (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line);
+      va_start (args, fmt);
+      (void) vfprintf (stderr, fmt, args);
+      va_end (args);
+    }
+}
+
+static void
+lt_error_core (int exit_status, const char *file,
+	       int line, const char *mode,
+	       const char *message, va_list ap)
+{
+  fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode);
+  vfprintf (stderr, message, ap);
+  fprintf (stderr, ".\n");
+
+  if (exit_status >= 0)
+    exit (exit_status);
+}
+
+void
+lt_fatal (const char *file, int line, const char *message, ...)
+{
+  va_list ap;
+  va_start (ap, message);
+  lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap);
+  va_end (ap);
+}
+
+static const char *
+nonnull (const char *s)
+{
+  return s ? s : "(null)";
+}
+
+static const char *
+nonempty (const char *s)
+{
+  return (s && !*s) ? "(empty)" : nonnull (s);
+}
+
+void
+lt_setenv (const char *name, const char *value)
+{
+  lt_debugprintf (__FILE__, __LINE__,
+		  "(lt_setenv) setting '%s' to '%s'\n",
+                  nonnull (name), nonnull (value));
+  {
+#ifdef HAVE_SETENV
+    /* always make a copy, for consistency with !HAVE_SETENV */
+    char *str = xstrdup (value);
+    setenv (name, str, 1);
+#else
+    int len = strlen (name) + 1 + strlen (value) + 1;
+    char *str = XMALLOC (char, len);
+    sprintf (str, "%s=%s", name, value);
+    if (putenv (str) != EXIT_SUCCESS)
+      {
+        XFREE (str);
+      }
+#endif
+  }
+}
+
+char *
+lt_extend_str (const char *orig_value, const char *add, int to_end)
+{
+  char *new_value;
+  if (orig_value && *orig_value)
+    {
+      int orig_value_len = strlen (orig_value);
+      int add_len = strlen (add);
+      new_value = XMALLOC (char, add_len + orig_value_len + 1);
+      if (to_end)
+        {
+          strcpy (new_value, orig_value);
+          strcpy (new_value + orig_value_len, add);
+        }
+      else
+        {
+          strcpy (new_value, add);
+          strcpy (new_value + add_len, orig_value);
+        }
+    }
+  else
+    {
+      new_value = xstrdup (add);
+    }
+  return new_value;
+}
+
+void
+lt_update_exe_path (const char *name, const char *value)
+{
+  lt_debugprintf (__FILE__, __LINE__,
+		  "(lt_update_exe_path) modifying '%s' by prepending '%s'\n",
+                  nonnull (name), nonnull (value));
+
+  if (name && *name && value && *value)
+    {
+      char *new_value = lt_extend_str (getenv (name), value, 0);
+      /* some systems can't cope with a ':'-terminated path #' */
+      int len = strlen (new_value);
+      while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1]))
+        {
+          new_value[len-1] = '\0';
+        }
+      lt_setenv (name, new_value);
+      XFREE (new_value);
+    }
+}
+
+void
+lt_update_lib_path (const char *name, const char *value)
+{
+  lt_debugprintf (__FILE__, __LINE__,
+		  "(lt_update_lib_path) modifying '%s' by prepending '%s'\n",
+                  nonnull (name), nonnull (value));
+
+  if (name && *name && value && *value)
+    {
+      char *new_value = lt_extend_str (getenv (name), value, 0);
+      lt_setenv (name, new_value);
+      XFREE (new_value);
+    }
+}
+
+EOF
+	    case $host_os in
+	      mingw*)
+		cat <<"EOF"
+
+/* Prepares an argument vector before calling spawn().
+   Note that spawn() does not by itself call the command interpreter
+     (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") :
+      ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+         GetVersionEx(&v);
+         v.dwPlatformId == VER_PLATFORM_WIN32_NT;
+      }) ? "cmd.exe" : "command.com").
+   Instead it simply concatenates the arguments, separated by ' ', and calls
+   CreateProcess().  We must quote the arguments since Win32 CreateProcess()
+   interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
+   special way:
+   - Space and tab are interpreted as delimiters. They are not treated as
+     delimiters if they are surrounded by double quotes: "...".
+   - Unescaped double quotes are removed from the input. Their only effect is
+     that within double quotes, space and tab are treated like normal
+     characters.
+   - Backslashes not followed by double quotes are not special.
+   - But 2*n+1 backslashes followed by a double quote become
+     n backslashes followed by a double quote (n >= 0):
+       \" -> "
+       \\\" -> \"
+       \\\\\" -> \\"
+ */
+#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+char **
+prepare_spawn (char **argv)
+{
+  size_t argc;
+  char **new_argv;
+  size_t i;
+
+  /* Count number of arguments.  */
+  for (argc = 0; argv[argc] != NULL; argc++)
+    ;
+
+  /* Allocate new argument vector.  */
+  new_argv = XMALLOC (char *, argc + 1);
+
+  /* Put quoted arguments into the new argument vector.  */
+  for (i = 0; i < argc; i++)
+    {
+      const char *string = argv[i];
+
+      if (string[0] == '\0')
+	new_argv[i] = xstrdup ("\"\"");
+      else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
+	{
+	  int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
+	  size_t length;
+	  unsigned int backslashes;
+	  const char *s;
+	  char *quoted_string;
+	  char *p;
+
+	  length = 0;
+	  backslashes = 0;
+	  if (quote_around)
+	    length++;
+	  for (s = string; *s != '\0'; s++)
+	    {
+	      char c = *s;
+	      if (c == '"')
+		length += backslashes + 1;
+	      length++;
+	      if (c == '\\')
+		backslashes++;
+	      else
+		backslashes = 0;
+	    }
+	  if (quote_around)
+	    length += backslashes + 1;
+
+	  quoted_string = XMALLOC (char, length + 1);
+
+	  p = quoted_string;
+	  backslashes = 0;
+	  if (quote_around)
+	    *p++ = '"';
+	  for (s = string; *s != '\0'; s++)
+	    {
+	      char c = *s;
+	      if (c == '"')
+		{
+		  unsigned int j;
+		  for (j = backslashes + 1; j > 0; j--)
+		    *p++ = '\\';
+		}
+	      *p++ = c;
+	      if (c == '\\')
+		backslashes++;
+	      else
+		backslashes = 0;
+	    }
+	  if (quote_around)
+	    {
+	      unsigned int j;
+	      for (j = backslashes; j > 0; j--)
+		*p++ = '\\';
+	      *p++ = '"';
+	    }
+	  *p = '\0';
+
+	  new_argv[i] = quoted_string;
+	}
+      else
+	new_argv[i] = (char *) string;
+    }
+  new_argv[argc] = NULL;
+
+  return new_argv;
+}
+EOF
+		;;
+	    esac
+
+            cat <<"EOF"
+void lt_dump_script (FILE* f)
+{
+EOF
+	    func_emit_wrapper yes |
+	      $SED -n -e '
+s/^\(.\{79\}\)\(..*\)/\1\
+\2/
+h
+s/\([\\"]\)/\\\1/g
+s/$/\\n/
+s/\([^\n]*\).*/  fputs ("\1", f);/p
+g
+D'
+            cat <<"EOF"
+}
+EOF
+}
+# end: func_emit_cwrapperexe_src
+
+# func_win32_import_lib_p ARG
+# True if ARG is an import lib, as indicated by $file_magic_cmd
+func_win32_import_lib_p ()
+{
+    $opt_debug
+    case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in
+    *import*) : ;;
+    *) false ;;
+    esac
+}
+
+# func_mode_link arg...
+func_mode_link ()
+{
+    $opt_debug
+    case $host in
+    *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+      # It is impossible to link a dll without this setting, and
+      # we shouldn't force the makefile maintainer to figure out
+      # which system we are compiling for in order to pass an extra
+      # flag for every libtool invocation.
+      # allow_undefined=no
+
+      # FIXME: Unfortunately, there are problems with the above when trying
+      # to make a dll which has undefined symbols, in which case not
+      # even a static library is built.  For now, we need to specify
+      # -no-undefined on the libtool link line when we can be certain
+      # that all symbols are satisfied, otherwise we get a static library.
+      allow_undefined=yes
+      ;;
+    *)
+      allow_undefined=yes
+      ;;
+    esac
+    libtool_args=$nonopt
+    base_compile="$nonopt $@"
+    compile_command=$nonopt
+    finalize_command=$nonopt
+
+    compile_rpath=
+    finalize_rpath=
+    compile_shlibpath=
+    finalize_shlibpath=
+    convenience=
+    old_convenience=
+    deplibs=
+    old_deplibs=
+    compiler_flags=
+    linker_flags=
+    dllsearchpath=
+    lib_search_path=`pwd`
+    inst_prefix_dir=
+    new_inherited_linker_flags=
+
+    avoid_version=no
+    bindir=
+    dlfiles=
+    dlprefiles=
+    dlself=no
+    export_dynamic=no
+    export_symbols=
+    export_symbols_regex=
+    generated=
+    libobjs=
+    ltlibs=
+    module=no
+    no_install=no
+    objs=
+    non_pic_objects=
+    precious_files_regex=
+    prefer_static_libs=no
+    preload=no
+    prev=
+    prevarg=
+    release=
+    rpath=
+    xrpath=
+    perm_rpath=
+    temp_rpath=
+    thread_safe=no
+    vinfo=
+    vinfo_number=no
+    weak_libs=
+    single_module="${wl}-single_module"
+    func_infer_tag $base_compile
+
+    # We need to know -static, to get the right output filenames.
+    for arg
+    do
+      case $arg in
+      -shared)
+	test "$build_libtool_libs" != yes && \
+	  func_fatal_configuration "can not build a shared library"
+	build_old_libs=no
+	break
+	;;
+      -all-static | -static | -static-libtool-libs)
+	case $arg in
+	-all-static)
+	  if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
+	    func_warning "complete static linking is impossible in this configuration"
+	  fi
+	  if test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=yes
+	  ;;
+	-static)
+	  if test -z "$pic_flag" && test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=built
+	  ;;
+	-static-libtool-libs)
+	  if test -z "$pic_flag" && test -n "$link_static_flag"; then
+	    dlopen_self=$dlopen_self_static
+	  fi
+	  prefer_static_libs=yes
+	  ;;
+	esac
+	build_libtool_libs=no
+	build_old_libs=yes
+	break
+	;;
+      esac
+    done
+
+    # See if our shared archives depend on static archives.
+    test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+    # Go through the arguments, transforming them on the way.
+    while test "$#" -gt 0; do
+      arg="$1"
+      shift
+      func_quote_for_eval "$arg"
+      qarg=$func_quote_for_eval_unquoted_result
+      func_append libtool_args " $func_quote_for_eval_result"
+
+      # If the previous option needs an argument, assign it.
+      if test -n "$prev"; then
+	case $prev in
+	output)
+	  func_append compile_command " @OUTPUT@"
+	  func_append finalize_command " @OUTPUT@"
+	  ;;
+	esac
+
+	case $prev in
+	bindir)
+	  bindir="$arg"
+	  prev=
+	  continue
+	  ;;
+	dlfiles|dlprefiles)
+	  if test "$preload" = no; then
+	    # Add the symbol object into the linking commands.
+	    func_append compile_command " @SYMFILE@"
+	    func_append finalize_command " @SYMFILE@"
+	    preload=yes
+	  fi
+	  case $arg in
+	  *.la | *.lo) ;;  # We handle these cases below.
+	  force)
+	    if test "$dlself" = no; then
+	      dlself=needless
+	      export_dynamic=yes
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  self)
+	    if test "$prev" = dlprefiles; then
+	      dlself=yes
+	    elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
+	      dlself=yes
+	    else
+	      dlself=needless
+	      export_dynamic=yes
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  *)
+	    if test "$prev" = dlfiles; then
+	      func_append dlfiles " $arg"
+	    else
+	      func_append dlprefiles " $arg"
+	    fi
+	    prev=
+	    continue
+	    ;;
+	  esac
+	  ;;
+	expsyms)
+	  export_symbols="$arg"
+	  test -f "$arg" \
+	    || func_fatal_error "symbol file \`$arg' does not exist"
+	  prev=
+	  continue
+	  ;;
+	expsyms_regex)
+	  export_symbols_regex="$arg"
+	  prev=
+	  continue
+	  ;;
+	framework)
+	  case $host in
+	    *-*-darwin*)
+	      case "$deplibs " in
+		*" $qarg.ltframework "*) ;;
+		*) func_append deplibs " $qarg.ltframework" # this is fixed later
+		   ;;
+	      esac
+	      ;;
+	  esac
+	  prev=
+	  continue
+	  ;;
+	inst_prefix)
+	  inst_prefix_dir="$arg"
+	  prev=
+	  continue
+	  ;;
+	objectlist)
+	  if test -f "$arg"; then
+	    save_arg=$arg
+	    moreargs=
+	    for fil in `cat "$save_arg"`
+	    do
+#	      func_append moreargs " $fil"
+	      arg=$fil
+	      # A libtool-controlled object.
+
+	      # Check to see that this really is a libtool object.
+	      if func_lalib_unsafe_p "$arg"; then
+		pic_object=
+		non_pic_object=
+
+		# Read the .lo file
+		func_source "$arg"
+
+		if test -z "$pic_object" ||
+		   test -z "$non_pic_object" ||
+		   test "$pic_object" = none &&
+		   test "$non_pic_object" = none; then
+		  func_fatal_error "cannot find name of object for \`$arg'"
+		fi
+
+		# Extract subdirectory from the argument.
+		func_dirname "$arg" "/" ""
+		xdir="$func_dirname_result"
+
+		if test "$pic_object" != none; then
+		  # Prepend the subdirectory the object is found in.
+		  pic_object="$xdir$pic_object"
+
+		  if test "$prev" = dlfiles; then
+		    if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+		      func_append dlfiles " $pic_object"
+		      prev=
+		      continue
+		    else
+		      # If libtool objects are unsupported, then we need to preload.
+		      prev=dlprefiles
+		    fi
+		  fi
+
+		  # CHECK ME:  I think I busted this.  -Ossama
+		  if test "$prev" = dlprefiles; then
+		    # Preload the old-style object.
+		    func_append dlprefiles " $pic_object"
+		    prev=
+		  fi
+
+		  # A PIC object.
+		  func_append libobjs " $pic_object"
+		  arg="$pic_object"
+		fi
+
+		# Non-PIC object.
+		if test "$non_pic_object" != none; then
+		  # Prepend the subdirectory the object is found in.
+		  non_pic_object="$xdir$non_pic_object"
+
+		  # A standard non-PIC object
+		  func_append non_pic_objects " $non_pic_object"
+		  if test -z "$pic_object" || test "$pic_object" = none ; then
+		    arg="$non_pic_object"
+		  fi
+		else
+		  # If the PIC object exists, use it instead.
+		  # $xdir was prepended to $pic_object above.
+		  non_pic_object="$pic_object"
+		  func_append non_pic_objects " $non_pic_object"
+		fi
+	      else
+		# Only an error if not doing a dry-run.
+		if $opt_dry_run; then
+		  # Extract subdirectory from the argument.
+		  func_dirname "$arg" "/" ""
+		  xdir="$func_dirname_result"
+
+		  func_lo2o "$arg"
+		  pic_object=$xdir$objdir/$func_lo2o_result
+		  non_pic_object=$xdir$func_lo2o_result
+		  func_append libobjs " $pic_object"
+		  func_append non_pic_objects " $non_pic_object"
+	        else
+		  func_fatal_error "\`$arg' is not a valid libtool object"
+		fi
+	      fi
+	    done
+	  else
+	    func_fatal_error "link input file \`$arg' does not exist"
+	  fi
+	  arg=$save_arg
+	  prev=
+	  continue
+	  ;;
+	precious_regex)
+	  precious_files_regex="$arg"
+	  prev=
+	  continue
+	  ;;
+	release)
+	  release="-$arg"
+	  prev=
+	  continue
+	  ;;
+	rpath | xrpath)
+	  # We need an absolute path.
+	  case $arg in
+	  [\\/]* | [A-Za-z]:[\\/]*) ;;
+	  *)
+	    func_fatal_error "only absolute run-paths are allowed"
+	    ;;
+	  esac
+	  if test "$prev" = rpath; then
+	    case "$rpath " in
+	    *" $arg "*) ;;
+	    *) func_append rpath " $arg" ;;
+	    esac
+	  else
+	    case "$xrpath " in
+	    *" $arg "*) ;;
+	    *) func_append xrpath " $arg" ;;
+	    esac
+	  fi
+	  prev=
+	  continue
+	  ;;
+	shrext)
+	  shrext_cmds="$arg"
+	  prev=
+	  continue
+	  ;;
+	weak)
+	  func_append weak_libs " $arg"
+	  prev=
+	  continue
+	  ;;
+	xcclinker)
+	  func_append linker_flags " $qarg"
+	  func_append compiler_flags " $qarg"
+	  prev=
+	  func_append compile_command " $qarg"
+	  func_append finalize_command " $qarg"
+	  continue
+	  ;;
+	xcompiler)
+	  func_append compiler_flags " $qarg"
+	  prev=
+	  func_append compile_command " $qarg"
+	  func_append finalize_command " $qarg"
+	  continue
+	  ;;
+	xlinker)
+	  func_append linker_flags " $qarg"
+	  func_append compiler_flags " $wl$qarg"
+	  prev=
+	  func_append compile_command " $wl$qarg"
+	  func_append finalize_command " $wl$qarg"
+	  continue
+	  ;;
+	*)
+	  eval "$prev=\"\$arg\""
+	  prev=
+	  continue
+	  ;;
+	esac
+      fi # test -n "$prev"
+
+      prevarg="$arg"
+
+      case $arg in
+      -all-static)
+	if test -n "$link_static_flag"; then
+	  # See comment for -static flag below, for more details.
+	  func_append compile_command " $link_static_flag"
+	  func_append finalize_command " $link_static_flag"
+	fi
+	continue
+	;;
+
+      -allow-undefined)
+	# FIXME: remove this flag sometime in the future.
+	func_fatal_error "\`-allow-undefined' must not be used because it is the default"
+	;;
+
+      -avoid-version)
+	avoid_version=yes
+	continue
+	;;
+
+      -bindir)
+	prev=bindir
+	continue
+	;;
+
+      -dlopen)
+	prev=dlfiles
+	continue
+	;;
+
+      -dlpreopen)
+	prev=dlprefiles
+	continue
+	;;
+
+      -export-dynamic)
+	export_dynamic=yes
+	continue
+	;;
+
+      -export-symbols | -export-symbols-regex)
+	if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+	  func_fatal_error "more than one -exported-symbols argument is not allowed"
+	fi
+	if test "X$arg" = "X-export-symbols"; then
+	  prev=expsyms
+	else
+	  prev=expsyms_regex
+	fi
+	continue
+	;;
+
+      -framework)
+	prev=framework
+	continue
+	;;
+
+      -inst-prefix-dir)
+	prev=inst_prefix
+	continue
+	;;
+
+      # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
+      # so, if we see these flags be careful not to treat them like -L
+      -L[A-Z][A-Z]*:*)
+	case $with_gcc/$host in
+	no/*-*-irix* | /*-*-irix*)
+	  func_append compile_command " $arg"
+	  func_append finalize_command " $arg"
+	  ;;
+	esac
+	continue
+	;;
+
+      -L*)
+	func_stripname "-L" '' "$arg"
+	if test -z "$func_stripname_result"; then
+	  if test "$#" -gt 0; then
+	    func_fatal_error "require no space between \`-L' and \`$1'"
+	  else
+	    func_fatal_error "need path for \`-L' option"
+	  fi
+	fi
+	func_resolve_sysroot "$func_stripname_result"
+	dir=$func_resolve_sysroot_result
+	# We need an absolute path.
+	case $dir in
+	[\\/]* | [A-Za-z]:[\\/]*) ;;
+	*)
+	  absdir=`cd "$dir" && pwd`
+	  test -z "$absdir" && \
+	    func_fatal_error "cannot determine absolute directory name of \`$dir'"
+	  dir="$absdir"
+	  ;;
+	esac
+	case "$deplibs " in
+	*" -L$dir "* | *" $arg "*)
+	  # Will only happen for absolute or sysroot arguments
+	  ;;
+	*)
+	  # Preserve sysroot, but never include relative directories
+	  case $dir in
+	    [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;;
+	    *) func_append deplibs " -L$dir" ;;
+	  esac
+	  func_append lib_search_path " $dir"
+	  ;;
+	esac
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+	  testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'`
+	  case :$dllsearchpath: in
+	  *":$dir:"*) ;;
+	  ::) dllsearchpath=$dir;;
+	  *) func_append dllsearchpath ":$dir";;
+	  esac
+	  case :$dllsearchpath: in
+	  *":$testbindir:"*) ;;
+	  ::) dllsearchpath=$testbindir;;
+	  *) func_append dllsearchpath ":$testbindir";;
+	  esac
+	  ;;
+	esac
+	continue
+	;;
+
+      -l*)
+	if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
+	  case $host in
+	  *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*)
+	    # These systems don't actually have a C or math library (as such)
+	    continue
+	    ;;
+	  *-*-os2*)
+	    # These systems don't actually have a C library (as such)
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+	    # Do not include libc due to us having libc/libc_r.
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  *-*-rhapsody* | *-*-darwin1.[012])
+	    # Rhapsody C and math libraries are in the System framework
+	    func_append deplibs " System.ltframework"
+	    continue
+	    ;;
+	  *-*-sco3.2v5* | *-*-sco5v6*)
+	    # Causes problems with __ctype
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+	    # Compiler inserts libc in the correct place for threads to work
+	    test "X$arg" = "X-lc" && continue
+	    ;;
+	  esac
+	elif test "X$arg" = "X-lc_r"; then
+	 case $host in
+	 *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+	   # Do not include libc_r directly, use -pthread flag.
+	   continue
+	   ;;
+	 esac
+	fi
+	func_append deplibs " $arg"
+	continue
+	;;
+
+      -module)
+	module=yes
+	continue
+	;;
+
+      # Tru64 UNIX uses -model [arg] to determine the layout of C++
+      # classes, name mangling, and exception handling.
+      # Darwin uses the -arch flag to determine output architecture.
+      -model|-arch|-isysroot|--sysroot)
+	func_append compiler_flags " $arg"
+	func_append compile_command " $arg"
+	func_append finalize_command " $arg"
+	prev=xcompiler
+	continue
+	;;
+
+      -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
+      |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+	func_append compiler_flags " $arg"
+	func_append compile_command " $arg"
+	func_append finalize_command " $arg"
+	case "$new_inherited_linker_flags " in
+	    *" $arg "*) ;;
+	    * ) func_append new_inherited_linker_flags " $arg" ;;
+	esac
+	continue
+	;;
+
+      -multi_module)
+	single_module="${wl}-multi_module"
+	continue
+	;;
+
+      -no-fast-install)
+	fast_install=no
+	continue
+	;;
+
+      -no-install)
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*)
+	  # The PATH hackery in wrapper scripts is required on Windows
+	  # and Darwin in order for the loader to find any dlls it needs.
+	  func_warning "\`-no-install' is ignored for $host"
+	  func_warning "assuming \`-no-fast-install' instead"
+	  fast_install=no
+	  ;;
+	*) no_install=yes ;;
+	esac
+	continue
+	;;
+
+      -no-undefined)
+	allow_undefined=no
+	continue
+	;;
+
+      -objectlist)
+	prev=objectlist
+	continue
+	;;
+
+      -o) prev=output ;;
+
+      -precious-files-regex)
+	prev=precious_regex
+	continue
+	;;
+
+      -release)
+	prev=release
+	continue
+	;;
+
+      -rpath)
+	prev=rpath
+	continue
+	;;
+
+      -R)
+	prev=xrpath
+	continue
+	;;
+
+      -R*)
+	func_stripname '-R' '' "$arg"
+	dir=$func_stripname_result
+	# We need an absolute path.
+	case $dir in
+	[\\/]* | [A-Za-z]:[\\/]*) ;;
+	=*)
+	  func_stripname '=' '' "$dir"
+	  dir=$lt_sysroot$func_stripname_result
+	  ;;
+	*)
+	  func_fatal_error "only absolute run-paths are allowed"
+	  ;;
+	esac
+	case "$xrpath " in
+	*" $dir "*) ;;
+	*) func_append xrpath " $dir" ;;
+	esac
+	continue
+	;;
+
+      -shared)
+	# The effects of -shared are defined in a previous loop.
+	continue
+	;;
+
+      -shrext)
+	prev=shrext
+	continue
+	;;
+
+      -static | -static-libtool-libs)
+	# The effects of -static are defined in a previous loop.
+	# We used to do the same as -all-static on platforms that
+	# didn't have a PIC flag, but the assumption that the effects
+	# would be equivalent was wrong.  It would break on at least
+	# Digital Unix and AIX.
+	continue
+	;;
+
+      -thread-safe)
+	thread_safe=yes
+	continue
+	;;
+
+      -version-info)
+	prev=vinfo
+	continue
+	;;
+
+      -version-number)
+	prev=vinfo
+	vinfo_number=yes
+	continue
+	;;
+
+      -weak)
+        prev=weak
+	continue
+	;;
+
+      -Wc,*)
+	func_stripname '-Wc,' '' "$arg"
+	args=$func_stripname_result
+	arg=
+	save_ifs="$IFS"; IFS=','
+	for flag in $args; do
+	  IFS="$save_ifs"
+          func_quote_for_eval "$flag"
+	  func_append arg " $func_quote_for_eval_result"
+	  func_append compiler_flags " $func_quote_for_eval_result"
+	done
+	IFS="$save_ifs"
+	func_stripname ' ' '' "$arg"
+	arg=$func_stripname_result
+	;;
+
+      -Wl,*)
+	func_stripname '-Wl,' '' "$arg"
+	args=$func_stripname_result
+	arg=
+	save_ifs="$IFS"; IFS=','
+	for flag in $args; do
+	  IFS="$save_ifs"
+          func_quote_for_eval "$flag"
+	  func_append arg " $wl$func_quote_for_eval_result"
+	  func_append compiler_flags " $wl$func_quote_for_eval_result"
+	  func_append linker_flags " $func_quote_for_eval_result"
+	done
+	IFS="$save_ifs"
+	func_stripname ' ' '' "$arg"
+	arg=$func_stripname_result
+	;;
+
+      -Xcompiler)
+	prev=xcompiler
+	continue
+	;;
+
+      -Xlinker)
+	prev=xlinker
+	continue
+	;;
+
+      -XCClinker)
+	prev=xcclinker
+	continue
+	;;
+
+      # -msg_* for osf cc
+      -msg_*)
+	func_quote_for_eval "$arg"
+	arg="$func_quote_for_eval_result"
+	;;
+
+      # Flags to be passed through unchanged, with rationale:
+      # -64, -mips[0-9]      enable 64-bit mode for the SGI compiler
+      # -r[0-9][0-9]*        specify processor for the SGI compiler
+      # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler
+      # +DA*, +DD*           enable 64-bit mode for the HP compiler
+      # -q*                  compiler args for the IBM compiler
+      # -m*, -t[45]*, -txscale* architecture-specific flags for GCC
+      # -F/path              path to uninstalled frameworks, gcc on darwin
+      # -p, -pg, --coverage, -fprofile-*  profiling flags for GCC
+      # @file                GCC response files
+      # -tp=*                Portland pgcc target processor selection
+      # --sysroot=*          for sysroot support
+      # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
+      -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+      -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
+      -O*|-flto*|-fwhopr*|-fuse-linker-plugin)
+        func_quote_for_eval "$arg"
+	arg="$func_quote_for_eval_result"
+        func_append compile_command " $arg"
+        func_append finalize_command " $arg"
+        func_append compiler_flags " $arg"
+        continue
+        ;;
+
+      # Some other compiler flag.
+      -* | +*)
+        func_quote_for_eval "$arg"
+	arg="$func_quote_for_eval_result"
+	;;
+
+      *.$objext)
+	# A standard object.
+	func_append objs " $arg"
+	;;
+
+      *.lo)
+	# A libtool-controlled object.
+
+	# Check to see that this really is a libtool object.
+	if func_lalib_unsafe_p "$arg"; then
+	  pic_object=
+	  non_pic_object=
+
+	  # Read the .lo file
+	  func_source "$arg"
+
+	  if test -z "$pic_object" ||
+	     test -z "$non_pic_object" ||
+	     test "$pic_object" = none &&
+	     test "$non_pic_object" = none; then
+	    func_fatal_error "cannot find name of object for \`$arg'"
+	  fi
+
+	  # Extract subdirectory from the argument.
+	  func_dirname "$arg" "/" ""
+	  xdir="$func_dirname_result"
+
+	  if test "$pic_object" != none; then
+	    # Prepend the subdirectory the object is found in.
+	    pic_object="$xdir$pic_object"
+
+	    if test "$prev" = dlfiles; then
+	      if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+		func_append dlfiles " $pic_object"
+		prev=
+		continue
+	      else
+		# If libtool objects are unsupported, then we need to preload.
+		prev=dlprefiles
+	      fi
+	    fi
+
+	    # CHECK ME:  I think I busted this.  -Ossama
+	    if test "$prev" = dlprefiles; then
+	      # Preload the old-style object.
+	      func_append dlprefiles " $pic_object"
+	      prev=
+	    fi
+
+	    # A PIC object.
+	    func_append libobjs " $pic_object"
+	    arg="$pic_object"
+	  fi
+
+	  # Non-PIC object.
+	  if test "$non_pic_object" != none; then
+	    # Prepend the subdirectory the object is found in.
+	    non_pic_object="$xdir$non_pic_object"
+
+	    # A standard non-PIC object
+	    func_append non_pic_objects " $non_pic_object"
+	    if test -z "$pic_object" || test "$pic_object" = none ; then
+	      arg="$non_pic_object"
+	    fi
+	  else
+	    # If the PIC object exists, use it instead.
+	    # $xdir was prepended to $pic_object above.
+	    non_pic_object="$pic_object"
+	    func_append non_pic_objects " $non_pic_object"
+	  fi
+	else
+	  # Only an error if not doing a dry-run.
+	  if $opt_dry_run; then
+	    # Extract subdirectory from the argument.
+	    func_dirname "$arg" "/" ""
+	    xdir="$func_dirname_result"
+
+	    func_lo2o "$arg"
+	    pic_object=$xdir$objdir/$func_lo2o_result
+	    non_pic_object=$xdir$func_lo2o_result
+	    func_append libobjs " $pic_object"
+	    func_append non_pic_objects " $non_pic_object"
+	  else
+	    func_fatal_error "\`$arg' is not a valid libtool object"
+	  fi
+	fi
+	;;
+
+      *.$libext)
+	# An archive.
+	func_append deplibs " $arg"
+	func_append old_deplibs " $arg"
+	continue
+	;;
+
+      *.la)
+	# A libtool-controlled library.
+
+	func_resolve_sysroot "$arg"
+	if test "$prev" = dlfiles; then
+	  # This library was specified with -dlopen.
+	  func_append dlfiles " $func_resolve_sysroot_result"
+	  prev=
+	elif test "$prev" = dlprefiles; then
+	  # The library was specified with -dlpreopen.
+	  func_append dlprefiles " $func_resolve_sysroot_result"
+	  prev=
+	else
+	  func_append deplibs " $func_resolve_sysroot_result"
+	fi
+	continue
+	;;
+
+      # Some other compiler argument.
+      *)
+	# Unknown arguments in both finalize_command and compile_command need
+	# to be aesthetically quoted because they are evaled later.
+	func_quote_for_eval "$arg"
+	arg="$func_quote_for_eval_result"
+	;;
+      esac # arg
+
+      # Now actually substitute the argument into the commands.
+      if test -n "$arg"; then
+	func_append compile_command " $arg"
+	func_append finalize_command " $arg"
+      fi
+    done # argument parsing loop
+
+    test -n "$prev" && \
+      func_fatal_help "the \`$prevarg' option requires an argument"
+
+    if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
+      eval arg=\"$export_dynamic_flag_spec\"
+      func_append compile_command " $arg"
+      func_append finalize_command " $arg"
+    fi
+
+    oldlibs=
+    # calculate the name of the file, without its directory
+    func_basename "$output"
+    outputname="$func_basename_result"
+    libobjs_save="$libobjs"
+
+    if test -n "$shlibpath_var"; then
+      # get the directories listed in $shlibpath_var
+      eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\`
+    else
+      shlib_search_path=
+    fi
+    eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
+    eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+
+    func_dirname "$output" "/" ""
+    output_objdir="$func_dirname_result$objdir"
+    func_to_tool_file "$output_objdir/"
+    tool_output_objdir=$func_to_tool_file_result
+    # Create the object directory.
+    func_mkdir_p "$output_objdir"
+
+    # Determine the type of output
+    case $output in
+    "")
+      func_fatal_help "you must specify an output file"
+      ;;
+    *.$libext) linkmode=oldlib ;;
+    *.lo | *.$objext) linkmode=obj ;;
+    *.la) linkmode=lib ;;
+    *) linkmode=prog ;; # Anything else should be a program.
+    esac
+
+    specialdeplibs=
+
+    libs=
+    # Find all interdependent deplibs by searching for libraries
+    # that are linked more than once (e.g. -la -lb -la)
+    for deplib in $deplibs; do
+      if $opt_preserve_dup_deps ; then
+	case "$libs " in
+	*" $deplib "*) func_append specialdeplibs " $deplib" ;;
+	esac
+      fi
+      func_append libs " $deplib"
+    done
+
+    if test "$linkmode" = lib; then
+      libs="$predeps $libs $compiler_lib_search_path $postdeps"
+
+      # Compute libraries that are listed more than once in $predeps
+      # $postdeps and mark them as special (i.e., whose duplicates are
+      # not to be eliminated).
+      pre_post_deps=
+      if $opt_duplicate_compiler_generated_deps; then
+	for pre_post_dep in $predeps $postdeps; do
+	  case "$pre_post_deps " in
+	  *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;;
+	  esac
+	  func_append pre_post_deps " $pre_post_dep"
+	done
+      fi
+      pre_post_deps=
+    fi
+
+    deplibs=
+    newdependency_libs=
+    newlib_search_path=
+    need_relink=no # whether we're linking any uninstalled libtool libraries
+    notinst_deplibs= # not-installed libtool libraries
+    notinst_path= # paths that contain not-installed libtool libraries
+
+    case $linkmode in
+    lib)
+	passes="conv dlpreopen link"
+	for file in $dlfiles $dlprefiles; do
+	  case $file in
+	  *.la) ;;
+	  *)
+	    func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file"
+	    ;;
+	  esac
+	done
+	;;
+    prog)
+	compile_deplibs=
+	finalize_deplibs=
+	alldeplibs=no
+	newdlfiles=
+	newdlprefiles=
+	passes="conv scan dlopen dlpreopen link"
+	;;
+    *)  passes="conv"
+	;;
+    esac
+
+    for pass in $passes; do
+      # The preopen pass in lib mode reverses $deplibs; put it back here
+      # so that -L comes before libs that need it for instance...
+      if test "$linkmode,$pass" = "lib,link"; then
+	## FIXME: Find the place where the list is rebuilt in the wrong
+	##        order, and fix it there properly
+        tmp_deplibs=
+	for deplib in $deplibs; do
+	  tmp_deplibs="$deplib $tmp_deplibs"
+	done
+	deplibs="$tmp_deplibs"
+      fi
+
+      if test "$linkmode,$pass" = "lib,link" ||
+	 test "$linkmode,$pass" = "prog,scan"; then
+	libs="$deplibs"
+	deplibs=
+      fi
+      if test "$linkmode" = prog; then
+	case $pass in
+	dlopen) libs="$dlfiles" ;;
+	dlpreopen) libs="$dlprefiles" ;;
+	link)
+	  libs="$deplibs %DEPLIBS%"
+	  test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs"
+	  ;;
+	esac
+      fi
+      if test "$linkmode,$pass" = "lib,dlpreopen"; then
+	# Collect and forward deplibs of preopened libtool libs
+	for lib in $dlprefiles; do
+	  # Ignore non-libtool-libs
+	  dependency_libs=
+	  func_resolve_sysroot "$lib"
+	  case $lib in
+	  *.la)	func_source "$func_resolve_sysroot_result" ;;
+	  esac
+
+	  # Collect preopened libtool deplibs, except any this library
+	  # has declared as weak libs
+	  for deplib in $dependency_libs; do
+	    func_basename "$deplib"
+            deplib_base=$func_basename_result
+	    case " $weak_libs " in
+	    *" $deplib_base "*) ;;
+	    *) func_append deplibs " $deplib" ;;
+	    esac
+	  done
+	done
+	libs="$dlprefiles"
+      fi
+      if test "$pass" = dlopen; then
+	# Collect dlpreopened libraries
+	save_deplibs="$deplibs"
+	deplibs=
+      fi
+
+      for deplib in $libs; do
+	lib=
+	found=no
+	case $deplib in
+	-mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
+        |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+	  if test "$linkmode,$pass" = "prog,link"; then
+	    compile_deplibs="$deplib $compile_deplibs"
+	    finalize_deplibs="$deplib $finalize_deplibs"
+	  else
+	    func_append compiler_flags " $deplib"
+	    if test "$linkmode" = lib ; then
+		case "$new_inherited_linker_flags " in
+		    *" $deplib "*) ;;
+		    * ) func_append new_inherited_linker_flags " $deplib" ;;
+		esac
+	    fi
+	  fi
+	  continue
+	  ;;
+	-l*)
+	  if test "$linkmode" != lib && test "$linkmode" != prog; then
+	    func_warning "\`-l' is ignored for archives/objects"
+	    continue
+	  fi
+	  func_stripname '-l' '' "$deplib"
+	  name=$func_stripname_result
+	  if test "$linkmode" = lib; then
+	    searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path"
+	  else
+	    searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path"
+	  fi
+	  for searchdir in $searchdirs; do
+	    for search_ext in .la $std_shrext .so .a; do
+	      # Search the libtool library
+	      lib="$searchdir/lib${name}${search_ext}"
+	      if test -f "$lib"; then
+		if test "$search_ext" = ".la"; then
+		  found=yes
+		else
+		  found=no
+		fi
+		break 2
+	      fi
+	    done
+	  done
+	  if test "$found" != yes; then
+	    # deplib doesn't seem to be a libtool library
+	    if test "$linkmode,$pass" = "prog,link"; then
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    else
+	      deplibs="$deplib $deplibs"
+	      test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+	    fi
+	    continue
+	  else # deplib is a libtool library
+	    # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
+	    # We need to do some special things here, and not later.
+	    if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+	      case " $predeps $postdeps " in
+	      *" $deplib "*)
+		if func_lalib_p "$lib"; then
+		  library_names=
+		  old_library=
+		  func_source "$lib"
+		  for l in $old_library $library_names; do
+		    ll="$l"
+		  done
+		  if test "X$ll" = "X$old_library" ; then # only static version available
+		    found=no
+		    func_dirname "$lib" "" "."
+		    ladir="$func_dirname_result"
+		    lib=$ladir/$old_library
+		    if test "$linkmode,$pass" = "prog,link"; then
+		      compile_deplibs="$deplib $compile_deplibs"
+		      finalize_deplibs="$deplib $finalize_deplibs"
+		    else
+		      deplibs="$deplib $deplibs"
+		      test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+		    fi
+		    continue
+		  fi
+		fi
+		;;
+	      *) ;;
+	      esac
+	    fi
+	  fi
+	  ;; # -l
+	*.ltframework)
+	  if test "$linkmode,$pass" = "prog,link"; then
+	    compile_deplibs="$deplib $compile_deplibs"
+	    finalize_deplibs="$deplib $finalize_deplibs"
+	  else
+	    deplibs="$deplib $deplibs"
+	    if test "$linkmode" = lib ; then
+		case "$new_inherited_linker_flags " in
+		    *" $deplib "*) ;;
+		    * ) func_append new_inherited_linker_flags " $deplib" ;;
+		esac
+	    fi
+	  fi
+	  continue
+	  ;;
+	-L*)
+	  case $linkmode in
+	  lib)
+	    deplibs="$deplib $deplibs"
+	    test "$pass" = conv && continue
+	    newdependency_libs="$deplib $newdependency_libs"
+	    func_stripname '-L' '' "$deplib"
+	    func_resolve_sysroot "$func_stripname_result"
+	    func_append newlib_search_path " $func_resolve_sysroot_result"
+	    ;;
+	  prog)
+	    if test "$pass" = conv; then
+	      deplibs="$deplib $deplibs"
+	      continue
+	    fi
+	    if test "$pass" = scan; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    fi
+	    func_stripname '-L' '' "$deplib"
+	    func_resolve_sysroot "$func_stripname_result"
+	    func_append newlib_search_path " $func_resolve_sysroot_result"
+	    ;;
+	  *)
+	    func_warning "\`-L' is ignored for archives/objects"
+	    ;;
+	  esac # linkmode
+	  continue
+	  ;; # -L
+	-R*)
+	  if test "$pass" = link; then
+	    func_stripname '-R' '' "$deplib"
+	    func_resolve_sysroot "$func_stripname_result"
+	    dir=$func_resolve_sysroot_result
+	    # Make sure the xrpath contains only unique directories.
+	    case "$xrpath " in
+	    *" $dir "*) ;;
+	    *) func_append xrpath " $dir" ;;
+	    esac
+	  fi
+	  deplibs="$deplib $deplibs"
+	  continue
+	  ;;
+	*.la)
+	  func_resolve_sysroot "$deplib"
+	  lib=$func_resolve_sysroot_result
+	  ;;
+	*.$libext)
+	  if test "$pass" = conv; then
+	    deplibs="$deplib $deplibs"
+	    continue
+	  fi
+	  case $linkmode in
+	  lib)
+	    # Linking convenience modules into shared libraries is allowed,
+	    # but linking other static libraries is non-portable.
+	    case " $dlpreconveniencelibs " in
+	    *" $deplib "*) ;;
+	    *)
+	      valid_a_lib=no
+	      case $deplibs_check_method in
+		match_pattern*)
+		  set dummy $deplibs_check_method; shift
+		  match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+		  if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \
+		    | $EGREP "$match_pattern_regex" > /dev/null; then
+		    valid_a_lib=yes
+		  fi
+		;;
+		pass_all)
+		  valid_a_lib=yes
+		;;
+	      esac
+	      if test "$valid_a_lib" != yes; then
+		echo
+		$ECHO "*** Warning: Trying to link with static lib archive $deplib."
+		echo "*** I have the capability to make that library automatically link in when"
+		echo "*** you link to this library.  But I can only do this if you have a"
+		echo "*** shared version of the library, which you do not appear to have"
+		echo "*** because the file extensions .$libext of this argument makes me believe"
+		echo "*** that it is just a static archive that I should not use here."
+	      else
+		echo
+		$ECHO "*** Warning: Linking the shared library $output against the"
+		$ECHO "*** static library $deplib is not portable!"
+		deplibs="$deplib $deplibs"
+	      fi
+	      ;;
+	    esac
+	    continue
+	    ;;
+	  prog)
+	    if test "$pass" != link; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    fi
+	    continue
+	    ;;
+	  esac # linkmode
+	  ;; # *.$libext
+	*.lo | *.$objext)
+	  if test "$pass" = conv; then
+	    deplibs="$deplib $deplibs"
+	  elif test "$linkmode" = prog; then
+	    if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
+	      # If there is no dlopen support or we're linking statically,
+	      # we need to preload.
+	      func_append newdlprefiles " $deplib"
+	      compile_deplibs="$deplib $compile_deplibs"
+	      finalize_deplibs="$deplib $finalize_deplibs"
+	    else
+	      func_append newdlfiles " $deplib"
+	    fi
+	  fi
+	  continue
+	  ;;
+	%DEPLIBS%)
+	  alldeplibs=yes
+	  continue
+	  ;;
+	esac # case $deplib
+
+	if test "$found" = yes || test -f "$lib"; then :
+	else
+	  func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'"
+	fi
+
+	# Check to see that this really is a libtool archive.
+	func_lalib_unsafe_p "$lib" \
+	  || func_fatal_error "\`$lib' is not a valid libtool archive"
+
+	func_dirname "$lib" "" "."
+	ladir="$func_dirname_result"
+
+	dlname=
+	dlopen=
+	dlpreopen=
+	libdir=
+	library_names=
+	old_library=
+	inherited_linker_flags=
+	# If the library was installed with an old release of libtool,
+	# it will not redefine variables installed, or shouldnotlink
+	installed=yes
+	shouldnotlink=no
+	avoidtemprpath=
+
+
+	# Read the .la file
+	func_source "$lib"
+
+	# Convert "-framework foo" to "foo.ltframework"
+	if test -n "$inherited_linker_flags"; then
+	  tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'`
+	  for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do
+	    case " $new_inherited_linker_flags " in
+	      *" $tmp_inherited_linker_flag "*) ;;
+	      *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";;
+	    esac
+	  done
+	fi
+	dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	if test "$linkmode,$pass" = "lib,link" ||
+	   test "$linkmode,$pass" = "prog,scan" ||
+	   { test "$linkmode" != prog && test "$linkmode" != lib; }; then
+	  test -n "$dlopen" && func_append dlfiles " $dlopen"
+	  test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen"
+	fi
+
+	if test "$pass" = conv; then
+	  # Only check for convenience libraries
+	  deplibs="$lib $deplibs"
+	  if test -z "$libdir"; then
+	    if test -z "$old_library"; then
+	      func_fatal_error "cannot find name of link library for \`$lib'"
+	    fi
+	    # It is a libtool convenience library, so add in its objects.
+	    func_append convenience " $ladir/$objdir/$old_library"
+	    func_append old_convenience " $ladir/$objdir/$old_library"
+	    tmp_libs=
+	    for deplib in $dependency_libs; do
+	      deplibs="$deplib $deplibs"
+	      if $opt_preserve_dup_deps ; then
+		case "$tmp_libs " in
+		*" $deplib "*) func_append specialdeplibs " $deplib" ;;
+		esac
+	      fi
+	      func_append tmp_libs " $deplib"
+	    done
+	  elif test "$linkmode" != prog && test "$linkmode" != lib; then
+	    func_fatal_error "\`$lib' is not a convenience library"
+	  fi
+	  continue
+	fi # $pass = conv
+
+
+	# Get the name of the library we link against.
+	linklib=
+	if test -n "$old_library" &&
+	   { test "$prefer_static_libs" = yes ||
+	     test "$prefer_static_libs,$installed" = "built,no"; }; then
+	  linklib=$old_library
+	else
+	  for l in $old_library $library_names; do
+	    linklib="$l"
+	  done
+	fi
+	if test -z "$linklib"; then
+	  func_fatal_error "cannot find name of link library for \`$lib'"
+	fi
+
+	# This library was specified with -dlopen.
+	if test "$pass" = dlopen; then
+	  if test -z "$libdir"; then
+	    func_fatal_error "cannot -dlopen a convenience library: \`$lib'"
+	  fi
+	  if test -z "$dlname" ||
+	     test "$dlopen_support" != yes ||
+	     test "$build_libtool_libs" = no; then
+	    # If there is no dlname, no dlopen support or we're linking
+	    # statically, we need to preload.  We also need to preload any
+	    # dependent libraries so libltdl's deplib preloader doesn't
+	    # bomb out in the load deplibs phase.
+	    func_append dlprefiles " $lib $dependency_libs"
+	  else
+	    func_append newdlfiles " $lib"
+	  fi
+	  continue
+	fi # $pass = dlopen
+
+	# We need an absolute path.
+	case $ladir in
+	[\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;;
+	*)
+	  abs_ladir=`cd "$ladir" && pwd`
+	  if test -z "$abs_ladir"; then
+	    func_warning "cannot determine absolute directory name of \`$ladir'"
+	    func_warning "passing it literally to the linker, although it might fail"
+	    abs_ladir="$ladir"
+	  fi
+	  ;;
+	esac
+	func_basename "$lib"
+	laname="$func_basename_result"
+
+	# Find the relevant object directory and library name.
+	if test "X$installed" = Xyes; then
+	  if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+	    func_warning "library \`$lib' was moved."
+	    dir="$ladir"
+	    absdir="$abs_ladir"
+	    libdir="$abs_ladir"
+	  else
+	    dir="$lt_sysroot$libdir"
+	    absdir="$lt_sysroot$libdir"
+	  fi
+	  test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes
+	else
+	  if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+	    dir="$ladir"
+	    absdir="$abs_ladir"
+	    # Remove this search path later
+	    func_append notinst_path " $abs_ladir"
+	  else
+	    dir="$ladir/$objdir"
+	    absdir="$abs_ladir/$objdir"
+	    # Remove this search path later
+	    func_append notinst_path " $abs_ladir"
+	  fi
+	fi # $installed = yes
+	func_stripname 'lib' '.la' "$laname"
+	name=$func_stripname_result
+
+	# This library was specified with -dlpreopen.
+	if test "$pass" = dlpreopen; then
+	  if test -z "$libdir" && test "$linkmode" = prog; then
+	    func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'"
+	  fi
+	  case "$host" in
+	    # special handling for platforms with PE-DLLs.
+	    *cygwin* | *mingw* | *cegcc* )
+	      # Linker will automatically link against shared library if both
+	      # static and shared are present.  Therefore, ensure we extract
+	      # symbols from the import library if a shared library is present
+	      # (otherwise, the dlopen module name will be incorrect).  We do
+	      # this by putting the import library name into $newdlprefiles.
+	      # We recover the dlopen module name by 'saving' the la file
+	      # name in a special purpose variable, and (later) extracting the
+	      # dlname from the la file.
+	      if test -n "$dlname"; then
+	        func_tr_sh "$dir/$linklib"
+	        eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname"
+	        func_append newdlprefiles " $dir/$linklib"
+	      else
+	        func_append newdlprefiles " $dir/$old_library"
+	        # Keep a list of preopened convenience libraries to check
+	        # that they are being used correctly in the link pass.
+	        test -z "$libdir" && \
+	          func_append dlpreconveniencelibs " $dir/$old_library"
+	      fi
+	    ;;
+	    * )
+	      # Prefer using a static library (so that no silly _DYNAMIC symbols
+	      # are required to link).
+	      if test -n "$old_library"; then
+	        func_append newdlprefiles " $dir/$old_library"
+	        # Keep a list of preopened convenience libraries to check
+	        # that they are being used correctly in the link pass.
+	        test -z "$libdir" && \
+	          func_append dlpreconveniencelibs " $dir/$old_library"
+	      # Otherwise, use the dlname, so that lt_dlopen finds it.
+	      elif test -n "$dlname"; then
+	        func_append newdlprefiles " $dir/$dlname"
+	      else
+	        func_append newdlprefiles " $dir/$linklib"
+	      fi
+	    ;;
+	  esac
+	fi # $pass = dlpreopen
+
+	if test -z "$libdir"; then
+	  # Link the convenience library
+	  if test "$linkmode" = lib; then
+	    deplibs="$dir/$old_library $deplibs"
+	  elif test "$linkmode,$pass" = "prog,link"; then
+	    compile_deplibs="$dir/$old_library $compile_deplibs"
+	    finalize_deplibs="$dir/$old_library $finalize_deplibs"
+	  else
+	    deplibs="$lib $deplibs" # used for prog,scan pass
+	  fi
+	  continue
+	fi
+
+
+	if test "$linkmode" = prog && test "$pass" != link; then
+	  func_append newlib_search_path " $ladir"
+	  deplibs="$lib $deplibs"
+
+	  linkalldeplibs=no
+	  if test "$link_all_deplibs" != no || test -z "$library_names" ||
+	     test "$build_libtool_libs" = no; then
+	    linkalldeplibs=yes
+	  fi
+
+	  tmp_libs=
+	  for deplib in $dependency_libs; do
+	    case $deplib in
+	    -L*) func_stripname '-L' '' "$deplib"
+	         func_resolve_sysroot "$func_stripname_result"
+	         func_append newlib_search_path " $func_resolve_sysroot_result"
+		 ;;
+	    esac
+	    # Need to link against all dependency_libs?
+	    if test "$linkalldeplibs" = yes; then
+	      deplibs="$deplib $deplibs"
+	    else
+	      # Need to hardcode shared library paths
+	      # or/and link against static libraries
+	      newdependency_libs="$deplib $newdependency_libs"
+	    fi
+	    if $opt_preserve_dup_deps ; then
+	      case "$tmp_libs " in
+	      *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+	      esac
+	    fi
+	    func_append tmp_libs " $deplib"
+	  done # for deplib
+	  continue
+	fi # $linkmode = prog...
+
+	if test "$linkmode,$pass" = "prog,link"; then
+	  if test -n "$library_names" &&
+	     { { test "$prefer_static_libs" = no ||
+	         test "$prefer_static_libs,$installed" = "built,yes"; } ||
+	       test -z "$old_library"; }; then
+	    # We need to hardcode the library path
+	    if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then
+	      # Make sure the rpath contains only unique directories.
+	      case "$temp_rpath:" in
+	      *"$absdir:"*) ;;
+	      *) func_append temp_rpath "$absdir:" ;;
+	      esac
+	    fi
+
+	    # Hardcode the library path.
+	    # Skip directories that are in the system default run-time
+	    # search path.
+	    case " $sys_lib_dlsearch_path " in
+	    *" $absdir "*) ;;
+	    *)
+	      case "$compile_rpath " in
+	      *" $absdir "*) ;;
+	      *) func_append compile_rpath " $absdir" ;;
+	      esac
+	      ;;
+	    esac
+	    case " $sys_lib_dlsearch_path " in
+	    *" $libdir "*) ;;
+	    *)
+	      case "$finalize_rpath " in
+	      *" $libdir "*) ;;
+	      *) func_append finalize_rpath " $libdir" ;;
+	      esac
+	      ;;
+	    esac
+	  fi # $linkmode,$pass = prog,link...
+
+	  if test "$alldeplibs" = yes &&
+	     { test "$deplibs_check_method" = pass_all ||
+	       { test "$build_libtool_libs" = yes &&
+		 test -n "$library_names"; }; }; then
+	    # We only need to search for static libraries
+	    continue
+	  fi
+	fi
+
+	link_static=no # Whether the deplib will be linked statically
+	use_static_libs=$prefer_static_libs
+	if test "$use_static_libs" = built && test "$installed" = yes; then
+	  use_static_libs=no
+	fi
+	if test -n "$library_names" &&
+	   { test "$use_static_libs" = no || test -z "$old_library"; }; then
+	  case $host in
+	  *cygwin* | *mingw* | *cegcc*)
+	      # No point in relinking DLLs because paths are not encoded
+	      func_append notinst_deplibs " $lib"
+	      need_relink=no
+	    ;;
+	  *)
+	    if test "$installed" = no; then
+	      func_append notinst_deplibs " $lib"
+	      need_relink=yes
+	    fi
+	    ;;
+	  esac
+	  # This is a shared library
+
+	  # Warn about portability, can't link against -module's on some
+	  # systems (darwin).  Don't bleat about dlopened modules though!
+	  dlopenmodule=""
+	  for dlpremoduletest in $dlprefiles; do
+	    if test "X$dlpremoduletest" = "X$lib"; then
+	      dlopenmodule="$dlpremoduletest"
+	      break
+	    fi
+	  done
+	  if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then
+	    echo
+	    if test "$linkmode" = prog; then
+	      $ECHO "*** Warning: Linking the executable $output against the loadable module"
+	    else
+	      $ECHO "*** Warning: Linking the shared library $output against the loadable module"
+	    fi
+	    $ECHO "*** $linklib is not portable!"
+	  fi
+	  if test "$linkmode" = lib &&
+	     test "$hardcode_into_libs" = yes; then
+	    # Hardcode the library path.
+	    # Skip directories that are in the system default run-time
+	    # search path.
+	    case " $sys_lib_dlsearch_path " in
+	    *" $absdir "*) ;;
+	    *)
+	      case "$compile_rpath " in
+	      *" $absdir "*) ;;
+	      *) func_append compile_rpath " $absdir" ;;
+	      esac
+	      ;;
+	    esac
+	    case " $sys_lib_dlsearch_path " in
+	    *" $libdir "*) ;;
+	    *)
+	      case "$finalize_rpath " in
+	      *" $libdir "*) ;;
+	      *) func_append finalize_rpath " $libdir" ;;
+	      esac
+	      ;;
+	    esac
+	  fi
+
+	  if test -n "$old_archive_from_expsyms_cmds"; then
+	    # figure out the soname
+	    set dummy $library_names
+	    shift
+	    realname="$1"
+	    shift
+	    libname=`eval "\\$ECHO \"$libname_spec\""`
+	    # use dlname if we got it. it's perfectly good, no?
+	    if test -n "$dlname"; then
+	      soname="$dlname"
+	    elif test -n "$soname_spec"; then
+	      # bleh windows
+	      case $host in
+	      *cygwin* | mingw* | *cegcc*)
+	        func_arith $current - $age
+		major=$func_arith_result
+		versuffix="-$major"
+		;;
+	      esac
+	      eval soname=\"$soname_spec\"
+	    else
+	      soname="$realname"
+	    fi
+
+	    # Make a new name for the extract_expsyms_cmds to use
+	    soroot="$soname"
+	    func_basename "$soroot"
+	    soname="$func_basename_result"
+	    func_stripname 'lib' '.dll' "$soname"
+	    newlib=libimp-$func_stripname_result.a
+
+	    # If the library has no export list, then create one now
+	    if test -f "$output_objdir/$soname-def"; then :
+	    else
+	      func_verbose "extracting exported symbol list from \`$soname'"
+	      func_execute_cmds "$extract_expsyms_cmds" 'exit $?'
+	    fi
+
+	    # Create $newlib
+	    if test -f "$output_objdir/$newlib"; then :; else
+	      func_verbose "generating import library for \`$soname'"
+	      func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?'
+	    fi
+	    # make sure the library variables are pointing to the new library
+	    dir=$output_objdir
+	    linklib=$newlib
+	  fi # test -n "$old_archive_from_expsyms_cmds"
+
+	  if test "$linkmode" = prog || test "$opt_mode" != relink; then
+	    add_shlibpath=
+	    add_dir=
+	    add=
+	    lib_linked=yes
+	    case $hardcode_action in
+	    immediate | unsupported)
+	      if test "$hardcode_direct" = no; then
+		add="$dir/$linklib"
+		case $host in
+		  *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;;
+		  *-*-sysv4*uw2*) add_dir="-L$dir" ;;
+		  *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \
+		    *-*-unixware7*) add_dir="-L$dir" ;;
+		  *-*-darwin* )
+		    # if the lib is a (non-dlopened) module then we can not
+		    # link against it, someone is ignoring the earlier warnings
+		    if /usr/bin/file -L $add 2> /dev/null |
+			 $GREP ": [^:]* bundle" >/dev/null ; then
+		      if test "X$dlopenmodule" != "X$lib"; then
+			$ECHO "*** Warning: lib $linklib is a module, not a shared library"
+			if test -z "$old_library" ; then
+			  echo
+			  echo "*** And there doesn't seem to be a static archive available"
+			  echo "*** The link will probably fail, sorry"
+			else
+			  add="$dir/$old_library"
+			fi
+		      elif test -n "$old_library"; then
+			add="$dir/$old_library"
+		      fi
+		    fi
+		esac
+	      elif test "$hardcode_minus_L" = no; then
+		case $host in
+		*-*-sunos*) add_shlibpath="$dir" ;;
+		esac
+		add_dir="-L$dir"
+		add="-l$name"
+	      elif test "$hardcode_shlibpath_var" = no; then
+		add_shlibpath="$dir"
+		add="-l$name"
+	      else
+		lib_linked=no
+	      fi
+	      ;;
+	    relink)
+	      if test "$hardcode_direct" = yes &&
+	         test "$hardcode_direct_absolute" = no; then
+		add="$dir/$linklib"
+	      elif test "$hardcode_minus_L" = yes; then
+		add_dir="-L$absdir"
+		# Try looking first in the location we're being installed to.
+		if test -n "$inst_prefix_dir"; then
+		  case $libdir in
+		    [\\/]*)
+		      func_append add_dir " -L$inst_prefix_dir$libdir"
+		      ;;
+		  esac
+		fi
+		add="-l$name"
+	      elif test "$hardcode_shlibpath_var" = yes; then
+		add_shlibpath="$dir"
+		add="-l$name"
+	      else
+		lib_linked=no
+	      fi
+	      ;;
+	    *) lib_linked=no ;;
+	    esac
+
+	    if test "$lib_linked" != yes; then
+	      func_fatal_configuration "unsupported hardcode properties"
+	    fi
+
+	    if test -n "$add_shlibpath"; then
+	      case :$compile_shlibpath: in
+	      *":$add_shlibpath:"*) ;;
+	      *) func_append compile_shlibpath "$add_shlibpath:" ;;
+	      esac
+	    fi
+	    if test "$linkmode" = prog; then
+	      test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
+	      test -n "$add" && compile_deplibs="$add $compile_deplibs"
+	    else
+	      test -n "$add_dir" && deplibs="$add_dir $deplibs"
+	      test -n "$add" && deplibs="$add $deplibs"
+	      if test "$hardcode_direct" != yes &&
+		 test "$hardcode_minus_L" != yes &&
+		 test "$hardcode_shlibpath_var" = yes; then
+		case :$finalize_shlibpath: in
+		*":$libdir:"*) ;;
+		*) func_append finalize_shlibpath "$libdir:" ;;
+		esac
+	      fi
+	    fi
+	  fi
+
+	  if test "$linkmode" = prog || test "$opt_mode" = relink; then
+	    add_shlibpath=
+	    add_dir=
+	    add=
+	    # Finalize command for both is simple: just hardcode it.
+	    if test "$hardcode_direct" = yes &&
+	       test "$hardcode_direct_absolute" = no; then
+	      add="$libdir/$linklib"
+	    elif test "$hardcode_minus_L" = yes; then
+	      add_dir="-L$libdir"
+	      add="-l$name"
+	    elif test "$hardcode_shlibpath_var" = yes; then
+	      case :$finalize_shlibpath: in
+	      *":$libdir:"*) ;;
+	      *) func_append finalize_shlibpath "$libdir:" ;;
+	      esac
+	      add="-l$name"
+	    elif test "$hardcode_automatic" = yes; then
+	      if test -n "$inst_prefix_dir" &&
+		 test -f "$inst_prefix_dir$libdir/$linklib" ; then
+		add="$inst_prefix_dir$libdir/$linklib"
+	      else
+		add="$libdir/$linklib"
+	      fi
+	    else
+	      # We cannot seem to hardcode it, guess we'll fake it.
+	      add_dir="-L$libdir"
+	      # Try looking first in the location we're being installed to.
+	      if test -n "$inst_prefix_dir"; then
+		case $libdir in
+		  [\\/]*)
+		    func_append add_dir " -L$inst_prefix_dir$libdir"
+		    ;;
+		esac
+	      fi
+	      add="-l$name"
+	    fi
+
+	    if test "$linkmode" = prog; then
+	      test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
+	      test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
+	    else
+	      test -n "$add_dir" && deplibs="$add_dir $deplibs"
+	      test -n "$add" && deplibs="$add $deplibs"
+	    fi
+	  fi
+	elif test "$linkmode" = prog; then
+	  # Here we assume that one of hardcode_direct or hardcode_minus_L
+	  # is not unsupported.  This is valid on all known static and
+	  # shared platforms.
+	  if test "$hardcode_direct" != unsupported; then
+	    test -n "$old_library" && linklib="$old_library"
+	    compile_deplibs="$dir/$linklib $compile_deplibs"
+	    finalize_deplibs="$dir/$linklib $finalize_deplibs"
+	  else
+	    compile_deplibs="-l$name -L$dir $compile_deplibs"
+	    finalize_deplibs="-l$name -L$dir $finalize_deplibs"
+	  fi
+	elif test "$build_libtool_libs" = yes; then
+	  # Not a shared library
+	  if test "$deplibs_check_method" != pass_all; then
+	    # We're trying link a shared library against a static one
+	    # but the system doesn't support it.
+
+	    # Just print a warning and add the library to dependency_libs so
+	    # that the program can be linked against the static library.
+	    echo
+	    $ECHO "*** Warning: This system can not link to static lib archive $lib."
+	    echo "*** I have the capability to make that library automatically link in when"
+	    echo "*** you link to this library.  But I can only do this if you have a"
+	    echo "*** shared version of the library, which you do not appear to have."
+	    if test "$module" = yes; then
+	      echo "*** But as you try to build a module library, libtool will still create "
+	      echo "*** a static module, that should work as long as the dlopening application"
+	      echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
+	      if test -z "$global_symbol_pipe"; then
+		echo
+		echo "*** However, this would only work if libtool was able to extract symbol"
+		echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+		echo "*** not find such a program.  So, this module is probably useless."
+		echo "*** \`nm' from GNU binutils and a full rebuild may help."
+	      fi
+	      if test "$build_old_libs" = no; then
+		build_libtool_libs=module
+		build_old_libs=yes
+	      else
+		build_libtool_libs=no
+	      fi
+	    fi
+	  else
+	    deplibs="$dir/$old_library $deplibs"
+	    link_static=yes
+	  fi
+	fi # link shared/static library?
+
+	if test "$linkmode" = lib; then
+	  if test -n "$dependency_libs" &&
+	     { test "$hardcode_into_libs" != yes ||
+	       test "$build_old_libs" = yes ||
+	       test "$link_static" = yes; }; then
+	    # Extract -R from dependency_libs
+	    temp_deplibs=
+	    for libdir in $dependency_libs; do
+	      case $libdir in
+	      -R*) func_stripname '-R' '' "$libdir"
+	           temp_xrpath=$func_stripname_result
+		   case " $xrpath " in
+		   *" $temp_xrpath "*) ;;
+		   *) func_append xrpath " $temp_xrpath";;
+		   esac;;
+	      *) func_append temp_deplibs " $libdir";;
+	      esac
+	    done
+	    dependency_libs="$temp_deplibs"
+	  fi
+
+	  func_append newlib_search_path " $absdir"
+	  # Link against this library
+	  test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+	  # ... and its dependency_libs
+	  tmp_libs=
+	  for deplib in $dependency_libs; do
+	    newdependency_libs="$deplib $newdependency_libs"
+	    case $deplib in
+              -L*) func_stripname '-L' '' "$deplib"
+                   func_resolve_sysroot "$func_stripname_result";;
+              *) func_resolve_sysroot "$deplib" ;;
+            esac
+	    if $opt_preserve_dup_deps ; then
+	      case "$tmp_libs " in
+	      *" $func_resolve_sysroot_result "*)
+                func_append specialdeplibs " $func_resolve_sysroot_result" ;;
+	      esac
+	    fi
+	    func_append tmp_libs " $func_resolve_sysroot_result"
+	  done
+
+	  if test "$link_all_deplibs" != no; then
+	    # Add the search paths of all dependency libraries
+	    for deplib in $dependency_libs; do
+	      path=
+	      case $deplib in
+	      -L*) path="$deplib" ;;
+	      *.la)
+	        func_resolve_sysroot "$deplib"
+	        deplib=$func_resolve_sysroot_result
+	        func_dirname "$deplib" "" "."
+		dir=$func_dirname_result
+		# We need an absolute path.
+		case $dir in
+		[\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;;
+		*)
+		  absdir=`cd "$dir" && pwd`
+		  if test -z "$absdir"; then
+		    func_warning "cannot determine absolute directory name of \`$dir'"
+		    absdir="$dir"
+		  fi
+		  ;;
+		esac
+		if $GREP "^installed=no" $deplib > /dev/null; then
+		case $host in
+		*-*-darwin*)
+		  depdepl=
+		  eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
+		  if test -n "$deplibrary_names" ; then
+		    for tmp in $deplibrary_names ; do
+		      depdepl=$tmp
+		    done
+		    if test -f "$absdir/$objdir/$depdepl" ; then
+		      depdepl="$absdir/$objdir/$depdepl"
+		      darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+                      if test -z "$darwin_install_name"; then
+                          darwin_install_name=`${OTOOL64} -L $depdepl  | awk '{if (NR == 2) {print $1;exit}}'`
+                      fi
+		      func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}"
+		      func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}"
+		      path=
+		    fi
+		  fi
+		  ;;
+		*)
+		  path="-L$absdir/$objdir"
+		  ;;
+		esac
+		else
+		  eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+		  test -z "$libdir" && \
+		    func_fatal_error "\`$deplib' is not a valid libtool archive"
+		  test "$absdir" != "$libdir" && \
+		    func_warning "\`$deplib' seems to be moved"
+
+		  path="-L$absdir"
+		fi
+		;;
+	      esac
+	      case " $deplibs " in
+	      *" $path "*) ;;
+	      *) deplibs="$path $deplibs" ;;
+	      esac
+	    done
+	  fi # link_all_deplibs != no
+	fi # linkmode = lib
+      done # for deplib in $libs
+      if test "$pass" = link; then
+	if test "$linkmode" = "prog"; then
+	  compile_deplibs="$new_inherited_linker_flags $compile_deplibs"
+	  finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs"
+	else
+	  compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	fi
+      fi
+      dependency_libs="$newdependency_libs"
+      if test "$pass" = dlpreopen; then
+	# Link the dlpreopened libraries before other libraries
+	for deplib in $save_deplibs; do
+	  deplibs="$deplib $deplibs"
+	done
+      fi
+      if test "$pass" != dlopen; then
+	if test "$pass" != conv; then
+	  # Make sure lib_search_path contains only unique directories.
+	  lib_search_path=
+	  for dir in $newlib_search_path; do
+	    case "$lib_search_path " in
+	    *" $dir "*) ;;
+	    *) func_append lib_search_path " $dir" ;;
+	    esac
+	  done
+	  newlib_search_path=
+	fi
+
+	if test "$linkmode,$pass" != "prog,link"; then
+	  vars="deplibs"
+	else
+	  vars="compile_deplibs finalize_deplibs"
+	fi
+	for var in $vars dependency_libs; do
+	  # Add libraries to $var in reverse order
+	  eval tmp_libs=\"\$$var\"
+	  new_libs=
+	  for deplib in $tmp_libs; do
+	    # FIXME: Pedantically, this is the right thing to do, so
+	    #        that some nasty dependency loop isn't accidentally
+	    #        broken:
+	    #new_libs="$deplib $new_libs"
+	    # Pragmatically, this seems to cause very few problems in
+	    # practice:
+	    case $deplib in
+	    -L*) new_libs="$deplib $new_libs" ;;
+	    -R*) ;;
+	    *)
+	      # And here is the reason: when a library appears more
+	      # than once as an explicit dependence of a library, or
+	      # is implicitly linked in more than once by the
+	      # compiler, it is considered special, and multiple
+	      # occurrences thereof are not removed.  Compare this
+	      # with having the same library being listed as a
+	      # dependency of multiple other libraries: in this case,
+	      # we know (pedantically, we assume) the library does not
+	      # need to be listed more than once, so we keep only the
+	      # last copy.  This is not always right, but it is rare
+	      # enough that we require users that really mean to play
+	      # such unportable linking tricks to link the library
+	      # using -Wl,-lname, so that libtool does not consider it
+	      # for duplicate removal.
+	      case " $specialdeplibs " in
+	      *" $deplib "*) new_libs="$deplib $new_libs" ;;
+	      *)
+		case " $new_libs " in
+		*" $deplib "*) ;;
+		*) new_libs="$deplib $new_libs" ;;
+		esac
+		;;
+	      esac
+	      ;;
+	    esac
+	  done
+	  tmp_libs=
+	  for deplib in $new_libs; do
+	    case $deplib in
+	    -L*)
+	      case " $tmp_libs " in
+	      *" $deplib "*) ;;
+	      *) func_append tmp_libs " $deplib" ;;
+	      esac
+	      ;;
+	    *) func_append tmp_libs " $deplib" ;;
+	    esac
+	  done
+	  eval $var=\"$tmp_libs\"
+	done # for var
+      fi
+      # Last step: remove runtime libs from dependency_libs
+      # (they stay in deplibs)
+      tmp_libs=
+      for i in $dependency_libs ; do
+	case " $predeps $postdeps $compiler_lib_search_path " in
+	*" $i "*)
+	  i=""
+	  ;;
+	esac
+	if test -n "$i" ; then
+	  func_append tmp_libs " $i"
+	fi
+      done
+      dependency_libs=$tmp_libs
+    done # for pass
+    if test "$linkmode" = prog; then
+      dlfiles="$newdlfiles"
+    fi
+    if test "$linkmode" = prog || test "$linkmode" = lib; then
+      dlprefiles="$newdlprefiles"
+    fi
+
+    case $linkmode in
+    oldlib)
+      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+	func_warning "\`-dlopen' is ignored for archives"
+      fi
+
+      case " $deplibs" in
+      *\ -l* | *\ -L*)
+	func_warning "\`-l' and \`-L' are ignored for archives" ;;
+      esac
+
+      test -n "$rpath" && \
+	func_warning "\`-rpath' is ignored for archives"
+
+      test -n "$xrpath" && \
+	func_warning "\`-R' is ignored for archives"
+
+      test -n "$vinfo" && \
+	func_warning "\`-version-info/-version-number' is ignored for archives"
+
+      test -n "$release" && \
+	func_warning "\`-release' is ignored for archives"
+
+      test -n "$export_symbols$export_symbols_regex" && \
+	func_warning "\`-export-symbols' is ignored for archives"
+
+      # Now set the variables for building old libraries.
+      build_libtool_libs=no
+      oldlibs="$output"
+      func_append objs "$old_deplibs"
+      ;;
+
+    lib)
+      # Make sure we only generate libraries of the form `libNAME.la'.
+      case $outputname in
+      lib*)
+	func_stripname 'lib' '.la' "$outputname"
+	name=$func_stripname_result
+	eval shared_ext=\"$shrext_cmds\"
+	eval libname=\"$libname_spec\"
+	;;
+      *)
+	test "$module" = no && \
+	  func_fatal_help "libtool library \`$output' must begin with \`lib'"
+
+	if test "$need_lib_prefix" != no; then
+	  # Add the "lib" prefix for modules if required
+	  func_stripname '' '.la' "$outputname"
+	  name=$func_stripname_result
+	  eval shared_ext=\"$shrext_cmds\"
+	  eval libname=\"$libname_spec\"
+	else
+	  func_stripname '' '.la' "$outputname"
+	  libname=$func_stripname_result
+	fi
+	;;
+      esac
+
+      if test -n "$objs"; then
+	if test "$deplibs_check_method" != pass_all; then
+	  func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs"
+	else
+	  echo
+	  $ECHO "*** Warning: Linking the shared library $output against the non-libtool"
+	  $ECHO "*** objects $objs is not portable!"
+	  func_append libobjs " $objs"
+	fi
+      fi
+
+      test "$dlself" != no && \
+	func_warning "\`-dlopen self' is ignored for libtool libraries"
+
+      set dummy $rpath
+      shift
+      test "$#" -gt 1 && \
+	func_warning "ignoring multiple \`-rpath's for a libtool library"
+
+      install_libdir="$1"
+
+      oldlibs=
+      if test -z "$rpath"; then
+	if test "$build_libtool_libs" = yes; then
+	  # Building a libtool convenience library.
+	  # Some compilers have problems with a `.al' extension so
+	  # convenience libraries should have the same extension an
+	  # archive normally would.
+	  oldlibs="$output_objdir/$libname.$libext $oldlibs"
+	  build_libtool_libs=convenience
+	  build_old_libs=yes
+	fi
+
+	test -n "$vinfo" && \
+	  func_warning "\`-version-info/-version-number' is ignored for convenience libraries"
+
+	test -n "$release" && \
+	  func_warning "\`-release' is ignored for convenience libraries"
+      else
+
+	# Parse the version information argument.
+	save_ifs="$IFS"; IFS=':'
+	set dummy $vinfo 0 0 0
+	shift
+	IFS="$save_ifs"
+
+	test -n "$7" && \
+	  func_fatal_help "too many parameters to \`-version-info'"
+
+	# convert absolute version numbers to libtool ages
+	# this retains compatibility with .la files and attempts
+	# to make the code below a bit more comprehensible
+
+	case $vinfo_number in
+	yes)
+	  number_major="$1"
+	  number_minor="$2"
+	  number_revision="$3"
+	  #
+	  # There are really only two kinds -- those that
+	  # use the current revision as the major version
+	  # and those that subtract age and use age as
+	  # a minor version.  But, then there is irix
+	  # which has an extra 1 added just for fun
+	  #
+	  case $version_type in
+	  # correct linux to gnu/linux during the next big refactor
+	  darwin|linux|osf|windows|none)
+	    func_arith $number_major + $number_minor
+	    current=$func_arith_result
+	    age="$number_minor"
+	    revision="$number_revision"
+	    ;;
+	  freebsd-aout|freebsd-elf|qnx|sunos)
+	    current="$number_major"
+	    revision="$number_minor"
+	    age="0"
+	    ;;
+	  irix|nonstopux)
+	    func_arith $number_major + $number_minor
+	    current=$func_arith_result
+	    age="$number_minor"
+	    revision="$number_minor"
+	    lt_irix_increment=no
+	    ;;
+	  *)
+	    func_fatal_configuration "$modename: unknown library version type \`$version_type'"
+	    ;;
+	  esac
+	  ;;
+	no)
+	  current="$1"
+	  revision="$2"
+	  age="$3"
+	  ;;
+	esac
+
+	# Check that each of the things are valid numbers.
+	case $current in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  func_error "CURRENT \`$current' must be a nonnegative integer"
+	  func_fatal_error "\`$vinfo' is not valid version information"
+	  ;;
+	esac
+
+	case $revision in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  func_error "REVISION \`$revision' must be a nonnegative integer"
+	  func_fatal_error "\`$vinfo' is not valid version information"
+	  ;;
+	esac
+
+	case $age in
+	0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+	*)
+	  func_error "AGE \`$age' must be a nonnegative integer"
+	  func_fatal_error "\`$vinfo' is not valid version information"
+	  ;;
+	esac
+
+	if test "$age" -gt "$current"; then
+	  func_error "AGE \`$age' is greater than the current interface number \`$current'"
+	  func_fatal_error "\`$vinfo' is not valid version information"
+	fi
+
+	# Calculate the version variables.
+	major=
+	versuffix=
+	verstring=
+	case $version_type in
+	none) ;;
+
+	darwin)
+	  # Like Linux, but with the current version available in
+	  # verstring for coding it into the library header
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix="$major.$age.$revision"
+	  # Darwin ld doesn't like 0 for these options...
+	  func_arith $current + 1
+	  minor_current=$func_arith_result
+	  xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision"
+	  verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+	  ;;
+
+	freebsd-aout)
+	  major=".$current"
+	  versuffix=".$current.$revision";
+	  ;;
+
+	freebsd-elf)
+	  major=".$current"
+	  versuffix=".$current"
+	  ;;
+
+	irix | nonstopux)
+	  if test "X$lt_irix_increment" = "Xno"; then
+	    func_arith $current - $age
+	  else
+	    func_arith $current - $age + 1
+	  fi
+	  major=$func_arith_result
+
+	  case $version_type in
+	    nonstopux) verstring_prefix=nonstopux ;;
+	    *)         verstring_prefix=sgi ;;
+	  esac
+	  verstring="$verstring_prefix$major.$revision"
+
+	  # Add in all the interfaces that we are compatible with.
+	  loop=$revision
+	  while test "$loop" -ne 0; do
+	    func_arith $revision - $loop
+	    iface=$func_arith_result
+	    func_arith $loop - 1
+	    loop=$func_arith_result
+	    verstring="$verstring_prefix$major.$iface:$verstring"
+	  done
+
+	  # Before this point, $major must not contain `.'.
+	  major=.$major
+	  versuffix="$major.$revision"
+	  ;;
+
+	linux) # correct to gnu/linux during the next big refactor
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix="$major.$age.$revision"
+	  ;;
+
+	osf)
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix=".$current.$age.$revision"
+	  verstring="$current.$age.$revision"
+
+	  # Add in all the interfaces that we are compatible with.
+	  loop=$age
+	  while test "$loop" -ne 0; do
+	    func_arith $current - $loop
+	    iface=$func_arith_result
+	    func_arith $loop - 1
+	    loop=$func_arith_result
+	    verstring="$verstring:${iface}.0"
+	  done
+
+	  # Make executables depend on our current version.
+	  func_append verstring ":${current}.0"
+	  ;;
+
+	qnx)
+	  major=".$current"
+	  versuffix=".$current"
+	  ;;
+
+	sunos)
+	  major=".$current"
+	  versuffix=".$current.$revision"
+	  ;;
+
+	windows)
+	  # Use '-' rather than '.', since we only want one
+	  # extension on DOS 8.3 filesystems.
+	  func_arith $current - $age
+	  major=$func_arith_result
+	  versuffix="-$major"
+	  ;;
+
+	*)
+	  func_fatal_configuration "unknown library version type \`$version_type'"
+	  ;;
+	esac
+
+	# Clear the version info if we defaulted, and they specified a release.
+	if test -z "$vinfo" && test -n "$release"; then
+	  major=
+	  case $version_type in
+	  darwin)
+	    # we can't check for "0.0" in archive_cmds due to quoting
+	    # problems, so we reset it completely
+	    verstring=
+	    ;;
+	  *)
+	    verstring="0.0"
+	    ;;
+	  esac
+	  if test "$need_version" = no; then
+	    versuffix=
+	  else
+	    versuffix=".0.0"
+	  fi
+	fi
+
+	# Remove version info from name if versioning should be avoided
+	if test "$avoid_version" = yes && test "$need_version" = no; then
+	  major=
+	  versuffix=
+	  verstring=""
+	fi
+
+	# Check to see if the archive will have undefined symbols.
+	if test "$allow_undefined" = yes; then
+	  if test "$allow_undefined_flag" = unsupported; then
+	    func_warning "undefined symbols not allowed in $host shared libraries"
+	    build_libtool_libs=no
+	    build_old_libs=yes
+	  fi
+	else
+	  # Don't allow undefined symbols.
+	  allow_undefined_flag="$no_undefined_flag"
+	fi
+
+      fi
+
+      func_generate_dlsyms "$libname" "$libname" "yes"
+      func_append libobjs " $symfileobj"
+      test "X$libobjs" = "X " && libobjs=
+
+      if test "$opt_mode" != relink; then
+	# Remove our outputs, but don't remove object files since they
+	# may have been created when compiling PIC objects.
+	removelist=
+	tempremovelist=`$ECHO "$output_objdir/*"`
+	for p in $tempremovelist; do
+	  case $p in
+	    *.$objext | *.gcno)
+	       ;;
+	    $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*)
+	       if test "X$precious_files_regex" != "X"; then
+		 if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
+		 then
+		   continue
+		 fi
+	       fi
+	       func_append removelist " $p"
+	       ;;
+	    *) ;;
+	  esac
+	done
+	test -n "$removelist" && \
+	  func_show_eval "${RM}r \$removelist"
+      fi
+
+      # Now set the variables for building old libraries.
+      if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
+	func_append oldlibs " $output_objdir/$libname.$libext"
+
+	# Transform .lo files to .o files.
+	oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP`
+      fi
+
+      # Eliminate all temporary directories.
+      #for path in $notinst_path; do
+      #	lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"`
+      #	deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"`
+      #	dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"`
+      #done
+
+      if test -n "$xrpath"; then
+	# If the user specified any rpath flags, then add them.
+	temp_xrpath=
+	for libdir in $xrpath; do
+	  func_replace_sysroot "$libdir"
+	  func_append temp_xrpath " -R$func_replace_sysroot_result"
+	  case "$finalize_rpath " in
+	  *" $libdir "*) ;;
+	  *) func_append finalize_rpath " $libdir" ;;
+	  esac
+	done
+	if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then
+	  dependency_libs="$temp_xrpath $dependency_libs"
+	fi
+      fi
+
+      # Make sure dlfiles contains only unique files that won't be dlpreopened
+      old_dlfiles="$dlfiles"
+      dlfiles=
+      for lib in $old_dlfiles; do
+	case " $dlprefiles $dlfiles " in
+	*" $lib "*) ;;
+	*) func_append dlfiles " $lib" ;;
+	esac
+      done
+
+      # Make sure dlprefiles contains only unique files
+      old_dlprefiles="$dlprefiles"
+      dlprefiles=
+      for lib in $old_dlprefiles; do
+	case "$dlprefiles " in
+	*" $lib "*) ;;
+	*) func_append dlprefiles " $lib" ;;
+	esac
+      done
+
+      if test "$build_libtool_libs" = yes; then
+	if test -n "$rpath"; then
+	  case $host in
+	  *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*)
+	    # these systems don't actually have a c library (as such)!
+	    ;;
+	  *-*-rhapsody* | *-*-darwin1.[012])
+	    # Rhapsody C library is in the System framework
+	    func_append deplibs " System.ltframework"
+	    ;;
+	  *-*-netbsd*)
+	    # Don't link with libc until the a.out ld.so is fixed.
+	    ;;
+	  *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+	    # Do not include libc due to us having libc/libc_r.
+	    ;;
+	  *-*-sco3.2v5* | *-*-sco5v6*)
+	    # Causes problems with __ctype
+	    ;;
+	  *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+	    # Compiler inserts libc in the correct place for threads to work
+	    ;;
+	  *)
+	    # Add libc to deplibs on all other systems if necessary.
+	    if test "$build_libtool_need_lc" = "yes"; then
+	      func_append deplibs " -lc"
+	    fi
+	    ;;
+	  esac
+	fi
+
+	# Transform deplibs into only deplibs that can be linked in shared.
+	name_save=$name
+	libname_save=$libname
+	release_save=$release
+	versuffix_save=$versuffix
+	major_save=$major
+	# I'm not sure if I'm treating the release correctly.  I think
+	# release should show up in the -l (ie -lgmp5) so we don't want to
+	# add it in twice.  Is that correct?
+	release=""
+	versuffix=""
+	major=""
+	newdeplibs=
+	droppeddeps=no
+	case $deplibs_check_method in
+	pass_all)
+	  # Don't check for shared/static.  Everything works.
+	  # This might be a little naive.  We might want to check
+	  # whether the library exists or not.  But this is on
+	  # osf3 & osf4 and I'm not really sure... Just
+	  # implementing what was already the behavior.
+	  newdeplibs=$deplibs
+	  ;;
+	test_compile)
+	  # This code stresses the "libraries are programs" paradigm to its
+	  # limits. Maybe even breaks it.  We compile a program, linking it
+	  # against the deplibs as a proxy for the library.  Then we can check
+	  # whether they linked in statically or dynamically with ldd.
+	  $opt_dry_run || $RM conftest.c
+	  cat > conftest.c <<EOF
+	  int main() { return 0; }
+EOF
+	  $opt_dry_run || $RM conftest
+	  if $LTCC $LTCFLAGS -o conftest conftest.c $deplibs; then
+	    ldd_output=`ldd conftest`
+	    for i in $deplibs; do
+	      case $i in
+	      -l*)
+		func_stripname -l '' "$i"
+		name=$func_stripname_result
+		if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		  case " $predeps $postdeps " in
+		  *" $i "*)
+		    func_append newdeplibs " $i"
+		    i=""
+		    ;;
+		  esac
+		fi
+		if test -n "$i" ; then
+		  libname=`eval "\\$ECHO \"$libname_spec\""`
+		  deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+		  set dummy $deplib_matches; shift
+		  deplib_match=$1
+		  if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+		    func_append newdeplibs " $i"
+		  else
+		    droppeddeps=yes
+		    echo
+		    $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+		    echo "*** I have the capability to make that library automatically link in when"
+		    echo "*** you link to this library.  But I can only do this if you have a"
+		    echo "*** shared version of the library, which I believe you do not have"
+		    echo "*** because a test_compile did reveal that the linker did not use it for"
+		    echo "*** its dynamic dependency list that programs get resolved with at runtime."
+		  fi
+		fi
+		;;
+	      *)
+		func_append newdeplibs " $i"
+		;;
+	      esac
+	    done
+	  else
+	    # Error occurred in the first compile.  Let's try to salvage
+	    # the situation: Compile a separate program for each library.
+	    for i in $deplibs; do
+	      case $i in
+	      -l*)
+		func_stripname -l '' "$i"
+		name=$func_stripname_result
+		$opt_dry_run || $RM conftest
+		if $LTCC $LTCFLAGS -o conftest conftest.c $i; then
+		  ldd_output=`ldd conftest`
+		  if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		    case " $predeps $postdeps " in
+		    *" $i "*)
+		      func_append newdeplibs " $i"
+		      i=""
+		      ;;
+		    esac
+		  fi
+		  if test -n "$i" ; then
+		    libname=`eval "\\$ECHO \"$libname_spec\""`
+		    deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+		    set dummy $deplib_matches; shift
+		    deplib_match=$1
+		    if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+		      func_append newdeplibs " $i"
+		    else
+		      droppeddeps=yes
+		      echo
+		      $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+		      echo "*** I have the capability to make that library automatically link in when"
+		      echo "*** you link to this library.  But I can only do this if you have a"
+		      echo "*** shared version of the library, which you do not appear to have"
+		      echo "*** because a test_compile did reveal that the linker did not use this one"
+		      echo "*** as a dynamic dependency that programs can get resolved with at runtime."
+		    fi
+		  fi
+		else
+		  droppeddeps=yes
+		  echo
+		  $ECHO "*** Warning!  Library $i is needed by this library but I was not able to"
+		  echo "*** make it link in!  You will probably need to install it or some"
+		  echo "*** library that it depends on before this library will be fully"
+		  echo "*** functional.  Installing it before continuing would be even better."
+		fi
+		;;
+	      *)
+		func_append newdeplibs " $i"
+		;;
+	      esac
+	    done
+	  fi
+	  ;;
+	file_magic*)
+	  set dummy $deplibs_check_method; shift
+	  file_magic_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+	  for a_deplib in $deplibs; do
+	    case $a_deplib in
+	    -l*)
+	      func_stripname -l '' "$a_deplib"
+	      name=$func_stripname_result
+	      if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		case " $predeps $postdeps " in
+		*" $a_deplib "*)
+		  func_append newdeplibs " $a_deplib"
+		  a_deplib=""
+		  ;;
+		esac
+	      fi
+	      if test -n "$a_deplib" ; then
+		libname=`eval "\\$ECHO \"$libname_spec\""`
+		if test -n "$file_magic_glob"; then
+		  libnameglob=`func_echo_all "$libname" | $SED -e $file_magic_glob`
+		else
+		  libnameglob=$libname
+		fi
+		test "$want_nocaseglob" = yes && nocaseglob=`shopt -p nocaseglob`
+		for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+		  if test "$want_nocaseglob" = yes; then
+		    shopt -s nocaseglob
+		    potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
+		    $nocaseglob
+		  else
+		    potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
+		  fi
+		  for potent_lib in $potential_libs; do
+		      # Follow soft links.
+		      if ls -lLd "$potent_lib" 2>/dev/null |
+			 $GREP " -> " >/dev/null; then
+			continue
+		      fi
+		      # The statement above tries to avoid entering an
+		      # endless loop below, in case of cyclic links.
+		      # We might still enter an endless loop, since a link
+		      # loop can be closed while we follow links,
+		      # but so what?
+		      potlib="$potent_lib"
+		      while test -h "$potlib" 2>/dev/null; do
+			potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'`
+			case $potliblink in
+			[\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
+			*) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";;
+			esac
+		      done
+		      if eval $file_magic_cmd \"\$potlib\" 2>/dev/null |
+			 $SED -e 10q |
+			 $EGREP "$file_magic_regex" > /dev/null; then
+			func_append newdeplibs " $a_deplib"
+			a_deplib=""
+			break 2
+		      fi
+		  done
+		done
+	      fi
+	      if test -n "$a_deplib" ; then
+		droppeddeps=yes
+		echo
+		$ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+		echo "*** I have the capability to make that library automatically link in when"
+		echo "*** you link to this library.  But I can only do this if you have a"
+		echo "*** shared version of the library, which you do not appear to have"
+		echo "*** because I did check the linker path looking for a file starting"
+		if test -z "$potlib" ; then
+		  $ECHO "*** with $libname but no candidates were found. (...for file magic test)"
+		else
+		  $ECHO "*** with $libname and none of the candidates passed a file format test"
+		  $ECHO "*** using a file magic. Last file checked: $potlib"
+		fi
+	      fi
+	      ;;
+	    *)
+	      # Add a -L argument.
+	      func_append newdeplibs " $a_deplib"
+	      ;;
+	    esac
+	  done # Gone through all deplibs.
+	  ;;
+	match_pattern*)
+	  set dummy $deplibs_check_method; shift
+	  match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+	  for a_deplib in $deplibs; do
+	    case $a_deplib in
+	    -l*)
+	      func_stripname -l '' "$a_deplib"
+	      name=$func_stripname_result
+	      if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+		case " $predeps $postdeps " in
+		*" $a_deplib "*)
+		  func_append newdeplibs " $a_deplib"
+		  a_deplib=""
+		  ;;
+		esac
+	      fi
+	      if test -n "$a_deplib" ; then
+		libname=`eval "\\$ECHO \"$libname_spec\""`
+		for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+		  potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+		  for potent_lib in $potential_libs; do
+		    potlib="$potent_lib" # see symlink-check above in file_magic test
+		    if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \
+		       $EGREP "$match_pattern_regex" > /dev/null; then
+		      func_append newdeplibs " $a_deplib"
+		      a_deplib=""
+		      break 2
+		    fi
+		  done
+		done
+	      fi
+	      if test -n "$a_deplib" ; then
+		droppeddeps=yes
+		echo
+		$ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+		echo "*** I have the capability to make that library automatically link in when"
+		echo "*** you link to this library.  But I can only do this if you have a"
+		echo "*** shared version of the library, which you do not appear to have"
+		echo "*** because I did check the linker path looking for a file starting"
+		if test -z "$potlib" ; then
+		  $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)"
+		else
+		  $ECHO "*** with $libname and none of the candidates passed a file format test"
+		  $ECHO "*** using a regex pattern. Last file checked: $potlib"
+		fi
+	      fi
+	      ;;
+	    *)
+	      # Add a -L argument.
+	      func_append newdeplibs " $a_deplib"
+	      ;;
+	    esac
+	  done # Gone through all deplibs.
+	  ;;
+	none | unknown | *)
+	  newdeplibs=""
+	  tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'`
+	  if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+	    for i in $predeps $postdeps ; do
+	      # can't use Xsed below, because $i might contain '/'
+	      tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"`
+	    done
+	  fi
+	  case $tmp_deplibs in
+	  *[!\	\ ]*)
+	    echo
+	    if test "X$deplibs_check_method" = "Xnone"; then
+	      echo "*** Warning: inter-library dependencies are not supported in this platform."
+	    else
+	      echo "*** Warning: inter-library dependencies are not known to be supported."
+	    fi
+	    echo "*** All declared inter-library dependencies are being dropped."
+	    droppeddeps=yes
+	    ;;
+	  esac
+	  ;;
+	esac
+	versuffix=$versuffix_save
+	major=$major_save
+	release=$release_save
+	libname=$libname_save
+	name=$name_save
+
+	case $host in
+	*-*-rhapsody* | *-*-darwin1.[012])
+	  # On Rhapsody replace the C library with the System framework
+	  newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'`
+	  ;;
+	esac
+
+	if test "$droppeddeps" = yes; then
+	  if test "$module" = yes; then
+	    echo
+	    echo "*** Warning: libtool could not satisfy all declared inter-library"
+	    $ECHO "*** dependencies of module $libname.  Therefore, libtool will create"
+	    echo "*** a static module, that should work as long as the dlopening"
+	    echo "*** application is linked with the -dlopen flag."
+	    if test -z "$global_symbol_pipe"; then
+	      echo
+	      echo "*** However, this would only work if libtool was able to extract symbol"
+	      echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+	      echo "*** not find such a program.  So, this module is probably useless."
+	      echo "*** \`nm' from GNU binutils and a full rebuild may help."
+	    fi
+	    if test "$build_old_libs" = no; then
+	      oldlibs="$output_objdir/$libname.$libext"
+	      build_libtool_libs=module
+	      build_old_libs=yes
+	    else
+	      build_libtool_libs=no
+	    fi
+	  else
+	    echo "*** The inter-library dependencies that have been dropped here will be"
+	    echo "*** automatically added whenever a program is linked with this library"
+	    echo "*** or is declared to -dlopen it."
+
+	    if test "$allow_undefined" = no; then
+	      echo
+	      echo "*** Since this library must not contain undefined symbols,"
+	      echo "*** because either the platform does not support them or"
+	      echo "*** it was explicitly requested with -no-undefined,"
+	      echo "*** libtool will only create a static version of it."
+	      if test "$build_old_libs" = no; then
+		oldlibs="$output_objdir/$libname.$libext"
+		build_libtool_libs=module
+		build_old_libs=yes
+	      else
+		build_libtool_libs=no
+	      fi
+	    fi
+	  fi
+	fi
+	# Done checking deplibs!
+	deplibs=$newdeplibs
+      fi
+      # Time to change all our "foo.ltframework" stuff back to "-framework foo"
+      case $host in
+	*-*-darwin*)
+	  newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	  new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	  deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	  ;;
+      esac
+
+      # move library search paths that coincide with paths to not yet
+      # installed libraries to the beginning of the library search list
+      new_libs=
+      for path in $notinst_path; do
+	case " $new_libs " in
+	*" -L$path/$objdir "*) ;;
+	*)
+	  case " $deplibs " in
+	  *" -L$path/$objdir "*)
+	    func_append new_libs " -L$path/$objdir" ;;
+	  esac
+	  ;;
+	esac
+      done
+      for deplib in $deplibs; do
+	case $deplib in
+	-L*)
+	  case " $new_libs " in
+	  *" $deplib "*) ;;
+	  *) func_append new_libs " $deplib" ;;
+	  esac
+	  ;;
+	*) func_append new_libs " $deplib" ;;
+	esac
+      done
+      deplibs="$new_libs"
+
+      # All the library-specific variables (install_libdir is set above).
+      library_names=
+      old_library=
+      dlname=
+
+      # Test again, we may have decided not to build it any more
+      if test "$build_libtool_libs" = yes; then
+	# Remove ${wl} instances when linking with ld.
+	# FIXME: should test the right _cmds variable.
+	case $archive_cmds in
+	  *\$LD\ *) wl= ;;
+        esac
+	if test "$hardcode_into_libs" = yes; then
+	  # Hardcode the library paths
+	  hardcode_libdirs=
+	  dep_rpath=
+	  rpath="$finalize_rpath"
+	  test "$opt_mode" != relink && rpath="$compile_rpath$rpath"
+	  for libdir in $rpath; do
+	    if test -n "$hardcode_libdir_flag_spec"; then
+	      if test -n "$hardcode_libdir_separator"; then
+		func_replace_sysroot "$libdir"
+		libdir=$func_replace_sysroot_result
+		if test -z "$hardcode_libdirs"; then
+		  hardcode_libdirs="$libdir"
+		else
+		  # Just accumulate the unique libdirs.
+		  case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+		  *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		    ;;
+		  *)
+		    func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+		    ;;
+		  esac
+		fi
+	      else
+		eval flag=\"$hardcode_libdir_flag_spec\"
+		func_append dep_rpath " $flag"
+	      fi
+	    elif test -n "$runpath_var"; then
+	      case "$perm_rpath " in
+	      *" $libdir "*) ;;
+	      *) func_append perm_rpath " $libdir" ;;
+	      esac
+	    fi
+	  done
+	  # Substitute the hardcoded libdirs into the rpath.
+	  if test -n "$hardcode_libdir_separator" &&
+	     test -n "$hardcode_libdirs"; then
+	    libdir="$hardcode_libdirs"
+	    eval "dep_rpath=\"$hardcode_libdir_flag_spec\""
+	  fi
+	  if test -n "$runpath_var" && test -n "$perm_rpath"; then
+	    # We should set the runpath_var.
+	    rpath=
+	    for dir in $perm_rpath; do
+	      func_append rpath "$dir:"
+	    done
+	    eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
+	  fi
+	  test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
+	fi
+
+	shlibpath="$finalize_shlibpath"
+	test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath"
+	if test -n "$shlibpath"; then
+	  eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
+	fi
+
+	# Get the real and link names of the library.
+	eval shared_ext=\"$shrext_cmds\"
+	eval library_names=\"$library_names_spec\"
+	set dummy $library_names
+	shift
+	realname="$1"
+	shift
+
+	if test -n "$soname_spec"; then
+	  eval soname=\"$soname_spec\"
+	else
+	  soname="$realname"
+	fi
+	if test -z "$dlname"; then
+	  dlname=$soname
+	fi
+
+	lib="$output_objdir/$realname"
+	linknames=
+	for link
+	do
+	  func_append linknames " $link"
+	done
+
+	# Use standard objects if they are pic
+	test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+	test "X$libobjs" = "X " && libobjs=
+
+	delfiles=
+	if test -n "$export_symbols" && test -n "$include_expsyms"; then
+	  $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp"
+	  export_symbols="$output_objdir/$libname.uexp"
+	  func_append delfiles " $export_symbols"
+	fi
+
+	orig_export_symbols=
+	case $host_os in
+	cygwin* | mingw* | cegcc*)
+	  if test -n "$export_symbols" && test -z "$export_symbols_regex"; then
+	    # exporting using user supplied symfile
+	    if test "x`$SED 1q $export_symbols`" != xEXPORTS; then
+	      # and it's NOT already a .def file. Must figure out
+	      # which of the given symbols are data symbols and tag
+	      # them as such. So, trigger use of export_symbols_cmds.
+	      # export_symbols gets reassigned inside the "prepare
+	      # the list of exported symbols" if statement, so the
+	      # include_expsyms logic still works.
+	      orig_export_symbols="$export_symbols"
+	      export_symbols=
+	      always_export_symbols=yes
+	    fi
+	  fi
+	  ;;
+	esac
+
+	# Prepare the list of exported symbols
+	if test -z "$export_symbols"; then
+	  if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
+	    func_verbose "generating symbol list for \`$libname.la'"
+	    export_symbols="$output_objdir/$libname.exp"
+	    $opt_dry_run || $RM $export_symbols
+	    cmds=$export_symbols_cmds
+	    save_ifs="$IFS"; IFS='~'
+	    for cmd1 in $cmds; do
+	      IFS="$save_ifs"
+	      # Take the normal branch if the nm_file_list_spec branch
+	      # doesn't work or if tool conversion is not needed.
+	      case $nm_file_list_spec~$to_tool_file_cmd in
+		*~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*)
+		  try_normal_branch=yes
+		  eval cmd=\"$cmd1\"
+		  func_len " $cmd"
+		  len=$func_len_result
+		  ;;
+		*)
+		  try_normal_branch=no
+		  ;;
+	      esac
+	      if test "$try_normal_branch" = yes \
+		 && { test "$len" -lt "$max_cmd_len" \
+		      || test "$max_cmd_len" -le -1; }
+	      then
+		func_show_eval "$cmd" 'exit $?'
+		skipped_export=false
+	      elif test -n "$nm_file_list_spec"; then
+		func_basename "$output"
+		output_la=$func_basename_result
+		save_libobjs=$libobjs
+		save_output=$output
+		output=${output_objdir}/${output_la}.nm
+		func_to_tool_file "$output"
+		libobjs=$nm_file_list_spec$func_to_tool_file_result
+		func_append delfiles " $output"
+		func_verbose "creating $NM input file list: $output"
+		for obj in $save_libobjs; do
+		  func_to_tool_file "$obj"
+		  $ECHO "$func_to_tool_file_result"
+		done > "$output"
+		eval cmd=\"$cmd1\"
+		func_show_eval "$cmd" 'exit $?'
+		output=$save_output
+		libobjs=$save_libobjs
+		skipped_export=false
+	      else
+		# The command line is too long to execute in one step.
+		func_verbose "using reloadable object file for export list..."
+		skipped_export=:
+		# Break out early, otherwise skipped_export may be
+		# set to false by a later but shorter cmd.
+		break
+	      fi
+	    done
+	    IFS="$save_ifs"
+	    if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then
+	      func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+	      func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+	    fi
+	  fi
+	fi
+
+	if test -n "$export_symbols" && test -n "$include_expsyms"; then
+	  tmp_export_symbols="$export_symbols"
+	  test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+	  $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+	fi
+
+	if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then
+	  # The given exports_symbols file has to be filtered, so filter it.
+	  func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+	  # FIXME: $output_objdir/$libname.filter potentially contains lots of
+	  # 's' commands which not all seds can handle. GNU sed should be fine
+	  # though. Also, the filter scales superlinearly with the number of
+	  # global variables. join(1) would be nice here, but unfortunately
+	  # isn't a blessed tool.
+	  $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+	  func_append delfiles " $export_symbols $output_objdir/$libname.filter"
+	  export_symbols=$output_objdir/$libname.def
+	  $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+	fi
+
+	tmp_deplibs=
+	for test_deplib in $deplibs; do
+	  case " $convenience " in
+	  *" $test_deplib "*) ;;
+	  *)
+	    func_append tmp_deplibs " $test_deplib"
+	    ;;
+	  esac
+	done
+	deplibs="$tmp_deplibs"
+
+	if test -n "$convenience"; then
+	  if test -n "$whole_archive_flag_spec" &&
+	    test "$compiler_needs_object" = yes &&
+	    test -z "$libobjs"; then
+	    # extract the archives, so we have objects to list.
+	    # TODO: could optimize this to just extract one archive.
+	    whole_archive_flag_spec=
+	  fi
+	  if test -n "$whole_archive_flag_spec"; then
+	    save_libobjs=$libobjs
+	    eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+	    test "X$libobjs" = "X " && libobjs=
+	  else
+	    gentop="$output_objdir/${outputname}x"
+	    func_append generated " $gentop"
+
+	    func_extract_archives $gentop $convenience
+	    func_append libobjs " $func_extract_archives_result"
+	    test "X$libobjs" = "X " && libobjs=
+	  fi
+	fi
+
+	if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
+	  eval flag=\"$thread_safe_flag_spec\"
+	  func_append linker_flags " $flag"
+	fi
+
+	# Make a backup of the uninstalled library when relinking
+	if test "$opt_mode" = relink; then
+	  $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $?
+	fi
+
+	# Do each of the archive commands.
+	if test "$module" = yes && test -n "$module_cmds" ; then
+	  if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+	    eval test_cmds=\"$module_expsym_cmds\"
+	    cmds=$module_expsym_cmds
+	  else
+	    eval test_cmds=\"$module_cmds\"
+	    cmds=$module_cmds
+	  fi
+	else
+	  if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+	    eval test_cmds=\"$archive_expsym_cmds\"
+	    cmds=$archive_expsym_cmds
+	  else
+	    eval test_cmds=\"$archive_cmds\"
+	    cmds=$archive_cmds
+	  fi
+	fi
+
+	if test "X$skipped_export" != "X:" &&
+	   func_len " $test_cmds" &&
+	   len=$func_len_result &&
+	   test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+	  :
+	else
+	  # The command line is too long to link in one step, link piecewise
+	  # or, if using GNU ld and skipped_export is not :, use a linker
+	  # script.
+
+	  # Save the value of $output and $libobjs because we want to
+	  # use them later.  If we have whole_archive_flag_spec, we
+	  # want to use save_libobjs as it was before
+	  # whole_archive_flag_spec was expanded, because we can't
+	  # assume the linker understands whole_archive_flag_spec.
+	  # This may have to be revisited, in case too many
+	  # convenience libraries get linked in and end up exceeding
+	  # the spec.
+	  if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
+	    save_libobjs=$libobjs
+	  fi
+	  save_output=$output
+	  func_basename "$output"
+	  output_la=$func_basename_result
+
+	  # Clear the reloadable object creation command queue and
+	  # initialize k to one.
+	  test_cmds=
+	  concat_cmds=
+	  objlist=
+	  last_robj=
+	  k=1
+
+	  if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then
+	    output=${output_objdir}/${output_la}.lnkscript
+	    func_verbose "creating GNU ld script: $output"
+	    echo 'INPUT (' > $output
+	    for obj in $save_libobjs
+	    do
+	      func_to_tool_file "$obj"
+	      $ECHO "$func_to_tool_file_result" >> $output
+	    done
+	    echo ')' >> $output
+	    func_append delfiles " $output"
+	    func_to_tool_file "$output"
+	    output=$func_to_tool_file_result
+	  elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then
+	    output=${output_objdir}/${output_la}.lnk
+	    func_verbose "creating linker input file list: $output"
+	    : > $output
+	    set x $save_libobjs
+	    shift
+	    firstobj=
+	    if test "$compiler_needs_object" = yes; then
+	      firstobj="$1 "
+	      shift
+	    fi
+	    for obj
+	    do
+	      func_to_tool_file "$obj"
+	      $ECHO "$func_to_tool_file_result" >> $output
+	    done
+	    func_append delfiles " $output"
+	    func_to_tool_file "$output"
+	    output=$firstobj\"$file_list_spec$func_to_tool_file_result\"
+	  else
+	    if test -n "$save_libobjs"; then
+	      func_verbose "creating reloadable object files..."
+	      output=$output_objdir/$output_la-${k}.$objext
+	      eval test_cmds=\"$reload_cmds\"
+	      func_len " $test_cmds"
+	      len0=$func_len_result
+	      len=$len0
+
+	      # Loop over the list of objects to be linked.
+	      for obj in $save_libobjs
+	      do
+		func_len " $obj"
+		func_arith $len + $func_len_result
+		len=$func_arith_result
+		if test "X$objlist" = X ||
+		   test "$len" -lt "$max_cmd_len"; then
+		  func_append objlist " $obj"
+		else
+		  # The command $test_cmds is almost too long, add a
+		  # command to the queue.
+		  if test "$k" -eq 1 ; then
+		    # The first file doesn't have a previous command to add.
+		    reload_objs=$objlist
+		    eval concat_cmds=\"$reload_cmds\"
+		  else
+		    # All subsequent reloadable object files will link in
+		    # the last one created.
+		    reload_objs="$objlist $last_robj"
+		    eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\"
+		  fi
+		  last_robj=$output_objdir/$output_la-${k}.$objext
+		  func_arith $k + 1
+		  k=$func_arith_result
+		  output=$output_objdir/$output_la-${k}.$objext
+		  objlist=" $obj"
+		  func_len " $last_robj"
+		  func_arith $len0 + $func_len_result
+		  len=$func_arith_result
+		fi
+	      done
+	      # Handle the remaining objects by creating one last
+	      # reloadable object file.  All subsequent reloadable object
+	      # files will link in the last one created.
+	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	      reload_objs="$objlist $last_robj"
+	      eval concat_cmds=\"\${concat_cmds}$reload_cmds\"
+	      if test -n "$last_robj"; then
+	        eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\"
+	      fi
+	      func_append delfiles " $output"
+
+	    else
+	      output=
+	    fi
+
+	    if ${skipped_export-false}; then
+	      func_verbose "generating symbol list for \`$libname.la'"
+	      export_symbols="$output_objdir/$libname.exp"
+	      $opt_dry_run || $RM $export_symbols
+	      libobjs=$output
+	      # Append the command to create the export file.
+	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	      eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\"
+	      if test -n "$last_robj"; then
+		eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
+	      fi
+	    fi
+
+	    test -n "$save_libobjs" &&
+	      func_verbose "creating a temporary reloadable object file: $output"
+
+	    # Loop through the commands generated above and execute them.
+	    save_ifs="$IFS"; IFS='~'
+	    for cmd in $concat_cmds; do
+	      IFS="$save_ifs"
+	      $opt_silent || {
+		  func_quote_for_expand "$cmd"
+		  eval "func_echo $func_quote_for_expand_result"
+	      }
+	      $opt_dry_run || eval "$cmd" || {
+		lt_exit=$?
+
+		# Restore the uninstalled library and exit
+		if test "$opt_mode" = relink; then
+		  ( cd "$output_objdir" && \
+		    $RM "${realname}T" && \
+		    $MV "${realname}U" "$realname" )
+		fi
+
+		exit $lt_exit
+	      }
+	    done
+	    IFS="$save_ifs"
+
+	    if test -n "$export_symbols_regex" && ${skipped_export-false}; then
+	      func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+	      func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+	    fi
+	  fi
+
+          if ${skipped_export-false}; then
+	    if test -n "$export_symbols" && test -n "$include_expsyms"; then
+	      tmp_export_symbols="$export_symbols"
+	      test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+	      $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+	    fi
+
+	    if test -n "$orig_export_symbols"; then
+	      # The given exports_symbols file has to be filtered, so filter it.
+	      func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+	      # FIXME: $output_objdir/$libname.filter potentially contains lots of
+	      # 's' commands which not all seds can handle. GNU sed should be fine
+	      # though. Also, the filter scales superlinearly with the number of
+	      # global variables. join(1) would be nice here, but unfortunately
+	      # isn't a blessed tool.
+	      $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+	      func_append delfiles " $export_symbols $output_objdir/$libname.filter"
+	      export_symbols=$output_objdir/$libname.def
+	      $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+	    fi
+	  fi
+
+	  libobjs=$output
+	  # Restore the value of output.
+	  output=$save_output
+
+	  if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
+	    eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+	    test "X$libobjs" = "X " && libobjs=
+	  fi
+	  # Expand the library linking commands again to reset the
+	  # value of $libobjs for piecewise linking.
+
+	  # Do each of the archive commands.
+	  if test "$module" = yes && test -n "$module_cmds" ; then
+	    if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+	      cmds=$module_expsym_cmds
+	    else
+	      cmds=$module_cmds
+	    fi
+	  else
+	    if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+	      cmds=$archive_expsym_cmds
+	    else
+	      cmds=$archive_cmds
+	    fi
+	  fi
+	fi
+
+	if test -n "$delfiles"; then
+	  # Append the command to remove temporary files to $cmds.
+	  eval cmds=\"\$cmds~\$RM $delfiles\"
+	fi
+
+	# Add any objects from preloaded convenience libraries
+	if test -n "$dlprefiles"; then
+	  gentop="$output_objdir/${outputname}x"
+	  func_append generated " $gentop"
+
+	  func_extract_archives $gentop $dlprefiles
+	  func_append libobjs " $func_extract_archives_result"
+	  test "X$libobjs" = "X " && libobjs=
+	fi
+
+	save_ifs="$IFS"; IFS='~'
+	for cmd in $cmds; do
+	  IFS="$save_ifs"
+	  eval cmd=\"$cmd\"
+	  $opt_silent || {
+	    func_quote_for_expand "$cmd"
+	    eval "func_echo $func_quote_for_expand_result"
+	  }
+	  $opt_dry_run || eval "$cmd" || {
+	    lt_exit=$?
+
+	    # Restore the uninstalled library and exit
+	    if test "$opt_mode" = relink; then
+	      ( cd "$output_objdir" && \
+	        $RM "${realname}T" && \
+		$MV "${realname}U" "$realname" )
+	    fi
+
+	    exit $lt_exit
+	  }
+	done
+	IFS="$save_ifs"
+
+	# Restore the uninstalled library and exit
+	if test "$opt_mode" = relink; then
+	  $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $?
+
+	  if test -n "$convenience"; then
+	    if test -z "$whole_archive_flag_spec"; then
+	      func_show_eval '${RM}r "$gentop"'
+	    fi
+	  fi
+
+	  exit $EXIT_SUCCESS
+	fi
+
+	# Create links to the real library.
+	for linkname in $linknames; do
+	  if test "$realname" != "$linkname"; then
+	    func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?'
+	  fi
+	done
+
+	# If -module or -export-dynamic was specified, set the dlname.
+	if test "$module" = yes || test "$export_dynamic" = yes; then
+	  # On all known operating systems, these are identical.
+	  dlname="$soname"
+	fi
+      fi
+      ;;
+
+    obj)
+      if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+	func_warning "\`-dlopen' is ignored for objects"
+      fi
+
+      case " $deplibs" in
+      *\ -l* | *\ -L*)
+	func_warning "\`-l' and \`-L' are ignored for objects" ;;
+      esac
+
+      test -n "$rpath" && \
+	func_warning "\`-rpath' is ignored for objects"
+
+      test -n "$xrpath" && \
+	func_warning "\`-R' is ignored for objects"
+
+      test -n "$vinfo" && \
+	func_warning "\`-version-info' is ignored for objects"
+
+      test -n "$release" && \
+	func_warning "\`-release' is ignored for objects"
+
+      case $output in
+      *.lo)
+	test -n "$objs$old_deplibs" && \
+	  func_fatal_error "cannot build library object \`$output' from non-libtool objects"
+
+	libobj=$output
+	func_lo2o "$libobj"
+	obj=$func_lo2o_result
+	;;
+      *)
+	libobj=
+	obj="$output"
+	;;
+      esac
+
+      # Delete the old objects.
+      $opt_dry_run || $RM $obj $libobj
+
+      # Objects from convenience libraries.  This assumes
+      # single-version convenience libraries.  Whenever we create
+      # different ones for PIC/non-PIC, this we'll have to duplicate
+      # the extraction.
+      reload_conv_objs=
+      gentop=
+      # reload_cmds runs $LD directly, so let us get rid of
+      # -Wl from whole_archive_flag_spec and hope we can get by with
+      # turning comma into space..
+      wl=
+
+      if test -n "$convenience"; then
+	if test -n "$whole_archive_flag_spec"; then
+	  eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\"
+	  reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'`
+	else
+	  gentop="$output_objdir/${obj}x"
+	  func_append generated " $gentop"
+
+	  func_extract_archives $gentop $convenience
+	  reload_conv_objs="$reload_objs $func_extract_archives_result"
+	fi
+      fi
+
+      # If we're not building shared, we need to use non_pic_objs
+      test "$build_libtool_libs" != yes && libobjs="$non_pic_objects"
+
+      # Create the old-style object.
+      reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
+
+      output="$obj"
+      func_execute_cmds "$reload_cmds" 'exit $?'
+
+      # Exit if we aren't doing a library object file.
+      if test -z "$libobj"; then
+	if test -n "$gentop"; then
+	  func_show_eval '${RM}r "$gentop"'
+	fi
+
+	exit $EXIT_SUCCESS
+      fi
+
+      if test "$build_libtool_libs" != yes; then
+	if test -n "$gentop"; then
+	  func_show_eval '${RM}r "$gentop"'
+	fi
+
+	# Create an invalid libtool object if no PIC, so that we don't
+	# accidentally link it into a program.
+	# $show "echo timestamp > $libobj"
+	# $opt_dry_run || eval "echo timestamp > $libobj" || exit $?
+	exit $EXIT_SUCCESS
+      fi
+
+      if test -n "$pic_flag" || test "$pic_mode" != default; then
+	# Only do commands if we really have different PIC objects.
+	reload_objs="$libobjs $reload_conv_objs"
+	output="$libobj"
+	func_execute_cmds "$reload_cmds" 'exit $?'
+      fi
+
+      if test -n "$gentop"; then
+	func_show_eval '${RM}r "$gentop"'
+      fi
+
+      exit $EXIT_SUCCESS
+      ;;
+
+    prog)
+      case $host in
+	*cygwin*) func_stripname '' '.exe' "$output"
+	          output=$func_stripname_result.exe;;
+      esac
+      test -n "$vinfo" && \
+	func_warning "\`-version-info' is ignored for programs"
+
+      test -n "$release" && \
+	func_warning "\`-release' is ignored for programs"
+
+      test "$preload" = yes \
+        && test "$dlopen_support" = unknown \
+	&& test "$dlopen_self" = unknown \
+	&& test "$dlopen_self_static" = unknown && \
+	  func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support."
+
+      case $host in
+      *-*-rhapsody* | *-*-darwin1.[012])
+	# On Rhapsody replace the C library is the System framework
+	compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'`
+	finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'`
+	;;
+      esac
+
+      case $host in
+      *-*-darwin*)
+	# Don't allow lazy linking, it breaks C++ global constructors
+	# But is supposedly fixed on 10.4 or later (yay!).
+	if test "$tagname" = CXX ; then
+	  case ${MACOSX_DEPLOYMENT_TARGET-10.0} in
+	    10.[0123])
+	      func_append compile_command " ${wl}-bind_at_load"
+	      func_append finalize_command " ${wl}-bind_at_load"
+	    ;;
+	  esac
+	fi
+	# Time to change all our "foo.ltframework" stuff back to "-framework foo"
+	compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+	;;
+      esac
+
+
+      # move library search paths that coincide with paths to not yet
+      # installed libraries to the beginning of the library search list
+      new_libs=
+      for path in $notinst_path; do
+	case " $new_libs " in
+	*" -L$path/$objdir "*) ;;
+	*)
+	  case " $compile_deplibs " in
+	  *" -L$path/$objdir "*)
+	    func_append new_libs " -L$path/$objdir" ;;
+	  esac
+	  ;;
+	esac
+      done
+      for deplib in $compile_deplibs; do
+	case $deplib in
+	-L*)
+	  case " $new_libs " in
+	  *" $deplib "*) ;;
+	  *) func_append new_libs " $deplib" ;;
+	  esac
+	  ;;
+	*) func_append new_libs " $deplib" ;;
+	esac
+      done
+      compile_deplibs="$new_libs"
+
+
+      func_append compile_command " $compile_deplibs"
+      func_append finalize_command " $finalize_deplibs"
+
+      if test -n "$rpath$xrpath"; then
+	# If the user specified any rpath flags, then add them.
+	for libdir in $rpath $xrpath; do
+	  # This is the magic to use -rpath.
+	  case "$finalize_rpath " in
+	  *" $libdir "*) ;;
+	  *) func_append finalize_rpath " $libdir" ;;
+	  esac
+	done
+      fi
+
+      # Now hardcode the library paths
+      rpath=
+      hardcode_libdirs=
+      for libdir in $compile_rpath $finalize_rpath; do
+	if test -n "$hardcode_libdir_flag_spec"; then
+	  if test -n "$hardcode_libdir_separator"; then
+	    if test -z "$hardcode_libdirs"; then
+	      hardcode_libdirs="$libdir"
+	    else
+	      # Just accumulate the unique libdirs.
+	      case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+	      *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		;;
+	      *)
+		func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+		;;
+	      esac
+	    fi
+	  else
+	    eval flag=\"$hardcode_libdir_flag_spec\"
+	    func_append rpath " $flag"
+	  fi
+	elif test -n "$runpath_var"; then
+	  case "$perm_rpath " in
+	  *" $libdir "*) ;;
+	  *) func_append perm_rpath " $libdir" ;;
+	  esac
+	fi
+	case $host in
+	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+	  testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'`
+	  case :$dllsearchpath: in
+	  *":$libdir:"*) ;;
+	  ::) dllsearchpath=$libdir;;
+	  *) func_append dllsearchpath ":$libdir";;
+	  esac
+	  case :$dllsearchpath: in
+	  *":$testbindir:"*) ;;
+	  ::) dllsearchpath=$testbindir;;
+	  *) func_append dllsearchpath ":$testbindir";;
+	  esac
+	  ;;
+	esac
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+	 test -n "$hardcode_libdirs"; then
+	libdir="$hardcode_libdirs"
+	eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      compile_rpath="$rpath"
+
+      rpath=
+      hardcode_libdirs=
+      for libdir in $finalize_rpath; do
+	if test -n "$hardcode_libdir_flag_spec"; then
+	  if test -n "$hardcode_libdir_separator"; then
+	    if test -z "$hardcode_libdirs"; then
+	      hardcode_libdirs="$libdir"
+	    else
+	      # Just accumulate the unique libdirs.
+	      case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+	      *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+		;;
+	      *)
+		func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+		;;
+	      esac
+	    fi
+	  else
+	    eval flag=\"$hardcode_libdir_flag_spec\"
+	    func_append rpath " $flag"
+	  fi
+	elif test -n "$runpath_var"; then
+	  case "$finalize_perm_rpath " in
+	  *" $libdir "*) ;;
+	  *) func_append finalize_perm_rpath " $libdir" ;;
+	  esac
+	fi
+      done
+      # Substitute the hardcoded libdirs into the rpath.
+      if test -n "$hardcode_libdir_separator" &&
+	 test -n "$hardcode_libdirs"; then
+	libdir="$hardcode_libdirs"
+	eval rpath=\" $hardcode_libdir_flag_spec\"
+      fi
+      finalize_rpath="$rpath"
+
+      if test -n "$libobjs" && test "$build_old_libs" = yes; then
+	# Transform all the library objects into standard objects.
+	compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+	finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+      fi
+
+      func_generate_dlsyms "$outputname" "@PROGRAM@" "no"
+
+      # template prelinking step
+      if test -n "$prelink_cmds"; then
+	func_execute_cmds "$prelink_cmds" 'exit $?'
+      fi
+
+      wrappers_required=yes
+      case $host in
+      *cegcc* | *mingw32ce*)
+        # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway.
+        wrappers_required=no
+        ;;
+      *cygwin* | *mingw* )
+        if test "$build_libtool_libs" != yes; then
+          wrappers_required=no
+        fi
+        ;;
+      *)
+        if test "$need_relink" = no || test "$build_libtool_libs" != yes; then
+          wrappers_required=no
+        fi
+        ;;
+      esac
+      if test "$wrappers_required" = no; then
+	# Replace the output file specification.
+	compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+	link_command="$compile_command$compile_rpath"
+
+	# We have no uninstalled library dependencies, so finalize right now.
+	exit_status=0
+	func_show_eval "$link_command" 'exit_status=$?'
+
+	if test -n "$postlink_cmds"; then
+	  func_to_tool_file "$output"
+	  postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+	  func_execute_cmds "$postlink_cmds" 'exit $?'
+	fi
+
+	# Delete the generated files.
+	if test -f "$output_objdir/${outputname}S.${objext}"; then
+	  func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"'
+	fi
+
+	exit $exit_status
+      fi
+
+      if test -n "$compile_shlibpath$finalize_shlibpath"; then
+	compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+      fi
+      if test -n "$finalize_shlibpath"; then
+	finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+      fi
+
+      compile_var=
+      finalize_var=
+      if test -n "$runpath_var"; then
+	if test -n "$perm_rpath"; then
+	  # We should set the runpath_var.
+	  rpath=
+	  for dir in $perm_rpath; do
+	    func_append rpath "$dir:"
+	  done
+	  compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+	fi
+	if test -n "$finalize_perm_rpath"; then
+	  # We should set the runpath_var.
+	  rpath=
+	  for dir in $finalize_perm_rpath; do
+	    func_append rpath "$dir:"
+	  done
+	  finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+	fi
+      fi
+
+      if test "$no_install" = yes; then
+	# We don't need to create a wrapper script.
+	link_command="$compile_var$compile_command$compile_rpath"
+	# Replace the output file specification.
+	link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+	# Delete the old output file.
+	$opt_dry_run || $RM $output
+	# Link the executable and exit
+	func_show_eval "$link_command" 'exit $?'
+
+	if test -n "$postlink_cmds"; then
+	  func_to_tool_file "$output"
+	  postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+	  func_execute_cmds "$postlink_cmds" 'exit $?'
+	fi
+
+	exit $EXIT_SUCCESS
+      fi
+
+      if test "$hardcode_action" = relink; then
+	# Fast installation is not supported
+	link_command="$compile_var$compile_command$compile_rpath"
+	relink_command="$finalize_var$finalize_command$finalize_rpath"
+
+	func_warning "this platform does not like uninstalled shared libraries"
+	func_warning "\`$output' will be relinked during installation"
+      else
+	if test "$fast_install" != no; then
+	  link_command="$finalize_var$compile_command$finalize_rpath"
+	  if test "$fast_install" = yes; then
+	    relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'`
+	  else
+	    # fast_install is set to needless
+	    relink_command=
+	  fi
+	else
+	  link_command="$compile_var$compile_command$compile_rpath"
+	  relink_command="$finalize_var$finalize_command$finalize_rpath"
+	fi
+      fi
+
+      # Replace the output file specification.
+      link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+
+      # Delete the old output files.
+      $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+      func_show_eval "$link_command" 'exit $?'
+
+      if test -n "$postlink_cmds"; then
+	func_to_tool_file "$output_objdir/$outputname"
+	postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+	func_execute_cmds "$postlink_cmds" 'exit $?'
+      fi
+
+      # Now create the wrapper script.
+      func_verbose "creating $output"
+
+      # Quote the relink command for shipping.
+      if test -n "$relink_command"; then
+	# Preserve any variables that may affect compiler behavior
+	for var in $variables_saved_for_relink; do
+	  if eval test -z \"\${$var+set}\"; then
+	    relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+	  elif eval var_value=\$$var; test -z "$var_value"; then
+	    relink_command="$var=; export $var; $relink_command"
+	  else
+	    func_quote_for_eval "$var_value"
+	    relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+	  fi
+	done
+	relink_command="(cd `pwd`; $relink_command)"
+	relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+      fi
+
+      # Only actually do things if not in dry run mode.
+      $opt_dry_run || {
+	# win32 will think the script is a binary if it has
+	# a .exe suffix, so we strip it off here.
+	case $output in
+	  *.exe) func_stripname '' '.exe' "$output"
+	         output=$func_stripname_result ;;
+	esac
+	# test for cygwin because mv fails w/o .exe extensions
+	case $host in
+	  *cygwin*)
+	    exeext=.exe
+	    func_stripname '' '.exe' "$outputname"
+	    outputname=$func_stripname_result ;;
+	  *) exeext= ;;
+	esac
+	case $host in
+	  *cygwin* | *mingw* )
+	    func_dirname_and_basename "$output" "" "."
+	    output_name=$func_basename_result
+	    output_path=$func_dirname_result
+	    cwrappersource="$output_path/$objdir/lt-$output_name.c"
+	    cwrapper="$output_path/$output_name.exe"
+	    $RM $cwrappersource $cwrapper
+	    trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
+
+	    func_emit_cwrapperexe_src > $cwrappersource
+
+	    # The wrapper executable is built using the $host compiler,
+	    # because it contains $host paths and files. If cross-
+	    # compiling, it, like the target executable, must be
+	    # executed on the $host or under an emulation environment.
+	    $opt_dry_run || {
+	      $LTCC $LTCFLAGS -o $cwrapper $cwrappersource
+	      $STRIP $cwrapper
+	    }
+
+	    # Now, create the wrapper script for func_source use:
+	    func_ltwrapper_scriptname $cwrapper
+	    $RM $func_ltwrapper_scriptname_result
+	    trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15
+	    $opt_dry_run || {
+	      # note: this script will not be executed, so do not chmod.
+	      if test "x$build" = "x$host" ; then
+		$cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result
+	      else
+		func_emit_wrapper no > $func_ltwrapper_scriptname_result
+	      fi
+	    }
+	  ;;
+	  * )
+	    $RM $output
+	    trap "$RM $output; exit $EXIT_FAILURE" 1 2 15
+
+	    func_emit_wrapper no > $output
+	    chmod +x $output
+	  ;;
+	esac
+      }
+      exit $EXIT_SUCCESS
+      ;;
+    esac
+
+    # See if we need to build an old-fashioned archive.
+    for oldlib in $oldlibs; do
+
+      if test "$build_libtool_libs" = convenience; then
+	oldobjs="$libobjs_save $symfileobj"
+	addlibs="$convenience"
+	build_libtool_libs=no
+      else
+	if test "$build_libtool_libs" = module; then
+	  oldobjs="$libobjs_save"
+	  build_libtool_libs=no
+	else
+	  oldobjs="$old_deplibs $non_pic_objects"
+	  if test "$preload" = yes && test -f "$symfileobj"; then
+	    func_append oldobjs " $symfileobj"
+	  fi
+	fi
+	addlibs="$old_convenience"
+      fi
+
+      if test -n "$addlibs"; then
+	gentop="$output_objdir/${outputname}x"
+	func_append generated " $gentop"
+
+	func_extract_archives $gentop $addlibs
+	func_append oldobjs " $func_extract_archives_result"
+      fi
+
+      # Do each command in the archive commands.
+      if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
+	cmds=$old_archive_from_new_cmds
+      else
+
+	# Add any objects from preloaded convenience libraries
+	if test -n "$dlprefiles"; then
+	  gentop="$output_objdir/${outputname}x"
+	  func_append generated " $gentop"
+
+	  func_extract_archives $gentop $dlprefiles
+	  func_append oldobjs " $func_extract_archives_result"
+	fi
+
+	# POSIX demands no paths to be encoded in archives.  We have
+	# to avoid creating archives with duplicate basenames if we
+	# might have to extract them afterwards, e.g., when creating a
+	# static archive out of a convenience library, or when linking
+	# the entirety of a libtool archive into another (currently
+	# not supported by libtool).
+	if (for obj in $oldobjs
+	    do
+	      func_basename "$obj"
+	      $ECHO "$func_basename_result"
+	    done | sort | sort -uc >/dev/null 2>&1); then
+	  :
+	else
+	  echo "copying selected object files to avoid basename conflicts..."
+	  gentop="$output_objdir/${outputname}x"
+	  func_append generated " $gentop"
+	  func_mkdir_p "$gentop"
+	  save_oldobjs=$oldobjs
+	  oldobjs=
+	  counter=1
+	  for obj in $save_oldobjs
+	  do
+	    func_basename "$obj"
+	    objbase="$func_basename_result"
+	    case " $oldobjs " in
+	    " ") oldobjs=$obj ;;
+	    *[\ /]"$objbase "*)
+	      while :; do
+		# Make sure we don't pick an alternate name that also
+		# overlaps.
+		newobj=lt$counter-$objbase
+		func_arith $counter + 1
+		counter=$func_arith_result
+		case " $oldobjs " in
+		*[\ /]"$newobj "*) ;;
+		*) if test ! -f "$gentop/$newobj"; then break; fi ;;
+		esac
+	      done
+	      func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj"
+	      func_append oldobjs " $gentop/$newobj"
+	      ;;
+	    *) func_append oldobjs " $obj" ;;
+	    esac
+	  done
+	fi
+	func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
+	tool_oldlib=$func_to_tool_file_result
+	eval cmds=\"$old_archive_cmds\"
+
+	func_len " $cmds"
+	len=$func_len_result
+	if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+	  cmds=$old_archive_cmds
+	elif test -n "$archiver_list_spec"; then
+	  func_verbose "using command file archive linking..."
+	  for obj in $oldobjs
+	  do
+	    func_to_tool_file "$obj"
+	    $ECHO "$func_to_tool_file_result"
+	  done > $output_objdir/$libname.libcmd
+	  func_to_tool_file "$output_objdir/$libname.libcmd"
+	  oldobjs=" $archiver_list_spec$func_to_tool_file_result"
+	  cmds=$old_archive_cmds
+	else
+	  # the command line is too long to link in one step, link in parts
+	  func_verbose "using piecewise archive linking..."
+	  save_RANLIB=$RANLIB
+	  RANLIB=:
+	  objlist=
+	  concat_cmds=
+	  save_oldobjs=$oldobjs
+	  oldobjs=
+	  # Is there a better way of finding the last object in the list?
+	  for obj in $save_oldobjs
+	  do
+	    last_oldobj=$obj
+	  done
+	  eval test_cmds=\"$old_archive_cmds\"
+	  func_len " $test_cmds"
+	  len0=$func_len_result
+	  len=$len0
+	  for obj in $save_oldobjs
+	  do
+	    func_len " $obj"
+	    func_arith $len + $func_len_result
+	    len=$func_arith_result
+	    func_append objlist " $obj"
+	    if test "$len" -lt "$max_cmd_len"; then
+	      :
+	    else
+	      # the above command should be used before it gets too long
+	      oldobjs=$objlist
+	      if test "$obj" = "$last_oldobj" ; then
+		RANLIB=$save_RANLIB
+	      fi
+	      test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+	      eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\"
+	      objlist=
+	      len=$len0
+	    fi
+	  done
+	  RANLIB=$save_RANLIB
+	  oldobjs=$objlist
+	  if test "X$oldobjs" = "X" ; then
+	    eval cmds=\"\$concat_cmds\"
+	  else
+	    eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
+	  fi
+	fi
+      fi
+      func_execute_cmds "$cmds" 'exit $?'
+    done
+
+    test -n "$generated" && \
+      func_show_eval "${RM}r$generated"
+
+    # Now create the libtool archive.
+    case $output in
+    *.la)
+      old_library=
+      test "$build_old_libs" = yes && old_library="$libname.$libext"
+      func_verbose "creating $output"
+
+      # Preserve any variables that may affect compiler behavior
+      for var in $variables_saved_for_relink; do
+	if eval test -z \"\${$var+set}\"; then
+	  relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+	elif eval var_value=\$$var; test -z "$var_value"; then
+	  relink_command="$var=; export $var; $relink_command"
+	else
+	  func_quote_for_eval "$var_value"
+	  relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+	fi
+      done
+      # Quote the link command for shipping.
+      relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+      relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+      if test "$hardcode_automatic" = yes ; then
+	relink_command=
+      fi
+
+      # Only create the output if not a dry run.
+      $opt_dry_run || {
+	for installed in no yes; do
+	  if test "$installed" = yes; then
+	    if test -z "$install_libdir"; then
+	      break
+	    fi
+	    output="$output_objdir/$outputname"i
+	    # Replace all uninstalled libtool libraries with the installed ones
+	    newdependency_libs=
+	    for deplib in $dependency_libs; do
+	      case $deplib in
+	      *.la)
+		func_basename "$deplib"
+		name="$func_basename_result"
+		func_resolve_sysroot "$deplib"
+		eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result`
+		test -z "$libdir" && \
+		  func_fatal_error "\`$deplib' is not a valid libtool archive"
+		func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name"
+		;;
+	      -L*)
+		func_stripname -L '' "$deplib"
+		func_replace_sysroot "$func_stripname_result"
+		func_append newdependency_libs " -L$func_replace_sysroot_result"
+		;;
+	      -R*)
+		func_stripname -R '' "$deplib"
+		func_replace_sysroot "$func_stripname_result"
+		func_append newdependency_libs " -R$func_replace_sysroot_result"
+		;;
+	      *) func_append newdependency_libs " $deplib" ;;
+	      esac
+	    done
+	    dependency_libs="$newdependency_libs"
+	    newdlfiles=
+
+	    for lib in $dlfiles; do
+	      case $lib in
+	      *.la)
+	        func_basename "$lib"
+		name="$func_basename_result"
+		eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+		test -z "$libdir" && \
+		  func_fatal_error "\`$lib' is not a valid libtool archive"
+		func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name"
+		;;
+	      *) func_append newdlfiles " $lib" ;;
+	      esac
+	    done
+	    dlfiles="$newdlfiles"
+	    newdlprefiles=
+	    for lib in $dlprefiles; do
+	      case $lib in
+	      *.la)
+		# Only pass preopened files to the pseudo-archive (for
+		# eventual linking with the app. that links it) if we
+		# didn't already link the preopened objects directly into
+		# the library:
+		func_basename "$lib"
+		name="$func_basename_result"
+		eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+		test -z "$libdir" && \
+		  func_fatal_error "\`$lib' is not a valid libtool archive"
+		func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name"
+		;;
+	      esac
+	    done
+	    dlprefiles="$newdlprefiles"
+	  else
+	    newdlfiles=
+	    for lib in $dlfiles; do
+	      case $lib in
+		[\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+		*) abs=`pwd`"/$lib" ;;
+	      esac
+	      func_append newdlfiles " $abs"
+	    done
+	    dlfiles="$newdlfiles"
+	    newdlprefiles=
+	    for lib in $dlprefiles; do
+	      case $lib in
+		[\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+		*) abs=`pwd`"/$lib" ;;
+	      esac
+	      func_append newdlprefiles " $abs"
+	    done
+	    dlprefiles="$newdlprefiles"
+	  fi
+	  $RM $output
+	  # place dlname in correct position for cygwin
+	  # In fact, it would be nice if we could use this code for all target
+	  # systems that can't hard-code library paths into their executables
+	  # and that have no shared library path variable independent of PATH,
+	  # but it turns out we can't easily determine that from inspecting
+	  # libtool variables, so we have to hard-code the OSs to which it
+	  # applies here; at the moment, that means platforms that use the PE
+	  # object format with DLL files.  See the long comment at the top of
+	  # tests/bindir.at for full details.
+	  tdlname=$dlname
+	  case $host,$output,$installed,$module,$dlname in
+	    *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll)
+	      # If a -bindir argument was supplied, place the dll there.
+	      if test "x$bindir" != x ;
+	      then
+		func_relative_path "$install_libdir" "$bindir"
+		tdlname=$func_relative_path_result$dlname
+	      else
+		# Otherwise fall back on heuristic.
+		tdlname=../bin/$dlname
+	      fi
+	      ;;
+	  esac
+	  $ECHO > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$tdlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Linker flags that can not go in dependency_libs.
+inherited_linker_flags='$new_inherited_linker_flags'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Names of additional weak libraries provided by this library
+weak_library_names='$weak_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=$module
+
+# Files to dlopen/dlpreopen
+dlopen='$dlfiles'
+dlpreopen='$dlprefiles'
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'"
+	  if test "$installed" = no && test "$need_relink" = yes; then
+	    $ECHO >> $output "\
+relink_command=\"$relink_command\""
+	  fi
+	done
+      }
+
+      # Do a symbolic link so that the libtool archive can be found in
+      # LD_LIBRARY_PATH before the program is installed.
+      func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?'
+      ;;
+    esac
+    exit $EXIT_SUCCESS
+}
+
+{ test "$opt_mode" = link || test "$opt_mode" = relink; } &&
+    func_mode_link ${1+"$@"}
+
+
+# func_mode_uninstall arg...
+func_mode_uninstall ()
+{
+    $opt_debug
+    RM="$nonopt"
+    files=
+    rmforce=
+    exit_status=0
+
+    # This variable tells wrapper scripts just to set variables rather
+    # than running their programs.
+    libtool_install_magic="$magic"
+
+    for arg
+    do
+      case $arg in
+      -f) func_append RM " $arg"; rmforce=yes ;;
+      -*) func_append RM " $arg" ;;
+      *) func_append files " $arg" ;;
+      esac
+    done
+
+    test -z "$RM" && \
+      func_fatal_help "you must specify an RM program"
+
+    rmdirs=
+
+    for file in $files; do
+      func_dirname "$file" "" "."
+      dir="$func_dirname_result"
+      if test "X$dir" = X.; then
+	odir="$objdir"
+      else
+	odir="$dir/$objdir"
+      fi
+      func_basename "$file"
+      name="$func_basename_result"
+      test "$opt_mode" = uninstall && odir="$dir"
+
+      # Remember odir for removal later, being careful to avoid duplicates
+      if test "$opt_mode" = clean; then
+	case " $rmdirs " in
+	  *" $odir "*) ;;
+	  *) func_append rmdirs " $odir" ;;
+	esac
+      fi
+
+      # Don't error if the file doesn't exist and rm -f was used.
+      if { test -L "$file"; } >/dev/null 2>&1 ||
+	 { test -h "$file"; } >/dev/null 2>&1 ||
+	 test -f "$file"; then
+	:
+      elif test -d "$file"; then
+	exit_status=1
+	continue
+      elif test "$rmforce" = yes; then
+	continue
+      fi
+
+      rmfiles="$file"
+
+      case $name in
+      *.la)
+	# Possibly a libtool archive, so verify it.
+	if func_lalib_p "$file"; then
+	  func_source $dir/$name
+
+	  # Delete the libtool libraries and symlinks.
+	  for n in $library_names; do
+	    func_append rmfiles " $odir/$n"
+	  done
+	  test -n "$old_library" && func_append rmfiles " $odir/$old_library"
+
+	  case "$opt_mode" in
+	  clean)
+	    case " $library_names " in
+	    *" $dlname "*) ;;
+	    *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;;
+	    esac
+	    test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i"
+	    ;;
+	  uninstall)
+	    if test -n "$library_names"; then
+	      # Do each command in the postuninstall commands.
+	      func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+	    fi
+
+	    if test -n "$old_library"; then
+	      # Do each command in the old_postuninstall commands.
+	      func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+	    fi
+	    # FIXME: should reinstall the best remaining shared library.
+	    ;;
+	  esac
+	fi
+	;;
+
+      *.lo)
+	# Possibly a libtool object, so verify it.
+	if func_lalib_p "$file"; then
+
+	  # Read the .lo file
+	  func_source $dir/$name
+
+	  # Add PIC object to the list of files to remove.
+	  if test -n "$pic_object" &&
+	     test "$pic_object" != none; then
+	    func_append rmfiles " $dir/$pic_object"
+	  fi
+
+	  # Add non-PIC object to the list of files to remove.
+	  if test -n "$non_pic_object" &&
+	     test "$non_pic_object" != none; then
+	    func_append rmfiles " $dir/$non_pic_object"
+	  fi
+	fi
+	;;
+
+      *)
+	if test "$opt_mode" = clean ; then
+	  noexename=$name
+	  case $file in
+	  *.exe)
+	    func_stripname '' '.exe' "$file"
+	    file=$func_stripname_result
+	    func_stripname '' '.exe' "$name"
+	    noexename=$func_stripname_result
+	    # $file with .exe has already been added to rmfiles,
+	    # add $file without .exe
+	    func_append rmfiles " $file"
+	    ;;
+	  esac
+	  # Do a test to see if this is a libtool program.
+	  if func_ltwrapper_p "$file"; then
+	    if func_ltwrapper_executable_p "$file"; then
+	      func_ltwrapper_scriptname "$file"
+	      relink_command=
+	      func_source $func_ltwrapper_scriptname_result
+	      func_append rmfiles " $func_ltwrapper_scriptname_result"
+	    else
+	      relink_command=
+	      func_source $dir/$noexename
+	    fi
+
+	    # note $name still contains .exe if it was in $file originally
+	    # as does the version of $file that was added into $rmfiles
+	    func_append rmfiles " $odir/$name $odir/${name}S.${objext}"
+	    if test "$fast_install" = yes && test -n "$relink_command"; then
+	      func_append rmfiles " $odir/lt-$name"
+	    fi
+	    if test "X$noexename" != "X$name" ; then
+	      func_append rmfiles " $odir/lt-${noexename}.c"
+	    fi
+	  fi
+	fi
+	;;
+      esac
+      func_show_eval "$RM $rmfiles" 'exit_status=1'
+    done
+
+    # Try to remove the ${objdir}s in the directories where we deleted files
+    for dir in $rmdirs; do
+      if test -d "$dir"; then
+	func_show_eval "rmdir $dir >/dev/null 2>&1"
+      fi
+    done
+
+    exit $exit_status
+}
+
+{ test "$opt_mode" = uninstall || test "$opt_mode" = clean; } &&
+    func_mode_uninstall ${1+"$@"}
+
+test -z "$opt_mode" && {
+  help="$generic_help"
+  func_fatal_help "you must specify a MODE"
+}
+
+test -z "$exec_cmd" && \
+  func_fatal_help "invalid operation mode \`$opt_mode'"
+
+if test -n "$exec_cmd"; then
+  eval exec "$exec_cmd"
+  exit $EXIT_FAILURE
+fi
+
+exit $exit_status
+
+
+# The TAGs below are defined such that we never get into a situation
+# in which we disable both kinds of libraries.  Given conflicting
+# choices, we go for a static library, that is the most portable,
+# since we can't tell whether shared libraries were disabled because
+# the user asked for that or because the platform doesn't support
+# them.  This is particularly important on AIX, because we don't
+# support having both static and shared libraries enabled at the same
+# time on that platform, so we default to a shared-only configuration.
+# If a disable-shared tag is given, we'll fallback to a static-only
+# configuration.  But we'll never go from static-only to shared-only.
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
+build_libtool_libs=no
+build_old_libs=yes
+# ### END LIBTOOL TAG CONFIG: disable-shared
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-static
+build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
+# ### END LIBTOOL TAG CONFIG: disable-static
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
+# vi:sw=2
+
diff --git a/autostuff/ltoptions.m4 b/autostuff/ltoptions.m4
new file mode 100644
index 0000000..5d9acd8
--- /dev/null
+++ b/autostuff/ltoptions.m4
@@ -0,0 +1,384 @@
+# Helper functions for option handling.                    -*- Autoconf -*-
+#
+#   Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation,
+#   Inc.
+#   Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 7 ltoptions.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
+
+
+# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
+# ------------------------------------------
+m4_define([_LT_MANGLE_OPTION],
+[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
+
+
+# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
+# ---------------------------------------
+# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
+# matching handler defined, dispatch to it.  Other OPTION-NAMEs are
+# saved as a flag.
+m4_define([_LT_SET_OPTION],
+[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
+m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
+        _LT_MANGLE_DEFUN([$1], [$2]),
+    [m4_warning([Unknown $1 option `$2'])])[]dnl
+])
+
+
+# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
+# ------------------------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+m4_define([_LT_IF_OPTION],
+[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
+
+
+# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
+# -------------------------------------------------------
+# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
+# are set.
+m4_define([_LT_UNLESS_OPTIONS],
+[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+	    [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
+		      [m4_define([$0_found])])])[]dnl
+m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
+])[]dnl
+])
+
+
+# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
+# ----------------------------------------
+# OPTION-LIST is a space-separated list of Libtool options associated
+# with MACRO-NAME.  If any OPTION has a matching handler declared with
+# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
+# the unknown option and exit.
+m4_defun([_LT_SET_OPTIONS],
+[# Set options
+m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+    [_LT_SET_OPTION([$1], _LT_Option)])
+
+m4_if([$1],[LT_INIT],[
+  dnl
+  dnl Simply set some default values (i.e off) if boolean options were not
+  dnl specified:
+  _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
+  ])
+  _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
+  ])
+  dnl
+  dnl If no reference was made to various pairs of opposing options, then
+  dnl we run the default mode handler for the pair.  For example, if neither
+  dnl `shared' nor `disable-shared' was passed, we enable building of shared
+  dnl archives by default:
+  _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
+  _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
+  _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
+  _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
+  		   [_LT_ENABLE_FAST_INSTALL])
+  ])
+])# _LT_SET_OPTIONS
+
+
+## --------------------------------- ##
+## Macros to handle LT_INIT options. ##
+## --------------------------------- ##
+
+# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
+# -----------------------------------------
+m4_define([_LT_MANGLE_DEFUN],
+[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
+
+
+# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
+# -----------------------------------------------
+m4_define([LT_OPTION_DEFINE],
+[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
+])# LT_OPTION_DEFINE
+
+
+# dlopen
+# ------
+LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
+])
+
+AU_DEFUN([AC_LIBTOOL_DLOPEN],
+[_LT_SET_OPTION([LT_INIT], [dlopen])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `dlopen' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
+
+
+# win32-dll
+# ---------
+# Declare package support for building win32 dll's.
+LT_OPTION_DEFINE([LT_INIT], [win32-dll],
+[enable_win32_dll=yes
+
+case $host in
+*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
+  AC_CHECK_TOOL(AS, as, false)
+  AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+  AC_CHECK_TOOL(OBJDUMP, objdump, false)
+  ;;
+esac
+
+test -z "$AS" && AS=as
+_LT_DECL([], [AS],      [1], [Assembler program])dnl
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
+])# win32-dll
+
+AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+_LT_SET_OPTION([LT_INIT], [win32-dll])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `win32-dll' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
+
+
+# _LT_ENABLE_SHARED([DEFAULT])
+# ----------------------------
+# implement the --enable-shared flag, and supports the `shared' and
+# `disable-shared' LT_INIT options.
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_SHARED],
+[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([shared],
+    [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
+	[build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_shared=yes ;;
+    no) enable_shared=no ;;
+    *)
+      enable_shared=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_shared=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
+
+    _LT_DECL([build_libtool_libs], [enable_shared], [0],
+	[Whether or not to build shared libraries])
+])# _LT_ENABLE_SHARED
+
+LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
+])
+
+AC_DEFUN([AC_DISABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], [disable-shared])
+])
+
+AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
+AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_SHARED], [])
+dnl AC_DEFUN([AM_DISABLE_SHARED], [])
+
+
+
+# _LT_ENABLE_STATIC([DEFAULT])
+# ----------------------------
+# implement the --enable-static flag, and support the `static' and
+# `disable-static' LT_INIT options.
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_STATIC],
+[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([static],
+    [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
+	[build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_static=yes ;;
+    no) enable_static=no ;;
+    *)
+     enable_static=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_static=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_static=]_LT_ENABLE_STATIC_DEFAULT)
+
+    _LT_DECL([build_old_libs], [enable_static], [0],
+	[Whether or not to build static libraries])
+])# _LT_ENABLE_STATIC
+
+LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
+])
+
+AC_DEFUN([AC_DISABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], [disable-static])
+])
+
+AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
+AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_STATIC], [])
+dnl AC_DEFUN([AM_DISABLE_STATIC], [])
+
+
+
+# _LT_ENABLE_FAST_INSTALL([DEFAULT])
+# ----------------------------------
+# implement the --enable-fast-install flag, and support the `fast-install'
+# and `disable-fast-install' LT_INIT options.
+# DEFAULT is either `yes' or `no'.  If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_FAST_INSTALL],
+[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([fast-install],
+    [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
+    [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
+    [p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_fast_install=yes ;;
+    no) enable_fast_install=no ;;
+    *)
+      enable_fast_install=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_fast_install=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
+
+_LT_DECL([fast_install], [enable_fast_install], [0],
+	 [Whether or not to optimize for fast installation])dnl
+])# _LT_ENABLE_FAST_INSTALL
+
+LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
+
+# Old names:
+AU_DEFUN([AC_ENABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `fast-install' option into LT_INIT's first parameter.])
+])
+
+AU_DEFUN([AC_DISABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `disable-fast-install' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
+dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
+
+
+# _LT_WITH_PIC([MODE])
+# --------------------
+# implement the --with-pic flag, and support the `pic-only' and `no-pic'
+# LT_INIT options.
+# MODE is either `yes' or `no'.  If omitted, it defaults to `both'.
+m4_define([_LT_WITH_PIC],
+[AC_ARG_WITH([pic],
+    [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
+	[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
+    [lt_p=${PACKAGE-default}
+    case $withval in
+    yes|no) pic_mode=$withval ;;
+    *)
+      pic_mode=default
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for lt_pkg in $withval; do
+	IFS="$lt_save_ifs"
+	if test "X$lt_pkg" = "X$lt_p"; then
+	  pic_mode=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac],
+    [pic_mode=default])
+
+test -z "$pic_mode" && pic_mode=m4_default([$1], [default])
+
+_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
+])# _LT_WITH_PIC
+
+LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
+
+# Old name:
+AU_DEFUN([AC_LIBTOOL_PICMODE],
+[_LT_SET_OPTION([LT_INIT], [pic-only])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `pic-only' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
+
+## ----------------- ##
+## LTDL_INIT Options ##
+## ----------------- ##
+
+m4_define([_LTDL_MODE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
+		 [m4_define([_LTDL_MODE], [nonrecursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [recursive],
+		 [m4_define([_LTDL_MODE], [recursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [subproject],
+		 [m4_define([_LTDL_MODE], [subproject])])
+
+m4_define([_LTDL_TYPE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [installable],
+		 [m4_define([_LTDL_TYPE], [installable])])
+LT_OPTION_DEFINE([LTDL_INIT], [convenience],
+		 [m4_define([_LTDL_TYPE], [convenience])])
diff --git a/autostuff/ltsugar.m4 b/autostuff/ltsugar.m4
new file mode 100644
index 0000000..9000a05
--- /dev/null
+++ b/autostuff/ltsugar.m4
@@ -0,0 +1,123 @@
+# ltsugar.m4 -- libtool m4 base layer.                         -*-Autoconf-*-
+#
+# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 6 ltsugar.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
+
+
+# lt_join(SEP, ARG1, [ARG2...])
+# -----------------------------
+# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
+# associated separator.
+# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
+# versions in m4sugar had bugs.
+m4_define([lt_join],
+[m4_if([$#], [1], [],
+       [$#], [2], [[$2]],
+       [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
+m4_define([_lt_join],
+[m4_if([$#$2], [2], [],
+       [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
+
+
+# lt_car(LIST)
+# lt_cdr(LIST)
+# ------------
+# Manipulate m4 lists.
+# These macros are necessary as long as will still need to support
+# Autoconf-2.59 which quotes differently.
+m4_define([lt_car], [[$1]])
+m4_define([lt_cdr],
+[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
+       [$#], 1, [],
+       [m4_dquote(m4_shift($@))])])
+m4_define([lt_unquote], $1)
+
+
+# lt_append(MACRO-NAME, STRING, [SEPARATOR])
+# ------------------------------------------
+# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
+# Note that neither SEPARATOR nor STRING are expanded; they are appended
+# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
+# No SEPARATOR is output if MACRO-NAME was previously undefined (different
+# than defined and empty).
+#
+# This macro is needed until we can rely on Autoconf 2.62, since earlier
+# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
+m4_define([lt_append],
+[m4_define([$1],
+	   m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
+
+
+
+# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
+# ----------------------------------------------------------
+# Produce a SEP delimited list of all paired combinations of elements of
+# PREFIX-LIST with SUFFIX1 through SUFFIXn.  Each element of the list
+# has the form PREFIXmINFIXSUFFIXn.
+# Needed until we can rely on m4_combine added in Autoconf 2.62.
+m4_define([lt_combine],
+[m4_if(m4_eval([$# > 3]), [1],
+       [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
+[[m4_foreach([_Lt_prefix], [$2],
+	     [m4_foreach([_Lt_suffix],
+		]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
+	[_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
+
+
+# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
+# -----------------------------------------------------------------------
+# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
+# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
+m4_define([lt_if_append_uniq],
+[m4_ifdef([$1],
+	  [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
+		 [lt_append([$1], [$2], [$3])$4],
+		 [$5])],
+	  [lt_append([$1], [$2], [$3])$4])])
+
+
+# lt_dict_add(DICT, KEY, VALUE)
+# -----------------------------
+m4_define([lt_dict_add],
+[m4_define([$1($2)], [$3])])
+
+
+# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
+# --------------------------------------------
+m4_define([lt_dict_add_subkey],
+[m4_define([$1($2:$3)], [$4])])
+
+
+# lt_dict_fetch(DICT, KEY, [SUBKEY])
+# ----------------------------------
+m4_define([lt_dict_fetch],
+[m4_ifval([$3],
+	m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
+    m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
+
+
+# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
+# -----------------------------------------------------------------
+m4_define([lt_if_dict_fetch],
+[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
+	[$5],
+    [$6])])
+
+
+# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
+# --------------------------------------------------------------
+m4_define([lt_dict_filter],
+[m4_if([$5], [], [],
+  [lt_join(m4_quote(m4_default([$4], [[, ]])),
+           lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
+		      [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
+])
diff --git a/autostuff/ltversion.m4 b/autostuff/ltversion.m4
new file mode 100644
index 0000000..07a8602
--- /dev/null
+++ b/autostuff/ltversion.m4
@@ -0,0 +1,23 @@
+# ltversion.m4 -- version numbers			-*- Autoconf -*-
+#
+#   Copyright (C) 2004 Free Software Foundation, Inc.
+#   Written by Scott James Remnant, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# @configure_input@
+
+# serial 3337 ltversion.m4
+# This file is part of GNU Libtool
+
+m4_define([LT_PACKAGE_VERSION], [2.4.2])
+m4_define([LT_PACKAGE_REVISION], [1.3337])
+
+AC_DEFUN([LTVERSION_VERSION],
+[macro_version='2.4.2'
+macro_revision='1.3337'
+_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
+_LT_DECL(, macro_revision, 0)
+])
diff --git a/autostuff/lt~obsolete.m4 b/autostuff/lt~obsolete.m4
new file mode 100644
index 0000000..c573da9
--- /dev/null
+++ b/autostuff/lt~obsolete.m4
@@ -0,0 +1,98 @@
+# lt~obsolete.m4 -- aclocal satisfying obsolete definitions.    -*-Autoconf-*-
+#
+#   Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
+#   Written by Scott James Remnant, 2004.
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 5 lt~obsolete.m4
+
+# These exist entirely to fool aclocal when bootstrapping libtool.
+#
+# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
+# which have later been changed to m4_define as they aren't part of the
+# exported API, or moved to Autoconf or Automake where they belong.
+#
+# The trouble is, aclocal is a bit thick.  It'll see the old AC_DEFUN
+# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
+# using a macro with the same name in our local m4/libtool.m4 it'll
+# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
+# and doesn't know about Autoconf macros at all.)
+#
+# So we provide this file, which has a silly filename so it's always
+# included after everything else.  This provides aclocal with the
+# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
+# because those macros already exist, or will be overwritten later.
+# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. 
+#
+# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
+# Yes, that means every name once taken will need to remain here until
+# we give up compatibility with versions before 1.7, at which point
+# we need to keep only those names which we still refer to.
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
+
+m4_ifndef([AC_LIBTOOL_LINKER_OPTION],	[AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
+m4_ifndef([AC_PROG_EGREP],		[AC_DEFUN([AC_PROG_EGREP])])
+m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH],	[AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_AC_SHELL_INIT],		[AC_DEFUN([_LT_AC_SHELL_INIT])])
+m4_ifndef([_LT_AC_SYS_LIBPATH_AIX],	[AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
+m4_ifndef([_LT_PROG_LTMAIN],		[AC_DEFUN([_LT_PROG_LTMAIN])])
+m4_ifndef([_LT_AC_TAGVAR],		[AC_DEFUN([_LT_AC_TAGVAR])])
+m4_ifndef([AC_LTDL_ENABLE_INSTALL],	[AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
+m4_ifndef([AC_LTDL_PREOPEN],		[AC_DEFUN([AC_LTDL_PREOPEN])])
+m4_ifndef([_LT_AC_SYS_COMPILER],	[AC_DEFUN([_LT_AC_SYS_COMPILER])])
+m4_ifndef([_LT_AC_LOCK],		[AC_DEFUN([_LT_AC_LOCK])])
+m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE],	[AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
+m4_ifndef([_LT_AC_TRY_DLOPEN_SELF],	[AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
+m4_ifndef([AC_LIBTOOL_PROG_CC_C_O],	[AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
+m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
+m4_ifndef([AC_LIBTOOL_OBJDIR],		[AC_DEFUN([AC_LIBTOOL_OBJDIR])])
+m4_ifndef([AC_LTDL_OBJDIR],		[AC_DEFUN([AC_LTDL_OBJDIR])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
+m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP],	[AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
+m4_ifndef([AC_PATH_MAGIC],		[AC_DEFUN([AC_PATH_MAGIC])])
+m4_ifndef([AC_PROG_LD_GNU],		[AC_DEFUN([AC_PROG_LD_GNU])])
+m4_ifndef([AC_PROG_LD_RELOAD_FLAG],	[AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
+m4_ifndef([AC_DEPLIBS_CHECK_METHOD],	[AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
+m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS],	[AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
+m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP],	[AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
+m4_ifndef([LT_AC_PROG_EGREP],		[AC_DEFUN([LT_AC_PROG_EGREP])])
+m4_ifndef([LT_AC_PROG_SED],		[AC_DEFUN([LT_AC_PROG_SED])])
+m4_ifndef([_LT_CC_BASENAME],		[AC_DEFUN([_LT_CC_BASENAME])])
+m4_ifndef([_LT_COMPILER_BOILERPLATE],	[AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
+m4_ifndef([_LT_LINKER_BOILERPLATE],	[AC_DEFUN([_LT_LINKER_BOILERPLATE])])
+m4_ifndef([_AC_PROG_LIBTOOL],		[AC_DEFUN([_AC_PROG_LIBTOOL])])
+m4_ifndef([AC_LIBTOOL_SETUP],		[AC_DEFUN([AC_LIBTOOL_SETUP])])
+m4_ifndef([_LT_AC_CHECK_DLFCN],		[AC_DEFUN([_LT_AC_CHECK_DLFCN])])
+m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER],	[AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
+m4_ifndef([_LT_AC_TAGCONFIG],		[AC_DEFUN([_LT_AC_TAGCONFIG])])
+m4_ifndef([AC_DISABLE_FAST_INSTALL],	[AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
+m4_ifndef([_LT_AC_LANG_CXX],		[AC_DEFUN([_LT_AC_LANG_CXX])])
+m4_ifndef([_LT_AC_LANG_F77],		[AC_DEFUN([_LT_AC_LANG_F77])])
+m4_ifndef([_LT_AC_LANG_GCJ],		[AC_DEFUN([_LT_AC_LANG_GCJ])])
+m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
+m4_ifndef([_LT_AC_LANG_C_CONFIG],	[AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
+m4_ifndef([_LT_AC_LANG_CXX_CONFIG],	[AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
+m4_ifndef([_LT_AC_LANG_F77_CONFIG],	[AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
+m4_ifndef([_LT_AC_LANG_GCJ_CONFIG],	[AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG],	[AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
+m4_ifndef([_LT_AC_LANG_RC_CONFIG],	[AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
+m4_ifndef([AC_LIBTOOL_CONFIG],		[AC_DEFUN([AC_LIBTOOL_CONFIG])])
+m4_ifndef([_LT_AC_FILE_LTDLL_C],	[AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
+m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS],	[AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
+m4_ifndef([_LT_AC_PROG_CXXCPP],		[AC_DEFUN([_LT_AC_PROG_CXXCPP])])
+m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS],	[AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
+m4_ifndef([_LT_PROG_ECHO_BACKSLASH],	[AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_PROG_F77],		[AC_DEFUN([_LT_PROG_F77])])
+m4_ifndef([_LT_PROG_FC],		[AC_DEFUN([_LT_PROG_FC])])
+m4_ifndef([_LT_PROG_CXX],		[AC_DEFUN([_LT_PROG_CXX])])
diff --git a/autostuff/missing b/autostuff/missing
new file mode 100755
index 0000000..db98974
--- /dev/null
+++ b/autostuff/missing
@@ -0,0 +1,215 @@
+#! /bin/sh
+# Common wrapper for a few potentially missing GNU programs.
+
+scriptversion=2013-10-28.13; # UTC
+
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Originally written by Fran,cois Pinard <pinard at iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+  echo 1>&2 "Try '$0 --help' for more information"
+  exit 1
+fi
+
+case $1 in
+
+  --is-lightweight)
+    # Used by our autoconf macros to check whether the available missing
+    # script is modern enough.
+    exit 0
+    ;;
+
+  --run)
+    # Back-compat with the calling convention used by older automake.
+    shift
+    ;;
+
+  -h|--h|--he|--hel|--help)
+    echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
+to PROGRAM being missing or too old.
+
+Options:
+  -h, --help      display this help and exit
+  -v, --version   output version information and exit
+
+Supported PROGRAM values:
+  aclocal   autoconf  autoheader   autom4te  automake  makeinfo
+  bison     yacc      flex         lex       help2man
+
+Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
+'g' are ignored when checking the name.
+
+Send bug reports to <bug-automake at gnu.org>."
+    exit $?
+    ;;
+
+  -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+    echo "missing $scriptversion (GNU Automake)"
+    exit $?
+    ;;
+
+  -*)
+    echo 1>&2 "$0: unknown '$1' option"
+    echo 1>&2 "Try '$0 --help' for more information"
+    exit 1
+    ;;
+
+esac
+
+# Run the given program, remember its exit status.
+"$@"; st=$?
+
+# If it succeeded, we are done.
+test $st -eq 0 && exit 0
+
+# Also exit now if we it failed (or wasn't found), and '--version' was
+# passed; such an option is passed most likely to detect whether the
+# program is present and works.
+case $2 in --version|--help) exit $st;; esac
+
+# Exit code 63 means version mismatch.  This often happens when the user
+# tries to use an ancient version of a tool on a file that requires a
+# minimum version.
+if test $st -eq 63; then
+  msg="probably too old"
+elif test $st -eq 127; then
+  # Program was missing.
+  msg="missing on your system"
+else
+  # Program was found and executed, but failed.  Give up.
+  exit $st
+fi
+
+perl_URL=http://www.perl.org/
+flex_URL=http://flex.sourceforge.net/
+gnu_software_URL=http://www.gnu.org/software
+
+program_details ()
+{
+  case $1 in
+    aclocal|automake)
+      echo "The '$1' program is part of the GNU Automake package:"
+      echo "<$gnu_software_URL/automake>"
+      echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
+      echo "<$gnu_software_URL/autoconf>"
+      echo "<$gnu_software_URL/m4/>"
+      echo "<$perl_URL>"
+      ;;
+    autoconf|autom4te|autoheader)
+      echo "The '$1' program is part of the GNU Autoconf package:"
+      echo "<$gnu_software_URL/autoconf/>"
+      echo "It also requires GNU m4 and Perl in order to run:"
+      echo "<$gnu_software_URL/m4/>"
+      echo "<$perl_URL>"
+      ;;
+  esac
+}
+
+give_advice ()
+{
+  # Normalize program name to check for.
+  normalized_program=`echo "$1" | sed '
+    s/^gnu-//; t
+    s/^gnu//; t
+    s/^g//; t'`
+
+  printf '%s\n' "'$1' is $msg."
+
+  configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
+  case $normalized_program in
+    autoconf*)
+      echo "You should only need it if you modified 'configure.ac',"
+      echo "or m4 files included by it."
+      program_details 'autoconf'
+      ;;
+    autoheader*)
+      echo "You should only need it if you modified 'acconfig.h' or"
+      echo "$configure_deps."
+      program_details 'autoheader'
+      ;;
+    automake*)
+      echo "You should only need it if you modified 'Makefile.am' or"
+      echo "$configure_deps."
+      program_details 'automake'
+      ;;
+    aclocal*)
+      echo "You should only need it if you modified 'acinclude.m4' or"
+      echo "$configure_deps."
+      program_details 'aclocal'
+      ;;
+   autom4te*)
+      echo "You might have modified some maintainer files that require"
+      echo "the 'autom4te' program to be rebuilt."
+      program_details 'autom4te'
+      ;;
+    bison*|yacc*)
+      echo "You should only need it if you modified a '.y' file."
+      echo "You may want to install the GNU Bison package:"
+      echo "<$gnu_software_URL/bison/>"
+      ;;
+    lex*|flex*)
+      echo "You should only need it if you modified a '.l' file."
+      echo "You may want to install the Fast Lexical Analyzer package:"
+      echo "<$flex_URL>"
+      ;;
+    help2man*)
+      echo "You should only need it if you modified a dependency" \
+           "of a man page."
+      echo "You may want to install the GNU Help2man package:"
+      echo "<$gnu_software_URL/help2man/>"
+    ;;
+    makeinfo*)
+      echo "You should only need it if you modified a '.texi' file, or"
+      echo "any other file indirectly affecting the aspect of the manual."
+      echo "You might want to install the Texinfo package:"
+      echo "<$gnu_software_URL/texinfo/>"
+      echo "The spurious makeinfo call might also be the consequence of"
+      echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
+      echo "want to install GNU make:"
+      echo "<$gnu_software_URL/make/>"
+      ;;
+    *)
+      echo "You might have modified some files without having the proper"
+      echo "tools for further handling them.  Check the 'README' file, it"
+      echo "often tells you about the needed prerequisites for installing"
+      echo "this package.  You may also peek at any GNU archive site, in"
+      echo "case some other package contains this missing '$1' program."
+      ;;
+  esac
+}
+
+give_advice "$1" | sed -e '1s/^/WARNING: /' \
+                       -e '2,$s/^/         /' >&2
+
+# Propagate the correct exit status (expected to be 127 for a program
+# not found, 63 for a program that failed due to version mismatch).
+exit $st
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/autostuff/test-driver b/autostuff/test-driver
new file mode 100755
index 0000000..d306056
--- /dev/null
+++ b/autostuff/test-driver
@@ -0,0 +1,139 @@
+#! /bin/sh
+# test-driver - basic testsuite driver script.
+
+scriptversion=2013-07-13.22; # UTC
+
+# Copyright (C) 2011-2013 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake at gnu.org> or send patches to
+# <automake-patches at gnu.org>.
+
+# Make unconditional expansion of undefined variables an error.  This
+# helps a lot in preventing typo-related bugs.
+set -u
+
+usage_error ()
+{
+  echo "$0: $*" >&2
+  print_usage >&2
+  exit 2
+}
+
+print_usage ()
+{
+  cat <<END
+Usage:
+  test-driver --test-name=NAME --log-file=PATH --trs-file=PATH
+              [--expect-failure={yes|no}] [--color-tests={yes|no}]
+              [--enable-hard-errors={yes|no}] [--]
+              TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS]
+The '--test-name', '--log-file' and '--trs-file' options are mandatory.
+END
+}
+
+test_name= # Used for reporting.
+log_file=  # Where to save the output of the test script.
+trs_file=  # Where to save the metadata of the test run.
+expect_failure=no
+color_tests=no
+enable_hard_errors=yes
+while test $# -gt 0; do
+  case $1 in
+  --help) print_usage; exit $?;;
+  --version) echo "test-driver $scriptversion"; exit $?;;
+  --test-name) test_name=$2; shift;;
+  --log-file) log_file=$2; shift;;
+  --trs-file) trs_file=$2; shift;;
+  --color-tests) color_tests=$2; shift;;
+  --expect-failure) expect_failure=$2; shift;;
+  --enable-hard-errors) enable_hard_errors=$2; shift;;
+  --) shift; break;;
+  -*) usage_error "invalid option: '$1'";;
+   *) break;;
+  esac
+  shift
+done
+
+missing_opts=
+test x"$test_name" = x && missing_opts="$missing_opts --test-name"
+test x"$log_file"  = x && missing_opts="$missing_opts --log-file"
+test x"$trs_file"  = x && missing_opts="$missing_opts --trs-file"
+if test x"$missing_opts" != x; then
+  usage_error "the following mandatory options are missing:$missing_opts"
+fi
+
+if test $# -eq 0; then
+  usage_error "missing argument"
+fi
+
+if test $color_tests = yes; then
+  # Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'.
+  red='' # Red.
+  grn='' # Green.
+  lgn='' # Light green.
+  blu='' # Blue.
+  mgn='' # Magenta.
+  std=''     # No color.
+else
+  red= grn= lgn= blu= mgn= std=
+fi
+
+do_exit='rm -f $log_file $trs_file; (exit $st); exit $st'
+trap "st=129; $do_exit" 1
+trap "st=130; $do_exit" 2
+trap "st=141; $do_exit" 13
+trap "st=143; $do_exit" 15
+
+# Test script is run here.
+"$@" >$log_file 2>&1
+estatus=$?
+if test $enable_hard_errors = no && test $estatus -eq 99; then
+  estatus=1
+fi
+
+case $estatus:$expect_failure in
+  0:yes) col=$red res=XPASS recheck=yes gcopy=yes;;
+  0:*)   col=$grn res=PASS  recheck=no  gcopy=no;;
+  77:*)  col=$blu res=SKIP  recheck=no  gcopy=yes;;
+  99:*)  col=$mgn res=ERROR recheck=yes gcopy=yes;;
+  *:yes) col=$lgn res=XFAIL recheck=no  gcopy=yes;;
+  *:*)   col=$red res=FAIL  recheck=yes gcopy=yes;;
+esac
+
+# Report outcome to console.
+echo "${col}${res}${std}: $test_name"
+
+# Register the test result, and other relevant metadata.
+echo ":test-result: $res" > $trs_file
+echo ":global-test-result: $res" >> $trs_file
+echo ":recheck: $recheck" >> $trs_file
+echo ":copy-in-global-log: $gcopy" >> $trs_file
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/backend.c b/backend.c
new file mode 100644
index 0000000..2f51eed
--- /dev/null
+++ b/backend.c
@@ -0,0 +1,399 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010-2012 Bert Vermeulen <bert at biot.com>
+ * Copyright (C) 2012 Peter Stuge <peter at stuge.se>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include "config.h" /* Needed for HAVE_LIBUSB_1_0 and others. */
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+/** @cond PRIVATE */
+#define LOG_PREFIX "backend"
+/** @endcond */
+
+extern struct sr_session *session;
+
+/**
+ * @mainpage libsigrok API
+ *
+ * @section sec_intro Introduction
+ *
+ * The <a href="http://sigrok.org">sigrok</a> project aims at creating a
+ * portable, cross-platform, Free/Libre/Open-Source signal analysis software
+ * suite that supports various device types (such as logic analyzers,
+ * oscilloscopes, multimeters, and more).
+ *
+ * <a href="http://sigrok.org/wiki/Libsigrok">libsigrok</a> is a shared
+ * library written in C which provides the basic API for talking to
+ * <a href="http://sigrok.org/wiki/Supported_hardware">supported hardware</a>
+ * and reading/writing the acquired data into various
+ * <a href="http://sigrok.org/wiki/Input_output_formats">input/output
+ * file formats</a>.
+ *
+ * @section sec_api API reference
+ *
+ * See the "Modules" page for an introduction to various libsigrok
+ * related topics and the detailed API documentation of the respective
+ * functions.
+ *
+ * You can also browse the API documentation by file, or review all
+ * data structures.
+ *
+ * @section sec_mailinglists Mailing lists
+ *
+ * There are two mailing lists for sigrok/libsigrok: <a href="https://lists.sourceforge.net/lists/listinfo/sigrok-devel">sigrok-devel</a> and <a href="https://lists.sourceforge.net/lists/listinfo/sigrok-commits">sigrok-commits</a>.
+ *
+ * @section sec_irc IRC
+ *
+ * You can find the sigrok developers in the
+ * <a href="irc://chat.freenode.net/sigrok">\#sigrok</a>
+ * IRC channel on Freenode.
+ *
+ * @section sec_website Website
+ *
+ * <a href="http://sigrok.org/wiki/Libsigrok">sigrok.org/wiki/Libsigrok</a>
+ */
+
+/**
+ * @file
+ *
+ * Initializing and shutting down libsigrok.
+ */
+
+/**
+ * @defgroup grp_init Initialization
+ *
+ * Initializing and shutting down libsigrok.
+ *
+ * Before using any of the libsigrok functionality, sr_init() must
+ * be called to initialize the library, which will return a struct sr_context
+ * when the initialization was successful.
+ *
+ * When libsigrok functionality is no longer needed, sr_exit() should be
+ * called, which will (among other things) free the struct sr_context.
+ *
+ * Example for a minimal program using libsigrok:
+ *
+ * @code{.c}
+ *   #include <stdio.h>
+ *   #include <libsigrok/libsigrok.h>
+ *
+ *   int main(int argc, char **argv)
+ *   {
+ *   	int ret;
+ *   	struct sr_context *sr_ctx;
+ *
+ *   	if ((ret = sr_init(&sr_ctx)) != SR_OK) {
+ *   		printf("Error initializing libsigrok (%s): %s.\n",
+ *   		       sr_strerror_name(ret), sr_strerror(ret));
+ *   		return 1;
+ *   	}
+ *
+ *   	// Use libsigrok functions here...
+ *
+ *   	if ((ret = sr_exit(sr_ctx)) != SR_OK) {
+ *   		printf("Error shutting down libsigrok (%s): %s.\n",
+ *   		       sr_strerror_name(ret), sr_strerror(ret));
+ *   		return 1;
+ *   	}
+ *
+ *   	return 0;
+ *   }
+ * @endcode
+ *
+ * @{
+ */
+
+/**
+ * Sanity-check all libsigrok drivers.
+ *
+ * @retval SR_OK All drivers are OK
+ * @retval SR_ERR One or more drivers have issues.
+ */
+static int sanity_check_all_drivers(void)
+{
+	int i, errors, ret = SR_OK;
+	struct sr_dev_driver **drivers;
+	const char *d;
+
+	sr_spew("Sanity-checking all drivers.");
+
+	drivers = sr_driver_list();
+	for (i = 0; drivers[i]; i++) {
+		errors = 0;
+
+		d = (drivers[i]->name) ? drivers[i]->name : "NULL";
+
+		if (!drivers[i]->name) {
+			sr_err("No name in driver %d ('%s').", i, d);
+			errors++;
+		}
+		if (!drivers[i]->longname) {
+			sr_err("No longname in driver %d ('%s').", i, d);
+			errors++;
+		}
+		if (drivers[i]->api_version < 1) {
+			sr_err("API version in driver %d ('%s') < 1.", i, d);
+			errors++;
+		}
+		if (!drivers[i]->init) {
+			sr_err("No init in driver %d ('%s').", i, d);
+			errors++;
+		}
+		if (!drivers[i]->cleanup) {
+			sr_err("No cleanup in driver %d ('%s').", i, d);
+			errors++;
+		}
+		if (!drivers[i]->scan) {
+			sr_err("No scan in driver %d ('%s').", i, d);
+			errors++;
+		}
+		if (!drivers[i]->dev_list) {
+			sr_err("No dev_list in driver %d ('%s').", i, d);
+			errors++;
+		}
+		/* Note: config_get() is optional. */
+		if (!drivers[i]->config_set) {
+			sr_err("No config_set in driver %d ('%s').", i, d);
+			errors++;
+		}
+		if (!drivers[i]->config_list) {
+			sr_err("No config_list in driver %d ('%s').", i, d);
+			errors++;
+		}
+		if (!drivers[i]->dev_open) {
+			sr_err("No dev_open in driver %d ('%s').", i, d);
+			errors++;
+		}
+		if (!drivers[i]->dev_close) {
+			sr_err("No dev_close in driver %d ('%s').", i, d);
+			errors++;
+		}
+		if (!drivers[i]->dev_acquisition_start) {
+			sr_err("No dev_acquisition_start in driver %d ('%s').",
+			       i, d);
+			errors++;
+		}
+		if (!drivers[i]->dev_acquisition_stop) {
+			sr_err("No dev_acquisition_stop in driver %d ('%s').",
+			       i, d);
+			errors++;
+		}
+
+		/* Note: 'priv' is allowed to be NULL. */
+
+		if (errors == 0)
+			continue;
+
+		ret = SR_ERR;
+	}
+
+	return ret;
+}
+
+/**
+ * Sanity-check all libsigrok input modules.
+ *
+ * @retval SR_OK All modules are OK
+ * @retval SR_ERR One or more modules have issues.
+ */
+static int sanity_check_all_input_modules(void)
+{
+	int i, errors, ret = SR_OK;
+	struct sr_input_format **inputs;
+	const char *d;
+
+	sr_spew("Sanity-checking all input modules.");
+
+	inputs = sr_input_list();
+	for (i = 0; inputs[i]; i++) {
+		errors = 0;
+
+		d = (inputs[i]->id) ? inputs[i]->id : "NULL";
+
+		if (!inputs[i]->id) {
+			sr_err("No ID in module %d ('%s').", i, d);
+			errors++;
+		}
+		if (!inputs[i]->description) {
+			sr_err("No description in module %d ('%s').", i, d);
+			errors++;
+		}
+		if (!inputs[i]->format_match) {
+			sr_err("No format_match in module %d ('%s').", i, d);
+			errors++;
+		}
+		if (!inputs[i]->init) {
+			sr_err("No init in module %d ('%s').", i, d);
+			errors++;
+		}
+		if (!inputs[i]->loadfile) {
+			sr_err("No loadfile in module %d ('%s').", i, d);
+			errors++;
+		}
+
+		if (errors == 0)
+			continue;
+
+		ret = SR_ERR;
+	}
+
+	return ret;
+}
+
+/**
+ * Sanity-check all libsigrok output modules.
+ *
+ * @retval SR_OK All modules are OK
+ * @retval SR_ERR One or more modules have issues.
+ */
+static int sanity_check_all_output_modules(void)
+{
+	int i, errors, ret = SR_OK;
+	struct sr_output_format **outputs;
+	const char *d;
+
+	sr_spew("Sanity-checking all output modules.");
+
+	outputs = sr_output_list();
+	for (i = 0; outputs[i]; i++) {
+		errors = 0;
+
+		d = (outputs[i]->id) ? outputs[i]->id : "NULL";
+
+		if (!outputs[i]->id) {
+			sr_err("No ID in module %d ('%s').", i, d);
+			errors++;
+		}
+		if (!outputs[i]->description) {
+			sr_err("No description in module '%s'.", d);
+			errors++;
+		}
+		if (!outputs[i]->receive) {
+			sr_err("No receive in module '%s'.", d);
+			errors++;
+		}
+
+		if (errors == 0)
+			continue;
+
+		ret = SR_ERR;
+	}
+
+	return ret;
+}
+
+/**
+ * Initialize libsigrok.
+ *
+ * This function must be called before any other libsigrok function.
+ *
+ * @param ctx Pointer to a libsigrok context struct pointer. Must not be NULL.
+ *            This will be a pointer to a newly allocated libsigrok context
+ *            object upon success, and is undefined upon errors.
+ *
+ * @return SR_OK upon success, a (negative) error code otherwise. Upon errors
+ *         the 'ctx' pointer is undefined and should not be used. Upon success,
+ *         the context will be free'd by sr_exit() as part of the libsigrok
+ *         shutdown.
+ *
+ * @since 0.2.0
+ */
+SR_API int sr_init(struct sr_context **ctx)
+{
+	int ret = SR_ERR;
+	struct sr_context *context;
+
+	if (!ctx) {
+		sr_err("%s(): libsigrok context was NULL.", __func__);
+		return SR_ERR;
+	}
+
+	if (sanity_check_all_drivers() < 0) {
+		sr_err("Internal driver error(s), aborting.");
+		return ret;
+	}
+
+	if (sanity_check_all_input_modules() < 0) {
+		sr_err("Internal input module error(s), aborting.");
+		return ret;
+	}
+
+	if (sanity_check_all_output_modules() < 0) {
+		sr_err("Internal output module error(s), aborting.");
+		return ret;
+	}
+
+	/* + 1 to handle when struct sr_context has no members. */
+	context = g_try_malloc0(sizeof(struct sr_context) + 1);
+
+	if (!context) {
+		ret = SR_ERR_MALLOC;
+		goto done;
+	}
+
+#ifdef HAVE_LIBUSB_1_0
+	ret = libusb_init(&context->libusb_ctx);
+	if (LIBUSB_SUCCESS != ret) {
+		sr_err("libusb_init() returned %s.", libusb_error_name(ret));
+		ret = SR_ERR;
+		goto done;
+	}
+#endif
+
+	*ctx = context;
+	context = NULL;
+	session = NULL;
+	ret = SR_OK;
+
+done:
+	if (context)
+		g_free(context);
+	return ret;
+}
+
+/**
+ * Shutdown libsigrok.
+ *
+ * @param ctx Pointer to a libsigrok context struct. Must not be NULL.
+ *
+ * @retval SR_OK Success
+ * @retval other Error code SR_ERR, ...
+ *
+ * @since 0.2.0
+ */
+SR_API int sr_exit(struct sr_context *ctx)
+{
+	if (!ctx) {
+		sr_err("%s(): libsigrok context was NULL.", __func__);
+		return SR_ERR;
+	}
+
+	sr_hw_cleanup_all();
+
+#ifdef HAVE_LIBUSB_1_0
+	libusb_exit(ctx->libusb_ctx);
+#endif
+
+	g_free(ctx);
+
+	return SR_OK;
+}
+
+/** @} */
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 0000000..79530cd
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,196 @@
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+#ifndef SR_CONFIG_H
+#define SR_CONFIG_H    /* To stop multiple inclusions. */
+
+/* Define if building universal (internal helper macro) */
+#undef AC_APPLE_UNIVERSAL_BUILD
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Agilent DMM support */
+#undef HAVE_HW_AGILENT_DMM
+
+/* APPA 55II support */
+#undef HAVE_HW_APPA_55II
+
+/* ASIX SIGMA/SIGMA2 support */
+#undef HAVE_HW_ASIX_SIGMA
+
+/* Atten PPS3xxx support */
+#undef HAVE_HW_ATTEN_PPS3XXX
+
+/* Brymen BM86X support */
+#undef HAVE_HW_BRYMEN_BM86X
+
+/* Brymen DMM support */
+#undef HAVE_HW_BRYMEN_DMM
+
+/* CEM DT-885x support */
+#undef HAVE_HW_CEM_DT_885X
+
+/* Center 3xx support */
+#undef HAVE_HW_CENTER_3XX
+
+/* ChronoVu LA support */
+#undef HAVE_HW_CHRONOVU_LA
+
+/* Colead SLM support */
+#undef HAVE_HW_COLEAD_SLM
+
+/* Conrad DIGI 35 CPU support */
+#undef HAVE_HW_CONRAD_DIGI_35_CPU
+
+/* Demo driver support */
+#undef HAVE_HW_DEMO
+
+/* Fluke DMM support */
+#undef HAVE_HW_FLUKE_DMM
+
+/* fx2lafw support */
+#undef HAVE_HW_FX2LAFW
+
+/* gmc-mh-1x-2x support */
+#undef HAVE_HW_GMC_MH_1X_2X
+
+/* Hameg HMO support */
+#undef HAVE_HW_HAMEG_HMO
+
+/* Hantek DSO support */
+#undef HAVE_HW_HANTEK_DSO
+
+/* IKALOGIC Scanalogic-2 support */
+#undef HAVE_HW_IKALOGIC_SCANALOGIC2
+
+/* IKALOGIC ScanaPLUS support */
+#undef HAVE_HW_IKALOGIC_SCANAPLUS
+
+/* Kecheng KC-330B support */
+#undef HAVE_HW_KECHENG_KC_330B
+
+/* Lascar EL-USB support */
+#undef HAVE_HW_LASCAR_EL_USB
+
+/* MIC 985xx support */
+#undef HAVE_HW_MIC_985XX
+
+/* Norma DMM support */
+#undef HAVE_HW_NORMA_DMM
+
+/* OpenBench Logic Sniffer (OLS) support */
+#undef HAVE_HW_OLS
+
+/* Rigol DS support */
+#undef HAVE_HW_RIGOL_DS
+
+/* Saleae Logic16 support */
+#undef HAVE_HW_SALEAE_LOGIC16
+
+/* Serial DMM support */
+#undef HAVE_HW_SERIAL_DMM
+
+/* Sysclk LWLA support */
+#undef HAVE_HW_SYSCLK_LWLA
+
+/* Teleinfo support */
+#undef HAVE_HW_TELEINFO
+
+/* Tondaj SL-814 support */
+#undef HAVE_HW_TONDAJ_SL_814
+
+/* UNI-T DMM support */
+#undef HAVE_HW_UNI_T_DMM
+
+/* UNI-T UT32x support */
+#undef HAVE_HW_UNI_T_UT32X
+
+/* Victor DMM support */
+#undef HAVE_HW_VICTOR_DMM
+
+/* ZEROPLUS Logic Cube support */
+#undef HAVE_HW_ZEROPLUS_LOGIC_CUBE
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Specifies whether we have librevisa. */
+#undef HAVE_LIBREVISA
+
+/* Specifies whether we have libserialport. */
+#undef HAVE_LIBSERIALPORT
+
+/* Specifies whether we have a libusb.h header. */
+#undef HAVE_LIBUSB_1_0
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Specifies whether we have RPC support. */
+#undef HAVE_RPC
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#undef LT_OBJDIR
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Version number of package */
+#undef VERSION
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+   significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+#  define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+#  undef WORDS_BIGENDIAN
+# endif
+#endif
+
+#endif /* SR_CONFIG_H */
diff --git a/configure b/configure
new file mode 100755
index 0000000..f3a3310
--- /dev/null
+++ b/configure
@@ -0,0 +1,17330 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69 for libsigrok 0.3.0.
+#
+# Report bugs to <sigrok-devel at lists.sourceforge.net>.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+  # into an infinite loop, continuously re-executing ourselves.
+  if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+    _as_can_reexec=no; export _as_can_reexec;
+    # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+  fi
+  # We don't want this to propagate to other subprocesses.
+          { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+  as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '\${1+\"\$@\"}'='\"\$@\"'
+  setopt NO_GLOB_SUBST
+else
+  case \`(set -o) 2>/dev/null\` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+"
+  as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+  exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+  as_suggested="  as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+  as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+  eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+  test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+
+  test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || (
+    ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+    ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+    ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+    PATH=/empty FPATH=/empty; export PATH FPATH
+    test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\
+      || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1"
+  if (eval "$as_required") 2>/dev/null; then :
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+  if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  as_found=:
+  case $as_dir in #(
+	 /*)
+	   for as_base in sh bash ksh sh5; do
+	     # Try only shells that exist, to save several forks.
+	     as_shell=$as_dir/$as_base
+	     if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+		    { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  CONFIG_SHELL=$as_shell as_have_required=yes
+		   if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+  break 2
+fi
+fi
+	   done;;
+       esac
+  as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+	      { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+  CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+      if test "x$CONFIG_SHELL" != x; then :
+  export CONFIG_SHELL
+             # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+  *v*x* | *x*v* ) as_opts=-vx ;;
+  *v* ) as_opts=-v ;;
+  *x* ) as_opts=-x ;;
+  * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+    if test x$as_have_required = xno; then :
+  $as_echo "$0: This script requires a shell more modern than all"
+  $as_echo "$0: the shells that I found on your system."
+  if test x${ZSH_VERSION+set} = xset ; then
+    $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+    $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+  else
+    $as_echo "$0: Please tell bug-autoconf at gnu.org and
+$0: sigrok-devel at lists.sourceforge.net about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+  fi
+  exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+  as_lineno_1=$LINENO as_lineno_1a=$LINENO
+  as_lineno_2=$LINENO as_lineno_2a=$LINENO
+  eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+  test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+  # Blame Lee E. McMahon (1931-1989) for sed's syntax.  :-)
+  sed -n '
+    p
+    /[$]LINENO/=
+  ' <$as_myself |
+    sed '
+      s/[$]LINENO.*/&-/
+      t lineno
+      b
+      :lineno
+      N
+      :loop
+      s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+      t loop
+      s/-\n.*//
+    ' >$as_me.lineno &&
+  chmod +x "$as_me.lineno" ||
+    { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+  # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+  # already done that, so ensure we don't try to do so again and fall
+  # in an infinite loop.  This has already happened in practice.
+  _as_can_reexec=no; export _as_can_reexec
+  # Don't try to exec as it changes $[0], causing all sort of problems
+  # (the dirname of $[0] is not the place where we might find the
+  # original and so on.  Autoconf is especially sensitive to this).
+  . "./$as_me.lineno"
+  # Exit status is that of the last command.
+  exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME='libsigrok'
+PACKAGE_TARNAME='libsigrok'
+PACKAGE_VERSION='0.3.0'
+PACKAGE_STRING='libsigrok 0.3.0'
+PACKAGE_BUGREPORT='sigrok-devel at lists.sourceforge.net'
+PACKAGE_URL='http://www.sigrok.org'
+
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+#  include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='am__EXEEXT_FALSE
+am__EXEEXT_TRUE
+LTLIBOBJS
+LIBOBJS
+SR_PACKAGE_VERSION
+SR_PACKAGE_VERSION_MICRO
+SR_PACKAGE_VERSION_MINOR
+SR_PACKAGE_VERSION_MAJOR
+AM_LIBTOOLFLAGS
+MAKEFLAGS
+FIRMWARE_DIR
+HW_ZEROPLUS_LOGIC_CUBE_FALSE
+HW_ZEROPLUS_LOGIC_CUBE_TRUE
+HW_VICTOR_DMM_FALSE
+HW_VICTOR_DMM_TRUE
+HW_UNI_T_UT32X_FALSE
+HW_UNI_T_UT32X_TRUE
+HW_UNI_T_DMM_FALSE
+HW_UNI_T_DMM_TRUE
+HW_TONDAJ_SL_814_FALSE
+HW_TONDAJ_SL_814_TRUE
+HW_TELEINFO_FALSE
+HW_TELEINFO_TRUE
+HW_SYSCLK_LWLA_FALSE
+HW_SYSCLK_LWLA_TRUE
+HW_SERIAL_DMM_FALSE
+HW_SERIAL_DMM_TRUE
+HW_SALEAE_LOGIC16_FALSE
+HW_SALEAE_LOGIC16_TRUE
+HW_RIGOL_DS_FALSE
+HW_RIGOL_DS_TRUE
+HW_OLS_FALSE
+HW_OLS_TRUE
+HW_NORMA_DMM_FALSE
+HW_NORMA_DMM_TRUE
+HW_MIC_985XX_FALSE
+HW_MIC_985XX_TRUE
+HW_LASCAR_EL_USB_FALSE
+HW_LASCAR_EL_USB_TRUE
+HW_KECHENG_KC_330B_FALSE
+HW_KECHENG_KC_330B_TRUE
+HW_IKALOGIC_SCANAPLUS_FALSE
+HW_IKALOGIC_SCANAPLUS_TRUE
+HW_IKALOGIC_SCANALOGIC2_FALSE
+HW_IKALOGIC_SCANALOGIC2_TRUE
+HW_HAMEG_HMO_FALSE
+HW_HAMEG_HMO_TRUE
+HW_HANTEK_DSO_FALSE
+HW_HANTEK_DSO_TRUE
+HW_GMC_MH_1X_2X_FALSE
+HW_GMC_MH_1X_2X_TRUE
+HW_FX2LAFW_FALSE
+HW_FX2LAFW_TRUE
+HW_FLUKE_DMM_FALSE
+HW_FLUKE_DMM_TRUE
+HW_DEMO_FALSE
+HW_DEMO_TRUE
+HW_CONRAD_DIGI_35_CPU_FALSE
+HW_CONRAD_DIGI_35_CPU_TRUE
+HW_COLEAD_SLM_FALSE
+HW_COLEAD_SLM_TRUE
+HW_CHRONOVU_LA_FALSE
+HW_CHRONOVU_LA_TRUE
+HW_CENTER_3XX_FALSE
+HW_CENTER_3XX_TRUE
+HW_CEM_DT_885X_FALSE
+HW_CEM_DT_885X_TRUE
+HW_BRYMEN_DMM_FALSE
+HW_BRYMEN_DMM_TRUE
+HW_BRYMEN_BM86X_FALSE
+HW_BRYMEN_BM86X_TRUE
+HW_ATTEN_PPS3XXX_FALSE
+HW_ATTEN_PPS3XXX_TRUE
+HW_ASIX_SIGMA_FALSE
+HW_ASIX_SIGMA_TRUE
+HW_APPA_55II_FALSE
+HW_APPA_55II_TRUE
+HW_AGILENT_DMM_FALSE
+HW_AGILENT_DMM_TRUE
+SR_PKGLIBS
+HAVE_CHECK_FALSE
+HAVE_CHECK_TRUE
+check_LIBS
+check_CFLAGS
+libftdi_LIBS
+libftdi_CFLAGS
+NEED_USB_FALSE
+NEED_USB_TRUE
+libusb_LIBS
+libusb_CFLAGS
+NEED_VISA_FALSE
+NEED_VISA_TRUE
+librevisa_LIBS
+librevisa_CFLAGS
+NEED_SERIAL_FALSE
+NEED_SERIAL_TRUE
+libserialport_LIBS
+libserialport_CFLAGS
+libzip_LIBS
+libzip_CFLAGS
+GLIB_COMPILE_RESOURCES
+GLIB_MKENUMS
+GOBJECT_QUERY
+GLIB_GENMARSHAL
+GLIB_LIBS
+GLIB_CFLAGS
+NEED_RPC_FALSE
+NEED_RPC_TRUE
+SR_LIB_LDFLAGS
+SR_LIB_VERSION
+SR_LIB_VERSION_AGE
+SR_LIB_VERSION_REVISION
+SR_LIB_VERSION_CURRENT
+PKG_CONFIG_LIBDIR
+PKG_CONFIG_PATH
+PKG_CONFIG
+OTOOL64
+OTOOL
+LIPO
+NMEDIT
+DSYMUTIL
+MANIFEST_TOOL
+RANLIB
+DLLTOOL
+OBJDUMP
+NM
+ac_ct_DUMPBIN
+DUMPBIN
+LD
+FGREP
+EGREP
+GREP
+SED
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+LIBTOOL
+LN_S
+CPP
+am__fastdepCC_FALSE
+am__fastdepCC_TRUE
+CCDEPMODE
+am__nodep
+AMDEPBACKSLASH
+AMDEP_FALSE
+AMDEP_TRUE
+am__quote
+am__include
+DEPDIR
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+ac_ct_AR
+AR
+AM_BACKSLASH
+AM_DEFAULT_VERBOSITY
+AM_DEFAULT_V
+AM_V
+am__untar
+am__tar
+AMTAR
+am__leading_dot
+SET_MAKE
+AWK
+mkdir_p
+MKDIR_P
+INSTALL_STRIP_PROGRAM
+STRIP
+install_sh
+MAKEINFO
+AUTOHEADER
+AUTOMAKE
+AUTOCONF
+ACLOCAL
+VERSION
+PACKAGE
+CYGPATH_W
+am__isrc
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_silent_rules
+enable_dependency_tracking
+enable_shared
+enable_static
+with_pic
+enable_fast_install
+with_gnu_ld
+with_sysroot
+enable_libtool_lock
+enable_all_drivers
+enable_agilent_dmm
+enable_appa_55ii
+enable_asix_sigma
+enable_atten_pps3xxx
+enable_brymen_bm86x
+enable_brymen_dmm
+enable_cem_dt_885x
+enable_center_3xx
+enable_chronovu_la
+enable_colead_slm
+enable_conrad_digi_35_cpu
+enable_demo
+enable_fluke_dmm
+enable_fx2lafw
+enable_gmc_mh_1x_2x
+enable_hameg_hmo
+enable_hantek_dso
+enable_ikalogic_scanalogic2
+enable_ikalogic_scanaplus
+enable_kecheng_kc_330b
+enable_lascar_el_usb
+enable_mic_985xx
+enable_norma_dmm
+enable_ols
+enable_rigol_ds
+enable_saleae_logic16
+enable_serial_dmm
+enable_sysclk_lwla
+enable_teleinfo
+enable_tondaj_sl_814
+enable_uni_t_dmm
+enable_uni_t_ut32x
+enable_victor_dmm
+enable_zeroplus_logic_cube
+enable_glibtest
+'
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP
+PKG_CONFIG
+PKG_CONFIG_PATH
+PKG_CONFIG_LIBDIR
+libzip_CFLAGS
+libzip_LIBS
+libserialport_CFLAGS
+libserialport_LIBS
+librevisa_CFLAGS
+librevisa_LIBS
+libusb_CFLAGS
+libusb_LIBS
+libftdi_CFLAGS
+libftdi_LIBS
+check_CFLAGS
+check_LIBS'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+  # If the previous option needs an argument, assign it.
+  if test -n "$ac_prev"; then
+    eval $ac_prev=\$ac_option
+    ac_prev=
+    continue
+  fi
+
+  case $ac_option in
+  *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+  *=)   ac_optarg= ;;
+  *)    ac_optarg=yes ;;
+  esac
+
+  # Accept the important Cygnus configure options, so we can diagnose typos.
+
+  case $ac_dashdash$ac_option in
+  --)
+    ac_dashdash=yes ;;
+
+  -bindir | --bindir | --bindi | --bind | --bin | --bi)
+    ac_prev=bindir ;;
+  -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+    bindir=$ac_optarg ;;
+
+  -build | --build | --buil | --bui | --bu)
+    ac_prev=build_alias ;;
+  -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+    build_alias=$ac_optarg ;;
+
+  -cache-file | --cache-file | --cache-fil | --cache-fi \
+  | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+    ac_prev=cache_file ;;
+  -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+  | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+    cache_file=$ac_optarg ;;
+
+  --config-cache | -C)
+    cache_file=config.cache ;;
+
+  -datadir | --datadir | --datadi | --datad)
+    ac_prev=datadir ;;
+  -datadir=* | --datadir=* | --datadi=* | --datad=*)
+    datadir=$ac_optarg ;;
+
+  -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+  | --dataroo | --dataro | --datar)
+    ac_prev=datarootdir ;;
+  -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+  | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+    datarootdir=$ac_optarg ;;
+
+  -disable-* | --disable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=no ;;
+
+  -docdir | --docdir | --docdi | --doc | --do)
+    ac_prev=docdir ;;
+  -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+    docdir=$ac_optarg ;;
+
+  -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+    ac_prev=dvidir ;;
+  -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+    dvidir=$ac_optarg ;;
+
+  -enable-* | --enable-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid feature name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"enable_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval enable_$ac_useropt=\$ac_optarg ;;
+
+  -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+  | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+  | --exec | --exe | --ex)
+    ac_prev=exec_prefix ;;
+  -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+  | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+  | --exec=* | --exe=* | --ex=*)
+    exec_prefix=$ac_optarg ;;
+
+  -gas | --gas | --ga | --g)
+    # Obsolete; use --with-gas.
+    with_gas=yes ;;
+
+  -help | --help | --hel | --he | -h)
+    ac_init_help=long ;;
+  -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+    ac_init_help=recursive ;;
+  -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+    ac_init_help=short ;;
+
+  -host | --host | --hos | --ho)
+    ac_prev=host_alias ;;
+  -host=* | --host=* | --hos=* | --ho=*)
+    host_alias=$ac_optarg ;;
+
+  -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+    ac_prev=htmldir ;;
+  -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+  | --ht=*)
+    htmldir=$ac_optarg ;;
+
+  -includedir | --includedir | --includedi | --included | --include \
+  | --includ | --inclu | --incl | --inc)
+    ac_prev=includedir ;;
+  -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+  | --includ=* | --inclu=* | --incl=* | --inc=*)
+    includedir=$ac_optarg ;;
+
+  -infodir | --infodir | --infodi | --infod | --info | --inf)
+    ac_prev=infodir ;;
+  -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+    infodir=$ac_optarg ;;
+
+  -libdir | --libdir | --libdi | --libd)
+    ac_prev=libdir ;;
+  -libdir=* | --libdir=* | --libdi=* | --libd=*)
+    libdir=$ac_optarg ;;
+
+  -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+  | --libexe | --libex | --libe)
+    ac_prev=libexecdir ;;
+  -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+  | --libexe=* | --libex=* | --libe=*)
+    libexecdir=$ac_optarg ;;
+
+  -localedir | --localedir | --localedi | --localed | --locale)
+    ac_prev=localedir ;;
+  -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+    localedir=$ac_optarg ;;
+
+  -localstatedir | --localstatedir | --localstatedi | --localstated \
+  | --localstate | --localstat | --localsta | --localst | --locals)
+    ac_prev=localstatedir ;;
+  -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+  | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+    localstatedir=$ac_optarg ;;
+
+  -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+    ac_prev=mandir ;;
+  -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+    mandir=$ac_optarg ;;
+
+  -nfp | --nfp | --nf)
+    # Obsolete; use --without-fp.
+    with_fp=no ;;
+
+  -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+  | --no-cr | --no-c | -n)
+    no_create=yes ;;
+
+  -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+  | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+    no_recursion=yes ;;
+
+  -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+  | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+  | --oldin | --oldi | --old | --ol | --o)
+    ac_prev=oldincludedir ;;
+  -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+  | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+  | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+    oldincludedir=$ac_optarg ;;
+
+  -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+    ac_prev=prefix ;;
+  -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+    prefix=$ac_optarg ;;
+
+  -program-prefix | --program-prefix | --program-prefi | --program-pref \
+  | --program-pre | --program-pr | --program-p)
+    ac_prev=program_prefix ;;
+  -program-prefix=* | --program-prefix=* | --program-prefi=* \
+  | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+    program_prefix=$ac_optarg ;;
+
+  -program-suffix | --program-suffix | --program-suffi | --program-suff \
+  | --program-suf | --program-su | --program-s)
+    ac_prev=program_suffix ;;
+  -program-suffix=* | --program-suffix=* | --program-suffi=* \
+  | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+    program_suffix=$ac_optarg ;;
+
+  -program-transform-name | --program-transform-name \
+  | --program-transform-nam | --program-transform-na \
+  | --program-transform-n | --program-transform- \
+  | --program-transform | --program-transfor \
+  | --program-transfo | --program-transf \
+  | --program-trans | --program-tran \
+  | --progr-tra | --program-tr | --program-t)
+    ac_prev=program_transform_name ;;
+  -program-transform-name=* | --program-transform-name=* \
+  | --program-transform-nam=* | --program-transform-na=* \
+  | --program-transform-n=* | --program-transform-=* \
+  | --program-transform=* | --program-transfor=* \
+  | --program-transfo=* | --program-transf=* \
+  | --program-trans=* | --program-tran=* \
+  | --progr-tra=* | --program-tr=* | --program-t=*)
+    program_transform_name=$ac_optarg ;;
+
+  -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+    ac_prev=pdfdir ;;
+  -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+    pdfdir=$ac_optarg ;;
+
+  -psdir | --psdir | --psdi | --psd | --ps)
+    ac_prev=psdir ;;
+  -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+    psdir=$ac_optarg ;;
+
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil)
+    silent=yes ;;
+
+  -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+    ac_prev=sbindir ;;
+  -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+  | --sbi=* | --sb=*)
+    sbindir=$ac_optarg ;;
+
+  -sharedstatedir | --sharedstatedir | --sharedstatedi \
+  | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+  | --sharedst | --shareds | --shared | --share | --shar \
+  | --sha | --sh)
+    ac_prev=sharedstatedir ;;
+  -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+  | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+  | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+  | --sha=* | --sh=*)
+    sharedstatedir=$ac_optarg ;;
+
+  -site | --site | --sit)
+    ac_prev=site ;;
+  -site=* | --site=* | --sit=*)
+    site=$ac_optarg ;;
+
+  -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+    ac_prev=srcdir ;;
+  -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+    srcdir=$ac_optarg ;;
+
+  -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+  | --syscon | --sysco | --sysc | --sys | --sy)
+    ac_prev=sysconfdir ;;
+  -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+  | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+    sysconfdir=$ac_optarg ;;
+
+  -target | --target | --targe | --targ | --tar | --ta | --t)
+    ac_prev=target_alias ;;
+  -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+    target_alias=$ac_optarg ;;
+
+  -v | -verbose | --verbose | --verbos | --verbo | --verb)
+    verbose=yes ;;
+
+  -version | --version | --versio | --versi | --vers | -V)
+    ac_init_version=: ;;
+
+  -with-* | --with-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+      as_fn_error $? "invalid package name: $ac_useropt"
+    ac_useropt_orig=$ac_useropt
+    ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+    case $ac_user_opts in
+      *"
+"with_$ac_useropt"
+"*) ;;
+      *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+	 ac_unrecognized_sep=', ';;
+    esac
+    eval with_$ac_useropt=no ;;
+
+  --x)
+    # Obsolete; use --with-x.
+    with_x=yes ;;
+
+  -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+  | --x-incl | --x-inc | --x-in | --x-i)
+    ac_prev=x_includes ;;
+  -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+  | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+    x_includes=$ac_optarg ;;
+
+  -x-libraries | --x-libraries | --x-librarie | --x-librari \
+  | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+    ac_prev=x_libraries ;;
+  -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+  | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+    x_libraries=$ac_optarg ;;
+
+  -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    case $ac_envvar in #(
+      '' | [0-9]* | *[!_$as_cr_alnum]* )
+      as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+    esac
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+    : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+    ;;
+
+  esac
+done
+
+if test -n "$ac_prev"; then
+  ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+  as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+  case $enable_option_checking in
+    no) ;;
+    fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+    *)     $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+  esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
+		datadir sysconfdir sharedstatedir localstatedir includedir \
+		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+		libdir localedir mandir
+do
+  eval ac_val=\$$ac_var
+  # Remove trailing slashes.
+  case $ac_val in
+    */ )
+      ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+      eval $ac_var=\$ac_val;;
+  esac
+  # Be sure to have absolute directory names.
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+  if test "x$build_alias" = x; then
+    cross_compiling=maybe
+  elif test "x$build_alias" != "x$host_alias"; then
+    cross_compiling=yes
+  fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+  as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+  ac_srcdir_defaulted=yes
+  # Try the directory containing this script, then the parent directory.
+  ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_myself" : 'X\(//\)[^/]' \| \
+	 X"$as_myself" : 'X\(//\)$' \| \
+	 X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  srcdir=$ac_confdir
+  if test ! -r "$srcdir/$ac_unique_file"; then
+    srcdir=..
+  fi
+else
+  ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+  test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+  as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+	cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+	pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+  srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+  eval ac_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_env_${ac_var}_value=\$${ac_var}
+  eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+  eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+  # Omit some internal or obsolete options to make the list less imposing.
+  # This message is too long to be a string in the A/UX 3.1 sh.
+  cat <<_ACEOF
+\`configure' configures libsigrok 0.3.0 to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE.  See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+  -h, --help              display this help and exit
+      --help=short        display options specific to this package
+      --help=recursive    display the short help of all the included packages
+  -V, --version           display version information and exit
+  -q, --quiet, --silent   do not print \`checking ...' messages
+      --cache-file=FILE   cache test results in FILE [disabled]
+  -C, --config-cache      alias for \`--cache-file=config.cache'
+  -n, --no-create         do not create output files
+      --srcdir=DIR        find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+  --prefix=PREFIX         install architecture-independent files in PREFIX
+                          [$ac_default_prefix]
+  --exec-prefix=EPREFIX   install architecture-dependent files in EPREFIX
+                          [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc.  You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+  --bindir=DIR            user executables [EPREFIX/bin]
+  --sbindir=DIR           system admin executables [EPREFIX/sbin]
+  --libexecdir=DIR        program executables [EPREFIX/libexec]
+  --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
+  --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
+  --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --libdir=DIR            object code libraries [EPREFIX/lib]
+  --includedir=DIR        C header files [PREFIX/include]
+  --oldincludedir=DIR     C header files for non-gcc [/usr/include]
+  --datarootdir=DIR       read-only arch.-independent data root [PREFIX/share]
+  --datadir=DIR           read-only architecture-independent data [DATAROOTDIR]
+  --infodir=DIR           info documentation [DATAROOTDIR/info]
+  --localedir=DIR         locale-dependent data [DATAROOTDIR/locale]
+  --mandir=DIR            man documentation [DATAROOTDIR/man]
+  --docdir=DIR            documentation root [DATAROOTDIR/doc/libsigrok]
+  --htmldir=DIR           html documentation [DOCDIR]
+  --dvidir=DIR            dvi documentation [DOCDIR]
+  --pdfdir=DIR            pdf documentation [DOCDIR]
+  --psdir=DIR             ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+
+Program names:
+  --program-prefix=PREFIX            prepend PREFIX to installed program names
+  --program-suffix=SUFFIX            append SUFFIX to installed program names
+  --program-transform-name=PROGRAM   run sed PROGRAM on installed program names
+
+System types:
+  --build=BUILD     configure for building on BUILD [guessed]
+  --host=HOST       cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+  case $ac_init_help in
+     short | recursive ) echo "Configuration of libsigrok 0.3.0:";;
+   esac
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-option-checking  ignore unrecognized --enable/--with options
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --enable-silent-rules   less verbose build output (undo: "make V=1")
+  --disable-silent-rules  verbose build output (undo: "make V=0")
+  --enable-dependency-tracking
+                          do not reject slow dependency extractors
+  --disable-dependency-tracking
+                          speeds up one-time build
+  --enable-shared[=PKGS]  build shared libraries [default=yes]
+  --enable-static[=PKGS]  build static libraries [default=yes]
+  --enable-fast-install[=PKGS]
+                          optimize for fast installation [default=yes]
+  --disable-libtool-lock  avoid locking (might break parallel builds)
+  --enable-all-drivers    enable all drivers by default [default=yes]
+  --enable-agilent-dmm    enable Agilent DMM support [default=yes]
+  --enable-appa-55ii      enable APPA 55II support [default=yes]
+  --enable-asix-sigma     enable ASIX SIGMA/SIGMA2 support [default=yes]
+  --enable-atten-pps3xxx  enable Atten PPS3xxx support [default=yes]
+  --enable-brymen-bm86x   enable Brymen BM86X support [default=yes]
+  --enable-brymen-dmm     enable Brymen DMM support [default=yes]
+  --enable-cem-dt-885x    enable CEM DT-885x support [default=yes]
+  --enable-center-3xx     enable Center 3xx support [default=yes]
+  --enable-chronovu-la    enable ChronoVu LA support [default=yes]
+  --enable-colead-slm     enable Colead SLM support [default=yes]
+  --enable-conrad-digi-35-cpu
+                          enable Conrad DIGI 35 CPU support [default=yes]
+  --enable-demo           enable demo driver support [default=yes]
+  --enable-fluke-dmm      enable Fluke DMM support [default=yes]
+  --enable-fx2lafw        enable fx2lafw support (for FX2 LAs). [default=yes]
+  --enable-gmc-mh-1x-2x   enable gmc-mh-1x-2x support [default=yes]
+  --enable-hameg-hmo      enable Hameg HMO support [default=yes]
+  --enable-hantek-dso     enable Hantek DSO support [default=yes]
+  --enable-ikalogic-scanalogic2
+                          enable IKALOGIC Scanalogic-2 support [default=yes]
+  --enable-ikalogic-scanaplus
+                          enable IKALOGIC ScanaPLUS support [default=yes]
+  --enable-kecheng-kc-330b
+                          enable Kecheng KC-330B support [default=yes]
+  --enable-lascar-el-usb  enable Lascar EL-USB support [default=yes]
+  --enable-mic-985xx      enable MIC 985xx support [default=yes]
+  --enable-norma-dmm      enable Norma DMM support [default=yes]
+  --enable-ols            enable OpenBench Logic Sniffer (OLS) support
+                          [default=yes]
+  --enable-rigol-ds       enable Rigol DS support [default=yes]
+  --enable-saleae-logic16 enable Saleae Logic16 support [default=yes]
+  --enable-serial-dmm     enable serial DMM support [default=yes]
+  --enable-sysclk-lwla    enable Sysclk LWLA support [default=yes]
+  --enable-teleinfo       enable Teleinfo support [default=yes]
+  --enable-tondaj-sl-814  enable Tondaj SL-814 support [default=yes]
+  --enable-uni-t-dmm      enable UNI-T DMM support [default=yes]
+  --enable-uni-t-ut32x    enable UNI-T UT32x support [default=yes]
+  --enable-victor-dmm     enable victor-dmm support [default=yes]
+  --enable-zeroplus-logic-cube
+                          enable ZEROPLUS Logic Cube support [default=yes]
+  --disable-glibtest      do not try to compile and run a test GLIB program
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-pic[=PKGS]       try to use only PIC/non-PIC objects [default=use
+                          both]
+  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
+  --with-sysroot=DIR Search for dependent libraries within DIR
+                        (or the compiler's sysroot if not specified).
+
+Some influential environment variables:
+  CC          C compiler command
+  CFLAGS      C compiler flags
+  LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
+              nonstandard directory <lib dir>
+  LIBS        libraries to pass to the linker, e.g. -l<library>
+  CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
+  CPP         C preprocessor
+  PKG_CONFIG  path to pkg-config utility
+  PKG_CONFIG_PATH
+              directories to add to pkg-config's search path
+  PKG_CONFIG_LIBDIR
+              path overriding pkg-config's built-in search path
+  libzip_CFLAGS
+              C compiler flags for libzip, overriding pkg-config
+  libzip_LIBS linker flags for libzip, overriding pkg-config
+  libserialport_CFLAGS
+              C compiler flags for libserialport, overriding pkg-config
+  libserialport_LIBS
+              linker flags for libserialport, overriding pkg-config
+  librevisa_CFLAGS
+              C compiler flags for librevisa, overriding pkg-config
+  librevisa_LIBS
+              linker flags for librevisa, overriding pkg-config
+  libusb_CFLAGS
+              C compiler flags for libusb, overriding pkg-config
+  libusb_LIBS linker flags for libusb, overriding pkg-config
+  libftdi_CFLAGS
+              C compiler flags for libftdi, overriding pkg-config
+  libftdi_LIBS
+              linker flags for libftdi, overriding pkg-config
+  check_CFLAGS
+              C compiler flags for check, overriding pkg-config
+  check_LIBS  linker flags for check, overriding pkg-config
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to <sigrok-devel at lists.sourceforge.net>.
+libsigrok home page: <http://www.sigrok.org>.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+  # If there are subdirs, report their specific --help.
+  for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+    test -d "$ac_dir" ||
+      { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+      continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+    cd "$ac_dir" || { ac_status=$?; continue; }
+    # Check for guested configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+    elif test -f "$ac_srcdir/configure"; then
+      echo &&
+      $SHELL "$ac_srcdir/configure" --help=recursive
+    else
+      $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+    fi || ac_status=$?
+    cd "$ac_pwd" || { ac_status=$?; break; }
+  done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+  cat <<\_ACEOF
+libsigrok configure 0.3.0
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+  exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext
+  if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } > conftest.i && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+    ac_retval=1
+fi
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext conftest$ac_exeext
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+	 test "$cross_compiling" = yes ||
+	 test -x conftest$ac_exeext
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_retval=1
+fi
+  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+  # interfere with the next link command; also delete a directory that is
+  # left behind by Apple's compiler.  We do this before executing the actions.
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: program exited with status $ac_status" >&5
+       $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=$ac_status
+fi
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $2 (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by libsigrok $as_me 0.3.0, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
+
+  $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X     = `(/bin/uname -X) 2>/dev/null     || echo unknown`
+
+/bin/arch              = `(/bin/arch) 2>/dev/null              || echo unknown`
+/usr/bin/arch -k       = `(/usr/bin/arch -k) 2>/dev/null       || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo      = `(/usr/bin/hostinfo) 2>/dev/null      || echo unknown`
+/bin/machine           = `(/bin/machine) 2>/dev/null           || echo unknown`
+/usr/bin/oslevel       = `(/usr/bin/oslevel) 2>/dev/null       || echo unknown`
+/bin/universe          = `(/bin/universe) 2>/dev/null          || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    $as_echo "PATH: $as_dir"
+  done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+  for ac_arg
+  do
+    case $ac_arg in
+    -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+    -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+    | -silent | --silent | --silen | --sile | --sil)
+      continue ;;
+    *\'*)
+      ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+    2)
+      as_fn_append ac_configure_args1 " '$ac_arg'"
+      if test $ac_must_keep_next = true; then
+	ac_must_keep_next=false # Got value, back to normal.
+      else
+	case $ac_arg in
+	  *=* | --config-cache | -C | -disable-* | --disable-* \
+	  | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+	  | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+	  | -with-* | --with-* | -without-* | --without-* | --x)
+	    case "$ac_configure_args0 " in
+	      "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+	    esac
+	    ;;
+	  -* ) ac_must_keep_next=true ;;
+	esac
+      fi
+      as_fn_append ac_configure_args " '$ac_arg'"
+      ;;
+    esac
+  done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log.  We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+  # Save into config.log some information that might help in debugging.
+  {
+    echo
+
+    $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+    echo
+    # The following way of writing the cache mishandles newlines in values,
+(
+  for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+  (set) 2>&1 |
+    case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      sed -n \
+	"s/'\''/'\''\\\\'\'''\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+      ;; #(
+    *)
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+)
+    echo
+
+    $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      $as_echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+      echo
+      for ac_var in $ac_subst_files
+      do
+	eval ac_val=\$$ac_var
+	case $ac_val in
+	*\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+	esac
+	$as_echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      $as_echo "$as_me: caught signal $ac_signal"
+    $as_echo "$as_me: exit $exit_status"
+  } >&5
+  rm -f core *.core core.conftest.* &&
+    rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+    exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+  trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+  # We do not want a PATH search for config.site.
+  case $CONFIG_SITE in #((
+    -*)  ac_site_file1=./$CONFIG_SITE;;
+    */*) ac_site_file1=$CONFIG_SITE;;
+    *)   ac_site_file1=./$CONFIG_SITE;;
+  esac
+elif test "x$prefix" != xNONE; then
+  ac_site_file1=$prefix/share/config.site
+  ac_site_file2=$prefix/etc/config.site
+else
+  ac_site_file1=$ac_default_prefix/share/config.site
+  ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+  test "x$ac_site_file" = xNONE && continue
+  if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file" \
+      || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+  fi
+done
+
+if test -r "$cache_file"; then
+  # Some versions of bash will fail to source /dev/null (special files
+  # actually), so we avoid doing that.  DJGPP emulates it as a regular file.
+  if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+  >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+  eval ac_old_set=\$ac_cv_env_${ac_var}_set
+  eval ac_new_set=\$ac_env_${ac_var}_set
+  eval ac_old_val=\$ac_cv_env_${ac_var}_value
+  eval ac_new_val=\$ac_env_${ac_var}_value
+  case $ac_old_set,$ac_new_set in
+    set,)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,);;
+    *)
+      if test "x$ac_old_val" != "x$ac_new_val"; then
+	# differences in whitespace do not lead to failure.
+	ac_old_val_w=`echo x $ac_old_val`
+	ac_new_val_w=`echo x $ac_new_val`
+	if test "$ac_old_val_w" != "$ac_new_val_w"; then
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+	  ac_cache_corrupted=:
+	else
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+	  eval $ac_var=\$ac_old_val
+	fi
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   former value:  \`$ac_old_val'" >&5
+$as_echo "$as_me:   former value:  \`$ac_old_val'" >&2;}
+	{ $as_echo "$as_me:${as_lineno-$LINENO}:   current value: \`$ac_new_val'" >&5
+$as_echo "$as_me:   current value: \`$ac_new_val'" >&2;}
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+    *) ac_arg=$ac_var=$ac_new_val ;;
+    esac
+    case " $ac_configure_args " in
+      *" '$ac_arg' "*) ;; # Avoid dups.  Use of quotes ensures accuracy.
+      *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+  { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+
+ac_aux_dir=
+for ac_dir in autostuff "$srcdir"/autostuff; do
+  if test -f "$ac_dir/install-sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install-sh -c"
+    break
+  elif test -f "$ac_dir/install.sh"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/install.sh -c"
+    break
+  elif test -f "$ac_dir/shtool"; then
+    ac_aux_dir=$ac_dir
+    ac_install_sh="$ac_aux_dir/shtool install -c"
+    break
+  fi
+done
+if test -z "$ac_aux_dir"; then
+  as_fn_error $? "cannot find install-sh, install.sh, or shtool in autostuff \"$srcdir\"/autostuff" "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"  # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"  # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure"  # Please don't use this var.
+
+
+
+# We require at least automake 1.11 (needed for 'silent rules').
+am__api_version='1.14'
+
+# Find a good install program.  We prefer a C program (faster),
+# so one script is as good as another.  But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if ${ac_cv_path_install+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+  ./ | .// | /[cC]/* | \
+  /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+  ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+  /usr/ucb/* ) ;;
+  *)
+    # OSF1 and SCO ODT 3.0 have their own names for install.
+    # Don't use installbsd from OSF since it installs stuff as root
+    # by default.
+    for ac_prog in ginstall scoinst install; do
+      for ac_exec_ext in '' $ac_executable_extensions; do
+	if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+	  if test $ac_prog = install &&
+	    grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # AIX install.  It has an incompatible calling convention.
+	    :
+	  elif test $ac_prog = install &&
+	    grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+	    # program-specific install script used by HP pwplus--don't use.
+	    :
+	  else
+	    rm -rf conftest.one conftest.two conftest.dir
+	    echo one > conftest.one
+	    echo two > conftest.two
+	    mkdir conftest.dir
+	    if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+	      test -s conftest.one && test -s conftest.two &&
+	      test -s conftest.dir/conftest.one &&
+	      test -s conftest.dir/conftest.two
+	    then
+	      ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+	      break 3
+	    fi
+	  fi
+	fi
+      done
+    done
+    ;;
+esac
+
+  done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+  if test "${ac_cv_path_install+set}" = set; then
+    INSTALL=$ac_cv_path_install
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for INSTALL within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    INSTALL=$ac_install_sh
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
+$as_echo_n "checking whether build environment is sane... " >&6; }
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name.  Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+  *[\\\"\#\$\&\'\`$am_lf]*)
+    as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;;
+esac
+case $srcdir in
+  *[\\\"\#\$\&\'\`$am_lf\ \	]*)
+    as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments.  Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+   am_has_slept=no
+   for am_try in 1 2; do
+     echo "timestamp, slept: $am_has_slept" > conftest.file
+     set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+     if test "$*" = "X"; then
+	# -L didn't work.
+	set X `ls -t "$srcdir/configure" conftest.file`
+     fi
+     if test "$*" != "X $srcdir/configure conftest.file" \
+	&& test "$*" != "X conftest.file $srcdir/configure"; then
+
+	# If neither matched, then we have a broken ls.  This can happen
+	# if, for instance, CONFIG_SHELL is bash and it inherits a
+	# broken ls alias from the environment.  This has actually
+	# happened.  Such a system could not be considered "sane".
+	as_fn_error $? "ls -t appears to fail.  Make sure there is not a broken
+  alias in your environment" "$LINENO" 5
+     fi
+     if test "$2" = conftest.file || test $am_try -eq 2; then
+       break
+     fi
+     # Just in case.
+     sleep 1
+     am_has_slept=yes
+   done
+   test "$2" = conftest.file
+   )
+then
+   # Ok.
+   :
+else
+   as_fn_error $? "newly created file is older than distributed files!
+Check your system clock" "$LINENO" 5
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+  ( sleep 1 ) &
+  am_sleep_pid=$!
+fi
+
+rm -f conftest.file
+
+test "$program_prefix" != NONE &&
+  program_transform_name="s&^&$program_prefix&;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+  program_transform_name="s&\$&$program_suffix&;$program_transform_name"
+# Double any \ or $.
+# By default was `s,x,x', remove it if useless.
+ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
+program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
+
+# expand $ac_aux_dir to an absolute path
+am_aux_dir=`cd $ac_aux_dir && pwd`
+
+if test x"${MISSING+set}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+  *)
+    MISSING="\${SHELL} $am_aux_dir/missing" ;;
+  esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+  am_missing_run="$MISSING "
+else
+  am_missing_run=
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5
+$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;}
+fi
+
+if test x"${install_sh}" != xset; then
+  case $am_aux_dir in
+  *\ * | *\	*)
+    install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+  *)
+    install_sh="\${SHELL} $am_aux_dir/install-sh"
+  esac
+fi
+
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip".  However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+if test "$cross_compiling" != no; then
+  if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$STRIP"; then
+  ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+  ac_ct_STRIP=$STRIP
+  # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_STRIP"; then
+  ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_STRIP="strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_STRIP" = x; then
+    STRIP=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    STRIP=$ac_ct_STRIP
+  fi
+else
+  STRIP="$ac_cv_prog_STRIP"
+fi
+
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5
+$as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
+if test -z "$MKDIR_P"; then
+  if ${ac_cv_path_mkdir+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in mkdir gmkdir; do
+	 for ac_exec_ext in '' $ac_executable_extensions; do
+	   as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue
+	   case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
+	     'mkdir (GNU coreutils) '* | \
+	     'mkdir (coreutils) '* | \
+	     'mkdir (fileutils) '4.1*)
+	       ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
+	       break 3;;
+	   esac
+	 done
+       done
+  done
+IFS=$as_save_IFS
+
+fi
+
+  test -d ./--version && rmdir ./--version
+  if test "${ac_cv_path_mkdir+set}" = set; then
+    MKDIR_P="$ac_cv_path_mkdir -p"
+  else
+    # As a last resort, use the slow shell script.  Don't cache a
+    # value for MKDIR_P within a source directory, because that will
+    # break other packages using the cache if that directory is
+    # removed, or if the value is a relative name.
+    MKDIR_P="$ac_install_sh -d"
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
+$as_echo "$MKDIR_P" >&6; }
+
+for ac_prog in gawk mawk nawk awk
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AWK+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AWK"; then
+  ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_AWK="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$AWK" && break
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+	@echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+  *@@@%%%=?*=@@@%%%*)
+    eval ac_cv_prog_make_${ac_make}_set=yes;;
+  *)
+    eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+  SET_MAKE=
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+  SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+  am__leading_dot=.
+else
+  am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+
+# Check whether --enable-silent-rules was given.
+if test "${enable_silent_rules+set}" = set; then :
+  enableval=$enable_silent_rules;
+fi
+
+case $enable_silent_rules in # (((
+  yes) AM_DEFAULT_VERBOSITY=0;;
+   no) AM_DEFAULT_VERBOSITY=1;;
+    *) AM_DEFAULT_VERBOSITY=1;;
+esac
+am_make=${MAKE-make}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
+$as_echo_n "checking whether $am_make supports nested variables... " >&6; }
+if ${am_cv_make_support_nested_variables+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if $as_echo 'TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+	@$(TRUE)
+.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then
+  am_cv_make_support_nested_variables=yes
+else
+  am_cv_make_support_nested_variables=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
+$as_echo "$am_cv_make_support_nested_variables" >&6; }
+if test $am_cv_make_support_nested_variables = yes; then
+    AM_V='$(V)'
+  AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+  AM_V=$AM_DEFAULT_VERBOSITY
+  AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AM_BACKSLASH='\'
+
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+  # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+  # is not polluted with repeated "-I."
+  am__isrc=' -I$(srcdir)'
+  # test to see if srcdir already configured
+  if test -f $srcdir/config.status; then
+    as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5
+  fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+  if (cygpath --version) >/dev/null 2>/dev/null; then
+    CYGPATH_W='cygpath -w'
+  else
+    CYGPATH_W=echo
+  fi
+fi
+
+
+# Define the identity of the package.
+ PACKAGE='libsigrok'
+ VERSION='0.3.0'
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE "$PACKAGE"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define VERSION "$VERSION"
+_ACEOF
+
+# Some tools Automake needs.
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+# For better backward compatibility.  To be removed once Automake 1.9.x
+# dies out for good.  For more background, see:
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
+mkdir_p='$(MKDIR_P)'
+
+# We need awk for the "check" target.  The system "awk" is bad on
+# some platforms.
+# Always define AMTAR for backward compatibility.  Yes, it's still used
+# in the wild :-(  We should find a proper way to deprecate it ...
+AMTAR='$${TAR-tar}'
+
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar  pax cpio none'
+
+am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'
+
+
+
+
+
+
+# POSIX will say in a future version that running "rm -f" with no argument
+# is OK; and we want to be able to make that assumption in our Makefile
+# recipes.  So use an aggressive probe to check that the usage we want is
+# actually supported "in the wild" to an acceptable degree.
+# See automake bug#10828.
+# To make any issue more visible, cause the running configure to be aborted
+# by default if the 'rm' program in use doesn't match our expectations; the
+# user can still override this though.
+if rm -f && rm -fr && rm -rf; then : OK; else
+  cat >&2 <<'END'
+Oops!
+
+Your 'rm' program seems unable to run without file operands specified
+on the command line, even when the '-f' option is present.  This is contrary
+to the behaviour of most rm programs out there, and not conforming with
+the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
+
+Please tell bug-automake at gnu.org about your system, including the value
+of your $PATH and any error possibly output before this message.  This
+can help us improve future automake versions.
+
+END
+  if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
+    echo 'Configuration will proceed anyway, since you have set the' >&2
+    echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
+    echo >&2
+  else
+    cat >&2 <<'END'
+Aborting the configuration process, to ensure you take notice of the issue.
+
+You can download and install GNU coreutils to get an 'rm' implementation
+that behaves properly: <http://www.gnu.org/software/coreutils/>.
+
+If you want to complete the configuration process using your problematic
+'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
+to "yes", and re-run configure.
+
+END
+    as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5
+  fi
+fi
+
+# Check whether --enable-silent-rules was given.
+if test "${enable_silent_rules+set}" = set; then :
+  enableval=$enable_silent_rules;
+fi
+
+case $enable_silent_rules in # (((
+  yes) AM_DEFAULT_VERBOSITY=0;;
+   no) AM_DEFAULT_VERBOSITY=1;;
+    *) AM_DEFAULT_VERBOSITY=0;;
+esac
+am_make=${MAKE-make}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
+$as_echo_n "checking whether $am_make supports nested variables... " >&6; }
+if ${am_cv_make_support_nested_variables+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if $as_echo 'TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+	@$(TRUE)
+.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then
+  am_cv_make_support_nested_variables=yes
+else
+  am_cv_make_support_nested_variables=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
+$as_echo "$am_cv_make_support_nested_variables" >&6; }
+if test $am_cv_make_support_nested_variables = yes; then
+    AM_V='$(V)'
+  AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+  AM_V=$AM_DEFAULT_VERBOSITY
+  AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AM_BACKSLASH='\'
+
+DEPDIR="${am__leading_dot}deps"
+
+ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+	@echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5
+$as_echo_n "checking for style of include used by $am_make... " >&6; }
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from 'make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+  am__include=include
+  am__quote=
+  _am_result=GNU
+  ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+   echo '.include "confinc"' > confmf
+   case `$am_make -s -f confmf 2> /dev/null` in #(
+   *the\ am__doit\ target*)
+     am__include=.include
+     am__quote="\""
+     _am_result=BSD
+     ;;
+   esac
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5
+$as_echo "$_am_result" >&6; }
+rm -f confinc confmf
+
+# Check whether --enable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then :
+  enableval=$enable_dependency_tracking;
+fi
+
+if test "x$enable_dependency_tracking" != xno; then
+  am_depcomp="$ac_aux_dir/depcomp"
+  AMDEPBACKSLASH='\'
+  am__nodep='_no'
+fi
+ if test "x$enable_dependency_tracking" != xno; then
+  AMDEP_TRUE=
+  AMDEP_FALSE='#'
+else
+  AMDEP_TRUE='#'
+  AMDEP_FALSE=
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+  esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link_default") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile.  We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+	;;
+    [ab].out )
+	# We found the default executable, but exeext='' is most
+	# certainly right.
+	break;;
+    *.* )
+	if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+	then :; else
+	   ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	fi
+	# We set ac_cv_exeext here because the later test for it is not
+	# safe: cross compilers may not add the suffix if given an `-o'
+	# argument, so we may need to know it at that point already.
+	# Even if this section looks crufty: it has the advantage of
+	# actually working.
+	break;;
+    * )
+	break;;
+  esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+  ac_file=''
+fi
+if test -z "$ac_file"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'.  For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+  test -f "$ac_file" || continue
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	  break;;
+    * ) break;;
+  esac
+done
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+  { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+  if { ac_try='./conftest$ac_cv_exeext'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+	cross_compiling=yes
+    else
+	{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+    fi
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compile") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then :
+  for ac_file in conftest.o conftest.obj conftest.*; do
+  test -f "$ac_file" || continue;
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+else
+  CFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  ac_c_werror_flag=$ac_save_c_werror_flag
+	 CFLAGS="-g"
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+	-Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5
+$as_echo_n "checking whether $CC understands -c and -o together... " >&6; }
+if ${am_cv_prog_cc_c_o+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+  # Make sure it works both with $CC and with simple cc.
+  # Following AC_PROG_CC_C_O, we do the test twice because some
+  # compilers refuse to overwrite an existing .o file with -o,
+  # though they will create one.
+  am_cv_prog_cc_c_o=yes
+  for am_i in 1 2; do
+    if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5
+   ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5
+   ac_status=$?
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   (exit $ac_status); } \
+         && test -f conftest2.$ac_objext; then
+      : OK
+    else
+      am_cv_prog_cc_c_o=no
+      break
+    fi
+  done
+  rm -f core conftest*
+  unset am_i
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5
+$as_echo "$am_cv_prog_cc_c_o" >&6; }
+if test "$am_cv_prog_cc_c_o" != yes; then
+   # Losing compiler, so override with the script.
+   # FIXME: It is wrong to rewrite CC.
+   # But if we don't then we get into trouble of one sort or another.
+   # A longer-term fix would be to have automake use am__CC in this case,
+   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+   CC="$am_aux_dir/compile $CC"
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+depcc="$CC"   am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if ${am_cv_CC_dependencies_compiler_type+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named 'D' -- because '-MD' means "put the output
+  # in D".
+  rm -rf conftest.dir
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_CC_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+  fi
+  am__universal=false
+  case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac
+
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+      # Solaris 10 /bin/sh.
+      echo '/* dummy */' > sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    # We check with '-c' and '-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle '-M -o', and we need to detect this.  Also, some Intel
+    # versions had trouble with output in subdirs.
+    am__obj=sub/conftest.${OBJEXT-o}
+    am__minus_obj="-o $am__obj"
+    case $depmode in
+    gcc)
+      # This depmode causes a compiler race in universal mode.
+      test "$am__universal" = false || continue
+      ;;
+    nosideeffect)
+      # After this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested.
+      if test "x$enable_dependency_tracking" = xyes; then
+	continue
+      else
+	break
+      fi
+      ;;
+    msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+      # This compiler won't grok '-c -o', but also, the minuso test has
+      # not run yet.  These depmodes are late enough in the game, and
+      # so weak that their functioning should not be impacted.
+      am__obj=conftest.${OBJEXT-o}
+      am__minus_obj=
+      ;;
+    none) break ;;
+    esac
+    if depmode=$depmode \
+       source=sub/conftest.c object=$am__obj \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_CC_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+ if
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+  am__fastdepCC_TRUE=
+  am__fastdepCC_FALSE='#'
+else
+  am__fastdepCC_TRUE='#'
+  am__fastdepCC_FALSE=
+fi
+
+
+
+if test -n "$ac_tool_prefix"; then
+  for ac_prog in ar lib "link -lib"
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AR+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AR"; then
+  ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_AR="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$AR" && break
+  done
+fi
+if test -z "$AR"; then
+  ac_ct_AR=$AR
+  for ac_prog in ar lib "link -lib"
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_AR+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_AR"; then
+  ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_AR="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_AR" && break
+done
+
+  if test "x$ac_ct_AR" = x; then
+    AR="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    AR=$ac_ct_AR
+  fi
+fi
+
+: ${AR=ar}
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the archiver ($AR) interface" >&5
+$as_echo_n "checking the archiver ($AR) interface... " >&6; }
+if ${am_cv_ar_interface+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+   am_cv_ar_interface=ar
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int some_variable = 0;
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&5'
+      { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5
+  (eval $am_ar_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+      if test "$ac_status" -eq 0; then
+        am_cv_ar_interface=ar
+      else
+        am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&5'
+        { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5
+  (eval $am_ar_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+        if test "$ac_status" -eq 0; then
+          am_cv_ar_interface=lib
+        else
+          am_cv_ar_interface=unknown
+        fi
+      fi
+      rm -f conftest.lib libconftest.a
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_ar_interface" >&5
+$as_echo "$am_cv_ar_interface" >&6; }
+
+case $am_cv_ar_interface in
+ar)
+  ;;
+lib)
+  # Microsoft lib, so override with the ar-lib wrapper script.
+  # FIXME: It is wrong to rewrite AR.
+  # But if we don't then we get into trouble of one sort or another.
+  # A longer-term fix would be to have automake use am__AR in this case,
+  # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something
+  # similar.
+  AR="$am_aux_dir/ar-lib $AR"
+  ;;
+unknown)
+  as_fn_error $? "could not determine $AR interface" "$LINENO" 5
+  ;;
+esac
+
+
+
+
+
+# Enable more compiler warnings via -Wall and -Wextra. Add -fvisibility=hidden
+# and enforce use of SR_API to explicitly mark all public API functions.
+COMMON_FLAGS="$CFLAGS -Wall -Wextra -fvisibility=hidden"
+CFLAGS="$COMMON_FLAGS -Wmissing-prototypes"
+
+# Checks for programs.
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  fi
+fi
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$CC" && break
+  done
+fi
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_CC" && break
+done
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+else
+  CFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  ac_c_werror_flag=$ac_save_c_werror_flag
+	 CFLAGS="-g"
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+	-Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5
+$as_echo_n "checking whether $CC understands -c and -o together... " >&6; }
+if ${am_cv_prog_cc_c_o+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+  # Make sure it works both with $CC and with simple cc.
+  # Following AC_PROG_CC_C_O, we do the test twice because some
+  # compilers refuse to overwrite an existing .o file with -o,
+  # though they will create one.
+  am_cv_prog_cc_c_o=yes
+  for am_i in 1 2; do
+    if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5
+   ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5
+   ac_status=$?
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   (exit $ac_status); } \
+         && test -f conftest2.$ac_objext; then
+      : OK
+    else
+      am_cv_prog_cc_c_o=no
+      break
+    fi
+  done
+  rm -f core conftest*
+  unset am_i
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5
+$as_echo "$am_cv_prog_cc_c_o" >&6; }
+if test "$am_cv_prog_cc_c_o" != yes; then
+   # Losing compiler, so override with the script.
+   # FIXME: It is wrong to rewrite CC.
+   # But if we don't then we get into trouble of one sort or another.
+   # A longer-term fix would be to have automake use am__CC in this case,
+   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+   CC="$am_aux_dir/compile $CC"
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+depcc="$CC"   am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if ${am_cv_CC_dependencies_compiler_type+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named 'D' -- because '-MD' means "put the output
+  # in D".
+  rm -rf conftest.dir
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_CC_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+  fi
+  am__universal=false
+  case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac
+
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+      # Solaris 10 /bin/sh.
+      echo '/* dummy */' > sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    # We check with '-c' and '-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle '-M -o', and we need to detect this.  Also, some Intel
+    # versions had trouble with output in subdirs.
+    am__obj=sub/conftest.${OBJEXT-o}
+    am__minus_obj="-o $am__obj"
+    case $depmode in
+    gcc)
+      # This depmode causes a compiler race in universal mode.
+      test "$am__universal" = false || continue
+      ;;
+    nosideeffect)
+      # After this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested.
+      if test "x$enable_dependency_tracking" = xyes; then
+	continue
+      else
+	break
+      fi
+      ;;
+    msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+      # This compiler won't grok '-c -o', but also, the minuso test has
+      # not run yet.  These depmodes are late enough in the game, and
+      # so weak that their functioning should not be impacted.
+      am__obj=conftest.${OBJEXT-o}
+      am__minus_obj=
+      ;;
+    none) break ;;
+    esac
+    if depmode=$depmode \
+       source=sub/conftest.c object=$am__obj \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_CC_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+ if
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+  am__fastdepCC_TRUE=
+  am__fastdepCC_FALSE='#'
+else
+  am__fastdepCC_TRUE='#'
+  am__fastdepCC_FALSE=
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if ${ac_cv_prog_CPP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+  break
+fi
+
+    done
+    ac_cv_prog_CPP=$CPP
+
+fi
+  CPP=$ac_cv_prog_CPP
+else
+  ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
+else
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
+$as_echo_n "checking whether ln -s works... " >&6; }
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
+$as_echo "no, using $LN_S" >&6; }
+fi
+
+
+# Required for per-target flags or subdir-objects with C sources.
+
+
+# Initialize libtool.
+case `pwd` in
+  *\ * | *\	*)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
+$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
+esac
+
+
+
+macro_version='2.4.2'
+macro_revision='1.3337'
+
+
+
+
+
+
+
+
+
+
+
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+  as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if ${ac_cv_build+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+  as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+  as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if ${ac_cv_host+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "x$host_alias" = x; then
+  ac_cv_host=$ac_cv_build
+else
+  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+    as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5
+$as_echo_n "checking how to print strings... " >&6; }
+# Test print first, because it will be a builtin if present.
+if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
+   test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='printf %s\n'
+else
+  # Use this function as a fallback that always works.
+  func_fallback_echo ()
+  {
+    eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+  }
+  ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO ""
+}
+
+case "$ECHO" in
+  printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5
+$as_echo "printf" >&6; } ;;
+  print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5
+$as_echo "print -r" >&6; } ;;
+  *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5
+$as_echo "cat" >&6; } ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
+$as_echo_n "checking for a sed that does not truncate output... " >&6; }
+if ${ac_cv_path_SED+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+            ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+     for ac_i in 1 2 3 4 5 6 7; do
+       ac_script="$ac_script$as_nl$ac_script"
+     done
+     echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
+     { ac_script=; unset ac_script;}
+     if test -z "$SED"; then
+  ac_path_SED_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_SED" || continue
+# Check for GNU ac_path_SED and select it if it is found.
+  # Check for GNU $ac_path_SED
+case `"$ac_path_SED" --version 2>&1` in
+*GNU*)
+  ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo '' >> "conftest.nl"
+    "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_SED_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_SED="$ac_path_SED"
+      ac_path_SED_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_SED_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_SED"; then
+    as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
+  fi
+else
+  ac_cv_path_SED=$SED
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
+$as_echo "$ac_cv_path_SED" >&6; }
+ SED="$ac_cv_path_SED"
+  rm -f conftest.sed
+
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$GREP"; then
+  ac_path_GREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in grep ggrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_GREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_GREP"; then
+    as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     if test -z "$EGREP"; then
+  ac_path_EGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in egrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_EGREP" || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+  # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'EGREP' >> "conftest.nl"
+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_EGREP="$ac_path_EGREP"
+      ac_path_EGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_EGREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_EGREP"; then
+    as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_EGREP=$EGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5
+$as_echo_n "checking for fgrep... " >&6; }
+if ${ac_cv_path_FGREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1
+   then ac_cv_path_FGREP="$GREP -F"
+   else
+     if test -z "$FGREP"; then
+  ac_path_FGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in fgrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_FGREP" || continue
+# Check for GNU ac_path_FGREP and select it if it is found.
+  # Check for GNU $ac_path_FGREP
+case `"$ac_path_FGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'FGREP' >> "conftest.nl"
+    "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_FGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_FGREP="$ac_path_FGREP"
+      ac_path_FGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_FGREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_FGREP"; then
+    as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_FGREP=$FGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5
+$as_echo "$ac_cv_path_FGREP" >&6; }
+ FGREP="$ac_cv_path_FGREP"
+
+
+test -z "$GREP" && GREP=grep
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then :
+  withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
+else
+  with_gnu_ld=no
+fi
+
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
+$as_echo_n "checking for ld used by $CC... " >&6; }
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [\\/]* | ?:[\\/]*)
+      re_direlt='/[^/][^/]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+	ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
+$as_echo_n "checking for GNU ld... " >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
+$as_echo_n "checking for non-GNU ld... " >&6; }
+fi
+if ${lt_cv_path_LD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$LD"; then
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some variants of GNU ld only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+	test "$with_gnu_ld" != no && break
+	;;
+      *)
+	test "$with_gnu_ld" != yes && break
+	;;
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+else
+  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+$as_echo "$LD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
+$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
+if ${lt_cv_prog_gnu_ld+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
+$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5
+$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; }
+if ${lt_cv_path_NM+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$NM"; then
+  # Let the user override the test.
+  lt_cv_path_NM="$NM"
+else
+  lt_nm_to_check="${ac_tool_prefix}nm"
+  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+    lt_nm_to_check="$lt_nm_to_check nm"
+  fi
+  for lt_tmp_nm in $lt_nm_to_check; do
+    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+      IFS="$lt_save_ifs"
+      test -z "$ac_dir" && ac_dir=.
+      tmp_nm="$ac_dir/$lt_tmp_nm"
+      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+	# Check to see if the nm accepts a BSD-compat flag.
+	# Adding the `sed 1q' prevents false positives on HP-UX, which says:
+	#   nm: unknown option "B" ignored
+	# Tru64's nm complains that /dev/null is an invalid object file
+	case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+	*/dev/null* | *'Invalid file or object type'*)
+	  lt_cv_path_NM="$tmp_nm -B"
+	  break
+	  ;;
+	*)
+	  case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+	  */dev/null*)
+	    lt_cv_path_NM="$tmp_nm -p"
+	    break
+	    ;;
+	  *)
+	    lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+	    continue # so that we can try to find one that supports BSD flags
+	    ;;
+	  esac
+	  ;;
+	esac
+      fi
+    done
+    IFS="$lt_save_ifs"
+  done
+  : ${lt_cv_path_NM=no}
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
+$as_echo "$lt_cv_path_NM" >&6; }
+if test "$lt_cv_path_NM" != "no"; then
+  NM="$lt_cv_path_NM"
+else
+  # Didn't find any BSD compatible name lister, look for dumpbin.
+  if test -n "$DUMPBIN"; then :
+    # Let the user override the test.
+  else
+    if test -n "$ac_tool_prefix"; then
+  for ac_prog in dumpbin "link -dump"
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DUMPBIN+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DUMPBIN"; then
+  ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+DUMPBIN=$ac_cv_prog_DUMPBIN
+if test -n "$DUMPBIN"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5
+$as_echo "$DUMPBIN" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$DUMPBIN" && break
+  done
+fi
+if test -z "$DUMPBIN"; then
+  ac_ct_DUMPBIN=$DUMPBIN
+  for ac_prog in dumpbin "link -dump"
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DUMPBIN"; then
+  ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN
+if test -n "$ac_ct_DUMPBIN"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5
+$as_echo "$ac_ct_DUMPBIN" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_DUMPBIN" && break
+done
+
+  if test "x$ac_ct_DUMPBIN" = x; then
+    DUMPBIN=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DUMPBIN=$ac_ct_DUMPBIN
+  fi
+fi
+
+    case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+    *COFF*)
+      DUMPBIN="$DUMPBIN -symbols"
+      ;;
+    *)
+      DUMPBIN=:
+      ;;
+    esac
+  fi
+
+  if test "$DUMPBIN" != ":"; then
+    NM="$DUMPBIN"
+  fi
+fi
+test -z "$NM" && NM=nm
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5
+$as_echo_n "checking the name lister ($NM) interface... " >&6; }
+if ${lt_cv_nm_interface+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_nm_interface="BSD nm"
+  echo "int some_variable = 0;" > conftest.$ac_ext
+  (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5)
+  (eval "$ac_compile" 2>conftest.err)
+  cat conftest.err >&5
+  (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+  (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+  cat conftest.err >&5
+  (eval echo "\"\$as_me:$LINENO: output\"" >&5)
+  cat conftest.out >&5
+  if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+    lt_cv_nm_interface="MS dumpbin"
+  fi
+  rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5
+$as_echo "$lt_cv_nm_interface" >&6; }
+
+# find the maximum length of command line arguments
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5
+$as_echo_n "checking the maximum length of command line arguments... " >&6; }
+if ${lt_cv_sys_max_cmd_len+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+    i=0
+  teststring="ABCD"
+
+  case $build_os in
+  msdosdjgpp*)
+    # On DJGPP, this test can blow up pretty badly due to problems in libc
+    # (any single argument exceeding 2000 bytes causes a buffer overrun
+    # during glob expansion).  Even if it were fixed, the result of this
+    # check would be larger than it should be.
+    lt_cv_sys_max_cmd_len=12288;    # 12K is about right
+    ;;
+
+  gnu*)
+    # Under GNU Hurd, this test is not required because there is
+    # no limit to the length of command line arguments.
+    # Libtool will interpret -1 as no limit whatsoever
+    lt_cv_sys_max_cmd_len=-1;
+    ;;
+
+  cygwin* | mingw* | cegcc*)
+    # On Win9x/ME, this test blows up -- it succeeds, but takes
+    # about 5 minutes as the teststring grows exponentially.
+    # Worse, since 9x/ME are not pre-emptively multitasking,
+    # you end up with a "frozen" computer, even though with patience
+    # the test eventually succeeds (with a max line length of 256k).
+    # Instead, let's just punt: use the minimum linelength reported by
+    # all of the supported platforms: 8192 (on NT/2K/XP).
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  mint*)
+    # On MiNT this can take a long time and run out of memory.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  amigaos*)
+    # On AmigaOS with pdksh, this test takes hours, literally.
+    # So we just punt and use a minimum line length of 8192.
+    lt_cv_sys_max_cmd_len=8192;
+    ;;
+
+  netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+    # This has been around since 386BSD, at least.  Likely further.
+    if test -x /sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+    elif test -x /usr/sbin/sysctl; then
+      lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+    else
+      lt_cv_sys_max_cmd_len=65536	# usable default for all BSDs
+    fi
+    # And add a safety zone
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+    lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    ;;
+
+  interix*)
+    # We know the value 262144 and hardcode it with a safety zone (like BSD)
+    lt_cv_sys_max_cmd_len=196608
+    ;;
+
+  os2*)
+    # The test takes a long time on OS/2.
+    lt_cv_sys_max_cmd_len=8192
+    ;;
+
+  osf*)
+    # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+    # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+    # nice to cause kernel panics so lets avoid the loop below.
+    # First set a reasonable default.
+    lt_cv_sys_max_cmd_len=16384
+    #
+    if test -x /sbin/sysconfig; then
+      case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+        *1*) lt_cv_sys_max_cmd_len=-1 ;;
+      esac
+    fi
+    ;;
+  sco3.2v5*)
+    lt_cv_sys_max_cmd_len=102400
+    ;;
+  sysv5* | sco5v6* | sysv4.2uw2*)
+    kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+    if test -n "$kargmax"; then
+      lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[	 ]//'`
+    else
+      lt_cv_sys_max_cmd_len=32768
+    fi
+    ;;
+  *)
+    lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+    if test -n "$lt_cv_sys_max_cmd_len" && \
+	test undefined != "$lt_cv_sys_max_cmd_len"; then
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+    else
+      # Make teststring a little bigger before we do anything with it.
+      # a 1K string should be a reasonable start.
+      for i in 1 2 3 4 5 6 7 8 ; do
+        teststring=$teststring$teststring
+      done
+      SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+      # If test is not a shell built-in, we'll probably end up computing a
+      # maximum length that is only half of the actual maximum length, but
+      # we can't tell.
+      while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \
+	         = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+	      test $i != 17 # 1/2 MB should be enough
+      do
+        i=`expr $i + 1`
+        teststring=$teststring$teststring
+      done
+      # Only check the string length outside the loop.
+      lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+      teststring=
+      # Add a significant safety factor because C++ compilers can tack on
+      # massive amounts of additional arguments before passing them to the
+      # linker.  It appears as though 1/2 is a usable value.
+      lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+    fi
+    ;;
+  esac
+
+fi
+
+if test -n $lt_cv_sys_max_cmd_len ; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5
+$as_echo "$lt_cv_sys_max_cmd_len" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
+$as_echo "none" >&6; }
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+
+
+
+
+
+: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5
+$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; }
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+  test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \
+      = c,a/b,b/c, \
+    && eval 'test $(( 1 + 1 )) -eq 2 \
+    && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
+  && xsi_shell=yes
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5
+$as_echo "$xsi_shell" >&6; }
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5
+$as_echo_n "checking whether the shell understands \"+=\"... " >&6; }
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \
+    >/dev/null 2>&1 \
+  && lt_shell_append=yes
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5
+$as_echo "$lt_shell_append" >&6; }
+
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  lt_unset=unset
+else
+  lt_unset=false
+fi
+
+
+
+
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+    # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+  lt_SP2NL='tr \040 \012'
+  lt_NL2SP='tr \015\012 \040\040'
+  ;;
+ *) # EBCDIC based system
+  lt_SP2NL='tr \100 \n'
+  lt_NL2SP='tr \r\n \100\100'
+  ;;
+esac
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5
+$as_echo_n "checking how to convert $build file names to $host format... " >&6; }
+if ${lt_cv_to_host_file_cmd+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
+        ;;
+    esac
+    ;;
+  *-*-cygwin* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
+        ;;
+      *-*-cygwin* )
+        lt_cv_to_host_file_cmd=func_convert_file_noop
+        ;;
+      * ) # otherwise, assume *nix
+        lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
+        ;;
+    esac
+    ;;
+  * ) # unhandled hosts (and "normal" native builds)
+    lt_cv_to_host_file_cmd=func_convert_file_noop
+    ;;
+esac
+
+fi
+
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5
+$as_echo "$lt_cv_to_host_file_cmd" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5
+$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; }
+if ${lt_cv_to_tool_file_cmd+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  #assume ordinary cross tools, or native build.
+lt_cv_to_tool_file_cmd=func_convert_file_noop
+case $host in
+  *-*-mingw* )
+    case $build in
+      *-*-mingw* ) # actually msys
+        lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
+        ;;
+    esac
+    ;;
+esac
+
+fi
+
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5
+$as_echo "$lt_cv_to_tool_file_cmd" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5
+$as_echo_n "checking for $LD option to reload object files... " >&6; }
+if ${lt_cv_ld_reload_flag+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_reload_flag='-r'
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5
+$as_echo "$lt_cv_ld_reload_flag" >&6; }
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    if test "$GCC" != yes; then
+      reload_cmds=false
+    fi
+    ;;
+  darwin*)
+    if test "$GCC" = yes; then
+      reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+    else
+      reload_cmds='$LD$reload_flag -o $output$reload_objs'
+    fi
+    ;;
+esac
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
+set dummy ${ac_tool_prefix}objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OBJDUMP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OBJDUMP"; then
+  ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+OBJDUMP=$ac_cv_prog_OBJDUMP
+if test -n "$OBJDUMP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
+$as_echo "$OBJDUMP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OBJDUMP"; then
+  ac_ct_OBJDUMP=$OBJDUMP
+  # Extract the first word of "objdump", so it can be a program name with args.
+set dummy objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OBJDUMP"; then
+  ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_OBJDUMP="objdump"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
+if test -n "$ac_ct_OBJDUMP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
+$as_echo "$ac_ct_OBJDUMP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OBJDUMP" = x; then
+    OBJDUMP="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OBJDUMP=$ac_ct_OBJDUMP
+  fi
+else
+  OBJDUMP="$ac_cv_prog_OBJDUMP"
+fi
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5
+$as_echo_n "checking how to recognize dependent libraries... " >&6; }
+if ${lt_cv_deplibs_check_method+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[4-9]*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+beos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+bsdi[45]*)
+  lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
+  lt_cv_file_magic_cmd='/usr/bin/file -L'
+  lt_cv_file_magic_test_file=/shlib/libc.so
+  ;;
+
+cygwin*)
+  # func_win32_libid is a shell function defined in ltmain.sh
+  lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+  lt_cv_file_magic_cmd='func_win32_libid'
+  ;;
+
+mingw* | pw32*)
+  # Base MSYS/MinGW do not provide the 'file' command needed by
+  # func_win32_libid shell function, so use a weaker test based on 'objdump',
+  # unless we find 'file', for example because we are cross-compiling.
+  # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
+  if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
+    lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+    lt_cv_file_magic_cmd='func_win32_libid'
+  else
+    # Keep this pattern in sync with the one in func_win32_libid.
+    lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
+    lt_cv_file_magic_cmd='$OBJDUMP -f'
+  fi
+  ;;
+
+cegcc*)
+  # use the weaker test based on 'objdump'. See mingw*.
+  lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+  lt_cv_file_magic_cmd='$OBJDUMP -f'
+  ;;
+
+darwin* | rhapsody*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+freebsd* | dragonfly*)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    case $host_cpu in
+    i*86 )
+      # Not sure whether the presence of OpenBSD here was a mistake.
+      # Let's accept both of them until this is cleared up.
+      lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library'
+      lt_cv_file_magic_cmd=/usr/bin/file
+      lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+      ;;
+    esac
+  else
+    lt_cv_deplibs_check_method=pass_all
+  fi
+  ;;
+
+haiku*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+hpux10.20* | hpux11*)
+  lt_cv_file_magic_cmd=/usr/bin/file
+  case $host_cpu in
+  ia64*)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
+    lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+    ;;
+  hppa*64*)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'
+    lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+    ;;
+  *)
+    lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library'
+    lt_cv_file_magic_test_file=/usr/lib/libc.sl
+    ;;
+  esac
+  ;;
+
+interix[3-9]*)
+  # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+  lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$'
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $LD in
+  *-32|*"-32 ") libmagic=32-bit;;
+  *-n32|*"-n32 ") libmagic=N32;;
+  *-64|*"-64 ") libmagic=64-bit;;
+  *) libmagic=never-match;;
+  esac
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+netbsd* | netbsdelf*-gnu)
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$'
+  fi
+  ;;
+
+newos6*)
+  lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
+  lt_cv_file_magic_cmd=/usr/bin/file
+  lt_cv_file_magic_test_file=/usr/lib/libnls.so
+  ;;
+
+*nto* | *qnx*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+openbsd*)
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$'
+  else
+    lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+  fi
+  ;;
+
+osf3* | osf4* | osf5*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+rdos*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+solaris*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+
+sysv4 | sysv4.3*)
+  case $host_vendor in
+  motorola)
+    lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
+    lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+    ;;
+  ncr)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  sequent)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
+    ;;
+  sni)
+    lt_cv_file_magic_cmd='/bin/file'
+    lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"
+    lt_cv_file_magic_test_file=/lib/libc.so
+    ;;
+  siemens)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  pc)
+    lt_cv_deplibs_check_method=pass_all
+    ;;
+  esac
+  ;;
+
+tpf*)
+  lt_cv_deplibs_check_method=pass_all
+  ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5
+$as_echo "$lt_cv_deplibs_check_method" >&6; }
+
+file_magic_glob=
+want_nocaseglob=no
+if test "$build" = "$host"; then
+  case $host_os in
+  mingw* | pw32*)
+    if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
+      want_nocaseglob=yes
+    else
+      file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"`
+    fi
+    ;;
+  esac
+fi
+
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DLLTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DLLTOOL"; then
+  ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+DLLTOOL=$ac_cv_prog_DLLTOOL
+if test -n "$DLLTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5
+$as_echo "$DLLTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DLLTOOL"; then
+  ac_ct_DLLTOOL=$DLLTOOL
+  # Extract the first word of "dlltool", so it can be a program name with args.
+set dummy dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DLLTOOL"; then
+  ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_DLLTOOL="dlltool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL
+if test -n "$ac_ct_DLLTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5
+$as_echo "$ac_ct_DLLTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_DLLTOOL" = x; then
+    DLLTOOL="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DLLTOOL=$ac_ct_DLLTOOL
+  fi
+else
+  DLLTOOL="$ac_cv_prog_DLLTOOL"
+fi
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5
+$as_echo_n "checking how to associate runtime and link libraries... " >&6; }
+if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_sharedlib_from_linklib_cmd='unknown'
+
+case $host_os in
+cygwin* | mingw* | pw32* | cegcc*)
+  # two different shell functions defined in ltmain.sh
+  # decide which to use based on capabilities of $DLLTOOL
+  case `$DLLTOOL --help 2>&1` in
+  *--identify-strict*)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
+    ;;
+  *)
+    lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
+    ;;
+  esac
+  ;;
+*)
+  # fallback: assume linklib IS sharedlib
+  lt_cv_sharedlib_from_linklib_cmd="$ECHO"
+  ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5
+$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; }
+sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
+test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  for ac_prog in ar
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AR+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AR"; then
+  ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_AR="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$AR" && break
+  done
+fi
+if test -z "$AR"; then
+  ac_ct_AR=$AR
+  for ac_prog in ar
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_AR+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_AR"; then
+  ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_AR="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_AR" && break
+done
+
+  if test "x$ac_ct_AR" = x; then
+    AR="false"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    AR=$ac_ct_AR
+  fi
+fi
+
+: ${AR=ar}
+: ${AR_FLAGS=cru}
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5
+$as_echo_n "checking for archiver @FILE support... " >&6; }
+if ${lt_cv_ar_at_file+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ar_at_file=no
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  echo conftest.$ac_objext > conftest.lst
+      lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5'
+      { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
+  (eval $lt_ar_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+      if test "$ac_status" -eq 0; then
+	# Ensure the archiver fails upon bogus file names.
+	rm -f conftest.$ac_objext libconftest.a
+	{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
+  (eval $lt_ar_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+	if test "$ac_status" -ne 0; then
+          lt_cv_ar_at_file=@
+        fi
+      fi
+      rm -f conftest.* libconftest.a
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5
+$as_echo "$lt_cv_ar_at_file" >&6; }
+
+if test "x$lt_cv_ar_at_file" = xno; then
+  archiver_list_spec=
+else
+  archiver_list_spec=$lt_cv_ar_at_file
+fi
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$STRIP"; then
+  ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+  ac_ct_STRIP=$STRIP
+  # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_STRIP"; then
+  ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_STRIP="strip"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_STRIP" = x; then
+    STRIP=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    STRIP=$ac_ct_STRIP
+  fi
+else
+  STRIP="$ac_cv_prog_STRIP"
+fi
+
+test -z "$STRIP" && STRIP=:
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_RANLIB+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$RANLIB"; then
+  ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+  ac_ct_RANLIB=$RANLIB
+  # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_RANLIB"; then
+  ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_RANLIB="ranlib"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_RANLIB" = x; then
+    RANLIB=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    RANLIB=$ac_ct_RANLIB
+  fi
+else
+  RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+test -z "$RANLIB" && RANLIB=:
+
+
+
+
+
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+  case $host_os in
+  openbsd*)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
+    ;;
+  *)
+    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
+    ;;
+  esac
+  old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
+fi
+
+case $host_os in
+  darwin*)
+    lock_old_archive_extraction=yes ;;
+  *)
+    lock_old_archive_extraction=no ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5
+$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; }
+if ${lt_cv_sys_global_symbol_pipe+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix.  What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[BCDEGRST]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+  symcode='[BCDT]'
+  ;;
+cygwin* | mingw* | pw32* | cegcc*)
+  symcode='[ABCDGISTW]'
+  ;;
+hpux*)
+  if test "$host_cpu" = ia64; then
+    symcode='[ABCDEGRST]'
+  fi
+  ;;
+irix* | nonstopux*)
+  symcode='[BCDEGRST]'
+  ;;
+osf*)
+  symcode='[BCDEGQRST]'
+  ;;
+solaris*)
+  symcode='[BDRT]'
+  ;;
+sco3.2v5*)
+  symcode='[DT]'
+  ;;
+sysv4.2uw2*)
+  symcode='[DT]'
+  ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+  symcode='[ABDT]'
+  ;;
+sysv4)
+  symcode='[DFNSTU]'
+  ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+  symcode='[ABCDGIRSTW]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/  {\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/  {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/  {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/  {\"lib\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+  opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+  ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+  # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+  symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+  # Write the raw and C identifiers.
+  if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+    # Fake it for dumpbin and say T for any non-static function
+    # and D for any global variable.
+    # Also find C++ and __fastcall symbols from MSVC++,
+    # which start with @ or ?.
+    lt_cv_sys_global_symbol_pipe="$AWK '"\
+"     {last_section=section; section=\$ 3};"\
+"     /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
+"     /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+"     \$ 0!~/External *\|/{next};"\
+"     / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+"     {if(hide[section]) next};"\
+"     {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+"     {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+"     s[1]~/^[@?]/{print s[1], s[1]; next};"\
+"     s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+"     ' prfx=^$ac_symprfx"
+  else
+    lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[	 ]\($symcode$symcode*\)[	 ][	 ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+  fi
+  lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
+
+  # Check to see that the pipe works correctly.
+  pipe_works=no
+
+  rm -f conftest*
+  cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    # Now try to grab the symbols.
+    nlist=conftest.nm
+    if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5
+  (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s "$nlist"; then
+      # Try sorting and uniquifying the output.
+      if sort "$nlist" | uniq > "$nlist"T; then
+	mv -f "$nlist"T "$nlist"
+      else
+	rm -f "$nlist"T
+      fi
+
+      # Make sure that we snagged all the symbols we need.
+      if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+	if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+	  cat <<_LT_EOF > conftest.$ac_ext
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests.  */
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
+/* DATA imports from DLLs on WIN32 con't be const, because runtime
+   relocations are performed -- see ld's documentation on pseudo-relocs.  */
+# define LT_DLSYM_CONST
+#elif defined(__osf__)
+/* This system does not cope well with relocations in const data.  */
+# define LT_DLSYM_CONST
+#else
+# define LT_DLSYM_CONST const
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+	  # Now generate the symbol file.
+	  eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+	  cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols.  */
+LT_DLSYM_CONST struct {
+  const char *name;
+  void       *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[] =
+{
+  { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+	  $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/  {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+	  cat <<\_LT_EOF >> conftest.$ac_ext
+  {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+  return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+	  # Now try linking the two files.
+	  mv conftest.$ac_objext conftstm.$ac_objext
+	  lt_globsym_save_LIBS=$LIBS
+	  lt_globsym_save_CFLAGS=$CFLAGS
+	  LIBS="conftstm.$ac_objext"
+	  CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
+	  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s conftest${ac_exeext}; then
+	    pipe_works=yes
+	  fi
+	  LIBS=$lt_globsym_save_LIBS
+	  CFLAGS=$lt_globsym_save_CFLAGS
+	else
+	  echo "cannot find nm_test_func in $nlist" >&5
+	fi
+      else
+	echo "cannot find nm_test_var in $nlist" >&5
+      fi
+    else
+      echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5
+    fi
+  else
+    echo "$progname: failed program was:" >&5
+    cat conftest.$ac_ext >&5
+  fi
+  rm -rf conftest* conftst*
+
+  # Do not use the global_symbol_pipe unless it works.
+  if test "$pipe_works" = yes; then
+    break
+  else
+    lt_cv_sys_global_symbol_pipe=
+  fi
+done
+
+fi
+
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+  lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5
+$as_echo "failed" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+fi
+
+# Response file support.
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+  nm_file_list_spec='@'
+elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then
+  nm_file_list_spec='@'
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5
+$as_echo_n "checking for sysroot... " >&6; }
+
+# Check whether --with-sysroot was given.
+if test "${with_sysroot+set}" = set; then :
+  withval=$with_sysroot;
+else
+  with_sysroot=no
+fi
+
+
+lt_sysroot=
+case ${with_sysroot} in #(
+ yes)
+   if test "$GCC" = yes; then
+     lt_sysroot=`$CC --print-sysroot 2>/dev/null`
+   fi
+   ;; #(
+ /*)
+   lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
+   ;; #(
+ no|'')
+   ;; #(
+ *)
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5
+$as_echo "${with_sysroot}" >&6; }
+   as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5
+   ;;
+esac
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5
+$as_echo "${lt_sysroot:-no}" >&6; }
+
+
+
+
+
+# Check whether --enable-libtool-lock was given.
+if test "${enable_libtool_lock+set}" = set; then :
+  enableval=$enable_libtool_lock;
+fi
+
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    case `/usr/bin/file conftest.$ac_objext` in
+      *ELF-32*)
+	HPUX_IA64_MODE="32"
+	;;
+      *ELF-64*)
+	HPUX_IA64_MODE="64"
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+*-*-irix6*)
+  # Find out which ABI we are using.
+  echo '#line '$LINENO' "configure"' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    if test "$lt_cv_prog_gnu_ld" = yes; then
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -melf32bsmip"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -melf32bmipn32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -melf64bmip"
+	;;
+      esac
+    else
+      case `/usr/bin/file conftest.$ac_objext` in
+	*32-bit*)
+	  LD="${LD-ld} -32"
+	  ;;
+	*N32*)
+	  LD="${LD-ld} -n32"
+	  ;;
+	*64-bit*)
+	  LD="${LD-ld} -64"
+	  ;;
+      esac
+    fi
+  fi
+  rm -rf conftest*
+  ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    case `/usr/bin/file conftest.o` in
+      *32-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_i386_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    case `/usr/bin/file conftest.o` in
+	      *x86-64*)
+		LD="${LD-ld} -m elf32_x86_64"
+		;;
+	      *)
+		LD="${LD-ld} -m elf_i386"
+		;;
+	    esac
+	    ;;
+	  powerpc64le-*)
+	    LD="${LD-ld} -m elf32lppclinux"
+	    ;;
+	  powerpc64-*)
+	    LD="${LD-ld} -m elf32ppclinux"
+	    ;;
+	  s390x-*linux*)
+	    LD="${LD-ld} -m elf_s390"
+	    ;;
+	  sparc64-*linux*)
+	    LD="${LD-ld} -m elf32_sparc"
+	    ;;
+	esac
+	;;
+      *64-bit*)
+	case $host in
+	  x86_64-*kfreebsd*-gnu)
+	    LD="${LD-ld} -m elf_x86_64_fbsd"
+	    ;;
+	  x86_64-*linux*)
+	    LD="${LD-ld} -m elf_x86_64"
+	    ;;
+	  powerpcle-*)
+	    LD="${LD-ld} -m elf64lppc"
+	    ;;
+	  powerpc-*)
+	    LD="${LD-ld} -m elf64ppc"
+	    ;;
+	  s390*-*linux*|s390*-*tpf*)
+	    LD="${LD-ld} -m elf64_s390"
+	    ;;
+	  sparc*-*linux*)
+	    LD="${LD-ld} -m elf64_sparc"
+	    ;;
+	esac
+	;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+
+*-*-sco3.2v5*)
+  # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+  SAVE_CFLAGS="$CFLAGS"
+  CFLAGS="$CFLAGS -belf"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5
+$as_echo_n "checking whether the C compiler needs -belf... " >&6; }
+if ${lt_cv_cc_needs_belf+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  lt_cv_cc_needs_belf=yes
+else
+  lt_cv_cc_needs_belf=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+     ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5
+$as_echo "$lt_cv_cc_needs_belf" >&6; }
+  if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+    # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+    CFLAGS="$SAVE_CFLAGS"
+  fi
+  ;;
+*-*solaris*)
+  # Find out which ABI we are using.
+  echo 'int i;' > conftest.$ac_ext
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+    case `/usr/bin/file conftest.o` in
+    *64-bit*)
+      case $lt_cv_prog_gnu_ld in
+      yes*)
+        case $host in
+        i?86-*-solaris*)
+          LD="${LD-ld} -m elf_x86_64"
+          ;;
+        sparc*-*-solaris*)
+          LD="${LD-ld} -m elf64_sparc"
+          ;;
+        esac
+        # GNU ld 2.21 introduced _sol2 emulations.  Use them if available.
+        if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
+          LD="${LD-ld}_sol2"
+        fi
+        ;;
+      *)
+	if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+	  LD="${LD-ld} -64"
+	fi
+	;;
+      esac
+      ;;
+    esac
+  fi
+  rm -rf conftest*
+  ;;
+esac
+
+need_locks="$enable_libtool_lock"
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args.
+set dummy ${ac_tool_prefix}mt; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_MANIFEST_TOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$MANIFEST_TOOL"; then
+  ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL
+if test -n "$MANIFEST_TOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5
+$as_echo "$MANIFEST_TOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_MANIFEST_TOOL"; then
+  ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL
+  # Extract the first word of "mt", so it can be a program name with args.
+set dummy mt; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_MANIFEST_TOOL"; then
+  ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_MANIFEST_TOOL="mt"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL
+if test -n "$ac_ct_MANIFEST_TOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5
+$as_echo "$ac_ct_MANIFEST_TOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_MANIFEST_TOOL" = x; then
+    MANIFEST_TOOL=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL
+  fi
+else
+  MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL"
+fi
+
+test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5
+$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; }
+if ${lt_cv_path_mainfest_tool+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_path_mainfest_tool=no
+  echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5
+  $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
+  cat conftest.err >&5
+  if $GREP 'Manifest Tool' conftest.out > /dev/null; then
+    lt_cv_path_mainfest_tool=yes
+  fi
+  rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5
+$as_echo "$lt_cv_path_mainfest_tool" >&6; }
+if test "x$lt_cv_path_mainfest_tool" != xyes; then
+  MANIFEST_TOOL=:
+fi
+
+
+
+
+
+
+  case $host_os in
+    rhapsody* | darwin*)
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DSYMUTIL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DSYMUTIL"; then
+  ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+DSYMUTIL=$ac_cv_prog_DSYMUTIL
+if test -n "$DSYMUTIL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5
+$as_echo "$DSYMUTIL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DSYMUTIL"; then
+  ac_ct_DSYMUTIL=$DSYMUTIL
+  # Extract the first word of "dsymutil", so it can be a program name with args.
+set dummy dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DSYMUTIL"; then
+  ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL
+if test -n "$ac_ct_DSYMUTIL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5
+$as_echo "$ac_ct_DSYMUTIL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_DSYMUTIL" = x; then
+    DSYMUTIL=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DSYMUTIL=$ac_ct_DSYMUTIL
+  fi
+else
+  DSYMUTIL="$ac_cv_prog_DSYMUTIL"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args.
+set dummy ${ac_tool_prefix}nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_NMEDIT+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$NMEDIT"; then
+  ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+NMEDIT=$ac_cv_prog_NMEDIT
+if test -n "$NMEDIT"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5
+$as_echo "$NMEDIT" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_NMEDIT"; then
+  ac_ct_NMEDIT=$NMEDIT
+  # Extract the first word of "nmedit", so it can be a program name with args.
+set dummy nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_NMEDIT"; then
+  ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_NMEDIT="nmedit"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT
+if test -n "$ac_ct_NMEDIT"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5
+$as_echo "$ac_ct_NMEDIT" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_NMEDIT" = x; then
+    NMEDIT=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    NMEDIT=$ac_ct_NMEDIT
+  fi
+else
+  NMEDIT="$ac_cv_prog_NMEDIT"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args.
+set dummy ${ac_tool_prefix}lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_LIPO+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$LIPO"; then
+  ac_cv_prog_LIPO="$LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+LIPO=$ac_cv_prog_LIPO
+if test -n "$LIPO"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5
+$as_echo "$LIPO" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_LIPO"; then
+  ac_ct_LIPO=$LIPO
+  # Extract the first word of "lipo", so it can be a program name with args.
+set dummy lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_LIPO+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_LIPO"; then
+  ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_LIPO="lipo"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO
+if test -n "$ac_ct_LIPO"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5
+$as_echo "$ac_ct_LIPO" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_LIPO" = x; then
+    LIPO=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    LIPO=$ac_ct_LIPO
+  fi
+else
+  LIPO="$ac_cv_prog_LIPO"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OTOOL"; then
+  ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL=$ac_cv_prog_OTOOL
+if test -n "$OTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
+$as_echo "$OTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL"; then
+  ac_ct_OTOOL=$OTOOL
+  # Extract the first word of "otool", so it can be a program name with args.
+set dummy otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OTOOL"; then
+  ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_OTOOL="otool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL
+if test -n "$ac_ct_OTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5
+$as_echo "$ac_ct_OTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OTOOL" = x; then
+    OTOOL=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OTOOL=$ac_ct_OTOOL
+  fi
+else
+  OTOOL="$ac_cv_prog_OTOOL"
+fi
+
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OTOOL64+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OTOOL64"; then
+  ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL64=$ac_cv_prog_OTOOL64
+if test -n "$OTOOL64"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5
+$as_echo "$OTOOL64" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL64"; then
+  ac_ct_OTOOL64=$OTOOL64
+  # Extract the first word of "otool64", so it can be a program name with args.
+set dummy otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_OTOOL64"; then
+  ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_OTOOL64="otool64"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64
+if test -n "$ac_ct_OTOOL64"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5
+$as_echo "$ac_ct_OTOOL64" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_ct_OTOOL64" = x; then
+    OTOOL64=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OTOOL64=$ac_ct_OTOOL64
+  fi
+else
+  OTOOL64="$ac_cv_prog_OTOOL64"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5
+$as_echo_n "checking for -single_module linker flag... " >&6; }
+if ${lt_cv_apple_cc_single_mod+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_apple_cc_single_mod=no
+      if test -z "${LT_MULTI_MODULE}"; then
+	# By default we will add the -single_module flag. You can override
+	# by either setting the environment variable LT_MULTI_MODULE
+	# non-empty at configure time, or by adding -multi_module to the
+	# link flags.
+	rm -rf libconftest.dylib*
+	echo "int foo(void){return 1;}" > conftest.c
+	echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&5
+	$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+	  -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+        _lt_result=$?
+	# If there is a non-empty error log, and "single_module"
+	# appears in it, assume the flag caused a linker warning
+        if test -s conftest.err && $GREP single_module conftest.err; then
+	  cat conftest.err >&5
+	# Otherwise, if the output was created with a 0 exit code from
+	# the compiler, it worked.
+	elif test -f libconftest.dylib && test $_lt_result -eq 0; then
+	  lt_cv_apple_cc_single_mod=yes
+	else
+	  cat conftest.err >&5
+	fi
+	rm -rf libconftest.dylib*
+	rm -f conftest.*
+      fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5
+$as_echo "$lt_cv_apple_cc_single_mod" >&6; }
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5
+$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; }
+if ${lt_cv_ld_exported_symbols_list+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_exported_symbols_list=no
+      save_LDFLAGS=$LDFLAGS
+      echo "_main" > conftest.sym
+      LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  lt_cv_ld_exported_symbols_list=yes
+else
+  lt_cv_ld_exported_symbols_list=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+	LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5
+$as_echo "$lt_cv_ld_exported_symbols_list" >&6; }
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5
+$as_echo_n "checking for -force_load linker flag... " >&6; }
+if ${lt_cv_ld_force_load+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_force_load=no
+      cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5
+      $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5
+      echo "$AR cru libconftest.a conftest.o" >&5
+      $AR cru libconftest.a conftest.o 2>&5
+      echo "$RANLIB libconftest.a" >&5
+      $RANLIB libconftest.a 2>&5
+      cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5
+      $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+      _lt_result=$?
+      if test -s conftest.err && $GREP force_load conftest.err; then
+	cat conftest.err >&5
+      elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then
+	lt_cv_ld_force_load=yes
+      else
+	cat conftest.err >&5
+      fi
+        rm -f conftest.err libconftest.a conftest conftest.c
+        rm -rf conftest.dSYM
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5
+$as_echo "$lt_cv_ld_force_load" >&6; }
+    case $host_os in
+    rhapsody* | darwin1.[012])
+      _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+    darwin1.*)
+      _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+    darwin*) # darwin 5.x on
+      # if running on 10.5 or later, the deployment target defaults
+      # to the OS version, if on x86, and 10.4, the deployment
+      # target defaults to 10.4. Don't you love it?
+      case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+	10.0,*86*-darwin8*|10.0,*-darwin[91]*)
+	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+	10.[012]*)
+	  _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+	10.*)
+	  _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+      esac
+    ;;
+  esac
+    if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+      _lt_dar_single_mod='$single_module'
+    fi
+    if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+      _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+    else
+      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+    fi
+    if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+      _lt_dsymutil='~$DSYMUTIL $lib || :'
+    else
+      _lt_dsymutil=
+    fi
+    ;;
+  esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_stdc=yes
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then :
+  :
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+		   (('a' <= (c) && (c) <= 'i') \
+		     || ('j' <= (c) && (c) <= 'r') \
+		     || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+	|| toupper (i) != TOUPPER (i))
+      return 2;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+		  inttypes.h stdint.h unistd.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_header in dlfcn.h
+do :
+  ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default
+"
+if test "x$ac_cv_header_dlfcn_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_DLFCN_H 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+
+# Set options
+
+
+
+        enable_dlopen=no
+
+
+  enable_win32_dll=no
+
+
+            # Check whether --enable-shared was given.
+if test "${enable_shared+set}" = set; then :
+  enableval=$enable_shared; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_shared=yes ;;
+    no) enable_shared=no ;;
+    *)
+      enable_shared=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_shared=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  enable_shared=yes
+fi
+
+
+
+
+
+
+
+
+
+  # Check whether --enable-static was given.
+if test "${enable_static+set}" = set; then :
+  enableval=$enable_static; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_static=yes ;;
+    no) enable_static=no ;;
+    *)
+     enable_static=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_static=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  enable_static=yes
+fi
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-pic was given.
+if test "${with_pic+set}" = set; then :
+  withval=$with_pic; lt_p=${PACKAGE-default}
+    case $withval in
+    yes|no) pic_mode=$withval ;;
+    *)
+      pic_mode=default
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for lt_pkg in $withval; do
+	IFS="$lt_save_ifs"
+	if test "X$lt_pkg" = "X$lt_p"; then
+	  pic_mode=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  pic_mode=default
+fi
+
+
+test -z "$pic_mode" && pic_mode=default
+
+
+
+
+
+
+
+  # Check whether --enable-fast-install was given.
+if test "${enable_fast_install+set}" = set; then :
+  enableval=$enable_fast_install; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_fast_install=yes ;;
+    no) enable_fast_install=no ;;
+    *)
+      enable_fast_install=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+	IFS="$lt_save_ifs"
+	if test "X$pkg" = "X$p"; then
+	  enable_fast_install=yes
+	fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  enable_fast_install=yes
+fi
+
+
+
+
+
+
+
+
+
+
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+test -z "$LN_S" && LN_S="ln -s"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5
+$as_echo_n "checking for objdir... " >&6; }
+if ${lt_cv_objdir+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+  lt_cv_objdir=.libs
+else
+  # MS-DOS does not allow filenames that begin with a dot.
+  lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5
+$as_echo "$lt_cv_objdir" >&6; }
+objdir=$lt_cv_objdir
+
+
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define LT_OBJDIR "$lt_cv_objdir/"
+_ACEOF
+
+
+
+
+case $host_os in
+aix3*)
+  # AIX sometimes has problems with the GCC collect2 program.  For some
+  # reason, if we set the COLLECT_NAMES environment variable, the problems
+  # vanish in a puff of smoke.
+  if test "X${COLLECT_NAMES+set}" != Xset; then
+    COLLECT_NAMES=
+    export COLLECT_NAMES
+  fi
+  ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+for cc_temp in $compiler""; do
+  case $cc_temp in
+    compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+    distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+    \-*) ;;
+    *) break;;
+  esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+  if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5
+$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; }
+if ${lt_cv_path_MAGIC_CMD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $MAGIC_CMD in
+[\\/*] |  ?:[\\/]*)
+  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD="$MAGIC_CMD"
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+  for ac_dir in $ac_dummy; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/${ac_tool_prefix}file; then
+      lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file"
+      if test -n "$file_magic_test_file"; then
+	case $deplibs_check_method in
+	"file_magic "*)
+	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+	    $EGREP "$file_magic_regex" > /dev/null; then
+	    :
+	  else
+	    cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool at gnu.org
+
+_LT_EOF
+	  fi ;;
+	esac
+      fi
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+
+
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+  if test -n "$ac_tool_prefix"; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5
+$as_echo_n "checking for file... " >&6; }
+if ${lt_cv_path_MAGIC_CMD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $MAGIC_CMD in
+[\\/*] |  ?:[\\/]*)
+  lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+  ;;
+*)
+  lt_save_MAGIC_CMD="$MAGIC_CMD"
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+  for ac_dir in $ac_dummy; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f $ac_dir/file; then
+      lt_cv_path_MAGIC_CMD="$ac_dir/file"
+      if test -n "$file_magic_test_file"; then
+	case $deplibs_check_method in
+	"file_magic "*)
+	  file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+	  MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+	  if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+	    $EGREP "$file_magic_regex" > /dev/null; then
+	    :
+	  else
+	    cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such.  This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem.  Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool at gnu.org
+
+_LT_EOF
+	  fi ;;
+	esac
+      fi
+      break
+    fi
+  done
+  IFS="$lt_save_ifs"
+  MAGIC_CMD="$lt_save_MAGIC_CMD"
+  ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  else
+    MAGIC_CMD=:
+  fi
+fi
+
+  fi
+  ;;
+esac
+
+# Use C for the default configuration in the libtool script
+
+lt_save_CC="$CC"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+objext=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+
+lt_prog_compiler_no_builtin_flag=
+
+if test "$GCC" = yes; then
+  case $cc_basename in
+  nvcc*)
+    lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;;
+  *)
+    lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;;
+  esac
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; }
+if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_rtti_exceptions=no
+   ac_outfile=conftest.$ac_objext
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="-fno-rtti -fno-exceptions"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_rtti_exceptions=yes
+     fi
+   fi
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
+$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; }
+
+if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then
+    lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
+else
+    :
+fi
+
+fi
+
+
+
+
+
+
+  lt_prog_compiler_wl=
+lt_prog_compiler_pic=
+lt_prog_compiler_static=
+
+
+  if test "$GCC" = yes; then
+    lt_prog_compiler_wl='-Wl,'
+    lt_prog_compiler_static='-static'
+
+    case $host_os in
+      aix*)
+      # All AIX code is PIC.
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static='-Bstatic'
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            lt_prog_compiler_pic='-fPIC'
+        ;;
+      m68k)
+            # FIXME: we need at least 68020 code to build shared libraries, but
+            # adding the `-m68020' flag to GCC prevents building anything better,
+            # like `-m68040'.
+            lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
+        ;;
+      esac
+      ;;
+
+    beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+      # PIC is the default for these OSes.
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      # Although the cygwin gcc ignores -fPIC, still need this for old-style
+      # (--disable-auto-import) libraries
+      lt_prog_compiler_pic='-DDLL_EXPORT'
+      ;;
+
+    darwin* | rhapsody*)
+      # PIC is the default on this platform
+      # Common symbols not allowed in MH_DYLIB files
+      lt_prog_compiler_pic='-fno-common'
+      ;;
+
+    haiku*)
+      # PIC is the default for Haiku.
+      # The "-static" flag exists, but is broken.
+      lt_prog_compiler_static=
+      ;;
+
+    hpux*)
+      # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+      # PA HP-UX.  On IA64 HP-UX, PIC is the default but the pic flag
+      # sets the default TLS model and affects inlining.
+      case $host_cpu in
+      hppa*64*)
+	# +Z the default
+	;;
+      *)
+	lt_prog_compiler_pic='-fPIC'
+	;;
+      esac
+      ;;
+
+    interix[3-9]*)
+      # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+      # Instead, we relocate shared libraries at runtime.
+      ;;
+
+    msdosdjgpp*)
+      # Just because we use GCC doesn't mean we suddenly get shared libraries
+      # on systems that don't support them.
+      lt_prog_compiler_can_build_shared=no
+      enable_shared=no
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      lt_prog_compiler_pic='-fPIC -shared'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	lt_prog_compiler_pic=-Kconform_pic
+      fi
+      ;;
+
+    *)
+      lt_prog_compiler_pic='-fPIC'
+      ;;
+    esac
+
+    case $cc_basename in
+    nvcc*) # Cuda Compiler Driver 2.2
+      lt_prog_compiler_wl='-Xlinker '
+      if test -n "$lt_prog_compiler_pic"; then
+        lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic"
+      fi
+      ;;
+    esac
+  else
+    # PORTME Check for flag to pass linker flags through the system compiler.
+    case $host_os in
+    aix*)
+      lt_prog_compiler_wl='-Wl,'
+      if test "$host_cpu" = ia64; then
+	# AIX 5 now supports IA64 processor
+	lt_prog_compiler_static='-Bstatic'
+      else
+	lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp'
+      fi
+      ;;
+
+    mingw* | cygwin* | pw32* | os2* | cegcc*)
+      # This hack is so that the source file can tell whether it is being
+      # built for inclusion in a dll (and should export symbols for example).
+      lt_prog_compiler_pic='-DDLL_EXPORT'
+      ;;
+
+    hpux9* | hpux10* | hpux11*)
+      lt_prog_compiler_wl='-Wl,'
+      # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+      # not for PA HP-UX.
+      case $host_cpu in
+      hppa*64*|ia64*)
+	# +Z the default
+	;;
+      *)
+	lt_prog_compiler_pic='+Z'
+	;;
+      esac
+      # Is there a better lt_prog_compiler_static that works with the bundled CC?
+      lt_prog_compiler_static='${wl}-a ${wl}archive'
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      lt_prog_compiler_wl='-Wl,'
+      # PIC (with -KPIC) is the default.
+      lt_prog_compiler_static='-non_shared'
+      ;;
+
+    linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+      case $cc_basename in
+      # old Intel for x86_64 which still supported -KPIC.
+      ecc*)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-KPIC'
+	lt_prog_compiler_static='-static'
+        ;;
+      # icc used to be incompatible with GCC.
+      # ICC 10 doesn't accept -KPIC any more.
+      icc* | ifort*)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-fPIC'
+	lt_prog_compiler_static='-static'
+        ;;
+      # Lahey Fortran 8.1.
+      lf95*)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='--shared'
+	lt_prog_compiler_static='--static'
+	;;
+      nagfor*)
+	# NAG Fortran compiler
+	lt_prog_compiler_wl='-Wl,-Wl,,'
+	lt_prog_compiler_pic='-PIC'
+	lt_prog_compiler_static='-Bstatic'
+	;;
+      pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+        # Portland Group compilers (*not* the Pentium gcc compiler,
+	# which looks to be a dead project)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-fpic'
+	lt_prog_compiler_static='-Bstatic'
+        ;;
+      ccc*)
+        lt_prog_compiler_wl='-Wl,'
+        # All Alpha code is PIC.
+        lt_prog_compiler_static='-non_shared'
+        ;;
+      xl* | bgxl* | bgf* | mpixl*)
+	# IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-qpic'
+	lt_prog_compiler_static='-qstaticlink'
+	;;
+      *)
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*)
+	  # Sun Fortran 8.3 passes all unrecognized flags to the linker
+	  lt_prog_compiler_pic='-KPIC'
+	  lt_prog_compiler_static='-Bstatic'
+	  lt_prog_compiler_wl=''
+	  ;;
+	*Sun\ F* | *Sun*Fortran*)
+	  lt_prog_compiler_pic='-KPIC'
+	  lt_prog_compiler_static='-Bstatic'
+	  lt_prog_compiler_wl='-Qoption ld '
+	  ;;
+	*Sun\ C*)
+	  # Sun C 5.9
+	  lt_prog_compiler_pic='-KPIC'
+	  lt_prog_compiler_static='-Bstatic'
+	  lt_prog_compiler_wl='-Wl,'
+	  ;;
+        *Intel*\ [CF]*Compiler*)
+	  lt_prog_compiler_wl='-Wl,'
+	  lt_prog_compiler_pic='-fPIC'
+	  lt_prog_compiler_static='-static'
+	  ;;
+	*Portland\ Group*)
+	  lt_prog_compiler_wl='-Wl,'
+	  lt_prog_compiler_pic='-fpic'
+	  lt_prog_compiler_static='-Bstatic'
+	  ;;
+	esac
+	;;
+      esac
+      ;;
+
+    newsos6)
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    *nto* | *qnx*)
+      # QNX uses GNU C++, but need to define -shared option too, otherwise
+      # it will coredump.
+      lt_prog_compiler_pic='-fPIC -shared'
+      ;;
+
+    osf3* | osf4* | osf5*)
+      lt_prog_compiler_wl='-Wl,'
+      # All OSF/1 code is PIC.
+      lt_prog_compiler_static='-non_shared'
+      ;;
+
+    rdos*)
+      lt_prog_compiler_static='-non_shared'
+      ;;
+
+    solaris*)
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      case $cc_basename in
+      f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+	lt_prog_compiler_wl='-Qoption ld ';;
+      *)
+	lt_prog_compiler_wl='-Wl,';;
+      esac
+      ;;
+
+    sunos4*)
+      lt_prog_compiler_wl='-Qoption ld '
+      lt_prog_compiler_pic='-PIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    sysv4 | sysv4.2uw2* | sysv4.3*)
+      lt_prog_compiler_wl='-Wl,'
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec ;then
+	lt_prog_compiler_pic='-Kconform_pic'
+	lt_prog_compiler_static='-Bstatic'
+      fi
+      ;;
+
+    sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+      lt_prog_compiler_wl='-Wl,'
+      lt_prog_compiler_pic='-KPIC'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    unicos*)
+      lt_prog_compiler_wl='-Wl,'
+      lt_prog_compiler_can_build_shared=no
+      ;;
+
+    uts4*)
+      lt_prog_compiler_pic='-pic'
+      lt_prog_compiler_static='-Bstatic'
+      ;;
+
+    *)
+      lt_prog_compiler_can_build_shared=no
+      ;;
+    esac
+  fi
+
+case $host_os in
+  # For platforms which do not support PIC, -DPIC is meaningless:
+  *djgpp*)
+    lt_prog_compiler_pic=
+    ;;
+  *)
+    lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC"
+    ;;
+esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
+$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
+if ${lt_cv_prog_compiler_pic+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_pic=$lt_prog_compiler_pic
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5
+$as_echo "$lt_cv_prog_compiler_pic" >&6; }
+lt_prog_compiler_pic=$lt_cv_prog_compiler_pic
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
+$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; }
+if ${lt_cv_prog_compiler_pic_works+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_pic_works=no
+   ac_outfile=conftest.$ac_objext
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+   lt_compiler_flag="$lt_prog_compiler_pic -DPIC"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   # The option is referenced via a variable to avoid confusing sed.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>conftest.err)
+   ac_status=$?
+   cat conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s "$ac_outfile"; then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings other than the usual output.
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+     $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+     if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_pic_works=yes
+     fi
+   fi
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5
+$as_echo "$lt_cv_prog_compiler_pic_works" >&6; }
+
+if test x"$lt_cv_prog_compiler_pic_works" = xyes; then
+    case $lt_prog_compiler_pic in
+     "" | " "*) ;;
+     *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
+     esac
+else
+    lt_prog_compiler_pic=
+     lt_prog_compiler_can_build_shared=no
+fi
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
+if ${lt_cv_prog_compiler_static_works+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_static_works=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&5
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         lt_cv_prog_compiler_static_works=yes
+       fi
+     else
+       lt_cv_prog_compiler_static_works=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5
+$as_echo "$lt_cv_prog_compiler_static_works" >&6; }
+
+if test x"$lt_cv_prog_compiler_static_works" = xyes; then
+    :
+else
+    lt_prog_compiler_static=
+fi
+
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_c_o=yes
+     fi
+   fi
+   chmod u+w . 2>&5
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler_c_o=no
+   $RM -r conftest 2>/dev/null
+   mkdir conftest
+   cd conftest
+   mkdir out
+   echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+   lt_compiler_flag="-o out/conftest2.$ac_objext"
+   # Insert the option either (1) after the last *FLAGS variable, or
+   # (2) before a word containing "conftest.", or (3) at the end.
+   # Note that $ac_compile itself does not contain backslashes and begins
+   # with a dollar sign (not a hyphen), so the echo should work correctly.
+   lt_compile=`echo "$ac_compile" | $SED \
+   -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+   -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+   -e 's:$: $lt_compiler_flag:'`
+   (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+   (eval "$lt_compile" 2>out/conftest.err)
+   ac_status=$?
+   cat out/conftest.err >&5
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   if (exit $ac_status) && test -s out/conftest2.$ac_objext
+   then
+     # The compiler can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+     $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+     if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+       lt_cv_prog_compiler_c_o=yes
+     fi
+   fi
+   chmod u+w . 2>&5
+   $RM conftest*
+   # SGI C++ compiler will create directory out/ii_files/ for
+   # template instantiation
+   test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+   $RM out/* && rmdir out
+   cd ..
+   $RM -r conftest
+   $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then
+  # do not overwrite the value of need_locks provided by the user
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
+$as_echo_n "checking if we can lock with hard links... " >&6; }
+  hard_links=yes
+  $RM conftest*
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  touch conftest.a
+  ln conftest.a conftest.b 2>&5 || hard_links=no
+  ln conftest.a conftest.b 2>/dev/null && hard_links=no
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
+$as_echo "$hard_links" >&6; }
+  if test "$hard_links" = no; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+    need_locks=warn
+  fi
+else
+  need_locks=no
+fi
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+
+  runpath_var=
+  allow_undefined_flag=
+  always_export_symbols=no
+  archive_cmds=
+  archive_expsym_cmds=
+  compiler_needs_object=no
+  enable_shared_with_static_runtimes=no
+  export_dynamic_flag_spec=
+  export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+  hardcode_automatic=no
+  hardcode_direct=no
+  hardcode_direct_absolute=no
+  hardcode_libdir_flag_spec=
+  hardcode_libdir_separator=
+  hardcode_minus_L=no
+  hardcode_shlibpath_var=unsupported
+  inherit_rpath=no
+  link_all_deplibs=unknown
+  module_cmds=
+  module_expsym_cmds=
+  old_archive_from_new_cmds=
+  old_archive_from_expsyms_cmds=
+  thread_safe_flag_spec=
+  whole_archive_flag_spec=
+  # include_expsyms should be a list of space-separated symbols to be *always*
+  # included in the symbol list
+  include_expsyms=
+  # exclude_expsyms can be an extended regexp of symbols to exclude
+  # it will be wrapped by ` (' and `)$', so one must not match beginning or
+  # end of line.  Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+  # as well as any symbol that contains `d'.
+  exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
+  # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+  # platforms (ab)use it in PIC code, but their linkers get confused if
+  # the symbol is explicitly referenced.  Since portable code cannot
+  # rely on this symbol name, it's probably fine to never include it in
+  # preloaded symbol tables.
+  # Exclude shared library initialization/finalization symbols.
+  extract_expsyms_cmds=
+
+  case $host_os in
+  cygwin* | mingw* | pw32* | cegcc*)
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+    # When not using gcc, we currently assume that we are using
+    # Microsoft Visual C++.
+    if test "$GCC" != yes; then
+      with_gnu_ld=no
+    fi
+    ;;
+  interix*)
+    # we just hope/assume this is gcc and not c89 (= MSVC++)
+    with_gnu_ld=yes
+    ;;
+  openbsd*)
+    with_gnu_ld=no
+    ;;
+  linux* | k*bsd*-gnu | gnu*)
+    link_all_deplibs=no
+    ;;
+  esac
+
+  ld_shlibs=yes
+
+  # On some targets, GNU ld is compatible enough with the native linker
+  # that we're better off using the native interface for both.
+  lt_use_gnu_ld_interface=no
+  if test "$with_gnu_ld" = yes; then
+    case $host_os in
+      aix*)
+	# The AIX port of GNU ld has always aspired to compatibility
+	# with the native linker.  However, as the warning in the GNU ld
+	# block says, versions before 2.19.5* couldn't really create working
+	# shared libraries, regardless of the interface used.
+	case `$LD -v 2>&1` in
+	  *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+	  *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;;
+	  *\ \(GNU\ Binutils\)\ [3-9]*) ;;
+	  *)
+	    lt_use_gnu_ld_interface=yes
+	    ;;
+	esac
+	;;
+      *)
+	lt_use_gnu_ld_interface=yes
+	;;
+    esac
+  fi
+
+  if test "$lt_use_gnu_ld_interface" = yes; then
+    # If archive_cmds runs LD, not CC, wlarc should be empty
+    wlarc='${wl}'
+
+    # Set some defaults for GNU ld with shared library support. These
+    # are reset later if shared libraries are not supported. Putting them
+    # here allows them to be overridden if necessary.
+    runpath_var=LD_RUN_PATH
+    hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+    export_dynamic_flag_spec='${wl}--export-dynamic'
+    # ancient GNU ld didn't support --whole-archive et. al.
+    if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+      whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+    else
+      whole_archive_flag_spec=
+    fi
+    supports_anon_versioning=no
+    case `$LD -v 2>&1` in
+      *GNU\ gold*) supports_anon_versioning=yes ;;
+      *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+      *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+      *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+      *\ 2.11.*) ;; # other 2.11 versions
+      *) supports_anon_versioning=yes ;;
+    esac
+
+    # See if GNU ld supports shared libraries.
+    case $host_os in
+    aix[3-9]*)
+      # On AIX/PPC, the GNU linker is very broken
+      if test "$host_cpu" != ia64; then
+	ld_shlibs=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support.  If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            archive_expsym_cmds=''
+        ;;
+      m68k)
+            archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            hardcode_libdir_flag_spec='-L$libdir'
+            hardcode_minus_L=yes
+        ;;
+      esac
+      ;;
+
+    beos*)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	allow_undefined_flag=unsupported
+	# Joseph Beckenbach <jrb3 at best.com> says some releases of gcc
+	# support --undefined.  This deserves some investigation.  FIXME
+	archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
+      # as there is no search path for DLLs.
+      hardcode_libdir_flag_spec='-L$libdir'
+      export_dynamic_flag_spec='${wl}--export-all-symbols'
+      allow_undefined_flag=unsupported
+      always_export_symbols=no
+      enable_shared_with_static_runtimes=yes
+      export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols'
+      exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'
+
+      if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+        archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+	# If the export-symbols file already is a .def file (1st line
+	# is EXPORTS), use it as is; otherwise, prepend...
+	archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	  cp $export_symbols $output_objdir/$soname.def;
+	else
+	  echo EXPORTS > $output_objdir/$soname.def;
+	  cat $export_symbols >> $output_objdir/$soname.def;
+	fi~
+	$CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    haiku*)
+      archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+      link_all_deplibs=yes
+      ;;
+
+    interix[3-9]*)
+      hardcode_direct=no
+      hardcode_shlibpath_var=no
+      hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+      export_dynamic_flag_spec='${wl}-E'
+      # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+      # Instead, shared libraries are loaded at an image base (0x10000000 by
+      # default) and relocated if they conflict, which is a slow very memory
+      # consuming and fragmenting process.  To avoid this, we pick a random,
+      # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+      # time.  Moving up from 0x10000000 also allows more sbrk(2) space.
+      archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+      ;;
+
+    gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+      tmp_diet=no
+      if test "$host_os" = linux-dietlibc; then
+	case $cc_basename in
+	  diet\ *) tmp_diet=yes;;	# linux-dietlibc with static linking (!diet-dyn)
+	esac
+      fi
+      if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+	 && test "$tmp_diet" = no
+      then
+	tmp_addflag=' $pic_flag'
+	tmp_sharedflag='-shared'
+	case $cc_basename,$host_cpu in
+        pgcc*)				# Portland Group C compiler
+	  whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  tmp_addflag=' $pic_flag'
+	  ;;
+	pgf77* | pgf90* | pgf95* | pgfortran*)
+					# Portland Group f77 and f90 compilers
+	  whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  tmp_addflag=' $pic_flag -Mnomain' ;;
+	ecc*,ia64* | icc*,ia64*)	# Intel C compiler on ia64
+	  tmp_addflag=' -i_dynamic' ;;
+	efc*,ia64* | ifort*,ia64*)	# Intel Fortran compiler on ia64
+	  tmp_addflag=' -i_dynamic -nofor_main' ;;
+	ifc* | ifort*)			# Intel Fortran compiler
+	  tmp_addflag=' -nofor_main' ;;
+	lf95*)				# Lahey Fortran 8.1
+	  whole_archive_flag_spec=
+	  tmp_sharedflag='--shared' ;;
+	xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+	  tmp_sharedflag='-qmkshrobj'
+	  tmp_addflag= ;;
+	nvcc*)	# Cuda Compiler Driver 2.2
+	  whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  compiler_needs_object=yes
+	  ;;
+	esac
+	case `$CC -V 2>&1 | sed 5q` in
+	*Sun\ C*)			# Sun C 5.9
+	  whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+	  compiler_needs_object=yes
+	  tmp_sharedflag='-G' ;;
+	*Sun\ F*)			# Sun Fortran 8.3
+	  tmp_sharedflag='-G' ;;
+	esac
+	archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+        if test "x$supports_anon_versioning" = xyes; then
+          archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+	    cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+	    echo "local: *; };" >> $output_objdir/$libname.ver~
+	    $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+        fi
+
+	case $cc_basename in
+	xlf* | bgf* | bgxlf* | mpixlf*)
+	  # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+	  whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive'
+	  hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+	  archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
+	  if test "x$supports_anon_versioning" = xyes; then
+	    archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+	      cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+	      echo "local: *; };" >> $output_objdir/$libname.ver~
+	      $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+	  fi
+	  ;;
+	esac
+      else
+        ld_shlibs=no
+      fi
+      ;;
+
+    netbsd* | netbsdelf*-gnu)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+	wlarc=
+      else
+	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      fi
+      ;;
+
+    solaris*)
+      if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+	ld_shlibs=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+      elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+      case `$LD -v 2>&1` in
+        *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+	ld_shlibs=no
+	cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems.  Therefore, libtool
+*** is disabling shared libraries support.  We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer.  Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+	;;
+	*)
+	  # For security reasons, it is highly recommended that you always
+	  # use absolute paths for naming shared libraries, and exclude the
+	  # DT_RUNPATH tag from executables and libraries.  But doing so
+	  # requires that you compile everything twice, which is a pain.
+	  if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	    hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+	    archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	    archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+	  else
+	    ld_shlibs=no
+	  fi
+	;;
+      esac
+      ;;
+
+    sunos4*)
+      archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      wlarc=
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    *)
+      if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+	archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+      else
+	ld_shlibs=no
+      fi
+      ;;
+    esac
+
+    if test "$ld_shlibs" = no; then
+      runpath_var=
+      hardcode_libdir_flag_spec=
+      export_dynamic_flag_spec=
+      whole_archive_flag_spec=
+    fi
+  else
+    # PORTME fill in a description of your system's linker (not GNU ld)
+    case $host_os in
+    aix3*)
+      allow_undefined_flag=unsupported
+      always_export_symbols=yes
+      archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+      # Note: this linker hardcodes the directories in LIBPATH if there
+      # are no directories specified by -L.
+      hardcode_minus_L=yes
+      if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+	# Neither direct hardcoding nor static linking is supported with a
+	# broken collect2.
+	hardcode_direct=unsupported
+      fi
+      ;;
+
+    aix[4-9]*)
+      if test "$host_cpu" = ia64; then
+	# On IA64, the linker does run time linking by default, so we don't
+	# have to do anything special.
+	aix_use_runtimelinking=no
+	exp_sym_flag='-Bexport'
+	no_entry_flag=""
+      else
+	# If we're using GNU nm, then we don't want the "-C" option.
+	# -C means demangle to AIX nm, but means don't demangle with GNU nm
+	# Also, AIX nm treats weak defined symbols like other global
+	# defined symbols, whereas GNU nm marks them as "W".
+	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+	  export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	else
+	  export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+	fi
+	aix_use_runtimelinking=no
+
+	# Test if we are trying to use run time linking or normal
+	# AIX style linking. If -brtl is somewhere in LDFLAGS, we
+	# need to do runtime linking.
+	case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+	  for ld_flag in $LDFLAGS; do
+	  if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+	    aix_use_runtimelinking=yes
+	    break
+	  fi
+	  done
+	  ;;
+	esac
+
+	exp_sym_flag='-bexport'
+	no_entry_flag='-bnoentry'
+      fi
+
+      # When large executables or shared objects are built, AIX ld can
+      # have problems creating the table of contents.  If linking a library
+      # or program results in "error TOC overflow" add -mminimal-toc to
+      # CXXFLAGS/CFLAGS for g++/gcc.  In the cases where that is not
+      # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+      archive_cmds=''
+      hardcode_direct=yes
+      hardcode_direct_absolute=yes
+      hardcode_libdir_separator=':'
+      link_all_deplibs=yes
+      file_list_spec='${wl}-f,'
+
+      if test "$GCC" = yes; then
+	case $host_os in aix4.[012]|aix4.[012].*)
+	# We only want to do this on AIX 4.2 and lower, the check
+	# below for broken collect2 doesn't work under 4.3+
+	  collect2name=`${CC} -print-prog-name=collect2`
+	  if test -f "$collect2name" &&
+	   strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+	  then
+	  # We have reworked collect2
+	  :
+	  else
+	  # We have old collect2
+	  hardcode_direct=unsupported
+	  # It fails to find uninstalled libraries when the uninstalled
+	  # path is not listed in the libpath.  Setting hardcode_minus_L
+	  # to unsupported forces relinking
+	  hardcode_minus_L=yes
+	  hardcode_libdir_flag_spec='-L$libdir'
+	  hardcode_libdir_separator=
+	  fi
+	  ;;
+	esac
+	shared_flag='-shared'
+	if test "$aix_use_runtimelinking" = yes; then
+	  shared_flag="$shared_flag "'${wl}-G'
+	fi
+	link_all_deplibs=no
+      else
+	# not using gcc
+	if test "$host_cpu" = ia64; then
+	# VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+	# chokes on -Wl,-G. The following line is correct:
+	  shared_flag='-G'
+	else
+	  if test "$aix_use_runtimelinking" = yes; then
+	    shared_flag='${wl}-G'
+	  else
+	    shared_flag='${wl}-bM:SRE'
+	  fi
+	fi
+      fi
+
+      export_dynamic_flag_spec='${wl}-bexpall'
+      # It seems that -bexpall does not export symbols beginning with
+      # underscore (_), so it is better to generate a list of symbols to export.
+      always_export_symbols=yes
+      if test "$aix_use_runtimelinking" = yes; then
+	# Warning - without using the other runtime loading flags (-brtl),
+	# -berok will link without error, but may produce a broken library.
+	allow_undefined_flag='-berok'
+        # Determine the default libpath from the value encoded in an
+        # empty executable.
+        if test "${lt_cv_aix_libpath+set}" = set; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  if ${lt_cv_aix_libpath_+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+  lt_aix_libpath_sed='
+      /Import File Strings/,/^$/ {
+	  /^0/ {
+	      s/^0  *\([^ ]*\) *$/\1/
+	      p
+	  }
+      }'
+  lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$lt_cv_aix_libpath_"; then
+    lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  if test -z "$lt_cv_aix_libpath_"; then
+    lt_cv_aix_libpath_="/usr/lib:/lib"
+  fi
+
+fi
+
+  aix_libpath=$lt_cv_aix_libpath_
+fi
+
+        hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+        archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+      else
+	if test "$host_cpu" = ia64; then
+	  hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+	  allow_undefined_flag="-z nodefs"
+	  archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+	else
+	 # Determine the default libpath from the value encoded in an
+	 # empty executable.
+	 if test "${lt_cv_aix_libpath+set}" = set; then
+  aix_libpath=$lt_cv_aix_libpath
+else
+  if ${lt_cv_aix_libpath_+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+  lt_aix_libpath_sed='
+      /Import File Strings/,/^$/ {
+	  /^0/ {
+	      s/^0  *\([^ ]*\) *$/\1/
+	      p
+	  }
+      }'
+  lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  # Check for a 64-bit object if we didn't find anything.
+  if test -z "$lt_cv_aix_libpath_"; then
+    lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+  fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+  if test -z "$lt_cv_aix_libpath_"; then
+    lt_cv_aix_libpath_="/usr/lib:/lib"
+  fi
+
+fi
+
+  aix_libpath=$lt_cv_aix_libpath_
+fi
+
+	 hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+	  # Warning - without using the other run time loading flags,
+	  # -berok will link without error, but may produce a broken library.
+	  no_undefined_flag=' ${wl}-bernotok'
+	  allow_undefined_flag=' ${wl}-berok'
+	  if test "$with_gnu_ld" = yes; then
+	    # We only use this code for GNU lds that support --whole-archive.
+	    whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+	  else
+	    # Exported symbols can be pulled into shared objects from archives
+	    whole_archive_flag_spec='$convenience'
+	  fi
+	  archive_cmds_need_lc=yes
+	  # This is similar to how AIX traditionally builds its shared libraries.
+	  archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+	fi
+      fi
+      ;;
+
+    amigaos*)
+      case $host_cpu in
+      powerpc)
+            # see comment about AmigaOS4 .so support
+            archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+            archive_expsym_cmds=''
+        ;;
+      m68k)
+            archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+            hardcode_libdir_flag_spec='-L$libdir'
+            hardcode_minus_L=yes
+        ;;
+      esac
+      ;;
+
+    bsdi[45]*)
+      export_dynamic_flag_spec=-rdynamic
+      ;;
+
+    cygwin* | mingw* | pw32* | cegcc*)
+      # When not using gcc, we currently assume that we are using
+      # Microsoft Visual C++.
+      # hardcode_libdir_flag_spec is actually meaningless, as there is
+      # no search path for DLLs.
+      case $cc_basename in
+      cl*)
+	# Native MSVC
+	hardcode_libdir_flag_spec=' '
+	allow_undefined_flag=unsupported
+	always_export_symbols=yes
+	file_list_spec='@'
+	# Tell ltmain to make .lib files, not .a files.
+	libext=lib
+	# Tell ltmain to make .dll files, not .so files.
+	shrext_cmds=".dll"
+	# FIXME: Setting linknames here is a bad hack.
+	archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
+	archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+	    sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
+	  else
+	    sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
+	  fi~
+	  $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+	  linknames='
+	# The linker will not automatically build a static lib if we build a DLL.
+	# _LT_TAGVAR(old_archive_from_new_cmds, )='true'
+	enable_shared_with_static_runtimes=yes
+	exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+	export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols'
+	# Don't use ranlib
+	old_postinstall_cmds='chmod 644 $oldlib'
+	postlink_cmds='lt_outputfile="@OUTPUT@"~
+	  lt_tool_outputfile="@TOOL_OUTPUT@"~
+	  case $lt_outputfile in
+	    *.exe|*.EXE) ;;
+	    *)
+	      lt_outputfile="$lt_outputfile.exe"
+	      lt_tool_outputfile="$lt_tool_outputfile.exe"
+	      ;;
+	  esac~
+	  if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
+	    $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+	    $RM "$lt_outputfile.manifest";
+	  fi'
+	;;
+      *)
+	# Assume MSVC wrapper
+	hardcode_libdir_flag_spec=' '
+	allow_undefined_flag=unsupported
+	# Tell ltmain to make .lib files, not .a files.
+	libext=lib
+	# Tell ltmain to make .dll files, not .so files.
+	shrext_cmds=".dll"
+	# FIXME: Setting linknames here is a bad hack.
+	archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+	# The linker will automatically build a .lib file if we build a DLL.
+	old_archive_from_new_cmds='true'
+	# FIXME: Should let the user specify the lib program.
+	old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs'
+	enable_shared_with_static_runtimes=yes
+	;;
+      esac
+      ;;
+
+    darwin* | rhapsody*)
+
+
+  archive_cmds_need_lc=no
+  hardcode_direct=no
+  hardcode_automatic=yes
+  hardcode_shlibpath_var=unsupported
+  if test "$lt_cv_ld_force_load" = "yes"; then
+    whole_archive_flag_spec='`for conv in $convenience\"\"; do test  -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+
+  else
+    whole_archive_flag_spec=''
+  fi
+  link_all_deplibs=yes
+  allow_undefined_flag="$_lt_dar_allow_undefined"
+  case $cc_basename in
+     ifort*) _lt_dar_can_shared=yes ;;
+     *) _lt_dar_can_shared=$GCC ;;
+  esac
+  if test "$_lt_dar_can_shared" = "yes"; then
+    output_verbose_link_cmd=func_echo_all
+    archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+    module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+    archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+    module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+
+  else
+  ld_shlibs=no
+  fi
+
+      ;;
+
+    dgux*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_shlibpath_var=no
+      ;;
+
+    # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+    # support.  Future versions do this automatically, but an explicit c++rt0.o
+    # does not break anything, and helps significantly (at the cost of a little
+    # extra space).
+    freebsd2.2*)
+      archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+    freebsd2.*)
+      archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct=yes
+      hardcode_minus_L=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+    freebsd* | dragonfly*)
+      archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    hpux9*)
+      if test "$GCC" = yes; then
+	archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      else
+	archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+      fi
+      hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+      hardcode_libdir_separator=:
+      hardcode_direct=yes
+
+      # hardcode_minus_L: Not really in the search PATH,
+      # but as the default location of the library.
+      hardcode_minus_L=yes
+      export_dynamic_flag_spec='${wl}-E'
+      ;;
+
+    hpux10*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+	archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      if test "$with_gnu_ld" = no; then
+	hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+	hardcode_libdir_separator=:
+	hardcode_direct=yes
+	hardcode_direct_absolute=yes
+	export_dynamic_flag_spec='${wl}-E'
+	# hardcode_minus_L: Not really in the search PATH,
+	# but as the default location of the library.
+	hardcode_minus_L=yes
+      fi
+      ;;
+
+    hpux11*)
+      if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+	case $host_cpu in
+	hppa*64*)
+	  archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+	  archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	esac
+      else
+	case $host_cpu in
+	hppa*64*)
+	  archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	ia64*)
+	  archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+	  ;;
+	*)
+
+	  # Older versions of the 11.00 compiler do not understand -b yet
+	  # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+	  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5
+$as_echo_n "checking if $CC understands -b... " >&6; }
+if ${lt_cv_prog_compiler__b+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_prog_compiler__b=no
+   save_LDFLAGS="$LDFLAGS"
+   LDFLAGS="$LDFLAGS -b"
+   echo "$lt_simple_link_test_code" > conftest.$ac_ext
+   if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+     # The linker can only warn and ignore the option if not recognized
+     # So say no if there are warnings
+     if test -s conftest.err; then
+       # Append any errors to the config.log.
+       cat conftest.err 1>&5
+       $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+       $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+       if diff conftest.exp conftest.er2 >/dev/null; then
+         lt_cv_prog_compiler__b=yes
+       fi
+     else
+       lt_cv_prog_compiler__b=yes
+     fi
+   fi
+   $RM -r conftest*
+   LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5
+$as_echo "$lt_cv_prog_compiler__b" >&6; }
+
+if test x"$lt_cv_prog_compiler__b" = xyes; then
+    archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+else
+    archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+fi
+
+	  ;;
+	esac
+      fi
+      if test "$with_gnu_ld" = no; then
+	hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+	hardcode_libdir_separator=:
+
+	case $host_cpu in
+	hppa*64*|ia64*)
+	  hardcode_direct=no
+	  hardcode_shlibpath_var=no
+	  ;;
+	*)
+	  hardcode_direct=yes
+	  hardcode_direct_absolute=yes
+	  export_dynamic_flag_spec='${wl}-E'
+
+	  # hardcode_minus_L: Not really in the search PATH,
+	  # but as the default location of the library.
+	  hardcode_minus_L=yes
+	  ;;
+	esac
+      fi
+      ;;
+
+    irix5* | irix6* | nonstopux*)
+      if test "$GCC" = yes; then
+	archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	# Try to use the -exported_symbol ld option, if it does not
+	# work, assume that -exports_file does not work either and
+	# implicitly export all symbols.
+	# This should be the same for all languages, so no per-tag cache variable.
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5
+$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; }
+if ${lt_cv_irix_exported_symbol+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  save_LDFLAGS="$LDFLAGS"
+	   LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+	   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int foo (void) { return 0; }
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  lt_cv_irix_exported_symbol=yes
+else
+  lt_cv_irix_exported_symbol=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+           LDFLAGS="$save_LDFLAGS"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5
+$as_echo "$lt_cv_irix_exported_symbol" >&6; }
+	if test "$lt_cv_irix_exported_symbol" = yes; then
+          archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+	fi
+      else
+	archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+      fi
+      archive_cmds_need_lc='no'
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      inherit_rpath=yes
+      link_all_deplibs=yes
+      ;;
+
+    netbsd* | netbsdelf*-gnu)
+      if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+	archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
+      else
+	archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags'      # ELF
+      fi
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_direct=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    newsos6)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_direct=yes
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      hardcode_shlibpath_var=no
+      ;;
+
+    *nto* | *qnx*)
+      ;;
+
+    openbsd*)
+      if test -f /usr/libexec/ld.so; then
+	hardcode_direct=yes
+	hardcode_shlibpath_var=no
+	hardcode_direct_absolute=yes
+	if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+	  archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+	  hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+	  export_dynamic_flag_spec='${wl}-E'
+	else
+	  case $host_os in
+	   openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+	     archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+	     hardcode_libdir_flag_spec='-R$libdir'
+	     ;;
+	   *)
+	     archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+	     hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+	     ;;
+	  esac
+	fi
+      else
+	ld_shlibs=no
+      fi
+      ;;
+
+    os2*)
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_minus_L=yes
+      allow_undefined_flag=unsupported
+      archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+      old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+      ;;
+
+    osf3*)
+      if test "$GCC" = yes; then
+	allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+	archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+      else
+	allow_undefined_flag=' -expect_unresolved \*'
+	archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+      fi
+      archive_cmds_need_lc='no'
+      hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      hardcode_libdir_separator=:
+      ;;
+
+    osf4* | osf5*)	# as osf3* with the addition of -msym flag
+      if test "$GCC" = yes; then
+	allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+	archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+	hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+      else
+	allow_undefined_flag=' -expect_unresolved \*'
+	archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+	archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+	$CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+	# Both c and cxx compiler support -rpath directly
+	hardcode_libdir_flag_spec='-rpath $libdir'
+      fi
+      archive_cmds_need_lc='no'
+      hardcode_libdir_separator=:
+      ;;
+
+    solaris*)
+      no_undefined_flag=' -z defs'
+      if test "$GCC" = yes; then
+	wlarc='${wl}'
+	archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+      else
+	case `$CC -V 2>&1` in
+	*"Compilers 5.0"*)
+	  wlarc=''
+	  archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+	  ;;
+	*)
+	  wlarc='${wl}'
+	  archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+	  archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+	  $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+	  ;;
+	esac
+      fi
+      hardcode_libdir_flag_spec='-R$libdir'
+      hardcode_shlibpath_var=no
+      case $host_os in
+      solaris2.[0-5] | solaris2.[0-5].*) ;;
+      *)
+	# The compiler driver will combine and reorder linker options,
+	# but understands `-z linker_flag'.  GCC discards it without `$wl',
+	# but is careful enough not to reorder.
+	# Supported since Solaris 2.6 (maybe 2.5.1?)
+	if test "$GCC" = yes; then
+	  whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+	else
+	  whole_archive_flag_spec='-z allextract$convenience -z defaultextract'
+	fi
+	;;
+      esac
+      link_all_deplibs=yes
+      ;;
+
+    sunos4*)
+      if test "x$host_vendor" = xsequent; then
+	# Use $CC to link under sequent, because it throws in some extra .o
+	# files that make .init and .fini sections work.
+	archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+      fi
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_direct=yes
+      hardcode_minus_L=yes
+      hardcode_shlibpath_var=no
+      ;;
+
+    sysv4)
+      case $host_vendor in
+	sni)
+	  archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  hardcode_direct=yes # is this really true???
+	;;
+	siemens)
+	  ## LD is ld it makes a PLAMLIB
+	  ## CC just makes a GrossModule.
+	  archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+	  reload_cmds='$CC -r -o $output$reload_objs'
+	  hardcode_direct=no
+        ;;
+	motorola)
+	  archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	  hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+	;;
+      esac
+      runpath_var='LD_RUN_PATH'
+      hardcode_shlibpath_var=no
+      ;;
+
+    sysv4.3*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_shlibpath_var=no
+      export_dynamic_flag_spec='-Bexport'
+      ;;
+
+    sysv4*MP*)
+      if test -d /usr/nec; then
+	archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+	hardcode_shlibpath_var=no
+	runpath_var=LD_RUN_PATH
+	hardcode_runpath_var=yes
+	ld_shlibs=yes
+      fi
+      ;;
+
+    sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+      no_undefined_flag='${wl}-z,text'
+      archive_cmds_need_lc=no
+      hardcode_shlibpath_var=no
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+	archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    sysv5* | sco3.2v5* | sco5v6*)
+      # Note: We can NOT use -z defs as we might desire, because we do not
+      # link with -lc, and that would cause any symbols used from libc to
+      # always be unresolved, which means just about no library would
+      # ever link correctly.  If we're not using GNU ld we use -z text
+      # though, which does catch some bad symbols but isn't as heavy-handed
+      # as -z defs.
+      no_undefined_flag='${wl}-z,text'
+      allow_undefined_flag='${wl}-z,nodefs'
+      archive_cmds_need_lc=no
+      hardcode_shlibpath_var=no
+      hardcode_libdir_flag_spec='${wl}-R,$libdir'
+      hardcode_libdir_separator=':'
+      link_all_deplibs=yes
+      export_dynamic_flag_spec='${wl}-Bexport'
+      runpath_var='LD_RUN_PATH'
+
+      if test "$GCC" = yes; then
+	archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      else
+	archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+	archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+      fi
+      ;;
+
+    uts4*)
+      archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+      hardcode_libdir_flag_spec='-L$libdir'
+      hardcode_shlibpath_var=no
+      ;;
+
+    *)
+      ld_shlibs=no
+      ;;
+    esac
+
+    if test x$host_vendor = xsni; then
+      case $host in
+      sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+	export_dynamic_flag_spec='${wl}-Blargedynsym'
+	;;
+      esac
+    fi
+  fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5
+$as_echo "$ld_shlibs" >&6; }
+test "$ld_shlibs" = no && can_build_shared=no
+
+with_gnu_ld=$with_gnu_ld
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc" in
+x|xyes)
+  # Assume -lc should be added
+  archive_cmds_need_lc=yes
+
+  if test "$enable_shared" = yes && test "$GCC" = yes; then
+    case $archive_cmds in
+    *'~'*)
+      # FIXME: we may have to deal with multi-command sequences.
+      ;;
+    '$CC '*)
+      # Test whether the compiler implicitly links with -lc since on some
+      # systems, -lgcc has to come before -lc. If gcc already passes -lc
+      # to ld, don't add -lc before -lgcc.
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
+$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
+if ${lt_cv_archive_cmds_need_lc+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  $RM conftest*
+	echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+	if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+  (eval $ac_compile) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } 2>conftest.err; then
+	  soname=conftest
+	  lib=conftest
+	  libobjs=conftest.$ac_objext
+	  deplibs=
+	  wl=$lt_prog_compiler_wl
+	  pic_flag=$lt_prog_compiler_pic
+	  compiler_flags=-v
+	  linker_flags=-v
+	  verstring=
+	  output_objdir=.
+	  libname=conftest
+	  lt_save_allow_undefined_flag=$allow_undefined_flag
+	  allow_undefined_flag=
+	  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
+  (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+	  then
+	    lt_cv_archive_cmds_need_lc=no
+	  else
+	    lt_cv_archive_cmds_need_lc=yes
+	  fi
+	  allow_undefined_flag=$lt_save_allow_undefined_flag
+	else
+	  cat conftest.err 1>&5
+	fi
+	$RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5
+$as_echo "$lt_cv_archive_cmds_need_lc" >&6; }
+      archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc
+      ;;
+    esac
+  fi
+  ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
+$as_echo_n "checking dynamic linker characteristics... " >&6; }
+
+if test "$GCC" = yes; then
+  case $host_os in
+    darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+    *) lt_awk_arg="/^libraries:/" ;;
+  esac
+  case $host_os in
+    mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;;
+    *) lt_sed_strip_eq="s,=/,/,g" ;;
+  esac
+  lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+  case $lt_search_path_spec in
+  *\;*)
+    # if the path contains ";" then we assume it to be the separator
+    # otherwise default to the standard path separator (i.e. ":") - it is
+    # assumed that no part of a normal pathname contains ";" but that should
+    # okay in the real world where ";" in dirpaths is itself problematic.
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+    ;;
+  *)
+    lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+    ;;
+  esac
+  # Ok, now we have the path, separated by spaces, we can step through it
+  # and add multilib dir if necessary.
+  lt_tmp_lt_search_path_spec=
+  lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+  for lt_sys_path in $lt_search_path_spec; do
+    if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+      lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+    else
+      test -d "$lt_sys_path" && \
+	lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+    fi
+  done
+  lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+  lt_foo="";
+  lt_count=0;
+  for (lt_i = NF; lt_i > 0; lt_i--) {
+    if ($lt_i != "" && $lt_i != ".") {
+      if ($lt_i == "..") {
+        lt_count++;
+      } else {
+        if (lt_count == 0) {
+          lt_foo="/" $lt_i lt_foo;
+        } else {
+          lt_count--;
+        }
+      }
+    }
+  }
+  if (lt_foo != "") { lt_freq[lt_foo]++; }
+  if (lt_freq[lt_foo] == 1) { print lt_foo; }
+}'`
+  # AWK program above erroneously prepends '/' to C:/dos/paths
+  # for these hosts.
+  case $host_os in
+    mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+      $SED 's,/\([A-Za-z]:\),\1,g'` ;;
+  esac
+  sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+  sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+  shlibpath_var=LIBPATH
+
+  # AIX 3 has no versioning support, so we append a major version to the name.
+  soname_spec='${libname}${release}${shared_ext}$major'
+  ;;
+
+aix[4-9]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  hardcode_into_libs=yes
+  if test "$host_cpu" = ia64; then
+    # AIX 5 supports IA64
+    library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+    shlibpath_var=LD_LIBRARY_PATH
+  else
+    # With GCC up to 2.95.x, collect2 would create an import file
+    # for dependence libraries.  The import file would start with
+    # the line `#! .'.  This would cause the generated library to
+    # depend on `.', always an invalid library.  This was fixed in
+    # development snapshots of GCC prior to 3.0.
+    case $host_os in
+      aix4 | aix4.[01] | aix4.[01].*)
+      if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+	   echo ' yes '
+	   echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+	:
+      else
+	can_build_shared=no
+      fi
+      ;;
+    esac
+    # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+    # soname into executable. Probably we can add versioning support to
+    # collect2, so additional links can be useful in future.
+    if test "$aix_use_runtimelinking" = yes; then
+      # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+      # instead of lib<name>.a to let people know that these are not
+      # typical AIX shared libraries.
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    else
+      # We preserve .a as extension for shared libraries through AIX4.2
+      # and later when we are not doing run time linking.
+      library_names_spec='${libname}${release}.a $libname.a'
+      soname_spec='${libname}${release}${shared_ext}$major'
+    fi
+    shlibpath_var=LIBPATH
+  fi
+  ;;
+
+amigaos*)
+  case $host_cpu in
+  powerpc)
+    # Since July 2007 AmigaOS4 officially supports .so libraries.
+    # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    ;;
+  m68k)
+    library_names_spec='$libname.ixlibrary $libname.a'
+    # Create ${libname}_ixlibrary.a entries in /sys/libs.
+    finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+    ;;
+  esac
+  ;;
+
+beos*)
+  library_names_spec='${libname}${shared_ext}'
+  dynamic_linker="$host_os ld.so"
+  shlibpath_var=LIBRARY_PATH
+  ;;
+
+bsdi[45]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+  sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+  # the default ld.so.conf also contains /usr/contrib/lib and
+  # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+  # libtool to hard-code these into programs
+  ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+  version_type=windows
+  shrext_cmds=".dll"
+  need_version=no
+  need_lib_prefix=no
+
+  case $GCC,$cc_basename in
+  yes,*)
+    # gcc
+    library_names_spec='$libname.dll.a'
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname~
+      chmod a+x \$dldir/$dlname~
+      if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+        eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+      fi'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+
+    case $host_os in
+    cygwin*)
+      # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+      soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+
+      sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"
+      ;;
+    mingw* | cegcc*)
+      # MinGW DLLs use traditional 'lib' prefix
+      soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    pw32*)
+      # pw32 DLLs use 'pw' prefix rather than 'lib'
+      library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+      ;;
+    esac
+    dynamic_linker='Win32 ld.exe'
+    ;;
+
+  *,cl*)
+    # Native MSVC
+    libname_spec='$name'
+    soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+    library_names_spec='${libname}.dll.lib'
+
+    case $build_os in
+    mingw*)
+      sys_lib_search_path_spec=
+      lt_save_ifs=$IFS
+      IFS=';'
+      for lt_path in $LIB
+      do
+        IFS=$lt_save_ifs
+        # Let DOS variable expansion print the short 8.3 style file name.
+        lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+        sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+      done
+      IFS=$lt_save_ifs
+      # Convert to MSYS style.
+      sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'`
+      ;;
+    cygwin*)
+      # Convert to unix form, then to dos form, then back to unix form
+      # but this time dos style (no spaces!) so that the unix form looks
+      # like /cygdrive/c/PROGRA~1:/cygdr...
+      sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+      sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+      sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      ;;
+    *)
+      sys_lib_search_path_spec="$LIB"
+      if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
+        # It is most probably a Windows format PATH.
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+      else
+        sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+      fi
+      # FIXME: find the short name or the path components, as spaces are
+      # common. (e.g. "Program Files" -> "PROGRA~1")
+      ;;
+    esac
+
+    # DLL is installed to $(libdir)/../bin by postinstall_cmds
+    postinstall_cmds='base_file=`basename \${file}`~
+      dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+      dldir=$destdir/`dirname \$dlpath`~
+      test -d \$dldir || mkdir -p \$dldir~
+      $install_prog $dir/$dlname \$dldir/$dlname'
+    postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+      dlpath=$dir/\$dldll~
+       $RM \$dlpath'
+    shlibpath_overrides_runpath=yes
+    dynamic_linker='Win32 link.exe'
+    ;;
+
+  *)
+    # Assume MSVC wrapper
+    library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+    dynamic_linker='Win32 ld.exe'
+    ;;
+  esac
+  # FIXME: first we should search . and the directory the executable is in
+  shlibpath_var=PATH
+  ;;
+
+darwin* | rhapsody*)
+  dynamic_linker="$host_os dyld"
+  version_type=darwin
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+  soname_spec='${libname}${release}${major}$shared_ext'
+  shlibpath_overrides_runpath=yes
+  shlibpath_var=DYLD_LIBRARY_PATH
+  shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+
+  sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"
+  sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+  ;;
+
+dgux*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+freebsd* | dragonfly*)
+  # DragonFly does not have aout.  When/if they implement a new
+  # versioning mechanism, adjust this.
+  if test -x /usr/bin/objformat; then
+    objformat=`/usr/bin/objformat`
+  else
+    case $host_os in
+    freebsd[23].*) objformat=aout ;;
+    *) objformat=elf ;;
+    esac
+  fi
+  version_type=freebsd-$objformat
+  case $version_type in
+    freebsd-elf*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+      need_version=no
+      need_lib_prefix=no
+      ;;
+    freebsd-*)
+      library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+      need_version=yes
+      ;;
+  esac
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_os in
+  freebsd2.*)
+    shlibpath_overrides_runpath=yes
+    ;;
+  freebsd3.[01]* | freebsdelf3.[01]*)
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+  freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
+    shlibpath_overrides_runpath=no
+    hardcode_into_libs=yes
+    ;;
+  *) # from 4.6 on, and DragonFly
+    shlibpath_overrides_runpath=yes
+    hardcode_into_libs=yes
+    ;;
+  esac
+  ;;
+
+haiku*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  dynamic_linker="$host_os runtime_loader"
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+  hardcode_into_libs=yes
+  ;;
+
+hpux9* | hpux10* | hpux11*)
+  # Give a soname corresponding to the major version so that dld.sl refuses to
+  # link against other versions.
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  case $host_cpu in
+  ia64*)
+    shrext_cmds='.so'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.so"
+    shlibpath_var=LD_LIBRARY_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    if test "X$HPUX_IA64_MODE" = X32; then
+      sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+    else
+      sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+    fi
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  hppa*64*)
+    shrext_cmds='.sl'
+    hardcode_into_libs=yes
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+    shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+    sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+    ;;
+  *)
+    shrext_cmds='.sl'
+    dynamic_linker="$host_os dld.sl"
+    shlibpath_var=SHLIB_PATH
+    shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    ;;
+  esac
+  # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+  postinstall_cmds='chmod 555 $lib'
+  # or fails outright, so override atomically:
+  install_override_mode=555
+  ;;
+
+interix[3-9]*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+irix5* | irix6* | nonstopux*)
+  case $host_os in
+    nonstopux*) version_type=nonstopux ;;
+    *)
+	if test "$lt_cv_prog_gnu_ld" = yes; then
+		version_type=linux # correct to gnu/linux during the next big refactor
+	else
+		version_type=irix
+	fi ;;
+  esac
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+  case $host_os in
+  irix5* | nonstopux*)
+    libsuff= shlibsuff=
+    ;;
+  *)
+    case $LD in # libtool.m4 will add one of these switches to LD
+    *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+      libsuff= shlibsuff= libmagic=32-bit;;
+    *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+      libsuff=32 shlibsuff=N32 libmagic=N32;;
+    *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+      libsuff=64 shlibsuff=64 libmagic=64-bit;;
+    *) libsuff= shlibsuff= libmagic=never-match;;
+    esac
+    ;;
+  esac
+  shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+  shlibpath_overrides_runpath=no
+  sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+  sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+  hardcode_into_libs=yes
+  ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+  dynamic_linker=no
+  ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+
+  # Some binutils ld are patched to set DT_RUNPATH
+  if ${lt_cv_shlibpath_overrides_runpath+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_shlibpath_overrides_runpath=no
+    save_LDFLAGS=$LDFLAGS
+    save_libdir=$libdir
+    eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \
+	 LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\""
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  if  ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
+  lt_cv_shlibpath_overrides_runpath=yes
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+    LDFLAGS=$save_LDFLAGS
+    libdir=$save_libdir
+
+fi
+
+  shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+  # This implies no fast_install, which is unacceptable.
+  # Some rework will be needed to allow for fast_install
+  # before this can be enabled.
+  hardcode_into_libs=yes
+
+  # Append ld.so.conf contents to the search path
+  if test -f /etc/ld.so.conf; then
+    lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[	 ]*hwcap[	 ]/d;s/[:,	]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+    sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+  fi
+
+  # We used to test for /lib/ld.so.1 and disable shared libraries on
+  # powerpc, because MkLinux only supported shared libraries with the
+  # GNU dynamic linker.  Since this was broken with cross compilers,
+  # most powerpc-linux boxes support dynamic linking these days and
+  # people can always --disable-shared, the test was removed, and we
+  # assume the GNU/Linux dynamic linker is in use.
+  dynamic_linker='GNU/Linux ld.so'
+  ;;
+
+netbsdelf*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='NetBSD ld.elf_so'
+  ;;
+
+netbsd*)
+  version_type=sunos
+  need_lib_prefix=no
+  need_version=no
+  if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+    finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+    dynamic_linker='NetBSD (a.out) ld.so'
+  else
+    library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+    soname_spec='${libname}${release}${shared_ext}$major'
+    dynamic_linker='NetBSD ld.elf_so'
+  fi
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  ;;
+
+newsos6)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  ;;
+
+*nto* | *qnx*)
+  version_type=qnx
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='ldqnx.so'
+  ;;
+
+openbsd*)
+  version_type=sunos
+  sys_lib_dlsearch_path_spec="/usr/lib"
+  need_lib_prefix=no
+  # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+  case $host_os in
+    openbsd3.3 | openbsd3.3.*)	need_version=yes ;;
+    *)				need_version=no  ;;
+  esac
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+    case $host_os in
+      openbsd2.[89] | openbsd2.[89].*)
+	shlibpath_overrides_runpath=no
+	;;
+      *)
+	shlibpath_overrides_runpath=yes
+	;;
+      esac
+  else
+    shlibpath_overrides_runpath=yes
+  fi
+  ;;
+
+os2*)
+  libname_spec='$name'
+  shrext_cmds=".dll"
+  need_lib_prefix=no
+  library_names_spec='$libname${shared_ext} $libname.a'
+  dynamic_linker='OS/2 ld.exe'
+  shlibpath_var=LIBPATH
+  ;;
+
+osf3* | osf4* | osf5*)
+  version_type=osf
+  need_lib_prefix=no
+  need_version=no
+  soname_spec='${libname}${release}${shared_ext}$major'
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+  sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+  ;;
+
+rdos*)
+  dynamic_linker=no
+  ;;
+
+solaris*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  # ldd complains unless libraries are executable
+  postinstall_cmds='chmod +x $lib'
+  ;;
+
+sunos4*)
+  version_type=sunos
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+  finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  if test "$with_gnu_ld" = yes; then
+    need_lib_prefix=no
+  fi
+  need_version=yes
+  ;;
+
+sysv4 | sysv4.3*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  case $host_vendor in
+    sni)
+      shlibpath_overrides_runpath=no
+      need_lib_prefix=no
+      runpath_var=LD_RUN_PATH
+      ;;
+    siemens)
+      need_lib_prefix=no
+      ;;
+    motorola)
+      need_lib_prefix=no
+      need_version=no
+      shlibpath_overrides_runpath=no
+      sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+      ;;
+  esac
+  ;;
+
+sysv4*MP*)
+  if test -d /usr/nec ;then
+    version_type=linux # correct to gnu/linux during the next big refactor
+    library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+    soname_spec='$libname${shared_ext}.$major'
+    shlibpath_var=LD_LIBRARY_PATH
+  fi
+  ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+  version_type=freebsd-elf
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=yes
+  hardcode_into_libs=yes
+  if test "$with_gnu_ld" = yes; then
+    sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+  else
+    sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+    case $host_os in
+      sco3.2v5*)
+        sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+	;;
+    esac
+  fi
+  sys_lib_dlsearch_path_spec='/usr/lib'
+  ;;
+
+tpf*)
+  # TPF is a cross-target only.  Preferred cross-host = GNU/Linux.
+  version_type=linux # correct to gnu/linux during the next big refactor
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  ;;
+
+uts4*)
+  version_type=linux # correct to gnu/linux during the next big refactor
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  ;;
+
+*)
+  dynamic_linker=no
+  ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
+$as_echo "$dynamic_linker" >&6; }
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+  variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+  sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+  sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
+$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
+hardcode_action=
+if test -n "$hardcode_libdir_flag_spec" ||
+   test -n "$runpath_var" ||
+   test "X$hardcode_automatic" = "Xyes" ; then
+
+  # We can hardcode non-existent directories.
+  if test "$hardcode_direct" != no &&
+     # If the only mechanism to avoid hardcoding is shlibpath_var, we
+     # have to relink, otherwise we might link with an installed library
+     # when we should be linking with a yet-to-be-installed one
+     ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no &&
+     test "$hardcode_minus_L" != no; then
+    # Linking always hardcodes the temporary library directory.
+    hardcode_action=relink
+  else
+    # We can link without hardcoding, and we can hardcode nonexisting dirs.
+    hardcode_action=immediate
+  fi
+else
+  # We cannot hardcode anything, or else we can only hardcode existing
+  # directories.
+  hardcode_action=unsupported
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5
+$as_echo "$hardcode_action" >&6; }
+
+if test "$hardcode_action" = relink ||
+   test "$inherit_rpath" = yes; then
+  # Fast installation is not supported
+  enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+     test "$enable_shared" = no; then
+  # Fast installation is not necessary
+  enable_fast_install=needless
+fi
+
+
+
+
+
+
+  if test "x$enable_dlopen" != xyes; then
+  enable_dlopen=unknown
+  enable_dlopen_self=unknown
+  enable_dlopen_self_static=unknown
+else
+  lt_cv_dlopen=no
+  lt_cv_dlopen_libs=
+
+  case $host_os in
+  beos*)
+    lt_cv_dlopen="load_add_on"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+    ;;
+
+  mingw* | pw32* | cegcc*)
+    lt_cv_dlopen="LoadLibrary"
+    lt_cv_dlopen_libs=
+    ;;
+
+  cygwin*)
+    lt_cv_dlopen="dlopen"
+    lt_cv_dlopen_libs=
+    ;;
+
+  darwin*)
+  # if libdl is installed we need to link against it
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dl_dlopen=yes
+else
+  ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+
+    lt_cv_dlopen="dyld"
+    lt_cv_dlopen_libs=
+    lt_cv_dlopen_self=yes
+
+fi
+
+    ;;
+
+  *)
+    ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load"
+if test "x$ac_cv_func_shl_load" = xyes; then :
+  lt_cv_dlopen="shl_load"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
+$as_echo_n "checking for shl_load in -ldld... " >&6; }
+if ${ac_cv_lib_dld_shl_load+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shl_load ();
+int
+main ()
+{
+return shl_load ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dld_shl_load=yes
+else
+  ac_cv_lib_dld_shl_load=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
+$as_echo "$ac_cv_lib_dld_shl_load" >&6; }
+if test "x$ac_cv_lib_dld_shl_load" = xyes; then :
+  lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"
+else
+  ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
+if test "x$ac_cv_func_dlopen" = xyes; then :
+  lt_cv_dlopen="dlopen"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dl_dlopen=yes
+else
+  ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5
+$as_echo_n "checking for dlopen in -lsvld... " >&6; }
+if ${ac_cv_lib_svld_dlopen+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsvld  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_svld_dlopen=yes
+else
+  ac_cv_lib_svld_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5
+$as_echo "$ac_cv_lib_svld_dlopen" >&6; }
+if test "x$ac_cv_lib_svld_dlopen" = xyes; then :
+  lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5
+$as_echo_n "checking for dld_link in -ldld... " >&6; }
+if ${ac_cv_lib_dld_dld_link+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dld_link ();
+int
+main ()
+{
+return dld_link ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_dld_dld_link=yes
+else
+  ac_cv_lib_dld_dld_link=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5
+$as_echo "$ac_cv_lib_dld_dld_link" >&6; }
+if test "x$ac_cv_lib_dld_dld_link" = xyes; then :
+  lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+    ;;
+  esac
+
+  if test "x$lt_cv_dlopen" != xno; then
+    enable_dlopen=yes
+  else
+    enable_dlopen=no
+  fi
+
+  case $lt_cv_dlopen in
+  dlopen)
+    save_CPPFLAGS="$CPPFLAGS"
+    test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+    save_LDFLAGS="$LDFLAGS"
+    wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+    save_LIBS="$LIBS"
+    LIBS="$lt_cv_dlopen_libs $LIBS"
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5
+$as_echo_n "checking whether a program can dlopen itself... " >&6; }
+if ${lt_cv_dlopen_self+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  	  if test "$cross_compiling" = yes; then :
+  lt_cv_dlopen_self=cross
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<_LT_EOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else
+        {
+	  if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
+          else puts (dlerror ());
+	}
+      /* dlclose (self); */
+    }
+  else
+    puts (dlerror ());
+
+  return status;
+}
+_LT_EOF
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) >&5 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
+      x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
+      x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;;
+    esac
+  else :
+    # compilation failed
+    lt_cv_dlopen_self=no
+  fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5
+$as_echo "$lt_cv_dlopen_self" >&6; }
+
+    if test "x$lt_cv_dlopen_self" = xyes; then
+      wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5
+$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; }
+if ${lt_cv_dlopen_self_static+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  	  if test "$cross_compiling" = yes; then :
+  lt_cv_dlopen_self_static=cross
+else
+  lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+  lt_status=$lt_dlunknown
+  cat > conftest.$ac_ext <<_LT_EOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+#  define LT_DLGLOBAL		RTLD_GLOBAL
+#else
+#  ifdef DL_GLOBAL
+#    define LT_DLGLOBAL		DL_GLOBAL
+#  else
+#    define LT_DLGLOBAL		0
+#  endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+   find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+#  ifdef RTLD_LAZY
+#    define LT_DLLAZY_OR_NOW		RTLD_LAZY
+#  else
+#    ifdef DL_LAZY
+#      define LT_DLLAZY_OR_NOW		DL_LAZY
+#    else
+#      ifdef RTLD_NOW
+#        define LT_DLLAZY_OR_NOW	RTLD_NOW
+#      else
+#        ifdef DL_NOW
+#          define LT_DLLAZY_OR_NOW	DL_NOW
+#        else
+#          define LT_DLLAZY_OR_NOW	0
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+   correspondingly for the symbols needed.  */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+  void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+  int status = $lt_dlunknown;
+
+  if (self)
+    {
+      if (dlsym (self,"fnord"))       status = $lt_dlno_uscore;
+      else
+        {
+	  if (dlsym( self,"_fnord"))  status = $lt_dlneed_uscore;
+          else puts (dlerror ());
+	}
+      /* dlclose (self); */
+    }
+  else
+    puts (dlerror ());
+
+  return status;
+}
+_LT_EOF
+  if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+  (eval $ac_link) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+    (./conftest; exit; ) >&5 2>/dev/null
+    lt_status=$?
+    case x$lt_status in
+      x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
+      x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
+      x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;;
+    esac
+  else :
+    # compilation failed
+    lt_cv_dlopen_self_static=no
+  fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5
+$as_echo "$lt_cv_dlopen_self_static" >&6; }
+    fi
+
+    CPPFLAGS="$save_CPPFLAGS"
+    LDFLAGS="$save_LDFLAGS"
+    LIBS="$save_LIBS"
+    ;;
+  esac
+
+  case $lt_cv_dlopen_self in
+  yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+  *) enable_dlopen_self=unknown ;;
+  esac
+
+  case $lt_cv_dlopen_self_static in
+  yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+  *) enable_dlopen_self_static=unknown ;;
+  esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+striplib=
+old_striplib=
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5
+$as_echo_n "checking whether stripping libraries is possible... " >&6; }
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+  case $host_os in
+  darwin*)
+    if test -n "$STRIP" ; then
+      striplib="$STRIP -x"
+      old_striplib="$STRIP -S"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+    else
+      { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+    fi
+    ;;
+  *)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+    ;;
+  esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+  # Report which library types will actually be built
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5
+$as_echo_n "checking if libtool supports shared libraries... " >&6; }
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5
+$as_echo "$can_build_shared" >&6; }
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5
+$as_echo_n "checking whether to build shared libraries... " >&6; }
+  test "$can_build_shared" = "no" && enable_shared=no
+
+  # On AIX, shared libraries and static libraries use the same namespace, and
+  # are all built from PIC.
+  case $host_os in
+  aix3*)
+    test "$enable_shared" = yes && enable_static=no
+    if test -n "$RANLIB"; then
+      archive_cmds="$archive_cmds~\$RANLIB \$lib"
+      postinstall_cmds='$RANLIB $lib'
+    fi
+    ;;
+
+  aix[4-9]*)
+    if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+      test "$enable_shared" = yes && enable_static=no
+    fi
+    ;;
+  esac
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5
+$as_echo "$enable_shared" >&6; }
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5
+$as_echo_n "checking whether to build static libraries... " >&6; }
+  # Make sure either enable_shared or enable_static is yes.
+  test "$enable_shared" = yes || enable_static=yes
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5
+$as_echo "$enable_static" >&6; }
+
+
+
+
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC="$lt_save_CC"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+        ac_config_commands="$ac_config_commands libtool"
+
+
+
+
+# Only expand once:
+
+
+
+# Initialize pkg-config.
+# We require at least 0.22, as "Requires.private" behaviour changed there.
+
+
+
+
+
+
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+	if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
+$as_echo "$PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_PKG_CONFIG"; then
+  ac_pt_PKG_CONFIG=$PKG_CONFIG
+  # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $ac_pt_PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+if test -n "$ac_pt_PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
+$as_echo "$ac_pt_PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_pt_PKG_CONFIG" = x; then
+    PKG_CONFIG=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    PKG_CONFIG=$ac_pt_PKG_CONFIG
+  fi
+else
+  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
+fi
+
+fi
+if test -n "$PKG_CONFIG"; then
+	_pkg_min_version=0.22
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
+$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
+	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+	else
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+		PKG_CONFIG=""
+	fi
+fi
+
+# Library version for libsigrok (NOT the same as the package version).
+# Carefully read the libtool docs before updating these numbers!
+# The algorithm for determining which number to change (and how) is nontrivial!
+# http://www.gnu.org/software/libtool/manual/libtool.html#Updating-version-info
+SR_LIB_VERSION_CURRENT=2
+SR_LIB_VERSION_REVISION=0
+SR_LIB_VERSION_AGE=0
+SR_LIB_VERSION="$SR_LIB_VERSION_CURRENT:$SR_LIB_VERSION_REVISION:$SR_LIB_VERSION_AGE"
+SR_LIB_LDFLAGS="-version-info $SR_LIB_VERSION"
+
+
+
+
+
+
+# Hardware support '--enable' options.
+
+# Check whether --enable-all-drivers was given.
+if test "${enable_all_drivers+set}" = set; then :
+  enableval=$enable_all_drivers; HW_ENABLED_DEFAULT="$enableval"
+else
+  HW_ENABLED_DEFAULT="yes"
+fi
+
+
+# Check whether --enable-agilent-dmm was given.
+if test "${enable_agilent_dmm+set}" = set; then :
+  enableval=$enable_agilent_dmm; HW_AGILENT_DMM="$enableval"
+else
+  HW_AGILENT_DMM=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-appa-55ii was given.
+if test "${enable_appa_55ii+set}" = set; then :
+  enableval=$enable_appa_55ii; HW_APPA_55II="$enableval"
+else
+  HW_APPA_55II=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-asix-sigma was given.
+if test "${enable_asix_sigma+set}" = set; then :
+  enableval=$enable_asix_sigma; HW_ASIX_SIGMA="$enableval"
+else
+  HW_ASIX_SIGMA=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-atten-pps3xxx was given.
+if test "${enable_atten_pps3xxx+set}" = set; then :
+  enableval=$enable_atten_pps3xxx; HW_ATTEN_PPS3XXX="$enableval"
+else
+  HW_ATTEN_PPS3XXX=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-brymen-bm86x was given.
+if test "${enable_brymen_bm86x+set}" = set; then :
+  enableval=$enable_brymen_bm86x; HW_BRYMEN_BM86X="$enableval"
+else
+  HW_BRYMEN_BM86X=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-brymen-dmm was given.
+if test "${enable_brymen_dmm+set}" = set; then :
+  enableval=$enable_brymen_dmm; HW_BRYMEN_DMM="$enableval"
+else
+  HW_BRYMEN_DMM=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-cem-dt-885x was given.
+if test "${enable_cem_dt_885x+set}" = set; then :
+  enableval=$enable_cem_dt_885x; HW_CEM_DT_885X="$enableval"
+else
+  HW_CEM_DT_885X=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-center-3xx was given.
+if test "${enable_center_3xx+set}" = set; then :
+  enableval=$enable_center_3xx; HW_CENTER_3XX="$enableval"
+else
+  HW_CENTER_3XX=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-chronovu-la was given.
+if test "${enable_chronovu_la+set}" = set; then :
+  enableval=$enable_chronovu_la; HW_CHRONOVU_LA="$enableval"
+else
+  HW_CHRONOVU_LA=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-colead-slm was given.
+if test "${enable_colead_slm+set}" = set; then :
+  enableval=$enable_colead_slm; HW_COLEAD_SLM="$enableval"
+else
+  HW_COLEAD_SLM=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-conrad-digi-35-cpu was given.
+if test "${enable_conrad_digi_35_cpu+set}" = set; then :
+  enableval=$enable_conrad_digi_35_cpu; HW_CONRAD_DIGI_35_CPU="$enableval"
+else
+  HW_CONRAD_DIGI_35_CPU=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-demo was given.
+if test "${enable_demo+set}" = set; then :
+  enableval=$enable_demo; HW_DEMO="$enableval"
+else
+  HW_DEMO=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-fluke-dmm was given.
+if test "${enable_fluke_dmm+set}" = set; then :
+  enableval=$enable_fluke_dmm; HW_FLUKE_DMM="$enableval"
+else
+  HW_FLUKE_DMM=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-fx2lafw was given.
+if test "${enable_fx2lafw+set}" = set; then :
+  enableval=$enable_fx2lafw; HW_FX2LAFW="$enableval"
+else
+  HW_FX2LAFW=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-gmc-mh-1x-2x was given.
+if test "${enable_gmc_mh_1x_2x+set}" = set; then :
+  enableval=$enable_gmc_mh_1x_2x; HW_GMC_MH_1X_2X="$enableval"
+else
+  HW_GMC_MH_1X_2X=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-hameg-hmo was given.
+if test "${enable_hameg_hmo+set}" = set; then :
+  enableval=$enable_hameg_hmo; HW_HAMEG_HMO="$enableval"
+else
+  HW_HAMEG_HMO=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-hantek-dso was given.
+if test "${enable_hantek_dso+set}" = set; then :
+  enableval=$enable_hantek_dso; HW_HANTEK_DSO="$enableval"
+else
+  HW_HANTEK_DSO=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-ikalogic-scanalogic2 was given.
+if test "${enable_ikalogic_scanalogic2+set}" = set; then :
+  enableval=$enable_ikalogic_scanalogic2; HW_IKALOGIC_SCANALOGIC2="$enableval"
+else
+  HW_IKALOGIC_SCANALOGIC2=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-ikalogic-scanaplus was given.
+if test "${enable_ikalogic_scanaplus+set}" = set; then :
+  enableval=$enable_ikalogic_scanaplus; HW_IKALOGIC_SCANAPLUS="$enableval"
+else
+  HW_IKALOGIC_SCANAPLUS=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-kecheng-kc-330b was given.
+if test "${enable_kecheng_kc_330b+set}" = set; then :
+  enableval=$enable_kecheng_kc_330b; HW_KECHENG_KC_330B="$enableval"
+else
+  HW_KECHENG_KC_330B=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-lascar-el-usb was given.
+if test "${enable_lascar_el_usb+set}" = set; then :
+  enableval=$enable_lascar_el_usb; HW_LASCAR_EL_USB="$enableval"
+else
+  HW_LASCAR_EL_USB=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-mic-985xx was given.
+if test "${enable_mic_985xx+set}" = set; then :
+  enableval=$enable_mic_985xx; HW_MIC_985XX="$enableval"
+else
+  HW_MIC_985XX=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-norma-dmm was given.
+if test "${enable_norma_dmm+set}" = set; then :
+  enableval=$enable_norma_dmm; HW_NORMA_DMM="$enableval"
+else
+  HW_NORMA_DMM=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-ols was given.
+if test "${enable_ols+set}" = set; then :
+  enableval=$enable_ols; HW_OLS="$enableval"
+else
+  HW_OLS=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-rigol-ds was given.
+if test "${enable_rigol_ds+set}" = set; then :
+  enableval=$enable_rigol_ds; HW_RIGOL_DS="$enableval"
+else
+  HW_RIGOL_DS=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-saleae-logic16 was given.
+if test "${enable_saleae_logic16+set}" = set; then :
+  enableval=$enable_saleae_logic16; HW_SALEAE_LOGIC16="$enableval"
+else
+  HW_SALEAE_LOGIC16=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-serial-dmm was given.
+if test "${enable_serial_dmm+set}" = set; then :
+  enableval=$enable_serial_dmm; HW_SERIAL_DMM="$enableval"
+else
+  HW_SERIAL_DMM=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-sysclk-lwla was given.
+if test "${enable_sysclk_lwla+set}" = set; then :
+  enableval=$enable_sysclk_lwla; HW_SYSCLK_LWLA="$enableval"
+else
+  HW_SYSCLK_LWLA=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-teleinfo was given.
+if test "${enable_teleinfo+set}" = set; then :
+  enableval=$enable_teleinfo; HW_TELEINFO="$enableval"
+else
+  HW_TELEINFO=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-tondaj-sl-814 was given.
+if test "${enable_tondaj_sl_814+set}" = set; then :
+  enableval=$enable_tondaj_sl_814; HW_TONDAJ_SL_814="$enableval"
+else
+  HW_TONDAJ_SL_814=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-uni-t-dmm was given.
+if test "${enable_uni_t_dmm+set}" = set; then :
+  enableval=$enable_uni_t_dmm; HW_UNI_T_DMM="$enableval"
+else
+  HW_UNI_T_DMM=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-uni-t-ut32x was given.
+if test "${enable_uni_t_ut32x+set}" = set; then :
+  enableval=$enable_uni_t_ut32x; HW_UNI_T_UT32X="$enableval"
+else
+  HW_UNI_T_UT32X=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-victor-dmm was given.
+if test "${enable_victor_dmm+set}" = set; then :
+  enableval=$enable_victor_dmm; HW_VICTOR_DMM="$enableval"
+else
+  HW_VICTOR_DMM=$HW_ENABLED_DEFAULT
+fi
+
+
+# Check whether --enable-zeroplus-logic-cube was given.
+if test "${enable_zeroplus_logic_cube+set}" = set; then :
+  enableval=$enable_zeroplus_logic_cube; HW_ZEROPLUS_LOGIC_CUBE="$enableval"
+else
+  HW_ZEROPLUS_LOGIC_CUBE=$HW_ENABLED_DEFAULT
+fi
+
+
+# Checks for libraries.
+
+case "$host" in
+*mingw*)
+	# We need to link against the Winsock2 library for SCPI over TCP.
+	LIBS="$LIBS -lws2_32";;
+esac
+
+# This variable collects the pkg-config names of all detected libs.
+# It is then used to construct the "Requires.private:" field in the
+# libsigrok.pc file.
+SR_PKGLIBS=""
+
+# libm (the standard math library) is always needed.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing pow" >&5
+$as_echo_n "checking for library containing pow... " >&6; }
+if ${ac_cv_search_pow+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pow ();
+int
+main ()
+{
+return pow ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' m; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_search_pow=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext
+  if ${ac_cv_search_pow+:} false; then :
+  break
+fi
+done
+if ${ac_cv_search_pow+:} false; then :
+
+else
+  ac_cv_search_pow=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_pow" >&5
+$as_echo "$ac_cv_search_pow" >&6; }
+ac_res=$ac_cv_search_pow
+if test "$ac_res" != no; then :
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+
+# RPC is only needed for VXI support.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for RPC support" >&5
+$as_echo_n "checking for RPC support... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <rpc/rpc.h>
+int
+main ()
+{
+CLIENT *rpc_test(void)
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; have_rpc=1
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; };  have_rpc=0
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+# Define HAVE_RPC in config.h if we found RPC support.
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_RPC $have_rpc
+_ACEOF
+
+# VXI support is only compiled if RPC support was found.
+ if test "x$have_rpc" != "x0"; then
+  NEED_RPC_TRUE=
+  NEED_RPC_FALSE='#'
+else
+  NEED_RPC_TRUE='#'
+  NEED_RPC_FALSE=
+fi
+
+
+# libglib-2.0 is always needed. Abort if it's not found.
+# Note: glib-2.0 is part of the libsigrok API (hard pkg-config requirement).
+# We require at least 2.32.0 due to e.g. g_variant_new_fixed_array().
+# Check whether --enable-glibtest was given.
+if test "${enable_glibtest+set}" = set; then :
+  enableval=$enable_glibtest;
+else
+  enable_glibtest=yes
+fi
+
+
+  pkg_config_args=glib-2.0
+  for module in .
+  do
+      case "$module" in
+         gmodule)
+             pkg_config_args="$pkg_config_args gmodule-2.0"
+         ;;
+         gmodule-no-export)
+             pkg_config_args="$pkg_config_args gmodule-no-export-2.0"
+         ;;
+         gobject)
+             pkg_config_args="$pkg_config_args gobject-2.0"
+         ;;
+         gthread)
+             pkg_config_args="$pkg_config_args gthread-2.0"
+         ;;
+         gio*)
+             pkg_config_args="$pkg_config_args $module-2.0"
+         ;;
+      esac
+  done
+
+
+
+
+
+
+
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+	if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
+$as_echo "$PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_PKG_CONFIG"; then
+  ac_pt_PKG_CONFIG=$PKG_CONFIG
+  # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $ac_pt_PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+if test -n "$ac_pt_PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
+$as_echo "$ac_pt_PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+  if test "x$ac_pt_PKG_CONFIG" = x; then
+    PKG_CONFIG=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    PKG_CONFIG=$ac_pt_PKG_CONFIG
+  fi
+else
+  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
+fi
+
+fi
+if test -n "$PKG_CONFIG"; then
+	_pkg_min_version=0.16
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
+$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
+	if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+	else
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+		PKG_CONFIG=""
+	fi
+fi
+
+  no_glib=""
+
+  if test "x$PKG_CONFIG" = x ; then
+    no_glib=yes
+    PKG_CONFIG=no
+  fi
+
+  min_glib_version=2.32.0
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GLIB - version >= $min_glib_version" >&5
+$as_echo_n "checking for GLIB - version >= $min_glib_version... " >&6; }
+
+  if test x$PKG_CONFIG != xno ; then
+    ## don't try to run the test against uninstalled libtool libs
+    if $PKG_CONFIG --uninstalled $pkg_config_args; then
+	  echo "Will use uninstalled version of GLib found in PKG_CONFIG_PATH"
+	  enable_glibtest=no
+    fi
+
+    if $PKG_CONFIG --atleast-version $min_glib_version $pkg_config_args; then
+	  :
+    else
+	  no_glib=yes
+    fi
+  fi
+
+  if test x"$no_glib" = x ; then
+    GLIB_GENMARSHAL=`$PKG_CONFIG --variable=glib_genmarshal glib-2.0`
+    GOBJECT_QUERY=`$PKG_CONFIG --variable=gobject_query glib-2.0`
+    GLIB_MKENUMS=`$PKG_CONFIG --variable=glib_mkenums glib-2.0`
+    GLIB_COMPILE_RESOURCES=`$PKG_CONFIG --variable=glib_compile_resources gio-2.0`
+
+    GLIB_CFLAGS=`$PKG_CONFIG --cflags $pkg_config_args`
+    GLIB_LIBS=`$PKG_CONFIG --libs $pkg_config_args`
+    glib_config_major_version=`$PKG_CONFIG --modversion glib-2.0 | \
+           sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\1/'`
+    glib_config_minor_version=`$PKG_CONFIG --modversion glib-2.0 | \
+           sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\2/'`
+    glib_config_micro_version=`$PKG_CONFIG --modversion glib-2.0 | \
+           sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\3/'`
+    if test "x$enable_glibtest" = "xyes" ; then
+      ac_save_CFLAGS="$CFLAGS"
+      ac_save_LIBS="$LIBS"
+      CFLAGS="$CFLAGS $GLIB_CFLAGS"
+      LIBS="$GLIB_LIBS $LIBS"
+      rm -f conf.glibtest
+      if test "$cross_compiling" = yes; then :
+  echo $ac_n "cross compiling; assumed OK... $ac_c"
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include <glib.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main ()
+{
+  unsigned int major, minor, micro;
+
+  fclose (fopen ("conf.glibtest", "w"));
+
+  if (sscanf("$min_glib_version", "%u.%u.%u", &major, &minor, &micro) != 3) {
+     printf("%s, bad version string\n", "$min_glib_version");
+     exit(1);
+   }
+
+  if ((glib_major_version != $glib_config_major_version) ||
+      (glib_minor_version != $glib_config_minor_version) ||
+      (glib_micro_version != $glib_config_micro_version))
+    {
+      printf("\n*** 'pkg-config --modversion glib-2.0' returned %d.%d.%d, but GLIB (%d.%d.%d)\n",
+             $glib_config_major_version, $glib_config_minor_version, $glib_config_micro_version,
+             glib_major_version, glib_minor_version, glib_micro_version);
+      printf ("*** was found! If pkg-config was correct, then it is best\n");
+      printf ("*** to remove the old version of GLib. You may also be able to fix the error\n");
+      printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n");
+      printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n");
+      printf("*** required on your system.\n");
+      printf("*** If pkg-config was wrong, set the environment variable PKG_CONFIG_PATH\n");
+      printf("*** to point to the correct configuration files\n");
+    }
+  else if ((glib_major_version != GLIB_MAJOR_VERSION) ||
+	   (glib_minor_version != GLIB_MINOR_VERSION) ||
+           (glib_micro_version != GLIB_MICRO_VERSION))
+    {
+      printf("*** GLIB header files (version %d.%d.%d) do not match\n",
+	     GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
+      printf("*** library (version %d.%d.%d)\n",
+	     glib_major_version, glib_minor_version, glib_micro_version);
+    }
+  else
+    {
+      if ((glib_major_version > major) ||
+        ((glib_major_version == major) && (glib_minor_version > minor)) ||
+        ((glib_major_version == major) && (glib_minor_version == minor) && (glib_micro_version >= micro)))
+      {
+        return 0;
+       }
+     else
+      {
+        printf("\n*** An old version of GLIB (%u.%u.%u) was found.\n",
+               glib_major_version, glib_minor_version, glib_micro_version);
+        printf("*** You need a version of GLIB newer than %u.%u.%u. The latest version of\n",
+	       major, minor, micro);
+        printf("*** GLIB is always available from ftp://ftp.gtk.org.\n");
+        printf("***\n");
+        printf("*** If you have already installed a sufficiently new version, this error\n");
+        printf("*** probably means that the wrong copy of the pkg-config shell script is\n");
+        printf("*** being found. The easiest way to fix this is to remove the old version\n");
+        printf("*** of GLIB, but you can also set the PKG_CONFIG environment to point to the\n");
+        printf("*** correct copy of pkg-config. (In this case, you will have to\n");
+        printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n");
+        printf("*** so that the correct libraries are found at run-time))\n");
+      }
+    }
+  return 1;
+}
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+  no_glib=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+       CFLAGS="$ac_save_CFLAGS"
+       LIBS="$ac_save_LIBS"
+     fi
+  fi
+  if test "x$no_glib" = x ; then
+     { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (version $glib_config_major_version.$glib_config_minor_version.$glib_config_micro_version)" >&5
+$as_echo "yes (version $glib_config_major_version.$glib_config_minor_version.$glib_config_micro_version)" >&6; }
+     LIB_CFLAGS="$LIB_CFLAGS $GLIB_CFLAGS"; LIBS="$LIBS $GLIB_LIBS"
+  else
+     { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+     if test "$PKG_CONFIG" = "no" ; then
+       echo "*** A new enough version of pkg-config was not found."
+       echo "*** See http://www.freedesktop.org/software/pkgconfig/"
+     else
+       if test -f conf.glibtest ; then
+        :
+       else
+          echo "*** Could not run GLIB test program, checking why..."
+          ac_save_CFLAGS="$CFLAGS"
+          ac_save_LIBS="$LIBS"
+          CFLAGS="$CFLAGS $GLIB_CFLAGS"
+          LIBS="$LIBS $GLIB_LIBS"
+          cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#include <glib.h>
+#include <stdio.h>
+
+int
+main ()
+{
+ return ((glib_major_version) || (glib_minor_version) || (glib_micro_version));
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+   echo "*** The test program compiled, but did not run. This usually means"
+          echo "*** that the run-time linker is not finding GLIB or finding the wrong"
+          echo "*** version of GLIB. If it is not finding GLIB, you'll need to set your"
+          echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+          echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+          echo "*** is required on your system"
+	  echo "***"
+          echo "*** If you have an old version installed, it is best to remove it, although"
+          echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"
+else
+   echo "*** The test program failed to compile or link. See the file config.log for the"
+          echo "*** exact error that occured. This usually means GLIB is incorrectly installed."
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+          CFLAGS="$ac_save_CFLAGS"
+          LIBS="$ac_save_LIBS"
+       fi
+     fi
+     GLIB_CFLAGS=""
+     GLIB_LIBS=""
+     GLIB_GENMARSHAL=""
+     GOBJECT_QUERY=""
+     GLIB_MKENUMS=""
+     GLIB_COMPILE_RESOURCES=""
+     :
+  fi
+
+
+
+
+
+
+  rm -f conf.glibtest
+
+
+# libzip is always needed. Abort if it's not found.
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libzip" >&5
+$as_echo_n "checking for libzip... " >&6; }
+
+if test -n "$libzip_CFLAGS"; then
+    pkg_cv_libzip_CFLAGS="$libzip_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzip >= 0.10\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzip >= 0.10") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_libzip_CFLAGS=`$PKG_CONFIG --cflags "libzip >= 0.10" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$libzip_LIBS"; then
+    pkg_cv_libzip_LIBS="$libzip_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzip >= 0.10\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libzip >= 0.10") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_libzip_LIBS=`$PKG_CONFIG --libs "libzip >= 0.10" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        libzip_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libzip >= 0.10" 2>&1`
+        else
+	        libzip_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libzip >= 0.10" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$libzip_PKG_ERRORS" >&5
+
+	as_fn_error $? "Package requirements (libzip >= 0.10) were not met:
+
+$libzip_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+Alternatively, you may set the environment variables libzip_CFLAGS
+and libzip_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details." "$LINENO" 5
+elif test $pkg_failed = untried; then
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+	{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "The pkg-config script could not be found or is too old.  Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+Alternatively, you may set the environment variables libzip_CFLAGS
+and libzip_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.
+See \`config.log' for more details" "$LINENO" 5; }
+else
+	libzip_CFLAGS=$pkg_cv_libzip_CFLAGS
+	libzip_LIBS=$pkg_cv_libzip_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+	LIB_CFLAGS="$LIB_CFLAGS $libzip_CFLAGS"; LIBS="$LIBS $libzip_LIBS";
+	SR_PKGLIBS="$SR_PKGLIBS libzip"
+fi
+
+# libserialport is only needed for some hardware drivers. Disable the
+# respective drivers if it is not found.
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libserialport" >&5
+$as_echo_n "checking for libserialport... " >&6; }
+
+if test -n "$libserialport_CFLAGS"; then
+    pkg_cv_libserialport_CFLAGS="$libserialport_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libserialport >= 0.1.0\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libserialport >= 0.1.0") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_libserialport_CFLAGS=`$PKG_CONFIG --cflags "libserialport >= 0.1.0" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$libserialport_LIBS"; then
+    pkg_cv_libserialport_LIBS="$libserialport_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libserialport >= 0.1.0\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libserialport >= 0.1.0") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_libserialport_LIBS=`$PKG_CONFIG --libs "libserialport >= 0.1.0" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        libserialport_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libserialport >= 0.1.0" 2>&1`
+        else
+	        libserialport_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libserialport >= 0.1.0" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$libserialport_PKG_ERRORS" >&5
+
+	have_libserialport="no"; HW_AGILENT_DMM="no"; HW_APPA_55II="no";
+	HW_ATTEN_PPS3XXX="no"; HW_BRYMEN_DMM="no"; HW_CEM_DT_885X="no";
+	HW_CENTER_3XX="no"; HW_COLEAD_SLM="no"; HW_CONRAD_DIGI_35_CPU="no";
+	HW_FLUKE_DMM="no"; HW_GMC_MH_1X_2X="no"; HW_HAMEG_HMO="no";
+	HW_MIC_985XX="no"; HW_NORMA_DMM="no"; HW_OLS="no";
+	HW_SERIAL_DMM="no"; HW_TELEINFO="no"; HW_TONDAJ_SL_814="no"
+elif test $pkg_failed = untried; then
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+	have_libserialport="no"; HW_AGILENT_DMM="no"; HW_APPA_55II="no";
+	HW_ATTEN_PPS3XXX="no"; HW_BRYMEN_DMM="no"; HW_CEM_DT_885X="no";
+	HW_CENTER_3XX="no"; HW_COLEAD_SLM="no"; HW_CONRAD_DIGI_35_CPU="no";
+	HW_FLUKE_DMM="no"; HW_GMC_MH_1X_2X="no"; HW_HAMEG_HMO="no";
+	HW_MIC_985XX="no"; HW_NORMA_DMM="no"; HW_OLS="no";
+	HW_SERIAL_DMM="no"; HW_TELEINFO="no"; HW_TONDAJ_SL_814="no"
+else
+	libserialport_CFLAGS=$pkg_cv_libserialport_CFLAGS
+	libserialport_LIBS=$pkg_cv_libserialport_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+	have_libserialport="yes"; LIB_CFLAGS="$LIB_CFLAGS $libserialport_CFLAGS";
+	LIBS="$LIBS $libserialport_LIBS";
+	SR_PKGLIBS="$SR_PKGLIBS libserialport"
+fi
+
+# Define HAVE_LIBSERIALPORT in config.h if we found libserialport.
+if test "x$have_libserialport" != "xno"; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBSERIALPORT 1
+_ACEOF
+
+fi
+
+# Serial port helper code is only compiled in if libserialport was found.
+ if test "x$have_libserialport" != xno; then
+  NEED_SERIAL_TRUE=
+  NEED_SERIAL_FALSE='#'
+else
+  NEED_SERIAL_TRUE='#'
+  NEED_SERIAL_FALSE=
+fi
+
+
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for librevisa" >&5
+$as_echo_n "checking for librevisa... " >&6; }
+
+if test -n "$librevisa_CFLAGS"; then
+    pkg_cv_librevisa_CFLAGS="$librevisa_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"librevisa >= 0.0.20130812\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "librevisa >= 0.0.20130812") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_librevisa_CFLAGS=`$PKG_CONFIG --cflags "librevisa >= 0.0.20130812" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$librevisa_LIBS"; then
+    pkg_cv_librevisa_LIBS="$librevisa_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"librevisa >= 0.0.20130812\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "librevisa >= 0.0.20130812") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_librevisa_LIBS=`$PKG_CONFIG --libs "librevisa >= 0.0.20130812" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        librevisa_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "librevisa >= 0.0.20130812" 2>&1`
+        else
+	        librevisa_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "librevisa >= 0.0.20130812" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$librevisa_PKG_ERRORS" >&5
+
+	have_librevisa="no"
+elif test $pkg_failed = untried; then
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+	have_librevisa="no"
+else
+	librevisa_CFLAGS=$pkg_cv_librevisa_CFLAGS
+	librevisa_LIBS=$pkg_cv_librevisa_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+	have_librevisa="yes"; LIB_CFLAGS="$LIB_CFLAGS $librevisa_CFLAGS";
+	LIBS="$LIBS $librevisa_LIBS";
+	SR_PKGLIBS="$SR_PKGLIBS librevisa"
+fi
+
+# VISA SCPI backend is only compiled in if librevisa was found.
+ if test "x$have_librevisa" != xno; then
+  NEED_VISA_TRUE=
+  NEED_VISA_FALSE='#'
+else
+  NEED_VISA_TRUE='#'
+  NEED_VISA_FALSE=
+fi
+
+
+# Define HAVE_LIBREVISA in config.h if we found librevisa.
+if test "x$have_librevisa" != "xno"; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBREVISA 1
+_ACEOF
+
+fi
+
+# libusb-1.0 is only needed for some hardware drivers. Disable the respective
+# drivers if it is not found.
+case "$host" in
+*freebsd*)
+	# FreeBSD comes with an "integrated" libusb-1.0-style USB API.
+	# This means libusb-1.0 is always available, no need to check for it,
+	# and no need to (potentially) disable any drivers if it's not found.
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBUSB_1_0 1
+_ACEOF
+
+	;;
+*)
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libusb" >&5
+$as_echo_n "checking for libusb... " >&6; }
+
+if test -n "$libusb_CFLAGS"; then
+    pkg_cv_libusb_CFLAGS="$libusb_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libusb-1.0 >= 1.0.16\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libusb-1.0 >= 1.0.16") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_libusb_CFLAGS=`$PKG_CONFIG --cflags "libusb-1.0 >= 1.0.16" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$libusb_LIBS"; then
+    pkg_cv_libusb_LIBS="$libusb_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libusb-1.0 >= 1.0.16\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libusb-1.0 >= 1.0.16") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_libusb_LIBS=`$PKG_CONFIG --libs "libusb-1.0 >= 1.0.16" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        libusb_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libusb-1.0 >= 1.0.16" 2>&1`
+        else
+	        libusb_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libusb-1.0 >= 1.0.16" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$libusb_PKG_ERRORS" >&5
+
+	have_libusb1_0="no"; HW_BRYMEN_BM86X="no"; HW_FX2LAFW="no";
+		HW_HANTEK_DSO="no"; HW_IKALOGIC_SCANALOGIC2="no";
+		HW_KECHENG_KC_330B="no"; HW_LASCAR_EL_USB="no";
+		HW_SYSCLK_LWLA="no"; HW_UNI_T_DMM="no";
+		HW_UNI_T_UT32X="no"; HW_VICTOR_DMM="no";
+		HW_ZEROPLUS_LOGIC_CUBE="no"; HW_SALEAE_LOGIC16="no"
+elif test $pkg_failed = untried; then
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+	have_libusb1_0="no"; HW_BRYMEN_BM86X="no"; HW_FX2LAFW="no";
+		HW_HANTEK_DSO="no"; HW_IKALOGIC_SCANALOGIC2="no";
+		HW_KECHENG_KC_330B="no"; HW_LASCAR_EL_USB="no";
+		HW_SYSCLK_LWLA="no"; HW_UNI_T_DMM="no";
+		HW_UNI_T_UT32X="no"; HW_VICTOR_DMM="no";
+		HW_ZEROPLUS_LOGIC_CUBE="no"; HW_SALEAE_LOGIC16="no"
+else
+	libusb_CFLAGS=$pkg_cv_libusb_CFLAGS
+	libusb_LIBS=$pkg_cv_libusb_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+	have_libusb1_0="yes"; LIB_CFLAGS="$LIB_CFLAGS $libusb_CFLAGS";
+		LIBS="$LIBS $libusb_LIBS";
+		SR_PKGLIBS="$SR_PKGLIBS libusb-1.0"
+fi
+
+	# Define HAVE_LIBUSB_1_0 in config.h if we found libusb-1.0.
+	if test "x$have_libusb1_0" != "xno"; then
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBUSB_1_0 1
+_ACEOF
+
+	fi
+	;;
+esac
+
+# USB + FX2 firmware helper code is only compiled in if libusb-1.0 was found.
+ if test "x$have_libusb1_0" != xno; then
+  NEED_USB_TRUE=
+  NEED_USB_FALSE='#'
+else
+  NEED_USB_TRUE='#'
+  NEED_USB_FALSE=
+fi
+
+
+# libftdi is only needed for some hardware drivers. Disable them if not found.
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libftdi" >&5
+$as_echo_n "checking for libftdi... " >&6; }
+
+if test -n "$libftdi_CFLAGS"; then
+    pkg_cv_libftdi_CFLAGS="$libftdi_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libftdi >= 0.16\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libftdi >= 0.16") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_libftdi_CFLAGS=`$PKG_CONFIG --cflags "libftdi >= 0.16" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$libftdi_LIBS"; then
+    pkg_cv_libftdi_LIBS="$libftdi_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libftdi >= 0.16\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libftdi >= 0.16") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_libftdi_LIBS=`$PKG_CONFIG --libs "libftdi >= 0.16" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        libftdi_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libftdi >= 0.16" 2>&1`
+        else
+	        libftdi_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libftdi >= 0.16" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$libftdi_PKG_ERRORS" >&5
+
+	HW_ASIX_SIGMA="no"; HW_CHRONOVU_LA="no"; HW_IKALOGIC_SCANAPLUS="no"
+elif test $pkg_failed = untried; then
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+	HW_ASIX_SIGMA="no"; HW_CHRONOVU_LA="no"; HW_IKALOGIC_SCANAPLUS="no"
+else
+	libftdi_CFLAGS=$pkg_cv_libftdi_CFLAGS
+	libftdi_LIBS=$pkg_cv_libftdi_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+	LIB_CFLAGS="$LIB_CFLAGS $libftdi_CFLAGS";
+	LIBS="$LIBS $libftdi_LIBS";
+	SR_PKGLIBS="$SR_PKGLIBS libftdi"
+fi
+
+# The Check unit testing framework is optional. Disable if not found.
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for check" >&5
+$as_echo_n "checking for check... " >&6; }
+
+if test -n "$check_CFLAGS"; then
+    pkg_cv_check_CFLAGS="$check_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"check >= 0.9.4\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "check >= 0.9.4") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_check_CFLAGS=`$PKG_CONFIG --cflags "check >= 0.9.4" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$check_LIBS"; then
+    pkg_cv_check_LIBS="$check_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"check >= 0.9.4\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "check >= 0.9.4") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_check_LIBS=`$PKG_CONFIG --libs "check >= 0.9.4" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        check_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "check >= 0.9.4" 2>&1`
+        else
+	        check_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "check >= 0.9.4" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$check_PKG_ERRORS" >&5
+
+	have_check="no"
+elif test $pkg_failed = untried; then
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+	have_check="no"
+else
+	check_CFLAGS=$pkg_cv_check_CFLAGS
+	check_LIBS=$pkg_cv_check_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+	have_check="yes"; LIB_CFLAGS="$LIB_CFLAGS $check_CFLAGS";
+	LIBS="$LIBS $check_LIBS"
+fi
+ if test x"$have_check" = "xyes"; then
+  HAVE_CHECK_TRUE=
+  HAVE_CHECK_FALSE='#'
+else
+  HAVE_CHECK_TRUE='#'
+  HAVE_CHECK_FALSE=
+fi
+
+
+# The OLS driver uses serial port file descriptors directly, and therefore
+# will not currently work on Windows.
+case "$host" in
+*mingw*)
+       HW_OLS="no"
+       ;;
+esac
+
+
+
+CFLAGS="$CFLAGS $LIB_CFLAGS"
+
+# Now set AM_CONDITIONALs and AC_DEFINEs for the enabled/disabled drivers.
+
+ if test x$HW_AGILENT_DMM = xyes; then
+  HW_AGILENT_DMM_TRUE=
+  HW_AGILENT_DMM_FALSE='#'
+else
+  HW_AGILENT_DMM_TRUE='#'
+  HW_AGILENT_DMM_FALSE=
+fi
+
+if test "x$HW_AGILENT_DMM" = "xyes"; then
+
+$as_echo "#define HAVE_HW_AGILENT_DMM 1" >>confdefs.h
+
+fi
+
+ if test x$HW_APPA_55II = xyes; then
+  HW_APPA_55II_TRUE=
+  HW_APPA_55II_FALSE='#'
+else
+  HW_APPA_55II_TRUE='#'
+  HW_APPA_55II_FALSE=
+fi
+
+if test "x$HW_APPA_55II" = "xyes"; then
+
+$as_echo "#define HAVE_HW_APPA_55II 1" >>confdefs.h
+
+fi
+
+ if test x$HW_ASIX_SIGMA = xyes; then
+  HW_ASIX_SIGMA_TRUE=
+  HW_ASIX_SIGMA_FALSE='#'
+else
+  HW_ASIX_SIGMA_TRUE='#'
+  HW_ASIX_SIGMA_FALSE=
+fi
+
+if test "x$HW_ASIX_SIGMA" = "xyes"; then
+
+$as_echo "#define HAVE_HW_ASIX_SIGMA 1" >>confdefs.h
+
+fi
+
+ if test x$HW_ATTEN_PPS3XXX = xyes; then
+  HW_ATTEN_PPS3XXX_TRUE=
+  HW_ATTEN_PPS3XXX_FALSE='#'
+else
+  HW_ATTEN_PPS3XXX_TRUE='#'
+  HW_ATTEN_PPS3XXX_FALSE=
+fi
+
+if test "x$HW_ATTEN_PPS3XXX" = "xyes"; then
+
+$as_echo "#define HAVE_HW_ATTEN_PPS3XXX 1" >>confdefs.h
+
+fi
+
+ if test x$HW_BRYMEN_BM86X = xyes; then
+  HW_BRYMEN_BM86X_TRUE=
+  HW_BRYMEN_BM86X_FALSE='#'
+else
+  HW_BRYMEN_BM86X_TRUE='#'
+  HW_BRYMEN_BM86X_FALSE=
+fi
+
+if test "x$HW_BRYMEN_BM86X" = "xyes"; then
+
+$as_echo "#define HAVE_HW_BRYMEN_BM86X 1" >>confdefs.h
+
+fi
+
+ if test x$HW_BRYMEN_DMM = xyes; then
+  HW_BRYMEN_DMM_TRUE=
+  HW_BRYMEN_DMM_FALSE='#'
+else
+  HW_BRYMEN_DMM_TRUE='#'
+  HW_BRYMEN_DMM_FALSE=
+fi
+
+if test "x$HW_BRYMEN_DMM" = "xyes"; then
+
+$as_echo "#define HAVE_HW_BRYMEN_DMM 1" >>confdefs.h
+
+fi
+
+ if test x$HW_CEM_DT_885X = xyes; then
+  HW_CEM_DT_885X_TRUE=
+  HW_CEM_DT_885X_FALSE='#'
+else
+  HW_CEM_DT_885X_TRUE='#'
+  HW_CEM_DT_885X_FALSE=
+fi
+
+if test "x$HW_CEM_DT_885X" = "xyes"; then
+
+$as_echo "#define HAVE_HW_CEM_DT_885X 1" >>confdefs.h
+
+fi
+
+ if test x$HW_CENTER_3XX = xyes; then
+  HW_CENTER_3XX_TRUE=
+  HW_CENTER_3XX_FALSE='#'
+else
+  HW_CENTER_3XX_TRUE='#'
+  HW_CENTER_3XX_FALSE=
+fi
+
+if test "x$HW_CENTER_3XX" = "xyes"; then
+
+$as_echo "#define HAVE_HW_CENTER_3XX 1" >>confdefs.h
+
+fi
+
+ if test x$HW_CHRONOVU_LA = xyes; then
+  HW_CHRONOVU_LA_TRUE=
+  HW_CHRONOVU_LA_FALSE='#'
+else
+  HW_CHRONOVU_LA_TRUE='#'
+  HW_CHRONOVU_LA_FALSE=
+fi
+
+if test "x$HW_CHRONOVU_LA" = "xyes"; then
+
+$as_echo "#define HAVE_HW_CHRONOVU_LA 1" >>confdefs.h
+
+fi
+
+ if test x$HW_COLEAD_SLM = xyes; then
+  HW_COLEAD_SLM_TRUE=
+  HW_COLEAD_SLM_FALSE='#'
+else
+  HW_COLEAD_SLM_TRUE='#'
+  HW_COLEAD_SLM_FALSE=
+fi
+
+if test "x$HW_COLEAD_SLM" = "xyes"; then
+
+$as_echo "#define HAVE_HW_COLEAD_SLM 1" >>confdefs.h
+
+fi
+
+ if test x$HW_CONRAD_DIGI_35_CPU = xyes; then
+  HW_CONRAD_DIGI_35_CPU_TRUE=
+  HW_CONRAD_DIGI_35_CPU_FALSE='#'
+else
+  HW_CONRAD_DIGI_35_CPU_TRUE='#'
+  HW_CONRAD_DIGI_35_CPU_FALSE=
+fi
+
+if test "x$HW_CONRAD_DIGI_35_CPU" = "xyes"; then
+
+$as_echo "#define HAVE_HW_CONRAD_DIGI_35_CPU 1" >>confdefs.h
+
+fi
+
+ if test x$HW_DEMO = xyes; then
+  HW_DEMO_TRUE=
+  HW_DEMO_FALSE='#'
+else
+  HW_DEMO_TRUE='#'
+  HW_DEMO_FALSE=
+fi
+
+if test "x$HW_DEMO" = "xyes"; then
+
+$as_echo "#define HAVE_HW_DEMO 1" >>confdefs.h
+
+fi
+
+ if test x$HW_FLUKE_DMM = xyes; then
+  HW_FLUKE_DMM_TRUE=
+  HW_FLUKE_DMM_FALSE='#'
+else
+  HW_FLUKE_DMM_TRUE='#'
+  HW_FLUKE_DMM_FALSE=
+fi
+
+if test "x$HW_FLUKE_DMM" = "xyes"; then
+
+$as_echo "#define HAVE_HW_FLUKE_DMM 1" >>confdefs.h
+
+fi
+
+ if test x$HW_FX2LAFW = xyes; then
+  HW_FX2LAFW_TRUE=
+  HW_FX2LAFW_FALSE='#'
+else
+  HW_FX2LAFW_TRUE='#'
+  HW_FX2LAFW_FALSE=
+fi
+
+if test "x$HW_FX2LAFW" = "xyes"; then
+
+$as_echo "#define HAVE_HW_FX2LAFW 1" >>confdefs.h
+
+fi
+
+ if test x$HW_GMC_MH_1X_2X = xyes; then
+  HW_GMC_MH_1X_2X_TRUE=
+  HW_GMC_MH_1X_2X_FALSE='#'
+else
+  HW_GMC_MH_1X_2X_TRUE='#'
+  HW_GMC_MH_1X_2X_FALSE=
+fi
+
+if test "x$HW_GMC_MH_1X_2X" = "xyes"; then
+
+$as_echo "#define HAVE_HW_GMC_MH_1X_2X 1" >>confdefs.h
+
+fi
+
+ if test x$HW_HANTEK_DSO = xyes; then
+  HW_HANTEK_DSO_TRUE=
+  HW_HANTEK_DSO_FALSE='#'
+else
+  HW_HANTEK_DSO_TRUE='#'
+  HW_HANTEK_DSO_FALSE=
+fi
+
+if test "x$HW_HANTEK_DSO" = "xyes"; then
+
+$as_echo "#define HAVE_HW_HANTEK_DSO 1" >>confdefs.h
+
+fi
+
+ if test x$HW_HAMEG_HMO = xyes; then
+  HW_HAMEG_HMO_TRUE=
+  HW_HAMEG_HMO_FALSE='#'
+else
+  HW_HAMEG_HMO_TRUE='#'
+  HW_HAMEG_HMO_FALSE=
+fi
+
+if test "x$HW_HAMEG_HMO" = "xyes"; then
+
+$as_echo "#define HAVE_HW_HAMEG_HMO 1" >>confdefs.h
+
+fi
+
+ if test x$HW_IKALOGIC_SCANALOGIC2 = xyes; then
+  HW_IKALOGIC_SCANALOGIC2_TRUE=
+  HW_IKALOGIC_SCANALOGIC2_FALSE='#'
+else
+  HW_IKALOGIC_SCANALOGIC2_TRUE='#'
+  HW_IKALOGIC_SCANALOGIC2_FALSE=
+fi
+
+if test "x$HW_IKALOGIC_SCANALOGIC2" = "xyes"; then
+
+$as_echo "#define HAVE_HW_IKALOGIC_SCANALOGIC2 1" >>confdefs.h
+
+fi
+
+ if test x$HW_IKALOGIC_SCANAPLUS = xyes; then
+  HW_IKALOGIC_SCANAPLUS_TRUE=
+  HW_IKALOGIC_SCANAPLUS_FALSE='#'
+else
+  HW_IKALOGIC_SCANAPLUS_TRUE='#'
+  HW_IKALOGIC_SCANAPLUS_FALSE=
+fi
+
+if test "x$HW_IKALOGIC_SCANAPLUS" = "xyes"; then
+
+$as_echo "#define HAVE_HW_IKALOGIC_SCANAPLUS 1" >>confdefs.h
+
+fi
+
+ if test x$HW_KECHENG_KC_330B = xyes; then
+  HW_KECHENG_KC_330B_TRUE=
+  HW_KECHENG_KC_330B_FALSE='#'
+else
+  HW_KECHENG_KC_330B_TRUE='#'
+  HW_KECHENG_KC_330B_FALSE=
+fi
+
+if test "x$HW_KECHENG_KC_330B" = "xyes"; then
+
+$as_echo "#define HAVE_HW_KECHENG_KC_330B 1" >>confdefs.h
+
+fi
+
+ if test x$HW_LASCAR_EL_USB = xyes; then
+  HW_LASCAR_EL_USB_TRUE=
+  HW_LASCAR_EL_USB_FALSE='#'
+else
+  HW_LASCAR_EL_USB_TRUE='#'
+  HW_LASCAR_EL_USB_FALSE=
+fi
+
+if test "x$HW_LASCAR_EL_USB" = "xyes"; then
+
+$as_echo "#define HAVE_HW_LASCAR_EL_USB 1" >>confdefs.h
+
+fi
+
+ if test x$HW_MIC_985XX = xyes; then
+  HW_MIC_985XX_TRUE=
+  HW_MIC_985XX_FALSE='#'
+else
+  HW_MIC_985XX_TRUE='#'
+  HW_MIC_985XX_FALSE=
+fi
+
+if test "x$HW_MIC_985XX" = "xyes"; then
+
+$as_echo "#define HAVE_HW_MIC_985XX 1" >>confdefs.h
+
+fi
+
+ if test x$HW_NORMA_DMM = xyes; then
+  HW_NORMA_DMM_TRUE=
+  HW_NORMA_DMM_FALSE='#'
+else
+  HW_NORMA_DMM_TRUE='#'
+  HW_NORMA_DMM_FALSE=
+fi
+
+if test "x$HW_NORMA_DMM" = "xyes"; then
+
+$as_echo "#define HAVE_HW_NORMA_DMM 1" >>confdefs.h
+
+fi
+
+ if test x$HW_OLS = xyes; then
+  HW_OLS_TRUE=
+  HW_OLS_FALSE='#'
+else
+  HW_OLS_TRUE='#'
+  HW_OLS_FALSE=
+fi
+
+if test "x$HW_OLS" = "xyes"; then
+
+$as_echo "#define HAVE_HW_OLS 1" >>confdefs.h
+
+fi
+
+ if test x$HW_RIGOL_DS = xyes; then
+  HW_RIGOL_DS_TRUE=
+  HW_RIGOL_DS_FALSE='#'
+else
+  HW_RIGOL_DS_TRUE='#'
+  HW_RIGOL_DS_FALSE=
+fi
+
+if test "x$HW_RIGOL_DS" = "xyes"; then
+
+$as_echo "#define HAVE_HW_RIGOL_DS 1" >>confdefs.h
+
+fi
+
+ if test x$HW_SALEAE_LOGIC16 = xyes; then
+  HW_SALEAE_LOGIC16_TRUE=
+  HW_SALEAE_LOGIC16_FALSE='#'
+else
+  HW_SALEAE_LOGIC16_TRUE='#'
+  HW_SALEAE_LOGIC16_FALSE=
+fi
+
+if test "x$HW_SALEAE_LOGIC16" = "xyes"; then
+
+$as_echo "#define HAVE_HW_SALEAE_LOGIC16 1" >>confdefs.h
+
+fi
+
+ if test x$HW_SERIAL_DMM = xyes; then
+  HW_SERIAL_DMM_TRUE=
+  HW_SERIAL_DMM_FALSE='#'
+else
+  HW_SERIAL_DMM_TRUE='#'
+  HW_SERIAL_DMM_FALSE=
+fi
+
+if test "x$HW_SERIAL_DMM" = "xyes"; then
+
+$as_echo "#define HAVE_HW_SERIAL_DMM 1" >>confdefs.h
+
+fi
+
+ if test x$HW_SYSCLK_LWLA = xyes; then
+  HW_SYSCLK_LWLA_TRUE=
+  HW_SYSCLK_LWLA_FALSE='#'
+else
+  HW_SYSCLK_LWLA_TRUE='#'
+  HW_SYSCLK_LWLA_FALSE=
+fi
+
+if test "x$HW_SYSCLK_LWLA" = "xyes"; then
+
+$as_echo "#define HAVE_HW_SYSCLK_LWLA 1" >>confdefs.h
+
+fi
+
+ if test x$HW_TELEINFO = xyes; then
+  HW_TELEINFO_TRUE=
+  HW_TELEINFO_FALSE='#'
+else
+  HW_TELEINFO_TRUE='#'
+  HW_TELEINFO_FALSE=
+fi
+
+if test "x$HW_TELEINFO" = "xyes"; then
+
+$as_echo "#define HAVE_HW_TELEINFO 1" >>confdefs.h
+
+fi
+
+ if test x$HW_TONDAJ_SL_814 = xyes; then
+  HW_TONDAJ_SL_814_TRUE=
+  HW_TONDAJ_SL_814_FALSE='#'
+else
+  HW_TONDAJ_SL_814_TRUE='#'
+  HW_TONDAJ_SL_814_FALSE=
+fi
+
+if test "x$HW_TONDAJ_SL_814" = "xyes"; then
+
+$as_echo "#define HAVE_HW_TONDAJ_SL_814 1" >>confdefs.h
+
+fi
+
+ if test x$HW_UNI_T_DMM = xyes; then
+  HW_UNI_T_DMM_TRUE=
+  HW_UNI_T_DMM_FALSE='#'
+else
+  HW_UNI_T_DMM_TRUE='#'
+  HW_UNI_T_DMM_FALSE=
+fi
+
+if test "x$HW_UNI_T_DMM" = "xyes"; then
+
+$as_echo "#define HAVE_HW_UNI_T_DMM 1" >>confdefs.h
+
+fi
+
+ if test x$HW_UNI_T_UT32X = xyes; then
+  HW_UNI_T_UT32X_TRUE=
+  HW_UNI_T_UT32X_FALSE='#'
+else
+  HW_UNI_T_UT32X_TRUE='#'
+  HW_UNI_T_UT32X_FALSE=
+fi
+
+if test "x$HW_UNI_T_UT32X" = "xyes"; then
+
+$as_echo "#define HAVE_HW_UNI_T_UT32X 1" >>confdefs.h
+
+fi
+
+ if test x$HW_VICTOR_DMM = xyes; then
+  HW_VICTOR_DMM_TRUE=
+  HW_VICTOR_DMM_FALSE='#'
+else
+  HW_VICTOR_DMM_TRUE='#'
+  HW_VICTOR_DMM_FALSE=
+fi
+
+if test "x$HW_VICTOR_DMM" = "xyes"; then
+
+$as_echo "#define HAVE_HW_VICTOR_DMM 1" >>confdefs.h
+
+fi
+
+ if test x$HW_ZEROPLUS_LOGIC_CUBE = xyes; then
+  HW_ZEROPLUS_LOGIC_CUBE_TRUE=
+  HW_ZEROPLUS_LOGIC_CUBE_FALSE='#'
+else
+  HW_ZEROPLUS_LOGIC_CUBE_TRUE='#'
+  HW_ZEROPLUS_LOGIC_CUBE_FALSE=
+fi
+
+if test "x$HW_ZEROPLUS_LOGIC_CUBE" = "xyes"; then
+
+$as_echo "#define HAVE_HW_ZEROPLUS_LOGIC_CUBE 1" >>confdefs.h
+
+fi
+
+# Checks for header files.
+# These are already checked: inttypes.h stdint.h stdlib.h string.h unistd.h.
+
+# Checks for typedefs, structures, and compiler characteristics.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
+$as_echo_n "checking whether byte ordering is bigendian... " >&6; }
+if ${ac_cv_c_bigendian+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_c_bigendian=unknown
+    # See if we're dealing with a universal compiler.
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifndef __APPLE_CC__
+	       not a universal capable compiler
+	     #endif
+	     typedef int dummy;
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+	# Check for potential -arch flags.  It is not universal unless
+	# there are at least two -arch flags with different values.
+	ac_arch=
+	ac_prev=
+	for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do
+	 if test -n "$ac_prev"; then
+	   case $ac_word in
+	     i?86 | x86_64 | ppc | ppc64)
+	       if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then
+		 ac_arch=$ac_word
+	       else
+		 ac_cv_c_bigendian=universal
+		 break
+	       fi
+	       ;;
+	   esac
+	   ac_prev=
+	 elif test "x$ac_word" = "x-arch"; then
+	   ac_prev=arch
+	 fi
+       done
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+    if test $ac_cv_c_bigendian = unknown; then
+      # See if sys/param.h defines the BYTE_ORDER macro.
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+	     #include <sys/param.h>
+
+int
+main ()
+{
+#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \
+		     && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \
+		     && LITTLE_ENDIAN)
+	      bogus endian macros
+	     #endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  # It does; now see whether it defined to BIG_ENDIAN or not.
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+		#include <sys/param.h>
+
+int
+main ()
+{
+#if BYTE_ORDER != BIG_ENDIAN
+		 not big endian
+		#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_bigendian=yes
+else
+  ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+    fi
+    if test $ac_cv_c_bigendian = unknown; then
+      # See if <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris).
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <limits.h>
+
+int
+main ()
+{
+#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN)
+	      bogus endian macros
+	     #endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  # It does; now see whether it defined to _BIG_ENDIAN or not.
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <limits.h>
+
+int
+main ()
+{
+#ifndef _BIG_ENDIAN
+		 not big endian
+		#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_bigendian=yes
+else
+  ac_cv_c_bigendian=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+    fi
+    if test $ac_cv_c_bigendian = unknown; then
+      # Compile a test program.
+      if test "$cross_compiling" = yes; then :
+  # Try to guess by grepping values from an object file.
+	 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+short int ascii_mm[] =
+		  { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
+		short int ascii_ii[] =
+		  { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
+		int use_ascii (int i) {
+		  return ascii_mm[i] + ascii_ii[i];
+		}
+		short int ebcdic_ii[] =
+		  { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
+		short int ebcdic_mm[] =
+		  { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
+		int use_ebcdic (int i) {
+		  return ebcdic_mm[i] + ebcdic_ii[i];
+		}
+		extern int foo;
+
+int
+main ()
+{
+return use_ascii (foo) == use_ebcdic (foo);
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then
+	      ac_cv_c_bigendian=yes
+	    fi
+	    if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then
+	      if test "$ac_cv_c_bigendian" = unknown; then
+		ac_cv_c_bigendian=no
+	      else
+		# finding both strings is unlikely to happen, but who knows?
+		ac_cv_c_bigendian=unknown
+	      fi
+	    fi
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$ac_includes_default
+int
+main ()
+{
+
+	     /* Are we little or big endian?  From Harbison&Steele.  */
+	     union
+	     {
+	       long int l;
+	       char c[sizeof (long int)];
+	     } u;
+	     u.l = 1;
+	     return u.c[sizeof (long int) - 1] == 1;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  ac_cv_c_bigendian=no
+else
+  ac_cv_c_bigendian=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+    fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5
+$as_echo "$ac_cv_c_bigendian" >&6; }
+ case $ac_cv_c_bigendian in #(
+   yes)
+     $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h
+;; #(
+   no)
+      ;; #(
+   universal)
+
+$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
+
+     ;; #(
+   *)
+     as_fn_error $? "unknown endianness
+ presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;;
+ esac
+
+
+FIRMWARE_DIR="$datadir/sigrok-firmware"
+
+MAKEFLAGS='--no-print-directory'
+
+AM_LIBTOOLFLAGS='--silent'
+
+
+SR_PACKAGE_VERSION_MAJOR=0
+SR_PACKAGE_VERSION_MINOR=3
+SR_PACKAGE_VERSION_MICRO=0
+SR_PACKAGE_VERSION=0.3.0
+
+
+
+
+
+
+ac_config_files="$ac_config_files Makefile version.h libsigrok.pc"
+
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems.  If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+  for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+    eval ac_val=\$$ac_var
+    case $ac_val in #(
+    *${as_nl}*)
+      case $ac_var in #(
+      *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+      *) { eval $ac_var=; unset $ac_var;} ;;
+      esac ;;
+    esac
+  done
+
+  (set) 2>&1 |
+    case $as_nl`(ac_space=' '; set) 2>&1` in #(
+    *${as_nl}ac_space=\ *)
+      # `set' does not quote correctly, so add quotes: double-quote
+      # substitution turns \\\\ into \\, and sed turns \\ into \.
+      sed -n \
+	"s/'/'\\\\''/g;
+	  s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+      ;; #(
+    *)
+      # `set' quotes correctly as required by POSIX, so do not add quotes.
+      sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+      ;;
+    esac |
+    sort
+) |
+  sed '
+     /^ac_cv_env_/b end
+     t clear
+     :clear
+     s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+     t end
+     s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+     :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+  if test -w "$cache_file"; then
+    if test "x$cache_file" != "x/dev/null"; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+      if test ! -f "$cache_file" || test -h "$cache_file"; then
+	cat confcache >"$cache_file"
+      else
+        case $cache_file in #(
+        */* | ?:*)
+	  mv -f confcache "$cache_file"$$ &&
+	  mv -f "$cache_file"$$ "$cache_file" ;; #(
+        *)
+	  mv -f confcache "$cache_file" ;;
+	esac
+      fi
+    fi
+  else
+    { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+  fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+  # 1. Remove the extension, and $U if already installed.
+  ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+  ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+  # 2. Prepend LIBOBJDIR.  When used with automake>=1.10 LIBOBJDIR
+  #    will be set to the directory where LIBOBJS objects are built.
+  as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5
+$as_echo_n "checking that generated files are newer than configure... " >&6; }
+   if test -n "$am_sleep_pid"; then
+     # Hide warnings about reused PIDs.
+     wait $am_sleep_pid 2>/dev/null
+   fi
+   { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5
+$as_echo "done" >&6; }
+ if test -n "$EXEEXT"; then
+  am__EXEEXT_TRUE=
+  am__EXEEXT_FALSE='#'
+else
+  am__EXEEXT_TRUE='#'
+  am__EXEEXT_FALSE=
+fi
+
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+  as_fn_error $? "conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+  as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+  as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${NEED_RPC_TRUE}" && test -z "${NEED_RPC_FALSE}"; then
+  as_fn_error $? "conditional \"NEED_RPC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${NEED_SERIAL_TRUE}" && test -z "${NEED_SERIAL_FALSE}"; then
+  as_fn_error $? "conditional \"NEED_SERIAL\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${NEED_VISA_TRUE}" && test -z "${NEED_VISA_FALSE}"; then
+  as_fn_error $? "conditional \"NEED_VISA\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${NEED_USB_TRUE}" && test -z "${NEED_USB_FALSE}"; then
+  as_fn_error $? "conditional \"NEED_USB\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HAVE_CHECK_TRUE}" && test -z "${HAVE_CHECK_FALSE}"; then
+  as_fn_error $? "conditional \"HAVE_CHECK\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_AGILENT_DMM_TRUE}" && test -z "${HW_AGILENT_DMM_FALSE}"; then
+  as_fn_error $? "conditional \"HW_AGILENT_DMM\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_APPA_55II_TRUE}" && test -z "${HW_APPA_55II_FALSE}"; then
+  as_fn_error $? "conditional \"HW_APPA_55II\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_ASIX_SIGMA_TRUE}" && test -z "${HW_ASIX_SIGMA_FALSE}"; then
+  as_fn_error $? "conditional \"HW_ASIX_SIGMA\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_ATTEN_PPS3XXX_TRUE}" && test -z "${HW_ATTEN_PPS3XXX_FALSE}"; then
+  as_fn_error $? "conditional \"HW_ATTEN_PPS3XXX\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_BRYMEN_BM86X_TRUE}" && test -z "${HW_BRYMEN_BM86X_FALSE}"; then
+  as_fn_error $? "conditional \"HW_BRYMEN_BM86X\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_BRYMEN_DMM_TRUE}" && test -z "${HW_BRYMEN_DMM_FALSE}"; then
+  as_fn_error $? "conditional \"HW_BRYMEN_DMM\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_CEM_DT_885X_TRUE}" && test -z "${HW_CEM_DT_885X_FALSE}"; then
+  as_fn_error $? "conditional \"HW_CEM_DT_885X\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_CENTER_3XX_TRUE}" && test -z "${HW_CENTER_3XX_FALSE}"; then
+  as_fn_error $? "conditional \"HW_CENTER_3XX\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_CHRONOVU_LA_TRUE}" && test -z "${HW_CHRONOVU_LA_FALSE}"; then
+  as_fn_error $? "conditional \"HW_CHRONOVU_LA\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_COLEAD_SLM_TRUE}" && test -z "${HW_COLEAD_SLM_FALSE}"; then
+  as_fn_error $? "conditional \"HW_COLEAD_SLM\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_CONRAD_DIGI_35_CPU_TRUE}" && test -z "${HW_CONRAD_DIGI_35_CPU_FALSE}"; then
+  as_fn_error $? "conditional \"HW_CONRAD_DIGI_35_CPU\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_DEMO_TRUE}" && test -z "${HW_DEMO_FALSE}"; then
+  as_fn_error $? "conditional \"HW_DEMO\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_FLUKE_DMM_TRUE}" && test -z "${HW_FLUKE_DMM_FALSE}"; then
+  as_fn_error $? "conditional \"HW_FLUKE_DMM\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_FX2LAFW_TRUE}" && test -z "${HW_FX2LAFW_FALSE}"; then
+  as_fn_error $? "conditional \"HW_FX2LAFW\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_GMC_MH_1X_2X_TRUE}" && test -z "${HW_GMC_MH_1X_2X_FALSE}"; then
+  as_fn_error $? "conditional \"HW_GMC_MH_1X_2X\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_HANTEK_DSO_TRUE}" && test -z "${HW_HANTEK_DSO_FALSE}"; then
+  as_fn_error $? "conditional \"HW_HANTEK_DSO\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_HAMEG_HMO_TRUE}" && test -z "${HW_HAMEG_HMO_FALSE}"; then
+  as_fn_error $? "conditional \"HW_HAMEG_HMO\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_IKALOGIC_SCANALOGIC2_TRUE}" && test -z "${HW_IKALOGIC_SCANALOGIC2_FALSE}"; then
+  as_fn_error $? "conditional \"HW_IKALOGIC_SCANALOGIC2\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_IKALOGIC_SCANAPLUS_TRUE}" && test -z "${HW_IKALOGIC_SCANAPLUS_FALSE}"; then
+  as_fn_error $? "conditional \"HW_IKALOGIC_SCANAPLUS\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_KECHENG_KC_330B_TRUE}" && test -z "${HW_KECHENG_KC_330B_FALSE}"; then
+  as_fn_error $? "conditional \"HW_KECHENG_KC_330B\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_LASCAR_EL_USB_TRUE}" && test -z "${HW_LASCAR_EL_USB_FALSE}"; then
+  as_fn_error $? "conditional \"HW_LASCAR_EL_USB\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_MIC_985XX_TRUE}" && test -z "${HW_MIC_985XX_FALSE}"; then
+  as_fn_error $? "conditional \"HW_MIC_985XX\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_NORMA_DMM_TRUE}" && test -z "${HW_NORMA_DMM_FALSE}"; then
+  as_fn_error $? "conditional \"HW_NORMA_DMM\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_OLS_TRUE}" && test -z "${HW_OLS_FALSE}"; then
+  as_fn_error $? "conditional \"HW_OLS\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_RIGOL_DS_TRUE}" && test -z "${HW_RIGOL_DS_FALSE}"; then
+  as_fn_error $? "conditional \"HW_RIGOL_DS\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_SALEAE_LOGIC16_TRUE}" && test -z "${HW_SALEAE_LOGIC16_FALSE}"; then
+  as_fn_error $? "conditional \"HW_SALEAE_LOGIC16\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_SERIAL_DMM_TRUE}" && test -z "${HW_SERIAL_DMM_FALSE}"; then
+  as_fn_error $? "conditional \"HW_SERIAL_DMM\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_SYSCLK_LWLA_TRUE}" && test -z "${HW_SYSCLK_LWLA_FALSE}"; then
+  as_fn_error $? "conditional \"HW_SYSCLK_LWLA\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_TELEINFO_TRUE}" && test -z "${HW_TELEINFO_FALSE}"; then
+  as_fn_error $? "conditional \"HW_TELEINFO\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_TONDAJ_SL_814_TRUE}" && test -z "${HW_TONDAJ_SL_814_FALSE}"; then
+  as_fn_error $? "conditional \"HW_TONDAJ_SL_814\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_UNI_T_DMM_TRUE}" && test -z "${HW_UNI_T_DMM_FALSE}"; then
+  as_fn_error $? "conditional \"HW_UNI_T_DMM\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_UNI_T_UT32X_TRUE}" && test -z "${HW_UNI_T_UT32X_FALSE}"; then
+  as_fn_error $? "conditional \"HW_UNI_T_UT32X\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_VICTOR_DMM_TRUE}" && test -z "${HW_VICTOR_DMM_FALSE}"; then
+  as_fn_error $? "conditional \"HW_VICTOR_DMM\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HW_ZEROPLUS_LOGIC_CUBE_TRUE}" && test -z "${HW_ZEROPLUS_LOGIC_CUBE_FALSE}"; then
+  as_fn_error $? "conditional \"HW_ZEROPLUS_LOGIC_CUBE\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+  emulate sh
+  NULLCMD=:
+  # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+  # is contrary to our usage.  Disable this feature.
+  alias -g '${1+"$@"}'='"$@"'
+  setopt NO_GLOB_SUBST
+else
+  case `(set -o) 2>/dev/null` in #(
+  *posix*) :
+    set -o posix ;; #(
+  *) :
+     ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+    && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='print -r --'
+  as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+  as_echo='printf %s\n'
+  as_echo_n='printf %s'
+else
+  if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+    as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+    as_echo_n='/usr/ucb/echo -n'
+  else
+    as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+    as_echo_n_body='eval
+      arg=$1;
+      case $arg in #(
+      *"$as_nl"*)
+	expr "X$arg" : "X\\(.*\\)$as_nl";
+	arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+      esac;
+      expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+    '
+    export as_echo_n_body
+    as_echo_n='sh -c $as_echo_n_body as_echo'
+  fi
+  export as_echo_body
+  as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  PATH_SEPARATOR=:
+  (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+    (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+      PATH_SEPARATOR=';'
+  }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.  Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+  *[\\/]* ) as_myself=$0 ;;
+  *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+  done
+IFS=$as_save_IFS
+
+     ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+  as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+  $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh).  But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there.  '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+  && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+  as_status=$1; test $as_status -eq 0 && as_status=1
+  if test "$4"; then
+    as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+    $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+  fi
+  $as_echo "$as_me: error: $2" >&2
+  as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+  return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+  set +e
+  as_fn_set_status $1
+  exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+  { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+  eval 'as_fn_append ()
+  {
+    eval $1+=\$2
+  }'
+else
+  as_fn_append ()
+  {
+    eval $1=\$$1\$2
+  }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+  eval 'as_fn_arith ()
+  {
+    as_val=$(( $* ))
+  }'
+else
+  as_fn_arith ()
+  {
+    as_val=`expr "$@" || test $? -eq 1`
+  }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+  as_basename=basename
+else
+  as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+  case `echo 'xy\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  xy)  ECHO_C='\c';;
+  *)   echo `echo ksh88 bug on AIX 6.1` > /dev/null
+       ECHO_T='	';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+  rm -f conf$$.dir/conf$$.file
+else
+  rm -f conf$$.dir
+  mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+  if ln -s conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s='ln -s'
+    # ... but there are two gotchas:
+    # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+    # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+    # In both cases, we have to default to `cp -pR'.
+    ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+      as_ln_s='cp -pR'
+  elif ln conf$$.file conf$$ 2>/dev/null; then
+    as_ln_s=ln
+  else
+    as_ln_s='cp -pR'
+  fi
+else
+  as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || eval $as_mkdir_p || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+      *) as_qdir=$as_dir;;
+      esac
+      as_dirs="'$as_qdir' $as_dirs"
+      as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$as_dir" : 'X\(//\)[^/]' \| \
+	 X"$as_dir" : 'X\(//\)$' \| \
+	 X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      test -d "$as_dir" && break
+    done
+    test -z "$as_dirs" || eval "mkdir $as_dirs"
+  } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+  as_mkdir_p='mkdir -p "$as_dir"'
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+  test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by libsigrok $as_me 0.3.0, which was
+generated by GNU Autoconf 2.69.  Invocation command line was
+
+  CONFIG_FILES    = $CONFIG_FILES
+  CONFIG_HEADERS  = $CONFIG_HEADERS
+  CONFIG_LINKS    = $CONFIG_LINKS
+  CONFIG_COMMANDS = $CONFIG_COMMANDS
+  $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+config_commands="$ac_config_commands"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration.  Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+      --config     print configuration, then exit
+  -q, --quiet, --silent
+                   do not print progress messages
+  -d, --debug      don't remove temporary files
+      --recheck    update $as_me by reconfiguring in the same conditions
+      --file=FILE[:TEMPLATE]
+                   instantiate the configuration file FILE
+      --header=FILE[:TEMPLATE]
+                   instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to <sigrok-devel at lists.sourceforge.net>.
+libsigrok home page: <http://www.sigrok.org>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+libsigrok config.status 0.3.0
+configured by $0, generated by GNU Autoconf 2.69,
+  with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+MKDIR_P='$MKDIR_P'
+AWK='$AWK'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+  case $1 in
+  --*=?*)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+    ac_shift=:
+    ;;
+  --*=)
+    ac_option=`expr "X$1" : 'X\([^=]*\)='`
+    ac_optarg=
+    ac_shift=:
+    ;;
+  *)
+    ac_option=$1
+    ac_optarg=$2
+    ac_shift=shift
+    ;;
+  esac
+
+  case $ac_option in
+  # Handling of the options.
+  -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+    ac_cs_recheck=: ;;
+  --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+    $as_echo "$ac_cs_version"; exit ;;
+  --config | --confi | --conf | --con | --co | --c )
+    $as_echo "$ac_cs_config"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    '') as_fn_error $? "missing file argument" ;;
+    esac
+    as_fn_append CONFIG_FILES " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    case $ac_optarg in
+    *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+    ac_need_defaults=false;;
+  --he | --h)
+    # Conflict between --help and --header
+    as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+  --help | --hel | -h )
+    $as_echo "$ac_cs_usage"; exit ;;
+  -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+  | -silent | --silent | --silen | --sile | --sil | --si | --s)
+    ac_cs_silent=: ;;
+
+  # This is an error.
+  -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+  *) as_fn_append ac_config_targets " $1"
+     ac_need_defaults=false ;;
+
+  esac
+  shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+  exec 6>/dev/null
+  ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+  set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+  shift
+  \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+  CONFIG_SHELL='$SHELL'
+  export CONFIG_SHELL
+  exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+#
+# INIT-COMMANDS
+#
+AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
+
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`'
+macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`'
+enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`'
+enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`'
+pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`'
+enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`'
+SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`'
+ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`'
+PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`'
+host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`'
+host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`'
+host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`'
+build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`'
+build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`'
+build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`'
+SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`'
+Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`'
+GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`'
+EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`'
+FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`'
+LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`'
+NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`'
+LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`'
+max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`'
+ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`'
+exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`'
+lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`'
+lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`'
+lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`'
+lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`'
+lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`'
+reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`'
+reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`'
+OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`'
+deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`'
+file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`'
+file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`'
+want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`'
+DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`'
+sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`'
+AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`'
+AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`'
+archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`'
+STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`'
+RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`'
+old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`'
+lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`'
+CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`'
+CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`'
+compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`'
+GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`'
+nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`'
+lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`'
+objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`'
+MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`'
+need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`'
+MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`'
+DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`'
+NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`'
+LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`'
+OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`'
+OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`'
+libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`'
+shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`'
+extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`'
+export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`'
+whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`'
+compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`'
+old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`'
+archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`'
+module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`'
+allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`'
+no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`'
+hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`'
+hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`'
+hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`'
+hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`'
+inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`'
+link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`'
+always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`'
+export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`'
+exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`'
+include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`'
+prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`'
+postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`'
+file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`'
+variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`'
+need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`'
+need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`'
+version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`'
+runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`'
+libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`'
+library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`'
+soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`'
+install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`'
+postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`'
+finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`'
+hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`'
+sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`'
+sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`'
+enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`'
+old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`'
+striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`'
+
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+  eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in SHELL \
+ECHO \
+PATH_SEPARATOR \
+SED \
+GREP \
+EGREP \
+FGREP \
+LD \
+NM \
+LN_S \
+lt_SP2NL \
+lt_NL2SP \
+reload_flag \
+OBJDUMP \
+deplibs_check_method \
+file_magic_cmd \
+file_magic_glob \
+want_nocaseglob \
+DLLTOOL \
+sharedlib_from_linklib_cmd \
+AR \
+AR_FLAGS \
+archiver_list_spec \
+STRIP \
+RANLIB \
+CC \
+CFLAGS \
+compiler \
+lt_cv_sys_global_symbol_pipe \
+lt_cv_sys_global_symbol_to_cdecl \
+lt_cv_sys_global_symbol_to_c_name_address \
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \
+nm_file_list_spec \
+lt_prog_compiler_no_builtin_flag \
+lt_prog_compiler_pic \
+lt_prog_compiler_wl \
+lt_prog_compiler_static \
+lt_cv_prog_compiler_c_o \
+need_locks \
+MANIFEST_TOOL \
+DSYMUTIL \
+NMEDIT \
+LIPO \
+OTOOL \
+OTOOL64 \
+shrext_cmds \
+export_dynamic_flag_spec \
+whole_archive_flag_spec \
+compiler_needs_object \
+with_gnu_ld \
+allow_undefined_flag \
+no_undefined_flag \
+hardcode_libdir_flag_spec \
+hardcode_libdir_separator \
+exclude_expsyms \
+include_expsyms \
+file_list_spec \
+variables_saved_for_relink \
+libname_spec \
+library_names_spec \
+soname_spec \
+install_override_mode \
+finish_eval \
+old_striplib \
+striplib; do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[\\\\\\\`\\"\\\$]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+# Double-quote double-evaled strings.
+for var in reload_cmds \
+old_postinstall_cmds \
+old_postuninstall_cmds \
+old_archive_cmds \
+extract_expsyms_cmds \
+old_archive_from_new_cmds \
+old_archive_from_expsyms_cmds \
+archive_cmds \
+archive_expsym_cmds \
+module_cmds \
+module_expsym_cmds \
+export_symbols_cmds \
+prelink_cmds \
+postlink_cmds \
+postinstall_cmds \
+postuninstall_cmds \
+finish_cmds \
+sys_lib_search_path_spec \
+sys_lib_dlsearch_path_spec; do
+    case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+    *[\\\\\\\`\\"\\\$]*)
+      eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+      ;;
+    *)
+      eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+      ;;
+    esac
+done
+
+ac_aux_dir='$ac_aux_dir'
+xsi_shell='$xsi_shell'
+lt_shell_append='$lt_shell_append'
+
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+   setopt NO_GLOB_SUBST
+fi
+
+
+    PACKAGE='$PACKAGE'
+    VERSION='$VERSION'
+    TIMESTAMP='$TIMESTAMP'
+    RM='$RM'
+    ofile='$ofile'
+
+
+
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+    "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+    "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
+    "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+    "version.h") CONFIG_FILES="$CONFIG_FILES version.h" ;;
+    "libsigrok.pc") CONFIG_FILES="$CONFIG_FILES libsigrok.pc" ;;
+
+  *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+  esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used.  Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+  test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+  test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+  test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience.  Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+  tmp= ac_tmp=
+  trap 'exit_status=$?
+  : "${ac_tmp:=$tmp}"
+  { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+  trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+  eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+  ac_cs_awk_cr='\\r'
+else
+  ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+  echo "cat >conf$$subs.awk <<_ACEOF" &&
+  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+  echo "_ACEOF"
+} >conf$$subs.sh ||
+  as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  . ./conf$$subs.sh ||
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+  ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+  if test $ac_delim_n = $ac_delim_num; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+  N
+  s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+  for (key in S) S_is_set[key] = 1
+  FS = ""
+
+}
+{
+  line = $ 0
+  nfields = split(line, field, "@")
+  substed = 0
+  len = length(field[1])
+  for (i = 2; i < nfields; i++) {
+    key = field[i]
+    keylen = length(key)
+    if (S_is_set[key]) {
+      value = S[key]
+      line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+      len += length(value) + length(field[++i])
+      substed = 1
+    } else
+      len += 1 + keylen
+  }
+
+  print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+  sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+  cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+  || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+  ac_vpsub='/^[	 ]*VPATH[	 ]*=[	 ]*/{
+h
+s///
+s/^/:/
+s/[	 ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[	 ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[	 ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+  ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+  if test -z "$ac_tt"; then
+    break
+  elif $ac_last_try; then
+    as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any.  Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[	 ]*#[	 ]*define[	 ][	 ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[	 ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  for (key in D) D_is_set[key] = 1
+  FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+  line = \$ 0
+  split(line, arg, " ")
+  if (arg[1] == "#") {
+    defundef = arg[2]
+    mac1 = arg[3]
+  } else {
+    defundef = substr(arg[1], 2)
+    mac1 = arg[2]
+  }
+  split(mac1, mac2, "(") #)
+  macro = mac2[1]
+  prefix = substr(line, 1, index(line, defundef) - 1)
+  if (D_is_set[macro]) {
+    # Preserve the white space surrounding the "#".
+    print prefix "define", macro P[macro] D[macro]
+    next
+  } else {
+    # Replace #undef with comments.  This is necessary, for example,
+    # in the case of _POSIX_SOURCE, which is predefined and required
+    # on some systems where configure will not decide to define it.
+    if (defundef == "undef") {
+      print "/*", prefix defundef, macro, "*/"
+      next
+    }
+  }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+  as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X "  :F $CONFIG_FILES  :H $CONFIG_HEADERS    :C $CONFIG_COMMANDS"
+shift
+for ac_tag
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+  :[FH]-) ac_tag=-:-;;
+  :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+  esac
+  ac_save_IFS=$IFS
+  IFS=:
+  set x $ac_tag
+  IFS=$ac_save_IFS
+  shift
+  ac_file=$1
+  shift
+
+  case $ac_mode in
+  :L) ac_source=$1;;
+  :[FH])
+    ac_file_inputs=
+    for ac_f
+    do
+      case $ac_f in
+      -) ac_f="$ac_tmp/stdin";;
+      *) # Look for the file first in the build tree, then in the source tree
+	 # (if the path is not absolute).  The absolute path cannot be DOS-style,
+	 # because $ac_f cannot contain `:'.
+	 test -f "$ac_f" ||
+	   case $ac_f in
+	   [\\/$]*) false;;
+	   *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+	   esac ||
+	   as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+      esac
+      case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+      as_fn_append ac_file_inputs " '$ac_f'"
+    done
+
+    # Let's still pretend it is `configure' which instantiates (i.e., don't
+    # use $as_me), people would be surprised to read:
+    #    /* config.h.  Generated by config.status.  */
+    configure_input='Generated from '`
+	  $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+	`' by configure.'
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+    fi
+    # Neutralize special characters interpreted by sed in replacement strings.
+    case $configure_input in #(
+    *\&* | *\|* | *\\* )
+       ac_sed_conf_input=`$as_echo "$configure_input" |
+       sed 's/[\\\\&|]/\\\\&/g'`;; #(
+    *) ac_sed_conf_input=$configure_input;;
+    esac
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$ac_tmp/stdin" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+    esac
+    ;;
+  esac
+
+  ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$ac_file" : 'X\(//\)[^/]' \| \
+	 X"$ac_file" : 'X\(//\)$' \| \
+	 X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+  as_dir="$ac_dir"; as_fn_mkdir_p
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+  case $ac_top_builddir_sub in
+  "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+  *)  ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+  esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+  .)  # We are building in place.
+    ac_srcdir=.
+    ac_top_srcdir=$ac_top_builddir_sub
+    ac_abs_top_srcdir=$ac_pwd ;;
+  [\\/]* | ?:[\\/]* )  # Absolute name.
+    ac_srcdir=$srcdir$ac_dir_suffix;
+    ac_top_srcdir=$srcdir
+    ac_abs_top_srcdir=$srcdir ;;
+  *) # Relative name.
+    ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+    ac_top_srcdir=$ac_top_build_prefix$srcdir
+    ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+  case $ac_mode in
+  :F)
+  #
+  # CONFIG_FILE
+  #
+
+  case $INSTALL in
+  [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+  *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+  esac
+  ac_MKDIR_P=$MKDIR_P
+  case $MKDIR_P in
+  [\\/$]* | ?:[\\/]* ) ;;
+  */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
+  esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+  ac_datarootdir_hack='
+  s&@datadir@&$datadir&g
+  s&@docdir@&$docdir&g
+  s&@infodir@&$infodir&g
+  s&@localedir@&$localedir&g
+  s&@mandir@&$mandir&g
+  s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+s&@MKDIR_P@&$ac_MKDIR_P&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+  >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' \
+      "$ac_tmp/out"`; test -z "$ac_out"; } &&
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined" >&2;}
+
+  rm -f "$ac_tmp/stdin"
+  case $ac_file in
+  -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+  *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+  esac \
+  || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+  :H)
+  #
+  # CONFIG_HEADER
+  #
+  if test x"$ac_file" != x-; then
+    {
+      $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+    } >"$ac_tmp/config.h" \
+      || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      rm -f "$ac_file"
+      mv "$ac_tmp/config.h" "$ac_file" \
+	|| as_fn_error $? "could not create $ac_file" "$LINENO" 5
+    fi
+  else
+    $as_echo "/* $configure_input  */" \
+      && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+      || as_fn_error $? "could not create -" "$LINENO" 5
+  fi
+# Compute "$ac_file"'s index in $config_headers.
+_am_arg="$ac_file"
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+  case $_am_header in
+    $_am_arg | $_am_arg:* )
+      break ;;
+    * )
+      _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+  esac
+done
+echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" ||
+$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$_am_arg" : 'X\(//\)[^/]' \| \
+	 X"$_am_arg" : 'X\(//\)$' \| \
+	 X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$_am_arg" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`/stamp-h$_am_stamp_count
+ ;;
+
+  :C)  { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
+$as_echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+  esac
+
+
+  case $ac_file$ac_mode in
+    "depfiles":C) test x"$AMDEP_TRUE" != x"" || {
+  # Older Autoconf quotes --file arguments for eval, but not when files
+  # are listed without --file.  Let's play safe and only enable the eval
+  # if we detect the quoting.
+  case $CONFIG_FILES in
+  *\'*) eval set x "$CONFIG_FILES" ;;
+  *)   set x $CONFIG_FILES ;;
+  esac
+  shift
+  for mf
+  do
+    # Strip MF so we end up with the name of the file.
+    mf=`echo "$mf" | sed -e 's/:.*$//'`
+    # Check whether this is an Automake generated Makefile or not.
+    # We used to match only the files named 'Makefile.in', but
+    # some people rename them; so instead we look at the file content.
+    # Grep'ing the first line is not enough: some people post-process
+    # each Makefile.in and add a new line on top of each file to say so.
+    # Grep'ing the whole file is not good either: AIX grep has a line
+    # limit of 2048, but all sed's we know have understand at least 4000.
+    if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+      dirpart=`$as_dirname -- "$mf" ||
+$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$mf" : 'X\(//\)[^/]' \| \
+	 X"$mf" : 'X\(//\)$' \| \
+	 X"$mf" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$mf" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+    else
+      continue
+    fi
+    # Extract the definition of DEPDIR, am__include, and am__quote
+    # from the Makefile without running 'make'.
+    DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+    test -z "$DEPDIR" && continue
+    am__include=`sed -n 's/^am__include = //p' < "$mf"`
+    test -z "$am__include" && continue
+    am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+    # Find all dependency output files, they are included files with
+    # $(DEPDIR) in their names.  We invoke sed twice because it is the
+    # simplest approach to changing $(DEPDIR) to its actual value in the
+    # expansion.
+    for file in `sed -n "
+      s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+	 sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
+      # Make sure the directory exists.
+      test -f "$dirpart/$file" && continue
+      fdir=`$as_dirname -- "$file" ||
+$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$file" : 'X\(//\)[^/]' \| \
+	 X"$file" : 'X\(//\)$' \| \
+	 X"$file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$file" |
+    sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)[^/].*/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+      as_dir=$dirpart/$fdir; as_fn_mkdir_p
+      # echo "creating $dirpart/$file"
+      echo '# dummy' > "$dirpart/$file"
+    done
+  done
+}
+ ;;
+    "libtool":C)
+
+    # See if we are running on zsh, and set the options which allow our
+    # commands through without removal of \ escapes.
+    if test -n "${ZSH_VERSION+set}" ; then
+      setopt NO_GLOB_SUBST
+    fi
+
+    cfgfile="${ofile}T"
+    trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+    $RM "$cfgfile"
+
+    cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+#   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+#                 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+#                 Foundation, Inc.
+#   Written by Gordon Matzigkeit, 1996
+#
+#   This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING.  If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+# The names of the tagged configurations supported by this script.
+available_tags=""
+
+# ### BEGIN LIBTOOL CONFIG
+
+# Which release of libtool.m4 was used?
+macro_version=$macro_version
+macro_revision=$macro_revision
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# What type of objects to build.
+pic_mode=$pic_mode
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# An echo program that protects backslashes.
+ECHO=$lt_ECHO
+
+# The PATH separator for the build system.
+PATH_SEPARATOR=$lt_PATH_SEPARATOR
+
+# The host system.
+host_alias=$host_alias
+host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="\$SED -e 1s/^X//"
+
+# A grep program that handles long lines.
+GREP=$lt_GREP
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# A literal string matcher.
+FGREP=$lt_FGREP
+
+# A BSD- or MS-compatible name lister.
+NM=$lt_NM
+
+# Whether we need soft or hard links.
+LN_S=$lt_LN_S
+
+# What is the maximum length of a command?
+max_cmd_len=$max_cmd_len
+
+# Object file suffix (normally "o").
+objext=$ac_objext
+
+# Executable file suffix (normally "").
+exeext=$exeext
+
+# whether the shell understands "unset".
+lt_unset=$lt_unset
+
+# turn spaces into newlines.
+SP2NL=$lt_lt_SP2NL
+
+# turn newlines into spaces.
+NL2SP=$lt_lt_NL2SP
+
+# convert \$build file names to \$host format.
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+
+# convert \$build files to toolchain format.
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+
+# An object symbol dumper.
+OBJDUMP=$lt_OBJDUMP
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method = "file_magic".
+file_magic_cmd=$lt_file_magic_cmd
+
+# How to find potential files when deplibs_check_method = "file_magic".
+file_magic_glob=$lt_file_magic_glob
+
+# Find potential files using nocaseglob when deplibs_check_method = "file_magic".
+want_nocaseglob=$lt_want_nocaseglob
+
+# DLL creation program.
+DLLTOOL=$lt_DLLTOOL
+
+# Command to associate shared and link libraries.
+sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd
+
+# The archiver.
+AR=$lt_AR
+
+# Flags to create an archive.
+AR_FLAGS=$lt_AR_FLAGS
+
+# How to feed a file listing to the archiver.
+archiver_list_spec=$lt_archiver_list_spec
+
+# A symbol stripping program.
+STRIP=$lt_STRIP
+
+# Commands used to install an old-style archive.
+RANLIB=$lt_RANLIB
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Whether to use a lock for old archive extraction.
+lock_old_archive_extraction=$lock_old_archive_extraction
+
+# A C compiler.
+LTCC=$lt_CC
+
+# LTCC compiler flags.
+LTCFLAGS=$lt_CFLAGS
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration.
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair.
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# Transform the output of nm in a C name address pair when lib prefix is needed.
+global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix
+
+# Specify filename containing input files for \$NM.
+nm_file_list_spec=$lt_nm_file_list_spec
+
+# The root where to search for dependent libraries,and in which our libraries should be installed.
+lt_sysroot=$lt_sysroot
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# Used to examine libraries when file_magic_cmd begins with "file".
+MAGIC_CMD=$MAGIC_CMD
+
+# Must we lock files when doing compilation?
+need_locks=$lt_need_locks
+
+# Manifest tool.
+MANIFEST_TOOL=$lt_MANIFEST_TOOL
+
+# Tool to manipulate archived DWARF debug symbol files on Mac OS X.
+DSYMUTIL=$lt_DSYMUTIL
+
+# Tool to change global to local symbols on Mac OS X.
+NMEDIT=$lt_NMEDIT
+
+# Tool to manipulate fat objects and archives on Mac OS X.
+LIPO=$lt_LIPO
+
+# ldd/readelf like tool for Mach-O binaries on Mac OS X.
+OTOOL=$lt_OTOOL
+
+# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4.
+OTOOL64=$lt_OTOOL64
+
+# Old archive suffix (normally "a").
+libext=$libext
+
+# Shared library suffix (normally ".so").
+shrext_cmds=$lt_shrext_cmds
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at link time.
+variables_saved_for_relink=$lt_variables_saved_for_relink
+
+# Do we need the "lib" prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Library versioning type.
+version_type=$version_type
+
+# Shared library runtime path variable.
+runpath_var=$runpath_var
+
+# Shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names.  First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Permission mode override for installation of shared libraries.
+install_override_mode=$lt_install_override_mode
+
+# Command to use after installation of a shared archive.
+postinstall_cmds=$lt_postinstall_cmds
+
+# Command to use after uninstallation of a shared archive.
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# As "finish_cmds", except a single script fragment to be evaled but
+# not shown.
+finish_eval=$lt_finish_eval
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Compile-time system search path for libraries.
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries.
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+
+# The linker used to build libraries.
+LD=$lt_LD
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds
+
+# A language specific compiler.
+CC=$lt_compiler
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds
+archive_expsym_cmds=$lt_archive_expsym_cmds
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds
+module_expsym_cmds=$lt_module_expsym_cmds
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds
+
+# Commands necessary for finishing linking programs.
+postlink_cmds=$lt_postlink_cmds
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action
+
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+  case $host_os in
+  aix3*)
+    cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program.  For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+  COLLECT_NAMES=
+  export COLLECT_NAMES
+fi
+_LT_EOF
+    ;;
+  esac
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+
+  # We use sed instead of cat because bash on DJGPP gets confused if
+  # if finds mixed CR/LF and LF-only lines.  Since sed operates in
+  # text mode, it properly converts lines to CR/LF.  This bash problem
+  # is reportedly fixed, but why not run on old versions too?
+  sed '$q' "$ltmain" >> "$cfgfile" \
+     || (rm -f "$cfgfile"; exit 1)
+
+  if test x"$xsi_shell" = xyes; then
+  sed -e '/^func_dirname ()$/,/^} # func_dirname /c\
+func_dirname ()\
+{\
+\    case ${1} in\
+\      */*) func_dirname_result="${1%/*}${2}" ;;\
+\      *  ) func_dirname_result="${3}" ;;\
+\    esac\
+} # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_basename ()$/,/^} # func_basename /c\
+func_basename ()\
+{\
+\    func_basename_result="${1##*/}"\
+} # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\
+func_dirname_and_basename ()\
+{\
+\    case ${1} in\
+\      */*) func_dirname_result="${1%/*}${2}" ;;\
+\      *  ) func_dirname_result="${3}" ;;\
+\    esac\
+\    func_basename_result="${1##*/}"\
+} # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_stripname ()$/,/^} # func_stripname /c\
+func_stripname ()\
+{\
+\    # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\
+\    # positional parameters, so assign one to ordinary parameter first.\
+\    func_stripname_result=${3}\
+\    func_stripname_result=${func_stripname_result#"${1}"}\
+\    func_stripname_result=${func_stripname_result%"${2}"}\
+} # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\
+func_split_long_opt ()\
+{\
+\    func_split_long_opt_name=${1%%=*}\
+\    func_split_long_opt_arg=${1#*=}\
+} # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\
+func_split_short_opt ()\
+{\
+\    func_split_short_opt_arg=${1#??}\
+\    func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\
+} # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\
+func_lo2o ()\
+{\
+\    case ${1} in\
+\      *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\
+\      *)    func_lo2o_result=${1} ;;\
+\    esac\
+} # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_xform ()$/,/^} # func_xform /c\
+func_xform ()\
+{\
+    func_xform_result=${1%.*}.lo\
+} # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_arith ()$/,/^} # func_arith /c\
+func_arith ()\
+{\
+    func_arith_result=$(( $* ))\
+} # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_len ()$/,/^} # func_len /c\
+func_len ()\
+{\
+    func_len_result=${#1}\
+} # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+fi
+
+if test x"$lt_shell_append" = xyes; then
+  sed -e '/^func_append ()$/,/^} # func_append /c\
+func_append ()\
+{\
+    eval "${1}+=\\${2}"\
+} # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\
+func_append_quoted ()\
+{\
+\    func_quote_for_eval "${2}"\
+\    eval "${1}+=\\\\ \\$func_quote_for_eval_result"\
+} # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \
+  && mv -f "$cfgfile.tmp" "$cfgfile" \
+    || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+  # Save a `func_append' function call where possible by direct use of '+='
+  sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \
+    && mv -f "$cfgfile.tmp" "$cfgfile" \
+      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+  test 0 -eq $? || _lt_function_replace_fail=:
+else
+  # Save a `func_append' function call even when '+=' is not available
+  sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \
+    && mv -f "$cfgfile.tmp" "$cfgfile" \
+      || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+  test 0 -eq $? || _lt_function_replace_fail=:
+fi
+
+if test x"$_lt_function_replace_fail" = x":"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5
+$as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;}
+fi
+
+
+   mv -f "$cfgfile" "$ofile" ||
+    (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+  chmod +x "$ofile"
+
+ ;;
+
+  esac
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+  as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded.  So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status.  When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+  ac_cs_success=:
+  ac_config_status_args=
+  test "$silent" = yes &&
+    ac_config_status_args="$ac_config_status_args --quiet"
+  exec 5>/dev/null
+  $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+  exec 5>>config.log
+  # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+  # would make configure fail if this is the last instruction.
+  $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+
+echo
+echo "libsigrok configuration summary:"
+echo
+echo "  - Package version (major.minor.micro):    $SR_PACKAGE_VERSION"
+echo "  - Library version (current:revision:age): $SR_LIB_VERSION"
+echo "  - Prefix: $prefix"
+echo "  - Building on: $build"
+echo "  - Building for: $host"
+echo
+echo "Detected libraries:"
+echo
+
+# Note: This only works for libs with pkg-config integration.
+for lib in "glib-2.0 >= 2.32.0" "libzip >= 0.10" "libserialport >= 0.1.0" "librevisa >= 0.0.20130812" "libusb-1.0 >= 1.0.16" "libftdi >= 0.16" "check >= 0.9.4"; do
+	optional="OPTIONAL"
+	if test "x$lib" = "xglib-2.0 >= 2.32.0"; then optional="REQUIRED"; fi
+	if test "x$lib" = "xlibzip >= 0.10"; then optional="REQUIRED"; fi
+	if `$PKG_CONFIG --exists $lib`; then
+		ver=`$PKG_CONFIG --modversion $lib`
+		answer="yes ($ver)"
+	else
+		answer="no"
+	fi
+	echo "  - ($optional) $lib: $answer"
+done
+
+echo -e "\nEnabled hardware drivers:\n"
+echo "  - agilent-dmm..................... $HW_AGILENT_DMM"
+echo "  - appa-55ii....................... $HW_APPA_55II"
+echo "  - asix-sigma...................... $HW_ASIX_SIGMA"
+echo "  - atten-pps3xxx................... $HW_ATTEN_PPS3XXX"
+echo "  - brymen-bm86x.................... $HW_BRYMEN_BM86X"
+echo "  - brymen-dmm...................... $HW_BRYMEN_DMM"
+echo "  - cem-dt-885x..................... $HW_CEM_DT_885X"
+echo "  - center-3xx...................... $HW_CENTER_3XX"
+echo "  - chronovu-la..................... $HW_CHRONOVU_LA"
+echo "  - colead-slm...................... $HW_COLEAD_SLM"
+echo "  - conrad-digi-35-cpu.............. $HW_CONRAD_DIGI_35_CPU"
+echo "  - demo............................ $HW_DEMO"
+echo "  - fluke-dmm....................... $HW_FLUKE_DMM"
+echo "  - fx2lafw......................... $HW_FX2LAFW"
+echo "  - gmc-mh-1x-2x.................... $HW_GMC_MH_1X_2X"
+echo "  - hameg-hmo....................... $HW_HAMEG_HMO"
+echo "  - hantek-dso...................... $HW_HANTEK_DSO"
+echo "  - ikalogic-scanalogic2............ $HW_IKALOGIC_SCANALOGIC2"
+echo "  - ikalogic-scanaplus.............. $HW_IKALOGIC_SCANAPLUS"
+echo "  - kecheng-kc-330b................. $HW_KECHENG_KC_330B"
+echo "  - lascar-el-usb................... $HW_LASCAR_EL_USB"
+echo "  - mic-985xx....................... $HW_MIC_985XX"
+echo "  - norma-dmm....................... $HW_NORMA_DMM"
+echo "  - openbench-logic-sniffer......... $HW_OLS"
+echo "  - rigol-ds........................ $HW_RIGOL_DS"
+echo "  - saleae-logic16.................. $HW_SALEAE_LOGIC16"
+echo "  - serial-dmm...................... $HW_SERIAL_DMM"
+echo "  - sysclk-lwla..................... $HW_SYSCLK_LWLA"
+echo "  - teleinfo........................ $HW_TELEINFO"
+echo "  - tondaj-sl-814................... $HW_TONDAJ_SL_814"
+echo "  - uni-t-dmm....................... $HW_UNI_T_DMM"
+echo "  - uni-t-ut32x..................... $HW_UNI_T_UT32X"
+echo "  - victor-dmm...................... $HW_VICTOR_DMM"
+echo "  - zeroplus-logic-cube............. $HW_ZEROPLUS_LOGIC_CUBE"
+echo
+
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..cb4eeaf
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,651 @@
+##
+## This file is part of the libsigrok project.
+##
+## Copyright (C) 2010-2012 Bert Vermeulen <bert at biot.com>
+## Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me at gmail.com>
+##
+## This program is free software: you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program.  If not, see <http://www.gnu.org/licenses/>.
+##
+
+# We require at least autoconf 2.63 (AC_INIT format changed there).
+AC_PREREQ([2.63])
+
+# libsigrok package version number (NOT the same as shared lib version!).
+m4_define([sr_package_version_major], [0])
+m4_define([sr_package_version_minor], [3])
+m4_define([sr_package_version_micro], [0])
+m4_define([sr_package_version], [sr_package_version_major.sr_package_version_minor.sr_package_version_micro])
+
+AC_INIT([libsigrok], [sr_package_version], [sigrok-devel at lists.sourceforge.net],
+	[libsigrok], [http://www.sigrok.org])
+AC_CONFIG_HEADER([config.h])
+AC_CONFIG_MACRO_DIR([autostuff])
+AC_CONFIG_AUX_DIR([autostuff])
+
+# We require at least automake 1.11 (needed for 'silent rules').
+AM_INIT_AUTOMAKE([1.11 -Wall -Werror subdir-objects check-news color-tests])
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
+
+AH_TOP([#ifndef SR_CONFIG_H
+#define SR_CONFIG_H    /* To stop multiple inclusions. */])
+AH_BOTTOM([#endif /* SR_CONFIG_H */])
+
+# Enable more compiler warnings via -Wall and -Wextra. Add -fvisibility=hidden
+# and enforce use of SR_API to explicitly mark all public API functions.
+COMMON_FLAGS="$CFLAGS -Wall -Wextra -fvisibility=hidden"
+CFLAGS="$COMMON_FLAGS -Wmissing-prototypes"
+
+# Checks for programs.
+AC_PROG_CC
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_LN_S
+
+# Required for per-target flags or subdir-objects with C sources.
+AM_PROG_CC_C_O
+
+# Initialize libtool.
+LT_INIT
+
+# Initialize pkg-config.
+# We require at least 0.22, as "Requires.private" behaviour changed there.
+PKG_PROG_PKG_CONFIG([0.22])
+
+# Library version for libsigrok (NOT the same as the package version).
+# Carefully read the libtool docs before updating these numbers!
+# The algorithm for determining which number to change (and how) is nontrivial!
+# http://www.gnu.org/software/libtool/manual/libtool.html#Updating-version-info
+SR_LIB_VERSION_CURRENT=2
+SR_LIB_VERSION_REVISION=0
+SR_LIB_VERSION_AGE=0
+SR_LIB_VERSION="$SR_LIB_VERSION_CURRENT:$SR_LIB_VERSION_REVISION:$SR_LIB_VERSION_AGE"
+SR_LIB_LDFLAGS="-version-info $SR_LIB_VERSION"
+AC_SUBST(SR_LIB_VERSION_CURRENT)
+AC_SUBST(SR_LIB_VERSION_REVISION)
+AC_SUBST(SR_LIB_VERSION_AGE)
+AC_SUBST(SR_LIB_VERSION)
+AC_SUBST(SR_LIB_LDFLAGS)
+
+# Hardware support '--enable' options.
+
+AC_ARG_ENABLE(all-drivers, AC_HELP_STRING([--enable-all-drivers],
+	[enable all drivers by default [default=yes]]),
+	[HW_ENABLED_DEFAULT="$enableval"],
+	[HW_ENABLED_DEFAULT="yes"])
+
+AC_ARG_ENABLE(agilent-dmm, AC_HELP_STRING([--enable-agilent-dmm],
+	[enable Agilent DMM support [default=yes]]),
+	[HW_AGILENT_DMM="$enableval"],
+	[HW_AGILENT_DMM=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(appa-55ii, AC_HELP_STRING([--enable-appa-55ii],
+	[enable APPA 55II support [default=yes]]),
+	[HW_APPA_55II="$enableval"],
+	[HW_APPA_55II=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(asix-sigma, AC_HELP_STRING([--enable-asix-sigma],
+	[enable ASIX SIGMA/SIGMA2 support [default=yes]]),
+	[HW_ASIX_SIGMA="$enableval"],
+	[HW_ASIX_SIGMA=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(atten-pps3xxx, AC_HELP_STRING([--enable-atten-pps3xxx],
+	[enable Atten PPS3xxx support [default=yes]]),
+	[HW_ATTEN_PPS3XXX="$enableval"],
+	[HW_ATTEN_PPS3XXX=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(brymen-bm86x, AC_HELP_STRING([--enable-brymen-bm86x],
+	[enable Brymen BM86X support [default=yes]]),
+	[HW_BRYMEN_BM86X="$enableval"],
+	[HW_BRYMEN_BM86X=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(brymen-dmm, AC_HELP_STRING([--enable-brymen-dmm],
+	[enable Brymen DMM support [default=yes]]),
+	[HW_BRYMEN_DMM="$enableval"],
+	[HW_BRYMEN_DMM=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(cem-dt-885x, AC_HELP_STRING([--enable-cem-dt-885x],
+	[enable CEM DT-885x support [default=yes]]),
+	[HW_CEM_DT_885X="$enableval"],
+	[HW_CEM_DT_885X=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(center-3xx, AC_HELP_STRING([--enable-center-3xx],
+	[enable Center 3xx support [default=yes]]),
+	[HW_CENTER_3XX="$enableval"],
+	[HW_CENTER_3XX=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(chronovu-la, AC_HELP_STRING([--enable-chronovu-la],
+	[enable ChronoVu LA support [default=yes]]),
+	[HW_CHRONOVU_LA="$enableval"],
+	[HW_CHRONOVU_LA=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(colead-slm, AC_HELP_STRING([--enable-colead-slm],
+	[enable Colead SLM support [default=yes]]),
+	[HW_COLEAD_SLM="$enableval"],
+	[HW_COLEAD_SLM=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(conrad-digi-35-cpu, AC_HELP_STRING([--enable-conrad-digi-35-cpu],
+	[enable Conrad DIGI 35 CPU support [default=yes]]),
+	[HW_CONRAD_DIGI_35_CPU="$enableval"],
+	[HW_CONRAD_DIGI_35_CPU=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(demo, AC_HELP_STRING([--enable-demo],
+	[enable demo driver support [default=yes]]),
+	[HW_DEMO="$enableval"],
+	[HW_DEMO=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(fluke-dmm, AC_HELP_STRING([--enable-fluke-dmm],
+	[enable Fluke DMM support [default=yes]]),
+	[HW_FLUKE_DMM="$enableval"],
+	[HW_FLUKE_DMM=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(fx2lafw, AC_HELP_STRING([--enable-fx2lafw],
+	[enable fx2lafw support (for FX2 LAs). [default=yes]]),
+	[HW_FX2LAFW="$enableval"],
+	[HW_FX2LAFW=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(gmc-mh-1x-2x, AC_HELP_STRING([--enable-gmc-mh-1x-2x],
+	[enable gmc-mh-1x-2x support [default=yes]]),
+	[HW_GMC_MH_1X_2X="$enableval"],
+	[HW_GMC_MH_1X_2X=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(hameg-hmo, AC_HELP_STRING([--enable-hameg-hmo],
+	[enable Hameg HMO support [default=yes]]),
+	[HW_HAMEG_HMO="$enableval"],
+	[HW_HAMEG_HMO=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(hantek-dso, AC_HELP_STRING([--enable-hantek-dso],
+	[enable Hantek DSO support [default=yes]]),
+	[HW_HANTEK_DSO="$enableval"],
+	[HW_HANTEK_DSO=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(ikalogic-scanalogic2, AC_HELP_STRING([--enable-ikalogic-scanalogic2],
+	[enable IKALOGIC Scanalogic-2 support [default=yes]]),
+	[HW_IKALOGIC_SCANALOGIC2="$enableval"],
+	[HW_IKALOGIC_SCANALOGIC2=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(ikalogic-scanaplus, AC_HELP_STRING([--enable-ikalogic-scanaplus],
+	[enable IKALOGIC ScanaPLUS support [default=yes]]),
+	[HW_IKALOGIC_SCANAPLUS="$enableval"],
+	[HW_IKALOGIC_SCANAPLUS=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(kecheng-kc-330b, AC_HELP_STRING([--enable-kecheng-kc-330b],
+	[enable Kecheng KC-330B support [default=yes]]),
+	[HW_KECHENG_KC_330B="$enableval"],
+	[HW_KECHENG_KC_330B=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(lascar-el-usb, AC_HELP_STRING([--enable-lascar-el-usb],
+	[enable Lascar EL-USB support [default=yes]]),
+	[HW_LASCAR_EL_USB="$enableval"],
+	[HW_LASCAR_EL_USB=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(mic-985xx, AC_HELP_STRING([--enable-mic-985xx],
+	[enable MIC 985xx support [default=yes]]),
+	[HW_MIC_985XX="$enableval"],
+	[HW_MIC_985XX=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(norma-dmm, AC_HELP_STRING([--enable-norma-dmm],
+	[enable Norma DMM support [default=yes]]),
+	[HW_NORMA_DMM="$enableval"],
+	[HW_NORMA_DMM=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(ols, AC_HELP_STRING([--enable-ols],
+	[enable OpenBench Logic Sniffer (OLS) support [default=yes]]),
+	[HW_OLS="$enableval"],
+	[HW_OLS=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(rigol-ds, AC_HELP_STRING([--enable-rigol-ds],
+	[enable Rigol DS support [default=yes]]),
+	[HW_RIGOL_DS="$enableval"],
+	[HW_RIGOL_DS=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(saleae-logic16, AC_HELP_STRING([--enable-saleae-logic16],
+	[enable Saleae Logic16 support [default=yes]]),
+	[HW_SALEAE_LOGIC16="$enableval"],
+	[HW_SALEAE_LOGIC16=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(serial-dmm, AC_HELP_STRING([--enable-serial-dmm],
+	[enable serial DMM support [default=yes]]),
+	[HW_SERIAL_DMM="$enableval"],
+	[HW_SERIAL_DMM=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(sysclk-lwla, AC_HELP_STRING([--enable-sysclk-lwla],
+	[enable Sysclk LWLA support [default=yes]]),
+	[HW_SYSCLK_LWLA="$enableval"],
+	[HW_SYSCLK_LWLA=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(teleinfo, AC_HELP_STRING([--enable-teleinfo],
+	[enable Teleinfo support [default=yes]]),
+	[HW_TELEINFO="$enableval"],
+	[HW_TELEINFO=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(tondaj-sl-814, AC_HELP_STRING([--enable-tondaj-sl-814],
+	[enable Tondaj SL-814 support [default=yes]]),
+	[HW_TONDAJ_SL_814="$enableval"],
+	[HW_TONDAJ_SL_814=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(uni-t-dmm, AC_HELP_STRING([--enable-uni-t-dmm],
+	[enable UNI-T DMM support [default=yes]]),
+	[HW_UNI_T_DMM="$enableval"],
+	[HW_UNI_T_DMM=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(uni-t-ut32x, AC_HELP_STRING([--enable-uni-t-ut32x],
+	[enable UNI-T UT32x support [default=yes]]),
+	[HW_UNI_T_UT32X="$enableval"],
+	[HW_UNI_T_UT32X=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(victor-dmm, AC_HELP_STRING([--enable-victor-dmm],
+	[enable victor-dmm support [default=yes]]),
+	[HW_VICTOR_DMM="$enableval"],
+	[HW_VICTOR_DMM=$HW_ENABLED_DEFAULT])
+
+AC_ARG_ENABLE(zeroplus-logic-cube,
+	AC_HELP_STRING([--enable-zeroplus-logic-cube],
+	[enable ZEROPLUS Logic Cube support [default=yes]]),
+	[HW_ZEROPLUS_LOGIC_CUBE="$enableval"],
+	[HW_ZEROPLUS_LOGIC_CUBE=$HW_ENABLED_DEFAULT])
+
+# Checks for libraries.
+
+case "$host" in
+*mingw*)
+	# We need to link against the Winsock2 library for SCPI over TCP.
+	LIBS="$LIBS -lws2_32";;
+esac
+
+# This variable collects the pkg-config names of all detected libs.
+# It is then used to construct the "Requires.private:" field in the
+# libsigrok.pc file.
+SR_PKGLIBS=""
+
+# libm (the standard math library) is always needed.
+AC_SEARCH_LIBS([pow], [m])
+
+# RPC is only needed for VXI support.
+AC_MSG_CHECKING([for RPC support])
+AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <rpc/rpc.h>],
+				[CLIENT *rpc_test(void)],
+				[{ return clnt_create("", 0, 0, ""); }])],
+	       [AC_MSG_RESULT([yes]); have_rpc=1],
+	       [AC_MSG_RESULT([no]);  have_rpc=0])
+# Define HAVE_RPC in config.h if we found RPC support.
+AC_DEFINE_UNQUOTED(HAVE_RPC, [$have_rpc], [Specifies whether we have RPC support.])
+# VXI support is only compiled if RPC support was found.
+AM_CONDITIONAL(NEED_RPC, test "x$have_rpc" != "x0")
+
+# libglib-2.0 is always needed. Abort if it's not found.
+# Note: glib-2.0 is part of the libsigrok API (hard pkg-config requirement).
+# We require at least 2.32.0 due to e.g. g_variant_new_fixed_array().
+AM_PATH_GLIB_2_0([2.32.0],
+	[LIB_CFLAGS="$LIB_CFLAGS $GLIB_CFLAGS"; LIBS="$LIBS $GLIB_LIBS"])
+
+# libzip is always needed. Abort if it's not found.
+PKG_CHECK_MODULES([libzip], [libzip >= 0.10],
+	[LIB_CFLAGS="$LIB_CFLAGS $libzip_CFLAGS"; LIBS="$LIBS $libzip_LIBS";
+	SR_PKGLIBS="$SR_PKGLIBS libzip"])
+
+# libserialport is only needed for some hardware drivers. Disable the
+# respective drivers if it is not found.
+PKG_CHECK_MODULES([libserialport], [libserialport >= 0.1.0],
+	[have_libserialport="yes"; LIB_CFLAGS="$LIB_CFLAGS $libserialport_CFLAGS";
+	LIBS="$LIBS $libserialport_LIBS";
+	SR_PKGLIBS="$SR_PKGLIBS libserialport"],
+	[have_libserialport="no"; HW_AGILENT_DMM="no"; HW_APPA_55II="no";
+	HW_ATTEN_PPS3XXX="no"; HW_BRYMEN_DMM="no"; HW_CEM_DT_885X="no";
+	HW_CENTER_3XX="no"; HW_COLEAD_SLM="no"; HW_CONRAD_DIGI_35_CPU="no";
+	HW_FLUKE_DMM="no"; HW_GMC_MH_1X_2X="no"; HW_HAMEG_HMO="no";
+	HW_MIC_985XX="no"; HW_NORMA_DMM="no"; HW_OLS="no";
+	HW_SERIAL_DMM="no"; HW_TELEINFO="no"; HW_TONDAJ_SL_814="no"])
+
+# Define HAVE_LIBSERIALPORT in config.h if we found libserialport.
+if test "x$have_libserialport" != "xno"; then
+	AC_DEFINE_UNQUOTED(HAVE_LIBSERIALPORT, [1],
+		[Specifies whether we have libserialport.])
+fi
+
+# Serial port helper code is only compiled in if libserialport was found.
+AM_CONDITIONAL(NEED_SERIAL, test "x$have_libserialport" != xno)
+
+PKG_CHECK_MODULES([librevisa], [librevisa >= 0.0.20130812],
+	[have_librevisa="yes"; LIB_CFLAGS="$LIB_CFLAGS $librevisa_CFLAGS";
+	LIBS="$LIBS $librevisa_LIBS";
+	SR_PKGLIBS="$SR_PKGLIBS librevisa"],
+	[have_librevisa="no"])
+
+# VISA SCPI backend is only compiled in if librevisa was found.
+AM_CONDITIONAL(NEED_VISA, test "x$have_librevisa" != xno)
+
+# Define HAVE_LIBREVISA in config.h if we found librevisa.
+if test "x$have_librevisa" != "xno"; then
+	AC_DEFINE_UNQUOTED(HAVE_LIBREVISA, [1],
+		[Specifies whether we have librevisa.])
+fi
+
+# libusb-1.0 is only needed for some hardware drivers. Disable the respective
+# drivers if it is not found.
+case "$host" in
+*freebsd*)
+	# FreeBSD comes with an "integrated" libusb-1.0-style USB API.
+	# This means libusb-1.0 is always available, no need to check for it,
+	# and no need to (potentially) disable any drivers if it's not found.
+	AC_DEFINE_UNQUOTED(HAVE_LIBUSB_1_0, [1],
+		[Specifies whether we have a libusb.h header.])
+	;;
+*)
+	PKG_CHECK_MODULES([libusb], [libusb-1.0 >= 1.0.16],
+		[have_libusb1_0="yes"; LIB_CFLAGS="$LIB_CFLAGS $libusb_CFLAGS";
+		LIBS="$LIBS $libusb_LIBS";
+		SR_PKGLIBS="$SR_PKGLIBS libusb-1.0"],
+		[have_libusb1_0="no"; HW_BRYMEN_BM86X="no"; HW_FX2LAFW="no";
+		HW_HANTEK_DSO="no"; HW_IKALOGIC_SCANALOGIC2="no";
+		HW_KECHENG_KC_330B="no"; HW_LASCAR_EL_USB="no";
+		HW_SYSCLK_LWLA="no"; HW_UNI_T_DMM="no";
+		HW_UNI_T_UT32X="no"; HW_VICTOR_DMM="no";
+		HW_ZEROPLUS_LOGIC_CUBE="no"; HW_SALEAE_LOGIC16="no"])
+
+	# Define HAVE_LIBUSB_1_0 in config.h if we found libusb-1.0.
+	if test "x$have_libusb1_0" != "xno"; then
+		AC_DEFINE_UNQUOTED(HAVE_LIBUSB_1_0, [1],
+			[Specifies whether we have a libusb.h header.])
+	fi
+	;;
+esac
+
+# USB + FX2 firmware helper code is only compiled in if libusb-1.0 was found.
+AM_CONDITIONAL(NEED_USB, test "x$have_libusb1_0" != xno)
+
+# libftdi is only needed for some hardware drivers. Disable them if not found.
+PKG_CHECK_MODULES([libftdi], [libftdi >= 0.16],
+	[LIB_CFLAGS="$LIB_CFLAGS $libftdi_CFLAGS";
+	LIBS="$LIBS $libftdi_LIBS";
+	SR_PKGLIBS="$SR_PKGLIBS libftdi"],
+	[HW_ASIX_SIGMA="no"; HW_CHRONOVU_LA="no"; HW_IKALOGIC_SCANAPLUS="no"])
+
+# The Check unit testing framework is optional. Disable if not found.
+PKG_CHECK_MODULES([check], [check >= 0.9.4],
+	[have_check="yes"; LIB_CFLAGS="$LIB_CFLAGS $check_CFLAGS";
+	LIBS="$LIBS $check_LIBS"], [have_check="no"])
+AM_CONDITIONAL(HAVE_CHECK, test x"$have_check" = "xyes")
+
+# The OLS driver uses serial port file descriptors directly, and therefore
+# will not currently work on Windows.
+case "$host" in
+*mingw*)
+       HW_OLS="no"
+       ;;
+esac
+
+AC_SUBST(SR_PKGLIBS)
+
+CFLAGS="$CFLAGS $LIB_CFLAGS"
+
+# Now set AM_CONDITIONALs and AC_DEFINEs for the enabled/disabled drivers.
+
+AM_CONDITIONAL(HW_AGILENT_DMM, test x$HW_AGILENT_DMM = xyes)
+if test "x$HW_AGILENT_DMM" = "xyes"; then
+	AC_DEFINE(HAVE_HW_AGILENT_DMM, 1, [Agilent DMM support])
+fi
+
+AM_CONDITIONAL(HW_APPA_55II, test x$HW_APPA_55II = xyes)
+if test "x$HW_APPA_55II" = "xyes"; then
+	AC_DEFINE(HAVE_HW_APPA_55II, 1, [APPA 55II support])
+fi
+
+AM_CONDITIONAL(HW_ASIX_SIGMA, test x$HW_ASIX_SIGMA = xyes)
+if test "x$HW_ASIX_SIGMA" = "xyes"; then
+	AC_DEFINE(HAVE_HW_ASIX_SIGMA, 1, [ASIX SIGMA/SIGMA2 support])
+fi
+
+AM_CONDITIONAL(HW_ATTEN_PPS3XXX, test x$HW_ATTEN_PPS3XXX = xyes)
+if test "x$HW_ATTEN_PPS3XXX" = "xyes"; then
+       AC_DEFINE(HAVE_HW_ATTEN_PPS3XXX, 1, [Atten PPS3xxx support])
+fi
+
+AM_CONDITIONAL(HW_BRYMEN_BM86X, test x$HW_BRYMEN_BM86X = xyes)
+if test "x$HW_BRYMEN_BM86X" = "xyes"; then
+	AC_DEFINE(HAVE_HW_BRYMEN_BM86X, 1, [Brymen BM86X support])
+fi
+
+AM_CONDITIONAL(HW_BRYMEN_DMM, test x$HW_BRYMEN_DMM = xyes)
+if test "x$HW_BRYMEN_DMM" = "xyes"; then
+	AC_DEFINE(HAVE_HW_BRYMEN_DMM, 1, [Brymen DMM support])
+fi
+
+AM_CONDITIONAL(HW_CEM_DT_885X, test x$HW_CEM_DT_885X = xyes)
+if test "x$HW_CEM_DT_885X" = "xyes"; then
+	AC_DEFINE(HAVE_HW_CEM_DT_885X, 1, [CEM DT-885x support])
+fi
+
+AM_CONDITIONAL(HW_CENTER_3XX, test x$HW_CENTER_3XX = xyes)
+if test "x$HW_CENTER_3XX" = "xyes"; then
+	AC_DEFINE(HAVE_HW_CENTER_3XX, 1, [Center 3xx support])
+fi
+
+AM_CONDITIONAL(HW_CHRONOVU_LA, test x$HW_CHRONOVU_LA = xyes)
+if test "x$HW_CHRONOVU_LA" = "xyes"; then
+	AC_DEFINE(HAVE_HW_CHRONOVU_LA, 1, [ChronoVu LA support])
+fi
+
+AM_CONDITIONAL(HW_COLEAD_SLM, test x$HW_COLEAD_SLM = xyes)
+if test "x$HW_COLEAD_SLM" = "xyes"; then
+	AC_DEFINE(HAVE_HW_COLEAD_SLM, 1, [Colead SLM support])
+fi
+
+AM_CONDITIONAL(HW_CONRAD_DIGI_35_CPU, test x$HW_CONRAD_DIGI_35_CPU = xyes)
+if test "x$HW_CONRAD_DIGI_35_CPU" = "xyes"; then
+	AC_DEFINE(HAVE_HW_CONRAD_DIGI_35_CPU, 1, [Conrad DIGI 35 CPU support])
+fi
+
+AM_CONDITIONAL(HW_DEMO, test x$HW_DEMO = xyes)
+if test "x$HW_DEMO" = "xyes"; then
+	AC_DEFINE(HAVE_HW_DEMO, 1, [Demo driver support])
+fi
+
+AM_CONDITIONAL(HW_FLUKE_DMM, test x$HW_FLUKE_DMM = xyes)
+if test "x$HW_FLUKE_DMM" = "xyes"; then
+	AC_DEFINE(HAVE_HW_FLUKE_DMM, 1, [Fluke DMM support])
+fi
+
+AM_CONDITIONAL(HW_FX2LAFW, test x$HW_FX2LAFW = xyes)
+if test "x$HW_FX2LAFW" = "xyes"; then
+	AC_DEFINE(HAVE_HW_FX2LAFW, 1, [fx2lafw support])
+fi
+
+AM_CONDITIONAL(HW_GMC_MH_1X_2X, test x$HW_GMC_MH_1X_2X = xyes)
+if test "x$HW_GMC_MH_1X_2X" = "xyes"; then
+	AC_DEFINE(HAVE_HW_GMC_MH_1X_2X, 1, [gmc-mh-1x-2x support])
+fi
+
+AM_CONDITIONAL(HW_HANTEK_DSO, test x$HW_HANTEK_DSO = xyes)
+if test "x$HW_HANTEK_DSO" = "xyes"; then
+	AC_DEFINE(HAVE_HW_HANTEK_DSO, 1, [Hantek DSO support])
+fi
+
+AM_CONDITIONAL(HW_HAMEG_HMO, test x$HW_HAMEG_HMO = xyes)
+if test "x$HW_HAMEG_HMO" = "xyes"; then
+	AC_DEFINE(HAVE_HW_HAMEG_HMO, 1, [Hameg HMO support])
+fi
+
+AM_CONDITIONAL(HW_IKALOGIC_SCANALOGIC2, test x$HW_IKALOGIC_SCANALOGIC2 = xyes)
+if test "x$HW_IKALOGIC_SCANALOGIC2" = "xyes"; then
+	AC_DEFINE(HAVE_HW_IKALOGIC_SCANALOGIC2, 1, [IKALOGIC Scanalogic-2 support])
+fi
+
+AM_CONDITIONAL(HW_IKALOGIC_SCANAPLUS, test x$HW_IKALOGIC_SCANAPLUS = xyes)
+if test "x$HW_IKALOGIC_SCANAPLUS" = "xyes"; then
+	AC_DEFINE(HAVE_HW_IKALOGIC_SCANAPLUS, 1, [IKALOGIC ScanaPLUS support])
+fi
+
+AM_CONDITIONAL(HW_KECHENG_KC_330B, test x$HW_KECHENG_KC_330B = xyes)
+if test "x$HW_KECHENG_KC_330B" = "xyes"; then
+	AC_DEFINE(HAVE_HW_KECHENG_KC_330B, 1, [Kecheng KC-330B support])
+fi
+
+AM_CONDITIONAL(HW_LASCAR_EL_USB, test x$HW_LASCAR_EL_USB = xyes)
+if test "x$HW_LASCAR_EL_USB" = "xyes"; then
+	AC_DEFINE(HAVE_HW_LASCAR_EL_USB, 1, [Lascar EL-USB support])
+fi
+
+AM_CONDITIONAL(HW_MIC_985XX, test x$HW_MIC_985XX = xyes)
+if test "x$HW_MIC_985XX" = "xyes"; then
+	AC_DEFINE(HAVE_HW_MIC_985XX, 1, [MIC 985xx support])
+fi
+
+AM_CONDITIONAL(HW_NORMA_DMM, test x$HW_NORMA_DMM = xyes)
+if test "x$HW_NORMA_DMM" = "xyes"; then
+       AC_DEFINE(HAVE_HW_NORMA_DMM, 1, [Norma DMM support])
+fi
+
+AM_CONDITIONAL(HW_OLS, test x$HW_OLS = xyes)
+if test "x$HW_OLS" = "xyes"; then
+	AC_DEFINE(HAVE_HW_OLS, 1, [OpenBench Logic Sniffer (OLS) support])
+fi
+
+AM_CONDITIONAL(HW_RIGOL_DS, test x$HW_RIGOL_DS = xyes)
+if test "x$HW_RIGOL_DS" = "xyes"; then
+	AC_DEFINE(HAVE_HW_RIGOL_DS, 1, [Rigol DS support])
+fi
+
+AM_CONDITIONAL(HW_SALEAE_LOGIC16, test x$HW_SALEAE_LOGIC16 = xyes)
+if test "x$HW_SALEAE_LOGIC16" = "xyes"; then
+	AC_DEFINE(HAVE_HW_SALEAE_LOGIC16, 1, [Saleae Logic16 support])
+fi
+
+AM_CONDITIONAL(HW_SERIAL_DMM, test x$HW_SERIAL_DMM = xyes)
+if test "x$HW_SERIAL_DMM" = "xyes"; then
+	AC_DEFINE(HAVE_HW_SERIAL_DMM, 1, [Serial DMM support])
+fi
+
+AM_CONDITIONAL(HW_SYSCLK_LWLA, test x$HW_SYSCLK_LWLA = xyes)
+if test "x$HW_SYSCLK_LWLA" = "xyes"; then
+	AC_DEFINE(HAVE_HW_SYSCLK_LWLA, 1, [Sysclk LWLA support])
+fi
+
+AM_CONDITIONAL(HW_TELEINFO, test x$HW_TELEINFO = xyes)
+if test "x$HW_TELEINFO" = "xyes"; then
+	AC_DEFINE(HAVE_HW_TELEINFO, 1, [Teleinfo support])
+fi
+
+AM_CONDITIONAL(HW_TONDAJ_SL_814, test x$HW_TONDAJ_SL_814 = xyes)
+if test "x$HW_TONDAJ_SL_814" = "xyes"; then
+	AC_DEFINE(HAVE_HW_TONDAJ_SL_814, 1, [Tondaj SL-814 support])
+fi
+
+AM_CONDITIONAL(HW_UNI_T_DMM, test x$HW_UNI_T_DMM = xyes)
+if test "x$HW_UNI_T_DMM" = "xyes"; then
+	AC_DEFINE(HAVE_HW_UNI_T_DMM, 1, [UNI-T DMM support])
+fi
+
+AM_CONDITIONAL(HW_UNI_T_UT32X, test x$HW_UNI_T_UT32X = xyes)
+if test "x$HW_UNI_T_UT32X" = "xyes"; then
+	AC_DEFINE(HAVE_HW_UNI_T_UT32X, 1, [UNI-T UT32x support])
+fi
+
+AM_CONDITIONAL(HW_VICTOR_DMM, test x$HW_VICTOR_DMM = xyes)
+if test "x$HW_VICTOR_DMM" = "xyes"; then
+	AC_DEFINE(HAVE_HW_VICTOR_DMM, 1, [Victor DMM support])
+fi
+
+AM_CONDITIONAL(HW_ZEROPLUS_LOGIC_CUBE, test x$HW_ZEROPLUS_LOGIC_CUBE = xyes)
+if test "x$HW_ZEROPLUS_LOGIC_CUBE" = "xyes"; then
+	AC_DEFINE(HAVE_HW_ZEROPLUS_LOGIC_CUBE, 1, [ZEROPLUS Logic Cube support])
+fi
+
+# Checks for header files.
+# These are already checked: inttypes.h stdint.h stdlib.h string.h unistd.h.
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_C_BIGENDIAN
+
+AC_SUBST(FIRMWARE_DIR, "$datadir/sigrok-firmware")
+AC_SUBST(MAKEFLAGS, '--no-print-directory')
+AC_SUBST(AM_LIBTOOLFLAGS, '--silent')
+
+SR_PACKAGE_VERSION_MAJOR=sr_package_version_major
+SR_PACKAGE_VERSION_MINOR=sr_package_version_minor
+SR_PACKAGE_VERSION_MICRO=sr_package_version_micro
+SR_PACKAGE_VERSION=sr_package_version
+
+AC_SUBST(SR_PACKAGE_VERSION_MAJOR)
+AC_SUBST(SR_PACKAGE_VERSION_MINOR)
+AC_SUBST(SR_PACKAGE_VERSION_MICRO)
+AC_SUBST(SR_PACKAGE_VERSION)
+
+AC_CONFIG_FILES([Makefile version.h libsigrok.pc])
+
+AC_OUTPUT
+
+echo
+echo "libsigrok configuration summary:"
+echo
+echo "  - Package version (major.minor.micro):    $SR_PACKAGE_VERSION"
+echo "  - Library version (current:revision:age): $SR_LIB_VERSION"
+echo "  - Prefix: $prefix"
+echo "  - Building on: $build"
+echo "  - Building for: $host"
+echo
+echo "Detected libraries:"
+echo
+
+# Note: This only works for libs with pkg-config integration.
+for lib in "glib-2.0 >= 2.32.0" "libzip >= 0.10" "libserialport >= 0.1.0" "librevisa >= 0.0.20130812" "libusb-1.0 >= 1.0.16" "libftdi >= 0.16" "check >= 0.9.4"; do
+	optional="OPTIONAL"
+	if test "x$lib" = "xglib-2.0 >= 2.32.0"; then optional="REQUIRED"; fi
+	if test "x$lib" = "xlibzip >= 0.10"; then optional="REQUIRED"; fi
+	if `$PKG_CONFIG --exists $lib`; then
+		ver=`$PKG_CONFIG --modversion $lib`
+		answer="yes ($ver)"
+	else
+		answer="no"
+	fi
+	echo "  - ($optional) $lib: $answer"
+done
+
+echo -e "\nEnabled hardware drivers:\n"
+echo "  - agilent-dmm..................... $HW_AGILENT_DMM"
+echo "  - appa-55ii....................... $HW_APPA_55II"
+echo "  - asix-sigma...................... $HW_ASIX_SIGMA"
+echo "  - atten-pps3xxx................... $HW_ATTEN_PPS3XXX"
+echo "  - brymen-bm86x.................... $HW_BRYMEN_BM86X"
+echo "  - brymen-dmm...................... $HW_BRYMEN_DMM"
+echo "  - cem-dt-885x..................... $HW_CEM_DT_885X"
+echo "  - center-3xx...................... $HW_CENTER_3XX"
+echo "  - chronovu-la..................... $HW_CHRONOVU_LA"
+echo "  - colead-slm...................... $HW_COLEAD_SLM"
+echo "  - conrad-digi-35-cpu.............. $HW_CONRAD_DIGI_35_CPU"
+echo "  - demo............................ $HW_DEMO"
+echo "  - fluke-dmm....................... $HW_FLUKE_DMM"
+echo "  - fx2lafw......................... $HW_FX2LAFW"
+echo "  - gmc-mh-1x-2x.................... $HW_GMC_MH_1X_2X"
+echo "  - hameg-hmo....................... $HW_HAMEG_HMO"
+echo "  - hantek-dso...................... $HW_HANTEK_DSO"
+echo "  - ikalogic-scanalogic2............ $HW_IKALOGIC_SCANALOGIC2"
+echo "  - ikalogic-scanaplus.............. $HW_IKALOGIC_SCANAPLUS"
+echo "  - kecheng-kc-330b................. $HW_KECHENG_KC_330B"
+echo "  - lascar-el-usb................... $HW_LASCAR_EL_USB"
+echo "  - mic-985xx....................... $HW_MIC_985XX"
+echo "  - norma-dmm....................... $HW_NORMA_DMM"
+echo "  - openbench-logic-sniffer......... $HW_OLS"
+echo "  - rigol-ds........................ $HW_RIGOL_DS"
+echo "  - saleae-logic16.................. $HW_SALEAE_LOGIC16"
+echo "  - serial-dmm...................... $HW_SERIAL_DMM"
+echo "  - sysclk-lwla..................... $HW_SYSCLK_LWLA"
+echo "  - teleinfo........................ $HW_TELEINFO"
+echo "  - tondaj-sl-814................... $HW_TONDAJ_SL_814"
+echo "  - uni-t-dmm....................... $HW_UNI_T_DMM"
+echo "  - uni-t-ut32x..................... $HW_UNI_T_UT32X"
+echo "  - victor-dmm...................... $HW_VICTOR_DMM"
+echo "  - zeroplus-logic-cube............. $HW_ZEROPLUS_LOGIC_CUBE"
+echo
+
diff --git a/contrib/gnuplot_chronovu_la8.gpi b/contrib/gnuplot_chronovu_la8.gpi
new file mode 100644
index 0000000..d8a8b48
--- /dev/null
+++ b/contrib/gnuplot_chronovu_la8.gpi
@@ -0,0 +1,47 @@
+##
+## This file is part of the libsigrok project.
+##
+## Copyright (C) 2011 Uwe Hermann <uwe at hermann-uwe.de>
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+# We're setting the colors of the 8 channels to match the colors of the
+# probe cables on the ChronoVu LA8:
+#   background = white, borders = black, axes = gray,
+#   ch0 = green, ch1 = orange, ch2 = white, ch3 = red,
+#   ch4 = gray, ch5 = brown, ch6 = blue, ch7 = yellow
+set terminal png large size 2048, 1536 xffffff x000000 x404040 \
+                                       x37aa34 xff7c00 xe0e0e0 xff0000 \
+                                       x808080 x925525 x425adc xfbee13
+set autoscale
+set grid
+set ytics ("Channel 7" 2,  "Channel 6" 4,  "Channel 5" 6,  "Channel 4" 8, \
+           "Channel 3" 10, "Channel 2" 12, "Channel 1" 14, "Channel 0" 16)
+set title "sigrok gnuplot output, http://www.sigrok.org, ChronoVu LA8"
+set xlabel "Sample number"
+set ylabel "Channel"
+set output "sigrok_gnuplot.png"
+
+plot [0:8388608] [0:18] \
+"sigrok_gnuplot.dat" using 1:($2 + 15) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($3 + 13) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($4 + 11) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($5 +  9) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($6 +  7) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($7 +  5) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($8 +  3) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($9 +  1) with lines linewidth 2 title ""
+
diff --git a/contrib/gnuplot_rigol_ds1xx2.gpi b/contrib/gnuplot_rigol_ds1xx2.gpi
new file mode 100644
index 0000000..a598b9e
--- /dev/null
+++ b/contrib/gnuplot_rigol_ds1xx2.gpi
@@ -0,0 +1,37 @@
+##
+## This file is part of the libsigrok project.
+##
+## Copyright (C) 2013 Uwe Hermann <uwe at hermann-uwe.de>
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+set terminal png large size 2048, 1536
+set autoscale
+set grid
+set title "sigrok gnuplot output, http://www.sigrok.org, Rigol DS1xx2"
+set xlabel "Time"
+set ylabel "Voltage"
+set output "sigrok_gnuplot.png"
+
+#
+# Rigol DS1xx2 output is currently always 600 samples in size.
+# This script currently also assumes only one channel is acquired like this:
+#
+#   $ sigrok-cli --driver rigol-ds --frames 1 -p CH1 ...
+#
+plot [0:600] \
+"sigrok_gnuplot.dat" using 1 with lines linewidth 2 title "CH1"
+
diff --git a/contrib/gnuplot_usbeedx16.gpi b/contrib/gnuplot_usbeedx16.gpi
new file mode 100644
index 0000000..4ee0942
--- /dev/null
+++ b/contrib/gnuplot_usbeedx16.gpi
@@ -0,0 +1,62 @@
+##
+## This file is part of the libsigrok project.
+##
+## Copyright (C) 2010 Uwe Hermann <uwe at hermann-uwe.de>
+## Copyright (C) 2012 Ivan Fedorov <oxyum at oxyum.ru>
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+# We're setting the colors of the 16 channels to match the colors of the
+# probe cables on the CWAV USBee DX:
+#   background = white, borders = black, axes = gray,
+#   ch0 = black, ch1 = brown, ch2 = red, ch3 = orange,
+#   ch4 = yellow, ch5 = green, ch6 = blue, ch7 = violet
+#   ch8 = black, ch9 = brown, chA = red, chB = orange,
+#   chC = yellow, chD = green, chE = blue, chF = violet
+set terminal png large size 2048, 1536 xffffff x000000 x404040 \
+                                       x000000 xc25525 xff0000 xff7c00 \
+                                       xfbee13 x37ba34 x425adc x9500d3 \
+                                       x000000 xc25525 xff0000 xff7c00 \
+                                       xfbee13 x37ba34 x425adc x9500d3
+set autoscale
+set grid
+set ytics ("Channel F" 2,  "Channel E" 4,  "Channel D" 6,  "Channel C" 8,  \
+           "Channel B" 10, "Channel A" 12, "Channel 9" 14, "Channel 8" 16, \
+           "Channel 7" 18, "Channel 6" 20, "Channel 5" 22, "Channel 4" 24, \
+           "Channel 3" 26, "Channel 2" 28, "Channel 1" 30, "Channel 0" 32)
+set title "sigrok gnuplot output, http://www.sigrok.org, CWAV USBee DX"
+set xlabel "Sample number"
+set ylabel "Channel"
+set output "sigrok_gnuplot.png"
+
+plot [0:200000] [0:34] \
+"sigrok_gnuplot.dat" using 1:($6 + 31) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($7 + 29) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($8 + 27) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($9 + 25) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($5 + 23) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($4 + 21) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($3 + 19) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($2 + 17) with lines linewidth 2 title "", \
+\
+"sigrok_gnuplot.dat" using 1:($17 + 15) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($16 + 13) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($15 + 11) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($10 +  9) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($11 +  7) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($12 +  5) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($13 +  3) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($14 +  1) with lines linewidth 2 title ""
diff --git a/contrib/gnuplot_usbeedx8.gpi b/contrib/gnuplot_usbeedx8.gpi
new file mode 100644
index 0000000..69f6c43
--- /dev/null
+++ b/contrib/gnuplot_usbeedx8.gpi
@@ -0,0 +1,47 @@
+##
+## This file is part of the libsigrok project.
+##
+## Copyright (C) 2010 Uwe Hermann <uwe at hermann-uwe.de>
+## Copyright (C) 2012 Ivan Fedorov <oxyum at oxyum.ru>
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+# We're setting the colors of the 8 channels to match the colors of the
+# probe cables on the CWAV USBee DX:
+#   background = white, borders = black, axes = gray,
+#   ch0 = black, ch1 = brown, ch2 = red, ch3 = orange,
+#   ch4 = yellow, ch5 = green, ch6 = blue, ch7 = violet
+set terminal png large size 2048, 1536 xffffff x000000 x404040 \
+                                       x000000 xc25525 xff0000 xff7c00 \
+                                       xfbee13 x37ba34 x425adc x9500d3
+set autoscale
+set grid
+set ytics ("Channel 7" 2,  "Channel 6" 4,  "Channel 5" 6,  "Channel 4" 8, \
+           "Channel 3" 10, "Channel 2" 12, "Channel 1" 14, "Channel 0" 16)
+set title "sigrok gnuplot output, http://www.sigrok.org, CWAV USBee DX"
+set xlabel "Sample number"
+set ylabel "Channel"
+set output "sigrok_gnuplot.png"
+
+plot [0:200000] [0:18] \
+"sigrok_gnuplot.dat" using 1:($6 + 15) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($7 + 13) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($8 + 11) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($9 +  9) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($5 +  7) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($4 +  5) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($3 +  3) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($2 +  1) with lines linewidth 2 title ""
diff --git a/contrib/gnuplot_usbeesx.gpi b/contrib/gnuplot_usbeesx.gpi
new file mode 100644
index 0000000..74b664a
--- /dev/null
+++ b/contrib/gnuplot_usbeesx.gpi
@@ -0,0 +1,47 @@
+##
+## This file is part of the libsigrok project.
+##
+## Copyright (C) 2010 Uwe Hermann <uwe at hermann-uwe.de>
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+# We're setting the colors of the 8 channels to match the colors of the
+# probe cables on the CWAV USBee SX:
+#   background = white, borders = black, axes = gray,
+#   ch0 = black, ch1 = brown, ch2 = red, ch3 = orange,
+#   ch4 = yellow, ch5 = green, ch6 = blue, ch7 = violet
+set terminal png large size 2048, 1536 xffffff x000000 x404040 \
+                                       x000000 xc25525 xff0000 xff7c00 \
+                                       xfbee13 x37ba34 x425adc x9500d3
+set autoscale
+set grid
+set ytics ("Channel 7" 2,  "Channel 6" 4,  "Channel 5" 6,  "Channel 4" 8, \
+           "Channel 3" 10, "Channel 2" 12, "Channel 1" 14, "Channel 0" 16)
+set title "sigrok gnuplot output, http://www.sigrok.org, CWAV USBee SX"
+set xlabel "Sample number"
+set ylabel "Channel"
+set output "sigrok_gnuplot.png"
+
+plot [0:1000000] [0:18] \
+"sigrok_gnuplot.dat" using 1:($2 + 15) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($3 + 13) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($4 + 11) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($5 +  9) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($6 +  7) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($7 +  5) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($8 +  3) with lines linewidth 2 title "", \
+"sigrok_gnuplot.dat" using 1:($9 +  1) with lines linewidth 2 title ""
+
diff --git a/contrib/sigrok-logo-notext.png b/contrib/sigrok-logo-notext.png
new file mode 100644
index 0000000..a3ca65f
Binary files /dev/null and b/contrib/sigrok-logo-notext.png differ
diff --git a/contrib/z60_libsigrok.rules b/contrib/z60_libsigrok.rules
new file mode 100644
index 0000000..46590c1
--- /dev/null
+++ b/contrib/z60_libsigrok.rules
@@ -0,0 +1,188 @@
+##
+## This file is part of the libsigrok project.
+##
+## Copyright (C) 2010-2013 Uwe Hermann <uwe at hermann-uwe.de>
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+##
+## Please keep this list sorted alphabetically by vendor/device name.
+##
+
+ACTION!="add|change", GOTO="libsigrok_rules_end"
+SUBSYSTEM!="usb|usbmisc|usb_device", GOTO="libsigrok_rules_end"
+
+# ASIX SIGMA
+# ASIX SIGMA2
+ATTRS{idVendor}=="a600", ATTRS{idProduct}=="a000", MODE="664", GROUP="plugdev"
+
+# Braintechnology USB-LPS
+ATTRS{idVendor}=="16d0", ATTRS{idProduct}=="0498", MODE="664", GROUP="plugdev"
+
+# CEM DT-8852
+ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", MODE="664", GROUP="plugdev"
+
+# ChronoVu LA8 (new VID/PID)
+# ChronoVu LA16 (new VID/PID)
+ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8867", MODE="664", GROUP="plugdev"
+
+# CWAV USBee AX
+# ARMFLY AX-Pro (clone of the CWAV USBee AX)
+# ARMFLY Mini-Logic (clone of the CWAV USBee AX)
+# EE Electronics ESLA201A (clone of the CWAV USBee AX)
+# MCU123 USBee AX Pro clone (clone of the CWAV USBee AX)
+# XZL_Studio AX (clone of the CWAV USBee AX)
+ATTRS{idVendor}=="08a9", ATTRS{idProduct}=="0014", MODE="664", GROUP="plugdev"
+
+# CWAV USBee DX
+# XZL_Studio DX (clone of the CWAV USBee DX)
+ATTRS{idVendor}=="08a9", ATTRS{idProduct}=="0015", MODE="664", GROUP="plugdev"
+
+# CWAV USBee SX
+ATTRS{idVendor}=="08a9", ATTRS{idProduct}=="0009", MODE="664", GROUP="plugdev"
+
+# Cypress FX2 eval boards without EEPROM:
+# Lcsoft Mini Board
+# Braintechnology USB Interface V2.x
+ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="8613", MODE="664", GROUP="plugdev"
+
+# Dangerous Prototypes Buspirate (v3)
+# ChronoVu LA8 (old VID/PID)
+# ChronoVu LA16 (old VID/PID)
+ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE="664", GROUP="plugdev"
+
+# Dangerous Prototypes Buspirate (v4)
+ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="fb00", MODE="664", GROUP="plugdev"
+
+# Hantek DSO-2090
+# lsusb: "04b4:2090 Cypress Semiconductor Corp."
+# lsusb after FW upload: "04b5:2090 ROHM LSI Systems USA, LLC"
+ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="2090", MODE="664", GROUP="plugdev"
+ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="2090", MODE="664", GROUP="plugdev"
+
+# Hantek DSO-2150
+# lsusb: "04b4:2150 Cypress Semiconductor Corp."
+# lsusb after FW upload: "04b5:2150 ROHM LSI Systems USA, LLC"
+ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="2150", MODE="664", GROUP="plugdev"
+ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="2150", MODE="664", GROUP="plugdev"
+
+# Hantek DSO-2250
+# lsusb: "04b4:2250 Cypress Semiconductor Corp."
+# lsusb after FW upload: "04b5:2250 ROHM LSI Systems USA, LLC"
+ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="2250", MODE="664", GROUP="plugdev"
+ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="2250", MODE="664", GROUP="plugdev"
+
+# Hantek DSO-5200
+# lsusb: "04b4:5200 Cypress Semiconductor Corp."
+# lsusb after FW upload: "04b5:5200 ROHM LSI Systems USA, LLC"
+ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="5200", MODE="664", GROUP="plugdev"
+ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="5200", MODE="664", GROUP="plugdev"
+
+# Hantek DSO-5200A
+# lsusb: "04b4:520a Cypress Semiconductor Corp."
+# lsusb after FW upload: "04b5:520a ROHM LSI Systems USA, LLC"
+ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="520a", MODE="664", GROUP="plugdev"
+ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="520a", MODE="664", GROUP="plugdev"
+
+# IKALOGIC Scanalogic-2
+ATTRS{idVendor}=="20a0", ATTRS{idProduct}=="4123", MODE="664", GROUP="plugdev"
+
+# IKALOGIC ScanaPLUS
+ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6014", MODE="664", GROUP="plugdev"
+
+# Kecheng KC-330B
+ATTRS{idVendor}=="1041", ATTRS{idProduct}=="8101", MODE="664", GROUP="plugdev"
+
+# Lascar Electronics EL-USB-2
+# Lascar Electronics EL-USB-CO
+# This is actually the generic SiLabs (Cygnal) F32x USBXpress VID:PID.
+ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="0002", MODE="664", GROUP="plugdev"
+
+# Link Instruments MSO-19
+ATTRS{idVendor}=="3195", ATTRS{idProduct}=="f190", MODE="664", GROUP="plugdev"
+
+# Logic Shrimp
+ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="fa95", MODE="664", GROUP="plugdev"
+
+# MiniLA Mockup
+ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", MODE="664", GROUP="plugdev"
+
+# MIC 98581
+# MIC 98583
+# Tondaj SL-814
+ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", MODE="664", GROUP="plugdev"
+
+# Openbench Logic Sniffer
+ATTRS{idVendor}=="04d8", ATTRS{idProduct}=="000a", MODE="664", GROUP="plugdev"
+
+# Rigol DS1000 series
+ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="0588", MODE="664", GROUP="plugdev"
+
+# Rigol DS2000 series
+ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="04b0", MODE="664", GROUP="plugdev"
+
+# Rigol DG4000 series
+ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="0641", MODE="664", GROUP="plugdev"
+
+# Agilent DSO1000 series
+ATTRS{idVendor}=="0957", ATTRS{idProduct}=="0588", MODE="664", GROUP="plugdev"
+
+# Saleae Logic
+# EE Electronics ESLA100 (clone of the Saleae Logic)
+# Robomotic MiniLogic (clone of the Saleae Logic)
+# Robomotic BugLogic 3 (clone of the Saleae Logic)
+# MCU123 Saleae Logic clone (clone of the Saleae Logic)
+ATTRS{idVendor}=="0925", ATTRS{idProduct}=="3881", MODE="664", GROUP="plugdev"
+
+# Saleae Logic16
+ATTRS{idVendor}=="21a9", ATTRS{idProduct}=="1001", MODE="664", GROUP="plugdev"
+
+# SysClk LWLA1034
+ATTRS{idVendor}=="2961", ATTRS{idProduct}=="6689", MODE="664", GROUP="plugdev"
+
+# UNI-T UT-D04 multimeter cable (for various UNI-T and rebranded DMMs)
+# http://sigrok.org/wiki/Device_cables#UNI-T_UT-D04
+# UNI-T UT325
+ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="e008", MODE="664", GROUP="plugdev"
+
+# V&A VA4000 multimeter cable (for various V&A DMMs)
+# http://sigrok.org/wiki/Device_cables#V.26A_VA4000
+ATTRS{idVendor}=="04fc", ATTRS{idProduct}=="0201", MODE="664", GROUP="plugdev"
+
+# Victor 70C
+# Victor 86C
+ATTRS{idVendor}=="1244", ATTRS{idProduct}=="d237", MODE="664", GROUP="plugdev"
+
+# ZEROPLUS Logic Cube LAP-C series
+# There are various devices in the ZEROPLUS Logic Cube series:
+# 0c12:7002: LAP-16128U
+# 0c12:7009: LAP-C(16064)
+# 0c12:700a: LAP-C(16128)
+# 0c12:700b: LAP-C(32128)
+# 0c12:700c: LAP-C(321000)
+# 0c12:700d: LAP-C(322000)
+# 0c12:700e: LAP-C(16032)
+# 0c12:7016: LAP-C(162000)
+ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="7002", MODE="664", GROUP="plugdev"
+ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="7009", MODE="664", GROUP="plugdev"
+ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="700a", MODE="664", GROUP="plugdev"
+ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="700b", MODE="664", GROUP="plugdev"
+ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="700c", MODE="664", GROUP="plugdev"
+ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="700d", MODE="664", GROUP="plugdev"
+ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="700e", MODE="664", GROUP="plugdev"
+ATTRS{idVendor}=="0c12", ATTRS{idProduct}=="7016", MODE="664", GROUP="plugdev"
+
+LABEL="libsigrok_rules_end"
diff --git a/device.c b/device.c
new file mode 100644
index 0000000..f87bb66
--- /dev/null
+++ b/device.c
@@ -0,0 +1,530 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <glib.h>
+#include "config.h" /* Needed for HAVE_LIBUSB_1_0 and others. */
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+/** @cond PRIVATE */
+#define LOG_PREFIX "device"
+/** @endcond */
+
+/**
+ * @file
+ *
+ * Device handling in libsigrok.
+ */
+
+/**
+ * @defgroup grp_devices Devices
+ *
+ * Device handling in libsigrok.
+ *
+ * @{
+ */
+
+/** @private
+ *  Allocate and initialize new struct sr_channel
+ *  @param[in]  index @copydoc sr_channel::index
+ *  @param[in]  type @copydoc sr_channel::type
+ *  @param[in]  enabled @copydoc sr_channel::enabled
+ *  @param[in]  name @copydoc sr_channel::name
+ *
+ *  @return NULL (failure) or new struct sr_channel*.
+ */
+SR_PRIV struct sr_channel *sr_channel_new(int index, int type,
+		gboolean enabled, const char *name)
+{
+	struct sr_channel *ch;
+
+	if (!(ch = g_try_malloc0(sizeof(struct sr_channel)))) {
+		sr_err("Channel malloc failed.");
+		return NULL;
+	}
+
+	ch->index = index;
+	ch->type = type;
+	ch->enabled = enabled;
+	if (name)
+		ch->name = g_strdup(name);
+
+	return ch;
+}
+
+/**
+ * Set the name of the specified channel in the specified device.
+ *
+ * If the channel already has a different name assigned to it, it will be
+ * removed, and the new name will be saved instead.
+ *
+ * @param sdi The device instance the channel is connected to.
+ * @param[in] channelnum The number of the channel whose name to set.
+ *                 Note that the channel numbers start at 0.
+ * @param[in] name The new name that the specified channel should get. A copy
+ *             of the string is made.
+ *
+ * @return SR_OK on success, or SR_ERR_ARG on invalid arguments.
+ *
+ * @since 0.3.0
+ */
+SR_API int sr_dev_channel_name_set(const struct sr_dev_inst *sdi,
+		int channelnum, const char *name)
+{
+	GSList *l;
+	struct sr_channel *ch;
+	int ret;
+
+	if (!sdi) {
+		sr_err("%s: sdi was NULL", __func__);
+		return SR_ERR_ARG;
+	}
+
+	ret = SR_ERR_ARG;
+	for (l = sdi->channels; l; l = l->next) {
+		ch = l->data;
+		if (ch->index == channelnum) {
+			g_free(ch->name);
+			ch->name = g_strdup(name);
+			ret = SR_OK;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+/**
+ * Enable or disable a channel on the specified device.
+ *
+ * @param sdi The device instance the channel is connected to.
+ * @param channelnum The channel number, starting from 0.
+ * @param state TRUE to enable the channel, FALSE to disable.
+ *
+ * @return SR_OK on success or SR_ERR on failure.  In case of invalid
+ *         arguments, SR_ERR_ARG is returned and the channel enabled state
+ *         remains unchanged.
+ *
+ * @since 0.3.0
+ */
+SR_API int sr_dev_channel_enable(const struct sr_dev_inst *sdi, int channelnum,
+		gboolean state)
+{
+	GSList *l;
+	struct sr_channel *ch;
+	int ret;
+	gboolean was_enabled;
+
+	if (!sdi)
+		return SR_ERR_ARG;
+
+	ret = SR_ERR_ARG;
+	for (l = sdi->channels; l; l = l->next) {
+		ch = l->data;
+		if (ch->index == channelnum) {
+			was_enabled = ch->enabled;
+			ch->enabled = state;
+			ret = SR_OK;
+			if (!state != !was_enabled && sdi->driver
+					&& sdi->driver->config_channel_set) {
+				ret = sdi->driver->config_channel_set(
+					sdi, ch, SR_CHANNEL_SET_ENABLED);
+				/* Roll back change if it wasn't applicable. */
+				if (ret == SR_ERR_ARG)
+					ch->enabled = was_enabled;
+			}
+			break;
+		}
+	}
+
+	return ret;
+}
+
+/**
+ * Add a trigger to the specified device (and the specified channel).
+ *
+ * If the specified channel of this device already has a trigger, it will
+ * be silently replaced.
+ *
+ * @param[in,out] sdi Pointer to the device instance; must not be NULL.
+ * @param[in] channelnum Number of channel, starting at 0.
+ * @param[in] trigger Trigger string, in the format used by sigrok-cli
+ *
+ * @return SR_OK on success or SR_ERR on failure.  In case of invalid
+ *         arguments, SR_ERR_ARG is returned and the trigger settings
+ *         remain unchanged.
+ *
+ * @since 0.2.0
+ */
+SR_API int sr_dev_trigger_set(const struct sr_dev_inst *sdi, int channelnum,
+		const char *trigger)
+{
+	GSList *l;
+	struct sr_channel *ch;
+	char *old_trigger;
+	int ret;
+
+	if (!sdi)
+		return SR_ERR_ARG;
+
+	ret = SR_ERR_ARG;
+	for (l = sdi->channels; l; l = l->next) {
+		ch = l->data;
+		if (ch->index == channelnum) {
+			old_trigger = ch->trigger;
+			ret = SR_OK;
+			if (g_strcmp0(trigger, old_trigger) == 0)
+				break;
+			/* Set new trigger if it has changed. */
+			ch->trigger = g_strdup(trigger);
+
+			if (sdi->driver && sdi->driver->config_channel_set) {
+				ret = sdi->driver->config_channel_set(
+					sdi, ch, SR_CHANNEL_SET_TRIGGER);
+				/* Roll back change if it wasn't applicable. */
+				if (ret == SR_ERR_ARG) {
+					g_free(ch->trigger);
+					ch->trigger = old_trigger;
+					break;
+				}
+			}
+			g_free(old_trigger);
+			break;
+		}
+	}
+
+	return ret;
+}
+
+/**
+ * Determine whether the specified device instance has the specified
+ * capability.
+ *
+ * @param sdi Pointer to the device instance to be checked. Must not be NULL.
+ *            If the device's 'driver' field is NULL (virtual device), this
+ *            function will always return FALSE (virtual devices don't have
+ *            a hardware capabilities list).
+ * @param[in] key The option that should be checked for is supported by the
+ *            specified device.
+ *
+ * @retval TRUE Device has the specified option
+ * @retval FALSE Device does not have the specified option, invalid input
+ *         parameters or other error conditions.
+ *
+ * @since 0.2.0
+ */
+SR_API gboolean sr_dev_has_option(const struct sr_dev_inst *sdi, int key)
+{
+	GVariant *gvar;
+	const int *devopts;
+	gsize num_opts, i;
+	int ret;
+
+	if (!sdi || !sdi->driver || !sdi->driver->config_list)
+		return FALSE;
+
+	if (sdi->driver->config_list(SR_CONF_DEVICE_OPTIONS,
+				&gvar, sdi, NULL) != SR_OK)
+		return FALSE;
+
+	ret = FALSE;
+	devopts = g_variant_get_fixed_array(gvar, &num_opts, sizeof(int32_t));
+	for (i = 0; i < num_opts; i++) {
+		if (devopts[i] == key) {
+			ret = TRUE;
+			break;
+		}
+	}
+	g_variant_unref(gvar);
+
+	return ret;
+}
+
+/** @private
+ *  Allocate and init new device instance struct.
+ *  @param[in]  index   @copydoc sr_dev_inst::index
+ *  @param[in]  status  @copydoc sr_dev_inst::status
+ *  @param[in]  vendor  @copydoc sr_dev_inst::vendor
+ *  @param[in]  model   @copydoc sr_dev_inst::model
+ *  @param[in]  version @copydoc sr_dev_inst::version
+ *
+ *  @retval NULL Error
+ *  @retval struct sr_dev_inst *. Dynamically allocated, free using
+ *              sr_dev_inst_free().
+ */
+SR_PRIV struct sr_dev_inst *sr_dev_inst_new(int index, int status,
+		const char *vendor, const char *model, const char *version)
+{
+	struct sr_dev_inst *sdi;
+
+	if (!(sdi = g_try_malloc(sizeof(struct sr_dev_inst)))) {
+		sr_err("Device instance malloc failed.");
+		return NULL;
+	}
+
+	sdi->driver = NULL;
+	sdi->index = index;
+	sdi->status = status;
+	sdi->inst_type = -1;
+	sdi->vendor = vendor ? g_strdup(vendor) : NULL;
+	sdi->model = model ? g_strdup(model) : NULL;
+	sdi->version = version ? g_strdup(version) : NULL;
+	sdi->channels = NULL;
+	sdi->channel_groups = NULL;
+	sdi->conn = NULL;
+	sdi->priv = NULL;
+
+	return sdi;
+}
+
+/** @private
+ *  Free device instance struct created by sr_dev_inst().
+ *  @param sdi  struct* to free.
+ */
+SR_PRIV void sr_dev_inst_free(struct sr_dev_inst *sdi)
+{
+	struct sr_channel *ch;
+	GSList *l;
+
+	for (l = sdi->channels; l; l = l->next) {
+		ch = l->data;
+		g_free(ch->name);
+		g_free(ch->trigger);
+		g_free(ch);
+	}
+	g_slist_free(sdi->channels);
+
+	if (sdi->channel_groups)
+		g_slist_free(sdi->channel_groups);
+
+	g_free(sdi->vendor);
+	g_free(sdi->model);
+	g_free(sdi->version);
+	g_free(sdi);
+}
+
+#ifdef HAVE_LIBUSB_1_0
+
+/** @private
+ *  Allocate and init struct for USB device instance.
+ *  @param[in]  bus @copydoc sr_usb_dev_inst::bus
+ *  @param[in]  address @copydoc sr_usb_dev_inst::address
+ *  @param[in]  hdl @copydoc sr_usb_dev_inst::devhdl
+ *
+ *  @retval NULL Error
+ *  @retval other struct sr_usb_dev_inst * for USB device instance.
+ */
+SR_PRIV struct sr_usb_dev_inst *sr_usb_dev_inst_new(uint8_t bus,
+			uint8_t address, struct libusb_device_handle *hdl)
+{
+	struct sr_usb_dev_inst *udi;
+
+	if (!(udi = g_try_malloc(sizeof(struct sr_usb_dev_inst)))) {
+		sr_err("USB device instance malloc failed.");
+		return NULL;
+	}
+
+	udi->bus = bus;
+	udi->address = address;
+	udi->devhdl = hdl;
+
+	return udi;
+}
+
+/** @private
+ *  Free struct * allocated by sr_usb_dev_inst().
+ *  @param usb  struct* to free. Must not be NULL.
+ */
+SR_PRIV void sr_usb_dev_inst_free(struct sr_usb_dev_inst *usb)
+{
+	g_free(usb);
+}
+
+#endif
+
+#ifdef HAVE_LIBSERIALPORT
+
+/**
+ * @private
+ *
+ * Both parameters are copied to newly allocated strings, and freed
+ * automatically by sr_serial_dev_inst_free().
+ *
+ * @param[in] port OS-specific serial port specification. Examples:
+ *                 "/dev/ttyUSB0", "/dev/ttyACM1", "/dev/tty.Modem-0", "COM1".
+ * @param[in] serialcomm A serial communication parameters string, in the form
+ *              of \<speed\>/\<data bits\>\<parity\>\<stopbits\>, for example
+ *              "9600/8n1" or "600/7o2". This is an optional parameter;
+ *              it may be filled in later.
+ *
+ * @return A pointer to a newly initialized struct sr_serial_dev_inst,
+ *         or NULL on error.
+ */
+SR_PRIV struct sr_serial_dev_inst *sr_serial_dev_inst_new(const char *port,
+		const char *serialcomm)
+{
+	struct sr_serial_dev_inst *serial;
+
+	if (!port) {
+		sr_err("Serial port required.");
+		return NULL;
+	}
+
+	if (!(serial = g_try_malloc0(sizeof(struct sr_serial_dev_inst)))) {
+		sr_err("Serial device instance malloc failed.");
+		return NULL;
+	}
+
+	serial->port = g_strdup(port);
+	if (serialcomm)
+		serial->serialcomm = g_strdup(serialcomm);
+
+	return serial;
+}
+
+/** @private
+ *  Free struct sr_serial_dev_inst * allocated by sr_serial_dev_inst().
+ *  @param serial   struct sr_serial_dev_inst * to free. Must not be NULL.
+ */
+SR_PRIV void sr_serial_dev_inst_free(struct sr_serial_dev_inst *serial)
+{
+	g_free(serial->port);
+	g_free(serial->serialcomm);
+	g_free(serial);
+}
+#endif
+
+/** @private */
+SR_PRIV struct sr_usbtmc_dev_inst *sr_usbtmc_dev_inst_new(const char *device)
+{
+	struct sr_usbtmc_dev_inst *usbtmc;
+
+	if (!device) {
+		sr_err("Device name required.");
+		return NULL;
+	}
+
+	if (!(usbtmc = g_try_malloc0(sizeof(struct sr_usbtmc_dev_inst)))) {
+		sr_err("USBTMC device instance malloc failed.");
+		return NULL;
+	}
+
+	usbtmc->device = g_strdup(device);
+	usbtmc->fd = -1;
+
+	return usbtmc;
+}
+
+/** @private */
+SR_PRIV void sr_usbtmc_dev_inst_free(struct sr_usbtmc_dev_inst *usbtmc)
+{
+	g_free(usbtmc->device);
+	g_free(usbtmc);
+}
+
+/**
+ * Get the list of devices/instances of the specified driver.
+ *
+ * @param driver The driver to use. Must not be NULL.
+ *
+ * @return The list of devices/instances of this driver, or NULL upon errors
+ *         or if the list is empty.
+ *
+ * @since 0.2.0
+ */
+SR_API GSList *sr_dev_list(const struct sr_dev_driver *driver)
+{
+	if (driver && driver->dev_list)
+		return driver->dev_list();
+	else
+		return NULL;
+}
+
+/**
+ * Clear the list of device instances a driver knows about.
+ *
+ * @param driver The driver to use. This must be a pointer to one of
+ *               the entries returned by sr_driver_list(). Must not be NULL.
+ *
+ * @retval SR_OK Success
+ * @retval SR_ERR_ARG Invalid driver
+ *
+ * @since 0.2.0
+ */
+SR_API int sr_dev_clear(const struct sr_dev_driver *driver)
+{
+	int ret;
+
+	if (!driver) {
+		sr_err("Invalid driver.");
+		return SR_ERR_ARG;
+	}
+
+	if (driver->dev_clear)
+		ret = driver->dev_clear();
+	else
+		ret = std_dev_clear(driver, NULL);
+
+	return ret;
+}
+
+/**
+ * Open the specified device.
+ *
+ * @param sdi Device instance to use. Must not be NULL.
+ *
+ * @return SR_OK upon success, a negative error code upon errors.
+ *
+ * @since 0.2.0
+ */
+SR_API int sr_dev_open(struct sr_dev_inst *sdi)
+{
+	int ret;
+
+	if (!sdi || !sdi->driver || !sdi->driver->dev_open)
+		return SR_ERR;
+
+	ret = sdi->driver->dev_open(sdi);
+
+	return ret;
+}
+
+/**
+ * Close the specified device.
+ *
+ * @param sdi Device instance to use. Must not be NULL.
+ *
+ * @return SR_OK upon success, a negative error code upon errors.
+ *
+ * @since 0.2.0
+ */
+SR_API int sr_dev_close(struct sr_dev_inst *sdi)
+{
+	int ret;
+
+	if (!sdi || !sdi->driver || !sdi->driver->dev_close)
+		return SR_ERR;
+
+	ret = sdi->driver->dev_close(sdi);
+
+	return ret;
+}
+
+/** @} */
diff --git a/error.c b/error.c
new file mode 100644
index 0000000..f877975
--- /dev/null
+++ b/error.c
@@ -0,0 +1,137 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "libsigrok.h"
+
+/**
+ * @file
+ *
+ * Error handling in libsigrok.
+ */
+
+/**
+ * @defgroup grp_error Error handling
+ *
+ * Error handling in libsigrok.
+ *
+ * libsigrok functions usually return @ref SR_OK upon success, or a negative
+ * error code on failure.
+ *
+ * @{
+ */
+
+/**
+ * Return a human-readable error string for the given libsigrok error code.
+ *
+ * @param error_code A libsigrok error code number, such as SR_ERR_MALLOC.
+ *
+ * @return A const string containing a short, human-readable (English)
+ *         description of the error, such as "memory allocation error".
+ *         The string must NOT be free'd by the caller!
+ *
+ * @see sr_strerror_name
+ *
+ * @since 0.2.0
+ */
+SR_API const char *sr_strerror(int error_code)
+{
+	/*
+	 * Note: All defined SR_* error macros from libsigrok.h must have
+	 * an entry in this function, as well as in sr_strerror_name().
+	 */
+
+	switch (error_code) {
+	case SR_OK:
+		return "no error";
+	case SR_ERR:
+		return "generic/unspecified error";
+	case SR_ERR_MALLOC:
+		return "memory allocation error";
+	case SR_ERR_ARG:
+		return "invalid argument";
+	case SR_ERR_BUG:
+		return "internal error";
+	case SR_ERR_SAMPLERATE:
+		return "invalid samplerate";
+	case SR_ERR_NA:
+		return "not applicable";
+	case SR_ERR_DEV_CLOSED:
+		return "device closed but should be open";
+	case SR_ERR_TIMEOUT:
+		return "timeout occurred";
+	case SR_ERR_CHANNEL_GROUP:
+		return "no channel group specified";
+	default:
+		return "unknown error";
+	}
+}
+
+/**
+ * Return the "name" string of the given libsigrok error code.
+ *
+ * For example, the "name" of the SR_ERR_MALLOC error code is "SR_ERR_MALLOC",
+ * the name of the SR_OK code is "SR_OK", and so on.
+ *
+ * This function can be used for various purposes where the "name" string of
+ * a libsigrok error code is useful.
+ *
+ * @param error_code A libsigrok error code number, such as SR_ERR_MALLOC.
+ *
+ * @return A const string containing the "name" of the error code as string.
+ *         The string must NOT be free'd by the caller!
+ *
+ * @see sr_strerror
+ *
+ * @since 0.2.0
+ */
+SR_API const char *sr_strerror_name(int error_code)
+{
+	/*
+	 * Note: All defined SR_* error macros from libsigrok.h must have
+	 * an entry in this function, as well as in sr_strerror().
+	 */
+
+	switch (error_code) {
+	case SR_OK:
+		return "SR_OK";
+	case SR_ERR:
+		return "SR_ERR";
+	case SR_ERR_MALLOC:
+		return "SR_ERR_MALLOC";
+	case SR_ERR_ARG:
+		return "SR_ERR_ARG";
+	case SR_ERR_BUG:
+		return "SR_ERR_BUG";
+	case SR_ERR_SAMPLERATE:
+		return "SR_ERR_SAMPLERATE";
+	case SR_ERR_NA:
+		return "SR_ERR_NA";
+	case SR_ERR_DEV_CLOSED:
+		return "SR_ERR_DEV_CLOSED";
+	case SR_ERR_TIMEOUT:
+		return "SR_ERR_TIMEOUT";
+	case SR_ERR_CHANNEL_GROUP:
+		return "SR_ERR_CHANNEL_GROUP";
+	default:
+		return "unknown error code";
+	}
+}
+
+/** @} */
diff --git a/hardware/agilent-dmm/agilent-dmm.h b/hardware/agilent-dmm/agilent-dmm.h
new file mode 100644
index 0000000..2277111
--- /dev/null
+++ b/hardware/agilent-dmm/agilent-dmm.h
@@ -0,0 +1,80 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_AGILENT_DMM_AGILENT_DMM_H
+#define LIBSIGROK_HARDWARE_AGILENT_DMM_AGILENT_DMM_H
+
+#define LOG_PREFIX "agilent-dmm"
+
+#define AGDMM_BUFSIZE  256
+
+/* Supported models */
+enum {
+	AGILENT_U1231A = 1,
+	AGILENT_U1232A,
+	AGILENT_U1233A,
+	AGILENT_U1251A,
+	AGILENT_U1252A,
+	AGILENT_U1253A,
+};
+
+/* Supported device profiles */
+struct agdmm_profile {
+	int model;
+	const char *modelname;
+	const struct agdmm_job *jobs;
+	const struct agdmm_recv *recvs;
+};
+
+/* Private, per-device-instance driver context. */
+struct dev_context {
+	const struct agdmm_profile *profile;
+	uint64_t limit_samples;
+	uint64_t limit_msec;
+
+	/* Opaque pointer passed in by the frontend. */
+	void *cb_data;
+
+	/* Runtime. */
+	uint64_t num_samples;
+	int64_t jobqueue[8];
+	unsigned char buf[AGDMM_BUFSIZE];
+	int buflen;
+	int cur_mq;
+	int cur_unit;
+	int cur_mqflags;
+	int cur_divider;
+	int cur_acdc;
+	int mode_tempaux;
+	int mode_continuity;
+};
+
+struct agdmm_job {
+	int interval;
+	int (*send) (const struct sr_dev_inst *sdi);
+};
+
+struct agdmm_recv {
+	const char *recv_regex;
+	int (*recv) (const struct sr_dev_inst *sdi, GMatchInfo *match);
+};
+
+SR_PRIV int agdmm_receive_data(int fd, int revents, void *cb_data);
+
+#endif
diff --git a/hardware/agilent-dmm/api.c b/hardware/agilent-dmm/api.c
new file mode 100644
index 0000000..ccc2f65
--- /dev/null
+++ b/hardware/agilent-dmm/api.c
@@ -0,0 +1,280 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "agilent-dmm.h"
+
+static const int32_t hwopts[] = {
+	SR_CONF_CONN,
+	SR_CONF_SERIALCOMM,
+};
+
+static const int32_t hwcaps[] = {
+	SR_CONF_MULTIMETER,
+	SR_CONF_LIMIT_SAMPLES,
+	SR_CONF_LIMIT_MSEC,
+	SR_CONF_CONTINUOUS,
+};
+
+extern const struct agdmm_job agdmm_jobs_u123x[];
+extern const struct agdmm_recv agdmm_recvs_u123x[];
+extern const struct agdmm_job agdmm_jobs_u125x[];
+extern const struct agdmm_recv agdmm_recvs_u125x[];
+
+/* This works on all the Agilent U12xxA series, although the
+ * U127xA can apparently also run at 19200/8n1. */
+#define SERIALCOMM "9600/8n1"
+
+static const struct agdmm_profile supported_agdmm[] = {
+	{ AGILENT_U1231A, "U1231A", agdmm_jobs_u123x, agdmm_recvs_u123x },
+	{ AGILENT_U1232A, "U1232A", agdmm_jobs_u123x, agdmm_recvs_u123x },
+	{ AGILENT_U1233A, "U1233A", agdmm_jobs_u123x, agdmm_recvs_u123x },
+	{ AGILENT_U1251A, "U1251A", agdmm_jobs_u125x, agdmm_recvs_u125x },
+	{ AGILENT_U1252A, "U1252A", agdmm_jobs_u125x, agdmm_recvs_u125x },
+	{ AGILENT_U1253A, "U1253A", agdmm_jobs_u125x, agdmm_recvs_u125x },
+	{ 0, NULL, NULL, NULL }
+};
+
+SR_PRIV struct sr_dev_driver agdmm_driver_info;
+static struct sr_dev_driver *di = &agdmm_driver_info;
+
+static int init(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+	struct sr_dev_inst *sdi;
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_config *src;
+	struct sr_channel *ch;
+	struct sr_serial_dev_inst *serial;
+	GSList *l, *devices;
+	int len, i;
+	const char *conn, *serialcomm;
+	char *buf, **tokens;
+
+	drvc = di->priv;
+	drvc->instances = NULL;
+
+	devices = NULL;
+	conn = serialcomm = NULL;
+	for (l = options; l; l = l->next) {
+		src = l->data;
+		switch (src->key) {
+		case SR_CONF_CONN:
+			conn = g_variant_get_string(src->data, NULL);
+			break;
+		case SR_CONF_SERIALCOMM:
+			serialcomm = g_variant_get_string(src->data, NULL);
+			break;
+		}
+	}
+	if (!conn)
+		return NULL;
+	if (!serialcomm)
+		serialcomm = SERIALCOMM;
+
+	if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+		return NULL;
+
+	if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+		return NULL;
+
+	serial_flush(serial);
+	if (serial_write(serial, "*IDN?\r\n", 7) == -1) {
+		sr_err("Unable to send identification string: %s.",
+		       strerror(errno));
+		return NULL;
+	}
+
+	len = 128;
+	if (!(buf = g_try_malloc(len))) {
+		sr_err("Serial buffer malloc failed.");
+		return NULL;
+	}
+	serial_readline(serial, &buf, &len, 150);
+	if (!len)
+		return NULL;
+
+	tokens = g_strsplit(buf, ",", 4);
+	if (!strcmp("Agilent Technologies", tokens[0])
+			&& tokens[1] && tokens[2] && tokens[3]) {
+		for (i = 0; supported_agdmm[i].model; i++) {
+			if (strcmp(supported_agdmm[i].modelname, tokens[1]))
+				continue;
+			if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "Agilent",
+					tokens[1], tokens[3])))
+				return NULL;
+			if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+				sr_err("Device context malloc failed.");
+				return NULL;
+			}
+			devc->profile = &supported_agdmm[i];
+			devc->cur_mq = -1;
+			sdi->inst_type = SR_INST_SERIAL;
+			sdi->conn = serial;
+			sdi->priv = devc;
+			sdi->driver = di;
+			if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
+				return NULL;
+			sdi->channels = g_slist_append(sdi->channels, ch);
+			drvc->instances = g_slist_append(drvc->instances, sdi);
+			devices = g_slist_append(devices, sdi);
+			break;
+		}
+	}
+	g_strfreev(tokens);
+	g_free(buf);
+
+	serial_close(serial);
+	if (!devices)
+		sr_serial_dev_inst_free(serial);
+
+	return devices;
+}
+
+static GSList *dev_list(void)
+{
+	return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int cleanup(void)
+{
+	return std_dev_clear(di, NULL);
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+
+	(void)cg;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!(devc = sdi->priv)) {
+		sr_err("sdi->priv was NULL.");
+		return SR_ERR_BUG;
+	}
+
+	switch (id) {
+	case SR_CONF_LIMIT_MSEC:
+		/* TODO: not yet implemented */
+		if (g_variant_get_uint64(data) == 0) {
+			sr_err("LIMIT_MSEC can't be 0.");
+			return SR_ERR;
+		}
+		devc->limit_msec = g_variant_get_uint64(data);
+		sr_dbg("Setting time limit to %" PRIu64 "ms.",
+		       devc->limit_msec);
+		break;
+	case SR_CONF_LIMIT_SAMPLES:
+		devc->limit_samples = g_variant_get_uint64(data);
+		sr_dbg("Setting sample limit to %" PRIu64 ".",
+		       devc->limit_samples);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	(void)sdi;
+	(void)cg;
+
+	switch (key) {
+	case SR_CONF_SCAN_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+		break;
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!(devc = sdi->priv)) {
+		sr_err("sdi->priv was NULL.");
+		return SR_ERR_BUG;
+	}
+
+	devc->cb_data = cb_data;
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	/* Poll every 100ms, or whenever some data comes in. */
+	serial = sdi->conn;
+	serial_source_add(serial, G_IO_IN, 100, agdmm_receive_data, (void *)sdi);
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close,
+			sdi->conn, LOG_PREFIX);
+}
+
+SR_PRIV struct sr_dev_driver agdmm_driver_info = {
+	.name = "agilent-dmm",
+	.longname = "Agilent U12xx series DMMs",
+	.api_version = 1,
+	.init = init,
+	.cleanup = cleanup,
+	.scan = scan,
+	.dev_list = dev_list,
+	.dev_clear = NULL,
+	.config_get = NULL,
+	.config_set = config_set,
+	.config_list = config_list,
+	.dev_open = std_serial_dev_open,
+	.dev_close = std_serial_dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/agilent-dmm/sched.c b/hardware/agilent-dmm/sched.c
new file mode 100644
index 0000000..bd9cb38
--- /dev/null
+++ b/hardware/agilent-dmm/sched.c
@@ -0,0 +1,474 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "agilent-dmm.h"
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+
+static void dispatch(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	const struct agdmm_job *jobs;
+	int64_t now;
+	int i;
+
+	devc = sdi->priv;
+	jobs = devc->profile->jobs;
+	now = g_get_monotonic_time() / 1000;
+	for (i = 0; (&jobs[i])->interval; i++) {
+		if (now - devc->jobqueue[i] > (&jobs[i])->interval) {
+			sr_spew("Running job %d.", i);
+			(&jobs[i])->send(sdi);
+			devc->jobqueue[i] = now;
+		}
+	}
+}
+
+static void receive_line(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	const struct agdmm_recv *recvs, *recv;
+	GRegex *reg;
+	GMatchInfo *match;
+	int i;
+
+	devc = sdi->priv;
+
+	/* Strip CRLF */
+	while (devc->buflen) {
+		if (*(devc->buf + devc->buflen - 1) == '\r'
+				|| *(devc->buf + devc->buflen - 1) == '\n')
+			*(devc->buf + --devc->buflen) = '\0';
+		else
+			break;
+	}
+	sr_spew("Received '%s'.", devc->buf);
+
+	recv = NULL;
+	recvs = devc->profile->recvs;
+	for (i = 0; (&recvs[i])->recv_regex; i++) {
+		reg = g_regex_new((&recvs[i])->recv_regex, 0, 0, NULL);
+		if (g_regex_match(reg, (char *)devc->buf, 0, &match)) {
+			recv = &recvs[i];
+			break;
+		}
+		g_match_info_unref(match);
+		g_regex_unref(reg);
+	}
+	if (recv) {
+		recv->recv(sdi, match);
+		g_match_info_unref(match);
+		g_regex_unref(reg);
+	} else
+		sr_dbg("Unknown line '%s'.", devc->buf);
+
+	/* Done with this. */
+	devc->buflen = 0;
+}
+
+SR_PRIV int agdmm_receive_data(int fd, int revents, void *cb_data)
+{
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+	int len;
+
+	(void)fd;
+
+	if (!(sdi = cb_data))
+		return TRUE;
+
+	if (!(devc = sdi->priv))
+		return TRUE;
+
+	serial = sdi->conn;
+	if (revents == G_IO_IN) {
+		/* Serial data arrived. */
+		while(AGDMM_BUFSIZE - devc->buflen - 1 > 0) {
+			len = serial_read(serial, devc->buf + devc->buflen, 1);
+			if (len < 1)
+				break;
+			devc->buflen += len;
+			*(devc->buf + devc->buflen) = '\0';
+			if (*(devc->buf + devc->buflen - 1) == '\n') {
+				/* End of line */
+				receive_line(sdi);
+				break;
+			}
+		}
+	}
+
+	dispatch(sdi);
+
+	if (devc->limit_samples && devc->num_samples >= devc->limit_samples)
+		sdi->driver->dev_acquisition_stop(sdi, cb_data);
+
+	return TRUE;
+}
+
+static int agdmm_send(const struct sr_dev_inst *sdi, const char *cmd)
+{
+	struct sr_serial_dev_inst *serial;
+	char buf[32];
+
+	serial = sdi->conn;
+
+	sr_spew("Sending '%s'.", cmd);
+	strncpy(buf, cmd, 28);
+	if (!strncmp(buf, "*IDN?", 5))
+		strncat(buf, "\r\n", 32);
+	else
+		strncat(buf, "\n\r\n", 32);
+	if (serial_write(serial, buf, strlen(buf)) == -1) {
+		sr_err("Failed to send: %s.", strerror(errno));
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+static int send_stat(const struct sr_dev_inst *sdi)
+{
+	return agdmm_send(sdi, "STAT?");
+}
+
+static int recv_stat_u123x(const struct sr_dev_inst *sdi, GMatchInfo *match)
+{
+	struct dev_context *devc;
+	char *s;
+
+	devc = sdi->priv;
+	s = g_match_info_fetch(match, 1);
+	sr_spew("STAT response '%s'.", s);
+
+	/* Max, Min or Avg mode -- no way to tell which, so we'll
+	 * set both flags to denote it's not a normal measurement. */
+	if (s[0] == '1')
+		devc->cur_mqflags |= SR_MQFLAG_MAX | SR_MQFLAG_MIN;
+	else
+		devc->cur_mqflags &= ~(SR_MQFLAG_MAX | SR_MQFLAG_MIN);
+
+	if (s[1] == '1')
+		devc->cur_mqflags |= SR_MQFLAG_RELATIVE;
+	else
+		devc->cur_mqflags &= ~SR_MQFLAG_RELATIVE;
+
+	/* Triggered or auto hold modes. */
+	if (s[2] == '1' || s[3] == '1')
+		devc->cur_mqflags |= SR_MQFLAG_HOLD;
+	else
+		devc->cur_mqflags &= ~SR_MQFLAG_HOLD;
+
+	/* Temp/aux mode. */
+	if (s[7] == '1')
+		devc->mode_tempaux = TRUE;
+	else
+		devc->mode_tempaux = FALSE;
+
+	/* Continuity mode. */
+	if (s[16] == '1')
+		devc->mode_continuity = TRUE;
+	else
+		devc->mode_continuity = FALSE;
+
+	g_free(s);
+
+	return SR_OK;
+}
+
+static int recv_stat_u125x(const struct sr_dev_inst *sdi, GMatchInfo *match)
+{
+	struct dev_context *devc;
+	char *s;
+
+	devc = sdi->priv;
+	s = g_match_info_fetch(match, 1);
+	sr_spew("STAT response '%s'.", s);
+
+	/* Peak hold mode. */
+	if (s[4] == '1')
+		devc->cur_mqflags |= SR_MQFLAG_MAX;
+	else
+		devc->cur_mqflags &= ~SR_MQFLAG_MAX;
+
+	/* Triggered hold mode. */
+	if (s[7] == '1')
+		devc->cur_mqflags |= SR_MQFLAG_HOLD;
+	else
+		devc->cur_mqflags &= ~SR_MQFLAG_HOLD;
+
+	g_free(s);
+
+	return SR_OK;
+}
+
+static int send_fetc(const struct sr_dev_inst *sdi)
+{
+	return agdmm_send(sdi, "FETC?");
+}
+
+static int recv_fetc(const struct sr_dev_inst *sdi, GMatchInfo *match)
+{
+	struct dev_context *devc;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_analog analog;
+	float fvalue;
+	char *mstr;
+
+	sr_spew("FETC reply '%s'.", g_match_info_get_string(match));
+	devc = sdi->priv;
+
+	if (devc->cur_mq == -1)
+		/* Haven't seen configuration yet, so can't know what
+		 * the fetched float means. Not really an error, we'll
+		 * get metadata soon enough. */
+		return SR_OK;
+
+	if (!strcmp(g_match_info_get_string(match), "+9.90000000E+37")) {
+		/* An invalid measurement shows up on the display as "O.L", but
+		 * comes through like this. Since comparing 38-digit floats
+		 * is rather problematic, we'll cut through this here. */
+		fvalue = NAN;
+	} else {
+		mstr = g_match_info_fetch(match, 1);
+		if (sr_atof_ascii(mstr, &fvalue) != SR_OK || fvalue == 0.0) {
+			g_free(mstr);
+			sr_err("Invalid float.");
+			return SR_ERR;
+		}
+		g_free(mstr);
+		if (devc->cur_divider > 0)
+			fvalue /= devc->cur_divider;
+	}
+
+	memset(&analog, 0, sizeof(struct sr_datafeed_analog));
+	analog.mq = devc->cur_mq;
+	analog.unit = devc->cur_unit;
+	analog.mqflags = devc->cur_mqflags;
+	analog.channels = sdi->channels;
+	analog.num_samples = 1;
+	analog.data = &fvalue;
+	packet.type = SR_DF_ANALOG;
+	packet.payload = &analog;
+	sr_session_send(devc->cb_data, &packet);
+
+	devc->num_samples++;
+
+	return SR_OK;
+}
+
+static int send_conf(const struct sr_dev_inst *sdi)
+{
+	return agdmm_send(sdi, "CONF?");
+}
+
+static int recv_conf_u123x(const struct sr_dev_inst *sdi, GMatchInfo *match)
+{
+	struct dev_context *devc;
+	char *mstr;
+
+	sr_spew("CONF? response '%s'.", g_match_info_get_string(match));
+	devc = sdi->priv;
+	mstr = g_match_info_fetch(match, 1);
+	if (!strcmp(mstr, "V")) {
+		devc->cur_mq = SR_MQ_VOLTAGE;
+		devc->cur_unit = SR_UNIT_VOLT;
+		devc->cur_mqflags = 0;
+		devc->cur_divider = 0;
+	} else if(!strcmp(mstr, "MV")) {
+		if (devc->mode_tempaux) {
+			devc->cur_mq = SR_MQ_TEMPERATURE;
+			/* No way to detect whether Fahrenheit or Celcius
+			 * is used, so we'll just default to Celcius. */
+			devc->cur_unit = SR_UNIT_CELSIUS;
+		devc->cur_mqflags = 0;
+		devc->cur_divider = 0;
+		} else {
+			devc->cur_mq = SR_MQ_VOLTAGE;
+			devc->cur_unit = SR_UNIT_VOLT;
+			devc->cur_mqflags = 0;
+			devc->cur_divider = 1000;
+		}
+	} else if(!strcmp(mstr, "A")) {
+		devc->cur_mq = SR_MQ_CURRENT;
+		devc->cur_unit = SR_UNIT_AMPERE;
+		devc->cur_mqflags = 0;
+		devc->cur_divider = 0;
+	} else if(!strcmp(mstr, "UA")) {
+		devc->cur_mq = SR_MQ_CURRENT;
+		devc->cur_unit = SR_UNIT_AMPERE;
+		devc->cur_mqflags = 0;
+		devc->cur_divider = 1000000;
+	} else if(!strcmp(mstr, "FREQ")) {
+		devc->cur_mq = SR_MQ_FREQUENCY;
+		devc->cur_unit = SR_UNIT_HERTZ;
+		devc->cur_mqflags = 0;
+		devc->cur_divider = 0;
+	} else if(!strcmp(mstr, "RES")) {
+		if (devc->mode_continuity) {
+			devc->cur_mq = SR_MQ_CONTINUITY;
+			devc->cur_unit = SR_UNIT_BOOLEAN;
+		} else {
+			devc->cur_mq = SR_MQ_RESISTANCE;
+			devc->cur_unit = SR_UNIT_OHM;
+		}
+		devc->cur_mqflags = 0;
+		devc->cur_divider = 0;
+	} else if(!strcmp(mstr, "CAP")) {
+		devc->cur_mq = SR_MQ_CAPACITANCE;
+		devc->cur_unit = SR_UNIT_FARAD;
+		devc->cur_mqflags = 0;
+		devc->cur_divider = 0;
+	} else
+		sr_dbg("Unknown first argument.");
+	g_free(mstr);
+
+	if (g_match_info_get_match_count(match) == 4) {
+		mstr = g_match_info_fetch(match, 3);
+		/* Third value, if present, is always AC or DC. */
+		if (!strcmp(mstr, "AC"))
+			devc->cur_mqflags |= SR_MQFLAG_AC;
+		else if (!strcmp(mstr, "DC"))
+			devc->cur_mqflags |= SR_MQFLAG_DC;
+		else
+			sr_dbg("Unknown third argument.");
+		g_free(mstr);
+	} else
+		devc->cur_mqflags &= ~(SR_MQFLAG_AC | SR_MQFLAG_DC);
+
+	return SR_OK;
+}
+
+static int recv_conf_u125x(const struct sr_dev_inst *sdi, GMatchInfo *match)
+{
+	struct dev_context *devc;
+	char *mstr;
+
+	sr_spew("CONF? response '%s'.", g_match_info_get_string(match));
+	devc = sdi->priv;
+	mstr = g_match_info_fetch(match, 1);
+	if (!strncmp(mstr, "VOLT", 4)) {
+		devc->cur_mq = SR_MQ_VOLTAGE;
+		devc->cur_unit = SR_UNIT_VOLT;
+		devc->cur_mqflags = 0;
+		devc->cur_divider = 0;
+		if (mstr[4] == ':') {
+			if (!strcmp(mstr + 4, "AC"))
+				devc->cur_mqflags |= SR_MQFLAG_AC;
+			else if (!strcmp(mstr + 4, "DC"))
+				devc->cur_mqflags |= SR_MQFLAG_DC;
+			else
+				/* "ACDC" appears as well, no idea what it means. */
+				devc->cur_mqflags &= ~(SR_MQFLAG_AC | SR_MQFLAG_DC);
+		} else
+			devc->cur_mqflags &= ~(SR_MQFLAG_AC | SR_MQFLAG_DC);
+	} else if(!strcmp(mstr, "CURR")) {
+		devc->cur_mq = SR_MQ_CURRENT;
+		devc->cur_unit = SR_UNIT_AMPERE;
+		devc->cur_mqflags = 0;
+		devc->cur_divider = 0;
+	} else if(!strcmp(mstr, "RES")) {
+		if (devc->mode_continuity) {
+			devc->cur_mq = SR_MQ_CONTINUITY;
+			devc->cur_unit = SR_UNIT_BOOLEAN;
+		} else {
+			devc->cur_mq = SR_MQ_RESISTANCE;
+			devc->cur_unit = SR_UNIT_OHM;
+		}
+		devc->cur_mqflags = 0;
+		devc->cur_divider = 0;
+	} else
+		sr_dbg("Unknown first argument.");
+	g_free(mstr);
+
+	return SR_OK;
+}
+
+/* At least the 123x and 125x appear to have this. */
+static int recv_conf(const struct sr_dev_inst *sdi, GMatchInfo *match)
+{
+	struct dev_context *devc;
+	char *mstr;
+
+	sr_spew("CONF? response '%s'.", g_match_info_get_string(match));
+	devc = sdi->priv;
+	mstr = g_match_info_fetch(match, 1);
+	if(!strcmp(mstr, "DIOD")) {
+		devc->cur_mq = SR_MQ_VOLTAGE;
+		devc->cur_unit = SR_UNIT_VOLT;
+		devc->cur_mqflags = SR_MQFLAG_DIODE;
+		devc->cur_divider = 0;
+	} else
+		sr_dbg("Unknown single argument.");
+	g_free(mstr);
+
+	return SR_OK;
+}
+
+/* This comes in whenever the rotary switch is changed to a new position.
+ * We could use it to determine the major measurement mode, but we already
+ * have the output of CONF? for that, which is more detailed. However
+ * we do need to catch this here, or it'll show up in some other output. */
+static int recv_switch(const struct sr_dev_inst *sdi, GMatchInfo *match)
+{
+	(void)sdi;
+
+	sr_spew("Switch '%s'.", g_match_info_get_string(match));
+
+	return SR_OK;
+}
+
+SR_PRIV const struct agdmm_job agdmm_jobs_u123x[] = {
+	{ 143, send_stat },
+	{ 1000, send_conf },
+	{ 143, send_fetc },
+	{ 0, NULL }
+};
+
+SR_PRIV const struct agdmm_recv agdmm_recvs_u123x[] = {
+	{ "^\"(\\d\\d.{18}\\d)\"$", recv_stat_u123x },
+	{ "^\\*([0-9])$", recv_switch },
+	{ "^([-+][0-9]\\.[0-9]{8}E[-+][0-9]{2})$", recv_fetc },
+	{ "^\"(V|MV|A|UA|FREQ),(\\d),(AC|DC)\"$", recv_conf_u123x },
+	{ "^\"(RES|CAP),(\\d)\"$", recv_conf_u123x},
+	{ "^\"(DIOD)\"$", recv_conf },
+	{ NULL, NULL }
+};
+
+SR_PRIV const struct agdmm_job agdmm_jobs_u125x[] = {
+	{ 143, send_stat },
+	{ 1000, send_conf },
+	{ 143, send_fetc },
+	{ 0, NULL }
+};
+
+SR_PRIV const struct agdmm_recv agdmm_recvs_u125x[] = {
+	{ "^\"(\\d\\d.{18}\\d)\"$", recv_stat_u125x },
+	{ "^\\*([0-9])$", recv_switch },
+	{ "^([-+][0-9]\\.[0-9]{8}E[-+][0-9]{2})$", recv_fetc },
+	{ "^(VOLT|CURR|RES|CAP) ([-+][0-9\\.E\\-+]+),([-+][0-9\\.E\\-+]+)$", recv_conf_u125x },
+	{ "^(VOLT:[ACD]+) ([-+][0-9\\.E\\-+]+),([-+][0-9\\.E\\-+]+)$", recv_conf_u125x },
+	{ "^\"(DIOD)\"$", recv_conf },
+	{ NULL, NULL }
+};
diff --git a/hardware/appa-55ii/api.c b/hardware/appa-55ii/api.c
new file mode 100644
index 0000000..38c23b7
--- /dev/null
+++ b/hardware/appa-55ii/api.c
@@ -0,0 +1,290 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Aurelien Jacobs <aurel at gnuage.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include "protocol.h"
+
+static const int32_t hwopts[] = {
+	SR_CONF_CONN,
+	SR_CONF_SERIALCOMM,
+};
+
+static const int32_t hwcaps[] = {
+	SR_CONF_THERMOMETER,
+	SR_CONF_LIMIT_SAMPLES,
+	SR_CONF_LIMIT_MSEC,
+	SR_CONF_CONTINUOUS,
+	SR_CONF_DATA_SOURCE,
+};
+
+static const char *data_sources[] = {
+	"Live",
+	"Memory",
+};
+
+SR_PRIV struct sr_dev_driver appa_55ii_driver_info;
+static struct sr_dev_driver *di = &appa_55ii_driver_info;
+
+static int init(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+	struct sr_dev_inst *sdi;
+	struct sr_channel *ch;
+	struct sr_config *src;
+	GSList *devices, *l;
+	const char *conn, *serialcomm;
+	uint8_t buf[50];
+	size_t len;
+
+	len = sizeof(buf);
+	devices = NULL;
+	conn = serialcomm = NULL;
+	for (l = options; l; l = l->next) {
+		src = l->data;
+		switch (src->key) {
+		case SR_CONF_CONN:
+			conn = g_variant_get_string(src->data, NULL);
+			break;
+		case SR_CONF_SERIALCOMM:
+			serialcomm = g_variant_get_string(src->data, NULL);
+			break;
+		}
+	}
+	if (!conn)
+		return NULL;
+	if (!serialcomm)
+		serialcomm = "9600/8n1";
+
+	if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+		return NULL;
+	if (serial_open(serial, SERIAL_RDONLY | SERIAL_NONBLOCK) != SR_OK)
+		return NULL;
+
+	sr_info("Probing serial port %s.", conn);
+
+	drvc = di->priv;
+	drvc->instances = NULL;
+	serial_flush(serial);
+
+	/* Let's get a bit of data and see if we can find a packet. */
+	if (serial_stream_detect(serial, buf, &len, 25,
+			appa_55ii_packet_valid, 500, 9600) != SR_OK)
+		goto scan_cleanup;
+
+	sr_info("Found device on port %s.", conn);
+
+	if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "APPA", "55II", NULL)))
+		goto scan_cleanup;
+
+	if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+		sr_err("Device context malloc failed.");
+		goto scan_cleanup;
+	}
+
+	devc->data_source = DEFAULT_DATA_SOURCE;
+
+	sdi->inst_type = SR_INST_SERIAL;
+	sdi->conn = serial;
+	sdi->priv = devc;
+	sdi->driver = di;
+
+	if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "T1")))
+		goto scan_cleanup;
+	sdi->channels = g_slist_append(sdi->channels, ch);
+	if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "T2")))
+		goto scan_cleanup;
+	sdi->channels = g_slist_append(sdi->channels, ch);
+
+	drvc->instances = g_slist_append(drvc->instances, sdi);
+	devices = g_slist_append(devices, sdi);
+
+scan_cleanup:
+	serial_close(serial);
+
+	return devices;
+}
+
+static GSList *dev_list(void)
+{
+	return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int cleanup(void)
+{
+	return std_dev_clear(di, NULL);
+}
+
+static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc = sdi->priv;
+
+	(void)cg;
+
+	switch (key) {
+	case SR_CONF_LIMIT_SAMPLES:
+		*data = g_variant_new_uint64(devc->limit_samples);
+		break;
+	case SR_CONF_LIMIT_MSEC:
+		*data = g_variant_new_uint64(devc->limit_msec);
+		break;
+	case SR_CONF_DATA_SOURCE:
+		*data = g_variant_new_string(data_sources[devc->data_source]);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	const char *tmp_str;
+	unsigned int i;
+
+	(void)cg;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!(devc = sdi->priv)) {
+		sr_err("sdi->priv was NULL.");
+		return SR_ERR_BUG;
+	}
+
+	switch (key) {
+	case SR_CONF_LIMIT_SAMPLES:
+		devc->limit_samples = g_variant_get_uint64(data);
+		sr_dbg("Setting sample limit to %" PRIu64 ".", devc->limit_samples);
+		break;
+	case SR_CONF_LIMIT_MSEC:
+		devc->limit_msec = g_variant_get_uint64(data);
+		sr_dbg("Setting time limit to %" PRIu64 "ms.", devc->limit_msec);
+		break;
+	case SR_CONF_DATA_SOURCE: {
+		tmp_str = g_variant_get_string(data, NULL);
+		for (i = 0; i < ARRAY_SIZE(data_sources); i++)
+			if (!strcmp(tmp_str, data_sources[i])) {
+				devc->data_source = i;
+				break;
+			}
+		if (i == ARRAY_SIZE(data_sources))
+			return SR_ERR;
+		break;
+	}
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	(void)sdi;
+	(void)cg;
+
+	switch (key) {
+	case SR_CONF_SCAN_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+		break;
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+		break;
+	case SR_CONF_DATA_SOURCE:
+		*data = g_variant_new_strv(data_sources, ARRAY_SIZE(data_sources));
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi,
+		void *cb_data)
+{
+	struct sr_serial_dev_inst *serial;
+	struct dev_context *devc;
+
+	serial = sdi->conn;
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!(devc = sdi->priv)) {
+		sr_err("sdi->priv was NULL.");
+		return SR_ERR_BUG;
+	}
+
+	devc->session_cb_data = cb_data;
+
+	/*
+	 * Reset the number of samples to take. If we've already collected our
+	 * quota, but we start a new session, and don't reset this, we'll just
+	 * quit without acquiring any new samples.
+	 */
+	devc->num_samples = 0;
+	devc->start_time = g_get_monotonic_time();
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	/* Poll every 50ms, or whenever some data comes in. */
+	serial_source_add(serial, G_IO_IN, 50, appa_55ii_receive_data, (void *)sdi);
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	return std_serial_dev_acquisition_stop(sdi, cb_data,
+			std_serial_dev_close, sdi->conn, LOG_PREFIX);
+}
+
+SR_PRIV struct sr_dev_driver appa_55ii_driver_info = {
+	.name = "appa-55ii",
+	.longname = "APPA 55II",
+	.api_version = 1,
+	.init = init,
+	.cleanup = cleanup,
+	.scan = scan,
+	.dev_list = dev_list,
+	.dev_clear = NULL,
+	.config_get = config_get,
+	.config_set = config_set,
+	.config_list = config_list,
+	.dev_open = std_serial_dev_open,
+	.dev_close = std_serial_dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/appa-55ii/protocol.c b/hardware/appa-55ii/protocol.c
new file mode 100644
index 0000000..708262b
--- /dev/null
+++ b/hardware/appa-55ii/protocol.c
@@ -0,0 +1,320 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Aurelien Jacobs <aurel at gnuage.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <math.h>
+#include "protocol.h"
+
+typedef enum {
+    LIVE_DATA    = 0x00,
+    LOG_METADATA = 0x11,
+    LOG_DATA     = 0x14,
+    LOG_START    = 0x18,
+    LOG_END      = 0x19,
+} packet_type;
+
+static gboolean appa_55ii_checksum(const uint8_t *buf)
+{
+	int i, size, checksum;
+
+	size = buf[3] + 4;
+	checksum = 0;
+	for (i = 0; i < size; i++)
+		checksum += buf[i];
+
+	return buf[size] == (checksum & 0xFF);
+}
+
+SR_PRIV gboolean appa_55ii_packet_valid(const uint8_t *buf)
+{
+	if (buf[0] == 0x55 && buf[1] == 0x55 && buf[3] <= 32
+			&& appa_55ii_checksum(buf))
+		return TRUE;
+
+	return FALSE;
+}
+
+static uint64_t appa_55ii_flags(const uint8_t *buf)
+{
+	uint8_t disp_mode;
+	uint64_t flags;
+
+	disp_mode = buf[4 + 13];
+	flags = 0;
+	if ((disp_mode & 0xF0) == 0x20)
+		flags |= SR_MQFLAG_HOLD;
+	if ((disp_mode & 0x0C) == 0x04)
+		flags |= SR_MQFLAG_MAX;
+	if ((disp_mode & 0x0C) == 0x08)
+		flags |= SR_MQFLAG_MIN;
+	if ((disp_mode & 0x0C) == 0x0C)
+		flags |= SR_MQFLAG_AVG;
+
+	return flags;
+}
+
+static float appa_55ii_temp(const uint8_t *buf, int ch)
+{
+	const uint8_t *ptr;
+	int16_t temp;
+	uint8_t flags;
+
+	ptr = buf + 4 + 14 + 3 * ch;
+	temp = RL16(ptr);
+	flags = ptr[2];
+
+	if (flags & 0x60)
+		return INFINITY;
+	else if (flags & 1)
+		return (float)temp / 10;
+	else
+		return (float)temp;
+}
+
+static void appa_55ii_live_data(struct sr_dev_inst *sdi, const uint8_t *buf)
+{
+	struct dev_context *devc;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_analog analog;
+	struct sr_channel *ch;
+	float values[APPA_55II_NUM_CHANNELS], *val_ptr;
+	int i;
+
+	devc = sdi->priv;
+
+	if (devc->data_source != DATA_SOURCE_LIVE)
+		return;
+
+	val_ptr = values;
+	memset(&analog, 0, sizeof(analog));
+	analog.num_samples = 1;
+	analog.mq = SR_MQ_TEMPERATURE;
+	analog.unit = SR_UNIT_CELSIUS;
+	analog.mqflags = appa_55ii_flags(buf);
+	analog.data = values;
+
+	for (i = 0; i < APPA_55II_NUM_CHANNELS; i++) {
+		ch = g_slist_nth_data(sdi->channels, i);
+		if (!ch->enabled)
+			continue;
+		analog.channels = g_slist_append(analog.channels, ch);
+		*val_ptr++ = appa_55ii_temp(buf, i);
+	}
+
+	packet.type = SR_DF_ANALOG;
+	packet.payload = &analog;
+	sr_session_send(devc->session_cb_data, &packet);
+	g_slist_free(analog.channels);
+
+	devc->num_samples++;
+}
+
+static void appa_55ii_log_metadata(struct sr_dev_inst *sdi, const uint8_t *buf)
+{
+	struct dev_context *devc;
+
+	devc = sdi->priv;
+	devc->num_log_records = (buf[5] << 8) + buf[4];
+}
+
+static void appa_55ii_log_data_parse(struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_analog analog;
+	struct sr_channel *ch;
+	float values[APPA_55II_NUM_CHANNELS], *val_ptr;
+	const uint8_t *buf;
+	int16_t temp;
+	int offset, i;
+
+	devc = sdi->priv;
+	offset = 0;
+
+	while (devc->log_buf_len >= 20 && devc->num_log_records > 0) {
+		buf = devc->log_buf + offset;
+		val_ptr = values;
+
+		/* FIXME: Timestamp should be sent in the packet. */
+		sr_dbg("Timestamp: %02d:%02d:%02d", buf[2], buf[3], buf[4]);
+
+		memset(&analog, 0, sizeof(analog));
+		analog.num_samples = 1;
+		analog.mq = SR_MQ_TEMPERATURE;
+		analog.unit = SR_UNIT_CELSIUS;
+		analog.data = values;
+
+		for (i = 0; i < APPA_55II_NUM_CHANNELS; i++) {
+			temp = RL16(buf + 12 + 2 * i);
+			ch = g_slist_nth_data(sdi->channels, i);
+			if (!ch->enabled)
+				continue;
+			analog.channels = g_slist_append(analog.channels, ch);
+			*val_ptr++ = temp == 0x7FFF ? INFINITY : (float)temp / 10;
+		}
+
+		packet.type = SR_DF_ANALOG;
+		packet.payload = &analog;
+		sr_session_send(devc->session_cb_data, &packet);
+		g_slist_free(analog.channels);
+
+		devc->num_samples++;
+		devc->log_buf_len -= 20;
+		offset += 20;
+		devc->num_log_records--;
+	}
+
+	memmove(devc->log_buf, devc->log_buf + offset, devc->log_buf_len);
+}
+
+static void appa_55ii_log_data(struct sr_dev_inst *sdi, const uint8_t *buf)
+{
+	struct dev_context *devc;
+	const uint8_t *ptr;
+	unsigned int size;
+	int s;
+
+	devc = sdi->priv;
+	if (devc->data_source != DATA_SOURCE_MEMORY)
+		return;
+
+	ptr = buf + 4;
+	size = buf[3];
+	while (size > 0) {
+		s = MIN(size, sizeof(devc->log_buf) - devc->log_buf_len);
+		memcpy(devc->log_buf + devc->log_buf_len, ptr, s);
+		devc->log_buf_len += s;
+		size -= s;
+		ptr += s;
+
+		appa_55ii_log_data_parse(sdi);
+	}
+}
+
+static void appa_55ii_log_end(struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+
+	devc = sdi->priv;
+	if (devc->data_source != DATA_SOURCE_MEMORY)
+		return;
+
+	sdi->driver->dev_acquisition_stop(sdi, devc->session_cb_data);
+}
+
+static const uint8_t *appa_55ii_parse_data(struct sr_dev_inst *sdi,
+		const uint8_t *buf, int len)
+{
+	if (len < 5)
+		/* Need more data. */
+		return NULL;
+
+	if (buf[0] != 0x55 || buf[1] != 0x55)
+		/* Try to re-synchronize on a packet start. */
+		return buf + 1;
+
+	if (len < 5 + buf[3])
+		/* Need more data. */
+		return NULL;
+
+	if (!appa_55ii_checksum(buf))
+		/* Skip broken packet. */
+		return buf + 4 + buf[3] + 1;
+
+	switch ((packet_type)buf[2]) {
+	case LIVE_DATA:
+		appa_55ii_live_data(sdi, buf);
+		break;
+	case LOG_METADATA:
+		appa_55ii_log_metadata(sdi, buf);
+		break;
+	case LOG_DATA:
+		appa_55ii_log_data(sdi, buf);
+		break;
+	case LOG_START:
+		break;
+	case LOG_END:
+		appa_55ii_log_end(sdi);
+		break;
+	default:
+		sr_warn("Invalid packet type: 0x%02x.", buf[2]);
+		break;
+	}
+
+	return buf + 4 + buf[3] + 1;
+}
+
+SR_PRIV int appa_55ii_receive_data(int fd, int revents, void *cb_data)
+{
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+	int64_t time;
+	const uint8_t *ptr, *next_ptr, *end_ptr;
+	int len;
+
+	(void)fd;
+
+	if (!(sdi = cb_data) || !(devc = sdi->priv) || revents != G_IO_IN)
+		return TRUE;
+	serial = sdi->conn;
+
+	/* Try to get as much data as the buffer can hold. */
+	len = sizeof(devc->buf) - devc->buf_len;
+	len = serial_read(serial, devc->buf + devc->buf_len, len);
+	if (len < 1) {
+		sr_err("Serial port read error: %d.", len);
+		return FALSE;
+	}
+	devc->buf_len += len;
+
+	/* Now look for packets in that data. */
+	ptr = devc->buf;
+	end_ptr = ptr + devc->buf_len;
+	while ((next_ptr = appa_55ii_parse_data(sdi, ptr, end_ptr - ptr)))
+		ptr = next_ptr;
+
+	/* If we have any data left, move it to the beginning of our buffer. */
+	memmove(devc->buf, ptr, end_ptr - ptr);
+	devc->buf_len -= ptr - devc->buf;
+
+	/* If buffer is full and no valid packet was found, wipe buffer. */
+	if (devc->buf_len >= sizeof(devc->buf)) {
+		devc->buf_len = 0;
+		return FALSE;
+	}
+
+	if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
+		sr_info("Requested number of samples reached.");
+		sdi->driver->dev_acquisition_stop(sdi, devc->session_cb_data);
+		return TRUE;
+	}
+
+	if (devc->limit_msec) {
+		time = (g_get_monotonic_time() - devc->start_time) / 1000;
+		if (time > (int64_t)devc->limit_msec) {
+			sr_info("Requested time limit reached.");
+			sdi->driver->dev_acquisition_stop(sdi,
+					devc->session_cb_data);
+			return TRUE;
+		}
+	}
+
+	return TRUE;
+}
diff --git a/hardware/appa-55ii/protocol.h b/hardware/appa-55ii/protocol.h
new file mode 100644
index 0000000..fa3c247
--- /dev/null
+++ b/hardware/appa-55ii/protocol.h
@@ -0,0 +1,62 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Aurelien Jacobs <aurel at gnuage.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_APPA_55II_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_APPA_55II_PROTOCOL_H
+
+#include <stdint.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "appa-55ii"
+
+#define APPA_55II_NUM_CHANNELS  2
+#define APPA_55II_BUF_SIZE    (4 + 32 + 1)
+#define DEFAULT_DATA_SOURCE   DATA_SOURCE_LIVE
+
+enum {
+	DATA_SOURCE_LIVE,
+	DATA_SOURCE_MEMORY,
+};
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+	/* Acquisition settings */
+	uint64_t limit_samples;   /**< The sampling limit (in number of samples). */
+	uint64_t limit_msec;      /**< The time limit (in milliseconds). */
+	gboolean data_source;     /**< Whether to read live samples or memory */
+	void *session_cb_data;    /**< Opaque pointer passed in by the frontend. */
+
+	/* Operational state */
+	uint64_t num_samples;     /**< The number of already received samples. */
+	int64_t start_time;       /**< The time at which sampling started. */
+
+	/* Temporary state across callbacks */
+	uint8_t buf[APPA_55II_BUF_SIZE];
+	unsigned int buf_len;
+	uint8_t log_buf[64];
+	unsigned int log_buf_len;
+	unsigned int num_log_records;
+};
+
+SR_PRIV gboolean appa_55ii_packet_valid(const uint8_t *buf);
+SR_PRIV int appa_55ii_receive_data(int fd, int revents, void *cb_data);
+
+#endif
diff --git a/hardware/asix-sigma/asix-sigma.c b/hardware/asix-sigma/asix-sigma.c
new file mode 100644
index 0000000..df9a888
--- /dev/null
+++ b/hardware/asix-sigma/asix-sigma.c
@@ -0,0 +1,1540 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010-2012 Håvard Espeland <gus at ping.uio.no>,
+ * Copyright (C) 2010 Martin Stensgård <mastensg at ping.uio.no>
+ * Copyright (C) 2010 Carl Henrik Lunde <chlunde at ping.uio.no>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * ASIX SIGMA/SIGMA2 logic analyzer driver
+ */
+
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <ftdi.h>
+#include <string.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "asix-sigma.h"
+
+#define USB_VENDOR			0xa600
+#define USB_PRODUCT			0xa000
+#define USB_DESCRIPTION			"ASIX SIGMA"
+#define USB_VENDOR_NAME			"ASIX"
+#define USB_MODEL_NAME			"SIGMA"
+#define TRIGGER_TYPE 			"rf10"
+
+SR_PRIV struct sr_dev_driver asix_sigma_driver_info;
+static struct sr_dev_driver *di = &asix_sigma_driver_info;
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data);
+
+/*
+ * The ASIX Sigma supports arbitrary integer frequency divider in
+ * the 50MHz mode. The divider is in range 1...256 , allowing for
+ * very precise sampling rate selection. This driver supports only
+ * a subset of the sampling rates.
+ */
+static const uint64_t samplerates[] = {
+	SR_KHZ(200),	/* div=250 */
+	SR_KHZ(250),	/* div=200 */
+	SR_KHZ(500),	/* div=100 */
+	SR_MHZ(1),	/* div=50  */
+	SR_MHZ(5),	/* div=10  */
+	SR_MHZ(10),	/* div=5   */
+	SR_MHZ(25),	/* div=2   */
+	SR_MHZ(50),	/* div=1   */
+	SR_MHZ(100),	/* Special FW needed */
+	SR_MHZ(200),	/* Special FW needed */
+};
+
+/*
+ * Channel numbers seem to go from 1-16, according to this image:
+ * http://tools.asix.net/img/sigma_sigmacab_pins_720.jpg
+ * (the cable has two additional GND pins, and a TI and TO pin)
+ */
+static const char *channel_names[] = {
+	"1", "2", "3", "4", "5", "6", "7", "8",
+	"9", "10", "11", "12", "13", "14", "15", "16",
+};
+
+static const int32_t hwcaps[] = {
+	SR_CONF_LOGIC_ANALYZER,
+	SR_CONF_SAMPLERATE,
+	SR_CONF_TRIGGER_TYPE,
+	SR_CONF_CAPTURE_RATIO,
+	SR_CONF_LIMIT_MSEC,
+};
+
+static const char *sigma_firmware_files[] = {
+	/* 50 MHz, supports 8 bit fractions */
+	FIRMWARE_DIR "/asix-sigma-50.fw",
+	/* 100 MHz */
+	FIRMWARE_DIR "/asix-sigma-100.fw",
+	/* 200 MHz */
+	FIRMWARE_DIR "/asix-sigma-200.fw",
+	/* Synchronous clock from pin */
+	FIRMWARE_DIR "/asix-sigma-50sync.fw",
+	/* Frequency counter */
+	FIRMWARE_DIR "/asix-sigma-phasor.fw",
+};
+
+static int sigma_read(void *buf, size_t size, struct dev_context *devc)
+{
+	int ret;
+
+	ret = ftdi_read_data(&devc->ftdic, (unsigned char *)buf, size);
+	if (ret < 0) {
+		sr_err("ftdi_read_data failed: %s",
+		       ftdi_get_error_string(&devc->ftdic));
+	}
+
+	return ret;
+}
+
+static int sigma_write(void *buf, size_t size, struct dev_context *devc)
+{
+	int ret;
+
+	ret = ftdi_write_data(&devc->ftdic, (unsigned char *)buf, size);
+	if (ret < 0) {
+		sr_err("ftdi_write_data failed: %s",
+		       ftdi_get_error_string(&devc->ftdic));
+	} else if ((size_t) ret != size) {
+		sr_err("ftdi_write_data did not complete write.");
+	}
+
+	return ret;
+}
+
+static int sigma_write_register(uint8_t reg, uint8_t *data, size_t len,
+				struct dev_context *devc)
+{
+	size_t i;
+	uint8_t buf[len + 2];
+	int idx = 0;
+
+	buf[idx++] = REG_ADDR_LOW | (reg & 0xf);
+	buf[idx++] = REG_ADDR_HIGH | (reg >> 4);
+
+	for (i = 0; i < len; ++i) {
+		buf[idx++] = REG_DATA_LOW | (data[i] & 0xf);
+		buf[idx++] = REG_DATA_HIGH_WRITE | (data[i] >> 4);
+	}
+
+	return sigma_write(buf, idx, devc);
+}
+
+static int sigma_set_register(uint8_t reg, uint8_t value, struct dev_context *devc)
+{
+	return sigma_write_register(reg, &value, 1, devc);
+}
+
+static int sigma_read_register(uint8_t reg, uint8_t *data, size_t len,
+			       struct dev_context *devc)
+{
+	uint8_t buf[3];
+
+	buf[0] = REG_ADDR_LOW | (reg & 0xf);
+	buf[1] = REG_ADDR_HIGH | (reg >> 4);
+	buf[2] = REG_READ_ADDR;
+
+	sigma_write(buf, sizeof(buf), devc);
+
+	return sigma_read(data, len, devc);
+}
+
+static uint8_t sigma_get_register(uint8_t reg, struct dev_context *devc)
+{
+	uint8_t value;
+
+	if (1 != sigma_read_register(reg, &value, 1, devc)) {
+		sr_err("sigma_get_register: 1 byte expected");
+		return 0;
+	}
+
+	return value;
+}
+
+static int sigma_read_pos(uint32_t *stoppos, uint32_t *triggerpos,
+			  struct dev_context *devc)
+{
+	uint8_t buf[] = {
+		REG_ADDR_LOW | READ_TRIGGER_POS_LOW,
+
+		REG_READ_ADDR | NEXT_REG,
+		REG_READ_ADDR | NEXT_REG,
+		REG_READ_ADDR | NEXT_REG,
+		REG_READ_ADDR | NEXT_REG,
+		REG_READ_ADDR | NEXT_REG,
+		REG_READ_ADDR | NEXT_REG,
+	};
+	uint8_t result[6];
+
+	sigma_write(buf, sizeof(buf), devc);
+
+	sigma_read(result, sizeof(result), devc);
+
+	*triggerpos = result[0] | (result[1] << 8) | (result[2] << 16);
+	*stoppos = result[3] | (result[4] << 8) | (result[5] << 16);
+
+	/* Not really sure why this must be done, but according to spec. */
+	if ((--*stoppos & 0x1ff) == 0x1ff)
+		stoppos -= 64;
+
+	if ((*--triggerpos & 0x1ff) == 0x1ff)
+		triggerpos -= 64;
+
+	return 1;
+}
+
+static int sigma_read_dram(uint16_t startchunk, size_t numchunks,
+			   uint8_t *data, struct dev_context *devc)
+{
+	size_t i;
+	uint8_t buf[4096];
+	int idx = 0;
+
+	/* Send the startchunk. Index start with 1. */
+	buf[0] = startchunk >> 8;
+	buf[1] = startchunk & 0xff;
+	sigma_write_register(WRITE_MEMROW, buf, 2, devc);
+
+	/* Read the DRAM. */
+	buf[idx++] = REG_DRAM_BLOCK;
+	buf[idx++] = REG_DRAM_WAIT_ACK;
+
+	for (i = 0; i < numchunks; ++i) {
+		/* Alternate bit to copy from DRAM to cache. */
+		if (i != (numchunks - 1))
+			buf[idx++] = REG_DRAM_BLOCK | (((i + 1) % 2) << 4);
+
+		buf[idx++] = REG_DRAM_BLOCK_DATA | ((i % 2) << 4);
+
+		if (i != (numchunks - 1))
+			buf[idx++] = REG_DRAM_WAIT_ACK;
+	}
+
+	sigma_write(buf, idx, devc);
+
+	return sigma_read(data, numchunks * CHUNK_SIZE, devc);
+}
+
+/* Upload trigger look-up tables to Sigma. */
+static int sigma_write_trigger_lut(struct triggerlut *lut, struct dev_context *devc)
+{
+	int i;
+	uint8_t tmp[2];
+	uint16_t bit;
+
+	/* Transpose the table and send to Sigma. */
+	for (i = 0; i < 16; ++i) {
+		bit = 1 << i;
+
+		tmp[0] = tmp[1] = 0;
+
+		if (lut->m2d[0] & bit)
+			tmp[0] |= 0x01;
+		if (lut->m2d[1] & bit)
+			tmp[0] |= 0x02;
+		if (lut->m2d[2] & bit)
+			tmp[0] |= 0x04;
+		if (lut->m2d[3] & bit)
+			tmp[0] |= 0x08;
+
+		if (lut->m3 & bit)
+			tmp[0] |= 0x10;
+		if (lut->m3s & bit)
+			tmp[0] |= 0x20;
+		if (lut->m4 & bit)
+			tmp[0] |= 0x40;
+
+		if (lut->m0d[0] & bit)
+			tmp[1] |= 0x01;
+		if (lut->m0d[1] & bit)
+			tmp[1] |= 0x02;
+		if (lut->m0d[2] & bit)
+			tmp[1] |= 0x04;
+		if (lut->m0d[3] & bit)
+			tmp[1] |= 0x08;
+
+		if (lut->m1d[0] & bit)
+			tmp[1] |= 0x10;
+		if (lut->m1d[1] & bit)
+			tmp[1] |= 0x20;
+		if (lut->m1d[2] & bit)
+			tmp[1] |= 0x40;
+		if (lut->m1d[3] & bit)
+			tmp[1] |= 0x80;
+
+		sigma_write_register(WRITE_TRIGGER_SELECT0, tmp, sizeof(tmp),
+				     devc);
+		sigma_set_register(WRITE_TRIGGER_SELECT1, 0x30 | i, devc);
+	}
+
+	/* Send the parameters */
+	sigma_write_register(WRITE_TRIGGER_SELECT0, (uint8_t *) &lut->params,
+			     sizeof(lut->params), devc);
+
+	return SR_OK;
+}
+
+static void clear_helper(void *priv)
+{
+	struct dev_context *devc;
+
+	devc = priv;
+
+	ftdi_deinit(&devc->ftdic);
+}
+
+static int dev_clear(void)
+{
+	return std_dev_clear(di, clear_helper);
+}
+
+static int init(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+	struct sr_dev_inst *sdi;
+	struct sr_channel *ch;
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	GSList *devices;
+	struct ftdi_device_list *devlist;
+	char serial_txt[10];
+	uint32_t serial;
+	int ret;
+	unsigned int i;
+
+	(void)options;
+
+	drvc = di->priv;
+
+	devices = NULL;
+
+	if (!(devc = g_try_malloc(sizeof(struct dev_context)))) {
+		sr_err("%s: devc malloc failed", __func__);
+		return NULL;
+	}
+
+	ftdi_init(&devc->ftdic);
+
+	/* Look for SIGMAs. */
+
+	if ((ret = ftdi_usb_find_all(&devc->ftdic, &devlist,
+	    USB_VENDOR, USB_PRODUCT)) <= 0) {
+		if (ret < 0)
+			sr_err("ftdi_usb_find_all(): %d", ret);
+		goto free;
+	}
+
+	/* Make sure it's a version 1 or 2 SIGMA. */
+	ftdi_usb_get_strings(&devc->ftdic, devlist->dev, NULL, 0, NULL, 0,
+			     serial_txt, sizeof(serial_txt));
+	sscanf(serial_txt, "%x", &serial);
+
+	if (serial < 0xa6010000 || serial > 0xa602ffff) {
+		sr_err("Only SIGMA and SIGMA2 are supported "
+		       "in this version of libsigrok.");
+		goto free;
+	}
+
+	sr_info("Found ASIX SIGMA - Serial: %s", serial_txt);
+
+	devc->cur_samplerate = samplerates[0];
+	devc->period_ps = 0;
+	devc->limit_msec = 0;
+	devc->cur_firmware = -1;
+	devc->num_channels = 0;
+	devc->samples_per_event = 0;
+	devc->capture_ratio = 50;
+	devc->use_triggers = 0;
+
+	/* Register SIGMA device. */
+	if (!(sdi = sr_dev_inst_new(0, SR_ST_INITIALIZING, USB_VENDOR_NAME,
+				    USB_MODEL_NAME, NULL))) {
+		sr_err("%s: sdi was NULL", __func__);
+		goto free;
+	}
+	sdi->driver = di;
+
+	for (i = 0; i < ARRAY_SIZE(channel_names); i++) {
+		ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE,
+				    channel_names[i]);
+		if (!ch)
+			return NULL;
+		sdi->channels = g_slist_append(sdi->channels, ch);
+	}
+
+	devices = g_slist_append(devices, sdi);
+	drvc->instances = g_slist_append(drvc->instances, sdi);
+	sdi->priv = devc;
+
+	/* We will open the device again when we need it. */
+	ftdi_list_free(&devlist);
+
+	return devices;
+
+free:
+	ftdi_deinit(&devc->ftdic);
+	g_free(devc);
+	return NULL;
+}
+
+static GSList *dev_list(void)
+{
+	return ((struct drv_context *)(di->priv))->instances;
+}
+
+/*
+ * Configure the FPGA for bitbang mode.
+ * This sequence is documented in section 2. of the ASIX Sigma programming
+ * manual. This sequence is necessary to configure the FPGA in the Sigma
+ * into Bitbang mode, in which it can be programmed with the firmware.
+ */
+static int sigma_fpga_init_bitbang(struct dev_context *devc)
+{
+	uint8_t suicide[] = {
+		0x84, 0x84, 0x88, 0x84, 0x88, 0x84, 0x88, 0x84,
+	};
+	uint8_t init_array[] = {
+		0x01, 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01,
+		0x01, 0x01,
+	};
+	int i, ret, timeout = 10000;
+	uint8_t data;
+
+	/* Section 2. part 1), do the FPGA suicide. */
+	sigma_write(suicide, sizeof(suicide), devc);
+	sigma_write(suicide, sizeof(suicide), devc);
+	sigma_write(suicide, sizeof(suicide), devc);
+	sigma_write(suicide, sizeof(suicide), devc);
+
+	/* Section 2. part 2), do pulse on D1. */
+	sigma_write(init_array, sizeof(init_array), devc);
+	ftdi_usb_purge_buffers(&devc->ftdic);
+
+	/* Wait until the FPGA asserts D6/INIT_B. */
+	for (i = 0; i < timeout; i++) {
+		ret = sigma_read(&data, 1, devc);
+		if (ret < 0)
+			return ret;
+		/* Test if pin D6 got asserted. */
+		if (data & (1 << 5))
+			return 0;
+		/* The D6 was not asserted yet, wait a bit. */
+		usleep(10000);
+	}
+
+	return SR_ERR_TIMEOUT;
+}
+
+/*
+ * Configure the FPGA for logic-analyzer mode.
+ */
+static int sigma_fpga_init_la(struct dev_context *devc)
+{
+	/* Initialize the logic analyzer mode. */
+	uint8_t logic_mode_start[] = {
+		REG_ADDR_LOW  | (READ_ID & 0xf),
+		REG_ADDR_HIGH | (READ_ID >> 8),
+		REG_READ_ADDR,	/* Read ID register. */
+
+		REG_ADDR_LOW | (WRITE_TEST & 0xf),
+		REG_DATA_LOW | 0x5,
+		REG_DATA_HIGH_WRITE | 0x5,
+		REG_READ_ADDR,	/* Read scratch register. */
+
+		REG_DATA_LOW | 0xa,
+		REG_DATA_HIGH_WRITE | 0xa,
+		REG_READ_ADDR,	/* Read scratch register. */
+
+		REG_ADDR_LOW | (WRITE_MODE & 0xf),
+		REG_DATA_LOW | 0x0,
+		REG_DATA_HIGH_WRITE | 0x8,
+	};
+
+	uint8_t result[3];
+	int ret;
+
+	/* Initialize the logic analyzer mode. */
+	sigma_write(logic_mode_start, sizeof(logic_mode_start), devc);
+
+	/* Expect a 3 byte reply since we issued three READ requests. */
+	ret = sigma_read(result, 3, devc);
+	if (ret != 3)
+		goto err;
+
+	if (result[0] != 0xa6 || result[1] != 0x55 || result[2] != 0xaa)
+		goto err;
+
+	return SR_OK;
+err:
+	sr_err("Configuration failed. Invalid reply received.");
+	return SR_ERR;
+}
+
+/*
+ * Read the firmware from a file and transform it into a series of bitbang
+ * pulses used to program the FPGA. Note that the *bb_cmd must be free()'d
+ * by the caller of this function.
+ */
+static int sigma_fw_2_bitbang(const char *filename,
+			      uint8_t **bb_cmd, gsize *bb_cmd_size)
+{
+	GMappedFile *file;
+	GError *error;
+	gsize i, file_size, bb_size;
+	gchar *firmware;
+	uint8_t *bb_stream, *bbs;
+	uint32_t imm;
+	int bit, v;
+	int ret = SR_OK;
+
+	/*
+	 * Map the file and make the mapped buffer writable.
+	 * NOTE: Using writable=TRUE does _NOT_ mean that file that is mapped
+	 *       will be modified. It will not be modified until someone uses
+	 *       g_file_set_contents() on it.
+	 */
+	error = NULL;
+	file = g_mapped_file_new(filename, TRUE, &error);
+	g_assert_no_error(error);
+
+	file_size = g_mapped_file_get_length(file);
+	firmware = g_mapped_file_get_contents(file);
+	g_assert(firmware);
+
+	/* Weird magic transformation below, I have no idea what it does. */
+	imm = 0x3f6df2ab;
+	for (i = 0; i < file_size; i++) {
+		imm = (imm + 0xa853753) % 177 + (imm * 0x8034052);
+		firmware[i] ^= imm & 0xff;
+	}
+
+	/*
+	 * Now that the firmware is "transformed", we will transcribe the
+	 * firmware blob into a sequence of toggles of the Dx wires. This
+	 * sequence will be fed directly into the Sigma, which must be in
+	 * the FPGA bitbang programming mode.
+	 */
+
+	/* Each bit of firmware is transcribed as two toggles of Dx wires. */
+	bb_size = file_size * 8 * 2;
+	bb_stream = (uint8_t *)g_try_malloc(bb_size);
+	if (!bb_stream) {
+		sr_err("%s: Failed to allocate bitbang stream", __func__);
+		ret = SR_ERR_MALLOC;
+		goto exit;
+	}
+
+	bbs = bb_stream;
+	for (i = 0; i < file_size; i++) {
+		for (bit = 7; bit >= 0; bit--) {
+			v = (firmware[i] & (1 << bit)) ? 0x40 : 0x00;
+			*bbs++ = v | 0x01;
+			*bbs++ = v;
+		}
+	}
+
+	/* The transformation completed successfully, return the result. */
+	*bb_cmd = bb_stream;
+	*bb_cmd_size = bb_size;
+
+exit:
+	g_mapped_file_unref(file);
+	return ret;
+}
+
+static int upload_firmware(int firmware_idx, struct dev_context *devc)
+{
+	int ret;
+	unsigned char *buf;
+	unsigned char pins;
+	size_t buf_size;
+	const char *firmware = sigma_firmware_files[firmware_idx];
+	struct ftdi_context *ftdic = &devc->ftdic;
+
+	/* Make sure it's an ASIX SIGMA. */
+	ret = ftdi_usb_open_desc(ftdic, USB_VENDOR, USB_PRODUCT,
+				 USB_DESCRIPTION, NULL);
+	if (ret < 0) {
+		sr_err("ftdi_usb_open failed: %s",
+		       ftdi_get_error_string(ftdic));
+		return 0;
+	}
+
+	ret = ftdi_set_bitmode(ftdic, 0xdf, BITMODE_BITBANG);
+	if (ret < 0) {
+		sr_err("ftdi_set_bitmode failed: %s",
+		       ftdi_get_error_string(ftdic));
+		return 0;
+	}
+
+	/* Four times the speed of sigmalogan - Works well. */
+	ret = ftdi_set_baudrate(ftdic, 750000);
+	if (ret < 0) {
+		sr_err("ftdi_set_baudrate failed: %s",
+		       ftdi_get_error_string(ftdic));
+		return 0;
+	}
+
+	/* Initialize the FPGA for firmware upload. */
+	ret = sigma_fpga_init_bitbang(devc);
+	if (ret)
+		return ret;
+
+	/* Prepare firmware. */
+	ret = sigma_fw_2_bitbang(firmware, &buf, &buf_size);
+	if (ret != SR_OK) {
+		sr_err("An error occured while reading the firmware: %s",
+		       firmware);
+		return ret;
+	}
+
+	/* Upload firmare. */
+	sr_info("Uploading firmware file '%s'.", firmware);
+	sigma_write(buf, buf_size, devc);
+
+	g_free(buf);
+
+	ret = ftdi_set_bitmode(ftdic, 0x00, BITMODE_RESET);
+	if (ret < 0) {
+		sr_err("ftdi_set_bitmode failed: %s",
+		       ftdi_get_error_string(ftdic));
+		return SR_ERR;
+	}
+
+	ftdi_usb_purge_buffers(ftdic);
+
+	/* Discard garbage. */
+	while (sigma_read(&pins, 1, devc) == 1)
+		;
+
+	/* Initialize the FPGA for logic-analyzer mode. */
+	ret = sigma_fpga_init_la(devc);
+	if (ret != SR_OK)
+		return ret;
+
+	devc->cur_firmware = firmware_idx;
+
+	sr_info("Firmware uploaded.");
+
+	return SR_OK;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	int ret;
+
+	devc = sdi->priv;
+
+	/* Make sure it's an ASIX SIGMA. */
+	if ((ret = ftdi_usb_open_desc(&devc->ftdic,
+		USB_VENDOR, USB_PRODUCT, USB_DESCRIPTION, NULL)) < 0) {
+
+		sr_err("ftdi_usb_open failed: %s",
+		       ftdi_get_error_string(&devc->ftdic));
+
+		return 0;
+	}
+
+	sdi->status = SR_ST_ACTIVE;
+
+	return SR_OK;
+}
+
+static int set_samplerate(const struct sr_dev_inst *sdi, uint64_t samplerate)
+{
+	struct dev_context *devc;
+	unsigned int i;
+	int ret;
+
+	devc = sdi->priv;
+	ret = SR_OK;
+
+	for (i = 0; i < ARRAY_SIZE(samplerates); i++) {
+		if (samplerates[i] == samplerate)
+			break;
+	}
+	if (samplerates[i] == 0)
+		return SR_ERR_SAMPLERATE;
+
+	if (samplerate <= SR_MHZ(50)) {
+		ret = upload_firmware(0, devc);
+		devc->num_channels = 16;
+	} else if (samplerate == SR_MHZ(100)) {
+		ret = upload_firmware(1, devc);
+		devc->num_channels = 8;
+	} else if (samplerate == SR_MHZ(200)) {
+		ret = upload_firmware(2, devc);
+		devc->num_channels = 4;
+	}
+
+	if (ret == SR_OK) {
+		devc->cur_samplerate = samplerate;
+		devc->period_ps = 1000000000000ULL / samplerate;
+		devc->samples_per_event = 16 / devc->num_channels;
+		devc->state.state = SIGMA_IDLE;
+	}
+
+	return ret;
+}
+
+/*
+ * In 100 and 200 MHz mode, only a single pin rising/falling can be
+ * set as trigger. In other modes, two rising/falling triggers can be set,
+ * in addition to value/mask trigger for any number of channels.
+ *
+ * The Sigma supports complex triggers using boolean expressions, but this
+ * has not been implemented yet.
+ */
+static int configure_channels(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc = sdi->priv;
+	const struct sr_channel *ch;
+	const GSList *l;
+	int trigger_set = 0;
+	int channelbit;
+
+	memset(&devc->trigger, 0, sizeof(struct sigma_trigger));
+
+	for (l = sdi->channels; l; l = l->next) {
+		ch = (struct sr_channel *)l->data;
+		channelbit = 1 << (ch->index);
+
+		if (!ch->enabled || !ch->trigger)
+			continue;
+
+		if (devc->cur_samplerate >= SR_MHZ(100)) {
+			/* Fast trigger support. */
+			if (trigger_set) {
+				sr_err("Only a single pin trigger in 100 and "
+				       "200MHz mode is supported.");
+				return SR_ERR;
+			}
+			if (ch->trigger[0] == 'f')
+				devc->trigger.fallingmask |= channelbit;
+			else if (ch->trigger[0] == 'r')
+				devc->trigger.risingmask |= channelbit;
+			else {
+				sr_err("Only rising/falling trigger in 100 "
+				       "and 200MHz mode is supported.");
+				return SR_ERR;
+			}
+
+			++trigger_set;
+		} else {
+			/* Simple trigger support (event). */
+			if (ch->trigger[0] == '1') {
+				devc->trigger.simplevalue |= channelbit;
+				devc->trigger.simplemask |= channelbit;
+			}
+			else if (ch->trigger[0] == '0') {
+				devc->trigger.simplevalue &= ~channelbit;
+				devc->trigger.simplemask |= channelbit;
+			}
+			else if (ch->trigger[0] == 'f') {
+				devc->trigger.fallingmask |= channelbit;
+				++trigger_set;
+			}
+			else if (ch->trigger[0] == 'r') {
+				devc->trigger.risingmask |= channelbit;
+				++trigger_set;
+			}
+
+			/*
+			 * Actually, Sigma supports 2 rising/falling triggers,
+			 * but they are ORed and the current trigger syntax
+			 * does not permit ORed triggers.
+			 */
+			if (trigger_set > 1) {
+				sr_err("Only 1 rising/falling trigger "
+				       "is supported.");
+				return SR_ERR;
+			}
+		}
+
+		if (trigger_set)
+			devc->use_triggers = 1;
+	}
+
+	return SR_OK;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+
+	devc = sdi->priv;
+
+	/* TODO */
+	if (sdi->status == SR_ST_ACTIVE)
+		ftdi_usb_close(&devc->ftdic);
+
+	sdi->status = SR_ST_INACTIVE;
+
+	return SR_OK;
+}
+
+static int cleanup(void)
+{
+	return dev_clear();
+}
+
+static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+
+	(void)cg;
+
+	if (!sdi)
+		return SR_ERR;
+	devc = sdi->priv;
+
+	switch (id) {
+	case SR_CONF_SAMPLERATE:
+		*data = g_variant_new_uint64(devc->cur_samplerate);
+		break;
+	case SR_CONF_LIMIT_MSEC:
+		*data = g_variant_new_uint64(devc->limit_msec);
+		break;
+	case SR_CONF_CAPTURE_RATIO:
+		*data = g_variant_new_uint64(devc->capture_ratio);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	uint64_t tmp;
+	int ret;
+
+	(void)cg;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	devc = sdi->priv;
+
+	ret = SR_OK;
+	switch (id) {
+	case SR_CONF_SAMPLERATE:
+		ret = set_samplerate(sdi, g_variant_get_uint64(data));
+		break;
+	case SR_CONF_LIMIT_MSEC:
+		tmp = g_variant_get_uint64(data);
+		if (tmp > 0)
+			devc->limit_msec = g_variant_get_uint64(data);
+		else
+			ret = SR_ERR;
+		break;
+	case SR_CONF_LIMIT_SAMPLES:
+		tmp = g_variant_get_uint64(data);
+		devc->limit_msec = tmp * 1000 / devc->cur_samplerate;
+		break;
+	case SR_CONF_CAPTURE_RATIO:
+		tmp = g_variant_get_uint64(data);
+		if (tmp <= 100)
+			devc->capture_ratio = tmp;
+		else
+			ret = SR_ERR;
+		break;
+	default:
+		ret = SR_ERR_NA;
+	}
+
+	return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	GVariant *gvar;
+	GVariantBuilder gvb;
+
+	(void)sdi;
+	(void)cg;
+
+	switch (key) {
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+		break;
+	case SR_CONF_SAMPLERATE:
+		g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
+		gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), samplerates,
+				ARRAY_SIZE(samplerates), sizeof(uint64_t));
+		g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
+		*data = g_variant_builder_end(&gvb);
+		break;
+	case SR_CONF_TRIGGER_TYPE:
+		*data = g_variant_new_string(TRIGGER_TYPE);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+/* Software trigger to determine exact trigger position. */
+static int get_trigger_offset(uint8_t *samples, uint16_t last_sample,
+			      struct sigma_trigger *t)
+{
+	int i;
+	uint16_t sample = 0;
+
+	for (i = 0; i < 8; ++i) {
+		if (i > 0)
+			last_sample = sample;
+		sample = samples[2 * i] | (samples[2 * i + 1] << 8);
+
+		/* Simple triggers. */
+		if ((sample & t->simplemask) != t->simplevalue)
+			continue;
+
+		/* Rising edge. */
+		if (((last_sample & t->risingmask) != 0) ||
+		    ((sample & t->risingmask) != t->risingmask))
+			continue;
+
+		/* Falling edge. */
+		if ((last_sample & t->fallingmask) != t->fallingmask ||
+		    (sample & t->fallingmask) != 0)
+			continue;
+
+		break;
+	}
+
+	/* If we did not match, return original trigger pos. */
+	return i & 0x7;
+}
+
+
+/*
+ * Return the timestamp of "DRAM cluster".
+ */
+static uint16_t sigma_dram_cluster_ts(struct sigma_dram_cluster *cluster)
+{
+	return (cluster->timestamp_hi << 8) | cluster->timestamp_lo;
+}
+
+static void sigma_decode_dram_cluster(struct sigma_dram_cluster *dram_cluster,
+				      unsigned int events_in_cluster,
+				      unsigned int triggered,
+				      struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc = sdi->priv;
+	struct sigma_state *ss = &devc->state;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_logic logic;
+	uint16_t tsdiff, ts;
+	uint8_t samples[2048];
+	unsigned int i;
+
+	ts = sigma_dram_cluster_ts(dram_cluster);
+	tsdiff = ts - ss->lastts;
+	ss->lastts = ts;
+
+	packet.type = SR_DF_LOGIC;
+	packet.payload = &logic;
+	logic.unitsize = 2;
+	logic.data = samples;
+
+	/*
+	 * First of all, send Sigrok a copy of the last sample from
+	 * previous cluster as many times as needed to make up for
+	 * the differential characteristics of data we get from the
+	 * Sigma. Sigrok needs one sample of data per period.
+	 *
+	 * One DRAM cluster contains a timestamp and seven samples,
+	 * the units of timestamp are "devc->period_ps" , the first
+	 * sample in the cluster happens at the time of the timestamp
+	 * and the remaining samples happen at timestamp +1...+6 .
+	 */
+	for (ts = 0; ts < tsdiff - (EVENTS_PER_CLUSTER - 1); ts++) {
+		i = ts % 1024;
+		samples[2 * i + 0] = ss->lastsample & 0xff;
+		samples[2 * i + 1] = ss->lastsample >> 8;
+
+		/*
+		 * If we have 1024 samples ready or we're at the
+		 * end of submitting the padding samples, submit
+		 * the packet to Sigrok.
+		 */
+		if ((i == 1023) || (ts == (tsdiff - EVENTS_PER_CLUSTER))) {
+			logic.length = (i + 1) * logic.unitsize;
+			sr_session_send(devc->cb_data, &packet);
+		}
+	}
+
+	/*
+	 * Parse the samples in current cluster and prepare them
+	 * to be submitted to Sigrok.
+	 */
+	for (i = 0; i < events_in_cluster; i++) {
+		samples[2 * i + 1] = dram_cluster->samples[i].sample_lo;
+		samples[2 * i + 0] = dram_cluster->samples[i].sample_hi;
+	}
+
+	/* Send data up to trigger point (if triggered). */
+	int trigger_offset = 0;
+	if (triggered) {
+		/*
+		 * Trigger is not always accurate to sample because of
+		 * pipeline delay. However, it always triggers before
+		 * the actual event. We therefore look at the next
+		 * samples to pinpoint the exact position of the trigger.
+		 */
+		trigger_offset = get_trigger_offset(samples,
+					ss->lastsample, &devc->trigger);
+
+		if (trigger_offset > 0) {
+			packet.type = SR_DF_LOGIC;
+			logic.length = trigger_offset * logic.unitsize;
+			sr_session_send(devc->cb_data, &packet);
+			events_in_cluster -= trigger_offset;
+		}
+
+		/* Only send trigger if explicitly enabled. */
+		if (devc->use_triggers) {
+			packet.type = SR_DF_TRIGGER;
+			sr_session_send(devc->cb_data, &packet);
+		}
+	}
+
+	if (events_in_cluster > 0) {
+		packet.type = SR_DF_LOGIC;
+		logic.length = events_in_cluster * logic.unitsize;
+		logic.data = samples + (trigger_offset * logic.unitsize);
+		sr_session_send(devc->cb_data, &packet);
+	}
+
+	ss->lastsample =
+		samples[2 * (events_in_cluster - 1) + 0] |
+		(samples[2 * (events_in_cluster - 1) + 1] << 8);
+
+}
+
+/*
+ * Decode chunk of 1024 bytes, 64 clusters, 7 events per cluster.
+ * Each event is 20ns apart, and can contain multiple samples.
+ *
+ * For 200 MHz, events contain 4 samples for each channel, spread 5 ns apart.
+ * For 100 MHz, events contain 2 samples for each channel, spread 10 ns apart.
+ * For 50 MHz and below, events contain one sample for each channel,
+ * spread 20 ns apart.
+ */
+static int decode_chunk_ts(struct sigma_dram_line *dram_line,
+			   uint16_t events_in_line,
+			   uint32_t trigger_event,
+			   void *cb_data)
+{
+	struct sigma_dram_cluster *dram_cluster;
+	struct sr_dev_inst *sdi = cb_data;
+	struct dev_context *devc = sdi->priv;
+	unsigned int clusters_in_line =
+		(events_in_line + (EVENTS_PER_CLUSTER - 1)) / EVENTS_PER_CLUSTER;
+	unsigned int events_in_cluster;
+	unsigned int i;
+	uint32_t trigger_cluster = ~0, triggered = 0;
+
+	/* Check if trigger is in this chunk. */
+	if (trigger_event < (64 * 7)) {
+		if (devc->cur_samplerate <= SR_MHZ(50)) {
+			trigger_event -= MIN(EVENTS_PER_CLUSTER - 1,
+					     trigger_event);
+		}
+
+		/* Find in which cluster the trigger occured. */
+		trigger_cluster = trigger_event / EVENTS_PER_CLUSTER;
+	}
+
+	/* For each full DRAM cluster. */
+	for (i = 0; i < clusters_in_line; i++) {
+		dram_cluster = &dram_line->cluster[i];
+
+		/* The last cluster might not be full. */
+		if ((i == clusters_in_line - 1) &&
+		    (events_in_line % EVENTS_PER_CLUSTER)) {
+			events_in_cluster = events_in_line % EVENTS_PER_CLUSTER;
+		} else {
+			events_in_cluster = EVENTS_PER_CLUSTER;
+		}
+
+		triggered = (i == trigger_cluster);
+		sigma_decode_dram_cluster(dram_cluster, events_in_cluster,
+					  triggered, sdi);
+	}
+
+	return SR_OK;
+}
+
+static int download_capture(struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc = sdi->priv;
+	const int chunks_per_read = 32;
+	struct sigma_dram_line *dram_line;
+	int bufsz;
+	uint32_t stoppos, triggerpos;
+	struct sr_datafeed_packet packet;
+	uint8_t modestatus;
+
+	uint32_t i;
+	uint32_t dl_lines_total, dl_lines_curr, dl_lines_done;
+	uint32_t dl_events_in_line = 64 * 7;
+	uint32_t trg_line = ~0, trg_event = ~0;
+
+	dram_line = g_try_malloc0(chunks_per_read * sizeof(*dram_line));
+	if (!dram_line)
+		return FALSE;
+
+	sr_info("Downloading sample data.");
+
+	/* Stop acquisition. */
+	sigma_set_register(WRITE_MODE, 0x11, devc);
+
+	/* Set SDRAM Read Enable. */
+	sigma_set_register(WRITE_MODE, 0x02, devc);
+
+	/* Get the current position. */
+	sigma_read_pos(&stoppos, &triggerpos, devc);
+
+	/* Check if trigger has fired. */
+	modestatus = sigma_get_register(READ_MODE, devc);
+	if (modestatus & 0x20) {
+		trg_line = triggerpos >> 9;
+		trg_event = triggerpos & 0x1ff;
+	}
+
+	/*
+	 * Determine how many 1024b "DRAM lines" do we need to read from the
+	 * Sigma so we have a complete set of samples. Note that the last
+	 * line can be only partial, containing less than 64 clusters.
+	 */
+	dl_lines_total = (stoppos >> 9) + 1;
+
+	dl_lines_done = 0;
+
+	while (dl_lines_total > dl_lines_done) {
+		/* We can download only up-to 32 DRAM lines in one go! */
+		dl_lines_curr = MIN(chunks_per_read, dl_lines_total);
+
+		bufsz = sigma_read_dram(dl_lines_done, dl_lines_curr,
+					(uint8_t *)dram_line, devc);
+		/* TODO: Check bufsz. For now, just avoid compiler warnings. */
+		(void)bufsz;
+
+		/* This is the first DRAM line, so find the initial timestamp. */
+		if (dl_lines_done == 0) {
+			devc->state.lastts =
+				sigma_dram_cluster_ts(&dram_line[0].cluster[0]);
+			devc->state.lastsample = 0;
+		}
+
+		for (i = 0; i < dl_lines_curr; i++) {
+			uint32_t trigger_event = ~0;
+			/* The last "DRAM line" can be only partially full. */
+			if (dl_lines_done + i == dl_lines_total - 1)
+				dl_events_in_line = stoppos & 0x1ff;
+
+			/* Test if the trigger happened on this line. */
+			if (dl_lines_done + i == trg_line)
+				trigger_event = trg_event;
+
+			decode_chunk_ts(dram_line + i, dl_events_in_line,
+					trigger_event, sdi);
+		}
+
+		dl_lines_done += dl_lines_curr;
+	}
+
+	/* All done. */
+	packet.type = SR_DF_END;
+	sr_session_send(sdi, &packet);
+
+	dev_acquisition_stop(sdi, sdi);
+
+	g_free(dram_line);
+
+	return TRUE;
+}
+
+/*
+ * Handle the Sigma when in CAPTURE mode. This function checks:
+ * - Sampling time ended
+ * - DRAM capacity overflow
+ * This function triggers download of the samples from Sigma
+ * in case either of the above conditions is true.
+ */
+static int sigma_capture_mode(struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc = sdi->priv;
+
+	uint64_t running_msec;
+	struct timeval tv;
+
+	uint32_t stoppos, triggerpos;
+
+	/* Check if the selected sampling duration passed. */
+	gettimeofday(&tv, 0);
+	running_msec = (tv.tv_sec - devc->start_tv.tv_sec) * 1000 +
+		       (tv.tv_usec - devc->start_tv.tv_usec) / 1000;
+	if (running_msec >= devc->limit_msec)
+		return download_capture(sdi);
+
+	/* Get the position in DRAM to which the FPGA is writing now. */
+	sigma_read_pos(&stoppos, &triggerpos, devc);
+	/* Test if DRAM is full and if so, download the data. */
+	if ((stoppos >> 9) == 32767)
+		return download_capture(sdi);
+
+	return TRUE;
+}
+
+static int receive_data(int fd, int revents, void *cb_data)
+{
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+
+	(void)fd;
+	(void)revents;
+
+	sdi = cb_data;
+	devc = sdi->priv;
+
+	if (devc->state.state == SIGMA_IDLE)
+		return TRUE;
+
+	if (devc->state.state == SIGMA_CAPTURE)
+		return sigma_capture_mode(sdi);
+
+	return TRUE;
+}
+
+/* Build a LUT entry used by the trigger functions. */
+static void build_lut_entry(uint16_t value, uint16_t mask, uint16_t *entry)
+{
+	int i, j, k, bit;
+
+	/* For each quad channel. */
+	for (i = 0; i < 4; ++i) {
+		entry[i] = 0xffff;
+
+		/* For each bit in LUT. */
+		for (j = 0; j < 16; ++j)
+
+			/* For each channel in quad. */
+			for (k = 0; k < 4; ++k) {
+				bit = 1 << (i * 4 + k);
+
+				/* Set bit in entry */
+				if ((mask & bit) &&
+				    ((!(value & bit)) !=
+				    (!(j & (1 << k)))))
+					entry[i] &= ~(1 << j);
+			}
+	}
+}
+
+/* Add a logical function to LUT mask. */
+static void add_trigger_function(enum triggerop oper, enum triggerfunc func,
+				 int index, int neg, uint16_t *mask)
+{
+	int i, j;
+	int x[2][2], tmp, a, b, aset, bset, rset;
+
+	memset(x, 0, 4 * sizeof(int));
+
+	/* Trigger detect condition. */
+	switch (oper) {
+	case OP_LEVEL:
+		x[0][1] = 1;
+		x[1][1] = 1;
+		break;
+	case OP_NOT:
+		x[0][0] = 1;
+		x[1][0] = 1;
+		break;
+	case OP_RISE:
+		x[0][1] = 1;
+		break;
+	case OP_FALL:
+		x[1][0] = 1;
+		break;
+	case OP_RISEFALL:
+		x[0][1] = 1;
+		x[1][0] = 1;
+		break;
+	case OP_NOTRISE:
+		x[1][1] = 1;
+		x[0][0] = 1;
+		x[1][0] = 1;
+		break;
+	case OP_NOTFALL:
+		x[1][1] = 1;
+		x[0][0] = 1;
+		x[0][1] = 1;
+		break;
+	case OP_NOTRISEFALL:
+		x[1][1] = 1;
+		x[0][0] = 1;
+		break;
+	}
+
+	/* Transpose if neg is set. */
+	if (neg) {
+		for (i = 0; i < 2; ++i) {
+			for (j = 0; j < 2; ++j) {
+				tmp = x[i][j];
+				x[i][j] = x[1-i][1-j];
+				x[1-i][1-j] = tmp;
+			}
+		}
+	}
+
+	/* Update mask with function. */
+	for (i = 0; i < 16; ++i) {
+		a = (i >> (2 * index + 0)) & 1;
+		b = (i >> (2 * index + 1)) & 1;
+
+		aset = (*mask >> i) & 1;
+		bset = x[b][a];
+
+		if (func == FUNC_AND || func == FUNC_NAND)
+			rset = aset & bset;
+		else if (func == FUNC_OR || func == FUNC_NOR)
+			rset = aset | bset;
+		else if (func == FUNC_XOR || func == FUNC_NXOR)
+			rset = aset ^ bset;
+
+		if (func == FUNC_NAND || func == FUNC_NOR || func == FUNC_NXOR)
+			rset = !rset;
+
+		*mask &= ~(1 << i);
+
+		if (rset)
+			*mask |= 1 << i;
+	}
+}
+
+/*
+ * Build trigger LUTs used by 50 MHz and lower sample rates for supporting
+ * simple pin change and state triggers. Only two transitions (rise/fall) can be
+ * set at any time, but a full mask and value can be set (0/1).
+ */
+static int build_basic_trigger(struct triggerlut *lut, struct dev_context *devc)
+{
+	int i,j;
+	uint16_t masks[2] = { 0, 0 };
+
+	memset(lut, 0, sizeof(struct triggerlut));
+
+	/* Contant for simple triggers. */
+	lut->m4 = 0xa000;
+
+	/* Value/mask trigger support. */
+	build_lut_entry(devc->trigger.simplevalue, devc->trigger.simplemask,
+			lut->m2d);
+
+	/* Rise/fall trigger support. */
+	for (i = 0, j = 0; i < 16; ++i) {
+		if (devc->trigger.risingmask & (1 << i) ||
+		    devc->trigger.fallingmask & (1 << i))
+			masks[j++] = 1 << i;
+	}
+
+	build_lut_entry(masks[0], masks[0], lut->m0d);
+	build_lut_entry(masks[1], masks[1], lut->m1d);
+
+	/* Add glue logic */
+	if (masks[0] || masks[1]) {
+		/* Transition trigger. */
+		if (masks[0] & devc->trigger.risingmask)
+			add_trigger_function(OP_RISE, FUNC_OR, 0, 0, &lut->m3);
+		if (masks[0] & devc->trigger.fallingmask)
+			add_trigger_function(OP_FALL, FUNC_OR, 0, 0, &lut->m3);
+		if (masks[1] & devc->trigger.risingmask)
+			add_trigger_function(OP_RISE, FUNC_OR, 1, 0, &lut->m3);
+		if (masks[1] & devc->trigger.fallingmask)
+			add_trigger_function(OP_FALL, FUNC_OR, 1, 0, &lut->m3);
+	} else {
+		/* Only value/mask trigger. */
+		lut->m3 = 0xffff;
+	}
+
+	/* Triggertype: event. */
+	lut->params.selres = 3;
+
+	return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct dev_context *devc;
+	struct clockselect_50 clockselect;
+	int frac, triggerpin, ret;
+	uint8_t triggerselect = 0;
+	struct triggerinout triggerinout_conf;
+	struct triggerlut lut;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	devc = sdi->priv;
+
+	if (configure_channels(sdi) != SR_OK) {
+		sr_err("Failed to configure channels.");
+		return SR_ERR;
+	}
+
+	/* If the samplerate has not been set, default to 200 kHz. */
+	if (devc->cur_firmware == -1) {
+		if ((ret = set_samplerate(sdi, SR_KHZ(200))) != SR_OK)
+			return ret;
+	}
+
+	/* Enter trigger programming mode. */
+	sigma_set_register(WRITE_TRIGGER_SELECT1, 0x20, devc);
+
+	/* 100 and 200 MHz mode. */
+	if (devc->cur_samplerate >= SR_MHZ(100)) {
+		sigma_set_register(WRITE_TRIGGER_SELECT1, 0x81, devc);
+
+		/* Find which pin to trigger on from mask. */
+		for (triggerpin = 0; triggerpin < 8; ++triggerpin)
+			if ((devc->trigger.risingmask | devc->trigger.fallingmask) &
+			    (1 << triggerpin))
+				break;
+
+		/* Set trigger pin and light LED on trigger. */
+		triggerselect = (1 << LEDSEL1) | (triggerpin & 0x7);
+
+		/* Default rising edge. */
+		if (devc->trigger.fallingmask)
+			triggerselect |= 1 << 3;
+
+	/* All other modes. */
+	} else if (devc->cur_samplerate <= SR_MHZ(50)) {
+		build_basic_trigger(&lut, devc);
+
+		sigma_write_trigger_lut(&lut, devc);
+
+		triggerselect = (1 << LEDSEL1) | (1 << LEDSEL0);
+	}
+
+	/* Setup trigger in and out pins to default values. */
+	memset(&triggerinout_conf, 0, sizeof(struct triggerinout));
+	triggerinout_conf.trgout_bytrigger = 1;
+	triggerinout_conf.trgout_enable = 1;
+
+	sigma_write_register(WRITE_TRIGGER_OPTION,
+			     (uint8_t *) &triggerinout_conf,
+			     sizeof(struct triggerinout), devc);
+
+	/* Go back to normal mode. */
+	sigma_set_register(WRITE_TRIGGER_SELECT1, triggerselect, devc);
+
+	/* Set clock select register. */
+	if (devc->cur_samplerate == SR_MHZ(200))
+		/* Enable 4 channels. */
+		sigma_set_register(WRITE_CLOCK_SELECT, 0xf0, devc);
+	else if (devc->cur_samplerate == SR_MHZ(100))
+		/* Enable 8 channels. */
+		sigma_set_register(WRITE_CLOCK_SELECT, 0x00, devc);
+	else {
+		/*
+		 * 50 MHz mode (or fraction thereof). Any fraction down to
+		 * 50 MHz / 256 can be used, but is not supported by sigrok API.
+		 */
+		frac = SR_MHZ(50) / devc->cur_samplerate - 1;
+
+		clockselect.async = 0;
+		clockselect.fraction = frac;
+		clockselect.disabled_channels = 0;
+
+		sigma_write_register(WRITE_CLOCK_SELECT,
+				     (uint8_t *) &clockselect,
+				     sizeof(clockselect), devc);
+	}
+
+	/* Setup maximum post trigger time. */
+	sigma_set_register(WRITE_POST_TRIGGER,
+			   (devc->capture_ratio * 255) / 100, devc);
+
+	/* Start acqusition. */
+	gettimeofday(&devc->start_tv, 0);
+	sigma_set_register(WRITE_MODE, 0x0d, devc);
+
+	devc->cb_data = cb_data;
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	/* Add capture source. */
+	sr_source_add(0, G_IO_IN, 10, receive_data, (void *)sdi);
+
+	devc->state.state = SIGMA_CAPTURE;
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct dev_context *devc;
+
+	(void)cb_data;
+
+	devc = sdi->priv;
+	devc->state.state = SIGMA_IDLE;
+
+	sr_source_remove(0);
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver asix_sigma_driver_info = {
+	.name = "asix-sigma",
+	.longname = "ASIX SIGMA/SIGMA2",
+	.api_version = 1,
+	.init = init,
+	.cleanup = cleanup,
+	.scan = scan,
+	.dev_list = dev_list,
+	.dev_clear = dev_clear,
+	.config_get = config_get,
+	.config_set = config_set,
+	.config_list = config_list,
+	.dev_open = dev_open,
+	.dev_close = dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/asix-sigma/asix-sigma.h b/hardware/asix-sigma/asix-sigma.h
new file mode 100644
index 0000000..4c9deff
--- /dev/null
+++ b/hardware/asix-sigma/asix-sigma.h
@@ -0,0 +1,211 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010 Håvard Espeland <gus at ping.uio.no>,
+ * Copyright (C) 2010 Martin Stensgård <mastensg at ping.uio.no>
+ * Copyright (C) 2010 Carl Henrik Lunde <chlunde at ping.uio.no>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_ASIX_SIGMA_ASIX_SIGMA_H
+#define LIBSIGROK_HARDWARE_ASIX_SIGMA_ASIX_SIGMA_H
+
+#define LOG_PREFIX "asix-sigma"
+
+enum sigma_write_register {
+	WRITE_CLOCK_SELECT	= 0,
+	WRITE_TRIGGER_SELECT0	= 1,
+	WRITE_TRIGGER_SELECT1	= 2,
+	WRITE_MODE		= 3,
+	WRITE_MEMROW		= 4,
+	WRITE_POST_TRIGGER	= 5,
+	WRITE_TRIGGER_OPTION	= 6,
+	WRITE_PIN_VIEW		= 7,
+
+	WRITE_TEST		= 15,
+};
+
+enum sigma_read_register {
+	READ_ID			= 0,
+	READ_TRIGGER_POS_LOW	= 1,
+	READ_TRIGGER_POS_HIGH	= 2,
+	READ_TRIGGER_POS_UP	= 3,
+	READ_STOP_POS_LOW	= 4,
+	READ_STOP_POS_HIGH	= 5,
+	READ_STOP_POS_UP	= 6,
+	READ_MODE		= 7,
+	READ_PIN_CHANGE_LOW	= 8,
+	READ_PIN_CHANGE_HIGH	= 9,
+	READ_BLOCK_LAST_TS_LOW	= 10,
+	READ_BLOCK_LAST_TS_HIGH	= 11,
+	READ_PIN_VIEW		= 12,
+
+	READ_TEST		= 15,
+};
+
+#define REG_ADDR_LOW		(0x0 << 4)
+#define REG_ADDR_HIGH		(0x1 << 4)
+#define REG_DATA_LOW		(0x2 << 4)
+#define REG_DATA_HIGH_WRITE	(0x3 << 4)
+#define REG_READ_ADDR		(0x4 << 4)
+#define REG_DRAM_WAIT_ACK	(0x5 << 4)
+
+/* Bit (1 << 4) can be low or high (double buffer / cache) */
+#define REG_DRAM_BLOCK		(0x6 << 4)
+#define REG_DRAM_BLOCK_BEGIN	(0x8 << 4)
+#define REG_DRAM_BLOCK_DATA	(0xa << 4)
+
+#define LEDSEL0			6
+#define LEDSEL1			7
+
+#define NEXT_REG		1
+
+#define EVENTS_PER_CLUSTER	7
+
+#define CHUNK_SIZE		1024
+
+/*
+ * The entire ASIX Sigma DRAM is an array of struct sigma_dram_line[1024];
+ */
+
+/* One "DRAM cluster" contains a timestamp and 7 samples, 16b total. */
+struct sigma_dram_cluster {
+	uint8_t		timestamp_lo;
+	uint8_t		timestamp_hi;
+	struct {
+		uint8_t	sample_hi;
+		uint8_t	sample_lo;
+	}		samples[7];
+};
+
+/* One "DRAM line" contains 64 "DRAM clusters", 1024b total. */
+struct sigma_dram_line {
+	struct sigma_dram_cluster	cluster[64];
+};
+
+struct clockselect_50 {
+	uint8_t async;
+	uint8_t fraction;
+	uint16_t disabled_channels;
+};
+
+/* The effect of all these are still a bit unclear. */
+struct triggerinout {
+	uint8_t trgout_resistor_enable : 1;
+	uint8_t trgout_resistor_pullup : 1;
+	uint8_t reserved1 : 1;
+	uint8_t trgout_bytrigger : 1;
+	uint8_t trgout_byevent : 1;
+	uint8_t trgout_bytriggerin : 1;
+	uint8_t reserved2 : 2;
+
+	/* Should be set same as the first two */
+	uint8_t trgout_resistor_enable2 : 1;
+	uint8_t trgout_resistor_pullup2 : 1;
+
+	uint8_t reserved3 : 1;
+	uint8_t trgout_long : 1;
+	uint8_t trgout_pin : 1; /* Use 1k resistor. Pullup? */
+	uint8_t trgin_negate : 1;
+	uint8_t trgout_enable : 1;
+	uint8_t trgin_enable : 1;
+};
+
+struct triggerlut {
+	/* The actual LUTs. */
+	uint16_t m0d[4], m1d[4], m2d[4];
+	uint16_t m3, m3s, m4;
+
+	/* Paramters should be sent as a single register write. */
+	struct {
+		uint8_t selc : 2;
+		uint8_t selpresc : 6;
+
+		uint8_t selinc : 2;
+		uint8_t selres : 2;
+		uint8_t sela : 2;
+		uint8_t selb : 2;
+
+		uint16_t cmpb;
+		uint16_t cmpa;
+	} params;
+};
+
+/* Trigger configuration */
+struct sigma_trigger {
+	/* Only two channels can be used in mask. */
+	uint16_t risingmask;
+	uint16_t fallingmask;
+
+	/* Simple trigger support (<= 50 MHz). */
+	uint16_t simplemask;
+	uint16_t simplevalue;
+
+	/* TODO: Advanced trigger support (boolean expressions). */
+};
+
+/* Events for trigger operation. */
+enum triggerop {
+	OP_LEVEL = 1,
+	OP_NOT,
+	OP_RISE,
+	OP_FALL,
+	OP_RISEFALL,
+	OP_NOTRISE,
+	OP_NOTFALL,
+	OP_NOTRISEFALL,
+};
+
+/* Logical functions for trigger operation. */
+enum triggerfunc {
+	FUNC_AND = 1,
+	FUNC_NAND,
+	FUNC_OR,
+	FUNC_NOR,
+	FUNC_XOR,
+	FUNC_NXOR,
+};
+
+struct sigma_state {
+	enum {
+		SIGMA_UNINITIALIZED = 0,
+		SIGMA_IDLE,
+		SIGMA_CAPTURE,
+		SIGMA_DOWNLOAD,
+	} state;
+
+	uint16_t lastts;
+	uint16_t lastsample;
+};
+
+/* Private, per-device-instance driver context. */
+struct dev_context {
+	struct ftdi_context ftdic;
+	uint64_t cur_samplerate;
+	uint64_t period_ps;
+	uint64_t limit_msec;
+	struct timeval start_tv;
+	int cur_firmware;
+	int num_channels;
+	int cur_channels;
+	int samples_per_event;
+	int capture_ratio;
+	struct sigma_trigger trigger;
+	int use_triggers;
+	struct sigma_state state;
+	void *cb_data;
+};
+
+#endif
diff --git a/hardware/atten-pps3xxx/api.c b/hardware/atten-pps3xxx/api.c
new file mode 100644
index 0000000..3b9f002
--- /dev/null
+++ b/hardware/atten-pps3xxx/api.c
@@ -0,0 +1,517 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <errno.h>
+#include "protocol.h"
+
+/*
+ * The default serial communication settings on the device are 9600
+ * baud, 9 data bits. The 9th bit isn't actually used, and the vendor
+ * software uses Mark parity to absorb the extra bit.
+ *
+ * Since 9 data bits is not a standard available in POSIX, we use two
+ * stop bits to skip over the extra bit instead.
+ */
+#define SERIALCOMM "9600/8n2"
+
+static const int32_t scanopts[] = {
+	SR_CONF_CONN,
+	SR_CONF_SERIALCOMM,
+};
+
+static const int32_t devopts[] = {
+	SR_CONF_POWER_SUPPLY,
+	SR_CONF_CONTINUOUS,
+	SR_CONF_OUTPUT_CHANNEL,
+	SR_CONF_OVER_CURRENT_PROTECTION,
+};
+
+static const int32_t devopts_cg[] = {
+	SR_CONF_OUTPUT_VOLTAGE,
+	SR_CONF_OUTPUT_VOLTAGE_MAX,
+	SR_CONF_OUTPUT_CURRENT,
+	SR_CONF_OUTPUT_CURRENT_MAX,
+	SR_CONF_OUTPUT_ENABLED,
+};
+
+static const char *channel_modes[] = {
+	"Independent",
+	"Series",
+	"Parallel",
+};
+
+static struct pps_model models[] = {
+	{ PPS_3203T_3S, "PPS3203T-3S",
+		CHANMODE_INDEPENDENT | CHANMODE_SERIES | CHANMODE_PARALLEL,
+		3,
+		{
+			/* Channel 1 */
+			{ { 0, 32, 0.01 }, { 0, 3, 0.001 } },
+			/* Channel 2 */
+			{ { 0, 32, 0.01 }, { 0, 3, 0.001 } },
+			/* Channel 3 */
+			{ { 0, 6, 0.01 }, { 0, 3, 0.001 } },
+		},
+	},
+};
+
+
+SR_PRIV struct sr_dev_driver atten_pps3203_driver_info;
+static struct sr_dev_driver *di = &atten_pps3203_driver_info;
+
+static int init(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options, int modelid)
+{
+	struct sr_dev_inst *sdi;
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_config *src;
+	struct sr_channel *ch;
+	struct sr_channel_group *cg;
+	struct sr_serial_dev_inst *serial;
+	GSList *l, *devices;
+	struct pps_model *model;
+	uint8_t packet[PACKET_SIZE];
+	unsigned int i;
+	int ret;
+	const char *conn, *serialcomm;
+	char channel[10];
+
+	devices = NULL;
+	drvc = di->priv;
+	drvc->instances = NULL;
+
+	conn = serialcomm = NULL;
+	for (l = options; l; l = l->next) {
+		src = l->data;
+		switch (src->key) {
+		case SR_CONF_CONN:
+			conn = g_variant_get_string(src->data, NULL);
+			break;
+		case SR_CONF_SERIALCOMM:
+			serialcomm = g_variant_get_string(src->data, NULL);
+			break;
+		}
+	}
+	if (!conn)
+		return NULL;
+	if (!serialcomm)
+		serialcomm = SERIALCOMM;
+
+	if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+		return NULL;
+
+	if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+		return NULL;
+	serial_flush(serial);
+
+	/* This is how the vendor software channels for hardware. */
+	memset(packet, 0, PACKET_SIZE);
+	packet[0] = 0xaa;
+	packet[1] = 0xaa;
+	if (serial_write(serial, packet, PACKET_SIZE) == -1) {
+		sr_err("Unable to write while probing for hardware: %s",
+				strerror(errno));
+		return NULL;
+	}
+	/* The device responds with a 24-byte packet when it receives a packet.
+	 * At 9600 baud, 300ms is long enough for it to have arrived. */
+	g_usleep(300 * 1000);
+	memset(packet, 0, PACKET_SIZE);
+	if ((ret = serial_read_nonblocking(serial, packet, PACKET_SIZE)) < 0) {
+		sr_err("Unable to read while probing for hardware: %s",
+				strerror(errno));
+		return NULL;
+	}
+	if (ret != PACKET_SIZE || packet[0] != 0xaa || packet[1] != 0xaa) {
+		/* Doesn't look like an Atten PPS. */
+		return NULL;
+	}
+
+	model = NULL;
+	for (i = 0; i < ARRAY_SIZE(models); i++) {
+		if (models[i].modelid == modelid) {
+			model = &models[i];
+			break;
+		}
+	}
+	if (!model) {
+		sr_err("Unknown modelid %d", modelid);
+		return NULL;
+	}
+
+	sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "Atten", model->name, NULL);
+	sdi->driver = di;
+	sdi->inst_type = SR_INST_SERIAL;
+	sdi->conn = serial;
+	for (i = 0; i < MAX_CHANNELS; i++) {
+		snprintf(channel, 10, "CH%d", i + 1);
+		ch = sr_channel_new(i, SR_CHANNEL_ANALOG, TRUE, channel);
+		sdi->channels = g_slist_append(sdi->channels, ch);
+		cg = g_malloc(sizeof(struct sr_channel_group));
+		cg->name = g_strdup(channel);
+		cg->channels = g_slist_append(NULL, ch);
+		cg->priv = NULL;
+		sdi->channel_groups = g_slist_append(sdi->channel_groups, cg);
+	}
+
+	devc = g_malloc0(sizeof(struct dev_context));
+	devc->model = model;
+	devc->config = g_malloc0(sizeof(struct per_channel_config) * model->num_channels);
+	sdi->priv = devc;
+	drvc->instances = g_slist_append(drvc->instances, sdi);
+	devices = g_slist_append(devices, sdi);
+
+	serial_close(serial);
+	if (!devices)
+		sr_serial_dev_inst_free(serial);
+
+	return devices;
+}
+
+static GSList *scan_3203(GSList *options)
+{
+	return scan(options, PPS_3203T_3S);
+}
+
+static GSList *dev_list(void)
+{
+	return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int cleanup(void)
+{
+	return std_dev_clear(di, NULL);
+}
+
+static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	struct sr_channel *ch;
+	int channel, ret;
+
+	if (!sdi)
+		return SR_ERR_ARG;
+
+	devc = sdi->priv;
+
+	ret = SR_OK;
+	if (!cg) {
+		/* No channel group: global options. */
+		switch (key) {
+		case SR_CONF_OUTPUT_CHANNEL:
+			*data = g_variant_new_string(channel_modes[devc->channel_mode]);
+			break;
+		case SR_CONF_OVER_CURRENT_PROTECTION:
+			*data = g_variant_new_boolean(devc->over_current_protection);
+			break;
+		default:
+			return SR_ERR_NA;
+		}
+	} else {
+		/* We only ever have one channel per channel group in this driver. */
+		ch = cg->channels->data;
+		channel = ch->index;
+
+		switch (key) {
+		case SR_CONF_OUTPUT_VOLTAGE:
+			*data = g_variant_new_double(devc->config[channel].output_voltage_last);
+			break;
+		case SR_CONF_OUTPUT_VOLTAGE_MAX:
+			*data = g_variant_new_double(devc->config[channel].output_voltage_max);
+			break;
+		case SR_CONF_OUTPUT_CURRENT:
+			*data = g_variant_new_double(devc->config[channel].output_current_last);
+			break;
+		case SR_CONF_OUTPUT_CURRENT_MAX:
+			*data = g_variant_new_double(devc->config[channel].output_current_max);
+			break;
+		case SR_CONF_OUTPUT_ENABLED:
+			*data = g_variant_new_boolean(devc->config[channel].output_enabled);
+			break;
+		default:
+			return SR_ERR_NA;
+		}
+	}
+
+	return ret;
+}
+
+static int find_str(const char *str, const char **strings, int array_size)
+{
+	int idx, i;
+
+	idx = -1;
+	for (i = 0; i < array_size; i++) {
+		if (!strcmp(str, strings[i])) {
+			idx = i;
+			break;
+		}
+	}
+
+	return idx;
+}
+
+static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	struct sr_channel *ch;
+	gdouble dval;
+	int channel, ret, ival;
+	const char *sval;
+	gboolean bval;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	ret = SR_OK;
+	devc = sdi->priv;
+	if (!cg) {
+		/* No channel group: global options. */
+		switch (key) {
+		case SR_CONF_OUTPUT_CHANNEL:
+			sval = g_variant_get_string(data, NULL);
+			if ((ival = find_str(sval, channel_modes,
+							ARRAY_SIZE(channel_modes))) == -1) {
+				ret = SR_ERR_ARG;
+				break;
+			}
+			if (devc->model->channel_modes && (1 << ival) == 0) {
+				/* Not supported on this model. */
+				ret = SR_ERR_ARG;
+			}
+			if (ival == devc->channel_mode_set)
+				/* Nothing to do. */
+				break;
+			devc->channel_mode_set = ival;
+			devc->config_dirty = TRUE;
+			break;
+		case SR_CONF_OVER_CURRENT_PROTECTION:
+			bval = g_variant_get_boolean(data);
+			if (bval == devc->over_current_protection_set)
+				/* Nothing to do. */
+				break;
+			devc->over_current_protection_set = bval;
+			devc->config_dirty = TRUE;
+			break;
+		default:
+			return SR_ERR_NA;
+		}
+	} else {
+		/* Channel group specified: per-channel options. */
+		/* We only ever have one channel per channel group in this driver. */
+		ch = cg->channels->data;
+		channel = ch->index;
+
+		switch (key) {
+		case SR_CONF_OUTPUT_VOLTAGE_MAX:
+			dval = g_variant_get_double(data);
+			if (dval < 0 || dval > devc->model->channels[channel].voltage[1])
+				ret = SR_ERR_ARG;
+			devc->config[channel].output_voltage_max = dval;
+			devc->config_dirty = TRUE;
+			break;
+		case SR_CONF_OUTPUT_CURRENT_MAX:
+			dval = g_variant_get_double(data);
+			if (dval < 0 || dval > devc->model->channels[channel].current[1])
+				ret = SR_ERR_ARG;
+			devc->config[channel].output_current_max = dval;
+			devc->config_dirty = TRUE;
+			break;
+		case SR_CONF_OUTPUT_ENABLED:
+			bval = g_variant_get_boolean(data);
+			if (bval == devc->config[channel].output_enabled_set)
+				/* Nothing to do. */
+				break;
+			devc->config[channel].output_enabled_set = bval;
+			devc->config_dirty = TRUE;
+			break;
+		default:
+			ret = SR_ERR_NA;
+		}
+	}
+
+
+	return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	struct sr_channel *ch;
+	GVariant *gvar;
+	GVariantBuilder gvb;
+	int channel, ret, i;
+
+	/* Always available, even without sdi. */
+	if (key == SR_CONF_SCAN_OPTIONS) {
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				scanopts, ARRAY_SIZE(scanopts), sizeof(int32_t));
+		return SR_OK;
+	}
+
+	if (!sdi)
+		return SR_ERR_ARG;
+	devc = sdi->priv;
+
+	ret = SR_OK;
+	if (!cg) {
+		/* No channel group: global options. */
+		switch (key) {
+		case SR_CONF_DEVICE_OPTIONS:
+			*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+					devopts, ARRAY_SIZE(devopts), sizeof(int32_t));
+			break;
+		case SR_CONF_OUTPUT_CHANNEL:
+			if (devc->model->channel_modes == CHANMODE_INDEPENDENT) {
+				/* The 1-channel models. */
+				*data = g_variant_new_strv(channel_modes, 1);
+			} else {
+				/* The other models support all modes. */
+				*data = g_variant_new_strv(channel_modes, ARRAY_SIZE(channel_modes));
+			}
+			break;
+		default:
+			return SR_ERR_NA;
+		}
+	} else {
+		/* Channel group specified: per-channel options. */
+		if (!sdi)
+			return SR_ERR_ARG;
+		/* We only ever have one channel per channel group in this driver. */
+		ch = cg->channels->data;
+		channel = ch->index;
+
+		switch (key) {
+		case SR_CONF_DEVICE_OPTIONS:
+			*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+					devopts_cg, ARRAY_SIZE(devopts_cg), sizeof(int32_t));
+			break;
+		case SR_CONF_OUTPUT_VOLTAGE_MAX:
+			g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
+			/* Min, max, step. */
+			for (i = 0; i < 3; i++) {
+				gvar = g_variant_new_double(devc->model->channels[channel].voltage[i]);
+				g_variant_builder_add_value(&gvb, gvar);
+			}
+			*data = g_variant_builder_end(&gvb);
+			break;
+		case SR_CONF_OUTPUT_CURRENT_MAX:
+			g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
+			/* Min, max, step. */
+			for (i = 0; i < 3; i++) {
+				gvar = g_variant_new_double(devc->model->channels[channel].current[i]);
+				g_variant_builder_add_value(&gvb, gvar);
+			}
+			*data = g_variant_builder_end(&gvb);
+			break;
+		default:
+			return SR_ERR_NA;
+		}
+	}
+
+	return ret;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+
+	devc = sdi->priv;
+	if (devc->config_dirty)
+		/* Some configuration changes were queued up but didn't
+		 * get sent to the device, likely because we were never
+		 * in acquisition mode. Send them out now. */
+		send_config(sdi);
+
+	return std_serial_dev_close(sdi);
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi,
+		void *cb_data)
+{
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+	uint8_t packet[PACKET_SIZE];
+
+	(void)cb_data;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	devc = sdi->priv;
+	memset(devc->packet, 0x44, PACKET_SIZE);
+	devc->packet_size = 0;
+
+	devc->acquisition_running = TRUE;
+
+	serial = sdi->conn;
+	serial_source_add(serial, G_IO_IN, 50, atten_pps3xxx_receive_data, (void *)sdi);
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	/* Send a "channel" configuration packet now. */
+	memset(packet, 0, PACKET_SIZE);
+	packet[0] = 0xaa;
+	packet[1] = 0xaa;
+	send_packet(sdi, packet);
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct dev_context *devc;
+
+	(void)cb_data;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	devc = sdi->priv;
+	devc->acquisition_running = FALSE;
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver atten_pps3203_driver_info = {
+	.name = "atten-pps3203",
+	.longname = "Atten PPS3203T-3S",
+	.api_version = 1,
+	.init = init,
+	.cleanup = cleanup,
+	.scan = scan_3203,
+	.dev_list = dev_list,
+	.dev_clear = NULL,
+	.config_get = config_get,
+	.config_set = config_set,
+	.config_list = config_list,
+	.dev_open = std_serial_dev_open,
+	.dev_close = dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/atten-pps3xxx/protocol.c b/hardware/atten-pps3xxx/protocol.c
new file mode 100644
index 0000000..5658d5d
--- /dev/null
+++ b/hardware/atten-pps3xxx/protocol.c
@@ -0,0 +1,165 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <errno.h>
+#include "protocol.h"
+
+static void dump_packet(char *msg, uint8_t *packet)
+{
+	int i;
+	char str[128];
+
+	str[0] = 0;
+	for (i = 0; i < PACKET_SIZE; i++)
+		sprintf(str + strlen(str), "%.2x ", packet[i]);
+	sr_dbg("%s: %s", msg, str);
+
+}
+
+static void handle_packet(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_analog analog;
+	float value, data[MAX_CHANNELS];
+	int offset, i;
+
+	devc = sdi->priv;
+	dump_packet("received", devc->packet);
+	packet.type = SR_DF_ANALOG;
+	packet.payload = &analog;
+	analog.channels = sdi->channels;
+	analog.num_samples = 1;
+
+	analog.mq = SR_MQ_VOLTAGE;
+	analog.unit = SR_UNIT_VOLT;
+	analog.mqflags = SR_MQFLAG_DC;
+	analog.data = data;
+	for (i = 0; i < devc->model->num_channels; i++) {
+		offset = 2 + i * 4;
+		value = ((devc->packet[offset] << 8) + devc->packet[offset + 1]) / 100.0;
+		analog.data[i] = value;
+		devc->config[i].output_voltage_last = value;
+	}
+	sr_session_send(sdi, &packet);
+
+	analog.mq = SR_MQ_CURRENT;
+	analog.unit = SR_UNIT_AMPERE;
+	analog.mqflags = 0;
+	analog.data = data;
+	for (i = 0; i < devc->model->num_channels; i++) {
+		offset = 4 + i * 4;
+		value = ((devc->packet[offset] << 8) + devc->packet[offset + 1]) / 1000.0;
+		analog.data[i] = value;
+		devc->config[i].output_current_last = value;
+	}
+	sr_session_send(sdi, &packet);
+
+	for (i = 0; i < devc->model->num_channels; i++)
+		devc->config[i].output_enabled = (devc->packet[15] & (1 << i)) ? TRUE : FALSE;
+
+	devc->over_current_protection = devc->packet[18] ? TRUE : FALSE;
+	if (devc->packet[19] < 3)
+		devc->channel_mode = devc->packet[19];
+
+}
+
+SR_PRIV void send_packet(const struct sr_dev_inst *sdi, uint8_t *packet)
+{
+	struct sr_serial_dev_inst *serial;
+
+	serial = sdi->conn;
+	if (serial_write(serial, packet, PACKET_SIZE) == -1)
+		sr_dbg("Failed to send packet: %s", strerror(errno));
+	dump_packet("sent", packet);
+}
+
+SR_PRIV void send_config(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	uint8_t packet[PACKET_SIZE];
+	int value, offset, i;
+
+	devc = sdi->priv;
+	memset(packet, 0, PACKET_SIZE);
+	packet[0] = 0xaa;
+	packet[1] = 0x20;
+	packet[14] = 0x01;
+	packet[16] = 0x01;
+	for (i = 0; i < devc->model->num_channels; i++) {
+		offset = 2 + i * 4;
+		value = devc->config[i].output_voltage_max * 100;
+		packet[offset] = (value >> 8) & 0xff;
+		packet[offset + 1] = value & 0xff;
+		value = devc->config[i].output_current_max * 1000;
+		packet[offset + 2] = (value >> 8) & 0xff;
+		packet[offset + 3] = value & 0xff;
+		if (devc->config[i].output_enabled_set)
+			packet[15] |= 1 << i;
+	}
+	packet[18] = devc->over_current_protection_set ? 1 : 0;
+	packet[19] = devc->channel_mode_set;
+	/* Checksum. */
+	value = 0;
+	for (i = 0; i < PACKET_SIZE - 1; i++)
+		value += packet[i];
+	packet[i] = value & 0xff;
+	send_packet(sdi, packet);
+	devc->config_dirty = FALSE;
+
+}
+
+SR_PRIV int atten_pps3xxx_receive_data(int fd, int revents, void *cb_data)
+{
+	struct dev_context *devc;
+	const struct sr_dev_inst *sdi;
+	struct sr_serial_dev_inst *serial;
+	struct sr_datafeed_packet packet;
+	unsigned char c;
+
+	(void)fd;
+
+	if (!(sdi = cb_data))
+		return TRUE;
+
+	if (!(devc = sdi->priv))
+		return TRUE;
+
+	serial = sdi->conn;
+	if (revents == G_IO_IN) {
+		if (serial_read_nonblocking(serial, &c, 1) < 0)
+			return TRUE;
+		devc->packet[devc->packet_size++] = c;
+		if (devc->packet_size == PACKET_SIZE) {
+			handle_packet(sdi);
+			devc->packet_size = 0;
+			if (devc->acquisition_running)
+				send_config(sdi);
+			else {
+				serial_source_remove(serial);
+				packet.type = SR_DF_END;
+				sr_session_send(sdi, &packet);
+			}
+		}
+	}
+
+	return TRUE;
+}
+
diff --git a/hardware/atten-pps3xxx/protocol.h b/hardware/atten-pps3xxx/protocol.h
new file mode 100644
index 0000000..1441305
--- /dev/null
+++ b/hardware/atten-pps3xxx/protocol.h
@@ -0,0 +1,102 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_ATTEN_PPS3XXX_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_ATTEN_PPS3XXX_PROTOCOL_H
+
+#include <stdint.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "atten-pps3xxx"
+
+/* Packets to/from the device. */
+#define PACKET_SIZE 24
+
+enum {
+	PPS_3203T_3S,
+	PPS_3203T_2S,
+	PPS_3205T_3S,
+	PPS_3205T_2S,
+	PPS_3003S,
+	PPS_3005S,
+};
+
+/* Maximum number of output channels handled by this driver. */
+#define MAX_CHANNELS 3
+
+#define CHANMODE_INDEPENDENT 1 << 0
+#define CHANMODE_SERIES      1 << 1
+#define CHANMODE_PARALLEL    1 << 2
+
+struct channel_spec {
+	/* Min, max, step. */
+	gdouble voltage[3];
+	gdouble current[3];
+};
+
+struct pps_model {
+	int modelid;
+	char *name;
+	int channel_modes;
+	int num_channels;
+	struct channel_spec channels[MAX_CHANNELS];
+};
+
+struct per_channel_config {
+	/* Received from device. */
+	gdouble output_voltage_last;
+	gdouble output_current_last;
+	gboolean output_enabled;
+	/* Set by frontend. */
+	gdouble output_voltage_max;
+	gdouble output_current_max;
+	gboolean output_enabled_set;
+};
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+	/* Model-specific information */
+	struct pps_model *model;
+
+	/* Acquisition state */
+	gboolean acquisition_running;
+
+	/* Operational state */
+	gboolean config_dirty;
+	struct per_channel_config *config;
+	/* Received from device. */
+	int channel_mode;
+	gboolean over_current_protection;
+	/* Set by frontend. */
+	int channel_mode_set;
+	gboolean over_current_protection_set;
+
+	/* Temporary state across callbacks */
+	uint8_t packet[PACKET_SIZE];
+	int packet_size;
+
+};
+
+SR_PRIV int atten_pps3xxx_receive_data(int fd, int revents, void *cb_data);
+SR_PRIV void send_packet(const struct sr_dev_inst *sdi, uint8_t *packet);
+SR_PRIV void send_config(const struct sr_dev_inst *sdi);
+
+#endif
diff --git a/hardware/brymen-bm86x/api.c b/hardware/brymen-bm86x/api.c
new file mode 100644
index 0000000..169721d
--- /dev/null
+++ b/hardware/brymen-bm86x/api.c
@@ -0,0 +1,312 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Aurelien Jacobs <aurel at gnuage.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "protocol.h"
+
+#define BRYMEN_BC86X "0820.0001"
+
+static const int32_t hwopts[] = {
+	SR_CONF_CONN,
+};
+
+static const int32_t hwcaps[] = {
+	SR_CONF_MULTIMETER,
+	SR_CONF_LIMIT_SAMPLES,
+	SR_CONF_LIMIT_MSEC,
+	SR_CONF_CONTINUOUS,
+};
+
+SR_PRIV struct sr_dev_driver brymen_bm86x_driver_info;
+static struct sr_dev_driver *di = &brymen_bm86x_driver_info;
+
+static int init(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+	GSList *usb_devices, *devices, *l;
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_dev_inst *sdi;
+	struct sr_usb_dev_inst *usb;
+	struct sr_config *src;
+	struct sr_channel *ch;
+	const char *conn;
+
+	drvc = di->priv;
+	drvc->instances = NULL;
+
+	conn = BRYMEN_BC86X;
+	for (l = options; l; l = l->next) {
+		src = l->data;
+		switch (src->key) {
+		case SR_CONF_CONN:
+			conn = g_variant_get_string(src->data, NULL);
+			break;
+		}
+	}
+
+	devices = NULL;
+	if (!(usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn))) {
+		g_slist_free_full(usb_devices, g_free);
+		return NULL;
+	}
+
+	for (l = usb_devices; l; l = l->next) {
+		usb = l->data;
+
+		if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE,
+		                            "Brymen", "BM869", NULL))) {
+			sr_err("sr_dev_inst_new returned NULL.");
+			return NULL;
+		}
+
+		if (!(devc = g_try_malloc0(sizeof(*devc)))) {
+			sr_err("Device context malloc failed.");
+			return NULL;
+		}
+
+		sdi->priv = devc;
+		sdi->driver = di;
+		if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
+			return NULL;
+		sdi->channels = g_slist_append(sdi->channels, ch);
+		if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P2")))
+			return NULL;
+		sdi->channels = g_slist_append(sdi->channels, ch);
+
+		sdi->inst_type = SR_INST_USB;
+		sdi->conn = usb;
+
+		drvc->instances = g_slist_append(drvc->instances, sdi);
+		devices = g_slist_append(devices, sdi);
+	}
+
+	return devices;
+}
+
+static GSList *dev_list(void)
+{
+	return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+	struct drv_context *drvc = di->priv;
+	struct sr_usb_dev_inst *usb;
+	struct dev_context *devc;
+	int ret;
+
+	usb = sdi->conn;
+	devc = sdi->priv;
+
+	if ((ret = sr_usb_open(drvc->sr_ctx->libusb_ctx, usb)) == SR_OK)
+		sdi->status = SR_ST_ACTIVE;
+
+	/* Detach kernel drivers which grabbed this device (if any). */
+	if (libusb_kernel_driver_active(usb->devhdl, 0) == 1) {
+		ret = libusb_detach_kernel_driver(usb->devhdl, 0);
+		if (ret < 0) {
+			sr_err("Failed to detach kernel driver: %s.",
+			       libusb_error_name(ret));
+			return SR_ERR;
+		}
+		devc->detached_kernel_driver = 1;
+		sr_dbg("Successfully detached kernel driver.");
+	} else {
+		sr_dbg("No need to detach a kernel driver.");
+	}
+
+	/* Claim interface 0. */
+	if ((ret = libusb_claim_interface(usb->devhdl, 0)) < 0) {
+		sr_err("Failed to claim interface 0: %s.",
+		       libusb_error_name(ret));
+		return SR_ERR;
+	}
+	sr_dbg("Successfully claimed interface 0.");
+
+	return ret;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+	struct sr_usb_dev_inst *usb;
+	struct dev_context *devc;
+	int ret;
+
+	usb = sdi->conn;
+	devc = sdi->priv;
+
+	if ((ret = libusb_release_interface(usb->devhdl, 0)))
+		sr_err("Failed to release interface 0: %s.\n", libusb_error_name(ret));
+	else
+		sr_dbg("Successfully released interface 0.\n");
+
+	if (!ret && devc->detached_kernel_driver) {
+		if ((ret = libusb_attach_kernel_driver(usb->devhdl, 0))) {
+			sr_err("Failed to attach kernel driver: %s.\n",
+			       libusb_error_name(ret));
+		} else {
+			devc->detached_kernel_driver = 0;
+			sr_dbg("Successfully attached kernel driver.\n");
+		}
+	}
+
+	libusb_close(usb->devhdl);
+
+	sdi->status = SR_ST_INACTIVE;
+
+	return ret;
+}
+
+static int cleanup(void)
+{
+	return std_dev_clear(di, NULL);
+}
+
+static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc = sdi->priv;
+
+	(void)cg;
+
+	switch (key) {
+	case SR_CONF_LIMIT_SAMPLES:
+		*data = g_variant_new_uint64(devc->limit_samples);
+		break;
+	case SR_CONF_LIMIT_MSEC:
+		*data = g_variant_new_uint64(devc->limit_msec);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+
+	(void)cg;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!(devc = sdi->priv)) {
+		sr_err("sdi->priv was NULL.");
+		return SR_ERR_BUG;
+	}
+
+	switch (key) {
+	case SR_CONF_LIMIT_SAMPLES:
+		devc->limit_samples = g_variant_get_uint64(data);
+		sr_dbg("Setting sample limit to %" PRIu64 ".", devc->limit_samples);
+		break;
+	case SR_CONF_LIMIT_MSEC:
+		devc->limit_msec = g_variant_get_uint64(data);
+		sr_dbg("Setting time limit to %" PRIu64 "ms.", devc->limit_msec);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	(void)sdi;
+	(void)cg;
+
+	switch (key) {
+	case SR_CONF_SCAN_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+		break;
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi,
+				    void *cb_data)
+{
+	struct dev_context *devc;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	devc = sdi->priv;
+	devc->session_cb_data = cb_data;
+	devc->start_time = g_get_monotonic_time();
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	sr_source_add(0, 0, 10, brymen_bm86x_receive_data, (void *)sdi);
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct sr_datafeed_packet packet;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	/* Send end packet to the session bus. */
+	packet.type = SR_DF_END;
+	sr_session_send(cb_data, &packet);
+
+	sr_source_remove(0);
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver brymen_bm86x_driver_info = {
+	.name = "brymen-bm86x",
+	.longname = "Brymen BM86X",
+	.api_version = 1,
+	.init = init,
+	.cleanup = cleanup,
+	.scan = scan,
+	.dev_list = dev_list,
+	.dev_clear = NULL,
+	.config_get = config_get,
+	.config_set = config_set,
+	.config_list = config_list,
+	.dev_open = dev_open,
+	.dev_close = dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/brymen-bm86x/protocol.c b/hardware/brymen-bm86x/protocol.c
new file mode 100644
index 0000000..b8fdcaa
--- /dev/null
+++ b/hardware/brymen-bm86x/protocol.c
@@ -0,0 +1,343 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Aurelien Jacobs <aurel at gnuage.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <math.h>
+#include "protocol.h"
+
+#define USB_TIMEOUT 500
+
+static char char_map[128] = {
+	[0x20] = '-',
+	[0x5F] = '0',
+	[0x50] = '1',
+	[0x6D] = '2',
+	[0x7C] = '3',
+	[0x72] = '4',
+	[0x3E] = '5',
+	[0x3F] = '6',
+	[0x54] = '7',
+	[0x7F] = '8',
+	[0x7E] = '9',
+	[0x0F] = 'C',
+	[0x27] = 'F',
+	[0x0B] = 'L',
+	[0x79] = 'd',
+	[0x10] = 'i',
+	[0x39] = 'o',
+};
+
+static int brymen_bm86x_parse_digits(const unsigned char *buf, int length,
+                                     char *str, float *floatval,
+                                     char *temp_unit, int flag)
+{
+	char c, *p = str;
+	int i, ret;
+
+	if (buf[0] & flag)
+		*p++ = '-';
+	for (i = 0; i < length; i++) {
+		if (i && i < 5 && buf[i+1] & 0x01)
+			*p++ = '.';
+		c = char_map[buf[i+1] >> 1];
+		if (i == 5 && (c == 'C' || c == 'F'))
+			*temp_unit = c;
+		else if (c)
+			*p++ = c;
+	}
+	*p = 0;
+
+	if ((ret = sr_atof_ascii(str, floatval))) {
+		sr_dbg("invalid float string: '%s'", str);
+		return ret;
+	}
+
+	return SR_OK;
+}
+
+static void brymen_bm86x_parse(unsigned char *buf, float *floatval,
+                               struct sr_datafeed_analog *analog)
+{
+	char str[16], temp_unit;
+	int ret1, ret2, over_limit;
+
+	ret1 = brymen_bm86x_parse_digits(buf+2, 6, str, &floatval[0],
+	                                 &temp_unit, 0x80);
+	over_limit = strstr(str, "0L") || strstr(str, "0.L");
+	ret2 = brymen_bm86x_parse_digits(buf+9, 4, str, &floatval[1],
+	                                 &temp_unit, 0x10);
+
+	/* main display */
+	if (ret1 == SR_OK || over_limit) {
+		/* SI unit */
+		if (buf[8] & 0x01) {
+			analog[0].mq = SR_MQ_VOLTAGE;
+			analog[0].unit = SR_UNIT_VOLT;
+			if (!strcmp(str, "diod"))
+				analog[0].mqflags |= SR_MQFLAG_DIODE;
+		} else if (buf[14] & 0x80) {
+			analog[0].mq = SR_MQ_CURRENT;
+			analog[0].unit = SR_UNIT_AMPERE;
+		} else if (buf[14] & 0x20) {
+			analog[0].mq = SR_MQ_CAPACITANCE;
+			analog[0].unit = SR_UNIT_FARAD;
+		} else if (buf[14] & 0x10) {
+			analog[0].mq = SR_MQ_CONDUCTANCE;
+			analog[0].unit = SR_UNIT_SIEMENS;
+		} else if (buf[15] & 0x01) {
+			analog[0].mq = SR_MQ_FREQUENCY;
+			analog[0].unit = SR_UNIT_HERTZ;
+		} else if (buf[10] & 0x01) {
+			analog[0].mq = SR_MQ_CONTINUITY;
+			analog[0].unit = SR_UNIT_OHM;
+		} else if (buf[15] & 0x10) {
+			analog[0].mq = SR_MQ_RESISTANCE;
+			analog[0].unit = SR_UNIT_OHM;
+		} else if (buf[15] & 0x02) {
+			analog[0].mq = SR_MQ_POWER;
+			analog[0].unit = SR_UNIT_DECIBEL_MW;
+		} else if (buf[15] & 0x80) {
+			analog[0].mq = SR_MQ_DUTY_CYCLE;
+			analog[0].unit = SR_UNIT_PERCENTAGE;
+		} else if (buf[ 2] & 0x0A) {
+			analog[0].mq = SR_MQ_TEMPERATURE;
+			if (temp_unit == 'F')
+				analog[0].unit = SR_UNIT_FAHRENHEIT;
+			else
+				analog[0].unit = SR_UNIT_CELSIUS;
+		}
+
+		/* when MIN MAX and AVG are displayed at the same time, remove them */
+		if ((buf[1] & 0xE0) == 0xE0)
+			buf[1] &= ~0xE0;
+
+		/* AC/DC/Auto flags */
+		if (buf[1] & 0x10)  analog[0].mqflags |= SR_MQFLAG_DC;
+		if (buf[2] & 0x01)  analog[0].mqflags |= SR_MQFLAG_AC;
+		if (buf[1] & 0x01)  analog[0].mqflags |= SR_MQFLAG_AUTORANGE;
+		if (buf[1] & 0x08)  analog[0].mqflags |= SR_MQFLAG_HOLD;
+		if (buf[1] & 0x20)  analog[0].mqflags |= SR_MQFLAG_MAX;
+		if (buf[1] & 0x40)  analog[0].mqflags |= SR_MQFLAG_MIN;
+		if (buf[1] & 0x80)  analog[0].mqflags |= SR_MQFLAG_AVG;
+		if (buf[3] & 0x01)  analog[0].mqflags |= SR_MQFLAG_RELATIVE;
+
+		/* when dBm is displayed, remove the m suffix so that it is
+		   not considered as the 10e-3 SI prefix */
+		if (buf[15] & 0x02)
+			buf[15] &= ~0x04;
+
+		/* SI prefix */
+		if (buf[14] & 0x40)  floatval[0] *= 1e-9;  /* n */
+		if (buf[15] & 0x08)  floatval[0] *= 1e-6;  /* µ */
+		if (buf[15] & 0x04)  floatval[0] *= 1e-3;  /* m */
+		if (buf[15] & 0x40)  floatval[0] *= 1e3;   /* k */
+		if (buf[15] & 0x20)  floatval[0] *= 1e6;   /* M */
+
+		if (over_limit)      floatval[0] = INFINITY;
+	}
+
+	/* secondary display */
+	if (ret2 == SR_OK) {
+		/* SI unit */
+		if (buf[14] & 0x08) {
+			analog[1].mq = SR_MQ_VOLTAGE;
+			analog[1].unit = SR_UNIT_VOLT;
+		} else if (buf[9] & 0x04) {
+			analog[1].mq = SR_MQ_CURRENT;
+			analog[1].unit = SR_UNIT_AMPERE;
+		} else if (buf[14] & 0x04) {
+			analog[1].mq = SR_MQ_FREQUENCY;
+			analog[1].unit = SR_UNIT_HERTZ;
+		} else if (buf[9] & 0x40) {
+			analog[1].mq = SR_MQ_TEMPERATURE;
+			if (temp_unit == 'F')
+				analog[1].unit = SR_UNIT_FAHRENHEIT;
+			else
+				analog[1].unit = SR_UNIT_CELSIUS;
+		}
+
+		/* AC flag */
+		if (buf[9] & 0x20)  analog[1].mqflags |= SR_MQFLAG_AC;
+
+		/* SI prefix */
+		if (buf[ 9] & 0x01)  floatval[1] *= 1e-6;  /* µ */
+		if (buf[ 9] & 0x02)  floatval[1] *= 1e-3;  /* m */
+		if (buf[14] & 0x02)  floatval[1] *= 1e3;   /* k */
+		if (buf[14] & 0x01)  floatval[1] *= 1e6;   /* M */
+	}
+
+	if (buf[9] & 0x80)
+		sr_spew("Battery is low.");
+}
+
+static void brymen_bm86x_handle_packet(const struct sr_dev_inst *sdi,
+                                       unsigned char *buf)
+{
+	struct dev_context *devc;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_analog analog[2];
+	float floatval[2];
+
+	devc = sdi->priv;
+
+	analog[0].mq = -1;
+	analog[0].mqflags = 0;
+
+	analog[1].mq = -1;
+	analog[1].mqflags = 0;
+
+	brymen_bm86x_parse(buf, floatval, analog);
+
+	if (analog[0].mq != -1) {
+		/* Got a measurement. */
+		analog[0].num_samples = 1;
+		analog[0].data = &floatval[0];
+		analog[0].channels = g_slist_append(NULL, sdi->channels->data);
+		packet.type = SR_DF_ANALOG;
+		packet.payload = &analog[0];
+		sr_session_send(devc->session_cb_data, &packet);
+		g_slist_free(analog[0].channels);
+	}
+
+	if (analog[1].mq != -1) {
+		/* Got a measurement. */
+		analog[1].num_samples = 1;
+		analog[1].data = &floatval[1];
+		analog[1].channels = g_slist_append(NULL, sdi->channels->next->data);
+		packet.type = SR_DF_ANALOG;
+		packet.payload = &analog[1];
+		sr_session_send(devc->session_cb_data, &packet);
+		g_slist_free(analog[1].channels);
+	}
+
+	if (analog[0].mq != -1 || analog[1].mq != -1)
+		devc->num_samples++;
+}
+
+static int brymen_bm86x_send_command(const struct sr_dev_inst *sdi)
+{
+	struct sr_usb_dev_inst *usb;
+	unsigned char buf[] = { 0x00, 0x86, 0x66 };
+	int ret;
+
+	usb = sdi->conn;
+
+	sr_dbg("Sending HID set report.");
+	ret = libusb_control_transfer(usb->devhdl,
+	                              LIBUSB_REQUEST_TYPE_CLASS  |
+	                              LIBUSB_RECIPIENT_INTERFACE |
+	                              LIBUSB_ENDPOINT_OUT,
+	                              9,     /* bRequest: HID set_report */
+	                              0x300, /* wValue: HID feature, report num 0 */
+	                              0,     /* wIndex: interface 0 */
+	                              buf, sizeof(buf), USB_TIMEOUT);
+
+	if (ret < 0) {
+		sr_err("HID feature report error: %s.", libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	if (ret != sizeof(buf)) {
+		sr_err("Short packet: sent %d/%ld bytes.", ret, sizeof(buf));
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+static int brymen_bm86x_read_interrupt(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_usb_dev_inst *usb;
+	unsigned char buf[24];
+	int ret, transferred;
+
+	devc = sdi->priv;
+	usb = sdi->conn;
+
+	sr_dbg("Reading HID interrupt report.");
+	/* Get data from EP1 using an interrupt transfer. */
+	ret = libusb_interrupt_transfer(usb->devhdl,
+	                                LIBUSB_ENDPOINT_IN | 1, /* EP1, IN */
+	                                buf, sizeof(buf),
+	                                &transferred, USB_TIMEOUT);
+
+	if (ret == LIBUSB_ERROR_TIMEOUT) {
+		if (++devc->interrupt_pending > 3)
+			devc->interrupt_pending = 0;
+		return SR_OK;
+	}
+
+	if (ret < 0) {
+		sr_err("USB receive error: %s.", libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	if (transferred != sizeof(buf)) {
+		sr_err("Short packet: received %d/%d bytes.", transferred, sizeof(buf));
+		return SR_ERR;
+	}
+
+	devc->interrupt_pending = 0;
+	brymen_bm86x_handle_packet(sdi, buf);
+
+	return SR_OK;
+}
+
+SR_PRIV int brymen_bm86x_receive_data(int fd, int revents, void *cb_data)
+{
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+	int64_t time;
+
+	(void)fd;
+	(void)revents;
+
+	if (!(sdi = cb_data))
+		return TRUE;
+
+	if (!(devc = sdi->priv))
+		return TRUE;
+
+	if (!devc->interrupt_pending) {
+		if (brymen_bm86x_send_command(sdi))
+			return FALSE;
+		devc->interrupt_pending = 1;
+	}
+
+	if (brymen_bm86x_read_interrupt(sdi))
+		return FALSE;
+
+	if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
+		sr_info("Requested number of samples reached, stopping.");
+		sdi->driver->dev_acquisition_stop(sdi, cb_data);
+		return TRUE;
+	}
+
+	if (devc->limit_msec) {
+		time = (g_get_monotonic_time() - devc->start_time) / 1000;
+		if (time > (int64_t)devc->limit_msec) {
+			sr_info("Requested time limit reached, stopping.");
+			sdi->driver->dev_acquisition_stop(sdi, cb_data);
+			return TRUE;
+		}
+	}
+
+	return TRUE;
+}
diff --git a/hardware/brymen-bm86x/protocol.h b/hardware/brymen-bm86x/protocol.h
new file mode 100644
index 0000000..d3d8955
--- /dev/null
+++ b/hardware/brymen-bm86x/protocol.h
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Aurelien Jacobs <aurel at gnuage.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_BRYMEN_BM86X_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_BRYMEN_BM86X_PROTOCOL_H
+
+#include <stdint.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "brymen-bm86x"
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+	/* Acquisition settings */
+	uint64_t limit_samples;    /**< The sampling limit (in number of samples).*/
+	uint64_t limit_msec;       /**< The time limit (in milliseconds). */
+	void *session_cb_data;     /**< Opaque pointer passed in by the frontend. */
+
+	/* Operational state */
+	int detached_kernel_driver;/**< Whether kernel driver was detached or not */
+	uint64_t num_samples;      /**< The number of already received samples. */
+	int64_t start_time;        /**< The time at which sampling started. */
+
+	/* Temporary state across callbacks */
+	int interrupt_pending;
+};
+
+SR_PRIV int brymen_bm86x_receive_data(int fd, int revents, void *cb_data);
+
+#endif
diff --git a/hardware/brymen-dmm/api.c b/hardware/brymen-dmm/api.c
new file mode 100644
index 0000000..41a3181
--- /dev/null
+++ b/hardware/brymen-dmm/api.c
@@ -0,0 +1,262 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me at gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "protocol.h"
+
+static const int32_t hwopts[] = {
+	SR_CONF_CONN,
+	SR_CONF_SERIALCOMM,
+};
+
+static const int32_t hwcaps[] = {
+	SR_CONF_MULTIMETER,
+	SR_CONF_LIMIT_SAMPLES,
+	SR_CONF_CONTINUOUS,
+	SR_CONF_LIMIT_MSEC,
+};
+
+SR_PRIV struct sr_dev_driver brymen_bm857_driver_info;
+static struct sr_dev_driver *di = &brymen_bm857_driver_info;
+
+static int init(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *brymen_scan(const char *conn, const char *serialcomm)
+{
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+	struct drv_context *drvc;
+	struct sr_channel *ch;
+	struct sr_serial_dev_inst *serial;
+	GSList *devices;
+	int ret;
+	uint8_t buf[128];
+	size_t len;
+
+	if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+		return NULL;
+
+	if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+		return NULL;
+
+	sr_info("Probing port %s.", conn);
+
+	devices = NULL;
+
+	/* Request reading */
+	if ((ret = brymen_packet_request(serial)) < 0) {
+		sr_err("Unable to send command: %d.", ret);
+		goto scan_cleanup;
+	}
+
+	len = 128;
+	ret = brymen_stream_detect(serial, buf, &len, brymen_packet_length,
+			     brymen_packet_is_valid, 1000, 9600);
+	if (ret != SR_OK)
+		goto scan_cleanup;
+
+	sr_info("Found device on port %s.", conn);
+
+	if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "Brymen", "BM85x", NULL)))
+		goto scan_cleanup;
+
+	if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+		sr_err("Device context malloc failed.");
+		goto scan_cleanup;
+	}
+
+	sdi->inst_type = SR_INST_SERIAL;
+	sdi->conn = serial;
+	drvc = di->priv;
+	sdi->priv = devc;
+	sdi->driver = di;
+
+	if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
+		goto scan_cleanup;
+
+	sdi->channels = g_slist_append(sdi->channels, ch);
+	drvc->instances = g_slist_append(drvc->instances, sdi);
+	devices = g_slist_append(devices, sdi);
+
+scan_cleanup:
+	serial_close(serial);
+
+	return devices;
+}
+
+static GSList *scan(GSList *options)
+{
+	struct drv_context *drvc;
+	struct sr_config *src;
+	GSList *devices, *l;
+	const char *conn, *serialcomm;
+
+	devices = NULL;
+	drvc = di->priv;
+	drvc->instances = NULL;
+
+	conn = serialcomm = NULL;
+	for (l = options; l; l = l->next) {
+		src = l->data;
+		switch (src->key) {
+		case SR_CONF_CONN:
+			conn = g_variant_get_string(src->data, NULL);
+			break;
+		case SR_CONF_SERIALCOMM:
+			serialcomm = g_variant_get_string(src->data, NULL);
+			break;
+		}
+	}
+	if (!conn)
+		return NULL;
+
+	if (serialcomm) {
+		/* Use the provided comm specs. */
+		devices = brymen_scan(conn, serialcomm);
+	} else {
+		/* But 9600/8n1 should work all of the time. */
+		devices = brymen_scan(conn, "9600/8n1/dtr=1/rts=1");
+	}
+
+	return devices;
+}
+
+static GSList *dev_list(void)
+{
+	return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int cleanup(void)
+{
+	return std_dev_clear(di, NULL);
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	int ret;
+
+	(void)cg;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!(devc = sdi->priv)) {
+		sr_err("sdi->priv was NULL.");
+		return SR_ERR_BUG;
+	}
+
+	ret = SR_OK;
+	switch (id) {
+	case SR_CONF_LIMIT_SAMPLES:
+		devc->limit_samples = g_variant_get_uint64(data);
+		break;
+	case SR_CONF_LIMIT_MSEC:
+		devc->limit_msec = g_variant_get_uint64(data);
+		break;
+	default:
+		ret = SR_ERR_NA;
+	}
+
+	return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	(void)sdi;
+	(void)cg;
+
+	switch (key) {
+	case SR_CONF_SCAN_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+		break;
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!(devc = sdi->priv)) {
+		sr_err("sdi->priv was NULL.");
+		return SR_ERR_BUG;
+	}
+
+	devc->cb_data = cb_data;
+
+	/*
+	 * Reset the number of samples to take. If we've already collected our
+	 * quota, but we start a new session, and don't reset this, we'll just
+	 * quit without acquiring any new samples.
+	 */
+	devc->num_samples = 0;
+	devc->starttime = g_get_monotonic_time();
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	/* Poll every 50ms, or whenever some data comes in. */
+	serial = sdi->conn;
+	serial_source_add(serial, G_IO_IN, 50,
+		      brymen_dmm_receive_data, (void *)sdi);
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close,
+			sdi->conn, LOG_PREFIX);
+}
+
+SR_PRIV struct sr_dev_driver brymen_bm857_driver_info = {
+	.name = "brymen-bm857",
+	.longname = "Brymen BM857",
+	.api_version = 1,
+	.init = init,
+	.cleanup = cleanup,
+	.scan = scan,
+	.dev_list = dev_list,
+	.dev_clear = NULL,
+	.config_get = NULL,
+	.config_set = config_set,
+	.config_list = config_list,
+	.dev_open = std_serial_dev_open,
+	.dev_close = std_serial_dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/brymen-dmm/parser.c b/hardware/brymen-dmm/parser.c
new file mode 100644
index 0000000..e4b1227
--- /dev/null
+++ b/hardware/brymen-dmm/parser.c
@@ -0,0 +1,288 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me at gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "protocol.h"
+
+#define MAX_PACKET_LEN 22
+
+/* Flags passed from the DMM. */
+struct brymen_flags {
+	gboolean is_low_batt, is_decibel, is_duty_cycle, is_hertz, is_amp;
+	gboolean is_beep, is_ohm, is_fahrenheit, is_celsius, is_capacitance;
+	gboolean is_diode, is_volt, is_dc, is_ac;
+};
+
+struct bm850_command {
+	uint8_t dle;
+	uint8_t stx;
+	uint8_t cmd;
+	uint8_t arg[2];
+	uint8_t checksum;
+	uint8_t dle2;
+	uint8_t etx;
+};
+
+struct brymen_header {
+	uint8_t dle;
+	uint8_t stx;
+	uint8_t cmd;
+	uint8_t len;
+};
+
+struct brymen_tail {
+	uint8_t checksum;
+	uint8_t dle;
+	uint8_t etx;
+};
+
+/*
+ * We only have one command because we only support the BM-857. However, the
+ * driver is easily extensible to support more models, as the protocols are
+ * very similar.
+ */
+enum {
+	BM_CMD_REQUEST_READING = 0x00,
+};
+
+static int bm_send_command(uint8_t command, uint8_t arg1, uint8_t arg2,
+			   struct sr_serial_dev_inst *serial)
+{
+	struct bm850_command cmdout;
+	int written;
+
+	cmdout.dle = 0x10;
+	cmdout.stx = 0x02;
+	cmdout.cmd = command;
+	cmdout.arg[0] = arg1;
+	cmdout.arg[1] = arg2;
+	cmdout.checksum = arg1 ^ arg2;
+	cmdout.dle2 = 0x10;
+	cmdout.etx = 0x03;
+
+	/* TODO: How to compute the checksum? Hardware seems to ignore it. */
+
+	/* Request reading. */
+	written = serial_write(serial, &cmdout, sizeof(cmdout));
+	if (written != sizeof(cmdout))
+		return SR_ERR;
+
+	return SR_OK;
+}
+
+SR_PRIV int brymen_packet_request(struct sr_serial_dev_inst *serial)
+{
+	return bm_send_command(BM_CMD_REQUEST_READING, 0, 0, serial);
+}
+
+SR_PRIV int brymen_packet_length(const uint8_t *buf, int *len)
+{
+	struct brymen_header *hdr;
+	int packet_len;
+	size_t buflen;
+
+	buflen = *len;
+	hdr = (void *)buf;
+
+	/* Did we receive a complete header yet? */
+	if (buflen < sizeof(*hdr))
+		return PACKET_NEED_MORE_DATA;
+
+	if (hdr->dle != 0x10 || hdr->stx != 0x02)
+		return PACKET_INVALID_HEADER;
+
+	/* Our packet includes the header, the payload, and the tail. */
+	packet_len = sizeof(*hdr) + hdr->len + sizeof(struct brymen_tail);
+
+	/* In case we pick up an invalid header, limit our search. */
+	if (packet_len > MAX_PACKET_LEN) {
+		sr_spew("Header specifies an invalid payload length: %i.",
+			hdr->len);
+		return PACKET_INVALID_HEADER;
+	}
+
+	*len = packet_len;
+	sr_spew("Expecting a %d-byte packet.", *len);
+	return PACKET_HEADER_OK;
+}
+
+SR_PRIV gboolean brymen_packet_is_valid(const uint8_t *buf)
+{
+	struct brymen_header *hdr;
+	struct brymen_tail *tail;
+	int i;
+	uint8_t chksum = 0;
+	uint8_t *payload;
+	
+	payload = (uint8_t *)(buf + sizeof(struct brymen_header));
+
+	hdr = (void *)buf;
+	tail = (void *)(payload + hdr->len);
+	
+	for (i = 0; i< hdr->len; i++)
+		chksum ^= payload[i];
+	
+	if (tail->checksum != chksum) {
+		sr_dbg("Packet has invalid checksum 0x%.2x. Expected 0x%.2x.",
+		       chksum, tail->checksum);
+		return FALSE;
+	}
+	
+	return TRUE;
+}
+
+static int parse_value(const char *strbuf, int len, float *floatval)
+{
+	int s, d;
+	char str[32];
+
+	if (strstr(strbuf, "OL")) {
+		sr_dbg("Overlimit.");
+		*floatval = INFINITY;
+		return SR_OK;
+	}
+
+	memset(str, 0, sizeof(str));
+	/* Spaces may interfere with parsing the exponent. Strip them. */
+	for (s = 0, d = 0; s < len; s++) {
+		if (strbuf[s] != ' ')
+			str[d++] = strbuf[s];
+	}
+	if (sr_atof_ascii(str, floatval) != SR_OK)
+		return SR_ERR;
+
+	return SR_OK;
+}
+
+static void parse_flags(const uint8_t *buf, struct brymen_flags *info)
+{
+	info->is_low_batt	= (buf[4 + 3] & (1 << 7)) != 0;
+
+	info->is_decibel	= (buf[4 + 1] & (1 << 5)) != 0;
+	info->is_duty_cycle	= (buf[4 + 1] & (1 << 3)) != 0;
+	info->is_hertz		= (buf[4 + 1] & (1 << 2)) != 0;
+	info->is_amp		= (buf[4 + 1] & (1 << 1)) != 0;
+	info->is_beep		= (buf[4 + 1] & (1 << 0)) != 0;
+
+	info->is_ohm		= (buf[4 + 0] & (1 << 7)) != 0;
+	info->is_fahrenheit	= (buf[4 + 0] & (1 << 6)) != 0;
+	info->is_celsius	= (buf[4 + 0] & (1 << 5)) != 0;
+	info->is_diode		= (buf[4 + 0] & (1 << 4)) != 0;
+	info->is_capacitance	= (buf[4 + 0] & (1 << 3)) != 0;
+	info->is_volt		= (buf[4 + 0] & (1 << 2)) != 0;
+	info->is_dc		= (buf[4 + 0] & (1 << 1)) != 0;
+	info->is_ac		= (buf[4 + 0] & (1 << 0)) != 0;
+}
+
+SR_PRIV int brymen_parse(const uint8_t *buf, float *floatval,
+		struct sr_datafeed_analog *analog, void *info)
+{
+	struct brymen_flags flags;
+	struct brymen_header *hdr;
+	uint8_t *bfunc;
+	int asciilen;
+
+	(void)info;
+
+	hdr = (void *)buf;
+	bfunc = (uint8_t *)(buf + sizeof(struct brymen_header));
+
+	analog->mqflags = 0;
+
+	/* Give some debug info about the package. */
+	asciilen = hdr->len - 4;
+	sr_dbg("DMM flags: %.2x %.2x %.2x %.2x",
+	       bfunc[3], bfunc[2], bfunc[1], bfunc[0]);
+	/* Value is an ASCII string. */
+	sr_dbg("DMM packet: \"%.*s\"", asciilen, bfunc + 4);
+
+	parse_flags(buf, &flags);
+	if (parse_value((const char *)(bfunc + 4), asciilen, floatval) != SR_OK)
+		return SR_ERR;
+
+	if (flags.is_volt) {
+		analog->mq = SR_MQ_VOLTAGE;
+		analog->unit = SR_UNIT_VOLT;
+	}
+	if (flags.is_amp) {
+		analog->mq = SR_MQ_CURRENT;
+		analog->unit = SR_UNIT_AMPERE;
+	}
+	if (flags.is_ohm) {
+		if (flags.is_beep)
+			analog->mq = SR_MQ_CONTINUITY;
+		else
+			analog->mq = SR_MQ_RESISTANCE;
+		analog->unit = SR_UNIT_OHM;
+	}
+	if (flags.is_hertz) {
+		analog->mq = SR_MQ_FREQUENCY;
+		analog->unit = SR_UNIT_HERTZ;
+	}
+	if (flags.is_duty_cycle) {
+		analog->mq = SR_MQ_DUTY_CYCLE;
+		analog->unit = SR_UNIT_PERCENTAGE;
+	}
+	if (flags.is_capacitance) {
+		analog->mq = SR_MQ_CAPACITANCE;
+		analog->unit = SR_UNIT_FARAD;
+	}
+	if (flags.is_fahrenheit) {
+		analog->mq = SR_MQ_TEMPERATURE;
+		analog->unit = SR_UNIT_FAHRENHEIT;
+	}
+	if (flags.is_celsius) {
+		analog->mq = SR_MQ_TEMPERATURE;
+		analog->unit = SR_UNIT_CELSIUS;
+	}
+	if (flags.is_capacitance) {
+		analog->mq = SR_MQ_CAPACITANCE;
+		analog->unit = SR_UNIT_FARAD;
+	}
+
+	/*
+	 * The high-end Brymen models have a configurable reference impedance.
+	 * When the reference impedance is changed, the DMM sends one packet
+	 * with the value of the new reference impedance. Both decibel and ohm
+	 * flags are set in this case, so we must be careful to correctly
+	 * identify the value as ohm, not dBmW.
+	 */
+	if (flags.is_decibel && !flags.is_ohm) {
+		analog->mq = SR_MQ_POWER;
+		analog->unit = SR_UNIT_DECIBEL_MW;
+		/*
+		 * For some reason, dBm measurements are sent by the multimeter
+		 * with a value three orders of magnitude smaller than the
+		 * displayed value.
+		 */
+		*floatval *= 1000;
+	}
+
+	if (flags.is_diode)
+		analog->mqflags |= SR_MQFLAG_DIODE;
+	/* We can have both AC+DC in a single measurement. */
+	if (flags.is_ac)
+		analog->mqflags |= SR_MQFLAG_AC;
+	if (flags.is_dc)
+		analog->mqflags |= SR_MQFLAG_DC;
+
+	if (flags.is_low_batt)
+		sr_info("Low battery!");
+
+	return SR_OK;
+}
diff --git a/hardware/brymen-dmm/protocol.c b/hardware/brymen-dmm/protocol.c
new file mode 100644
index 0000000..dff7b98
--- /dev/null
+++ b/hardware/brymen-dmm/protocol.c
@@ -0,0 +1,260 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me at gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "protocol.h"
+
+static void handle_packet(const uint8_t *buf, struct sr_dev_inst *sdi)
+{
+	float floatval;
+	struct dev_context *devc;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_analog analog;
+
+	devc = sdi->priv;
+
+	analog.num_samples = 1;
+	analog.mq = -1;
+
+	if (brymen_parse(buf, &floatval, &analog, NULL) != SR_OK)
+		return;
+	analog.data = &floatval;
+
+	analog.channels = sdi->channels;
+
+	if (analog.mq != -1) {
+		/* Got a measurement. */
+		packet.type = SR_DF_ANALOG;
+		packet.payload = &analog;
+		sr_session_send(devc->cb_data, &packet);
+		devc->num_samples++;
+	}
+}
+
+static void handle_new_data(struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	int len, status, offset = 0;
+	struct sr_serial_dev_inst *serial;
+
+	devc = sdi->priv;
+	serial = sdi->conn;
+
+	/* Try to get as much data as the buffer can hold. */
+	len = DMM_BUFSIZE - devc->buflen;
+	len = serial_read(serial, devc->buf + devc->buflen, len);
+	if (len < 1) {
+		sr_err("Serial port read error: %d.", len);
+		return;
+	}
+	devc->buflen += len;
+	status = PACKET_INVALID_HEADER;
+
+	/* Now look for packets in that data. */
+	while (status != PACKET_NEED_MORE_DATA) {
+		/* We don't have a header, look for one. */
+		if (devc->next_packet_len == 0) {
+			len = devc->buflen - offset;
+			status = brymen_packet_length(devc->buf + offset, &len);
+			if (status == PACKET_HEADER_OK) {
+				/* We know how large the packet will be. */
+				devc->next_packet_len = len;
+			} else if (status == PACKET_NEED_MORE_DATA) {
+				/* We didn't yet receive the full header. */
+				devc->next_packet_len = 0;
+				break;
+			} else {
+				/* Invalid header. Move on. */
+				devc->next_packet_len = 0;
+				offset++;
+				continue;
+			}
+		}
+
+		/* We know how the packet size, but did we receive all of it? */
+		if (devc->buflen - offset < devc->next_packet_len)
+			break;
+
+		/* We should have a full packet here, so we can check it. */
+		if (brymen_packet_is_valid(devc->buf + offset)) {
+			handle_packet(devc->buf + offset, sdi);
+			offset += devc->next_packet_len;
+		} else {
+			offset++;
+		}
+
+		/* We are done with this packet. Look for a new one. */
+		devc->next_packet_len = 0;
+	}
+
+	/* If we have any data left, move it to the beginning of our buffer. */
+	memmove(devc->buf, devc->buf + offset, devc->buflen - offset);
+	devc->buflen -= offset;
+}
+
+SR_PRIV int brymen_dmm_receive_data(int fd, int revents, void *cb_data)
+{
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+	int ret;
+	int64_t time;
+
+	(void)fd;
+
+	if (!(sdi = cb_data))
+		return TRUE;
+
+	if (!(devc = sdi->priv))
+		return TRUE;
+
+	serial = sdi->conn;
+
+	if (revents == G_IO_IN) {
+		/* Serial data arrived. */
+		handle_new_data(sdi);
+	} else {
+		/* Timeout, send another packet request. */
+		if ((ret = brymen_packet_request(serial)) < 0) {
+			sr_err("Failed to request packet: %d.", ret);
+			return FALSE;
+		}
+	}
+
+	if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
+		sr_info("Requested number of samples reached, stopping.");
+		sdi->driver->dev_acquisition_stop(sdi, cb_data);
+		return TRUE;
+	}
+
+	if (devc->limit_msec) {
+		time = (g_get_monotonic_time() - devc->starttime) / 1000;
+		if (time > (int64_t)devc->limit_msec) {
+			sr_info("Requested time limit reached, stopping.");
+			sdi->driver->dev_acquisition_stop(sdi, cb_data);
+			return TRUE;
+		}
+	}
+
+	return TRUE;
+}
+
+/**
+ * Try to find a valid packet in a serial data stream.
+ *
+ * @param serial Previously initialized serial port structure.
+ * @param buf Buffer containing the bytes to write.
+ * @param buflen Size of the buffer.
+ * @param get_packet_size Callback that assesses the size of incoming packets.
+ * @param is_valid Callback that assesses whether the packet is valid or not.
+ * @param timeout_ms The timeout after which, if no packet is detected, to
+ *                   abort scanning.
+ * @param baudrate The baudrate of the serial port. This parameter is not
+ *                 critical, but it helps fine tune the serial port polling
+ *                 delay.
+ *
+ * @return SR_OK if a valid packet is found within the given timeout,
+ *         SR_ERR upon failure.
+ */
+SR_PRIV int brymen_stream_detect(struct sr_serial_dev_inst *serial,
+				uint8_t *buf, size_t *buflen,
+				packet_length_t get_packet_size,
+				packet_valid_callback is_valid,
+				uint64_t timeout_ms, int baudrate)
+{
+	int64_t start, time, byte_delay_us;
+	size_t ibuf, i, maxlen;
+	int status, len, packet_len, stream_len;
+
+	maxlen = *buflen;
+
+	sr_dbg("Detecting packets on %s (timeout = %" PRIu64
+	       "ms, baudrate = %d).", serial->port, timeout_ms, baudrate);
+
+	/* Assume 8n1 transmission. That is 10 bits for every byte. */
+	byte_delay_us = 10 * (1000000 / baudrate);
+	start = g_get_monotonic_time();
+
+	packet_len = i = ibuf = len = 0;
+	while (ibuf < maxlen) {
+		len = serial_read(serial, &buf[ibuf], maxlen - ibuf);
+		if (len > 0) {
+			ibuf += len;
+			sr_spew("Read %d bytes.", len);
+		}
+
+		time = g_get_monotonic_time() - start;
+		time /= 1000;
+
+		stream_len = ibuf - i;
+		if (stream_len > 0 && packet_len == 0) {
+			/* How large of a packet are we expecting? */
+			packet_len = stream_len;
+			status = get_packet_size(&buf[i], &packet_len);
+			switch(status) {
+			case PACKET_HEADER_OK:
+				/* We know how much data we need to wait for. */
+				break;
+			case PACKET_NEED_MORE_DATA:
+				/* We did not receive the full header. */
+				packet_len = 0;
+				break;
+			case PACKET_INVALID_HEADER:
+			default:
+				/*
+				 * We had enough data, but here was an error in
+				 * parsing the header. Restart parsing from the
+				 * next byte.
+				 */
+				packet_len = 0;
+				i++;
+				break;
+			}
+		}
+
+		if ((stream_len >= packet_len) && (packet_len != 0)) {
+			/* We have at least a packet's worth of data. */
+			if (is_valid(&buf[i])) {
+				sr_spew("Found valid %d-byte packet after "
+					"%" PRIu64 "ms.", packet_len, time);
+				*buflen = ibuf;
+				return SR_OK;
+			} else {
+				sr_spew("Got %d bytes, but not a valid "
+					"packet.", packet_len);
+
+			}
+
+			/* Not a valid packet. Continue searching. */
+			i++;
+			packet_len = 0;
+		}
+
+		if (time >= (int64_t)timeout_ms) {
+			/* Timeout */
+			sr_dbg("Detection timed out after %dms.", time);
+			break;
+		}
+		g_usleep(byte_delay_us);
+	}
+
+	*buflen = ibuf;
+	sr_err("Didn't find a valid packet (read %d bytes).", ibuf);
+
+	return SR_ERR;
+}
diff --git a/hardware/brymen-dmm/protocol.h b/hardware/brymen-dmm/protocol.h
new file mode 100644
index 0000000..7c9aaae
--- /dev/null
+++ b/hardware/brymen-dmm/protocol.h
@@ -0,0 +1,88 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me at gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_BRYMEN_DMM_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_BRYMEN_DMM_PROTOCOL_H
+
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "brymen-dmm"
+
+#define DMM_BUFSIZE 256
+
+enum packet_len_status {
+	PACKET_HEADER_OK,
+	PACKET_NEED_MORE_DATA,
+	PACKET_INVALID_HEADER,
+};
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+	/** The current sampling limit (in number of samples). */
+	uint64_t limit_samples;
+
+	/** The current sampling limit (in ms). */
+	uint64_t limit_msec;
+
+	/** Opaque pointer passed in by the frontend. */
+	void *cb_data;
+
+	/** The current number of already received samples. */
+	uint64_t num_samples;
+
+	/** Start time of acquisition session */
+	int64_t starttime;
+
+	uint8_t buf[DMM_BUFSIZE];
+	int bufoffset;
+	int buflen;
+	int next_packet_len;
+};
+
+/**
+ * Callback that assesses the size and status of the incoming packet.
+ *
+ * @return PACKET_HEADER_OK - This is a proper packet header.
+ *         PACKET_NEED_MORE_DATA The buffer does not contain the entire header.
+ *         PACKET_INVALID_HEADER Not a valid start of packet.
+ */
+typedef int (*packet_length_t)(const uint8_t *buf, int *len);
+
+SR_PRIV int brymen_dmm_receive_data(int fd, int revents, void *cb_data);
+SR_PRIV int brymen_packet_request(struct sr_serial_dev_inst *serial);
+
+SR_PRIV int brymen_packet_length(const uint8_t *buf, int *len);
+SR_PRIV gboolean brymen_packet_is_valid(const uint8_t *buf);
+
+SR_PRIV int brymen_parse(const uint8_t *buf, float *floatval,
+		struct sr_datafeed_analog *analog, void *info);
+
+SR_PRIV int brymen_stream_detect(struct sr_serial_dev_inst *serial,
+				 uint8_t *buf, size_t *buflen,
+				 packet_length_t get_packet_size,
+				 packet_valid_callback is_valid,
+				 uint64_t timeout_ms, int baudrate);
+
+#endif
diff --git a/hardware/cem-dt-885x/api.c b/hardware/cem-dt-885x/api.c
new file mode 100644
index 0000000..34853a0
--- /dev/null
+++ b/hardware/cem-dt-885x/api.c
@@ -0,0 +1,432 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include "protocol.h"
+
+#define SERIALCOMM "9600/8n1"
+/* 23ms is the longest interval between tokens. */
+#define MAX_SCAN_TIME 25 * 1000
+
+static const int32_t hwopts[] = {
+	SR_CONF_CONN,
+};
+
+static const int32_t hwcaps[] = {
+	SR_CONF_SOUNDLEVELMETER,
+	SR_CONF_LIMIT_SAMPLES,
+	SR_CONF_CONTINUOUS,
+	SR_CONF_SPL_WEIGHT_FREQ,
+	SR_CONF_SPL_WEIGHT_TIME,
+	SR_CONF_SPL_MEASUREMENT_RANGE,
+	SR_CONF_DATALOG,
+	SR_CONF_HOLD_MAX,
+	SR_CONF_HOLD_MIN,
+	SR_CONF_POWER_OFF,
+	SR_CONF_DATA_SOURCE,
+};
+
+static const char *weight_freq[] = {
+	"A",
+	"C",
+};
+
+static const char *weight_time[] = {
+	"F",
+	"S",
+};
+
+static const uint64_t meas_ranges[][2] = {
+	{ 30, 130 },
+	{ 30, 80 },
+	{ 50, 100 },
+	{ 80, 130 },
+};
+
+static const char *data_sources[] = {
+	"Live",
+	"Memory",
+};
+SR_PRIV struct sr_dev_driver cem_dt_885x_driver_info;
+static struct sr_dev_driver *di = &cem_dt_885x_driver_info;
+
+
+static int init(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_config *src;
+	struct sr_serial_dev_inst *serial;
+	struct sr_dev_inst *sdi;
+	struct sr_channel *ch;
+	GSList *l, *devices;
+	gint64 start;
+	const char *conn;
+	unsigned char c;
+
+	conn = NULL;
+	for (l = options; l; l = l->next) {
+		src = l->data;
+		if (src->key == SR_CONF_CONN)
+			conn = g_variant_get_string(src->data, NULL);
+	}
+	if (!conn)
+		return NULL;
+
+	if (!(serial = sr_serial_dev_inst_new(conn, SERIALCOMM)))
+		return NULL;
+
+	if (serial_open(serial, SERIAL_RDONLY | SERIAL_NONBLOCK) != SR_OK)
+		return NULL;
+
+	devices = NULL;
+	drvc = di->priv;
+	start = g_get_monotonic_time();
+	while (g_get_monotonic_time() - start < MAX_SCAN_TIME) {
+		if (serial_read(serial, &c, 1) == 1 && c == 0xa5) {
+			/* Found one. */
+			if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "CEM",
+					"DT-885x", NULL)))
+				return NULL;
+
+			if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+				sr_dbg("Device context malloc failed.");
+				return NULL;
+			}
+			devc->cur_mqflags = 0;
+			devc->recording = -1;
+			devc->cur_meas_range = 0;
+			devc->cur_data_source = DATA_SOURCE_LIVE;
+			devc->enable_data_source_memory = FALSE;
+
+			if (!(sdi->conn = sr_serial_dev_inst_new(conn, SERIALCOMM)))
+				return NULL;
+
+			sdi->inst_type = SR_INST_SERIAL;
+			sdi->priv = devc;
+			sdi->driver = di;
+			if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "SPL")))
+				return NULL;
+			sdi->channels = g_slist_append(sdi->channels, ch);
+			drvc->instances = g_slist_append(drvc->instances, sdi);
+			devices = g_slist_append(devices, sdi);
+			break;
+		}
+		/* It takes about 1ms for a byte to come in. */
+		g_usleep(1000);
+	}
+
+	serial_close(serial);
+
+	return devices;
+}
+
+static GSList *dev_list(void)
+{
+	return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+	struct sr_serial_dev_inst *serial;
+
+	serial = sdi->conn;
+	if (serial_open(serial, SERIAL_RDWR) != SR_OK)
+		return SR_ERR;
+
+	sdi->status = SR_ST_ACTIVE;
+
+	return SR_OK;
+}
+
+static int cleanup(void)
+{
+	return std_dev_clear(di, NULL);
+}
+
+static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	GVariant *range[2];
+	uint64_t low, high;
+	int tmp, ret;
+
+	(void)cg;
+
+	if (!sdi)
+		return SR_ERR_ARG;
+
+	devc = sdi->priv;
+	ret = SR_OK;
+	switch (key) {
+	case SR_CONF_LIMIT_SAMPLES:
+		*data = g_variant_new_uint64(devc->limit_samples);
+		break;
+	case SR_CONF_DATALOG:
+		if ((ret = cem_dt_885x_recording_get(sdi, &tmp)) == SR_OK)
+			*data = g_variant_new_boolean(tmp);
+		break;
+	case SR_CONF_SPL_WEIGHT_FREQ:
+		tmp = cem_dt_885x_weight_freq_get(sdi);
+		if (tmp == SR_MQFLAG_SPL_FREQ_WEIGHT_A)
+			*data = g_variant_new_string("A");
+		else if (tmp == SR_MQFLAG_SPL_FREQ_WEIGHT_C)
+			*data = g_variant_new_string("C");
+		else
+			return SR_ERR;
+		break;
+	case SR_CONF_SPL_WEIGHT_TIME:
+		tmp = cem_dt_885x_weight_time_get(sdi);
+		if (tmp == SR_MQFLAG_SPL_TIME_WEIGHT_F)
+			*data = g_variant_new_string("F");
+		else if (tmp == SR_MQFLAG_SPL_TIME_WEIGHT_S)
+			*data = g_variant_new_string("S");
+		else
+			return SR_ERR;
+		break;
+	case SR_CONF_HOLD_MAX:
+		if ((ret = cem_dt_885x_holdmode_get(sdi, &tmp)) == SR_OK)
+			*data = g_variant_new_boolean(tmp == SR_MQFLAG_MAX);
+		break;
+	case SR_CONF_HOLD_MIN:
+		if ((ret = cem_dt_885x_holdmode_get(sdi, &tmp)) == SR_OK)
+			*data = g_variant_new_boolean(tmp == SR_MQFLAG_MIN);
+		break;
+	case SR_CONF_SPL_MEASUREMENT_RANGE:
+		if ((ret = cem_dt_885x_meas_range_get(sdi, &low, &high)) == SR_OK) {
+			range[0] = g_variant_new_uint64(low);
+			range[1] = g_variant_new_uint64(high);
+			*data = g_variant_new_tuple(range, 2);
+		}
+		break;
+	case SR_CONF_POWER_OFF:
+		*data = g_variant_new_boolean(FALSE);
+		break;
+	case SR_CONF_DATA_SOURCE:
+		if (devc->cur_data_source == DATA_SOURCE_LIVE)
+			*data = g_variant_new_string("Live");
+		else
+			*data = g_variant_new_string("Memory");
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return ret;
+}
+
+static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	uint64_t tmp_u64, low, high;
+	unsigned int i;
+	int tmp, ret;
+	const char *tmp_str;
+
+	(void)cg;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!(devc = sdi->priv)) {
+		sr_err("sdi->priv was NULL.");
+		return SR_ERR_BUG;
+	}
+
+	ret = SR_OK;
+	switch (key) {
+	case SR_CONF_LIMIT_SAMPLES:
+		tmp_u64 = g_variant_get_uint64(data);
+		devc->limit_samples = tmp_u64;
+		ret = SR_OK;
+		break;
+	case SR_CONF_DATALOG:
+		ret = cem_dt_885x_recording_set(sdi, g_variant_get_boolean(data));
+		break;
+	case SR_CONF_SPL_WEIGHT_FREQ:
+		tmp_str = g_variant_get_string(data, NULL);
+		if (!strcmp(tmp_str, "A"))
+			ret = cem_dt_885x_weight_freq_set(sdi,
+					SR_MQFLAG_SPL_FREQ_WEIGHT_A);
+		else if (!strcmp(tmp_str, "C"))
+			ret = cem_dt_885x_weight_freq_set(sdi,
+					SR_MQFLAG_SPL_FREQ_WEIGHT_C);
+		else
+			return SR_ERR_ARG;
+		break;
+	case SR_CONF_SPL_WEIGHT_TIME:
+		tmp_str = g_variant_get_string(data, NULL);
+		if (!strcmp(tmp_str, "F"))
+			ret = cem_dt_885x_weight_time_set(sdi,
+					SR_MQFLAG_SPL_TIME_WEIGHT_F);
+		else if (!strcmp(tmp_str, "S"))
+			ret = cem_dt_885x_weight_time_set(sdi,
+					SR_MQFLAG_SPL_TIME_WEIGHT_S);
+		else
+			return SR_ERR_ARG;
+		break;
+	case SR_CONF_HOLD_MAX:
+		tmp = g_variant_get_boolean(data) ? SR_MQFLAG_MAX : 0;
+		ret = cem_dt_885x_holdmode_set(sdi, tmp);
+		break;
+	case SR_CONF_HOLD_MIN:
+		tmp = g_variant_get_boolean(data) ? SR_MQFLAG_MIN : 0;
+		ret = cem_dt_885x_holdmode_set(sdi, tmp);
+		break;
+	case SR_CONF_SPL_MEASUREMENT_RANGE:
+		g_variant_get(data, "(tt)", &low, &high);
+		ret = SR_ERR_ARG;
+		for (i = 0; i < ARRAY_SIZE(meas_ranges); i++) {
+			if (meas_ranges[i][0] == low && meas_ranges[i][1] == high) {
+				ret = cem_dt_885x_meas_range_set(sdi, low, high);
+				break;
+			}
+		}
+		break;
+	case SR_CONF_POWER_OFF:
+		if (g_variant_get_boolean(data))
+			ret = cem_dt_885x_power_off(sdi);
+		break;
+	case SR_CONF_DATA_SOURCE:
+		tmp_str = g_variant_get_string(data, NULL);
+		if (!strcmp(tmp_str, "Live"))
+			devc->cur_data_source = DATA_SOURCE_LIVE;
+		else if (!strcmp(tmp_str, "Memory"))
+			devc->cur_data_source = DATA_SOURCE_MEMORY;
+		else
+			return SR_ERR;
+		devc->enable_data_source_memory = devc->cur_data_source == DATA_SOURCE_MEMORY;
+		break;
+	default:
+		ret = SR_ERR_NA;
+	}
+
+	return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	GVariant *tuple, *range[2];
+	GVariantBuilder gvb;
+	unsigned int i;
+	int ret;
+
+	(void)sdi;
+	(void)cg;
+
+	ret = SR_OK;
+	switch (key) {
+	case SR_CONF_SCAN_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+		break;
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+		break;
+	case SR_CONF_SPL_WEIGHT_FREQ:
+		*data = g_variant_new_strv(weight_freq, ARRAY_SIZE(weight_freq));
+		break;
+	case SR_CONF_SPL_WEIGHT_TIME:
+		*data = g_variant_new_strv(weight_time, ARRAY_SIZE(weight_time));
+		break;
+	case SR_CONF_SPL_MEASUREMENT_RANGE:
+		g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
+		for (i = 0; i < ARRAY_SIZE(meas_ranges); i++) {
+			range[0] = g_variant_new_uint64(meas_ranges[i][0]);
+			range[1] = g_variant_new_uint64(meas_ranges[i][1]);
+			tuple = g_variant_new_tuple(range, 2);
+			g_variant_builder_add_value(&gvb, tuple);
+		}
+		*data = g_variant_builder_end(&gvb);
+		break;
+	case SR_CONF_DATA_SOURCE:
+		*data = g_variant_new_strv(data_sources, ARRAY_SIZE(data_sources));
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return ret;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!(devc = sdi->priv)) {
+		sr_err("sdi->priv was NULL.");
+		return SR_ERR_BUG;
+	}
+
+	devc->cb_data = cb_data;
+	devc->state = ST_INIT;
+	devc->num_samples = 0;
+	devc->buf_len = 0;
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	/* Poll every 100ms, or whenever some data comes in. */
+	serial = sdi->conn;
+	serial_source_add(serial, G_IO_IN, 150, cem_dt_885x_receive_data,
+			(void *)sdi);
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close,
+			sdi->conn, LOG_PREFIX);
+}
+
+SR_PRIV struct sr_dev_driver cem_dt_885x_driver_info = {
+	.name = "cem-dt-885x",
+	.longname = "CEM DT-885x",
+	.api_version = 1,
+	.init = init,
+	.cleanup = cleanup,
+	.scan = scan,
+	.dev_list = dev_list,
+	.dev_clear = NULL,
+	.config_get = config_get,
+	.config_set = config_set,
+	.config_list = config_list,
+	.dev_open = dev_open,
+	.dev_close = std_serial_dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/cem-dt-885x/protocol.c b/hardware/cem-dt-885x/protocol.c
new file mode 100644
index 0000000..19e0830
--- /dev/null
+++ b/hardware/cem-dt-885x/protocol.c
@@ -0,0 +1,838 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include "protocol.h"
+
+/* Length of expected payload for each token. */
+static int token_payloads[][2] = {
+	{ TOKEN_WEIGHT_TIME_FAST, 0 },
+	{ TOKEN_WEIGHT_TIME_SLOW, 0 },
+	{ TOKEN_HOLD_MAX, 0 },
+	{ TOKEN_HOLD_MIN, 0 },
+	{ TOKEN_TIME, 3 },
+	{ TOKEN_MEAS_RANGE_OVER, 0 },
+	{ TOKEN_MEAS_RANGE_UNDER, 0 },
+	{ TOKEN_STORE_FULL, 0 },
+	{ TOKEN_RECORDING_ON, 0 },
+	{ TOKEN_MEAS_WAS_READOUT, 1 },
+	{ TOKEN_MEAS_WAS_BARGRAPH, 0 },
+	{ TOKEN_MEASUREMENT, 2 },
+	{ TOKEN_HOLD_NONE, 0 },
+	{ TOKEN_BATTERY_LOW, 0 },
+	{ TOKEN_MEAS_RANGE_OK, 0 },
+	{ TOKEN_STORE_OK, 0 },
+	{ TOKEN_RECORDING_OFF, 0 },
+	{ TOKEN_WEIGHT_FREQ_A, 1 },
+	{ TOKEN_WEIGHT_FREQ_C, 1 },
+	{ TOKEN_BATTERY_OK, 0 },
+	{ TOKEN_MEAS_RANGE_30_80, 0 },
+	{ TOKEN_MEAS_RANGE_30_130, 0 },
+	{ TOKEN_MEAS_RANGE_50_100, 0 },
+	{ TOKEN_MEAS_RANGE_80_130, 0 },
+};
+
+static int find_token_payload_len(unsigned char c)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(token_payloads); i++) {
+		if (token_payloads[i][0] == c)
+			return token_payloads[i][1];
+	}
+
+	return -1;
+}
+
+/* Process measurement or setting (0xa5 command). */
+static void process_mset(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_analog analog;
+	GString *dbg;
+	float fvalue;
+	int i;
+
+	devc = sdi->priv;
+	if (sr_log_loglevel_get() >= SR_LOG_SPEW) {
+		dbg = g_string_sized_new(128);
+		g_string_printf(dbg, "got command 0x%.2x token 0x%.2x",
+				devc->cmd, devc->token);
+		if (devc->buf_len) {
+			g_string_append_printf(dbg, " payload");
+			for (i = 0; i < devc->buf_len; i++)
+				g_string_append_printf(dbg, " %.2x", devc->buf[i]);
+		}
+		sr_spew("%s", dbg->str);
+		g_string_free(dbg, TRUE);
+	}
+
+	switch(devc->token) {
+	case TOKEN_WEIGHT_TIME_FAST:
+		devc->cur_mqflags |= SR_MQFLAG_SPL_TIME_WEIGHT_F;
+		devc->cur_mqflags &= ~SR_MQFLAG_SPL_TIME_WEIGHT_S;
+		break;
+	case TOKEN_WEIGHT_TIME_SLOW:
+		devc->cur_mqflags |= SR_MQFLAG_SPL_TIME_WEIGHT_S;
+		devc->cur_mqflags &= ~SR_MQFLAG_SPL_TIME_WEIGHT_F;
+		break;
+	case TOKEN_WEIGHT_FREQ_A:
+		devc->cur_mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_A;
+		devc->cur_mqflags &= ~SR_MQFLAG_SPL_FREQ_WEIGHT_C;
+		break;
+	case TOKEN_WEIGHT_FREQ_C:
+		devc->cur_mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_C;
+		devc->cur_mqflags &= ~SR_MQFLAG_SPL_FREQ_WEIGHT_A;
+		break;
+	case TOKEN_HOLD_MAX:
+		devc->cur_mqflags |= SR_MQFLAG_HOLD | SR_MQFLAG_MAX;
+		devc->cur_mqflags &= ~SR_MQFLAG_MIN;
+		break;
+	case TOKEN_HOLD_MIN:
+		devc->cur_mqflags |= SR_MQFLAG_HOLD | SR_MQFLAG_MIN;
+		devc->cur_mqflags &= ~SR_MQFLAG_MAX;
+		break;
+	case TOKEN_HOLD_NONE:
+		devc->cur_mqflags &= ~(SR_MQFLAG_MAX | SR_MQFLAG_MIN | SR_MQFLAG_HOLD);
+		break;
+	case TOKEN_MEASUREMENT:
+		fvalue = ((devc->buf[0] & 0xf0) >> 4) * 100;
+		fvalue += (devc->buf[0] & 0x0f) * 10;
+		fvalue += ((devc->buf[1] & 0xf0) >> 4);
+		fvalue += (devc->buf[1] & 0x0f) / 10.0;
+		devc->last_spl = fvalue;
+		break;
+	case TOKEN_MEAS_WAS_READOUT:
+	case TOKEN_MEAS_WAS_BARGRAPH:
+		if (devc->cur_mqflags & (SR_MQFLAG_MAX | SR_MQFLAG_MIN)) {
+			if (devc->token == TOKEN_MEAS_WAS_BARGRAPH) {
+				/* The device still sends bargraph measurements even
+				 * when in max/min hold mode. Suppress them here, unless
+				 * they're readout values. This duplicates the behavior
+				 * of the device display exactly. */
+				break;
+			}
+		}
+		memset(&analog, 0, sizeof(struct sr_datafeed_analog));
+		analog.mq = SR_MQ_SOUND_PRESSURE_LEVEL;
+		analog.mqflags = devc->cur_mqflags;
+		analog.unit = SR_UNIT_DECIBEL_SPL;
+		analog.channels = sdi->channels;
+		analog.num_samples = 1;
+		analog.data = &devc->last_spl;
+		packet.type = SR_DF_ANALOG;
+		packet.payload = &analog;
+		sr_session_send(devc->cb_data, &packet);
+
+		devc->num_samples++;
+		if (devc->limit_samples && devc->num_samples >= devc->limit_samples)
+			sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi,
+					devc->cb_data);
+		break;
+	case TOKEN_RECORDING_ON:
+		devc->recording = TRUE;
+		break;
+	case TOKEN_RECORDING_OFF:
+		devc->recording = FALSE;
+		break;
+	case TOKEN_MEAS_RANGE_30_80:
+	case TOKEN_MEAS_RANGE_30_130:
+	case TOKEN_MEAS_RANGE_50_100:
+	case TOKEN_MEAS_RANGE_80_130:
+		devc->cur_meas_range = devc->token;
+		break;
+	case TOKEN_TIME:
+	case TOKEN_STORE_OK:
+	case TOKEN_STORE_FULL:
+	case TOKEN_BATTERY_OK:
+	case TOKEN_BATTERY_LOW:
+	case TOKEN_MEAS_RANGE_OK:
+	case TOKEN_MEAS_RANGE_OVER:
+	case TOKEN_MEAS_RANGE_UNDER:
+		/* Not useful, or not expressable in sigrok. */
+		break;
+	}
+
+}
+
+static void send_data(const struct sr_dev_inst *sdi, unsigned char *data,
+		uint64_t num_samples)
+{
+	struct dev_context *devc;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_analog analog;
+	float fbuf[SAMPLES_PER_PACKET];
+	unsigned int i;
+
+	devc = sdi->priv;
+
+	for (i = 0; i < num_samples; i ++) {
+		fbuf[i] = ((data[i * 2] & 0xf0) >> 4) * 100;
+		fbuf[i] += (data[i * 2] & 0x0f) * 10;
+		fbuf[i] += ((data[i * 2 + 1] & 0xf0) >> 4);
+		fbuf[i] += (data[i * 2 + 1] & 0x0f) / 10.0;
+	}
+	memset(&analog, 0, sizeof(struct sr_datafeed_analog));
+	analog.mq = SR_MQ_SOUND_PRESSURE_LEVEL;
+	analog.mqflags = devc->cur_mqflags;
+	analog.unit = SR_UNIT_DECIBEL_SPL;
+	analog.channels = sdi->channels;
+	analog.num_samples = num_samples;
+	analog.data = fbuf;
+	packet.type = SR_DF_ANALOG;
+	packet.payload = &analog;
+	sr_session_send(devc->cb_data, &packet);
+
+	devc->num_samples += analog.num_samples;
+	if (devc->limit_samples && devc->num_samples >= devc->limit_samples)
+		sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi,
+				devc->cb_data);
+
+	return;
+}
+
+static void process_byte(const struct sr_dev_inst *sdi, const unsigned char c,
+		int handle_packets)
+{
+	struct dev_context *devc;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_meta meta;
+	struct sr_config *src;
+	gint64 cur_time;
+	int len;
+
+	if (!(devc = sdi->priv))
+		return;
+
+	if (c == 0xff) {
+		/* Device is in hold mode */
+		devc->cur_mqflags |= SR_MQFLAG_HOLD;
+
+		if (devc->hold_last_sent == 0) {
+			/* First hold notification. */
+			devc->hold_last_sent = g_get_monotonic_time();
+			/* When the device leaves hold mode, it starts from scratch. */
+			devc->state = ST_INIT;
+		} else {
+			cur_time = g_get_monotonic_time();
+			if (cur_time - devc->hold_last_sent > HOLD_REPEAT_INTERVAL) {
+				/* Force the last measurement out again. */
+				devc->cmd = 0xa5;
+				devc->token = TOKEN_MEAS_WAS_READOUT;
+				if (handle_packets)
+					process_mset(sdi);
+				devc->hold_last_sent = cur_time;
+			}
+		}
+
+		return;
+	}
+	devc->cur_mqflags &= ~SR_MQFLAG_HOLD;
+	devc->hold_last_sent = 0;
+
+	if (devc->state == ST_INIT) {
+		if (c == 0xa5) {
+			devc->cmd = c;
+			devc->token = 0x00;
+			devc->state = ST_GET_TOKEN;
+		} else if (c == 0xbb) {
+			devc->cmd = c;
+			devc->buf_len = 0;
+			devc->state = ST_GET_LOG_HEADER;
+			sr_dbg("got command 0xbb");
+		}
+	} else if (devc->state == ST_GET_TOKEN) {
+		devc->token = c;
+		devc->buf_len = 0;
+		len = find_token_payload_len(devc->token);
+		if (len == -1 || len > 0) {
+			devc->buf_len = 0;
+			devc->state = ST_GET_DATA;
+		} else {
+			if (handle_packets)
+				process_mset(sdi);
+			devc->state = ST_INIT;
+		}
+	} else if (devc->state == ST_GET_DATA) {
+		len = find_token_payload_len(devc->token);
+		if (len == -1) {
+			/* We don't know this token. */
+			sr_dbg("Unknown 0xa5 token 0x%.2x", devc->token);
+			if (c == 0xa5 || c == 0xbb) {
+				/* Looks like a new command however. */
+				if (handle_packets)
+					process_mset(sdi);
+				devc->state = ST_INIT;
+			} else {
+				devc->buf[devc->buf_len++] = c;
+				if (devc->buf_len > BUF_SIZE) {
+					/* Shouldn't happen, ignore. */
+					devc->state = ST_INIT;
+				}
+			}
+		} else {
+			devc->buf[devc->buf_len++] = c;
+			if (devc->buf_len == len) {
+				if (handle_packets)
+					process_mset(sdi);
+				devc->state = ST_INIT;
+			} else if (devc->buf_len > BUF_SIZE) {
+				/* Shouldn't happen, ignore. */
+				devc->state = ST_INIT;
+			}
+		}
+	} else if (devc->state == ST_GET_LOG_HEADER) {
+		sr_dbg("log header: 0x%.2x", c);
+		if (devc->buf_len < 2)
+			devc->buf[devc->buf_len++] = c;
+		if (devc->buf_len == 2) {
+			sr_dbg("Device says it has %d bytes stored.",
+					((devc->buf[0] << 8) + devc->buf[1]) - 100);
+			devc->buf_len = 0;
+			devc->state = ST_GET_LOG_RECORD_META;
+		}
+	} else if (devc->state == ST_GET_LOG_RECORD_META) {
+		sr_dbg("log meta: 0x%.2x", c);
+		if (c == RECORD_END) {
+			devc->state = ST_INIT;
+			/* Stop acquisition after transferring all stored
+			 * records. Otherwise the frontend would have no
+			 * way to tell where stored data ends and live
+			 * measurements begin. */
+			sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi,
+					devc->cb_data);
+		} else if (c == RECORD_DATA) {
+			devc->buf_len = 0;
+			devc->state = ST_GET_LOG_RECORD_DATA;
+		} else {
+			/* RECORD_DBA/RECORD_DBC + 7 bytes of metadata */
+			devc->buf[devc->buf_len++] = c;
+			if (devc->buf_len < 8)
+				/* Keep filling up the record header. */
+				return;
+			if (devc->buf[0] == RECORD_DBA)
+				devc->cur_mqflags = SR_MQFLAG_SPL_FREQ_WEIGHT_A;
+			else if (devc->buf[0] == RECORD_DBC)
+				devc->cur_mqflags = SR_MQFLAG_SPL_FREQ_WEIGHT_C;
+			else {
+				/* Shouldn't happen. */
+				sr_dbg("Unknown record token 0x%.2x", c);
+				return;
+			}
+			packet.type = SR_DF_META;
+			packet.payload = &meta;
+			src = sr_config_new(SR_CONF_SAMPLE_INTERVAL,
+					g_variant_new_uint64(devc->buf[7] * 1000));
+			meta.config = g_slist_append(NULL, src);
+			sr_session_send(devc->cb_data, &packet);
+			g_free(src);
+			devc->buf_len = 0;
+		}
+	} else if (devc->state == ST_GET_LOG_RECORD_DATA) {
+		sr_dbg("log data: 0x%.2x", c);
+		if (c == RECORD_DBA || c == RECORD_DBC || c == RECORD_DATA || c == RECORD_END) {
+			/* Work around off-by-one bug in device firmware. This
+			 * happens only on the last record, i.e. before RECORD_END */
+			if (devc->buf_len & 1)
+				devc->buf_len--;
+			/* Done with this set of samples */
+			send_data(sdi, devc->buf, devc->buf_len / 2);
+			devc->buf_len = 0;
+
+			/* Process this meta marker in the right state. */
+			devc->state = ST_GET_LOG_RECORD_META;
+			process_byte(sdi, c, handle_packets);
+		} else {
+			devc->buf[devc->buf_len++] = c;
+			if (devc->buf_len == SAMPLES_PER_PACKET * 2) {
+				send_data(sdi, devc->buf, devc->buf_len / 2);
+				devc->buf_len = 0;
+			}
+		}
+	}
+
+}
+
+SR_PRIV int cem_dt_885x_receive_data(int fd, int revents, void *cb_data)
+{
+	const struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+	unsigned char c, cmd;
+
+	(void)fd;
+
+	if (!(sdi = cb_data))
+		return TRUE;
+
+	devc = sdi->priv;
+	serial = sdi->conn;
+	if (revents == G_IO_IN) {
+		if (serial_read(serial, &c, 1) != 1)
+			return TRUE;
+		process_byte(sdi, c, TRUE);
+
+		if (devc->enable_data_source_memory) {
+			if (devc->state == ST_GET_LOG_HEADER) {
+				/* Memory transfer started. */
+				devc->enable_data_source_memory = FALSE;
+			} else {
+				/* Tell device to start transferring from memory. */
+				cmd = CMD_TRANSFER_MEMORY;
+				serial_write(serial, &cmd, 1);
+			}
+		}
+	}
+
+	return TRUE;
+}
+
+
+static int wait_for_token(const struct sr_dev_inst *sdi, int8_t *tokens, int timeout)
+{
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+	gint64 start_time;
+	int i;
+	unsigned char c;
+
+	serial = sdi->conn;
+	devc = sdi->priv;
+	devc->state = ST_INIT;
+	start_time = g_get_monotonic_time() / 1000;
+	while (TRUE) {
+		if (serial_read(serial, &c, 1) != 1)
+			/* Device might have gone away. */
+			return SR_ERR;
+		process_byte(sdi, c, FALSE);
+		if (devc->state != ST_INIT)
+			/* Wait for a whole packet to get processed. */
+			continue;
+		for (i = 0; tokens[i] != -1; i++) {
+			if (devc->token == tokens[i]) {
+				sr_spew("wait_for_token: got token 0x%.2x", devc->token);
+				return SR_OK;
+			}
+		}
+		if (timeout && g_get_monotonic_time() / 1000 - start_time > timeout)
+			return SR_ERR_TIMEOUT;
+	}
+
+	return SR_OK;
+}
+
+/* cmd is the command to send, tokens are the tokens that denote the state
+ * which the command affects. The first token is the desired state. */
+static int cem_dt_885x_toggle(const struct sr_dev_inst *sdi, uint8_t cmd,
+		int8_t *tokens, int timeout)
+{
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+
+	serial = sdi->conn;
+	devc = sdi->priv;
+
+	/* The device doesn't respond to commands very well. The
+	 * only thing to do is wait for the token that will confirm
+	 * whether the command worked or not, and resend if needed. */
+	while (TRUE) {
+		if (serial_write(serial, (const void *)&cmd, 1) != 1)
+			return SR_ERR;
+		if (wait_for_token(sdi, tokens, timeout) == SR_ERR)
+			return SR_ERR;
+		if (devc->token == tokens[0])
+			/* It worked. */
+			break;
+	}
+
+	return SR_OK;
+}
+
+SR_PRIV gboolean cem_dt_885x_recording_get(const struct sr_dev_inst *sdi,
+		int *state)
+{
+	struct dev_context *devc;
+	int8_t tokens[5];
+
+	devc = sdi->priv;
+	if (devc->recording == -1) {
+		/* Didn't pick up device state yet. */
+		tokens[0] = TOKEN_RECORDING_ON;
+		tokens[1] = TOKEN_RECORDING_OFF;
+		tokens[2] = -1;
+		if (wait_for_token(sdi, tokens, 510) != SR_OK)
+			return SR_ERR;
+	}
+	*state = devc->token == TOKEN_RECORDING_ON;
+
+	return SR_OK;
+}
+
+SR_PRIV int cem_dt_885x_recording_set(const struct sr_dev_inst *sdi,
+		gboolean state)
+{
+	struct dev_context *devc;
+	int ret;
+	int8_t tokens[5];
+
+	devc = sdi->priv;
+
+	/* The toggle below needs the desired state in first position. */
+	if (state) {
+		tokens[0] = TOKEN_RECORDING_ON;
+		tokens[1] = TOKEN_RECORDING_OFF;
+	} else {
+		tokens[0] = TOKEN_RECORDING_OFF;
+		tokens[1] = TOKEN_RECORDING_ON;
+	}
+	tokens[2] = -1;
+
+	if (devc->recording == -1) {
+		/* Didn't pick up device state yet. */
+		if (wait_for_token(sdi, tokens, 0) != SR_OK)
+			return SR_ERR;
+		if (devc->token == tokens[0])
+			/* Nothing to do. */
+			return SR_OK;
+	} else if (devc->recording == state)
+		/* Nothing to do. */
+		return SR_OK;
+
+	/* Recording state notifications are sent at 2Hz, so allow just over
+	 * that, 510ms, for the state to come in. */
+	ret = cem_dt_885x_toggle(sdi, CMD_TOGGLE_RECORDING, tokens, 510);
+
+	return ret;
+}
+
+SR_PRIV int cem_dt_885x_weight_freq_get(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	int cur_setting;
+	int8_t tokens[5];
+
+	devc = sdi->priv;
+
+	cur_setting = devc->cur_mqflags & (SR_MQFLAG_SPL_FREQ_WEIGHT_A | SR_MQFLAG_SPL_FREQ_WEIGHT_C);
+	if (cur_setting == 0) {
+		/* Didn't pick up device state yet. */
+		tokens[0] = TOKEN_WEIGHT_FREQ_A;
+		tokens[1] = TOKEN_WEIGHT_FREQ_C;
+		tokens[2] = -1;
+		if (wait_for_token(sdi, tokens, 0) != SR_OK)
+			return SR_ERR;
+		if (devc->token == TOKEN_WEIGHT_FREQ_A)
+			return SR_MQFLAG_SPL_FREQ_WEIGHT_A;
+		else
+			return SR_MQFLAG_SPL_FREQ_WEIGHT_C;
+	} else
+		return cur_setting;
+}
+
+SR_PRIV int cem_dt_885x_weight_freq_set(const struct sr_dev_inst *sdi, int freqw)
+{
+	struct dev_context *devc;
+	int cur_setting, ret;
+	int8_t tokens[5];
+
+	devc = sdi->priv;
+
+	cur_setting = devc->cur_mqflags & (SR_MQFLAG_SPL_FREQ_WEIGHT_A | SR_MQFLAG_SPL_FREQ_WEIGHT_C);
+	if (cur_setting == freqw)
+		/* Already set to this frequency weighting. */
+		return SR_OK;
+
+	/* The toggle below needs the desired state in first position. */
+	if (freqw == SR_MQFLAG_SPL_FREQ_WEIGHT_A) {
+		tokens[0] = TOKEN_WEIGHT_FREQ_A;
+		tokens[1] = TOKEN_WEIGHT_FREQ_C;
+	} else {
+		tokens[0] = TOKEN_WEIGHT_FREQ_C;
+		tokens[1] = TOKEN_WEIGHT_FREQ_A;
+	}
+	tokens[2] = -1;
+
+	if (cur_setting == 0) {
+		/* Didn't pick up device state yet. */
+		if (wait_for_token(sdi, tokens, 0) != SR_OK)
+			return SR_ERR;
+		if (devc->token == tokens[0])
+			/* Nothing to do. */
+			return SR_OK;
+	}
+
+	/* 10ms timeout seems to work best for this. */
+	ret = cem_dt_885x_toggle(sdi, CMD_TOGGLE_WEIGHT_FREQ, tokens, 10);
+
+	return ret;
+}
+
+SR_PRIV int cem_dt_885x_weight_time_get(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	int cur_setting;
+	int8_t tokens[5];
+
+	devc = sdi->priv;
+
+	cur_setting = devc->cur_mqflags & (SR_MQFLAG_SPL_TIME_WEIGHT_F | SR_MQFLAG_SPL_TIME_WEIGHT_S);
+	if (cur_setting == 0) {
+		/* Didn't pick up device state yet. */
+		tokens[0] = TOKEN_WEIGHT_TIME_FAST;
+		tokens[1] = TOKEN_WEIGHT_TIME_SLOW;
+		tokens[2] = -1;
+		if (wait_for_token(sdi, tokens, 0) != SR_OK)
+			return SR_ERR;
+		if (devc->token == TOKEN_WEIGHT_TIME_FAST)
+			return SR_MQFLAG_SPL_TIME_WEIGHT_F;
+		else
+			return SR_MQFLAG_SPL_TIME_WEIGHT_S;
+	} else
+		return cur_setting;
+}
+
+SR_PRIV int cem_dt_885x_weight_time_set(const struct sr_dev_inst *sdi, int timew)
+{
+	struct dev_context *devc;
+	int cur_setting, ret;
+	int8_t tokens[5];
+
+	devc = sdi->priv;
+
+	cur_setting = devc->cur_mqflags & (SR_MQFLAG_SPL_TIME_WEIGHT_F | SR_MQFLAG_SPL_TIME_WEIGHT_S);
+	if (cur_setting == timew)
+		/* Already set to this time weighting. */
+		return SR_OK;
+
+	/* The toggle below needs the desired state in first position. */
+	if (timew == SR_MQFLAG_SPL_TIME_WEIGHT_F) {
+		tokens[0] = TOKEN_WEIGHT_TIME_FAST;
+		tokens[1] = TOKEN_WEIGHT_TIME_SLOW;
+	} else {
+		tokens[0] = TOKEN_WEIGHT_TIME_SLOW;
+		tokens[1] = TOKEN_WEIGHT_TIME_FAST;
+	}
+	tokens[2] = -1;
+
+	if (cur_setting == 0) {
+		/* Didn't pick up device state yet. */
+		if (wait_for_token(sdi, tokens, 0) != SR_OK)
+			return SR_ERR;
+		if (devc->token == tokens[0])
+			/* Nothing to do. */
+			return SR_OK;
+	}
+
+	/* 51ms timeout seems to work best for this. */
+	ret = cem_dt_885x_toggle(sdi, CMD_TOGGLE_WEIGHT_TIME, tokens, 51);
+
+	return ret;
+}
+
+SR_PRIV int cem_dt_885x_holdmode_get(const struct sr_dev_inst *sdi,
+		gboolean *holdmode)
+{
+	struct dev_context *devc;
+	int8_t tokens[5];
+
+	devc = sdi->priv;
+
+	if (devc->cur_mqflags == 0) {
+		tokens[0] = TOKEN_HOLD_MAX;
+		tokens[1] = TOKEN_HOLD_MIN;
+		tokens[2] = TOKEN_HOLD_NONE;
+		tokens[3] = -1;
+		if (wait_for_token(sdi, tokens, 0) != SR_OK)
+			return SR_ERR;
+		if (devc->token == TOKEN_HOLD_MAX)
+			devc->cur_mqflags = SR_MQFLAG_MAX;
+		else if (devc->token == TOKEN_HOLD_MIN)
+			devc->cur_mqflags = SR_MQFLAG_MIN;
+	}
+	*holdmode = devc->cur_mqflags & (SR_MQFLAG_MAX | SR_MQFLAG_MIN);
+
+	return SR_OK;
+}
+
+SR_PRIV int cem_dt_885x_holdmode_set(const struct sr_dev_inst *sdi, int holdmode)
+{
+	struct dev_context *devc;
+	int cur_setting, ret;
+	int8_t tokens[5];
+
+	devc = sdi->priv;
+
+	/* The toggle below needs the desired state in first position. */
+	if (holdmode == SR_MQFLAG_MAX) {
+		tokens[0] = TOKEN_HOLD_MAX;
+		tokens[1] = TOKEN_HOLD_MIN;
+		tokens[2] = TOKEN_HOLD_NONE;
+	} else if (holdmode == SR_MQFLAG_MIN) {
+		tokens[0] = TOKEN_HOLD_MIN;
+		tokens[1] = TOKEN_HOLD_MAX;
+		tokens[2] = TOKEN_HOLD_NONE;
+	} else {
+		tokens[0] = TOKEN_HOLD_NONE;
+		tokens[1] = TOKEN_HOLD_MAX;
+		tokens[2] = TOKEN_HOLD_MIN;
+	}
+	tokens[3] = -1;
+
+	if (devc->cur_mqflags == 0) {
+		/* Didn't pick up device state yet. */
+		if (wait_for_token(sdi, tokens, 0) != SR_OK)
+			return SR_ERR;
+		if (devc->token == tokens[0])
+			/* Nothing to do. */
+			return SR_OK;
+	} else {
+		cur_setting = devc->cur_mqflags & (SR_MQFLAG_MAX | SR_MQFLAG_MIN);
+		if (cur_setting == holdmode)
+			/* Already set correctly. */
+			return SR_OK;
+	}
+
+	/* 51ms timeout seems to work best for this. */
+	ret = cem_dt_885x_toggle(sdi, CMD_TOGGLE_HOLD_MAX_MIN, tokens, 51);
+
+	return ret;
+}
+
+SR_PRIV int cem_dt_885x_meas_range_get(const struct sr_dev_inst *sdi,
+		uint64_t *low, uint64_t *high)
+{
+	struct dev_context *devc;
+	int8_t tokens[5];
+
+	devc = sdi->priv;
+	if (devc->cur_meas_range == 0) {
+		tokens[0] = TOKEN_MEAS_RANGE_30_130;
+		tokens[1] = TOKEN_MEAS_RANGE_30_80;
+		tokens[2] = TOKEN_MEAS_RANGE_50_100;
+		tokens[3] = TOKEN_MEAS_RANGE_80_130;
+		tokens[4] = -1;
+		if (wait_for_token(sdi, tokens, 0) != SR_OK)
+			return SR_ERR;
+		devc->cur_meas_range = devc->token;
+	}
+
+	switch (devc->cur_meas_range) {
+	case TOKEN_MEAS_RANGE_30_130:
+		*low = 30;
+		*high = 130;
+		break;
+	case TOKEN_MEAS_RANGE_30_80:
+		*low = 30;
+		*high = 80;
+		break;
+	case TOKEN_MEAS_RANGE_50_100:
+		*low = 50;
+		*high = 100;
+		break;
+	case TOKEN_MEAS_RANGE_80_130:
+		*low = 80;
+		*high = 130;
+		break;
+	default:
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+SR_PRIV int cem_dt_885x_meas_range_set(const struct sr_dev_inst *sdi,
+		uint64_t low, uint64_t high)
+{
+	struct dev_context *devc;
+	int ret;
+	int8_t token, tokens[6];
+
+	devc = sdi->priv;
+	if (low == 30 && high == 130)
+		token = TOKEN_MEAS_RANGE_30_130;
+	else if (low == 30 &&  high == 80)
+		token = TOKEN_MEAS_RANGE_30_80;
+	else if (low == 50 &&  high == 100)
+		token = TOKEN_MEAS_RANGE_50_100;
+	else if (low == 80 &&  high == 130)
+		token = TOKEN_MEAS_RANGE_80_130;
+	else
+		return SR_ERR;
+
+	sr_dbg("want 0x%.2x", token);
+	/* The toggle below needs the desired state in first position. */
+	tokens[0] = token;
+	tokens[1] = TOKEN_MEAS_RANGE_30_130;
+	tokens[2] = TOKEN_MEAS_RANGE_30_80;
+	tokens[3] = TOKEN_MEAS_RANGE_50_100;
+	tokens[4] = TOKEN_MEAS_RANGE_80_130;
+	tokens[5] = -1;
+
+	if (devc->cur_meas_range == 0) {
+		/* 110ms should be enough for two of these announcements */
+		if (wait_for_token(sdi, tokens, 110) != SR_OK)
+			return SR_ERR;
+		devc->cur_meas_range = devc->token;
+	}
+
+	if (devc->cur_meas_range == token)
+		/* Already set to this range. */
+		return SR_OK;
+
+	/* For measurement range, it works best to ignore announcements of the
+	 * current setting and keep resending the toggle quickly. */
+	tokens[1] = -1;
+	ret = cem_dt_885x_toggle(sdi, CMD_TOGGLE_MEAS_RANGE, tokens, 11);
+
+	return ret;
+}
+
+SR_PRIV int cem_dt_885x_power_off(const struct sr_dev_inst *sdi)
+{
+	struct sr_serial_dev_inst *serial;
+	char c, cmd;
+
+	serial = sdi->conn;
+
+	/* Reopen the port in non-blocking mode, so we can properly
+	 * detect when the device stops communicating. */
+	serial_close(serial);
+	if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+		return SR_ERR;
+
+	cmd = CMD_TOGGLE_POWER_OFF;
+	while (TRUE) {
+		serial_flush(serial);
+		if (serial_write(serial, (const void *)&cmd, 1) != 1)
+			return SR_ERR;
+		/* It never takes more than 23ms for the next token to arrive. */
+		g_usleep(25 * 1000);
+		if (serial_read(serial, &c, 1) != 1)
+			/* Device is no longer responding. Good! */
+			break;
+	}
+
+	/* In case the user manually turns on the device again, reset
+	 * the port back to blocking. */
+	serial_close(serial);
+	serial_open(serial, SERIAL_RDWR);
+
+	return SR_OK;
+}
diff --git a/hardware/cem-dt-885x/protocol.h b/hardware/cem-dt-885x/protocol.h
new file mode 100644
index 0000000..233ef86
--- /dev/null
+++ b/hardware/cem-dt-885x/protocol.h
@@ -0,0 +1,143 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_CEM_DT_885X_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_CEM_DT_885X_PROTOCOL_H
+
+#include <stdint.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "cem-dt-885x"
+
+/* When retrieving samples from device memory, group this many
+ * together into a sigrok packet. */
+#define SAMPLES_PER_PACKET 50
+
+/* Various temporary storage, at least 8 bytes. */
+#define BUF_SIZE SAMPLES_PER_PACKET * 2
+
+/* When in hold mode, force the last measurement out at this interval.
+ * We're using 50ms, which duplicates the non-hold 20Hz update rate. */
+#define HOLD_REPEAT_INTERVAL 50 * 1000
+
+enum {
+	TOKEN_WEIGHT_TIME_FAST = 0x02,
+	TOKEN_WEIGHT_TIME_SLOW = 0x03,
+	TOKEN_HOLD_MAX = 0x04,
+	TOKEN_HOLD_MIN = 0x05,
+	TOKEN_TIME = 0x06,
+	TOKEN_MEAS_RANGE_OVER = 0x07,
+	TOKEN_MEAS_RANGE_UNDER = 0x08,
+	TOKEN_STORE_FULL = 0x09,
+	TOKEN_RECORDING_ON = 0x0a,
+	TOKEN_MEAS_WAS_READOUT = 0x0b,
+	TOKEN_MEAS_WAS_BARGRAPH = 0x0c,
+	TOKEN_MEASUREMENT = 0xd,
+	TOKEN_HOLD_NONE = 0x0e,
+	TOKEN_BATTERY_LOW = 0x0f,
+	TOKEN_MEAS_RANGE_OK = 0x11,
+	TOKEN_STORE_OK = 0x19,
+	TOKEN_RECORDING_OFF = 0x1a,
+	TOKEN_WEIGHT_FREQ_A = 0x1b,
+	TOKEN_WEIGHT_FREQ_C = 0x1c,
+	TOKEN_BATTERY_OK = 0x1f,
+	TOKEN_MEAS_RANGE_30_80 = 0x30,
+	TOKEN_MEAS_RANGE_30_130 = 0x40,
+	TOKEN_MEAS_RANGE_50_100 = 0x4b,
+	TOKEN_MEAS_RANGE_80_130 = 0x4c,
+};
+
+enum {
+	CMD_TOGGLE_RECORDING = 0x55,
+	CMD_TOGGLE_WEIGHT_FREQ = 0x99,
+	CMD_TOGGLE_WEIGHT_TIME = 0x77,
+	CMD_TOGGLE_HOLD_MAX_MIN = 0x11,
+	CMD_TOGGLE_MEAS_RANGE = 0x88,
+	CMD_TOGGLE_POWER_OFF = 0x33,
+	CMD_TRANSFER_MEMORY = 0xac,
+};
+
+enum {
+	RECORD_DBA = 0xaa,
+	RECORD_DBC = 0xcc,
+	RECORD_DATA = 0xac,
+	RECORD_END = 0xdd,
+};
+
+enum {
+	DATA_SOURCE_LIVE,
+	DATA_SOURCE_MEMORY,
+};
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+	/* Device state */
+	uint64_t cur_mqflags;
+	int recording;
+	int cur_meas_range;
+	int cur_data_source;
+
+	/* Acquisition settings */
+	uint64_t limit_samples;
+
+	/* Operational state */
+	int state;
+	uint64_t num_samples;
+	gboolean enable_data_source_memory;
+
+	/* Temporary state across callbacks */
+	void *cb_data;
+	unsigned char cmd;
+	unsigned char token;
+	int buf_len;
+	unsigned char buf[BUF_SIZE];
+	float last_spl;
+	gint64 hold_last_sent;
+};
+
+/* Parser state machine. */
+enum {
+	ST_INIT,
+	ST_GET_TOKEN,
+	ST_GET_DATA,
+	ST_GET_LOG_HEADER,
+	ST_GET_LOG_RECORD_META,
+	ST_GET_LOG_RECORD_DATA,
+};
+
+SR_PRIV int cem_dt_885x_receive_data(int fd, int revents, void *cb_data);
+SR_PRIV int cem_dt_885x_recording_set(const struct sr_dev_inst *sdi, gboolean start);
+SR_PRIV gboolean cem_dt_885x_recording_get(const struct sr_dev_inst *sdi,
+		int *state);
+SR_PRIV int cem_dt_885x_weight_freq_get(const struct sr_dev_inst *sdi);
+SR_PRIV int cem_dt_885x_weight_freq_set(const struct sr_dev_inst *sdi, int freqw);
+SR_PRIV int cem_dt_885x_weight_time_get(const struct sr_dev_inst *sdi);
+SR_PRIV int cem_dt_885x_weight_time_set(const struct sr_dev_inst *sdi, int timew);
+SR_PRIV int cem_dt_885x_holdmode_get(const struct sr_dev_inst *sdi,
+		gboolean *holdmode);
+SR_PRIV int cem_dt_885x_holdmode_set(const struct sr_dev_inst *sdi, int holdmode);
+SR_PRIV int cem_dt_885x_meas_range_get(const struct sr_dev_inst *sdi,
+		uint64_t *low, uint64_t *high);
+SR_PRIV int cem_dt_885x_meas_range_set(const struct sr_dev_inst *sdi,
+		uint64_t low, uint64_t high);
+SR_PRIV int cem_dt_885x_power_off(const struct sr_dev_inst *sdi);
+
+#endif
diff --git a/hardware/center-3xx/api.c b/hardware/center-3xx/api.c
new file mode 100644
index 0000000..ddac154
--- /dev/null
+++ b/hardware/center-3xx/api.c
@@ -0,0 +1,289 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "protocol.h"
+
+static const int32_t hwopts[] = {
+	SR_CONF_CONN,
+	SR_CONF_SERIALCOMM,
+};
+
+static const int32_t hwcaps[] = {
+	SR_CONF_THERMOMETER,
+	SR_CONF_LIMIT_SAMPLES,
+	SR_CONF_LIMIT_MSEC,
+	SR_CONF_CONTINUOUS,
+};
+
+static const char *channel_names[] = {
+	"T1", "T2", "T3", "T4",
+	NULL,
+};
+
+SR_PRIV struct sr_dev_driver center_309_driver_info;
+SR_PRIV struct sr_dev_driver voltcraft_k204_driver_info;
+
+SR_PRIV const struct center_dev_info center_devs[] = {
+	{
+		"Center", "309", "9600/8n1", 4, 32000, 45,
+		center_3xx_packet_valid,
+		&center_309_driver_info, receive_data_CENTER_309,
+	},
+	{
+		"Voltcraft", "K204", "9600/8n1", 4, 32000, 45,
+		center_3xx_packet_valid,
+		&voltcraft_k204_driver_info, receive_data_VOLTCRAFT_K204,
+	},
+};
+
+static int dev_clear(int idx)
+{
+	return std_dev_clear(center_devs[idx].di, NULL);
+}
+
+static int init(struct sr_context *sr_ctx, int idx)
+{
+	sr_dbg("Selected '%s' subdriver.", center_devs[idx].di->name);
+
+	return std_init(sr_ctx, center_devs[idx].di, LOG_PREFIX);
+}
+
+static GSList *center_scan(const char *conn, const char *serialcomm, int idx)
+{
+	int i;
+	struct sr_dev_inst *sdi;
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_channel *ch;
+	struct sr_serial_dev_inst *serial;
+	GSList *devices;
+
+	if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+		return NULL;
+
+	if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+		return NULL;
+
+	drvc = center_devs[idx].di->priv;
+	devices = NULL;
+	serial_flush(serial);
+
+	sr_info("Found device on port %s.", conn);
+
+	if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, center_devs[idx].vendor,
+				    center_devs[idx].device, NULL)))
+		goto scan_cleanup;
+
+	if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+		sr_err("Device context malloc failed.");
+		goto scan_cleanup;
+	}
+
+	sdi->inst_type = SR_INST_SERIAL;
+	sdi->conn = serial;
+
+	sdi->priv = devc;
+	sdi->driver = center_devs[idx].di;
+
+	for (i = 0; i <  center_devs[idx].num_channels; i++) {
+		if (!(ch = sr_channel_new(i, SR_CHANNEL_ANALOG,
+					   TRUE, channel_names[i])))
+			goto scan_cleanup;
+		sdi->channels = g_slist_append(sdi->channels, ch);
+	}
+
+	drvc->instances = g_slist_append(drvc->instances, sdi);
+	devices = g_slist_append(devices, sdi);
+
+scan_cleanup:
+	serial_close(serial);
+
+	return devices;
+}
+
+static GSList *scan(GSList *options, int idx)
+{
+	struct sr_config *src;
+	GSList *l, *devices;
+	const char *conn, *serialcomm;
+
+	conn = serialcomm = NULL;
+	for (l = options; l; l = l->next) {
+		src = l->data;
+		switch (src->key) {
+		case SR_CONF_CONN:
+			conn = g_variant_get_string(src->data, NULL);
+			break;
+		case SR_CONF_SERIALCOMM:
+			serialcomm = g_variant_get_string(src->data, NULL);
+			break;
+		}
+	}
+	if (!conn)
+		return NULL;
+
+	if (serialcomm) {
+		/* Use the provided comm specs. */
+		devices = center_scan(conn, serialcomm, idx);
+	} else {
+		/* Try the default. */
+		devices = center_scan(conn, center_devs[idx].conn, idx);
+	}
+
+	return devices;
+}
+
+static GSList *dev_list(int idx)
+{
+	return ((struct drv_context *)(center_devs[idx].di->priv))->instances;
+}
+
+static int cleanup(int idx)
+{
+	return dev_clear(idx);
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+
+	(void)cg;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	devc = sdi->priv;
+
+	switch (id) {
+	case SR_CONF_LIMIT_SAMPLES:
+		if (g_variant_get_uint64(data) == 0)
+			return SR_ERR_ARG;
+		devc->limit_samples = g_variant_get_uint64(data);
+		break;
+	case SR_CONF_LIMIT_MSEC:
+		if (g_variant_get_uint64(data) == 0)
+			return SR_ERR_ARG;
+		devc->limit_msec = g_variant_get_uint64(data);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	(void)sdi;
+	(void)cg;
+
+	switch (key) {
+	case SR_CONF_SCAN_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+		break;
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi,
+				    void *cb_data, int idx)
+{
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	devc = sdi->priv;
+	devc->cb_data = cb_data;
+	devc->num_samples = 0;
+	devc->starttime = g_get_monotonic_time();
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	/* Poll every 500ms, or whenever some data comes in. */
+	serial = sdi->conn;
+	serial_source_add(serial, G_IO_IN, 500,
+		      center_devs[idx].receive_data, (void *)sdi);
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	return std_serial_dev_acquisition_stop(sdi, cb_data,
+			std_serial_dev_close, sdi->conn, LOG_PREFIX);
+}
+
+/* Driver-specific API function wrappers */
+#define HW_INIT(X) \
+static int init_##X(struct sr_context *sr_ctx) { return init(sr_ctx, X); }
+#define HW_CLEANUP(X) \
+static int cleanup_##X(void) { return cleanup(X); }
+#define HW_SCAN(X) \
+static GSList *scan_##X(GSList *options) { return scan(options, X); }
+#define HW_DEV_LIST(X) \
+static GSList *dev_list_##X(void) { return dev_list(X); }
+#define HW_DEV_CLEAR(X) \
+static int dev_clear_##X(void) { return dev_clear(X); }
+#define HW_DEV_ACQUISITION_START(X) \
+static int dev_acquisition_start_##X(const struct sr_dev_inst *sdi, \
+void *cb_data) { return dev_acquisition_start(sdi, cb_data, X); }
+
+/* Driver structs and API function wrappers */
+#define DRV(ID, ID_UPPER, NAME, LONGNAME) \
+HW_INIT(ID_UPPER) \
+HW_CLEANUP(ID_UPPER) \
+HW_SCAN(ID_UPPER) \
+HW_DEV_LIST(ID_UPPER) \
+HW_DEV_CLEAR(ID_UPPER) \
+HW_DEV_ACQUISITION_START(ID_UPPER) \
+SR_PRIV struct sr_dev_driver ID##_driver_info = { \
+	.name = NAME, \
+	.longname = LONGNAME, \
+	.api_version = 1, \
+	.init = init_##ID_UPPER, \
+	.cleanup = cleanup_##ID_UPPER, \
+	.scan = scan_##ID_UPPER, \
+	.dev_list = dev_list_##ID_UPPER, \
+	.dev_clear = dev_clear_##ID_UPPER, \
+	.config_get = NULL, \
+	.config_set = config_set, \
+	.config_list = config_list, \
+	.dev_open = std_serial_dev_open, \
+	.dev_close = std_serial_dev_close, \
+	.dev_acquisition_start = dev_acquisition_start_##ID_UPPER, \
+	.dev_acquisition_stop = dev_acquisition_stop, \
+	.priv = NULL, \
+};
+
+DRV(center_309, CENTER_309, "center-309", "Center 309")
+DRV(voltcraft_k204, VOLTCRAFT_K204, "voltcraft-k204", "Voltcraft K204")
diff --git a/hardware/center-3xx/protocol.c b/hardware/center-3xx/protocol.c
new file mode 100644
index 0000000..ef8b9dc
--- /dev/null
+++ b/hardware/center-3xx/protocol.c
@@ -0,0 +1,256 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "protocol.h"
+
+struct center_info {
+	float temp[4];
+	gboolean rec, std, max, min, maxmin, t1t2, rel, hold, lowbat, celsius;
+	gboolean memfull, autooff;
+	gboolean mode_std, mode_rel, mode_max, mode_min, mode_maxmin;
+};
+
+static int center_send(struct sr_serial_dev_inst *serial, const char *cmd)
+{
+	int ret;
+
+	if ((ret = serial_write(serial, cmd, strlen(cmd))) < 0) {
+		sr_err("Error sending '%s' command: %d.", cmd, ret);
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+SR_PRIV gboolean center_3xx_packet_valid(const uint8_t *buf)
+{
+	return (buf[0] == 0x02 && buf[44] == 0x03);
+}
+
+static void log_packet(const uint8_t *buf, int idx)
+{
+	int i;
+	GString *s;
+
+	s = g_string_sized_new(100);
+	g_string_printf(s, "Packet: ");
+	for (i = 0; i < center_devs[idx].packet_size; i++)
+	        g_string_append_printf(s, "%02x ", buf[i]);
+	sr_spew("%s", s->str);
+	g_string_free(s, TRUE);
+}
+
+static int packet_parse(const uint8_t *buf, int idx, struct center_info *info)
+{
+	int i;
+	uint16_t temp_u16;
+
+	log_packet(buf, idx);
+
+	/* Byte 0: Always 0x02. */
+
+	/* Byte 1: Various status bits. */
+	info->rec         = (buf[1] & (1 << 0)) != 0;
+	info->mode_std    = (((buf[1] >> 1) & 0x3) == 0);
+	info->mode_max    = (((buf[1] >> 1) & 0x3) == 1);
+	info->mode_min    = (((buf[1] >> 1) & 0x3) == 2);
+	info->mode_maxmin = (((buf[1] >> 1) & 0x3) == 3);
+	/* TODO: Rel. Not available on all models. */
+	info->t1t2        = (buf[1] & (1 << 3)) != 0;
+	info->rel         = (buf[1] & (1 << 4)) != 0;
+	info->hold        = (buf[1] & (1 << 5)) != 0;
+	info->lowbat      = (buf[1] & (1 << 6)) != 0;
+	info->celsius     = (buf[1] & (1 << 7)) != 0;
+
+	/* Byte 2: Further status bits. */
+	info->memfull     = (buf[2] & (1 << 0)) != 0;
+	info->autooff     = (buf[2] & (1 << 7)) != 0;
+
+	/* Byte 7+8/9+10/11+12/13+14: channel T1/T2/T3/T4 temperature. */
+	for (i = 0; i < 4; i++) {
+		temp_u16 = buf[8 + (i * 2)];
+		temp_u16 |= ((uint16_t)buf[7 + (i * 2)] << 8);
+		info->temp[i] = (float)temp_u16;
+	}
+
+	/* Byte 43: Specifies whether we need to divide the value(s) by 10. */
+	for (i = 0; i < 4; i++) {
+		/* Bit = 0: Divide by 10. Bit = 1: Don't divide by 10. */
+		if ((buf[43] & (1 << i)) == 0)
+			info->temp[i] /= 10;
+	}
+
+	/* Bytes 39-42: Overflow/overlimit bits, depending on mode. */
+	for (i = 0; i < 4; i++) {
+		if (info->mode_std && ((buf[39] & (1 << i)) != 0))
+			info->temp[i] = INFINITY;
+		/* TODO: Rel. Not available on all models. */
+		// if (info->mode_rel && ((buf[40] & (1 << i)) != 0))
+		// 	info->temp[i] = INFINITY;
+		if (info->mode_max && ((buf[41] & (1 << i)) != 0))
+			info->temp[i] = INFINITY;
+		if (info->mode_min && ((buf[42] & (1 << i)) != 0))
+			info->temp[i] = INFINITY;
+		/* TODO: Minmax? */
+	}
+
+	/* Byte 44: Always 0x03. */
+
+	return SR_OK;
+}
+
+static int handle_packet(const uint8_t *buf, struct sr_dev_inst *sdi, int idx)
+{
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_analog analog;
+	struct dev_context *devc;
+	struct center_info info;
+	GSList *l;
+	int i, ret;
+
+	devc = sdi->priv;
+
+	memset(&analog, 0, sizeof(struct sr_datafeed_analog));
+	memset(&info, 0, sizeof(struct center_info));
+
+	ret = packet_parse(buf, idx, &info);
+	if (ret < 0) {
+		sr_err("Failed to parse packet.");
+		return SR_ERR;
+	}
+
+	/* Common values for all 4 channels. */
+	packet.type = SR_DF_ANALOG;
+	packet.payload = &analog;
+	analog.mq = SR_MQ_TEMPERATURE;
+	analog.unit = (info.celsius) ? SR_UNIT_CELSIUS : SR_UNIT_FAHRENHEIT;
+	analog.num_samples = 1;
+
+	/* Send the values for T1 - T4. */
+	for (i = 0; i < 4; i++) {
+		l = NULL;
+		l = g_slist_append(l, g_slist_nth_data(sdi->channels, i));
+		analog.channels = l;
+		analog.data = &(info.temp[i]);
+		sr_session_send(devc->cb_data, &packet);
+		g_slist_free(l);
+	}
+
+	devc->num_samples++;
+
+	return SR_OK;
+}
+
+/* Return TRUE if a full packet was parsed, FALSE otherwise. */
+static gboolean handle_new_data(struct sr_dev_inst *sdi, int idx)
+{
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+	int len, i, offset = 0, ret = FALSE;
+
+	devc = sdi->priv;
+	serial = sdi->conn;
+
+	/* Try to get as much data as the buffer can hold. */
+	len = SERIAL_BUFSIZE - devc->buflen;
+	len = serial_read(serial, devc->buf + devc->buflen, len);
+	if (len < 1) {
+		sr_err("Serial port read error: %d.", len);
+		return FALSE;
+	}
+
+	devc->buflen += len;
+
+	/* Now look for packets in that data. */
+	while ((devc->buflen - offset) >= center_devs[idx].packet_size) {
+		if (center_devs[idx].packet_valid(devc->buf + offset)) {
+			handle_packet(devc->buf + offset, sdi, idx);
+			offset += center_devs[idx].packet_size;
+			ret = TRUE;
+		} else {
+			offset++;
+		}
+	}
+
+	/* If we have any data left, move it to the beginning of our buffer. */
+	for (i = 0; i < devc->buflen - offset; i++)
+		devc->buf[i] = devc->buf[offset + i];
+	devc->buflen -= offset;
+
+	return ret;
+}
+
+static int receive_data(int fd, int revents, int idx, void *cb_data)
+{
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+	int64_t t;
+	static gboolean request_new_packet = TRUE;
+	struct sr_serial_dev_inst *serial;
+
+	(void)fd;
+
+	if (!(sdi = cb_data))
+		return TRUE;
+
+	if (!(devc = sdi->priv))
+		return TRUE;
+
+	serial = sdi->conn;
+
+	if (revents == G_IO_IN) {
+		/* New data arrived. */
+		request_new_packet = handle_new_data(sdi, idx);
+	} else {
+		/*
+		 * Timeout. Send "A" to request a packet, but then don't send
+		 * further "A" commands until we received a full packet first.
+		 */
+		if (request_new_packet) {
+			center_send(serial, "A");
+			request_new_packet = FALSE;
+		}
+	}
+
+	if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
+		sr_info("Requested number of samples reached.");
+		sdi->driver->dev_acquisition_stop(sdi, cb_data);
+		return TRUE;
+	}
+
+	if (devc->limit_msec) {
+		t = (g_get_monotonic_time() - devc->starttime) / 1000;
+		if (t > (int64_t)devc->limit_msec) {
+			sr_info("Requested time limit reached.");
+			sdi->driver->dev_acquisition_stop(sdi, cb_data);
+			return TRUE;
+		}
+	}
+
+	return TRUE;
+}
+
+#define RECEIVE_DATA(ID_UPPER) \
+SR_PRIV int receive_data_##ID_UPPER(int fd, int revents, void *cb_data) { \
+	return receive_data(fd, revents, ID_UPPER, cb_data); }
+
+/* Driver-specific receive_data() wrappers */
+RECEIVE_DATA(CENTER_309)
+RECEIVE_DATA(VOLTCRAFT_K204)
diff --git a/hardware/center-3xx/protocol.h b/hardware/center-3xx/protocol.h
new file mode 100644
index 0000000..71e2630
--- /dev/null
+++ b/hardware/center-3xx/protocol.h
@@ -0,0 +1,84 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef LIBSIGROK_HARDWARE_CENTER_3XX_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_CENTER_3XX_PROTOCOL_H
+
+#include <stdint.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "center-3xx"
+
+/* Note: When adding entries here, don't forget to update CENTER_DEV_COUNT. */
+enum {
+	CENTER_309,
+	VOLTCRAFT_K204,
+};
+
+#define CENTER_DEV_COUNT 2
+
+struct center_dev_info {
+	char *vendor;
+	char *device;
+	char *conn;
+	int num_channels;
+	uint32_t max_sample_points;
+	uint8_t packet_size;
+	gboolean (*packet_valid)(const uint8_t *);
+	struct sr_dev_driver *di;
+	int (*receive_data)(int, int, void *);
+};
+
+extern SR_PRIV const struct center_dev_info center_devs[CENTER_DEV_COUNT];
+
+#define SERIAL_BUFSIZE 256
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+	/** The current sampling limit (in number of samples). */
+	uint64_t limit_samples;
+
+	/** The current sampling limit (in ms). */
+	uint64_t limit_msec;
+
+	/** Opaque pointer passed in by the frontend. */
+	void *cb_data;
+
+	/** The current number of already received samples. */
+	uint64_t num_samples;
+
+	int64_t starttime;
+
+	uint8_t buf[SERIAL_BUFSIZE];
+	int bufoffset;
+	int buflen;
+};
+
+SR_PRIV gboolean center_3xx_packet_valid(const uint8_t *buf);
+
+SR_PRIV int receive_data_CENTER_309(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_VOLTCRAFT_K204(int fd, int revents, void *cb_data);
+
+#endif
diff --git a/hardware/chronovu-la/api.c b/hardware/chronovu-la/api.c
new file mode 100644
index 0000000..b232a10
--- /dev/null
+++ b/hardware/chronovu-la/api.c
@@ -0,0 +1,549 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2011-2014 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "protocol.h"
+
+SR_PRIV struct sr_dev_driver chronovu_la_driver_info;
+static struct sr_dev_driver *di = &chronovu_la_driver_info;
+
+static const int32_t hwcaps[] = {
+	SR_CONF_LOGIC_ANALYZER,
+	SR_CONF_SAMPLERATE,
+	SR_CONF_TRIGGER_TYPE,
+	SR_CONF_LIMIT_MSEC, /* TODO: Not yet implemented. */
+	SR_CONF_LIMIT_SAMPLES, /* TODO: Not yet implemented. */
+};
+
+/* The ChronoVu LA8/LA16 can have multiple VID/PID pairs. */
+static struct {
+	uint16_t vid;
+	uint16_t pid;
+	int model;
+	const char *iproduct;
+} vid_pid[] = {
+	{ 0x0403, 0x6001, CHRONOVU_LA8,  "ChronoVu LA8"  },
+	{ 0x0403, 0x8867, CHRONOVU_LA8,  "ChronoVu LA8"  },
+	{ 0x0403, 0x6001, CHRONOVU_LA16, "ChronoVu LA16" },
+	{ 0x0403, 0x8867, CHRONOVU_LA16, "ChronoVu LA16" },
+};
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data);
+
+static void clear_helper(void *priv)
+{
+	struct dev_context *devc;
+
+	devc = priv;
+
+	ftdi_free(devc->ftdic);
+	g_free(devc->final_buf);
+}
+
+static int dev_clear(void)
+{
+	return std_dev_clear(di, clear_helper);
+}
+
+static int init(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static int add_device(int idx, int model, GSList **devices)
+{
+	int ret;
+	unsigned int i;
+	struct sr_dev_inst *sdi;
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_channel *ch;
+
+	ret = SR_OK;
+
+	drvc = di->priv;
+
+	/* Allocate memory for our private device context. */
+	devc = g_try_malloc(sizeof(struct dev_context));
+
+	/* Set some sane defaults. */
+	devc->prof = &cv_profiles[model];
+	devc->ftdic = NULL; /* Will be set in the open() API call. */
+	devc->cur_samplerate = 0; /* Set later (different for LA8/LA16). */
+	devc->limit_msec = 0;
+	devc->limit_samples = 0;
+	devc->cb_data = NULL;
+	memset(devc->mangled_buf, 0, BS);
+	devc->final_buf = NULL;
+	devc->trigger_pattern = 0x0000; /* Irrelevant, see trigger_mask. */
+	devc->trigger_mask = 0x0000; /* All channels: "don't care". */
+	devc->trigger_edgemask = 0x0000; /* All channels: "state triggered". */
+	devc->trigger_found = 0;
+	devc->done = 0;
+	devc->block_counter = 0;
+	devc->divcount = 0;
+	devc->usb_vid = vid_pid[idx].vid;
+	devc->usb_pid = vid_pid[idx].pid;
+	memset(devc->samplerates, 0, sizeof(uint64_t) * 255);
+
+	/* Allocate memory where we'll store the de-mangled data. */
+	if (!(devc->final_buf = g_try_malloc(SDRAM_SIZE))) {
+		sr_err("Failed to allocate memory for sample buffer.");
+		ret = SR_ERR_MALLOC;
+		goto err_free_devc;
+	}
+
+	/* We now know the device, set its max. samplerate as default. */
+	devc->cur_samplerate = devc->prof->max_samplerate;
+
+	/* Register the device with libsigrok. */
+	sdi = sr_dev_inst_new(0, SR_ST_INITIALIZING,
+			      "ChronoVu", devc->prof->modelname, NULL);
+	if (!sdi) {
+		sr_err("Failed to create device instance.");
+		ret = SR_ERR;
+		goto err_free_final_buf;
+	}
+	sdi->driver = di;
+	sdi->priv = devc;
+
+	for (i = 0; i < devc->prof->num_channels; i++) {
+		if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE,
+					  cv_channel_names[i]))) {
+			ret = SR_ERR;
+			goto err_free_dev_inst;
+		}
+		sdi->channels = g_slist_append(sdi->channels, ch);
+	}
+
+	*devices = g_slist_append(*devices, sdi);
+	drvc->instances = g_slist_append(drvc->instances, sdi);
+
+	return SR_OK;
+
+err_free_dev_inst:
+	sr_dev_inst_free(sdi);
+err_free_final_buf:
+	g_free(devc->final_buf);
+err_free_devc:
+	g_free(devc);
+
+	return ret;
+}
+
+static GSList *scan(GSList *options)
+{
+	int ret;
+	unsigned int i;
+	GSList *devices;
+	struct ftdi_context *ftdic;
+
+	(void)options;
+
+	devices = NULL;
+
+	/* Allocate memory for the FTDI context and initialize it. */
+	if (!(ftdic = ftdi_new())) {
+		sr_err("Failed to initialize libftdi.");
+		return NULL;
+	}
+
+	/* Check for LA8 and/or LA16 devices with various VID/PIDs. */
+	for (i = 0; i < ARRAY_SIZE(vid_pid); i++) {
+		ret = ftdi_usb_open_desc(ftdic, vid_pid[i].vid,
+			vid_pid[i].pid, vid_pid[i].iproduct, NULL);
+		/* Show errors other than "device not found". */
+		if (ret < 0 && ret != -3)
+			sr_dbg("Error finding/opening device (%d): %s.",
+			       ret, ftdi_get_error_string(ftdic));
+		if (ret < 0)
+			continue; /* No device found, or not usable. */
+
+		sr_dbg("Found %s device (%04x:%04x).",
+		       vid_pid[i].iproduct, vid_pid[i].vid, vid_pid[i].pid);
+
+		if ((ret = add_device(i, vid_pid[i].model, &devices)) < 0)
+			sr_dbg("Failed to add device: %d.", ret);
+
+		if ((ret = ftdi_usb_close(ftdic)) < 0)
+			sr_dbg("Failed to close FTDI device (%d): %s.",
+			       ret, ftdi_get_error_string(ftdic));
+	}
+
+	/* Close USB device, deinitialize and free the FTDI context. */
+	ftdi_free(ftdic);
+	ftdic = NULL;
+
+	return devices;
+}
+
+static GSList *dev_list(void)
+{
+	return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	int ret;
+
+	ret = SR_ERR;
+
+	if (!(devc = sdi->priv))
+		return SR_ERR_BUG;
+
+	/* Allocate memory for the FTDI context and initialize it. */
+	if (!(devc->ftdic = ftdi_new())) {
+		sr_err("Failed to initialize libftdi.");
+		return SR_ERR;
+	}
+
+	sr_dbg("Opening %s device (%04x:%04x).", devc->prof->modelname,
+	       devc->usb_vid, devc->usb_pid);
+
+	/* Open the device. */
+	if ((ret = ftdi_usb_open_desc(devc->ftdic, devc->usb_vid,
+			devc->usb_pid, devc->prof->iproduct, NULL)) < 0) {
+		sr_err("Failed to open FTDI device (%d): %s.",
+		       ret, ftdi_get_error_string(devc->ftdic));
+		goto err_ftdi_free;
+	}
+	sr_dbg("Device opened successfully.");
+
+	/* Purge RX/TX buffers in the FTDI chip. */
+	if ((ret = ftdi_usb_purge_buffers(devc->ftdic)) < 0) {
+		sr_err("Failed to purge FTDI buffers (%d): %s.",
+		       ret, ftdi_get_error_string(devc->ftdic));
+		goto err_ftdi_free;
+	}
+	sr_dbg("FTDI buffers purged successfully.");
+
+	/* Enable flow control in the FTDI chip. */
+	if ((ret = ftdi_setflowctrl(devc->ftdic, SIO_RTS_CTS_HS)) < 0) {
+		sr_err("Failed to enable FTDI flow control (%d): %s.",
+		       ret, ftdi_get_error_string(devc->ftdic));
+		goto err_ftdi_free;
+	}
+	sr_dbg("FTDI flow control enabled successfully.");
+
+	/* Wait 100ms. */
+	g_usleep(100 * 1000);
+
+	sdi->status = SR_ST_ACTIVE;
+
+	return SR_OK;
+
+err_ftdi_free:
+	ftdi_free(devc->ftdic); /* Close device (if open), free FTDI context. */
+	devc->ftdic = NULL;
+	return ret;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+	int ret;
+	struct dev_context *devc;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_OK;
+
+	devc = sdi->priv;
+
+	if (devc->ftdic && (ret = ftdi_usb_close(devc->ftdic)) < 0)
+		sr_err("Failed to close FTDI device (%d): %s.",
+		       ret, ftdi_get_error_string(devc->ftdic));
+	sdi->status = SR_ST_INACTIVE;
+
+	return SR_OK;
+}
+
+static int cleanup(void)
+{
+	return dev_clear();
+}
+
+static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+
+	(void)cg;
+
+	switch (id) {
+	case SR_CONF_SAMPLERATE:
+		if (!sdi || !(devc = sdi->priv))
+			return SR_ERR_BUG;
+		*data = g_variant_new_uint64(devc->cur_samplerate);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+
+	(void)cg;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!(devc = sdi->priv))
+		return SR_ERR_BUG;
+
+	switch (id) {
+	case SR_CONF_SAMPLERATE:
+		if (cv_set_samplerate(sdi, g_variant_get_uint64(data)) < 0)
+			return SR_ERR;
+		break;
+	case SR_CONF_LIMIT_MSEC:
+		if (g_variant_get_uint64(data) == 0)
+			return SR_ERR_ARG;
+		devc->limit_msec = g_variant_get_uint64(data);
+		break;
+	case SR_CONF_LIMIT_SAMPLES:
+		if (g_variant_get_uint64(data) == 0)
+			return SR_ERR_ARG;
+		devc->limit_samples = g_variant_get_uint64(data);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	GVariant *gvar, *grange[2];
+	GVariantBuilder gvb;
+	struct dev_context *devc;
+
+	(void)cg;
+
+	switch (key) {
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+		break;
+	case SR_CONF_SAMPLERATE:
+		if (!sdi || !sdi->priv || !(devc = sdi->priv))
+			return SR_ERR_BUG;
+		cv_fill_samplerates_if_needed(sdi);
+		g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
+		gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
+				devc->samplerates,
+				ARRAY_SIZE(devc->samplerates),
+				sizeof(uint64_t));
+		g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
+		*data = g_variant_builder_end(&gvb);
+		break;
+	case SR_CONF_LIMIT_SAMPLES:
+		if (!sdi || !sdi->priv || !(devc = sdi->priv) || !devc->prof)
+			return SR_ERR_BUG;
+		grange[0] = g_variant_new_uint64(0);
+		if (devc->prof->model == CHRONOVU_LA8)
+			grange[1] = g_variant_new_uint64(MAX_NUM_SAMPLES);
+		else
+			grange[1] = g_variant_new_uint64(MAX_NUM_SAMPLES / 2);
+		*data = g_variant_new_tuple(grange, 2);
+		break;
+	case SR_CONF_TRIGGER_TYPE:
+		if (!sdi || !sdi->priv || !(devc = sdi->priv) || !devc->prof)
+			return SR_ERR_BUG;
+		*data = g_variant_new_string(devc->prof->trigger_type);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int receive_data(int fd, int revents, void *cb_data)
+{
+	int i, ret;
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+
+	(void)fd;
+	(void)revents;
+
+	if (!(sdi = cb_data)) {
+		sr_err("cb_data was NULL.");
+		return FALSE;
+	}
+
+	if (!(devc = sdi->priv)) {
+		sr_err("sdi->priv was NULL.");
+		return FALSE;
+	}
+
+	if (!devc->ftdic) {
+		sr_err("devc->ftdic was NULL.");
+		return FALSE;
+	}
+
+	/* Get one block of data. */
+	if ((ret = cv_read_block(devc)) < 0) {
+		sr_err("Failed to read data block: %d.", ret);
+		dev_acquisition_stop(sdi, sdi);
+		return FALSE;
+	}
+
+	/* We need to get exactly NUM_BLOCKS blocks (i.e. 8MB) of data. */
+	if (devc->block_counter != (NUM_BLOCKS - 1)) {
+		devc->block_counter++;
+		return TRUE;
+	}
+
+	sr_dbg("Sampling finished, sending data to session bus now.");
+
+	/*
+	 * All data was received and demangled, send it to the session bus.
+	 *
+	 * Note: Due to the method how data is spread across the 8MByte of
+	 * SDRAM, we can _not_ send it to the session bus in a streaming
+	 * manner while we receive it. We have to receive and de-mangle the
+	 * full 8MByte first, only then the whole buffer contains valid data.
+	 */
+	for (i = 0; i < NUM_BLOCKS; i++)
+		cv_send_block_to_session_bus(devc, i);
+
+	dev_acquisition_stop(sdi, sdi);
+
+	return TRUE;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct dev_context *devc;
+	uint8_t buf[8];
+	int bytes_to_write, bytes_written;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!(devc = sdi->priv)) {
+		sr_err("sdi->priv was NULL.");
+		return SR_ERR_BUG;
+	}
+
+	if (!devc->ftdic) {
+		sr_err("devc->ftdic was NULL.");
+		return SR_ERR_BUG;
+	}
+
+	devc->divcount = cv_samplerate_to_divcount(sdi, devc->cur_samplerate);
+	if (devc->divcount == 0xff) {
+		sr_err("Invalid divcount/samplerate.");
+		return SR_ERR;
+	}
+
+	if (cv_configure_channels(sdi) != SR_OK) {
+		sr_err("Failed to configure channels.");
+		return SR_ERR;
+	}
+
+	/* Fill acquisition parameters into buf[]. */
+	if (devc->prof->model == CHRONOVU_LA8) {
+		buf[0] = devc->divcount;
+		buf[1] = 0xff; /* This byte must always be 0xff. */
+		buf[2] = devc->trigger_pattern & 0xff;
+		buf[3] = devc->trigger_mask & 0xff;
+		bytes_to_write = 4;
+	} else {
+		buf[0] = devc->divcount;
+		buf[1] = 0xff; /* This byte must always be 0xff. */
+		buf[2] = (devc->trigger_pattern & 0xff00) >> 8;  /* LSB */
+		buf[3] = (devc->trigger_pattern & 0x00ff) >> 0;  /* MSB */
+		buf[4] = (devc->trigger_mask & 0xff00) >> 8;     /* LSB */
+		buf[5] = (devc->trigger_mask & 0x00ff) >> 0;     /* MSB */
+		buf[6] = (devc->trigger_edgemask & 0xff00) >> 8; /* LSB */
+		buf[7] = (devc->trigger_edgemask & 0x00ff) >> 0; /* MSB */
+		bytes_to_write = 8;
+	}
+
+	/* Start acquisition. */
+	bytes_written = cv_write(devc, buf, bytes_to_write);
+
+	if (bytes_written < 0 || bytes_written != bytes_to_write) {
+		sr_err("Acquisition failed to start.");
+		return SR_ERR;
+	}
+
+	sr_dbg("Hardware acquisition started successfully.");
+
+	devc->cb_data = cb_data;
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	/* Time when we should be done (for detecting trigger timeouts). */
+	devc->done = (devc->divcount + 1) * devc->prof->trigger_constant +
+			g_get_monotonic_time() + (10 * G_TIME_SPAN_SECOND);
+	devc->block_counter = 0;
+	devc->trigger_found = 0;
+
+	/* Hook up a dummy handler to receive data from the device. */
+	sr_source_add(-1, G_IO_IN, 0, receive_data, (void *)sdi);
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct sr_datafeed_packet packet;
+
+	(void)sdi;
+
+	sr_dbg("Stopping acquisition.");
+	sr_source_remove(-1);
+
+	/* Send end packet to the session bus. */
+	sr_dbg("Sending SR_DF_END.");
+	packet.type = SR_DF_END;
+	sr_session_send(cb_data, &packet);
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver chronovu_la_driver_info = {
+	.name = "chronovu-la",
+	.longname = "ChronoVu LA8/LA16",
+	.api_version = 1,
+	.init = init,
+	.cleanup = cleanup,
+	.scan = scan,
+	.dev_list = dev_list,
+	.dev_clear = dev_clear,
+	.config_get = config_get,
+	.config_set = config_set,
+	.config_list = config_list,
+	.dev_open = dev_open,
+	.dev_close = dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/chronovu-la/protocol.c b/hardware/chronovu-la/protocol.c
new file mode 100644
index 0000000..5b4723c
--- /dev/null
+++ b/hardware/chronovu-la/protocol.c
@@ -0,0 +1,521 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2011-2014 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "protocol.h"
+
+SR_PRIV const struct cv_profile cv_profiles[] = {
+	{ CHRONOVU_LA8,  "LA8",  "ChronoVu LA8",  8,  SR_MHZ(100), "01",
+	  0.8388608 },
+	{ CHRONOVU_LA16, "LA16", "ChronoVu LA16", 16, SR_MHZ(200), "01rf",
+	  0.042 },
+	{ 0, NULL, NULL, 0, 0, NULL, 0.0 },
+};
+
+/* LA8: channels are numbered 0-7. LA16: channels are numbered 0-15. */
+SR_PRIV const char *cv_channel_names[] = {
+	"0", "1", "2", "3", "4", "5", "6", "7",
+	"8", "9", "10", "11", "12", "13", "14", "15",
+};
+
+static int close_usb_reset_sequencer(struct dev_context *devc);
+
+SR_PRIV void cv_fill_samplerates_if_needed(const struct sr_dev_inst *sdi)
+{
+	int i;
+	struct dev_context *devc;
+
+	devc = sdi->priv;
+
+	if (devc->samplerates[0] != 0)
+		return;
+
+	for (i = 0; i < 255; i++)
+		devc->samplerates[254 - i] = devc->prof->max_samplerate / (i + 1);
+}
+
+/**
+ * Check if the given samplerate is supported by the hardware.
+ *
+ * @param sdi Device instance.
+ * @param samplerate The samplerate (in Hz) to check.
+ *
+ * @return 1 if the samplerate is supported/valid, 0 otherwise.
+ */
+static int is_valid_samplerate(const struct sr_dev_inst *sdi,
+			       uint64_t samplerate)
+{
+	int i;
+	struct dev_context *devc;
+
+	devc = sdi->priv;
+
+	cv_fill_samplerates_if_needed(sdi);
+
+	for (i = 0; i < 255; i++) {
+		if (devc->samplerates[i] == samplerate)
+			return 1;
+	}
+
+	sr_err("Invalid samplerate (%" PRIu64 "Hz).", samplerate);
+
+	return 0;
+}
+
+/**
+ * Convert a samplerate (in Hz) to the 'divcount' value the device wants.
+ *
+ * The divcount value can be 0x00 - 0xfe (0xff is not valid).
+ *
+ * LA8:
+ * sample period = (divcount + 1) * 10ns.
+ * divcount = 0x00: 10ns period, 100MHz samplerate.
+ * divcount = 0xfe: 2550ns period, 392.15kHz samplerate.
+ *
+ * LA16:
+ * sample period = (divcount + 1) * 5ns.
+ * divcount = 0x00: 5ns period, 200MHz samplerate.
+ * divcount = 0xfe: 1275ns period, ~784.31kHz samplerate.
+ *
+ * @param sdi Device instance.
+ * @param samplerate The samplerate in Hz.
+ *
+ * @return The divcount value as needed by the hardware, or 0xff upon errors.
+ */
+SR_PRIV uint8_t cv_samplerate_to_divcount(const struct sr_dev_inst *sdi,
+					  uint64_t samplerate)
+{
+	struct dev_context *devc;
+
+	devc = sdi->priv;
+
+	if (samplerate == 0) {
+		sr_err("Can't convert invalid samplerate of 0 Hz.");
+		return 0xff;
+	}
+
+	if (!is_valid_samplerate(sdi, samplerate)) {
+		sr_err("Can't get divcount, samplerate invalid.");
+		return 0xff;
+	}
+
+	return (devc->prof->max_samplerate / samplerate) - 1;
+}
+
+/**
+ * Write data of a certain length to the FTDI device.
+ *
+ * @param devc The struct containing private per-device-instance data. Must not
+ *             be NULL. devc->ftdic must not be NULL either.
+ * @param buf The buffer containing the data to write. Must not be NULL.
+ * @param size The number of bytes to write. Must be > 0.
+ *
+ * @return The number of bytes written, or a negative value upon errors.
+ */
+SR_PRIV int cv_write(struct dev_context *devc, uint8_t *buf, int size)
+{
+	int bytes_written;
+
+	/* Note: Caller ensures devc/devc->ftdic/buf != NULL and size > 0. */
+
+	bytes_written = ftdi_write_data(devc->ftdic, buf, size);
+
+	if (bytes_written < 0) {
+		sr_err("Failed to write data (%d): %s.",
+		       bytes_written, ftdi_get_error_string(devc->ftdic));
+		(void) close_usb_reset_sequencer(devc); /* Ignore errors. */
+	} else if (bytes_written != size) {
+		sr_err("Failed to write data, only %d/%d bytes written.",
+		       size, bytes_written);
+		(void) close_usb_reset_sequencer(devc); /* Ignore errors. */
+	}
+
+	return bytes_written;
+}
+
+/**
+ * Read a certain amount of bytes from the FTDI device.
+ *
+ * @param devc The struct containing private per-device-instance data. Must not
+ *             be NULL. devc->ftdic must not be NULL either.
+ * @param buf The buffer where the received data will be stored. Must not
+ *            be NULL.
+ * @param size The number of bytes to read. Must be >= 1.
+ *
+ * @return The number of bytes read, or a negative value upon errors.
+ */
+static int cv_read(struct dev_context *devc, uint8_t *buf, int size)
+{
+	int bytes_read;
+
+	/* Note: Caller ensures devc/devc->ftdic/buf != NULL and size > 0. */
+
+	bytes_read = ftdi_read_data(devc->ftdic, buf, size);
+
+	if (bytes_read < 0) {
+		sr_err("Failed to read data (%d): %s.",
+		       bytes_read, ftdi_get_error_string(devc->ftdic));
+	} else if (bytes_read != size) {
+		// sr_err("Failed to read data, only %d/%d bytes read.",
+		//        bytes_read, size);
+	}
+
+	return bytes_read;
+}
+
+/**
+ * Close the USB port and reset the sequencer logic.
+ *
+ * @param devc The struct containing private per-device-instance data.
+ *
+ * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments.
+ */
+static int close_usb_reset_sequencer(struct dev_context *devc)
+{
+	/* Magic sequence of bytes for resetting the sequencer logic. */
+	uint8_t buf[8] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};
+	int ret;
+
+	/* Note: Caller checked that devc and devc->ftdic != NULL. */
+
+	if (devc->ftdic->usb_dev) {
+		/* Reset the sequencer logic, then wait 100ms. */
+		sr_dbg("Resetting sequencer logic.");
+		(void) cv_write(devc, buf, 8); /* Ignore errors. */
+		g_usleep(100 * 1000);
+
+		/* Purge FTDI buffers, then reset and close the FTDI device. */
+		sr_dbg("Purging buffers, resetting+closing FTDI device.");
+
+		/* Log errors, but ignore them (i.e., don't abort). */
+		if ((ret = ftdi_usb_purge_buffers(devc->ftdic)) < 0)
+			sr_err("Failed to purge FTDI buffers (%d): %s.",
+			       ret, ftdi_get_error_string(devc->ftdic));
+		if ((ret = ftdi_usb_reset(devc->ftdic)) < 0)
+			sr_err("Failed to reset FTDI device (%d): %s.",
+			       ret, ftdi_get_error_string(devc->ftdic));
+		if ((ret = ftdi_usb_close(devc->ftdic)) < 0)
+			sr_err("Failed to close FTDI device (%d): %s.",
+			       ret, ftdi_get_error_string(devc->ftdic));
+	}
+
+	/* Close USB device, deinitialize and free the FTDI context. */
+	ftdi_free(devc->ftdic);
+	devc->ftdic = NULL;
+
+	return SR_OK;
+}
+
+/**
+ * Reset the ChronoVu device.
+ *
+ * A reset is required after a failed read/write operation or upon timeouts.
+ *
+ * @param devc The struct containing private per-device-instance data.
+ *
+ * @return SR_OK upon success, SR_ERR upon failure.
+ */
+static int reset_device(struct dev_context *devc)
+{
+	uint8_t buf[BS];
+	gint64 done, now;
+	int bytes_read;
+
+	/* Note: Caller checked that devc and devc->ftdic != NULL. */
+
+	sr_dbg("Resetting the device.");
+
+	/*
+	 * Purge pending read data from the FTDI hardware FIFO until
+	 * no more data is left, or a timeout occurs (after 20s).
+	 */
+	done = (20 * G_TIME_SPAN_SECOND) + g_get_monotonic_time();
+	do {
+		/* Try to read bytes until none are left (or errors occur). */
+		bytes_read = cv_read(devc, (uint8_t *)&buf, BS);
+		now = g_get_monotonic_time();
+	} while ((done > now) && (bytes_read > 0));
+
+	/* Reset the sequencer logic and close the USB port. */
+	(void) close_usb_reset_sequencer(devc); /* Ignore errors. */
+
+	sr_dbg("Device reset finished.");
+
+	return SR_OK;
+}
+
+SR_PRIV int cv_configure_channels(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	const struct sr_channel *ch;
+	const GSList *l;
+	uint16_t channel_bit;
+	char *tc;
+
+	devc = sdi->priv;
+	devc->trigger_pattern = 0x0000; /* Default to "low" trigger. */
+	devc->trigger_mask = 0x0000; /* Default to "don't care". */
+	devc->trigger_edgemask = 0x0000; /* Default to "state triggered". */
+
+	for (l = sdi->channels; l; l = l->next) {
+		ch = (struct sr_channel *)l->data;
+
+		if (!ch) {
+			sr_err("%s: channel was NULL.", __func__);
+			return SR_ERR;
+		}
+
+		/* Skip disabled channels. */
+		if (!ch->enabled)
+			continue;
+
+		/* Skip (enabled) channels with no configured trigger. */
+		if (!ch->trigger)
+			continue;
+
+		/* Note: Must only be run if ch->trigger != NULL. */
+		if (ch->index < 0 || ch->index > (int)devc->prof->num_channels - 1) {
+			sr_err("Invalid channel index %d, must be "
+			       "between 0 and %d.", ch->index,
+			       devc->prof->num_channels - 1);
+			return SR_ERR;
+		}
+
+		channel_bit = (1 << (ch->index));
+
+		/* Configure the channel's trigger pattern/mask/edgemask. */
+		for (tc = ch->trigger; tc && *tc; tc++) {
+			devc->trigger_mask |= channel_bit;
+
+			/* Sanity check, LA8 only supports low/high trigger. */
+			if ((devc->prof->model == CHRONOVU_LA8) &&
+			    (*tc != '0' && *tc != '1')) {
+				sr_err("Invalid trigger '%c', only "
+				       "'0'/'1' supported.", *tc);
+				return SR_ERR;
+			}
+
+			/* state: 1 == high, edge: 1 == rising edge. */
+			if (*tc == '1' || *tc == 'r')
+				devc->trigger_pattern |= channel_bit;
+
+			/* LA16 (but not LA8) supports edge triggering. */
+			if ((devc->prof->model == CHRONOVU_LA16)) {
+				if (*tc == 'r' || *tc == 'f')
+					devc->trigger_edgemask |= channel_bit;
+			}
+
+		}
+	}
+
+	sr_dbg("Trigger pattern/mask/edgemask = 0x%04x / 0x%04x / 0x%04x.",
+	       devc->trigger_pattern, devc->trigger_mask,
+	       devc->trigger_edgemask);
+
+	return SR_OK;
+}
+
+SR_PRIV int cv_set_samplerate(const struct sr_dev_inst *sdi, uint64_t samplerate)
+{
+	struct dev_context *devc;
+
+	/* Note: Caller checked that sdi and sdi->priv != NULL. */
+
+	devc = sdi->priv;
+
+	sr_spew("Trying to set samplerate to %" PRIu64 "Hz.", samplerate);
+
+	cv_fill_samplerates_if_needed(sdi);
+
+	/* Check if this is a samplerate supported by the hardware. */
+	if (!is_valid_samplerate(sdi, samplerate)) {
+		sr_dbg("Failed to set invalid samplerate (%" PRIu64 "Hz).",
+		       samplerate);
+		return SR_ERR;
+	}
+
+	devc->cur_samplerate = samplerate;
+
+	sr_dbg("Samplerate set to %" PRIu64 "Hz.", devc->cur_samplerate);
+
+	return SR_OK;
+}
+
+/**
+ * Get a block of data from the device.
+ *
+ * @param devc The struct containing private per-device-instance data. Must not
+ *             be NULL. devc->ftdic must not be NULL either.
+ *
+ * @return SR_OK upon success, or SR_ERR upon errors.
+ */
+SR_PRIV int cv_read_block(struct dev_context *devc)
+{
+	int i, byte_offset, m, mi, p, q, index, bytes_read;
+	gint64 now;
+
+	/* Note: Caller checked that devc and devc->ftdic != NULL. */
+
+	sr_spew("Reading block %d.", devc->block_counter);
+
+	bytes_read = cv_read(devc, devc->mangled_buf, BS);
+
+	/* If first block read got 0 bytes, retry until success or timeout. */
+	if ((bytes_read == 0) && (devc->block_counter == 0)) {
+		do {
+			sr_spew("Reading block 0 (again).");
+			/* Note: If bytes_read < 0 cv_read() will log errors. */
+			bytes_read = cv_read(devc, devc->mangled_buf, BS);
+			now = g_get_monotonic_time();
+		} while ((devc->done > now) && (bytes_read == 0));
+	}
+
+	/* Check if block read was successful or a timeout occured. */
+	if (bytes_read != BS) {
+		sr_err("Trigger timed out. Bytes read: %d.", bytes_read);
+		(void) reset_device(devc); /* Ignore errors. */
+		return SR_ERR;
+	}
+
+	/* De-mangle the data. */
+	sr_spew("Demangling block %d.", devc->block_counter);
+	byte_offset = devc->block_counter * BS;
+	m = byte_offset / (1024 * 1024);
+	mi = m * (1024 * 1024);
+	for (i = 0; i < BS; i++) {
+		if (devc->prof->model == CHRONOVU_LA8) {
+			p = i & (1 << 0);
+			index = m * 2 + (((byte_offset + i) - mi) / 2) * 16;
+			index += (devc->divcount == 0) ? p : (1 - p);
+		} else {
+			p = i & (1 << 0);
+			q = i & (1 << 1);
+			index = m * 4 + (((byte_offset + i) - mi) / 4) * 32;
+			index += q + (1 - p);
+		}
+		devc->final_buf[index] = devc->mangled_buf[i];
+	}
+
+	return SR_OK;
+}
+
+SR_PRIV void cv_send_block_to_session_bus(struct dev_context *devc, int block)
+{
+	int i, idx;
+	uint8_t sample, expected_sample, tmp8;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_logic logic;
+	int trigger_point; /* Relative trigger point (in this block). */
+
+	/* Note: Caller ensures devc/devc->ftdic != NULL and block > 0. */
+
+	/* TODO: Implement/test proper trigger support for the LA16. */
+
+	/* Check if we can find the trigger condition in this block. */
+	trigger_point = -1;
+	expected_sample = devc->trigger_pattern & devc->trigger_mask;
+	for (i = 0; i < BS; i++) {
+		/* Don't continue if the trigger was found previously. */
+		if (devc->trigger_found)
+			break;
+
+		/*
+		 * Also, don't continue if triggers are "don't care", i.e. if
+		 * no trigger conditions were specified by the user. In that
+		 * case we don't want to send an SR_DF_TRIGGER packet at all.
+		 */
+		if (devc->trigger_mask == 0x0000)
+			break;
+
+		sample = *(devc->final_buf + (block * BS) + i);
+
+		if ((sample & devc->trigger_mask) == expected_sample) {
+			trigger_point = i;
+			devc->trigger_found = 1;
+			break;
+		}
+	}
+
+	/* Swap low and high bytes of the 16-bit LA16 samples. */
+	if (devc->prof->model == CHRONOVU_LA16) {
+		for (i = 0; i < BS; i += 2) {
+			idx = (block * BS) + i;
+			tmp8 = devc->final_buf[idx];
+			devc->final_buf[idx] = devc->final_buf[idx + 1];
+			devc->final_buf[idx + 1] = tmp8;
+		}
+	}
+
+	/* If no trigger was found, send one SR_DF_LOGIC packet. */
+	if (trigger_point == -1) {
+		/* Send an SR_DF_LOGIC packet to the session bus. */
+		sr_spew("Sending SR_DF_LOGIC packet (%d bytes) for "
+		        "block %d.", BS, block);
+		packet.type = SR_DF_LOGIC;
+		packet.payload = &logic;
+		logic.length = BS;
+		logic.unitsize = devc->prof->num_channels / 8;
+		logic.data = devc->final_buf + (block * BS);
+		sr_session_send(devc->cb_data, &packet);
+		return;
+	}
+
+	/*
+	 * We found the trigger, so some special handling is needed. We have
+	 * to send an SR_DF_LOGIC packet with the samples before the trigger
+	 * (if any), then the SD_DF_TRIGGER packet itself, then another
+	 * SR_DF_LOGIC packet with the samples after the trigger (if any).
+	 */
+
+	/* TODO: Send SR_DF_TRIGGER packet before or after the actual sample? */
+
+	/* If at least one sample is located before the trigger... */
+	if (trigger_point > 0) {
+		/* Send pre-trigger SR_DF_LOGIC packet to the session bus. */
+		sr_spew("Sending pre-trigger SR_DF_LOGIC packet, "
+			"start = %d, length = %d.", block * BS, trigger_point);
+		packet.type = SR_DF_LOGIC;
+		packet.payload = &logic;
+		logic.length = trigger_point;
+		logic.unitsize = devc->prof->num_channels / 8;
+		logic.data = devc->final_buf + (block * BS);
+		sr_session_send(devc->cb_data, &packet);
+	}
+
+	/* Send the SR_DF_TRIGGER packet to the session bus. */
+	sr_spew("Sending SR_DF_TRIGGER packet, sample = %d.",
+		(block * BS) + trigger_point);
+	packet.type = SR_DF_TRIGGER;
+	packet.payload = NULL;
+	sr_session_send(devc->cb_data, &packet);
+
+	/* If at least one sample is located after the trigger... */
+	if (trigger_point < (BS - 1)) {
+		/* Send post-trigger SR_DF_LOGIC packet to the session bus. */
+		sr_spew("Sending post-trigger SR_DF_LOGIC packet, "
+			"start = %d, length = %d.",
+			(block * BS) + trigger_point, BS - trigger_point);
+		packet.type = SR_DF_LOGIC;
+		packet.payload = &logic;
+		logic.length = BS - trigger_point;
+		logic.unitsize = devc->prof->num_channels / 8;
+		logic.data = devc->final_buf + (block * BS) + trigger_point;
+		sr_session_send(devc->cb_data, &packet);
+	}
+}
diff --git a/hardware/chronovu-la/protocol.h b/hardware/chronovu-la/protocol.h
new file mode 100644
index 0000000..6941661
--- /dev/null
+++ b/hardware/chronovu-la/protocol.h
@@ -0,0 +1,141 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2011-2014 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef LIBSIGROK_HARDWARE_CHRONOVU_LA_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_CHRONOVU_LA_PROTOCOL_H
+
+#include <glib.h>
+#include <ftdi.h>
+#include <stdint.h>
+#include <string.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "la8/la16"
+
+#define SDRAM_SIZE			(8 * 1024 * 1024)
+#define MAX_NUM_SAMPLES			SDRAM_SIZE
+
+#define BS				4096 /* Block size */
+#define NUM_BLOCKS			2048 /* Number of blocks */
+
+enum {
+	CHRONOVU_LA8,
+	CHRONOVU_LA16,
+};
+
+struct cv_profile {
+	int model;
+	const char *modelname;
+	const char *iproduct; /* USB iProduct string */
+	unsigned int num_channels;
+	uint64_t max_samplerate;
+	const char *trigger_type;
+	float trigger_constant;
+};
+
+/* Private, per-device-instance driver context. */
+struct dev_context {
+	/** Device profile struct for this device. */
+	const struct cv_profile *prof;
+
+	/** FTDI device context (used by libftdi). */
+	struct ftdi_context *ftdic;
+
+	/** The currently configured samplerate of the device. */
+	uint64_t cur_samplerate;
+
+	/** The current sampling limit (in ms). */
+	uint64_t limit_msec;
+
+	/** The current sampling limit (in number of samples). */
+	uint64_t limit_samples;
+
+	void *cb_data;
+
+	/**
+	 * A buffer containing some (mangled) samples from the device.
+	 * Format: Pretty mangled-up (due to hardware reasons), see code.
+	 */
+	uint8_t mangled_buf[BS];
+
+	/**
+	 * An 8MB buffer where we'll store the de-mangled samples.
+	 * LA8: Each sample is 1 byte, MSB is channel 7, LSB is channel 0.
+	 * LA16: Each sample is 2 bytes, MSB is channel 15, LSB is channel 0.
+	 */
+	uint8_t *final_buf;
+
+	/**
+	 * Trigger pattern.
+	 * A 1 bit matches a high signal, 0 matches a low signal on a channel.
+	 *
+	 * If the resp. 'trigger_edgemask' bit is set, 1 means "rising edge",
+	 * and 0 means "falling edge".
+	 */
+	uint16_t trigger_pattern;
+
+	/**
+	 * Trigger mask.
+	 * A 1 bit means "must match trigger_pattern", 0 means "don't care".
+	 */
+	uint16_t trigger_mask;
+
+	/**
+	 * Trigger edge mask.
+	 * A 1 bit means "edge triggered", 0 means "state triggered".
+	 *
+	 * Edge triggering is only supported on LA16 (but not LA8).
+	 */
+	uint16_t trigger_edgemask;
+
+	/** Tells us whether an SR_DF_TRIGGER packet was already sent. */
+	int trigger_found;
+
+	/** Used for keeping track how much time has passed. */
+	gint64 done;
+
+	/** Counter/index for the data block to be read. */
+	int block_counter;
+
+	/** The divcount value (determines the sample period). */
+	uint8_t divcount;
+
+	/** This ChronoVu device's USB VID/PID. */
+	uint16_t usb_vid;
+	uint16_t usb_pid;
+
+	/** Samplerates supported by this device. */
+	uint64_t samplerates[255];
+};
+
+/* protocol.c */
+extern SR_PRIV const char *cv_channel_names[];
+extern const struct cv_profile cv_profiles[];
+SR_PRIV void cv_fill_samplerates_if_needed(const struct sr_dev_inst *sdi);
+SR_PRIV uint8_t cv_samplerate_to_divcount(const struct sr_dev_inst *sdi,
+					  uint64_t samplerate);
+SR_PRIV int cv_write(struct dev_context *devc, uint8_t *buf, int size);
+SR_PRIV int cv_configure_channels(const struct sr_dev_inst *sdi);
+SR_PRIV int cv_set_samplerate(const struct sr_dev_inst *sdi, uint64_t samplerate);
+SR_PRIV int cv_read_block(struct dev_context *devc);
+SR_PRIV void cv_send_block_to_session_bus(struct dev_context *devc, int block);
+
+#endif
diff --git a/hardware/colead-slm/api.c b/hardware/colead-slm/api.c
new file mode 100644
index 0000000..f658827
--- /dev/null
+++ b/hardware/colead-slm/api.c
@@ -0,0 +1,241 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+/* The Colead SL-5868P uses this. */
+#define SERIALCOMM "2400/8n1"
+
+static const int32_t hwopts[] = {
+	SR_CONF_CONN,
+	SR_CONF_SERIALCOMM,
+};
+
+static const int32_t hwcaps[] = {
+	SR_CONF_SOUNDLEVELMETER,
+	SR_CONF_LIMIT_SAMPLES,
+	SR_CONF_LIMIT_MSEC,
+	SR_CONF_CONTINUOUS,
+};
+
+SR_PRIV struct sr_dev_driver colead_slm_driver_info;
+static struct sr_dev_driver *di = &colead_slm_driver_info;
+
+static int init(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_dev_inst *sdi;
+	struct sr_config *src;
+	struct sr_channel *ch;
+	GSList *devices, *l;
+	const char *conn, *serialcomm;
+
+	drvc = di->priv;
+	drvc->instances = NULL;
+
+	devices = NULL;
+
+	conn = serialcomm = NULL;
+	for (l = options; l; l = l->next) {
+		src = l->data;
+		switch (src->key) {
+		case SR_CONF_CONN:
+			conn = g_variant_get_string(src->data, NULL);
+			break;
+		case SR_CONF_SERIALCOMM:
+			serialcomm = g_variant_get_string(src->data, NULL);
+			break;
+		}
+	}
+	if (!conn)
+		return NULL;
+	if (!serialcomm)
+		serialcomm = SERIALCOMM;
+
+	if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "Colead",
+			"SL-5868P", NULL)))
+		return NULL;
+
+	if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+		sr_dbg("Device context malloc failed.");
+		return NULL;
+	}
+
+	if (!(sdi->conn = sr_serial_dev_inst_new(conn, serialcomm)))
+		return NULL;
+
+	sdi->inst_type = SR_INST_SERIAL;
+	sdi->priv = devc;
+	sdi->driver = di;
+	if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
+		return NULL;
+	sdi->channels = g_slist_append(sdi->channels, ch);
+	drvc->instances = g_slist_append(drvc->instances, sdi);
+	devices = g_slist_append(devices, sdi);
+
+	return devices;
+}
+
+static GSList *dev_list(void)
+{
+	return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+	struct sr_serial_dev_inst *serial;
+
+	serial = sdi->conn;
+	if (serial_open(serial, SERIAL_RDWR) != SR_OK)
+		return SR_ERR;
+
+	sdi->status = SR_ST_ACTIVE;
+
+	return SR_OK;
+}
+
+static int cleanup(void)
+{
+	return std_dev_clear(di, NULL);
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+
+	(void)cg;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!(devc = sdi->priv)) {
+		sr_err("sdi->priv was NULL.");
+		return SR_ERR_BUG;
+	}
+
+	switch (id) {
+	case SR_CONF_LIMIT_MSEC:
+		/* TODO: not yet implemented */
+		if (g_variant_get_uint64(data) == 0) {
+			sr_err("LIMIT_MSEC can't be 0.");
+			return SR_ERR;
+		}
+		devc->limit_msec = g_variant_get_uint64(data);;
+		sr_dbg("Setting time limit to %" PRIu64 "ms.",
+		       devc->limit_msec);
+		break;
+	case SR_CONF_LIMIT_SAMPLES:
+		devc->limit_samples = g_variant_get_uint64(data);
+		sr_dbg("Setting sample limit to %" PRIu64 ".",
+		       devc->limit_samples);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	(void)sdi;
+	(void)cg;
+
+	switch (key) {
+	case SR_CONF_SCAN_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+		break;
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!(devc = sdi->priv)) {
+		sr_err("sdi->priv was NULL.");
+		return SR_ERR_BUG;
+	}
+
+	devc->cb_data = cb_data;
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	/* Poll every 150ms, or whenever some data comes in. */
+	serial = sdi->conn;
+	serial_source_add(serial, G_IO_IN, 150, colead_slm_receive_data,
+			(void *)sdi);
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close,
+			sdi->conn, LOG_PREFIX);
+}
+
+SR_PRIV struct sr_dev_driver colead_slm_driver_info = {
+	.name = "colead-slm",
+	.longname = "Colead SLM",
+	.api_version = 1,
+	.init = init,
+	.cleanup = cleanup,
+	.scan = scan,
+	.dev_list = dev_list,
+	.dev_clear = NULL,
+	.config_get = NULL,
+	.config_set = config_set,
+	.config_list = config_list,
+	.dev_open = dev_open,
+	.dev_close = std_serial_dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/colead-slm/protocol.c b/hardware/colead-slm/protocol.c
new file mode 100644
index 0000000..4abcdd5
--- /dev/null
+++ b/hardware/colead-slm/protocol.c
@@ -0,0 +1,233 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+#include <errno.h>
+#include <string.h>
+
+static void process_packet(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_analog analog;
+	GString *dbg;
+	float fvalue;
+	int checksum, mode, i;
+
+	devc = sdi->priv;
+	if (sr_log_loglevel_get() >= SR_LOG_SPEW) {
+		dbg = g_string_sized_new(128);
+		g_string_printf(dbg, "received packet:");
+		for (i = 0; i < 10; i++)
+			g_string_append_printf(dbg, " %.2x", (devc->buf)[i]);
+		sr_spew("%s", dbg->str);
+		g_string_free(dbg, TRUE);
+	}
+
+	if (devc->buf[0] != 0x08 || devc->buf[1] != 0x04) {
+		sr_dbg("invalid packet header.");
+		return;
+	}
+
+	if (devc->buf[8] != 0x01) {
+		sr_dbg("invalid measurement.");
+		return;
+	}
+
+	checksum = 0;
+	for (i = 0; i < 9; i++)
+		checksum += devc->buf[i];
+	if ((checksum & 0xff) != devc->buf[9]) {
+		sr_dbg("invalid packet checksum.");
+		return;
+	}
+
+	fvalue = 0.0;
+	for (i = 3; i < 8; i++) {
+		if (devc->buf[i] > 0x09)
+			continue;
+		fvalue *= 10;
+		fvalue += devc->buf[i];
+	}
+	fvalue /= 10;
+
+	memset(&analog, 0, sizeof(struct sr_datafeed_analog));
+	analog.mq = SR_MQ_SOUND_PRESSURE_LEVEL;
+	analog.unit = SR_UNIT_DECIBEL_SPL;
+	analog.channels = sdi->channels;
+	analog.num_samples = 1;
+	analog.data = &fvalue;
+
+	/* High nibble should only have 0x01 or 0x02. */
+	mode = (devc->buf[2] >> 4) & 0x0f;
+	if (mode == 0x02)
+		analog.mqflags |= SR_MQFLAG_HOLD;
+	else if (mode != 0x01) {
+		sr_dbg("unknown measurement mode 0x%.2x", mode);
+		return;
+	}
+
+	/* Low nibble has 14 combinations of direct/long-term average,
+	 * time scale of that average, frequency weighting, and time
+	 * weighting. */
+	mode = devc->buf[2] & 0x0f;
+	switch (mode) {
+		case 0x0:
+			analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_A \
+					| SR_MQFLAG_SPL_TIME_WEIGHT_F;
+			break;
+		case 0x1:
+			analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_A \
+					| SR_MQFLAG_SPL_TIME_WEIGHT_S;
+			break;
+		case 0x2:
+			analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_C \
+					| SR_MQFLAG_SPL_TIME_WEIGHT_F;
+			break;
+		case 0x3:
+			analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_C \
+					| SR_MQFLAG_SPL_TIME_WEIGHT_S;
+			break;
+		case 0x4:
+			analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_FLAT \
+					| SR_MQFLAG_SPL_TIME_WEIGHT_F;
+			break;
+		case 0x5:
+			analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_FLAT \
+					| SR_MQFLAG_SPL_TIME_WEIGHT_S;
+			break;
+		case 0x6:
+			analog.mqflags |= SR_MQFLAG_SPL_PCT_OVER_ALARM \
+					| SR_MQFLAG_SPL_FREQ_WEIGHT_A \
+					| SR_MQFLAG_SPL_TIME_WEIGHT_F;
+			break;
+		case 0x7:
+			analog.mqflags |= SR_MQFLAG_SPL_PCT_OVER_ALARM \
+					| SR_MQFLAG_SPL_FREQ_WEIGHT_A \
+					| SR_MQFLAG_SPL_TIME_WEIGHT_S;
+			break;
+		case 0x8:
+			/* 10-second mean, but we don't have MQ flags to express it. */
+			analog.mqflags |= SR_MQFLAG_SPL_LAT \
+					| SR_MQFLAG_SPL_FREQ_WEIGHT_A \
+					| SR_MQFLAG_SPL_TIME_WEIGHT_F;
+			break;
+		case 0x9:
+			/* Mean over a time period between 11 seconds and 24 hours.
+			 * Which is so silly that there's no point in expressing
+			 * either this or the previous case.  */
+			analog.mqflags |= SR_MQFLAG_SPL_LAT \
+					| SR_MQFLAG_SPL_FREQ_WEIGHT_A \
+					| SR_MQFLAG_SPL_TIME_WEIGHT_F;
+			break;
+		case 0xa:
+			/* 10-second mean. */
+			analog.mqflags |= SR_MQFLAG_SPL_LAT \
+					| SR_MQFLAG_SPL_FREQ_WEIGHT_A \
+					| SR_MQFLAG_SPL_TIME_WEIGHT_S;
+			break;
+		case 0xb:
+			/* Mean over a time period between 11 seconds and 24 hours. */
+			analog.mqflags |= SR_MQFLAG_SPL_LAT \
+					| SR_MQFLAG_SPL_FREQ_WEIGHT_A \
+					| SR_MQFLAG_SPL_TIME_WEIGHT_S;
+			break;
+		case 0xc:
+			/* Internal calibration on 1kHz sine at 94dB, not useful
+			 * to anything but the device. */
+			analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_FLAT;
+			break;
+		case 0xd:
+			/* Internal calibration on 1kHz sine at 94dB, not useful
+			 * to anything but the device. */
+			analog.mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_FLAT;
+			break;
+		default:
+			sr_dbg("unknown configuration 0x%.2x", mode);
+			return;
+			break;
+	}
+
+	packet.type = SR_DF_ANALOG;
+	packet.payload = &analog;
+	sr_session_send(devc->cb_data, &packet);
+
+	devc->num_samples++;
+
+}
+
+SR_PRIV int colead_slm_receive_data(int fd, int revents, void *cb_data)
+{
+	const struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+	int len;
+	char buf[128];
+
+	(void)fd;
+
+	if (!(sdi = cb_data))
+		return TRUE;
+
+	if (!(devc = sdi->priv))
+		return TRUE;
+
+	if (revents != G_IO_IN)
+		/* Timeout event. */
+		return TRUE;
+
+	serial = sdi->conn;
+	if (devc->state == IDLE) {
+		if (serial_read(serial, buf, 128) != 1 || buf[0] != 0x10)
+			/* Nothing there, or caught the tail end of a previous packet,
+			 * or some garbage. Unless it's a single "data ready" byte,
+			 * we don't want it. */
+			return TRUE;
+		/* Got 0x10, "measurement ready". */
+		if (serial_write(serial, "\x20", 1) == -1)
+			sr_err("unable to send command: %s", strerror(errno));
+		else {
+			devc->state = COMMAND_SENT;
+			devc->buflen = 0;
+		}
+	} else {
+		len = serial_read(serial, devc->buf + devc->buflen,
+				10 - devc->buflen);
+		if (len < 1)
+			return TRUE;
+		devc->buflen += len;
+		if (devc->buflen > 10) {
+			sr_dbg("buffer overrun");
+			devc->state = IDLE;
+			return TRUE;
+		}
+		if (devc->buflen == 10) {
+			/* If we got here, we're sure the device sent a "data ready"
+			 * notification, we asked for data, and got it. */
+			process_packet(sdi);
+			devc->state = IDLE;
+		}
+	}
+
+	return TRUE;
+}
diff --git a/hardware/colead-slm/protocol.h b/hardware/colead-slm/protocol.h
new file mode 100644
index 0000000..8942ac8
--- /dev/null
+++ b/hardware/colead-slm/protocol.h
@@ -0,0 +1,54 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_COLEAD_SLM_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_COLEAD_SLM_PROTOCOL_H
+
+#include <stdint.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "colead-slm"
+
+enum {
+	IDLE,
+	COMMAND_SENT,
+};
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+	/** The current sampling limit (in number of samples). */
+	uint64_t limit_samples;
+
+	/** The current sampling limit (in ms). */
+	uint64_t limit_msec;
+
+	/** Opaque pointer passed in by the frontend. */
+	void *cb_data;
+
+	/** The current number of already received samples. */
+	uint64_t num_samples;
+	int state;
+	char buf[10];
+	int buflen;
+};
+
+SR_PRIV int colead_slm_receive_data(int fd, int revents, void *cb_data);
+
+#endif
diff --git a/hardware/common/dmm/es519xx.c b/hardware/common/dmm/es519xx.c
new file mode 100644
index 0000000..075587c
--- /dev/null
+++ b/hardware/common/dmm/es519xx.c
@@ -0,0 +1,828 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Uwe Hermann <uwe at hermann-uwe.de>
+ * Copyright (C) 2013 Aurelien Jacobs <aurel at gnuage.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/*
+ * Cyrustek ES519XX protocol parser.
+ *
+ * Communication parameters: Unidirectional, 2400/7o1 or 19230/7o1
+ */
+
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "es519xx"
+
+/* Factors for the respective measurement mode (0 means "invalid"). */
+static const float factors_2400_11b[9][8] = {
+	{1e-4,  1e-3,  1e-2,  1e-1, 1,    0,    0,    0   }, /* V */
+	{1e-7,  1e-6,  0,     0,    0,    0,    0,    0   }, /* uA */
+	{1e-5,  1e-4,  0,     0,    0,    0,    0,    0   }, /* mA */
+	{1e-2,  0,     0,     0,    0,    0,    0,    0   }, /* A */
+	{1e1,   1e2,   1e3,   1e4,  1e5,  1e6,  0,    0   }, /* RPM */
+	{1e-1,  1,     1e1,   1e2,  1e3,  1e4,  0,    0   }, /* Resistance */
+	{1,     1e1,   1e2,   1e3,  1e4,  1e5,  0,    0   }, /* Frequency */
+	{1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5}, /* Capacitance */
+	{1e-3,  0,     0,     0,    0,    0,    0,    0   }, /* Diode */
+};
+static const float factors_19200_11b_5digits[9][8] = {
+	{1e-4,  1e-3,  1e-2,  1e-1, 1e-5, 0,    0,    0},    /* V */
+	{1e-8,  1e-7,  0,     0,    0,    0,    0,    0},    /* uA */
+	{1e-6,  1e-5,  0,     0,    0,    0,    0,    0},    /* mA */
+	{0,     1e-3,  0,     0,    0,    0,    0,    0},    /* A */
+	{1e-4,  1e-3,  1e-2,  1e-1, 1,    0,    0,    0},    /* Manual A */
+	{1e-2,  1e-1,  1,     1e1,  1e2,  1e3,  1e4,  0},    /* Resistance */
+	{1e-1,  0,     1,     1e1,  1e2,  1e3,  1e4,  0},    /* Frequency */
+	{1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5}, /* Capacitance */
+	{1e-4,  0,     0,     0,    0,    0,    0,    0   }, /* Diode */
+};
+static const float factors_19200_11b_clampmeter[9][8] = {
+	{1e-3,  1e-2,  1e-1,  1,    1e-4, 0,    0,    0},    /* V */
+	{1e-7,  1e-6,  0,     0,    0,    0,    0,    0},    /* uA */
+	{1e-5,  1e-4,  0,     0,    0,    0,    0,    0},    /* mA */
+	{1e-2,  0,     0,     0,    0,    0,    0,    0},    /* A */
+	{1e-3,  1e-2,  1e-1,  1,    0,    0,    0,    0},    /* Manual A */
+	{1e-1,  1,     1e1,   1e2,  1e3,  1e4,  0,    0},    /* Resistance */
+	{1e-1,  0,     1,     1e1,  1e2,  1e3,  1e4,  0},    /* Frequency */
+	{1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5}, /* Capacitance */
+	{1e-3,  0,     0,     0,    0,    0,    0,    0   }, /* Diode */
+};
+static const float factors_19200_11b[9][8] = {
+	{1e-3,  1e-2,  1e-1,  1,    1e-4, 0,    0,    0},    /* V */
+	{1e-7,  1e-6,  0,     0,    0,    0,    0,    0},    /* uA */
+	{1e-5,  1e-4,  0,     0,    0,    0,    0,    0},    /* mA */
+	{1e-3,  1e-2,  0,     0,    0,    0,    0,    0},    /* A */
+	{0,     0,     0,     0,    0,    0,    0,    0},    /* Manual A */
+	{1e-1,  1,     1e1,   1e2,  1e3,  1e4,  0,    0},    /* Resistance */
+	{1,     1e1,   1e2,   1e3,  1e4,  0,    0,    0},    /* Frequency */
+	{1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 0},    /* Capacitance */
+	{1e-3,  0,     0,     0,    0,    0,    0,    0},    /* Diode */
+};
+static const float factors_19200_14b[9][8] = {
+	{1e-4,  1e-3,  1e-2,  1e-1, 1e-5, 0,    0,    0},    /* V */
+	{1e-8,  1e-7,  0,     0,    0,    0,    0,    0},    /* uA */
+	{1e-6,  1e-5,  0,     0,    0,    0,    0,    0},    /* mA */
+	{1e-3,  0,     0,     0,    0,    0,    0,    0},    /* A */
+	{1e-4,  1e-3,  1e-2,  1e-1, 1,    0,    0,    0},    /* Manual A */
+	{1e-2,  1e-1,  1,     1e1,  1e2,  1e3,  1e4,  0},    /* Resistance */
+	{1e-2,  1e-1,  0,     1,    1e1,  1e2,  1e3,  1e4},  /* Frequency */
+	{1e-12, 1e-11, 1e-10, 1e-9, 1e-8, 1e-7, 1e-6, 1e-5}, /* Capacitance */
+	{1e-4,  0,     0,     0,    0,    0,    0,    0   }, /* Diode */
+};
+
+static int parse_value(const uint8_t *buf, struct es519xx_info *info,
+                       float *result)
+{
+	int i, intval, num_digits;
+	float floatval;
+
+	num_digits = 4 + ((info->packet_size == 14) ? 1 : 0);
+
+	/* Bytes 1-4 (or 5): Value (4 or 5 decimal digits) */
+	if (info->is_ol) {
+		sr_spew("Over limit.");
+		*result = INFINITY;
+		return SR_OK;
+	} else if (info->is_ul) {
+		sr_spew("Under limit.");
+		*result = INFINITY;
+		return SR_OK;
+	} else if (!isdigit(buf[1]) || !isdigit(buf[2]) ||
+	           !isdigit(buf[3]) || !isdigit(buf[4]) ||
+	           (num_digits == 5 && !isdigit(buf[5]))) {
+		sr_dbg("Value contained invalid digits: %02x %02x %02x %02x "
+		       "(%c %c %c %c).", buf[1], buf[2], buf[3], buf[4],
+		       buf[1], buf[2], buf[3], buf[4]);
+		return SR_ERR;
+	}
+	intval = (info->is_digit4) ? 1 : 0;
+	for (i = 0; i < num_digits; i++)
+		intval = 10 * intval + (buf[i + 1] - '0');
+
+	/* Apply sign. */
+	intval *= info->is_sign ? -1 : 1;
+
+	floatval = (float)intval;
+
+	/* Note: The decimal point position will be parsed later. */
+
+	sr_spew("The display value is %f.", floatval);
+
+	*result = floatval;
+
+	return SR_OK;
+}
+
+static int parse_range(uint8_t b, float *floatval,
+                       const struct es519xx_info *info)
+{
+	int idx, mode;
+	float factor = 0;
+
+	idx = b - '0';
+
+	if (idx < 0 || idx > 7) {
+		sr_dbg("Invalid range byte / index: 0x%02x / 0x%02x.", b, idx);
+		return SR_ERR;
+	}
+
+	/* Parse range byte (depends on the measurement mode). */
+	if (info->is_voltage)
+		mode = 0; /* V */
+	else if (info->is_current && info->is_micro)
+		mode = 1; /* uA */
+	else if (info->is_current && info->is_milli)
+		mode = 2; /* mA */
+	else if (info->is_current && info->is_auto)
+		mode = 3; /* A */
+	else if (info->is_current && !info->is_auto)
+		mode = 4; /* Manual A */
+	else if (info->is_rpm)
+		/* Not a typo, it's really index 4 in factors_2400_11b[][]. */
+		mode = 4; /* RPM */
+	else if (info->is_resistance || info->is_continuity)
+		mode = 5; /* Resistance */
+	else if (info->is_frequency)
+		mode = 6; /* Frequency */
+	else if (info->is_capacitance)
+		mode = 7; /* Capacitance */
+	else if (info->is_diode)
+		mode = 8; /* Diode */
+	else if (info->is_duty_cycle)
+		mode = 0; /* Dummy, unused */
+	else {
+		sr_dbg("Invalid mode, range byte was: 0x%02x.", b);
+		return SR_ERR;
+	}
+
+	if (info->is_vbar) {
+		if (info->is_micro)
+			factor = (const float[]){1e-1, 1}[idx];
+		else if (info->is_milli)
+			factor = (const float[]){1e-2, 1e-1}[idx];
+	}
+	else if (info->is_duty_cycle)
+		factor = 1e-1;
+	else if (info->baudrate == 2400)
+		factor = factors_2400_11b[mode][idx];
+	else if (info->fivedigits)
+		factor = factors_19200_11b_5digits[mode][idx];
+	else if (info->clampmeter)
+		factor = factors_19200_11b_clampmeter[mode][idx];
+	else if (info->packet_size == 11)
+		factor = factors_19200_11b[mode][idx];
+	else if (info->packet_size == 14)
+		factor = factors_19200_14b[mode][idx];
+
+	if (factor == 0) {
+		sr_dbg("Invalid factor for range byte: 0x%02x.", b);
+		return SR_ERR;
+	}
+
+	/* Apply respective factor (mode-dependent) on the value. */
+	*floatval *= factor;
+	sr_dbg("Applying factor %f, new value is %f.", factor, *floatval);
+
+	return SR_OK;
+}
+
+static void parse_flags(const uint8_t *buf, struct es519xx_info *info)
+{
+	int function, status;
+
+	function = 5 + ((info->packet_size == 14) ? 1 : 0);
+	status = function + 1;
+
+	/* Status byte */
+	if (info->alt_functions) {
+		info->is_sign  = (buf[status] & (1 << 3)) != 0;
+		info->is_batt  = (buf[status] & (1 << 2)) != 0; /* Bat. low */
+		info->is_ol    = (buf[status] & (1 << 1)) != 0; /* Overflow */
+		info->is_ol   |= (buf[status] & (1 << 0)) != 0; /* Overflow */
+	} else {
+		info->is_judge = (buf[status] & (1 << 3)) != 0;
+		info->is_sign  = (buf[status] & (1 << 2)) != 0;
+		info->is_batt  = (buf[status] & (1 << 1)) != 0; /* Bat. low */
+		info->is_ol    = (buf[status] & (1 << 0)) != 0; /* Overflow */
+	}
+
+	if (info->packet_size == 14) {
+		/* Option 1 byte */
+		info->is_max  = (buf[8] & (1 << 3)) != 0;
+		info->is_min  = (buf[8] & (1 << 2)) != 0;
+		info->is_rel  = (buf[8] & (1 << 1)) != 0;
+		info->is_rmr  = (buf[8] & (1 << 0)) != 0;
+
+		/* Option 2 byte */
+		info->is_ul   = (buf[9] & (1 << 3)) != 0; /* Underflow */
+		info->is_pmax = (buf[9] & (1 << 2)) != 0; /* Max. peak value */
+		info->is_pmin = (buf[9] & (1 << 1)) != 0; /* Min. peak value */
+
+		/* Option 3 byte */
+		info->is_dc   = (buf[10] & (1 << 3)) != 0;
+		info->is_ac   = (buf[10] & (1 << 2)) != 0;
+		info->is_auto = (buf[10] & (1 << 1)) != 0;
+		info->is_vahz = (buf[10] & (1 << 0)) != 0;
+
+		/* LPF: Low-pass filter(s) */
+		if (info->selectable_lpf) {
+			/* Option 4 byte */
+			info->is_hold = (buf[11] & (1 << 3)) != 0;
+			info->is_vbar = (buf[11] & (1 << 2)) != 0;
+			info->is_lpf1 = (buf[11] & (1 << 1)) != 0;
+			info->is_lpf0 = (buf[11] & (1 << 0)) != 0;
+		} else {
+			/* Option 4 byte */
+			info->is_vbar = (buf[11] & (1 << 2)) != 0;
+			info->is_hold = (buf[11] & (1 << 1)) != 0;
+			info->is_lpf1 = (buf[11] & (1 << 0)) != 0;
+		}
+	} else if (info->alt_functions) {
+		/* Option 2 byte */
+		info->is_dc   = (buf[8] & (1 << 3)) != 0;
+		info->is_auto = (buf[8] & (1 << 2)) != 0;
+		info->is_apo  = (buf[8] & (1 << 0)) != 0;
+		info->is_ac   = !info->is_dc;
+	} else {
+		/* Option 1 byte */
+		if (info->baudrate == 2400) {
+			info->is_pmax   = (buf[7] & (1 << 3)) != 0;
+			info->is_pmin   = (buf[7] & (1 << 2)) != 0;
+			info->is_vahz   = (buf[7] & (1 << 0)) != 0;
+		} else if (info->fivedigits) {
+			info->is_ul     = (buf[7] & (1 << 3)) != 0;
+			info->is_pmax   = (buf[7] & (1 << 2)) != 0;
+			info->is_pmin   = (buf[7] & (1 << 1)) != 0;
+			info->is_digit4 = (buf[7] & (1 << 0)) != 0;
+		} else if (info->clampmeter) {
+			info->is_ul     = (buf[7] & (1 << 3)) != 0;
+			info->is_vasel  = (buf[7] & (1 << 2)) != 0;
+			info->is_vbar   = (buf[7] & (1 << 1)) != 0;
+		} else {
+			info->is_hold   = (buf[7] & (1 << 3)) != 0;
+			info->is_max    = (buf[7] & (1 << 2)) != 0;
+			info->is_min    = (buf[7] & (1 << 1)) != 0;
+		}
+
+		/* Option 2 byte */
+		info->is_dc   = (buf[8] & (1 << 3)) != 0;
+		info->is_ac   = (buf[8] & (1 << 2)) != 0;
+		info->is_auto = (buf[8] & (1 << 1)) != 0;
+		if (info->baudrate == 2400)
+			info->is_apo  = (buf[8] & (1 << 0)) != 0;
+		else
+			info->is_vahz = (buf[8] & (1 << 0)) != 0;
+	}
+
+	/* Function byte */
+	if (info->alt_functions) {
+		switch (buf[function]) {
+		case 0x3f: /* A */
+			info->is_current = info->is_auto = TRUE;
+			break;
+		case 0x3e: /* uA */
+			info->is_current = info->is_micro = info->is_auto = TRUE;
+			break;
+		case 0x3d: /* mA */
+			info->is_current = info->is_milli = info->is_auto = TRUE;
+			break;
+		case 0x3c: /* V */
+			info->is_voltage = TRUE;
+			break;
+		case 0x37: /* Resistance */
+			info->is_resistance = TRUE;
+			break;
+		case 0x36: /* Continuity */
+			info->is_continuity = TRUE;
+			break;
+		case 0x3b: /* Diode */
+			info->is_diode = TRUE;
+			break;
+		case 0x3a: /* Frequency */
+			info->is_frequency = TRUE;
+			break;
+		case 0x34: /* ADP0 */
+		case 0x35: /* ADP0 */
+			info->is_adp0 = TRUE;
+			break;
+		case 0x38: /* ADP1 */
+		case 0x39: /* ADP1 */
+			info->is_adp1 = TRUE;
+			break;
+		case 0x32: /* ADP2 */
+		case 0x33: /* ADP2 */
+			info->is_adp2 = TRUE;
+			break;
+		case 0x30: /* ADP3 */
+		case 0x31: /* ADP3 */
+			info->is_adp3 = TRUE;
+			break;
+		default:
+			sr_dbg("Invalid function byte: 0x%02x.", buf[function]);
+			break;
+		}
+	} else {
+		/* Note: Some of these mappings are fixed up later. */
+		switch (buf[function]) {
+		case 0x3b: /* V */
+			info->is_voltage = TRUE;
+			break;
+		case 0x3d: /* uA */
+			info->is_current = info->is_micro = info->is_auto = TRUE;
+			break;
+		case 0x3f: /* mA */
+			info->is_current = info->is_milli = info->is_auto = TRUE;
+			break;
+		case 0x30: /* A */
+			info->is_current = info->is_auto = TRUE;
+			break;
+		case 0x39: /* Manual A */
+			info->is_current = TRUE;
+			info->is_auto = FALSE; /* Manual mode */
+			break;
+		case 0x33: /* Resistance */
+			info->is_resistance = TRUE;
+			break;
+		case 0x35: /* Continuity */
+			info->is_continuity = TRUE;
+			break;
+		case 0x31: /* Diode */
+			info->is_diode = TRUE;
+			break;
+		case 0x32: /* Frequency / RPM / duty cycle */
+			if (info->packet_size == 14) {
+				if (info->is_judge)
+					info->is_duty_cycle = TRUE;
+				else
+					info->is_frequency = TRUE;
+			} else {
+				if (info->is_judge)
+					info->is_rpm = TRUE;
+				else
+					info->is_frequency = TRUE;
+			}
+			break;
+		case 0x36: /* Capacitance */
+			info->is_capacitance = TRUE;
+			break;
+		case 0x34: /* Temperature */
+			info->is_temperature = TRUE;
+			if (info->is_judge)
+				info->is_celsius = TRUE;
+			else
+				info->is_fahrenheit = TRUE;
+			/* IMPORTANT: The digits always represent Celsius! */
+			break;
+		case 0x3e: /* ADP0 */
+			info->is_adp0 = TRUE;
+			break;
+		case 0x3c: /* ADP1 */
+			info->is_adp1 = TRUE;
+			break;
+		case 0x38: /* ADP2 */
+			info->is_adp2 = TRUE;
+			break;
+		case 0x3a: /* ADP3 */
+			info->is_adp3 = TRUE;
+			break;
+		default:
+			sr_dbg("Invalid function byte: 0x%02x.", buf[function]);
+			break;
+		}
+	}
+
+	if (info->is_vahz && (info->is_voltage || info->is_current)) {
+		info->is_voltage = FALSE;
+		info->is_current = FALSE;
+		info->is_milli = info->is_micro = FALSE;
+		if (info->packet_size == 14) {
+			if (info->is_judge)
+				info->is_duty_cycle = TRUE;
+			else
+				info->is_frequency = TRUE;
+		} else {
+			if (info->is_judge)
+				info->is_rpm = TRUE;
+			else
+				info->is_frequency = TRUE;
+		}
+	}
+
+	if (info->is_current && (info->is_micro || info->is_milli) && info->is_vasel) {
+		info->is_current = info->is_auto = FALSE;
+		info->is_voltage = TRUE;
+	}
+
+	if (info->baudrate == 2400) {
+		/* Inverted mapping between mA and A, and no manual A. */
+		if (info->is_current && (info->is_milli || !info->is_auto)) {
+			info->is_milli = !info->is_milli;
+			info->is_auto = TRUE;
+		}
+	}
+}
+
+static void handle_flags(struct sr_datafeed_analog *analog,
+			 float *floatval, const struct es519xx_info *info)
+{
+	/*
+	 * Note: is_micro etc. are not used directly to multiply/divide
+	 * floatval, this is handled via parse_range() and factors[][].
+	 */
+
+	/* Measurement modes */
+	if (info->is_voltage) {
+		analog->mq = SR_MQ_VOLTAGE;
+		analog->unit = SR_UNIT_VOLT;
+	}
+	if (info->is_current) {
+		analog->mq = SR_MQ_CURRENT;
+		analog->unit = SR_UNIT_AMPERE;
+	}
+	if (info->is_resistance) {
+		analog->mq = SR_MQ_RESISTANCE;
+		analog->unit = SR_UNIT_OHM;
+	}
+	if (info->is_frequency) {
+		analog->mq = SR_MQ_FREQUENCY;
+		analog->unit = SR_UNIT_HERTZ;
+	}
+	if (info->is_capacitance) {
+		analog->mq = SR_MQ_CAPACITANCE;
+		analog->unit = SR_UNIT_FARAD;
+	}
+	if (info->is_temperature && info->is_celsius) {
+		analog->mq = SR_MQ_TEMPERATURE;
+		analog->unit = SR_UNIT_CELSIUS;
+	}
+	if (info->is_temperature && info->is_fahrenheit) {
+		analog->mq = SR_MQ_TEMPERATURE;
+		analog->unit = SR_UNIT_FAHRENHEIT;
+	}
+	if (info->is_continuity) {
+		analog->mq = SR_MQ_CONTINUITY;
+		analog->unit = SR_UNIT_BOOLEAN;
+		*floatval = (*floatval < 0.0 || *floatval > 25.0) ? 0.0 : 1.0;
+	}
+	if (info->is_diode) {
+		analog->mq = SR_MQ_VOLTAGE;
+		analog->unit = SR_UNIT_VOLT;
+	}
+	if (info->is_rpm) {
+		analog->mq = SR_MQ_FREQUENCY;
+		analog->unit = SR_UNIT_REVOLUTIONS_PER_MINUTE;
+	}
+	if (info->is_duty_cycle) {
+		analog->mq = SR_MQ_DUTY_CYCLE;
+		analog->unit = SR_UNIT_PERCENTAGE;
+	}
+
+	/* Measurement related flags */
+	if (info->is_ac)
+		analog->mqflags |= SR_MQFLAG_AC;
+	if (info->is_dc)
+		analog->mqflags |= SR_MQFLAG_DC;
+	if (info->is_auto)
+		analog->mqflags |= SR_MQFLAG_AUTORANGE;
+	if (info->is_diode)
+		analog->mqflags |= SR_MQFLAG_DIODE;
+	if (info->is_hold)
+		/*
+		* Note: HOLD only affects the number displayed on the LCD,
+		* but not the value sent via the protocol! It also does not
+		* affect the bargraph on the LCD.
+		*/
+		analog->mqflags |= SR_MQFLAG_HOLD;
+	if (info->is_max)
+		analog->mqflags |= SR_MQFLAG_MAX;
+	if (info->is_min)
+		analog->mqflags |= SR_MQFLAG_MIN;
+	if (info->is_rel)
+		analog->mqflags |= SR_MQFLAG_RELATIVE;
+
+	/* Other flags */
+	if (info->is_judge)
+		sr_spew("Judge bit is set.");
+	if (info->is_batt)
+		sr_spew("Battery is low.");
+	if (info->is_ol)
+		sr_spew("Input overflow.");
+	if (info->is_ul)
+		sr_spew("Input underflow.");
+	if (info->is_pmax)
+		sr_spew("pMAX active, LCD shows max. peak value.");
+	if (info->is_pmin)
+		sr_spew("pMIN active, LCD shows min. peak value.");
+	if (info->is_vahz)
+		sr_spew("VAHZ active.");
+	if (info->is_apo)
+		sr_spew("Auto-Power-Off enabled.");
+	if (info->is_vbar)
+		sr_spew("VBAR active.");
+	if ((!info->selectable_lpf && info->is_lpf1) ||
+	    (info->selectable_lpf && (!info->is_lpf0 || !info->is_lpf1)))
+		sr_spew("Low-pass filter feature is active.");
+}
+
+static gboolean flags_valid(const struct es519xx_info *info)
+{
+	int count;
+
+	/* Does the packet have more than one multiplier? */
+	count  = (info->is_micro) ? 1 : 0;
+	count += (info->is_milli) ? 1 : 0;
+	if (count > 1) {
+		sr_dbg("More than one multiplier detected in packet.");
+		return FALSE;
+	}
+
+	/* Does the packet "measure" more than one type of value? */
+	count  = (info->is_voltage) ? 1 : 0;
+	count += (info->is_current) ? 1 : 0;
+	count += (info->is_resistance) ? 1 : 0;
+	count += (info->is_frequency) ? 1 : 0;
+	count += (info->is_capacitance) ? 1 : 0;
+	count += (info->is_temperature) ? 1 : 0;
+	count += (info->is_continuity) ? 1 : 0;
+	count += (info->is_diode) ? 1 : 0;
+	count += (info->is_rpm) ? 1 : 0;
+	if (count > 1) {
+		sr_dbg("More than one measurement type detected in packet.");
+		return FALSE;
+	}
+
+	/* Both AC and DC set? */
+	if (info->is_ac && info->is_dc) {
+		sr_dbg("Both AC and DC flags detected in packet.");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static gboolean sr_es519xx_packet_valid(const uint8_t *buf,
+                                        struct es519xx_info *info)
+{
+	int s;
+
+	s = info->packet_size;
+
+	if (s == 11 && memcmp(buf, buf + s, s))
+		return FALSE;
+
+	if (buf[s - 2] != '\r' || buf[s - 1] != '\n')
+		return FALSE;
+
+	parse_flags(buf, info);
+
+	if (!flags_valid(info))
+		return FALSE;
+
+	return TRUE;
+}
+
+static int sr_es519xx_parse(const uint8_t *buf, float *floatval,
+                            struct sr_datafeed_analog *analog,
+                            struct es519xx_info *info)
+{
+	int ret;
+
+	if (!sr_es519xx_packet_valid(buf, info))
+		return SR_ERR;
+
+	if ((ret = parse_value(buf, info, floatval)) != SR_OK) {
+		sr_dbg("Error parsing value: %d.", ret);
+		return ret;
+	}
+
+	if ((ret = parse_range(buf[0], floatval, info)) != SR_OK)
+		return ret;
+
+	handle_flags(analog, floatval, info);
+	return SR_OK;
+}
+
+/*
+ * Functions for 2400 baud / 11 bytes protocols.
+ * This includes ES51962, ES51971, ES51972, ES51978 and ES51989.
+ */
+SR_PRIV gboolean sr_es519xx_2400_11b_packet_valid(const uint8_t *buf)
+{
+	struct es519xx_info info;
+
+	memset(&info, 0, sizeof(struct es519xx_info));
+	info.baudrate = 2400;
+	info.packet_size = 11;
+
+	return sr_es519xx_packet_valid(buf, &info);
+}
+
+SR_PRIV int sr_es519xx_2400_11b_parse(const uint8_t *buf, float *floatval,
+				struct sr_datafeed_analog *analog, void *info)
+{
+	struct es519xx_info *info_local;
+
+	info_local = info;
+	memset(info_local, 0, sizeof(struct es519xx_info));
+	info_local->baudrate = 2400;
+	info_local->packet_size = 11;
+
+	return sr_es519xx_parse(buf, floatval, analog, info);
+}
+
+/*
+ * Functions for 2400 baud / 11 byte protocols.
+ * This includes ES51960, ES51977 and ES51988.
+ */
+SR_PRIV gboolean sr_es519xx_2400_11b_altfn_packet_valid(const uint8_t *buf)
+{
+	struct es519xx_info info;
+
+	memset(&info, 0, sizeof(struct es519xx_info));
+	info.baudrate = 2400;
+	info.packet_size = 11;
+	info.alt_functions = TRUE;
+
+	return sr_es519xx_packet_valid(buf, &info);
+}
+
+SR_PRIV int sr_es519xx_2400_11b_altfn_parse(const uint8_t *buf,
+		float *floatval, struct sr_datafeed_analog *analog, void *info)
+{
+	struct es519xx_info *info_local;
+
+	info_local = info;
+	memset(info_local, 0, sizeof(struct es519xx_info));
+	info_local->baudrate = 2400;
+	info_local->packet_size = 11;
+	info_local->alt_functions = TRUE;
+
+	return sr_es519xx_parse(buf, floatval, analog, info);
+}
+
+/*
+ * Functions for 19200 baud / 11 bytes protocols with 5 digits display.
+ * This includes ES51911, ES51916 and ES51918.
+ */
+SR_PRIV gboolean sr_es519xx_19200_11b_5digits_packet_valid(const uint8_t *buf)
+{
+	struct es519xx_info info;
+
+	memset(&info, 0, sizeof(struct es519xx_info));
+	info.baudrate = 19200;
+	info.packet_size = 11;
+	info.fivedigits = TRUE;
+
+	return sr_es519xx_packet_valid(buf, &info);
+}
+
+SR_PRIV int sr_es519xx_19200_11b_5digits_parse(const uint8_t *buf,
+		float *floatval, struct sr_datafeed_analog *analog, void *info)
+{
+	struct es519xx_info *info_local;
+
+	info_local = info;
+	memset(info_local, 0, sizeof(struct es519xx_info));
+	info_local->baudrate = 19200;
+	info_local->packet_size = 11;
+	info_local->fivedigits = TRUE;
+
+	return sr_es519xx_parse(buf, floatval, analog, info);
+}
+
+/*
+ * Functions for 19200 baud / 11 bytes protocols with clamp meter support.
+ * This includes ES51967 and ES51969.
+ */
+SR_PRIV gboolean sr_es519xx_19200_11b_clamp_packet_valid(const uint8_t *buf)
+{
+	struct es519xx_info info;
+
+	memset(&info, 0, sizeof(struct es519xx_info));
+	info.baudrate = 19200;
+	info.packet_size = 11;
+	info.clampmeter = TRUE;
+
+	return sr_es519xx_packet_valid(buf, &info);
+}
+
+SR_PRIV int sr_es519xx_19200_11b_clamp_parse(const uint8_t *buf,
+		float *floatval, struct sr_datafeed_analog *analog, void *info)
+{
+	struct es519xx_info *info_local;
+
+	info_local = info;
+	memset(info_local, 0, sizeof(struct es519xx_info));
+	info_local->baudrate = 19200;
+	info_local->packet_size = 11;
+	info_local->clampmeter = TRUE;
+
+	return sr_es519xx_parse(buf, floatval, analog, info);
+}
+
+/*
+ * Functions for 19200 baud / 11 bytes protocols.
+ * This includes ES51981, ES51982, ES51983, ES51984 and ES51986.
+ */
+SR_PRIV gboolean sr_es519xx_19200_11b_packet_valid(const uint8_t *buf)
+{
+	struct es519xx_info info;
+
+	memset(&info, 0, sizeof(struct es519xx_info));
+	info.baudrate = 19200;
+	info.packet_size = 11;
+
+	return sr_es519xx_packet_valid(buf, &info);
+}
+
+SR_PRIV int sr_es519xx_19200_11b_parse(const uint8_t *buf, float *floatval,
+			struct sr_datafeed_analog *analog, void *info)
+{
+	struct es519xx_info *info_local;
+
+	info_local = info;
+	memset(info_local, 0, sizeof(struct es519xx_info));
+	info_local->baudrate = 19200;
+	info_local->packet_size = 11;
+
+	return sr_es519xx_parse(buf, floatval, analog, info);
+}
+
+/*
+ * Functions for 19200 baud / 14 bytes protocols.
+ * This includes ES51921 and ES51922.
+ */
+SR_PRIV gboolean sr_es519xx_19200_14b_packet_valid(const uint8_t *buf)
+{
+	struct es519xx_info info;
+
+	memset(&info, 0, sizeof(struct es519xx_info));
+	info.baudrate = 19200;
+	info.packet_size = 14;
+
+	return sr_es519xx_packet_valid(buf, &info);
+}
+
+SR_PRIV int sr_es519xx_19200_14b_parse(const uint8_t *buf, float *floatval,
+			struct sr_datafeed_analog *analog, void *info)
+{
+	struct es519xx_info *info_local;
+
+	info_local = info;
+	memset(info_local, 0, sizeof(struct es519xx_info));
+	info_local->baudrate = 19200;
+	info_local->packet_size = 14;
+
+	return sr_es519xx_parse(buf, floatval, analog, info);
+}
+
+/*
+ * Functions for 19200 baud / 14 bytes protocols with selectable LPF.
+ * This includes ES51931 and ES51932.
+ */
+SR_PRIV gboolean sr_es519xx_19200_14b_sel_lpf_packet_valid(const uint8_t *buf)
+{
+	struct es519xx_info info;
+
+	memset(&info, 0, sizeof(struct es519xx_info));
+	info.baudrate = 19200;
+	info.packet_size = 14;
+	info.selectable_lpf = TRUE;
+
+	return sr_es519xx_packet_valid(buf, &info);
+}
+
+SR_PRIV int sr_es519xx_19200_14b_sel_lpf_parse(const uint8_t *buf,
+		float *floatval, struct sr_datafeed_analog *analog, void *info)
+{
+	struct es519xx_info *info_local;
+
+	info_local = info;
+	memset(info_local, 0, sizeof(struct es519xx_info));
+	info_local->baudrate = 19200;
+	info_local->packet_size = 14;
+	info_local->selectable_lpf = TRUE;
+
+	return sr_es519xx_parse(buf, floatval, analog, info);
+}
diff --git a/hardware/common/dmm/fs9721.c b/hardware/common/dmm/fs9721.c
new file mode 100644
index 0000000..f3101f8
--- /dev/null
+++ b/hardware/common/dmm/fs9721.c
@@ -0,0 +1,445 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Uwe Hermann <uwe at hermann-uwe.de>
+ * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/*
+ * Fortune Semiconductor FS9721_LP3/FS9721B protocol parser.
+ *
+ * FS9721_LP3: 4000 counts (3 3/4 digits)
+ * FS9721B/Q100: 2400 counts (3 2/3 digits)
+ *
+ * Same for both chips:
+ *  - Packages: Bare die (78 pins) or QFP-100
+ *  - Communication parameters: Unidirectional, 2400/8n1
+ *  - The protocol seems to be exactly the same.
+ */
+
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "fs9721"
+
+static int parse_digit(uint8_t b)
+{
+	switch (b) {
+	case 0x7d:
+		return 0;
+	case 0x05:
+		return 1;
+	case 0x5b:
+		return 2;
+	case 0x1f:
+		return 3;
+	case 0x27:
+		return 4;
+	case 0x3e:
+		return 5;
+	case 0x7e:
+		return 6;
+	case 0x15:
+		return 7;
+	case 0x7f:
+		return 8;
+	case 0x3f:
+		return 9;
+	default:
+		sr_dbg("Invalid digit byte: 0x%02x.", b);
+		return -1;
+	}
+}
+
+static gboolean sync_nibbles_valid(const uint8_t *buf)
+{
+	int i;
+
+	/* Check the synchronization nibbles, and make sure they all match. */
+	for (i = 0; i < FS9721_PACKET_SIZE; i++) {
+		if (((buf[i] >> 4) & 0x0f) != (i + 1)) {
+			sr_dbg("Sync nibble in byte %d (0x%02x) is invalid.",
+			       i, buf[i]);
+			return FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
+static gboolean flags_valid(const struct fs9721_info *info)
+{
+	int count;
+
+	/* Does the packet have more than one multiplier? */
+	count = 0;
+	count += (info->is_nano) ? 1 : 0;
+	count += (info->is_micro) ? 1 : 0;
+	count += (info->is_milli) ? 1 : 0;
+	count += (info->is_kilo) ? 1 : 0;
+	count += (info->is_mega) ? 1 : 0;
+	if (count > 1) {
+		sr_dbg("More than one multiplier detected in packet.");
+		return FALSE;
+	}
+
+	/* Does the packet "measure" more than one type of value? */
+	count = 0;
+	count += (info->is_hz) ? 1 : 0;
+	count += (info->is_ohm) ? 1 : 0;
+	count += (info->is_farad) ? 1 : 0;
+	count += (info->is_ampere) ? 1 : 0;
+	count += (info->is_volt) ? 1 : 0;
+	count += (info->is_percent) ? 1 : 0;
+	if (count > 1) {
+		sr_dbg("More than one measurement type detected in packet.");
+		return FALSE;
+	}
+
+	/* Both AC and DC set? */
+	if (info->is_ac && info->is_dc) {
+		sr_dbg("Both AC and DC flags detected in packet.");
+		return FALSE;
+	}
+
+	/* RS232 flag not set? */
+	if (!info->is_rs232) {
+		sr_dbg("No RS232 flag detected in packet.");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static int parse_value(const uint8_t *buf, float *result)
+{
+	int i, sign, intval = 0, digits[4];
+	uint8_t digit_bytes[4];
+	float floatval;
+
+	/* Byte 1: LCD SEG2 */
+	sign = ((buf[1] & (1 << 3)) != 0) ? -1 : 1;
+
+	/*
+	 * Bytes 1-8: Value (4 decimal digits, sign, decimal point)
+	 *
+	 * Over limit: "0L" (LCD), 0x00 0x7d 0x68 0x00 (digit bytes).
+	 */
+
+	/* Merge the two nibbles for a digit into one byte. */
+	for (i = 0; i < 4; i++) {
+		digit_bytes[i] = ((buf[1 + (i * 2)] & 0x0f) << 4);
+		digit_bytes[i] |= (buf[1 + (i * 2) + 1] & 0x0f);
+
+		/* Bit 7 in the byte is not part of the digit. */
+		digit_bytes[i] &= ~(1 << 7);
+	}
+
+	/* Check for "OL". */
+	if (digit_bytes[0] == 0x00 && digit_bytes[1] == 0x7d &&
+	    digit_bytes[2] == 0x68 && digit_bytes[3] == 0x00) {
+		sr_spew("Over limit.");
+		*result = INFINITY;
+		return SR_OK;
+	}
+
+	/* Parse the digits. */
+	for (i = 0; i < 4; i++)
+		digits[i] = parse_digit(digit_bytes[i]);
+	sr_spew("Digits: %02x %02x %02x %02x (%d%d%d%d).",
+		digit_bytes[0], digit_bytes[1], digit_bytes[2], digit_bytes[3],
+		digits[0], digits[1], digits[2], digits[3]);
+
+	/* Merge all digits into an integer value. */
+	for (i = 0; i < 4; i++) {
+		intval *= 10;
+		intval += digits[i];
+	}
+
+	floatval = (float)intval;
+
+	/* Decimal point position. */
+	if ((buf[3] & (1 << 3)) != 0) {
+		floatval /= 1000;
+		sr_spew("Decimal point after first digit.");
+	} else if ((buf[5] & (1 << 3)) != 0) {
+		floatval /= 100;
+		sr_spew("Decimal point after second digit.");
+	} else if ((buf[7] & (1 << 3)) != 0) {
+		floatval /= 10;
+		sr_spew("Decimal point after third digit.");
+	} else {
+		sr_spew("No decimal point in the number.");
+	}
+
+	/* Apply sign. */
+	floatval *= sign;
+
+	sr_spew("The display value is %f.", floatval);
+
+	*result = floatval;
+
+	return SR_OK;
+}
+
+static void parse_flags(const uint8_t *buf, struct fs9721_info *info)
+{
+	/* Byte 0: LCD SEG1 */
+	info->is_ac         = (buf[0] & (1 << 3)) != 0;
+	info->is_dc         = (buf[0] & (1 << 2)) != 0;
+	info->is_auto       = (buf[0] & (1 << 1)) != 0;
+	info->is_rs232      = (buf[0] & (1 << 0)) != 0;
+
+	/* Byte 1: LCD SEG2 */
+	info->is_sign       = (buf[1] & (1 << 3)) != 0;
+
+	/* Byte 9: LCD SEG10 */
+	info->is_micro      = (buf[9] & (1 << 3)) != 0;
+	info->is_nano       = (buf[9] & (1 << 2)) != 0;
+	info->is_kilo       = (buf[9] & (1 << 1)) != 0;
+	info->is_diode      = (buf[9] & (1 << 0)) != 0;
+
+	/* Byte 10: LCD SEG11 */
+	info->is_milli      = (buf[10] & (1 << 3)) != 0;
+	info->is_percent    = (buf[10] & (1 << 2)) != 0;
+	info->is_mega       = (buf[10] & (1 << 1)) != 0;
+	info->is_beep       = (buf[10] & (1 << 0)) != 0;
+
+	/* Byte 11: LCD SEG12 */
+	info->is_farad      = (buf[11] & (1 << 3)) != 0;
+	info->is_ohm        = (buf[11] & (1 << 2)) != 0;
+	info->is_rel        = (buf[11] & (1 << 1)) != 0;
+	info->is_hold       = (buf[11] & (1 << 0)) != 0;
+
+	/* Byte 12: LCD SEG13 */
+	info->is_ampere     = (buf[12] & (1 << 3)) != 0;
+	info->is_volt       = (buf[12] & (1 << 2)) != 0;
+	info->is_hz         = (buf[12] & (1 << 1)) != 0;
+	info->is_bat        = (buf[12] & (1 << 0)) != 0;
+
+	/* Byte 13: LCD SEG14 */
+	info->is_c2c1_11    = (buf[13] & (1 << 3)) != 0;
+	info->is_c2c1_10    = (buf[13] & (1 << 2)) != 0;
+	info->is_c2c1_01    = (buf[13] & (1 << 1)) != 0;
+	info->is_c2c1_00    = (buf[13] & (1 << 0)) != 0;
+}
+
+static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
+			 const struct fs9721_info *info)
+{
+	/* Factors */
+	if (info->is_nano)
+		*floatval /= 1000000000;
+	if (info->is_micro)
+		*floatval /= 1000000;
+	if (info->is_milli)
+		*floatval /= 1000;
+	if (info->is_kilo)
+		*floatval *= 1000;
+	if (info->is_mega)
+		*floatval *= 1000000;
+
+	/* Measurement modes */
+	if (info->is_volt) {
+		analog->mq = SR_MQ_VOLTAGE;
+		analog->unit = SR_UNIT_VOLT;
+	}
+	if (info->is_ampere) {
+		analog->mq = SR_MQ_CURRENT;
+		analog->unit = SR_UNIT_AMPERE;
+	}
+	if (info->is_ohm) {
+		analog->mq = SR_MQ_RESISTANCE;
+		analog->unit = SR_UNIT_OHM;
+	}
+	if (info->is_hz) {
+		analog->mq = SR_MQ_FREQUENCY;
+		analog->unit = SR_UNIT_HERTZ;
+	}
+	if (info->is_farad) {
+		analog->mq = SR_MQ_CAPACITANCE;
+		analog->unit = SR_UNIT_FARAD;
+	}
+	if (info->is_beep) {
+		analog->mq = SR_MQ_CONTINUITY;
+		analog->unit = SR_UNIT_BOOLEAN;
+		*floatval = (*floatval == INFINITY) ? 0.0 : 1.0;
+	}
+	if (info->is_diode) {
+		analog->mq = SR_MQ_VOLTAGE;
+		analog->unit = SR_UNIT_VOLT;
+	}
+	if (info->is_percent) {
+		analog->mq = SR_MQ_DUTY_CYCLE;
+		analog->unit = SR_UNIT_PERCENTAGE;
+	}
+
+	/* Measurement related flags */
+	if (info->is_ac)
+		analog->mqflags |= SR_MQFLAG_AC;
+	if (info->is_dc)
+		analog->mqflags |= SR_MQFLAG_DC;
+	if (info->is_auto)
+		analog->mqflags |= SR_MQFLAG_AUTORANGE;
+	if (info->is_diode)
+		analog->mqflags |= SR_MQFLAG_DIODE;
+	if (info->is_hold)
+		analog->mqflags |= SR_MQFLAG_HOLD;
+	if (info->is_rel)
+		analog->mqflags |= SR_MQFLAG_RELATIVE;
+
+	/* Other flags */
+	if (info->is_rs232)
+		sr_spew("RS232 enabled.");
+	if (info->is_bat)
+		sr_spew("Battery is low.");
+	if (info->is_c2c1_00)
+		sr_spew("User-defined LCD symbol 0 is active.");
+	if (info->is_c2c1_01)
+		sr_spew("User-defined LCD symbol 1 is active.");
+	if (info->is_c2c1_10)
+		sr_spew("User-defined LCD symbol 2 is active.");
+	if (info->is_c2c1_11)
+		sr_spew("User-defined LCD symbol 3 is active.");
+}
+
+SR_PRIV gboolean sr_fs9721_packet_valid(const uint8_t *buf)
+{
+	struct fs9721_info info;
+
+	parse_flags(buf, &info);
+
+	return (sync_nibbles_valid(buf) && flags_valid(&info));
+}
+
+/**
+ * Parse a protocol packet.
+ *
+ * @param buf Buffer containing the 14-byte protocol packet. Must not be NULL.
+ * @param floatval Pointer to a float variable. That variable will contain the
+ *                 result value upon parsing success. Mut not be NULL.
+ * @param analog Pointer to a struct sr_datafeed_analog. The struct will be
+ *               filled with data according to the protocol packet.
+ *               Must not be NULL.
+ * @param info Pointer to a struct fs9721_info. The struct will be filled
+ *             with data according to the protocol packet. Must not be NULL.
+ *
+ * @return SR_OK upon success, SR_ERR upon failure. Upon errors, the
+ *         'analog' variable contents are undefined and should not be used.
+ */
+SR_PRIV int sr_fs9721_parse(const uint8_t *buf, float *floatval,
+			    struct sr_datafeed_analog *analog, void *info)
+{
+	int ret;
+	struct fs9721_info *info_local;
+
+	info_local = (struct fs9721_info *)info;
+
+	if ((ret = parse_value(buf, floatval)) != SR_OK) {
+		sr_dbg("Error parsing value: %d.", ret);
+		return ret;
+	}
+
+	parse_flags(buf, info_local);
+	handle_flags(analog, floatval, info_local);
+
+	return SR_OK;
+}
+
+SR_PRIV void sr_fs9721_00_temp_c(struct sr_datafeed_analog *analog, void *info)
+{
+	struct fs9721_info *info_local;
+
+	info_local = (struct fs9721_info *)info;
+
+	/* User-defined FS9721_LP3 flag 'c2c1_00' means temperature (C). */
+	if (info_local->is_c2c1_00) {
+		analog->mq = SR_MQ_TEMPERATURE;
+		analog->unit = SR_UNIT_CELSIUS;
+	}
+}
+
+SR_PRIV void sr_fs9721_01_temp_c(struct sr_datafeed_analog *analog, void *info)
+{
+	struct fs9721_info *info_local;
+
+	info_local = (struct fs9721_info *)info;
+
+	/* User-defined FS9721_LP3 flag 'c2c1_01' means temperature (C). */
+	if (info_local->is_c2c1_01) {
+		analog->mq = SR_MQ_TEMPERATURE;
+		analog->unit = SR_UNIT_CELSIUS;
+	}
+}
+
+SR_PRIV void sr_fs9721_10_temp_c(struct sr_datafeed_analog *analog, void *info)
+{
+	struct fs9721_info *info_local;
+
+	info_local = (struct fs9721_info *)info;
+
+	/* User-defined FS9721_LP3 flag 'c2c1_10' means temperature (C). */
+	if (info_local->is_c2c1_10) {
+		analog->mq = SR_MQ_TEMPERATURE;
+		analog->unit = SR_UNIT_CELSIUS;
+	}
+}
+
+SR_PRIV void sr_fs9721_01_10_temp_f_c(struct sr_datafeed_analog *analog, void *info)
+{
+	struct fs9721_info *info_local;
+
+	info_local = (struct fs9721_info *)info;
+
+	/* User-defined FS9721_LP3 flag 'c2c1_01' means temperature (F). */
+	if (info_local->is_c2c1_01) {
+		analog->mq = SR_MQ_TEMPERATURE;
+		analog->unit = SR_UNIT_FAHRENHEIT;
+	}
+
+	/* User-defined FS9721_LP3 flag 'c2c1_10' means temperature (C). */
+	if (info_local->is_c2c1_10) {
+		analog->mq = SR_MQ_TEMPERATURE;
+		analog->unit = SR_UNIT_CELSIUS;
+	}
+}
+
+SR_PRIV void sr_fs9721_max_c_min(struct sr_datafeed_analog *analog, void *info)
+{
+	struct fs9721_info *info_local;
+
+	info_local = (struct fs9721_info *)info;
+
+	/* User-defined FS9721_LP3 flag 'c2c1_00' means MAX. */
+	if (info_local->is_c2c1_00)
+		analog->mqflags |= SR_MQFLAG_MAX;
+
+	/* User-defined FS9721_LP3 flag 'c2c1_01' means temperature (C). */
+	if (info_local->is_c2c1_01) {
+		analog->mq = SR_MQ_TEMPERATURE;
+		analog->unit = SR_UNIT_CELSIUS;
+	}
+
+	/* User-defined FS9721_LP3 flag 'c2c1_11' means MIN. */
+	if (info_local->is_c2c1_11)
+		analog->mqflags |= SR_MQFLAG_MIN;
+
+}
diff --git a/hardware/common/dmm/fs9922.c b/hardware/common/dmm/fs9922.c
new file mode 100644
index 0000000..caaa51c
--- /dev/null
+++ b/hardware/common/dmm/fs9922.c
@@ -0,0 +1,384 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/*
+ * Fortune Semiconductor FS9922-DMM3/FS9922-DMM4 protocol parser.
+ */
+
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "fs9922"
+
+static gboolean flags_valid(const struct fs9922_info *info)
+{
+	int count;
+
+	/* Does the packet have more than one multiplier? */
+	count = 0;
+	count += (info->is_nano) ? 1 : 0;
+	count += (info->is_micro) ? 1 : 0;
+	count += (info->is_milli) ? 1 : 0;
+	count += (info->is_kilo) ? 1 : 0;
+	count += (info->is_mega) ? 1 : 0;
+	if (count > 1) {
+		sr_dbg("More than one multiplier detected in packet.");
+		return FALSE;
+	}
+
+	/*
+	 * Does the packet "measure" more than one type of value?
+	 *
+	 * Note: In "diode mode", both is_diode and is_volt will be set.
+	 * That is a valid use-case, so we don't want to error out below
+	 * if it happens. Thus, we don't check for is_diode here.
+	 */
+	count = 0;
+	// count += (info->is_diode) ? 1 : 0;
+	count += (info->is_percent) ? 1 : 0;
+	count += (info->is_volt) ? 1 : 0;
+	count += (info->is_ampere) ? 1 : 0;
+	count += (info->is_ohm) ? 1 : 0;
+	count += (info->is_hfe) ? 1 : 0;
+	count += (info->is_hertz) ? 1 : 0;
+	count += (info->is_farad) ? 1 : 0;
+	count += (info->is_celsius) ? 1 : 0;
+	count += (info->is_fahrenheit) ? 1 : 0;
+	if (count > 1) {
+		sr_dbg("More than one measurement type detected in packet.");
+		return FALSE;
+	}
+
+	/* Both AC and DC set? */
+	if (info->is_ac && info->is_dc) {
+		sr_dbg("Both AC and DC flags detected in packet.");
+		return FALSE;
+	}
+
+	/* Both Celsius and Fahrenheit set? */
+	if (info->is_celsius && info->is_fahrenheit) {
+		sr_dbg("Both Celsius and Fahrenheit flags detected in packet.");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static int parse_value(const uint8_t *buf, float *result)
+{
+	int sign, intval;
+	float floatval;
+
+	/* Byte 0: Sign ('+' or '-') */
+	if (buf[0] == '+') {
+		sign = 1;
+	} else if (buf[0] == '-') {
+		sign = -1;
+	} else {
+		sr_dbg("Invalid sign byte: 0x%02x.", buf[0]);
+		return SR_ERR;
+	}
+
+	/*
+	 * Bytes 1-4: Value (4 decimal digits)
+	 *
+	 * Over limit: "0.L" on the display, "?0:?" as protocol "digits".
+	 */
+	if (buf[1] == '?' && buf[2] == '0' && buf[3] == ':' && buf[4] == '?') {
+		sr_spew("Over limit.");
+		*result = INFINITY;
+		return SR_OK;
+	} else if (!isdigit(buf[1]) || !isdigit(buf[2]) ||
+		   !isdigit(buf[3]) || !isdigit(buf[4])) {
+		sr_dbg("Value contained invalid digits: %02x %02x %02x %02x ("
+		       "%c %c %c %c).", buf[1], buf[2], buf[3], buf[4]);
+		return SR_ERR;
+	}
+	intval = 0;
+	intval += (buf[1] - '0') * 1000;
+	intval += (buf[2] - '0') * 100;
+	intval += (buf[3] - '0') * 10;
+	intval += (buf[4] - '0') * 1;
+
+	floatval = (float)intval;
+
+	/* Byte 5: Always ' ' (space, 0x20) */
+
+	/*
+	 * Byte 6: Decimal point position ('0', '1', '2', or '4')
+	 *
+	 * Note: The Fortune Semiconductor FS9922-DMM3/4 datasheets both have
+	 * an error/typo here. They claim that the values '0'/'1'/'2'/'3' are
+	 * used, but '0'/'1'/'2'/'4' is actually correct.
+	 */
+	if (buf[6] != '0' && buf[6] != '1' && buf[6] != '2' && buf[6] != '4') {
+		sr_dbg("Invalid decimal point value: 0x%02x.", buf[6]);
+		return SR_ERR;
+	}
+	if (buf[6] == '0')
+		floatval /= 1;
+	else if (buf[6] == '1')
+		floatval /= 1000;
+	else if (buf[6] == '2')
+		floatval /= 100;
+	else if (buf[6] == '4')
+		floatval /= 10;
+
+	/* Apply sign. */
+	floatval *= sign;
+
+	sr_spew("The display value is %f.", floatval);
+
+	*result = floatval;
+
+	return SR_OK;
+}
+
+static void parse_flags(const uint8_t *buf, struct fs9922_info *info)
+{
+	/* Z1/Z2/Z3/Z4 are bits for user-defined LCD symbols (on/off). */
+
+	/* Byte 7 */
+	/* Bit 7: Always 0 */
+	/* Bit 6: Always 0 */
+	info->is_auto       = (buf[7] & (1 << 5)) != 0;
+	info->is_dc         = (buf[7] & (1 << 4)) != 0;
+	info->is_ac         = (buf[7] & (1 << 3)) != 0;
+	info->is_rel        = (buf[7] & (1 << 2)) != 0;
+	info->is_hold       = (buf[7] & (1 << 1)) != 0;
+	info->is_bpn        = (buf[7] & (1 << 0)) != 0; /* Bargraph shown */
+
+	/* Byte 8 */
+	info->is_z1         = (buf[8] & (1 << 7)) != 0; /* User symbol 1 */
+	info->is_z2         = (buf[8] & (1 << 6)) != 0; /* User symbol 2 */
+	info->is_max        = (buf[8] & (1 << 5)) != 0;
+	info->is_min        = (buf[8] & (1 << 4)) != 0;
+	info->is_apo        = (buf[8] & (1 << 3)) != 0; /* Auto-poweroff on */
+	info->is_bat        = (buf[8] & (1 << 2)) != 0; /* Battery low */
+	info->is_nano       = (buf[8] & (1 << 1)) != 0;
+	info->is_z3         = (buf[8] & (1 << 0)) != 0; /* User symbol 3 */
+
+	/* Byte 9 */
+	info->is_micro      = (buf[9] & (1 << 7)) != 0;
+	info->is_milli      = (buf[9] & (1 << 6)) != 0;
+	info->is_kilo       = (buf[9] & (1 << 5)) != 0;
+	info->is_mega       = (buf[9] & (1 << 4)) != 0;
+	info->is_beep       = (buf[9] & (1 << 3)) != 0;
+	info->is_diode      = (buf[9] & (1 << 2)) != 0;
+	info->is_percent    = (buf[9] & (1 << 1)) != 0;
+	info->is_z4         = (buf[9] & (1 << 0)) != 0; /* User symbol 4 */
+
+	/* Byte 10 */
+	info->is_volt       = (buf[10] & (1 << 7)) != 0;
+	info->is_ampere     = (buf[10] & (1 << 6)) != 0;
+	info->is_ohm        = (buf[10] & (1 << 5)) != 0;
+	info->is_hfe        = (buf[10] & (1 << 4)) != 0;
+	info->is_hertz      = (buf[10] & (1 << 3)) != 0;
+	info->is_farad      = (buf[10] & (1 << 2)) != 0;
+	info->is_celsius    = (buf[10] & (1 << 1)) != 0; /* Only FS9922-DMM4 */
+	info->is_fahrenheit = (buf[10] & (1 << 0)) != 0; /* Only FS9922-DMM4 */
+
+	/*
+	 * Byte 11: Bar graph
+	 *
+	 * Bit 7 contains the sign of the bargraph number (if the bit is set,
+	 * the number is negative), bits 6..0 contain the actual number.
+	 * Valid range: 0-40 (FS9922-DMM3), 0-60 (FS9922-DMM4).
+	 *
+	 * Upon "over limit" the bargraph value is 1 count above the highest
+	 * valid number (i.e. 41 or 61, depending on chip).
+	 */
+	if (info->is_bpn) {
+		info->bargraph_sign = ((buf[11] & (1 << 7)) != 0) ? -1 : 1;
+		info->bargraph_value = (buf[11] & 0x7f);
+		info->bargraph_value *= info->bargraph_sign;
+	}
+
+	/* Byte 12: Always '\r' (carriage return, 0x0d, 13) */
+
+	/* Byte 13: Always '\n' (newline, 0x0a, 10) */
+}
+
+static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
+			 const struct fs9922_info *info)
+{
+	/* Factors */
+	if (info->is_nano)
+		*floatval /= 1000000000;
+	if (info->is_micro)
+		*floatval /= 1000000;
+	if (info->is_milli)
+		*floatval /= 1000;
+	if (info->is_kilo)
+		*floatval *= 1000;
+	if (info->is_mega)
+		*floatval *= 1000000;
+
+	/* Measurement modes */
+	if (info->is_volt || info->is_diode) {
+		/* Note: In "diode mode" both is_diode and is_volt are set. */
+		analog->mq = SR_MQ_VOLTAGE;
+		analog->unit = SR_UNIT_VOLT;
+	}
+	if (info->is_ampere) {
+		analog->mq = SR_MQ_CURRENT;
+		analog->unit = SR_UNIT_AMPERE;
+	}
+	if (info->is_ohm) {
+		analog->mq = SR_MQ_RESISTANCE;
+		analog->unit = SR_UNIT_OHM;
+	}
+	if (info->is_hfe) {
+		analog->mq = SR_MQ_GAIN;
+		analog->unit = SR_UNIT_UNITLESS;
+	}
+	if (info->is_hertz) {
+		analog->mq = SR_MQ_FREQUENCY;
+		analog->unit = SR_UNIT_HERTZ;
+	}
+	if (info->is_farad) {
+		analog->mq = SR_MQ_CAPACITANCE;
+		analog->unit = SR_UNIT_FARAD;
+	}
+	if (info->is_celsius) {
+		analog->mq = SR_MQ_TEMPERATURE;
+		analog->unit = SR_UNIT_CELSIUS;
+	}
+	if (info->is_fahrenheit) {
+		analog->mq = SR_MQ_TEMPERATURE;
+		analog->unit = SR_UNIT_FAHRENHEIT;
+	}
+	if (info->is_beep) {
+		analog->mq = SR_MQ_CONTINUITY;
+		analog->unit = SR_UNIT_BOOLEAN;
+		*floatval = (*floatval == INFINITY) ? 0.0 : 1.0;
+	}
+	if (info->is_percent) {
+		analog->mq = SR_MQ_DUTY_CYCLE;
+		analog->unit = SR_UNIT_PERCENTAGE;
+	}
+
+	/* Measurement related flags */
+	if (info->is_ac)
+		analog->mqflags |= SR_MQFLAG_AC;
+	if (info->is_dc)
+		analog->mqflags |= SR_MQFLAG_DC;
+	if (info->is_auto)
+		analog->mqflags |= SR_MQFLAG_AUTORANGE;
+	if (info->is_diode)
+		analog->mqflags |= SR_MQFLAG_DIODE;
+	if (info->is_hold)
+		analog->mqflags |= SR_MQFLAG_HOLD;
+	if (info->is_max)
+		analog->mqflags |= SR_MQFLAG_MAX;
+	if (info->is_min)
+		analog->mqflags |= SR_MQFLAG_MIN;
+	if (info->is_rel)
+		analog->mqflags |= SR_MQFLAG_RELATIVE;
+
+	/* Other flags */
+	if (info->is_apo)
+		sr_spew("Automatic power-off function is active.");
+	if (info->is_bat)
+		sr_spew("Battery is low.");
+	if (info->is_z1)
+		sr_spew("User-defined LCD symbol 1 is active.");
+	if (info->is_z2)
+		sr_spew("User-defined LCD symbol 2 is active.");
+	if (info->is_z3)
+		sr_spew("User-defined LCD symbol 3 is active.");
+	if (info->is_z4)
+		sr_spew("User-defined LCD symbol 4 is active.");
+	if (info->is_bpn)
+		sr_spew("The bargraph value is %d.", info->bargraph_value);
+	else
+		sr_spew("The bargraph is not active.");
+
+}
+
+SR_PRIV gboolean sr_fs9922_packet_valid(const uint8_t *buf)
+{
+	struct fs9922_info info;
+
+	/* Byte 0: Sign (must be '+' or '-') */
+	if (buf[0] != '+' && buf[0] != '-')
+		return FALSE;
+
+	/* Byte 12: Always '\r' (carriage return, 0x0d, 13) */
+	/* Byte 13: Always '\n' (newline, 0x0a, 10) */
+	if (buf[12] != '\r' || buf[13] != '\n')
+		return FALSE;
+
+	parse_flags(buf, &info);
+
+	return flags_valid(&info);
+}
+
+/**
+ * Parse a protocol packet.
+ *
+ * @param buf Buffer containing the protocol packet. Must not be NULL.
+ * @param floatval Pointer to a float variable. That variable will contain the
+ *                 result value upon parsing success. Must not be NULL.
+ * @param analog Pointer to a struct sr_datafeed_analog. The struct will be
+ *               filled with data according to the protocol packet.
+ *               Must not be NULL.
+ * @param info Pointer to a struct fs9922_info. The struct will be filled
+ *             with data according to the protocol packet. Must not be NULL.
+ *
+ * @return SR_OK upon success, SR_ERR upon failure. Upon errors, the
+ *         'analog' variable contents are undefined and should not be used.
+ */
+SR_PRIV int sr_fs9922_parse(const uint8_t *buf, float *floatval,
+			    struct sr_datafeed_analog *analog, void *info)
+{
+	int ret;
+	struct fs9922_info *info_local;
+
+	info_local = (struct fs9922_info *)info;
+
+	if ((ret = parse_value(buf, floatval)) != SR_OK) {
+		sr_dbg("Error parsing value: %d.", ret);
+		return ret;
+	}
+
+	parse_flags(buf, info_local);
+	handle_flags(analog, floatval, info_local);
+
+	return SR_OK;
+}
+
+SR_PRIV void sr_fs9922_z1_diode(struct sr_datafeed_analog *analog, void *info)
+{
+	struct fs9922_info *info_local;
+
+	info_local = (struct fs9922_info *)info;
+
+	/* User-defined z1 flag means "diode mode". */
+	if (info_local->is_z1) {
+		analog->mq = SR_MQ_VOLTAGE;
+		analog->unit = SR_UNIT_VOLT;
+		analog->mqflags |= SR_MQFLAG_DIODE;
+	}
+}
diff --git a/hardware/common/dmm/m2110.c b/hardware/common/dmm/m2110.c
new file mode 100644
index 0000000..5863cef
--- /dev/null
+++ b/hardware/common/dmm/m2110.c
@@ -0,0 +1,70 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Matthias Heidbrink <m-sigrok at heidbrink.biz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * @file
+ *
+ * BBC Goerz Metrawatt M2110 ASCII protocol parser.
+ *
+ * Most probably the simplest multimeter protocol ever ;-) .
+ */
+
+#include <string.h>
+#include <math.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "m2110"
+
+SR_PRIV gboolean sr_m2110_packet_valid(const uint8_t *buf)
+{
+	float val;
+
+	if ((buf[7] != '\r') || (buf[8] != '\n'))
+		return FALSE;
+
+	if (!strncmp((const char *)buf, "OVERRNG", 7))
+		return TRUE;
+
+	if (sscanf((const char *)buf, "%f", &val) == 1)
+		return TRUE;
+	else
+		return FALSE;
+}
+
+SR_PRIV int sr_m2110_parse(const uint8_t *buf, float *floatval,
+				struct sr_datafeed_analog *analog, void *info)
+{
+	float val;
+
+	(void)info;
+
+	/* We don't know the unit, so that's the best we can do. */
+	analog->mq = SR_MQ_GAIN;
+	analog->unit = SR_UNIT_UNITLESS;
+	analog->mqflags = 0;
+
+	if (!strncmp((const char *)buf, "OVERRNG", 7))
+		*floatval = INFINITY;
+	else if (sscanf((const char *)buf, "%f", &val) == 1)
+		*floatval = val;
+
+	return SR_OK;
+}
diff --git a/hardware/common/dmm/metex14.c b/hardware/common/dmm/metex14.c
new file mode 100644
index 0000000..8151aa9
--- /dev/null
+++ b/hardware/common/dmm/metex14.c
@@ -0,0 +1,343 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012-2013 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/**
+ * @file
+ *
+ * Metex 14-bytes ASCII protocol parser.
+ *
+ * @internal
+ * This should work for various multimeters which use this kind of protocol,
+ * even though there is some variation in which modes each DMM supports.
+ *
+ * It does _not_ work for all Metex DMMs, some use a quite different protocol.
+ */
+
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "metex14"
+
+/** Parse value from buf, byte 2-8. */
+static int parse_value(const uint8_t *buf, struct metex14_info *info,
+			float *result)
+{
+	int i, is_ol, cnt;
+	char valstr[7 + 1];
+
+	/* Strip all spaces from bytes 2-8. */
+	memset(&valstr, 0, 7 + 1);
+	for (i = 0, cnt = 0; i < 7; i++) {
+		if (buf[2 + i] != ' ')
+			valstr[cnt++] = buf[2 + i];
+	}
+
+	/* Bytes 5-7: Over limit (various forms) */
+	is_ol = 0;
+	is_ol += (!strcasecmp((const char *)&valstr, ".OL")) ? 1 : 0;
+	is_ol += (!strcasecmp((const char *)&valstr, "O.L")) ? 1 : 0;
+	is_ol += (!strcasecmp((const char *)&valstr, "OL.")) ? 1 : 0;
+	is_ol += (!strcasecmp((const char *)&valstr, "OL")) ? 1 : 0;
+	is_ol += (!strcasecmp((const char *)&valstr, "-.OL")) ? 1 : 0;
+	is_ol += (!strcasecmp((const char *)&valstr, "-O.L")) ? 1 : 0;
+	is_ol += (!strcasecmp((const char *)&valstr, "-OL.")) ? 1 : 0;
+	is_ol += (!strcasecmp((const char *)&valstr, "-OL")) ? 1 : 0;
+	if (is_ol != 0) {
+		sr_spew("Over limit.");
+		*result = INFINITY;
+		return SR_OK;
+	}
+
+	/* Logic functions */
+	if (!strcmp((const char *)&valstr, "READY") ||
+			!strcmp((const char *)&valstr, "FLOAT")) {
+		*result = INFINITY;
+		info->is_logic = TRUE;
+	} else if (!strcmp((const char *)&valstr, "Hi")) {
+		*result = 1.0;
+		info->is_logic = TRUE;
+	} else if (!strcmp((const char *)&valstr, "Lo")) {
+		*result = 0.0;
+		info->is_logic = TRUE;
+	}
+	if (info->is_logic)
+		return SR_OK;
+
+	/* Bytes 2-8: Sign, value (up to 5 digits) and decimal point */
+	sscanf((const char *)&valstr, "%f", result);
+
+	sr_spew("The display value is %f.", *result);
+
+	return SR_OK;
+}
+
+static void parse_flags(const char *buf, struct metex14_info *info)
+{
+	int i, cnt;
+	char unit[4 + 1];
+	const char *u;
+
+	/* Bytes 0-1: Measurement mode AC, DC */
+	info->is_ac = !strncmp(buf, "AC", 2);
+	info->is_dc = !strncmp(buf, "DC", 2);
+
+	/* Bytes 2-8: See parse_value(). */
+
+	/* Strip all spaces from bytes 9-12. */
+	memset(&unit, 0, 4 + 1);
+	for (i = 0, cnt = 0; i < 4; i++) {
+		if (buf[9 + i] != ' ')
+			unit[cnt++] = buf[9 + i];
+	}
+
+	/* Bytes 9-12: Unit */
+	u = (const char *)&unit;
+	if (!strcasecmp(u, "A"))
+		info->is_ampere = TRUE;
+	else if (!strcasecmp(u, "mA"))
+		info->is_milli = info->is_ampere = TRUE;
+	else if (!strcasecmp(u, "uA"))
+		info->is_micro = info->is_ampere = TRUE;
+	else if (!strcasecmp(u, "V"))
+		info->is_volt = TRUE;
+	else if (!strcasecmp(u, "mV"))
+		info->is_milli = info->is_volt = TRUE;
+	else if (!strcasecmp(u, "Ohm"))
+		info->is_ohm = TRUE;
+	else if (!strcasecmp(u, "KOhm"))
+		info->is_kilo = info->is_ohm = TRUE;
+	else if (!strcasecmp(u, "MOhm"))
+		info->is_mega = info->is_ohm = TRUE;
+	else if (!strcasecmp(u, "pF"))
+		info->is_pico = info->is_farad = TRUE;
+	else if (!strcasecmp(u, "nF"))
+		info->is_nano = info->is_farad = TRUE;
+	else if (!strcasecmp(u, "uF"))
+		info->is_micro = info->is_farad = TRUE;
+	else if (!strcasecmp(u, "KHz"))
+		info->is_kilo = info->is_hertz = TRUE;
+	else if (!strcasecmp(u, "C"))
+		info->is_celsius = TRUE;
+	else if (!strcasecmp(u, "DB"))
+		info->is_decibel = TRUE;
+	else if (!strcasecmp(u, ""))
+		info->is_unitless = TRUE;
+
+	/* Bytes 0-1: Measurement mode, except AC/DC */
+	info->is_resistance  = !strncmp(buf, "OH", 2) ||
+		(!strncmp(buf, "  ", 2) && info->is_ohm);
+	info->is_capacity    = !strncmp(buf, "CA", 2) ||
+		(!strncmp(buf, "  ", 2) && info->is_farad);
+	info->is_temperature = !strncmp(buf, "TE", 2);
+	info->is_diode       = !strncmp(buf, "DI", 2) ||
+		(!strncmp(buf, "  ", 2) && info->is_volt && info->is_milli);
+	info->is_frequency   = !strncmp(buf, "FR", 2) ||
+		(!strncmp(buf, "  ", 2) && info->is_hertz);
+	info->is_gain        = !strncmp(buf, "DB", 2);
+	info->is_hfe         = !strncmp(buf, "HF", 2) ||
+		(!strncmp(buf, "  ", 2) && !info->is_volt && !info->is_ohm &&
+		 !info->is_logic && !info->is_farad && !info->is_hertz);
+	/*
+	 * Note:
+	 * - Protocol doesn't distinguish "resistance" from "beep" mode.
+	 * - "DB" shows the logarithmic ratio of input voltage to a
+	 *   pre-stored (user-changeable) value in the DMM.
+	 */
+
+	/* Byte 13: Always '\r' (carriage return, 0x0d, 13) */
+}
+
+static void handle_flags(struct sr_datafeed_analog *analog, float *floatval,
+			 const struct metex14_info *info)
+{
+	/* Factors */
+	if (info->is_pico)
+		*floatval /= 1000000000000ULL;
+	if (info->is_nano)
+		*floatval /= 1000000000;
+	if (info->is_micro)
+		*floatval /= 1000000;
+	if (info->is_milli)
+		*floatval /= 1000;
+	if (info->is_kilo)
+		*floatval *= 1000;
+	if (info->is_mega)
+		*floatval *= 1000000;
+
+	/* Measurement modes */
+	if (info->is_volt) {
+		analog->mq = SR_MQ_VOLTAGE;
+		analog->unit = SR_UNIT_VOLT;
+	}
+	if (info->is_ampere) {
+		analog->mq = SR_MQ_CURRENT;
+		analog->unit = SR_UNIT_AMPERE;
+	}
+	if (info->is_ohm) {
+		analog->mq = SR_MQ_RESISTANCE;
+		analog->unit = SR_UNIT_OHM;
+	}
+	if (info->is_hertz) {
+		analog->mq = SR_MQ_FREQUENCY;
+		analog->unit = SR_UNIT_HERTZ;
+	}
+	if (info->is_farad) {
+		analog->mq = SR_MQ_CAPACITANCE;
+		analog->unit = SR_UNIT_FARAD;
+	}
+	if (info->is_celsius) {
+		analog->mq = SR_MQ_TEMPERATURE;
+		analog->unit = SR_UNIT_CELSIUS;
+	}
+	if (info->is_diode) {
+		analog->mq = SR_MQ_VOLTAGE;
+		analog->unit = SR_UNIT_VOLT;
+	}
+	if (info->is_gain) {
+		analog->mq = SR_MQ_GAIN;
+		analog->unit = SR_UNIT_DECIBEL_VOLT;
+	}
+	if (info->is_hfe) {
+		analog->mq = SR_MQ_GAIN;
+		analog->unit = SR_UNIT_UNITLESS;
+	}
+	if (info->is_logic) {
+		analog->mq = SR_MQ_GAIN;
+		analog->unit = SR_UNIT_UNITLESS;
+	}
+
+	/* Measurement related flags */
+	if (info->is_ac)
+		analog->mqflags |= SR_MQFLAG_AC;
+	if (info->is_dc)
+		analog->mqflags |= SR_MQFLAG_DC;
+	if (info->is_diode)
+		analog->mqflags |= SR_MQFLAG_DIODE;
+}
+
+static gboolean flags_valid(const struct metex14_info *info)
+{
+	int count;
+
+	/* Does the packet have more than one multiplier? */
+	count = 0;
+	count += (info->is_pico) ? 1 : 0;
+	count += (info->is_nano) ? 1 : 0;
+	count += (info->is_micro) ? 1 : 0;
+	count += (info->is_milli) ? 1 : 0;
+	count += (info->is_kilo) ? 1 : 0;
+	count += (info->is_mega) ? 1 : 0;
+	if (count > 1) {
+		sr_dbg("More than one multiplier detected in packet.");
+		return FALSE;
+	}
+
+	/* Does the packet "measure" more than one type of value? */
+	count = 0;
+	count += (info->is_ac) ? 1 : 0;
+	count += (info->is_dc) ? 1 : 0;
+	count += (info->is_resistance) ? 1 : 0;
+	count += (info->is_capacity) ? 1 : 0;
+	count += (info->is_temperature) ? 1 : 0;
+	count += (info->is_diode) ? 1 : 0;
+	count += (info->is_frequency) ? 1 : 0;
+	if (count > 1) {
+		sr_dbg("More than one measurement type detected in packet.");
+		return FALSE;
+	}
+
+	/* Both AC and DC set? */
+	if (info->is_ac && info->is_dc) {
+		sr_dbg("Both AC and DC flags detected in packet.");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+#ifdef HAVE_LIBSERIALPORT
+SR_PRIV int sr_metex14_packet_request(struct sr_serial_dev_inst *serial)
+{
+	const uint8_t wbuf = 'D';
+
+	sr_spew("Requesting DMM packet.");
+
+	return (serial_write(serial, &wbuf, 1) == 1) ? SR_OK : SR_ERR;
+}
+#endif
+
+SR_PRIV gboolean sr_metex14_packet_valid(const uint8_t *buf)
+{
+	struct metex14_info info;
+
+	memset(&info, 0x00, sizeof(struct metex14_info));
+	parse_flags((const char *)buf, &info);
+
+	if (!flags_valid(&info))
+		return FALSE;
+
+	if (buf[13] != '\r')
+		return FALSE;
+
+	return TRUE;
+}
+
+/**
+ * Parse a protocol packet.
+ *
+ * @param buf Buffer containing the protocol packet. Must not be NULL.
+ * @param floatval Pointer to a float variable. That variable will be modified
+ *                 in-place depending on the protocol packet. Must not be NULL.
+ * @param analog Pointer to a struct sr_datafeed_analog. The struct will be
+ *               filled with data according to the protocol packet.
+ *               Must not be NULL.
+ * @param info Pointer to a struct metex14_info. The struct will be filled
+ *             with data according to the protocol packet. Must not be NULL.
+ *
+ * @return SR_OK upon success, SR_ERR upon failure. Upon errors, the
+ *         'analog' variable contents are undefined and should not be used.
+ */
+SR_PRIV int sr_metex14_parse(const uint8_t *buf, float *floatval,
+			     struct sr_datafeed_analog *analog, void *info)
+{
+	int ret;
+	struct metex14_info *info_local;
+
+	info_local = (struct metex14_info *)info;
+
+	/* Don't print byte 13. That one contains the carriage return. */
+	sr_dbg("DMM packet: \"%.13s\"", buf);
+
+	memset(info_local, 0x00, sizeof(struct metex14_info));
+
+	if ((ret = parse_value(buf, info_local, floatval)) != SR_OK) {
+		sr_dbg("Error parsing value: %d.", ret);
+		return ret;
+	}
+
+	parse_flags((const char *)buf, info_local);
+	handle_flags(analog, floatval, info_local);
+
+	return SR_OK;
+}
diff --git a/hardware/common/dmm/rs9lcd.c b/hardware/common/dmm/rs9lcd.c
new file mode 100644
index 0000000..539c233
--- /dev/null
+++ b/hardware/common/dmm/rs9lcd.c
@@ -0,0 +1,437 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me at gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * RadioShack 22-812 protocol parser.
+ *
+ * This protocol is currently encountered on the RadioShack 22-812 DMM.
+ * It is a 9-byte packet representing a 1:1 mapping of the LCD segments, hence
+ * the name rs9lcd.
+ *
+ * The chip is a bare die covered by a plastic blob. It is unclear if this chip
+ * and protocol is used on any other device.
+ */
+
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "rs9lcd"
+
+/* Byte 1 of the packet, and the modes it represents */
+#define IND1_HZ		(1 << 7)
+#define IND1_OHM	(1 << 6)
+#define IND1_KILO	(1 << 5)
+#define IND1_MEGA	(1 << 4)
+#define IND1_FARAD	(1 << 3)
+#define IND1_AMP	(1 << 2)
+#define IND1_VOLT	(1 << 1)
+#define IND1_MILI	(1 << 0)
+/* Byte 2 of the packet, and the modes it represents */
+#define IND2_MICRO	(1 << 7)
+#define IND2_NANO	(1 << 6)
+#define IND2_DBM	(1 << 5)
+#define IND2_SEC	(1 << 4)
+#define IND2_DUTY	(1 << 3)
+#define IND2_HFE	(1 << 2)
+#define IND2_REL	(1 << 1)
+#define IND2_MIN	(1 << 0)
+/* Byte 7 of the packet, and the modes it represents */
+#define INFO_BEEP	(1 << 7)
+#define INFO_DIODE	(1 << 6)
+#define INFO_BAT	(1 << 5)
+#define INFO_HOLD	(1 << 4)
+#define INFO_NEG	(1 << 3)
+#define INFO_AC		(1 << 2)
+#define INFO_RS232	(1 << 1)
+#define INFO_AUTO	(1 << 0)
+/* Instead of a decimal point, digit 4 carries the MAX flag */
+#define DIG4_MAX	(1 << 3)
+/* Mask to remove the decimal point from a digit */
+#define DP_MASK		(1 << 3)
+
+/* What the LCD values represent */
+#define LCD_0		0xd7
+#define LCD_1		0x50
+#define LCD_2		0xb5
+#define LCD_3		0xf1
+#define LCD_4		0x72
+#define LCD_5		0xe3
+#define LCD_6		0xe7
+#define LCD_7		0x51
+#define LCD_8		0xf7
+#define LCD_9		0xf3
+
+#define LCD_C		0x87
+#define LCD_E
+#define LCD_F
+#define LCD_h		0x66
+#define LCD_H		0x76
+#define LCD_I
+#define LCD_n
+#define LCD_P		0x37
+#define LCD_r
+
+enum {
+	MODE_DC_V	= 0,
+	MODE_AC_V	= 1,
+	MODE_DC_UA	= 2,
+	MODE_DC_MA	= 3,
+	MODE_DC_A 	= 4,
+	MODE_AC_UA	= 5,
+	MODE_AC_MA	= 6,
+	MODE_AC_A	= 7,
+	MODE_OHM	= 8,
+	MODE_FARAD	= 9,
+	MODE_HZ		= 10,
+	MODE_VOLT_HZ	= 11,	/* Dial set to V, Hz selected by Hz button */
+	MODE_AMP_HZ	= 12,	/* Dial set to A, Hz selected by Hz button */
+	MODE_DUTY	= 13,
+	MODE_VOLT_DUTY	= 14,	/* Dial set to V, duty cycle selected */
+	MODE_AMP_DUTY	= 15,	/* Dial set to A, duty cycle selected */
+	MODE_WIDTH	= 16,
+	MODE_VOLT_WIDTH	= 17,	/* Dial set to V, pulse width selected */
+	MODE_AMP_WIDTH	= 18,	/* Dial set to A, pulse width selected */
+	MODE_DIODE	= 19,
+	MODE_CONT	= 20,
+	MODE_HFE	= 21,
+	MODE_LOGIC	= 22,
+	MODE_DBM	= 23,
+	/* MODE_EF	= 24, */ /* Not encountered on any DMM */
+	MODE_TEMP	= 25,
+	MODE_INVALID	= 26,
+};
+
+enum {
+	READ_ALL,
+	READ_TEMP,
+};
+
+struct rs9lcd_packet {
+	uint8_t mode;
+	uint8_t indicatrix1;
+	uint8_t indicatrix2;
+	uint8_t digit4;
+	uint8_t digit3;
+	uint8_t digit2;
+	uint8_t digit1;
+	uint8_t info;
+	uint8_t checksum;
+};
+
+static gboolean checksum_valid(const struct rs9lcd_packet *rs_packet)
+{
+	uint8_t *raw;
+	uint8_t sum = 0;
+	int i;
+
+	raw = (void *)rs_packet;
+
+	for (i = 0; i < RS9LCD_PACKET_SIZE - 1; i++)
+		sum += raw[i];
+
+	/* This is just a funky constant added to the checksum. */
+	sum += 57;
+	sum -= rs_packet->checksum;
+	return (sum == 0);
+}
+
+static gboolean selection_good(const struct rs9lcd_packet *rs_packet)
+{
+	int count;
+
+	/* Does the packet have more than one multiplier? */
+	count = 0;
+	count += (rs_packet->indicatrix1 & IND1_KILO)  ? 1 : 0;
+	count += (rs_packet->indicatrix1 & IND1_MEGA)  ? 1 : 0;
+	count += (rs_packet->indicatrix1 & IND1_MILI)  ? 1 : 0;
+	count += (rs_packet->indicatrix2 & IND2_MICRO) ? 1 : 0;
+	count += (rs_packet->indicatrix2 & IND2_NANO)  ? 1 : 0;
+	if (count > 1) {
+		sr_dbg("More than one multiplier detected in packet.");
+		return FALSE;
+	}
+
+	/* Does the packet "measure" more than one type of value? */
+	count = 0;
+	count += (rs_packet->indicatrix1 & IND1_HZ)    ? 1 : 0;
+	count += (rs_packet->indicatrix1 & IND1_OHM)   ? 1 : 0;
+	count += (rs_packet->indicatrix1 & IND1_FARAD) ? 1 : 0;
+	count += (rs_packet->indicatrix1 & IND1_AMP)   ? 1 : 0;
+	count += (rs_packet->indicatrix1 & IND1_VOLT)  ? 1 : 0;
+	count += (rs_packet->indicatrix2 & IND2_DBM)   ? 1 : 0;
+	count += (rs_packet->indicatrix2 & IND2_SEC)   ? 1 : 0;
+	count += (rs_packet->indicatrix2 & IND2_DUTY)  ? 1 : 0;
+	count += (rs_packet->indicatrix2 & IND2_HFE)   ? 1 : 0;
+	if (count > 1) {
+		sr_dbg("More than one measurement type detected in packet.");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+/*
+ * Since the 22-812 does not identify itself in any way, shape, or form,
+ * we really don't know for sure who is sending the data. We must use every
+ * possible check to filter out bad packets, especially since detection of the
+ * 22-812 depends on how well we can filter the packets.
+ */
+SR_PRIV gboolean sr_rs9lcd_packet_valid(const uint8_t *buf)
+{
+	const struct rs9lcd_packet *rs_packet = (void *)buf;
+
+	/*
+	 * Check for valid mode first, before calculating the checksum. No
+	 * point calculating the checksum, if we know we'll reject the packet.
+	 */
+	if (!(rs_packet->mode < MODE_INVALID))
+		return FALSE;
+
+	if (!checksum_valid(rs_packet)) {
+		sr_spew("Packet with invalid checksum. Discarding.");
+		return FALSE;
+	}
+
+	if (!selection_good(rs_packet)) {
+		sr_spew("Packet with invalid selection bits. Discarding.");
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static uint8_t decode_digit(uint8_t raw_digit)
+{
+	/* Take out the decimal point, so we can use a simple switch(). */
+	raw_digit &= ~DP_MASK;
+
+	switch (raw_digit) {
+	case 0x00:
+	case LCD_0:
+		return 0;
+	case LCD_1:
+		return 1;
+	case LCD_2:
+		return 2;
+	case LCD_3:
+		return 3;
+	case LCD_4:
+		return 4;
+	case LCD_5:
+		return 5;
+	case LCD_6:
+		return 6;
+	case LCD_7:
+		return 7;
+	case LCD_8:
+		return 8;
+	case LCD_9:
+		return 9;
+	default:
+		sr_dbg("Invalid digit byte: 0x%02x.", raw_digit);
+		return 0xff;
+	}
+}
+
+static double lcd_to_double(const struct rs9lcd_packet *rs_packet, int type)
+{
+	double rawval = 0, multiplier = 1;
+	uint8_t digit, raw_digit;
+	gboolean dp_reached = FALSE;
+	int i, end;
+
+	/* end = 1: Don't parse last digit. end = 0: Parse all digits. */
+	end = (type == READ_TEMP) ? 1 : 0;
+
+	/* We have 4 digits, and we start from the most significant. */
+	for (i = 3; i >= end; i--) {
+		raw_digit = *(&(rs_packet->digit4) + i);
+		digit = decode_digit(raw_digit);
+		if (digit == 0xff) {
+			rawval = NAN;
+			break;
+		}
+		/*
+		 * Digit 1 does not have a decimal point. Instead, the decimal
+		 * point is used to indicate MAX, so we must avoid testing it.
+		 */
+		if ((i < 3) && (raw_digit & DP_MASK))
+			dp_reached = TRUE;
+		if (dp_reached)
+			multiplier /= 10;
+		rawval = rawval * 10 + digit;
+	}
+	rawval *= multiplier;
+	if (rs_packet->info & INFO_NEG)
+		rawval *= -1;
+
+	/* See if we need to multiply our raw value by anything. */
+	if (rs_packet->indicatrix1 & IND2_NANO)
+		rawval *= 1E-9;
+	else if (rs_packet->indicatrix2 & IND2_MICRO)
+		rawval *= 1E-6;
+	else if (rs_packet->indicatrix1 & IND1_MILI)
+		rawval *= 1E-3;
+	else if (rs_packet->indicatrix1 & IND1_KILO)
+		rawval *= 1E3;
+	else if (rs_packet->indicatrix1 & IND1_MEGA)
+		rawval *= 1E6;
+
+	return rawval;
+}
+
+static gboolean is_celsius(const struct rs9lcd_packet *rs_packet)
+{
+	return ((rs_packet->digit4 & ~DP_MASK) == LCD_C);
+}
+
+static gboolean is_shortcirc(const struct rs9lcd_packet *rs_packet)
+{
+	return ((rs_packet->digit2 & ~DP_MASK) == LCD_h);
+}
+
+static gboolean is_logic_high(const struct rs9lcd_packet *rs_packet)
+{
+	sr_spew("Digit 2: 0x%02x.", rs_packet->digit2 & ~DP_MASK);
+	return ((rs_packet->digit2 & ~DP_MASK) == LCD_H);
+}
+
+SR_PRIV int sr_rs9lcd_parse(const uint8_t *buf, float *floatval,
+			    struct sr_datafeed_analog *analog, void *info)
+{
+	const struct rs9lcd_packet *rs_packet = (void *)buf;
+	double rawval;
+
+	(void)info;
+
+	rawval = lcd_to_double(rs_packet, READ_ALL);
+
+	switch (rs_packet->mode) {
+	case MODE_DC_V:
+		analog->mq = SR_MQ_VOLTAGE;
+		analog->unit = SR_UNIT_VOLT;
+		analog->mqflags |= SR_MQFLAG_DC;
+		break;
+	case MODE_AC_V:
+		analog->mq = SR_MQ_VOLTAGE;
+		analog->unit = SR_UNIT_VOLT;
+		analog->mqflags |= SR_MQFLAG_AC;
+		break;
+	case MODE_DC_UA:	/* Fall through */
+	case MODE_DC_MA:	/* Fall through */
+	case MODE_DC_A:
+		analog->mq = SR_MQ_CURRENT;
+		analog->unit = SR_UNIT_AMPERE;
+		analog->mqflags |= SR_MQFLAG_DC;
+		break;
+	case MODE_AC_UA:	/* Fall through */
+	case MODE_AC_MA:	/* Fall through */
+	case MODE_AC_A:
+		analog->mq = SR_MQ_CURRENT;
+		analog->unit = SR_UNIT_AMPERE;
+		analog->mqflags |= SR_MQFLAG_AC;
+		break;
+	case MODE_OHM:
+		analog->mq = SR_MQ_RESISTANCE;
+		analog->unit = SR_UNIT_OHM;
+		break;
+	case MODE_FARAD:
+		analog->mq = SR_MQ_CAPACITANCE;
+		analog->unit = SR_UNIT_FARAD;
+		break;
+	case MODE_CONT:
+		analog->mq = SR_MQ_CONTINUITY;
+		analog->unit = SR_UNIT_BOOLEAN;
+		rawval = is_shortcirc(rs_packet);
+		break;
+	case MODE_DIODE:
+		analog->mq = SR_MQ_VOLTAGE;
+		analog->unit = SR_UNIT_VOLT;
+		analog->mqflags |= SR_MQFLAG_DIODE | SR_MQFLAG_DC;
+		break;
+	case MODE_HZ:		/* Fall through */
+	case MODE_VOLT_HZ:	/* Fall through */
+	case MODE_AMP_HZ:
+		analog->mq = SR_MQ_FREQUENCY;
+		analog->unit = SR_UNIT_HERTZ;
+		break;
+	case MODE_LOGIC:
+		/*
+		 * No matter whether or not we have an actual voltage reading,
+		 * we are measuring voltage, so we set our MQ as VOLTAGE.
+		 */
+		analog->mq = SR_MQ_VOLTAGE;
+		if (!isnan(rawval)) {
+			/* We have an actual voltage. */
+			analog->unit = SR_UNIT_VOLT;
+		} else {
+			/* We have either HI or LOW. */
+			analog->unit = SR_UNIT_BOOLEAN;
+			rawval = is_logic_high(rs_packet);
+		}
+		break;
+	case MODE_HFE:
+		analog->mq = SR_MQ_GAIN;
+		analog->unit = SR_UNIT_UNITLESS;
+		break;
+	case MODE_DUTY:		/* Fall through */
+	case MODE_VOLT_DUTY:	/* Fall through */
+	case MODE_AMP_DUTY:
+		analog->mq = SR_MQ_DUTY_CYCLE;
+		analog->unit = SR_UNIT_PERCENTAGE;
+		break;
+	case MODE_WIDTH:	/* Fall through */
+	case MODE_VOLT_WIDTH:	/* Fall through */
+	case MODE_AMP_WIDTH:
+		analog->mq = SR_MQ_PULSE_WIDTH;
+		analog->unit = SR_UNIT_SECOND;
+		break;
+	case MODE_TEMP:
+		analog->mq = SR_MQ_TEMPERATURE;
+		/* We need to reparse. */
+		rawval = lcd_to_double(rs_packet, READ_TEMP);
+		analog->unit = is_celsius(rs_packet) ?
+				SR_UNIT_CELSIUS : SR_UNIT_FAHRENHEIT;
+		break;
+	case MODE_DBM:
+		analog->mq = SR_MQ_POWER;
+		analog->unit = SR_UNIT_DECIBEL_MW;
+		analog->mqflags |= SR_MQFLAG_AC;
+		break;
+	default:
+		sr_dbg("Unknown mode: %d.", rs_packet->mode);
+		break;
+	}
+
+	if (rs_packet->info & INFO_HOLD)
+		analog->mqflags |= SR_MQFLAG_HOLD;
+	if (rs_packet->digit4 & DIG4_MAX)
+		analog->mqflags |= SR_MQFLAG_MAX;
+	if (rs_packet->indicatrix2 & IND2_MIN)
+		analog->mqflags |= SR_MQFLAG_MIN;
+	if (rs_packet->info & INFO_AUTO)
+		analog->mqflags |= SR_MQFLAG_AUTORANGE;
+
+	*floatval = rawval;
+	return SR_OK;
+}
diff --git a/hardware/common/ezusb.c b/hardware/common/ezusb.c
new file mode 100644
index 0000000..044b464
--- /dev/null
+++ b/hardware/common/ezusb.c
@@ -0,0 +1,136 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010-2012 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Helper functions for the Cypress EZ-USB / FX2 series chips.
+ */
+
+#include <libusb.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "ezusb"
+
+SR_PRIV int ezusb_reset(struct libusb_device_handle *hdl, int set_clear)
+{
+	int ret;
+	unsigned char buf[1];
+
+	sr_info("setting CPU reset mode %s...",
+		set_clear ? "on" : "off");
+	buf[0] = set_clear ? 1 : 0;
+	ret = libusb_control_transfer(hdl, LIBUSB_REQUEST_TYPE_VENDOR, 0xa0,
+				      0xe600, 0x0000, buf, 1, 100);
+	if (ret < 0)
+		sr_err("Unable to send control request: %s.",
+				libusb_error_name(ret));
+
+	return ret;
+}
+
+SR_PRIV int ezusb_install_firmware(libusb_device_handle *hdl,
+				   const char *filename)
+{
+	FILE *fw;
+	int offset, chunksize, ret, result;
+	unsigned char buf[4096];
+
+	sr_info("Uploading firmware at %s", filename);
+	if ((fw = g_fopen(filename, "rb")) == NULL) {
+		sr_err("Unable to open firmware file %s for reading: %s",
+		       filename, strerror(errno));
+		return SR_ERR;
+	}
+
+	result = SR_OK;
+	offset = 0;
+	while (1) {
+		chunksize = fread(buf, 1, 4096, fw);
+		if (chunksize == 0)
+			break;
+		ret = libusb_control_transfer(hdl, LIBUSB_REQUEST_TYPE_VENDOR |
+					      LIBUSB_ENDPOINT_OUT, 0xa0, offset,
+					      0x0000, buf, chunksize, 100);
+		if (ret < 0) {
+			sr_err("Unable to send firmware to device: %s.",
+					libusb_error_name(ret));
+			result = SR_ERR;
+			break;
+		}
+		sr_info("Uploaded %d bytes", chunksize);
+		offset += chunksize;
+	}
+	fclose(fw);
+	sr_info("Firmware upload done");
+
+	return result;
+}
+
+SR_PRIV int ezusb_upload_firmware(libusb_device *dev, int configuration,
+				  const char *filename)
+{
+	struct libusb_device_handle *hdl;
+	int ret;
+
+	sr_info("uploading firmware to device on %d.%d",
+		libusb_get_bus_number(dev), libusb_get_device_address(dev));
+
+	if ((ret = libusb_open(dev, &hdl)) < 0) {
+		sr_err("failed to open device: %s.", libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+/*
+ * The libusbx darwin backend is broken: it can report a kernel driver being
+ * active, but detaching it always returns an error.
+ */
+#if !defined(__APPLE__)
+	if (libusb_kernel_driver_active(hdl, 0) == 1) {
+		if ((ret = libusb_detach_kernel_driver(hdl, 0)) < 0) {
+			sr_err("failed to detach kernel driver: %s",
+					libusb_error_name(ret));
+			return SR_ERR;
+		}
+	}
+#endif
+
+	if ((ret = libusb_set_configuration(hdl, configuration)) < 0) {
+		sr_err("Unable to set configuration: %s",
+				libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	if ((ezusb_reset(hdl, 1)) < 0)
+		return SR_ERR;
+
+	if (ezusb_install_firmware(hdl, filename) < 0)
+		return SR_ERR;
+
+	if ((ezusb_reset(hdl, 0)) < 0)
+		return SR_ERR;
+
+	libusb_close(hdl);
+
+	return SR_OK;
+}
diff --git a/hardware/common/scpi.c b/hardware/common/scpi.c
new file mode 100644
index 0000000..a3101a9
--- /dev/null
+++ b/hardware/common/scpi.c
@@ -0,0 +1,750 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 poljar (Damir Jelić) <poljarinho at gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#include <glib.h>
+#include <string.h>
+
+#define LOG_PREFIX "scpi"
+
+#define SCPI_READ_RETRIES 100
+#define SCPI_READ_RETRY_TIMEOUT 10000
+
+/**
+ * Parse a string representation of a boolean-like value into a gboolean.
+ * Similar to sr_parse_boolstring but rejects strings which do not represent
+ * a boolean-like value.
+ *
+ * @param str String to convert.
+ * @param ret Pointer to a gboolean where the result of the conversion will be
+ * stored.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+static int parse_strict_bool(const char *str, gboolean *ret)
+{
+	if (!str)
+		return SR_ERR_ARG;
+
+	if (!g_strcmp0(str, "1") ||
+	    !g_ascii_strncasecmp(str, "y", 1) ||
+	    !g_ascii_strncasecmp(str, "t", 1) ||
+	    !g_ascii_strncasecmp(str, "yes", 3) ||
+	    !g_ascii_strncasecmp(str, "true", 4) ||
+	    !g_ascii_strncasecmp(str, "on", 2)) {
+		*ret = TRUE;
+		return SR_OK;
+	} else if (!g_strcmp0(str, "0") ||
+		   !g_ascii_strncasecmp(str, "n", 1) ||
+		   !g_ascii_strncasecmp(str, "f", 1) ||
+		   !g_ascii_strncasecmp(str, "no", 2) ||
+		   !g_ascii_strncasecmp(str, "false", 5) ||
+		   !g_ascii_strncasecmp(str, "off", 3)) {
+		*ret = FALSE;
+		return SR_OK;
+	}
+
+	return SR_ERR;
+}
+
+SR_PRIV extern const struct sr_scpi_dev_inst scpi_serial_dev;
+SR_PRIV extern const struct sr_scpi_dev_inst scpi_tcp_raw_dev;
+SR_PRIV extern const struct sr_scpi_dev_inst scpi_tcp_rigol_dev;
+SR_PRIV extern const struct sr_scpi_dev_inst scpi_usbtmc_libusb_dev;
+SR_PRIV extern const struct sr_scpi_dev_inst scpi_vxi_dev;
+SR_PRIV extern const struct sr_scpi_dev_inst scpi_visa_dev;
+
+static const struct sr_scpi_dev_inst *scpi_devs[] = {
+	&scpi_tcp_raw_dev,
+	&scpi_tcp_rigol_dev,
+#ifdef HAVE_LIBUSB_1_0
+	&scpi_usbtmc_libusb_dev,
+#endif
+#if HAVE_RPC
+	&scpi_vxi_dev,
+#endif
+#ifdef HAVE_LIBREVISA
+	&scpi_visa_dev,
+#endif
+#ifdef HAVE_LIBSERIALPORT
+	&scpi_serial_dev,  /* must be last as it matches any resource */
+#endif
+};
+
+static GSList *sr_scpi_scan_resource(struct drv_context *drvc,
+		const char *resource, const char *serialcomm,
+		struct sr_dev_inst *(*probe_device)(struct sr_scpi_dev_inst *scpi))
+{
+	struct sr_scpi_dev_inst *scpi;
+	struct sr_dev_inst *sdi;
+
+	if (!(scpi = scpi_dev_inst_new(drvc, resource, serialcomm)))
+		return NULL;
+
+	if (sr_scpi_open(scpi) != SR_OK) {
+		sr_info("Couldn't open SCPI device.");
+		sr_scpi_free(scpi);
+		return NULL;
+	};
+
+	if ((sdi = probe_device(scpi)))
+		return g_slist_append(NULL, sdi);
+
+	sr_scpi_close(scpi);
+	sr_scpi_free(scpi);
+	return NULL;
+}
+
+SR_PRIV GSList *sr_scpi_scan(struct drv_context *drvc, GSList *options,
+		struct sr_dev_inst *(*probe_device)(struct sr_scpi_dev_inst *scpi))
+{
+	GSList *resources, *l, *d, *devices = NULL;
+	const char *resource = NULL;
+	const char *serialcomm = NULL;
+	gchar **res;
+	unsigned i;
+
+	for (l = options; l; l = l->next) {
+		struct sr_config *src = l->data;
+		switch (src->key) {
+		case SR_CONF_CONN:
+			resource = g_variant_get_string(src->data, NULL);
+			break;
+		case SR_CONF_SERIALCOMM:
+			serialcomm = g_variant_get_string(src->data, NULL);
+			break;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(scpi_devs); i++) {
+		if ((resource && strcmp(resource, scpi_devs[i]->prefix))
+		    || !scpi_devs[i]->scan)
+			continue;
+		resources = scpi_devs[i]->scan(drvc);
+		for (l = resources; l; l = l->next) {
+			res = g_strsplit(l->data, ":", 2);
+			if (res[0] && (d = sr_scpi_scan_resource(drvc, res[0],
+			               serialcomm ? serialcomm : res[1], probe_device)))
+				devices = g_slist_concat(devices, d);
+			g_strfreev(res);
+		}
+		g_slist_free_full(resources, g_free);
+	}
+
+	if (!devices && resource)
+		devices = sr_scpi_scan_resource(drvc, resource, serialcomm,
+		                                probe_device);
+
+	/* Tack a copy of the newly found devices onto the driver list. */
+	if (devices)
+		drvc->instances = g_slist_concat(drvc->instances,
+		                                 g_slist_copy(devices));
+
+	return devices;
+}
+
+SR_PRIV struct sr_scpi_dev_inst *scpi_dev_inst_new(struct drv_context *drvc,
+		const char *resource, const char *serialcomm)
+{
+	struct sr_scpi_dev_inst *scpi = NULL;
+	const struct sr_scpi_dev_inst *scpi_dev;
+	gchar **params;
+	unsigned i;
+
+	for (i = 0; i < ARRAY_SIZE(scpi_devs); i++) {
+		scpi_dev = scpi_devs[i];
+		if (!strncmp(resource, scpi_dev->prefix, strlen(scpi_dev->prefix))) {
+			sr_dbg("Opening %s device %s.", scpi_dev->name, resource);
+			scpi = g_malloc(sizeof(*scpi));
+			*scpi = *scpi_dev;
+			scpi->priv = g_malloc0(scpi->priv_size);
+			params = g_strsplit(resource, "/", 0);
+			if (scpi->dev_inst_new(scpi->priv, drvc, resource,
+			                       params, serialcomm) != SR_OK) {
+				sr_scpi_free(scpi);
+				scpi = NULL;
+			}
+			g_strfreev(params);
+			break;
+		}
+	}
+
+	return scpi;
+}
+
+/**
+ * Open SCPI device.
+ *
+ * @param scpi Previously initialized SCPI device structure.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+SR_PRIV int sr_scpi_open(struct sr_scpi_dev_inst *scpi)
+{
+	return scpi->open(scpi->priv);
+}
+
+/**
+ * Add an event source for an SCPI device.
+ *
+ * @param scpi Previously initialized SCPI device structure.
+ * @param events Events to check for.
+ * @param timeout Max time to wait before the callback is called, ignored if 0.
+ * @param cb Callback function to add. Must not be NULL.
+ * @param cb_data Data for the callback function. Can be NULL.
+ *
+ * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments, or
+ *         SR_ERR_MALLOC upon memory allocation errors.
+ */
+SR_PRIV int sr_scpi_source_add(struct sr_scpi_dev_inst *scpi, int events,
+		int timeout, sr_receive_data_callback cb, void *cb_data)
+{
+	return scpi->source_add(scpi->priv, events, timeout, cb, cb_data);
+}
+
+/**
+ * Remove event source for an SCPI device.
+ *
+ * @param scpi Previously initialized SCPI device structure.
+ *
+ * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments, or
+ *         SR_ERR_MALLOC upon memory allocation errors, SR_ERR_BUG upon
+ *         internal errors.
+ */
+SR_PRIV int sr_scpi_source_remove(struct sr_scpi_dev_inst *scpi)
+{
+	return scpi->source_remove(scpi->priv);
+}
+
+/**
+ * Send a SCPI command.
+ *
+ * @param scpi Previously initialized SCPI device structure.
+ * @param format Format string, to be followed by any necessary arguments.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+SR_PRIV int sr_scpi_send(struct sr_scpi_dev_inst *scpi,
+			 const char *format, ...)
+{
+	va_list args;
+	int ret;
+
+	va_start(args, format);
+	ret = sr_scpi_send_variadic(scpi, format, args);
+	va_end(args);
+
+	return ret;
+}
+
+/**
+ * Send a SCPI command with a variadic argument list.
+ *
+ * @param scpi Previously initialized SCPI device structure.
+ * @param format Format string.
+ * @param args Argument list.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+SR_PRIV int sr_scpi_send_variadic(struct sr_scpi_dev_inst *scpi,
+			 const char *format, va_list args)
+{
+	va_list args_copy;
+	char *buf;
+	int len, ret;
+
+	/* Get length of buffer required. */
+	va_copy(args_copy, args);
+	len = vsnprintf(NULL, 0, format, args_copy);
+	va_end(args_copy);
+
+	/* Allocate buffer and write out command. */
+	buf = g_malloc(len + 1);
+	vsprintf(buf, format, args);
+
+	/* Send command. */
+	ret = scpi->send(scpi->priv, buf);
+
+	/* Free command buffer. */
+	g_free(buf);
+
+	return ret;
+}
+
+/**
+ * Begin receiving an SCPI reply.
+ *
+ * @param scpi Previously initialised SCPI device structure.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+SR_PRIV int sr_scpi_read_begin(struct sr_scpi_dev_inst *scpi)
+{
+	return scpi->read_begin(scpi->priv);
+}
+
+/**
+ * Read part of a response from SCPI device.
+ *
+ * @param scpi Previously initialised SCPI device structure.
+ * @param buf Buffer to store result.
+ * @param maxlen Maximum number of bytes to read.
+ *
+ * @return Number of bytes read, or SR_ERR upon failure.
+ */
+SR_PRIV int sr_scpi_read_data(struct sr_scpi_dev_inst *scpi,
+			char *buf, int maxlen)
+{
+	return scpi->read_data(scpi->priv, buf, maxlen);
+}
+
+/**
+ * Check whether a complete SCPI response has been received.
+ *
+ * @param scpi Previously initialised SCPI device structure.
+ *
+ * @return 1 if complete, 0 otherwise.
+ */
+SR_PRIV int sr_scpi_read_complete(struct sr_scpi_dev_inst *scpi)
+{
+	return scpi->read_complete(scpi->priv);
+}
+
+/**
+ * Close SCPI device.
+ *
+ * @param scpi Previously initialized SCPI device structure.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+SR_PRIV int sr_scpi_close(struct sr_scpi_dev_inst *scpi)
+{
+	return scpi->close(scpi->priv);
+}
+
+/**
+ * Free SCPI device.
+ *
+ * @param scpi Previously initialized SCPI device structure.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+SR_PRIV void sr_scpi_free(struct sr_scpi_dev_inst *scpi)
+{
+	scpi->free(scpi->priv);
+	g_free(scpi->priv);
+	g_free(scpi);
+}
+
+/**
+ * Send a SCPI command, receive the reply and store the reply in scpi_response.
+ *
+ * @param scpi Previously initialised SCPI device structure.
+ * @param command The SCPI command to send to the device (can be NULL).
+ * @param scpi_response Pointer where to store the SCPI response.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+SR_PRIV int sr_scpi_get_string(struct sr_scpi_dev_inst *scpi,
+			       const char *command, char **scpi_response)
+{
+	char buf[256];
+	int len;
+	GString *response;
+
+	if (command)
+		if (sr_scpi_send(scpi, command) != SR_OK)
+			return SR_ERR;
+
+	if (sr_scpi_read_begin(scpi) != SR_OK)
+		return SR_ERR;
+
+	response = g_string_new("");
+
+	*scpi_response = NULL;
+
+	while (!sr_scpi_read_complete(scpi)) {
+		len = sr_scpi_read_data(scpi, buf, sizeof(buf));
+		if (len < 0) {
+			g_string_free(response, TRUE);
+			return SR_ERR;
+		}
+		g_string_append_len(response, buf, len);
+	}
+
+	/* Get rid of trailing linefeed if present */
+	if (response->len >= 1 && response->str[response->len - 1] == '\n')
+		g_string_truncate(response, response->len - 1);
+
+	*scpi_response = response->str;
+	g_string_free(response, FALSE);
+
+	sr_spew("Got response: '%.70s'.", *scpi_response);
+
+	return SR_OK;
+}
+
+/**
+ * Send a SCPI command, read the reply, parse it as a bool value and store the
+ * result in scpi_response.
+ *
+ * @param scpi Previously initialised SCPI device structure.
+ * @param command The SCPI command to send to the device (can be NULL).
+ * @param scpi_response Pointer where to store the parsed result.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+SR_PRIV int sr_scpi_get_bool(struct sr_scpi_dev_inst *scpi,
+			     const char *command, gboolean *scpi_response)
+{
+	int ret;
+	char *response;
+
+	response = NULL;
+
+	if (sr_scpi_get_string(scpi, command, &response) != SR_OK)
+		if (!response)
+			return SR_ERR;
+
+	if (parse_strict_bool(response, scpi_response) == SR_OK)
+		ret = SR_OK;
+	else
+		ret = SR_ERR;
+
+	g_free(response);
+
+	return ret;
+}
+
+/**
+ * Send a SCPI command, read the reply, parse it as an integer and store the
+ * result in scpi_response.
+ *
+ * @param scpi Previously initialised SCPI device structure.
+ * @param command The SCPI command to send to the device (can be NULL).
+ * @param scpi_response Pointer where to store the parsed result.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+SR_PRIV int sr_scpi_get_int(struct sr_scpi_dev_inst *scpi,
+			    const char *command, int *scpi_response)
+{
+	int ret;
+	char *response;
+
+	response = NULL;
+
+	if (sr_scpi_get_string(scpi, command, &response) != SR_OK)
+		if (!response)
+			return SR_ERR;
+
+	if (sr_atoi(response, scpi_response) == SR_OK)
+		ret = SR_OK;
+	else
+		ret = SR_ERR;
+
+	g_free(response);
+
+	return ret;
+}
+
+/**
+ * Send a SCPI command, read the reply, parse it as a float and store the
+ * result in scpi_response.
+ *
+ * @param scpi Previously initialised SCPI device structure.
+ * @param command The SCPI command to send to the device (can be NULL).
+ * @param scpi_response Pointer where to store the parsed result.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+SR_PRIV int sr_scpi_get_float(struct sr_scpi_dev_inst *scpi,
+			      const char *command, float *scpi_response)
+{
+	int ret;
+	char *response;
+
+	response = NULL;
+
+	if (sr_scpi_get_string(scpi, command, &response) != SR_OK)
+		if (!response)
+			return SR_ERR;
+
+	if (sr_atof_ascii(response, scpi_response) == SR_OK)
+		ret = SR_OK;
+	else
+		ret = SR_ERR;
+
+	g_free(response);
+
+	return ret;
+}
+
+/**
+ * Send a SCPI command, read the reply, parse it as a double and store the
+ * result in scpi_response.
+ *
+ * @param scpi Previously initialised SCPI device structure.
+ * @param command The SCPI command to send to the device (can be NULL).
+ * @param scpi_response Pointer where to store the parsed result.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+SR_PRIV int sr_scpi_get_double(struct sr_scpi_dev_inst *scpi,
+			       const char *command, double *scpi_response)
+{
+	int ret;
+	char *response;
+
+	response = NULL;
+
+	if (sr_scpi_get_string(scpi, command, &response) != SR_OK)
+		if (!response)
+			return SR_ERR;
+
+	if (sr_atod(response, scpi_response) == SR_OK)
+		ret = SR_OK;
+	else
+		ret = SR_ERR;
+
+	g_free(response);
+
+	return ret;
+}
+
+/**
+ * Send a SCPI *OPC? command, read the reply and return the result of the
+ * command.
+ *
+ * @param scpi Previously initialised SCPI device structure.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+SR_PRIV int sr_scpi_get_opc(struct sr_scpi_dev_inst *scpi)
+{
+	unsigned int i;
+	gboolean opc;
+
+	for (i = 0; i < SCPI_READ_RETRIES; ++i) {
+		sr_scpi_get_bool(scpi, SCPI_CMD_OPC, &opc);
+		if (opc)
+			return SR_OK;
+		g_usleep(SCPI_READ_RETRY_TIMEOUT);
+	}
+
+	return SR_ERR;
+}
+
+/**
+ * Send a SCPI command, read the reply, parse it as comma separated list of
+ * floats and store the as an result in scpi_response.
+ *
+ * @param scpi Previously initialised SCPI device structure.
+ * @param command The SCPI command to send to the device (can be NULL).
+ * @param scpi_response Pointer where to store the parsed result.
+ *
+ * @return SR_OK upon successfully parsing all values, SR_ERR upon a parsing
+ *         error or upon no response. The allocated response must be freed by
+ *         the caller in the case of an SR_OK as well as in the case of
+ *         parsing error.
+ */
+SR_PRIV int sr_scpi_get_floatv(struct sr_scpi_dev_inst *scpi,
+			       const char *command, GArray **scpi_response)
+{
+	int ret;
+	float tmp;
+	char *response;
+	gchar **ptr, **tokens;
+	GArray *response_array;
+
+	ret = SR_OK;
+	response = NULL;
+	tokens = NULL;
+
+	if (sr_scpi_get_string(scpi, command, &response) != SR_OK)
+		if (!response)
+			return SR_ERR;
+
+	tokens = g_strsplit(response, ",", 0);
+	ptr = tokens;
+
+	response_array = g_array_sized_new(TRUE, FALSE, sizeof(float), 256);
+
+	while (*ptr) {
+		if (sr_atof_ascii(*ptr, &tmp) == SR_OK)
+			response_array = g_array_append_val(response_array,
+							    tmp);
+		else
+			ret = SR_ERR;
+
+		ptr++;
+	}
+	g_strfreev(tokens);
+	g_free(response);
+
+	if (ret == SR_ERR && response_array->len == 0) {
+		g_array_free(response_array, TRUE);
+		*scpi_response = NULL;
+		return SR_ERR;
+	}
+
+	*scpi_response = response_array;
+
+	return ret;
+}
+
+/**
+ * Send a SCPI command, read the reply, parse it as comma separated list of
+ * unsigned 8 bit integers and store the as an result in scpi_response.
+ *
+ * @param scpi Previously initialised SCPI device structure.
+ * @param command The SCPI command to send to the device (can be NULL).
+ * @param scpi_response Pointer where to store the parsed result.
+ *
+ * @return SR_OK upon successfully parsing all values, SR_ERR upon a parsing
+ *         error or upon no response. The allocated response must be freed by
+ *         the caller in the case of an SR_OK as well as in the case of
+ *         parsing error.
+ */
+SR_PRIV int sr_scpi_get_uint8v(struct sr_scpi_dev_inst *scpi,
+			       const char *command, GArray **scpi_response)
+{
+	int tmp, ret;
+	char *response;
+	gchar **ptr, **tokens;
+	GArray *response_array;
+
+	ret = SR_OK;
+	response = NULL;
+	tokens = NULL;
+
+	if (sr_scpi_get_string(scpi, command, &response) != SR_OK)
+		if (!response)
+			return SR_ERR;
+
+	tokens = g_strsplit(response, ",", 0);
+	ptr = tokens;
+
+	response_array = g_array_sized_new(TRUE, FALSE, sizeof(uint8_t), 256);
+
+	while (*ptr) {
+		if (sr_atoi(*ptr, &tmp) == SR_OK)
+			response_array = g_array_append_val(response_array,
+							    tmp);
+		else
+			ret = SR_ERR;
+
+		ptr++;
+	}
+	g_strfreev(tokens);
+	g_free(response);
+
+	if (response_array->len == 0) {
+		g_array_free(response_array, TRUE);
+		*scpi_response = NULL;
+		return SR_ERR;
+	}
+
+	*scpi_response = response_array;
+
+	return ret;
+}
+
+/**
+ * Send the *IDN? SCPI command, receive the reply, parse it and store the
+ * reply as a sr_scpi_hw_info structure in the supplied scpi_response pointer.
+ *
+ * The hw_info structure must be freed by the caller via sr_scpi_hw_info_free().
+ *
+ * @param scpi Previously initialised SCPI device structure.
+ * @param scpi_response Pointer where to store the hw_info structure.
+ *
+ * @return SR_OK upon success, SR_ERR on failure.
+ */
+SR_PRIV int sr_scpi_get_hw_id(struct sr_scpi_dev_inst *scpi,
+			      struct sr_scpi_hw_info **scpi_response)
+{
+	int num_tokens;
+	char *response;
+	gchar **tokens;
+	struct sr_scpi_hw_info *hw_info;
+
+	response = NULL;
+	tokens = NULL;
+
+	if (sr_scpi_get_string(scpi, SCPI_CMD_IDN, &response) != SR_OK)
+		if (!response)
+			return SR_ERR;
+
+	sr_info("Got IDN string: '%s'", response);
+
+	/*
+	 * The response to a '*IDN?' is specified by the SCPI spec. It contains
+	 * a comma-separated list containing the manufacturer name, instrument
+	 * model, serial number of the instrument and the firmware version.
+	 */
+	tokens = g_strsplit(response, ",", 0);
+
+	for (num_tokens = 0; tokens[num_tokens] != NULL; num_tokens++);
+
+	if (num_tokens != 4) {
+		sr_dbg("IDN response not according to spec: %80.s.", response);
+		g_strfreev(tokens);
+		g_free(response);
+		return SR_ERR;
+	}
+	g_free(response);
+
+	hw_info = g_try_malloc(sizeof(struct sr_scpi_hw_info));
+	if (!hw_info) {
+		g_strfreev(tokens);
+		return SR_ERR_MALLOC;
+	}
+
+	hw_info->manufacturer = g_strdup(tokens[0]);
+	hw_info->model = g_strdup(tokens[1]);
+	hw_info->serial_number = g_strdup(tokens[2]);
+	hw_info->firmware_version = g_strdup(tokens[3]);
+
+	g_strfreev(tokens);
+
+	*scpi_response = hw_info;
+
+	return SR_OK;
+}
+
+/**
+ * Free a sr_scpi_hw_info struct.
+ *
+ * @param hw_info Pointer to the struct to free.
+ *
+ * This function is safe to call with a NULL pointer.
+ */
+SR_PRIV void sr_scpi_hw_info_free(struct sr_scpi_hw_info *hw_info)
+{
+	if (hw_info) {
+		g_free(hw_info->manufacturer);
+		g_free(hw_info->model);
+		g_free(hw_info->serial_number);
+		g_free(hw_info->firmware_version);
+		g_free(hw_info);
+	}
+}
diff --git a/hardware/common/scpi_serial.c b/hardware/common/scpi_serial.c
new file mode 100644
index 0000000..7000962
--- /dev/null
+++ b/hardware/common/scpi_serial.c
@@ -0,0 +1,240 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 poljar (Damir Jelić) <poljarinho at gmail.com>
+ * Copyright (C) 2013 Martin Ling <martin-sigrok at earth.li>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#include <glib.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LOG_PREFIX "scpi_serial"
+
+#define BUFFER_SIZE 1024
+
+struct scpi_serial {
+	struct sr_serial_dev_inst *serial;
+	char buffer[BUFFER_SIZE];
+	size_t count;
+	size_t read;
+};
+
+static struct {
+	uint16_t vendor_id;
+	uint16_t product_id;
+	const char *serialcomm;
+} scpi_serial_usb_ids[] = {
+	{ 0x0403, 0xed72, "115200/8n1/flow=1" }, /* Hameg HO720 */
+	{ 0x0403, 0xed73, "115200/8n1/flow=1" }, /* Hameg HO730 */
+};
+
+static GSList *scpi_serial_scan(struct drv_context *drvc)
+{
+	GSList *l, *r, *resources = NULL;
+	gchar *res;
+	unsigned i;
+
+	(void)drvc;
+
+	for (i = 0; i < ARRAY_SIZE(scpi_serial_usb_ids); i++) {
+		if ((l = sr_serial_find_usb(scpi_serial_usb_ids[i].vendor_id,
+		                            scpi_serial_usb_ids[i].product_id)) == NULL)
+			continue;
+		for (r = l; r; r = r->next) {
+			if (scpi_serial_usb_ids[i].serialcomm)
+				res = g_strdup_printf("%s:%s", (char *) r->data,
+				                      scpi_serial_usb_ids[i].serialcomm);
+			else
+				res = g_strdup(r->data);
+			resources = g_slist_append(resources, res);
+		}
+		g_slist_free_full(l, g_free);
+	}
+
+	return resources;
+}
+
+static int scpi_serial_dev_inst_new(void *priv, struct drv_context *drvc,
+		const char *resource, char **params, const char *serialcomm)
+{
+	struct scpi_serial *sscpi = priv;
+
+	(void)drvc;
+	(void)params;
+
+	if (!(sscpi->serial = sr_serial_dev_inst_new(resource, serialcomm)))
+		return SR_ERR;
+
+	return SR_OK;
+}
+
+static int scpi_serial_open(void *priv)
+{
+	struct scpi_serial *sscpi = priv;
+	struct sr_serial_dev_inst *serial = sscpi->serial;
+
+	if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+		return SR_ERR;
+
+	if (serial_flush(serial) != SR_OK)
+		return SR_ERR;
+
+	sscpi->count = 0;
+	sscpi->read = 0;
+
+	return SR_OK;
+}
+
+static int scpi_serial_source_add(void *priv, int events, int timeout,
+			sr_receive_data_callback cb, void *cb_data)
+{
+	struct scpi_serial *sscpi = priv;
+	struct sr_serial_dev_inst *serial = sscpi->serial;
+
+	return serial_source_add(serial, events, timeout, cb, cb_data);
+}
+
+static int scpi_serial_source_remove(void *priv)
+{
+	struct scpi_serial *sscpi = priv;
+	struct sr_serial_dev_inst *serial = sscpi->serial;
+
+	return serial_source_remove(serial);
+}
+
+static int scpi_serial_send(void *priv, const char *command)
+{
+	int len, result, written;
+	gchar *terminated_command;
+	struct scpi_serial *sscpi = priv;
+	struct sr_serial_dev_inst *serial = sscpi->serial;
+
+	terminated_command = g_strconcat(command, "\n", NULL);
+	len = strlen(terminated_command);
+	written = 0;
+	while (written < len) {
+		result = serial_write(serial, terminated_command + written, len - written);
+		if (result < 0) {
+			sr_err("Error while sending SCPI command: '%s'.", command);
+			g_free(terminated_command);
+			return SR_ERR;
+		}
+		written += result;
+	}
+
+	g_free(terminated_command);
+
+	sr_spew("Successfully sent SCPI command: '%s'.", command);
+
+	return SR_OK;
+}
+
+static int scpi_serial_read_begin(void *priv)
+{
+	(void) priv;
+
+	return SR_OK;
+}
+
+static int scpi_serial_read_data(void *priv, char *buf, int maxlen)
+{
+	struct scpi_serial *sscpi = priv;
+	int len, ret;
+
+	len = BUFFER_SIZE - sscpi->count;
+
+	/* Try to read new data into the buffer if there is space. */
+	if (len > 0) {
+		ret = serial_read(sscpi->serial, sscpi->buffer + sscpi->read,
+				BUFFER_SIZE - sscpi->count);
+
+		if (ret < 0)
+			return ret;
+
+		sscpi->count += ret;
+
+		if (ret > 0)
+			sr_spew("Read %d bytes into buffer.", ret);
+	}
+
+	/* Return as many bytes as possible from buffer, excluding any trailing newline. */
+	if (sscpi->read < sscpi->count) {
+		len = sscpi->count - sscpi->read;
+		if (len > maxlen)
+			len = maxlen;
+		if (sscpi->buffer[sscpi->read + len - 1] == '\n')
+			len--;
+		sr_spew("Returning %d bytes from buffer.", len);
+		memcpy(buf, sscpi->buffer + sscpi->read, len);
+		sscpi->read += len;
+		if (sscpi->read == BUFFER_SIZE) {
+			sr_spew("Resetting buffer.");
+			sscpi->count = 0;
+			sscpi->read = 0;
+		}
+		return len;
+	}
+
+	return 0;
+}
+
+static int scpi_serial_read_complete(void *priv)
+{
+	struct scpi_serial *sscpi = priv;
+
+	/* If the next character is a newline, discard it and report complete. */
+	if (sscpi->read < sscpi->count && sscpi->buffer[sscpi->read] == '\n') {
+		sscpi->read++;
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+static int scpi_serial_close(void *priv)
+{
+	struct scpi_serial *sscpi = priv;
+
+	return serial_close(sscpi->serial);
+}
+
+static void scpi_serial_free(void *priv)
+{
+	struct scpi_serial *sscpi = priv;
+
+	sr_serial_dev_inst_free(sscpi->serial);
+}
+
+SR_PRIV const struct sr_scpi_dev_inst scpi_serial_dev = {
+	.name          = "serial",
+	.prefix        = "",
+	.priv_size     = sizeof(struct scpi_serial),
+	.scan          = scpi_serial_scan,
+	.dev_inst_new  = scpi_serial_dev_inst_new,
+	.open          = scpi_serial_open,
+	.source_add    = scpi_serial_source_add,
+	.source_remove = scpi_serial_source_remove,
+	.send          = scpi_serial_send,
+	.read_begin    = scpi_serial_read_begin,
+	.read_data     = scpi_serial_read_data,
+	.read_complete = scpi_serial_read_complete,
+	.close         = scpi_serial_close,
+	.free          = scpi_serial_free,
+};
diff --git a/hardware/common/scpi_tcp.c b/hardware/common/scpi_tcp.c
new file mode 100644
index 0000000..8ac2200
--- /dev/null
+++ b/hardware/common/scpi_tcp.c
@@ -0,0 +1,280 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Martin Ling <martin-sigrok at earth.li>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef _WIN32
+#define _WIN32_WINNT 0x0501
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#include <glib.h>
+#include <string.h>
+#include <unistd.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#endif
+#include <errno.h>
+
+#define LOG_PREFIX "scpi_tcp"
+
+#define LENGTH_BYTES 4
+
+struct scpi_tcp {
+	char *address;
+	char *port;
+	int socket;
+	char length_buf[LENGTH_BYTES];
+	int length_bytes_read;
+	int response_length;
+	int response_bytes_read;
+};
+
+static int scpi_tcp_dev_inst_new(void *priv, struct drv_context *drvc,
+		const char *resource, char **params, const char *serialcomm)
+{
+	struct scpi_tcp *tcp = priv;
+
+	(void)drvc;
+	(void)resource;
+	(void)serialcomm;
+
+	if (!params || !params[1] || !params[2]) {
+		sr_err("Invalid parameters.");
+		return SR_ERR;
+	}
+
+	tcp->address = g_strdup(params[1]);
+	tcp->port    = g_strdup(params[2]);
+	tcp->socket  = -1;
+
+	return SR_OK;
+}
+
+static int scpi_tcp_open(void *priv)
+{
+	struct scpi_tcp *tcp = priv;
+	struct addrinfo hints;
+	struct addrinfo *results, *res;
+	int err;
+
+	memset(&hints, 0, sizeof(hints));
+	hints.ai_family = AF_UNSPEC;
+	hints.ai_socktype = SOCK_STREAM;
+	hints.ai_protocol = IPPROTO_TCP;
+
+	err = getaddrinfo(tcp->address, tcp->port, &hints, &results);
+
+	if (err) {
+		sr_err("Address lookup failed: %s:%d: %s", tcp->address, tcp->port,
+			gai_strerror(err));
+		return SR_ERR;
+	}
+
+	for (res = results; res; res = res->ai_next) {
+		if ((tcp->socket = socket(res->ai_family, res->ai_socktype,
+						res->ai_protocol)) < 0)
+			continue;
+		if (connect(tcp->socket, res->ai_addr, res->ai_addrlen) != 0) {
+			close(tcp->socket);
+			tcp->socket = -1;
+			continue;
+		}
+		break;
+	}
+
+	freeaddrinfo(results);
+
+	if (tcp->socket < 0) {
+		sr_err("Failed to connect to %s:%s: %s", tcp->address, tcp->port,
+				strerror(errno));
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+static int scpi_tcp_source_add(void *priv, int events, int timeout,
+			sr_receive_data_callback cb, void *cb_data)
+{
+	struct scpi_tcp *tcp = priv;
+
+	return sr_source_add(tcp->socket, events, timeout, cb, cb_data);
+}
+
+static int scpi_tcp_source_remove(void *priv)
+{
+	struct scpi_tcp *tcp = priv;
+
+	return sr_source_remove(tcp->socket);
+}
+
+static int scpi_tcp_send(void *priv, const char *command)
+{
+	struct scpi_tcp *tcp = priv;
+	int len, out;
+	char *terminated_command;
+
+	terminated_command = g_strdup_printf("%s\r\n", command);
+	len = strlen(terminated_command);
+	out = send(tcp->socket, terminated_command, len, 0);
+	g_free(terminated_command);
+
+	if (out < 0) {
+		sr_err("Send error: %s", strerror(errno));
+		return SR_ERR;
+	}
+
+	if (out < len) {
+		sr_dbg("Only sent %d/%d bytes of SCPI command: '%s'.", out,
+		       len, command);
+	}
+
+	sr_spew("Successfully sent SCPI command: '%s'.", command);
+
+	return SR_OK;
+}
+
+static int scpi_tcp_read_begin(void *priv)
+{
+	struct scpi_tcp *tcp = priv;
+
+	tcp->response_bytes_read = 0;
+	tcp->length_bytes_read = 0;
+
+	return SR_OK;
+}
+
+static int scpi_tcp_raw_read_data(void *priv, char *buf, int maxlen)
+{
+	struct scpi_tcp *tcp = priv;
+	int len;
+
+	len = recv(tcp->socket, buf, maxlen, 0);
+
+	if (len < 0) {
+		sr_err("Receive error: %s", strerror(errno));
+		return SR_ERR;
+	}
+
+	tcp->length_bytes_read = LENGTH_BYTES;
+	tcp->response_length = len < maxlen ? len : maxlen + 1;
+	tcp->response_bytes_read = len;
+
+	return len;
+}
+
+static int scpi_tcp_rigol_read_data(void *priv, char *buf, int maxlen)
+{
+	struct scpi_tcp *tcp = priv;
+	int len;
+
+	if (tcp->length_bytes_read < LENGTH_BYTES) {
+		len = recv(tcp->socket, tcp->length_buf + tcp->length_bytes_read,
+				LENGTH_BYTES - tcp->length_bytes_read, 0);
+		if (len < 0) {
+			sr_err("Receive error: %s", strerror(errno));
+			return SR_ERR;
+		}
+
+		tcp->length_bytes_read += len;
+
+		if (tcp->length_bytes_read < LENGTH_BYTES)
+			return 0;
+		else
+			tcp->response_length = RL32(tcp->length_buf);
+	}
+
+	if (tcp->response_bytes_read >= tcp->response_length)
+		return SR_ERR;
+
+	len = recv(tcp->socket, buf, maxlen, 0);
+
+	if (len < 0) {
+		sr_err("Receive error: %s", strerror(errno));
+		return SR_ERR;
+	}
+
+	tcp->response_bytes_read += len;
+
+	return len;
+}
+
+static int scpi_tcp_read_complete(void *priv)
+{
+	struct scpi_tcp *tcp = priv;
+
+	return (tcp->length_bytes_read == LENGTH_BYTES &&
+			tcp->response_bytes_read >= tcp->response_length);
+}
+
+static int scpi_tcp_close(void *priv)
+{
+	struct scpi_tcp *tcp = priv;
+
+	if (close(tcp->socket) < 0)
+		return SR_ERR;
+
+	return SR_OK;
+}
+
+static void scpi_tcp_free(void *priv)
+{
+	struct scpi_tcp *tcp = priv;
+
+	g_free(tcp->address);
+	g_free(tcp->port);
+}
+
+SR_PRIV const struct sr_scpi_dev_inst scpi_tcp_raw_dev = {
+	.name          = "RAW TCP",
+	.prefix        = "tcp-raw",
+	.priv_size     = sizeof(struct scpi_tcp),
+	.dev_inst_new  = scpi_tcp_dev_inst_new,
+	.open          = scpi_tcp_open,
+	.source_add    = scpi_tcp_source_add,
+	.source_remove = scpi_tcp_source_remove,
+	.send          = scpi_tcp_send,
+	.read_begin    = scpi_tcp_read_begin,
+	.read_data     = scpi_tcp_raw_read_data,
+	.read_complete = scpi_tcp_read_complete,
+	.close         = scpi_tcp_close,
+	.free          = scpi_tcp_free,
+};
+
+SR_PRIV const struct sr_scpi_dev_inst scpi_tcp_rigol_dev = {
+	.name          = "RIGOL TCP",
+	.prefix        = "tcp-rigol",
+	.priv_size     = sizeof(struct scpi_tcp),
+	.dev_inst_new  = scpi_tcp_dev_inst_new,
+	.open          = scpi_tcp_open,
+	.source_add    = scpi_tcp_source_add,
+	.source_remove = scpi_tcp_source_remove,
+	.send          = scpi_tcp_send,
+	.read_begin    = scpi_tcp_read_begin,
+	.read_data     = scpi_tcp_rigol_read_data,
+	.read_complete = scpi_tcp_read_complete,
+	.close         = scpi_tcp_close,
+	.free          = scpi_tcp_free,
+};
diff --git a/hardware/common/scpi_usbtmc_libusb.c b/hardware/common/scpi_usbtmc_libusb.c
new file mode 100644
index 0000000..653a0d8
--- /dev/null
+++ b/hardware/common/scpi_usbtmc_libusb.c
@@ -0,0 +1,583 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Aurelien Jacobs <aurel at gnuage.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "scpi_usbtmc"
+
+#define MAX_TRANSFER_LENGTH 2048
+#define TRANSFER_TIMEOUT 1000
+
+struct scpi_usbtmc_libusb {
+	struct sr_context *ctx;
+	struct sr_usb_dev_inst *usb;
+	int detached_kernel_driver;
+	uint8_t interface;
+	uint8_t bulk_in_ep;
+	uint8_t bulk_out_ep;
+	uint8_t interrupt_ep;
+	uint8_t usbtmc_int_cap;
+	uint8_t usbtmc_dev_cap;
+	uint8_t usb488_dev_cap;
+	uint8_t bTag;
+	uint8_t bulkin_attributes;
+	uint8_t buffer[MAX_TRANSFER_LENGTH];
+	int response_length;
+	int response_bytes_read;
+	int remaining_length;
+	int rigol_ds1000;
+};
+
+/* Some USBTMC-specific enums, as defined in the USBTMC standard. */
+#define SUBCLASS_USBTMC  0x03
+#define USBTMC_USB488    0x01
+
+enum {
+	/* USBTMC control requests */
+	INITIATE_ABORT_BULK_OUT     =   1,
+	CHECK_ABORT_BULK_OUT_STATUS =   2,
+	INITIATE_ABORT_BULK_IN      =   3,
+	CHECK_ABORT_BULK_IN_STATUS  =   4,
+	INITIATE_CLEAR              =   5,
+	CHECK_CLEAR_STATUS          =   6,
+	GET_CAPABILITIES            =   7,
+	INDICATOR_PULSE             =  64,
+
+	/* USB488 control requests */
+	READ_STATUS_BYTE            = 128,
+	REN_CONTROL                 = 160,
+	GO_TO_LOCAL                 = 161,
+	LOCAL_LOCKOUT               = 162,
+};
+
+/* USBTMC capabilities */
+#define USBTMC_INT_CAP_LISTEN_ONLY 0x01
+#define USBTMC_INT_CAP_TALK_ONLY   0x02
+#define USBTMC_INT_CAP_INDICATOR   0x04
+
+#define USBTMC_DEV_CAP_TERMCHAR    0x01
+
+#define USB488_DEV_CAP_DT1         0x01
+#define USB488_DEV_CAP_RL1         0x02
+#define USB488_DEV_CAP_SR1         0x04
+#define USB488_DEV_CAP_SCPI        0x08
+
+/* Bulk messages constants */
+#define USBTMC_BULK_HEADER_SIZE  12
+
+/* Bulk MsgID values */
+#define DEV_DEP_MSG_OUT         1
+#define REQUEST_DEV_DEP_MSG_IN  2
+#define DEV_DEP_MSG_IN          2
+
+/* bmTransferAttributes */
+#define EOM                0x01
+#define TERM_CHAR_ENABLED  0x02
+
+
+static GSList *scpi_usbtmc_libusb_scan(struct drv_context *drvc)
+{
+	struct libusb_device **devlist;
+	struct libusb_device_descriptor des;
+	struct libusb_config_descriptor *confdes;
+	const struct libusb_interface_descriptor *intfdes;
+	GSList *resources = NULL;
+	int confidx, intfidx, ret, i;
+	char *res;
+
+	ret = libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
+	if (ret < 0) {
+		sr_err("Failed to get device list: %s.",
+		       libusb_error_name(ret));
+		return NULL;
+	}
+	for (i = 0; devlist[i]; i++) {
+		if ((ret = libusb_get_device_descriptor(devlist[i], &des)) < 0) {
+			sr_err("Failed to get device descriptor: %s.",
+			       libusb_error_name(ret));
+			continue;
+		}
+
+		for (confidx = 0; confidx < des.bNumConfigurations; confidx++) {
+			if ((ret = libusb_get_config_descriptor(devlist[i], confidx, &confdes)) < 0) {
+				sr_dbg("Failed to get configuration descriptor: %s, "
+				       "ignoring device.", libusb_error_name(ret));
+				break;
+			}
+			for (intfidx = 0; intfidx < confdes->bNumInterfaces; intfidx++) {
+				intfdes = confdes->interface[intfidx].altsetting;
+				if (intfdes->bInterfaceClass    != LIBUSB_CLASS_APPLICATION ||
+				    intfdes->bInterfaceSubClass != SUBCLASS_USBTMC          ||
+				    intfdes->bInterfaceProtocol != USBTMC_USB488)
+					continue;
+				sr_dbg("Found USBTMC device (VID:PID = %04x:%04x, "
+				       "bus.address = %d.%d).", des.idVendor, des.idProduct,
+				       libusb_get_bus_number(devlist[i]),
+				       libusb_get_device_address(devlist[i]));
+				res = g_strdup_printf("usbtmc/%d.%d",
+				                      libusb_get_bus_number(devlist[i]),
+				                      libusb_get_device_address(devlist[i]));
+				resources = g_slist_append(resources, res);
+			}
+			libusb_free_config_descriptor(confdes);
+		}
+	}
+	libusb_free_device_list(devlist, 1);
+
+	sr_dbg("Found %d device(s).", g_slist_length(resources));
+
+	return resources;
+}
+
+static int scpi_usbtmc_libusb_dev_inst_new(void *priv, struct drv_context *drvc,
+		const char *resource, char **params, const char *serialcomm)
+{
+	struct scpi_usbtmc_libusb *uscpi = priv;
+	GSList *devices;
+
+	(void)resource;
+	(void)serialcomm;
+
+	if (!params || !params[1]) {
+		sr_err("Invalid parameters.");
+		return SR_ERR;
+	}
+
+	uscpi->ctx = drvc->sr_ctx;
+	devices = sr_usb_find(uscpi->ctx->libusb_ctx, params[1]);
+	if (g_slist_length(devices) != 1) {
+		sr_err("Failed to find USB device '%s'.", params[1]);
+		g_slist_free_full(devices, (GDestroyNotify)sr_usb_dev_inst_free);
+		return SR_ERR;
+	}
+	uscpi->usb = devices->data;
+	g_slist_free(devices);
+
+	return SR_OK;
+}
+
+static int scpi_usbtmc_libusb_open(void *priv)
+{
+	struct scpi_usbtmc_libusb *uscpi = priv;
+	struct sr_usb_dev_inst *usb = uscpi->usb;
+	struct libusb_device *dev;
+	struct libusb_device_descriptor des;
+	struct libusb_config_descriptor *confdes;
+	const struct libusb_interface_descriptor *intfdes;
+	const struct libusb_endpoint_descriptor *ep;
+	int confidx, intfidx, epidx, config = 0;
+	uint8_t capabilities[24];
+	int ret, found = 0;
+
+	if (usb->devhdl)
+		return SR_OK;
+
+	if (sr_usb_open(uscpi->ctx->libusb_ctx, usb) != SR_OK)
+		return SR_ERR;
+
+	dev = libusb_get_device(usb->devhdl);
+	if ((ret = libusb_get_device_descriptor(dev, &des)) < 0) {
+		sr_err("Failed to get device descriptor: %s.",
+		       libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	for (confidx = 0; confidx < des.bNumConfigurations; confidx++) {
+		if ((ret = libusb_get_config_descriptor(dev, confidx, &confdes)) < 0) {
+			sr_dbg("Failed to get configuration descriptor: %s, "
+			       "ignoring device.", libusb_error_name(ret));
+			continue;
+		}
+		for (intfidx = 0; intfidx < confdes->bNumInterfaces; intfidx++) {
+			intfdes = confdes->interface[intfidx].altsetting;
+			if (intfdes->bInterfaceClass    != LIBUSB_CLASS_APPLICATION ||
+			    intfdes->bInterfaceSubClass != SUBCLASS_USBTMC          ||
+			    intfdes->bInterfaceProtocol != USBTMC_USB488)
+				continue;
+			uscpi->interface = intfdes->bInterfaceNumber;
+			sr_dbg("Interface %d", uscpi->interface);
+			config = confdes->bConfigurationValue;
+			sr_dbg("Configuration %d", config);
+			for (epidx = 0; epidx < intfdes->bNumEndpoints; epidx++) {
+				ep = &intfdes->endpoint[epidx];
+				if (ep->bmAttributes == LIBUSB_TRANSFER_TYPE_BULK &&
+				    !(ep->bEndpointAddress & (LIBUSB_ENDPOINT_DIR_MASK))) {
+					uscpi->bulk_out_ep = ep->bEndpointAddress;
+					sr_dbg("Bulk OUT EP %d", uscpi->bulk_out_ep);
+				}
+				if (ep->bmAttributes == LIBUSB_TRANSFER_TYPE_BULK &&
+				    ep->bEndpointAddress & (LIBUSB_ENDPOINT_DIR_MASK)) {
+					uscpi->bulk_in_ep = ep->bEndpointAddress;
+					sr_dbg("Bulk IN EP %d", uscpi->bulk_in_ep);
+				}
+				if (ep->bmAttributes == LIBUSB_TRANSFER_TYPE_INTERRUPT &&
+				    ep->bEndpointAddress & (LIBUSB_ENDPOINT_DIR_MASK)) {
+					uscpi->interrupt_ep = ep->bEndpointAddress;
+					sr_dbg("Interrupt EP %d", uscpi->interrupt_ep);
+				}
+			}
+			found = 1;
+			uscpi->rigol_ds1000 = des.idVendor  == 0x1ab1 &&
+			                      des.idProduct == 0x0588;
+		}
+		libusb_free_config_descriptor(confdes);
+		if (found)
+			break;
+	}
+
+	if (!found) {
+		sr_err("Failed to find USBTMC interface.");
+		return SR_ERR;
+	}
+
+	if (libusb_kernel_driver_active(usb->devhdl, uscpi->interface) == 1) {
+		if ((ret = libusb_detach_kernel_driver(usb->devhdl,
+		                                       uscpi->interface)) < 0) {
+			sr_err("Failed to detach kernel driver: %s.",
+			       libusb_error_name(ret));
+			return SR_ERR;
+		}
+		uscpi->detached_kernel_driver = 1;
+	}
+
+	if ((ret = libusb_set_configuration(usb->devhdl, config)) < 0) {
+		sr_err("Failed to set configuration: %s.",
+		       libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	if ((ret = libusb_claim_interface(usb->devhdl, uscpi->interface)) < 0) {
+		sr_err("Failed to claim interface: %s.",
+		       libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	if (!uscpi->rigol_ds1000) {
+	if ((ret = libusb_clear_halt(usb->devhdl, uscpi->bulk_in_ep)) < 0) {
+		sr_err("Failed to clear halt/stall condition for EP %d: %s.",
+		       uscpi->bulk_in_ep, libusb_error_name(ret));
+		return SR_ERR;
+	}
+	if ((ret = libusb_clear_halt(usb->devhdl, uscpi->bulk_out_ep)) < 0) {
+		sr_err("Failed to clear halt/stall condition for EP %d: %s.",
+		       uscpi->bulk_out_ep, libusb_error_name(ret));
+		return SR_ERR;
+	}
+	if ((ret = libusb_clear_halt(usb->devhdl, uscpi->interrupt_ep)) < 0) {
+		sr_err("Failed to clear halt/stall condition for EP %d: %s.",
+		       uscpi->interrupt_ep, libusb_error_name(ret));
+		return SR_ERR;
+	}
+	}
+
+	/* Get capabilities. */
+	ret = libusb_control_transfer(usb->devhdl,
+	                              LIBUSB_ENDPOINT_IN         |
+	                              LIBUSB_REQUEST_TYPE_CLASS  |
+	                              LIBUSB_RECIPIENT_INTERFACE,
+	                              GET_CAPABILITIES, 0,
+	                              uscpi->interface,
+	                              capabilities, sizeof(capabilities),
+	                              TRANSFER_TIMEOUT);
+	if (ret == sizeof(capabilities)) {
+		uscpi->usbtmc_int_cap = capabilities[ 4];
+		uscpi->usbtmc_dev_cap = capabilities[ 5];
+		uscpi->usb488_dev_cap = capabilities[15];
+	}
+	sr_dbg("Device capabilities: %s%s%s%s%s, %s, %s",
+	       uscpi->usb488_dev_cap & USB488_DEV_CAP_SCPI       ? "SCPI, "    : "",
+	       uscpi->usbtmc_dev_cap & USBTMC_DEV_CAP_TERMCHAR   ? "TermChar, ": "",
+	       uscpi->usbtmc_int_cap & USBTMC_INT_CAP_LISTEN_ONLY? "L3, " :
+	       uscpi->usbtmc_int_cap & USBTMC_INT_CAP_TALK_ONLY  ? ""     : "L4, ",
+	       uscpi->usbtmc_int_cap & USBTMC_INT_CAP_TALK_ONLY  ? "T5, " :
+	       uscpi->usbtmc_int_cap & USBTMC_INT_CAP_LISTEN_ONLY? ""     : "T6, ",
+	       uscpi->usb488_dev_cap & USB488_DEV_CAP_SR1        ? "SR1"  : "SR0",
+	       uscpi->usb488_dev_cap & USB488_DEV_CAP_RL1        ? "RL1"  : "RL0",
+	       uscpi->usb488_dev_cap & USB488_DEV_CAP_DT1        ? "DT1"  : "DT0");
+
+	return SR_OK;
+}
+
+static int scpi_usbtmc_libusb_source_add(void *priv, int events, int timeout,
+			sr_receive_data_callback cb, void *cb_data)
+{
+	struct scpi_usbtmc_libusb *uscpi = priv;
+	(void)events;
+	return usb_source_add(uscpi->ctx, timeout, cb, cb_data);
+}
+
+static int scpi_usbtmc_libusb_source_remove(void *priv)
+{
+	struct scpi_usbtmc_libusb *uscpi = priv;
+	return usb_source_remove(uscpi->ctx);
+}
+
+static void usbtmc_bulk_out_header_write(void *header, uint8_t MsgID,
+                                         uint8_t bTag,
+                                         uint32_t TransferSize,
+                                         uint8_t bmTransferAttributes,
+                                         char TermChar)
+{
+	  W8(header+ 0, MsgID);
+	  W8(header+ 1, bTag);
+	  W8(header+ 2, ~bTag);
+	  W8(header+ 3, 0);
+	WL32(header+ 4, TransferSize);
+	  W8(header+ 8, bmTransferAttributes);
+	  W8(header+ 9, TermChar);
+	WL16(header+10, 0);
+}
+
+static int usbtmc_bulk_in_header_read(void *header, uint8_t MsgID,
+                                      unsigned char bTag,
+                                      int32_t *TransferSize,
+                                      uint8_t *bmTransferAttributes)
+{
+	if (R8(header+0) != MsgID ||
+	    R8(header+1) != bTag  ||
+	    R8(header+2) != (unsigned char)~bTag)
+		return SR_ERR;
+	if (TransferSize)
+		*TransferSize = RL32(header+4);
+	if (bmTransferAttributes)
+		*bmTransferAttributes = R8(header+8);
+	return SR_OK;
+}
+
+static int scpi_usbtmc_bulkout(struct scpi_usbtmc_libusb *uscpi,
+                               uint8_t msg_id, const void *data, int32_t size,
+                               uint8_t transfer_attributes)
+{
+	struct sr_usb_dev_inst *usb = uscpi->usb;
+	int padded_size, ret, transferred;
+
+	if (data && size+USBTMC_BULK_HEADER_SIZE+3 > (int)sizeof(uscpi->buffer)) {
+		sr_err("USBTMC bulk out transfer is too big.");
+		return SR_ERR;
+	}
+
+	uscpi->bTag++;
+	uscpi->bTag += !uscpi->bTag;  /* bTag == 0 is invalid so avoid it. */
+
+	usbtmc_bulk_out_header_write(uscpi->buffer, msg_id, uscpi->bTag,
+	                             size, transfer_attributes, 0);
+	if (data)
+		memcpy(uscpi->buffer+USBTMC_BULK_HEADER_SIZE, data, size);
+	else
+		size = 0;
+	size += USBTMC_BULK_HEADER_SIZE;
+	padded_size = (size + 3) & ~0x3;
+	memset(uscpi->buffer+size, 0, padded_size - size);
+
+	ret = libusb_bulk_transfer(usb->devhdl, uscpi->bulk_out_ep,
+	                           uscpi->buffer, padded_size, &transferred,
+	                           TRANSFER_TIMEOUT);
+	if (ret < 0) {
+		sr_err("USBTMC bulk out transfer error: %s.",
+		       libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	if (transferred < padded_size) {
+		sr_dbg("USBTMC bulk out partial transfer (%d/%d bytes).",
+		       transferred, padded_size);
+		return SR_ERR;
+	}
+
+	return transferred - USBTMC_BULK_HEADER_SIZE;
+}
+
+static int scpi_usbtmc_bulkin_start(struct scpi_usbtmc_libusb *uscpi,
+                                    uint8_t msg_id, void *data, int32_t size,
+                                    uint8_t *transfer_attributes)
+{
+	struct sr_usb_dev_inst *usb = uscpi->usb;
+	int ret, transferred, message_size;
+
+	ret = libusb_bulk_transfer(usb->devhdl, uscpi->bulk_in_ep, data, size,
+	                           &transferred, TRANSFER_TIMEOUT);
+	if (ret < 0) {
+		sr_err("USBTMC bulk in transfer error: %s.",
+		       libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	if (usbtmc_bulk_in_header_read(data, msg_id, uscpi->bTag, &message_size,
+	                               transfer_attributes) != SR_OK) {
+		sr_err("USBTMC invalid bulk in header.");
+		return SR_ERR;
+	}
+
+	message_size += USBTMC_BULK_HEADER_SIZE;
+	uscpi->response_length = MIN(transferred, message_size);
+	uscpi->response_bytes_read = USBTMC_BULK_HEADER_SIZE;
+	uscpi->remaining_length = message_size - uscpi->response_length;
+
+	return transferred - USBTMC_BULK_HEADER_SIZE;
+}
+
+static int scpi_usbtmc_bulkin_continue(struct scpi_usbtmc_libusb *uscpi,
+                                       void *data, int size)
+{
+	struct sr_usb_dev_inst *usb = uscpi->usb;
+	int ret, transferred;
+
+	ret = libusb_bulk_transfer(usb->devhdl, uscpi->bulk_in_ep, data, size,
+	                           &transferred, TRANSFER_TIMEOUT);
+	if (ret < 0) {
+		sr_err("USBTMC bulk in transfer error: %s.",
+		       libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	uscpi->response_length = MIN(transferred, uscpi->remaining_length);
+	uscpi->response_bytes_read = 0;
+	uscpi->remaining_length -= uscpi->response_length;
+
+	return transferred;
+}
+
+static int scpi_usbtmc_libusb_send(void *priv, const char *command)
+{
+	struct scpi_usbtmc_libusb *uscpi = priv;
+
+	if (scpi_usbtmc_bulkout(uscpi, DEV_DEP_MSG_OUT,
+	                        command, strlen(command), EOM) <= 0)
+		return SR_ERR;
+
+	sr_spew("Successfully sent SCPI command: '%s'.", command);
+
+	return SR_OK;
+}
+
+static int scpi_usbtmc_libusb_read_begin(void *priv)
+{
+	struct scpi_usbtmc_libusb *uscpi = priv;
+
+	uscpi->remaining_length = 0;
+
+	if (scpi_usbtmc_bulkout(uscpi, REQUEST_DEV_DEP_MSG_IN,
+	    NULL, INT32_MAX, 0) < 0)
+		return SR_ERR;
+	if (scpi_usbtmc_bulkin_start(uscpi, DEV_DEP_MSG_IN,
+	                             uscpi->buffer, sizeof(uscpi->buffer),
+	                             &uscpi->bulkin_attributes) < 0)
+		return SR_ERR;
+
+	return SR_OK;
+}
+
+static int scpi_usbtmc_libusb_read_data(void *priv, char *buf, int maxlen)
+{
+	struct scpi_usbtmc_libusb *uscpi = priv;
+	int read_length;
+
+	if (uscpi->response_bytes_read >= uscpi->response_length) {
+		if (uscpi->remaining_length > 0) {
+			if (scpi_usbtmc_bulkin_continue(uscpi, uscpi->buffer,
+			                                sizeof(uscpi->buffer)) <= 0)
+				return SR_ERR;
+		} else {
+			if (uscpi->bulkin_attributes & EOM)
+				return SR_ERR;
+			if (scpi_usbtmc_libusb_read_begin(uscpi) < 0)
+				return SR_ERR;
+		}
+	}
+
+	read_length = MIN(uscpi->response_length - uscpi->response_bytes_read, maxlen);
+
+	memcpy(buf, uscpi->buffer + uscpi->response_bytes_read, read_length);
+
+	uscpi->response_bytes_read += read_length;
+
+	return read_length;
+}
+
+static int scpi_usbtmc_libusb_read_complete(void *priv)
+{
+	struct scpi_usbtmc_libusb *uscpi = priv;
+	return uscpi->response_bytes_read >= uscpi->response_length &&
+	       uscpi->remaining_length <= 0 &&
+	       uscpi->bulkin_attributes & EOM;
+}
+
+static int scpi_usbtmc_libusb_close(void *priv)
+{
+	int ret;
+	struct scpi_usbtmc_libusb *uscpi = priv;
+	struct sr_usb_dev_inst *usb = uscpi->usb;
+
+	if (!usb->devhdl)
+		return SR_ERR;
+
+	if (!uscpi->rigol_ds1000) {
+	if ((ret = libusb_clear_halt(usb->devhdl, uscpi->bulk_in_ep)) < 0)
+		sr_err("Failed to clear halt/stall condition for EP %d: %s.",
+		       uscpi->bulk_in_ep, libusb_error_name(ret));
+	if ((ret = libusb_clear_halt(usb->devhdl, uscpi->bulk_out_ep)) < 0)
+		sr_err("Failed to clear halt/stall condition for EP %d: %s.",
+		       uscpi->bulk_out_ep, libusb_error_name(ret));
+	if ((ret = libusb_clear_halt(usb->devhdl, uscpi->interrupt_ep)) < 0)
+		sr_err("Failed to clear halt/stall condition for EP %d: %s.",
+		       uscpi->interrupt_ep, libusb_error_name(ret));
+	}
+
+	if ((ret = libusb_release_interface(usb->devhdl, uscpi->interface)) < 0)
+		sr_err("Failed to release interface: %s.",
+		       libusb_error_name(ret));
+	
+	if (uscpi->detached_kernel_driver) {
+		if ((ret = libusb_attach_kernel_driver(usb->devhdl,
+						uscpi->interface)) < 0)
+			sr_err("Failed to re-attach kernel driver: %s.",
+			       libusb_error_name(ret));
+
+		uscpi->detached_kernel_driver = 0;
+	}
+	libusb_close(usb->devhdl);
+	usb->devhdl = NULL;
+
+	return SR_OK;
+}
+
+static void scpi_usbtmc_libusb_free(void *priv)
+{
+	struct scpi_usbtmc_libusb *uscpi = priv;
+	sr_usb_dev_inst_free(uscpi->usb);
+}
+
+SR_PRIV const struct sr_scpi_dev_inst scpi_usbtmc_libusb_dev = {
+	.name          = "USBTMC",
+	.prefix        = "usbtmc",
+	.priv_size     = sizeof(struct scpi_usbtmc_libusb),
+	.scan          = scpi_usbtmc_libusb_scan,
+	.dev_inst_new  = scpi_usbtmc_libusb_dev_inst_new,
+	.open          = scpi_usbtmc_libusb_open,
+	.source_add    = scpi_usbtmc_libusb_source_add,
+	.source_remove = scpi_usbtmc_libusb_source_remove,
+	.send          = scpi_usbtmc_libusb_send,
+	.read_begin    = scpi_usbtmc_libusb_read_begin,
+	.read_data     = scpi_usbtmc_libusb_read_data,
+	.read_complete = scpi_usbtmc_libusb_read_complete,
+	.close         = scpi_usbtmc_libusb_close,
+	.free          = scpi_usbtmc_libusb_free,
+};
diff --git a/hardware/common/scpi_visa.c b/hardware/common/scpi_visa.c
new file mode 100644
index 0000000..b342a91
--- /dev/null
+++ b/hardware/common/scpi_visa.c
@@ -0,0 +1,174 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Martin Ling <martin-sigrok at earth.li>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#include <visa.h>
+#include <string.h>
+
+#define LOG_PREFIX "scpi_visa"
+
+struct scpi_visa {
+	char *resource;
+	ViSession rmgr;
+	ViSession vi;
+};
+
+static int scpi_visa_dev_inst_new(void *priv, struct drv_context *drvc,
+		const char *resource, char **params, const char *serialcomm)
+{
+	struct scpi_visa *vscpi = priv;
+
+	(void)drvc;
+	(void)resource;
+	(void)serialcomm;
+
+	if (!params || !params[1]) {
+		sr_err("Invalid parameters.");
+		return SR_ERR_BUG;
+	}
+
+	vscpi->resource = g_strdup(params[1]);
+
+	return SR_OK;
+}
+
+static int scpi_visa_open(void *priv)
+{
+	struct scpi_visa *vscpi = priv;
+
+	if (viOpenDefaultRM(&vscpi->rmgr) != VI_SUCCESS) {
+		sr_err("Cannot open default resource manager.");
+		return SR_ERR;
+	}
+
+	if (viOpen(vscpi->rmgr, vscpi->resource, VI_NO_LOCK, 0, &vscpi->vi) != VI_SUCCESS) {
+		sr_err("Cannot open resource.");
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+static int scpi_visa_source_add(void *priv, int events, int timeout,
+			sr_receive_data_callback cb, void *cb_data)
+{
+	(void) priv;
+
+	/* Hook up a dummy handler to receive data from the device. */
+	return sr_source_add(-1, events, timeout, cb, cb_data);
+}
+
+static int scpi_visa_source_remove(void *priv)
+{
+	(void) priv;
+
+	return sr_source_remove(-1);
+}
+
+static int scpi_visa_send(void *priv, const char *command)
+{
+	struct scpi_visa *vscpi = priv;
+	gchar *terminated_command;
+	ViUInt32 written = 0;
+	int len;
+
+	terminated_command = g_strconcat(command, "\n", NULL);
+	len = strlen(terminated_command);
+	if (viWrite(vscpi->vi, (ViBuf) (terminated_command + written), len,
+			&written) != VI_SUCCESS) {
+		sr_err("Error while sending SCPI command: '%s'.", command);
+		g_free(terminated_command);
+		return SR_ERR;
+	}
+
+	g_free(terminated_command);
+
+	sr_spew("Successfully sent SCPI command: '%s'.", command);
+
+	return SR_OK;
+}
+
+static int scpi_visa_read_begin(void *priv)
+{
+	(void) priv;
+
+	return SR_OK;
+}
+
+static int scpi_visa_read_data(void *priv, char *buf, int maxlen)
+{
+	struct scpi_visa *vscpi = priv;
+	ViUInt32 count;
+
+	if (viRead(vscpi->vi, (ViBuf) buf, maxlen, &count) != VI_SUCCESS) {
+		sr_err("Read failed.");
+		return SR_ERR;
+	}
+
+	return count;
+}
+
+static int scpi_visa_read_complete(void *priv)
+{
+	struct scpi_visa *vscpi = priv;
+	ViUInt16 status;
+
+	if (viReadSTB(vscpi->vi, &status) != VI_SUCCESS) {
+		sr_err("Failed to read status.");
+		return SR_ERR;
+	}
+
+	return !(status & 16);
+}
+
+static int scpi_visa_close(void *priv)
+{
+	struct scpi_visa *vscpi = priv;
+
+	viClose(vscpi->vi);
+	viClose(vscpi->rmgr);
+
+	return SR_OK;
+}
+
+static void scpi_visa_free(void *priv)
+{
+	struct scpi_visa *vscpi = priv;
+
+	g_free(vscpi->resource);
+	g_free(vscpi);
+}
+
+SR_PRIV const struct sr_scpi_dev_inst scpi_visa_dev = {
+	.name = "VISA",
+	.prefix = "visa",
+	.priv_size = sizeof(struct scpi_visa),
+	.dev_inst_new = scpi_visa_dev_inst_new,
+	.open = scpi_visa_open,
+	.source_add = scpi_visa_source_add,
+	.source_remove = scpi_visa_source_remove,
+	.send = scpi_visa_send,
+	.read_begin = scpi_visa_read_begin,
+	.read_data = scpi_visa_read_data,
+	.read_complete = scpi_visa_read_complete,
+	.close = scpi_visa_close,
+	.free = scpi_visa_free,
+};
diff --git a/hardware/common/scpi_vxi.c b/hardware/common/scpi_vxi.c
new file mode 100644
index 0000000..639b3b5
--- /dev/null
+++ b/hardware/common/scpi_vxi.c
@@ -0,0 +1,238 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Aurelien Jacobs <aurel at gnuage.org>
+ *
+ * Inspired by the VXI11 Ethernet Protocol for Linux:
+ * http://optics.eee.nottingham.ac.uk/vxi11/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <rpc/rpc.h>
+#include <string.h>
+
+#include "vxi.h"
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "scpi_vxi"
+#define VXI_DEFAULT_TIMEOUT  2000  /* in ms */
+
+struct scpi_vxi {
+	char *address;
+	char *instrument;
+	CLIENT *client;
+	Device_Link link;
+	unsigned int max_send_size;
+	unsigned int read_complete;
+};
+
+static int scpi_vxi_dev_inst_new(void *priv, struct drv_context *drvc,
+		const char *resource, char **params, const char *serialcomm)
+{
+	struct scpi_vxi *vxi = priv;
+
+	(void)drvc;
+	(void)resource;
+	(void)serialcomm;
+
+	if (!params || !params[1]) {
+		sr_err("Invalid parameters.");
+		return SR_ERR;
+	}
+
+	vxi->address    = g_strdup(params[1]);
+	vxi->instrument = g_strdup(params[2] ? params[2] : "inst0");
+
+	return SR_OK;
+}
+
+static int scpi_vxi_open(void *priv)
+{
+	struct scpi_vxi *vxi = priv;
+	Create_LinkParms link_parms;
+	Create_LinkResp *link_resp;
+
+	vxi->client = clnt_create(vxi->address, DEVICE_CORE, DEVICE_CORE_VERSION, "tcp");
+	if (vxi->client == NULL) {
+		sr_err("Client creation failed for %s", vxi->address);
+		return SR_ERR;
+	}
+
+	/* Set link parameters */
+	link_parms.clientId = (long) vxi->client;
+	link_parms.lockDevice = 0;
+	link_parms.lock_timeout = VXI_DEFAULT_TIMEOUT;
+	link_parms.device = "inst0";
+
+	if (!(link_resp = create_link_1(&link_parms, vxi->client))) {
+		sr_err("Link creation failed for %s", vxi->address);
+		return SR_ERR;
+	}
+	vxi->link = link_resp->lid;
+	vxi->max_send_size = link_resp->maxRecvSize;
+
+	/* Set a default maxRecvSize for devices which do not specify it */
+	if (vxi->max_send_size <= 0)
+		vxi->max_send_size = 4096;
+
+	return SR_OK;
+}
+
+static int scpi_vxi_source_add(void *priv, int events, int timeout,
+			sr_receive_data_callback cb, void *cb_data)
+{
+	(void)priv;
+
+	/* Hook up a dummy handler to receive data from the device. */
+	return sr_source_add(-1, events, timeout, cb, cb_data);
+}
+
+static int scpi_vxi_source_remove(void *priv)
+{
+	(void)priv;
+
+	return sr_source_remove(-1);
+}
+
+/* Operation Flags */
+#define DF_WAITLOCK  0x01  /* wait if the operation is locked by another link */
+#define DF_END       0x08  /* an END indicator is sent with last byte of buffer */
+#define DF_TERM      0x80  /* a termination char is set during a read */
+
+static int scpi_vxi_send(void *priv, const char *command)
+{
+	struct scpi_vxi *vxi = priv;
+	Device_WriteResp *write_resp;
+	Device_WriteParms write_parms;
+	char *terminated_command;
+	unsigned int len;
+
+	terminated_command = g_strdup_printf("%s\r\n", command);
+	len = strlen(terminated_command);
+
+	write_parms.lid           = vxi->link;
+	write_parms.io_timeout    = VXI_DEFAULT_TIMEOUT;
+	write_parms.lock_timeout  = VXI_DEFAULT_TIMEOUT;
+	write_parms.flags         = DF_END;
+	write_parms.data.data_len = MIN(len, vxi->max_send_size);
+	write_parms.data.data_val = terminated_command;
+
+	if (!(write_resp = device_write_1(&write_parms, vxi->client))
+	    || write_resp->error) {
+		sr_err("Device write failed for %s with error %d",
+		       vxi->address, write_resp->error);
+		return SR_ERR;
+	}
+
+	g_free(terminated_command);
+
+	if (write_resp->size < len)
+		sr_dbg("Only sent %d/%d bytes of SCPI command: '%s'.",
+		       write_resp->size, len, command);
+	else
+		sr_spew("Successfully sent SCPI command: '%s'.", command);
+
+	return SR_OK;
+}
+
+static int scpi_vxi_read_begin(void *priv)
+{
+	struct scpi_vxi *vxi = priv;
+
+	vxi->read_complete = 0;
+
+	return SR_OK;
+}
+
+/* Read Response Reason Flags */
+#define RRR_SIZE  0x01  /* requestSize bytes have been transferred */
+#define RRR_TERM  0x02  /* a termination char has been read */
+#define RRR_END   0x04  /* an END indicator has been read */
+
+static int scpi_vxi_read_data(void *priv, char *buf, int maxlen)
+{
+	struct scpi_vxi *vxi = priv;
+	Device_ReadParms read_parms;
+	Device_ReadResp *read_resp;
+
+	read_parms.lid          = vxi->link;
+	read_parms.io_timeout   = VXI_DEFAULT_TIMEOUT;
+	read_parms.lock_timeout = VXI_DEFAULT_TIMEOUT;
+	read_parms.flags        = 0;
+	read_parms.termChar     = 0;
+	read_parms.requestSize  = maxlen;
+
+	if (!(read_resp = device_read_1(&read_parms, vxi->client))
+	    || read_resp->error) {
+		sr_err("Device read failed for %s with error %d",
+		       vxi->address, read_resp->error);
+		return SR_ERR;
+	}
+
+	memcpy(buf, read_resp->data.data_val, read_resp->data.data_len);
+	vxi->read_complete = read_resp->reason & (RRR_SIZE | RRR_TERM | RRR_END);
+	return read_resp->data.data_len;  /* actual number of bytes received */
+}
+
+static int scpi_vxi_read_complete(void *priv)
+{
+	struct scpi_vxi *vxi = priv;
+
+	return vxi->read_complete;
+}
+
+static int scpi_vxi_close(void *priv)
+{
+	struct scpi_vxi *vxi = priv;
+	Device_Error *dev_error;
+
+	if (!vxi->client)
+		return SR_ERR;
+
+	if (!(dev_error = destroy_link_1(&vxi->link, vxi->client))) {
+		sr_err("Link destruction failed for %s", vxi->address);
+		return SR_ERR;
+	}
+
+	clnt_destroy(vxi->client);
+	vxi->client = NULL;
+
+	return SR_OK;
+}
+
+static void scpi_vxi_free(void *priv)
+{
+	struct scpi_vxi *vxi = priv;
+
+	g_free(vxi->address);
+	g_free(vxi->instrument);
+}
+
+SR_PRIV const struct sr_scpi_dev_inst scpi_vxi_dev = {
+	.name          = "VXI",
+	.prefix        = "vxi",
+	.priv_size     = sizeof(struct scpi_vxi),
+	.dev_inst_new  = scpi_vxi_dev_inst_new,
+	.open          = scpi_vxi_open,
+	.source_add    = scpi_vxi_source_add,
+	.source_remove = scpi_vxi_source_remove,
+	.send          = scpi_vxi_send,
+	.read_begin    = scpi_vxi_read_begin,
+	.read_data     = scpi_vxi_read_data,
+	.read_complete = scpi_vxi_read_complete,
+	.close         = scpi_vxi_close,
+	.free          = scpi_vxi_free,
+};
diff --git a/hardware/common/serial.c b/hardware/common/serial.c
new file mode 100644
index 0000000..e99b768
--- /dev/null
+++ b/hardware/common/serial.c
@@ -0,0 +1,885 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010-2012 Bert Vermeulen <bert at biot.com>
+ * Copyright (C) 2010-2012 Uwe Hermann <uwe at hermann-uwe.de>
+ * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me at gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <libserialport.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "serial"
+
+/**
+ * Open the specified serial port.
+ *
+ * @param serial Previously initialized serial port structure.
+ * @param flags Flags to use when opening the serial port. Possible flags
+ *              include SERIAL_RDWR, SERIAL_RDONLY, SERIAL_NONBLOCK.
+ *
+ * If the serial structure contains a serialcomm string, it will be
+ * passed to serial_set_paramstr() after the port is opened.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+SR_PRIV int serial_open(struct sr_serial_dev_inst *serial, int flags)
+{
+	int ret;
+	char *error;
+	int sp_flags = 0;
+
+	if (!serial) {
+		sr_dbg("Invalid serial port.");
+		return SR_ERR;
+	}
+
+	sr_spew("Opening serial port '%s' (flags %d).", serial->port, flags);
+
+	sp_get_port_by_name(serial->port, &serial->data);
+
+	if (flags & SERIAL_RDWR)
+		sp_flags = (SP_MODE_READ | SP_MODE_WRITE);
+	else if (flags & SERIAL_RDONLY)
+		sp_flags = SP_MODE_READ;
+
+	serial->nonblocking = (flags & SERIAL_NONBLOCK) ? 1 : 0;
+
+	ret = sp_open(serial->data, sp_flags);
+
+	switch (ret) {
+	case SP_ERR_ARG:
+		sr_err("Attempt to open serial port with invalid parameters.");
+		return SR_ERR_ARG;
+	case SP_ERR_FAIL:
+		error = sp_last_error_message();
+		sr_err("Error opening port (%d): %s.",
+			sp_last_error_code(), error);
+		sp_free_error_message(error);
+		return SR_ERR;
+	}
+
+	if (serial->serialcomm)
+		return serial_set_paramstr(serial, serial->serialcomm);
+	else
+		return SR_OK;
+}
+
+/**
+ * Close the specified serial port.
+ *
+ * @param serial Previously initialized serial port structure.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+SR_PRIV int serial_close(struct sr_serial_dev_inst *serial)
+{
+	int ret;
+	char *error;
+
+	if (!serial) {
+		sr_dbg("Invalid serial port.");
+		return SR_ERR;
+	}
+
+	if (!serial->data) {
+		sr_dbg("Cannot close unopened serial port %s.", serial->port);
+		return SR_ERR;
+	}
+
+	sr_spew("Closing serial port %s.", serial->port);
+
+	ret = sp_close(serial->data);
+
+	switch (ret) {
+	case SP_ERR_ARG:
+		sr_err("Attempt to close an invalid serial port.");
+		return SR_ERR_ARG;
+	case SP_ERR_FAIL:
+		error = sp_last_error_message();
+		sr_err("Error closing port (%d): %s.",
+			sp_last_error_code(), error);
+		sp_free_error_message(error);
+		return SR_ERR;
+	}
+
+	sp_free_port(serial->data);
+	serial->data = NULL;
+
+	return SR_OK;
+}
+
+/**
+ * Flush serial port buffers.
+ *
+ * @param serial Previously initialized serial port structure.
+ *
+ * @return SR_OK on success, SR_ERR on failure.
+ */
+SR_PRIV int serial_flush(struct sr_serial_dev_inst *serial)
+{
+	int ret;
+	char *error;
+
+	if (!serial) {
+		sr_dbg("Invalid serial port.");
+		return SR_ERR;
+	}
+
+	if (!serial->data) {
+		sr_dbg("Cannot flush unopened serial port %s.", serial->port);
+		return SR_ERR;
+	}
+
+	sr_spew("Flushing serial port %s.", serial->port);
+
+	ret = sp_flush(serial->data, SP_BUF_BOTH);
+
+	switch (ret) {
+	case SP_ERR_ARG:
+		sr_err("Attempt to flush an invalid serial port.");
+		return SR_ERR_ARG;
+	case SP_ERR_FAIL:
+		error = sp_last_error_message();
+		sr_err("Error flushing port (%d): %s.",
+			sp_last_error_code(), error);
+		sp_free_error_message(error);
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+static int _serial_write(struct sr_serial_dev_inst *serial,
+		const void *buf, size_t count, int nonblocking)
+{
+	ssize_t ret;
+	char *error;
+
+	if (!serial) {
+		sr_dbg("Invalid serial port.");
+		return SR_ERR;
+	}
+
+	if (!serial->data) {
+		sr_dbg("Cannot use unopened serial port %s.", serial->port);
+		return SR_ERR;
+	}
+
+	if (nonblocking)
+		ret = sp_nonblocking_write(serial->data, buf, count);
+	else
+		ret = sp_blocking_write(serial->data, buf, count, 0);
+
+	switch (ret) {
+	case SP_ERR_ARG:
+		sr_err("Attempted serial port write with invalid arguments.");
+		return SR_ERR_ARG;
+	case SP_ERR_FAIL:
+		error = sp_last_error_message();
+		sr_err("Write error (%d): %s.", sp_last_error_code(), error);
+		sp_free_error_message(error);
+		return SR_ERR;
+	}
+
+	sr_spew("Wrote %d/%d bytes.", ret, count);
+
+	return ret;
+}
+
+/**
+ * Write a number of bytes to the specified serial port.
+ *
+ * @param serial Previously initialized serial port structure.
+ * @param buf Buffer containing the bytes to write.
+ * @param count Number of bytes to write.
+ *
+ * @return The number of bytes written, or a negative error code upon failure.
+ */
+SR_PRIV int serial_write(struct sr_serial_dev_inst *serial,
+		const void *buf, size_t count)
+{
+	return _serial_write(serial, buf, count, serial->nonblocking);
+}
+
+SR_PRIV int serial_write_blocking(struct sr_serial_dev_inst *serial,
+		const void *buf, size_t count)
+{
+	return _serial_write(serial, buf, count, 0);
+}
+
+SR_PRIV int serial_write_nonblocking(struct sr_serial_dev_inst *serial,
+		const void *buf, size_t count)
+{
+	return _serial_write(serial, buf, count, 1);
+}
+
+static int _serial_read(struct sr_serial_dev_inst *serial, void *buf,
+		size_t count, int nonblocking)
+{
+	ssize_t ret;
+	char *error;
+
+	if (!serial) {
+		sr_dbg("Invalid serial port.");
+		return SR_ERR;
+	}
+
+	if (!serial->data) {
+		sr_dbg("Cannot use unopened serial port %s.", serial->port);
+		return SR_ERR;
+	}
+
+	if (nonblocking)
+		ret = sp_nonblocking_read(serial->data, buf, count);
+	else
+		ret = sp_blocking_read(serial->data, buf, count, 0);
+
+	switch (ret) {
+	case SP_ERR_ARG:
+		sr_err("Attempted serial port read with invalid arguments.");
+		return SR_ERR_ARG;
+	case SP_ERR_FAIL:
+		error = sp_last_error_message();
+		sr_err("Read error (%d): %s.", sp_last_error_code(), error);
+		sp_free_error_message(error);
+		return SR_ERR;
+	}
+
+	if (ret > 0)
+		sr_spew("Read %d/%d bytes.", ret, count);
+
+	return ret;
+}
+
+/**
+ * Read a number of bytes from the specified serial port.
+ *
+ * @param serial Previously initialized serial port structure.
+ * @param buf Buffer where to store the bytes that are read.
+ * @param count The number of bytes to read.
+ *
+ * @return The number of bytes read, or a negative error code upon failure.
+ */
+SR_PRIV int serial_read(struct sr_serial_dev_inst *serial, void *buf,
+		size_t count)
+{
+	return _serial_read(serial, buf, count, serial->nonblocking);
+}
+
+SR_PRIV int serial_read_blocking(struct sr_serial_dev_inst *serial, void *buf,
+		size_t count)
+{
+	return _serial_read(serial, buf, count, 0);
+}
+
+SR_PRIV int serial_read_nonblocking(struct sr_serial_dev_inst *serial, void *buf,
+		size_t count)
+{
+	return _serial_read(serial, buf, count, 1);
+}
+
+/**
+ * Set serial parameters for the specified serial port.
+ *
+ * @param serial Previously initialized serial port structure.
+ * @param[in] baudrate The baudrate to set.
+ * @param[in] bits The number of data bits to use (5, 6, 7 or 8).
+ * @param[in] parity The parity setting to use (0 = none, 1 = even, 2 = odd).
+ * @param[in] stopbits The number of stop bits to use (1 or 2).
+ * @param[in] flowcontrol The flow control settings to use (0 = none,
+ *                      1 = RTS/CTS, 2 = XON/XOFF).
+ * @param[in] rts Status of RTS line (0 or 1; required by some interfaces).
+ * @param[in] dtr Status of DTR line (0 or 1; required by some interfaces).
+ *
+ * @retval SR_OK Success
+ * @retval SR_ERR Failure.
+ */
+SR_PRIV int serial_set_params(struct sr_serial_dev_inst *serial, int baudrate,
+			      int bits, int parity, int stopbits,
+			      int flowcontrol, int rts, int dtr)
+{
+	int ret;
+	char *error;
+	struct sp_port_config *config;
+
+	if (!serial) {
+		sr_dbg("Invalid serial port.");
+		return SR_ERR;
+	}
+
+	if (!serial->data) {
+		sr_dbg("Cannot configure unopened serial port %s.", serial->port);
+		return SR_ERR;
+	}
+
+	sr_spew("Setting serial parameters on port %s.", serial->port);
+
+	sp_new_config(&config);
+	sp_set_config_baudrate(config, baudrate);
+	sp_set_config_bits(config, bits);
+	switch (parity) {
+	case 0:
+		sp_set_config_parity(config, SP_PARITY_NONE);
+		break;
+	case 1:
+		sp_set_config_parity(config, SP_PARITY_EVEN);
+		break;
+	case 2:
+		sp_set_config_parity(config, SP_PARITY_ODD);
+		break;
+	default:
+		return SR_ERR_ARG;
+	}
+	sp_set_config_stopbits(config, stopbits);
+	sp_set_config_rts(config, flowcontrol == 1 ? SP_RTS_FLOW_CONTROL : rts);
+	sp_set_config_cts(config, flowcontrol == 1 ? SP_CTS_FLOW_CONTROL : SP_CTS_IGNORE);
+	sp_set_config_dtr(config, dtr);
+	sp_set_config_dsr(config, SP_DSR_IGNORE);
+	sp_set_config_xon_xoff(config, flowcontrol == 2 ? SP_XONXOFF_INOUT : SP_XONXOFF_DISABLED);
+
+	ret = sp_set_config(serial->data, config);
+	sp_free_config(config);
+
+	switch (ret) {
+	case SP_ERR_ARG:
+		sr_err("Invalid arguments for setting serial port parameters.");
+		return SR_ERR_ARG;
+	case SP_ERR_FAIL:
+		error = sp_last_error_message();
+		sr_err("Error setting serial port parameters (%d): %s.",
+			sp_last_error_code(), error);
+		sp_free_error_message(error);
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+/**
+ * Set serial parameters for the specified serial port from parameter string.
+ *
+ * @param serial Previously initialized serial port structure.
+ * @param[in] paramstr A serial communication parameters string of the form
+ * "<baudrate>/<bits><parity><stopbits>{/<option>}".\n
+ *  Examples: "9600/8n1", "600/7o2/dtr=1/rts=0" or "460800/8n1/flow=2".\n
+ * \<baudrate\>=integer Baud rate.\n
+ * \<bits\>=5|6|7|8 Number of data bits.\n
+ * \<parity\>=n|e|o None, even, odd.\n
+ * \<stopbits\>=1|2 One or two stop bits.\n
+ * Options:\n
+ * dtr=0|1 Set DTR off resp. on.\n
+ * flow=0|1|2 Flow control. 0 for none, 1 for RTS/CTS, 2 for XON/XOFF.\n
+ * rts=0|1 Set RTS off resp. on.\n
+ * Please note that values and combinations of these parameters must be
+ * supported by the concrete serial interface hardware and the drivers for it.
+ * @retval SR_OK Success.
+ * @retval SR_ERR Failure.
+ */
+SR_PRIV int serial_set_paramstr(struct sr_serial_dev_inst *serial,
+		const char *paramstr)
+{
+#define SERIAL_COMM_SPEC "^(\\d+)/([5678])([neo])([12])(.*)$"
+
+	GRegex *reg;
+	GMatchInfo *match;
+	int speed, databits, parity, stopbits, flow, rts, dtr, i;
+	char *mstr, **opts, **kv;
+
+	speed = databits = parity = stopbits = flow = 0;
+	rts = dtr = -1;
+	sr_spew("Parsing parameters from \"%s\".", paramstr);
+	reg = g_regex_new(SERIAL_COMM_SPEC, 0, 0, NULL);
+	if (g_regex_match(reg, paramstr, 0, &match)) {
+		if ((mstr = g_match_info_fetch(match, 1)))
+			speed = strtoul(mstr, NULL, 10);
+		g_free(mstr);
+		if ((mstr = g_match_info_fetch(match, 2)))
+			databits = strtoul(mstr, NULL, 10);
+		g_free(mstr);
+		if ((mstr = g_match_info_fetch(match, 3))) {
+			switch (mstr[0]) {
+			case 'n':
+				parity = SERIAL_PARITY_NONE;
+				break;
+			case 'e':
+				parity = SERIAL_PARITY_EVEN;
+				break;
+			case 'o':
+				parity = SERIAL_PARITY_ODD;
+				break;
+			}
+		}
+		g_free(mstr);
+		if ((mstr = g_match_info_fetch(match, 4)))
+			stopbits = strtoul(mstr, NULL, 10);
+		g_free(mstr);
+		if ((mstr = g_match_info_fetch(match, 5)) && mstr[0] != '\0') {
+			if (mstr[0] != '/') {
+				sr_dbg("missing separator before extra options");
+				speed = 0;
+			} else {
+				/* A set of "key=value" options separated by / */
+				opts = g_strsplit(mstr + 1, "/", 0);
+				for (i = 0; opts[i]; i++) {
+					kv = g_strsplit(opts[i], "=", 2);
+					if (!strncmp(kv[0], "rts", 3)) {
+						if (kv[1][0] == '1')
+							rts = 1;
+						else if (kv[1][0] == '0')
+							rts = 0;
+						else {
+							sr_dbg("invalid value for rts: %c", kv[1][0]);
+							speed = 0;
+						}
+					} else if (!strncmp(kv[0], "dtr", 3)) {
+						if (kv[1][0] == '1')
+							dtr = 1;
+						else if (kv[1][0] == '0')
+							dtr = 0;
+						else {
+							sr_dbg("invalid value for dtr: %c", kv[1][0]);
+							speed = 0;
+						}
+					} else if (!strncmp(kv[0], "flow", 4)) {
+						if (kv[1][0] == '0')
+							flow = 0;
+						else if (kv[1][0] == '1')
+							flow = 1;
+						else if (kv[1][0] == '2')
+							flow = 2;
+						else {
+							sr_dbg("invalid value for flow: %c", kv[1][0]);
+							speed = 0;
+						}
+					}
+					g_strfreev(kv);
+				}
+				g_strfreev(opts);
+			}
+		}
+		g_free(mstr);
+	}
+	g_match_info_unref(match);
+	g_regex_unref(reg);
+
+	if (speed) {
+		return serial_set_params(serial, speed, databits, parity,
+					 stopbits, flow, rts, dtr);
+	} else {
+		sr_dbg("Could not infer speed from parameter string.");
+		return SR_ERR_ARG;
+	}
+}
+
+/**
+ * Read a line from the specified serial port.
+ *
+ * @param serial Previously initialized serial port structure.
+ * @param buf Buffer where to store the bytes that are read.
+ * @param buflen Size of the buffer.
+ * @param[in] timeout_ms How long to wait for a line to come in.
+ *
+ * Reading stops when CR of LR is found, which is stripped from the buffer.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR Failure.
+ */
+SR_PRIV int serial_readline(struct sr_serial_dev_inst *serial, char **buf,
+		int *buflen, gint64 timeout_ms)
+{
+	gint64 start;
+	int maxlen, len;
+
+	if (!serial) {
+		sr_dbg("Invalid serial port.");
+		return SR_ERR;
+	}
+
+	if (!serial->data) {
+		sr_dbg("Cannot use unopened serial port %s.", serial->port);
+		return -1;
+	}
+
+	timeout_ms *= 1000;
+	start = g_get_monotonic_time();
+
+	maxlen = *buflen;
+	*buflen = len = 0;
+	while(1) {
+		len = maxlen - *buflen - 1;
+		if (len < 1)
+			break;
+		len = serial_read(serial, *buf + *buflen, 1);
+		if (len > 0) {
+			*buflen += len;
+			*(*buf + *buflen) = '\0';
+			if (*buflen > 0 && (*(*buf + *buflen - 1) == '\r'
+					|| *(*buf + *buflen - 1) == '\n')) {
+				/* Strip CR/LF and terminate. */
+				*(*buf + --*buflen) = '\0';
+				break;
+			}
+		}
+		if (g_get_monotonic_time() - start > timeout_ms)
+			/* Timeout */
+			break;
+		if (len < 1)
+			g_usleep(2000);
+	}
+	if (*buflen)
+		sr_dbg("Received %d: '%s'.", *buflen, *buf);
+
+	return SR_OK;
+}
+
+/**
+ * Try to find a valid packet in a serial data stream.
+ *
+ * @param serial Previously initialized serial port structure.
+ * @param buf Buffer containing the bytes to write.
+ * @param buflen Size of the buffer.
+ * @param[in] packet_size Size, in bytes, of a valid packet.
+ * @param is_valid Callback that assesses whether the packet is valid or not.
+ * @param[in] timeout_ms The timeout after which, if no packet is detected, to
+ *                   abort scanning.
+ * @param[in] baudrate The baudrate of the serial port. This parameter is not
+ *                 critical, but it helps fine tune the serial port polling
+ *                 delay.
+ *
+ * @retval SR_OK Valid packet was found within the given timeout
+ * @retval SR_ERR Failure.
+ */
+SR_PRIV int serial_stream_detect(struct sr_serial_dev_inst *serial,
+				 uint8_t *buf, size_t *buflen,
+				 size_t packet_size,
+				 packet_valid_callback is_valid,
+				 uint64_t timeout_ms, int baudrate)
+{
+	uint64_t start, time, byte_delay_us;
+	size_t ibuf, i, maxlen;
+	int len;
+
+	maxlen = *buflen;
+
+	sr_dbg("Detecting packets on %s (timeout = %" PRIu64
+	       "ms, baudrate = %d).", serial->port, timeout_ms, baudrate);
+
+	if (maxlen < (packet_size / 2) ) {
+		sr_err("Buffer size must be at least twice the packet size.");
+		return SR_ERR;
+	}
+
+	/* Assume 8n1 transmission. That is 10 bits for every byte. */
+	byte_delay_us = 10 * (1000000 / baudrate);
+	start = g_get_monotonic_time();
+
+	i = ibuf = len = 0;
+	while (ibuf < maxlen) {
+		len = serial_read(serial, &buf[ibuf], 1);
+		if (len > 0) {
+			ibuf += len;
+		} else if (len == 0) {
+			/* No logging, already done in serial_read(). */
+		} else {
+			/* Error reading byte, but continuing anyway. */
+		}
+
+		time = g_get_monotonic_time() - start;
+		time /= 1000;
+
+		if ((ibuf - i) >= packet_size) {
+			/* We have at least a packet's worth of data. */
+			if (is_valid(&buf[i])) {
+				sr_spew("Found valid %d-byte packet after "
+					"%" PRIu64 "ms.", (ibuf - i), time);
+				*buflen = ibuf;
+				return SR_OK;
+			} else {
+				sr_spew("Got %d bytes, but not a valid "
+					"packet.", (ibuf - i));
+			}
+			/* Not a valid packet. Continue searching. */
+			i++;
+		}
+		if (time >= timeout_ms) {
+			/* Timeout */
+			sr_dbg("Detection timed out after %dms.", time);
+			break;
+		}
+		if (len < 1)
+			g_usleep(byte_delay_us);
+	}
+
+	*buflen = ibuf;
+
+	sr_err("Didn't find a valid packet (read %d bytes).", *buflen);
+
+	return SR_ERR;
+}
+
+/**
+ * Extract the serial device and options from the options linked list.
+ *
+ * @param options List of options passed from the command line.
+ * @param serial_device Pointer where to store the exctracted serial device.
+ * @param serial_options Pointer where to store the optional extracted serial
+ * options.
+ *
+ * @return SR_OK if a serial_device is found, SR_ERR if no device is found. The
+ * returned string should not be freed by the caller.
+ */
+SR_PRIV int sr_serial_extract_options(GSList *options, const char **serial_device,
+				      const char **serial_options)
+{
+	GSList *l;
+	struct sr_config *src;
+
+	*serial_device = NULL;
+
+	for (l = options; l; l = l->next) {
+		src = l->data;
+		switch (src->key) {
+		case SR_CONF_CONN:
+			*serial_device = g_variant_get_string(src->data, NULL);
+			sr_dbg("Parsed serial device: %s", *serial_device);
+			break;
+
+		case SR_CONF_SERIALCOMM:
+			*serial_options = g_variant_get_string(src->data, NULL);
+			sr_dbg("Parsed serial options: %s", *serial_options);
+			break;
+		}
+	}
+
+	if (!*serial_device) {
+		sr_dbg("No serial device specified");
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+#ifdef _WIN32
+typedef HANDLE event_handle;
+#else
+typedef int event_handle;
+#endif
+
+SR_PRIV int serial_source_add(struct sr_serial_dev_inst *serial, int events,
+		int timeout, sr_receive_data_callback cb, void *cb_data)
+{
+	enum sp_event mask = 0;
+	unsigned int i;
+
+	if (sp_new_event_set(&serial->event_set) != SP_OK)
+		return SR_ERR;
+
+	if (events & G_IO_IN)
+		mask |= SP_EVENT_RX_READY;
+	if (events & G_IO_OUT)
+		mask |= SP_EVENT_TX_READY;
+	if (events & G_IO_ERR)
+		mask |= SP_EVENT_ERROR;
+
+	if (sp_add_port_events(serial->event_set, serial->data, mask) != SP_OK) {
+		sp_free_event_set(serial->event_set);
+		return SR_ERR;
+	}
+
+	serial->pollfds = (GPollFD *) g_malloc0(sizeof(GPollFD) * serial->event_set->count);
+
+	for (i = 0; i < serial->event_set->count; i++) {
+
+		serial->pollfds[i].fd = ((event_handle *) serial->event_set->handles)[i];
+
+		mask = serial->event_set->masks[i];
+
+		if (mask & SP_EVENT_RX_READY)
+			serial->pollfds[i].events |= G_IO_IN;
+		if (mask & SP_EVENT_TX_READY)
+			serial->pollfds[i].events |= G_IO_OUT;
+		if (mask & SP_EVENT_ERROR)
+			serial->pollfds[i].events |= G_IO_ERR;
+
+		if (sr_session_source_add_pollfd(&serial->pollfds[i],
+				timeout, cb, cb_data) != SR_OK)
+			return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+SR_PRIV int serial_source_remove(struct sr_serial_dev_inst *serial)
+{
+	unsigned int i;
+
+	for (i = 0; i < serial->event_set->count; i++)
+		if (sr_session_source_remove_pollfd(&serial->pollfds[i]) != SR_OK)
+			return SR_ERR;
+
+	g_free(serial->pollfds);
+	sp_free_event_set(serial->event_set);
+
+	serial->pollfds = NULL;
+	serial->event_set = NULL;
+
+	return SR_OK;
+}
+
+/**
+ * Find USB serial devices via the USB vendor ID and product ID.
+ *
+ * @param vendor_id Vendor ID of the USB device.
+ * @param product_id Product ID of the USB device.
+ *
+ * @return A GSList of strings containing the path of the serial device or
+ *         NULL if no serial device is found. The returned list must be freed
+ *         by the caller.
+ */
+SR_PRIV GSList *sr_serial_find_usb(uint16_t vendor_id, uint16_t product_id)
+{
+#ifdef __linux__
+	const gchar *usb_dev;
+	const char device_tree[] = "/sys/bus/usb/devices/";
+	GDir *devices_dir, *device_dir;
+	GSList *l = NULL;
+	GSList *tty_devs;
+	GSList *matched_paths;
+	FILE *fd;
+	char tmp[5];
+	gchar *vendor_path, *product_path, *path_copy;
+	gchar *prefix, *subdir_path, *device_path, *tty_path;
+	unsigned long read_vendor_id, read_product_id;
+	const char *file;
+
+	l = NULL;
+	tty_devs = NULL;
+	matched_paths = NULL;
+
+	if (!(devices_dir = g_dir_open(device_tree, 0, NULL)))
+		return NULL;
+
+	/*
+	 * Find potential candidates using the vendor ID and product ID
+	 * and store them in matched_paths.
+	 */
+	while ((usb_dev = g_dir_read_name(devices_dir))) {
+		vendor_path = g_strconcat(device_tree,
+					  usb_dev, "/idVendor", NULL);
+		product_path = g_strconcat(device_tree,
+					   usb_dev, "/idProduct", NULL);
+
+		if (!g_file_test(vendor_path, G_FILE_TEST_EXISTS) ||
+		    !g_file_test(product_path, G_FILE_TEST_EXISTS))
+			goto skip_device;
+
+		if ((fd = g_fopen(vendor_path, "r")) == NULL)
+			goto skip_device;
+
+		if (fgets(tmp, sizeof(tmp), fd) == NULL) {
+			fclose(fd);
+			goto skip_device;
+		}
+		read_vendor_id = strtoul(tmp, NULL, 16);
+
+		fclose(fd);
+
+		if ((fd = g_fopen(product_path, "r")) == NULL)
+			goto skip_device;
+
+		if (fgets(tmp, sizeof(tmp), fd) == NULL) {
+			fclose(fd);
+			goto skip_device;
+		}
+		read_product_id = strtoul(tmp, NULL, 16);
+
+		fclose(fd);
+
+		if (vendor_id == read_vendor_id &&
+		    product_id == read_product_id) {
+			path_copy = g_strdup(usb_dev);
+			matched_paths = g_slist_prepend(matched_paths,
+							path_copy);
+		}
+
+skip_device:
+		g_free(vendor_path);
+		g_free(product_path);
+	}
+	g_dir_close(devices_dir);
+
+	/* For every matched device try to find a ttyUSBX subfolder. */
+	for (l = matched_paths; l; l = l->next) {
+		subdir_path = NULL;
+
+		device_path = g_strconcat(device_tree, l->data, NULL);
+
+		if (!(device_dir = g_dir_open(device_path, 0, NULL))) {
+			g_free(device_path);
+			continue;
+		}
+
+		prefix = g_strconcat(l->data, ":", NULL);
+
+		while ((file = g_dir_read_name(device_dir))) {
+			if (g_str_has_prefix(file, prefix)) {
+				subdir_path = g_strconcat(device_path,
+						"/", file, NULL);
+				break;
+			}
+		}
+		g_dir_close(device_dir);
+
+		g_free(prefix);
+		g_free(device_path);
+
+		if (subdir_path) {
+			if (!(device_dir = g_dir_open(subdir_path, 0, NULL))) {
+				g_free(subdir_path);
+				continue;
+			}
+			g_free(subdir_path);
+
+			while ((file = g_dir_read_name(device_dir))) {
+				if (g_str_has_prefix(file, "ttyUSB")) {
+					tty_path = g_strconcat("/dev/",
+							       file, NULL);
+					sr_dbg("Found USB device %04x:%04x attached to %s.",
+					       vendor_id, product_id, tty_path);
+					tty_devs = g_slist_prepend(tty_devs,
+							tty_path);
+					break;
+				}
+			}
+			g_dir_close(device_dir);
+		}
+	}
+	g_slist_free_full(matched_paths, g_free);
+
+	return tty_devs;
+#else
+	(void)vendor_id;
+	(void)product_id;
+
+	return NULL;
+#endif
+}
diff --git a/hardware/common/usb.c b/hardware/common/usb.c
new file mode 100644
index 0000000..62db385
--- /dev/null
+++ b/hardware/common/usb.c
@@ -0,0 +1,269 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Uwe Hermann <uwe at hermann-uwe.de>
+ * Copyright (C) 2012 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <glib.h>
+#include <libusb.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+/* SR_CONF_CONN takes one of these: */
+#define CONN_USB_VIDPID  "^([0-9a-z]{4})\\.([0-9a-z]{4})$"
+#define CONN_USB_BUSADDR "^(\\d+)\\.(\\d+)$"
+
+#define LOG_PREFIX "usb"
+
+/**
+ * Find USB devices according to a connection string.
+ *
+ * @param usb_ctx libusb context to use while scanning.
+ * @param conn Connection string specifying the device(s) to match. This
+ * can be of the form "<bus>.<address>", or "<vendorid>.<productid>".
+ *
+ * @return A GSList of struct sr_usb_dev_inst, with bus and address fields
+ * matching the device that matched the connection string. The GSList and
+ * its contents must be freed by the caller.
+ */
+SR_PRIV GSList *sr_usb_find(libusb_context *usb_ctx, const char *conn)
+{
+	struct sr_usb_dev_inst *usb;
+	struct libusb_device **devlist;
+	struct libusb_device_descriptor des;
+	GSList *devices;
+	GRegex *reg;
+	GMatchInfo *match;
+	int vid, pid, bus, addr, b, a, ret, i;
+	char *mstr;
+
+	vid = pid = bus = addr = 0;
+	reg = g_regex_new(CONN_USB_VIDPID, 0, 0, NULL);
+	if (g_regex_match(reg, conn, 0, &match)) {
+		if ((mstr = g_match_info_fetch(match, 1)))
+			vid = strtoul(mstr, NULL, 16);
+		g_free(mstr);
+
+		if ((mstr = g_match_info_fetch(match, 2)))
+			pid = strtoul(mstr, NULL, 16);
+		g_free(mstr);
+		sr_dbg("Trying to find USB device with VID:PID = %04x:%04x.",
+		       vid, pid);
+	} else {
+		g_match_info_unref(match);
+		g_regex_unref(reg);
+		reg = g_regex_new(CONN_USB_BUSADDR, 0, 0, NULL);
+		if (g_regex_match(reg, conn, 0, &match)) {
+			if ((mstr = g_match_info_fetch(match, 1)))
+				bus = strtoul(mstr, NULL, 10);
+			g_free(mstr);
+
+			if ((mstr = g_match_info_fetch(match, 2)))
+				addr = strtoul(mstr, NULL, 10);
+			g_free(mstr);
+			sr_dbg("Trying to find USB device with bus.address = "
+			       "%d.%d.", bus, addr);
+		}
+	}
+	g_match_info_unref(match);
+	g_regex_unref(reg);
+
+	if (vid + pid + bus + addr == 0) {
+		sr_err("Neither VID:PID nor bus.address was specified.");
+		return NULL;
+	}
+
+	if (bus > 64) {
+		sr_err("Invalid bus specified: %d.", bus);
+		return NULL;
+	}
+
+	if (addr > 127) {
+		sr_err("Invalid address specified: %d.", addr);
+		return NULL;
+	}
+
+	/* Looks like a valid USB device specification, but is it connected? */
+	devices = NULL;
+	libusb_get_device_list(usb_ctx, &devlist);
+	for (i = 0; devlist[i]; i++) {
+		if ((ret = libusb_get_device_descriptor(devlist[i], &des))) {
+			sr_err("Failed to get device descriptor: %s.",
+			       libusb_error_name(ret));
+			continue;
+		}
+
+		if (vid + pid && (des.idVendor != vid || des.idProduct != pid))
+			continue;
+
+		b = libusb_get_bus_number(devlist[i]);
+		a = libusb_get_device_address(devlist[i]);
+		if (bus + addr && (b != bus || a != addr))
+			continue;
+
+		sr_dbg("Found USB device (VID:PID = %04x:%04x, bus.address = "
+		       "%d.%d).", des.idVendor, des.idProduct, b, a);
+
+		usb = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]),
+				libusb_get_device_address(devlist[i]), NULL);
+		devices = g_slist_append(devices, usb);
+	}
+	libusb_free_device_list(devlist, 1);
+
+	sr_dbg("Found %d device(s).", g_slist_length(devices));
+	
+	return devices;
+}
+
+SR_PRIV int sr_usb_open(libusb_context *usb_ctx, struct sr_usb_dev_inst *usb)
+{
+	struct libusb_device **devlist;
+	struct libusb_device_descriptor des;
+	int ret, r, cnt, i, a, b;
+
+	sr_dbg("Trying to open USB device %d.%d.", usb->bus, usb->address);
+
+	if ((cnt = libusb_get_device_list(usb_ctx, &devlist)) < 0) {
+		sr_err("Failed to retrieve device list: %s.",
+		       libusb_error_name(cnt));
+		return SR_ERR;
+	}
+
+	ret = SR_ERR;
+	for (i = 0; i < cnt; i++) {
+		if ((r = libusb_get_device_descriptor(devlist[i], &des)) < 0) {
+			sr_err("Failed to get device descriptor: %s.",
+			       libusb_error_name(r));
+			continue;
+		}
+
+		b = libusb_get_bus_number(devlist[i]);
+		a = libusb_get_device_address(devlist[i]);
+		if (b != usb->bus || a != usb->address)
+			continue;
+
+		if ((r = libusb_open(devlist[i], &usb->devhdl)) < 0) {
+			sr_err("Failed to open device: %s.",
+			       libusb_error_name(r));
+			break;
+		}
+
+		sr_dbg("Opened USB device (VID:PID = %04x:%04x, bus.address = "
+		       "%d.%d).", des.idVendor, des.idProduct, b, a);
+
+		ret = SR_OK;
+		break;
+	}
+
+	libusb_free_device_list(devlist, 1);
+
+	return ret;
+}
+
+#ifdef _WIN32
+static gpointer usb_thread(gpointer data)
+{
+	struct sr_context *ctx = data;
+
+	while (ctx->usb_thread_running) {
+		g_mutex_lock(&ctx->usb_mutex);
+		libusb_wait_for_event(ctx->libusb_ctx, NULL);
+		SetEvent(ctx->usb_event);
+		g_mutex_unlock(&ctx->usb_mutex);
+		g_thread_yield();
+	}
+
+	return NULL;
+}
+
+static int usb_callback(int fd, int revents, void *cb_data)
+{
+	struct sr_context *ctx = cb_data;
+	int ret;
+
+	g_mutex_lock(&ctx->usb_mutex);
+	ret = ctx->usb_cb(fd, revents, ctx->usb_cb_data);
+
+	if (ctx->usb_thread_running) {
+		ResetEvent(ctx->usb_event);
+		g_mutex_unlock(&ctx->usb_mutex);
+	}
+
+	return ret;
+}
+#endif
+
+SR_PRIV int usb_source_add(struct sr_context *ctx, int timeout,
+		sr_receive_data_callback cb, void *cb_data)
+{
+	if (ctx->usb_source_present) {
+		sr_err("A USB event source is already present.");
+		return SR_ERR;
+	}
+
+#ifdef _WIN32
+	ctx->usb_event = CreateEvent(NULL, TRUE, FALSE, NULL);
+	g_mutex_init(&ctx->usb_mutex);
+	ctx->usb_thread_running = TRUE;
+	ctx->usb_thread = g_thread_new("usb", usb_thread, ctx);
+	ctx->usb_pollfd.fd = ctx->usb_event;
+	ctx->usb_pollfd.events = G_IO_IN;
+	ctx->usb_cb = cb;
+	ctx->usb_cb_data = cb_data;
+	sr_session_source_add_pollfd(&ctx->usb_pollfd, timeout, usb_callback, ctx);
+#else
+	const struct libusb_pollfd **lupfd;
+	unsigned int i;
+
+	lupfd = libusb_get_pollfds(ctx->libusb_ctx);
+	for (i = 0; lupfd[i]; i++)
+		sr_source_add(lupfd[i]->fd, lupfd[i]->events, timeout, cb, cb_data);
+	free(lupfd);
+#endif
+	ctx->usb_source_present = TRUE;
+
+	return SR_OK;
+}
+
+SR_PRIV int usb_source_remove(struct sr_context *ctx)
+{
+	if (!ctx->usb_source_present)
+		return SR_OK;
+
+#ifdef _WIN32
+	ctx->usb_thread_running = FALSE;
+	g_mutex_unlock(&ctx->usb_mutex);
+	libusb_unlock_events(ctx->libusb_ctx);
+	g_thread_join(ctx->usb_thread);
+	g_mutex_clear(&ctx->usb_mutex);
+	sr_session_source_remove_pollfd(&ctx->usb_pollfd);
+	CloseHandle(ctx->usb_event);
+#else
+	const struct libusb_pollfd **lupfd;
+	unsigned int i;
+
+	lupfd = libusb_get_pollfds(ctx->libusb_ctx);
+	for (i = 0; lupfd[i]; i++)
+		sr_source_remove(lupfd[i]->fd);
+	free(lupfd);
+#endif
+	ctx->usb_source_present = FALSE;
+
+	return SR_OK;
+}
diff --git a/hardware/common/vxi.h b/hardware/common/vxi.h
new file mode 100644
index 0000000..61a51f6
--- /dev/null
+++ b/hardware/common/vxi.h
@@ -0,0 +1,342 @@
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#ifndef _VXI_H_RPCGEN
+#define _VXI_H_RPCGEN
+
+#include <rpc/rpc.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef long Device_Link;
+
+enum Device_AddrFamily {
+	DEVICE_TCP = 0,
+	DEVICE_UDP = 1,
+};
+typedef enum Device_AddrFamily Device_AddrFamily;
+
+typedef long Device_Flags;
+
+typedef long Device_ErrorCode;
+
+struct Device_Error {
+	Device_ErrorCode error;
+};
+typedef struct Device_Error Device_Error;
+
+struct Create_LinkParms {
+	long clientId;
+	bool_t lockDevice;
+	u_long lock_timeout;
+	char *device;
+};
+typedef struct Create_LinkParms Create_LinkParms;
+
+struct Create_LinkResp {
+	Device_ErrorCode error;
+	Device_Link lid;
+	u_short abortPort;
+	u_long maxRecvSize;
+};
+typedef struct Create_LinkResp Create_LinkResp;
+
+struct Device_WriteParms {
+	Device_Link lid;
+	u_long io_timeout;
+	u_long lock_timeout;
+	Device_Flags flags;
+	struct {
+		u_int data_len;
+		char *data_val;
+	} data;
+};
+typedef struct Device_WriteParms Device_WriteParms;
+
+struct Device_WriteResp {
+	Device_ErrorCode error;
+	u_long size;
+};
+typedef struct Device_WriteResp Device_WriteResp;
+
+struct Device_ReadParms {
+	Device_Link lid;
+	u_long requestSize;
+	u_long io_timeout;
+	u_long lock_timeout;
+	Device_Flags flags;
+	char termChar;
+};
+typedef struct Device_ReadParms Device_ReadParms;
+
+struct Device_ReadResp {
+	Device_ErrorCode error;
+	long reason;
+	struct {
+		u_int data_len;
+		char *data_val;
+	} data;
+};
+typedef struct Device_ReadResp Device_ReadResp;
+
+struct Device_ReadStbResp {
+	Device_ErrorCode error;
+	u_char stb;
+};
+typedef struct Device_ReadStbResp Device_ReadStbResp;
+
+struct Device_GenericParms {
+	Device_Link lid;
+	Device_Flags flags;
+	u_long lock_timeout;
+	u_long io_timeout;
+};
+typedef struct Device_GenericParms Device_GenericParms;
+
+struct Device_RemoteFunc {
+	u_long hostAddr;
+	u_short hostPort;
+	u_long progNum;
+	u_long progVers;
+	Device_AddrFamily progFamily;
+};
+typedef struct Device_RemoteFunc Device_RemoteFunc;
+
+struct Device_EnableSrqParms {
+	Device_Link lid;
+	bool_t enable;
+	struct {
+		u_int handle_len;
+		char *handle_val;
+	} handle;
+};
+typedef struct Device_EnableSrqParms Device_EnableSrqParms;
+
+struct Device_LockParms {
+	Device_Link lid;
+	Device_Flags flags;
+	u_long lock_timeout;
+};
+typedef struct Device_LockParms Device_LockParms;
+
+struct Device_DocmdParms {
+	Device_Link lid;
+	Device_Flags flags;
+	u_long io_timeout;
+	u_long lock_timeout;
+	long cmd;
+	bool_t network_order;
+	long datasize;
+	struct {
+		u_int data_in_len;
+		char *data_in_val;
+	} data_in;
+};
+typedef struct Device_DocmdParms Device_DocmdParms;
+
+struct Device_DocmdResp {
+	Device_ErrorCode error;
+	struct {
+		u_int data_out_len;
+		char *data_out_val;
+	} data_out;
+};
+typedef struct Device_DocmdResp Device_DocmdResp;
+
+struct Device_SrqParms {
+	struct {
+		u_int handle_len;
+		char *handle_val;
+	} handle;
+};
+typedef struct Device_SrqParms Device_SrqParms;
+
+#define DEVICE_ASYNC 0x0607B0
+#define DEVICE_ASYNC_VERSION 1
+
+#if defined(__STDC__) || defined(__cplusplus)
+#define device_abort 1
+extern  Device_Error * device_abort_1(Device_Link *, CLIENT *);
+extern  Device_Error * device_abort_1_svc(Device_Link *, struct svc_req *);
+extern int device_async_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
+
+#else /* K&R C */
+#define device_abort 1
+extern  Device_Error * device_abort_1();
+extern  Device_Error * device_abort_1_svc();
+extern int device_async_1_freeresult ();
+#endif /* K&R C */
+
+#define DEVICE_CORE 0x0607AF
+#define DEVICE_CORE_VERSION 1
+
+#if defined(__STDC__) || defined(__cplusplus)
+#define create_link 10
+extern  Create_LinkResp * create_link_1(Create_LinkParms *, CLIENT *);
+extern  Create_LinkResp * create_link_1_svc(Create_LinkParms *, struct svc_req *);
+#define device_write 11
+extern  Device_WriteResp * device_write_1(Device_WriteParms *, CLIENT *);
+extern  Device_WriteResp * device_write_1_svc(Device_WriteParms *, struct svc_req *);
+#define device_read 12
+extern  Device_ReadResp * device_read_1(Device_ReadParms *, CLIENT *);
+extern  Device_ReadResp * device_read_1_svc(Device_ReadParms *, struct svc_req *);
+#define device_readstb 13
+extern  Device_ReadStbResp * device_readstb_1(Device_GenericParms *, CLIENT *);
+extern  Device_ReadStbResp * device_readstb_1_svc(Device_GenericParms *, struct svc_req *);
+#define device_trigger 14
+extern  Device_Error * device_trigger_1(Device_GenericParms *, CLIENT *);
+extern  Device_Error * device_trigger_1_svc(Device_GenericParms *, struct svc_req *);
+#define device_clear 15
+extern  Device_Error * device_clear_1(Device_GenericParms *, CLIENT *);
+extern  Device_Error * device_clear_1_svc(Device_GenericParms *, struct svc_req *);
+#define device_remote 16
+extern  Device_Error * device_remote_1(Device_GenericParms *, CLIENT *);
+extern  Device_Error * device_remote_1_svc(Device_GenericParms *, struct svc_req *);
+#define device_local 17
+extern  Device_Error * device_local_1(Device_GenericParms *, CLIENT *);
+extern  Device_Error * device_local_1_svc(Device_GenericParms *, struct svc_req *);
+#define device_lock 18
+extern  Device_Error * device_lock_1(Device_LockParms *, CLIENT *);
+extern  Device_Error * device_lock_1_svc(Device_LockParms *, struct svc_req *);
+#define device_unlock 19
+extern  Device_Error * device_unlock_1(Device_Link *, CLIENT *);
+extern  Device_Error * device_unlock_1_svc(Device_Link *, struct svc_req *);
+#define device_enable_srq 20
+extern  Device_Error * device_enable_srq_1(Device_EnableSrqParms *, CLIENT *);
+extern  Device_Error * device_enable_srq_1_svc(Device_EnableSrqParms *, struct svc_req *);
+#define device_docmd 22
+extern  Device_DocmdResp * device_docmd_1(Device_DocmdParms *, CLIENT *);
+extern  Device_DocmdResp * device_docmd_1_svc(Device_DocmdParms *, struct svc_req *);
+#define destroy_link 23
+extern  Device_Error * destroy_link_1(Device_Link *, CLIENT *);
+extern  Device_Error * destroy_link_1_svc(Device_Link *, struct svc_req *);
+#define create_intr_chan 25
+extern  Device_Error * create_intr_chan_1(Device_RemoteFunc *, CLIENT *);
+extern  Device_Error * create_intr_chan_1_svc(Device_RemoteFunc *, struct svc_req *);
+#define destroy_intr_chan 26
+extern  Device_Error * destroy_intr_chan_1(void *, CLIENT *);
+extern  Device_Error * destroy_intr_chan_1_svc(void *, struct svc_req *);
+extern int device_core_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
+
+#else /* K&R C */
+#define create_link 10
+extern  Create_LinkResp * create_link_1();
+extern  Create_LinkResp * create_link_1_svc();
+#define device_write 11
+extern  Device_WriteResp * device_write_1();
+extern  Device_WriteResp * device_write_1_svc();
+#define device_read 12
+extern  Device_ReadResp * device_read_1();
+extern  Device_ReadResp * device_read_1_svc();
+#define device_readstb 13
+extern  Device_ReadStbResp * device_readstb_1();
+extern  Device_ReadStbResp * device_readstb_1_svc();
+#define device_trigger 14
+extern  Device_Error * device_trigger_1();
+extern  Device_Error * device_trigger_1_svc();
+#define device_clear 15
+extern  Device_Error * device_clear_1();
+extern  Device_Error * device_clear_1_svc();
+#define device_remote 16
+extern  Device_Error * device_remote_1();
+extern  Device_Error * device_remote_1_svc();
+#define device_local 17
+extern  Device_Error * device_local_1();
+extern  Device_Error * device_local_1_svc();
+#define device_lock 18
+extern  Device_Error * device_lock_1();
+extern  Device_Error * device_lock_1_svc();
+#define device_unlock 19
+extern  Device_Error * device_unlock_1();
+extern  Device_Error * device_unlock_1_svc();
+#define device_enable_srq 20
+extern  Device_Error * device_enable_srq_1();
+extern  Device_Error * device_enable_srq_1_svc();
+#define device_docmd 22
+extern  Device_DocmdResp * device_docmd_1();
+extern  Device_DocmdResp * device_docmd_1_svc();
+#define destroy_link 23
+extern  Device_Error * destroy_link_1();
+extern  Device_Error * destroy_link_1_svc();
+#define create_intr_chan 25
+extern  Device_Error * create_intr_chan_1();
+extern  Device_Error * create_intr_chan_1_svc();
+#define destroy_intr_chan 26
+extern  Device_Error * destroy_intr_chan_1();
+extern  Device_Error * destroy_intr_chan_1_svc();
+extern int device_core_1_freeresult ();
+#endif /* K&R C */
+
+#define DEVICE_INTR 0x0607B1
+#define DEVICE_INTR_VERSION 1
+
+#if defined(__STDC__) || defined(__cplusplus)
+#define device_intr_srq 30
+extern  void * device_intr_srq_1(Device_SrqParms *, CLIENT *);
+extern  void * device_intr_srq_1_svc(Device_SrqParms *, struct svc_req *);
+extern int device_intr_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
+
+#else /* K&R C */
+#define device_intr_srq 30
+extern  void * device_intr_srq_1();
+extern  void * device_intr_srq_1_svc();
+extern int device_intr_1_freeresult ();
+#endif /* K&R C */
+
+/* the xdr functions */
+
+#if defined(__STDC__) || defined(__cplusplus)
+extern  bool_t xdr_Device_Link (XDR *, Device_Link*);
+extern  bool_t xdr_Device_AddrFamily (XDR *, Device_AddrFamily*);
+extern  bool_t xdr_Device_Flags (XDR *, Device_Flags*);
+extern  bool_t xdr_Device_ErrorCode (XDR *, Device_ErrorCode*);
+extern  bool_t xdr_Device_Error (XDR *, Device_Error*);
+extern  bool_t xdr_Create_LinkParms (XDR *, Create_LinkParms*);
+extern  bool_t xdr_Create_LinkResp (XDR *, Create_LinkResp*);
+extern  bool_t xdr_Device_WriteParms (XDR *, Device_WriteParms*);
+extern  bool_t xdr_Device_WriteResp (XDR *, Device_WriteResp*);
+extern  bool_t xdr_Device_ReadParms (XDR *, Device_ReadParms*);
+extern  bool_t xdr_Device_ReadResp (XDR *, Device_ReadResp*);
+extern  bool_t xdr_Device_ReadStbResp (XDR *, Device_ReadStbResp*);
+extern  bool_t xdr_Device_GenericParms (XDR *, Device_GenericParms*);
+extern  bool_t xdr_Device_RemoteFunc (XDR *, Device_RemoteFunc*);
+extern  bool_t xdr_Device_EnableSrqParms (XDR *, Device_EnableSrqParms*);
+extern  bool_t xdr_Device_LockParms (XDR *, Device_LockParms*);
+extern  bool_t xdr_Device_DocmdParms (XDR *, Device_DocmdParms*);
+extern  bool_t xdr_Device_DocmdResp (XDR *, Device_DocmdResp*);
+extern  bool_t xdr_Device_SrqParms (XDR *, Device_SrqParms*);
+
+#else /* K&R C */
+extern bool_t xdr_Device_Link ();
+extern bool_t xdr_Device_AddrFamily ();
+extern bool_t xdr_Device_Flags ();
+extern bool_t xdr_Device_ErrorCode ();
+extern bool_t xdr_Device_Error ();
+extern bool_t xdr_Create_LinkParms ();
+extern bool_t xdr_Create_LinkResp ();
+extern bool_t xdr_Device_WriteParms ();
+extern bool_t xdr_Device_WriteResp ();
+extern bool_t xdr_Device_ReadParms ();
+extern bool_t xdr_Device_ReadResp ();
+extern bool_t xdr_Device_ReadStbResp ();
+extern bool_t xdr_Device_GenericParms ();
+extern bool_t xdr_Device_RemoteFunc ();
+extern bool_t xdr_Device_EnableSrqParms ();
+extern bool_t xdr_Device_LockParms ();
+extern bool_t xdr_Device_DocmdParms ();
+extern bool_t xdr_Device_DocmdResp ();
+extern bool_t xdr_Device_SrqParms ();
+
+#endif /* K&R C */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_VXI_H_RPCGEN */
diff --git a/hardware/common/vxi_clnt.c b/hardware/common/vxi_clnt.c
new file mode 100644
index 0000000..55a72dc
--- /dev/null
+++ b/hardware/common/vxi_clnt.c
@@ -0,0 +1,265 @@
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#include <memory.h> /* for memset */
+#include "vxi.h"
+
+/* Default timeout can be changed using clnt_control() */
+static struct timeval TIMEOUT = { 25, 0 };
+
+Device_Error *
+device_abort_1(Device_Link *argp, CLIENT *clnt)
+{
+	static Device_Error clnt_res;
+
+	memset((char *)&clnt_res, 0, sizeof(clnt_res));
+	if (clnt_call (clnt, device_abort,
+		(xdrproc_t) xdr_Device_Link, (caddr_t) argp,
+		(xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
+		TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&clnt_res);
+}
+
+Create_LinkResp *
+create_link_1(Create_LinkParms *argp, CLIENT *clnt)
+{
+	static Create_LinkResp clnt_res;
+
+	memset((char *)&clnt_res, 0, sizeof(clnt_res));
+	if (clnt_call (clnt, create_link,
+		(xdrproc_t) xdr_Create_LinkParms, (caddr_t) argp,
+		(xdrproc_t) xdr_Create_LinkResp, (caddr_t) &clnt_res,
+		TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&clnt_res);
+}
+
+Device_WriteResp *
+device_write_1(Device_WriteParms *argp, CLIENT *clnt)
+{
+	static Device_WriteResp clnt_res;
+
+	memset((char *)&clnt_res, 0, sizeof(clnt_res));
+	if (clnt_call (clnt, device_write,
+		(xdrproc_t) xdr_Device_WriteParms, (caddr_t) argp,
+		(xdrproc_t) xdr_Device_WriteResp, (caddr_t) &clnt_res,
+		TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&clnt_res);
+}
+
+Device_ReadResp *
+device_read_1(Device_ReadParms *argp, CLIENT *clnt)
+{
+	static Device_ReadResp clnt_res;
+
+	memset((char *)&clnt_res, 0, sizeof(clnt_res));
+	if (clnt_call (clnt, device_read,
+		(xdrproc_t) xdr_Device_ReadParms, (caddr_t) argp,
+		(xdrproc_t) xdr_Device_ReadResp, (caddr_t) &clnt_res,
+		TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&clnt_res);
+}
+
+Device_ReadStbResp *
+device_readstb_1(Device_GenericParms *argp, CLIENT *clnt)
+{
+	static Device_ReadStbResp clnt_res;
+
+	memset((char *)&clnt_res, 0, sizeof(clnt_res));
+	if (clnt_call (clnt, device_readstb,
+		(xdrproc_t) xdr_Device_GenericParms, (caddr_t) argp,
+		(xdrproc_t) xdr_Device_ReadStbResp, (caddr_t) &clnt_res,
+		TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&clnt_res);
+}
+
+Device_Error *
+device_trigger_1(Device_GenericParms *argp, CLIENT *clnt)
+{
+	static Device_Error clnt_res;
+
+	memset((char *)&clnt_res, 0, sizeof(clnt_res));
+	if (clnt_call (clnt, device_trigger,
+		(xdrproc_t) xdr_Device_GenericParms, (caddr_t) argp,
+		(xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
+		TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&clnt_res);
+}
+
+Device_Error *
+device_clear_1(Device_GenericParms *argp, CLIENT *clnt)
+{
+	static Device_Error clnt_res;
+
+	memset((char *)&clnt_res, 0, sizeof(clnt_res));
+	if (clnt_call (clnt, device_clear,
+		(xdrproc_t) xdr_Device_GenericParms, (caddr_t) argp,
+		(xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
+		TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&clnt_res);
+}
+
+Device_Error *
+device_remote_1(Device_GenericParms *argp, CLIENT *clnt)
+{
+	static Device_Error clnt_res;
+
+	memset((char *)&clnt_res, 0, sizeof(clnt_res));
+	if (clnt_call (clnt, device_remote,
+		(xdrproc_t) xdr_Device_GenericParms, (caddr_t) argp,
+		(xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
+		TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&clnt_res);
+}
+
+Device_Error *
+device_local_1(Device_GenericParms *argp, CLIENT *clnt)
+{
+	static Device_Error clnt_res;
+
+	memset((char *)&clnt_res, 0, sizeof(clnt_res));
+	if (clnt_call (clnt, device_local,
+		(xdrproc_t) xdr_Device_GenericParms, (caddr_t) argp,
+		(xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
+		TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&clnt_res);
+}
+
+Device_Error *
+device_lock_1(Device_LockParms *argp, CLIENT *clnt)
+{
+	static Device_Error clnt_res;
+
+	memset((char *)&clnt_res, 0, sizeof(clnt_res));
+	if (clnt_call (clnt, device_lock,
+		(xdrproc_t) xdr_Device_LockParms, (caddr_t) argp,
+		(xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
+		TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&clnt_res);
+}
+
+Device_Error *
+device_unlock_1(Device_Link *argp, CLIENT *clnt)
+{
+	static Device_Error clnt_res;
+
+	memset((char *)&clnt_res, 0, sizeof(clnt_res));
+	if (clnt_call (clnt, device_unlock,
+		(xdrproc_t) xdr_Device_Link, (caddr_t) argp,
+		(xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
+		TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&clnt_res);
+}
+
+Device_Error *
+device_enable_srq_1(Device_EnableSrqParms *argp, CLIENT *clnt)
+{
+	static Device_Error clnt_res;
+
+	memset((char *)&clnt_res, 0, sizeof(clnt_res));
+	if (clnt_call (clnt, device_enable_srq,
+		(xdrproc_t) xdr_Device_EnableSrqParms, (caddr_t) argp,
+		(xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
+		TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&clnt_res);
+}
+
+Device_DocmdResp *
+device_docmd_1(Device_DocmdParms *argp, CLIENT *clnt)
+{
+	static Device_DocmdResp clnt_res;
+
+	memset((char *)&clnt_res, 0, sizeof(clnt_res));
+	if (clnt_call (clnt, device_docmd,
+		(xdrproc_t) xdr_Device_DocmdParms, (caddr_t) argp,
+		(xdrproc_t) xdr_Device_DocmdResp, (caddr_t) &clnt_res,
+		TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&clnt_res);
+}
+
+Device_Error *
+destroy_link_1(Device_Link *argp, CLIENT *clnt)
+{
+	static Device_Error clnt_res;
+
+	memset((char *)&clnt_res, 0, sizeof(clnt_res));
+	if (clnt_call (clnt, destroy_link,
+		(xdrproc_t) xdr_Device_Link, (caddr_t) argp,
+		(xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
+		TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&clnt_res);
+}
+
+Device_Error *
+create_intr_chan_1(Device_RemoteFunc *argp, CLIENT *clnt)
+{
+	static Device_Error clnt_res;
+
+	memset((char *)&clnt_res, 0, sizeof(clnt_res));
+	if (clnt_call (clnt, create_intr_chan,
+		(xdrproc_t) xdr_Device_RemoteFunc, (caddr_t) argp,
+		(xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
+		TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&clnt_res);
+}
+
+Device_Error *
+destroy_intr_chan_1(void *argp, CLIENT *clnt)
+{
+	static Device_Error clnt_res;
+
+	memset((char *)&clnt_res, 0, sizeof(clnt_res));
+	if (clnt_call (clnt, destroy_intr_chan,
+		(xdrproc_t) xdr_void, (caddr_t) argp,
+		(xdrproc_t) xdr_Device_Error, (caddr_t) &clnt_res,
+		TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return (&clnt_res);
+}
+
+void *
+device_intr_srq_1(Device_SrqParms *argp, CLIENT *clnt)
+{
+	static char clnt_res;
+
+	memset((char *)&clnt_res, 0, sizeof(clnt_res));
+	if (clnt_call (clnt, device_intr_srq,
+		(xdrproc_t) xdr_Device_SrqParms, (caddr_t) argp,
+		(xdrproc_t) xdr_void, (caddr_t) &clnt_res,
+		TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return ((void *)&clnt_res);
+}
diff --git a/hardware/common/vxi_xdr.c b/hardware/common/vxi_xdr.c
new file mode 100644
index 0000000..bc7d79f
--- /dev/null
+++ b/hardware/common/vxi_xdr.c
@@ -0,0 +1,428 @@
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#include "vxi.h"
+
+bool_t
+xdr_Device_Link (XDR *xdrs, Device_Link *objp)
+{
+	 if (!xdr_long (xdrs, objp))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_Device_AddrFamily (XDR *xdrs, Device_AddrFamily *objp)
+{
+	 if (!xdr_enum (xdrs, (enum_t *) objp))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_Device_Flags (XDR *xdrs, Device_Flags *objp)
+{
+	 if (!xdr_long (xdrs, objp))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_Device_ErrorCode (XDR *xdrs, Device_ErrorCode *objp)
+{
+	 if (!xdr_long (xdrs, objp))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_Device_Error (XDR *xdrs, Device_Error *objp)
+{
+	 if (!xdr_Device_ErrorCode (xdrs, &objp->error))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_Create_LinkParms (XDR *xdrs, Create_LinkParms *objp)
+{
+	register int32_t *buf;
+
+	if (xdrs->x_op == XDR_ENCODE) {
+		buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT);
+		if (buf == NULL) {
+			 if (!xdr_long (xdrs, &objp->clientId))
+				 return FALSE;
+			 if (!xdr_bool (xdrs, &objp->lockDevice))
+				 return FALSE;
+			 if (!xdr_u_long (xdrs, &objp->lock_timeout))
+				 return FALSE;
+
+		} else {
+		IXDR_PUT_LONG(buf, objp->clientId);
+		IXDR_PUT_BOOL(buf, objp->lockDevice);
+		IXDR_PUT_U_LONG(buf, objp->lock_timeout);
+		}
+		 if (!xdr_string (xdrs, &objp->device, ~0))
+			 return FALSE;
+		return TRUE;
+	} else if (xdrs->x_op == XDR_DECODE) {
+		buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT);
+		if (buf == NULL) {
+			 if (!xdr_long (xdrs, &objp->clientId))
+				 return FALSE;
+			 if (!xdr_bool (xdrs, &objp->lockDevice))
+				 return FALSE;
+			 if (!xdr_u_long (xdrs, &objp->lock_timeout))
+				 return FALSE;
+
+		} else {
+		objp->clientId = IXDR_GET_LONG(buf);
+		objp->lockDevice = IXDR_GET_BOOL(buf);
+		objp->lock_timeout = IXDR_GET_U_LONG(buf);
+		}
+		 if (!xdr_string (xdrs, &objp->device, ~0))
+			 return FALSE;
+	 return TRUE;
+	}
+
+	 if (!xdr_long (xdrs, &objp->clientId))
+		 return FALSE;
+	 if (!xdr_bool (xdrs, &objp->lockDevice))
+		 return FALSE;
+	 if (!xdr_u_long (xdrs, &objp->lock_timeout))
+		 return FALSE;
+	 if (!xdr_string (xdrs, &objp->device, ~0))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_Create_LinkResp (XDR *xdrs, Create_LinkResp *objp)
+{
+	 if (!xdr_Device_ErrorCode (xdrs, &objp->error))
+		 return FALSE;
+	 if (!xdr_Device_Link (xdrs, &objp->lid))
+		 return FALSE;
+	 if (!xdr_u_short (xdrs, &objp->abortPort))
+		 return FALSE;
+	 if (!xdr_u_long (xdrs, &objp->maxRecvSize))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_Device_WriteParms (XDR *xdrs, Device_WriteParms *objp)
+{
+	 if (!xdr_Device_Link (xdrs, &objp->lid))
+		 return FALSE;
+	 if (!xdr_u_long (xdrs, &objp->io_timeout))
+		 return FALSE;
+	 if (!xdr_u_long (xdrs, &objp->lock_timeout))
+		 return FALSE;
+	 if (!xdr_Device_Flags (xdrs, &objp->flags))
+		 return FALSE;
+	 if (!xdr_bytes (xdrs, (char **)&objp->data.data_val, (u_int *) &objp->data.data_len, ~0))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_Device_WriteResp (XDR *xdrs, Device_WriteResp *objp)
+{
+	 if (!xdr_Device_ErrorCode (xdrs, &objp->error))
+		 return FALSE;
+	 if (!xdr_u_long (xdrs, &objp->size))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_Device_ReadParms (XDR *xdrs, Device_ReadParms *objp)
+{
+	register int32_t *buf;
+
+	if (xdrs->x_op == XDR_ENCODE) {
+		 if (!xdr_Device_Link (xdrs, &objp->lid))
+			 return FALSE;
+		buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT);
+		if (buf == NULL) {
+			 if (!xdr_u_long (xdrs, &objp->requestSize))
+				 return FALSE;
+			 if (!xdr_u_long (xdrs, &objp->io_timeout))
+				 return FALSE;
+			 if (!xdr_u_long (xdrs, &objp->lock_timeout))
+				 return FALSE;
+
+		} else {
+		IXDR_PUT_U_LONG(buf, objp->requestSize);
+		IXDR_PUT_U_LONG(buf, objp->io_timeout);
+		IXDR_PUT_U_LONG(buf, objp->lock_timeout);
+		}
+		 if (!xdr_Device_Flags (xdrs, &objp->flags))
+			 return FALSE;
+		 if (!xdr_char (xdrs, &objp->termChar))
+			 return FALSE;
+		return TRUE;
+	} else if (xdrs->x_op == XDR_DECODE) {
+		 if (!xdr_Device_Link (xdrs, &objp->lid))
+			 return FALSE;
+		buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT);
+		if (buf == NULL) {
+			 if (!xdr_u_long (xdrs, &objp->requestSize))
+				 return FALSE;
+			 if (!xdr_u_long (xdrs, &objp->io_timeout))
+				 return FALSE;
+			 if (!xdr_u_long (xdrs, &objp->lock_timeout))
+				 return FALSE;
+
+		} else {
+		objp->requestSize = IXDR_GET_U_LONG(buf);
+		objp->io_timeout = IXDR_GET_U_LONG(buf);
+		objp->lock_timeout = IXDR_GET_U_LONG(buf);
+		}
+		 if (!xdr_Device_Flags (xdrs, &objp->flags))
+			 return FALSE;
+		 if (!xdr_char (xdrs, &objp->termChar))
+			 return FALSE;
+	 return TRUE;
+	}
+
+	 if (!xdr_Device_Link (xdrs, &objp->lid))
+		 return FALSE;
+	 if (!xdr_u_long (xdrs, &objp->requestSize))
+		 return FALSE;
+	 if (!xdr_u_long (xdrs, &objp->io_timeout))
+		 return FALSE;
+	 if (!xdr_u_long (xdrs, &objp->lock_timeout))
+		 return FALSE;
+	 if (!xdr_Device_Flags (xdrs, &objp->flags))
+		 return FALSE;
+	 if (!xdr_char (xdrs, &objp->termChar))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_Device_ReadResp (XDR *xdrs, Device_ReadResp *objp)
+{
+	 if (!xdr_Device_ErrorCode (xdrs, &objp->error))
+		 return FALSE;
+	 if (!xdr_long (xdrs, &objp->reason))
+		 return FALSE;
+	 if (!xdr_bytes (xdrs, (char **)&objp->data.data_val, (u_int *) &objp->data.data_len, ~0))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_Device_ReadStbResp (XDR *xdrs, Device_ReadStbResp *objp)
+{
+	 if (!xdr_Device_ErrorCode (xdrs, &objp->error))
+		 return FALSE;
+	 if (!xdr_u_char (xdrs, &objp->stb))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_Device_GenericParms (XDR *xdrs, Device_GenericParms *objp)
+{
+	 if (!xdr_Device_Link (xdrs, &objp->lid))
+		 return FALSE;
+	 if (!xdr_Device_Flags (xdrs, &objp->flags))
+		 return FALSE;
+	 if (!xdr_u_long (xdrs, &objp->lock_timeout))
+		 return FALSE;
+	 if (!xdr_u_long (xdrs, &objp->io_timeout))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_Device_RemoteFunc (XDR *xdrs, Device_RemoteFunc *objp)
+{
+	register int32_t *buf;
+
+	if (xdrs->x_op == XDR_ENCODE) {
+		buf = XDR_INLINE (xdrs, 4 * BYTES_PER_XDR_UNIT);
+		if (buf == NULL) {
+			 if (!xdr_u_long (xdrs, &objp->hostAddr))
+				 return FALSE;
+			 if (!xdr_u_short (xdrs, &objp->hostPort))
+				 return FALSE;
+			 if (!xdr_u_long (xdrs, &objp->progNum))
+				 return FALSE;
+			 if (!xdr_u_long (xdrs, &objp->progVers))
+				 return FALSE;
+
+		} else {
+		IXDR_PUT_U_LONG(buf, objp->hostAddr);
+		IXDR_PUT_U_SHORT(buf, objp->hostPort);
+		IXDR_PUT_U_LONG(buf, objp->progNum);
+		IXDR_PUT_U_LONG(buf, objp->progVers);
+		}
+		 if (!xdr_Device_AddrFamily (xdrs, &objp->progFamily))
+			 return FALSE;
+		return TRUE;
+	} else if (xdrs->x_op == XDR_DECODE) {
+		buf = XDR_INLINE (xdrs, 4 * BYTES_PER_XDR_UNIT);
+		if (buf == NULL) {
+			 if (!xdr_u_long (xdrs, &objp->hostAddr))
+				 return FALSE;
+			 if (!xdr_u_short (xdrs, &objp->hostPort))
+				 return FALSE;
+			 if (!xdr_u_long (xdrs, &objp->progNum))
+				 return FALSE;
+			 if (!xdr_u_long (xdrs, &objp->progVers))
+				 return FALSE;
+
+		} else {
+		objp->hostAddr = IXDR_GET_U_LONG(buf);
+		objp->hostPort = IXDR_GET_U_SHORT(buf);
+		objp->progNum = IXDR_GET_U_LONG(buf);
+		objp->progVers = IXDR_GET_U_LONG(buf);
+		}
+		 if (!xdr_Device_AddrFamily (xdrs, &objp->progFamily))
+			 return FALSE;
+	 return TRUE;
+	}
+
+	 if (!xdr_u_long (xdrs, &objp->hostAddr))
+		 return FALSE;
+	 if (!xdr_u_short (xdrs, &objp->hostPort))
+		 return FALSE;
+	 if (!xdr_u_long (xdrs, &objp->progNum))
+		 return FALSE;
+	 if (!xdr_u_long (xdrs, &objp->progVers))
+		 return FALSE;
+	 if (!xdr_Device_AddrFamily (xdrs, &objp->progFamily))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_Device_EnableSrqParms (XDR *xdrs, Device_EnableSrqParms *objp)
+{
+	 if (!xdr_Device_Link (xdrs, &objp->lid))
+		 return FALSE;
+	 if (!xdr_bool (xdrs, &objp->enable))
+		 return FALSE;
+	 if (!xdr_bytes (xdrs, (char **)&objp->handle.handle_val, (u_int *) &objp->handle.handle_len, 40))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_Device_LockParms (XDR *xdrs, Device_LockParms *objp)
+{
+	 if (!xdr_Device_Link (xdrs, &objp->lid))
+		 return FALSE;
+	 if (!xdr_Device_Flags (xdrs, &objp->flags))
+		 return FALSE;
+	 if (!xdr_u_long (xdrs, &objp->lock_timeout))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_Device_DocmdParms (XDR *xdrs, Device_DocmdParms *objp)
+{
+	register int32_t *buf;
+
+	if (xdrs->x_op == XDR_ENCODE) {
+		 if (!xdr_Device_Link (xdrs, &objp->lid))
+			 return FALSE;
+		 if (!xdr_Device_Flags (xdrs, &objp->flags))
+			 return FALSE;
+		buf = XDR_INLINE (xdrs, 5 * BYTES_PER_XDR_UNIT);
+		if (buf == NULL) {
+			 if (!xdr_u_long (xdrs, &objp->io_timeout))
+				 return FALSE;
+			 if (!xdr_u_long (xdrs, &objp->lock_timeout))
+				 return FALSE;
+			 if (!xdr_long (xdrs, &objp->cmd))
+				 return FALSE;
+			 if (!xdr_bool (xdrs, &objp->network_order))
+				 return FALSE;
+			 if (!xdr_long (xdrs, &objp->datasize))
+				 return FALSE;
+
+		} else {
+		IXDR_PUT_U_LONG(buf, objp->io_timeout);
+		IXDR_PUT_U_LONG(buf, objp->lock_timeout);
+		IXDR_PUT_LONG(buf, objp->cmd);
+		IXDR_PUT_BOOL(buf, objp->network_order);
+		IXDR_PUT_LONG(buf, objp->datasize);
+		}
+		 if (!xdr_bytes (xdrs, (char **)&objp->data_in.data_in_val, (u_int *) &objp->data_in.data_in_len, ~0))
+			 return FALSE;
+		return TRUE;
+	} else if (xdrs->x_op == XDR_DECODE) {
+		 if (!xdr_Device_Link (xdrs, &objp->lid))
+			 return FALSE;
+		 if (!xdr_Device_Flags (xdrs, &objp->flags))
+			 return FALSE;
+		buf = XDR_INLINE (xdrs, 5 * BYTES_PER_XDR_UNIT);
+		if (buf == NULL) {
+			 if (!xdr_u_long (xdrs, &objp->io_timeout))
+				 return FALSE;
+			 if (!xdr_u_long (xdrs, &objp->lock_timeout))
+				 return FALSE;
+			 if (!xdr_long (xdrs, &objp->cmd))
+				 return FALSE;
+			 if (!xdr_bool (xdrs, &objp->network_order))
+				 return FALSE;
+			 if (!xdr_long (xdrs, &objp->datasize))
+				 return FALSE;
+
+		} else {
+		objp->io_timeout = IXDR_GET_U_LONG(buf);
+		objp->lock_timeout = IXDR_GET_U_LONG(buf);
+		objp->cmd = IXDR_GET_LONG(buf);
+		objp->network_order = IXDR_GET_BOOL(buf);
+		objp->datasize = IXDR_GET_LONG(buf);
+		}
+		 if (!xdr_bytes (xdrs, (char **)&objp->data_in.data_in_val, (u_int *) &objp->data_in.data_in_len, ~0))
+			 return FALSE;
+	 return TRUE;
+	}
+
+	 if (!xdr_Device_Link (xdrs, &objp->lid))
+		 return FALSE;
+	 if (!xdr_Device_Flags (xdrs, &objp->flags))
+		 return FALSE;
+	 if (!xdr_u_long (xdrs, &objp->io_timeout))
+		 return FALSE;
+	 if (!xdr_u_long (xdrs, &objp->lock_timeout))
+		 return FALSE;
+	 if (!xdr_long (xdrs, &objp->cmd))
+		 return FALSE;
+	 if (!xdr_bool (xdrs, &objp->network_order))
+		 return FALSE;
+	 if (!xdr_long (xdrs, &objp->datasize))
+		 return FALSE;
+	 if (!xdr_bytes (xdrs, (char **)&objp->data_in.data_in_val, (u_int *) &objp->data_in.data_in_len, ~0))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_Device_DocmdResp (XDR *xdrs, Device_DocmdResp *objp)
+{
+	 if (!xdr_Device_ErrorCode (xdrs, &objp->error))
+		 return FALSE;
+	 if (!xdr_bytes (xdrs, (char **)&objp->data_out.data_out_val, (u_int *) &objp->data_out.data_out_len, ~0))
+		 return FALSE;
+	return TRUE;
+}
+
+bool_t
+xdr_Device_SrqParms (XDR *xdrs, Device_SrqParms *objp)
+{
+	 if (!xdr_bytes (xdrs, (char **)&objp->handle.handle_val, (u_int *) &objp->handle.handle_len, ~0))
+		 return FALSE;
+	return TRUE;
+}
diff --git a/hardware/conrad-digi-35-cpu/api.c b/hardware/conrad-digi-35-cpu/api.c
new file mode 100644
index 0000000..01adcef
--- /dev/null
+++ b/hardware/conrad-digi-35-cpu/api.c
@@ -0,0 +1,229 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Matthias Heidbrink <m-sigrok at heidbrink.biz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** @file
+ *  <em>Conrad DIGI 35 CPU</em> power supply driver
+ *  @internal
+ */
+
+#include "protocol.h"
+
+#define SERIALCOMM "9600/8n1"
+
+static const int32_t hwopts[] = {
+	SR_CONF_CONN,
+	SR_CONF_SERIALCOMM,
+};
+
+static const int32_t hwcaps[] = {
+	SR_CONF_POWER_SUPPLY,
+	SR_CONF_OUTPUT_VOLTAGE,
+	SR_CONF_OUTPUT_CURRENT,
+	/* There's no SR_CONF_OUTPUT_ENABLED; can't know/set status remotely. */
+	SR_CONF_OVER_CURRENT_PROTECTION,
+};
+
+SR_PRIV struct sr_dev_driver conrad_digi_35_cpu_driver_info;
+static struct sr_dev_driver *di = &conrad_digi_35_cpu_driver_info;
+
+static int init(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+	struct sr_dev_inst *sdi;
+	struct drv_context *drvc;
+	struct sr_config *src;
+	struct sr_channel *ch;
+	struct sr_serial_dev_inst *serial;
+	GSList *l, *devices;
+	const char *conn, *serialcomm;
+
+	devices = NULL;
+	drvc = di->priv;
+	drvc->instances = NULL;
+	conn = serialcomm = NULL;
+
+	for (l = options; l; l = l->next) {
+		src = l->data;
+		switch (src->key) {
+		case SR_CONF_CONN:
+			conn = g_variant_get_string(src->data, NULL);
+			break;
+		case SR_CONF_SERIALCOMM:
+			serialcomm = g_variant_get_string(src->data, NULL);
+			break;
+		}
+	}
+	if (!conn)
+		return NULL;
+	if (!serialcomm)
+		serialcomm = SERIALCOMM;
+
+	/*
+	 * We cannot scan for this device because it is write-only.
+	 * So just check that the port parameters are valid and assume that
+	 * the device is there.
+	 */
+
+	if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+		return NULL;
+
+	if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+		return NULL;
+
+	serial_flush(serial);
+	serial_close(serial);
+
+	sr_spew("Conrad DIGI 35 CPU assumed at %s.", conn);
+
+	if (!(sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, "Conrad", "DIGI 35 CPU", NULL)))
+		return NULL;
+
+	sdi->conn = serial;
+	sdi->priv = NULL;
+	sdi->driver = di;
+	if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "CH1")))
+		return NULL;
+	sdi->channels = g_slist_append(sdi->channels, ch);
+
+	drvc->instances = g_slist_append(drvc->instances, sdi);
+	devices = g_slist_append(devices, sdi);
+
+	return devices;
+}
+
+static GSList *dev_list(void)
+{
+	return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int cleanup(void)
+{
+	return std_dev_clear(di, NULL);
+}
+
+static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	int ret;
+	double dblval;
+
+	(void)cg;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	ret = SR_OK;
+	switch (key) {
+	case SR_CONF_OUTPUT_VOLTAGE:
+		dblval = g_variant_get_double(data);
+		if ((dblval < 0.0) || (dblval > 35.0)) {
+			sr_err("Voltage out of range (0 - 35.0)!");
+			return SR_ERR_ARG;
+		}
+		ret = send_msg1(sdi, 'V', (int) (dblval * 10 + 0.5));
+		break;
+	case SR_CONF_OUTPUT_CURRENT:
+		dblval = g_variant_get_double(data);
+		if ((dblval < 0.01) || (dblval > 2.55)) {
+			sr_err("Current out of range (0 - 2.55)!");
+			return SR_ERR_ARG;
+		}
+		ret = send_msg1(sdi, 'C', (int) (dblval * 100 + 0.5));
+		break;
+	/* No SR_CONF_OUTPUT_ENABLED :-( . */
+	case SR_CONF_OVER_CURRENT_PROTECTION:
+		if (g_variant_get_boolean(data))
+			ret = send_msg1(sdi, 'V', 900);
+		else /* Constant current mode */
+			ret = send_msg1(sdi, 'V', 901);
+		break;
+	default:
+		ret = SR_ERR_NA;
+	}
+
+	return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	int ret;
+
+	(void)sdi;
+	(void)cg;
+
+	ret = SR_OK;
+	switch (key) {
+	case SR_CONF_SCAN_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+		break;
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return ret;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+	(void)cb_data;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	(void)cb_data;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver conrad_digi_35_cpu_driver_info = {
+	.name = "conrad-digi-35-cpu",
+	.longname = "Conrad DIGI 35 CPU",
+	.api_version = 1,
+	.init = init,
+	.cleanup = cleanup,
+	.scan = scan,
+	.dev_list = dev_list,
+	.dev_clear = NULL,
+	.config_get = NULL,
+	.config_set = config_set,
+	.config_list = config_list,
+	.dev_open = std_serial_dev_open,
+	.dev_close = std_serial_dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/conrad-digi-35-cpu/protocol.c b/hardware/conrad-digi-35-cpu/protocol.c
new file mode 100644
index 0000000..7657b31
--- /dev/null
+++ b/hardware/conrad-digi-35-cpu/protocol.c
@@ -0,0 +1,63 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Matthias Heidbrink <m-sigrok at heidbrink.biz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * @file
+ * <em>Conrad DIGI 35 CPU</em> power supply driver
+ * @internal
+ */
+
+#include "protocol.h"
+
+/**
+ * Send command with parameter.
+ *
+ * @param[in] cmd Command
+ * @param[in] param Parameter (0..999, depending on command).
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_ARG Invalid argument.
+ * @retval SR_ERR Error.
+ */
+SR_PRIV int send_msg1(const struct sr_dev_inst *sdi, char cmd, int param)
+{
+	struct sr_serial_dev_inst *serial;
+	char buf[5];
+
+	if (!sdi || !(serial = sdi->conn))
+		return SR_ERR_ARG;
+
+	snprintf(buf, sizeof(buf), "%c%03d", cmd, param);
+	buf[4] = '\r';
+
+	sr_spew("send_msg1(): %c%c%c%c\\r", buf[0], buf[1], buf[2], buf[3]);
+
+	if (serial_write(serial, buf, sizeof(buf)) == -1) {
+		sr_err("Write error for cmd=%c: %d %s", cmd, errno, strerror(errno));
+		return SR_ERR;
+	}
+
+	/*
+	 * Wait 50ms to ensure that the device does not swallow any of the
+	 * following commands.
+	 */
+	g_usleep(50000);
+
+	return SR_OK;
+}
diff --git a/hardware/conrad-digi-35-cpu/protocol.h b/hardware/conrad-digi-35-cpu/protocol.h
new file mode 100644
index 0000000..fcde852
--- /dev/null
+++ b/hardware/conrad-digi-35-cpu/protocol.h
@@ -0,0 +1,40 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Matthias Heidbrink <m-sigrok at heidbrink.biz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * @file
+ * <em>Conrad DIGI 35 CPU</em> power supply driver
+ * @internal
+ */
+
+#ifndef LIBSIGROK_HARDWARE_CONRAD_DIGI_35_CPU_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_CONRAD_DIGI_35_CPU_PROTOCOL_H
+
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "conrad-digi-35-cpu"
+
+SR_PRIV int send_msg1(const struct sr_dev_inst *sdi, char cmd, int param);
+
+#endif
diff --git a/hardware/demo/demo.c b/hardware/demo/demo.c
new file mode 100644
index 0000000..1718f81
--- /dev/null
+++ b/hardware/demo/demo.c
@@ -0,0 +1,780 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010 Uwe Hermann <uwe at hermann-uwe.de>
+ * Copyright (C) 2011 Olivier Fauchon <olivier at aixmarseille.com>
+ * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <math.h>
+#ifdef _WIN32
+#include <io.h>
+#include <fcntl.h>
+#define pipe(fds) _pipe(fds, 4096, _O_BINARY)
+#endif
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "demo"
+
+#define DEFAULT_NUM_LOGIC_CHANNELS     8
+#define DEFAULT_NUM_ANALOG_CHANNELS    4
+
+/* The size in bytes of chunks to send through the session bus. */
+#define LOGIC_BUFSIZE        4096
+/* Size of the analog pattern space per channel. */
+#define ANALOG_BUFSIZE       4096
+
+#define ANALOG_AMPLITUDE 25
+#define ANALOG_SAMPLES_PER_PERIOD 20
+
+/* Logic patterns we can generate. */
+enum {
+	/**
+	 * Spells "sigrok" across 8 channels using '0's (with '1's as
+	 * "background") when displayed using the 'bits' output format.
+	 * The pattern is repeated every 8 channels, shifted to the right
+	 * in time by one bit.
+	 */
+	PATTERN_SIGROK,
+
+	/** Pseudo-random values on all channels. */
+	PATTERN_RANDOM,
+
+	/**
+	 * Incrementing number across 8 channels. The pattern is repeated
+	 * every 8 channels, shifted to the right in time by one bit.
+	 */
+	PATTERN_INC,
+
+	/** All channels have a low logic state. */
+	PATTERN_ALL_LOW,
+
+	/** All channels have a high logic state. */
+	PATTERN_ALL_HIGH,
+};
+
+/* Analog patterns we can generate. */
+enum {
+	/**
+	 * Square wave.
+	 */
+	PATTERN_SQUARE,
+	PATTERN_SINE,
+	PATTERN_TRIANGLE,
+	PATTERN_SAWTOOTH,
+};
+
+static const char *logic_pattern_str[] = {
+	"sigrok",
+	"random",
+	"incremental",
+	"all-low",
+	"all-high",
+};
+
+static const char *analog_pattern_str[] = {
+	"square",
+	"sine",
+	"triangle",
+	"sawtooth",
+};
+
+struct analog_gen {
+	int pattern;
+	float pattern_data[ANALOG_BUFSIZE];
+	unsigned int num_samples;
+	struct sr_datafeed_analog packet;
+};
+
+/* Private, per-device-instance driver context. */
+struct dev_context {
+	int pipe_fds[2];
+	GIOChannel *channel;
+	uint64_t cur_samplerate;
+	uint64_t limit_samples;
+	uint64_t limit_msec;
+	uint64_t logic_counter;
+	uint64_t analog_counter;
+	int64_t starttime;
+	uint64_t step;
+	/* Logic */
+	int32_t num_logic_channels;
+	unsigned int logic_unitsize;
+	/* There is only ever one logic channel group, so its pattern goes here. */
+	uint8_t logic_pattern;
+	unsigned char logic_data[LOGIC_BUFSIZE];
+	/* Analog */
+	int32_t num_analog_channels;
+	GSList *analog_channel_groups;
+};
+
+static const int32_t scanopts[] = {
+	SR_CONF_NUM_LOGIC_CHANNELS,
+	SR_CONF_NUM_ANALOG_CHANNELS,
+};
+
+static const int devopts[] = {
+	SR_CONF_LOGIC_ANALYZER,
+	SR_CONF_DEMO_DEV,
+	SR_CONF_SAMPLERATE,
+	SR_CONF_LIMIT_SAMPLES,
+	SR_CONF_LIMIT_MSEC,
+};
+
+static const int devopts_cg[] = {
+	SR_CONF_PATTERN_MODE,
+};
+
+static const uint64_t samplerates[] = {
+	SR_HZ(1),
+	SR_GHZ(1),
+	SR_HZ(1),
+};
+
+static uint8_t pattern_sigrok[] = {
+	0x4c, 0x92, 0x92, 0x92, 0x64, 0x00, 0x00, 0x00,
+	0x82, 0xfe, 0xfe, 0x82, 0x00, 0x00, 0x00, 0x00,
+	0x7c, 0x82, 0x82, 0x92, 0x74, 0x00, 0x00, 0x00,
+	0xfe, 0x12, 0x12, 0x32, 0xcc, 0x00, 0x00, 0x00,
+	0x7c, 0x82, 0x82, 0x82, 0x7c, 0x00, 0x00, 0x00,
+	0xfe, 0x10, 0x28, 0x44, 0x82, 0x00, 0x00, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0xbe, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+SR_PRIV struct sr_dev_driver demo_driver_info;
+static struct sr_dev_driver *di = &demo_driver_info;
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data);
+
+
+static int init(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static void generate_analog_pattern(const struct sr_channel_group *cg, uint64_t sample_rate)
+{
+	struct analog_gen *ag;
+	double t, frequency;
+	float value;
+	unsigned int num_samples, i;
+	int last_end;
+
+	ag = cg->priv;
+	num_samples = ANALOG_BUFSIZE / sizeof(float);
+
+	sr_dbg("Generating %s pattern for channel group %s",
+	       analog_pattern_str[ag->pattern], cg->name);
+
+	switch (ag->pattern) {
+	case PATTERN_SQUARE:
+		value = ANALOG_AMPLITUDE;
+		last_end = 0;
+		for (i = 0; i < num_samples; i++) {
+			if (i % 5 == 0)
+				value = -value;
+			if (i % 10 == 0)
+				last_end = i - 1;
+			ag->pattern_data[i] = value;
+		}
+		ag->num_samples = last_end;
+		break;
+
+	case PATTERN_SINE:
+		frequency = (double) sample_rate / ANALOG_SAMPLES_PER_PERIOD;
+
+		/* Make sure the number of samples we put out is an integer
+		 * multiple of our period size */
+		/* FIXME we actually need only one period. A ringbuffer would be
+		 * usefull here.*/
+		while (num_samples % ANALOG_SAMPLES_PER_PERIOD != 0)
+			num_samples--;
+
+		for (i = 0; i < num_samples; i++) {
+			t = (double) i / (double) sample_rate;
+			ag->pattern_data[i] = ANALOG_AMPLITUDE *
+						sin(2 * M_PI * frequency * t);
+		}
+
+		ag->num_samples = num_samples;
+		break;
+
+	case PATTERN_TRIANGLE:
+		frequency = (double) sample_rate / ANALOG_SAMPLES_PER_PERIOD;
+
+		while (num_samples % ANALOG_SAMPLES_PER_PERIOD != 0)
+			num_samples--;
+
+		for (i = 0; i < num_samples; i++) {
+			t = (double) i / (double) sample_rate;
+			ag->pattern_data[i] = (2 * ANALOG_AMPLITUDE / M_PI) *
+						asin(sin(2 * M_PI * frequency * t));
+		}
+
+		ag->num_samples = num_samples;
+		break;
+
+	case PATTERN_SAWTOOTH:
+		frequency = (double) sample_rate / ANALOG_SAMPLES_PER_PERIOD;
+
+		while (num_samples % ANALOG_SAMPLES_PER_PERIOD != 0)
+			num_samples--;
+
+		for (i = 0; i < num_samples; i++) {
+			t = (double) i / (double) sample_rate;
+			ag->pattern_data[i] = 2 * ANALOG_AMPLITUDE *
+						((t * frequency) - floor(0.5f + t * frequency));
+		}
+
+		ag->num_samples = num_samples;
+		break;
+	}
+}
+
+static GSList *scan(GSList *options)
+{
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_dev_inst *sdi;
+	struct sr_channel *ch;
+	struct sr_channel_group *cg;
+	struct sr_config *src;
+	struct analog_gen *ag;
+	GSList *devices, *l;
+	int num_logic_channels, num_analog_channels, pattern, i;
+	char channel_name[16];
+
+	drvc = di->priv;
+
+	num_logic_channels = DEFAULT_NUM_LOGIC_CHANNELS;
+	num_analog_channels = DEFAULT_NUM_ANALOG_CHANNELS;
+	for (l = options; l; l = l->next) {
+		src = l->data;
+		switch (src->key) {
+		case SR_CONF_NUM_LOGIC_CHANNELS:
+			num_logic_channels = g_variant_get_int32(src->data);
+			break;
+		case SR_CONF_NUM_ANALOG_CHANNELS:
+			num_analog_channels = g_variant_get_int32(src->data);
+			break;
+		}
+	}
+
+	devices = NULL;
+	sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, "Demo device", NULL, NULL);
+	if (!sdi) {
+		sr_err("Device instance creation failed.");
+		return NULL;
+	}
+	sdi->driver = di;
+
+	if (!(devc = g_try_malloc(sizeof(struct dev_context)))) {
+		sr_err("Device context malloc failed.");
+		return NULL;
+	}
+	devc->cur_samplerate = SR_KHZ(200);
+	devc->limit_samples = 0;
+	devc->limit_msec = 0;
+	devc->step = 0;
+	devc->num_logic_channels = num_logic_channels;
+	devc->logic_unitsize = (devc->num_logic_channels + 7) / 8;
+	devc->logic_pattern = PATTERN_SIGROK;
+	devc->num_analog_channels = num_analog_channels;
+	devc->analog_channel_groups = NULL;
+
+	/* Logic channels, all in one channel group. */
+	if (!(cg = g_try_malloc(sizeof(struct sr_channel_group))))
+		return NULL;
+	cg->name = g_strdup("Logic");
+	cg->channels = NULL;
+	cg->priv = NULL;
+	for (i = 0; i < num_logic_channels; i++) {
+		sprintf(channel_name, "D%d", i);
+		if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE, channel_name)))
+			return NULL;
+		sdi->channels = g_slist_append(sdi->channels, ch);
+		cg->channels = g_slist_append(cg->channels, ch);
+	}
+	sdi->channel_groups = g_slist_append(NULL, cg);
+
+	/* Analog channels, channel groups and pattern generators. */
+
+	pattern = 0;
+	for (i = 0; i < num_analog_channels; i++) {
+		sprintf(channel_name, "A%d", i);
+		if (!(ch = sr_channel_new(i + num_logic_channels,
+				SR_CHANNEL_ANALOG, TRUE, channel_name)))
+			return NULL;
+		sdi->channels = g_slist_append(sdi->channels, ch);
+
+		/* Every analog channel gets its own channel group. */
+		if (!(cg = g_try_malloc(sizeof(struct sr_channel_group))))
+			return NULL;
+		cg->name = g_strdup(channel_name);
+		cg->channels = g_slist_append(NULL, ch);
+
+		/* Every channel group gets a generator struct. */
+		if (!(ag = g_try_malloc(sizeof(struct analog_gen))))
+			return NULL;
+		ag->packet.channels = cg->channels;
+		ag->packet.mq = 0;
+		ag->packet.mqflags = 0;
+		ag->packet.unit = SR_UNIT_VOLT;
+		ag->packet.data = ag->pattern_data;
+		ag->pattern = pattern;
+		cg->priv = ag;
+
+		sdi->channel_groups = g_slist_append(sdi->channel_groups, cg);
+		devc->analog_channel_groups = g_slist_append(devc->analog_channel_groups, cg);
+
+		if (++pattern == ARRAY_SIZE(analog_pattern_str))
+			pattern = 0;
+	}
+
+	sdi->priv = devc;
+	devices = g_slist_append(devices, sdi);
+	drvc->instances = g_slist_append(drvc->instances, sdi);
+
+	return devices;
+}
+
+static GSList *dev_list(void)
+{
+	return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+	sdi->status = SR_ST_ACTIVE;
+
+	return SR_OK;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+	sdi->status = SR_ST_INACTIVE;
+
+	return SR_OK;
+}
+
+static int cleanup(void)
+{
+	return std_dev_clear(di, NULL);
+}
+
+static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	struct sr_channel *ch;
+	struct analog_gen *ag;
+	int pattern;
+
+	if (!sdi)
+		return SR_ERR_ARG;
+
+	devc = sdi->priv;
+	switch (id) {
+	case SR_CONF_SAMPLERATE:
+		*data = g_variant_new_uint64(devc->cur_samplerate);
+		break;
+	case SR_CONF_LIMIT_SAMPLES:
+		*data = g_variant_new_uint64(devc->limit_samples);
+		break;
+	case SR_CONF_LIMIT_MSEC:
+		*data = g_variant_new_uint64(devc->limit_msec);
+		break;
+	case SR_CONF_PATTERN_MODE:
+		if (!cg)
+			return SR_ERR_CHANNEL_GROUP;
+		ch = cg->channels->data;
+		if (ch->type == SR_CHANNEL_LOGIC) {
+			pattern = devc->logic_pattern;
+			*data = g_variant_new_string(logic_pattern_str[pattern]);
+		} else if (ch->type == SR_CHANNEL_ANALOG) {
+			ag = cg->priv;
+			pattern = ag->pattern;
+			*data = g_variant_new_string(analog_pattern_str[pattern]);
+		} else
+			return SR_ERR_BUG;
+		break;
+	case SR_CONF_NUM_LOGIC_CHANNELS:
+		*data = g_variant_new_int32(devc->num_logic_channels);
+		break;
+	case SR_CONF_NUM_ANALOG_CHANNELS:
+		*data = g_variant_new_int32(devc->num_analog_channels);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	struct analog_gen *ag;
+	struct sr_channel *ch;
+	int pattern, ret;
+	unsigned int i;
+	const char *stropt;
+
+	devc = sdi->priv;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	ret = SR_OK;
+	switch (id) {
+	case SR_CONF_SAMPLERATE:
+		devc->cur_samplerate = g_variant_get_uint64(data);
+		sr_dbg("Setting samplerate to %" PRIu64, devc->cur_samplerate);
+		break;
+	case SR_CONF_LIMIT_SAMPLES:
+		devc->limit_msec = 0;
+		devc->limit_samples = g_variant_get_uint64(data);
+		sr_dbg("Setting sample limit to %" PRIu64, devc->limit_samples);
+		break;
+	case SR_CONF_LIMIT_MSEC:
+		devc->limit_msec = g_variant_get_uint64(data);
+		devc->limit_samples = 0;
+		sr_dbg("Setting time limit to %" PRIu64"ms", devc->limit_msec);
+		break;
+	case SR_CONF_PATTERN_MODE:
+		if (!cg)
+			return SR_ERR_CHANNEL_GROUP;
+		stropt = g_variant_get_string(data, NULL);
+		ch = cg->channels->data;
+		pattern = -1;
+		if (ch->type == SR_CHANNEL_LOGIC) {
+			for (i = 0; i < ARRAY_SIZE(logic_pattern_str); i++) {
+				if (!strcmp(stropt, logic_pattern_str[i])) {
+					pattern = i;
+					break;
+				}
+			}
+			if (pattern == -1)
+				return SR_ERR_ARG;
+			devc->logic_pattern = pattern;
+
+			/* Might as well do this now, these are static. */
+			if (pattern == PATTERN_ALL_LOW)
+				memset(devc->logic_data, 0x00, LOGIC_BUFSIZE);
+			else if (pattern == PATTERN_ALL_HIGH)
+				memset(devc->logic_data, 0xff, LOGIC_BUFSIZE);
+			sr_dbg("Setting logic pattern to %s",
+					logic_pattern_str[pattern]);
+		} else if (ch->type == SR_CHANNEL_ANALOG) {
+			for (i = 0; i < ARRAY_SIZE(analog_pattern_str); i++) {
+				if (!strcmp(stropt, analog_pattern_str[i])) {
+					pattern = i;
+					break;
+				}
+			}
+			if (pattern == -1)
+				return SR_ERR_ARG;
+			sr_dbg("Setting analog pattern for channel group %s to %s",
+					cg->name, analog_pattern_str[pattern]);
+			ag = cg->priv;
+			ag->pattern = pattern;
+		} else
+			return SR_ERR_BUG;
+		break;
+	default:
+		ret = SR_ERR_NA;
+	}
+
+	return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct sr_channel *ch;
+	GVariant *gvar;
+	GVariantBuilder gvb;
+
+	(void)sdi;
+
+	if (key == SR_CONF_SCAN_OPTIONS) {
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				scanopts, ARRAY_SIZE(scanopts), sizeof(int32_t));
+		return SR_OK;
+	}
+
+	if (!sdi)
+		return SR_ERR_ARG;
+
+	if (!cg) {
+		switch (key) {
+		case SR_CONF_DEVICE_OPTIONS:
+			*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+					devopts, ARRAY_SIZE(devopts), sizeof(int32_t));
+			break;
+		case SR_CONF_SAMPLERATE:
+			g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
+			gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), samplerates,
+					ARRAY_SIZE(samplerates), sizeof(uint64_t));
+			g_variant_builder_add(&gvb, "{sv}", "samplerate-steps", gvar);
+			*data = g_variant_builder_end(&gvb);
+			break;
+		default:
+			return SR_ERR_NA;
+		}
+	} else {
+		ch = cg->channels->data;
+		switch (key) {
+		case SR_CONF_DEVICE_OPTIONS:
+			*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+					devopts_cg, ARRAY_SIZE(devopts_cg), sizeof(int32_t));
+			break;
+		case SR_CONF_PATTERN_MODE:
+			if (ch->type == SR_CHANNEL_LOGIC)
+				*data = g_variant_new_strv(logic_pattern_str,
+						ARRAY_SIZE(logic_pattern_str));
+			else if (ch->type == SR_CHANNEL_ANALOG)
+				*data = g_variant_new_strv(analog_pattern_str,
+						ARRAY_SIZE(analog_pattern_str));
+			else
+				return SR_ERR_BUG;
+			break;
+		default:
+			return SR_ERR_NA;
+		}
+	}
+
+	return SR_OK;
+}
+
+static void logic_generator(struct sr_dev_inst *sdi, uint64_t size)
+{
+	struct dev_context *devc;
+	uint64_t i, j;
+	uint8_t pat;
+
+	devc = sdi->priv;
+
+	switch (devc->logic_pattern) {
+	case PATTERN_SIGROK:
+		memset(devc->logic_data, 0x00, size);
+		for (i = 0; i < size; i += devc->logic_unitsize) {
+			for (j = 0; j < devc->logic_unitsize; j++) {
+				pat = pattern_sigrok[(devc->step + j) % sizeof(pattern_sigrok)] >> 1;
+				devc->logic_data[i + j] = ~pat;
+			}
+			devc->step++;
+		}
+		break;
+	case PATTERN_RANDOM:
+		for (i = 0; i < size; i++)
+			devc->logic_data[i] = (uint8_t)(rand() & 0xff);
+		break;
+	case PATTERN_INC:
+		for (i = 0; i < size; i++) {
+			for (j = 0; j < devc->logic_unitsize; j++) {
+				devc->logic_data[i + j] = devc->step;
+			}
+			devc->step++;
+		}
+		break;
+	case PATTERN_ALL_LOW:
+	case PATTERN_ALL_HIGH:
+		/* These were set when the pattern mode was selected. */
+		break;
+	default:
+		sr_err("Unknown pattern: %d.", devc->logic_pattern);
+		break;
+	}
+}
+
+/* Callback handling data */
+static int prepare_data(int fd, int revents, void *cb_data)
+{
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_logic logic;
+	struct sr_channel_group *cg;
+	struct analog_gen *ag;
+	GSList *l;
+	uint64_t logic_todo, analog_todo, expected_samplenum, analog_samples, sending_now;
+	int64_t time, elapsed;
+
+	(void)fd;
+	(void)revents;
+
+	sdi = cb_data;
+	devc = sdi->priv;
+
+	/* How many "virtual" samples should we have collected by now? */
+	time = g_get_monotonic_time();
+	elapsed = time - devc->starttime;
+	expected_samplenum = elapsed * devc->cur_samplerate / 1000000;
+
+	/* Of those, how many do we still have to send? */
+	logic_todo = MIN(expected_samplenum, devc->limit_samples) - devc->logic_counter;
+	analog_todo = MIN(expected_samplenum, devc->limit_samples) - devc->analog_counter;
+
+	while (logic_todo || analog_todo) {
+		/* Logic */
+		if (devc->num_logic_channels > 0 && logic_todo > 0) {
+			sending_now = MIN(logic_todo,
+					LOGIC_BUFSIZE / devc->logic_unitsize);
+			logic_generator(sdi, sending_now * devc->logic_unitsize);
+			packet.type = SR_DF_LOGIC;
+			packet.payload = &logic;
+			logic.length = sending_now * devc->logic_unitsize;
+			logic.unitsize = devc->logic_unitsize;
+			logic.data = devc->logic_data;
+			sr_session_send(sdi, &packet);
+			logic_todo -= sending_now;
+			devc->logic_counter += sending_now;
+		}
+
+		/* Analog, one channel at a time */
+		if (devc->num_analog_channels > 0 && analog_todo > 0) {
+			sending_now = 0;
+			for (l = devc->analog_channel_groups; l; l = l->next) {
+				cg = l->data;
+				ag = cg->priv;
+				packet.type = SR_DF_ANALOG;
+				packet.payload = &ag->packet;
+
+				/* FIXME we should make sure we output a whole
+				 * period of data before we send out again the
+				 * beginning of our buffer. A ring buffer would
+				 * help here as well */
+
+				analog_samples = MIN(analog_todo, ag->num_samples);
+				/* Whichever channel group gets there first. */
+				sending_now = MAX(sending_now, analog_samples);
+				ag->packet.num_samples = analog_samples;
+				sr_session_send(sdi, &packet);
+			}
+			analog_todo -= sending_now;
+			devc->analog_counter += sending_now;
+		}
+	}
+
+	if (devc->logic_counter >= devc->limit_samples &&
+			devc->analog_counter >= devc->limit_samples) {
+		sr_dbg("Requested number of samples reached.");
+		dev_acquisition_stop(sdi, cb_data);
+		return TRUE;
+	}
+
+	return TRUE;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+	GSList *l;
+	struct dev_context *devc;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	devc = sdi->priv;
+	if (devc->limit_samples == 0)
+		return SR_ERR;
+	devc->logic_counter = devc->analog_counter = 0;
+
+	/*
+	 * Setting two channels connected by a pipe is a remnant from when the
+	 * demo driver generated data in a thread, and collected and sent the
+	 * data in the main program loop.
+	 * They are kept here because it provides a convenient way of setting
+	 * up a timeout-based polling mechanism.
+	 */
+	if (pipe(devc->pipe_fds)) {
+		sr_err("%s: pipe() failed", __func__);
+		return SR_ERR;
+	}
+
+	for (l = devc->analog_channel_groups; l; l = l->next) {
+		generate_analog_pattern(l->data, devc->cur_samplerate);
+	}
+
+	devc->channel = g_io_channel_unix_new(devc->pipe_fds[0]);
+
+	g_io_channel_set_flags(devc->channel, G_IO_FLAG_NONBLOCK, NULL);
+
+	/* Set channel encoding to binary (default is UTF-8). */
+	g_io_channel_set_encoding(devc->channel, NULL, NULL);
+
+	/* Make channels to unbuffered. */
+	g_io_channel_set_buffered(devc->channel, FALSE);
+
+	sr_session_source_add_channel(devc->channel, G_IO_IN | G_IO_ERR,
+			40, prepare_data, (void *)sdi);
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	/* We use this timestamp to decide how many more samples to send. */
+	devc->starttime = g_get_monotonic_time();
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct dev_context *devc;
+	struct sr_datafeed_packet packet;
+
+	(void)cb_data;
+
+	devc = sdi->priv;
+	sr_dbg("Stopping acquisition.");
+
+	sr_session_source_remove_channel(devc->channel);
+	g_io_channel_shutdown(devc->channel, FALSE, NULL);
+	g_io_channel_unref(devc->channel);
+	devc->channel = NULL;
+
+	/* Send last packet. */
+	packet.type = SR_DF_END;
+	sr_session_send(sdi, &packet);
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver demo_driver_info = {
+	.name = "demo",
+	.longname = "Demo driver and pattern generator",
+	.api_version = 1,
+	.init = init,
+	.cleanup = cleanup,
+	.scan = scan,
+	.dev_list = dev_list,
+	.dev_clear = NULL,
+	.config_get = config_get,
+	.config_set = config_set,
+	.config_list = config_list,
+	.dev_open = dev_open,
+	.dev_close = dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/fluke-dmm/api.c b/hardware/fluke-dmm/api.c
new file mode 100644
index 0000000..e0dee04
--- /dev/null
+++ b/hardware/fluke-dmm/api.c
@@ -0,0 +1,321 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "fluke-dmm.h"
+
+static const int32_t hwopts[] = {
+	SR_CONF_CONN,
+	SR_CONF_SERIALCOMM,
+};
+
+static const int32_t hwcaps[] = {
+	SR_CONF_MULTIMETER,
+	SR_CONF_LIMIT_SAMPLES,
+	SR_CONF_LIMIT_MSEC,
+	SR_CONF_CONTINUOUS,
+};
+
+SR_PRIV struct sr_dev_driver flukedmm_driver_info;
+static struct sr_dev_driver *di = &flukedmm_driver_info;
+
+static char *scan_conn[] = {
+	/* 287/289 */
+	"115200/8n1",
+	/* 187/189 */
+	"9600/8n1",
+	/* Scopemeter 190 series */
+	"1200/8n1",
+	NULL
+};
+
+static const struct flukedmm_profile supported_flukedmm[] = {
+	{ FLUKE_187, "187", 100, 1000 },
+	{ FLUKE_189, "189", 100, 1000 },
+	{ FLUKE_287, "287", 100, 1000 },
+	{ FLUKE_190, "199B", 1000, 3500 },
+};
+
+static int init(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *fluke_scan(const char *conn, const char *serialcomm)
+{
+	struct sr_dev_inst *sdi;
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_channel *ch;
+	struct sr_serial_dev_inst *serial;
+	GSList *devices;
+	int retry, len, i, s;
+	char buf[128], *b, **tokens;
+
+	if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+		return NULL;
+
+	if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+		return NULL;
+
+	drvc = di->priv;
+	b = buf;
+	retry = 0;
+	devices = NULL;
+	/* We'll try the discovery sequence three times in case the device
+	 * is not in an idle state when we send ID. */
+	while (!devices && retry < 3) {
+		retry++;
+		serial_flush(serial);
+		if (serial_write(serial, "ID\r", 3) == -1) {
+			sr_err("Unable to send ID string: %s.",
+			       strerror(errno));
+			continue;
+		}
+
+		/* Response is first a CMD_ACK byte (ASCII '0' for OK,
+		 * or '1' to signify an error. */
+		len = 128;
+		serial_readline(serial, &b, &len, 150);
+		if (len != 1)
+			continue;
+		if (buf[0] != '0')
+			continue;
+
+		/* If CMD_ACK was OK, ID string follows. */
+		len = 128;
+		serial_readline(serial, &b, &len, 850);
+		if (len < 10)
+			continue;
+		if (strcspn(buf, ",") < 15)
+			/* Looks like it's comma-separated. */
+			tokens = g_strsplit(buf, ",", 3);
+		else
+			/* Fluke 199B, at least, uses semicolon. */
+			tokens = g_strsplit(buf, ";", 3);
+		if (!strncmp("FLUKE", tokens[0], 5)
+				&& tokens[1] && tokens[2]) {
+			for (i = 0; supported_flukedmm[i].model; i++) {
+				if (strcmp(supported_flukedmm[i].modelname, tokens[0] + 6))
+					continue;
+				/* Skip leading spaces in version number. */
+				for (s = 0; tokens[1][s] == ' '; s++);
+				if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "Fluke",
+						tokens[0] + 6, tokens[1] + s)))
+					return NULL;
+				if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+					sr_err("Device context malloc failed.");
+					return NULL;
+				}
+				devc->profile = &supported_flukedmm[i];
+				sdi->inst_type = SR_INST_SERIAL;
+				sdi->conn = serial;
+				sdi->priv = devc;
+				sdi->driver = di;
+				if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
+					return NULL;
+				sdi->channels = g_slist_append(sdi->channels, ch);
+				drvc->instances = g_slist_append(drvc->instances, sdi);
+				devices = g_slist_append(devices, sdi);
+				break;
+			}
+		}
+		g_strfreev(tokens);
+		if (devices)
+			/* Found one. */
+			break;
+	}
+	serial_close(serial);
+	if (!devices)
+		sr_serial_dev_inst_free(serial);
+
+	return devices;
+}
+
+static GSList *scan(GSList *options)
+{
+	struct sr_config *src;
+	GSList *l, *devices;
+	int i;
+	const char *conn, *serialcomm;
+
+	conn = serialcomm = NULL;
+	for (l = options; l; l = l->next) {
+		src = l->data;
+		switch (src->key) {
+		case SR_CONF_CONN:
+			conn = g_variant_get_string(src->data, NULL);
+			break;
+		case SR_CONF_SERIALCOMM:
+			serialcomm = g_variant_get_string(src->data, NULL);
+			break;
+		}
+	}
+	if (!conn)
+		return NULL;
+
+	if (serialcomm) {
+		/* Use the provided comm specs. */
+		devices = fluke_scan(conn, serialcomm);
+	} else {
+		for (i = 0; scan_conn[i]; i++) {
+			if ((devices = fluke_scan(conn, scan_conn[i])))
+				break;
+			/* The Scopemeter 199B, at least, requires this
+			 * after all the 115k/9.6k confusion. */
+			g_usleep(5000);
+		}
+	}
+
+	return devices;
+}
+
+static GSList *dev_list(void)
+{
+	return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int cleanup(void)
+{
+	return std_dev_clear(di, NULL);
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+
+	(void)cg;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!(devc = sdi->priv)) {
+		sr_err("sdi->priv was NULL.");
+		return SR_ERR_BUG;
+	}
+
+	switch (id) {
+	case SR_CONF_LIMIT_MSEC:
+		/* TODO: not yet implemented */
+		if (g_variant_get_uint64(data) == 0) {
+			sr_err("LIMIT_MSEC can't be 0.");
+			return SR_ERR;
+		}
+		devc->limit_msec = g_variant_get_uint64(data);
+		sr_dbg("Setting time limit to %" PRIu64 "ms.",
+		       devc->limit_msec);
+		break;
+	case SR_CONF_LIMIT_SAMPLES:
+		devc->limit_samples = g_variant_get_uint64(data);
+		sr_dbg("Setting sample limit to %" PRIu64 ".",
+		       devc->limit_samples);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	(void)sdi;
+	(void)cg;
+
+	switch (key) {
+	case SR_CONF_SCAN_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+		break;
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!(devc = sdi->priv)) {
+		sr_err("sdi->priv was NULL.");
+		return SR_ERR_BUG;
+	}
+
+	devc->cb_data = cb_data;
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	/* Poll every 100ms, or whenever some data comes in. */
+	serial = sdi->conn;
+	serial_source_add(serial, G_IO_IN, 50, fluke_receive_data, (void *)sdi);
+
+	if (serial_write(serial, "QM\r", 3) == -1) {
+		sr_err("Unable to send QM: %s.", strerror(errno));
+		return SR_ERR;
+	}
+	devc->cmd_sent_at = g_get_monotonic_time() / 1000;
+	devc->expect_response = TRUE;
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close,
+			sdi->conn, LOG_PREFIX);
+}
+
+SR_PRIV struct sr_dev_driver flukedmm_driver_info = {
+	.name = "fluke-dmm",
+	.longname = "Fluke 18x/28x series DMMs",
+	.api_version = 1,
+	.init = init,
+	.cleanup = cleanup,
+	.scan = scan,
+	.dev_list = dev_list,
+	.dev_clear = NULL,
+	.config_get = NULL,
+	.config_set = config_set,
+	.config_list = config_list,
+	.dev_open = std_serial_dev_open,
+	.dev_close = std_serial_dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/fluke-dmm/fluke-dmm.h b/hardware/fluke-dmm/fluke-dmm.h
new file mode 100644
index 0000000..d162bdd
--- /dev/null
+++ b/hardware/fluke-dmm/fluke-dmm.h
@@ -0,0 +1,69 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_FLUKE_DMM_FLUKE_DMM_H
+#define LIBSIGROK_HARDWARE_FLUKE_DMM_FLUKE_DMM_H
+
+#define LOG_PREFIX "fluke-dmm"
+
+#define FLUKEDMM_BUFSIZE  256
+
+/* Supported models */
+enum {
+	FLUKE_187 = 1,
+	FLUKE_189,
+	FLUKE_287,
+	FLUKE_190,
+};
+
+/* Supported device profiles */
+struct flukedmm_profile {
+	int model;
+	const char *modelname;
+	/* How often to poll, in ms. */
+	int poll_period;
+	/* If no response received, how long to wait before retrying. */
+	int timeout;
+};
+
+/* Private, per-device-instance driver context. */
+struct dev_context {
+	const struct flukedmm_profile *profile;
+	uint64_t limit_samples;
+	uint64_t limit_msec;
+
+	/* Opaque pointer passed in by the frontend. */
+	void *cb_data;
+
+	/* Runtime. */
+	uint64_t num_samples;
+	char buf[FLUKEDMM_BUFSIZE];
+	int buflen;
+	int64_t cmd_sent_at;
+	int expect_response;
+	int meas_type;
+	int is_relative;
+	int mq;
+	int unit;
+	int mqflags;
+};
+
+SR_PRIV int fluke_receive_data(int fd, int revents, void *cb_data);
+
+#endif
diff --git a/hardware/fluke-dmm/fluke.c b/hardware/fluke-dmm/fluke.c
new file mode 100644
index 0000000..edb6734
--- /dev/null
+++ b/hardware/fluke-dmm/fluke.c
@@ -0,0 +1,536 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "fluke-dmm.h"
+
+static struct sr_datafeed_analog *handle_qm_18x(const struct sr_dev_inst *sdi,
+		char **tokens)
+{
+	struct sr_datafeed_analog *analog;
+	float fvalue;
+	char *e, *u;
+	gboolean is_oor;
+
+	if (strcmp(tokens[0], "QM") || !tokens[1])
+		return NULL;
+
+	if ((e = strstr(tokens[1], "Out of range"))) {
+		is_oor = TRUE;
+		fvalue = -1;
+		while(*e && *e != '.')
+			e++;
+	} else {
+		is_oor = FALSE;
+		/* Delimit the float, since sr_atof_ascii() wants only
+		 * a valid float here. */
+		e = tokens[1];
+		while(*e && *e != ' ')
+			e++;
+		*e++ = '\0';
+		if (sr_atof_ascii(tokens[1], &fvalue) != SR_OK || fvalue == 0.0) {
+			/* Happens all the time, when switching modes. */
+			sr_dbg("Invalid float.");
+			return NULL;
+		}
+	}
+	while(*e && *e == ' ')
+		e++;
+
+	if (!(analog = g_try_malloc0(sizeof(struct sr_datafeed_analog))))
+		return NULL;
+	if (!(analog->data = g_try_malloc(sizeof(float))))
+		return NULL;
+	analog->channels = sdi->channels;
+	analog->num_samples = 1;
+	if (is_oor)
+		*analog->data = NAN;
+	else
+		*analog->data = fvalue;
+	analog->mq = -1;
+
+	if ((u = strstr(e, "V DC")) || (u = strstr(e, "V AC"))) {
+		analog->mq = SR_MQ_VOLTAGE;
+		analog->unit = SR_UNIT_VOLT;
+		if (!is_oor && e[0] == 'm')
+			*analog->data /= 1000;
+		/* This catches "V AC", "V DC" and "V AC+DC". */
+		if (strstr(u, "AC"))
+			analog->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
+		if (strstr(u, "DC"))
+			analog->mqflags |= SR_MQFLAG_DC;
+	} else if ((u = strstr(e, "dBV")) || (u = strstr(e, "dBm"))) {
+		analog->mq = SR_MQ_VOLTAGE;
+		if (u[2] == 'm')
+			analog->unit = SR_UNIT_DECIBEL_MW;
+		else
+			analog->unit = SR_UNIT_DECIBEL_VOLT;
+		analog->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
+	} else if ((u = strstr(e, "Ohms"))) {
+		analog->mq = SR_MQ_RESISTANCE;
+		analog->unit = SR_UNIT_OHM;
+		if (is_oor)
+			*analog->data = INFINITY;
+		else if (e[0] == 'k')
+			*analog->data *= 1000;
+		else if (e[0] == 'M')
+			*analog->data *= 1000000;
+	} else if (!strcmp(e, "nS")) {
+		analog->mq = SR_MQ_CONDUCTANCE;
+		analog->unit = SR_UNIT_SIEMENS;
+		*analog->data /= 1e+9;
+	} else if ((u = strstr(e, "Farads"))) {
+		analog->mq = SR_MQ_CAPACITANCE;
+		analog->unit = SR_UNIT_FARAD;
+		if (!is_oor) {
+			if (e[0] == 'm')
+				*analog->data /= 1e+3;
+			else if (e[0] == 'u')
+				*analog->data /= 1e+6;
+			else if (e[0] == 'n')
+				*analog->data /= 1e+9;
+		}
+	} else if ((u = strstr(e, "Deg C")) || (u = strstr(e, "Deg F"))) {
+		analog->mq = SR_MQ_TEMPERATURE;
+		if (u[4] == 'C')
+			analog->unit = SR_UNIT_CELSIUS;
+		else
+			analog->unit = SR_UNIT_FAHRENHEIT;
+	} else if ((u = strstr(e, "A AC")) || (u = strstr(e, "A DC"))) {
+		analog->mq = SR_MQ_CURRENT;
+		analog->unit = SR_UNIT_AMPERE;
+		/* This catches "A AC", "A DC" and "A AC+DC". */
+		if (strstr(u, "AC"))
+			analog->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
+		if (strstr(u, "DC"))
+			analog->mqflags |= SR_MQFLAG_DC;
+		if (!is_oor) {
+			if (e[0] == 'm')
+				*analog->data /= 1e+3;
+			else if (e[0] == 'u')
+				*analog->data /= 1e+6;
+		}
+	} else if ((u = strstr(e, "Hz"))) {
+		analog->mq = SR_MQ_FREQUENCY;
+		analog->unit = SR_UNIT_HERTZ;
+		if (e[0] == 'k')
+			*analog->data *= 1e+3;
+	} else if (!strcmp(e, "%")) {
+		analog->mq = SR_MQ_DUTY_CYCLE;
+		analog->unit = SR_UNIT_PERCENTAGE;
+	} else if ((u = strstr(e, "ms"))) {
+		analog->mq = SR_MQ_PULSE_WIDTH;
+		analog->unit = SR_UNIT_SECOND;
+		*analog->data /= 1e+3;
+	}
+
+	if (analog->mq == -1) {
+		/* Not a valid measurement. */
+		g_free(analog->data);
+		g_free(analog);
+		analog = NULL;
+	}
+
+	return analog;
+}
+
+static struct sr_datafeed_analog *handle_qm_28x(const struct sr_dev_inst *sdi,
+		char **tokens)
+{
+	struct sr_datafeed_analog *analog;
+	float fvalue;
+
+	if (!tokens[1])
+		return NULL;
+
+	if (sr_atof_ascii(tokens[0], &fvalue) != SR_OK || fvalue == 0.0) {
+		sr_err("Invalid float '%s'.", tokens[0]);
+		return NULL;
+	}
+
+	if (!(analog = g_try_malloc0(sizeof(struct sr_datafeed_analog))))
+		return NULL;
+	if (!(analog->data = g_try_malloc(sizeof(float))))
+		return NULL;
+	analog->channels = sdi->channels;
+	analog->num_samples = 1;
+	*analog->data = fvalue;
+	analog->mq = -1;
+
+	if (!strcmp(tokens[1], "VAC") || !strcmp(tokens[1], "VDC")) {
+		analog->mq = SR_MQ_VOLTAGE;
+		analog->unit = SR_UNIT_VOLT;
+		if (!strcmp(tokens[2], "NORMAL")) {
+			if (tokens[1][1] == 'A') {
+				analog->mqflags |= SR_MQFLAG_AC;
+				analog->mqflags |= SR_MQFLAG_RMS;
+			} else
+				analog->mqflags |= SR_MQFLAG_DC;
+		} else if (!strcmp(tokens[2], "OL") || !strcmp(tokens[2], "OL_MINUS")) {
+			*analog->data = NAN;
+		} else
+			analog->mq = -1;
+	} else if (!strcmp(tokens[1], "dBV") || !strcmp(tokens[1], "dBm")) {
+		analog->mq = SR_MQ_VOLTAGE;
+		if (tokens[1][2] == 'm')
+			analog->unit = SR_UNIT_DECIBEL_MW;
+		else
+			analog->unit = SR_UNIT_DECIBEL_VOLT;
+		analog->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_RMS;
+	} else if (!strcmp(tokens[1], "CEL") || !strcmp(tokens[1], "FAR")) {
+		if (!strcmp(tokens[2], "NORMAL")) {
+			analog->mq = SR_MQ_TEMPERATURE;
+			if (tokens[1][0] == 'C')
+				analog->unit = SR_UNIT_CELSIUS;
+			else
+				analog->unit = SR_UNIT_FAHRENHEIT;
+		}
+	} else if (!strcmp(tokens[1], "OHM")) {
+		if (!strcmp(tokens[3], "NONE")) {
+			analog->mq = SR_MQ_RESISTANCE;
+			analog->unit = SR_UNIT_OHM;
+			if (!strcmp(tokens[2], "OL") || !strcmp(tokens[2], "OL_MINUS")) {
+				*analog->data = INFINITY;
+			} else if (strcmp(tokens[2], "NORMAL"))
+				analog->mq = -1;
+		} else if (!strcmp(tokens[3], "OPEN_CIRCUIT")) {
+			analog->mq = SR_MQ_CONTINUITY;
+			analog->unit = SR_UNIT_BOOLEAN;
+			*analog->data = 0.0;
+		} else if (!strcmp(tokens[3], "SHORT_CIRCUIT")) {
+			analog->mq = SR_MQ_CONTINUITY;
+			analog->unit = SR_UNIT_BOOLEAN;
+			*analog->data = 1.0;
+		}
+	} else if (!strcmp(tokens[1], "F")
+			&& !strcmp(tokens[2], "NORMAL")
+			&& !strcmp(tokens[3], "NONE")) {
+		analog->mq = SR_MQ_CAPACITANCE;
+		analog->unit = SR_UNIT_FARAD;
+	} else if (!strcmp(tokens[1], "AAC") || !strcmp(tokens[1], "ADC")) {
+		analog->mq = SR_MQ_CURRENT;
+		analog->unit = SR_UNIT_AMPERE;
+		if (!strcmp(tokens[2], "NORMAL")) {
+			if (tokens[1][1] == 'A') {
+				analog->mqflags |= SR_MQFLAG_AC;
+				analog->mqflags |= SR_MQFLAG_RMS;
+			} else
+				analog->mqflags |= SR_MQFLAG_DC;
+		} else if (!strcmp(tokens[2], "OL") || !strcmp(tokens[2], "OL_MINUS")) {
+			*analog->data = NAN;
+		} else
+			analog->mq = -1;
+	} if (!strcmp(tokens[1], "Hz") && !strcmp(tokens[2], "NORMAL")) {
+		analog->mq = SR_MQ_FREQUENCY;
+		analog->unit = SR_UNIT_HERTZ;
+	} else if (!strcmp(tokens[1], "PCT") && !strcmp(tokens[2], "NORMAL")) {
+		analog->mq = SR_MQ_DUTY_CYCLE;
+		analog->unit = SR_UNIT_PERCENTAGE;
+	} else if (!strcmp(tokens[1], "S") && !strcmp(tokens[2], "NORMAL")) {
+		analog->mq = SR_MQ_PULSE_WIDTH;
+		analog->unit = SR_UNIT_SECOND;
+	} else if (!strcmp(tokens[1], "SIE") && !strcmp(tokens[2], "NORMAL")) {
+		analog->mq = SR_MQ_CONDUCTANCE;
+		analog->unit = SR_UNIT_SIEMENS;
+	}
+
+	if (analog->mq == -1) {
+		/* Not a valid measurement. */
+		g_free(analog->data);
+		g_free(analog);
+		analog = NULL;
+	}
+
+	return analog;
+}
+
+static void handle_qm_19x_meta(const struct sr_dev_inst *sdi, char **tokens)
+{
+	struct dev_context *devc;
+	int meas_type, meas_unit, meas_char, i;
+
+	/* Make sure we have 7 valid tokens. */
+	for (i = 0; tokens[i] && i < 7; i++);
+	if (i != 7)
+		return;
+
+	if (strcmp(tokens[1], "1"))
+		/* Invalid measurement. */
+		return;
+
+	if (strcmp(tokens[2], "3"))
+		/* Only interested in input from the meter mode source. */
+		return;
+
+	devc = sdi->priv;
+
+	/* Measurement type 11 == absolute, 19 = relative */
+	meas_type = strtol(tokens[0], NULL, 10);
+	if (meas_type != 11 && meas_type != 19)
+		/* Device is in some mode we don't support. */
+		return;
+
+	/* We might get metadata for absolute and relative mode (if the device
+	 * is in relative mode). In that case, relative takes precedence. */
+	if (meas_type == 11 && devc->meas_type == 19)
+		return;
+
+	meas_unit = strtol(tokens[3], NULL, 10);
+	if (meas_unit == 0)
+		/* Device is turned off. Really. */
+		return;
+	meas_char = strtol(tokens[4], NULL, 10);
+
+	devc->mq = devc->unit = -1;
+	devc->mqflags = 0;
+	switch (meas_unit) {
+	case 1:
+		devc->mq = SR_MQ_VOLTAGE;
+		devc->unit = SR_UNIT_VOLT;
+		if (meas_char == 1)
+			devc->mqflags |= SR_MQFLAG_DC;
+		else if (meas_char == 2)
+			devc->mqflags |= SR_MQFLAG_AC;
+		else if (meas_char == 3)
+			devc->mqflags |= SR_MQFLAG_DC | SR_MQFLAG_AC;
+		else if (meas_char == 15)
+			devc->mqflags |= SR_MQFLAG_DIODE;
+		break;
+	case 2:
+		devc->mq = SR_MQ_CURRENT;
+		devc->unit = SR_UNIT_AMPERE;
+		if (meas_char == 1)
+			devc->mqflags |= SR_MQFLAG_DC;
+		else if (meas_char == 2)
+			devc->mqflags |= SR_MQFLAG_AC;
+		else if (meas_char == 3)
+			devc->mqflags |= SR_MQFLAG_DC | SR_MQFLAG_AC;
+		break;
+	case 3:
+		if (meas_char == 1) {
+			devc->mq = SR_MQ_RESISTANCE;
+			devc->unit = SR_UNIT_OHM;
+		} else if (meas_char == 16) {
+			devc->mq = SR_MQ_CONTINUITY;
+			devc->unit = SR_UNIT_BOOLEAN;
+		}
+		break;
+	case 12:
+		devc->mq = SR_MQ_TEMPERATURE;
+		devc->unit = SR_UNIT_CELSIUS;
+		break;
+	case 13:
+		devc->mq = SR_MQ_TEMPERATURE;
+		devc->unit = SR_UNIT_FAHRENHEIT;
+		break;
+	default:
+		sr_dbg("unknown unit: %d", meas_unit);
+	}
+	if (devc->mq == -1 && devc->unit == -1)
+		return;
+
+	/* If we got here, we know how to interpret the measurement. */
+	devc->meas_type = meas_type;
+	if (meas_type == 11)
+		/* Absolute meter reading. */
+		devc->is_relative = FALSE;
+	else if (!strcmp(tokens[0], "19"))
+		/* Relative meter reading. */
+		devc->is_relative = TRUE;
+
+}
+
+static void handle_qm_19x_data(const struct sr_dev_inst *sdi, char **tokens)
+{
+	struct dev_context *devc;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_analog analog;
+	float fvalue;
+
+	if (!strcmp(tokens[0], "9.9E+37")) {
+		/* An invalid measurement shows up on the display as "OL", but
+		 * comes through like this. Since comparing 38-digit floats
+		 * is rather problematic, we'll cut through this here. */
+		fvalue = NAN;
+	} else {
+		if (sr_atof_ascii(tokens[0], &fvalue) != SR_OK || fvalue == 0.0) {
+			sr_err("Invalid float '%s'.", tokens[0]);
+			return;
+		}
+	}
+
+	devc = sdi->priv;
+	if (devc->mq == -1 || devc->unit == -1)
+		/* Don't have valid metadata yet. */
+		return;
+
+
+	if (devc->mq == SR_MQ_RESISTANCE && isnan(fvalue))
+		fvalue = INFINITY;
+	else if (devc->mq == SR_MQ_CONTINUITY) {
+		if (isnan(fvalue))
+			fvalue = 0.0;
+		else
+			fvalue = 1.0;
+	}
+
+	analog.channels = sdi->channels;
+	analog.num_samples = 1;
+	analog.data = &fvalue;
+	analog.mq = devc->mq;
+	analog.unit = devc->unit;
+	analog.mqflags = 0;
+	packet.type = SR_DF_ANALOG;
+	packet.payload = &analog;
+	sr_session_send(devc->cb_data, &packet);
+	devc->num_samples++;
+
+}
+
+static void handle_line(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_analog *analog;
+	int num_tokens, n, i;
+	char cmd[16], **tokens;
+
+	devc = sdi->priv;
+	serial = sdi->conn;
+	sr_spew("Received line '%s' (%d).", devc->buf, devc->buflen);
+
+	if (devc->buflen == 1) {
+		if (devc->buf[0] != '0') {
+			/* Not just a CMD_ACK from the query command. */
+			sr_dbg("Got CMD_ACK '%c'.", devc->buf[0]);
+			devc->expect_response = FALSE;
+		}
+		devc->buflen = 0;
+		return;
+	}
+
+	analog = NULL;
+	tokens = g_strsplit(devc->buf, ",", 0);
+	if (tokens[0]) {
+		if (devc->profile->model == FLUKE_187 || devc->profile->model == FLUKE_189) {
+			devc->expect_response = FALSE;
+			analog = handle_qm_18x(sdi, tokens);
+		} else if (devc->profile->model == FLUKE_287) {
+			devc->expect_response = FALSE;
+			analog = handle_qm_28x(sdi, tokens);
+		} else if (devc->profile->model == FLUKE_190) {
+			devc->expect_response = FALSE;
+			for (num_tokens = 0; tokens[num_tokens]; num_tokens++);
+			if (num_tokens >= 7) {
+				/* Response to QM: this is a comma-separated list of
+				 * fields with metadata about the measurement. This
+				 * format can return multiple sets of metadata,
+				 * split into sets of 7 tokens each. */
+				devc->meas_type = 0;
+				for (i = 0; i < num_tokens; i += 7)
+					handle_qm_19x_meta(sdi, tokens + i);
+				if (devc->meas_type) {
+					/* Slip the request in now, before the main
+					 * timer loop asks for metadata again. */
+					n = sprintf(cmd, "QM %d\r", devc->meas_type);
+					if (serial_write(serial, cmd, n) == -1)
+						sr_err("Unable to send QM (measurement): %s.",
+								strerror(errno));
+				}
+			} else {
+				/* Response to QM <n> measurement request. */
+				handle_qm_19x_data(sdi, tokens);
+			}
+		}
+	}
+	g_strfreev(tokens);
+	devc->buflen = 0;
+
+	if (analog) {
+		/* Got a measurement. */
+		packet.type = SR_DF_ANALOG;
+		packet.payload = analog;
+		sr_session_send(devc->cb_data, &packet);
+		devc->num_samples++;
+		g_free(analog->data);
+		g_free(analog);
+	}
+
+}
+
+SR_PRIV int fluke_receive_data(int fd, int revents, void *cb_data)
+{
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+	int len;
+	int64_t now, elapsed;
+
+	(void)fd;
+
+	if (!(sdi = cb_data))
+		return TRUE;
+
+	if (!(devc = sdi->priv))
+		return TRUE;
+
+	serial = sdi->conn;
+	if (revents == G_IO_IN) {
+		/* Serial data arrived. */
+		while(FLUKEDMM_BUFSIZE - devc->buflen - 1 > 0) {
+			len = serial_read(serial, devc->buf + devc->buflen, 1);
+			if (len < 1)
+				break;
+			devc->buflen++;
+			*(devc->buf + devc->buflen) = '\0';
+			if (*(devc->buf + devc->buflen - 1) == '\r') {
+				*(devc->buf + --devc->buflen) = '\0';
+				handle_line(sdi);
+				break;
+			}
+		}
+	}
+
+	if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
+		sdi->driver->dev_acquisition_stop(sdi, cb_data);
+		return TRUE;
+	}
+
+	now = g_get_monotonic_time() / 1000;
+	elapsed = now - devc->cmd_sent_at;
+	/* Send query command at poll_period interval, or after 1 second
+	 * has elapsed. This will make it easier to recover from any
+	 * out-of-sync or temporary disconnect issues. */
+	if ((devc->expect_response == FALSE && elapsed > devc->profile->poll_period)
+			|| elapsed > devc->profile->timeout) {
+		if (serial_write(serial, "QM\r", 3) == -1)
+			sr_err("Unable to send QM: %s.", strerror(errno));
+		devc->cmd_sent_at = now;
+		devc->expect_response = TRUE;
+	}
+
+	return TRUE;
+}
diff --git a/hardware/fx2lafw/api.c b/hardware/fx2lafw/api.c
new file mode 100644
index 0000000..6b7f9fa
--- /dev/null
+++ b/hardware/fx2lafw/api.c
@@ -0,0 +1,608 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ * Copyright (C) 2012 Joel Holdsworth <joel at airwebreathe.org.uk>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "protocol.h"
+
+static const struct fx2lafw_profile supported_fx2[] = {
+	/*
+	 * CWAV USBee AX
+	 * EE Electronics ESLA201A
+	 * ARMFLY AX-Pro
+	 */
+	{ 0x08a9, 0x0014, "CWAV", "USBee AX", NULL,
+		FIRMWARE_DIR "/fx2lafw-cwav-usbeeax.fw",
+		0, NULL, NULL},
+	/*
+	 * CWAV USBee DX
+	 * XZL-Studio DX
+	 */
+	{ 0x08a9, 0x0015, "CWAV", "USBee DX", NULL,
+		FIRMWARE_DIR "/fx2lafw-cwav-usbeedx.fw",
+		DEV_CAPS_16BIT, NULL, NULL },
+
+	/*
+	 * CWAV USBee SX
+	 */
+	{ 0x08a9, 0x0009, "CWAV", "USBee SX", NULL,
+		FIRMWARE_DIR "/fx2lafw-cwav-usbeesx.fw",
+		0, NULL, NULL},
+
+	/*
+	 * Saleae Logic
+	 * EE Electronics ESLA100
+	 * Robomotic MiniLogic
+	 * Robomotic BugLogic 3
+	 */
+	{ 0x0925, 0x3881, "Saleae", "Logic", NULL,
+		FIRMWARE_DIR "/fx2lafw-saleae-logic.fw",
+		0, NULL, NULL},
+
+	/*
+	 * Default Cypress FX2 without EEPROM, e.g.:
+	 * Lcsoft Mini Board
+	 * Braintechnology USB Interface V2.x
+	 */
+	{ 0x04B4, 0x8613, "Cypress", "FX2", NULL,
+		FIRMWARE_DIR "/fx2lafw-cypress-fx2.fw",
+		DEV_CAPS_16BIT, NULL, NULL },
+
+	/*
+	 * Braintechnology USB-LPS
+	 */
+	{ 0x16d0, 0x0498, "Braintechnology", "USB-LPS", NULL,
+		FIRMWARE_DIR "/fx2lafw-braintechnology-usb-lps.fw",
+		DEV_CAPS_16BIT, NULL, NULL },
+
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+static const int32_t hwopts[] = {
+	SR_CONF_CONN,
+};
+
+static const int32_t hwcaps[] = {
+	SR_CONF_LOGIC_ANALYZER,
+	SR_CONF_TRIGGER_TYPE,
+	SR_CONF_SAMPLERATE,
+
+	/* These are really implemented in the driver, not the hardware. */
+	SR_CONF_LIMIT_SAMPLES,
+	SR_CONF_CONTINUOUS,
+};
+
+static const char *channel_names[] = {
+	"0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",
+	"8",  "9", "10", "11", "12", "13", "14", "15",
+	NULL,
+};
+
+static const uint64_t samplerates[] = {
+	SR_KHZ(20),
+	SR_KHZ(25),
+	SR_KHZ(50),
+	SR_KHZ(100),
+	SR_KHZ(200),
+	SR_KHZ(250),
+	SR_KHZ(500),
+	SR_MHZ(1),
+	SR_MHZ(2),
+	SR_MHZ(3),
+	SR_MHZ(4),
+	SR_MHZ(6),
+	SR_MHZ(8),
+	SR_MHZ(12),
+	SR_MHZ(16),
+	SR_MHZ(24),
+};
+
+SR_PRIV struct sr_dev_driver fx2lafw_driver_info;
+static struct sr_dev_driver *di = &fx2lafw_driver_info;
+
+static int init(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_dev_inst *sdi;
+	struct sr_usb_dev_inst *usb;
+	struct sr_channel *ch;
+	struct sr_config *src;
+	const struct fx2lafw_profile *prof;
+	GSList *l, *devices, *conn_devices;
+	struct libusb_device_descriptor des;
+	libusb_device **devlist;
+	struct libusb_device_handle *hdl;
+	int devcnt, num_logic_channels, ret, i, j;
+	const char *conn;
+	char manufacturer[64], product[64];
+
+	drvc = di->priv;
+
+	conn = NULL;
+	for (l = options; l; l = l->next) {
+		src = l->data;
+		switch (src->key) {
+		case SR_CONF_CONN:
+			conn = g_variant_get_string(src->data, NULL);
+			break;
+		}
+	}
+	if (conn)
+		conn_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn);
+	else
+		conn_devices = NULL;
+
+	/* Find all fx2lafw compatible devices and upload firmware to them. */
+	devices = NULL;
+	libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
+	for (i = 0; devlist[i]; i++) {
+		if (conn) {
+			usb = NULL;
+			for (l = conn_devices; l; l = l->next) {
+				usb = l->data;
+				if (usb->bus == libusb_get_bus_number(devlist[i])
+					&& usb->address == libusb_get_device_address(devlist[i]))
+					break;
+			}
+			if (!l)
+				/* This device matched none of the ones that
+				 * matched the conn specification. */
+				continue;
+		}
+
+		if ((ret = libusb_get_device_descriptor( devlist[i], &des)) != 0) {
+			sr_warn("Failed to get device descriptor: %s.",
+				libusb_error_name(ret));
+			continue;
+		}
+
+		if ((ret = libusb_open(devlist[i], &hdl)) < 0)
+			continue;
+
+		if (des.iManufacturer == 0) {
+			manufacturer[0] = '\0';
+		} else if ((ret = libusb_get_string_descriptor_ascii(hdl,
+				des.iManufacturer, (unsigned char *) manufacturer,
+				sizeof(manufacturer))) < 0) {
+			sr_warn("Failed to get manufacturer string descriptor: %s.",
+				libusb_error_name(ret));
+			continue;
+		}
+
+		if (des.iProduct == 0) {
+			product[0] = '\0';
+		} else if ((ret = libusb_get_string_descriptor_ascii(hdl,
+				des.iProduct, (unsigned char *) product,
+				sizeof(product))) < 0) {
+			sr_warn("Failed to get product string descriptor: %s.",
+				libusb_error_name(ret));
+			continue;
+		}
+
+		libusb_close(hdl);
+
+		prof = NULL;
+		for (j = 0; supported_fx2[j].vid; j++) {
+			if (des.idVendor == supported_fx2[j].vid &&
+					des.idProduct == supported_fx2[j].pid &&
+					(!supported_fx2[j].usb_manufacturer ||
+					 !strcmp(manufacturer, supported_fx2[j].usb_manufacturer)) &&
+					(!supported_fx2[j].usb_manufacturer ||
+					 !strcmp(product, supported_fx2[j].usb_product))) {
+				prof = &supported_fx2[j];
+				break;
+			}
+		}
+
+		/* Skip if the device was not found. */
+		if (!prof)
+			continue;
+
+		devcnt = g_slist_length(drvc->instances);
+		sdi = sr_dev_inst_new(devcnt, SR_ST_INITIALIZING,
+			prof->vendor, prof->model, prof->model_version);
+		if (!sdi)
+			return NULL;
+		sdi->driver = di;
+
+		/* Fill in channellist according to this device's profile. */
+		num_logic_channels = prof->dev_caps & DEV_CAPS_16BIT ? 16 : 8;
+		for (j = 0; j < num_logic_channels; j++) {
+			if (!(ch = sr_channel_new(j, SR_CHANNEL_LOGIC, TRUE,
+					channel_names[j])))
+				return NULL;
+			sdi->channels = g_slist_append(sdi->channels, ch);
+		}
+
+		devc = fx2lafw_dev_new();
+		devc->profile = prof;
+		sdi->priv = devc;
+		drvc->instances = g_slist_append(drvc->instances, sdi);
+		devices = g_slist_append(devices, sdi);
+
+		if (fx2lafw_check_conf_profile(devlist[i])) {
+			/* Already has the firmware, so fix the new address. */
+			sr_dbg("Found an fx2lafw device.");
+			sdi->status = SR_ST_INACTIVE;
+			sdi->inst_type = SR_INST_USB;
+			sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]),
+					libusb_get_device_address(devlist[i]), NULL);
+		} else {
+			if (ezusb_upload_firmware(devlist[i], USB_CONFIGURATION,
+				prof->firmware) == SR_OK)
+				/* Store when this device's FW was updated. */
+				devc->fw_updated = g_get_monotonic_time();
+			else
+				sr_err("Firmware upload failed for "
+				       "device %d.", devcnt);
+			sdi->inst_type = SR_INST_USB;
+			sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]),
+					0xff, NULL);
+		}
+	}
+	libusb_free_device_list(devlist, 1);
+	g_slist_free_full(conn_devices, (GDestroyNotify)sr_usb_dev_inst_free);
+
+	return devices;
+}
+
+static GSList *dev_list(void)
+{
+	return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+	struct sr_usb_dev_inst *usb;
+	struct dev_context *devc;
+	int ret;
+	int64_t timediff_us, timediff_ms;
+
+	devc = sdi->priv;
+	usb = sdi->conn;
+
+	/*
+	 * If the firmware was recently uploaded, wait up to MAX_RENUM_DELAY_MS
+	 * milliseconds for the FX2 to renumerate.
+	 */
+	ret = SR_ERR;
+	if (devc->fw_updated > 0) {
+		sr_info("Waiting for device to reset.");
+		/* Takes >= 300ms for the FX2 to be gone from the USB bus. */
+		g_usleep(300 * 1000);
+		timediff_ms = 0;
+		while (timediff_ms < MAX_RENUM_DELAY_MS) {
+			if ((ret = fx2lafw_dev_open(sdi, di)) == SR_OK)
+				break;
+			g_usleep(100 * 1000);
+
+			timediff_us = g_get_monotonic_time() - devc->fw_updated;
+			timediff_ms = timediff_us / 1000;
+			sr_spew("Waited %" PRIi64 "ms.", timediff_ms);
+		}
+		if (ret != SR_OK) {
+			sr_err("Device failed to renumerate.");
+			return SR_ERR;
+		}
+		sr_info("Device came back after %" PRIi64 "ms.", timediff_ms);
+	} else {
+		sr_info("Firmware upload was not needed.");
+		ret = fx2lafw_dev_open(sdi, di);
+	}
+
+	if (ret != SR_OK) {
+		sr_err("Unable to open device.");
+		return SR_ERR;
+	}
+
+	ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE);
+	if (ret != 0) {
+		switch (ret) {
+		case LIBUSB_ERROR_BUSY:
+			sr_err("Unable to claim USB interface. Another "
+			       "program or driver has already claimed it.");
+			break;
+		case LIBUSB_ERROR_NO_DEVICE:
+			sr_err("Device has been disconnected.");
+			break;
+		default:
+			sr_err("Unable to claim interface: %s.",
+			       libusb_error_name(ret));
+			break;
+		}
+
+		return SR_ERR;
+	}
+
+	if (devc->cur_samplerate == 0) {
+		/* Samplerate hasn't been set; default to the slowest one. */
+		devc->cur_samplerate = samplerates[0];
+	}
+
+	return SR_OK;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+	struct sr_usb_dev_inst *usb;
+
+	usb = sdi->conn;
+	if (usb->devhdl == NULL)
+		return SR_ERR;
+
+	sr_info("fx2lafw: Closing device %d on %d.%d interface %d.",
+		sdi->index, usb->bus, usb->address, USB_INTERFACE);
+	libusb_release_interface(usb->devhdl, USB_INTERFACE);
+	libusb_close(usb->devhdl);
+	usb->devhdl = NULL;
+	sdi->status = SR_ST_INACTIVE;
+
+	return SR_OK;
+}
+
+static int cleanup(void)
+{
+	int ret;
+	struct drv_context *drvc;
+
+	if (!(drvc = di->priv))
+		return SR_OK;
+
+
+	ret = std_dev_clear(di, NULL);
+
+	g_free(drvc);
+	di->priv = NULL;
+
+	return ret;
+}
+
+static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	struct sr_usb_dev_inst *usb;
+	char str[128];
+
+	(void)cg;
+
+	if (!sdi)
+		return SR_ERR_ARG;
+
+	devc = sdi->priv;
+
+	switch (id) {
+	case SR_CONF_CONN:
+		if (!sdi->conn)
+			return SR_ERR_ARG;
+		usb = sdi->conn;
+		if (usb->address == 255)
+			/* Device still needs to re-enumerate after firmware
+			 * upload, so we don't know its (future) address. */
+			return SR_ERR;
+		snprintf(str, 128, "%d.%d", usb->bus, usb->address);
+		*data = g_variant_new_string(str);
+		break;
+	case SR_CONF_LIMIT_SAMPLES:
+		*data = g_variant_new_uint64(devc->limit_samples);
+		break;
+	case SR_CONF_SAMPLERATE:
+		*data = g_variant_new_uint64(devc->cur_samplerate);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	int ret;
+
+	(void)cg;
+
+	if (!sdi)
+		return SR_ERR_ARG;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR;
+
+	devc = sdi->priv;
+
+	ret = SR_OK;
+
+	switch (id)
+	{
+		case SR_CONF_SAMPLERATE:
+			devc->cur_samplerate = g_variant_get_uint64(data);
+			break;
+		case SR_CONF_LIMIT_SAMPLES:
+			devc->limit_samples = g_variant_get_uint64(data);
+			break;
+		default:
+			ret = SR_ERR_NA;
+	}
+
+	return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	GVariant *gvar;
+	GVariantBuilder gvb;
+
+	(void)sdi;
+	(void)cg;
+
+	switch (key) {
+	case SR_CONF_SCAN_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+		break;
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+		break;
+	case SR_CONF_SAMPLERATE:
+		g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
+		gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), samplerates,
+				ARRAY_SIZE(samplerates), sizeof(uint64_t));
+		g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
+		*data = g_variant_builder_end(&gvb);
+		break;
+	case SR_CONF_TRIGGER_TYPE:
+		*data = g_variant_new_string(TRIGGER_TYPE);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int receive_data(int fd, int revents, void *cb_data)
+{
+	struct timeval tv;
+	struct drv_context *drvc;
+
+	(void)fd;
+	(void)revents;
+	(void)cb_data;
+
+	drvc = di->priv;
+
+	tv.tv_sec = tv.tv_usec = 0;
+	libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
+
+	return TRUE;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct dev_context *devc;
+	struct drv_context *drvc;
+	struct sr_usb_dev_inst *usb;
+	struct libusb_transfer *transfer;
+	unsigned int i, timeout, num_transfers;
+	int ret;
+	unsigned char *buf;
+	size_t size;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	drvc = di->priv;
+	devc = sdi->priv;
+	usb = sdi->conn;
+
+	/* Configures devc->trigger_* and devc->sample_wide */
+	if (fx2lafw_configure_channels(sdi) != SR_OK) {
+		sr_err("Failed to configure channels.");
+		return SR_ERR;
+	}
+
+	devc->cb_data = cb_data;
+	devc->sent_samples = 0;
+	devc->acq_aborted = FALSE;
+	devc->empty_transfer_count = 0;
+
+	timeout = fx2lafw_get_timeout(devc);
+	num_transfers = fx2lafw_get_number_of_transfers(devc);
+	size = fx2lafw_get_buffer_size(devc);
+	devc->submitted_transfers = 0;
+
+	devc->transfers = g_try_malloc0(sizeof(*devc->transfers) * num_transfers);
+	if (!devc->transfers) {
+		sr_err("USB transfers malloc failed.");
+		return SR_ERR_MALLOC;
+	}
+
+	devc->num_transfers = num_transfers;
+	for (i = 0; i < num_transfers; i++) {
+		if (!(buf = g_try_malloc(size))) {
+			sr_err("USB transfer buffer malloc failed.");
+			return SR_ERR_MALLOC;
+		}
+		transfer = libusb_alloc_transfer(0);
+		libusb_fill_bulk_transfer(transfer, usb->devhdl,
+				2 | LIBUSB_ENDPOINT_IN, buf, size,
+				fx2lafw_receive_transfer, devc, timeout);
+		if ((ret = libusb_submit_transfer(transfer)) != 0) {
+			sr_err("Failed to submit transfer: %s.",
+			       libusb_error_name(ret));
+			libusb_free_transfer(transfer);
+			g_free(buf);
+			fx2lafw_abort_acquisition(devc);
+			return SR_ERR;
+		}
+		devc->transfers[i] = transfer;
+		devc->submitted_transfers++;
+	}
+
+	devc->ctx = drvc->sr_ctx;
+
+	usb_source_add(devc->ctx, timeout, receive_data, NULL);
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	if ((ret = fx2lafw_command_start_acquisition(sdi)) != SR_OK) {
+		fx2lafw_abort_acquisition(devc);
+		return ret;
+	}
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	(void)cb_data;
+
+	fx2lafw_abort_acquisition(sdi->priv);
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver fx2lafw_driver_info = {
+	.name = "fx2lafw",
+	.longname = "fx2lafw (generic driver for FX2 based LAs)",
+	.api_version = 1,
+	.init = init,
+	.cleanup = cleanup,
+	.scan = scan,
+	.dev_list = dev_list,
+	.dev_clear = NULL,
+	.config_get = config_get,
+	.config_set = config_set,
+	.config_list = config_list,
+	.dev_open = dev_open,
+	.dev_close = dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/fx2lafw/protocol.c b/hardware/fx2lafw/protocol.c
new file mode 100644
index 0000000..45e7837
--- /dev/null
+++ b/hardware/fx2lafw/protocol.c
@@ -0,0 +1,617 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ * Copyright (C) 2012 Joel Holdsworth <joel at airwebreathe.org.uk>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "protocol.h"
+
+/* Protocol commands */
+#define CMD_GET_FW_VERSION		0xb0
+#define CMD_START			0xb1
+#define CMD_GET_REVID_VERSION		0xb2
+
+#define CMD_START_FLAGS_WIDE_POS	5
+#define CMD_START_FLAGS_CLK_SRC_POS	6
+
+#define CMD_START_FLAGS_SAMPLE_8BIT	(0 << CMD_START_FLAGS_WIDE_POS)
+#define CMD_START_FLAGS_SAMPLE_16BIT	(1 << CMD_START_FLAGS_WIDE_POS)
+
+#define CMD_START_FLAGS_CLK_30MHZ	(0 << CMD_START_FLAGS_CLK_SRC_POS)
+#define CMD_START_FLAGS_CLK_48MHZ	(1 << CMD_START_FLAGS_CLK_SRC_POS)
+
+#pragma pack(push, 1)
+
+struct version_info {
+	uint8_t major;
+	uint8_t minor;
+};
+
+struct cmd_start_acquisition {
+	uint8_t flags;
+	uint8_t sample_delay_h;
+	uint8_t sample_delay_l;
+};
+
+#pragma pack(pop)
+
+static int command_get_fw_version(libusb_device_handle *devhdl,
+				  struct version_info *vi)
+{
+	int ret;
+
+	ret = libusb_control_transfer(devhdl, LIBUSB_REQUEST_TYPE_VENDOR |
+		LIBUSB_ENDPOINT_IN, CMD_GET_FW_VERSION, 0x0000, 0x0000,
+		(unsigned char *)vi, sizeof(struct version_info), 100);
+
+	if (ret < 0) {
+		sr_err("Unable to get version info: %s.",
+		       libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+static int command_get_revid_version(struct sr_dev_inst *sdi, uint8_t *revid)
+{
+	struct sr_usb_dev_inst *usb = sdi->conn;
+	libusb_device_handle *devhdl = usb->devhdl;
+	int ret;
+
+	ret = libusb_control_transfer(devhdl, LIBUSB_REQUEST_TYPE_VENDOR |
+		LIBUSB_ENDPOINT_IN, CMD_GET_REVID_VERSION, 0x0000, 0x0000,
+		revid, 1, 100);
+
+	if (ret < 0) {
+		sr_err("Unable to get REVID: %s.", libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+SR_PRIV int fx2lafw_command_start_acquisition(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc = sdi->priv;
+	struct sr_usb_dev_inst *usb = sdi->conn;
+	libusb_device_handle *devhdl = usb->devhdl;
+	uint64_t samplerate = devc->cur_samplerate;
+	gboolean samplewide = devc->sample_wide;
+	struct cmd_start_acquisition cmd = { 0 };
+	int delay = 0, ret;
+
+	/* Compute the sample rate. */
+	if (samplewide && samplerate > MAX_16BIT_SAMPLE_RATE) {
+		sr_err("Unable to sample at %" PRIu64 "Hz "
+		       "when collecting 16-bit samples.", samplerate);
+		return SR_ERR;
+	}
+
+	if ((SR_MHZ(48) % samplerate) == 0) {
+		cmd.flags = CMD_START_FLAGS_CLK_48MHZ;
+		delay = SR_MHZ(48) / samplerate - 1;
+		if (delay > MAX_SAMPLE_DELAY)
+			delay = 0;
+	}
+
+	if (delay == 0 && (SR_MHZ(30) % samplerate) == 0) {
+		cmd.flags = CMD_START_FLAGS_CLK_30MHZ;
+		delay = SR_MHZ(30) / samplerate - 1;
+	}
+
+	sr_info("GPIF delay = %d, clocksource = %sMHz.", delay,
+		(cmd.flags & CMD_START_FLAGS_CLK_48MHZ) ? "48" : "30");
+
+	if (delay <= 0 || delay > MAX_SAMPLE_DELAY) {
+		sr_err("Unable to sample at %" PRIu64 "Hz.", samplerate);
+		return SR_ERR;
+	}
+
+	cmd.sample_delay_h = (delay >> 8) & 0xff;
+	cmd.sample_delay_l = delay & 0xff;
+
+	/* Select the sampling width. */
+	cmd.flags |= samplewide ? CMD_START_FLAGS_SAMPLE_16BIT :
+		CMD_START_FLAGS_SAMPLE_8BIT;
+
+	/* Send the control message. */
+	ret = libusb_control_transfer(devhdl, LIBUSB_REQUEST_TYPE_VENDOR |
+			LIBUSB_ENDPOINT_OUT, CMD_START, 0x0000, 0x0000,
+			(unsigned char *)&cmd, sizeof(cmd), 100);
+	if (ret < 0) {
+		sr_err("Unable to send start command: %s.",
+		       libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+/**
+ * Check the USB configuration to determine if this is an fx2lafw device.
+ *
+ * @return TRUE if the device's configuration profile match fx2lafw
+ *         configuration, FALSE otherwise.
+ */
+SR_PRIV gboolean fx2lafw_check_conf_profile(libusb_device *dev)
+{
+	struct libusb_device_descriptor des;
+	struct libusb_device_handle *hdl;
+	gboolean ret;
+	unsigned char strdesc[64];
+
+	hdl = NULL;
+	ret = FALSE;
+	while (!ret) {
+		/* Assume the FW has not been loaded, unless proven wrong. */
+		if (libusb_get_device_descriptor(dev, &des) != 0)
+			break;
+
+		if (libusb_open(dev, &hdl) != 0)
+			break;
+
+		if (libusb_get_string_descriptor_ascii(hdl,
+		    des.iManufacturer, strdesc, sizeof(strdesc)) < 0)
+			break;
+		if (strncmp((const char *)strdesc, "sigrok", 6))
+			break;
+
+		if (libusb_get_string_descriptor_ascii(hdl,
+				des.iProduct, strdesc, sizeof(strdesc)) < 0)
+			break;
+		if (strncmp((const char *)strdesc, "fx2lafw", 7))
+			break;
+
+		/* If we made it here, it must be an fx2lafw. */
+		ret = TRUE;
+	}
+	if (hdl)
+		libusb_close(hdl);
+
+	return ret;
+}
+
+SR_PRIV int fx2lafw_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di)
+{
+	libusb_device **devlist;
+	struct sr_usb_dev_inst *usb;
+	struct libusb_device_descriptor des;
+	struct dev_context *devc;
+	struct drv_context *drvc;
+	struct version_info vi;
+	int ret, skip, i, device_count;
+	uint8_t revid;
+
+	drvc = di->priv;
+	devc = sdi->priv;
+	usb = sdi->conn;
+
+	if (sdi->status == SR_ST_ACTIVE)
+		/* Device is already in use. */
+		return SR_ERR;
+
+	skip = 0;
+	device_count = libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
+	if (device_count < 0) {
+		sr_err("Failed to get device list: %s.",
+		       libusb_error_name(device_count));
+		return SR_ERR;
+	}
+
+	for (i = 0; i < device_count; i++) {
+		if ((ret = libusb_get_device_descriptor(devlist[i], &des))) {
+			sr_err("Failed to get device descriptor: %s.",
+			       libusb_error_name(ret));
+			continue;
+		}
+
+		if (des.idVendor != devc->profile->vid
+		    || des.idProduct != devc->profile->pid)
+			continue;
+
+		if (sdi->status == SR_ST_INITIALIZING) {
+			if (skip != sdi->index) {
+				/* Skip devices of this type that aren't the one we want. */
+				skip += 1;
+				continue;
+			}
+		} else if (sdi->status == SR_ST_INACTIVE) {
+			/*
+			 * This device is fully enumerated, so we need to find
+			 * this device by vendor, product, bus and address.
+			 */
+			if (libusb_get_bus_number(devlist[i]) != usb->bus
+				|| libusb_get_device_address(devlist[i]) != usb->address)
+				/* This is not the one. */
+				continue;
+		}
+
+		if (!(ret = libusb_open(devlist[i], &usb->devhdl))) {
+			if (usb->address == 0xff)
+				/*
+				 * First time we touch this device after FW
+				 * upload, so we don't know the address yet.
+				 */
+				usb->address = libusb_get_device_address(devlist[i]);
+		} else {
+			sr_err("Failed to open device: %s.",
+			       libusb_error_name(ret));
+			break;
+		}
+
+		ret = command_get_fw_version(usb->devhdl, &vi);
+		if (ret != SR_OK) {
+			sr_err("Failed to get firmware version.");
+			break;
+		}
+
+		ret = command_get_revid_version(sdi, &revid);
+		if (ret != SR_OK) {
+			sr_err("Failed to get REVID.");
+			break;
+		}
+
+		/*
+		 * Changes in major version mean incompatible/API changes, so
+		 * bail out if we encounter an incompatible version.
+		 * Different minor versions are OK, they should be compatible.
+		 */
+		if (vi.major != FX2LAFW_REQUIRED_VERSION_MAJOR) {
+			sr_err("Expected firmware version %d.x, "
+			       "got %d.%d.", FX2LAFW_REQUIRED_VERSION_MAJOR,
+			       vi.major, vi.minor);
+			break;
+		}
+
+		sdi->status = SR_ST_ACTIVE;
+		sr_info("Opened device %d on %d.%d, "
+			"interface %d, firmware %d.%d.",
+			sdi->index, usb->bus, usb->address,
+			USB_INTERFACE, vi.major, vi.minor);
+
+		sr_info("Detected REVID=%d, it's a Cypress CY7C68013%s.",
+			revid, (revid != 1) ? " (FX2)" : "A (FX2LP)");
+
+		break;
+	}
+	libusb_free_device_list(devlist, 1);
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR;
+
+	return SR_OK;
+}
+
+SR_PRIV int fx2lafw_configure_channels(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_channel *ch;
+	GSList *l;
+	int channel_bit, stage, i;
+	char *tc;
+
+	devc = sdi->priv;
+	for (i = 0; i < NUM_TRIGGER_STAGES; i++) {
+		devc->trigger_mask[i] = 0;
+		devc->trigger_value[i] = 0;
+	}
+
+	stage = -1;
+	for (l = sdi->channels; l; l = l->next) {
+		ch = (struct sr_channel *)l->data;
+		if (ch->enabled == FALSE)
+			continue;
+
+		if (ch->index > 7)
+			devc->sample_wide = TRUE;
+
+		channel_bit = 1 << (ch->index);
+		if (!(ch->trigger))
+			continue;
+
+		stage = 0;
+		for (tc = ch->trigger; *tc; tc++) {
+			devc->trigger_mask[stage] |= channel_bit;
+			if (*tc == '1')
+				devc->trigger_value[stage] |= channel_bit;
+			stage++;
+			if (stage > NUM_TRIGGER_STAGES)
+				return SR_ERR;
+		}
+	}
+
+	if (stage == -1) {
+		/*
+		 * We didn't configure any triggers, make sure acquisition
+		 * doesn't wait for any.
+		 */
+		devc->trigger_fired = TRUE;
+	} else {
+		devc->trigger_fired = FALSE;
+		devc->trigger_stage = 0;
+	}
+
+	return SR_OK;
+}
+
+SR_PRIV struct dev_context *fx2lafw_dev_new(void)
+{
+	struct dev_context *devc;
+
+	if (!(devc = g_try_malloc(sizeof(struct dev_context)))) {
+		sr_err("Device context malloc failed.");
+		return NULL;
+	}
+
+	devc->profile = NULL;
+	devc->fw_updated = 0;
+	devc->cur_samplerate = 0;
+	devc->limit_samples = 0;
+	devc->sample_wide = FALSE;
+
+	return devc;
+}
+
+SR_PRIV void fx2lafw_abort_acquisition(struct dev_context *devc)
+{
+	int i;
+
+	devc->acq_aborted = TRUE;
+
+	for (i = devc->num_transfers - 1; i >= 0; i--) {
+		if (devc->transfers[i])
+			libusb_cancel_transfer(devc->transfers[i]);
+	}
+}
+
+static void finish_acquisition(struct dev_context *devc)
+{
+	struct sr_datafeed_packet packet;
+
+	/* Terminate session. */
+	packet.type = SR_DF_END;
+	sr_session_send(devc->cb_data, &packet);
+
+	/* Remove fds from polling. */
+	usb_source_remove(devc->ctx);
+
+	devc->num_transfers = 0;
+	g_free(devc->transfers);
+}
+
+static void free_transfer(struct libusb_transfer *transfer)
+{
+	struct dev_context *devc;
+	unsigned int i;
+
+	devc = transfer->user_data;
+
+	g_free(transfer->buffer);
+	transfer->buffer = NULL;
+	libusb_free_transfer(transfer);
+
+	for (i = 0; i < devc->num_transfers; i++) {
+		if (devc->transfers[i] == transfer) {
+			devc->transfers[i] = NULL;
+			break;
+		}
+	}
+
+	devc->submitted_transfers--;
+	if (devc->submitted_transfers == 0)
+		finish_acquisition(devc);
+}
+
+static void resubmit_transfer(struct libusb_transfer *transfer)
+{
+	int ret;
+
+	if ((ret = libusb_submit_transfer(transfer)) == LIBUSB_SUCCESS)
+		return;
+
+	free_transfer(transfer);
+	/* TODO: Stop session? */
+
+	sr_err("%s: %s", __func__, libusb_error_name(ret));
+}
+
+SR_PRIV void fx2lafw_receive_transfer(struct libusb_transfer *transfer)
+{
+	gboolean packet_has_error = FALSE;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_logic logic;
+	struct dev_context *devc;
+	unsigned int trigger_offset, num_samples;
+	int cur_sample_count, sample_width, i;
+	uint8_t *cur_buf;
+	uint16_t cur_sample;
+
+	devc = transfer->user_data;
+
+	/*
+	 * If acquisition has already ended, just free any queued up
+	 * transfer that come in.
+	 */
+	if (devc->acq_aborted) {
+		free_transfer(transfer);
+		return;
+	}
+
+	sr_info("receive_transfer(): status %d received %d bytes.",
+		transfer->status, transfer->actual_length);
+
+	/* Save incoming transfer before reusing the transfer struct. */
+	cur_buf = transfer->buffer;
+	sample_width = devc->sample_wide ? 2 : 1;
+	cur_sample_count = transfer->actual_length / sample_width;
+
+	switch (transfer->status) {
+	case LIBUSB_TRANSFER_NO_DEVICE:
+		fx2lafw_abort_acquisition(devc);
+		free_transfer(transfer);
+		return;
+	case LIBUSB_TRANSFER_COMPLETED:
+	case LIBUSB_TRANSFER_TIMED_OUT: /* We may have received some data though. */
+		break;
+	default:
+		packet_has_error = TRUE;
+		break;
+	}
+
+	if (transfer->actual_length == 0 || packet_has_error) {
+		devc->empty_transfer_count++;
+		if (devc->empty_transfer_count > MAX_EMPTY_TRANSFERS) {
+			/*
+			 * The FX2 gave up. End the acquisition, the frontend
+			 * will work out that the samplecount is short.
+			 */
+			fx2lafw_abort_acquisition(devc);
+			free_transfer(transfer);
+		} else {
+			resubmit_transfer(transfer);
+		}
+		return;
+	} else {
+		devc->empty_transfer_count = 0;
+	}
+
+	trigger_offset = 0;
+	if (!devc->trigger_fired) {
+		for (i = 0; i < cur_sample_count; i++) {
+			cur_sample = devc->sample_wide ?
+				*((uint16_t *)cur_buf + i) :
+				*((uint8_t *)cur_buf + i);
+
+			if ((cur_sample & devc->trigger_mask[devc->trigger_stage]) ==
+				devc->trigger_value[devc->trigger_stage]) {
+				/* Match on this trigger stage. */
+				devc->trigger_buffer[devc->trigger_stage] = cur_sample;
+				devc->trigger_stage++;
+
+				if (devc->trigger_stage == NUM_TRIGGER_STAGES ||
+					devc->trigger_mask[devc->trigger_stage] == 0) {
+					/* Match on all trigger stages, we're done. */
+					trigger_offset = i;
+
+					/*
+					 * TODO: Send pre-trigger buffer to session bus.
+					 * Tell the frontend we hit the trigger here.
+					 */
+					packet.type = SR_DF_TRIGGER;
+					packet.payload = NULL;
+					sr_session_send(devc->cb_data, &packet);
+
+					/*
+					 * Send the samples that triggered it,
+					 * since we're skipping past them.
+					 */
+					packet.type = SR_DF_LOGIC;
+					packet.payload = &logic;
+					num_samples = cur_sample_count - trigger_offset;
+					if (devc->limit_samples &&
+							num_samples > devc->limit_samples - devc->sent_samples)
+						num_samples = devc->limit_samples - devc->sent_samples;
+					logic.length = num_samples * sample_width;
+					logic.unitsize = sample_width;
+					logic.data = cur_buf + trigger_offset * sample_width;
+					sr_session_send(devc->cb_data, &packet);
+					devc->sent_samples += num_samples;
+
+					devc->trigger_fired = TRUE;
+					break;
+				}
+			} else if (devc->trigger_stage > 0) {
+				/*
+				 * We had a match before, but not in the next sample. However, we may
+				 * have a match on this stage in the next bit -- trigger on 0001 will
+				 * fail on seeing 00001, so we need to go back to stage 0 -- but at
+				 * the next sample from the one that matched originally, which the
+				 * counter increment at the end of the loop takes care of.
+				 */
+				i -= devc->trigger_stage;
+				if (i < -1)
+					i = -1; /* Oops, went back past this buffer. */
+				/* Reset trigger stage. */
+				devc->trigger_stage = 0;
+			}
+		}
+	} else if (devc->sent_samples < devc->limit_samples) {
+		/* Send the incoming transfer to the session bus. */
+		packet.type = SR_DF_LOGIC;
+		packet.payload = &logic;
+		if (devc->sent_samples + cur_sample_count > devc->limit_samples)
+			num_samples = devc->limit_samples - devc->sent_samples;
+		else
+			num_samples = cur_sample_count;
+		logic.length = num_samples * sample_width;
+		logic.unitsize = sample_width;
+		logic.data = cur_buf;
+		sr_session_send(devc->cb_data, &packet);
+		devc->sent_samples += cur_sample_count;
+	}
+
+	if (devc->limit_samples && devc->sent_samples >= devc->limit_samples) {
+		fx2lafw_abort_acquisition(devc);
+		free_transfer(transfer);
+		return;
+	}
+
+	resubmit_transfer(transfer);
+}
+
+static unsigned int to_bytes_per_ms(unsigned int samplerate)
+{
+	return samplerate / 1000;
+}
+
+SR_PRIV size_t fx2lafw_get_buffer_size(struct dev_context *devc)
+{
+	size_t s;
+
+	/*
+	 * The buffer should be large enough to hold 10ms of data and
+	 * a multiple of 512.
+	 */
+	s = 10 * to_bytes_per_ms(devc->cur_samplerate);
+	return (s + 511) & ~511;
+}
+
+SR_PRIV unsigned int fx2lafw_get_number_of_transfers(struct dev_context *devc)
+{
+	unsigned int n;
+
+	/* Total buffer size should be able to hold about 500ms of data. */
+	n = (500 * to_bytes_per_ms(devc->cur_samplerate) /
+		fx2lafw_get_buffer_size(devc));
+
+	if (n > NUM_SIMUL_TRANSFERS)
+		return NUM_SIMUL_TRANSFERS;
+
+	return n;
+}
+
+SR_PRIV unsigned int fx2lafw_get_timeout(struct dev_context *devc)
+{
+	size_t total_size;
+	unsigned int timeout;
+
+	total_size = fx2lafw_get_buffer_size(devc) *
+			fx2lafw_get_number_of_transfers(devc);
+	timeout = total_size / to_bytes_per_ms(devc->cur_samplerate);
+	return timeout + timeout / 4; /* Leave a headroom of 25% percent. */
+}
diff --git a/hardware/fx2lafw/protocol.h b/hardware/fx2lafw/protocol.h
new file mode 100644
index 0000000..dfb6ef8
--- /dev/null
+++ b/hardware/fx2lafw/protocol.h
@@ -0,0 +1,115 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ * Copyright (C) 2012 Joel Holdsworth <joel at airwebreathe.org.uk>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_FX2LAFW_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_FX2LAFW_PROTOCOL_H
+
+#include <glib.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libusb.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "fx2lafw"
+
+#define USB_INTERFACE		0
+#define USB_CONFIGURATION	1
+#define NUM_TRIGGER_STAGES	4
+#define TRIGGER_TYPE 		"01"
+
+#define MAX_RENUM_DELAY_MS	3000
+#define NUM_SIMUL_TRANSFERS	32
+#define MAX_EMPTY_TRANSFERS	(NUM_SIMUL_TRANSFERS * 2)
+
+#define FX2LAFW_REQUIRED_VERSION_MAJOR	1
+
+#define MAX_8BIT_SAMPLE_RATE	SR_MHZ(24)
+#define MAX_16BIT_SAMPLE_RATE	SR_MHZ(12)
+
+/* 6 delay states of up to 256 clock ticks */
+#define MAX_SAMPLE_DELAY	(6 * 256)
+
+#define DEV_CAPS_16BIT_POS	0
+
+#define DEV_CAPS_16BIT		(1 << DEV_CAPS_16BIT_POS)
+
+struct fx2lafw_profile {
+	uint16_t vid;
+	uint16_t pid;
+
+	const char *vendor;
+	const char *model;
+	const char *model_version;
+
+	const char *firmware;
+
+	uint32_t dev_caps;
+
+	const char *usb_manufacturer;
+	const char *usb_product;
+};
+
+struct dev_context {
+	const struct fx2lafw_profile *profile;
+	/*
+	 * Since we can't keep track of an fx2lafw device after upgrading
+	 * the firmware (it renumerates into a different device address
+	 * after the upgrade) this is like a global lock. No device will open
+	 * until a proper delay after the last device was upgraded.
+	 */
+	int64_t fw_updated;
+
+	/* Device/capture settings */
+	uint64_t cur_samplerate;
+	uint64_t limit_samples;
+
+	/* Operational settings */
+	gboolean trigger_fired;
+	gboolean acq_aborted;
+	gboolean sample_wide;
+	uint16_t trigger_mask[NUM_TRIGGER_STAGES];
+	uint16_t trigger_value[NUM_TRIGGER_STAGES];
+	unsigned int trigger_stage;
+	uint16_t trigger_buffer[NUM_TRIGGER_STAGES];
+
+	unsigned int sent_samples;
+	int submitted_transfers;
+	int empty_transfer_count;
+
+	void *cb_data;
+	unsigned int num_transfers;
+	struct libusb_transfer **transfers;
+	struct sr_context *ctx;
+};
+
+SR_PRIV int fx2lafw_command_start_acquisition(const struct sr_dev_inst *sdi);
+SR_PRIV gboolean fx2lafw_check_conf_profile(libusb_device *dev);
+SR_PRIV int fx2lafw_dev_open(struct sr_dev_inst *sdi, struct sr_dev_driver *di);
+SR_PRIV int fx2lafw_configure_channels(const struct sr_dev_inst *sdi);
+SR_PRIV struct dev_context *fx2lafw_dev_new(void);
+SR_PRIV void fx2lafw_abort_acquisition(struct dev_context *devc);
+SR_PRIV void fx2lafw_receive_transfer(struct libusb_transfer *transfer);
+SR_PRIV size_t fx2lafw_get_buffer_size(struct dev_context *devc);
+SR_PRIV unsigned int fx2lafw_get_number_of_transfers(struct dev_context *devc);
+SR_PRIV unsigned int fx2lafw_get_timeout(struct dev_context *devc);
+
+#endif
diff --git a/hardware/gmc-mh-1x-2x/api.c b/hardware/gmc-mh-1x-2x/api.c
new file mode 100644
index 0000000..3c0a7aa
--- /dev/null
+++ b/hardware/gmc-mh-1x-2x/api.c
@@ -0,0 +1,618 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013, 2014 Matthias Heidbrink <m-sigrok at heidbrink.biz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** @file
+ *  Gossen Metrawatt Metrahit 1x/2x drivers
+ *  @internal
+ */
+
+#include <string.h>
+#include "protocol.h"
+
+/* Serial communication parameters for Metrahit 1x/2x with 'RS232' adaptor */
+#define SERIALCOMM_1X_RS232 "8228/6n1/dtr=1/rts=1/flow=0" /* =8192, closer with divider */
+#define SERIALCOMM_2X_RS232 "9600/6n1/dtr=1/rts=1/flow=0"
+#define SERIALCOMM_2X "9600/8n1/dtr=1/rts=1/flow=0"
+#define VENDOR_GMC "Gossen Metrawatt"
+
+SR_PRIV struct sr_dev_driver gmc_mh_1x_2x_rs232_driver_info;
+SR_PRIV struct sr_dev_driver gmc_mh_2x_bd232_driver_info;
+
+static const int32_t hwopts[] = {
+	SR_CONF_CONN,
+	SR_CONF_SERIALCOMM,
+};
+
+/** Hardware capabilities for Metrahit 1x/2x devices in send mode. */
+static const int32_t hwcaps_sm[] = {
+	SR_CONF_MULTIMETER,
+	SR_CONF_THERMOMETER,    /**< All GMC 1x/2x multimeters seem to support this */
+	SR_CONF_LIMIT_SAMPLES,
+	SR_CONF_LIMIT_MSEC,
+	SR_CONF_CONTINUOUS,
+};
+
+/** Hardware capabilities for Metrahit 2x devices in bidirectional Mode. */
+static const int32_t hwcaps_bd[] = {
+	SR_CONF_MULTIMETER,
+	SR_CONF_THERMOMETER,    /**< All GMC 1x/2x multimeters seem to support this */
+	SR_CONF_LIMIT_SAMPLES,
+	SR_CONF_LIMIT_MSEC,
+	SR_CONF_CONTINUOUS,
+	SR_CONF_POWER_OFF,
+};
+
+
+/* TODO:
+ * - For the 29S SR_CONF_ENERGYMETER, too.
+ * - SR_CONF_PATTERN_MODE for some 2x devices
+ * - SR_CONF_DATALOG for 22M, 26M, 29S and storage adaptors.
+ * Need to implement device-specific lists.
+ */
+
+/** Init driver gmc_mh_1x_2x_rs232. */
+static int init_1x_2x_rs232(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, &gmc_mh_1x_2x_rs232_driver_info, LOG_PREFIX);
+}
+
+/** Init driver gmc_mh_2x_bd232. */
+static int init_2x_bd232(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, &gmc_mh_2x_bd232_driver_info, LOG_PREFIX);
+}
+
+/**
+ * Read single byte from serial port.
+ *
+ * @retval -1 Timeout or error.
+ * @retval other Byte.
+ */
+static int read_byte(struct sr_serial_dev_inst *serial, gint64 timeout)
+{
+	uint8_t result = 0;
+	int rc = 0;
+
+	for (;;) {
+		rc = serial_read(serial, &result, 1);
+		if (rc == 1) {
+			sr_spew("read: 0x%02x/%d", result, result);
+			return result;
+		}
+		if (g_get_monotonic_time() > timeout)
+			return -1;
+		g_usleep(2000);
+	}
+}
+
+/**
+ * Try to detect GMC 1x/2x multimeter model in send mode for max. 1 second.
+ *
+ * @param serial Configured, open serial port.
+ *
+ * @retval NULL Detection failed.
+ * @retval other Model code.
+ */
+static enum model scan_model_sm(struct sr_serial_dev_inst *serial)
+{
+	int byte, bytecnt, cnt;
+	enum model model;
+	gint64 timeout_us;
+
+	model = METRAHIT_NONE;
+	timeout_us = g_get_monotonic_time() + 1 * 1000 * 1000;
+
+	/*
+	 * Try to find message consisting of device code and several
+	 * (at least 4) data bytes.
+	 */
+	for (bytecnt = 0; bytecnt < 100; bytecnt++) {
+		byte = read_byte(serial, timeout_us);
+		if ((byte == -1) || (timeout_us < g_get_monotonic_time()))
+			break;
+		if ((byte & MSGID_MASK) == MSGID_INF) {
+			if (!(model = gmc_decode_model_sm(byte & MSGC_MASK)))
+				break;
+			/* Now expect (at least) 4 data bytes. */
+			for (cnt = 0; cnt < 4; cnt++) {
+				byte = read_byte(serial, timeout_us);
+				if ((byte == -1) ||
+						((byte & MSGID_MASK) != MSGID_DATA))
+				{
+					model = METRAHIT_NONE;
+					bytecnt = 100;
+					break;
+				}
+			}
+			break;
+		}
+	}
+
+	return model;
+}
+
+/**
+ * Scan for Metrahit 1x and Metrahit 2x in send mode using Gossen Metrawatt
+ * 'RS232' interface.
+ *
+ * The older 1x models use 8192 baud and the newer 2x 9600 baud.
+ * The DMM usually sends up to about 20 messages per second. However, depending
+ * on configuration and measurement mode the intervals can be much larger and
+ * then the detection might not work.
+ */
+static GSList *scan_1x_2x_rs232(GSList *options)
+{
+	struct sr_dev_inst *sdi;
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_config *src;
+	struct sr_channel *ch;
+	struct sr_serial_dev_inst *serial;
+	GSList *l, *devices;
+	const char *conn, *serialcomm;
+	enum model model;
+	gboolean serialcomm_given;
+
+	devices = NULL;
+	drvc = (&gmc_mh_1x_2x_rs232_driver_info)->priv;
+	drvc->instances = NULL;
+	conn = serialcomm = NULL;
+	model = METRAHIT_NONE;
+	serialcomm_given = FALSE;
+
+	sr_spew("scan_1x_2x_rs232() called!");
+
+	for (l = options; l; l = l->next) {
+		src = l->data;
+		switch (src->key) {
+		case SR_CONF_CONN:
+			conn = g_variant_get_string(src->data, NULL);
+			break;
+		case SR_CONF_SERIALCOMM:
+			serialcomm = g_variant_get_string(src->data, NULL);
+			serialcomm_given = TRUE;
+			break;
+		}
+	}
+	if (!conn)
+		return NULL;
+	if (!serialcomm)
+		serialcomm = SERIALCOMM_2X_RS232;
+
+	if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+		return NULL;
+
+	if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK) {
+		sr_serial_dev_inst_free(serial);
+		return NULL;
+	}
+
+	serial_flush(serial);
+
+	model = scan_model_sm(serial);
+
+	/*
+	 * If detection failed and no user-supplied parameters,
+	 * try second baud rate.
+	 */
+	if ((model == METRAHIT_NONE) && !serialcomm_given) {
+		serialcomm = SERIALCOMM_1X_RS232;
+		g_free(serial->serialcomm);
+		serial->serialcomm = g_strdup(serialcomm);
+		if (serial_set_paramstr(serial, serialcomm) == SR_OK) {
+			serial_flush(serial);
+			model = scan_model_sm(serial);
+		}
+	}
+
+	if (model != METRAHIT_NONE) {
+		sr_spew("%s %s detected!", VENDOR_GMC, gmc_model_str(model));
+		if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, VENDOR_GMC,
+				gmc_model_str(model), NULL)))
+			return NULL;
+		if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+			sr_err("Device context malloc failed.");
+			return NULL;
+		}
+		devc->model = model;
+		devc->limit_samples = 0;
+		devc->limit_msec = 0;
+		devc->num_samples = 0;
+		devc->elapsed_msec = g_timer_new();
+		devc->settings_ok = FALSE;
+
+		sdi->conn = serial;
+		sdi->priv = devc;
+		sdi->driver = &gmc_mh_1x_2x_rs232_driver_info;
+		if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
+			return NULL;
+		sdi->channels = g_slist_append(sdi->channels, ch);
+		drvc->instances = g_slist_append(drvc->instances, sdi);
+		devices = g_slist_append(devices, sdi);
+	}
+
+	return devices;
+}
+
+/** Scan for Metrahit 2x in a bidirectional mode using Gossen Metrawatt 'BD 232' interface.
+ *
+ */
+static GSList *scan_2x_bd232(GSList *options)
+{
+	struct sr_dev_inst *sdi;
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_config *src;
+	struct sr_channel *ch;
+	struct sr_serial_dev_inst *serial;
+	GSList *l, *devices;
+	const char *conn, *serialcomm;
+	int cnt, byte;
+	gint64 timeout_us;
+
+	sdi = NULL;
+	devc = NULL;
+	conn = serialcomm = NULL;
+	devices = NULL;
+
+	drvc = (&gmc_mh_2x_bd232_driver_info)->priv;
+	drvc->instances = NULL;
+
+	sr_spew("scan_2x_bd232() called!");
+
+	for (l = options; l; l = l->next) {
+		src = l->data;
+		switch (src->key) {
+		case SR_CONF_CONN:
+			conn = g_variant_get_string(src->data, NULL);
+			break;
+		case SR_CONF_SERIALCOMM:
+			serialcomm = g_variant_get_string(src->data, NULL);
+			break;
+		}
+	}
+	if (!conn)
+		return NULL;
+	if (!serialcomm)
+		serialcomm = SERIALCOMM_2X;
+
+	if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+		return NULL;
+
+	if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+		goto exit_err;
+
+	if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+		sr_err("Device context malloc failed.");
+		goto exit_err;
+	}
+
+	if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, VENDOR_GMC, NULL, NULL)))
+		goto exit_err;
+
+	sdi->priv = devc;
+
+	/* Send message 03 "Query multimeter version and status" */
+	sdi->conn = serial;
+	sdi->priv = devc;
+	if (req_stat14(sdi, TRUE) != SR_OK)
+		goto exit_err;
+
+	/* Wait for reply from device(s) for up to 2s. */
+	timeout_us = g_get_monotonic_time() + 2*1000*1000;
+
+	while (timeout_us > g_get_monotonic_time()) {
+		/* Receive reply (14 bytes) */
+		devc->buflen = 0;
+		for (cnt = 0; cnt < 14; cnt++) {
+			byte = read_byte(serial, timeout_us);
+			if (byte != -1)
+				devc->buf[devc->buflen++] = (byte & MASK_6BITS);
+		}
+
+		if (devc->buflen != 14)
+			continue;
+
+		devc->addr = devc->buf[0];
+		process_msg14(sdi);
+		devc->buflen = 0;
+
+		if (devc->model != METRAHIT_NONE) {
+			sr_spew("%s %s detected!", VENDOR_GMC, gmc_model_str(devc->model));
+
+			devc->elapsed_msec = g_timer_new();
+
+			sdi->model = g_strdup(gmc_model_str(devc->model));
+			sdi->version = g_strdup_printf("Firmware %d.%d", devc->fw_ver_maj, devc->fw_ver_min);
+			sdi->conn = serial;
+			sdi->priv = devc;
+			sdi->driver = &gmc_mh_2x_bd232_driver_info;
+			if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
+				goto exit_err;
+			sdi->channels = g_slist_append(sdi->channels, ch);
+			drvc->instances = g_slist_append(drvc->instances, sdi);
+			devices = g_slist_append(devices, sdi);
+
+			if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+				sr_err("Device context malloc failed.");
+				goto exit_err;
+			}
+
+			if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, VENDOR_GMC, NULL, NULL)))
+				goto exit_err;
+		}
+	};
+
+	/* Free last alloc if no device found */
+	if (devc->model == METRAHIT_NONE) {
+		g_free(devc);
+		sr_dev_inst_free(sdi);
+	}
+
+	return devices;
+
+exit_err:
+	sr_info("scan_2x_bd232(): Error!");
+
+	if (serial)
+		sr_serial_dev_inst_free(serial);
+	if (devc)
+		g_free(devc);
+	if (sdi)
+		sr_dev_inst_free(sdi);
+
+	return NULL;
+}
+
+/** Driver device list function */
+static GSList *dev_list_1x_2x_rs232(void)
+{
+	return ((struct drv_context *)(gmc_mh_1x_2x_rs232_driver_info.priv))->instances;
+}
+
+/** Driver device list function */
+static GSList *dev_list_2x_bd232(void)
+{
+	return ((struct drv_context *)(gmc_mh_2x_bd232_driver_info.priv))
+			->instances;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+
+	std_serial_dev_close(sdi);
+
+	sdi->status = SR_ST_INACTIVE;
+
+	/* Free dynamically allocated resources. */
+	if ((devc = sdi->priv) && devc->elapsed_msec) {
+		g_timer_destroy(devc->elapsed_msec);
+		devc->elapsed_msec = NULL;
+		devc->model = METRAHIT_NONE;
+	}
+
+	return SR_OK;
+}
+
+static int cleanup_sm_rs232(void)
+{
+	return std_dev_clear(&gmc_mh_1x_2x_rs232_driver_info, NULL);
+}
+
+static int cleanup_2x_bd232(void)
+{
+	return std_dev_clear(&gmc_mh_2x_bd232_driver_info, NULL);
+}
+
+/** Get value of configuration item */
+static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		      const struct sr_channel_group *cg)
+{
+	int ret;
+	struct dev_context *devc;
+
+	(void)cg;
+
+	ret = SR_OK;
+
+	if (!sdi || !(devc = sdi->priv))
+		return SR_ERR_ARG;
+
+	ret = SR_OK;
+	switch (key) {
+	case SR_CONF_LIMIT_SAMPLES:
+		*data = g_variant_new_uint64(devc->limit_samples);
+		break;
+	case SR_CONF_LIMIT_MSEC:
+		*data = g_variant_new_uint64(devc->limit_msec);
+		break;
+	case SR_CONF_POWER_OFF:
+		*data = g_variant_new_boolean(FALSE);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return ret;
+}
+
+/** Implementation of config_list, auxiliary function for common parts, */
+static int config_list_common(int key, GVariant **data, const struct sr_dev_inst *sdi,
+			      const struct sr_channel_group *cg)
+{
+	(void)sdi;
+	(void)cg;
+
+	switch (key) {
+	case SR_CONF_SCAN_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+						  hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+/** Implementation of config_list for Metrahit 1x/2x send mode */
+static int config_list_sm(int key, GVariant **data, const struct sr_dev_inst *sdi,
+			  const struct sr_channel_group *cg)
+{
+	switch (key) {
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+						  hwcaps_sm, ARRAY_SIZE(hwcaps_sm), sizeof(int32_t));
+		break;
+	default:
+		return config_list_common(key, data, sdi, cg);
+	}
+
+	return SR_OK;
+}
+
+/** Implementation of config_list for Metrahit 2x bidirectional mode */
+static int config_list_bd(int key, GVariant **data, const struct sr_dev_inst *sdi,
+			  const struct sr_channel_group *cg)
+{
+	switch (key) {
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+						  hwcaps_bd, ARRAY_SIZE(hwcaps_bd), sizeof(int32_t));
+		break;
+	default:
+		return config_list_common(key, data, sdi, cg);
+	}
+
+	return SR_OK;
+}
+
+static int dev_acquisition_start_1x_2x_rs232(const struct sr_dev_inst *sdi,
+					     void *cb_data)
+{
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+
+	if (!sdi || !cb_data || !(devc = sdi->priv))
+		return SR_ERR_BUG;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	devc->cb_data = cb_data;
+	devc->settings_ok = FALSE;
+	devc->buflen = 0;
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	/* Start timer, if required. */
+	if (devc->limit_msec)
+		g_timer_start(devc->elapsed_msec);
+
+	/* Poll every 40ms, or whenever some data comes in. */
+	serial = sdi->conn;
+	serial_source_add(serial, G_IO_IN, 40, gmc_mh_1x_2x_receive_data,
+			  (void *)sdi);
+
+	return SR_OK;
+}
+
+static int dev_acquisition_start_2x_bd232(const struct sr_dev_inst *sdi,
+					  void *cb_data)
+{
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+
+	if (!sdi || !cb_data || !(devc = sdi->priv))
+		return SR_ERR_BUG;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	devc->cb_data = cb_data;
+	devc->settings_ok = FALSE;
+	devc->buflen = 0;
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	/* Start timer, if required. */
+	if (devc->limit_msec)
+		g_timer_start(devc->elapsed_msec);
+
+	/* Poll every 40ms, or whenever some data comes in. */
+	serial = sdi->conn;
+	serial_source_add(serial, G_IO_IN, 40, gmc_mh_2x_receive_data,
+			  (void *)sdi);
+
+	/* Send start message */
+	return req_meas14(sdi);
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct dev_context *devc;
+
+	/* Stop timer, if required. */
+	if (sdi && (devc = sdi->priv) && devc->limit_msec)
+		g_timer_stop(devc->elapsed_msec);
+
+	return std_serial_dev_acquisition_stop(sdi, cb_data, dev_close,
+			sdi->conn, LOG_PREFIX);
+}
+
+SR_PRIV struct sr_dev_driver gmc_mh_1x_2x_rs232_driver_info = {
+	.name = "gmc-mh-1x-2x-rs232",
+	.longname = "Gossen Metrawatt Metrahit 1x/2x, RS232 interface",
+	.api_version = 1,
+	.init = init_1x_2x_rs232,
+	.cleanup = cleanup_sm_rs232,
+	.scan = scan_1x_2x_rs232,
+	.dev_list = dev_list_1x_2x_rs232,
+	.dev_clear = NULL,
+	.config_get = config_get,
+	.config_set = config_set,
+	.config_list = config_list_sm,
+	.dev_open = std_serial_dev_open,
+	.dev_close = dev_close,
+	.dev_acquisition_start = dev_acquisition_start_1x_2x_rs232,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
+
+SR_PRIV struct sr_dev_driver gmc_mh_2x_bd232_driver_info = {
+	.name = "gmc-mh-2x-bd232",
+	.longname = "Gossen Metrawatt Metrahit 2x, BD232/SI232-II interface",
+	.api_version = 1,
+	.init = init_2x_bd232,
+	.cleanup = cleanup_2x_bd232,
+	.scan = scan_2x_bd232,
+	.dev_list = dev_list_2x_bd232,
+	.dev_clear = NULL,
+	.config_get = config_get,
+	.config_set = config_set,
+	.config_list = config_list_bd,
+	.dev_open = std_serial_dev_open,
+	.dev_close = dev_close,
+	.dev_acquisition_start = dev_acquisition_start_2x_bd232,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/gmc-mh-1x-2x/protocol.c b/hardware/gmc-mh-1x-2x/protocol.c
new file mode 100644
index 0000000..fc086a7
--- /dev/null
+++ b/hardware/gmc-mh-1x-2x/protocol.c
@@ -0,0 +1,1547 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013, 2014 Matthias Heidbrink <m-sigrok at heidbrink.biz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** @file
+ *  Gossen Metrawatt Metrahit 1x/2x drivers
+ *  @internal
+ */
+
+#include <math.h>
+#include <string.h>
+#include "protocol.h"
+
+/* Internal Headers */
+static guchar calc_chksum_14(guchar* dta);
+static int chk_msg14(struct sr_dev_inst *sdi);
+
+/** Set or clear flags in devc->mqflags. */
+static void setmqf(struct dev_context *devc, uint64_t flags, gboolean set)
+{
+	if (set)
+		devc->mqflags |= flags;
+	else
+		devc->mqflags &= ~flags;
+}
+
+/** Decode current type and measured value, Metrahit 12-16. */
+static void decode_ctmv_16(uint8_t ctmv, struct dev_context *devc)
+{
+	devc->mq = 0;
+	devc->unit = 0;
+	devc->mqflags = 0;
+
+	switch (ctmv) {
+	case 0x00: /* 0000 - */
+		break;
+	case 0x01: /* 0001 mV DC */
+		devc->scale1000 = -1; /* Fall through */
+	case 0x02: /* 0010 V DC */
+	case 0x03: /* 0011 V AC+DC */
+	case 0x04: /* 0100 V AC */
+		devc->mq = SR_MQ_VOLTAGE;
+		devc->unit = SR_UNIT_VOLT;
+		if (ctmv <= 0x03)
+			devc->mqflags |= SR_MQFLAG_DC;
+		if (ctmv >= 0x03) {
+			devc->mqflags |= SR_MQFLAG_AC;
+			if (devc->model >= METRAHIT_16S)
+				devc->mqflags |= SR_MQFLAG_RMS;
+		}
+		break;
+	case 0x05: /* 0101 Hz (15S/16S only) */
+	case 0x06: /* 0110 kHz (15S/16S only) */
+		devc->mq = SR_MQ_FREQUENCY;
+		devc->unit = SR_UNIT_HERTZ;
+		if (ctmv == 0x06)
+			devc->scale1000 = 1;
+		break;
+	case 0x07: /* 0111 % (15S/16S only) */
+		devc->mq = SR_MQ_DUTY_CYCLE;
+		devc->unit = SR_UNIT_PERCENTAGE;
+		break;
+	case 0x08: /* 1000 Diode */
+		devc->mq = SR_MQ_VOLTAGE;
+		devc->unit = SR_UNIT_VOLT;
+		devc->mqflags |= SR_MQFLAG_DIODE;
+		break;
+	case 0x09: /* 1001 Ohm, °C */
+	case 0x0a: /* 1010 kOhm */
+	case 0x0b: /* 1011 MOhm */
+		devc->mq = SR_MQ_RESISTANCE; /* Changed to temp. later if req.*/
+		devc->unit = SR_UNIT_OHM;
+		devc->scale1000 = ctmv - 0x09;
+		break;
+	case 0x0c: /* 1100 nF (15S/16S only) */
+	case 0x0d: /* 1101 µF (15S/16S only) */
+		devc->mq = SR_MQ_CAPACITANCE;
+		devc->unit = SR_UNIT_FARAD;
+		if (ctmv == 0x0c)
+			devc->scale1000 = -3;
+		else
+			devc->scale1000 = -2;
+		break;
+	case 0x0e: /* mA, µA */
+		devc->scale1000 = -1; /* Fall through. */
+	case 0x0f: /* A */
+		devc->mq = SR_MQ_CURRENT;
+		devc->unit = SR_UNIT_AMPERE;
+		if (devc->model == METRAHIT_16S)
+			devc->mqflags |= SR_MQFLAG_RMS;
+		/* 16I A only with clamp, RMS questionable. */
+		break;
+	}
+}
+
+/**
+ * Decode range/sign/acdc byte special chars (Metrahit 12-16).
+ *
+ * @param[in] rs Range and sign byte.
+ */
+static void decode_rs_16(uint8_t rs, struct dev_context *devc)
+{
+	sr_spew("decode_rs_16(%d) scale = %f", rs, devc->scale);
+
+	if (rs & 0x04) /* Sign */
+		devc->scale *= -1.0;
+
+	if (devc->mq == SR_MQ_CURRENT) {
+		if (rs & 0x08) /* Current is AC */
+			devc->mqflags |= SR_MQFLAG_AC;
+		else
+			devc->mqflags |= SR_MQFLAG_DC;
+	}
+
+	switch (rs & 0x03) {
+	case 0:
+		if (devc->mq == SR_MQ_VOLTAGE) /* V */
+			devc->scale *= 0.1;
+		else if (devc->mq == SR_MQ_CURRENT) /* 000.0 µA */
+			devc->scale *= 0.00001;
+		else if (devc->mq == SR_MQ_RESISTANCE) {
+			if (devc->buflen >= 10) {
+				/* °C with 10 byte msg type, otherwise GOhm. */
+				devc->mq = SR_MQ_TEMPERATURE;
+				devc->unit = SR_UNIT_CELSIUS;
+				devc->scale *= 0.01;
+			} else if (devc->scale1000 == 2) {
+				/* 16I Iso 500/1000V 3 GOhm */
+				devc->scale *= 0.1;
+			}
+		}
+		break;
+	case 1:
+		devc->scale *= 0.0001;
+		break;
+	case 2:
+		devc->scale *= 0.001;
+		break;
+	case 3:
+		devc->scale *= 0.01;
+		break;
+	}
+}
+
+/**
+ * Decode special chars, Metrahit 12-16.
+ *
+ * @param[in] spc Special characters 1 and 2 (s1 | (s2 << 4)).
+ */
+static void decode_spc_16(uint8_t spc, struct dev_context *devc)
+{
+	/* xxxx1xxx ON */
+	/* TODO: What does that mean? Power on? The 16I sets this. */
+	/* xxxxx1xx BEEP */
+	/* xxxxxx1x Low battery */
+	/* xxxxxxx1 FUSE */
+	/* 1xxxxxxx MIN */
+	setmqf(devc, SR_MQFLAG_MIN, spc & 0x80);
+
+	/* x1xxxxxx MAN */
+	setmqf(devc, SR_MQFLAG_AUTORANGE, !(spc & 0x40));
+
+	/* xx1xxxxx DATA */
+	setmqf(devc, SR_MQFLAG_HOLD, spc & 0x20);
+
+	/* xxx1xxxx MAX */
+	setmqf(devc, SR_MQFLAG_MAX, spc & 0x10);
+}
+
+/** Decode current type and measured value, Metrahit 18. */
+static void decode_ctmv_18(uint8_t ctmv, struct dev_context *devc)
+{
+	devc->mq = 0;
+	devc->unit = 0;
+	devc->mqflags = 0;
+
+	switch (ctmv) {
+	case 0x00: /* 0000 - */
+		break;
+	case 0x01: /* 0001 V AC */
+	case 0x02: /* 0010 V AC+DC */
+	case 0x03: /* 0011 V DC */
+		devc->mq = SR_MQ_VOLTAGE;
+		devc->unit = SR_UNIT_VOLT;
+		if (ctmv <= 0x02)
+			devc->mqflags |= (SR_MQFLAG_AC | SR_MQFLAG_RMS);
+		if (ctmv >= 0x02)
+			devc->mqflags |= SR_MQFLAG_DC;
+		break;
+	case 0x04: /* 0100 Ohm/Ohm with buzzer */
+		devc->mq = SR_MQ_RESISTANCE;
+		devc->unit = SR_UNIT_OHM;
+		break;
+	case 0x05: /* 0101 Diode/Diode with buzzer */
+		devc->mq = SR_MQ_VOLTAGE;
+		devc->unit = SR_UNIT_VOLT;
+		devc->mqflags |= SR_MQFLAG_DIODE;
+		break;
+	case 0x06: /* 0110 °C */
+		devc->mq = SR_MQ_TEMPERATURE;
+		devc->unit = SR_UNIT_CELSIUS;
+		break;
+	case 0x07: /* 0111 F */
+		devc->mq = SR_MQ_CAPACITANCE;
+		devc->unit = SR_UNIT_FARAD;
+		break;
+	case 0x08: /* 1000 mA DC */
+	case 0x09: /* 1001 A DC */
+	case 0x0a: /* 1010 mA AC+DC */
+	case 0x0b: /* 1011 A AC+DC */
+		devc->mq = SR_MQ_CURRENT;
+		devc->unit = SR_UNIT_AMPERE;
+		devc->mqflags |= SR_MQFLAG_DC;
+		if (ctmv >= 0x0a)
+			devc->mqflags |= (SR_MQFLAG_AC | SR_MQFLAG_RMS);
+		if ((ctmv == 0x08) || (ctmv == 0x0a))
+			devc->scale1000 = -1;
+		break;
+	case 0x0c: /* 1100 Hz */
+		devc->mq = SR_MQ_FREQUENCY;
+		devc->unit = SR_UNIT_HERTZ;
+		break;
+	case 0x0d: /* 1101 dB */
+		devc->mq = SR_MQ_VOLTAGE;
+		devc->unit = SR_UNIT_DECIBEL_VOLT;
+		devc->mqflags |= SR_MQFLAG_AC; /* dB available for AC only */
+		break;
+	case 0x0e: /* 1110 Events AC, Events AC+DC. Actually delivers just
+		* current voltage via IR, nothing more. */
+		devc->mq = SR_MQ_VOLTAGE;
+		devc->unit = SR_UNIT_VOLT;
+		devc->mqflags |= SR_MQFLAG_AC | SR_MQFLAG_DC | SR_MQFLAG_RMS;
+		break;
+	case 0x0f: /* 1111 Clock */
+		devc->mq = SR_MQ_TIME;
+		devc->unit = SR_UNIT_SECOND;
+		devc->mqflags |= SR_MQFLAG_DURATION;
+		break;
+	}
+}
+
+/**
+ * Decode range/sign/acdc byte special chars, Metrahit 18.
+ *
+ * @param[in] rs Rance/sign byte.
+ */
+static void decode_rs_18(uint8_t rs, struct dev_context *devc)
+{
+	int range;
+
+	/* Sign */
+	if (((devc->scale > 0) && (rs & 0x08)) ||
+			((devc->scale < 0) && !(rs & 0x08)))
+		devc->scale *= -1.0;
+
+	/* Range */
+	range = rs & 0x07;
+	switch (devc->mq) {
+	case SR_MQ_VOLTAGE:
+		if (devc->unit == SR_UNIT_DECIBEL_VOLT) {
+			devc->scale *= pow(10.0, -2);
+			/*
+			 * When entering relative mode, the device switches
+			 * from 10 byte to 6 byte msg format. Unfortunately
+			 * it switches back to 10 byte when the second value
+			 * is measured, so that's not sufficient to
+			 * identify relative mode.
+			 */
+		}
+		else if (devc->vmains_29S)
+			devc->scale *= pow(10.0, range - 2);
+		else
+			devc->scale *= pow(10.0, range - 5);
+		break;
+	case SR_MQ_CURRENT:
+		if (devc->scale1000 == -1)
+			devc->scale *= pow(10.0, range - 5);
+		else
+			devc->scale *= pow(10.0, range - 4);
+		break;
+	case SR_MQ_RESISTANCE:
+		devc->scale *= pow(10.0, range - 2);
+		break;
+	case SR_MQ_FREQUENCY:
+		devc->scale *= pow(10.0, range - 2);
+		break;
+	case SR_MQ_TEMPERATURE:
+		devc->scale *= pow(10.0, range - 2);
+		break;
+	case SR_MQ_CAPACITANCE:
+		devc->scale *= pow(10.0, range - 13);
+		break;
+		/* TODO: 29S Mains measurements. */
+	}
+}
+
+/**
+ * Decode special chars, Metrahit 18.
+ *
+ * @param[in] spc Special characters 1 and 2 (s1 | (s2 << 4)).
+ */
+static void decode_spc_18(uint8_t spc, struct dev_context *devc)
+{
+	/* xxxx1xxx ZERO */
+	/* xxxxx1xx BEEP */
+	/* xxxxxx1x Low battery */
+	/* xxxxxxx1 Fuse */
+
+	if (devc->mq == SR_MQ_TIME) {
+		/* xxx1xxxx Clock running: 1; stop: 0 */
+		sr_spew("Clock running: %d", spc >> 4);
+	} else {
+		/* 1xxxxxxx MAN */
+		setmqf(devc, SR_MQFLAG_AUTORANGE, !(spc & 0x80));
+
+		/* x1xxxxxx MIN */
+		setmqf(devc, SR_MQFLAG_MIN, spc & 0x40);
+
+		/* xx1xxxxx MAX */
+		setmqf(devc, SR_MQFLAG_MAX, spc & 0x20);
+
+		/* xxx1xxxx DATA */
+		setmqf(devc, SR_MQFLAG_HOLD, spc & 0x10);
+	}
+}
+
+/**
+ * Decode current type and measured value, Metrahit 2x.
+ *
+ * @param[in] ctmv Current type and measured value (v1 | (v2 << 4)).
+ */
+static void decode_ctmv_2x(uint8_t ctmv, struct dev_context *devc)
+{
+	if ((ctmv > 0x1c) || (!devc)) {
+		sr_err("decode_ctmv_2x(%d): invalid param(s)!", ctmv);
+		return;
+	}
+
+	devc->mq = 0;
+	devc->unit = 0;
+	devc->mqflags = 0;
+
+	switch (ctmv) {
+	/* 00000 unused */
+	case 0x01: /* 00001 V DC */
+	case 0x02: /* 00010 V AC+DC */
+	case 0x03: /* 00011 V AC */
+		devc->mq = SR_MQ_VOLTAGE;
+		devc->unit = SR_UNIT_VOLT;
+		if (ctmv <= 0x02)
+			devc->mqflags |= SR_MQFLAG_DC;
+		if (ctmv >= 0x02) {
+			devc->mqflags |= SR_MQFLAG_AC;
+			if (devc->model >= METRAHIT_24S)
+				devc->mqflags |= SR_MQFLAG_RMS;
+		}
+		break;
+	case 0x04: /* 00100 mA DC */
+	case 0x05: /* 00101 mA AC+DC */
+		devc->scale1000 = -1;
+	case 0x06: /* 00110 A DC */
+	case 0x07: /* 00111 A AC+DC */
+		devc->mq = SR_MQ_CURRENT;
+		devc->unit = SR_UNIT_AMPERE;
+		devc->mqflags |= SR_MQFLAG_DC;
+		if ((ctmv == 0x05) || (ctmv == 0x07)) {
+			devc->mqflags |= SR_MQFLAG_AC;
+			if (devc->model >= METRAHIT_24S)
+				devc->mqflags |= SR_MQFLAG_RMS;
+		}
+		break;
+	case 0x08: /* 01000 Ohm */
+		devc->mq = SR_MQ_RESISTANCE;
+		devc->unit = SR_UNIT_OHM;
+		break;
+	case 0x09: /* 01001 F */
+		devc->mq = SR_MQ_CAPACITANCE;
+		devc->unit = SR_UNIT_FARAD;
+		devc->scale *= 0.1;
+		break;
+	case 0x0a: /* 01010 V dB */
+		devc->mq = SR_MQ_VOLTAGE;
+		devc->unit = SR_UNIT_DECIBEL_VOLT;
+		devc->mqflags |= SR_MQFLAG_AC;
+		if (devc->model >= METRAHIT_24S)
+			devc->mqflags |= SR_MQFLAG_RMS;
+		break;
+	case 0x0b: /* 01011 Hz U ACDC */
+	case 0x0c: /* 01100 Hz U AC */
+		devc->mq = SR_MQ_FREQUENCY;
+		devc->unit = SR_UNIT_HERTZ;
+		devc->mqflags |= SR_MQFLAG_AC;
+		if (ctmv <= 0x0b)
+			devc->mqflags |= SR_MQFLAG_DC;
+		break;
+	case 0x0d: /* 01101 W on power, mA range (29S only) */
+		devc->scale *= 0.001;
+		/* Fall through! */
+	case 0x0e: /* 01110 W on power, A range (29S only) */
+		devc->mq = SR_MQ_POWER;
+		devc->unit = SR_UNIT_WATT;
+		break;
+	case 0x0f: /* 01111 Diode */
+	case 0x10: /* 10000 Diode with buzzer (actually cont. with voltage) */
+		devc->unit = SR_UNIT_VOLT;
+		if (ctmv == 0x0f) {
+			devc->mq = SR_MQ_VOLTAGE;
+			devc->mqflags |= SR_MQFLAG_DIODE;
+		} else {
+			devc->mq = SR_MQ_CONTINUITY;
+			devc->scale *= 0.00001;
+		}
+		devc->unit = SR_UNIT_VOLT;
+		break;
+	case 0x11: /* 10001 Ohm with buzzer */
+		devc->mq = SR_MQ_CONTINUITY;
+		devc->unit = SR_UNIT_OHM;
+		devc->scale1000 = -1;
+		break;
+	case 0x12: /* 10010 Temperature */
+		devc->mq = SR_MQ_TEMPERATURE;
+		devc->unit = SR_UNIT_CELSIUS;
+		/* This can be Fahrenheit. That is detected by range=4 later. */
+		break;
+	/* 0x13 10011, 0x14 10100 unsed */
+	case 0x15: /* 10101 Press (29S only) */
+		/* TODO: What does that mean? Possibly phase shift?
+		   Then we need a unit/flag for it. */
+		devc->mq = SR_MQ_GAIN;
+		devc->unit = SR_UNIT_PERCENTAGE;
+		break;
+	case 0x16: /* 10110 Pulse W (29S only) */
+		/* TODO: Own unit and flag for this! */
+		devc->mq = SR_MQ_POWER;
+		devc->unit = SR_UNIT_WATT;
+		break;
+	case 0x17: /* 10111 TRMS V on mains (29S only) */
+		devc->mq = SR_MQ_VOLTAGE;
+		devc->unit = SR_UNIT_VOLT;
+		devc->mqflags |= (SR_MQFLAG_AC | SR_MQFLAG_RMS);
+		devc->vmains_29S = TRUE;
+		break;
+	case 0x18: /* 11000 Counter (zero crossings of a signal) */
+		devc->mq = SR_MQ_VOLTAGE;
+		devc->unit = SR_UNIT_UNITLESS;
+		break;
+	case 0x19: /* 11001 Events U ACDC */
+	case 0x1a: /* 11010 Events U AC */
+		/* TODO: No unit or flags for this yet! */
+		devc->mq = SR_MQ_VOLTAGE;
+		devc->unit = SR_UNIT_UNITLESS;
+		devc->mqflags |= SR_MQFLAG_AC;
+		if (ctmv <= 0x19)
+			devc->mqflags |= SR_MQFLAG_DC;
+		break;
+	case 0x1b: /* 11011 pulse on mains (29S only) */
+		/* TODO: No unit or flags for this yet! */
+		devc->mq = SR_MQ_VOLTAGE;
+		devc->unit = SR_UNIT_UNITLESS;
+		devc->mqflags |= SR_MQFLAG_AC;
+		break;
+	case 0x1c: /* 11100 dropout on mains (29S only) */
+		/* TODO: No unit or flags for this yet! */
+		devc->mq = SR_MQ_VOLTAGE;
+		devc->unit = SR_UNIT_UNITLESS;
+		devc->mqflags |= SR_MQFLAG_AC;
+		break;
+	case 0x1f: /* 11111 Undocumented: 25S in stopwatch mode.
+			The value is voltage, not time, so treat it such. */
+		devc->mq = SR_MQ_VOLTAGE;
+		devc->unit = SR_UNIT_VOLT;
+		devc->mqflags |= SR_MQFLAG_DC;
+		break;
+	case 0x20: /* 100000 Undocumented: 25S in event count mode.
+		Value is 0 anyway. */
+		devc->mq = SR_MQ_VOLTAGE;
+		devc->unit = SR_UNIT_UNITLESS;
+		break;
+	default:
+		sr_err("decode_ctmv_2x(%d, ...): Unknown ctmv!", ctmv);
+		break;
+	}
+}
+
+/**
+ * Decode range/sign/acdc byte special chars, Metrahit 2x, table TR.
+ *
+ * @param[in] rs Range/sign byte.
+ */
+static void decode_rs_2x(uint8_t rs, struct dev_context *devc)
+{
+	int range;
+
+	/* Sign */
+	if (((devc->scale > 0) && (rs & 0x08)) ||
+			((devc->scale < 0) && !(rs & 0x08)))
+		devc->scale *= -1.0;
+
+	/* Range */
+	range = rs & 0x07;
+	switch (devc->mq) {
+	case SR_MQ_VOLTAGE:
+		if (devc->unit == SR_UNIT_DECIBEL_VOLT)
+			devc->scale *= pow(10.0, -3);
+		else if (devc->vmains_29S)
+			devc->scale *= pow(10.0, range - 2);
+		else
+			devc->scale *= pow(10.0, range - 6);
+		break;
+	case SR_MQ_CURRENT:
+		if (devc->scale1000 != -1) /* uA, mA */
+			range += 1;/* mA and A ranges differ by 10^4, not 10^3!*/
+		devc->scale *= pow(10.0, range - 6);
+		break;
+	case SR_MQ_RESISTANCE:
+		devc->scale *= pow(10.0, range - 3);
+		break;
+	case SR_MQ_FREQUENCY:
+		devc->scale *= pow(10.0, range - 3);
+		break;
+	case SR_MQ_TEMPERATURE:
+		if (range == 4) /* Indicator for °F */
+			devc->unit = SR_UNIT_FAHRENHEIT;
+		devc->scale *= pow(10.0, - 2);
+		break;
+	case SR_MQ_CAPACITANCE:
+		if (range == 7)
+			range -= 1; /* Same value as range 6 */
+		devc->scale *= pow(10.0, range - 13);
+		break;
+	/* TODO: 29S Mains measurements. */
+	}
+}
+
+/**
+ * Decode range/sign/acdc byte special chars, Metrahit 2x, table TR 2.
+ *
+ * @param[in] rs Range/sign byte.
+ */
+static void decode_rs_2x_TR2(uint8_t rs, struct dev_context *devc)
+{
+	int range;
+
+	/* Range */
+	range = rs & 0x07;
+	switch (devc->mq) {
+	case SR_MQ_CURRENT:
+		if (devc->scale1000 == -1) /* mA */
+			switch(range) {
+			case 0: case 1:	/* 100, 300 µA */
+				devc->scale *= pow(10.0, -6);
+				break;
+			case 2: case 3:	/* 1, 3 mA */
+				devc->scale *= pow(10.0, -5);
+				break;
+			case 4: case 5:	/* 10, 30 mA */
+				devc->scale *= pow(10.0, -4);
+				break;
+			case 6: case 7:	/* 100, 300 mA */
+				devc->scale *= pow(10.0, -3);
+				break;
+			}
+		else /* A */
+			switch(range) {
+			case 0: case 1:	/* 1, 3 A */
+				devc->scale *= pow(10.0, -5);
+				break;
+			case 2: /* 10 A */
+				devc->scale *= pow(10.0, -4);
+				break;
+			}
+		break;
+	default:
+		decode_rs_2x(rs, devc);
+		return;
+	}
+
+	/* Sign */
+	if (((devc->scale > 0) && (rs & 0x08)) ||
+			((devc->scale < 0) && !(rs & 0x08)))
+		devc->scale *= -1.0;
+}
+
+
+/**
+ * Decode special chars (Metrahit 2x).
+ *
+ * @param[in] spc Special characters 1 and 2 (s1 | (s2 << 4)).
+ */
+static void decode_spc_2x(uint8_t spc, struct dev_context *devc)
+{
+	/* xxxxxxx1 Fuse */
+
+	/* xxxxxx1x Low battery */
+
+	/* xxxxx1xx BEEP */
+
+	/* xxxx1xxx ZERO */
+
+	/* xxx1xxxx DATA */
+	setmqf(devc, SR_MQFLAG_HOLD, spc & 0x10);
+
+	/* x11xxxxx unused */
+	/* 1xxxxxxx MAN */
+	setmqf(devc, SR_MQFLAG_AUTORANGE, !(spc & 0x80));
+}
+
+/** Clean range and sign. */
+static void clean_rs_v(struct dev_context *devc)
+{
+	devc->value = 0.0;
+	devc->scale = 1.0;
+}
+
+/** Clean current type, measured variable, range and sign. */
+static void clean_ctmv_rs_v(struct dev_context *devc)
+{
+	devc->mq = 0;
+	devc->unit = 0;
+	devc->mqflags = 0;
+	devc->scale1000 = 0;
+	devc->vmains_29S = FALSE;
+	clean_rs_v(devc);
+}
+
+/** Send prepared value. */
+static void send_value(struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_datafeed_analog analog;
+	struct sr_datafeed_packet packet;
+
+	devc = sdi->priv;
+
+	memset(&analog, 0, sizeof(analog));
+	analog.channels = sdi->channels;
+	analog.num_samples = 1;
+	analog.mq = devc->mq;
+	analog.unit = devc->unit;
+	analog.mqflags = devc->mqflags;
+	analog.data = &devc->value;
+
+	memset(&packet, 0, sizeof(packet));
+	packet.type = SR_DF_ANALOG;
+	packet.payload = &analog;
+	sr_session_send(devc->cb_data, &packet);
+
+	devc->num_samples++;
+}
+
+/** Process 6-byte data message, Metrahit 1x/2x send mode. */
+static void process_msg_dta_6(struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	int cnt;
+	uint8_t dgt;
+
+	devc = sdi->priv;
+	clean_rs_v(devc);
+
+	/* Byte 0, range and sign */
+	if (devc->model <= METRAHIT_16X)
+		decode_rs_16(bc(devc->buf[0]), devc);
+	else if (devc->model < METRAHIT_2X)
+		decode_rs_18(bc(devc->buf[0]), devc);
+	else {
+		decode_rs_2x(bc(devc->buf[0]), devc);
+		devc->scale *= 10; /* Compensate for format having only 5 digits, decode_rs_2x() assumes 6. */
+	}
+
+	/* Bytes 1-5, digits (ls first). */
+	for (cnt = 0; cnt < 5; cnt++) {
+		dgt = bc(devc->buf[1 + cnt]);
+		if (dgt >= 10) {
+			/* 10 Overload; on model <= 16X also 11 possible. */
+			devc->value = NAN;
+			devc->scale = 1.0;
+			break;
+		}
+		devc->value += pow(10.0, cnt) * dgt;
+	}
+
+	sr_spew("process_msg_dta_6() value=%f scale=%f scale1000=%d",
+		devc->value, devc->scale, devc->scale1000);
+	if (devc->value != NAN)
+		devc->value *= devc->scale * pow(1000.0, devc->scale1000);
+
+	/* Create and send packet. */
+	send_value(sdi);
+}
+
+/** Process 5-byte info message, Metrahit 1x/2x. */
+static void process_msg_inf_5(struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	enum model model;
+
+	devc = sdi->priv;
+
+	clean_ctmv_rs_v(devc);
+
+	/* Process byte 0 */
+	model = gmc_decode_model_sm(bc(devc->buf[0]));
+	if (model != devc->model) {
+		sr_warn("Model mismatch in data: Detected %s, now %s",
+			gmc_model_str(devc->model), gmc_model_str(model));
+	}
+
+	/* Process bytes 1-4 */
+	if (devc->model <= METRAHIT_16X) {
+		decode_ctmv_16(bc(devc->buf[1]), devc);
+		decode_spc_16(bc(devc->buf[2]) | (bc(devc->buf[3]) << 4), devc);
+		decode_rs_16(bc(devc->buf[4]), devc);
+	} else if (devc->model <= METRAHIT_18S) {
+		decode_ctmv_18(bc(devc->buf[1]), devc);
+		decode_spc_18(bc(devc->buf[2]) | (bc(devc->buf[3]) << 4), devc);
+		decode_rs_18(bc(devc->buf[4]), devc);
+	} else { /* Must be Metrahit 2x */
+		decode_ctmv_2x(bc(devc->buf[1]), devc);
+		decode_spc_2x(bc(devc->buf[2]) | (bc(devc->buf[3]) << 4), devc);
+		decode_rs_2x(bc(devc->buf[4]), devc);
+	}
+}
+
+/** Process 10-byte info/data message, Metrahit 15+. */
+static void process_msg_inf_10(struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	int cnt;
+	uint8_t dgt;
+
+	devc = sdi->priv;
+
+	process_msg_inf_5(sdi);
+
+	/* Now decode numbers */
+	for (cnt = 0; cnt < 5; cnt++) {
+		dgt = bc(devc->buf[5 + cnt]);
+		if (dgt == 11) { /* Empty digit */
+			dgt = 0;
+		}
+		else if (dgt >= 12) { /* Overload */
+			devc->value = NAN;
+			devc->scale = 1.0;
+			break;
+		}
+		devc->value += pow(10.0, cnt) * dgt;
+	}
+	sr_spew("process_msg_inf_10() value=%f scale=%f scalet=%d",
+		devc->value, devc->scale,  devc->scale1000);
+
+	if (devc->value != NAN)
+		devc->value *= devc->scale * pow(1000.0, devc->scale1000);
+
+	/* Create and send packet. */
+	send_value(sdi);
+}
+
+/** Decode send interval (Metrahit 2x only). */
+static const char *decode_send_interval(uint8_t si)
+{
+	switch (si) {
+	case 0x00:
+		return "0.05";
+	case 0x01:
+		return "0.1";
+	case 0x02:
+		return "0.2";
+	case 0x03:
+		return "0.5";
+	case 0x04:
+		return "00:01";
+	case 0x05:
+		return "00:02";
+	case 0x06:
+		return "00:05";
+	case 0x07:
+		return "00:10";
+	case 0x08:
+		return "00:20";
+	case 0x09:
+		return "00:30";
+	case 0x0a:
+		return "01:00";
+	case 0x0b:
+		return "02:00";
+	case 0x0c:
+		return "05:00";
+	case 0x0d:
+		return "10:00";
+	case 0x0e:
+		return "----";
+	case 0x0f:
+		return "data";
+	default:
+		return "Unknown value";
+	}
+}
+
+/** Process 13-byte info/data message, Metrahit 2x. */
+static void process_msg_inf_13(struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	enum model model;
+	int cnt;
+	uint8_t dgt;
+
+	devc = sdi->priv;
+
+	clean_ctmv_rs_v(devc);
+
+	/* Byte 0, model. */
+	model = gmc_decode_model_sm(bc(devc->buf[0]));
+	if (model != devc->model) {
+		sr_warn("Model mismatch in data: Detected %s, now %s",
+			gmc_model_str(devc->model), gmc_model_str(model));
+	}
+
+	/* Bytes 1-4, 11. */
+	decode_ctmv_2x(bc(devc->buf[1]) | (bc(devc->buf[11]) << 4), devc);
+	decode_spc_2x(bc(devc->buf[2]) | (bc(devc->buf[3]) << 4), devc);
+	decode_rs_2x(bc(devc->buf[4]), devc);
+
+	/* Bytes 5-10, digits (ls first). */
+	for (cnt = 0; cnt < 6; cnt++) {
+		dgt = bc(devc->buf[5 + cnt]);
+		if (dgt == 10) { /* Overload */
+			devc->value = NAN;
+			devc->scale = 1.0;
+			break;
+		}
+		devc->value += pow(10.0, cnt) * dgt;
+	}
+	sr_spew("process_msg_inf_13() value=%f scale=%f scale1000=%d mq=%d "
+		"unit=%d mqflags=0x%02llx", devc->value, devc->scale,
+		devc->scale1000, devc->mq, devc->unit, devc->mqflags);
+	if (devc->value != NAN)
+		devc->value *= devc->scale * pow(1000.0, devc->scale1000);
+
+	/* Byte 12, Send Interval */
+	sr_spew("Send interval: %s", decode_send_interval(bc(devc->buf[12])));
+
+	/* Create and send packet. */
+	send_value(sdi);
+}
+
+/** Dump contents of 14-byte message.
+ *  @param buf Pointer to array of 14 data bytes.
+ *  @param[in] raw Write only data bytes, no interpretation.
+ */
+void dump_msg14(guchar* buf, gboolean raw)
+{
+	if (!buf)
+		return;
+
+	if (raw)
+		sr_spew("msg14: 0x %02x %02x %02x %02x %02x %02x %02x %02x "
+			"%02x %02x %02x %02x %02x %02x",
+			buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6],
+				buf[7], buf[8], buf[9], buf[10], buf[11], buf[12],
+				buf[13]);
+	else
+		sr_spew("msg14: 0x a=%d c1=%02x c2=%02x cmd=%02x dta=%02x "
+			"%02x %02x %02x %02x %02x %02x %02x %02x chs=%02x",
+			buf[1] == 0x2b?buf[0] >> 2:buf[0] % 0x0f, buf[1], buf[2], buf[3], buf[4], buf[5],
+				buf[6],	buf[7], buf[8], buf[9], buf[10], buf[11],
+				buf[12], buf[13]);
+}
+
+/** Calc checksum for 14 byte message type.
+ *
+ *  @param[in] dta Pointer to array of 13 data bytes.
+ *  @return Checksum.
+ */
+static guchar calc_chksum_14(guchar* dta)
+{
+	guchar cnt, chs;
+
+	for (chs = 0, cnt = 0; cnt < 13; cnt++)
+		chs += dta[cnt];
+
+	return (64 - chs) & MASK_6BITS;
+}
+
+/** Check 14-byte message, Metrahit 2x. */
+static int chk_msg14(struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	int retc;
+	gboolean isreq; /* Message is request to multimeter (otherwise response) */
+	uint8_t addr;  /* Adaptor address */
+
+	retc = SR_OK;
+
+	/* Check parameters and message */
+	if (!sdi || !(devc = sdi->priv))
+		return SR_ERR_ARG;
+
+	if (devc->buflen != 14) {
+		sr_err("process_msg_14(): Msg len 14 expected!");
+		return SR_ERR_ARG;
+	}
+
+	isreq = devc->buf[1] == 0x2b;
+	if (isreq)
+		addr = devc->buf[0] >> 2;
+	else
+		addr = devc->buf[0] & 0x0f;
+
+	if ((devc->addr != addr) && !(isreq && (addr == 0))) {
+		sr_err("process_msg_14(): Address mismatch, msg for other device!");
+		retc = SR_ERR_ARG;
+	}
+
+	if (devc->buf[1] == 0) { /* Error msg from device! */
+		retc = SR_ERR_ARG;
+		switch (devc->buf[2]) {
+		case 1: /* Not used */
+			sr_err("Device: Illegal error code!");
+			break;
+		case 2: /* Incorrect check sum of received block */
+			sr_err("Device: Incorrect checksum in cmd!");
+			break;
+		case 3: /* Incorrect length of received block */
+			sr_err("Device: Incorrect block length in cmd!");
+			break;
+		case 4: /* Incorrect 2nd or 3rd byte */
+			sr_err("Device: Incorrect byte 2 or 3 in cmd!");
+			break;
+		case 5: /* Parameter out of range */
+			sr_err("Device: Parameter out of range!");
+			break;
+		default:
+			sr_err("Device: Unknown error code!");
+		}
+		retc = SR_ERR_ARG;
+	}
+	else if (!isreq && ((devc->buf[1] != 0x27) || (devc->buf[2] != 0x3f))) {
+		sr_err("process_msg_14(): byte 1/2 unexpected!");
+		retc = SR_ERR_ARG;
+	}
+
+	if (calc_chksum_14(devc->buf) != devc->buf[13]) {
+		sr_err("process_msg_14(): Invalid checksum!");
+		retc = SR_ERR_ARG;
+	}
+
+	if (retc != SR_OK)
+		dump_msg14(devc->buf, TRUE);
+
+	return retc;
+}
+
+/** Check 14-byte message, Metrahit 2x. */
+SR_PRIV int process_msg14(struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	int retc;
+	uint8_t addr;
+	uint8_t cnt, dgt;
+
+	if ((retc = chk_msg14(sdi)) != SR_OK)
+		return retc;
+
+	devc = sdi->priv;
+
+	clean_ctmv_rs_v(devc);
+	addr = devc->buf[0] & MASK_6BITS;
+	if (addr != devc->addr)
+		sr_info("Device address mismatch %d/%d!", addr, devc->addr);
+
+	switch (devc->buf[3]) { /* That's the command this reply is for */
+	/* 0 cannot occur, the respective message is not a 14-byte message */
+	case 1: /* Read first free and occupied address */
+		sr_spew("Cmd %d unimplemented!", devc->buf[3]);
+		break;
+	case 2: /* Clear all RAM in multimeter */
+		sr_spew("Cmd %d unimplemented!", devc->buf[3]);
+		break;
+	case 3: /* Read firmware version and status */
+		sr_spew("Cmd 3, Read firmware and status", devc->buf[3]);
+		switch (devc->cmd_idx) {
+		case 0:
+			devc->fw_ver_maj = devc->buf[5];
+			devc->fw_ver_min = devc->buf[4];
+			sr_spew("Firmware version %d.%d", (int)devc->fw_ver_maj, (int)devc->fw_ver_min);
+			sr_spew("Rotary Switch Position (1..10): %d", (int)devc->buf[6]);
+			/** Docs say values 0..9, but that's not true */
+			sr_spew("Measurement Function: %d ", (int)devc->buf[7]);
+			decode_ctmv_2x(devc->buf[7], devc);
+			sr_spew("Range: 0x%x", devc->buf[8]);
+			decode_rs_2x_TR2(devc->buf[8] & 0x0f, devc);  /* Docs wrong, uses conversion table TR_2! */
+			devc->autorng = (devc->buf[8] & 0x20) == 0;
+			// TODO 9, 10: 29S special functions
+			devc->ubatt = 0.1 * (float)devc->buf[11];
+			devc->model = gmc_decode_model_bd(devc->buf[12]);
+			sr_spew("Model=%s, battery voltage=%2.1f V", gmc_model_str(devc->model), (double)devc->ubatt);
+			break;
+		case 1:
+			sr_spew("Internal version %d.%d", (int)devc->buf[5], (int)devc->buf[4]);
+			sr_spew("Comm mode: 0x%x", (int)devc->buf[6]);
+			sr_spew("Block cnt%%64: %d", (int)devc->buf[7]);
+			sr_spew("drpCi: %d  drpCh: %d", (int)devc->buf[8], (int)devc->buf[9]);
+			// Semantics undocumented. Possibly Metrahit 29S dropouts stuff?
+			break;
+		default:
+			sr_spew("Cmd 3: Unknown cmd_idx=%d", devc->cmd_idx);
+			break;
+		}
+		break;
+	case 4: /* Set real time, date, sample rate, trigger, ... */
+		sr_spew("Cmd %d unimplemented!", devc->buf[3]);
+		break;
+	case 5: /* Read real time, date, sample rate, trigger... */
+		sr_spew("Cmd %d unimplemented!", devc->buf[3]);
+		break;
+	case 6: /* Set modes or power off */
+		sr_spew("Cmd %d unimplemented!", devc->buf[3]);
+		break;
+	case 7: /* Set measurement function, range, autom/man. */
+		sr_spew("Cmd %d unimplemented!", devc->buf[3]);
+		break;
+	case 8: /* Get one measurement value */
+		sr_spew("Cmd 8, get one measurement value");
+		sr_spew("Measurement Function: %d ", (int)devc->buf[5]);
+		decode_ctmv_2x(devc->buf[5], devc);
+		if (!(devc->buf[6] & 0x10)) /* If bit4=0, old data. */
+			return SR_OK;
+
+		decode_rs_2x_TR2(devc->buf[6] & 0x0f, devc); // The docs say conversion table TR_3, but that does not work
+		setmqf(devc, SR_MQFLAG_AUTORANGE, devc->autorng);
+		/* 6 digits */
+		for (cnt = 0; cnt < 6; cnt++) {
+			dgt = bc(devc->buf[7 + cnt]);
+			if (dgt == 10) { /* Overload */
+				devc->value = NAN;
+				devc->scale = 1.0;
+				break;
+			}
+			else if (dgt == 13) { /* FUSE */
+				sr_err("FUSE!");
+			}
+			else if (dgt == 14) { /* Function recognition mode, OPEN */
+				sr_info("Function recognition mode, OPEN!");
+				devc->value = NAN;
+				devc->scale = 1.0;
+				break;
+			}
+			devc->value += pow(10.0, cnt) * dgt;
+		}
+		sr_spew("process_msg14() value=%f scale=%f scale1000=%d mq=%d "
+			"unit=%d mqflags=0x%02llx", devc->value, devc->scale,
+			devc->scale1000, devc->mq, devc->unit, devc->mqflags);
+		if (devc->value != NAN)
+			devc->value *= devc->scale * pow(1000.0, devc->scale1000);
+
+		send_value(sdi);
+
+		break;
+	default:
+		sr_spew("Unknown cmd %d!", devc->buf[3]);
+		break;
+	}
+
+	return SR_OK;
+}
+
+/** Data reception callback function. */
+SR_PRIV int gmc_mh_1x_2x_receive_data(int fd, int revents, void *cb_data)
+{
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+	uint8_t buf, msgt;
+	int len;
+	gdouble elapsed_s;
+
+	(void)fd;
+
+	if (!(sdi = cb_data))
+		return TRUE;
+
+	if (!(devc = sdi->priv))
+		return TRUE;
+
+	serial = sdi->conn;
+
+	if (revents == G_IO_IN) { /* Serial data arrived. */
+		while (GMC_BUFSIZE - devc->buflen - 1 > 0) {
+			len = serial_read(serial, devc->buf + devc->buflen, 1);
+			if (len < 1)
+				break;
+			buf = *(devc->buf + devc->buflen);
+			sr_spew("read 0x%02x/%d/%d", buf, buf, buf & MSGC_MASK);
+			devc->buflen += len;
+			if (!devc->settings_ok) {
+				/*
+				 * If no device type/settings record processed
+				 * yet, wait for one.
+				 */
+				if ((devc->buf[0] & MSGID_MASK) != MSGID_INF) {
+					devc->buflen = 0;
+					continue;
+				}
+				devc->settings_ok = TRUE;
+			}
+
+			msgt = devc->buf[0] & MSGID_MASK;
+			switch (msgt) {
+			case MSGID_INF:
+				if (devc->buflen == 13) {
+					process_msg_inf_13(sdi);
+					devc->buflen = 0;
+					continue;
+				} else if ((devc->buflen == 10) &&
+					   (devc->model <= METRAHIT_18S)) {
+					process_msg_inf_10(sdi);
+					devc->buflen = 0;
+					continue;
+				}
+				else if ((devc->buflen >= 5) &&
+					 (devc->buf[devc->buflen - 1] &
+					  MSGID_MASK) != MSGID_DATA) {
+					/*
+					 * Char just received is beginning
+					 * of next message.
+					 */
+					process_msg_inf_5(sdi);
+					devc->buf[0] =
+							devc->buf[devc->buflen - 1];
+					devc->buflen = 1;
+					continue;
+				}
+				break;
+			case MSGID_DTA:
+			case MSGID_D10:
+				if (devc->buflen == 6) {
+					process_msg_dta_6(sdi);
+					devc->buflen = 0;
+				}
+				break;
+			case MSGID_DATA:
+				sr_err("Comm error, unexpected data byte!");
+				devc->buflen = 0;
+				break;
+			}
+		}
+	}
+
+	/* If number of samples or time limit reached, stop acquisition. */
+	if (devc->limit_samples && (devc->num_samples >= devc->limit_samples))
+		sdi->driver->dev_acquisition_stop(sdi, cb_data);
+
+	if (devc->limit_msec) {
+		elapsed_s = g_timer_elapsed(devc->elapsed_msec, NULL);
+		if ((elapsed_s * 1000) >= devc->limit_msec)
+			sdi->driver->dev_acquisition_stop(sdi, cb_data);
+	}
+
+	return TRUE;
+}
+
+SR_PRIV int gmc_mh_2x_receive_data(int fd, int revents, void *cb_data)
+{
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+	uint8_t buf;
+	int len;
+	gdouble elapsed_s;
+
+	(void)fd;
+
+	if (!(sdi = cb_data))
+		return TRUE;
+
+	if (!(devc = sdi->priv))
+		return TRUE;
+
+	serial = sdi->conn;
+
+	if (revents == G_IO_IN) { /* Serial data arrived. */
+		while (GMC_BUFSIZE - devc->buflen - 1 > 0) {
+			len = serial_read(serial, devc->buf + devc->buflen, 1);
+			if (len < 1)
+				break;
+			buf = *(devc->buf + devc->buflen);
+			sr_spew("read 0x%02x/%d/%d", buf, buf, buf & MASK_6BITS);
+			devc->buf[devc->buflen] &= MASK_6BITS;
+			devc->buflen += len;
+
+			if (devc->buflen == 14) {
+				devc->response_pending = FALSE;
+				sr_spew("gmc_mh_2x_receive_data processing msg");
+				process_msg14(sdi);
+				devc->buflen = 0;
+			}
+		}
+	}
+
+	/* If number of samples or time limit reached, stop acquisition. */
+	if (devc->limit_samples && (devc->num_samples >= devc->limit_samples))
+		sdi->driver->dev_acquisition_stop(sdi, cb_data);
+
+	if (devc->limit_msec) {
+		elapsed_s = g_timer_elapsed(devc->elapsed_msec, NULL);
+		if ((elapsed_s * 1000) >= devc->limit_msec)
+			sdi->driver->dev_acquisition_stop(sdi, cb_data);
+	}
+
+	/* Request next data set, if required */
+	if (sdi->status == SR_ST_ACTIVE) {
+		if (devc->response_pending) {
+			gint64 elapsed_us = g_get_monotonic_time() - devc->req_sent_at;
+			if (elapsed_us > 1*1000*1000) /* Timeout! */
+				devc->response_pending = FALSE;
+		}
+		if (!devc->response_pending) {
+			devc->cmd_seq++;
+			if (devc->cmd_seq % 10 == 0) {
+				if (req_stat14(sdi, FALSE) != SR_OK)
+					return FALSE;
+			}
+			else if (req_meas14(sdi) != SR_OK)
+				return FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
+/** Create 14 (42) byte command for Metrahit 2x multimeter in bidir mode.
+ *
+ *  Actually creates 42 bytes due to the encoding method used.
+ *  @param[in] addr Device address (0=adapter, 1..15 multimeter; for byte 0).
+ *  @param[in] func Function code (byte 3).
+ *  @param[in] params Further parameters (9 bytes)
+ *  @param[out] buf Buffer to create msg in (42 bytes).
+ */
+void create_cmd_14(guchar addr, guchar func, guchar* params, guchar* buf)
+{
+	uint8_t dta[14];	/* Unencoded message */
+	int cnt;
+
+	if (!params || !buf)
+		return;
+
+	/* 0: Address */
+	dta[0] = ((addr << 2) | 0x03) & MASK_6BITS;
+
+	/* 1-3: Set command header */
+	dta[1] = 0x2b;
+	dta[2] = 0x3f;
+	dta[3] = func;
+
+	/* 4-12: Copy further parameters */
+	for (cnt = 0; cnt < 9; cnt++)
+		dta[cnt+4] = (params[cnt] & MASK_6BITS);
+
+	/* 13: Checksum (b complement) */
+	dta[13] = calc_chksum_14(dta);
+
+	/* The whole message is packed into 3 bytes per byte now (lower 6 bits only) the most
+	 * peculiar way I have ever seen. Possibly to improve IR communication? */
+	for (cnt = 0; cnt < 14; cnt++) {
+		buf[3*cnt] = (dta[cnt] & 0x01 ? 0x0f : 0) | (dta[cnt] & 0x02 ? 0xf0 : 0);
+		buf[3*cnt + 1] = (dta[cnt] & 0x04 ? 0x0f : 0) | (dta[cnt] & 0x08 ? 0xf0 : 0);
+		buf[3*cnt + 2] = (dta[cnt] & 0x10 ? 0x0f : 0) | (dta[cnt] & 0x20 ? 0xf0 : 0);
+	}
+}
+
+/** Request one measurement from 2x multimeter (msg 8).
+ *
+ */
+int req_meas14(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+	uint8_t params[9];
+	uint8_t msg[42];
+
+	if (!sdi || !(devc = sdi->priv) || !(serial = sdi->conn))
+		return SR_ERR;
+
+	memset(params, 0, sizeof(params));
+	params[0] = 0;
+	devc->cmd_idx = 0;
+	create_cmd_14(devc->addr, 8, params, msg);
+	devc->req_sent_at = g_get_monotonic_time();
+	if (serial_write(serial, msg, sizeof(msg)) == -1) {
+		return SR_ERR;
+	}
+
+	devc->response_pending = TRUE;
+
+	return SR_OK;
+}
+
+/** Request status from 2x multimeter (msg 3).
+ *  @param[in] power_on Try to power on powered off multimeter by sending additional messages.
+ */
+int req_stat14(const struct sr_dev_inst *sdi, gboolean power_on)
+{
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+	uint8_t params[9];
+	uint8_t msg[42];
+
+	if (!sdi || !(devc = sdi->priv) || !(serial = sdi->conn))
+		return SR_ERR;
+
+	memset(params, 0, sizeof(params));
+	params[0] = 0;
+	devc->cmd_idx = 0;
+	create_cmd_14(devc->addr, 3, params, msg);
+
+	if (power_on) {
+		sr_info("Write some data and wait 3s to turn on powered off device...");
+		if (serial_write(serial, msg, sizeof(msg)) < 0)
+			return SR_ERR;
+		g_usleep(1*1000*1000);
+		if (serial_write(serial, msg, sizeof(msg)) < 0)
+			return SR_ERR;
+		g_usleep(1*1000*1000);
+		if (serial_write(serial, msg, sizeof(msg)) < 0)
+			return SR_ERR;
+		g_usleep(1*1000*1000);
+		serial_flush(serial);
+	}
+
+	/* Write message and wait for reply */
+	devc->req_sent_at = g_get_monotonic_time();
+	if (serial_write(serial, msg, sizeof(msg)) == -1) {
+		return SR_ERR;
+	}
+
+	devc->response_pending = TRUE;
+
+	return SR_OK;
+}
+
+/** Decode model in "send mode".
+ *
+ * @param[in] mcode Model code.
+ * @return Model code.
+ */
+SR_PRIV int gmc_decode_model_sm(uint8_t mcode)
+{
+	if (mcode > 0xf) {
+		sr_err("decode_model(%d): Model code 0..15 expected!", mcode);
+		return METRAHIT_NONE;
+	}
+
+	switch(mcode) {
+	case 0x04: /* 0100b */
+		return METRAHIT_12S;
+	case 0x08: /* 1000b */
+		return METRAHIT_13S14A;
+	case 0x09: /* 1001b */
+		return METRAHIT_14S;
+	case 0x0A: /* 1010b */
+		return METRAHIT_15S;
+	case 0x0B: /* 1011b */
+		return METRAHIT_16S;
+	case 0x06: /* 0110b (undocumented by GMC!) */
+		return METRAHIT_16I;
+	case 0x0D: /* 1101b */
+		return METRAHIT_18S;
+	case 0x02: /* 0010b */
+		return METRAHIT_22SM;
+	case 0x03: /* 0011b */
+		return METRAHIT_23S;
+	case 0x0f: /* 1111b */
+		return METRAHIT_24S;
+	case 0x05: /* 0101b */
+		return METRAHIT_25S;
+	case 0x01: /* 0001b */
+		return METRAHIT_26SM;
+	case 0x0c: /* 1100b */
+		return METRAHIT_28S;
+	case 0x0e: /* 1110b */
+		return METRAHIT_29S;
+	default:
+		sr_err("Unknown model code %d!", mcode);
+		return METRAHIT_NONE;
+	}
+}
+
+/** Convert GMC model code in bidirectional mode to sigrok-internal one.
+ *
+ *  @param[in] mcode Model code.
+ *
+ *  @return Model code.
+ */
+SR_PRIV int gmc_decode_model_bd(uint8_t mcode)
+{
+	switch (mcode & 0x1f) {
+	case 2:
+		if (mcode & 0x20)
+			return METRAHIT_22M;
+		else
+			return METRAHIT_22S;
+	case 3:
+		return METRAHIT_23S;
+	case 4:
+		return METRAHIT_24S;
+	case 5:
+		return METRAHIT_25S;
+	case 1:
+		if (mcode & 0x20)
+			return METRAHIT_26M;
+		else
+			return METRAHIT_26S;
+	case 12:
+		return METRAHIT_28S;
+	case 14:
+		return METRAHIT_29S;
+	default:
+		sr_err("Unknown model code %d!", mcode);
+		return METRAHIT_NONE;
+	}
+}
+
+/** Convert sigrok-internal model code to string.
+ *
+ *  @param[in] mcode Model code.
+ *
+ *  @return Model code string.
+ */
+SR_PRIV const char *gmc_model_str(enum model mcode)
+{
+	switch (mcode) {
+	case METRAHIT_NONE:
+		return "-uninitialized model variable-";
+	case METRAHIT_12S:
+		return "METRAHit 12S";
+	case METRAHIT_13S14A:
+		return "METRAHit 13S/14A";
+	case METRAHIT_14S:
+		return "METRAHit 14S";
+	case METRAHIT_15S:
+		return "METRAHit 15S";
+	case METRAHIT_16S:
+		return "METRAHit 16S";
+	case METRAHIT_16I:
+		return "METRAHit 16I";
+	case METRAHIT_18S:
+		return "METRAHit 18S";
+	case METRAHIT_22SM:
+		return "METRAHit 22S/M";
+	case METRAHIT_22S:
+		return "METRAHit 22S";
+	case METRAHIT_22M:
+		return "METRAHit 22M";
+	case METRAHIT_23S:
+		return "METRAHit 23S";
+	case METRAHIT_24S:
+		return "METRAHit 24S";
+	case METRAHIT_25S:
+		return "METRAHit 25S";
+	case METRAHIT_26SM:
+		return "METRAHit 26S/M";
+	case METRAHIT_26S:
+		return "METRAHit 26S";
+	case METRAHIT_26M:
+		return "METRAHit 26M";
+	case METRAHIT_28S:
+		return "METRAHit 28S";
+	case METRAHIT_29S:
+		return "METRAHit 29S";
+	default:
+		return "Unknown model code";
+	}
+}
+
+
+/** @copydoc sr_dev_driver.config_set
+ */
+SR_PRIV int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+		       const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	uint8_t params[9];
+	uint8_t msg[42];
+
+	(void)cg;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!(devc = sdi->priv)) {
+		sr_err("sdi->priv was NULL.");
+		return SR_ERR_BUG;
+	}
+
+	switch (key) {
+	case SR_CONF_POWER_OFF:
+		if (devc->model < METRAHIT_2X)
+			return SR_ERR_NA;
+		if (!g_variant_get_boolean(data))
+			return SR_ERR;
+		sr_info("Powering device off.");
+
+		memset(params, 0, sizeof(params));
+		params[0] = 5;
+		params[1] = 5;
+		create_cmd_14(devc->addr, 6, params, msg);
+		if (serial_write(sdi->conn, msg, sizeof(msg)) == -1)
+			return SR_ERR;
+		else
+			g_usleep(2000000); /* Wait to ensure transfer before interface switched off. */
+		break;
+	case SR_CONF_LIMIT_MSEC:
+		if (g_variant_get_uint64(data) == 0) {
+			sr_err("LIMIT_MSEC can't be 0.");
+			return SR_ERR;
+		}
+		devc->limit_msec = g_variant_get_uint64(data);
+		sr_dbg("Setting time limit to %" PRIu64 "ms.",
+			devc->limit_msec);
+		break;
+	case SR_CONF_LIMIT_SAMPLES:
+		devc->limit_samples = g_variant_get_uint64(data);
+		sr_dbg("Setting sample limit to %" PRIu64 ".",
+			devc->limit_samples);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
diff --git a/hardware/gmc-mh-1x-2x/protocol.h b/hardware/gmc-mh-1x-2x/protocol.h
new file mode 100644
index 0000000..3d34d9a
--- /dev/null
+++ b/hardware/gmc-mh-1x-2x/protocol.h
@@ -0,0 +1,135 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013, 2014 Matthias Heidbrink <m-sigrok at heidbrink.biz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** @file
+ *  Gossen Metrawatt Metrahit 1x/2x drivers
+ *  @internal
+ */
+
+#ifndef LIBSIGROK_HARDWARE_GMC_MH_1X_2X_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_GMC_MH_1X_2X_PROTOCOL_H
+
+#include <stdint.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "gmc-mh-1x-2x"
+
+#define GMC_BUFSIZE  266
+
+/** Message ID bits 4, 5 */
+#define MSGID_MASK  0x30 /**< Mask to get message ID bits */
+#define MSGID_INF   0x00 /**< Start of message with device info */
+#define MSGID_D10   0x10 /**< Start of data message, non-displayed intermediate */
+#define MSGID_DTA   0x20 /**< Start of data message, displayed, averaged */
+#define MSGID_DATA  0x30 /**< Data byte in message */
+
+#define MSGC_MASK   0x0f  /**< Mask to get message byte contents in send mode */
+
+#define MSGSRC_MASK 0xc0 /**< Mask to get bits related to message source */
+
+#define bc(x) (x & MSGC_MASK) /**< Get contents from a byte */
+
+#define MASK_6BITS  0x3f /**< Mask lower six bits. */
+
+/**
+ * Internal multimeter model codes. In opposite to the multimeter models from
+ * protocol (see decode_model()), these codes allow working with ranges.
+ */
+enum model {
+	METRAHIT_NONE		= 0,  /**< Value for uninitialized variable */
+	METRAHIT_12S		= 12,
+	METRAHIT_13S14A		= 13,
+	METRAHIT_14S		= 14,
+	METRAHIT_15S		= 15,
+	METRAHIT_16S		= 16,
+	METRAHIT_16I		= 17,
+	METRAHIT_16X = METRAHIT_16I,  /**< All Metrahit 16 */
+	/* A Metrahit 17 exists, but seems not to have an IR interface. */
+	METRAHIT_18S		= 18,
+	METRAHIT_2X		= 20, /**< For model type comparisons */
+	METRAHIT_22SM		= METRAHIT_2X + 1,	/**< Send mode */
+	METRAHIT_22S		= METRAHIT_22SM + 1,	/**< Bidi mode */
+	METRAHIT_22M		= METRAHIT_22S + 1,	/**< Bidi mode */
+	METRAHIT_23S		= METRAHIT_22M + 1,
+	METRAHIT_24S		= METRAHIT_23S + 1,
+	METRAHIT_25S		= METRAHIT_24S + 1,
+	METRAHIT_26SM		= METRAHIT_25S + 1,	/**< Send mode */
+	METRAHIT_26S		= METRAHIT_26SM + 1,	/**< Bidi mode */
+	METRAHIT_26M		= METRAHIT_26S + 1,	/**< Bidi mode */
+	METRAHIT_28S		= METRAHIT_26M + 1,
+	METRAHIT_29S		= METRAHIT_28S + 1,
+};
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+	/* Model-specific information */
+	enum model model;	/**< Model code. */
+
+	/* Acquisition settings */
+	uint64_t limit_samples;	/**< Target number of samples */
+	uint64_t limit_msec;	/**< Target sampling time */
+
+	/* Opaque pointer passed in by frontend. */
+	void *cb_data;
+
+	/* Operational state */
+	gboolean settings_ok;	/**< Settings msg received yet. */
+	int msg_type;       /**< Message type (MSGID_INF, ...). */
+	int msg_len;        /**< Message lengh (valid when msg, curr. type known).*/
+	int mq;             /**< Measured quantity */
+	int unit;           /**< Measured unit */
+	uint64_t mqflags;	/**< Measured quantity flags */
+	float value;		/**< Measured value */
+	float scale;		/**< Scale for value. */
+	int8_t scale1000;   /**< Additional scale factor 1000x. */
+	gboolean vmains_29S;	/**< Measured ctmv is V mains (29S only). */
+	int addr;           /**< Device address (1..15). */
+	int cmd_idx;        /**< Parameter "Idx" (Index) of current command, if required. */
+	int cmd_seq;        /**< Command sequence. Used to query status every n messages. */
+	gboolean autorng;   /**< Auto range enabled. */
+	float ubatt;        /**< Battery voltage. */
+	uint8_t fw_ver_maj; /**< Firmware version major. */
+	uint8_t fw_ver_min; /**< Firmware version minor. */
+	int64_t req_sent_at;    /**< Request sent. */
+	gboolean response_pending; /**< Request sent, response is pending. */
+
+	/* Temporary state across callbacks */
+	uint64_t num_samples;	/**< Current #samples for limit_samples */
+	GTimer *elapsed_msec;	/**< Used for sampling with limit_msec  */
+	uint8_t buf[GMC_BUFSIZE];	/**< Buffer for read callback */
+	int buflen;			/**< Data len in buf */
+};
+
+/* Forward declarations */
+SR_PRIV int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg);
+SR_PRIV void create_cmd_14(guchar addr, guchar func, guchar* params, guchar* buf);
+SR_PRIV void dump_msg14(guchar* buf, gboolean raw);
+SR_PRIV int gmc_decode_model_bd(uint8_t mcode);
+SR_PRIV int gmc_decode_model_sm(uint8_t mcode);
+SR_PRIV int gmc_mh_1x_2x_receive_data(int fd, int revents, void *cb_data);
+SR_PRIV int gmc_mh_2x_receive_data(int fd, int revents, void *cb_data);
+SR_PRIV const char *gmc_model_str(enum model mcode);
+SR_PRIV int process_msg14(struct sr_dev_inst *sdi);
+SR_PRIV int req_meas14(const struct sr_dev_inst *sdi);
+SR_PRIV int req_stat14(const struct sr_dev_inst *sdi, gboolean power_on);
+
+#endif
diff --git a/hardware/hameg-hmo/api.c b/hardware/hameg-hmo/api.c
new file mode 100644
index 0000000..b5b3bc2
--- /dev/null
+++ b/hardware/hameg-hmo/api.c
@@ -0,0 +1,805 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 poljar (Damir Jelić) <poljarinho at gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include "protocol.h"
+
+#define SERIALCOMM "115200/8n1/flow=1"
+
+SR_PRIV struct sr_dev_driver hameg_hmo_driver_info;
+static struct sr_dev_driver *di = &hameg_hmo_driver_info;
+
+static const char *manufacturers[] = {
+	"HAMEG",
+};
+
+static const int32_t hwopts[] = {
+	SR_CONF_CONN,
+	SR_CONF_SERIALCOMM,
+};
+
+enum {
+	CG_INVALID = -1,
+	CG_NONE,
+	CG_ANALOG,
+	CG_DIGITAL,
+};
+
+static int init(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static int check_manufacturer(const char *manufacturer)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(manufacturers); ++i)
+		if (!strcmp(manufacturer, manufacturers[i]))
+			return SR_OK;
+
+	return SR_ERR;
+}
+
+static struct sr_dev_inst *hmo_probe_serial_device(struct sr_scpi_dev_inst *scpi)
+{
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+	struct sr_scpi_hw_info *hw_info;
+
+	sdi = NULL;
+	devc = NULL;
+	hw_info = NULL;
+
+	if (sr_scpi_get_hw_id(scpi, &hw_info) != SR_OK) {
+		sr_info("Couldn't get IDN response.");
+		goto fail;
+	}
+
+	if (check_manufacturer(hw_info->manufacturer) != SR_OK)
+		goto fail;
+
+	if (!(sdi = sr_dev_inst_new(0, SR_ST_ACTIVE,
+				    hw_info->manufacturer, hw_info->model,
+				    hw_info->firmware_version))) {
+		goto fail;
+	}
+	sr_scpi_hw_info_free(hw_info);
+	hw_info = NULL;
+
+	if (!(devc = g_try_malloc0(sizeof(struct dev_context))))
+		goto fail;
+
+	sdi->driver = di;
+	sdi->priv = devc;
+	sdi->inst_type = SR_INST_SCPI;
+	sdi->conn = scpi;
+
+	if (hmo_init_device(sdi) != SR_OK)
+		goto fail;
+
+	sr_scpi_close(sdi->conn);
+
+	sdi->status = SR_ST_INACTIVE;
+
+	return sdi;
+
+fail:
+	if (hw_info)
+		sr_scpi_hw_info_free(hw_info);
+	if (sdi)
+		sr_dev_inst_free(sdi);
+	if (devc)
+		g_free(devc);
+
+	return NULL;
+}
+
+static GSList *scan(GSList *options)
+{
+	return sr_scpi_scan(di->priv, options, hmo_probe_serial_device);
+}
+
+static GSList *dev_list(void)
+{
+	return ((struct drv_context *)(di->priv))->instances;
+}
+
+static void clear_helper(void *priv)
+{
+	unsigned int i;
+	struct dev_context *devc;
+	struct scope_config *model;
+
+	devc = priv;
+	model = devc->model_config;
+
+	hmo_scope_state_free(devc->model_state);
+
+	for (i = 0; i < model->analog_channels; ++i)
+		g_slist_free(devc->analog_groups[i].channels);
+
+	for (i = 0; i < model->digital_pods; ++i) {
+		g_slist_free(devc->digital_groups[i].channels);
+		g_free(devc->digital_groups[i].name);
+	}
+
+	g_free(devc->analog_groups);
+	g_free(devc->digital_groups);
+
+	g_free(devc);
+}
+
+static int dev_clear(void)
+{
+	return std_dev_clear(di, clear_helper);
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+	if (sdi->status != SR_ST_ACTIVE && sr_scpi_open(sdi->conn) != SR_OK)
+		return SR_ERR;
+
+	if (hmo_scope_state_get(sdi) != SR_OK)
+		return SR_ERR;
+
+	sdi->status = SR_ST_ACTIVE;
+
+	return SR_OK;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+	if (sdi->status == SR_ST_INACTIVE)
+		return SR_OK;
+
+	sr_scpi_close(sdi->conn);
+
+	sdi->status = SR_ST_INACTIVE;
+
+	return SR_OK;
+}
+
+static int cleanup(void)
+{
+	dev_clear();
+
+	return SR_OK;
+}
+
+static int check_channel_group(struct dev_context *devc,
+			     const struct sr_channel_group *cg)
+{
+	unsigned int i;
+	struct scope_config *model;
+
+	model = devc->model_config;
+
+	if (!cg)
+		return CG_NONE;
+
+	for (i = 0; i < model->analog_channels; ++i)
+		if (cg == &devc->analog_groups[i])
+			return CG_ANALOG;
+
+	for (i = 0; i < model->digital_pods; ++i)
+		if (cg == &devc->digital_groups[i])
+			return CG_DIGITAL;
+
+	sr_err("Invalid channel group specified.");
+
+	return CG_INVALID;
+}
+
+static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		      const struct sr_channel_group *cg)
+{
+	int ret, cg_type;
+	unsigned int i;
+	struct dev_context *devc;
+	struct scope_config *model;
+	struct scope_state *state;
+
+	if (!sdi || !(devc = sdi->priv))
+		return SR_ERR_ARG;
+
+	if ((cg_type = check_channel_group(devc, cg)) == CG_INVALID)
+		return SR_ERR;
+
+	ret = SR_ERR_NA;
+	model = devc->model_config;
+	state = devc->model_state;
+
+	switch (key) {
+	case SR_CONF_NUM_TIMEBASE:
+		*data = g_variant_new_int32(model->num_xdivs);
+		ret = SR_OK;
+		break;
+	case SR_CONF_TIMEBASE:
+		*data = g_variant_new("(tt)", (*model->timebases)[state->timebase][0],
+				      (*model->timebases)[state->timebase][1]);
+		ret = SR_OK;
+		break;
+	case SR_CONF_NUM_VDIV:
+		if (cg_type == CG_NONE) {
+			sr_err("No channel group specified.");
+			return SR_ERR_CHANNEL_GROUP;
+		} else if (cg_type == CG_ANALOG) {
+			for (i = 0; i < model->analog_channels; ++i) {
+				if (cg != &devc->analog_groups[i])
+					continue;
+				*data = g_variant_new_int32(model->num_ydivs);
+				ret = SR_OK;
+				break;
+			}
+
+		} else {
+			ret = SR_ERR_NA;
+		}
+		break;
+	case SR_CONF_VDIV:
+		if (cg_type == CG_NONE) {
+			sr_err("No channel group specified.");
+			return SR_ERR_CHANNEL_GROUP;
+		} else if (cg_type == CG_ANALOG) {
+			for (i = 0; i < model->analog_channels; ++i) {
+				if (cg != &devc->analog_groups[i])
+					continue;
+				*data = g_variant_new("(tt)",
+						      (*model->vdivs)[state->analog_channels[i].vdiv][0],
+						      (*model->vdivs)[state->analog_channels[i].vdiv][1]);
+				ret = SR_OK;
+				break;
+			}
+
+		} else {
+			ret = SR_ERR_NA;
+		}
+		break;
+	case SR_CONF_TRIGGER_SOURCE:
+		*data = g_variant_new_string((*model->trigger_sources)[state->trigger_source]);
+		ret = SR_OK;
+		break;
+	case SR_CONF_TRIGGER_SLOPE:
+		*data = g_variant_new_string((*model->trigger_slopes)[state->trigger_slope]);
+		ret = SR_OK;
+		break;
+	case SR_CONF_HORIZ_TRIGGERPOS:
+		*data = g_variant_new_double(state->horiz_triggerpos);
+		ret = SR_OK;
+		break;
+	case SR_CONF_COUPLING:
+		if (cg_type == CG_NONE) {
+			sr_err("No channel group specified.");
+			return SR_ERR_CHANNEL_GROUP;
+		} else if (cg_type == CG_ANALOG) {
+			for (i = 0; i < model->analog_channels; ++i) {
+				if (cg != &devc->analog_groups[i])
+					continue;
+				*data = g_variant_new_string((*model->coupling_options)[state->analog_channels[i].coupling]);
+				ret = SR_OK;
+				break;
+			}
+
+		} else {
+			ret = SR_ERR_NA;
+		}
+		break;
+	case SR_CONF_SAMPLERATE:
+		*data = g_variant_new_uint64(state->sample_rate);
+		ret = SR_OK;
+		break;
+	default:
+		ret = SR_ERR_NA;
+	}
+
+	return ret;
+}
+
+static GVariant *build_tuples(const uint64_t (*array)[][2], unsigned int n)
+{
+	unsigned int i;
+	GVariant *rational[2];
+	GVariantBuilder gvb;
+
+	g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
+
+	for (i = 0; i < n; i++) {
+		rational[0] = g_variant_new_uint64((*array)[i][0]);
+		rational[1] = g_variant_new_uint64((*array)[i][1]);
+
+		/* FIXME: Valgrind reports a memory leak here. */
+		g_variant_builder_add_value(&gvb, g_variant_new_tuple(rational, 2));
+	}
+
+	return g_variant_builder_end(&gvb);
+}
+
+static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+		      const struct sr_channel_group *cg)
+{
+	int ret, cg_type;
+	unsigned int i, j;
+	char command[MAX_COMMAND_SIZE], float_str[30];
+	struct dev_context *devc;
+	struct scope_config *model;
+	struct scope_state *state;
+	const char *tmp;
+	uint64_t p, q;
+	double tmp_d;
+	gboolean update_sample_rate;
+
+	if (!sdi || !(devc = sdi->priv))
+		return SR_ERR_ARG;
+
+	if ((cg_type = check_channel_group(devc, cg)) == CG_INVALID)
+		return SR_ERR;
+
+	model = devc->model_config;
+	state = devc->model_state;
+	update_sample_rate = FALSE;
+
+	ret = SR_ERR_NA;
+
+	switch (key) {
+	case SR_CONF_LIMIT_FRAMES:
+		devc->frame_limit = g_variant_get_uint64(data);
+		ret = SR_OK;
+		break;
+	case SR_CONF_TRIGGER_SOURCE:
+		tmp = g_variant_get_string(data, NULL);
+		for (i = 0; (*model->trigger_sources)[i]; i++) {
+			if (g_strcmp0(tmp, (*model->trigger_sources)[i]) != 0)
+				continue;
+			state->trigger_source = i;
+			g_snprintf(command, sizeof(command),
+				   (*model->scpi_dialect)[SCPI_CMD_SET_TRIGGER_SOURCE],
+				   (*model->trigger_sources)[i]);
+
+			ret = sr_scpi_send(sdi->conn, command);
+			break;
+		}
+		break;
+	case SR_CONF_VDIV:
+		if (cg_type == CG_NONE) {
+			sr_err("No channel group specified.");
+			return SR_ERR_CHANNEL_GROUP;
+		}
+
+		g_variant_get(data, "(tt)", &p, &q);
+
+		for (i = 0; i < model->num_vdivs; i++) {
+			if (p != (*model->vdivs)[i][0] ||
+			    q != (*model->vdivs)[i][1])
+				continue;
+			for (j = 1; j <= model->analog_channels; ++j) {
+				if (cg != &devc->analog_groups[j - 1])
+					continue;
+				state->analog_channels[j - 1].vdiv = i;
+				g_ascii_formatd(float_str, sizeof(float_str), "%E", (float) p / q);
+				g_snprintf(command, sizeof(command),
+					   (*model->scpi_dialect)[SCPI_CMD_SET_VERTICAL_DIV],
+					   j, float_str);
+
+				if (sr_scpi_send(sdi->conn, command) != SR_OK ||
+				    sr_scpi_get_opc(sdi->conn) != SR_OK)
+					return SR_ERR;
+
+				break;
+			}
+
+			ret = SR_OK;
+			break;
+		}
+		break;
+	case SR_CONF_TIMEBASE:
+		g_variant_get(data, "(tt)", &p, &q);
+
+		for (i = 0; i < model->num_timebases; i++) {
+			if (p != (*model->timebases)[i][0] ||
+			    q != (*model->timebases)[i][1])
+				continue;
+			state->timebase = i;
+			g_ascii_formatd(float_str, sizeof(float_str), "%E", (float) p / q);
+			g_snprintf(command, sizeof(command),
+				   (*model->scpi_dialect)[SCPI_CMD_SET_TIMEBASE],
+				   float_str);
+
+			ret = sr_scpi_send(sdi->conn, command);
+			update_sample_rate = TRUE;
+			break;
+		}
+		break;
+	case SR_CONF_HORIZ_TRIGGERPOS:
+		tmp_d = g_variant_get_double(data);
+
+		if (tmp_d < 0.0 || tmp_d > 1.0)
+			return SR_ERR;
+
+		state->horiz_triggerpos = tmp_d;
+		tmp_d = -(tmp_d - 0.5) *
+			((double) (*model->timebases)[state->timebase][0] /
+			(*model->timebases)[state->timebase][1])
+			 * model->num_xdivs;
+
+		g_ascii_formatd(float_str, sizeof(float_str), "%E", tmp_d);
+		g_snprintf(command, sizeof(command),
+			   (*model->scpi_dialect)[SCPI_CMD_SET_HORIZ_TRIGGERPOS],
+			   float_str);
+
+		ret = sr_scpi_send(sdi->conn, command);
+		break;
+	case SR_CONF_TRIGGER_SLOPE:
+		tmp = g_variant_get_string(data, NULL);
+
+		if (!tmp || !(tmp[0] == 'f' || tmp[0] == 'r'))
+			return SR_ERR_ARG;
+
+		state->trigger_slope = (tmp[0] == 'r') ? 0 : 1;
+
+		g_snprintf(command, sizeof(command),
+			   (*model->scpi_dialect)[SCPI_CMD_SET_TRIGGER_SLOPE],
+			   (state->trigger_slope == 0) ? "POS" : "NEG");
+
+		ret = sr_scpi_send(sdi->conn, command);
+		break;
+	case SR_CONF_COUPLING:
+		if (cg_type == CG_NONE) {
+			sr_err("No channel group specified.");
+			return SR_ERR_CHANNEL_GROUP;
+		}
+
+		tmp = g_variant_get_string(data, NULL);
+
+		for (i = 0; (*model->coupling_options)[i]; i++) {
+			if (strcmp(tmp, (*model->coupling_options)[i]) != 0)
+				continue;
+			for (j = 1; j <= model->analog_channels; ++j) {
+				if (cg != &devc->analog_groups[j - 1])
+					continue;
+				state->analog_channels[j-1].coupling = i;
+
+				g_snprintf(command, sizeof(command),
+					   (*model->scpi_dialect)[SCPI_CMD_SET_COUPLING],
+					   j, tmp);
+
+				if (sr_scpi_send(sdi->conn, command) != SR_OK ||
+				    sr_scpi_get_opc(sdi->conn) != SR_OK)
+					return SR_ERR;
+				break;
+			}
+
+			ret = SR_OK;
+			break;
+		}
+		break;
+	default:
+		ret = SR_ERR_NA;
+		break;
+	}
+
+	if (ret == SR_OK)
+		ret = sr_scpi_get_opc(sdi->conn);
+
+	if (ret == SR_OK && update_sample_rate)
+		ret = hmo_update_sample_rate(sdi);
+
+	return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		       const struct sr_channel_group *cg)
+{
+	int cg_type;
+	struct dev_context *devc;
+	struct scope_config *model;
+
+	if (!sdi || !(devc = sdi->priv))
+		return SR_ERR_ARG;
+
+	if ((cg_type = check_channel_group(devc, cg)) == CG_INVALID)
+		return SR_ERR;
+
+	model = devc->model_config;
+
+	switch (key) {
+	case SR_CONF_DEVICE_OPTIONS:
+		if (cg_type == CG_NONE) {
+			*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				model->hw_caps, model->num_hwcaps,
+				sizeof(int32_t));
+		} else if (cg_type == CG_ANALOG) {
+			*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				model->analog_hwcaps, model->num_analog_hwcaps,
+				sizeof(int32_t));
+		} else {
+			*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				NULL, 0, sizeof(int32_t));
+		}
+		break;
+	case SR_CONF_COUPLING:
+		if (cg_type == CG_NONE)
+			return SR_ERR_CHANNEL_GROUP;
+		*data = g_variant_new_strv(*model->coupling_options,
+			   g_strv_length((char **)*model->coupling_options));
+		break;
+	case SR_CONF_TRIGGER_SOURCE:
+		*data = g_variant_new_strv(*model->trigger_sources,
+			   g_strv_length((char **)*model->trigger_sources));
+		break;
+	case SR_CONF_TRIGGER_SLOPE:
+		*data = g_variant_new_strv(*model->trigger_slopes,
+			   g_strv_length((char **)*model->trigger_slopes));
+		break;
+	case SR_CONF_TIMEBASE:
+		*data = build_tuples(model->timebases, model->num_timebases);
+		break;
+	case SR_CONF_VDIV:
+		if (cg_type == CG_NONE)
+			return SR_ERR_CHANNEL_GROUP;
+		*data = build_tuples(model->vdivs, model->num_vdivs);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+SR_PRIV int hmo_request_data(const struct sr_dev_inst *sdi)
+{
+	char command[MAX_COMMAND_SIZE];
+	struct sr_channel *ch;
+	struct dev_context *devc;
+	struct scope_config *model;
+
+	devc = sdi->priv;
+	model = devc->model_config;
+
+	ch = devc->current_channel->data;
+
+	switch (ch->type) {
+	case SR_CHANNEL_ANALOG:
+		g_snprintf(command, sizeof(command),
+			   (*model->scpi_dialect)[SCPI_CMD_GET_ANALOG_DATA],
+			   ch->index + 1);
+		break;
+	case SR_CHANNEL_LOGIC:
+		g_snprintf(command, sizeof(command),
+			   (*model->scpi_dialect)[SCPI_CMD_GET_DIG_DATA],
+			   ch->index < 8 ? 1 : 2);
+		break;
+	default:
+		sr_err("Invalid channel type.");
+		break;
+	}
+
+	return sr_scpi_send(sdi->conn, command);
+}
+
+static int hmo_check_channels(GSList *channels)
+{
+	GSList *l;
+	struct sr_channel *ch;
+	gboolean enabled_pod1, enabled_pod2, enabled_chan3, enabled_chan4;
+
+	enabled_pod1 = enabled_pod2 = enabled_chan3 = enabled_chan4 = FALSE;
+
+	for (l = channels; l; l = l->next) {
+		ch = l->data;
+		switch (ch->type) {
+		case SR_CHANNEL_ANALOG:
+			if (ch->index == 2)
+				enabled_chan3 = TRUE;
+			else if (ch->index == 3)
+				enabled_chan4 = TRUE;
+			break;
+		case SR_CHANNEL_LOGIC:
+			if (ch->index < 8)
+				enabled_pod1 = TRUE;
+			else
+				enabled_pod2 = TRUE;
+			break;
+		default:
+			return SR_ERR;
+		}
+	}
+
+	if ((enabled_pod1 && enabled_chan3) ||
+	    (enabled_pod2 && enabled_chan4))
+		return SR_ERR;
+
+	return SR_OK;
+}
+
+static int hmo_setup_channels(const struct sr_dev_inst *sdi)
+{
+	GSList *l;
+	unsigned int i;
+	gboolean *pod_enabled, setup_changed;
+	char command[MAX_COMMAND_SIZE];
+	struct scope_state *state;
+	struct scope_config *model;
+	struct sr_channel *ch;
+	struct dev_context *devc;
+	struct sr_scpi_dev_inst *scpi;
+
+	devc = sdi->priv;
+	scpi = sdi->conn;
+	state = devc->model_state;
+	model = devc->model_config;
+	setup_changed = FALSE;
+
+	pod_enabled = g_try_malloc0(sizeof(gboolean) * model->digital_pods);
+
+	for (l = sdi->channels; l; l = l->next) {
+		ch = l->data;
+		switch (ch->type) {
+		case SR_CHANNEL_ANALOG:
+			if (ch->enabled == state->analog_channels[ch->index].state)
+				break;
+			g_snprintf(command, sizeof(command),
+				   (*model->scpi_dialect)[SCPI_CMD_SET_ANALOG_CHAN_STATE],
+				   ch->index + 1, ch->enabled);
+
+			if (sr_scpi_send(scpi, command) != SR_OK)
+				return SR_ERR;
+			state->analog_channels[ch->index].state = ch->enabled;
+			setup_changed = TRUE;
+			break;
+		case SR_CHANNEL_LOGIC:
+			/*
+			 * A digital POD needs to be enabled for every group of
+			 * 8 channels.
+			 */
+			if (ch->enabled)
+				pod_enabled[ch->index < 8 ? 0 : 1] = TRUE;
+
+			if (ch->enabled == state->digital_channels[ch->index])
+				break;
+			g_snprintf(command, sizeof(command),
+				   (*model->scpi_dialect)[SCPI_CMD_SET_DIG_CHAN_STATE],
+				   ch->index, ch->enabled);
+
+			if (sr_scpi_send(scpi, command) != SR_OK)
+				return SR_ERR;
+
+			state->digital_channels[ch->index] = ch->enabled;
+			setup_changed = TRUE;
+			break;
+		default:
+			return SR_ERR;
+		}
+	}
+
+	for (i = 1; i <= model->digital_pods; ++i) {
+		if (state->digital_pods[i - 1] == pod_enabled[i - 1])
+			continue;
+		g_snprintf(command, sizeof(command),
+			   (*model->scpi_dialect)[SCPI_CMD_SET_DIG_POD_STATE],
+			   i, pod_enabled[i - 1]);
+		if (sr_scpi_send(scpi, command) != SR_OK)
+			return SR_ERR;
+		state->digital_pods[i - 1] = pod_enabled[i - 1];
+		setup_changed = TRUE;
+	}
+
+	g_free(pod_enabled);
+
+	if (setup_changed && hmo_update_sample_rate(sdi) != SR_OK)
+		return SR_ERR;
+
+	return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+	GSList *l;
+	gboolean digital_added;
+	struct sr_channel *ch;
+	struct dev_context *devc;
+	struct sr_scpi_dev_inst *scpi;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	scpi = sdi->conn;
+	devc = sdi->priv;
+	digital_added = FALSE;
+
+	for (l = sdi->channels; l; l = l->next) {
+		ch = l->data;
+		if (!ch->enabled)
+			continue;
+		/* Only add a single digital channel. */
+		if (ch->type != SR_CHANNEL_LOGIC || !digital_added) {
+			devc->enabled_channels = g_slist_append(
+					devc->enabled_channels, ch);
+			if (ch->type == SR_CHANNEL_LOGIC)
+				digital_added = TRUE;
+		}
+	}
+
+	if (!devc->enabled_channels)
+		return SR_ERR;
+
+	if (hmo_check_channels(devc->enabled_channels) != SR_OK) {
+		sr_err("Invalid channel configuration specified!");
+		return SR_ERR_NA;
+	}
+
+	if (hmo_setup_channels(sdi) != SR_OK) {
+		sr_err("Failed to setup channel configuration!");
+		return SR_ERR;
+	}
+
+	sr_scpi_source_add(scpi, G_IO_IN, 50, hmo_receive_data, (void *)sdi);
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	devc->current_channel = devc->enabled_channels;
+
+	return hmo_request_data(sdi);
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct dev_context *devc;
+	struct sr_scpi_dev_inst *scpi;
+	struct sr_datafeed_packet packet;
+
+	(void)cb_data;
+
+	packet.type = SR_DF_END;
+	packet.payload = NULL;
+	sr_session_send(sdi, &packet);
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	devc = sdi->priv;
+
+	devc->num_frames = 0;
+	g_slist_free(devc->enabled_channels);
+	devc->enabled_channels = NULL;
+	scpi = sdi->conn;
+	sr_scpi_source_remove(scpi);
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver hameg_hmo_driver_info = {
+	.name = "hameg-hmo",
+	.longname = "Hameg HMO",
+	.api_version = 1,
+	.init = init,
+	.cleanup = cleanup,
+	.scan = scan,
+	.dev_list = dev_list,
+	.dev_clear = dev_clear,
+	.config_get = config_get,
+	.config_set = config_set,
+	.config_list = config_list,
+	.dev_open = dev_open,
+	.dev_close = dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/hameg-hmo/protocol.c b/hardware/hameg-hmo/protocol.c
new file mode 100644
index 0000000..afa6efe
--- /dev/null
+++ b/hardware/hameg-hmo/protocol.c
@@ -0,0 +1,741 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 poljar (Damir Jelić) <poljarinho at gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "protocol.h"
+
+static const char *hameg_scpi_dialect[] = {
+	[SCPI_CMD_GET_DIG_DATA]		    = ":POD%d:DATA?",
+	[SCPI_CMD_GET_TIMEBASE]		    = ":TIM:SCAL?",
+	[SCPI_CMD_SET_TIMEBASE]		    = ":TIM:SCAL %s",
+	[SCPI_CMD_GET_COUPLING]		    = ":CHAN%d:COUP?",
+	[SCPI_CMD_SET_COUPLING]		    = ":CHAN%d:COUP %s",
+	[SCPI_CMD_GET_SAMPLE_RATE]	    = ":ACQ:SRAT?",
+	[SCPI_CMD_GET_SAMPLE_RATE_LIVE]	    = ":%s:DATA:POINTS?",
+	[SCPI_CMD_GET_ANALOG_DATA]	    = ":CHAN%d:DATA?",
+	[SCPI_CMD_GET_VERTICAL_DIV]	    = ":CHAN%d:SCAL?",
+	[SCPI_CMD_SET_VERTICAL_DIV]	    = ":CHAN%d:SCAL %s",
+	[SCPI_CMD_GET_DIG_POD_STATE]	    = ":POD%d:STAT?",
+	[SCPI_CMD_SET_DIG_POD_STATE]	    = ":POD%d:STAT %d",
+	[SCPI_CMD_GET_TRIGGER_SLOPE]	    = ":TRIG:A:EDGE:SLOP?",
+	[SCPI_CMD_SET_TRIGGER_SLOPE]	    = ":TRIG:A:EDGE:SLOP %s",
+	[SCPI_CMD_GET_TRIGGER_SOURCE]	    = ":TRIG:A:SOUR?",
+	[SCPI_CMD_SET_TRIGGER_SOURCE]	    = ":TRIG:A:SOUR %s",
+	[SCPI_CMD_GET_DIG_CHAN_STATE]	    = ":LOG%d:STAT?",
+	[SCPI_CMD_SET_DIG_CHAN_STATE]	    = ":LOG%d:STAT %d",
+	[SCPI_CMD_GET_VERTICAL_OFFSET]	    = ":CHAN%d:POS?",
+	[SCPI_CMD_GET_HORIZ_TRIGGERPOS]	    = ":TIM:POS?",
+	[SCPI_CMD_SET_HORIZ_TRIGGERPOS]	    = ":TIM:POS %s",
+	[SCPI_CMD_GET_ANALOG_CHAN_STATE]    = ":CHAN%d:STAT?",
+	[SCPI_CMD_SET_ANALOG_CHAN_STATE]    = ":CHAN%d:STAT %d",
+};
+
+static const int32_t hmo_hwcaps[] = {
+	SR_CONF_OSCILLOSCOPE,
+	SR_CONF_TRIGGER_SOURCE,
+	SR_CONF_TIMEBASE,
+	SR_CONF_NUM_TIMEBASE,
+	SR_CONF_TRIGGER_SLOPE,
+	SR_CONF_HORIZ_TRIGGERPOS,
+	SR_CONF_SAMPLERATE,
+	SR_CONF_LIMIT_FRAMES,
+};
+
+static const int32_t hmo_analog_caps[] = {
+	SR_CONF_NUM_VDIV,
+	SR_CONF_COUPLING,
+	SR_CONF_VDIV,
+};
+
+static const char *hmo_coupling_options[] = {
+	"AC",
+	"ACL",
+	"DC",
+	"DCL",
+	"GND",
+	NULL,
+};
+
+static const char *scope_trigger_slopes[] = {
+	"POS",
+	"NEG",
+	NULL,
+};
+
+static const char *hmo_compact2_trigger_sources[] = {
+	"CH1",
+	"CH2",
+	"LINE",
+	"EXT",
+	"D0",
+	"D1",
+	"D2",
+	"D3",
+	"D4",
+	"D5",
+	"D6",
+	"D7",
+	NULL,
+};
+
+static const char *hmo_compact4_trigger_sources[] = {
+	"CH1",
+	"CH2",
+	"CH3",
+	"CH4",
+	"LINE",
+	"EXT",
+	"D0",
+	"D1",
+	"D2",
+	"D3",
+	"D4",
+	"D5",
+	"D6",
+	"D7",
+	NULL,
+};
+
+static const uint64_t hmo_timebases[][2] = {
+	/* nanoseconds */
+	{ 2, 1000000000 },
+	{ 5, 1000000000 },
+	{ 10, 1000000000 },
+	{ 20, 1000000000 },
+	{ 50, 1000000000 },
+	{ 100, 1000000000 },
+	{ 200, 1000000000 },
+	{ 500, 1000000000 },
+	/* microseconds */
+	{ 1, 1000000 },
+	{ 2, 1000000 },
+	{ 5, 1000000 },
+	{ 10, 1000000 },
+	{ 20, 1000000 },
+	{ 50, 1000000 },
+	{ 100, 1000000 },
+	{ 200, 1000000 },
+	{ 500, 1000000 },
+	/* milliseconds */
+	{ 1, 1000 },
+	{ 2, 1000 },
+	{ 5, 1000 },
+	{ 10, 1000 },
+	{ 20, 1000 },
+	{ 50, 1000 },
+	{ 100, 1000 },
+	{ 200, 1000 },
+	{ 500, 1000 },
+	/* seconds */
+	{ 1, 1 },
+	{ 2, 1 },
+	{ 5, 1 },
+	{ 10, 1 },
+	{ 20, 1 },
+	{ 50, 1 },
+};
+
+static const uint64_t hmo_vdivs[][2] = {
+	/* millivolts */
+	{ 1, 1000 },
+	{ 2, 1000 },
+	{ 5, 1000 },
+	{ 10, 1000 },
+	{ 20, 1000 },
+	{ 50, 1000 },
+	{ 100, 1000 },
+	{ 200, 1000 },
+	{ 500, 1000 },
+	/* volts */
+	{ 1, 1 },
+	{ 2, 1 },
+	{ 5, 1 },
+	{ 10, 1 },
+};
+
+static const char *scope_analog_channel_names[] = {
+	"CH1",
+	"CH2",
+	"CH3",
+	"CH4",
+};
+
+static const char *scope_digital_channel_names[] = {
+	"D0",
+	"D1",
+	"D2",
+	"D3",
+	"D4",
+	"D5",
+	"D6",
+	"D7",
+	"D8",
+	"D9",
+	"D10",
+	"D11",
+	"D12",
+	"D13",
+	"D14",
+	"D15",
+};
+
+static struct scope_config scope_models[] = {
+	{
+		.name = {"HMO722", "HMO1022", "HMO1522", "HMO2022", NULL},
+		.analog_channels = 2,
+		.digital_channels = 8,
+		.digital_pods = 1,
+
+		.analog_names = &scope_analog_channel_names,
+		.digital_names = &scope_digital_channel_names,
+
+		.hw_caps = &hmo_hwcaps,
+		.num_hwcaps = ARRAY_SIZE(hmo_hwcaps),
+
+		.analog_hwcaps = &hmo_analog_caps,
+		.num_analog_hwcaps = ARRAY_SIZE(hmo_analog_caps),
+
+		.coupling_options = &hmo_coupling_options,
+		.trigger_sources = &hmo_compact2_trigger_sources,
+		.trigger_slopes = &scope_trigger_slopes,
+
+		.timebases = &hmo_timebases,
+		.num_timebases = ARRAY_SIZE(hmo_timebases),
+
+		.vdivs = &hmo_vdivs,
+		.num_vdivs = ARRAY_SIZE(hmo_vdivs),
+
+		.num_xdivs = 12,
+		.num_ydivs = 8,
+
+		.scpi_dialect = &hameg_scpi_dialect,
+	},
+	{
+		.name = {"HMO724", "HMO1024", "HMO1524", "HMO2024", NULL},
+		.analog_channels = 4,
+		.digital_channels = 8,
+		.digital_pods = 1,
+
+		.analog_names = &scope_analog_channel_names,
+		.digital_names = &scope_digital_channel_names,
+
+		.hw_caps = &hmo_hwcaps,
+		.num_hwcaps = ARRAY_SIZE(hmo_hwcaps),
+
+		.analog_hwcaps = &hmo_analog_caps,
+		.num_analog_hwcaps = ARRAY_SIZE(hmo_analog_caps),
+
+		.coupling_options = &hmo_coupling_options,
+		.trigger_sources = &hmo_compact4_trigger_sources,
+		.trigger_slopes = &scope_trigger_slopes,
+
+		.timebases = &hmo_timebases,
+		.num_timebases = ARRAY_SIZE(hmo_timebases),
+
+		.vdivs = &hmo_vdivs,
+		.num_vdivs = ARRAY_SIZE(hmo_vdivs),
+
+		.num_xdivs = 12,
+		.num_ydivs = 8,
+
+		.scpi_dialect = &hameg_scpi_dialect,
+	},
+};
+
+static void scope_state_dump(struct scope_config *config,
+			     struct scope_state *state)
+{
+	unsigned int i;
+	char *tmp;
+
+	for (i = 0; i < config->analog_channels; ++i) {
+		tmp = sr_voltage_string((*config->vdivs)[state->analog_channels[i].vdiv][0],
+					     (*config->vdivs)[state->analog_channels[i].vdiv][1]);
+		sr_info("State of analog channel  %d -> %s : %s (coupling) %s (vdiv) %2.2e (offset)",
+			i + 1, state->analog_channels[i].state ? "On" : "Off",
+			(*config->coupling_options)[state->analog_channels[i].coupling],
+			tmp, state->analog_channels[i].vertical_offset);
+	}
+
+	for (i = 0; i < config->digital_channels; ++i) {
+		sr_info("State of digital channel %d -> %s", i,
+			state->digital_channels[i] ? "On" : "Off");
+	}
+
+	for (i = 0; i < config->digital_pods; ++i) {
+		sr_info("State of digital POD %d -> %s", i,
+			state->digital_pods[i] ? "On" : "Off");
+	}
+
+	tmp = sr_period_string((*config->timebases)[state->timebase][0] *
+			       (*config->timebases)[state->timebase][1]);
+	sr_info("Current timebase: %s", tmp);
+	g_free(tmp);
+
+	tmp = sr_samplerate_string(state->sample_rate);
+	sr_info("Current samplerate: %s", tmp);
+	g_free(tmp);
+
+	sr_info("Current trigger: %s (source), %s (slope) %.2f (offset)",
+		(*config->trigger_sources)[state->trigger_source],
+		(*config->trigger_slopes)[state->trigger_slope],
+		state->horiz_triggerpos);
+}
+
+static int scope_state_get_array_option(struct sr_scpi_dev_inst *scpi,
+		const char *command, const char *(*array)[], int *result)
+{
+	char *tmp;
+	unsigned int i;
+
+	if (sr_scpi_get_string(scpi, command, &tmp) != SR_OK) {
+		g_free(tmp);
+		return SR_ERR;
+	}
+
+	for (i = 0; (*array)[i]; ++i) {
+		if (!g_strcmp0(tmp, (*array)[i])) {
+			*result = i;
+			g_free(tmp);
+			tmp = NULL;
+			break;
+		}
+	}
+
+	if (tmp) {
+		g_free(tmp);
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+static int analog_channel_state_get(struct sr_scpi_dev_inst *scpi,
+				    struct scope_config *config,
+				    struct scope_state *state)
+{
+	unsigned int i, j;
+	float tmp_float;
+	char command[MAX_COMMAND_SIZE];
+
+	for (i = 0; i < config->analog_channels; ++i) {
+		g_snprintf(command, sizeof(command),
+			   (*config->scpi_dialect)[SCPI_CMD_GET_ANALOG_CHAN_STATE],
+			   i + 1);
+
+		if (sr_scpi_get_bool(scpi, command,
+				     &state->analog_channels[i].state) != SR_OK)
+			return SR_ERR;
+
+		g_snprintf(command, sizeof(command),
+			   (*config->scpi_dialect)[SCPI_CMD_GET_VERTICAL_DIV],
+			   i + 1);
+
+		if (sr_scpi_get_float(scpi, command, &tmp_float) != SR_OK)
+			return SR_ERR;
+		for (j = 0; j < config->num_vdivs; j++) {
+			if (tmp_float == ((float) (*config->vdivs)[j][0] /
+					  (*config->vdivs)[j][1])) {
+				state->analog_channels[i].vdiv = j;
+				break;
+			}
+		}
+		if (i == config->num_vdivs)
+			return SR_ERR;
+
+		g_snprintf(command, sizeof(command),
+			   (*config->scpi_dialect)[SCPI_CMD_GET_VERTICAL_OFFSET],
+			   i + 1);
+
+		if (sr_scpi_get_float(scpi, command,
+				     &state->analog_channels[i].vertical_offset) != SR_OK)
+			return SR_ERR;
+
+		g_snprintf(command, sizeof(command),
+			   (*config->scpi_dialect)[SCPI_CMD_GET_COUPLING],
+			   i + 1);
+
+		if (scope_state_get_array_option(scpi, command, config->coupling_options,
+					 &state->analog_channels[i].coupling) != SR_OK)
+			return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+static int digital_channel_state_get(struct sr_scpi_dev_inst *scpi,
+				     struct scope_config *config,
+				     struct scope_state *state)
+{
+	unsigned int i;
+	char command[MAX_COMMAND_SIZE];
+
+	for (i = 0; i < config->digital_channels; ++i) {
+		g_snprintf(command, sizeof(command),
+			   (*config->scpi_dialect)[SCPI_CMD_GET_DIG_CHAN_STATE],
+			   i);
+
+		if (sr_scpi_get_bool(scpi, command,
+				     &state->digital_channels[i]) != SR_OK)
+			return SR_ERR;
+	}
+
+	for (i = 0; i < config->digital_pods; ++i) {
+		g_snprintf(command, sizeof(command),
+			   (*config->scpi_dialect)[SCPI_CMD_GET_DIG_POD_STATE],
+			   i + 1);
+
+		if (sr_scpi_get_bool(scpi, command,
+				     &state->digital_pods[i]) != SR_OK)
+			return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+SR_PRIV int hmo_update_sample_rate(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct scope_state *state;
+	struct scope_config *config;
+
+	int tmp;
+	unsigned int i;
+	float tmp_float;
+	gboolean channel_found;
+	char tmp_str[MAX_COMMAND_SIZE];
+	char chan_name[20];
+
+	devc = sdi->priv;
+	config = devc->model_config;
+	state = devc->model_state;
+	channel_found = FALSE;
+
+	for (i = 0; i < config->analog_channels; ++i) {
+		if (state->analog_channels[i].state) {
+			g_snprintf(chan_name, sizeof(chan_name), "CHAN%d", i + 1);
+			g_snprintf(tmp_str, sizeof(tmp_str),
+				   (*config->scpi_dialect)[SCPI_CMD_GET_SAMPLE_RATE_LIVE],
+				   chan_name);
+			channel_found = TRUE;
+			break;
+		}
+	}
+
+	if (!channel_found) {
+		for (i = 0; i < config->digital_pods; i++) {
+			if (state->digital_pods[i]) {
+				g_snprintf(chan_name, sizeof(chan_name), "POD%d", i);
+				g_snprintf(tmp_str, sizeof(tmp_str),
+					   (*config->scpi_dialect)[SCPI_CMD_GET_SAMPLE_RATE_LIVE],
+					   chan_name);
+				channel_found = TRUE;
+				break;
+			}
+		}
+	}
+
+	/* No channel is active, ask the instrument for the sample rate
+	 * in single shot mode */
+	if (!channel_found) {
+		if (sr_scpi_get_float(sdi->conn,
+				      (*config->scpi_dialect)[SCPI_CMD_GET_SAMPLE_RATE],
+				      &tmp_float) != SR_OK)
+			return SR_ERR;
+
+		state->sample_rate = tmp_float;
+	} else {
+		if (sr_scpi_get_int(sdi->conn, tmp_str, &tmp) != SR_OK)
+			return SR_ERR;
+		state->sample_rate = tmp / (((float) (*config->timebases)[state->timebase][0] /
+					     (*config->timebases)[state->timebase][1]) *
+					    config->num_xdivs);
+	}
+
+	return SR_OK;
+}
+
+SR_PRIV int hmo_scope_state_get(struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct scope_state *state;
+	struct scope_config *config;
+	float tmp_float;
+	unsigned int i;
+
+	devc = sdi->priv;
+	config = devc->model_config;
+	state = devc->model_state;
+
+	sr_info("Fetching scope state");
+
+	if (analog_channel_state_get(sdi->conn, config, state) != SR_OK)
+		return SR_ERR;
+
+	if (digital_channel_state_get(sdi->conn, config, state) != SR_OK)
+		return SR_ERR;
+
+	if (sr_scpi_get_float(sdi->conn,
+			(*config->scpi_dialect)[SCPI_CMD_GET_TIMEBASE],
+			&tmp_float) != SR_OK)
+		return SR_ERR;
+
+	for (i = 0; i < config->num_timebases; i++) {
+		if (tmp_float == ((float) (*config->timebases)[i][0] /
+				  (*config->timebases)[i][1])) {
+			state->timebase = i;
+			break;
+		}
+	}
+	if (i == config->num_timebases)
+		return SR_ERR;
+
+	if (sr_scpi_get_float(sdi->conn,
+			(*config->scpi_dialect)[SCPI_CMD_GET_HORIZ_TRIGGERPOS],
+			&tmp_float) != SR_OK)
+		return SR_ERR;
+	state->horiz_triggerpos = tmp_float /
+		(((double) (*config->timebases)[state->timebase][0] /
+		  (*config->timebases)[state->timebase][1]) * config->num_xdivs);
+	state->horiz_triggerpos -= 0.5;
+	state->horiz_triggerpos *= -1;
+
+	if (scope_state_get_array_option(sdi->conn,
+			(*config->scpi_dialect)[SCPI_CMD_GET_TRIGGER_SOURCE],
+			config->trigger_sources, &state->trigger_source) != SR_OK)
+		return SR_ERR;
+
+	if (scope_state_get_array_option(sdi->conn,
+		(*config->scpi_dialect)[SCPI_CMD_GET_TRIGGER_SLOPE],
+		config->trigger_slopes, &state->trigger_slope) != SR_OK)
+		return SR_ERR;
+
+	if (hmo_update_sample_rate(sdi) != SR_OK)
+		return SR_ERR;
+
+	sr_info("Fetching finished.");
+
+	scope_state_dump(config, state);
+
+	return SR_OK;
+}
+
+static struct scope_state *scope_state_new(struct scope_config *config)
+{
+	struct scope_state *state;
+
+	if (!(state = g_try_malloc0(sizeof(struct scope_state))))
+		return NULL;
+
+	if (!(state->analog_channels = g_try_malloc0_n(config->analog_channels,
+				    sizeof(struct analog_channel_state))))
+	    goto fail;
+
+	if (!(state->digital_channels = g_try_malloc0_n(
+			config->digital_channels, sizeof(gboolean))))
+	    goto fail;
+
+	if (!(state->digital_pods = g_try_malloc0_n(config->digital_pods,
+						     sizeof(gboolean))))
+	    goto fail;
+
+	return state;
+
+fail:
+	if (state->analog_channels)
+		g_free(state->analog_channels);
+	if (state->digital_channels)
+		g_free(state->digital_channels);
+	if (state->digital_pods)
+		g_free(state->digital_pods);
+	g_free(state);
+
+	return NULL;
+}
+
+SR_PRIV void hmo_scope_state_free(struct scope_state *state)
+{
+	g_free(state->analog_channels);
+	g_free(state->digital_channels);
+	g_free(state->digital_pods);
+	g_free(state);
+}
+
+SR_PRIV int hmo_init_device(struct sr_dev_inst *sdi)
+{
+	char tmp[25];
+	int model_index;
+	unsigned int i, j;
+	struct sr_channel *ch;
+	struct dev_context *devc;
+
+	devc = sdi->priv;
+	model_index = -1;
+
+	/* Find the exact model. */
+	for (i = 0; i < ARRAY_SIZE(scope_models); i++) {
+		for (j = 0; scope_models[i].name[j]; j++) {
+			if (!strcmp(sdi->model, scope_models[i].name[j])) {
+				model_index = i;
+				break;
+			}
+		}
+		if (model_index != -1)
+			break;
+	}
+
+	if (model_index == -1) {
+		sr_dbg("Unsupported HMO device.");
+		return SR_ERR_NA;
+	}
+
+	if (!(devc->analog_groups = g_try_malloc0(sizeof(struct sr_channel_group) *
+						  scope_models[model_index].analog_channels)))
+			return SR_ERR_MALLOC;
+
+	if (!(devc->digital_groups = g_try_malloc0(sizeof(struct sr_channel_group) *
+						   scope_models[model_index].digital_pods)))
+			return SR_ERR_MALLOC;
+
+	/* Add analog channels. */
+	for (i = 0; i < scope_models[model_index].analog_channels; i++) {
+		if (!(ch = sr_channel_new(i, SR_CHANNEL_ANALOG, TRUE,
+			   (*scope_models[model_index].analog_names)[i])))
+			return SR_ERR_MALLOC;
+		sdi->channels = g_slist_append(sdi->channels, ch);
+
+		devc->analog_groups[i].name =
+			(char *)(*scope_models[model_index].analog_names)[i];
+		devc->analog_groups[i].channels = g_slist_append(NULL, ch);
+
+		sdi->channel_groups = g_slist_append(sdi->channel_groups,
+						   &devc->analog_groups[i]);
+	}
+
+	/* Add digital channel groups. */
+	for (i = 0; i < scope_models[model_index].digital_pods; ++i) {
+		g_snprintf(tmp, 25, "POD%d", i);
+		devc->digital_groups[i].name = g_strdup(tmp);
+		sdi->channel_groups = g_slist_append(sdi->channel_groups,
+				   &devc->digital_groups[i < 8 ? 0 : 1]);
+	}
+
+	/* Add digital channels. */
+	for (i = 0; i < scope_models[model_index].digital_channels; i++) {
+		if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE,
+			   (*scope_models[model_index].digital_names)[i])))
+			return SR_ERR_MALLOC;
+		sdi->channels = g_slist_append(sdi->channels, ch);
+
+		devc->digital_groups[i < 8 ? 0 : 1].channels = g_slist_append(
+			devc->digital_groups[i < 8 ? 0 : 1].channels, ch);
+	}
+
+	devc->model_config = &scope_models[model_index];
+	devc->frame_limit = 0;
+
+	if (!(devc->model_state = scope_state_new(devc->model_config)))
+		return SR_ERR_MALLOC;
+
+	return SR_OK;
+}
+
+SR_PRIV int hmo_receive_data(int fd, int revents, void *cb_data)
+{
+	struct sr_channel *ch;
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+	struct sr_datafeed_packet packet;
+	GArray *data;
+	struct sr_datafeed_analog analog;
+	struct sr_datafeed_logic logic;
+
+	(void)fd;
+
+	if (!(sdi = cb_data))
+		return TRUE;
+
+	if (!(devc = sdi->priv))
+		return TRUE;
+
+	if (revents == G_IO_IN) {
+		ch = devc->current_channel->data;
+
+		switch (ch->type) {
+		case SR_CHANNEL_ANALOG:
+			if (sr_scpi_get_floatv(sdi->conn, NULL, &data) != SR_OK) {
+				if (data)
+					g_array_free(data, TRUE);
+
+				return TRUE;
+			}
+
+			packet.type = SR_DF_FRAME_BEGIN;
+			sr_session_send(sdi, &packet);
+
+			analog.channels = g_slist_append(NULL, ch);
+			analog.num_samples = data->len;
+			analog.data = (float *) data->data;
+			analog.mq = SR_MQ_VOLTAGE;
+			analog.unit = SR_UNIT_VOLT;
+			analog.mqflags = 0;
+			packet.type = SR_DF_ANALOG;
+			packet.payload = &analog;
+			sr_session_send(cb_data, &packet);
+			g_slist_free(analog.channels);
+			g_array_free(data, TRUE);
+			break;
+		case SR_CHANNEL_LOGIC:
+			if (sr_scpi_get_uint8v(sdi->conn, NULL, &data) != SR_OK) {
+				if (data)
+					g_free(data);
+				return TRUE;
+			}
+
+			packet.type = SR_DF_FRAME_BEGIN;
+			sr_session_send(sdi, &packet);
+
+			logic.length = data->len;
+			logic.unitsize = 1;
+			logic.data = data->data;
+			packet.type = SR_DF_LOGIC;
+			packet.payload = &logic;
+			sr_session_send(cb_data, &packet);
+			g_array_free(data, TRUE);
+			break;
+		default:
+			sr_err("Invalid channel type.");
+			break;
+		}
+
+		packet.type = SR_DF_FRAME_END;
+		sr_session_send(sdi, &packet);
+
+		if (devc->current_channel->next) {
+			devc->current_channel = devc->current_channel->next;
+			hmo_request_data(sdi);
+		} else if (++devc->num_frames == devc->frame_limit) {
+			sdi->driver->dev_acquisition_stop(sdi, cb_data);
+		} else {
+			devc->current_channel = devc->enabled_channels;
+			hmo_request_data(sdi);
+		}
+	}
+
+	return TRUE;
+}
diff --git a/hardware/hameg-hmo/protocol.h b/hardware/hameg-hmo/protocol.h
new file mode 100644
index 0000000..bdf70fc
--- /dev/null
+++ b/hardware/hameg-hmo/protocol.h
@@ -0,0 +1,115 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 poljar (Damir Jelić) <poljarinho at gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_HAMEG_HMO_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_HAMEG_HMO_PROTOCOL_H
+
+#include <glib.h>
+#include <stdint.h>
+#include <string.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "hameg-hmo"
+
+#define MAX_INSTRUMENT_VERSIONS 10
+#define MAX_COMMAND_SIZE 31
+
+struct scope_config {
+	const char *name[MAX_INSTRUMENT_VERSIONS];
+	const uint8_t analog_channels;
+	const uint8_t digital_channels;
+	const uint8_t digital_pods;
+
+	const char *(*analog_names)[];
+	const char *(*digital_names)[];
+
+	const int32_t (*hw_caps)[];
+	const uint8_t num_hwcaps;
+
+	const int32_t (*analog_hwcaps)[];
+	const uint8_t num_analog_hwcaps;
+
+	const char *(*coupling_options)[];
+	const uint8_t num_coupling_options;
+
+	const char *(*trigger_sources)[];
+	const uint8_t num_trigger_sources;
+
+	const char *(*trigger_slopes)[];
+
+	const uint64_t (*timebases)[][2];
+	const uint8_t num_timebases;
+
+	const uint64_t (*vdivs)[][2];
+	const uint8_t num_vdivs;
+
+	const uint8_t num_xdivs;
+	const uint8_t num_ydivs;
+
+	const char *(*scpi_dialect)[];
+};
+
+struct analog_channel_state {
+	int coupling;
+
+	int vdiv;
+	float vertical_offset;
+
+	gboolean state;
+};
+
+struct scope_state {
+	struct analog_channel_state *analog_channels;
+	gboolean *digital_channels;
+	gboolean *digital_pods;
+
+	int timebase;
+	float horiz_triggerpos;
+
+	int trigger_source;
+	int trigger_slope;
+	uint64_t sample_rate;
+};
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+	void *model_config;
+	void *model_state;
+
+	struct sr_channel_group *analog_groups;
+	struct sr_channel_group *digital_groups;
+
+	GSList *enabled_channels;
+	GSList *current_channel;
+	uint64_t num_frames;
+
+	uint64_t frame_limit;
+};
+
+SR_PRIV int hmo_init_device(struct sr_dev_inst *sdi);
+SR_PRIV int hmo_request_data(const struct sr_dev_inst *sdi);
+SR_PRIV int hmo_receive_data(int fd, int revents, void *cb_data);
+
+SR_PRIV struct scope_state *hmo_scope_state_new(struct scope_config *config);
+SR_PRIV void hmo_scope_state_free(struct scope_state *state);
+SR_PRIV int hmo_scope_state_get(struct sr_dev_inst *sdi);
+SR_PRIV int hmo_update_sample_rate(const struct sr_dev_inst *sdi);
+
+#endif
diff --git a/hardware/hantek-dso/api.c b/hardware/hantek-dso/api.c
new file mode 100644
index 0000000..76696d5
--- /dev/null
+++ b/hardware/hantek-dso/api.c
@@ -0,0 +1,976 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/time.h>
+#include <inttypes.h>
+#include <glib.h>
+#include <libusb.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "dso.h"
+
+/* Max time in ms before we want to check on USB events */
+/* TODO tune this properly */
+#define TICK 1
+
+#define NUM_TIMEBASE  10
+#define NUM_VDIV      8
+
+static const int32_t scanopts[] = {
+	SR_CONF_CONN,
+};
+
+static const int32_t devopts[] = {
+	SR_CONF_OSCILLOSCOPE,
+	SR_CONF_LIMIT_FRAMES,
+	SR_CONF_CONTINUOUS,
+	SR_CONF_TIMEBASE,
+	SR_CONF_BUFFERSIZE,
+	SR_CONF_TRIGGER_SOURCE,
+	SR_CONF_TRIGGER_SLOPE,
+	SR_CONF_HORIZ_TRIGGERPOS,
+	SR_CONF_FILTER,
+	SR_CONF_VDIV,
+	SR_CONF_COUPLING,
+	SR_CONF_NUM_TIMEBASE,
+	SR_CONF_NUM_VDIV,
+};
+
+static const char *channel_names[] = {
+	"CH1", "CH2",
+	NULL,
+};
+
+static const uint64_t buffersizes_32k[] = {
+	10240, 32768,
+};
+static const uint64_t buffersizes_512k[] = {
+	10240, 524288,
+};
+static const uint64_t buffersizes_14k[] = {
+	10240, 14336,
+};
+
+static const struct dso_profile dev_profiles[] = {
+	{	0x04b4, 0x2090, 0x04b5, 0x2090,
+		"Hantek", "DSO-2090",
+		buffersizes_32k,
+		FIRMWARE_DIR "/hantek-dso-2090.fw" },
+	{	0x04b4, 0x2150, 0x04b5, 0x2150,
+		"Hantek", "DSO-2150",
+		buffersizes_32k,
+		FIRMWARE_DIR "/hantek-dso-2150.fw" },
+	{	0x04b4, 0x2250, 0x04b5, 0x2250,
+		"Hantek", "DSO-2250",
+		buffersizes_512k,
+		FIRMWARE_DIR "/hantek-dso-2250.fw" },
+	{	0x04b4, 0x5200, 0x04b5, 0x5200,
+		"Hantek", "DSO-5200",
+		buffersizes_14k,
+		FIRMWARE_DIR "/hantek-dso-5200.fw" },
+	{	0x04b4, 0x520a, 0x04b5, 0x520a,
+		"Hantek", "DSO-5200A",
+		buffersizes_512k,
+		FIRMWARE_DIR "/hantek-dso-5200A.fw" },
+	{ 0, 0, 0, 0, 0, 0, 0, 0 },
+};
+
+static const uint64_t timebases[][2] = {
+	/* microseconds */
+	{ 10, 1000000 },
+	{ 20, 1000000 },
+	{ 40, 1000000 },
+	{ 100, 1000000 },
+	{ 200, 1000000 },
+	{ 400, 1000000 },
+	/* milliseconds */
+	{ 1, 1000 },
+	{ 2, 1000 },
+	{ 4, 1000 },
+	{ 10, 1000 },
+	{ 20, 1000 },
+	{ 40, 1000 },
+	{ 100, 1000 },
+	{ 200, 1000 },
+	{ 400, 1000 },
+};
+
+static const uint64_t vdivs[][2] = {
+	/* millivolts */
+	{ 10, 1000 },
+	{ 20, 1000 },
+	{ 50, 1000 },
+	{ 100, 1000 },
+	{ 200, 1000 },
+	{ 500, 1000 },
+	/* volts */
+	{ 1, 1 },
+	{ 2, 1 },
+	{ 5, 1 },
+};
+
+static const char *trigger_sources[] = {
+	"CH1",
+	"CH2",
+	"EXT",
+	/* TODO: forced */
+};
+
+static const char *filter_targets[] = {
+	"CH1",
+	"CH2",
+	/* TODO: "TRIGGER", */
+};
+
+static const char *coupling[] = {
+	"AC",
+	"DC",
+	"GND",
+};
+
+SR_PRIV struct sr_dev_driver hantek_dso_driver_info;
+static struct sr_dev_driver *di = &hantek_dso_driver_info;
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data);
+
+static struct sr_dev_inst *dso_dev_new(int index, const struct dso_profile *prof)
+{
+	struct sr_dev_inst *sdi;
+	struct sr_channel *ch;
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	int i;
+
+	sdi = sr_dev_inst_new(index, SR_ST_INITIALIZING,
+		prof->vendor, prof->model, NULL);
+	if (!sdi)
+		return NULL;
+	sdi->driver = di;
+
+	/*
+	 * Add only the real channels -- EXT isn't a source of data, only
+	 * a trigger source internal to the device.
+	 */
+	for (i = 0; channel_names[i]; i++) {
+		if (!(ch = sr_channel_new(i, SR_CHANNEL_ANALOG, TRUE,
+				channel_names[i])))
+			return NULL;
+		sdi->channels = g_slist_append(sdi->channels, ch);
+	}
+
+	if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+		sr_err("Device context malloc failed.");
+		return NULL;
+	}
+
+	devc->profile = prof;
+	devc->dev_state = IDLE;
+	devc->timebase = DEFAULT_TIMEBASE;
+	devc->ch1_enabled = TRUE;
+	devc->ch2_enabled = TRUE;
+	devc->voltage_ch1 = DEFAULT_VOLTAGE;
+	devc->voltage_ch2 = DEFAULT_VOLTAGE;
+	devc->coupling_ch1 = DEFAULT_COUPLING;
+	devc->coupling_ch2 = DEFAULT_COUPLING;
+	devc->voffset_ch1 = DEFAULT_VERT_OFFSET;
+	devc->voffset_ch2 = DEFAULT_VERT_OFFSET;
+	devc->voffset_trigger = DEFAULT_VERT_TRIGGERPOS;
+	devc->framesize = DEFAULT_FRAMESIZE;
+	devc->triggerslope = SLOPE_POSITIVE;
+	devc->triggersource = g_strdup(DEFAULT_TRIGGER_SOURCE);
+	devc->triggerposition = DEFAULT_HORIZ_TRIGGERPOS;
+	sdi->priv = devc;
+	drvc = di->priv;
+	drvc->instances = g_slist_append(drvc->instances, sdi);
+
+	return sdi;
+}
+
+static int configure_channels(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_channel *ch;
+	const GSList *l;
+	int p;
+
+	devc = sdi->priv;
+
+	g_slist_free(devc->enabled_channels);
+	devc->ch1_enabled = devc->ch2_enabled = FALSE;
+	for (l = sdi->channels, p = 0; l; l = l->next, p++) {
+		ch = l->data;
+		if (p == 0)
+			devc->ch1_enabled = ch->enabled;
+		else
+			devc->ch2_enabled = ch->enabled;
+		if (ch->enabled)
+			devc->enabled_channels = g_slist_append(devc->enabled_channels, ch);
+	}
+
+	return SR_OK;
+}
+
+static void clear_dev_context(void *priv)
+{
+	struct dev_context *devc;
+
+	devc = priv;
+	g_free(devc->triggersource);
+	g_slist_free(devc->enabled_channels);
+
+}
+
+static int dev_clear(void)
+{
+	return std_dev_clear(di, clear_dev_context);
+}
+
+static int init(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_dev_inst *sdi;
+	struct sr_usb_dev_inst *usb;
+	struct sr_config *src;
+	const struct dso_profile *prof;
+	GSList *l, *devices, *conn_devices;
+	struct libusb_device_descriptor des;
+	libusb_device **devlist;
+	int devcnt, ret, i, j;
+	const char *conn;
+
+	drvc = di->priv;
+
+	devcnt = 0;
+	devices = 0;
+
+	conn = NULL;
+	for (l = options; l; l = l->next) {
+		src = l->data;
+		if (src->key == SR_CONF_CONN) {
+			conn = g_variant_get_string(src->data, NULL);
+			break;
+		}
+	}
+	if (conn)
+		conn_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn);
+	else
+		conn_devices = NULL;
+
+	/* Find all Hantek DSO devices and upload firmware to all of them. */
+	libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
+	for (i = 0; devlist[i]; i++) {
+		if (conn) {
+			usb = NULL;
+			for (l = conn_devices; l; l = l->next) {
+				usb = l->data;
+				if (usb->bus == libusb_get_bus_number(devlist[i])
+					&& usb->address == libusb_get_device_address(devlist[i]))
+					break;
+			}
+			if (!l)
+				/* This device matched none of the ones that
+				 * matched the conn specification. */
+				continue;
+		}
+
+		if ((ret = libusb_get_device_descriptor(devlist[i], &des))) {
+			sr_err("Failed to get device descriptor: %s.",
+					libusb_error_name(ret));
+			continue;
+		}
+
+		prof = NULL;
+		for (j = 0; dev_profiles[j].orig_vid; j++) {
+			if (des.idVendor == dev_profiles[j].orig_vid
+				&& des.idProduct == dev_profiles[j].orig_pid) {
+				/* Device matches the pre-firmware profile. */
+				prof = &dev_profiles[j];
+				sr_dbg("Found a %s %s.", prof->vendor, prof->model);
+				sdi = dso_dev_new(devcnt, prof);
+				devices = g_slist_append(devices, sdi);
+				devc = sdi->priv;
+				if (ezusb_upload_firmware(devlist[i], USB_CONFIGURATION,
+						prof->firmware) == SR_OK)
+					/* Remember when the firmware on this device was updated */
+					devc->fw_updated = g_get_monotonic_time();
+				else
+					sr_err("Firmware upload failed for "
+					        "device %d.", devcnt);
+				/* Dummy USB address of 0xff will get overwritten later. */
+				sdi->conn = sr_usb_dev_inst_new(
+						libusb_get_bus_number(devlist[i]), 0xff, NULL);
+				devcnt++;
+				break;
+			} else if (des.idVendor == dev_profiles[j].fw_vid
+				&& des.idProduct == dev_profiles[j].fw_pid) {
+				/* Device matches the post-firmware profile. */
+				prof = &dev_profiles[j];
+				sr_dbg("Found a %s %s.", prof->vendor, prof->model);
+				sdi = dso_dev_new(devcnt, prof);
+				sdi->status = SR_ST_INACTIVE;
+				devices = g_slist_append(devices, sdi);
+				devc = sdi->priv;
+				sdi->inst_type = SR_INST_USB;
+				sdi->conn = sr_usb_dev_inst_new(
+						libusb_get_bus_number(devlist[i]),
+						libusb_get_device_address(devlist[i]), NULL);
+				devcnt++;
+				break;
+			}
+		}
+		if (!prof)
+			/* not a supported VID/PID */
+			continue;
+	}
+	libusb_free_device_list(devlist, 1);
+
+	return devices;
+}
+
+static GSList *dev_list(void)
+{
+	return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_usb_dev_inst *usb;
+	int64_t timediff_us, timediff_ms;
+	int err;
+
+	devc = sdi->priv;
+	usb = sdi->conn;
+
+	/*
+	 * If the firmware was recently uploaded, wait up to MAX_RENUM_DELAY_MS
+	 * for the FX2 to renumerate.
+	 */
+	err = SR_ERR;
+	if (devc->fw_updated > 0) {
+		sr_info("Waiting for device to reset.");
+		/* Takes >= 300ms for the FX2 to be gone from the USB bus. */
+		g_usleep(300 * 1000);
+		timediff_ms = 0;
+		while (timediff_ms < MAX_RENUM_DELAY_MS) {
+			if ((err = dso_open(sdi)) == SR_OK)
+				break;
+			g_usleep(100 * 1000);
+			timediff_us = g_get_monotonic_time() - devc->fw_updated;
+			timediff_ms = timediff_us / 1000;
+			sr_spew("Waited %" PRIi64 " ms.", timediff_ms);
+		}
+		sr_info("Device came back after %d ms.", timediff_ms);
+	} else {
+		err = dso_open(sdi);
+	}
+
+	if (err != SR_OK) {
+		sr_err("Unable to open device.");
+		return SR_ERR;
+	}
+
+	err = libusb_claim_interface(usb->devhdl, USB_INTERFACE);
+	if (err != 0) {
+		sr_err("Unable to claim interface: %s.",
+			   libusb_error_name(err));
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+	dso_close(sdi);
+
+	return SR_OK;
+}
+
+static int cleanup(void)
+{
+	return dev_clear();
+}
+
+static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct sr_usb_dev_inst *usb;
+	char str[128];
+
+	(void)cg;
+
+	switch (id) {
+	case SR_CONF_CONN:
+		if (!sdi || !sdi->conn)
+			return SR_ERR_ARG;
+		usb = sdi->conn;
+		if (usb->address == 255)
+			/* Device still needs to re-enumerate after firmware
+			 * upload, so we don't know its (future) address. */
+			return SR_ERR;
+		snprintf(str, 128, "%d.%d", usb->bus, usb->address);
+		*data = g_variant_new_string(str);
+		break;
+	case SR_CONF_NUM_TIMEBASE:
+		*data = g_variant_new_int32(NUM_TIMEBASE);
+		break;
+	case SR_CONF_NUM_VDIV:
+		*data = g_variant_new_int32(NUM_VDIV);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	double tmp_double;
+	uint64_t tmp_u64, p, q;
+	int tmp_int, ret;
+	unsigned int i;
+	const char *tmp_str;
+	char **targets;
+
+	(void)cg;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	ret = SR_OK;
+	devc = sdi->priv;
+	switch (id) {
+	case SR_CONF_LIMIT_FRAMES:
+		devc->limit_frames = g_variant_get_uint64(data);
+		break;
+	case SR_CONF_TRIGGER_SLOPE:
+		tmp_str = g_variant_get_string(data, NULL);
+		if (!tmp_str || !(tmp_str[0] == 'f' || tmp_str[0] == 'r'))
+			return SR_ERR_ARG;
+		devc->triggerslope = (tmp_str[0] == 'r')
+			? SLOPE_POSITIVE : SLOPE_NEGATIVE;
+		break;
+	case SR_CONF_HORIZ_TRIGGERPOS:
+		tmp_double = g_variant_get_double(data);
+		if (tmp_double < 0.0 || tmp_double > 1.0) {
+			sr_err("Trigger position should be between 0.0 and 1.0.");
+			ret = SR_ERR_ARG;
+		} else
+			devc->triggerposition = tmp_double;
+		break;
+	case SR_CONF_BUFFERSIZE:
+		tmp_u64 = g_variant_get_uint64(data);
+		for (i = 0; i < 2; i++) {
+			if (devc->profile->buffersizes[i] == tmp_u64) {
+				devc->framesize = tmp_u64;
+				break;
+			}
+		}
+		if (i == 2)
+			ret = SR_ERR_ARG;
+		break;
+	case SR_CONF_TIMEBASE:
+		g_variant_get(data, "(tt)", &p, &q);
+		tmp_int = -1;
+		for (i = 0; i < ARRAY_SIZE(timebases); i++) {
+			if (timebases[i][0] == p && timebases[i][1] == q) {
+				tmp_int = i;
+				break;
+			}
+		}
+		if (tmp_int >= 0)
+			devc->timebase = tmp_int;
+		else
+			ret = SR_ERR_ARG;
+		break;
+	case SR_CONF_TRIGGER_SOURCE:
+		tmp_str = g_variant_get_string(data, NULL);
+		for (i = 0; trigger_sources[i]; i++) {
+			if (!strcmp(tmp_str, trigger_sources[i])) {
+				devc->triggersource = g_strdup(tmp_str);
+				break;
+			}
+		}
+		if (trigger_sources[i] == 0)
+			ret = SR_ERR_ARG;
+		break;
+	case SR_CONF_FILTER:
+		tmp_str = g_variant_get_string(data, NULL);
+		devc->filter_ch1 = devc->filter_ch2 = devc->filter_trigger = 0;
+		targets = g_strsplit(tmp_str, ",", 0);
+		for (i = 0; targets[i]; i++) {
+			if (targets[i] == '\0')
+				/* Empty filter string can be used to clear them all. */
+				;
+			else if (!strcmp(targets[i], "CH1"))
+				devc->filter_ch1 = TRUE;
+			else if (!strcmp(targets[i], "CH2"))
+				devc->filter_ch2 = TRUE;
+			else if (!strcmp(targets[i], "TRIGGER"))
+				devc->filter_trigger = TRUE;
+			else {
+				sr_err("Invalid filter target %s.", targets[i]);
+				ret = SR_ERR_ARG;
+			}
+		}
+		g_strfreev(targets);
+		break;
+	case SR_CONF_VDIV:
+		/* TODO: Not supporting vdiv per channel yet. */
+		g_variant_get(data, "(tt)", &p, &q);
+		tmp_int = -1;
+		for (i = 0; i < ARRAY_SIZE(vdivs); i++) {
+			if (vdivs[i][0] == p && vdivs[i][1] == q) {
+				tmp_int = i;
+				break;
+			}
+		}
+		if (tmp_int >= 0) {
+			devc->voltage_ch1 = tmp_int;
+			devc->voltage_ch2 = tmp_int;
+		} else
+			ret = SR_ERR_ARG;
+		break;
+	case SR_CONF_COUPLING:
+		tmp_str = g_variant_get_string(data, NULL);
+		/* TODO: Not supporting coupling per channel yet. */
+		for (i = 0; coupling[i]; i++) {
+			if (!strcmp(tmp_str, coupling[i])) {
+				devc->coupling_ch1 = i;
+				devc->coupling_ch2 = i;
+				break;
+			}
+		}
+		if (coupling[i] == 0)
+			ret = SR_ERR_ARG;
+		break;
+	default:
+		ret = SR_ERR_NA;
+		break;
+	}
+
+	return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	GVariant *tuple, *rational[2];
+	GVariantBuilder gvb;
+	unsigned int i;
+
+	(void)cg;
+
+	switch (key) {
+	case SR_CONF_SCAN_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				scanopts, ARRAY_SIZE(scanopts), sizeof(int32_t));
+		break;
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				devopts, ARRAY_SIZE(devopts), sizeof(int32_t));
+		break;
+	case SR_CONF_BUFFERSIZE:
+		if (!sdi)
+			return SR_ERR_ARG;
+		devc = sdi->priv;
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT64,
+				devc->profile->buffersizes, 2, sizeof(uint64_t));
+		break;
+	case SR_CONF_COUPLING:
+		*data = g_variant_new_strv(coupling, ARRAY_SIZE(coupling));
+		break;
+	case SR_CONF_VDIV:
+		g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
+		for (i = 0; i < ARRAY_SIZE(vdivs); i++) {
+			rational[0] = g_variant_new_uint64(vdivs[i][0]);
+			rational[1] = g_variant_new_uint64(vdivs[i][1]);
+			tuple = g_variant_new_tuple(rational, 2);
+			g_variant_builder_add_value(&gvb, tuple);
+		}
+		*data = g_variant_builder_end(&gvb);
+		break;
+	case SR_CONF_FILTER:
+		*data = g_variant_new_strv(filter_targets,
+				ARRAY_SIZE(filter_targets));
+		break;
+	case SR_CONF_TIMEBASE:
+		g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
+		for (i = 0; i < ARRAY_SIZE(timebases); i++) {
+			rational[0] = g_variant_new_uint64(timebases[i][0]);
+			rational[1] = g_variant_new_uint64(timebases[i][1]);
+			tuple = g_variant_new_tuple(rational, 2);
+			g_variant_builder_add_value(&gvb, tuple);
+		}
+		*data = g_variant_builder_end(&gvb);
+		break;
+	case SR_CONF_TRIGGER_SOURCE:
+		*data = g_variant_new_strv(trigger_sources,
+				ARRAY_SIZE(trigger_sources));
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static void send_chunk(struct sr_dev_inst *sdi, unsigned char *buf,
+		int num_samples)
+{
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_analog analog;
+	struct dev_context *devc;
+	float ch1, ch2, range;
+	int num_channels, data_offset, i;
+
+	devc = sdi->priv;
+	num_channels = (devc->ch1_enabled && devc->ch2_enabled) ? 2 : 1;
+	packet.type = SR_DF_ANALOG;
+	packet.payload = &analog;
+	/* TODO: support for 5xxx series 9-bit samples */
+	analog.channels = devc->enabled_channels;
+	analog.num_samples = num_samples;
+	analog.mq = SR_MQ_VOLTAGE;
+	analog.unit = SR_UNIT_VOLT;
+	/* TODO: Check malloc return value. */
+	analog.data = g_try_malloc(analog.num_samples * sizeof(float) * num_channels);
+	data_offset = 0;
+	for (i = 0; i < analog.num_samples; i++) {
+		/*
+		 * The device always sends data for both channels. If a channel
+		 * is disabled, it contains a copy of the enabled channel's
+		 * data. However, we only send the requested channels to
+		 * the bus.
+		 *
+		 * Voltage values are encoded as a value 0-255 (0-512 on the
+		 * DSO-5200*), where the value is a point in the range
+		 * represented by the vdiv setting. There are 8 vertical divs,
+		 * so e.g. 500mV/div represents 4V peak-to-peak where 0 = -2V
+		 * and 255 = +2V.
+		 */
+		/* TODO: Support for DSO-5xxx series 9-bit samples. */
+		if (devc->ch1_enabled) {
+			range = ((float)vdivs[devc->voltage_ch1][0] / vdivs[devc->voltage_ch1][1]) * 8;
+			ch1 = range / 255 * *(buf + i * 2 + 1);
+			/* Value is centered around 0V. */
+			ch1 -= range / 2;
+			analog.data[data_offset++] = ch1;
+		}
+		if (devc->ch2_enabled) {
+			range = ((float)vdivs[devc->voltage_ch2][0] / vdivs[devc->voltage_ch2][1]) * 8;
+			ch2 = range / 255 * *(buf + i * 2);
+			ch2 -= range / 2;
+			analog.data[data_offset++] = ch2;
+		}
+	}
+	sr_session_send(devc->cb_data, &packet);
+}
+
+/*
+ * Called by libusb (as triggered by handle_event()) when a transfer comes in.
+ * Only channel data comes in asynchronously, and all transfers for this are
+ * queued up beforehand, so this just needs to chuck the incoming data onto
+ * the libsigrok session bus.
+ */
+static void receive_transfer(struct libusb_transfer *transfer)
+{
+	struct sr_datafeed_packet packet;
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+	int num_samples, pre;
+
+	sdi = transfer->user_data;
+	devc = sdi->priv;
+	sr_spew("receive_transfer(): status %d received %d bytes.",
+		   transfer->status, transfer->actual_length);
+
+	if (transfer->actual_length == 0)
+		/* Nothing to send to the bus. */
+		return;
+
+	num_samples = transfer->actual_length / 2;
+
+	sr_spew("Got %d-%d/%d samples in frame.", devc->samp_received + 1,
+		   devc->samp_received + num_samples, devc->framesize);
+
+	/*
+	 * The device always sends a full frame, but the beginning of the frame
+	 * doesn't represent the trigger point. The offset at which the trigger
+	 * happened came in with the capture state, so we need to start sending
+	 * from there up the session bus. The samples in the frame buffer
+	 * before that trigger point came after the end of the device's frame
+	 * buffer was reached, and it wrapped around to overwrite up until the
+	 * trigger point.
+	 */
+	if (devc->samp_received < devc->trigger_offset) {
+		/* Trigger point not yet reached. */
+		if (devc->samp_received + num_samples < devc->trigger_offset) {
+			/* The entire chunk is before the trigger point. */
+			memcpy(devc->framebuf + devc->samp_buffered * 2,
+					transfer->buffer, num_samples * 2);
+			devc->samp_buffered += num_samples;
+		} else {
+			/*
+			 * This chunk hits or overruns the trigger point.
+			 * Store the part before the trigger fired, and
+			 * send the rest up to the session bus.
+			 */
+			pre = devc->trigger_offset - devc->samp_received;
+			memcpy(devc->framebuf + devc->samp_buffered * 2,
+					transfer->buffer, pre * 2);
+			devc->samp_buffered += pre;
+
+			/* The rest of this chunk starts with the trigger point. */
+			sr_dbg("Reached trigger point, %d samples buffered.",
+				   devc->samp_buffered);
+
+			/* Avoid the corner case where the chunk ended at
+			 * exactly the trigger point. */
+			if (num_samples > pre)
+				send_chunk(sdi, transfer->buffer + pre * 2,
+						num_samples - pre);
+		}
+	} else {
+		/* Already past the trigger point, just send it all out. */
+		send_chunk(sdi, transfer->buffer,
+				num_samples);
+	}
+
+	devc->samp_received += num_samples;
+
+	/* Everything in this transfer was either copied to the buffer or
+	 * sent to the session bus. */
+	g_free(transfer->buffer);
+	libusb_free_transfer(transfer);
+
+	if (devc->samp_received >= devc->framesize) {
+		/* That was the last chunk in this frame. Send the buffered
+		 * pre-trigger samples out now, in one big chunk. */
+		sr_dbg("End of frame, sending %d pre-trigger buffered samples.",
+			   devc->samp_buffered);
+		send_chunk(sdi, devc->framebuf, devc->samp_buffered);
+
+		/* Mark the end of this frame. */
+		packet.type = SR_DF_FRAME_END;
+		sr_session_send(devc->cb_data, &packet);
+
+		if (devc->limit_frames && ++devc->num_frames == devc->limit_frames) {
+			/* Terminate session */
+			devc->dev_state = STOPPING;
+		} else {
+			devc->dev_state = NEW_CAPTURE;
+		}
+	}
+}
+
+static int handle_event(int fd, int revents, void *cb_data)
+{
+	const struct sr_dev_inst *sdi;
+	struct sr_datafeed_packet packet;
+	struct timeval tv;
+	struct dev_context *devc;
+	struct drv_context *drvc = di->priv;
+	int num_channels;
+	uint32_t trigger_offset;
+	uint8_t capturestate;
+
+	(void)fd;
+	(void)revents;
+
+	sdi = cb_data;
+	devc = sdi->priv;
+	if (devc->dev_state == STOPPING) {
+		/* We've been told to wind up the acquisition. */
+		sr_dbg("Stopping acquisition.");
+		/*
+		 * TODO: Doesn't really cancel pending transfers so they might
+		 * come in after SR_DF_END is sent.
+		 */
+		usb_source_remove(drvc->sr_ctx);
+
+		packet.type = SR_DF_END;
+		sr_session_send(sdi, &packet);
+
+		devc->dev_state = IDLE;
+
+		return TRUE;
+	}
+
+	/* Always handle pending libusb events. */
+	tv.tv_sec = tv.tv_usec = 0;
+	libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
+
+	/* TODO: ugh */
+	if (devc->dev_state == NEW_CAPTURE) {
+		if (dso_capture_start(sdi) != SR_OK)
+			return TRUE;
+		if (dso_enable_trigger(sdi) != SR_OK)
+			return TRUE;
+//		if (dso_force_trigger(sdi) != SR_OK)
+//			return TRUE;
+		sr_dbg("Successfully requested next chunk.");
+		devc->dev_state = CAPTURE;
+		return TRUE;
+	}
+	if (devc->dev_state != CAPTURE)
+		return TRUE;
+
+	if ((dso_get_capturestate(sdi, &capturestate, &trigger_offset)) != SR_OK)
+		return TRUE;
+
+	sr_dbg("Capturestate %d.", capturestate);
+	sr_dbg("Trigger offset 0x%.6x.", trigger_offset);
+	switch (capturestate) {
+	case CAPTURE_EMPTY:
+		if (++devc->capture_empty_count >= MAX_CAPTURE_EMPTY) {
+			devc->capture_empty_count = 0;
+			if (dso_capture_start(sdi) != SR_OK)
+				break;
+			if (dso_enable_trigger(sdi) != SR_OK)
+				break;
+//			if (dso_force_trigger(sdi) != SR_OK)
+//				break;
+			sr_dbg("Successfully requested next chunk.");
+		}
+		break;
+	case CAPTURE_FILLING:
+		/* No data yet. */
+		break;
+	case CAPTURE_READY_8BIT:
+		/* Remember where in the captured frame the trigger is. */
+		devc->trigger_offset = trigger_offset;
+
+		num_channels = (devc->ch1_enabled && devc->ch2_enabled) ? 2 : 1;
+		/* TODO: Check malloc return value. */
+		devc->framebuf = g_try_malloc(devc->framesize * num_channels * 2);
+		devc->samp_buffered = devc->samp_received = 0;
+
+		/* Tell the scope to send us the first frame. */
+		if (dso_get_channeldata(sdi, receive_transfer) != SR_OK)
+			break;
+
+		/*
+		 * Don't hit the state machine again until we're done fetching
+		 * the data we just told the scope to send.
+		 */
+		devc->dev_state = FETCH_DATA;
+
+		/* Tell the frontend a new frame is on the way. */
+		packet.type = SR_DF_FRAME_BEGIN;
+		sr_session_send(sdi, &packet);
+		break;
+	case CAPTURE_READY_9BIT:
+		/* TODO */
+		sr_err("Not yet supported.");
+		break;
+	case CAPTURE_TIMEOUT:
+		/* Doesn't matter, we'll try again next time. */
+		break;
+	default:
+		sr_dbg("Unknown capture state: %d.", capturestate);
+		break;
+	}
+
+	return TRUE;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct dev_context *devc;
+	struct drv_context *drvc = di->priv;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	devc = sdi->priv;
+	devc->cb_data = cb_data;
+
+	if (configure_channels(sdi) != SR_OK) {
+		sr_err("Failed to configure channels.");
+		return SR_ERR;
+	}
+
+	if (dso_init(sdi) != SR_OK)
+		return SR_ERR;
+
+	if (dso_capture_start(sdi) != SR_OK)
+		return SR_ERR;
+
+	devc->dev_state = CAPTURE;
+	usb_source_add(drvc->sr_ctx, TICK, handle_event, (void *)sdi);
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct dev_context *devc;
+
+	(void)cb_data;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR;
+
+	devc = sdi->priv;
+	devc->dev_state = STOPPING;
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver hantek_dso_driver_info = {
+	.name = "hantek-dso",
+	.longname = "Hantek DSO",
+	.api_version = 1,
+	.init = init,
+	.cleanup = cleanup,
+	.scan = scan,
+	.dev_list = dev_list,
+	.dev_clear = dev_clear,
+	.config_get = config_get,
+	.config_set = config_set,
+	.config_list = config_list,
+	.dev_open = dev_open,
+	.dev_close = dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/hantek-dso/dso.c b/hardware/hantek-dso/dso.c
new file mode 100644
index 0000000..da5eb12
--- /dev/null
+++ b/hardware/hantek-dso/dso.c
@@ -0,0 +1,787 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert at biot.com>
+ * With protocol information from the hantekdso project,
+ * Copyright (C) 2008 Oleg Khudyakov <prcoder at gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "dso.h"
+#include <string.h>
+#include <glib.h>
+#include <libusb.h>
+
+extern struct sr_dev_driver hantek_dso_driver_info;
+
+static int send_begin(const struct sr_dev_inst *sdi)
+{
+	struct sr_usb_dev_inst *usb;
+	int ret;
+	unsigned char buffer[] = {0x0f, 0x03, 0x03, 0x03, 0x68, 0xac, 0xfe,
+	0x00, 0x01, 0x00};
+
+	sr_dbg("Sending CTRL_BEGINCOMMAND.");
+
+	usb = sdi->conn;
+	if ((ret = libusb_control_transfer(usb->devhdl,
+			LIBUSB_REQUEST_TYPE_VENDOR, CTRL_BEGINCOMMAND,
+			0, 0, buffer, sizeof(buffer), 200)) != sizeof(buffer)) {
+		sr_err("Failed to send begincommand: %s.",
+		       libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+static int send_bulkcmd(const struct sr_dev_inst *sdi, uint8_t *cmdstring, int cmdlen)
+{
+	struct sr_usb_dev_inst *usb;
+	int ret, tmp;
+
+	usb = sdi->conn;
+
+	if (send_begin(sdi) != SR_OK)
+		return SR_ERR;
+
+	if ((ret = libusb_bulk_transfer(usb->devhdl, DSO_EP_OUT, cmdstring,
+			cmdlen, &tmp, 200)) != 0)
+		return SR_ERR;
+
+	return SR_OK;
+}
+
+static int dso_getmps(libusb_device *dev)
+{
+	struct libusb_device_descriptor des;
+	struct libusb_config_descriptor *conf_dsc;
+	const struct libusb_interface_descriptor *intf_dsc;
+	int mps;
+
+	if (libusb_get_device_descriptor(dev, &des) != 0)
+		return 0;
+
+	if (des.bNumConfigurations != 1)
+		return 0;
+
+	if (libusb_get_config_descriptor(dev, 0, &conf_dsc) != 0)
+		return 0;
+
+	mps = 0;
+	intf_dsc = &(conf_dsc->interface[0].altsetting[0]);
+	if (intf_dsc->bNumEndpoints != 2)
+		goto err;
+
+	if ((intf_dsc->endpoint[0].bEndpointAddress & 0x8f) !=
+	    (2 | LIBUSB_ENDPOINT_OUT))
+		/* The first endpoint should be 2 (outbound). */
+		goto err;
+
+	if ((intf_dsc->endpoint[1].bEndpointAddress & 0x8f) !=
+	    (6 | LIBUSB_ENDPOINT_IN))
+		/* The second endpoint should be 6 (inbound). */
+		goto err;
+
+	mps = intf_dsc->endpoint[1].wMaxPacketSize;
+
+err:
+	if (conf_dsc)
+		libusb_free_config_descriptor(conf_dsc);
+
+	return mps;
+}
+
+SR_PRIV int dso_open(struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct drv_context *drvc = hantek_dso_driver_info.priv;
+	struct sr_usb_dev_inst *usb;
+	struct libusb_device_descriptor des;
+	libusb_device **devlist;
+	int err, skip, i;
+
+	devc = sdi->priv;
+	usb = sdi->conn;
+
+	if (sdi->status == SR_ST_ACTIVE)
+		/* already in use */
+		return SR_ERR;
+
+	skip = 0;
+	libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
+	for (i = 0; devlist[i]; i++) {
+		if ((err = libusb_get_device_descriptor(devlist[i], &des))) {
+			sr_err("Failed to get device descriptor: %s.",
+			       libusb_error_name(err));
+			continue;
+		}
+
+		if (des.idVendor != devc->profile->fw_vid
+		    || des.idProduct != devc->profile->fw_pid)
+			continue;
+
+		if (sdi->status == SR_ST_INITIALIZING) {
+			if (skip != sdi->index) {
+				/* Skip devices of this type that aren't the one we want. */
+				skip += 1;
+				continue;
+			}
+		} else if (sdi->status == SR_ST_INACTIVE) {
+			/*
+			 * This device is fully enumerated, so we need to find
+			 * this device by vendor, product, bus and address.
+			 */
+			if (libusb_get_bus_number(devlist[i]) != usb->bus
+				|| libusb_get_device_address(devlist[i]) != usb->address)
+				/* this is not the one */
+				continue;
+		}
+
+		if (!(err = libusb_open(devlist[i], &usb->devhdl))) {
+			if (usb->address == 0xff)
+				/*
+				 * first time we touch this device after firmware upload,
+				 * so we don't know the address yet.
+				 */
+				usb->address = libusb_get_device_address(devlist[i]);
+
+			if (!(devc->epin_maxpacketsize = dso_getmps(devlist[i])))
+				sr_err("Wrong endpoint profile.");
+			else {
+				sdi->status = SR_ST_ACTIVE;
+				sr_info("Opened device %d on %d.%d interface %d.",
+					sdi->index, usb->bus,
+					usb->address, USB_INTERFACE);
+			}
+		} else {
+			sr_err("Failed to open device: %s.",
+			       libusb_error_name(err));
+		}
+
+		/* If we made it here, we handled the device (somehow). */
+		break;
+	}
+	libusb_free_device_list(devlist, 1);
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR;
+
+	return SR_OK;
+}
+
+SR_PRIV void dso_close(struct sr_dev_inst *sdi)
+{
+	struct sr_usb_dev_inst *usb;
+
+	usb = sdi->conn;
+
+	if (usb->devhdl == NULL)
+		return;
+
+	sr_info("Closing device %d on %d.%d interface %d.", sdi->index,
+		usb->bus, usb->address, USB_INTERFACE);
+	libusb_release_interface(usb->devhdl, USB_INTERFACE);
+	libusb_close(usb->devhdl);
+	usb->devhdl = NULL;
+	sdi->status = SR_ST_INACTIVE;
+
+}
+
+static int get_channel_offsets(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_usb_dev_inst *usb;
+	GString *gs;
+	int chan, v, ret;
+
+	sr_dbg("Getting channel offsets.");
+
+	devc = sdi->priv;
+	usb = sdi->conn;
+
+	ret = libusb_control_transfer(usb->devhdl,
+			LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR,
+			CTRL_READ_EEPROM, EEPROM_CHANNEL_OFFSETS, 0,
+			(unsigned char *)&devc->channel_levels,
+			sizeof(devc->channel_levels), 200);
+	if (ret != sizeof(devc->channel_levels)) {
+		sr_err("Failed to get channel offsets: %s.",
+		       libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	/* Comes in as 16-bit numbers with the second byte always 0 on
+	 * the DSO-2090. Guessing this is supposed to be big-endian,
+	 * since that's how voltage offsets are submitted back to the DSO.
+	 * Convert to host order now, so we can use them natively.
+	 */
+	for (chan = 0; chan < 2; chan++) {
+		for (v = 0; v < 9; v++) {
+			devc->channel_levels[chan][v][0] =
+				g_ntohs(devc->channel_levels[chan][v][0]);
+			devc->channel_levels[chan][v][1] =
+				g_ntohs(devc->channel_levels[chan][v][1]);
+		}
+	}
+
+	if (sr_log_loglevel_get() >= SR_LOG_DBG) {
+		gs = g_string_sized_new(128);
+		for (chan = 0; chan < 2; chan++) {
+			g_string_printf(gs, "CH%d:", chan + 1);
+			for (v = 0; v < 9; v++) {
+				g_string_append_printf(gs, " %.4x-%.4x",
+					devc->channel_levels[chan][v][0],
+					devc->channel_levels[chan][v][1]);
+			}
+			sr_dbg("%s", gs->str);
+		}
+		g_string_free(gs, TRUE);
+	}
+
+	return SR_OK;
+}
+
+static int dso_set_trigger_samplerate(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_usb_dev_inst *usb;
+	int ret, tmp;
+	uint8_t cmdstring[12];
+	uint16_t timebase_small[] = { 0xffff, 0xfffc, 0xfff7, 0xffe8, 0xffce,
+		0xff9c, 0xff07, 0xfe0d, 0xfc19, 0xf63d, 0xec79, 0xd8f1 };
+	uint16_t timebase_large[] = { 0xffff, 0x0000, 0xfffc, 0xfff7, 0xffe8,
+		0xffce, 0xff9d, 0xff07, 0xfe0d, 0xfc19, 0xf63d, 0xec79 };
+
+	sr_dbg("Preparing CMD_SET_TRIGGER_SAMPLERATE.");
+
+	devc = sdi->priv;
+	usb = sdi->conn;
+
+	memset(cmdstring, 0, sizeof(cmdstring));
+	/* Command */
+	cmdstring[0] = CMD_SET_TRIGGER_SAMPLERATE;
+
+	/* Trigger source */
+	sr_dbg("Trigger source %s.", devc->triggersource);
+	if (!strcmp("CH2", devc->triggersource))
+		tmp = 0;
+	else if (!strcmp("CH1", devc->triggersource))
+		tmp = 1;
+	else if (!strcmp("EXT", devc->triggersource))
+		tmp = 2;
+	else {
+		sr_err("Invalid trigger source: '%s'.", devc->triggersource);
+		return SR_ERR_ARG;
+	}
+	cmdstring[2] = tmp;
+
+	/* Frame size */
+	sr_dbg("Frame size: %d.", devc->framesize);
+	cmdstring[2] |= (devc->framesize == FRAMESIZE_SMALL ? 0x01 : 0x02) << 2;
+
+	/* Timebase fast */
+	sr_dbg("Time base index: %d.", devc->timebase);
+	if (devc->framesize == FRAMESIZE_SMALL) {
+		if (devc->timebase < TIME_20us)
+			tmp = 0;
+		else if (devc->timebase == TIME_20us)
+			tmp = 1;
+		else if (devc->timebase == TIME_40us)
+			tmp = 2;
+		else if (devc->timebase == TIME_100us)
+			tmp = 3;
+		else if (devc->timebase >= TIME_200us)
+			tmp = 4;
+	} else {
+		if (devc->timebase < TIME_40us) {
+			sr_err("Timebase < 40us only supported with 10K buffer.");
+			return SR_ERR_ARG;
+		}
+		else if (devc->timebase == TIME_40us)
+			tmp = 0;
+		else if (devc->timebase == TIME_100us)
+			tmp = 2;
+		else if (devc->timebase == TIME_200us)
+			tmp = 3;
+		else if (devc->timebase >= TIME_400us)
+			tmp = 4;
+	}
+	cmdstring[2] |= (tmp & 0x07) << 5;
+
+	/* Enabled channels: 00=CH1 01=CH2 10=both */
+	sr_dbg("Channels CH1=%d CH2=%d", devc->ch1_enabled, devc->ch2_enabled);
+	tmp = (((devc->ch2_enabled ? 1 : 0) << 1) + (devc->ch1_enabled ? 1 : 0)) - 1;
+	cmdstring[3] = tmp;
+
+	/* Fast rates channel */
+	/* TODO: Is this right? */
+	tmp = devc->timebase < TIME_10us ? 1 : 0;
+	cmdstring[3] |= tmp << 2;
+
+	/* Trigger slope: 0=positive 1=negative */
+	/* TODO: Does this work? */
+	sr_dbg("Trigger slope: %d.", devc->triggerslope);
+	cmdstring[3] |= (devc->triggerslope == SLOPE_NEGATIVE ? 1 : 0) << 3;
+
+	/* Timebase slow */
+	if (devc->timebase < TIME_100us)
+		tmp = 0;
+	else if (devc->timebase > TIME_400ms)
+		tmp = 0xffed;
+	else {
+		if (devc->framesize == FRAMESIZE_SMALL)
+			tmp = timebase_small[devc->timebase - 3];
+		else
+			tmp = timebase_large[devc->timebase - 3];
+	}
+	cmdstring[4] = tmp & 0xff;
+	cmdstring[5] = (tmp >> 8) & 0xff;
+
+	/* Horizontal trigger position */
+	sr_dbg("Trigger position: %3.2f.", devc->triggerposition);
+	tmp = 0x77fff + 0x8000 * devc->triggerposition;
+	cmdstring[6] = tmp & 0xff;
+	cmdstring[7] = (tmp >> 8) & 0xff;
+	cmdstring[10] = (tmp >> 16) & 0xff;
+
+	if (send_begin(sdi) != SR_OK)
+		return SR_ERR;
+
+	if ((ret = libusb_bulk_transfer(usb->devhdl, DSO_EP_OUT,
+			cmdstring, sizeof(cmdstring), &tmp, 100)) != 0) {
+		sr_err("Failed to set trigger/samplerate: %s.",
+		       libusb_error_name(ret));
+		return SR_ERR;
+	}
+	sr_dbg("Sent CMD_SET_TRIGGER_SAMPLERATE.");
+
+	return SR_OK;
+}
+
+static int dso_set_filters(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_usb_dev_inst *usb;
+	int ret, tmp;
+	uint8_t cmdstring[8];
+
+	sr_dbg("Preparing CMD_SET_FILTERS.");
+
+	devc = sdi->priv;
+	usb = sdi->conn;
+
+	memset(cmdstring, 0, sizeof(cmdstring));
+	cmdstring[0] = CMD_SET_FILTERS;
+	cmdstring[1] = 0x0f;
+	if (devc->filter_ch1) {
+		sr_dbg("Turning on CH1 filter.");
+		cmdstring[2] |= 0x80;
+	}
+	if (devc->filter_ch2) {
+		sr_dbg("Turning on CH2 filter.");
+		cmdstring[2] |= 0x40;
+	}
+	if (devc->filter_trigger) {
+		/* TODO: supported on the DSO-2090? */
+		sr_dbg("Turning on trigger filter.");
+		cmdstring[2] |= 0x20;
+	}
+
+	if (send_begin(sdi) != SR_OK)
+		return SR_ERR;
+
+	if ((ret = libusb_bulk_transfer(usb->devhdl, DSO_EP_OUT,
+			cmdstring, sizeof(cmdstring), &tmp, 100)) != 0) {
+		sr_err("Failed to set filters: %s.", libusb_error_name(ret));
+		return SR_ERR;
+	}
+	sr_dbg("Sent CMD_SET_FILTERS.");
+
+	return SR_OK;
+}
+
+static int dso_set_voltage(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_usb_dev_inst *usb;
+	int ret, tmp;
+	uint8_t cmdstring[8];
+
+	sr_dbg("Preparing CMD_SET_VOLTAGE.");
+
+	devc = sdi->priv;
+	usb = sdi->conn;
+
+	memset(cmdstring, 0, sizeof(cmdstring));
+	cmdstring[0] = CMD_SET_VOLTAGE;
+	cmdstring[1] = 0x0f;
+	cmdstring[2] = 0x30;
+
+	/* CH1 volts/div is encoded in bits 0-1 */
+	sr_dbg("CH1 vdiv index: %d.", devc->voltage_ch1);
+	switch (devc->voltage_ch1) {
+	case VDIV_1V:
+	case VDIV_100MV:
+	case VDIV_10MV:
+		cmdstring[2] |= 0x00;
+		break;
+	case VDIV_2V:
+	case VDIV_200MV:
+	case VDIV_20MV:
+		cmdstring[2] |= 0x01;
+		break;
+	case VDIV_5V:
+	case VDIV_500MV:
+	case VDIV_50MV:
+		cmdstring[2] |= 0x02;
+		break;
+	}
+
+	/* CH2 volts/div is encoded in bits 2-3 */
+	sr_dbg("CH2 vdiv index: %d.", devc->voltage_ch2);
+	switch (devc->voltage_ch2) {
+	case VDIV_1V:
+	case VDIV_100MV:
+	case VDIV_10MV:
+		cmdstring[2] |= 0x00;
+		break;
+	case VDIV_2V:
+	case VDIV_200MV:
+	case VDIV_20MV:
+		cmdstring[2] |= 0x04;
+		break;
+	case VDIV_5V:
+	case VDIV_500MV:
+	case VDIV_50MV:
+		cmdstring[2] |= 0x08;
+		break;
+	}
+
+	if (send_begin(sdi) != SR_OK)
+		return SR_ERR;
+
+	if ((ret = libusb_bulk_transfer(usb->devhdl, DSO_EP_OUT,
+			cmdstring, sizeof(cmdstring), &tmp, 100)) != 0) {
+		sr_err("Failed to set voltage: %s.", libusb_error_name(ret));
+		return SR_ERR;
+	}
+	sr_dbg("Sent CMD_SET_VOLTAGE.");
+
+	return SR_OK;
+}
+
+static int dso_set_relays(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_usb_dev_inst *usb;
+	GString *gs;
+	int ret, i;
+	uint8_t relays[17] = { 0x00, 0x04, 0x08, 0x02, 0x20, 0x40, 0x10, 0x01,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+	sr_dbg("Preparing CTRL_SETRELAYS.");
+
+	devc = sdi->priv;
+	usb = sdi->conn;
+
+	if (devc->voltage_ch1 < VDIV_1V)
+		relays[1] = ~relays[1];
+
+	if (devc->voltage_ch1 < VDIV_100MV)
+		relays[2] = ~relays[2];
+
+	sr_dbg("CH1 coupling: %d.", devc->coupling_ch1);
+	if (devc->coupling_ch1 != COUPLING_AC)
+		relays[3] = ~relays[3];
+
+	if (devc->voltage_ch2 < VDIV_1V)
+		relays[4] = ~relays[4];
+
+	if (devc->voltage_ch2 < VDIV_100MV)
+		relays[5] = ~relays[5];
+
+	sr_dbg("CH2 coupling: %d.", devc->coupling_ch1);
+	if (devc->coupling_ch2 != COUPLING_AC)
+		relays[6] = ~relays[6];
+
+	if (!strcmp(devc->triggersource, "EXT"))
+		relays[7] = ~relays[7];
+
+	if (sr_log_loglevel_get() >= SR_LOG_DBG) {
+		gs = g_string_sized_new(128);
+		g_string_printf(gs, "Relays:");
+		for (i = 0; i < 17; i++)
+			g_string_append_printf(gs, " %.2x", relays[i]);
+		sr_dbg("%s", gs->str);
+		g_string_free(gs, TRUE);
+	}
+
+	if ((ret = libusb_control_transfer(usb->devhdl,
+			LIBUSB_REQUEST_TYPE_VENDOR, CTRL_SETRELAYS,
+			0, 0, relays, 17, 100)) != sizeof(relays)) {
+		sr_err("Failed to set relays: %s.", libusb_error_name(ret));
+		return SR_ERR;
+	}
+	sr_dbg("Sent CTRL_SETRELAYS.");
+
+	return SR_OK;
+}
+
+static int dso_set_voffsets(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_usb_dev_inst *usb;
+	int offset, ret;
+	uint16_t *ch_levels;
+	uint8_t offsets[17];
+
+	sr_dbg("Preparing CTRL_SETOFFSET.");
+
+	devc = sdi->priv;
+	usb = sdi->conn;
+
+	memset(offsets, 0, sizeof(offsets));
+	/* Channel 1 */
+	ch_levels = devc->channel_levels[0][devc->voltage_ch1];
+	offset = (ch_levels[1] - ch_levels[0]) * devc->voffset_ch1 + ch_levels[0];
+	offsets[0] = (offset >> 8) | 0x20;
+	offsets[1] = offset & 0xff;
+	sr_dbg("CH1 offset: %3.2f (%.2x%.2x).", devc->voffset_ch1,
+	       offsets[0], offsets[1]);
+
+	/* Channel 2 */
+	ch_levels = devc->channel_levels[1][devc->voltage_ch2];
+	offset = (ch_levels[1] - ch_levels[0]) * devc->voffset_ch2 + ch_levels[0];
+	offsets[2] = (offset >> 8) | 0x20;
+	offsets[3] = offset & 0xff;
+	sr_dbg("CH2 offset: %3.2f (%.2x%.2x).", devc->voffset_ch2,
+	       offsets[2], offsets[3]);
+
+	/* Trigger */
+	offset = MAX_VERT_TRIGGER * devc->voffset_trigger;
+	offsets[4] = (offset >> 8) | 0x20;
+	offsets[5] = offset & 0xff;
+	sr_dbg("Trigger offset: %3.2f (%.2x%.2x).", devc->voffset_trigger,
+			offsets[4], offsets[5]);
+
+	if ((ret = libusb_control_transfer(usb->devhdl,
+			LIBUSB_REQUEST_TYPE_VENDOR, CTRL_SETOFFSET,
+			0, 0, offsets, sizeof(offsets), 100)) != sizeof(offsets)) {
+		sr_err("Failed to set offsets: %s.", libusb_error_name(ret));
+		return SR_ERR;
+	}
+	sr_dbg("Sent CTRL_SETOFFSET.");
+
+	return SR_OK;
+}
+
+SR_PRIV int dso_enable_trigger(const struct sr_dev_inst *sdi)
+{
+	struct sr_usb_dev_inst *usb;
+	int ret, tmp;
+	uint8_t cmdstring[2];
+
+	sr_dbg("Sending CMD_ENABLE_TRIGGER.");
+
+	usb = sdi->conn;
+
+	memset(cmdstring, 0, sizeof(cmdstring));
+	cmdstring[0] = CMD_ENABLE_TRIGGER;
+	cmdstring[1] = 0x00;
+
+	if (send_begin(sdi) != SR_OK)
+		return SR_ERR;
+
+	if ((ret = libusb_bulk_transfer(usb->devhdl, DSO_EP_OUT,
+			cmdstring, sizeof(cmdstring), &tmp, 100)) != 0) {
+		sr_err("Failed to enable trigger: %s.", libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+SR_PRIV int dso_force_trigger(const struct sr_dev_inst *sdi)
+{
+	struct sr_usb_dev_inst *usb;
+	int ret, tmp;
+	uint8_t cmdstring[2];
+
+	sr_dbg("Sending CMD_FORCE_TRIGGER.");
+
+	usb = sdi->conn;
+
+	memset(cmdstring, 0, sizeof(cmdstring));
+	cmdstring[0] = CMD_FORCE_TRIGGER;
+	cmdstring[1] = 0x00;
+
+	if (send_begin(sdi) != SR_OK)
+		return SR_ERR;
+
+	if ((ret = libusb_bulk_transfer(usb->devhdl, DSO_EP_OUT,
+			cmdstring, sizeof(cmdstring), &tmp, 100)) != 0) {
+		sr_err("Failed to force trigger: %s.", libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+SR_PRIV int dso_init(const struct sr_dev_inst *sdi)
+{
+
+	sr_dbg("Initializing DSO.");
+
+	if (get_channel_offsets(sdi) != SR_OK)
+		return SR_ERR;
+
+	if (dso_set_trigger_samplerate(sdi) != SR_OK)
+		return SR_ERR;
+
+	if (dso_set_filters(sdi) != SR_OK)
+		return SR_ERR;
+
+	if (dso_set_voltage(sdi) != SR_OK)
+		return SR_ERR;
+
+	if (dso_set_relays(sdi) != SR_OK)
+		return SR_ERR;
+
+	if (dso_set_voffsets(sdi) != SR_OK)
+		return SR_ERR;
+
+	if (dso_enable_trigger(sdi) != SR_OK)
+		return SR_ERR;
+
+	return SR_OK;
+}
+
+SR_PRIV int dso_get_capturestate(const struct sr_dev_inst *sdi,
+		uint8_t *capturestate, uint32_t *trigger_offset)
+{
+	struct sr_usb_dev_inst *usb;
+	int ret, tmp, i;
+	unsigned int bitvalue, toff;
+	uint8_t cmdstring[2], inbuf[512];
+
+	sr_dbg("Sending CMD_GET_CAPTURESTATE.");
+
+	usb = sdi->conn;
+
+	cmdstring[0] = CMD_GET_CAPTURESTATE;
+	cmdstring[1] = 0;
+
+	if ((ret = send_bulkcmd(sdi, cmdstring, sizeof(cmdstring))) != SR_OK) {
+		sr_dbg("Failed to send get_capturestate command: %s.",
+		       libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	if ((ret = libusb_bulk_transfer(usb->devhdl, DSO_EP_IN,
+			inbuf, 512, &tmp, 100)) != 0) {
+		sr_dbg("Failed to get capturestate: %s.",
+		       libusb_error_name(ret));
+		return SR_ERR;
+	}
+	*capturestate = inbuf[0];
+	toff = (inbuf[1] << 16) | (inbuf[3] << 8) | inbuf[2];
+
+	/*
+	 * This conversion comes from the openhantek project.
+	 * Each set bit in the 24-bit value inverts all bits with a lower
+	 * value. No idea why the device reports the trigger point this way.
+	 */
+	bitvalue = 1;
+	for (i = 0; i < 24; i++) {
+		/* Each set bit inverts all bits with a lower value. */
+		if(toff & bitvalue)
+			toff ^= bitvalue - 1;
+		bitvalue <<= 1;
+	}
+	*trigger_offset = toff;
+
+	return SR_OK;
+}
+
+SR_PRIV int dso_capture_start(const struct sr_dev_inst *sdi)
+{
+	int ret;
+	uint8_t cmdstring[2];
+
+	sr_dbg("Sending CMD_CAPTURE_START.");
+
+	cmdstring[0] = CMD_CAPTURE_START;
+	cmdstring[1] = 0;
+
+	if ((ret = send_bulkcmd(sdi, cmdstring, sizeof(cmdstring))) != SR_OK) {
+		sr_err("Failed to send capture_start command: %s.",
+		       libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+SR_PRIV int dso_get_channeldata(const struct sr_dev_inst *sdi,
+		libusb_transfer_cb_fn cb)
+{
+	struct dev_context *devc;
+	struct sr_usb_dev_inst *usb;
+	struct libusb_transfer *transfer;
+	int num_transfers, ret, i;
+	uint8_t cmdstring[2];
+	unsigned char *buf;
+
+	sr_dbg("Sending CMD_GET_CHANNELDATA.");
+
+	devc = sdi->priv;
+	usb = sdi->conn;
+
+	cmdstring[0] = CMD_GET_CHANNELDATA;
+	cmdstring[1] = 0;
+
+	if ((ret = send_bulkcmd(sdi, cmdstring, sizeof(cmdstring))) != SR_OK) {
+		sr_err("Failed to get channel data: %s.",
+		       libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	/* TODO: DSO-2xxx only. */
+	num_transfers = devc->framesize *
+			sizeof(unsigned short) / devc->epin_maxpacketsize;
+	sr_dbg("Queueing up %d transfers.", num_transfers);
+	for (i = 0; i < num_transfers; i++) {
+		if (!(buf = g_try_malloc(devc->epin_maxpacketsize))) {
+			sr_err("Failed to malloc USB endpoint buffer.");
+			return SR_ERR_MALLOC;
+		}
+		transfer = libusb_alloc_transfer(0);
+		libusb_fill_bulk_transfer(transfer, usb->devhdl, DSO_EP_IN, buf,
+				devc->epin_maxpacketsize, cb, (void *)sdi, 40);
+		if ((ret = libusb_submit_transfer(transfer)) != 0) {
+			sr_err("Failed to submit transfer: %s.",
+			       libusb_error_name(ret));
+			/* TODO: Free them all. */
+			libusb_free_transfer(transfer);
+			g_free(buf);
+			return SR_ERR;
+		}
+	}
+
+	return SR_OK;
+}
diff --git a/hardware/hantek-dso/dso.h b/hardware/hantek-dso/dso.h
new file mode 100644
index 0000000..edccb72
--- /dev/null
+++ b/hardware/hantek-dso/dso.h
@@ -0,0 +1,219 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert at biot.com>
+ * With protocol information from the hantekdso project,
+ * Copyright (C) 2008 Oleg Khudyakov <prcoder at gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_HANTEK_DSO_DSO_H
+#define LIBSIGROK_HARDWARE_HANTEK_DSO_DSO_H
+
+#define LOG_PREFIX "hantek-dso"
+
+#define USB_INTERFACE           0
+#define USB_CONFIGURATION       1
+#define DSO_EP_IN               0x86
+#define DSO_EP_OUT              0x02
+
+/* FX2 renumeration delay in ms */
+#define MAX_RENUM_DELAY_MS      3000
+
+#define MAX_CAPTURE_EMPTY       3
+
+#define DEFAULT_VOLTAGE         VDIV_500MV
+#define DEFAULT_FRAMESIZE       FRAMESIZE_SMALL
+#define DEFAULT_TIMEBASE        TIME_100us
+#define DEFAULT_TRIGGER_SOURCE  "CH1"
+#define DEFAULT_COUPLING        COUPLING_DC
+#define DEFAULT_HORIZ_TRIGGERPOS 0.5
+#define DEFAULT_VERT_OFFSET     0.5
+#define DEFAULT_VERT_TRIGGERPOS 0.5
+
+#define MAX_VERT_TRIGGER        0xfe
+
+/* Hantek DSO-specific protocol values */
+#define EEPROM_CHANNEL_OFFSETS  0x08
+
+/* All models have this for their "fast" mode. */
+#define FRAMESIZE_SMALL         10240
+
+enum control_requests {
+	CTRL_READ_EEPROM = 0xa2,
+	CTRL_GETSPEED = 0xb2,
+	CTRL_BEGINCOMMAND = 0xb3,
+	CTRL_SETOFFSET = 0xb4,
+	CTRL_SETRELAYS = 0xb5,
+};
+
+enum dso_commands {
+	CMD_SET_FILTERS = 0,
+	CMD_SET_TRIGGER_SAMPLERATE,
+	CMD_FORCE_TRIGGER,
+	CMD_CAPTURE_START,
+	CMD_ENABLE_TRIGGER,
+	CMD_GET_CHANNELDATA,
+	CMD_GET_CAPTURESTATE,
+	CMD_SET_VOLTAGE,
+	/* unused */
+	CMD_SET_LOGICALDATA,
+	CMD_GET_LOGICALDATA,
+};
+
+/* Must match the coupling table. */
+enum couplings {
+	COUPLING_AC = 0,
+	COUPLING_DC,
+	/* TODO not used, how to enable? */
+	COUPLING_GND,
+};
+
+/* Must match the timebases table. */
+enum time_bases {
+	TIME_10us = 0,
+	TIME_20us,
+	TIME_40us,
+	TIME_100us,
+	TIME_200us,
+	TIME_400us,
+	TIME_1ms,
+	TIME_2ms,
+	TIME_4ms,
+	TIME_10ms,
+	TIME_20ms,
+	TIME_40ms,
+	TIME_100ms,
+	TIME_200ms,
+	TIME_400ms,
+};
+
+/* Must match the vdivs table. */
+enum {
+	VDIV_10MV,
+	VDIV_20MV,
+	VDIV_50MV,
+	VDIV_100MV,
+	VDIV_200MV,
+	VDIV_500MV,
+	VDIV_1V,
+	VDIV_2V,
+	VDIV_5V,
+};
+
+enum trigger_slopes {
+	SLOPE_POSITIVE = 0,
+	SLOPE_NEGATIVE,
+};
+
+enum trigger_sources {
+	TRIGGER_CH2 = 0,
+	TRIGGER_CH1,
+	TRIGGER_EXT,
+};
+
+enum capturestates {
+	CAPTURE_EMPTY = 0,
+	CAPTURE_FILLING = 1,
+	CAPTURE_READY_8BIT = 2,
+	CAPTURE_READY_9BIT = 7,
+	CAPTURE_TIMEOUT = 127,
+	CAPTURE_UNKNOWN = 255,
+};
+
+enum triggermodes {
+	TRIGGERMODE_AUTO,
+	TRIGGERMODE_NORMAL,
+	TRIGGERMODE_SINGLE,
+};
+
+enum states {
+	IDLE,
+	NEW_CAPTURE,
+	CAPTURE,
+	FETCH_DATA,
+	STOPPING,
+};
+
+struct dso_profile {
+	/* VID/PID after cold boot */
+	uint16_t orig_vid;
+	uint16_t orig_pid;
+	/* VID/PID after firmware upload */
+	uint16_t fw_vid;
+	uint16_t fw_pid;
+	char *vendor;
+	char *model;
+	const uint64_t *buffersizes;
+	char *firmware;
+};
+
+struct dev_context {
+	const struct dso_profile *profile;
+	void *cb_data;
+	uint64_t limit_frames;
+	uint64_t num_frames;
+	GSList *enabled_channels;
+	/* We can't keep track of an FX2-based device after upgrading
+	 * the firmware (it re-enumerates into a different device address
+	 * after the upgrade) this is like a global lock. No device will open
+	 * until a proper delay after the last device was upgraded.
+	 */
+	int64_t fw_updated;
+	int epin_maxpacketsize;
+	int capture_empty_count;
+	int dev_state;
+
+	/* Oscilloscope settings. */
+	int timebase;
+	gboolean ch1_enabled;
+	gboolean ch2_enabled;
+	int voltage_ch1;
+	int voltage_ch2;
+	int coupling_ch1;
+	int coupling_ch2;
+	// voltage offset (vertical position)
+	float voffset_ch1;
+	float voffset_ch2;
+	float voffset_trigger;
+	uint16_t channel_levels[2][9][2];
+	unsigned int framesize;
+	gboolean filter_ch1;
+	gboolean filter_ch2;
+	gboolean filter_trigger;
+	int triggerslope;
+	char *triggersource;
+	float triggerposition;
+	int triggermode;
+
+	/* Frame transfer */
+	unsigned int samp_received;
+	unsigned int samp_buffered;
+	unsigned int trigger_offset;
+	unsigned char *framebuf;
+};
+
+SR_PRIV int dso_open(struct sr_dev_inst *sdi);
+SR_PRIV void dso_close(struct sr_dev_inst *sdi);
+SR_PRIV int dso_enable_trigger(const struct sr_dev_inst *sdi);
+SR_PRIV int dso_force_trigger(const struct sr_dev_inst *sdi);
+SR_PRIV int dso_init(const struct sr_dev_inst *sdi);
+SR_PRIV int dso_get_capturestate(const struct sr_dev_inst *sdi,
+		uint8_t *capturestate, uint32_t *trigger_offset);
+SR_PRIV int dso_capture_start(const struct sr_dev_inst *sdi);
+SR_PRIV int dso_get_channeldata(const struct sr_dev_inst *sdi,
+		libusb_transfer_cb_fn cb);
+
+#endif
diff --git a/hardware/ikalogic-scanalogic2/api.c b/hardware/ikalogic-scanalogic2/api.c
new file mode 100644
index 0000000..e586011
--- /dev/null
+++ b/hardware/ikalogic-scanalogic2/api.c
@@ -0,0 +1,528 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Marc Schink <sigrok-dev at marcschink.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "protocol.h"
+
+static const int hwcaps[] = {
+	SR_CONF_LOGIC_ANALYZER,
+	SR_CONF_SAMPLERATE,
+	SR_CONF_LIMIT_SAMPLES,
+	SR_CONF_TRIGGER_TYPE,
+	SR_CONF_CAPTURE_RATIO,
+};
+
+SR_PRIV const uint64_t sl2_samplerates[NUM_SAMPLERATES] = {
+	SR_KHZ(1.25),
+	SR_KHZ(10),
+	SR_KHZ(50),
+	SR_KHZ(100),
+	SR_KHZ(250),
+	SR_KHZ(500),
+	SR_MHZ(1),
+	SR_MHZ(2.5),
+	SR_MHZ(5),
+	SR_MHZ(10),
+	SR_MHZ(20),
+};
+
+static const char *channel_names[NUM_CHANNELS + 1] = {
+	"0", "1", "2", "3",
+	NULL,
+};
+
+SR_PRIV struct sr_dev_driver ikalogic_scanalogic2_driver_info;
+static struct sr_dev_driver *di = &ikalogic_scanalogic2_driver_info;
+
+static int init(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+	GSList *usb_devices, *devices, *l;
+	struct drv_context *drvc;
+	struct sr_dev_inst *sdi;
+	struct sr_channel *ch;
+	struct dev_context *devc;
+	struct sr_usb_dev_inst *usb;
+	struct device_info dev_info;
+	int ret, device_index, i;
+	char *fw_ver_str;
+
+	(void)options;
+
+	devices = NULL;
+	drvc = di->priv;
+	drvc->instances = NULL;
+	device_index = 0;
+
+	usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, USB_VID_PID);
+
+	if (usb_devices == NULL)
+		return NULL;
+
+	for (l = usb_devices; l; l = l->next) {
+		usb = l->data;
+
+		if ((ret = sl2_get_device_info(*usb, &dev_info)) < 0) {
+			sr_warn("Failed to get device information: %d.", ret);
+			sr_usb_dev_inst_free(usb);
+			continue;
+		}
+
+		if (!(devc = g_try_malloc(sizeof(struct dev_context)))) {
+			sr_err("Device instance malloc failed.");
+			sr_usb_dev_inst_free(usb);
+			continue;
+		}
+
+		if (!(devc->xfer_in = libusb_alloc_transfer(0))) {
+			sr_err("Transfer malloc failed.");
+			sr_usb_dev_inst_free(usb);
+			g_free(devc);
+			continue;
+		}
+
+		if (!(devc->xfer_out = libusb_alloc_transfer(0))) {
+			sr_err("Transfer malloc failed.");
+			sr_usb_dev_inst_free(usb);
+			libusb_free_transfer(devc->xfer_in);
+			g_free(devc);
+			continue;
+		}
+
+		fw_ver_str = g_strdup_printf("%u.%u", dev_info.fw_ver_major,
+			dev_info.fw_ver_minor);
+		if (!fw_ver_str) {
+			sr_err("Firmware string malloc failed.");
+			sr_usb_dev_inst_free(usb);
+			libusb_free_transfer(devc->xfer_in);
+			libusb_free_transfer(devc->xfer_out);
+			g_free(devc);
+			continue;
+		}
+
+		sdi = sr_dev_inst_new(device_index, SR_ST_INACTIVE, VENDOR_NAME,
+			MODEL_NAME, fw_ver_str);
+		g_free(fw_ver_str);
+		if (!sdi) {
+			sr_err("sr_dev_inst_new failed.");
+			sr_usb_dev_inst_free(usb);
+			libusb_free_transfer(devc->xfer_in);
+			libusb_free_transfer(devc->xfer_out);
+			g_free(devc);
+			continue;
+		}
+
+		sdi->priv = devc;
+		sdi->driver = di;
+		sdi->inst_type = SR_INST_USB;
+		sdi->conn = usb;
+
+		for (i = 0; channel_names[i]; i++) {
+			ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE,
+				channel_names[i]);
+			sdi->channels = g_slist_append(sdi->channels, ch);
+			devc->channels[i] = ch;
+		}
+
+		devc->state = STATE_IDLE;
+		devc->next_state = STATE_IDLE;
+
+		/* Set default samplerate. */
+		sl2_set_samplerate(sdi, DEFAULT_SAMPLERATE);
+
+		/* Set default capture ratio. */
+		devc->capture_ratio = 0;
+
+		/* Set default after trigger delay. */
+		devc->after_trigger_delay = 0;
+
+		memset(devc->xfer_buf_in, 0, LIBUSB_CONTROL_SETUP_SIZE +
+			PACKET_LENGTH);
+		memset(devc->xfer_buf_out, 0, LIBUSB_CONTROL_SETUP_SIZE +
+			PACKET_LENGTH);
+
+		libusb_fill_control_setup(devc->xfer_buf_in,
+			USB_REQUEST_TYPE_IN, USB_HID_GET_REPORT,
+			USB_HID_REPORT_TYPE_FEATURE, USB_INTERFACE,
+			PACKET_LENGTH);
+		libusb_fill_control_setup(devc->xfer_buf_out,
+			USB_REQUEST_TYPE_OUT, USB_HID_SET_REPORT,
+			USB_HID_REPORT_TYPE_FEATURE, USB_INTERFACE,
+			PACKET_LENGTH);
+
+		devc->xfer_data_in = devc->xfer_buf_in +
+			LIBUSB_CONTROL_SETUP_SIZE;
+		devc->xfer_data_out = devc->xfer_buf_out +
+			LIBUSB_CONTROL_SETUP_SIZE;
+
+		drvc->instances = g_slist_append(drvc->instances, sdi);
+		devices = g_slist_append(devices, sdi);
+
+		device_index++;
+	}
+
+	g_slist_free(usb_devices);
+
+	return devices;
+}
+
+static GSList *dev_list(void)
+{
+	return ((struct drv_context *)(di->priv))->instances;
+}
+
+static void clear_dev_context(void *priv)
+{
+	struct dev_context *devc;
+
+	devc = priv;
+
+	sr_dbg("Device context cleared.");
+
+	libusb_free_transfer(devc->xfer_in);
+	libusb_free_transfer(devc->xfer_out);
+	g_free(devc);
+}
+
+static int dev_clear(void)
+{
+	return std_dev_clear(di, &clear_dev_context);
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_usb_dev_inst *usb;
+	uint8_t buffer[PACKET_LENGTH];
+	int ret;
+
+	if (!(drvc = di->priv)) {
+		sr_err("Driver was not initialized.");
+		return SR_ERR;
+	}
+
+	usb = sdi->conn;
+	devc = sdi->priv;
+
+	if (sr_usb_open(drvc->sr_ctx->libusb_ctx, usb) != SR_OK)
+		return SR_ERR;
+
+	/*
+	 * Determine if a kernel driver is active on this interface and, if so,
+	 * detach it.
+	 */
+	if (libusb_kernel_driver_active(usb->devhdl, USB_INTERFACE) == 1) {
+		ret = libusb_detach_kernel_driver(usb->devhdl, USB_INTERFACE);
+		if (ret < 0) {
+			sr_err("Failed to detach kernel driver: %s.",
+				libusb_error_name(ret));
+			return SR_ERR;
+		}
+	}
+
+	if ((ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE)) < 0) {
+		sr_err("Failed to claim interface: %s.",
+			libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	libusb_fill_control_transfer(devc->xfer_in, usb->devhdl,
+		devc->xfer_buf_in, sl2_receive_transfer_in,
+		sdi, USB_TIMEOUT);
+
+	libusb_fill_control_transfer(devc->xfer_out, usb->devhdl,
+		devc->xfer_buf_out, sl2_receive_transfer_out,
+		sdi, USB_TIMEOUT);
+
+	memset(buffer, 0, sizeof(buffer));
+
+	buffer[0] = CMD_RESET;
+	if ((ret = sl2_transfer_out(usb->devhdl, buffer)) != PACKET_LENGTH) {
+		sr_err("Device reset failed: %s.", libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	/*
+	 * Set the device to idle state. If the device is not in idle state it
+	 * possibly will reset itself after a few seconds without being used
+	 * and thereby close the connection.
+	 */
+	buffer[0] = CMD_IDLE;
+	if ((ret = sl2_transfer_out(usb->devhdl, buffer)) != PACKET_LENGTH) {
+		sr_err("Failed to set device in idle state: %s.",
+			libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	sdi->status = SR_ST_ACTIVE;
+
+	return SR_OK;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+	struct sr_usb_dev_inst *usb;
+
+	if (!di->priv) {
+		sr_err("Driver was not initialized.");
+		return SR_ERR;
+	}
+
+	usb = sdi->conn;
+
+	if (!usb->devhdl)
+		return SR_OK;
+
+	libusb_release_interface(usb->devhdl, USB_INTERFACE);
+	libusb_close(usb->devhdl);
+
+	usb->devhdl = NULL;
+	sdi->status = SR_ST_INACTIVE;
+
+	return SR_OK;
+}
+
+static int cleanup(void)
+{
+	return dev_clear();
+}
+
+static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	int ret;
+
+	(void)cg;
+
+	ret = SR_OK;
+	devc = sdi->priv;
+
+	switch (key) {
+	case SR_CONF_SAMPLERATE:
+		*data = g_variant_new_uint64(devc->samplerate);
+		break;
+	case SR_CONF_CAPTURE_RATIO:
+		*data = g_variant_new_uint64(devc->capture_ratio);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return ret;
+}
+
+static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	uint64_t samplerate, limit_samples, capture_ratio;
+	int ret;
+
+	(void)cg;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	ret = SR_OK;
+
+	switch (key) {
+	case SR_CONF_LIMIT_SAMPLES:
+		limit_samples = g_variant_get_uint64(data);
+		ret = sl2_set_limit_samples(sdi, limit_samples);
+		break;
+	case SR_CONF_SAMPLERATE:
+		samplerate = g_variant_get_uint64(data);
+		ret = sl2_set_samplerate(sdi, samplerate);
+		break;
+	case SR_CONF_CAPTURE_RATIO:
+		capture_ratio = g_variant_get_uint64(data);
+		ret = sl2_set_capture_ratio(sdi, capture_ratio);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	GVariant *gvar, *grange[2];
+	GVariantBuilder gvb;
+	int ret;
+
+	(void)sdi;
+	(void)cg;
+
+	ret = SR_OK;
+
+	switch (key) {
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, hwcaps,
+			ARRAY_SIZE(hwcaps), sizeof(int32_t));
+		break;
+	case SR_CONF_SAMPLERATE:
+		g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
+		gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
+			sl2_samplerates, ARRAY_SIZE(sl2_samplerates),
+			sizeof(uint64_t));
+		g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
+		*data = g_variant_builder_end(&gvb);
+		break;
+	case SR_CONF_TRIGGER_TYPE:
+		*data = g_variant_new_string(TRIGGER_TYPES);
+		break;
+	case SR_CONF_LIMIT_SAMPLES:
+		grange[0] = g_variant_new_uint64(0);
+		grange[1] = g_variant_new_uint64(MAX_SAMPLES);
+		*data = g_variant_new_tuple(grange, 2);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return ret;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	uint16_t trigger_bytes, tmp;
+	unsigned int i, j;
+	int ret;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	devc = sdi->priv;
+	drvc = di->priv;
+
+	devc->cb_data = cb_data;
+	devc->wait_data_ready_locked = TRUE;
+	devc->stopping_in_progress = FALSE;
+	devc->transfer_error = FALSE;
+	devc->samples_processed = 0;
+	devc->channel = 0;
+	devc->sample_packet = 0;
+
+	/*
+	 * The trigger must be configured first because the calculation of the
+	 * pre and post trigger samples depends on a configured trigger.
+	 */
+	sl2_configure_trigger(sdi);
+	sl2_calculate_trigger_samples(sdi);
+
+	trigger_bytes = devc->pre_trigger_bytes + devc->post_trigger_bytes;
+
+	/* Calculate the number of expected sample packets. */
+	devc->num_sample_packets = trigger_bytes / PACKET_NUM_SAMPLE_BYTES;
+
+	/* Round up the number of expected sample packets. */
+	if (trigger_bytes % PACKET_NUM_SAMPLE_BYTES != 0)
+		devc->num_sample_packets++;
+
+	devc->num_enabled_channels = 0;
+
+	/*
+	 * Count the number of enabled channels and number them for a sequential
+	 * access.
+	 */
+	for (i = 0, j = 0; i < NUM_CHANNELS; i++) {
+		if (devc->channels[i]->enabled) {
+			devc->num_enabled_channels++;
+			devc->channel_map[j] = i;
+			j++;
+		}
+	}
+
+	sr_dbg("Number of enabled channels: %i.", devc->num_enabled_channels);
+
+	/* Set up the transfer buffer for the acquisition. */
+	devc->xfer_data_out[0] = CMD_SAMPLE;
+	devc->xfer_data_out[1] = 0x00;
+
+	tmp = GUINT16_TO_LE(devc->pre_trigger_bytes);
+	memcpy(devc->xfer_data_out + 2, &tmp, sizeof(tmp));
+
+	tmp = GUINT16_TO_LE(devc->post_trigger_bytes);
+	memcpy(devc->xfer_data_out + 4, &tmp, sizeof(tmp));
+
+	devc->xfer_data_out[6] = devc->samplerate_id;
+	devc->xfer_data_out[7] = devc->trigger_type;
+	devc->xfer_data_out[8] = devc->trigger_channel;
+	devc->xfer_data_out[9] = 0x00;
+
+	tmp = GUINT16_TO_LE(devc->after_trigger_delay);
+	memcpy(devc->xfer_data_out + 10, &tmp, sizeof(tmp));
+
+	if ((ret = libusb_submit_transfer(devc->xfer_out)) != 0) {
+		sr_err("Submit transfer failed: %s.", libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	usb_source_add(drvc->sr_ctx, 100, ikalogic_scanalogic2_receive_data, (void *)sdi);
+
+	sr_dbg("Acquisition started successfully.");
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	devc->next_state = STATE_SAMPLE;
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	(void)cb_data;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	sr_dbg("Stopping acquisition.");
+
+	sdi->status = SR_ST_STOPPING;
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver ikalogic_scanalogic2_driver_info = {
+	.name = "ikalogic-scanalogic2",
+	.longname = "IKALOGIC Scanalogic-2",
+	.api_version = 1,
+	.init = init,
+	.cleanup = cleanup,
+	.scan = scan,
+	.dev_list = dev_list,
+	.dev_clear = dev_clear,
+	.config_get = config_get,
+	.config_set = config_set,
+	.config_list = config_list,
+	.dev_open = dev_open,
+	.dev_close = dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/ikalogic-scanalogic2/protocol.c b/hardware/ikalogic-scanalogic2/protocol.c
new file mode 100644
index 0000000..b99709c
--- /dev/null
+++ b/hardware/ikalogic-scanalogic2/protocol.c
@@ -0,0 +1,758 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Marc Schink <sigrok-dev at marcschink.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "protocol.h"
+
+extern struct sr_dev_driver ikalogic_scanalogic2_driver_info;
+static struct sr_dev_driver *di = &ikalogic_scanalogic2_driver_info;
+
+extern uint64_t sl2_samplerates[NUM_SAMPLERATES];
+
+static void stop_acquisition(struct sr_dev_inst *sdi)
+{
+	struct drv_context *drvc = sdi->driver->priv;
+	struct dev_context *devc;
+	struct sr_datafeed_packet packet;
+
+	devc = sdi->priv;
+
+	/* Remove USB file descriptors from polling. */
+	usb_source_remove(drvc->sr_ctx);
+
+	packet.type = SR_DF_END;
+	sr_session_send(devc->cb_data, &packet);
+
+	sdi->status = SR_ST_ACTIVE;
+}
+
+static void abort_acquisition(struct sr_dev_inst *sdi)
+{
+	struct drv_context *drvc = sdi->driver->priv;
+	struct dev_context *devc;
+	struct sr_datafeed_packet packet;
+
+	devc = sdi->priv;
+
+	/* Remove USB file descriptors from polling. */
+	usb_source_remove(drvc->sr_ctx);
+
+	packet.type = SR_DF_END;
+	sr_session_send(devc->cb_data, &packet);
+
+	sdi->driver->dev_close(sdi);
+}
+
+static void buffer_sample_data(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	unsigned int offset, packet_length;
+
+	devc = sdi->priv;
+
+	if (devc->channels[devc->channel]->enabled) {
+		offset = devc->sample_packet * PACKET_NUM_SAMPLE_BYTES;
+
+		/*
+		 * Determine the packet length to ensure that the last packet
+		 * will not exceed the buffer size.
+		 */
+		packet_length = MIN(PACKET_NUM_SAMPLE_BYTES,
+			MAX_DEV_SAMPLE_BYTES - offset);
+
+		/*
+		 * Skip the first 4 bytes of the source buffer because they
+		 * contain channel and packet information only.
+		 */
+		memcpy(devc->sample_buffer[devc->channel] + offset,
+			devc->xfer_data_in + 4, packet_length);
+	}
+}
+
+static void process_sample_data(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_logic logic;
+	uint8_t i, j, tmp, buffer[PACKET_NUM_SAMPLES], *ptr[NUM_CHANNELS];
+	uint16_t offset, n = 0;
+	int8_t k;
+
+	devc = sdi->priv;
+	offset = devc->sample_packet * PACKET_NUM_SAMPLE_BYTES;
+
+	/*
+	 * Array of pointers to the sample data of all channels up to the last
+	 * enabled one for an uniform access to them. Note that the currently
+	 * received samples always belong to the last enabled channel.
+	 */
+	for (i = 0; i < devc->num_enabled_channels - 1; i++)
+		ptr[i] = devc->sample_buffer[devc->channel_map[i]] + offset;
+
+	/*
+	 * Skip the first 4 bytes of the buffer because they contain channel
+	 * and packet information only.
+	 */
+	ptr[i] = devc->xfer_data_in + 4;
+
+	for (i = 0; i < PACKET_NUM_SAMPLE_BYTES; i++) {
+		/* Stop processing if all requested samples are processed. */
+		if (devc->samples_processed == devc->limit_samples)
+			break;
+
+		k = 7;
+
+		if (devc->samples_processed == 0) {
+			/*
+			 * Adjust the position of the first sample to be
+			 * processed because possibly more samples than
+			 * necessary might have been acquired. This is because
+			 * the number of acquired samples is always rounded up
+			 * to a multiple of 8.
+			 */
+			k = k - (devc->pre_trigger_bytes * 8) +
+				devc->pre_trigger_samples;
+
+			sr_dbg("Start processing at sample: %d.", 7 - k);
+
+			/*
+			 * Send the trigger before the first sample is
+			 * processed if no pre trigger samples were calculated
+			 * through the capture ratio.
+			 */
+			if (devc->trigger_type != TRIGGER_TYPE_NONE &&
+					devc->pre_trigger_samples == 0) {
+				packet.type = SR_DF_TRIGGER;
+				sr_session_send(devc->cb_data, &packet);
+			}
+		}
+
+		for (; k >= 0; k--) {
+			/*
+			 * Stop processing if all requested samples are
+			 * processed.
+			 */
+			if (devc->samples_processed == devc->limit_samples)
+				break;
+
+			buffer[n] = 0;
+
+			/*
+			 * Extract the current sample for each enabled channel
+			 * and store them in the buffer.
+			 */
+			for (j = 0; j < devc->num_enabled_channels; j++) {
+				tmp = (ptr[j][i] & (1 << k)) >> k;
+				buffer[n] |= tmp << devc->channel_map[j];
+			}
+
+			n++;
+			devc->samples_processed++;
+
+			/*
+			 * Send all processed samples and the trigger if the
+			 * number of processed samples reaches the calculated
+			 * number of pre trigger samples.
+			 */
+			if (devc->samples_processed == devc->pre_trigger_samples &&
+					devc->trigger_type != TRIGGER_TYPE_NONE) {
+				packet.type = SR_DF_LOGIC;
+				packet.payload = &logic;
+				logic.length = n;
+				logic.unitsize = 1;
+				logic.data = buffer;
+				sr_session_send(devc->cb_data, &packet);
+
+				packet.type = SR_DF_TRIGGER;
+				sr_session_send(devc->cb_data, &packet);
+
+				n = 0;
+			}
+		}
+	}
+
+	if (n > 0) {
+		packet.type = SR_DF_LOGIC;
+		packet.payload = &logic;
+		logic.length = n;
+		logic.unitsize = 1;
+		logic.data = buffer;
+		sr_session_send(devc->cb_data, &packet);
+	}
+}
+
+SR_PRIV int ikalogic_scanalogic2_receive_data(int fd, int revents, void *cb_data)
+{
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+	struct drv_context *drvc;
+	struct timeval tv;
+	int64_t current_time, time_elapsed;
+	int ret = 0;
+
+	(void)fd;
+	(void)revents;
+
+	if (!(sdi = cb_data))
+		return TRUE;
+
+	if (!(devc = sdi->priv))
+		return TRUE;
+
+	drvc = di->priv;
+	current_time = g_get_monotonic_time();
+
+	if (devc->state == STATE_WAIT_DATA_READY &&
+			!devc->wait_data_ready_locked) {
+		time_elapsed = current_time - devc->wait_data_ready_time;
+
+		/*
+		 * Check here for stopping in addition to the transfer
+		 * callback functions to avoid waiting until the
+		 * WAIT_DATA_READY_INTERVAL has expired.
+		 */
+		if (sdi->status == SR_ST_STOPPING) {
+			if (!devc->stopping_in_progress) {
+				devc->next_state = STATE_RESET_AND_IDLE;
+				devc->stopping_in_progress = TRUE;
+				ret = libusb_submit_transfer(devc->xfer_in);
+			}
+		} else if (time_elapsed >= WAIT_DATA_READY_INTERVAL) {
+			devc->wait_data_ready_locked = TRUE;
+			ret = libusb_submit_transfer(devc->xfer_in);
+		}
+	}
+
+	if (ret != 0) {
+		sr_err("Submit transfer failed: %s.", libusb_error_name(ret));
+		abort_acquisition(sdi);
+		return TRUE;
+	}
+
+	tv.tv_sec = 0;
+	tv.tv_usec = 0;
+
+	libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx, &tv,
+		NULL);
+
+	/* Check if an error occurred on a transfer. */
+	if (devc->transfer_error)
+		abort_acquisition(sdi);
+
+	return TRUE;
+}
+
+SR_PRIV void sl2_receive_transfer_in( struct libusb_transfer *transfer)
+{
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+	uint8_t last_channel;
+	int ret = 0;
+
+	sdi = transfer->user_data;
+	devc = sdi->priv;
+
+	if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
+		sr_err("Transfer to device failed: %i.", transfer->status);
+		devc->transfer_error = TRUE;
+		return;
+	}
+
+	if (sdi->status == SR_ST_STOPPING && !devc->stopping_in_progress) {
+		devc->next_state = STATE_RESET_AND_IDLE;
+		devc->stopping_in_progress = TRUE;
+
+		if (libusb_submit_transfer(devc->xfer_in) != 0) {
+			sr_err("Submit transfer failed: %s.",
+				libusb_error_name(ret));
+			devc->transfer_error = TRUE;
+		}
+
+		return;
+	}
+
+	if (devc->state != devc->next_state)
+		sr_spew("State changed from %i to %i.",
+			devc->state, devc->next_state);
+	devc->state = devc->next_state;
+
+	if (devc->state == STATE_WAIT_DATA_READY) {
+		/* Check if the received data are a valid device status. */
+		if (devc->xfer_data_in[0] == 0x05) {
+			if (devc->xfer_data_in[1] == STATUS_WAITING_FOR_TRIGGER)
+				sr_dbg("Waiting for trigger.");
+			else if (devc->xfer_data_in[1] == STATUS_SAMPLING)
+				sr_dbg("Sampling in progress.");
+		}
+
+		/*
+		 * Check if the received data are a valid device status and the
+		 * sample data are ready.
+		 */
+		if (devc->xfer_data_in[0] == 0x05 &&
+				devc->xfer_data_in[1] == STATUS_DATA_READY) {
+			devc->next_state = STATE_RECEIVE_DATA;
+			ret = libusb_submit_transfer(transfer);
+		} else {
+			devc->wait_data_ready_locked = FALSE;
+			devc->wait_data_ready_time = g_get_monotonic_time();
+		}
+	} else if (devc->state == STATE_RECEIVE_DATA) {
+		last_channel = devc->channel_map[devc->num_enabled_channels - 1];
+
+		if (devc->channel < last_channel) {
+			buffer_sample_data(sdi);
+		} else if (devc->channel == last_channel) {
+			process_sample_data(sdi);
+		} else {
+			/*
+			 * Stop acquisition because all samples of enabled
+			 * channels are processed.
+			 */
+			devc->next_state = STATE_RESET_AND_IDLE;
+		}
+
+		devc->sample_packet++;
+		devc->sample_packet %= devc->num_sample_packets;
+
+		if (devc->sample_packet == 0)
+			devc->channel++;
+
+		ret = libusb_submit_transfer(transfer);
+	} else if (devc->state == STATE_RESET_AND_IDLE) {
+		/* Check if the received data are a valid device status. */
+		if (devc->xfer_data_in[0] == 0x05) {
+			if (devc->xfer_data_in[1] == STATUS_DEVICE_READY) {
+				devc->next_state = STATE_IDLE;
+				devc->xfer_data_out[0] = CMD_IDLE;
+			} else {
+				devc->next_state = STATE_WAIT_DEVICE_READY;
+				devc->xfer_data_out[0] = CMD_RESET;
+			}
+
+			ret = libusb_submit_transfer(devc->xfer_out);
+		} else {
+			/*
+			 * The received device status is invalid which
+			 * indicates that the device is not ready to accept
+			 * commands. Request a new device status until a valid
+			 * device status is received.
+			 */
+			ret = libusb_submit_transfer(transfer);
+		}
+	} else if (devc->state == STATE_WAIT_DEVICE_READY) {
+		/* Check if the received data are a valid device status. */
+		if (devc->xfer_data_in[0] == 0x05) {
+			if (devc->xfer_data_in[1] == STATUS_DEVICE_READY) {
+				devc->next_state = STATE_IDLE;
+				devc->xfer_data_out[0] = CMD_IDLE;
+			} else {
+				/*
+				 * The received device status is valid but the
+				 * device is not ready. Probably the device did
+				 * not recognize the last reset. Reset the
+				 * device again.
+				 */
+				devc->xfer_data_out[0] = CMD_RESET;
+			}
+
+			ret = libusb_submit_transfer(devc->xfer_out);
+		} else {
+			/*
+			 * The device is not ready and therefore not able to
+			 * change to the idle state. Request a new device
+			 * status until the device is ready.
+			 */
+			ret = libusb_submit_transfer(transfer);
+		}
+	}
+
+	if (ret != 0) {
+		sr_err("Submit transfer failed: %s.", libusb_error_name(ret));
+		devc->transfer_error = TRUE;
+	}
+}
+
+SR_PRIV void sl2_receive_transfer_out( struct libusb_transfer *transfer)
+{
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+	int ret = 0;
+
+	sdi = transfer->user_data;
+	devc = sdi->priv;
+
+	if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
+		sr_err("Transfer to device failed: %i.", transfer->status);
+		devc->transfer_error = TRUE;
+		return;
+	}
+
+	if (sdi->status == SR_ST_STOPPING && !devc->stopping_in_progress) {
+		devc->next_state = STATE_RESET_AND_IDLE;
+		devc->stopping_in_progress = TRUE;
+
+		if (libusb_submit_transfer(devc->xfer_in) != 0) {
+			sr_err("Submit transfer failed: %s.",
+				libusb_error_name(ret));
+
+			devc->transfer_error = TRUE;
+		}
+
+		return;
+	}
+
+	if (devc->state != devc->next_state)
+		sr_spew("State changed from %i to %i.",
+			devc->state, devc->next_state);
+	devc->state = devc->next_state;
+
+	if (devc->state == STATE_IDLE) {
+		stop_acquisition(sdi);
+	} else if (devc->state == STATE_SAMPLE) {
+		devc->next_state = STATE_WAIT_DATA_READY;
+		ret = libusb_submit_transfer(devc->xfer_in);
+	} else if (devc->state == STATE_WAIT_DEVICE_READY) {
+		ret = libusb_submit_transfer(devc->xfer_in);
+	}
+
+	if (ret != 0) {
+		sr_err("Submit transfer failed: %s.", libusb_error_name(ret));
+		devc->transfer_error = TRUE;
+	}
+}
+
+SR_PRIV int sl2_set_samplerate(const struct sr_dev_inst *sdi,
+		uint64_t samplerate)
+{
+	struct dev_context *devc;
+	unsigned int i;
+
+	devc = sdi->priv;
+
+	for (i = 0; i < NUM_SAMPLERATES; i++) {
+		if (sl2_samplerates[i] == samplerate) {
+			devc->samplerate = samplerate;
+			devc->samplerate_id = NUM_SAMPLERATES - i - 1;
+			return SR_OK;
+		}
+	}
+
+	return SR_ERR_ARG;
+}
+
+SR_PRIV int sl2_set_limit_samples(const struct sr_dev_inst *sdi,
+				  uint64_t limit_samples)
+{
+	struct dev_context *devc;
+
+	devc = sdi->priv;
+
+	if (limit_samples == 0) {
+		sr_err("Invalid number of limit samples: %" PRIu64 ".",
+			limit_samples);
+		return SR_ERR_ARG;
+	}
+
+	if (limit_samples > MAX_SAMPLES)
+		limit_samples = MAX_SAMPLES;
+
+	sr_dbg("Limit samples set to %" PRIu64 ".", limit_samples);
+
+	devc->limit_samples = limit_samples;
+
+	return SR_OK;
+}
+
+SR_PRIV void sl2_configure_trigger(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_channel *ch;
+	uint8_t trigger_type;
+	int channel_index, num_triggers_anyedge;
+	char *trigger;
+	GSList *l;
+
+	devc = sdi->priv;
+
+	/* Disable the trigger by default. */
+	devc->trigger_channel = TRIGGER_CHANNEL_0;
+	devc->trigger_type = TRIGGER_TYPE_NONE;
+
+	num_triggers_anyedge = 0;
+
+	for (l = sdi->channels, channel_index = 0; l; l = l->next, channel_index++) {
+		ch = l->data;
+		trigger = ch->trigger;
+
+		if (!trigger || !ch->enabled)
+			continue;
+
+		switch (*trigger) {
+		case 'r':
+			trigger_type = TRIGGER_TYPE_POSEDGE;
+			break;
+		case 'f':
+			trigger_type = TRIGGER_TYPE_NEGEDGE;
+			break;
+		case 'c':
+			trigger_type = TRIGGER_TYPE_ANYEDGE;
+			num_triggers_anyedge++;
+			break;
+		default:
+			continue;
+		}
+
+		devc->trigger_channel = channel_index + 1;
+		devc->trigger_type = trigger_type;
+	}
+
+	/*
+	 * Set trigger to any edge on all channels if the trigger for each
+	 * channel is set to any edge.
+	 */
+	if (num_triggers_anyedge == NUM_CHANNELS) {
+		devc->trigger_channel = TRIGGER_CHANNEL_ALL;
+		devc->trigger_type = TRIGGER_TYPE_ANYEDGE;
+	}
+
+	sr_dbg("Trigger set to channel 0x%02x and type 0x%02x.",
+		devc->trigger_channel, devc->trigger_type);
+}
+
+SR_PRIV int sl2_set_capture_ratio(const struct sr_dev_inst *sdi,
+				  uint64_t capture_ratio)
+{
+	struct dev_context *devc;
+
+	devc = sdi->priv;
+
+	if (capture_ratio > 100) {
+		sr_err("Invalid capture ratio: %" PRIu64 " %%.", capture_ratio);
+		return SR_ERR_ARG;
+	}
+
+	sr_info("Capture ratio set to %" PRIu64 " %%.", capture_ratio);
+
+	devc->capture_ratio = capture_ratio;
+
+	return SR_OK;
+}
+
+SR_PRIV int sl2_set_after_trigger_delay(const struct sr_dev_inst *sdi,
+					uint64_t after_trigger_delay)
+{
+	struct dev_context *devc;
+
+	devc = sdi->priv;
+
+	if (after_trigger_delay > MAX_AFTER_TRIGGER_DELAY) {
+		sr_err("Invalid after trigger delay: %" PRIu64 " ms.",
+			after_trigger_delay);
+		return SR_ERR_ARG;
+	}
+
+	sr_info("After trigger delay set to %" PRIu64 " ms.",
+		after_trigger_delay);
+
+	devc->after_trigger_delay = after_trigger_delay;
+
+	return SR_OK;
+}
+
+SR_PRIV void sl2_calculate_trigger_samples(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	uint64_t pre_trigger_samples, post_trigger_samples;
+	uint16_t pre_trigger_bytes, post_trigger_bytes;
+	uint8_t cr;
+
+	devc = sdi->priv;
+	cr = devc->capture_ratio;
+
+	/* Ignore the capture ratio if no trigger is enabled. */
+	if (devc->trigger_type == TRIGGER_TYPE_NONE)
+		cr = 0;
+
+	pre_trigger_samples = (devc->limit_samples * cr) / 100;
+	post_trigger_samples = (devc->limit_samples * (100 - cr)) / 100;
+
+	/*
+	 * Increase the number of post trigger samples by one to compensate the
+	 * possible loss of a sample through integer rounding.
+	 */
+	if (pre_trigger_samples + post_trigger_samples != devc->limit_samples)
+		post_trigger_samples++;
+
+	/*
+	 * The device requires the number of samples in multiples of 8 which
+	 * will also be called sample bytes in the following.
+	 */
+	pre_trigger_bytes = pre_trigger_samples / 8;
+	post_trigger_bytes = post_trigger_samples / 8;
+
+	/*
+	 * Round up the number of sample bytes to ensure that at least the
+	 * requested number of samples will be acquired. Note that due to this
+	 * rounding the buffer to store these sample bytes needs to be at least
+	 * one sample byte larger than the minimal number of sample bytes
+	 * needed to store the requested samples.
+	 */
+	if (pre_trigger_samples % 8 != 0)
+		pre_trigger_bytes++;
+
+	if (post_trigger_samples % 8 != 0)
+		post_trigger_bytes++;
+
+	sr_info("Pre trigger samples: %" PRIu64 ".", pre_trigger_samples);
+	sr_info("Post trigger samples: %" PRIu64 ".", post_trigger_samples);
+	sr_dbg("Pre trigger sample bytes: %" PRIu16 ".", pre_trigger_bytes);
+	sr_dbg("Post trigger sample bytes: %" PRIu16 ".", post_trigger_bytes);
+
+	devc->pre_trigger_samples = pre_trigger_samples;
+	devc->pre_trigger_bytes = pre_trigger_bytes;
+	devc->post_trigger_bytes = post_trigger_bytes;
+}
+
+SR_PRIV int sl2_get_device_info(struct sr_usb_dev_inst usb,
+		struct device_info *dev_info)
+{
+	struct drv_context *drvc;
+	uint8_t buffer[PACKET_LENGTH];
+	int ret;
+
+	drvc = di->priv;
+
+	if (!dev_info)
+		return SR_ERR_ARG;
+
+	if (sr_usb_open(drvc->sr_ctx->libusb_ctx, &usb) != SR_OK)
+		return SR_ERR;
+
+	/*
+	 * Determine if a kernel driver is active on this interface and, if so,
+	 * detach it.
+	 */
+	if (libusb_kernel_driver_active(usb.devhdl, USB_INTERFACE) == 1) {
+		ret = libusb_detach_kernel_driver(usb.devhdl,
+			USB_INTERFACE);
+
+		if (ret < 0) {
+			sr_err("Failed to detach kernel driver: %s.",
+				libusb_error_name(ret));
+			libusb_close(usb.devhdl);
+			return SR_ERR;
+		}
+	}
+
+	ret = libusb_claim_interface(usb.devhdl, USB_INTERFACE);
+
+	if (ret) {
+		sr_err("Failed to claim interface: %s.",
+			libusb_error_name(ret));
+		libusb_close(usb.devhdl);
+		return SR_ERR;
+	}
+
+	memset(buffer, 0, sizeof(buffer));
+
+	/*
+	 * Reset the device to ensure it is in a proper state to request the
+	 * device information.
+	 */
+	buffer[0] = CMD_RESET;
+	if ((ret = sl2_transfer_out(usb.devhdl, buffer)) != PACKET_LENGTH) {
+		sr_err("Resetting of device failed: %s.",
+			libusb_error_name(ret));
+		libusb_release_interface(usb.devhdl, USB_INTERFACE);
+		libusb_close(usb.devhdl);
+		return SR_ERR;
+	}
+
+	buffer[0] = CMD_INFO;
+	if ((ret = sl2_transfer_out(usb.devhdl, buffer)) != PACKET_LENGTH) {
+		sr_err("Requesting of device information failed: %s.",
+			libusb_error_name(ret));
+		libusb_release_interface(usb.devhdl, USB_INTERFACE);
+		libusb_close(usb.devhdl);
+		return SR_ERR;
+	}
+
+	if ((ret = sl2_transfer_in(usb.devhdl, buffer)) != PACKET_LENGTH) {
+		sr_err("Receiving of device information failed: %s.",
+			libusb_error_name(ret));
+		libusb_release_interface(usb.devhdl, USB_INTERFACE);
+		libusb_close(usb.devhdl);
+		return SR_ERR;
+	}
+
+	memcpy(&(dev_info->serial), buffer + 1, sizeof(uint32_t));
+	dev_info->serial = GUINT32_FROM_LE(dev_info->serial);
+
+	dev_info->fw_ver_major = buffer[5];
+	dev_info->fw_ver_minor = buffer[6];
+
+	buffer[0] = CMD_RESET;
+	if ((ret = sl2_transfer_out(usb.devhdl, buffer)) != PACKET_LENGTH) {
+		sr_err("Device reset failed: %s.", libusb_error_name(ret));
+		libusb_release_interface(usb.devhdl, USB_INTERFACE);
+		libusb_close(usb.devhdl);
+		return SR_ERR;
+	}
+
+	/*
+	 * Set the device to idle state. If the device is not in idle state it
+	 * possibly will reset itself after a few seconds without being used
+	 * and thereby close the connection.
+	 */
+	buffer[0] = CMD_IDLE;
+	if ((ret = sl2_transfer_out(usb.devhdl, buffer)) != PACKET_LENGTH) {
+		sr_err("Failed to set device in idle state: %s.",
+			libusb_error_name(ret));
+		libusb_release_interface(usb.devhdl, USB_INTERFACE);
+		libusb_close(usb.devhdl);
+		return SR_ERR;
+	}
+
+	ret = libusb_release_interface(usb.devhdl, USB_INTERFACE);
+
+	if (ret < 0) {
+		sr_err("Failed to release interface: %s.",
+			libusb_error_name(ret));
+		libusb_close(usb.devhdl);
+		return SR_ERR;
+	}
+
+	libusb_close(usb.devhdl);
+
+	return SR_OK;
+}
+
+SR_PRIV int sl2_transfer_in(libusb_device_handle *dev_handle, uint8_t *data)
+{
+	return libusb_control_transfer(dev_handle, USB_REQUEST_TYPE_IN,
+		USB_HID_GET_REPORT, USB_HID_REPORT_TYPE_FEATURE, USB_INTERFACE,
+		(unsigned char *)data, PACKET_LENGTH, USB_TIMEOUT);
+}
+
+SR_PRIV int sl2_transfer_out(libusb_device_handle *dev_handle, uint8_t *data)
+{
+	return libusb_control_transfer(dev_handle, USB_REQUEST_TYPE_OUT,
+		USB_HID_SET_REPORT, USB_HID_REPORT_TYPE_FEATURE, USB_INTERFACE,
+		(unsigned char *)data, PACKET_LENGTH, USB_TIMEOUT);
+}
diff --git a/hardware/ikalogic-scanalogic2/protocol.h b/hardware/ikalogic-scanalogic2/protocol.h
new file mode 100644
index 0000000..3b411e6
--- /dev/null
+++ b/hardware/ikalogic-scanalogic2/protocol.h
@@ -0,0 +1,239 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Marc Schink <sigrok-dev at marcschink.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_IKALOGIC_SCANALOGIC2_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_IKALOGIC_SCANALOGIC2_PROTOCOL_H
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "ikalogic-scanalogic2"
+
+#define VENDOR_NAME			"IKALOGIC"
+#define MODEL_NAME			"Scanalogic-2"
+
+#define USB_VID_PID			"20a0.4123"
+#define USB_INTERFACE			0
+#define USB_TIMEOUT			5000
+
+#define USB_REQUEST_TYPE_IN		(LIBUSB_REQUEST_TYPE_CLASS | \
+	LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_IN)
+
+#define USB_REQUEST_TYPE_OUT		(LIBUSB_REQUEST_TYPE_CLASS | \
+	LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_OUT)
+
+#define USB_HID_GET_REPORT		0x01
+#define USB_HID_SET_REPORT		0x09
+#define USB_HID_REPORT_TYPE_FEATURE	0x300
+
+#define NUM_SAMPLERATES			11
+#define NUM_CHANNELS			4
+
+#define TRIGGER_TYPES			"rfc"
+
+/*
+ * Number of sample bytes and samples the device can acquire. Note that the
+ * vendor software can acquire 32736 sample bytes only but the device is capable
+ * to acquire up to 32766 sample bytes.
+ */
+#define MAX_DEV_SAMPLE_BYTES		32766
+#define MAX_DEV_SAMPLES			(MAX_INT_SAMPLE_BYTES * 8)
+
+/* Number of sample bytes and samples the driver can acquire. */
+#define MAX_SAMPLE_BYTES		(MAX_DEV_SAMPLE_BYTES - 1)
+#define MAX_SAMPLES			(MAX_SAMPLE_BYTES * 8)
+
+/* Maximum time that the trigger can be delayed in milliseconds. */
+#define MAX_AFTER_TRIGGER_DELAY		65000
+
+#define PACKET_LENGTH			128
+
+/* Number of sample bytes per packet where a sample byte contains 8 samples. */
+#define PACKET_NUM_SAMPLE_BYTES		124
+
+/* Number of samples per packet. */
+#define PACKET_NUM_SAMPLES		(PACKET_NUM_SAMPLE_BYTES * 8)
+
+#define DEFAULT_SAMPLERATE		SR_KHZ(1.25)
+
+/*
+ * Time interval between the last status of available data received and the
+ * moment when the next status request will be sent in microseconds.
+ */
+#define WAIT_DATA_READY_INTERVAL	1500000
+
+#define CMD_SAMPLE			0x01
+#define CMD_RESET			0x02
+#define CMD_IDLE			0x07
+#define CMD_INFO			0x0a
+
+#define TRIGGER_CHANNEL_ALL		0x00
+#define TRIGGER_CHANNEL_0		0x01
+#define TRIGGER_CHANNEL_1		0x02
+#define TRIGGER_CHANNEL_2		0x03
+
+#define TRIGGER_TYPE_NEGEDGE		0x00
+#define TRIGGER_TYPE_POSEDGE		0x01
+#define TRIGGER_TYPE_ANYEDGE		0x02
+#define TRIGGER_TYPE_NONE		0x03
+
+#define STATUS_DATA_READY		0x60
+#define STATUS_WAITING_FOR_TRIGGER	0x61
+#define STATUS_SAMPLING			0x62
+#define STATUS_DEVICE_READY		0x63
+
+struct device_info {
+	/* Serial number of the device. */
+	uint32_t serial;
+
+	/* Major version of the firmware. */
+	uint8_t fw_ver_major;
+
+	/* Minor version of the firmware. */
+	uint8_t fw_ver_minor;
+};
+
+enum {
+	STATE_IDLE = 0,
+	STATE_SAMPLE,
+	STATE_WAIT_DATA_READY,
+	STATE_RECEIVE_DATA,
+	STATE_RESET_AND_IDLE,
+	STATE_WAIT_DEVICE_READY
+};
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+	/* Current selected samplerate. */
+	uint64_t samplerate;
+
+	/* Device specific identifier for the current samplerate. */
+	uint8_t samplerate_id;
+
+	/* Current sampling limit. */
+	uint64_t limit_samples;
+
+	/* Calculated number of pre-trigger samples. */
+	uint64_t pre_trigger_samples;
+
+	/* Number of pre- and post-trigger sample bytes to acquire. */
+	uint16_t pre_trigger_bytes;
+	uint16_t post_trigger_bytes;
+
+	/* Device specific settings for the trigger. */
+	uint8_t trigger_channel;
+	uint8_t trigger_type;
+
+	unsigned int capture_ratio;
+
+	/* Time that the trigger will be delayed in milliseconds. */
+	uint16_t after_trigger_delay;
+
+	void *cb_data;
+
+	/* Array to provide an index based access to all channels. */
+	const struct sr_channel *channels[NUM_CHANNELS];
+
+	struct libusb_transfer *xfer_in, *xfer_out;
+
+	/*
+	 * Buffer to store setup and payload data for incoming and outgoing
+	 * transfers.
+	 */
+	uint8_t xfer_buf_in[LIBUSB_CONTROL_SETUP_SIZE + PACKET_LENGTH];
+	uint8_t xfer_buf_out[LIBUSB_CONTROL_SETUP_SIZE + PACKET_LENGTH];
+
+	/* Pointers to the payload of incoming and outgoing transfers. */
+	uint8_t *xfer_data_in, *xfer_data_out;
+
+	/* Current state of the state machine */
+	unsigned int state;
+
+	/* Next state of the state machine. */
+	unsigned int next_state;
+
+	/*
+	 * Locking variable to ensure that no status about available data will
+	 * be requested until the last status was received.
+	 */
+	gboolean wait_data_ready_locked;
+
+	/*
+	 * Time when the last response about the status of available data was
+	 * received.
+	 */
+	int64_t wait_data_ready_time;
+
+	/*
+	 * Indicates that stopping of the acquisition is currently in progress.
+	 */
+	gboolean stopping_in_progress;
+
+	/*
+	 * Buffer which contains the samples received from the device for each
+	 * channel except the last one. The samples of the last channel will be
+	 * processed directly after they will be received.
+	 */
+	uint8_t sample_buffer[NUM_CHANNELS - 1][MAX_DEV_SAMPLE_BYTES];
+
+	/* Expected number of sample packets for each channel. */
+	uint16_t num_sample_packets;
+
+	/* Number of samples already processed. */
+	uint64_t samples_processed;
+
+	/* Sample packet number that is currently processed. */
+	uint16_t sample_packet;
+
+	/* Channel number that is currently processed. */
+	uint8_t channel;
+
+	/* Number of enabled channels. */
+	unsigned int num_enabled_channels;
+
+	/* Array to provide a sequential access to all enabled channel indices. */
+	uint8_t channel_map[NUM_CHANNELS];
+
+	/* Indicates whether a transfer failed. */
+	gboolean transfer_error;
+};
+
+SR_PRIV int ikalogic_scanalogic2_receive_data(int fd, int revents, void *cb_data);
+SR_PRIV void sl2_receive_transfer_in(struct libusb_transfer *transfer);
+SR_PRIV void sl2_receive_transfer_out(struct libusb_transfer *transfer);
+SR_PRIV int sl2_set_samplerate(const struct sr_dev_inst *sdi,
+		uint64_t samplerate);
+SR_PRIV int sl2_set_limit_samples(const struct sr_dev_inst *sdi,
+				  uint64_t limit_samples);
+SR_PRIV void sl2_configure_trigger(const struct sr_dev_inst *sdi);
+SR_PRIV int sl2_set_capture_ratio(const struct sr_dev_inst *sdi,
+				  uint64_t capture_ratio);
+SR_PRIV int sl2_set_after_trigger_delay(const struct sr_dev_inst *sdi,
+					uint64_t after_trigger_delay);
+SR_PRIV void sl2_calculate_trigger_samples(const struct sr_dev_inst *sdi);
+SR_PRIV int sl2_get_device_info(struct sr_usb_dev_inst usb,
+		struct device_info *dev_info);
+SR_PRIV int sl2_transfer_in(libusb_device_handle *dev_handle, uint8_t *data);
+SR_PRIV int sl2_transfer_out(libusb_device_handle *dev_handle, uint8_t *data);
+
+#endif
diff --git a/hardware/ikalogic-scanaplus/api.c b/hardware/ikalogic-scanaplus/api.c
new file mode 100644
index 0000000..e855097
--- /dev/null
+++ b/hardware/ikalogic-scanaplus/api.c
@@ -0,0 +1,438 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "protocol.h"
+
+#define USB_VENDOR_ID			0x0403
+#define USB_DEVICE_ID			0x6014
+#define USB_VENDOR_NAME			"IKALOGIC"
+#define USB_MODEL_NAME			"ScanaPLUS"
+#define USB_IPRODUCT			"SCANAPLUS"
+
+#define SAMPLE_BUF_SIZE			(8 * 1024 * 1024)
+
+static const int32_t hwcaps[] = {
+	SR_CONF_LOGIC_ANALYZER,
+	SR_CONF_SAMPLERATE,
+	SR_CONF_LIMIT_MSEC,
+	SR_CONF_LIMIT_SAMPLES,
+	SR_CONF_CONTINUOUS, // TODO?
+};
+
+/* Channels are numbered 1-9. */
+static const char *channel_names[] = {
+	"1", "2", "3", "4", "5", "6", "7", "8", "9",
+	NULL,
+};
+
+/* Note: The IKALOGIC ScanaPLUS always samples at 100MHz. */
+static uint64_t samplerates[1] = { SR_MHZ(100) };
+
+SR_PRIV struct sr_dev_driver ikalogic_scanaplus_driver_info;
+static struct sr_dev_driver *di = &ikalogic_scanaplus_driver_info;
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data);
+
+static void clear_helper(void *priv)
+{
+	struct dev_context *devc;
+
+	devc = priv;
+
+	ftdi_free(devc->ftdic);
+	g_free(devc->compressed_buf);
+	g_free(devc->sample_buf);
+}
+
+static int dev_clear(void)
+{
+	return std_dev_clear(di, clear_helper);
+}
+
+static int init(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+	struct sr_dev_inst *sdi;
+	struct sr_channel *ch;
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	GSList *devices;
+	unsigned int i;
+	int ret;
+
+	(void)options;
+
+	drvc = di->priv;
+
+	devices = NULL;
+
+	/* Allocate memory for our private device context. */
+	if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+		sr_err("Device context malloc failed.");
+		goto err_free_nothing;
+	}
+
+	/* Allocate memory for the incoming compressed samples. */
+	if (!(devc->compressed_buf = g_try_malloc0(COMPRESSED_BUF_SIZE))) {
+		sr_err("compressed_buf malloc failed.");
+		goto err_free_devc;
+	}
+
+	/* Allocate memory for the uncompressed samples. */
+	if (!(devc->sample_buf = g_try_malloc0(SAMPLE_BUF_SIZE))) {
+		sr_err("sample_buf malloc failed.");
+		goto err_free_compressed_buf;
+	}
+
+	/* Allocate memory for the FTDI context (ftdic) and initialize it. */
+	if (!(devc->ftdic = ftdi_new())) {
+		sr_err("Failed to initialize libftdi.");
+		goto err_free_sample_buf;
+	}
+
+	/* Check for the device and temporarily open it. */
+	ret = ftdi_usb_open_desc(devc->ftdic, USB_VENDOR_ID, USB_DEVICE_ID,
+				 USB_IPRODUCT, NULL);
+	if (ret < 0) {
+		/* Log errors, except for -3 ("device not found"). */
+		if (ret != -3)
+			sr_err("Failed to open device (%d): %s", ret,
+			       ftdi_get_error_string(devc->ftdic));
+		goto err_free_ftdic;
+	}
+
+	/* Register the device with libsigrok. */
+	sdi = sr_dev_inst_new(0, SR_ST_INITIALIZING,
+			USB_VENDOR_NAME, USB_MODEL_NAME, NULL);
+	if (!sdi) {
+		sr_err("Failed to create device instance.");
+		goto err_close_ftdic;
+	}
+	sdi->driver = di;
+	sdi->priv = devc;
+
+	for (i = 0; channel_names[i]; i++) {
+		if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE,
+					   channel_names[i])))
+			return NULL;
+		sdi->channels = g_slist_append(sdi->channels, ch);
+	}
+
+	devices = g_slist_append(devices, sdi);
+	drvc->instances = g_slist_append(drvc->instances, sdi);
+
+	/* Close device. We'll reopen it again when we need it. */
+	scanaplus_close(devc);
+
+	return devices;
+
+err_close_ftdic:
+	scanaplus_close(devc);
+err_free_ftdic:
+	ftdi_free(devc->ftdic); /* NOT free() or g_free()! */
+err_free_sample_buf:
+	g_free(devc->sample_buf);
+err_free_compressed_buf:
+	g_free(devc->compressed_buf);
+err_free_devc:
+	g_free(devc);
+err_free_nothing:
+
+	return NULL;
+}
+
+static GSList *dev_list(void)
+{
+	return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	int ret;
+
+	devc = sdi->priv;
+
+	/* Select interface A, otherwise communication will fail. */
+	ret = ftdi_set_interface(devc->ftdic, INTERFACE_A);
+	if (ret < 0) {
+		sr_err("Failed to set FTDI interface A (%d): %s", ret,
+		       ftdi_get_error_string(devc->ftdic));
+		return SR_ERR;
+	}
+	sr_dbg("FTDI chip interface A set successfully.");
+
+	/* Open the device. */
+	ret = ftdi_usb_open_desc(devc->ftdic, USB_VENDOR_ID, USB_DEVICE_ID,
+				 USB_IPRODUCT, NULL);
+	if (ret < 0) {
+		sr_err("Failed to open device (%d): %s", ret,
+		       ftdi_get_error_string(devc->ftdic));
+		return SR_ERR;
+	}
+	sr_dbg("FTDI device opened successfully.");
+
+	/* Purge RX/TX buffers in the FTDI chip. */
+	if ((ret = ftdi_usb_purge_buffers(devc->ftdic)) < 0) {
+		sr_err("Failed to purge FTDI RX/TX buffers (%d): %s.",
+		       ret, ftdi_get_error_string(devc->ftdic));
+		goto err_dev_open_close_ftdic;
+	}
+	sr_dbg("FTDI chip buffers purged successfully.");
+
+	/* Reset the FTDI bitmode. */
+	ret = ftdi_set_bitmode(devc->ftdic, 0xff, BITMODE_RESET);
+	if (ret < 0) {
+		sr_err("Failed to reset the FTDI chip bitmode (%d): %s.",
+		       ret, ftdi_get_error_string(devc->ftdic));
+		goto err_dev_open_close_ftdic;
+	}
+	sr_dbg("FTDI chip bitmode reset successfully.");
+
+	/* Set FTDI bitmode to "sync FIFO". */
+	ret = ftdi_set_bitmode(devc->ftdic, 0xff, BITMODE_SYNCFF);
+	if (ret < 0) {
+		sr_err("Failed to put FTDI chip into sync FIFO mode (%d): %s.",
+		       ret, ftdi_get_error_string(devc->ftdic));
+		goto err_dev_open_close_ftdic;
+	}
+	sr_dbg("FTDI chip sync FIFO mode entered successfully.");
+
+	/* Set the FTDI latency timer to 2. */
+	ret = ftdi_set_latency_timer(devc->ftdic, 2);
+	if (ret < 0) {
+		sr_err("Failed to set FTDI latency timer (%d): %s.",
+		       ret, ftdi_get_error_string(devc->ftdic));
+		goto err_dev_open_close_ftdic;
+	}
+	sr_dbg("FTDI chip latency timer set successfully.");
+
+	/* Set the FTDI read data chunk size to 64kB. */
+	ret = ftdi_read_data_set_chunksize(devc->ftdic, 64 * 1024);
+	if (ret < 0) {
+		sr_err("Failed to set FTDI read data chunk size (%d): %s.",
+		       ret, ftdi_get_error_string(devc->ftdic));
+		goto err_dev_open_close_ftdic;
+	}
+	sr_dbg("FTDI chip read data chunk size set successfully.");
+
+	/* Get the ScanaPLUS device ID from the FTDI EEPROM. */
+	if ((ret = scanaplus_get_device_id(devc)) < 0) {
+		sr_err("Failed to get ScanaPLUS device ID: %d.", ret);
+		goto err_dev_open_close_ftdic;
+	}
+	sr_dbg("Received ScanaPLUS device ID successfully: %02x %02x %02x.",
+	       devc->devid[0], devc->devid[1], devc->devid[2]);
+
+	sdi->status = SR_ST_ACTIVE;
+
+	return SR_OK;
+
+err_dev_open_close_ftdic:
+	scanaplus_close(devc);
+	return SR_ERR;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+	int ret;
+	struct dev_context *devc;
+
+	ret = SR_OK;
+	devc = sdi->priv;
+
+	if (sdi->status == SR_ST_ACTIVE) {
+		sr_dbg("Status ACTIVE, closing device.");
+		ret = scanaplus_close(devc);
+	} else {
+		sr_spew("Status not ACTIVE, nothing to do.");
+	}
+
+	sdi->status = SR_ST_INACTIVE;
+
+	return ret;
+}
+
+static int cleanup(void)
+{
+	return dev_clear();
+}
+
+static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	(void)sdi;
+	(void)cg;
+
+	switch (id) {
+	case SR_CONF_SAMPLERATE:
+		/* The ScanaPLUS samplerate is 100MHz and can't be changed. */
+		*data = g_variant_new_uint64(SR_MHZ(100));
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+
+	(void)cg;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	devc = sdi->priv;
+
+	switch (id) {
+	case SR_CONF_SAMPLERATE:
+		if (g_variant_get_uint64(data) != SR_MHZ(100)) {
+			sr_err("ScanaPLUS only supports samplerate = 100MHz.");
+			return SR_ERR_ARG;
+		}
+		/* Nothing to do, the ScanaPLUS samplerate is always 100MHz. */
+		break;
+	case SR_CONF_LIMIT_MSEC:
+		if (g_variant_get_uint64(data) == 0)
+			return SR_ERR_ARG;
+		devc->limit_msec = g_variant_get_uint64(data);
+		break;
+	case SR_CONF_LIMIT_SAMPLES:
+		if (g_variant_get_uint64(data) == 0)
+			return SR_ERR_ARG;
+		devc->limit_samples = g_variant_get_uint64(data);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	GVariant *gvar;
+	GVariantBuilder gvb;
+
+	(void)sdi;
+	(void)cg;
+
+	switch (key) {
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+		break;
+	case SR_CONF_SAMPLERATE:
+		g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
+		gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
+				samplerates, ARRAY_SIZE(samplerates),
+				sizeof(uint64_t));
+		g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
+		*data = g_variant_builder_end(&gvb);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+	int ret;
+	struct dev_context *devc;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!(devc = sdi->priv))
+		return SR_ERR_BUG;
+
+	if (!devc->ftdic)
+		return SR_ERR_BUG;
+
+	/* TODO: Configure channels later (thresholds etc.). */
+
+	devc->cb_data = cb_data;
+
+	/* Properly reset internal variables before every new acquisition. */
+	devc->compressed_bytes_ignored = 0;
+	devc->samples_sent = 0;
+	devc->bytes_received = 0;
+
+	if ((ret = scanaplus_init(devc)) < 0)
+		return ret;
+
+	if ((ret = scanaplus_start_acquisition(devc)) < 0)
+		return ret;
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	/* Hook up a dummy handler to receive data from the device. */
+	sr_source_add(-1, G_IO_IN, 0, scanaplus_receive_data, (void *)sdi);
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct sr_datafeed_packet packet;
+
+	(void)sdi;
+
+	sr_dbg("Stopping acquisition.");
+	sr_source_remove(-1);
+
+	/* Send end packet to the session bus. */
+	sr_dbg("Sending SR_DF_END.");
+	packet.type = SR_DF_END;
+	sr_session_send(cb_data, &packet);
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver ikalogic_scanaplus_driver_info = {
+	.name = "ikalogic-scanaplus",
+	.longname = "IKALOGIC ScanaPLUS",
+	.api_version = 1,
+	.init = init,
+	.cleanup = cleanup,
+	.scan = scan,
+	.dev_list = dev_list,
+	.dev_clear = dev_clear,
+	.config_get = config_get,
+	.config_set = config_set,
+	.config_list = config_list,
+	.dev_open = dev_open,
+	.dev_close = dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/ikalogic-scanaplus/protocol.c b/hardware/ikalogic-scanaplus/protocol.c
new file mode 100644
index 0000000..3a834f7
--- /dev/null
+++ b/hardware/ikalogic-scanaplus/protocol.c
@@ -0,0 +1,370 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "protocol.h"
+
+/*
+ * Logic level thresholds.
+ *
+ * For each of the two channel groups (1-4 and 5-9), the logic level
+ * threshold can be set independently.
+ *
+ * The threshold can be set to values that are usable for systems with
+ * different voltage levels, e.g. for 1.8V or 3.3V systems.
+ *
+ * The actual threshold value is always the middle of the values below.
+ * E.g. for a system voltage level of 1.8V, the threshold is at 0.9V. That
+ * means that values <= 0.9V are considered to be a logic 0/low, and
+ * values > 0.9V are considered to be a logic 1/high.
+ *
+ *  - 1.2V system: threshold = 0.6V
+ *  - 1.5V system: threshold = 0.75V
+ *  - 1.8V system: threshold = 0.9V
+ *  - 2.8V system: threshold = 1.4V
+ *  - 3.3V system: threshold = 1.65V
+ */
+#define THRESHOLD_1_2V_SYSTEM 0x2e
+#define THRESHOLD_1_5V_SYSTEM 0x39
+#define THRESHOLD_1_8V_SYSTEM 0x45
+#define THRESHOLD_2_8V_SYSTEM 0x6c
+#define THRESHOLD_3_3V_SYSTEM 0x7f
+
+static int scanaplus_write(struct dev_context *devc, uint8_t *buf, int size)
+{
+	int i, bytes_written;
+	GString *s;
+
+	/* Note: Caller checks devc, devc->ftdic, buf, size. */
+
+	s = g_string_sized_new(100);
+	g_string_printf(s, "Writing %d bytes: ", size);
+	for (i = 0; i < size; i++)
+		g_string_append_printf(s, "0x%02x ", buf[i]);
+	sr_spew("%s", s->str);
+	g_string_free(s, TRUE);
+
+	bytes_written = ftdi_write_data(devc->ftdic, buf, size);
+	if (bytes_written < 0) {
+		sr_err("Failed to write FTDI data (%d): %s.",
+		       bytes_written, ftdi_get_error_string(devc->ftdic));
+	} else if (bytes_written != size) {
+		sr_err("FTDI write error, only %d/%d bytes written: %s.",
+		       bytes_written, size, ftdi_get_error_string(devc->ftdic));
+	}
+
+	return bytes_written;
+}
+
+SR_PRIV int scanaplus_close(struct dev_context *devc)
+{
+	int ret;
+
+	/* Note: Caller checks devc and devc->ftdic. */
+
+	if ((ret = ftdi_usb_close(devc->ftdic)) < 0) {
+		sr_err("Failed to close FTDI device (%d): %s.",
+		       ret, ftdi_get_error_string(devc->ftdic));
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+static void scanaplus_uncompress_block(struct dev_context *devc,
+				       uint64_t num_bytes)
+{
+	uint64_t i, j;
+	uint8_t num_samples, low, high;
+
+	for (i = 0; i < num_bytes; i += 2) {
+		num_samples = devc->compressed_buf[i + 0] >> 1;
+
+		low = devc->compressed_buf[i + 0] & (1 << 0);
+		high = devc->compressed_buf[i + 1];
+
+		for (j = 0; j < num_samples; j++) {
+			devc->sample_buf[devc->bytes_received++] = high;
+			devc->sample_buf[devc->bytes_received++] = low;
+		}
+	}
+}
+
+static void send_samples(struct dev_context *devc, uint64_t samples_to_send)
+{
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_logic logic;
+
+	sr_spew("Sending %" PRIu64 " samples.", samples_to_send);
+
+	packet.type = SR_DF_LOGIC;
+	packet.payload = &logic;
+	logic.length = samples_to_send * 2;
+	logic.unitsize = 2; /* We need 2 bytes for 9 channels. */
+	logic.data = devc->sample_buf;
+	sr_session_send(devc->cb_data, &packet);
+
+	devc->samples_sent += samples_to_send;
+	devc->bytes_received -= samples_to_send * 2;
+}
+
+SR_PRIV int scanaplus_get_device_id(struct dev_context *devc)
+{
+	int ret;
+	uint16_t val1, val2;
+
+	/* FTDI EEPROM indices 16+17 contain the 3 device ID bytes. */
+	if ((ret = ftdi_read_eeprom_location(devc->ftdic, 16, &val1)) < 0) {
+		sr_err("Failed to read EEPROM index 16 (%d): %s.",
+		       ret, ftdi_get_error_string(devc->ftdic));
+		return SR_ERR;
+	}
+	if ((ret = ftdi_read_eeprom_location(devc->ftdic, 17, &val2)) < 0) {
+		sr_err("Failed to read EEPROM index 17 (%d): %s.",
+		       ret, ftdi_get_error_string(devc->ftdic));
+		return SR_ERR;
+	}
+
+	/*
+	 * Note: Bit 7 of the three bytes must not be used, apparently.
+	 *
+	 * Even though the three bits can be either 0 or 1 (we've seen both
+	 * in actual ScanaPLUS devices), the device ID as sent to the FPGA
+	 * has bit 7 of each byte zero'd out.
+	 *
+	 * It is unknown whether bit 7 of these bytes has any meaning,
+	 * whether it's used somewhere, or whether it can be simply ignored.
+	 */
+	devc->devid[0] = ((val1 >> 0) & 0xff) & ~(1 << 7);
+	devc->devid[1] = ((val1 >> 8) & 0xff) & ~(1 << 7);
+	devc->devid[2] = ((val2 >> 0) & 0xff) & ~(1 << 7);
+
+	return SR_OK;
+}
+
+static int scanaplus_clear_device_id(struct dev_context *devc)
+{
+	uint8_t buf[2];
+
+	buf[0] = 0x8c;
+	buf[1] = 0x00;
+	if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
+		return SR_ERR;
+
+	buf[0] = 0x8e;
+	buf[1] = 0x00;
+	if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
+		return SR_ERR;
+
+	buf[0] = 0x8f;
+	buf[1] = 0x00;
+	if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
+		return SR_ERR;
+
+	return SR_OK;
+}
+
+static int scanaplus_send_device_id(struct dev_context *devc)
+{
+	uint8_t buf[2];
+
+	buf[0] = 0x8c;
+	buf[1] = devc->devid[0];
+	if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
+		return SR_ERR;
+
+	buf[0] = 0x8e;
+	buf[1] = devc->devid[1];
+	if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
+		return SR_ERR;
+
+	buf[0] = 0x8f;
+	buf[1] = devc->devid[2];
+	if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
+		return SR_ERR;
+
+	return SR_OK;
+}
+
+SR_PRIV int scanaplus_init(struct dev_context *devc)
+{
+	int i;
+	uint8_t buf[8];
+
+	buf[0] = 0x88;
+	buf[1] = 0x41;
+	if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
+		return SR_ERR;
+
+	buf[0] = 0x89;
+	buf[1] = 0x64;
+	buf[2] = 0x8a;
+	buf[3] = 0x64;
+	if (scanaplus_write(devc, (uint8_t *)&buf, 4) < 0)
+		return SR_ERR;
+
+	buf[0] = 0x88;
+	buf[1] = 0x41;
+	if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
+		return SR_ERR;
+
+	buf[0] = 0x88;
+	buf[1] = 0x40;
+	if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
+		return SR_ERR;
+
+	buf[0] = 0x8d;
+	buf[1] = 0x01;
+	buf[2] = 0x8d;
+	buf[3] = 0x05;
+	buf[4] = 0x8d;
+	buf[5] = 0x01;
+	buf[6] = 0x8d;
+	buf[7] = 0x02;
+	if (scanaplus_write(devc, (uint8_t *)&buf, 8) < 0)
+		return SR_ERR;
+
+	for (i = 0; i < 57; i++) {
+		buf[0] = 0x8d;
+		buf[1] = 0x06;
+		if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
+			return SR_ERR;
+
+		buf[0] = 0x8d;
+		buf[1] = 0x02;
+		if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
+			return SR_ERR;
+	}
+
+	if (scanaplus_send_device_id(devc) < 0)
+		return SR_ERR;
+
+	buf[0] = 0x88;
+	buf[1] = 0x40;
+	if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
+		return SR_ERR;
+
+	return SR_OK;
+}
+
+SR_PRIV int scanaplus_start_acquisition(struct dev_context *devc)
+{
+	uint8_t buf[4];
+
+	/* Threshold and differential channel settings not yet implemented. */
+
+	buf[0] = 0x89;
+	buf[1] = 0x7f; /* Logic level threshold for channels 1-4. */
+	buf[2] = 0x8a;
+	buf[3] = 0x7f; /* Logic level threshold for channels 5-9. */
+	if (scanaplus_write(devc, (uint8_t *)&buf, 4) < 0)
+		return SR_ERR;
+
+	buf[0] = 0x88;
+	buf[1] = 0x40; /* Special config of channels 5/6 and 7/8. */
+	/* 0x40: normal, 0x50: ch56 diff, 0x48: ch78 diff, 0x58: ch5678 diff */
+	if (scanaplus_write(devc, (uint8_t *)&buf, 2) < 0)
+		return SR_ERR;
+
+	if (scanaplus_clear_device_id(devc) < 0)
+		return SR_ERR;
+
+	if (scanaplus_send_device_id(devc) < 0)
+		return SR_ERR;
+
+	return SR_OK;
+}
+
+SR_PRIV int scanaplus_receive_data(int fd, int revents, void *cb_data)
+{
+	int bytes_read;
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+	uint64_t max, n;
+
+	(void)fd;
+	(void)revents;
+
+	if (!(sdi = cb_data))
+		return TRUE;
+
+	if (!(devc = sdi->priv))
+		return TRUE;
+
+	if (!devc->ftdic)
+		return TRUE;
+
+	/* Get a block of data. */
+	bytes_read = ftdi_read_data(devc->ftdic, devc->compressed_buf,
+				    COMPRESSED_BUF_SIZE);
+	if (bytes_read < 0) {
+		sr_err("Failed to read FTDI data (%d): %s.",
+		       bytes_read, ftdi_get_error_string(devc->ftdic));
+		sdi->driver->dev_acquisition_stop(sdi, sdi);
+		return FALSE;
+	}
+	if (bytes_read == 0) {
+		sr_spew("Received 0 bytes, nothing to do.");
+		return TRUE;
+	}
+
+	/*
+	 * After a ScanaPLUS acquisition starts, a bunch of samples will be
+	 * returned as all-zero, no matter which signals are actually present
+	 * on the channels. This is probably due to the FPGA reconfiguring some
+	 * of its internal state/config during this time.
+	 *
+	 * As far as we know there is apparently no way for the PC-side to
+	 * know when this "reconfiguration" starts or ends. The FTDI chip
+	 * will return all-zero "dummy" samples during this time, which is
+	 * indistinguishable from actual all-zero samples.
+	 *
+	 * We currently simply ignore the first 64kB of data after an
+	 * acquisition starts. Empirical tests have shown that the
+	 * "reconfigure" time is a lot less than that usually.
+	 */
+	if (devc->compressed_bytes_ignored < COMPRESSED_BUF_SIZE) {
+		/* Ignore the first 64kB of data of every acquisition. */
+		sr_spew("Ignoring first 64kB chunk of data.");
+		devc->compressed_bytes_ignored += COMPRESSED_BUF_SIZE;
+		return TRUE;
+	}
+
+	/* TODO: Handle bytes_read which is not a multiple of 2? */
+	scanaplus_uncompress_block(devc, bytes_read);
+
+	n = devc->samples_sent + (devc->bytes_received / 2);
+	max = (SR_MHZ(100) / 1000) * devc->limit_msec;
+
+	if (devc->limit_samples && (n >= devc->limit_samples)) {
+		send_samples(devc, devc->limit_samples - devc->samples_sent);
+		sr_info("Requested number of samples reached.");
+		sdi->driver->dev_acquisition_stop(sdi, cb_data);
+		return TRUE;
+	} else if (devc->limit_msec && (n >= max)) {
+		send_samples(devc, max - devc->samples_sent);
+		sr_info("Requested time limit reached.");
+		sdi->driver->dev_acquisition_stop(sdi, cb_data);
+		return TRUE;
+	} else {
+		send_samples(devc, devc->bytes_received / 2);
+	}
+
+	return TRUE;
+}
diff --git a/hardware/ikalogic-scanaplus/protocol.h b/hardware/ikalogic-scanaplus/protocol.h
new file mode 100644
index 0000000..1df0517
--- /dev/null
+++ b/hardware/ikalogic-scanaplus/protocol.h
@@ -0,0 +1,64 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef LIBSIGROK_HARDWARE_IKALOGIC_SCANAPLUS_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_IKALOGIC_SCANAPLUS_PROTOCOL_H
+
+#include <stdint.h>
+#include <string.h>
+#include <glib.h>
+#include <ftdi.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "ikalogic-scanaplus"
+
+#define COMPRESSED_BUF_SIZE		(64 * 1024)
+
+/* Private, per-device-instance driver context. */
+struct dev_context {
+	/** FTDI device context (used by libftdi). */
+	struct ftdi_context *ftdic;
+
+	/** The current sampling limit (in ms). */
+	uint64_t limit_msec;
+
+	/** The current sampling limit (in number of samples). */
+	uint64_t limit_samples;
+
+	void *cb_data;
+
+	uint8_t *compressed_buf;
+	uint64_t compressed_bytes_ignored;
+	uint8_t *sample_buf;
+	uint64_t bytes_received;
+	uint64_t samples_sent;
+
+	/** ScanaPLUS unique device ID (3 bytes). */
+	uint8_t devid[3];
+};
+
+SR_PRIV int scanaplus_close(struct dev_context *devc);
+SR_PRIV int scanaplus_get_device_id(struct dev_context *devc);
+SR_PRIV int scanaplus_init(struct dev_context *devc);
+SR_PRIV int scanaplus_start_acquisition(struct dev_context *devc);
+SR_PRIV int scanaplus_receive_data(int fd, int revents, void *cb_data);
+
+#endif
diff --git a/hardware/kecheng-kc-330b/api.c b/hardware/kecheng-kc-330b/api.c
new file mode 100644
index 0000000..57dafdf
--- /dev/null
+++ b/hardware/kecheng-kc-330b/api.c
@@ -0,0 +1,575 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include "protocol.h"
+
+#define USB_CONN "1041.8101"
+#define VENDOR "Kecheng"
+#define USB_INTERFACE 0
+
+static const int32_t hwcaps[] = {
+	SR_CONF_SOUNDLEVELMETER,
+	SR_CONF_LIMIT_SAMPLES,
+	SR_CONF_CONTINUOUS,
+	SR_CONF_DATALOG,
+	SR_CONF_SPL_WEIGHT_FREQ,
+	SR_CONF_SPL_WEIGHT_TIME,
+	SR_CONF_DATA_SOURCE,
+};
+
+SR_PRIV const uint64_t kecheng_kc_330b_sample_intervals[][2] = {
+	{ 1, 8 },
+	{ 1, 2 },
+	{ 1, 1 },
+	{ 2, 1 },
+	{ 5, 1 },
+	{ 10, 1 },
+	{ 60, 1 },
+};
+
+static const char *weight_freq[] = {
+	"A",
+	"C",
+};
+
+static const char *weight_time[] = {
+	"F",
+	"S",
+};
+
+static const char *data_sources[] = {
+	"Live",
+	"Memory",
+};
+
+SR_PRIV struct sr_dev_driver kecheng_kc_330b_driver_info;
+static struct sr_dev_driver *di = &kecheng_kc_330b_driver_info;
+
+
+static int init(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static int scan_kecheng(struct sr_usb_dev_inst *usb, char **model)
+{
+	struct drv_context *drvc;
+	int len, ret;
+	unsigned char cmd, buf[32];
+
+	drvc = di->priv;
+	if (sr_usb_open(drvc->sr_ctx->libusb_ctx, usb) != SR_OK)
+		return SR_ERR;
+
+	cmd = CMD_IDENTIFY;
+	ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, &cmd, 1, &len, 5);
+	if (ret != 0) {
+		libusb_close(usb->devhdl);
+		sr_dbg("Failed to send Identify command: %s", libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	ret = libusb_bulk_transfer(usb->devhdl, EP_IN, buf, 32, &len, 10);
+	if (ret != 0) {
+		libusb_close(usb->devhdl);
+		sr_dbg("Failed to receive response: %s", libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	libusb_close(usb->devhdl);
+	usb->devhdl = NULL;
+
+	if (len < 2 || buf[0] != (CMD_IDENTIFY | 0x80) || buf[1] > 30) {
+		sr_dbg("Invalid response to Identify command");
+		return SR_ERR;
+	}
+
+	buf[buf[1] + 2] = '\x0';
+	*model = g_strndup((const gchar *)buf + 2, 30);
+
+	return SR_OK;
+}
+
+static GSList *scan(GSList *options)
+{
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_dev_inst *sdi;
+	struct sr_channel *ch;
+	GSList *usb_devices, *devices, *l;
+	char *model;
+
+	(void)options;
+
+	drvc = di->priv;
+	drvc->instances = NULL;
+
+	devices = NULL;
+	if ((usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, USB_CONN))) {
+		/* We have a list of sr_usb_dev_inst matching the connection
+		 * string. Wrap them in sr_dev_inst and we're done. */
+		for (l = usb_devices; l; l = l->next) {
+			if (scan_kecheng(l->data, &model) != SR_OK)
+				continue;
+			if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, VENDOR,
+					model, NULL)))
+				return NULL;
+			g_free(model);
+			sdi->driver = di;
+			sdi->inst_type = SR_INST_USB;
+			sdi->conn = l->data;
+			if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "SPL")))
+				return NULL;
+			sdi->channels = g_slist_append(sdi->channels, ch);
+
+			if (!(devc = g_try_malloc(sizeof(struct dev_context)))) {
+				sr_dbg("Device context malloc failed.");
+				return NULL;
+			}
+			sdi->priv = devc;
+			devc->limit_samples = 0;
+			/* The protocol provides no way to read the current
+			 * settings, so we'll enforce these. */
+			devc->sample_interval = DEFAULT_SAMPLE_INTERVAL;
+			devc->alarm_low = DEFAULT_ALARM_LOW;
+			devc->alarm_high = DEFAULT_ALARM_HIGH;
+			devc->mqflags = DEFAULT_WEIGHT_TIME | DEFAULT_WEIGHT_FREQ;
+			devc->data_source = DEFAULT_DATA_SOURCE;
+			devc->config_dirty = FALSE;
+
+			/* TODO: Set date/time? */
+
+			drvc->instances = g_slist_append(drvc->instances, sdi);
+			devices = g_slist_append(devices, sdi);
+		}
+		g_slist_free(usb_devices);
+	} else
+		g_slist_free_full(usb_devices, g_free);
+
+	return devices;
+}
+
+static GSList *dev_list(void)
+{
+	return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+	struct drv_context *drvc;
+	struct sr_usb_dev_inst *usb;
+	int ret;
+
+	if (!(drvc = di->priv)) {
+		sr_err("Driver was not initialized.");
+		return SR_ERR;
+	}
+
+	usb = sdi->conn;
+
+	if (sr_usb_open(drvc->sr_ctx->libusb_ctx, usb) != SR_OK)
+		return SR_ERR;
+
+	if ((ret = libusb_set_configuration(usb->devhdl, 1))) {
+		sr_err("Failed to set configuration: %s.", libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	if ((ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE))) {
+		sr_err("Failed to claim interface: %s.", libusb_error_name(ret));
+		return SR_ERR;
+	}
+	sdi->status = SR_ST_ACTIVE;
+
+	return ret;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_usb_dev_inst *usb;
+
+	if (!di->priv) {
+		sr_err("Driver was not initialized.");
+		return SR_ERR;
+	}
+
+	usb = sdi->conn;
+
+	if (!usb->devhdl)
+		/*  Nothing to do. */
+		return SR_OK;
+
+	/* This allows a frontend to configure the device without ever
+	 * doing an acquisition step. */
+	devc = sdi->priv;
+	if (!devc->config_dirty)
+		kecheng_kc_330b_configure(sdi);
+
+	libusb_release_interface(usb->devhdl, USB_INTERFACE);
+	libusb_close(usb->devhdl);
+	usb->devhdl = NULL;
+	sdi->status = SR_ST_INACTIVE;
+
+	return SR_OK;
+}
+
+static int cleanup(void)
+{
+	int ret;
+	struct drv_context *drvc;
+
+	if (!(drvc = di->priv))
+		/* Can get called on an unused driver, doesn't matter. */
+		return SR_OK;
+
+
+	ret = std_dev_clear(di, NULL);
+	g_free(drvc);
+	di->priv = NULL;
+
+	return ret;
+}
+
+static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	GVariant *rational[2];
+	const uint64_t *si;
+
+	(void)cg;
+
+	devc = sdi->priv;
+	switch (key) {
+	case SR_CONF_LIMIT_SAMPLES:
+		*data = g_variant_new_uint64(devc->limit_samples);
+		break;
+	case SR_CONF_SAMPLE_INTERVAL:
+		si = kecheng_kc_330b_sample_intervals[devc->sample_interval];
+		rational[0] = g_variant_new_uint64(si[0]);
+		rational[1] = g_variant_new_uint64(si[1]);
+		*data = g_variant_new_tuple(rational, 2);
+		break;
+	case SR_CONF_DATALOG:
+		/* There really isn't a way to be sure the device is logging. */
+		return SR_ERR_NA;
+		break;
+	case SR_CONF_SPL_WEIGHT_FREQ:
+		if (devc->mqflags & SR_MQFLAG_SPL_FREQ_WEIGHT_A)
+			*data = g_variant_new_string("A");
+		else
+			*data = g_variant_new_string("C");
+		break;
+	case SR_CONF_SPL_WEIGHT_TIME:
+		if (devc->mqflags & SR_MQFLAG_SPL_TIME_WEIGHT_F)
+			*data = g_variant_new_string("F");
+		else
+			*data = g_variant_new_string("S");
+		break;
+	case SR_CONF_DATA_SOURCE:
+		if (devc->data_source == DATA_SOURCE_LIVE)
+			*data = g_variant_new_string("Live");
+		else
+			*data = g_variant_new_string("Memory");
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	uint64_t p, q;
+	unsigned int i;
+	int tmp, ret;
+	const char *tmp_str;
+
+	(void)cg;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!di->priv) {
+		sr_err("Driver was not initialized.");
+		return SR_ERR;
+	}
+
+	devc = sdi->priv;
+	ret = SR_OK;
+	switch (key) {
+	case SR_CONF_LIMIT_SAMPLES:
+		devc->limit_samples = g_variant_get_uint64(data);
+		sr_dbg("Setting sample limit to %" PRIu64 ".",
+		       devc->limit_samples);
+		break;
+	case SR_CONF_SAMPLE_INTERVAL:
+		g_variant_get(data, "(tt)", &p, &q);
+		for (i = 0; i < ARRAY_SIZE(kecheng_kc_330b_sample_intervals); i++) {
+			if (kecheng_kc_330b_sample_intervals[i][0] != p || kecheng_kc_330b_sample_intervals[i][1] != q)
+				continue;
+			devc->sample_interval = i;
+			devc->config_dirty = TRUE;
+			break;
+		}
+		if (i == ARRAY_SIZE(kecheng_kc_330b_sample_intervals))
+			ret = SR_ERR_ARG;
+		break;
+	case SR_CONF_SPL_WEIGHT_FREQ:
+		tmp_str = g_variant_get_string(data, NULL);
+		if (!strcmp(tmp_str, "A"))
+			tmp = SR_MQFLAG_SPL_FREQ_WEIGHT_A;
+		else if (!strcmp(tmp_str, "C"))
+			tmp = SR_MQFLAG_SPL_FREQ_WEIGHT_C;
+		else
+			return SR_ERR_ARG;
+		devc->mqflags &= ~(SR_MQFLAG_SPL_FREQ_WEIGHT_A | SR_MQFLAG_SPL_FREQ_WEIGHT_C);
+		devc->mqflags |= tmp;
+		devc->config_dirty = TRUE;
+		break;
+	case SR_CONF_SPL_WEIGHT_TIME:
+		tmp_str = g_variant_get_string(data, NULL);
+		if (!strcmp(tmp_str, "F"))
+			tmp = SR_MQFLAG_SPL_TIME_WEIGHT_F;
+		else if (!strcmp(tmp_str, "S"))
+			tmp = SR_MQFLAG_SPL_TIME_WEIGHT_S;
+		else
+			return SR_ERR_ARG;
+		devc->mqflags &= ~(SR_MQFLAG_SPL_TIME_WEIGHT_F | SR_MQFLAG_SPL_TIME_WEIGHT_S);
+		devc->mqflags |= tmp;
+		devc->config_dirty = TRUE;
+		break;
+	case SR_CONF_DATA_SOURCE:
+		tmp_str = g_variant_get_string(data, NULL);
+		if (!strcmp(tmp_str, "Live"))
+			devc->data_source = DATA_SOURCE_LIVE;
+		else if (!strcmp(tmp_str, "Memory"))
+			devc->data_source = DATA_SOURCE_MEMORY;
+		else
+			return SR_ERR;
+		devc->config_dirty = TRUE;
+		break;
+	default:
+		ret = SR_ERR_NA;
+	}
+
+	return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	GVariant *tuple, *rational[2];
+	GVariantBuilder gvb;
+	unsigned int i;
+
+	(void)sdi;
+	(void)cg;
+
+	switch (key) {
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+		break;
+	case SR_CONF_SAMPLE_INTERVAL:
+		g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
+		for (i = 0; i < ARRAY_SIZE(kecheng_kc_330b_sample_intervals); i++) {
+			rational[0] = g_variant_new_uint64(kecheng_kc_330b_sample_intervals[i][0]);
+			rational[1] = g_variant_new_uint64(kecheng_kc_330b_sample_intervals[i][1]);
+			tuple = g_variant_new_tuple(rational, 2);
+			g_variant_builder_add_value(&gvb, tuple);
+		}
+		*data = g_variant_builder_end(&gvb);
+		break;
+	case SR_CONF_SPL_WEIGHT_FREQ:
+		*data = g_variant_new_strv(weight_freq, ARRAY_SIZE(weight_freq));
+		break;
+	case SR_CONF_SPL_WEIGHT_TIME:
+		*data = g_variant_new_strv(weight_time, ARRAY_SIZE(weight_time));
+		break;
+	case SR_CONF_DATA_SOURCE:
+		*data = g_variant_new_strv(data_sources, ARRAY_SIZE(data_sources));
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi,
+		void *cb_data)
+{
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_meta meta;
+	struct sr_config *src;
+	struct sr_usb_dev_inst *usb;
+	GVariant *gvar, *rational[2];
+	const uint64_t *si;
+	int stored_mqflags, req_len, buf_len, len, ret;
+	unsigned char buf[9];
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	drvc = di->priv;
+	devc = sdi->priv;
+	usb = sdi->conn;
+
+	devc->cb_data = cb_data;
+	devc->num_samples = 0;
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	if (devc->data_source == DATA_SOURCE_LIVE) {
+		/* Force configuration. */
+		kecheng_kc_330b_configure(sdi);
+
+		if (kecheng_kc_330b_status_get(sdi, &ret) != SR_OK)
+			return SR_ERR;
+		if (ret != DEVICE_ACTIVE) {
+			sr_err("Device is inactive");
+			/* Still continue though, since the device will
+			 * just return 30.0 until the user hits the button
+			 * on the device -- and then start feeding good
+			 * samples back. */
+		}
+	} else {
+		if (kecheng_kc_330b_log_info_get(sdi, buf) != SR_OK)
+			return SR_ERR;
+		stored_mqflags = buf[4] ? SR_MQFLAG_SPL_TIME_WEIGHT_S : SR_MQFLAG_SPL_TIME_WEIGHT_F;
+		stored_mqflags |= buf[5] ? SR_MQFLAG_SPL_FREQ_WEIGHT_C : SR_MQFLAG_SPL_FREQ_WEIGHT_A;
+		devc->stored_samples = (buf[7] << 8) | buf[8];
+		if (devc->stored_samples == 0) {
+			/* Notify frontend of empty log by sending start/end packets. */
+			packet.type = SR_DF_END;
+			sr_session_send(cb_data, &packet);
+			return SR_OK;
+		}
+
+		if (devc->limit_samples && devc->limit_samples < devc->stored_samples)
+			devc->stored_samples = devc->limit_samples;
+
+		si = kecheng_kc_330b_sample_intervals[buf[1]];
+		rational[0] = g_variant_new_uint64(si[0]);
+		rational[1] = g_variant_new_uint64(si[1]);
+		gvar = g_variant_new_tuple(rational, 2);
+		src = sr_config_new(SR_CONF_SAMPLE_INTERVAL, gvar);
+		packet.type = SR_DF_META;
+		packet.payload = &meta;
+		meta.config = g_slist_append(NULL, src);
+		sr_session_send(devc->cb_data, &packet);
+		g_free(src);
+	}
+
+	if (!(devc->xfer = libusb_alloc_transfer(0)))
+		return SR_ERR;
+
+	usb_source_add(drvc->sr_ctx, 10,
+		kecheng_kc_330b_handle_events, (void *)sdi);
+
+	if (devc->data_source == DATA_SOURCE_LIVE) {
+		buf[0] = CMD_GET_LIVE_SPL;
+		buf_len = 1;
+		devc->state = LIVE_SPL_WAIT;
+		devc->last_live_request = g_get_monotonic_time() / 1000;
+		req_len = 3;
+	} else {
+		buf[0] = CMD_GET_LOG_DATA;
+		buf[1] = 0;
+		buf[2] = 0;
+		buf_len = 4;
+		devc->state = LOG_DATA_WAIT;
+		if (devc->stored_samples < 63)
+			buf[3] = devc->stored_samples;
+		else
+			buf[3] = 63;
+		/* Command ack byte + 2 bytes per sample. */
+		req_len = 1 + buf[3] * 2;
+	}
+
+	ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, buf, buf_len, &len, 5);
+	if (ret != 0 || len != 1) {
+		sr_dbg("Failed to start acquisition: %s", libusb_error_name(ret));
+		libusb_free_transfer(devc->xfer);
+		return SR_ERR;
+	}
+
+	libusb_fill_bulk_transfer(devc->xfer, usb->devhdl, EP_IN, devc->buf,
+			req_len, kecheng_kc_330b_receive_transfer, (void *)sdi, 15);
+	if (libusb_submit_transfer(devc->xfer) != 0) {
+		libusb_free_transfer(devc->xfer);
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct dev_context *devc;
+
+	(void)cb_data;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	/* Signal USB transfer handler to clean up and stop. */
+	sdi->status = SR_ST_STOPPING;
+
+	devc = sdi->priv;
+	if (devc->data_source == DATA_SOURCE_MEMORY && devc->config_dirty) {
+		/* The protocol doesn't have a command to clear stored data;
+		 * it clears it whenever new configuration is set. That means
+		 * we can't just configure the device any time we want when
+		 * it's in DATA_SOURCE_MEMORY mode. The only safe time to do
+		 * it is now, when we're sure we've pulled in all the stored
+		 * data. */
+		kecheng_kc_330b_configure(sdi);
+	}
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver kecheng_kc_330b_driver_info = {
+	.name = "kecheng-kc-330b",
+	.longname = "Kecheng KC-330B",
+	.api_version = 1,
+	.init = init,
+	.cleanup = cleanup,
+	.scan = scan,
+	.dev_list = dev_list,
+	.dev_clear = NULL,
+	.config_get = config_get,
+	.config_set = config_set,
+	.config_list = config_list,
+	.dev_open = dev_open,
+	.dev_close = dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/kecheng-kc-330b/protocol.c b/hardware/kecheng-kc-330b/protocol.c
new file mode 100644
index 0000000..072eb7e
--- /dev/null
+++ b/hardware/kecheng-kc-330b/protocol.c
@@ -0,0 +1,338 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include "protocol.h"
+
+extern struct sr_dev_driver kecheng_kc_330b_driver_info;
+static struct sr_dev_driver *di = &kecheng_kc_330b_driver_info;
+extern const uint64_t kecheng_kc_330b_sample_intervals[][2];
+
+SR_PRIV int kecheng_kc_330b_handle_events(int fd, int revents, void *cb_data)
+{
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_datafeed_packet packet;
+	struct sr_dev_inst *sdi;
+	struct sr_usb_dev_inst *usb;
+	struct timeval tv;
+	const uint64_t *intv_entry;
+	gint64 now, interval;
+	int offset, len, ret;
+	unsigned char buf[4];
+
+	(void)fd;
+	(void)revents;
+
+	drvc = di->priv;
+	sdi = cb_data;
+	devc = sdi->priv;
+	usb = sdi->conn;
+
+	memset(&tv, 0, sizeof(struct timeval));
+	libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx, &tv,
+					       NULL);
+
+	if (sdi->status == SR_ST_STOPPING) {
+		libusb_free_transfer(devc->xfer);
+		usb_source_remove(drvc->sr_ctx);
+		packet.type = SR_DF_END;
+		sr_session_send(cb_data, &packet);
+		sdi->status = SR_ST_ACTIVE;
+		return TRUE;
+	}
+
+	if (devc->state == LIVE_SPL_IDLE) {
+		/* Request samples at the interval rate. */
+		now = g_get_monotonic_time() / 1000;
+		intv_entry = kecheng_kc_330b_sample_intervals[devc->sample_interval];
+		interval = intv_entry[0] * 1000 / intv_entry[1];
+		if (now - devc->last_live_request > interval) {
+			buf[0] = CMD_GET_LIVE_SPL;
+			ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, buf, 1, &len, 5);
+			if (ret != 0 || len != 1) {
+				sr_dbg("Failed to request new acquisition: %s",
+						libusb_error_name(ret));
+				sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi,
+						devc->cb_data);
+				return TRUE;
+			}
+			libusb_submit_transfer(devc->xfer);
+			devc->last_live_request = now;
+			devc->state = LIVE_SPL_WAIT;
+		}
+	} else if (devc->state == LIVE_SPL_IDLE) {
+		buf[0] = CMD_GET_LOG_DATA;
+		offset = devc->num_samples / 63;
+		buf[1] = (offset >> 8) & 0xff;
+		buf[2] = offset & 0xff;
+		if (devc->stored_samples - devc->num_samples > 63)
+			buf[3] = 63;
+		else
+			/* Last chunk. */
+			buf[3] = devc->stored_samples - devc->num_samples;
+		ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, buf, 4, &len, 5);
+		if (ret != 0 || len != 4) {
+			sr_dbg("Failed to request next chunk: %s",
+					libusb_error_name(ret));
+			sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi,
+					devc->cb_data);
+			return TRUE;
+		}
+		libusb_submit_transfer(devc->xfer);
+		devc->state = LIVE_SPL_WAIT;
+	}
+
+	return TRUE;
+}
+
+static void send_data(const struct sr_dev_inst *sdi, void *buf, unsigned int buf_len)
+{
+	struct dev_context *devc;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_analog analog;
+
+	devc = sdi->priv;
+
+	memset(&analog, 0, sizeof(struct sr_datafeed_analog));
+	analog.mq = SR_MQ_SOUND_PRESSURE_LEVEL;
+	analog.mqflags = devc->mqflags;
+	analog.unit = SR_UNIT_DECIBEL_SPL;
+	analog.channels = sdi->channels;
+	analog.num_samples = buf_len;
+	analog.data = buf;
+	packet.type = SR_DF_ANALOG;
+	packet.payload = &analog;
+	sr_session_send(devc->cb_data, &packet);
+
+}
+
+SR_PRIV void kecheng_kc_330b_receive_transfer(struct libusb_transfer *transfer)
+{
+	struct dev_context *devc;
+	struct sr_dev_inst *sdi;
+	float fvalue[64];
+	int packet_has_error, num_samples, i;
+
+	sdi = transfer->user_data;
+	devc = sdi->priv;
+
+	packet_has_error = FALSE;
+	switch (transfer->status) {
+	case LIBUSB_TRANSFER_NO_DEVICE:
+		/* USB device was unplugged. */
+		sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi,
+				devc->cb_data);
+		return;
+	case LIBUSB_TRANSFER_COMPLETED:
+	case LIBUSB_TRANSFER_TIMED_OUT: /* We may have received some data though */
+		break;
+	default:
+		packet_has_error = TRUE;
+		break;
+	}
+
+	if (packet_has_error)
+		return;
+
+	if (devc->state == LIVE_SPL_WAIT) {
+		if (transfer->actual_length != 3 || transfer->buffer[0] != 0x88) {
+			sr_dbg("Received invalid SPL packet.");
+		} else {
+			fvalue[0] = ((transfer->buffer[1] << 8) + transfer->buffer[2]) / 10.0;
+			send_data(sdi, fvalue, 1);
+			devc->num_samples++;
+			if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
+				sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi,
+						devc->cb_data);
+			} else {
+				/* let USB event handler fire off another
+				 * request when the time is right. */
+				devc->state = LIVE_SPL_IDLE;
+			}
+		}
+	} else if (devc->state == LOG_DATA_WAIT) {
+		if (transfer->actual_length < 1 || !(transfer->actual_length & 0x01)) {
+			sr_dbg("Received invalid stored SPL packet.");
+		} else {
+			num_samples = (transfer->actual_length - 1) / 2;
+			for (i = 0; i < num_samples; i++) {
+				fvalue[i] = transfer->buffer[1 + i * 2] << 8;
+				fvalue[i] += transfer->buffer[1 + i * 2 + 1];
+				fvalue[i] /= 10.0;
+			}
+			send_data(sdi, fvalue, 1);
+			devc->num_samples += num_samples;
+			if (devc->num_samples >= devc->stored_samples) {
+				sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi,
+						devc->cb_data);
+			} else {
+				/* let USB event handler fire off another
+				 * request when the time is right. */
+				devc->state = LOG_DATA_IDLE;
+			}
+		}
+	}
+
+}
+
+SR_PRIV int kecheng_kc_330b_configure(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_usb_dev_inst *usb;
+	int len, ret;
+	unsigned char buf[7];
+
+	sr_dbg("Configuring device.");
+
+	usb = sdi->conn;
+	devc = sdi->priv;
+
+	buf[0] = CMD_CONFIGURE;
+	buf[1] = devc->sample_interval;
+	buf[2] = devc->alarm_low;
+	buf[3] = devc->alarm_high;
+	buf[4] = devc->mqflags & SR_MQFLAG_SPL_TIME_WEIGHT_F ? 0 : 1;
+	buf[5] = devc->mqflags & SR_MQFLAG_SPL_FREQ_WEIGHT_A ? 0 : 1;
+	buf[6] = devc->data_source;
+	ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, buf, 7, &len, 5);
+	if (ret != 0 || len != 7) {
+		sr_dbg("Failed to configure device: %s", libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	/* The configure command ack takes about 32ms to come in. */
+	ret = libusb_bulk_transfer(usb->devhdl, EP_IN, buf, 1, &len, 40);
+	if (ret != 0 || len != 1) {
+		sr_dbg("Failed to configure device (no ack): %s", libusb_error_name(ret));
+		return SR_ERR;
+	}
+	if (buf[0] != (CMD_CONFIGURE | 0x80)) {
+		sr_dbg("Failed to configure device: invalid response 0x%2.x", buf[0]);
+		return SR_ERR;
+	}
+
+	devc->config_dirty = FALSE;
+
+	return SR_OK;
+}
+
+SR_PRIV int kecheng_kc_330b_set_date_time(struct sr_dev_inst *sdi)
+{
+	struct sr_usb_dev_inst *usb;
+	GDateTime *dt;
+	int len, ret;
+	unsigned char buf[7];
+
+	sr_dbg("Setting device date/time.");
+
+	usb = sdi->conn;
+
+	dt = g_date_time_new_now_local();
+	buf[0] = CMD_SET_DATE_TIME;
+	buf[1] = g_date_time_get_year(dt) - 2000;
+	buf[2] = g_date_time_get_month(dt);
+	buf[3] = g_date_time_get_day_of_month(dt);
+	buf[4] = g_date_time_get_hour(dt);
+	buf[5] = g_date_time_get_minute(dt);
+	buf[6] = g_date_time_get_second(dt);
+	g_date_time_unref(dt);
+	ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, buf, 7, &len, 5);
+	if (ret != 0 || len != 7) {
+		sr_dbg("Failed to set date/time: %s", libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	ret = libusb_bulk_transfer(usb->devhdl, EP_IN, buf, 1, &len, 10);
+	if (ret != 0 || len != 1) {
+		sr_dbg("Failed to set date/time (no ack): %s", libusb_error_name(ret));
+		return SR_ERR;
+	}
+	if (buf[0] != (CMD_SET_DATE_TIME | 0x80)) {
+		sr_dbg("Failed to set date/time: invalid response 0x%2.x", buf[0]);
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+SR_PRIV int kecheng_kc_330b_status_get(const struct sr_dev_inst *sdi,
+		int *status)
+{
+	struct sr_usb_dev_inst *usb;
+	int len, ret;
+	unsigned char buf;
+
+	sr_dbg("Getting device status.");
+
+	usb = sdi->conn;
+	buf = CMD_GET_STATUS;
+	ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, &buf, 1, &len, 5);
+	if (ret != 0 || len != 1) {
+		sr_dbg("Failed to get status: %s", libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	ret = libusb_bulk_transfer(usb->devhdl, EP_IN, &buf, 1, &len, 10);
+	if (ret != 0 || len != 1) {
+		sr_dbg("Failed to get status (no ack): %s", libusb_error_name(ret));
+		return SR_ERR;
+	}
+	/* Need either 0x84 or 0xa4. */
+	if (buf != (CMD_GET_STATUS | 0x80) && buf != (CMD_GET_STATUS | 0xa0)) {
+		sr_dbg("Failed to get status: invalid response 0x%2.x", buf);
+		return SR_ERR;
+	}
+
+	if (buf & 0x20)
+		*status = DEVICE_INACTIVE;
+	else
+		*status = DEVICE_ACTIVE;
+
+	return SR_OK;
+}
+
+SR_PRIV int kecheng_kc_330b_log_info_get(const struct sr_dev_inst *sdi,
+		unsigned char *buf)
+{
+	struct sr_usb_dev_inst *usb;
+	int len, ret;
+
+	sr_dbg("Getting logging info.");
+
+	usb = sdi->conn;
+	buf[0] = CMD_GET_LOG_INFO;
+	ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, buf, 1, &len, 5);
+	if (ret != 0 || len != 1) {
+		sr_dbg("Failed to get status: %s", libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	ret = libusb_bulk_transfer(usb->devhdl, EP_IN, buf, 9, &len, 10);
+	if (ret != 0 || len != 9) {
+		sr_dbg("Failed to get status (no ack): %s", libusb_error_name(ret));
+		return SR_ERR;
+	}
+	if (buf[0] != (CMD_GET_LOG_INFO | 0x80) || buf[1] > 6) {
+		sr_dbg("Failed to get log info: invalid response 0x%2.x", buf[0]);
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
diff --git a/hardware/kecheng-kc-330b/protocol.h b/hardware/kecheng-kc-330b/protocol.h
new file mode 100644
index 0000000..09152b9
--- /dev/null
+++ b/hardware/kecheng-kc-330b/protocol.h
@@ -0,0 +1,104 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_KECHENG_KC_330B_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_KECHENG_KC_330B_PROTOCOL_H
+
+#include <stdint.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "kecheng-kc-330b"
+
+#define EP_IN 0x80 | 1
+#define EP_OUT 2
+
+/* 500ms */
+#define DEFAULT_SAMPLE_INTERVAL 0
+#define DEFAULT_ALARM_LOW 40
+#define DEFAULT_ALARM_HIGH 120
+#define DEFAULT_WEIGHT_TIME SR_MQFLAG_SPL_TIME_WEIGHT_F
+#define DEFAULT_WEIGHT_FREQ SR_MQFLAG_SPL_FREQ_WEIGHT_A
+/* Live */
+#define DEFAULT_DATA_SOURCE DATA_SOURCE_LIVE
+
+enum {
+	LIVE_SPL_IDLE,
+	LIVE_SPL_WAIT,
+	LOG_DATA_IDLE,
+	LOG_DATA_WAIT,
+};
+
+enum {
+	CMD_CONFIGURE = 0x01,
+	CMD_IDENTIFY = 0x02,
+	CMD_SET_DATE_TIME = 0x03,
+	CMD_GET_STATUS = 0x04,
+	CMD_GET_LOG_INFO = 0x05,
+	CMD_GET_LOG_DATA = 0x07,
+	CMD_GET_LIVE_SPL = 0x08,
+};
+
+enum {
+	DATA_SOURCE_LIVE,
+	DATA_SOURCE_MEMORY,
+};
+
+enum {
+	DEVICE_ACTIVE,
+	DEVICE_INACTIVE,
+};
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+	/* Acquisition settings */
+	uint64_t limit_samples;
+	int sample_interval;
+	int alarm_low;
+	int alarm_high;
+	uint64_t mqflags;
+	int data_source;
+
+	/* Operational state */
+	int state;
+	gboolean config_dirty;
+	uint64_t num_samples;
+	uint64_t stored_samples;
+	void *cb_data;
+	struct libusb_transfer *xfer;
+	unsigned char buf[128];
+
+	/* Temporary state across callbacks */
+	gint64 last_live_request;
+
+};
+
+SR_PRIV int kecheng_kc_330b_handle_events(int fd, int revents, void *cb_data);
+SR_PRIV void kecheng_kc_330b_receive_transfer(struct libusb_transfer *transfer);
+SR_PRIV int kecheng_kc_330b_configure(const struct sr_dev_inst *sdi);
+SR_PRIV int kecheng_kc_330b_set_date_time(struct sr_dev_inst *sdi);
+SR_PRIV int kecheng_kc_330b_recording_get(const struct sr_dev_inst *sdi,
+		gboolean *tmp);
+SR_PRIV int kecheng_kc_330b_status_get(const struct sr_dev_inst *sdi,
+		int *status);
+SR_PRIV int kecheng_kc_330b_log_info_get(const struct sr_dev_inst *sdi,
+		unsigned char *buf);
+
+#endif
diff --git a/hardware/lascar-el-usb/api.c b/hardware/lascar-el-usb/api.c
new file mode 100644
index 0000000..657d993
--- /dev/null
+++ b/hardware/lascar-el-usb/api.c
@@ -0,0 +1,489 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <libusb.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+
+SR_PRIV struct sr_dev_driver lascar_el_usb_driver_info;
+static struct sr_dev_driver *di = &lascar_el_usb_driver_info;
+
+static const int32_t hwopts[] = {
+	SR_CONF_CONN,
+};
+
+static const int32_t hwcaps[] = {
+	SR_CONF_THERMOMETER,
+	SR_CONF_HYGROMETER,
+	SR_CONF_DATALOG,
+	SR_CONF_LIMIT_SAMPLES,
+};
+
+static int init(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+	struct drv_context *drvc;
+	struct sr_dev_inst *sdi;
+	struct sr_usb_dev_inst *usb;
+	struct sr_config *src;
+	GSList *usb_devices, *devices, *l;
+	const char *conn;
+
+	drvc = di->priv;
+
+	conn = NULL;
+	for (l = options; l; l = l->next) {
+		src = l->data;
+		switch (src->key) {
+		case SR_CONF_CONN:
+			conn = g_variant_get_string(src->data, NULL);
+			break;
+		}
+	}
+	if (!conn)
+		return NULL;
+
+	devices = NULL;
+	if ((usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn))) {
+		/* We have a list of sr_usb_dev_inst matching the connection
+		 * string. Wrap them in sr_dev_inst and we're done. */
+		for (l = usb_devices; l; l = l->next) {
+			usb = l->data;
+			if (!(sdi = lascar_scan(usb->bus, usb->address))) {
+				/* Not a Lascar EL-USB. */
+				g_free(usb);
+				continue;
+			}
+			sdi->inst_type = SR_INST_USB;
+			sdi->conn = usb;
+			drvc->instances = g_slist_append(drvc->instances, sdi);
+			devices = g_slist_append(devices, sdi);
+		}
+		g_slist_free(usb_devices);
+	} else
+		g_slist_free_full(usb_devices, g_free);
+
+	return devices;
+}
+
+static GSList *dev_list(void)
+{
+	return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+	struct drv_context *drvc;
+	struct sr_usb_dev_inst *usb;
+	int ret;
+
+	if (!(drvc = di->priv)) {
+		sr_err("Driver was not initialized.");
+		return SR_ERR;
+	}
+
+	usb = sdi->conn;
+
+	if (sr_usb_open(drvc->sr_ctx->libusb_ctx, usb) != SR_OK)
+		return SR_ERR;
+
+	if ((ret = libusb_claim_interface(usb->devhdl, LASCAR_INTERFACE))) {
+		sr_err("Failed to claim interface: %s.", libusb_error_name(ret));
+		return SR_ERR;
+	}
+	sdi->status = SR_ST_ACTIVE;
+
+	return ret;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+	struct sr_usb_dev_inst *usb;
+
+	if (!di->priv) {
+		sr_err("Driver was not initialized.");
+		return SR_ERR;
+	}
+
+	usb = sdi->conn;
+
+	if (!usb->devhdl)
+		/*  Nothing to do. */
+		return SR_OK;
+
+	libusb_release_interface(usb->devhdl, LASCAR_INTERFACE);
+	libusb_close(usb->devhdl);
+	usb->devhdl = NULL;
+	sdi->status = SR_ST_INACTIVE;
+
+	return SR_OK;
+}
+
+static int cleanup(void)
+{
+	int ret;
+	struct drv_context *drvc;
+
+	if (!(drvc = di->priv))
+		/* Can get called on an unused driver, doesn't matter. */
+		return SR_OK;
+
+
+	ret = std_dev_clear(di, NULL);
+	g_free(drvc);
+	di->priv = NULL;
+
+	return ret;
+}
+
+static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	struct sr_usb_dev_inst *usb;
+	int ret;
+	char str[128];
+
+	(void)cg;
+
+	devc = sdi->priv;
+	switch (id) {
+	case SR_CONF_CONN:
+		if (!sdi || !sdi->conn)
+			return SR_ERR_ARG;
+		usb = sdi->conn;
+		snprintf(str, 128, "%d.%d", usb->bus, usb->address);
+		*data = g_variant_new_string(str);
+		break;
+	case SR_CONF_DATALOG:
+		if (!sdi)
+			return SR_ERR_ARG;
+		if ((ret = lascar_is_logging(sdi)) == -1)
+			return SR_ERR;
+		*data = g_variant_new_boolean(ret ? TRUE : FALSE);
+		break;
+	case SR_CONF_LIMIT_SAMPLES:
+		*data = g_variant_new_uint64(devc->limit_samples);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	int ret;
+
+	(void)cg;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!di->priv) {
+		sr_err("Driver was not initialized.");
+		return SR_ERR;
+	}
+
+	devc = sdi->priv;
+	ret = SR_OK;
+	switch (id) {
+	case SR_CONF_DATALOG:
+		if (g_variant_get_boolean(data)) {
+			/* Start logging. */
+			ret = lascar_start_logging(sdi);
+		} else {
+			/* Stop logging. */
+			ret = lascar_stop_logging(sdi);
+		}
+		break;
+	case SR_CONF_LIMIT_SAMPLES:
+		devc->limit_samples = g_variant_get_uint64(data);
+		sr_dbg("Setting sample limit to %" PRIu64 ".",
+		       devc->limit_samples);
+		break;
+	default:
+		ret = SR_ERR_NA;
+	}
+
+	return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	(void)sdi;
+	(void)cg;
+
+	switch (key) {
+	case SR_CONF_SCAN_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+		break;
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static void mark_xfer(struct libusb_transfer *xfer)
+{
+
+	if (xfer->status == LIBUSB_TRANSFER_COMPLETED)
+		xfer->user_data = GINT_TO_POINTER(1);
+	else
+		xfer->user_data = GINT_TO_POINTER(-1);
+
+}
+
+/* The Lascar software, in its infinite ignorance, reads a set of four
+ * bytes from the device config struct and interprets it as a float.
+ * That only works because they only use windows, and only on x86. However
+ * we may be running on any architecture, any operating system. So we have
+ * to convert these four bytes as the Lascar software would on windows/x86,
+ * to the local representation of a float.
+ * The source format is little-endian, with IEEE 754-2008 BINARY32 encoding. */
+static float binary32_le_to_float(unsigned char *buf)
+{
+	GFloatIEEE754 f;
+
+	f.v_float = 0;
+	f.mpn.sign = (buf[3] & 0x80) ? 1 : 0;
+	f.mpn.biased_exponent = (buf[3] << 1) | (buf[2] >> 7);
+	f.mpn.mantissa = buf[0] | (buf[1] << 8) | ((buf[2] & 0x7f) << 16);
+
+	return f.v_float;
+}
+
+static int lascar_proc_config(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_usb_dev_inst *usb;
+	int dummy, ret;
+
+	devc = sdi->priv;
+	usb = sdi->conn;
+
+	if (lascar_get_config(usb->devhdl, devc->config, &dummy) != SR_OK)
+		return SR_ERR;
+
+	ret = SR_OK;
+	switch (devc->profile->logformat) {
+	case LOG_TEMP_RH:
+		devc->sample_size = 2;
+		devc->temp_unit = devc->config[0x2e] | (devc->config[0x2f] << 8);
+		if (devc->temp_unit != 0 && devc->temp_unit != 1) {
+			sr_dbg("invalid temperature unit %d", devc->temp_unit);
+			/* Default to Celcius, we're all adults here. */
+			devc->temp_unit = 0;
+		} else
+			sr_dbg("temperature unit is %s", devc->temp_unit
+					? "Fahrenheit" : "Celcius");
+		break;
+	case LOG_CO:
+		devc->sample_size = 2;
+		devc->co_high = binary32_le_to_float(devc->config + 0x24);
+		devc->co_low = binary32_le_to_float(devc->config + 0x28);
+		sr_dbg("EL-USB-CO calibration high %f low %f", devc->co_high,
+				devc->co_low);
+		break;
+	default:
+		ret = SR_ERR_ARG;
+	}
+	devc->logged_samples = devc->config[0x1e] | (devc->config[0x1f] << 8);
+	sr_dbg("device log contains %d samples.", devc->logged_samples);
+
+	return ret;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_meta meta;
+	struct sr_config *src;
+	struct dev_context *devc;
+	struct drv_context *drvc;
+	struct sr_usb_dev_inst *usb;
+	struct libusb_transfer *xfer_in, *xfer_out;
+	struct timeval tv;
+	uint64_t interval;
+	int ret;
+	unsigned char cmd[3], resp[4], *buf;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!di->priv) {
+		sr_err("Driver was not initialized.");
+		return SR_ERR;
+	}
+
+	drvc = di->priv;
+	devc = sdi->priv;
+	usb = sdi->conn;
+	devc->cb_data = cb_data;
+
+	if (lascar_proc_config(sdi) != SR_OK)
+		return SR_ERR;
+
+	sr_dbg("Starting log retrieval.");
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	interval = (devc->config[0x1c] | (devc->config[0x1d] << 8)) * 1000;
+	packet.type = SR_DF_META;
+	packet.payload = &meta;
+	src = sr_config_new(SR_CONF_SAMPLE_INTERVAL, g_variant_new_uint64(interval));
+	meta.config = g_slist_append(NULL, src);
+	sr_session_send(devc->cb_data, &packet);
+	g_free(src);
+
+	if (devc->logged_samples == 0) {
+		/* This ensures the frontend knows the session is done. */
+		packet.type = SR_DF_END;
+		sr_session_send(devc->cb_data, &packet);
+		return SR_OK;
+	}
+
+	if (!(xfer_in = libusb_alloc_transfer(0)) ||
+			!(xfer_out = libusb_alloc_transfer(0)))
+		return SR_ERR;
+
+	libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR,
+			0x00, 0xffff, 0x00, NULL, 0, 50);
+	libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR,
+			0x02, 0x0002, 0x00, NULL, 0, 50);
+	libusb_control_transfer(usb->devhdl, LIBUSB_REQUEST_TYPE_VENDOR,
+			0x02, 0x0001, 0x00, NULL, 0, 50);
+
+
+	/* Flush input. The F321 requires this. */
+	while (libusb_bulk_transfer(usb->devhdl, LASCAR_EP_IN, resp,
+			256, &ret, 5) == 0 && ret > 0)
+		;
+
+	libusb_fill_bulk_transfer(xfer_in, usb->devhdl, LASCAR_EP_IN,
+			resp, sizeof(resp), mark_xfer, 0, 10000);
+	if (libusb_submit_transfer(xfer_in) != 0) {
+		libusb_free_transfer(xfer_in);
+		libusb_free_transfer(xfer_out);
+		return SR_ERR;
+	}
+
+	cmd[0] = 0x03;
+	cmd[1] = 0xff;
+	cmd[2] = 0xff;
+	libusb_fill_bulk_transfer(xfer_out, usb->devhdl, LASCAR_EP_OUT,
+			cmd, 3, mark_xfer, 0, 100);
+	if (libusb_submit_transfer(xfer_out) != 0) {
+		libusb_free_transfer(xfer_in);
+		libusb_free_transfer(xfer_out);
+		return SR_ERR;
+	}
+
+	tv.tv_sec = 0;
+	tv.tv_usec = 0;
+	while (!xfer_in->user_data || !xfer_out->user_data) {
+		g_usleep(5000);
+		libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
+	}
+	if (xfer_in->user_data != GINT_TO_POINTER(1) ||
+			xfer_in->user_data != GINT_TO_POINTER(1)) {
+		sr_dbg("no response to log transfer request");
+		libusb_free_transfer(xfer_in);
+		libusb_free_transfer(xfer_out);
+		return SR_ERR;
+	}
+	if (xfer_in->actual_length != 3 || xfer_in->buffer[0] != 2) {
+		sr_dbg("invalid response to log transfer request");
+		libusb_free_transfer(xfer_in);
+		libusb_free_transfer(xfer_out);
+		return SR_ERR;
+	}
+	devc->log_size = xfer_in->buffer[1] + (xfer_in->buffer[2] << 8);
+	libusb_free_transfer(xfer_out);
+
+	usb_source_add(drvc->sr_ctx, 100, lascar_el_usb_handle_events, (void *)sdi);
+
+	buf = g_try_malloc(4096);
+	libusb_fill_bulk_transfer(xfer_in, usb->devhdl, LASCAR_EP_IN,
+			buf, 4096, lascar_el_usb_receive_transfer, cb_data, 100);
+	if ((ret = libusb_submit_transfer(xfer_in) != 0)) {
+		sr_err("Unable to submit transfer: %s.", libusb_error_name(ret));
+		libusb_free_transfer(xfer_in);
+		g_free(buf);
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+SR_PRIV int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	(void)cb_data;
+
+	if (!di->priv) {
+		sr_err("Driver was not initialized.");
+		return SR_ERR;
+	}
+
+	if (sdi->status != SR_ST_ACTIVE) {
+		sr_err("Device inactive, can't stop acquisition.");
+		return SR_ERR;
+	}
+
+	sdi->status = SR_ST_STOPPING;
+	/* TODO: free ongoing transfers? */
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver lascar_el_usb_driver_info = {
+	.name = "lascar-el-usb",
+	.longname = "Lascar EL-USB",
+	.api_version = 1,
+	.init = init,
+	.cleanup = cleanup,
+	.scan = scan,
+	.dev_list = dev_list,
+	.dev_clear = NULL,
+	.config_get = config_get,
+	.config_set = config_set,
+	.config_list = config_list,
+	.dev_open = dev_open,
+	.dev_close = dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/lascar-el-usb/protocol.c b/hardware/lascar-el-usb/protocol.c
new file mode 100644
index 0000000..050b42b
--- /dev/null
+++ b/hardware/lascar-el-usb/protocol.c
@@ -0,0 +1,656 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <sys/time.h>
+#include <string.h>
+#include <math.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+
+extern struct sr_dev_driver lascar_el_usb_driver_info;
+static struct sr_dev_driver *di = &lascar_el_usb_driver_info;
+
+static const struct elusb_profile profiles[] = {
+	{ 1, "EL-USB-1", LOG_UNSUPPORTED },
+	{ 2, "EL-USB-1", LOG_UNSUPPORTED },
+	{ 3, "EL-USB-2", LOG_TEMP_RH },
+	{ 4, "EL-USB-3", LOG_UNSUPPORTED },
+	{ 5, "EL-USB-4", LOG_UNSUPPORTED },
+	{ 6, "EL-USB-3", LOG_UNSUPPORTED },
+	{ 7, "EL-USB-4", LOG_UNSUPPORTED },
+	{ 8, "EL-USB-LITE", LOG_UNSUPPORTED },
+	{ 9, "EL-USB-CO", LOG_CO },
+	{ 10, "EL-USB-TC", LOG_UNSUPPORTED },
+	{ 11, "EL-USB-CO300", LOG_CO },
+	{ 12, "EL-USB-2-LCD", LOG_TEMP_RH },
+	{ 13, "EL-USB-2+", LOG_TEMP_RH },
+	{ 14, "EL-USB-1-PRO", LOG_UNSUPPORTED },
+	{ 15, "EL-USB-TC-LCD", LOG_UNSUPPORTED },
+	{ 16, "EL-USB-2-LCD+", LOG_TEMP_RH },
+	{ 17, "EL-USB-5", LOG_UNSUPPORTED },
+	{ 18, "EL-USB-1-RCG", LOG_UNSUPPORTED },
+	{ 19, "EL-USB-1-LCD", LOG_UNSUPPORTED },
+	{ 20, "EL-OEM-3", LOG_UNSUPPORTED },
+	{ 21, "EL-USB-1-LCD", LOG_UNSUPPORTED },
+	{ 0, NULL, 0 }
+};
+
+
+static libusb_device_handle *lascar_open(struct libusb_device *dev)
+{
+	libusb_device_handle *dev_hdl;
+	int ret;
+
+	if ((ret = libusb_open(dev, &dev_hdl)) != 0) {
+		sr_dbg("failed to open device for scan: %s",
+				libusb_error_name(ret));
+		return NULL;
+	}
+
+	/* Some of these fail, but it needs doing -- some sort of mode
+	 * setup for the SILabs F32x. */
+	libusb_control_transfer(dev_hdl, LIBUSB_REQUEST_TYPE_VENDOR,
+			0x00, 0xffff, 0x00, NULL, 0, 50);
+	libusb_control_transfer(dev_hdl, LIBUSB_REQUEST_TYPE_VENDOR,
+			0x02, 0x0002, 0x00, NULL, 0, 50);
+	libusb_control_transfer(dev_hdl, LIBUSB_REQUEST_TYPE_VENDOR,
+			0x02, 0x0001, 0x00, NULL, 0, 50);
+
+	return dev_hdl;
+}
+
+static void mark_xfer(struct libusb_transfer *xfer)
+{
+
+	xfer->user_data = GINT_TO_POINTER(1);
+
+}
+
+SR_PRIV int lascar_get_config(libusb_device_handle *dev_hdl,
+		unsigned char *configblock, int *configlen)
+{
+	struct drv_context *drvc;
+	struct libusb_transfer *xfer_in, *xfer_out;
+	struct timeval tv;
+	int64_t start;
+	int buflen;
+	unsigned char cmd[3], buf[MAX_CONFIGBLOCK_SIZE];
+
+	sr_spew("Reading config block.");
+
+	drvc = di->priv;
+	*configlen = 0;
+
+	if (!(xfer_in = libusb_alloc_transfer(0)) ||
+			!(xfer_out = libusb_alloc_transfer(0)))
+		return SR_ERR;
+
+	/* Flush anything the F321 still has queued. */
+	while (libusb_bulk_transfer(dev_hdl, LASCAR_EP_IN, buf, 256, &buflen,
+			5) == 0 && buflen > 0)
+		;
+
+	/* Keep a read request waiting in the wings, ready to pounce
+	 * the moment the device sends something. */
+	libusb_fill_bulk_transfer(xfer_in, dev_hdl, LASCAR_EP_IN,
+			buf, 256, mark_xfer, 0, 10000);
+	if (libusb_submit_transfer(xfer_in) != 0)
+		goto cleanup;
+
+	/* Request device configuration structure. */
+	cmd[0] = 0x00;
+	cmd[1] = 0xff;
+	cmd[2] = 0xff;
+	libusb_fill_bulk_transfer(xfer_out, dev_hdl, LASCAR_EP_OUT,
+			cmd, 3, mark_xfer, 0, 100);
+	if (libusb_submit_transfer(xfer_out) != 0)
+		goto cleanup;
+
+	tv.tv_sec = 0;
+	tv.tv_usec = 0;
+	start = g_get_monotonic_time();
+	while (!xfer_in->user_data || !xfer_out->user_data) {
+		if (g_get_monotonic_time() - start > SCAN_TIMEOUT) {
+			start = 0;
+			break;
+		}
+		g_usleep(5000);
+		libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
+	}
+	if (!start) {
+		sr_dbg("no response");
+		goto cleanup;
+	}
+	if (xfer_in->actual_length != 3) {
+		sr_dbg("expected 3-byte header, got %d bytes", xfer_in->actual_length);
+		goto cleanup;
+	}
+
+	/* Got configuration structure header. */
+	sr_spew("Response to config request: 0x%.2x 0x%.2x 0x%.2x ",
+			buf[0], buf[1], buf[2]);
+	buflen = buf[1] | (buf[2] << 8);
+	if (buf[0] != 0x02 || buflen > MAX_CONFIGBLOCK_SIZE) {
+		sr_dbg("Invalid response to config request: "
+				"0x%.2x 0x%.2x 0x%.2x ", buf[0], buf[1], buf[2]);
+		libusb_close(dev_hdl);
+		goto cleanup;
+	}
+
+	/* Get configuration structure. */
+	xfer_in->length = buflen;
+	xfer_in->user_data = 0;
+	if (libusb_submit_transfer(xfer_in) != 0)
+		goto cleanup;
+	while (!xfer_in->user_data) {
+		if (g_get_monotonic_time() - start > SCAN_TIMEOUT) {
+			start = 0;
+			break;
+		}
+		g_usleep(5000);
+		libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
+	}
+	if (!start) {
+		sr_dbg("Timeout waiting for configuration structure.");
+		goto cleanup;
+	}
+	if (xfer_in->actual_length != buflen) {
+		sr_dbg("expected %d-byte structure, got %d bytes", buflen,
+				xfer_in->actual_length);
+		goto cleanup;
+	}
+
+	memcpy(configblock, buf, buflen);
+	*configlen = buflen;
+
+cleanup:
+	if (!xfer_in->user_data || !xfer_in->user_data) {
+		if (!xfer_in->user_data)
+			libusb_cancel_transfer(xfer_in);
+		if (!xfer_out->user_data)
+			libusb_cancel_transfer(xfer_out);
+		start = g_get_monotonic_time();
+		while (!xfer_in->user_data || !xfer_out->user_data) {
+			if (g_get_monotonic_time() - start > 10000)
+				break;
+			g_usleep(1000);
+			libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
+		}
+	}
+	libusb_free_transfer(xfer_in);
+	libusb_free_transfer(xfer_out);
+
+	return *configlen ? SR_OK : SR_ERR;
+}
+
+static int lascar_save_config(libusb_device_handle *dev_hdl,
+		unsigned char *config, int configlen)
+{
+	struct drv_context *drvc;
+	struct libusb_transfer *xfer_in, *xfer_out;
+	struct timeval tv;
+	int64_t start;
+	int buflen, ret;
+	unsigned char cmd[3], buf[256];
+
+	sr_spew("Writing config block.");
+
+	drvc = di->priv;
+
+	if (!(xfer_in = libusb_alloc_transfer(0)) ||
+			!(xfer_out = libusb_alloc_transfer(0)))
+		return SR_ERR;
+
+	/* Flush anything the F321 still has queued. */
+	while (libusb_bulk_transfer(dev_hdl, LASCAR_EP_IN, buf, 256, &buflen,
+			5) == 0 && buflen > 0)
+		;
+	ret = SR_OK;
+
+	/* Keep a read request waiting in the wings, ready to pounce
+	 * the moment the device sends something. */
+	libusb_fill_bulk_transfer(xfer_in, dev_hdl, LASCAR_EP_IN,
+			buf, 256, mark_xfer, 0, 10000);
+	if (libusb_submit_transfer(xfer_in) != 0) {
+		ret = SR_ERR;
+		goto cleanup;
+	}
+
+	/* Request device configuration structure. */
+	cmd[0] = 0x01;
+	cmd[1] = configlen & 0xff;
+	cmd[2] = (configlen >> 8) & 0xff;
+	libusb_fill_bulk_transfer(xfer_out, dev_hdl, LASCAR_EP_OUT,
+			cmd, 3, mark_xfer, 0, 100);
+	if (libusb_submit_transfer(xfer_out) != 0) {
+		ret = SR_ERR;
+		goto cleanup;
+	}
+	tv.tv_sec = 0;
+	tv.tv_usec = 0;
+	while (!xfer_out->user_data) {
+		g_usleep(5000);
+		libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
+	}
+
+	libusb_fill_bulk_transfer(xfer_out, dev_hdl, LASCAR_EP_OUT,
+			config, configlen, mark_xfer, 0, 100);
+	if (libusb_submit_transfer(xfer_out) != 0) {
+		ret = SR_ERR;
+		goto cleanup;
+	}
+	while (!xfer_in->user_data || !xfer_out->user_data) {
+		g_usleep(5000);
+		libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
+	}
+
+	if (xfer_in->actual_length != 1 || buf[0] != 0xff) {
+		sr_dbg("unexpected response after transfer");
+		ret = SR_ERR;
+	}
+
+cleanup:
+	if (!xfer_in->user_data || !xfer_in->user_data) {
+		if (!xfer_in->user_data)
+			libusb_cancel_transfer(xfer_in);
+		if (!xfer_out->user_data)
+			libusb_cancel_transfer(xfer_out);
+		start = g_get_monotonic_time();
+		while (!xfer_in->user_data || !xfer_out->user_data) {
+			if (g_get_monotonic_time() - start > 10000)
+				break;
+			g_usleep(1000);
+			libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
+		}
+	}
+	libusb_free_transfer(xfer_in);
+	libusb_free_transfer(xfer_out);
+
+	return ret;
+}
+
+static struct sr_dev_inst *lascar_identify(unsigned char *config)
+{
+	struct dev_context *devc;
+	const struct elusb_profile *profile;
+	struct sr_dev_inst *sdi;
+	struct sr_channel *ch;
+	int modelid, i;
+	char firmware[5];
+
+	modelid = config[0];
+	sdi = NULL;
+	if (modelid) {
+		profile = NULL;
+		for (i = 0; profiles[i].modelid; i++) {
+			if (profiles[i].modelid == modelid) {
+				profile = &profiles[i];
+				break;
+			}
+		}
+		if (!profile) {
+			sr_dbg("unknown EL-USB modelid %d", modelid);
+			return NULL;
+		}
+
+		i = config[52] | (config[53] << 8);
+		memcpy(firmware, config + 0x30, 4);
+		firmware[4] = '\0';
+		sr_dbg("found %s with firmware version %s serial %d",
+				profile->modelname, firmware, i);
+
+		if (profile->logformat == LOG_UNSUPPORTED) {
+			sr_dbg("unsupported EL-USB logformat for %s", profile->modelname);
+			return NULL;
+		}
+
+		if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, LASCAR_VENDOR,
+				profile->modelname, firmware)))
+			return NULL;
+		sdi->driver = di;
+
+		if (profile->logformat == LOG_TEMP_RH) {
+			/* Model this as two channels: temperature and humidity. */
+			if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "Temp")))
+				return NULL;
+			sdi->channels = g_slist_append(NULL, ch);
+			if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "Hum")))
+				return NULL;
+			sdi->channels = g_slist_append(sdi->channels, ch);
+		} else if (profile->logformat == LOG_CO) {
+			if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "CO")))
+				return NULL;
+			sdi->channels = g_slist_append(NULL, ch);
+		} else {
+			if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
+				return NULL;
+			sdi->channels = g_slist_append(NULL, ch);
+		}
+
+		if (!(devc = g_try_malloc0(sizeof(struct dev_context))))
+			return NULL;
+		sdi->priv = devc;
+		devc->profile = profile;
+	}
+
+	return sdi;
+}
+
+SR_PRIV struct sr_dev_inst *lascar_scan(int bus, int address)
+{
+	struct drv_context *drvc;
+	struct sr_dev_inst *sdi;
+	struct libusb_device **devlist;
+	struct libusb_device_descriptor des;
+	libusb_device_handle *dev_hdl;
+	int dummy, ret, i;
+	unsigned char config[MAX_CONFIGBLOCK_SIZE];
+
+	drvc = di->priv;
+	sdi = NULL;
+
+	libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
+	for (i = 0; devlist[i]; i++) {
+		if ((ret = libusb_get_device_descriptor(devlist[i], &des))) {
+			sr_err("Failed to get device descriptor: %d.", ret);
+			continue;
+		}
+
+		if (libusb_get_bus_number(devlist[i]) != bus ||
+				libusb_get_device_address(devlist[i]) != address)
+			continue;
+
+		if (!(dev_hdl = lascar_open(devlist[i])))
+			continue;
+
+		if (lascar_get_config(dev_hdl, config, &dummy) != SR_OK)
+			continue;
+
+		libusb_close(dev_hdl);
+		sdi = lascar_identify(config);
+	}
+
+	return sdi;
+}
+
+static void lascar_el_usb_dispatch(struct sr_dev_inst *sdi, unsigned char *buf,
+		int buflen)
+{
+	struct dev_context *devc;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_analog analog;
+	struct sr_channel *ch;
+	float *temp, *rh;
+	uint16_t s;
+	int samples, samples_left, i, j;
+
+	devc = sdi->priv;
+
+	samples = buflen / devc->sample_size;
+	samples_left = devc->logged_samples - devc->rcvd_samples;
+	if (samples_left < samples)
+		samples = samples_left;
+	switch (devc->profile->logformat) {
+	case LOG_TEMP_RH:
+		packet.type = SR_DF_ANALOG;
+		packet.payload = &analog;
+		analog.mqflags = 0;
+		if (!(temp = g_try_malloc(sizeof(float) * samples)))
+			break;
+		if (!(rh = g_try_malloc(sizeof(float) * samples)))
+			break;
+		for (i = 0, j = 0; i < samples; i++) {
+			/* Both Celcius and Fahrenheit stored at base -40. */
+			if (devc->temp_unit == 0)
+				/* Celcius is stored in half-degree increments. */
+				temp[j] = buf[i * 2] / 2 - 40;
+			else
+				temp[j] = buf[i * 2] - 40;
+
+			rh[j] = buf[i * 2 + 1] / 2;
+
+			if (temp[j] == 0.0 && rh[j] == 0.0)
+				/* Skip invalid measurement. */
+				continue;
+			j++;
+		}
+		analog.num_samples = j;
+
+		ch = sdi->channels->data;
+		if (ch->enabled) {
+			analog.channels = g_slist_append(NULL, ch);
+			analog.mq = SR_MQ_TEMPERATURE;
+			if (devc->temp_unit == 1)
+				analog.unit = SR_UNIT_FAHRENHEIT;
+			else
+				analog.unit = SR_UNIT_CELSIUS;
+			analog.data = temp;
+			sr_session_send(devc->cb_data, &packet);
+		}
+
+		ch = sdi->channels->next->data;
+		if (ch->enabled) {
+			analog.channels = g_slist_append(NULL, ch);
+			analog.mq = SR_MQ_RELATIVE_HUMIDITY;
+			analog.unit = SR_UNIT_PERCENTAGE;
+			analog.data = rh;
+			sr_session_send(devc->cb_data, &packet);
+		}
+
+		g_free(temp);
+		g_free(rh);
+		break;
+	case LOG_CO:
+		packet.type = SR_DF_ANALOG;
+		packet.payload = &analog;
+		analog.channels = sdi->channels;
+		analog.num_samples = samples;
+		analog.mq = SR_MQ_CARBON_MONOXIDE;
+		analog.unit = SR_UNIT_CONCENTRATION;
+		analog.mqflags = 0;
+		if (!(analog.data = g_try_malloc(sizeof(float) * samples)))
+			break;
+		for (i = 0; i < samples; i++) {
+			s = (buf[i * 2] << 8) | buf[i * 2 + 1];
+			analog.data[i] = (s * devc->co_high + devc->co_low) / 1000000;
+			if (analog.data[i] < 0.0)
+				analog.data[i] = 0.0;
+		}
+		sr_session_send(devc->cb_data, &packet);
+		g_free(analog.data);
+		break;
+	default:
+		/* How did we even get this far? */
+		break;
+	}
+	devc->rcvd_samples += samples;
+
+}
+
+SR_PRIV int lascar_el_usb_handle_events(int fd, int revents, void *cb_data)
+{
+	struct drv_context *drvc = di->priv;
+	struct sr_datafeed_packet packet;
+	struct sr_dev_inst *sdi;
+	struct timeval tv;
+
+	(void)fd;
+	(void)revents;
+
+	sdi = cb_data;
+
+	if (sdi->status == SR_ST_STOPPING) {
+		usb_source_remove(drvc->sr_ctx);
+
+		packet.type = SR_DF_END;
+		sr_session_send(cb_data, &packet);
+	}
+
+	memset(&tv, 0, sizeof(struct timeval));
+	libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx, &tv,
+					       NULL);
+
+	return TRUE;
+}
+
+SR_PRIV void lascar_el_usb_receive_transfer(struct libusb_transfer *transfer)
+{
+	struct dev_context *devc;
+	struct sr_dev_inst *sdi;
+	int ret;
+	gboolean packet_has_error;
+
+	sdi = transfer->user_data;
+	devc = sdi->priv;
+
+	packet_has_error = FALSE;
+	switch (transfer->status) {
+	case LIBUSB_TRANSFER_NO_DEVICE:
+		/* USB device was unplugged. */
+		dev_acquisition_stop(sdi, sdi);
+		return;
+	case LIBUSB_TRANSFER_COMPLETED:
+	case LIBUSB_TRANSFER_TIMED_OUT: /* We may have received some data though */
+		break;
+	default:
+		packet_has_error = TRUE;
+		break;
+	}
+
+	if (!packet_has_error) {
+		if (devc->rcvd_samples < devc->logged_samples)
+			lascar_el_usb_dispatch(sdi, transfer->buffer,
+					transfer->actual_length);
+		devc->rcvd_bytes += transfer->actual_length;
+		sr_spew("received %d/%d bytes (%d/%d samples)",
+				devc->rcvd_bytes, devc->log_size,
+				devc->rcvd_samples, devc->logged_samples);
+		if (devc->rcvd_bytes >= devc->log_size)
+			dev_acquisition_stop(sdi, sdi);
+	}
+
+	if (sdi->status == SR_ST_ACTIVE) {
+		/* Send the same request again. */
+		if ((ret = libusb_submit_transfer(transfer) != 0)) {
+			sr_err("Unable to resubmit transfer: %s.",
+			       libusb_error_name(ret));
+			g_free(transfer->buffer);
+			libusb_free_transfer(transfer);
+			dev_acquisition_stop(sdi, sdi);
+		}
+	} else {
+		/* This was the last transfer we're going to receive, so
+		 * clean up now. */
+		g_free(transfer->buffer);
+		libusb_free_transfer(transfer);
+	}
+
+}
+
+static int get_flags(unsigned char *configblock)
+{
+	int flags;
+
+	flags = (configblock[32] | (configblock[33] << 8)) & 0x1fff;
+	sr_spew("Read flags (0x%.4x).", flags);
+
+	return flags;
+}
+
+static int set_flags(unsigned char *configblock, int flags)
+{
+
+	sr_spew("Setting flags to 0x%.4x.", flags);
+	configblock[32] = flags & 0xff;
+	configblock[33] = (flags >> 8) & 0x1f;
+
+	return flags;
+}
+
+SR_PRIV int lascar_is_logging(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_usb_dev_inst *usb;
+	int dummy, flags, ret;
+
+	devc = sdi->priv;
+	usb = sdi->conn;
+
+	if (lascar_get_config(usb->devhdl, devc->config, &dummy) != SR_OK)
+		return -1;
+
+	flags = get_flags(devc->config);
+	if (flags & 0x0100)
+		ret = 1;
+	else
+		ret = 0;
+
+	return ret;
+}
+
+SR_PRIV int lascar_start_logging(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_usb_dev_inst *usb;
+	int len, flags, ret;
+
+	devc = sdi->priv;
+	usb = sdi->conn;
+
+	if (lascar_get_config(usb->devhdl, devc->config, &len) != SR_OK)
+		return SR_ERR;
+
+	/* Turn on logging. */
+	flags = get_flags(devc->config);
+	flags |= 0x0100;
+	set_flags(devc->config, flags);
+
+	/* Start logging in 0 seconds. */
+	memset(devc->config + 24, 0, 4);
+
+	ret = lascar_save_config(usb->devhdl, devc->config, len);
+	sr_info("Started internal logging.");
+
+	return ret;
+}
+
+SR_PRIV int lascar_stop_logging(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_usb_dev_inst *usb;
+	int len, flags, ret;
+
+	devc = sdi->priv;
+	usb = sdi->conn;
+
+	if (lascar_get_config(usb->devhdl, devc->config, &len) != SR_OK)
+		return SR_ERR;
+
+	flags = get_flags(devc->config);
+	flags &= ~0x0100;
+	set_flags(devc->config, flags);
+
+	ret = lascar_save_config(usb->devhdl, devc->config, len);
+	sr_info("Stopped internal logging.");
+
+	return ret;
+}
diff --git a/hardware/lascar-el-usb/protocol.h b/hardware/lascar-el-usb/protocol.h
new file mode 100644
index 0000000..a94bd8a
--- /dev/null
+++ b/hardware/lascar-el-usb/protocol.h
@@ -0,0 +1,80 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_LASCAR_EL_USB_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_LASCAR_EL_USB_PROTOCOL_H
+
+#include <stdint.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "lascar-el-usb"
+
+#define LASCAR_VENDOR "Lascar"
+#define LASCAR_INTERFACE 0
+#define LASCAR_EP_IN 0x82
+#define LASCAR_EP_OUT 2
+/* Max 100ms for a device to positively identify. */
+#define SCAN_TIMEOUT 100000
+#define MAX_CONFIGBLOCK_SIZE 256
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+	void *cb_data;
+	const struct elusb_profile *profile;
+	/* Generic EL-USB */
+	unsigned char config[MAX_CONFIGBLOCK_SIZE];
+	unsigned int log_size;
+	unsigned int rcvd_bytes;
+	unsigned int sample_size;
+	unsigned int logged_samples;
+	unsigned int rcvd_samples;
+	uint64_t limit_samples;
+	/* Model-specific */
+	/* EL-USB-CO: these are something like scaling and calibration values
+	 * fixed per device, used to convert the sample values to CO ppm. */
+	float co_high;
+	float co_low;
+	/* Temperature units as stored in the device config. */
+	int temp_unit;
+};
+
+enum {
+	LOG_UNSUPPORTED,
+	LOG_TEMP_RH,
+	LOG_CO,
+};
+
+struct elusb_profile {
+	int modelid;
+	char *modelname;
+	int logformat;
+};
+
+SR_PRIV int lascar_get_config(libusb_device_handle *dev_hdl,
+		unsigned char *configblock, int *configlen);
+SR_PRIV struct sr_dev_inst *lascar_scan(int bus, int address);
+SR_PRIV int lascar_el_usb_handle_events(int fd, int revents, void *cb_data);
+SR_PRIV void lascar_el_usb_receive_transfer(struct libusb_transfer *transfer);
+SR_PRIV int lascar_start_logging(const struct sr_dev_inst *sdi);
+SR_PRIV int lascar_stop_logging(const struct sr_dev_inst *sdi);
+SR_PRIV int lascar_is_logging(const struct sr_dev_inst *sdi);
+SR_PRIV int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data);
+
+#endif
diff --git a/hardware/mic-985xx/api.c b/hardware/mic-985xx/api.c
new file mode 100644
index 0000000..7b0d680
--- /dev/null
+++ b/hardware/mic-985xx/api.c
@@ -0,0 +1,291 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "protocol.h"
+
+static const int32_t hwopts[] = {
+	SR_CONF_CONN,
+	SR_CONF_SERIALCOMM,
+};
+
+static const int32_t hwcaps[] = {
+	SR_CONF_THERMOMETER,
+	SR_CONF_HYGROMETER,
+	SR_CONF_LIMIT_SAMPLES,
+	SR_CONF_LIMIT_MSEC,
+	SR_CONF_CONTINUOUS,
+};
+
+SR_PRIV struct sr_dev_driver mic_98581_driver_info;
+SR_PRIV struct sr_dev_driver mic_98583_driver_info;
+
+SR_PRIV const struct mic_dev_info mic_devs[] = {
+	{
+		"MIC", "98581", "38400/8n2", 32000, TRUE, FALSE, 6,
+		packet_valid_temp,
+		&mic_98581_driver_info, receive_data_MIC_98581,
+	},
+	{
+		"MIC", "98583", "38400/8n2", 32000, TRUE, TRUE, 10,
+		packet_valid_temp_hum,
+		&mic_98583_driver_info, receive_data_MIC_98583,
+	},
+};
+
+static int dev_clear(int idx)
+{
+	return std_dev_clear(mic_devs[idx].di, NULL);
+}
+
+static int init(struct sr_context *sr_ctx, int idx)
+{
+	sr_dbg("Selected '%s' subdriver.", mic_devs[idx].di->name);
+
+	return std_init(sr_ctx, mic_devs[idx].di, LOG_PREFIX);
+}
+
+static GSList *mic_scan(const char *conn, const char *serialcomm, int idx)
+{
+	struct sr_dev_inst *sdi;
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_channel *ch;
+	struct sr_serial_dev_inst *serial;
+	GSList *devices;
+
+	if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+		return NULL;
+
+	if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+		return NULL;
+
+	drvc = mic_devs[idx].di->priv;
+	devices = NULL;
+	serial_flush(serial);
+
+	/* TODO: Query device type. */
+	// ret = mic_cmd_get_device_info(serial);
+
+	sr_info("Found device on port %s.", conn);
+
+	/* TODO: Fill in version from protocol response. */
+	if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, mic_devs[idx].vendor,
+				    mic_devs[idx].device, NULL)))
+		goto scan_cleanup;
+
+	if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+		sr_err("Device context malloc failed.");
+		goto scan_cleanup;
+	}
+
+	sdi->inst_type = SR_INST_SERIAL;
+	sdi->conn = serial;
+
+	sdi->priv = devc;
+	sdi->driver = mic_devs[idx].di;
+
+	if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "Temperature")))
+		goto scan_cleanup;
+	sdi->channels = g_slist_append(sdi->channels, ch);
+
+	if (mic_devs[idx].has_humidity) {
+		if (!(ch = sr_channel_new(1, SR_CHANNEL_ANALOG, TRUE, "Humidity")))
+			goto scan_cleanup;
+		sdi->channels = g_slist_append(sdi->channels, ch);
+	}
+
+	drvc->instances = g_slist_append(drvc->instances, sdi);
+	devices = g_slist_append(devices, sdi);
+
+scan_cleanup:
+	serial_close(serial);
+
+	return devices;
+}
+
+static GSList *scan(GSList *options, int idx)
+{
+	struct sr_config *src;
+	GSList *l, *devices;
+	const char *conn, *serialcomm;
+
+	conn = serialcomm = NULL;
+	for (l = options; l; l = l->next) {
+		src = l->data;
+		switch (src->key) {
+		case SR_CONF_CONN:
+			conn = g_variant_get_string(src->data, NULL);
+			break;
+		case SR_CONF_SERIALCOMM:
+			serialcomm = g_variant_get_string(src->data, NULL);
+			break;
+		}
+	}
+	if (!conn)
+		return NULL;
+
+	if (serialcomm) {
+		/* Use the provided comm specs. */
+		devices = mic_scan(conn, serialcomm, idx);
+	} else {
+		/* Try the default. */
+		devices = mic_scan(conn, mic_devs[idx].conn, idx);
+	}
+
+	return devices;
+}
+
+static GSList *dev_list(int idx)
+{
+	return ((struct drv_context *)(mic_devs[idx].di->priv))->instances;
+}
+
+static int cleanup(int idx)
+{
+	return dev_clear(idx);
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+
+	(void)cg;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	devc = sdi->priv;
+
+	switch (id) {
+	case SR_CONF_LIMIT_SAMPLES:
+		devc->limit_samples = g_variant_get_uint64(data);
+		sr_dbg("Setting sample limit to %" PRIu64 ".",
+		       devc->limit_samples);
+		break;
+	case SR_CONF_LIMIT_MSEC:
+		devc->limit_msec = g_variant_get_uint64(data);
+		sr_dbg("Setting time limit to %" PRIu64 "ms.",
+		       devc->limit_msec);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	(void)sdi;
+	(void)cg;
+
+	switch (key) {
+	case SR_CONF_SCAN_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+		break;
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi,
+				    void *cb_data, int idx)
+{
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	devc = sdi->priv;
+	devc->cb_data = cb_data;
+	devc->num_samples = 0;
+	devc->starttime = g_get_monotonic_time();
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	/* Poll every 100ms, or whenever some data comes in. */
+	serial = sdi->conn;
+	serial_source_add(serial, G_IO_IN, 100,
+		      mic_devs[idx].receive_data, (void *)sdi);
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close,
+			sdi->conn, LOG_PREFIX);
+}
+
+/* Driver-specific API function wrappers */
+#define HW_INIT(X) \
+static int init_##X(struct sr_context *sr_ctx) { return init(sr_ctx, X); }
+#define HW_CLEANUP(X) \
+static int cleanup_##X(void) { return cleanup(X); }
+#define HW_SCAN(X) \
+static GSList *scan_##X(GSList *options) { return scan(options, X); }
+#define HW_DEV_LIST(X) \
+static GSList *dev_list_##X(void) { return dev_list(X); }
+#define HW_DEV_CLEAR(X) \
+static int dev_clear_##X(void) { return dev_clear(X); }
+#define HW_DEV_ACQUISITION_START(X) \
+static int dev_acquisition_start_##X(const struct sr_dev_inst *sdi, \
+void *cb_data) { return dev_acquisition_start(sdi, cb_data, X); }
+
+/* Driver structs and API function wrappers */
+#define DRV(ID, ID_UPPER, NAME, LONGNAME) \
+HW_INIT(ID_UPPER) \
+HW_CLEANUP(ID_UPPER) \
+HW_SCAN(ID_UPPER) \
+HW_DEV_LIST(ID_UPPER) \
+HW_DEV_CLEAR(ID_UPPER) \
+HW_DEV_ACQUISITION_START(ID_UPPER) \
+SR_PRIV struct sr_dev_driver ID##_driver_info = { \
+	.name = NAME, \
+	.longname = LONGNAME, \
+	.api_version = 1, \
+	.init = init_##ID_UPPER, \
+	.cleanup = cleanup_##ID_UPPER, \
+	.scan = scan_##ID_UPPER, \
+	.dev_list = dev_list_##ID_UPPER, \
+	.dev_clear = dev_clear_##ID_UPPER, \
+	.config_get = NULL, \
+	.config_set = config_set, \
+	.config_list = config_list, \
+	.dev_open = std_serial_dev_open, \
+	.dev_close = std_serial_dev_close, \
+	.dev_acquisition_start = dev_acquisition_start_##ID_UPPER, \
+	.dev_acquisition_stop = dev_acquisition_stop, \
+	.priv = NULL, \
+};
+
+DRV(mic_98581, MIC_98581, "mic-98581", "MIC 98581")
+DRV(mic_98583, MIC_98583, "mic-98583", "MIC 98583")
diff --git a/hardware/mic-985xx/protocol.c b/hardware/mic-985xx/protocol.c
new file mode 100644
index 0000000..ce5f020
--- /dev/null
+++ b/hardware/mic-985xx/protocol.c
@@ -0,0 +1,234 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "protocol.h"
+
+static int mic_send(struct sr_serial_dev_inst *serial, const char *cmd)
+{
+	int ret;
+
+	if ((ret = serial_write(serial, cmd, strlen(cmd))) < 0) {
+		sr_err("Error sending '%s' command: %d.", cmd, ret);
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+SR_PRIV int mic_cmd_get_device_info(struct sr_serial_dev_inst *serial)
+{
+	return mic_send(serial, "I\r");
+}
+
+static int mic_cmd_set_realtime_mode(struct sr_serial_dev_inst *serial)
+{
+	return mic_send(serial, "S 1 M 2 32 3\r");
+}
+
+SR_PRIV gboolean packet_valid_temp(const uint8_t *buf)
+{
+	if (buf[0] != 'v' || buf[1] != ' ' || buf[5] != '\r')
+		return FALSE;
+
+	if (!isdigit(buf[2]) || !isdigit(buf[3]) || !isdigit(buf[4]))
+		return FALSE;
+
+	return TRUE;
+}
+
+SR_PRIV gboolean packet_valid_temp_hum(const uint8_t *buf)
+{
+	if (buf[0] != 'v' || buf[1] != ' ' || buf[5] != ' ' || buf[9] != '\r')
+		return FALSE;
+
+	if (!isdigit(buf[2]) || !isdigit(buf[3]) || !isdigit(buf[4]))
+		return FALSE;
+
+	if (!isdigit(buf[6]) || !isdigit(buf[7]) || !isdigit(buf[8]))
+		return FALSE;
+
+	return TRUE;
+}
+
+static int packet_parse(const char *buf, int idx, float *temp, float *humidity)
+{
+	char tmp[4];
+
+	/* Packet format MIC98581: "v ttt\r". */
+	/* Packet format MIC98583: "v ttt hhh\r". */
+
+	/* TODO: Sanity check on buf. For now we assume well-formed ASCII. */
+
+	tmp[3] = '\0';
+
+	strncpy((char *)&tmp, &buf[2], 3);
+	*temp = g_ascii_strtoull((const char *)&tmp, NULL, 10) / 10;
+
+	if (mic_devs[idx].has_humidity) {
+		strncpy((char *)&tmp, &buf[6], 3);
+		*humidity = g_ascii_strtoull((const char *)&tmp, NULL, 10) / 10;
+	}
+
+	return SR_OK;
+}
+
+static int handle_packet(const uint8_t *buf, struct sr_dev_inst *sdi, int idx)
+{
+	float temperature, humidity;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_analog analog;
+	struct dev_context *devc;
+	GSList *l;
+	int ret;
+
+	(void)idx;
+
+	devc = sdi->priv;
+
+	ret = packet_parse((const char *)buf, idx, &temperature, &humidity);
+	if (ret < 0) {
+		sr_err("Failed to parse packet.");
+		return SR_ERR;
+	}
+
+	/* Clear 'analog', otherwise it'll contain random garbage. */
+	memset(&analog, 0, sizeof(struct sr_datafeed_analog));
+
+	/* Common values for both channels. */
+	packet.type = SR_DF_ANALOG;
+	packet.payload = &analog;
+	analog.num_samples = 1;
+
+	/* Temperature. */
+	l = g_slist_copy(sdi->channels);
+	l = g_slist_remove_link(l, g_slist_nth(l, 1));
+	analog.channels = l;
+	analog.mq = SR_MQ_TEMPERATURE;
+	analog.unit = SR_UNIT_CELSIUS; /* TODO: Use C/F correctly. */
+	analog.data = &temperature;
+	sr_session_send(devc->cb_data, &packet);
+	g_slist_free(l);
+
+	/* Humidity. */
+	if (mic_devs[idx].has_humidity) {
+		l = g_slist_copy(sdi->channels);
+		l = g_slist_remove_link(l, g_slist_nth(l, 0));
+		analog.channels = l;
+		analog.mq = SR_MQ_RELATIVE_HUMIDITY;
+		analog.unit = SR_UNIT_PERCENTAGE;
+		analog.data = &humidity;
+		sr_session_send(devc->cb_data, &packet);
+		g_slist_free(l);
+	}
+
+	devc->num_samples++;
+
+	return SR_OK;
+}
+
+static void handle_new_data(struct sr_dev_inst *sdi, int idx)
+{
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+	int len, i, offset = 0;
+
+	devc = sdi->priv;
+	serial = sdi->conn;
+
+	/* Try to get as much data as the buffer can hold. */
+	len = SERIAL_BUFSIZE - devc->buflen;
+	len = serial_read(serial, devc->buf + devc->buflen, len);
+	if (len < 1) {
+		sr_err("Serial port read error: %d.", len);
+		return;
+	}
+
+	devc->buflen += len;
+
+	/* Now look for packets in that data. */
+	while ((devc->buflen - offset) >= mic_devs[idx].packet_size) {
+		if (mic_devs[idx].packet_valid(devc->buf + offset)) {
+			handle_packet(devc->buf + offset, sdi, idx);
+			offset += mic_devs[idx].packet_size;
+		} else {
+			offset++;
+		}
+	}
+
+	/* If we have any data left, move it to the beginning of our buffer. */
+	for (i = 0; i < devc->buflen - offset; i++)
+		devc->buf[i] = devc->buf[offset + i];
+	devc->buflen -= offset;
+}
+
+static int receive_data(int fd, int revents, int idx, void *cb_data)
+{
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+	int64_t t;
+	static gboolean first_time = TRUE;
+	struct sr_serial_dev_inst *serial;
+
+	(void)fd;
+
+	if (!(sdi = cb_data))
+		return TRUE;
+
+	if (!(devc = sdi->priv))
+		return TRUE;
+
+	serial = sdi->conn;
+
+	if (revents == G_IO_IN) {
+		/* New data arrived. */
+		handle_new_data(sdi, idx);
+	} else {
+		/* Timeout. */
+		if (first_time) {
+			mic_cmd_set_realtime_mode(serial);
+			first_time = FALSE;
+		}
+	}
+
+	if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
+		sr_info("Requested number of samples reached.");
+		sdi->driver->dev_acquisition_stop(sdi, cb_data);
+		return TRUE;
+	}
+
+	if (devc->limit_msec) {
+		t = (g_get_monotonic_time() - devc->starttime) / 1000;
+		if (t > (int64_t)devc->limit_msec) {
+			sr_info("Requested time limit reached.");
+			sdi->driver->dev_acquisition_stop(sdi, cb_data);
+			return TRUE;
+		}
+	}
+
+	return TRUE;
+}
+
+#define RECEIVE_DATA(ID_UPPER) \
+SR_PRIV int receive_data_##ID_UPPER(int fd, int revents, void *cb_data) { \
+	return receive_data(fd, revents, ID_UPPER, cb_data); }
+
+/* Driver-specific receive_data() wrappers */
+RECEIVE_DATA(MIC_98581)
+RECEIVE_DATA(MIC_98583)
diff --git a/hardware/mic-985xx/protocol.h b/hardware/mic-985xx/protocol.h
new file mode 100644
index 0000000..279cca5
--- /dev/null
+++ b/hardware/mic-985xx/protocol.h
@@ -0,0 +1,87 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef LIBSIGROK_HARDWARE_MIC_985XX_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_MIC_985XX_PROTOCOL_H
+
+#include <stdint.h>
+#include <string.h>
+#include <ctype.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "mic-985xx"
+
+/* Note: When adding entries here, don't forget to update MIC_DEV_COUNT. */
+enum {
+	MIC_98581,
+	MIC_98583,
+};
+
+#define MIC_DEV_COUNT 2
+
+struct mic_dev_info {
+	char *vendor;
+	char *device;
+	char *conn;
+	uint32_t max_sample_points;
+	gboolean has_temperature;
+	gboolean has_humidity;
+	uint8_t packet_size;
+	gboolean (*packet_valid)(const uint8_t *);
+	struct sr_dev_driver *di;
+	int (*receive_data)(int, int, void *);
+};
+
+extern SR_PRIV const struct mic_dev_info mic_devs[MIC_DEV_COUNT];
+
+#define SERIAL_BUFSIZE 256
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+	/** The current sampling limit (in number of samples). */
+	uint64_t limit_samples;
+
+	/** The current sampling limit (in ms). */
+	uint64_t limit_msec;
+
+	/** Opaque pointer passed in by the frontend. */
+	void *cb_data;
+
+	/** The current number of already received samples. */
+	uint64_t num_samples;
+
+	int64_t starttime;
+
+	uint8_t buf[SERIAL_BUFSIZE];
+	int bufoffset;
+	int buflen;
+};
+
+SR_PRIV gboolean packet_valid_temp(const uint8_t *buf);
+SR_PRIV gboolean packet_valid_temp_hum(const uint8_t *buf);
+
+SR_PRIV int receive_data_MIC_98581(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_MIC_98583(int fd, int revents, void *cb_data);
+
+SR_PRIV int mic_cmd_get_device_info(struct sr_serial_dev_inst *serial);
+
+#endif
diff --git a/hardware/norma-dmm/api.c b/hardware/norma-dmm/api.c
new file mode 100644
index 0000000..6860a78
--- /dev/null
+++ b/hardware/norma-dmm/api.c
@@ -0,0 +1,305 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Matthias Heidbrink <m-sigrok at heidbrink.biz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "protocol.h"
+
+static const int32_t hwopts[] = {
+	SR_CONF_CONN,
+	SR_CONF_SERIALCOMM,
+};
+
+static const int32_t hwcaps[] = {
+	SR_CONF_MULTIMETER,
+	SR_CONF_LIMIT_SAMPLES,
+	SR_CONF_LIMIT_MSEC,
+	SR_CONF_CONTINUOUS,
+};
+
+#define BUF_MAX 50
+
+#define SERIALCOMM "4800/8n1/dtr=1/rts=0/flow=1"
+
+SR_PRIV struct sr_dev_driver norma_dmm_driver_info;
+static struct sr_dev_driver *di = &norma_dmm_driver_info;
+
+static int init(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+	struct sr_dev_inst *sdi;
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_config *src;
+	struct sr_channel *ch;
+	struct sr_serial_dev_inst *serial;
+	GSList *l, *devices;
+	int len, cnt;
+	const char *conn, *serialcomm;
+	char *buf;
+	char fmttype[10];
+	char req[10];
+	int auxtype;
+
+	devices = NULL;
+	drvc = di->priv;
+	drvc->instances = NULL;
+	conn = serialcomm = NULL;
+
+	for (l = options; l; l = l->next) {
+		src = l->data;
+		switch (src->key) {
+		case SR_CONF_CONN:
+			conn = g_variant_get_string(src->data, NULL);
+			break;
+		case SR_CONF_SERIALCOMM:
+			serialcomm = g_variant_get_string(src->data, NULL);
+			break;
+		}
+	}
+	if (!conn)
+		return NULL;
+	if (!serialcomm)
+		serialcomm = SERIALCOMM;
+
+	if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+		return NULL;
+
+	if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+		return NULL;
+
+	serial_flush(serial);
+
+	if (!(buf = g_try_malloc(BUF_MAX))) {
+		sr_err("Serial buffer malloc failed.");
+		return NULL;
+	}
+
+	snprintf(req, sizeof(req), "%s\r\n",
+		 nmadmm_requests[NMADMM_REQ_IDN].req_str);
+	for (cnt = 0; cnt < 7; cnt++) {
+		if (serial_write(serial, req, strlen(req)) == -1) {
+			sr_err("Unable to send identification request: %d %s.",
+			       errno, strerror(errno));
+			return NULL;
+		}
+		len = BUF_MAX;
+		serial_readline(serial, &buf, &len, 1500);
+		if (!len)
+			continue;
+		buf[BUF_MAX - 1] = '\0';
+
+		/* Match ID string, e.g. "1834 065 V1.06,IF V1.02" (DM950) */
+		if (g_regex_match_simple("^1834 [^,]*,IF V*", (char *)buf, 0, 0)) {
+			auxtype = xgittoint(buf[7]);
+				// TODO: Will this work with non-DM950?
+			snprintf(fmttype, sizeof(fmttype), "DM9%d0", auxtype);
+			sr_spew("Norma %s DMM %s detected!", fmttype, &buf[9]);
+
+			if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE,
+						"Norma", fmttype, buf + 9)))
+				return NULL;
+			if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+				sr_err("Device context malloc failed.");
+				return NULL;
+			}
+			devc->type = auxtype;
+			devc->version = g_strdup(&buf[9]);
+			devc->elapsed_msec = g_timer_new();
+
+			sdi->conn = serial;
+			sdi->priv = devc;
+			sdi->driver = di;
+			if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE,
+				"P1")))
+				return NULL;
+			sdi->channels = g_slist_append(sdi->channels, ch);
+			drvc->instances = g_slist_append(drvc->instances, sdi);
+			devices = g_slist_append(devices, sdi);
+			break;
+		}
+
+		/*
+		 * The interface of the DM9x0 contains a cap that needs to
+		 * charge for up to 10s before the interface works, if not
+		 * powered externally. Therefore wait a little to improve
+		 * chances.
+		 */
+		if (cnt == 3) {
+			sr_info("Waiting 5s to allow interface to settle.");
+			g_usleep(5 * 1000 * 1000);
+		}
+	}
+
+	g_free(buf);
+
+	serial_close(serial);
+	if (!devices)
+		sr_serial_dev_inst_free(serial);
+
+	return devices;
+}
+
+static GSList *dev_list(void)
+{
+	return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+
+	std_serial_dev_close(sdi);
+
+	/* Free dynamically allocated resources. */
+	if ((devc = sdi->priv) && devc->version) {
+		g_free(devc->version);
+		devc->version = NULL;
+		g_timer_destroy(devc->elapsed_msec);
+	}
+
+	return SR_OK;
+}
+
+static int cleanup(void)
+{
+	return std_dev_clear(di, NULL);
+}
+
+static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+
+	(void)cg;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!(devc = sdi->priv)) {
+		sr_err("sdi->priv was NULL.");
+		return SR_ERR_BUG;
+	}
+
+	switch (key) {
+	case SR_CONF_LIMIT_MSEC:
+		/* TODO: not yet implemented */
+		if (g_variant_get_uint64(data) == 0) {
+			sr_err("LIMIT_MSEC can't be 0.");
+			return SR_ERR;
+		}
+		devc->limit_msec = g_variant_get_uint64(data);
+		sr_dbg("Setting time limit to %" PRIu64 "ms.",
+		       devc->limit_msec);
+		break;
+	case SR_CONF_LIMIT_SAMPLES:
+		devc->limit_samples = g_variant_get_uint64(data);
+		sr_dbg("Setting sample limit to %" PRIu64 ".",
+		       devc->limit_samples);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	(void)sdi;
+	(void)cg;
+
+	switch (key) {
+	case SR_CONF_SCAN_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+		break;
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi,
+				    void *cb_data)
+{
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+
+	if (!sdi || !cb_data || !(devc = sdi->priv))
+		return SR_ERR_BUG;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	devc->cb_data = cb_data;
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	/* Start timer, if required. */
+	if (devc->limit_msec)
+		g_timer_start(devc->elapsed_msec);
+
+	/* Poll every 100ms, or whenever some data comes in. */
+	serial = sdi->conn;
+	serial_source_add(serial, G_IO_IN, 100, norma_dmm_receive_data,
+		      (void *)sdi);
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct dev_context *devc;
+
+	/* Stop timer, if required. */
+	if (sdi && (devc = sdi->priv) && devc->limit_msec)
+		g_timer_stop(devc->elapsed_msec);
+
+	return std_serial_dev_acquisition_stop(sdi, cb_data, dev_close,
+			sdi->conn, LOG_PREFIX);
+}
+
+SR_PRIV struct sr_dev_driver norma_dmm_driver_info = {
+	.name = "norma-dmm",
+	.longname = "Norma DM9x0 / Siemens B102x DMMs",
+	.api_version = 1,
+	.init = init,
+	.cleanup = cleanup,
+	.scan = scan,
+	.dev_list = dev_list,
+	.dev_clear = NULL,
+	.config_get = NULL,
+	.config_set = config_set,
+	.config_list = config_list,
+	.dev_open = std_serial_dev_open,
+	.dev_close = dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/norma-dmm/protocol.c b/hardware/norma-dmm/protocol.c
new file mode 100644
index 0000000..8e1466a
--- /dev/null
+++ b/hardware/norma-dmm/protocol.c
@@ -0,0 +1,426 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Matthias Heidbrink <m-sigrok at heidbrink.biz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "protocol.h"
+
+SR_PRIV const struct nmadmm_req nmadmm_requests[] = {
+	{ NMADMM_REQ_IDN, "IDN?" },
+	{ NMADMM_REQ_IDN, "STATUS?" },
+	{ 0, NULL },
+};
+
+static int nma_send_req(const struct sr_dev_inst *sdi, int req, char *params)
+{
+	struct sr_serial_dev_inst *serial;
+	struct dev_context *devc;
+	char buf[NMADMM_BUFSIZE];
+	int len;
+
+	if (!sdi || !(serial = sdi->conn) || !(devc = sdi->priv))
+		return SR_ERR_BUG;
+
+	len = snprintf(buf, sizeof(buf), "%s%s\r\n",
+		nmadmm_requests[req].req_str, params ? params : "");
+
+	sr_spew("Sending request: '%s'.", buf);
+
+	devc->last_req = req;
+	devc->last_req_pending = TRUE;
+
+	if (serial_write(serial, buf, len) == -1) {
+		sr_err("Unable to send request: %d %s.",
+			errno, strerror(errno));
+		devc->last_req_pending = FALSE;
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+/**
+ * Convert hexadecimal digit to int.
+ *
+ * @param[in] xgit Hexadecimal digit to convert.
+ * @return Int value of xgit (0 on invalid xgit).
+ */
+SR_PRIV int xgittoint(char xgit)
+{
+	if ((xgit >= '0') && (xgit <= '9'))
+		return xgit - '0';
+	xgit = tolower(xgit);
+	if ((xgit >= 'a') && (xgit <= 'f'))
+		return xgit - 'a';
+	return 0;
+}
+
+/**
+ * Process received line. It consists of 20 hex digits + \\r\\n,
+ * e.g. '08100400018100400000'.
+ */
+static void nma_process_line(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	int pos, flags;
+	int vt, range;	/* Measurement value type, range in device format */
+	int mmode, devstat;	/* Measuring mode, device status */
+	float value;	/* Measured value */
+	float scale;	/* Scaling factor depending on range and function */
+	struct sr_datafeed_analog analog;
+	struct sr_datafeed_packet packet;
+
+	devc = sdi->priv;
+
+	devc->buf[20] = '\0';
+
+	sr_spew("Received line '%s'.", devc->buf);
+
+	/* Check line. */
+	if (strlen((const char *)devc->buf) != 20) {
+		sr_err("line: Invalid status '%s', must be 20 hex digits.",
+		       devc->buf);
+		devc->buflen = 0;
+		return;
+	}
+
+	for (pos = 0; pos < 20; pos++) {
+		if (!isxdigit(devc->buf[pos])) {
+			sr_err("line: Expected hex digit in '%s' at pos %d!",
+				devc->buf, pos);
+			devc->buflen = 0;
+			return;
+		}
+	}
+
+	/* Start decoding. */
+	value = 0.0;
+	scale = 1.0;
+	memset(&analog, 0, sizeof(analog));
+
+	/*
+	 * The numbers are hex digits, starting from 0.
+	 * 0: Keyboard status, currently not interesting.
+	 * 1: Central switch status, currently not interesting.
+	 * 2: Type of measured value.
+	 */
+	vt = xgittoint(devc->buf[2]);
+	switch (vt) {
+	case 0:
+		analog.mq = SR_MQ_VOLTAGE;
+		break;
+	case 1:
+		analog.mq = SR_MQ_CURRENT;	/* 2A */
+		break;
+	case 2:
+		analog.mq = SR_MQ_RESISTANCE;
+		break;
+	case 3:
+		analog.mq = SR_MQ_CAPACITANCE;
+		break;
+	case 4:
+		analog.mq = SR_MQ_TEMPERATURE;
+		break;
+	case 5:
+		analog.mq = SR_MQ_FREQUENCY;
+		break;
+	case 6:
+		analog.mq = SR_MQ_CURRENT;	/* 10A */
+		break;
+	case 7:
+		analog.mq = SR_MQ_GAIN;		/* TODO: Scale factor */
+		break;
+	case 8:
+		analog.mq = SR_MQ_GAIN;		/* Percentage */
+		scale /= 100.0;
+		break;
+	case 9:
+		analog.mq = SR_MQ_GAIN;		/* dB */
+		scale /= 100.0;
+		break;
+	default:
+		sr_err("Unknown value type: 0x%02x.", vt);
+		break;
+	}
+
+	/* 3: Measurement range for measured value */
+	range = xgittoint(devc->buf[3]);
+	switch (vt) {
+	case 0: /* V */
+		scale *= pow(10.0, range - 5);
+		break;
+	case 1: /* A */
+		scale *= pow(10.0, range - 7);
+		break;
+	case 2: /* Ω */
+		scale *= pow(10.0, range - 2);
+		break;
+	case 3: /* F */
+		scale *= pow(10.0, range - 12);
+		break;
+	case 4: /* °C */
+		scale *= pow(10.0, range - 1);
+		break;
+	case 5: /* Hz */
+		scale *= pow(10.0, range - 2);
+		break;
+	// No default, other value types have fixed display format.
+	}
+
+	/* 5: Sign and 1st digit */
+	flags = xgittoint(devc->buf[5]);
+	value = (flags & 0x03);
+	if (flags & 0x04)
+		scale *= -1;
+
+	/* 6-9: 2nd-4th digit */
+	for (pos = 6; pos < 10; pos++)
+		value = value * 10 + xgittoint(devc->buf[pos]);
+	value *= scale;
+
+	/* 10: Display counter */
+	mmode = xgittoint(devc->buf[10]);
+	switch (mmode) {
+	case 0: /* Frequency */
+		analog.unit = SR_UNIT_HERTZ;
+		break;
+	case 1: /* V TRMS, only type 5 */
+		analog.unit = SR_UNIT_VOLT;
+		analog.mqflags |= (SR_MQFLAG_AC | SR_MQFLAG_DC | SR_MQFLAG_RMS);
+		break;
+	case 2: /* V AC */
+		analog.unit = SR_UNIT_VOLT;
+		analog.mqflags |= SR_MQFLAG_AC;
+		if (devc->type >= 3)
+			analog.mqflags |= SR_MQFLAG_RMS;
+		break;
+	case 3: /* V DC */
+		analog.unit = SR_UNIT_VOLT;
+		analog.mqflags |= SR_MQFLAG_DC;
+		break;
+	case 4: /* Ohm */
+		analog.unit = SR_UNIT_OHM;
+		break;
+	case 5: /* Continuity */
+		analog.unit = SR_UNIT_BOOLEAN;
+		analog.mq = SR_MQ_CONTINUITY;
+		/* TODO: Continuity handling is a bit odd in libsigrok. */
+		break;
+	case 6: /* Degree Celsius */
+		analog.unit = SR_UNIT_CELSIUS;
+		break;
+	case 7: /* Capacity */
+		analog.unit = SR_UNIT_FARAD;
+		break;
+	case 8: /* Current DC */
+		analog.unit = SR_UNIT_AMPERE;
+		analog.mqflags |= SR_MQFLAG_DC;
+		break;
+	case 9: /* Current AC */
+		analog.unit = SR_UNIT_AMPERE;
+		analog.mqflags |= SR_MQFLAG_AC;
+		if (devc->type >= 3)
+			analog.mqflags |= SR_MQFLAG_RMS;
+		break;
+	case 0xa: /* Current TRMS, only type 5 */
+		analog.unit = SR_UNIT_AMPERE;
+		analog.mqflags |= (SR_MQFLAG_AC | SR_MQFLAG_DC | SR_MQFLAG_RMS);
+		break;
+	case 0xb: /* Diode */
+		analog.unit = SR_UNIT_VOLT;
+		analog.mqflags |= (SR_MQFLAG_DIODE | SR_MQFLAG_DC);
+		break;
+	default:
+		sr_err("Unknown mmode: 0x%02x.", mmode);
+		break;
+	}
+
+	/* 11: Device status */
+	devstat = xgittoint(devc->buf[11]);
+
+	switch (devstat) {
+	case 1: /* Normal measurement */
+		break;
+	case 2: /* Input loop (limit, reference values) */
+		break;
+	case 3: /* TRANS/SENS */
+		break;
+	case 4: /* Error */
+		sr_err("Device error. Fuse?"); /* TODO: Really abort? */
+		devc->buflen = 0;
+		return;	/* Cannot continue. */
+	default:
+		sr_err("Unknown device status: 0x%02x", devstat);
+		break;
+	}
+
+	/* 12-19: Flags and display symbols */
+	/* 12, 13 */
+	flags = (xgittoint(devc->buf[12]) << 8) | xgittoint(devc->buf[13]);
+	/* 0x80: PRINT TODO: Stop polling when discovered? */
+	/* 0x40: EXTR */
+	if (analog.mq == SR_MQ_CONTINUITY) {
+		if (flags & 0x20)
+			value = 1.0; /* Beep */
+		else
+			value = 0.0;
+	}
+	/* 0x10: AVG */
+	/* 0x08: Diode */
+	if (flags & 0x04) /* REL */
+		analog.mqflags |= SR_MQFLAG_RELATIVE;
+	/* 0x02: SHIFT	*/
+	if (flags & 0x01) /* % */
+		analog.unit = SR_UNIT_PERCENTAGE;
+
+	/* 14, 15 */
+	flags = (xgittoint(devc->buf[14]) << 8) | xgittoint(devc->buf[15]);
+	if (!(flags & 0x80))	/* MAN: Manual range */
+		analog.mqflags |= SR_MQFLAG_AUTORANGE;
+	if (flags & 0x40) /* LOBATT1: Low battery, measurement still within specs */
+		devc->lowbatt = 1;
+	/* 0x20: PEAK */
+	/* 0x10: COUNT */
+	if (flags & 0x08)	/* HOLD */
+		analog.mqflags |= SR_MQFLAG_HOLD;
+	/* 0x04: LIMIT	*/
+	if (flags & 0x02) 	/* MAX */
+		analog.mqflags |= SR_MQFLAG_MAX;
+	if (flags & 0x01) 	/* MIN */
+		analog.mqflags |= SR_MQFLAG_MIN;
+
+	/* 16, 17 */
+	flags = (xgittoint(devc->buf[16]) << 8) | xgittoint(devc->buf[17]);
+	/* 0xe0: undefined */
+	if (flags & 0x10) { /* LOBATT2: Low battery, measurement inaccurate */
+		devc->lowbatt = 2;
+		sr_warn("Low battery, measurement quality degraded!");
+	}
+	/* 0x08: SCALED */
+	/* 0x04: RATE (=lower resolution, allows higher rata rate up to 10/s. */
+	/* 0x02: Current clamp */
+	if (flags & 0x01) { /* dB */
+		/*
+		 * TODO: The Norma has an adjustable dB reference value. If
+		 * changed from default, this is not correct.
+		 */
+		if (analog.unit == SR_UNIT_VOLT)
+			analog.unit = SR_UNIT_DECIBEL_VOLT;
+		else
+			analog.unit = SR_UNIT_UNITLESS;
+	}
+
+	/* 18, 19 */
+	/* flags = (xgittoint(devc->buf[18]) << 8) | xgittoint(devc->buf[19]); */
+	/* 0x80: Undefined. */
+	/* 0x40: Remote mode, keyboard locked */
+	/* 0x38: Undefined. */
+	/* 0x04: MIN > MAX */
+	/* 0x02: Measured value < Min */
+	/* 0x01: Measured value > Max */
+
+	/* 4: Flags. Evaluating this after setting value! */
+	flags = xgittoint(devc->buf[4]);
+	if (flags & 0x04) /* Invalid value */
+	    value = NAN;
+	else if (flags & 0x01) /* Overload */
+	    value =  INFINITY;
+	if (flags & 0x02) { /* Duplicate value, has been sent before. */
+	    sr_spew("Duplicate value, dismissing!");
+	    devc->buflen = 0;
+	    return;
+	}
+
+	sr_spew("range=%d/scale=%f/value=%f", range,
+		(double)scale, (double)value);
+
+	/* Finish and send packet. */
+	analog.channels = sdi->channels;
+	analog.num_samples = 1;
+	analog.data = &value;
+
+	memset(&packet, 0, sizeof(packet));
+	packet.type = SR_DF_ANALOG;
+	packet.payload = &analog;
+	sr_session_send(devc->cb_data, &packet);
+
+	/* Finish processing. */
+	devc->num_samples++;
+	devc->buflen = 0;
+}
+
+SR_PRIV int norma_dmm_receive_data(int fd, int revents, void *cb_data)
+{
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+	int len;
+	gboolean terminating;
+	gdouble elapsed_s;
+
+	(void)fd;
+
+	if (!(sdi = cb_data))
+		return TRUE;
+
+	if (!(devc = sdi->priv))
+		return TRUE;
+
+	serial = sdi->conn;
+	if (revents == G_IO_IN) {
+		/* Serial data arrived. */
+		while (NMADMM_BUFSIZE - devc->buflen - 1 > 0) {
+			len = serial_read(serial, devc->buf + devc->buflen, 1);
+			if (len < 1)
+				break;
+			devc->buflen += len;
+			*(devc->buf + devc->buflen) = '\0';
+			if (*(devc->buf + devc->buflen - 1) == '\n') {
+				/*
+				 * TODO: According to specs, should be \r, but
+				 * then we'd have to get rid of the \n.
+				 */
+				devc->last_req_pending = FALSE;
+				nma_process_line(sdi);
+				break;
+			}
+		}
+	}
+
+	/* If number of samples or time limit reached, stop acquisition. */
+	terminating = FALSE;
+	if (devc->limit_samples && (devc->num_samples >= devc->limit_samples)) {
+		sdi->driver->dev_acquisition_stop(sdi, cb_data);
+		terminating = TRUE;
+	}
+
+	if (devc->limit_msec) {
+		elapsed_s = g_timer_elapsed(devc->elapsed_msec, NULL);
+		if ((elapsed_s * 1000) >= devc->limit_msec) {
+			sdi->driver->dev_acquisition_stop(sdi, cb_data);
+			terminating = TRUE;
+		}
+	}
+
+	/* Request next package. */
+	if (!terminating && !devc->last_req_pending) {
+		if (nma_send_req(sdi, NMADMM_REQ_STATUS, NULL) != SR_OK)
+			return FALSE;
+	}
+
+	return TRUE;
+}
diff --git a/hardware/norma-dmm/protocol.h b/hardware/norma-dmm/protocol.h
new file mode 100644
index 0000000..2ed0e25
--- /dev/null
+++ b/hardware/norma-dmm/protocol.h
@@ -0,0 +1,79 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Matthias Heidbrink <m-sigrok at heidbrink.biz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_NORMA_DMM_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_NORMA_DMM_PROTOCOL_H
+
+#include <stdint.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <math.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "norma-dmm"
+
+#define NMADMM_BUFSIZE  256
+
+/** Norma DMM request types (used ones only, the DMMs support about 50). */
+enum {
+	NMADMM_REQ_IDN = 0,	/**< Request identity */
+	NMADMM_REQ_STATUS,	/**< Request device status (value + ...) */
+};
+
+/** Defines requests used to communicate with device. */
+struct nmadmm_req {
+	int req_type;		/**< Request type. */
+	const char *req_str;	/**< Request string. */
+};
+
+/** Strings for requests. */
+extern const struct nmadmm_req nmadmm_requests[];
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+	/* Model-specific information */
+	char *version;		/**< Version string */
+	int type;		/**< DM9x0, e.g. 5 = DM950 */
+
+	/* Acquisition settings */
+	uint64_t limit_samples;	/**< Target number of samples */
+	uint64_t limit_msec;	/**< Target sampling time */
+
+	/* Opaque pointer passed in by frontend. */
+	void *cb_data;
+
+	/* Operational state */
+	int last_req;			/**< Last request. */
+	gboolean last_req_pending;	/**< Last request not answered yet. */
+	int lowbatt;			/**< Low battery. 1=low, 2=critical. */
+
+	/* Temporary state across callbacks */
+	uint64_t num_samples;		/**< Current #samples. */
+	GTimer *elapsed_msec;		/**< Used for limit_msec */
+	uint8_t buf[NMADMM_BUFSIZE];	/**< Buffer for read callback */
+	int buflen;			/**< Data len in buf */
+};
+
+SR_PRIV int norma_dmm_receive_data(int fd, int revents, void *cb_data);
+SR_PRIV int xgittoint(char xgit);
+
+#endif
diff --git a/hardware/openbench-logic-sniffer/api.c b/hardware/openbench-logic-sniffer/api.c
new file mode 100644
index 0000000..b99d8e7
--- /dev/null
+++ b/hardware/openbench-logic-sniffer/api.c
@@ -0,0 +1,599 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "protocol.h"
+#include <libserialport.h>
+
+#define SERIALCOMM "115200/8n1"
+
+static const int32_t hwopts[] = {
+	SR_CONF_CONN,
+	SR_CONF_SERIALCOMM,
+};
+
+static const int32_t hwcaps[] = {
+	SR_CONF_LOGIC_ANALYZER,
+	SR_CONF_SAMPLERATE,
+	SR_CONF_TRIGGER_TYPE,
+	SR_CONF_CAPTURE_RATIO,
+	SR_CONF_LIMIT_SAMPLES,
+	SR_CONF_EXTERNAL_CLOCK,
+	SR_CONF_PATTERN_MODE,
+	SR_CONF_SWAP,
+	SR_CONF_RLE,
+};
+
+#define STR_PATTERN_NONE     "None"
+#define STR_PATTERN_EXTERNAL "External"
+#define STR_PATTERN_INTERNAL "Internal"
+
+/* Supported methods of test pattern outputs */
+enum {
+	/**
+	 * Capture pins 31:16 (unbuffered wing) output a test pattern
+	 * that can captured on pins 0:15.
+	 */
+	PATTERN_EXTERNAL,
+
+	/** Route test pattern internally to capture buffer. */
+	PATTERN_INTERNAL,
+};
+
+static const char *patterns[] = {
+	STR_PATTERN_NONE,
+	STR_PATTERN_EXTERNAL,
+	STR_PATTERN_INTERNAL,
+};
+
+/* Channels are numbered 0-31 (on the PCB silkscreen). */
+SR_PRIV const char *ols_channel_names[NUM_CHANNELS + 1] = {
+	"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12",
+	"13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23",
+	"24", "25", "26", "27", "28", "29", "30", "31",
+	NULL,
+};
+
+/* Default supported samplerates, can be overridden by device metadata. */
+static const uint64_t samplerates[] = {
+	SR_HZ(10),
+	SR_MHZ(200),
+	SR_HZ(1),
+};
+
+SR_PRIV struct sr_dev_driver ols_driver_info;
+static struct sr_dev_driver *di = &ols_driver_info;
+
+static int init(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+	struct sr_config *src;
+	struct sr_dev_inst *sdi;
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_channel *ch;
+	struct sr_serial_dev_inst *serial;
+	GPollFD probefd;
+	GSList *l, *devices;
+	int ret, i;
+	const char *conn, *serialcomm;
+	char buf[8];
+
+	drvc = di->priv;
+
+	devices = NULL;
+
+	conn = serialcomm = NULL;
+	for (l = options; l; l = l->next) {
+		src = l->data;
+		switch (src->key) {
+		case SR_CONF_CONN:
+			conn = g_variant_get_string(src->data, NULL);
+			break;
+		case SR_CONF_SERIALCOMM:
+			serialcomm = g_variant_get_string(src->data, NULL);
+			break;
+		}
+	}
+	if (!conn)
+		return NULL;
+
+	if (serialcomm == NULL)
+		serialcomm = SERIALCOMM;
+
+	if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+		return NULL;
+
+	/* The discovery procedure is like this: first send the Reset
+	 * command (0x00) 5 times, since the device could be anywhere
+	 * in a 5-byte command. Then send the ID command (0x02).
+	 * If the device responds with 4 bytes ("OLS1" or "SLA1"), we
+	 * have a match.
+	 */
+	sr_info("Probing %s.", conn);
+	if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+		return NULL;
+
+	ret = SR_OK;
+	for (i = 0; i < 5; i++) {
+		if ((ret = send_shortcommand(serial, CMD_RESET)) != SR_OK) {
+			sr_err("Port %s is not writable.", conn);
+			break;
+		}
+	}
+	if (ret != SR_OK) {
+		serial_close(serial);
+		sr_err("Could not use port %s. Quitting.", conn);
+		return NULL;
+	}
+	send_shortcommand(serial, CMD_ID);
+
+	/* Wait 10ms for a response. */
+	g_usleep(10000);
+
+	sp_get_port_handle(serial->data, &probefd.fd);
+	probefd.events = G_IO_IN;
+	g_poll(&probefd, 1, 1);
+
+	if (probefd.revents != G_IO_IN)
+		return NULL;
+	if (serial_read_blocking(serial, buf, 4) != 4)
+		return NULL;
+	if (strncmp(buf, "1SLO", 4) && strncmp(buf, "1ALS", 4))
+		return NULL;
+
+	/* Definitely using the OLS protocol, check if it supports
+	 * the metadata command.
+	 */
+	send_shortcommand(serial, CMD_METADATA);
+	if (g_poll(&probefd, 1, 10) > 0) {
+		/* Got metadata. */
+		sdi = get_metadata(serial);
+		sdi->index = 0;
+		devc = sdi->priv;
+	} else {
+		/* Not an OLS -- some other board that uses the sump protocol. */
+		sr_info("Device does not support metadata.");
+		sdi = sr_dev_inst_new(0, SR_ST_INACTIVE,
+				"Sump", "Logic Analyzer", "v1.0");
+		sdi->driver = di;
+		for (i = 0; i < 32; i++) {
+			if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE,
+					ols_channel_names[i])))
+				return 0;
+			sdi->channels = g_slist_append(sdi->channels, ch);
+		}
+		devc = ols_dev_new();
+		sdi->priv = devc;
+	}
+	/* Configure samplerate and divider. */
+	if (ols_set_samplerate(sdi, DEFAULT_SAMPLERATE) != SR_OK)
+		sr_dbg("Failed to set default samplerate (%"PRIu64").",
+				DEFAULT_SAMPLERATE);
+	/* Clear trigger masks, values and stages. */
+	ols_configure_channels(sdi);
+	sdi->inst_type = SR_INST_SERIAL;
+	sdi->conn = serial;
+
+	drvc->instances = g_slist_append(drvc->instances, sdi);
+	devices = g_slist_append(devices, sdi);
+
+	serial_close(serial);
+
+	return devices;
+}
+
+static GSList *dev_list(void)
+{
+	return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int cleanup(void)
+{
+	return std_dev_clear(di, NULL);
+}
+
+static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+
+	(void)cg;
+
+	if (!sdi)
+		return SR_ERR_ARG;
+
+	devc = sdi->priv;
+	switch (id) {
+	case SR_CONF_SAMPLERATE:
+		*data = g_variant_new_uint64(devc->cur_samplerate);
+		break;
+	case SR_CONF_CAPTURE_RATIO:
+		*data = g_variant_new_uint64(devc->capture_ratio);
+		break;
+	case SR_CONF_LIMIT_SAMPLES:
+		*data = g_variant_new_uint64(devc->limit_samples);
+		break;
+	case SR_CONF_PATTERN_MODE:
+		if (devc->flag_reg & FLAG_EXTERNAL_TEST_MODE)
+			*data = g_variant_new_string(STR_PATTERN_EXTERNAL);
+		else if (devc->flag_reg & FLAG_INTERNAL_TEST_MODE)
+			*data = g_variant_new_string(STR_PATTERN_INTERNAL);
+		else
+			*data = g_variant_new_string(STR_PATTERN_NONE);
+		break;
+	case SR_CONF_RLE:
+		*data = g_variant_new_boolean(devc->flag_reg & FLAG_RLE ? TRUE : FALSE);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	uint16_t flag;
+	uint64_t tmp_u64;
+	int ret;
+	const char *stropt;
+
+	(void)cg;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	devc = sdi->priv;
+
+	switch (id) {
+	case SR_CONF_SAMPLERATE:
+		tmp_u64 = g_variant_get_uint64(data);
+		if (tmp_u64 < samplerates[0] || tmp_u64 > samplerates[1])
+			return SR_ERR_SAMPLERATE;
+		ret = ols_set_samplerate(sdi, g_variant_get_uint64(data));
+		break;
+	case SR_CONF_LIMIT_SAMPLES:
+		tmp_u64 = g_variant_get_uint64(data);
+		if (tmp_u64 < MIN_NUM_SAMPLES)
+			return SR_ERR;
+		devc->limit_samples = tmp_u64;
+		ret = SR_OK;
+		break;
+	case SR_CONF_CAPTURE_RATIO:
+		devc->capture_ratio = g_variant_get_uint64(data);
+		if (devc->capture_ratio < 0 || devc->capture_ratio > 100) {
+			devc->capture_ratio = 0;
+			ret = SR_ERR;
+		} else
+			ret = SR_OK;
+		break;
+	case SR_CONF_EXTERNAL_CLOCK:
+		if (g_variant_get_boolean(data)) {
+			sr_info("Enabling external clock.");
+			devc->flag_reg |= FLAG_CLOCK_EXTERNAL;
+		} else {
+			sr_info("Disabled external clock.");
+			devc->flag_reg &= ~FLAG_CLOCK_EXTERNAL;
+		}
+		ret = SR_OK;
+		break;
+	case SR_CONF_PATTERN_MODE:
+		stropt = g_variant_get_string(data, NULL);
+		ret = SR_OK;
+		flag = 0xffff;
+		if (!strcmp(stropt, STR_PATTERN_NONE)) {
+			sr_info("Disabling test modes.");
+			flag = 0x0000;
+		}else if (!strcmp(stropt, STR_PATTERN_INTERNAL)) {
+			sr_info("Enabling internal test mode.");
+			flag = FLAG_INTERNAL_TEST_MODE;
+		} else if (!strcmp(stropt, STR_PATTERN_EXTERNAL)) {
+			sr_info("Enabling external test mode.");
+			flag = FLAG_EXTERNAL_TEST_MODE;
+		} else {
+			ret = SR_ERR;
+		}
+		if (flag != 0xffff) {
+			devc->flag_reg &= ~(FLAG_INTERNAL_TEST_MODE | FLAG_EXTERNAL_TEST_MODE);
+			devc->flag_reg |= flag;
+		}
+		break;
+	case SR_CONF_SWAP:
+		if (g_variant_get_boolean(data)) {
+			sr_info("Enabling channel swapping.");
+			devc->flag_reg |= FLAG_SWAP_CHANNELS;
+		} else {
+			sr_info("Disabling channel swapping.");
+			devc->flag_reg &= ~FLAG_SWAP_CHANNELS;
+		}
+		ret = SR_OK;
+		break;
+
+	case SR_CONF_RLE:
+		if (g_variant_get_boolean(data)) {
+			sr_info("Enabling RLE.");
+			devc->flag_reg |= FLAG_RLE;
+		} else {
+			sr_info("Disabling RLE.");
+			devc->flag_reg &= ~FLAG_RLE;
+		}
+		ret = SR_OK;
+		break;
+	default:
+		ret = SR_ERR_NA;
+	}
+
+	return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	GVariant *gvar, *grange[2];
+	GVariantBuilder gvb;
+	int num_channels, i;
+
+	(void)cg;
+
+	switch (key) {
+	case SR_CONF_SCAN_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+		break;
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+		break;
+	case SR_CONF_SAMPLERATE:
+		g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
+		gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"), samplerates,
+				ARRAY_SIZE(samplerates), sizeof(uint64_t));
+		g_variant_builder_add(&gvb, "{sv}", "samplerate-steps", gvar);
+		*data = g_variant_builder_end(&gvb);
+		break;
+	case SR_CONF_TRIGGER_TYPE:
+		*data = g_variant_new_string(TRIGGER_TYPE);
+		break;
+	case SR_CONF_PATTERN_MODE:
+		*data = g_variant_new_strv(patterns, ARRAY_SIZE(patterns));
+		break;
+	case SR_CONF_LIMIT_SAMPLES:
+		if (!sdi)
+			return SR_ERR_ARG;
+		devc = sdi->priv;
+		if (devc->flag_reg & FLAG_RLE)
+			return SR_ERR_NA;
+		if (devc->max_samples == 0)
+			/* Device didn't specify sample memory size in metadata. */
+			return SR_ERR_NA;
+		/*
+		 * Channel groups are turned off if no channels in that group are
+		 * enabled, making more room for samples for the enabled group.
+		*/
+		ols_configure_channels(sdi);
+		num_channels = 0;
+		for (i = 0; i < 4; i++) {
+			if (devc->channel_mask & (0xff << (i * 8)))
+				num_channels++;
+		}
+		if (num_channels == 0) {
+			/* This can happen, but shouldn't cause too much drama.
+			 * However we can't continue because the code below would
+			 * divide by zero. */
+			break;
+		}
+		grange[0] = g_variant_new_uint64(MIN_NUM_SAMPLES);
+		grange[1] = g_variant_new_uint64(devc->max_samples / num_channels);
+		*data = g_variant_new_tuple(grange, 2);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int set_trigger(const struct sr_dev_inst *sdi, int stage)
+{
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+	uint8_t cmd, arg[4];
+
+	devc = sdi->priv;
+	serial = sdi->conn;
+
+	cmd = CMD_SET_TRIGGER_MASK + stage * 4;
+	arg[0] = devc->trigger_mask[stage] & 0xff;
+	arg[1] = (devc->trigger_mask[stage] >> 8) & 0xff;
+	arg[2] = (devc->trigger_mask[stage] >> 16) & 0xff;
+	arg[3] = (devc->trigger_mask[stage] >> 24) & 0xff;
+	if (send_longcommand(serial, cmd, arg) != SR_OK)
+		return SR_ERR;
+
+	cmd = CMD_SET_TRIGGER_VALUE + stage * 4;
+	arg[0] = devc->trigger_value[stage] & 0xff;
+	arg[1] = (devc->trigger_value[stage] >> 8) & 0xff;
+	arg[2] = (devc->trigger_value[stage] >> 16) & 0xff;
+	arg[3] = (devc->trigger_value[stage] >> 24) & 0xff;
+	if (send_longcommand(serial, cmd, arg) != SR_OK)
+		return SR_ERR;
+
+	cmd = CMD_SET_TRIGGER_CONFIG + stage * 4;
+	arg[0] = arg[1] = arg[3] = 0x00;
+	arg[2] = stage;
+	if (stage == devc->num_stages)
+		/* Last stage, fire when this one matches. */
+		arg[3] |= TRIGGER_START;
+	if (send_longcommand(serial, cmd, arg) != SR_OK)
+		return SR_ERR;
+
+	return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi,
+		void *cb_data)
+{
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+	uint16_t samplecount, readcount, delaycount;
+	uint8_t changrp_mask, arg[4];
+	int num_channels;
+	int ret, i;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	devc = sdi->priv;
+	serial = sdi->conn;
+
+	if (ols_configure_channels(sdi) != SR_OK) {
+		sr_err("Failed to configure channels.");
+		return SR_ERR;
+	}
+
+	/*
+	 * Enable/disable channel groups in the flag register according to the
+	 * channel mask. Calculate this here, because num_channels is needed
+	 * to limit readcount.
+	 */
+	changrp_mask = 0;
+	num_channels = 0;
+	for (i = 0; i < 4; i++) {
+		if (devc->channel_mask & (0xff << (i * 8))) {
+			changrp_mask |= (1 << i);
+			num_channels++;
+		}
+	}
+
+	/*
+	 * Limit readcount to prevent reading past the end of the hardware
+	 * buffer.
+	 */
+	samplecount = MIN(devc->max_samples / num_channels, devc->limit_samples);
+	readcount = samplecount / 4;
+
+	/* Rather read too many samples than too few. */
+	if (samplecount % 4 != 0)
+		readcount++;
+
+	/* Basic triggers. */
+	if (devc->trigger_mask[0] != 0x00000000) {
+		/* At least one channel has a trigger on it. */
+		delaycount = readcount * (1 - devc->capture_ratio / 100.0);
+		devc->trigger_at = (readcount - delaycount) * 4 - devc->num_stages;
+		for (i = 0; i <= devc->num_stages; i++) {
+			sr_dbg("Setting stage %d trigger.", i);
+			if ((ret = set_trigger(sdi, i)) != SR_OK)
+				return ret;
+		}
+	} else {
+		/* No triggers configured, force trigger on first stage. */
+		sr_dbg("Forcing trigger at stage 0.");
+		if ((ret = set_trigger(sdi, 0)) != SR_OK)
+			return ret;
+		delaycount = readcount;
+	}
+
+	/* Samplerate. */
+	sr_dbg("Setting samplerate to %" PRIu64 "Hz (divider %u)",
+			devc->cur_samplerate, devc->cur_samplerate_divider);
+	arg[0] = devc->cur_samplerate_divider & 0xff;
+	arg[1] = (devc->cur_samplerate_divider & 0xff00) >> 8;
+	arg[2] = (devc->cur_samplerate_divider & 0xff0000) >> 16;
+	arg[3] = 0x00;
+	if (send_longcommand(serial, CMD_SET_DIVIDER, arg) != SR_OK)
+		return SR_ERR;
+
+	/* Send sample limit and pre/post-trigger capture ratio. */
+	sr_dbg("Setting sample limit %d, trigger point at %d",
+			(readcount - 1) * 4, (delaycount - 1) * 4);
+	arg[0] = ((readcount - 1) & 0xff);
+	arg[1] = ((readcount - 1) & 0xff00) >> 8;
+	arg[2] = ((delaycount - 1) & 0xff);
+	arg[3] = ((delaycount - 1) & 0xff00) >> 8;
+	if (send_longcommand(serial, CMD_CAPTURE_SIZE, arg) != SR_OK)
+		return SR_ERR;
+
+	/* Flag register. */
+	sr_dbg("Setting intpat %s, extpat %s, RLE %s, noise_filter %s, demux %s",
+			devc->flag_reg & FLAG_INTERNAL_TEST_MODE ? "on": "off",
+			devc->flag_reg & FLAG_EXTERNAL_TEST_MODE ? "on": "off",
+			devc->flag_reg & FLAG_RLE ? "on" : "off",
+			devc->flag_reg & FLAG_FILTER ? "on": "off",
+			devc->flag_reg & FLAG_DEMUX ? "on" : "off");
+	/* 1 means "disable channel". */
+	devc->flag_reg |= ~(changrp_mask << 2) & 0x3c;
+	arg[0] = devc->flag_reg & 0xff;
+	arg[1] = devc->flag_reg >> 8;
+	arg[2] = arg[3] = 0x00;
+	if (send_longcommand(serial, CMD_SET_FLAGS, arg) != SR_OK)
+		return SR_ERR;
+
+	/* Start acquisition on the device. */
+	if (send_shortcommand(serial, CMD_RUN) != SR_OK)
+		return SR_ERR;
+
+	/* Reset all operational states. */
+	devc->rle_count = devc->num_transfers = 0;
+	devc->num_samples = devc->num_bytes = 0;
+	devc->cnt_bytes = devc->cnt_samples = devc->cnt_samples_rle = 0;
+	memset(devc->sample, 0, 4);
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	serial_source_add(serial, G_IO_IN, -1, ols_receive_data, cb_data);
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	(void)cb_data;
+
+	abort_acquisition(sdi);
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver ols_driver_info = {
+	.name = "ols",
+	.longname = "Openbench Logic Sniffer",
+	.api_version = 1,
+	.init = init,
+	.cleanup = cleanup,
+	.scan = scan,
+	.dev_list = dev_list,
+	.dev_clear = NULL,
+	.config_get = config_get,
+	.config_set = config_set,
+	.config_list = config_list,
+	.dev_open = std_serial_dev_open,
+	.dev_close = std_serial_dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/openbench-logic-sniffer/protocol.c b/hardware/openbench-logic-sniffer/protocol.c
new file mode 100644
index 0000000..4530447
--- /dev/null
+++ b/hardware/openbench-logic-sniffer/protocol.c
@@ -0,0 +1,507 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "protocol.h"
+#include <libserialport.h>
+
+extern SR_PRIV struct sr_dev_driver ols_driver_info;
+static struct sr_dev_driver *di = &ols_driver_info;
+
+SR_PRIV int send_shortcommand(struct sr_serial_dev_inst *serial,
+		uint8_t command)
+{
+	char buf[1];
+
+	sr_dbg("Sending cmd 0x%.2x.", command);
+	buf[0] = command;
+	if (serial_write_blocking(serial, buf, 1) != 1)
+		return SR_ERR;
+
+	return SR_OK;
+}
+
+SR_PRIV int send_longcommand(struct sr_serial_dev_inst *serial,
+		uint8_t command, uint8_t *data)
+{
+	char buf[5];
+
+	sr_dbg("Sending cmd 0x%.2x data 0x%.2x%.2x%.2x%.2x.", command,
+			data[0], data[1], data[2], data[3]);
+	buf[0] = command;
+	buf[1] = data[0];
+	buf[2] = data[1];
+	buf[3] = data[2];
+	buf[4] = data[3];
+	if (serial_write_blocking(serial, buf, 5) != 5)
+		return SR_ERR;
+
+	return SR_OK;
+}
+
+SR_PRIV int ols_configure_channels(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	const struct sr_channel *ch;
+	const GSList *l;
+	int channel_bit, stage, i;
+	char *tc;
+
+	devc = sdi->priv;
+
+	devc->channel_mask = 0;
+	for (i = 0; i < NUM_TRIGGER_STAGES; i++) {
+		devc->trigger_mask[i] = 0;
+		devc->trigger_value[i] = 0;
+	}
+
+	devc->num_stages = 0;
+	for (l = sdi->channels; l; l = l->next) {
+		ch = (const struct sr_channel *)l->data;
+		if (!ch->enabled)
+			continue;
+
+		if (ch->index >= devc->max_channels) {
+			sr_err("Channels over the limit of %d\n", devc->max_channels);
+			return SR_ERR;
+		}
+
+		/*
+		 * Set up the channel mask for later configuration into the
+		 * flag register.
+		 */
+		channel_bit = 1 << (ch->index);
+		devc->channel_mask |= channel_bit;
+
+		if (!ch->trigger)
+			continue;
+
+		/* Configure trigger mask and value. */
+		stage = 0;
+		for (tc = ch->trigger; tc && *tc; tc++) {
+			devc->trigger_mask[stage] |= channel_bit;
+			if (*tc == '1')
+				devc->trigger_value[stage] |= channel_bit;
+			stage++;
+			/* Only supporting parallel mode, with up to 4 stages. */
+			if (stage > 4)
+				return SR_ERR;
+		}
+		if (stage > devc->num_stages)
+			devc->num_stages = stage - 1;
+	}
+
+	return SR_OK;
+}
+
+SR_PRIV struct dev_context *ols_dev_new(void)
+{
+	struct dev_context *devc;
+
+	if (!(devc = g_try_malloc(sizeof(struct dev_context)))) {
+		sr_err("Device context malloc failed.");
+		return NULL;
+	}
+
+	/* Device-specific settings */
+	devc->max_samples = devc->max_samplerate = devc->protocol_version = 0;
+
+	/* Acquisition settings */
+	devc->limit_samples = devc->capture_ratio = 0;
+	devc->trigger_at = -1;
+	devc->channel_mask = 0xffffffff;
+	devc->flag_reg = 0;
+
+	return devc;
+}
+
+SR_PRIV struct sr_dev_inst *get_metadata(struct sr_serial_dev_inst *serial)
+{
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+	struct sr_channel *ch;
+	uint32_t tmp_int, ui;
+	uint8_t key, type, token;
+	GString *tmp_str, *devname, *version;
+	guchar tmp_c;
+
+	sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, NULL, NULL, NULL);
+	sdi->driver = di;
+	devc = ols_dev_new();
+	sdi->priv = devc;
+
+	devname = g_string_new("");
+	version = g_string_new("");
+
+	key = 0xff;
+	while (key) {
+		if (serial_read_blocking(serial, &key, 1) != 1)
+			break;
+		if (key == 0x00) {
+			sr_dbg("Got metadata key 0x00, metadata ends.");
+			break;
+		}
+		type = key >> 5;
+		token = key & 0x1f;
+		switch (type) {
+		case 0:
+			/* NULL-terminated string */
+			tmp_str = g_string_new("");
+			while (serial_read_blocking(serial, &tmp_c, 1) == 1 && tmp_c != '\0')
+				g_string_append_c(tmp_str, tmp_c);
+			sr_dbg("Got metadata key 0x%.2x value '%s'.",
+			       key, tmp_str->str);
+			switch (token) {
+			case 0x01:
+				/* Device name */
+				devname = g_string_append(devname, tmp_str->str);
+				break;
+			case 0x02:
+				/* FPGA firmware version */
+				if (version->len)
+					g_string_append(version, ", ");
+				g_string_append(version, "FPGA version ");
+				g_string_append(version, tmp_str->str);
+				break;
+			case 0x03:
+				/* Ancillary version */
+				if (version->len)
+					g_string_append(version, ", ");
+				g_string_append(version, "Ancillary version ");
+				g_string_append(version, tmp_str->str);
+				break;
+			default:
+				sr_info("ols: unknown token 0x%.2x: '%s'",
+					token, tmp_str->str);
+				break;
+			}
+			g_string_free(tmp_str, TRUE);
+			break;
+		case 1:
+			/* 32-bit unsigned integer */
+			if (serial_read_blocking(serial, &tmp_int, 4) != 4)
+				break;
+			tmp_int = RB32(&tmp_int);
+			sr_dbg("Got metadata key 0x%.2x value 0x%.8x.",
+			       key, tmp_int);
+			switch (token) {
+			case 0x00:
+				/* Number of usable channels */
+				for (ui = 0; ui < tmp_int; ui++) {
+					if (!(ch = sr_channel_new(ui, SR_CHANNEL_LOGIC, TRUE,
+							ols_channel_names[ui])))
+						return 0;
+					sdi->channels = g_slist_append(sdi->channels, ch);
+				}
+				break;
+			case 0x01:
+				/* Amount of sample memory available (bytes) */
+				devc->max_samples = tmp_int;
+				break;
+			case 0x02:
+				/* Amount of dynamic memory available (bytes) */
+				/* what is this for? */
+				break;
+			case 0x03:
+				/* Maximum sample rate (hz) */
+				devc->max_samplerate = tmp_int;
+				break;
+			case 0x04:
+				/* protocol version */
+				devc->protocol_version = tmp_int;
+				break;
+			default:
+				sr_info("Unknown token 0x%.2x: 0x%.8x.",
+					token, tmp_int);
+				break;
+			}
+			break;
+		case 2:
+			/* 8-bit unsigned integer */
+			if (serial_read_blocking(serial, &tmp_c, 1) != 1)
+				break;
+			sr_dbg("Got metadata key 0x%.2x value 0x%.2x.",
+			       key, tmp_c);
+			switch (token) {
+			case 0x00:
+				/* Number of usable channels */
+				for (ui = 0; ui < tmp_c; ui++) {
+					if (!(ch = sr_channel_new(ui, SR_CHANNEL_LOGIC, TRUE,
+							ols_channel_names[ui])))
+						return 0;
+					sdi->channels = g_slist_append(sdi->channels, ch);
+				}
+				break;
+			case 0x01:
+				/* protocol version */
+				devc->protocol_version = tmp_c;
+				break;
+			default:
+				sr_info("Unknown token 0x%.2x: 0x%.2x.",
+					token, tmp_c);
+				break;
+			}
+			break;
+		default:
+			/* unknown type */
+			break;
+		}
+	}
+
+	sdi->model = devname->str;
+	sdi->version = version->str;
+	g_string_free(devname, FALSE);
+	g_string_free(version, FALSE);
+
+	return sdi;
+}
+
+SR_PRIV int ols_set_samplerate(const struct sr_dev_inst *sdi,
+		const uint64_t samplerate)
+{
+	struct dev_context *devc;
+
+	devc = sdi->priv;
+	if (devc->max_samplerate && samplerate > devc->max_samplerate)
+		return SR_ERR_SAMPLERATE;
+
+	if (samplerate > CLOCK_RATE) {
+		sr_info("Enabling demux mode.");
+		devc->flag_reg |= FLAG_DEMUX;
+		devc->flag_reg &= ~FLAG_FILTER;
+		devc->max_channels = NUM_CHANNELS / 2;
+		devc->cur_samplerate_divider = (CLOCK_RATE * 2 / samplerate) - 1;
+	} else {
+		sr_info("Disabling demux mode.");
+		devc->flag_reg &= ~FLAG_DEMUX;
+		devc->flag_reg |= FLAG_FILTER;
+		devc->max_channels = NUM_CHANNELS;
+		devc->cur_samplerate_divider = (CLOCK_RATE / samplerate) - 1;
+	}
+
+	/* Calculate actual samplerate used and complain if it is different
+	 * from the requested.
+	 */
+	devc->cur_samplerate = CLOCK_RATE / (devc->cur_samplerate_divider + 1);
+	if (devc->flag_reg & FLAG_DEMUX)
+		devc->cur_samplerate *= 2;
+	if (devc->cur_samplerate != samplerate)
+		sr_info("Can't match samplerate %" PRIu64 ", using %"
+		       PRIu64 ".", samplerate, devc->cur_samplerate);
+
+	return SR_OK;
+}
+
+SR_PRIV void abort_acquisition(const struct sr_dev_inst *sdi)
+{
+	struct sr_datafeed_packet packet;
+	struct sr_serial_dev_inst *serial;
+
+	serial = sdi->conn;
+	serial_source_remove(serial);
+
+	/* Terminate session */
+	packet.type = SR_DF_END;
+	sr_session_send(sdi, &packet);
+}
+
+SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data)
+{
+	struct dev_context *devc;
+	struct sr_dev_inst *sdi;
+	struct sr_serial_dev_inst *serial;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_logic logic;
+	uint32_t sample;
+	int num_channels, offset, j;
+	unsigned int i;
+	unsigned char byte;
+
+	(void)fd;
+
+	sdi = cb_data;
+	serial = sdi->conn;
+	devc = sdi->priv;
+
+	if (devc->num_transfers++ == 0) {
+		/*
+		 * First time round, means the device started sending data,
+		 * and will not stop until done. If it stops sending for
+		 * longer than it takes to send a byte, that means it's
+		 * finished. We'll double that to 30ms to be sure...
+		 */
+		serial_source_remove(serial);
+		serial_source_add(serial, G_IO_IN, 30, ols_receive_data, cb_data);
+		devc->raw_sample_buf = g_try_malloc(devc->limit_samples * 4);
+		if (!devc->raw_sample_buf) {
+			sr_err("Sample buffer malloc failed.");
+			return FALSE;
+		}
+		/* fill with 1010... for debugging */
+		memset(devc->raw_sample_buf, 0x82, devc->limit_samples * 4);
+	}
+
+	num_channels = 0;
+	for (i = NUM_CHANNELS; i > 0x02; i /= 2) {
+		if ((devc->flag_reg & i) == 0) {
+			num_channels++;
+		}
+	}
+
+	if (revents == G_IO_IN && devc->num_samples < devc->limit_samples) {
+		if (serial_read_nonblocking(serial, &byte, 1) != 1)
+			return FALSE;
+		devc->cnt_bytes++;
+
+		/* Ignore it if we've read enough. */
+		if (devc->num_samples >= devc->limit_samples)
+			return TRUE;
+
+		devc->sample[devc->num_bytes++] = byte;
+		sr_spew("Received byte 0x%.2x.", byte);
+		if (devc->num_bytes == num_channels) {
+			devc->cnt_samples++;
+			devc->cnt_samples_rle++;
+			/*
+			 * Got a full sample. Convert from the OLS's little-endian
+			 * sample to the local format.
+			 */
+			sample = devc->sample[0] | (devc->sample[1] << 8) \
+					| (devc->sample[2] << 16) | (devc->sample[3] << 24);
+			sr_dbg("Received sample 0x%.*x.", devc->num_bytes * 2, sample);
+			if (devc->flag_reg & FLAG_RLE) {
+				/*
+				 * In RLE mode the high bit of the sample is the
+				 * "count" flag, meaning this sample is the number
+				 * of times the previous sample occurred.
+				 */
+				if (devc->sample[devc->num_bytes - 1] & 0x80) {
+					/* Clear the high bit. */
+					sample &= ~(0x80 << (devc->num_bytes - 1) * 8);
+					devc->rle_count = sample;
+					devc->cnt_samples_rle += devc->rle_count;
+					sr_dbg("RLE count: %u.", devc->rle_count);
+					devc->num_bytes = 0;
+					return TRUE;
+				}
+			}
+			devc->num_samples += devc->rle_count + 1;
+			if (devc->num_samples > devc->limit_samples) {
+				/* Save us from overrunning the buffer. */
+				devc->rle_count -= devc->num_samples - devc->limit_samples;
+				devc->num_samples = devc->limit_samples;
+			}
+
+			if (num_channels < 4) {
+				/*
+				 * Some channel groups may have been turned
+				 * off, to speed up transfer between the
+				 * hardware and the PC. Expand that here before
+				 * submitting it over the session bus --
+				 * whatever is listening on the bus will be
+				 * expecting a full 32-bit sample, based on
+				 * the number of channels.
+				 */
+				j = 0;
+				memset(devc->tmp_sample, 0, 4);
+				for (i = 0; i < 4; i++) {
+					if (((devc->flag_reg >> 2) & (1 << i)) == 0) {
+						/*
+						 * This channel group was
+						 * enabled, copy from received
+						 * sample.
+						 */
+						devc->tmp_sample[i] = devc->sample[j++];
+					} else if (devc->flag_reg & FLAG_DEMUX && (i > 2)) {
+						/* group 2 & 3 get added to 0 & 1 */
+						devc->tmp_sample[i - 2] = devc->sample[j++];
+					}
+				}
+				memcpy(devc->sample, devc->tmp_sample, 4);
+				sr_spew("Expanded sample: 0x%.8x.", sample);
+			}
+
+			/*
+			 * the OLS sends its sample buffer backwards.
+			 * store it in reverse order here, so we can dump
+			 * this on the session bus later.
+			 */
+			offset = (devc->limit_samples - devc->num_samples) * 4;
+			for (i = 0; i <= devc->rle_count; i++) {
+				memcpy(devc->raw_sample_buf + offset + (i * 4),
+				       devc->sample, 4);
+			}
+			memset(devc->sample, 0, 4);
+			devc->num_bytes = 0;
+			devc->rle_count = 0;
+		}
+	} else {
+		/*
+		 * This is the main loop telling us a timeout was reached, or
+		 * we've acquired all the samples we asked for -- we're done.
+		 * Send the (properly-ordered) buffer to the frontend.
+		 */
+		sr_dbg("Received %d bytes, %d samples, %d decompressed samples.",
+				devc->cnt_bytes, devc->cnt_samples,
+				devc->cnt_samples_rle);
+		if (devc->trigger_at != -1) {
+			/*
+			 * A trigger was set up, so we need to tell the frontend
+			 * about it.
+			 */
+			if (devc->trigger_at > 0) {
+				/* There are pre-trigger samples, send those first. */
+				packet.type = SR_DF_LOGIC;
+				packet.payload = &logic;
+				logic.length = devc->trigger_at * 4;
+				logic.unitsize = 4;
+				logic.data = devc->raw_sample_buf +
+					(devc->limit_samples - devc->num_samples) * 4;
+				sr_session_send(cb_data, &packet);
+			}
+
+			/* Send the trigger. */
+			packet.type = SR_DF_TRIGGER;
+			sr_session_send(cb_data, &packet);
+
+			/* Send post-trigger samples. */
+			packet.type = SR_DF_LOGIC;
+			packet.payload = &logic;
+			logic.length = (devc->num_samples * 4) - (devc->trigger_at * 4);
+			logic.unitsize = 4;
+			logic.data = devc->raw_sample_buf + devc->trigger_at * 4 +
+				(devc->limit_samples - devc->num_samples) * 4;
+			sr_session_send(cb_data, &packet);
+		} else {
+			/* no trigger was used */
+			packet.type = SR_DF_LOGIC;
+			packet.payload = &logic;
+			logic.length = devc->num_samples * 4;
+			logic.unitsize = 4;
+			logic.data = devc->raw_sample_buf +
+				(devc->limit_samples - devc->num_samples) * 4;
+			sr_session_send(cb_data, &packet);
+		}
+		g_free(devc->raw_sample_buf);
+
+		serial_flush(serial);
+		abort_acquisition(sdi);
+	}
+
+	return TRUE;
+}
diff --git a/hardware/openbench-logic-sniffer/protocol.h b/hardware/openbench-logic-sniffer/protocol.h
new file mode 100644
index 0000000..98831b5
--- /dev/null
+++ b/hardware/openbench-logic-sniffer/protocol.h
@@ -0,0 +1,120 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_OPENBENCH_LOGIC_SNIFFER_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_OPENBENCH_LOGIC_SNIFFER_PROTOCOL_H
+
+#include <stdint.h>
+#include <string.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "ols"
+
+#define NUM_CHANNELS             32
+#define NUM_TRIGGER_STAGES     4
+#define TRIGGER_TYPE           "01"
+#define SERIAL_SPEED           B115200
+#define CLOCK_RATE             SR_MHZ(100)
+#define MIN_NUM_SAMPLES        4
+#define DEFAULT_SAMPLERATE     SR_KHZ(200)
+
+/* Command opcodes */
+#define CMD_RESET                  0x00
+#define CMD_RUN                    0x01
+#define CMD_TESTMODE               0x03
+#define CMD_ID                     0x02
+#define CMD_METADATA               0x04
+#define CMD_SET_FLAGS              0x82
+#define CMD_SET_DIVIDER            0x80
+#define CMD_CAPTURE_SIZE           0x81
+#define CMD_SET_TRIGGER_MASK       0xc0
+#define CMD_SET_TRIGGER_VALUE      0xc1
+#define CMD_SET_TRIGGER_CONFIG     0xc2
+
+/* Trigger config */
+#define TRIGGER_START              (1 << 3)
+
+/* Bitmasks for CMD_FLAGS */
+/* 12-13 unused, 14-15 RLE mode (we hardcode mode 0). */
+#define FLAG_INTERNAL_TEST_MODE    (1 << 11)
+#define FLAG_EXTERNAL_TEST_MODE    (1 << 10)
+#define FLAG_SWAP_CHANNELS           (1 << 9)
+#define FLAG_RLE                   (1 << 8)
+#define FLAG_SLOPE_FALLING         (1 << 7)
+#define FLAG_CLOCK_EXTERNAL        (1 << 6)
+#define FLAG_CHANNELGROUP_4        (1 << 5)
+#define FLAG_CHANNELGROUP_3        (1 << 4)
+#define FLAG_CHANNELGROUP_2        (1 << 3)
+#define FLAG_CHANNELGROUP_1        (1 << 2)
+#define FLAG_FILTER                (1 << 1)
+#define FLAG_DEMUX                 (1 << 0)
+
+/* Private, per-device-instance driver context. */
+struct dev_context {
+	/* Fixed device settings */
+	int max_channels;
+	uint32_t max_samples;
+	uint32_t max_samplerate;
+	uint32_t protocol_version;
+
+	/* Acquisition settings */
+	uint64_t cur_samplerate;
+	uint32_t cur_samplerate_divider;
+	uint64_t limit_samples;
+	int capture_ratio;
+	int trigger_at;
+	uint32_t channel_mask;
+	uint32_t trigger_mask[4];
+	uint32_t trigger_value[4];
+	int num_stages;
+	uint16_t flag_reg;
+
+	/* Operational states */
+	unsigned int num_transfers;
+	unsigned int num_samples;
+	int num_bytes;
+	int cnt_bytes;
+	int cnt_samples;
+	int cnt_samples_rle;
+
+	/* Temporary variables */
+	unsigned int rle_count;
+	unsigned char sample[4];
+	unsigned char tmp_sample[4];
+	unsigned char *raw_sample_buf;
+};
+
+
+SR_PRIV extern const char *ols_channel_names[NUM_CHANNELS + 1];
+
+SR_PRIV int send_shortcommand(struct sr_serial_dev_inst *serial,
+		uint8_t command);
+SR_PRIV int send_longcommand(struct sr_serial_dev_inst *serial,
+		uint8_t command, uint8_t *data);
+SR_PRIV int ols_configure_channels(const struct sr_dev_inst *sdi);
+SR_PRIV struct dev_context *ols_dev_new(void);
+SR_PRIV struct sr_dev_inst *get_metadata(struct sr_serial_dev_inst *serial);
+SR_PRIV int ols_set_samplerate(const struct sr_dev_inst *sdi,
+		uint64_t samplerate);
+SR_PRIV void abort_acquisition(const struct sr_dev_inst *sdi);
+SR_PRIV int ols_receive_data(int fd, int revents, void *cb_data);
+
+#endif
diff --git a/hardware/rigol-ds/api.c b/hardware/rigol-ds/api.c
new file mode 100644
index 0000000..4650010
--- /dev/null
+++ b/hardware/rigol-ds/api.c
@@ -0,0 +1,1039 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Martin Ling <martin-git at earth.li>
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ * Copyright (C) 2013 Mathias Grimmberger <mgri at zaphod.sax.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+
+static const int32_t hwopts[] = {
+	SR_CONF_CONN,
+	SR_CONF_SERIALCOMM
+};
+
+static const int32_t hwcaps[] = {
+	SR_CONF_OSCILLOSCOPE,
+	SR_CONF_TIMEBASE,
+	SR_CONF_TRIGGER_SOURCE,
+	SR_CONF_TRIGGER_SLOPE,
+	SR_CONF_HORIZ_TRIGGERPOS,
+	SR_CONF_NUM_TIMEBASE,
+	SR_CONF_LIMIT_FRAMES,
+	SR_CONF_SAMPLERATE,
+};
+
+static const int32_t analog_hwcaps[] = {
+	SR_CONF_NUM_VDIV,
+	SR_CONF_VDIV,
+	SR_CONF_COUPLING,
+	SR_CONF_DATA_SOURCE,
+};
+
+static const uint64_t timebases[][2] = {
+	/* nanoseconds */
+	{ 1, 1000000000 },
+	{ 2, 1000000000 },
+	{ 5, 1000000000 },
+	{ 10, 1000000000 },
+	{ 20, 1000000000 },
+	{ 50, 1000000000 },
+	{ 100, 1000000000 },
+	{ 500, 1000000000 },
+	/* microseconds */
+	{ 1, 1000000 },
+	{ 2, 1000000 },
+	{ 5, 1000000 },
+	{ 10, 1000000 },
+	{ 20, 1000000 },
+	{ 50, 1000000 },
+	{ 100, 1000000 },
+	{ 200, 1000000 },
+	{ 500, 1000000 },
+	/* milliseconds */
+	{ 1, 1000 },
+	{ 2, 1000 },
+	{ 5, 1000 },
+	{ 10, 1000 },
+	{ 20, 1000 },
+	{ 50, 1000 },
+	{ 100, 1000 },
+	{ 200, 1000 },
+	{ 500, 1000 },
+	/* seconds */
+	{ 1, 1 },
+	{ 2, 1 },
+	{ 5, 1 },
+	{ 10, 1 },
+	{ 20, 1 },
+	{ 50, 1 },
+	{ 100, 1 },
+	{ 200, 1 },
+	{ 500, 1 },
+	{ 1000, 1 },
+};
+
+static const uint64_t vdivs[][2] = {
+	/* microvolts */
+	{ 500, 1000000 },
+	/* millivolts */
+	{ 1, 1000 },
+	{ 2, 1000 },
+	{ 5, 1000 },
+	{ 10, 1000 },
+	{ 20, 1000 },
+	{ 50, 1000 },
+	{ 100, 1000 },
+	{ 200, 1000 },
+	{ 500, 1000 },
+	/* volts */
+	{ 1, 1 },
+	{ 2, 1 },
+	{ 5, 1 },
+	{ 10, 1 },
+};
+
+#define NUM_TIMEBASE  ARRAY_SIZE(timebases)
+#define NUM_VDIV      ARRAY_SIZE(vdivs)
+
+static const char *trigger_sources[] = {
+	"CH1",
+	"CH2",
+	"CH3",
+	"CH4",
+	"EXT",
+	"AC Line",
+	"D0",
+	"D1",
+	"D2",
+	"D3",
+	"D4",
+	"D5",
+	"D6",
+	"D7",
+	"D8",
+	"D9",
+	"D10",
+	"D11",
+	"D12",
+	"D13",
+	"D14",
+	"D15",
+};
+
+static const char *trigger_slopes[] = {
+	"r",
+	"f",
+};
+
+static const char *coupling[] = {
+	"AC",
+	"DC",
+	"GND",
+};
+
+/* Do not change the order of entries */
+static const char *data_sources[] = {
+	"Live",
+	"Memory",
+	"Segmented",
+};
+
+enum vendor {
+	RIGOL,
+	AGILENT,
+};
+
+enum series {
+	VS5000,
+	DS1000,
+	DS2000,
+	DS2000A,
+	DSO1000,
+};
+
+/* short name, full name */
+static const struct rigol_ds_vendor supported_vendors[] = {
+	[RIGOL] = {"Rigol", "Rigol Technologies"},
+	[AGILENT] = {"Agilent", "Rigol Technologies"},
+};
+
+#define VENDOR(x) &supported_vendors[x]
+/* vendor, series, protocol, max timebase, min vdiv, number of horizontal divs,
+ * live waveform samples, memory buffer samples */
+static const struct rigol_ds_series supported_series[] = {
+	[VS5000] = {VENDOR(RIGOL), "VS5000", PROTOCOL_V1, FORMAT_RAW,
+		{50, 1}, {2, 1000}, 14, 2048, 0},
+	[DS1000] = {VENDOR(RIGOL), "DS1000", PROTOCOL_V2, FORMAT_IEEE488_2,
+		{50, 1}, {2, 1000}, 12, 600, 1048576},
+	[DS2000] = {VENDOR(RIGOL), "DS2000", PROTOCOL_V3, FORMAT_IEEE488_2,
+		{500, 1}, {2, 1000}, 14, 1400, 14000},
+	[DS2000A] = {VENDOR(RIGOL), "DS2000A", PROTOCOL_V3, FORMAT_IEEE488_2,
+		{1000, 1}, {500, 1000000}, 14, 1400, 14000},
+	[DSO1000] = {VENDOR(AGILENT), "DSO1000", PROTOCOL_V3, FORMAT_IEEE488_2,
+		{50, 1}, {2, 1000}, 12, 600, 20480},
+};
+
+#define SERIES(x) &supported_series[x]
+/* series, model, min timebase, analog channels, digital */
+static const struct rigol_ds_model supported_models[] = {
+	{SERIES(VS5000), "VS5022", {20, 1000000000}, 2, false},
+	{SERIES(VS5000), "VS5042", {10, 1000000000}, 2, false},
+	{SERIES(VS5000), "VS5062", {5, 1000000000}, 2, false},
+	{SERIES(VS5000), "VS5102", {2, 1000000000}, 2, false},
+	{SERIES(VS5000), "VS5202", {2, 1000000000}, 2, false},
+	{SERIES(VS5000), "VS5022D", {20, 1000000000}, 2, true},
+	{SERIES(VS5000), "VS5042D", {10, 1000000000}, 2, true},
+	{SERIES(VS5000), "VS5062D", {5, 1000000000}, 2, true},
+	{SERIES(VS5000), "VS5102D", {2, 1000000000}, 2, true},
+	{SERIES(VS5000), "VS5202D", {2, 1000000000}, 2, true},
+	{SERIES(DS1000), "DS1052E", {5, 1000000000}, 2, false},
+	{SERIES(DS1000), "DS1102E", {2, 1000000000}, 2, false},
+	{SERIES(DS1000), "DS1152E", {2, 1000000000}, 2, false},
+	{SERIES(DS1000), "DS1052D", {5, 1000000000}, 2, true},
+	{SERIES(DS1000), "DS1102D", {2, 1000000000}, 2, true},
+	{SERIES(DS1000), "DS1152D", {2, 1000000000}, 2, true},
+	{SERIES(DS2000), "DS2072", {5, 1000000000}, 2, false},
+	{SERIES(DS2000), "DS2102", {5, 1000000000}, 2, false},
+	{SERIES(DS2000), "DS2202", {2, 1000000000}, 2, false},
+	{SERIES(DS2000), "DS2302", {1, 1000000000}, 2, false},
+	{SERIES(DS2000A), "DS2072A", {5, 1000000000}, 2, false},
+	{SERIES(DS2000A), "DS2102A", {5, 1000000000}, 2, false},
+	{SERIES(DS2000A), "DS2202A", {2, 1000000000}, 2, false},
+	{SERIES(DS2000A), "DS2302A", {1, 1000000000}, 2, false},
+	{SERIES(DSO1000), "DSO1002A", {5, 1000000000}, 2, false},
+	{SERIES(DSO1000), "DSO1004A", {5, 1000000000}, 4, false},
+	{SERIES(DSO1000), "DSO1012A", {2, 1000000000}, 2, false},
+	{SERIES(DSO1000), "DSO1014A", {2, 1000000000}, 4, false},
+	{SERIES(DSO1000), "DSO1022A", {2, 1000000000}, 2, false},
+	{SERIES(DSO1000), "DSO1024A", {2, 1000000000}, 4, false},
+};
+
+SR_PRIV struct sr_dev_driver rigol_ds_driver_info;
+static struct sr_dev_driver *di = &rigol_ds_driver_info;
+
+static void clear_helper(void *priv)
+{
+	struct dev_context *devc;
+
+	devc = priv;
+	g_free(devc->data);
+	g_free(devc->buffer);
+	g_free(devc->coupling[0]);
+	g_free(devc->coupling[1]);
+	g_free(devc->trigger_source);
+	g_free(devc->trigger_slope);
+	g_slist_free(devc->analog_groups[0].channels);
+	g_slist_free(devc->analog_groups[1].channels);
+	g_slist_free(devc->digital_group.channels);
+}
+
+static int dev_clear(void)
+{
+	return std_dev_clear(di, clear_helper);
+}
+
+static int init(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static struct sr_dev_inst *probe_device(struct sr_scpi_dev_inst *scpi)
+{
+	struct dev_context *devc;
+	struct sr_dev_inst *sdi;
+	struct sr_scpi_hw_info *hw_info;
+	struct sr_channel *ch;
+	long n[3];
+	unsigned int i;
+	const struct rigol_ds_model *model = NULL;
+	gchar *channel_name, **version;
+
+	if (sr_scpi_get_hw_id(scpi, &hw_info) != SR_OK) {
+		sr_info("Couldn't get IDN response, retrying.");
+		sr_scpi_close(scpi);
+		sr_scpi_open(scpi);
+		if (sr_scpi_get_hw_id(scpi, &hw_info) != SR_OK) {
+			sr_info("Couldn't get IDN response.");
+			return NULL;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(supported_models); i++) {
+		if (!strcasecmp(hw_info->manufacturer,
+					supported_models[i].series->vendor->full_name) &&
+				!strcmp(hw_info->model, supported_models[i].name)) {
+			model = &supported_models[i];
+			break;
+		}
+	}
+
+	if (!model || !(sdi = sr_dev_inst_new(0, SR_ST_ACTIVE,
+					      model->series->vendor->name,
+						  model->name,
+						  hw_info->firmware_version))) {
+		sr_scpi_hw_info_free(hw_info);
+		return NULL;
+	}
+
+	sdi->conn = scpi;
+
+	sdi->driver = di;
+	sdi->inst_type = SR_INST_SCPI;
+
+	if (!(devc = g_try_malloc0(sizeof(struct dev_context))))
+		return NULL;
+
+	devc->limit_frames = 0;
+	devc->model = model;
+	devc->format = model->series->format;
+
+	/* DS1000 models with firmware before 0.2.4 used the old data format. */
+	if (model->series == SERIES(DS1000)) {
+		version = g_strsplit(hw_info->firmware_version, ".", 0);
+		do {
+			if (!version[0] || !version[1] || !version[2])
+				break;
+			if (version[0][0] == 0 || version[1][0] == 0 || version[2][0] == 0)
+				break;
+			for (i = 0; i < 3; i++) {
+				if (sr_atol(version[i], &n[i]) != SR_OK)
+					break;
+			}
+			if (i != 3)
+				break;
+			if (n[0] != 0 || n[1] > 2)
+				break;
+			if (n[1] == 2 && n[2] > 3)
+				break;
+			sr_dbg("Found DS1000 firmware < 0.2.4, using raw data format.");
+			devc->format = FORMAT_RAW;
+		} while(0);
+		g_strfreev(version);
+	}
+
+	sr_scpi_hw_info_free(hw_info);
+
+	for (i = 0; i < model->analog_channels; i++) {
+		if (!(channel_name = g_strdup_printf("CH%d", i + 1)))
+			return NULL;
+		ch = sr_channel_new(i, SR_CHANNEL_ANALOG, TRUE, channel_name);
+		sdi->channels = g_slist_append(sdi->channels, ch);
+		devc->analog_groups[i].name = channel_name;
+		devc->analog_groups[i].channels = g_slist_append(NULL, ch);
+		sdi->channel_groups = g_slist_append(sdi->channel_groups,
+				&devc->analog_groups[i]);
+	}
+
+	if (devc->model->has_digital) {
+		for (i = 0; i < 16; i++) {
+			if (!(channel_name = g_strdup_printf("D%d", i)))
+				return NULL;
+			ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE, channel_name);
+			g_free(channel_name);
+			if (!ch)
+				return NULL;
+			sdi->channels = g_slist_append(sdi->channels, ch);
+			devc->digital_group.channels = g_slist_append(
+					devc->digital_group.channels, ch);
+		}
+		devc->digital_group.name = "LA";
+		sdi->channel_groups = g_slist_append(sdi->channel_groups,
+				&devc->digital_group);
+	}
+
+	for (i = 0; i < NUM_TIMEBASE; i++) {
+		if (!memcmp(&devc->model->min_timebase, &timebases[i], sizeof(uint64_t[2])))
+			devc->timebases = &timebases[i];
+		if (!memcmp(&devc->model->series->max_timebase, &timebases[i], sizeof(uint64_t[2])))
+			devc->num_timebases = &timebases[i] - devc->timebases + 1;
+	}
+
+	for (i = 0; i < NUM_VDIV; i++)
+		if (!memcmp(&devc->model->series->min_vdiv, &vdivs[i], sizeof(uint64_t[2])))
+			devc->vdivs = &vdivs[i];
+
+	if (!(devc->buffer = g_try_malloc(ACQ_BUFFER_SIZE)))
+		return NULL;
+	if (!(devc->data = g_try_malloc(ACQ_BUFFER_SIZE * sizeof(float))))
+		return NULL;
+
+	devc->data_source = DATA_SOURCE_LIVE;
+
+	sdi->priv = devc;
+
+	return sdi;
+}
+
+static GSList *scan(GSList *options)
+{
+	return sr_scpi_scan(di->priv, options, probe_device);
+}
+
+static GSList *dev_list(void)
+{
+	return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+	struct sr_scpi_dev_inst *scpi = sdi->conn;
+
+	if (sr_scpi_open(scpi) < 0)
+		return SR_ERR;
+
+	if (rigol_ds_get_dev_cfg(sdi) != SR_OK)
+		return SR_ERR;
+
+	sdi->status = SR_ST_ACTIVE;
+
+	return SR_OK;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+	struct sr_scpi_dev_inst *scpi;
+	struct dev_context *devc;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	scpi = sdi->conn;
+	devc = sdi->priv;
+
+	if (devc->model->series->protocol == PROTOCOL_V2)
+		rigol_ds_config_set(sdi, ":KEY:LOCK DISABLE");
+
+	if (scpi) {
+		if (sr_scpi_close(scpi) < 0)
+			return SR_ERR;
+		sdi->status = SR_ST_INACTIVE;
+	}
+
+	return SR_OK;
+}
+
+static int cleanup(void)
+{
+	return dev_clear();
+}
+
+static int analog_frame_size(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc = sdi->priv;
+	struct sr_channel *ch;
+	int analog_channels = 0;
+	GSList *l;
+
+	for (l = sdi->channels; l; l = l->next) {
+		ch = l->data;
+		if (ch->type == SR_CHANNEL_ANALOG && ch->enabled)
+			analog_channels++;
+	}
+
+	if (analog_channels == 0)
+		return 0;
+
+	switch (devc->data_source) {
+	case DATA_SOURCE_LIVE:
+		return devc->model->series->live_samples;
+	case DATA_SOURCE_MEMORY:
+		return devc->model->series->buffer_samples / analog_channels;
+	default:
+		return 0;
+	}
+}
+
+static int digital_frame_size(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc = sdi->priv;
+
+	switch (devc->data_source) {
+	case DATA_SOURCE_LIVE:
+		return devc->model->series->live_samples * 2;
+	case DATA_SOURCE_MEMORY:
+		return devc->model->series->buffer_samples * 2;
+	default:
+		return 0;
+	}
+}
+
+static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	struct sr_channel *ch;
+	const char *tmp_str;
+	uint64_t samplerate;
+	int analog_channel = -1;
+	float smallest_diff = 0.0000000001;
+	int idx = -1;
+	unsigned i;
+
+	if (!sdi || !(devc = sdi->priv))
+		return SR_ERR_ARG;
+
+	/* If a channel group is specified, it must be a valid one. */
+	if (cg && !g_slist_find(sdi->channel_groups, cg)) {
+		sr_err("Invalid channel group specified.");
+		return SR_ERR;
+	}
+
+	if (cg) {
+		ch = g_slist_nth_data(cg->channels, 0);
+		if (!ch)
+			return SR_ERR;
+		if (ch->type == SR_CHANNEL_ANALOG) {
+			if (ch->name[2] < '1' || ch->name[2] > '4')
+				return SR_ERR;
+			analog_channel = ch->name[2] - '1';
+		}
+	}
+
+	switch (id) {
+	case SR_CONF_NUM_TIMEBASE:
+		*data = g_variant_new_int32(devc->model->series->num_horizontal_divs);
+		break;
+	case SR_CONF_NUM_VDIV:
+		*data = g_variant_new_int32(NUM_VDIV);
+	case SR_CONF_DATA_SOURCE:
+		if (devc->data_source == DATA_SOURCE_LIVE)
+			*data = g_variant_new_string("Live");
+		else if (devc->data_source == DATA_SOURCE_MEMORY)
+			*data = g_variant_new_string("Memory");
+		else
+			*data = g_variant_new_string("Segmented");
+		break;
+	case SR_CONF_SAMPLERATE:
+		if (devc->data_source == DATA_SOURCE_LIVE) {
+			samplerate = analog_frame_size(sdi) /
+				(devc->timebase * devc->model->series->num_horizontal_divs);
+			*data = g_variant_new_uint64(samplerate);
+		} else {
+			return SR_ERR_NA;
+		}
+		break;
+	case SR_CONF_TRIGGER_SOURCE:
+		if (!strcmp(devc->trigger_source, "ACL"))
+			tmp_str = "AC Line";
+		else if (!strcmp(devc->trigger_source, "CHAN1"))
+			tmp_str = "CH1";
+		else if (!strcmp(devc->trigger_source, "CHAN2"))
+			tmp_str = "CH2";
+		else if (!strcmp(devc->trigger_source, "CHAN3"))
+			tmp_str = "CH3";
+		else if (!strcmp(devc->trigger_source, "CHAN4"))
+			tmp_str = "CH4";
+		else
+			tmp_str = devc->trigger_source;
+		*data = g_variant_new_string(tmp_str);
+		break;
+	case SR_CONF_TRIGGER_SLOPE:
+		if (!strcmp(devc->trigger_slope, "POS"))
+			tmp_str = "r";
+		else if (!strcmp(devc->trigger_slope, "NEG"))
+			tmp_str = "f";
+		else
+			return SR_ERR_NA;
+		*data = g_variant_new_string(tmp_str);
+		break;
+	case SR_CONF_TIMEBASE:
+		for (i = 0; i < devc->num_timebases; i++) {
+			float tb = (float)devc->timebases[i][0] / devc->timebases[i][1];
+			float diff = fabs(devc->timebase - tb);
+			if (diff < smallest_diff) {
+				smallest_diff = diff;
+				idx = i;
+			}
+		}
+		if (idx < 0)
+			return SR_ERR_NA;
+		*data = g_variant_new("(tt)", devc->timebases[idx][0],
+		                              devc->timebases[idx][1]);
+		break;
+	case SR_CONF_VDIV:
+		if (analog_channel < 0)
+			return SR_ERR_NA;
+		for (i = 0; i < ARRAY_SIZE(vdivs); i++) {
+			float vdiv = (float)vdivs[i][0] / vdivs[i][1];
+			float diff = fabs(devc->vdiv[analog_channel] - vdiv);
+			if (diff < smallest_diff) {
+				smallest_diff = diff;
+				idx = i;
+			}
+		}
+		if (idx < 0)
+			return SR_ERR_NA;
+		*data = g_variant_new("(tt)", vdivs[idx][0], vdivs[idx][1]);
+		break;
+	case SR_CONF_COUPLING:
+		if (analog_channel < 0)
+			return SR_ERR_NA;
+		*data = g_variant_new_string(devc->coupling[analog_channel]);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	uint64_t p, q;
+	double t_dbl;
+	unsigned int i, j;
+	int ret;
+	const char *tmp_str;
+	char buffer[16];
+
+	if (!(devc = sdi->priv))
+		return SR_ERR_ARG;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	/* If a channel group is specified, it must be a valid one. */
+	if (cg && !g_slist_find(sdi->channel_groups, cg)) {
+		sr_err("Invalid channel group specified.");
+		return SR_ERR;
+	}
+
+	ret = SR_OK;
+	switch (id) {
+	case SR_CONF_LIMIT_FRAMES:
+		devc->limit_frames = g_variant_get_uint64(data);
+		break;
+	case SR_CONF_TRIGGER_SLOPE:
+		tmp_str = g_variant_get_string(data, NULL);
+
+		if (!tmp_str || !(tmp_str[0] == 'f' || tmp_str[0] == 'r'))
+			return SR_ERR_ARG;
+
+		g_free(devc->trigger_slope);
+		devc->trigger_slope = g_strdup((tmp_str[0] == 'r') ? "POS" : "NEG");
+		ret = rigol_ds_config_set(sdi, ":TRIG:EDGE:SLOP %s", devc->trigger_slope);
+		break;
+	case SR_CONF_HORIZ_TRIGGERPOS:
+		t_dbl = g_variant_get_double(data);
+		if (t_dbl < 0.0 || t_dbl > 1.0)
+			return SR_ERR;
+		devc->horiz_triggerpos = t_dbl;
+		/* We have the trigger offset as a percentage of the frame, but
+		 * need to express this in seconds. */
+		t_dbl = -(devc->horiz_triggerpos - 0.5) * devc->timebase * devc->num_timebases;
+		g_ascii_formatd(buffer, sizeof(buffer), "%.6f", t_dbl);
+		ret = rigol_ds_config_set(sdi, ":TIM:OFFS %s", buffer);
+		break;
+	case SR_CONF_TIMEBASE:
+		g_variant_get(data, "(tt)", &p, &q);
+		for (i = 0; i < devc->num_timebases; i++) {
+			if (devc->timebases[i][0] == p && devc->timebases[i][1] == q) {
+				devc->timebase = (float)p / q;
+				g_ascii_formatd(buffer, sizeof(buffer), "%.9f",
+				                devc->timebase);
+				ret = rigol_ds_config_set(sdi, ":TIM:SCAL %s", buffer);
+				break;
+			}
+		}
+		if (i == devc->num_timebases)
+			ret = SR_ERR_ARG;
+		break;
+	case SR_CONF_TRIGGER_SOURCE:
+		tmp_str = g_variant_get_string(data, NULL);
+		for (i = 0; i < ARRAY_SIZE(trigger_sources); i++) {
+			if (!strcmp(trigger_sources[i], tmp_str)) {
+				g_free(devc->trigger_source);
+				devc->trigger_source = g_strdup(trigger_sources[i]);
+				if (!strcmp(devc->trigger_source, "AC Line"))
+					tmp_str = "ACL";
+				else if (!strcmp(devc->trigger_source, "CH1"))
+					tmp_str = "CHAN1";
+				else if (!strcmp(devc->trigger_source, "CH2"))
+					tmp_str = "CHAN2";
+				else if (!strcmp(devc->trigger_source, "CH3"))
+					tmp_str = "CHAN3";
+				else if (!strcmp(devc->trigger_source, "CH4"))
+					tmp_str = "CHAN4";
+				else
+					tmp_str = (char *)devc->trigger_source;
+				ret = rigol_ds_config_set(sdi, ":TRIG:EDGE:SOUR %s", tmp_str);
+				break;
+			}
+		}
+		if (i == ARRAY_SIZE(trigger_sources))
+			ret = SR_ERR_ARG;
+		break;
+	case SR_CONF_VDIV:
+		if (!cg) {
+			sr_err("No channel group specified.");
+			return SR_ERR_CHANNEL_GROUP;
+		}
+		g_variant_get(data, "(tt)", &p, &q);
+		for (i = 0; i < 2; i++) {
+			if (cg == &devc->analog_groups[i]) {
+				for (j = 0; j < ARRAY_SIZE(vdivs); j++) {
+					if (vdivs[j][0] != p || vdivs[j][1] != q)
+						continue;
+					devc->vdiv[i] = (float)p / q;
+					g_ascii_formatd(buffer, sizeof(buffer), "%.3f",
+					                devc->vdiv[i]);
+					return rigol_ds_config_set(sdi, ":CHAN%d:SCAL %s", i + 1,
+							buffer);
+				}
+				return SR_ERR_ARG;
+			}
+		}
+		return SR_ERR_NA;
+	case SR_CONF_COUPLING:
+		if (!cg) {
+			sr_err("No channel group specified.");
+			return SR_ERR_CHANNEL_GROUP;
+		}
+		tmp_str = g_variant_get_string(data, NULL);
+		for (i = 0; i < 2; i++) {
+			if (cg == &devc->analog_groups[i]) {
+				for (j = 0; j < ARRAY_SIZE(coupling); j++) {
+					if (!strcmp(tmp_str, coupling[j])) {
+						g_free(devc->coupling[i]);
+						devc->coupling[i] = g_strdup(coupling[j]);
+						return rigol_ds_config_set(sdi, ":CHAN%d:COUP %s", i + 1,
+								devc->coupling[i]);
+					}
+				}
+				return SR_ERR_ARG;
+			}
+		}
+		return SR_ERR_NA;
+	case SR_CONF_DATA_SOURCE:
+		tmp_str = g_variant_get_string(data, NULL);
+		if (!strcmp(tmp_str, "Live"))
+			devc->data_source = DATA_SOURCE_LIVE;
+		else if (devc->model->series->protocol >= PROTOCOL_V2
+			&& !strcmp(tmp_str, "Memory"))
+			devc->data_source = DATA_SOURCE_MEMORY;
+		else if (devc->model->series->protocol >= PROTOCOL_V3
+			 && !strcmp(tmp_str, "Segmented"))
+			devc->data_source = DATA_SOURCE_SEGMENTED;
+		else
+			return SR_ERR;
+		break;
+	default:
+		ret = SR_ERR_NA;
+		break;
+	}
+
+	return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	GVariant *tuple, *rational[2];
+	GVariantBuilder gvb;
+	unsigned int i;
+	struct dev_context *devc = NULL;
+
+	if (sdi)
+		devc = sdi->priv;
+
+	if (key == SR_CONF_SCAN_OPTIONS) {
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+		return SR_OK;
+	} else if (key == SR_CONF_DEVICE_OPTIONS && cg == NULL) {
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+			hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+		return SR_OK;
+	}
+
+	/* Every other option requires a valid device instance. */
+	if (!sdi || !(devc = sdi->priv))
+		return SR_ERR_ARG;
+
+	/* If a channel group is specified, it must be a valid one. */
+	if (cg) {
+		if (cg != &devc->analog_groups[0]
+				&& cg != &devc->analog_groups[1]) {
+			sr_err("Invalid channel group specified.");
+			return SR_ERR;
+		}
+	}
+
+	switch (key) {
+	case SR_CONF_DEVICE_OPTIONS:
+		if (!cg) {
+			sr_err("No channel group specified.");
+			return SR_ERR_CHANNEL_GROUP;
+		}
+		if (cg == &devc->digital_group) {
+			*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				NULL, 0, sizeof(int32_t));
+			return SR_OK;
+		} else {
+			for (i = 0; i < 2; i++) {
+				if (cg == &devc->analog_groups[i]) {
+					*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+						analog_hwcaps, ARRAY_SIZE(analog_hwcaps), sizeof(int32_t));
+					return SR_OK;
+				}
+			}
+			return SR_ERR_NA;
+		}
+		break;
+	case SR_CONF_COUPLING:
+		if (!cg) {
+			sr_err("No channel group specified.");
+			return SR_ERR_CHANNEL_GROUP;
+		}
+		*data = g_variant_new_strv(coupling, ARRAY_SIZE(coupling));
+		break;
+	case SR_CONF_VDIV:
+		if (!devc)
+			/* Can't know this until we have the exact model. */
+			return SR_ERR_ARG;
+		if (!cg) {
+			sr_err("No channel group specified.");
+			return SR_ERR_CHANNEL_GROUP;
+		}
+		g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
+		for (i = 0; i < NUM_VDIV; i++) {
+			rational[0] = g_variant_new_uint64(devc->vdivs[i][0]);
+			rational[1] = g_variant_new_uint64(devc->vdivs[i][1]);
+			tuple = g_variant_new_tuple(rational, 2);
+			g_variant_builder_add_value(&gvb, tuple);
+		}
+		*data = g_variant_builder_end(&gvb);
+		break;
+	case SR_CONF_TIMEBASE:
+		if (!devc)
+			/* Can't know this until we have the exact model. */
+			return SR_ERR_ARG;
+		if (devc->num_timebases <= 0)
+			return SR_ERR_NA;
+		g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
+		for (i = 0; i < devc->num_timebases; i++) {
+			rational[0] = g_variant_new_uint64(devc->timebases[i][0]);
+			rational[1] = g_variant_new_uint64(devc->timebases[i][1]);
+			tuple = g_variant_new_tuple(rational, 2);
+			g_variant_builder_add_value(&gvb, tuple);
+		}
+		*data = g_variant_builder_end(&gvb);
+		break;
+	case SR_CONF_TRIGGER_SOURCE:
+		if (!devc)
+			/* Can't know this until we have the exact model. */
+			return SR_ERR_ARG;
+		*data = g_variant_new_strv(trigger_sources,
+				devc->model->has_digital ? ARRAY_SIZE(trigger_sources) : 4);
+		break;
+	case SR_CONF_TRIGGER_SLOPE:
+		*data = g_variant_new_strv(trigger_slopes, ARRAY_SIZE(trigger_slopes));
+		break;
+	case SR_CONF_DATA_SOURCE:
+		if (!devc)
+			/* Can't know this until we have the exact model. */
+			return SR_ERR_ARG;
+		switch (devc->model->series->protocol) {
+		case PROTOCOL_V1:
+			*data = g_variant_new_strv(data_sources, ARRAY_SIZE(data_sources) - 2);
+			break;
+		case PROTOCOL_V2:
+			*data = g_variant_new_strv(data_sources, ARRAY_SIZE(data_sources) - 1);
+			break;
+		default:
+			*data = g_variant_new_strv(data_sources, ARRAY_SIZE(data_sources));
+			break;
+		}
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct sr_scpi_dev_inst *scpi;
+	struct dev_context *devc;
+	struct sr_channel *ch;
+	struct sr_datafeed_packet packet;
+	GSList *l;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	scpi = sdi->conn;
+	devc = sdi->priv;
+
+	devc->num_frames = 0;
+
+	for (l = sdi->channels; l; l = l->next) {
+		ch = l->data;
+		sr_dbg("handling channel %s", ch->name);
+		if (ch->type == SR_CHANNEL_ANALOG) {
+			if (ch->enabled)
+				devc->enabled_analog_channels = g_slist_append(
+						devc->enabled_analog_channels, ch);
+			if (ch->enabled != devc->analog_channels[ch->index]) {
+				/* Enabled channel is currently disabled, or vice versa. */
+				if (rigol_ds_config_set(sdi, ":CHAN%d:DISP %s", ch->index + 1,
+						ch->enabled ? "ON" : "OFF") != SR_OK)
+					return SR_ERR;
+				devc->analog_channels[ch->index] = ch->enabled;
+			}
+		} else if (ch->type == SR_CHANNEL_LOGIC) {
+			if (ch->enabled) {
+				devc->enabled_digital_channels = g_slist_append(
+						devc->enabled_digital_channels, ch);
+				/* Turn on LA module if currently off. */
+				if (!devc->la_enabled) {
+					if (rigol_ds_config_set(sdi, ":LA:DISP ON") != SR_OK)
+						return SR_ERR;
+					devc->la_enabled = TRUE;
+				}
+			}
+			if (ch->enabled != devc->digital_channels[ch->index]) {
+				/* Enabled channel is currently disabled, or vice versa. */
+				if (rigol_ds_config_set(sdi, ":DIG%d:TURN %s", ch->index,
+						ch->enabled ? "ON" : "OFF") != SR_OK)
+					return SR_ERR;
+				devc->digital_channels[ch->index] = ch->enabled;
+			}
+		}
+	}
+
+	if (!devc->enabled_analog_channels && !devc->enabled_digital_channels)
+		return SR_ERR;
+
+	/* Turn off LA module if on and no digital channels selected. */
+	if (devc->la_enabled && !devc->enabled_digital_channels)
+		if (rigol_ds_config_set(sdi, ":LA:DISP OFF") != SR_OK)
+			return SR_ERR;
+
+	/* Set memory mode. */
+	if (devc->data_source == DATA_SOURCE_SEGMENTED) {
+		sr_err("Data source 'Segmented' not yet supported");
+		return SR_ERR;
+	}
+
+	devc->analog_frame_size = analog_frame_size(sdi);
+	devc->digital_frame_size = digital_frame_size(sdi);
+
+	switch (devc->model->series->protocol) {
+	case PROTOCOL_V2:
+		if (rigol_ds_config_set(sdi, ":ACQ:MEMD LONG") != SR_OK)
+			return SR_ERR;
+		break;
+	case PROTOCOL_V3:
+		/* Apparently for the DS2000 the memory
+		 * depth can only be set in Running state -
+		 * this matches the behaviour of the UI. */
+		if (rigol_ds_config_set(sdi, ":RUN") != SR_OK)
+			return SR_ERR;
+		if (rigol_ds_config_set(sdi, ":ACQ:MDEP %d",
+					devc->analog_frame_size) != SR_OK)
+			return SR_ERR;
+		if (rigol_ds_config_set(sdi, ":STOP") != SR_OK)
+			return SR_ERR;
+		break;
+	default:
+		break;
+	}
+
+	if (devc->data_source == DATA_SOURCE_LIVE)
+		if (rigol_ds_config_set(sdi, ":RUN") != SR_OK)
+			return SR_ERR;
+
+	sr_scpi_source_add(scpi, G_IO_IN, 50, rigol_ds_receive, (void *)sdi);
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	if (devc->enabled_analog_channels)
+		devc->channel_entry = devc->enabled_analog_channels;
+	else
+		devc->channel_entry = devc->enabled_digital_channels;
+
+	if (rigol_ds_capture_start(sdi) != SR_OK)
+		return SR_ERR;
+
+	/* Start of first frame. */
+	packet.type = SR_DF_FRAME_BEGIN;
+	sr_session_send(cb_data, &packet);
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct dev_context *devc;
+	struct sr_scpi_dev_inst *scpi;
+	struct sr_datafeed_packet packet;
+
+	(void)cb_data;
+
+	devc = sdi->priv;
+
+	if (sdi->status != SR_ST_ACTIVE) {
+		sr_err("Device inactive, can't stop acquisition.");
+		return SR_ERR;
+	}
+
+	/* End of last frame. */
+	packet.type = SR_DF_END;
+	sr_session_send(sdi, &packet);
+
+	g_slist_free(devc->enabled_analog_channels);
+	g_slist_free(devc->enabled_digital_channels);
+	devc->enabled_analog_channels = NULL;
+	devc->enabled_digital_channels = NULL;
+	scpi = sdi->conn;
+	sr_scpi_source_remove(scpi);
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver rigol_ds_driver_info = {
+	.name = "rigol-ds",
+	.longname = "Rigol DS",
+	.api_version = 1,
+	.init = init,
+	.cleanup = cleanup,
+	.scan = scan,
+	.dev_list = dev_list,
+	.dev_clear = dev_clear,
+	.config_get = config_get,
+	.config_set = config_set,
+	.config_list = config_list,
+	.dev_open = dev_open,
+	.dev_close = dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/rigol-ds/protocol.c b/hardware/rigol-ds/protocol.c
new file mode 100644
index 0000000..97cb353
--- /dev/null
+++ b/hardware/rigol-ds/protocol.c
@@ -0,0 +1,812 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Martin Ling <martin-git at earth.li>
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ * Copyright (C) 2013 Mathias Grimmberger <mgri at zaphod.sax.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <math.h>
+#include <ctype.h>
+#include <time.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+
+/*
+ * This is a unified protocol driver for the DS1000 and DS2000 series.
+ *
+ * DS1000 support tested with a Rigol DS1102D.
+ *
+ * DS2000 support tested with a Rigol DS2072 using firmware version 01.01.00.02.
+ *
+ * The Rigol DS2000 series scopes try to adhere to the IEEE 488.2 (I think)
+ * standard. If you want to read it - it costs real money...
+ *
+ * Every response from the scope has a linefeed appended because the
+ * standard says so. In principle this could be ignored because sending the
+ * next command clears the output queue of the scope. This driver tries to
+ * avoid doing that because it may cause an error being generated inside the
+ * scope and who knows what bugs the firmware has WRT this.
+ *
+ * Waveform data is transferred in a format called "arbitrary block program
+ * data" specified in IEEE 488.2. See Agilents programming manuals for their
+ * 2000/3000 series scopes for a nice description.
+ *
+ * Each data block from the scope has a header, e.g. "#900000001400".
+ * The '#' marks the start of a block.
+ * Next is one ASCII decimal digit between 1 and 9, this gives the number of
+ * ASCII decimal digits following.
+ * Last are the ASCII decimal digits giving the number of bytes (not
+ * samples!) in the block.
+ *
+ * After this header as many data bytes as indicated follow.
+ *
+ * Each data block has a trailing linefeed too.
+ */
+
+static int parse_int(const char *str, int *ret)
+{
+	char *e;
+	long tmp;
+
+	errno = 0;
+	tmp = strtol(str, &e, 10);
+	if (e == str || *e != '\0') {
+		sr_dbg("Failed to parse integer: '%s'", str);
+		return SR_ERR;
+	}
+	if (errno) {
+		sr_dbg("Failed to parse integer: '%s', numerical overflow", str);
+		return SR_ERR;
+	}
+	if (tmp > INT_MAX || tmp < INT_MIN) {
+		sr_dbg("Failed to parse integer: '%s', value to large/small", str);
+		return SR_ERR;
+	}
+
+	*ret = (int)tmp;
+	return SR_OK;
+}
+
+/* Set the next event to wait for in rigol_ds_receive */
+static void rigol_ds_set_wait_event(struct dev_context *devc, enum wait_events event)
+{
+	if (event == WAIT_STOP)
+		devc->wait_status = 2;
+	else
+		devc->wait_status = 1;
+	devc->wait_event = event;
+}
+
+/*
+ * Waiting for a event will return a timeout after 2 to 3 seconds in order
+ * to not block the application.
+ */
+static int rigol_ds_event_wait(const struct sr_dev_inst *sdi, char status1, char status2)
+{
+	char *buf;
+	struct dev_context *devc;
+	time_t start;
+
+	if (!(devc = sdi->priv))
+		return SR_ERR;
+
+	start = time(NULL);
+
+	/*
+	 * Trigger status may return:
+	 * "TD" or "T'D" - triggered
+	 * "AUTO"        - autotriggered
+	 * "RUN"         - running
+	 * "WAIT"        - waiting for trigger
+	 * "STOP"        - stopped
+	 */
+
+	if (devc->wait_status == 1) {
+		do {
+			if (time(NULL) - start >= 3) {
+				sr_dbg("Timeout waiting for trigger");
+				return SR_ERR_TIMEOUT;
+			}
+
+			if (sr_scpi_get_string(sdi->conn, ":TRIG:STAT?", &buf) != SR_OK)
+				return SR_ERR;
+		} while (buf[0] == status1 || buf[0] == status2);
+
+		devc->wait_status = 2;
+	}
+	if (devc->wait_status == 2) {
+		do {
+			if (time(NULL) - start >= 3) {
+				sr_dbg("Timeout waiting for trigger");
+				return SR_ERR_TIMEOUT;
+			}
+
+			if (sr_scpi_get_string(sdi->conn, ":TRIG:STAT?", &buf) != SR_OK)
+				return SR_ERR;
+		} while (buf[0] != status1 && buf[0] != status2);
+
+		rigol_ds_set_wait_event(devc, WAIT_NONE);
+	}
+
+	return SR_OK;
+}
+
+/*
+ * For live capture we need to wait for a new trigger event to ensure that
+ * sample data is not returned twice.
+ *
+ * Unfortunately this will never really work because for sufficiently fast
+ * timebases and trigger rates it just can't catch the status changes.
+ *
+ * What would be needed is a trigger event register with autoreset like the
+ * Agilents have. The Rigols don't seem to have anything like this.
+ *
+ * The workaround is to only wait for the trigger when the timebase is slow
+ * enough. Of course this means that for faster timebases sample data can be
+ * returned multiple times, this effect is mitigated somewhat by sleeping
+ * for about one sweep time in that case.
+ */
+static int rigol_ds_trigger_wait(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	long s;
+
+	if (!(devc = sdi->priv))
+		return SR_ERR;
+
+	/* 
+	 * If timebase < 50 msecs/DIV just sleep about one sweep time except
+	 * for really fast sweeps.
+	 */
+	if (devc->timebase < 0.0499) {
+		if (devc->timebase > 0.99e-6) {
+			/*
+			 * Timebase * num hor. divs * 85(%) * 1e6(usecs) / 100
+			 * -> 85 percent of sweep time
+			 */
+			s = (devc->timebase * devc->model->series->num_horizontal_divs
+			     * 85e6) / 100L;
+			sr_spew("Sleeping for %ld usecs instead of trigger-wait", s);
+			g_usleep(s);
+		}
+		rigol_ds_set_wait_event(devc, WAIT_NONE);
+		return SR_OK;
+	} else {
+		return rigol_ds_event_wait(sdi, 'T', 'A');
+	}
+}
+
+/* Wait for scope to got to "Stop" in single shot mode */
+static int rigol_ds_stop_wait(const struct sr_dev_inst *sdi)
+{
+	return rigol_ds_event_wait(sdi, 'S', 'S');
+}
+
+/* Check that a single shot acquisition actually succeeded on the DS2000 */
+static int rigol_ds_check_stop(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_channel *ch;
+	int tmp;
+
+	if (!(devc = sdi->priv))
+		return SR_ERR;
+
+	ch = devc->channel_entry->data;
+
+	if (devc->model->series->protocol <= PROTOCOL_V2)
+		return SR_OK;
+
+	if (rigol_ds_config_set(sdi, ":WAV:SOUR CHAN%d",
+			  ch->index + 1) != SR_OK)
+		return SR_ERR;
+	/* Check that the number of samples will be accepted */
+	if (rigol_ds_config_set(sdi, ":WAV:POIN %d", devc->analog_frame_size) != SR_OK)
+		return SR_ERR;
+	if (sr_scpi_get_int(sdi->conn, "*ESR?", &tmp) != SR_OK)
+		return SR_ERR;
+	/*
+	 * If we get an "Execution error" the scope went from "Single" to
+	 * "Stop" without actually triggering. There is no waveform
+	 * displayed and trying to download one will fail - the scope thinks
+	 * it has 1400 samples (like display memory) and the driver thinks
+	 * it has a different number of samples.
+	 *
+	 * In that case just try to capture something again. Might still
+	 * fail in interesting ways.
+	 *
+	 * Ain't firmware fun?
+	 */
+	if (tmp & 0x10) {
+		sr_warn("Single shot acquisition failed, retrying...");
+		/* Sleep a bit, otherwise the single shot will often fail */
+		g_usleep(500000);
+		rigol_ds_config_set(sdi, ":SING");
+		rigol_ds_set_wait_event(devc, WAIT_STOP);
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+/* Wait for enough data becoming available in scope output buffer */
+static int rigol_ds_block_wait(const struct sr_dev_inst *sdi)
+{
+	char *buf;
+	struct dev_context *devc;
+	time_t start;
+	int len;
+
+	if (!(devc = sdi->priv))
+		return SR_ERR;
+
+	if (devc->model->series->protocol >= PROTOCOL_V3) {
+
+		start = time(NULL);
+
+		do {
+			if (time(NULL) - start >= 3) {
+				sr_dbg("Timeout waiting for data block");
+				return SR_ERR_TIMEOUT;
+			}
+
+			/*
+			 * The scope copies data really slowly from sample
+			 * memory to its output buffer, so try not to bother
+			 * it too much with SCPI requests but don't wait too
+			 * long for short sample frame sizes.
+			 */
+			g_usleep(devc->analog_frame_size < 15000 ? 100000 : 1000000);
+
+			/* "READ,nnnn" (still working) or "IDLE,nnnn" (finished) */
+			if (sr_scpi_get_string(sdi->conn, ":WAV:STAT?", &buf) != SR_OK)
+				return SR_ERR;
+
+			if (parse_int(buf + 5, &len) != SR_OK)
+				return SR_ERR;
+		} while (buf[0] == 'R' && len < 1000000);
+	}
+
+	rigol_ds_set_wait_event(devc, WAIT_NONE);
+
+	return SR_OK;
+}
+
+/* Send a configuration setting. */
+SR_PRIV int rigol_ds_config_set(const struct sr_dev_inst *sdi, const char *format, ...)
+{
+	struct dev_context *devc = sdi->priv;
+	va_list args;
+	int ret;
+
+	va_start(args, format);
+	ret = sr_scpi_send_variadic(sdi->conn, format, args);
+	va_end(args);
+
+	if (ret != SR_OK)
+		return SR_ERR;
+
+	if (devc->model->series->protocol == PROTOCOL_V2) {
+		/* The DS1000 series needs this stupid delay, *OPC? doesn't work. */
+		sr_spew("delay %dms", 100);
+		g_usleep(100000);
+		return SR_OK;
+	} else {
+		return sr_scpi_get_opc(sdi->conn);
+	}
+}
+
+/* Start capturing a new frameset */
+SR_PRIV int rigol_ds_capture_start(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	gchar *trig_mode;
+
+	if (!(devc = sdi->priv))
+		return SR_ERR;
+
+	sr_dbg("Starting data capture for frameset %lu of %lu",
+	       devc->num_frames + 1, devc->limit_frames);
+
+	switch (devc->model->series->protocol) {
+	case PROTOCOL_V1:
+		rigol_ds_set_wait_event(devc, WAIT_TRIGGER);
+		break;
+	case PROTOCOL_V2:
+		if (devc->data_source == DATA_SOURCE_LIVE) {
+			if (rigol_ds_config_set(sdi, ":WAV:POIN:MODE NORMAL") != SR_OK)
+				return SR_ERR;
+			rigol_ds_set_wait_event(devc, WAIT_TRIGGER);
+		} else {
+			if (rigol_ds_config_set(sdi, ":STOP") != SR_OK)
+				return SR_ERR;
+			if (rigol_ds_config_set(sdi, ":WAV:POIN:MODE RAW") != SR_OK)
+				return SR_ERR;
+			if (sr_scpi_get_string(sdi->conn, ":TRIG:MODE?", &trig_mode) != SR_OK)
+				return SR_ERR;
+			if (rigol_ds_config_set(sdi, ":TRIG:%s:SWE SING", trig_mode) != SR_OK)
+				return SR_ERR;
+			if (rigol_ds_config_set(sdi, ":RUN") != SR_OK)
+				return SR_ERR;
+			rigol_ds_set_wait_event(devc, WAIT_STOP);
+		}
+		break;
+	case PROTOCOL_V3:
+		if (rigol_ds_config_set(sdi, ":WAV:FORM BYTE") != SR_OK)
+			return SR_ERR;
+		if (devc->data_source == DATA_SOURCE_LIVE) {
+			if (rigol_ds_config_set(sdi, ":WAV:MODE NORM") != SR_OK)
+				return SR_ERR;
+			rigol_ds_set_wait_event(devc, WAIT_TRIGGER);
+		} else {
+			if (rigol_ds_config_set(sdi, ":WAV:MODE RAW") != SR_OK)
+				return SR_ERR;
+			if (rigol_ds_config_set(sdi, ":SING") != SR_OK)
+				return SR_ERR;
+			rigol_ds_set_wait_event(devc, WAIT_STOP);
+		}
+		break;
+	}
+
+	return SR_OK;
+}
+
+/* Start reading data from the current channel */
+SR_PRIV int rigol_ds_channel_start(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_channel *ch;
+
+	if (!(devc = sdi->priv))
+		return SR_ERR;
+
+	ch = devc->channel_entry->data;
+
+	sr_dbg("Starting reading data from channel %d", ch->index + 1);
+
+	if (devc->model->series->protocol <= PROTOCOL_V2) {
+		if (ch->type == SR_CHANNEL_LOGIC) {
+			if (sr_scpi_send(sdi->conn, ":WAV:DATA? DIG") != SR_OK)
+				return SR_ERR;
+		} else {
+			if (sr_scpi_send(sdi->conn, ":WAV:DATA? CHAN%d",
+					ch->index + 1) != SR_OK)
+				return SR_ERR;
+		}
+		rigol_ds_set_wait_event(devc, WAIT_NONE);
+	} else {
+		if (rigol_ds_config_set(sdi, ":WAV:SOUR CHAN%d",
+				  ch->index + 1) != SR_OK)
+			return SR_ERR;
+		if (devc->data_source != DATA_SOURCE_LIVE) {
+			if (rigol_ds_config_set(sdi, ":WAV:RES") != SR_OK)
+				return SR_ERR;
+			if (rigol_ds_config_set(sdi, ":WAV:BEG") != SR_OK)
+				return SR_ERR;
+		}
+	}
+
+	rigol_ds_set_wait_event(devc, WAIT_BLOCK);
+
+	devc->num_channel_bytes = 0;
+	devc->num_header_bytes = 0;
+	devc->num_block_bytes = 0;
+
+	return SR_OK;
+}
+
+/* Read the header of a data block */
+static int rigol_ds_read_header(struct sr_dev_inst *sdi)
+{
+	struct sr_scpi_dev_inst *scpi = sdi->conn;
+	struct dev_context *devc = sdi->priv;
+	char *buf = (char *) devc->buffer;
+	size_t header_length;
+	int ret;
+
+	/* Try to read the hashsign and length digit. */
+	if (devc->num_header_bytes < 2) {
+		ret = sr_scpi_read_data(scpi, buf + devc->num_header_bytes,
+				2 - devc->num_header_bytes);
+		if (ret < 0) {
+			sr_err("Read error while reading data header.");
+			return SR_ERR;
+		}
+		devc->num_header_bytes += ret;
+	}
+
+	if (devc->num_header_bytes < 2)
+		return 0;
+
+	if (buf[0] != '#' || !isdigit(buf[1]) || buf[1] == '0') {
+		sr_err("Received invalid data block header '%c%c'.", buf[0], buf[1]);
+		return SR_ERR;
+	}
+
+	header_length = 2 + buf[1] - '0';
+
+	/* Try to read the length. */
+	if (devc->num_header_bytes < header_length) {
+		ret = sr_scpi_read_data(scpi, buf + devc->num_header_bytes,
+				header_length - devc->num_header_bytes);
+		if (ret < 0) {
+			sr_err("Read error while reading data header.");
+			return SR_ERR;
+		}
+		devc->num_header_bytes += ret;
+	}
+
+	if (devc->num_header_bytes < header_length)
+		return 0;
+
+	/* Read the data length. */
+	buf[header_length] = '\0';
+
+	if (parse_int(buf + 2, &ret) != SR_OK) {
+		sr_err("Received invalid data block length '%s'.", buf + 2);
+		return -1;
+	}
+
+	sr_dbg("Received data block header: '%s' -> block length %d", buf, ret);
+
+	return ret;
+}
+
+SR_PRIV int rigol_ds_receive(int fd, int revents, void *cb_data)
+{
+	struct sr_dev_inst *sdi;
+	struct sr_scpi_dev_inst *scpi;
+	struct dev_context *devc;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_analog analog;
+	struct sr_datafeed_logic logic;
+	double vdiv, offset;
+	int len, i, vref;
+	struct sr_channel *ch;
+	gsize expected_data_bytes;
+
+	(void)fd;
+
+	if (!(sdi = cb_data))
+		return TRUE;
+
+	if (!(devc = sdi->priv))
+		return TRUE;
+
+	scpi = sdi->conn;
+
+	if (revents == G_IO_IN || revents == 0) {
+		switch(devc->wait_event) {
+		case WAIT_NONE:
+			break;
+		case WAIT_TRIGGER:
+			if (rigol_ds_trigger_wait(sdi) != SR_OK)
+				return TRUE;
+			if (rigol_ds_channel_start(sdi) != SR_OK)
+				return TRUE;
+			return TRUE;
+		case WAIT_BLOCK:
+			if (rigol_ds_block_wait(sdi) != SR_OK)
+				return TRUE;
+			break;
+		case WAIT_STOP:
+			if (rigol_ds_stop_wait(sdi) != SR_OK)
+				return TRUE;
+			if (rigol_ds_check_stop(sdi) != SR_OK)
+				return TRUE;
+			if (rigol_ds_channel_start(sdi) != SR_OK)
+				return TRUE;
+			return TRUE;
+		default:
+			sr_err("BUG: Unknown event target encountered");
+		}
+
+		ch = devc->channel_entry->data;
+
+		expected_data_bytes = ch->type == SR_CHANNEL_ANALOG ?
+				devc->analog_frame_size : devc->digital_frame_size;
+
+		if (devc->num_block_bytes == 0) {
+			if (devc->model->series->protocol >= PROTOCOL_V3)
+				if (sr_scpi_send(sdi->conn, ":WAV:DATA?") != SR_OK)
+					return TRUE;
+
+			if (sr_scpi_read_begin(scpi) != SR_OK)
+				return TRUE;
+
+			if (devc->format == FORMAT_IEEE488_2) {
+				sr_dbg("New block header expected");
+				len = rigol_ds_read_header(sdi);
+				if (len == 0)
+					/* Still reading the header. */
+					return TRUE;
+				if (len == -1) {
+					sr_err("Read error, aborting capture.");
+					packet.type = SR_DF_FRAME_END;
+					sr_session_send(cb_data, &packet);
+					sdi->driver->dev_acquisition_stop(sdi, cb_data);
+					return TRUE;
+				}
+				/* At slow timebases in live capture the DS2072
+				 * sometimes returns "short" data blocks, with
+				 * apparently no way to get the rest of the data.
+				 * Discard these, the complete data block will
+				 * appear eventually.
+				 */
+				if (devc->data_source == DATA_SOURCE_LIVE
+						&& (unsigned)len < expected_data_bytes) {
+					sr_dbg("Discarding short data block");
+					sr_scpi_read_data(scpi, (char *)devc->buffer, len + 1);
+					return TRUE;
+				}
+				devc->num_block_bytes = len;
+			} else {
+				devc->num_block_bytes = expected_data_bytes;
+			}
+			devc->num_block_read = 0;
+		}
+
+		len = devc->num_block_bytes - devc->num_block_read;
+		if (len > ACQ_BUFFER_SIZE)
+			len = ACQ_BUFFER_SIZE;
+		sr_dbg("Requesting read of %d bytes", len);
+
+		len = sr_scpi_read_data(scpi, (char *)devc->buffer, len);
+
+		if (len == -1) {
+			sr_err("Read error, aborting capture.");
+			packet.type = SR_DF_FRAME_END;
+			sr_session_send(cb_data, &packet);
+			sdi->driver->dev_acquisition_stop(sdi, cb_data);
+			return TRUE;
+		}
+
+		sr_dbg("Received %d bytes.", len);
+
+		devc->num_block_read += len;
+
+		if (ch->type == SR_CHANNEL_ANALOG) {
+			vref = devc->vert_reference[ch->index];
+			vdiv = devc->vdiv[ch->index] / 25.6;
+			offset = devc->vert_offset[ch->index];
+			if (devc->model->series->protocol >= PROTOCOL_V3)
+				for (i = 0; i < len; i++)
+					devc->data[i] = ((int)devc->buffer[i] - vref) * vdiv - offset;
+			else
+				for (i = 0; i < len; i++)
+					devc->data[i] = (128 - devc->buffer[i]) * vdiv - offset;
+			analog.channels = g_slist_append(NULL, ch);
+			analog.num_samples = len;
+			analog.data = devc->data;
+			analog.mq = SR_MQ_VOLTAGE;
+			analog.unit = SR_UNIT_VOLT;
+			analog.mqflags = 0;
+			packet.type = SR_DF_ANALOG;
+			packet.payload = &analog;
+			sr_session_send(cb_data, &packet);
+			g_slist_free(analog.channels);
+		} else {
+			logic.length = len;
+			logic.unitsize = 2;
+			logic.data = devc->buffer;
+			packet.type = SR_DF_LOGIC;
+			packet.payload = &logic;
+			sr_session_send(cb_data, &packet);
+		}
+
+		if (devc->num_block_read == devc->num_block_bytes) {
+			sr_dbg("Block has been completed");
+			if (devc->model->series->protocol >= PROTOCOL_V3) {
+				/* Discard the terminating linefeed */
+				sr_scpi_read_data(scpi, (char *)devc->buffer, 1);
+			}
+			if (devc->format == FORMAT_IEEE488_2) {
+				/* Prepare for possible next block */
+				devc->num_header_bytes = 0;
+				devc->num_block_bytes = 0;
+				if (devc->data_source != DATA_SOURCE_LIVE)
+					rigol_ds_set_wait_event(devc, WAIT_BLOCK);
+			}
+			if (!sr_scpi_read_complete(scpi)) {
+				sr_err("Read should have been completed");
+				packet.type = SR_DF_FRAME_END;
+				sr_session_send(cb_data, &packet);
+				sdi->driver->dev_acquisition_stop(sdi, cb_data);
+				return TRUE;
+			}
+			devc->num_block_read = 0;
+		} else {
+			sr_dbg("%d of %d block bytes read", devc->num_block_read, devc->num_block_bytes);
+		}
+
+		devc->num_channel_bytes += len;
+
+		if (devc->num_channel_bytes < expected_data_bytes)
+			/* Don't have the full data for this channel yet, re-run. */
+			return TRUE;
+
+		/* End of data for this channel. */
+		if (devc->model->series->protocol >= PROTOCOL_V3) {
+			/* Signal end of data download to scope */
+			if (devc->data_source != DATA_SOURCE_LIVE)
+				/*
+				 * This causes a query error, without it switching
+				 * to the next channel causes an error. Fun with
+				 * firmware...
+				 */
+				rigol_ds_config_set(sdi, ":WAV:END");
+		}
+
+		if (ch->type == SR_CHANNEL_ANALOG
+				&& devc->channel_entry->next != NULL) {
+			/* We got the frame for this analog channel, but
+			 * there's another analog channel. */
+			devc->channel_entry = devc->channel_entry->next;
+			rigol_ds_channel_start(sdi);
+		} else {
+			/* Done with all analog channels in this frame. */
+			if (devc->enabled_digital_channels
+					&& devc->channel_entry != devc->enabled_digital_channels) {
+				/* Now we need to get the digital data. */
+				devc->channel_entry = devc->enabled_digital_channels;
+				rigol_ds_channel_start(sdi);
+			} else {
+				/* Done with this frame. */
+				packet.type = SR_DF_FRAME_END;
+				sr_session_send(cb_data, &packet);
+
+				if (++devc->num_frames == devc->limit_frames) {
+					/* Last frame, stop capture. */
+					sdi->driver->dev_acquisition_stop(sdi, cb_data);
+				} else {
+					/* Get the next frame, starting with the first analog channel. */
+					if (devc->enabled_analog_channels)
+						devc->channel_entry = devc->enabled_analog_channels;
+					else
+						devc->channel_entry = devc->enabled_digital_channels;
+
+					rigol_ds_capture_start(sdi);
+
+					/* Start of next frame. */
+					packet.type = SR_DF_FRAME_BEGIN;
+					sr_session_send(cb_data, &packet);
+				}
+			}
+		}
+	}
+
+	return TRUE;
+}
+
+SR_PRIV int rigol_ds_get_dev_cfg(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	char *t_s, *cmd;
+	unsigned int i;
+	int res;
+
+	devc = sdi->priv;
+
+	/* Analog channel state. */
+	for (i = 0; i < devc->model->analog_channels; i++) {
+		cmd = g_strdup_printf(":CHAN%d:DISP?", i + 1);
+		res = sr_scpi_get_string(sdi->conn, cmd, &t_s);
+		g_free(cmd);
+		if (res != SR_OK)
+			return SR_ERR;
+		devc->analog_channels[i] = !strcmp(t_s, "ON") || !strcmp(t_s, "1");
+	}
+	sr_dbg("Current analog channel state:");
+	for (i = 0; i < devc->model->analog_channels; i++)
+		sr_dbg("CH%d %s", i + 1, devc->analog_channels[i] ? "on" : "off");
+
+	/* Digital channel state. */
+	if (devc->model->has_digital) {
+		if (sr_scpi_get_string(sdi->conn, ":LA:DISP?", &t_s) != SR_OK)
+			return SR_ERR;
+		devc->la_enabled = !strcmp(t_s, "ON") ? TRUE : FALSE;
+		sr_dbg("Logic analyzer %s, current digital channel state:",
+				devc->la_enabled ? "enabled" : "disabled");
+		for (i = 0; i < 16; i++) {
+			cmd = g_strdup_printf(":DIG%d:TURN?", i);
+			res = sr_scpi_get_string(sdi->conn, cmd, &t_s);
+			g_free(cmd);
+			if (res != SR_OK)
+				return SR_ERR;
+			devc->digital_channels[i] = !strcmp(t_s, "ON") ? TRUE : FALSE;
+			g_free(t_s);
+			sr_dbg("D%d: %s", i, devc->digital_channels[i] ? "on" : "off");
+		}
+	}
+
+	/* Timebase. */
+	if (sr_scpi_get_float(sdi->conn, ":TIM:SCAL?", &devc->timebase) != SR_OK)
+		return SR_ERR;
+	sr_dbg("Current timebase %g", devc->timebase);
+
+	/* Vertical gain. */
+	for (i = 0; i < devc->model->analog_channels; i++) {
+		cmd = g_strdup_printf(":CHAN%d:SCAL?", i + 1);
+		res = sr_scpi_get_float(sdi->conn, cmd, &devc->vdiv[i]);
+		g_free(cmd);
+		if (res != SR_OK)
+			return SR_ERR;
+	}
+	sr_dbg("Current vertical gain:");
+	for (i = 0; i < devc->model->analog_channels; i++)
+		sr_dbg("CH%d %g", i + 1, devc->vdiv[i]);
+
+	sr_dbg("Current vertical reference:");
+	if (devc->model->series->protocol >= PROTOCOL_V3) {
+		/* Vertical reference - not certain if this is the place to read it. */
+		for (i = 0; i < devc->model->analog_channels; i++) {
+			if (rigol_ds_config_set(sdi, ":WAV:SOUR CHAN%d", i + 1) != SR_OK)
+				return SR_ERR;
+			if (sr_scpi_get_int(sdi->conn, ":WAV:YREF?", &devc->vert_reference[i]) != SR_OK)
+				return SR_ERR;
+			sr_dbg("CH%d %d", i + 1, devc->vert_reference[i]);
+		}
+	}
+
+	/* Vertical offset. */
+	for (i = 0; i < devc->model->analog_channels; i++) {
+		cmd = g_strdup_printf(":CHAN%d:OFFS?", i + 1);
+		res = sr_scpi_get_float(sdi->conn, cmd, &devc->vert_offset[i]);
+		g_free(cmd);
+		if (res != SR_OK)
+			return SR_ERR;
+	}
+	sr_dbg("Current vertical offset:");
+	for (i = 0; i < devc->model->analog_channels; i++)
+		sr_dbg("CH%d %g", i + 1, devc->vert_offset[i]);
+
+	/* Coupling. */
+	for (i = 0; i < devc->model->analog_channels; i++) {
+		cmd = g_strdup_printf(":CHAN%d:COUP?", i + 1);
+		res = sr_scpi_get_string(sdi->conn, cmd, &devc->coupling[i]);
+		g_free(cmd);
+		if (res != SR_OK)
+			return SR_ERR;
+	}
+	sr_dbg("Current coupling:");
+	for (i = 0; i < devc->model->analog_channels; i++)
+		sr_dbg("CH%d %s", i + 1, devc->coupling[i]);
+
+	/* Trigger source. */
+	if (sr_scpi_get_string(sdi->conn, ":TRIG:EDGE:SOUR?", &devc->trigger_source) != SR_OK)
+		return SR_ERR;
+	sr_dbg("Current trigger source %s", devc->trigger_source);
+
+	/* Horizontal trigger position. */
+	if (sr_scpi_get_float(sdi->conn, ":TIM:OFFS?", &devc->horiz_triggerpos) != SR_OK)
+		return SR_ERR;
+	sr_dbg("Current horizontal trigger position %g", devc->horiz_triggerpos);
+
+	/* Trigger slope. */
+	if (sr_scpi_get_string(sdi->conn, ":TRIG:EDGE:SLOP?", &devc->trigger_slope) != SR_OK)
+		return SR_ERR;
+	sr_dbg("Current trigger slope %s", devc->trigger_slope);
+
+	return SR_OK;
+}
diff --git a/hardware/rigol-ds/protocol.h b/hardware/rigol-ds/protocol.h
new file mode 100644
index 0000000..0117628
--- /dev/null
+++ b/hardware/rigol-ds/protocol.h
@@ -0,0 +1,155 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Martin Ling <martin-git at earth.li>
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_RIGOL_DS_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_RIGOL_DS_PROTOCOL_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "rigol-ds"
+
+/* Size of acquisition buffers */
+#define ACQ_BUFFER_SIZE 32768
+
+#define MAX_ANALOG_CHANNELS 4
+#define MAX_DIGITAL_CHANNELS 16
+
+enum protocol_version {
+	PROTOCOL_V1, /* VS5000 */
+	PROTOCOL_V2, /* DS1000 */
+	PROTOCOL_V3, /* DS2000, DSO1000 */
+};
+
+enum data_format {
+	/* Used by DS1000 versions up to 2.02, and VS5000 series */
+	FORMAT_RAW,
+	/* Used by DS1000 versions from 2.04 onwards and all later series */
+	FORMAT_IEEE488_2,
+};
+
+enum data_source {
+	DATA_SOURCE_LIVE,
+	DATA_SOURCE_MEMORY,
+	DATA_SOURCE_SEGMENTED,
+};
+
+struct rigol_ds_vendor {
+	const char *name;
+	const char *full_name;
+};
+
+struct rigol_ds_series {
+	const struct rigol_ds_vendor *vendor;
+	const char *name;
+	enum protocol_version protocol;
+	enum data_format format;
+	uint64_t max_timebase[2];
+	uint64_t min_vdiv[2];
+	int num_horizontal_divs;
+	int live_samples;
+	int buffer_samples;
+};
+
+struct rigol_ds_model {
+	const struct rigol_ds_series *series;
+	const char *name;
+	uint64_t min_timebase[2];
+	unsigned int analog_channels;
+	bool has_digital;
+};
+
+enum wait_events {
+	WAIT_NONE,    /* Don't wait */
+	WAIT_TRIGGER, /* Wait for trigger (only live capture) */
+	WAIT_BLOCK,   /* Wait for block data (only when reading sample mem) */
+	WAIT_STOP,    /* Wait for scope stopping (only single shots) */
+};
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+	/* Device model */
+	const struct rigol_ds_model *model;
+	enum data_format format;
+
+	/* Device properties */
+	const uint64_t (*timebases)[2];
+	uint64_t num_timebases;
+	const uint64_t (*vdivs)[2];
+	uint64_t num_vdivs;
+
+	/* Channel groups */
+	struct sr_channel_group analog_groups[MAX_ANALOG_CHANNELS];
+	struct sr_channel_group digital_group;
+
+	/* Acquisition settings */
+	GSList *enabled_analog_channels;
+	GSList *enabled_digital_channels;
+	uint64_t limit_frames;
+	void *cb_data;
+	enum data_source data_source;
+	uint64_t analog_frame_size;
+	uint64_t digital_frame_size;
+
+	/* Device settings */
+	gboolean analog_channels[MAX_ANALOG_CHANNELS];
+	gboolean digital_channels[MAX_DIGITAL_CHANNELS];
+	gboolean la_enabled;
+	float timebase;
+	float vdiv[MAX_ANALOG_CHANNELS];
+	int vert_reference[MAX_ANALOG_CHANNELS];
+	float vert_offset[MAX_ANALOG_CHANNELS];
+	char *trigger_source;
+	float horiz_triggerpos;
+	char *trigger_slope;
+	char *coupling[MAX_ANALOG_CHANNELS];
+
+	/* Operational state */
+
+	/* Number of frames received in total. */
+	uint64_t num_frames;
+	/* GSList entry for the current channel. */
+	GSList *channel_entry;
+	/* Number of bytes received for current channel. */
+	uint64_t num_channel_bytes;
+	/* Number of bytes of block header read */
+	uint64_t num_header_bytes;
+	/* Number of bytes in current data block, if 0 block header expected */
+	uint64_t num_block_bytes;
+	/* Number of data block bytes already read */
+	uint64_t num_block_read;
+	/* What to wait for in *_receive */
+	enum wait_events wait_event;
+	/* Trigger/block copying/stop waiting status */
+	int wait_status;
+	/* Acq buffers used for reading from the scope and sending data to app */
+	unsigned char *buffer;
+	float *data;
+};
+
+SR_PRIV int rigol_ds_config_set(const struct sr_dev_inst *sdi, const char *format, ...);
+SR_PRIV int rigol_ds_capture_start(const struct sr_dev_inst *sdi);
+SR_PRIV int rigol_ds_channel_start(const struct sr_dev_inst *sdi);
+SR_PRIV int rigol_ds_receive(int fd, int revents, void *cb_data);
+SR_PRIV int rigol_ds_get_dev_cfg(const struct sr_dev_inst *sdi);
+
+#endif
diff --git a/hardware/saleae-logic16/api.c b/hardware/saleae-logic16/api.c
new file mode 100644
index 0000000..388d95a
--- /dev/null
+++ b/hardware/saleae-logic16/api.c
@@ -0,0 +1,829 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Marcus Comstedt <marcus at mc.pp.se>
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ * Copyright (C) 2012 Joel Holdsworth <joel at airwebreathe.org.uk>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <libusb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+
+#define LOGIC16_VID		0x21a9
+#define LOGIC16_PID		0x1001
+
+#define USB_INTERFACE		0
+#define USB_CONFIGURATION	1
+#define FX2_FIRMWARE		FIRMWARE_DIR "/saleae-logic16-fx2.fw"
+
+#define MAX_RENUM_DELAY_MS	3000
+#define NUM_SIMUL_TRANSFERS	32
+
+SR_PRIV struct sr_dev_driver saleae_logic16_driver_info;
+static struct sr_dev_driver *di = &saleae_logic16_driver_info;
+
+static const int32_t hwopts[] = {
+	SR_CONF_CONN,
+};
+
+static const int32_t hwcaps[] = {
+	SR_CONF_LOGIC_ANALYZER,
+	SR_CONF_SAMPLERATE,
+	SR_CONF_VOLTAGE_THRESHOLD,
+
+	/* These are really implemented in the driver, not the hardware. */
+	SR_CONF_LIMIT_SAMPLES,
+	SR_CONF_CONTINUOUS,
+};
+
+static const char *channel_names[] = {
+	"0", "1", "2", "3", "4", "5", "6", "7", "8",
+	"9", "10", "11", "12", "13", "14", "15",
+	NULL,
+};
+
+static const struct {
+	enum voltage_range range;
+	gdouble low;
+	gdouble high;
+} volt_thresholds[] = {
+	{ VOLTAGE_RANGE_18_33_V, 0.7, 1.4 },
+	{ VOLTAGE_RANGE_5_V,     1.4, 3.6 },
+};
+
+static const uint64_t samplerates[] = {
+	SR_KHZ(500),
+	SR_MHZ(1),
+	SR_MHZ(2),
+	SR_MHZ(4),
+	SR_MHZ(5),
+	SR_MHZ(8),
+	SR_MHZ(10),
+	SR_KHZ(12500),
+	SR_MHZ(16),
+	SR_MHZ(25),
+	SR_MHZ(32),
+	SR_MHZ(40),
+	SR_MHZ(80),
+	SR_MHZ(100),
+};
+
+static int init(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static gboolean check_conf_profile(libusb_device *dev)
+{
+	struct libusb_device_descriptor des;
+	struct libusb_device_handle *hdl;
+	gboolean ret;
+	unsigned char strdesc[64];
+
+	hdl = NULL;
+	ret = FALSE;
+	while (!ret) {
+		/* Assume the FW has not been loaded, unless proven wrong. */
+		if (libusb_get_device_descriptor(dev, &des) != 0)
+			break;
+
+		if (libusb_open(dev, &hdl) != 0)
+			break;
+
+		if (libusb_get_string_descriptor_ascii(hdl,
+		    des.iManufacturer, strdesc, sizeof(strdesc)) < 0)
+			break;
+		if (strcmp((const char *)strdesc, "Saleae LLC"))
+			break;
+
+		if (libusb_get_string_descriptor_ascii(hdl,
+		    des.iProduct, strdesc, sizeof(strdesc)) < 0)
+			break;
+		if (strcmp((const char *)strdesc, "Logic S/16"))
+			break;
+
+		/* If we made it here, it must be a configured Logic16. */
+		ret = TRUE;
+	}
+	if (hdl)
+		libusb_close(hdl);
+
+	return ret;
+}
+
+static GSList *scan(GSList *options)
+{
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_dev_inst *sdi;
+	struct sr_usb_dev_inst *usb;
+	struct sr_channel *ch;
+	struct sr_config *src;
+	GSList *l, *devices, *conn_devices;
+	struct libusb_device_descriptor des;
+	libusb_device **devlist;
+	int devcnt, ret, i, j;
+	const char *conn;
+
+	drvc = di->priv;
+
+	conn = NULL;
+	for (l = options; l; l = l->next) {
+		src = l->data;
+		switch (src->key) {
+		case SR_CONF_CONN:
+			conn = g_variant_get_string(src->data, NULL);
+			break;
+		}
+	}
+	if (conn)
+		conn_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn);
+	else
+		conn_devices = NULL;
+
+	/* Find all Logic16 devices and upload firmware to them. */
+	devices = NULL;
+	libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
+	for (i = 0; devlist[i]; i++) {
+		if (conn) {
+			usb = NULL;
+			for (l = conn_devices; l; l = l->next) {
+				usb = l->data;
+				if (usb->bus == libusb_get_bus_number(devlist[i])
+				    && usb->address == libusb_get_device_address(devlist[i]))
+					break;
+			}
+			if (!l)
+				/* This device matched none of the ones that
+				 * matched the conn specification. */
+				continue;
+		}
+
+		if ((ret = libusb_get_device_descriptor(devlist[i], &des)) != 0) {
+			sr_warn("Failed to get device descriptor: %s.",
+				libusb_error_name(ret));
+			continue;
+		}
+
+		if (des.idVendor != LOGIC16_VID || des.idProduct != LOGIC16_PID)
+			continue;
+
+		devcnt = g_slist_length(drvc->instances);
+		sdi = sr_dev_inst_new(devcnt, SR_ST_INITIALIZING,
+				      "Saleae", "Logic16", NULL);
+		if (!sdi)
+			return NULL;
+		sdi->driver = di;
+
+		for (j = 0; channel_names[j]; j++) {
+			if (!(ch = sr_channel_new(j, SR_CHANNEL_LOGIC, TRUE,
+						   channel_names[j])))
+				return NULL;
+			sdi->channels = g_slist_append(sdi->channels, ch);
+		}
+
+		if (!(devc = g_try_malloc0(sizeof(struct dev_context))))
+			return NULL;
+		devc->selected_voltage_range = VOLTAGE_RANGE_18_33_V;
+		sdi->priv = devc;
+		drvc->instances = g_slist_append(drvc->instances, sdi);
+		devices = g_slist_append(devices, sdi);
+
+		if (check_conf_profile(devlist[i])) {
+			/* Already has the firmware, so fix the new address. */
+			sr_dbg("Found a Logic16 device.");
+			sdi->status = SR_ST_INACTIVE;
+			sdi->inst_type = SR_INST_USB;
+			sdi->conn = sr_usb_dev_inst_new(
+				libusb_get_bus_number(devlist[i]),
+				libusb_get_device_address(devlist[i]), NULL);
+		} else {
+			if (ezusb_upload_firmware(devlist[i], USB_CONFIGURATION,
+						  FX2_FIRMWARE) == SR_OK)
+				/* Store when this device's FW was updated. */
+				devc->fw_updated = g_get_monotonic_time();
+			else
+				sr_err("Firmware upload failed for "
+				       "device %d.", devcnt);
+			sdi->inst_type = SR_INST_USB;
+			sdi->conn = sr_usb_dev_inst_new(
+				libusb_get_bus_number(devlist[i]), 0xff, NULL);
+		}
+	}
+	libusb_free_device_list(devlist, 1);
+	g_slist_free_full(conn_devices, (GDestroyNotify)sr_usb_dev_inst_free);
+
+	return devices;
+}
+
+static GSList *dev_list(void)
+{
+	return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int logic16_dev_open(struct sr_dev_inst *sdi)
+{
+	libusb_device **devlist;
+	struct sr_usb_dev_inst *usb;
+	struct libusb_device_descriptor des;
+	struct drv_context *drvc;
+	int ret, skip, i, device_count;
+
+	drvc = di->priv;
+	usb = sdi->conn;
+
+	if (sdi->status == SR_ST_ACTIVE)
+		/* Device is already in use. */
+		return SR_ERR;
+
+	skip = 0;
+	device_count = libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
+	if (device_count < 0) {
+		sr_err("Failed to get device list: %s.",
+		       libusb_error_name(device_count));
+		return SR_ERR;
+	}
+
+	for (i = 0; i < device_count; i++) {
+		if ((ret = libusb_get_device_descriptor(devlist[i], &des))) {
+			sr_err("Failed to get device descriptor: %s.",
+			       libusb_error_name(ret));
+			continue;
+		}
+
+		if (des.idVendor != LOGIC16_VID || des.idProduct != LOGIC16_PID)
+			continue;
+
+		if (sdi->status == SR_ST_INITIALIZING) {
+			if (skip != sdi->index) {
+				/* Skip devices of this type that aren't the one we want. */
+				skip += 1;
+				continue;
+			}
+		} else if (sdi->status == SR_ST_INACTIVE) {
+			/*
+			 * This device is fully enumerated, so we need to find
+			 * this device by vendor, product, bus and address.
+			 */
+			if (libusb_get_bus_number(devlist[i]) != usb->bus
+			    || libusb_get_device_address(devlist[i]) != usb->address)
+				/* This is not the one. */
+				continue;
+		}
+
+		if (!(ret = libusb_open(devlist[i], &usb->devhdl))) {
+			if (usb->address == 0xff)
+				/*
+				 * First time we touch this device after FW
+				 * upload, so we don't know the address yet.
+				 */
+				usb->address = libusb_get_device_address(devlist[i]);
+		} else {
+			sr_err("Failed to open device: %s.",
+			       libusb_error_name(ret));
+			break;
+		}
+
+		ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE);
+		if (ret == LIBUSB_ERROR_BUSY) {
+			sr_err("Unable to claim USB interface. Another "
+			       "program or driver has already claimed it.");
+			break;
+		} else if (ret == LIBUSB_ERROR_NO_DEVICE) {
+			sr_err("Device has been disconnected.");
+			break;
+		} else if (ret != 0) {
+			sr_err("Unable to claim interface: %s.",
+			       libusb_error_name(ret));
+			break;
+		}
+
+		if ((ret = logic16_init_device(sdi)) != SR_OK) {
+			sr_err("Failed to init device.");
+			break;
+		}
+
+		sdi->status = SR_ST_ACTIVE;
+		sr_info("Opened device %d on %d.%d, interface %d.",
+			sdi->index, usb->bus, usb->address, USB_INTERFACE);
+
+		break;
+	}
+	libusb_free_device_list(devlist, 1);
+
+	if (sdi->status != SR_ST_ACTIVE) {
+		if (usb->devhdl) {
+			libusb_release_interface(usb->devhdl, USB_INTERFACE);
+			libusb_close(usb->devhdl);
+			usb->devhdl = NULL;
+		}
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	int ret;
+	int64_t timediff_us, timediff_ms;
+
+	devc = sdi->priv;
+
+	/*
+	 * If the firmware was recently uploaded, wait up to MAX_RENUM_DELAY_MS
+	 * milliseconds for the FX2 to renumerate.
+	 */
+	ret = SR_ERR;
+	if (devc->fw_updated > 0) {
+		sr_info("Waiting for device to reset.");
+		/* Takes >= 300ms for the FX2 to be gone from the USB bus. */
+		g_usleep(300 * 1000);
+		timediff_ms = 0;
+		while (timediff_ms < MAX_RENUM_DELAY_MS) {
+			if ((ret = logic16_dev_open(sdi)) == SR_OK)
+				break;
+			g_usleep(100 * 1000);
+
+			timediff_us = g_get_monotonic_time() - devc->fw_updated;
+			timediff_ms = timediff_us / 1000;
+			sr_spew("Waited %" PRIi64 "ms.", timediff_ms);
+		}
+		if (ret != SR_OK) {
+			sr_err("Device failed to renumerate.");
+			return SR_ERR;
+		}
+		sr_info("Device came back after %" PRIi64 "ms.", timediff_ms);
+	} else {
+		sr_info("Firmware upload was not needed.");
+		ret = logic16_dev_open(sdi);
+	}
+
+	if (ret != SR_OK) {
+		sr_err("Unable to open device.");
+		return SR_ERR;
+	}
+
+	if (devc->cur_samplerate == 0) {
+		/* Samplerate hasn't been set; default to the slowest one. */
+		devc->cur_samplerate = samplerates[0];
+	}
+
+	return SR_OK;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+	struct sr_usb_dev_inst *usb;
+
+	usb = sdi->conn;
+	if (usb->devhdl == NULL)
+		return SR_ERR;
+
+	sr_info("Closing device %d on %d.%d interface %d.",
+		sdi->index, usb->bus, usb->address, USB_INTERFACE);
+	libusb_release_interface(usb->devhdl, USB_INTERFACE);
+	libusb_close(usb->devhdl);
+	usb->devhdl = NULL;
+	sdi->status = SR_ST_INACTIVE;
+
+	return SR_OK;
+}
+
+static int cleanup(void)
+{
+	int ret;
+	struct drv_context *drvc;
+
+	if (!(drvc = di->priv))
+		/* Can get called on an unused driver, doesn't matter. */
+		return SR_OK;
+
+
+	ret = std_dev_clear(di, NULL);
+	g_free(drvc);
+	di->priv = NULL;
+
+	return ret;
+}
+
+static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	struct sr_usb_dev_inst *usb;
+	GVariant *range[2];
+	char str[128];
+	int ret;
+	unsigned int i;
+
+	(void)cg;
+
+	ret = SR_OK;
+	switch (key) {
+	case SR_CONF_CONN:
+		if (!sdi || !sdi->conn)
+			return SR_ERR_ARG;
+		usb = sdi->conn;
+		if (usb->address == 255)
+			/* Device still needs to re-enumerate after firmware
+			 * upload, so we don't know its (future) address. */
+			return SR_ERR;
+		snprintf(str, 128, "%d.%d", usb->bus, usb->address);
+		*data = g_variant_new_string(str);
+		break;
+	case SR_CONF_SAMPLERATE:
+		if (!sdi)
+			return SR_ERR;
+		devc = sdi->priv;
+		*data = g_variant_new_uint64(devc->cur_samplerate);
+		break;
+	case SR_CONF_VOLTAGE_THRESHOLD:
+		if (!sdi)
+			return SR_ERR;
+		devc = sdi->priv;
+		ret = SR_ERR;
+		for (i = 0; i < ARRAY_SIZE(volt_thresholds); i++) {
+			if (devc->selected_voltage_range !=
+			    volt_thresholds[i].range)
+				continue;
+			range[0] = g_variant_new_double(volt_thresholds[i].low);
+			range[1] = g_variant_new_double(volt_thresholds[i].high);
+			*data = g_variant_new_tuple(range, 2);
+			ret = SR_OK;
+			break;
+		}
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return ret;
+}
+
+static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	gdouble low, high;
+	int ret;
+	unsigned int i;
+
+	(void)cg;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	devc = sdi->priv;
+
+	ret = SR_OK;
+	switch (key) {
+	case SR_CONF_SAMPLERATE:
+		devc->cur_samplerate = g_variant_get_uint64(data);
+		break;
+	case SR_CONF_LIMIT_SAMPLES:
+		devc->limit_samples = g_variant_get_uint64(data);
+		break;
+	case SR_CONF_VOLTAGE_THRESHOLD:
+		g_variant_get(data, "(dd)", &low, &high);
+		ret = SR_ERR_ARG;
+		for (i = 0; i < ARRAY_SIZE(volt_thresholds); i++) {
+			if (fabs(volt_thresholds[i].low - low) < 0.1 &&
+			    fabs(volt_thresholds[i].high - high) < 0.1) {
+				devc->selected_voltage_range =
+					volt_thresholds[i].range;
+				ret = SR_OK;
+				break;
+			}
+		}
+		break;
+	default:
+		ret = SR_ERR_NA;
+	}
+
+	return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	GVariant *gvar, *range[2];
+	GVariantBuilder gvb;
+	int ret;
+	unsigned int i;
+
+	(void)sdi;
+	(void)cg;
+
+	ret = SR_OK;
+	switch (key) {
+	case SR_CONF_SCAN_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+		break;
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+		break;
+	case SR_CONF_SAMPLERATE:
+		g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
+		gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
+			samplerates, ARRAY_SIZE(samplerates), sizeof(uint64_t));
+		g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
+		*data = g_variant_builder_end(&gvb);
+		break;
+	case SR_CONF_VOLTAGE_THRESHOLD:
+		g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
+		for (i = 0; i < ARRAY_SIZE(volt_thresholds); i++) {
+			range[0] = g_variant_new_double(volt_thresholds[i].low);
+			range[1] = g_variant_new_double(volt_thresholds[i].high);
+			gvar = g_variant_new_tuple(range, 2);
+			g_variant_builder_add_value(&gvb, gvar);
+		}
+		*data = g_variant_builder_end(&gvb);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return ret;
+}
+
+static void abort_acquisition(struct dev_context *devc)
+{
+	int i;
+
+	devc->num_samples = -1;
+
+	for (i = devc->num_transfers - 1; i >= 0; i--) {
+		if (devc->transfers[i])
+			libusb_cancel_transfer(devc->transfers[i]);
+	}
+}
+
+static unsigned int bytes_per_ms(struct dev_context *devc)
+{
+	return devc->cur_samplerate * devc->num_channels / 8000;
+}
+
+static size_t get_buffer_size(struct dev_context *devc)
+{
+	size_t s;
+
+	/*
+	 * The buffer should be large enough to hold 10ms of data and
+	 * a multiple of 512.
+	 */
+	s = 10 * bytes_per_ms(devc);
+	return (s + 511) & ~511;
+}
+
+static unsigned int get_number_of_transfers(struct dev_context *devc)
+{
+	unsigned int n;
+
+	/* Total buffer size should be able to hold about 500ms of data. */
+	n = 500 * bytes_per_ms(devc) / get_buffer_size(devc);
+
+	if (n > NUM_SIMUL_TRANSFERS)
+		return NUM_SIMUL_TRANSFERS;
+
+	return n;
+}
+
+static unsigned int get_timeout(struct dev_context *devc)
+{
+	size_t total_size;
+	unsigned int timeout;
+
+	total_size = get_buffer_size(devc) * get_number_of_transfers(devc);
+	timeout = total_size / bytes_per_ms(devc);
+	return timeout + timeout / 4; /* Leave a headroom of 25% percent. */
+}
+
+static int configure_channels(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_channel *ch;
+	GSList *l;
+	uint16_t channel_bit;
+#ifdef WORDS_BIGENDIAN
+	int i;
+#endif
+
+	devc = sdi->priv;
+
+	devc->cur_channels = 0;
+	devc->num_channels = 0;
+	for (l = sdi->channels; l; l = l->next) {
+		ch = (struct sr_channel *)l->data;
+		if (ch->enabled == FALSE)
+			continue;
+
+		channel_bit = 1 << (ch->index);
+
+		devc->cur_channels |= channel_bit;
+
+#ifdef WORDS_BIGENDIAN
+		/*
+		 * Output logic data should be stored in little endian format.
+		 * To speed things up during conversion, do the switcharoo
+		 * here instead.
+		 */
+		channel_bit = 1 << (ch->index ^ 8);
+#endif
+
+		devc->channel_masks[devc->num_channels++] = channel_bit;
+	}
+
+	if (devc->cur_channels & ~0xff) {
+		devc->unitsize = 2;
+	} else {
+#ifdef WORDS_BIGENDIAN
+		for (i = 0; i < devc->num_channels; i++)
+			devc->channel_masks[i] >>= 8;
+#endif
+		devc->unitsize = 1;
+	}
+
+	return SR_OK;
+}
+
+static int receive_data(int fd, int revents, void *cb_data)
+{
+	struct timeval tv;
+	struct dev_context *devc;
+	struct drv_context *drvc;
+	const struct sr_dev_inst *sdi;
+
+	(void)fd;
+	(void)revents;
+
+	sdi = cb_data;
+	drvc = di->priv;
+	devc = sdi->priv;
+
+	tv.tv_sec = tv.tv_usec = 0;
+	libusb_handle_events_timeout(drvc->sr_ctx->libusb_ctx, &tv);
+
+	if (devc->num_samples == -2) {
+		logic16_abort_acquisition(sdi);
+		abort_acquisition(devc);
+	}
+
+	return TRUE;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct dev_context *devc;
+	struct drv_context *drvc;
+	struct sr_usb_dev_inst *usb;
+	struct libusb_transfer *transfer;
+	unsigned int i, timeout, num_transfers;
+	int ret;
+	unsigned char *buf;
+	size_t size, convsize;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	drvc = di->priv;
+	devc = sdi->priv;
+	usb = sdi->conn;
+
+	/* Configures devc->cur_channels. */
+	if (configure_channels(sdi) != SR_OK) {
+		sr_err("Failed to configure channels.");
+		return SR_ERR;
+	}
+
+	devc->cb_data = cb_data;
+	devc->num_samples = 0;
+	devc->empty_transfer_count = 0;
+	devc->cur_channel = 0;
+	memset(devc->channel_data, 0, sizeof(devc->channel_data));
+
+	timeout = get_timeout(devc);
+	num_transfers = get_number_of_transfers(devc);
+	size = get_buffer_size(devc);
+	convsize = (size / devc->num_channels + 2) * 16;
+	devc->submitted_transfers = 0;
+
+	devc->convbuffer_size = convsize;
+	if (!(devc->convbuffer = g_try_malloc(convsize))) {
+		sr_err("Conversion buffer malloc failed.");
+		return SR_ERR_MALLOC;
+	}
+
+	devc->transfers = g_try_malloc0(sizeof(*devc->transfers) * num_transfers);
+	if (!devc->transfers) {
+		sr_err("USB transfers malloc failed.");
+		g_free(devc->convbuffer);
+		return SR_ERR_MALLOC;
+	}
+
+	if ((ret = logic16_setup_acquisition(sdi, devc->cur_samplerate,
+					     devc->cur_channels)) != SR_OK) {
+		g_free(devc->transfers);
+		g_free(devc->convbuffer);
+		return ret;
+	}
+
+	devc->num_transfers = num_transfers;
+	for (i = 0; i < num_transfers; i++) {
+		if (!(buf = g_try_malloc(size))) {
+			sr_err("USB transfer buffer malloc failed.");
+			if (devc->submitted_transfers)
+				abort_acquisition(devc);
+			else {
+				g_free(devc->transfers);
+				g_free(devc->convbuffer);
+			}
+			return SR_ERR_MALLOC;
+		}
+		transfer = libusb_alloc_transfer(0);
+		libusb_fill_bulk_transfer(transfer, usb->devhdl,
+				2 | LIBUSB_ENDPOINT_IN, buf, size,
+				logic16_receive_transfer, devc, timeout);
+		if ((ret = libusb_submit_transfer(transfer)) != 0) {
+			sr_err("Failed to submit transfer: %s.",
+			       libusb_error_name(ret));
+			libusb_free_transfer(transfer);
+			g_free(buf);
+			abort_acquisition(devc);
+			return SR_ERR;
+		}
+		devc->transfers[i] = transfer;
+		devc->submitted_transfers++;
+	}
+
+	devc->ctx = drvc->sr_ctx;
+
+	usb_source_add(devc->ctx, timeout, receive_data, (void *)sdi);
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	if ((ret = logic16_start_acquisition(sdi)) != SR_OK) {
+		abort_acquisition(devc);
+		return ret;
+	}
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	int ret;
+
+	(void)cb_data;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	ret = logic16_abort_acquisition(sdi);
+
+	abort_acquisition(sdi->priv);
+
+	return ret;
+}
+
+SR_PRIV struct sr_dev_driver saleae_logic16_driver_info = {
+	.name = "saleae-logic16",
+	.longname = "Saleae Logic16",
+	.api_version = 1,
+	.init = init,
+	.cleanup = cleanup,
+	.scan = scan,
+	.dev_list = dev_list,
+	.dev_clear = NULL,
+	.config_get = config_get,
+	.config_set = config_set,
+	.config_list = config_list,
+	.dev_open = dev_open,
+	.dev_close = dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/saleae-logic16/protocol.c b/hardware/saleae-logic16/protocol.c
new file mode 100644
index 0000000..e2c5f88
--- /dev/null
+++ b/hardware/saleae-logic16/protocol.c
@@ -0,0 +1,819 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Marcus Comstedt <marcus at mc.pp.se>
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ * Copyright (C) 2012 Joel Holdsworth <joel at airwebreathe.org.uk>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "protocol.h"
+
+#include <stdint.h>
+#include <string.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <stdio.h>
+#include <errno.h>
+#include <math.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define FPGA_FIRMWARE_18	FIRMWARE_DIR"/saleae-logic16-fpga-18.bitstream"
+#define FPGA_FIRMWARE_33	FIRMWARE_DIR"/saleae-logic16-fpga-33.bitstream"
+
+#define MAX_SAMPLE_RATE		SR_MHZ(100)
+#define MAX_4CH_SAMPLE_RATE	SR_MHZ(50)
+#define MAX_7CH_SAMPLE_RATE	SR_MHZ(40)
+#define MAX_8CH_SAMPLE_RATE	SR_MHZ(32)
+#define MAX_10CH_SAMPLE_RATE	SR_MHZ(25)
+#define MAX_13CH_SAMPLE_RATE	SR_MHZ(16)
+
+#define BASE_CLOCK_0_FREQ	SR_MHZ(100)
+#define BASE_CLOCK_1_FREQ	SR_MHZ(160)
+
+#define COMMAND_START_ACQUISITION	1
+#define COMMAND_ABORT_ACQUISITION_ASYNC	2
+#define COMMAND_WRITE_EEPROM		6
+#define COMMAND_READ_EEPROM		7
+#define COMMAND_WRITE_LED_TABLE		0x7a
+#define COMMAND_SET_LED_MODE		0x7b
+#define COMMAND_RETURN_TO_BOOTLOADER	0x7c
+#define COMMAND_ABORT_ACQUISITION_SYNC	0x7d
+#define COMMAND_FPGA_UPLOAD_INIT	0x7e
+#define COMMAND_FPGA_UPLOAD_SEND_DATA	0x7f
+#define COMMAND_FPGA_WRITE_REGISTER	0x80
+#define COMMAND_FPGA_READ_REGISTER	0x81
+#define COMMAND_GET_REVID		0x82
+
+#define WRITE_EEPROM_COOKIE1		0x42
+#define WRITE_EEPROM_COOKIE2		0x55
+#define READ_EEPROM_COOKIE1		0x33
+#define READ_EEPROM_COOKIE2		0x81
+#define ABORT_ACQUISITION_SYNC_PATTERN	0x55
+
+#define MAX_EMPTY_TRANSFERS		64
+
+static void encrypt(uint8_t *dest, const uint8_t *src, uint8_t cnt)
+{
+	uint8_t state1 = 0x9b, state2 = 0x54;
+	uint8_t t, v;
+	int i;
+
+	for (i = 0; i < cnt; i++) {
+		v = src[i];
+		t = (((v ^ state2 ^ 0x2b) - 0x05) ^ 0x35) - 0x39;
+		t = (((t ^ state1 ^ 0x5a) - 0xb0) ^ 0x38) - 0x45;
+		dest[i] = state2 = t;
+		state1 = v;
+	}
+}
+
+static void decrypt(uint8_t *dest, const uint8_t *src, uint8_t cnt)
+{
+	uint8_t state1 = 0x9b, state2 = 0x54;
+	uint8_t t, v;
+	int i;
+
+	for (i = 0; i < cnt; i++) {
+		v = src[i];
+		t = (((v + 0x45) ^ 0x38) + 0xb0) ^ 0x5a ^ state1;
+		t = (((t + 0x39) ^ 0x35) + 0x05) ^ 0x2b ^ state2;
+		dest[i] = state1 = t;
+		state2 = v;
+	}
+}
+
+static int do_ep1_command(const struct sr_dev_inst *sdi,
+			  const uint8_t *command, uint8_t cmd_len,
+			  uint8_t *reply, uint8_t reply_len)
+{
+	uint8_t buf[64];
+	struct sr_usb_dev_inst *usb;
+	int ret, xfer;
+
+	usb = sdi->conn;
+
+	if (cmd_len < 1 || cmd_len > 64 || reply_len > 64 ||
+	    command == NULL || (reply_len > 0 && reply == NULL))
+		return SR_ERR_ARG;
+
+	encrypt(buf, command, cmd_len);
+
+	ret = libusb_bulk_transfer(usb->devhdl, 1, buf, cmd_len, &xfer, 1000);
+	if (ret != 0) {
+		sr_dbg("Failed to send EP1 command 0x%02x: %s.",
+		       command[0], libusb_error_name(ret));
+		return SR_ERR;
+	}
+	if (xfer != cmd_len) {
+		sr_dbg("Failed to send EP1 command 0x%02x: incorrect length "
+		       "%d != %d.", xfer, cmd_len);
+		return SR_ERR;
+	}
+
+	if (reply_len == 0)
+		return SR_OK;
+
+	ret = libusb_bulk_transfer(usb->devhdl, 0x80 | 1, buf, reply_len,
+				   &xfer, 1000);
+	if (ret != 0) {
+		sr_dbg("Failed to receive reply to EP1 command 0x%02x: %s.",
+		       command[0], libusb_error_name(ret));
+		return SR_ERR;
+	}
+	if (xfer != reply_len) {
+		sr_dbg("Failed to receive reply to EP1 command 0x%02x: "
+		       "incorrect length %d != %d.", xfer, reply_len);
+		return SR_ERR;
+	}
+
+	decrypt(reply, buf, reply_len);
+
+	return SR_OK;
+}
+
+static int read_eeprom(const struct sr_dev_inst *sdi,
+		       uint8_t address, uint8_t length, uint8_t *buf)
+{
+	uint8_t command[5] = {
+		COMMAND_READ_EEPROM,
+		READ_EEPROM_COOKIE1,
+		READ_EEPROM_COOKIE2,
+		address,
+		length,
+	};
+
+	return do_ep1_command(sdi, command, 5, buf, length);
+}
+
+static int upload_led_table(const struct sr_dev_inst *sdi,
+			    const uint8_t *table, uint8_t offset, uint8_t cnt)
+{
+	uint8_t chunk, command[64];
+	int ret;
+
+	if (cnt < 1 || cnt + offset > 64 || table == NULL)
+		return SR_ERR_ARG;
+
+	while (cnt > 0) {
+		chunk = (cnt > 32 ? 32 : cnt);
+
+		command[0] = COMMAND_WRITE_LED_TABLE;
+		command[1] = offset;
+		command[2] = chunk;
+		memcpy(command + 3, table, chunk);
+
+		ret = do_ep1_command(sdi, command, 3 + chunk, NULL, 0);
+		if (ret != SR_OK)
+			return ret;
+
+		table += chunk;
+		offset += chunk;
+		cnt -= chunk;
+	}
+
+	return SR_OK;
+}
+
+static int set_led_mode(const struct sr_dev_inst *sdi,
+			uint8_t animate, uint16_t t2reload, uint8_t div,
+			uint8_t repeat)
+{
+	uint8_t command[6] = {
+		COMMAND_SET_LED_MODE,
+		animate,
+		t2reload & 0xff,
+		t2reload >> 8,
+		div,
+		repeat,
+	};
+
+	return do_ep1_command(sdi, command, 6, NULL, 0);
+}
+
+static int read_fpga_register(const struct sr_dev_inst *sdi,
+			      uint8_t address, uint8_t *value)
+{
+	uint8_t command[3] = {
+		COMMAND_FPGA_READ_REGISTER,
+		1,
+		address,
+	};
+
+	return do_ep1_command(sdi, command, 3, value, 1);
+}
+
+static int write_fpga_registers(const struct sr_dev_inst *sdi,
+				uint8_t (*regs)[2], uint8_t cnt)
+{
+	uint8_t command[64];
+	int i;
+
+	if (cnt < 1 || cnt > 31)
+		return SR_ERR_ARG;
+
+	command[0] = COMMAND_FPGA_WRITE_REGISTER;
+	command[1] = cnt;
+	for (i = 0; i < cnt; i++) {
+		command[2 + 2 * i] = regs[i][0];
+		command[3 + 2 * i] = regs[i][1];
+	}
+
+	return do_ep1_command(sdi, command, 2 * (cnt + 1), NULL, 0);
+}
+
+static int write_fpga_register(const struct sr_dev_inst *sdi,
+			       uint8_t address, uint8_t value)
+{
+	uint8_t regs[2] = { address, value };
+
+	return write_fpga_registers(sdi, &regs, 1);
+}
+
+static uint8_t map_eeprom_data(uint8_t v)
+{
+	return (((v ^ 0x80) + 0x44) ^ 0xd5) + 0x69;
+}
+
+static int prime_fpga(const struct sr_dev_inst *sdi)
+{
+	uint8_t eeprom_data[16];
+	uint8_t old_reg_10, version;
+	uint8_t regs[8][2] = {
+		{10, 0x00},
+		{10, 0x40},
+		{12, 0},
+		{10, 0xc0},
+		{10, 0x40},
+		{6, 0},
+		{7, 1},
+		{7, 0}
+	};
+	int i, ret;
+
+	if ((ret = read_eeprom(sdi, 16, 16, eeprom_data)) != SR_OK)
+		return ret;
+
+	if ((ret = read_fpga_register(sdi, 10, &old_reg_10)) != SR_OK)
+		return ret;
+
+	regs[0][1] = (old_reg_10 &= 0x7f);
+	regs[1][1] |= old_reg_10;
+	regs[3][1] |= old_reg_10;
+	regs[4][1] |= old_reg_10;
+
+	for (i = 0; i < 16; i++) {
+		regs[2][1] = eeprom_data[i];
+		regs[5][1] = map_eeprom_data(eeprom_data[i]);
+		if (i)
+			ret = write_fpga_registers(sdi, &regs[2], 6);
+		else
+			ret = write_fpga_registers(sdi, &regs[0], 8);
+		if (ret != SR_OK)
+			return ret;
+	}
+
+	if ((ret = write_fpga_register(sdi, 10, old_reg_10)) != SR_OK)
+		return ret;
+
+	if ((ret = read_fpga_register(sdi, 0, &version)) != SR_OK)
+		return ret;
+
+	if (version != 0x10) {
+		sr_err("Invalid FPGA bitstream version: 0x%02x != 0x10.", version);
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+static void make_heartbeat(uint8_t *table, int len)
+{
+	int i, j;
+
+	memset(table, 0, len);
+	len >>= 3;
+	for (i = 0; i < 2; i++)
+		for (j = 0; j < len; j++)
+			*table++ = sin(j * M_PI / len) * 255;
+}
+
+static int configure_led(const struct sr_dev_inst *sdi)
+{
+	uint8_t table[64];
+	int ret;
+
+	make_heartbeat(table, 64);
+	if ((ret = upload_led_table(sdi, table, 0, 64)) != SR_OK)
+		return ret;
+
+	return set_led_mode(sdi, 1, 6250, 0, 1);
+}
+
+static int upload_fpga_bitstream(const struct sr_dev_inst *sdi,
+				 enum voltage_range vrange)
+{
+	struct dev_context *devc;
+	int offset, chunksize, ret;
+	const char *filename;
+	uint8_t len, buf[256 * 62], command[64];
+	FILE *fw;
+
+	devc = sdi->priv;
+
+	if (devc->cur_voltage_range == vrange)
+		return SR_OK;
+
+	switch (vrange) {
+	case VOLTAGE_RANGE_18_33_V:
+		filename = FPGA_FIRMWARE_18;
+		break;
+	case VOLTAGE_RANGE_5_V:
+		filename = FPGA_FIRMWARE_33;
+		break;
+	default:
+		sr_err("Unsupported voltage range.");
+		return SR_ERR;
+	}
+
+	sr_info("Uploading FPGA bitstream at %s.", filename);
+	if ((fw = g_fopen(filename, "rb")) == NULL) {
+		sr_err("Unable to open bitstream file %s for reading: %s.",
+		       filename, strerror(errno));
+		return SR_ERR;
+	}
+
+	buf[0] = COMMAND_FPGA_UPLOAD_INIT;
+	if ((ret = do_ep1_command(sdi, buf, 1, NULL, 0)) != SR_OK) {
+		fclose(fw);
+		return ret;
+	}
+
+	while (1) {
+		chunksize = fread(buf, 1, sizeof(buf), fw);
+		if (chunksize == 0)
+			break;
+
+		for (offset = 0; offset < chunksize; offset += 62) {
+			len = (offset + 62 > chunksize ?
+				chunksize - offset : 62);
+			command[0] = COMMAND_FPGA_UPLOAD_SEND_DATA;
+			command[1] = len;
+			memcpy(command + 2, buf + offset, len);
+			ret = do_ep1_command(sdi, command, len + 2, NULL, 0);
+			if (ret != SR_OK) {
+				fclose(fw);
+				return ret;
+			}
+		}
+
+		sr_info("Uploaded %d bytes.", chunksize);
+	}
+	fclose(fw);
+	sr_info("FPGA bitstream upload done.");
+
+	if ((ret = prime_fpga(sdi)) != SR_OK)
+		return ret;
+
+	if ((ret = configure_led(sdi)) != SR_OK)
+		return ret;
+
+	devc->cur_voltage_range = vrange;
+	return SR_OK;
+}
+
+static int abort_acquisition_sync(const struct sr_dev_inst *sdi)
+{
+	static const uint8_t command[2] = {
+		COMMAND_ABORT_ACQUISITION_SYNC,
+		ABORT_ACQUISITION_SYNC_PATTERN,
+	};
+	uint8_t reply, expected_reply;
+	int ret;
+
+	if ((ret = do_ep1_command(sdi, command, 2, &reply, 1)) != SR_OK)
+		return ret;
+
+	expected_reply = ~command[1];
+	if (reply != expected_reply) {
+		sr_err("Invalid response for abort acquisition command: "
+		       "0x%02x != 0x%02x.", reply, expected_reply);
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+SR_PRIV int logic16_setup_acquisition(const struct sr_dev_inst *sdi,
+			     uint64_t samplerate, uint16_t channels)
+{
+	uint8_t clock_select, reg1, reg10;
+	uint64_t div;
+	int i, ret, nchan = 0;
+	struct dev_context *devc;
+
+	devc = sdi->priv;
+
+	if (samplerate == 0 || samplerate > MAX_SAMPLE_RATE) {
+		sr_err("Unable to sample at %" PRIu64 "Hz.", samplerate);
+		return SR_ERR;
+	}
+
+	if (BASE_CLOCK_0_FREQ % samplerate == 0 &&
+	    (div = BASE_CLOCK_0_FREQ / samplerate) <= 256) {
+		clock_select = 0;
+	} else if (BASE_CLOCK_1_FREQ % samplerate == 0 &&
+		   (div = BASE_CLOCK_1_FREQ / samplerate) <= 256) {
+		clock_select = 1;
+	} else {
+		sr_err("Unable to sample at %" PRIu64 "Hz.", samplerate);
+		return SR_ERR;
+	}
+
+	for (i = 0; i < 16; i++)
+		if (channels & (1U << i))
+			nchan++;
+
+	if ((nchan >= 13 && samplerate > MAX_13CH_SAMPLE_RATE) ||
+	    (nchan >= 10 && samplerate > MAX_10CH_SAMPLE_RATE) ||
+	    (nchan >= 8  && samplerate > MAX_8CH_SAMPLE_RATE) ||
+	    (nchan >= 7  && samplerate > MAX_7CH_SAMPLE_RATE) ||
+	    (nchan >= 4  && samplerate > MAX_4CH_SAMPLE_RATE)) {
+		sr_err("Unable to sample at %" PRIu64 "Hz "
+		       "with this many channels.", samplerate);
+		return SR_ERR;
+	}
+
+	ret = upload_fpga_bitstream(sdi, devc->selected_voltage_range);
+	if (ret != SR_OK)
+		return ret;
+
+	if ((ret = read_fpga_register(sdi, 1, &reg1)) != SR_OK)
+		return ret;
+
+	if (reg1 != 0x08) {
+		sr_dbg("Invalid state at acquisition setup: 0x%02x != 0x08.", reg1);
+		return SR_ERR;
+	}
+
+	if ((ret = write_fpga_register(sdi, 1, 0x40)) != SR_OK)
+		return ret;
+
+	if ((ret = write_fpga_register(sdi, 10, clock_select)) != SR_OK)
+		return ret;
+
+	if ((ret = write_fpga_register(sdi, 4, (uint8_t)(div - 1))) != SR_OK)
+		return ret;
+
+	if ((ret = write_fpga_register(sdi, 2, (uint8_t)(channels & 0xff))) != SR_OK)
+		return ret;
+
+	if ((ret = write_fpga_register(sdi, 3, (uint8_t)(channels >> 8))) != SR_OK)
+		return ret;
+
+	if ((ret = write_fpga_register(sdi, 1, 0x42)) != SR_OK)
+		return ret;
+
+	if ((ret = write_fpga_register(sdi, 1, 0x40)) != SR_OK)
+		return ret;
+
+	if ((ret = read_fpga_register(sdi, 1, &reg1)) != SR_OK)
+		return ret;
+
+	if (reg1 != 0x48) {
+		sr_dbg("Invalid state at acquisition setup: 0x%02x != 0x48.", reg1);
+		return SR_ERR;
+	}
+
+	if ((ret = read_fpga_register(sdi, 10, &reg10)) != SR_OK)
+		return ret;
+
+	if (reg10 != clock_select) {
+		sr_dbg("Invalid state at acquisition setup: 0x%02x != 0x%02x.",
+		       reg10, clock_select);
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+SR_PRIV int logic16_start_acquisition(const struct sr_dev_inst *sdi)
+{
+	static const uint8_t command[1] = {
+		COMMAND_START_ACQUISITION,
+	};
+	int ret;
+
+	if ((ret = do_ep1_command(sdi, command, 1, NULL, 0)) != SR_OK)
+		return ret;
+
+	return write_fpga_register(sdi, 1, 0x41);
+}
+
+SR_PRIV int logic16_abort_acquisition(const struct sr_dev_inst *sdi)
+{
+	static const uint8_t command[1] = {
+		COMMAND_ABORT_ACQUISITION_ASYNC,
+	};
+	int ret;
+	uint8_t reg1, reg8, reg9;
+
+	if ((ret = do_ep1_command(sdi, command, 1, NULL, 0)) != SR_OK)
+		return ret;
+
+	if ((ret = write_fpga_register(sdi, 1, 0x00)) != SR_OK)
+		return ret;
+
+	if ((ret = read_fpga_register(sdi, 1, &reg1)) != SR_OK)
+		return ret;
+
+	if (reg1 != 0x08) {
+		sr_dbg("Invalid state at acquisition stop: 0x%02x != 0x08.", reg1);
+		return SR_ERR;
+	}
+
+	if ((ret = read_fpga_register(sdi, 8, &reg8)) != SR_OK)
+		return ret;
+
+	if ((ret = read_fpga_register(sdi, 9, &reg9)) != SR_OK)
+		return ret;
+
+	return SR_OK;
+}
+
+SR_PRIV int logic16_init_device(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	int ret;
+
+	devc = sdi->priv;
+
+	devc->cur_voltage_range = VOLTAGE_RANGE_UNKNOWN;
+
+	if ((ret = abort_acquisition_sync(sdi)) != SR_OK)
+		return ret;
+
+	if ((ret = read_eeprom(sdi, 8, 8, devc->eeprom_data)) != SR_OK)
+		return ret;
+
+	ret = upload_fpga_bitstream(sdi, devc->selected_voltage_range);
+	if (ret != SR_OK)
+		return ret;
+
+	return SR_OK;
+}
+
+static void finish_acquisition(struct dev_context *devc)
+{
+	struct sr_datafeed_packet packet;
+
+	/* Terminate session. */
+	packet.type = SR_DF_END;
+	sr_session_send(devc->cb_data, &packet);
+
+	/* Remove fds from polling. */
+	usb_source_remove(devc->ctx);
+
+	devc->num_transfers = 0;
+	g_free(devc->transfers);
+	g_free(devc->convbuffer);
+}
+
+static void free_transfer(struct libusb_transfer *transfer)
+{
+	struct dev_context *devc;
+	unsigned int i;
+
+	devc = transfer->user_data;
+
+	g_free(transfer->buffer);
+	transfer->buffer = NULL;
+	libusb_free_transfer(transfer);
+
+	for (i = 0; i < devc->num_transfers; i++) {
+		if (devc->transfers[i] == transfer) {
+			devc->transfers[i] = NULL;
+			break;
+		}
+	}
+
+	devc->submitted_transfers--;
+	if (devc->submitted_transfers == 0)
+		finish_acquisition(devc);
+}
+
+static void resubmit_transfer(struct libusb_transfer *transfer)
+{
+	int ret;
+
+	if ((ret = libusb_submit_transfer(transfer)) == LIBUSB_SUCCESS)
+		return;
+
+	free_transfer(transfer);
+	/* TODO: Stop session? */
+
+	sr_err("%s: %s", __func__, libusb_error_name(ret));
+}
+
+static size_t convert_sample_data_16(struct dev_context *devc,
+				     uint8_t *dest, size_t destcnt,
+				     const uint8_t *src, size_t srccnt)
+{
+	uint16_t *channel_data;
+	int i, cur_channel;
+	size_t ret = 0;
+	uint16_t sample, channel_mask;
+
+	srccnt /= 2;
+
+	channel_data = devc->channel_data;
+	cur_channel = devc->cur_channel;
+
+	while (srccnt--) {
+		sample = src[0] | (src[1] << 8);
+		src += 2;
+
+		channel_mask = devc->channel_masks[cur_channel];
+
+		for (i = 15; i >= 0; --i, sample >>= 1)
+			if (sample & 1)
+				channel_data[i] |= channel_mask;
+
+		if (++cur_channel == devc->num_channels) {
+			cur_channel = 0;
+			if (destcnt < 16 * 2) {
+				sr_err("Conversion buffer too small!");
+				break;
+			}
+			memcpy(dest, channel_data, 16 * 2);
+			memset(channel_data, 0, 16 * 2);
+			dest += 16 * 2;
+			ret += 16;
+			destcnt -= 16 * 2;
+		}
+	}
+
+	devc->cur_channel = cur_channel;
+
+	return ret;
+}
+
+static size_t convert_sample_data_8(struct dev_context *devc,
+				    uint8_t *dest, size_t destcnt,
+				    const uint8_t *src, size_t srccnt)
+{
+	uint8_t *channel_data;
+	int i, cur_channel;
+	size_t ret = 0;
+	uint16_t sample;
+	uint8_t channel_mask;
+
+	srccnt /= 2;
+
+	channel_data = (uint8_t *)devc->channel_data;
+	cur_channel = devc->cur_channel;
+
+	while (srccnt--) {
+		sample = src[0] | (src[1] << 8);
+		src += 2;
+
+		channel_mask = devc->channel_masks[cur_channel];
+
+		for (i = 15; i >= 0; --i, sample >>= 1)
+			if (sample & 1)
+				channel_data[i] |= channel_mask;
+
+		if (++cur_channel == devc->num_channels) {
+			cur_channel = 0;
+			if (destcnt < 16) {
+				sr_err("Conversion buffer too small!");
+				break;
+			}
+			memcpy(dest, channel_data, 16);
+			memset(channel_data, 0, 16);
+			dest += 16;
+			ret += 16;
+			destcnt -= 16;
+		}
+	}
+
+	devc->cur_channel = cur_channel;
+
+	return ret;
+}
+
+static size_t convert_sample_data(struct dev_context *devc,
+				  uint8_t *dest, size_t destcnt,
+				  const uint8_t *src, size_t srccnt,
+				  int unitsize)
+{
+	return (unitsize == 2 ?
+		convert_sample_data_16(devc, dest, destcnt, src, srccnt) :
+		convert_sample_data_8(devc, dest, destcnt, src, srccnt));
+}
+
+SR_PRIV void logic16_receive_transfer(struct libusb_transfer *transfer)
+{
+	gboolean packet_has_error = FALSE;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_logic logic;
+	struct dev_context *devc;
+	size_t converted_length;
+
+	devc = transfer->user_data;
+
+	/*
+	 * If acquisition has already ended, just free any queued up
+	 * transfer that come in.
+	 */
+	if (devc->num_samples < 0) {
+		free_transfer(transfer);
+		return;
+	}
+
+	sr_info("receive_transfer(): status %d received %d bytes.",
+		transfer->status, transfer->actual_length);
+
+	switch (transfer->status) {
+	case LIBUSB_TRANSFER_NO_DEVICE:
+		devc->num_samples = -2;
+		free_transfer(transfer);
+		return;
+	case LIBUSB_TRANSFER_COMPLETED:
+	case LIBUSB_TRANSFER_TIMED_OUT: /* We may have received some data though. */
+		break;
+	default:
+		packet_has_error = TRUE;
+		break;
+	}
+
+	if (transfer->actual_length & 1) {
+		sr_err("Got an odd number of bytes from the device. "
+		       "This should not happen.");
+		/* Bail out right away. */
+		packet_has_error = TRUE;
+		devc->empty_transfer_count = MAX_EMPTY_TRANSFERS;
+	}
+
+	if (transfer->actual_length == 0 || packet_has_error) {
+		devc->empty_transfer_count++;
+		if (devc->empty_transfer_count > MAX_EMPTY_TRANSFERS) {
+			/*
+			 * The FX2 gave up. End the acquisition, the frontend
+			 * will work out that the samplecount is short.
+			 */
+			devc->num_samples = -2;
+			free_transfer(transfer);
+		} else {
+			resubmit_transfer(transfer);
+		}
+		return;
+	} else {
+		devc->empty_transfer_count = 0;
+	}
+
+	converted_length = convert_sample_data(devc, devc->convbuffer,
+				devc->convbuffer_size, transfer->buffer,
+				transfer->actual_length, devc->unitsize);
+
+	if (converted_length > 0) {
+		/* Cap sample count if needed. */
+		if (devc->limit_samples &&
+		    (uint64_t)devc->num_samples + converted_length
+		    > devc->limit_samples) {
+			converted_length =
+				devc->limit_samples - devc->num_samples;
+		}
+
+		/* Send the incoming transfer to the session bus. */
+		packet.type = SR_DF_LOGIC;
+		packet.payload = &logic;
+		logic.length = converted_length * devc->unitsize;
+		logic.unitsize = devc->unitsize;
+		logic.data = devc->convbuffer;
+		sr_session_send(devc->cb_data, &packet);
+
+		devc->num_samples += converted_length;
+		if (devc->limit_samples &&
+		    (uint64_t)devc->num_samples >= devc->limit_samples) {
+			devc->num_samples = -2;
+			free_transfer(transfer);
+			return;
+		}
+	}
+
+	resubmit_transfer(transfer);
+}
diff --git a/hardware/saleae-logic16/protocol.h b/hardware/saleae-logic16/protocol.h
new file mode 100644
index 0000000..00f9656
--- /dev/null
+++ b/hardware/saleae-logic16/protocol.h
@@ -0,0 +1,88 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Marcus Comstedt <marcus at mc.pp.se>
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ * Copyright (C) 2012 Joel Holdsworth <joel at airwebreathe.org.uk>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_SALEAE_LOGIC16_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_SALEAE_LOGIC16_PROTOCOL_H
+
+#include <stdint.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "saleae-logic16"
+
+enum voltage_range {
+	VOLTAGE_RANGE_UNKNOWN,
+	VOLTAGE_RANGE_18_33_V,	/* 1.8V and 3.3V logic */
+	VOLTAGE_RANGE_5_V,	/* 5V logic */
+};
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+	/*
+	 * Since we can't keep track of a Logic16 device after upgrading
+	 * the firmware (it renumerates into a different device address
+	 * after the upgrade) this is like a global lock. No device will open
+	 * until a proper delay after the last device was upgraded.
+	 */
+	int64_t fw_updated;
+
+	/** The currently configured samplerate of the device. */
+	uint64_t cur_samplerate;
+
+	/** Maximum number of samples to capture, if nonzero. */
+	uint64_t limit_samples;
+
+	/** The currently configured input voltage of the device. */
+	enum voltage_range cur_voltage_range;
+
+	/** The input voltage selected by the user. */
+	enum voltage_range selected_voltage_range;
+
+	/** Channels to use. */
+	uint16_t cur_channels;
+
+	/* EEPROM data from address 8. */
+	uint8_t eeprom_data[8];
+
+	int64_t num_samples;
+	int submitted_transfers;
+	int empty_transfer_count;
+	int num_channels, cur_channel, unitsize;
+	uint16_t channel_masks[16];
+	uint16_t channel_data[16];
+	uint8_t *convbuffer;
+	size_t convbuffer_size;
+
+	void *cb_data;
+	unsigned int num_transfers;
+	struct libusb_transfer **transfers;
+	struct sr_context *ctx;
+};
+
+SR_PRIV int logic16_setup_acquisition(const struct sr_dev_inst *sdi,
+			uint64_t samplerate, uint16_t channels);
+SR_PRIV int logic16_start_acquisition(const struct sr_dev_inst *sdi);
+SR_PRIV int logic16_abort_acquisition(const struct sr_dev_inst *sdi);
+SR_PRIV int logic16_init_device(const struct sr_dev_inst *sdi);
+SR_PRIV void logic16_receive_transfer(struct libusb_transfer *transfer);
+
+#endif
diff --git a/hardware/serial-dmm/api.c b/hardware/serial-dmm/api.c
new file mode 100644
index 0000000..136d2a7
--- /dev/null
+++ b/hardware/serial-dmm/api.c
@@ -0,0 +1,632 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert at biot.com>
+ * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me at gmail.com>
+ * Copyright (C) 2012 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+
+static const int32_t hwopts[] = {
+	SR_CONF_CONN,
+	SR_CONF_SERIALCOMM,
+};
+
+static const int32_t hwcaps[] = {
+	SR_CONF_MULTIMETER,
+	SR_CONF_LIMIT_SAMPLES,
+	SR_CONF_LIMIT_MSEC,
+	SR_CONF_CONTINUOUS,
+};
+
+SR_PRIV struct sr_dev_driver bbcgm_m2110_driver_info;
+SR_PRIV struct sr_dev_driver digitek_dt4000zc_driver_info;
+SR_PRIV struct sr_dev_driver tekpower_tp4000zc_driver_info;
+SR_PRIV struct sr_dev_driver metex_me31_driver_info;
+SR_PRIV struct sr_dev_driver peaktech_3410_driver_info;
+SR_PRIV struct sr_dev_driver mastech_mas345_driver_info;
+SR_PRIV struct sr_dev_driver va_va18b_driver_info;
+SR_PRIV struct sr_dev_driver va_va40b_driver_info;
+SR_PRIV struct sr_dev_driver metex_m3640d_driver_info;
+SR_PRIV struct sr_dev_driver metex_m4650cr_driver_info;
+SR_PRIV struct sr_dev_driver peaktech_4370_driver_info;
+SR_PRIV struct sr_dev_driver pce_pce_dm32_driver_info;
+SR_PRIV struct sr_dev_driver radioshack_22_168_driver_info;
+SR_PRIV struct sr_dev_driver radioshack_22_805_driver_info;
+SR_PRIV struct sr_dev_driver radioshack_22_812_driver_info;
+SR_PRIV struct sr_dev_driver tecpel_dmm_8061_ser_driver_info;
+SR_PRIV struct sr_dev_driver voltcraft_m3650cr_driver_info;
+SR_PRIV struct sr_dev_driver voltcraft_m3650d_driver_info;
+SR_PRIV struct sr_dev_driver voltcraft_m4650cr_driver_info;
+SR_PRIV struct sr_dev_driver voltcraft_me42_driver_info;
+SR_PRIV struct sr_dev_driver voltcraft_vc820_ser_driver_info;
+SR_PRIV struct sr_dev_driver voltcraft_vc830_ser_driver_info;
+SR_PRIV struct sr_dev_driver voltcraft_vc840_ser_driver_info;
+SR_PRIV struct sr_dev_driver uni_t_ut60a_ser_driver_info;
+SR_PRIV struct sr_dev_driver uni_t_ut60e_ser_driver_info;
+SR_PRIV struct sr_dev_driver uni_t_ut60g_ser_driver_info;
+SR_PRIV struct sr_dev_driver uni_t_ut61b_ser_driver_info;
+SR_PRIV struct sr_dev_driver uni_t_ut61c_ser_driver_info;
+SR_PRIV struct sr_dev_driver uni_t_ut61d_ser_driver_info;
+SR_PRIV struct sr_dev_driver uni_t_ut61e_ser_driver_info;
+SR_PRIV struct sr_dev_driver iso_tech_idm103n_driver_info;
+SR_PRIV struct sr_dev_driver tenma_72_7745_ser_driver_info;
+SR_PRIV struct sr_dev_driver tenma_72_7750_ser_driver_info;
+
+SR_PRIV struct dmm_info dmms[] = {
+	{
+		"BBC Goertz Metrawatt", "M2110", "1200/7n2", 1200,
+		BBCGM_M2110_PACKET_SIZE, NULL,
+		sr_m2110_packet_valid, sr_m2110_parse,
+		NULL,
+		&bbcgm_m2110_driver_info, receive_data_BBCGM_M2110,
+	},
+	{
+		"Digitek", "DT4000ZC", "2400/8n1/dtr=1", 2400,
+		FS9721_PACKET_SIZE, NULL,
+		sr_fs9721_packet_valid, sr_fs9721_parse,
+		sr_fs9721_10_temp_c,
+		&digitek_dt4000zc_driver_info, receive_data_DIGITEK_DT4000ZC,
+	},
+	{
+		"TekPower", "TP4000ZC", "2400/8n1/dtr=1", 2400,
+		FS9721_PACKET_SIZE, NULL,
+		sr_fs9721_packet_valid, sr_fs9721_parse,
+		sr_fs9721_10_temp_c,
+		&tekpower_tp4000zc_driver_info, receive_data_TEKPOWER_TP4000ZC,
+	},
+	{
+		"Metex", "ME-31", "600/7n2/rts=0/dtr=1", 600,
+		METEX14_PACKET_SIZE, sr_metex14_packet_request,
+		sr_metex14_packet_valid, sr_metex14_parse,
+		NULL,
+		&metex_me31_driver_info, receive_data_METEX_ME31,
+	},
+	{
+		"Peaktech", "3410", "600/7n2/rts=0/dtr=1", 600,
+		METEX14_PACKET_SIZE, sr_metex14_packet_request,
+		sr_metex14_packet_valid, sr_metex14_parse,
+		NULL,
+		&peaktech_3410_driver_info, receive_data_PEAKTECH_3410,
+	},
+	{
+		"MASTECH", "MAS345", "600/7n2/rts=0/dtr=1", 600,
+		METEX14_PACKET_SIZE, sr_metex14_packet_request,
+		sr_metex14_packet_valid, sr_metex14_parse,
+		NULL,
+		&mastech_mas345_driver_info, receive_data_MASTECH_MAS345,
+	},
+	{
+		"V&A", "VA18B", "2400/8n1", 2400,
+		FS9721_PACKET_SIZE, NULL,
+		sr_fs9721_packet_valid, sr_fs9721_parse,
+		sr_fs9721_01_temp_c,
+		&va_va18b_driver_info, receive_data_VA_VA18B,
+	},
+	{
+		"V&A", "VA40B", "2400/8n1", 2400,
+		FS9721_PACKET_SIZE, NULL,
+		sr_fs9721_packet_valid, sr_fs9721_parse,
+		sr_fs9721_max_c_min,
+		&va_va40b_driver_info, receive_data_VA_VA40B,
+	},
+	{
+		"Metex", "M-3640D", "1200/7n2/rts=0/dtr=1", 1200,
+		METEX14_PACKET_SIZE, sr_metex14_packet_request,
+		sr_metex14_packet_valid, sr_metex14_parse,
+		NULL,
+		&metex_m3640d_driver_info, receive_data_METEX_M3640D,
+	},
+	{
+		"Metex", "M-4650CR", "1200/7n2/rts=0/dtr=1", 1200,
+		METEX14_PACKET_SIZE, sr_metex14_packet_request,
+		sr_metex14_packet_valid, sr_metex14_parse,
+		NULL,
+		&metex_m4650cr_driver_info, receive_data_METEX_M4650CR,
+	},
+	{
+		"PeakTech", "4370", "1200/7n2/rts=0/dtr=1", 1200,
+		METEX14_PACKET_SIZE, sr_metex14_packet_request,
+		sr_metex14_packet_valid, sr_metex14_parse,
+		NULL,
+		&peaktech_4370_driver_info, receive_data_PEAKTECH_4370,
+	},
+	{
+		"PCE", "PCE-DM32", "2400/8n1", 2400,
+		FS9721_PACKET_SIZE, NULL,
+		sr_fs9721_packet_valid, sr_fs9721_parse,
+		sr_fs9721_01_10_temp_f_c,
+		&pce_pce_dm32_driver_info, receive_data_PCE_PCE_DM32,
+	},
+	{
+		"RadioShack", "22-168", "1200/7n2/rts=0/dtr=1", 1200,
+		METEX14_PACKET_SIZE, sr_metex14_packet_request,
+		sr_metex14_packet_valid, sr_metex14_parse,
+		NULL,
+		&radioshack_22_168_driver_info, receive_data_RADIOSHACK_22_168,
+	},
+	{
+		"RadioShack", "22-805", "600/7n2/rts=0/dtr=1", 600,
+		METEX14_PACKET_SIZE, sr_metex14_packet_request,
+		sr_metex14_packet_valid, sr_metex14_parse,
+		NULL,
+		&radioshack_22_805_driver_info, receive_data_RADIOSHACK_22_805,
+	},
+	{
+		"RadioShack", "22-812", "4800/8n1/rts=0/dtr=1", 4800,
+		RS9LCD_PACKET_SIZE, NULL,
+		sr_rs9lcd_packet_valid, sr_rs9lcd_parse,
+		NULL,
+		&radioshack_22_812_driver_info, receive_data_RADIOSHACK_22_812,
+	},
+	{
+		"Tecpel", "DMM-8061 (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
+		2400, FS9721_PACKET_SIZE, NULL,
+		sr_fs9721_packet_valid, sr_fs9721_parse,
+		sr_fs9721_00_temp_c,
+		&tecpel_dmm_8061_ser_driver_info,
+		receive_data_TECPEL_DMM_8061_SER,
+	},
+	{
+		"Voltcraft", "M-3650CR", "1200/7n2/rts=0/dtr=1", 1200,
+		METEX14_PACKET_SIZE, sr_metex14_packet_request,
+		sr_metex14_packet_valid, sr_metex14_parse,
+		NULL,
+		&voltcraft_m3650cr_driver_info, receive_data_VOLTCRAFT_M3650CR,
+	},
+	{
+		"Voltcraft", "M-3650D", "1200/7n2/rts=0/dtr=1", 1200,
+		METEX14_PACKET_SIZE, sr_metex14_packet_request,
+		sr_metex14_packet_valid, sr_metex14_parse,
+		NULL,
+		&voltcraft_m3650d_driver_info, receive_data_VOLTCRAFT_M3650D,
+	},
+	{
+		"Voltcraft", "M-4650CR", "1200/7n2/rts=0/dtr=1", 1200,
+		METEX14_PACKET_SIZE, sr_metex14_packet_request,
+		sr_metex14_packet_valid, sr_metex14_parse,
+		NULL,
+		&voltcraft_m4650cr_driver_info, receive_data_VOLTCRAFT_M4650CR,
+	},
+	{
+		"Voltcraft", "ME-42", "600/7n2/rts=0/dtr=1", 600,
+		METEX14_PACKET_SIZE, sr_metex14_packet_request,
+		sr_metex14_packet_valid, sr_metex14_parse,
+		NULL,
+		&voltcraft_me42_driver_info, receive_data_VOLTCRAFT_ME42,
+	},
+	{
+		"Voltcraft", "VC-820 (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
+		2400, FS9721_PACKET_SIZE, NULL,
+		sr_fs9721_packet_valid, sr_fs9721_parse,
+		NULL,
+		&voltcraft_vc820_ser_driver_info,
+		receive_data_VOLTCRAFT_VC820_SER,
+	},
+	{
+		/*
+		 * Note: The VC830 doesn't set the 'volt' and 'diode' bits of
+		 * the FS9922 protocol. Instead, it only sets the user-defined
+		 * bit "z1" to indicate "diode mode" and "voltage".
+		 */
+		"Voltcraft", "VC-830 (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
+		2400, FS9922_PACKET_SIZE, NULL,
+		sr_fs9922_packet_valid, sr_fs9922_parse,
+		&sr_fs9922_z1_diode,
+		&voltcraft_vc830_ser_driver_info,
+		receive_data_VOLTCRAFT_VC830_SER,
+	},
+	{
+		"Voltcraft", "VC-840 (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
+		2400, FS9721_PACKET_SIZE, NULL,
+		sr_fs9721_packet_valid, sr_fs9721_parse,
+		sr_fs9721_00_temp_c,
+		&voltcraft_vc840_ser_driver_info,
+		receive_data_VOLTCRAFT_VC840_SER,
+	},
+	{
+		"UNI-T", "UT60A (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
+		2400, FS9721_PACKET_SIZE, NULL,
+		sr_fs9721_packet_valid, sr_fs9721_parse,
+		NULL,
+		&uni_t_ut60a_ser_driver_info,
+		receive_data_UNI_T_UT60A_SER,
+	},
+	{
+		"UNI-T", "UT60E (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
+		2400, FS9721_PACKET_SIZE, NULL,
+		sr_fs9721_packet_valid, sr_fs9721_parse,
+		sr_fs9721_00_temp_c,
+		&uni_t_ut60e_ser_driver_info,
+		receive_data_UNI_T_UT60E_SER,
+	},
+	{
+		/* Note: ES51986 baudrate is actually 19230! */
+		"UNI-T", "UT60G (UT-D02 cable)", "19200/7o1/rts=0/dtr=1",
+		19200, ES519XX_11B_PACKET_SIZE, NULL,
+		sr_es519xx_19200_11b_packet_valid, sr_es519xx_19200_11b_parse,
+		NULL,
+		&uni_t_ut60g_ser_driver_info, receive_data_UNI_T_UT60G_SER,
+	},
+	{
+		"UNI-T", "UT61B (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
+		2400, FS9922_PACKET_SIZE, NULL,
+		sr_fs9922_packet_valid, sr_fs9922_parse, NULL,
+		&uni_t_ut61b_ser_driver_info, receive_data_UNI_T_UT61B_SER,
+	},
+	{
+		"UNI-T", "UT61C (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
+		2400, FS9922_PACKET_SIZE, NULL,
+		sr_fs9922_packet_valid, sr_fs9922_parse, NULL,
+		&uni_t_ut61c_ser_driver_info, receive_data_UNI_T_UT61C_SER,
+	},
+	{
+		"UNI-T", "UT61D (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
+		2400, FS9922_PACKET_SIZE, NULL,
+		sr_fs9922_packet_valid, sr_fs9922_parse, NULL,
+		&uni_t_ut61d_ser_driver_info, receive_data_UNI_T_UT61D_SER,
+	},
+	{
+		/* Note: ES51922 baudrate is actually 19230! */
+		"UNI-T", "UT61E (UT-D02 cable)", "19200/7o1/rts=0/dtr=1",
+		19200, ES519XX_14B_PACKET_SIZE, NULL,
+		sr_es519xx_19200_14b_packet_valid, sr_es519xx_19200_14b_parse,
+		NULL,
+		&uni_t_ut61e_ser_driver_info, receive_data_UNI_T_UT61E_SER,
+	},
+	{
+		"ISO-TECH", "IDM103N", "2400/7o1/rts=0/dtr=1",
+		2400, ES519XX_11B_PACKET_SIZE, NULL,
+		sr_es519xx_2400_11b_packet_valid, sr_es519xx_2400_11b_parse,
+		NULL,
+		&iso_tech_idm103n_driver_info, receive_data_ISO_TECH_IDM103N,
+	},
+	{
+		"Tenma", "72-7745 (UT-D02 cable)", "2400/8n1/rts=0/dtr=1",
+		2400, FS9721_PACKET_SIZE, NULL,
+		sr_fs9721_packet_valid, sr_fs9721_parse,
+		sr_fs9721_00_temp_c,
+		&tenma_72_7745_ser_driver_info, receive_data_TENMA_72_7745_SER,
+	},
+	{
+		/* Note: ES51986 baudrate is actually 19230! */
+		"Tenma", "72-7750 (UT-D02 cable)", "19200/7o1/rts=0/dtr=1",
+		19200, ES519XX_11B_PACKET_SIZE, NULL,
+		sr_es519xx_19200_11b_packet_valid, sr_es519xx_19200_11b_parse,
+		NULL,
+		&tenma_72_7750_ser_driver_info, receive_data_TENMA_72_7750_SER,
+	},
+};
+
+static int dev_clear(int dmm)
+{
+	return std_dev_clear(dmms[dmm].di, NULL);
+}
+
+static int init(struct sr_context *sr_ctx, int dmm)
+{
+	sr_dbg("Selected '%s' subdriver.", dmms[dmm].di->name);
+
+	return std_init(sr_ctx, dmms[dmm].di, LOG_PREFIX);
+}
+
+static GSList *sdmm_scan(const char *conn, const char *serialcomm, int dmm)
+{
+	struct sr_dev_inst *sdi;
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_channel *ch;
+	struct sr_serial_dev_inst *serial;
+	GSList *devices;
+	int dropped, ret;
+	size_t len;
+	uint8_t buf[128];
+
+	if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+		return NULL;
+
+	if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+		return NULL;
+
+	sr_info("Probing serial port %s.", conn);
+
+	drvc = dmms[dmm].di->priv;
+	devices = NULL;
+	serial_flush(serial);
+
+	/* Request a packet if the DMM requires this. */
+	if (dmms[dmm].packet_request) {
+		if ((ret = dmms[dmm].packet_request(serial)) < 0) {
+			sr_err("Failed to request packet: %d.", ret);
+			return FALSE;
+		}
+	}
+
+	/*
+	 * There's no way to get an ID from the multimeter. It just sends data
+	 * periodically (or upon request), so the best we can do is check if
+	 * the packets match the expected format.
+	 */
+
+	/* Let's get a bit of data and see if we can find a packet. */
+	len = sizeof(buf);
+	ret = serial_stream_detect(serial, buf, &len, dmms[dmm].packet_size,
+				   dmms[dmm].packet_valid, 3000,
+				   dmms[dmm].baudrate);
+	if (ret != SR_OK)
+		goto scan_cleanup;
+
+	/*
+	 * If we dropped more than two packets worth of data, something is
+	 * wrong. We shouldn't quit however, since the dropped bytes might be
+	 * just zeroes at the beginning of the stream. Those can occur as a
+	 * combination of the nonstandard cable that ships with some devices
+	 * and the serial port or USB to serial adapter.
+	 */
+	dropped = len - dmms[dmm].packet_size;
+	if (dropped > 2 * dmms[dmm].packet_size)
+		sr_warn("Had to drop too much data.");
+
+	sr_info("Found device on port %s.", conn);
+
+	if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, dmms[dmm].vendor,
+				    dmms[dmm].device, NULL)))
+		goto scan_cleanup;
+
+	if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+		sr_err("Device context malloc failed.");
+		goto scan_cleanup;
+	}
+
+	sdi->inst_type = SR_INST_SERIAL;
+	sdi->conn = serial;
+
+	sdi->priv = devc;
+	sdi->driver = dmms[dmm].di;
+	if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
+		goto scan_cleanup;
+	sdi->channels = g_slist_append(sdi->channels, ch);
+	drvc->instances = g_slist_append(drvc->instances, sdi);
+	devices = g_slist_append(devices, sdi);
+
+scan_cleanup:
+	serial_close(serial);
+
+	return devices;
+}
+
+static GSList *scan(GSList *options, int dmm)
+{
+	struct sr_config *src;
+	GSList *l, *devices;
+	const char *conn, *serialcomm;
+
+	conn = serialcomm = NULL;
+	for (l = options; l; l = l->next) {
+		src = l->data;
+		switch (src->key) {
+		case SR_CONF_CONN:
+			conn = g_variant_get_string(src->data, NULL);
+			break;
+		case SR_CONF_SERIALCOMM:
+			serialcomm = g_variant_get_string(src->data, NULL);
+			break;
+		}
+	}
+	if (!conn)
+		return NULL;
+
+	if (serialcomm) {
+		/* Use the provided comm specs. */
+		devices = sdmm_scan(conn, serialcomm, dmm);
+	} else {
+		/* Try the default. */
+		devices = sdmm_scan(conn, dmms[dmm].conn, dmm);
+	}
+
+	return devices;
+}
+
+static GSList *dev_list(int dmm)
+{
+	return ((struct drv_context *)(dmms[dmm].di->priv))->instances;
+}
+
+static int cleanup(int dmm)
+{
+	return dev_clear(dmm);
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+
+	(void)cg;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!(devc = sdi->priv)) {
+		sr_err("sdi->priv was NULL.");
+		return SR_ERR_BUG;
+	}
+
+	switch (id) {
+	case SR_CONF_LIMIT_SAMPLES:
+		devc->limit_samples = g_variant_get_uint64(data);
+		sr_dbg("Setting sample limit to %" PRIu64 ".",
+		       devc->limit_samples);
+		break;
+	case SR_CONF_LIMIT_MSEC:
+		devc->limit_msec = g_variant_get_uint64(data);
+		sr_dbg("Setting time limit to %" PRIu64 "ms.",
+		       devc->limit_msec);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	(void)sdi;
+	(void)cg;
+
+	switch (key) {
+	case SR_CONF_SCAN_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+		break;
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi,
+				    void *cb_data, int dmm)
+{
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!(devc = sdi->priv)) {
+		sr_err("sdi->priv was NULL.");
+		return SR_ERR_BUG;
+	}
+
+	devc->cb_data = cb_data;
+
+	/*
+	 * Reset the number of samples to take. If we've already collected our
+	 * quota, but we start a new session, and don't reset this, we'll just
+	 * quit without acquiring any new samples.
+	 */
+	devc->num_samples = 0;
+	devc->starttime = g_get_monotonic_time();
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	/* Poll every 50ms, or whenever some data comes in. */
+	serial = sdi->conn;
+	serial_source_add(serial, G_IO_IN, 50,
+		      dmms[dmm].receive_data, (void *)sdi);
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close,
+			sdi->conn, LOG_PREFIX);
+}
+
+/* Driver-specific API function wrappers */
+#define HW_INIT(X) \
+static int init_##X(struct sr_context *sr_ctx) { return init(sr_ctx, X); }
+#define HW_CLEANUP(X) \
+static int cleanup_##X(void) { return cleanup(X); }
+#define HW_SCAN(X) \
+static GSList *scan_##X(GSList *options) { return scan(options, X); }
+#define HW_DEV_LIST(X) \
+static GSList *dev_list_##X(void) { return dev_list(X); }
+#define HW_DEV_CLEAR(X) \
+static int dev_clear_##X(void) { return dev_clear(X); }
+#define HW_DEV_ACQUISITION_START(X) \
+static int dev_acquisition_start_##X(const struct sr_dev_inst *sdi, \
+void *cb_data) { return dev_acquisition_start(sdi, cb_data, X); }
+
+/* Driver structs and API function wrappers */
+#define DRV(ID, ID_UPPER, NAME, LONGNAME) \
+HW_INIT(ID_UPPER) \
+HW_CLEANUP(ID_UPPER) \
+HW_SCAN(ID_UPPER) \
+HW_DEV_LIST(ID_UPPER) \
+HW_DEV_CLEAR(ID_UPPER) \
+HW_DEV_ACQUISITION_START(ID_UPPER) \
+SR_PRIV struct sr_dev_driver ID##_driver_info = { \
+	.name = NAME, \
+	.longname = LONGNAME, \
+	.api_version = 1, \
+	.init = init_##ID_UPPER, \
+	.cleanup = cleanup_##ID_UPPER, \
+	.scan = scan_##ID_UPPER, \
+	.dev_list = dev_list_##ID_UPPER, \
+	.dev_clear = dev_clear_##ID_UPPER, \
+	.config_get = NULL, \
+	.config_set = config_set, \
+	.config_list = config_list, \
+	.dev_open = std_serial_dev_open, \
+	.dev_close = std_serial_dev_close, \
+	.dev_acquisition_start = dev_acquisition_start_##ID_UPPER, \
+	.dev_acquisition_stop = dev_acquisition_stop, \
+	.priv = NULL, \
+};
+
+DRV(bbcgm_m2110, BBCGM_M2110, "bbcgm-m2110", "BBC Goertz Metrawatt M2110")
+DRV(digitek_dt4000zc, DIGITEK_DT4000ZC, "digitek-dt4000zc", "Digitek DT4000ZC")
+DRV(tekpower_tp4000zc, TEKPOWER_TP4000ZC, "tekpower-tp4000zc", "TekPower TP4000ZC")
+DRV(metex_me31, METEX_ME31, "metex-me31", "Metex ME-31")
+DRV(peaktech_3410, PEAKTECH_3410, "peaktech-3410", "PeakTech 3410")
+DRV(mastech_mas345, MASTECH_MAS345, "mastech-mas345", "MASTECH MAS345")
+DRV(va_va18b, VA_VA18B, "va-va18b", "V&A VA18B")
+DRV(va_va40b, VA_VA40B, "va-va40b", "V&A VA40B")
+DRV(metex_m3640d, METEX_M3640D, "metex-m3640d", "Metex M-3640D")
+DRV(metex_m4650cr, METEX_M4650CR, "metex-m4650cr", "Metex M-4650CR")
+DRV(peaktech_4370, PEAKTECH_4370, "peaktech-4370", "PeakTech 4370")
+DRV(pce_pce_dm32, PCE_PCE_DM32, "pce-pce-dm32", "PCE PCE-DM32")
+DRV(radioshack_22_168, RADIOSHACK_22_168, "radioshack-22-168", "RadioShack 22-168")
+DRV(radioshack_22_805, RADIOSHACK_22_805, "radioshack-22-805", "RadioShack 22-805")
+DRV(radioshack_22_812, RADIOSHACK_22_812, "radioshack-22-812", "RadioShack 22-812")
+DRV(tecpel_dmm_8061_ser, TECPEL_DMM_8061_SER, "tecpel-dmm-8061-ser", "Tecpel DMM-8061 (UT-D02 cable)")
+DRV(voltcraft_m3650cr, VOLTCRAFT_M3650CR, "voltcraft-m3650cr", "Voltcraft M-3650CR")
+DRV(voltcraft_m3650d, VOLTCRAFT_M3650D, "voltcraft-m3650d", "Voltcraft M-3650D")
+DRV(voltcraft_m4650cr, VOLTCRAFT_M4650CR, "voltcraft-m4650cr", "Voltcraft M-4650CR")
+DRV(voltcraft_me42, VOLTCRAFT_ME42, "voltcraft-me42", "Voltcraft ME-42")
+DRV(voltcraft_vc820_ser, VOLTCRAFT_VC820_SER, "voltcraft-vc820-ser", "Voltcraft VC-820 (UT-D02 cable)")
+DRV(voltcraft_vc830_ser, VOLTCRAFT_VC830_SER, "voltcraft-vc830-ser", "Voltcraft VC-830 (UT-D02 cable)")
+DRV(voltcraft_vc840_ser, VOLTCRAFT_VC840_SER, "voltcraft-vc840-ser", "Voltcraft VC-840 (UT-D02 cable)")
+DRV(uni_t_ut60a_ser, UNI_T_UT60A_SER, "uni-t-ut60a-ser", "UNI-T UT60A (UT-D02 cable)")
+DRV(uni_t_ut60e_ser, UNI_T_UT60E_SER, "uni-t-ut60e-ser", "UNI-T UT60E (UT-D02 cable)")
+DRV(uni_t_ut60g_ser, UNI_T_UT60G_SER, "uni-t-ut60g-ser", "UNI-T UT60G (UT-D02 cable)")
+DRV(uni_t_ut61b_ser, UNI_T_UT61B_SER, "uni-t-ut61b-ser", "UNI-T UT61B (UT-D02 cable)")
+DRV(uni_t_ut61c_ser, UNI_T_UT61C_SER, "uni-t-ut61c-ser", "UNI-T UT61C (UT-D02 cable)")
+DRV(uni_t_ut61d_ser, UNI_T_UT61D_SER, "uni-t-ut61d-ser", "UNI-T UT61D (UT-D02 cable)")
+DRV(uni_t_ut61e_ser, UNI_T_UT61E_SER, "uni-t-ut61e-ser", "UNI-T UT61E (UT-D02 cable)")
+DRV(iso_tech_idm103n, ISO_TECH_IDM103N, "iso-tech-idm103n", "ISO-TECH IDM103N")
+DRV(tenma_72_7745_ser, TENMA_72_7745_SER, "tenma-72-7745-ser", "Tenma 72-7745 (UT-D02 cable)")
+DRV(tenma_72_7750_ser, TENMA_72_7750_SER, "tenma-72-7750-ser", "Tenma 72-7750 (UT-D02 cable)")
diff --git a/hardware/serial-dmm/protocol.c b/hardware/serial-dmm/protocol.c
new file mode 100644
index 0000000..36e6944
--- /dev/null
+++ b/hardware/serial-dmm/protocol.c
@@ -0,0 +1,195 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me at gmail.com>
+ * Copyright (C) 2012 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+
+static void log_dmm_packet(const uint8_t *buf)
+{
+	sr_dbg("DMM packet: %02x %02x %02x %02x %02x %02x %02x"
+	       " %02x %02x %02x %02x %02x %02x %02x",
+	       buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6],
+	       buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13]);
+}
+
+static void handle_packet(const uint8_t *buf, struct sr_dev_inst *sdi,
+			  int dmm, void *info)
+{
+	float floatval;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_analog analog;
+	struct dev_context *devc;
+
+	log_dmm_packet(buf);
+	devc = sdi->priv;
+
+	memset(&analog, 0, sizeof(struct sr_datafeed_analog));
+
+	analog.channels = sdi->channels;
+	analog.num_samples = 1;
+	analog.mq = -1;
+
+	dmms[dmm].packet_parse(buf, &floatval, &analog, info);
+	analog.data = &floatval;
+
+	/* If this DMM needs additional handling, call the resp. function. */
+	if (dmms[dmm].dmm_details)
+		dmms[dmm].dmm_details(&analog, info);
+
+	if (analog.mq != -1) {
+		/* Got a measurement. */
+		packet.type = SR_DF_ANALOG;
+		packet.payload = &analog;
+		sr_session_send(devc->cb_data, &packet);
+		devc->num_samples++;
+	}
+}
+
+static void handle_new_data(struct sr_dev_inst *sdi, int dmm, void *info)
+{
+	struct dev_context *devc;
+	int len, i, offset = 0;
+	struct sr_serial_dev_inst *serial;
+
+	devc = sdi->priv;
+	serial = sdi->conn;
+
+	/* Try to get as much data as the buffer can hold. */
+	len = DMM_BUFSIZE - devc->buflen;
+	len = serial_read(serial, devc->buf + devc->buflen, len);
+	if (len == 0)
+		return; /* No new bytes, nothing to do. */
+	if (len < 0) {
+		sr_err("Serial port read error: %d.", len);
+		return;
+	}
+	devc->buflen += len;
+
+	/* Now look for packets in that data. */
+	while ((devc->buflen - offset) >= dmms[dmm].packet_size) {
+		if (dmms[dmm].packet_valid(devc->buf + offset)) {
+			handle_packet(devc->buf + offset, sdi, dmm, info);
+			offset += dmms[dmm].packet_size;
+		} else {
+			offset++;
+		}
+	}
+
+	/* If we have any data left, move it to the beginning of our buffer. */
+	for (i = 0; i < devc->buflen - offset; i++)
+		devc->buf[i] = devc->buf[offset + i];
+	devc->buflen -= offset;
+}
+
+static int receive_data(int fd, int revents, int dmm, void *info, void *cb_data)
+{
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+	int64_t time;
+	int ret;
+
+	(void)fd;
+
+	if (!(sdi = cb_data))
+		return TRUE;
+
+	if (!(devc = sdi->priv))
+		return TRUE;
+
+	serial = sdi->conn;
+
+	if (revents == G_IO_IN) {
+		/* Serial data arrived. */
+		handle_new_data(sdi, dmm, info);
+	} else {
+		/* Timeout, send another packet request (if DMM needs it). */
+		if (dmms[dmm].packet_request) {
+			ret = dmms[dmm].packet_request(serial);
+			if (ret < 0) {
+				sr_err("Failed to request packet: %d.", ret);
+				return FALSE;
+			}
+		}
+	}
+
+	if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
+		sr_info("Requested number of samples reached.");
+		sdi->driver->dev_acquisition_stop(sdi, cb_data);
+		return TRUE;
+	}
+
+	if (devc->limit_msec) {
+		time = (g_get_monotonic_time() - devc->starttime) / 1000;
+		if (time > (int64_t)devc->limit_msec) {
+			sr_info("Requested time limit reached.");
+			sdi->driver->dev_acquisition_stop(sdi, cb_data);
+			return TRUE;
+		}
+	}
+
+	return TRUE;
+}
+
+#define RECEIVE_DATA(ID_UPPER, DMM_DRIVER) \
+SR_PRIV int receive_data_##ID_UPPER(int fd, int revents, void *cb_data) { \
+	struct DMM_DRIVER##_info info; \
+	return receive_data(fd, revents, ID_UPPER, &info, cb_data); }
+
+/* Driver-specific receive_data() wrappers */
+RECEIVE_DATA(BBCGM_M2110, metex14) /* metex14_info used as a dummy. */
+RECEIVE_DATA(DIGITEK_DT4000ZC, fs9721)
+RECEIVE_DATA(TEKPOWER_TP4000ZC, fs9721)
+RECEIVE_DATA(METEX_ME31, metex14)
+RECEIVE_DATA(PEAKTECH_3410, metex14)
+RECEIVE_DATA(MASTECH_MAS345, metex14)
+RECEIVE_DATA(VA_VA18B, fs9721)
+RECEIVE_DATA(VA_VA40B, fs9721)
+RECEIVE_DATA(METEX_M3640D, metex14)
+RECEIVE_DATA(METEX_M4650CR, metex14)
+RECEIVE_DATA(PEAKTECH_4370, metex14)
+RECEIVE_DATA(PCE_PCE_DM32, fs9721)
+RECEIVE_DATA(RADIOSHACK_22_168, metex14)
+RECEIVE_DATA(RADIOSHACK_22_805, metex14)
+RECEIVE_DATA(RADIOSHACK_22_812, rs9lcd)
+RECEIVE_DATA(TECPEL_DMM_8061_SER, fs9721)
+RECEIVE_DATA(VOLTCRAFT_M3650CR, metex14)
+RECEIVE_DATA(VOLTCRAFT_M3650D, metex14)
+RECEIVE_DATA(VOLTCRAFT_M4650CR, metex14)
+RECEIVE_DATA(VOLTCRAFT_ME42, metex14)
+RECEIVE_DATA(VOLTCRAFT_VC820_SER, fs9721)
+RECEIVE_DATA(VOLTCRAFT_VC830_SER, fs9922)
+RECEIVE_DATA(VOLTCRAFT_VC840_SER, fs9721)
+RECEIVE_DATA(UNI_T_UT60A_SER, fs9721)
+RECEIVE_DATA(UNI_T_UT60E_SER, fs9721)
+RECEIVE_DATA(UNI_T_UT60G_SER, es519xx)
+RECEIVE_DATA(UNI_T_UT61B_SER, fs9922)
+RECEIVE_DATA(UNI_T_UT61C_SER, fs9922)
+RECEIVE_DATA(UNI_T_UT61D_SER, fs9922)
+RECEIVE_DATA(UNI_T_UT61E_SER, es519xx)
+RECEIVE_DATA(ISO_TECH_IDM103N, es519xx)
+RECEIVE_DATA(TENMA_72_7745_SER, fs9721)
+RECEIVE_DATA(TENMA_72_7750_SER, es519xx)
diff --git a/hardware/serial-dmm/protocol.h b/hardware/serial-dmm/protocol.h
new file mode 100644
index 0000000..f96e43d
--- /dev/null
+++ b/hardware/serial-dmm/protocol.h
@@ -0,0 +1,146 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Alexandru Gagniuc <mr.nuke.me at gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_SERIAL_DMM_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_SERIAL_DMM_PROTOCOL_H
+
+#define LOG_PREFIX "serial-dmm"
+
+enum {
+	BBCGM_M2110,
+	DIGITEK_DT4000ZC,
+	TEKPOWER_TP4000ZC,
+	METEX_ME31,
+	PEAKTECH_3410,
+	MASTECH_MAS345,
+	VA_VA18B,
+	VA_VA40B,
+	METEX_M3640D,
+	METEX_M4650CR,
+	PEAKTECH_4370,
+	PCE_PCE_DM32,
+	RADIOSHACK_22_168,
+	RADIOSHACK_22_805,
+	RADIOSHACK_22_812,
+	TECPEL_DMM_8061_SER,
+	VOLTCRAFT_M3650CR,
+	VOLTCRAFT_M3650D,
+	VOLTCRAFT_M4650CR,
+	VOLTCRAFT_ME42,
+	VOLTCRAFT_VC820_SER,
+	VOLTCRAFT_VC830_SER,
+	VOLTCRAFT_VC840_SER,
+	UNI_T_UT60A_SER,
+	UNI_T_UT60E_SER,
+	UNI_T_UT60G_SER,
+	UNI_T_UT61B_SER,
+	UNI_T_UT61C_SER,
+	UNI_T_UT61D_SER,
+	UNI_T_UT61E_SER,
+	ISO_TECH_IDM103N,
+	TENMA_72_7745_SER,
+	TENMA_72_7750_SER,
+};
+
+struct dmm_info {
+	/** Manufacturer/brand. */
+	char *vendor;
+	/** Model. */
+	char *device;
+	/** serialconn string. */
+	char *conn;
+	/** Baud rate. */
+	uint32_t baudrate;
+	/** Packet size in bytes. */
+	int packet_size;
+	/** Packet request function. */
+	int (*packet_request)(struct sr_serial_dev_inst *);
+	/** Packet validation function. */
+	gboolean (*packet_valid)(const uint8_t *);
+	/** Packet parsing function. */
+	int (*packet_parse)(const uint8_t *, float *,
+			    struct sr_datafeed_analog *, void *);
+	/** */
+	void (*dmm_details)(struct sr_datafeed_analog *, void *);
+	/** libsigrok driver info struct. */
+	struct sr_dev_driver *di;
+	/** Data reception function. */
+	int (*receive_data)(int, int, void *);
+};
+
+extern SR_PRIV struct dmm_info dmms[];
+
+#define DMM_BUFSIZE 256
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+	/** The current sampling limit (in number of samples). */
+	uint64_t limit_samples;
+
+	/** The time limit (in milliseconds). */
+	uint64_t limit_msec;
+
+	/** Opaque pointer passed in by the frontend. */
+	void *cb_data;
+
+	/** The current number of already received samples. */
+	uint64_t num_samples;
+
+	int64_t starttime;
+
+	uint8_t buf[DMM_BUFSIZE];
+	int bufoffset;
+	int buflen;
+};
+
+SR_PRIV int receive_data_BBCGM_M2110(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_DIGITEK_DT4000ZC(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_TEKPOWER_TP4000ZC(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_METEX_ME31(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_PEAKTECH_3410(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_MASTECH_MAS345(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_VA_VA18B(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_VA_VA40B(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_METEX_M3640D(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_METEX_M4650CR(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_PEAKTECH_4370(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_PCE_PCE_DM32(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_RADIOSHACK_22_168(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_RADIOSHACK_22_805(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_RADIOSHACK_22_812(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_TECPEL_DMM_8061_SER(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_VOLTCRAFT_M3650CR(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_VOLTCRAFT_M3650D(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_VOLTCRAFT_M4650CR(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_VOLTCRAFT_ME42(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_VOLTCRAFT_VC820_SER(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_VOLTCRAFT_VC830_SER(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_VOLTCRAFT_VC840_SER(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_UNI_T_UT60A_SER(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_UNI_T_UT60E_SER(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_UNI_T_UT60G_SER(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_UNI_T_UT61B_SER(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_UNI_T_UT61C_SER(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_UNI_T_UT61D_SER(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_UNI_T_UT61E_SER(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_ISO_TECH_IDM103N(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_TENMA_72_7745_SER(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_TENMA_72_7750_SER(int fd, int revents, void *cb_data);
+
+#endif
diff --git a/hardware/sysclk-lwla/api.c b/hardware/sysclk-lwla/api.c
new file mode 100644
index 0000000..12a1e08
--- /dev/null
+++ b/hardware/sysclk-lwla/api.c
@@ -0,0 +1,612 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Daniel Elstner <daniel.kitta at gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "protocol.h"
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include <glib.h>
+#include <libusb.h>
+#include <stdlib.h>
+#include <string.h>
+
+static const int32_t hwopts[] = {
+	SR_CONF_CONN,
+};
+
+static const int32_t hwcaps[] = {
+	SR_CONF_LOGIC_ANALYZER,
+	SR_CONF_SAMPLERATE,
+	SR_CONF_EXTERNAL_CLOCK,
+	SR_CONF_CLOCK_EDGE,
+	SR_CONF_TRIGGER_TYPE,
+	SR_CONF_TRIGGER_SOURCE,
+	SR_CONF_TRIGGER_SLOPE,
+	SR_CONF_LIMIT_MSEC,
+	SR_CONF_LIMIT_SAMPLES,
+};
+
+/* The hardware supports more samplerates than these, but these are the
+ * options hardcoded into the vendor's Windows GUI.
+ */
+static const uint64_t samplerates[] = {
+	SR_MHZ(125), SR_MHZ(100),
+	SR_MHZ(50),  SR_MHZ(20),  SR_MHZ(10),
+	SR_MHZ(5),   SR_MHZ(2),   SR_MHZ(1),
+	SR_KHZ(500), SR_KHZ(200), SR_KHZ(100),
+	SR_KHZ(50),  SR_KHZ(20),  SR_KHZ(10),
+	SR_KHZ(5),   SR_KHZ(2),   SR_KHZ(1),
+	SR_HZ(500),  SR_HZ(200),  SR_HZ(100),
+};
+
+/* Names assigned to available trigger sources.  Indices must match
+ * trigger_source enum values.
+ */
+static const char *const trigger_source_names[] = { "CH", "TRG" };
+
+/* Names assigned to available trigger slope choices.  Indices must
+ * match the signal_edge enum values.
+ */
+static const char *const signal_edge_names[] = { "r", "f" };
+
+SR_PRIV struct sr_dev_driver sysclk_lwla_driver_info;
+static struct sr_dev_driver *const di = &sysclk_lwla_driver_info;
+
+static int init(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *gen_channel_list(int num_channels)
+{
+	GSList *list;
+	struct sr_channel *ch;
+	int i;
+	char name[8];
+
+	list = NULL;
+
+	for (i = num_channels; i > 0; --i) {
+		/* The LWLA series simply number channels from CH1 to CHxx. */
+		g_snprintf(name, sizeof(name), "CH%d", i);
+
+		ch = sr_channel_new(i - 1, SR_CHANNEL_LOGIC, TRUE, name);
+		list = g_slist_prepend(list, ch);
+	}
+
+	return list;
+}
+
+static struct sr_dev_inst *dev_inst_new(int device_index)
+{
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+
+	/* Allocate memory for our private driver context. */
+	devc = g_try_new0(struct dev_context, 1);
+	if (!devc) {
+		sr_err("Device context malloc failed.");
+		return NULL;
+	}
+
+	/* Register the device with libsigrok. */
+	sdi = sr_dev_inst_new(device_index, SR_ST_INACTIVE,
+			      VENDOR_NAME, MODEL_NAME, NULL);
+	if (!sdi) {
+		sr_err("Failed to instantiate device.");
+		g_free(devc);
+		return NULL;
+	}
+
+	/* Enable all channels to match the default channel configuration. */
+	devc->channel_mask = ALL_CHANNELS_MASK;
+	devc->samplerate = DEFAULT_SAMPLERATE;
+
+	sdi->priv = devc;
+	sdi->channels = gen_channel_list(NUM_CHANNELS);
+
+	return sdi;
+}
+
+static GSList *scan(GSList *options)
+{
+	GSList *usb_devices, *devices, *node;
+	struct drv_context *drvc;
+	struct sr_dev_inst *sdi;
+	struct sr_usb_dev_inst *usb;
+	struct sr_config *src;
+	const char *conn;
+	int device_index;
+
+	drvc = di->priv;
+	conn = USB_VID_PID;
+
+	for (node = options; node != NULL; node = node->next) {
+		src = node->data;
+		if (src->key == SR_CONF_CONN) {
+			conn = g_variant_get_string(src->data, NULL);
+			break;
+		}
+	}
+	usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn);
+	devices = NULL;
+	device_index = g_slist_length(drvc->instances);
+
+	for (node = usb_devices; node != NULL; node = node->next) {
+		usb = node->data;
+
+		/* Create sigrok device instance. */
+		sdi = dev_inst_new(device_index);
+		if (!sdi) {
+			sr_usb_dev_inst_free(usb);
+			continue;
+		}
+		sdi->driver = di;
+		sdi->inst_type = SR_INST_USB;
+		sdi->conn = usb;
+
+		/* Register device instance with driver. */
+		drvc->instances = g_slist_append(drvc->instances, sdi);
+		devices = g_slist_append(devices, sdi);
+	}
+
+	g_slist_free(usb_devices);
+
+	return devices;
+}
+
+static GSList *dev_list(void)
+{
+	struct drv_context *drvc;
+
+	drvc = di->priv;
+
+	return drvc->instances;
+}
+
+static void clear_dev_context(void *priv)
+{
+	struct dev_context *devc;
+
+	devc = priv;
+
+	sr_dbg("Device context cleared.");
+
+	lwla_free_acquisition_state(devc->acquisition);
+	g_free(devc);
+}
+
+static int dev_clear(void)
+{
+	return std_dev_clear(di, &clear_dev_context);
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+	struct drv_context *drvc;
+	struct sr_usb_dev_inst *usb;
+	int ret;
+
+	drvc = di->priv;
+
+	if (!drvc) {
+		sr_err("Driver was not initialized.");
+		return SR_ERR;
+	}
+
+	usb = sdi->conn;
+
+	ret = sr_usb_open(drvc->sr_ctx->libusb_ctx, usb);
+	if (ret != SR_OK)
+		return ret;
+
+	ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE);
+	if (ret < 0) {
+		sr_err("Failed to claim interface: %s.",
+			libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	sdi->status = SR_ST_INITIALIZING;
+
+	ret = lwla_init_device(sdi);
+
+	if (ret == SR_OK)
+		sdi->status = SR_ST_ACTIVE;
+
+	return ret;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+	struct sr_usb_dev_inst *usb;
+
+	if (!di->priv) {
+		sr_err("Driver was not initialized.");
+		return SR_ERR;
+	}
+
+	usb = sdi->conn;
+	if (!usb->devhdl)
+		return SR_OK;
+
+	sdi->status = SR_ST_INACTIVE;
+
+	/* Trigger download of the shutdown bitstream. */
+	if (lwla_set_clock_config(sdi) != SR_OK)
+		sr_err("Unable to shut down device.");
+
+	libusb_release_interface(usb->devhdl, USB_INTERFACE);
+	libusb_close(usb->devhdl);
+
+	usb->devhdl = NULL;
+
+	return SR_OK;
+}
+
+static int cleanup(void)
+{
+	return dev_clear();
+}
+
+static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		      const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	size_t idx;
+
+	(void)cg;
+
+	if (!sdi)
+		return SR_ERR_ARG;
+
+	devc = sdi->priv;
+
+	switch (key) {
+	case SR_CONF_SAMPLERATE:
+		*data = g_variant_new_uint64(devc->samplerate);
+		break;
+	case SR_CONF_LIMIT_MSEC:
+		*data = g_variant_new_uint64(devc->limit_msec);
+		break;
+	case SR_CONF_LIMIT_SAMPLES:
+		*data = g_variant_new_uint64(devc->limit_samples);
+		break;
+	case SR_CONF_EXTERNAL_CLOCK:
+		*data = g_variant_new_boolean(devc->cfg_clock_source
+						== CLOCK_EXT_CLK);
+		break;
+	case SR_CONF_CLOCK_EDGE:
+		idx = devc->cfg_clock_edge;
+		if (idx >= G_N_ELEMENTS(signal_edge_names))
+			return SR_ERR_BUG;
+		*data = g_variant_new_string(signal_edge_names[idx]);
+		break;
+	case SR_CONF_TRIGGER_SOURCE:
+		idx = devc->cfg_trigger_source;
+		if (idx >= G_N_ELEMENTS(trigger_source_names))
+			return SR_ERR_BUG;
+		*data = g_variant_new_string(trigger_source_names[idx]);
+		break;
+	case SR_CONF_TRIGGER_SLOPE:
+		idx = devc->cfg_trigger_slope;
+		if (idx >= G_N_ELEMENTS(signal_edge_names))
+			return SR_ERR_BUG;
+		*data = g_variant_new_string(signal_edge_names[idx]);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+/* Helper for mapping a string-typed configuration value to an index
+ * within a table of possible values.
+ */
+static int lookup_index(GVariant *value, const char *const *table, int len)
+{
+	const char *entry;
+	int i;
+
+	entry = g_variant_get_string(value, NULL);
+	if (!entry)
+		return -1;
+
+	/* Linear search is fine for very small tables. */
+	for (i = 0; i < len; ++i) {
+		if (strcmp(entry, table[i]) == 0)
+			return i;
+	}
+	return -1;
+}
+
+static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+		      const struct sr_channel_group *cg)
+{
+	uint64_t value;
+	struct dev_context *devc;
+	int idx;
+
+	(void)cg;
+
+	devc = sdi->priv;
+	if (!devc)
+		return SR_ERR_DEV_CLOSED;
+
+	switch (key) {
+	case SR_CONF_SAMPLERATE:
+		value = g_variant_get_uint64(data);
+		if (value < samplerates[G_N_ELEMENTS(samplerates) - 1]
+				|| value > samplerates[0])
+			return SR_ERR_SAMPLERATE;
+		devc->samplerate = value;
+		break;
+	case SR_CONF_LIMIT_MSEC:
+		value = g_variant_get_uint64(data);
+		if (value > MAX_LIMIT_MSEC)
+			return SR_ERR_ARG;
+		devc->limit_msec = value;
+		break;
+	case SR_CONF_LIMIT_SAMPLES:
+		value = g_variant_get_uint64(data);
+		if (value > MAX_LIMIT_SAMPLES)
+			return SR_ERR_ARG;
+		devc->limit_samples = value;
+		break;
+	case SR_CONF_EXTERNAL_CLOCK:
+		devc->cfg_clock_source = (g_variant_get_boolean(data))
+			? CLOCK_EXT_CLK : CLOCK_INTERNAL;
+		break;
+	case SR_CONF_CLOCK_EDGE:
+		idx = lookup_index(data, signal_edge_names,
+				   G_N_ELEMENTS(signal_edge_names));
+		if (idx < 0)
+			return SR_ERR_ARG;
+		devc->cfg_clock_edge = idx;
+		break;
+	case SR_CONF_TRIGGER_SOURCE:
+		idx = lookup_index(data, trigger_source_names,
+				   G_N_ELEMENTS(trigger_source_names));
+		if (idx < 0)
+			return SR_ERR_ARG;
+		devc->cfg_trigger_source = idx;
+		break;
+	case SR_CONF_TRIGGER_SLOPE:
+		idx = lookup_index(data, signal_edge_names,
+				   G_N_ELEMENTS(signal_edge_names));
+		if (idx < 0)
+			return SR_ERR_ARG;
+		devc->cfg_trigger_slope = idx;
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_channel_set(const struct sr_dev_inst *sdi,
+			    struct sr_channel *ch, unsigned int changes)
+{
+	uint64_t channel_bit;
+	uint64_t trigger_mask;
+	uint64_t trigger_values;
+	uint64_t trigger_edge_mask;
+	struct dev_context *devc;
+
+	devc = sdi->priv;
+	if (!devc)
+		return SR_ERR_DEV_CLOSED;
+
+	if (ch->index < 0 || ch->index >= NUM_CHANNELS) {
+		sr_err("Channel index %d out of range.", ch->index);
+		return SR_ERR_BUG;
+	}
+	channel_bit = (uint64_t)1 << ch->index;
+
+	if ((changes & SR_CHANNEL_SET_ENABLED) != 0) {
+		/* Enable or disable input channel for this channel. */
+		if (ch->enabled)
+			devc->channel_mask |= channel_bit;
+		else
+			devc->channel_mask &= ~channel_bit;
+	}
+
+	if ((changes & SR_CHANNEL_SET_TRIGGER) != 0) {
+		trigger_mask = devc->trigger_mask & ~channel_bit;
+		trigger_values = devc->trigger_values & ~channel_bit;
+		trigger_edge_mask = devc->trigger_edge_mask & ~channel_bit;
+
+		if (ch->trigger && ch->trigger[0] != '\0') {
+			if (ch->trigger[1] != '\0') {
+				sr_warn("Trigger configuration \"%s\" with "
+					"multiple stages is not supported.",
+					ch->trigger);
+				return SR_ERR_ARG;
+			}
+			/* Enable trigger for this channel. */
+			trigger_mask |= channel_bit;
+
+			/* Configure edge mask and trigger value. */
+			switch (ch->trigger[0]) {
+			case '1': trigger_values |= channel_bit;
+			case '0': break;
+
+			case 'r': trigger_values |= channel_bit;
+			case 'f': trigger_edge_mask |= channel_bit;
+				  break;
+			default:
+				sr_warn("Trigger type '%c' is not supported.",
+					ch->trigger[0]);
+				return SR_ERR_ARG;
+			}
+		}
+		/* Store validated trigger setup. */
+		devc->trigger_mask = trigger_mask;
+		devc->trigger_values = trigger_values;
+		devc->trigger_edge_mask = trigger_edge_mask;
+	}
+
+	return SR_OK;
+}
+
+static int config_commit(const struct sr_dev_inst *sdi)
+{
+	if (sdi->status != SR_ST_ACTIVE) {
+		sr_err("Device not ready (status %d).", (int)sdi->status);
+		return SR_ERR;
+	}
+
+	return lwla_set_clock_config(sdi);
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		       const struct sr_channel_group *cg)
+{
+	GVariant *gvar;
+	GVariantBuilder gvb;
+
+	(void)sdi;
+	(void)cg;
+
+	switch (key) {
+	case SR_CONF_SCAN_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwopts, G_N_ELEMENTS(hwopts), sizeof(int32_t));
+		break;
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwcaps, G_N_ELEMENTS(hwcaps), sizeof(int32_t));
+		break;
+	case SR_CONF_SAMPLERATE:
+		g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
+		gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
+				samplerates, G_N_ELEMENTS(samplerates),
+				sizeof(uint64_t));
+		g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
+		*data = g_variant_builder_end(&gvb);
+		break;
+	case SR_CONF_TRIGGER_TYPE:
+		*data = g_variant_new_string(TRIGGER_TYPES);
+		break;
+	case SR_CONF_TRIGGER_SOURCE:
+		*data = g_variant_new_strv(trigger_source_names,
+					   G_N_ELEMENTS(trigger_source_names));
+		break;
+	case SR_CONF_TRIGGER_SLOPE:
+	case SR_CONF_CLOCK_EDGE:
+		*data = g_variant_new_strv(signal_edge_names,
+					   G_N_ELEMENTS(signal_edge_names));
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct acquisition_state *acq;
+	int ret;
+
+	(void)cb_data;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	devc = sdi->priv;
+	drvc = di->priv;
+
+	if (devc->acquisition) {
+		sr_err("Acquisition still in progress?");
+		return SR_ERR;
+	}
+	acq = lwla_alloc_acquisition_state();
+	if (!acq)
+		return SR_ERR_MALLOC;
+
+	devc->stopping_in_progress = FALSE;
+	devc->transfer_error = FALSE;
+
+	sr_info("Starting acquisition.");
+
+	devc->acquisition = acq;
+	ret = lwla_setup_acquisition(sdi);
+	if (ret != SR_OK) {
+		sr_err("Failed to set up acquisition.");
+		devc->acquisition = NULL;
+		lwla_free_acquisition_state(acq);
+		return ret;
+	}
+
+	ret = lwla_start_acquisition(sdi);
+	if (ret != SR_OK) {
+		sr_err("Failed to start acquisition.");
+		devc->acquisition = NULL;
+		lwla_free_acquisition_state(acq);
+		return ret;
+	}
+	usb_source_add(drvc->sr_ctx, 100, &lwla_receive_data,
+		       (struct sr_dev_inst *)sdi);
+
+	sr_info("Waiting for data.");
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(sdi, LOG_PREFIX);
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	(void)cb_data;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	sr_dbg("Stopping acquisition.");
+
+	sdi->status = SR_ST_STOPPING;
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver sysclk_lwla_driver_info = {
+	.name = "sysclk-lwla",
+	.longname = "SysClk LWLA series",
+	.api_version = 1,
+	.init = init,
+	.cleanup = cleanup,
+	.scan = scan,
+	.dev_list = dev_list,
+	.dev_clear = dev_clear,
+	.config_get = config_get,
+	.config_set = config_set,
+	.config_channel_set = config_channel_set,
+	.config_commit = config_commit,
+	.config_list = config_list,
+	.dev_open = dev_open,
+	.dev_close = dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/sysclk-lwla/lwla.c b/hardware/sysclk-lwla/lwla.c
new file mode 100644
index 0000000..dcb7af7
--- /dev/null
+++ b/hardware/sysclk-lwla/lwla.c
@@ -0,0 +1,237 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Daniel Elstner <daniel.kitta at gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "lwla.h"
+#include "protocol.h"
+#include "libsigrok-internal.h"
+#include <errno.h>
+#include <glib/gstdio.h>
+
+#define BITSTREAM_MAX_SIZE	262144	/* bitstream size limit for safety */
+#define BITSTREAM_HEADER_SIZE	4	/* transfer header size in bytes */
+
+/* Load a bitstream file into memory.  Returns a newly allocated array
+ * consisting of a 32-bit length field followed by the bitstream data.
+ */
+static unsigned char *load_bitstream_file(const char *filename, int *length_p)
+{
+	GStatBuf statbuf;
+	FILE *file;
+	unsigned char *stream;
+	size_t length, count;
+
+	/* Retrieve and validate the file size. */
+	if (g_stat(filename, &statbuf) < 0) {
+		sr_err("Failed to access bitstream file: %s.",
+		       g_strerror(errno));
+		return NULL;
+	}
+	if (!S_ISREG(statbuf.st_mode)) {
+		sr_err("Bitstream is not a regular file.");
+		return NULL;
+	}
+	if (statbuf.st_size <= 0 || statbuf.st_size > BITSTREAM_MAX_SIZE) {
+		sr_err("Refusing to load bitstream of unreasonable size "
+		       "(%" PRIu64 " bytes).", (uint64_t)statbuf.st_size);
+		return NULL;
+	}
+
+	/* The message length includes the 4-byte header. */
+	length = BITSTREAM_HEADER_SIZE + statbuf.st_size;
+	stream = g_try_malloc(length);
+	if (!stream) {
+		sr_err("Failed to allocate bitstream buffer.");
+		return NULL;
+	}
+
+	file = g_fopen(filename, "rb");
+	if (!file) {
+		sr_err("Failed to open bitstream file: %s.", g_strerror(errno));
+		g_free(stream);
+		return NULL;
+	}
+
+	/* Write the message length header. */
+	*(uint32_t *)stream = GUINT32_TO_BE(length);
+
+	count = fread(stream + BITSTREAM_HEADER_SIZE,
+		      length - BITSTREAM_HEADER_SIZE, 1, file);
+	if (count != 1) {
+		sr_err("Failed to read bitstream file: %s.", g_strerror(errno));
+		fclose(file);
+		g_free(stream);
+		return NULL;
+	}
+	fclose(file);
+
+	*length_p = length;
+	return stream;
+}
+
+/* Load a Raw Binary File (.rbf) from the firmware directory and transfer
+ * it to the device.
+ */
+SR_PRIV int lwla_send_bitstream(const struct sr_usb_dev_inst *usb,
+				const char *basename)
+{
+	char *filename;
+	unsigned char *stream;
+	int ret;
+	int length;
+	int xfer_len;
+
+	if (!usb || !basename)
+		return SR_ERR_BUG;
+
+	filename = g_build_filename(FIRMWARE_DIR, basename, NULL);
+	sr_info("Downloading FPGA bitstream at '%s'.", filename);
+
+	stream = load_bitstream_file(filename, &length);
+	g_free(filename);
+
+	if (!stream)
+		return SR_ERR;
+
+	/* Transfer the entire bitstream in one URB. */
+	ret = libusb_bulk_transfer(usb->devhdl, EP_BITSTREAM,
+				   stream, length, &xfer_len, USB_TIMEOUT);
+	g_free(stream);
+
+	if (ret != 0) {
+		sr_err("Failed to transfer bitstream: %s.",
+		       libusb_error_name(ret));
+		return SR_ERR;
+	}
+	if (xfer_len != length) {
+		sr_err("Failed to transfer bitstream: incorrect length "
+		       "%d != %d.", xfer_len, length);
+		return SR_ERR;
+	}
+	sr_info("FPGA bitstream download of %d bytes done.", xfer_len);
+
+	/* This delay appears to be necessary for reliable operation. */
+	g_usleep(30000);
+
+	return SR_OK;
+}
+
+SR_PRIV int lwla_send_command(const struct sr_usb_dev_inst *usb,
+			      const uint16_t *command, int cmd_len)
+{
+	int ret;
+	int xfer_len;
+
+	if (!usb || !command || cmd_len <= 0)
+		return SR_ERR_BUG;
+
+	xfer_len = 0;
+	ret = libusb_bulk_transfer(usb->devhdl, EP_COMMAND,
+				   (unsigned char *)command, cmd_len * 2,
+				   &xfer_len, USB_TIMEOUT);
+	if (ret != 0) {
+		sr_dbg("Failed to send command %d: %s.",
+		       LWLA_TO_UINT16(command[0]), libusb_error_name(ret));
+		return SR_ERR;
+	}
+	if (xfer_len != cmd_len * 2) {
+		sr_dbg("Failed to send command %d: incorrect length %d != %d.",
+		       LWLA_TO_UINT16(command[0]), xfer_len, cmd_len * 2);
+		return SR_ERR;
+	}
+	return SR_OK;
+}
+
+SR_PRIV int lwla_receive_reply(const struct sr_usb_dev_inst *usb,
+			       uint32_t *reply, int reply_len, int expect_len)
+{
+	int ret;
+	int xfer_len;
+
+	if (!usb || !reply || reply_len <= 0)
+		return SR_ERR_BUG;
+
+	xfer_len = 0;
+	ret = libusb_bulk_transfer(usb->devhdl, EP_REPLY,
+				   (unsigned char *)reply, reply_len * 4,
+				   &xfer_len, USB_TIMEOUT);
+	if (ret != 0) {
+		sr_dbg("Failed to receive reply: %s.", libusb_error_name(ret));
+		return SR_ERR;
+	}
+	if (xfer_len != expect_len * 4) {
+		sr_dbg("Failed to receive reply: incorrect length %d != %d.",
+		       xfer_len, expect_len * 4);
+		return SR_ERR;
+	}
+	return SR_OK;
+}
+
+SR_PRIV int lwla_read_reg(const struct sr_usb_dev_inst *usb,
+			  uint16_t reg, uint32_t *value)
+{
+	int ret;
+	uint16_t command[2];
+	uint32_t reply[128]; /* full EP buffer to avoid overflows */
+
+	command[0] = LWLA_WORD(CMD_READ_REG);
+	command[1] = LWLA_WORD(reg);
+
+	ret = lwla_send_command(usb, command, G_N_ELEMENTS(command));
+
+	if (ret != SR_OK)
+		return ret;
+
+	ret = lwla_receive_reply(usb, reply, G_N_ELEMENTS(reply), 1);
+
+	if (ret == SR_OK)
+		*value = LWLA_TO_UINT32(reply[0]);
+
+	return ret;
+}
+
+SR_PRIV int lwla_write_reg(const struct sr_usb_dev_inst *usb,
+			   uint16_t reg, uint32_t value)
+{
+	uint16_t command[4];
+
+	command[0] = LWLA_WORD(CMD_WRITE_REG);
+	command[1] = LWLA_WORD(reg);
+	command[2] = LWLA_WORD_0(value);
+	command[3] = LWLA_WORD_1(value);
+
+	return lwla_send_command(usb, command, G_N_ELEMENTS(command));
+}
+
+SR_PRIV int lwla_write_regs(const struct sr_usb_dev_inst *usb,
+			    const struct regval_pair *regvals, int count)
+{
+	int i;
+	int ret;
+
+	ret = SR_OK;
+
+	for (i = 0; i < count; ++i) {
+		ret = lwla_write_reg(usb, regvals[i].reg, regvals[i].val);
+
+		if (ret != SR_OK)
+			break;
+	}
+
+	return ret;
+}
diff --git a/hardware/sysclk-lwla/lwla.h b/hardware/sysclk-lwla/lwla.h
new file mode 100644
index 0000000..94db07e
--- /dev/null
+++ b/hardware/sysclk-lwla/lwla.h
@@ -0,0 +1,122 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Daniel Elstner <daniel.kitta at gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_SYSCLK_LWLA_LWLA_H
+#define LIBSIGROK_HARDWARE_SYSCLK_LWLA_LWLA_H
+
+#include "libsigrok.h"
+#include <stdint.h>
+#include <libusb.h>
+#include <glib.h>
+
+struct sr_usb_dev_inst;
+
+/* Rotate argument n bits to the left.
+ * This construct is an idiom recognized by GCC as bit rotation.
+ */
+#define LROTATE(a, n) (((a) << (n)) | ((a) >> (CHAR_BIT * sizeof(a) - (n))))
+
+/* Convert 16-bit little endian LWLA protocol word to machine word order. */
+#define LWLA_TO_UINT16(val) GUINT16_FROM_LE(val)
+
+/* Convert 32-bit mixed endian LWLA protocol word to machine word order. */
+#define LWLA_TO_UINT32(val) LROTATE(GUINT32_FROM_LE(val), 16)
+
+/* Convert 16-bit argument to LWLA protocol word. */
+#define LWLA_WORD(val) GUINT16_TO_LE(val)
+
+/* Extract 16-bit units in mixed endian order from 32/64-bit value. */
+#define LWLA_WORD_0(val) GUINT16_TO_LE(((val) >> 16) & 0xFFFF)
+#define LWLA_WORD_1(val) GUINT16_TO_LE((val) & 0xFFFF)
+#define LWLA_WORD_2(val) GUINT16_TO_LE(((val) >> 48) & 0xFFFF)
+#define LWLA_WORD_3(val) GUINT16_TO_LE(((val) >> 32) & 0xFFFF)
+
+/** USB device end points.
+ */
+enum {
+	EP_COMMAND   = 2,
+	EP_BITSTREAM = 4,
+	EP_REPLY     = 6 | LIBUSB_ENDPOINT_IN
+};
+
+/** LWLA protocol command ID codes.
+ */
+enum {
+	CMD_READ_REG	= 1,
+	CMD_WRITE_REG	= 2,
+	CMD_READ_MEM	= 6,
+	CMD_CAP_SETUP	= 7,
+	CMD_CAP_STATUS	= 8,
+};
+
+/** LWLA capture state flags.
+ */
+enum {
+	STATUS_CAPTURING = 1 << 1,
+	STATUS_TRIGGERED = 1 << 4,
+	STATUS_MEM_AVAIL = 1 << 5,
+	STATUS_FLAG_MASK = 0x3F
+};
+
+/** LWLA register addresses.
+ */
+enum {
+	REG_MEM_CTRL2   = 0x1074, /* capture buffer control ??? */
+	REG_MEM_FILL    = 0x1078, /* capture buffer fill level */
+	REG_MEM_CTRL4   = 0x107C, /* capture buffer control ??? */
+
+	REG_DIV_BYPASS  = 0x1094, /* bypass clock divider flag */
+
+	REG_CMD_CTRL1   = 0x10B0, /* command control ??? */
+	REG_CMD_CTRL2   = 0x10B4, /* command control ??? */
+	REG_CMD_CTRL3   = 0x10B8, /* command control ??? */
+	REG_CMD_CTRL4   = 0x10BC, /* command control ??? */
+
+	REG_FREQ_CH1    = 0x10C0, /* channel 1 live frequency */
+	REG_FREQ_CH2    = 0x10C4, /* channel 2 live frequency */
+	REG_FREQ_CH3    = 0x10C8, /* channel 3 live frequency */
+	REG_FREQ_CH4    = 0x10CC, /* channel 4 live frequency */
+};
+
+/** Register/value pair.
+ */
+struct regval_pair {
+	unsigned int reg;
+	unsigned int val;
+};
+
+SR_PRIV int lwla_send_bitstream(const struct sr_usb_dev_inst *usb,
+				const char *basename);
+
+SR_PRIV int lwla_send_command(const struct sr_usb_dev_inst *usb,
+			      const uint16_t *command, int cmd_len);
+
+SR_PRIV int lwla_receive_reply(const struct sr_usb_dev_inst *usb,
+			       uint32_t *reply, int reply_len, int expect_len);
+
+SR_PRIV int lwla_read_reg(const struct sr_usb_dev_inst *usb,
+			  uint16_t reg, uint32_t *value);
+
+SR_PRIV int lwla_write_reg(const struct sr_usb_dev_inst *usb,
+			   uint16_t reg, uint32_t value);
+
+SR_PRIV int lwla_write_regs(const struct sr_usb_dev_inst *usb,
+			    const struct regval_pair *regvals, int count);
+
+#endif /* !LIBSIGROK_HARDWARE_SYSCLK_LWLA_LWLA_H */
diff --git a/hardware/sysclk-lwla/protocol.c b/hardware/sysclk-lwla/protocol.c
new file mode 100644
index 0000000..7bb1948
--- /dev/null
+++ b/hardware/sysclk-lwla/protocol.c
@@ -0,0 +1,985 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Daniel Elstner <daniel.kitta at gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "protocol.h"
+#include <string.h>
+
+/* Bit mask for the RLE repeat-count-follows flag. */
+#define RLE_FLAG_LEN_FOLLOWS ((uint64_t)1 << 35)
+
+/* Start address of capture status memory area to read. */
+#define CAP_STAT_ADDR 5
+
+/* Number of 64-bit words read from the capture status memory. */
+#define CAP_STAT_LEN 5
+
+/* The bitstream filenames are indexed by the clock_config enumeration.
+ */
+static const char bitstream_map[][32] = {
+	"sysclk-lwla1034-off.rbf",
+	"sysclk-lwla1034-int.rbf",
+	"sysclk-lwla1034-extpos.rbf",
+	"sysclk-lwla1034-extneg.rbf",
+};
+
+/* Submit an already filled-in USB transfer.
+ */
+static int submit_transfer(struct dev_context *devc,
+			   struct libusb_transfer *xfer)
+{
+	int ret;
+
+	ret = libusb_submit_transfer(xfer);
+
+	if (ret != 0) {
+		sr_err("Submit transfer failed: %s.", libusb_error_name(ret));
+		devc->transfer_error = TRUE;
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+/* Set up the LWLA in preparation for an acquisition session.
+ */
+static int capture_setup(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct acquisition_state *acq;
+	uint64_t divider_count;
+	uint64_t trigger_mask;
+	uint64_t memory_limit;
+	uint16_t command[3 + 10*4];
+
+	devc = sdi->priv;
+	acq  = devc->acquisition;
+
+	command[0] = LWLA_WORD(CMD_CAP_SETUP);
+	command[1] = LWLA_WORD(0); /* address */
+	command[2] = LWLA_WORD(10); /* length */
+
+	command[3] = LWLA_WORD_0(devc->channel_mask);
+	command[4] = LWLA_WORD_1(devc->channel_mask);
+	command[5] = LWLA_WORD_2(devc->channel_mask);
+	command[6] = LWLA_WORD_3(devc->channel_mask);
+
+	/* Set the clock divide counter maximum for samplerates of up to
+	 * 100 MHz. At the highest samplerate of 125 MHz the clock divider
+	 * is bypassed.
+	 */
+	if (!acq->bypass_clockdiv && devc->samplerate > 0)
+		divider_count = SR_MHZ(100) / devc->samplerate - 1;
+	else
+		divider_count = 0;
+
+	command[7]  = LWLA_WORD_0(divider_count);
+	command[8]  = LWLA_WORD_1(divider_count);
+	command[9]  = LWLA_WORD_2(divider_count);
+	command[10] = LWLA_WORD_3(divider_count);
+
+	command[11] = LWLA_WORD_0(devc->trigger_values);
+	command[12] = LWLA_WORD_1(devc->trigger_values);
+	command[13] = LWLA_WORD_2(devc->trigger_values);
+	command[14] = LWLA_WORD_3(devc->trigger_values);
+
+	command[15] = LWLA_WORD_0(devc->trigger_edge_mask);
+	command[16] = LWLA_WORD_1(devc->trigger_edge_mask);
+	command[17] = LWLA_WORD_2(devc->trigger_edge_mask);
+	command[18] = LWLA_WORD_3(devc->trigger_edge_mask);
+
+	trigger_mask = devc->trigger_mask;
+	/* Set bits to select external TRG input edge. */
+	if (devc->cfg_trigger_source == TRIGGER_EXT_TRG)
+		switch (devc->cfg_trigger_slope) {
+		case EDGE_POSITIVE: trigger_mask |= (uint64_t)1 << 35; break; 
+		case EDGE_NEGATIVE: trigger_mask |= (uint64_t)1 << 34; break; 
+		}
+
+	command[19] = LWLA_WORD_0(trigger_mask);
+	command[20] = LWLA_WORD_1(trigger_mask);
+	command[21] = LWLA_WORD_2(trigger_mask);
+	command[22] = LWLA_WORD_3(trigger_mask);
+
+	/* Set the capture memory full threshold. This is slightly less
+	 * than the actual maximum, most likely in order to compensate for
+	 * pipeline latency.
+	 */
+	memory_limit = MEMORY_DEPTH - 16;
+
+	command[23] = LWLA_WORD_0(memory_limit);
+	command[24] = LWLA_WORD_1(memory_limit);
+	command[25] = LWLA_WORD_2(memory_limit);
+	command[26] = LWLA_WORD_3(memory_limit);
+
+	/* Fill remaining 64-bit words with zeroes. */
+	memset(&command[27], 0, 16 * sizeof(uint16_t));
+
+	return lwla_send_command(sdi->conn, command, G_N_ELEMENTS(command));
+}
+
+/* Issue a register write command as an asynchronous USB transfer.
+ */
+static int issue_write_reg(const struct sr_dev_inst *sdi,
+			   unsigned int reg, unsigned int value)
+{
+	struct dev_context *devc;
+	struct acquisition_state *acq;
+
+	devc = sdi->priv;
+	acq  = devc->acquisition;
+
+	acq->xfer_buf_out[0] = LWLA_WORD(CMD_WRITE_REG);
+	acq->xfer_buf_out[1] = LWLA_WORD(reg);
+	acq->xfer_buf_out[2] = LWLA_WORD_0(value);
+	acq->xfer_buf_out[3] = LWLA_WORD_1(value);
+
+	acq->xfer_out->length = 4 * sizeof(uint16_t);
+
+	return submit_transfer(devc, acq->xfer_out);
+}
+
+/* Issue a register write command as an asynchronous USB transfer for the
+ * next register/value pair of the currently active register write sequence.
+ */
+static int issue_next_write_reg(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct regval_pair *regval;
+	int ret;
+
+	devc = sdi->priv;
+
+	if (devc->reg_write_pos >= devc->reg_write_len) {
+		sr_err("Already written all registers in sequence.");
+		return SR_ERR_BUG;
+	}
+	regval = &devc->reg_write_seq[devc->reg_write_pos];
+
+	ret = issue_write_reg(sdi, regval->reg, regval->val);
+	if (ret != SR_OK)
+		return ret;
+
+	++devc->reg_write_pos;
+	return SR_OK;
+}
+
+/* Issue a capture status request as an asynchronous USB transfer.
+ */
+static void request_capture_status(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct acquisition_state *acq;
+
+	devc = sdi->priv;
+	acq  = devc->acquisition;
+
+	acq->xfer_buf_out[0] = LWLA_WORD(CMD_CAP_STATUS);
+	acq->xfer_buf_out[1] = LWLA_WORD(CAP_STAT_ADDR);
+	acq->xfer_buf_out[2] = LWLA_WORD(CAP_STAT_LEN);
+
+	acq->xfer_out->length = 3 * sizeof(uint16_t);
+
+	if (submit_transfer(devc, acq->xfer_out) == SR_OK)
+		devc->state = STATE_STATUS_REQUEST;
+}
+
+/* Issue a request for the capture buffer fill level as
+ * an asynchronous USB transfer.
+ */
+static void request_capture_length(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct acquisition_state *acq;
+
+	devc = sdi->priv;
+	acq  = devc->acquisition;
+
+	acq->xfer_buf_out[0] = LWLA_WORD(CMD_READ_REG);
+	acq->xfer_buf_out[1] = LWLA_WORD(REG_MEM_FILL);
+
+	acq->xfer_out->length = 2 * sizeof(uint16_t);
+
+	if (submit_transfer(devc, acq->xfer_out) == SR_OK)
+		devc->state = STATE_LENGTH_REQUEST;
+}
+
+/* Initiate the capture memory read operation:  Reset the acquisition state
+ * and start a sequence of register writes in order to set up the device for
+ * reading from the capture buffer.
+ */
+static void issue_read_start(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct acquisition_state *acq;
+	struct regval_pair *regvals;
+
+	devc = sdi->priv;
+	acq  = devc->acquisition;
+
+	/* Reset RLE state. */
+	acq->rle = RLE_STATE_DATA;
+	acq->sample  = 0;
+	acq->run_len = 0;
+
+	acq->samples_done = 0;
+
+	/* For some reason, the start address is 4 rather than 0. */
+	acq->mem_addr_done = 4;
+	acq->mem_addr_next = 4;
+	acq->mem_addr_stop = acq->mem_addr_fill;
+
+	/* Sample position in the packet output buffer. */
+	acq->out_index = 0;
+
+	regvals = devc->reg_write_seq;
+
+	regvals[0].reg = REG_DIV_BYPASS;
+	regvals[0].val = 1;
+
+	regvals[1].reg = REG_MEM_CTRL2;
+	regvals[1].val = 2;
+
+	regvals[2].reg = REG_MEM_CTRL4;
+	regvals[2].val = 4;
+
+	devc->reg_write_pos = 0;
+	devc->reg_write_len = 3;
+
+	if (issue_next_write_reg(sdi) == SR_OK)
+		devc->state = STATE_READ_PREPARE;
+}
+
+/* Issue a command as an asynchronous USB transfer which returns the device
+ * to normal state after a read operation.  Sets a new device context state
+ * on success.
+ */
+static void issue_read_end(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+
+	devc = sdi->priv;
+
+	if (issue_write_reg(sdi, REG_DIV_BYPASS, 0) == SR_OK)
+		devc->state = STATE_READ_END;
+}
+
+/* Decode an incoming reponse to a buffer fill level request and act on it
+ * as appropriate.  Note that this function changes the device context state.
+ */
+static void process_capture_length(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct acquisition_state *acq;
+
+	devc = sdi->priv;
+	acq  = devc->acquisition;
+
+	if (acq->xfer_in->actual_length != 4) {
+		sr_err("Received size %d doesn't match expected size 4.",
+		       acq->xfer_in->actual_length);
+		devc->transfer_error = TRUE;
+		return;
+	}
+	acq->mem_addr_fill = LWLA_TO_UINT32(acq->xfer_buf_in[0]);
+
+	sr_dbg("%zu words in capture buffer.", acq->mem_addr_fill);
+
+	if (acq->mem_addr_fill > 0 && sdi->status == SR_ST_ACTIVE)
+		issue_read_start(sdi);
+	else
+		issue_read_end(sdi);
+}
+
+/* Initiate a sequence of register write commands with the effect of
+ * cancelling a running capture operation.  This sets a new device state
+ * if issuing the first command succeeds.
+ */
+static void issue_stop_capture(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct regval_pair *regvals;
+
+	devc = sdi->priv;
+
+	if (devc->stopping_in_progress)
+		return;
+
+	regvals = devc->reg_write_seq;
+
+	regvals[0].reg = REG_CMD_CTRL2;
+	regvals[0].val = 10;
+
+	regvals[1].reg = REG_CMD_CTRL3;
+	regvals[1].val = 0;
+
+	regvals[2].reg = REG_CMD_CTRL4;
+	regvals[2].val = 0;
+
+	regvals[3].reg = REG_CMD_CTRL1;
+	regvals[3].val = 0;
+
+	regvals[4].reg = REG_DIV_BYPASS;
+	regvals[4].val = 0;
+
+	devc->reg_write_pos = 0;
+	devc->reg_write_len = 5;
+
+	if (issue_next_write_reg(sdi) == SR_OK) {
+		devc->stopping_in_progress = TRUE;
+		devc->state = STATE_STOP_CAPTURE;
+	}
+}
+
+/* Decode an incoming capture status reponse and act on it as appropriate.
+ * Note that this function changes the device state.
+ */
+static void process_capture_status(const struct sr_dev_inst *sdi)
+{
+	uint64_t duration;
+	struct dev_context *devc;
+	struct acquisition_state *acq;
+	unsigned int mem_fill;
+	unsigned int flags;
+
+	devc = sdi->priv;
+	acq  = devc->acquisition;
+
+	if (acq->xfer_in->actual_length != CAP_STAT_LEN * 8) {
+		sr_err("Received size %d doesn't match expected size %d.",
+		       acq->xfer_in->actual_length, CAP_STAT_LEN * 8);
+		devc->transfer_error = TRUE;
+		return;
+	}
+
+	/* TODO: Find out the actual bit width of these fields as stored
+	 * in the FPGA.  These fields are definitely less than 64 bit wide
+	 * internally, and the unused bits occasionally even contain garbage.
+	 */
+	mem_fill = LWLA_TO_UINT32(acq->xfer_buf_in[0]);
+	duration = LWLA_TO_UINT32(acq->xfer_buf_in[4]);
+	flags    = LWLA_TO_UINT32(acq->xfer_buf_in[8]) & STATUS_FLAG_MASK;
+
+	/* The LWLA1034 runs at 125 MHz if the clock divider is bypassed.
+	 * However, the time base used for the duration is apparently not
+	 * adjusted for this "boost" mode.  Whereas normally the duration
+	 * unit is 1 ms, it is 0.8 ms when the clock divider is bypassed.
+	 * As 0.8 = 100 MHz / 125 MHz, it seems that the internal cycle
+	 * counter period is the same as at the 100 MHz setting.
+	 */
+	if (acq->bypass_clockdiv)
+		acq->duration_now = duration * 4 / 5;
+	else
+		acq->duration_now = duration;
+
+	sr_spew("Captured %u words, %" PRIu64 " ms, flags 0x%02X.",
+		mem_fill, acq->duration_now, flags);
+
+	if ((flags & STATUS_TRIGGERED) > (acq->capture_flags & STATUS_TRIGGERED))
+		sr_info("Capture triggered.");
+
+	acq->capture_flags = flags;
+
+	if (acq->duration_now >= acq->duration_max) {
+		sr_dbg("Time limit reached, stopping capture.");
+		issue_stop_capture(sdi);
+		return;
+	}
+	devc->state = STATE_STATUS_WAIT;
+
+	if ((acq->capture_flags & STATUS_TRIGGERED) == 0) {
+		sr_spew("Waiting for trigger.");
+	} else if ((acq->capture_flags & STATUS_MEM_AVAIL) == 0) {
+		sr_dbg("Capture memory filled.");
+		request_capture_length(sdi);
+	} else if ((acq->capture_flags & STATUS_CAPTURING) != 0) {
+		sr_spew("Sampling in progress.");
+	}
+}
+
+/* Issue a capture buffer read request as an asynchronous USB transfer.
+ * The address and size of the memory area to read are derived from the
+ * current acquisition state.
+ */
+static void request_read_mem(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct acquisition_state *acq;
+	size_t count;
+
+	devc = sdi->priv;
+	acq  = devc->acquisition;
+
+	if (acq->mem_addr_next >= acq->mem_addr_stop)
+		return;
+
+	/* Always read a multiple of 8 device words. */
+	count = (acq->mem_addr_stop - acq->mem_addr_next + 7) / 8 * 8;
+	count = MIN(count, READ_CHUNK_LEN);
+
+	acq->xfer_buf_out[0] = LWLA_WORD(CMD_READ_MEM);
+	acq->xfer_buf_out[1] = LWLA_WORD_0(acq->mem_addr_next);
+	acq->xfer_buf_out[2] = LWLA_WORD_1(acq->mem_addr_next);
+	acq->xfer_buf_out[3] = LWLA_WORD_0(count);
+	acq->xfer_buf_out[4] = LWLA_WORD_1(count);
+
+	acq->xfer_out->length = 5 * sizeof(uint16_t);
+
+	if (submit_transfer(devc, acq->xfer_out) == SR_OK) {
+		acq->mem_addr_next += count;
+		devc->state = STATE_READ_REQUEST;
+	}
+}
+
+/* Demangle and decompress incoming sample data from the capture buffer.
+ * The data chunk is taken from the acquisition state, and is expected to
+ * contain a multiple of 8 device words.
+ * All data currently in the acquisition buffer will be processed.  Packets
+ * of decoded samples are sent off to the session bus whenever the output
+ * buffer becomes full while decoding.
+ */
+static int process_sample_data(const struct sr_dev_inst *sdi)
+{
+	uint64_t sample;
+	uint64_t high_nibbles;
+	uint64_t word;
+	struct dev_context *devc;
+	struct acquisition_state *acq;
+	uint8_t *out_p;
+	uint32_t *slice;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_logic logic;
+	size_t expect_len;
+	size_t actual_len;
+	size_t out_max_samples;
+	size_t out_run_samples;
+	size_t ri;
+	size_t in_words_left;
+	size_t si;
+
+	devc = sdi->priv;
+	acq  = devc->acquisition;
+
+	if (acq->mem_addr_done >= acq->mem_addr_stop
+			|| acq->samples_done >= acq->samples_max)
+		return SR_OK;
+
+	in_words_left = MIN(acq->mem_addr_stop - acq->mem_addr_done,
+			    READ_CHUNK_LEN);
+	expect_len = LWLA1034_MEMBUF_LEN(in_words_left) * sizeof(uint32_t);
+	actual_len = acq->xfer_in->actual_length;
+
+	if (actual_len != expect_len) {
+		sr_err("Received size %zu does not match expected size %zu.",
+		       actual_len, expect_len);
+		devc->transfer_error = TRUE;
+		return SR_ERR;
+	}
+	acq->mem_addr_done += in_words_left;
+
+	/* Prepare session packet. */
+	packet.type    = SR_DF_LOGIC;
+	packet.payload = &logic;
+	logic.unitsize = UNIT_SIZE;
+	logic.data     = acq->out_packet;
+
+	slice = acq->xfer_buf_in;
+	si = 0; /* word index within slice */
+
+	for (;;) {
+		/* Calculate number of samples to write into packet. */
+		out_max_samples = MIN(acq->samples_max - acq->samples_done,
+				      PACKET_LENGTH - acq->out_index);
+		out_run_samples = MIN(acq->run_len, out_max_samples);
+
+		/* Expand run-length samples into session packet. */
+		sample = acq->sample;
+		out_p = &acq->out_packet[acq->out_index * UNIT_SIZE];
+
+		for (ri = 0; ri < out_run_samples; ++ri) {
+			out_p[0] =  sample        & 0xFF;
+			out_p[1] = (sample >>  8) & 0xFF;
+			out_p[2] = (sample >> 16) & 0xFF;
+			out_p[3] = (sample >> 24) & 0xFF;
+			out_p[4] = (sample >> 32) & 0xFF;
+			out_p += UNIT_SIZE;
+		}
+		acq->run_len -= out_run_samples;
+		acq->out_index += out_run_samples;
+		acq->samples_done += out_run_samples;
+
+		/* Packet full or sample count limit reached? */
+		if (out_run_samples == out_max_samples) {
+			logic.length = acq->out_index * UNIT_SIZE;
+			sr_session_send(sdi, &packet);
+			acq->out_index = 0;
+
+			if (acq->samples_done >= acq->samples_max)
+				return SR_OK; /* sample limit reached */
+			if (acq->run_len > 0)
+				continue; /* need another packet */
+		}
+
+		if (in_words_left == 0)
+			break; /* done with current chunk */
+
+		/* Now work on the current slice. */
+		high_nibbles = LWLA_TO_UINT32(slice[8]);
+		word = LWLA_TO_UINT32(slice[si]);
+		word |= (high_nibbles << (4 * si + 4)) & ((uint64_t)0xF << 32);
+
+		if (acq->rle == RLE_STATE_DATA) {
+			acq->sample = word & ALL_CHANNELS_MASK;
+			acq->run_len = ((word >> NUM_CHANNELS) & 1) + 1;
+			if (word & RLE_FLAG_LEN_FOLLOWS)
+				acq->rle = RLE_STATE_LEN;
+		} else {
+			acq->run_len += word << 1;
+			acq->rle = RLE_STATE_DATA;
+		}
+
+		/* Move to next word. */
+		si = (si + 1) % 8;
+		if (si == 0)
+			slice += 9;
+		--in_words_left;
+	}
+
+	/* Send out partially filled packet if this was the last chunk. */
+	if (acq->mem_addr_done >= acq->mem_addr_stop && acq->out_index > 0) {
+		logic.length = acq->out_index * UNIT_SIZE;
+		sr_session_send(sdi, &packet);
+		acq->out_index = 0;
+	}
+	return SR_OK;
+}
+
+/* Finish an acquisition session.  This sends the end packet to the session
+ * bus and removes the listener for asynchronous USB transfers.
+ */
+static void end_acquisition(struct sr_dev_inst *sdi)
+{
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_datafeed_packet packet;
+
+	drvc = sdi->driver->priv;
+	devc = sdi->priv;
+
+	if (devc->state == STATE_IDLE)
+		return;
+
+	devc->state = STATE_IDLE;
+
+	/* Remove USB file descriptors from polling. */
+	usb_source_remove(drvc->sr_ctx);
+
+	packet.type = SR_DF_END;
+	sr_session_send(sdi, &packet);
+
+	lwla_free_acquisition_state(devc->acquisition);
+	devc->acquisition = NULL;
+
+	sdi->status = SR_ST_ACTIVE;
+}
+
+/* USB output transfer completion callback.
+ */
+static void receive_transfer_out(struct libusb_transfer *transfer)
+{
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+
+	sdi  = transfer->user_data;
+	devc = sdi->priv;
+
+	if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
+		sr_err("Transfer to device failed: %d.", transfer->status);
+		devc->transfer_error = TRUE;
+		return;
+	}
+
+	if (devc->reg_write_pos < devc->reg_write_len) {
+		issue_next_write_reg(sdi);
+	} else {
+		switch (devc->state) {
+		case STATE_START_CAPTURE:
+			devc->state = STATE_STATUS_WAIT;
+			break;
+		case STATE_STATUS_REQUEST:
+			devc->state = STATE_STATUS_RESPONSE;
+			submit_transfer(devc, devc->acquisition->xfer_in);
+			break;
+		case STATE_STOP_CAPTURE:
+			if (sdi->status == SR_ST_ACTIVE)
+				request_capture_length(sdi);
+			else
+				end_acquisition(sdi);
+			break;
+		case STATE_LENGTH_REQUEST:
+			devc->state = STATE_LENGTH_RESPONSE;
+			submit_transfer(devc, devc->acquisition->xfer_in);
+			break;
+		case STATE_READ_PREPARE:
+			request_read_mem(sdi);
+			break;
+		case STATE_READ_REQUEST:
+			devc->state = STATE_READ_RESPONSE;
+			submit_transfer(devc, devc->acquisition->xfer_in);
+			break;
+		case STATE_READ_END:
+			end_acquisition(sdi);
+			break;
+		default:
+			sr_err("Unexpected device state %d.", devc->state);
+			break;
+		}
+	}
+}
+
+/* USB input transfer completion callback.
+ */
+static void receive_transfer_in(struct libusb_transfer *transfer)
+{
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+	struct acquisition_state *acq;
+
+	sdi  = transfer->user_data;
+	devc = sdi->priv;
+	acq  = devc->acquisition;
+
+	if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
+		sr_err("Transfer from device failed: %d.", transfer->status);
+		devc->transfer_error = TRUE;
+		return;
+	}
+
+	switch (devc->state) {
+	case STATE_STATUS_RESPONSE:
+		process_capture_status(sdi);
+		break;
+	case STATE_LENGTH_RESPONSE:
+		process_capture_length(sdi);
+		break;
+	case STATE_READ_RESPONSE:
+		if (process_sample_data(sdi) == SR_OK
+				&& acq->mem_addr_next < acq->mem_addr_stop
+				&& acq->samples_done < acq->samples_max)
+			request_read_mem(sdi);
+		else
+			issue_read_end(sdi);
+		break;
+	default:
+		sr_err("Unexpected device state %d.", devc->state);
+		break;
+	}
+}
+
+/* Initialize the LWLA.  This downloads a bitstream into the FPGA
+ * and executes a simple device test sequence.
+ */
+SR_PRIV int lwla_init_device(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	int ret;
+	uint32_t value;
+
+	devc = sdi->priv;
+
+	/* Force reload of bitstream */
+	devc->cur_clock_config = CONF_CLOCK_NONE;
+
+	ret = lwla_set_clock_config(sdi);
+
+	if (ret != SR_OK)
+		return ret;
+
+	ret = lwla_write_reg(sdi->conn, REG_CMD_CTRL2, 100);
+	if (ret != SR_OK)
+		return ret;
+
+	ret = lwla_read_reg(sdi->conn, REG_CMD_CTRL1, &value);
+	if (ret != SR_OK)
+		return ret;
+	sr_dbg("Received test word 0x%08X back.", value);
+	if (value != 0x12345678)
+		return SR_ERR;
+
+	ret = lwla_read_reg(sdi->conn, REG_CMD_CTRL4, &value);
+	if (ret != SR_OK)
+		return ret;
+	sr_dbg("Received test word 0x%08X back.", value);
+	if (value != 0x12345678)
+		return SR_ERR;
+
+	ret = lwla_read_reg(sdi->conn, REG_CMD_CTRL3, &value);
+	if (ret != SR_OK)
+		return ret;
+	sr_dbg("Received test word 0x%08X back.", value);
+	if (value != 0x87654321)
+		return SR_ERR;
+
+	return ret;
+}
+
+/* Select the LWLA clock configuration.  If the clock source changed from
+ * the previous setting, this will download a new bitstream to the FPGA.
+ */
+SR_PRIV int lwla_set_clock_config(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	int ret;
+	enum clock_config choice;
+
+	devc = sdi->priv;
+
+	if (sdi->status == SR_ST_INACTIVE)
+		choice = CONF_CLOCK_NONE;
+	else if (devc->cfg_clock_source == CLOCK_INTERNAL)
+		choice = CONF_CLOCK_INT;
+	else if (devc->cfg_clock_edge == EDGE_POSITIVE)
+		choice = CONF_CLOCK_EXT_RISE;
+	else
+		choice = CONF_CLOCK_EXT_FALL;
+
+	if (choice != devc->cur_clock_config) {
+		devc->cur_clock_config = CONF_CLOCK_NONE;
+		ret = lwla_send_bitstream(sdi->conn, bitstream_map[choice]);
+		if (ret == SR_OK)
+			devc->cur_clock_config = choice;
+		return ret;
+	}
+	return SR_OK;
+}
+
+/* Configure the LWLA in preparation for an acquisition session.
+ */
+SR_PRIV int lwla_setup_acquisition(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_usb_dev_inst *usb;
+	struct acquisition_state *acq;
+	struct regval_pair regvals[7];
+	int ret;
+
+	devc = sdi->priv;
+	usb  = sdi->conn;
+	acq  = devc->acquisition;
+
+	if (devc->limit_msec > 0) {
+		acq->duration_max = devc->limit_msec;
+		sr_info("Acquisition time limit %" PRIu64 " ms.",
+			devc->limit_msec);
+	} else
+		acq->duration_max = MAX_LIMIT_MSEC;
+
+	if (devc->limit_samples > 0) {
+		acq->samples_max = devc->limit_samples;
+		sr_info("Acquisition sample count limit %" PRIu64 ".",
+			devc->limit_samples);
+	} else
+		acq->samples_max = MAX_LIMIT_SAMPLES;
+
+	if (devc->cfg_clock_source == CLOCK_INTERNAL) {
+		sr_info("Internal clock, samplerate %" PRIu64 ".",
+			devc->samplerate);
+		if (devc->samplerate == 0)
+			return SR_ERR_BUG;
+		/* At 125 MHz, the clock divider is bypassed. */
+		acq->bypass_clockdiv = (devc->samplerate > SR_MHZ(100));
+
+		/* If only one of the limits is set, derive the other one. */
+		if (devc->limit_msec == 0 && devc->limit_samples > 0)
+			acq->duration_max = devc->limit_samples
+					* 1000 / devc->samplerate + 1;
+		else if (devc->limit_samples == 0 && devc->limit_msec > 0)
+			acq->samples_max = devc->limit_msec
+					* devc->samplerate / 1000;
+	} else {
+		acq->bypass_clockdiv = TRUE;
+
+		if (devc->cfg_clock_edge == EDGE_NEGATIVE)
+			sr_info("External clock, falling edge.");
+		else
+			sr_info("External clock, rising edge.");
+	}
+
+	regvals[0].reg = REG_MEM_CTRL2;
+	regvals[0].val = 2;
+
+	regvals[1].reg = REG_MEM_CTRL2;
+	regvals[1].val = 1;
+
+	regvals[2].reg = REG_CMD_CTRL2;
+	regvals[2].val = 10;
+
+	regvals[3].reg = REG_CMD_CTRL3;
+	regvals[3].val = 0x74;
+
+	regvals[4].reg = REG_CMD_CTRL4;
+	regvals[4].val = 0;
+
+	regvals[5].reg = REG_CMD_CTRL1;
+	regvals[5].val = 0;
+
+	regvals[6].reg = REG_DIV_BYPASS;
+	regvals[6].val = acq->bypass_clockdiv;
+
+	ret = lwla_write_regs(usb, regvals, G_N_ELEMENTS(regvals));
+	if (ret != SR_OK)
+		return ret;
+
+	return capture_setup(sdi);
+}
+
+/* Start the capture operation on the LWLA device.  Beginning with this
+ * function, all USB transfers will be asynchronous until the end of the
+ * acquisition session.
+ */
+SR_PRIV int lwla_start_acquisition(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_usb_dev_inst *usb;
+	struct acquisition_state *acq;
+	struct regval_pair *regvals;
+
+	devc = sdi->priv;
+	usb  = sdi->conn;
+	acq  = devc->acquisition;
+
+	acq->duration_now  = 0;
+	acq->mem_addr_fill = 0;
+	acq->capture_flags = 0;
+
+	libusb_fill_bulk_transfer(acq->xfer_out, usb->devhdl, EP_COMMAND,
+				  (unsigned char *)acq->xfer_buf_out, 0,
+				  &receive_transfer_out,
+				  (struct sr_dev_inst *)sdi, USB_TIMEOUT);
+
+	libusb_fill_bulk_transfer(acq->xfer_in, usb->devhdl, EP_REPLY,
+				  (unsigned char *)acq->xfer_buf_in,
+				  sizeof acq->xfer_buf_in,
+				  &receive_transfer_in,
+				  (struct sr_dev_inst *)sdi, USB_TIMEOUT);
+
+	regvals = devc->reg_write_seq;
+
+	regvals[0].reg = REG_CMD_CTRL2;
+	regvals[0].val = 10;
+
+	regvals[1].reg = REG_CMD_CTRL3;
+	regvals[1].val = 1;
+
+	regvals[2].reg = REG_CMD_CTRL4;
+	regvals[2].val = 0;
+
+	regvals[3].reg = REG_CMD_CTRL1;
+	regvals[3].val = 0;
+
+	devc->reg_write_pos = 0;
+	devc->reg_write_len = 4;
+
+	devc->state = STATE_START_CAPTURE;
+
+	return issue_next_write_reg(sdi);
+}
+
+/* Allocate an acquisition state object.
+ */
+SR_PRIV struct acquisition_state *lwla_alloc_acquisition_state(void)
+{
+	struct acquisition_state *acq;
+
+	acq = g_try_new0(struct acquisition_state, 1);
+	if (!acq) {
+		sr_err("Acquisition state malloc failed.");
+		return NULL;
+	}
+
+	acq->xfer_in = libusb_alloc_transfer(0);
+	if (!acq->xfer_in) {
+		sr_err("Transfer malloc failed.");
+		g_free(acq);
+		return NULL;
+	}
+
+	acq->xfer_out = libusb_alloc_transfer(0);
+	if (!acq->xfer_out) {
+		sr_err("Transfer malloc failed.");
+		libusb_free_transfer(acq->xfer_in);
+		g_free(acq);
+		return NULL;
+	}
+
+	return acq;
+}
+
+/* Deallocate an acquisition state object.
+ */
+SR_PRIV void lwla_free_acquisition_state(struct acquisition_state *acq)
+{
+	if (acq) {
+		libusb_free_transfer(acq->xfer_out);
+		libusb_free_transfer(acq->xfer_in);
+		g_free(acq);
+	}
+}
+
+/* USB I/O source callback.
+ */
+SR_PRIV int lwla_receive_data(int fd, int revents, void *cb_data)
+{
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+	struct drv_context *drvc;
+	struct timeval tv;
+	int ret;
+
+	(void)fd;
+
+	sdi  = cb_data;
+	devc = sdi->priv;
+	drvc = sdi->driver->priv;
+
+	if (!devc || !drvc)
+		return FALSE;
+
+	/* No timeout: return immediately. */
+	tv.tv_sec  = 0;
+	tv.tv_usec = 0;
+
+	ret = libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx,
+						     &tv, NULL);
+	if (ret != 0)
+		sr_err("Event handling failed: %s.", libusb_error_name(ret));
+
+	/* If no event flags are set the timeout must have expired. */
+	if (revents == 0 && devc->state == STATE_STATUS_WAIT) {
+		if (sdi->status == SR_ST_STOPPING)
+			issue_stop_capture(sdi);
+		else
+			request_capture_status(sdi);
+	}
+
+	/* Check if an error occurred on a transfer. */
+	if (devc->transfer_error)
+		end_acquisition(sdi);
+
+	return TRUE;
+}
diff --git a/hardware/sysclk-lwla/protocol.h b/hardware/sysclk-lwla/protocol.h
new file mode 100644
index 0000000..d77db0f
--- /dev/null
+++ b/hardware/sysclk-lwla/protocol.h
@@ -0,0 +1,263 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Daniel Elstner <daniel.kitta at gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_SYSCLK_LWLA_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_SYSCLK_LWLA_PROTOCOL_H
+
+#define LOG_PREFIX "sysclk-lwla"
+
+#include "lwla.h"
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include <stdint.h>
+#include <glib.h>
+
+/* For now, only the LWLA1034 is supported.
+ */
+#define VENDOR_NAME	"SysClk"
+#define MODEL_NAME	"LWLA1034"
+
+#define USB_VID_PID	"2961.6689"
+#define USB_INTERFACE	0
+#define USB_TIMEOUT	3000 /* ms */
+
+#define NUM_CHANNELS	34
+#define TRIGGER_TYPES	"01fr"
+
+/* Bit mask covering all 34 channels.
+ */
+#define ALL_CHANNELS_MASK (((uint64_t)1 << NUM_CHANNELS) - 1)
+
+/** Unit and packet size for the sigrok logic datafeed.
+ */
+#define UNIT_SIZE	((NUM_CHANNELS + 7) / 8)
+#define PACKET_LENGTH	10000	/* units */
+
+/** Size of the acquisition buffer in device memory units.
+ */
+#define MEMORY_DEPTH	(256 * 1024)	/* 256k x 36 bit */
+
+/** Number of device memory units (36 bit) to read at a time.  Slices of 8
+ * consecutive 36-bit words are mapped to 9 32-bit words each, so the chunk
+ * length should be a multiple of 8 to ensure alignment to slice boundaries.
+ *
+ * Experimentation has shown that reading chunks larger than about 1024 bytes
+ * is unreliable.  The threshold seems to relate to the buffer size on the FX2
+ * USB chip:  The configured endpoint buffer size is 512, and with double or
+ * triple buffering enabled a multiple of 512 bytes can be kept in fly.
+ *
+ * The vendor software limits reads to 120 words (15 slices, 540 bytes) at
+ * a time.  So far, it appears safe to increase this to 224 words (28 slices,
+ * 1008 bytes), thus making the most of two 512 byte buffers.
+ */
+#define READ_CHUNK_LEN	(28 * 8)
+
+/** Calculate the required buffer size in 32-bit units for reading a given
+ * number of device memory words.  Rounded to a multiple of 8 device words.
+ */
+#define LWLA1034_MEMBUF_LEN(count) (((count) + 7) / 8 * 9)
+
+/** Maximum number of 16-bit words sent at a time during acquisition.
+ * Used for allocating the libusb transfer buffer.
+ */
+#define MAX_ACQ_SEND_WORDS	8 /* 5 for memory read request plus stuffing */
+
+/** Maximum number of 32-bit words received at a time during acquisition.
+ * Round to the next multiple of the endpoint buffer size to avoid nasty
+ * transfer overflow conditions on hiccups.
+ */
+#define MAX_ACQ_RECV_LEN	((READ_CHUNK_LEN / 8 * 9 + 127) / 128 * 128)
+
+/** Maximum length of a register write sequence.
+ */
+#define MAX_REG_WRITE_SEQ_LEN   5
+
+/** Default configured samplerate.
+ */
+#define DEFAULT_SAMPLERATE	SR_MHZ(125)
+
+/** Maximum configurable sample count limit.
+ */
+#define MAX_LIMIT_SAMPLES	(UINT64_C(1) << 48)
+
+/** Maximum configurable capture duration in milliseconds.
+ */
+#define MAX_LIMIT_MSEC		(UINT64_C(1) << 32)
+
+/** LWLA1034 FPGA clock configurations.
+ */
+enum clock_config {
+	CONF_CLOCK_NONE,
+	CONF_CLOCK_INT,
+	CONF_CLOCK_EXT_RISE,
+	CONF_CLOCK_EXT_FALL,
+};
+
+/** Available clock sources.
+ */
+enum clock_source {
+	CLOCK_INTERNAL,
+	CLOCK_EXT_CLK,
+};
+
+/** Available trigger sources.
+ */
+enum trigger_source {
+	TRIGGER_CHANNELS = 0,
+	TRIGGER_EXT_TRG,
+};
+
+/** Available edge choices for the external clock and trigger inputs.
+ */
+enum signal_edge {
+	EDGE_POSITIVE = 0,
+	EDGE_NEGATIVE,
+};
+
+/** LWLA device states.
+ */
+enum device_state {
+	STATE_IDLE = 0,
+
+	STATE_START_CAPTURE,
+
+	STATE_STATUS_WAIT,
+	STATE_STATUS_REQUEST,
+	STATE_STATUS_RESPONSE,
+
+	STATE_STOP_CAPTURE,
+
+	STATE_LENGTH_REQUEST,
+	STATE_LENGTH_RESPONSE,
+
+	STATE_READ_PREPARE,
+	STATE_READ_REQUEST,
+	STATE_READ_RESPONSE,
+	STATE_READ_END,
+};
+
+/** LWLA run-length encoding states.
+ */
+enum rle_state {
+	RLE_STATE_DATA,
+	RLE_STATE_LEN
+};
+
+/** LWLA sample acquisition and decompression state.
+ */
+struct acquisition_state {
+	uint64_t sample;
+	uint64_t run_len;
+
+	/** Maximum number of samples to process. */
+	uint64_t samples_max;
+	/** Number of samples sent to the session bus. */
+	uint64_t samples_done;
+
+	/** Maximum duration of capture, in milliseconds. */
+	uint64_t duration_max;
+	/** Running capture duration since trigger event. */
+	uint64_t duration_now;
+
+	/** Capture memory fill level. */
+	size_t mem_addr_fill;
+
+	size_t mem_addr_done;
+	size_t mem_addr_next;
+	size_t mem_addr_stop;
+
+	size_t out_index;
+
+	struct libusb_transfer *xfer_in;
+	struct libusb_transfer *xfer_out;
+
+	unsigned int capture_flags;
+
+	enum rle_state rle;
+
+	/** Whether to bypass the clock divider. */
+	gboolean bypass_clockdiv;
+
+	/* Payload data buffers for incoming and outgoing transfers. */
+	uint32_t xfer_buf_in[MAX_ACQ_RECV_LEN];
+	uint16_t xfer_buf_out[MAX_ACQ_SEND_WORDS];
+
+	/* Payload buffer for sigrok logic packets. */
+	uint8_t out_packet[PACKET_LENGTH * UNIT_SIZE];
+};
+
+/** Private, per-device-instance driver context.
+ */
+struct dev_context {
+	/** The samplerate selected by the user. */
+	uint64_t samplerate;
+
+	/** The maximimum sampling duration, in milliseconds. */
+	uint64_t limit_msec;
+
+	/** The maximimum number of samples to acquire. */
+	uint64_t limit_samples;
+
+	/** Channels to use. */
+	uint64_t channel_mask;
+
+	uint64_t trigger_mask;
+	uint64_t trigger_edge_mask;
+	uint64_t trigger_values;
+
+	struct acquisition_state *acquisition;
+
+	struct regval_pair reg_write_seq[MAX_REG_WRITE_SEQ_LEN];
+	int reg_write_pos;
+	int reg_write_len;
+
+	enum device_state state;
+
+	/** The currently active clock configuration of the device. */
+	enum clock_config cur_clock_config;
+
+	/** Clock source configuration setting. */
+	enum clock_source cfg_clock_source;
+	/** Clock edge configuration setting. */
+	enum signal_edge cfg_clock_edge;
+
+	/** Trigger source configuration setting. */
+	enum trigger_source cfg_trigger_source;
+	/** Trigger slope configuration setting. */
+	enum signal_edge cfg_trigger_slope;
+
+	/* Indicates that stopping the acquisition is currently in progress. */
+	gboolean stopping_in_progress;
+
+	/* Indicates whether a transfer failed. */
+	gboolean transfer_error;
+};
+
+SR_PRIV struct acquisition_state *lwla_alloc_acquisition_state(void);
+SR_PRIV void lwla_free_acquisition_state(struct acquisition_state *acq);
+
+SR_PRIV int lwla_init_device(const struct sr_dev_inst *sdi);
+SR_PRIV int lwla_set_clock_config(const struct sr_dev_inst *sdi);
+SR_PRIV int lwla_setup_acquisition(const struct sr_dev_inst *sdi);
+SR_PRIV int lwla_start_acquisition(const struct sr_dev_inst *sdi);
+SR_PRIV int lwla_abort_acquisition(const struct sr_dev_inst *sdi);
+
+SR_PRIV int lwla_receive_data(int fd, int revents, void *cb_data);
+
+#endif /* !LIBSIGROK_HARDWARE_SYSCLK_LWLA_PROTOCOL_H */
diff --git a/hardware/teleinfo/api.c b/hardware/teleinfo/api.c
new file mode 100644
index 0000000..931e599
--- /dev/null
+++ b/hardware/teleinfo/api.c
@@ -0,0 +1,288 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Aurelien Jacobs <aurel at gnuage.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+
+static const int32_t hwopts[] = {
+	SR_CONF_CONN,
+	SR_CONF_SERIALCOMM,
+};
+
+static const int32_t hwcaps[] = {
+	SR_CONF_ENERGYMETER,
+	SR_CONF_LIMIT_SAMPLES,
+	SR_CONF_LIMIT_MSEC,
+	SR_CONF_CONTINUOUS,
+};
+
+SR_PRIV struct sr_dev_driver teleinfo_driver_info;
+static struct sr_dev_driver *di = &teleinfo_driver_info;
+
+static int init(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+	struct sr_dev_inst *sdi;
+	struct sr_channel *ch;
+	GSList *devices = NULL, *l;
+	const char *conn = NULL, *serialcomm = NULL;
+	uint8_t buf[292];
+	size_t len;
+	struct sr_config *src;
+
+	len = sizeof(buf);
+
+	for (l = options; l; l = l->next) {
+		src = l->data;
+		switch (src->key) {
+		case SR_CONF_CONN:
+			conn = g_variant_get_string(src->data, NULL);
+			break;
+		case SR_CONF_SERIALCOMM:
+			serialcomm = g_variant_get_string(src->data, NULL);
+			break;
+		}
+	}
+	if (!conn)
+		return NULL;
+	if (!serialcomm)
+		serialcomm = "1200/7e1";
+
+	if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+		return NULL;
+	if (serial_open(serial, SERIAL_RDONLY | SERIAL_NONBLOCK) != SR_OK)
+		return NULL;
+
+	sr_info("Probing serial port %s.", conn);
+
+	drvc = di->priv;
+	drvc->instances = NULL;
+	serial_flush(serial);
+
+	/* Let's get a bit of data and see if we can find a packet. */
+	if (serial_stream_detect(serial, buf, &len, len,
+	                         teleinfo_packet_valid, 3000, 1200) != SR_OK)
+		goto scan_cleanup;
+
+	sr_info("Found device on port %s.", conn);
+
+	if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "EDF", "Teleinfo", NULL)))
+		goto scan_cleanup;
+
+	if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+		sr_err("Device context malloc failed.");
+		goto scan_cleanup;
+	}
+
+	devc->optarif = teleinfo_get_optarif(buf);
+
+	sdi->inst_type = SR_INST_SERIAL;
+	sdi->conn = serial;
+	sdi->priv = devc;
+	sdi->driver = di;
+
+	if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P")))
+		goto scan_cleanup;
+	sdi->channels = g_slist_append(sdi->channels, ch);
+
+	if (devc->optarif == OPTARIF_BASE) {
+		if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "BASE")))
+			goto scan_cleanup;
+		sdi->channels = g_slist_append(sdi->channels, ch);
+	} else if (devc->optarif == OPTARIF_HC) {
+		if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HP")))
+			goto scan_cleanup;
+		sdi->channels = g_slist_append(sdi->channels, ch);
+		if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HC")))
+			goto scan_cleanup;
+		sdi->channels = g_slist_append(sdi->channels, ch);
+	} else if (devc->optarif == OPTARIF_EJP) {
+		if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HN")))
+			goto scan_cleanup;
+		sdi->channels = g_slist_append(sdi->channels, ch);
+		if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HPM")))
+			goto scan_cleanup;
+		sdi->channels = g_slist_append(sdi->channels, ch);
+	} else if (devc->optarif == OPTARIF_BBR) {
+		if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HPJB")))
+			goto scan_cleanup;
+		sdi->channels = g_slist_append(sdi->channels, ch);
+		if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HPJW")))
+			goto scan_cleanup;
+		sdi->channels = g_slist_append(sdi->channels, ch);
+		if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HPJR")))
+			goto scan_cleanup;
+		sdi->channels = g_slist_append(sdi->channels, ch);
+		if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HCJB")))
+			goto scan_cleanup;
+		sdi->channels = g_slist_append(sdi->channels, ch);
+		if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HCJW")))
+			goto scan_cleanup;
+		sdi->channels = g_slist_append(sdi->channels, ch);
+		if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "HCJR")))
+			goto scan_cleanup;
+		sdi->channels = g_slist_append(sdi->channels, ch);
+	}
+
+	if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "IINST")))
+		goto scan_cleanup;
+	sdi->channels = g_slist_append(sdi->channels, ch);
+
+	if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "PAPP")))
+		goto scan_cleanup;
+	sdi->channels = g_slist_append(sdi->channels, ch);
+
+	drvc->instances = g_slist_append(drvc->instances, sdi);
+	devices = g_slist_append(devices, sdi);
+
+scan_cleanup:
+	serial_close(serial);
+
+	return devices;
+}
+
+static GSList *dev_list(void)
+{
+	return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int cleanup(void)
+{
+	return std_dev_clear(di, NULL);
+}
+
+static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+
+	(void)cg;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!(devc = sdi->priv)) {
+		sr_err("sdi->priv was NULL.");
+		return SR_ERR_BUG;
+	}
+
+	switch (key) {
+	case SR_CONF_LIMIT_SAMPLES:
+		devc->limit_samples = g_variant_get_uint64(data);
+		sr_dbg("Setting sample limit to %" PRIu64 ".", devc->limit_samples);
+		break;
+	case SR_CONF_LIMIT_MSEC:
+		devc->limit_msec = g_variant_get_uint64(data);
+		sr_dbg("Setting time limit to %" PRIu64 "ms.", devc->limit_msec);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	(void)sdi;
+	(void)cg;
+
+	switch (key) {
+	case SR_CONF_SCAN_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+		break;
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct sr_serial_dev_inst *serial = sdi->conn;
+	struct dev_context *devc;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!(devc = sdi->priv)) {
+		sr_err("sdi->priv was NULL.");
+		return SR_ERR_BUG;
+	}
+
+	devc->session_cb_data = cb_data;
+
+	/*
+	 * Reset the number of samples to take. If we've already collected our
+	 * quota, but we start a new session, and don't reset this, we'll just
+	 * quit without acquiring any new samples.
+	 */
+	devc->num_samples = 0;
+	devc->start_time = g_get_monotonic_time();
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	/* Poll every 50ms, or whenever some data comes in. */
+	serial_source_add(serial, G_IO_IN, 50, teleinfo_receive_data, (void *)sdi);
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	return std_serial_dev_acquisition_stop(sdi, cb_data,
+			std_serial_dev_close, sdi->conn, LOG_PREFIX);
+}
+
+SR_PRIV struct sr_dev_driver teleinfo_driver_info = {
+	.name = "teleinfo",
+	.longname = "Teleinfo",
+	.api_version = 1,
+	.init = init,
+	.cleanup = cleanup,
+	.scan = scan,
+	.dev_list = dev_list,
+	.dev_clear = NULL,
+	.config_get = NULL,
+	.config_set = config_set,
+	.config_list = config_list,
+	.dev_open = std_serial_dev_open,
+	.dev_close = std_serial_dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/teleinfo/protocol.c b/hardware/teleinfo/protocol.c
new file mode 100644
index 0000000..a610173
--- /dev/null
+++ b/hardware/teleinfo/protocol.c
@@ -0,0 +1,237 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Aurelien Jacobs <aurel at gnuage.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include "protocol.h"
+
+#define STX  0x02
+#define ETX  0x03
+#define EOT  0x04
+#define LF   0x0A
+#define CR   0x0D
+
+static gboolean teleinfo_control_check(char *label, char *data, char control)
+{
+	int sum = 0;
+	while (*label)
+		sum += *label++;
+	sum += ' ';
+	while (*data)
+		sum += *data++;
+	return ((sum & 0x3F) + ' ') == control;
+}
+
+static gint teleinfo_channel_compare(gconstpointer a, gconstpointer b)
+{
+	const struct sr_channel *ch = a;
+	const char *name = b;
+	return strcmp(ch->name, name);
+}
+
+static struct sr_channel *teleinfo_find_channel(struct sr_dev_inst *sdi,
+                                            const char *name)
+{
+	GSList *elem = g_slist_find_custom(sdi->channels, name,
+	                                   teleinfo_channel_compare);
+	return elem ? elem->data : NULL;
+}
+
+static void teleinfo_send_value(struct sr_dev_inst *sdi, const char *channel_name,
+                                float value, int mq, int unit)
+{
+	struct dev_context *devc;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_analog analog;
+	struct sr_channel *ch;
+
+	devc = sdi->priv;
+	ch = teleinfo_find_channel(sdi, channel_name);
+
+	if (!ch || !ch->enabled)
+		return;
+
+	memset(&analog, 0, sizeof(struct sr_datafeed_analog));
+	analog.channels = g_slist_append(analog.channels, ch);
+	analog.num_samples = 1;
+	analog.mq = mq;
+	analog.unit = unit;
+	analog.data = &value;
+
+	packet.type = SR_DF_ANALOG;
+	packet.payload = &analog;
+	sr_session_send(devc->session_cb_data, &packet);
+	g_slist_free(analog.channels);
+}
+
+static void teleinfo_handle_mesurement(struct sr_dev_inst *sdi,
+                                       const char *label, const char *data,
+                                       char *optarif)
+{
+	struct dev_context *devc;
+	int v = atoi(data);
+
+	if (!sdi || !(devc = sdi->priv)) {
+		if (optarif && !strcmp(label, "OPTARIF"))
+			strcpy(optarif, data);
+		return;
+	}
+
+	if (!strcmp(label, "ADCO")) {
+		devc->num_samples++;
+	} else if (!strcmp(label, "BASE")) {
+		teleinfo_send_value(sdi, "BASE", v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
+	} else if (!strcmp(label, "HCHP")) {
+		teleinfo_send_value(sdi, "HP"  , v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
+	} else if (!strcmp(label, "HCHC")) {
+		teleinfo_send_value(sdi, "HC"  , v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
+	} else if (!strcmp(label, "EJPHN")) {
+		teleinfo_send_value(sdi, "HN"  , v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
+	} else if (!strcmp(label, "EJPHPM")) {
+		teleinfo_send_value(sdi, "HPM" , v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
+	} else if (!strcmp(label, "BBRHPJB")) {
+		teleinfo_send_value(sdi, "HPJB", v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
+	} else if (!strcmp(label, "BBRHPJW")) {
+		teleinfo_send_value(sdi, "HPJW", v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
+	} else if (!strcmp(label, "BBRHPJR")) {
+		teleinfo_send_value(sdi, "HPJR", v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
+	} else if (!strcmp(label, "BBRHCJB")) {
+		teleinfo_send_value(sdi, "HCJB", v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
+	} else if (!strcmp(label, "BBRHCJW")) {
+		teleinfo_send_value(sdi, "HCJW", v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
+	} else if (!strcmp(label, "BBRHCJR")) {
+		teleinfo_send_value(sdi, "HCJR", v, SR_MQ_POWER, SR_UNIT_WATT_HOUR);
+	} else if (!strcmp(label, "IINST")) {
+		teleinfo_send_value(sdi, "IINST", v, SR_MQ_CURRENT, SR_UNIT_AMPERE);
+	} else if (!strcmp(label, "PAPP")) {
+		teleinfo_send_value(sdi, "PAPP", v, SR_MQ_POWER, SR_UNIT_VOLT_AMPERE);
+	}
+}
+
+static gboolean teleinfo_parse_group(struct sr_dev_inst *sdi,
+                                     const uint8_t *group, char *optarif)
+{
+	char label[9], data[13], control, cr;
+	const char *str = (const char *)group;
+	if (sscanf(str, "\x0A%8s %13s %c%c", label, data, &control, &cr) != 4
+	    || cr != CR)
+		return FALSE;
+	if (!teleinfo_control_check(label, data, control))
+		return FALSE;
+	teleinfo_handle_mesurement(sdi, label, data, optarif);
+	return TRUE;
+}
+
+static const uint8_t *teleinfo_parse_data(struct sr_dev_inst *sdi,
+                                          const uint8_t *buf, int len,
+                                          char *optarif)
+{
+	const uint8_t *group_start, *group_end;
+
+	group_start = memchr(buf, LF, len);
+	if (!group_start)
+		return NULL;
+
+	group_end = memchr(group_start, CR, len - (group_start - buf));
+	if (!group_end)
+		return NULL;
+
+	teleinfo_parse_group(sdi, group_start, optarif);
+	return group_end + 1;
+}
+
+SR_PRIV int teleinfo_get_optarif(const uint8_t *buf)
+{
+	const uint8_t *ptr = buf;
+	char optarif[5] = { 0 };
+
+	while ((ptr = teleinfo_parse_data(NULL, ptr, 292-(ptr-buf), optarif)));
+	if (!strcmp(optarif, "BASE"))
+		return OPTARIF_BASE;
+	else if (!strcmp(optarif, "HC.."))
+		return OPTARIF_HC;
+	else if (!strcmp(optarif, "EJP."))
+		return OPTARIF_EJP;
+	else if (!strncmp(optarif, "BBR", 3))
+		return OPTARIF_BBR;
+	return OPTARIF_NONE;
+}
+
+SR_PRIV gboolean teleinfo_packet_valid(const uint8_t *buf)
+{
+	return !!teleinfo_get_optarif(buf);
+}
+
+SR_PRIV int teleinfo_receive_data(int fd, int revents, void *cb_data)
+{
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+	const uint8_t *ptr, *next_ptr, *end_ptr;
+	int len;
+	int64_t time;
+
+	(void)fd;
+
+	if (!(sdi = cb_data) || !(devc = sdi->priv) || revents != G_IO_IN)
+		return TRUE;
+	serial = sdi->conn;
+
+	/* Try to get as much data as the buffer can hold. */
+	len = TELEINFO_BUF_SIZE - devc->buf_len;
+	len = serial_read(serial, devc->buf + devc->buf_len, len);
+	if (len < 1) {
+		sr_err("Serial port read error: %d.", len);
+		return FALSE;
+	}
+	devc->buf_len += len;
+
+	/* Now look for packets in that data. */
+	ptr = devc->buf;
+	end_ptr = ptr + devc->buf_len;
+	while ((next_ptr = teleinfo_parse_data(sdi, ptr, end_ptr - ptr, NULL)))
+		ptr = next_ptr;
+
+	/* If we have any data left, move it to the beginning of our buffer. */
+	memmove(devc->buf, ptr, end_ptr - ptr);
+	devc->buf_len -= ptr - devc->buf;
+
+	/* If buffer is full and no valid packet was found, wipe buffer. */
+	if (devc->buf_len >= TELEINFO_BUF_SIZE) {
+		devc->buf_len = 0;
+		return FALSE;
+	}
+
+	if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
+		sr_info("Requested number of samples reached.");
+		sdi->driver->dev_acquisition_stop(sdi, devc->session_cb_data);
+		return TRUE;
+	}
+
+	if (devc->limit_msec) {
+		time = (g_get_monotonic_time() - devc->start_time) / 1000;
+		if (time > (int64_t)devc->limit_msec) {
+			sr_info("Requested time limit reached.");
+			sdi->driver->dev_acquisition_stop(sdi, devc->session_cb_data);
+			return TRUE;
+		}
+	}
+	return TRUE;
+}
diff --git a/hardware/teleinfo/protocol.h b/hardware/teleinfo/protocol.h
new file mode 100644
index 0000000..f95c50e
--- /dev/null
+++ b/hardware/teleinfo/protocol.h
@@ -0,0 +1,61 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Aurelien Jacobs <aurel at gnuage.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_TELEINFO_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_TELEINFO_PROTOCOL_H
+
+#include <stdint.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "teleinfo"
+
+enum optarif {
+	OPTARIF_NONE,
+	OPTARIF_BASE,
+	OPTARIF_HC,
+	OPTARIF_EJP,
+	OPTARIF_BBR,
+};
+
+#define TELEINFO_BUF_SIZE 256
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+	/* Acquisition settings */
+	uint64_t limit_samples;   /**< The sampling limit (in number of samples). */
+	uint64_t limit_msec;      /**< The time limit (in milliseconds). */
+	void *session_cb_data;    /**< Opaque pointer passed in by the frontend. */
+
+	/* Operational state */
+	enum optarif optarif;     /**< The device mode (which mesures are reported) */
+	uint64_t num_samples;     /**< The number of already received samples. */
+	int64_t start_time;       /**< The time at which sampling started. */
+
+	/* Temporary state across callbacks */
+	uint8_t buf[TELEINFO_BUF_SIZE];
+	int buf_len;
+};
+
+SR_PRIV gboolean teleinfo_packet_valid(const uint8_t *buf);
+SR_PRIV int teleinfo_receive_data(int fd, int revents, void *cb_data);
+SR_PRIV int teleinfo_get_optarif(const uint8_t *buf);
+
+#endif
diff --git a/hardware/tondaj-sl-814/api.c b/hardware/tondaj-sl-814/api.c
new file mode 100644
index 0000000..d112b19
--- /dev/null
+++ b/hardware/tondaj-sl-814/api.c
@@ -0,0 +1,224 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <fcntl.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+
+#define SERIALCOMM "9600/8e1"
+
+static const int32_t hwopts[] = {
+	SR_CONF_CONN,
+	SR_CONF_SERIALCOMM,
+};
+
+static const int32_t hwcaps[] = {
+	SR_CONF_SOUNDLEVELMETER,
+	SR_CONF_LIMIT_SAMPLES,
+	SR_CONF_CONTINUOUS,
+};
+
+SR_PRIV struct sr_dev_driver tondaj_sl_814_driver_info;
+static struct sr_dev_driver *di = &tondaj_sl_814_driver_info;
+
+static int init(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_dev_inst *sdi;
+	struct sr_config *src;
+	struct sr_channel *ch;
+	GSList *devices, *l;
+	const char *conn, *serialcomm;
+	struct sr_serial_dev_inst *serial;
+
+	drvc = di->priv;
+	drvc->instances = NULL;
+
+	devices = NULL;
+
+	conn = serialcomm = NULL;
+	for (l = options; l; l = l->next) {
+		if (!(src = l->data)) {
+			sr_err("Invalid option data, skipping.");
+			continue;
+		}
+		switch (src->key) {
+		case SR_CONF_CONN:
+			conn = g_variant_get_string(src->data, NULL);
+			break;
+		case SR_CONF_SERIALCOMM:
+			serialcomm = g_variant_get_string(src->data, NULL);
+			break;
+		default:
+			sr_err("Unknown option %d, skipping.", src->key);
+			break;
+		}
+	}
+	if (!conn)
+		return NULL;
+	if (!serialcomm)
+		serialcomm = SERIALCOMM;
+
+	if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, "Tondaj",
+				    "SL-814", NULL))) {
+		sr_err("Failed to create device instance.");
+		return NULL;
+	}
+
+	if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+		sr_err("Device context malloc failed.");
+		return NULL;
+	}
+
+	if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+		return NULL;
+
+	if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+		return NULL;
+
+	sdi->inst_type = SR_INST_SERIAL;
+	sdi->conn = serial;
+
+	sdi->priv = devc;
+	sdi->driver = di;
+	ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1");
+	if (!ch) {
+		sr_err("Failed to create channel.");
+		return NULL;
+	}
+	sdi->channels = g_slist_append(sdi->channels, ch);
+	drvc->instances = g_slist_append(drvc->instances, sdi);
+	devices = g_slist_append(devices, sdi);
+
+	return devices;
+}
+
+static GSList *dev_list(void)
+{
+	return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int cleanup(void)
+{
+	return std_dev_clear(di, NULL);
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+
+	(void)cg;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	devc = sdi->priv;
+
+	switch (id) {
+	case SR_CONF_LIMIT_SAMPLES:
+		devc->limit_samples = g_variant_get_uint64(data);
+		sr_dbg("Setting sample limit to %" PRIu64 ".",
+		       devc->limit_samples);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	(void)sdi;
+	(void)cg;
+
+	switch (key) {
+	case SR_CONF_SCAN_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+		break;
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi,
+				    void *cb_data)
+{
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	devc = sdi->priv;
+	devc->cb_data = cb_data;
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	/* Poll every 500ms, or whenever some data comes in. */
+	serial = sdi->conn;
+	serial_source_add(serial, G_IO_IN, 500,
+		      tondaj_sl_814_receive_data, (void *)sdi);
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	return std_serial_dev_acquisition_stop(sdi, cb_data, std_serial_dev_close,
+			sdi->conn, LOG_PREFIX);
+}
+
+SR_PRIV struct sr_dev_driver tondaj_sl_814_driver_info = {
+	.name = "tondaj-sl-814",
+	.longname = "Tondaj SL-814",
+	.api_version = 1,
+	.init = init,
+	.cleanup = cleanup,
+	.scan = scan,
+	.dev_list = dev_list,
+	.dev_clear = NULL,
+	.config_get = NULL,
+	.config_set = config_set,
+	.config_list = config_list,
+	.dev_open = std_serial_dev_open,
+	.dev_close = std_serial_dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/tondaj-sl-814/protocol.c b/hardware/tondaj-sl-814/protocol.c
new file mode 100644
index 0000000..feeec69
--- /dev/null
+++ b/hardware/tondaj-sl-814/protocol.c
@@ -0,0 +1,208 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <string.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+
+/* States */
+enum {
+	SEND_INIT,
+	GET_INIT_REPLY,
+	SEND_PACKET_REQUEST,
+	GET_PACKET,
+};
+
+static void parse_packet(const uint8_t *buf, float *floatval,
+			 struct sr_datafeed_analog *analog)
+{
+	gboolean is_a, is_fast;
+	uint16_t intval;
+	uint8_t level = 0, level_bits;
+
+	/* Byte 0 [7:7]: 0 = A, 1 = C */
+	is_a = ((buf[0] & (1 << 7)) == 0);
+
+	/* Byte 0 [6:6]: Unknown/unused? */
+
+	/* Byte 0 [5:4]: Level (00 = 40, 01 = 60, 10 = 80, 11 = 100) */
+	level_bits = (buf[0] >> 4) & 0x03;
+	if (level_bits == 0)
+		level = 40;
+	else if (level_bits == 1)
+		level = 60;
+	else if (level_bits == 2)
+		level = 80;
+	else if (level_bits == 3)
+		level = 100;
+
+	/* Byte 0 [3:3]: 0 = fast, 1 = slow */
+	is_fast = ((buf[0] & (1 << 3)) == 0);
+
+	/* Byte 0 [2:0]: value[10..8] */
+	/* Byte 1 [7:0]: value[7..0] */
+	intval = (buf[0] & 0x7) << 8;
+	intval |= buf[1];
+
+	*floatval = (float)intval;
+
+	/* The value on the display always has one digit after the comma. */
+	*floatval /= 10;
+
+	analog->mq = SR_MQ_SOUND_PRESSURE_LEVEL;
+	analog->unit = SR_UNIT_DECIBEL_SPL;
+
+	if (is_a)
+		analog->mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_A;
+	else
+		analog->mqflags |= SR_MQFLAG_SPL_FREQ_WEIGHT_C;
+
+	if (is_fast)
+		analog->mqflags |= SR_MQFLAG_SPL_TIME_WEIGHT_F;
+	else
+		analog->mqflags |= SR_MQFLAG_SPL_TIME_WEIGHT_S;
+
+	/* TODO: How to handle level? */
+	(void)level;
+}
+
+static void decode_packet(struct sr_dev_inst *sdi)
+{
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_analog analog;
+	struct dev_context *devc;
+	float floatval;
+
+	devc = sdi->priv;
+	memset(&analog, 0, sizeof(struct sr_datafeed_analog));
+
+	parse_packet(devc->buf, &floatval, &analog);
+
+	/* Send a sample packet with one analog value. */
+	analog.channels = sdi->channels;
+	analog.num_samples = 1;
+	analog.data = &floatval;
+	packet.type = SR_DF_ANALOG;
+	packet.payload = &analog;
+	sr_session_send(devc->cb_data, &packet);
+
+	devc->num_samples++;
+}
+
+int tondaj_sl_814_receive_data(int fd, int revents, void *cb_data)
+{
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+	struct sr_serial_dev_inst *serial;
+	uint8_t buf[3];
+	int ret;
+
+	(void)fd;
+	(void)revents;
+
+	sdi = cb_data;
+	serial = sdi->conn;
+	devc = sdi->priv;
+
+	/* TODO: Parts of this code need to be improved later. */
+
+	/* State machine. */
+	if (devc->state == SEND_INIT) {
+		/* On the first run, send the "init" command. */
+		buf[0] = 0x10;
+		buf[1] = 0x04;
+		buf[2] = 0x0d;
+		sr_spew("Sending init command: %02x %02x %02x.",
+			buf[0], buf[1], buf[2]);
+		if ((ret = serial_write(serial, buf, 3)) < 0) {
+			sr_err("Error sending init command: %d.", ret);
+			return FALSE;
+		}
+		devc->state = GET_INIT_REPLY;
+	} else if (devc->state == GET_INIT_REPLY) {
+		/* If we just sent the "init" command, get its reply. */
+		if ((ret = serial_read(serial, buf, 2)) < 0) {
+			sr_err("Error reading init reply: %d.", ret);
+			return FALSE;
+		}
+		sr_spew("Received init reply: %02x %02x.", buf[0], buf[1]);
+		/* Expected reply: 0x05 0x0d */
+		if (buf[0] != 0x05 || buf[1] != 0x0d) {
+			sr_err("Received incorrect init reply, retrying.");
+			devc->state = SEND_INIT;
+			return TRUE;
+		}
+		devc->state = SEND_PACKET_REQUEST;
+	} else if (devc->state == SEND_PACKET_REQUEST) {
+		/* Request a packet (send 0x30 ZZ 0x0d). */
+		buf[0] = 0x30;
+		buf[1] = 0x00; /* ZZ */
+		buf[2] = 0x0d;
+		sr_spew("Sending data request command: %02x %02x %02x.",
+			buf[0], buf[1], buf[2]);
+		if ((ret = serial_write(serial, buf, 3)) < 0) {
+			sr_err("Error sending request command: %d.", ret);
+			return FALSE;
+		}
+		devc->buflen = 0;
+		devc->state = GET_PACKET;
+	} else if (devc->state == GET_PACKET) {
+		/* Read a packet from the device. */
+		ret = serial_read(serial, devc->buf + devc->buflen,
+				  4 - devc->buflen);
+		if (ret < 0) {
+			sr_err("Error reading packet: %d.", ret);
+			return TRUE;
+		}
+
+		devc->buflen += ret;
+
+		/* Didn't receive all 4 bytes, yet. */
+		if (devc->buflen != 4)
+			return TRUE;
+
+		sr_spew("Received packet: %02x %02x %02x %02x.", devc->buf[0],
+			devc->buf[1], devc->buf[2], devc->buf[3]);
+
+		/* Expected reply: AA BB ZZ+1 0x0d */
+		if (devc->buf[2] != 0x01 || devc->buf[3] != 0x0d) {
+			sr_err("Received incorrect request reply, retrying.");
+			devc->state = SEND_PACKET_REQUEST;
+			return TRUE;
+		}
+
+		decode_packet(sdi);
+
+		devc->state = SEND_PACKET_REQUEST;
+	} else {
+		sr_err("Invalid state: %d.", devc->state);
+		return FALSE;
+	}
+
+	/* Stop acquisition if we acquired enough samples. */
+	if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
+		sr_info("Requested number of samples reached.");
+		sdi->driver->dev_acquisition_stop(sdi, cb_data);
+	}
+
+	return TRUE;
+}
diff --git a/hardware/tondaj-sl-814/protocol.h b/hardware/tondaj-sl-814/protocol.h
new file mode 100644
index 0000000..027b66d
--- /dev/null
+++ b/hardware/tondaj-sl-814/protocol.h
@@ -0,0 +1,52 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef LIBSIGROK_HARDWARE_TONDAJ_SL_814_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_TONDAJ_SL_814_PROTOCOL_H
+
+#include <stdint.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "tondaj-sl-814"
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+	/** The current sampling limit (in number of samples). */
+	uint64_t limit_samples;
+
+	/** The current sampling limit (in ms). */
+	uint64_t limit_msec;
+
+	/** Opaque pointer passed in by the frontend. */
+	void *cb_data;
+
+	/** The current number of already received samples. */
+	uint64_t num_samples;
+
+	int state;
+
+	uint8_t buf[4];
+	uint8_t buflen;
+};
+
+SR_PRIV int tondaj_sl_814_receive_data(int fd, int revents, void *cb_data);
+
+#endif
diff --git a/hardware/uni-t-dmm/api.c b/hardware/uni-t-dmm/api.c
new file mode 100644
index 0000000..ef31de0
--- /dev/null
+++ b/hardware/uni-t-dmm/api.c
@@ -0,0 +1,425 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012-2013 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+
+#define UNI_T_UT_D04_NEW "1a86.e008"
+
+static const int32_t hwopts[] = {
+	SR_CONF_CONN,
+};
+
+static const int32_t hwcaps[] = {
+	SR_CONF_MULTIMETER,
+	SR_CONF_LIMIT_SAMPLES,
+	SR_CONF_LIMIT_MSEC,
+	SR_CONF_CONTINUOUS,
+};
+
+SR_PRIV struct sr_dev_driver tecpel_dmm_8061_driver_info;
+SR_PRIV struct sr_dev_driver uni_t_ut60a_driver_info;
+SR_PRIV struct sr_dev_driver uni_t_ut60e_driver_info;
+SR_PRIV struct sr_dev_driver uni_t_ut60g_driver_info;
+SR_PRIV struct sr_dev_driver uni_t_ut61b_driver_info;
+SR_PRIV struct sr_dev_driver uni_t_ut61c_driver_info;
+SR_PRIV struct sr_dev_driver uni_t_ut61d_driver_info;
+SR_PRIV struct sr_dev_driver uni_t_ut61e_driver_info;
+SR_PRIV struct sr_dev_driver voltcraft_vc820_driver_info;
+SR_PRIV struct sr_dev_driver voltcraft_vc830_driver_info;
+SR_PRIV struct sr_dev_driver voltcraft_vc840_driver_info;
+SR_PRIV struct sr_dev_driver tenma_72_7745_driver_info;
+SR_PRIV struct sr_dev_driver tenma_72_7750_driver_info;
+
+SR_PRIV struct dmm_info udmms[] = {
+	{
+		"Tecpel", "DMM-8061", 2400,
+		FS9721_PACKET_SIZE,
+		sr_fs9721_packet_valid, sr_fs9721_parse,
+		sr_fs9721_00_temp_c,
+		&tecpel_dmm_8061_driver_info, receive_data_TECPEL_DMM_8061,
+	},
+	{
+		"UNI-T", "UT60A", 2400,
+		FS9721_PACKET_SIZE,
+		sr_fs9721_packet_valid, sr_fs9721_parse,
+		NULL,
+		&uni_t_ut60a_driver_info, receive_data_UNI_T_UT60A,
+	},
+	{
+		"UNI-T", "UT60E", 2400,
+		FS9721_PACKET_SIZE,
+		sr_fs9721_packet_valid, sr_fs9721_parse,
+		sr_fs9721_00_temp_c,
+		&uni_t_ut60e_driver_info, receive_data_UNI_T_UT60E,
+	},
+	{
+		/* The baudrate is actually 19230, see "Note 1" below. */
+		"UNI-T", "UT60G", 19200,
+		ES519XX_11B_PACKET_SIZE,
+		sr_es519xx_19200_11b_packet_valid, sr_es519xx_19200_11b_parse,
+		NULL,
+		&uni_t_ut60g_driver_info, receive_data_UNI_T_UT60G,
+	},
+	{
+		"UNI-T", "UT61B", 2400,
+		FS9922_PACKET_SIZE,
+		sr_fs9922_packet_valid, sr_fs9922_parse,
+		NULL,
+		&uni_t_ut61b_driver_info, receive_data_UNI_T_UT61B,
+	},
+	{
+		"UNI-T", "UT61C", 2400,
+		FS9922_PACKET_SIZE,
+		sr_fs9922_packet_valid, sr_fs9922_parse,
+		NULL,
+		&uni_t_ut61c_driver_info, receive_data_UNI_T_UT61C,
+	},
+	{
+		"UNI-T", "UT61D", 2400,
+		FS9922_PACKET_SIZE,
+		sr_fs9922_packet_valid, sr_fs9922_parse,
+		NULL,
+		&uni_t_ut61d_driver_info, receive_data_UNI_T_UT61D,
+	},
+	{
+		/* The baudrate is actually 19230, see "Note 1" below. */
+		"UNI-T", "UT61E", 19200,
+		ES519XX_14B_PACKET_SIZE,
+		sr_es519xx_19200_14b_packet_valid, sr_es519xx_19200_14b_parse,
+		NULL,
+		&uni_t_ut61e_driver_info, receive_data_UNI_T_UT61E,
+	},
+	{
+		"Voltcraft", "VC-820", 2400,
+		FS9721_PACKET_SIZE,
+		sr_fs9721_packet_valid, sr_fs9721_parse,
+		NULL,
+		&voltcraft_vc820_driver_info, receive_data_VOLTCRAFT_VC820,
+	},
+	{
+		/*
+		 * Note: The VC830 doesn't set the 'volt' and 'diode' bits of
+		 * the FS9922 protocol. Instead, it only sets the user-defined
+		 * bit "z1" to indicate "diode mode" and "voltage".
+		 */
+		"Voltcraft", "VC-830", 2400,
+		FS9922_PACKET_SIZE,
+		sr_fs9922_packet_valid, sr_fs9922_parse,
+		&sr_fs9922_z1_diode,
+		&voltcraft_vc830_driver_info, receive_data_VOLTCRAFT_VC830,
+	},
+	{
+		"Voltcraft", "VC-840", 2400,
+		FS9721_PACKET_SIZE,
+		sr_fs9721_packet_valid, sr_fs9721_parse,
+		sr_fs9721_00_temp_c,
+		&voltcraft_vc840_driver_info, receive_data_VOLTCRAFT_VC840,
+	},
+	{
+		"Tenma", "72-7745", 2400,
+		FS9721_PACKET_SIZE,
+		sr_fs9721_packet_valid, sr_fs9721_parse,
+		sr_fs9721_00_temp_c,
+		&tenma_72_7745_driver_info, receive_data_TENMA_72_7745,
+	},
+	{
+		/* The baudrate is actually 19230, see "Note 1" below. */
+		"Tenma", "72-7750", 19200,
+		ES519XX_11B_PACKET_SIZE,
+		sr_es519xx_19200_11b_packet_valid, sr_es519xx_19200_11b_parse,
+		NULL,
+		&tenma_72_7750_driver_info, receive_data_TENMA_72_7750,
+	},
+};
+
+/*
+ * Note 1: The actual baudrate of the Cyrustek ES519xx chip used in this DMM
+ * is 19230. However, the WCH CH9325 chip (UART to USB/HID) used in (some
+ * versions of) the UNI-T UT-D04 cable doesn't support 19230 baud. It only
+ * supports 19200, and setting an unsupported baudrate will result in the
+ * default of 2400 being used (which will not work with this DMM, of course).
+ */
+
+static int dev_clear(int dmm)
+{
+	return std_dev_clear(udmms[dmm].di, NULL);
+}
+
+static int init(struct sr_context *sr_ctx, int dmm)
+{
+	sr_dbg("Selected '%s' subdriver.", udmms[dmm].di->name);
+
+	return std_init(sr_ctx, udmms[dmm].di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options, int dmm)
+{
+	GSList *usb_devices, *devices, *l;
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+	struct drv_context *drvc;
+	struct sr_usb_dev_inst *usb;
+	struct sr_config *src;
+	struct sr_channel *ch;
+	const char *conn;
+
+	drvc = udmms[dmm].di->priv;
+
+	conn = NULL;
+	for (l = options; l; l = l->next) {
+		src = l->data;
+		switch (src->key) {
+		case SR_CONF_CONN:
+			conn = g_variant_get_string(src->data, NULL);
+			break;
+		}
+	}
+	if (!conn)
+		return NULL;
+
+	devices = NULL;
+	if (!(usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn))) {
+		g_slist_free_full(usb_devices, g_free);
+		return NULL;
+	}
+
+	for (l = usb_devices; l; l = l->next) {
+		usb = l->data;
+
+		if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+			sr_err("Device context malloc failed.");
+			return NULL;
+		}
+
+		devc->first_run = TRUE;
+
+		if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE,
+				udmms[dmm].vendor, udmms[dmm].device, NULL))) {
+			sr_err("sr_dev_inst_new returned NULL.");
+			return NULL;
+		}
+		sdi->priv = devc;
+		sdi->driver = udmms[dmm].di;
+		if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
+			return NULL;
+		sdi->channels = g_slist_append(sdi->channels, ch);
+
+		sdi->inst_type = SR_INST_USB;
+		sdi->conn = usb;
+
+		drvc->instances = g_slist_append(drvc->instances, sdi);
+		devices = g_slist_append(devices, sdi);
+	}
+
+	return devices;
+}
+
+static GSList *dev_list(int dmm)
+{
+	return ((struct drv_context *)(udmms[dmm].di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi, int dmm)
+{
+	struct drv_context *drvc;
+	struct sr_usb_dev_inst *usb;
+	int ret;
+
+	drvc = udmms[dmm].di->priv;
+	usb = sdi->conn;
+
+	if ((ret = sr_usb_open(drvc->sr_ctx->libusb_ctx, usb)) == SR_OK)
+		sdi->status = SR_ST_ACTIVE;
+
+	return ret;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+	/* TODO */
+
+	sdi->status = SR_ST_INACTIVE;
+
+	return SR_OK;
+}
+
+static int cleanup(int dmm)
+{
+	return dev_clear(dmm);
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+
+	(void)cg;
+
+	devc = sdi->priv;
+
+	switch (id) {
+	case SR_CONF_LIMIT_MSEC:
+		if (g_variant_get_uint64(data) == 0) {
+			sr_err("Time limit cannot be 0.");
+			return SR_ERR;
+		}
+		devc->limit_msec = g_variant_get_uint64(data);
+		sr_dbg("Setting time limit to %" PRIu64 "ms.",
+		       devc->limit_msec);
+		break;
+	case SR_CONF_LIMIT_SAMPLES:
+		if (g_variant_get_uint64(data) == 0) {
+			sr_err("Sample limit cannot be 0.");
+			return SR_ERR;
+		}
+		devc->limit_samples = g_variant_get_uint64(data);
+		sr_dbg("Setting sample limit to %" PRIu64 ".",
+		       devc->limit_samples);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	(void)sdi;
+	(void)cg;
+
+	switch (key) {
+	case SR_CONF_SCAN_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+		break;
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi,
+				    void *cb_data, int dmm)
+{
+	struct dev_context *devc;
+
+	devc = sdi->priv;
+
+	devc->cb_data = cb_data;
+
+	devc->starttime = g_get_monotonic_time();
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	sr_source_add(0, 0, 10 /* poll_timeout */,
+		      udmms[dmm].receive_data, (void *)sdi);
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct sr_datafeed_packet packet;
+
+	(void)sdi;
+
+	sr_dbg("Stopping acquisition.");
+
+	/* Send end packet to the session bus. */
+	sr_dbg("Sending SR_DF_END.");
+	packet.type = SR_DF_END;
+	sr_session_send(cb_data, &packet);
+
+	/* TODO? */
+	sr_source_remove(0);
+
+	return SR_OK;
+}
+
+/* Driver-specific API function wrappers */
+#define HW_INIT(X) \
+static int init_##X(struct sr_context *sr_ctx) { return init(sr_ctx, X); }
+#define HW_CLEANUP(X) \
+static int cleanup_##X(void) { return cleanup(X); }
+#define HW_SCAN(X) \
+static GSList *scan_##X(GSList *options) { return scan(options, X); }
+#define HW_DEV_LIST(X) \
+static GSList *dev_list_##X(void) { return dev_list(X); }
+#define HW_DEV_CLEAR(X) \
+static int dev_clear_##X(void) { return dev_clear(X); }
+#define HW_DEV_ACQUISITION_START(X) \
+static int dev_acquisition_start_##X(const struct sr_dev_inst *sdi, \
+void *cb_data) { return dev_acquisition_start(sdi, cb_data, X); }
+#define HW_DEV_OPEN(X) \
+static int dev_open_##X(struct sr_dev_inst *sdi) { return dev_open(sdi, X); }
+
+/* Driver structs and API function wrappers */
+#define DRV(ID, ID_UPPER, NAME, LONGNAME) \
+HW_INIT(ID_UPPER) \
+HW_CLEANUP(ID_UPPER) \
+HW_SCAN(ID_UPPER) \
+HW_DEV_LIST(ID_UPPER) \
+HW_DEV_CLEAR(ID_UPPER) \
+HW_DEV_ACQUISITION_START(ID_UPPER) \
+HW_DEV_OPEN(ID_UPPER) \
+SR_PRIV struct sr_dev_driver ID##_driver_info = { \
+	.name = NAME, \
+	.longname = LONGNAME, \
+	.api_version = 1, \
+	.init = init_##ID_UPPER, \
+	.cleanup = cleanup_##ID_UPPER, \
+	.scan = scan_##ID_UPPER, \
+	.dev_list = dev_list_##ID_UPPER, \
+	.dev_clear = dev_clear_##ID_UPPER, \
+	.config_get = NULL, \
+	.config_set = config_set, \
+	.config_list = config_list, \
+	.dev_open = dev_open_##ID_UPPER, \
+	.dev_close = dev_close, \
+	.dev_acquisition_start = dev_acquisition_start_##ID_UPPER, \
+	.dev_acquisition_stop = dev_acquisition_stop, \
+	.priv = NULL, \
+};
+
+DRV(tecpel_dmm_8061, TECPEL_DMM_8061, "tecpel-dmm-8061", "Tecpel DMM-8061")
+DRV(uni_t_ut60a, UNI_T_UT60A, "uni-t-ut60a", "UNI-T UT60A")
+DRV(uni_t_ut60e, UNI_T_UT60E, "uni-t-ut60e", "UNI-T UT60E")
+DRV(uni_t_ut60g, UNI_T_UT60G, "uni-t-ut60g", "UNI-T UT60G")
+DRV(uni_t_ut61b, UNI_T_UT61B, "uni-t-ut61b", "UNI-T UT61B")
+DRV(uni_t_ut61c, UNI_T_UT61C, "uni-t-ut61c", "UNI-T UT61C")
+DRV(uni_t_ut61d, UNI_T_UT61D, "uni-t-ut61d", "UNI-T UT61D")
+DRV(uni_t_ut61e, UNI_T_UT61E, "uni-t-ut61e", "UNI-T UT61E")
+DRV(voltcraft_vc820, VOLTCRAFT_VC820, "voltcraft-vc820", "Voltcraft VC-820")
+DRV(voltcraft_vc830, VOLTCRAFT_VC830, "voltcraft-vc830", "Voltcraft VC-830")
+DRV(voltcraft_vc840, VOLTCRAFT_VC840, "voltcraft-vc840", "Voltcraft VC-840")
+DRV(tenma_72_7745, TENMA_72_7745, "tenma-72-7745", "Tenma 72-7745")
+DRV(tenma_72_7750, TENMA_72_7750, "tenma-72-7750", "Tenma 72-7750")
diff --git a/hardware/uni-t-dmm/protocol.c b/hardware/uni-t-dmm/protocol.c
new file mode 100644
index 0000000..ca2568e
--- /dev/null
+++ b/hardware/uni-t-dmm/protocol.c
@@ -0,0 +1,315 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012-2013 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <string.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+
+extern struct dmm_info udmms[];
+
+/*
+ * Driver for various UNI-T multimeters (and rebranded ones).
+ *
+ * Most UNI-T DMMs can be used with two (three) different PC interface cables:
+ *  - The UT-D04 USB/HID cable, old version with Hoitek HE2325U chip.
+ *  - The UT-D04 USB/HID cable, new version with WCH CH9325 chip.
+ *  - The UT-D02 RS232 cable.
+ *
+ * This driver is meant to support all USB/HID cables, and various DMMs that
+ * can be attached to a PC via these cables. Currently only the UT-D04 cable
+ * (new version) is supported/tested.
+ * The UT-D02 RS232 cable is handled by the 'serial-dmm' driver.
+ *
+ * The data for one DMM packet (e.g. 14 bytes if the respective DMM uses a
+ * Fortune Semiconductor FS9922-DMM4 chip) is spread across multiple
+ * 8-byte chunks.
+ *
+ * An 8-byte chunk looks like this:
+ *  - Byte 0: 0xfz, where z is the number of actual data bytes in this chunk.
+ *  - Bytes 1-7: z data bytes, the rest of the bytes should be ignored.
+ *
+ * Example:
+ *  f0 00 00 00 00 00 00 00 (no data bytes)
+ *  f2 55 77 00 00 00 00 00 (2 data bytes, 0x55 and 0x77)
+ *  f1 d1 00 00 00 00 00 00 (1 data byte, 0xd1)
+ */
+
+static void decode_packet(struct sr_dev_inst *sdi, int dmm, const uint8_t *buf,
+			  void *info)
+{
+	struct dev_context *devc;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_analog analog;
+	float floatval;
+	int ret;
+
+	devc = sdi->priv;
+	memset(&analog, 0, sizeof(struct sr_datafeed_analog));
+
+	/* Parse the protocol packet. */
+	ret = udmms[dmm].packet_parse(buf, &floatval, &analog, info);
+	if (ret != SR_OK) {
+		sr_dbg("Invalid DMM packet, ignoring.");
+		return;
+	}
+
+	/* If this DMM needs additional handling, call the resp. function. */
+	if (udmms[dmm].dmm_details)
+		udmms[dmm].dmm_details(&analog, info);
+
+	/* Send a sample packet with one analog value. */
+	analog.channels = sdi->channels;
+	analog.num_samples = 1;
+	analog.data = &floatval;
+	packet.type = SR_DF_ANALOG;
+	packet.payload = &analog;
+	sr_session_send(devc->cb_data, &packet);
+
+	/* Increase sample count. */
+	devc->num_samples++;
+}
+
+static int hid_chip_init(struct sr_dev_inst *sdi, uint16_t baudrate)
+{
+	int ret;
+	uint8_t buf[5];
+	struct sr_usb_dev_inst *usb;
+
+	usb = sdi->conn;
+	
+	/* Detach kernel drivers which grabbed this device (if any). */
+	if (libusb_kernel_driver_active(usb->devhdl, 0) == 1) {
+		ret = libusb_detach_kernel_driver(usb->devhdl, 0);
+		if (ret < 0) {
+			sr_err("Failed to detach kernel driver: %s.",
+			       libusb_error_name(ret));
+			return SR_ERR;
+		}
+		sr_dbg("Successfully detached kernel driver.");
+	} else {
+		sr_dbg("No need to detach a kernel driver.");
+	}
+
+	/* Claim interface 0. */
+	if ((ret = libusb_claim_interface(usb->devhdl, 0)) < 0) {
+		sr_err("Failed to claim interface 0: %s.",
+		       libusb_error_name(ret));
+		return SR_ERR;
+	}
+	sr_dbg("Successfully claimed interface 0.");
+
+	/* Set data for the HID feature report (e.g. baudrate). */
+	buf[0] = baudrate & 0xff;        /* Baudrate, LSB */
+	buf[1] = (baudrate >> 8) & 0xff; /* Baudrate, MSB */
+	buf[2] = 0x00;                   /* Unknown/unused (?) */
+	buf[3] = 0x00;                   /* Unknown/unused (?) */
+	buf[4] = 0x03;                   /* Unknown, always 0x03. */
+
+	/* Send HID feature report to setup the baudrate/chip. */
+	sr_dbg("Sending initial HID feature report.");
+	sr_spew("HID init = 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x (%d baud)",
+		buf[0], buf[1], buf[2], buf[3], buf[4], baudrate);
+	ret = libusb_control_transfer(
+		usb->devhdl, /* libusb device handle */
+		LIBUSB_REQUEST_TYPE_CLASS |
+		LIBUSB_RECIPIENT_INTERFACE |
+		LIBUSB_ENDPOINT_OUT,
+		9, /* bRequest: HID set_report */
+		0x300, /* wValue: HID feature, report number 0 */
+		0, /* wIndex: interface 0 */
+		(unsigned char *)&buf, /* payload buffer */
+		5, /* wLength: 5 bytes payload */
+		1000 /* timeout (ms) */);
+
+	if (ret < 0) {
+		sr_err("HID feature report error: %s.", libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	if (ret != 5) {
+		/* TODO: Handle better by also sending the remaining bytes. */
+		sr_err("Short packet: sent %d/5 bytes.", ret);
+		return SR_ERR;
+	}
+
+	sr_dbg("Successfully sent initial HID feature report.");
+
+	return SR_OK;
+}
+
+static void log_8byte_chunk(const uint8_t *buf)
+{
+	sr_spew("8-byte chunk: %02x %02x %02x %02x %02x %02x %02x %02x "
+		"(%d data bytes)", buf[0], buf[1], buf[2], buf[3],
+		buf[4], buf[5], buf[6], buf[7], (buf[0] & 0x0f));
+}
+
+static void log_dmm_packet(const uint8_t *buf)
+{
+	sr_dbg("DMM packet:   %02x %02x %02x %02x %02x %02x %02x"
+	       " %02x %02x %02x %02x %02x %02x %02x",
+	       buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6],
+	       buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13]);
+}
+
+static int get_and_handle_data(struct sr_dev_inst *sdi, int dmm, void *info)
+{
+	struct dev_context *devc;
+	uint8_t buf[CHUNK_SIZE], *pbuf;
+	int i, ret, len, num_databytes_in_chunk;
+	struct sr_usb_dev_inst *usb;
+
+	devc = sdi->priv;
+	usb = sdi->conn;
+	pbuf = devc->protocol_buf;
+
+	/* On the first run, we need to init the HID chip. */
+	if (devc->first_run) {
+		if ((ret = hid_chip_init(sdi, udmms[dmm].baudrate)) != SR_OK) {
+			sr_err("HID chip init failed: %d.", ret);
+			return SR_ERR;
+		}
+		memset(pbuf, 0x00, DMM_BUFSIZE);
+		devc->first_run = FALSE;
+	}
+
+	memset(&buf, 0x00, CHUNK_SIZE);
+
+	/* Get data from EP2 using an interrupt transfer. */
+	ret = libusb_interrupt_transfer(
+		usb->devhdl, /* libusb device handle */
+		LIBUSB_ENDPOINT_IN | 2, /* EP2, IN */
+		(unsigned char *)&buf, /* receive buffer */
+		CHUNK_SIZE, /* wLength */
+		&len, /* actually received byte count */
+		1000 /* timeout (ms) */);
+
+	if (ret < 0) {
+		sr_err("USB receive error: %s.", libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	if (len != CHUNK_SIZE) {
+		sr_err("Short packet: received %d/%d bytes.", len, CHUNK_SIZE);
+		/* TODO: Print the bytes? */
+		return SR_ERR;
+	}
+
+	log_8byte_chunk((const uint8_t *)&buf);
+
+	/* If there are no data bytes just return (without error). */
+	if (buf[0] == 0xf0)
+		return SR_OK;
+
+	devc->bufoffset = 0;
+
+	/*
+	 * Append the 1-7 data bytes of this chunk to pbuf.
+	 *
+	 * Special case:
+	 * DMMs with Cyrustek ES51922 chip need serial settings of
+	 * 19230/7o1. The WCH CH9325 UART to USB/HID chip used in (some
+	 * versions of) the UNI-T UT-D04 cable however, will also send
+	 * the parity bit to the host in the 8-byte data chunks. This bit
+	 * is encoded in bit 7 of each of the 1-7 data bytes and must thus
+	 * be removed in order for the actual ES51922 protocol parser to
+	 * work properly.
+	 */
+	num_databytes_in_chunk = buf[0] & 0x0f;
+	for (i = 0; i < num_databytes_in_chunk; i++, devc->buflen++) {
+		pbuf[devc->buflen] = buf[1 + i];
+		if (udmms[dmm].packet_parse == sr_es519xx_19200_14b_parse)
+			pbuf[devc->buflen] &= ~(1 << 7);
+	}
+
+	/* Now look for packets in that data. */
+	while ((devc->buflen - devc->bufoffset) >= udmms[dmm].packet_size) {
+		if (udmms[dmm].packet_valid(pbuf + devc->bufoffset)) {
+			log_dmm_packet(pbuf + devc->bufoffset);
+			decode_packet(sdi, dmm, pbuf + devc->bufoffset, info);
+			devc->bufoffset += udmms[dmm].packet_size;
+		} else {
+			devc->bufoffset++;
+		}
+	}
+
+	/* Move remaining bytes to beginning of buffer. */
+	for (i = 0; i < devc->buflen - devc->bufoffset; i++)
+		pbuf[i] = pbuf[devc->bufoffset + i];
+	devc->buflen -= devc->bufoffset;
+
+	return SR_OK;
+}
+
+static int receive_data(int fd, int revents, int dmm, void *info, void *cb_data)
+{
+	int ret;
+	struct sr_dev_inst *sdi;
+	struct dev_context *devc;
+	int64_t time_ms;
+
+	(void)fd;
+	(void)revents;
+
+	sdi = cb_data;
+	devc = sdi->priv;
+
+	if ((ret = get_and_handle_data(sdi, dmm, info)) != SR_OK)
+		return FALSE;
+
+	/* Abort acquisition if we acquired enough samples. */
+	if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
+		sr_info("Requested number of samples reached.");
+		sdi->driver->dev_acquisition_stop(sdi, cb_data);
+	}
+
+	if (devc->limit_msec) {
+		time_ms = (g_get_monotonic_time() - devc->starttime) / 1000;
+		if (time_ms > (int64_t)devc->limit_msec) {
+			sr_info("Requested time limit reached.");
+			sdi->driver->dev_acquisition_stop(sdi, cb_data);
+			return TRUE;
+		}
+	}
+
+	return TRUE;
+}
+
+#define RECEIVE_DATA(ID_UPPER, DMM_DRIVER) \
+SR_PRIV int receive_data_##ID_UPPER(int fd, int revents, void *cb_data) { \
+	struct DMM_DRIVER##_info info; \
+	return receive_data(fd, revents, ID_UPPER, &info, cb_data); }
+
+/* Driver-specific receive_data() wrappers */
+RECEIVE_DATA(TECPEL_DMM_8061, fs9721)
+RECEIVE_DATA(UNI_T_UT60A, fs9721)
+RECEIVE_DATA(UNI_T_UT60E, fs9721)
+RECEIVE_DATA(UNI_T_UT60G, es519xx)
+RECEIVE_DATA(UNI_T_UT61B, fs9922)
+RECEIVE_DATA(UNI_T_UT61C, fs9922)
+RECEIVE_DATA(UNI_T_UT61D, fs9922)
+RECEIVE_DATA(UNI_T_UT61E, es519xx)
+RECEIVE_DATA(VOLTCRAFT_VC820, fs9721)
+RECEIVE_DATA(VOLTCRAFT_VC830, fs9922)
+RECEIVE_DATA(VOLTCRAFT_VC840, fs9721)
+RECEIVE_DATA(TENMA_72_7745, es519xx)
+RECEIVE_DATA(TENMA_72_7750, es519xx)
diff --git a/hardware/uni-t-dmm/protocol.h b/hardware/uni-t-dmm/protocol.h
new file mode 100644
index 0000000..08fb537
--- /dev/null
+++ b/hardware/uni-t-dmm/protocol.h
@@ -0,0 +1,102 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012-2013 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef LIBSIGROK_HARDWARE_UNI_T_DMM_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_UNI_T_DMM_PROTOCOL_H
+
+#include <stdint.h>
+#include <glib.h>
+#include <libusb.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "uni-t-dmm"
+
+enum {
+	TECPEL_DMM_8061,
+	UNI_T_UT60A,
+	UNI_T_UT60E,
+	UNI_T_UT60G,
+	UNI_T_UT61B,
+	UNI_T_UT61C,
+	UNI_T_UT61D,
+	UNI_T_UT61E,
+	VOLTCRAFT_VC820,
+	VOLTCRAFT_VC830,
+	VOLTCRAFT_VC840,
+	TENMA_72_7745,
+	TENMA_72_7750,
+};
+
+struct dmm_info {
+	char *vendor;
+	char *device;
+	uint32_t baudrate;
+	int packet_size;
+	gboolean (*packet_valid)(const uint8_t *);
+	int (*packet_parse)(const uint8_t *, float *,
+			    struct sr_datafeed_analog *, void *);
+	void (*dmm_details)(struct sr_datafeed_analog *, void *);
+	struct sr_dev_driver *di;
+	int (*receive_data)(int, int, void *);
+};
+
+#define CHUNK_SIZE		8
+
+#define DMM_BUFSIZE		256
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+	/** The current sampling limit (in number of samples). */
+	uint64_t limit_samples;
+
+	/** The current sampling limit (in ms). */
+	uint64_t limit_msec;
+
+	/** Opaque pointer passed in by the frontend. */
+	void *cb_data;
+
+	/** The current number of already received samples. */
+	uint64_t num_samples;
+
+	int64_t starttime;
+
+	gboolean first_run;
+
+	uint8_t protocol_buf[DMM_BUFSIZE];
+	uint8_t bufoffset;
+	uint8_t buflen;
+};
+
+SR_PRIV int receive_data_TECPEL_DMM_8061(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_UNI_T_UT60A(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_UNI_T_UT60E(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_UNI_T_UT60G(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_UNI_T_UT61B(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_UNI_T_UT61C(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_UNI_T_UT61D(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_UNI_T_UT61E(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_VOLTCRAFT_VC820(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_VOLTCRAFT_VC830(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_VOLTCRAFT_VC840(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_TENMA_72_7745(int fd, int revents, void *cb_data);
+SR_PRIV int receive_data_TENMA_72_7750(int fd, int revents, void *cb_data);
+
+#endif
diff --git a/hardware/uni-t-ut32x/api.c b/hardware/uni-t-ut32x/api.c
new file mode 100644
index 0000000..b38d2fb
--- /dev/null
+++ b/hardware/uni-t-ut32x/api.c
@@ -0,0 +1,384 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "protocol.h"
+
+#include <string.h>
+
+static const int32_t hwcaps[] = {
+	SR_CONF_THERMOMETER,
+	SR_CONF_LIMIT_SAMPLES,
+	SR_CONF_CONTINUOUS,
+	SR_CONF_DATA_SOURCE,
+};
+
+static char *channels[] = {
+	"T1",
+	"T2",
+	"T1-T2",
+};
+
+static const char *data_sources[] = {
+	"Live",
+	"Memory",
+};
+
+SR_PRIV struct sr_dev_driver uni_t_ut32x_driver_info;
+static struct sr_dev_driver *di = &uni_t_ut32x_driver_info;
+
+
+static int init(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_dev_inst *sdi;
+	struct sr_channel *ch;
+	struct sr_config *src;
+	GSList *usb_devices, *devices, *l;
+	int i;
+	const char *conn;
+
+	drvc = di->priv;
+	drvc->instances = NULL;
+
+	conn = NULL;
+	for (l = options; l; l = l->next) {
+		src = l->data;
+		switch (src->key) {
+		case SR_CONF_CONN:
+			conn = g_variant_get_string(src->data, NULL);
+			break;
+		}
+	}
+	if (!conn)
+		return NULL;
+
+	devices = NULL;
+	if ((usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, conn))) {
+		/* We have a list of sr_usb_dev_inst matching the connection
+		 * string. Wrap them in sr_dev_inst and we're done. */
+		for (l = usb_devices; l; l = l->next) {
+			if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, VENDOR,
+					MODEL, NULL)))
+				return NULL;
+			sdi->driver = di;
+			sdi->inst_type = SR_INST_USB;
+			sdi->conn = l->data;
+			for (i = 0; i < 3; i++) {
+				if (!(ch = sr_channel_new(i, SR_CHANNEL_ANALOG, TRUE,
+						channels[i]))) {
+					sr_dbg("Channel malloc failed.");
+					return NULL;
+				}
+				sdi->channels = g_slist_append(sdi->channels, ch);
+			}
+
+			if (!(devc = g_try_malloc(sizeof(struct dev_context)))) {
+				sr_dbg("Device context malloc failed.");
+				return NULL;
+			}
+			sdi->priv = devc;
+			devc->limit_samples = 0;
+			devc->data_source = DEFAULT_DATA_SOURCE;
+			drvc->instances = g_slist_append(drvc->instances, sdi);
+			devices = g_slist_append(devices, sdi);
+		}
+		g_slist_free(usb_devices);
+	} else
+		g_slist_free_full(usb_devices, g_free);
+
+	return devices;
+}
+
+static GSList *dev_list(void)
+{
+	return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+	struct drv_context *drvc;
+	struct sr_usb_dev_inst *usb;
+	int ret;
+
+	if (!(drvc = di->priv)) {
+		sr_err("Driver was not initialized.");
+		return SR_ERR;
+	}
+
+	usb = sdi->conn;
+
+	if (sr_usb_open(drvc->sr_ctx->libusb_ctx, usb) != SR_OK)
+		return SR_ERR;
+
+/*
+ * The libusbx 1.0.9 darwin backend is broken: it can report a kernel
+ * driver being active, but detaching it always returns an error.
+ */
+#if !defined(__APPLE__)
+	if (libusb_kernel_driver_active(usb->devhdl, USB_INTERFACE) == 1) {
+		if ((ret = libusb_detach_kernel_driver(usb->devhdl, USB_INTERFACE)) < 0) {
+			sr_err("failed to detach kernel driver: %s",
+					libusb_error_name(ret));
+			return SR_ERR;
+		}
+	}
+#endif
+
+	if ((ret = libusb_set_configuration(usb->devhdl, USB_CONFIGURATION))) {
+		sr_err("Failed to set configuration: %s.", libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	if ((ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE))) {
+		sr_err("Failed to claim interface: %s.", libusb_error_name(ret));
+		return SR_ERR;
+	}
+	sdi->status = SR_ST_ACTIVE;
+
+	return ret;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+	struct sr_usb_dev_inst *usb;
+
+	if (!di->priv) {
+		sr_err("Driver was not initialized.");
+		return SR_ERR;
+	}
+
+	usb = sdi->conn;
+	if (!usb->devhdl)
+		/*  Nothing to do. */
+		return SR_OK;
+
+	libusb_release_interface(usb->devhdl, USB_INTERFACE);
+	libusb_close(usb->devhdl);
+	usb->devhdl = NULL;
+	sdi->status = SR_ST_INACTIVE;
+
+	return SR_OK;
+}
+
+static int cleanup(void)
+{
+	int ret;
+	struct drv_context *drvc;
+
+	if (!(drvc = di->priv))
+		/* Can get called on an unused driver, doesn't matter. */
+		return SR_OK;
+
+
+	ret = std_dev_clear(di, NULL);
+	g_free(drvc);
+	di->priv = NULL;
+
+	return ret;
+}
+
+static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+
+	(void)cg;
+
+	devc = sdi->priv;
+	switch (key) {
+	case SR_CONF_LIMIT_SAMPLES:
+		*data = g_variant_new_uint64(devc->limit_samples);
+		break;
+	case SR_CONF_DATA_SOURCE:
+		if (devc->data_source == DATA_SOURCE_LIVE)
+			*data = g_variant_new_string("Live");
+		else
+			*data = g_variant_new_string("Memory");
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	int ret;
+	const char *tmp_str;
+
+	(void)cg;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!di->priv) {
+		sr_err("Driver was not initialized.");
+		return SR_ERR;
+	}
+
+	devc = sdi->priv;
+	ret = SR_OK;
+	switch (key) {
+	case SR_CONF_LIMIT_SAMPLES:
+		devc->limit_samples = g_variant_get_uint64(data);
+		sr_dbg("Setting sample limit to %" PRIu64 ".",
+		       devc->limit_samples);
+		break;
+	case SR_CONF_DATA_SOURCE:
+		tmp_str = g_variant_get_string(data, NULL);
+		if (!strcmp(tmp_str, "Live"))
+			devc->data_source = DATA_SOURCE_LIVE;
+		else if (!strcmp(tmp_str, "Memory"))
+			devc->data_source = DATA_SOURCE_MEMORY;
+		else
+			return SR_ERR;
+		break;
+	default:
+		ret = SR_ERR_NA;
+	}
+
+	return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+
+	(void)sdi;
+	(void)cg;
+
+	switch (key) {
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+		break;
+	case SR_CONF_DATA_SOURCE:
+		*data = g_variant_new_strv(data_sources, ARRAY_SIZE(data_sources));
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi,
+				    void *cb_data)
+{
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_usb_dev_inst *usb;
+	int len, ret;
+	unsigned char cmd[2];
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	drvc = di->priv;
+	devc = sdi->priv;
+	usb = sdi->conn;
+
+	devc->cb_data = cb_data;
+	devc->num_samples = 0;
+	devc->packet_len = 0;
+
+	/* Configure serial port parameters on USB-UART interface
+	 * chip inside the device (just baudrate 2400 actually). */
+	cmd[0] = 0x09;
+	cmd[1] = 0x60;
+	ret = libusb_control_transfer(usb->devhdl, 0x21, 0x09, 0x0300, 0x00,
+			cmd, 2, 5);
+	if (ret != 2) {
+		sr_dbg("Failed to configure CH9325: %s", libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	if (!(devc->xfer = libusb_alloc_transfer(0)))
+		return SR_ERR;
+
+	/* Length of payload to follow. */
+	cmd[0] = 0x01;
+	if (devc->data_source == DATA_SOURCE_LIVE)
+		cmd[1] = CMD_GET_LIVE;
+	else
+		cmd[1] = CMD_GET_STORED;
+
+	ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, cmd, 2, &len, 5);
+	if (ret != 0 || len != 2) {
+		sr_dbg("Failed to start acquisition: %s", libusb_error_name(ret));
+		libusb_free_transfer(devc->xfer);
+		return SR_ERR;
+	}
+
+	libusb_fill_bulk_transfer(devc->xfer, usb->devhdl, EP_IN, devc->buf,
+			8, uni_t_ut32x_receive_transfer, (void *)sdi, 15);
+	if (libusb_submit_transfer(devc->xfer) != 0) {
+		libusb_free_transfer(devc->xfer);
+		return SR_ERR;
+	}
+
+	usb_source_add(drvc->sr_ctx, 10, uni_t_ut32x_handle_events, (void *)sdi);
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+
+	(void)cb_data;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	/* Signal USB transfer handler to clean up and stop. */
+	sdi->status = SR_ST_STOPPING;
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver uni_t_ut32x_driver_info = {
+	.name = "uni-t-ut32x",
+	.longname = "UNI-T UT32x",
+	.api_version = 1,
+	.init = init,
+	.cleanup = cleanup,
+	.scan = scan,
+	.dev_list = dev_list,
+	.dev_clear = NULL,
+	.config_get = config_get,
+	.config_set = config_set,
+	.config_list = config_list,
+	.dev_open = dev_open,
+	.dev_close = dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/uni-t-ut32x/protocol.c b/hardware/uni-t-ut32x/protocol.c
new file mode 100644
index 0000000..863f9fa
--- /dev/null
+++ b/hardware/uni-t-ut32x/protocol.c
@@ -0,0 +1,240 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "protocol.h"
+
+#include <string.h>
+#include <math.h>
+
+extern struct sr_dev_driver uni_t_ut32x_driver_info;
+static struct sr_dev_driver *di = &uni_t_ut32x_driver_info;
+
+static float parse_temperature(unsigned char *buf)
+{
+	float temp;
+	int i;
+	gboolean negative;
+
+	negative = FALSE;
+	temp = 0.0;
+	for (i = 0; i < 4; i++) {
+		if (buf[i] == 0x3a)
+			continue;
+		if (buf[i] == 0x3b) {
+			if (negative) {
+				sr_dbg("Double negative sign!");
+				return NAN;
+			} else {
+				negative = TRUE;
+				continue;
+			}
+		}
+		if (buf[i] < 0x30 || buf[i] > 0x39) {
+			sr_dbg("Invalid digit '%.2x'!", buf[i]);
+			return NAN;
+		}
+		temp *= 10;
+		temp += (buf[i] - 0x30);
+	}
+	temp /= 10;
+	if (negative)
+		temp = -temp;
+
+	return temp;
+}
+
+static void process_packet(struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_analog analog;
+	GString *spew;
+	float temp;
+	int i;
+	gboolean is_valid;
+
+	devc = sdi->priv;
+	sr_dbg("Received full 19-byte packet.");
+	if (sr_log_loglevel_get() >= SR_LOG_SPEW) {
+		spew = g_string_sized_new(60);
+		for (i = 0; i < devc->packet_len; i++)
+			g_string_append_printf(spew, "%.2x ", devc->packet[i]);
+		sr_spew("%s", spew->str);
+		g_string_free(spew, TRUE);
+	}
+
+	is_valid = TRUE;
+	if (devc->packet[1] == 0x3b && devc->packet[2] == 0x3b
+			&& devc->packet[3] == 0x3b && devc->packet[4] == 0x3b)
+		/* No measurement: missing channel, empty storage location, ... */
+		is_valid = FALSE;
+
+	temp = parse_temperature(devc->packet + 1);
+	if (isnan(temp))
+		is_valid = FALSE;
+
+	if (is_valid) {
+		memset(&analog, 0, sizeof(struct sr_datafeed_analog));
+		analog.mq = SR_MQ_TEMPERATURE;
+		analog.mqflags = 0;
+		switch (devc->packet[5] - 0x30) {
+		case 1:
+			analog.unit = SR_UNIT_CELSIUS;
+			break;
+		case 2:
+			analog.unit = SR_UNIT_FAHRENHEIT;
+			break;
+		case 3:
+			analog.unit = SR_UNIT_KELVIN;
+			break;
+		default:
+			/* We can still pass on the measurement, whatever it is. */
+			sr_dbg("Unknown unit 0x%.2x.", devc->packet[5]);
+		}
+		switch (devc->packet[13] - 0x30) {
+		case 0:
+			/* Channel T1. */
+			analog.channels = g_slist_append(NULL, g_slist_nth_data(sdi->channels, 0));
+			break;
+		case 1:
+			/* Channel T2. */
+			analog.channels = g_slist_append(NULL, g_slist_nth_data(sdi->channels, 1));
+			break;
+		case 2:
+		case 3:
+			/* Channel T1-T2. */
+			analog.channels = g_slist_append(NULL, g_slist_nth_data(sdi->channels, 2));
+			analog.mqflags |= SR_MQFLAG_RELATIVE;
+			break;
+		default:
+			sr_err("Unknown channel 0x%.2x.", devc->packet[13]);
+			is_valid = FALSE;
+		}
+		if (is_valid) {
+			analog.num_samples = 1;
+			analog.data = &temp;
+			packet.type = SR_DF_ANALOG;
+			packet.payload = &analog;
+			sr_session_send(devc->cb_data, &packet);
+			g_slist_free(analog.channels);
+		}
+	}
+
+	/* We count packets even if the temperature was invalid. This way
+	 * a sample limit on "Memory" data source still works: unused
+	 * memory slots come through as "----" measurements. */
+	devc->num_samples++;
+	if (devc->limit_samples && devc->num_samples >= devc->limit_samples) {
+		sdi->driver->dev_acquisition_stop((struct sr_dev_inst *)sdi,
+				devc->cb_data);
+	}
+
+}
+
+SR_PRIV void uni_t_ut32x_receive_transfer(struct libusb_transfer *transfer)
+{
+	struct dev_context *devc;
+	struct sr_dev_inst *sdi;
+	int hid_payload_len, ret;
+
+	sdi = transfer->user_data;
+	devc = sdi->priv;
+	if (transfer->actual_length == 8) {
+		/* CH9325 encodes length in low nibble of first byte, with
+		 * bytes 1-7 being the (padded) payload. */
+		hid_payload_len = transfer->buffer[0] & 0x0f;
+		memcpy(devc->packet + devc->packet_len, transfer->buffer + 1,
+				hid_payload_len);
+		devc->packet_len += hid_payload_len;
+		if (devc->packet_len >= 2
+				&& devc->packet[devc->packet_len - 2] == 0x0d
+				&& devc->packet[devc->packet_len - 1] == 0x0a) {
+			/* Got end of packet, but do we have a complete packet? */
+			if (devc->packet_len == 19)
+				process_packet(sdi);
+			/* Either way, done with it. */
+			devc->packet_len = 0;
+		} else if (devc->packet_len > 19) {
+			/* Guard against garbage from the device overrunning
+			 * our packet buffer. */
+			sr_dbg("Buffer overrun!");
+			devc->packet_len = 0;
+		}
+	}
+
+	/* Get the next transfer (unless we're shutting down). */
+	if (sdi->status != SR_ST_STOPPING) {
+		if ((ret = libusb_submit_transfer(devc->xfer)) != 0) {
+			sr_dbg("Failed to resubmit transfer: %s", libusb_error_name(ret));
+			sdi->status = SR_ST_STOPPING;
+			libusb_free_transfer(devc->xfer);
+		}
+	} else
+		libusb_free_transfer(devc->xfer);
+
+}
+
+SR_PRIV int uni_t_ut32x_handle_events(int fd, int revents, void *cb_data)
+{
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_dev_inst *sdi;
+	struct sr_datafeed_packet packet;
+	struct sr_usb_dev_inst *usb;
+	struct timeval tv;
+	int len, ret;
+	unsigned char cmd[2];
+
+	(void)fd;
+	(void)revents;
+
+	drvc = di->priv;
+
+	if (!(sdi = cb_data))
+		return TRUE;
+
+	if (!(devc = sdi->priv))
+		return TRUE;
+
+	memset(&tv, 0, sizeof(struct timeval));
+	libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx, &tv,
+			NULL);
+
+	if (sdi->status == SR_ST_STOPPING) {
+		usb_source_remove(drvc->sr_ctx);
+		packet.type = SR_DF_END;
+		sr_session_send(cb_data, &packet);
+
+		/* Tell the device to stop sending USB packets. */
+		usb = sdi->conn;
+		cmd[0] = 0x01;
+		cmd[1] = CMD_STOP;
+		ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, cmd, 2, &len, 5);
+		if (ret != 0 || len != 2) {
+			/* Warning only, doesn't matter. */
+			sr_dbg("Failed to send stop command: %s", libusb_error_name(ret));
+		}
+
+		sdi->status = SR_ST_ACTIVE;
+		return TRUE;
+	}
+
+	return TRUE;
+}
+
diff --git a/hardware/uni-t-ut32x/protocol.h b/hardware/uni-t-ut32x/protocol.h
new file mode 100644
index 0000000..8513117
--- /dev/null
+++ b/hardware/uni-t-ut32x/protocol.h
@@ -0,0 +1,71 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_UNI_T_UT32X_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_UNI_T_UT32X_PROTOCOL_H
+
+#include <stdint.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "uni-t-ut32x"
+
+#define DEFAULT_DATA_SOURCE DATA_SOURCE_LIVE
+#define USB_CONN "1a86.e008"
+#define VENDOR "UNI-T"
+#define MODEL "UT32x"
+#define USB_INTERFACE 0
+#define USB_CONFIGURATION 1
+
+#define EP_IN 0x80 | 2
+#define EP_OUT 2
+
+enum {
+    DATA_SOURCE_LIVE,
+	DATA_SOURCE_MEMORY,
+};
+
+enum {
+	CMD_GET_LIVE = 1,
+	CMD_STOP = 2,
+	CMD_GET_STORED = 7,
+};
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+	/* Acquisition settings */
+	uint64_t limit_samples;
+	gboolean data_source;
+
+	/* Operational state */
+	uint64_t num_samples;
+	unsigned char buf[8];
+	struct libusb_transfer *xfer;
+	void *cb_data;
+
+	/* Temporary state across callbacks */
+	unsigned char packet[32];
+	int packet_len;
+};
+
+SR_PRIV int uni_t_ut32x_handle_events(int fd, int revents, void *cb_data);
+SR_PRIV void uni_t_ut32x_receive_transfer(struct libusb_transfer *transfer);
+
+#endif
diff --git a/hardware/victor-dmm/api.c b/hardware/victor-dmm/api.c
new file mode 100644
index 0000000..74523ed
--- /dev/null
+++ b/hardware/victor-dmm/api.c
@@ -0,0 +1,447 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <libusb.h>
+#include <stdlib.h>
+#include <string.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+
+#define VICTOR_VID 0x1244
+#define VICTOR_PID 0xd237
+#define VICTOR_VENDOR "Victor"
+#define VICTOR_INTERFACE 0
+#define VICTOR_ENDPOINT LIBUSB_ENDPOINT_IN | 1
+
+SR_PRIV struct sr_dev_driver victor_dmm_driver_info;
+static struct sr_dev_driver *di = &victor_dmm_driver_info;
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data);
+
+static const int32_t hwopts[] = {
+	SR_CONF_CONN,
+};
+
+static const int32_t hwcaps[] = {
+	SR_CONF_MULTIMETER,
+	SR_CONF_LIMIT_MSEC,
+	SR_CONF_LIMIT_SAMPLES,
+	SR_CONF_CONTINUOUS,
+};
+
+static int init(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	struct sr_dev_inst *sdi;
+	struct sr_channel *ch;
+	struct libusb_device_descriptor des;
+	libusb_device **devlist;
+	GSList *devices;
+	int ret, devcnt, i;
+
+	(void)options;
+
+	drvc = di->priv;
+
+	devices = NULL;
+	libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
+	for (i = 0; devlist[i]; i++) {
+		if ((ret = libusb_get_device_descriptor(devlist[i], &des)) != 0) {
+			sr_warn("Failed to get device descriptor: %s",
+					libusb_error_name(ret));
+			continue;
+		}
+
+		if (des.idVendor != VICTOR_VID || des.idProduct != VICTOR_PID)
+			continue;
+
+		devcnt = g_slist_length(drvc->instances);
+		if (!(sdi = sr_dev_inst_new(devcnt, SR_ST_INACTIVE,
+				VICTOR_VENDOR, NULL, NULL)))
+			return NULL;
+		sdi->driver = di;
+
+		if (!(devc = g_try_malloc0(sizeof(struct dev_context))))
+			return NULL;
+		sdi->priv = devc;
+
+		if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
+			return NULL;
+		sdi->channels = g_slist_append(NULL, ch);
+
+		if (!(sdi->conn = sr_usb_dev_inst_new(libusb_get_bus_number(devlist[i]),
+				libusb_get_device_address(devlist[i]), NULL)))
+			return NULL;
+		sdi->inst_type = SR_INST_USB;
+
+		drvc->instances = g_slist_append(drvc->instances, sdi);
+		devices = g_slist_append(devices, sdi);
+	}
+	libusb_free_device_list(devlist, 1);
+
+	return devices;
+}
+
+static GSList *dev_list(void)
+{
+	return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+	struct drv_context *drvc = di->priv;
+	struct sr_usb_dev_inst *usb;
+	libusb_device **devlist;
+	int ret, i;
+
+	if (!di->priv) {
+		sr_err("Driver was not initialized.");
+		return SR_ERR;
+	}
+
+	usb = sdi->conn;
+
+	libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist);
+	for (i = 0; devlist[i]; i++) {
+		if (libusb_get_bus_number(devlist[i]) != usb->bus
+				|| libusb_get_device_address(devlist[i]) != usb->address)
+			continue;
+		if ((ret = libusb_open(devlist[i], &usb->devhdl))) {
+			sr_err("Failed to open device: %s.", libusb_error_name(ret));
+			return SR_ERR;
+		}
+		break;
+	}
+	libusb_free_device_list(devlist, 1);
+	if (!devlist[i]) {
+		sr_err("Device not found.");
+		return SR_ERR;
+	}
+
+	/* The device reports as HID class, so the kernel would have
+	 * claimed it. */
+	if (libusb_kernel_driver_active(usb->devhdl, 0) == 1) {
+		if ((ret = libusb_detach_kernel_driver(usb->devhdl, 0)) < 0) {
+			sr_err("Failed to detach kernel driver: %s.",
+			       libusb_error_name(ret));
+			return SR_ERR;
+		}
+	}
+
+	if ((ret = libusb_claim_interface(usb->devhdl,
+			VICTOR_INTERFACE))) {
+		sr_err("Failed to claim interface: %s.", libusb_error_name(ret));
+		return SR_ERR;
+	}
+	sdi->status = SR_ST_ACTIVE;
+
+	return SR_OK;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+	struct sr_usb_dev_inst *usb;
+
+	if (!di->priv) {
+		sr_err("Driver was not initialized.");
+		return SR_ERR;
+	}
+
+	usb = sdi->conn;
+
+	if (!usb->devhdl)
+		/*  Nothing to do. */
+		return SR_OK;
+
+	libusb_release_interface(usb->devhdl, VICTOR_INTERFACE);
+	libusb_close(usb->devhdl);
+	usb->devhdl = NULL;
+	sdi->status = SR_ST_INACTIVE;
+
+	return SR_OK;
+}
+
+static int cleanup(void)
+{
+	int ret;
+	struct drv_context *drvc;
+
+	if (!(drvc = di->priv))
+		/* Can get called on an unused driver, doesn't matter. */
+		return SR_OK;
+
+
+	ret = std_dev_clear(di, NULL);
+	g_free(drvc);
+	di->priv = NULL;
+
+	return ret;
+}
+
+static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct sr_usb_dev_inst *usb;
+	char str[128];
+
+	(void)cg;
+
+	switch (id) {
+	case SR_CONF_CONN:
+		if (!sdi || !sdi->conn)
+			return SR_ERR_ARG;
+		usb = sdi->conn;
+		snprintf(str, 128, "%d.%d", usb->bus, usb->address);
+		*data = g_variant_new_string(str);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	gint64 now;
+	int ret;
+
+	(void)cg;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!di->priv) {
+		sr_err("Driver was not initialized.");
+		return SR_ERR;
+	}
+
+	devc = sdi->priv;
+	ret = SR_OK;
+	switch (id) {
+	case SR_CONF_LIMIT_MSEC:
+		devc->limit_msec = g_variant_get_uint64(data);
+		now = g_get_monotonic_time() / 1000;
+		devc->end_time = now + devc->limit_msec;
+		sr_dbg("Setting time limit to %" PRIu64 "ms.",
+		       devc->limit_msec);
+		break;
+	case SR_CONF_LIMIT_SAMPLES:
+		devc->limit_samples = g_variant_get_uint64(data);
+		sr_dbg("Setting sample limit to %" PRIu64 ".",
+		       devc->limit_samples);
+		break;
+	default:
+		ret = SR_ERR_NA;
+	}
+
+	return ret;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	(void)sdi;
+	(void)cg;
+
+	switch (key) {
+	case SR_CONF_SCAN_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
+		break;
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static void receive_transfer(struct libusb_transfer *transfer)
+{
+	struct dev_context *devc;
+	struct sr_dev_inst *sdi;
+	int ret;
+
+	sdi = transfer->user_data;
+	devc = sdi->priv;
+	if (transfer->status == LIBUSB_TRANSFER_NO_DEVICE) {
+		/* USB device was unplugged. */
+		dev_acquisition_stop(sdi, sdi);
+	} else if (transfer->status == LIBUSB_TRANSFER_COMPLETED) {
+		sr_dbg("Got %d-byte packet.", transfer->actual_length);
+		if (transfer->actual_length == DMM_DATA_SIZE) {
+			victor_dmm_receive_data(sdi, transfer->buffer);
+			if (devc->limit_samples) {
+				if (devc->num_samples >= devc->limit_samples)
+					dev_acquisition_stop(sdi, sdi);
+			}
+		}
+	}
+	/* Anything else is either an error or a timeout, which is fine:
+	 * we were just going to send another transfer request anyway. */
+
+	if (sdi->status == SR_ST_ACTIVE) {
+		/* Send the same request again. */
+		if ((ret = libusb_submit_transfer(transfer) != 0)) {
+			sr_err("Unable to resubmit transfer: %s.",
+			       libusb_error_name(ret));
+			g_free(transfer->buffer);
+			libusb_free_transfer(transfer);
+			dev_acquisition_stop(sdi, sdi);
+		}
+	} else {
+		/* This was the last transfer we're going to receive, so
+		 * clean up now. */
+		g_free(transfer->buffer);
+		libusb_free_transfer(transfer);
+	}
+}
+
+static int handle_events(int fd, int revents, void *cb_data)
+{
+	struct dev_context *devc;
+	struct drv_context *drvc = di->priv;
+	struct sr_datafeed_packet packet;
+	struct sr_dev_inst *sdi;
+	struct timeval tv;
+	gint64 now;
+
+	(void)fd;
+	(void)revents;
+
+	sdi = cb_data;
+	devc = sdi->priv;
+
+	if (devc->limit_msec) {
+		now = g_get_monotonic_time() / 1000;
+		if (now > devc->end_time)
+			dev_acquisition_stop(sdi, sdi);
+	}
+
+	if (sdi->status == SR_ST_STOPPING) {
+		usb_source_remove(drvc->sr_ctx);
+
+		dev_close(sdi);
+
+		packet.type = SR_DF_END;
+		sr_session_send(cb_data, &packet);
+	}
+
+	memset(&tv, 0, sizeof(struct timeval));
+	libusb_handle_events_timeout_completed(drvc->sr_ctx->libusb_ctx, &tv,
+					       NULL);
+
+	return TRUE;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct dev_context *devc;
+	struct drv_context *drvc = di->priv;
+	struct sr_usb_dev_inst *usb;
+	struct libusb_transfer *transfer;
+	int ret;
+	unsigned char *buf;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!di->priv) {
+		sr_err("Driver was not initialized.");
+		return SR_ERR;
+	}
+
+	devc = sdi->priv;
+	usb = sdi->conn;
+	devc->cb_data = cb_data;
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	usb_source_add(drvc->sr_ctx, 100, handle_events, (void *)sdi);
+
+	buf = g_try_malloc(DMM_DATA_SIZE);
+	transfer = libusb_alloc_transfer(0);
+	/* Each transfer request gets 100ms to arrive before it's restarted.
+	 * The device only sends 1 transfer/second no matter how many
+	 * times you ask, but we want to keep step with the USB events
+	 * handling above. */
+	libusb_fill_interrupt_transfer(transfer, usb->devhdl,
+			VICTOR_ENDPOINT, buf, DMM_DATA_SIZE, receive_transfer,
+			cb_data, 100);
+	if ((ret = libusb_submit_transfer(transfer) != 0)) {
+		sr_err("Unable to submit transfer: %s.", libusb_error_name(ret));
+		libusb_free_transfer(transfer);
+		g_free(buf);
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	(void)cb_data;
+
+	if (!di->priv) {
+		sr_err("Driver was not initialized.");
+		return SR_ERR;
+	}
+
+	if (sdi->status != SR_ST_ACTIVE) {
+		sr_err("Device not active, can't stop acquisition.");
+		return SR_ERR;
+	}
+
+	sdi->status = SR_ST_STOPPING;
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver victor_dmm_driver_info = {
+	.name = "victor-dmm",
+	.longname = "Victor DMMs",
+	.api_version = 1,
+	.init = init,
+	.cleanup = cleanup,
+	.scan = scan,
+	.dev_list = dev_list,
+	.dev_clear = NULL,
+	.config_get = config_get,
+	.config_set = config_set,
+	.config_list = config_list,
+	.dev_open = dev_open,
+	.dev_close = dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/victor-dmm/protocol.c b/hardware/victor-dmm/protocol.c
new file mode 100644
index 0000000..6af5141
--- /dev/null
+++ b/hardware/victor-dmm/protocol.c
@@ -0,0 +1,298 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <string.h>
+#include <math.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "protocol.h"
+
+/* Reverse the high nibble into the low nibble */
+static uint8_t decode_digit(uint8_t in)
+{
+	uint8_t out, i;
+
+	out = 0;
+	in >>= 4;
+	for (i = 0x08; i; i >>= 1) {
+		out >>= 1;
+		if (in & i)
+			out |= 0x08;
+	}
+
+	return out;
+}
+
+static void decode_buf(struct sr_dev_inst *sdi, unsigned char *data)
+{
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_analog analog;
+	struct dev_context *devc;
+	long factor, ivalue;
+	uint8_t digits[4];
+	gboolean is_duty, is_continuity, is_diode, is_ac, is_dc, is_auto;
+	gboolean is_hold, is_max, is_min, is_relative, minus;
+	float fvalue;
+
+	devc = sdi->priv;
+
+	digits[0] = decode_digit(data[12]);
+	digits[1] = decode_digit(data[11]);
+	digits[2] = decode_digit(data[10]);
+	digits[3] = decode_digit(data[9]);
+
+	if (digits[0] == 0x0f && digits[1] == 0x00 && digits[2] == 0x0a &&
+			digits[3] == 0x0f)
+		/* The "over limit" (OL) display comes through like this */
+		ivalue = -1;
+	else if (digits[0] > 9 || digits[1] > 9 || digits[2] > 9 || digits[3] > 9)
+		/* An invalid digit in any position denotes no value. */
+		ivalue = -2;
+	else {
+		ivalue = digits[0] * 1000;
+		ivalue += digits[1] * 100;
+		ivalue += digits[2] * 10;
+		ivalue += digits[3];
+	}
+
+	/* Decimal point position */
+	factor = 0;
+	switch (data[7] >> 4) {
+	case 0x00:
+		factor = 0;
+		break;
+	case 0x02:
+		factor = 1;
+		break;
+	case 0x04:
+		factor = 2;
+		break;
+	case 0x08:
+		factor = 3;
+		break;
+	default:
+		sr_err("Unknown decimal point byte: 0x%.2x.", data[7]);
+		break;
+	}
+
+	/* Minus flag */
+	minus = data[2] & 0x01;
+
+	/* Mode detail symbols on the right side of the digits */
+	is_duty = is_continuity = is_diode = FALSE;
+	switch (data[4]) {
+	case 0x00:
+		/* None. */
+		break;
+	case 0x01:
+		/* Micro */
+		factor += 6;
+		break;
+	case 0x02:
+		/* Milli */
+		factor += 3;
+		break;
+	case 0x04:
+		/* Kilo */
+		ivalue *= 1000;
+		break;
+	case 0x08:
+		/* Mega */
+		ivalue *= 1000000;
+		break;
+	case 0x10:
+		/* Continuity shows up as Ohm + this bit */
+		is_continuity = TRUE;
+		break;
+	case 0x20:
+		/* Diode tester is Volt + this bit */
+		is_diode = TRUE;
+		break;
+	case 0x40:
+		is_duty = TRUE;
+		break;
+	case 0x80:
+		/* Never seen */
+		sr_dbg("Unknown mode right detail: 0x%.2x.", data[4]);
+		break;
+	default:
+		sr_dbg("Unknown/invalid mode right detail: 0x%.2x.", data[4]);
+		break;
+	}
+
+	/* Scale flags on the right, continued */
+	is_max = is_min = FALSE;
+	if (data[5] & 0x04)
+		is_max = TRUE;
+	if (data[5] & 0x08)
+		is_min = TRUE;
+	if (data[5] & 0x40)
+		/* Nano */
+		factor += 9;
+
+	/* Mode detail symbols on the left side of the digits */
+	is_auto = is_dc = is_ac = is_hold = is_relative = FALSE;
+	if (data[6] & 0x04)
+		is_auto = TRUE;
+	if (data[6] & 0x08)
+		is_dc = TRUE;
+	if (data[6] & 0x10)
+		is_ac = TRUE;
+	if (data[6] & 0x20)
+		is_relative = TRUE;
+	if (data[6] & 0x40)
+		is_hold = TRUE;
+
+	fvalue = (float)ivalue / pow(10, factor);
+	if (minus)
+		fvalue = -fvalue;
+
+	memset(&analog, 0, sizeof(struct sr_datafeed_analog));
+
+	/* Measurement mode */
+	analog.mq = -1;
+	switch (data[3]) {
+	case 0x00:
+		if (is_duty) {
+			analog.mq = SR_MQ_DUTY_CYCLE;
+			analog.unit = SR_UNIT_PERCENTAGE;
+		} else
+			sr_dbg("Unknown measurement mode: %.2x.", data[3]);
+		break;
+	case 0x01:
+		if (is_diode) {
+			analog.mq = SR_MQ_VOLTAGE;
+			analog.unit = SR_UNIT_VOLT;
+			analog.mqflags |= SR_MQFLAG_DIODE;
+			if (ivalue < 0)
+				fvalue = NAN;
+		} else {
+			if (ivalue < 0)
+				break;
+			analog.mq = SR_MQ_VOLTAGE;
+			analog.unit = SR_UNIT_VOLT;
+			if (is_ac)
+				analog.mqflags |= SR_MQFLAG_AC;
+			if (is_dc)
+				analog.mqflags |= SR_MQFLAG_DC;
+		}
+		break;
+	case 0x02:
+		analog.mq = SR_MQ_CURRENT;
+		analog.unit = SR_UNIT_AMPERE;
+		if (is_ac)
+			analog.mqflags |= SR_MQFLAG_AC;
+		if (is_dc)
+			analog.mqflags |= SR_MQFLAG_DC;
+		break;
+	case 0x04:
+		if (is_continuity) {
+			analog.mq = SR_MQ_CONTINUITY;
+			analog.unit = SR_UNIT_BOOLEAN;
+			fvalue = ivalue < 0 ? 0.0 : 1.0;
+		} else {
+			analog.mq = SR_MQ_RESISTANCE;
+			analog.unit = SR_UNIT_OHM;
+			if (ivalue < 0)
+				fvalue = INFINITY;
+		}
+		break;
+	case 0x08:
+		/* Never seen */
+		sr_dbg("Unknown measurement mode: 0x%.2x.", data[3]);
+		break;
+	case 0x10:
+		analog.mq = SR_MQ_FREQUENCY;
+		analog.unit = SR_UNIT_HERTZ;
+		break;
+	case 0x20:
+		analog.mq = SR_MQ_CAPACITANCE;
+		analog.unit = SR_UNIT_FARAD;
+		break;
+	case 0x40:
+		analog.mq = SR_MQ_TEMPERATURE;
+		analog.unit = SR_UNIT_CELSIUS;
+		break;
+	case 0x80:
+		analog.mq = SR_MQ_TEMPERATURE;
+		analog.unit = SR_UNIT_FAHRENHEIT;
+		break;
+	default:
+		sr_dbg("Unknown/invalid measurement mode: 0x%.2x.", data[3]);
+		break;
+	}
+	if (analog.mq == -1)
+		return;
+
+	if (is_auto)
+		analog.mqflags |= SR_MQFLAG_AUTORANGE;
+	if (is_hold)
+		analog.mqflags |= SR_MQFLAG_HOLD;
+	if (is_max)
+		analog.mqflags |= SR_MQFLAG_MAX;
+	if (is_min)
+		analog.mqflags |= SR_MQFLAG_MIN;
+	if (is_relative)
+		analog.mqflags |= SR_MQFLAG_RELATIVE;
+
+	analog.channels = sdi->channels;
+	analog.num_samples = 1;
+	analog.data = &fvalue;
+	packet.type = SR_DF_ANALOG;
+	packet.payload = &analog;
+	sr_session_send(devc->cb_data, &packet);
+
+	devc->num_samples++;
+}
+
+SR_PRIV int victor_dmm_receive_data(struct sr_dev_inst *sdi, unsigned char *buf)
+{
+	GString *dbg;
+	int i;
+	unsigned char data[DMM_DATA_SIZE];
+	unsigned char obfuscation[DMM_DATA_SIZE] = "jodenxunickxia";
+	unsigned char shuffle[DMM_DATA_SIZE] = {
+		6, 13, 5, 11, 2, 7, 9, 8, 3, 10, 12, 0, 4, 1
+	};
+
+	for (i = 0; i < DMM_DATA_SIZE && buf[i] == 0; i++);
+	if (i == DMM_DATA_SIZE) {
+		/* This DMM outputs all zeroes from time to time, just ignore it. */
+		sr_dbg("Received all zeroes.");
+		return SR_OK;
+	}
+
+	/* Deobfuscate and reorder data. */
+	for (i = 0; i < DMM_DATA_SIZE; i++)
+		data[shuffle[i]] = (buf[i] - obfuscation[i]) & 0xff;
+
+	if (sr_log_loglevel_get() >= SR_LOG_SPEW) {
+		dbg = g_string_sized_new(128);
+		g_string_printf(dbg, "Deobfuscated.");
+		for (i = 0; i < DMM_DATA_SIZE; i++)
+			g_string_append_printf(dbg, " %.2x", data[i]);
+		sr_spew("%s", dbg->str);
+		g_string_free(dbg, TRUE);
+	}
+
+	decode_buf(sdi, data);
+
+	return SR_OK;
+}
diff --git a/hardware/victor-dmm/protocol.h b/hardware/victor-dmm/protocol.h
new file mode 100644
index 0000000..8f12680
--- /dev/null
+++ b/hardware/victor-dmm/protocol.h
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_VICTOR_DMM_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_VICTOR_DMM_PROTOCOL_H
+
+#include <stdint.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "victor-dmm"
+
+#define DMM_DATA_SIZE 14
+
+/** Private, per-device-instance driver context. */
+struct dev_context {
+	/** The current sampling limit (in number of samples). */
+	uint64_t limit_samples;
+
+	/** The current sampling limit (in ms). */
+	uint64_t limit_msec;
+
+	/** Opaque pointer passed in by the frontend. */
+	void *cb_data;
+
+	/** The current number of already received samples. */
+	uint64_t num_samples;
+	gint64 end_time;
+};
+
+SR_PRIV int victor_dmm_receive_data(struct sr_dev_inst *sdi, unsigned char *buf);
+
+#endif
diff --git a/hardware/zeroplus-logic-cube/analyzer.c b/hardware/zeroplus-logic-cube/analyzer.c
new file mode 100644
index 0000000..47dcfc8
--- /dev/null
+++ b/hardware/zeroplus-logic-cube/analyzer.c
@@ -0,0 +1,663 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010 Sven Peter <sven at fail0verflow.com>
+ * Copyright (C) 2010 Haxx Enterprises <bushing at gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ *  THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "analyzer.h"
+#include "gl_usb.h"
+#include "protocol.h"
+
+enum {
+	HARD_DATA_CHECK_SUM		= 0x00,
+	PASS_WORD,
+
+	DEV_ID0				= 0x10,
+	DEV_ID1,
+
+	START_STATUS			= 0x20,
+	DEV_STATUS			= 0x21,
+	FREQUENCY_REG0			= 0x30,
+	FREQUENCY_REG1,
+	FREQUENCY_REG2,
+	FREQUENCY_REG3,
+	FREQUENCY_REG4,
+	MEMORY_LENGTH,
+	CLOCK_SOURCE,
+
+	TRIGGER_STATUS0			= 0x40,
+	TRIGGER_STATUS1,
+	TRIGGER_STATUS2,
+	TRIGGER_STATUS3,
+	TRIGGER_STATUS4,
+	TRIGGER_STATUS5,
+	TRIGGER_STATUS6,
+	TRIGGER_STATUS7,
+	TRIGGER_STATUS8,
+
+	TRIGGER_COUNT0			= 0x50,
+	TRIGGER_COUNT1,
+
+	TRIGGER_LEVEL0			= 0x55,
+	TRIGGER_LEVEL1,
+	TRIGGER_LEVEL2,
+	TRIGGER_LEVEL3,
+
+	RAMSIZE_TRIGGERBAR_ADDRESS0	= 0x60,
+	RAMSIZE_TRIGGERBAR_ADDRESS1,
+	RAMSIZE_TRIGGERBAR_ADDRESS2,
+	TRIGGERBAR_ADDRESS0,
+	TRIGGERBAR_ADDRESS1,
+	TRIGGERBAR_ADDRESS2,
+	DONT_CARE_TRIGGERBAR,
+
+	FILTER_ENABLE			= 0x70,
+	FILTER_STATUS,
+
+	ENABLE_DELAY_TIME0		= 0x7a,
+	ENABLE_DELAY_TIME1,
+
+	ENABLE_INSERT_DATA0		= 0x80,
+	ENABLE_INSERT_DATA1,
+	ENABLE_INSERT_DATA2,
+	ENABLE_INSERT_DATA3,
+	COMPRESSION_TYPE0,
+	COMPRESSION_TYPE1,
+
+	TRIGGER_ADDRESS0		= 0x90,
+	TRIGGER_ADDRESS1,
+	TRIGGER_ADDRESS2,
+
+	NOW_ADDRESS0			= 0x96,
+	NOW_ADDRESS1,
+	NOW_ADDRESS2,
+
+	STOP_ADDRESS0			= 0x9b,
+	STOP_ADDRESS1,
+	STOP_ADDRESS2,
+
+	READ_RAM_STATUS			= 0xa0,
+};
+
+static int g_trigger_status[9] = { 0 };
+static int g_trigger_count = 1;
+static int g_filter_status[8] = { 0 };
+static int g_filter_enable = 0;
+
+static int g_freq_value = 1;
+static int g_freq_scale = FREQ_SCALE_MHZ;
+static int g_memory_size = MEMORY_SIZE_8K;
+static int g_ramsize_triggerbar_addr = 2 * 1024;
+static int g_triggerbar_addr = 0;
+static int g_compression = COMPRESSION_NONE;
+static int g_thresh = 0x31; /* 1.5V */
+
+/* Maybe unk specifies an "endpoint" or "register" of sorts. */
+static int analyzer_write_status(libusb_device_handle *devh, unsigned char unk,
+				 unsigned char flags)
+{
+	assert(unk <= 3);
+	return gl_reg_write(devh, START_STATUS, unk << 6 | flags);
+}
+
+#if 0
+static int __analyzer_set_freq(libusb_device_handle *devh, int freq, int scale)
+{
+	int reg0 = 0, divisor = 0, reg2 = 0;
+
+	switch (scale) {
+	case FREQ_SCALE_MHZ: /* MHz */
+		if (freq >= 100 && freq <= 200) {
+			reg0 = freq * 0.1;
+			divisor = 1;
+			reg2 = 0;
+			break;
+		}
+		if (freq >= 50 && freq < 100) {
+			reg0 = freq * 0.2;
+			divisor = 2;
+			reg2 = 0;
+			break;
+		}
+		if (freq >= 10 && freq < 50) {
+			if (freq == 25) {
+				reg0 = 25;
+				divisor = 5;
+				reg2 = 1;
+				break;
+			} else {
+				reg0 = freq * 0.5;
+				divisor = 5;
+				reg2 = 1;
+				break;
+			}
+		}
+		if (freq >= 2 && freq < 10) {
+			divisor = 5;
+			reg0 = freq * 2;
+			reg2 = 2;
+			break;
+		}
+		if (freq == 1) {
+			divisor = 5;
+			reg2 = 16;
+			reg0 = 5;
+			break;
+		}
+		divisor = 5;
+		reg0 = 5;
+		reg2 = 64;
+		break;
+	case FREQ_SCALE_HZ: /* Hz */
+		if (freq >= 500 && freq < 1000) {
+			reg0 = freq * 0.01;
+			divisor = 10;
+			reg2 = 64;
+			break;
+		}
+		if (freq >= 300 && freq < 500) {
+			reg0 = freq * 0.005 * 8;
+			divisor = 5;
+			reg2 = 67;
+			break;
+		}
+		if (freq >= 100 && freq < 300) {
+			reg0 = freq * 0.005 * 16;
+			divisor = 5;
+			reg2 = 68;
+			break;
+		}
+		divisor = 5;
+		reg0 = 5;
+		reg2 = 64;
+		break;
+	case FREQ_SCALE_KHZ: /* kHz */
+		if (freq >= 500 && freq < 1000) {
+			reg0 = freq * 0.01;
+			divisor = 5;
+			reg2 = 17;
+			break;
+		}
+		if (freq >= 100 && freq < 500) {
+			reg0 = freq * 0.05;
+			divisor = 5;
+			reg2 = 32;
+			break;
+		}
+		if (freq >= 50 && freq < 100) {
+			reg0 = freq * 0.1;
+			divisor = 5;
+			reg2 = 33;
+			break;
+		}
+		if (freq >= 10 && freq < 50) {
+			if (freq == 25) {
+				reg0 = 25;
+				divisor = 5;
+				reg2 = 49;
+				break;
+			}
+			reg0 = freq * 0.5;
+			divisor = 5;
+			reg2 = 48;
+			break;
+		}
+		if (freq >= 2 && freq < 10) {
+			divisor = 5;
+			reg0 = freq * 2;
+			reg2 = 50;
+			break;
+		}
+		divisor = 5;
+		reg0 = 5;
+		reg2 = 64;
+		break;
+	default:
+		divisor = 5;
+		reg0 = 5;
+		reg2 = 64;
+		break;
+	}
+
+	sr_dbg("Setting samplerate regs (freq=%d, scale=%d): "
+	       "reg0: %d, reg1: %d, reg2: %d, reg3: %d.",
+	       freq, scale, divisor, reg0, 0x02, reg2);
+
+	if (gl_reg_write(devh, FREQUENCY_REG0, divisor) < 0)
+		return -1; /* Divisor maybe? */
+
+	if (gl_reg_write(devh, FREQUENCY_REG1, reg0) < 0)
+		return -1; /* 10 / 0.2 */
+
+	if (gl_reg_write(devh, FREQUENCY_REG2, 0x02) < 0)
+		return -1; /* Always 2 */
+
+	if (gl_reg_write(devh, FREQUENCY_REG4, reg2) < 0)
+		return -1;
+
+	return 0;
+}
+#endif
+
+/*
+ * It seems that ...
+ *	FREQUENCT_REG0 - division factor (?)
+ *	FREQUENCT_REG1 - multiplication factor (?)
+ *	FREQUENCT_REG4 - clock selection (?)
+ *
+ *	clock selection
+ *	0  10MHz  16   1MHz  32 100kHz  48  10kHz  64   1kHz
+ *	1   5MHz  17 500kHz  33  50kHz  49   5kHz  65  500Hz
+ *	2 2.5MHz   .          .         50 2.5kHz  66  250Hz
+ *	.          .          .          .         67  125Hz
+ *	.          .          .          .         68 62.5Hz
+ */
+static int __analyzer_set_freq(libusb_device_handle *devh, int freq, int scale)
+{
+	struct freq_factor {
+		int freq;
+		int scale;
+		int sel;
+		int div;
+		int mul;
+	};
+
+	static const struct freq_factor f[] = {
+		{ 200, FREQ_SCALE_MHZ,  0,  1, 20 },
+		{ 150, FREQ_SCALE_MHZ,  0,  1, 15 },
+		{ 100, FREQ_SCALE_MHZ,  0,  1, 10 },
+		{  80, FREQ_SCALE_MHZ,  0,  2, 16 },
+		{  50, FREQ_SCALE_MHZ,  0,  2, 10 },
+		{  25, FREQ_SCALE_MHZ,  1,  5, 25 },
+		{  10, FREQ_SCALE_MHZ,  1,  5, 10 },
+		{   1, FREQ_SCALE_MHZ, 16,  5,  5 },
+		{ 800, FREQ_SCALE_KHZ, 17,  5,  8 },
+		{ 400, FREQ_SCALE_KHZ, 32,  5, 20 },
+		{ 200, FREQ_SCALE_KHZ, 32,  5, 10 },
+		{ 100, FREQ_SCALE_KHZ, 32,  5,  5 },
+		{  50, FREQ_SCALE_KHZ, 33,  5,  5 },
+		{  25, FREQ_SCALE_KHZ, 49,  5, 25 },
+		{   5, FREQ_SCALE_KHZ, 50,  5, 10 },
+		{   1, FREQ_SCALE_KHZ, 64,  5,  5 },
+		{ 500, FREQ_SCALE_HZ,  64, 10,  5 },
+		{ 100, FREQ_SCALE_HZ,  68,  5,  8 },
+		{   0, 0,              0,   0,  0 }
+	};
+
+	int i;
+
+	for (i = 0; f[i].freq; i++) {
+		if (scale == f[i].scale && freq == f[i].freq)
+			break;
+	}
+	if (!f[i].freq)
+		return -1;
+
+	sr_dbg("Setting samplerate regs (freq=%d, scale=%d): "
+	       "reg0: %d, reg1: %d, reg2: %d, reg3: %d.",
+	       freq, scale, f[i].div, f[i].mul, 0x02, f[i].sel);
+
+	if (gl_reg_write(devh, FREQUENCY_REG0, f[i].div) < 0)
+		return -1;
+
+	if (gl_reg_write(devh, FREQUENCY_REG1, f[i].mul) < 0)
+		return -1;
+
+	if (gl_reg_write(devh, FREQUENCY_REG2, 0x02) < 0)
+		return -1;
+
+	if (gl_reg_write(devh, FREQUENCY_REG4, f[i].sel) < 0)
+		return -1;
+
+	return 0;
+}
+
+static void __analyzer_set_ramsize_trigger_address(libusb_device_handle *devh,
+						   unsigned int address)
+{
+	gl_reg_write(devh, RAMSIZE_TRIGGERBAR_ADDRESS0, (address >> 0) & 0xFF);
+	gl_reg_write(devh, RAMSIZE_TRIGGERBAR_ADDRESS1, (address >> 8) & 0xFF);
+	gl_reg_write(devh, RAMSIZE_TRIGGERBAR_ADDRESS2, (address >> 16) & 0xFF);
+}
+
+static void __analyzer_set_triggerbar_address(libusb_device_handle *devh,
+					      unsigned int address)
+{
+	gl_reg_write(devh, TRIGGERBAR_ADDRESS0, (address >> 0) & 0xFF);
+	gl_reg_write(devh, TRIGGERBAR_ADDRESS1, (address >> 8) & 0xFF);
+	gl_reg_write(devh, TRIGGERBAR_ADDRESS2, (address >> 16) & 0xFF);
+}
+
+static void __analyzer_set_compression(libusb_device_handle *devh,
+				       unsigned int type)
+{
+	gl_reg_write(devh, COMPRESSION_TYPE0, (type >> 0) & 0xFF);
+	gl_reg_write(devh, COMPRESSION_TYPE1, (type >> 8) & 0xFF);
+}
+
+static void __analyzer_set_trigger_count(libusb_device_handle *devh,
+					 unsigned int count)
+{
+	gl_reg_write(devh, TRIGGER_COUNT0, (count >> 0) & 0xFF);
+	gl_reg_write(devh, TRIGGER_COUNT1, (count >> 8) & 0xFF);
+}
+
+static void analyzer_write_enable_insert_data(libusb_device_handle *devh)
+{
+	gl_reg_write(devh, ENABLE_INSERT_DATA0, 0x12);
+	gl_reg_write(devh, ENABLE_INSERT_DATA1, 0x34);
+	gl_reg_write(devh, ENABLE_INSERT_DATA2, 0x56);
+	gl_reg_write(devh, ENABLE_INSERT_DATA3, 0x78);
+}
+
+static void analyzer_set_filter(libusb_device_handle *devh)
+{
+	int i;
+	gl_reg_write(devh, FILTER_ENABLE, g_filter_enable);
+	for (i = 0; i < 8; i++)
+		gl_reg_write(devh, FILTER_STATUS + i, g_filter_status[i]);
+}
+
+SR_PRIV void analyzer_reset(libusb_device_handle *devh)
+{
+	analyzer_write_status(devh, 3, STATUS_FLAG_NONE);	// reset device
+	analyzer_write_status(devh, 3, STATUS_FLAG_RESET);	// reset device
+}
+
+SR_PRIV void analyzer_initialize(libusb_device_handle *devh)
+{
+	analyzer_write_status(devh, 1, STATUS_FLAG_NONE);
+	analyzer_write_status(devh, 1, STATUS_FLAG_INIT);
+	analyzer_write_status(devh, 1, STATUS_FLAG_NONE);
+}
+
+SR_PRIV void analyzer_wait(libusb_device_handle *devh, int set, int unset)
+{
+	int status;
+
+	while (1) {
+		status = gl_reg_read(devh, DEV_STATUS);
+		if ((!set || (status & set)) && ((status & unset) == 0))
+			return;
+	}
+}
+
+SR_PRIV void analyzer_read_start(libusb_device_handle *devh)
+{
+	analyzer_write_status(devh, 3, STATUS_FLAG_20 | STATUS_FLAG_READ);
+
+	/* Prep for bulk reads */
+	gl_reg_read_buf(devh, READ_RAM_STATUS, NULL, 0);
+}
+
+SR_PRIV int analyzer_read_data(libusb_device_handle *devh, void *buffer,
+		       unsigned int size)
+{
+	return gl_read_bulk(devh, buffer, size);
+}
+
+SR_PRIV void analyzer_read_stop(libusb_device_handle *devh)
+{
+	analyzer_write_status(devh, 3, STATUS_FLAG_20);
+	analyzer_write_status(devh, 3, STATUS_FLAG_NONE);
+}
+
+SR_PRIV void analyzer_start(libusb_device_handle *devh)
+{
+	analyzer_write_status(devh, 1, STATUS_FLAG_NONE);
+	analyzer_write_status(devh, 1, STATUS_FLAG_INIT);
+	analyzer_write_status(devh, 1, STATUS_FLAG_NONE);
+	analyzer_write_status(devh, 1, STATUS_FLAG_GO);
+}
+
+SR_PRIV void analyzer_configure(libusb_device_handle *devh)
+{
+	int i;
+
+	/* Write_Start_Status */
+	analyzer_write_status(devh, 1, STATUS_FLAG_RESET);
+	analyzer_write_status(devh, 1, STATUS_FLAG_NONE);
+
+	/* Start_Config_Outside_Device ? */
+	analyzer_write_status(devh, 1, STATUS_FLAG_INIT);
+	analyzer_write_status(devh, 1, STATUS_FLAG_NONE);
+
+	/* SetData_To_Frequence_Reg */
+	__analyzer_set_freq(devh, g_freq_value, g_freq_scale);
+
+	/* SetMemory_Length */
+	gl_reg_write(devh, MEMORY_LENGTH, g_memory_size);
+
+	/* Sele_Inside_Outside_Clock */
+	gl_reg_write(devh, CLOCK_SOURCE, 0x03);
+
+	/* Set_Trigger_Status */
+	for (i = 0; i < 9; i++)
+		gl_reg_write(devh, TRIGGER_STATUS0 + i, g_trigger_status[i]);
+
+	__analyzer_set_trigger_count(devh, g_trigger_count);
+
+	/* Set_Trigger_Level */
+	gl_reg_write(devh, TRIGGER_LEVEL0, g_thresh);
+	gl_reg_write(devh, TRIGGER_LEVEL1, g_thresh);
+	gl_reg_write(devh, TRIGGER_LEVEL2, g_thresh);
+	gl_reg_write(devh, TRIGGER_LEVEL3, g_thresh);
+
+	/* Size of actual memory >> 2 */
+	__analyzer_set_ramsize_trigger_address(devh, g_ramsize_triggerbar_addr);
+	__analyzer_set_triggerbar_address(devh, g_triggerbar_addr);
+
+	/* Set_Dont_Care_TriggerBar */
+	gl_reg_write(devh, DONT_CARE_TRIGGERBAR, 0x01);
+
+	/* Enable_Status */
+	analyzer_set_filter(devh);
+
+	/* Set_Enable_Delay_Time */
+	gl_reg_write(devh, 0x7a, 0x00);
+	gl_reg_write(devh, 0x7b, 0x00);
+	analyzer_write_enable_insert_data(devh);
+	__analyzer_set_compression(devh, g_compression);
+}
+
+SR_PRIV void analyzer_add_trigger(int channel, int type)
+{
+	switch (type) {
+	case TRIGGER_HIGH:
+		g_trigger_status[channel / 4] |= 1 << (channel % 4 * 2);
+		break;
+	case TRIGGER_LOW:
+		g_trigger_status[channel / 4] |= 2 << (channel % 4 * 2);
+		break;
+#if 0
+	case TRIGGER_POSEDGE:
+		g_trigger_status[8] = 0x40 | channel;
+		break;
+	case TRIGGER_NEGEDGE:
+		g_trigger_status[8] = 0x80 | channel;
+		break;
+	case TRIGGER_ANYEDGE:
+		g_trigger_status[8] = 0xc0 | channel;
+		break;
+#endif
+	default:
+		break;
+	}
+}
+
+SR_PRIV void analyzer_add_filter(int channel, int type)
+{
+	int i;
+
+	if (type != FILTER_HIGH && type != FILTER_LOW)
+		return;
+	if ((channel & 0xf) >= 8)
+		return;
+
+	if (channel & CHANNEL_A)
+		i = 0;
+	else if (channel & CHANNEL_B)
+		i = 2;
+	else if (channel & CHANNEL_C)
+		i = 4;
+	else if (channel & CHANNEL_D)
+		i = 6;
+	else
+		return;
+
+	if ((channel & 0xf) >= 4) {
+		i++;
+		channel -= 4;
+	}
+
+	g_filter_status[i] |=
+	    1 << ((2 * channel) + (type == FILTER_LOW ? 1 : 0));
+
+	g_filter_enable = 1;
+}
+
+SR_PRIV void analyzer_set_trigger_count(int count)
+{
+	g_trigger_count = count;
+}
+
+SR_PRIV void analyzer_set_freq(int freq, int scale)
+{
+	g_freq_value = freq;
+	g_freq_scale = scale;
+}
+
+SR_PRIV void analyzer_set_memory_size(unsigned int size)
+{
+	g_memory_size = size;
+}
+
+SR_PRIV void analyzer_set_ramsize_trigger_address(unsigned int address)
+{
+	g_ramsize_triggerbar_addr = address;
+}
+
+SR_PRIV unsigned int analyzer_get_ramsize_trigger_address(void)
+{
+	return g_ramsize_triggerbar_addr;
+}
+
+SR_PRIV void analyzer_set_triggerbar_address(unsigned int address)
+{
+	g_triggerbar_addr = address;
+}
+
+SR_PRIV unsigned int analyzer_get_triggerbar_address(void)
+{
+	return g_triggerbar_addr;
+}
+
+SR_PRIV unsigned int analyzer_read_status(libusb_device_handle *devh)
+{
+	return gl_reg_read(devh, DEV_STATUS);
+}
+
+SR_PRIV unsigned int analyzer_read_id(libusb_device_handle *devh)
+{
+	return gl_reg_read(devh, DEV_ID1) << 8 | gl_reg_read(devh, DEV_ID0);
+}
+
+SR_PRIV unsigned int analyzer_get_stop_address(libusb_device_handle *devh)
+{
+	return gl_reg_read(devh, STOP_ADDRESS2) << 16 | gl_reg_read(devh,
+			STOP_ADDRESS1) << 8 | gl_reg_read(devh, STOP_ADDRESS0);
+}
+
+SR_PRIV unsigned int analyzer_get_now_address(libusb_device_handle *devh)
+{
+	return gl_reg_read(devh, NOW_ADDRESS2) << 16 | gl_reg_read(devh,
+			NOW_ADDRESS1) << 8 | gl_reg_read(devh, NOW_ADDRESS0);
+}
+
+SR_PRIV unsigned int analyzer_get_trigger_address(libusb_device_handle *devh)
+{
+	return gl_reg_read(devh, TRIGGER_ADDRESS2) << 16 | gl_reg_read(devh,
+		TRIGGER_ADDRESS1) << 8 | gl_reg_read(devh, TRIGGER_ADDRESS0);
+}
+
+SR_PRIV void analyzer_set_compression(unsigned int type)
+{
+	g_compression = type;
+}
+
+SR_PRIV void analyzer_set_voltage_threshold(int thresh)
+{
+	g_thresh = thresh;
+}
+
+SR_PRIV void analyzer_wait_button(libusb_device_handle *devh)
+{
+	analyzer_wait(devh, STATUS_BUTTON_PRESSED, 0);
+}
+
+SR_PRIV void analyzer_wait_data(libusb_device_handle *devh)
+{
+	analyzer_wait(devh, 0, STATUS_BUSY);
+}
+
+SR_PRIV int analyzer_decompress(void *input, unsigned int input_len,
+				void *output, unsigned int output_len)
+{
+	unsigned char *in = input;
+	unsigned char *out = output;
+	unsigned int A, B, C, count;
+	unsigned int written = 0;
+
+	while (input_len > 0) {
+		A = *in++;
+		B = *in++;
+		C = *in++;
+		count = (*in++) + 1;
+
+		if (count > output_len)
+			count = output_len;
+		output_len -= count;
+		written += count;
+
+		while (count--) {
+			*out++ = A;
+			*out++ = B;
+			*out++ = C;
+			*out++ = 0; /* Channel D */
+		}
+
+		input_len -= 4;
+		if (output_len == 0)
+			break;
+	}
+
+	return written;
+}
diff --git a/hardware/zeroplus-logic-cube/analyzer.h b/hardware/zeroplus-logic-cube/analyzer.h
new file mode 100644
index 0000000..f0bb799
--- /dev/null
+++ b/hardware/zeroplus-logic-cube/analyzer.h
@@ -0,0 +1,118 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010 Sven Peter <sven at fail0verflow.com>
+ * Copyright (C) 2010 Haxx Enterprises <bushing at gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ *  THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_ZEROPLUS_LOGIC_CUBE_ANALYZER_H
+#define LIBSIGROK_HARDWARE_ZEROPLUS_LOGIC_CUBE_ANALYZER_H
+
+#include <libusb.h>
+#include "libsigrok.h"
+
+#define STATUS_FLAG_NONE	0x00
+#define STATUS_FLAG_RESET	0x01
+#define STATUS_FLAG_INIT	0x02
+#define STATUS_FLAG_GO		0x04
+#define STATUS_FLAG_PAUSE	0x08
+#define STATUS_FLAG_READ	0x10
+#define STATUS_FLAG_20		0x20
+
+/* In bytes */
+#define MEMORY_SIZE_8K		0x00
+#define MEMORY_SIZE_64K		0x01
+#define MEMORY_SIZE_128K	0x02
+#define MEMORY_SIZE_256K	0x03
+#define MEMORY_SIZE_512K	0x04
+#define MEMORY_SIZE_1M		0x05
+#define MEMORY_SIZE_2M		0x06
+#define MEMORY_SIZE_4M		0x07
+#define MEMORY_SIZE_8M		0x08
+
+#define STATUS_BUSY		0x01	/* WTF / ??? */
+#define STATUS_READY		0x02
+#define STATUS_BUTTON_PRESSED	0x04
+
+#define CHANNEL_A		0x1000
+#define CHANNEL_B		0x2000
+#define CHANNEL_C		0x3000
+#define CHANNEL_D		0x4000
+
+#define FREQ_SCALE_HZ		0
+#define FREQ_SCALE_KHZ		1
+#define FREQ_SCALE_MHZ		2
+
+#define FILTER_HIGH		0
+#define FILTER_LOW		1
+
+#define COMPRESSION_NONE	0x0001
+#define COMPRESSION_ENABLE	0x8001
+#define COMPRESSION_DOUBLE	0x8002
+
+enum {
+	TRIGGER_HIGH = 0,
+	TRIGGER_LOW,
+	TRIGGER_POSEDGE,
+	TRIGGER_NEGEDGE,
+	TRIGGER_ANYEDGE,
+};
+
+SR_PRIV void analyzer_set_freq(int freq, int scale);
+SR_PRIV void analyzer_set_ramsize_trigger_address(unsigned int address);
+SR_PRIV void analyzer_set_triggerbar_address(unsigned int address);
+SR_PRIV unsigned int  analyzer_get_ramsize_trigger_address(void );
+SR_PRIV unsigned int analyzer_get_triggerbar_address(void);
+SR_PRIV void analyzer_set_compression(unsigned int type);
+SR_PRIV void analyzer_set_memory_size(unsigned int size);
+SR_PRIV void analyzer_add_trigger(int channel, int type);
+SR_PRIV void analyzer_set_trigger_count(int count);
+SR_PRIV void analyzer_add_filter(int channel, int type);
+SR_PRIV void analyzer_set_voltage_threshold(int thresh);
+
+SR_PRIV unsigned int analyzer_read_status(libusb_device_handle *devh);
+SR_PRIV unsigned int analyzer_read_id(libusb_device_handle *devh);
+SR_PRIV unsigned int analyzer_get_stop_address(libusb_device_handle *devh);
+SR_PRIV unsigned int analyzer_get_now_address(libusb_device_handle *devh);
+SR_PRIV unsigned int analyzer_get_trigger_address(libusb_device_handle *devh);
+SR_PRIV int analyzer_decompress(void *input, unsigned int input_len,
+				void *output, unsigned int output_len);
+
+SR_PRIV void analyzer_reset(libusb_device_handle *devh);
+SR_PRIV void analyzer_initialize(libusb_device_handle *devh);
+SR_PRIV void analyzer_wait(libusb_device_handle *devh, int set, int unset);
+SR_PRIV void analyzer_read_start(libusb_device_handle *devh);
+SR_PRIV int analyzer_read_data(libusb_device_handle *devh, void *buffer,
+			       unsigned int size);
+SR_PRIV void analyzer_read_stop(libusb_device_handle *devh);
+SR_PRIV void analyzer_start(libusb_device_handle *devh);
+SR_PRIV void analyzer_configure(libusb_device_handle *devh);
+
+SR_PRIV void analyzer_wait_button(libusb_device_handle *devh);
+SR_PRIV void analyzer_wait_data(libusb_device_handle *devh);
+
+#endif
diff --git a/hardware/zeroplus-logic-cube/api.c b/hardware/zeroplus-logic-cube/api.c
new file mode 100644
index 0000000..34213e7
--- /dev/null
+++ b/hardware/zeroplus-logic-cube/api.c
@@ -0,0 +1,835 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010-2012 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "protocol.h"
+
+#define VENDOR_NAME			"ZEROPLUS"
+#define USB_INTERFACE			0
+#define USB_CONFIGURATION		1
+#define NUM_TRIGGER_STAGES		4
+#define TRIGGER_TYPE 			"01"
+#define PACKET_SIZE			2048	/* ?? */
+
+//#define ZP_EXPERIMENTAL
+
+struct zp_model {
+	uint16_t vid;
+	uint16_t pid;
+	char *model_name;
+	unsigned int channels;
+	unsigned int sample_depth;	/* In Ksamples/channel */
+	unsigned int max_sampling_freq;
+};
+
+/*
+ * Note -- 16032, 16064 and 16128 *usually* -- but not always -- have the
+ * same 128K sample depth.
+ */
+static const struct zp_model zeroplus_models[] = {
+	{0x0c12, 0x7002, "LAP-16128U",    16, 128,  200},
+	{0x0c12, 0x7009, "LAP-C(16064)",  16, 64,   100},
+	{0x0c12, 0x700a, "LAP-C(16128)",  16, 128,  200},
+	{0x0c12, 0x700b, "LAP-C(32128)",  32, 128,  200},
+	{0x0c12, 0x700c, "LAP-C(321000)", 32, 1024, 200},
+	{0x0c12, 0x700d, "LAP-C(322000)", 32, 2048, 200},
+	{0x0c12, 0x700e, "LAP-C(16032)",  16, 32,   100},
+	{0x0c12, 0x7016, "LAP-C(162000)", 16, 2048, 200},
+	{ 0, 0, 0, 0, 0, 0 }
+};
+
+static const int32_t hwcaps[] = {
+	SR_CONF_LOGIC_ANALYZER,
+	SR_CONF_SAMPLERATE,
+	SR_CONF_TRIGGER_TYPE,
+	SR_CONF_CAPTURE_RATIO,
+	SR_CONF_VOLTAGE_THRESHOLD,
+	SR_CONF_LIMIT_SAMPLES,
+};
+
+/*
+ * ZEROPLUS LAP-C (16032) numbers the 16 channels A0-A7 and B0-B7.
+ * We currently ignore other untested/unsupported devices here.
+ */
+static const char *channel_names[] = {
+	"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
+	"B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7",
+	"C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7",
+	"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
+	NULL,
+};
+
+SR_PRIV struct sr_dev_driver zeroplus_logic_cube_driver_info;
+static struct sr_dev_driver *di = &zeroplus_logic_cube_driver_info;
+
+/*
+ * The hardware supports more samplerates than these, but these are the
+ * options hardcoded into the vendor's Windows GUI.
+ */
+
+static const uint64_t samplerates_100[] = {
+	SR_HZ(100),
+	SR_HZ(500),
+	SR_KHZ(1),
+	SR_KHZ(5),
+	SR_KHZ(25),
+	SR_KHZ(50),
+	SR_KHZ(100),
+	SR_KHZ(200),
+	SR_KHZ(400),
+	SR_KHZ(800),
+	SR_MHZ(1),
+	SR_MHZ(10),
+	SR_MHZ(25),
+	SR_MHZ(50),
+	SR_MHZ(80),
+	SR_MHZ(100),
+};
+
+const uint64_t samplerates_200[] = {
+	SR_HZ(100),
+	SR_HZ(500),
+	SR_KHZ(1),
+	SR_KHZ(5),
+	SR_KHZ(25),
+	SR_KHZ(50),
+	SR_KHZ(100),
+	SR_KHZ(200),
+	SR_KHZ(400),
+	SR_KHZ(800),
+	SR_MHZ(1),
+	SR_MHZ(10),
+	SR_MHZ(25),
+	SR_MHZ(50),
+	SR_MHZ(80),
+	SR_MHZ(100),
+	SR_MHZ(150),
+	SR_MHZ(200),
+};
+
+static int dev_close(struct sr_dev_inst *sdi);
+
+#if 0
+static int configure_channels(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	const struct sr_channel *ch;
+	const GSList *l;
+	int channel_bit, stage, i;
+	char *tc;
+
+	/* Note: sdi and sdi->priv are non-NULL, the caller checked this. */
+	devc = sdi->priv;
+
+	devc->channel_mask = 0;
+	for (i = 0; i < NUM_TRIGGER_STAGES; i++) {
+		devc->trigger_mask[i] = 0;
+		devc->trigger_value[i] = 0;
+	}
+
+	stage = -1;
+	for (l = sdi->channels; l; l = l->next) {
+		ch = (struct sr_channel *)l->data;
+		if (ch->enabled == FALSE)
+			continue;
+		channel_bit = 1 << (ch->index);
+		devc->channel_mask |= channel_bit;
+
+		if (ch->trigger) {
+			stage = 0;
+			for (tc = ch->trigger; *tc; tc++) {
+				devc->trigger_mask[stage] |= channel_bit;
+				if (*tc == '1')
+					devc->trigger_value[stage] |= channel_bit;
+				stage++;
+				if (stage > NUM_TRIGGER_STAGES)
+					return SR_ERR;
+			}
+		}
+	}
+
+	return SR_OK;
+}
+#endif
+
+static int configure_channels(const struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	const GSList *l;
+	const struct sr_channel *ch;
+	char *tc;
+	int type;
+
+	/* Note: sdi and sdi->priv are non-NULL, the caller checked this. */
+	devc = sdi->priv;
+
+	for (l = sdi->channels; l; l = l->next) {
+		ch = (struct sr_channel *)l->data;
+		if (ch->enabled == FALSE)
+			continue;
+
+		if ((tc = ch->trigger)) {
+			switch (*tc) {
+			case '1':
+				type = TRIGGER_HIGH;
+				break;
+			case '0':
+				type = TRIGGER_LOW;
+				break;
+#if 0
+			case 'r':
+				type = TRIGGER_POSEDGE;
+				break;
+			case 'f':
+				type = TRIGGER_NEGEDGE;
+				break;
+			case 'c':
+				type = TRIGGER_ANYEDGE;
+				break;
+#endif
+			default:
+				return SR_ERR;
+			}
+			analyzer_add_trigger(ch->index, type);
+			devc->trigger = 1;
+		}
+	}
+
+	return SR_OK;
+}
+
+SR_PRIV int zp_set_samplerate(struct dev_context *devc, uint64_t samplerate)
+{
+	int i;
+
+	for (i = 0; ARRAY_SIZE(samplerates_200); i++)
+		if (samplerate == samplerates_200[i])
+			break;
+
+	if (i == ARRAY_SIZE(samplerates_200) || samplerate > devc->max_samplerate) {
+		sr_err("Unsupported samplerate: %" PRIu64 "Hz.", samplerate);
+		return SR_ERR_ARG;
+	}
+
+	sr_info("Setting samplerate to %" PRIu64 "Hz.", samplerate);
+
+	if (samplerate >= SR_MHZ(1))
+		analyzer_set_freq(samplerate / SR_MHZ(1), FREQ_SCALE_MHZ);
+	else if (samplerate >= SR_KHZ(1))
+		analyzer_set_freq(samplerate / SR_KHZ(1), FREQ_SCALE_KHZ);
+	else
+		analyzer_set_freq(samplerate, FREQ_SCALE_HZ);
+
+	devc->cur_samplerate = samplerate;
+
+	return SR_OK;
+}
+
+static int init(struct sr_context *sr_ctx)
+{
+	return std_init(sr_ctx, di, LOG_PREFIX);
+}
+
+static GSList *scan(GSList *options)
+{
+	struct sr_dev_inst *sdi;
+	struct sr_channel *ch;
+	struct drv_context *drvc;
+	struct dev_context *devc;
+	const struct zp_model *prof;
+	struct libusb_device_descriptor des;
+	libusb_device **devlist;
+	GSList *devices;
+	int ret, devcnt, i, j;
+
+	(void)options;
+
+	drvc = di->priv;
+
+	devices = NULL;
+
+	/* Find all ZEROPLUS analyzers and add them to device list. */
+	devcnt = 0;
+	libusb_get_device_list(drvc->sr_ctx->libusb_ctx, &devlist); /* TODO: Errors. */
+
+	for (i = 0; devlist[i]; i++) {
+		ret = libusb_get_device_descriptor(devlist[i], &des);
+		if (ret != 0) {
+			sr_err("Failed to get device descriptor: %s.",
+			       libusb_error_name(ret));
+			continue;
+		}
+
+		prof = NULL;
+		for (j = 0; j < zeroplus_models[j].vid; j++) {
+			if (des.idVendor == zeroplus_models[j].vid &&
+				des.idProduct == zeroplus_models[j].pid) {
+				prof = &zeroplus_models[j];
+			}
+		}
+		/* Skip if the device was not found. */
+		if (!prof)
+			continue;
+		sr_info("Found ZEROPLUS %s.", prof->model_name);
+
+		/* Register the device with libsigrok. */
+		if (!(sdi = sr_dev_inst_new(devcnt, SR_ST_INACTIVE,
+				VENDOR_NAME, prof->model_name, NULL))) {
+			sr_err("%s: sr_dev_inst_new failed", __func__);
+			return NULL;
+		}
+		sdi->driver = di;
+
+		/* Allocate memory for our private driver context. */
+		if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+			sr_err("Device context malloc failed.");
+			return NULL;
+		}
+
+		sdi->priv = devc;
+		devc->prof = prof;
+		devc->num_channels = prof->channels;
+#ifdef ZP_EXPERIMENTAL
+		devc->max_sample_depth = 128 * 1024;
+		devc->max_samplerate = 200;
+#else
+		devc->max_sample_depth = prof->sample_depth * 1024;
+		devc->max_samplerate = prof->max_sampling_freq;
+#endif
+		devc->max_samplerate *= SR_MHZ(1);
+		devc->memory_size = MEMORY_SIZE_8K;
+		// memset(devc->trigger_buffer, 0, NUM_TRIGGER_STAGES);
+
+		/* Fill in channellist according to this device's profile. */
+		for (j = 0; j < devc->num_channels; j++) {
+			if (!(ch = sr_channel_new(j, SR_CHANNEL_LOGIC, TRUE,
+					channel_names[j])))
+				return NULL;
+			sdi->channels = g_slist_append(sdi->channels, ch);
+		}
+
+		devices = g_slist_append(devices, sdi);
+		drvc->instances = g_slist_append(drvc->instances, sdi);
+		sdi->inst_type = SR_INST_USB;
+		sdi->conn = sr_usb_dev_inst_new(
+			libusb_get_bus_number(devlist[i]),
+			libusb_get_device_address(devlist[i]), NULL);
+		devcnt++;
+
+	}
+	libusb_free_device_list(devlist, 1);
+
+	return devices;
+}
+
+static GSList *dev_list(void)
+{
+	return ((struct drv_context *)(di->priv))->instances;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+	struct dev_context *devc;
+	struct drv_context *drvc;
+	struct sr_usb_dev_inst *usb;
+	libusb_device **devlist, *dev;
+	struct libusb_device_descriptor des;
+	int device_count, ret, i;
+
+	drvc = di->priv;
+	usb = sdi->conn;
+
+	if (!(devc = sdi->priv)) {
+		sr_err("%s: sdi->priv was NULL", __func__);
+		return SR_ERR_ARG;
+	}
+
+	device_count = libusb_get_device_list(drvc->sr_ctx->libusb_ctx,
+					      &devlist);
+	if (device_count < 0) {
+		sr_err("Failed to retrieve device list.");
+		return SR_ERR;
+	}
+
+	dev = NULL;
+	for (i = 0; i < device_count; i++) {
+		if ((ret = libusb_get_device_descriptor(devlist[i], &des))) {
+			sr_err("Failed to get device descriptor: %s.",
+			       libusb_error_name(ret));
+			continue;
+		}
+		if (libusb_get_bus_number(devlist[i]) == usb->bus
+		    && libusb_get_device_address(devlist[i]) == usb->address) {
+			dev = devlist[i];
+			break;
+		}
+	}
+	if (!dev) {
+		sr_err("Device on bus %d address %d disappeared!",
+		       usb->bus, usb->address);
+		return SR_ERR;
+	}
+
+	if (!(ret = libusb_open(dev, &(usb->devhdl)))) {
+		sdi->status = SR_ST_ACTIVE;
+		sr_info("Opened device %d on %d.%d interface %d.",
+			sdi->index, usb->bus, usb->address, USB_INTERFACE);
+	} else {
+		sr_err("Failed to open device: %s.", libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	ret = libusb_set_configuration(usb->devhdl, USB_CONFIGURATION);
+	if (ret < 0) {
+		sr_err("Unable to set USB configuration %d: %s.",
+		       USB_CONFIGURATION, libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE);
+	if (ret != 0) {
+		sr_err("Unable to claim interface: %s.",
+		       libusb_error_name(ret));
+		return SR_ERR;
+	}
+
+	/* Set default configuration after power on. */
+	if (analyzer_read_status(usb->devhdl) == 0)
+		analyzer_configure(usb->devhdl);
+
+	analyzer_reset(usb->devhdl);
+	analyzer_initialize(usb->devhdl);
+
+	//analyzer_set_memory_size(MEMORY_SIZE_512K);
+	// analyzer_set_freq(g_freq, g_freq_scale);
+	analyzer_set_trigger_count(1);
+	// analyzer_set_ramsize_trigger_address((((100 - g_pre_trigger)
+	// * get_memory_size(g_memory_size)) / 100) >> 2);
+
+#if 0
+	if (g_double_mode == 1)
+		analyzer_set_compression(COMPRESSION_DOUBLE);
+	else if (g_compression == 1)
+		analyzer_set_compression(COMPRESSION_ENABLE);
+	else
+#endif
+	analyzer_set_compression(COMPRESSION_NONE);
+
+	if (devc->cur_samplerate == 0) {
+		/* Samplerate hasn't been set. Default to 1MHz. */
+		analyzer_set_freq(1, FREQ_SCALE_MHZ);
+		devc->cur_samplerate = SR_MHZ(1);
+	}
+
+	if (devc->cur_threshold == 0)
+		set_voltage_threshold(devc, 1.5);
+
+	return SR_OK;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+	struct sr_usb_dev_inst *usb;
+
+	usb = sdi->conn;
+
+	if (!usb->devhdl)
+		return SR_ERR;
+
+	sr_info("Closing device %d on %d.%d interface %d.", sdi->index,
+		usb->bus, usb->address, USB_INTERFACE);
+	libusb_release_interface(usb->devhdl, USB_INTERFACE);
+	libusb_reset_device(usb->devhdl);
+	libusb_close(usb->devhdl);
+	usb->devhdl = NULL;
+	sdi->status = SR_ST_INACTIVE;
+
+	return SR_OK;
+}
+
+static int cleanup(void)
+{
+	return std_dev_clear(di, NULL);
+}
+
+static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+
+	(void)cg;
+
+	switch (id) {
+	case SR_CONF_SAMPLERATE:
+		if (sdi) {
+			devc = sdi->priv;
+			*data = g_variant_new_uint64(devc->cur_samplerate);
+			sr_spew("Returning samplerate: %" PRIu64 "Hz.",
+				devc->cur_samplerate);
+		} else
+			return SR_ERR_ARG;
+		break;
+	case SR_CONF_CAPTURE_RATIO:
+		if (sdi) {
+			devc = sdi->priv;
+			*data = g_variant_new_uint64(devc->capture_ratio);
+		} else
+			return SR_ERR_ARG;
+		break;
+	case SR_CONF_VOLTAGE_THRESHOLD:
+		if (sdi) {
+			GVariant *range[2];
+			devc = sdi->priv;
+			range[0] = g_variant_new_double(devc->cur_threshold);
+			range[1] = g_variant_new_double(devc->cur_threshold);
+			*data = g_variant_new_tuple(range, 2);
+		} else
+			return SR_ERR_ARG;
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	gdouble low, high;
+
+	(void)cg;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!(devc = sdi->priv)) {
+		sr_err("%s: sdi->priv was NULL", __func__);
+		return SR_ERR_ARG;
+	}
+
+	switch (id) {
+	case SR_CONF_SAMPLERATE:
+		return zp_set_samplerate(devc, g_variant_get_uint64(data));
+	case SR_CONF_LIMIT_SAMPLES:
+		return set_limit_samples(devc, g_variant_get_uint64(data));
+	case SR_CONF_CAPTURE_RATIO:
+		return set_capture_ratio(devc, g_variant_get_uint64(data));
+	case SR_CONF_VOLTAGE_THRESHOLD:
+		g_variant_get(data, "(dd)", &low, &high);
+		return set_voltage_threshold(devc, (low + high) / 2.0);
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct dev_context *devc;
+	GVariant *gvar, *grange[2];
+	GVariantBuilder gvb;
+	double v;
+	GVariant *range[2];
+
+	(void)cg;
+
+	switch (key) {
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+		break;
+	case SR_CONF_SAMPLERATE:
+		devc = sdi->priv;
+		g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
+		if (devc->prof->max_sampling_freq == 100) {
+			gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
+					samplerates_100, ARRAY_SIZE(samplerates_100),
+					sizeof(uint64_t));
+		} else if (devc->prof->max_sampling_freq == 200) {
+			gvar = g_variant_new_fixed_array(G_VARIANT_TYPE("t"),
+					samplerates_200, ARRAY_SIZE(samplerates_200),
+					sizeof(uint64_t));
+		} else {
+			sr_err("Internal error: Unknown max. samplerate: %d.",
+			       devc->prof->max_sampling_freq);
+			return SR_ERR_ARG;
+		}
+		g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar);
+		*data = g_variant_builder_end(&gvb);
+		break;
+	case SR_CONF_TRIGGER_TYPE:
+		*data = g_variant_new_string(TRIGGER_TYPE);
+		break;
+	case SR_CONF_VOLTAGE_THRESHOLD:
+		g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
+		for (v = -6.0; v <= 6.0; v += 0.1) {
+			range[0] = g_variant_new_double(v);
+			range[1] = g_variant_new_double(v);
+			gvar = g_variant_new_tuple(range, 2);
+			g_variant_builder_add_value(&gvb, gvar);
+		}
+		*data = g_variant_builder_end(&gvb);
+		break;
+	case SR_CONF_LIMIT_SAMPLES:
+		if (!sdi)
+			return SR_ERR_ARG;
+		devc = sdi->priv;
+		grange[0] = g_variant_new_uint64(0);
+		grange[1] = g_variant_new_uint64(devc->max_sample_depth);
+		*data = g_variant_new_tuple(grange, 2);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi,
+		void *cb_data)
+{
+	struct dev_context *devc;
+	struct sr_usb_dev_inst *usb;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_logic logic;
+	unsigned int samples_read;
+	int res;
+	unsigned int packet_num, n;
+	unsigned char *buf;
+	unsigned int status;
+	unsigned int stop_address;
+	unsigned int now_address;
+	unsigned int trigger_address;
+	unsigned int trigger_offset;
+	unsigned int triggerbar;
+	unsigned int ramsize_trigger;
+	unsigned int memory_size;
+	unsigned int valid_samples;
+	unsigned int discard;
+	int trigger_now;
+
+	if (sdi->status != SR_ST_ACTIVE)
+		return SR_ERR_DEV_CLOSED;
+
+	if (!(devc = sdi->priv)) {
+		sr_err("%s: sdi->priv was NULL", __func__);
+		return SR_ERR_ARG;
+	}
+
+	if (configure_channels(sdi) != SR_OK) {
+		sr_err("Failed to configure channels.");
+		return SR_ERR;
+	}
+
+	usb = sdi->conn;
+
+	set_triggerbar(devc);
+
+	/* Push configured settings to device. */
+	analyzer_configure(usb->devhdl);
+
+	analyzer_start(usb->devhdl);
+	sr_info("Waiting for data.");
+	analyzer_wait_data(usb->devhdl);
+
+	status = analyzer_read_status(usb->devhdl);
+	stop_address = analyzer_get_stop_address(usb->devhdl);
+	now_address = analyzer_get_now_address(usb->devhdl);
+	trigger_address = analyzer_get_trigger_address(usb->devhdl);
+
+	triggerbar = analyzer_get_triggerbar_address();
+	ramsize_trigger = analyzer_get_ramsize_trigger_address();
+
+	n = get_memory_size(devc->memory_size);
+	memory_size = n / 4;
+
+	sr_info("Status = 0x%x.", status);
+	sr_info("Stop address       = 0x%x.", stop_address);
+	sr_info("Now address        = 0x%x.", now_address);
+	sr_info("Trigger address    = 0x%x.", trigger_address);
+	sr_info("Triggerbar address = 0x%x.", triggerbar);
+	sr_info("Ramsize trigger    = 0x%x.", ramsize_trigger);
+	sr_info("Memory size        = 0x%x.", memory_size);
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	/* Check for empty capture */
+	if ((status & STATUS_READY) && !stop_address) {
+		packet.type = SR_DF_END;
+		sr_session_send(cb_data, &packet);
+		return SR_OK;
+	}
+
+	if (!(buf = g_try_malloc(PACKET_SIZE))) {
+		sr_err("Packet buffer malloc failed.");
+		return SR_ERR_MALLOC;
+	}
+
+	/* Check if the trigger is in the samples we are throwing away */
+	trigger_now = now_address == trigger_address ||
+		((now_address + 1) % memory_size) == trigger_address;
+
+	/*
+	 * STATUS_READY doesn't clear until now_address advances past
+	 * addr 0, but for our logic, clear it in that case
+	 */
+	if (!now_address)
+		status &= ~STATUS_READY;
+
+	analyzer_read_start(usb->devhdl);
+
+	/* Calculate how much data to discard */
+	discard = 0;
+	if (status & STATUS_READY) {
+		/*
+		 * We haven't wrapped around, we need to throw away data from
+		 * our current position to the end of the buffer.
+		 * Additionally, the first two samples captured are always
+		 * bogus.
+		 */
+		discard += memory_size - now_address + 2;
+		now_address = 2;
+	}
+
+	/* If we have more samples than we need, discard them */
+	valid_samples = (stop_address - now_address) % memory_size;
+	if (valid_samples > ramsize_trigger + triggerbar) {
+		discard += valid_samples - (ramsize_trigger + triggerbar);
+		now_address += valid_samples - (ramsize_trigger + triggerbar);
+	}
+
+	sr_info("Need to discard %d samples.", discard);
+
+	/* Calculate how far in the trigger is */
+	if (trigger_now)
+		trigger_offset = 0;
+	else
+		trigger_offset = (trigger_address - now_address) % memory_size;
+
+	/* Recalculate the number of samples available */
+	valid_samples = (stop_address - now_address) % memory_size;
+
+	/* Send the incoming transfer to the session bus. */
+	samples_read = 0;
+	for (packet_num = 0; packet_num < n / PACKET_SIZE; packet_num++) {
+		unsigned int len;
+		unsigned int buf_offset;
+
+		res = analyzer_read_data(usb->devhdl, buf, PACKET_SIZE);
+		sr_info("Tried to read %d bytes, actually read %d bytes.",
+			PACKET_SIZE, res);
+
+		if (discard >= PACKET_SIZE / 4) {
+			discard -= PACKET_SIZE / 4;
+			continue;
+		}
+
+		len = PACKET_SIZE - discard * 4;
+		buf_offset = discard * 4;
+		discard = 0;
+
+		/* Check if we've read all the samples */
+		if (samples_read + len / 4 >= valid_samples)
+			len = (valid_samples - samples_read) * 4;
+		if (!len)
+			break;
+
+		if (samples_read < trigger_offset &&
+		    samples_read + len / 4 > trigger_offset) {
+			/* Send out samples remaining before trigger */
+			packet.type = SR_DF_LOGIC;
+			packet.payload = &logic;
+			logic.length = (trigger_offset - samples_read) * 4;
+			logic.unitsize = 4;
+			logic.data = buf + buf_offset;
+			sr_session_send(cb_data, &packet);
+			len -= logic.length;
+			samples_read += logic.length / 4;
+			buf_offset += logic.length;
+		}
+
+		if (samples_read == trigger_offset) {
+			/* Send out trigger */
+			packet.type = SR_DF_TRIGGER;
+			packet.payload = NULL;
+			sr_session_send(cb_data, &packet);
+		}
+
+		/* Send out data (or data after trigger) */
+		packet.type = SR_DF_LOGIC;
+		packet.payload = &logic;
+		logic.length = len;
+		logic.unitsize = 4;
+		logic.data = buf + buf_offset;
+		sr_session_send(cb_data, &packet);
+		samples_read += len / 4;
+	}
+	analyzer_read_stop(usb->devhdl);
+	g_free(buf);
+
+	packet.type = SR_DF_END;
+	sr_session_send(cb_data, &packet);
+
+	return SR_OK;
+}
+
+/* TODO: This stops acquisition on ALL devices, ignoring dev_index. */
+static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct dev_context *devc;
+	struct sr_usb_dev_inst *usb;
+	struct sr_datafeed_packet packet;
+
+	packet.type = SR_DF_END;
+	sr_session_send(cb_data, &packet);
+
+	if (!(devc = sdi->priv)) {
+		sr_err("%s: sdi->priv was NULL", __func__);
+		return SR_ERR_BUG;
+	}
+
+	usb = sdi->conn;
+	analyzer_reset(usb->devhdl);
+	/* TODO: Need to cancel and free any queued up transfers. */
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_dev_driver zeroplus_logic_cube_driver_info = {
+	.name = "zeroplus-logic-cube",
+	.longname = "ZEROPLUS Logic Cube LAP-C series",
+	.api_version = 1,
+	.init = init,
+	.cleanup = cleanup,
+	.scan = scan,
+	.dev_list = dev_list,
+	.dev_clear = NULL,
+	.config_get = config_get,
+	.config_set = config_set,
+	.config_list = config_list,
+	.dev_open = dev_open,
+	.dev_close = dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = dev_acquisition_stop,
+	.priv = NULL,
+};
diff --git a/hardware/zeroplus-logic-cube/gl_usb.c b/hardware/zeroplus-logic-cube/gl_usb.c
new file mode 100644
index 0000000..2099328
--- /dev/null
+++ b/hardware/zeroplus-logic-cube/gl_usb.c
@@ -0,0 +1,152 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010 Sven Peter <sven at fail0verflow.com>
+ * Copyright (C) 2010 Haxx Enterprises <bushing at gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ *  THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <libusb.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "gl_usb.h"
+#include "protocol.h"
+
+#define CTRL_IN		(LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN | \
+			 LIBUSB_RECIPIENT_INTERFACE)
+#define CTRL_OUT	(LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT | \
+			 LIBUSB_RECIPIENT_INTERFACE)
+#define EP1_BULK_IN	(LIBUSB_ENDPOINT_IN | 1)
+
+#define TIMEOUT		5000	/* Timeout in ms */
+
+enum {
+	REQ_READBULK = 0x82,
+	REQ_WRITEADDR,
+	REQ_READDATA,
+	REQ_WRITEDATA,
+};
+
+static int gl_write_address(libusb_device_handle *devh, unsigned int address)
+{
+	unsigned char packet[8] = { address & 0xFF };
+	int ret;
+
+	ret = libusb_control_transfer(devh, CTRL_OUT, 0xc, REQ_WRITEADDR,
+					 0, packet, 1, TIMEOUT);
+	if (ret != 1)
+		sr_err("%s: %s.", __func__, libusb_error_name(ret));
+	return ret;
+}
+
+static int gl_write_data(libusb_device_handle *devh, unsigned int val)
+{
+	unsigned char packet[8] = { val & 0xFF };
+	int ret;
+
+	ret = libusb_control_transfer(devh, CTRL_OUT, 0xc, REQ_WRITEDATA,
+				      0, packet, 1, TIMEOUT);
+	if (ret != 1)
+		sr_err("%s: %s.", __func__, libusb_error_name(ret));
+	return ret;
+}
+
+static int gl_read_data(libusb_device_handle *devh)
+{
+	unsigned char packet[8] = { 0 };
+	int ret;
+
+	ret = libusb_control_transfer(devh, CTRL_IN, 0xc, REQ_READDATA,
+				      0, packet, 1, TIMEOUT);
+	if (ret != 1)
+		sr_err("%s: %s, val=%hhx.", __func__,
+		       libusb_error_name(ret), packet[0]);
+	return (ret == 1) ? packet[0] : ret;
+}
+
+SR_PRIV int gl_read_bulk(libusb_device_handle *devh, void *buffer,
+			 unsigned int size)
+{
+	unsigned char packet[8] =
+	    { 0, 0, 0, 0, size & 0xff, (size & 0xff00) >> 8,
+	      (size & 0xff0000) >> 16, (size & 0xff000000) >> 24 };
+	int ret, transferred = 0;
+
+	ret = libusb_control_transfer(devh, CTRL_OUT, 0x4, REQ_READBULK,
+				      0, packet, 8, TIMEOUT);
+	if (ret != 8)
+		sr_err("%s: libusb_control_transfer: %s.", __func__,
+		       libusb_error_name(ret));
+
+	ret = libusb_bulk_transfer(devh, EP1_BULK_IN, buffer, size,
+				   &transferred, TIMEOUT);
+	if (ret < 0)
+		sr_err("%s: libusb_bulk_transfer: %s.", __func__,
+		       libusb_error_name(ret));
+	return transferred;
+}
+
+SR_PRIV int gl_reg_write(libusb_device_handle *devh, unsigned int reg,
+		 unsigned int val)
+{
+	int ret;
+
+	ret = gl_write_address(devh, reg);
+	if (ret < 0)
+		return ret;
+	ret = gl_write_data(devh, val);
+	return ret;
+}
+
+SR_PRIV int gl_reg_read(libusb_device_handle *devh, unsigned int reg)
+{
+	int ret;
+
+	ret = gl_write_address(devh, reg);
+	if (ret < 0)
+		return ret;
+	ret = gl_read_data(devh);
+	return ret;
+}
+
+SR_PRIV int gl_reg_read_buf(libusb_device_handle *devh, unsigned int reg,
+		unsigned char *buf, unsigned int len)
+{
+	int ret;
+	unsigned int i;
+
+	ret = gl_write_address(devh, reg);
+	if (ret < 0)
+		return ret;
+	for (i = 0; i < len; i++) {
+		ret = gl_read_data(devh);
+		if (ret < 0)
+			return ret;
+		buf[i] = ret;
+	}
+	return 0;
+}
diff --git a/hardware/zeroplus-logic-cube/gl_usb.h b/hardware/zeroplus-logic-cube/gl_usb.h
new file mode 100644
index 0000000..c3a33fb
--- /dev/null
+++ b/hardware/zeroplus-logic-cube/gl_usb.h
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010 Sven Peter <sven at fail0verflow.com>
+ * Copyright (C) 2010 Haxx Enterprises <bushing at gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ *  THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LIBSIGROK_HARDWARE_ZEROPLUS_LOGIC_CUBE_GL_USB_H
+#define LIBSIGROK_HARDWARE_ZEROPLUS_LOGIC_CUBE_GL_USB_H
+
+#include <libusb.h>
+#include "libsigrok.h"
+
+SR_PRIV int gl_read_bulk(libusb_device_handle *devh, void *buffer,
+			 unsigned int size);
+SR_PRIV int gl_reg_write(libusb_device_handle *devh, unsigned int reg,
+			 unsigned int val);
+SR_PRIV int gl_reg_read(libusb_device_handle *devh, unsigned int reg);
+SR_PRIV int gl_reg_read_buf(libusb_device_handle *devh, unsigned int reg,
+			unsigned char *buf, unsigned int len);
+#endif
diff --git a/hardware/zeroplus-logic-cube/protocol.c b/hardware/zeroplus-logic-cube/protocol.c
new file mode 100644
index 0000000..ce20ccf
--- /dev/null
+++ b/hardware/zeroplus-logic-cube/protocol.c
@@ -0,0 +1,139 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010-2012 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <math.h>
+#include "protocol.h"
+
+SR_PRIV unsigned int get_memory_size(int type)
+{
+	if (type == MEMORY_SIZE_8K)
+		return 8 * 1024;
+	else if (type <= MEMORY_SIZE_8M)
+		return (32 * 1024) << type;
+	else
+		return 0;
+}
+
+static int clz(unsigned int x)
+{
+	int n = 0;
+	if (x == 0)
+		return 32;
+	if (!(x & 0xFFFF0000)) {
+		n = n + 16;
+		x = x << 16;
+	}
+	if (!(x & 0xFF000000)) {
+		n = n + 8;
+		x = x << 8;
+	}
+	if (!(x & 0xF0000000)) {
+		n = n + 4;
+		x = x << 4;
+	}
+	if (!(x & 0xC0000000)) {
+		n = n + 2;
+		x = x << 2;
+	}
+	if (!(x & 0x80000000))
+		n = n + 1;
+	return n;
+}
+
+SR_PRIV int set_limit_samples(struct dev_context *devc, uint64_t samples)
+{
+	if (samples > devc->max_sample_depth)
+		samples = devc->max_sample_depth;
+
+	devc->limit_samples = samples;
+
+	if (samples <= 2 * 1024)
+		devc->memory_size = MEMORY_SIZE_8K;
+	else if (samples <= 16 * 1024)
+		devc->memory_size = MEMORY_SIZE_64K;
+	else
+		devc->memory_size = 19 - clz(samples - 1);
+
+	sr_info("Setting memory size to %dK.",
+		get_memory_size(devc->memory_size) / 1024);
+
+	analyzer_set_memory_size(devc->memory_size);
+
+	return SR_OK;
+}
+
+SR_PRIV int set_capture_ratio(struct dev_context *devc, uint64_t ratio)
+{
+	if (ratio > 100) {
+		sr_err("Invalid capture ratio: %" PRIu64 ".", ratio);
+		return SR_ERR_ARG;
+	}
+
+	devc->capture_ratio = ratio;
+
+	sr_info("Setting capture ratio to %d%%.", devc->capture_ratio);
+
+	return SR_OK;
+}
+
+SR_PRIV int set_voltage_threshold(struct dev_context *devc, double thresh)
+{
+	if (thresh > 6.0)
+		thresh = 6.0;
+	if (thresh < -6.0)
+		thresh = -6.0;
+
+	devc->cur_threshold = thresh;
+
+	analyzer_set_voltage_threshold((int) round(-9.1*thresh + 62.6));
+
+	sr_info("Setting voltage threshold to %fV.", devc->cur_threshold);
+
+	return SR_OK;
+}
+
+SR_PRIV void set_triggerbar(struct dev_context *devc)
+{
+	unsigned int trigger_depth, triggerbar, ramsize_trigger;
+
+	trigger_depth = get_memory_size(devc->memory_size) / 4;
+	if (devc->limit_samples < trigger_depth)
+		trigger_depth = devc->limit_samples;
+
+	if (devc->trigger)
+		triggerbar = trigger_depth * devc->capture_ratio / 100;
+	else
+		triggerbar = 0;
+
+	ramsize_trigger = trigger_depth - triggerbar;
+	/* Matches USB packet captures from official app/driver */
+	if (triggerbar > 2)
+		triggerbar -= 2;
+	else {
+		ramsize_trigger -= 1;
+		triggerbar = 0;
+	}
+
+	analyzer_set_triggerbar_address(triggerbar);
+	analyzer_set_ramsize_trigger_address(ramsize_trigger);
+
+	sr_dbg("triggerbar_address = %d(0x%x)", triggerbar, triggerbar);
+	sr_dbg("ramsize_triggerbar_address = %d(0x%x)",
+	       ramsize_trigger, ramsize_trigger);
+}
diff --git a/hardware/zeroplus-logic-cube/protocol.h b/hardware/zeroplus-logic-cube/protocol.h
new file mode 100644
index 0000000..4b55b33
--- /dev/null
+++ b/hardware/zeroplus-logic-cube/protocol.h
@@ -0,0 +1,58 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef LIBSIGROK_HARDWARE_ZEROPLUS_LOGIC_CUBE_PROTOCOL_H
+#define LIBSIGROK_HARDWARE_ZEROPLUS_LOGIC_CUBE_PROTOCOL_H
+
+#include <stdint.h>
+#include <glib.h>
+#include <libusb.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+#include "analyzer.h"
+
+#define LOG_PREFIX "zeroplus"
+
+/* Private, per-device-instance driver context. */
+struct dev_context {
+	uint64_t cur_samplerate;
+	uint64_t max_samplerate;
+	uint64_t limit_samples;
+	int num_channels;
+	int memory_size;
+	unsigned int max_sample_depth;
+	//uint8_t channel_mask;
+	//uint8_t trigger_mask[NUM_TRIGGER_STAGES];
+	//uint8_t trigger_value[NUM_TRIGGER_STAGES];
+	// uint8_t trigger_buffer[NUM_TRIGGER_STAGES];
+	int trigger;
+	unsigned int capture_ratio;
+	double cur_threshold;
+	const struct zp_model *prof;
+};
+
+SR_PRIV unsigned int get_memory_size(int type);
+SR_PRIV int zp_set_samplerate(struct dev_context *devc, uint64_t samplerate);
+SR_PRIV int set_limit_samples(struct dev_context *devc, uint64_t samples);
+SR_PRIV int set_capture_ratio(struct dev_context *devc, uint64_t ratio);
+SR_PRIV int set_voltage_threshold(struct dev_context *devc, double thresh);
+SR_PRIV void set_triggerbar(struct dev_context *devc);
+
+#endif
diff --git a/hwdriver.c b/hwdriver.c
new file mode 100644
index 0000000..f028ea1
--- /dev/null
+++ b/hwdriver.c
@@ -0,0 +1,796 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <string.h>
+#include <glib.h>
+#include "config.h" /* Needed for HAVE_LIBUSB_1_0 and others. */
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+/** @cond PRIVATE */
+#define LOG_PREFIX "hwdriver"
+/** @endcond */
+
+/**
+ * @file
+ *
+ * Hardware driver handling in libsigrok.
+ */
+
+/**
+ * @defgroup grp_driver Hardware drivers
+ *
+ * Hardware driver handling in libsigrok.
+ *
+ * @{
+ */
+
+static struct sr_config_info sr_config_info_data[] = {
+	{SR_CONF_CONN, SR_T_STRING, "conn",
+		"Connection", NULL},
+	{SR_CONF_SERIALCOMM, SR_T_STRING, "serialcomm",
+		"Serial communication", NULL},
+	{SR_CONF_SAMPLERATE, SR_T_UINT64, "samplerate",
+		"Sample rate", NULL},
+	{SR_CONF_CAPTURE_RATIO, SR_T_UINT64, "captureratio",
+		"Pre-trigger capture ratio", NULL},
+	{SR_CONF_PATTERN_MODE, SR_T_STRING, "pattern",
+		"Pattern", NULL},
+	{SR_CONF_TRIGGER_TYPE, SR_T_STRING, "triggertype",
+		"Trigger types", NULL},
+	{SR_CONF_EXTERNAL_CLOCK, SR_T_BOOL, "external_clock",
+		"External clock mode", NULL},
+	{SR_CONF_SWAP, SR_T_BOOL, "swap",
+		"Swap channel order", NULL},
+	{SR_CONF_RLE, SR_T_BOOL, "rle",
+		"Run Length Encoding", NULL},
+	{SR_CONF_TRIGGER_SLOPE, SR_T_STRING, "triggerslope",
+		"Trigger slope", NULL},
+	{SR_CONF_TRIGGER_SOURCE, SR_T_STRING, "triggersource",
+		"Trigger source", NULL},
+	{SR_CONF_HORIZ_TRIGGERPOS, SR_T_FLOAT, "horiz_triggerpos",
+		"Horizontal trigger position", NULL},
+	{SR_CONF_BUFFERSIZE, SR_T_UINT64, "buffersize",
+		"Buffer size", NULL},
+	{SR_CONF_TIMEBASE, SR_T_RATIONAL_PERIOD, "timebase",
+		"Time base", NULL},
+	{SR_CONF_FILTER, SR_T_STRING, "filter",
+		"Filter targets", NULL},
+	{SR_CONF_VDIV, SR_T_RATIONAL_VOLT, "vdiv",
+		"Volts/div", NULL},
+	{SR_CONF_COUPLING, SR_T_STRING, "coupling",
+		"Coupling", NULL},
+	{SR_CONF_DATALOG, SR_T_BOOL, "datalog",
+		"Datalog", NULL},
+	{SR_CONF_SPL_WEIGHT_FREQ, SR_T_STRING, "spl_weight_freq",
+		"Sound pressure level frequency weighting", NULL},
+	{SR_CONF_SPL_WEIGHT_TIME, SR_T_STRING, "spl_weight_time",
+		"Sound pressure level time weighting", NULL},
+	{SR_CONF_HOLD_MAX, SR_T_BOOL, "hold_max",
+		"Hold max", NULL},
+	{SR_CONF_HOLD_MIN, SR_T_BOOL, "hold_min",
+		"Hold min", NULL},
+	{SR_CONF_SPL_MEASUREMENT_RANGE, SR_T_UINT64_RANGE, "spl_meas_range",
+		"Sound pressure level measurement range", NULL},
+	{SR_CONF_VOLTAGE_THRESHOLD, SR_T_DOUBLE_RANGE, "voltage_threshold",
+		"Voltage threshold", NULL },
+	{SR_CONF_POWER_OFF, SR_T_BOOL, "power_off",
+		"Power off", NULL},
+	{SR_CONF_DATA_SOURCE, SR_T_STRING, "data_source",
+		"Data source", NULL},
+	{SR_CONF_NUM_LOGIC_CHANNELS, SR_T_INT32, "logic_channels",
+		"Number of logic channels", NULL},
+	{SR_CONF_NUM_ANALOG_CHANNELS, SR_T_INT32, "analog_channels",
+		"Number of analog channels", NULL},
+	{SR_CONF_OUTPUT_VOLTAGE, SR_T_FLOAT, "output_voltage",
+		"Current output voltage", NULL},
+	{SR_CONF_OUTPUT_VOLTAGE_MAX, SR_T_FLOAT, "output_voltage_max",
+		"Maximum output voltage", NULL},
+	{SR_CONF_OUTPUT_CURRENT, SR_T_FLOAT, "output_current",
+		"Current output current", NULL},
+	{SR_CONF_OUTPUT_CURRENT_MAX, SR_T_FLOAT, "output_current_max",
+		"Maximum output current", NULL},
+	{SR_CONF_OUTPUT_ENABLED, SR_T_BOOL, "output_enabled",
+		"Output enabled", NULL},
+	{SR_CONF_OUTPUT_CHANNEL, SR_T_STRING, "output_channel",
+		"Output channel modes", NULL},
+	{SR_CONF_OVER_VOLTAGE_PROTECTION, SR_T_BOOL, "ovp",
+		"Over-voltage protection", NULL},
+	{SR_CONF_OVER_CURRENT_PROTECTION, SR_T_BOOL, "ocp",
+		"Over-current protection", NULL},
+	{SR_CONF_LIMIT_SAMPLES, SR_T_UINT64, "limit_samples",
+		"Sample limit", NULL},
+	{SR_CONF_CLOCK_EDGE, SR_T_STRING, "clock_edge",
+		"Clock edge", NULL},
+	{0, 0, NULL, NULL, NULL},
+};
+
+/** @cond PRIVATE */
+#ifdef HAVE_HW_APPA_55II
+extern SR_PRIV struct sr_dev_driver appa_55ii_driver_info;
+#endif
+#ifdef HAVE_HW_ATTEN_PPS3XXX
+extern SR_PRIV struct sr_dev_driver atten_pps3203_driver_info;
+#endif
+#ifdef HAVE_HW_BRYMEN_BM86X
+extern SR_PRIV struct sr_dev_driver brymen_bm86x_driver_info;
+#endif
+#ifdef HAVE_HW_BRYMEN_DMM
+extern SR_PRIV struct sr_dev_driver brymen_bm857_driver_info;
+#endif
+#ifdef HAVE_HW_CEM_DT_885X
+extern SR_PRIV struct sr_dev_driver cem_dt_885x_driver_info;
+#endif
+#ifdef HAVE_HW_CENTER_3XX
+extern SR_PRIV struct sr_dev_driver center_309_driver_info;
+extern SR_PRIV struct sr_dev_driver voltcraft_k204_driver_info;
+#endif
+#ifdef HAVE_HW_COLEAD_SLM
+extern SR_PRIV struct sr_dev_driver colead_slm_driver_info;
+#endif
+#ifdef HAVE_HW_CONRAD_DIGI_35_CPU
+extern SR_PRIV struct sr_dev_driver conrad_digi_35_cpu_driver_info;
+#endif
+#ifdef HAVE_HW_DEMO
+extern SR_PRIV struct sr_dev_driver demo_driver_info;
+#endif
+#ifdef HAVE_HW_GMC_MH_1X_2X
+extern SR_PRIV struct sr_dev_driver gmc_mh_1x_2x_rs232_driver_info;
+extern SR_PRIV struct sr_dev_driver gmc_mh_2x_bd232_driver_info;
+#endif
+#ifdef HAVE_HW_HAMEG_HMO
+extern SR_PRIV struct sr_dev_driver hameg_hmo_driver_info;
+#endif
+#ifdef HAVE_HW_IKALOGIC_SCANALOGIC2
+extern SR_PRIV struct sr_dev_driver ikalogic_scanalogic2_driver_info;
+#endif
+#ifdef HAVE_HW_IKALOGIC_SCANAPLUS
+extern SR_PRIV struct sr_dev_driver ikalogic_scanaplus_driver_info;
+#endif
+#ifdef HAVE_HW_KECHENG_KC_330B
+extern SR_PRIV struct sr_dev_driver kecheng_kc_330b_driver_info;
+#endif
+#ifdef HAVE_HW_LASCAR_EL_USB
+extern SR_PRIV struct sr_dev_driver lascar_el_usb_driver_info;
+#endif
+#ifdef HAVE_HW_MIC_985XX
+extern SR_PRIV struct sr_dev_driver mic_98581_driver_info;
+extern SR_PRIV struct sr_dev_driver mic_98583_driver_info;
+#endif
+#ifdef HAVE_HW_NORMA_DMM
+extern SR_PRIV struct sr_dev_driver norma_dmm_driver_info;
+#endif
+#ifdef HAVE_HW_OLS
+extern SR_PRIV struct sr_dev_driver ols_driver_info;
+#endif
+#ifdef HAVE_HW_RIGOL_DS
+extern SR_PRIV struct sr_dev_driver rigol_ds_driver_info;
+#endif
+#ifdef HAVE_HW_SALEAE_LOGIC16
+extern SR_PRIV struct sr_dev_driver saleae_logic16_driver_info;
+#endif
+#ifdef HAVE_HW_SYSCLK_LWLA
+extern SR_PRIV struct sr_dev_driver sysclk_lwla_driver_info;
+#endif
+#ifdef HAVE_HW_TELEINFO
+extern SR_PRIV struct sr_dev_driver teleinfo_driver_info;
+#endif
+#ifdef HAVE_HW_TONDAJ_SL_814
+extern SR_PRIV struct sr_dev_driver tondaj_sl_814_driver_info;
+#endif
+#ifdef HAVE_HW_UNI_T_UT32X
+extern SR_PRIV struct sr_dev_driver uni_t_ut32x_driver_info;
+#endif
+#ifdef HAVE_HW_VICTOR_DMM
+extern SR_PRIV struct sr_dev_driver victor_dmm_driver_info;
+#endif
+#ifdef HAVE_HW_ZEROPLUS_LOGIC_CUBE
+extern SR_PRIV struct sr_dev_driver zeroplus_logic_cube_driver_info;
+#endif
+#ifdef HAVE_HW_ASIX_SIGMA
+extern SR_PRIV struct sr_dev_driver asix_sigma_driver_info;
+#endif
+#ifdef HAVE_HW_CHRONOVU_LA
+extern SR_PRIV struct sr_dev_driver chronovu_la_driver_info;
+#endif
+#ifdef HAVE_HW_LINK_MSO19
+extern SR_PRIV struct sr_dev_driver link_mso19_driver_info;
+#endif
+#ifdef HAVE_HW_FX2LAFW
+extern SR_PRIV struct sr_dev_driver fx2lafw_driver_info;
+#endif
+#ifdef HAVE_HW_HANTEK_DSO
+extern SR_PRIV struct sr_dev_driver hantek_dso_driver_info;
+#endif
+#ifdef HAVE_HW_AGILENT_DMM
+extern SR_PRIV struct sr_dev_driver agdmm_driver_info;
+#endif
+#ifdef HAVE_HW_FLUKE_DMM
+extern SR_PRIV struct sr_dev_driver flukedmm_driver_info;
+#endif
+#ifdef HAVE_HW_SERIAL_DMM
+extern SR_PRIV struct sr_dev_driver bbcgm_m2110_driver_info;
+extern SR_PRIV struct sr_dev_driver digitek_dt4000zc_driver_info;
+extern SR_PRIV struct sr_dev_driver tekpower_tp4000zc_driver_info;
+extern SR_PRIV struct sr_dev_driver metex_me31_driver_info;
+extern SR_PRIV struct sr_dev_driver peaktech_3410_driver_info;
+extern SR_PRIV struct sr_dev_driver mastech_mas345_driver_info;
+extern SR_PRIV struct sr_dev_driver va_va18b_driver_info;
+extern SR_PRIV struct sr_dev_driver va_va40b_driver_info;
+extern SR_PRIV struct sr_dev_driver metex_m3640d_driver_info;
+extern SR_PRIV struct sr_dev_driver metex_m4650cr_driver_info;
+extern SR_PRIV struct sr_dev_driver peaktech_4370_driver_info;
+extern SR_PRIV struct sr_dev_driver pce_pce_dm32_driver_info;
+extern SR_PRIV struct sr_dev_driver radioshack_22_168_driver_info;
+extern SR_PRIV struct sr_dev_driver radioshack_22_805_driver_info;
+extern SR_PRIV struct sr_dev_driver radioshack_22_812_driver_info;
+extern SR_PRIV struct sr_dev_driver tecpel_dmm_8061_ser_driver_info;
+extern SR_PRIV struct sr_dev_driver voltcraft_m3650cr_driver_info;
+extern SR_PRIV struct sr_dev_driver voltcraft_m3650d_driver_info;
+extern SR_PRIV struct sr_dev_driver voltcraft_m4650cr_driver_info;
+extern SR_PRIV struct sr_dev_driver voltcraft_me42_driver_info;
+extern SR_PRIV struct sr_dev_driver voltcraft_vc820_ser_driver_info;
+extern SR_PRIV struct sr_dev_driver voltcraft_vc830_ser_driver_info;
+extern SR_PRIV struct sr_dev_driver voltcraft_vc840_ser_driver_info;
+extern SR_PRIV struct sr_dev_driver uni_t_ut60a_ser_driver_info;
+extern SR_PRIV struct sr_dev_driver uni_t_ut60e_ser_driver_info;
+extern SR_PRIV struct sr_dev_driver uni_t_ut60g_ser_driver_info;
+extern SR_PRIV struct sr_dev_driver uni_t_ut61b_ser_driver_info;
+extern SR_PRIV struct sr_dev_driver uni_t_ut61c_ser_driver_info;
+extern SR_PRIV struct sr_dev_driver uni_t_ut61d_ser_driver_info;
+extern SR_PRIV struct sr_dev_driver uni_t_ut61e_ser_driver_info;
+extern SR_PRIV struct sr_dev_driver iso_tech_idm103n_driver_info;
+extern SR_PRIV struct sr_dev_driver tenma_72_7745_ser_driver_info;
+extern SR_PRIV struct sr_dev_driver tenma_72_7750_ser_driver_info;
+#endif
+#ifdef HAVE_HW_UNI_T_DMM
+extern SR_PRIV struct sr_dev_driver tecpel_dmm_8061_driver_info;
+extern SR_PRIV struct sr_dev_driver uni_t_ut60a_driver_info;
+extern SR_PRIV struct sr_dev_driver uni_t_ut60e_driver_info;
+extern SR_PRIV struct sr_dev_driver uni_t_ut60g_driver_info;
+extern SR_PRIV struct sr_dev_driver uni_t_ut61b_driver_info;
+extern SR_PRIV struct sr_dev_driver uni_t_ut61c_driver_info;
+extern SR_PRIV struct sr_dev_driver uni_t_ut61d_driver_info;
+extern SR_PRIV struct sr_dev_driver uni_t_ut61e_driver_info;
+extern SR_PRIV struct sr_dev_driver voltcraft_vc820_driver_info;
+extern SR_PRIV struct sr_dev_driver voltcraft_vc830_driver_info;
+extern SR_PRIV struct sr_dev_driver voltcraft_vc840_driver_info;
+extern SR_PRIV struct sr_dev_driver tenma_72_7745_driver_info;
+extern SR_PRIV struct sr_dev_driver tenma_72_7750_driver_info;
+#endif
+/** @endcond */
+
+static struct sr_dev_driver *drivers_list[] = {
+#ifdef HAVE_HW_APPA_55II
+	&appa_55ii_driver_info,
+#endif
+#ifdef HAVE_HW_ATTEN_PPS3XXX
+	&atten_pps3203_driver_info,
+#endif
+#ifdef HAVE_HW_BRYMEN_BM86X
+	&brymen_bm86x_driver_info,
+#endif
+#ifdef HAVE_HW_BRYMEN_DMM
+	&brymen_bm857_driver_info,
+#endif
+#ifdef HAVE_HW_CEM_DT_885X
+	&cem_dt_885x_driver_info,
+#endif
+#ifdef HAVE_HW_CENTER_3XX
+	&center_309_driver_info,
+	&voltcraft_k204_driver_info,
+#endif
+#ifdef HAVE_HW_COLEAD_SLM
+	&colead_slm_driver_info,
+#endif
+#ifdef HAVE_HW_CONRAD_DIGI_35_CPU
+	&conrad_digi_35_cpu_driver_info,
+#endif
+#ifdef HAVE_HW_DEMO
+	&demo_driver_info,
+#endif
+#ifdef HAVE_HW_GMC_MH_1X_2X
+	&gmc_mh_1x_2x_rs232_driver_info,
+	&gmc_mh_2x_bd232_driver_info,
+#endif
+#ifdef HAVE_HW_HAMEG_HMO
+	&hameg_hmo_driver_info,
+#endif
+#ifdef HAVE_HW_IKALOGIC_SCANALOGIC2
+	&ikalogic_scanalogic2_driver_info,
+#endif
+#ifdef HAVE_HW_IKALOGIC_SCANAPLUS
+	&ikalogic_scanaplus_driver_info,
+#endif
+#ifdef HAVE_HW_KECHENG_KC_330B
+	&kecheng_kc_330b_driver_info,
+#endif
+#ifdef HAVE_HW_LASCAR_EL_USB
+	&lascar_el_usb_driver_info,
+#endif
+#ifdef HAVE_HW_MIC_985XX
+	&mic_98581_driver_info,
+	&mic_98583_driver_info,
+#endif
+#ifdef HAVE_HW_NORMA_DMM
+	&norma_dmm_driver_info,
+#endif
+#ifdef HAVE_HW_OLS
+	&ols_driver_info,
+#endif
+#ifdef HAVE_HW_RIGOL_DS
+	&rigol_ds_driver_info,
+#endif
+#ifdef HAVE_HW_SALEAE_LOGIC16
+	&saleae_logic16_driver_info,
+#endif
+#ifdef HAVE_HW_SYSCLK_LWLA
+	&sysclk_lwla_driver_info,
+#endif
+#ifdef HAVE_HW_TELEINFO
+	&teleinfo_driver_info,
+#endif
+#ifdef HAVE_HW_TONDAJ_SL_814
+	&tondaj_sl_814_driver_info,
+#endif
+#ifdef HAVE_HW_UNI_T_UT32X
+	&uni_t_ut32x_driver_info,
+#endif
+#ifdef HAVE_HW_VICTOR_DMM
+	&victor_dmm_driver_info,
+#endif
+#ifdef HAVE_HW_ZEROPLUS_LOGIC_CUBE
+	&zeroplus_logic_cube_driver_info,
+#endif
+#ifdef HAVE_HW_ASIX_SIGMA
+	&asix_sigma_driver_info,
+#endif
+#ifdef HAVE_HW_CHRONOVU_LA
+	&chronovu_la_driver_info,
+#endif
+#ifdef HAVE_HW_LINK_MSO19
+	&link_mso19_driver_info,
+#endif
+#ifdef HAVE_HW_FX2LAFW
+	&fx2lafw_driver_info,
+#endif
+#ifdef HAVE_HW_HANTEK_DSO
+	&hantek_dso_driver_info,
+#endif
+#ifdef HAVE_HW_AGILENT_DMM
+	&agdmm_driver_info,
+#endif
+#ifdef HAVE_HW_FLUKE_DMM
+	&flukedmm_driver_info,
+#endif
+#ifdef HAVE_HW_SERIAL_DMM
+	&bbcgm_m2110_driver_info,
+	&digitek_dt4000zc_driver_info,
+	&tekpower_tp4000zc_driver_info,
+	&metex_me31_driver_info,
+	&peaktech_3410_driver_info,
+	&mastech_mas345_driver_info,
+	&va_va18b_driver_info,
+	&va_va40b_driver_info,
+	&metex_m3640d_driver_info,
+	&metex_m4650cr_driver_info,
+	&peaktech_4370_driver_info,
+	&pce_pce_dm32_driver_info,
+	&radioshack_22_168_driver_info,
+	&radioshack_22_805_driver_info,
+	&radioshack_22_812_driver_info,
+	&tecpel_dmm_8061_ser_driver_info,
+	&voltcraft_m3650cr_driver_info,
+	&voltcraft_m3650d_driver_info,
+	&voltcraft_m4650cr_driver_info,
+	&voltcraft_me42_driver_info,
+	&voltcraft_vc820_ser_driver_info,
+	&voltcraft_vc830_ser_driver_info,
+	&voltcraft_vc840_ser_driver_info,
+	&uni_t_ut60a_ser_driver_info,
+	&uni_t_ut60e_ser_driver_info,
+	&uni_t_ut60g_ser_driver_info,
+	&uni_t_ut61b_ser_driver_info,
+	&uni_t_ut61c_ser_driver_info,
+	&uni_t_ut61d_ser_driver_info,
+	&uni_t_ut61e_ser_driver_info,
+	&iso_tech_idm103n_driver_info,
+	&tenma_72_7745_ser_driver_info,
+	&tenma_72_7750_ser_driver_info,
+#endif
+#ifdef HAVE_HW_UNI_T_DMM
+	&tecpel_dmm_8061_driver_info,
+	&uni_t_ut60a_driver_info,
+	&uni_t_ut60e_driver_info,
+	&uni_t_ut60g_driver_info,
+	&uni_t_ut61b_driver_info,
+	&uni_t_ut61c_driver_info,
+	&uni_t_ut61d_driver_info,
+	&uni_t_ut61e_driver_info,
+	&voltcraft_vc820_driver_info,
+	&voltcraft_vc830_driver_info,
+	&voltcraft_vc840_driver_info,
+	&tenma_72_7745_driver_info,
+	&tenma_72_7750_driver_info,
+#endif
+	NULL,
+};
+
+/**
+ * Return the list of supported hardware drivers.
+ *
+ * @return Pointer to the NULL-terminated list of hardware driver pointers.
+ *
+ * @since 0.1.0
+ */
+SR_API struct sr_dev_driver **sr_driver_list(void)
+{
+
+	return drivers_list;
+}
+
+/**
+ * Initialize a hardware driver.
+ *
+ * This usually involves memory allocations and variable initializations
+ * within the driver, but _not_ scanning for attached devices.
+ * The API call sr_driver_scan() is used for that.
+ *
+ * @param ctx A libsigrok context object allocated by a previous call to
+ *            sr_init(). Must not be NULL.
+ * @param driver The driver to initialize. This must be a pointer to one of
+ *               the entries returned by sr_driver_list(). Must not be NULL.
+ *
+ * @retval SR_OK Success
+ * @retval SR_ERR_ARG Invalid parameter(s).
+ * @retval SR_ERR_BUG Internal errors.
+ * @retval other Another negative error code upon other errors.
+ *
+ * @since 0.2.0
+ */
+SR_API int sr_driver_init(struct sr_context *ctx, struct sr_dev_driver *driver)
+{
+	int ret;
+
+	if (!ctx) {
+		sr_err("Invalid libsigrok context, can't initialize.");
+		return SR_ERR_ARG;
+	}
+
+	if (!driver) {
+		sr_err("Invalid driver, can't initialize.");
+		return SR_ERR_ARG;
+	}
+
+	sr_spew("Initializing driver '%s'.", driver->name);
+	if ((ret = driver->init(ctx)) < 0)
+		sr_err("Failed to initialize the driver: %d.", ret);
+
+	return ret;
+}
+
+/**
+ * Tell a hardware driver to scan for devices.
+ *
+ * In addition to the detection, the devices that are found are also
+ * initialized automatically. On some devices, this involves a firmware upload,
+ * or other such measures.
+ *
+ * The order in which the system is scanned for devices is not specified. The
+ * caller should not assume or rely on any specific order.
+ *
+ * Before calling sr_driver_scan(), the user must have previously initialized
+ * the driver by calling sr_driver_init().
+ *
+ * @param driver The driver that should scan. This must be a pointer to one of
+ *               the entries returned by sr_driver_list(). Must not be NULL.
+ * @param options A list of 'struct sr_hwopt' options to pass to the driver's
+ *                scanner. Can be NULL/empty.
+ *
+ * @return A GSList * of 'struct sr_dev_inst', or NULL if no devices were
+ *         found (or errors were encountered). This list must be freed by the
+ *         caller using g_slist_free(), but without freeing the data pointed
+ *         to in the list.
+ *
+ * @since 0.2.0
+ */
+SR_API GSList *sr_driver_scan(struct sr_dev_driver *driver, GSList *options)
+{
+	GSList *l;
+
+	if (!driver) {
+		sr_err("Invalid driver, can't scan for devices.");
+		return NULL;
+	}
+
+	if (!driver->priv) {
+		sr_err("Driver not initialized, can't scan for devices.");
+		return NULL;
+	}
+
+	l = driver->scan(options);
+
+	sr_spew("Scan of '%s' found %d devices.", driver->name,
+		g_slist_length(l));
+
+	return l;
+}
+
+/** Call driver cleanup function for all drivers.
+ *  @private */
+SR_PRIV void sr_hw_cleanup_all(void)
+{
+	int i;
+	struct sr_dev_driver **drivers;
+
+	drivers = sr_driver_list();
+	for (i = 0; drivers[i]; i++) {
+		if (drivers[i]->cleanup)
+			drivers[i]->cleanup();
+	}
+}
+
+/** Allocate struct sr_config.
+ *  A floating reference can be passed in for data.
+ *  @private
+ */
+SR_PRIV struct sr_config *sr_config_new(int key, GVariant *data)
+{
+	struct sr_config *src;
+
+	if (!(src = g_try_malloc(sizeof(struct sr_config))))
+		return NULL;
+	src->key = key;
+	src->data = g_variant_ref_sink(data);
+
+	return src;
+}
+
+/** Free struct sr_config.
+ *  @private
+ */
+SR_PRIV void sr_config_free(struct sr_config *src)
+{
+
+	if (!src || !src->data) {
+		sr_err("%s: invalid data!", __func__);
+		return;
+	}
+
+	g_variant_unref(src->data);
+	g_free(src);
+
+}
+
+/**
+ * Query value of a configuration key at the given driver or device instance.
+ *
+ * @param[in] driver The sr_dev_driver struct to query.
+ * @param[in] sdi (optional) If the key is specific to a device, this must
+ *            contain a pointer to the struct sr_dev_inst to be checked.
+ *            Otherwise it must be NULL.
+ * @param[in] cg The channel group on the device for which to list the
+ *                    values, or NULL.
+ * @param[in] key The configuration key (SR_CONF_*).
+ * @param[in,out] data Pointer to a GVariant where the value will be stored.
+ *             Must not be NULL. The caller is given ownership of the GVariant
+ *             and must thus decrease the refcount after use. However if
+ *             this function returns an error code, the field should be
+ *             considered unused, and should not be unreferenced.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR Error.
+ * @retval SR_ERR_ARG The driver doesn't know that key, but this is not to be
+ *          interpreted as an error by the caller; merely as an indication
+ *          that it's not applicable.
+ *
+ * @since 0.3.0
+ */
+SR_API int sr_config_get(const struct sr_dev_driver *driver,
+		const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg,
+		int key, GVariant **data)
+{
+	int ret;
+
+	if (!driver || !data)
+		return SR_ERR;
+
+	if (!driver->config_get)
+		return SR_ERR_ARG;
+
+	if ((ret = driver->config_get(key, data, sdi, cg)) == SR_OK) {
+		/* Got a floating reference from the driver. Sink it here,
+		 * caller will need to unref when done with it. */
+		g_variant_ref_sink(*data);
+	}
+
+	return ret;
+}
+
+/**
+ * Set value of a configuration key in a device instance.
+ *
+ * @param[in] sdi The device instance.
+ * @param[in] cg The channel group on the device for which to list the
+ *                    values, or NULL.
+ * @param[in] key The configuration key (SR_CONF_*).
+ * @param data The new value for the key, as a GVariant with GVariantType
+ *        appropriate to that key. A floating reference can be passed
+ *        in; its refcount will be sunk and unreferenced after use.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR Error.
+ * @retval SR_ERR_ARG The driver doesn't know that key, but this is not to be
+ *          interpreted as an error by the caller; merely as an indication
+ *          that it's not applicable.
+ *
+ * @since 0.3.0
+ */
+SR_API int sr_config_set(const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg,
+		int key, GVariant *data)
+{
+	int ret;
+
+	g_variant_ref_sink(data);
+
+	if (!sdi || !sdi->driver || !data)
+		ret = SR_ERR;
+	else if (!sdi->driver->config_set)
+		ret = SR_ERR_ARG;
+	else
+		ret = sdi->driver->config_set(key, data, sdi, cg);
+
+	g_variant_unref(data);
+
+	return ret;
+}
+
+/**
+ * Apply configuration settings to the device hardware.
+ *
+ * @param sdi The device instance.
+ *
+ * @return SR_OK upon success or SR_ERR in case of error.
+ *
+ * @since 0.3.0
+ */
+SR_API int sr_config_commit(const struct sr_dev_inst *sdi)
+{
+	int ret;
+
+	if (!sdi || !sdi->driver)
+		ret = SR_ERR;
+	else if (!sdi->driver->config_commit)
+		ret = SR_OK;
+	else
+		ret = sdi->driver->config_commit(sdi);
+
+	return ret;
+}
+
+/**
+ * List all possible values for a configuration key.
+ *
+ * @param[in] driver The sr_dev_driver struct to query.
+ * @param[in] sdi (optional) If the key is specific to a device, this must
+ *            contain a pointer to the struct sr_dev_inst to be checked.
+ * @param[in] cg The channel group on the device for which to list the
+ *                    values, or NULL.
+ * @param[in] key The configuration key (SR_CONF_*).
+ * @param[in,out] data A pointer to a GVariant where the list will be stored.
+ *             The caller is given ownership of the GVariant and must thus
+ *             unref the GVariant after use. However if this function
+ *             returns an error code, the field should be considered
+ *             unused, and should not be unreferenced.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR Error.
+ * @retval SR_ERR_ARG The driver doesn't know that key, but this is not to be
+ *          interpreted as an error by the caller; merely as an indication
+ *          that it's not applicable.
+ *
+ * @since 0.3.0
+ */
+SR_API int sr_config_list(const struct sr_dev_driver *driver,
+		const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg,
+		int key, GVariant **data)
+{
+	int ret;
+
+	if (!driver || !data)
+		ret = SR_ERR;
+	else if (!driver->config_list)
+		ret = SR_ERR_ARG;
+	else if ((ret = driver->config_list(key, data, sdi, cg)) == SR_OK)
+		g_variant_ref_sink(*data);
+
+	return ret;
+}
+
+/**
+ * Get information about a configuration key, by key.
+ *
+ * @param[in] key The configuration key.
+ *
+ * @return A pointer to a struct sr_config_info, or NULL if the key
+ *         was not found.
+ *
+ * @since 0.2.0
+ */
+SR_API const struct sr_config_info *sr_config_info_get(int key)
+{
+	int i;
+
+	for (i = 0; sr_config_info_data[i].key; i++) {
+		if (sr_config_info_data[i].key == key)
+			return &sr_config_info_data[i];
+	}
+
+	return NULL;
+}
+
+/**
+ * Get information about a configuration key, by name.
+ *
+ * @param[in] optname The configuration key.
+ *
+ * @return A pointer to a struct sr_config_info, or NULL if the key
+ *         was not found.
+ *
+ * @since 0.2.0
+ */
+SR_API const struct sr_config_info *sr_config_info_name_get(const char *optname)
+{
+	int i;
+
+	for (i = 0; sr_config_info_data[i].key; i++) {
+		if (!strcmp(sr_config_info_data[i].id, optname))
+			return &sr_config_info_data[i];
+	}
+
+	return NULL;
+}
+
+/* Unnecessary level of indirection follows. */
+
+/** @private
+ *  @see sr_session_source_remove()
+ */
+SR_PRIV int sr_source_remove(int fd)
+{
+	return sr_session_source_remove(fd);
+}
+
+/** @private
+ *  @see sr_session_source_add()
+ */
+SR_PRIV int sr_source_add(int fd, int events, int timeout,
+			  sr_receive_data_callback cb, void *cb_data)
+{
+	return sr_session_source_add(fd, events, timeout, cb, cb_data);
+}
+
+/** @} */
diff --git a/input/binary.c b/input/binary.c
new file mode 100644
index 0000000..e0d4c1d
--- /dev/null
+++ b/input/binary.c
@@ -0,0 +1,151 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "input/binary"
+
+#define CHUNKSIZE             (512 * 1024)
+#define DEFAULT_NUM_CHANNELS  8
+
+struct context {
+	uint64_t samplerate;
+};
+
+static int format_match(const char *filename)
+{
+	(void)filename;
+
+	/* This module will handle anything you throw at it. */
+	return TRUE;
+}
+
+static int init(struct sr_input *in, const char *filename)
+{
+	struct sr_channel *ch;
+	int num_channels, i;
+	char name[SR_MAX_CHANNELNAME_LEN + 1];
+	char *param;
+	struct context *ctx;
+
+	(void)filename;
+
+	if (!(ctx = g_try_malloc0(sizeof(*ctx)))) {
+		sr_err("Input format context malloc failed.");
+		return SR_ERR_MALLOC;
+	}
+
+	num_channels = DEFAULT_NUM_CHANNELS;
+	ctx->samplerate = 0;
+
+	if (in->param) {
+		param = g_hash_table_lookup(in->param, "numchannels");
+		if (param) {
+			num_channels = strtoul(param, NULL, 10);
+			if (num_channels < 1)
+				return SR_ERR;
+		}
+
+		param = g_hash_table_lookup(in->param, "samplerate");
+		if (param) {
+			if (sr_parse_sizestring(param, &ctx->samplerate) != SR_OK)
+				return SR_ERR;
+		}
+	}
+
+	/* Create a virtual device. */
+	in->sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, NULL, NULL, NULL);
+	in->internal = ctx;
+
+	for (i = 0; i < num_channels; i++) {
+		snprintf(name, SR_MAX_CHANNELNAME_LEN, "%d", i);
+		/* TODO: Check return value. */
+		if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE, name)))
+			return SR_ERR;
+		in->sdi->channels = g_slist_append(in->sdi->channels, ch);
+	}
+
+	return SR_OK;
+}
+
+static int loadfile(struct sr_input *in, const char *filename)
+{
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_meta meta;
+	struct sr_datafeed_logic logic;
+	struct sr_config *src;
+	unsigned char buffer[CHUNKSIZE];
+	int fd, size, num_channels;
+	struct context *ctx;
+
+	ctx = in->internal;
+
+	if ((fd = open(filename, O_RDONLY)) == -1)
+		return SR_ERR;
+
+	num_channels = g_slist_length(in->sdi->channels);
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(in->sdi, LOG_PREFIX);
+
+	if (ctx->samplerate) {
+		packet.type = SR_DF_META;
+		packet.payload = &meta;
+		src = sr_config_new(SR_CONF_SAMPLERATE,
+				g_variant_new_uint64(ctx->samplerate));
+		meta.config = g_slist_append(NULL, src);
+		sr_session_send(in->sdi, &packet);
+		sr_config_free(src);
+	}
+
+	/* Chop up the input file into chunks & send it to the session bus. */
+	packet.type = SR_DF_LOGIC;
+	packet.payload = &logic;
+	logic.unitsize = (num_channels + 7) / 8;
+	logic.data = buffer;
+	while ((size = read(fd, buffer, CHUNKSIZE)) > 0) {
+		logic.length = size;
+		sr_session_send(in->sdi, &packet);
+	}
+	close(fd);
+
+	/* Send end packet to the session bus. */
+	packet.type = SR_DF_END;
+	sr_session_send(in->sdi, &packet);
+
+	g_free(ctx);
+	in->internal = NULL;
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_input_format input_binary = {
+	.id = "binary",
+	.description = "Raw binary",
+	.format_match = format_match,
+	.init = init,
+	.loadfile = loadfile,
+};
diff --git a/input/chronovu_la8.c b/input/chronovu_la8.c
new file mode 100644
index 0000000..dcedcf8
--- /dev/null
+++ b/input/chronovu_la8.c
@@ -0,0 +1,206 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2011 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "input/chronovu-la8"
+
+#define NUM_PACKETS		2048
+#define PACKET_SIZE		4096
+#define DEFAULT_NUM_CHANNELS	8
+
+/**
+ * Convert the LA8 'divcount' value to the respective samplerate (in Hz).
+ *
+ * LA8 hardware: sample period = (divcount + 1) * 10ns.
+ * Min. value for divcount: 0x00 (10ns sample period, 100MHz samplerate).
+ * Max. value for divcount: 0xfe (2550ns sample period, 392.15kHz samplerate).
+ *
+ * @param divcount The divcount value as needed by the hardware.
+ *
+ * @return The samplerate in Hz, or 0xffffffffffffffff upon errors.
+ */
+static uint64_t divcount_to_samplerate(uint8_t divcount)
+{
+	if (divcount == 0xff)
+		return 0xffffffffffffffffULL;
+
+	return SR_MHZ(100) / (divcount + 1);
+}
+
+static int format_match(const char *filename)
+{
+	struct stat stat_buf;
+	int ret;
+
+	if (!filename) {
+		sr_err("%s: filename was NULL", __func__);
+		// return SR_ERR; /* FIXME */
+		return FALSE;
+	}
+
+	if (!g_file_test(filename, G_FILE_TEST_EXISTS)) {
+		sr_err("%s: input file '%s' does not exist",
+		       __func__, filename);
+		// return SR_ERR; /* FIXME */
+		return FALSE;
+	}
+
+	if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) {
+		sr_err("%s: input file '%s' not a regular file",
+		       __func__, filename);
+		// return SR_ERR; /* FIXME */
+		return FALSE;
+	}
+
+	/* Only accept files of length 8MB + 5 bytes. */
+	ret = stat(filename, &stat_buf);
+	if (ret != 0) {
+		sr_err("%s: Error getting file size of '%s'",
+		       __func__, filename);
+		return FALSE;
+	}
+	if (stat_buf.st_size != (8 * 1024 * 1024 + 5)) {
+		sr_dbg("%s: File size must be exactly 8388613 bytes ("
+		       "it actually is %d bytes in size), so this is not a "
+		       "ChronoVu LA8 file.", __func__, stat_buf.st_size);
+		return FALSE;
+	}
+
+	/* TODO: Check for divcount != 0xff. */
+
+	return TRUE;
+}
+
+static int init(struct sr_input *in, const char *filename)
+{
+	struct sr_channel *ch;
+	int num_channels, i;
+	char name[SR_MAX_CHANNELNAME_LEN + 1];
+	char *param;
+
+	(void)filename;
+
+	num_channels = DEFAULT_NUM_CHANNELS;
+
+	if (in->param) {
+		param = g_hash_table_lookup(in->param, "numchannels");
+		if (param) {
+			num_channels = strtoul(param, NULL, 10);
+			if (num_channels < 1) {
+				sr_err("%s: strtoul failed", __func__);
+				return SR_ERR;
+			}
+		}
+	}
+
+	/* Create a virtual device. */
+	in->sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, NULL, NULL, NULL);
+
+	for (i = 0; i < num_channels; i++) {
+		snprintf(name, SR_MAX_CHANNELNAME_LEN, "%d", i);
+		/* TODO: Check return value. */
+		if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE, name)))
+			return SR_ERR;
+		in->sdi->channels = g_slist_append(in->sdi->channels, ch);
+	}
+
+	return SR_OK;
+}
+
+static int loadfile(struct sr_input *in, const char *filename)
+{
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_meta meta;
+	struct sr_datafeed_logic logic;
+	struct sr_config *src;
+	uint8_t buf[PACKET_SIZE], divcount;
+	int i, fd, size, num_channels;
+	uint64_t samplerate;
+
+	/* TODO: Use glib functions! GIOChannel, g_fopen, etc. */
+	if ((fd = open(filename, O_RDONLY)) == -1) {
+		sr_err("%s: file open failed", __func__);
+		return SR_ERR;
+	}
+
+	num_channels = g_slist_length(in->sdi->channels);
+
+	/* Seek to the end of the file, and read the divcount byte. */
+	divcount = 0x00; /* TODO: Don't hardcode! */
+
+	/* Convert the divcount value to a samplerate. */
+	samplerate = divcount_to_samplerate(divcount);
+	if (samplerate == 0xffffffffffffffffULL) {
+		close(fd); /* FIXME */
+		return SR_ERR;
+	}
+	sr_dbg("%s: samplerate is %" PRIu64, __func__, samplerate);
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(in->sdi, LOG_PREFIX);
+
+	/* Send metadata about the SR_DF_LOGIC packets to come. */
+	packet.type = SR_DF_META;
+	packet.payload = &meta;
+	src = sr_config_new(SR_CONF_SAMPLERATE, g_variant_new_uint64(samplerate));
+	meta.config = g_slist_append(NULL, src);
+	sr_session_send(in->sdi, &packet);
+	sr_config_free(src);
+
+	/* TODO: Handle trigger point. */
+
+	/* Send data packets to the session bus. */
+	sr_dbg("%s: sending SR_DF_LOGIC data packets", __func__);
+	packet.type = SR_DF_LOGIC;
+	packet.payload = &logic;
+	logic.unitsize = (num_channels + 7) / 8;
+	logic.data = buf;
+
+	/* Send 8MB of total data to the session bus in small chunks. */
+	for (i = 0; i < NUM_PACKETS; i++) {
+		/* TODO: Handle errors, handle incomplete reads. */
+		size = read(fd, buf, PACKET_SIZE);
+		logic.length = size;
+		sr_session_send(in->sdi, &packet);
+	}
+	close(fd); /* FIXME */
+
+	/* Send end packet to the session bus. */
+	sr_dbg("%s: sending SR_DF_END", __func__);
+	packet.type = SR_DF_END;
+	packet.payload = NULL;
+	sr_session_send(in->sdi, &packet);
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_input_format input_chronovu_la8 = {
+	.id = "chronovu-la8",
+	.description = "ChronoVu LA8",
+	.format_match = format_match,
+	.init = init,
+	.loadfile = loadfile,
+};
diff --git a/input/csv.c b/input/csv.c
new file mode 100644
index 0000000..6dd06f4
--- /dev/null
+++ b/input/csv.c
@@ -0,0 +1,868 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Marc Schink <sigrok-dev at marcschink.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "input/csv"
+
+/*
+ * The CSV input module has the following options:
+ *
+ * single-column: Specifies the column number which stores the sample data for
+ *                single column mode and enables single column mode. Multi
+ *                column mode is used if this parameter is omitted.
+ *
+ * numchannels:   Specifies the number of channels to use. In multi column mode
+ *                the number of channels are the number of columns and in single
+ *                column mode the number of bits (LSB first) beginning at
+ *                'first-channel'.
+ *
+ * delimiter:     Specifies the delimiter for columns. Must be at least one
+ *                character. Comma is used as default delimiter.
+ *
+ * format:        Specifies the format of the sample data in single column mode.
+ *                Available formats are: 'bin', 'hex' and 'oct'. The binary
+ *                format is used by default. This option has no effect in multi
+ *                column mode.
+ *
+ * comment:       Specifies the prefix character(s) for comments. No prefix
+ *                characters are used by default which disables removing of
+ *                comments.
+ *
+ * samplerate:    Samplerate which the sample data was captured with. Default
+ *                value is 0.
+ *
+ * first-channel: Column number of the first channel in multi column mode and
+ *                position of the bit for the first channel in single column mode.
+ *                Default value is 0.
+ *
+ * header:        Determines if the first line should be treated as header
+ *                and used for channel names in multi column mode. Empty header
+ *                names will be replaced by the channel number. If enabled in
+ *                single column mode the first line will be skipped. Usage of
+ *                header is disabled by default.
+ *
+ * startline:     Line number to start processing sample data. Must be greater
+ *                than 0. The default line number to start processing is 1.
+ */
+
+/* Single column formats. */
+enum {
+	FORMAT_BIN,
+	FORMAT_HEX,
+	FORMAT_OCT
+};
+
+struct context {
+	/* Current selected samplerate. */
+	uint64_t samplerate;
+
+	/* Number of channels. */
+	gsize num_channels;
+
+	/* Column delimiter character(s). */
+	GString *delimiter;
+
+	/* Comment prefix character(s). */
+	GString *comment;
+
+	/* Determines if sample data is stored in multiple columns. */
+	gboolean multi_column_mode;
+
+	/* Column number of the sample data in single column mode. */
+	gsize single_column;
+
+	/*
+	 * Number of the first column to parse. Equivalent to the number of the
+	 * first channel in multi column mode and the single column number in
+	 * single column mode.
+	 */
+	gsize first_column;
+
+	/*
+	 * Column number of the first channel in multi column mode and position of
+	 * the bit for the first channel in single column mode.
+	 */
+	gsize first_channel;
+
+	/* Line number to start processing. */
+	gsize start_line;
+
+	/*
+	 * Determines if the first line should be treated as header and used for
+	 * channel names in multi column mode.
+	 */
+	gboolean header;
+
+	/* Format sample data is stored in single column mode. */
+	int format;
+
+	/* Size of the sample buffer. */
+	gsize sample_buffer_size;
+
+	/* Buffer to store sample data. */
+	uint8_t *sample_buffer;
+
+	GIOChannel *channel;
+
+	/* Buffer for the current line. */
+	GString *buffer;
+
+	/* Current line number. */
+	gsize line_number;
+};
+
+static int format_match(const char *filename)
+{
+	if (!filename) {
+		sr_err("%s: filename was NULL.", __func__);
+		return FALSE;
+	}
+
+	if (!g_file_test(filename, G_FILE_TEST_EXISTS)) {
+		sr_err("Input file '%s' does not exist.", filename);
+		return FALSE;
+	}
+
+	if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) {
+		sr_err("Input file '%s' not a regular file.", filename);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static void free_context(struct context *ctx)
+{
+	if (!ctx)
+		return;
+
+	if (ctx->delimiter)
+		g_string_free(ctx->delimiter, TRUE);
+
+	if (ctx->comment)
+		g_string_free(ctx->comment, TRUE);
+
+	if (ctx->channel) {
+		g_io_channel_shutdown(ctx->channel, FALSE, NULL);
+		g_io_channel_unref(ctx->channel);
+	}
+
+	if (ctx->sample_buffer)
+		g_free(ctx->sample_buffer);
+
+	if (ctx->buffer)
+		g_string_free(ctx->buffer, TRUE);
+
+	g_free(ctx);
+}
+
+static void strip_comment(GString *string, const GString *prefix)
+{
+	char *ptr;
+
+	if (!prefix->len)
+		return;
+
+	if (!(ptr = strstr(string->str, prefix->str)))
+		return;
+
+	g_string_truncate(string, ptr - string->str);
+}
+
+static int parse_binstr(const char *str, struct context *ctx)
+{
+	gsize i, j, length;
+
+	length = strlen(str);
+
+	if (!length) {
+		sr_err("Column %zu in line %zu is empty.", ctx->single_column,
+			ctx->line_number);
+		return SR_ERR;
+	}
+
+	/* Clear buffer in order to set bits only. */
+	memset(ctx->sample_buffer, 0, (ctx->num_channels + 7) >> 3);
+
+	i = ctx->first_channel;
+
+	for (j = 0; i < length && j < ctx->num_channels; i++, j++) {
+		if (str[length - i - 1] == '1') {
+			ctx->sample_buffer[j / 8] |= (1 << (j % 8));
+		} else if (str[length - i - 1] != '0') {
+			sr_err("Invalid value '%s' in column %zu in line %zu.",
+				str, ctx->single_column, ctx->line_number);
+			return SR_ERR;
+		}
+	}
+
+	return SR_OK;
+}
+
+static int parse_hexstr(const char *str, struct context *ctx)
+{
+	gsize i, j, k, length;
+	uint8_t value;
+	char c;
+
+	length = strlen(str);
+
+	if (!length) {
+		sr_err("Column %zu in line %zu is empty.", ctx->single_column,
+			ctx->line_number);
+		return SR_ERR;
+	}
+
+	/* Clear buffer in order to set bits only. */
+	memset(ctx->sample_buffer, 0, (ctx->num_channels + 7) >> 3);
+
+	/* Calculate the position of the first hexadecimal digit. */
+	i = ctx->first_channel / 4;
+
+	for (j = 0; i < length && j < ctx->num_channels; i++) {
+		c = str[length - i - 1];
+
+		if (!g_ascii_isxdigit(c)) {
+			sr_err("Invalid value '%s' in column %zu in line %zu.",
+				str, ctx->single_column, ctx->line_number);
+			return SR_ERR;
+		}
+
+		value = g_ascii_xdigit_value(c);
+
+		k = (ctx->first_channel + j) % 4;
+
+		for (; j < ctx->num_channels && k < 4; k++) {
+			if (value & (1 << k))
+				ctx->sample_buffer[j / 8] |= (1 << (j % 8));
+
+			j++;
+		}
+	}
+
+	return SR_OK;
+}
+
+static int parse_octstr(const char *str, struct context *ctx)
+{
+	gsize i, j, k, length;
+	uint8_t value;
+	char c;
+
+	length = strlen(str);
+
+	if (!length) {
+		sr_err("Column %zu in line %zu is empty.", ctx->single_column,
+			ctx->line_number);
+		return SR_ERR;
+	}
+
+	/* Clear buffer in order to set bits only. */
+	memset(ctx->sample_buffer, 0, (ctx->num_channels + 7) >> 3);
+
+	/* Calculate the position of the first octal digit. */
+	i = ctx->first_channel / 3;
+
+	for (j = 0; i < length && j < ctx->num_channels; i++) {
+		c = str[length - i - 1];
+
+		if (c < '0' || c > '7') {
+			sr_err("Invalid value '%s' in column %zu in line %zu.",
+				str, ctx->single_column, ctx->line_number);
+			return SR_ERR;
+		}
+
+		value = g_ascii_xdigit_value(c);
+
+		k = (ctx->first_channel + j) % 3;
+
+		for (; j < ctx->num_channels && k < 3; k++) {
+			if (value & (1 << k))
+				ctx->sample_buffer[j / 8] |= (1 << (j % 8));
+
+			j++;
+		}
+	}
+
+	return SR_OK;
+}
+
+static char **parse_line(const struct context *ctx, int max_columns)
+{
+	const char *str, *remainder;
+	GSList *list, *l;
+	char **columns;
+	char *column;
+	gsize n, k;
+
+	n = 0;
+	k = 0;
+	list = NULL;
+
+	remainder = ctx->buffer->str;
+	str = strstr(remainder, ctx->delimiter->str);
+
+	while (str && max_columns) {
+		if (n >= ctx->first_column) {
+			column = g_strndup(remainder, str - remainder);
+			list = g_slist_prepend(list, g_strstrip(column));
+
+			max_columns--;
+			k++;
+		}
+
+		remainder = str + ctx->delimiter->len;
+		str = strstr(remainder, ctx->delimiter->str);
+		n++;
+	}
+
+	if (ctx->buffer->len && max_columns && n >= ctx->first_column) {
+		column = g_strdup(remainder);
+		list = g_slist_prepend(list, g_strstrip(column));
+		k++;
+	}
+
+	if (!(columns = g_try_new(char *, k + 1)))
+		return NULL;
+
+	columns[k--] = NULL;
+
+	for (l = list; l; l = l->next)
+		columns[k--] = l->data;
+
+	g_slist_free(list);
+
+	return columns;
+}
+
+static int parse_multi_columns(char **columns, struct context *ctx)
+{
+	gsize i;
+
+	/* Clear buffer in order to set bits only. */
+	memset(ctx->sample_buffer, 0, (ctx->num_channels + 7) >> 3);
+
+	for (i = 0; i < ctx->num_channels; i++) {
+		if (columns[i][0] == '1') {
+			ctx->sample_buffer[i / 8] |= (1 << (i % 8));
+		} else if (!strlen(columns[i])) {
+			sr_err("Column %zu in line %zu is empty.",
+				ctx->first_channel + i, ctx->line_number);
+			return SR_ERR;
+		} else if (columns[i][0] != '0') {
+			sr_err("Invalid value '%s' in column %zu in line %zu.",
+				columns[i], ctx->first_channel + i,
+				ctx->line_number);
+			return SR_ERR;
+		}
+	}
+
+	return SR_OK;
+}
+
+static int parse_single_column(const char *column, struct context *ctx)
+{
+	int res;
+
+	res = SR_ERR;
+
+	switch(ctx->format) {
+	case FORMAT_BIN:
+		res = parse_binstr(column, ctx);
+		break;
+	case FORMAT_HEX:
+		res = parse_hexstr(column, ctx);
+		break;
+	case FORMAT_OCT:
+		res = parse_octstr(column, ctx);
+		break;
+	}
+
+	return res;
+}
+
+static int send_samples(const struct sr_dev_inst *sdi, uint8_t *buffer,
+			gsize buffer_size, gsize count)
+{
+	int res;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_logic logic;
+	gsize i;
+
+	packet.type = SR_DF_LOGIC;
+	packet.payload = &logic;
+	logic.unitsize = buffer_size;
+	logic.length = buffer_size;
+	logic.data = buffer;
+
+	for (i = 0; i < count; i++) {
+		if ((res = sr_session_send(sdi, &packet)) != SR_OK)
+			return res;
+	}
+
+	return SR_OK;
+}
+
+static int init(struct sr_input *in, const char *filename)
+{
+	int res;
+	struct context *ctx;
+	const char *param;
+	GIOStatus status;
+	gsize i, term_pos;
+	char channel_name[SR_MAX_CHANNELNAME_LEN + 1];
+	struct sr_channel *ch;
+	char **columns;
+	gsize num_columns;
+	char *ptr;
+
+	if (!(ctx = g_try_malloc0(sizeof(struct context)))) {
+		sr_err("Context malloc failed.");
+		return SR_ERR_MALLOC;
+	}
+
+	/* Create a virtual device. */
+	in->sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, NULL, NULL, NULL);
+	in->internal = ctx;
+
+	/* Set default samplerate. */
+	ctx->samplerate = 0;
+
+	/*
+	 * Enable auto-detection of the number of channels in multi column mode
+	 * and enforce the specification of the number of channels in single
+	 * column mode.
+	 */
+	ctx->num_channels = 0;
+
+	/* Set default delimiter. */
+	if (!(ctx->delimiter = g_string_new(","))) {
+		sr_err("Delimiter malloc failed.");
+		free_context(ctx);
+		return SR_ERR_MALLOC;
+	}
+
+	/*
+	 * Set default comment prefix. Note that an empty comment prefix
+	 * disables removing of comments.
+	 */
+	if (!(ctx->comment = g_string_new(""))) {
+		sr_err("Comment malloc failed.");
+		free_context(ctx);
+		return SR_ERR_MALLOC;
+	}
+
+	/* Enable multi column mode by default. */
+	ctx->multi_column_mode = TRUE;
+
+	/* Use first column as default single column number. */
+	ctx->single_column = 0;
+
+	/*
+	 * In multi column mode start parsing sample data at the first column
+	 * and in single column mode at the first bit.
+	 */
+	ctx->first_channel = 0;
+
+	/* Start at the beginning of the file. */
+	ctx->start_line = 1;
+
+	/* Disable the usage of the first line as header by default. */
+	ctx->header = FALSE;
+
+	/* Set default format for single column mode. */
+	ctx->format = FORMAT_BIN;
+
+	if (!(ctx->buffer = g_string_new(""))) {
+		sr_err("Line buffer malloc failed.");
+		free_context(ctx);
+		return SR_ERR_MALLOC;
+	}
+
+	if (in->param) {
+		if ((param = g_hash_table_lookup(in->param, "samplerate"))) {
+			res = sr_parse_sizestring(param, &ctx->samplerate);
+
+			if (res != SR_OK) {
+				sr_err("Invalid samplerate: %s.", param);
+				free_context(ctx);
+				return SR_ERR_ARG;
+			}
+		}
+
+		if ((param = g_hash_table_lookup(in->param, "numchannels")))
+			ctx->num_channels = g_ascii_strtoull(param, NULL, 10);
+
+		if ((param = g_hash_table_lookup(in->param, "delimiter"))) {
+			if (!strlen(param)) {
+				sr_err("Delimiter must be at least one character.");
+				free_context(ctx);
+				return SR_ERR_ARG;
+			}
+
+			if (!g_ascii_strcasecmp(param, "\\t"))
+				g_string_assign(ctx->delimiter, "\t");
+			else
+				g_string_assign(ctx->delimiter, param);
+		}
+
+		if ((param = g_hash_table_lookup(in->param, "comment")))
+			g_string_assign(ctx->comment, param);
+
+		if ((param = g_hash_table_lookup(in->param, "single-column"))) {
+			ctx->single_column = g_ascii_strtoull(param, &ptr, 10);
+			ctx->multi_column_mode = FALSE;
+
+			if (param == ptr) {
+				sr_err("Invalid single-colum number: %s.",
+					param);
+				free_context(ctx);
+				return SR_ERR_ARG;
+			}
+		}
+
+		if ((param = g_hash_table_lookup(in->param, "first-channel")))
+			ctx->first_channel = g_ascii_strtoull(param, NULL, 10);
+
+		if ((param = g_hash_table_lookup(in->param, "startline"))) {
+			ctx->start_line = g_ascii_strtoull(param, NULL, 10);
+
+			if (ctx->start_line < 1) {
+				sr_err("Invalid start line: %s.", param);
+				free_context(ctx);
+				return SR_ERR_ARG;
+			}
+		}
+
+		if ((param = g_hash_table_lookup(in->param, "header")))
+			ctx->header = sr_parse_boolstring(param);
+
+		if ((param = g_hash_table_lookup(in->param, "format"))) {
+			if (!g_ascii_strncasecmp(param, "bin", 3)) {
+				ctx->format = FORMAT_BIN;
+			} else if (!g_ascii_strncasecmp(param, "hex", 3)) {
+				ctx->format = FORMAT_HEX;
+			} else if (!g_ascii_strncasecmp(param, "oct", 3)) {
+				ctx->format = FORMAT_OCT;
+			} else {
+				sr_err("Invalid format: %s.", param);
+				free_context(ctx);
+				return SR_ERR;
+			}
+		}
+	}
+
+	if (ctx->multi_column_mode)
+		ctx->first_column = ctx->first_channel;
+	else
+		ctx->first_column = ctx->single_column;
+
+	if (!ctx->multi_column_mode && !ctx->num_channels) {
+		sr_err("Number of channels needs to be specified in single column mode.");
+		free_context(ctx);
+		return SR_ERR;
+	}
+
+	if (!(ctx->channel = g_io_channel_new_file(filename, "r", NULL))) {
+		sr_err("Input file '%s' could not be opened.", filename);
+		free_context(ctx);
+		return SR_ERR;
+	}
+
+	while (TRUE) {
+		ctx->line_number++;
+		status = g_io_channel_read_line_string(ctx->channel,
+			ctx->buffer, &term_pos, NULL);
+
+		if (status == G_IO_STATUS_EOF) {
+			sr_err("Input file is empty.");
+			free_context(ctx);
+			return SR_ERR;
+		}
+
+		if (status != G_IO_STATUS_NORMAL) {
+			sr_err("Error while reading line %zu.",
+				ctx->line_number);
+			free_context(ctx);
+			return SR_ERR;
+		}
+
+		if (ctx->start_line > ctx->line_number) {
+			sr_spew("Line %zu skipped.", ctx->line_number);
+			continue;
+		}
+
+		/* Remove line termination character(s). */
+		g_string_truncate(ctx->buffer, term_pos);
+
+		if (!ctx->buffer->len) {
+			sr_spew("Blank line %zu skipped.", ctx->line_number);
+			continue;
+		}
+
+		/* Remove trailing comment. */
+		strip_comment(ctx->buffer, ctx->comment);
+
+		if (ctx->buffer->len)
+			break;
+
+		sr_spew("Comment-only line %zu skipped.", ctx->line_number);
+	}
+
+	/*
+	 * In order to determine the number of columns parse the current line
+	 * without limiting the number of columns.
+	 */
+	if (!(columns = parse_line(ctx, -1))) {
+		sr_err("Error while parsing line %zu.", ctx->line_number);
+		free_context(ctx);
+		return SR_ERR;
+	}
+
+	num_columns = g_strv_length(columns);
+
+	/* Ensure that the first column is not out of bounds. */
+	if (!num_columns) {
+		sr_err("Column %zu in line %zu is out of bounds.",
+			ctx->first_column, ctx->line_number);
+		g_strfreev(columns);
+		free_context(ctx);
+		return SR_ERR;
+	}
+
+	if (ctx->multi_column_mode) {
+		/*
+		 * Detect the number of channels in multi column mode
+		 * automatically if not specified.
+		 */
+		if (!ctx->num_channels) {
+			ctx->num_channels = num_columns;
+			sr_info("Number of auto-detected channels: %zu.",
+				ctx->num_channels);
+		}
+
+		/*
+		 * Ensure that the number of channels does not exceed the number
+		 * of columns in multi column mode.
+		 */
+		if (num_columns < ctx->num_channels) {
+			sr_err("Not enough columns for desired number of channels in line %zu.",
+				ctx->line_number);
+			g_strfreev(columns);
+			free_context(ctx);
+			return SR_ERR;
+		}
+	}
+
+	for (i = 0; i < ctx->num_channels; i++) {
+		if (ctx->header && ctx->multi_column_mode && strlen(columns[i]))
+			snprintf(channel_name, sizeof(channel_name), "%s",
+				columns[i]);
+		else
+			snprintf(channel_name, sizeof(channel_name), "%zu", i);
+
+		ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE, channel_name);
+
+		if (!ch) {
+			sr_err("Channel creation failed.");
+			free_context(ctx);
+			g_strfreev(columns);
+			return SR_ERR;
+		}
+
+		in->sdi->channels = g_slist_append(in->sdi->channels, ch);
+	}
+
+	g_strfreev(columns);
+
+	/*
+	 * Calculate the minimum buffer size to store the sample data of the
+	 * channels.
+	 */
+	ctx->sample_buffer_size = (ctx->num_channels + 7) >> 3;
+
+	if (!(ctx->sample_buffer = g_try_malloc(ctx->sample_buffer_size))) {
+		sr_err("Sample buffer malloc failed.");
+		free_context(ctx);
+		return SR_ERR_MALLOC;
+	}
+
+	return SR_OK;
+}
+
+static int loadfile(struct sr_input *in, const char *filename)
+{
+	int res;
+	struct context *ctx;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_meta meta;
+	struct sr_config *cfg;
+	GIOStatus status;
+	gboolean read_new_line;
+	gsize term_pos;
+	char **columns;
+	gsize num_columns;
+	int max_columns;
+
+	(void)filename;
+
+	ctx = in->internal;
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(in->sdi, LOG_PREFIX);
+
+	if (ctx->samplerate) {
+		packet.type = SR_DF_META;
+		packet.payload = &meta;
+		cfg = sr_config_new(SR_CONF_SAMPLERATE,
+			g_variant_new_uint64(ctx->samplerate));
+		meta.config = g_slist_append(NULL, cfg);
+		sr_session_send(in->sdi, &packet);
+		sr_config_free(cfg);
+	}
+
+	read_new_line = FALSE;
+
+	/* Limit the number of columns to parse. */
+	if (ctx->multi_column_mode)
+		max_columns = ctx->num_channels;
+	else
+		max_columns = 1;
+
+	while (TRUE) {
+		/*
+		 * Skip reading a new line for the first time if the last read
+		 * line was not a header because the sample data is not parsed
+		 * yet.
+		 */
+		if (read_new_line || ctx->header) {
+			ctx->line_number++;
+			status = g_io_channel_read_line_string(ctx->channel,
+				ctx->buffer, &term_pos, NULL);
+
+			if (status == G_IO_STATUS_EOF)
+				break;
+
+			if (status != G_IO_STATUS_NORMAL) {
+				sr_err("Error while reading line %zu.",
+					ctx->line_number);
+				free_context(ctx);
+				return SR_ERR;
+			}
+
+			/* Remove line termination character(s). */
+			g_string_truncate(ctx->buffer, term_pos);
+		}
+
+		read_new_line = TRUE;
+
+		if (!ctx->buffer->len) {
+			sr_spew("Blank line %zu skipped.", ctx->line_number);
+			continue;
+		}
+
+		/* Remove trailing comment. */
+		strip_comment(ctx->buffer, ctx->comment);
+
+		if (!ctx->buffer->len) {
+			sr_spew("Comment-only line %zu skipped.",
+				ctx->line_number);
+			continue;
+		}
+
+		if (!(columns = parse_line(ctx, max_columns))) {
+			sr_err("Error while parsing line %zu.",
+				ctx->line_number);
+			free_context(ctx);
+			return SR_ERR;
+		}
+
+		num_columns = g_strv_length(columns);
+
+		/* Ensure that the first column is not out of bounds. */
+		if (!num_columns) {
+			sr_err("Column %zu in line %zu is out of bounds.",
+				ctx->first_column, ctx->line_number);
+			g_strfreev(columns);
+			free_context(ctx);
+			return SR_ERR;
+		}
+
+		/*
+		 * Ensure that the number of channels does not exceed the number
+		 * of columns in multi column mode.
+		 */
+		if (ctx->multi_column_mode && num_columns < ctx->num_channels) {
+			sr_err("Not enough columns for desired number of channels in line %zu.",
+				ctx->line_number);
+			g_strfreev(columns);
+			free_context(ctx);
+			return SR_ERR;
+		}
+
+		if (ctx->multi_column_mode)
+			res = parse_multi_columns(columns, ctx);
+		else
+			res = parse_single_column(columns[0], ctx);
+
+		if (res != SR_OK) {
+			g_strfreev(columns);
+			free_context(ctx);
+			return SR_ERR;
+		}
+
+		g_strfreev(columns);
+
+		/*
+		 * TODO: Parse sample numbers / timestamps and use it for
+		 * decompression.
+		 */
+
+		/* Send sample data to the session bus. */
+		res = send_samples(in->sdi, ctx->sample_buffer,
+			ctx->sample_buffer_size, 1);
+
+		if (res != SR_OK) {
+			sr_err("Sending samples failed.");
+			free_context(ctx);
+			return SR_ERR;
+		}
+	}
+
+	/* Send end packet to the session bus. */
+	packet.type = SR_DF_END;
+	sr_session_send(in->sdi, &packet);
+
+	free_context(ctx);
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_input_format input_csv = {
+	.id = "csv",
+	.description = "Comma-separated values (CSV)",
+	.format_match = format_match,
+	.init = init,
+	.loadfile = loadfile,
+};
diff --git a/input/input.c b/input/input.c
new file mode 100644
index 0000000..d22b373
--- /dev/null
+++ b/input/input.c
@@ -0,0 +1,76 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010-2012 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+/**
+ * @file
+ *
+ * Input file/data format handling.
+ */
+
+/**
+ * @defgroup grp_input Input formats
+ *
+ * Input file/data format handling.
+ *
+ * libsigrok can process acquisition data in several different ways.
+ * Aside from acquiring data from a hardware device, it can also take it from
+ * a file in various formats (binary, CSV, VCD, and so on).
+ *
+ * Like everything in libsigrok that handles data, processing is done in a
+ * streaming manner -- input should be supplied to libsigrok a chunk at a time.
+ * This way anything that processes data can do so in real time, without the
+ * user having to wait for the whole thing to be finished.
+ *
+ * Every input module is "pluggable", meaning it's handled as being separate
+ * from the main libsigrok, but linked in to it statically. To keep things
+ * modular and separate like this, functions within an input module should be
+ * declared static, with only the respective 'struct sr_input_format' being
+ * exported for use into the wider libsigrok namespace.
+ *
+ * @{
+ */
+
+/** @cond PRIVATE */
+extern SR_PRIV struct sr_input_format input_chronovu_la8;
+extern SR_PRIV struct sr_input_format input_csv;
+extern SR_PRIV struct sr_input_format input_binary;
+extern SR_PRIV struct sr_input_format input_vcd;
+extern SR_PRIV struct sr_input_format input_wav;
+/* @endcond */
+
+static struct sr_input_format *input_module_list[] = {
+	&input_vcd,
+	&input_chronovu_la8,
+	&input_wav,
+	&input_csv,
+	/* This one has to be last, because it will take any input. */
+	&input_binary,
+	NULL,
+};
+
+/** @since 0.1.0 */
+SR_API struct sr_input_format **sr_input_list(void)
+{
+	return input_module_list;
+}
+
+/** @} */
diff --git a/input/vcd.c b/input/vcd.c
new file mode 100644
index 0000000..6759d73
--- /dev/null
+++ b/input/vcd.c
@@ -0,0 +1,546 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Petteri Aimonen <jpa at sr.mail.kapsi.fi>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* The VCD input module has the following options:
+ *
+ * numchannels: Maximum number of channels to use. The channels are
+ *              detected in the same order as they are listed
+ *              in the $var sections of the VCD file.
+ *
+ * skip:        Allows skipping until given timestamp in the file.
+ *              This can speed up analyzing of long captures.
+ *            
+ *              Value < 0: Skip until first timestamp listed in
+ *              the file. (default)
+ *
+ *              Value = 0: Do not skip, instead generate samples
+ *              beginning from timestamp 0.
+ *
+ *              Value > 0: Start at the given timestamp.
+ *
+ * downsample:  Divide the samplerate by the given factor.
+ *              This can speed up analyzing of long captures.
+ *
+ * compress:    Compress idle periods longer than this value.
+ *              This can speed up analyzing of long captures.
+ *              Default 0 = don't compress.
+ *
+ * Based on Verilog standard IEEE Std 1364-2001 Version C
+ *
+ * Supported features:
+ * - $var with 'wire' and 'reg' types of scalar variables
+ * - $timescale definition for samplerate
+ * - multiple character variable identifiers
+ *
+ * Most important unsupported features:
+ * - vector variables (bit vectors etc.)
+ * - analog, integer and real number variables
+ * - $dumpvars initial value declaration
+ * - $scope namespaces
+ * - more than 64 channels
+ */
+
+#include <stdlib.h>
+#include <glib.h>
+#include <stdio.h>
+#include <string.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "input/vcd"
+
+#define DEFAULT_NUM_CHANNELS 8
+#define CHUNKSIZE 1024
+
+struct context {
+	uint64_t samplerate;
+	int maxchannels;
+	int channelcount;
+	int downsample;
+	unsigned compress;
+	int64_t skip;
+	GSList *channels;
+};
+
+struct vcd_channel {
+	gchar *name;
+	gchar *identifier;
+};
+
+
+/* Read until specific type of character occurs in file.
+ * Skip input if dest is NULL.
+ * Modes:
+ * 'W' read until whitespace
+ * 'N' read until non-whitespace, and ungetc() the character
+ * '$' read until $end
+ */
+static gboolean read_until(FILE *file, GString *dest, char mode)
+{
+	int  c;
+	char prev[4] = "";
+
+	for(;;) {
+		c = fgetc(file);
+
+		if (c == EOF) {
+			if (mode == '$')
+				sr_err("Unexpected EOF.");
+			return FALSE;
+		}
+
+		if (mode == 'W' && g_ascii_isspace(c))
+			return TRUE;
+
+		if (mode == 'N' && !g_ascii_isspace(c)) {
+			ungetc(c, file);
+			return TRUE;
+		}
+
+		if (mode == '$') {
+			prev[0] = prev[1]; prev[1] = prev[2]; prev[2] = prev[3]; prev[3] = c;
+			if (prev[0] == '$' && prev[1] == 'e' && prev[2] == 'n' && prev[3] == 'd') {
+				if (dest != NULL)
+					g_string_truncate(dest, dest->len - 3);
+
+				return TRUE;
+			}
+		}
+
+		if (dest != NULL)
+			g_string_append_c(dest, c);
+	}
+}
+
+/*
+ * Reads a single VCD section from input file and parses it to structure.
+ * e.g. $timescale 1ps $end  => "timescale" "1ps"
+ */
+static gboolean parse_section(FILE *file, gchar **name, gchar **contents)
+{
+	gboolean status;
+	GString *sname, *scontents;
+
+	/* Skip any initial white-space */
+	if (!read_until(file, NULL, 'N')) return FALSE;
+
+	/* Section tag should start with $. */
+	if (fgetc(file) != '$') {
+		sr_err("Expected $ at beginning of section.");
+		return FALSE;
+	}
+
+	/* Read the section tag */
+	sname = g_string_sized_new(32);
+	status = read_until(file, sname, 'W');
+
+	/* Skip whitespace before content */
+	status = status && read_until(file, NULL, 'N');
+
+	/* Read the content */
+	scontents = g_string_sized_new(128);
+	status = status && read_until(file, scontents, '$');
+	g_strchomp(scontents->str);
+
+	/* Release strings if status is FALSE, return them if status is TRUE */
+	*name = g_string_free(sname, !status);
+	*contents = g_string_free(scontents, !status);
+	return status;
+}
+
+static void free_channel(void *data)
+{
+	struct vcd_channel *vcd_ch = data;
+	g_free(vcd_ch->name);
+	g_free(vcd_ch->identifier);
+	g_free(vcd_ch);
+}
+
+static void release_context(struct context *ctx)
+{
+	g_slist_free_full(ctx->channels, free_channel);
+	g_free(ctx);
+}
+
+/* Remove empty parts from an array returned by g_strsplit. */
+static void remove_empty_parts(gchar **parts)
+{
+	gchar **src = parts;
+	gchar **dest = parts;
+	while (*src != NULL) {
+		if (**src != '\0')
+			*dest++ = *src;
+		src++;
+	}
+
+	*dest = NULL;
+}
+
+/*
+ * Parse VCD header to get values for context structure.
+ * The context structure should be zeroed before calling this.
+ */
+static gboolean parse_header(FILE *file, struct context *ctx)
+{
+	uint64_t p, q;
+	gchar *name = NULL, *contents = NULL;
+	gboolean status = FALSE;
+	struct vcd_channel *vcd_ch;
+
+	while (parse_section(file, &name, &contents)) {
+		sr_dbg("Section '%s', contents '%s'.", name, contents);
+
+		if (g_strcmp0(name, "enddefinitions") == 0) {
+			status = TRUE;
+			break;
+		} else if (g_strcmp0(name, "timescale") == 0) {
+			/*
+			 * The standard allows for values 1, 10 or 100
+			 * and units s, ms, us, ns, ps and fs.
+			 * */
+			if (sr_parse_period(contents, &p, &q) == SR_OK) {
+				ctx->samplerate = q / p;
+				if (q % p != 0) {
+					/* Does not happen unless time value is non-standard */
+					sr_warn("Inexact rounding of samplerate, %" PRIu64 " / %" PRIu64 " to %" PRIu64 " Hz.",
+						q, p, ctx->samplerate);
+				}
+
+				sr_dbg("Samplerate: %" PRIu64, ctx->samplerate);
+			} else {
+				sr_err("Parsing timescale failed.");
+			}
+		} else if (g_strcmp0(name, "var") == 0) {
+			/* Format: $var type size identifier reference $end */
+			gchar **parts = g_strsplit_set(contents, " \r\n\t", 0);
+			remove_empty_parts(parts);
+
+			if (g_strv_length(parts) != 4)
+				sr_warn("$var section should have 4 items");
+			else if (g_strcmp0(parts[0], "reg") != 0 && g_strcmp0(parts[0], "wire") != 0)
+				sr_info("Unsupported signal type: '%s'", parts[0]);
+			else if (strtol(parts[1], NULL, 10) != 1)
+				sr_info("Unsupported signal size: '%s'", parts[1]);
+			else if (ctx->channelcount >= ctx->maxchannels)
+				sr_warn("Skipping '%s' because only %d channels requested.", parts[3], ctx->maxchannels);
+			else {
+				sr_info("Channel %d is '%s' identified by '%s'.", ctx->channelcount, parts[3], parts[2]);
+				vcd_ch = g_malloc(sizeof(struct vcd_channel));
+				vcd_ch->identifier = g_strdup(parts[2]);
+				vcd_ch->name = g_strdup(parts[3]);
+				ctx->channels = g_slist_append(ctx->channels, vcd_ch);
+				ctx->channelcount++;
+			}
+
+			g_strfreev(parts);
+		}
+
+		g_free(name); name = NULL;
+		g_free(contents); contents = NULL;
+	}
+
+	g_free(name);
+	g_free(contents);
+
+	return status;
+}
+
+static int format_match(const char *filename)
+{
+	FILE *file;
+	gchar *name = NULL, *contents = NULL;
+	gboolean status;
+
+	file = fopen(filename, "r");
+	if (file == NULL)
+		return FALSE;
+
+	/*
+	 * If we can parse the first section correctly,
+	 * then it is assumed to be a VCD file.
+	 */
+	status = parse_section(file, &name, &contents);
+	status = status && (*name != '\0');
+
+	g_free(name);
+	g_free(contents);
+	fclose(file);
+
+	return status;
+}
+
+static int init(struct sr_input *in, const char *filename)
+{
+	struct sr_channel *ch;
+	int num_channels, i;
+	char name[SR_MAX_CHANNELNAME_LEN + 1];
+	char *param;
+	struct context *ctx;
+
+	(void)filename;
+
+	if (!(ctx = g_try_malloc0(sizeof(*ctx)))) {
+		sr_err("Input format context malloc failed.");
+		return SR_ERR_MALLOC;
+	}
+
+	num_channels = DEFAULT_NUM_CHANNELS;
+	ctx->samplerate = 0;
+	ctx->downsample = 1;
+	ctx->skip = -1;
+
+	if (in->param) {
+		param = g_hash_table_lookup(in->param, "numchannels");
+		if (param) {
+			num_channels = strtoul(param, NULL, 10);
+			if (num_channels < 1) {
+				release_context(ctx);
+				return SR_ERR;
+			} else if (num_channels > 64) {
+				sr_err("No more than 64 channels supported.");
+				return SR_ERR;
+			}
+		}
+
+		param = g_hash_table_lookup(in->param, "downsample");
+		if (param) {
+			ctx->downsample = strtoul(param, NULL, 10);
+			if (ctx->downsample < 1)
+				ctx->downsample = 1;
+		}
+
+		param = g_hash_table_lookup(in->param, "compress");
+		if (param)
+			ctx->compress = strtoul(param, NULL, 10);
+
+		param = g_hash_table_lookup(in->param, "skip");
+		if (param)
+			ctx->skip = strtoul(param, NULL, 10) / ctx->downsample;
+	}
+
+	/* Maximum number of channels to parse from the VCD */
+	ctx->maxchannels = num_channels;
+
+	/* Create a virtual device. */
+	in->sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, NULL, NULL, NULL);
+	in->internal = ctx;
+
+	for (i = 0; i < num_channels; i++) {
+		snprintf(name, SR_MAX_CHANNELNAME_LEN, "%d", i);
+
+		if (!(ch = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE, name))) {
+			release_context(ctx);
+			return SR_ERR;
+		}
+
+		in->sdi->channels = g_slist_append(in->sdi->channels, ch);
+	}
+
+	return SR_OK;
+}
+
+/* Send N samples of the given value. */
+static void send_samples(const struct sr_dev_inst *sdi, uint64_t sample, uint64_t count)
+{
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_logic logic;
+	uint64_t buffer[CHUNKSIZE];
+	uint64_t i;
+	unsigned chunksize = CHUNKSIZE;
+
+	if (count < chunksize)
+		chunksize = count;
+
+	for (i = 0; i < chunksize; i++)
+		buffer[i] = sample;
+
+	packet.type = SR_DF_LOGIC;
+	packet.payload = &logic;
+	logic.unitsize = sizeof(uint64_t);
+	logic.data = buffer;
+
+	while (count) {
+		if (count < chunksize)
+			chunksize = count;
+
+		logic.length = sizeof(uint64_t) * chunksize;
+
+		sr_session_send(sdi, &packet);
+		count -= chunksize;
+	}
+}
+
+/* Parse the data section of VCD */
+static void parse_contents(FILE *file, const struct sr_dev_inst *sdi, struct context *ctx)
+{
+	GString *token = g_string_sized_new(32);
+
+	uint64_t prev_timestamp = 0;
+	uint64_t prev_values = 0;
+
+	/* Read one space-delimited token at a time. */
+	while (read_until(file, NULL, 'N') && read_until(file, token, 'W')) {
+		if (token->str[0] == '#' && g_ascii_isdigit(token->str[1])) {
+			/* Numeric value beginning with # is a new timestamp value */
+			uint64_t timestamp;
+			timestamp = strtoull(token->str + 1, NULL, 10);
+
+			if (ctx->downsample > 1)
+				timestamp /= ctx->downsample;
+
+			/*
+			 * Skip < 0 => skip until first timestamp.
+			 * Skip = 0 => don't skip
+			 * Skip > 0 => skip until timestamp >= skip.
+			 */
+			if (ctx->skip < 0) {
+				ctx->skip = timestamp;
+				prev_timestamp = timestamp;
+			} else if (ctx->skip > 0 && timestamp < (uint64_t)ctx->skip) {
+				prev_timestamp = ctx->skip;
+			}
+			else if (timestamp == prev_timestamp) {
+				/* Ignore repeated timestamps (e.g. sigrok outputs these) */
+			}
+			else {
+				if (ctx->compress != 0 && timestamp - prev_timestamp > ctx->compress)
+				{
+					/* Compress long idle periods */
+					prev_timestamp = timestamp - ctx->compress;
+				}
+
+				sr_dbg("New timestamp: %" PRIu64, timestamp);
+
+				/* Generate samples from prev_timestamp up to timestamp - 1. */
+				send_samples(sdi, prev_values, timestamp - prev_timestamp);
+				prev_timestamp = timestamp;
+			}
+		} else if (token->str[0] == '$' && token->len > 1) {
+			/* This is probably a $dumpvars, $comment or similar.
+			 * $dump* contain useful data, but other tags will be skipped until $end. */
+			if (g_strcmp0(token->str, "$dumpvars") == 0
+					|| g_strcmp0(token->str, "$dumpon") == 0
+					|| g_strcmp0(token->str, "$dumpoff") == 0
+					|| g_strcmp0(token->str, "$end") == 0) {
+				/* Ignore, parse contents as normally. */
+			} else {
+				/* Skip until $end */
+				read_until(file, NULL, '$');
+			}
+		}
+		else if (strchr("bBrR", token->str[0]) != NULL) {
+			/* A vector value. Skip it and also the following identifier. */
+			read_until(file, NULL, 'N');
+			read_until(file, NULL, 'W');
+		} else if (strchr("01xXzZ", token->str[0]) != NULL) {
+			/* A new 1-bit sample value */
+			int i, bit;
+			GSList *l;
+			struct vcd_channel *vcd_ch;
+
+			bit = (token->str[0] == '1');
+
+			g_string_erase(token, 0, 1);
+			if (token->len == 0) {
+				/* There was a space between value and identifier.
+				 * Read in the rest.
+				 */
+				read_until(file, NULL, 'N');
+				read_until(file, token, 'W');
+			}
+
+			for (i = 0, l = ctx->channels; i < ctx->channelcount && l; i++, l = l->next) {
+				vcd_ch = l->data;
+
+				if (g_strcmp0(token->str, vcd_ch->identifier) == 0) {
+					/* Found our channel */
+					if (bit)
+						prev_values |= (uint64_t)1 << i;
+					else
+						prev_values &= ~((uint64_t)1 << i);
+
+					break;
+				}
+			}
+
+			if (i == ctx->channelcount)
+				sr_dbg("Did not find channel for identifier '%s'.", token->str);
+		} else {
+			sr_warn("Skipping unknown token '%s'.", token->str);
+		}
+
+		g_string_truncate(token, 0);
+	}
+
+	g_string_free(token, TRUE);
+}
+
+static int loadfile(struct sr_input *in, const char *filename)
+{
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_meta meta;
+	struct sr_config *src;
+	FILE *file;
+	struct context *ctx;
+	uint64_t samplerate;
+
+	ctx = in->internal;
+
+	if ((file = fopen(filename, "r")) == NULL)
+		return SR_ERR;
+
+	if (!parse_header(file, ctx)) {
+		sr_err("VCD parsing failed");
+		fclose(file);
+		return SR_ERR;
+	}
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(in->sdi, LOG_PREFIX);
+
+	/* Send metadata about the SR_DF_LOGIC packets to come. */
+	packet.type = SR_DF_META;
+	packet.payload = &meta;
+	samplerate = ctx->samplerate / ctx->downsample;
+	src = sr_config_new(SR_CONF_SAMPLERATE, g_variant_new_uint64(samplerate));
+	meta.config = g_slist_append(NULL, src);
+	sr_session_send(in->sdi, &packet);
+	sr_config_free(src);
+
+	/* Parse the contents of the VCD file */
+	parse_contents(file, in->sdi, ctx);
+
+	/* Send end packet to the session bus. */
+	packet.type = SR_DF_END;
+	sr_session_send(in->sdi, &packet);
+
+	fclose(file);
+	release_context(ctx);
+	in->internal = NULL;
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_input_format input_vcd = {
+	.id = "vcd",
+	.description = "Value Change Dump",
+	.format_match = format_match,
+	.init = init,
+	.loadfile = loadfile,
+};
diff --git a/input/wav.c b/input/wav.c
new file mode 100644
index 0000000..1c3f050
--- /dev/null
+++ b/input/wav.c
@@ -0,0 +1,204 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "input/wav"
+
+#define CHUNK_SIZE 4096
+
+struct context {
+	uint64_t samplerate;
+	int samplesize;
+	int num_channels;
+};
+
+static int get_wav_header(const char *filename, char *buf)
+{
+	struct stat st;
+	int fd, l;
+
+	l = strlen(filename);
+	if (l <= 4 || strcasecmp(filename + l - 4, ".wav"))
+		return SR_ERR;
+
+	if (stat(filename, &st) == -1)
+		return SR_ERR;
+	if (st.st_size <= 45)
+		/* Minimum size of header + 1 8-bit mono PCM sample. */
+		return SR_ERR;
+
+	if ((fd = open(filename, O_RDONLY)) == -1)
+		return SR_ERR;
+
+	l = read(fd, buf, 40);
+	close(fd);
+	if (l != 40)
+		return SR_ERR;
+
+	return SR_OK;
+}
+
+static int format_match(const char *filename)
+{
+	char buf[40];
+
+	if (get_wav_header(filename, buf) != SR_OK)
+		return FALSE;
+
+	if (strncmp(buf, "RIFF", 4))
+		return FALSE;
+	if (strncmp(buf + 8, "WAVE", 4))
+		return FALSE;
+	if (strncmp(buf + 12, "fmt ", 4))
+		return FALSE;
+	if (GUINT16_FROM_LE(*(uint16_t *)(buf + 20)) != 1)
+		/* Not PCM. */
+		return FALSE;
+	if (strncmp(buf + 36, "data", 4))
+		return FALSE;
+
+	return TRUE;
+}
+
+static int init(struct sr_input *in, const char *filename)
+{
+	struct sr_channel *ch;
+	struct context *ctx;
+	char buf[40], channelname[8];
+	int i;
+
+	if (get_wav_header(filename, buf) != SR_OK)
+		return SR_ERR;
+
+	if (!(ctx = g_try_malloc0(sizeof(struct context))))
+		return SR_ERR_MALLOC;
+
+	/* Create a virtual device. */
+	in->sdi = sr_dev_inst_new(0, SR_ST_ACTIVE, NULL, NULL, NULL);
+	in->sdi->priv = ctx;
+
+   	ctx->samplerate = GUINT32_FROM_LE(*(uint32_t *)(buf + 24));
+	ctx->samplesize = GUINT16_FROM_LE(*(uint16_t *)(buf + 34)) / 8;
+	if (ctx->samplesize != 1 && ctx->samplesize != 2 && ctx->samplesize != 4) {
+		sr_err("only 8, 16 or 32 bits per sample supported.");
+		return SR_ERR;
+	}
+
+	if ((ctx->num_channels = GUINT16_FROM_LE(*(uint16_t *)(buf + 22))) > 20) {
+		sr_err("%d channels seems crazy.", ctx->num_channels);
+		return SR_ERR;
+	}
+
+	for (i = 0; i < ctx->num_channels; i++) {
+		snprintf(channelname, 8, "CH%d", i + 1);
+		if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, channelname)))
+			return SR_ERR;
+		in->sdi->channels = g_slist_append(in->sdi->channels, ch);
+	}
+
+	return SR_OK;
+}
+
+static int loadfile(struct sr_input *in, const char *filename)
+{
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_meta meta;
+	struct sr_datafeed_analog analog;
+	struct sr_config *src;
+	struct context *ctx;
+	float fdata[CHUNK_SIZE];
+	uint64_t sample;
+	int num_samples, chunk_samples, s, c, fd, l;
+	char buf[CHUNK_SIZE];
+
+	ctx = in->sdi->priv;
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(in->sdi, LOG_PREFIX);
+
+	packet.type = SR_DF_META;
+	packet.payload = &meta;
+	src = sr_config_new(SR_CONF_SAMPLERATE,
+			g_variant_new_uint64(ctx->samplerate));
+	meta.config = g_slist_append(NULL, src);
+	sr_session_send(in->sdi, &packet);
+	sr_config_free(src);
+
+	if ((fd = open(filename, O_RDONLY)) == -1)
+		return SR_ERR;
+
+	lseek(fd, 40, SEEK_SET);
+	l = read(fd, buf, 4);
+	num_samples = GUINT32_FROM_LE((uint32_t)*(buf));
+	num_samples /= ctx->samplesize / ctx->num_channels;
+	while (TRUE) {
+		if ((l = read(fd, buf, CHUNK_SIZE)) < 1)
+			break;
+		chunk_samples = l / ctx->samplesize / ctx->num_channels;
+		for (s = 0; s < chunk_samples; s++) {
+			for (c = 0; c < ctx->num_channels; c++) {
+				sample = 0;
+				memcpy(&sample, buf + s * ctx->samplesize + c, ctx->samplesize);
+				switch (ctx->samplesize) {
+				case 1:
+					/* 8-bit PCM samples are unsigned. */
+					fdata[s + c] = (uint8_t)sample / 255.0;
+					break;
+				case 2:
+					fdata[s + c] = GINT16_FROM_LE(sample) / 32767.0;
+					break;
+				case 4:
+					fdata[s + c] = GINT32_FROM_LE(sample) / 65535.0;
+					break;
+				}
+			}
+		}
+		packet.type = SR_DF_ANALOG;
+		packet.payload = &analog;
+		analog.channels = in->sdi->channels;
+		analog.num_samples = chunk_samples;
+		analog.mq = 0;
+		analog.unit = 0;
+		analog.data = fdata;
+		sr_session_send(in->sdi, &packet);
+	}
+
+	close(fd);
+	packet.type = SR_DF_END;
+	sr_session_send(in->sdi, &packet);
+
+	return SR_OK;
+}
+
+
+SR_PRIV struct sr_input_format input_wav = {
+	.id = "wav",
+	.description = "WAV file",
+	.format_match = format_match,
+	.init = init,
+	.loadfile = loadfile,
+};
+
diff --git a/libsigrok-internal.h b/libsigrok-internal.h
new file mode 100644
index 0000000..eb4b1a2
--- /dev/null
+++ b/libsigrok-internal.h
@@ -0,0 +1,616 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** @file
+  * @internal
+  */
+
+#ifndef LIBSIGROK_LIBSIGROK_INTERNAL_H
+#define LIBSIGROK_LIBSIGROK_INTERNAL_H
+
+#include <stdarg.h>
+#include <glib.h>
+#include "config.h" /* Needed for HAVE_LIBUSB_1_0 and others. */
+#ifdef HAVE_LIBUSB_1_0
+#include <libusb.h>
+#endif
+#ifdef HAVE_LIBSERIALPORT
+#include <libserialport.h>
+#endif
+
+/**
+ * @file
+ *
+ * libsigrok private header file, only to be used internally.
+ */
+
+/*--- Macros ----------------------------------------------------------------*/
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#endif
+
+#ifndef ARRAY_AND_SIZE
+#define ARRAY_AND_SIZE(a) (a), ARRAY_SIZE(a)
+#endif
+
+/**
+ * Read a 8 bits integer out of memory.
+ * @param x a pointer to the input memory
+ * @return the corresponding integer
+ */
+#define R8(x)     ((unsigned)((const uint8_t*)(x))[0])
+
+/**
+ * Read a 16 bits big endian integer out of memory.
+ * @param x a pointer to the input memory
+ * @return the corresponding integer
+ */
+#define RB16(x)  (((unsigned)((const uint8_t*)(x))[0] <<  8) |  \
+                   (unsigned)((const uint8_t*)(x))[1])
+
+/**
+ * Read a 16 bits little endian integer out of memory.
+ * @param x a pointer to the input memory
+ * @return the corresponding integer
+ */
+#define RL16(x)  (((unsigned)((const uint8_t*)(x))[1] <<  8) | \
+                   (unsigned)((const uint8_t*)(x))[0])
+
+/**
+ * Read a 32 bits big endian integer out of memory.
+ * @param x a pointer to the input memory
+ * @return the corresponding integer
+ */
+#define RB32(x)  (((unsigned)((const uint8_t*)(x))[0] << 24) | \
+                  ((unsigned)((const uint8_t*)(x))[1] << 16) |  \
+                  ((unsigned)((const uint8_t*)(x))[2] <<  8) |  \
+                   (unsigned)((const uint8_t*)(x))[3])
+
+/**
+ * Read a 32 bits little endian integer out of memory.
+ * @param x a pointer to the input memory
+ * @return the corresponding integer
+ */
+#define RL32(x)  (((unsigned)((const uint8_t*)(x))[3] << 24) | \
+                  ((unsigned)((const uint8_t*)(x))[2] << 16) |  \
+                  ((unsigned)((const uint8_t*)(x))[1] <<  8) |  \
+                   (unsigned)((const uint8_t*)(x))[0])
+
+/**
+ * Write a 8 bits integer to memory.
+ * @param p a pointer to the output memory
+ * @param x the input integer
+ */
+#define W8(p, x)    do { ((uint8_t*)(p))[0] = (uint8_t) (x);      } while(0)
+
+/**
+ * Write a 16 bits integer to memory stored as big endian.
+ * @param p a pointer to the output memory
+ * @param x the input integer
+ */
+#define WB16(p, x)  do { ((uint8_t*)(p))[1] = (uint8_t) (x);      \
+                         ((uint8_t*)(p))[0] = (uint8_t)((x)>>8);  } while(0)
+
+/**
+ * Write a 16 bits integer to memory stored as little endian.
+ * @param p a pointer to the output memory
+ * @param x the input integer
+ */
+#define WL16(p, x)  do { ((uint8_t*)(p))[0] = (uint8_t) (x);      \
+                         ((uint8_t*)(p))[1] = (uint8_t)((x)>>8);  } while(0)
+
+/**
+ * Write a 32 bits integer to memory stored as big endian.
+ * @param p a pointer to the output memory
+ * @param x the input integer
+ */
+#define WB32(p, x)  do { ((uint8_t*)(p))[3] = (uint8_t) (x);      \
+                         ((uint8_t*)(p))[2] = (uint8_t)((x)>>8);  \
+                         ((uint8_t*)(p))[1] = (uint8_t)((x)>>16); \
+                         ((uint8_t*)(p))[0] = (uint8_t)((x)>>24); } while(0)
+
+/**
+ * Write a 32 bits integer to memory stored as little endian.
+ * @param p a pointer to the output memory
+ * @param x the input integer
+ */
+#define WL32(p, x)  do { ((uint8_t*)(p))[0] = (uint8_t) (x);      \
+                         ((uint8_t*)(p))[1] = (uint8_t)((x)>>8);  \
+                         ((uint8_t*)(p))[2] = (uint8_t)((x)>>16); \
+                         ((uint8_t*)(p))[3] = (uint8_t)((x)>>24); } while(0)
+
+/* Portability fixes for FreeBSD. */
+#ifdef __FreeBSD__
+#define LIBUSB_CLASS_APPLICATION 0xfe
+#define libusb_handle_events_timeout_completed(ctx, tv, c) \
+	libusb_handle_events_timeout(ctx, tv)
+#endif
+
+struct sr_context {
+#ifdef HAVE_LIBUSB_1_0
+	libusb_context *libusb_ctx;
+	gboolean usb_source_present;
+#ifdef _WIN32
+	GThread *usb_thread;
+	gboolean usb_thread_running;
+	GMutex usb_mutex;
+	HANDLE usb_event;
+	GPollFD usb_pollfd;
+	sr_receive_data_callback usb_cb;
+	void *usb_cb_data;
+#endif
+#endif
+};
+
+#ifdef HAVE_LIBUSB_1_0
+/** USB device instance */
+struct sr_usb_dev_inst {
+	/** USB bus */
+	uint8_t bus;
+	/** Device address on USB bus */
+	uint8_t address;
+	/** libusb device handle */
+	struct libusb_device_handle *devhdl;
+};
+#endif
+
+#ifdef HAVE_LIBSERIALPORT
+#define SERIAL_PARITY_NONE SP_PARITY_NONE
+#define SERIAL_PARITY_EVEN SP_PARITY_EVEN
+#define SERIAL_PARITY_ODD  SP_PARITY_ODD
+struct sr_serial_dev_inst {
+	/** Port name, e.g. '/dev/tty42'. */
+	char *port;
+	/** Comm params for serial_set_paramstr(). */
+	char *serialcomm;
+	/** Port is non-blocking. */
+	int nonblocking;
+	/** libserialport port handle */
+	struct sp_port *data;
+	/** libserialport event set */
+	struct sp_event_set *event_set;
+	/** GPollFDs for event polling */
+	GPollFD *pollfds;
+};
+#endif
+
+struct sr_usbtmc_dev_inst {
+	char *device;
+	int fd;
+};
+
+/* Private driver context. */
+struct drv_context {
+	/** sigrok context */
+	struct sr_context *sr_ctx;
+	GSList *instances;
+};
+
+/*--- log.c -----------------------------------------------------------------*/
+
+SR_PRIV int sr_log(int loglevel, const char *format, ...);
+SR_PRIV int sr_spew(const char *format, ...);
+SR_PRIV int sr_dbg(const char *format, ...);
+SR_PRIV int sr_info(const char *format, ...);
+SR_PRIV int sr_warn(const char *format, ...);
+SR_PRIV int sr_err(const char *format, ...);
+
+/* Message logging helpers with subsystem-specific prefix string. */
+#ifndef NO_LOG_WRAPPERS
+#define sr_log(l, s, args...) sr_log(l, "%s: " s, LOG_PREFIX, ## args)
+#define sr_spew(s, args...) sr_spew("%s: " s, LOG_PREFIX, ## args)
+#define sr_dbg(s, args...) sr_dbg("%s: " s, LOG_PREFIX, ## args)
+#define sr_info(s, args...) sr_info("%s: " s, LOG_PREFIX, ## args)
+#define sr_warn(s, args...) sr_warn("%s: " s, LOG_PREFIX, ## args)
+#define sr_err(s, args...) sr_err("%s: " s, LOG_PREFIX, ## args)
+#endif
+
+/*--- device.c --------------------------------------------------------------*/
+
+/** Values for the changes argument of sr_dev_driver.config_channel_set. */
+enum {
+	/** The enabled state of the channel has been changed. */
+	SR_CHANNEL_SET_ENABLED = 1 << 0,
+	/** The trigger setup of the channel has been changed. */
+	SR_CHANNEL_SET_TRIGGER = 1 << 1,
+};
+
+SR_PRIV struct sr_channel *sr_channel_new(int index, int type,
+		gboolean enabled, const char *name);
+
+/* Generic device instances */
+SR_PRIV struct sr_dev_inst *sr_dev_inst_new(int index, int status,
+		const char *vendor, const char *model, const char *version);
+SR_PRIV void sr_dev_inst_free(struct sr_dev_inst *sdi);
+
+#ifdef HAVE_LIBUSB_1_0
+/* USB-specific instances */
+SR_PRIV struct sr_usb_dev_inst *sr_usb_dev_inst_new(uint8_t bus,
+		uint8_t address, struct libusb_device_handle *hdl);
+SR_PRIV void sr_usb_dev_inst_free(struct sr_usb_dev_inst *usb);
+#endif
+
+#ifdef HAVE_LIBSERIALPORT
+/* Serial-specific instances */
+SR_PRIV struct sr_serial_dev_inst *sr_serial_dev_inst_new(const char *port,
+		const char *serialcomm);
+SR_PRIV void sr_serial_dev_inst_free(struct sr_serial_dev_inst *serial);
+#endif
+
+/* USBTMC-specific instances */
+SR_PRIV struct sr_usbtmc_dev_inst *sr_usbtmc_dev_inst_new(const char *device);
+SR_PRIV void sr_usbtmc_dev_inst_free(struct sr_usbtmc_dev_inst *usbtmc);
+
+/*--- hwdriver.c ------------------------------------------------------------*/
+
+SR_PRIV void sr_hw_cleanup_all(void);
+SR_PRIV struct sr_config *sr_config_new(int key, GVariant *data);
+SR_PRIV void sr_config_free(struct sr_config *src);
+SR_PRIV int sr_source_remove(int fd);
+SR_PRIV int sr_source_add(int fd, int events, int timeout,
+		sr_receive_data_callback cb, void *cb_data);
+
+/*--- session.c -------------------------------------------------------------*/
+
+struct sr_session {
+	/** List of struct sr_dev pointers. */
+	GSList *devs;
+	/** List of struct datafeed_callback pointers. */
+	GSList *datafeed_callbacks;
+	GTimeVal starttime;
+	gboolean running;
+
+	unsigned int num_sources;
+
+	/*
+	 * Both "sources" and "pollfds" are of the same size and contain pairs
+	 * of descriptor and callback function. We can not embed the GPollFD
+	 * into the source struct since we want to be able to pass the array
+	 * of all poll descriptors to g_poll().
+	 */
+	struct source *sources;
+	GPollFD *pollfds;
+	int source_timeout;
+
+	/*
+	 * These are our synchronization primitives for stopping the session in
+	 * an async fashion. We need to make sure the session is stopped from
+	 * within the session thread itself.
+	 */
+	/** Mutex protecting access to abort_session. */
+	GMutex stop_mutex;
+	/** Abort current session. See sr_session_stop(). */
+	gboolean abort_session;
+};
+
+SR_PRIV int sr_session_send(const struct sr_dev_inst *sdi,
+		const struct sr_datafeed_packet *packet);
+SR_PRIV int sr_session_stop_sync(void);
+SR_PRIV int sr_sessionfile_check(const char *filename);
+
+/*--- std.c -----------------------------------------------------------------*/
+
+typedef int (*dev_close_callback)(struct sr_dev_inst *sdi);
+typedef void (*std_dev_clear_callback)(void *priv);
+
+SR_PRIV int std_init(struct sr_context *sr_ctx, struct sr_dev_driver *di,
+		const char *prefix);
+#ifdef HAVE_LIBSERIALPORT
+SR_PRIV int std_serial_dev_open(struct sr_dev_inst *sdi);
+SR_PRIV int std_serial_dev_acquisition_stop(struct sr_dev_inst *sdi,
+		void *cb_data, dev_close_callback dev_close_fn,
+		struct sr_serial_dev_inst *serial, const char *prefix);
+#endif
+SR_PRIV int std_session_send_df_header(const struct sr_dev_inst *sdi,
+		const char *prefix);
+SR_PRIV int std_dev_clear(const struct sr_dev_driver *driver,
+		std_dev_clear_callback clear_private);
+SR_PRIV int std_serial_dev_close(struct sr_dev_inst *sdi);
+
+/*--- strutil.c -------------------------------------------------------------*/
+
+SR_PRIV int sr_atol(const char *str, long *ret);
+SR_PRIV int sr_atoi(const char *str, int *ret);
+SR_PRIV int sr_atod(const char *str, double *ret);
+SR_PRIV int sr_atof(const char *str, float *ret);
+SR_PRIV int sr_atof_ascii(const char *str, float *ret);
+
+/*--- hardware/common/serial.c ----------------------------------------------*/
+
+#ifdef HAVE_LIBSERIALPORT
+enum {
+	SERIAL_RDWR = 1,
+	SERIAL_RDONLY = 2,
+	SERIAL_NONBLOCK = 4,
+};
+
+typedef gboolean (*packet_valid_callback)(const uint8_t *buf);
+
+SR_PRIV int serial_open(struct sr_serial_dev_inst *serial, int flags);
+SR_PRIV int serial_close(struct sr_serial_dev_inst *serial);
+SR_PRIV int serial_flush(struct sr_serial_dev_inst *serial);
+SR_PRIV int serial_write(struct sr_serial_dev_inst *serial,
+		const void *buf, size_t count);
+SR_PRIV int serial_write_blocking(struct sr_serial_dev_inst *serial,
+		const void *buf, size_t count);
+SR_PRIV int serial_write_nonblocking(struct sr_serial_dev_inst *serial,
+		const void *buf, size_t count);
+SR_PRIV int serial_read(struct sr_serial_dev_inst *serial, void *buf,
+		size_t count);
+SR_PRIV int serial_read_blocking(struct sr_serial_dev_inst *serial, void *buf,
+		size_t count);
+SR_PRIV int serial_read_nonblocking(struct sr_serial_dev_inst *serial, void *buf,
+		size_t count);
+SR_PRIV int serial_set_params(struct sr_serial_dev_inst *serial, int baudrate,
+		int bits, int parity, int stopbits, int flowcontrol, int rts, int dtr);
+SR_PRIV int serial_set_paramstr(struct sr_serial_dev_inst *serial,
+		const char *paramstr);
+SR_PRIV int serial_readline(struct sr_serial_dev_inst *serial, char **buf,
+		int *buflen, gint64 timeout_ms);
+SR_PRIV int serial_stream_detect(struct sr_serial_dev_inst *serial,
+				 uint8_t *buf, size_t *buflen,
+				 size_t packet_size,
+				 packet_valid_callback is_valid,
+				 uint64_t timeout_ms, int baudrate);
+SR_PRIV int sr_serial_extract_options(GSList *options, const char **serial_device,
+				      const char **serial_options);
+SR_PRIV int serial_source_add(struct sr_serial_dev_inst *serial, int events,
+		int timeout, sr_receive_data_callback cb, void *cb_data);
+SR_PRIV int serial_source_remove(struct sr_serial_dev_inst *serial);
+SR_PRIV GSList *sr_serial_find_usb(uint16_t vendor_id, uint16_t product_id);
+#endif
+
+/*--- hardware/common/ezusb.c -----------------------------------------------*/
+
+#ifdef HAVE_LIBUSB_1_0
+SR_PRIV int ezusb_reset(struct libusb_device_handle *hdl, int set_clear);
+SR_PRIV int ezusb_install_firmware(libusb_device_handle *hdl,
+				   const char *filename);
+SR_PRIV int ezusb_upload_firmware(libusb_device *dev, int configuration,
+				  const char *filename);
+#endif
+
+/*--- hardware/common/usb.c -------------------------------------------------*/
+
+#ifdef HAVE_LIBUSB_1_0
+SR_PRIV GSList *sr_usb_find(libusb_context *usb_ctx, const char *conn);
+SR_PRIV int sr_usb_open(libusb_context *usb_ctx, struct sr_usb_dev_inst *usb);
+SR_PRIV int usb_source_add(struct sr_context *ctx, int timeout,
+		sr_receive_data_callback cb, void *cb_data);
+SR_PRIV int usb_source_remove(struct sr_context *ctx);
+#endif
+
+/*--- hardware/common/scpi.c ------------------------------------------------*/
+
+#define SCPI_CMD_IDN "*IDN?"
+#define SCPI_CMD_OPC "*OPC?"
+
+enum {
+	SCPI_CMD_SET_TRIGGER_SOURCE,
+	SCPI_CMD_SET_TIMEBASE,
+	SCPI_CMD_SET_VERTICAL_DIV,
+	SCPI_CMD_SET_TRIGGER_SLOPE,
+	SCPI_CMD_SET_COUPLING,
+	SCPI_CMD_SET_HORIZ_TRIGGERPOS,
+	SCPI_CMD_GET_ANALOG_CHAN_STATE,
+	SCPI_CMD_GET_DIG_CHAN_STATE,
+	SCPI_CMD_GET_TIMEBASE,
+	SCPI_CMD_GET_VERTICAL_DIV,
+	SCPI_CMD_GET_VERTICAL_OFFSET,
+	SCPI_CMD_GET_TRIGGER_SOURCE,
+	SCPI_CMD_GET_HORIZ_TRIGGERPOS,
+	SCPI_CMD_GET_TRIGGER_SLOPE,
+	SCPI_CMD_GET_COUPLING,
+	SCPI_CMD_SET_ANALOG_CHAN_STATE,
+	SCPI_CMD_SET_DIG_CHAN_STATE,
+	SCPI_CMD_GET_DIG_POD_STATE,
+	SCPI_CMD_SET_DIG_POD_STATE,
+	SCPI_CMD_GET_ANALOG_DATA,
+	SCPI_CMD_GET_DIG_DATA,
+	SCPI_CMD_GET_SAMPLE_RATE,
+	SCPI_CMD_GET_SAMPLE_RATE_LIVE,
+};
+
+struct sr_scpi_hw_info {
+	char *manufacturer;
+	char *model;
+	char *serial_number;
+	char *firmware_version;
+};
+
+struct sr_scpi_dev_inst {
+	const char *name;
+	const char *prefix;
+	int priv_size;
+	GSList *(*scan)(struct drv_context *drvc);
+	int (*dev_inst_new)(void *priv, struct drv_context *drvc,
+		const char *resource, char **params, const char *serialcomm);
+	int (*open)(void *priv);
+	int (*source_add)(void *priv, int events,
+		int timeout, sr_receive_data_callback cb, void *cb_data);
+	int (*source_remove)(void *priv);
+	int (*send)(void *priv, const char *command);
+	int (*read_begin)(void *priv);
+	int (*read_data)(void *priv, char *buf, int maxlen);
+	int (*read_complete)(void *priv);
+	int (*close)(void *priv);
+	void (*free)(void *priv);
+	void *priv;
+};
+
+SR_PRIV GSList *sr_scpi_scan(struct drv_context *drvc, GSList *options,
+		struct sr_dev_inst *(*probe_device)(struct sr_scpi_dev_inst *scpi));
+SR_PRIV struct sr_scpi_dev_inst *scpi_dev_inst_new(struct drv_context *drvc,
+		const char *resource, const char *serialcomm);
+SR_PRIV int sr_scpi_open(struct sr_scpi_dev_inst *scpi);
+SR_PRIV int sr_scpi_source_add(struct sr_scpi_dev_inst *scpi, int events,
+		int timeout, sr_receive_data_callback cb, void *cb_data);
+SR_PRIV int sr_scpi_source_remove(struct sr_scpi_dev_inst *scpi);
+SR_PRIV int sr_scpi_send(struct sr_scpi_dev_inst *scpi,
+		const char *format, ...);
+SR_PRIV int sr_scpi_send_variadic(struct sr_scpi_dev_inst *scpi,
+		const char *format, va_list args);
+SR_PRIV int sr_scpi_read_begin(struct sr_scpi_dev_inst *scpi);
+SR_PRIV int sr_scpi_read_data(struct sr_scpi_dev_inst *scpi, char *buf, int maxlen);
+SR_PRIV int sr_scpi_read_complete(struct sr_scpi_dev_inst *scpi);
+SR_PRIV int sr_scpi_close(struct sr_scpi_dev_inst *scpi);
+SR_PRIV void sr_scpi_free(struct sr_scpi_dev_inst *scpi);
+
+SR_PRIV int sr_scpi_get_string(struct sr_scpi_dev_inst *scpi,
+			const char *command, char **scpi_response);
+SR_PRIV int sr_scpi_get_bool(struct sr_scpi_dev_inst *scpi,
+			const char *command, gboolean *scpi_response);
+SR_PRIV int sr_scpi_get_int(struct sr_scpi_dev_inst *scpi,
+			const char *command, int *scpi_response);
+SR_PRIV int sr_scpi_get_float(struct sr_scpi_dev_inst *scpi,
+			const char *command, float *scpi_response);
+SR_PRIV int sr_scpi_get_double(struct sr_scpi_dev_inst *scpi,
+			const char *command, double *scpi_response);
+SR_PRIV int sr_scpi_get_opc(struct sr_scpi_dev_inst *scpi);
+SR_PRIV int sr_scpi_get_floatv(struct sr_scpi_dev_inst *scpi,
+			const char *command, GArray **scpi_response);
+SR_PRIV int sr_scpi_get_uint8v(struct sr_scpi_dev_inst *scpi,
+			const char *command, GArray **scpi_response);
+SR_PRIV int sr_scpi_get_hw_id(struct sr_scpi_dev_inst *scpi,
+			struct sr_scpi_hw_info **scpi_response);
+SR_PRIV void sr_scpi_hw_info_free(struct sr_scpi_hw_info *hw_info);
+
+/*--- hardware/common/dmm/es519xx.c -----------------------------------------*/
+
+/**
+ * All 11-byte es519xx chips repeat each block twice for each conversion cycle
+ * so always read 2 blocks at a time.
+ */
+#define ES519XX_11B_PACKET_SIZE (11 * 2)
+#define ES519XX_14B_PACKET_SIZE 14
+
+struct es519xx_info {
+	gboolean is_judge, is_voltage, is_auto, is_micro, is_current;
+	gboolean is_milli, is_resistance, is_continuity, is_diode;
+	gboolean is_frequency, is_rpm, is_capacitance, is_duty_cycle;
+	gboolean is_temperature, is_celsius, is_fahrenheit;
+	gboolean is_adp0, is_adp1, is_adp2, is_adp3;
+	gboolean is_sign, is_batt, is_ol, is_pmax, is_pmin, is_apo;
+	gboolean is_dc, is_ac, is_vahz, is_min, is_max, is_rel, is_hold;
+	gboolean is_digit4, is_ul, is_vasel, is_vbar, is_lpf1, is_lpf0, is_rmr;
+	uint32_t baudrate;
+	int packet_size;
+	gboolean alt_functions, fivedigits, clampmeter, selectable_lpf;
+};
+
+SR_PRIV gboolean sr_es519xx_2400_11b_packet_valid(const uint8_t *buf);
+SR_PRIV int sr_es519xx_2400_11b_parse(const uint8_t *buf, float *floatval,
+		struct sr_datafeed_analog *analog, void *info);
+SR_PRIV gboolean sr_es519xx_2400_11b_altfn_packet_valid(const uint8_t *buf);
+SR_PRIV int sr_es519xx_2400_11b_altfn_parse(const uint8_t *buf,
+		float *floatval, struct sr_datafeed_analog *analog, void *info);
+SR_PRIV gboolean sr_es519xx_19200_11b_5digits_packet_valid(const uint8_t *buf);
+SR_PRIV int sr_es519xx_19200_11b_5digits_parse(const uint8_t *buf,
+		float *floatval, struct sr_datafeed_analog *analog, void *info);
+SR_PRIV gboolean sr_es519xx_19200_11b_clamp_packet_valid(const uint8_t *buf);
+SR_PRIV int sr_es519xx_19200_11b_clamp_parse(const uint8_t *buf,
+		float *floatval, struct sr_datafeed_analog *analog, void *info);
+SR_PRIV gboolean sr_es519xx_19200_11b_packet_valid(const uint8_t *buf);
+SR_PRIV int sr_es519xx_19200_11b_parse(const uint8_t *buf, float *floatval,
+		struct sr_datafeed_analog *analog, void *info);
+SR_PRIV gboolean sr_es519xx_19200_14b_packet_valid(const uint8_t *buf);
+SR_PRIV int sr_es519xx_19200_14b_parse(const uint8_t *buf, float *floatval,
+		struct sr_datafeed_analog *analog, void *info);
+SR_PRIV gboolean sr_es519xx_19200_14b_sel_lpf_packet_valid(const uint8_t *buf);
+SR_PRIV int sr_es519xx_19200_14b_sel_lpf_parse(const uint8_t *buf,
+		float *floatval, struct sr_datafeed_analog *analog, void *info);
+
+/*--- hardware/common/dmm/fs9922.c ------------------------------------------*/
+
+#define FS9922_PACKET_SIZE 14
+
+struct fs9922_info {
+	gboolean is_auto, is_dc, is_ac, is_rel, is_hold, is_bpn, is_z1, is_z2;
+	gboolean is_max, is_min, is_apo, is_bat, is_nano, is_z3, is_micro;
+	gboolean is_milli, is_kilo, is_mega, is_beep, is_diode, is_percent;
+	gboolean is_z4, is_volt, is_ampere, is_ohm, is_hfe, is_hertz, is_farad;
+	gboolean is_celsius, is_fahrenheit;
+	int bargraph_sign, bargraph_value;
+};
+
+SR_PRIV gboolean sr_fs9922_packet_valid(const uint8_t *buf);
+SR_PRIV int sr_fs9922_parse(const uint8_t *buf, float *floatval,
+			    struct sr_datafeed_analog *analog, void *info);
+SR_PRIV void sr_fs9922_z1_diode(struct sr_datafeed_analog *analog, void *info);
+
+/*--- hardware/common/dmm/fs9721.c ------------------------------------------*/
+
+#define FS9721_PACKET_SIZE 14
+
+struct fs9721_info {
+	gboolean is_ac, is_dc, is_auto, is_rs232, is_micro, is_nano, is_kilo;
+	gboolean is_diode, is_milli, is_percent, is_mega, is_beep, is_farad;
+	gboolean is_ohm, is_rel, is_hold, is_ampere, is_volt, is_hz, is_bat;
+	gboolean is_c2c1_11, is_c2c1_10, is_c2c1_01, is_c2c1_00, is_sign;
+};
+
+SR_PRIV gboolean sr_fs9721_packet_valid(const uint8_t *buf);
+SR_PRIV int sr_fs9721_parse(const uint8_t *buf, float *floatval,
+			    struct sr_datafeed_analog *analog, void *info);
+SR_PRIV void sr_fs9721_00_temp_c(struct sr_datafeed_analog *analog, void *info);
+SR_PRIV void sr_fs9721_01_temp_c(struct sr_datafeed_analog *analog, void *info);
+SR_PRIV void sr_fs9721_10_temp_c(struct sr_datafeed_analog *analog, void *info);
+SR_PRIV void sr_fs9721_01_10_temp_f_c(struct sr_datafeed_analog *analog, void *info);
+SR_PRIV void sr_fs9721_max_c_min(struct sr_datafeed_analog *analog, void *info);
+
+/*--- hardware/common/dmm/m2110.c -----------------------------------------*/
+
+#define BBCGM_M2110_PACKET_SIZE 9
+
+SR_PRIV gboolean sr_m2110_packet_valid(const uint8_t *buf);
+SR_PRIV int sr_m2110_parse(const uint8_t *buf, float *floatval,
+			     struct sr_datafeed_analog *analog, void *info);
+
+/*--- hardware/common/dmm/metex14.c -----------------------------------------*/
+
+#define METEX14_PACKET_SIZE 14
+
+struct metex14_info {
+	gboolean is_ac, is_dc, is_resistance, is_capacity, is_temperature;
+	gboolean is_diode, is_frequency, is_ampere, is_volt, is_farad;
+	gboolean is_hertz, is_ohm, is_celsius, is_pico, is_nano, is_micro;
+	gboolean is_milli, is_kilo, is_mega, is_gain, is_decibel, is_hfe;
+	gboolean is_unitless, is_logic;
+};
+
+#ifdef HAVE_LIBSERIALPORT
+SR_PRIV int sr_metex14_packet_request(struct sr_serial_dev_inst *serial);
+#endif
+SR_PRIV gboolean sr_metex14_packet_valid(const uint8_t *buf);
+SR_PRIV int sr_metex14_parse(const uint8_t *buf, float *floatval,
+			     struct sr_datafeed_analog *analog, void *info);
+
+/*--- hardware/common/dmm/rs9lcd.c ------------------------------------------*/
+
+#define RS9LCD_PACKET_SIZE 9
+
+/* Dummy info struct. The parser does not use it. */
+struct rs9lcd_info { int dummy; };
+
+SR_PRIV gboolean sr_rs9lcd_packet_valid(const uint8_t *buf);
+SR_PRIV int sr_rs9lcd_parse(const uint8_t *buf, float *floatval,
+			    struct sr_datafeed_analog *analog, void *info);
+
+#endif
diff --git a/libsigrok.h b/libsigrok.h
new file mode 100644
index 0000000..0b6888d
--- /dev/null
+++ b/libsigrok.h
@@ -0,0 +1,975 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_LIBSIGROK_H
+#define LIBSIGROK_LIBSIGROK_H
+
+#include <stdio.h>
+#include <sys/time.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <glib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file
+ *
+ * The public libsigrok header file to be used by frontends.
+ *
+ * This is the only file that libsigrok users (frontends) are supposed to
+ * use and \#include. There are other header files which get installed with
+ * libsigrok, but those are not meant to be used directly by frontends.
+ *
+ * The correct way to get/use the libsigrok API functions is:
+ *
+ * @code{.c}
+ *   #include <libsigrok/libsigrok.h>
+ * @endcode
+ */
+
+/*
+ * All possible return codes of libsigrok functions must be listed here.
+ * Functions should never return hardcoded numbers as status, but rather
+ * use these enum values. All error codes are negative numbers.
+ *
+ * The error codes are globally unique in libsigrok, i.e. if one of the
+ * libsigrok functions returns a "malloc error" it must be exactly the same
+ * return value as used by all other functions to indicate "malloc error".
+ * There must be no functions which indicate two different errors via the
+ * same return code.
+ *
+ * Also, for compatibility reasons, no defined return codes are ever removed
+ * or reused for different errors later. You can only add new entries and
+ * return codes, but never remove or redefine existing ones.
+ */
+
+/** Status/error codes returned by libsigrok functions. */
+enum sr_error_code {
+	SR_OK                =  0, /**< No error. */
+	SR_ERR               = -1, /**< Generic/unspecified error. */
+	SR_ERR_MALLOC        = -2, /**< Malloc/calloc/realloc error. */
+	SR_ERR_ARG           = -3, /**< Function argument error. */
+	SR_ERR_BUG           = -4, /**< Errors hinting at internal bugs. */
+	SR_ERR_SAMPLERATE    = -5, /**< Incorrect samplerate. */
+	SR_ERR_NA            = -6, /**< Not applicable. */
+	SR_ERR_DEV_CLOSED    = -7, /**< Device is closed, but must be open. */
+	SR_ERR_TIMEOUT       = -8, /**< A timeout occurred. */
+	SR_ERR_CHANNEL_GROUP = -9, /**< A channel group must be specified. */
+
+	/*
+	 * Note: When adding entries here, don't forget to also update the
+	 * sr_strerror() and sr_strerror_name() functions in error.c.
+	 */
+};
+
+#define SR_MAX_CHANNELNAME_LEN 32
+
+/* Handy little macros */
+#define SR_HZ(n)  (n)
+#define SR_KHZ(n) ((n) * (uint64_t)(1000ULL))
+#define SR_MHZ(n) ((n) * (uint64_t)(1000000ULL))
+#define SR_GHZ(n) ((n) * (uint64_t)(1000000000ULL))
+
+#define SR_HZ_TO_NS(n) ((uint64_t)(1000000000ULL) / (n))
+
+/** libsigrok loglevels. */
+enum sr_loglevel {
+	SR_LOG_NONE = 0, /**< Output no messages at all. */
+	SR_LOG_ERR  = 1, /**< Output error messages. */
+	SR_LOG_WARN = 2, /**< Output warnings. */
+	SR_LOG_INFO = 3, /**< Output informational messages. */
+	SR_LOG_DBG  = 4, /**< Output debug messages. */
+	SR_LOG_SPEW = 5, /**< Output very noisy debug messages. */
+};
+
+/*
+ * Use SR_API to mark public API symbols, and SR_PRIV for private symbols.
+ *
+ * Variables and functions marked 'static' are private already and don't
+ * need SR_PRIV. However, functions which are not static (because they need
+ * to be used in other libsigrok-internal files) but are also not meant to
+ * be part of the public libsigrok API, must use SR_PRIV.
+ *
+ * This uses the 'visibility' feature of gcc (requires gcc >= 4.0).
+ *
+ * This feature is not available on MinGW/Windows, as it is a feature of
+ * ELF files and MinGW/Windows uses PE files.
+ *
+ * Details: http://gcc.gnu.org/wiki/Visibility
+ */
+
+/* Marks public libsigrok API symbols. */
+#ifndef _WIN32
+#define SR_API __attribute__((visibility("default")))
+#else
+#define SR_API
+#endif
+
+/* Marks private, non-public libsigrok symbols (not part of the API). */
+#ifndef _WIN32
+#define SR_PRIV __attribute__((visibility("hidden")))
+#else
+#define SR_PRIV
+#endif
+
+/** Type definition for callback function for data reception. */
+typedef int (*sr_receive_data_callback)(int fd, int revents, void *cb_data);
+
+/** Data types used by sr_config_info(). */
+enum sr_datatype {
+	SR_T_UINT64 = 10000,
+	SR_T_STRING,
+	SR_T_BOOL,
+	SR_T_FLOAT,
+	SR_T_RATIONAL_PERIOD,
+	SR_T_RATIONAL_VOLT,
+	SR_T_KEYVALUE,
+	SR_T_UINT64_RANGE,
+	SR_T_DOUBLE_RANGE,
+	SR_T_INT32,
+};
+
+/** Value for sr_datafeed_packet.type. */
+enum sr_packettype {
+	/** Payload is sr_datafeed_header. */
+	SR_DF_HEADER = 10000,
+	/** End of stream (no further data). */
+	SR_DF_END,
+	/** Payload is struct sr_datafeed_meta */
+	SR_DF_META,
+	/** The trigger matched at this point in the data feed. No payload. */
+	SR_DF_TRIGGER,
+	/** Payload is struct sr_datafeed_logic. */
+	SR_DF_LOGIC,
+	/** Payload is struct sr_datafeed_analog. */
+	SR_DF_ANALOG,
+	/** Beginning of frame. No payload. */
+	SR_DF_FRAME_BEGIN,
+	/** End of frame. No payload. */
+	SR_DF_FRAME_END,
+};
+
+/** Measured quantity, sr_datafeed_analog.mq. */
+enum sr_mq {
+	SR_MQ_VOLTAGE = 10000,
+	SR_MQ_CURRENT,
+	SR_MQ_RESISTANCE,
+	SR_MQ_CAPACITANCE,
+	SR_MQ_TEMPERATURE,
+	SR_MQ_FREQUENCY,
+	/** Duty cycle, e.g. on/off ratio. */
+	SR_MQ_DUTY_CYCLE,
+	/** Continuity test. */
+	SR_MQ_CONTINUITY,
+	SR_MQ_PULSE_WIDTH,
+	SR_MQ_CONDUCTANCE,
+	/** Electrical power, usually in W, or dBm. */
+	SR_MQ_POWER,
+	/** Gain (a transistor's gain, or hFE, for example). */
+	SR_MQ_GAIN,
+	/** Logarithmic representation of sound pressure relative to a
+	 * reference value. */
+	SR_MQ_SOUND_PRESSURE_LEVEL,
+	/** Carbon monoxide level */
+	SR_MQ_CARBON_MONOXIDE,
+	/** Humidity */
+	SR_MQ_RELATIVE_HUMIDITY,
+	/** Time */
+	SR_MQ_TIME,
+};
+
+/** Unit of measured quantity, sr_datafeed_analog.unit. */
+enum sr_unit {
+	/** Volt */
+	SR_UNIT_VOLT = 10000,
+	/** Ampere (current). */
+	SR_UNIT_AMPERE,
+	/** Ohm (resistance). */
+	SR_UNIT_OHM,
+	/** Farad (capacity). */
+	SR_UNIT_FARAD,
+	/** Kelvin (temperature). */
+	SR_UNIT_KELVIN,
+	/** Degrees Celsius (temperature). */
+	SR_UNIT_CELSIUS,
+	/** Degrees Fahrenheit (temperature). */
+	SR_UNIT_FAHRENHEIT,
+	/** Hertz (frequency, 1/s, [Hz]). */
+	SR_UNIT_HERTZ,
+	/** Percent value. */
+	SR_UNIT_PERCENTAGE,
+	/** Boolean value. */
+	SR_UNIT_BOOLEAN,
+	/** Time in seconds. */
+	SR_UNIT_SECOND,
+	/** Unit of conductance, the inverse of resistance. */
+	SR_UNIT_SIEMENS,
+	/**
+	 * An absolute measurement of power, in decibels, referenced to
+	 * 1 milliwatt (dBu).
+	 */
+	SR_UNIT_DECIBEL_MW,
+	/** Voltage in decibel, referenced to 1 volt (dBV). */
+	SR_UNIT_DECIBEL_VOLT,
+	/**
+	 * Measurements that intrinsically do not have units attached, such
+	 * as ratios, gains, etc. Specifically, a transistor's gain (hFE) is
+	 * a unitless quantity, for example.
+	 */
+	SR_UNIT_UNITLESS,
+	/** Sound pressure level relative so 20 micropascals. */
+	SR_UNIT_DECIBEL_SPL,
+	/**
+	 * Normalized (0 to 1) concentration of a substance or compound with 0
+	 * representing a concentration of 0%, and 1 being 100%. This is
+	 * represented as the fraction of number of particles of the substance.
+	 */
+	SR_UNIT_CONCENTRATION,
+	/** Revolutions per minute. */
+	SR_UNIT_REVOLUTIONS_PER_MINUTE,
+	/** Apparent power [VA]. */
+	SR_UNIT_VOLT_AMPERE,
+	/** Real power [W]. */
+	SR_UNIT_WATT,
+	/** Consumption [Wh]. */
+	SR_UNIT_WATT_HOUR,
+};
+
+/** Values for sr_datafeed_analog.flags. */
+enum sr_mqflag {
+	/** Voltage measurement is alternating current (AC). */
+	SR_MQFLAG_AC = 0x01,
+	/** Voltage measurement is direct current (DC). */
+	SR_MQFLAG_DC = 0x02,
+	/** This is a true RMS measurement. */
+	SR_MQFLAG_RMS = 0x04,
+	/** Value is voltage drop across a diode, or NAN. */
+	SR_MQFLAG_DIODE = 0x08,
+	/** Device is in "hold" mode (repeating the last measurement). */
+	SR_MQFLAG_HOLD = 0x10,
+	/** Device is in "max" mode, only updating upon a new max value. */
+	SR_MQFLAG_MAX = 0x20,
+	/** Device is in "min" mode, only updating upon a new min value. */
+	SR_MQFLAG_MIN = 0x40,
+	/** Device is in autoranging mode. */
+	SR_MQFLAG_AUTORANGE = 0x80,
+	/** Device is in relative mode. */
+	SR_MQFLAG_RELATIVE = 0x100,
+	/** Sound pressure level is A-weighted in the frequency domain,
+	 * according to IEC 61672:2003. */
+	SR_MQFLAG_SPL_FREQ_WEIGHT_A = 0x200,
+	/** Sound pressure level is C-weighted in the frequency domain,
+	 * according to IEC 61672:2003. */
+	SR_MQFLAG_SPL_FREQ_WEIGHT_C = 0x400,
+	/** Sound pressure level is Z-weighted (i.e. not at all) in the
+	 * frequency domain, according to IEC 61672:2003. */
+	SR_MQFLAG_SPL_FREQ_WEIGHT_Z = 0x800,
+	/** Sound pressure level is not weighted in the frequency domain,
+	 * albeit without standards-defined low and high frequency limits. */
+	SR_MQFLAG_SPL_FREQ_WEIGHT_FLAT = 0x1000,
+	/** Sound pressure level measurement is S-weighted (1s) in the
+	 * time domain. */
+	SR_MQFLAG_SPL_TIME_WEIGHT_S = 0x2000,
+	/** Sound pressure level measurement is F-weighted (125ms) in the
+	 * time domain. */
+	SR_MQFLAG_SPL_TIME_WEIGHT_F = 0x4000,
+	/** Sound pressure level is time-averaged (LAT), also known as
+	 * Equivalent Continuous A-weighted Sound Level (LEQ). */
+	SR_MQFLAG_SPL_LAT = 0x8000,
+	/** Sound pressure level represented as a percentage of measurements
+	 * that were over a preset alarm level. */
+	SR_MQFLAG_SPL_PCT_OVER_ALARM = 0x10000,
+	/** Time is duration (as opposed to epoch, ...). */
+	SR_MQFLAG_DURATION = 0x20000,
+	/** Device is in "avg" mode, averaging upon each new value. */
+	SR_MQFLAG_AVG = 0x40000,
+};
+
+/**
+ * @struct sr_context
+ * Opaque structure representing a libsigrok context.
+ *
+ * None of the fields of this structure are meant to be accessed directly.
+ *
+ * @see sr_init(), sr_exit().
+ */
+struct sr_context;
+
+/** Packet in a sigrok data feed. */
+struct sr_datafeed_packet {
+	uint16_t type;
+	const void *payload;
+};
+
+/** Header of a sigrok data feed. */
+struct sr_datafeed_header {
+	int feed_version;
+	struct timeval starttime;
+};
+
+/** Datafeed payload for type SR_DF_META. */
+struct sr_datafeed_meta {
+	GSList *config;
+};
+
+/** Logic datafeed payload for type SR_DF_LOGIC. */
+struct sr_datafeed_logic {
+	uint64_t length;
+	uint16_t unitsize;
+	void *data;
+};
+
+/** Analog datafeed payload for type SR_DF_ANALOG. */
+struct sr_datafeed_analog {
+	/** The channels for which data is included in this packet. */
+	GSList *channels;
+	/** Number of samples in data */
+	int num_samples;
+	/** Measured quantity (voltage, current, temperature, and so on).
+	 *  Use SR_MQ_VOLTAGE, ... */
+	int mq;
+	/** Unit in which the MQ is measured. Use SR_UNIT_VOLT, ... */
+	int unit;
+	/** Bitmap with extra information about the MQ. Use SR_MQFLAG_AC, ... */
+	uint64_t mqflags;
+	/** The analog value(s). The data is interleaved according to
+	 * the channels list. */
+	float *data;
+};
+
+/** Input (file) format struct. */
+struct sr_input {
+	/**
+	 * A pointer to this input format's 'struct sr_input_format'.
+	 * The frontend can use this to call the module's callbacks.
+	 */
+	struct sr_input_format *format;
+
+	GHashTable *param;
+
+	struct sr_dev_inst *sdi;
+
+	void *internal;
+};
+
+/** Input (file) format driver. */
+struct sr_input_format {
+	/** The unique ID for this input format. Must not be NULL. */
+	char *id;
+
+	/**
+	 * A short description of the input format, which can (for example)
+	 * be displayed to the user by frontends. Must not be NULL.
+	 */
+	char *description;
+
+	/**
+	 * Check if this input module can load and parse the specified file.
+	 *
+	 * @param[in] filename The name (and path) of the file to check.
+	 *
+	 * @retval TRUE This module knows the format.
+	 * @retval FALSE This module does not know the format.
+	 */
+	int (*format_match) (const char *filename);
+
+	/**
+	 * Initialize the input module.
+	 *
+	 * @param in A pointer to a valid 'struct sr_input' that the caller
+	 *           has to allocate and provide to this function. It is also
+	 *           the responsibility of the caller to free it later.
+	 * @param[in] filename The name (and path) of the file to use.
+	 *
+	 * @retval SR_OK Success
+	 * @retval other Negative error code.
+	 */
+	int (*init) (struct sr_input *in, const char *filename);
+
+	/**
+	 * Load a file, parsing the input according to the file's format.
+	 *
+	 * This function will send datafeed packets to the session bus, so
+	 * the calling frontend must have registered its session callbacks
+	 * beforehand.
+	 *
+	 * The packet types sent across the session bus by this function must
+	 * include at least SR_DF_HEADER, SR_DF_END, and an appropriate data
+	 * type such as SR_DF_LOGIC. It may also send a SR_DF_TRIGGER packet
+	 * if appropriate.
+	 *
+	 * @param in A pointer to a valid 'struct sr_input' that the caller
+	 *           has to allocate and provide to this function. It is also
+	 *           the responsibility of the caller to free it later.
+	 * @param filename The name (and path) of the file to use.
+	 *
+	 * @retval SR_OK Success
+	 * @retval other Negative error code.
+	 */
+	int (*loadfile) (struct sr_input *in, const char *filename);
+};
+
+/** Output (file) format struct. */
+struct sr_output {
+	/** A pointer to this output's format.  */
+	struct sr_output_format *format;
+
+	/**
+	 * The device for which this output module is creating output. This
+	 * can be used by the module to find out channel names and numbers.
+	 */
+	const struct sr_dev_inst *sdi;
+
+	/**
+	 * An optional parameter which the frontend can pass in to the
+	 * output module. How the string is interpreted is entirely up to
+	 * the module.
+	 */
+	GHashTable *params;
+
+	/**
+	 * A generic pointer which can be used by the module to keep internal
+	 * state between calls into its callback functions.
+	 *
+	 * For example, the module might store a pointer to a chunk of output
+	 * there, and only flush it when it reaches a certain size.
+	 */
+	void *internal;
+};
+
+/** Output (file) format driver. */
+struct sr_output_format {
+	/**
+	 * A unique ID for this output format. Must not be NULL.
+	 *
+	 * It can be used by frontends to select this output format for use.
+	 *
+	 * For example, calling sigrok-cli with <code>-O hex</code> will
+	 * select the hexadecimal text output format.
+	 */
+	char *id;
+
+	/**
+	 * A short description of the output format. Must not be NULL.
+	 *
+	 * This can be displayed by frontends, e.g. when selecting the output
+	 * format for saving a file.
+	 */
+	char *description;
+
+	/**
+	 * This function is called once, at the beginning of an output stream.
+	 *
+	 * The device struct will be available in the output struct passed in,
+	 * as well as the param field -- which may be NULL or an empty string,
+	 * if no parameter was passed.
+	 *
+	 * The module can use this to initialize itself, create a struct for
+	 * keeping state and storing it in the <code>internal</code> field.
+	 *
+	 * @param o Pointer to the respective 'struct sr_output'.
+	 *
+	 * @retval SR_OK Success
+	 * @retval other Negative error code.
+	 */
+	int (*init) (struct sr_output *o);
+
+	/**
+	 * This function is passed a copy of every packed in the data feed.
+	 * Any output generated by the output module in response to the
+	 * packet should be returned in a newly allocated GString
+	 * <code>out</code>, which will be freed by the caller.
+	 *
+	 * Packets not of interest to the output module can just be ignored,
+	 * and the <code>out</code> parameter set to NULL.
+	 *
+	 * @param o Pointer to the respective 'struct sr_output'.
+	 * @param sdi The device instance that generated the packet.
+	 * @param packet The complete packet.
+	 * @param out A pointer where a GString * should be stored if
+	 * the module generates output, or NULL if not.
+	 *
+	 * @retval SR_OK Success
+	 * @retval other Negative error code.
+	 */
+	int (*receive) (struct sr_output *o,
+			const struct sr_datafeed_packet *packet, GString **out);
+
+	/**
+	 * This function is called after the caller is finished using
+	 * the output module, and can be used to free any internal
+	 * resources the module may keep.
+	 *
+	 * @retval SR_OK Success
+	 * @retval other Negative error code.
+	 */
+	int (*cleanup) (struct sr_output *o);
+};
+
+/** Constants for channel type. */
+enum sr_channeltype {
+	/** Channel type is logic channel. */
+	SR_CHANNEL_LOGIC = 10000,
+	/** Channel type is analog channel. */
+	SR_CHANNEL_ANALOG,
+};
+
+/** Information on single channel. */
+struct sr_channel {
+	/** Number of channels, starting at 0. */
+	int index;
+	/** Channel type (SR_CHANNEL_LOGIC, ...) */
+	int type;
+	/** Is this channel enabled? */
+	gboolean enabled;
+	/** Name of channel. */
+	char *name;
+	/** Trigger string, format like used by sigrok-cli */
+	char *trigger;
+};
+
+/** Structure for groups of channels that have common properties. */
+struct sr_channel_group {
+	/** Name of the channel group. */
+	char *name;
+	/** List of sr_channel structs of the channels belonging to this group. */
+	GSList *channels;
+	/** Private data for driver use. */
+	void *priv;
+};
+
+/** Used for setting or getting value of a config item. */
+struct sr_config {
+	/** Config key like SR_CONF_CONN, etc. */
+	int key;
+	/** Key-specific data. */
+	GVariant *data;
+};
+
+/** Information about a config key. */
+struct sr_config_info {
+	/** Config key like SR_CONF_CONN, etc. */
+	int key;
+	/** Data type like SR_T_STRING, etc. */
+	int datatype;
+	/** Id string, e.g. "serialcomm". */
+	char *id;
+	/** Name, e.g. "Serial communication". */
+	char *name;
+	/** Verbose description (unused currently). */
+	char *description;
+};
+
+/** Constants for device classes */
+enum sr_configkey {
+	/*--- Device classes ------------------------------------------------*/
+
+	/** The device can act as logic analyzer. */
+	SR_CONF_LOGIC_ANALYZER = 10000,
+
+	/** The device can act as an oscilloscope. */
+	SR_CONF_OSCILLOSCOPE,
+
+	/** The device can act as a multimeter. */
+	SR_CONF_MULTIMETER,
+
+	/** The device is a demo device. */
+	SR_CONF_DEMO_DEV,
+
+	/** The device can act as a sound level meter. */
+	SR_CONF_SOUNDLEVELMETER,
+
+	/** The device can measure temperature. */
+	SR_CONF_THERMOMETER,
+
+	/** The device can measure humidity. */
+	SR_CONF_HYGROMETER,
+
+	/** The device can measure energy consumption. */
+	SR_CONF_ENERGYMETER,
+
+	/** The device can demodulate signals. */
+	SR_CONF_DEMODULATOR,
+
+	/** Programmable power supply. */
+	SR_CONF_POWER_SUPPLY,
+
+	/*--- Driver scan options -------------------------------------------*/
+
+	/**
+	 * Specification on how to connect to a device.
+	 *
+	 * In combination with SR_CONF_SERIALCOMM, this is a serial port in
+	 * the form which makes sense to the OS (e.g., /dev/ttyS0).
+	 * Otherwise this specifies a USB device, either in the form of
+	 * @verbatim <bus>.<address> @endverbatim (decimal, e.g. 1.65) or
+	 * @verbatim <vendorid>.<productid> @endverbatim
+	 * (hexadecimal, e.g. 1d6b.0001).
+	 */
+	SR_CONF_CONN = 20000,
+
+	/**
+	 * Serial communication specification, in the form:
+	 *
+	 *   @verbatim <baudrate>/<databits><parity><stopbits> @endverbatim
+	 *
+	 * Example: 9600/8n1
+	 *
+	 * The string may also be followed by one or more special settings,
+	 * in the form "/key=value". Supported keys and their values are:
+	 *
+	 * rts    0,1    set the port's RTS pin to low or high
+	 * dtr    0,1    set the port's DTR pin to low or high
+	 * flow   0      no flow control
+	 *        1      hardware-based (RTS/CTS) flow control
+	 *        2      software-based (XON/XOFF) flow control
+	 *
+	 * This is always an optional parameter, since a driver typically
+	 * knows the speed at which the device wants to communicate.
+	 */
+	SR_CONF_SERIALCOMM,
+
+	/*--- Device configuration ------------------------------------------*/
+
+	/** The device supports setting its samplerate, in Hz. */
+	SR_CONF_SAMPLERATE = 30000,
+
+	/** The device supports setting a pre/post-trigger capture ratio. */
+	SR_CONF_CAPTURE_RATIO,
+
+	/** The device supports setting a pattern (pattern generator mode). */
+	SR_CONF_PATTERN_MODE,
+
+	/** The device supports Run Length Encoding. */
+	SR_CONF_RLE,
+
+	/** The device supports setting trigger slope. */
+	SR_CONF_TRIGGER_SLOPE,
+
+	/** Trigger source. */
+	SR_CONF_TRIGGER_SOURCE,
+
+	/** Horizontal trigger position. */
+	SR_CONF_HORIZ_TRIGGERPOS,
+
+	/** Buffer size. */
+	SR_CONF_BUFFERSIZE,
+
+	/** Time base. */
+	SR_CONF_TIMEBASE,
+
+	/** Filter. */
+	SR_CONF_FILTER,
+
+	/** Volts/div. */
+	SR_CONF_VDIV,
+
+	/** Coupling. */
+	SR_CONF_COUPLING,
+
+	/** Trigger types.  */
+	SR_CONF_TRIGGER_TYPE,
+
+	/** The device supports setting its sample interval, in ms. */
+	SR_CONF_SAMPLE_INTERVAL,
+
+	/** Number of timebases, as related to SR_CONF_TIMEBASE.  */
+	SR_CONF_NUM_TIMEBASE,
+
+	/** Number of vertical divisions, as related to SR_CONF_VDIV.  */
+	SR_CONF_NUM_VDIV,
+
+	/** Sound pressure level frequency weighting.  */
+	SR_CONF_SPL_WEIGHT_FREQ,
+
+	/** Sound pressure level time weighting.  */
+	SR_CONF_SPL_WEIGHT_TIME,
+
+	/** Sound pressure level measurement range.  */
+	SR_CONF_SPL_MEASUREMENT_RANGE,
+
+	/** Max hold mode. */
+	SR_CONF_HOLD_MAX,
+
+	/** Min hold mode. */
+	SR_CONF_HOLD_MIN,
+
+	/** Logic low-high threshold range. */
+	SR_CONF_VOLTAGE_THRESHOLD,
+
+	/** The device supports using an external clock. */
+	SR_CONF_EXTERNAL_CLOCK,
+
+	/**
+	 * The device supports swapping channels. Typical this is between
+	 * buffered and unbuffered channels.
+	 */
+	SR_CONF_SWAP,
+
+	/** Center frequency.
+	 * The input signal is downmixed by this frequency before the ADC
+	 * anti-aliasing filter.
+	 */
+	SR_CONF_CENTER_FREQUENCY,
+
+	/** The device supports setting the number of logic channels. */
+	SR_CONF_NUM_LOGIC_CHANNELS,
+
+	/** The device supports setting the number of analog channels. */
+	SR_CONF_NUM_ANALOG_CHANNELS,
+
+	/** Output voltage. */
+	SR_CONF_OUTPUT_VOLTAGE,
+
+	/** Maximum output voltage. */
+	SR_CONF_OUTPUT_VOLTAGE_MAX,
+
+	/** Output current. */
+	SR_CONF_OUTPUT_CURRENT,
+
+	/** Maximum output current. */
+	SR_CONF_OUTPUT_CURRENT_MAX,
+
+	/** Enabling/disabling output. */
+	SR_CONF_OUTPUT_ENABLED,
+
+	/** Channel output configuration. */
+	SR_CONF_OUTPUT_CHANNEL,
+
+	/** Over-voltage protection (OVP) */
+	SR_CONF_OVER_VOLTAGE_PROTECTION,
+
+	/** Over-current protection (OCP) */
+	SR_CONF_OVER_CURRENT_PROTECTION,
+
+	/** Choice of clock edge for external clock ("r" or "f"). */
+	SR_CONF_CLOCK_EDGE,
+
+	/*--- Special stuff -------------------------------------------------*/
+
+	/** Scan options supported by the driver. */
+	SR_CONF_SCAN_OPTIONS = 40000,
+
+	/** Device options for a particular device. */
+	SR_CONF_DEVICE_OPTIONS,
+
+	/** Session filename. */
+	SR_CONF_SESSIONFILE,
+
+	/** The device supports specifying a capturefile to inject. */
+	SR_CONF_CAPTUREFILE,
+
+	/** The device supports specifying the capturefile unit size. */
+	SR_CONF_CAPTURE_UNITSIZE,
+
+	/** Power off the device. */
+	SR_CONF_POWER_OFF,
+
+	/**
+	 * Data source for acquisition. If not present, acquisition from
+	 * the device is always "live", i.e. acquisition starts when the
+	 * frontend asks and the results are sent out as soon as possible.
+	 *
+	 * If present, it indicates that either the device has no live
+	 * acquisition capability (for example a pure data logger), or
+	 * there is a choice. sr_config_list() returns those choices.
+	 *
+	 * In any case if a device has live acquisition capabilities, it
+	 * is always the default.
+	 */
+	SR_CONF_DATA_SOURCE,
+
+	/*--- Acquisition modes ---------------------------------------------*/
+
+	/**
+	 * The device supports setting a sample time limit (how long
+	 * the sample acquisition should run, in ms).
+	 */
+	SR_CONF_LIMIT_MSEC = 50000,
+
+	/**
+	 * The device supports setting a sample number limit (how many
+	 * samples should be acquired).
+	 */
+	SR_CONF_LIMIT_SAMPLES,
+
+	/**
+	 * The device supports setting a frame limit (how many
+	 * frames should be acquired).
+	 */
+	SR_CONF_LIMIT_FRAMES,
+
+	/**
+	 * The device supports continuous sampling. Neither a time limit
+	 * nor a sample number limit has to be supplied, it will just acquire
+	 * samples continuously, until explicitly stopped by a certain command.
+	 */
+	SR_CONF_CONTINUOUS,
+
+	/** The device has internal storage, into which data is logged. This
+	 * starts or stops the internal logging. */
+	SR_CONF_DATALOG,
+
+	/** Device mode for multi-function devices. */
+	SR_CONF_DEVICE_MODE,
+
+	/** Self test mode. */
+	SR_CONF_TEST_MODE,
+};
+
+/** Device instance data
+ */
+struct sr_dev_inst {
+	/** Device driver. */
+	struct sr_dev_driver *driver;
+	/** Index of device in driver. */
+	int index;
+	/** Device instance status. SR_ST_NOT_FOUND, etc. */
+	int status;
+	/** Device instance type. SR_INST_USB, etc. */
+	int inst_type;
+	/** Device vendor. */
+	char *vendor;
+	/** Device model. */
+	char *model;
+	/** Device version. */
+	char *version;
+	/** List of channels. */
+	GSList *channels;
+	/** List of sr_channel_group structs */
+	GSList *channel_groups;
+	/** Device instance connection data (used?) */
+	void *conn;
+	/** Device instance private data (used?) */
+	void *priv;
+};
+
+/** Types of device instance, struct sr_dev_inst.type */
+enum sr_dev_inst_type {
+	/** Device instance type for USB devices. */
+	SR_INST_USB = 10000,
+	/** Device instance type for serial port devices. */
+	SR_INST_SERIAL,
+	/** Device instance type for SCPI devices. */
+	SR_INST_SCPI,
+};
+
+/** Device instance status, struct sr_dev_inst.status */
+enum sr_dev_inst_status {
+	/** The device instance was not found. */
+	SR_ST_NOT_FOUND = 10000,
+	/** The device instance was found, but is still booting. */
+	SR_ST_INITIALIZING,
+	/** The device instance is live, but not in use. */
+	SR_ST_INACTIVE,
+	/** The device instance is actively in use in a session. */
+	SR_ST_ACTIVE,
+	/** The device is winding down its session. */
+	SR_ST_STOPPING,
+};
+
+/** Device driver data. See also http://sigrok.org/wiki/Hardware_driver_API . */
+struct sr_dev_driver {
+	/* Driver-specific */
+	/** Driver name. Lowercase a-z, 0-9 and dashes (-) only. */
+	char *name;
+	/** Long name. Verbose driver name shown to user. */
+	char *longname;
+	/** API version (currently 1).	*/
+	int api_version;
+	/** Called when driver is loaded, e.g. program startup. */
+	int (*init) (struct sr_context *sr_ctx);
+	/** Called before driver is unloaded.
+	 *  Driver must free all resouces held by it. */
+	int (*cleanup) (void);
+	/** Scan for devices. Driver should do all initialisation required.
+	 *  Can be called several times, e.g. with different port options.
+	 *  \retval NULL Error or no devices found.
+	 *  \retval other GSList of a struct sr_dev_inst for each device.
+	 *                Must be freed by caller!
+	 */
+	GSList *(*scan) (GSList *options);
+	/** Get list of device instances the driver knows about.
+	 *  \returns NULL or GSList of a struct sr_dev_inst for each device.
+	 *           Must not be freed by caller!
+	 */
+	GSList *(*dev_list) (void);
+	/** Clear list of devices the driver knows about. */
+	int (*dev_clear) (void);
+	/** Query value of a configuration key in driver or given device instance.
+	 *  @see sr_config_get().
+	 */
+	int (*config_get) (int id, GVariant **data,
+			const struct sr_dev_inst *sdi,
+			const struct sr_channel_group *cg);
+	/** Set value of a configuration key in driver or a given device instance.
+	 *  @see sr_config_set(). */
+	int (*config_set) (int id, GVariant *data,
+			const struct sr_dev_inst *sdi,
+			const struct sr_channel_group *cg);
+	/** Channel status change.
+	 *  @see sr_dev_channel_enable(), sr_dev_trigger_set(). */
+	int (*config_channel_set) (const struct sr_dev_inst *sdi,
+			struct sr_channel *ch, unsigned int changes);
+	/** Apply configuration settings to the device hardware.
+	 *  @see sr_config_commit().*/
+	int (*config_commit) (const struct sr_dev_inst *sdi);
+	/** List all possible values for a configuration key in a device instance.
+	 *  @see sr_config_list().
+	 */
+	int (*config_list) (int info_id, GVariant **data,
+			const struct sr_dev_inst *sdi,
+			const struct sr_channel_group *cg);
+
+	/* Device-specific */
+	/** Open device */
+	int (*dev_open) (struct sr_dev_inst *sdi);
+	/** Close device */
+	int (*dev_close) (struct sr_dev_inst *sdi);
+	/** Begin data acquisition on the specified device. */
+	int (*dev_acquisition_start) (const struct sr_dev_inst *sdi,
+			void *cb_data);
+	/** End data acquisition on the specified device. */
+	int (*dev_acquisition_stop) (struct sr_dev_inst *sdi,
+			void *cb_data);
+
+	/* Dynamic */
+	/** Device driver private data. Initialized by init(). */
+	void *priv;
+};
+
+/**
+ * @struct sr_session
+ *
+ * Opaque data structure representing a libsigrok session. None of the fields
+ * of this structure are meant to be accessed directly.
+ */
+struct sr_session;
+
+#include "proto.h"
+#include "version.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libsigrok.pc.in b/libsigrok.pc.in
new file mode 100644
index 0000000..219f7c3
--- /dev/null
+++ b/libsigrok.pc.in
@@ -0,0 +1,15 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libsigrok
+Description: Backend library of the sigrok logic analyzer software
+URL: http://www.sigrok.org
+Requires: glib-2.0
+Requires.private: @SR_PKGLIBS@
+Version: @VERSION@
+Libs: -L${libdir} -lsigrok
+Libs.private: -lm
+Cflags: -I${includedir}
+
diff --git a/log.c b/log.c
new file mode 100644
index 0000000..db16c30
--- /dev/null
+++ b/log.c
@@ -0,0 +1,302 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2011-2012 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "libsigrok.h"
+/** @cond PRIVATE */
+#define NO_LOG_WRAPPERS
+/** @endcond */
+#include "libsigrok-internal.h"
+
+/**
+ * @file
+ *
+ * Controlling the libsigrok message logging functionality.
+ */
+
+/**
+ * @defgroup grp_logging Logging
+ *
+ * Controlling the libsigrok message logging functionality.
+ *
+ * @{
+ */
+
+/* Currently selected libsigrok loglevel. Default: SR_LOG_WARN. */
+static int cur_loglevel = SR_LOG_WARN; /* Show errors+warnings per default. */
+
+/* Function prototype. */
+static int sr_logv(void *cb_data, int loglevel, const char *format,
+		   va_list args);
+
+/* Pointer to the currently selected log callback. Default: sr_logv(). */
+static sr_log_callback sr_log_cb = sr_logv;
+
+/*
+ * Pointer to private data that can be passed to the log callback.
+ * This can be used (for example) by C++ GUIs to pass a "this" pointer.
+ */
+static void *sr_log_cb_data = NULL;
+
+/* Log domain (a short string that is used as prefix for all messages). */
+/** @cond PRIVATE */
+#define LOGDOMAIN_MAXLEN 30
+#define LOGDOMAIN_DEFAULT "sr: "
+/** @endcond */
+static char sr_log_domain[LOGDOMAIN_MAXLEN + 1] = LOGDOMAIN_DEFAULT;
+
+/**
+ * Set the libsigrok loglevel.
+ *
+ * This influences the amount of log messages (debug messages, error messages,
+ * and so on) libsigrok will output. Using SR_LOG_NONE disables all messages.
+ *
+ * Note that this function itself will also output log messages. After the
+ * loglevel has changed, it will output a debug message with SR_LOG_DBG for
+ * example. Whether this message is shown depends on the (new) loglevel.
+ *
+ * @param loglevel The loglevel to set (SR_LOG_NONE, SR_LOG_ERR, SR_LOG_WARN,
+ *                 SR_LOG_INFO, SR_LOG_DBG, or SR_LOG_SPEW).
+ *
+ * @return SR_OK upon success, SR_ERR_ARG upon invalid loglevel.
+ *
+ * @since 0.1.0
+ */
+SR_API int sr_log_loglevel_set(int loglevel)
+{
+	if (loglevel < SR_LOG_NONE || loglevel > SR_LOG_SPEW) {
+		sr_err("Invalid loglevel %d.", loglevel);
+		return SR_ERR_ARG;
+	}
+
+	cur_loglevel = loglevel;
+
+	sr_dbg("libsigrok loglevel set to %d.", loglevel);
+
+	return SR_OK;
+}
+
+/**
+ * Get the libsigrok loglevel.
+ *
+ * @return The currently configured libsigrok loglevel.
+ *
+ * @since 0.1.0
+ */
+SR_API int sr_log_loglevel_get(void)
+{
+	return cur_loglevel;
+}
+
+/**
+ * Set the libsigrok logdomain string.
+ *
+ * @param logdomain The string to use as logdomain for libsigrok log
+ *                  messages from now on. Must not be NULL. The maximum
+ *                  length of the string is 30 characters (this does not
+ *                  include the trailing NUL-byte). Longer strings are
+ *                  silently truncated.
+ *                  In order to not use a logdomain, pass an empty string.
+ *                  The function makes its own copy of the input string, i.e.
+ *                  the caller does not need to keep it around.
+ *
+ * @return SR_OK upon success, SR_ERR_ARG upon invalid logdomain.
+ *
+ * @since 0.1.0
+ */
+SR_API int sr_log_logdomain_set(const char *logdomain)
+{
+	if (!logdomain) {
+		sr_err("log: %s: logdomain was NULL", __func__);
+		return SR_ERR_ARG;
+	}
+
+	/* TODO: Error handling. */
+	snprintf((char *)&sr_log_domain, LOGDOMAIN_MAXLEN, "%s", logdomain);
+
+	sr_dbg("Log domain set to '%s'.", (const char *)&sr_log_domain);
+
+	return SR_OK;
+}
+
+/**
+ * Get the currently configured libsigrok logdomain.
+ *
+ * @return A copy of the currently configured libsigrok logdomain
+ *         string. The caller is responsible for g_free()ing the string when
+ *         it is no longer needed.
+ *
+ * @since 0.1.0
+ */
+SR_API char *sr_log_logdomain_get(void)
+{
+	return g_strdup((const char *)&sr_log_domain);
+}
+
+/**
+ * Set the libsigrok log callback to the specified function.
+ *
+ * @param cb Function pointer to the log callback function to use.
+ *           Must not be NULL.
+ * @param cb_data Pointer to private data to be passed on. This can be used by
+ *                the caller to pass arbitrary data to the log functions. This
+ *                pointer is only stored or passed on by libsigrok, and is
+ *                never used or interpreted in any way. The pointer is allowed
+ *                to be NULL if the caller doesn't need/want to pass any data.
+ *
+ * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments.
+ *
+ * @since 0.3.0
+ */
+SR_API int sr_log_callback_set(sr_log_callback cb, void *cb_data)
+{
+	if (!cb) {
+		sr_err("log: %s: cb was NULL", __func__);
+		return SR_ERR_ARG;
+	}
+
+	/* Note: 'cb_data' is allowed to be NULL. */
+
+	sr_log_cb = cb;
+	sr_log_cb_data = cb_data;
+
+	return SR_OK;
+}
+
+/**
+ * Set the libsigrok log callback to the default built-in one.
+ *
+ * Additionally, the internal 'sr_log_cb_data' pointer is set to NULL.
+ *
+ * @return SR_OK upon success, a negative error code otherwise.
+ *
+ * @since 0.1.0
+ */
+SR_API int sr_log_callback_set_default(void)
+{
+	/*
+	 * Note: No log output in this function, as it should safely work
+	 * even if the currently set log callback is buggy/broken.
+	 */
+	sr_log_cb = sr_logv;
+	sr_log_cb_data = NULL;
+
+	return SR_OK;
+}
+
+static int sr_logv(void *cb_data, int loglevel, const char *format, va_list args)
+{
+	int ret;
+
+	/* This specific log callback doesn't need the void pointer data. */
+	(void)cb_data;
+
+	/* Only output messages of at least the selected loglevel(s). */
+	if (loglevel > cur_loglevel)
+		return SR_OK; /* TODO? */
+
+	if (sr_log_domain[0] != '\0')
+		fprintf(stderr, "%s", sr_log_domain);
+	ret = vfprintf(stderr, format, args);
+	fprintf(stderr, "\n");
+
+	return ret;
+}
+
+/** @private */
+SR_PRIV int sr_log(int loglevel, const char *format, ...)
+{
+	int ret;
+	va_list args;
+
+	va_start(args, format);
+	ret = sr_log_cb(sr_log_cb_data, loglevel, format, args);
+	va_end(args);
+
+	return ret;
+}
+
+/** @private */
+SR_PRIV int sr_spew(const char *format, ...)
+{
+	int ret;
+	va_list args;
+
+	va_start(args, format);
+	ret = sr_log_cb(sr_log_cb_data, SR_LOG_SPEW, format, args);
+	va_end(args);
+
+	return ret;
+}
+
+/** @private */
+SR_PRIV int sr_dbg(const char *format, ...)
+{
+	int ret;
+	va_list args;
+
+	va_start(args, format);
+	ret = sr_log_cb(sr_log_cb_data, SR_LOG_DBG, format, args);
+	va_end(args);
+
+	return ret;
+}
+
+/** @private */
+SR_PRIV int sr_info(const char *format, ...)
+{
+	int ret;
+	va_list args;
+
+	va_start(args, format);
+	ret = sr_log_cb(sr_log_cb_data, SR_LOG_INFO, format, args);
+	va_end(args);
+
+	return ret;
+}
+
+/** @private */
+SR_PRIV int sr_warn(const char *format, ...)
+{
+	int ret;
+	va_list args;
+
+	va_start(args, format);
+	ret = sr_log_cb(sr_log_cb_data, SR_LOG_WARN, format, args);
+	va_end(args);
+
+	return ret;
+}
+
+/** @private */
+SR_PRIV int sr_err(const char *format, ...)
+{
+	int ret;
+	va_list args;
+
+	va_start(args, format);
+	ret = sr_log_cb(sr_log_cb_data, SR_LOG_ERR, format, args);
+	va_end(args);
+
+	return ret;
+}
+
+/** @} */
diff --git a/output/analog.c b/output/analog.c
new file mode 100644
index 0000000..bdb5573
--- /dev/null
+++ b/output/analog.c
@@ -0,0 +1,268 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "output/analog"
+
+struct context {
+	int num_enabled_channels;
+	GPtrArray *channellist;
+};
+
+static int init(struct sr_output *o)
+{
+	struct context *ctx;
+	struct sr_channel *ch;
+	GSList *l;
+
+	sr_spew("Initializing output module.");
+
+	if (!o || !o->sdi)
+		return SR_ERR_ARG;
+
+	if (!(ctx = g_try_malloc0(sizeof(struct context)))) {
+		sr_err("Output module context malloc failed.");
+		return SR_ERR_MALLOC;
+	}
+	o->internal = ctx;
+
+	/* Get the number of channels and their names. */
+	ctx->channellist = g_ptr_array_new();
+	for (l = o->sdi->channels; l; l = l->next) {
+		ch = l->data;
+		if (!ch || !ch->enabled)
+			continue;
+		g_ptr_array_add(ctx->channellist, ch->name);
+		ctx->num_enabled_channels++;
+	}
+
+	return SR_OK;
+}
+
+static void si_printf(float value, GString *out, char *unitstr)
+{
+	float v;
+
+	if (signbit(value))
+		v = -(value);
+	else
+		v = value;
+
+	if (v < 1e-12 || v > 1e+12)
+		g_string_append_printf(out, "%f %s", value, unitstr);
+	else if (v > 1e+9)
+		g_string_append_printf(out, "%f G%s", value / 1e+9, unitstr);
+	else if (v > 1e+6)
+		g_string_append_printf(out, "%f M%s", value / 1e+6, unitstr);
+	else if (v > 1e+3)
+		g_string_append_printf(out, "%f k%s", value / 1e+3, unitstr);
+	else if (v < 1e-9)
+		g_string_append_printf(out, "%f n%s", value * 1e+9, unitstr);
+	else if (v < 1e-6)
+		g_string_append_printf(out, "%f u%s", value * 1e+6, unitstr);
+	else if (v < 1e-3)
+		g_string_append_printf(out, "%f m%s", value * 1e+3, unitstr);
+	else
+		g_string_append_printf(out, "%f %s", value, unitstr);
+
+}
+
+static void fancyprint(int unit, int mqflags, float value, GString *out)
+{
+	switch (unit) {
+	case SR_UNIT_VOLT:
+		si_printf(value, out, "V");
+		break;
+	case SR_UNIT_AMPERE:
+		si_printf(value, out, "A");
+		break;
+	case SR_UNIT_OHM:
+		si_printf(value, out, "");
+		g_string_append_unichar(out, 0x2126);
+		break;
+	case SR_UNIT_FARAD:
+		si_printf(value, out, "F");
+		break;
+	case SR_UNIT_KELVIN:
+		si_printf(value, out, "K");
+		break;
+	case SR_UNIT_CELSIUS:
+		si_printf(value, out, "");
+		g_string_append_unichar(out, 0x00b0);
+		g_string_append_c(out, 'C');
+		break;
+	case SR_UNIT_FAHRENHEIT:
+		si_printf(value, out, "");
+		g_string_append_unichar(out, 0x00b0);
+		g_string_append_c(out, 'F');
+		break;
+	case SR_UNIT_HERTZ:
+		si_printf(value, out, "Hz");
+		break;
+	case SR_UNIT_PERCENTAGE:
+		g_string_append_printf(out, "%f %%", value);
+		break;
+	case SR_UNIT_BOOLEAN:
+		if (value > 0)
+			g_string_append_printf(out, "TRUE");
+		else
+			g_string_append_printf(out, "FALSE");
+		break;
+	case SR_UNIT_SECOND:
+		si_printf(value, out, "s");
+		break;
+	case SR_UNIT_SIEMENS:
+		si_printf(value, out, "S");
+		break;
+	case SR_UNIT_DECIBEL_MW:
+		si_printf(value, out, "dBu");
+		break;
+	case SR_UNIT_DECIBEL_VOLT:
+		si_printf(value, out, "dBV");
+		break;
+	case SR_UNIT_DECIBEL_SPL:
+		if (mqflags & SR_MQFLAG_SPL_FREQ_WEIGHT_A)
+			si_printf(value, out, "dB(A)");
+		else if (mqflags & SR_MQFLAG_SPL_FREQ_WEIGHT_C)
+			si_printf(value, out, "dB(C)");
+		else if (mqflags & SR_MQFLAG_SPL_FREQ_WEIGHT_Z)
+			si_printf(value, out, "dB(Z)");
+		else
+			/* No frequency weighting, or non-standard "flat" */
+			si_printf(value, out, "dB(SPL)");
+		if (mqflags & SR_MQFLAG_SPL_TIME_WEIGHT_S)
+			g_string_append(out, " S");
+		else if (mqflags & SR_MQFLAG_SPL_TIME_WEIGHT_F)
+			g_string_append(out, " F");
+		if (mqflags & SR_MQFLAG_SPL_LAT)
+			g_string_append(out, " LAT");
+		else if (mqflags & SR_MQFLAG_SPL_PCT_OVER_ALARM)
+			/* Not a standard function for SLMs, so this is
+			 * a made-up notation. */
+			g_string_append(out, " %oA");
+		break;
+	case SR_UNIT_CONCENTRATION:
+		g_string_append_printf(out, "%f ppm", value * 1000000);
+		break;
+	case SR_UNIT_REVOLUTIONS_PER_MINUTE:
+		si_printf(value, out, "RPM");
+		break;
+	case SR_UNIT_VOLT_AMPERE:
+		si_printf(value, out, "VA");
+		break;
+	case SR_UNIT_WATT:
+		si_printf(value, out, "W");
+		break;
+	case SR_UNIT_WATT_HOUR:
+		si_printf(value, out, "Wh");
+		break;
+	default:
+		si_printf(value, out, "");
+		break;
+	}
+
+	if (mqflags & SR_MQFLAG_AC)
+		g_string_append_printf(out, " AC");
+	if (mqflags & SR_MQFLAG_DC)
+		g_string_append_printf(out, " DC");
+	if (mqflags & SR_MQFLAG_RMS)
+		g_string_append_printf(out, " RMS");
+	if (mqflags & SR_MQFLAG_DIODE)
+		g_string_append_printf(out, " DIODE");
+	if (mqflags & SR_MQFLAG_HOLD)
+		g_string_append_printf(out, " HOLD");
+	if (mqflags & SR_MQFLAG_MAX)
+		g_string_append_printf(out, " MAX");
+	if (mqflags & SR_MQFLAG_MIN)
+		g_string_append_printf(out, " MIN");
+	if (mqflags & SR_MQFLAG_AUTORANGE)
+		g_string_append_printf(out, " AUTO");
+	if (mqflags & SR_MQFLAG_RELATIVE)
+		g_string_append_printf(out, " REL");
+	if (mqflags & SR_MQFLAG_AVG)
+		g_string_append_printf(out, " AVG");
+	g_string_append_c(out, '\n');
+}
+
+static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+		GString **out)
+{
+	const struct sr_datafeed_analog *analog;
+	struct sr_channel *ch;
+	GSList *l;
+	const float *fdata;
+	int i, p;
+
+	*out = NULL;
+	if (!o || !o->sdi)
+		return SR_ERR_ARG;
+
+	switch (packet->type) {
+	case SR_DF_FRAME_BEGIN:
+		*out = g_string_new("FRAME-BEGIN\n");
+		break;
+	case SR_DF_FRAME_END:
+		*out = g_string_new("FRAME-END\n");
+		break;
+	case SR_DF_ANALOG:
+		analog = packet->payload;
+		fdata = (const float *)analog->data;
+		*out = g_string_sized_new(512);
+		for (i = 0; i < analog->num_samples; i++) {
+			for (l = analog->channels, p = 0; l; l = l->next, p++) {
+				ch = l->data;
+				g_string_append_printf(*out, "%s: ", ch->name);
+				fancyprint(analog->unit, analog->mqflags,
+						fdata[i + p], *out);
+			}
+		}
+		break;
+	}
+
+	return SR_OK;
+}
+
+static int cleanup(struct sr_output *o)
+{
+	struct context *ctx;
+
+	if (!o || !o->sdi)
+		return SR_ERR_ARG;
+	ctx = o->internal;
+
+	g_ptr_array_free(ctx->channellist, 1);
+	g_free(ctx);
+	o->internal = NULL;
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_output_format output_analog = {
+	.id = "analog",
+	.description = "Analog data",
+	.init = init,
+	.receive = receive,
+	.cleanup = cleanup
+};
diff --git a/output/ascii.c b/output/ascii.c
new file mode 100644
index 0000000..d068942
--- /dev/null
+++ b/output/ascii.c
@@ -0,0 +1,261 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2011 Håvard Espeland <gus at ping.uio.no>
+ * Copyright (C) 2014 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "output/hex"
+
+#define DEFAULT_SAMPLES_PER_LINE 74
+
+struct context {
+	unsigned int num_enabled_channels;
+	int samples_per_line;
+	int bit_cnt;
+	int spl_cnt;
+	int trigger;
+	uint64_t samplerate;
+	int *channel_index;
+	char **channel_names;
+	char **line_values;
+	uint8_t *prev_sample;
+	gboolean header_done;
+	GString **lines;
+	GString *header;
+};
+
+static int init(struct sr_output *o)
+{
+	struct context *ctx;
+	struct sr_channel *ch;
+	GSList *l;
+	GHashTableIter iter;
+	gpointer key, value;
+	unsigned int i, j;
+	int spl;
+
+	if (!o || !o->sdi)
+		return SR_ERR_ARG;
+
+	spl = DEFAULT_SAMPLES_PER_LINE;
+	g_hash_table_iter_init(&iter, o->params);
+	while (g_hash_table_iter_next(&iter, &key, &value)) {
+		if (!strcmp(key, "width")) {
+			if ((spl = strtoul(value, NULL, 10)) < 1) {
+				sr_err("Invalid width.");
+				return SR_ERR_ARG;
+			}
+		} else {
+			sr_err("Unknown parameter '%s'.", key);
+			return SR_ERR_ARG;
+		}
+	}
+
+	ctx = g_malloc0(sizeof(struct context));
+	o->internal = ctx;
+	ctx->trigger = -1;
+	ctx->samples_per_line = spl;
+
+	for (l = o->sdi->channels; l; l = l->next) {
+		ch = l->data;
+		if (ch->type != SR_CHANNEL_LOGIC)
+			continue;
+		if (!ch->enabled)
+			continue;
+		ctx->num_enabled_channels++;
+	}
+	ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
+	ctx->channel_names = g_malloc(sizeof(char *) * ctx->num_enabled_channels);
+	ctx->lines = g_malloc(sizeof(GString *) * ctx->num_enabled_channels);
+	ctx->prev_sample = g_malloc(g_slist_length(o->sdi->channels));
+
+	j = 0;
+	for (i = 0, l = o->sdi->channels; l; l = l->next, i++) {
+		ch = l->data;
+		if (ch->type != SR_CHANNEL_LOGIC)
+			continue;
+		if (!ch->enabled)
+			continue;
+		ctx->channel_index[j] = ch->index;
+		ctx->channel_names[j] = ch->name;
+		ctx->lines[j] = g_string_sized_new(80);
+		g_string_printf(ctx->lines[j], "%s:", ch->name);
+		j++;
+	}
+
+	return SR_OK;
+}
+
+static GString *gen_header(struct sr_output *o)
+{
+	struct context *ctx;
+	GVariant *gvar;
+	GString *header;
+	int num_channels;
+	char *samplerate_s;
+
+	ctx = o->internal;
+	if (ctx->samplerate == 0) {
+		if (sr_config_get(o->sdi->driver, o->sdi, NULL, SR_CONF_SAMPLERATE,
+				&gvar) == SR_OK) {
+			ctx->samplerate = g_variant_get_uint64(gvar);
+			g_variant_unref(gvar);
+		}
+	}
+
+	header = g_string_sized_new(512);
+	g_string_printf(header, "%s\n", PACKAGE_STRING);
+	num_channels = g_slist_length(o->sdi->channels);
+	g_string_append_printf(header, "Acquisition with %d/%d channels",
+			ctx->num_enabled_channels, num_channels);
+	if (ctx->samplerate != 0) {
+		samplerate_s = sr_samplerate_string(ctx->samplerate);
+		g_string_append_printf(header, " at %s", samplerate_s);
+		g_free(samplerate_s);
+	}
+	g_string_append_printf(header, "\n");
+
+	return header;
+}
+
+static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+		GString **out)
+{
+	const struct sr_datafeed_meta *meta;
+	const struct sr_datafeed_logic *logic;
+	const struct sr_config *src;
+	GSList *l;
+	struct context *ctx;
+	int idx, offset, curbit, prevbit;
+	uint64_t i, j;
+	gchar *p, c;
+
+	*out = NULL;
+	if (!o || !o->sdi)
+		return SR_ERR_ARG;
+	if (!(ctx = o->internal))
+		return SR_ERR_ARG;
+
+	switch (packet->type) {
+	case SR_DF_META:
+		meta = packet->payload;
+		for (l = meta->config; l; l = l->next) {
+			src = l->data;
+			if (src->key != SR_CONF_SAMPLERATE)
+				continue;
+			ctx->samplerate = g_variant_get_uint64(src->data);
+		}
+		break;
+	case SR_DF_TRIGGER:
+		ctx->trigger = ctx->spl_cnt;
+		break;
+	case SR_DF_LOGIC:
+		if (!ctx->header_done) {
+			*out = gen_header(o);
+			ctx->header_done = TRUE;
+		} else
+			*out = g_string_sized_new(512);
+
+		logic = packet->payload;
+		for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
+			ctx->spl_cnt++;
+			for (j = 0; j < ctx->num_enabled_channels; j++) {
+				idx = ctx->channel_index[j];
+				p = logic->data + i + idx / 8;
+				curbit = *p & (1 << (idx % 8));
+				prevbit = (ctx->prev_sample[idx / 8] & ((uint8_t) 1 << (idx % 8)));
+
+				c = curbit ? '"' : '.';
+				if (ctx->spl_cnt > 1) {
+					if (curbit < prevbit)
+						c = '\\';
+					else if (curbit > prevbit)
+						c = '/';
+				}
+				g_string_append_c(ctx->lines[j], c);
+
+				if (ctx->spl_cnt == ctx->samples_per_line) {
+					/* Flush line buffers. */
+					g_string_append_len(*out, ctx->lines[j]->str, ctx->lines[j]->len);
+					g_string_append_c(*out, '\n');
+					if (j == ctx->num_enabled_channels  - 1 && ctx->trigger > -1) {
+						offset = ctx->trigger + ctx->trigger / 8;
+						g_string_append_printf(*out, "T:%*s^ %d\n", offset, "", ctx->trigger);
+						ctx->trigger = -1;
+					}
+					g_string_printf(ctx->lines[j], "%s:", ctx->channel_names[j]);
+				}
+			}
+			if (ctx->spl_cnt == ctx->samples_per_line)
+				/* Line buffers were already flushed. */
+				ctx->spl_cnt = 0;
+			memcpy(ctx->prev_sample, logic->data + i, logic->unitsize);
+		}
+		break;
+	case SR_DF_END:
+		if (ctx->spl_cnt) {
+			/* Line buffers need flushing. */
+			*out = g_string_sized_new(512);
+			for (i = 0; i < ctx->num_enabled_channels; i++) {
+				g_string_append_len(*out, ctx->lines[i]->str, ctx->lines[i]->len);
+				g_string_append_c(*out, '\n');
+			}
+		}
+		break;
+	}
+
+	return SR_OK;
+}
+
+static int cleanup(struct sr_output *o)
+{
+	struct context *ctx;
+	unsigned int i;
+
+	if (!o)
+		return SR_ERR_ARG;
+
+	if (!(ctx = o->internal))
+		return SR_OK;
+
+	g_free(ctx->channel_index);
+	g_free(ctx->prev_sample);
+	g_free(ctx->channel_names);
+	for (i = 0; i < ctx->num_enabled_channels; i++)
+		g_string_free(ctx->lines[i], TRUE);
+	g_free(ctx->lines);
+	g_free(ctx);
+	o->internal = NULL;
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_output_format output_ascii = {
+	.id = "ascii",
+	.description = "ASCII",
+	.init = init,
+	.receive = receive,
+	.cleanup = cleanup,
+};
+
+
diff --git a/output/binary.c b/output/binary.c
new file mode 100644
index 0000000..6e2531d
--- /dev/null
+++ b/output/binary.c
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "output/binary"
+
+static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+		GString **out)
+{
+	const struct sr_datafeed_logic *logic;
+
+	(void)o;
+
+	*out = NULL;
+	if (packet->type != SR_DF_LOGIC)
+		return SR_OK;
+	logic = packet->payload;
+	*out = g_string_new_len(logic->data, logic->length);
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_output_format output_binary = {
+	.id = "binary",
+	.description = "Raw binary",
+	.receive = receive,
+};
diff --git a/output/bits.c b/output/bits.c
new file mode 100644
index 0000000..b44f105
--- /dev/null
+++ b/output/bits.c
@@ -0,0 +1,245 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "output/bits"
+
+#define DEFAULT_SAMPLES_PER_LINE 64
+
+struct context {
+	unsigned int num_enabled_channels;
+	int samples_per_line;
+	int spl_cnt;
+	int trigger;
+	uint64_t samplerate;
+	int *channel_index;
+	char **channel_names;
+	gboolean header_done;
+	GString **lines;
+};
+
+static int init(struct sr_output *o)
+{
+	struct context *ctx;
+	struct sr_channel *ch;
+	GSList *l;
+	GHashTableIter iter;
+	gpointer key, value;
+	unsigned int i, j;
+	int spl;
+
+	if (!o || !o->sdi)
+		return SR_ERR_ARG;
+
+	spl = DEFAULT_SAMPLES_PER_LINE;
+	g_hash_table_iter_init(&iter, o->params);
+	while (g_hash_table_iter_next(&iter, &key, &value)) {
+		if (!strcmp(key, "width")) {
+			if ((spl = strtoul(value, NULL, 10)) < 1) {
+				sr_err("Invalid width.");
+				return SR_ERR_ARG;
+			}
+		} else {
+			sr_err("Unknown parameter '%s'.", key);
+			return SR_ERR_ARG;
+		}
+	}
+
+	ctx = g_malloc0(sizeof(struct context));
+	o->internal = ctx;
+	ctx->trigger = -1;
+	ctx->samples_per_line = spl;
+
+	for (l = o->sdi->channels; l; l = l->next) {
+		ch = l->data;
+		if (ch->type != SR_CHANNEL_LOGIC)
+			continue;
+		if (!ch->enabled)
+			continue;
+		ctx->num_enabled_channels++;
+	}
+	ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
+	ctx->channel_names = g_malloc(sizeof(char *) * ctx->num_enabled_channels);
+	ctx->lines = g_malloc(sizeof(GString *) * ctx->num_enabled_channels);
+
+	j = 0;
+	for (i = 0, l = o->sdi->channels; l; l = l->next, i++) {
+		ch = l->data;
+		if (ch->type != SR_CHANNEL_LOGIC)
+			continue;
+		if (!ch->enabled)
+			continue;
+		ctx->channel_index[j] = ch->index;
+		ctx->channel_names[j] = ch->name;
+		ctx->lines[j] = g_string_sized_new(80);
+		g_string_printf(ctx->lines[j], "%s:", ch->name);
+		j++;
+	}
+
+	return SR_OK;
+}
+
+static GString *gen_header(struct sr_output *o)
+{
+	struct context *ctx;
+	GVariant *gvar;
+	GString *header;
+	int num_channels;
+	char *samplerate_s;
+
+	ctx = o->internal;
+	if (ctx->samplerate == 0) {
+		if (sr_config_get(o->sdi->driver, o->sdi, NULL, SR_CONF_SAMPLERATE,
+				&gvar) == SR_OK) {
+			ctx->samplerate = g_variant_get_uint64(gvar);
+			g_variant_unref(gvar);
+		}
+	}
+
+	header = g_string_sized_new(512);
+	g_string_printf(header, "%s\n", PACKAGE_STRING);
+	num_channels = g_slist_length(o->sdi->channels);
+	g_string_append_printf(header, "Acquisition with %d/%d channels",
+			ctx->num_enabled_channels, num_channels);
+	if (ctx->samplerate != 0) {
+		samplerate_s = sr_samplerate_string(ctx->samplerate);
+		g_string_append_printf(header, " at %s", samplerate_s);
+		g_free(samplerate_s);
+	}
+	g_string_append_printf(header, "\n");
+
+	return header;
+}
+
+static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+		GString **out)
+{
+	const struct sr_datafeed_meta *meta;
+	const struct sr_datafeed_logic *logic;
+	const struct sr_config *src;
+	struct context *ctx;
+	GSList *l;
+	int idx, offset;
+	uint64_t i, j;
+	gchar *p, c;
+
+	*out = NULL;
+	if (!o || !o->sdi)
+		return SR_ERR_ARG;
+	if (!(ctx = o->internal))
+		return SR_ERR_ARG;
+
+	switch (packet->type) {
+	case SR_DF_META:
+		meta = packet->payload;
+		for (l = meta->config; l; l = l->next) {
+			src = l->data;
+			if (src->key != SR_CONF_SAMPLERATE)
+				continue;
+			ctx->samplerate = g_variant_get_uint64(src->data);
+		}
+		break;
+	case SR_DF_TRIGGER:
+		ctx->trigger = ctx->spl_cnt;
+		break;
+	case SR_DF_LOGIC:
+		if (!ctx->header_done) {
+			*out = gen_header(o);
+			ctx->header_done = TRUE;
+		} else
+			*out = g_string_sized_new(512);
+
+		logic = packet->payload;
+		for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
+			ctx->spl_cnt++;
+			for (j = 0; j < ctx->num_enabled_channels; j++) {
+				idx = ctx->channel_index[j];
+				p = logic->data + i + idx / 8;
+				c = (*p & (1 << (idx % 8))) ? '1' : '0';
+				g_string_append_c(ctx->lines[j], c);
+
+				if (ctx->spl_cnt == ctx->samples_per_line) {
+					/* Flush line buffers. */
+					g_string_append_len(*out, ctx->lines[j]->str, ctx->lines[j]->len);
+					g_string_append_c(*out, '\n');
+					if (j == ctx->num_enabled_channels  - 1 && ctx->trigger > -1) {
+						offset = ctx->trigger + ctx->trigger / 8;
+						g_string_append_printf(*out, "T:%*s^ %d\n", offset, "", ctx->trigger);
+						ctx->trigger = -1;
+					}
+					g_string_printf(ctx->lines[j], "%s:", ctx->channel_names[j]);
+				} else if ((ctx->spl_cnt & 7) == 0) {
+					/* Add a space every 8th bit. */
+					g_string_append_c(ctx->lines[j], ' ');
+				}
+			}
+			if (ctx->spl_cnt == ctx->samples_per_line)
+				/* Line buffers were already flushed. */
+				ctx->spl_cnt = 0;
+		}
+		break;
+	case SR_DF_END:
+		if (ctx->spl_cnt) {
+			/* Line buffers need flushing. */
+			*out = g_string_sized_new(512);
+			for (i = 0; i < ctx->num_enabled_channels; i++) {
+				g_string_append_len(*out, ctx->lines[i]->str, ctx->lines[i]->len);
+				g_string_append_c(*out, '\n');
+			}
+		}
+		break;
+	}
+
+	return SR_OK;
+}
+
+static int cleanup(struct sr_output *o)
+{
+	struct context *ctx;
+	unsigned int i;
+
+	if (!o)
+		return SR_ERR_ARG;
+
+	if (!(ctx = o->internal))
+		return SR_OK;
+
+	g_free(ctx->channel_index);
+	g_free(ctx->channel_names);
+	for (i = 0; i < ctx->num_enabled_channels; i++)
+		g_string_free(ctx->lines[i], TRUE);
+	g_free(ctx->lines);
+	g_free(ctx);
+	o->internal = NULL;
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_output_format output_bits = {
+	.id = "bits",
+	.description = "Bits",
+	.init = init,
+	.receive = receive,
+	.cleanup = cleanup,
+};
diff --git a/output/chronovu_la8.c b/output/chronovu_la8.c
new file mode 100644
index 0000000..ad0b5d3
--- /dev/null
+++ b/output/chronovu_la8.c
@@ -0,0 +1,190 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2011 Uwe Hermann <uwe at hermann-uwe.de>
+ * Copyright (C) 2014 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "output/chronovu-la8"
+
+struct context {
+	unsigned int num_enabled_channels;
+	gboolean triggered;
+	uint64_t samplerate;
+	uint64_t samplecount;
+	int *channel_index;
+	GString *pretrig_buf;
+};
+
+/**
+ * Check if the given samplerate is supported by the LA8 hardware.
+ *
+ * @param samplerate The samplerate (in Hz) to check.
+ *
+ * @return 1 if the samplerate is supported/valid, 0 otherwise.
+ */
+static gboolean is_valid_samplerate(uint64_t samplerate)
+{
+	unsigned int i;
+
+	for (i = 0; i < 255; i++) {
+		if (samplerate == (SR_MHZ(100) / (i + 1)))
+			return TRUE;
+	}
+
+	return FALSE;
+}
+
+/**
+ * Convert a samplerate (in Hz) to the 'divcount' value the LA8 wants.
+ *
+ * LA8 hardware: sample period = (divcount + 1) * 10ns.
+ * Min. value for divcount: 0x00 (10ns sample period, 100MHz samplerate).
+ * Max. value for divcount: 0xfe (2550ns sample period, 392.15kHz samplerate).
+ *
+ * @param samplerate The samplerate in Hz.
+ *
+ * @return The divcount value as needed by the hardware, or 0xff upon errors.
+ */
+static uint8_t samplerate_to_divcount(uint64_t samplerate)
+{
+	if (samplerate == 0 || !is_valid_samplerate(samplerate)) {
+		sr_warn("Invalid samplerate (%" PRIu64 "Hz)", samplerate);
+		return 0xff;
+	}
+
+	return (SR_MHZ(100) / samplerate) - 1;
+}
+
+static int init(struct sr_output *o)
+{
+	struct context *ctx;
+	struct sr_channel *ch;
+	GSList *l;
+
+	if (!o || !o->sdi)
+		return SR_ERR_ARG;
+
+	ctx = g_malloc0(sizeof(struct context));
+	o->internal = ctx;
+
+	for (l = o->sdi->channels; l; l = l->next) {
+		ch = l->data;
+		if (ch->type != SR_CHANNEL_LOGIC)
+			continue;
+		if (!ch->enabled)
+			continue;
+		ctx->num_enabled_channels++;
+	}
+	ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
+	ctx->pretrig_buf = g_string_sized_new(1024);
+
+	return SR_OK;
+}
+
+static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+		GString **out)
+{
+	const struct sr_datafeed_logic *logic;
+	struct context *ctx;
+	GVariant *gvar;
+	uint64_t samplerate;
+	gchar c[4];
+
+	*out = NULL;
+	if (!o || !o->sdi)
+		return SR_ERR_ARG;
+	if (!(ctx = o->internal))
+		return SR_ERR_ARG;
+
+	switch (packet->type) {
+	case SR_DF_HEADER:
+		/* One byte for the 'divcount' value. */
+		if (sr_config_get(o->sdi->driver, o->sdi, NULL, SR_CONF_SAMPLERATE,
+				&gvar) == SR_OK) {
+			samplerate = g_variant_get_uint64(gvar);
+			g_variant_unref(gvar);
+		} else
+			samplerate = 0;
+		c[0] = samplerate_to_divcount(samplerate);
+		*out = g_string_new_len(c, 1);
+		ctx->triggered = FALSE;
+		break;
+	case SR_DF_TRIGGER:
+		/* Four bytes (little endian) for the trigger point. */
+		c[0] = ctx->samplecount & 0xff;
+		c[1] = (ctx->samplecount >> 8) & 0xff;
+		c[2] = (ctx->samplecount >> 16) & 0xff;
+		c[3] = (ctx->samplecount >> 24) & 0xff;
+		*out = g_string_new_len(c, 4);
+		/* Flush the pre-trigger buffer. */
+		if (ctx->pretrig_buf->len)
+			g_string_append_len(*out, ctx->pretrig_buf->str,
+					ctx->pretrig_buf->len);
+		ctx->triggered = TRUE;
+		break;
+	case SR_DF_LOGIC:
+		logic = packet->payload;
+		if (!ctx->triggered)
+			g_string_append_len(ctx->pretrig_buf, logic->data, logic->length);
+		else
+			*out = g_string_new_len(logic->data, logic->length);
+		ctx->samplecount += logic->length / logic->unitsize;
+		break;
+	case SR_DF_END:
+		if (!ctx->triggered && ctx->pretrig_buf->len) {
+			/* We never got a trigger, submit an empty one. */
+			*out = g_string_sized_new(ctx->pretrig_buf->len + 4);
+			g_string_append_len(*out, "\x00\x00\x00\x00", 4);
+			g_string_append_len(*out, ctx->pretrig_buf->str, ctx->pretrig_buf->len);
+		}
+		break;
+	}
+
+	return SR_OK;
+}
+
+static int cleanup(struct sr_output *o)
+{
+	struct context *ctx;
+
+	if (!o || !o->sdi)
+		return SR_ERR_ARG;
+
+	if (o->internal) {
+		ctx = o->internal;
+		g_string_free(ctx->pretrig_buf, TRUE);
+		g_free(ctx->channel_index);
+		g_free(o->internal);
+		o->internal = NULL;
+	}
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_output_format output_chronovu_la8 = {
+	.id = "chronovu-la8",
+	.description = "ChronoVu LA8",
+	.init = init,
+	.receive = receive,
+	.cleanup = cleanup,
+};
diff --git a/output/csv.c b/output/csv.c
new file mode 100644
index 0000000..d17969e
--- /dev/null
+++ b/output/csv.c
@@ -0,0 +1,220 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2011 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include "config.h" /* Needed for PACKAGE_STRING and others. */
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "output/csv"
+
+struct context {
+	unsigned int num_enabled_channels;
+	uint64_t samplerate;
+	char separator;
+	gboolean header_done;
+	int *channel_index;
+};
+
+/*
+ * TODO:
+ *  - Option to specify delimiter character and/or string.
+ *  - Option to (not) print metadata as comments.
+ *  - Option to specify the comment character(s), e.g. # or ; or C/C++-style.
+ *  - Option to (not) print samplenumber / time as extra column.
+ *  - Option to "compress" output (only print changed samples, VCD-like).
+ *  - Option to print comma-separated bits, or whole bytes/words (for 8/16
+ *    channel LAs) as ASCII/hex etc. etc.
+ *  - Trigger support.
+ */
+
+static int init(struct sr_output *o)
+{
+	struct context *ctx;
+	struct sr_channel *ch;
+	GSList *l;
+	int i;
+
+	if (!o || !o->sdi)
+		return SR_ERR_ARG;
+
+	ctx = g_malloc0(sizeof(struct context));
+	o->internal = ctx;
+	ctx->separator = ',';
+
+	/* Get the number of channels, and the unitsize. */
+	for (l = o->sdi->channels; l; l = l->next) {
+		ch = l->data;
+		if (ch->type != SR_CHANNEL_LOGIC)
+			continue;
+		if (!ch->enabled)
+			continue;
+		ctx->num_enabled_channels++;
+	}
+	ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
+
+	/* Once more to map the enabled channels. */
+	for (i = 0, l = o->sdi->channels; l; l = l->next) {
+		ch = l->data;
+		if (ch->type != SR_CHANNEL_LOGIC)
+			continue;
+		if (!ch->enabled)
+			continue;
+		ctx->channel_index[i++] = ch->index;
+	}
+
+	return SR_OK;
+}
+
+static GString *gen_header(struct sr_output *o)
+{
+	struct context *ctx;
+	struct sr_channel *ch;
+	GVariant *gvar;
+	GString *header;
+	GSList *l;
+	time_t t;
+	int num_channels, i;
+	char *samplerate_s;
+
+	ctx = o->internal;
+	header = g_string_sized_new(512);
+
+	/* Some metadata */
+	t = time(NULL);
+	g_string_append_printf(header, "; CSV, generated by %s on %s",
+			PACKAGE_STRING, ctime(&t));
+
+	/* Columns / channels */
+	num_channels = g_slist_length(o->sdi->channels);
+	g_string_append_printf(header, "; Channels (%d/%d):",
+			ctx->num_enabled_channels, num_channels);
+	for (i = 0, l = o->sdi->channels; l; l = l->next, i++) {
+		ch = l->data;
+		if (ch->type != SR_CHANNEL_LOGIC)
+			continue;
+		if (!ch->enabled)
+			continue;
+		g_string_append_printf(header, " %s,", ch->name);
+	}
+	if (o->sdi->channels)
+		/* Drop last separator. */
+		g_string_truncate(header, header->len - 1);
+	g_string_append_printf(header, "\n");
+
+	if (ctx->samplerate == 0) {
+		if (sr_config_get(o->sdi->driver, o->sdi, NULL, SR_CONF_SAMPLERATE,
+				&gvar) == SR_OK) {
+			ctx->samplerate = g_variant_get_uint64(gvar);
+			g_variant_unref(gvar);
+		}
+	}
+	if (ctx->samplerate != 0) {
+		samplerate_s = sr_samplerate_string(ctx->samplerate);
+		g_string_append_printf(header, "; Samplerate: %s\n", samplerate_s);
+		g_free(samplerate_s);
+	}
+
+	return header;
+}
+
+static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+		GString **out)
+{
+	const struct sr_datafeed_meta *meta;
+	const struct sr_datafeed_logic *logic;
+	const struct sr_config *src;
+	GSList *l;
+	struct context *ctx;
+	int idx;
+	uint64_t i, j;
+	gchar *p, c;
+
+	*out = NULL;
+	if (!o || !o->sdi)
+		return SR_ERR_ARG;
+	if (!(ctx = o->internal))
+		return SR_ERR_ARG;
+
+	switch (packet->type) {
+	case SR_DF_META:
+		meta = packet->payload;
+		for (l = meta->config; l; l = l->next) {
+			src = l->data;
+			if (src->key != SR_CONF_SAMPLERATE)
+				continue;
+			ctx->samplerate = g_variant_get_uint64(src->data);
+		}
+		break;
+	case SR_DF_LOGIC:
+		logic = packet->payload;
+		if (!ctx->header_done) {
+			*out = gen_header(o);
+			ctx->header_done = TRUE;
+		} else {
+			*out = g_string_sized_new(512);
+		}
+
+		for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
+			for (j = 0; j < ctx->num_enabled_channels; j++) {
+				idx = ctx->channel_index[j];
+				p = logic->data + i + idx / 8;
+				c = *p & (1 << (idx % 8));
+				g_string_append_c(*out, c ? '1' : '0');
+				g_string_append_c(*out, ctx->separator);
+			}
+			if (j) {
+				/* Drop last separator. */
+				g_string_truncate(*out, (*out)->len - 1);
+			}
+			g_string_append_printf(*out, "\n");
+		}
+		break;
+	}
+
+	return SR_OK;
+}
+
+static int cleanup(struct sr_output *o)
+{
+	struct context *ctx;
+
+	if (!o || !o->sdi)
+		return SR_ERR_ARG;
+
+	if (o->internal) {
+		ctx = o->internal;
+		g_free(ctx->channel_index);
+		g_free(o->internal);
+		o->internal = NULL;
+	}
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_output_format output_csv = {
+	.id = "csv",
+	.description = "Comma-separated values (CSV)",
+	.init = init,
+	.receive = receive,
+	.cleanup = cleanup,
+};
diff --git a/output/gnuplot.c b/output/gnuplot.c
new file mode 100644
index 0000000..a9feec6
--- /dev/null
+++ b/output/gnuplot.c
@@ -0,0 +1,224 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include "config.h" /* Needed for PACKAGE_STRING and others. */
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "output/gnuplot"
+
+struct context {
+	unsigned int num_enabled_channels;
+	uint64_t samplerate;
+	uint64_t samplecount;
+	gboolean header_done;
+	uint8_t *prevsample;
+	int *channel_index;
+};
+
+static const char *gnuplot_header = "\
+# Sample data in space-separated columns format usable by gnuplot.\n";
+static const char *gnuplot_header2 = "\
+#\n# Column\tChannel\n\
+# -----------------------------------------------------------------------------\n\
+# 0\t\tSample counter (for internal gnuplot purposes)\n";
+
+
+static int init(struct sr_output *o)
+{
+	struct context *ctx;
+	struct sr_channel *ch;
+	GSList *l;
+	unsigned int i;
+
+	if (!o || !o->sdi)
+		return SR_ERR_ARG;
+
+	ctx = g_malloc0(sizeof(struct context));
+	o->internal = ctx;
+	ctx->num_enabled_channels = 0;
+	for (l = o->sdi->channels; l; l = l->next) {
+		ch = l->data;
+		if (ch->type != SR_CHANNEL_LOGIC)
+			continue;
+		if (!ch->enabled)
+			continue;
+		ctx->num_enabled_channels++;
+	}
+	if (ctx->num_enabled_channels <= 0) {
+		sr_err("No logic channel enabled.");
+		return SR_ERR;
+	}
+	ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
+
+	/* Once more to map the enabled channels. */
+	for (i = 0, l = o->sdi->channels; l; l = l->next) {
+		ch = l->data;
+		if (ch->type != SR_CHANNEL_LOGIC)
+			continue;
+		if (!ch->enabled)
+			continue;
+		ctx->channel_index[i++] = ch->index;
+	}
+
+	return SR_OK;
+}
+
+static GString *gen_header(struct sr_output *o)
+{
+	struct context *ctx;
+	struct sr_channel *ch;
+	GVariant *gvar;
+	GString *header;
+	time_t t;
+	unsigned int num_channels, i;
+	char *samplerate_s;
+
+	ctx = o->internal;
+	if (ctx->samplerate == 0) {
+		if (sr_config_get(o->sdi->driver, o->sdi, NULL, SR_CONF_SAMPLERATE,
+				&gvar) == SR_OK) {
+			ctx->samplerate = g_variant_get_uint64(gvar);
+			g_variant_unref(gvar);
+		}
+	}
+
+	t = time(NULL);
+	header = g_string_sized_new(512);
+	g_string_printf(header, "%s", gnuplot_header);
+	g_string_append_printf(header, "# Generated by %s on %s",
+			PACKAGE_STRING, ctime(&t));
+
+	num_channels = g_slist_length(o->sdi->channels);
+	g_string_append_printf(header, "# Acquisition with %d/%d channels",
+			ctx->num_enabled_channels, num_channels);
+	if (ctx->samplerate != 0) {
+		samplerate_s = sr_samplerate_string(ctx->samplerate);
+		g_string_append_printf(header, " at %s", samplerate_s);
+		g_free(samplerate_s);
+	}
+	g_string_append_printf(header, "\n");
+
+	g_string_append_printf(header, "%s", gnuplot_header2);
+
+	/* Columns / channels */
+	for (i = 0; i < ctx->num_enabled_channels; i++) {
+		ch = g_slist_nth_data(o->sdi->channels, ctx->channel_index[i]);
+		g_string_append_printf(header, "# %d\t\t%s\n", i + 1, ch->name);
+	}
+
+	return header;
+}
+
+static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+		GString **out)
+{
+	const struct sr_datafeed_meta *meta;
+	const struct sr_datafeed_logic *logic;
+	const struct sr_config *src;
+	GSList *l;
+	struct context *ctx;
+	const uint8_t *sample;
+	unsigned int curbit, p, idx, i;
+
+	*out = NULL;
+	if (!o || !o->internal)
+		return SR_ERR_BUG;
+	ctx = o->internal;
+
+	if (packet->type == SR_DF_META) {
+		meta = packet->payload;
+		for (l = meta->config; l; l = l->next) {
+			src = l->data;
+			if (src->key != SR_CONF_SAMPLERATE)
+				continue;
+			ctx->samplerate = g_variant_get_uint64(src->data);
+		}
+	}
+
+	if (packet->type != SR_DF_LOGIC)
+		return SR_OK;
+	logic = packet->payload;
+
+	if (!ctx->prevsample) {
+		/* Can't allocate this until we know the stream's unitsize. */
+		ctx->prevsample = g_malloc0(logic->unitsize);
+	}
+
+	if (!ctx->header_done) {
+		*out = gen_header(o);
+		ctx->header_done = TRUE;
+	} else {
+		*out = g_string_sized_new(512);
+	}
+
+	for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
+		sample = logic->data + i;
+		ctx->samplecount++;
+
+		/*
+		 * Don't output the same sample multiple times, but make
+		 * sure to output at least the first and last sample.
+		 */
+		if (i > 0 && i < logic->length - logic->unitsize) {
+			if (!memcmp(sample, ctx->prevsample, logic->unitsize))
+				continue;
+		}
+		memcpy(ctx->prevsample, sample, logic->unitsize);
+
+		/* The first column is a counter (needed for gnuplot). */
+		g_string_append_printf(*out, "%" PRIu64 "\t", ctx->samplecount);
+
+		/* The next columns are the values of all channels. */
+		for (p = 0; p < ctx->num_enabled_channels; p++) {
+			idx = ctx->channel_index[p];
+			curbit = (sample[idx / 8] & ((uint8_t) (1 << (idx % 8)))) >> (idx % 8);
+			g_string_append_printf(*out, "%d ", curbit);
+		}
+		g_string_append_printf(*out, "\n");
+	}
+
+	return SR_OK;
+}
+
+static int cleanup(struct sr_output *o)
+{
+	struct context *ctx;
+
+	if (!o || !o->internal)
+		return SR_ERR_BUG;
+	ctx = o->internal;
+	g_free(ctx->channel_index);
+	g_free(ctx->prevsample);
+	g_free(ctx);
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_output_format output_gnuplot = {
+	.id = "gnuplot",
+	.description = "Gnuplot",
+	.init = init,
+	.receive = receive,
+	.cleanup = cleanup,
+};
diff --git a/output/hex.c b/output/hex.c
new file mode 100644
index 0000000..07a430c
--- /dev/null
+++ b/output/hex.c
@@ -0,0 +1,260 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2014 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "output/hex"
+
+#define DEFAULT_SAMPLES_PER_LINE 192
+
+struct context {
+	unsigned int num_enabled_channels;
+	int samples_per_line;
+	int bit_cnt;
+	int spl_cnt;
+	int trigger;
+	uint64_t samplerate;
+	int *channel_index;
+	char **channel_names;
+	char **line_values;
+	uint8_t *sample_buf;
+	gboolean header_done;
+	GString **lines;
+};
+
+static int init(struct sr_output *o)
+{
+	struct context *ctx;
+	struct sr_channel *ch;
+	GSList *l;
+	GHashTableIter iter;
+	gpointer key, value;
+	unsigned int i, j;
+	int spl;
+
+	if (!o || !o->sdi)
+		return SR_ERR_ARG;
+
+	spl = DEFAULT_SAMPLES_PER_LINE;
+	g_hash_table_iter_init(&iter, o->params);
+	while (g_hash_table_iter_next(&iter, &key, &value)) {
+		if (!strcmp(key, "width")) {
+			if ((spl = strtoul(value, NULL, 10)) < 1) {
+				sr_err("Invalid width.");
+				return SR_ERR_ARG;
+			}
+		} else {
+			sr_err("Unknown parameter '%s'.", key);
+			return SR_ERR_ARG;
+		}
+	}
+
+	ctx = g_malloc0(sizeof(struct context));
+	o->internal = ctx;
+	ctx->trigger = -1;
+	ctx->samples_per_line = spl;
+
+	for (l = o->sdi->channels; l; l = l->next) {
+		ch = l->data;
+		if (ch->type != SR_CHANNEL_LOGIC)
+			continue;
+		if (!ch->enabled)
+			continue;
+		ctx->num_enabled_channels++;
+	}
+	ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
+	ctx->channel_names = g_malloc(sizeof(char *) * ctx->num_enabled_channels);
+	ctx->lines = g_malloc(sizeof(GString *) * ctx->num_enabled_channels);
+	ctx->sample_buf = g_malloc(ctx->num_enabled_channels);
+
+	j = 0;
+	for (i = 0, l = o->sdi->channels; l; l = l->next, i++) {
+		ch = l->data;
+		if (ch->type != SR_CHANNEL_LOGIC)
+			continue;
+		if (!ch->enabled)
+			continue;
+		ctx->channel_index[j] = ch->index;
+		ctx->channel_names[j] = ch->name;
+		ctx->lines[j] = g_string_sized_new(80);
+		ctx->sample_buf[j] = 0;
+		g_string_printf(ctx->lines[j], "%s:", ch->name);
+		j++;
+	}
+
+	return SR_OK;
+}
+
+static GString *gen_header(struct sr_output *o)
+{
+	struct context *ctx;
+	GVariant *gvar;
+	GString *header;
+	int num_channels;
+	char *samplerate_s;
+
+	ctx = o->internal;
+	if (ctx->samplerate == 0) {
+		if (sr_config_get(o->sdi->driver, o->sdi, NULL, SR_CONF_SAMPLERATE,
+				&gvar) == SR_OK) {
+			ctx->samplerate = g_variant_get_uint64(gvar);
+			g_variant_unref(gvar);
+		}
+	}
+
+	header = g_string_sized_new(512);
+	g_string_printf(header, "%s\n", PACKAGE_STRING);
+	num_channels = g_slist_length(o->sdi->channels);
+	g_string_append_printf(header, "Acquisition with %d/%d channels",
+			ctx->num_enabled_channels, num_channels);
+	if (ctx->samplerate != 0) {
+		samplerate_s = sr_samplerate_string(ctx->samplerate);
+		g_string_append_printf(header, " at %s", samplerate_s);
+		g_free(samplerate_s);
+	}
+	g_string_append_printf(header, "\n");
+
+	return header;
+}
+
+static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+		GString **out)
+{
+	const struct sr_datafeed_meta *meta;
+	const struct sr_datafeed_logic *logic;
+	const struct sr_config *src;
+	GSList *l;
+	struct context *ctx;
+	int idx, pos, offset;
+	uint64_t i, j;
+	gchar *p;
+
+	*out = NULL;
+	if (!o || !o->sdi)
+		return SR_ERR_ARG;
+	if (!(ctx = o->internal))
+		return SR_ERR_ARG;
+
+	switch (packet->type) {
+	case SR_DF_META:
+		meta = packet->payload;
+		for (l = meta->config; l; l = l->next) {
+			src = l->data;
+			if (src->key != SR_CONF_SAMPLERATE)
+				continue;
+			ctx->samplerate = g_variant_get_uint64(src->data);
+		}
+		break;
+	case SR_DF_TRIGGER:
+		ctx->trigger = ctx->spl_cnt;
+		break;
+	case SR_DF_LOGIC:
+		if (!ctx->header_done) {
+			*out = gen_header(o);
+			ctx->header_done = TRUE;
+		} else
+			*out = g_string_sized_new(512);
+
+		logic = packet->payload;
+		for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
+			ctx->spl_cnt++;
+			pos = ctx->spl_cnt & 7;
+			for (j = 0; j < ctx->num_enabled_channels; j++) {
+				idx = ctx->channel_index[j];
+				p = logic->data + i + idx / 8;
+				ctx->sample_buf[j] <<= 1;
+				if (*p & (1 << (idx % 8)))
+					ctx->sample_buf[j] |= 1;
+				if (ctx->spl_cnt && pos == 0) {
+					/* Buffered a byte's worth, output hex. */
+					g_string_append_printf(ctx->lines[j], "%.2x ",
+							ctx->sample_buf[j]);
+					ctx->sample_buf[j] = 0;
+				}
+
+				if (ctx->spl_cnt == ctx->samples_per_line) {
+					/* Flush line buffers. */
+					g_string_append_len(*out, ctx->lines[j]->str, ctx->lines[j]->len);
+					g_string_append_c(*out, '\n');
+					if (j == ctx->num_enabled_channels  - 1 && ctx->trigger > -1) {
+						offset = ctx->trigger + ctx->trigger / 8;
+						g_string_append_printf(*out, "T:%*s^ %d\n", offset, "", ctx->trigger);
+						ctx->trigger = -1;
+					}
+					g_string_printf(ctx->lines[j], "%s:", ctx->channel_names[j]);
+				}
+			}
+			if (ctx->spl_cnt == ctx->samples_per_line)
+				/* Line buffers were already flushed. */
+				ctx->spl_cnt = 0;
+		}
+		break;
+	case SR_DF_END:
+		if (ctx->spl_cnt) {
+			/* Line buffers need flushing. */
+			*out = g_string_sized_new(512);
+			for (i = 0; i < ctx->num_enabled_channels; i++) {
+				if (ctx->spl_cnt & 7)
+					g_string_append_printf(ctx->lines[i], "%.2x ",
+							ctx->sample_buf[i] << (8 - (ctx->spl_cnt & 7)));
+				g_string_append_len(*out, ctx->lines[i]->str, ctx->lines[i]->len);
+				g_string_append_c(*out, '\n');
+			}
+		}
+		break;
+	}
+
+	return SR_OK;
+}
+
+static int cleanup(struct sr_output *o)
+{
+	struct context *ctx;
+	unsigned int i;
+
+	if (!o)
+		return SR_ERR_ARG;
+
+	if (!(ctx = o->internal))
+		return SR_OK;
+
+	g_free(ctx->channel_index);
+	g_free(ctx->sample_buf);
+	g_free(ctx->channel_names);
+	for (i = 0; i < ctx->num_enabled_channels; i++)
+		g_string_free(ctx->lines[i], TRUE);
+	g_free(ctx->lines);
+	g_free(ctx);
+	o->internal = NULL;
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_output_format output_hex = {
+	.id = "hex",
+	.description = "Hexadecimal",
+	.init = init,
+	.receive = receive,
+	.cleanup = cleanup,
+};
+
diff --git a/output/ols.c b/output/ols.c
new file mode 100644
index 0000000..78a41bb
--- /dev/null
+++ b/output/ols.c
@@ -0,0 +1,157 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2011 Uwe Hermann <uwe at hermann-uwe.de>
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/*
+ * This implements version 1.3 of the output format for the OpenBench Logic
+ * Sniffer "Alternative" Java client. Details:
+ * https://github.com/jawi/ols/wiki/OLS-data-file-format
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "output/ols"
+
+struct context {
+	uint64_t samplerate;
+	uint64_t num_samples;
+};
+
+static int init(struct sr_output *o)
+{
+	struct context *ctx;
+
+	if (!(ctx = g_try_malloc(sizeof(struct context)))) {
+		sr_err("%s: ctx malloc failed", __func__);
+		return SR_ERR_MALLOC;
+	}
+	o->internal = ctx;
+
+	ctx->samplerate = 0;
+	ctx->num_samples = 0;
+
+	return SR_OK;
+}
+
+static GString *gen_header(const struct sr_dev_inst *sdi, struct context *ctx)
+{
+	struct sr_channel *ch;
+	GSList *l;
+	GString *s;
+	GVariant *gvar;
+	int num_enabled_channels;
+
+	if (!ctx->samplerate && sr_config_get(sdi->driver, sdi, NULL,
+			SR_CONF_SAMPLERATE, &gvar) == SR_OK) {
+		ctx->samplerate = g_variant_get_uint64(gvar);
+		g_variant_unref(gvar);
+	}
+
+	num_enabled_channels = 0;
+	for (l = sdi->channels; l; l = l->next) {
+		ch = l->data;
+		if (ch->type != SR_CHANNEL_LOGIC)
+			continue;
+		if (!ch->enabled)
+			continue;
+		num_enabled_channels++;
+	}
+
+	s = g_string_sized_new(512);
+	g_string_append_printf(s, ";Rate: %"PRIu64"\n", ctx->samplerate);
+	g_string_append_printf(s, ";Channels: %d\n", num_enabled_channels);
+	g_string_append_printf(s, ";EnabledChannels: -1\n");
+	g_string_append_printf(s, ";Compressed: true\n");
+	g_string_append_printf(s, ";CursorEnabled: false\n");
+
+	return s;
+}
+
+static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+		GString **out)
+{
+	struct context *ctx;
+	const struct sr_datafeed_meta *meta;
+	const struct sr_datafeed_logic *logic;
+	const struct sr_config *src;
+	GSList *l;
+	unsigned int i, j;
+	uint8_t c;
+
+	*out = NULL;
+	if (!o || !o->sdi)
+		return SR_ERR_ARG;
+	ctx = o->internal;
+
+	switch (packet->type) {
+	case SR_DF_META:
+		meta = packet->payload;
+		for (l = meta->config; l; l = l->next) {
+			src = l->data;
+			if (src->key == SR_CONF_SAMPLERATE)
+				ctx->samplerate = g_variant_get_uint64(src->data);
+		}
+		break;
+	case SR_DF_LOGIC:
+		logic = packet->payload;
+		if (ctx->num_samples == 0) {
+			/* First logic packet in the feed. */
+			*out = gen_header(o->sdi, ctx);
+		} else
+			*out = g_string_sized_new(512);
+		for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
+			for (j = 0; j < logic->unitsize; j++) {
+				/* The OLS format wants the samples presented MSB first. */
+				c = *((uint8_t *)logic->data + i + logic->unitsize - 1 - j);
+				g_string_append_printf(*out, "%02x", c);
+			}
+			g_string_append_printf(*out, "@%"PRIu64"\n", ctx->num_samples++);
+		}
+		break;
+	}
+
+	return SR_OK;
+}
+
+static int cleanup(struct sr_output *o)
+{
+	struct context *ctx;
+
+	if (!o || !o->sdi)
+		return SR_ERR_ARG;
+
+	ctx = o->internal;
+	g_free(ctx);
+	o->internal = NULL;
+
+	return SR_OK;
+}
+
+SR_PRIV struct sr_output_format output_ols = {
+	.id = "ols",
+	.description = "OpenBench Logic Sniffer",
+	.init = init,
+	.receive = receive,
+	.cleanup = cleanup
+};
diff --git a/output/output.c b/output/output.c
new file mode 100644
index 0000000..4cf78f6
--- /dev/null
+++ b/output/output.c
@@ -0,0 +1,120 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010-2012 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+/**
+ * @file
+ *
+ * Output file/data format handling.
+ */
+
+/**
+ * @defgroup grp_output Output formats
+ *
+ * Output file/data format handling.
+ *
+ * libsigrok supports several output (file) formats, e.g. binary, VCD,
+ * gnuplot, and so on. It provides an output API that frontends can use.
+ * New output formats can be added/implemented in libsigrok without having
+ * to change the frontends at all.
+ *
+ * All output modules are fed data in a stream. Devices that can stream data
+ * into libsigrok, instead of storing and then transferring the whole buffer,
+ * can thus generate output live.
+ *
+ * Output modules generate a newly allocated GString. The caller is then
+ * expected to free this with g_string_free() when finished with it.
+ *
+ * @{
+ */
+
+/** @cond PRIVATE */
+extern SR_PRIV struct sr_output_format output_bits;
+extern SR_PRIV struct sr_output_format output_hex;
+extern SR_PRIV struct sr_output_format output_ascii;
+extern SR_PRIV struct sr_output_format output_binary;
+extern SR_PRIV struct sr_output_format output_vcd;
+extern SR_PRIV struct sr_output_format output_ols;
+extern SR_PRIV struct sr_output_format output_gnuplot;
+extern SR_PRIV struct sr_output_format output_chronovu_la8;
+extern SR_PRIV struct sr_output_format output_csv;
+extern SR_PRIV struct sr_output_format output_analog;
+/* @endcond */
+
+static struct sr_output_format *output_module_list[] = {
+	&output_ascii,
+	&output_binary,
+	&output_bits,
+	&output_csv,
+	&output_gnuplot,
+	&output_hex,
+	&output_ols,
+	&output_vcd,
+	&output_chronovu_la8,
+	&output_analog,
+	NULL,
+};
+
+/** @since 0.1.0 */
+SR_API struct sr_output_format **sr_output_list(void)
+{
+	return output_module_list;
+}
+
+/** @since 0.3.0 */
+SR_API struct sr_output *sr_output_new(struct sr_output_format *of,
+		GHashTable *params, const struct sr_dev_inst *sdi)
+{
+	struct sr_output *o;
+
+	o = g_malloc(sizeof(struct sr_output));
+	o->format = of;
+	o->sdi = sdi;
+	o->params = params;
+	if (o->format->init && o->format->init(o) != SR_OK) {
+		g_free(o);
+		o = NULL;
+	}
+
+	return o;
+}
+
+/** @since 0.3.0 */
+SR_API int sr_output_send(struct sr_output *o,
+		const struct sr_datafeed_packet *packet, GString **out)
+{
+	return o->format->receive(o, packet, out);
+}
+
+/** @since 0.3.0 */
+SR_API int sr_output_free(struct sr_output *o)
+{
+	int ret;
+
+	ret = SR_OK;
+	if (o->format->cleanup)
+		ret = o->format->cleanup(o);
+	g_free(o);
+
+	return ret;
+}
+
+/** @} */
diff --git a/output/vcd.c b/output/vcd.c
new file mode 100644
index 0000000..87f8049
--- /dev/null
+++ b/output/vcd.c
@@ -0,0 +1,269 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010 Uwe Hermann <uwe at hermann-uwe.de>
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include "config.h" /* Needed for PACKAGE and others. */
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "output/vcd"
+
+struct context {
+	int num_enabled_channels;
+	GArray *channelindices;
+	uint8_t *prevsample;
+	gboolean header_done;
+	int period;
+	int *channel_index;
+	uint64_t samplerate;
+	uint64_t samplecount;
+};
+
+static const char *const vcd_header_comment =
+	"$comment\n  Acquisition with %d/%d channels at %s\n$end\n";
+
+static int init(struct sr_output *o)
+{
+	struct context *ctx;
+	struct sr_channel *ch;
+	GSList *l;
+	int num_enabled_channels, i;
+
+	num_enabled_channels = 0;
+	for (l = o->sdi->channels; l; l = l->next) {
+		ch = l->data;
+		if (ch->type != SR_CHANNEL_LOGIC)
+			continue;
+		if (!ch->enabled)
+			continue;
+		num_enabled_channels++;
+	}
+	if (num_enabled_channels > 94) {
+		sr_err("VCD only supports 94 channels.");
+		return SR_ERR;
+	}
+
+	ctx = g_malloc0(sizeof(struct context));
+	o->internal = ctx;
+	ctx->num_enabled_channels = num_enabled_channels;
+	ctx->channel_index = g_malloc(sizeof(int) * ctx->num_enabled_channels);
+
+	/* Once more to map the enabled channels. */
+	for (i = 0, l = o->sdi->channels; l; l = l->next) {
+		ch = l->data;
+		if (ch->type != SR_CHANNEL_LOGIC)
+			continue;
+		if (!ch->enabled)
+			continue;
+		ctx->channel_index[i++] = ch->index;
+	}
+
+	return SR_OK;
+}
+
+static GString *gen_header(struct sr_output *o)
+{
+	struct context *ctx;
+	struct sr_channel *ch;
+	GVariant *gvar;
+	GString *header;
+	GSList *l;
+	time_t t;
+	int num_channels, i;
+	char *samplerate_s, *frequency_s, *timestamp;
+
+	ctx = o->internal;
+	header = g_string_sized_new(512);
+	num_channels = g_slist_length(o->sdi->channels);
+
+	/* timestamp */
+	t = time(NULL);
+	timestamp = g_strdup(ctime(&t));
+	timestamp[strlen(timestamp)-1] = 0;
+	g_string_printf(header, "$date %s $end\n", timestamp);
+	g_free(timestamp);
+
+	/* generator */
+	g_string_append_printf(header, "$version %s %s $end\n",
+			PACKAGE, PACKAGE_VERSION);
+	g_string_append_printf(header, "$comment\n  Acquisition with "
+			"%d/%d channels", ctx->num_enabled_channels, num_channels);
+
+	if (ctx->samplerate == 0) {
+		if (sr_config_get(o->sdi->driver, o->sdi, NULL, SR_CONF_SAMPLERATE,
+				&gvar) == SR_OK) {
+			ctx->samplerate = g_variant_get_uint64(gvar);
+			g_variant_unref(gvar);
+		}
+	}
+	if (ctx->samplerate != 0) {
+		samplerate_s = sr_samplerate_string(ctx->samplerate);
+		g_string_append_printf(header, " at %s", samplerate_s);
+		g_free(samplerate_s);
+	}
+	g_string_append_printf(header, "\n$end\n");
+
+	/* timescale */
+	/* VCD can only handle 1/10/100 (s - fs), so scale up first */
+	if (ctx->samplerate > SR_MHZ(1))
+		ctx->period = SR_GHZ(1);
+	else if (ctx->samplerate > SR_KHZ(1))
+		ctx->period = SR_MHZ(1);
+	else
+		ctx->period = SR_KHZ(1);
+	frequency_s = sr_period_string(ctx->period);
+	g_string_append_printf(header, "$timescale %s $end\n", frequency_s);
+	g_free(frequency_s);
+
+	/* scope */
+	g_string_append_printf(header, "$scope module %s $end\n", PACKAGE);
+
+	/* Wires / channels */
+	for (i = 0, l = o->sdi->channels; l; l = l->next, i++) {
+		ch = l->data;
+		if (ch->type != SR_CHANNEL_LOGIC)
+			continue;
+		if (!ch->enabled)
+			continue;
+		g_string_append_printf(header, "$var wire 1 %c %s $end\n",
+				(char)('!' + i), ch->name);
+	}
+
+	g_string_append(header, "$upscope $end\n$enddefinitions $end\n");
+
+	return header;
+}
+
+static int receive(struct sr_output *o, const struct sr_datafeed_packet *packet,
+		GString **out)
+{
+	const struct sr_datafeed_meta *meta;
+	const struct sr_datafeed_logic *logic;
+	const struct sr_config *src;
+	GSList *l;
+	struct context *ctx;
+	unsigned int i;
+	int p, curbit, prevbit, index;
+	uint8_t *sample;
+	gboolean timestamp_written;
+
+	*out = NULL;
+	if (!o || !o->internal)
+		return SR_ERR_BUG;
+	ctx = o->internal;
+
+	switch (packet->type) {
+	case SR_DF_META:
+		meta = packet->payload;
+		for (l = meta->config; l; l = l->next) {
+			src = l->data;
+			if (src->key != SR_CONF_SAMPLERATE)
+				continue;
+			ctx->samplerate = g_variant_get_uint64(src->data);
+		}
+		break;
+	case SR_DF_LOGIC:
+		logic = packet->payload;
+
+		if (!ctx->header_done) {
+			*out = gen_header(o);
+			ctx->header_done = TRUE;
+		} else {
+			*out = g_string_sized_new(512);
+		}
+
+		if (!ctx->prevsample) {
+			/* Can't allocate this until we know the stream's unitsize. */
+			ctx->prevsample = g_malloc0(logic->unitsize);
+		}
+
+		for (i = 0; i <= logic->length - logic->unitsize; i += logic->unitsize) {
+			sample = logic->data + i;
+			timestamp_written = FALSE;
+
+			for (p = 0; p < ctx->num_enabled_channels; p++) {
+				index = ctx->channel_index[p];
+
+				curbit = ((unsigned)sample[index / 8]
+						>> (index % 8)) & 1;
+				prevbit = ((unsigned)ctx->prevsample[index / 8]
+						>> (index % 8)) & 1;
+
+				/* VCD only contains deltas/changes of signals. */
+				if (prevbit == curbit && ctx->samplecount > 0)
+					continue;
+
+				/* Output timestamp of subsequent signal changes. */
+				if (!timestamp_written)
+					g_string_append_printf(*out, "#%.0f",
+						(double)ctx->samplecount /
+							ctx->samplerate * ctx->period);
+
+				/* Output which signal changed to which value. */
+				g_string_append_c(*out, ' ');
+				g_string_append_c(*out, '0' + curbit);
+				g_string_append_c(*out, '!' + p);
+
+				timestamp_written = TRUE;
+			}
+
+			if (timestamp_written)
+				g_string_append_c(*out, '\n');
+
+			ctx->samplecount++;
+			memcpy(ctx->prevsample, sample, logic->unitsize);
+		}
+		break;
+	case SR_DF_END:
+		/* Write final timestamp as length indicator. */
+		*out = g_string_sized_new(512);
+		g_string_printf(*out, "#%.0f\n",
+				(double)ctx->samplecount / ctx->samplerate * ctx->period);
+		break;
+	}
+
+	return SR_OK;
+}
+
+static int cleanup(struct sr_output *o)
+{
+	struct context *ctx;
+
+	if (!o || !o->internal)
+		return SR_ERR_ARG;
+
+	ctx = o->internal;
+	g_free(ctx->prevsample);
+	g_free(ctx->channel_index);
+	g_free(ctx);
+
+	return SR_OK;
+}
+
+struct sr_output_format output_vcd = {
+	.id = "vcd",
+	.description = "Value Change Dump (VCD)",
+	.init = init,
+	.receive = receive,
+	.cleanup = cleanup,
+};
diff --git a/proto.h b/proto.h
new file mode 100644
index 0000000..49353d5
--- /dev/null
+++ b/proto.h
@@ -0,0 +1,163 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_PROTO_H
+#define LIBSIGROK_PROTO_H
+
+/**
+ * @file
+ *
+ * Header file containing API function prototypes.
+ */
+
+/*--- backend.c -------------------------------------------------------------*/
+
+SR_API int sr_init(struct sr_context **ctx);
+SR_API int sr_exit(struct sr_context *ctx);
+
+/*--- log.c -----------------------------------------------------------------*/
+
+typedef int (*sr_log_callback)(void *cb_data, int loglevel,
+				const char *format, va_list args);
+
+SR_API int sr_log_loglevel_set(int loglevel);
+SR_API int sr_log_loglevel_get(void);
+SR_API int sr_log_callback_set(sr_log_callback cb, void *cb_data);
+SR_API int sr_log_callback_set_default(void);
+SR_API int sr_log_logdomain_set(const char *logdomain);
+SR_API char *sr_log_logdomain_get(void);
+
+/*--- device.c --------------------------------------------------------------*/
+
+SR_API int sr_dev_channel_name_set(const struct sr_dev_inst *sdi,
+		int channelnum, const char *name);
+SR_API int sr_dev_channel_enable(const struct sr_dev_inst *sdi, int channelnum,
+		gboolean state);
+SR_API int sr_dev_trigger_set(const struct sr_dev_inst *sdi, int channelnum,
+		const char *trigger);
+SR_API gboolean sr_dev_has_option(const struct sr_dev_inst *sdi, int key);
+SR_API GSList *sr_dev_list(const struct sr_dev_driver *driver);
+SR_API int sr_dev_clear(const struct sr_dev_driver *driver);
+SR_API int sr_dev_open(struct sr_dev_inst *sdi);
+SR_API int sr_dev_close(struct sr_dev_inst *sdi);
+
+/*--- hwdriver.c ------------------------------------------------------------*/
+
+SR_API struct sr_dev_driver **sr_driver_list(void);
+SR_API int sr_driver_init(struct sr_context *ctx,
+		struct sr_dev_driver *driver);
+SR_API GSList *sr_driver_scan(struct sr_dev_driver *driver, GSList *options);
+SR_API int sr_config_get(const struct sr_dev_driver *driver,
+		const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg,
+		int key, GVariant **data);
+SR_API int sr_config_set(const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg,
+		int key, GVariant *data);
+SR_API int sr_config_commit(const struct sr_dev_inst *sdi);
+SR_API int sr_config_list(const struct sr_dev_driver *driver,
+		const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg,
+		int key, GVariant **data);
+SR_API const struct sr_config_info *sr_config_info_get(int key);
+SR_API const struct sr_config_info *sr_config_info_name_get(const char *optname);
+
+/*--- session.c -------------------------------------------------------------*/
+
+typedef void (*sr_datafeed_callback)(const struct sr_dev_inst *sdi,
+		const struct sr_datafeed_packet *packet, void *cb_data);
+
+/* Session setup */
+SR_API int sr_session_load(const char *filename);
+SR_API struct sr_session *sr_session_new(void);
+SR_API int sr_session_destroy(void);
+SR_API int sr_session_dev_remove_all(void);
+SR_API int sr_session_dev_add(const struct sr_dev_inst *sdi);
+SR_API int sr_session_dev_list(GSList **devlist);
+
+/* Datafeed setup */
+SR_API int sr_session_datafeed_callback_remove_all(void);
+SR_API int sr_session_datafeed_callback_add(sr_datafeed_callback cb,
+		void *cb_data);
+
+/* Session control */
+SR_API int sr_session_start(void);
+SR_API int sr_session_run(void);
+SR_API int sr_session_stop(void);
+SR_API int sr_session_save(const char *filename, const struct sr_dev_inst *sdi,
+		unsigned char *buf, int unitsize, int units);
+SR_API int sr_session_save_init(const char *filename, uint64_t samplerate,
+		char **channels);
+SR_API int sr_session_append(const char *filename, unsigned char *buf,
+		int unitsize, int units);
+SR_API int sr_session_source_add(int fd, int events, int timeout,
+		sr_receive_data_callback cb, void *cb_data);
+SR_API int sr_session_source_add_pollfd(GPollFD *pollfd, int timeout,
+		sr_receive_data_callback cb, void *cb_data);
+SR_API int sr_session_source_add_channel(GIOChannel *channel, int events,
+		int timeout, sr_receive_data_callback cb, void *cb_data);
+SR_API int sr_session_source_remove(int fd);
+SR_API int sr_session_source_remove_pollfd(GPollFD *pollfd);
+SR_API int sr_session_source_remove_channel(GIOChannel *channel);
+
+/*--- input/input.c ---------------------------------------------------------*/
+
+SR_API struct sr_input_format **sr_input_list(void);
+
+/*--- output/output.c -------------------------------------------------------*/
+
+SR_API struct sr_output_format **sr_output_list(void);
+SR_API struct sr_output *sr_output_new(struct sr_output_format *of,
+		GHashTable *params, const struct sr_dev_inst *sdi);
+SR_API int sr_output_send(struct sr_output *o,
+		const struct sr_datafeed_packet *packet, GString **out);
+SR_API int sr_output_free(struct sr_output *o);
+
+/*--- strutil.c -------------------------------------------------------------*/
+
+SR_API char *sr_si_string_u64(uint64_t x, const char *unit);
+SR_API char *sr_samplerate_string(uint64_t samplerate);
+SR_API char *sr_period_string(uint64_t frequency);
+SR_API char *sr_voltage_string(uint64_t v_p, uint64_t v_q);
+SR_API char **sr_parse_triggerstring(const struct sr_dev_inst *sdi,
+		const char *triggerstring);
+SR_API int sr_parse_sizestring(const char *sizestring, uint64_t *size);
+SR_API uint64_t sr_parse_timestring(const char *timestring);
+SR_API gboolean sr_parse_boolstring(const char *boolstring);
+SR_API int sr_parse_period(const char *periodstr, uint64_t *p, uint64_t *q);
+SR_API int sr_parse_voltage(const char *voltstr, uint64_t *p, uint64_t *q);
+
+/*--- version.c -------------------------------------------------------------*/
+
+SR_API int sr_package_version_major_get(void);
+SR_API int sr_package_version_minor_get(void);
+SR_API int sr_package_version_micro_get(void);
+SR_API const char *sr_package_version_string_get(void);
+
+SR_API int sr_lib_version_current_get(void);
+SR_API int sr_lib_version_revision_get(void);
+SR_API int sr_lib_version_age_get(void);
+SR_API const char *sr_lib_version_string_get(void);
+
+/*--- error.c ---------------------------------------------------------------*/
+
+SR_API const char *sr_strerror(int error_code);
+SR_API const char *sr_strerror_name(int error_code);
+
+#endif
diff --git a/session.c b/session.c
new file mode 100644
index 0000000..0540942
--- /dev/null
+++ b/session.c
@@ -0,0 +1,835 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010-2012 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+/** @cond PRIVATE */
+#define LOG_PREFIX "session"
+/** @endcond */
+
+/**
+ * @file
+ *
+ * Creating, using, or destroying libsigrok sessions.
+ */
+
+/**
+ * @defgroup grp_session Session handling
+ *
+ * Creating, using, or destroying libsigrok sessions.
+ *
+ * @{
+ */
+
+struct source {
+	int timeout;
+	sr_receive_data_callback cb;
+	void *cb_data;
+
+	/* This is used to keep track of the object (fd, pollfd or channel) which is
+	 * being polled and will be used to match the source when removing it again.
+	 */
+	gintptr poll_object;
+};
+
+struct datafeed_callback {
+	sr_datafeed_callback cb;
+	void *cb_data;
+};
+
+/* There can only be one session at a time. */
+/* 'session' is not static, it's used elsewhere (via 'extern'). */
+struct sr_session *session;
+
+/**
+ * Create a new session.
+ *
+ * @todo Should it use the file-global "session" variable or take an argument?
+ *       The same question applies to all the other session functions.
+ *
+ * @retval NULL Error.
+ * @retval other A pointer to the newly allocated session.
+ *
+ * @since 0.1.0
+ */
+SR_API struct sr_session *sr_session_new(void)
+{
+	if (!(session = g_try_malloc0(sizeof(struct sr_session)))) {
+		sr_err("Session malloc failed.");
+		return NULL;
+	}
+
+	session->source_timeout = -1;
+	session->running = FALSE;
+	session->abort_session = FALSE;
+	g_mutex_init(&session->stop_mutex);
+
+	return session;
+}
+
+/**
+ * Destroy the current session.
+ * This frees up all memory used by the session.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_BUG No session exists.
+ *
+ * @since 0.1.0
+ */
+SR_API int sr_session_destroy(void)
+{
+	if (!session) {
+		sr_err("%s: session was NULL", __func__);
+		return SR_ERR_BUG;
+	}
+
+	sr_session_dev_remove_all();
+
+	/* TODO: Error checks needed? */
+
+	g_mutex_clear(&session->stop_mutex);
+
+	g_free(session);
+	session = NULL;
+
+	return SR_OK;
+}
+
+/**
+ * Remove all the devices from the current session.
+ *
+ * The session itself (i.e., the struct sr_session) is not free'd and still
+ * exists after this function returns.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_BUG No session exists.
+ *
+ * @since 0.1.0
+ */
+SR_API int sr_session_dev_remove_all(void)
+{
+	if (!session) {
+		sr_err("%s: session was NULL", __func__);
+		return SR_ERR_BUG;
+	}
+
+	g_slist_free(session->devs);
+	session->devs = NULL;
+
+	return SR_OK;
+}
+
+/**
+ * Add a device instance to the current session.
+ *
+ * @param sdi The device instance to add to the current session. Must not
+ *            be NULL. Also, sdi->driver and sdi->driver->dev_open must
+ *            not be NULL.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_ARG Invalid argument.
+ * @retval SR_ERR_BUG No session exists.
+ *
+ * @since 0.2.0
+ */
+SR_API int sr_session_dev_add(const struct sr_dev_inst *sdi)
+{
+	int ret;
+
+	if (!sdi) {
+		sr_err("%s: sdi was NULL", __func__);
+		return SR_ERR_ARG;
+	}
+
+	if (!session) {
+		sr_err("%s: session was NULL", __func__);
+		return SR_ERR_BUG;
+	}
+
+	/* If sdi->driver is NULL, this is a virtual device. */
+	if (!sdi->driver) {
+		sr_dbg("%s: sdi->driver was NULL, this seems to be "
+		       "a virtual device; continuing", __func__);
+		/* Just add the device, don't run dev_open(). */
+		session->devs = g_slist_append(session->devs, (gpointer)sdi);
+		return SR_OK;
+	}
+
+	/* sdi->driver is non-NULL (i.e. we have a real device). */
+	if (!sdi->driver->dev_open) {
+		sr_err("%s: sdi->driver->dev_open was NULL", __func__);
+		return SR_ERR_BUG;
+	}
+
+	session->devs = g_slist_append(session->devs, (gpointer)sdi);
+
+	if (session->running) {
+		/* Adding a device to a running session. Commit settings
+		 * and start acquisition on that device now. */
+		if ((ret = sr_config_commit(sdi)) != SR_OK) {
+			sr_err("Failed to commit device settings before "
+			       "starting acquisition in running session (%s)",
+			       sr_strerror(ret));
+			return ret;
+		}
+		if ((ret = sdi->driver->dev_acquisition_start(sdi,
+						(void *)sdi)) != SR_OK) {
+			sr_err("Failed to start acquisition of device in "
+			       "running session (%s)", sr_strerror(ret));
+			return ret;
+		}
+	}
+
+	return SR_OK;
+}
+
+/**
+ * List all device instances attached to the current session.
+ *
+ * @param devlist A pointer where the device instance list will be
+ *                stored on return. If no devices are in the session,
+ *                this will be NULL. Each element in the list points
+ *                to a struct sr_dev_inst *.
+ *                The list must be freed by the caller, but not the
+ *                elements pointed to.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR Invalid argument.
+ *
+ * @since 0.3.0
+ */
+SR_API int sr_session_dev_list(GSList **devlist)
+{
+
+	*devlist = NULL;
+
+	if (!session)
+		return SR_ERR;
+
+	*devlist = g_slist_copy(session->devs);
+
+	return SR_OK;
+}
+
+/**
+ * Remove all datafeed callbacks in the current session.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_BUG No session exists.
+ *
+ * @since 0.1.0
+ */
+SR_API int sr_session_datafeed_callback_remove_all(void)
+{
+	if (!session) {
+		sr_err("%s: session was NULL", __func__);
+		return SR_ERR_BUG;
+	}
+
+	g_slist_free_full(session->datafeed_callbacks, g_free);
+	session->datafeed_callbacks = NULL;
+
+	return SR_OK;
+}
+
+/**
+ * Add a datafeed callback to the current session.
+ *
+ * @param cb Function to call when a chunk of data is received.
+ *           Must not be NULL.
+ * @param cb_data Opaque pointer passed in by the caller.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_BUG No session exists.
+ *
+ * @since 0.3.0
+ */
+SR_API int sr_session_datafeed_callback_add(sr_datafeed_callback cb, void *cb_data)
+{
+	struct datafeed_callback *cb_struct;
+
+	if (!session) {
+		sr_err("%s: session was NULL", __func__);
+		return SR_ERR_BUG;
+	}
+
+	if (!cb) {
+		sr_err("%s: cb was NULL", __func__);
+		return SR_ERR_ARG;
+	}
+
+	if (!(cb_struct = g_try_malloc0(sizeof(struct datafeed_callback))))
+		return SR_ERR_MALLOC;
+
+	cb_struct->cb = cb;
+	cb_struct->cb_data = cb_data;
+
+	session->datafeed_callbacks =
+	    g_slist_append(session->datafeed_callbacks, cb_struct);
+
+	return SR_OK;
+}
+
+/**
+ * Call every device in the session's callback.
+ *
+ * For sessions not driven by select loops such as sr_session_run(),
+ * but driven by another scheduler, this can be used to poll the devices
+ * from within that scheduler.
+ *
+ * @param block If TRUE, this call will wait for any of the session's
+ *              sources to fire an event on the file descriptors, or
+ *              any of their timeouts to activate. In other words, this
+ *              can be used as a select loop.
+ *              If FALSE, all sources have their callback run, regardless
+ *              of file descriptor or timeout status.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR Error occured.
+ */
+static int sr_session_iteration(gboolean block)
+{
+	unsigned int i;
+	int ret;
+
+	ret = g_poll(session->pollfds, session->num_sources,
+			block ? session->source_timeout : 0);
+	for (i = 0; i < session->num_sources; i++) {
+		if (session->pollfds[i].revents > 0 || (ret == 0
+			&& session->source_timeout == session->sources[i].timeout)) {
+			/*
+			 * Invoke the source's callback on an event,
+			 * or if the poll timed out and this source
+			 * asked for that timeout.
+			 */
+			if (!session->sources[i].cb(session->pollfds[i].fd,
+					session->pollfds[i].revents,
+					session->sources[i].cb_data))
+				sr_session_source_remove(session->sources[i].poll_object);
+		}
+		/*
+		 * We want to take as little time as possible to stop
+		 * the session if we have been told to do so. Therefore,
+		 * we check the flag after processing every source, not
+		 * just once per main event loop.
+		 */
+		g_mutex_lock(&session->stop_mutex);
+		if (session->abort_session) {
+			sr_session_stop_sync();
+			/* But once is enough. */
+			session->abort_session = FALSE;
+		}
+		g_mutex_unlock(&session->stop_mutex);
+	}
+
+	return SR_OK;
+}
+
+/**
+ * Start a session.
+ *
+ * There can only be one session at a time.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR Error occured.
+ *
+ * @since 0.1.0
+ */
+SR_API int sr_session_start(void)
+{
+	struct sr_dev_inst *sdi;
+	GSList *l;
+	int ret;
+
+	if (!session) {
+		sr_err("%s: session was NULL; a session must be "
+		       "created before starting it.", __func__);
+		return SR_ERR_BUG;
+	}
+
+	if (!session->devs) {
+		sr_err("%s: session->devs was NULL; a session "
+		       "cannot be started without devices.", __func__);
+		return SR_ERR_BUG;
+	}
+
+	sr_info("Starting.");
+
+	ret = SR_OK;
+	for (l = session->devs; l; l = l->next) {
+		sdi = l->data;
+		if ((ret = sr_config_commit(sdi)) != SR_OK) {
+			sr_err("Failed to commit device settings before "
+			       "starting acquisition (%s)", sr_strerror(ret));
+			break;
+		}
+		if ((ret = sdi->driver->dev_acquisition_start(sdi, sdi)) != SR_OK) {
+			sr_err("%s: could not start an acquisition "
+			       "(%s)", __func__, sr_strerror(ret));
+			break;
+		}
+	}
+
+	/* TODO: What if there are multiple devices? Which return code? */
+
+	return ret;
+}
+
+/**
+ * Run the session.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_BUG Error occured.
+ *
+ * @since 0.1.0
+ */
+SR_API int sr_session_run(void)
+{
+	if (!session) {
+		sr_err("%s: session was NULL; a session must be "
+		       "created first, before running it.", __func__);
+		return SR_ERR_BUG;
+	}
+
+	if (!session->devs) {
+		/* TODO: Actually the case? */
+		sr_err("%s: session->devs was NULL; a session "
+		       "cannot be run without devices.", __func__);
+		return SR_ERR_BUG;
+	}
+	session->running = TRUE;
+
+	sr_info("Running.");
+
+	/* Do we have real sources? */
+	if (session->num_sources == 1 && session->pollfds[0].fd == -1) {
+		/* Dummy source, freewheel over it. */
+		while (session->num_sources)
+			session->sources[0].cb(-1, 0, session->sources[0].cb_data);
+	} else {
+		/* Real sources, use g_poll() main loop. */
+		while (session->num_sources)
+			sr_session_iteration(TRUE);
+	}
+
+	return SR_OK;
+}
+
+/**
+ * Stop the current session.
+ *
+ * The current session is stopped immediately, with all acquisition sessions
+ * being stopped and hardware drivers cleaned up.
+ *
+ * This must be called from within the session thread, to prevent freeing
+ * resources that the session thread will try to use.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_BUG No session exists.
+ *
+ * @private
+ */
+SR_PRIV int sr_session_stop_sync(void)
+{
+	struct sr_dev_inst *sdi;
+	GSList *l;
+
+	if (!session) {
+		sr_err("%s: session was NULL", __func__);
+		return SR_ERR_BUG;
+	}
+
+	sr_info("Stopping.");
+
+	for (l = session->devs; l; l = l->next) {
+		sdi = l->data;
+		if (sdi->driver) {
+			if (sdi->driver->dev_acquisition_stop)
+				sdi->driver->dev_acquisition_stop(sdi, sdi);
+		}
+	}
+	session->running = FALSE;
+
+	return SR_OK;
+}
+
+/**
+ * Stop the current session.
+ *
+ * The current session is stopped immediately, with all acquisition sessions
+ * being stopped and hardware drivers cleaned up.
+ *
+ * If the session is run in a separate thread, this function will not block
+ * until the session is finished executing. It is the caller's responsibility
+ * to wait for the session thread to return before assuming that the session is
+ * completely decommissioned.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_BUG No session exists.
+ *
+ * @since 0.1.0
+ */
+SR_API int sr_session_stop(void)
+{
+	if (!session) {
+		sr_err("%s: session was NULL", __func__);
+		return SR_ERR_BUG;
+	}
+
+	g_mutex_lock(&session->stop_mutex);
+	session->abort_session = TRUE;
+	g_mutex_unlock(&session->stop_mutex);
+
+	return SR_OK;
+}
+
+/**
+ * Debug helper.
+ *
+ * @param packet The packet to show debugging information for.
+ */
+static void datafeed_dump(const struct sr_datafeed_packet *packet)
+{
+	const struct sr_datafeed_logic *logic;
+	const struct sr_datafeed_analog *analog;
+
+	switch (packet->type) {
+	case SR_DF_HEADER:
+		sr_dbg("bus: Received SR_DF_HEADER packet.");
+		break;
+	case SR_DF_TRIGGER:
+		sr_dbg("bus: Received SR_DF_TRIGGER packet.");
+		break;
+	case SR_DF_META:
+		sr_dbg("bus: Received SR_DF_META packet.");
+		break;
+	case SR_DF_LOGIC:
+		logic = packet->payload;
+		sr_dbg("bus: Received SR_DF_LOGIC packet (%" PRIu64 " bytes, "
+		       "unitsize = %d).", logic->length, logic->unitsize);
+		break;
+	case SR_DF_ANALOG:
+		analog = packet->payload;
+		sr_dbg("bus: Received SR_DF_ANALOG packet (%d samples).",
+		       analog->num_samples);
+		break;
+	case SR_DF_END:
+		sr_dbg("bus: Received SR_DF_END packet.");
+		break;
+	case SR_DF_FRAME_BEGIN:
+		sr_dbg("bus: Received SR_DF_FRAME_BEGIN packet.");
+		break;
+	case SR_DF_FRAME_END:
+		sr_dbg("bus: Received SR_DF_FRAME_END packet.");
+		break;
+	default:
+		sr_dbg("bus: Received unknown packet type: %d.", packet->type);
+		break;
+	}
+}
+
+/**
+ * Send a packet to whatever is listening on the datafeed bus.
+ *
+ * Hardware drivers use this to send a data packet to the frontend.
+ *
+ * @param sdi TODO.
+ * @param packet The datafeed packet to send to the session bus.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_ARG Invalid argument.
+ *
+ * @private
+ */
+SR_PRIV int sr_session_send(const struct sr_dev_inst *sdi,
+			    const struct sr_datafeed_packet *packet)
+{
+	GSList *l;
+	struct datafeed_callback *cb_struct;
+
+	if (!sdi) {
+		sr_err("%s: sdi was NULL", __func__);
+		return SR_ERR_ARG;
+	}
+
+	if (!packet) {
+		sr_err("%s: packet was NULL", __func__);
+		return SR_ERR_ARG;
+	}
+
+	for (l = session->datafeed_callbacks; l; l = l->next) {
+		if (sr_log_loglevel_get() >= SR_LOG_DBG)
+			datafeed_dump(packet);
+		cb_struct = l->data;
+		cb_struct->cb(sdi, packet, cb_struct->cb_data);
+	}
+
+	return SR_OK;
+}
+
+/**
+ * Add an event source for a file descriptor.
+ *
+ * @param pollfd The GPollFD.
+ * @param[in] timeout Max time to wait before the callback is called,
+ *              ignored if 0.
+ * @param cb Callback function to add. Must not be NULL.
+ * @param cb_data Data for the callback function. Can be NULL.
+ * @param poll_object TODO.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_ARG Invalid argument.
+ * @retval SR_ERR_MALLOC Memory allocation error.
+ */
+static int _sr_session_source_add(GPollFD *pollfd, int timeout,
+	sr_receive_data_callback cb, void *cb_data, gintptr poll_object)
+{
+	struct source *new_sources, *s;
+	GPollFD *new_pollfds;
+
+	if (!cb) {
+		sr_err("%s: cb was NULL", __func__);
+		return SR_ERR_ARG;
+	}
+
+	/* Note: cb_data can be NULL, that's not a bug. */
+
+	new_pollfds = g_try_realloc(session->pollfds,
+			sizeof(GPollFD) * (session->num_sources + 1));
+	if (!new_pollfds) {
+		sr_err("%s: new_pollfds malloc failed", __func__);
+		return SR_ERR_MALLOC;
+	}
+
+	new_sources = g_try_realloc(session->sources, sizeof(struct source) *
+			(session->num_sources + 1));
+	if (!new_sources) {
+		sr_err("%s: new_sources malloc failed", __func__);
+		return SR_ERR_MALLOC;
+	}
+
+	new_pollfds[session->num_sources] = *pollfd;
+	s = &new_sources[session->num_sources++];
+	s->timeout = timeout;
+	s->cb = cb;
+	s->cb_data = cb_data;
+	s->poll_object = poll_object;
+	session->pollfds = new_pollfds;
+	session->sources = new_sources;
+
+	if (timeout != session->source_timeout && timeout > 0
+	    && (session->source_timeout == -1 || timeout < session->source_timeout))
+		session->source_timeout = timeout;
+
+	return SR_OK;
+}
+
+/**
+ * Add an event source for a file descriptor.
+ *
+ * @param fd The file descriptor.
+ * @param events Events to check for.
+ * @param timeout Max time to wait before the callback is called, ignored if 0.
+ * @param cb Callback function to add. Must not be NULL.
+ * @param cb_data Data for the callback function. Can be NULL.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_ARG Invalid argument.
+ * @retval SR_ERR_MALLOC Memory allocation error.
+ *
+ * @since 0.3.0
+ */
+SR_API int sr_session_source_add(int fd, int events, int timeout,
+		sr_receive_data_callback cb, void *cb_data)
+{
+	GPollFD p;
+
+	p.fd = fd;
+	p.events = events;
+
+	return _sr_session_source_add(&p, timeout, cb, cb_data, (gintptr)fd);
+}
+
+/**
+ * Add an event source for a GPollFD.
+ *
+ * @param pollfd The GPollFD.
+ * @param timeout Max time to wait before the callback is called, ignored if 0.
+ * @param cb Callback function to add. Must not be NULL.
+ * @param cb_data Data for the callback function. Can be NULL.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_ARG Invalid argument.
+ * @retval SR_ERR_MALLOC Memory allocation error.
+ *
+ * @since 0.3.0
+ */
+SR_API int sr_session_source_add_pollfd(GPollFD *pollfd, int timeout,
+		sr_receive_data_callback cb, void *cb_data)
+{
+	return _sr_session_source_add(pollfd, timeout, cb,
+				      cb_data, (gintptr)pollfd);
+}
+
+/**
+ * Add an event source for a GIOChannel.
+ *
+ * @param channel The GIOChannel.
+ * @param events Events to poll on.
+ * @param timeout Max time to wait before the callback is called, ignored if 0.
+ * @param cb Callback function to add. Must not be NULL.
+ * @param cb_data Data for the callback function. Can be NULL.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_ARG Invalid argument.
+ * @retval SR_ERR_MALLOC Memory allocation error.
+ *
+ * @since 0.3.0
+ */
+SR_API int sr_session_source_add_channel(GIOChannel *channel, int events,
+		int timeout, sr_receive_data_callback cb, void *cb_data)
+{
+	GPollFD p;
+
+#ifdef _WIN32
+	g_io_channel_win32_make_pollfd(channel, events, &p);
+#else
+	p.fd = g_io_channel_unix_get_fd(channel);
+	p.events = events;
+#endif
+
+	return _sr_session_source_add(&p, timeout, cb, cb_data, (gintptr)channel);
+}
+
+/**
+ * Remove the source belonging to the specified channel.
+ *
+ * @todo Add more error checks and logging.
+ *
+ * @param poll_object The channel for which the source should be removed.
+ *
+ * @retval SR_OK Success
+ * @retval SR_ERR_ARG Invalid arguments
+ * @retval SR_ERR_MALLOC Memory allocation error
+ * @retval SR_ERR_BUG Internal error
+ */
+static int _sr_session_source_remove(gintptr poll_object)
+{
+	struct source *new_sources;
+	GPollFD *new_pollfds;
+	unsigned int old;
+
+	if (!session->sources || !session->num_sources) {
+		sr_err("%s: sources was NULL", __func__);
+		return SR_ERR_BUG;
+	}
+
+	for (old = 0; old < session->num_sources; old++) {
+		if (session->sources[old].poll_object == poll_object)
+			break;
+	}
+
+	/* fd not found, nothing to do */
+	if (old == session->num_sources)
+		return SR_OK;
+
+	session->num_sources -= 1;
+
+	if (old != session->num_sources) {
+		memmove(&session->pollfds[old], &session->pollfds[old+1],
+			(session->num_sources - old) * sizeof(GPollFD));
+		memmove(&session->sources[old], &session->sources[old+1],
+			(session->num_sources - old) * sizeof(struct source));
+	}
+
+	new_pollfds = g_try_realloc(session->pollfds, sizeof(GPollFD) * session->num_sources);
+	if (!new_pollfds && session->num_sources > 0) {
+		sr_err("%s: new_pollfds malloc failed", __func__);
+		return SR_ERR_MALLOC;
+	}
+
+	new_sources = g_try_realloc(session->sources, sizeof(struct source) * session->num_sources);
+	if (!new_sources && session->num_sources > 0) {
+		sr_err("%s: new_sources malloc failed", __func__);
+		return SR_ERR_MALLOC;
+	}
+
+	session->pollfds = new_pollfds;
+	session->sources = new_sources;
+
+	return SR_OK;
+}
+
+/**
+ * Remove the source belonging to the specified file descriptor.
+ *
+ * @param fd The file descriptor for which the source should be removed.
+ *
+ * @retval SR_OK Success
+ * @retval SR_ERR_ARG Invalid argument
+ * @retval SR_ERR_MALLOC Memory allocation error.
+ * @retval SR_ERR_BUG Internal error.
+ *
+ * @since 0.3.0
+ */
+SR_API int sr_session_source_remove(int fd)
+{
+	return _sr_session_source_remove((gintptr)fd);
+}
+
+/**
+ * Remove the source belonging to the specified poll descriptor.
+ *
+ * @param pollfd The poll descriptor for which the source should be removed.
+ *
+ * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments, or
+ *         SR_ERR_MALLOC upon memory allocation errors, SR_ERR_BUG upon
+ *         internal errors.
+ *
+ * @since 0.2.0
+ */
+SR_API int sr_session_source_remove_pollfd(GPollFD *pollfd)
+{
+	return _sr_session_source_remove((gintptr)pollfd);
+}
+
+/**
+ * Remove the source belonging to the specified channel.
+ *
+ * @param channel The channel for which the source should be removed.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_ARG Invalid argument.
+ * @retval SR_ERR_MALLOC Memory allocation error.
+ * @return SR_ERR_BUG Internal error.
+ *
+ * @since 0.2.0
+ */
+SR_API int sr_session_source_remove_channel(GIOChannel *channel)
+{
+	return _sr_session_source_remove((gintptr)channel);
+}
+
+/** @} */
diff --git a/session_driver.c b/session_driver.c
new file mode 100644
index 0000000..fe0db3e
--- /dev/null
+++ b/session_driver.c
@@ -0,0 +1,337 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <zip.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "virtual-session"
+
+/* size of payloads sent across the session bus */
+/** @cond PRIVATE */
+#define CHUNKSIZE (512 * 1024)
+/** @endcond */
+
+struct session_vdev {
+	char *sessionfile;
+	char *capturefile;
+	struct zip *archive;
+	struct zip_file *capfile;
+	int bytes_read;
+	uint64_t samplerate;
+	int unitsize;
+	int num_channels;
+	int cur_chunk;
+	gboolean finished;
+};
+
+static GSList *dev_insts = NULL;
+static const int hwcaps[] = {
+	SR_CONF_CAPTUREFILE,
+	SR_CONF_CAPTURE_UNITSIZE,
+	SR_CONF_SAMPLERATE,
+};
+
+static int receive_data(int fd, int revents, void *cb_data)
+{
+	struct sr_dev_inst *sdi;
+	struct session_vdev *vdev;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_logic logic;
+	struct zip_stat zs;
+	GSList *l;
+	int ret, got_data;
+	char capturefile[16];
+	void *buf;
+
+	(void)fd;
+	(void)revents;
+
+	got_data = FALSE;
+	for (l = dev_insts; l; l = l->next) {
+		sdi = l->data;
+		vdev = sdi->priv;
+		if (vdev->finished)
+			/* Already done with this instance. */
+			continue;
+
+		if (!vdev->capfile) {
+			/* No capture file opened yet, or finished with the last
+			 * chunked one. */
+			if (vdev->cur_chunk == 0) {
+				/* capturefile is always the unchunked base name. */
+				if (zip_stat(vdev->archive, vdev->capturefile, 0, &zs) != -1) {
+					/* No chunks, just a single capture file. */
+					vdev->cur_chunk = 0;
+					if (!(vdev->capfile = zip_fopen(vdev->archive,
+							vdev->capturefile, 0)))
+						return FALSE;
+						sr_dbg("Opened %s.", vdev->capturefile);
+				} else {
+					/* Try as first chunk filename. */
+					snprintf(capturefile, 15, "%s-1", vdev->capturefile);
+					if (zip_stat(vdev->archive, capturefile, 0, &zs) != -1) {
+						vdev->cur_chunk = 1;
+						if (!(vdev->capfile = zip_fopen(vdev->archive,
+								capturefile, 0)))
+							return FALSE;
+						sr_dbg("Opened %s.", capturefile);
+					} else {
+						sr_err("No capture file '%s' in " "session file '%s'.",
+								vdev->capturefile, vdev->sessionfile);
+						return FALSE;
+					}
+				}
+			} else {
+				/* Capture data is chunked, advance to the next chunk. */
+				vdev->cur_chunk++;
+				snprintf(capturefile, 15, "%s-%d", vdev->capturefile,
+						vdev->cur_chunk);
+				if (zip_stat(vdev->archive, capturefile, 0, &zs) != -1) {
+					if (!(vdev->capfile = zip_fopen(vdev->archive,
+							capturefile, 0)))
+						return FALSE;
+					sr_dbg("Opened %s.", capturefile);
+				} else {
+					/* We got all the chunks, finish up. */
+					vdev->finished = TRUE;
+					continue;
+				}
+			}
+		}
+
+		if (!(buf = g_try_malloc(CHUNKSIZE))) {
+			sr_err("%s: buf malloc failed", __func__);
+			return FALSE;
+		}
+
+		ret = zip_fread(vdev->capfile, buf,
+				CHUNKSIZE / vdev->unitsize * vdev->unitsize);
+		if (ret > 0) {
+			if (ret % vdev->unitsize != 0)
+				sr_warn("Read size %d not a multiple of the"
+					" unit size %d.", ret, vdev->unitsize);
+			got_data = TRUE;
+			packet.type = SR_DF_LOGIC;
+			packet.payload = &logic;
+			logic.length = ret;
+			logic.unitsize = vdev->unitsize;
+			logic.data = buf;
+			vdev->bytes_read += ret;
+			sr_session_send(cb_data, &packet);
+		} else {
+			/* done with this capture file */
+			zip_fclose(vdev->capfile);
+			vdev->capfile = NULL;
+			if (vdev->cur_chunk == 0) {
+				/* It was the only file. */
+				vdev->finished = TRUE;
+			} else {
+				/* There might be more chunks, so don't fall through
+				 * to the SR_DF_END here. */
+				g_free(buf);
+				return TRUE;
+			}
+		}
+		g_free(buf);
+	}
+
+	if (!got_data) {
+		packet.type = SR_DF_END;
+		sr_session_send(cb_data, &packet);
+		sr_session_source_remove(-1);
+	}
+
+	return TRUE;
+}
+
+/* driver callbacks */
+
+static int init(struct sr_context *sr_ctx)
+{
+	(void)sr_ctx;
+
+	return SR_OK;
+}
+
+static int dev_clear(void)
+{
+	GSList *l;
+
+	for (l = dev_insts; l; l = l->next)
+		sr_dev_inst_free(l->data);
+	g_slist_free(dev_insts);
+	dev_insts = NULL;
+
+	return SR_OK;
+}
+
+static int dev_open(struct sr_dev_inst *sdi)
+{
+	struct session_vdev *vdev;
+
+	vdev = g_try_malloc0(sizeof(struct session_vdev));
+	sdi->priv = vdev;
+	dev_insts = g_slist_append(dev_insts, sdi);
+
+	return SR_OK;
+}
+
+static int dev_close(struct sr_dev_inst *sdi)
+{
+	const struct session_vdev *const vdev = sdi->priv;
+	g_free(vdev->sessionfile);
+	g_free(vdev->capturefile);
+
+	g_free(sdi->priv);
+	sdi->priv = NULL;
+
+	return SR_OK;
+}
+
+static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct session_vdev *vdev;
+
+	(void)cg;
+
+	switch (id) {
+	case SR_CONF_SAMPLERATE:
+		if (sdi) {
+			vdev = sdi->priv;
+			*data = g_variant_new_uint64(vdev->samplerate);
+		} else
+			return SR_ERR;
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_set(int id, GVariant *data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	struct session_vdev *vdev;
+
+	(void)cg;
+
+	vdev = sdi->priv;
+
+	switch (id) {
+	case SR_CONF_SAMPLERATE:
+		vdev->samplerate = g_variant_get_uint64(data);
+		sr_info("Setting samplerate to %" PRIu64 ".", vdev->samplerate);
+		break;
+	case SR_CONF_SESSIONFILE:
+		g_free(vdev->sessionfile);
+		vdev->sessionfile = g_strdup(g_variant_get_string(data, NULL));
+		sr_info("Setting sessionfile to '%s'.", vdev->sessionfile);
+		break;
+	case SR_CONF_CAPTUREFILE:
+		g_free(vdev->capturefile);
+		vdev->capturefile = g_strdup(g_variant_get_string(data, NULL));
+		sr_info("Setting capturefile to '%s'.", vdev->capturefile);
+		break;
+	case SR_CONF_CAPTURE_UNITSIZE:
+		vdev->unitsize = g_variant_get_uint64(data);
+		break;
+	case SR_CONF_NUM_LOGIC_CHANNELS:
+		vdev->num_channels = g_variant_get_uint64(data);
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
+		const struct sr_channel_group *cg)
+{
+	(void)sdi;
+	(void)cg;
+
+	switch (key) {
+	case SR_CONF_DEVICE_OPTIONS:
+		*data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
+				hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
+		break;
+	default:
+		return SR_ERR_NA;
+	}
+
+	return SR_OK;
+}
+
+static int dev_acquisition_start(const struct sr_dev_inst *sdi, void *cb_data)
+{
+	struct session_vdev *vdev;
+	int ret;
+
+	vdev = sdi->priv;
+
+	vdev->bytes_read = 0;
+	vdev->cur_chunk = 0;
+	vdev->finished = FALSE;
+
+	sr_info("Opening archive %s file %s", vdev->sessionfile,
+		vdev->capturefile);
+
+	if (!(vdev->archive = zip_open(vdev->sessionfile, 0, &ret))) {
+		sr_err("Failed to open session file '%s': "
+		       "zip error %d.", vdev->sessionfile, ret);
+		return SR_ERR;
+	}
+
+	/* Send header packet to the session bus. */
+	std_session_send_df_header(cb_data, LOG_PREFIX);
+
+	/* freewheeling source */
+	sr_session_source_add(-1, 0, 0, receive_data, cb_data);
+
+	return SR_OK;
+}
+
+/** @private */
+SR_PRIV struct sr_dev_driver session_driver = {
+	.name = "virtual-session",
+	.longname = "Session-emulating driver",
+	.api_version = 1,
+	.init = init,
+	.cleanup = dev_clear,
+	.scan = NULL,
+	.dev_list = NULL,
+	.dev_clear = dev_clear,
+	.config_get = config_get,
+	.config_set = config_set,
+	.config_list = config_list,
+	.dev_open = dev_open,
+	.dev_close = dev_close,
+	.dev_acquisition_start = dev_acquisition_start,
+	.dev_acquisition_stop = NULL,
+	.priv = NULL,
+};
diff --git a/session_file.c b/session_file.c
new file mode 100644
index 0000000..880ef6d
--- /dev/null
+++ b/session_file.c
@@ -0,0 +1,504 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <zip.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include "config.h" /* Needed for PACKAGE_VERSION and others. */
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+/** @cond PRIVATE */
+#define LOG_PREFIX "session-file"
+/** @endcond */
+
+/**
+ * @file
+ *
+ * Loading and saving libsigrok session files.
+ */
+
+/**
+ * @addtogroup grp_session
+ *
+ * @{
+ */
+
+extern struct sr_session *session;
+extern SR_PRIV struct sr_dev_driver session_driver;
+
+/** @private */
+SR_PRIV int sr_sessionfile_check(const char *filename)
+{
+	struct stat st;
+	struct zip *archive;
+	struct zip_file *zf;
+	struct zip_stat zs;
+	int version, ret;
+	char s[11];
+
+	if (!filename)
+		return SR_ERR_ARG;
+
+	if (stat(filename, &st) == -1) {
+		sr_err("Couldn't stat %s: %s", filename, strerror(errno));
+		return SR_ERR;
+	}
+
+	if (!(archive = zip_open(filename, 0, &ret)))
+		/* No logging: this can be used just to check if it's
+		 * a sigrok session file or not. */
+		return SR_ERR;
+
+	/* check "version" */
+	version = 0;
+	if (!(zf = zip_fopen(archive, "version", 0))) {
+		sr_dbg("Not a sigrok session file: no version found.");
+		return SR_ERR;
+	}
+	if ((ret = zip_fread(zf, s, 10)) == -1)
+		return SR_ERR;
+	zip_fclose(zf);
+	s[ret] = 0;
+	version = strtoull(s, NULL, 10);
+	if (version > 2) {
+		sr_dbg("Cannot handle sigrok session file version %d.", version);
+		return SR_ERR;
+	}
+	sr_spew("Detected sigrok session file version %d.", version);
+
+	/* read "metadata" */
+	if (zip_stat(archive, "metadata", 0, &zs) == -1) {
+		sr_dbg("Not a valid sigrok session file.");
+		return SR_ERR;
+	}
+
+	return SR_OK;
+}
+
+/**
+ * Load the session from the specified filename.
+ *
+ * @param filename The name of the session file to load. Must not be NULL.
+ *
+ * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments,
+ *         SR_ERR_MALLOC upon memory allocation errors, or SR_ERR upon
+ *         other errors.
+ */
+SR_API int sr_session_load(const char *filename)
+{
+	GKeyFile *kf;
+	GPtrArray *capturefiles;
+	struct zip *archive;
+	struct zip_file *zf;
+	struct zip_stat zs;
+	struct sr_dev_inst *sdi;
+	struct sr_channel *ch;
+	int ret, channelnum, devcnt, i, j;
+	uint64_t tmp_u64, total_channels, enabled_channels, p;
+	char **sections, **keys, *metafile, *val;
+	char channelname[SR_MAX_CHANNELNAME_LEN + 1];
+
+	if ((ret = sr_sessionfile_check(filename)) != SR_OK)
+		return ret;
+
+	if (!(archive = zip_open(filename, 0, &ret)))
+		return SR_ERR;
+
+	if (zip_stat(archive, "metadata", 0, &zs) == -1)
+		return SR_ERR;
+
+	if (!(metafile = g_try_malloc(zs.size))) {
+		sr_err("%s: metafile malloc failed", __func__);
+		return SR_ERR_MALLOC;
+	}
+
+	zf = zip_fopen_index(archive, zs.index, 0);
+	zip_fread(zf, metafile, zs.size);
+	zip_fclose(zf);
+
+	kf = g_key_file_new();
+	if (!g_key_file_load_from_data(kf, metafile, zs.size, 0, NULL)) {
+		sr_dbg("Failed to parse metadata.");
+		return SR_ERR;
+	}
+
+	sr_session_new();
+
+	devcnt = 0;
+	capturefiles = g_ptr_array_new_with_free_func(g_free);
+	sections = g_key_file_get_groups(kf, NULL);
+	for (i = 0; sections[i]; i++) {
+		if (!strcmp(sections[i], "global"))
+			/* nothing really interesting in here yet */
+			continue;
+		if (!strncmp(sections[i], "device ", 7)) {
+			/* device section */
+			sdi = NULL;
+			enabled_channels = total_channels = 0;
+			keys = g_key_file_get_keys(kf, sections[i], NULL, NULL);
+			for (j = 0; keys[j]; j++) {
+				val = g_key_file_get_string(kf, sections[i], keys[j], NULL);
+				if (!strcmp(keys[j], "capturefile")) {
+					sdi = sr_dev_inst_new(devcnt, SR_ST_ACTIVE, NULL, NULL, NULL);
+					sdi->driver = &session_driver;
+					if (devcnt == 0)
+						/* first device, init the driver */
+						sdi->driver->init(NULL);
+					sr_dev_open(sdi);
+					sr_session_dev_add(sdi);
+					sdi->driver->config_set(SR_CONF_SESSIONFILE,
+							g_variant_new_string(filename), sdi, NULL);
+					sdi->driver->config_set(SR_CONF_CAPTUREFILE,
+							g_variant_new_string(val), sdi, NULL);
+					g_ptr_array_add(capturefiles, val);
+				} else if (!strcmp(keys[j], "samplerate")) {
+					sr_parse_sizestring(val, &tmp_u64);
+					sdi->driver->config_set(SR_CONF_SAMPLERATE,
+							g_variant_new_uint64(tmp_u64), sdi, NULL);
+				} else if (!strcmp(keys[j], "unitsize")) {
+					tmp_u64 = strtoull(val, NULL, 10);
+					sdi->driver->config_set(SR_CONF_CAPTURE_UNITSIZE,
+							g_variant_new_uint64(tmp_u64), sdi, NULL);
+				} else if (!strcmp(keys[j], "total probes")) {
+					total_channels = strtoull(val, NULL, 10);
+					sdi->driver->config_set(SR_CONF_NUM_LOGIC_CHANNELS,
+							g_variant_new_uint64(total_channels), sdi, NULL);
+					for (p = 0; p < total_channels; p++) {
+						snprintf(channelname, SR_MAX_CHANNELNAME_LEN, "%" PRIu64, p);
+						if (!(ch = sr_channel_new(p, SR_CHANNEL_LOGIC, TRUE,
+								channelname)))
+							return SR_ERR;
+						sdi->channels = g_slist_append(sdi->channels, ch);
+					}
+				} else if (!strncmp(keys[j], "probe", 5)) {
+					if (!sdi)
+						continue;
+					enabled_channels++;
+					tmp_u64 = strtoul(keys[j]+5, NULL, 10);
+					/* sr_session_save() */
+					sr_dev_channel_name_set(sdi, tmp_u64 - 1, val);
+				} else if (!strncmp(keys[j], "trigger", 7)) {
+					channelnum = strtoul(keys[j]+7, NULL, 10);
+					sr_dev_trigger_set(sdi, channelnum, val);
+				}
+			}
+			g_strfreev(keys);
+			/* Disable channels not specifically listed. */
+			if (total_channels)
+				for (p = enabled_channels; p < total_channels; p++)
+					sr_dev_channel_enable(sdi, p, FALSE);
+		}
+		devcnt++;
+	}
+	g_strfreev(sections);
+	g_key_file_free(kf);
+
+	return SR_OK;
+}
+
+/**
+ * Save the current session to the specified file.
+ *
+ * @param filename The name of the filename to save the current session as.
+ *                 Must not be NULL.
+ * @param sdi The device instance from which the data was captured.
+ * @param buf The data to be saved.
+ * @param unitsize The number of bytes per sample.
+ * @param units The number of samples.
+ *
+ * @retval SR_OK Success
+ * @retval SR_ERR_ARG Invalid arguments
+ * @retval SR_ERR Other errors
+ *
+ * @since 0.2.0
+ */
+SR_API int sr_session_save(const char *filename, const struct sr_dev_inst *sdi,
+		unsigned char *buf, int unitsize, int units)
+{
+	struct sr_channel *ch;
+	GSList *l;
+	GVariant *gvar;
+	uint64_t samplerate;
+	int cnt, ret;
+	char **channel_names;
+
+	samplerate = 0;
+	if (sr_dev_has_option(sdi, SR_CONF_SAMPLERATE)) {
+		if (sr_config_get(sdi->driver, sdi, NULL,
+					SR_CONF_SAMPLERATE, &gvar) == SR_OK) {
+			samplerate = g_variant_get_uint64(gvar);
+			g_variant_unref(gvar);
+		}
+	}
+
+	channel_names = g_malloc0(sizeof(char *) * (g_slist_length(sdi->channels) + 1));
+	cnt = 0;
+	for (l = sdi->channels; l; l = l->next) {
+		ch = l->data;
+		if (ch->type != SR_CHANNEL_LOGIC)
+			continue;
+		if (ch->enabled != TRUE)
+			continue;
+		if (!ch->name)
+			continue;
+		/* Just borrowing the ptr. */
+		channel_names[cnt++] = ch->name;
+	}
+
+	if ((ret = sr_session_save_init(filename, samplerate, channel_names)) != SR_OK)
+		return ret;
+
+	ret = sr_session_append(filename, buf, unitsize, units);
+
+	return ret;
+}
+
+/**
+ * Initialize a saved session file.
+ *
+ * @param filename The name of the filename to save the current session as.
+ *                 Must not be NULL.
+ * @param samplerate The samplerate to store for this session.
+ * @param channels A NULL-terminated array of strings containing the names
+ * of all the channels active in this session.
+ *
+ * @retval SR_OK Success
+ * @retval SR_ERR_ARG Invalid arguments
+ * @retval SR_ERR Other errors
+ *
+ * @since 0.3.0
+ */
+SR_API int sr_session_save_init(const char *filename, uint64_t samplerate,
+		char **channels)
+{
+	FILE *meta;
+	struct zip *zipfile;
+	struct zip_source *versrc, *metasrc;
+	int tmpfile, cnt, ret, i;
+	char version[1], metafile[32], *s;
+
+	if (!filename) {
+		sr_err("%s: filename was NULL", __func__);
+		return SR_ERR_ARG;
+	}
+
+	/* Quietly delete it first, libzip wants replace ops otherwise. */
+	unlink(filename);
+	if (!(zipfile = zip_open(filename, ZIP_CREATE, &ret)))
+		return SR_ERR;
+
+	/* "version" */
+	version[0] = '2';
+	if (!(versrc = zip_source_buffer(zipfile, version, 1, 0)))
+		return SR_ERR;
+	if (zip_add(zipfile, "version", versrc) == -1) {
+		sr_info("error saving version into zipfile: %s",
+			zip_strerror(zipfile));
+		return SR_ERR;
+	}
+
+	/* init "metadata" */
+	strcpy(metafile, "sigrok-meta-XXXXXX");
+	if ((tmpfile = g_mkstemp(metafile)) == -1)
+		return SR_ERR;
+	close(tmpfile);
+	meta = g_fopen(metafile, "wb");
+	fprintf(meta, "[global]\n");
+	fprintf(meta, "sigrok version = %s\n", PACKAGE_VERSION);
+
+	/* metadata */
+	fprintf(meta, "[device 1]\n");
+
+	/* metadata */
+	fprintf(meta, "capturefile = logic-1\n");
+	cnt = 0;
+	for (i = 0; channels[i]; i++)
+		cnt++;
+	fprintf(meta, "total probes = %d\n", cnt);
+	s = sr_samplerate_string(samplerate);
+	fprintf(meta, "samplerate = %s\n", s);
+	g_free(s);
+
+	for (i = 0; channels[i]; i++)
+		fprintf(meta, "probe%d = %s\n", i + 1, channels[i]);
+
+	fclose(meta);
+
+	if (!(metasrc = zip_source_file(zipfile, metafile, 0, -1))) {
+		unlink(metafile);
+		return SR_ERR;
+	}
+	if (zip_add(zipfile, "metadata", metasrc) == -1) {
+		unlink(metafile);
+		return SR_ERR;
+	}
+
+	if ((ret = zip_close(zipfile)) == -1) {
+		sr_info("error saving zipfile: %s", zip_strerror(zipfile));
+		unlink(metafile);
+		return SR_ERR;
+	}
+
+	unlink(metafile);
+
+	return SR_OK;
+}
+
+/**
+ * Append data to an existing session file.
+ *
+ * The session file must have been created with sr_session_save_init()
+ * or sr_session_save() beforehand.
+ *
+ * @param filename The name of the filename to append to. Must not be NULL.
+ * @param buf The data to be appended.
+ * @param unitsize The number of bytes per sample.
+ * @param units The number of samples.
+ *
+ * @retval SR_OK Success
+ * @retval SR_ERR_ARG Invalid arguments
+ * @retval SR_ERR Other errors
+ *
+ * @since 0.3.0
+ */
+SR_API int sr_session_append(const char *filename, unsigned char *buf,
+		int unitsize, int units)
+{
+	struct zip *archive;
+	struct zip_source *logicsrc;
+	zip_int64_t num_files;
+	struct zip_file *zf;
+	struct zip_stat zs;
+	struct zip_source *metasrc;
+	GKeyFile *kf;
+	GError *error;
+	gsize len;
+	int chunk_num, next_chunk_num, tmpfile, ret, i;
+	const char *entry_name;
+	char *metafile, tmpname[32], chunkname[16];
+
+	if ((ret = sr_sessionfile_check(filename)) != SR_OK)
+		return ret;
+
+	if (!(archive = zip_open(filename, 0, &ret)))
+		return SR_ERR;
+
+	if (zip_stat(archive, "metadata", 0, &zs) == -1)
+		return SR_ERR;
+
+	metafile = g_malloc(zs.size);
+	zf = zip_fopen_index(archive, zs.index, 0);
+	zip_fread(zf, metafile, zs.size);
+	zip_fclose(zf);
+
+	/*
+	 * If the file was only initialized but doesn't yet have any
+	 * data it in, it won't have a unitsize field in metadata yet.
+	 */
+	error = NULL;
+	kf = g_key_file_new();
+	if (!g_key_file_load_from_data(kf, metafile, zs.size, 0, &error)) {
+		sr_err("Failed to parse metadata: %s.", error->message);
+		return SR_ERR;
+	}
+	g_free(metafile);
+	tmpname[0] = '\0';
+	if (!g_key_file_has_key(kf, "device 1", "unitsize", &error)) {
+		if (error && error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
+			sr_err("Failed to check unitsize key: %s", error ? error->message : "?");
+			return SR_ERR;
+		}
+		/* Add unitsize field. */
+		g_key_file_set_integer(kf, "device 1", "unitsize", unitsize);
+		metafile = g_key_file_to_data(kf, &len, &error);
+		strcpy(tmpname, "sigrok-meta-XXXXXX");
+		if ((tmpfile = g_mkstemp(tmpname)) == -1)
+			return SR_ERR;
+		if (write(tmpfile, metafile, len) < 0) {
+			sr_dbg("Failed to create new metadata: %s", strerror(errno));
+			g_free(metafile);
+			unlink(tmpname);
+			return SR_ERR;
+		}
+		close(tmpfile);
+		if (!(metasrc = zip_source_file(archive, tmpname, 0, -1))) {
+			sr_err("Failed to create zip source for metadata.");
+			g_free(metafile);
+			unlink(tmpname);
+			return SR_ERR;
+		}
+		if (zip_replace(archive, zs.index, metasrc) == -1) {
+			sr_err("Failed to replace metadata file.");
+			g_free(metafile);
+			unlink(tmpname);
+			return SR_ERR;
+		}
+		g_free(metafile);
+	}
+	g_key_file_free(kf);
+
+	next_chunk_num = 1;
+	num_files = zip_get_num_entries(archive, 0);
+	for (i = 0; i < num_files; i++) {
+		entry_name = zip_get_name(archive, i, 0);
+		if (strncmp(entry_name, "logic-1", 7))
+			continue;
+		if (strlen(entry_name) == 7) {
+			/* This file has no extra chunks, just a single "logic-1".
+			 * Rename it to "logic-1-1" * and continue with chunk 2. */
+			if (zip_rename(archive, i, "logic-1-1") == -1) {
+				sr_err("Failed to rename 'logic-1' to 'logic-1-1'.");
+				unlink(tmpname);
+				return SR_ERR;
+			}
+			next_chunk_num = 2;
+			break;
+		} else if (strlen(entry_name) > 8 && entry_name[7] == '-') {
+			chunk_num = strtoull(entry_name + 8, NULL, 10);
+			if (chunk_num >= next_chunk_num)
+				next_chunk_num = chunk_num + 1;
+		}
+	}
+	snprintf(chunkname, 15, "logic-1-%d", next_chunk_num);
+	if (!(logicsrc = zip_source_buffer(archive, buf, units * unitsize, FALSE))) {
+		unlink(tmpname);
+		return SR_ERR;
+	}
+	if (zip_add(archive, chunkname, logicsrc) == -1) {
+		unlink(tmpname);
+		return SR_ERR;
+	}
+	if ((ret = zip_close(archive)) == -1) {
+		sr_info("error saving session file: %s", zip_strerror(archive));
+		unlink(tmpname);
+		return SR_ERR;
+	}
+	unlink(tmpname);
+
+	return SR_OK;
+}
+
+/** @} */
diff --git a/std.c b/std.c
new file mode 100644
index 0000000..1b9c600
--- /dev/null
+++ b/std.c
@@ -0,0 +1,291 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+/** @file
+  * Standard API helper functions.
+  * @internal
+  */
+
+#include <glib.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+#define LOG_PREFIX "std"
+
+/**
+ * Standard sr_driver_init() API helper.
+ *
+ * This function can be used to simplify most driver's init() API callback.
+ *
+ * It creates a new 'struct drv_context' (drvc), assigns sr_ctx to it, and
+ * then 'drvc' is assigned to the 'struct sr_dev_driver' (di) that is passed.
+ *
+ * @param sr_ctx The libsigrok context to assign.
+ * @param di The driver instance to use.
+ * @param[in] prefix A driver-specific prefix string used for log messages.
+ *
+ * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments, or
+ *         SR_ERR_MALLOC upon memory allocation errors.
+ */
+SR_PRIV int std_init(struct sr_context *sr_ctx, struct sr_dev_driver *di,
+		     const char *prefix)
+{
+	struct drv_context *drvc;
+
+	if (!di) {
+		sr_err("%s: Invalid driver, cannot initialize.", prefix);
+		return SR_ERR_ARG;
+	}
+
+	if (!(drvc = g_try_malloc(sizeof(struct drv_context)))) {
+		sr_err("%s: Driver context malloc failed.", prefix);
+		return SR_ERR_MALLOC;
+	}
+
+	drvc->sr_ctx = sr_ctx;
+	drvc->instances = NULL;
+	di->priv = drvc;
+
+	return SR_OK;
+}
+
+/**
+ * Standard API helper for sending an SR_DF_HEADER packet.
+ *
+ * This function can be used to simplify most driver's
+ * dev_acquisition_start() API callback.
+ *
+ * @param sdi The device instance to use.
+ * @param prefix A driver-specific prefix string used for log messages.
+ * 		 Must not be NULL. An empty string is allowed.
+ *
+ * @return SR_OK upon success, SR_ERR_ARG upon invalid arguments, or
+ *         SR_ERR upon other errors.
+ */
+SR_PRIV int std_session_send_df_header(const struct sr_dev_inst *sdi,
+				       const char *prefix)
+{
+	int ret;
+	struct sr_datafeed_packet packet;
+	struct sr_datafeed_header header;
+
+	if (!prefix) {
+		sr_err("Invalid prefix.");
+		return SR_ERR_ARG;
+	}
+
+	sr_dbg("%s: Starting acquisition.", prefix);
+
+	/* Send header packet to the session bus. */
+	sr_dbg("%s: Sending SR_DF_HEADER packet.", prefix);
+	packet.type = SR_DF_HEADER;
+	packet.payload = (uint8_t *)&header;
+	header.feed_version = 1;
+	gettimeofday(&header.starttime, NULL);
+
+	if ((ret = sr_session_send(sdi, &packet)) < 0) {
+		sr_err("%s: Failed to send header packet: %d.", prefix, ret);
+		return ret;
+	}
+
+	return SR_OK;
+}
+
+#ifdef HAVE_LIBSERIALPORT
+
+/**
+ * Standard serial driver dev_open() helper.
+ *
+ * This function can be used to implement the dev_open() driver API
+ * callback in drivers that use a serial port. The port is opened
+ * with the SERIAL_RDWR and SERIAL_NONBLOCK flags.
+ *
+ * If the open succeeded, the status field of the given sdi is set
+ * to SR_ST_ACTIVE.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR Serial port open failed.
+ */
+SR_PRIV int std_serial_dev_open(struct sr_dev_inst *sdi)
+{
+	struct sr_serial_dev_inst *serial;
+
+	serial = sdi->conn;
+	if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+		return SR_ERR;
+
+	sdi->status = SR_ST_ACTIVE;
+
+	return SR_OK;
+}
+
+/**
+ * Standard serial driver dev_close() helper.
+ *
+ * This function can be used to implement the dev_close() driver API
+ * callback in drivers that use a serial port.
+ *
+ * After closing the port, the status field of the given sdi is set
+ * to SR_ST_INACTIVE.
+ *
+ * @retval SR_OK Success.
+ */
+SR_PRIV int std_serial_dev_close(struct sr_dev_inst *sdi)
+{
+	struct sr_serial_dev_inst *serial;
+
+	serial = sdi->conn;
+	if (serial && sdi->status == SR_ST_ACTIVE) {
+		serial_close(serial);
+		sdi->status = SR_ST_INACTIVE;
+	}
+
+	return SR_OK;
+}
+
+/**
+ * Standard sr_session_stop() API helper.
+ *
+ * This function can be used to simplify most (serial port based) driver's
+ * dev_acquisition_stop() API callback.
+ *
+ * @param sdi The device instance for which acquisition should stop.
+ *            Must not be NULL.
+ * @param cb_data Opaque 'cb_data' pointer. Must not be NULL.
+ * @param dev_close_fn Function pointer to the driver's dev_close().
+ *               	  Must not be NULL.
+ * @param serial The serial device instance (struct serial_dev_inst *).
+ *               Must not be NULL.
+ * @param[in] prefix A driver-specific prefix string used for log messages.
+ *               Must not be NULL. An empty string is allowed.
+ *
+ * @retval SR_OK Success.
+ * @retval SR_ERR_ARG Invalid arguments.
+ * @retval SR_ERR_DEV_CLOSED Device is closed.
+ * @retval SR_ERR Other errors.
+ */
+SR_PRIV int std_serial_dev_acquisition_stop(struct sr_dev_inst *sdi,
+			void *cb_data, dev_close_callback dev_close_fn,
+			struct sr_serial_dev_inst *serial, const char *prefix)
+{
+	int ret;
+	struct sr_datafeed_packet packet;
+
+	if (!prefix) {
+		sr_err("Invalid prefix.");
+		return SR_ERR_ARG;
+	}
+
+	if (sdi->status != SR_ST_ACTIVE) {
+		sr_err("%s: Device inactive, can't stop acquisition.", prefix);
+		return SR_ERR_DEV_CLOSED;
+	}
+
+	sr_dbg("%s: Stopping acquisition.", prefix);
+
+	if ((ret = serial_source_remove(serial)) < 0) {
+		sr_err("%s: Failed to remove source: %d.", prefix, ret);
+		return ret;
+	}
+
+	if ((ret = dev_close_fn(sdi)) < 0) {
+		sr_err("%s: Failed to close device: %d.", prefix, ret);
+		return ret;
+	}
+
+	/* Send SR_DF_END packet to the session bus. */
+	sr_dbg("%s: Sending SR_DF_END packet.", prefix);
+	packet.type = SR_DF_END;
+	packet.payload = NULL;
+	if ((ret = sr_session_send(cb_data, &packet)) < 0) {
+		sr_err("%s: Failed to send SR_DF_END packet: %d.", prefix, ret);
+		return ret;
+	}
+
+	return SR_OK;
+}
+
+#endif
+
+/**
+ * Standard driver dev_clear() helper.
+ *
+ * Clear driver, this means, close all instances.
+ *
+ * This function can be used to implement the dev_clear() driver API
+ * callback. dev_close() is called before every sr_dev_inst is cleared.
+ *
+ * The only limitation is driver-specific device contexts (sdi->priv).
+ * These are freed, but any dynamic allocation within structs stored
+ * there cannot be freed.
+ *
+ * @param driver The driver which will have its instances released.
+ * @param clear_private If not NULL, this points to a function called
+ * with sdi->priv as argument. The function can then clear any device
+ * instance-specific resources kept there. It must also clear the struct
+ * pointed to by sdi->priv.
+ *
+ * @return SR_OK on success.
+ */
+SR_PRIV int std_dev_clear(const struct sr_dev_driver *driver,
+		std_dev_clear_callback clear_private)
+{
+	struct drv_context *drvc;
+	struct sr_dev_inst *sdi;
+	GSList *l;
+	int ret;
+
+	if (!(drvc = driver->priv))
+		/* Driver was never initialized, nothing to do. */
+		return SR_OK;
+
+	ret = SR_OK;
+	for (l = drvc->instances; l; l = l->next) {
+		if (!(sdi = l->data)) {
+			ret = SR_ERR_BUG;
+			continue;
+		}
+		if (driver->dev_close)
+			driver->dev_close(sdi);
+
+		if (sdi->conn) {
+#ifdef HAVE_LIBSERIALPORT
+			if (sdi->inst_type == SR_INST_SERIAL)
+				sr_serial_dev_inst_free(sdi->conn);
+#endif
+#ifdef HAVE_LIBUSB_1_0
+			if (sdi->inst_type == SR_INST_USB)
+				sr_usb_dev_inst_free(sdi->conn);
+#endif
+			if (sdi->inst_type == SR_INST_SCPI)
+				sr_scpi_free(sdi->conn);
+		}
+		if (clear_private)
+			clear_private(sdi->priv);
+		else
+			g_free(sdi->priv);
+		sr_dev_inst_free(sdi);
+	}
+
+	g_slist_free(drvc->instances);
+	drvc->instances = NULL;
+
+	return ret;
+}
diff --git a/strutil.c b/strutil.c
new file mode 100644
index 0000000..e63f12e
--- /dev/null
+++ b/strutil.c
@@ -0,0 +1,644 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "libsigrok.h"
+#include "libsigrok-internal.h"
+
+/** @cond PRIVATE */
+#define LOG_PREFIX "strutil"
+/** @endcond */
+
+/**
+ * @file
+ *
+ * Helper functions for handling or converting libsigrok-related strings.
+ */
+
+/**
+ * @defgroup grp_strutil String utilities
+ *
+ * Helper functions for handling or converting libsigrok-related strings.
+ *
+ * @{
+ */
+
+/**
+ * @private
+ *
+ * Convert a string representation of a numeric value to a long integer. The
+ * conversion is strict and will fail if the complete string does not represent
+ * a valid long integer. The function sets errno according to the details of the
+ * failure.
+ *
+ * @param str The string representation to convert.
+ * @param ret Pointer to long where the result of the conversion will be stored.
+ *
+ * @return SR_OK if conversion is successful, otherwise SR_ERR.
+ *
+ * @since 0.3.0
+ */
+SR_PRIV int sr_atol(const char *str, long *ret)
+{
+	long tmp;
+	char *endptr = NULL;
+
+	errno = 0;
+	tmp = strtol(str, &endptr, 0);
+
+	if (!endptr || *endptr || errno) {
+		if (!errno)
+			errno = EINVAL;
+		return SR_ERR;
+	}
+
+	*ret = tmp;
+	return SR_OK;
+}
+
+/**
+ * @private
+ *
+ * Convert a string representation of a numeric value to an integer. The
+ * conversion is strict and will fail if the complete string does not represent
+ * a valid integer. The function sets errno according to the details of the
+ * failure.
+ *
+ * @param str The string representation to convert.
+ * @param ret Pointer to int where the result of the conversion will be stored.
+ *
+ * @return SR_OK if conversion is successful, otherwise SR_ERR.
+ *
+ * @since 0.3.0
+ */
+SR_PRIV int sr_atoi(const char *str, int *ret)
+{
+	long tmp;
+
+	if (sr_atol(str, &tmp) != SR_OK)
+		return SR_ERR;
+
+	if ((int) tmp != tmp) {
+		errno = ERANGE;
+		return SR_ERR;
+	}
+
+	*ret = (int) tmp;
+	return SR_OK;
+}
+
+/**
+ * @private
+ *
+ * Convert a string representation of a numeric value to a double. The
+ * conversion is strict and will fail if the complete string does not represent
+ * a valid double. The function sets errno according to the details of the
+ * failure.
+ *
+ * @param str The string representation to convert.
+ * @param ret Pointer to double where the result of the conversion will be stored.
+ *
+ * @return SR_OK if conversion is successful, otherwise SR_ERR.
+ *
+ * @since 0.3.0
+ */
+SR_PRIV int sr_atod(const char *str, double *ret)
+{
+	double tmp;
+	char *endptr = NULL;
+
+	errno = 0;
+	tmp = strtof(str, &endptr);
+
+	if (!endptr || *endptr || errno) {
+		if (!errno)
+			errno = EINVAL;
+		return SR_ERR;
+	}
+
+	*ret = tmp;
+	return SR_OK;
+}
+
+/**
+ * @private
+ *
+ * Convert a string representation of a numeric value to a float. The
+ * conversion is strict and will fail if the complete string does not represent
+ * a valid float. The function sets errno according to the details of the
+ * failure.
+ *
+ * @param str The string representation to convert.
+ * @param ret Pointer to float where the result of the conversion will be stored.
+ *
+ * @return SR_OK if conversion is successful, otherwise SR_ERR.
+ *
+ * @since 0.3.0
+ */
+SR_PRIV int sr_atof(const char *str, float *ret)
+{
+	double tmp;
+
+	if (sr_atod(str, &tmp) != SR_OK)
+		return SR_ERR;
+
+	if ((float) tmp != tmp) {
+		errno = ERANGE;
+		return SR_ERR;
+	}
+
+	*ret = (float) tmp;
+	return SR_OK;
+}
+
+/**
+ * @private
+ *
+ * Convert a string representation of a numeric value to a float. The
+ * conversion is strict and will fail if the complete string does not represent
+ * a valid float. The function sets errno according to the details of the
+ * failure. This version ignores the locale.
+ *
+ * @param str The string representation to convert.
+ * @param ret Pointer to float where the result of the conversion will be stored.
+ *
+ * @return SR_OK if conversion is successful, otherwise SR_ERR.
+ *
+ * @since 0.3.0
+ */
+SR_PRIV int sr_atof_ascii(const char *str, float *ret)
+{
+	double tmp;
+	char *endptr = NULL;
+
+	errno = 0;
+	tmp = g_ascii_strtod(str, &endptr);
+
+	if (!endptr || *endptr || errno) {
+		if (!errno)
+			errno = EINVAL;
+		return SR_ERR;
+	}
+
+	/* FIXME This fails unexpectedly. Some other method to safel downcast
+	 * needs to be found. Checking against FLT_MAX doesn't work as well. */
+	/*
+	if ((float) tmp != tmp) {
+		errno = ERANGE;
+		sr_dbg("ERANGEEEE %e != %e", (float) tmp, tmp);
+		return SR_ERR;
+	}
+	*/
+
+	*ret = (float) tmp;
+	return SR_OK;
+}
+
+/**
+ * Convert a numeric value value to its "natural" string representation
+ * in SI units.
+ *
+ * E.g. a value of 3000000, with units set to "W", would be converted
+ * to "3 MW", 20000 to "20 kW", 31500 would become "31.5 kW".
+ *
+ * @param x The value to convert.
+ * @param unit The unit to append to the string, or NULL if the string
+ *             has no units.
+ *
+ * @return A g_try_malloc()ed string representation of the samplerate value,
+ *         or NULL upon errors. The caller is responsible to g_free() the
+ *         memory.
+ *
+ * @since 0.2.0
+ */
+SR_API char *sr_si_string_u64(uint64_t x, const char *unit)
+{
+	uint8_t i;
+	uint64_t quot, divisor[] = {
+		SR_HZ(1), SR_KHZ(1), SR_MHZ(1), SR_GHZ(1),
+		SR_GHZ(1000), SR_GHZ(1000 * 1000), SR_GHZ(1000 * 1000 * 1000),
+	};
+	const char *p, prefix[] = "\0kMGTPE";
+	char fmt[16], fract[20] = "", *f;
+
+	if (unit == NULL)
+		unit = "";
+
+	for (i = 0; (quot = x / divisor[i]) >= 1000; i++);
+
+	if (i) {
+		sprintf(fmt, ".%%0%d"PRIu64, i * 3);
+		f = fract + sprintf(fract, fmt, x % divisor[i]) - 1;
+
+		while (f >= fract && strchr("0.", *f))
+			*f-- = 0;
+	}
+
+	p = prefix + i;
+
+	return g_strdup_printf("%" PRIu64 "%s %.1s%s", quot, fract, p, unit);
+}
+
+/**
+ * Convert a numeric samplerate value to its "natural" string representation.
+ *
+ * E.g. a value of 3000000 would be converted to "3 MHz", 20000 to "20 kHz",
+ * 31500 would become "31.5 kHz".
+ *
+ * @param samplerate The samplerate in Hz.
+ *
+ * @return A g_try_malloc()ed string representation of the samplerate value,
+ *         or NULL upon errors. The caller is responsible to g_free() the
+ *         memory.
+ *
+ * @since 0.1.0
+ */
+SR_API char *sr_samplerate_string(uint64_t samplerate)
+{
+	return sr_si_string_u64(samplerate, "Hz");
+}
+
+/**
+ * Convert a numeric frequency value to the "natural" string representation
+ * of its period.
+ *
+ * E.g. a value of 3000000 would be converted to "3 us", 20000 to "50 ms".
+ *
+ * @param frequency The frequency in Hz.
+ *
+ * @return A g_try_malloc()ed string representation of the frequency value,
+ *         or NULL upon errors. The caller is responsible to g_free() the
+ *         memory.
+ *
+ * @since 0.1.0
+ */
+SR_API char *sr_period_string(uint64_t frequency)
+{
+	char *o;
+	int r;
+
+	/* Allocate enough for a uint64_t as string + " ms". */
+	if (!(o = g_try_malloc0(30 + 1))) {
+		sr_err("%s: o malloc failed", __func__);
+		return NULL;
+	}
+
+	if (frequency >= SR_GHZ(1))
+		r = snprintf(o, 30, "%" PRIu64 " ns", frequency / 1000000000);
+	else if (frequency >= SR_MHZ(1))
+		r = snprintf(o, 30, "%" PRIu64 " us", frequency / 1000000);
+	else if (frequency >= SR_KHZ(1))
+		r = snprintf(o, 30, "%" PRIu64 " ms", frequency / 1000);
+	else
+		r = snprintf(o, 30, "%" PRIu64 " s", frequency);
+
+	if (r < 0) {
+		/* Something went wrong... */
+		g_free(o);
+		return NULL;
+	}
+
+	return o;
+}
+
+/**
+ * Convert a numeric voltage value to the "natural" string representation
+ * of its voltage value. The voltage is specified as a rational number's
+ * numerator and denominator.
+ *
+ * E.g. a value of 300000 would be converted to "300mV", 2 to "2V".
+ *
+ * @param v_p The voltage numerator.
+ * @param v_q The voltage denominator.
+ *
+ * @return A g_try_malloc()ed string representation of the voltage value,
+ *         or NULL upon errors. The caller is responsible to g_free() the
+ *         memory.
+ *
+ * @since 0.2.0
+ */
+SR_API char *sr_voltage_string(uint64_t v_p, uint64_t v_q)
+{
+	int r;
+	char *o;
+
+	if (!(o = g_try_malloc0(30 + 1))) {
+		sr_err("%s: o malloc failed", __func__);
+		return NULL;
+	}
+
+	if (v_q == 1000)
+		r = snprintf(o, 30, "%" PRIu64 "mV", v_p);
+	else if (v_q == 1)
+		r = snprintf(o, 30, "%" PRIu64 "V", v_p);
+	else
+		r = snprintf(o, 30, "%gV", (float)v_p / (float)v_q);
+
+	if (r < 0) {
+		/* Something went wrong... */
+		g_free(o);
+		return NULL;
+	}
+
+	return o;
+}
+
+/**
+ * Parse a trigger specification string.
+ *
+ * @param sdi The device instance for which the trigger specification is
+ *            intended. Must not be NULL. Also, sdi->driver and
+ *            sdi->driver->info_get must not be NULL.
+ * @param triggerstring The string containing the trigger specification for
+ *        one or more channels of this device. Entries for multiple channels are
+ *        comma-separated. Triggers are specified in the form key=value,
+ *        where the key is a channel number (or channel name) and the value is
+ *        the requested trigger type. Valid trigger types currently
+ *        include 'r' (rising edge), 'f' (falling edge), 'c' (any pin value
+ *        change), '0' (low value), or '1' (high value).
+ *        Example: "1=r,sck=f,miso=0,7=c"
+ *
+ * @return Pointer to a list of trigger types (strings), or NULL upon errors.
+ *         The pointer list (if non-NULL) has as many entries as the
+ *         respective device has channels (all physically available channels,
+ *         not just enabled ones). Entries of the list which don't have
+ *         a trigger value set in 'triggerstring' are NULL, the other entries
+ *         contain the respective trigger type which is requested for the
+ *         respective channel (e.g. "r", "c", and so on).
+ *
+ * @since 0.2.0
+ */
+SR_API char **sr_parse_triggerstring(const struct sr_dev_inst *sdi,
+				     const char *triggerstring)
+{
+	GSList *l;
+	GVariant *gvar;
+	struct sr_channel *ch;
+	int max_channels, channelnum, i;
+	char **tokens, **triggerlist, *trigger, *tc;
+	const char *trigger_types;
+	gboolean error;
+
+	max_channels = g_slist_length(sdi->channels);
+	error = FALSE;
+
+	if (!(triggerlist = g_try_malloc0(max_channels * sizeof(char *)))) {
+		sr_err("%s: triggerlist malloc failed", __func__);
+		return NULL;
+	}
+
+	if (sdi->driver->config_list(SR_CONF_TRIGGER_TYPE,
+				&gvar, sdi, NULL) != SR_OK) {
+		sr_err("%s: Device doesn't support any triggers.", __func__);
+		return NULL;
+	}
+	trigger_types = g_variant_get_string(gvar, NULL);
+
+	tokens = g_strsplit(triggerstring, ",", max_channels);
+	for (i = 0; tokens[i]; i++) {
+		channelnum = -1;
+		for (l = sdi->channels; l; l = l->next) {
+			ch = (struct sr_channel *)l->data;
+			if (ch->enabled
+				&& !strncmp(ch->name, tokens[i],
+					strlen(ch->name))) {
+				channelnum = ch->index;
+				break;
+			}
+		}
+
+		if (channelnum < 0 || channelnum >= max_channels) {
+			sr_err("Invalid channel.");
+			error = TRUE;
+			break;
+		}
+
+		if ((trigger = strchr(tokens[i], '='))) {
+			for (tc = ++trigger; *tc; tc++) {
+				if (strchr(trigger_types, *tc) == NULL) {
+					sr_err("Unsupported trigger "
+					       "type '%c'.", *tc);
+					error = TRUE;
+					break;
+				}
+			}
+			if (!error)
+				triggerlist[channelnum] = g_strdup(trigger);
+		}
+	}
+	g_strfreev(tokens);
+	g_variant_unref(gvar);
+
+	if (error) {
+		for (i = 0; i < max_channels; i++)
+			g_free(triggerlist[i]);
+		g_free(triggerlist);
+		triggerlist = NULL;
+	}
+
+	return triggerlist;
+}
+
+/**
+ * Convert a "natural" string representation of a size value to uint64_t.
+ *
+ * E.g. a value of "3k" or "3 K" would be converted to 3000, a value
+ * of "15M" would be converted to 15000000.
+ *
+ * Value representations other than decimal (such as hex or octal) are not
+ * supported. Only 'k' (kilo), 'm' (mega), 'g' (giga) suffixes are supported.
+ * Spaces (but not other whitespace) between value and suffix are allowed.
+ *
+ * @param sizestring A string containing a (decimal) size value.
+ * @param size Pointer to uint64_t which will contain the string's size value.
+ *
+ * @return SR_OK upon success, SR_ERR upon errors.
+ *
+ * @since 0.1.0
+ */
+SR_API int sr_parse_sizestring(const char *sizestring, uint64_t *size)
+{
+	int multiplier, done;
+	double frac_part;
+	char *s;
+
+	*size = strtoull(sizestring, &s, 10);
+	multiplier = 0;
+	frac_part = 0;
+	done = FALSE;
+	while (s && *s && multiplier == 0 && !done) {
+		switch (*s) {
+		case ' ':
+			break;
+		case '.':
+			frac_part = g_ascii_strtod(s, &s);
+			break;
+		case 'k':
+		case 'K':
+			multiplier = SR_KHZ(1);
+			break;
+		case 'm':
+		case 'M':
+			multiplier = SR_MHZ(1);
+			break;
+		case 'g':
+		case 'G':
+			multiplier = SR_GHZ(1);
+			break;
+		default:
+			done = TRUE;
+			s--;
+		}
+		s++;
+	}
+	if (multiplier > 0) {
+		*size *= multiplier;
+		*size += frac_part * multiplier;
+	} else
+		*size += frac_part;
+
+	if (*s && strcasecmp(s, "Hz"))
+		return SR_ERR;
+
+	return SR_OK;
+}
+
+/**
+ * Convert a "natural" string representation of a time value to an
+ * uint64_t value in milliseconds.
+ *
+ * E.g. a value of "3s" or "3 s" would be converted to 3000, a value
+ * of "15ms" would be converted to 15.
+ *
+ * Value representations other than decimal (such as hex or octal) are not
+ * supported. Only lower-case "s" and "ms" time suffixes are supported.
+ * Spaces (but not other whitespace) between value and suffix are allowed.
+ *
+ * @param timestring A string containing a (decimal) time value.
+ * @return The string's time value as uint64_t, in milliseconds.
+ *
+ * @todo Add support for "m" (minutes) and others.
+ * @todo Add support for picoseconds?
+ * @todo Allow both lower-case and upper-case? If no, document it.
+ *
+ * @since 0.1.0
+ */
+SR_API uint64_t sr_parse_timestring(const char *timestring)
+{
+	uint64_t time_msec;
+	char *s;
+
+	/* TODO: Error handling, logging. */
+
+	time_msec = strtoull(timestring, &s, 10);
+	if (time_msec == 0 && s == timestring)
+		return 0;
+
+	if (s && *s) {
+		while (*s == ' ')
+			s++;
+		if (!strcmp(s, "s"))
+			time_msec *= 1000;
+		else if (!strcmp(s, "ms"))
+			; /* redundant */
+		else
+			return 0;
+	}
+
+	return time_msec;
+}
+
+/** @since 0.1.0 */
+SR_API gboolean sr_parse_boolstring(const char *boolstr)
+{
+	if (!boolstr)
+		return FALSE;
+
+	if (!g_ascii_strncasecmp(boolstr, "true", 4) ||
+	    !g_ascii_strncasecmp(boolstr, "yes", 3) ||
+	    !g_ascii_strncasecmp(boolstr, "on", 2) ||
+	    !g_ascii_strncasecmp(boolstr, "1", 1))
+		return TRUE;
+
+	return FALSE;
+}
+
+/** @since 0.2.0 */
+SR_API int sr_parse_period(const char *periodstr, uint64_t *p, uint64_t *q)
+{
+	char *s;
+
+	*p = strtoull(periodstr, &s, 10);
+	if (*p == 0 && s == periodstr)
+		/* No digits found. */
+		return SR_ERR_ARG;
+
+	if (s && *s) {
+		while (*s == ' ')
+			s++;
+		if (!strcmp(s, "fs"))
+			*q = 1000000000000000ULL;
+		else if (!strcmp(s, "ps"))
+			*q = 1000000000000ULL;
+		else if (!strcmp(s, "ns"))
+			*q = 1000000000ULL;
+		else if (!strcmp(s, "us"))
+			*q = 1000000;
+		else if (!strcmp(s, "ms"))
+			*q = 1000;
+		else if (!strcmp(s, "s"))
+			*q = 1;
+		else
+			/* Must have a time suffix. */
+			return SR_ERR_ARG;
+	}
+
+	return SR_OK;
+}
+
+/** @since 0.2.0 */
+SR_API int sr_parse_voltage(const char *voltstr, uint64_t *p, uint64_t *q)
+{
+	char *s;
+
+	*p = strtoull(voltstr, &s, 10);
+	if (*p == 0 && s == voltstr)
+		/* No digits found. */
+		return SR_ERR_ARG;
+
+	if (s && *s) {
+		while (*s == ' ')
+			s++;
+		if (!strcasecmp(s, "mv"))
+			*q = 1000L;
+		else if (!strcasecmp(s, "v"))
+			*q = 1;
+		else
+			/* Must have a base suffix. */
+			return SR_ERR_ARG;
+	}
+
+	return SR_OK;
+}
+
+/** @} */
diff --git a/tests/check_core.c b/tests/check_core.c
new file mode 100644
index 0000000..940afeb
--- /dev/null
+++ b/tests/check_core.c
@@ -0,0 +1,183 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <check.h>
+#include "../libsigrok.h"
+#include "lib.h"
+
+/*
+ * Check various basic init related things.
+ *
+ *  - Check whether an sr_init() call with a proper sr_ctx works.
+ *    If it returns != SR_OK (or segfaults) this test will fail.
+ *    The sr_init() call (among other things) also runs sanity checks on
+ *    all libsigrok hardware drivers and errors out upon issues.
+ *
+ *  - Check whether a subsequent sr_exit() with that sr_ctx works.
+ *    If it returns != SR_OK (or segfaults) this test will fail.
+ */
+START_TEST(test_init_exit)
+{
+	int ret;
+	struct sr_context *sr_ctx;
+
+	ret = sr_init(&sr_ctx);
+	fail_unless(ret == SR_OK, "sr_init() failed: %d.", ret);
+	ret = sr_exit(sr_ctx);
+	fail_unless(ret == SR_OK, "sr_exit() failed: %d.", ret);
+}
+END_TEST
+
+/*
+ * Check whether two nested sr_init() and sr_exit() calls work.
+ * The two functions have two different contexts.
+ * If any function returns != SR_OK (or segfaults) this test will fail.
+ */
+START_TEST(test_init_exit_2)
+{
+	int ret;
+	struct sr_context *sr_ctx1, *sr_ctx2;
+
+	ret = sr_init(&sr_ctx1);
+	fail_unless(ret == SR_OK, "sr_init() 1 failed: %d.", ret);
+	ret = sr_init(&sr_ctx2);
+	fail_unless(ret == SR_OK, "sr_init() 2 failed: %d.", ret);
+	ret = sr_exit(sr_ctx2);
+	fail_unless(ret == SR_OK, "sr_exit() 2 failed: %d.", ret);
+	ret = sr_exit(sr_ctx1);
+	fail_unless(ret == SR_OK, "sr_exit() 1 failed: %d.", ret);
+}
+END_TEST
+
+/*
+ * Same as above, but sr_exit() in the "wrong" order.
+ * This should work fine, it's not a bug to do this.
+ */
+START_TEST(test_init_exit_2_reverse)
+{
+	int ret;
+	struct sr_context *sr_ctx1, *sr_ctx2;
+
+	ret = sr_init(&sr_ctx1);
+	fail_unless(ret == SR_OK, "sr_init() 1 failed: %d.", ret);
+	ret = sr_init(&sr_ctx2);
+	fail_unless(ret == SR_OK, "sr_init() 2 failed: %d.", ret);
+	ret = sr_exit(sr_ctx1);
+	fail_unless(ret == SR_OK, "sr_exit() 1 failed: %d.", ret);
+	ret = sr_exit(sr_ctx2);
+	fail_unless(ret == SR_OK, "sr_exit() 2 failed: %d.", ret);
+}
+END_TEST
+
+/*
+ * Check whether three nested sr_init() and sr_exit() calls work.
+ * The three functions have three different contexts.
+ * If any function returns != SR_OK (or segfaults) this test will fail.
+ */
+START_TEST(test_init_exit_3)
+{
+	int ret;
+	struct sr_context *sr_ctx1, *sr_ctx2, *sr_ctx3;
+
+	ret = sr_init(&sr_ctx1);
+	fail_unless(ret == SR_OK, "sr_init() 1 failed: %d.", ret);
+	ret = sr_init(&sr_ctx2);
+	fail_unless(ret == SR_OK, "sr_init() 2 failed: %d.", ret);
+	ret = sr_init(&sr_ctx3);
+	fail_unless(ret == SR_OK, "sr_init() 3 failed: %d.", ret);
+	ret = sr_exit(sr_ctx3);
+	fail_unless(ret == SR_OK, "sr_exit() 3 failed: %d.", ret);
+	ret = sr_exit(sr_ctx2);
+	fail_unless(ret == SR_OK, "sr_exit() 2 failed: %d.", ret);
+	ret = sr_exit(sr_ctx1);
+	fail_unless(ret == SR_OK, "sr_exit() 1 failed: %d.", ret);
+}
+END_TEST
+
+/*
+ * Same as above, but sr_exit() in the "wrong" order.
+ * This should work fine, it's not a bug to do this.
+ */
+START_TEST(test_init_exit_3_reverse)
+{
+	int ret;
+	struct sr_context *sr_ctx1, *sr_ctx2, *sr_ctx3;
+
+	ret = sr_init(&sr_ctx1);
+	fail_unless(ret == SR_OK, "sr_init() 1 failed: %d.", ret);
+	ret = sr_init(&sr_ctx2);
+	fail_unless(ret == SR_OK, "sr_init() 2 failed: %d.", ret);
+	ret = sr_init(&sr_ctx3);
+	fail_unless(ret == SR_OK, "sr_init() 3 failed: %d.", ret);
+	ret = sr_exit(sr_ctx1);
+	fail_unless(ret == SR_OK, "sr_exit() 1 failed: %d.", ret);
+	ret = sr_exit(sr_ctx2);
+	fail_unless(ret == SR_OK, "sr_exit() 2 failed: %d.", ret);
+	ret = sr_exit(sr_ctx3);
+	fail_unless(ret == SR_OK, "sr_exit() 3 failed: %d.", ret);
+}
+END_TEST
+
+/* Check whether sr_init(NULL) fails as it should. */
+START_TEST(test_init_null)
+{
+	int ret;
+
+        ret = sr_log_loglevel_set(SR_LOG_NONE);
+        fail_unless(ret == SR_OK, "sr_log_loglevel_set() failed: %d.", ret);
+
+	ret = sr_init(NULL);
+	fail_unless(ret != SR_OK, "sr_init(NULL) should have failed.");
+}
+END_TEST
+
+/* Check whether sr_exit(NULL) fails as it should. */
+START_TEST(test_exit_null)
+{
+	int ret;
+
+        ret = sr_log_loglevel_set(SR_LOG_NONE);
+        fail_unless(ret == SR_OK, "sr_log_loglevel_set() failed: %d.", ret);
+
+	ret = sr_exit(NULL);
+	fail_unless(ret != SR_OK, "sr_exit(NULL) should have failed.");
+}
+END_TEST
+
+Suite *suite_core(void)
+{
+	Suite *s;
+	TCase *tc;
+
+	s = suite_create("core");
+
+	tc = tcase_create("init_exit");
+	tcase_add_test(tc, test_init_exit);
+	tcase_add_test(tc, test_init_exit_2);
+	tcase_add_test(tc, test_init_exit_2_reverse);
+	tcase_add_test(tc, test_init_exit_3);
+	tcase_add_test(tc, test_init_exit_3_reverse);
+	tcase_add_test(tc, test_init_null);
+	tcase_add_test(tc, test_exit_null);
+	suite_add_tcase(s, tc);
+
+	return s;
+}
diff --git a/tests/check_driver_all.c b/tests/check_driver_all.c
new file mode 100644
index 0000000..d15daaa
--- /dev/null
+++ b/tests/check_driver_all.c
@@ -0,0 +1,96 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <check.h>
+#include "../libsigrok.h"
+#include "lib.h"
+
+struct sr_context *sr_ctx;
+
+static void setup(void)
+{
+	int ret;
+
+	ret = sr_init(&sr_ctx);
+	fail_unless(ret == SR_OK, "sr_init() failed: %d.", ret);
+}
+
+static void teardown(void)
+{
+	int ret;
+
+	ret = sr_exit(sr_ctx);
+	fail_unless(ret == SR_OK, "sr_exit() failed: %d.", ret);
+}
+
+/* Check whether at least one driver is available. */
+START_TEST(test_driver_available)
+{
+	struct sr_dev_driver **drivers;
+
+	drivers = sr_driver_list();
+	fail_unless(drivers != NULL, "No drivers found.");
+}
+END_TEST
+
+/* Check whether initializing all drivers works. */
+START_TEST(test_driver_init_all)
+{
+	srtest_driver_init_all(sr_ctx);
+}
+END_TEST
+
+/*
+ * Check whether setting a samplerate works.
+ *
+ * Additionally, this also checks whether SR_CONF_SAMPLERATE can be both
+ * set and read back properly.
+ */
+#if 0
+START_TEST(test_config_get_set_samplerate)
+{
+	/*
+	 * Note: This currently only works for the demo driver.
+	 *       For other drivers, a scan is needed and the respective
+	 *       hardware must be attached to the host running the testsuite.
+	 */
+	srtest_check_samplerate(sr_ctx, "demo", SR_KHZ(19));
+}
+END_TEST
+#endif
+
+Suite *suite_driver_all(void)
+{
+	Suite *s;
+	TCase *tc;
+
+	s = suite_create("driver-all");
+
+	tc = tcase_create("config");
+	tcase_add_checked_fixture(tc, setup, teardown);
+	tcase_add_test(tc, test_driver_available);
+	tcase_add_test(tc, test_driver_init_all);
+	// TODO: Currently broken.
+	// tcase_add_test(tc, test_config_get_set_samplerate);
+	suite_add_tcase(s, tc);
+
+	return s;
+}
diff --git a/tests/check_input_all.c b/tests/check_input_all.c
new file mode 100644
index 0000000..ff46260
--- /dev/null
+++ b/tests/check_input_all.c
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <check.h>
+#include "../libsigrok.h"
+#include "lib.h"
+
+/* Check whether at least one input module is available. */
+START_TEST(test_input_available)
+{
+	struct sr_input_format **inputs;
+
+	inputs = sr_input_list();
+	fail_unless(inputs != NULL, "No input modules found.");
+}
+END_TEST
+
+Suite *suite_input_all(void)
+{
+	Suite *s;
+	TCase *tc;
+
+	s = suite_create("input-all");
+
+	tc = tcase_create("basic");
+	tcase_add_test(tc, test_input_available);
+	suite_add_tcase(s, tc);
+
+	return s;
+}
diff --git a/tests/check_input_binary.c b/tests/check_input_binary.c
new file mode 100644
index 0000000..9b40f1e
--- /dev/null
+++ b/tests/check_input_binary.c
@@ -0,0 +1,335 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <check.h>
+#include <glib/gstdio.h>
+#include "../libsigrok.h"
+#include "lib.h"
+
+#define FILENAME		"foo.dat"
+#define MAX_FILESIZE		(1 * 1000000)
+
+#define CHECK_ALL_LOW		0
+#define CHECK_ALL_HIGH		1
+#define CHECK_HELLO_WORLD	2
+
+static struct sr_context *sr_ctx;
+
+static uint64_t df_packet_counter = 0, sample_counter = 0;
+static gboolean have_seen_df_end = FALSE;
+static GArray *logic_channellist = NULL;
+static int check_to_perform;
+static uint64_t expected_samples;
+static uint64_t *expected_samplerate;
+
+static void setup(void)
+{
+	int ret;
+
+	ret = sr_init(&sr_ctx);
+	fail_unless(ret == SR_OK, "sr_init() failed: %d.", ret);
+}
+
+static void teardown(void)
+{
+	int ret;
+
+	ret = sr_exit(sr_ctx);
+	fail_unless(ret == SR_OK, "sr_exit() failed: %d.", ret);
+}
+
+static void check_all_low(const struct sr_datafeed_logic *logic)
+{
+	uint64_t i;
+	uint8_t *data;
+
+	for (i = 0; i < logic->length; i++) {
+		data = logic->data;
+		if (data[i * logic->unitsize] != 0)
+			fail("Logic data was not all-0x00.");
+	}
+}
+
+static void check_all_high(const struct sr_datafeed_logic *logic)
+{
+	uint64_t i;
+	uint8_t *data;
+
+	for (i = 0; i < logic->length; i++) {
+		data = logic->data;
+		if (data[i * logic->unitsize] != 0xff)
+			fail("Logic data was not all-0xff.");
+	}
+}
+
+static void check_hello_world(const struct sr_datafeed_logic *logic)
+{
+	uint64_t i;
+	uint8_t *data, b;
+	const char *h = "Hello world";
+
+	for (i = 0; i < logic->length; i++) {
+		data = logic->data;
+		b = data[sample_counter + i];
+		if (b != h[sample_counter + i])
+			fail("Logic data was not 'Hello world'.");
+	}
+}
+
+static void datafeed_in(const struct sr_dev_inst *sdi,
+	const struct sr_datafeed_packet *packet, void *cb_data)
+{
+	const struct sr_datafeed_meta *meta;
+	const struct sr_datafeed_logic *logic;
+	struct sr_config *src;
+	uint64_t samplerate, sample_interval;
+	GSList *l;
+	const void *p;
+
+	(void)cb_data;
+
+	fail_unless(sdi != NULL);
+	fail_unless(packet != NULL);
+
+	if (df_packet_counter++ == 0)
+		fail_unless(packet->type == SR_DF_HEADER,
+			    "The first packet must be an SR_DF_HEADER.");
+
+	if (have_seen_df_end)
+		fail("There must be no packets after an SR_DF_END, but we "
+		     "received a packet of type %d.", packet->type);
+
+	p = packet->payload;
+
+	switch (packet->type) {
+	case SR_DF_HEADER:
+		// g_debug("Received SR_DF_HEADER.");
+		// fail_unless(p != NULL, "SR_DF_HEADER payload was NULL.");
+
+		logic_channellist = srtest_get_enabled_logic_channels(sdi);
+		fail_unless(logic_channellist != NULL);
+		fail_unless(logic_channellist->len != 0);
+		// g_debug("Enabled channels: %d.", logic_channellist->len);
+		break;
+	case SR_DF_META:
+		// g_debug("Received SR_DF_META.");
+
+		meta = packet->payload;
+		fail_unless(p != NULL, "SR_DF_META payload was NULL.");
+
+		for (l = meta->config; l; l = l->next) {
+			src = l->data;
+			// g_debug("Got meta key: %d.", src->key);
+			switch (src->key) {
+			case SR_CONF_SAMPLERATE:
+				samplerate = g_variant_get_uint64(src->data);
+				if (!expected_samplerate)
+					break;
+				fail_unless(samplerate == *expected_samplerate,
+					    "Expected samplerate=%" PRIu64 ", "
+					    "got %" PRIu64 "", samplerate,
+					    *expected_samplerate);
+				// g_debug("samplerate = %" PRIu64 " Hz.",
+				// 	samplerate);
+				break;
+			case SR_CONF_SAMPLE_INTERVAL:
+				sample_interval = g_variant_get_uint64(src->data);
+				(void)sample_interval;
+				// g_debug("sample interval = %" PRIu64 " ms.",
+				// 	sample_interval);
+				break;
+			default:
+				/* Unknown metadata is not an error. */
+				g_debug("Got unknown meta key: %d.", src->key);
+				break;
+			}
+		}
+		break;
+	case SR_DF_LOGIC:
+		logic = packet->payload;
+		fail_unless(p != NULL, "SR_DF_LOGIC payload was NULL.");
+
+		// g_debug("Received SR_DF_LOGIC (%" PRIu64 " bytes, "
+		// 	"unitsize %d).", logic->length, logic->unitsize);
+
+		if (check_to_perform == CHECK_ALL_LOW)
+			check_all_low(logic);
+		else if (check_to_perform == CHECK_ALL_HIGH)
+			check_all_high(logic);
+		else if (check_to_perform == CHECK_HELLO_WORLD)
+			check_hello_world(logic);
+
+		sample_counter += logic->length / logic->unitsize;
+
+		break;
+	case SR_DF_END:
+		// g_debug("Received SR_DF_END.");
+		// fail_unless(p != NULL, "SR_DF_END payload was NULL.");
+		have_seen_df_end = TRUE;
+		if (sample_counter != expected_samples)
+			fail("Expected %" PRIu64 " samples, got %" PRIu64 "",
+			     expected_samples, sample_counter);
+		break;
+	default:
+		/*
+		 * Note: The binary input format doesn't support SR_DF_TRIGGER
+		 * and some other types, those should yield an error.
+		 */
+		fail("Invalid packet type: %d.", packet->type);
+		break;
+	}
+}
+
+static void check_buf(const char *filename, GHashTable *param,
+		const uint8_t *buf, int check, uint64_t samples,
+		uint64_t *samplerate)
+{
+	int ret;
+	struct sr_input *in;
+	struct sr_input_format *in_format;
+
+	/* Initialize global variables for this run. */
+	df_packet_counter = sample_counter = 0;
+	have_seen_df_end = FALSE;
+	logic_channellist = NULL;
+	check_to_perform = check;
+	expected_samples = samples;
+	expected_samplerate = samplerate;
+
+	in_format = srtest_input_get("binary");
+
+	in = g_try_malloc0(sizeof(struct sr_input));
+	fail_unless(in != NULL);
+
+	in->format = in_format;
+	in->param = param;
+
+	srtest_buf_to_file(filename, buf, samples); /* Create a file. */
+
+	ret = in->format->init(in, filename);
+	fail_unless(ret == SR_OK, "Input format init error: %d", ret);
+	
+	sr_session_new();
+	sr_session_datafeed_callback_add(datafeed_in, NULL);
+	sr_session_dev_add(in->sdi);
+	in_format->loadfile(in, filename);
+	sr_session_destroy();
+
+	g_unlink(filename); /* Delete file again. */
+}
+
+START_TEST(test_input_binary_all_low)
+{
+	uint64_t i, samplerate;
+	uint8_t *buf;
+	GHashTable *param;
+
+	buf = g_try_malloc0(MAX_FILESIZE);
+	fail_unless(buf != NULL);
+
+	param = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+	fail_unless(param != NULL);
+	g_hash_table_insert(param, g_strdup("samplerate"), g_strdup("1250"));
+	samplerate = SR_HZ(1250);
+
+	/* Check various filesizes, with/without specifying a samplerate. */
+	check_buf(FILENAME, NULL, buf, CHECK_ALL_LOW, 0, NULL);
+	check_buf(FILENAME, param, buf, CHECK_ALL_LOW, 0, &samplerate);
+	for (i = 1; i < MAX_FILESIZE; i *= 3) {
+		check_buf(FILENAME, NULL, buf, CHECK_ALL_LOW, i, NULL);
+		check_buf(FILENAME, param, buf, CHECK_ALL_LOW, i, &samplerate);
+
+	}
+
+	g_hash_table_destroy(param);
+	g_free(buf);
+}
+END_TEST
+
+START_TEST(test_input_binary_all_high)
+{
+	uint64_t i;
+	uint8_t *buf;
+
+	buf = g_try_malloc(MAX_FILESIZE);
+	memset(buf, 0xff, MAX_FILESIZE);
+
+	check_buf(FILENAME, NULL, buf, CHECK_ALL_LOW, 0, NULL);
+	for (i = 1; i < MAX_FILESIZE; i *= 3)
+		check_buf(FILENAME, NULL, buf, CHECK_ALL_HIGH, i, NULL);
+
+	g_free(buf);
+}
+END_TEST
+
+START_TEST(test_input_binary_all_high_loop)
+{
+	uint8_t *buf;
+
+	/* Note: _i is the loop variable from tcase_add_loop_test(). */
+
+	buf = g_try_malloc((_i * 10) + 1);
+	memset(buf, 0xff, _i * 10);
+
+	check_buf(FILENAME, NULL, buf, CHECK_ALL_HIGH, _i * 10, NULL);
+
+	g_free(buf);
+}
+END_TEST
+
+START_TEST(test_input_binary_hello_world)
+{
+	uint64_t samplerate;
+	uint8_t *buf;
+	GHashTable *param;
+
+	buf = (uint8_t *)g_strdup("Hello world");
+
+	param = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+	fail_unless(param != NULL);
+	g_hash_table_insert(param, g_strdup("samplerate"), g_strdup("1250"));
+	samplerate = SR_HZ(1250);
+
+	/* Check with and without specifying a samplerate. */
+	check_buf(FILENAME, NULL, buf, CHECK_HELLO_WORLD, 11, NULL);
+	check_buf(FILENAME, param, buf, CHECK_HELLO_WORLD, 11, &samplerate);
+
+	g_hash_table_destroy(param);
+	g_free(buf);
+}
+END_TEST
+
+Suite *suite_input_binary(void)
+{
+	Suite *s;
+	TCase *tc;
+
+	s = suite_create("input-binary");
+
+	tc = tcase_create("basic");
+	tcase_add_checked_fixture(tc, setup, teardown);
+	tcase_add_test(tc, test_input_binary_all_low);
+	tcase_add_test(tc, test_input_binary_all_high);
+	tcase_add_loop_test(tc, test_input_binary_all_high_loop, 0, 10);
+	tcase_add_test(tc, test_input_binary_hello_world);
+	suite_add_tcase(s, tc);
+
+	return s;
+}
diff --git a/tests/check_main.c b/tests/check_main.c
new file mode 100644
index 0000000..c4ce143
--- /dev/null
+++ b/tests/check_main.c
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <check.h>
+#include "../libsigrok.h"
+#include "lib.h"
+
+int main(void)
+{
+	int ret;
+	Suite *s;
+	SRunner *srunner;
+
+	s = suite_create("mastersuite");
+	srunner = srunner_create(s);
+
+	/* Add all testsuites to the master suite. */
+	srunner_add_suite(srunner, suite_core());
+	srunner_add_suite(srunner, suite_driver_all());
+	srunner_add_suite(srunner, suite_input_all());
+	srunner_add_suite(srunner, suite_input_binary());
+	srunner_add_suite(srunner, suite_output_all());
+	srunner_add_suite(srunner, suite_strutil());
+	srunner_add_suite(srunner, suite_version());
+
+	srunner_run_all(srunner, CK_VERBOSE);
+	ret = srunner_ntests_failed(srunner);
+	srunner_free(srunner);
+
+	return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/tests/check_output_all.c b/tests/check_output_all.c
new file mode 100644
index 0000000..497a24a
--- /dev/null
+++ b/tests/check_output_all.c
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <check.h>
+#include "../libsigrok.h"
+#include "lib.h"
+
+/* Check whether at least one output module is available. */
+START_TEST(test_output_available)
+{
+	struct sr_output_format **outputs;
+
+	outputs = sr_output_list();
+	fail_unless(outputs != NULL, "No output modules found.");
+}
+END_TEST
+
+Suite *suite_output_all(void)
+{
+	Suite *s;
+	TCase *tc;
+
+	s = suite_create("output-all");
+
+	tc = tcase_create("basic");
+	tcase_add_test(tc, test_output_available);
+	suite_add_tcase(s, tc);
+
+	return s;
+}
diff --git a/tests/check_strutil.c b/tests/check_strutil.c
new file mode 100644
index 0000000..ad67ef2
--- /dev/null
+++ b/tests/check_strutil.c
@@ -0,0 +1,191 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <check.h>
+#include "../libsigrok.h"
+#include "lib.h"
+
+struct sr_context *sr_ctx;
+
+static void setup(void)
+{
+	int ret;
+
+	ret = sr_init(&sr_ctx);
+	fail_unless(ret == SR_OK, "sr_init() failed: %d.", ret);
+}
+
+static void teardown(void)
+{
+	int ret;
+
+	ret = sr_exit(sr_ctx);
+	fail_unless(ret == SR_OK, "sr_exit() failed: %d.", ret);
+}
+
+static void test_samplerate(uint64_t samplerate, const char *expected)
+{
+	char *s;
+
+	s = sr_samplerate_string(samplerate);
+	fail_unless(s != NULL);
+	fail_unless(!strcmp(s, expected),
+		    "Invalid result for '%s': %s.", expected, s);
+	g_free(s);
+}
+
+/*
+ * Check various inputs for sr_samplerate_string():
+ *
+ *  - One, two, or three digit results (e.g. 5/55/555 MHz).
+ *  - Results which contain commas (e.g. 1.234 / 12.34 / 123.4 kHz).
+ *  - Results with zeroes right after the comma (e.g. 1.034 Hz).
+ *    See also: http://sigrok.org/bugzilla/show_bug.cgi?id=73
+ *  - Results with zeroes in the middle (e.g. 1.204 kHz).
+ *  - All of the above, but using SR_MHZ() and friends.
+ *    See also: http://sigrok.org/bugzilla/show_bug.cgi?id=72
+ *
+ * All of the above tests are done for the Hz/kHz/MHz/GHz ranges.
+ */
+
+START_TEST(test_hz)
+{
+	test_samplerate(0, "0 Hz");
+	test_samplerate(1, "1 Hz");
+	test_samplerate(23, "23 Hz");
+	test_samplerate(644, "644 Hz");
+	test_samplerate(604, "604 Hz");
+	test_samplerate(550, "550 Hz");
+
+	/* Again, but now using SR_HZ(). */
+	test_samplerate(SR_HZ(0), "0 Hz");
+	test_samplerate(SR_HZ(1), "1 Hz");
+	test_samplerate(SR_HZ(23), "23 Hz");
+	test_samplerate(SR_HZ(644), "644 Hz");
+	test_samplerate(SR_HZ(604), "604 Hz");
+	test_samplerate(SR_HZ(550), "550 Hz");
+}
+END_TEST
+
+START_TEST(test_khz)
+{
+	test_samplerate(1000, "1 kHz");
+	test_samplerate(99000, "99 kHz");
+	test_samplerate(225000, "225 kHz");
+	test_samplerate(1234, "1.234 kHz");
+	test_samplerate(12345, "12.345 kHz");
+	test_samplerate(123456, "123.456 kHz");
+	test_samplerate(1034, "1.034 kHz");
+	test_samplerate(1004, "1.004 kHz");
+	test_samplerate(1230, "1.23 kHz");
+
+	/* Again, but now using SR_KHZ(). */
+	test_samplerate(SR_KHZ(1), "1 kHz");
+	test_samplerate(SR_KHZ(99), "99 kHz");
+	test_samplerate(SR_KHZ(225), "225 kHz");
+	test_samplerate(SR_KHZ(1.234), "1.234 kHz");
+	test_samplerate(SR_KHZ(12.345), "12.345 kHz");
+	test_samplerate(SR_KHZ(123.456), "123.456 kHz");
+	test_samplerate(SR_KHZ(1.204), "1.204 kHz");
+	test_samplerate(SR_KHZ(1.034), "1.034 kHz");
+	test_samplerate(SR_KHZ(1.004), "1.004 kHz");
+	test_samplerate(SR_KHZ(1.230), "1.23 kHz");
+}
+END_TEST
+
+START_TEST(test_mhz)
+{
+	test_samplerate(1000000, "1 MHz");
+	test_samplerate(28000000, "28 MHz");
+	test_samplerate(775000000, "775 MHz");
+	test_samplerate(1234567, "1.234567 MHz");
+	test_samplerate(12345678, "12.345678 MHz");
+	test_samplerate(123456789, "123.456789 MHz");
+	test_samplerate(1230007, "1.230007 MHz");
+	test_samplerate(1034567, "1.034567 MHz");
+	test_samplerate(1000007, "1.000007 MHz");
+	test_samplerate(1234000, "1.234 MHz");
+
+	/* Again, but now using SR_MHZ(). */
+	test_samplerate(SR_MHZ(1), "1 MHz");
+	test_samplerate(SR_MHZ(28), "28 MHz");
+	test_samplerate(SR_MHZ(775), "775 MHz");
+	test_samplerate(SR_MHZ(1.234567), "1.234567 MHz");
+	test_samplerate(SR_MHZ(12.345678), "12.345678 MHz");
+	test_samplerate(SR_MHZ(123.456789), "123.456789 MHz");
+	test_samplerate(SR_MHZ(1.230007), "1.230007 MHz");
+	test_samplerate(SR_MHZ(1.034567), "1.034567 MHz");
+	test_samplerate(SR_MHZ(1.000007), "1.000007 MHz");
+	test_samplerate(SR_MHZ(1.234000), "1.234 MHz");
+}
+END_TEST
+
+START_TEST(test_ghz)
+{
+	/* Note: Numbers > 2^32 need a ULL suffix. */
+
+	test_samplerate(1000000000, "1 GHz");
+	test_samplerate(5000000000ULL, "5 GHz");
+	test_samplerate(72000000000ULL, "72 GHz");
+	test_samplerate(388000000000ULL, "388 GHz");
+	test_samplerate(4417594444ULL, "4.417594444 GHz");
+	test_samplerate(44175944444ULL, "44.175944444 GHz");
+	test_samplerate(441759444441ULL, "441.759444441 GHz");
+	test_samplerate(441759000001ULL, "441.759000001 GHz");
+	test_samplerate(441050000000ULL, "441.05 GHz");
+	test_samplerate(441000000005ULL, "441.000000005 GHz");
+	test_samplerate(441500000000ULL, "441.5 GHz");
+
+	/* Again, but now using SR_GHZ(). */
+	test_samplerate(SR_GHZ(1), "1 GHz");
+	test_samplerate(SR_GHZ(5), "5 GHz");
+	test_samplerate(SR_GHZ(72), "72 GHz");
+	test_samplerate(SR_GHZ(388), "388 GHz");
+	test_samplerate(SR_GHZ(4.417594444), "4.417594444 GHz");
+	test_samplerate(SR_GHZ(44.175944444), "44.175944444 GHz");
+	test_samplerate(SR_GHZ(441.759444441), "441.759444441 GHz");
+	test_samplerate(SR_GHZ(441.759000001), "441.759000001 GHz");
+	test_samplerate(SR_GHZ(441.050000000), "441.05 GHz");
+	test_samplerate(SR_GHZ(441.000000005), "441.000000005 GHz");
+	test_samplerate(SR_GHZ(441.500000000), "441.5 GHz");
+
+	/* Now check the biggest-possible samplerate (2^64 Hz). */
+	// test_samplerate(18446744073709551615ULL, "18446744073.709551615 GHz");
+	// test_samplerate(SR_GHZ(18446744073ULL), "18446744073 GHz");
+}
+END_TEST
+
+Suite *suite_strutil(void)
+{
+	Suite *s;
+	TCase *tc;
+
+	s = suite_create("strutil");
+
+	tc = tcase_create("sr_samplerate_string");
+	tcase_add_checked_fixture(tc, setup, teardown);
+	tcase_add_test(tc, test_hz);
+	tcase_add_test(tc, test_khz);
+	tcase_add_test(tc, test_mhz);
+	tcase_add_test(tc, test_ghz);
+	suite_add_tcase(s, tc);
+
+	return s;
+}
diff --git a/tests/check_version.c b/tests/check_version.c
new file mode 100644
index 0000000..37cf370
--- /dev/null
+++ b/tests/check_version.c
@@ -0,0 +1,93 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <check.h>
+#include "../libsigrok.h"
+#include "lib.h"
+
+/*
+ * Check the version number API calls and macros.
+ *
+ * The numbers returned by the sr_*_version*get() calls must match the
+ * respective SR_*_VERSION* macro values, must be >= 0, and must not be
+ * unreasonably high (> 20), otherwise something is probably wrong.
+ */
+START_TEST(test_version_numbers)
+{
+	int ver;
+
+	ver = sr_package_version_major_get();
+	fail_unless(ver == SR_PACKAGE_VERSION_MAJOR);
+	fail_unless(ver >= 0 && ver <= 20);
+	ver = sr_package_version_minor_get();
+	fail_unless(ver == SR_PACKAGE_VERSION_MINOR);
+	fail_unless(ver >= 0 && ver <= 20);
+	ver = sr_package_version_micro_get();
+	fail_unless(ver == SR_PACKAGE_VERSION_MICRO);
+	fail_unless(ver >= 0 && ver <= 20);
+
+	ver = sr_lib_version_current_get();
+	fail_unless(ver == SR_LIB_VERSION_CURRENT);
+	fail_unless(ver >= 0 && ver <= 20);
+	ver = sr_lib_version_revision_get();
+	fail_unless(ver == SR_LIB_VERSION_REVISION);
+	fail_unless(ver >= 0 && ver <= 20);
+	ver = sr_lib_version_age_get();
+	fail_unless(ver == SR_LIB_VERSION_AGE);
+	fail_unless(ver >= 0 && ver <= 20);
+}
+END_TEST
+
+/*
+ * Check the version number API calls and macros.
+ *
+ * The string representations of the package/lib version must match the
+ * version numbers, the string lengths must be >= 5 (e.g. "0.1.0"), and
+ * the strings length must be <= 20 characters, otherwise something is
+ * probably wrong.
+ */
+START_TEST(test_version_strings)
+{
+	const char *str;
+
+	str = sr_package_version_string_get();
+	fail_unless(str != NULL);
+	fail_unless(strlen(str) >= 5 && strlen(str) <= 20);
+	str = sr_lib_version_string_get();
+	fail_unless(str != NULL);
+	fail_unless(strlen(str) >= 5 && strlen(str) <= 20);
+}
+END_TEST
+
+Suite *suite_version(void)
+{
+	Suite *s;
+	TCase *tc;
+
+	s = suite_create("version");
+
+	tc = tcase_create("version");
+	tcase_add_test(tc, test_version_numbers);
+	tcase_add_test(tc, test_version_strings);
+	suite_add_tcase(s, tc);
+
+	return s;
+}
diff --git a/tests/lib.c b/tests/lib.c
new file mode 100644
index 0000000..ad0b3e1
--- /dev/null
+++ b/tests/lib.c
@@ -0,0 +1,231 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <check.h>
+#include "../libsigrok.h"
+#include "lib.h"
+
+/* Get a libsigrok driver by name. */
+struct sr_dev_driver *srtest_driver_get(const char *drivername)
+{
+	struct sr_dev_driver **drivers, *driver = NULL;
+	int i;
+
+	drivers = sr_driver_list();
+	fail_unless(drivers != NULL, "No drivers found.");
+
+	for (i = 0; drivers[i]; i++) {
+		if (strcmp(drivers[i]->name, drivername))
+			continue;
+		driver = drivers[i];
+	}
+	fail_unless(driver != NULL, "Driver '%s' not found.", drivername);
+
+	return driver;
+}
+
+/* Get a libsigrok input format by ID. */
+struct sr_input_format *srtest_input_get(const char *id)
+{
+	struct sr_input_format **inputs, *input = NULL;
+	int i;
+
+	inputs = sr_input_list();
+	fail_unless(inputs != NULL, "No input modules found.");
+
+	for (i = 0; inputs[i]; i++) {
+		if (strcmp(inputs[i]->id, id))
+			continue;
+		input = inputs[i];
+	}
+	fail_unless(input != NULL, "Input module '%s' not found.", id);
+
+	return input;
+}
+
+/* Get a libsigrok output format by ID. */
+struct sr_output_format *srtest_output_get(const char *id)
+{
+	struct sr_output_format **outputs, *output = NULL;
+	int i;
+
+	outputs = sr_output_list();
+	fail_unless(outputs != NULL, "No output modules found.");
+
+	for (i = 0; outputs[i]; i++) {
+		if (strcmp(outputs[i]->id, id))
+			continue;
+		output = outputs[i];
+	}
+	fail_unless(output != NULL, "Output module '%s' not found.", id);
+
+	return output;
+}
+
+/* Initialize a libsigrok driver. */
+void srtest_driver_init(struct sr_context *sr_ctx, struct sr_dev_driver *driver)
+{
+	int ret;
+
+	ret = sr_driver_init(sr_ctx, driver);
+	fail_unless(ret == SR_OK, "Failed to init '%s' driver: %d.",
+		    driver->name, ret);
+}
+
+/* Initialize all libsigrok drivers. */
+void srtest_driver_init_all(struct sr_context *sr_ctx)
+{
+	struct sr_dev_driver **drivers, *driver;
+	int i, ret;
+
+	drivers = sr_driver_list();
+	fail_unless(drivers != NULL, "No drivers found.");
+
+	for (i = 0; drivers[i]; i++) {
+		driver = drivers[i];
+		ret = sr_driver_init(sr_ctx, driver);
+		fail_unless(ret == SR_OK, "Failed to init '%s' driver: %d.",
+			    driver->name, ret);
+	}
+}
+
+/* Initialize a libsigrok input module. */
+void srtest_input_init(struct sr_context *sr_ctx, struct sr_input_format *input)
+{
+	int ret;
+	struct sr_input *in;
+
+	(void)sr_ctx;
+
+	in = g_try_malloc0(sizeof(struct sr_input));
+	fail_unless(in != NULL);
+
+	in->format = input;
+	in->param = NULL;
+
+	ret = in->format->init(in, "nonexisting.dat");
+	fail_unless(ret == SR_OK, "Failed to init '%s' input module: %d.",
+		    input->id, ret);
+
+	g_free(in);
+}
+
+/* Initialize all libsigrok input modules. */
+void srtest_input_init_all(struct sr_context *sr_ctx)
+{
+	struct sr_input_format **inputs;
+	int i;
+
+	inputs = sr_input_list();
+	fail_unless(inputs != NULL, "No input modules found.");
+
+	for (i = 0; inputs[i]; i++)
+		srtest_input_init(sr_ctx, inputs[i]);
+}
+
+/* Set the samplerate for the respective driver to the specified value. */
+void srtest_set_samplerate(struct sr_dev_driver *driver, uint64_t samplerate)
+{
+	int ret;
+	struct sr_dev_inst *sdi;
+	GVariant *gvar;
+
+	sdi = g_slist_nth_data(driver->priv, 0);
+
+	gvar = g_variant_new_uint64(samplerate);
+	ret = driver->config_set(SR_CONF_SAMPLERATE, gvar, sdi, NULL);
+	g_variant_unref(gvar);
+
+	fail_unless(ret == SR_OK, "%s: Failed to set SR_CONF_SAMPLERATE: %d.",
+		    driver->name, ret);
+}
+
+/* Get the respective driver's current samplerate. */
+uint64_t srtest_get_samplerate(struct sr_dev_driver *driver)
+{
+	int ret;
+	uint64_t samplerate;
+	struct sr_dev_inst *sdi;
+	GVariant *gvar;
+
+	sdi = g_slist_nth_data(driver->priv, 0);
+
+	ret = driver->config_get(SR_CONF_SAMPLERATE, &gvar, sdi, NULL);
+	samplerate = g_variant_get_uint64(gvar);
+	g_variant_unref(gvar);
+
+	fail_unless(ret == SR_OK, "%s: Failed to get SR_CONF_SAMPLERATE: %d.",
+		    driver->name, ret);
+
+	return samplerate;
+}
+
+/* Check whether the respective driver can set/get the correct samplerate. */
+void srtest_check_samplerate(struct sr_context *sr_ctx, const char *drivername,
+			     uint64_t samplerate)
+{
+	struct sr_dev_driver *driver;
+	uint64_t s;
+
+	driver = srtest_driver_get(drivername);
+	srtest_driver_init(sr_ctx, driver);;
+	srtest_set_samplerate(driver, samplerate);
+	s = srtest_get_samplerate(driver);
+	fail_unless(s == samplerate, "%s: Incorrect samplerate: %" PRIu64 ".",
+		    drivername, s);
+}
+
+void srtest_buf_to_file(const char *filename, const uint8_t *buf, uint64_t len)
+{
+	FILE *f;
+	GError *error = NULL;
+	gboolean ret;
+
+	f = g_fopen(filename, "wb");
+	fail_unless(f != NULL);
+
+	ret = g_file_set_contents(filename, (const gchar *)buf, len, &error);
+	fail_unless(ret == TRUE);
+
+	fclose(f);
+}
+
+GArray *srtest_get_enabled_logic_channels(const struct sr_dev_inst *sdi)
+{
+	struct sr_channel *ch;
+	GArray *channels;
+	GSList *l;
+
+	channels = g_array_new(FALSE, FALSE, sizeof(int));
+	for (l = sdi->channels; l; l = l->next) {
+		ch = l->data;
+		if (ch->type != SR_CHANNEL_LOGIC)
+			continue;
+		if (ch->enabled != TRUE)
+			continue;
+		g_array_append_val(channels, ch->index);
+	}
+
+	return channels;
+}
diff --git a/tests/lib.h b/tests/lib.h
new file mode 100644
index 0000000..e2e607e
--- /dev/null
+++ b/tests/lib.h
@@ -0,0 +1,52 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2013 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef LIBSIGROK_TESTS_LIB_H
+#define LIBSIGROK_TESTS_LIB_H
+
+#include "../libsigrok.h"
+
+struct sr_dev_driver *srtest_driver_get(const char *drivername);
+struct sr_input_format *srtest_input_get(const char *id);
+struct sr_output_format *srtest_output_get(const char *id);
+
+void srtest_driver_init(struct sr_context *sr_ctx, struct sr_dev_driver *driver);
+void srtest_driver_init_all(struct sr_context *sr_ctx);
+
+void srtest_input_init(struct sr_context *sr_ctx, struct sr_input_format *input);
+void srtest_input_init_all(struct sr_context *sr_ctx);
+
+void srtest_set_samplerate(struct sr_dev_driver *driver, uint64_t samplerate);
+uint64_t srtest_get_samplerate(struct sr_dev_driver *driver);
+void srtest_check_samplerate(struct sr_context *sr_ctx, const char *drivername,
+			     uint64_t samplerate);
+
+void srtest_buf_to_file(const char *filename, const uint8_t *buf, uint64_t len);
+GArray *srtest_get_enabled_logic_channels(const struct sr_dev_inst *sdi);
+
+Suite *suite_core(void);
+Suite *suite_driver_all(void);
+Suite *suite_input_all(void);
+Suite *suite_input_binary(void);
+Suite *suite_output_all(void);
+Suite *suite_strutil(void);
+Suite *suite_version(void);
+
+#endif
diff --git a/version.c b/version.c
new file mode 100644
index 0000000..3da0c17
--- /dev/null
+++ b/version.c
@@ -0,0 +1,147 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2012 Uwe Hermann <uwe at hermann-uwe.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "libsigrok.h"
+
+/**
+ * @file
+ *
+ * Version number querying functions, definitions, and macros.
+ */
+
+/**
+ * @defgroup grp_versions Versions
+ *
+ * Version number querying functions, definitions, and macros.
+ *
+ * This set of API calls returns two different version numbers related
+ * to libsigrok. The "package version" is the release version number of the
+ * libsigrok tarball in the usual "major.minor.micro" format, e.g. "0.1.0".
+ *
+ * The "library version" is independent of that; it is the libtool version
+ * number in the "current:revision:age" format, e.g. "2:0:0".
+ * See http://www.gnu.org/software/libtool/manual/libtool.html#Libtool-versioning for details.
+ *
+ * Both version numbers (and/or individual components of them) can be
+ * retrieved via the API calls at runtime, and/or they can be checked at
+ * compile/preprocessor time using the respective macros.
+ *
+ * @{
+ */
+
+/**
+ * Get the major libsigrok package version number.
+ *
+ * @return The major package version number.
+ *
+ * @since 0.1.0
+ */
+SR_API int sr_package_version_major_get(void)
+{
+	return SR_PACKAGE_VERSION_MAJOR;
+}
+
+/**
+ * Get the minor libsigrok package version number.
+ *
+ * @return The minor package version number.
+ *
+ * @since 0.1.0
+ */
+SR_API int sr_package_version_minor_get(void)
+{
+	return SR_PACKAGE_VERSION_MINOR;
+}
+
+/**
+ * Get the micro libsigrok package version number.
+ *
+ * @return The micro package version number.
+ *
+ * @since 0.1.0
+ */
+SR_API int sr_package_version_micro_get(void)
+{
+	return SR_PACKAGE_VERSION_MICRO;
+}
+
+/**
+ * Get the libsigrok package version number as a string.
+ *
+ * @return The package version number string. The returned string is
+ *         static and thus should NOT be free'd by the caller.
+ *
+ * @since 0.1.0
+ */
+SR_API const char *sr_package_version_string_get(void)
+{
+	return SR_PACKAGE_VERSION_STRING;
+}
+
+/**
+ * Get the "current" part of the libsigrok library version number.
+ *
+ * @return The "current" library version number.
+ *
+ * @since 0.1.0
+ */
+SR_API int sr_lib_version_current_get(void)
+{
+	return SR_LIB_VERSION_CURRENT;
+}
+
+/**
+ * Get the "revision" part of the libsigrok library version number.
+ *
+ * @return The "revision" library version number.
+ *
+ * @since 0.1.0
+ */
+SR_API int sr_lib_version_revision_get(void)
+{
+	return SR_LIB_VERSION_REVISION;
+}
+
+/**
+ * Get the "age" part of the libsigrok library version number.
+ *
+ * @return The "age" library version number.
+ *
+ * @since 0.1.0
+ */
+SR_API int sr_lib_version_age_get(void)
+{
+	return SR_LIB_VERSION_AGE;
+}
+
+/**
+ * Get the libsigrok library version number as a string.
+ *
+ * @return The library version number string. The returned string is
+ *         static and thus should NOT be free'd by the caller.
+ *
+ * @since 0.1.0
+ */
+SR_API const char *sr_lib_version_string_get(void)
+{
+	return SR_LIB_VERSION_STRING;
+}
+
+/** @} */
diff --git a/version.h b/version.h
new file mode 100644
index 0000000..069dd70
--- /dev/null
+++ b/version.h
@@ -0,0 +1,69 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010-2012 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_VERSION_H
+#define LIBSIGROK_VERSION_H
+
+/**
+ * @file
+ *
+ * Version number definitions and macros.
+ */
+
+/**
+ * @ingroup grp_versions
+ *
+ * @{
+ */
+
+/*
+ * Package version macros (can be used for conditional compilation).
+ */
+
+/** The libsigrok package 'major' version number. */
+#define SR_PACKAGE_VERSION_MAJOR 0
+
+/** The libsigrok package 'minor' version number. */
+#define SR_PACKAGE_VERSION_MINOR 3
+
+/** The libsigrok package 'micro' version number. */
+#define SR_PACKAGE_VERSION_MICRO 0
+
+/** The libsigrok package version ("major.minor.micro") as string. */
+#define SR_PACKAGE_VERSION_STRING "0.3.0"
+
+/*
+ * Library/libtool version macros (can be used for conditional compilation).
+ */
+
+/** The libsigrok libtool 'current' version number. */
+#define SR_LIB_VERSION_CURRENT 2
+
+/** The libsigrok libtool 'revision' version number. */
+#define SR_LIB_VERSION_REVISION 0
+
+/** The libsigrok libtool 'age' version number. */
+#define SR_LIB_VERSION_AGE 0
+
+/** The libsigrok libtool version ("current:revision:age") as string. */
+#define SR_LIB_VERSION_STRING "2:0:0"
+
+/** @} */
+
+#endif
diff --git a/version.h.in b/version.h.in
new file mode 100644
index 0000000..d044091
--- /dev/null
+++ b/version.h.in
@@ -0,0 +1,69 @@
+/*
+ * This file is part of the libsigrok project.
+ *
+ * Copyright (C) 2010-2012 Bert Vermeulen <bert at biot.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBSIGROK_VERSION_H
+#define LIBSIGROK_VERSION_H
+
+/**
+ * @file
+ *
+ * Version number definitions and macros.
+ */
+
+/**
+ * @ingroup grp_versions
+ *
+ * @{
+ */
+
+/*
+ * Package version macros (can be used for conditional compilation).
+ */
+
+/** The libsigrok package 'major' version number. */
+#define SR_PACKAGE_VERSION_MAJOR @SR_PACKAGE_VERSION_MAJOR@
+
+/** The libsigrok package 'minor' version number. */
+#define SR_PACKAGE_VERSION_MINOR @SR_PACKAGE_VERSION_MINOR@
+
+/** The libsigrok package 'micro' version number. */
+#define SR_PACKAGE_VERSION_MICRO @SR_PACKAGE_VERSION_MICRO@
+
+/** The libsigrok package version ("major.minor.micro") as string. */
+#define SR_PACKAGE_VERSION_STRING "@SR_PACKAGE_VERSION@"
+
+/*
+ * Library/libtool version macros (can be used for conditional compilation).
+ */
+
+/** The libsigrok libtool 'current' version number. */
+#define SR_LIB_VERSION_CURRENT @SR_LIB_VERSION_CURRENT@
+
+/** The libsigrok libtool 'revision' version number. */
+#define SR_LIB_VERSION_REVISION @SR_LIB_VERSION_REVISION@
+
+/** The libsigrok libtool 'age' version number. */
+#define SR_LIB_VERSION_AGE @SR_LIB_VERSION_AGE@
+
+/** The libsigrok libtool version ("current:revision:age") as string. */
+#define SR_LIB_VERSION_STRING "@SR_LIB_VERSION@"
+
+/** @} */
+
+#endif

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/libsigrok.git



More information about the debian-science-commits mailing list