[Pkg-voip-commits] [dahdi-tools] 02/285: Import DAHDI-Tools r9159

tzafrir at debian.org tzafrir at debian.org
Thu Jul 7 19:18:17 UTC 2016


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

tzafrir pushed a commit to branch master
in repository dahdi-tools.

commit 466357f5c28253c4f72799431f2033a3e82dea6b
Author: Asterisk Development Team <asteriskteam at digium.com>
Date:   Wed Aug 18 13:49:24 2010 +0000

    Import DAHDI-Tools r9159
    
    This revision of DAHDI-Tools is the base revision for the switch to
    git.
    
    git-svn-id: http://svn.astersk.org/svn/dahdi/tools/tools/trunk@9159
---
 LICENSE                                        |  341 ++
 LICENSE.LGPL                                   |  504 ++
 Makefile                                       |  420 ++
 README                                         |  233 +
 UPGRADE.txt                                    |  103 +
 acinclude.m4                                   | 1113 ++++
 autoconfig.h.in                                |  102 +
 bittest.h                                      |   17 +
 blacklist.sample                               |   13 +
 bootstrap.sh                                   |   48 +
 build_tools/dahdi_svn_tarball                  |   90 +
 build_tools/dump_sys_state                     |  147 +
 build_tools/make_firmware_object.in            |   11 +
 build_tools/make_tree                          |    7 +
 build_tools/make_version                       |   56 +
 build_tools/make_version_c                     |   10 +
 build_tools/menuselect-deps.in                 |    2 +
 build_tools/test_kernel_git                    |   80 +
 build_tools/uninstall-modules                  |   41 +
 config.guess                                   | 1526 ++++++
 config.sub                                     | 1658 ++++++
 configure                                      | 6991 ++++++++++++++++++++++++
 configure.ac                                   |  215 +
 dahdi.init                                     |  333 ++
 dahdi.xml                                      |   26 +
 dahdi_cfg.c                                    | 1662 ++++++
 dahdi_diag.c                                   |   55 +
 dahdi_maint.c                                  |  236 +
 dahdi_monitor.c                                |  783 +++
 dahdi_scan.c                                   |  205 +
 dahdi_speed.c                                  |   65 +
 dahdi_test.c                                   |  164 +
 dahdi_tool.c                                   |  541 ++
 dahdi_tools_version.h                          |   21 +
 doc/dahdi_cfg.8                                |   70 +
 doc/dahdi_diag.8                               |   52 +
 doc/dahdi_monitor.8                            |   43 +
 doc/dahdi_scan.8                               |  101 +
 doc/dahdi_test.8                               |   49 +
 doc/dahdi_tool.8                               |   25 +
 doc/fxotune.8                                  |  207 +
 doc/fxstest.8                                  |   60 +
 doc/patgen.8                                   |   44 +
 doc/pattest.8                                  |   49 +
 fxotune.c                                      | 1272 +++++
 fxotune.h                                      |  119 +
 fxstest.c                                      |  337 ++
 hdlcgen.c                                      |  135 +
 hdlcstress.c                                   |  233 +
 hdlctest.c                                     |  302 +
 hdlcverify.c                                   |  136 +
 ifup-hdlc                                      |   39 +
 init.conf.sample                               |   19 +
 install-sh                                     |  323 ++
 makeopts.in                                    |   47 +
 modprobe.conf.sample                           |    4 +
 modules.sample                                 |   48 +
 patgen.c                                       |  164 +
 patlooptest.c                                  |  295 +
 pattest.c                                      |  170 +
 ppp/Makefile                                   |   29 +
 ppp/dahdi.c                                    |  293 +
 sethdlc.c                                      |  704 +++
 system.conf.sample                             |  330 ++
 timertest.c                                    |   78 +
 tonezone.c                                     |  518 ++
 tonezone.h                                     |   90 +
 wavformat.h                                    |   48 +
 xpp/Makefile                                   |  140 +
 xpp/README.Astribank                           | 1656 ++++++
 xpp/astribank_allow.8                          |   70 +
 xpp/astribank_allow.c                          |  384 ++
 xpp/astribank_hexload.8                        |   66 +
 xpp/astribank_hexload.c                        |  229 +
 xpp/astribank_hook                             |  114 +
 xpp/astribank_is_starting.8                    |  100 +
 xpp/astribank_is_starting.c                    |  190 +
 xpp/astribank_tool.8                           |   86 +
 xpp/astribank_tool.c                           |  274 +
 xpp/astribank_upgrade                          |  150 +
 xpp/astribank_usb.c                            |  555 ++
 xpp/astribank_usb.h                            |  103 +
 xpp/dahdi.cgi                                  |  265 +
 xpp/dahdi_drivers                              |   23 +
 xpp/dahdi_genconf                              |  196 +
 xpp/dahdi_hardware                             |  196 +
 xpp/dahdi_registration                         |  166 +
 xpp/debug.c                                    |   53 +
 xpp/debug.h                                    |   46 +
 xpp/fpga_load.8                                |   86 +
 xpp/fpga_load.c                                | 1052 ++++
 xpp/genconf_parameters                         |  169 +
 xpp/hexfile.c                                  |  568 ++
 xpp/hexfile.h                                  |   87 +
 xpp/lsdahdi                                    |  110 +
 xpp/mpp.h                                      |  344 ++
 xpp/mpp_funcs.c                                | 1109 ++++
 xpp/mpp_funcs.h                                |   80 +
 xpp/perl_modules/Dahdi.pm                      |   79 +
 xpp/perl_modules/Dahdi/Chans.pm                |  264 +
 xpp/perl_modules/Dahdi/Config/Gen.pm           |  275 +
 xpp/perl_modules/Dahdi/Config/Gen/Chandahdi.pm |  299 +
 xpp/perl_modules/Dahdi/Config/Gen/Modules.pm   |   62 +
 xpp/perl_modules/Dahdi/Config/Gen/System.pm    |  278 +
 xpp/perl_modules/Dahdi/Config/Gen/Unicall.pm   |   72 +
 xpp/perl_modules/Dahdi/Config/Gen/Users.pm     |  227 +
 xpp/perl_modules/Dahdi/Config/Gen/Xpporder.pm  |  142 +
 xpp/perl_modules/Dahdi/Config/Params.pm        |  156 +
 xpp/perl_modules/Dahdi/Hardware.pm             |  235 +
 xpp/perl_modules/Dahdi/Hardware/PCI.pm         |  245 +
 xpp/perl_modules/Dahdi/Hardware/USB.pm         |  206 +
 xpp/perl_modules/Dahdi/Span.pm                 |  364 ++
 xpp/perl_modules/Dahdi/Utils.pm                |   66 +
 xpp/perl_modules/Dahdi/Xpp.pm                  |  343 ++
 xpp/perl_modules/Dahdi/Xpp/Line.pm             |   89 +
 xpp/perl_modules/Dahdi/Xpp/Mpp.pm              |  222 +
 xpp/perl_modules/Dahdi/Xpp/Xbus.pm             |  213 +
 xpp/perl_modules/Dahdi/Xpp/Xpd.pm              |  387 ++
 xpp/pic_loader.c                               |  276 +
 xpp/pic_loader.h                               |   46 +
 xpp/test_parse.c                               |   57 +
 xpp/twinstar                                   |  267 +
 xpp/twinstar_hook                              |   86 +
 xpp/twinstar_setup                             |  155 +
 xpp/waitfor_xpds                               |   93 +
 xpp/xpp_blink                                  |  168 +
 xpp/xpp_fxloader                               |  364 ++
 xpp/xpp_fxloader.usermap                       |   10 +
 xpp/xpp_modprobe                               |   10 +
 xpp/xpp_sync                                   |  226 +
 xpp/xpp_timing                                 |    6 +
 zonedata.c                                     |  983 ++++
 132 files changed, 39890 insertions(+)

diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..a52b16e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,341 @@
+
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  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
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  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.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+

+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+

+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+

+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+

+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the 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 a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE 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.
+
+		     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
+convey 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) 19yy  <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 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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision 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, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This 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 Library General
+Public License instead of this License.
diff --git a/LICENSE.LGPL b/LICENSE.LGPL
new file mode 100644
index 0000000..1f7c8cc
--- /dev/null
+++ b/LICENSE.LGPL
@@ -0,0 +1,504 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey 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 library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..835e410
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,420 @@
+#
+# Makefile for DAHDI tools
+#
+# Copyright (C) 2001-2010 Digium, Inc.
+#
+#
+
+# If the file .dahdi.makeopts is present in your home directory, you can
+# include all of your favorite menuselect options so that every time you download
+# a new version of Asterisk, you don't have to run menuselect to set them.
+# The file /etc/dahdi.makeopts will also be included but can be overridden
+# by the file in your home directory.
+
+GLOBAL_MAKEOPTS=$(wildcard /etc/dahdi.makeopts)
+USER_MAKEOPTS=$(wildcard ~/.dahdi.makeopts)
+
+ifeq ($(strip $(foreach var,clean distclean dist-clean update,$(findstring $(var),$(MAKECMDGOALS)))),)
+ ifneq ($(wildcard menuselect.makeopts),)
+  include menuselect.makeopts
+ endif
+endif
+
+ifeq ($(strip $(foreach var,clean distclean dist-clean update,$(findstring $(var),$(MAKECMDGOALS)))),)
+ ifneq ($(wildcard makeopts),)
+  include makeopts
+ endif
+endif
+
+SUBDIRS_UTILS_ALL:= ppp
+SUBDIRS_UTILS := xpp
+
+OPTFLAGS=-O2
+CFLAGS+=-I. $(OPTFLAGS) -g -fPIC -Wall -DBUILDING_TONEZONE #-DTONEZONE_DRIVER
+ifneq (,$(findstring ppc,$(UNAME_M)))
+CFLAGS+=-fsigned-char
+endif
+ifneq (,$(findstring x86_64,$(UNAME_M)))
+CFLAGS+=-m64
+endif
+
+ifeq ($(DAHDI_DEVMODE),yes)
+  CFLAGS+=-Werror -Wunused -Wundef $(DAHDI_DECLARATION_AFTER_STATEMENT) -Wmissing-format-attribute -Wformat-security #-Wformat=2
+endif
+
+ROOT_PREFIX=
+
+# extra cflags to build dependencies. Recursively expanded.
+MAKE_DEPS= -MD -MT $@ -MF .$(subst /,_,$@).d -MP
+
+CFLAGS+=$(DAHDI_INCLUDE)
+
+CHKCONFIG	:= $(wildcard /sbin/chkconfig)
+UPDATE_RCD	:= $(wildcard /usr/sbin/update-rc.d)
+ifeq (,$(DESTDIR))
+  ifneq (,$(CHKCONFIG))
+    ADD_INITD	:= $(CHKCONFIG) --add dahdi
+  else
+    ifneq (,$(UPDATE_RCD))
+      ADD_INITD	:= $(UPDATE_RCD) dahdi defaults 15 30
+    endif
+  endif
+endif
+
+INITRD_DIR	:= $(firstword $(wildcard $(DESTDIR)/etc/rc.d/init.d $(DESTDIR)/etc/init.d))
+ifneq (,$(INITRD_DIR))
+  INIT_TARGET	:= $(INITRD_DIR)/dahdi
+  COPY_INITD	:= install -D dahdi.init $(INIT_TARGET)
+endif
+
+RCCONF_FILE	= /etc/dahdi/init.conf
+MODULES_FILE	= /etc/dahdi/modules
+GENCONF_FILE	= /etc/dahdi/genconf_parameters
+MODPROBE_FILE	= /etc/modprobe.d/dahdi.conf
+BLACKLIST_FILE	= /etc/modprobe.d/dahdi.blacklist.conf
+
+NETSCR_DIR	:= $(firstword $(wildcard $(DESTDIR)/etc/sysconfig/network-scripts ))
+ifneq (,$(NETSCR_DIR))
+  NETSCR_TARGET	:= $(NETSCR_DIR)/ifup-hdlc
+  COPY_NETSCR	:= install -D ifup-hdlc $(NETSCR_TARGET)
+endif
+
+ifneq ($(wildcard .version),)
+  TOOLSVERSION:=$(shell cat .version)
+else
+ifneq ($(wildcard .svn),)
+  TOOLSVERSION=$(shell build_tools/make_version . dahdi/tools)
+endif
+endif
+
+LTZ_A:=libtonezone.a
+LTZ_A_OBJS:=zonedata.o tonezone.o version.o
+LTZ_SO:=libtonezone.so
+LTZ_SO_OBJS:=zonedata.lo tonezone.lo version.o
+LTZ_SO_MAJOR_VER:=2
+LTZ_SO_MINOR_VER:=0
+
+# sbindir, libdir, includedir and mandir are defined in makeopts
+# (from configure).
+BIN_DIR:=$(sbindir)
+LIB_DIR:=$(libdir)
+INC_DIR:=$(includedir)/dahdi
+MAN_DIR:=$(mandir)/man8
+CONFIG_DIR:=$(sysconfdir)/dahdi
+CONFIG_FILE:=$(CONFIG_DIR)/system.conf
+
+# Utilities we build with a standard build procedure:
+UTILS		= dahdi_tool dahdi_test dahdi_monitor dahdi_speed sethdlc dahdi_cfg \
+		  fxstest fxotune dahdi_diag dahdi_scan
+
+# some tests:
+UTILS		+= patgen pattest patlooptest hdlcstress hdlctest hdlcgen \
+		   hdlcverify timertest dahdi_maint
+
+BINS:=fxotune fxstest sethdlc dahdi_cfg dahdi_diag dahdi_monitor dahdi_speed dahdi_test dahdi_scan dahdi_tool dahdi_maint
+BINS:=$(filter-out $(MENUSELECT_UTILS),$(BINS))
+MAN_PAGES:=$(wildcard $(BINS:%=doc/%.8))
+
+TEST_BINS:=patgen pattest patlooptest hdlcstress hdlctest hdlcgen hdlcverify timertest dahdi_maint
+# All the man pages. Not just installed ones:
+GROFF_PAGES	:= $(wildcard doc/*.8 xpp/*.8)
+GROFF_HTML	:= $(GROFF_PAGES:%=%.html)
+
+GENERATED_DOCS	:= $(GROFF_HTML) README.html README.Astribank.html
+
+all: menuselect.makeopts 
+	@$(MAKE) _all
+
+_all: prereq programs
+
+libs: $(LTZ_SO) $(LTZ_A)
+
+utils-subdirs:
+	@for dir in $(SUBDIRS_UTILS); do \
+		$(MAKE) -C $$dir; \
+	done
+
+programs: libs utils
+
+utils: $(BINS) utils-subdirs
+
+version.c: FORCE
+	@TOOLSVERSION="${TOOLSVERSION}" build_tools/make_version_c > $@.tmp
+	@if cmp -s $@.tmp $@ ; then :; else \
+		mv $@.tmp $@ ; \
+	fi
+	@rm -f $@.tmp
+
+tests: $(TEST_BINS)
+
+$(UTILS): %: %.o
+
+$(UTILS): version.o
+
+%.o: %.c
+	$(CC) $(CFLAGS) $(MAKE_DEPS) -c -o $@ $<
+
+%.lo: %.c
+	$(CC) $(CFLAGS) $(MAKE_DEPS) -c -o $@ $<
+
+%: %.o
+	$(CC) $(LDFLAGS) $^ $(LIBS) -o $@
+
+prereq: config.status
+
+dahdi_tool: CFLAGS+=$(NEWT_INCLUDE)
+dahdi_tool: LIBS+=$(NEWT_LIB)
+
+dahdi_speed: CFLAGS+=-O0
+
+$(LTZ_A): $(LTZ_A_OBJS)
+	ar rcs $@ $^
+	ranlib $@
+
+$(LTZ_SO): $(LTZ_SO_OBJS)
+	$(CC) $(CFLAGS) -shared -Wl,-soname,$(LTZ_SO).$(LTZ_SO_MAJOR_VER).$(LTZ_SO_MINOR_VER) -o $@ $^ -lm
+
+dahdi_cfg: $(LTZ_A)
+dahdi_cfg: LIBS+=-lm
+
+fxstest: $(LTZ_SO)
+fxstest: LIBS+=-lm
+fxotune: LIBS+=-lm
+
+tonezones.txt: zonedata.c
+	perl -ne 'next unless (/\.(country|description) = *"([^"]*)/); \
+		print (($$1 eq "country")? "* $$2\t":"$$2\n");' $<  \
+	>$@
+
+%.asciidoc: %.sample
+	perl -n -e \
+		'if (/^#($$|\s)(.*)/){ if (!$$in_doc){print "\n"}; $$in_doc=1; print "$$2\n" } else { if ($$in_doc){print "\n"}; $$in_doc=0; print "  $$_" }' \
+		$< \
+	| perl -p -e 'if (/^  #?(\w+)=/ && ! exists $$cfgs{$$1}){my $$cfg = $$1; $$cfgs{$$cfg} = 1; s/^/\n[[cfg_$$cfg]]\n/}'  >$@
+
+docs: $(GENERATED_DOCS)
+
+genconf_parameters.sample: xpp/genconf_parameters
+	cp $< $@
+
+README.html: README system.conf.asciidoc init.conf.asciidoc tonezones.txt \
+  UPGRADE.txt genconf_parameters.asciidoc
+	$(ASCIIDOC) -n -a toc -a toclevels=3 $<
+
+README.Astribank.html: xpp/README.Astribank
+	$(ASCIIDOC) -o $@ -n -a toc -a toclevels=4 $<
+
+# on Debian: this requires the full groof, not just groff-base.
+%.8.html: %.8
+	man -Thtml $^ >$@
+
+htmlman: $(GROFF_HTML)
+
+install: all install-programs
+	@echo "###################################################"
+	@echo "###"
+	@echo "### DAHDI tools installed successfully."
+	@echo "### If you have not done so before, install init scripts with:"
+	@echo "###"
+	@echo "###   make config"
+	@echo "###"
+	@echo "###################################################"
+
+install-programs: install-utils install-libs
+
+install-utils: utils install-utils-subdirs
+ifneq (,$(BINS))
+	install -d $(DESTDIR)$(BIN_DIR)
+	install  $(BINS) $(DESTDIR)$(BIN_DIR)/
+	install -d $(DESTDIR)$(MAN_DIR)
+	install -m 644 $(MAN_PAGES) $(DESTDIR)$(MAN_DIR)/
+endif
+ifeq (,$(wildcard $(DESTDIR)$(CONFIG_FILE)))
+	$(INSTALL) -d $(DESTDIR)$(CONFIG_DIR)
+	$(INSTALL) -m 644 system.conf.sample $(DESTDIR)$(CONFIG_FILE)
+endif
+
+install-libs: libs
+	$(INSTALL) -d -m 755 $(DESTDIR)/$(LIB_DIR)
+	$(INSTALL) -m 755 $(LTZ_A) $(DESTDIR)$(LIB_DIR)/
+	$(INSTALL) -m 755 $(LTZ_SO) $(DESTDIR)$(LIB_DIR)/$(LTZ_SO).$(LTZ_SO_MAJOR_VER).$(LTZ_SO_MINOR_VER)
+ifeq (,$(DESTDIR))
+	if [ `id -u` = 0 ]; then \
+		/sbin/ldconfig || : ;\
+	fi
+endif
+	rm -f $(DESTDIR)$(LIB_DIR)/$(LTZ_SO)
+	$(LN) -sf $(LTZ_SO).$(LTZ_SO_MAJOR_VER).$(LTZ_SO_MINOR_VER) \
+		$(DESTDIR)$(LIB_DIR)/$(LTZ_SO).$(LTZ_SO_MAJOR_VER)
+	$(LN) -sf $(LTZ_SO).$(LTZ_SO_MAJOR_VER).$(LTZ_SO_MINOR_VER) \
+		$(DESTDIR)$(LIB_DIR)/$(LTZ_SO)
+	# Overwrite the 1.0 links out there.  dahdi-tools 2.0.0 installed
+	# 1.0 links but dahdi-tools changed them to 2.0 in order to explicitly
+	# break applications linked with zaptel.  But, this also meant that
+	# applications linked with libtonezone.so.1.0 broke when dahdi-tools
+	# 2.1.0 was installed.
+	$(LN) -sf $(LTZ_SO).$(LTZ_SO_MAJOR_VER).$(LTZ_SO_MINOR_VER) \
+		$(DESTDIR)$(LIB_DIR)/$(LTZ_SO).1.0
+	$(LN) -sf $(LTZ_SO).$(LTZ_SO_MAJOR_VER).$(LTZ_SO_MINOR_VER) \
+		$(DESTDIR)$(LIB_DIR)/$(LTZ_SO).1
+ifneq (no,$(USE_SELINUX))
+  ifeq (,$(DESTDIR))
+	/sbin/restorecon -v $(DESTDIR)$(LIB_DIR)/$(LTZ_SO)
+  endif
+endif
+	$(INSTALL) -d -m 755 $(DESTDIR)/$(INC_DIR)
+	$(INSTALL) -m 644 tonezone.h $(DESTDIR)$(INC_DIR)/
+
+install-utils-subdirs:
+	@for dir in $(SUBDIRS_UTILS); do \
+		$(MAKE) -C $$dir install; \
+	done
+
+config:
+ifneq (,$(COPY_INITD))
+	$(COPY_INITD)
+endif
+ifeq (,$(wildcard $(DESTDIR)$(RCCONF_FILE)))
+	$(INSTALL) -D -m 644 init.conf.sample $(DESTDIR)$(RCCONF_FILE)
+endif
+ifeq (,$(wildcard $(DESTDIR)$(MODULES_FILE)))
+	$(INSTALL) -D -m 644 modules.sample $(DESTDIR)$(MODULES_FILE)
+endif
+ifeq (,$(wildcard $(DESTDIR)$(GENCONF_FILE)))
+	$(INSTALL) -D -m 644 xpp/genconf_parameters $(DESTDIR)$(GENCONF_FILE)
+endif
+ifeq (,$(wildcard $(DESTDIR)$(MODPROBE_FILE)))
+	$(INSTALL) -D -m 644 modprobe.conf.sample $(DESTDIR)$(MODPROBE_FILE)
+endif
+ifeq (,$(wildcard $(DESTDIR)$(BLACKLIST_FILE)))
+	$(INSTALL) -D -m 644 blacklist.sample $(DESTDIR)$(BLACKLIST_FILE)
+endif
+ifneq (,$(COPY_NETSCR))
+	$(COPY_NETSCR)
+endif
+ifneq (,$(ADD_INITD))
+	$(ADD_INITD)
+endif
+	@echo "DAHDI has been configured."
+	@echo ""
+	@echo "List of detected DAHDI devices:"
+	@echo ""
+	@if [ `xpp/dahdi_hardware | tee /dev/stderr | wc -l` -eq 0 ]; then \
+		echo "No hardware found"; \
+	else \
+		echo ""; \
+		echo "run 'dahdi_genconf modules' to load support for only " ;\
+		echo "the DAHDI hardware installed in this system.  By "; \
+		echo "default support for all DAHDI hardware is loaded at "; \
+		echo "DAHDI start. "; \
+	fi
+
+update:
+	@if [ -d .svn ]; then \
+		echo "Updating from Subversion..." ; \
+		svn update | tee update.out; \
+		rm -f .version; \
+		if [ `grep -c ^C update.out` -gt 0 ]; then \
+			echo ; echo "The following files have conflicts:" ; \
+			grep ^C update.out | cut -b4- ; \
+		fi ; \
+		rm -f update.out; \
+	else \
+		echo "Not under version control";  \
+	fi
+
+clean:
+	-@$(MAKE) -C menuselect clean
+	rm -f $(BINS) $(TEST_BINS)
+	rm -f *.o dahdi_cfg tzdriver sethdlc
+	rm -f $(LTZ_SO) $(LTZ_A) *.lo
+	@for dir in $(SUBDIRS_UTILS_ALL); do \
+		$(MAKE) -C $$dir clean; \
+	done
+	@for dir in $(SUBDIRS_UTILS); do \
+		$(MAKE) -C $$dir clean; \
+	done
+	rm -f libtonezone*
+	rm -f fxotune
+	rm -f core
+	rm -f dahdi_cfg-shared fxstest
+	rm -rf $(GENERATED_DOCS) *.asciidoc tonezones.txt
+
+distclean: dist-clean
+
+dist-clean: clean
+	@$(MAKE) -C menuselect dist-clean
+	rm -f makeopts menuselect.makeopts menuselect-tree build_tools/menuselect-deps
+	rm -f config.log config.status
+	rm -f .*.d
+
+config.status: configure
+	@CFLAGS="" ./configure
+	@echo "****"
+	@echo "**** The configure script was just executed, so 'make' needs to be"
+	@echo "**** restarted."
+	@echo "****"
+	@exit 1
+
+menuselect.makeopts: menuselect/menuselect menuselect-tree makeopts
+	menuselect/menuselect --check-deps $@ $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS)
+
+menuconfig: menuselect
+
+cmenuconfig: cmenuselect
+
+gmenuconfig: gmenuselect
+
+nmenuconfig: nmenuselect
+
+menuselect: menuselect/cmenuselect menuselect/nmenuselect menuselect/gmenuselect
+	@if [ -x menuselect/nmenuselect ]; then \
+		$(MAKE) nmenuselect; \
+	elif [ -x menuselect/cmenuselect ]; then \
+		$(MAKE) cmenuselect; \
+	elif [ -x menuselect/gmenuselect ]; then \
+		$(MAKE) gmenuselect; \
+	else \
+		echo "No menuselect user interface found. Install ncurses,"; \
+		echo "newt or GTK libraries to build one and re-rerun"; \
+		echo "'make menuselect'."; \
+	fi
+
+cmenuselect: menuselect/cmenuselect menuselect-tree
+	- at menuselect/cmenuselect menuselect.makeopts $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS) && echo "menuselect changes saved!" || echo "menuselect changes NOT saved!"
+
+gmenuselect: menuselect/gmenuselect menuselect-tree
+	- at menuselect/gmenuselect menuselect.makeopts $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS) && echo "menuselect changes saved!" || echo "menuselect changes NOT saved!"
+
+nmenuselect: menuselect/nmenuselect menuselect-tree
+	- at menuselect/nmenuselect menuselect.makeopts $(GLOBAL_MAKEOPTS) $(USER_MAKEOPTS) && echo "menuselect changes saved!" || echo "menuselect changes NOT saved!"
+
+# options for make in menuselect/
+MAKE_MENUSELECT=CC="$(HOST_CC)" CXX="$(CXX)" LD="" AR="" RANLIB="" CFLAGS="" $(MAKE) -C menuselect CONFIGURE_SILENT="--silent"
+
+menuselect/menuselect: menuselect/makeopts
+	+$(MAKE_MENUSELECT) menuselect
+
+menuselect/cmenuselect: menuselect/makeopts
+	+$(MAKE_MENUSELECT) cmenuselect
+
+menuselect/gmenuselect: menuselect/makeopts
+	+$(MAKE_MENUSELECT) gmenuselect
+
+menuselect/nmenuselect: menuselect/makeopts
+	+$(MAKE_MENUSELECT) nmenuselect
+
+menuselect/makeopts: makeopts
+	+$(MAKE_MENUSELECT) makeopts
+
+menuselect-tree: dahdi.xml
+	@echo "Generating input for menuselect ..."
+	@build_tools/make_tree > $@
+
+.PHONY: menuselect distclean dist-clean clean all _all install programs tests devel data config update install-programs install-libs install-utils-subdirs utils-subdirs prereq
+
+FORCE:
+
+ifneq ($(wildcard .*.d),)
+   include .*.d
+endif
diff --git a/README b/README
new file mode 100644
index 0000000..a298a6b
--- /dev/null
+++ b/README
@@ -0,0 +1,233 @@
+DAHDI Telephony Interface Driver
+=================================
+Asterisk Development Team <asteriskteam at digium.com>
+$Revision$, $Date$
+
+DAHDI stands for Digium Asterisk Hardware Device Interface. This
+package contains the userspace tools to configure the kernel modules
+included in the package dahdi-linux.
+
+Build Requirements
+------------------
+This package needs the headers from dahdi-linux. Thus you should install
+dahdi-linux before building dahdi-tools.
+
+Build System
+~~~~~~~~~~~~
+gcc and friends. Generally you will need to install the package gcc.
+There may be cases where you will need a specific version of gcc to build
+kernel modules.
+
+
+Extra Libraries
+~~~~~~~~~~~~~~~
+Some libraries are needed for extra utilities that are provided with
+DAHDI.
+
+- libusb is needed for building fpga_load, needed for firmware loading of
+  the Xorcom Astribank.
+- libnewt is needed to build the optional but useful utility dahdi_tool.
+
+
+Installation
+~~~~~~~~~~~~
+Note: If using `sudo` to build/install, you may need to add /sbin to your PATH.
+----------------------------------
+./configure
+# optional step: select custom configuration:
+#make menuselect
+make
+make install
+# To install init scripts and config files:
+#make config
+----------------------------------
+
+
+Build Tweaks
+~~~~~~~~~~~~
+Partial Build/Install
+^^^^^^^^^^^^^^^^^^^^^
+There are some make targets that are provided to build or install just
+parts of DAHDI:
+
+. Build targets:
+  - make: Build DAHDI userspace programs. partial 
+    targets of it:
+    * make 'utilname': builds 'utilname' alone (e.g: `make dahdi_diag`)
+    * make utils: Build libtonezone.
+    * make libs: Build libtonezone.
+. Install targets:
+  - make install: Installs user space tools into /usr/sbin/ (TODO - list
+    partial targets)
+  - make config: should be run once to configure 
+
+
+Installation to a Subtree
+^^^^^^^^^^^^^^^^^^^^^^^^^
+The following may be useful when testing the package or when preparing a
+package for a binary distribution (such as an rpm package) installing
+onto a subtree rather than on th real system. 
+
+  make install DESTDIR=targetdir
+
+This can be useful for any partial install target from the list above.
+
+
+Options For ./configure
+^^^^^^^^^^^^^^^^^^^^^^^
+The configure script various several tests and based on them generates
+some files ( build_tools/menuselect-deps and makeopts). You can pass it
+--with options and variable settings, for instance:
+
+  ./configure --without-ncurses CC="gcc-4.10"
+
+If you just want to recreate the same files without a full detection
+run, use:
+
+  ./config.status
+
+To re-run ./configure with the same parameters it was run with last
+time, use:
+
+  ./ocnfig.status --recheck
+
+
+Configuration
+-------------
+Configuration for DAHDI resides under /etc/dahdi . 
+
+/etc/dahdi/system.conf
+~~~~~~~~~~~~~~~~~~~~~~
+The main method to configure DAHDI devices is using the utility
+*dahdi_cfg*. dahdi_cfg reads data from the configuration file 
+/etc/dahdi/system.conf , figures out what configuration to send to 
+channels, and send it to the kernel.
+
+A sample annotated system.conf is included in this directory and
+installed by default. Edit it to suit your configuration. Alternatively 
+use the script dahdi_genconf to generate one that should work with your 
+system.
+
+/etc/dahdi/init.conf
+~~~~~~~~~~~~~~~~~~~~
+The configuration file of the dahdi init.d script is
+/etc/dahdi/init.conf . That file is used to override defaults that are 
+set at the beginning of the init.d script.
+
+Reference Configuration
+~~~~~~~~~~~~~~~~~~~~~~~
+Sample system.conf
+~~~~~~~~~~~~~~~~~~
+include::system.conf.asciidoc[]
+
+
+Sample init.conf
+~~~~~~~~~~~~~~~~
+include::init.conf.asciidoc[]
+
+
+Sample genconf_parameters
+~~~~~~~~~~~~~~~~~~~~~~~~~
+FIXME: still not properly formatted.
+
+include::genconf_parameters.asciidoc[]
+
+
+Tonezones
+~~~~~~~~~
+The file zonedata.c contains the information about the tone zones used
+in libtonezone (and hence also in ztcfg). Here is a list of those zones:
+
+include::tonezones.txt[]
+
+
+DAHDI PERL modules
+~~~~~~~~~~~~~~~~~~
+The directory xpp has, in addition to helper utilities for the
+Xorcom Astribank, a collection of perl modules to provide information
+related to DAHDI. The perl modules themselves are under xpp/perl_modules/ .
+In xpp/ there are several utilities that use those modules:
+- xpp-specific: dahdi_registration, xpp_sync, xpp_blink .
+- General: lsdahdi, dahdi_genconf, dahdi_hardware, dahdi_drivers
+
+The DAHDI perl modules will currently only be automatically installed if you
+happen to install the xpp directory. Those utilities require the perl modules 
+to be installed, however they will also look for them in the directory 
+perl_modules, and thus can be run directly from the DAHDI source tree. For 
+example:
+
+  ./xpp/dahdi_hardware -v
+
+To get usage information on a program, you can also use perldoc
+(sometimes provided in a package separate from perl itself). For
+instance:
+
+  perldoc ./xpp/lsdahdi
+
+Some of them are specific for the Xorcom Astribank and described in its
+docuemntation. the others are:
+
+lsdahdi:: 
+  A somewhat glorified `cat /proc/dahdi/*`.
+dahdi_genconf::
+  Generates configuration based on the existing DAHDI channels and on
+  /etc/dahdi/genconf_parameters (replaces genzaptelconf as well).
+dahdi_drivers::
+  A two-liner script (not installed by default) that simply returns the
+  modules that should be modprobed on this system.
+dahdi_hardware:: 
+  Uses the information from sysfs and its own knowledge to show
+  what PCI/USB DAHDI hardware is connected and if it is currently used
+  by a driver. Shows also some more information for Astribanks from
+  /proc/xpp .
+
+
+PPP Support
+~~~~~~~~~~~
+DAHDI digital cards can provide data channels through ppp as
+point-to-point connections. This requires a plugin to the ppp daemon
+that is included in the ppp/ subdirectory. To install it:
+
+1. Make sure you have the PPP source / headers installed. On Debian:
+
+   apt-get install ppp-dev
+
+2. Run 'make' on the ppp subdirectory:
+
+   make -C ppp 
+   make -C ppp install
+
+3. Make sure your kernel has support for both PPP (which is common is
+   distribution kernels and for HDLC (much less common) - CONFIG_PPP and
+   CONFIG_HDLC .
+
+
+include::UPGRADE.txt[]
+
+
+License
+-------
+This package is distributed under the terms of the GNU General Public License
+Version 2, except for some components which are distributed under the terms of
+the GNU Lesser General Public License Version 2.1. Both licenses are included
+in this directory, and each file is clearly marked as to which license applies.
+
+If you wish to use the DAHDI drivers in an application for which the license
+terms are not appropriate (e.g. a proprietary embedded system), licenses under
+more flexible terms can be readily obtained through Digium, Inc. at reasonable
+cost.
+
+
+Reporting Bugs
+--------------
+Please report bug and patches to the Asterisk bug tracker at
+http://bugs.digium.com/[] in the "DAHDI" category.
+
+
+Links
+-----
+- http://asterisk.org/[] - The Asterisk PBX
+- http://voip-info.org/[]
+- http://voip-info.org/wiki/view/DAHDI[]
+- http://docs.tzafrir.org.il/dahdi-tools/README.html[Up-to-date HTML version
+  of this file]
diff --git a/UPGRADE.txt b/UPGRADE.txt
new file mode 100644
index 0000000..f26e09d
--- /dev/null
+++ b/UPGRADE.txt
@@ -0,0 +1,103 @@
+Upgrade Notes
+-------------
+
+Information for upgrading from Zaptel 1.2 or 1.4 to DAHDI 2.0
+
+Upgrading from Zaptel to DAHDI is fairly straightforward; install this
+package using the installation instructions, and then reconfigure and
+rebuild Asterisk; Asterisk 1.4 releases later than 1.4.21, and all
+releases of Asterisk 1.6, will automatically use DAHDI in preference
+to Zaptel, even if Zaptel is still installed on the system.
+
+Important notes about upgrading:
+
+The Zaptel package, which included both kernel modules and userspace
+tools for configuring and managing the modules, has been split into
+two packages:
+
+* dahdi-linux: kernel modules
+* dahdi-tools: userspace tools
+
+In addition, there is a dahdi-linux-complete package that contains both
+dahdi-linux and dahdi-tools for simplified installation.
+
+NOTE: The dahdi-linux and dahdi-tools packages have *separate*
+version numbers; they will not be released 'in sync', and it is
+perfectly acceptable to use (for example) dahdi-tools 2.0.6 with
+dahdi-linux 2.0.11. The dahdi-linux-complete package version number will
+always include *both* of these version numbers so that you will know
+what is included in it.
+
+
+DAHDI-Linux
+~~~~~~~~~~~
+Module Names
+^^^^^^^^^^^^
+The primary kernel modules have changed names; the new names are:
+
+      zaptel.ko	     ->	     dahdi.ko
+      ztd-eth.ko     ->	     dahdi_dynamic_eth.ko
+      ztd-loc.ko     ->	     dahdi_dynamic_loc.ko
+      ztdummy.ko     ->	     dahdi_dummy.ko
+      ztdynamic.ko   ->	     dahdi_dynamic.ko
+      zttranscode.ko ->	     dahdi_transcode.ko
+
+* The kernel modules for card drivers have *not* changed names,
+  although the wcusb and torisa drivers are no longer included.
+
+* This package no longer includes the 'menuselect' utility for
+  choosing which modules to build; all modules that can be built are
+  built automatically.
+
+
+Echo Canceller Modules
+^^^^^^^^^^^^^^^^^^^^^^
+It is no longer possible and needed to select a software echo canceler 
+at compile time to build into dahdi.ko; all four included echo
+cancelers (MG2, KB1, SEC and SEC2) are built as loadable modules.
+If the Digium HPEC binary object file has been placed into the
+proper directory the HPEC module will be built as well. 
+
+Any or all of these modules can be loaded at the same time, and the echo
+canceler to be used on the system's channels can be configured using
+the dahdi_cfg tool from the dahdi-tools package.
+
+IMPORTANT: It is *mandatory* to configure an echo canceler for the
+system's channels using dahdi_cfg unless the interface cards in use
+have echo canceler modules available and enabled. There is *no*
+default software echo canceler with DAHDI. See
+<<_echo_cancellers,section on echo cancellers>> in sample system.conf.
+
+
+DAHDI-Tools
+~~~~~~~~~~~
+Many tool names have changed:
+
+      ztcfg      ->  dahdi_cfg
+      ztmonitor  ->  dahdi_monitor
+      ztscan     ->  dahdi_scan
+      ztspeed    ->  dahdi_speed
+      zttest     ->  dahdi_test
+      zttool     ->  dahdi_tool
+      zapconf    ->  dahdi_genconf (deprecates genzaptelconf)
+
+* The system configuration file has moved from /etc/zaptel.conf to
+  <<_sample_system_conf,/etc/dahdi/system.conf>>.
+
+* The dahdi_cfg tool can now be used to select an echo canceler on a
+  channel-by-channel basis in the system configuration file; see
+  system.conf.sample for examples of how to do this.
+
+* The configuration for XPP init_card_* scripts is done now
+  in /etc/dahdi/xpp.conf and uses a simple syntax (example included).
+  For PRI modules, the 'pri_protocol' setting, determines how
+  to configure it (E1/T1).
+
+* In Astribank PRI modules, the LED behaviour represents which ports
+  are *CLOCK MASTER* (red color) and which are *CLOCK SLAVE* (green color).
+  Usually (but not always), this corresponds to the NT/TE settings in Asterisk.
+
+* The /etc/sysconfig/zaptel (or /etc/default/zaptel file, depending
+  on your distribution) is now split into two separate files:
+  /etc/dahdi/modules control which modules are loaded and module options are
+  set via /etc/modprobe.d/dahdi.  
diff --git a/acinclude.m4 b/acinclude.m4
new file mode 100644
index 0000000..587445e
--- /dev/null
+++ b/acinclude.m4
@@ -0,0 +1,1113 @@
+# Various support functions for configure.ac in asterisk
+#
+
+# Helper function to check for gcc attributes.
+# AST_GCC_ATTRIBUTE([attribute name])
+
+AC_DEFUN([AST_GCC_ATTRIBUTE],
+[
+AC_MSG_CHECKING(for compiler 'attribute $1' support)
+saved_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -Werror"
+AC_COMPILE_IFELSE(
+	AC_LANG_PROGRAM([static void __attribute__(($1)) *test(void *muffin, ...) {}],
+			[]),
+	AC_MSG_RESULT(yes)
+	AC_DEFINE_UNQUOTED([HAVE_ATTRIBUTE_$1], 1, [Define to 1 if your GCC C compiler supports the '$1' attribute.]),
+	AC_MSG_RESULT(no))
+]
+CFLAGS="$saved_CFLAGS"
+)
+
+# Helper function to setup variables for a package.
+# $1 -> the package name. Used in configure.ac and also as a prefix
+#	for the variables ($1_DIR, $1_INCLUDE, $1_LIB) in makeopts
+# $3 ->	option name, used in --with-$3 or --without-$3 when calling configure.
+# $2 and $4 are just text describing the package (short and long form)
+
+# AST_EXT_LIB_SETUP([package], [short description], [configure option name], [long description])
+
+AC_DEFUN([AST_EXT_LIB_SETUP],
+[
+    $1_DESCRIP="$2"
+    $1_OPTION="$3"
+    AC_ARG_WITH([$3], AC_HELP_STRING([--with-$3=PATH],[use $2 files in PATH $4]),
+    [
+	case ${withval} in
+	n|no)
+	USE_$1=no
+	;;
+	y|ye|yes)
+	ac_mandatory_list="${ac_mandatory_list} $1"
+	;;
+	*)
+	$1_DIR="${withval}"
+	ac_mandatory_list="${ac_mandatory_list} $1"
+	;;
+	esac
+    ])
+    PBX_$1=0
+    AC_SUBST([$1_LIB])
+    AC_SUBST([$1_INCLUDE])
+    AC_SUBST([$1_DIR])
+    AC_SUBST([PBX_$1])
+])
+
+# Check whether any of the mandatory modules are not present, and
+# print error messages in case. The mandatory list is built using
+# --with-* arguments when invoking configure.
+
+AC_DEFUN([AST_CHECK_MANDATORY],
+[
+	AC_MSG_CHECKING([for mandatory modules: ${ac_mandatory_list}])
+	err=0;
+	for i in ${ac_mandatory_list}; do
+		eval "a=\${PBX_$i}"
+		if test "x${a}" = "x1" ; then continue; fi
+		if test ${err} = "0" ; then AC_MSG_RESULT(fail) ; fi
+		AC_MSG_RESULT()
+		eval "a=\${${i}_OPTION}"
+		AC_MSG_NOTICE([***])
+		AC_MSG_NOTICE([*** The $i installation appears to be missing or broken.])
+		AC_MSG_NOTICE([*** Either correct the installation, or run configure])
+		AC_MSG_NOTICE([*** including --without-${a}.])
+		err=1
+	done
+	if test $err = 1 ; then exit 1; fi
+	AC_MSG_RESULT(ok)
+])
+
+# The next three functions check for the availability of a given package.
+# AST_C_DEFINE_CHECK looks for the presence of a #define in a header file,
+# AST_C_COMPILE_CHECK can be used for testing for various items in header files,
+# AST_EXT_LIB_CHECK looks for a symbol in a given library, or at least
+#	for the presence of a header file.
+# AST_EXT_TOOL_CHECK looks for a symbol in using $1-config to determine CFLAGS and LIBS
+#
+# They are only run if PBX_$1 != 1 (where $1 is the package),
+# so you can call them multiple times and stop at the first matching one.
+# On success, they both set PBX_$1 = 1, set $1_INCLUDE and $1_LIB as applicable,
+# and also #define HAVE_$1 1 and #define HAVE_$1_VERSION ${last_argument}
+# in autoconfig.h so you can tell which test succeeded.
+# They should be called after AST_EXT_LIB_SETUP($1, ...)
+
+# Check if a given macro is defined in a certain header.
+
+# AST_C_DEFINE_CHECK([package], [macro name], [header file], [version])
+AC_DEFUN([AST_C_DEFINE_CHECK],
+[
+    if test "x${PBX_$1}" != "x1"; then
+	AC_MSG_CHECKING([for $2 in $3])
+	saved_cppflags="${CPPFLAGS}"
+	if test "x${$1_DIR}" != "x"; then
+	    $1_INCLUDE="-I${$1_DIR}/include"
+	fi
+	CPPFLAGS="${CPPFLAGS} ${$1_INCLUDE}"
+
+	AC_COMPILE_IFELSE(
+	    [ AC_LANG_PROGRAM( [#include <$3>],
+			       [#if defined($2)
+				int foo = 0;
+			        #else
+			        int foo = bar;
+			        #endif
+				0
+			       ])],
+	    [   AC_MSG_RESULT(yes)
+		PBX_$1=1
+		AC_DEFINE([HAVE_$1], 1, [Define if your system has the $1 headers.])
+		AC_DEFINE([HAVE_$1_VERSION], $4, [Define $1 headers version])
+	    ],
+	    [   AC_MSG_RESULT(no) ] 
+	)
+	CPPFLAGS="${saved_cppflags}"
+    fi
+    AC_SUBST(PBX_$1)
+])
+
+
+# Check if a given expression will compile using a certain header.
+
+# AST_C_COMPILE_CHECK([package], [expression], [header file], [version])
+AC_DEFUN([AST_C_COMPILE_CHECK],
+[
+    if test "x${PBX_$1}" != "x1" -a "${USE_$1}" != "no"; then
+	AC_MSG_CHECKING([if "$2" compiles using $3])
+	saved_cppflags="${CPPFLAGS}"
+	if test "x${$1_DIR}" != "x"; then
+	    $1_INCLUDE="-I${$1_DIR}/include"
+	fi
+	CPPFLAGS="${CPPFLAGS} ${$1_INCLUDE}"
+
+	AC_COMPILE_IFELSE(
+	    [ AC_LANG_PROGRAM( [#include <$3>],
+			       [ $2; ]
+			       )],
+	    [   AC_MSG_RESULT(yes)
+		PBX_$1=1
+		AC_DEFINE([HAVE_$1], 1, [Define if your system has the $1 headers.])
+		AC_DEFINE([HAVE_$1_VERSION], $4, [Define $1 headers version])
+	    ],
+	    [       AC_MSG_RESULT(no) ] 
+	)
+	CPPFLAGS="${saved_cppflags}"
+    fi
+])
+
+
+# Check for existence of a given package ($1), either looking up a function
+# in a library, or, if no function is supplied, only check for the
+# existence of the header files.
+
+# AST_EXT_LIB_CHECK([package], [library], [function], [header],
+#	 [extra libs], [extra cflags], [version])
+AC_DEFUN([AST_EXT_LIB_CHECK],
+[
+if test "x${PBX_$1}" != "x1" -a "${USE_$1}" != "no"; then
+   pbxlibdir=""
+   # if --with-$1=DIR has been specified, use it.
+   if test "x${$1_DIR}" != "x"; then
+      if test -d ${$1_DIR}/lib; then
+      	 pbxlibdir="-L${$1_DIR}/lib"
+      else
+      	 pbxlibdir="-L${$1_DIR}"
+      fi
+   fi
+   pbxfuncname="$3"
+   if test "x${pbxfuncname}" = "x" ; then   # empty lib, assume only headers
+      AST_$1_FOUND=yes
+   else
+      AC_CHECK_LIB([$2], [${pbxfuncname}], [AST_$1_FOUND=yes], [AST_$1_FOUND=no], ${pbxlibdir} $5)
+   fi
+
+   # now check for the header.
+   if test "${AST_$1_FOUND}" = "yes"; then
+      $1_LIB="${pbxlibdir} -l$2 $5"
+      # if --with-$1=DIR has been specified, use it.
+      if test "x${$1_DIR}" != "x"; then
+	 $1_INCLUDE="-I${$1_DIR}/include"
+      fi
+      $1_INCLUDE="${$1_INCLUDE} $6"
+      if test "x$4" = "x" ; then	# no header, assume found
+         $1_HEADER_FOUND="1"
+      else				# check for the header
+         saved_cppflags="${CPPFLAGS}"
+         CPPFLAGS="${CPPFLAGS} ${$1_INCLUDE} $6"
+	 AC_CHECK_HEADER([$4], [$1_HEADER_FOUND=1], [$1_HEADER_FOUND=0])
+         CPPFLAGS="${saved_cppflags}"
+      fi
+      if test "x${$1_HEADER_FOUND}" = "x0" ; then
+         $1_LIB=""
+         $1_INCLUDE=""
+      else
+         if test "x${pbxfuncname}" = "x" ; then		# only checking headers -> no library
+	    $1_LIB=""
+	 fi
+         PBX_$1=1
+         # XXX don't know how to evaluate the description (third argument) in AC_DEFINE_UNQUOTED
+         AC_DEFINE_UNQUOTED([HAVE_$1], 1, [Define this to indicate the ${$1_DESCRIP} library])
+	 AC_DEFINE_UNQUOTED([HAVE_$1_VERSION], [$7], [Define to indicate the ${$1_DESCRIP} library version])
+      fi
+   fi
+fi
+])
+
+
+# Check for a package using $2-config. Similar to AST_EXT_LIB_CHECK,
+# but use $2-config to determine cflags and libraries to use.
+# $3 and $4 can be used to replace --cflags and --libs in the request
+
+# AST_EXT_TOOL_CHECK([package], [tool name], [--cflags], [--libs], [includes], [expression])
+AC_DEFUN([AST_EXT_TOOL_CHECK],
+[
+    if test "x${PBX_$1}" != "x1" -a "${USE_$1}" != "no"; then
+	PBX_$1=0
+	AC_CHECK_TOOL(CONFIG_$1, $2-config, No)
+	if test ! "x${CONFIG_$1}" = xNo; then
+	    if test x"$3" = x ; then A=--cflags ; else A="$3" ; fi
+	    $1_INCLUDE=$(${CONFIG_$1} $A)
+	    if test x"$4" = x ; then A=--libs ; else A="$4" ; fi
+	    $1_LIB=$(${CONFIG_$1} $A)
+	    if test x"$5" != x ; then
+		saved_cppflags="${CPPFLAGS}"
+		if test "x${$1_DIR}" != "x"; then
+		    $1_INCLUDE="-I${$1_DIR}/include"
+		fi
+		CPPFLAGS="${CPPFLAGS} ${$1_INCLUDE}"
+
+		saved_ldflags="${LDFLAGS}"
+		LDFLAGS="${$1_LIB}"
+
+		AC_LINK_IFELSE(
+		    [ AC_LANG_PROGRAM( [ $5 ],
+				       [ $6; ]
+				       )],
+		    [   PBX_$1=1
+			AC_DEFINE([HAVE_$1], 1, [Define if your system has the $1 headers.])
+		    ],
+		    []
+		)
+		CPPFLAGS="${saved_cppflags}"
+		LDFLAGS="${saved_ldflags}"
+	    else
+		PBX_$1=1
+		AC_DEFINE([HAVE_$1], 1, [Define if your system has the $1 libraries.])
+	    fi
+	fi
+    fi
+])
+
+AC_DEFUN([AST_CHECK_GNU_MAKE], [AC_CACHE_CHECK([for GNU make], [ac_cv_GNU_MAKE],
+   ac_cv_GNU_MAKE='Not Found' ;
+   ac_cv_GNU_MAKE_VERSION_MAJOR=0 ;
+   ac_cv_GNU_MAKE_VERSION_MINOR=0 ;
+   for a in make gmake gnumake ; do
+      if test -z "$a" ; then continue ; fi ;
+      if ( sh -c "$a --version" 2> /dev/null | grep GNU  2>&1 > /dev/null ) ;  then
+         ac_cv_GNU_MAKE=$a ;
+         ac_cv_GNU_MAKE_VERSION_MAJOR=`$ac_cv_GNU_MAKE --version | grep "GNU Make" | cut -f3 -d' ' | cut -f1 -d'.'`
+         ac_cv_GNU_MAKE_VERSION_MINOR=`$ac_cv_GNU_MAKE --version | grep "GNU Make" | cut -f2 -d'.' | cut -c1-2`
+         break;
+      fi
+   done ;
+) ;
+if test  "x$ac_cv_GNU_MAKE" = "xNot Found"  ; then
+   AC_MSG_ERROR( *** Please install GNU make.  It is required to build Asterisk!)
+   exit 1
+fi
+AC_SUBST([GNU_MAKE], [$ac_cv_GNU_MAKE])
+])
+
+AC_DEFUN(
+[AST_CHECK_PWLIB], [
+PWLIB_INCDIR=
+PWLIB_LIBDIR=
+AC_LANG_PUSH([C++])
+if test "${PWLIBDIR:-unset}" != "unset" ; then
+  AC_CHECK_HEADER(${PWLIBDIR}/version.h, HAS_PWLIB=1, )
+fi
+if test "${HAS_PWLIB:-unset}" = "unset" ; then
+  if test "${OPENH323DIR:-unset}" != "unset"; then
+    AC_CHECK_HEADER(${OPENH323DIR}/../pwlib/version.h, HAS_PWLIB=1, )
+  fi
+  if test "${HAS_PWLIB:-unset}" != "unset" ; then
+    PWLIBDIR="${OPENH323DIR}/../pwlib"
+  else
+    AC_CHECK_HEADER(${HOME}/pwlib/include/ptlib.h, HAS_PWLIB=1, )
+    if test "${HAS_PWLIB:-unset}" != "unset" ; then
+      PWLIBDIR="${HOME}/pwlib"
+    else
+      AC_CHECK_HEADER(/usr/local/include/ptlib.h, HAS_PWLIB=1, )
+      if test "${HAS_PWLIB:-unset}" != "unset" ; then
+        AC_PATH_PROG(PTLIB_CONFIG, ptlib-config, , /usr/local/bin)
+        if test "${PTLIB_CONFIG:-unset}" = "unset" ; then
+          AC_PATH_PROG(PTLIB_CONFIG, ptlib-config, , /usr/local/share/pwlib/make)
+        fi
+        PWLIB_INCDIR="/usr/local/include"
+        PWLIB_LIBDIR=`${PTLIB_CONFIG} --pwlibdir`
+        if test "${PWLIB_LIBDIR:-unset}" = "unset"; then
+          if test "x$LIB64" != "x"; then
+            PWLIB_LIBDIR="/usr/local/lib64"
+          else
+            PWLIB_LIBDIR="/usr/local/lib"
+          fi
+        fi
+        PWLIB_LIB=`${PTLIB_CONFIG} --ldflags --libs`
+        PWLIB_LIB="-L${PWLIB_LIBDIR} `echo ${PWLIB_LIB}`"
+      else
+        AC_CHECK_HEADER(/usr/include/ptlib.h, HAS_PWLIB=1, )
+        if test "${HAS_PWLIB:-unset}" != "unset" ; then
+          AC_PATH_PROG(PTLIB_CONFIG, ptlib-config, , /usr/share/pwlib/make)
+          PWLIB_INCDIR="/usr/include"
+          PWLIB_LIBDIR=`${PTLIB_CONFIG} --pwlibdir`
+          if test "${PWLIB_LIBDIR:-unset}" = "unset"; then
+            if test "x$LIB64" != "x"; then
+              PWLIB_LIBDIR="/usr/lib64"
+            else
+              PWLIB_LIBDIR="/usr/lib"
+            fi
+          fi
+          PWLIB_LIB=`${PTLIB_CONFIG} --ldflags --libs`
+          PWLIB_LIB="-L${PWLIB_LIBDIR} `echo ${PWLIB_LIB}`"
+        fi
+      fi
+    fi
+  fi
+fi
+
+#if test "${HAS_PWLIB:-unset}" = "unset" ; then
+#  echo "Cannot find pwlib - please install or set PWLIBDIR and try again"
+#  exit
+#fi
+
+if test "${HAS_PWLIB:-unset}" != "unset" ; then
+  if test "${PWLIBDIR:-unset}" = "unset" ; then
+    if test "${PTLIB_CONFIG:-unset}" != "unset" ; then
+      PWLIBDIR=`$PTLIB_CONFIG --prefix`
+    else
+      echo "Cannot find ptlib-config - please install and try again"
+      exit
+    fi
+  fi
+
+  if test "x$PWLIBDIR" = "x/usr" -o "x$PWLIBDIR" = "x/usr/"; then
+    PWLIBDIR="/usr/share/pwlib"
+    PWLIB_INCDIR="/usr/include"
+    if test "x$LIB64" != "x"; then
+      PWLIB_LIBDIR="/usr/lib64"
+    else
+      PWLIB_LIBDIR="/usr/lib"
+    fi
+  fi
+  if test "x$PWLIBDIR" = "x/usr/local" -o "x$PWLIBDIR" = "x/usr/"; then
+    PWLIBDIR="/usr/local/share/pwlib"
+    PWLIB_INCDIR="/usr/local/include"
+    if test "x$LIB64" != "x"; then
+      PWLIB_LIBDIR="/usr/local/lib64"
+    else
+      PWLIB_LIBDIR="/usr/local/lib"
+    fi
+  fi
+
+  if test "${PWLIB_INCDIR:-unset}" = "unset"; then
+    PWLIB_INCDIR="${PWLIBDIR}/include"
+  fi
+  if test "${PWLIB_LIBDIR:-unset}" = "unset"; then
+    PWLIB_LIBDIR="${PWLIBDIR}/lib"
+  fi
+
+  AC_SUBST([PWLIBDIR])
+  AC_SUBST([PWLIB_INCDIR])
+  AC_SUBST([PWLIB_LIBDIR])
+fi
+  AC_LANG_POP([C++])
+])
+
+
+AC_DEFUN(
+[AST_CHECK_OPENH323_PLATFORM], [
+PWLIB_OSTYPE=
+case "$host_os" in
+  linux*)          PWLIB_OSTYPE=linux ;
+  		;;
+  freebsd* )       PWLIB_OSTYPE=FreeBSD ;
+  		;;
+  openbsd* )       PWLIB_OSTYPE=OpenBSD ;
+				   ENDLDLIBS="-lossaudio" ;
+		;;
+  netbsd* )        PWLIB_OSTYPE=NetBSD ;
+				   ENDLDLIBS="-lossaudio" ;
+		;;
+  solaris* | sunos* ) PWLIB_OSTYPE=solaris ;
+		;;
+  darwin* )	       PWLIB_OSTYPE=Darwin ;
+		;;
+  beos*)           PWLIB_OSTYPE=beos ;
+                   STDCCFLAGS="$STDCCFLAGS -D__BEOS__"
+		;;
+  cygwin*)         PWLIB_OSTYPE=cygwin ;
+		;;
+  mingw*)	       PWLIB_OSTYPE=mingw ;
+		           STDCCFLAGS="$STDCCFLAGS -mms-bitfields" ;
+		           ENDLDLIBS="-lwinmm -lwsock32 -lsnmpapi -lmpr -lcomdlg32 -lgdi32 -lavicap32" ;
+		;;
+  * )		       PWLIB_OSTYPE="$host_os" ;
+		           AC_MSG_WARN("OS $PWLIB_OSTYPE not recognized - proceed with caution!") ;
+		;;
+esac
+
+PWLIB_MACHTYPE=
+case "$host_cpu" in
+   x86 | i686 | i586 | i486 | i386 ) PWLIB_MACHTYPE=x86
+                   ;;
+
+   x86_64)	   PWLIB_MACHTYPE=x86_64 ;
+		   P_64BIT=1 ;
+                   LIB64=1 ;
+		   ;;
+
+   alpha | alphaev56 | alphaev6 | alphaev67 | alphaev7) PWLIB_MACHTYPE=alpha ;
+		   P_64BIT=1 ;
+		   ;;
+
+   sparc )         PWLIB_MACHTYPE=sparc ;
+		   ;;
+
+   powerpc )       PWLIB_MACHTYPE=ppc ;
+		   ;;
+
+   ppc )           PWLIB_MACHTYPE=ppc ;
+		   ;;
+
+   powerpc64 )     PWLIB_MACHTYPE=ppc64 ;
+		   P_64BIT=1 ;
+                   LIB64=1 ;
+		   ;;
+
+   ppc64 )         PWLIB_MACHTYPE=ppc64 ;
+		   P_64BIT=1 ;
+                   LIB64=1 ;
+		   ;;
+
+   ia64)	   PWLIB_MACHTYPE=ia64 ;
+		   P_64BIT=1 ;
+	  	   ;;
+
+   s390x)	   PWLIB_MACHTYPE=s390x ;
+		   P_64BIT=1 ;
+                   LIB64=1 ;
+		   ;;
+
+   s390)	   PWLIB_MACHTYPE=s390 ;
+		   ;;
+
+   * )		   PWLIB_MACHTYPE="$host_cpu";
+		   AC_MSG_WARN("CPU $PWLIB_MACHTYPE not recognized - proceed with caution!") ;;
+esac
+
+PWLIB_PLATFORM="${PWLIB_OSTYPE}_${PWLIB_MACHTYPE}"
+
+AC_SUBST([PWLIB_PLATFORM])
+])
+
+
+AC_DEFUN(
+[AST_CHECK_OPENH323], [
+OPENH323_INCDIR=
+OPENH323_LIBDIR=
+AC_LANG_PUSH([C++])
+if test "${OPENH323DIR:-unset}" != "unset" ; then
+  AC_CHECK_HEADER(${OPENH323DIR}/version.h, HAS_OPENH323=1, )
+fi
+if test "${HAS_OPENH323:-unset}" = "unset" ; then
+  AC_CHECK_HEADER(${PWLIBDIR}/../openh323/version.h, OPENH323DIR="${PWLIBDIR}/../openh323"; HAS_OPENH323=1, )
+  if test "${HAS_OPENH323:-unset}" != "unset" ; then
+    OPENH323DIR="${PWLIBDIR}/../openh323"
+    saved_cppflags="${CPPFLAGS}"
+    CPPFLAGS="${CPPFLAGS} -I${PWLIB_INCDIR}/openh323 -I${PWLIB_INCDIR}"
+    AC_CHECK_HEADER(${OPENH323DIR}/include/h323.h, , OPENH323_INCDIR="${PWLIB_INCDIR}/openh323"; OPENH323_LIBDIR="${PWLIB_LIBDIR}", [#include <ptlib.h>])
+    CPPFLAGS="${saved_cppflags}"
+  else
+    saved_cppflags="${CPPFLAGS}"
+    CPPFLAGS="${CPPFLAGS} -I${HOME}/openh323/include -I${PWLIB_INCDIR}"
+    AC_CHECK_HEADER(${HOME}/openh323/include/h323.h, HAS_OPENH323=1, )
+    CPPFLAGS="${saved_cppflags}"
+    if test "${HAS_OPENH323:-unset}" != "unset" ; then
+      OPENH323DIR="${HOME}/openh323"
+    else
+      saved_cppflags="${CPPFLAGS}"
+      CPPFLAGS="${CPPFLAGS} -I/usr/local/include/openh323 -I${PWLIB_INCDIR}"
+      AC_CHECK_HEADER(/usr/local/include/openh323/h323.h, HAS_OPENH323=1, )
+      CPPFLAGS="${saved_cppflags}"
+      if test "${HAS_OPENH323:-unset}" != "unset" ; then
+        OPENH323DIR="/usr/local/share/openh323"
+        OPENH323_INCDIR="/usr/local/include/openh323"
+        if test "x$LIB64" != "x"; then
+          OPENH323_LIBDIR="/usr/local/lib64"
+        else
+          OPENH323_LIBDIR="/usr/local/lib"
+        fi
+      else
+        saved_cppflags="${CPPFLAGS}"
+        CPPFLAGS="${CPPFLAGS} -I/usr/include/openh323 -I${PWLIB_INCDIR}"
+        AC_CHECK_HEADER(/usr/include/openh323/h323.h, HAS_OPENH323=1, , [#include <ptlib.h>])
+        CPPFLAGS="${saved_cppflags}"
+        if test "${HAS_OPENH323:-unset}" != "unset" ; then
+          OPENH323DIR="/usr/share/openh323"
+          OPENH323_INCDIR="/usr/include/openh323"
+          if test "x$LIB64" != "x"; then
+            OPENH323_LIBDIR="/usr/lib64"
+          else
+            OPENH323_LIBDIR="/usr/lib"
+          fi
+        fi
+      fi
+    fi
+  fi
+fi
+
+if test "${HAS_OPENH323:-unset}" != "unset" ; then
+  if test "${OPENH323_INCDIR:-unset}" = "unset"; then
+    OPENH323_INCDIR="${OPENH323DIR}/include"
+  fi
+  if test "${OPENH323_LIBDIR:-unset}" = "unset"; then
+    OPENH323_LIBDIR="${OPENH323DIR}/lib"
+  fi
+
+  OPENH323_LIBDIR="`cd ${OPENH323_LIBDIR}; pwd`"
+  OPENH323_INCDIR="`cd ${OPENH323_INCDIR}; pwd`"
+  OPENH323DIR="`cd ${OPENH323DIR}; pwd`"
+
+  AC_SUBST([OPENH323DIR])
+  AC_SUBST([OPENH323_INCDIR])
+  AC_SUBST([OPENH323_LIBDIR])
+fi
+  AC_LANG_POP([C++])
+])
+
+
+AC_DEFUN(
+[AST_CHECK_PWLIB_VERSION], [
+	if test "${HAS_$2:-unset}" != "unset"; then
+		$2_VERSION=`grep "$2_VERSION" ${$2_INCDIR}/$3 | cut -f2 -d ' ' | sed -e 's/"//g'`
+		$2_MAJOR_VERSION=`echo ${$2_VERSION} | cut -f1 -d.`
+		$2_MINOR_VERSION=`echo ${$2_VERSION} | cut -f2 -d.`
+		$2_BUILD_NUMBER=`echo ${$2_VERSION} | cut -f3 -d.`
+		let $2_VER=${$2_MAJOR_VERSION}*10000+${$2_MINOR_VERSION}*100+${$2_BUILD_NUMBER}
+		let $2_REQ=$4*10000+$5*100+$6
+
+		AC_MSG_CHECKING(if $1 version ${$2_VERSION} is compatible with chan_h323)
+		if test ${$2_VER} -lt ${$2_REQ}; then
+			AC_MSG_RESULT(no)
+			unset HAS_$2
+		else
+			AC_MSG_RESULT(yes)
+		fi
+	fi
+])
+
+
+AC_DEFUN(
+[AST_CHECK_PWLIB_BUILD], [
+	if test "${HAS_$2:-unset}" != "unset"; then
+	   AC_MSG_CHECKING($1 installation validity)
+
+	   saved_cppflags="${CPPFLAGS}"
+	   saved_libs="${LIBS}"
+	   if test "${$2_LIB:-unset}" != "unset"; then
+	      LIBS="${LIBS} ${$2_LIB} $7"
+	   else
+    	      LIBS="${LIBS} -L${$2_LIBDIR} -l${PLATFORM_$2} $7"
+	   fi
+	   CPPFLAGS="${CPPFLAGS} -I${$2_INCDIR} $6"
+
+	   AC_LANG_PUSH([C++])
+
+	   AC_LINK_IFELSE(
+		[AC_LANG_PROGRAM([$4],[$5])],
+		[	AC_MSG_RESULT(yes) 
+			ac_cv_lib_$2="yes" 
+		],
+		[	AC_MSG_RESULT(no) 
+			ac_cv_lib_$2="no" 
+		]
+		)
+
+	   AC_LANG_POP([C++])
+
+	   LIBS="${saved_libs}"
+	   CPPFLAGS="${saved_cppflags}"
+
+	   if test "${ac_cv_lib_$2}" = "yes"; then
+	      if test "${$2_LIB:-undef}" = "undef"; then
+	         if test "${$2_LIBDIR}" != "" -a "${$2_LIBDIR}" != "/usr/lib"; then
+	            $2_LIB="-L${$2_LIBDIR} -l${PLATFORM_$2}"
+	         else
+	            $2_LIB="-l${PLATFORM_$2}"
+	         fi
+	      fi
+	      if test "${$2_INCDIR}" != "" -a "${$2_INCDIR}" != "/usr/include"; then
+	         $2_INCLUDE="-I${$2_INCDIR}"
+	      fi
+	   	  PBX_$2=1
+	   	  AC_DEFINE([HAVE_$2], 1, [$3])
+	   fi
+	fi
+])
+
+AC_DEFUN(
+[AST_CHECK_OPENH323_BUILD], [
+	if test "${HAS_OPENH323:-unset}" != "unset"; then
+		AC_MSG_CHECKING(OpenH323 build option)
+		OPENH323_SUFFIX=
+		prefixes="h323_${PWLIB_PLATFORM}_ h323_ openh323"
+		for pfx in $prefixes; do
+			files=`ls -l ${OPENH323_LIBDIR}/lib${pfx}*.so* 2>/dev/null`
+			libfile=
+			if test -n "$files"; then
+				for f in $files; do
+					if test -f $f -a ! -L $f; then
+						libfile=`basename $f`
+						break;
+					fi
+				done
+			fi
+			if test -n "$libfile"; then
+				OPENH323_PREFIX=$pfx
+				break;
+			fi
+		done
+		if test "${libfile:-unset}" != "unset"; then
+			OPENH323_SUFFIX=`eval "echo ${libfile} | sed -e 's/lib${OPENH323_PREFIX}\(@<:@^.@:>@*\)\..*/\1/'"`
+		fi
+		case "${OPENH323_SUFFIX}" in
+			n)
+				OPENH323_BUILD="notrace";;
+			r)
+				OPENH323_BUILD="opt";;
+			d)
+				OPENH323_BUILD="debug";;
+			*)
+				if test "${OPENH323_PREFIX:-undef}" = "openh323"; then
+					notrace=`eval "grep NOTRACE ${OPENH323DIR}/openh323u.mak | grep = | sed -e 's/@<:@A-Z0-9_@:>@*@<:@ 	@:>@*=@<:@ 	@:>@*//'"`
+					if test "x$notrace" = "x"; then
+						notrace="0"
+					fi
+					if test "$notrace" -ne 0; then
+						OPENH323_BUILD="notrace"
+					else
+						OPENH323_BUILD="opt"
+					fi
+					OPENH323_LIB="-l${OPENH323_PREFIX}"
+				else
+					OPENH323_BUILD="notrace"
+				fi
+				;;
+		esac
+		AC_MSG_RESULT(${OPENH323_BUILD})
+
+		AC_SUBST([OPENH323_SUFFIX])
+		AC_SUBST([OPENH323_BUILD])
+	fi
+])
+
+
+# AST_FUNC_FORK
+# -------------
+AN_FUNCTION([fork],  [AST_FUNC_FORK])
+AN_FUNCTION([vfork], [AST_FUNC_FORK])
+AC_DEFUN([AST_FUNC_FORK],
+[AC_REQUIRE([AC_TYPE_PID_T])dnl
+AC_CHECK_HEADERS(vfork.h)
+AC_CHECK_FUNCS(fork vfork)
+if test "x$ac_cv_func_fork" = xyes; then
+  _AST_FUNC_FORK
+else
+  ac_cv_func_fork_works=$ac_cv_func_fork
+fi
+if test "x$ac_cv_func_fork_works" = xcross; then
+  case $host in
+    *-*-amigaos* | *-*-msdosdjgpp* | *-*-uclinux* | *-*-linux-uclibc* )
+      # Override, as these systems have only a dummy fork() stub
+      ac_cv_func_fork_works=no
+      ;;
+    *)
+      ac_cv_func_fork_works=yes
+      ;;
+  esac
+  AC_MSG_WARN([result $ac_cv_func_fork_works guessed because of cross compilation])
+fi
+ac_cv_func_vfork_works=$ac_cv_func_vfork
+if test "x$ac_cv_func_vfork" = xyes; then
+  _AC_FUNC_VFORK
+fi;
+if test "x$ac_cv_func_fork_works" = xcross; then
+  ac_cv_func_vfork_works=$ac_cv_func_vfork
+  AC_MSG_WARN([result $ac_cv_func_vfork_works guessed because of cross compilation])
+fi
+
+if test "x$ac_cv_func_vfork_works" = xyes; then
+  AC_DEFINE(HAVE_WORKING_VFORK, 1, [Define to 1 if `vfork' works.])
+else
+  AC_DEFINE(vfork, fork, [Define as `fork' if `vfork' does not work.])
+fi
+if test "x$ac_cv_func_fork_works" = xyes; then
+  AC_DEFINE(HAVE_WORKING_FORK, 1, [Define to 1 if `fork' works.])
+fi
+])# AST_FUNC_FORK
+
+
+# _AST_FUNC_FORK
+# -------------
+AC_DEFUN([_AST_FUNC_FORK],
+  [AC_CACHE_CHECK(for working fork, ac_cv_func_fork_works,
+    [AC_RUN_IFELSE(
+      [AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT],
+	[
+	  /* By Ruediger Kuhlmann. */
+	  return fork () < 0;
+	])],
+      [ac_cv_func_fork_works=yes],
+      [ac_cv_func_fork_works=no],
+      [ac_cv_func_fork_works=cross])])]
+)# _AST_FUNC_FORK
+
+# AST_PROG_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([AST_PROG_LD],
+[AC_ARG_WITH([gnu-ld],
+    [AC_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])
+AC_REQUIRE([AST_PROG_SED])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])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])
+AST_PROG_LD_GNU
+])# AST_PROG_LD
+
+
+# AST_PROG_LD_GNU
+# --------------
+AC_DEFUN([AST_PROG_LD_GNU],
+[AC_REQUIRE([AST_PROG_EGREP])dnl
+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
+])# AST_PROG_LD_GNU
+
+# AST_PROG_EGREP
+# -------------
+m4_ifndef([AST_PROG_EGREP], [AC_DEFUN([AST_PROG_EGREP],
+[AC_CACHE_CHECK([for egrep], [ac_cv_prog_egrep],
+   [if echo a | (grep -E '(a|b)') >/dev/null 2>&1
+    then ac_cv_prog_egrep='grep -E'
+    else ac_cv_prog_egrep='egrep'
+    fi])
+ EGREP=$ac_cv_prog_egrep
+ AC_SUBST([EGREP])
+])]) # AST_PROG_EGREP
+
+# AST_PROG_SED
+# -----------
+# Check for a fully functional sed program that truncates
+# as few characters as possible.  Prefer GNU sed if found.
+AC_DEFUN([AST_PROG_SED],
+[AC_CACHE_CHECK([for a sed that does not truncate output], ac_cv_path_SED,
+    [dnl ac_script should not contain more than 99 commands (for HP-UX sed),
+     dnl but more than about 7000 bytes, to catch a limit in Solaris 8 /usr/ucb/sed.
+     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" | sed 99q >conftest.sed
+     $as_unset ac_script || ac_script=
+     _AC_PATH_PROG_FEATURE_CHECK(SED, [sed gsed],
+	[_AC_FEATURE_CHECK_LENGTH([ac_path_SED], [ac_cv_path_SED],
+		["$ac_path_SED" -f conftest.sed])])])
+ SED="$ac_cv_path_SED"
+ AC_SUBST([SED])dnl
+ rm -f conftest.sed
+])# AST_PROG_SED
+
+dnl @synopsis ACX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+dnl
+dnl @summary figure out how to build C programs using POSIX threads
+dnl
+dnl This macro figures out how to build C programs using POSIX threads.
+dnl It sets the PTHREAD_LIBS output variable to the threads library and
+dnl linker flags, and the PTHREAD_CFLAGS output variable to any special
+dnl C compiler flags that are needed. (The user can also force certain
+dnl compiler flags/libs to be tested by setting these environment
+dnl variables.)
+dnl
+dnl Also sets PTHREAD_CC to any special C compiler that is needed for
+dnl multi-threaded programs (defaults to the value of CC otherwise).
+dnl (This is necessary on AIX to use the special cc_r compiler alias.)
+dnl
+dnl NOTE: You are assumed to not only compile your program with these
+dnl flags, but also link it with them as well. e.g. you should link
+dnl with $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS
+dnl $LIBS
+dnl
+dnl If you are only building threads programs, you may wish to use
+dnl these variables in your default LIBS, CFLAGS, and CC:
+dnl
+dnl        LIBS="$PTHREAD_LIBS $LIBS"
+dnl        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+dnl        CC="$PTHREAD_CC"
+dnl
+dnl In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute
+dnl constant has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to
+dnl that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
+dnl
+dnl ACTION-IF-FOUND is a list of shell commands to run if a threads
+dnl library is found, and ACTION-IF-NOT-FOUND is a list of commands to
+dnl run it if it is not found. If ACTION-IF-FOUND is not specified, the
+dnl default action will define HAVE_PTHREAD.
+dnl
+dnl Please let the authors know if this macro fails on any platform, or
+dnl if you have any other suggestions or comments. This macro was based
+dnl on work by SGJ on autoconf scripts for FFTW (www.fftw.org) (with
+dnl help from M. Frigo), as well as ac_pthread and hb_pthread macros
+dnl posted by Alejandro Forero Cuervo to the autoconf macro repository.
+dnl We are also grateful for the helpful feedback of numerous users.
+dnl
+dnl @category InstalledPackages
+dnl @author Steven G. Johnson <stevenj at alum.mit.edu>
+dnl @version 2006-05-29
+dnl @license GPLWithACException
+
+AC_DEFUN([ACX_PTHREAD],
+[
+AC_REQUIRE([AC_CANONICAL_HOST])
+AC_LANG_SAVE
+AC_LANG_C
+acx_pthread_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on True64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
+        save_CFLAGS="$CFLAGS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+        save_LIBS="$LIBS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
+        AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes)
+        AC_MSG_RESULT($acx_pthread_ok)
+        if test x"$acx_pthread_ok" = xno; then
+                PTHREAD_LIBS=""
+                PTHREAD_CFLAGS=""
+        fi
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try.  Items starting with a "-" are
+# C compiler flags, and other items are library names, except for "none"
+# which indicates that we try without any flags at all, and "pthread-config"
+# which is a program returning the flags for the Pth emulation library.
+
+acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important.  Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+#       other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
+# -pthreads: Solaris/gcc
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+#      doesn't hurt to check since this sometimes defines pthreads too;
+#      also defines -D_REENTRANT)
+#      ... -mt is also the pthreads flag for HP/aCC
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case "${host_cpu}-${host_os}" in
+        *solaris*)
+
+        # On Solaris (at least, for some versions), libc contains stubbed
+        # (non-functional) versions of the pthreads routines, so link-based
+        # tests will erroneously succeed.  (We need to link with -pthreads/-mt/
+        # -lpthread.)  (The stubs are missing pthread_cleanup_push, or rather
+        # a function called by this macro, so we could check for that, but
+        # who knows whether they'll stub that too in a future libc.)  So,
+        # we'll just look for -pthreads and -lpthread first:
+
+        acx_pthread_flags="-pthreads pthread -mt -pthread $acx_pthread_flags"
+        ;;
+esac
+
+if test x"$acx_pthread_ok" = xno; then
+for flag in $acx_pthread_flags; do
+
+        case $flag in
+                none)
+                AC_MSG_CHECKING([whether pthreads work without any flags])
+                ;;
+
+                -*)
+                AC_MSG_CHECKING([whether pthreads work with $flag])
+                PTHREAD_CFLAGS="$flag"
+                ;;
+
+		pthread-config)
+		AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no)
+		if test x"$acx_pthread_config" = xno; then continue; fi
+		PTHREAD_CFLAGS="`pthread-config --cflags`"
+		PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+		;;
+
+                *)
+                AC_MSG_CHECKING([for the pthreads library -l$flag])
+                PTHREAD_LIBS="-l$flag"
+                ;;
+        esac
+
+        save_LIBS="$LIBS"
+        save_CFLAGS="$CFLAGS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+        # Check for various functions.  We must include pthread.h,
+        # since some functions may be macros.  (On the Sequent, we
+        # need a special flag -Kthread to make this header compile.)
+        # We check for pthread_join because it is in -lpthread on IRIX
+        # while pthread_create is in libc.  We check for pthread_attr_init
+        # due to DEC craziness with -lpthreads.  We check for
+        # pthread_cleanup_push because it is one of the few pthread
+        # functions on Solaris that doesn't have a non-functional libc stub.
+        # We try pthread_create on general principles.
+        AC_TRY_LINK([#include <pthread.h>],
+                    [pthread_t th; pthread_join(th, 0);
+                     pthread_attr_init(0); pthread_cleanup_push(0, 0);
+                     pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
+                    [acx_pthread_ok=yes])
+
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+
+        AC_MSG_RESULT($acx_pthread_ok)
+        if test "x$acx_pthread_ok" = xyes; then
+                break;
+        fi
+
+        PTHREAD_LIBS=""
+        PTHREAD_CFLAGS=""
+done
+fi
+
+# Various other checks:
+if test "x$acx_pthread_ok" = xyes; then
+        save_LIBS="$LIBS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        save_CFLAGS="$CFLAGS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+
+        # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+	AC_MSG_CHECKING([for joinable pthread attribute])
+	attr_name=unknown
+	for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+	    AC_TRY_LINK([#include <pthread.h>], [int attr=$attr; return attr;],
+                        [attr_name=$attr; break])
+	done
+        AC_MSG_RESULT($attr_name)
+        if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
+            AC_DEFINE_UNQUOTED(PTHREAD_CREATE_JOINABLE, $attr_name,
+                               [Define to necessary symbol if this constant
+                                uses a non-standard name on your system.])
+        fi
+
+        AC_MSG_CHECKING([if more special flags are required for pthreads])
+        flag=no
+        case "${host_cpu}-${host_os}" in
+            *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";;
+            *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";;
+        esac
+        AC_MSG_RESULT(${flag})
+        if test "x$flag" != xno; then
+            PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
+        fi
+
+        LIBS="$save_LIBS"
+        CFLAGS="$save_CFLAGS"
+
+        # More AIX lossage: must compile with xlc_r or cc_r
+	if test x"$GCC" != xyes; then
+          AC_CHECK_PROGS(PTHREAD_CC, xlc_r cc_r, ${CC})
+        else
+          PTHREAD_CC=$CC
+	fi
+else
+        PTHREAD_CC="$CC"
+fi
+
+AC_SUBST(PTHREAD_LIBS)
+AC_SUBST(PTHREAD_CFLAGS)
+AC_SUBST(PTHREAD_CC)
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test x"$acx_pthread_ok" = xyes; then
+        ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1])
+        :
+else
+        acx_pthread_ok=no
+        $2
+fi
+AC_LANG_RESTORE
+])dnl ACX_PTHREAD
diff --git a/autoconfig.h.in b/autoconfig.h.in
new file mode 100644
index 0000000..d95e19c
--- /dev/null
+++ b/autoconfig.h.in
@@ -0,0 +1,102 @@
+/* autoconfig.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define if your system has the DAHDI headers. */
+#undef HAVE_DAHDI
+
+/* Define DAHDI headers version */
+#undef HAVE_DAHDI_VERSION
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <linux/soundcard.h> header file. */
+#undef HAVE_LINUX_SOUNDCARD_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define this to indicate the ${NEWT_DESCRIP} library */
+#undef HAVE_NEWT
+
+/* Define to indicate the ${NEWT_DESCRIP} library version */
+#undef HAVE_NEWT_VERSION
+
+/* 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/soundcard.h> header file. */
+#undef HAVE_SYS_SOUNDCARD_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 this to indicate the ${USB_DESCRIP} library */
+#undef HAVE_USB
+
+/* Define to indicate the ${USB_DESCRIP} library version */
+#undef HAVE_USB_VERSION
+
+/* 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 version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Enable extensions on AIX 3, Interix.  */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris.  */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop.  */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+
+
+/* Define to 1 if on MINIX. */
+#undef _MINIX
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+   this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#undef _POSIX_SOURCE
diff --git a/bittest.h b/bittest.h
new file mode 100644
index 0000000..c9b9eb2
--- /dev/null
+++ b/bittest.h
@@ -0,0 +1,17 @@
+/*
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2 as published by the
+ * Free Software Foundation. See the LICENSE file included with
+ * this program for more details.
+ */
+
+static int bit_next(int prev)
+{
+	return (prev + 1) % 256;
+}
diff --git a/blacklist.sample b/blacklist.sample
new file mode 100644
index 0000000..3e918a2
--- /dev/null
+++ b/blacklist.sample
@@ -0,0 +1,13 @@
+# blacklist all the drivers by default in order to ensure that
+# /etc/init.d/dahdi installs them in the correct order so that the spans are
+# ordered consistently.
+
+blacklist wct4xxp
+blacklist wcte12xp
+blacklist wct1xxp
+blacklist wcte11xp
+blacklist wctdm24xxp
+blacklist wcfxo
+blacklist wctdm
+blacklist wctc4xxp
+blacklist wcb4xxp
diff --git a/bootstrap.sh b/bootstrap.sh
new file mode 100755
index 0000000..570d66c
--- /dev/null
+++ b/bootstrap.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+
+check_for_app() {
+	$1 --version 2>&1 >/dev/null
+	if [ $? != 0 ]
+	then
+		echo "Please install $1 and run bootstrap.sh again!"
+		exit 1
+	fi
+}
+
+# On FreeBSD and OpenBSD, multiple autoconf/automake versions have different names.
+# On linux, envitonment variables tell which one to use.
+
+uname -s | grep -q BSD
+if [ $? = 0 ] ; then	# BSD case
+	case `uname -sr` in
+		'FreeBSD 4'*)	# FreeBSD 4.x has a different naming
+			MY_AC_VER=259
+			MY_AM_VER=19
+			;;
+		*)
+			MY_AC_VER=-2.62
+			MY_AM_VER=-1.9
+			;;
+	esac
+else	# linux case
+	MY_AC_VER=
+	MY_AM_VER=
+	AUTOCONF_VERSION=2.60
+	AUTOMAKE_VERSION=1.9
+	export AUTOCONF_VERSION
+	export AUTOMAKE_VERSION
+fi
+
+check_for_app autoconf${MY_AC_VER}
+check_for_app autoheader${MY_AC_VER}
+check_for_app automake${MY_AM_VER}
+check_for_app aclocal${MY_AM_VER}
+
+echo "Generating the configure script ..."
+
+aclocal${MY_AM_VER}
+autoconf${MY_AC_VER}
+autoheader${MY_AC_VER}
+automake${MY_AM_VER} --add-missing --copy 2>/dev/null
+
+exit 0
diff --git a/build_tools/dahdi_svn_tarball b/build_tools/dahdi_svn_tarball
new file mode 100755
index 0000000..7667951
--- /dev/null
+++ b/build_tools/dahdi_svn_tarball
@@ -0,0 +1,90 @@
+#!/bin/sh
+
+# upload_dahdi: upload a dahdi tarball to updates.xorcom.com
+#
+
+set -e
+
+BRANCH_NAME=1.4
+REV=HEAD
+DAHDI_BASE=http://svn.digium.com/svn/dahdi
+TARBALLS_DIR=$PWD
+
+me=`basename $0`
+
+say() {
+  echo "$me: $@"
+}
+
+usage() {
+  echo >&2 "$0: Generate snapshot from DAHDI SVN"
+  echo >&2 '    ($Id$)'
+  echo >&2 ""
+  echo >&2 "$0 [-r REV] [-2] [-s]"
+  echo >&2 "$0 <-h | --help>: This message"
+  echo >&2 ""
+  echo >&2 "Options:"
+  echo >&2 "   -2 --dahdi12:         Use Asterisk 1.2. Implies -u."
+  echo >&2 "   -r --rev REV:       extract xpp-dahdi from this revision ($REV)."
+  echo >&2 "   -s --show:          Just show  versions. Do nothing"
+
+}
+
+opt_showonly=no
+
+options=`getopt -o 2hr:s --long dahdi12,help,rev:,revision:,show -- "$@"`
+if [ $? != 0 ] ; then echo >&2 "Terminating..." ; exit 1 ; fi
+
+# Note the quotes around `$TEMP': they are essential!
+eval set -- "$options"
+
+while true ; do
+	case "$1" in
+		-2|--dahdi12) BRANCH_NAME=1.2;;
+		-s|--show) opt_showonly=yes ;;
+		-r|--rev|--revision) REV="$2"; shift ;;
+		-h|--help) usage; exit 0;; 
+		--) shift ; break ;;
+	esac
+	shift;
+done
+
+BRANCH=branches/$BRANCH_NAME
+DAHDI_URL=$DAHDI_BASE/$BRANCH
+
+set -e
+
+# Get the name of the "previous version" for this release.
+# The idea is to look at the latest tag for that branhch. Tags are
+# global, and hence we filter tag names by branch name.
+#
+# Note: this strips any minor version number. 
+# e.g: if last releast was 1.4.5.1, this will still return 1.4.5 . Here
+# we rely on the fact that the revision number will be added.
+dahdi_ver=`svn ls -r $REV $DAHDI_BASE/tags | grep "^$BRANCH_NAME" \
+  | sed -e "s/\($BRANCH_NAME\.[0-9]\+\)[/.-].*/\1/" \
+  | sort -nu -t . -k 3 | tail -n 1`
+
+real_rev=`svn info -r $REV $DAHDI_URL \
+  | awk '/^Last Changed Rev: /{print $4}'`
+
+ver_full="$dahdi_ver.9.svn.$real_rev"
+tar_name="dahdi-$ver_full"
+tar_ball_full="$TARBALLS_DIR/$tar_name.tar.gz"
+
+say "Version: $ver_full (ver: $dahdi_ver, rev: $real_rev)"
+say "Tarball:  $tar_ball_full"
+
+if [ "$opt_showonly" = 'yes' ]; then
+	exit 0;
+fi
+
+DAHDI_CHECKOUT_DIR=`mktemp -d dahdi_checkout_dir_XXXXXX` 
+
+# Package a tarball from the subversion, using 'make dist':
+svn export -q -r $REV $DAHDI_URL $DAHDI_CHECKOUT_DIR/$tar_name
+echo "$ver_full" >$DAHDI_CHECKOUT_DIR/$tar_name/.version
+tar cz -C $DAHDI_CHECKOUT_DIR -f $tar_ball_full $tar_name
+
+rm -rf $DAHDI_CHECKOUT_DIR
+
diff --git a/build_tools/dump_sys_state b/build_tools/dump_sys_state
new file mode 100755
index 0000000..97456d5
--- /dev/null
+++ b/build_tools/dump_sys_state
@@ -0,0 +1,147 @@
+#!/bin/sh
+
+# dump_sys_state: dump some /sys and /proc files to a directory.
+# $Id$
+#
+# Written by Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+# Copyright (C) 2009, Xorcom
+#
+# All rights reserved.
+#
+# 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 Street, Fifth Floor, Boston, MA
+# 02110-1301, USA
+
+# The DAHDI-perl modules will use such a dump instead of the files from
+# the real system if DAHDI_VIRT_TOP is set to the root.
+#
+#  ./build_tools/dump_sys_state my_sys_state
+#
+#  # And then later:
+#  DAHDI_VIRT_TOP="$PWD/my_sys_state" dahdi_genconf
+
+name=dahdi_sys_state_dump
+
+usage() {
+  echo "$0: dump system data for Dahdi-Perl"
+  echo "Usage: $0 [<name>]]"
+  echo ""
+  echo "<name>: name of directory/tarball to create. Default: $name"
+}
+
+output_tar() {
+  gzip -9 >$name.tar.gz
+}
+
+output_cpio() {
+  gzip -9 >$name.cpio.gz
+}
+
+output_dir() {
+  rm -rf $name
+  mkdir -p $name
+  cd $name
+  #tar xf -
+  cpio -id
+}
+
+# Give usage message on expected texts
+case $1 in 
+  help | -* ) usage; exit 1;;
+esac
+
+if [ "$1" != '' ]; then
+  name="$1"
+fi
+
+# funky permissions on procfs. Sadly rm -f does not kill them.
+if [ -d "$name" ]; then
+  chmod -R u+w "$name"
+fi
+rm -rf "$name"
+mkdir -p "$name"
+
+# delete a (potentially empty) list of files
+rm_files() {
+	xargs rm -f rm_files_non_existing_file
+}
+
+if [ -r /proc/bus/usb/devices ]; then
+	mkdir -p "$name/proc/bus/usb"
+	cp -a /proc/bus/usb/devices "$name/proc/bus/usb/"
+fi
+
+if [ -d /proc/dahdi ]; then
+	mkdir -p "$name/proc/dahdi"
+	if find /proc/dahdi -type f >/dev/null; then
+		cp -a /proc/dahdi/* "$name/proc/dahdi/" 
+	fi
+fi
+
+if [ -d /proc/xpp ]; then
+	mkdir -p "$name/proc/xpp"
+	if find /proc/xpp -type f >/dev/null; then
+		cp -a /proc/xpp/* "$name/proc/xpp/" 
+		find "$name/proc/xpp" -type f -name command | rm_files
+	fi
+fi
+
+# FIXME: the following grab tons of files from sysfs. Any way to do with
+# less information?
+pci_dev_pat='/sys/devices/pci*'
+mkdir -p "$name/sys/devices"
+cp -a $pci_dev_pat "$name/sys/devices/" 2>/dev/null
+
+for bus in astribanks xpds pci pci_express usb; do
+	if [ -d /sys/bus/$bus ]; then
+		mkdir -p "$name/sys/bus/"
+		cp -a /sys/bus/$bus "$name/sys/bus/" 2>/dev/null
+	fi
+done
+
+# Remove PCI devices of irelevan classes:
+irrelevant_devs() {
+	grep . "$name"/$pci_dev_pat/0*/class "$name"/$pci_dev_pat/0*/0*/class \
+	| perl -n -e '# Perl provides commented regexes:
+		next unless m{/class:( # The following is a list of device classes
+			# that can be safely removed:
+			0x060000 | # Host bridge
+			0x030000 | # VGA compatible controller
+			0x038000 | # Display controller
+			0x040300 | # Audio device
+			0x060401 | # PCI bridge
+			0x060100 | # ISA bridge
+			0x01018a | # IDE interface
+			0x01018f | # IDE interface
+			0x0c0500 | # SMBus
+			0x060700 | # CardBus bridge
+			0x0c0010 | # FireWire (IEEE 1394)
+			# The following are not to be removed:
+			#0x0c0300 | # USB Controller (UHCI?)
+			#0x060400 | # PCI bridge
+			#0x0c0320 | # USB Controller (EHCI?)
+			#0x020000 | # Ethernet controller
+			#0x0c0010 | # Network controller: (Wifi?)
+		)$}x;
+		# Leave out just the name of the node:
+		s{/[^/]*$}{};
+		print;
+		print "\n"
+	'
+}
+
+# FIXME: deleting those seems to remove common 'vendor' directories
+# and mess things up. Skip it for now.
+#rm -rf `irrelevant_devs`
+
diff --git a/build_tools/make_firmware_object.in b/build_tools/make_firmware_object.in
new file mode 100755
index 0000000..1c301a4
--- /dev/null
+++ b/build_tools/make_firmware_object.in
@@ -0,0 +1,11 @@
+#!/bin/sh -e
+
+# make an object file from a raw binary firmware file
+# arguments:
+#   1 - firmware file
+#   2 - output file
+
+bfdname=@BDFNAME@
+bfdarch=@BDFARCH@
+
+objcopy -I binary ${1} -B ${bfdarch} -O ${bfdname} ${2} --rename-section .data=.rodata,alloc,load,data,contents,readonly
diff --git a/build_tools/make_tree b/build_tools/make_tree
new file mode 100755
index 0000000..01af666
--- /dev/null
+++ b/build_tools/make_tree
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+echo "<?xml version=\"1.0\"?>"
+echo
+echo "<menu name=\"DAHDI Tools Selection\">"
+cat dahdi.xml
+echo "</menu>"
diff --git a/build_tools/make_version b/build_tools/make_version
new file mode 100755
index 0000000..e6caaa2
--- /dev/null
+++ b/build_tools/make_version
@@ -0,0 +1,56 @@
+#!/bin/sh
+
+if [ -f ${1}/.version ]; then
+	cat ${1}.version
+elif [ -f ${1}/.svnrevision ]; then
+	echo SVN-`cat ${1}/.svnbranch`-r`cat ${1}/.svnrevision`
+elif [ -d .svn ]; then
+    PARTS=`LANG=C svn info ${1} | grep URL | awk '{print $2;}' | sed -e s:^.*/svn/${2}/:: | sed -e 's:/: :g'`
+    BRANCH=0
+    TEAM=0
+    
+    REV=`svnversion -c ${1} | cut -d: -f2`
+    
+    if [ "${PARTS}" = "trunk" ]
+	then
+	echo SVN-'trunk'-r${REV}
+	exit 0
+    fi
+    
+    for PART in $PARTS
+      do
+      if [ ${BRANCH} != 0 ]
+	  then
+	  RESULT="${RESULT}-${PART}"
+	  break
+      fi
+      
+      if [ ${TEAM} != 0 ]
+	  then
+	  RESULT="${RESULT}-${PART}"
+	  continue
+      fi
+      
+      if [ "${PART}" = "branches" ]
+	  then
+	  BRANCH=1
+	  RESULT="branch"
+	  continue
+      fi
+      
+      if [ "${PART}" = "tags" ]
+	  then
+	  BRANCH=1
+	  RESULT="tag"
+	  continue
+      fi
+      
+      if [ "${PART}" = "team" ]
+	  then
+	  TEAM=1
+	  continue
+      fi
+    done
+    
+    echo SVN-${RESULT##-}-r${REV}
+fi
diff --git a/build_tools/make_version_c b/build_tools/make_version_c
new file mode 100755
index 0000000..7382f3f
--- /dev/null
+++ b/build_tools/make_version_c
@@ -0,0 +1,10 @@
+#!/bin/sh
+cat << END
+/*
+ * version.c
+ * Automatically generated
+ */
+
+const char dahdi_tools_version[] = "DAHDI Tools Version - ${TOOLSVERSION}";
+
+END
diff --git a/build_tools/menuselect-deps.in b/build_tools/menuselect-deps.in
new file mode 100644
index 0000000..d8ff845
--- /dev/null
+++ b/build_tools/menuselect-deps.in
@@ -0,0 +1,2 @@
+LIBNEWT=@PBX_NEWT@
+HDLC=@PBX_HDLC@
diff --git a/build_tools/test_kernel_git b/build_tools/test_kernel_git
new file mode 100755
index 0000000..59c196d
--- /dev/null
+++ b/build_tools/test_kernel_git
@@ -0,0 +1,80 @@
+#!/bin/sh
+
+set -e
+
+GIT_URL=git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
+CONF_FILE=build_tools/git_test.conf
+
+usage() {
+	me=`basename $0`
+	echo "$me: test building Zaptel vs. kernel from git"
+	echo "Usage:"
+	echo "  $me checkout <kerneldir>  Pull a kernel version into <kerneldir>"
+	echo "  $me update                Update (pull) the kernel tree."
+	echo "  $me setver <kernel_ver>   Set the kernel version"
+	echo "  $me test                  Test-build"
+	echo ""
+	echo "  $me versions [pattern]    List available versions."
+}
+
+# Set a variable in $CONF_FILE
+# The format of CONF_FILE is assumed to be:
+# VAR=value
+# in shell syntax. "value" may be quoted.
+# "value should not contain a '|' character.
+set_var() {
+	var="$1"
+	val="$2"
+	if grep -q "^$var=" $CONF_FILE 2>/dev/null; then
+		sed -i -e "s|^$var=.*|$var=\"$val\"|" $CONF_FILE
+	else
+		echo "$var=\"$val\"" >>$CONF_FILE
+	fi
+}
+
+if [ -r "$CONF_FILE" ]; then . "$CONF_FILE"; fi
+
+if echo "$CONF_FILE" | grep -qv '^/'; then
+	# make CONF_FILE an absolute path:
+	CONF_FILE="$PWD/$CONF_FILE"
+fi
+
+command="$1"
+
+case "$command" in
+	checkout) 
+		kernel_dir="$2"
+		cd "$kernel_dir"
+		git clone $GIT_URL
+		set_var kernel_dir "$kernel_dir/linux-2.6"
+		;;
+	update)
+		cd "$kernel_dir"
+		git pull
+		;;
+	versions)
+		cd "$kernel_dir"
+		git tag -l $2 | cut -c2-
+		;;
+	setver)
+		kernel_ver="$2"
+		tag="v$kernel_ver"
+		cd "$kernel_dir"
+		git-reset --hard "$tag"
+		make defconfig prepare
+		set_var kernel_ver "$kernel_ver"
+		;;
+	test)
+		# you can pass extra parameters to the make command in
+		# two ways:
+		# 1. Set th value of MAKE_PARAMS in git_test.conf .
+		# 2. Any extra command-line parameter.
+		shift
+		make KSRC="$kernel_dir" KVERS=$kernel_ver $MAKE_PARAMS "$@"
+		;;
+	*)
+		echo "$0: no such command $command. Aborting."
+		usage
+		exit 1
+		;;
+esac
diff --git a/build_tools/uninstall-modules b/build_tools/uninstall-modules
new file mode 100755
index 0000000..a654c21
--- /dev/null
+++ b/build_tools/uninstall-modules
@@ -0,0 +1,41 @@
+#!/bin/sh
+# uninstall-modules
+#
+# Remove all the modules passed in on the command line from the modules
+# directory.  This script is called by the makefile.
+
+KERNEL_MODULES_DIR=$1
+shift
+MODULES="$*"
+
+usage() {
+	echo "$0: Used to delete kernel modules from the modules directory."
+	echo ""
+	echo "Usage:"
+	echo "  $0 MODULES_BASE_DIR mod1 [mod2 [...]]"
+	echo ""
+	echo "  MODULES_BASE_DIR - typically /lib/modules/KVERS"
+	echo "  modN -             (optionally partial) module name to remove."
+}
+
+if [ -z "$KERNEL_MODULES_DIR" ]; then
+	echo "Missing kernel module directory."
+	usage
+	exit 1;
+fi
+
+if [ -z "$MODULES" ]; then
+	echo "Missing one or more modules to delete."
+	usage
+	exit 1;
+fi
+for mod in $MODULES; do 
+	BASE=`basename $mod`
+	for file in `cat $KERNEL_MODULES_DIR/modules.dep | cut -d : -f 1 | grep "$BASE$"`; do
+		if [ -e "$file" ]; then
+			#echo "Deleting $file."
+			rm -f $file
+		fi
+	done
+done
+exit 0
diff --git a/config.guess b/config.guess
new file mode 100755
index 0000000..f32079a
--- /dev/null
+++ b/config.guess
@@ -0,0 +1,1526 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+#   Free Software Foundation, Inc.
+
+timestamp='2008-01-23'
+
+# 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 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 Street - Fifth Floor, Boston, MA
+# 02110-1301, 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.
+
+
+# Originally written by Per Bothner <per at bothner.com>.
+# Please send patches to <config-patches at gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub.  If it succeeds, it prints the system name on stdout, and
+# exits with 0.  Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+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 (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 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
+
+# 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 tupples: *-*-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 __ELF__ >/dev/null
+		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 ;;
+    *: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'`
+	exit ;;
+    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 ;;
+    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:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+	echo i386-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:*:[456])
+	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 __LP64__ >/dev/null
+	    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:*:*)
+	case ${UNAME_MACHINE} in
+	    pc98)
+		echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    amd64)
+		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	    *)
+		echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	esac
+	exit ;;
+    i*:CYGWIN*:*)
+	echo ${UNAME_MACHINE}-pc-cygwin
+	exit ;;
+    *:MINGW*:*)
+	echo ${UNAME_MACHINE}-pc-mingw32
+	exit ;;
+    i*:windows32*:*)
+    	# uname -m includes "-pc" on this system.
+    	echo ${UNAME_MACHINE}-mingw32
+	exit ;;
+    i*:PW*:*)
+	echo ${UNAME_MACHINE}-pc-pw32
+	exit ;;
+    *:Interix*:[3456]*)
+    	case ${UNAME_MACHINE} in
+	    x86)
+		echo i586-pc-interix${UNAME_RELEASE}
+		exit ;;
+	    EM64T | authenticamd)
+		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 ;;
+    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-gnu`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/[-(].*//'`-gnu
+	exit ;;
+    i*86:Minix:*:*)
+	echo ${UNAME_MACHINE}-pc-minix
+	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-gnu
+	else
+	    echo ${UNAME_MACHINE}-unknown-linux-gnueabi
+	fi
+	exit ;;
+    avr32*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    cris:Linux:*:*)
+	echo cris-axis-linux-gnu
+	exit ;;
+    crisv32:Linux:*:*)
+	echo crisv32-axis-linux-gnu
+	exit ;;
+    frv:Linux:*:*)
+    	echo frv-unknown-linux-gnu
+	exit ;;
+    ia64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m32r*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    m68*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    mips:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef mips
+	#undef mipsel
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=mipsel
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=mips
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+	    /^CPU/{
+		s: ::g
+		p
+	    }'`"
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+	;;
+    mips64:Linux:*:*)
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#undef CPU
+	#undef mips64
+	#undef mips64el
+	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+	CPU=mips64el
+	#else
+	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+	CPU=mips64
+	#else
+	CPU=
+	#endif
+	#endif
+EOF
+	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+	    /^CPU/{
+		s: ::g
+		p
+	    }'`"
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+	;;
+    or32:Linux:*:*)
+	echo or32-unknown-linux-gnu
+	exit ;;
+    ppc:Linux:*:*)
+	echo powerpc-unknown-linux-gnu
+	exit ;;
+    ppc64:Linux:*:*)
+	echo powerpc64-unknown-linux-gnu
+	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 ld.so.1 >/dev/null
+	if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+	echo ${UNAME_MACHINE}-unknown-linux-gnu${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-gnu ;;
+	  PA8*) echo hppa2.0-unknown-linux-gnu ;;
+	  *)    echo hppa-unknown-linux-gnu ;;
+	esac
+	exit ;;
+    parisc64:Linux:*:* | hppa64:Linux:*:*)
+	echo hppa64-unknown-linux-gnu
+	exit ;;
+    s390:Linux:*:* | s390x:Linux:*:*)
+	echo ${UNAME_MACHINE}-ibm-linux
+	exit ;;
+    sh64*:Linux:*:*)
+    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    sh*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    sparc:Linux:*:* | sparc64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    vax:Linux:*:*)
+	echo ${UNAME_MACHINE}-dec-linux-gnu
+	exit ;;
+    x86_64:Linux:*:*)
+	echo x86_64-unknown-linux-gnu
+	exit ;;
+    xtensa*:Linux:*:*)
+    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	exit ;;
+    i*86:Linux:*:*)
+	# The BFD linker knows what the default object file format is, so
+	# first see if it will tell us. cd to the root directory to prevent
+	# problems with other programs or directories called `ld' in the path.
+	# Set LC_ALL=C to ensure ld outputs messages in English.
+	ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \
+			 | sed -ne '/supported targets:/!d
+				    s/[ 	][ 	]*/ /g
+				    s/.*supported targets: *//
+				    s/ .*//
+				    p'`
+        case "$ld_supported_targets" in
+	  elf32-i386)
+		TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+		;;
+	  a.out-i386-linux)
+		echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+		exit ;;
+	  coff-i386)
+		echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+		exit ;;
+	  "")
+		# Either a pre-BFD a.out linker (linux-gnuoldld) or
+		# one that does not give us useful --help.
+		echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+		exit ;;
+	esac
+	# Determine whether the default compiler is a.out or elf
+	eval $set_cc_for_build
+	sed 's/^	//' << EOF >$dummy.c
+	#include <features.h>
+	#ifdef __ELF__
+	# ifdef __GLIBC__
+	#  if __GLIBC__ >= 2
+	LIBC=gnu
+	#  else
+	LIBC=gnulibc1
+	#  endif
+	# else
+	LIBC=gnulibc1
+	# endif
+	#else
+	#if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+	LIBC=gnu
+	#else
+	LIBC=gnuaout
+	#endif
+	#endif
+	#ifdef __dietlibc__
+	LIBC=dietlibc
+	#endif
+EOF
+	eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n '
+	    /^LIBC/{
+		s: ::g
+		p
+	    }'`"
+	test x"${LIBC}" != x && {
+		echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+		exit
+	}
+	test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; 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.0*:*)
+	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 i386.
+	echo i386-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; } ;;
+    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.0*:*)
+	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 ;;
+    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
+	case $UNAME_PROCESSOR in
+	    unknown) UNAME_PROCESSOR=powerpc ;;
+	esac
+	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 ;;
+    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 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+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/config.sub b/config.sub
new file mode 100755
index 0000000..6759825
--- /dev/null
+++ b/config.sub
@@ -0,0 +1,1658 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+#   Free Software Foundation, Inc.
+
+timestamp='2008-01-16'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine.  It does not imply ALL GNU software can.
+#
+# 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 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 Street - Fifth Floor, Boston, MA
+# 02110-1301, 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.
+
+
+# Please send patches to <config-patches at gnu.org>.  Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# 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.
+
+# 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 (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006, 2007, 2008 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-dietlibc | linux-newlib* | linux-uclibc* | \
+  uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
+  storm-chaos* | os2-emx* | rtmk-nova*)
+    os=-$maybe_os
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+    ;;
+  *)
+    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)
+		os=
+		basic_machine=$1
+		;;
+	-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*)
+		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 \
+	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+	| am33_2.0 \
+	| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+	| bfin \
+	| c4x | clipper \
+	| d10v | d30v | dlx | dsp16xx \
+	| fido | fr30 | frv \
+	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+	| i370 | i860 | i960 | ia64 \
+	| ip2k | iq2000 \
+	| m32c | m32r | m32rle | m68000 | m68k | m88k \
+	| maxq | mb | microblaze | mcore | mep \
+	| mips | mipsbe | mipseb | mipsel | mipsle \
+	| mips16 \
+	| mips64 | mips64el \
+	| mips64vr | mips64vrel \
+	| mips64orion | mips64orionel \
+	| mips64vr4100 | mips64vr4100el \
+	| mips64vr4300 | mips64vr4300el \
+	| mips64vr5000 | mips64vr5000el \
+	| mips64vr5900 | mips64vr5900el \
+	| mipsisa32 | mipsisa32el \
+	| mipsisa32r2 | mipsisa32r2el \
+	| mipsisa64 | mipsisa64el \
+	| mipsisa64r2 | mipsisa64r2el \
+	| mipsisa64sb1 | mipsisa64sb1el \
+	| mipsisa64sr71k | mipsisa64sr71kel \
+	| mipstx39 | mipstx39el \
+	| mn10200 | mn10300 \
+	| mt \
+	| msp430 \
+	| nios | nios2 \
+	| ns16k | ns32k \
+	| or32 \
+	| pdp10 | pdp11 | pj | pjl \
+	| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+	| pyramid \
+	| score \
+	| sh | sh[1234] | sh[24]a | 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 | strongarm \
+	| tahoe | thumb | tic4x | tic80 | tron \
+	| v850 | v850e \
+	| we32k \
+	| x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
+	| z8k)
+		basic_machine=$basic_machine-unknown
+		;;
+	m6811 | m68hc11 | m6812 | m68hc12)
+		# Motorola 68HC11/12.
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+		;;
+	ms1)
+		basic_machine=mt-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-* \
+	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
+	| avr-* | avr32-* \
+	| bfin-* | bs2000-* \
+	| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
+	| 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-* \
+	| i*86-* | i860-* | i960-* | ia64-* \
+	| ip2k-* | iq2000-* \
+	| m32c-* | m32r-* | m32rle-* \
+	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+	| m88110-* | m88k-* | maxq-* | mcore-* \
+	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+	| mips16-* \
+	| mips64-* | mips64el-* \
+	| mips64vr-* | mips64vrel-* \
+	| mips64orion-* | mips64orionel-* \
+	| mips64vr4100-* | mips64vr4100el-* \
+	| mips64vr4300-* | mips64vr4300el-* \
+	| mips64vr5000-* | mips64vr5000el-* \
+	| mips64vr5900-* | mips64vr5900el-* \
+	| mipsisa32-* | mipsisa32el-* \
+	| mipsisa32r2-* | mipsisa32r2el-* \
+	| mipsisa64-* | mipsisa64el-* \
+	| mipsisa64r2-* | mipsisa64r2el-* \
+	| mipsisa64sb1-* | mipsisa64sb1el-* \
+	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
+	| mipstx39-* | mipstx39el-* \
+	| mmix-* \
+	| mt-* \
+	| msp430-* \
+	| nios-* | nios2-* \
+	| none-* | np1-* | ns16k-* | ns32k-* \
+	| orion-* \
+	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+	| pyramid-* \
+	| romp-* | rs6000-* \
+	| sh-* | sh[1234]-* | sh[24]a-* | 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-* | strongarm-* | sv1-* | sx?-* \
+	| tahoe-* | thumb-* \
+	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+	| tron-* \
+	| v850-* | v850e-* | vax-* \
+	| we32k-* \
+	| x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+	| xstormy16-* | xtensa*-* \
+	| ymp-* \
+	| z8k-*)
+		;;
+	# 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
+		;;
+	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
+		;;
+	c90)
+		basic_machine=c90-cray
+		os=-unicos
+		;;
+	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)
+		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
+		;;
+	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'm not sure what "Sysv32" means.  Should this be sysv3.2?
+	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
+		;;
+	mingw32)
+		basic_machine=i386-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-/'`
+		;;
+	mvs)
+		basic_machine=i370-ibm
+		os=-mvs
+		;;
+	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
+		;;
+	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)	basic_machine=powerpc-unknown
+		;;
+	ppc-*)	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)
+		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
+		;;
+	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
+		;;
+	tic54x | c54x*)
+		basic_machine=tic54x-unknown
+		os=-coff
+		;;
+	tic55x | c55x*)
+		basic_machine=tic55x-unknown
+		os=-coff
+		;;
+	tic6x | c6x*)
+		basic_machine=tic6x-unknown
+		os=-coff
+		;;
+	tile*)
+		basic_machine=tile-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
+		;;
+	ymp)
+		basic_machine=ymp-cray
+		os=-unicos
+		;;
+	z8k-*-coff)
+		basic_machine=z8k-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[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.
+	-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* | -sunos | -sunos[34]*\
+	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+	      | -aos* \
+	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+	      | -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* \
+	      | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+	      | -mingw32* | -linux-gnu* | -linux-newlib* | -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*)
+	# 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
+		;;
+	-kaos*)
+		os=-kaos
+		;;
+	-zvmoe)
+		os=-zvmoe
+		;;
+	-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
+		;;
+	# 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
+		# This also exists in the configure program, but was not the
+		# default.
+		# os=-sunos4
+		;;
+	m68*-cisco)
+		os=-aout
+		;;
+        mep-*)
+		os=-elf
+		;;
+	mips*-cisco)
+		os=-elf
+		;;
+	mips*-*)
+		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
+				;;
+			-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/configure b/configure
new file mode 100755
index 0000000..883e545
--- /dev/null
+++ b/configure
@@ -0,0 +1,6991 @@
+#! /bin/sh
+# From configure.ac Revision: 8266 .
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.61.
+#
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+# 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+#
+# "dahdi-tools"
+## --------------------- ##
+## 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=:
+  # 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
+
+
+
+
+# PATH needs CR
+# 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
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conf$$.sh
+  echo  "exit 0"   >>conf$$.sh
+  chmod +x conf$$.sh
+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+    PATH_SEPARATOR=';'
+  else
+    PATH_SEPARATOR=:
+  fi
+  rm -f conf$$.sh
+fi
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+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.)
+as_nl='
+'
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+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
+  echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+  LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+  LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+  LC_TELEPHONE LC_TIME
+do
+  if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+    eval $as_var=C; export $as_var
+  else
+    ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+  fi
+done
+
+# Required to use basename.
+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
+
+
+# Name of the executable.
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+if test "x$CONFIG_SHELL" = x; then
+  if (eval ":") 2>/dev/null; then
+  as_have_required=yes
+else
+  as_have_required=no
+fi
+
+  if test $as_have_required = yes && 	 (eval ":
+(as_func_return () {
+  (exit \$1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0) || { (exit 1); exit 1; }
+
+(
+  as_lineno_1=\$LINENO
+  as_lineno_2=\$LINENO
+  test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" &&
+  test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; }
+") 2> /dev/null; then
+  :
+else
+  as_candidate_shells=
+    as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  case $as_dir in
+	 /*)
+	   for as_base in sh bash ksh sh5; do
+	     as_candidate_shells="$as_candidate_shells $as_dir/$as_base"
+	   done;;
+       esac
+done
+IFS=$as_save_IFS
+
+
+      for as_shell in $as_candidate_shells $SHELL; do
+	 # Try only shells that exist, to save several forks.
+	 if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+		{ ("$as_shell") 2> /dev/null <<\_ASEOF
+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
+
+
+:
+_ASEOF
+}; then
+  CONFIG_SHELL=$as_shell
+	       as_have_required=yes
+	       if { "$as_shell" 2> /dev/null <<\_ASEOF
+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
+
+
+:
+(as_func_return () {
+  (exit $1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = "$1" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test $exitcode = 0) || { (exit 1); exit 1; }
+
+(
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; }
+
+_ASEOF
+}; then
+  break
+fi
+
+fi
+
+      done
+
+      if test "x$CONFIG_SHELL" != x; then
+  for as_var in BASH_ENV ENV
+        do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+        done
+        export CONFIG_SHELL
+        exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"}
+fi
+
+
+    if test $as_have_required = no; then
+  echo This script requires a shell more modern than all the
+      echo shells that I found on your system.  Please install a
+      echo modern shell, or manually run the script under such a
+      echo shell if you do have one.
+      { (exit 1); exit 1; }
+fi
+
+
+fi
+
+fi
+
+
+
+(eval "as_func_return () {
+  (exit \$1)
+}
+as_func_success () {
+  as_func_return 0
+}
+as_func_failure () {
+  as_func_return 1
+}
+as_func_ret_success () {
+  return 0
+}
+as_func_ret_failure () {
+  return 1
+}
+
+exitcode=0
+if as_func_success; then
+  :
+else
+  exitcode=1
+  echo as_func_success failed.
+fi
+
+if as_func_failure; then
+  exitcode=1
+  echo as_func_failure succeeded.
+fi
+
+if as_func_ret_success; then
+  :
+else
+  exitcode=1
+  echo as_func_ret_success failed.
+fi
+
+if as_func_ret_failure; then
+  exitcode=1
+  echo as_func_ret_failure succeeded.
+fi
+
+if ( set x; as_func_ret_success y && test x = \"\$1\" ); then
+  :
+else
+  exitcode=1
+  echo positional parameters were not saved.
+fi
+
+test \$exitcode = 0") || {
+  echo No shell found that supports shell functions.
+  echo Please tell autoconf at gnu.org about your system,
+  echo including any error possibly output before this
+  echo message
+}
+
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line after each line using $LINENO; the second 'sed'
+  # does the real work.  The second script uses 'N' to pair each
+  # line-number line with the line containing $LINENO, and appends
+  # trailing '-' during substitution so that $LINENO is not a special
+  # case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # scripts with optimization help from Paolo Bonzini.  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" ||
+    { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+   { (exit 1); exit 1; }; }
+
+  # 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
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+  case `echo 'x\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  *)   ECHO_C='\c';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+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
+fi
+echo >conf$$.file
+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 -p'.
+  ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+    as_ln_s='cp -p'
+elif ln conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s=ln
+else
+  as_ln_s='cp -p'
+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=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+        test -d "$1/.";
+      else
+	case $1 in
+        -*)set "./$1";;
+	esac;
+	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+	???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# 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 7<&0 </dev/null 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, 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=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+
+ac_unique_file="dahdi"
+ac_unique_file="dahdi_cfg.c"
+# 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='SHELL
+PATH_SEPARATOR
+PACKAGE_NAME
+PACKAGE_TARNAME
+PACKAGE_VERSION
+PACKAGE_STRING
+PACKAGE_BUGREPORT
+exec_prefix
+prefix
+program_transform_name
+bindir
+sbindir
+libexecdir
+datarootdir
+datadir
+sysconfdir
+sharedstatedir
+localstatedir
+includedir
+oldincludedir
+docdir
+infodir
+htmldir
+dvidir
+pdfdir
+psdir
+libdir
+localedir
+mandir
+DEFS
+ECHO_C
+ECHO_N
+ECHO_T
+LIBS
+build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+CPPFLAGS
+ac_ct_CC
+EXEEXT
+OBJEXT
+CPP
+GREP
+EGREP
+LD
+INSTALL_PROGRAM
+INSTALL_SCRIPT
+INSTALL_DATA
+LN_S
+GNU_MAKE
+BDFNAME
+BDFARCH
+HOSTCC
+LN
+WGET
+FETCH
+DOWNLOAD
+DAHDI_DEVMODE
+DAHDI_DECLARATION_AFTER_STATEMENT
+DAHDI_LIB
+DAHDI_INCLUDE
+DAHDI_DIR
+PBX_DAHDI
+NEWT_LIB
+NEWT_INCLUDE
+NEWT_DIR
+PBX_NEWT
+USB_LIB
+USB_INCLUDE
+USB_DIR
+PBX_USB
+PBX_DAHDI23
+PBX_HDLC
+USE_SELINUX
+ASCIIDOC
+PPPD_VERSION
+LIBOBJS
+LTLIBOBJS'
+ac_subst_files=''
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# 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}'
+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=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_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+   { (exit 1); exit 1; }; }
+    ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'`
+    eval enable_$ac_feature=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_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+   { (exit 1); exit 1; }; }
+    ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'`
+    eval enable_$ac_feature=\$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_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid package name: $ac_package" >&2
+   { (exit 1); exit 1; }; }
+    ac_package=`echo $ac_package | sed 's/[-.]/_/g'`
+    eval with_$ac_package=\$ac_optarg ;;
+
+  -without-* | --without-*)
+    ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid package name: $ac_package" >&2
+   { (exit 1); exit 1; }; }
+    ac_package=`echo $ac_package | sed 's/[-.]/_/g'`
+    eval with_$ac_package=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 ;;
+
+  -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; }
+    ;;
+
+  *=*)
+    ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+    # Reject names that are not valid shell variable names.
+    expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+      { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+   { (exit 1); exit 1; }; }
+    eval $ac_envvar=\$ac_optarg
+    export $ac_envvar ;;
+
+  *)
+    # FIXME: should be removed in autoconf 3.0.
+    echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+    expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+      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'`
+  { echo "$as_me: error: missing argument to $ac_option" >&2
+   { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute directory names.
+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
+  case $ac_val in
+    [\\/$]* | ?:[\\/]* )  continue;;
+    NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+  esac
+  { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+   { (exit 1); exit 1; }; }
+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
+    echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+    If a cross compiler is detected then cross compile mode will be used." >&2
+  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 .` ||
+  { echo "$as_me: error: Working directory cannot be determined" >&2
+   { (exit 1); exit 1; }; }
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+  { echo "$as_me: error: pwd does not report name of working directory" >&2
+   { (exit 1); exit 1; }; }
+
+
+# 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 -- "$0" ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+	 X"$0" : 'X\(//\)[^/]' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X"$0" |
+    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 .."
+  { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+   { (exit 1); exit 1; }; }
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+	cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2
+   { (exit 1); exit 1; }; }
+	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 this package 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/PACKAGE]
+  --htmldir=DIR          html documentation [DOCDIR]
+  --dvidir=DIR           dvi documentation [DOCDIR]
+  --pdfdir=DIR           pdf documentation [DOCDIR]
+  --psdir=DIR            ps documentation [DOCDIR]
+_ACEOF
+
+  cat <<\_ACEOF
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+  cat <<\_ACEOF
+
+Optional Features:
+  --disable-FEATURE       do not include FEATURE (same as --enable-FEATURE=no)
+  --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
+  --enable-dev-mode    Turn on developer mode
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-dahdi=PATH       use DAHDI files in PATH
+  --with-newt=PATH        use newt files in PATH
+  --with-usb=PATH         use usb files in PATH
+  --with-selinux          enable (with) / disable (without) SELinux
+  --with-ppp=PATH         Use PPP support from PATH
+
+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    C/C++/Objective C preprocessor flags, e.g. -I<include dir> if
+              you have headers in a nonstandard directory <include dir>
+  CPP         C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+_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" || continue
+    ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`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
+      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
+configure
+generated by GNU Autoconf 2.61
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
+2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+
+"dahdi-tools"
+_ACEOF
+  exit
+fi
+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 $as_me, which was
+generated by GNU Autoconf 2.61.  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=.
+  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=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+    esac
+    case $ac_pass in
+    1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;;
+    2)
+      ac_configure_args1="$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
+      ac_configure_args="$ac_configure_args '$ac_arg'"
+      ;;
+    esac
+  done
+done
+$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; }
+$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export 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
+
+    cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+    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_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5
+echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      *) $as_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
+
+    cat <<\_ASBOX
+## ----------------- ##
+## Output variables. ##
+## ----------------- ##
+_ASBOX
+    echo
+    for ac_var in $ac_subst_vars
+    do
+      eval ac_val=\$$ac_var
+      case $ac_val in
+      *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+      esac
+      echo "$ac_var='\''$ac_val'\''"
+    done | sort
+    echo
+
+    if test -n "$ac_subst_files"; then
+      cat <<\_ASBOX
+## ------------------- ##
+## File substitutions. ##
+## ------------------- ##
+_ASBOX
+      echo
+      for ac_var in $ac_subst_files
+      do
+	eval ac_val=\$$ac_var
+	case $ac_val in
+	*\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+	esac
+	echo "$ac_var='\''$ac_val'\''"
+      done | sort
+      echo
+    fi
+
+    if test -s confdefs.h; then
+      cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+      echo
+      cat confdefs.h
+      echo
+    fi
+    test "$ac_signal" != 0 &&
+      echo "$as_me: caught signal $ac_signal"
+    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'; { (exit 1); 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
+
+# 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
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer explicitly selected file to automatically selected ones.
+if test -n "$CONFIG_SITE"; then
+  set x "$CONFIG_SITE"
+elif test "x$prefix" != xNONE; then
+  set x "$prefix/share/config.site" "$prefix/etc/config.site"
+else
+  set x "$ac_default_prefix/share/config.site" \
+	"$ac_default_prefix/etc/config.site"
+fi
+shift
+for ac_site_file
+do
+  if test -r "$ac_site_file"; then
+    { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+    sed 's/^/| /' "$ac_site_file" >&5
+    . "$ac_site_file"
+  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.
+  if test -f "$cache_file"; then
+    { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+    case $cache_file in
+      [\\/]* | ?:[\\/]* ) . "$cache_file";;
+      *)                      . "./$cache_file";;
+    esac
+  fi
+else
+  { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+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,)
+      { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+      ac_cache_corrupted=: ;;
+    ,set)
+      { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+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
+	{ echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+	{ echo "$as_me:$LINENO:   former value:  $ac_old_val" >&5
+echo "$as_me:   former value:  $ac_old_val" >&2;}
+	{ echo "$as_me:$LINENO:   current value: $ac_new_val" >&5
+echo "$as_me:   current value: $ac_new_val" >&2;}
+	ac_cache_corrupted=:
+      fi;;
+  esac
+  # Pass precious variables to config.status.
+  if test "$ac_new_set" = set; then
+    case $ac_new_val in
+    *\'*) ac_arg=$ac_var=`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.
+      *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+    esac
+  fi
+done
+if $ac_cache_corrupted; then
+  { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+  { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+   { (exit 1); exit 1; }; }
+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
+
+
+
+# check existence of the package
+
+
+
+
+
+ac_default_prefix=/usr
+if test ${sysconfdir} = '${prefix}/etc'; then
+   sysconfdir=/etc
+fi
+if test ${mandir} = '${prefix}/man'; then
+   mandir=/usr/share/man
+fi
+
+if test ${localstatedir} = '${prefix}/var'; then
+     localstatedir=/var
+fi
+
+# specify output header file
+ac_config_headers="$ac_config_headers autoconfig.h"
+
+
+# This needs to be before any macros that use the C compiler
+
+cat >>confdefs.h <<\_ACEOF
+#define _GNU_SOURCE 1
+_ACEOF
+
+
+
+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
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    echo "$as_me:$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
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}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
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    echo "$as_me:$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
+  { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf at gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf at gnu.org." >&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
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    echo "$as_me:$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
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}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
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$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"
+    echo "$as_me:$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
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}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
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    echo "$as_me:$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
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}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
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    echo "$as_me:$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
+  { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}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:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf at gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf at gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO: checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (ac_try="$ac_compiler --version >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler --version >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -v >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler -v >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -V >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler -V >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out 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.
+{ echo "$as_me:$LINENO: checking for C compiler default output file name" >&5
+echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6; }
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+#
+# List of possible output files, starting from the most likely.
+# The algorithm is not robust to junk in `.', hence go to wildcards (a.*)
+# only as a last resort.  b.out is created by i960 compilers.
+ac_files='a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out'
+#
+# The IRIX 6 linker writes into existing files which may not be
+# executable, retaining their permissions.  Remove them first so a
+# subsequent execution test works.
+ac_rmfiles=
+for ac_file in $ac_files
+do
+  case $ac_file in
+    *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link_default") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; 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 | *.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
+
+{ echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6; }
+if test -z "$ac_file"; then
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: C compiler cannot create executables
+See \`config.log' for more details." >&5
+echo "$as_me: error: C compiler cannot create executables
+See \`config.log' for more details." >&2;}
+   { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6; }
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+  if { ac_try='./$ac_file'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+    cross_compiling=no
+  else
+    if test "$cross_compiling" = maybe; then
+	cross_compiling=yes
+    else
+	{ { echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+    fi
+  fi
+fi
+{ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+
+rm -f a.out a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+# Check that the compiler produces executables we can run.  If not, either
+# the compiler is broken, or we cross compile.
+{ echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6; }
+{ echo "$as_me:$LINENO: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6; }
+
+{ echo "$as_me:$LINENO: checking for suffix of executables" >&5
+echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6; }
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; 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 | *.o | *.obj ) ;;
+    *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+	  break;;
+    * ) break;;
+  esac
+done
+else
+  { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+{ echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+{ echo "$as_me:$LINENO: checking for suffix of object files" >&5
+echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6; }
+if test "${ac_cv_objext+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* 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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; 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 ) ;;
+    *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+       break;;
+  esac
+done
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&5
+echo "$as_me: error: cannot compute suffix of object files: cannot compile
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; }
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_compiler_gnu=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	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
+{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; }
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; }
+if test "${ac_cv_prog_cc_g+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&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 >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	CFLAGS=""
+      cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_c_werror_flag=$ac_save_c_werror_flag
+	 CFLAGS="-g"
+	 cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+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
+{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$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
+{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5
+echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; }
+if test "${ac_cv_prog_cc_c89+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* 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"
+  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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_c89=$ac_arg
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+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)
+    { echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6; } ;;
+  xno)
+    { echo "$as_me:$LINENO: result: unsupported" >&5
+echo "${ECHO_T}unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+
+
+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
+{ echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if test "${ac_cv_prog_CPP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&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 >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  # Broken: success on invalid input.
+continue
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f 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
+{ echo "$as_me:$LINENO: result: $CPP" >&5
+echo "${ECHO_T}$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 >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  # Broken: success on invalid input.
+continue
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  :
+else
+  { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+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
+
+
+{ echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5
+echo $ECHO_N "checking for grep that handles long lines and -e... $ECHO_C" >&6; }
+if test "${ac_cv_path_GREP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  # Extract the first word of "grep ggrep" to use in msg output
+if test -z "$GREP"; then
+set dummy grep ggrep; ac_prog_name=$2
+if test "${ac_cv_path_GREP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  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"
+    { test -f "$ac_path_GREP" && $as_test_x "$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
+  echo $ECHO_N "0123456789$ECHO_C" >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    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
+    ac_count=`expr $ac_count + 1`
+    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
+
+
+fi
+
+GREP="$ac_cv_path_GREP"
+if test -z "$GREP"; then
+  { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
+echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+else
+  ac_cv_path_GREP=$GREP
+fi
+
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5
+echo "${ECHO_T}$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ echo "$as_me:$LINENO: checking for egrep" >&5
+echo $ECHO_N "checking for egrep... $ECHO_C" >&6; }
+if test "${ac_cv_path_EGREP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     # Extract the first word of "egrep" to use in msg output
+if test -z "$EGREP"; then
+set dummy egrep; ac_prog_name=$2
+if test "${ac_cv_path_EGREP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  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"
+    { test -f "$ac_path_EGREP" && $as_test_x "$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
+  echo $ECHO_N "0123456789$ECHO_C" >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    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
+    ac_count=`expr $ac_count + 1`
+    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
+
+
+fi
+
+EGREP="$ac_cv_path_EGREP"
+if test -z "$EGREP"; then
+  { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5
+echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+else
+  ac_cv_path_EGREP=$EGREP
+fi
+
+
+   fi
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5
+echo "${ECHO_T}$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6; }
+if test "${ac_cv_header_stdc+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_header_stdc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	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 >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* 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 >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* 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 >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* 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
+rm -f conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  :
+else
+  echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+
+
+fi
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\_ACEOF
+#define STDC_HEADERS 1
+_ACEOF
+
+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=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  eval "$as_ac_Header=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	eval "$as_ac_Header=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+	       { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+for ac_header in sys/soundcard.h linux/soundcard.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  { echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+	       { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <$ac_header>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; }
+if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  eval "$as_ac_Header=\$ac_header_preproc"
+fi
+ac_res=`eval echo '${'$as_ac_Header'}'`
+	       { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}ld", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ld; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_LD+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$LD"; then
+  ac_cv_prog_LD="$LD" # 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_LD="${ac_tool_prefix}ld"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+LD=$ac_cv_prog_LD
+if test -n "$LD"; then
+  { echo "$as_me:$LINENO: result: $LD" >&5
+echo "${ECHO_T}$LD" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_LD"; then
+  ac_ct_LD=$LD
+  # Extract the first word of "ld", so it can be a program name with args.
+set dummy ld; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_LD+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  if test -n "$ac_ct_LD"; then
+  ac_cv_prog_ac_ct_LD="$ac_ct_LD" # 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_LD="ld"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_LD=$ac_cv_prog_ac_ct_LD
+if test -n "$ac_ct_LD"; then
+  { echo "$as_me:$LINENO: result: $ac_ct_LD" >&5
+echo "${ECHO_T}$ac_ct_LD" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+  if test "x$ac_ct_LD" = x; then
+    LD=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf at gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf at gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+    LD=$ac_ct_LD
+  fi
+else
+  LD="$ac_cv_prog_LD"
+fi
+
+
+# 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
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    echo "$as_me:$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
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}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
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    echo "$as_me:$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
+  { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf at gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf at gnu.org." >&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
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    echo "$as_me:$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
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}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
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$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"
+    echo "$as_me:$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
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}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
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+    echo "$as_me:$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
+  { echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}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
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_ac_ct_CC="$ac_prog"
+    echo "$as_me:$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
+  { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}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:)
+{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf at gnu.org." >&5
+echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools
+whose name does not start with the host triplet.  If you think this
+configuration is useful to you, please write to autoconf at gnu.org." >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+fi
+
+fi
+
+
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:$LINENO: checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (ac_try="$ac_compiler --version >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler --version >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -v >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler -v >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+{ (ac_try="$ac_compiler -V >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compiler -V >&5") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }
+
+{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; }
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_compiler_gnu=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	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
+{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; }
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; }
+if test "${ac_cv_prog_cc_g+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&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 >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	CFLAGS=""
+      cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_c_werror_flag=$ac_save_c_werror_flag
+	 CFLAGS="-g"
+	 cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_g=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+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
+{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$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
+{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5
+echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; }
+if test "${ac_cv_prog_cc_c89+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* 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"
+  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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_cv_prog_cc_c89=$ac_arg
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+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)
+    { echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6; } ;;
+  xno)
+    { echo "$as_me:$LINENO: result: unsupported" >&5
+echo "${ECHO_T}unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+
+
+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
+{ echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
+fi
+if test -z "$CPP"; then
+  if test "${ac_cv_prog_CPP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&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 >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  # Broken: success on invalid input.
+continue
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f 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
+{ echo "$as_me:$LINENO: result: $CPP" >&5
+echo "${ECHO_T}$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 >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+		     Syntax error
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  :
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Broken: fails on valid input.
+continue
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  # Broken: success on invalid input.
+continue
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+  :
+else
+  { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details." >&2;}
+   { (exit 1); exit 1; }; }
+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_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; 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
+  { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5
+echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;}
+   { (exit 1); exit 1; }; }
+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.
+
+
+# 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.
+{ echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6; }
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&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 { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$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
+	    ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+	    break 3
+	  fi
+	fi
+      done
+    done
+    ;;
+esac
+done
+IFS=$as_save_IFS
+
+
+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
+{ echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$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'
+
+{ echo "$as_me:$LINENO: checking whether ln -s works" >&5
+echo $ECHO_N "checking whether ln -s works... $ECHO_C" >&6; }
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+  { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no, using $LN_S" >&5
+echo "${ECHO_T}no, using $LN_S" >&6; }
+fi
+
+{ echo "$as_me:$LINENO: checking for GNU make" >&5
+echo $ECHO_N "checking for GNU make... $ECHO_C" >&6; }
+if test "${ac_cv_GNU_MAKE+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_GNU_MAKE='Not Found' ;
+   ac_cv_GNU_MAKE_VERSION_MAJOR=0 ;
+   ac_cv_GNU_MAKE_VERSION_MINOR=0 ;
+   for a in make gmake gnumake ; do
+      if test -z "$a" ; then continue ; fi ;
+      if ( sh -c "$a --version" 2> /dev/null | grep GNU  2>&1 > /dev/null ) ;  then
+         ac_cv_GNU_MAKE=$a ;
+         ac_cv_GNU_MAKE_VERSION_MAJOR=`$ac_cv_GNU_MAKE --version | grep "GNU Make" | cut -f3 -d' ' | cut -f1 -d'.'`
+         ac_cv_GNU_MAKE_VERSION_MINOR=`$ac_cv_GNU_MAKE --version | grep "GNU Make" | cut -f2 -d'.' | cut -c1-2`
+         break;
+      fi
+   done ;
+
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_GNU_MAKE" >&5
+echo "${ECHO_T}$ac_cv_GNU_MAKE" >&6; } ;
+if test  "x$ac_cv_GNU_MAKE" = "xNot Found"  ; then
+   { { echo "$as_me:$LINENO: error: *** Please install GNU make.  It is required to build Asterisk!" >&5
+echo "$as_me: error: *** Please install GNU make.  It is required to build Asterisk!" >&2;}
+   { (exit 1); exit 1; }; }
+   exit 1
+fi
+GNU_MAKE=$ac_cv_GNU_MAKE
+
+
+
+test_obj=conftest.o
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+
+	BDFNAME=`LANG=C objdump -f $test_obj | grep -e "$test_obj:" | sed "s/.*file format \(.*\)/\1/"`
+	BDFARCH=`LANG=C objdump -f $test_obj | grep -e "architecture:" | sed "s/.*ture: \(.*\),.*/\1/"`
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+
+# Set the default value of HOSTCC from CC if --host was not provided:
+HOSTCC=${HOSTCC:=${CC}}
+
+
+# Extract the first word of "grep", so it can be a program name with args.
+set dummy grep; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_GREP+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $GREP in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_GREP="$GREP" # 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_GREP="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_path_GREP" && ac_cv_path_GREP=":"
+  ;;
+esac
+fi
+GREP=$ac_cv_path_GREP
+if test -n "$GREP"; then
+  { echo "$as_me:$LINENO: result: $GREP" >&5
+echo "${ECHO_T}$GREP" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+# Extract the first word of "sh", so it can be a program name with args.
+set dummy sh; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_SHELL+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $SHELL in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_SHELL="$SHELL" # 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_SHELL="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_path_SHELL" && ac_cv_path_SHELL=":"
+  ;;
+esac
+fi
+SHELL=$ac_cv_path_SHELL
+if test -n "$SHELL"; then
+  { echo "$as_me:$LINENO: result: $SHELL" >&5
+echo "${ECHO_T}$SHELL" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+# Extract the first word of "ln", so it can be a program name with args.
+set dummy ln; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_LN+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $LN in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_LN="$LN" # 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_LN="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_path_LN" && ac_cv_path_LN=":"
+  ;;
+esac
+fi
+LN=$ac_cv_path_LN
+if test -n "$LN"; then
+  { echo "$as_me:$LINENO: result: $LN" >&5
+echo "${ECHO_T}$LN" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+
+# Extract the first word of "wget", so it can be a program name with args.
+set dummy wget; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_WGET+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $WGET in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_WGET="$WGET" # 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_WGET="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_path_WGET" && ac_cv_path_WGET=":"
+  ;;
+esac
+fi
+WGET=$ac_cv_path_WGET
+if test -n "$WGET"; then
+  { echo "$as_me:$LINENO: result: $WGET" >&5
+echo "${ECHO_T}$WGET" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+if test "${WGET}" != ":" ; then
+  DOWNLOAD=${WGET}
+else
+  # Extract the first word of "fetch", so it can be a program name with args.
+set dummy fetch; ac_word=$2
+{ echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; }
+if test "${ac_cv_path_FETCH+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $FETCH in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_FETCH="$FETCH" # 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 { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_FETCH="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_path_FETCH" && ac_cv_path_FETCH=":"
+  ;;
+esac
+fi
+FETCH=$ac_cv_path_FETCH
+if test -n "$FETCH"; then
+  { echo "$as_me:$LINENO: result: $FETCH" >&5
+echo "${ECHO_T}$FETCH" >&6; }
+else
+  { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+fi
+
+
+  DOWNLOAD=${FETCH}
+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
+
+
+# Check whether --enable-dev-mode was given.
+if test "${enable_dev_mode+set}" = set; then
+  enableval=$enable_dev_mode; case "${enableval}" in
+	      y|ye|yes) DAHDI_DEVMODE=yes ;;
+	      n|no)  DAHDI_DEVMODE=no ;;
+	      *) { { echo "$as_me:$LINENO: error: bad value ${enableval} for --enable-dev-mode" >&5
+echo "$as_me: error: bad value ${enableval} for --enable-dev-mode" >&2;}
+   { (exit 1); exit 1; }; }  ;;
+	esac
+fi
+
+
+
+{ echo "$as_me:$LINENO: checking for -Wdeclaration-after-statement support" >&5
+echo $ECHO_N "checking for -Wdeclaration-after-statement support... $ECHO_C" >&6; }
+if $(${CC} -Wdeclaration-after-statement -S -o /dev/null -xc /dev/null > /dev/null 2>&1); then
+	{ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+	DAHDI_DECLARATION_AFTER_STATEMENT=-Wdeclaration-after-statement
+else
+	{ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+	DAHDI_DECLARATION_AFTER_STATEMENT=
+fi
+
+
+
+    DAHDI_DESCRIP="DAHDI"
+    DAHDI_OPTION="dahdi"
+
+# Check whether --with-dahdi was given.
+if test "${with_dahdi+set}" = set; then
+  withval=$with_dahdi;
+	case ${withval} in
+	n|no)
+	USE_DAHDI=no
+	;;
+	y|ye|yes)
+	ac_mandatory_list="${ac_mandatory_list} DAHDI"
+	;;
+	*)
+	DAHDI_DIR="${withval}"
+	ac_mandatory_list="${ac_mandatory_list} DAHDI"
+	;;
+	esac
+
+fi
+
+    PBX_DAHDI=0
+
+
+
+
+
+
+    NEWT_DESCRIP="newt"
+    NEWT_OPTION="newt"
+
+# Check whether --with-newt was given.
+if test "${with_newt+set}" = set; then
+  withval=$with_newt;
+	case ${withval} in
+	n|no)
+	USE_NEWT=no
+	;;
+	y|ye|yes)
+	ac_mandatory_list="${ac_mandatory_list} NEWT"
+	;;
+	*)
+	NEWT_DIR="${withval}"
+	ac_mandatory_list="${ac_mandatory_list} NEWT"
+	;;
+	esac
+
+fi
+
+    PBX_NEWT=0
+
+
+
+
+
+
+    USB_DESCRIP="usb"
+    USB_OPTION="usb"
+
+# Check whether --with-usb was given.
+if test "${with_usb+set}" = set; then
+  withval=$with_usb;
+	case ${withval} in
+	n|no)
+	USE_USB=no
+	;;
+	y|ye|yes)
+	ac_mandatory_list="${ac_mandatory_list} USB"
+	;;
+	*)
+	USB_DIR="${withval}"
+	ac_mandatory_list="${ac_mandatory_list} USB"
+	;;
+	esac
+
+fi
+
+    PBX_USB=0
+
+
+
+
+
+
+
+    if test "x${PBX_DAHDI}" != "x1"; then
+	{ echo "$as_me:$LINENO: checking for DAHDI_CODE in dahdi/user.h" >&5
+echo $ECHO_N "checking for DAHDI_CODE in dahdi/user.h... $ECHO_C" >&6; }
+	saved_cppflags="${CPPFLAGS}"
+	if test "x${DAHDI_DIR}" != "x"; then
+	    DAHDI_INCLUDE="-I${DAHDI_DIR}/include"
+	fi
+	CPPFLAGS="${CPPFLAGS} ${DAHDI_INCLUDE}"
+
+	cat >conftest.$ac_ext <<_ACEOF
+ /* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <dahdi/user.h>
+int
+main ()
+{
+#if defined(DAHDI_CODE)
+				int foo = 0;
+			        #else
+			        int foo = bar;
+			        #endif
+				0
+
+  ;
+  return 0;
+}
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+     { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+		PBX_DAHDI=1
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_DAHDI 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_DAHDI_VERSION
+_ACEOF
+
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	   { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+	CPPFLAGS="${saved_cppflags}"
+    fi
+
+
+DAHDI23_DIR="${DAHDI_DIR}"
+
+    if test "x${PBX_DAHDI23}" != "x1"; then
+	{ echo "$as_me:$LINENO: checking for DAHDI_CONFIG_NTTE in dahdi/user.h" >&5
+echo $ECHO_N "checking for DAHDI_CONFIG_NTTE in dahdi/user.h... $ECHO_C" >&6; }
+	saved_cppflags="${CPPFLAGS}"
+	if test "x${DAHDI23_DIR}" != "x"; then
+	    DAHDI23_INCLUDE="-I${DAHDI23_DIR}/include"
+	fi
+	CPPFLAGS="${CPPFLAGS} ${DAHDI23_INCLUDE}"
+
+	cat >conftest.$ac_ext <<_ACEOF
+ /* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <dahdi/user.h>
+int
+main ()
+{
+#if defined(DAHDI_CONFIG_NTTE)
+				int foo = 0;
+			        #else
+			        int foo = bar;
+			        #endif
+				0
+
+  ;
+  return 0;
+}
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+     { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+		PBX_DAHDI23=1
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_DAHDI23 1
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_DAHDI23_VERSION
+_ACEOF
+
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	   { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+	CPPFLAGS="${saved_cppflags}"
+    fi
+
+
+
+if test "x${PBX_NEWT}" != "x1" -a "${USE_NEWT}" != "no"; then
+   pbxlibdir=""
+   # if --with-NEWT=DIR has been specified, use it.
+   if test "x${NEWT_DIR}" != "x"; then
+      if test -d ${NEWT_DIR}/lib; then
+      	 pbxlibdir="-L${NEWT_DIR}/lib"
+      else
+      	 pbxlibdir="-L${NEWT_DIR}"
+      fi
+   fi
+   pbxfuncname="newtBell"
+   if test "x${pbxfuncname}" = "x" ; then   # empty lib, assume only headers
+      AST_NEWT_FOUND=yes
+   else
+      as_ac_Lib=`echo "ac_cv_lib_newt_${pbxfuncname}" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for ${pbxfuncname} in -lnewt" >&5
+echo $ECHO_N "checking for ${pbxfuncname} in -lnewt... $ECHO_C" >&6; }
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lnewt ${pbxlibdir}  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* 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 ${pbxfuncname} ();
+int
+main ()
+{
+return ${pbxfuncname} ();
+  ;
+  return 0;
+}
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_Lib=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	eval "$as_ac_Lib=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+ac_res=`eval echo '${'$as_ac_Lib'}'`
+	       { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_Lib'}'` = yes; then
+  AST_NEWT_FOUND=yes
+else
+  AST_NEWT_FOUND=no
+fi
+
+   fi
+
+   # now check for the header.
+   if test "${AST_NEWT_FOUND}" = "yes"; then
+      NEWT_LIB="${pbxlibdir} -lnewt "
+      # if --with-NEWT=DIR has been specified, use it.
+      if test "x${NEWT_DIR}" != "x"; then
+	 NEWT_INCLUDE="-I${NEWT_DIR}/include"
+      fi
+      NEWT_INCLUDE="${NEWT_INCLUDE} "
+      if test "xnewt.h" = "x" ; then	# no header, assume found
+         NEWT_HEADER_FOUND="1"
+      else				# check for the header
+         saved_cppflags="${CPPFLAGS}"
+         CPPFLAGS="${CPPFLAGS} ${NEWT_INCLUDE} "
+	 if test "${ac_cv_header_newt_h+set}" = set; then
+  { echo "$as_me:$LINENO: checking for newt.h" >&5
+echo $ECHO_N "checking for newt.h... $ECHO_C" >&6; }
+if test "${ac_cv_header_newt_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_newt_h" >&5
+echo "${ECHO_T}$ac_cv_header_newt_h" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking newt.h usability" >&5
+echo $ECHO_N "checking newt.h usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <newt.h>
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking newt.h presence" >&5
+echo $ECHO_N "checking newt.h presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <newt.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: newt.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: newt.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: newt.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: newt.h: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: newt.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: newt.h: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: newt.h:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: newt.h:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: newt.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: newt.h: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: newt.h:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: newt.h:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: newt.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: newt.h: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: newt.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: newt.h: in the future, the compiler will take precedence" >&2;}
+
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for newt.h" >&5
+echo $ECHO_N "checking for newt.h... $ECHO_C" >&6; }
+if test "${ac_cv_header_newt_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_header_newt_h=$ac_header_preproc
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_newt_h" >&5
+echo "${ECHO_T}$ac_cv_header_newt_h" >&6; }
+
+fi
+if test $ac_cv_header_newt_h = yes; then
+  NEWT_HEADER_FOUND=1
+else
+  NEWT_HEADER_FOUND=0
+fi
+
+
+         CPPFLAGS="${saved_cppflags}"
+      fi
+      if test "x${NEWT_HEADER_FOUND}" = "x0" ; then
+         NEWT_LIB=""
+         NEWT_INCLUDE=""
+      else
+         if test "x${pbxfuncname}" = "x" ; then		# only checking headers -> no library
+	    NEWT_LIB=""
+	 fi
+         PBX_NEWT=1
+         # XXX don't know how to evaluate the description (third argument) in AC_DEFINE_UNQUOTED
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_NEWT 1
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_NEWT_VERSION
+_ACEOF
+
+      fi
+   fi
+fi
+
+
+if test "x${PBX_USB}" != "x1" -a "${USE_USB}" != "no"; then
+   pbxlibdir=""
+   # if --with-USB=DIR has been specified, use it.
+   if test "x${USB_DIR}" != "x"; then
+      if test -d ${USB_DIR}/lib; then
+      	 pbxlibdir="-L${USB_DIR}/lib"
+      else
+      	 pbxlibdir="-L${USB_DIR}"
+      fi
+   fi
+   pbxfuncname="usb_init"
+   if test "x${pbxfuncname}" = "x" ; then   # empty lib, assume only headers
+      AST_USB_FOUND=yes
+   else
+      as_ac_Lib=`echo "ac_cv_lib_usb_${pbxfuncname}" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for ${pbxfuncname} in -lusb" >&5
+echo $ECHO_N "checking for ${pbxfuncname} in -lusb... $ECHO_C" >&6; }
+if { as_var=$as_ac_Lib; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lusb ${pbxlibdir}  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* 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 ${pbxfuncname} ();
+int
+main ()
+{
+return ${pbxfuncname} ();
+  ;
+  return 0;
+}
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest$ac_exeext &&
+       $as_test_x conftest$ac_exeext; then
+  eval "$as_ac_Lib=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	eval "$as_ac_Lib=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+ac_res=`eval echo '${'$as_ac_Lib'}'`
+	       { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_Lib'}'` = yes; then
+  AST_USB_FOUND=yes
+else
+  AST_USB_FOUND=no
+fi
+
+   fi
+
+   # now check for the header.
+   if test "${AST_USB_FOUND}" = "yes"; then
+      USB_LIB="${pbxlibdir} -lusb "
+      # if --with-USB=DIR has been specified, use it.
+      if test "x${USB_DIR}" != "x"; then
+	 USB_INCLUDE="-I${USB_DIR}/include"
+      fi
+      USB_INCLUDE="${USB_INCLUDE} "
+      if test "xusb.h" = "x" ; then	# no header, assume found
+         USB_HEADER_FOUND="1"
+      else				# check for the header
+         saved_cppflags="${CPPFLAGS}"
+         CPPFLAGS="${CPPFLAGS} ${USB_INCLUDE} "
+	 if test "${ac_cv_header_usb_h+set}" = set; then
+  { echo "$as_me:$LINENO: checking for usb.h" >&5
+echo $ECHO_N "checking for usb.h... $ECHO_C" >&6; }
+if test "${ac_cv_header_usb_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_usb_h" >&5
+echo "${ECHO_T}$ac_cv_header_usb_h" >&6; }
+else
+  # Is the header compilable?
+{ echo "$as_me:$LINENO: checking usb.h usability" >&5
+echo $ECHO_N "checking usb.h usability... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <usb.h>
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  ac_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	ac_header_compiler=no
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ echo "$as_me:$LINENO: checking usb.h presence" >&5
+echo $ECHO_N "checking usb.h presence... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <usb.h>
+_ACEOF
+if { (ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null && {
+	 test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       }; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+
+rm -f conftest.err conftest.$ac_ext
+{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6; }
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: usb.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: usb.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: usb.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: usb.h: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: usb.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: usb.h: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: usb.h:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: usb.h:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: usb.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: usb.h: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: usb.h:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: usb.h:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: usb.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: usb.h: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: usb.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: usb.h: in the future, the compiler will take precedence" >&2;}
+
+    ;;
+esac
+{ echo "$as_me:$LINENO: checking for usb.h" >&5
+echo $ECHO_N "checking for usb.h... $ECHO_C" >&6; }
+if test "${ac_cv_header_usb_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_header_usb_h=$ac_header_preproc
+fi
+{ echo "$as_me:$LINENO: result: $ac_cv_header_usb_h" >&5
+echo "${ECHO_T}$ac_cv_header_usb_h" >&6; }
+
+fi
+if test $ac_cv_header_usb_h = yes; then
+  USB_HEADER_FOUND=1
+else
+  USB_HEADER_FOUND=0
+fi
+
+
+         CPPFLAGS="${saved_cppflags}"
+      fi
+      if test "x${USB_HEADER_FOUND}" = "x0" ; then
+         USB_LIB=""
+         USB_INCLUDE=""
+      else
+         if test "x${pbxfuncname}" = "x" ; then		# only checking headers -> no library
+	    USB_LIB=""
+	 fi
+         PBX_USB=1
+         # XXX don't know how to evaluate the description (third argument) in AC_DEFINE_UNQUOTED
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_USB 1
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_USB_VERSION
+_ACEOF
+
+      fi
+   fi
+fi
+
+
+PBX_HDLC=0
+{ echo "$as_me:$LINENO: checking for GENERIC_HDLC_VERSION version 4 in linux/hdlc.h" >&5
+echo $ECHO_N "checking for GENERIC_HDLC_VERSION version 4 in linux/hdlc.h... $ECHO_C" >&6; }
+cat >conftest.$ac_ext <<_ACEOF
+ /* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <linux/hdlc.h>
+int
+main ()
+{
+#if defined(GENERIC_HDLC_VERSION) && GENERIC_HDLC_VERSION >= 4
+		int foo = 0;
+		#else
+		int foo = bar;
+		#endif
+		0
+  ;
+  return 0;
+}
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+	 PBX_HDLC=1
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	{ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+if test $PBX_HDLC = 0; then
+    { echo "$as_me:$LINENO: checking for GENERIC_HDLC_VERSION version 4 in linux/hdlc/ioctl.h" >&5
+echo $ECHO_N "checking for GENERIC_HDLC_VERSION version 4 in linux/hdlc/ioctl.h... $ECHO_C" >&6; }
+    cat >conftest.$ac_ext <<_ACEOF
+ /* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+		    #include <sys/socket.h>
+			#include <linux/if.h>
+int
+main ()
+{
+#if defined(GENERIC_HDLC_VERSION) && GENERIC_HDLC_VERSION >= 4
+			int foo = 0;
+			#else
+			int foo = bar;
+			#endif
+			0
+  ;
+  return 0;
+}
+_ACEOF
+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 "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } && {
+	 test -z "$ac_c_werror_flag" ||
+	 test ! -s conftest.err
+       } && test -s conftest.$ac_objext; then
+  { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+		 PBX_HDLC=1
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	{ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+
+if test "x${PBX_HDLC}" != "x1"; then
+   { echo "$as_me:$LINENO: GENERIC_HDLC_VERSION (version 4) not found, disabling sethdlc." >&5
+echo "$as_me: GENERIC_HDLC_VERSION (version 4) not found, disabling sethdlc." >&6;}
+fi
+
+
+
+
+# Check whether --with-selinux was given.
+if test "${with_selinux+set}" = set; then
+  withval=$with_selinux; USE_SELINUX=$withval
+else
+   if test ! -x /usr/sbin/sestatus; then
+	   	USE_SELINUX=no;
+	  elif /usr/sbin/sestatus | grep "SELinux status:" | grep -q "enabled"; then
+		USE_SELINUX=yes
+	  fi
+
+
+fi
+
+
+
+
+
+# for asciidoc before ver. 7, the backend must be stated explicitly:
+ASCIIDOC='asciidoc'
+asciidoc_ver=`asciidoc --version 2>&1 | awk '/^asciidoc /{print $2}' | cut -d. -f 1 | head -n 1`
+if test "$asciidoc_ver" != '' && test $asciidoc_ver -lt 7; then
+	ASCIIDOC="asciidoc -b xhtml"
+fi
+
+
+
+# Check whether --with-ppp was given.
+if test "${with_ppp+set}" = set; then
+  withval=$with_ppp;
+else
+  with_ppp=check
+
+fi
+
+# somebody will fix that
+default_ppp_path=/usr
+
+case "$with_ppp" in
+	yes|check) ppp_path="$default_ppp_path";;
+	no) ppp_path='' ;;
+	*) ppp_path="$with_ppp" ;;
+esac
+
+level_file="$ppp_path/include/pppd/patchlevel.h"
+PPP_VERSION=
+if test "$ppp_path" != '' && test -r "$level_file"; then
+	PPPD_VERSION=`awk -F '"' '/VERSION/ { print $$2; }' $level_file`
+fi
+
+case "$with_ppp" in
+	check|no) :;;
+	*)
+	# If we asked explicitly for ppp support
+	if test "$PPPD_VERSION" = ''; then
+		# but have not detected it
+		{ { echo "$as_me:$LINENO: error: failed to find pppd/patchlevel.h: no ppp support." >&5
+echo "$as_me: error: failed to find pppd/patchlevel.h: no ppp support." >&2;}
+   { (exit 1); exit 1; }; }
+	fi
+	;;
+esac
+
+if test "x${PBX_DAHDI}" != "x1"; then
+   { echo "$as_me:$LINENO: ***" >&5
+echo "$as_me: ***" >&6;}
+   { echo "$as_me:$LINENO: *** Building this package requires DAHDI support. *** " >&5
+echo "$as_me: *** Building this package requires DAHDI support. *** " >&6;}
+   { echo "$as_me:$LINENO: *** Please install the dahdi-linux package. ***" >&5
+echo "$as_me: *** Please install the dahdi-linux package. ***" >&6;}
+   { echo "$as_me:$LINENO: ***" >&5
+echo "$as_me: ***" >&6;}
+   exit 1
+fi
+
+if test "x${PBX_DAHDI23}" != "x1"; then
+   { echo "$as_me:$LINENO: ***" >&5
+echo "$as_me: ***" >&6;}
+   { echo "$as_me:$LINENO: *** Building this package requires DAHDI support (>= 2.3) *** " >&5
+echo "$as_me: *** Building this package requires DAHDI support (>= 2.3) *** " >&6;}
+   { echo "$as_me:$LINENO: *** Please install a recent dahdi-linux package. ***" >&5
+echo "$as_me: *** Please install a recent dahdi-linux package. ***" >&6;}
+   { echo "$as_me:$LINENO: ***" >&5
+echo "$as_me: ***" >&6;}
+   exit 1
+fi
+
+
+
+ac_config_files="$ac_config_files build_tools/menuselect-deps makeopts"
+
+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_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5
+echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;;
+      esac
+      case $ac_var in #(
+      _ | IFS | as_nl) ;; #(
+      *) $as_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
+    test "x$cache_file" != "x/dev/null" &&
+      { echo "$as_me:$LINENO: updating cache $cache_file" >&5
+echo "$as_me: updating cache $cache_file" >&6;}
+    cat confcache >$cache_file
+  else
+    { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5
+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=
+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=`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.
+  ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+  ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $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}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+## --------------------- ##
+## 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=:
+  # 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
+
+
+
+
+# PATH needs CR
+# 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
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conf$$.sh
+  echo  "exit 0"   >>conf$$.sh
+  chmod +x conf$$.sh
+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+    PATH_SEPARATOR=';'
+  else
+    PATH_SEPARATOR=:
+  fi
+  rm -f conf$$.sh
+fi
+
+# Support unset when possible.
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+  as_unset=unset
+else
+  as_unset=false
+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.)
+as_nl='
+'
+IFS=" ""	$as_nl"
+
+# Find who we are.  Look in the path if we contain no directory separator.
+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
+  echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+  { (exit 1); exit 1; }
+fi
+
+# Work around bugs in pre-3.0 UWIN ksh.
+for as_var in ENV MAIL MAILPATH
+do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+for as_var in \
+  LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
+  LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
+  LC_TELEPHONE LC_TIME
+do
+  if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
+    eval $as_var=C; export $as_var
+  else
+    ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var
+  fi
+done
+
+# Required to use basename.
+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
+
+
+# Name of the executable.
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+	 X"$0" : 'X\(//\)$' \| \
+	 X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+echo X/"$0" |
+    sed '/^.*\/\([^/][^/]*\)\/*$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\/\)$/{
+	    s//\1/
+	    q
+	  }
+	  /^X\/\(\/\).*/{
+	    s//\1/
+	    q
+	  }
+	  s/.*/./; q'`
+
+# CDPATH.
+$as_unset CDPATH
+
+
+
+  as_lineno_1=$LINENO
+  as_lineno_2=$LINENO
+  test "x$as_lineno_1" != "x$as_lineno_2" &&
+  test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || {
+
+  # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+  # uniformly replaced by the line number.  The first 'sed' inserts a
+  # line-number line after each line using $LINENO; the second 'sed'
+  # does the real work.  The second script uses 'N' to pair each
+  # line-number line with the line containing $LINENO, and appends
+  # trailing '-' during substitution so that $LINENO is not a special
+  # case at line end.
+  # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+  # scripts with optimization help from Paolo Bonzini.  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" ||
+    { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+   { (exit 1); exit 1; }; }
+
+  # 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
+}
+
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+  as_dirname=dirname
+else
+  as_dirname=false
+fi
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in
+-n*)
+  case `echo 'x\c'` in
+  *c*) ECHO_T='	';;	# ECHO_T is single tab character.
+  *)   ECHO_C='\c';;
+  esac;;
+*)
+  ECHO_N='-n';;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+   test "X`expr 00001 : '.*\(...\)'`" = X001; then
+  as_expr=expr
+else
+  as_expr=false
+fi
+
+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
+fi
+echo >conf$$.file
+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 -p'.
+  ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+    as_ln_s='cp -p'
+elif ln conf$$.file conf$$ 2>/dev/null; then
+  as_ln_s=ln
+else
+  as_ln_s='cp -p'
+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=:
+else
+  test -d ./-p && rmdir ./-p
+  as_mkdir_p=false
+fi
+
+if test -x / >/dev/null 2>&1; then
+  as_test_x='test -x'
+else
+  if ls -dL / >/dev/null 2>&1; then
+    as_ls_L_option=L
+  else
+    as_ls_L_option=
+  fi
+  as_test_x='
+    eval sh -c '\''
+      if test -d "$1"; then
+        test -d "$1/.";
+      else
+	case $1 in
+        -*)set "./$1";;
+	esac;
+	case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in
+	???[sx]*):;;*)false;;esac;fi
+    '\'' sh
+  '
+fi
+as_executable_p=$as_test_x
+
+# 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
+
+# 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 $as_me, which was
+generated by GNU Autoconf 2.61.  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
+
+cat >>$CONFIG_STATUS <<_ACEOF
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+  -h, --help       print this help, then exit
+  -V, --version    print version number and configuration settings, then exit
+  -q, --quiet      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
+
+Report bugs to <bug-autoconf at gnu.org>."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.61,
+  with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright (C) 2006 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'
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If no file are specified by the user, then we need to provide default
+# value.  By we need to know if files were specified by the user.
+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=$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 )
+    echo "$ac_cs_version"; exit ;;
+  --debug | --debu | --deb | --de | --d | -d )
+    debug=: ;;
+  --file | --fil | --fi | --f )
+    $ac_shift
+    CONFIG_FILES="$CONFIG_FILES $ac_optarg"
+    ac_need_defaults=false;;
+  --header | --heade | --head | --hea )
+    $ac_shift
+    CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
+    ac_need_defaults=false;;
+  --he | --h)
+    # Conflict between --help and --header
+    { echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; };;
+  --help | --hel | -h )
+    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.
+  -*) { echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2
+   { (exit 1); exit 1; }; } ;;
+
+  *) ac_config_targets="$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
+if \$ac_cs_recheck; then
+  echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6
+  CONFIG_SHELL=$SHELL
+  export CONFIG_SHELL
+  exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+exec 5>>config.log
+{
+  echo
+  sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+  echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+  case $ac_config_target in
+    "autoconfig.h") CONFIG_HEADERS="$CONFIG_HEADERS autoconfig.h" ;;
+    "build_tools/menuselect-deps") CONFIG_FILES="$CONFIG_FILES build_tools/menuselect-deps" ;;
+    "makeopts") CONFIG_FILES="$CONFIG_FILES makeopts" ;;
+
+  *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+   { (exit 1); exit 1; }; };;
+  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
+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=
+  trap 'exit_status=$?
+  { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status
+' 0
+  trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+  tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+  test -n "$tmp" && test -d "$tmp"
+}  ||
+{
+  tmp=./conf$$-$RANDOM
+  (umask 077 && mkdir "$tmp")
+} ||
+{
+   echo "$me: cannot create a temporary directory in ." >&2
+   { (exit 1); exit 1; }
+}
+
+#
+# Set up the sed scripts for CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "$CONFIG_FILES"; then
+
+_ACEOF
+
+
+
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+  cat >conf$$subs.sed <<_ACEOF
+SHELL!$SHELL$ac_delim
+PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim
+PACKAGE_NAME!$PACKAGE_NAME$ac_delim
+PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim
+PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim
+PACKAGE_STRING!$PACKAGE_STRING$ac_delim
+PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim
+exec_prefix!$exec_prefix$ac_delim
+prefix!$prefix$ac_delim
+program_transform_name!$program_transform_name$ac_delim
+bindir!$bindir$ac_delim
+sbindir!$sbindir$ac_delim
+libexecdir!$libexecdir$ac_delim
+datarootdir!$datarootdir$ac_delim
+datadir!$datadir$ac_delim
+sysconfdir!$sysconfdir$ac_delim
+sharedstatedir!$sharedstatedir$ac_delim
+localstatedir!$localstatedir$ac_delim
+includedir!$includedir$ac_delim
+oldincludedir!$oldincludedir$ac_delim
+docdir!$docdir$ac_delim
+infodir!$infodir$ac_delim
+htmldir!$htmldir$ac_delim
+dvidir!$dvidir$ac_delim
+pdfdir!$pdfdir$ac_delim
+psdir!$psdir$ac_delim
+libdir!$libdir$ac_delim
+localedir!$localedir$ac_delim
+mandir!$mandir$ac_delim
+DEFS!$DEFS$ac_delim
+ECHO_C!$ECHO_C$ac_delim
+ECHO_N!$ECHO_N$ac_delim
+ECHO_T!$ECHO_T$ac_delim
+LIBS!$LIBS$ac_delim
+build_alias!$build_alias$ac_delim
+host_alias!$host_alias$ac_delim
+target_alias!$target_alias$ac_delim
+CC!$CC$ac_delim
+CFLAGS!$CFLAGS$ac_delim
+LDFLAGS!$LDFLAGS$ac_delim
+CPPFLAGS!$CPPFLAGS$ac_delim
+ac_ct_CC!$ac_ct_CC$ac_delim
+EXEEXT!$EXEEXT$ac_delim
+OBJEXT!$OBJEXT$ac_delim
+CPP!$CPP$ac_delim
+GREP!$GREP$ac_delim
+EGREP!$EGREP$ac_delim
+LD!$LD$ac_delim
+INSTALL_PROGRAM!$INSTALL_PROGRAM$ac_delim
+INSTALL_SCRIPT!$INSTALL_SCRIPT$ac_delim
+INSTALL_DATA!$INSTALL_DATA$ac_delim
+LN_S!$LN_S$ac_delim
+GNU_MAKE!$GNU_MAKE$ac_delim
+BDFNAME!$BDFNAME$ac_delim
+BDFARCH!$BDFARCH$ac_delim
+HOSTCC!$HOSTCC$ac_delim
+LN!$LN$ac_delim
+WGET!$WGET$ac_delim
+FETCH!$FETCH$ac_delim
+DOWNLOAD!$DOWNLOAD$ac_delim
+DAHDI_DEVMODE!$DAHDI_DEVMODE$ac_delim
+DAHDI_DECLARATION_AFTER_STATEMENT!$DAHDI_DECLARATION_AFTER_STATEMENT$ac_delim
+DAHDI_LIB!$DAHDI_LIB$ac_delim
+DAHDI_INCLUDE!$DAHDI_INCLUDE$ac_delim
+DAHDI_DIR!$DAHDI_DIR$ac_delim
+PBX_DAHDI!$PBX_DAHDI$ac_delim
+NEWT_LIB!$NEWT_LIB$ac_delim
+NEWT_INCLUDE!$NEWT_INCLUDE$ac_delim
+NEWT_DIR!$NEWT_DIR$ac_delim
+PBX_NEWT!$PBX_NEWT$ac_delim
+USB_LIB!$USB_LIB$ac_delim
+USB_INCLUDE!$USB_INCLUDE$ac_delim
+USB_DIR!$USB_DIR$ac_delim
+PBX_USB!$PBX_USB$ac_delim
+PBX_DAHDI23!$PBX_DAHDI23$ac_delim
+PBX_HDLC!$PBX_HDLC$ac_delim
+USE_SELINUX!$USE_SELINUX$ac_delim
+ASCIIDOC!$ASCIIDOC$ac_delim
+PPPD_VERSION!$PPPD_VERSION$ac_delim
+LIBOBJS!$LIBOBJS$ac_delim
+LTLIBOBJS!$LTLIBOBJS$ac_delim
+_ACEOF
+
+  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 81; then
+    break
+  elif $ac_last_try; then
+    { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
+echo "$as_me: error: could not make $CONFIG_STATUS" >&2;}
+   { (exit 1); exit 1; }; }
+  else
+    ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+  fi
+done
+
+ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed`
+if test -n "$ac_eof"; then
+  ac_eof=`echo "$ac_eof" | sort -nru | sed 1q`
+  ac_eof=`expr $ac_eof + 1`
+fi
+
+cat >>$CONFIG_STATUS <<_ACEOF
+cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end
+_ACEOF
+sed '
+s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g
+s/^/s,@/; s/!/@,|#_!!_#|/
+:n
+t n
+s/'"$ac_delim"'$/,g/; t
+s/$/\\/; p
+N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n
+' >>$CONFIG_STATUS <conf$$subs.sed
+rm -f conf$$subs.sed
+cat >>$CONFIG_STATUS <<_ACEOF
+:end
+s/|#_!!_#|//g
+CEOF$ac_eof
+_ACEOF
+
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ 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[	 ]*=/{
+s/:*\$(srcdir):*/:/
+s/:*\${srcdir}:*/:/
+s/:*@srcdir@:*/:/
+s/^\([^=]*=[	 ]*\):*/\1/
+s/:*$//
+s/^[^=]*=[	 ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+fi # test -n "$CONFIG_FILES"
+
+
+for ac_tag in  :F $CONFIG_FILES  :H $CONFIG_HEADERS
+do
+  case $ac_tag in
+  :[FHLC]) ac_mode=$ac_tag; continue;;
+  esac
+  case $ac_mode$ac_tag in
+  :[FHL]*:*);;
+  :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5
+echo "$as_me: error: Invalid tag $ac_tag." >&2;}
+   { (exit 1); exit 1; }; };;
+  :[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="$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 ||
+	   { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5
+echo "$as_me: error: cannot find input file: $ac_f" >&2;}
+   { (exit 1); exit 1; }; };;
+      esac
+      ac_file_inputs="$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 "`IFS=:
+	  echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure."
+    if test x"$ac_file" != x-; then
+      configure_input="$ac_file.  $configure_input"
+      { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+    fi
+
+    case $ac_tag in
+    *:-:* | *:-) cat >"$tmp/stdin";;
+    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 ||
+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"
+  case $as_dir in #(
+  -*) as_dir=./$as_dir;;
+  esac
+  test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || {
+    as_dirs=
+    while :; do
+      case $as_dir in #(
+      *\'*) as_qdir=`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 ||
+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" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5
+echo "$as_me: error: cannot create directory $as_dir" >&2;}
+   { (exit 1); exit 1; }; }; }
+  ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+  ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+  # A ".." for each directory in $ac_dir_suffix.
+  ac_top_builddir_sub=`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
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# 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=
+
+case `sed -n '/datarootdir/ {
+  p
+  q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p
+' $ac_file_inputs` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+  { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+  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
+  sed "$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s&@configure_input@&$configure_input&;t t
+s&@top_builddir@&$ac_top_builddir_sub&;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
+$ac_datarootdir_hack
+" $ac_file_inputs | sed -f "$tmp/subs-1.sed" >$tmp/out
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+  { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } &&
+  { ac_out=`sed -n '/^[	 ]*datarootdir[	 ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } &&
+  { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined.  Please make sure it is defined." >&5
+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 "$tmp/stdin"
+  case $ac_file in
+  -) cat "$tmp/out"; rm -f "$tmp/out";;
+  *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;;
+  esac
+ ;;
+  :H)
+  #
+  # CONFIG_HEADER
+  #
+_ACEOF
+
+# Transform confdefs.h into a sed script `conftest.defines', that
+# substitutes the proper values into config.h.in to produce config.h.
+rm -f conftest.defines conftest.tail
+# First, append a space to every undef/define line, to ease matching.
+echo 's/$/ /' >conftest.defines
+# Then, protect against being on the right side of a sed subst, or in
+# an unquoted here document, in config.status.  If some macros were
+# called several times there might be several #defines for the same
+# symbol, which is useless.  But do not sort them, since the last
+# AC_DEFINE must be honored.
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+# These sed commands are passed to sed as "A NAME B PARAMS C VALUE D", where
+# NAME is the cpp macro being defined, VALUE is the value it is being given.
+# PARAMS is the parameter list in the macro definition--in most cases, it's
+# just an empty string.
+ac_dA='s,^\\([	 #]*\\)[^	 ]*\\([	 ]*'
+ac_dB='\\)[	 (].*,\\1define\\2'
+ac_dC=' '
+ac_dD=' ,'
+
+uniq confdefs.h |
+  sed -n '
+	t rset
+	:rset
+	s/^[	 ]*#[	 ]*define[	 ][	 ]*//
+	t ok
+	d
+	:ok
+	s/[\\&,]/\\&/g
+	s/^\('"$ac_word_re"'\)\(([^()]*)\)[	 ]*\(.*\)/ '"$ac_dA"'\1'"$ac_dB"'\2'"${ac_dC}"'\3'"$ac_dD"'/p
+	s/^\('"$ac_word_re"'\)[	 ]*\(.*\)/'"$ac_dA"'\1'"$ac_dB$ac_dC"'\2'"$ac_dD"'/p
+  ' >>conftest.defines
+
+# Remove the space that was appended to ease matching.
+# Then 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.
+# (The regexp can be short, since the line contains either #define or #undef.)
+echo 's/ $//
+s,^[	 #]*u.*,/* & */,' >>conftest.defines
+
+# Break up conftest.defines:
+ac_max_sed_lines=50
+
+# First sed command is:	 sed -f defines.sed $ac_file_inputs >"$tmp/out1"
+# Second one is:	 sed -f defines.sed "$tmp/out1" >"$tmp/out2"
+# Third one will be:	 sed -f defines.sed "$tmp/out2" >"$tmp/out1"
+# et cetera.
+ac_in='$ac_file_inputs'
+ac_out='"$tmp/out1"'
+ac_nxt='"$tmp/out2"'
+
+while :
+do
+  # Write a here document:
+    cat >>$CONFIG_STATUS <<_ACEOF
+    # First, check the format of the line:
+    cat >"\$tmp/defines.sed" <<\\CEOF
+/^[	 ]*#[	 ]*undef[	 ][	 ]*$ac_word_re[	 ]*\$/b def
+/^[	 ]*#[	 ]*define[	 ][	 ]*$ac_word_re[(	 ]/b def
+b
+:def
+_ACEOF
+  sed ${ac_max_sed_lines}q conftest.defines >>$CONFIG_STATUS
+  echo 'CEOF
+    sed -f "$tmp/defines.sed"' "$ac_in >$ac_out" >>$CONFIG_STATUS
+  ac_in=$ac_out; ac_out=$ac_nxt; ac_nxt=$ac_in
+  sed 1,${ac_max_sed_lines}d conftest.defines >conftest.tail
+  grep . conftest.tail >/dev/null || break
+  rm -f conftest.defines
+  mv conftest.tail conftest.defines
+done
+rm -f conftest.defines conftest.tail
+
+echo "ac_result=$ac_in" >>$CONFIG_STATUS
+cat >>$CONFIG_STATUS <<\_ACEOF
+  if test x"$ac_file" != x-; then
+    echo "/* $configure_input  */" >"$tmp/config.h"
+    cat "$ac_result" >>"$tmp/config.h"
+    if diff $ac_file "$tmp/config.h" >/dev/null 2>&1; then
+      { echo "$as_me:$LINENO: $ac_file is unchanged" >&5
+echo "$as_me: $ac_file is unchanged" >&6;}
+    else
+      rm -f $ac_file
+      mv "$tmp/config.h" $ac_file
+    fi
+  else
+    echo "/* $configure_input  */"
+    cat "$ac_result"
+  fi
+  rm -f "$tmp/out12"
+ ;;
+
+
+  esac
+
+done # for ac_tag
+
+
+{ (exit 0); exit 0; }
+_ACEOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+
+# 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 || { (exit 1); exit 1; }
+fi
+
+
+{ echo "$as_me:$LINENO: *** dahdi-tools build successfully configured ***" >&5
+echo "$as_me: *** dahdi-tools build successfully configured ***" >&6;}
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..35e51e1
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,215 @@
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ(2.59)
+ 
+m4_define([TOOLSVERSION],
+          m4_bpatsubst(m4_esyscmd([build_tools/make_version . dahdi/tools]),
+                       [\([0-9.]*\)\(\w\|\W\)*],
+                       [\1]))
+AC_INIT(dahdi, TOOLSVERSION, www.asterisk.org)
+
+# check existence of the package
+AC_CONFIG_SRCDIR([dahdi_cfg.c])
+
+AC_COPYRIGHT("dahdi-tools")
+AC_REVISION($Revision$)
+
+ac_default_prefix=/usr
+if test ${sysconfdir} = '${prefix}/etc'; then
+   sysconfdir=/etc
+fi
+if test ${mandir} = '${prefix}/man'; then
+   mandir=/usr/share/man
+fi
+
+if test ${localstatedir} = '${prefix}/var'; then
+     localstatedir=/var
+fi
+
+# specify output header file
+AC_CONFIG_HEADER(autoconfig.h)
+
+# This needs to be before any macros that use the C compiler
+AC_GNU_SOURCE
+
+AC_CHECK_HEADERS([sys/soundcard.h linux/soundcard.h])
+
+AC_CHECK_TOOL([LD], [ld])
+
+# Checks for programs.
+AC_PROG_CC
+AC_PROG_CPP
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AST_CHECK_GNU_MAKE
+
+test_obj=conftest.o
+AC_COMPILE_IFELSE(AC_LANG_SOURCE(),[
+	BDFNAME=`LANG=C objdump -f $test_obj | grep -e "$test_obj:" | sed "s/.*file format \(.*\)/\1/"`
+	BDFARCH=`LANG=C objdump -f $test_obj | grep -e "architecture:" | sed "s/.*ture: \(.*\),.*/\1/"`	   
+],[])
+AC_SUBST(BDFNAME)
+AC_SUBST(BDFARCH)
+
+# Set the default value of HOSTCC from CC if --host was not provided:
+HOSTCC=${HOSTCC:=${CC}}
+AC_SUBST(HOSTCC)
+
+AC_PATH_PROG([GREP], [grep], :)
+AC_PATH_PROG([SHELL], [sh], :)
+AC_PATH_PROG([LN], [ln], :)
+
+AC_PATH_PROG([WGET], [wget], :)
+if test "${WGET}" != ":" ; then
+  DOWNLOAD=${WGET}
+else
+  AC_PATH_PROG([FETCH], [fetch], [:])
+  DOWNLOAD=${FETCH}
+fi
+AC_SUBST(DOWNLOAD)
+
+AC_LANG(C)
+
+AC_ARG_ENABLE(dev-mode,
+	[  --enable-dev-mode    Turn on developer mode],
+	[case "${enableval}" in
+	      y|ye|yes) DAHDI_DEVMODE=yes ;;
+	      n|no)  DAHDI_DEVMODE=no ;;
+	      *) AC_MSG_ERROR(bad value ${enableval} for --enable-dev-mode)  ;;
+	esac])
+AC_SUBST(DAHDI_DEVMODE)
+
+AC_MSG_CHECKING(for -Wdeclaration-after-statement support)
+if $(${CC} -Wdeclaration-after-statement -S -o /dev/null -xc /dev/null > /dev/null 2>&1); then
+	AC_MSG_RESULT(yes)
+	DAHDI_DECLARATION_AFTER_STATEMENT=-Wdeclaration-after-statement
+else
+	AC_MSG_RESULT(no)
+	DAHDI_DECLARATION_AFTER_STATEMENT=
+fi
+AC_SUBST(DAHDI_DECLARATION_AFTER_STATEMENT)
+
+AST_EXT_LIB_SETUP([DAHDI], [DAHDI], [dahdi])
+AST_EXT_LIB_SETUP([NEWT], [newt], [newt])
+AST_EXT_LIB_SETUP([USB], [usb], [usb])
+
+AST_C_DEFINE_CHECK([DAHDI], [DAHDI_CODE], [dahdi/user.h])
+DAHDI23_DIR="${DAHDI_DIR}"
+AST_C_DEFINE_CHECK([DAHDI23], [DAHDI_CONFIG_NTTE], [dahdi/user.h])
+AST_EXT_LIB_CHECK([NEWT], [newt], [newtBell], [newt.h])
+AST_EXT_LIB_CHECK([USB], [usb], [usb_init], [usb.h])
+
+PBX_HDLC=0
+AC_MSG_CHECKING([for GENERIC_HDLC_VERSION version 4 in linux/hdlc.h])
+AC_COMPILE_IFELSE(
+    [ AC_LANG_PROGRAM( [#include <linux/hdlc.h>],
+	    [#if defined(GENERIC_HDLC_VERSION) && GENERIC_HDLC_VERSION >= 4
+		int foo = 0;
+		#else
+		int foo = bar;
+		#endif
+		0])],
+	[AC_MSG_RESULT(yes)
+	 PBX_HDLC=1],
+	[AC_MSG_RESULT(no)]
+)
+if test $PBX_HDLC = 0; then
+    AC_MSG_CHECKING([for GENERIC_HDLC_VERSION version 4 in linux/hdlc/ioctl.h])
+    AC_COMPILE_IFELSE(
+	    [ AC_LANG_PROGRAM( [
+		    #include <sys/socket.h>
+			#include <linux/if.h>],
+			[#if defined(GENERIC_HDLC_VERSION) && GENERIC_HDLC_VERSION >= 4
+			int foo = 0;
+			#else
+			int foo = bar;
+			#endif
+			0])],
+		[AC_MSG_RESULT(yes)
+		 PBX_HDLC=1],
+		[AC_MSG_RESULT(no)]
+	)
+fi
+
+if test "x${PBX_HDLC}" != "x1"; then
+   AC_MSG_NOTICE([GENERIC_HDLC_VERSION (version 4) not found, disabling sethdlc.])
+fi
+
+AC_SUBST(PBX_HDLC)
+
+AC_ARG_WITH(selinux,
+	[AS_HELP_STRING([--with-selinux],
+			[enable (with) / disable (without) SELinux])],
+	[USE_SELINUX=$withval],
+	[ if test ! -x /usr/sbin/sestatus; then 
+	   	USE_SELINUX=no;
+	  elif /usr/sbin/sestatus | grep "SELinux status:" | grep -q "enabled"; then
+		USE_SELINUX=yes
+	  fi
+	]
+)
+
+
+AC_SUBST(USE_SELINUX)
+
+# for asciidoc before ver. 7, the backend must be stated explicitly:
+ASCIIDOC='asciidoc'
+asciidoc_ver=`asciidoc --version 2>&1 | awk '/^asciidoc /{print $2}' | cut -d. -f 1 | head -n 1`
+if test "$asciidoc_ver" != '' && test $asciidoc_ver -lt 7; then
+	ASCIIDOC="asciidoc -b xhtml"
+fi
+AC_SUBST(ASCIIDOC)
+
+AC_ARG_WITH(ppp,
+	    [AS_HELP_STRING([--with-ppp=PATH],[Use PPP support from PATH])],
+	    [],
+	    [with_ppp=check]
+	    )
+# somebody will fix that
+default_ppp_path=/usr
+
+case "$with_ppp" in
+	yes|check) ppp_path="$default_ppp_path";;
+	no) ppp_path='' ;;
+	*) ppp_path="$with_ppp" ;;
+esac
+
+level_file="$ppp_path/include/pppd/patchlevel.h"
+PPP_VERSION=
+if test "$ppp_path" != '' && test -r "$level_file"; then
+	PPPD_VERSION=`awk -F '"' '/VERSION/ { print $$2; }' $level_file`
+fi
+
+case "$with_ppp" in 
+	check|no) :;;
+	*) 
+	# If we asked explicitly for ppp support
+	if test "$PPPD_VERSION" = ''; then
+		# but have not detected it
+		AC_MSG_ERROR(failed to find pppd/patchlevel.h: no ppp support.)
+	fi
+	;;
+esac
+
+if test "x${PBX_DAHDI}" != "x1"; then
+   AC_MSG_NOTICE([***])
+   AC_MSG_NOTICE([*** Building this package requires DAHDI support. *** ])
+   AC_MSG_NOTICE([*** Please install the dahdi-linux package. ***])
+   AC_MSG_NOTICE([***])
+   exit 1
+fi
+
+if test "x${PBX_DAHDI23}" != "x1"; then
+   AC_MSG_NOTICE([***])
+   AC_MSG_NOTICE([*** Building this package requires DAHDI support (>= 2.3) *** ])
+   AC_MSG_NOTICE([*** Please install a recent dahdi-linux package. ***])
+   AC_MSG_NOTICE([***])
+   exit 1
+fi
+
+AC_SUBST(PPPD_VERSION)
+
+AC_CONFIG_FILES([build_tools/menuselect-deps makeopts])
+AC_OUTPUT
+
+AC_MSG_NOTICE(*** dahdi-tools build successfully configured ***)
diff --git a/dahdi.init b/dahdi.init
new file mode 100755
index 0000000..874fa46
--- /dev/null
+++ b/dahdi.init
@@ -0,0 +1,333 @@
+#!/bin/sh
+#
+# dahdi         This shell script takes care of loading and unloading \
+#               DAHDI Telephony interfaces
+# chkconfig: 2345 9 92
+# description: The DAHDI drivers allow you to use your linux \
+# computer to accept incoming data and voice interfaces
+#
+# config: /etc/dahdi/init.conf
+
+### BEGIN INIT INFO
+# Provides:        dahdi
+# Required-Start:  $local_fs $remote_fs
+# Required-Stop:   $local_fs $remote_fs
+# Should-Start:    $network $syslog
+# Should-Stop:     $network $syslog
+# Default-Start:   2 3 4 5
+# Default-Stop:    0 1 6
+# Description:     dahdi - load and configure DAHDI modules
+### END INIT INFO
+
+initdir=/etc/init.d
+
+# Don't edit the following values. Edit /etc/dahdi/init.conf instead.
+
+DAHDI_CFG=/usr/sbin/dahdi_cfg
+DAHDI_CFG_CMD=${DAHDI_CFG_CMD:-"$DAHDI_CFG"} # e.g: for a custom system.conf location
+
+FXOTUNE=/usr/sbin/fxotune
+
+# The default syncer Astribank. Usually set automatically to a sane
+# value by xpp_sync(1) if you have an Astribank. You can set this to an
+# explicit Astribank (e.g: 01).
+XPP_SYNC=auto
+
+# The maximal timeout (seconds) to wait for udevd to finish generating
+# device nodes after the modules have loaded and before running dahdi_cfg.
+DAHDI_DEV_TIMEOUT=20
+
+# A list of modules to unload when stopping.
+# All of their dependencies will be unloaded as well.
+DAHDI_UNLOAD_MODULES="dahdi"
+
+#
+# Determine which kind of configuration we're using
+#
+system=redhat  # assume redhat
+if [ -f /etc/debian_version ]; then
+    system=debian
+fi
+
+if [ -f /etc/gentoo-release ]; then
+    system=debian
+fi
+
+if [ -f /etc/SuSE-release -o -f /etc/novell-release ]
+then
+    system=debian
+fi
+
+# Source function library.
+if [ $system = redhat ]; then
+    . $initdir/functions || exit 0
+fi
+
+DAHDI_MODULES_FILE="/etc/dahdi/modules"
+
+[ -r /etc/dahdi/init.conf ] && . /etc/dahdi/init.conf
+
+if [ $system = redhat ]; then
+	LOCKFILE=/var/lock/subsys/dahdi
+fi
+
+# recursively unload a module and its dependencies, if possible.
+# where's modprobe -r when you need it?
+# inputs: module to unload.
+# returns: the result from
+unload_module() {
+	module="$1"
+	line=`lsmod 2>/dev/null | grep "^$1 "`
+	if [ "$line" = '' ]; then return; fi # module was not loaded
+
+	set -- $line
+	# $1: the original module, $2: size, $3: refcount, $4: deps list
+	mods=`echo $4 | tr , ' '`
+	ec_modules=""
+	# xpp_usb keeps the xpds below busy if an xpp hardware is
+	# connected. Hence must be removed before them:
+	case "$module" in xpd_*) mods="xpp_usb $mods";; esac
+
+	for mod in $mods; do
+		case "$mod" in
+		dahdi_echocan_*)
+			ec_modules="$mod $ec_modules"
+			;;
+		*)
+			# run in a subshell, so it won't step over our vars:
+			(unload_module $mod)
+			;;
+		esac
+	done
+	# Now that all the other dependencies are unloaded, we can unload the
+	# dahdi_echocan modules.  The drivers that register spans may keep
+	# references on the echocan modules before they are unloaded.
+	for mod in $ec_modules; do
+		(unload_module $mod)
+	done
+	rmmod $module
+}
+
+unload_modules() {
+	for module in $DAHDI_UNLOAD_MODULES; do
+		unload_module $module
+	done
+}
+
+# In (xpp) hotplug mode, the init script is also executed from the
+# hotplug hook. In that case it should not attempt to loade modules.
+#
+# This function only retunrs false (1) if we're in hotplug mode and
+# coming from the hotplug hook script.
+hotplug_should_load_modules() {
+	if [ "$XPP_HOTPLUG_DAHDI" = yes -a "$CALLED_FROM_ATRIBANK_HOOK" != '' ]
+	then
+		return 1
+	fi
+	return 0
+}
+
+# In (xpp) hotplug mode: quit after we loaded modules.
+#
+# In hotplug mode, the main run should end here, whereas the rest of the
+# script should be finished by the instance running from the hook.
+# Note that we only get here if there are actually Astribanks on the
+# system (otherwise noone will trigger the run of the hotplug hook
+# script).
+hotplug_exit_after_load() {
+	if [ "$XPP_HOTPLUG_DAHDI" = yes -a "$CALLED_FROM_ATRIBANK_HOOK" = '' ]
+	then
+		exit 0
+	fi
+}
+
+# Initialize the Xorcom Astribank (xpp/) using perl utiliites:
+xpp_startup() {
+	# do nothing if there are no astribank devices:
+	if ! /usr/share/dahdi/waitfor_xpds; then return 0; fi
+
+	hotplug_exit_after_load
+
+	# overriding locales for the above two, as perl can be noisy
+	# when locales are missing.
+	# No register all the devices if they didn't auto-register:
+	LC_ALL=C dahdi_registration on
+}
+
+
+hpec_start() {
+	# HPEC license found
+	if ! echo /var/lib/digium/licenses/HPEC-*.lic | grep -v '\*' | grep -q .; then
+		return
+	fi
+
+	# dahdihpec_enable not installed in /usr/sbin
+	if [ ! -f /usr/sbin/dahdihpec_enable ]; then
+		echo -n "Running dahdihpec_enable: Failed"
+		echo -n "."
+		echo "  The dahdihpec_enable binary is not installed in /usr/sbin."
+		return
+	fi
+
+	# dahdihpec_enable not set executable
+	if [ ! -x /usr/sbin/dahdihpec_enable ]; then
+		echo -n "Running dahdihpec_enable: Failed"
+		echo -n "."
+		echo "  /usr/sbin/dahdihpec_enable is not set as executable."
+		return
+	fi
+
+	# dahdihpec_enable properly installed
+	if [ $system = debian ]; then
+		echo -n "Running dahdihpec_enable: "
+		/usr/sbin/dahdihpec_enable 2> /dev/null
+	elif [ $system = redhat ]; then
+		action "Running dahdihpec_enable: " /usr/sbin/dahdihpec_enable
+	fi
+	if [ $? = 0 ]; then
+		echo -n "done"
+		echo "."
+	else
+		echo -n "Failed"
+		echo -n "."
+		echo "  This can be caused if you had already run dahdihpec_enable, or if your HPEC license is no longer valid."
+	fi
+}
+
+shutdown_dynamic() {
+	if ! grep -q ' DYN/' /proc/dahdi/* 2>/dev/null; then return; fi
+
+	# we should only get here if we have dynamic spans. Right?
+	$DAHDI_CFG_CMD -s
+}
+
+load_modules() {
+  	# Some systems, e.g. Debian Lenny, add here -b, which will break
+	# loading of modules blacklisted in modprobe.d/*
+	unset MODPROBE_OPTIONS
+  	modules=`sed -e 's/#.*$//' $DAHDI_MODULES_FILE 2>/dev/null`
+	#if [ "$modules" = '' ]; then
+		# what?
+	#fi
+	echo "Loading DAHDI hardware modules:"
+	modprobe dahdi
+	for line in $modules; do
+		if [ $system = debian ]; then
+			echo -n "   ${line}: "
+			if modprobe $line 2> /dev/null; then
+				echo -n "done"
+			else
+				echo -n "error"
+			fi
+		elif [ $system = redhat ]; then
+			action "  ${line}: " modprobe $line
+		fi
+	done
+	echo ""
+}
+
+if [ ! -x "$DAHDI_CFG" ]; then
+       echo "dahdi_cfg not executable"
+       exit 0
+fi
+
+if [ ! -f /etc/dahdi/system.conf ]; then
+	echo "/etc/dahdi/system.conf not found. Nothing to do."
+       exit 0
+fi
+
+RETVAL=0
+
+# See how we were called.
+case "$1" in
+  start)
+  	if hotplug_should_load_modules; then
+		load_modules
+	fi
+
+	TMOUT=$DAHDI_DEV_TIMEOUT # max secs to wait
+
+	while [ ! -d /dev/dahdi ] ; do
+ 		sleep 1
+		TMOUT=`expr $TMOUT - 1`
+		if [ $TMOUT -eq 0 ] ; then
+			echo "Error: missing /dev/dahdi!"
+			exit 1
+		fi
+	done
+
+	xpp_startup
+
+	if [ ! -e /proc/dahdi/1 ]; then
+		echo "No hardware timing source found in /proc/dahdi, loading dahdi_dummy"
+		modprobe dahdi_dummy 2> /dev/null
+	fi
+
+	if [ $system = debian ]; then
+	    echo -n "Running dahdi_cfg: "
+	    $DAHDI_CFG_CMD 2> /dev/null && echo -n "done"
+	    echo "."
+	elif [ $system = redhat ]; then
+	    action "Running dahdi_cfg: " $DAHDI_CFG_CMD
+	fi
+	RETVAL=$?
+
+	if [ "$LOCKFILE" != '' ]; then
+		[ $RETVAL -eq 0 ] && touch $LOCKFILE
+	fi
+
+	if [ -x "$FXOTUNE" ] && [ -r /etc/fxotune.conf ]; then
+		# Allowed to fail if e.g. Asterisk already uses channels:
+		$FXOTUNE -s || :
+	fi
+
+	# Set the right Astribanks ticker:
+	LC_ALL=C xpp_sync "$XPP_SYNC"
+
+	hpec_start
+	;;
+  stop)
+	# Unload drivers
+	#shutdown_dynamic # FIXME: needs test from someone with dynamic spans
+	echo -n "Unloading DAHDI hardware modules: "
+	if unload_modules; then
+		echo "done"
+	else
+		echo "error"
+	fi
+	if [ "$LOCKFILE" != '' ]; then
+		[ $RETVAL -eq 0 ] && rm -f $LOCKFILE
+	fi
+	;;
+  unload)
+	unload_modules
+	;;
+  restart|force-reload)
+	$0 stop
+	$0 start
+	;;
+  reload)
+	if [ $system = debian ]; then
+	    echo -n "Rerunning dahdi_cfg: "
+	    $DAHDI_CFG_CMD 2> /dev/null && echo -n "done"
+	    echo "."
+	elif [ $system = redhat ]; then
+	    action "Rerunning dahdi_cfg: " $DAHDI_CFG_CMD
+	fi
+	RETVAL=$?
+	;;
+  status)
+	if [ -d /proc/dahdi ]; then
+		/usr/sbin/lsdahdi
+		RETVAL=0
+	else
+		RETVAL=3
+	fi
+	;;
+  *)
+	echo "Usage: dahdi {start|stop|restart|status|reload|unload}"
+	exit 1
+esac
+
+exit $RETVAL
+
diff --git a/dahdi.xml b/dahdi.xml
new file mode 100644
index 0000000..f071f5d
--- /dev/null
+++ b/dahdi.xml
@@ -0,0 +1,26 @@
+<category name="MENUSELECT_UTILS" displayname="Utilities">
+	<member name="fxotune" remove_on_change="fxotune fxotune.o">
+	</member>
+	<member name="fxstest" remove_on_change="fxstest fxstest.o">
+		<defaultenabled>no</defaultenabled>
+	</member>
+	<member name="sethdlc" remove_on_change="sethdlc sethdlc.o">
+		<depend>hdlc</depend>
+	</member>
+	<member name="dahdi_cfg" remove_on_change="dahdi_cfg dahdi_cfg.o">
+	</member>
+	<member name="dahdi_diag" remove_on_change="dahdi_diag dahdi_diag.o">
+		<defaultenabled>no</defaultenabled>
+	</member>
+	<member name="dahdi_monitor" remove_on_change="dahdi_monitor dahdi_monitor.o">
+	</member>
+	<member name="dahdi_scan" remove_on_change="dahdi_scan dahdi_scan.o">
+	</member>
+	<member name="dahdi_speed" remove_on_change="dahdi_speed dahdi_speed.o">
+	</member>
+	<member name="dahdi_test" remove_on_change="dahdi_test dahdi_test.o">
+	</member>
+	<member name="dahdi_tool" remove_on_change="dahdi_tool dahdi_tool.o">
+		<depend>libnewt</depend>
+	</member>
+</category>
diff --git a/dahdi_cfg.c b/dahdi_cfg.c
new file mode 100644
index 0000000..9386e00
--- /dev/null
+++ b/dahdi_cfg.c
@@ -0,0 +1,1662 @@
+/*
+ * Configuration program for DAHDI Telephony Interface
+ *
+ * Written by Mark Spencer <markster at digium.com>
+ * Based on previous works, designs, and architectures conceived and
+ * written by Jim Dixon <jim at lambdatel.com>.
+ *
+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
+ * Copyright (C) 2001-2008 Digium, Inc.
+ *
+ * All rights reserved.
+ *
+ * Primary Author: Mark Spencer <markster at digium.com>
+ * Radio Support by Jim Dixon <jim at lambdatel.com>
+ */
+
+/*
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2 as published by the
+ * Free Software Foundation. See the LICENSE file included with
+ * this program for more details.
+ */
+
+#include <stdio.h> 
+#include <getopt.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <dahdi/user.h>
+#include "tonezone.h"
+#include "dahdi_tools_version.h"
+
+#define CONFIG_FILENAME "/etc/dahdi/system.conf"
+#define MASTER_DEVICE   "/dev/dahdi/ctl"
+
+#define NUM_SPANS DAHDI_MAX_SPANS
+
+#define NUM_TONES 15
+
+/*! A sanity check for the timing parameter of the span. 
+ *
+ * Note that each driver using it is still responsible for validating
+ * that value.
+ */
+#define MAX_TIMING 255 
+
+/* Assume no more than 1024 dynamics */
+#define NUM_DYNAMIC	1024
+
+static int lineno=0;
+
+static FILE *cf;
+
+static char *filename=CONFIG_FILENAME;
+
+int rxtones[NUM_TONES + 1],rxtags[NUM_TONES + 1],txtones[NUM_TONES + 1];
+int bursttime = 0, debouncetime = 0, invertcor = 0, exttone = 0, corthresh = 0;
+int txgain = 0, rxgain = 0, deemp = 0, preemp = 0;
+
+int corthreshes[] = {3125,6250,9375,12500,15625,18750,21875,25000,0} ;
+
+static int toneindex = 1;
+
+#define DEBUG_READER (1 << 0)
+#define DEBUG_PARSER (1 << 1)
+#define DEBUG_APPLY  (1 << 2)
+static int debug = 0;
+
+static int errcnt = 0;
+
+static int deftonezone = -1;
+
+static struct dahdi_lineconfig lc[DAHDI_MAX_SPANS];
+
+static struct dahdi_chanconfig cc[DAHDI_MAX_CHANNELS];
+
+static struct dahdi_attach_echocan ae[DAHDI_MAX_CHANNELS];
+
+static struct dahdi_dynamic_span zds[NUM_DYNAMIC];
+
+static const char *sig[DAHDI_MAX_CHANNELS];		/* Signalling */
+
+static int slineno[DAHDI_MAX_CHANNELS];	/* Line number where signalling specified */
+
+static int fiftysixkhdlc[DAHDI_MAX_CHANNELS];
+
+static int spans=0;
+
+static int fo_real = 1;
+
+static int verbose = 0;
+
+static int force = 0;
+
+static int stopmode = 0;
+
+static int numdynamic = 0;
+
+static char zonestoload[DAHDI_TONE_ZONE_MAX][10];
+
+static int numzones = 0;
+
+static int fd = -1;
+
+static const char *lbostr[] = {
+"0 db (CSU)/0-133 feet (DSX-1)",
+"133-266 feet (DSX-1)",
+"266-399 feet (DSX-1)",
+"399-533 feet (DSX-1)",
+"533-655 feet (DSX-1)",
+"-7.5db (CSU)",
+"-15db (CSU)",
+"-22.5db (CSU)"
+};
+
+static const char *laws[] = {
+	"Default",
+	"Mu-law",
+	"A-law"
+};
+
+static const char *sigtype_to_str(const int sig)
+{
+	switch (sig) {
+	case 0:
+		return "Unused";
+	case DAHDI_SIG_EM:
+		return "E & M";
+	case DAHDI_SIG_EM_E1:
+		return "E & M E1";
+	case DAHDI_SIG_FXSLS:
+		return "FXS Loopstart";
+	case DAHDI_SIG_FXSGS:
+		return "FXS Groundstart";
+	case DAHDI_SIG_FXSKS:
+		return "FXS Kewlstart";
+	case DAHDI_SIG_FXOLS:
+		return "FXO Loopstart";
+	case DAHDI_SIG_FXOGS:
+		return "FXO Groundstart";
+	case DAHDI_SIG_FXOKS:
+		return "FXO Kewlstart";
+	case DAHDI_SIG_CAS:
+		return "CAS / User";
+	case DAHDI_SIG_DACS:
+		return "DACS";
+	case DAHDI_SIG_DACS_RBS:
+		return "DACS w/RBS";
+	case DAHDI_SIG_CLEAR:
+		return "Clear channel";
+	case DAHDI_SIG_SLAVE:
+		return "Slave channel";
+	case DAHDI_SIG_HDLCRAW:
+		return "Raw HDLC";
+	case DAHDI_SIG_HDLCNET:
+		return "Network HDLC";
+	case DAHDI_SIG_HDLCFCS:
+		return "HDLC with FCS check";
+	case DAHDI_SIG_HARDHDLC:
+		return "Hardware assisted D-channel";
+	case DAHDI_SIG_MTP2:
+		return "MTP2";
+	default:
+		return "Unknown";
+	}
+}
+
+int ind_ioctl(int channo, int fd, int op, void *data)
+{
+	struct dahdi_indirect_data ind;
+
+	ind.chan = channo;
+	ind.op = op;
+	ind.data = data;
+	return ioctl(fd, DAHDI_INDIRECT, &ind);
+}
+
+static void clear_fields()
+{
+
+	memset(rxtones,0,sizeof(rxtones));
+	memset(rxtags,0,sizeof(rxtags));
+	memset(txtones,0,sizeof(txtones));
+	bursttime = 0;
+	debouncetime = 0;
+	invertcor = 0;
+	exttone = 0;
+	txgain = 0;
+	rxgain = 0;
+	deemp = 0;
+	preemp = 0;
+}
+
+static int error(char *fmt, ...) __attribute__ ((format(printf, 1, 2)));
+
+static int error(char *fmt, ...)
+{
+	int res;
+	static int shown=0;
+	va_list ap;
+	if (!shown) {
+		fprintf(stderr, "Notice: Configuration file is %s\n", filename);
+		shown++;
+	}
+	res = fprintf(stderr, "line %d: ", lineno);
+	va_start(ap, fmt);
+	vfprintf(stderr, fmt, ap);
+	va_end(ap);
+	errcnt++;
+	return res;
+}
+
+static char *trim(char *buf)
+{
+	size_t len;
+
+	while (*buf && (*buf < 33)) {
+		buf++;
+	}
+
+	len = strlen(buf);
+
+	while (len && buf[len-1] < 33) {
+		buf[--len] = '\0';
+	}
+
+	return buf;
+}
+
+static int parseargs(char *input, char *output[], int maxargs, char sep)
+{
+	char *c;
+	int pos=0;
+	c = input;
+	output[pos++] = c;
+	while(*c) {
+		while(*c && (*c != sep)) c++;
+		if (*c) {
+			*c = '\0';
+			c++;
+			while(*c && (*c < 33)) c++;
+			if (*c)  {
+				if (pos >= maxargs)
+					return -1;
+				output[pos] = c;
+				trim(output[pos]);
+				pos++;
+				output[pos] = NULL;
+				/* Return error if we have too many */
+			} else
+				return pos;
+		}
+	}
+	return pos;
+}
+
+int dspanconfig(char *keyword, char *args)
+{
+	static char *realargs[10];
+	int argc;
+	int res;
+	int chans;
+	int timing;
+	argc = res = parseargs(args, realargs, 4, ',');
+	if (res != 4) {
+		error("Incorrect number of arguments to 'dynamic' (should be <driver>,<address>,<num channels>, <timing>)\n");
+		return -1;
+	}
+	res = sscanf(realargs[2], "%d", &chans);
+	if ((res == 1) && (chans < 1))
+		res = -1;
+	if (res != 1) {
+		error("Invalid number of channels '%s', should be a number > 0.\n", realargs[2]);
+		return -1;
+	}
+
+	res = sscanf(realargs[3], "%d", &timing);
+	if ((res == 1) && (timing < 0))
+		res = -1;
+	if (res != 1) {
+		error("Invalid timing '%s', should be a number > 0.\n", realargs[3]);
+		return -1;
+	}
+
+
+	dahdi_copy_string(zds[numdynamic].driver, realargs[0], sizeof(zds[numdynamic].driver));
+	dahdi_copy_string(zds[numdynamic].addr, realargs[1], sizeof(zds[numdynamic].addr));
+	zds[numdynamic].numchans = chans;
+	zds[numdynamic].timing = timing;
+	
+	numdynamic++;
+	return 0;
+}
+
+int spanconfig(char *keyword, char *args)
+{
+	static char *realargs[10];
+	int res;
+	int argc;
+	int span;
+	int timing;
+	int i;
+	argc = res = parseargs(args, realargs, 9, ',');
+	if ((res < 5) || (res > 9)) {
+		error("Incorrect number of arguments to 'span' (should be <spanno>,<timing>,<lbo>,<framing>,<coding>[, crc4 | yellow [, yellow]])\n");
+		return -1;
+	}
+	res = sscanf(realargs[0], "%d", &span);
+	if (res != 1) {
+		error("Span number should be a valid span number, not '%s'\n", realargs[0]);
+		return -1;
+	}
+	res = sscanf(realargs[1], "%d", &timing);
+	if ((res != 1) || (timing < 0) || (timing > MAX_TIMING)) {
+		error("Timing should be a number from 0 to %d, not '%s'\n", 
+				MAX_TIMING,  realargs[1]);
+		return -1;
+	}
+	res = sscanf(realargs[2], "%d", &lc[spans].lbo);
+	if (res != 1) {
+		error("Line build-out (LBO) should be a number from 0 to 7 (usually 0) not '%s'\n", realargs[2]);
+		return -1;
+	}
+	if ((lc[spans].lbo < 0) || (lc[spans].lbo > 7)) {
+		error("Line build-out should be in the range 0 to 7, not %d\n", lc[spans].lbo);
+		return -1;
+	}
+	if (!strcasecmp(realargs[3], "d4")) {
+		lc[spans].lineconfig |= DAHDI_CONFIG_D4;
+		lc[spans].lineconfig &= ~DAHDI_CONFIG_ESF;
+		lc[spans].lineconfig &= ~DAHDI_CONFIG_CCS;
+	} else if (!strcasecmp(realargs[3], "esf")) {
+		lc[spans].lineconfig |= DAHDI_CONFIG_ESF;
+		lc[spans].lineconfig &= ~DAHDI_CONFIG_D4;
+		lc[spans].lineconfig &= ~DAHDI_CONFIG_CCS;
+	} else if (!strcasecmp(realargs[3], "ccs")) {
+		lc[spans].lineconfig |= DAHDI_CONFIG_CCS;
+		lc[spans].lineconfig &= ~(DAHDI_CONFIG_ESF | DAHDI_CONFIG_D4);
+	} else if (!strcasecmp(realargs[3], "cas")) {
+		lc[spans].lineconfig &= ~DAHDI_CONFIG_CCS;
+		lc[spans].lineconfig &= ~(DAHDI_CONFIG_ESF | DAHDI_CONFIG_D4);
+	} else {
+		error("Framing(T1)/Signalling(E1) must be one of 'd4', 'esf', 'cas' or 'ccs', not '%s'\n", realargs[3]);
+		return -1;
+	}
+	if (!strcasecmp(realargs[4], "ami")) {
+		lc[spans].lineconfig &= ~(DAHDI_CONFIG_B8ZS | DAHDI_CONFIG_HDB3);
+		lc[spans].lineconfig |= DAHDI_CONFIG_AMI;
+	} else if (!strcasecmp(realargs[4], "b8zs")) {
+		lc[spans].lineconfig |= DAHDI_CONFIG_B8ZS;
+		lc[spans].lineconfig &= ~(DAHDI_CONFIG_AMI | DAHDI_CONFIG_HDB3);
+	} else if (!strcasecmp(realargs[4], "hdb3")) {
+		lc[spans].lineconfig |= DAHDI_CONFIG_HDB3;
+		lc[spans].lineconfig &= ~(DAHDI_CONFIG_AMI | DAHDI_CONFIG_B8ZS);
+	} else {
+		error("Coding must be one of 'ami', 'b8zs' or 'hdb3', not '%s'\n", realargs[4]);
+		return -1;
+	}
+	for (i = 5; i < argc; i++) {
+		if (!strcasecmp(realargs[i], "yellow"))
+			lc[spans].lineconfig |= DAHDI_CONFIG_NOTOPEN;
+		else if (!strcasecmp(realargs[i], "crc4"))
+			lc[spans].lineconfig |= DAHDI_CONFIG_CRC4;
+		else if (!strcasecmp(realargs[i], "nt"))
+			lc[spans].lineconfig |= DAHDI_CONFIG_NTTE;
+		else if (!strcasecmp(realargs[i], "te"))
+			lc[spans].lineconfig &= ~DAHDI_CONFIG_NTTE;
+		else if (!strcasecmp(realargs[i], "term"))
+			lc[spans].lineconfig |= DAHDI_CONFIG_TERM;
+		else {
+			error("Remaining arguments may be any of: 'yellow', 'crc4', 'nt', 'te', 'term', not '%s'\n", realargs[i]);
+			return -1;
+		}
+
+	}
+	lc[spans].span = span;
+	lc[spans].sync = timing;
+	/* Valid span */
+	spans++;
+	return 0;
+}
+
+int apply_channels(int chans[], char *argstr)
+{
+	char *args[DAHDI_MAX_CHANNELS+1];
+	char *range[3];
+	int res,x, res2,y;
+	int chan;
+	int start, finish;
+	char argcopy[256];
+	res = parseargs(argstr, args, DAHDI_MAX_CHANNELS, ',');
+	if (res < 0) {
+		error("Too many arguments...  Max is %d\n", DAHDI_MAX_CHANNELS);
+		return -1;
+	}
+	for (x=0;x<res;x++) {
+		if (strchr(args[x], '-')) {
+			/* It's a range */
+			dahdi_copy_string(argcopy, args[x], sizeof(argcopy));
+			res2 = parseargs(argcopy, range, 2, '-');
+			if (res2 != 2) {
+				error("Syntax error in range '%s'.  Should be <val1>-<val2>.\n", args[x]);
+				return -1;
+			}
+			res2 =sscanf(range[0], "%d", &start);
+			if (res2 != 1) {
+				error("Syntax error.  Start of range '%s' should be a number from 1 to %d\n", args[x], DAHDI_MAX_CHANNELS - 1);
+				return -1;
+			} else if ((start < 1) || (start >= DAHDI_MAX_CHANNELS)) {
+				error("Start of range '%s' must be between 1 and %d (not '%d')\n", args[x], DAHDI_MAX_CHANNELS - 1, start);
+				return -1;
+			}
+			res2 =sscanf(range[1], "%d", &finish);
+			if (res2 != 1) {
+				error("Syntax error.  End of range '%s' should be a number from 1 to %d\n", args[x], DAHDI_MAX_CHANNELS - 1);
+				return -1;
+			} else if ((finish < 1) || (finish >= DAHDI_MAX_CHANNELS)) {
+				error("end of range '%s' must be between 1 and %d (not '%d')\n", args[x], DAHDI_MAX_CHANNELS - 1, finish);
+				return -1;
+			}
+			if (start > finish) {
+				error("Range '%s' should start before it ends\n", args[x]);
+				return -1;
+			}
+			for (y=start;y<=finish;y++)
+				chans[y]=1;
+		} else {
+			/* It's a single channel */
+			res2 =sscanf(args[x], "%d", &chan);
+			if (res2 != 1) {
+				error("Syntax error.  Channel should be a number from 1 to %d, not '%s'\n", DAHDI_MAX_CHANNELS - 1, args[x]);
+				return -1;
+			} else if ((chan < 1) || (chan >= DAHDI_MAX_CHANNELS)) {
+				error("Channel must be between 1 and %d (not '%d')\n", DAHDI_MAX_CHANNELS - 1, chan);
+				return -1;
+			}
+			chans[chan]=1;
+		}		
+	}
+	return res;
+}
+
+int parse_idle(int *i, char *s)
+{
+	char a,b,c,d;
+	if (s) {
+		if (sscanf(s, "%c%c%c%c", &a,&b,&c,&d) == 4) {
+			if (((a == '0') || (a == '1')) && ((b == '0') || (b == '1')) && ((c == '0') || (c == '1')) && ((d == '0') || (d == '1'))) {
+				*i = 0;
+				if (a == '1') 
+					*i |= DAHDI_ABIT;
+				if (b == '1')
+					*i |= DAHDI_BBIT;
+				if (c == '1')
+					*i |= DAHDI_CBIT;
+				if (d == '1')
+					*i |= DAHDI_DBIT;
+				return 0;
+			}
+		}
+	}
+	error("CAS Signalling requires idle definition in the form ':xxxx' at the end of the channel definition, where xxxx represent the a, b, c, and d bits\n");
+	return -1;
+}
+
+static int parse_channel(char *channel, int *startchan)
+{
+	if (!channel || (sscanf(channel, "%d", startchan) != 1) || 
+		(*startchan < 1)) {
+		error("DACS requires a starting channel in the form ':x' where x is the channel\n");
+		return -1;
+	}
+	return 0;
+}
+
+static int chanconfig(char *keyword, char *args)
+{
+	int chans[DAHDI_MAX_CHANNELS];
+	int res = 0;
+	int x;
+	int master=0;
+	int dacschan = 0;
+	char *idle;
+	bzero(chans, sizeof(chans));
+	strtok(args, ":");
+	idle = strtok(NULL, ":");
+	if (!strcasecmp(keyword, "dacs") || !strcasecmp(keyword, "dacsrbs")) {
+		res = parse_channel(idle, &dacschan);
+	}
+	if (!res)
+		res = apply_channels(chans, args);
+	if (res <= 0)
+		return -1;
+	for (x=1;x<DAHDI_MAX_CHANNELS;x++) {
+		if (chans[x]) {
+			if (slineno[x]) {
+				error("Channel %d already configured as '%s' at line %d\n", x, sig[x], slineno[x]);
+				continue;
+			}
+			if ((!strcasecmp(keyword, "dacs") || !strcasecmp(keyword, "dacsrbs")) && slineno[dacschan]) {
+				error("DACS Destination channel %d already configured as '%s' at line %d\n", dacschan, sig[dacschan], slineno[dacschan]);
+				continue;
+			} else {
+				cc[dacschan].chan = dacschan;
+				cc[dacschan].master = dacschan;
+				slineno[dacschan] = lineno;
+			}
+			cc[x].chan = x;
+			cc[x].master = x;
+			slineno[x] = lineno;
+			if (!strcasecmp(keyword, "e&m")) {
+				cc[x].sigtype = DAHDI_SIG_EM;
+				sig[x] = sigtype_to_str(cc[x].sigtype);
+			} else if (!strcasecmp(keyword, "e&me1")) {
+				cc[x].sigtype = DAHDI_SIG_EM_E1;
+				sig[x] = sigtype_to_str(cc[x].sigtype);
+			} else if (!strcasecmp(keyword, "fxsls")) {
+				cc[x].sigtype = DAHDI_SIG_FXSLS;
+				sig[x] = sigtype_to_str(cc[x].sigtype);
+			} else if (!strcasecmp(keyword, "fxsgs")) {
+				cc[x].sigtype = DAHDI_SIG_FXSGS;
+				sig[x] = sigtype_to_str(cc[x].sigtype);
+			} else if (!strcasecmp(keyword, "fxsks")) {
+				cc[x].sigtype = DAHDI_SIG_FXSKS;
+				sig[x] = sigtype_to_str(cc[x].sigtype);
+			} else if (!strcasecmp(keyword, "fxols")) {
+				cc[x].sigtype = DAHDI_SIG_FXOLS;
+				sig[x] = sigtype_to_str(cc[x].sigtype);
+			} else if (!strcasecmp(keyword, "fxogs")) {
+				cc[x].sigtype = DAHDI_SIG_FXOGS;
+				sig[x] = sigtype_to_str(cc[x].sigtype);
+			} else if (!strcasecmp(keyword, "fxoks")) {
+				cc[x].sigtype = DAHDI_SIG_FXOKS;
+				sig[x] = sigtype_to_str(cc[x].sigtype);
+			} else if (!strcasecmp(keyword, "cas") || !strcasecmp(keyword, "user")) {
+				if (parse_idle(&cc[x].idlebits, idle))
+					return -1;
+				cc[x].sigtype = DAHDI_SIG_CAS;
+				sig[x] = sigtype_to_str(cc[x].sigtype);
+			} else if (!strcasecmp(keyword, "dacs")) {
+				/* Setup channel for monitor */
+				cc[x].idlebits = dacschan;
+				cc[x].sigtype = DAHDI_SIG_DACS;
+				sig[x] = sigtype_to_str(cc[x].sigtype);
+				/* Setup inverse */
+				cc[dacschan].idlebits = x;
+				cc[dacschan].sigtype = DAHDI_SIG_DACS;
+				sig[x] = sigtype_to_str(cc[dacschan].sigtype);
+				dacschan++;
+			} else if (!strcasecmp(keyword, "dacsrbs")) {
+				/* Setup channel for monitor */
+				cc[x].idlebits = dacschan;
+				cc[x].sigtype = DAHDI_SIG_DACS_RBS;
+				sig[x] = sigtype_to_str(cc[x].sigtype);
+				/* Setup inverse */
+				cc[dacschan].idlebits = x;
+				cc[dacschan].sigtype = DAHDI_SIG_DACS_RBS;
+				sig[x] = sigtype_to_str(cc[dacschan].sigtype);
+				dacschan++;
+			} else if (!strcasecmp(keyword, "unused")) {
+				cc[x].sigtype = 0;
+				sig[x] = sigtype_to_str(cc[x].sigtype);
+			} else if (!strcasecmp(keyword, "indclear") || !strcasecmp(keyword, "bchan")) {
+				cc[x].sigtype = DAHDI_SIG_CLEAR;
+				sig[x] = sigtype_to_str(cc[x].sigtype);
+			} else if (!strcasecmp(keyword, "clear")) {
+				sig[x] = sigtype_to_str(DAHDI_SIG_CLEAR);
+				if (master) {
+					cc[x].sigtype = DAHDI_SIG_SLAVE;
+					cc[x].master = master;
+				} else {
+					cc[x].sigtype = DAHDI_SIG_CLEAR;
+					master = x;
+				}
+			} else if (!strcasecmp(keyword, "rawhdlc")) {
+				sig[x] = sigtype_to_str(DAHDI_SIG_HDLCRAW);
+				if (master) {
+					cc[x].sigtype = DAHDI_SIG_SLAVE;
+					cc[x].master = master;
+				} else {
+					cc[x].sigtype = DAHDI_SIG_HDLCRAW;
+					master = x;
+				}
+			} else if (!strcasecmp(keyword, "nethdlc")) {
+				sig[x] = sigtype_to_str(DAHDI_SIG_HDLCNET);
+				memset(cc[x].netdev_name, 0, sizeof(cc[x].netdev_name));
+				if (master) {
+					cc[x].sigtype = DAHDI_SIG_SLAVE;
+					cc[x].master = master;
+				} else {
+					cc[x].sigtype = DAHDI_SIG_HDLCNET;
+					if (idle) {
+					    dahdi_copy_string(cc[x].netdev_name, idle, sizeof(cc[x].netdev_name));
+					}
+					master = x;
+				}
+			} else if (!strcasecmp(keyword, "fcshdlc")) {
+				sig[x] = sigtype_to_str(DAHDI_SIG_HDLCFCS);
+				if (master) {
+					cc[x].sigtype = DAHDI_SIG_SLAVE;
+					cc[x].master = master;
+				} else {
+					cc[x].sigtype = DAHDI_SIG_HDLCFCS;
+					master = x;
+				}
+			} else if (!strcasecmp(keyword, "dchan")) {
+				sig[x] = "D-channel";
+				cc[x].sigtype = DAHDI_SIG_HDLCFCS;
+			} else if (!strcasecmp(keyword, "hardhdlc")) {
+				sig[x] = "Hardware assisted D-channel";
+				cc[x].sigtype = DAHDI_SIG_HARDHDLC;
+			} else if (!strcasecmp(keyword, "mtp2")) {
+				sig[x] = "MTP2";
+				cc[x].sigtype = DAHDI_SIG_MTP2;
+			} else {
+				fprintf(stderr, "Huh? (%s)\n", keyword);
+			}
+		}
+	}
+	return 0;
+}
+
+static int setlaw(char *keyword, char *args)
+{
+	int res;
+	int law;
+	int x;
+	int chans[DAHDI_MAX_CHANNELS];
+
+	bzero(chans, sizeof(chans));
+	res = apply_channels(chans, args);
+	if (res <= 0)
+		return -1;
+	if (!strcasecmp(keyword, "alaw")) {
+		law = DAHDI_LAW_ALAW;
+	} else if (!strcasecmp(keyword, "mulaw")) {
+		law = DAHDI_LAW_MULAW;
+	} else if (!strcasecmp(keyword, "deflaw")) {
+		law = DAHDI_LAW_DEFAULT;
+	} else {
+		fprintf(stderr, "Huh??? Don't know about '%s' law\n", keyword);
+		return -1;
+	}
+	for (x=0;x<DAHDI_MAX_CHANNELS;x++) {
+		if (chans[x])
+			cc[x].deflaw = law;
+	}
+	return 0;
+}
+
+static int setfiftysixkhdlc(char *keyword, char *args)
+{
+	int res;
+
+	res = apply_channels(fiftysixkhdlc, args);
+	if (res <= 0)
+		return -1;
+
+	return 0;
+}
+
+static void apply_fiftysix(void)
+{
+	int x;
+	int rate;
+	int chanfd;
+
+	for (x = 1; x < DAHDI_MAX_CHANNELS; x++) {
+		chanfd = open("/dev/dahdi/channel", O_RDWR);
+		if (chanfd == -1) {
+			fprintf(stderr, 
+			    "Couldn't open /dev/dahdi/channel: %s\n", 
+			    strerror(errno));
+			exit(-1);
+		}
+
+		if (ioctl(chanfd, DAHDI_SPECIFY, &x)) {
+			close(chanfd);
+			continue;
+		}
+
+		if (fiftysixkhdlc[x]) {
+			printf("Setting channel %d to 56K mode (only valid on HDLC channels)\n", x);
+			rate = 56;
+		} else {
+			rate = 64;
+		}
+
+		if (ioctl(chanfd, DAHDI_HDLC_RATE, &rate)) {
+			fprintf(stderr, "Error setting HDLC rate\n");
+			exit(-1);
+		}
+		close(chanfd);
+	}
+}
+
+static int setechocan(char *keyword, char *args)
+{
+	int res;
+	int chans[DAHDI_MAX_CHANNELS] = { 0, };
+	char *echocan, *chanlist;
+	unsigned int x;
+
+	echocan = strtok(args, ",");
+
+	while ((chanlist = strtok(NULL, ","))) {
+		res = apply_channels(chans, chanlist);
+		if (res <= 0) {
+			return -1;
+		}
+	}
+
+	for (x = 0; x < DAHDI_MAX_CHANNELS; x++) {
+		if (chans[x]) {
+			dahdi_copy_string(ae[x].echocan, echocan, sizeof(ae[x].echocan));
+		}
+	}
+
+	return 0;
+}
+
+static int registerzone(char *keyword, char *args)
+{
+	if (numzones >= DAHDI_TONE_ZONE_MAX) {
+		error("Too many tone zones specified\n");
+		return 0;
+	}
+	dahdi_copy_string(zonestoload[numzones++], args, sizeof(zonestoload[0]));
+	return 0;
+}
+
+static int defaultzone(char *keyword, char *args)
+{
+	struct tone_zone *z;
+	if (!(z = tone_zone_find(args))) {
+		error("No such tone zone known: %s\n", args);
+		return 0;
+	}
+	deftonezone = z->zone;
+	return 0;
+}
+
+#if 0
+static int unimplemented(char *keyword, char *args)
+{
+	fprintf(stderr, "Warning: '%s' is not yet implemented\n", keyword);
+	return 0;
+}
+#endif
+
+
+/* Radio functions */
+
+int ctcss(char *keyword, char *args)
+{
+	static char *realargs[10];
+	int argc;
+	int res;
+	int rxtone;
+	int rxtag;
+	int txtone;
+	int isdcs = 0;
+	argc = res = parseargs(args, realargs, 3, ',');
+	if (res != 3) {
+		error("Incorrect number of arguments to 'ctcss' (should be <rxtone>,<rxtag>,<txtone>)\n");
+		return -1;
+	}
+	res = sscanf(realargs[0], "%d", &rxtone);
+	if ((res == 1) && (rxtone < 1))
+		res = -1;
+	if (res != 1) {
+		error("Invalid rxtone '%s', should be a number > 0.\n", realargs[0]);
+		return -1;
+	}
+	res = sscanf(realargs[1], "%d", &rxtag);
+	if ((res == 1) && (rxtag < 0))
+		res = -1;
+	if (res != 1) {
+		error("Invalid rxtag '%s', should be a number > 0.\n", realargs[1]);
+		return -1;
+	}
+	if ((*realargs[2] == 'D') || (*realargs[2] == 'd'))
+	{
+		realargs[2]++;
+		isdcs = 0x8000;
+	}
+	res = sscanf(realargs[2], "%d", &txtone);
+	if ((res == 1) && (rxtag < 0))
+		res = -1;
+	if (res != 1) {
+		error("Invalid txtone '%s', should be a number > 0.\n", realargs[2]);
+		return -1;
+	}
+
+	if (toneindex >= NUM_TONES)
+	{
+		error("Cannot specify more then %d CTCSS tones\n",NUM_TONES);
+		return -1;
+	}
+	rxtones[toneindex] = rxtone;
+	rxtags[toneindex] = rxtag;
+	txtones[toneindex] = txtone | isdcs;
+	toneindex++;
+	return 0;
+}
+
+int dcsrx(char *keyword, char *args)
+{
+	static char *realargs[10];
+	int argc;
+	int res;
+	int rxtone;
+	argc = res = parseargs(args, realargs, 1, ',');
+	if (res != 1) {
+		error("Incorrect number of arguments to 'dcsrx' (should be <rxtone>)\n");
+		return -1;
+	}
+	res = sscanf(realargs[0], "%d", &rxtone);
+	if ((res == 1) && (rxtone < 1))
+		res = -1;
+	if (res != 1) {
+		error("Invalid rxtone '%s', should be a number > 0.\n", realargs[0]);
+		return -1;
+	}
+
+	rxtones[0] = rxtone;
+	return 0;
+}
+
+int tx(char *keyword, char *args)
+{
+	static char *realargs[10];
+	int argc;
+	int res;
+	int txtone;
+	int isdcs = 0;
+	argc = res = parseargs(args, realargs, 1, ',');
+	if (res != 1) {
+		error("Incorrect number of arguments to 'tx' (should be <txtone>)\n");
+		return -1;
+	}
+	if ((*realargs[0] == 'D') || (*realargs[0] == 'd'))
+	{
+		realargs[0]++;
+		isdcs = 0x8000;
+	}
+	res = sscanf(realargs[0], "%d", &txtone);
+	if ((res == 1) && (txtone < 1))
+		res = -1;
+	if (res != 1) {
+		error("Invalid tx (tone) '%s', should be a number > 0.\n", realargs[0]);
+		return -1;
+	}
+
+	txtones[0] = txtone | isdcs;
+	return 0;
+}
+
+int debounce_time(char *keyword, char *args)
+{
+	static char *realargs[10];
+	int argc;
+	int res;
+	int val;
+	argc = res = parseargs(args, realargs, 1, ',');
+	if (res != 1) {
+		error("Incorrect number of arguments to 'debouncetime' (should be <value>)\n");
+		return -1;
+	}
+	res = sscanf(realargs[0], "%d", &val);
+	if ((res == 1) && (val < 1))
+		res = -1;
+	if (res != 1) {
+		error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
+		return -1;
+	}
+
+	debouncetime = val;
+	return 0;
+}
+
+int burst_time(char *keyword, char *args)
+{
+	static char *realargs[10];
+	int argc;
+	int res;
+	int val;
+	argc = res = parseargs(args, realargs, 1, ',');
+	if (res != 1) {
+		error("Incorrect number of arguments to 'bursttime' (should be <value>)\n");
+		return -1;
+	}
+	res = sscanf(realargs[0], "%d", &val);
+	if ((res == 1) && (val < 1))
+		res = -1;
+	if (res != 1) {
+		error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
+		return -1;
+	}
+
+	bursttime = val;
+	return 0;
+}
+
+int tx_gain(char *keyword, char *args)
+{
+	static char *realargs[10];
+	int argc;
+	int res;
+	int val;
+	argc = res = parseargs(args, realargs, 1, ',');
+	if (res != 1) {
+		error("Incorrect number of arguments to 'txgain' (should be <value>)\n");
+		return -1;
+	}
+	res = sscanf(realargs[0], "%d", &val);
+	if (res != 1) {
+		error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
+		return -1;
+	}
+
+	txgain = val;
+	return 0;
+}
+
+int rx_gain(char *keyword, char *args)
+{
+	static char *realargs[10];
+	int argc;
+	int res;
+	int val;
+	argc = res = parseargs(args, realargs, 1, ',');
+	if (res != 1) {
+		error("Incorrect number of arguments to 'rxgain' (should be <value>)\n");
+		return -1;
+	}
+	res = sscanf(realargs[0], "%d", &val);
+	if (res != 1) {
+		error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
+		return -1;
+	}
+
+	rxgain = val;
+	return 0;
+}
+
+int de_emp(char *keyword, char *args)
+{
+	static char *realargs[10];
+	int argc;
+	int res;
+	int val;
+	argc = res = parseargs(args, realargs, 1, ',');
+	if (res != 1) {
+		error("Incorrect number of arguments to 'de-emp' (should be <value>)\n");
+		return -1;
+	}
+	res = sscanf(realargs[0], "%d", &val);
+	if ((res == 1) && (val < 1))
+		res = -1;
+	if (res != 1) {
+		error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
+		return -1;
+	}
+
+	deemp = val;
+	return 0;
+}
+
+int pre_emp(char *keyword, char *args)
+{
+	static char *realargs[10];
+	int argc;
+	int res;
+	int val;
+	argc = res = parseargs(args, realargs, 1, ',');
+	if (res != 1) {
+		error("Incorrect number of arguments to 'pre_emp' (should be <value>)\n");
+		return -1;
+	}
+	res = sscanf(realargs[0], "%d", &val);
+	if ((res == 1) && (val < 1))
+		res = -1;
+	if (res != 1) {
+		error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
+		return -1;
+	}
+
+	preemp = val;
+	return 0;
+}
+
+int invert_cor(char *keyword, char *args)
+{
+	static char *realargs[10];
+	int argc;
+	int res;
+	int val;
+	argc = res = parseargs(args, realargs, 1, ',');
+	if (res != 1) {
+		error("Incorrect number of arguments to 'invertcor' (should be <value>)\n");
+		return -1;
+	}
+	if ((*realargs[0] == 'y') || (*realargs[0] == 'Y')) val = 1;
+	else if ((*realargs[0] == 'n') || (*realargs[0] == 'N')) val = 0;
+	else
+	{
+		res = sscanf(realargs[0], "%d", &val);
+		if ((res == 1) && (val < 0))
+			res = -1;
+		if (res != 1) {
+			error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
+			return -1;
+		}
+	}
+	invertcor = (val > 0);
+	return 0;
+}
+
+int ext_tone(char *keyword, char *args)
+{
+	static char *realargs[10];
+	int argc;
+	int res;
+	int val;
+	argc = res = parseargs(args, realargs, 1, ',');
+	if (res != 1) {
+		error("Incorrect number of arguments to 'exttone' (should be <value>)\n");
+		return -1;
+	}
+	if ((*realargs[0] == 'y') || (*realargs[0] == 'Y')) val = 1;
+	else if ((*realargs[0] == 'n') || (*realargs[0] == 'N')) val = 0;
+	else if ((*realargs[0] == 'i') || (*realargs[0] == 'I')) val = 2;
+	else
+	{
+		res = sscanf(realargs[0], "%d", &val);
+		if ((res == 1) && (val < 0))
+			res = -1;
+		if (val > 2) res = -1;
+		if (res != 1) {
+			error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
+			return -1;
+		}
+	}
+	exttone = val;
+	return 0;
+}
+
+int cor_thresh(char *keyword, char *args)
+{
+	static char *realargs[10];
+	int argc;
+	int res;
+	int val;
+	int x = 0;
+	argc = res = parseargs(args, realargs, 1, ',');
+	if (res != 1) {
+		error("Incorrect number of arguments to 'corthresh' (should be <value>)\n");
+		return -1;
+	}
+	res = sscanf(realargs[0], "%d", &val);
+	if ((res == 1) && (val < 1))
+		res = -1;
+	for(x = 0; corthreshes[x]; x++)
+	{
+		if (corthreshes[x] == val) break;
+	}
+	if (!corthreshes[x]) res = -1;
+	if (res != 1) {
+		error("Invalid value '%s', should be a number > 0.\n", realargs[0]);
+		return -1;
+	}
+	corthresh = x + 1;
+	return 0;
+}
+
+static int rad_chanconfig(char *keyword, char *args)
+{
+	int chans[DAHDI_MAX_CHANNELS];
+	int res = 0;
+	int x,i,n;
+	struct dahdi_radio_param p;
+
+	toneindex = 1;
+	bzero(chans, sizeof(chans));
+	res = apply_channels(chans, args);
+	if (res <= 0)
+		return -1;
+	for (x=1;x<DAHDI_MAX_CHANNELS;x++) {
+		if (chans[x]) {
+			p.radpar = DAHDI_RADPAR_NUMTONES;
+			if (ind_ioctl(x,fd,DAHDI_RADIO_GETPARAM,&p) == -1)
+				n = 0;
+			else
+				n = p.data;
+
+			if (n)
+			{
+				p.radpar = DAHDI_RADPAR_INITTONE;
+				if (ind_ioctl(x,fd,DAHDI_RADIO_SETPARAM,&p) == -1) {
+					error("Cannot init tones for channel %d\n",x);
+				}
+				if (!rxtones[0]) for(i = 1; i <= n; i++)
+				{
+					if (rxtones[i])
+					{
+						p.radpar = DAHDI_RADPAR_RXTONE;
+						p.index = i;
+						p.data = rxtones[i];
+						if (ind_ioctl(x,fd,DAHDI_RADIO_SETPARAM,&p) == -1)
+							error("Cannot set rxtone on channel %d\n",x);
+					}
+					if (rxtags[i])
+					{
+						p.radpar = DAHDI_RADPAR_RXTONECLASS;
+						p.index = i;
+						p.data = rxtags[i];
+						if (ind_ioctl(x,fd,DAHDI_RADIO_SETPARAM,&p) == -1)
+							error("Cannot set rxtag on channel %d\n",x);
+					}
+					if (txtones[i])
+					{
+						p.radpar = DAHDI_RADPAR_TXTONE;
+						p.index = i;
+						p.data = txtones[i];
+						if (ind_ioctl(x,fd,DAHDI_RADIO_SETPARAM,&p) == -1)
+							error("Cannot set txtone on channel %d\n",x);
+					}
+				} else { /* if we may have DCS receive */
+					if (rxtones[0])
+					{
+						p.radpar = DAHDI_RADPAR_RXTONE;
+						p.index = 0;
+						p.data = rxtones[0];
+						if (ind_ioctl(x,fd,DAHDI_RADIO_SETPARAM,&p) == -1)
+							error("Cannot set DCS rxtone on channel %d\n",x);
+					}
+				}
+				if (txtones[0])
+				{
+					p.radpar = DAHDI_RADPAR_TXTONE;
+					p.index = 0;
+					p.data = txtones[0];
+					if (ind_ioctl(x,fd,DAHDI_RADIO_SETPARAM,&p) == -1)
+						error("Cannot set default txtone on channel %d\n",x);
+				}
+			}
+			if (debouncetime)
+			{
+				p.radpar = DAHDI_RADPAR_DEBOUNCETIME;
+				p.data = debouncetime;
+				if (ind_ioctl(x,fd,DAHDI_RADIO_SETPARAM,&p) == -1)
+					error("Cannot set debouncetime on channel %d\n",x);
+			}
+			if (bursttime)
+			{
+				p.radpar = DAHDI_RADPAR_BURSTTIME;
+				p.data = bursttime;
+				if (ind_ioctl(x,fd,DAHDI_RADIO_SETPARAM,&p) == -1)
+					error("Cannot set bursttime on channel %d\n",x);
+			}
+			p.radpar = DAHDI_RADPAR_DEEMP;
+			p.data = deemp;
+			ind_ioctl(x,fd,DAHDI_RADIO_SETPARAM,&p);
+			p.radpar = DAHDI_RADPAR_PREEMP;
+			p.data = preemp;
+			ind_ioctl(x,fd,DAHDI_RADIO_SETPARAM,&p);
+			p.radpar = DAHDI_RADPAR_TXGAIN;
+			p.data = txgain;
+			ind_ioctl(x,fd,DAHDI_RADIO_SETPARAM,&p);
+			p.radpar = DAHDI_RADPAR_RXGAIN;
+			p.data = rxgain;
+			ind_ioctl(x,fd,DAHDI_RADIO_SETPARAM,&p);
+			p.radpar = DAHDI_RADPAR_INVERTCOR;
+			p.data = invertcor;
+			ind_ioctl(x,fd,DAHDI_RADIO_SETPARAM,&p);
+			p.radpar = DAHDI_RADPAR_EXTRXTONE;
+			p.data = exttone;
+			ind_ioctl(x,fd,DAHDI_RADIO_SETPARAM,&p);
+			if (corthresh)
+			{
+				p.radpar = DAHDI_RADPAR_CORTHRESH;
+				p.data = corthresh - 1;
+				if (ind_ioctl(x,fd,DAHDI_RADIO_SETPARAM,&p) == -1)
+					error("Cannot set corthresh on channel %d\n",x);
+			}
+		}
+	}
+	clear_fields();
+	return 0;
+}
+
+/* End Radio functions */
+
+static void printconfig(int fd)
+{
+	int x,y;
+	int ps;
+	int configs=0;
+	struct dahdi_versioninfo vi;
+
+	strcpy(vi.version, "Unknown");
+	strcpy(vi.echo_canceller, "Unknown");
+
+	if (ioctl(fd, DAHDI_GETVERSION, &vi))
+		error("Unable to read DAHDI version information.\n");
+
+	printf("\nDAHDI Version: %s\n"
+	       "Echo Canceller(s): %s\n"
+	       "Configuration\n"
+	       "======================\n\n", vi.version, vi.echo_canceller);
+	for (x = 0; x < spans; x++) {
+		printf("SPAN %d: %3s/%4s Build-out: %s\n",
+		       lc[x].span,
+		       (lc[x].lineconfig & DAHDI_CONFIG_D4 ? "D4" :
+			lc[x].lineconfig & DAHDI_CONFIG_ESF ? "ESF" :
+			lc[x].lineconfig & DAHDI_CONFIG_CCS ? "CCS" : "CAS"),
+		       (lc[x].lineconfig & DAHDI_CONFIG_AMI ? "AMI" :
+			lc[x].lineconfig & DAHDI_CONFIG_B8ZS ? "B8ZS" :
+			lc[x].lineconfig & DAHDI_CONFIG_HDB3 ? "HDB3" : "???"),
+		       lbostr[lc[x].lbo]);
+	}
+	for (x=0;x<numdynamic;x++) {
+		printf("Dynamic span %d: driver %s, addr %s, channels %d, timing %d\n",
+		       x +1, zds[x].driver, zds[x].addr, zds[x].numchans, zds[x].timing);
+	}
+	if (verbose > 1) {
+		printf("\nChannel map:\n\n");
+		for (x=1;x<DAHDI_MAX_CHANNELS;x++) {
+			if ((cc[x].sigtype != DAHDI_SIG_SLAVE) && (cc[x].sigtype)) {
+				configs++;
+				ps = 0;
+				if ((cc[x].sigtype & __DAHDI_SIG_DACS) == __DAHDI_SIG_DACS)
+					printf("Channel %02d %s to %02d", x, sig[x], cc[x].idlebits);
+				else {
+					printf("Channel %02d: %s (%s)", x, sig[x], laws[cc[x].deflaw]);
+					printf(" (Echo Canceler: %s)", ae[x].echocan[0] ? ae[x].echocan : "none");
+					for (y=1;y<DAHDI_MAX_CHANNELS;y++) {
+						if (cc[y].master == x)  {
+							printf("%s%02d", ps++ ? " " : " (Slaves: ", y);
+						}
+					}
+				}
+				if (ps)
+					printf(")\n");
+				else
+					printf("\n");
+			} else
+				if (cc[x].sigtype) configs++;
+		}
+	} else {
+		for (x=1;x<DAHDI_MAX_CHANNELS;x++) {
+			if (cc[x].sigtype)
+				configs++;
+		}
+	}
+	printf("\n%d channels to configure.\n\n", configs);
+}
+
+static struct handler {
+	char *keyword;
+	int (*func)(char *keyword, char *args);
+} handlers[] = {
+	{ "span", spanconfig },
+	{ "dynamic", dspanconfig },
+	{ "loadzone", registerzone },
+	{ "defaultzone", defaultzone },
+	{ "e&m", chanconfig },
+	{ "e&me1", chanconfig },
+	{ "fxsls", chanconfig },
+	{ "fxsgs", chanconfig },
+	{ "fxsks", chanconfig },
+	{ "fxols", chanconfig },
+	{ "fxogs", chanconfig },
+	{ "fxoks", chanconfig },
+	{ "rawhdlc", chanconfig },
+	{ "nethdlc", chanconfig },
+	{ "fcshdlc", chanconfig },
+	{ "hardhdlc", chanconfig },
+	{ "mtp2", chanconfig },
+	{ "dchan", chanconfig },
+	{ "bchan", chanconfig },
+	{ "indclear", chanconfig },
+	{ "clear", chanconfig },
+	{ "unused", chanconfig },
+	{ "cas", chanconfig },
+	{ "dacs", chanconfig },
+	{ "dacsrbs", chanconfig },
+	{ "user", chanconfig },
+	{ "alaw", setlaw },
+	{ "mulaw", setlaw },
+	{ "deflaw", setlaw },
+	{ "ctcss", ctcss },
+	{ "dcsrx", dcsrx },
+	{ "rxdcs", dcsrx },
+	{ "tx", tx },
+	{ "debouncetime", debounce_time },
+	{ "bursttime", burst_time },
+	{ "exttone", ext_tone },
+	{ "invertcor", invert_cor },
+	{ "corthresh", cor_thresh },
+	{ "rxgain", rx_gain },
+	{ "txgain", tx_gain },
+	{ "deemp", de_emp },
+	{ "preemp", pre_emp },
+	{ "channel", rad_chanconfig },
+	{ "channels", rad_chanconfig },
+	{ "echocanceller", setechocan },
+	{ "56k", setfiftysixkhdlc },
+};
+
+static char *readline()
+{
+	static char buf[256];
+	char *c;
+	do {
+		if (!fgets(buf, sizeof(buf), cf)) 
+			return NULL;
+		/* Strip comments */
+		c = strchr(buf, '#');
+		if (c)
+			*c = '\0';
+		trim(buf);
+		lineno++;
+	} while (!strlen(buf));
+	return buf;
+}
+
+static void usage(char *argv0, int exitcode)
+{
+	char *c;
+	c = strrchr(argv0, '/');
+	if (!c)
+		c = argv0;
+	else
+		c++;
+	fprintf(stderr, "%s\n", dahdi_tools_version);
+	fprintf(stderr, 
+		"Usage: %s [options]\n"
+		"    Valid options are:\n"
+		"  -c <filename>     -- Use <filename> instead of " CONFIG_FILENAME "\n"
+		"  -d [level]        -- Generate debugging output. (Default level is 1.)\n"
+		"  -f                -- Always reconfigure every channel\n"
+		"  -h                -- Generate this help statement\n"
+		"  -s                -- Shutdown spans only\n"
+		"  -t                -- Test mode only, do not apply\n"
+		"  -v                -- Verbose (more -v's means more verbose)\n"
+	,c);
+	exit(exitcode);
+}
+
+int main(int argc, char *argv[])
+{
+	int c;
+	char *buf;
+	char *key, *value;
+	int x,found;
+
+	while((c = getopt(argc, argv, "fthc:vsd::")) != -1) {
+		switch(c) {
+		case 'c':
+			filename=optarg;
+			break;
+		case 'h':
+			usage(argv[0], 0);
+			break;
+		case '?':
+			usage(argv[0], 1);
+			break;
+		case 'v':
+			verbose++;
+			break;
+		case 'f':
+			force++;
+			break;
+		case 't':
+			fo_real = 0;
+			break;
+		case 's':
+			stopmode = 1;
+			break;
+		case 'd':
+			if (optarg)
+				debug = atoi(optarg);
+			else
+				debug = 1;	
+			break;
+		}
+	}
+	
+	if (verbose) {
+		fprintf(stderr, "%s\n", dahdi_tools_version);
+	}
+
+	if (fd == -1) fd = open(MASTER_DEVICE, O_RDWR);
+	if (fd < 0) {
+		error("Unable to open master device '%s'\n", MASTER_DEVICE);
+		goto finish;
+	}
+	cf = fopen(filename, "r");
+	if (cf) {
+		while((buf = readline())) {
+			if (*buf == 10) /* skip new line */
+				continue;
+
+			if (debug & DEBUG_READER) 
+				fprintf(stderr, "Line %d: %s\n", lineno, buf);
+
+			if ((value = strchr(buf, '='))) {
+				*value++ = '\0';
+				value = trim(value);
+				key = trim(buf);
+			}
+
+			if (!value || !*value || !*key) {
+				error("Syntax error. Should be <keyword>=<value>\n");
+				continue;
+			}
+
+			if (debug & DEBUG_PARSER)
+				fprintf(stderr, "Keyword: [%s], Value: [%s]\n", key, value);
+
+			found = 0;
+			for (x = 0; x < sizeof(handlers) / sizeof(handlers[0]); x++) {
+				if (!strcasecmp(key, handlers[x].keyword)) {
+					found++;
+					handlers[x].func(key, value);
+					break;
+				}
+			}
+
+			if (!found) 
+				error("Unknown keyword '%s'\n", key);
+		}
+		if (debug & DEBUG_READER)
+			fprintf(stderr, "<End of File>\n");
+		/* fclose(cf); // causes seg fault (double free) */
+	} else {
+		error("Unable to open configuration file '%s'\n", filename);
+	}
+
+finish:
+	if (errcnt) {
+		fprintf(stderr, "\n%d error(s) detected\n\n", errcnt);
+		exit(1);
+	}
+	if (verbose) {
+		printconfig(fd);
+	}
+	if (!fo_real) 
+		exit(0);
+
+	
+	if (debug & DEBUG_APPLY) {
+		printf("About to open Master device\n");
+		fflush(stdout);
+	}
+	for (x=0;x<numdynamic;x++) {
+		/* destroy them all */
+		ioctl(fd, DAHDI_DYNAMIC_DESTROY, &zds[x]);
+	}
+	if (stopmode) {
+		for (x=0;x<spans;x++) {
+			if (ioctl(fd, DAHDI_SHUTDOWN, &lc[x].span)) {
+				fprintf(stderr, "DAHDI shutdown failed: %s\n", strerror(errno));
+				close(fd);
+				exit(1);
+			}
+		}
+		exit(1);
+	}
+	for (x=0;x<spans;x++) {
+		if (ioctl(fd, DAHDI_SPANCONFIG, lc + x)) {
+			fprintf(stderr, "DAHDI_SPANCONFIG failed on span %d: %s (%d)\n", lc[x].span, strerror(errno), errno);
+			close(fd);
+			exit(1);
+		}
+	}
+	for (x=0;x<numdynamic;x++) {
+		if (ioctl(fd, DAHDI_DYNAMIC_CREATE, &zds[x])) {
+			fprintf(stderr, "DAHDI dynamic span creation failed: %s\n", strerror(errno));
+			close(fd);
+			exit(1);
+		}
+	}
+	for (x=1;x<DAHDI_MAX_CHANNELS;x++) {
+		struct dahdi_params current_state;
+		int master;
+		int needupdate = force;
+		
+		if (debug & DEBUG_APPLY) {
+			printf("Configuring device %d\n", x);
+			fflush(stdout);
+		}
+		if (!cc[x].sigtype)
+			continue;
+		
+		if (!needupdate) {
+			memset(&current_state, 0, sizeof(current_state));
+			current_state.channo = cc[x].chan | DAHDI_GET_PARAMS_RETURN_MASTER;
+			if (ioctl(fd, DAHDI_GET_PARAMS, &current_state))
+				needupdate = 1;
+		}
+		
+		if (!needupdate) {
+			master = current_state.channo >> 16;
+			
+			if (cc[x].sigtype != current_state.sigtype) {
+				needupdate++;
+				if (verbose > 1)
+					printf("Changing signalling on channel %d from %s to %s\n",
+					       cc[x].chan, sigtype_to_str(current_state.sigtype),
+					       sigtype_to_str(cc[x].sigtype));
+			}
+			
+			if ((cc[x].deflaw != DAHDI_LAW_DEFAULT) && (cc[x].deflaw != current_state.curlaw)) {
+				needupdate++;
+				if (verbose > 1)
+					printf("Changing law on channel %d from %s to %s\n",
+					       cc[x].chan, laws[current_state.curlaw],
+					       laws[cc[x].deflaw]);
+			}
+			
+			if (cc[x].master != master) {
+				needupdate++;
+				if (verbose > 1)
+					printf("Changing master of channel %d from %d to %d\n",
+					       cc[x].chan, master,
+					       cc[x].master);
+			}
+			
+			if (cc[x].idlebits != current_state.idlebits) {
+				needupdate++;
+				if (verbose > 1)
+					printf("Changing idle bits of channel %d from %d to %d\n",
+					       cc[x].chan, current_state.idlebits,
+					       cc[x].idlebits);
+			}
+		}
+		
+		if (needupdate && ioctl(fd, DAHDI_CHANCONFIG, &cc[x])) {
+			fprintf(stderr, "DAHDI_CHANCONFIG failed on channel %d: %s (%d)\n", x, strerror(errno), errno);
+			if (errno == EINVAL) {
+				/* give helpful suggestions on signaling errors */
+				fprintf(stderr, "Selected signaling not "
+						"supported\n");
+				fprintf(stderr, "Possible causes:\n");
+				switch(cc[x].sigtype) {
+				case DAHDI_SIG_FXOKS:
+				case DAHDI_SIG_FXOLS:
+				case DAHDI_SIG_FXOGS:
+					fprintf(stderr, "\tFXO signaling is "
+						"being used on a FXO interface"
+						" (use a FXS signaling variant"
+						")\n");
+					fprintf(stderr, "\tRBS signaling is "
+						"being used on a E1 CCS span"
+						"\n");
+					break;
+				case DAHDI_SIG_FXSKS:
+				case DAHDI_SIG_FXSLS:
+				case DAHDI_SIG_FXSGS:
+					fprintf(stderr, "\tFXS signaling is "
+						"being used on a FXS interface"
+						" (use a FXO signaling variant"
+						")\n");
+					fprintf(stderr, "\tRBS signaling is "
+						"being used on a E1 CCS span"
+						"\n");
+					break;
+				case DAHDI_SIG_EM:
+					fprintf(stderr, "\te&m signaling is "
+						"being used on a E1 line (use"
+						" e&me1)\n");
+					break;
+				case DAHDI_SIG_EM_E1:
+					fprintf(stderr, "\te&me1 signaling is "
+						"being used on a T1 line (use "
+						"e&m)\n");
+					fprintf(stderr, "\tRBS signaling is "
+						"being used on a E1 CCS span"
+						"\n");
+					break;
+				case DAHDI_SIG_HARDHDLC:
+					fprintf(stderr, "\thardhdlc is being "
+						"used on a TE12x (use dchan)\n"
+						);
+					break;
+				case DAHDI_SIG_HDLCFCS:
+					fprintf(stderr, "\tdchan is being used"
+						" on a BRI span (use hardhdlc)"
+						"\n");
+					break;
+				default:
+					break;
+				}
+				fprintf(stderr, "\tSignaling is being assigned"
+					" to channel 16 of an E1 CAS span\n");
+			}
+			close(fd);
+			exit(1);
+		}
+
+		ae[x].chan = x;
+		if (verbose) {
+			printf("Setting echocan for channel %d to %s\n", ae[x].chan, ae[x].echocan[0] ? ae[x].echocan : "none");
+		}
+
+		if (ioctl(fd, DAHDI_ATTACH_ECHOCAN, &ae[x])) {
+			fprintf(stderr, "DAHDI_ATTACH_ECHOCAN failed on channel %d: %s (%d)\n", x, strerror(errno), errno);
+			close(fd);
+			exit(1);
+		}
+	}
+	if (0 == numzones) {
+		/* Default to the us zone if one wasn't specified. */
+		dahdi_copy_string(zonestoload[numzones++], "us", sizeof(zonestoload[0]));
+		deftonezone = 0;
+	}
+
+	for (x=0;x<numzones;x++) {
+		if (debug & DEBUG_APPLY) {
+			printf("Loading tone zone for %s\n", zonestoload[x]);
+			fflush(stdout);
+		}
+		if (tone_zone_register(fd, zonestoload[x])) {
+			if (errno != EBUSY)
+				error("Unable to register tone zone '%s'\n", zonestoload[x]);
+		}
+	}
+	if (debug & DEBUG_APPLY) {
+		printf("Doing startup\n");
+		fflush(stdout);
+	}
+	if (deftonezone > -1) {
+		if (ioctl(fd, DAHDI_DEFAULTZONE, &deftonezone)) {
+			fprintf(stderr, "DAHDI_DEFAULTZONE failed: %s (%d)\n", strerror(errno), errno);
+			close(fd);
+			exit(1);
+		}
+	}
+	for (x=0;x<spans;x++) {
+		if (ioctl(fd, DAHDI_STARTUP, &lc[x].span)) {
+			fprintf(stderr, "DAHDI startup failed: %s\n", strerror(errno));
+			close(fd);
+			exit(1);
+		}
+	}
+	apply_fiftysix();
+	exit(0);
+}
diff --git a/dahdi_diag.c b/dahdi_diag.c
new file mode 100644
index 0000000..ec1a587
--- /dev/null
+++ b/dahdi_diag.c
@@ -0,0 +1,55 @@
+/*
+ * Written by Mark Spencer <markster at digium.com>
+ * Based on previous works, designs, and architectures conceived and
+ * written by Jim Dixon <jim at lambdatel.com>.
+ *
+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
+ * Copyright (C) 2001-2008 Digium, Inc.
+ *
+ * All rights reserved.
+ *
+ * Primary Author: Mark Spencer <markster at digium.com>
+ * Radio Support by Jim Dixon <jim at lambdatel.com>
+ */
+
+/*
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2 as published by the
+ * Free Software Foundation. See the LICENSE file included with
+ * this program for more details.
+ */
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <dahdi/user.h>
+#include "dahdi_tools_version.h"
+
+int main(int argc, char *argv[])
+{
+	int fd;
+	int chan;
+	if ((argc < 2) || (sscanf(argv[1], "%d", &chan) != 1)) {
+		fprintf(stderr, "Usage: dahdi_diag <channel>\n");
+		exit(1);
+	}
+	fd = open("/dev/dahdi/ctl", O_RDWR);
+	if (fd < 0) {
+		perror("open(/dev/dahdi/ctl");
+		exit(1);
+	}
+	if (ioctl(fd, DAHDI_CHANDIAG, &chan)) {
+		perror("ioctl(DAHDI_CHANDIAG)");
+		exit(1);
+	}
+	exit(0);
+}
diff --git a/dahdi_maint.c b/dahdi_maint.c
new file mode 100644
index 0000000..f9c9083
--- /dev/null
+++ b/dahdi_maint.c
@@ -0,0 +1,236 @@
+/*
+ * Performance and Maintenance utility
+ *
+ * Written by Russ Meyerriecks <rmeyerriecks at digium.com>
+ *
+ * Copyright (C) 2009-2010 Digium, Inc.
+ *
+ * All rights reserved.
+ *
+ */
+
+/*
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2 as published by the
+ * Free Software Foundation. See the LICENSE file included with
+ * this program for more details.
+ */
+
+#include <stdio.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+#include <dahdi/user.h>
+#include "dahdi_tools_version.h"
+
+#define DAHDI_CTL "/dev/dahdi/ctl"
+
+extern char *optarg;
+extern int optind;
+
+void display_help(char *argv0, int exitcode)
+{
+	char *c;
+	c = strrchr(argv0, '/');
+	if (!c)
+		c = argv0;
+	else
+		c++;
+	fprintf(stderr, "%s\n\n", dahdi_tools_version);
+	fprintf(stderr, "Usage: %s -s <span num> <options>\n", c);
+	fprintf(stderr, "Options:\n");
+	fprintf(stderr, "        -h, --help		display help\n");
+	fprintf(stderr, "        -s, --span <span num>	specify the span\n");
+	fprintf(stderr, "        -l, --loopback <localhost|networkline|"\
+						"networkpayload|off>\n"\
+			"\t\tlocalhost - loop back towards host\n"\
+			"\t\tnetworkline - network line loopback\n"\
+			"\t\tnetworkpayload - network payload loopback\n");
+	fprintf(stderr, "        -i, --insert <fas|multi|crc|cas|prbs|bipolar>"\
+			"\n\t\tinsert an error of a specific type\n");
+	fprintf(stderr, "        -r, --reset		"\
+			"reset the error counters\n\n");
+	fprintf(stderr, "Examples: \n");
+	fprintf(stderr, "Enable network line loopback\n");
+	fprintf(stderr, "	dahdi_maint -s 1 --loopback networkline\n");
+	fprintf(stderr, "Disable network line loopback\n");
+	fprintf(stderr, "	dahdi_maint -s 1 --loopback off\n\n");
+
+	exit(exitcode);
+}
+
+int main(int argc, char *argv[])
+{
+	static int ctl = -1;
+	int res;
+
+	int doloopback = 0;
+	char *larg = NULL;
+	int sflag = 0;
+	int span = 1;
+	int iflag = 0;
+	char *iarg = NULL;
+	int gflag = 0;
+	int c;
+	int rflag = 0;
+
+	struct dahdi_maintinfo m;
+	struct dahdi_spaninfo s;
+
+	static struct option long_options[] = {
+		{"help",	no_argument,	   0, 'h'},
+		{"loopback",	required_argument, 0, 'l'},
+		{"span",	required_argument, 0, 's'},
+		{"insert",	required_argument, 0, 'i'},
+		{"reset",	no_argument, 	   0, 'r'},
+		{0, 0, 0, 0}
+	};
+	int option_index = 0;
+
+	if (argc < 2) { /* no options */
+		display_help(argv[0], 1);
+	}
+
+	while ((c = getopt_long(argc, argv, "hj:l:p:s:i:g:r",
+				long_options, &option_index)) != -1) {
+			switch (c) {
+			case 'h': /* local host loopback */
+				display_help(argv[0], 0);
+				break;
+			case 'l': /* network line loopback */
+				larg = optarg;
+				doloopback = 1;
+				break;
+			case 's': /* specify a span */
+				span = atoi(optarg);
+				sflag = 1;
+				break;
+			case 'i': /* insert an error */
+				iarg = optarg;
+				iflag = 1;
+				break;
+			case 'g': /* generate psuedo random sequence */
+				gflag = 1;
+				break;
+			case 'r': /* reset the error counters */
+				rflag = 1;
+				break;
+			}
+	}
+
+	ctl = open(DAHDI_CTL, O_RDWR);
+	if (ctl < 0) {
+		fprintf(stderr, "Unable to open %s\n", DAHDI_CTL);
+		return -1;
+	}
+
+	if (!(doloopback || iflag || gflag || rflag)) {
+		s.spanno = span;
+		res = ioctl(ctl, DAHDI_SPANSTAT, &s);
+		if (res)
+			printf("Error counters not supported by the driver"\
+					" for this span\n");
+		printf("Span %d:\n", span);
+		printf(">FEC : %d:\n", s.fecount);
+		printf(">CEC : %d:\n", s.crc4count);
+		printf(">CVC : %d:\n", s.cvcount);
+		printf(">EBC : %d:\n", s.ebitcount);
+		printf(">BEC : %d:\n", s.becount);
+		printf(">PRBS: %d:\n", s.prbs);
+		printf(">GES : %d:\n", s.errsec);
+
+		return 0;
+	}
+
+	m.spanno = span;
+
+	if (doloopback) {
+		if (!strcasecmp(larg, "localhost")) {
+			printf("Span %d: local host loopback ON\n", span);
+			m.command = DAHDI_MAINT_LOCALLOOP;
+		} else if (!strcasecmp(larg, "networkline")) {
+			printf("Span %d: network line loopback ON\n", span);
+			m.command = DAHDI_MAINT_NETWORKLINELOOP;
+		} else if (!strcasecmp(larg, "networkpayload")) {
+			printf("Span %d: network payload loopback ON\n", span);
+			m.command = DAHDI_MAINT_NETWORKPAYLOADLOOP;
+		} else if (!strcasecmp(larg, "off")) {
+			printf("Span %d: loopback OFF\n", span);
+			m.command = DAHDI_MAINT_NONE;
+		} else {
+			display_help(argv[0], 1);
+		}
+
+		res = ioctl(ctl, DAHDI_MAINT, &m);
+		if (res)
+			printf("This type of looping not supported by the"\
+					" driver for this span\n");
+	}
+
+	if (iflag) {
+		if (!strcasecmp(iarg, "fas")) {
+			m.command = DAHDI_MAINT_FAS_DEFECT;
+			printf("Inserting a single FAS defect\n");
+		} else if (!strcasecmp(iarg, "multi")) {
+			m.command = DAHDI_MAINT_MULTI_DEFECT;
+			printf("Inserting a single multiframe defect\n");
+		} else if (!strcasecmp(iarg, "crc")) {
+			m.command = DAHDI_MAINT_CRC_DEFECT;
+			printf("Inserting a single CRC defect\n");
+		} else if (!strcasecmp(iarg, "cas")) {
+			m.command = DAHDI_MAINT_CAS_DEFECT;
+			printf("Inserting a single CAS defect\n");
+		} else if (!strcasecmp(iarg, "prbs")) {
+			m.command = DAHDI_MAINT_PRBS_DEFECT;
+			printf("Inserting a single PRBS defect\n");
+		} else if (!strcasecmp(iarg, "bipolar")) {
+			m.command = DAHDI_MAINT_BIPOLAR_DEFECT;
+			printf("Inserting a single bipolar defect\n");
+#ifdef DAHDI_MAINT_ALARM_SIM
+		} else if (!strcasecmp(iarg, "sim")) {
+			m.command = DAHDI_MAINT_ALARM_SIM;
+			printf("Incrementing alarm simulator\n");
+#endif
+		} else {
+			display_help(argv[0], 1);
+		}
+		res = ioctl(ctl, DAHDI_MAINT, &m);
+		if (res)
+			printf("This type of error injection is not supported"\
+					" by the driver for this span\n");
+	}
+
+	if (gflag) {
+		printf("Enabled the Pseudo-Random Binary Sequence Generation"\
+			" and Monitor\n");
+		m.command = DAHDI_MAINT_PRBS;
+		res = ioctl(ctl, DAHDI_MAINT, &m);
+		if (res) {
+			printf("Pseudo-random binary sequence generation is"\
+				" not supported by the driver for this span\n");
+		}
+	}
+
+	if (rflag) {
+		printf("Resetting error counters for span %d\n", span);
+		m.command = DAHDI_RESET_COUNTERS;
+		res = ioctl(ctl, DAHDI_MAINT, &m);
+		if (res) {
+			printf("Resetting error counters is not supported by"\
+					" the driver for this span\n");
+		}
+	}
+
+	return 0;
+}
diff --git a/dahdi_monitor.c b/dahdi_monitor.c
new file mode 100644
index 0000000..e61b610
--- /dev/null
+++ b/dahdi_monitor.c
@@ -0,0 +1,783 @@
+/*
+ * Monitor a DAHDI Channel
+ *
+ * Written by Mark Spencer <markster at digium.com>
+ * Based on previous works, designs, and architectures conceived and
+ * written by Jim Dixon <jim at lambdatel.com>.
+ *
+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
+ * Copyright (C) 2001-2008 Digium, Inc.
+ *
+ * All rights reserved.
+ *
+ */
+
+/*
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2 as published by the
+ * Free Software Foundation. See the LICENSE file included with
+ * this program for more details.
+ */
+
+#include <stdio.h>
+#include <getopt.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <signal.h>
+
+#include <dahdi/user.h>
+#include "dahdi_tools_version.h"
+#include "wavformat.h"
+#include "autoconfig.h"
+
+#ifdef HAVE_SYS_SOUNDCARD_H
+# include <sys/soundcard.h>
+#else
+# ifdef HAVE_LINUX_SOUNDCARD_H
+#  include <linux/soundcard.h>
+# else
+#  error "Your installation appears to be missing soundcard.h which is needed to continue."
+# endif
+#endif
+
+/*
+* defines for file handle numbers
+*/
+#define MON_BRX		   0	/*!< both channels if multichannel==1 or receive otherwise */
+#define MON_TX		   1	/*!< transmit channel */
+#define MON_PRE_BRX	   2	/*!< same as MON_BRX but before echo cancellation */
+#define MON_PRE_TX	   3	/*!< same as MON_TX but before echo cancellation */
+#define MON_STEREO     4	/*!< stereo mix of rx/tx streams */
+#define MON_PRE_STEREO 5	/*!< stereo mix of rx/tx before echo can.  This is exactly what is fed into the echo can */
+
+#define BLOCK_SIZE 240
+
+#define BUFFERS 4
+
+#define FRAG_SIZE 8
+
+#define MAX_OFH 6
+
+/* Put the ofh (output file handles) outside the main loop in case we ever add a
+ * signal handler.
+ */
+static FILE *ofh[MAX_OFH];
+static int run = 1;
+
+static int stereo;
+static int verbose;
+
+/* handler to catch ctrl-c */
+void cleanup_and_exit(int signal)
+{
+	fprintf(stderr, "cntrl-c pressed\n");
+	run = 0; /* stop reading */
+}
+
+int filename_is_wav(char *filename)
+{
+	if (NULL != strstr(filename, ".wav"))
+		return 1;
+	return 0;
+}
+
+/*
+ * Fill the wav header with default info
+ * num_chans - 0 = mono; 1 = stereo
+ */
+void wavheader_init(struct wavheader *wavheader, int num_chans)
+{
+	memset(wavheader, 0, sizeof(struct wavheader));
+
+	memcpy(&wavheader->riff_chunk_id, "RIFF", 4);
+	memcpy(&wavheader->riff_type, "WAVE", 4);
+
+	memcpy(&wavheader->fmt_chunk_id, "fmt ", 4);
+	wavheader->fmt_data_size = 16;
+	wavheader->fmt_compression_code = 1;
+	wavheader->fmt_num_channels = num_chans;
+	wavheader->fmt_sample_rate = 8000;
+	wavheader->fmt_avg_bytes_per_sec = 16000;
+	wavheader->fmt_block_align = 2;
+	wavheader->fmt_significant_bps = 16;
+
+	memcpy(&wavheader->data_chunk_id, "data", 4);
+}
+
+int audio_open(void)
+{
+	int fd;
+	int speed = 8000;
+	int fmt = AFMT_S16_LE;
+	int fragsize = (BUFFERS << 16) | (FRAG_SIZE);
+	struct audio_buf_info ispace, ospace;
+	fd = open("/dev/dsp", O_WRONLY);
+	if (fd < 0) {
+		fprintf(stderr, "Unable to open /dev/dsp: %s\n", strerror(errno));
+		return -1;
+	}
+	/* Step 1: Signed linear */
+	if (ioctl(fd, SNDCTL_DSP_SETFMT, &fmt) < 0) {
+		fprintf(stderr, "ioctl(SETFMT) failed: %s\n", strerror(errno));
+		close(fd);
+		return -1;
+	}
+	/* Step 2: Make non-stereo */
+	if (ioctl(fd, SNDCTL_DSP_STEREO, &stereo) < 0) {
+		fprintf(stderr, "ioctl(STEREO) failed: %s\n", strerror(errno));
+		close(fd);
+		return -1;
+	}
+	if (stereo != 0) {
+		fprintf(stderr, "Can't turn stereo off :(\n");
+	}
+	/* Step 3: Make 8000 Hz */
+	if (ioctl(fd, SNDCTL_DSP_SPEED, &speed) < 0) {
+		fprintf(stderr, "ioctl(SPEED) failed: %s\n", strerror(errno));
+		close(fd);
+		return -1;
+	}
+	if (speed != 8000) {
+		fprintf(stderr, "Warning: Requested 8000 Hz, got %d\n", speed);
+	}
+	if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &fragsize)) {
+		fprintf(stderr, "Sound card won't let me set fragment size to %u %u-byte buffers (%x)\n"
+						"so sound may be choppy: %s.\n", BUFFERS, (1 << FRAG_SIZE), fragsize, strerror(errno));
+	}
+	bzero(&ispace, sizeof(ispace));
+	bzero(&ospace, sizeof(ospace));
+
+	if (ioctl(fd, SNDCTL_DSP_GETISPACE, &ispace)) {
+		/* They don't support block size stuff, so just return but notify the user */
+		fprintf(stderr, "Sound card won't let me know the input buffering...\n");
+	}
+	if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &ospace)) {
+		/* They don't support block size stuff, so just return but notify the user */
+		fprintf(stderr, "Sound card won't let me know the output buffering...\n");
+	}
+	fprintf(stderr, "New input space:  %d of %d %d byte fragments (%d bytes left)\n",
+		ispace.fragments, ispace.fragstotal, ispace.fragsize, ispace.bytes);
+	fprintf(stderr, "New output space:  %d of %d %d byte fragments (%d bytes left)\n",
+		ospace.fragments, ospace.fragstotal, ospace.fragsize, ospace.bytes);
+	return fd;
+}
+
+int pseudo_open(void)
+{
+	int fd;
+	int x = 1;
+	fd = open("/dev/dahdi/pseudo", O_RDWR);
+	if (fd < 0) {
+		fprintf(stderr, "Unable to open pseudo channel: %s\n", strerror(errno));
+		return -1;
+	}
+	if (ioctl(fd, DAHDI_SETLINEAR, &x)) {
+		fprintf(stderr, "Unable to set linear mode: %s\n", strerror(errno));
+		close(fd);
+		return -1;
+	}
+	x = BLOCK_SIZE;
+	if (ioctl(fd, DAHDI_SET_BLOCKSIZE, &x)) {
+		fprintf(stderr, "unable to set sane block size: %s\n", strerror(errno));
+		close(fd);
+		return -1;
+	}
+	return fd;
+}
+
+#define barlen 35
+#define baroptimal 3250
+//define barlevel 200
+#define barlevel ((baroptimal/barlen)*2)
+#define maxlevel (barlen*barlevel)
+
+void draw_barheader()
+{
+	char bar[barlen + 4];
+
+	memset(bar, '-', sizeof(bar));
+	memset(bar, '<', 1);
+	memset(bar + barlen + 2, '>', 1);
+	memset(bar + barlen + 3, '\0', 1);
+
+	memcpy(bar + (barlen / 2), "(RX)", 4);
+	printf("%s", bar);
+
+	memcpy(bar + (barlen / 2), "(TX)", 4);
+	printf(" %s\n", bar);
+}
+
+void draw_bar(int avg, int max)
+{
+	char bar[barlen+5];
+
+	memset(bar, ' ', sizeof(bar));
+
+	max /= barlevel;
+	avg /= barlevel;
+	if (avg > barlen)
+		avg = barlen;
+	if (max > barlen)
+		max = barlen;
+
+	if (avg > 0)
+		memset(bar, '#', avg);
+	if (max > 0)
+		memset(bar + max, '*', 1);
+
+	bar[barlen+1] = '\0';
+	printf("%s", bar);
+	fflush(stdout);
+}
+
+void visualize(short *tx, short *rx, int cnt)
+{
+	int x;
+	float txavg = 0;
+	float rxavg = 0;
+	static int txmax = 0;
+	static int rxmax = 0;
+	static int sametxmax = 0;
+	static int samerxmax = 0;
+	static int txbest = 0;
+	static int rxbest = 0;
+	float ms;
+	static struct timeval last;
+	struct timeval tv;
+
+	gettimeofday(&tv, NULL);
+	ms = (tv.tv_sec - last.tv_sec) * 1000.0 + (tv.tv_usec - last.tv_usec) / 1000.0;
+	for (x = 0; x < cnt; x++) {
+		txavg += abs(tx[x]);
+		rxavg += abs(rx[x]);
+	}
+	txavg = abs(txavg / cnt);
+	rxavg = abs(rxavg / cnt);
+
+	if (txavg > txbest)
+		txbest = txavg;
+	if (rxavg > rxbest)
+		rxbest = rxavg;
+
+	/* Update no more than 10 times a second */
+	if (ms < 100)
+		return;
+
+	/* Save as max levels, if greater */
+	if (txbest > txmax) {
+		txmax = txbest;
+		sametxmax = 0;
+	}
+	if (rxbest > rxmax) {
+		rxmax = rxbest;
+		samerxmax = 0;
+	}
+
+	memcpy(&last, &tv, sizeof(last));
+
+	/* Clear screen */
+	printf("\r ");
+	draw_bar(rxbest, rxmax);
+	printf("   ");
+	draw_bar(txbest, txmax);
+	if (verbose)
+		printf("   Rx: %5d (%5d) Tx: %5d (%5d)", rxbest, rxmax, txbest, txmax);
+	txbest = 0;
+	rxbest = 0;
+
+	/* If we have had the same max hits for x times, clear the values */
+	sametxmax++;
+	samerxmax++;
+	if (sametxmax > 6) {
+		txmax = 0;
+		sametxmax = 0;
+	}
+	if (samerxmax > 6) {
+		rxmax = 0;
+		samerxmax = 0;
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	int afd = -1;
+	int pfd[4] = {-1, -1, -1, -1};
+	short buf_brx[BLOCK_SIZE * 2];
+	short buf_tx[BLOCK_SIZE * 4];
+	short stereobuf[BLOCK_SIZE * 4];
+	int res_brx, res_tx;
+	int visual = 0;
+	int multichannel = 0;
+	int ossoutput = 0;
+	int preecho = 0;
+	int savefile = 0;
+	int stereo_output = 0;
+	int limit = 0;
+	int readcount = 0;
+	int x, chan;
+	struct dahdi_confinfo zc;
+	int opt;
+	extern char *optarg;
+	struct wavheader wavheaders[MAX_OFH]; /* we have one for each potential filehandle */
+	unsigned int bytes_written[MAX_OFH] = {0};
+	int file_is_wav[MAX_OFH] = {0};
+	int i;
+
+	if ((argc < 2) || (atoi(argv[1]) < 1)) {
+		fprintf(stderr, "Usage: dahdi_monitor <channel num> [-v[v]] [-m] [-o] [-l limit] [-f FILE | -s FILE | -r FILE1 -t FILE2] [-F FILE | -S FILE | -R FILE1 -T FILE2]\n");
+		fprintf(stderr, "Options:\n");
+		fprintf(stderr, "        -v: Visual mode.  Implies -m.\n");
+		fprintf(stderr, "        -vv: Visual/Verbose mode.  Implies -m.\n");
+		fprintf(stderr, "        -l LIMIT: Stop after reading LIMIT bytes\n");
+		fprintf(stderr, "        -m: Separate rx/tx streams.\n");
+		fprintf(stderr, "        -o: Output audio via OSS.  Note: Only 'normal' combined rx/tx streams are output via OSS.\n");
+		fprintf(stderr, "        -f FILE: Save combined rx/tx stream to mono FILE. Cannot be used with -m.\n");
+		fprintf(stderr, "        -r FILE: Save rx stream to FILE. Implies -m.\n");
+		fprintf(stderr, "        -t FILE: Save tx stream to FILE. Implies -m.\n");
+		fprintf(stderr, "        -s FILE: Save stereo rx/tx stream to FILE. Implies -m.\n");
+		fprintf(stderr, "        -F FILE: Save combined pre-echocanceled rx/tx stream to FILE. Cannot be used with -m.\n");
+		fprintf(stderr, "        -R FILE: Save pre-echocanceled rx stream to FILE. Implies -m.\n");
+		fprintf(stderr, "        -T FILE: Save pre-echocanceled tx stream to FILE. Implies -m.\n");
+		fprintf(stderr, "        -S FILE: Save pre-echocanceled stereo rx/tx stream to FILE. Implies -m.\n");
+		fprintf(stderr, "Examples:\n");
+		fprintf(stderr, "Save a stream to a file\n");
+		fprintf(stderr, "        dahdi_monitor 1 -f stream.raw\n");
+		fprintf(stderr, "Visualize an rx/tx stream and save them to separate files.\n");
+		fprintf(stderr, "        dahdi_monitor 1 -v -r streamrx.raw -t streamtx.raw\n");
+		fprintf(stderr, "Play a combined rx/tx stream via OSS and save it to a file\n");
+		fprintf(stderr, "        dahdi_monitor 1 -o -f stream.raw\n");
+		fprintf(stderr, "Save a combined normal rx/tx stream and a combined 'preecho' rx/tx stream to files\n");
+		fprintf(stderr, "        dahdi_monitor 1 -f stream.raw -F streampreecho.raw\n");
+		fprintf(stderr, "Save a normal rx/tx stream and a 'preecho' rx/tx stream to separate files\n");
+		fprintf(stderr, "        dahdi_monitor 1 -m -r streamrx.raw -t streamtx.raw -R streampreechorx.raw -T streampreechotx.raw\n");
+		exit(1);
+	}
+
+	chan = atoi(argv[1]);
+
+	while ((opt = getopt(argc, argv, "vmol:f:r:t:s:F:R:T:S:")) != -1) {
+		switch (opt) {
+		case '?':
+			exit(EXIT_FAILURE);
+		case 'v':
+			if (visual)
+				verbose = 1;
+			visual = 1;
+			multichannel = 1;
+			break;
+		case 'm':
+			multichannel = 1;
+			break;
+		case 'o':
+			ossoutput = 1;
+			break;
+		case 'l':
+			if (sscanf(optarg, "%d", &limit) != 1 || limit < 0)
+				limit = 0;
+			fprintf(stderr, "Will stop reading after %d bytes\n", limit);
+			break;
+		case 'f':
+			if (multichannel) {
+				fprintf(stderr, "'%c' mode cannot be used when multichannel mode is enabled.\n", opt);
+				exit(EXIT_FAILURE);
+			}
+			if (ofh[MON_BRX]) {
+				fprintf(stderr, "Cannot specify option '%c' more than once.\n", opt);
+				exit(EXIT_FAILURE);
+			}
+			if ((ofh[MON_BRX] = fopen(optarg, "w")) == NULL) {
+				fprintf(stderr, "Could not open %s for writing: %s\n", optarg, strerror(errno));
+				exit(EXIT_FAILURE);
+			}
+			fprintf(stderr, "Writing combined stream to %s\n", optarg);
+			file_is_wav[MON_BRX] = filename_is_wav(optarg);
+			if (file_is_wav[MON_BRX]) {
+				wavheader_init(&wavheaders[MON_BRX], 1);
+				if (fwrite(&wavheaders[MON_BRX], 1, sizeof(struct wavheader), ofh[MON_BRX]) != sizeof(struct wavheader)) {
+					fprintf(stderr, "Could not write wav header to %s: %s\n", optarg, strerror(errno));
+					exit(EXIT_FAILURE);
+				}
+			}
+			savefile = 1;
+			break;
+		case 'F':
+			if (multichannel) {
+				fprintf(stderr, "'%c' mode cannot be used when multichannel mode is enabled.\n", opt);
+				exit(EXIT_FAILURE);
+			}
+			if (ofh[MON_PRE_BRX]) {
+				fprintf(stderr, "Cannot specify option '%c' more than once.\n", opt);
+				exit(EXIT_FAILURE);
+			}
+			if ((ofh[MON_PRE_BRX] = fopen(optarg, "w")) == NULL) {
+				fprintf(stderr, "Could not open %s for writing: %s\n", optarg, strerror(errno));
+				exit(EXIT_FAILURE);
+			}
+			fprintf(stderr, "Writing pre-echo combined stream to %s\n", optarg);
+			preecho = 1;
+			savefile = 1;
+			break;
+		case 'r':
+			if (!multichannel && ofh[MON_BRX]) {
+				fprintf(stderr, "'%c' mode cannot be used when combined mode is enabled.\n", opt);
+				exit(EXIT_FAILURE);
+			}
+			if (ofh[MON_BRX]) {
+				fprintf(stderr, "Cannot specify option '%c' more than once.\n", opt);
+				exit(EXIT_FAILURE);
+			}
+			if ((ofh[MON_BRX] = fopen(optarg, "w")) == NULL) {
+				fprintf(stderr, "Could not open %s for writing: %s\n", optarg, strerror(errno));
+				exit(EXIT_FAILURE);
+			}
+			fprintf(stderr, "Writing receive stream to %s\n", optarg);
+			file_is_wav[MON_BRX] = filename_is_wav(optarg);
+			if (file_is_wav[MON_BRX]) {
+				wavheader_init(&wavheaders[MON_BRX], 1);
+				if (fwrite(&wavheaders[MON_BRX], 1, sizeof(struct wavheader), ofh[MON_BRX]) != sizeof(struct wavheader)) {
+					fprintf(stderr, "Could not write wav header to %s: %s\n", optarg, strerror(errno));
+					exit(EXIT_FAILURE);
+				}
+			}
+			multichannel = 1;
+			savefile = 1;
+			break;
+		case 'R':
+			if (!multichannel && ofh[MON_PRE_BRX]) {
+				fprintf(stderr, "'%c' mode cannot be used when combined mode is enabled.\n", opt);
+				exit(EXIT_FAILURE);
+			}
+			if (ofh[MON_PRE_BRX]) {
+				fprintf(stderr, "Cannot specify option '%c' more than once.\n", opt);
+				exit(EXIT_FAILURE);
+			}
+			if ((ofh[MON_PRE_BRX] = fopen(optarg, "w")) == NULL) {
+				fprintf(stderr, "Could not open %s for writing: %s\n", optarg, strerror(errno));
+				exit(EXIT_FAILURE);
+			}
+			fprintf(stderr, "Writing pre-echo receive stream to %s\n", optarg);
+			file_is_wav[MON_PRE_BRX] = filename_is_wav(optarg);
+			if (file_is_wav[MON_PRE_BRX]) {
+				wavheader_init(&wavheaders[MON_PRE_BRX], 1);
+				if (fwrite(&wavheaders[MON_PRE_BRX], 1, sizeof(struct wavheader), ofh[MON_PRE_BRX]) != sizeof(struct wavheader)) {
+					fprintf(stderr, "Could not write wav header to %s: %s\n", optarg, strerror(errno));
+					exit(EXIT_FAILURE);
+				}
+			}
+			preecho = 1;
+			multichannel = 1;
+			savefile = 1;
+			break;
+		case 't':
+			if (!multichannel && ofh[MON_BRX]) {
+				fprintf(stderr, "'%c' mode cannot be used when combined mode is enabled.\n", opt);
+				exit(EXIT_FAILURE);
+			}
+			if (ofh[MON_TX]) {
+				fprintf(stderr, "Cannot specify option '%c' more than once.\n", opt);
+				exit(EXIT_FAILURE);
+			}
+			if ((ofh[MON_TX] = fopen(optarg, "w")) == NULL) {
+				fprintf(stderr, "Could not open %s for writing: %s\n", optarg, strerror(errno));
+				exit(EXIT_FAILURE);
+			}
+			fprintf(stderr, "Writing transmit stream to %s\n", optarg);
+			file_is_wav[MON_TX] = filename_is_wav(optarg);
+			if (file_is_wav[MON_TX]) {
+				wavheader_init(&wavheaders[MON_TX], 1);
+				if (fwrite(&wavheaders[MON_TX], 1, sizeof(struct wavheader), ofh[MON_TX]) != sizeof(struct wavheader)) {
+					fprintf(stderr, "Could not write wav header to %s: %s\n", optarg, strerror(errno));
+					exit(EXIT_FAILURE);
+				}
+			}
+			multichannel = 1;
+			savefile = 1;
+			break;
+		case 'T':
+			if (!multichannel && ofh[MON_PRE_BRX]) {
+				fprintf(stderr, "'%c' mode cannot be used when combined mode is enabled.\n", opt);
+				exit(EXIT_FAILURE);
+			}
+			if (ofh[MON_PRE_TX]) {
+				fprintf(stderr, "Cannot specify option '%c' more than once.\n", opt);
+				exit(EXIT_FAILURE);
+			}
+			if ((ofh[MON_PRE_TX] = fopen(optarg, "w")) == NULL) {
+				fprintf(stderr, "Could not open %s for writing: %s\n", optarg, strerror(errno));
+				exit(EXIT_FAILURE);
+			}
+			fprintf(stderr, "Writing pre-echo transmit stream to %s\n", optarg);
+			file_is_wav[MON_PRE_TX] = filename_is_wav(optarg);
+			if (file_is_wav[MON_PRE_TX]) {
+				wavheader_init(&wavheaders[MON_PRE_TX], 1);
+				if (fwrite(&wavheaders[MON_PRE_TX], 1, sizeof(struct wavheader), ofh[MON_PRE_TX]) != sizeof(struct wavheader)) {
+					fprintf(stderr, "Could not write wav header to %s: %s\n", optarg, strerror(errno));
+					exit(EXIT_FAILURE);
+				}
+			}
+			preecho = 1;
+			multichannel = 1;
+			savefile = 1;
+			break;
+		case 's':
+			if (!multichannel && ofh[MON_BRX]) {
+				fprintf(stderr, "'%c' mode cannot be used when combined mode is enabled.\n", opt);
+				exit(EXIT_FAILURE);
+			}
+			if (ofh[MON_STEREO]) {
+				fprintf(stderr, "Cannot specify option '%c' more than once.\n", opt);
+				exit(EXIT_FAILURE);
+			}
+			if ((ofh[MON_STEREO] = fopen(optarg, "w")) == NULL) {
+				fprintf(stderr, "Could not open %s for writing: %s\n", optarg, strerror(errno));
+				exit(EXIT_FAILURE);
+			}
+			fprintf(stderr, "Writing stereo stream to %s\n", optarg);
+			file_is_wav[MON_STEREO] = filename_is_wav(optarg);
+			if (file_is_wav[MON_STEREO]) {
+				wavheader_init(&wavheaders[MON_STEREO], 2);
+				if (fwrite(&wavheaders[MON_STEREO], 1, sizeof(struct wavheader), ofh[MON_STEREO]) != sizeof(struct wavheader)) {
+					fprintf(stderr, "Could not write wav header to %s: %s\n", optarg, strerror(errno));
+					exit(EXIT_FAILURE);
+				}
+			}
+			multichannel = 1;
+			savefile = 1;
+			stereo_output = 1;
+			break;
+		case 'S':
+			if (!multichannel && ofh[MON_PRE_BRX]) {
+				fprintf(stderr, "'%c' mode cannot be used when combined mode is enabled.\n", opt);
+				exit(EXIT_FAILURE);
+			}
+			if (ofh[MON_PRE_STEREO]) {
+				fprintf(stderr, "Cannot specify option '%c' more than once.\n", opt);
+				exit(EXIT_FAILURE);
+			}
+			if ((ofh[MON_PRE_STEREO] = fopen(optarg, "w")) == NULL) {
+				fprintf(stderr, "Could not open %s for writing: %s\n", optarg, strerror(errno));
+				exit(EXIT_FAILURE);
+			}
+			fprintf(stderr, "Writing pre-echo stereo stream to %s\n", optarg);
+			file_is_wav[MON_PRE_STEREO] = filename_is_wav(optarg);
+			if (file_is_wav[MON_PRE_STEREO]) {
+				wavheader_init(&wavheaders[MON_PRE_STEREO], 2);
+				if (fwrite(&wavheaders[MON_PRE_STEREO], 1, sizeof(struct wavheader), ofh[MON_PRE_STEREO]) != sizeof(struct wavheader)) {
+					fprintf(stderr, "Could not write wav header to %s: %s\n", optarg, strerror(errno));
+					exit(EXIT_FAILURE);
+				}
+			}
+			preecho = 1;
+			multichannel = 1;
+			savefile = 1;
+			stereo_output = 1;
+			break;
+		}
+	}
+
+	if (ossoutput) {
+		if (multichannel) {
+			printf("Multi-channel audio is enabled.  OSS output will be disabled.\n");
+			ossoutput = 0;
+		} else {
+			/* Open audio */
+			if ((afd = audio_open()) < 0) {
+				printf("Cannot open audio ...\n");
+				ossoutput = 0;
+			}
+		}
+	}
+	if (!ossoutput && !multichannel && !savefile) {
+		fprintf(stderr, "Nothing to do with the stream(s) ...\n");
+		exit(1);
+	}
+
+	/* Open Pseudo device */
+	if ((pfd[MON_BRX] = pseudo_open()) < 0)
+		exit(1);
+	if (multichannel && ((pfd[MON_TX] = pseudo_open()) < 0))
+		exit(1);
+	if (preecho) {
+		if ((pfd[MON_PRE_BRX] = pseudo_open()) < 0)
+			exit(1);
+		if (multichannel && ((pfd[MON_PRE_TX] = pseudo_open()) < 0))
+			exit(1);
+	}
+	/* Conference them */
+	if (multichannel) {
+		memset(&zc, 0, sizeof(zc));
+		zc.chan = 0;
+		zc.confno = chan;
+		/* Two pseudo's, one for tx, one for rx */
+		zc.confmode = DAHDI_CONF_MONITOR;
+		if (ioctl(pfd[MON_BRX], DAHDI_SETCONF, &zc) < 0) {
+			fprintf(stderr, "Unable to monitor: %s\n", strerror(errno));
+			exit(1);
+		}
+		memset(&zc, 0, sizeof(zc));
+		zc.chan = 0;
+		zc.confno = chan;
+		zc.confmode = DAHDI_CONF_MONITORTX;
+		if (ioctl(pfd[MON_TX], DAHDI_SETCONF, &zc) < 0) {
+			fprintf(stderr, "Unable to monitor: %s\n", strerror(errno));
+			exit(1);
+		}
+		if (preecho) {
+			memset(&zc, 0, sizeof(zc));
+			zc.chan = 0;
+			zc.confno = chan;
+			/* Two pseudo's, one for tx, one for rx */
+			zc.confmode = DAHDI_CONF_MONITOR_RX_PREECHO;
+			if (ioctl(pfd[MON_PRE_BRX], DAHDI_SETCONF, &zc) < 0) {
+				fprintf(stderr, "Unable to monitor: %s\n", strerror(errno));
+				exit(1);
+			}
+			memset(&zc, 0, sizeof(zc));
+			zc.chan = 0;
+			zc.confno = chan;
+			zc.confmode = DAHDI_CONF_MONITOR_TX_PREECHO;
+			if (ioctl(pfd[MON_PRE_TX], DAHDI_SETCONF, &zc) < 0) {
+				fprintf(stderr, "Unable to monitor: %s\n", strerror(errno));
+				exit(1);
+			}
+		}
+	} else {
+		memset(&zc, 0, sizeof(zc));
+		zc.chan = 0;
+		zc.confno = chan;
+		zc.confmode = DAHDI_CONF_MONITORBOTH;
+		if (ioctl(pfd[MON_BRX], DAHDI_SETCONF, &zc) < 0) {
+			fprintf(stderr, "Unable to monitor: %s\n", strerror(errno));
+			exit(1);
+		}
+		if (preecho) {
+			memset(&zc, 0, sizeof(zc));
+			zc.chan = 0;
+			zc.confno = chan;
+			zc.confmode = DAHDI_CONF_MONITORBOTH_PREECHO;
+			if (ioctl(pfd[MON_PRE_BRX], DAHDI_SETCONF, &zc) < 0) {
+				fprintf(stderr, "Unable to monitor: %s\n", strerror(errno));
+				exit(1);
+			}
+		}
+	}
+	if (signal(SIGINT, cleanup_and_exit) == SIG_ERR) {
+		fprintf(stderr, "Error registering signal handler: %s\n", strerror(errno));
+	}
+	if (visual) {
+		printf("\nVisual Audio Levels.\n");
+		printf("--------------------\n");
+		printf(" Use chan_dahdi.conf file to adjust the gains if needed.\n\n");
+		printf("( # = Audio Level  * = Max Audio Hit )\n");
+		draw_barheader();
+	}
+	/* Now, copy from pseudo to audio */
+	while (run) {
+		res_brx = read(pfd[MON_BRX], buf_brx, sizeof(buf_brx));
+		if (res_brx < 1)
+			break;
+		readcount += res_brx;
+		if (ofh[MON_BRX])
+			bytes_written[MON_BRX] += fwrite(buf_brx, 1, res_brx, ofh[MON_BRX]);
+
+		if (multichannel) {
+			res_tx = read(pfd[MON_TX], buf_tx, res_brx);
+			if (res_tx < 1)
+				break;
+			if (ofh[MON_TX])
+				bytes_written[MON_TX] += fwrite(buf_tx, 1, res_tx, ofh[MON_TX]);
+
+			if (stereo_output && ofh[MON_STEREO]) {
+				for (x = 0; x < res_tx; x++) {
+					stereobuf[x*2] = buf_brx[x];
+					stereobuf[x*2+1] = buf_tx[x];
+				}
+				bytes_written[MON_STEREO] += fwrite(stereobuf, 1, res_tx*2, ofh[MON_STEREO]);
+			}
+
+			if (visual) {
+				if (res_brx == res_tx)
+					visualize((short *)buf_tx, (short *)buf_brx, res_brx/2);
+				else
+					printf("Huh?  res_tx = %d, res_brx = %d?\n", res_tx, res_brx);
+			}
+		}
+
+		if (preecho) {
+			res_brx = read(pfd[MON_PRE_BRX], buf_brx, sizeof(buf_brx));
+			if (res_brx < 1)
+				break;
+			if (ofh[MON_PRE_BRX])
+				bytes_written[MON_PRE_BRX] += fwrite(buf_brx, 1, res_brx, ofh[MON_PRE_BRX]);
+
+			if (multichannel) {
+				res_tx = read(pfd[MON_PRE_TX], buf_tx, res_brx);
+				if (res_tx < 1)
+					break;
+				if (ofh[MON_PRE_TX])
+					bytes_written[MON_PRE_TX] += fwrite(buf_tx, 1, res_tx, ofh[MON_PRE_TX]);
+
+				if (stereo_output && ofh[MON_PRE_STEREO]) {
+					for (x = 0; x < res_brx; x++) {
+						stereobuf[x*2] = buf_brx[x];
+						stereobuf[x*2+1] = buf_tx[x];
+					}
+					bytes_written[MON_PRE_STEREO] += fwrite(stereobuf, 1, res_brx * 2, ofh[MON_PRE_STEREO]);
+				}
+			}
+		}
+
+		if (ossoutput && afd) {
+			if (stereo) {
+				for (x = 0; x < res_brx; x++) {
+					buf_tx[x << 1] = buf_tx[(x << 1) + 1] = buf_brx[x];
+				}
+				x = write(afd, buf_tx, res_brx << 1);
+			} else {
+				x = write(afd, buf_brx, res_brx);
+			}
+		}
+
+		if (limit && readcount >= limit) {
+			/* bail if we've read too much */
+			break;
+		}
+	}
+	/* write filesize info */
+	for (i = 0; i < MAX_OFH; i++) {
+		if (NULL == ofh[i])
+			continue;
+		if (!(file_is_wav[i]))
+			continue;
+
+		rewind(ofh[i]);
+
+		if (fread(&wavheaders[i], 1, sizeof(struct wavheader), ofh[i]) != sizeof(struct wavheader)) {
+			fprintf(stderr, "Failed to read in a full wav header.  Expect bad things.\n");
+		}
+
+		wavheaders[i].riff_chunk_size = (bytes_written[i]) + sizeof(struct wavheader) - 8; /* filesize - 8 */
+		wavheaders[i].data_data_size = bytes_written[i];
+
+		rewind(ofh[i]);
+		if (fwrite(&wavheaders[i], 1, sizeof(struct wavheader), ofh[i]) != sizeof(struct wavheader)) {
+			fprintf(stderr, "Failed to write out a full wav header.\n");
+		}
+		fclose(ofh[i]);
+	}
+	printf("done cleaning up ... exiting.\n");
+	return 0;
+}
diff --git a/dahdi_scan.c b/dahdi_scan.c
new file mode 100644
index 0000000..582f44d
--- /dev/null
+++ b/dahdi_scan.c
@@ -0,0 +1,205 @@
+/*
+ * Scan and output information about DAHDI spans and ports.
+ * 
+ * Written by Brandon Kruse <bkruse at digium.com>
+ * and Kevin P. Fleming <kpfleming at digium.com>
+ * Copyright (C) 2007 Digium, Inc.
+ *
+ * Based on zttool written by Mark Spencer <markster at digium.com>
+ *
+ * All rights reserved.
+ *
+ */
+
+/*
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2 as published by the
+ * Free Software Foundation. See the LICENSE file included with
+ * this program for more details.
+ */
+
+#include <stdio.h> 
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <dahdi/user.h>
+
+#include "dahdi_tools_version.h"
+
+static inline int is_digital_span(struct dahdi_spaninfo *s)
+{
+	return (s->linecompat > 0);
+}
+
+int main(int argc, char *argv[])
+{
+	int ctl;
+	int x, y, z;
+	struct dahdi_params params;
+	unsigned int basechan = 1;
+	struct dahdi_spaninfo s;
+	char buf[100];
+	char alarms[50];
+	int filter_count = 0;
+	int span_filter[DAHDI_MAX_SPANS];
+
+	if ((ctl = open("/dev/dahdi/ctl", O_RDWR)) < 0) {
+		fprintf(stderr, "Unable to open /dev/dahdi/ctl: %s\n", strerror(errno));
+		exit(1);
+	}
+
+	for (x = 1; x < argc && filter_count < DAHDI_MAX_SPANS; x++) {
+		int s = atoi(argv[x]);
+		if (s > 0) {
+			span_filter[filter_count++] = s;
+		}
+	}
+
+	for (x = 1; x < DAHDI_MAX_SPANS; x++) {
+
+		memset(&s, 0, sizeof(s));
+		s.spanno = x;
+		if (ioctl(ctl, DAHDI_SPANSTAT, &s))
+			continue;
+
+		if (filter_count > 0) {
+			int match = 0;
+			for (z = 0; z < filter_count; z++) {
+				if (x == span_filter[z]) {
+					match = 1;
+					break;
+				}
+			}
+			if (!match) {
+				basechan += s.totalchans;
+				continue;
+			}
+		}
+
+		alarms[0] = '\0';
+		if (s.alarms) {
+			if (s.alarms & DAHDI_ALARM_BLUE)
+				strcat(alarms,"BLU/");
+			if (s.alarms & DAHDI_ALARM_YELLOW)
+				strcat(alarms, "YEL/");
+			if (s.alarms & DAHDI_ALARM_RED) {
+				strcat(alarms, "RED/");
+#ifdef DAHDI_ALARM_LFA
+				if (s.alarms & DAHDI_ALARM_LFA)
+					strcat(alarms, "LFA/");
+				if (s.alarms & DAHDI_ALARM_LMFA)
+					strcat(alarms, "LMFA/");
+#endif /* ifdef DAHDI_ALARM_LFA */
+			}
+			if (s.alarms & DAHDI_ALARM_LOOPBACK)
+				strcat(alarms,"LB/");
+			if (s.alarms & DAHDI_ALARM_RECOVER)
+				strcat(alarms,"REC/");
+			if (s.alarms & DAHDI_ALARM_NOTOPEN)
+				strcat(alarms, "NOP/");
+			if (!strlen(alarms))
+				strcat(alarms, "UUU/");
+			if (strlen(alarms)) {
+				/* Strip trailing / */
+				alarms[strlen(alarms)-1]='\0';
+			}
+		} else {
+			if (s.numchans)
+				strcpy(alarms, "OK");
+			else
+				strcpy(alarms, "UNCONFIGURED");
+		}
+
+		fprintf(stdout, "[%d]\n", x);
+		fprintf(stdout, "active=yes\n");
+		fprintf(stdout, "alarms=%s\n", alarms);
+		fprintf(stdout, "description=%s\n", s.desc);
+		fprintf(stdout, "name=%s\n", s.name);
+		fprintf(stdout, "manufacturer=%s\n", s.manufacturer);
+		fprintf(stdout, "devicetype=%s\n", s.devicetype);
+		fprintf(stdout, "location=%s\n", s.location);
+		fprintf(stdout, "basechan=%d\n", basechan);
+		fprintf(stdout, "totchans=%d\n", s.totalchans);
+		fprintf(stdout, "irq=%d\n", s.irq);
+		y = basechan;
+		memset(&params, 0, sizeof(params));
+		params.channo = y;
+		if (ioctl(ctl, DAHDI_GET_PARAMS, &params)) {
+			basechan += s.totalchans;
+			continue;
+		}
+
+		if (is_digital_span(&s)) {
+			/* this is a digital span */
+			fprintf(stdout, "type=digital-%s\n", s.spantype);
+			fprintf(stdout, "syncsrc=%d\n", s.syncsrc);
+			fprintf(stdout, "lbo=%s\n", s.lboname);
+			fprintf(stdout, "coding_opts=");
+			buf[0] = '\0';
+			if (s.linecompat & DAHDI_CONFIG_B8ZS) strcat(buf, "B8ZS,");
+			if (s.linecompat & DAHDI_CONFIG_AMI) strcat(buf, "AMI,");
+			if (s.linecompat & DAHDI_CONFIG_HDB3) strcat(buf, "HDB3,");
+			buf[strlen(buf) - 1] = '\0';
+			fprintf(stdout, "%s\n", buf);
+			fprintf(stdout, "framing_opts=");
+			buf[0] = '\0';
+			if (s.linecompat & DAHDI_CONFIG_ESF) strcat(buf, "ESF,");
+			if (s.linecompat & DAHDI_CONFIG_D4) strcat(buf, "D4,");
+			if (s.linecompat & DAHDI_CONFIG_CCS) strcat(buf, "CCS,");
+			if (s.linecompat & DAHDI_CONFIG_CRC4) strcat(buf, "CRC4,");
+			buf[strlen(buf) - 1] = '\0';
+			fprintf(stdout, "%s\n", buf);
+			fprintf(stdout, "coding=");
+			if (s.lineconfig & DAHDI_CONFIG_B8ZS) fprintf(stdout, "B8ZS");
+			else if (s.lineconfig & DAHDI_CONFIG_AMI) fprintf(stdout, "AMI");
+			else if (s.lineconfig & DAHDI_CONFIG_HDB3) fprintf(stdout, "HDB3");
+			fprintf(stdout, "\n");
+			fprintf(stdout, "framing=");
+			if (s.lineconfig & DAHDI_CONFIG_ESF) fprintf(stdout, "ESF");
+			else if (s.lineconfig & DAHDI_CONFIG_D4) fprintf(stdout, "D4");
+			else if (s.lineconfig & DAHDI_CONFIG_CCS) fprintf(stdout, "CCS");
+			else if (s.lineconfig & DAHDI_CONFIG_CRC4) fprintf(stdout, "/CRC4");
+			fprintf(stdout, "\n");
+		} else {
+			/* this is an analog span */
+			fprintf(stdout, "type=analog\n");
+			for (y = basechan; y < (basechan + s.totalchans); y++) {
+				memset(&params, 0, sizeof(params));
+				params.channo = y;
+				if (ioctl(ctl, DAHDI_GET_PARAMS, &params)) {
+					fprintf(stdout, "port=%d,unknown\n", y);
+					continue;
+				};
+				fprintf(stdout, "port=%d,", y);
+				switch (params.sigcap & (__DAHDI_SIG_FXO | __DAHDI_SIG_FXS)) {
+				case __DAHDI_SIG_FXO:
+					fprintf(stdout, "FXS");
+					break;
+				case __DAHDI_SIG_FXS:
+					fprintf(stdout, "FXO");
+					break;
+				default:
+					fprintf(stdout, "none");
+				}
+				if (params.sigcap & DAHDI_SIG_BROKEN)
+					fprintf(stdout, " FAILED");
+				fprintf(stdout, "\n");
+			}
+		}
+	  
+		basechan += s.totalchans;
+	}
+
+	exit(0);
+}
diff --git a/dahdi_speed.c b/dahdi_speed.c
new file mode 100644
index 0000000..75bfa86
--- /dev/null
+++ b/dahdi_speed.c
@@ -0,0 +1,65 @@
+/*
+ * Written by Mark Spencer <markster at digium.com>
+ * Based on previous works, designs, and architectures conceived and
+ * written by Jim Dixon <jim at lambdatel.com>.
+ *
+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
+ * Copyright (C) 2001-2008 Digium, Inc.
+ *
+ * All rights reserved.
+ *
+ * Primary Author: Mark Spencer <markster at digium.com>
+ * Radio Support by Jim Dixon <jim at lambdatel.com>
+ */
+
+/*
+ * 
+ * Generic speed test -- Run an infinite loop and
+ * see how high we can count (in 5 seconds).  You 
+ * can use this to measure how much CPU DAHDI REALLY 
+ * is taking.
+ * 
+ * MUST BE COMPILED WITHOUT OPTIMIZATION
+ *
+ */
+
+/*
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2 as published by the
+ * Free Software Foundation. See the LICENSE file included with
+ * this program for more details.
+ */
+
+#include <stdio.h>
+#include <sys/signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "dahdi_tools_version.h"
+
+static long count=0;
+
+static void alm(int sig)
+{
+	printf("Count: %ld\n", count);
+	exit(0);
+}
+
+
+int main(int argc, char *argv[])
+{
+	int a=0,b=0,c;
+	signal(SIGALRM, alm);
+	alarm(5);
+	for (;;) {
+		for (c=0;c<1000;c++)
+			a = a * b;
+		count++;
+	}
+}
diff --git a/dahdi_test.c b/dahdi_test.c
new file mode 100644
index 0000000..ed71443
--- /dev/null
+++ b/dahdi_test.c
@@ -0,0 +1,164 @@
+/*
+ * Written by Mark Spencer <markster at digium.com>
+ * Based on previous works, designs, and architectures conceived and
+ * written by Jim Dixon <jim at lambdatel.com>.
+ *
+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
+ * Copyright (C) 2001-2008 Digium, Inc.
+ *
+ * All rights reserved.
+ *
+ * Primary Author: Mark Spencer <markster at digium.com>
+ * Radio Support by Jim Dixon <jim at lambdatel.com>
+ */
+
+/*
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2 as published by the
+ * Free Software Foundation. See the LICENSE file included with
+ * this program for more details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/signal.h>
+#include <math.h>
+#include <getopt.h>
+
+#include "dahdi_tools_version.h"
+
+#define SIZE 8000
+
+static int pass = 0;
+static float best = 0.0;
+static float worst = 100.0;
+static double total = 0.0;
+static double delay_total = 0.0;
+
+void hup_handler(int sig)
+{
+	printf("\n--- Results after %d passes ---\n", pass);
+	printf("Best: %.3f -- Worst: %.3f -- Average: %f, Difference: %f\n", 
+			best, worst, pass ? total/pass : 100.00, pass ? delay_total/pass : 100);
+	exit(0);
+}
+
+static void usage(char *argv0)
+{
+	char *c;
+	c = strrchr(argv0, '/');
+	if (!c)
+		c = argv0;
+	else
+		c++;
+	fprintf(stderr, 
+		"Usage: %s [-c COUNT] [-v]\n"
+		"    Valid options are:\n"
+		"  -c COUNT    Run just COUNT cycles (otherwise: forever).\n"
+		"  -v          More verbose output.\n"
+		"  -h          This help text.\n"
+	, c);
+}
+
+int main(int argc, char *argv[])
+{
+	int fd;
+	int res;
+	int c;
+	int count = 0;
+	int seconds = 0;
+	int curarg = 1;
+	int verbose = 0;
+	char buf[8192];
+	float score;
+	float ms;
+	struct timeval start, now;
+	fd = open("/dev/dahdi/pseudo", O_RDWR);
+	if (fd < 0) {
+		fprintf(stderr, "Unable to open dahdi interface: %s\n", strerror(errno));
+		exit(1);
+	}
+	
+	while ((c = getopt(argc, argv, "c:hv")) != -1) {
+		switch(c) {
+		case 'c':
+			seconds = atoi(optarg);
+			break;
+		case 'h':
+			usage(argv[0]);
+			exit(0);
+			break;
+		case '?':
+			usage(argv[0]);
+			exit(1);
+			break;
+		case 'v':
+			verbose++;
+			break;
+		}
+	}
+	while (curarg < argc) {
+		if (!strcasecmp(argv[curarg], "-v"))
+			verbose++;
+		if (!strcasecmp(argv[curarg], "-c") && argc > curarg)
+			seconds = atoi(argv[curarg + 1]);
+		curarg++;
+	}
+	printf("Opened pseudo dahdi interface, measuring accuracy...\n");
+	signal(SIGHUP, hup_handler);
+	signal(SIGINT, hup_handler);
+	signal(SIGALRM, hup_handler);
+	/* Flush input buffer */
+	for (count = 0; count < 4; count++)
+		res = read(fd, buf, sizeof(buf));
+	count = 0;
+	ms = 0; /* Makes the compiler happy */
+	if (seconds > 0)
+		alarm(seconds + 1); /* This will give 'seconds' cycles */
+	for (;;) {
+		if (count == 0)
+			ms = 0;
+		gettimeofday(&start, NULL);
+		res = read(fd, buf, sizeof(buf));
+		if (res < 0) {
+			fprintf(stderr, "Failed to read from pseudo interface: %s\n", strerror(errno));
+			exit(1);
+		}
+		count += res;
+		gettimeofday(&now, NULL);
+		ms += (now.tv_sec - start.tv_sec) * 8000;
+		ms += (now.tv_usec - start.tv_usec) / 125.0;
+		if (count >= SIZE) {
+			double percent = 100.0 * (count - ms) / count;
+			if (verbose) {
+				printf("\n%d samples in %0.3f system clock sample intervals (%.3f%%)", 
+						count, ms, 100 - percent);
+			} else if (pass > 0 && (pass % 8) == 0) {
+				printf("\n");
+			}
+			score = 100.0 - fabs(percent);
+			if (score > best)
+				best = score;
+			if (score < worst)
+				worst = score;
+			if (!verbose)
+				printf("%.3f%% ", score);
+			total += score;
+			delay_total += 100 - percent;
+			fflush(stdout);
+			count = 0;
+			pass++;
+		}
+	}
+}
diff --git a/dahdi_tool.c b/dahdi_tool.c
new file mode 100644
index 0000000..a814931
--- /dev/null
+++ b/dahdi_tool.c
@@ -0,0 +1,541 @@
+/*
+ * Configuration program for Zapata Telephony Interface
+ *
+ * Written by Mark Spencer <markster at digium.com>
+ * Based on previous works, designs, and architectures conceived and
+ * written by Jim Dixon <jim at lambdatel.com>.
+ *
+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
+ * Copyright (C) 2001-2010 Digium, Inc.
+ *
+ * All rights reserved.
+ *
+ */
+
+/*
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2 as published by the
+ * Free Software Foundation. See the LICENSE file included with
+ * this program for more details.
+ */
+
+/*** MODULEINFO
+	<depend>newt</depend>
+ ***/
+
+#include <stdio.h> 
+#include <getopt.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <newt.h>
+
+#include <dahdi/user.h>
+#include "dahdi_tools_version.h"
+
+static int ctl = -1;
+static int span_max_chan_pos;
+
+static struct dahdi_spaninfo s[DAHDI_MAX_SPANS];
+
+static char *dahdi_txlevelnames[] = {
+"0 db (CSU)/0-133 feet (DSX-1)",
+"133-266 feet (DSX-1)",
+"266-399 feet (DSX-1)",
+"399-533 feet (DSX-1)",
+"533-655 feet (DSX-1)",
+"-7.5db (CSU)",
+"-15db (CSU)",
+"-22.5db (CSU)"
+} ;
+
+static char *alarmstr(int span)
+{
+	static char alarms[80];
+	strcpy(alarms, "");
+	if (s[span].alarms > 0) {
+		if (s[span].alarms & DAHDI_ALARM_BLUE)
+			strcat(alarms,"Blue Alarm/");
+		if (s[span].alarms & DAHDI_ALARM_YELLOW)
+			strcat(alarms, "Yellow Alarm/");
+		if (s[span].alarms & DAHDI_ALARM_RED)
+			strcat(alarms, "Red Alarm/");
+		if (s[span].alarms & DAHDI_ALARM_LOOPBACK)
+			strcat(alarms,"Loopback/");
+		if (s[span].alarms & DAHDI_ALARM_RECOVER)
+			strcat(alarms,"Recovering/");
+		if (s[span].alarms & DAHDI_ALARM_NOTOPEN)
+			strcat(alarms, "Not Open/");
+		if (!strlen(alarms))
+			strcat(alarms, "<unknown>/");
+		if (strlen(alarms)) {
+			/* Strip trailing / */
+			alarms[strlen(alarms)-1]='\0';
+		}
+	} else
+		strcpy(alarms, "No alarms.");
+	return alarms;
+}
+
+static char *getalarms(int span, int err)
+{
+	int res;
+	static char tmp[256];
+	char alarms[50];
+	s[span].spanno = span;
+	res = ioctl(ctl, DAHDI_SPANSTAT, &s[span]);
+	if (res) {
+		if (err)
+			fprintf(stderr, "Unable to get span info on span %d: %s\n", span, strerror(errno)); 
+		return NULL;
+	}
+	strcpy(alarms, "");
+	if (s[span].alarms > 0) {
+		if (s[span].alarms & DAHDI_ALARM_BLUE)
+			strcat(alarms,"BLU/");
+		if (s[span].alarms & DAHDI_ALARM_YELLOW)
+			strcat(alarms, "YEL/");
+		if (s[span].alarms & DAHDI_ALARM_RED)
+			strcat(alarms, "RED/");
+		if (s[span].alarms & DAHDI_ALARM_LOOPBACK)
+			strcat(alarms,"LB/");
+		if (s[span].alarms & DAHDI_ALARM_RECOVER)
+			strcat(alarms,"REC/");
+		if (s[span].alarms & DAHDI_ALARM_NOTOPEN)
+			strcat(alarms, "NOP/");
+		if (!strlen(alarms))
+			strcat(alarms, "UUU/");
+		if (strlen(alarms)) {
+			/* Strip trailing / */
+			alarms[strlen(alarms)-1]='\0';
+		}
+	} else {
+		if (s[span].numchans)
+			strcpy(alarms, "OK");
+		else
+			strcpy(alarms, "UNCONFIGURED");
+	}
+		
+	snprintf(tmp, sizeof(tmp), "%-15s %s", alarms, s[span].desc);
+	return tmp;
+}
+
+static void add_cards(newtComponent spans)
+{
+	int x;
+	char *s;
+	void *prev=NULL;
+	
+	if (spans)
+		prev = newtListboxGetCurrent(spans);
+	newtListboxClear(spans);
+	for (x=0;x<DAHDI_MAX_SPANS;x++) {
+		s = getalarms(x, 0);
+		if (s && spans) {
+			/* Found one! */
+			newtListboxAppendEntry(spans, s, (void *)(long)x);
+		}
+	}
+	if (spans)
+		newtListboxSetCurrentByKey(spans, prev);
+	
+}
+
+static void sel_callback(newtComponent c, void *cbdata)
+{
+	int span;
+	char info[256];
+	char info2[256];
+	cbdata = newtListboxGetCurrent(c);
+	if (cbdata) {
+		span = (long)(cbdata);
+		snprintf(info, sizeof (info), "Span %d: %d total channels, %d configured", span, s[span].totalchans, s[span].numchans);
+		snprintf(info2, sizeof(info2), "%-59s F1=Details F10=Quit", info);
+	} else {
+		span = -1;
+		strcpy(info, "There are no DAHDI spans on this system.");
+		snprintf(info2, sizeof(info2), "%-59s            F10=Quit", info);
+	}
+	newtPopHelpLine();
+	newtPushHelpLine(info2);
+}
+
+static void show_bits(int span, newtComponent bitbox, newtComponent inuse, newtComponent levels, newtComponent bpvcount,
+						newtComponent alarms, newtComponent syncsrc, newtComponent irqmisses)
+{
+	struct dahdi_params zp;
+	int x;
+	int res;
+	char c;
+	char tabits[80];
+	char tbbits[80];
+	char tcbits[80];
+	char tdbits[80];
+	char rabits[80];
+	char rbbits[80];
+	char rcbits[80];
+	char rdbits[80];
+	char tmp[1024];
+	
+	int use = 0;
+	
+	memset(tabits,0, sizeof(tabits));
+	memset(tbbits,0, sizeof(tbbits));
+	memset(rabits,0, sizeof(rabits));
+	memset(rbbits,0, sizeof(rbbits));
+	memset(tcbits,0, sizeof(tcbits));
+	memset(tdbits,0, sizeof(tdbits));
+	memset(rcbits,0, sizeof(rcbits));
+	memset(rdbits,0, sizeof(rdbits));
+	memset(tabits,32, span_max_chan_pos);
+	memset(tbbits,32, span_max_chan_pos);
+	memset(rabits,32, span_max_chan_pos);
+	memset(rbbits,32, span_max_chan_pos);
+	memset(tcbits,32, span_max_chan_pos);
+	memset(tdbits,32, span_max_chan_pos);
+	memset(rcbits,32, span_max_chan_pos);
+	memset(rdbits,32, span_max_chan_pos);
+	
+	for (x=0;x<DAHDI_MAX_CHANNELS;x++) {
+		memset(&zp, 0, sizeof(zp));
+		zp.channo = x;
+		res = ioctl(ctl, DAHDI_GET_PARAMS, &zp);
+		if (!res) {
+			if (zp.spanno == span) {
+				if (zp.sigtype && (zp.rxbits > -1)) {
+					if (zp.rxbits & DAHDI_ABIT)
+						rabits[zp.chanpos - 1] = '1';
+					else
+						rabits[zp.chanpos - 1] = '0';
+					if (zp.rxbits & DAHDI_BBIT)
+						rbbits[zp.chanpos - 1] = '1';
+					else
+						rbbits[zp.chanpos - 1] = '0';
+
+					if (zp.rxbits & DAHDI_CBIT)
+						rcbits[zp.chanpos - 1] = '1';
+					else
+						rcbits[zp.chanpos - 1] = '0';
+					if (zp.rxbits & DAHDI_DBIT)
+						rdbits[zp.chanpos - 1] = '1';
+					else
+						rdbits[zp.chanpos - 1] = '0';
+
+					if (zp.txbits & DAHDI_ABIT)
+						tabits[zp.chanpos - 1] = '1';
+					else
+						tabits[zp.chanpos - 1] = '0';
+					if (zp.txbits & DAHDI_BBIT)
+						tbbits[zp.chanpos - 1] = '1';
+					else
+						tbbits[zp.chanpos - 1] = '0';
+					if (zp.txbits & DAHDI_CBIT)
+						tcbits[zp.chanpos - 1] = '1';
+					else
+						tcbits[zp.chanpos - 1] = '0';
+					if (zp.txbits & DAHDI_DBIT)
+						tdbits[zp.chanpos - 1] = '1';
+					else
+						tdbits[zp.chanpos - 1] = '0';
+				} else {
+					c = '-';
+					if (!zp.sigtype)
+						c = ' ';
+					tabits[zp.chanpos - 1] = c;
+					tbbits[zp.chanpos - 1] = c;
+					tcbits[zp.chanpos - 1] = c;
+					tdbits[zp.chanpos - 1] = c;
+					rabits[zp.chanpos - 1] = c;
+					rbbits[zp.chanpos - 1] = c;
+					rcbits[zp.chanpos - 1] = c;
+					rdbits[zp.chanpos - 1] = c;
+				}
+				if (zp.rxisoffhook)
+					use++;
+			}
+		}
+	}
+	snprintf(tmp, sizeof(tmp), "%s\n%s\n%s\n%s\n\n%s\n%s\n%s\n%s", tabits, tbbits,tcbits,tdbits,rabits,rbbits,rcbits,rdbits);
+	newtTextboxSetText(bitbox, tmp);	
+	sprintf(tmp, "%3d/%3d/%3d", s[span].totalchans, s[span].numchans, use);
+	newtTextboxSetText(inuse, tmp);
+	sprintf(tmp, "%s/", dahdi_txlevelnames[s[span].txlevel]);
+	strcat(tmp, dahdi_txlevelnames[s[span].rxlevel]);
+	sprintf(tmp, "%3d/%3d", s[span].txlevel, s[span].rxlevel);
+	newtTextboxSetText(levels, tmp);
+	sprintf(tmp, "%7d", s[span].bpvcount);
+	newtTextboxSetText(bpvcount, tmp);
+	sprintf(tmp, "%7d", s[span].irqmisses);
+	newtTextboxSetText(irqmisses, tmp);
+	newtTextboxSetText(alarms, alarmstr(span));	
+	if (s[span].syncsrc > 0)
+		strcpy(tmp, s[s[span].syncsrc].desc);
+	else
+		strcpy(tmp, "Internally clocked");
+	newtTextboxSetText(syncsrc, tmp);
+	
+	
+}
+
+static newtComponent spans;
+static void show_span(int span)
+{
+	newtComponent form;
+	newtComponent back;
+	newtComponent label;
+	newtComponent bitbox;
+	newtComponent inuse;
+	newtComponent levels;
+	newtComponent bpvcount;
+	newtComponent alarms;
+	newtComponent syncsrc;
+	newtComponent irqmisses;
+	
+	char s1[] = "         1111111111222222222233";
+	char s2[] = "1234567890123456789012345678901";
+	int x;
+	struct newtExitStruct es;
+
+	void *ss;
+	char info2[256];
+
+	if (span < 0) {
+		/* Display info on a span */
+		ss = newtListboxGetCurrent(spans);
+		if (ss) {
+			span = (long)(ss);
+		}
+	}
+
+	snprintf(info2, sizeof(info2), "%-59s            F10=Back", s[span].desc);
+	newtCenteredWindow(60,20, s[span].desc);
+	newtPushHelpLine(info2);
+
+	back = newtButton(48,8,"Back");
+	form = newtForm(NULL, NULL, 0);
+
+	newtFormAddComponents(form, back, NULL);
+
+	span_max_chan_pos = s[span].totalchans;
+	for (x=0;x<DAHDI_MAX_CHANNELS;x++) {
+		struct dahdi_params zp;
+		int res;
+		memset(&zp, 0, sizeof(zp));
+		zp.channo = x;
+		res = ioctl(ctl, DAHDI_GET_PARAMS, &zp);
+		if (!res && zp.spanno == span && zp.chanpos > span_max_chan_pos )
+			span_max_chan_pos = zp.chanpos;
+	}
+
+	if (span_max_chan_pos > 32)
+		span_max_chan_pos = 32;
+
+	s1[span_max_chan_pos] = '\0';
+	s2[span_max_chan_pos] = '\0';
+
+	bitbox = newtTextbox(8,10,span_max_chan_pos,9,0);
+	newtFormAddComponent(form, bitbox);
+
+	label = newtLabel(8,8,s1);
+	newtFormAddComponent(form, label);
+
+	label = newtLabel(8,9,s2);
+	newtFormAddComponent(form, label);
+
+	newtFormAddHotKey(form, NEWT_KEY_F10);
+	newtFormSetTimer(form, 200);
+
+	label = newtLabel(4,10,"TxA");
+	newtFormAddComponent(form, label);
+
+	label = newtLabel(4,11,"TxB");
+	newtFormAddComponent(form, label);
+
+	label = newtLabel(4,12,"TxC");
+	newtFormAddComponent(form, label);
+
+	label = newtLabel(4,13,"TxD");
+	newtFormAddComponent(form, label);
+
+	label = newtLabel(4,15,"RxA");
+	newtFormAddComponent(form, label);
+
+	label = newtLabel(4,16,"RxB");
+	newtFormAddComponent(form, label);
+
+	label = newtLabel(4,17,"RxC");
+	newtFormAddComponent(form, label);
+
+	label = newtLabel(4,18,"RxD");
+	newtFormAddComponent(form, label);
+	
+	
+	label = newtLabel(4,7,"Total/Conf/Act: ");
+	newtFormAddComponent(form, label);
+	
+	inuse = newtTextbox(24,7,12,1,0);
+	newtFormAddComponent(form, inuse);
+
+	label = newtLabel(4,6,"Tx/Rx Levels: ");
+	newtFormAddComponent(form, label);
+
+	levels = newtTextbox(24,6,30,1,0);
+	newtFormAddComponent(form, levels);
+	
+	label = newtLabel(4,5,"Bipolar Viol: ");
+	newtFormAddComponent(form, label);
+
+	bpvcount = newtTextbox(24,5,30,1,0);
+	newtFormAddComponent(form, bpvcount);
+	
+	label = newtLabel(4,4,"IRQ Misses: ");
+	newtFormAddComponent(form, label);
+
+	irqmisses = newtTextbox(24,4,30,1,0);
+	newtFormAddComponent(form, irqmisses);
+
+	label = newtLabel(4,3,"Sync Source: ");
+	newtFormAddComponent(form, label);
+
+	syncsrc = newtTextbox(24,3,30,1,0);
+	newtFormAddComponent(form, syncsrc);
+
+	label = newtLabel(4,2,"Current Alarms: ");
+	newtFormAddComponent(form, label);
+
+	alarms = newtTextbox(24,2,30,1,0);
+	newtFormAddComponent(form, alarms);
+	
+	for(;;) {
+		/* Wait for user to select something */
+		do {
+			add_cards(NULL);
+			show_bits(span, bitbox, inuse, levels, bpvcount, alarms, syncsrc, irqmisses);
+			newtFormRun(form, &es);
+		} while(es.reason == NEWT_EXIT_TIMER);
+		switch(es.reason) {
+		case NEWT_EXIT_COMPONENT:
+			if (es.u.co == back) {
+				goto out;
+			}
+			break;
+		case NEWT_EXIT_HOTKEY:
+			switch(es.u.key) {
+#if 0
+			case NEWT_KEY_F1:
+				show_span(-1);
+				break;
+#endif				
+			case NEWT_KEY_F10:
+				goto out;
+			}
+			break;
+		default:
+			break;
+		}
+	}	
+
+out:	
+	newtFormDestroy(form);
+	newtPopWindow();
+	newtPopHelpLine();
+	span_max_chan_pos = 0;
+}
+
+static void show_spans(void)
+{
+	newtComponent form;
+	newtComponent quit;
+	newtComponent label;
+	newtComponent sel;
+
+	
+	struct newtExitStruct es;
+	
+	
+	quit = newtButton(50,14,"Quit");
+	sel = newtButton(10,14,"Select");
+	
+	spans = newtListbox(5, 2, 10, NEWT_FLAG_SCROLL);
+	newtListboxSetWidth(spans, 65);
+	
+	label = newtLabel(5,1,"Alarms          Span");
+	
+	newtCenteredWindow(72,18, "DAHDI Telephony Interfaces");
+	form = newtForm(NULL, NULL, 0);
+	
+	newtFormSetTimer(form, 200);
+	
+	newtFormAddComponents(form, spans, sel, quit, label, NULL);
+
+	newtComponentAddCallback(spans, sel_callback, NULL);
+
+	newtFormAddHotKey(form, NEWT_KEY_F1);
+	newtFormAddHotKey(form, NEWT_KEY_F10);
+	
+	for(;;) {
+		/* Wait for user to select something */
+		do {
+			add_cards(spans);
+			newtFormRun(form, &es);
+		} while(es.reason == NEWT_EXIT_TIMER);
+
+		switch(es.reason) {
+		case NEWT_EXIT_COMPONENT:
+			if (es.u.co == quit) {
+				/* Quit if appropriate */
+				newtFormDestroy(form);
+				return;
+			} else if (es.u.co == sel) {
+				show_span(-1);
+			}
+			break;
+		case NEWT_EXIT_HOTKEY:
+			switch(es.u.key) {
+			case NEWT_KEY_F1:
+				show_span(-1);
+				break;
+			case NEWT_KEY_F10:
+				newtFormDestroy(form);
+				return;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+static void cleanup(void)
+{
+	newtPopWindow();
+}
+
+int main(int argc, char *argv[])
+{
+
+	ctl = open("/dev/dahdi/ctl", O_RDWR);
+	if (ctl < 0) {
+		fprintf(stderr, "Unable to open /dev/dahdi/ctl: %s\n", strerror(errno));
+		exit(1);
+	}
+	newtInit();
+	newtCls();
+	
+	newtDrawRootText(0,0,"DAHDI Tool (C)2002-2008 Digium, Inc.");
+	newtPushHelpLine("Welcome to the DAHDI Tool!");
+	show_spans();
+	cleanup();
+	newtFinished();
+	return 0;
+}
diff --git a/dahdi_tools_version.h b/dahdi_tools_version.h
new file mode 100644
index 0000000..b4ec5fb
--- /dev/null
+++ b/dahdi_tools_version.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2008 Digium, Inc.
+ *
+ * All rights reserved.
+ *
+ */
+
+/*
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2 as published by the
+ * Free Software Foundation. See the LICENSE file included with
+ * this program for more details.
+ */
+
+extern const char dahdi_tools_version[];
diff --git a/doc/dahdi_cfg.8 b/doc/dahdi_cfg.8
new file mode 100644
index 0000000..7a1fe88
--- /dev/null
+++ b/doc/dahdi_cfg.8
@@ -0,0 +1,70 @@
+.TH "DAHDI_CFG" "8" "16 Jun 2008" "" ""
+
+.SH NAME
+dahdi_cfg \- configures DAHDI kernel modules from /etc/dahdi/system.conf
+.SH SYNOPSIS
+
+.B dahdi_cfg [\-c \fICFG_FILE\fB] [\-s] [\-f] [\-t] [\-v [\-v ... ] ]
+
+.B dahdi_cfg \-h
+
+.SH DESCRIPTION
+.B dahdi_cfg 
+configures DAHDI interface cards from a config file.
+
+You generally  need to run it with a valid configurations
+in order for DAHDI modules to work properly.
+
+It must be run to configure every DAHDI span. Normally it is run from
+the DAHDI init script.
+
+.SH OPTIONS
+
+.B \-c \fICFG_FILE
+.RS
+Use an alternative configuration file instead of
+.I /etc/dahdi/system.conf
+.RE
+
+.B \-s
+.RS
+Only shutdown spans.
+.RE
+
+.B \-f
+.RS
+Always configure every channel, even if it appears not to have changed.
+.RE
+
+.B \-t
+.RS
+Test mode. Don't do anything, just report what you wanted to do.
+.RE
+
+.B \-v
+.RS
+Be more verbose. Add extra v-s for extra verbosity.
+.RE
+
+.B \-h
+.RS
+Display a brief help message.
+.RE
+
+.SH FILES
+
+.I /etc/dahdi/system.conf
+.RS
+The default location for the configuration file.
+.RE
+
+.SH SEE ALSO
+dahdi_tool(8), dahdi_monitor(8), asterisk(8).
+
+.SH AUTHOR
+This manual page was written by Santiago Ruano Rinc\['o]n 
+<santiago at unicauca.edu.co> for
+the Debian system (but may be used by others).  Permission is
+granted to copy, distribute and/or modify this document under
+the terms of the GNU General Public License, Version 2 any 
+later version published by the Free Software Foundation.
diff --git a/doc/dahdi_diag.8 b/doc/dahdi_diag.8
new file mode 100644
index 0000000..0f01a09
--- /dev/null
+++ b/doc/dahdi_diag.8
@@ -0,0 +1,52 @@
+.TH dahdi_diag 8 "2008-01-07" 
+.SH NAME 
+dahdi_diag \(em Dump DAHDI channel parameters
+.SH SYNOPSIS 
+.B dahdi_diag 
+.I channel
+
+.SH DESCRIPTION 
+.B dahdi_diag
+asks the kernel to dump parameters for DAHDI channel no.
+.I channel
+to the kernel logs. You will be able to see them using, e.g. dmesg(1).
+
+
+.SH OPTIONS
+.I channel
+.RS
+The number of the DAHDI channel whose parammeters should be dumped.
+May be any DAHDI channel (even if it is open).
+.RE
+
+.SH EXAMPLE
+
+  # /tmp/dahdi_diag 5
+  # dmesg | tail \-n 15
+  Dump of DAHDI Channel 5 (XPP_BRI_TE/00/01/1,5,2):
+
+  flags: 501 hex, writechunk: c5190948, readchunk: c5190954
+  rxgain: ccad2e80, txgain: ccad2e80, gainalloc: 0
+  span: c48a900c, sig: 80 hex, sigcap: 80 hex
+  inreadbuf: \-1, outreadbuf: 0, inwritebuf: 0, outwritebuf: \-1
+  blocksize: 160, numbufs: 4, txbufpolicy: 0, txbufpolicy: 0
+  txdisable: 0, rxdisable: 0, iomask: 0
+  curzone: c78e7000, tonezone: 0, curtone: 00000000, tonep: 0
+  digitmode: 0, txdialbuf: , dialing: 0, aftdialtimer: 0, cadpos. 0
+  confna: 0, confn: 0, confmode: 0, confmute: 0
+  ec: 00000000, echocancel: 0, deflaw: 0, xlaw: ccab5e80
+  echostate: 00, echotimer: 0, echolastupdate: 0
+  itimer: 0, otimer: 0, ringdebtimer: 0
+
+.SH SEE ALSO 
+dahdi_cfg(8), asterisk(8), dmesg(1). 
+
+.SH AUTHOR 
+
+This manual page was written by Tzafrir Cohen <tzafrir.cohen at xorcom.com> 
+Permission is granted to copy, distribute and/or modify this document under 
+the terms of the GNU General Public License, Version 2 any  
+later version published by the Free Software Foundation. 
+ 
+On Debian systems, the complete text of the GNU General Public 
+License can be found in /usr/share/common\-licenses/GPL. 
diff --git a/doc/dahdi_monitor.8 b/doc/dahdi_monitor.8
new file mode 100644
index 0000000..17adc64
--- /dev/null
+++ b/doc/dahdi_monitor.8
@@ -0,0 +1,43 @@
+.TH "DAHDI_MONITOR" "8" "16 June 2008" "" ""
+
+.SH NAME
+dahdi_monitor \- checks the rx/tx levels of DAHDI channels
+.SH SYNOPSIS
+
+.B dahdi_monitor \fIchannel number\fB [\-v] [\-f \fIFILE\fB]
+
+.SH DESCRIPTION
+
+dahdi_monitor monitors a DAHDI channel. It gives you a visual
+representation of the sound strengths and makes it easy to see if
+the received or transmitted signals are too high or out of
+balance
+
+.SH OPTIONS
+The first (mandatory) parameter is the number of the channel
+to monitor.
+
+.B \-v
+.RS
+Display visual audio levels.
+.RE
+
+.B \-f \fIFILE
+.RS
+Write output to FILE
+.RE
+
+Some extra, yet undocumented, options.
+
+.SH SEE ALSO
+.PP
+dahdi_tool(8), dahdi_cfg(8), asterisk(8).
+
+.SH AUTHOR
+.PP
+This manual page was written by Santiago Ruano Rinc\['o]n 
+<santiago at unicauca.edu.co> for
+the Debian system (but may be used by others).  Permission is
+granted to copy, distribute and/or modify this document under
+the terms of the GNU General Public License, Version 2 any 
+later version published by the Free Software Foundation.
diff --git a/doc/dahdi_scan.8 b/doc/dahdi_scan.8
new file mode 100644
index 0000000..d7a9e16
--- /dev/null
+++ b/doc/dahdi_scan.8
@@ -0,0 +1,101 @@
+.TH dahdi_scan 8 "2008-03-18" 
+.SH NAME 
+dahdi_scan \(em Print Configuration of DAHDI Spans
+.SH SYNOPSIS 
+.B dahdi_scan
+.I [spans]
+
+.SH DESCRIPTION 
+.B dahdi_scan
+prints information about DAHDI spans in the system. For analog spans it
+also provides a list of channels.
+
+By default it prints information about all the spans in the system.
+However if parameters are provided, they will be considered to be a list
+of span numbers and information will be printed for them.
+
+Output is printed to the standard output. The format is that of an
+Asterisk configuration file (similar to a "ini" configuration file),
+where the name of the section is the number of the span. Note that the
+specifically for analog spans some keys may appear more than once, and
+hence you can not use a parser for an "ini" format and assume you have a
+dictionary.
+
+.SH EXAMPLES
+Printing information for spans 1, 2 and 4:
+
+  dahdi_scan 1 2 4
+
+And to print all the spans:
+
+  dahdi_scan
+
+Information about a certain analog span:
+
+  [5]
+  active=yes
+  alarms=OK
+  description=Xorcom XPD #00/10: FXS
+  name=XBUS\-00/XPD\-10
+  manufacturer=Xorcom Inc.
+  devicetype=Astribank: Unit 1 Subunit 0: FXS
+  location=usb\-0000:00:03.3\-4
+  basechan=125
+  totchans=8
+  irq=0
+  type=analog
+  port=125,FXS
+  port=126,FXS
+  port=127,FXS
+  port=128,FXS
+  port=129,FXS
+  port=130,FXS
+  port=131,FXS
+  port=132,FXS
+
+And an example of a digital span:
+
+  [1]
+  active=yes
+  alarms=RED
+  description=T2XXP (PCI) Card 0 Span 1
+  name=TE2/0/1
+  manufacturer=Digium
+  devicetype=Wildcard TE205P (4th Gen)
+  location=Board ID Switch 0
+  basechan=1
+  totchans=24
+  irq=193
+  type=digital\-T1
+  syncsrc=0
+  lbo=0 db (CSU)/0\-133 feet (DSX\-1)
+  coding_opts=B8ZS,AMI
+  framing_opts=ESF,D4
+  coding=B8ZS
+  framing=ESF
+
+The "type" field may contain: "analog", "digital\-T1", "digital\-E1",
+"digital\-J1" or "digital\-BRI".
+
+.SH FILES
+Requires read access to /dev/dahdi/ctl .
+
+.SH SEE ALSO 
+dahdi_cfg(8), asterisk(8). 
+
+.SH BUGS
+The program still does not do everything described in the man page.
+
+It also assumes that spans don't skip channel numbers, and that their 
+channel numbers are "running". This is anyway almost always the case. 
+And always the case in a normal boot process.
+
+.SH AUTHOR 
+
+This manual page was written by Tzafrir Cohen <tzafrir.cohen at xorcom.com> 
+Permission is granted to copy, distribute and/or modify this document under 
+the terms of the GNU General Public License, Version 2 any  
+later version published by the Free Software Foundation. 
+ 
+On Debian systems, the complete text of the GNU General Public 
+License can be found in /usr/share/common\-licenses/GPL. 
diff --git a/doc/dahdi_test.8 b/doc/dahdi_test.8
new file mode 100644
index 0000000..90b1e0b
--- /dev/null
+++ b/doc/dahdi_test.8
@@ -0,0 +1,49 @@
+.TH dahdi_test 8 "2005-06-25" 
+.SH "NAME" 
+dahdi_test \(em Test if the DAHDI timer provides timely response
+.SH "SYNOPSIS" 
+.B dahdi_test 
+.I [ \-v ]
+
+.SH DESCRIPTION 
+.B dahdi_test
+dahdi_test runs a timing test in a loop and prints the result of each loop.
+The test is as follows:
+
+It reads 8192 bytes from the DAHDI timer device (\fI/dev/dahdi/pseudo\fR). 
+This should take exactly 8000 ms . It uses calls to
+.I gettimeofday(2) 
+before and after that read to check that indeed exactly 8000ms have passed.
+
+Values of 100% and 99.99% Are normally considered a definite 
+.I pass.
+Values of 99.98% and 99.97% are probably OK as well.
+
+.SH OPTIONS
+.B \-v
+.RS
+Be more verbose: print one line per test.
+.RE
+
+.B \-c 
+.I count
+.RS
+Run for 
+.I count
+times instead of running forever.
+.RE
+
+.SH FILES
+.B /dev/dahdi/pseudo
+.RS
+.RE
+The device file used to access the DAHDI timer.
+
+.SH SEE ALSO 
+dahdi_tool(8), dahdi_cfg(8), asterisk(8). gettimeofday(2)
+
+.SH AUTHOR 
+This manual page was written by Tzafrir Cohen <tzafrir.cohen at xorcom.com> 
+Permission is granted to copy, distribute and/or modify this document under 
+the terms of the GNU General Public License, Version 2 any  
+later version published by the Free Software Foundation. 
diff --git a/doc/dahdi_tool.8 b/doc/dahdi_tool.8
new file mode 100644
index 0000000..2777366
--- /dev/null
+++ b/doc/dahdi_tool.8
@@ -0,0 +1,25 @@
+.TH "DAHDI_TOOL" "8" "16 June 2008" "" ""
+
+.SH NAME
+dahdi_tool \- Shows status of DAHDI interfaces
+.SH SYNOPSIS
+
+.B dahdi_tool
+
+.SH DESCRIPTION
+dahdi_tool shows the current status the DAHDI inteface cards plugged 
+to the computer.
+
+It displays values like Current Alarms, SyncSource, Tx/Rx
+Levels for each DAHDI interface.
+
+.SH SEE ALSO
+dahdi_monitor(8), asterisk (8).
+
+.SH AUTHOR
+This manual page was written by Santiago Ruano Rinc\['o]n 
+<santiago at unicauca.edu.co> for
+the Debian system (but may be used by others).  Permission is
+granted to copy, distribute and/or modify this document under
+the terms of the GNU General Public License, Version 2 any 
+later version published by the Free Software Foundation.
diff --git a/doc/fxotune.8 b/doc/fxotune.8
new file mode 100644
index 0000000..efa94c3
--- /dev/null
+++ b/doc/fxotune.8
@@ -0,0 +1,207 @@
+.TH FXOTUNE "8" "9 June 2007" "asterisk" "System Manager's Manuals: Asterisk"
+.SH NAME
+fxotune \- automatically tune DAHDI FXO channels
+.SH SYNOPSIS
+.B fxotune \-i 
+.I [options]
+\- detect mode
+
+.B fxotune \-d
+.I [ options ]
+\- dump mode
+
+.B fxotune \-s
+\- Startup mode
+.SH
+.SH DESCRIPTION
+.B fxotune 
+is a script that fine-tune parameters of the FXO modules of the 
+card. It has three modes of operation:
+
+.I Detect mode (\-i):
+it detects and tunes all the available FXO channels.
+It writes settings to a configuration file (/etc/fxotune.conf)
+from which it can be loaded (e.g: at startup) using \-s .
+
+.I Dump mode (\-d):
+Runs detection on a single DAHDI channel, and just dumps waveforms to
+.B fxotune_dump.vals
+is generated in the current directory.
+
+.I Startup mode (\-s):
+fxotune just reads the settings from fxotune.conf into the FXO modules.
+
+You are advised to run fxotune on all FXO ports you have that support 
+it and that are connected. Note that the tunning is affected by e.g.
+the physical parameters of the connection, and thus if it has been 
+radically changed, you may need to re-run fxotune.
+
+This program only works for the Digium TDM400P/800P/2400P cards and
+compatible and the Xorcom Astribank devices. Other cards (notably X100P
+cards and clones) do not have the hardware to support such tuning.
+
+The tuning process needs a clear line to do the tuning.  In order to do
+that, it runs in cycles of the following: sets the line off-hook, dials
+a dial string (which should set the PSTN provider waiting for the next
+digit), and then starts tuning. It has a limited ammount of time for
+tuning before the PSTN gives up and gives a busy tone. So after a while
+it hangs up and starts a new cycle.
+
+.B fxotune
+has two operation modes: tune (\-i) and set (\-s). In the tune mode it 
+generates /etc/fxotune.conf, and in the set mode it merely applies the 
+parameters from fxotune.conf to device's ports.
+
+.SH OPTIONS
+The following options below except \-v (verbose) affect only the
+detection process and hence apply only to the 
+.I detect
+and 
+.I dump
+modes.
+
+In addition, to maintain compatibility with older versions of fxotune,
+if in detect or dump mode there is a parameter with option before it, it
+is considered to be the 
+.I dialstring
+parameter (\-n).
+
+.B \-b
+.I startdev
+.RS
+Start tuning from dahdi channel num. \fI startdev\fR: skip all previous
+channels. By default starting from channel 1.
+
+In dump mode (\-d) this is the single channel that will be tested.
+.RE
+
+.B \-e
+.I stopdev
+.RS
+Tune only up to dahdi channel num. \fI stopdev\fR: skip all previous
+channels. By default stopping at channel 252.
+
+In dump mode (\-d) this parameter is ignored.
+.RE
+
+.B \-l
+.I delay-to-silence
+.RS
+Time in seconds to wait after dialing the dial-string to get a clear line.
+The default is 0. 
+before 
+.RE
+
+.B \-m
+.I silence-good-for
+.RS
+Time in seconds which states how long the PSTN will wait after we dialed
+the dial-string until it starts giving a busy tone. You can test this by
+connecting an analog phone to the line and dialing.
+
+The default is 18 (18 seconds). 
+.RE
+
+.B \-n
+.I dial-string
+.RS
+Digits to dial to the PSTN in order to get it stop its dialtone and
+waiting for the next digit. 
+
+The default is "4" (sending just the digit 4). It should work in most
+cases. Again, this can be tested by connecting a phone to the PSTN line
+and dialing the dial-string.
+.RE
+
+.B \-t
+.I detect-type
+.RS
+This option allows using the older detection method used by fxotune of
+Zaptel 1.2. use 
+.B \-t 1
+for that older method. whereas
+.B \-t 2
+(the default) uses the current method.
+
+This option only applies to detect mode (\-i).
+.RE
+
+.B \-v[vvvv]
+.RS
+Sets debugging on. The more v-s, the higher debug level. 
+
+Note that: \-vv \-v  will actually set debug level to 1 instead of 3.
+.RE
+
+.B \-w
+.I wave-form
+.RS
+The default: \-1, for multitone waveform. Alternatively: a frequency of a
+single tone.
+
+This option only applies to dump mode (\-d).
+.RE
+
+
+.SH EXAMPLES
+.RS
+fxotune \-i 9
+.RE
+if you need to dial 9 for an external line. If you always get a line, you
+can simply use any digit.
+.RE
+
+.B \-s
+.RS
+Load settings from the last test. Used at startup.
+.RE
+
+.SH FILES
+.I /etc/fxotune.conf
+.RS
+The configuration file generated by fxotune in detect mode and from which
+configuration is loaded when 
+.B \-s
+is used.
+
+.SH NOTES
+Running fxotune takes approximately a minute per port. If you wish to only 
+run fxotune for several ports, you can use the options \-b and \-e to set a 
+specific range of ports. Another useful trick is to actually keep asterisk 
+running, and only "destroy" the dahdi channels you wish to tune (dahdi 
+destroy channel NNN): other channels will be used by Asterisk, and hence 
+skipped. This can be useful if you have many FXO ports that are not connected.
+
+.B fxotune
+writes immediately to 
+.B /etc/fxotune.conf
+so if you stop it half-way, you may get a half-configured system. If you
+have already tuned your FXO channels and wish to test-run fxotune again, 
+you are advised to backup /etc/fxotune.conf .
+
+The default for \-m is 18 seconds. This asusmes that you get a clear line 
+for at least 18 seconds. It is advised that you test that timeout earlier
+by connecting a phone to the FXO line, dialing 4 (or whatever dial string 
+you put with \-n) and see how much time of silence you have.
+
+If you connect your device to a PSTN provider that is not in the US, there
+is a similar operation you should apply before even getting to fxotune:
+setting the opermode. The opermode sets a number of country-specific 
+parameters. For the Digium analog cards this is set through the kernel module 
+parameter 'opermode' . For the Xorcom Astribank this is set through the 
+variable 'opermode' in /etc/dahdi/xpp.conf .
+For valid values of this parameter, see
+/usr/share/asterisk/init_fxo_modes (FIXME: this has changed and will
+change. Tzafrir).
+
+.SH SEE ALSO 
+dahdi_cfg(8), dahdi_tool(8), dahdi_monitor(8), asterisk(8). 
+
+.SH AUTHOR 
+This manual page was written by Tzafrir Cohen <tzafrir.cohen at xorcom.com> 
+Permission is granted to copy, distribute and/or modify this document under 
+the terms of the GNU General Public License, Version 2 any  
+later version published by the Free Software Foundation. 
+
+On Debian systems, the complete text of the GNU General Public 
+License can be found in /usr/share/common\-licenses/GPL. 
diff --git a/doc/fxstest.8 b/doc/fxstest.8
new file mode 100644
index 0000000..159480f
--- /dev/null
+++ b/doc/fxstest.8
@@ -0,0 +1,60 @@
+.TH "FXSTEST" "8" "9 June 2007" "asterisk" "System Manager's Manuals: Asterisk"
+
+.SH NAME
+fxstest \- Simple tests for DAHDI FXS adapters
+.SH SYNOPSIS
+
+.B fxstest /dev/dahdi/\fIN comand\fR
+
+.SH DESCRIPTION
+fxstest can be used to issue one of a number simple tests to FXS
+adapters (analog adapters intended to connect phones). 
+
+.SH OPTIONS
+All of those tests operate on a single dahdi channel which has to be an
+FXS port, and must not be in use by Asterisk or any other program.
+
+The command has two mandatory parameters.
+The first parameter is the device file to operate on. It is typically
+/dev/dahdi/NN , a device file under /dev/dahdi .
+
+The second parameter is the name of the command to run on that channel:
+
+.I stats
+.RS
+Reports voltages
+.RE
+
+.I regdump
+.RS
+Dumps ProSLIC registers
+.RE
+
+.I tones
+.RS
+Plays a series of tones
+.RE
+
+.I polarity
+.RS
+Requests channel to reverse polarity.
+.RE
+
+.I ring
+.RS
+Rings phone
+.RE
+
+.SH "SEE ALSO"
+.PP
+dahdi_tool(8), dahdi_cfg(8), dahdi_monitor(8), asterisk(8).
+.SH BUGS
+Does not allow testing channels beyond 249. Should support opening
+channels through /dev/dahdi/channel .
+.SH AUTHOR
+.PP
+This manual page was written by Tzafrir Cohen <tzafrir.cohen at xorcom.com> .
+Permission is granted to copy, distribute and/or modify this document 
+under the terms of the GNU General Public License, Version 2 any 
+later version published by the Free Software Foundation.
+.PP
diff --git a/doc/patgen.8 b/doc/patgen.8
new file mode 100644
index 0000000..3585cff
--- /dev/null
+++ b/doc/patgen.8
@@ -0,0 +1,44 @@
+.TH patgen 8 "2 Dec 2009" 
+.SH NAME 
+patgen \(em Generates a Pattern for a DAHDI Clear Channel Test
+.SH SYNOPSIS 
+.B patgen 
+.I dahdi-device
+
+.SH DESCRIPTION 
+.B patgen
+Sends test data to a DAHDI channel. The channel should be of CLEAR
+signalling (e.g: B channel of a PRI line). pattest(8) is used to test
+the data at the other side.  See its manual for more information.
+
+.B patgen
+Must be able to write to the channel. Hence this cannot be used for a
+channel used by Asterisk.
+
+.SH OPTIONS
+.I dahdi-device
+.RS
+A DAHDI device. Can be either a device number or an explicit device file
+name
+.RE
+
+.SH EXAMPLE
+  patgen /dev/dahdi/5
+
+  patgen 305
+
+.SH BUGS
+Waiting for you to report them at <http://issues.asterisk.org> .
+
+.SH SEE ALSO 
+pattest(8), dahdi_cfg(8), asterisk(8). 
+
+.SH AUTHOR 
+
+This manual page was written by Tzafrir Cohen <tzafrir.cohen at xorcom.com> 
+Permission is granted to copy, distribute and/or modify this document under 
+the terms of the GNU General Public License, Version 2 any  
+later version published by the Free Software Foundation. 
+ 
+On Debian systems, the complete text of the GNU General Public 
+License can be found in /usr/share/common\-licenses/GPL. 
diff --git a/doc/pattest.8 b/doc/pattest.8
new file mode 100644
index 0000000..bce3f1c
--- /dev/null
+++ b/doc/pattest.8
@@ -0,0 +1,49 @@
+.TH pattest 8 "2 Dec 2009" 
+.SH NAME 
+pattest \(em Tests a Pattern for a DAHDI Clear Channel Test
+.SH SYNOPSIS 
+.B pattest 
+.I dahdi-device
+
+.SH DESCRIPTION 
+.B pattest
+Receives test data from a DAHDI channel and checks if it matches the 
+test pattern. The channel should be of CLEAR signalling (e.g: B channel 
+of a PRI line). patgen(8) is used to generate the data at the other side.  
+
+.B pattest
+Must be able to read from the channel. Hence this cannot be used for a
+channel used by Asterisk.
+
+The pattern is a simple series of values from 0 to 255. Hence it takes
+at most one sample to get in sync with the other side. If there is no
+output, all is well. Output is an error message.
+
+.SH OPTIONS
+.I dahdi-device
+.RS
+A DAHDI device. Can be either a device number or an explicit device file
+name
+.RE
+
+.SH EXAMPLE
+  pattest /dev/dahdi/5
+
+  pattest 305
+.RE
+
+.SH BUGS
+Gives way too many errors when does not get any input.
+
+.SH SEE ALSO 
+patgen(8), dahdi_cfg(8), asterisk(8). 
+
+.SH AUTHOR 
+
+This manual page was written by Tzafrir Cohen <tzafrir.cohen at xorcom.com> 
+Permission is granted to copy, distribute and/or modify this document under 
+the terms of the GNU General Public License, Version 2 any  
+later version published by the Free Software Foundation. 
+ 
+On Debian systems, the complete text of the GNU General Public 
+License can be found in /usr/share/common\-licenses/GPL. 
diff --git a/fxotune.c b/fxotune.c
new file mode 100644
index 0000000..08a9e9b
--- /dev/null
+++ b/fxotune.c
@@ -0,0 +1,1272 @@
+/* 
+ * fxotune.c -- A utility for tuning the various settings on the fxo
+ * 		modules for the TDM400 cards.
+ *
+ * by Matthew Fredrickson <creslin at digium.com>
+ * 
+ * (C) 2004-2008 Digium, Inc.
+ */
+
+/*
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2 as published by the
+ * Free Software Foundation. See the LICENSE file included with
+ * this program for more details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <math.h>
+#include <sys/time.h>
+
+#include <dahdi/user.h>
+#include <dahdi/wctdm_user.h>
+
+#include "dahdi_tools_version.h"
+#include "fxotune.h"
+
+#define TEST_DURATION 2000
+#define BUFFER_LENGTH (2 * TEST_DURATION)
+#define SKIP_SAMPLES 800
+#define SINE_SAMPLES 8000
+
+static float sintable[SINE_SAMPLES];
+
+static const float amplitude = 16384.0;
+
+static char *dahdipath = "/dev/dahdi";
+static char *configfile = "/etc/fxotune.conf";
+
+static int audio_dump_fd = -1;
+
+static int printbest = 0;
+
+#define MAX_RESULTS 	(5)
+struct result_catalog {
+	int 	idx;
+	float 	echo;
+	float 	freqres;
+	struct wctdm_echo_coefs settings;
+};
+
+struct {
+	struct result_catalog results[MAX_RESULTS];
+	int numactive;
+}	topresults;
+
+static char *usage =
+"Usage: fxotune [-v[vv] (-s | -i <options> | -d <options>)\n"
+"\n"
+"	-s : set previously calibrated echo settings\n"
+"	-i : calibrate echo settings\n"
+"		options : [<dialstring>] [-t <calibtype>]\n"
+"		[-b <startdev>][-e <stopdev>]\n"
+"		[-n <dialstring>][-l <delaytosilence>][-m <silencegoodfor>]\n"
+" 	-d : dump input and output waveforms to ./fxotune_dump.vals\n"
+"		options : [-b <device>][-w <waveform>]\n"
+"		   [-n <dialstring>][-l <delaytosilence>][-m <silencegoodfor>]\n"
+"	-v : more output (-vv, -vvv also)\n"
+"	-p : print the 5 best candidates for acim and coefficients settings\n"
+"	-x : Perform sin/cos functions using table lookup\n"
+"	-o <path> : Write the received raw 16-bit signed linear audio that is\n"
+"	            used in processing to the file specified by <path>\n"
+"	-c <config_file>\n"
+"\n"
+"		<calibtype>      - type of calibration\n"
+"		                   (default 2, old method 1)\n"
+"		<startdev>\n"
+"		<stopdev>        - defines a range of devices to test\n"
+"		                   (default: 1-252)\n"
+"		<dialstring>     - string to dial to clear the line\n"
+"		                   (default 5)\n"
+"		<delaytosilence> - seconds to wait for line to clear (default 0)\n"
+"		<silencegoodfor> - seconds before line will no longer be clear\n"
+"		                   (default 18)\n"
+"		<device>         - the device to perform waveform dump on\n"
+"		                   (default 1)\n"
+"		<waveform>       - -1 for multitone waveform, or frequency of\n"
+"		                   single tone (default -1)\n"
+"		<config_file>    - Alternative file to set from / calibrate to.\n"
+"				   (Default: /etc/fxotune.conf)\n"
+;
+
+
+#define OUT_OF_BOUNDS(x) ((x) < 0 || (x) > 255)
+
+struct silence_info{
+	char *dialstr;
+	/** fd of device we are working with */
+	int device; 
+	/** seconds we should wait after dialing the dialstring before we know for sure we'll have silence */
+	int initial_delay;
+	/** seconds after which a reset should occur */
+	int reset_after;
+	/** time of last reset */
+	struct timeval last_reset; 
+};
+
+static short outbuf[TEST_DURATION];
+static int debug = 0;
+
+static FILE *debugoutfile = NULL;
+
+static int use_table = 0;
+
+static int fxotune_read(int fd, void *buffer, int len)
+{
+	int res;
+
+	res = read(fd, buffer, len);
+
+	if ((res > 0) && (audio_dump_fd != -1)) {
+		res = write(audio_dump_fd, buffer, len);
+	}
+
+	return res;
+}
+
+/**
+ * Makes sure that the line is clear.
+ * Right now, we do this by relying on the user to specify how long after dialing the
+ * dialstring we can rely on the line being silent (before the telco complains about
+ * the user not hitting the next digit).
+ * 
+ * A more robust way to do this would be to actually measure the sound levels on the line,
+ * but that's a lot more complicated, and this should work.
+ * 
+ * @return 0 if succesful (no errors), 1 if unsuccesful
+ */
+static int ensure_silence(struct silence_info *info)
+{
+	struct timeval tv;
+	long int elapsedms;
+	int x = DAHDI_ONHOOK;
+	struct dahdi_dialoperation dop;
+
+	gettimeofday(&tv, NULL);
+	
+	if (info->last_reset.tv_sec == 0) {
+		/* this is the first request, we will force it to run */
+		elapsedms = -1;
+	} else {
+		/* this is not the first request, we will compute elapsed time */
+		elapsedms = ((tv.tv_sec - info->last_reset.tv_sec) * 1000L + (tv.tv_usec - info->last_reset.tv_usec) / 1000L);
+	}
+	if (debug > 4) {
+		fprintf(stdout, "Reset line request received - elapsed ms = %li / reset after = %ld\n", elapsedms, info->reset_after * 1000L);
+	}
+
+	if (elapsedms > 0 && elapsedms < info->reset_after * 1000L)
+		return 0;
+	
+	if (debug > 1){
+		fprintf(stdout, "Resetting line\n");
+	}
+	
+	/* do a line reset */
+	/* prepare line for silence */
+	/* Do line hookstate reset */
+
+	if (ioctl(info->device, DAHDI_HOOK, &x)) {
+		fprintf(stderr, "Unable to hang up fd %d\n", info->device);
+		return -1;
+	}
+
+	sleep(2);
+	x = DAHDI_OFFHOOK;
+	if (ioctl(info->device, DAHDI_HOOK, &x)) {
+		fprintf(stderr, "Cannot bring fd %d off hook\n", info->device);
+		return -1;
+	}
+	sleep(2); /* Added to ensure that dial can actually takes place */
+
+	memset(&dop, 0, sizeof(dop));
+	dop.op = DAHDI_DIAL_OP_REPLACE;
+	dop.dialstr[0] = 'T';
+	dahdi_copy_string(dop.dialstr + 1, info->dialstr, sizeof(dop.dialstr));
+
+
+	if (ioctl(info->device, DAHDI_DIAL, &dop)) {
+		fprintf(stderr, "Unable to dial!\n");
+		return -1;
+	}
+	sleep(1); 
+	sleep(info->initial_delay);  
+	
+	
+	gettimeofday(&info->last_reset, NULL);
+	
+	
+	return 0;
+}
+
+/**
+ * Generates a tone of specified frequency.
+ * 
+ * @param hz the frequency of the tone to be generated
+ * @param idx the current sample
+ * 		to begenerated.  For a normal waveform you need to increment
+ * 		this every time you execute the function.
+ *
+ * @return 16bit slinear sample for the specified index
+ */
+static short inline gentone(int hz, int idx)
+{
+	return amplitude * sin((idx * 2.0 * M_PI * hz)/8000);
+}
+
+/* Using DTMF tones for now since they provide good mid band testing 
+ * while not being harmonics of each other */
+static int freqs[] = {697, 770, 941, 1209, 1336, 1633};
+static int freqcount = 6;
+
+/**
+ * Generates a waveform of several frequencies.
+ * 
+ * @param idx the current sample
+ * 		to begenerated.  For a normal waveform you need to increment
+ * 		this every time you execute the function.
+ *
+ * @return 16bit slinear sample for the specified index
+ */
+static short inline genwaveform(int idx)
+{
+	int i = 0;
+	float response = (float)0;
+	for (i = 0; i < freqcount; i++){
+		response += sin((idx * 2.0 * M_PI * freqs[i])/8000);
+	}
+	
+
+	return amplitude * response / freqcount;
+}
+
+
+/**
+ *  Calculates the RMS of the waveform buffer of samples in 16bit slinear format.
+ *  prebuf the buffer of either shorts or floats
+ *  bufsize the number of elements in the prebuf buffer (not the number of bytes!)
+ *  short_format 1 if prebuf points to an array of shorts, 0 if it points to an array of floats
+ *  
+ *  Formula for RMS (http://en.wikipedia.org/wiki/Root_mean_square): 
+ *  
+ *  Xrms = sqrt(1/N Sum(x1^2, x2^2, ..., xn^2))
+ *  
+ *  Note:  this isn't really a power calculation - but it gives a good measure of the level of the response
+ *  
+ *  @param prebuf the buffer containing the values to compute
+ *  @param bufsize the size of the buffer
+ *  @param short_format 1 if prebuf contains short values, 0 if it contains float values
+ */
+static float power_of(void *prebuf, int bufsize, int short_format)
+{
+	float sum_of_squares = 0;
+	int numsamples = 0;
+	float finalanswer = 0;
+	short *sbuf = (short*)prebuf;
+	float *fbuf = (float*)prebuf;
+	int i = 0;
+
+	if (short_format) {
+		/* idiot proof checks */
+		if (bufsize <= 0)
+			return -1;
+
+		numsamples = bufsize; /* Got rid of divide by 2 - the bufsize parameter should give the number of samples (that's what it does for the float computation, and it should do it here as well) */
+
+		for (i = 0; i < numsamples; i++) {
+			sum_of_squares += ((float)sbuf[i] * (float)sbuf[i]);
+		}
+	} else {
+		/* Version for float inputs */
+		for (i = 0; i < bufsize; i++) {
+			sum_of_squares += (fbuf[i] * fbuf[i]);
+		}
+	}
+
+	finalanswer = sum_of_squares/(float)bufsize; /* need to divide by the number of elements in the sample for RMS calc */
+
+	if (finalanswer < 0) {
+		fprintf(stderr, "Error: Final answer negative number %f\n", finalanswer);
+		return -3;
+	}
+
+	return sqrtf(finalanswer);
+}
+
+/* 
+ * In an effort to eliminate as much as possible the effect of outside noise, we use principles
+ * from the Fourier Transform to attempt to calculate the return loss of our signal for each setting.
+ *
+ * To begin, we send our output signal out on the line.  We then receive back the reflected
+ * response.  In the Fourier Transform, each evenly distributed frequency within the window
+ * is correlated (multiplied against, then the resulting samples are added together) with
+ * the real (cos) and imaginary (sin) portions of that frequency base to detect that frequency.
+ * 
+ * Instead of doing a complete Fourier Transform, we solve the transform for only our signal
+ * by multiplying the received signal by the real and imaginary portions of our reference
+ * signal.  This then gives us the real and imaginary values that we can use to calculate
+ * the return loss of the sinusoids that we sent out on the line.  This is done by finding
+ * the magnitude (think polar form) of the vector resulting from the real and imaginary
+ * portions calculated above.
+ *
+ * This essentially filters out any other noise which maybe present on the line which is outside
+ * the frequencies used in our test multi-tone.
+ */
+
+void init_sinetable(void)
+{
+	int i;
+	if (debug) {
+		fprintf(stdout, "Using sine tables with %d samples\n", SINE_SAMPLES);
+	}
+	for (i = 0; i < SINE_SAMPLES; i++) {
+		sintable[i] = sin(((float)i * 2.0 * M_PI )/(float)(SINE_SAMPLES));
+	}
+}
+
+/* Sine and cosine table lookup to use periodicity of the calculations being done */
+float sin_tbl(int arg, int num_per_period)
+{
+	arg = arg % num_per_period;
+
+	arg = (arg * SINE_SAMPLES)/num_per_period;
+
+	return sintable[arg];
+}
+
+float cos_tbl(int arg, int num_per_period)
+{
+	arg = arg  % num_per_period;
+
+	arg = (arg * SINE_SAMPLES)/num_per_period;
+
+	arg = (arg + SINE_SAMPLES/4) % SINE_SAMPLES;  /* Pi/2 adjustment */
+
+	return sintable[arg];
+}
+
+
+static float db_loss(float measured, float reference)
+{
+	return 20 * (logf(measured/reference)/logf(10));
+}
+
+static void one_point_dft(const short *inbuf, int len, int frequency, float *real, float *imaginary)
+{
+	float myreal = 0, myimag = 0;
+	int i;
+
+	for (i = 0; i < len; i++) {
+		if (use_table) {
+			myreal += (float) inbuf[i] * cos_tbl(i*frequency, 8000);
+			myimag += (float) inbuf[i] * sin_tbl(i*frequency, 8000);
+		} else {
+			myreal += (float) inbuf[i] * cos((i * 2.0 * M_PI * frequency)/8000);
+			myimag += (float) inbuf[i] * sin((i * 2.0 * M_PI * frequency)/8000);
+		}
+	}
+
+	myimag *= -1;
+
+	*real = myreal / (float) len;
+	*imaginary = myimag / (float) len;
+}
+
+
+static float calc_magnitude(short *inbuf, int insamps)
+{
+	float real, imaginary, magnitude;
+	float totalmagnitude = 0;
+	int i;
+
+	for (i = 0; i < freqcount; i++) {
+		one_point_dft(inbuf, insamps, freqs[i], &real, &imaginary);
+		magnitude = sqrtf((real * real) + (imaginary * imaginary));
+		totalmagnitude += magnitude;
+	}
+
+	return totalmagnitude;
+}
+
+
+/**
+ *  dumps input and output buffer contents for the echo test - used to see exactly what's going on
+ */
+static int maptone(int whichdahdi, int freq, char *dialstr, int delayuntilsilence)
+{
+	int i = 0;
+	int res = 0, x = 0;
+	struct dahdi_bufferinfo bi;
+	short inbuf[TEST_DURATION]; /* changed from BUFFER_LENGTH - this buffer is for short values, so it should be allocated using the length of the test */
+	FILE *outfile = NULL;
+	int leadin = 50;
+	int trailout = 100;
+	struct silence_info sinfo;
+	float power_result;
+	float power_waveform;
+	float echo;
+
+	outfile = fopen("fxotune_dump.vals", "w");
+	if (!outfile) {
+		fprintf(stdout, "Cannot create fxotune_dump.vals\n");
+		return -1;
+	}
+
+	x = 1;
+	if (ioctl(whichdahdi, DAHDI_SETLINEAR, &x)) {
+		fprintf(stderr, "Unable to set channel to signed linear mode.\n");
+		return -1;
+	}
+
+	memset(&bi, 0, sizeof(bi));
+	if (ioctl(whichdahdi, DAHDI_GET_BUFINFO, &bi)) {
+		fprintf(stderr, "Unable to get buffer information!\n");
+		return -1;
+	}
+	bi.numbufs = 2;
+	bi.bufsize = TEST_DURATION; /* KD - changed from BUFFER_LENGTH; */
+	bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
+	bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
+	if (ioctl(whichdahdi, DAHDI_SET_BUFINFO, &bi)) {
+		fprintf(stderr, "Unable to set buffer information!\n");
+		return -1;
+	}
+
+	/* Fill the output buffers */
+	for (i = 0; i < leadin; i++)
+		outbuf[i] = 0;
+	for (; i < TEST_DURATION - trailout; i++){
+		outbuf[i] = freq > 0 ? gentone(freq, i) : genwaveform(i); /* if frequency is negative, use a multi-part waveform instead of a single frequency */
+	}
+	for (; i < TEST_DURATION; i++)
+		outbuf[i] = 0;
+
+	/* Make sure the line is clear */
+	memset(&sinfo, 0, sizeof(sinfo));
+	sinfo.device = whichdahdi;
+	sinfo.dialstr = dialstr;
+	sinfo.initial_delay = delayuntilsilence;
+	sinfo.reset_after = 4; /* doesn't matter - we are only running one test */
+	
+	if (ensure_silence(&sinfo)){
+		fprintf(stderr, "Unable to get a clear outside line\n");
+		return -1;
+	}
+
+	/* Flush buffers */
+	x = DAHDI_FLUSH_READ | DAHDI_FLUSH_WRITE | DAHDI_FLUSH_EVENT;
+	if (ioctl(whichdahdi, DAHDI_FLUSH, &x)) {
+		fprintf(stderr, "Unable to flush I/O: %s\n", strerror(errno));
+		return -1;
+	}
+
+	/* send data out on line */
+	res = write(whichdahdi, outbuf, BUFFER_LENGTH); /* we are sending a TEST_DURATION length array of shorts (which are 2 bytes each) */
+	if (res != BUFFER_LENGTH) { 
+		fprintf(stderr, "Could not write all data to line\n");
+		return -1;
+	}
+
+retry:
+		/* read return response */
+	res = fxotune_read(whichdahdi, inbuf, BUFFER_LENGTH);
+	if (res != BUFFER_LENGTH) {
+		int dummy;
+
+		ioctl(whichdahdi, DAHDI_GETEVENT, &dummy);
+		goto retry;
+	}
+
+	/* write content of output buffer to debug file */
+	power_result = power_of(inbuf, TEST_DURATION, 1);
+	power_waveform = power_of(outbuf, TEST_DURATION, 1);
+	echo = power_result/power_waveform;
+	
+	fprintf(outfile, "Buffers, freq=%d, outpower=%0.0f, echo=%0.4f\n", freq, power_result, echo);
+	fprintf(outfile, "Sample, Input (received from the line), Output (sent to the line)\n");
+	for (i = 0; i < TEST_DURATION; i++){
+		fprintf(outfile, "%d, %d, %d\n", 
+			i,
+			inbuf[i],
+			outbuf[i]
+		);
+	}
+
+	fclose(outfile);
+	
+	fprintf(stdout, "echo ratio = %0.4f (%0.1f / %0.1f)\n", echo, power_result, power_waveform);
+	
+	return 0;
+}
+
+
+/**
+ *  Initialize the data store for storing off best calculated results
+ */
+static void init_topresults(void)
+{
+	topresults.numactive = 0;
+}
+
+
+/**
+ *  If this is a best result candidate, store in the top results data store
+ * 		This is dependent on being the lowest echo value
+ *
+ *  @param tbleoffset - The offset into the echo_trys table used
+ *  @param setting - Pointer to the settings used to achieve the fgiven value
+ *  @param echo - The calculated echo return value (in dB)
+ *  @param echo - The calculated magnitude of the response
+ */
+static void set_topresults(int tbloffset, struct wctdm_echo_coefs *setting, float echo, float freqres)
+{
+	int place;
+	int idx;
+
+	for ( place = 0; place < MAX_RESULTS && place < topresults.numactive; place++) {
+		if (echo < topresults.results[place].echo) {
+			break;
+		}
+	}
+
+	if (place < MAX_RESULTS) {
+		/*  move results to the bottom */
+		for (idx = topresults.numactive-2; idx >= place; idx--) {
+			topresults.results[idx+1] = topresults.results[idx];
+		}
+		topresults.results[place].idx = tbloffset;
+		topresults.results[place].settings = *setting;
+		topresults.results[place].echo = echo;
+		topresults.results[place].freqres = freqres;
+		if (MAX_RESULTS > topresults.numactive) {
+			topresults.numactive++;
+		}
+	}
+}
+
+
+/**
+ *  Prints the top results stored to stdout
+ *
+ *  @param header - Text that goes in the header of the response
+ */
+static void print_topresults(char * header)
+{
+	int item;
+
+	fprintf(stdout, "Top %d results for %s\n", topresults.numactive, header);
+	for (item = 0; item < topresults.numactive; item++) {
+		fprintf(stdout, "Res #%d: index=%d, %3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d: magnitude = %0.0f, echo = %0.4f dB\n",
+				item+1, topresults.results[item].idx, topresults.results[item].settings.acim,
+				topresults.results[item].settings.coef1, topresults.results[item].settings.coef2,
+				topresults.results[item].settings.coef3, topresults.results[item].settings.coef4,
+				topresults.results[item].settings.coef5, topresults.results[item].settings.coef6,
+				topresults.results[item].settings.coef7, topresults.results[item].settings.coef8,
+				topresults.results[item].freqres, topresults.results[item].echo);
+		
+	}
+}
+
+
+/**
+ * Perform calibration type 2 on the specified device
+ * 
+ * Determine optimum echo coefficients for the specified device
+ * 
+ * New tuning strategy.  If we have a number that we can dial that will result in silence from the
+ * switch, the tune will be *much* faster (we don't have to keep hanging up and dialing a digit, etc...)
+ * The downside is that the user needs to actually find a 'no tone' phone number at their CO's switch - but for
+ * really fixing echo problems, this is what it takes.
+ *
+ * Also, for the purposes of optimizing settings, if we pick a single frequency and test with that,
+ * we can try a whole bunch of impedence/echo coefficients.  This should give better results than trying
+ * a bunch of frequencies, and we can always do a a frequency sweep to pick between the best 3 or 4
+ * impedence/coefficients configurations.
+ *   
+ * Note:  It may be possible to take this even further and do some pertubation analysis on the echo coefficients
+ * 		 themselves (maybe use the 72 entry sweep to find some settings that are close to working well, then
+ * 		 deviate the coefficients a bit to see if we can improve things).  A better way to do this would be to
+ * 		 use the optimization strategy from silabs.  For reference, here is an application note that describes
+ * 		 the echo coefficients (and acim values):
+ * 		 
+ * 		 http://www.silabs.com/Support%20Documents/TechnicalDocs/an84.pdf
+ *
+ * 		 See Table 13 in this document for a breakdown of acim values by region.
+ *
+ * 		 http://www.silabs.com/Support%20Documents/TechnicalDocs/si3050-18-19.pdf
+ * 		 
+ */
+static int acim_tune2(int whichdahdi, int freq, char *dialstr, int delayuntilsilence, int silencegoodfor, struct wctdm_echo_coefs *coefs_out)
+{
+	int i = 0;
+	int res = 0, x = 0;
+	int lowesttry = -1;
+	float lowesttryresult = 999999999999.0;
+	float lowestecho = 999999999999.0;
+	struct dahdi_bufferinfo bi;
+	short inbuf[TEST_DURATION * 2];
+	struct silence_info sinfo;
+	int echo_trys_size = 72;
+	int trys = 0;
+	float waveform_power;
+	float freq_result;
+	float echo;
+
+	init_topresults();
+
+	if (debug && !debugoutfile) {
+		if (!(debugoutfile = fopen("fxotune.vals", "w"))) {
+			fprintf(stdout, "Cannot create fxotune.vals\n");
+			return -1;
+		}
+	}
+
+	/* Set echo settings */
+	if (ioctl(whichdahdi, WCTDM_SET_ECHOTUNE, &echo_trys[0])) {
+		fprintf(stderr, "Unable to set impedance on fd %d\n", whichdahdi);
+		return -1;
+	}
+
+	x = 1;
+	if (ioctl(whichdahdi, DAHDI_SETLINEAR, &x)) {
+		fprintf(stderr, "Unable to set channel to signed linear mode.\n");
+		return -1;
+	}
+
+	memset(&bi, 0, sizeof(bi));
+	if (ioctl(whichdahdi, DAHDI_GET_BUFINFO, &bi)) {
+		fprintf(stderr, "Unable to get buffer information!\n");
+		return -1;
+	}
+	bi.numbufs = 2;
+	bi.bufsize = BUFFER_LENGTH;
+	bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
+	bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
+	if (ioctl(whichdahdi, DAHDI_SET_BUFINFO, &bi)) {
+		fprintf(stderr, "Unable to set buffer information!\n");
+		return -1;
+	}
+	x = DAHDI_OFFHOOK;
+	if (ioctl(whichdahdi, DAHDI_HOOK, &x)) {
+		fprintf(stderr, "Cannot bring fd %d off hook", whichdahdi);
+		return -1;
+	}
+
+
+	/* Set up silence settings */
+	memset(&sinfo, 0, sizeof(sinfo));
+	sinfo.device = whichdahdi;
+	sinfo.dialstr = dialstr;
+	sinfo.initial_delay = delayuntilsilence;
+	sinfo.reset_after = silencegoodfor;
+
+	/* Fill the output buffers */
+	for (i = 0; i < TEST_DURATION; i++)
+		outbuf[i] = freq > 0 ? gentone(freq, i) : genwaveform(i); /* if freq is negative, use a multi-frequency waveform */
+	
+	/* compute power of input (so we can later compute echo levels relative to input) */
+	waveform_power = calc_magnitude(outbuf, TEST_DURATION);
+
+	/* sweep through the various coefficient settings and see how our responses look */
+
+	for (trys = 0; trys < echo_trys_size; trys++){
+		
+		/* ensure silence on the line */
+		if (ensure_silence(&sinfo)){
+			fprintf(stderr, "Unable to get a clear outside line\n");
+			return -1;
+		}
+		
+		if (ioctl(whichdahdi, WCTDM_SET_ECHOTUNE, &echo_trys[trys])) {
+			fprintf(stderr, "Unable to set echo coefficients on fd %d\n", whichdahdi);
+			return -1;
+		}
+
+		/* Flush buffers */
+		x = DAHDI_FLUSH_READ | DAHDI_FLUSH_WRITE | DAHDI_FLUSH_EVENT;
+		if (ioctl(whichdahdi, DAHDI_FLUSH, &x)) {
+			fprintf(stderr, "Unable to flush I/O: %s\n", strerror(errno));
+			return -1;
+		}
+
+		/* send data out on line */
+		res = write(whichdahdi, outbuf, BUFFER_LENGTH);
+		if (res != BUFFER_LENGTH) {
+			fprintf(stderr, "Could not write all data to line\n");
+			return -1;
+		}
+
+retry:
+		/* read return response */
+		res = fxotune_read(whichdahdi, inbuf, BUFFER_LENGTH * 2);
+		if (res != BUFFER_LENGTH * 2) {
+			int dummy;
+
+			ioctl(whichdahdi, DAHDI_GETEVENT, &dummy);
+			goto retry;
+		}
+
+		freq_result = calc_magnitude(inbuf, TEST_DURATION * 2);
+		echo = db_loss(freq_result, waveform_power);
+		
+#if 0
+		if (debug > 0)
+			fprintf(stdout, "%3d,%d,%d,%d,%d,%d,%d,%d,%d: magnitude = %0.0f, echo = %0.4f dB\n", 
+					echo_trys[trys].acim, echo_trys[trys].coef1, echo_trys[trys].coef2,
+					echo_trys[trys].coef3, echo_trys[trys].coef4, echo_trys[trys].coef5,
+					echo_trys[trys].coef6, echo_trys[trys].coef7, echo_trys[trys].coef8,
+					freq_result, echo);
+#endif
+
+		if (freq_result < lowesttryresult){
+			lowesttry = trys;
+			lowesttryresult = freq_result;
+			lowestecho = echo;
+		}
+		if (debug) {
+			char result[256];
+			snprintf(result, sizeof(result), "%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,%f,%f", 
+						echo_trys[trys].acim, 
+						echo_trys[trys].coef1, 
+						echo_trys[trys].coef2, 
+						echo_trys[trys].coef3, 
+						echo_trys[trys].coef4, 
+						echo_trys[trys].coef5, 
+						echo_trys[trys].coef6, 
+						echo_trys[trys].coef7, 
+						echo_trys[trys].coef8, 
+						freq_result,
+						echo
+					);
+			
+			fprintf(debugoutfile, "%s\n", result);
+			fprintf(stdout, "%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d,%3d: magnitude = %0.0f, echo = %0.4f dB\n",
+					echo_trys[trys].acim, echo_trys[trys].coef1, echo_trys[trys].coef2,
+					echo_trys[trys].coef3, echo_trys[trys].coef4, echo_trys[trys].coef5,
+					echo_trys[trys].coef6, echo_trys[trys].coef7, echo_trys[trys].coef8,
+					freq_result, echo);
+		}
+
+		if (printbest) {
+			set_topresults(trys, &echo_trys[trys], echo, freq_result);
+		}
+	}
+
+	if (debug > 0)
+		fprintf(stdout, "Config with lowest response = %d, magnitude = %0.0f, echo = %0.4f dB\n", lowesttry, lowesttryresult, lowestecho);
+
+	memcpy(coefs_out, &echo_trys[lowesttry], sizeof(struct wctdm_echo_coefs));
+	if (printbest) {
+		print_topresults("Acim2_tune Test");
+	}
+
+	return 0;
+}
+
+/**
+ *  Perform calibration type 1 on the specified device.  Only tunes the line impedance.  Look for best response range 
+ */
+static int acim_tune(int whichdahdi, char *dialstr, int delayuntilsilence, int silencegoodfor, struct wctdm_echo_coefs *coefs_out)
+{
+	int i = 0, freq = 0, acim = 0;
+	int res = 0, x = 0;
+	struct dahdi_bufferinfo bi;
+	struct wctdm_echo_coefs coefs;
+	short inbuf[TEST_DURATION]; /* changed from BUFFER_LENGTH - this buffer is for short values, so it should be allocated using the length of the test */
+	int lowest = 0;
+	FILE *outfile = NULL;
+	float acim_results[16];
+	struct silence_info sinfo;
+
+	if (debug) {
+		outfile = fopen("fxotune.vals", "w");
+		if (!outfile) {
+			fprintf(stdout, "Cannot create fxotune.vals\n");
+			return -1;
+		}
+	}
+
+	/* Set up silence settings */
+	memset(&sinfo, 0, sizeof(sinfo));
+	sinfo.device = whichdahdi;
+	sinfo.dialstr = dialstr;
+	sinfo.initial_delay = delayuntilsilence;
+	sinfo.reset_after = silencegoodfor;
+	
+	/* Set echo settings */
+	memset(&coefs, 0, sizeof(coefs));
+	if (ioctl(whichdahdi, WCTDM_SET_ECHOTUNE, &coefs)) {
+		fprintf(stdout, "Skipping non-TDM / non-FXO\n");
+		return -1;
+	}
+
+	x = 1;
+	if (ioctl(whichdahdi, DAHDI_SETLINEAR, &x)) {
+		fprintf(stderr, "Unable to set channel to signed linear mode.\n");
+		return -1;
+	}
+
+	memset(&bi, 0, sizeof(bi));
+	if (ioctl(whichdahdi, DAHDI_GET_BUFINFO, &bi)) {
+		fprintf(stderr, "Unable to get buffer information!\n");
+		return -1;
+	}
+	bi.numbufs = 2;
+	bi.bufsize = BUFFER_LENGTH;
+	bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
+	bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
+	if (ioctl(whichdahdi, DAHDI_SET_BUFINFO, &bi)) {
+		fprintf(stderr, "Unable to set buffer information!\n");
+		return -1;
+	}
+
+	for (acim = 0; acim < 16; acim++) {
+		float freq_results[15];
+
+		coefs.acim = acim;
+		if (ioctl(whichdahdi, WCTDM_SET_ECHOTUNE, &coefs)) {
+			fprintf(stderr, "Unable to set impedance on fd %d\n", whichdahdi);
+			return -1;
+		}
+
+		for (freq = 200; freq <=3000; freq+=200) {
+			/* Fill the output buffers */
+			for (i = 0; i < TEST_DURATION; i++)
+				outbuf[i] = gentone(freq, i);
+
+			/* Make sure line is ready for next test iteration */
+			if (ensure_silence(&sinfo)){
+				fprintf(stderr, "Unable to get a clear line\n");
+				return -1;
+			}
+			
+
+			/* Flush buffers */
+			x = DAHDI_FLUSH_READ | DAHDI_FLUSH_WRITE | DAHDI_FLUSH_EVENT;
+			if (ioctl(whichdahdi, DAHDI_FLUSH, &x)) {
+				fprintf(stderr, "Unable to flush I/O: %s\n", strerror(errno));
+				return -1;
+			}
+	
+			/* send data out on line */
+			res = write(whichdahdi, outbuf, BUFFER_LENGTH);
+			if (res != BUFFER_LENGTH) {
+				fprintf(stderr, "Could not write all data to line\n");
+				return -1;
+			}
+
+			/* read return response */
+retry:
+			/* read return response */
+			res = fxotune_read(whichdahdi, inbuf, BUFFER_LENGTH);
+			if (res != BUFFER_LENGTH) {
+				int dummy;
+	
+				ioctl(whichdahdi, DAHDI_GETEVENT, &dummy);
+				goto retry;
+			}
+
+			/* calculate power of response */
+			
+			freq_results[(freq/200)-1] = power_of(inbuf+SKIP_SAMPLES, TEST_DURATION-SKIP_SAMPLES, 1); /* changed from inbuf+SKIP_BYTES, BUFFER_LENGTH-SKIP_BYTES, 1 */
+			if (debug) fprintf(outfile, "%d,%d,%f\n", acim, freq, freq_results[(freq/200)-1]);
+		}
+		acim_results[acim] = power_of(freq_results, 15, 0);
+	}
+
+	if (debug) {
+		for (i = 0; i < 16; i++)
+			fprintf(outfile, "acim_results[%d] = %f\n", i, acim_results[i]);
+	}
+	/* Find out what the "best" impedance is for the line */
+	lowest = 0;
+	for (i = 0; i < 16; i++) {
+		if (acim_results[i] < acim_results[lowest]) {
+			lowest = i;
+		}
+	}
+
+	coefs_out->acim = lowest;
+	coefs_out->coef1 = 0;
+	coefs_out->coef2 = 0;
+	coefs_out->coef3 = 0;
+	coefs_out->coef4 = 0;
+	coefs_out->coef5 = 0;
+	coefs_out->coef6 = 0;
+	coefs_out->coef7 = 0;
+	coefs_out->coef8 = 0;
+	
+	return 0;
+}
+
+/**
+ * Reads echo register settings from the configuration file and pushes them into
+ * the appropriate devices
+ * 
+ * @param configfilename the path of the file that the calibration results should be written to
+ * 
+ * @return 0 if successful, !0 otherwise
+ */	
+static int do_set(char *configfilename)
+{
+	FILE *fp = NULL;
+	int res = 0;
+	int fd = 0;
+		
+	fp = fopen(configfile, "r");
+	
+    if (!fp) {
+            fprintf(stdout, "Cannot open %s!\n",configfile);
+            return -1;
+    }
+
+	
+	while (res != EOF) {
+		struct wctdm_echo_coefs mycoefs;
+		char completedahdipath[56] = "";
+		int mydahdi,myacim,mycoef1,mycoef2,mycoef3,mycoef4,mycoef5,mycoef6,mycoef7,mycoef8;
+
+
+		res = fscanf(fp, "%d=%d,%d,%d,%d,%d,%d,%d,%d,%d",&mydahdi,&myacim,&mycoef1,
+				&mycoef2,&mycoef3,&mycoef4,&mycoef5,&mycoef6,&mycoef7,
+				&mycoef8);
+
+		if (res == EOF) {
+			break;
+		}
+
+		/* Check to be sure conversion is done correctly */
+		if (OUT_OF_BOUNDS(myacim) || OUT_OF_BOUNDS(mycoef1)||
+			OUT_OF_BOUNDS(mycoef2)|| OUT_OF_BOUNDS(mycoef3)||
+			OUT_OF_BOUNDS(mycoef4)|| OUT_OF_BOUNDS(mycoef5)||
+			OUT_OF_BOUNDS(mycoef6)|| OUT_OF_BOUNDS(mycoef7)|| OUT_OF_BOUNDS(mycoef8)) {
+
+			fprintf(stdout, "Bounds check error on inputs from %s:%d\n", configfile, mydahdi);
+			return -1;
+		}
+
+		mycoefs.acim = myacim;
+		mycoefs.coef1 = mycoef1;
+		mycoefs.coef2 = mycoef2;
+		mycoefs.coef3 = mycoef3;
+		mycoefs.coef4 = mycoef4;
+		mycoefs.coef5 = mycoef5;
+		mycoefs.coef6 = mycoef6;
+		mycoefs.coef7 = mycoef7;
+		mycoefs.coef8 = mycoef8;
+	
+		snprintf(completedahdipath, sizeof(completedahdipath), "%s/%d", dahdipath, mydahdi);
+		fd = open(completedahdipath, O_RDWR);
+
+		if (fd < 0) {
+			fprintf(stdout, "open error on %s: %s\n", completedahdipath, strerror(errno));
+			return -1;
+		}
+
+		if (ioctl(fd, WCTDM_SET_ECHOTUNE, &mycoefs)) {
+			fprintf(stdout, "%s: %s\n", completedahdipath, strerror(errno));
+			return -1;
+		}
+
+		close(fd);
+	}
+
+	fclose(fp);
+
+	if (debug)
+		fprintf(stdout, "fxotune: successfully set echo coeffecients on FXO modules\n");
+	return 0;	
+}
+
+/**
+ * Output waveform information from a single test
+ * 
+ * Clears the line, then sends a single waveform (multi-tone, or single tone), and listens
+ * for the response on the line.  Output is written to fxotune_dump.vals
+ * 
+ * @param startdev the device to test
+ * @param dialstr the string that should be dialed to clear the dialtone from the line
+ * @param delayuntilsilence the number of seconds to wait after dialing dialstr before starting the test
+ * @param silencegoodfor the number of seconds that the test can run before having to reset the line again
+ * 			(this is basically the amount of time it takes before the 'if you'd like to make a call...' message
+ * 			kicks in after you dial dialstr.  This test is so short that the value is pretty much ignored.
+ * @param waveformtype the type of waveform to use - -1 = multi-tone waveform, otherwise the specified value
+ * 			is used as the frequency of a single tone.  A value of 0 will output silence.
+ */
+static int do_dump(int startdev, char* dialstr, int delayuntilsilence, int silencegoodfor, int waveformtype)
+{
+	int res = 0;
+	int fd;
+	char dahdidev[80] = "";
+	
+	int dahdimodule = startdev;
+	snprintf(dahdidev, sizeof(dahdidev), "%s/%d", dahdipath, dahdimodule);
+
+	fd = open(dahdidev, O_RDWR);
+	if (fd < 0) {
+		fprintf(stdout, "%s absent: %s\n", dahdidev, strerror(errno));
+		return -1;
+	}
+
+	fprintf(stdout, "Dumping module %s\n", dahdidev);
+	res = maptone(fd, waveformtype, dialstr, delayuntilsilence); 
+
+	close(fd);
+
+	if (res) {
+		fprintf(stdout, "Failure!\n");
+		return res;
+	} else {
+		fprintf(stdout, "Done!\n");
+		return 0;
+	}
+
+}	
+
+/**
+ * Performs calibration on all specified devices
+ * 
+ * @param startdev the first device to check
+ * @param enddev the last device to check
+ * @param calibtype the type of calibration to perform.  1=old style (loops through individual frequencies
+ * 			doesn't optimize echo coefficients.  2=new style (uses multi-tone and optimizes echo coefficients
+ * 			and acim setting)
+ * @param configfilename the path of the file that the calibration results should be written to
+ * @param dialstr the string that should be dialed to clear the dialtone from the line
+ * @param delayuntilsilence the number of seconds to wait after dialing dialstr before starting the test
+ * @param silencegoodfor the number of seconds that the test can run before having to reset the line again
+ * 			(this is basically the amount of time it takes before the 'if you'd like to make a call...' message
+ * 			kicks in after you dial dialstr
+ * 
+ * @return 0 if successful, -1 for serious error such as device not available , > 0 indicates the number of channels
+ */	
+static int do_calibrate(int startdev, int enddev, int calibtype, char* configfilename, char* dialstr, int delayuntilsilence, int silencegoodfor)
+{
+	int problems = 0;
+	int res = 0;
+	int configfd, fd;
+	int devno = 0;
+	char dahdidev[80] = "";
+	struct wctdm_echo_coefs coefs;
+	
+	configfd = open(configfile, O_CREAT|O_TRUNC|O_WRONLY, 0666);
+
+	if (configfd < 0) {
+		fprintf(stderr, "Cannot generate config file %s: open: %s\n", configfile, strerror(errno));
+		return -1;
+	}
+
+	for (devno = startdev; devno <= enddev; devno++) {
+		snprintf(dahdidev, sizeof(dahdidev), "%s/%d", dahdipath, devno);
+
+		fd = open(dahdidev, O_RDWR);
+		if (fd < 0) {
+			fprintf(stdout, "%s absent: %s\n", dahdidev, strerror(errno));
+			continue;
+		}
+
+		fprintf(stdout, "Tuning module %s\n", dahdidev);
+		
+		if (1 == calibtype)
+			res = acim_tune(fd, dialstr, delayuntilsilence, silencegoodfor, &coefs);
+		else
+			res = acim_tune2(fd, -1, dialstr, delayuntilsilence, silencegoodfor, &coefs);
+
+		close(fd);
+		
+		if (res) {
+			fprintf(stdout, "Failure!\n");
+			problems++;
+		} else {
+			fprintf(stdout, "Done!\n");
+		}
+
+		if (res == 0) {
+			
+		/* Do output to file */
+			int len = 0;
+			static char output[255] = "";
+
+			snprintf(output, sizeof(output), "%d=%d,%d,%d,%d,%d,%d,%d,%d,%d\n", 
+				devno,
+				coefs.acim, 
+				coefs.coef1, 
+				coefs.coef2, 
+				coefs.coef3, 
+				coefs.coef4, 
+				coefs.coef5, 
+				coefs.coef6, 
+				coefs.coef7, 
+				coefs.coef8
+			);
+
+			if (debug)
+				fprintf(stdout, "Found best echo coefficients: %s\n", output);
+
+			len = strlen(output);
+			res = write(configfd, output, strlen(output));
+			if (res != len) {
+				fprintf(stdout, "Unable to write line \"%s\" to file.\n", output);
+				return -1;
+			}
+		}
+	}
+
+	close(configfd);
+	
+	if (problems)
+		fprintf(stdout, "Unable to tune %d devices, even though those devices are present\n", problems);
+	
+	return problems;
+}	
+	
+int main(int argc , char **argv)
+{
+	int startdev = 1; /* -b */
+	int stopdev = 252; /* -e */
+	int calibtype = 2; /* -t */
+	int waveformtype = -1; /* -w multi-tone by default.  If > 0, single tone of specified frequency */
+	int delaytosilence = 0; /* -l */
+	int silencegoodfor = 18; /* -m */
+	char* dialstr = "5"; /* -n */
+	int res = 0;
+	int doset = 0; /* -s */
+	int docalibrate = 0; /* -i <dialstr> */
+	int dodump = 0; /* -d */
+	int i = 0;
+	int moreargs;
+	
+	for (i = 1; i < argc; i++){
+		if (!(argv[i][0] == '-' || argv[i][0] == '/') || (strlen(argv[i]) <= 1)){
+			fprintf(stdout, "Unknown option : %s\n", argv[i]);
+			/* Show usage */
+			fputs(usage, stdout);
+			return -1;
+		}
+
+		moreargs = (i < argc - 1);
+		
+		switch(argv[i][1]){
+			case 's':
+				doset=1;
+				continue;
+			case 'i':
+				docalibrate = 1;
+				if (moreargs){ /* we need to check for a value after 'i' for backwards compatability with command line options of old fxotune */
+					if (argv[i+1][0] != '-' && argv[i+1][0] != '/')
+						dialstr = argv[++i];
+				}
+				continue;
+			case 'c':
+				configfile = moreargs ? argv[++i] : configfile;
+				continue;
+			case 'd':
+				dodump = 1;
+				continue;
+			case 'b':
+				startdev = moreargs ? atoi(argv[++i]) : startdev;
+				break;
+			case 'e':
+				stopdev = moreargs ? atoi(argv[++i]) : stopdev;
+				break;
+			case 't':
+				calibtype = moreargs ? atoi(argv[++i]) : calibtype;
+				break;
+			case 'w':
+				waveformtype = moreargs ? atoi(argv[++i]) : waveformtype;
+				break;
+			case 'l':
+				delaytosilence = moreargs ? atoi(argv[++i]) : delaytosilence;
+				break;
+			case 'm':
+				silencegoodfor = moreargs ? atoi(argv[++i]) : silencegoodfor;
+				break;
+			case 'n':
+				dialstr = moreargs ? argv[++i] : dialstr;
+				break;
+			case 'p':
+				printbest++;
+				break;
+			case 'x':
+				use_table = 1;
+				break;
+			case 'v':
+				debug = strlen(argv[i])-1;
+				break;
+			case 'o':
+				if (moreargs) {
+					audio_dump_fd = open(argv[++i], O_WRONLY|O_CREAT|O_TRUNC, 0666);
+					if (audio_dump_fd == -1) {
+						fprintf(stdout, "Unable to open file %s: %s\n", argv[i], strerror(errno));
+						return -1;
+					}
+					break;
+				} else {
+					fprintf(stdout, "No path supplied to -o option!\n");
+					return -1;
+				}
+			default:
+				fprintf(stdout, "Unknown option : %s\n", argv[i]);
+				/* Show usage */
+				fputs(usage, stdout);
+				return -1;
+				
+		}
+	}
+	
+	if (debug > 3){
+		fprintf(stdout, "Running with parameters:\n");
+		fprintf(stdout, "\tdoset=%d\n", doset);	
+		fprintf(stdout, "\tdocalibrate=%d\n", docalibrate);	
+		fprintf(stdout, "\tdodump=%d\n", dodump);	
+		fprintf(stdout, "\tprint best settings=%d\n", printbest);
+		fprintf(stdout, "\tstartdev=%d\n", startdev);
+		fprintf(stdout, "\tstopdev=%d\n", stopdev);	
+		fprintf(stdout, "\tcalibtype=%d\n", calibtype);	
+		fprintf(stdout, "\twaveformtype=%d\n", waveformtype);	
+		fprintf(stdout, "\tdelaytosilence=%d\n", delaytosilence);	
+		fprintf(stdout, "\tsilencegoodfor=%d\n", silencegoodfor);	
+		fprintf(stdout, "\tdialstr=%s\n", dialstr);	
+		fprintf(stdout, "\tdebug=%d\n", debug);	
+	}
+
+	if(use_table) {
+		init_sinetable();
+	}
+	
+	if (docalibrate){
+		res = do_calibrate(startdev, stopdev, calibtype, configfile, dialstr, delaytosilence, silencegoodfor);
+		if (!res)
+			return do_set(configfile);	
+		else
+			return -1;
+	}
+
+	if (doset)
+		return do_set(configfile);
+				
+	if (dodump){
+		res = do_dump(startdev, dialstr, delaytosilence, silencegoodfor, waveformtype);
+		if (!res)
+			return 0;
+		else
+			return -1;
+	}
+
+	fputs(usage, stdout);
+	return -1;
+}
diff --git a/fxotune.h b/fxotune.h
new file mode 100644
index 0000000..97b02e6
--- /dev/null
+++ b/fxotune.h
@@ -0,0 +1,119 @@
+/*
+ * fxotune.h -- data structures and associated definitions for fxotune.c
+ *
+ * By Matthew Fredrickson <creslin at digium.com>
+ *
+ * Echo coefficients and acim register values taken from AN84 from Silicon
+ * Laboratories app note AN84 for setting echo cancellation coefficients
+ *
+ * (C) 2005 Digium, Inc.
+ */
+
+/*
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2 as published by the
+ * Free Software Foundation. See the LICENSE file included with
+ * this program for more details.
+ */
+
+struct wctdm_echo_coefs echo_trys [] =
+{
+	/* 600 ohm echo settings */
+	{ 0, 0, 0, 0, 0, 0, 0, 0, 0},
+	{ 10, 0, 6, 1, 254, 2, 255, 0, 0},
+	{ 3, 255, 255, 0, 1, 0, 0, 0, 0},
+	{ 3, 1, 253, 253, 2, 255, 0, 0, 0},
+	{ 9, 254, 251, 255, 2, 0, 1, 0, 0},
+	{ 5, 3, 251, 250, 2, 254, 0, 0, 255},
+	{ 8, 253, 2, 244, 255, 10, 244, 3, 253},
+	{ 10, 249, 244, 8, 12, 245, 252, 0, 1},
+	
+	/* 900 ohm echo settings */
+	{ 1, 0, 0, 0, 0, 0, 0, 0, 0},
+	{ 10, 252, 255, 1, 255, 0, 0, 0, 0},
+	{ 7, 255, 251, 251, 2, 255, 255, 1, 255},
+	{ 3, 1, 251, 250, 1, 254, 255, 0, 255},
+	{ 5, 252, 250, 0, 0, 255, 1, 0, 0},
+	{ 5, 3, 251, 250, 1, 253, 0, 0, 255},
+	{ 8, 253, 2, 244, 255, 10, 244, 3, 253},
+	{ 10, 249, 244, 8, 12, 245, 252, 0, 1},
+
+	/* 270 ohm + (750 ohm || 150 nF) (CTR21) */
+	{ 2, 0, 0, 0, 0, 0, 0, 0, 0},
+	{ 7, 0, 0, 255, 254, 0, 0, 0, 0},
+	{ 9, 0, 253, 254, 2, 255, 0, 0, 0},
+	{ 5, 1, 249, 254, 4, 253, 1, 0, 0},
+	{ 5, 252, 250, 1, 1, 254, 0, 255, 0},
+	{ 5, 3, 251, 250, 2, 253, 255, 255, 255},
+	{ 8, 253, 2, 244, 255, 10, 244, 3, 253},
+	{ 10, 249, 244, 8, 12, 245, 252, 0, 1},
+
+	/* 220 ohm + (820 ohm || 120 nF) (Australia/NewZealand) and 220 ohm + (820 ohm
+	 * || 115nF) (Slovakia/SAfrica/Germany/Austria/Bulgaria)
+	 */
+	{ 3, 0, 0, 0, 0, 0, 0, 0, 0},
+	{ 7, 0, 255, 254, 255, 0, 255, 0, 0},
+	{ 9, 0, 253, 253, 1, 255, 0, 0, 0},
+	{ 5, 1, 249, 254, 3, 253, 1, 0, 0},
+	{ 5, 252, 250, 1, 1, 254, 0, 255, 0},
+	{ 5, 3, 251, 251, 2, 253, 255, 255, 255},
+	{ 8, 253, 2, 244, 255, 10, 244, 3, 253},
+	{ 10, 249, 244, 8, 12, 245, 252, 0, 1},
+	
+	/* 370 ohm + (620ohm || 310nF) (New Zealand #2/India) CO Termination */
+	{ 4, 0, 0, 0, 0, 0, 0, 0, 0},
+	{ 9, 255, 1, 4, 0, 0, 1, 255, 0},
+	{ 9, 0, 253, 0, 3, 254, 0, 0, 255},
+	{ 9, 2, 250, 253, 5, 253, 1, 0 ,255},
+	{ 5, 252, 250, 1, 2, 255, 0 ,255, 0},
+	{ 5, 3, 251, 250, 3, 254, 255, 255, 255},
+	{ 8, 253, 2, 244, 255, 10, 244, 3, 253},
+	{ 10, 249, 244, 8, 12, 245, 252, 0, 1},
+	
+	/* 320 ohm + (1050ohm || 230 nF) (England) CO Termination */
+	{ 5, 0, 0, 0, 0, 0, 0, 0, 0},
+	{ 9, 0 ,255, 1, 255, 255, 0, 255, 0},
+	{ 5, 255, 252, 0, 2, 254, 0, 255, 255},
+	{ 9, 2, 250, 253, 4, 252, 0, 255, 255},
+	{ 5, 252, 250, 1, 1, 254, 0 ,255, 255},
+	{ 5, 3, 251, 250, 2, 253, 255, 255, 254},
+	{ 3, 1, 1, 242, 2, 9, 245, 3, 253},
+	{ 10, 249, 244, 8, 12, 245, 252, 0, 1},
+
+	/* 370 ohm + (820 ohm || 110 nF) CO Termination */
+	{ 6, 0, 0, 0, 0, 0, 0, 0, 0},
+	{ 6, 1, 254, 253, 0, 255, 0, 0, 0},
+	{ 9, 0, 251, 252, 2, 255, 0, 0, 0},
+	{ 5, 1, 248, 252, 4, 253, 1, 0, 0},
+	{ 5, 252, 250, 0, 0, 254, 0 , 255, 0},
+	{ 5, 3, 251, 250, 2, 253, 255, 255, 254},
+	{ 3, 1, 1, 242, 2, 9, 245, 3, 253},
+	{ 10, 249, 244, 8, 12, 245, 252, 0, 1},
+
+	/* 275 ohm + (780 ohm || 115 nF) CO Termination */
+	{ 7, 0, 0, 0, 0, 0, 0, 0, 0},
+	{ 7, 255, 255, 255, 255, 0, 0, 0, 0},
+	{ 9, 0, 253, 254, 2, 255, 0, 0, 0},
+	{ 5, 1, 249, 254, 4, 253, 1, 0, 0},
+	{ 5, 252, 250, 1, 1, 254, 0, 255, 0},
+	{ 5, 3, 251, 250, 2, 253, 255, 255, 255},
+	{ 8, 253, 2, 244, 255, 10, 244, 3, 253},
+	{ 10, 249, 244, 8, 12, 245, 252, 0, 1},
+	
+	/* Make sure we include the rest of the impedances */
+	{ 8, 0, 0, 0, 0, 0, 0, 0, 0},
+	{ 9, 0, 0, 0, 0, 0, 0, 0, 0},
+	{ 10, 0, 0, 0, 0, 0, 0, 0, 0},
+	{ 11, 0, 0, 0, 0, 0, 0, 0, 0},
+	{ 12, 0, 0, 0, 0, 0, 0, 0, 0},
+	{ 13, 0, 0, 0, 0, 0, 0, 0, 0},
+	{ 14, 0, 0, 0, 0, 0, 0, 0, 0},
+	{ 15, 0, 0, 0, 0, 0, 0, 0, 0},
+};
+
diff --git a/fxstest.c b/fxstest.c
new file mode 100644
index 0000000..130fad5
--- /dev/null
+++ b/fxstest.c
@@ -0,0 +1,337 @@
+/*
+ * Written by Mark Spencer <markster at digium.com>
+ * Based on previous works, designs, and architectures conceived and
+ * written by Jim Dixon <jim at lambdatel.com>.
+ *
+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
+ * Copyright (C) 2001-2008 Digium, Inc.
+ *
+ * All rights reserved.
+ *
+ * Primary Author: Mark Spencer <markster at digium.com>
+ * Radio Support by Jim Dixon <jim at lambdatel.com>
+ */
+
+/*
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2 as published by the
+ * Free Software Foundation. See the LICENSE file included with
+ * this program for more details.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <dahdi/user.h>
+#include <dahdi/wctdm_user.h>
+
+#include "tonezone.h"
+#include "dahdi_tools_version.h"
+
+static int tones[] = {
+	DAHDI_TONE_DIALTONE,
+	DAHDI_TONE_BUSY,
+	DAHDI_TONE_RINGTONE,
+	DAHDI_TONE_CONGESTION,
+	DAHDI_TONE_DIALRECALL,
+};
+
+struct dahdi_vmwi_info mwisend_setting; /*!< Which VMWI methods to use */
+
+/* Use to translate a DTMF character to the value required by the dahdi call */
+static int digit_to_dtmfindex(char digit)
+{
+	if (isdigit(digit))
+		return DAHDI_TONE_DTMF_BASE + (digit - '0');
+	else if (digit >= 'A' && digit <= 'D')
+		return DAHDI_TONE_DTMF_A + (digit - 'A');
+	else if (digit >= 'a' && digit <= 'd')
+		return DAHDI_TONE_DTMF_A + (digit - 'a');
+	else if (digit == '*')
+		return DAHDI_TONE_DTMF_s;
+	else if (digit == '#')
+		return DAHDI_TONE_DTMF_p;
+	else
+		return -1;
+}
+
+/* Place a channel into ringing mode */
+static int dahdi_ring_phone(int fd)
+{
+	int x;
+	int res;
+	/* Make sure our transmit state is on hook */
+	x = 0;
+	x = DAHDI_ONHOOK;
+	res = ioctl(fd, DAHDI_HOOK, &x);
+	do {
+		x = DAHDI_RING;
+		res = ioctl(fd, DAHDI_HOOK, &x);
+		if (res) {
+			switch (errno) {
+				case EBUSY:
+				case EINTR:
+					/* Wait just in case */
+					fprintf(stderr, "Ring phone is busy:%s\n", strerror(errno));
+					usleep(10000);
+					continue;
+				case EINPROGRESS:
+					fprintf(stderr, "Ring In Progress:%s\n", strerror(errno));
+					res = 0;
+					break;
+				default:
+					fprintf(stderr, "Couldn't ring the phone: %s\n", strerror(errno));
+					res = 0;
+			}
+		} else {
+			fprintf(stderr, "Phone is ringing\n");
+		}
+	} while (res);
+	return res;
+}
+
+int main(int argc, char *argv[])
+{
+	int fd;
+	int res;
+	int x;
+	if (argc < 3) {
+		fprintf(stderr, "Usage: fxstest <dahdi device> <cmd>\n"
+		       "       where cmd is one of:\n"
+		       "       stats - reports voltages\n"
+		       "       regdump - dumps ProSLIC registers\n"
+		       "       tones - plays a series of tones\n"
+		       "       polarity - tests polarity reversal\n"
+		       "       ring - rings phone\n"
+		       "       vmwi - toggles VMWI LED lamp\n"
+		       "       hvdc - toggles VMWI HV lamp\n"
+		       "       neon - toggles VMWI NEON lamp\n"
+		       "       dtmf <sequence> [<duration>]- Send a sequence of dtmf tones (\"-\" denotes no tone)\n"
+		       "       dtmfcid - create a dtmf cid spill without polarity reversal\n");
+		exit(1);
+	}
+	fd = open(argv[1], O_RDWR);
+	if (fd < 0) {
+		fprintf(stderr, "Unable to open %s: %s\n", argv[1], strerror(errno));
+		exit(1);
+	}
+	
+	if ( !strcasecmp(argv[2], "neon") || !strcasecmp(argv[2], "vmwi") || !strcasecmp(argv[2], "hvdc")) {
+		fprintf(stderr, "Twiddling %s ...\n", argv[2]);
+
+		if ( !strcasecmp(argv[2], "vmwi") ) {
+			mwisend_setting.vmwi_type = DAHDI_VMWI_LREV;
+		} else if ( !strcasecmp(argv[2], "neon") ) {
+			mwisend_setting.vmwi_type = DAHDI_VMWI_HVAC;
+		} else if ( !strcasecmp(argv[2], "hvdc") ) {
+			mwisend_setting.vmwi_type = DAHDI_VMWI_HVDC;
+		}
+		res = ioctl(fd, DAHDI_VMWI_CONFIG, &mwisend_setting);
+
+		x = 1;
+		res = ioctl(fd, DAHDI_VMWI, &x);
+		if (res) {
+			fprintf(stderr, "Unable to set %s ...\n", argv[2]);
+		} else {
+			fprintf(stderr, "Set 1 Voice Message...\n");
+
+			sleep(5);
+			x = 2;
+			ioctl(fd, DAHDI_VMWI, &x);
+			fprintf(stderr, "Set 2 Voice Messages...\n");
+
+			sleep(5);
+			x = 0;
+			ioctl(fd, DAHDI_VMWI, &x);
+			fprintf(stderr, "Set No Voice messages...\n");
+			sleep(2);
+			mwisend_setting.vmwi_type = 0;
+		}
+	} else if (!strcasecmp(argv[2], "ring")) {
+		fprintf(stderr, "Ringing phone...\n");
+		x = DAHDI_RING;
+		res = ioctl(fd, DAHDI_HOOK, &x);
+		if (res) {
+			fprintf(stderr, "Unable to ring phone...\n");
+		} else {
+			fprintf(stderr, "Phone is ringing...\n");
+			sleep(2);
+		}
+	} else if (!strcasecmp(argv[2], "polarity")) {
+		fprintf(stderr, "Twiddling polarity...\n");
+		/* Insure that the channel is in active mode */
+		x = DAHDI_RING;
+		res = ioctl(fd, DAHDI_HOOK, &x);
+		usleep(100000);
+		x = 0;
+		res = ioctl(fd, DAHDI_HOOK, &x);
+
+		x = 0;
+		res = ioctl(fd, DAHDI_SETPOLARITY, &x);
+		if (res) {
+			fprintf(stderr, "Unable to polarity...\n");
+		} else {
+			fprintf(stderr, "Polarity is forward...\n");
+			sleep(2);
+			x = 1;
+			ioctl(fd, DAHDI_SETPOLARITY, &x);
+			fprintf(stderr, "Polarity is reversed...\n");
+			sleep(5);
+			x = 0;
+			ioctl(fd, DAHDI_SETPOLARITY, &x);
+			fprintf(stderr, "Polarity is forward...\n");
+			sleep(2);
+		}
+	} else if (!strcasecmp(argv[2], "tones")) {
+		int x = 0;
+		for (;;) {
+			res = tone_zone_play_tone(fd, tones[x]);
+			if (res)
+				fprintf(stderr, "Unable to play tone %d\n", tones[x]);
+			sleep(3);
+			x=(x+1) % (sizeof(tones) / sizeof(tones[0]));
+		}
+	} else if (!strcasecmp(argv[2], "stats")) {
+		struct wctdm_stats stats;
+		res = ioctl(fd, WCTDM_GET_STATS, &stats);
+		if (res) {
+			fprintf(stderr, "Unable to get stats on channel %s\n", argv[1]);
+		} else {
+			printf("TIP: %7.4f Volts\n", (float)stats.tipvolt / 1000.0);
+			printf("RING: %7.4f Volts\n", (float)stats.ringvolt / 1000.0);
+			printf("VBAT: %7.4f Volts\n", (float)stats.batvolt / 1000.0);
+		}
+	} else if (!strcasecmp(argv[2], "regdump")) {
+		struct wctdm_regs regs;
+		int numregs = NUM_REGS;
+		memset(&regs, 0, sizeof(regs));
+		res = ioctl(fd, WCTDM_GET_REGS, &regs);
+		if (res) {
+			fprintf(stderr, "Unable to get registers on channel %s\n", argv[1]);
+		} else {
+			for (x=60;x<NUM_REGS;x++) {
+				if (regs.direct[x])
+					break;
+			}
+			if (x == NUM_REGS) 
+				numregs = 60;
+			printf("Direct registers: \n");
+			for (x=0;x<numregs;x++) {
+				printf("%3d. %02x  ", x, regs.direct[x]);
+				if ((x % 8) == 7)
+					printf("\n");
+			}
+			if (numregs == NUM_REGS) {
+				printf("\n\nIndirect registers: \n");
+				for (x=0;x<NUM_INDIRECT_REGS;x++) {
+					printf("%3d. %04x  ", x, regs.indirect[x]);
+					if ((x % 6) == 5)
+						printf("\n");
+				}
+			}
+			printf("\n\n");
+		}
+	} else if (!strcasecmp(argv[2], "setdirect") ||
+				!strcasecmp(argv[2], "setindirect")) {
+		struct wctdm_regop regop;
+		int val;
+		int reg;
+		if ((argc < 5) || (sscanf(argv[3], "%i", &reg) != 1) ||
+			(sscanf(argv[4], "%i", &val) != 1)) {
+			fprintf(stderr, "Need a register and value...\n");
+		} else {
+			regop.reg = reg;
+			regop.val = val;
+			if (!strcasecmp(argv[2], "setindirect")) {
+				regop.indirect = 1;
+			} else {
+				regop.indirect = 0;
+			}
+			res = ioctl(fd, WCTDM_SET_REG, &regop);
+			if (res) 
+				fprintf(stderr, "Unable to get registers on channel %s\n", argv[1]);
+			else
+				printf("Success.\n");
+		}
+	} else if (!strcasecmp(argv[2], "dtmf")) {
+		int duration = 50;  /* default to 50 mS duration */
+		char * outstring = "";
+		int dtmftone;
+
+		if(argc < 4) {	/* user supplied string */
+			fprintf(stderr, "You must specify a string of dtmf characters to send\n");
+		} else {
+			outstring = argv[3];
+			if(argc >= 5) {
+				sscanf(argv[4], "%30i", &duration);
+			}
+			printf("Going to send a set of DTMF tones >%s<\n", outstring);
+			printf("Using a duration of %d mS per tone\n", duration);
+					/* Flush any left remaining characs in the buffer and place the channel into on-hook transfer mode */
+			x = DAHDI_FLUSH_BOTH;
+			res = ioctl(fd, DAHDI_FLUSH, &x);
+			x = 500 + strlen(outstring) * duration;
+			ioctl(fd, DAHDI_ONHOOKTRANSFER, &x);
+
+			for (x = 0; '\0' != outstring[x]; x++) {
+				dtmftone = digit_to_dtmfindex(outstring[x]);
+				if (0 > dtmftone) {
+					dtmftone = -1;
+				}
+				res = tone_zone_play_tone(fd, dtmftone);
+				if (res) {
+					fprintf(stderr, "Unable to play DTMF tone %d (0x%x)\n", dtmftone, dtmftone);
+				}
+				usleep(duration * 1000);
+			}
+		}
+	} else if (!strcasecmp(argv[2], "dtmfcid")) {
+		char * outstring = "A5551212C";  /* Default string using A and C tones to bracket the number */
+		int dtmftone;
+		
+		if(argc >= 4) {	/* Use user supplied string */
+			outstring = argv[3];
+		}
+		printf("Going to send a set of DTMF tones >%s<\n", outstring);
+		/* Flush any left remaining characs in the buffer and place the channel into on-hook transfer mode */
+		x = DAHDI_FLUSH_BOTH;
+		res = ioctl(fd, DAHDI_FLUSH, &x);
+		x = 500 + strlen(outstring) * 100;
+		ioctl(fd, DAHDI_ONHOOKTRANSFER, &x);
+
+		/* Play the DTMF tones at a 50 mS on and 50 mS off rate which is standard for DTMF CID spills */
+		for (x = 0; '\0' != outstring[x]; x++) {
+
+			dtmftone = digit_to_dtmfindex(outstring[x]);
+			if (0 > dtmftone) {
+				dtmftone = -1;
+			}
+			res = tone_zone_play_tone(fd, dtmftone);
+			if (res) {
+				fprintf(stderr, "Unable to play DTMF tone %d (0x%x)\n", dtmftone, dtmftone);
+			}
+			usleep(50000);
+			tone_zone_play_tone(fd, -1);
+			usleep(50000);
+		}
+		/* Wait for 150 mS from end of last tone to initiating the ring */
+		usleep(100000);
+		dahdi_ring_phone(fd);
+		sleep(10);
+		printf("Ringing Done\n");
+	} else
+		fprintf(stderr, "Invalid command\n");
+	close(fd);
+	return 0;
+}
diff --git a/hdlcgen.c b/hdlcgen.c
new file mode 100644
index 0000000..29811bb
--- /dev/null
+++ b/hdlcgen.c
@@ -0,0 +1,135 @@
+/*
+ * Written by Mark Spencer <markster at digium.com>
+ * Based on previous works, designs, and architectures conceived and
+ * written by Jim Dixon <jim at lambdatel.com>.
+ *
+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
+ * Copyright (C) 2001-2008 Digium, Inc.
+ *
+ * All rights reserved.
+ *
+ * Primary Author: Mark Spencer <markster at digium.com>
+ * Radio Support by Jim Dixon <jim at lambdatel.com>
+ */
+
+/*
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2 as published by the
+ * Free Software Foundation. See the LICENSE file included with
+ * this program for more details.
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#define FAST_HDLC_NEED_TABLES
+#include <dahdi/fasthdlc.h>
+
+#include "dahdi_tools_version.h"
+
+#define RANDOM "/dev/urandom"			/* Not genuinely random */
+/* #define RANDOM "/dev/random" */		/* Quite genuinely random */
+
+int myread(int fd, char *buf, int len)
+{
+	int sofar;
+	int res;
+	sofar = 0;
+	while(sofar < len) {
+		res = read(fd, buf + sofar, len - sofar);
+		if (res < 0)
+			return res;
+		sofar += res;
+	}
+	return sofar;
+}
+
+int main(int argc, char *argv[])
+{
+	unsigned char buf[1024];
+	unsigned char outbuf[2048];
+	int res;
+	int randin;
+	int randout;
+	int hdlcout;
+	int cnt;
+	int hdlccnt;
+	int x;
+	int flags;
+	struct fasthdlc_state transmitter;
+	
+	fasthdlc_precalc();
+	
+	fasthdlc_init(&transmitter, FASTHDLC_MODE_64);
+	
+	randin = open(RANDOM, O_RDONLY);
+	if (randin < 0) {
+		fprintf(stderr, "Unable to open %s: %s\n", RANDOM, strerror(errno));
+		exit(1);
+	}
+	randout = open("random.raw", O_WRONLY|O_TRUNC|O_CREAT, 0666);
+	if (randout < 0) {
+		fprintf(stderr, "Unable to open random.raw: %s\n", strerror(errno));
+		exit(1);
+	}
+	hdlcout = open("random.hdlc", O_WRONLY|O_TRUNC|O_CREAT, 0666);
+	if (hdlcout < 0) {
+		fprintf(stderr, "Unable to open random.hdlc: %s\n", strerror(errno));
+		exit(1);
+	}
+	for (;;) {
+		cnt = (rand() % 256) + 4;	/* Read a pseudo-random amount of stuff */
+		res = myread(randin, buf, cnt);
+		if (res != cnt) {
+			fprintf(stderr, "Tried to read %d bytes, but read %d instead\n", cnt, res);
+			exit(1);
+		}
+		res = write(randout, buf, cnt);
+		if (res != cnt) {
+			fprintf(stderr, "Tried to write %d bytes, but wrote %d instead\n", cnt, res);
+			exit(1);
+		}
+		/* HDLC encode */
+		hdlccnt = 0;
+		/* Start with a flag */
+		fasthdlc_tx_frame(&transmitter);
+		if (transmitter.bits >= 8)
+			outbuf[hdlccnt++] = fasthdlc_tx_run(&transmitter);
+		for (x=0;x<cnt;x++) {
+			res = fasthdlc_tx_load(&transmitter, buf[x]);
+			if (res < 0) {
+				fprintf(stderr, "Unable to load byte :(\n");
+				exit(1);
+			}
+			while(transmitter.bits >= 8)  {
+				outbuf[hdlccnt++] = fasthdlc_tx_run(&transmitter);
+			}
+		}
+		flags = (rand() % 4);
+		for (x=0;x<flags;x++) {
+			if (transmitter.bits < 8)
+				fasthdlc_tx_frame(&transmitter);
+			else
+				fprintf(stderr, "Huh?  Don't need a frame?\n");
+			outbuf[hdlccnt++] = fasthdlc_tx_run(&transmitter);
+		}
+		if (argc > 1)
+			printf("Encoded %d byte message with %d bytes of HDLC and %d extra flags\n", cnt, hdlccnt, flags);
+		res = write(hdlcout, outbuf, hdlccnt);
+		if (res != hdlccnt) {
+			fprintf(stderr, "Tried to write %d HDLC bytes, but wrote %d instead\n", cnt, res);
+			exit(1);
+		}
+		
+	}
+}
diff --git a/hdlcstress.c b/hdlcstress.c
new file mode 100644
index 0000000..6704f1f
--- /dev/null
+++ b/hdlcstress.c
@@ -0,0 +1,233 @@
+/*
+ * Written by Mark Spencer <markster at digium.com>
+ * Based on previous works, designs, and architectures conceived and
+ * written by Jim Dixon <jim at lambdatel.com>.
+ *
+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
+ * Copyright (C) 2001-2008 Digium, Inc.
+ *
+ * All rights reserved.
+ *
+ * Primary Author: Mark Spencer <markster at digium.com>
+ * Radio Support by Jim Dixon <jim at lambdatel.com>
+ */
+
+/*
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2 as published by the
+ * Free Software Foundation. See the LICENSE file included with
+ * this program for more details.
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <linux/types.h>
+#include <linux/ppp_defs.h> 
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <dahdi/user.h>
+
+#define FAST_HDLC_NEED_TABLES
+#include <dahdi/fasthdlc.h>
+
+#include "bittest.h"
+
+
+#include "dahdi_tools_version.h"
+
+/* #define BLOCK_SIZE 2048 */
+#define BLOCK_SIZE 2041
+
+static int hdlcmode = 0;
+static int bri_delay = 0;
+
+
+static unsigned short fcstab[256] =
+{
+	0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+	0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+	0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+	0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+	0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+	0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+	0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+	0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+	0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+	0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+	0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+	0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+	0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+	0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+	0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+	0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+	0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+	0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+	0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+	0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+	0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+	0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+	0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+	0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+	0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+	0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+	0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+	0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+	0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+	0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+	0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+	0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+#define PPP_INITFCS	0xffff	/* Initial FCS value */
+#define PPP_GOODFCS	0xf0b8	/* Good final FCS value */
+#define PPP_FCS(fcs, c)	(((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
+
+void print_packet(unsigned char *buf, int len)
+{
+	int x;
+	printf("{ ");
+	for (x=0;x<len;x++)
+		printf("%02x ",buf[x]);
+	printf("}\n");
+}
+
+static int fd;
+static struct fasthdlc_state fs;
+
+void send_packet(unsigned char *buf, int len)
+{
+	int res;
+	int x;
+	unsigned char outbuf[BLOCK_SIZE];
+	int pos=0;
+	unsigned int fcs = PPP_INITFCS;
+	if (hdlcmode)
+		res = write(fd, buf, len + 2);
+	else {
+		for (x=0;x<len;x++) {
+			if (fasthdlc_tx_load(&fs, buf[x]))
+				printf("Load error\n");
+			fcs = PPP_FCS(fcs, buf[x]);
+			outbuf[pos++] = fasthdlc_tx_run(&fs);
+			if (fs.bits > 7)
+				outbuf[pos++] = fasthdlc_tx_run(&fs);
+		}
+		fcs ^= 0xffff;
+		if (fasthdlc_tx_load(&fs, (fcs & 0xff)))
+			fprintf(stderr, "Load error (fcs1)\n");
+		outbuf[pos++] = fasthdlc_tx_run(&fs);
+		if (fs.bits > 7)
+			outbuf[pos++] = fasthdlc_tx_run(&fs);
+		if (fasthdlc_tx_load(&fs, ((fcs >> 8) & 0xff)))
+			fprintf(stderr, "Load error (fcs2)\n");
+		outbuf[pos++] = fasthdlc_tx_run(&fs);
+		if (fs.bits > 7)
+			outbuf[pos++] = fasthdlc_tx_run(&fs);
+		if (fasthdlc_tx_frame(&fs))
+			fprintf(stderr, "Frame error\n");
+		if (fs.bits > 7)
+			outbuf[pos++] = fasthdlc_tx_run(&fs);
+		if (fs.bits > 7)
+			outbuf[pos++] = fasthdlc_tx_run(&fs);
+		write(fd, outbuf, pos);
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	int res, ch, x;
+	struct dahdi_params tp;
+	struct dahdi_bufferinfo bi;
+	int bs = BLOCK_SIZE;
+	unsigned char c=0;
+	unsigned char outbuf[BLOCK_SIZE];
+
+	while((ch = getopt(argc, argv, "b")) != -1) {
+		switch(ch) {
+			case 'b': bri_delay = 300000; break;
+			case '?': exit(1);
+		}
+	}
+
+	if (argc - optind != 1) {
+		fprintf(stderr, "Usage: %s [-b] <DAHDI device>\n", argv[0]);
+		exit(1);
+	}
+	fd = open(argv[optind], O_RDWR, 0600);
+	if (fd < 0) {
+		fprintf(stderr, "Unable to open %s: %s\n", argv[optind], strerror(errno));
+		exit(1);
+	}
+	if (ioctl(fd, DAHDI_SET_BLOCKSIZE, &bs)) {
+		fprintf(stderr, "Unable to set block size to %d: %s\n", bs, strerror(errno));
+		exit(1);
+	}
+	if (ioctl(fd, DAHDI_GET_PARAMS, &tp)) {
+		fprintf(stderr, "Unable to get channel parameters\n");
+		exit(1);
+	}
+	if ((tp.sigtype & DAHDI_SIG_HDLCRAW) == DAHDI_SIG_HDLCRAW) {
+		printf("In HDLC mode\n");
+		hdlcmode = 1;
+	} else if ((tp.sigtype & DAHDI_SIG_CLEAR) == DAHDI_SIG_CLEAR) {
+		printf("In CLEAR mode\n");
+		hdlcmode = 0;
+	} else {
+		fprintf(stderr, "Not in a reasonable mode\n");
+		exit(1);
+	}
+	res = ioctl(fd, DAHDI_GET_BUFINFO, &bi);
+	if (!res) {
+		bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
+		bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
+		bi.numbufs = 4;
+		res = ioctl(fd, DAHDI_SET_BUFINFO, &bi);
+		if (res < 0) {
+			fprintf(stderr, "Unable to set buf info: %s\n", strerror(errno));
+			exit(1);
+		}
+	} else {
+		fprintf(stderr, "Unable to get buf info: %s\n", strerror(errno));
+		exit(1);
+	}
+	ioctl(fd, DAHDI_GETEVENT);
+	fasthdlc_precalc();
+	fasthdlc_init(&fs, FASTHDLC_MODE_64);
+#if 0
+	print_packet(outbuf, res);
+	printf("FCS is %x, PPP_GOODFCS is %x\n",
+	fcs,PPP_GOODFCS);
+#endif
+	for(;;) {
+		if (c < 1)
+			c = 1;
+		for (x=0;x<50;x++) {
+			outbuf[x] = c;
+		}
+		send_packet(outbuf, 50);
+#if 0
+		printf("Wrote %d of %d bytes\n", res, c);
+#endif		
+		/* The HFC chip can't be bombarded too much. If a write has 
+		   failed, let it recover */
+		if (bri_delay)
+			usleep(bri_delay);
+
+		c = bit_next(c);
+#if 0
+		printf("(%d) Wrote %d bytes\n", packets++, res);
+#endif
+	}
+	
+}
diff --git a/hdlctest.c b/hdlctest.c
new file mode 100644
index 0000000..7358fc1
--- /dev/null
+++ b/hdlctest.c
@@ -0,0 +1,302 @@
+/*
+ * Written by Mark Spencer <markster at digium.com>
+ * Based on previous works, designs, and architectures conceived and
+ * written by Jim Dixon <jim at lambdatel.com>.
+ *
+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
+ * Copyright (C) 2001-2008 Digium, Inc.
+ *
+ * All rights reserved.
+ *
+ * Primary Author: Mark Spencer <markster at digium.com>
+ * Radio Support by Jim Dixon <jim at lambdatel.com>
+ */
+
+/*
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2 as published by the
+ * Free Software Foundation. See the LICENSE file included with
+ * this program for more details.
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <linux/types.h>
+#include <linux/ppp_defs.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <dahdi/user.h>
+
+#define FAST_HDLC_NEED_TABLES
+#include <dahdi/fasthdlc.h>
+
+#include "bittest.h"
+
+#include "dahdi_tools_version.h"
+
+#define BLOCK_SIZE 2039
+
+static unsigned short fcstab[256] =
+{
+	0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+	0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+	0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+	0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+	0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+	0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+	0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+	0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+	0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+	0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+	0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+	0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+	0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+	0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+	0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+	0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+	0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+	0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+	0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+	0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+	0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+	0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+	0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+	0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+	0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+	0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+	0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+	0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+	0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+	0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+	0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+	0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+#define PPP_INITFCS	0xffff	/* Initial FCS value */
+#define PPP_GOODFCS	0xf0b8	/* Good final FCS value */
+#define PPP_FCS(fcs, c)	(((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
+
+void print_packet(unsigned char *buf, int len)
+{
+	int x;
+	printf("{ ");
+	for (x = 0; x < len; x++) {
+		printf("%02x ", buf[x]);
+	}
+	printf("}\n");
+}
+
+static int bytes;
+static int errors;
+static int c;
+
+void dump_bits(unsigned char *outbuf, int len)
+{
+	int x, i;
+	for (x = 0; x < len; x++) {
+		for (i = 0; i < 8; i++) {
+			if (outbuf[x] & (1 << (7 - i))) {
+				printf("1");
+			} else {
+				printf("0");
+			}
+		}
+	}
+	printf("\n");
+}
+
+void dump_bitslong(unsigned int outbuf, int bits)
+{
+	int i;
+	printf("Dumping %d bits from %04x\n", bits, outbuf);
+	for (i = 0; i < bits; i++) {
+		if (outbuf & (1 << (31 - i))) {
+			printf("1");
+		} else {
+			printf("0");
+		}
+	}
+	printf("\n");
+}
+
+int check_frame(unsigned char *outbuf, int res)
+{
+	static int setup = 0;
+	int x;
+	unsigned short fcs = PPP_INITFCS;
+	if (c < 1) {
+		c = 1;
+	}
+	if (!setup) {
+		c = outbuf[0];
+		setup++;
+	}
+	for (x = 0; x < res; x++) {
+		if (outbuf[x] != c && (x < res - 2)) {
+			printf("(Error %d): Unexpected result, %d != %d, position %d %d bytes since last error.\n",
+				   ++errors, outbuf[x], c, x, bytes);
+			if (!x) {
+				c = outbuf[0];
+			}
+			bytes = 0;
+		} else {
+			bytes++;
+		}
+		fcs = PPP_FCS(fcs, outbuf[x]);
+	}
+	if (fcs != PPP_GOODFCS) {
+		printf("FCS Check failed :( (%04x != %04x)\n", fcs, PPP_GOODFCS);
+	}
+#if 0
+	if (res != c) {
+		printf("Res is %d, expected %d\n", res, c+2);
+	}
+#endif
+	c = bit_next(c);
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	int fd;
+	int res, x;
+	struct dahdi_params tp;
+	struct dahdi_bufferinfo bi;
+	int bs = BLOCK_SIZE;
+	int pos = 0;
+	unsigned char inbuf[BLOCK_SIZE];
+	unsigned char outbuf[BLOCK_SIZE];
+	int bytes = 0;
+	int out;
+	unsigned int olddata1;
+	int oldones1;
+	int oldbits1;
+	unsigned int olddata = 0;
+	int oldones = 0;
+	int oldbits = 0;
+	int hdlcmode = 0;
+	struct fasthdlc_state fs;
+	if (argc < 2) {
+		fprintf(stderr, "Usage: %s <DAHDI device>\n", argv[0]);
+		exit(1);
+	}
+	fd = open(argv[1], O_RDWR, 0600);
+	if (fd < 0) {
+		fprintf(stderr, "Unable to open %s: %s\n", argv[1], strerror(errno));
+		exit(1);
+	}
+	if (ioctl(fd, DAHDI_SET_BLOCKSIZE, &bs)) {
+		fprintf(stderr, "Unable to set block size to %d: %s\n", bs, strerror(errno));
+		exit(1);
+	}
+	if (ioctl(fd, DAHDI_GET_PARAMS, &tp)) {
+		fprintf(stderr, "Unable to get channel parameters\n");
+		exit(1);
+	}
+	if ((tp.sigtype & DAHDI_SIG_HDLCRAW) == DAHDI_SIG_HDLCRAW) {
+		printf("In HDLC mode\n");
+		hdlcmode = 1;
+	} else if ((tp.sigtype & DAHDI_SIG_CLEAR) == DAHDI_SIG_CLEAR) {
+		printf("In CLEAR mode\n");
+		hdlcmode = 0;
+	} else {
+		fprintf(stderr, "Not in a reasonable mode\n");
+		exit(1);
+	}
+	res = ioctl(fd, DAHDI_GET_BUFINFO, &bi);
+	if (!res) {
+		bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
+		bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
+		bi.numbufs = 4;
+		res = ioctl(fd, DAHDI_SET_BUFINFO, &bi);
+		if (res < 0) {
+			fprintf(stderr, "Unable to set buf info: %s\n", strerror(errno));
+			exit(1);
+		}
+	} else {
+		fprintf(stderr, "Unable to get buf info: %s\n", strerror(errno));
+		exit(1);
+	}
+	ioctl(fd, DAHDI_GETEVENT);
+	fasthdlc_precalc();
+	fasthdlc_init(&fs, FASTHDLC_MODE_64);
+	for (;;) {
+		res = read(fd, outbuf, sizeof(outbuf));
+		if (hdlcmode) {
+			if (res < 0) {
+				if (errno == ELAST) {
+					if (ioctl(fd, DAHDI_GETEVENT, &x) < 0) {
+						fprintf(stderr, "Unaable to get event: %s\n", strerror(errno));
+						exit(1);
+					}
+					fprintf(stderr, "Event: %d (%d bytes since last error)\n", x, bytes);
+					bytes = 0;
+					continue;
+				} else {
+					fprintf(stderr, "Error: %s\n", strerror(errno));
+					exit(1);
+				}
+			}
+#if 0
+			printf("Res is %d, buf0 is %d, buf1 is %d\n", res, outbuf[0], outbuf[1]);
+#endif
+			if (res < 2) {
+				fprintf(stderr, "Too small?  Only got %d bytes\n", res);
+			}
+			check_frame(outbuf, res);
+		} else {
+			for (x = 0; x < res; x++) {
+				oldones1 = oldones;
+				oldbits1 = oldbits;
+				olddata1 = olddata;
+				oldones = fs.ones;
+				oldbits = fs.bits;
+				olddata = fs.data;
+				fasthdlc_rx_load(&fs, outbuf[x]);
+				out = fasthdlc_rx_run(&fs);
+				if (out & RETURN_EMPTY_FLAG) {
+					/* Empty */
+				} else if (out & RETURN_COMPLETE_FLAG) {
+					if (pos && (pos < 2)) {
+						printf("Too short? (%d)\n", pos);
+					} else if (pos) {
+						check_frame(inbuf, pos);
+					}
+					pos = 0;
+				} else if (out & RETURN_DISCARD_FLAG) {
+					printf("Discard (search = %d, len = %d, buf = %d, x=%d, res=%d, oldones: %d, oldbits: %d)\n",
+						   c, pos, inbuf[0], x, res, oldones, oldbits);
+					dump_bitslong(olddata, oldbits);
+					printf("Discard                                                 oldones: %d, oldbits: %d)\n",
+						   oldones1, oldbits1);
+					dump_bitslong(olddata1, oldbits1);
+					if (x > 64) {
+						dump_bits(outbuf + x - 64, 64);
+						dump_bits(outbuf + x, 64);
+					}
+					pos = 0;
+				} else {
+					if ((out != c) && (pos < c) && !pos) {
+						printf("Warning: Expecting %d at pos %d, got %d (x =%d)\n", c, pos, out, x);
+						if (x > 64) {
+							dump_bits(outbuf + x - 64, 64);
+							dump_bits(outbuf + x, 64);
+						}
+					}
+					inbuf[pos++] = out;
+				}
+			}
+		}
+	}
+
+}
diff --git a/hdlcverify.c b/hdlcverify.c
new file mode 100644
index 0000000..a7401fe
--- /dev/null
+++ b/hdlcverify.c
@@ -0,0 +1,136 @@
+/*
+ * Written by Mark Spencer <markster at digium.com>
+ * Based on previous works, designs, and architectures conceived and
+ * written by Jim Dixon <jim at lambdatel.com>.
+ *
+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
+ * Copyright (C) 2001-2008 Digium, Inc.
+ *
+ * All rights reserved.
+ *
+ * Primary Author: Mark Spencer <markster at digium.com>
+ * Radio Support by Jim Dixon <jim at lambdatel.com>
+ */
+
+/*
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2 as published by the
+ * Free Software Foundation. See the LICENSE file included with
+ * this program for more details.
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#define FAST_HDLC_NEED_TABLES
+#include <dahdi/fasthdlc.h>
+
+#include "dahdi_tools_version.h"
+
+int myread(int fd, unsigned char *buf, int len)
+{
+	int sofar;
+	int res;
+	sofar = 0;
+	while(sofar < len) {
+		res = read(fd, buf + sofar, len - sofar);
+		if (res < 0)
+			return res;
+		sofar += res;
+	}
+	return sofar;
+}
+
+static inline unsigned char nextchar(int fd)
+{
+	static unsigned char inbuf[2048];
+	static int bytes = 0;
+	static int pos = 0;
+	if (pos >= bytes) {
+		pos = 0;
+		bytes = read(fd, inbuf, sizeof(inbuf));
+		if (bytes < 0) {
+			fprintf(stderr, "Unable to read more data: %s\n", strerror(errno));
+			exit(1);
+		}
+		if (bytes == 0) {
+			fprintf(stderr, "-- END OF DATA --\n");
+			exit(0);
+		}
+	}
+	return inbuf[pos++];
+}
+
+int main(int argc, char *argv[])
+{
+	unsigned char decbuf[1024];
+	unsigned char actual[1024];
+	int res;
+	int datain;
+	int hdlcin;
+	int hdlccnt;
+	int x;
+	struct fasthdlc_state receiver;
+	
+	fasthdlc_precalc();
+	
+	fasthdlc_init(&receiver, FASTHDLC_MODE_64);
+	
+	hdlcin = open("random.hdlc", O_RDONLY);
+	if (hdlcin < 0) {
+		fprintf(stderr, "Unable to open %s: %s\n", "random.hdlc", strerror(errno));
+		exit(1);
+	}
+	datain = open("random.raw", O_RDONLY);
+	if (datain < 0) {
+		fprintf(stderr, "Unable to open random.raw: %s\n", strerror(errno));
+		exit(1);
+	}
+	hdlccnt = 0;
+	for (;;) {
+		/* Feed in some input */
+		if (fasthdlc_rx_load(&receiver, nextchar(hdlcin))) {
+			fprintf(stderr, "Unable to feed receiver :(\n");
+			exit(1);
+		}
+		res = fasthdlc_rx_run(&receiver);
+		if (res & RETURN_EMPTY_FLAG)
+			continue;
+		if (res & RETURN_COMPLETE_FLAG) {
+			if (hdlccnt) {
+				if (argc > 1)
+					printf("Got message of length %d\n", hdlccnt);
+				res = myread(datain, actual, hdlccnt);
+				if (res != hdlccnt) {
+					fprintf(stderr, "Tried to read %d bytes, but read %d instead\n", hdlccnt, res);
+					exit(1);
+				}
+				for (x=0;x<hdlccnt;x++) {
+					if (actual[x] != decbuf[x]) {
+						fprintf(stderr, "Found discrepancy at offset %d\n", x);
+						exit(1);
+					}
+				}
+				/* Reset message receiver */
+				hdlccnt = 0;
+			}
+		} else if (res & RETURN_DISCARD_FLAG) {
+			if (1 || hdlccnt) {
+				fprintf(stderr, "Detected abort :(\n");
+				exit(1);
+			}
+		} else {
+			decbuf[hdlccnt++] = res;
+		}
+	}
+}
diff --git a/ifup-hdlc b/ifup-hdlc
new file mode 100644
index 0000000..6602c46
--- /dev/null
+++ b/ifup-hdlc
@@ -0,0 +1,39 @@
+#!/bin/sh
+PATH=/sbin:/usr/sbin:/bin:/usr/bin
+
+cd /etc/sysconfig/network-scripts
+. network-functions
+
+CONFIG=$1
+source_config
+
+if [ "foo$2" = "fooboot" -a "${ONBOOT}" = "no" ]
+then
+	exit
+fi
+
+if [ -z "${MODE}" ]; then
+	echo "No mode specified!"
+	exit
+fi
+
+sethdlc ${DEVICE} mode ${MODE}
+ifconfig ${DEVICE} ${IPADDR} pointopoint ${REMIP}
+route add -net ${NETWORK} netmask ${NETMASK} ${DEVICE}
+
+# this is broken! it's only here to keep compatibility with old RH sytstems
+if [ "${GATEWAY}" != "" -a "${GATEWAY}" != "none" ]
+then
+	route add default gw ${GATEWAY} metric 1 ${DEVICE}
+fi
+
+. /etc/sysconfig/network
+
+if [ "${GATEWAY}" != "" ]; then
+	if [ "${GATEWAYDEV}" = "" -o "${GATEWAYDEV}" = "${DEVICE}" ]; then
+		# set up default gateway
+		route add default gw ${GATEWAY}
+	fi
+fi
+
+/etc/sysconfig/network-scripts/ifup-post $1
diff --git a/init.conf.sample b/init.conf.sample
new file mode 100644
index 0000000..58edec5
--- /dev/null
+++ b/init.conf.sample
@@ -0,0 +1,19 @@
+#
+# Shell settings for Dahdi initialization scripts.
+# This replaces the old/per-platform files (/etc/sysconfig/zaptel,
+# /etc/defaults/zaptel)
+#
+
+# The maximal timeout (seconds) to wait for udevd to finish generating 
+# device nodes after the modules have loaded and before running dahdi_cfg. 
+#DAHDI_DEV_TIMEOUT=40
+
+# A list of modules to unload when stopping.
+# All of their dependencies will be unloaded as well.
+#DAHDI_UNLOAD_MODULES=""		# Disable module unloading
+#DAHDI_UNLOAD_MODULES="dahdi echo"	# If you use OSLEC
+
+# Override settings for xpp_fxloader
+#XPP_FIRMWARE_DIR=/usr/share/dahdi
+#XPP_HOTPLUG_DISABLED=yes
+#XPP_HOTPLUG_DAHDI=yes
diff --git a/install-sh b/install-sh
new file mode 100755
index 0000000..4d4a951
--- /dev/null
+++ b/install-sh
@@ -0,0 +1,323 @@
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2005-05-14.22
+
+# 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.  It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+chmodcmd="$chmodprog 0755"
+chowncmd=
+chgrpcmd=
+stripcmd=
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=
+dst=
+dir_arg=
+dstarg=
+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:
+-c         (ignored)
+-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.
+--help     display this help and exit.
+--version  display version info and exit.
+
+Environment variables override the default commands:
+  CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
+"
+
+while test -n "$1"; do
+  case $1 in
+    -c) shift
+        continue;;
+
+    -d) dir_arg=true
+        shift
+        continue;;
+
+    -g) chgrpcmd="$chgrpprog $2"
+        shift
+        shift
+        continue;;
+
+    --help) echo "$usage"; exit $?;;
+
+    -m) chmodcmd="$chmodprog $2"
+        shift
+        shift
+        continue;;
+
+    -o) chowncmd="$chownprog $2"
+        shift
+        shift
+        continue;;
+
+    -s) stripcmd=$stripprog
+        shift
+        continue;;
+
+    -t) dstarg=$2
+	shift
+	shift
+	continue;;
+
+    -T) no_target_directory=true
+	shift
+	continue;;
+
+    --version) echo "$0 $scriptversion"; exit $?;;
+
+    *)  # When -d is used, all remaining arguments are directories to create.
+	# When -t is used, the destination is already specified.
+	test -n "$dir_arg$dstarg" && break
+        # Otherwise, the last argument is the destination.  Remove it from $@.
+	for arg
+	do
+          if test -n "$dstarg"; then
+	    # $@ is not empty: it contains at least $arg.
+	    set fnord "$@" "$dstarg"
+	    shift # fnord
+	  fi
+	  shift # arg
+	  dstarg=$arg
+	done
+	break;;
+  esac
+done
+
+if test -z "$1"; 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
+
+for src
+do
+  # Protect names starting with `-'.
+  case $src in
+    -*) src=./$src ;;
+  esac
+
+  if test -n "$dir_arg"; then
+    dst=$src
+    src=
+
+    if test -d "$dst"; then
+      mkdircmd=:
+      chmodcmd=
+    else
+      mkdircmd=$mkdirprog
+    fi
+  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 "$dstarg"; then
+      echo "$0: no destination specified." >&2
+      exit 1
+    fi
+
+    dst=$dstarg
+    # Protect names starting with `-'.
+    case $dst in
+      -*) dst=./$dst ;;
+    esac
+
+    # 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: $dstarg: Is a directory" >&2
+	exit 1
+      fi
+      dst=$dst/`basename "$src"`
+    fi
+  fi
+
+  # This sed command emulates the dirname command.
+  dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'`
+
+  # Make sure that the destination directory exists.
+
+  # Skip lots of stat calls in the usual case.
+  if test ! -d "$dstdir"; then
+    defaultIFS='
+	 '
+    IFS="${IFS-$defaultIFS}"
+
+    oIFS=$IFS
+    # Some sh's can't handle IFS=/ for some reason.
+    IFS='%'
+    set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
+    shift
+    IFS=$oIFS
+
+    pathcomp=
+
+    while test $# -ne 0 ; do
+      pathcomp=$pathcomp$1
+      shift
+      if test ! -d "$pathcomp"; then
+        $mkdirprog "$pathcomp"
+	# mkdir can fail with a `File exist' error in case several
+	# install-sh are creating the directory concurrently.  This
+	# is OK.
+	test -d "$pathcomp" || exit
+      fi
+      pathcomp=$pathcomp/
+    done
+  fi
+
+  if test -n "$dir_arg"; then
+    $doit $mkdircmd "$dst" \
+      && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \
+      && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \
+      && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \
+      && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; }
+
+  else
+    dstfile=`basename "$dst"`
+
+    # 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
+    trap '(exit $?); exit' 1 2 13 15
+
+    # Copy the file name to the temp name.
+    $doit $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 "$dsttmp"; } &&
+
+    # Now rename the file to the real destination.
+    { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 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.
+	   {
+	     if test -f "$dstdir/$dstfile"; then
+	       $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \
+	       || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \
+	       || {
+		 echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
+		 (exit 1); exit 1
+	       }
+	     else
+	       :
+	     fi
+	   } &&
+
+	   # Now rename the file to the real destination.
+	   $doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
+	 }
+    }
+  fi || { (exit 1); exit 1; }
+done
+
+# The final little trick to "correctly" pass the exit status to the exit trap.
+{
+  (exit 0); exit 0
+}
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/makeopts.in b/makeopts.in
new file mode 100644
index 0000000..9d01d76
--- /dev/null
+++ b/makeopts.in
@@ -0,0 +1,47 @@
+CC=@CC@
+LD=@LD@
+HOSTCC=@HOSTCC@
+CFLAGS=@CFLAGS@
+LDFLAGS=@LDFLAGS@
+
+INSTALL=@INSTALL@
+GREP=@GREP@
+SHELL=@SHELL@
+LN=@LN@
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+datarootdir = @datarootdir@
+datadir = @datadir@
+includedir = @includedir@
+infodir = @infodir@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+
+DOWNLOAD=@DOWNLOAD@
+
+DAHDI_DEVMODE=@DAHDI_DEVMODE@
+DAHDI_DECLARATION_AFTER_STATEMENT=@DAHDI_DECLARATION_AFTER_STATEMENT@
+
+PBX_NEWT=@PBX_NEWT@
+NEWT_LIB=@NEWT_LIB@
+NEWT_INCLUDE=@NEWT_INCLUDE@
+
+PBX_USB=@PBX_USB@
+USB_LIB=@USB_LIB@
+USB_INCLUDE=@USB_INCLUDE@
+
+DAHDI_INCLUDE=@DAHDI_INCLUDE@
+
+USE_SELINUX=@USE_SELINUX@
+
+PPPD_VERSION=@PPPD_VERSION@
+
+ASCIIDOC=@ASCIIDOC@
diff --git a/modprobe.conf.sample b/modprobe.conf.sample
new file mode 100644
index 0000000..1570d00
--- /dev/null
+++ b/modprobe.conf.sample
@@ -0,0 +1,4 @@
+# You should place any module parameters for your DAHDI modules here
+# Example:
+#
+# options wctdm24xxp latency=6 
diff --git a/modules.sample b/modules.sample
new file mode 100644
index 0000000..96053b3
--- /dev/null
+++ b/modules.sample
@@ -0,0 +1,48 @@
+# Contains the list of modules to be loaded / unloaded by /etc/init.d/dahdi.
+#
+# NOTE:  Please add/edit /etc/modprobe.d/dahdi or /etc/modprobe.conf if you 
+#        would like to add any module parameters.
+#
+# Format of this file: list of modules, each in its own line. 
+# Anything after a '#' is ignore, likewise trailing and leading
+# whitespaces and empty lines.
+
+# Digium TE205P/TE207P/TE210P/TE212P: PCI dual-port T1/E1/J1
+# Digium TE405P/TE407P/TE410P/TE412P: PCI quad-port T1/E1/J1
+# Digium TE220: PCI-Express dual-port T1/E1/J1
+# Digium TE420: PCI-Express quad-port T1/E1/J1
+wct4xxp
+
+# Digium TE120P: PCI single-port T1/E1/J1
+# Digium TE121: PCI-Express single-port T1/E1/J1
+# Digium TE122: PCI single-port T1/E1/J1
+wcte12xp
+
+# Digium T100P: PCI single-port T1
+# Digium E100P: PCI single-port E1
+wct1xxp
+
+# Digium TE110P: PCI single-port T1/E1/J1
+wcte11xp
+
+# Digium TDM2400P/AEX2400: up to 24 analog ports
+# Digium TDM800P/AEX800: up to 8 analog ports
+# Digium TDM410P/AEX410: up to 4 analog ports
+wctdm24xxp
+
+# X100P - Single port FXO interface
+# X101P - Single port FXO interface 
+wcfxo
+
+# Digium TDM400P: up to 4 analog ports
+wctdm
+
+# Digium B410P: 4 NT/TE BRI ports
+wcb4xxp
+
+# Digium TC400B: G729 / G723 Transcoding Engine
+wctc4xxp
+
+# Xorcom Astribank Devices
+xpp_usb
+
diff --git a/patgen.c b/patgen.c
new file mode 100644
index 0000000..e816dd9
--- /dev/null
+++ b/patgen.c
@@ -0,0 +1,164 @@
+/*
+ * Written by Mark Spencer <markster at digium.com>
+ * Based on previous works, designs, and architectures conceived and
+ * written by Jim Dixon <jim at lambdatel.com>.
+ *
+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
+ * Copyright (C) 2001-2008 Digium, Inc.
+ *
+ * All rights reserved.
+ *
+ * Primary Author: Mark Spencer <markster at digium.com>
+ * Radio Support by Jim Dixon <jim at lambdatel.com>
+ */
+
+/*
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2 as published by the
+ * Free Software Foundation. See the LICENSE file included with
+ * this program for more details.
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <linux/types.h>
+#include <linux/ppp_defs.h> 
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "bittest.h"
+
+#include <dahdi/user.h>
+#include "dahdi_tools_version.h"
+
+/* #define BLOCK_SIZE 2048 */
+#define BLOCK_SIZE 2041
+#define DEVICE	  "/dev/dahdi/channel"
+
+static const char	rcsid[] = "$Id$";
+char			*prog_name;
+
+static void usage(void)
+{
+	fprintf(stderr, "Usage: %s <dahdi_chan>\n", prog_name);
+	fprintf(stderr, "   e.g.: %s /dev/dahdi/55\n", prog_name);
+	fprintf(stderr, "         %s 455\n", prog_name);
+	fprintf(stderr, "%s version %s\n", prog_name, rcsid);
+	exit(1);
+}
+
+void print_packet(unsigned char *buf, int len)
+{
+	int x;
+	printf("{ ");
+	for (x=0;x<len;x++)
+		printf("%02x ",buf[x]);
+	printf("}\n");
+}
+
+int channel_open(char *name, int *bs)
+{
+	int 			channo;
+	int			fd;
+	struct 			dahdi_params tp;
+	char 			*dev;
+
+	channo = atoi(name);
+	/* channo==0: The user passed a file name to be opened. */
+	dev = channo ? DEVICE : name;
+
+	fd = open(dev, O_RDWR, 0600);
+
+	if (fd < 0) {
+		perror(DEVICE);
+		return -1;
+	}
+
+	/* If we got a channel number, get it from /dev/dahdi/channel: */
+	if(channo && ioctl(fd, DAHDI_SPECIFY, &channo) < 0) {
+		perror("SPECIFY");
+		return -1;
+	}
+	if(ioctl(fd, DAHDI_SET_BLOCKSIZE, bs) < 0) {
+		perror("SET_BLOCKSIZE");
+		return -1;
+	}
+
+	if (ioctl(fd, DAHDI_GET_PARAMS, &tp)) {
+		fprintf(stderr, "Unable to get channel parameters\n");
+		return -1;
+	}
+
+	return fd;
+}
+
+int main(int argc, char *argv[])
+{
+	int fd;
+	int res, res1, x;
+	int bs = BLOCK_SIZE;
+	unsigned char c=0;
+	unsigned char outbuf[BLOCK_SIZE];
+
+	prog_name = argv[0];
+
+	if (argc < 2) {
+		usage();
+	}
+
+	fd = channel_open(argv[1], &bs);
+	if (fd < 0)
+		exit(1);
+
+	ioctl(fd, DAHDI_GETEVENT);
+#if 0
+	print_packet(outbuf, res);
+	printf("FCS is %x, PPP_GOODFCS is %x\n",
+	fcs,PPP_GOODFCS);
+#endif
+	for(;;) {
+		res = bs;
+		for (x=0;x<bs;x++) {
+			outbuf[x] = c;
+			c = bit_next(c);
+		}
+		res1 = write(fd, outbuf, res);
+		if (res1 < res) {
+			int e;
+			struct dahdi_spaninfo zi;
+			res = ioctl(fd,DAHDI_GETEVENT,&e);
+			if (res == -1)
+			{
+				perror("DAHDI_GETEVENT");
+				exit(1);
+			}
+			if (e == DAHDI_EVENT_NOALARM)
+				printf("ALARMS CLEARED\n");
+			if (e == DAHDI_EVENT_ALARM)
+			{
+				zi.spanno = 0;
+				res = ioctl(fd,DAHDI_SPANSTAT,&zi);
+				if (res == -1)
+				{
+					perror("DAHDI_SPANSTAT");
+					exit(1);
+				}
+				printf("Alarm mask %x hex\n",zi.alarms);
+			}
+			continue;
+		}
+#if 0
+		printf("(%d) Wrote %d bytes\n", packets++, res);
+#endif
+	}
+	
+}
diff --git a/patlooptest.c b/patlooptest.c
new file mode 100644
index 0000000..4be399c
--- /dev/null
+++ b/patlooptest.c
@@ -0,0 +1,295 @@
+/*
+ * Written by Mark Spencer <markster at digium.com>
+ * Based on previous works, designs, and architectures conceived and
+ * written by Jim Dixon <jim at lambdatel.com>.
+ *
+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
+ * Copyright (C) 2001-2008 Digium, Inc.
+ *
+ * All rights reserved.
+ *
+ * Primary Author: Mark Spencer <markster at digium.com>
+ * Radio Support by Jim Dixon <jim at lambdatel.com>
+ */
+
+/*
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2 as published by the
+ * Free Software Foundation. See the LICENSE file included with
+ * this program for more details.
+ */
+
+/*
+ *	This test sends a set of incrementing byte values out the specified
+ * dadhi device.  The device is then read back and the read back characters
+ * are verified that they increment as well.
+ * 	If there is a break in the incrementing pattern, an error is flagged 
+ * and the comparison starts at the last value read. 
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include <dahdi/user.h>
+#include "dahdi_tools_version.h"
+
+#define BLOCK_SIZE	2039
+
+#define CONTEXT_SIZE	7
+/* Prints a set of bytes in hex format */
+static void print_packet(unsigned char *buf, int len)
+{
+	int x;
+	printf("{ ");
+	for (x=0;x<len;x++)
+		printf("%02x ",buf[x]);
+	printf("}\n");
+}
+
+/* Shows data immediately before and after the specified byte to provide context for an error */
+static void show_error_context(unsigned char *buf, int offset, int bufsize)
+{
+	int low;
+	int total = CONTEXT_SIZE;
+
+	if (offset >= bufsize || 0 >= bufsize || 0 > offset ) {
+		return;
+	}
+	
+	low = offset - (CONTEXT_SIZE-1)/2;
+	if (0 > low) {
+		total += low;
+		low = 0;
+	}
+	if (low + total > bufsize) {
+		total = bufsize - low;
+	}
+	buf += low;
+	printf("Offset %d  ", low);
+	print_packet(buf, total);
+	return;
+}
+
+/* Shows how the program can be invoked */
+static void usage(const char * progname)
+{
+	printf("%s: Pattern loop test\n", progname);
+	printf("Usage:  %s <dahdi device> [-t <secs>] [-r <count>] [-b <count>] [-vh?] \n", progname);
+	printf("\t-? - Print this usage summary\n");
+	printf("\t-t <secs> - # of seconds for the test to run\n");
+	printf("\t-r <count> - # of test loops to run before a summary is printed\n");
+	printf("\t-s <count> - # of writes to skip before testing for results\n");
+	printf("\t-v - Verbosity (repetitive v's add to the verbosity level e.g. -vvvv)\n");
+	printf("\t-b <# buffer bytes> - # of bytes to display from buffers on each pass\n");
+	printf("\n\t Also accepts old style usage:\n\t  %s <device name> [<timeout in secs>]\n", progname);
+}
+
+int main(int argc, char *argv[])
+{
+	int fd;
+	int res, x;
+	int i;
+	struct dahdi_params tp;
+	int bs = BLOCK_SIZE;
+	int skipcount = 10;
+	unsigned char c=0,c1=0;
+	unsigned char inbuf[BLOCK_SIZE];
+	unsigned char outbuf[BLOCK_SIZE];
+	int setup=0;
+	unsigned long bytes=0;
+	int timeout=0;
+	int loop_errorcount;
+	int reportloops = 0;
+	int buff_disp = 0; 
+	unsigned long currentloop = 0;
+	unsigned long total_errorcount = 0;
+	int verbose = 0; 
+	char * device;
+	int opt;
+	int oldstyle_cmdline = 1;
+
+	/* Parse the command line arguments */
+	while((opt = getopt(argc, argv, "b:s:t:r:v?h")) != -1) {
+		switch(opt) {
+		case 'h':
+		case '?':
+			usage(argv[0]);
+			exit(1);
+			break;
+		case 'b':
+			buff_disp = strtoul(optarg, NULL, 10);
+			if (BLOCK_SIZE < buff_disp) {
+				buff_disp = BLOCK_SIZE;
+			}
+			oldstyle_cmdline = 0;
+			break;
+		case 'r':
+			reportloops = strtoul(optarg, NULL, 10);
+			oldstyle_cmdline = 0;
+			break;
+		case 's':
+			skipcount = strtoul(optarg, NULL, 10);
+			oldstyle_cmdline = 0;
+			break;
+		case 't':
+			timeout = strtoul(optarg, NULL, 10);
+			oldstyle_cmdline = 0;
+			break;
+		case 'v':
+			verbose++;
+			oldstyle_cmdline = 0;
+			break;
+		}
+	}
+
+	/* If no device was specified */
+	if(NULL == argv[optind]) {
+		printf("You need to supply a dahdi device to test\n");
+		usage(argv[0]);
+		exit (1);
+	}
+
+	/* Get the dahdi device name */
+	if (argv[optind])
+		device = argv[optind];
+
+	/* To maintain backward compatibility with previous versions process old style command line */
+	if (oldstyle_cmdline && argc > optind +1) {
+		timeout = strtoul(argv[optind+1], NULL, 10);
+	}
+	
+	time_t start_time = 0;
+
+	fd = open(device, O_RDWR, 0600);
+	if (fd < 0) {
+		fprintf(stderr, "Unable to open %s: %s\n", device, strerror(errno));
+		exit(1);
+	}
+	if (ioctl(fd, DAHDI_SET_BLOCKSIZE, &bs)) {
+		fprintf(stderr, "Unable to set block size to %d: %s\n", bs, strerror(errno));
+		exit(1);
+	}
+	if (ioctl(fd, DAHDI_GET_PARAMS, &tp)) {
+		fprintf(stderr, "Unable to get channel parameters\n");
+		exit(1);
+	}
+	ioctl(fd, DAHDI_GETEVENT);
+
+	i = DAHDI_FLUSH_ALL;
+	if (ioctl(fd,DAHDI_FLUSH,&i) == -1) {
+		perror("DAHDI_FLUSH");
+		exit(255);
+	}
+
+	/* Mark time if program has a specified timeout */
+	if(0 < timeout){
+		start_time = time(NULL);
+		printf("Using Timeout of %d Seconds\n",timeout);
+	}
+
+	/* ********* MAIN TESTING LOOP ************ */
+	for(;;) {
+		/* Prep the data and write it out to dahdi device */
+		res = bs;
+		for (x = 0; x < bs; x++) {
+			outbuf[x] = c1++;
+		}
+
+		res = write(fd,outbuf,bs);
+		if (res != bs) {
+			printf("Res is %d: %s\n", res, strerror(errno));
+			ioctl(fd, DAHDI_GETEVENT, &x);
+			printf("Event: %d\n", x);
+			exit(1);
+		}
+
+		/* If this is the start of the test then skip a number of packets before test results */
+		if (skipcount) {
+			if (skipcount > 1) {
+				res = read(fd,inbuf,bs);
+			}
+			skipcount--;
+			if (!skipcount) {
+				printf("Going for it...\n");
+			}
+			continue;
+		}
+
+		res = read(fd, inbuf, bs);
+		if (res < bs) {
+			printf("read error: returned %d\n", res);
+			exit(1);
+		}
+		/* If first time through, set byte that is used to test further bytes */
+		if (!setup) {
+			c = inbuf[0];
+			setup++;
+		}
+		/* Test the packet read back for data pattern */
+		loop_errorcount = 0;
+		for (x = 0; x < bs; x++)  {
+			/* if error */
+			if (inbuf[x] != c) {
+				total_errorcount++;
+				loop_errorcount++;
+				if (oldstyle_cmdline) {
+					printf("(Error %ld): Unexpected result, %d != %d, %ld bytes since last error.\n", total_errorcount, inbuf[x],c, bytes);
+				} else {
+					if (1 <= verbose) {
+						printf("Error %ld (loop %ld, offset %d, error %d): Unexpected result, Read: 0x%02x, Expected 0x%02x.\n",
+							total_errorcount,
+							currentloop,
+							x,
+							loop_errorcount,
+							inbuf[x],
+							c);
+					}
+					if (2 <= verbose) {
+						show_error_context(inbuf, x, bs);
+					}
+				}
+				/* Reset the expected data to what was just read.  so test can resynch on skipped data */
+				c = inbuf[x];
+				bytes=0;  /* Reset the count from the last encountered error */
+			}
+			c++;
+			bytes++;
+		}
+		/* If the user wants to see some of each buffer transaction */
+		if (0 < buff_disp) {
+			printf("Buffer Display %d (errors =%d)\nIN: ", buff_disp, loop_errorcount);
+			print_packet(inbuf, 64);
+			printf("OUT:");
+			print_packet(outbuf, 64);
+		}
+		
+		currentloop++;
+		/* Update stats if the user has specified it */
+		if (0 < reportloops && 0 == (currentloop % reportloops)) {
+			printf("Status on loop %lu:  Total errors = %lu\n", currentloop, total_errorcount);
+			
+		}
+#if 0
+		printf("(%d) Wrote %d bytes\n", packets++, res);
+#endif
+		if(timeout && (time(NULL)-start_time) > timeout){
+			printf("Timeout achieved Ending Program\n");
+			printf("Test ran %ld loops of %d bytes/loop with %ld errors\n", currentloop, bs, total_errorcount);
+			return total_errorcount;
+		}
+	}
+	
+}
diff --git a/pattest.c b/pattest.c
new file mode 100644
index 0000000..7e33a5c
--- /dev/null
+++ b/pattest.c
@@ -0,0 +1,170 @@
+/*
+ * Written by Mark Spencer <markster at digium.com>
+ * Based on previous works, designs, and architectures conceived and
+ * written by Jim Dixon <jim at lambdatel.com>.
+ *
+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
+ * Copyright (C) 2001-2008 Digium, Inc.
+ *
+ * All rights reserved.
+ *
+ * Primary Author: Mark Spencer <markster at digium.com>
+ * Radio Support by Jim Dixon <jim at lambdatel.com>
+ */
+
+/*
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2 as published by the
+ * Free Software Foundation. See the LICENSE file included with
+ * this program for more details.
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <linux/types.h>
+#include <linux/ppp_defs.h> 
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "bittest.h"
+
+#include <dahdi/user.h>
+#include "dahdi_tools_version.h"
+
+#define BLOCK_SIZE 2039
+#define DEVICE	  "/dev/dahdi/channel"
+
+static const char	rcsid[] = "$Id$";
+char			*prog_name;
+
+static void usage(void)
+{
+	fprintf(stderr, "Usage: %s <dahdi_chan>\n", prog_name);
+	fprintf(stderr, "   e.g.: %s /dev/dahdi/55\n", prog_name);
+	fprintf(stderr, "         %s 455\n", prog_name);
+	fprintf(stderr, "%s version %s\n", prog_name, rcsid);
+	exit(1);
+}
+
+void print_packet(unsigned char *buf, int len)
+{
+	int x;
+	printf("{ ");
+	for (x=0;x<len;x++)
+		printf("%02x ",buf[x]);
+	printf("}\n");
+}
+
+int channel_open(char *name, int *bs)
+{
+	int 			channo;
+	int			fd;
+	struct 			dahdi_params tp;
+	char 			*dev;
+
+	channo = atoi(name);
+	/* channo==0: The user passed a file name to be opened. */
+	dev = channo ? DEVICE : name;
+
+	fd = open(dev, O_RDWR, 0600);
+
+	if (fd < 0) {
+		perror(DEVICE);
+		return -1;
+	}
+
+	/* If we got a channel number, get it from /dev/dahdi/channel: */
+	if(channo && ioctl(fd, DAHDI_SPECIFY, &channo) < 0) {
+		perror("SPECIFY");
+		return -1;
+	}
+	if(ioctl(fd, DAHDI_SET_BLOCKSIZE, bs) < 0) {
+		perror("SET_BLOCKSIZE");
+		return -1;
+	}
+
+	if (ioctl(fd, DAHDI_GET_PARAMS, &tp)) {
+		fprintf(stderr, "Unable to get channel parameters\n");
+		return -1;
+	}
+
+	return fd;
+}
+
+int main(int argc, char *argv[])
+{
+	int fd;
+	int res, x;
+	int bs = BLOCK_SIZE;
+	unsigned char c=0;
+	unsigned char outbuf[BLOCK_SIZE];
+	int setup=0;
+	int errors=0;
+	int bytes=0;
+
+	prog_name = argv[0];
+
+	if (argc < 2) {
+		usage();
+	}
+
+	fd = channel_open(argv[1], &bs);
+	if (fd < 0)
+		exit(1);
+
+	ioctl(fd, DAHDI_GETEVENT);
+	for(;;) {
+		res = bs;
+		res = read(fd, outbuf, res);
+		if (res < bs) {
+			int e;
+			struct dahdi_spaninfo zi;
+			res = ioctl(fd,DAHDI_GETEVENT,&e);
+			if (res == -1)
+			{
+				perror("DAHDI_GETEVENT");
+				exit(1);
+			}
+			if (e == DAHDI_EVENT_NOALARM)
+				printf("ALARMS CLEARED\n");
+			if (e == DAHDI_EVENT_ALARM)
+			{
+				zi.spanno = 0;
+				res = ioctl(fd,DAHDI_SPANSTAT,&zi);
+				if (res == -1)
+				{
+					perror("DAHDI_SPANSTAT");
+					exit(1);
+				}
+				printf("Alarm mask %x hex\n",zi.alarms);
+			}
+			continue;
+		}
+		if (!setup) {
+			c = outbuf[0];
+			setup++;
+		}
+		for (x=0;x<bs;x++)  {
+			if (outbuf[x] != c) {
+				printf("(Error %d): Unexpected result, %d != %d, %d bytes since last error.\n", ++errors, outbuf[x], c, bytes); 
+				c = outbuf[x];
+				bytes=0;
+			}
+			c = bit_next(c);
+			bytes++;
+		}
+#if 0
+		printf("(%d) Wrote %d bytes\n", packets++, res);
+#endif
+	}
+	
+}
diff --git a/ppp/Makefile b/ppp/Makefile
new file mode 100644
index 0000000..0ff55c2
--- /dev/null
+++ b/ppp/Makefile
@@ -0,0 +1,29 @@
+#COPTS	= -O2 -g
+
+-include ../makeopts
+
+CFLAGS		+= $(COPTS) -fPIC
+LDFLAGS		+= -shared
+
+INCLUDE_DIR	= $(includedir)/pppd
+
+LIBDIR		= $(libdir)/pppd/$(PPPD_VERSION)
+
+PLUGINS := dahdi.so
+
+all:	$(PLUGINS)
+
+%.so: %.c
+ifeq (,$(PPPD_VERSION))
+	@echo "pppd version not found (in patchlevel.h)."
+	@echo "Install ppp source/headers and/or ./configure --with-ppp=PATH."
+	exit 1
+endif
+	$(CC) -o $@ $(CFLAGS) $^ $(LDFLAGS) 
+
+install: $(PLUGINS)
+	$(INSTALL) -d $(DESTDIR)$(LIBDIR)
+	$(INSTALL) -m 0644 $? $(DESTDIR)$(LIBDIR)
+
+clean:
+	rm -f *.o *.so *.a
diff --git a/ppp/dahdi.c b/ppp/dahdi.c
new file mode 100644
index 0000000..6991ccf
--- /dev/null
+++ b/ppp/dahdi.c
@@ -0,0 +1,293 @@
+/* dahdi.c - pppd plugin to implement PPP over DAHDI HDLC channel.
+ *
+ * Copyright 2002  Digium, Inc. 
+ *		   Mark Spencer <markster at digium.inc>
+ *
+ * Borrows from PPPoE by Michal Ostrowski <mostrows at styx.uwaterloo.ca>,
+ *		  Jamal Hadi Salim <hadi at cyberus.ca>
+ *
+ * which in turn...
+ *
+ * Borrows heavily from the PPPoATM plugin by Mitchell Blank Jr.,
+ * which is based in part on work from Jens Axboe and Paul Mackerras.
+ *
+ */
+
+/*
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2 as published by the
+ * Free Software Foundation. See the LICENSE file included with
+ * this program for more details.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <pppd/pppd.h>
+#include <pppd/fsm.h>
+#include <pppd/lcp.h>
+#include <pppd/ipcp.h>
+#include <pppd/ccp.h>
+#include <pppd/pathnames.h>
+
+#include <dahdi/user.h>
+
+extern int new_style_driver;
+
+const char pppd_version[] = VERSION;
+
+#define _PATH_DAHDI_OPT         _ROOT_PATH "/etc/ppp/options."
+
+#define DAHDI_MTU	(DAHDI_DEFAULT_MTU_MRU - 16)
+extern int kill_link;
+int     retries = 0;
+
+int setdevname_dahdi(const char *cp);
+
+static option_t dahdi_options[] = {
+	{ "device name", o_wild, (void *) &setdevname_dahdi,
+	  "Serial port device name",
+	  OPT_DEVNAM | OPT_PRIVFIX | OPT_NOARG  | OPT_A2STRVAL | OPT_STATIC,
+	  devnam},
+	{ NULL }
+};
+
+static int dahdi_fd = -1;
+static int dahdi_chan = 0;
+
+static int connect_dahdi(void)
+{
+    
+    struct dahdi_params dahdi_params;
+    int res;
+    int x;
+
+    info("DAHDI device is '%s'\n", devnam);
+
+    strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam));
+
+    if (strlen(devnam) && strcmp(devnam, "stdin")) {
+	/* Get the channel number */
+	dahdi_chan = atoi(devnam);
+	if (dahdi_chan < 1) {
+		fatal("'%s' is not a valid device name\n", devnam);
+		return -1;
+	}
+
+	/* Open /dev/dahdi/channel interface */
+	dahdi_fd = open("/dev/dahdi/channel", O_RDWR);
+	if (dahdi_fd < 0) {
+		fatal("Unable to open DAHDI channel interface: '%s'\n", strerror(errno));
+		return dahdi_fd;
+	}
+
+	/* Specify which channel we really want */
+	x = dahdi_chan;
+	res = ioctl(dahdi_fd, DAHDI_SPECIFY, &x);
+	if (res) {
+		fatal("Unable to specify channel %d: %s\n", dahdi_chan, strerror(errno));
+		close(dahdi_fd);
+		dahdi_fd = -1;
+		return -1;
+	}
+    } else
+        dahdi_fd = STDIN_FILENO;
+
+
+    /* Get channel parameters */
+    memset(&dahdi_params, 0, sizeof(dahdi_params));
+    dahdi_params.channo = -1;
+
+    res = ioctl(dahdi_fd, DAHDI_GET_PARAMS, &dahdi_params);
+
+    if (res) {
+	fatal("Device '%s' does not appear to be a DAHDI device\n", devnam ? devnam : "<stdin>");
+    }
+
+    x = 1;
+
+    /* Throw into HDLC/PPP mode */
+    res = ioctl(dahdi_fd, DAHDI_HDLCPPP, &x);
+
+    if (res) {
+	fatal("Unable to put device '%s' into HDLC mode\n", devnam);
+	close(dahdi_fd);
+	dahdi_fd = -1;
+	return -1;
+    }
+
+    /* Once the logging is fixed, print a message here indicating
+       connection parameters */
+    dahdi_chan = dahdi_params.channo;
+    info("Connected to DAHDI device '%s' (%d)\n", dahdi_params.name, dahdi_params.channo);
+
+    return dahdi_fd;
+}
+
+static void disconnect_dahdi(void)
+{
+    int res;
+    int x = 0;
+    /* Throw out of HDLC mode */
+    res = ioctl(dahdi_fd, DAHDI_HDLCPPP, &x);
+
+    if (res) {
+	warn("Unable to take device '%s' out of HDLC mode\n", devnam);
+    }
+
+    /* Close if it's not stdin */
+    if (strlen(devnam))
+	close(dahdi_fd);
+    warn("Disconnect from DAHDI");
+
+}
+
+
+static int setspeed_dahdi(const char *cp)
+{
+    return 0;
+}
+
+static void dahdi_extra_options()
+{
+    int ret;
+    char buf[256];
+    snprintf(buf, 256, _PATH_DAHDI_OPT "%s",devnam);
+    if(!options_from_file(buf, 0, 0, 1))
+	exit(EXIT_OPTION_ERROR);
+
+}
+
+
+
+static void send_config_dahdi(int mtu,
+			      u_int32_t asyncmap,
+			      int pcomp,
+			      int accomp)
+{
+    int sock;
+
+    if (mtu > DAHDI_MTU) {
+	warn("Couldn't increase MTU to %d.", mtu);
+	mtu = DAHDI_MTU;
+    }
+}
+
+
+static void recv_config_dahdi(int mru,
+			      u_int32_t asyncmap,
+			      int pcomp,
+			      int accomp)
+{
+    if (mru > DAHDI_MTU)
+	error("Couldn't increase MRU to %d", mru);
+}
+
+static void set_xaccm_pppoe(int unit, ext_accm accm)
+{
+    /* NOTHING */
+}
+
+
+
+struct channel dahdi_channel;
+
+/* Check is cp is a valid DAHDI device
+ * return either 1 if "cp" is a reasonable thing to name a device
+ * or die.
+ * Note that we don't actually open the device at this point
+ * We do need to fill in:
+ *   devnam: a string representation of the device
+ */
+
+int (*old_setdevname_hook)(const char* cp) = NULL;
+int setdevname_dahdi(const char *cp)
+{
+    int ret;
+    int chan;
+
+    /* If already set, forgoe */
+    if (strlen(devnam))
+	return 1;
+
+
+    if (strcmp(cp, "stdin")) {
+	ret = sscanf(cp, "%d", &chan);
+	if (ret != 1) {
+		fatal("DAHDI: Invalid channel: '%s'\n", cp);
+		return -1;
+	}
+    }
+
+    dahdi__copy_string(devnam, cp, sizeof(devnam));
+
+    info("Using DAHDI device '%s'\n", devnam);
+
+    ret = 1;
+
+    if( ret == 1 && the_channel != &dahdi_channel ){
+
+	the_channel = &dahdi_channel;
+
+	modem = 0;
+
+	lcp_allowoptions[0].neg_accompression = 0;
+	lcp_wantoptions[0].neg_accompression = 0;
+
+	lcp_allowoptions[0].neg_pcompression = 0;
+	lcp_wantoptions[0].neg_pcompression = 0;
+
+	ccp_allowoptions[0].deflate = 0 ;
+	ccp_wantoptions[0].deflate = 0 ;
+
+	ipcp_allowoptions[0].neg_vj=0;
+	ipcp_wantoptions[0].neg_vj=0;
+
+	ccp_allowoptions[0].bsd_compress = 0;
+	ccp_wantoptions[0].bsd_compress = 0;
+
+	lcp_allowoptions[0].neg_asyncmap = 0;
+	lcp_wantoptions[0].neg_asyncmap = 0;
+
+    }
+    return ret;
+}
+
+
+
+void plugin_init(void)
+{
+    if (!ppp_available() && !new_style_driver)
+	fatal("Kernel doesn't support ppp_generic needed for DAHDI PPP");
+    add_options(dahdi_options);
+
+    info("DAHDI Plugin Initialized");
+}
+
+struct channel dahdi_channel = {
+    options: dahdi_options,
+    process_extra_options: &dahdi_extra_options,
+    check_options: NULL,
+    connect: &connect_dahdi,
+    disconnect: &disconnect_dahdi,
+    establish_ppp: &generic_establish_ppp,
+    disestablish_ppp: &generic_disestablish_ppp,
+    send_config: &send_config_dahdi,
+    recv_config: &recv_config_dahdi,
+    close: NULL,
+    cleanup: NULL
+};
+
diff --git a/sethdlc.c b/sethdlc.c
new file mode 100644
index 0000000..cc0517c
--- /dev/null
+++ b/sethdlc.c
@@ -0,0 +1,704 @@
+/*
+ * sethdlc.c
+ *
+ * Copyright (C) 1999 - 2002 Krzysztof Halasa <khc at pm.waw.pl>
+ *
+ */
+
+/*
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2 as published by the
+ * Free Software Foundation. See the LICENSE file included with
+ * this program for more details.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <asm/types.h>
+#include <linux/hdlc.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <linux/sockios.h>
+
+#include <dahdi/user.h>
+#include "dahdi_tools_version.h"
+
+#if GENERIC_HDLC_VERSION != 4
+#error Generic HDLC layer version mismatch, please get correct sethdlc.c
+#endif
+
+#if !defined(IF_PROTO_HDLC_ETH) || !defined(IF_PROTO_FR_ETH_PVC)
+#warning "No kernel support for Ethernet over Frame Relay / HDLC, skipping it"
+#endif
+
+
+static struct ifreq req;	/* for ioctl */
+static int argc;
+static char **argv;
+int sock;
+
+
+static void error(const char *format, ...) __attribute__ ((noreturn, format(printf, 1, 2)));
+
+static void error(const char *format, ...)
+{
+	va_list args;
+
+	va_start(args, format);
+	fprintf(stderr, "%s: ", req.ifr_name);
+	vfprintf(stderr, format, args);
+	va_end(args);
+	exit(1);
+}
+
+
+
+typedef struct {
+	const char *name;
+	const unsigned int value;
+} parsertab;
+
+
+
+static int checkkey(const char* name)
+{
+	if (argc < 1)
+		return -1;	/* no enough parameters */
+
+	if (strcmp(name, argv[0]))
+		return -1;
+	argc--;
+	argv++;
+	return 0;
+}
+
+
+
+static int checktab(parsertab *tab, unsigned int *value)
+{
+	int i;
+
+	if (argc < 1)
+		return -1;	/* no enough parameters */
+	
+	for (i = 0; tab[i].name; i++)
+		if (!strcmp(tab[i].name, argv[0])) {
+			argc--;
+			argv++;
+			*value = tab[i].value;
+			return 0;
+		}
+
+	return -1;		/* Not found */
+}
+
+
+
+static const char* tabstr(unsigned int value, parsertab *tab,
+			  const char* unknown)
+{
+	int i;
+	for (i = 0; tab[i].name; i++)
+		if (tab[i].value == value)
+			return tab[i].name;
+
+	return unknown;		/* Not found */
+}
+
+
+
+static unsigned int match(const char* name, unsigned int *value,
+			  unsigned int minimum, unsigned int maximum)
+{
+	char test;
+
+	if (argc < 1)
+		return -1;	/* no enough parameters */
+
+	if (name) {
+		if (strcmp(name, argv[0]))
+			return -1;
+		argc--;
+		argv++;
+	}
+
+	if (argc < 1)
+		error("Missing parameter\n");
+
+	if (sscanf(argv[0], "%u%c", value, &test) != 1)
+		error("Invalid parameter: %s\n", argv[0]);
+
+	if ((*value > maximum) || (*value < minimum))
+		error("Parameter out of range [%u - %u]: %u\n",
+		      minimum, maximum, *value);
+
+	argc--;
+	argv++;
+	return 0;
+}
+
+
+static parsertab ifaces[] = {{ "v35", IF_IFACE_V35 },
+			     { "v24", IF_IFACE_V24 },
+			     { "x21", IF_IFACE_X21 },
+			     { "e1", IF_IFACE_E1 },
+			     { "t1", IF_IFACE_T1 },
+			     { NULL, 0 }};
+
+static parsertab clocks[] = {{ "int", CLOCK_INT },
+			     { "ext", CLOCK_EXT },
+			     { "txint", CLOCK_TXINT },
+			     { "txfromrx", CLOCK_TXFROMRX },
+			     { NULL, 0 }};
+
+
+static parsertab protos[] = {{ "hdlc", IF_PROTO_HDLC},
+			     { "cisco", IF_PROTO_CISCO},
+			     { "fr", IF_PROTO_FR},
+			     { "ppp", IF_PROTO_PPP},
+			     { "x25", IF_PROTO_X25},
+#ifdef IF_PROTO_HDLC_ETH
+			     { "hdlc-eth", IF_PROTO_HDLC_ETH},
+#endif
+			     { NULL, 0 }};
+
+
+static parsertab hdlc_enc[] = {{ "nrz", ENCODING_NRZ },
+			       { "nrzi", ENCODING_NRZI },
+			       { "fm-mark", ENCODING_FM_MARK },
+			       { "fm-space", ENCODING_FM_SPACE },
+			       { "manchester", ENCODING_MANCHESTER },
+			       { NULL, 0 }};
+
+static parsertab hdlc_par[] = {{ "no-parity", PARITY_NONE },
+			       { "crc16", PARITY_CRC16_PR1 },
+			       { "crc16-pr0", PARITY_CRC16_PR0 },
+			       { "crc16-itu", PARITY_CRC16_PR1_CCITT },
+			       { "crc16-itu-pr0", PARITY_CRC16_PR0_CCITT },
+			       { "crc32-itu", PARITY_CRC32_PR1_CCITT },
+			       { NULL, 0 }};
+
+static parsertab lmi[] = {{ "none", LMI_NONE },
+			  { "ansi", LMI_ANSI },
+			  { "ccitt", LMI_CCITT },
+			  { NULL, 0 }};
+
+
+static void set_iface(void)
+{
+	int orig_argc = argc;
+	te1_settings te1;
+
+	memset(&te1, 0, sizeof(te1));
+	req.ifr_settings.type = IF_IFACE_SYNC_SERIAL;
+
+	while (argc > 0) {
+		if (req.ifr_settings.type == IF_IFACE_SYNC_SERIAL)
+			if (!checktab(ifaces, &req.ifr_settings.type))
+				continue;
+
+		if (!te1.clock_type)
+			if (!checkkey("clock")) {
+				if (!checktab(clocks, &te1.clock_type))
+					continue;
+				error("Invalid clock type\n");
+			}
+
+		if (!te1.clock_rate &&
+		    (te1.clock_type == CLOCK_INT ||
+		     te1.clock_type == CLOCK_TXINT))
+			if (!match("rate", &te1.clock_rate, 1, 0xFFFFFFFF))
+				continue;
+		if (!te1.loopback) {
+			if (!checkkey("loopback") ||
+			    !checkkey("lb")) {
+				te1.loopback = 1;
+				continue;
+			}
+		}
+		/* slotmap goes here */
+
+		if (orig_argc == argc)
+			return;	/* not an iface definition */
+		error("Invalid parameter: %s\n", argv[0]);
+	}
+
+	if (!te1.clock_rate &&
+	    (te1.clock_type == CLOCK_INT ||
+	     te1.clock_type == CLOCK_TXINT))
+		te1.clock_rate = 64000;
+
+	/* FIXME stupid hack, will remove it later */
+	req.ifr_settings.ifs_ifsu.te1 = &te1;
+	if (req.ifr_settings.type == IF_IFACE_E1 ||
+	    req.ifr_settings.type == IF_IFACE_T1)
+		req.ifr_settings.size = sizeof(te1_settings);
+	else
+		req.ifr_settings.size = sizeof(sync_serial_settings);
+
+	if (ioctl(sock, SIOCWANDEV, &req))
+		error("Unable to set interface information: %s\n",
+		      strerror(errno));
+
+	exit(0);
+}
+
+
+
+static void set_proto_fr(void)
+{
+	unsigned int lmi_type = 0;
+	fr_proto fr;
+
+	memset(&fr, 0, sizeof(fr));
+
+	while (argc > 0) {
+		if (!lmi_type)
+			if (!checkkey("lmi")) {
+				if (!checktab(lmi, &lmi_type))
+					continue;
+				error("Invalid LMI type: %s\n",
+				      argv[0]);
+			}
+
+		if (lmi_type && lmi_type != LMI_NONE) {
+			if (!fr.dce)
+				if (!checkkey("dce")) {
+					fr.dce = 1;
+					continue;
+				}
+
+			if (!fr.t391)
+				if (!match("t391", &fr.t391,
+					   1, 1000))
+					continue;
+			if (!fr.t392)
+				if (!match("t392", &fr.t392,
+					   1, 1000))
+					continue;
+			if (!fr.n391)
+				if (!match("n391", &fr.n391,
+					   1, 1000))
+					continue;
+			if (!fr.n392)
+				if (!match("n392", &fr.n392,
+					   1, 1000))
+					continue;
+			if (!fr.n393)
+				if (!match("n393", &fr.n393,
+					   1, 1000))
+					continue;
+		}
+		error("Invalid parameter: %s\n", argv[0]);
+	}
+
+	 /* polling verification timer*/
+	if (!fr.t391) fr.t391 = 10;
+	/* link integrity verification polling timer */
+	if (!fr.t392) fr.t392 = 15;
+	/* full status polling counter*/
+	if (!fr.n391) fr.n391 = 6;
+	/* error threshold */
+	if (!fr.n392) fr.n392 = 3;
+	/* monitored events count */
+	if (!fr.n393) fr.n393 = 4;
+
+	if (!lmi_type)
+		fr.lmi = LMI_DEFAULT;
+	else
+		fr.lmi = lmi_type;
+
+	req.ifr_settings.ifs_ifsu.fr = &fr;
+	req.ifr_settings.size = sizeof(fr);
+
+	if (ioctl(sock, SIOCWANDEV, &req))
+		error("Unable to set FR protocol information: %s\n",
+		      strerror(errno));
+}
+
+
+
+static void set_proto_hdlc(int eth)
+{
+	unsigned int enc = 0, par = 0;
+	raw_hdlc_proto raw;
+
+	memset(&raw, 0, sizeof(raw));
+
+	while (argc > 0) {
+		if (!enc)
+			if (!checktab(hdlc_enc, &enc))
+				continue;
+		if (!par)
+			if (!checktab(hdlc_par, &par))
+				continue;
+
+		error("Invalid parameter: %s\n", argv[0]);
+	}
+
+	if (!enc)
+		raw.encoding = ENCODING_DEFAULT;
+	else
+		raw.encoding = enc;
+
+	if (!par)
+		raw.parity = ENCODING_DEFAULT;
+	else
+		raw.parity = par;
+
+	req.ifr_settings.ifs_ifsu.raw_hdlc = &raw;
+	req.ifr_settings.size = sizeof(raw);
+
+	if (ioctl(sock, SIOCWANDEV, &req))
+		error("Unable to set HDLC%s protocol information: %s\n",
+		      eth ? "-ETH" : "", strerror(errno));
+}
+
+
+
+static void set_proto_cisco(void)
+{
+	cisco_proto cisco;
+	memset(&cisco, 0, sizeof(cisco));
+
+	while (argc > 0) {
+		if (!cisco.interval)
+			if (!match("interval", &cisco.interval,
+				   1, 100))
+				continue;
+		if (!cisco.timeout)
+			if (!match("timeout", &cisco.timeout,
+				   1, 100))
+				continue;
+
+		error("Invalid parameter: %s\n",
+		      argv[0]);
+	}
+
+	if (!cisco.interval)
+		cisco.interval = 10;
+	if (!cisco.timeout)
+		cisco.timeout = 25;
+
+	req.ifr_settings.ifs_ifsu.cisco = &cisco;
+	req.ifr_settings.size = sizeof(cisco);
+
+	if (ioctl(sock, SIOCWANDEV, &req))
+		error("Unable to set Cisco HDLC protocol information: %s\n",
+		      strerror(errno));
+}
+
+
+
+static void set_proto(void)
+{
+	if (checktab(protos, &req.ifr_settings.type))
+		return;
+
+	switch(req.ifr_settings.type) {
+	case IF_PROTO_HDLC: set_proto_hdlc(0); break;
+#ifdef IF_PROTO_HDLC_ETH
+	case IF_PROTO_HDLC_ETH: set_proto_hdlc(1); break;
+#endif
+	case IF_PROTO_CISCO: set_proto_cisco(); break;
+	case IF_PROTO_FR: set_proto_fr(); break;
+
+	case IF_PROTO_PPP:
+	case IF_PROTO_X25:
+		req.ifr_settings.ifs_ifsu.sync = NULL; /* FIXME */
+		req.ifr_settings.size = 0;
+
+		if (!ioctl(sock, SIOCWANDEV, &req))
+			break;
+
+		error("Unable to set %s protocol information: %s\n",
+		      req.ifr_settings.type == IF_PROTO_PPP
+		      ? "PPP" : "X.25", strerror(errno));
+
+	default: error("Unknown protocol %u\n", req.ifr_settings.type);
+	}
+
+	if (argc > 0)
+		error("Unexpected parameter: %s\n", argv[0]);
+
+	close(sock);
+	exit(0);
+}
+
+
+
+static void set_pvc(void)
+{
+	char *op = argv[0];
+	parsertab ops[] = {{ "create", IF_PROTO_FR_ADD_PVC },
+			   { "delete", IF_PROTO_FR_DEL_PVC },
+			   { NULL, 0 }};
+	fr_proto_pvc pvc;
+
+	memset(&pvc, 0, sizeof(pvc));
+
+	if (checktab(ops, &req.ifr_settings.type))
+		return;
+
+#ifdef IF_PROTO_FR_ETH_PVC
+	if (!match("ether", &pvc.dlci, 0, 1023)) {
+		if (req.ifr_settings.type == IF_PROTO_FR_ADD_PVC)
+			req.ifr_settings.type = IF_PROTO_FR_ADD_ETH_PVC;
+		else
+			req.ifr_settings.type = IF_PROTO_FR_DEL_ETH_PVC;
+
+	} else
+#endif
+		if (match(NULL, &pvc.dlci, 0, 1023))
+			return;
+
+	if (argc != 0)
+		return;
+
+	req.ifr_settings.ifs_ifsu.fr_pvc = &pvc;
+	req.ifr_settings.size = sizeof(pvc);
+
+	if (ioctl(sock, SIOCWANDEV, &req))
+		error("Unable to %s PVC: %s\n", op, strerror(errno));
+	exit(0);
+}
+
+
+
+static void private(void)
+{
+	if (argc < 1)
+		return;
+
+	if (!strcmp(argv[0], "private")) {
+		if (argc != 1)
+			return;
+		if (ioctl(sock, SIOCDEVPRIVATE, &req))
+			error("SIOCDEVPRIVATE: %s\n", strerror(errno));
+		exit(0);
+	}
+}
+
+
+
+static void show_port(void)
+{
+	const char *s;
+	char buffer[128];
+	const te1_settings *te1 = (void*)buffer;
+	const raw_hdlc_proto *raw = (void*)buffer;
+	const cisco_proto *cisco = (void*)buffer;
+	const fr_proto *fr = (void*)buffer;
+#ifdef IF_PROTO_FR_PVC
+	const fr_proto_pvc_info *pvc = (void*)buffer;
+#endif
+	req.ifr_settings.ifs_ifsu.sync = (void*)buffer; /* FIXME */
+
+	printf("%s: ", req.ifr_name);
+
+	req.ifr_settings.size = sizeof(buffer);
+	req.ifr_settings.type = IF_GET_IFACE;
+
+	if (ioctl(sock, SIOCWANDEV, &req))
+		if (errno != EINVAL) {
+			printf("unable to get interface information: %s\n",
+			       strerror(errno));
+			close(sock);
+			exit(1);
+		}
+	
+	/* Get and print physical interface settings */
+	if (req.ifr_settings.type == IF_IFACE_SYNC_SERIAL)
+		s = "";		/* Unspecified serial interface */
+	else
+		s = tabstr(req.ifr_settings.type, ifaces, NULL);
+
+	if (!s)
+		printf("unknown interface 0x%x\n", req.ifr_settings.type);
+	else {
+		if (*s)
+			printf("interface %s ", s);
+
+		printf("clock %s", tabstr(te1->clock_type, clocks,
+					  "type unknown"));
+		if (te1->clock_type == CLOCK_INT ||
+		    te1->clock_type == CLOCK_TXINT)
+			printf(" rate %u", te1->clock_rate);
+
+		if (te1->loopback)
+			printf(" loopback");
+
+		if (req.ifr_settings.type == IF_IFACE_E1 ||
+		    req.ifr_settings.type == IF_IFACE_T1) {
+			unsigned int u;
+			printf(" slotmap ");
+			for (u = te1->slot_map; u != 0; u /= 2)
+				printf("%u", u % 2);
+		}
+		printf("\n");
+	}
+
+	/* Get and print protocol settings */
+	do {
+		printf("\t");
+		req.ifr_settings.size = sizeof(buffer);
+		req.ifr_settings.type = IF_GET_PROTO;
+
+		if (ioctl(sock, SIOCWANDEV, &req)) {
+			if (errno == EINVAL)
+				printf("no protocol set\n");
+			else
+				printf("unable to get protocol information: "
+				       "%s\n", strerror(errno));
+			break;
+		}
+
+		switch(req.ifr_settings.type) {
+		case IF_PROTO_FR:
+			printf("protocol fr lmi %s",
+			       tabstr(fr->lmi, lmi, "unknown"));
+			if (fr->lmi == LMI_ANSI ||
+			    fr->lmi == LMI_CCITT)
+				printf("%s t391 %u t392 %u n391 %u n392 %u "
+				       "n393 %u\n",
+				       fr->dce ? " dce" : "",
+				       fr->t391,
+				       fr->t392,
+				       fr->n391,
+				       fr->n392,
+				       fr->n393);
+			else
+				putchar('\n');
+			break;
+
+#ifdef IF_PROTO_FR_PVC
+		case IF_PROTO_FR_PVC:
+			printf("Frame-Relay PVC: DLCI %u, master device %s\n",
+			       pvc->dlci, pvc->master);
+			break;
+#endif
+
+#ifdef IF_PROTO_FR_ETH_PVC
+		case IF_PROTO_FR_ETH_PVC:
+			printf("Frame-Relay PVC (Ethernet emulation): DLCI %u,"
+			       " master device %s\n", pvc->dlci, pvc->master);
+			break;
+#endif
+
+		case IF_PROTO_HDLC:
+			printf("protocol hdlc %s %s\n",
+			       tabstr(raw->encoding, hdlc_enc, "unknown"),
+			       tabstr(raw->parity, hdlc_par, "unknown"));
+			break;
+
+#ifdef IF_PROTO_HDLC_ETH
+		case IF_PROTO_HDLC_ETH:
+			printf("protocol hdlc-eth %s %s\n",
+			       tabstr(raw->encoding, hdlc_enc, "unknown"),
+			       tabstr(raw->parity, hdlc_par, "unknown"));
+			break;
+#endif
+
+		case IF_PROTO_CISCO:
+			printf("protocol cisco interval %u timeout %u\n",
+			       cisco->interval,
+			       cisco->timeout);
+			break;
+
+		case IF_PROTO_PPP:
+			printf("protocol ppp\n");
+			break;
+
+		case IF_PROTO_X25:
+			printf("protocol x25\n");
+			break;
+
+		default:
+			printf("unknown protocol %u\n", req.ifr_settings.type);
+		}
+	}while(0);
+
+	close(sock);
+	exit(0);
+}
+
+
+
+static void usage(void)
+{
+	fprintf(stderr, "sethdlc version 1.15\n"
+		"Copyright (C) 2000 - 2003 Krzysztof Halasa <khc at pm.waw.pl>\n"
+		"\n"
+		"Usage: sethdlc INTERFACE [PHYSICAL] [clock CLOCK] [LOOPBACK] "
+		"[slotmap SLOTMAP]\n"
+		"       sethdlc INTERFACE [PROTOCOL]\n"
+		"       sethdlc INTERFACE create | delete"
+#ifdef IF_PROTO_FR_ETH_PVC
+		" [ether]"
+#endif
+		" DLCI\n"
+		"       sethdlc INTERFACE private...\n"
+		"\n"
+		"PHYSICAL := v24 | v35 | x21 | e1 | t1\n"
+		"CLOCK := int [rate RATE] | ext | txint [rate RATE] | txfromrx\n"
+		"LOOPBACK := loopback | lb\n"
+		"\n"
+		"PROTOCOL := hdlc [ENCODING] [PARITY] |\n"
+#ifdef IF_PROTO_HDLC_ETH
+		"            hdlc-eth [ENCODING] [PARITY] |\n"
+#endif
+		"            cisco [interval val] [timeout val] |\n"
+		"            fr [lmi LMI] |\n"
+		"            ppp |\n"
+		"            x25\n"
+		"\n"
+		"ENCODING := nrz | nrzi | fm-mark | fm-space | manchester\n"
+		"PARITY := no-parity | crc16 | crc16-pr0 | crc16-itu | crc16-itu-pr0 | crc32-itu\n"
+		"LMI := none | ansi [LMI_SPEC] | ccitt [LMI_SPEC]\n"
+		"LMI_SPEC := [dce] [t391 val] [t392 val] [n391 val] [n392 val] [n393 val]\n");
+	exit(0);
+}
+
+
+
+int main(int arg_c, char *arg_v[])
+{
+	argc = arg_c;
+	argv = arg_v;
+
+	if (argc <= 1)
+		usage();
+  
+	sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+	if (sock < 0)
+		error("Unable to create socket: %s\n", strerror(errno));
+  
+	dahdi_copy_string(req.ifr_name, argv[1], sizeof(req.ifr_name)); /* Device name */
+
+	if (argc == 2)
+		show_port();
+
+	argc -= 2;
+	argv += 2;
+
+	set_iface();
+	set_proto();
+	set_pvc();
+	private();
+
+	close(sock);
+	usage();
+	exit(0);
+}
diff --git a/system.conf.sample b/system.conf.sample
new file mode 100644
index 0000000..ff6e3b9
--- /dev/null
+++ b/system.conf.sample
@@ -0,0 +1,330 @@
+#
+# DAHDI Configuration File
+#
+# This file is parsed by the DAHDI Configurator, dahdi_cfg
+#
+# Span Configuration
+# ^^^^^^^^^^^^^^^^^^
+# First come the span definitions, in the format
+# 
+#   span=<span num>,<timing source>,<line build out (LBO)>,<framing>,<coding>[,yellow]
+#
+# All T1/E1/BRI spans generate a clock signal on their transmit side. The
+# <timing source> parameter determines whether the clock signal from the far
+# end of the T1/E1/BRI is used as the master source of clock timing. If it is, our
+# own clock will synchronise to it. T1/E1/BRI connected directly or indirectly to
+# a PSTN provider (telco) should generally be the first choice to sync to. The
+# PSTN will never be a slave to you. You must be a slave to it.
+#
+# Choose 1 to make the equipment at the far end of the E1/T1/BRI link the preferred
+# source of the master clock. Choose 2 to make it the second choice for the master
+# clock, if the first choice port fails (the far end dies, a cable breaks, or
+# whatever). Choose 3 to make a port the third choice, and so on. If you have, say,
+# 2 ports connected to the PSTN, mark those as 1 and 2. The number used for each
+# port should be different.
+#
+# If you choose 0, the port will never be used as a source of timing. This is
+# appropriate when you know the far end should always be a slave to you. If
+# the port is connected to a channel bank, for example, you should always be
+# its master. Likewise, BRI TE ports should always be configured as a slave.
+# Any number of ports can be marked as 0.
+#
+# Incorrect timing sync may cause clicks/noise in the audio, poor quality or failed
+# faxes, unreliable modem operation, and is a general all round bad thing.
+#
+# The line build-out (or LBO) is an integer, from the following table:
+#
+#  0: 0 db (CSU) / 0-133 feet (DSX-1)
+#  1: 133-266 feet (DSX-1)
+#  2: 266-399 feet (DSX-1)
+#  3: 399-533 feet (DSX-1)
+#  4: 533-655 feet (DSX-1)
+#  5: -7.5db (CSU)
+#  6: -15db (CSU)
+#  7: -22.5db (CSU)
+#
+# If the span is a BRI port the line build-out is not used and should be set
+# to 0.
+#
+# framing:: 
+#   one of 'd4' or 'esf' for T1 or 'cas' or 'ccs' for E1. Use 'ccs' for BRI.
+#  'd4' could be referred to as 'sf' or 'superframe'
+#
+# coding:: 
+#   one of 'ami' or 'b8zs' for T1 or 'ami' or 'hdb3' for E1. Use 'ami' for
+#   BRI.
+#
+#   * For E1 there is the optional keyword 'crc4' to enable CRC4 checking.
+#   * If the keyword 'yellow' follows, yellow alarm is transmitted when no
+#     channels are open.
+#
+#span=1,0,0,esf,b8zs
+#span=2,1,0,esf,b8zs
+#span=3,0,0,ccs,hdb3,crc4
+#
+# Dynamic Spans
+# ^^^^^^^^^^^^^
+# Next come the dynamic span definitions, in the form:
+# 
+#   dynamic=<driver>,<address>,<numchans>,<timing>
+#
+# Where <driver> is the name of the driver (e.g. eth), <address> is the
+# driver specific address (like a MAC for eth), <numchans> is the number
+# of channels, and <timing> is a timing priority, like for a normal span.
+# use "0" to not use this as a timing source, or prioritize them as
+# primary, secondard, etc.  Note that you MUST have a REAL DAHDI device
+# if you are not using external timing.
+#
+#   dynamic=eth,eth0/00:02:b3:35:43:9c,24,0
+#
+# If a non-zero timing value is used, as above, only the last span should
+# have the non-zero value. 
+#
+# Channel Configuration
+# ^^^^^^^^^^^^^^^^^^^^^
+# Next come the definitions for using the channels.  The format is:
+# <device>=<channel list>
+#
+# Valid devices are:
+#
+# e&m::
+#   Channel(s) are signalled using E&M signalling on a T1 line.
+#   Specific implementation, such as Immediate, Wink, or Feature
+#   Group D are handled by the userspace library.
+# e&me1::
+#   Channel(s) are signalled using E&M signalling on an E1 line.
+# fxsls:: 
+#   Channel(s) are signalled using FXS Loopstart protocol.
+# fxsgs:: 
+#   Channel(s) are signalled using FXS Groundstart protocol.
+# fxsks:: 
+#   Channel(s) are signalled using FXS Koolstart protocol.
+# fxols:: 
+#   Channel(s) are signalled using FXO Loopstart protocol.
+# fxogs:: 
+#   Channel(s) are signalled using FXO Groundstart protocol.
+# fxoks:: 
+#   Channel(s) are signalled using FXO Koolstart protocol.
+# sf:: 
+#   Channel(s) are signalled using in-band single freq tone. 
+#   Syntax as follows: 
+#    
+#     channel# => sf:<rxfreq>,<rxbw>,<rxflag>,<txfreq>,<txlevel>,<txflag>
+#   
+#   rxfreq is rx tone freq in Hz, rxbw is rx notch (and decode)
+#   bandwith in hz (typically 10.0), rxflag is either 'normal' or
+#   'inverted', txfreq is tx tone freq in hz, txlevel is tx tone 
+#   level in dbm, txflag is either 'normal' or 'inverted'. Set 
+#   rxfreq or txfreq to 0.0 if that tone is not desired.
+#
+# unused:: 
+#   No signalling is performed, each channel in the list remains idle
+# clear::
+#   Channel(s) are bundled into a single span.  No conversion or
+#   signalling is performed, and raw data is available on the master.
+# bchan:: 
+#   Like 'clear' except all channels are treated individually and
+#   are not bundled.  'inclear' is an alias for this.
+# rawhdlc::
+#   The DAHDI driver performs HDLC encoding and decoding on the 
+#   bundle, and the resulting data is communicated via the master
+#   device.
+# dchan::
+#   The DAHDI driver performs HDLC encoding and decoding on the
+#   bundle and also performs incoming and outgoing FCS insertion
+#   and verification.  'fcshdlc' is an alias for this. 
+# hardhdlc::
+#   The hardware driver performs HDLC encoding and decoding on the
+#   bundle and also performs incoming and outgoing FCS insertion
+#   and verification.  Is subject to limitations and support of underlying
+#   hardware. BRI spans serviced by the wcb4xxp driver must use hardhdlc
+#   channels for the signalling channels. 
+# nethdlc::
+#   The DAHDI driver bundles the channels together into an
+#   hdlc network device, which in turn can be configured with
+#   sethdlc (available separately). In 2.6.x kernels you can also optionally
+#   pass the name for the network interface after the channel list.
+#   Syntax:
+#   
+#     nethdlc=<channel list>[:interface name]
+#   Use original names, don't use the names which have been already registered 
+#   in system e.g eth.
+#
+# dacs::
+#   The DAHDI driver cross connects the channels starting at
+#   the channel number listed at the end, after a colon
+# dacsrbs::
+#   The DAHDI driver cross connects the channels starting at
+#   the channel number listed at the end, after a colon and 
+#   also performs the DACSing of RBS bits
+#
+# The channel list is a comma-separated list of channels or ranges, for
+# example:
+#
+#   1,3,5 (channels one, three, and five)
+#   16-23, 29 (channels 16 through 23, as well as channel 29)
+#
+# So, some complete examples are:
+#
+#   e&m=1-12
+#   nethdlc=13-24
+#   fxsls=25,26,27,28
+#   fxols=29-32
+#
+# An example of BRI port:
+# 
+#   span=1,1,0,ccs,ami
+#   bchan=1,2
+#   hardhdlc=3
+#
+# NOTE: When using BRI channels in asterisk, use the bri_cpe, bri_net, or
+# bri_cpe_ptmp (for point to multipoint mode). libpri does not currently
+# support point to multipoint when in NT mode. Otherwise, the bearer channel
+# are configured identically to other DAHDI channels.
+#
+#fxoks=1-24
+#bchan=25-47
+#dchan=48
+#fxols=1-12
+#fxols=13-24
+#e&m=25-29
+#nethdlc=30-33
+#clear=44
+#clear=45
+#clear=46
+#clear=47
+#fcshdlc=48
+#dacs=1-24:48
+#dacsrbs=1-24:48
+#
+# Tone Zone Data
+# ^^^^^^^^^^^^^^
+# Finally, you can preload some tone zones, to prevent them from getting
+# overwritten by other users (if you allow non-root users to open /dev/dahdi/*
+# interfaces anyway.  Also this means they won't have to be loaded at runtime.
+# The format is "loadzone=<zone>" where the zone is a two letter country code.
+# 
+# You may also specify a default zone with "defaultzone=<zone>" where zone
+# is a two letter country code.
+#
+# An up-to-date list of the zones can be found in the file zonedata.c
+#
+loadzone = us
+#loadzone = us-old
+#loadzone=gr
+#loadzone=it
+#loadzone=fr
+#loadzone=de
+#loadzone=uk
+#loadzone=fi
+#loadzone=jp
+#loadzone=sp
+#loadzone=no
+#loadzone=hu
+#loadzone=lt
+#loadzone=pl
+defaultzone=us
+#
+# PCI Radio Interface
+# ^^^^^^^^^^^^^^^^^^^
+# (see http://www.zapatatelephony.org/app_rpt.html)
+#
+# The PCI Radio Interface card interfaces up to 4 two-way radios (either
+# a base/mobile radio or repeater system) to DAHDI channels. The driver
+# may work either independent of an application, or with it, through
+# the driver;s ioctl() interface. This file gives you access to specify
+# load-time parameters for Radio channels, so that the driver may run
+# by itself, and just act like a generic DAHDI radio interface.
+#
+# Unlike the rest of this file, you specify a block of parameters, and
+# then the channel(s) to which they apply. CTCSS is specified as a frequency
+# in tenths of hertz, for example 131.8 HZ is specified as 1318. DCS
+# for receive is specified as the code directly, for example 223. DCS for
+# transmit is specified as D and then the code, for example D223.
+#
+# The hardware supports a "community" CTCSS decoder system that has
+# arbitrary transmit CTCSS or DCS codes associated with them, unlike
+# traditional "community" systems that encode the same tone they decode.
+# 
+# this example is a single tone DCS transmit and receive
+#
+# specify the transmit tone (in DCS mode this stays constant):
+#tx=D371
+#
+# specify the receive DCS code:
+#dcsrx=223
+#
+# this example is a "community" CTCSS (if you only want a single tone, then
+# only specify 1 in the ctcss list)
+#
+# specify the default transmit tone (when not receiving):
+#tx=1000
+#
+# Specify the receive freq, the tag (use 0 if none), and the transmit code.
+# The tag may be used by applications to determine classification of tones.
+# The tones are to be specified in order of presedence, most important first.
+# Currently, 15 tones may be specified..
+#
+#ctcss=1318,1,1318
+#ctcss=1862,1,1862
+#
+# The following parameters may be omitted if their default value is acceptible
+#
+# Set the receive debounce time in milliseconds:
+#debouncetime=123
+#
+# set the transmit quiet dropoff burst time in milliseconds:
+#bursttime=234
+#
+# set the COR level threshold (specified in tenths of millivolts)
+# valid values are {3125,6250,9375,12500,15625,18750,21875,25000}
+#corthresh=12500
+#
+# Invert COR signal {y,n}
+#invertcor=y
+# Set the external tone mode; yes, no, internal {y,n,i}
+#exttone=y
+#
+# Now apply the configuration to the specified channels:
+#
+# We are all done with our channel parameters, so now we specify what
+# channels they apply to
+#channels=1-4
+#
+# Overiding PCM encoding
+# ^^^^^^^^^^^^^^^^^^^^^^
+# Usually the channel driver sets the encoding of the PCM for the
+# channel (mulaw / alaw. That is: g711u or g711a). However there are
+# some cases where you would like to override that. 'mulaw' and 'alaw'
+# set different such encoding. Use them for channels you have already
+# defined with e.g. 'bchan' or 'fxoks'.
+#mulaw=1-4
+#alaw=1-4
+#
+# 'deflaw' is similar, but resets the encoding to the channel driver's
+# default. It must be useful for something, I guess.
+#mulaw=1-10
+#deflaw=5
+#
+# Echo Cancellers
+# ^^^^^^^^^^^^^^^
+# DAHDI uses modular echo cancellers that are configured per channel. The echo
+# cancellers are compiled and installed as part of the dahdi-linux package.
+# You can specify in this file the echo canceller to be used for each
+# channel. The default behavior is for there to be NO echo canceller on any
+# channel, so it is very important that you specify one here if you do
+# not have hardware echo cancellers and need echo cancellation.
+#
+# Valid echo cancellers are: mg2, kb1, sec2, and sec.
+# If compiled, 'hpec' is also a valid echo canceller.
+# 
+# To configure the default echo cancellers, use the format:
+# echocanceller=<echocanceller name>,<channel(s)>
+#
+# Example:
+# Configure channels 1 through 8 to use the mg2 echo canceller
+#echocanceller=mg2,1-8 
+#
+# And change channel 2 to use the kb1 echo canceller.
+#echocanceller=kb1,2
+#
diff --git a/timertest.c b/timertest.c
new file mode 100644
index 0000000..6f72885
--- /dev/null
+++ b/timertest.c
@@ -0,0 +1,78 @@
+/*
+ * Written by Mark Spencer <markster at digium.com>
+ * Based on previous works, designs, and architectures conceived and
+ * written by Jim Dixon <jim at lambdatel.com>.
+ *
+ * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
+ * Copyright (C) 2001-2008 Digium, Inc.
+ *
+ * All rights reserved.
+ *
+ * Primary Author: Mark Spencer <markster at digium.com>
+ * Radio Support by Jim Dixon <jim at lambdatel.com>
+ */
+
+/*
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2 as published by the
+ * Free Software Foundation. See the LICENSE file included with
+ * this program for more details.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <errno.h>
+
+#include <dahdi/user.h>
+#include "dahdi_tools_version.h"
+
+int main(int argc, char *argv[])
+{
+	int fd;
+	int x = 8000;
+	int res;
+	fd_set fds;
+	struct timeval orig, now;
+	fd = open("/dev/dahdi/timer", O_RDWR);
+	if (fd < 0) {
+		fprintf(stderr, "Unable to open timer: %s\n", strerror(errno));
+		exit(1);
+	}
+	printf("Opened timer...\n");
+	if (ioctl(fd, DAHDI_TIMERCONFIG, &x)) {
+		fprintf(stderr, "Unable to set timer: %s\n", strerror(errno));
+		exit(1);
+	}
+	printf("Set timer duration to %d samples (%d ms)\n", x, x/8);
+	printf("Waiting...\n");
+	gettimeofday(&orig, NULL);
+	for(;;) {
+		FD_ZERO(&fds);
+		FD_SET(fd, &fds);
+		res = select(fd + 1, NULL, NULL, &fds, NULL);
+		if (res != 1) {
+			fprintf(stderr, "Unexpected result %d: %s\n", res, strerror(errno));
+			exit(1);
+		}
+		x = -1;
+		if (ioctl(fd, DAHDI_TIMERACK, &x)) {
+			fprintf(stderr, "Unable to ack timer: %s\n", strerror(errno));
+			exit(1);
+		}
+		gettimeofday(&now, NULL);
+		printf("Timer Expired (%ld ms)!\n", (now.tv_sec - orig.tv_sec) * 1000 + (now.tv_usec - orig.tv_usec) / 1000);
+	}
+	exit(0);
+}
diff --git a/tonezone.c b/tonezone.c
new file mode 100644
index 0000000..afdec99
--- /dev/null
+++ b/tonezone.c
@@ -0,0 +1,518 @@
+/*
+ * BSD Telephony Of Mexico "Tormenta" Tone Zone Support 2/22/01
+ * 
+ * Working with the "Tormenta ISA" Card 
+ *
+ * Primary Author: Mark Spencer <markster at digium.com>
+ *
+ */
+
+/*
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU Lesser General Public License Version 2.1 as published
+ * by the Free Software Foundation. See the LICENSE.LGPL file
+ * included with this program for more details.
+ *
+ * In addition, when this program is distributed with Asterisk in
+ * any form that would qualify as a 'combined work' or as a
+ * 'derivative work' (but not mere aggregation), you can redistribute
+ * and/or modify the combination under the terms of the license
+ * provided with that copy of Asterisk, instead of the license
+ * terms granted here.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "dahdi/user.h"
+#include "tonezone.h"
+#include "dahdi_tools_version.h"
+
+#define DEFAULT_DAHDI_DEV "/dev/dahdi/ctl"
+
+#define MAX_SIZE 16384
+#define CLIP 32635
+#define BIAS 0x84
+
+#if 0
+# define PRINT_DEBUG(x, ...) printf(x, __VA_ARGS__)
+#else
+# define PRINT_DEBUG(x, ...)
+#endif
+
+#ifndef ENODATA
+#define ENODATA EINVAL
+#endif
+
+struct tone_zone *tone_zone_find(char *country)
+{
+	struct tone_zone *z;
+	z = builtin_zones;
+	while(z->zone > -1) {
+		if (!strcasecmp(country, z->country))
+			return z;
+		z++;
+	}
+	return NULL;
+}
+
+struct tone_zone *tone_zone_find_by_num(int id)
+{
+	struct tone_zone *z;
+	z = builtin_zones;
+	while(z->zone > -1) {
+		if (z->zone == id)
+			return z;
+		z++;
+	}
+	return NULL;
+}
+
+#define LEVEL -10
+
+static int build_tone(void *data, size_t size, struct tone_zone_sound *t, int *count)
+{
+	char *dup, *s;
+	struct dahdi_tone_def *td=NULL;
+	int firstnobang = -1;
+	int freq1, freq2, time;
+	int modulate = 0;
+	float gain;
+	int used = 0;
+	dup = strdup(t->data);
+	s = strtok(dup, ",");
+	while(s && strlen(s)) {
+		/* Handle optional ! which signifies don't start here*/
+		if (s[0] == '!') 
+			s++;
+		else if (firstnobang < 0) {
+			PRINT_DEBUG("First no bang: %s\n", s);
+			firstnobang = *count;
+		}
+		if (sscanf(s, "%d+%d/%d", &freq1, &freq2, &time) == 3) {
+			/* f1+f2/time format */
+			PRINT_DEBUG("f1+f2/time format: %d, %d, %d\n", freq1, freq2, time);
+		} else if (sscanf(s, "%d*%d/%d", &freq1, &freq2, &time) == 3) {
+			/* f1*f2/time format */
+			PRINT_DEBUG("f1+f2/time format: %d, %d, %d\n", freq1, freq2, time);
+			modulate = 1;
+		} else if (sscanf(s, "%d+%d", &freq1, &freq2) == 2) {
+			PRINT_DEBUG("f1+f2 format: %d, %d\n", freq1, freq2);
+			time = 0;
+		} else if (sscanf(s, "%d*%d", &freq1, &freq2) == 2) {
+			PRINT_DEBUG("f1+f2 format: %d, %d\n", freq1, freq2);
+			modulate = 1;
+			time = 0;
+		} else if (sscanf(s, "%d/%d", &freq1, &time) == 2) {
+			PRINT_DEBUG("f1/time format: %d, %d\n", freq1, time);
+			freq2 = 0;
+		} else if (sscanf(s, "%d", &freq1) == 1) {
+			PRINT_DEBUG("f1 format: %d\n", freq1);
+			firstnobang = *count;
+			freq2 = 0;
+			time = 0;
+		} else {
+			fprintf(stderr, "tone component '%s' of '%s' is a syntax error\n", s,t->data);
+			return -1;
+		}
+
+		PRINT_DEBUG("Using %d samples for %d and %d\n", time * 8, freq1, freq2);
+
+		if (size < sizeof(*td)) {
+			fprintf(stderr, "Not enough space for tones\n");
+			return -1;
+		}
+		td = data;
+
+		/* Bring it down -8 dbm */
+		gain = pow(10.0, (LEVEL - 3.14) / 20.0) * 65536.0 / 2.0;
+
+		td->fac1 = 2.0 * cos(2.0 * M_PI * (freq1 / 8000.0)) * 32768.0;
+		td->init_v2_1 = sin(-4.0 * M_PI * (freq1 / 8000.0)) * gain;
+		td->init_v3_1 = sin(-2.0 * M_PI * (freq1 / 8000.0)) * gain;
+		
+		td->fac2 = 2.0 * cos(2.0 * M_PI * (freq2 / 8000.0)) * 32768.0;
+		td->init_v2_2 = sin(-4.0 * M_PI * (freq2 / 8000.0)) * gain;
+		td->init_v3_2 = sin(-2.0 * M_PI * (freq2 / 8000.0)) * gain;
+
+		td->modulate = modulate;
+
+		data += sizeof(*td);
+		used += sizeof(*td);
+		size -= sizeof(*td);
+		td->tone = t->toneid;
+		if (time) {
+			/* We should move to the next tone */
+			td->next = *count + 1;
+			td->samples = time * 8;
+		} else {
+			/* Stay with us */
+			td->next = *count;
+			td->samples = 8000;
+		}
+		*count += 1;
+		s = strtok(NULL, ",");
+	}
+	if (td && time) {
+		/* If we don't end on a solid tone, return */
+		td->next = firstnobang;
+	}
+	if (firstnobang < 0)
+		fprintf(stderr, "tone '%s' does not end with a solid tone or silence (all tone components have an exclamation mark)\n", t->data);
+
+	return used;
+}
+
+char *tone_zone_tone_name(int id)
+{
+	static char tmp[80];
+	switch(id) {
+	case DAHDI_TONE_DIALTONE:
+		return "Dialtone";
+	case DAHDI_TONE_BUSY:
+		return "Busy";
+	case DAHDI_TONE_RINGTONE:
+		return "Ringtone";
+	case DAHDI_TONE_CONGESTION:
+		return "Congestion";
+	case DAHDI_TONE_CALLWAIT:
+		return "Call Waiting";
+	case DAHDI_TONE_DIALRECALL:
+		return "Dial Recall";
+	case DAHDI_TONE_RECORDTONE:
+		return "Record Tone";
+	case DAHDI_TONE_CUST1:
+		return "Custom 1";
+	case DAHDI_TONE_CUST2:
+		return "Custom 2";
+	case DAHDI_TONE_INFO:
+		return "Special Information";
+	case DAHDI_TONE_STUTTER:
+		return "Stutter Dialtone";
+	default:
+		snprintf(tmp, sizeof(tmp), "Unknown tone %d", id);
+		return tmp;
+	}
+}
+
+#ifdef TONEZONE_DRIVER
+static void dump_tone_zone(void *data, int size)
+{
+	struct dahdi_tone_def_header *z;
+	struct dahdi_tone_def *td;
+	int x;
+	int len = sizeof(*z);
+
+	z = data;
+	data += sizeof(*z);
+	printf("Header: %d tones, %d bytes of data, zone %d (%s)\n", 
+		z->count, size, z->zone, z->name);
+	for (x = 0; x < z->count; x++) {
+		td = data;
+		printf("Tone Fragment %d: tone is %d, next is %d, %d samples\n",
+			x, td->tone, td->next, td->samples);
+		data += sizeof(*td);
+		len += sizeof(*td);
+	}
+	printf("Total measured bytes of data: %d\n", len);
+}
+#endif
+
+/* Tone frequency tables */
+struct mf_tone {
+	int	tone;
+	float   f1;     /* first freq */
+	float   f2;     /* second freq */
+};
+ 
+static struct mf_tone dtmf_tones[] = {
+	{ DAHDI_TONE_DTMF_0, 941.0, 1336.0 },
+	{ DAHDI_TONE_DTMF_1, 697.0, 1209.0 },
+	{ DAHDI_TONE_DTMF_2, 697.0, 1336.0 },
+	{ DAHDI_TONE_DTMF_3, 697.0, 1477.0 },
+	{ DAHDI_TONE_DTMF_4, 770.0, 1209.0 },
+	{ DAHDI_TONE_DTMF_5, 770.0, 1336.0 },
+	{ DAHDI_TONE_DTMF_6, 770.0, 1477.0 },
+	{ DAHDI_TONE_DTMF_7, 852.0, 1209.0 },
+	{ DAHDI_TONE_DTMF_8, 852.0, 1336.0 },
+	{ DAHDI_TONE_DTMF_9, 852.0, 1477.0 },
+	{ DAHDI_TONE_DTMF_s, 941.0, 1209.0 },
+	{ DAHDI_TONE_DTMF_p, 941.0, 1477.0 },
+	{ DAHDI_TONE_DTMF_A, 697.0, 1633.0 },
+	{ DAHDI_TONE_DTMF_B, 770.0, 1633.0 },
+	{ DAHDI_TONE_DTMF_C, 852.0, 1633.0 },
+	{ DAHDI_TONE_DTMF_D, 941.0, 1633.0 },
+	{ 0, 0, 0 }
+};
+ 
+static struct mf_tone mfr1_tones[] = {
+	{ DAHDI_TONE_MFR1_0, 1300.0, 1500.0 },
+	{ DAHDI_TONE_MFR1_1, 700.0, 900.0 },
+	{ DAHDI_TONE_MFR1_2, 700.0, 1100.0 },
+	{ DAHDI_TONE_MFR1_3, 900.0, 1100.0 },
+	{ DAHDI_TONE_MFR1_4, 700.0, 1300.0 },
+	{ DAHDI_TONE_MFR1_5, 900.0, 1300.0 },
+	{ DAHDI_TONE_MFR1_6, 1100.0, 1300.0 },
+	{ DAHDI_TONE_MFR1_7, 700.0, 1500.0 },
+	{ DAHDI_TONE_MFR1_8, 900.0, 1500.0 },
+	{ DAHDI_TONE_MFR1_9, 1100.0, 1500.0 },
+	{ DAHDI_TONE_MFR1_KP, 1100.0, 1700.0 },	/* KP */
+	{ DAHDI_TONE_MFR1_ST, 1500.0, 1700.0 },	/* ST */
+	{ DAHDI_TONE_MFR1_STP, 900.0, 1700.0 },	/* KP' or ST' */
+	{ DAHDI_TONE_MFR1_ST2P, 1300.0, 1700.0 },	/* KP'' or ST'' */ 
+	{ DAHDI_TONE_MFR1_ST3P, 700.0, 1700.0 },	/* KP''' or ST''' */
+	{ 0, 0, 0 }
+};
+
+static struct mf_tone mfr2_fwd_tones[] = {
+	{ DAHDI_TONE_MFR2_FWD_1, 1380.0, 1500.0 },
+	{ DAHDI_TONE_MFR2_FWD_2, 1380.0, 1620.0 },
+	{ DAHDI_TONE_MFR2_FWD_3, 1500.0, 1620.0 },
+	{ DAHDI_TONE_MFR2_FWD_4, 1380.0, 1740.0 },
+	{ DAHDI_TONE_MFR2_FWD_5, 1500.0, 1740.0 },
+	{ DAHDI_TONE_MFR2_FWD_6, 1620.0, 1740.0 },
+	{ DAHDI_TONE_MFR2_FWD_7, 1380.0, 1860.0 },
+	{ DAHDI_TONE_MFR2_FWD_8, 1500.0, 1860.0 },
+	{ DAHDI_TONE_MFR2_FWD_9, 1620.0, 1860.0 },
+	{ DAHDI_TONE_MFR2_FWD_10, 1740.0, 1860.0 },
+	{ DAHDI_TONE_MFR2_FWD_11, 1380.0, 1980.0 },
+	{ DAHDI_TONE_MFR2_FWD_12, 1500.0, 1980.0 },
+	{ DAHDI_TONE_MFR2_FWD_13, 1620.0, 1980.0 },
+	{ DAHDI_TONE_MFR2_FWD_14, 1740.0, 1980.0 },
+	{ DAHDI_TONE_MFR2_FWD_15, 1860.0, 1980.0 },
+	{ 0, 0, 0 }
+};
+
+static struct mf_tone mfr2_rev_tones[] = {
+	{ DAHDI_TONE_MFR2_REV_1, 1020.0, 1140.0 },
+	{ DAHDI_TONE_MFR2_REV_2, 900.0, 1140.0 },
+	{ DAHDI_TONE_MFR2_REV_3, 900.0, 1020.0 },
+	{ DAHDI_TONE_MFR2_REV_4, 780.0, 1140.0 },
+	{ DAHDI_TONE_MFR2_REV_5, 780.0, 1020.0 },
+	{ DAHDI_TONE_MFR2_REV_6, 780.0, 900.0 },
+	{ DAHDI_TONE_MFR2_REV_7, 660.0, 1140.0 },
+	{ DAHDI_TONE_MFR2_REV_8, 660.0, 1020.0 },
+	{ DAHDI_TONE_MFR2_REV_9, 660.0, 900.0 },
+	{ DAHDI_TONE_MFR2_REV_10, 660.0, 780.0 },
+	{ DAHDI_TONE_MFR2_REV_11, 540.0, 1140.0 },
+	{ DAHDI_TONE_MFR2_REV_12, 540.0, 1020.0 },
+	{ DAHDI_TONE_MFR2_REV_13, 540.0, 900.0 },
+	{ DAHDI_TONE_MFR2_REV_14, 540.0, 780.0 },
+	{ DAHDI_TONE_MFR2_REV_15, 540.0, 660.0 },
+	{ 0, 0, 0 }
+};
+
+static int build_mf_tones(void *data, size_t size, int *count, struct mf_tone *tone, int low_tone_level, int high_tone_level)
+{
+	struct dahdi_tone_def *td;
+	float gain;
+	int used = 0;
+
+	while (tone->tone) {
+		if (size < sizeof(*td)) {
+			fprintf(stderr, "Not enough space for samples\n");
+			return -1;
+		}
+		td = data;
+		data += sizeof(*td);
+		used += sizeof(*td);
+		size -= sizeof(*td);
+		td->tone = tone->tone;
+		*count += 1;
+
+		/* Bring it down 6 dBm */
+		gain = pow(10.0, (low_tone_level - 3.14) / 20.0) * 65536.0 / 2.0;
+		td->fac1 = 2.0 * cos(2.0 * M_PI * (tone->f1 / 8000.0)) * 32768.0;
+		td->init_v2_1 = sin(-4.0 * M_PI * (tone->f1 / 8000.0)) * gain;
+		td->init_v3_1 = sin(-2.0 * M_PI * (tone->f1 / 8000.0)) * gain;
+		
+		gain = pow(10.0, (high_tone_level - 3.14) / 20.0) * 65536.0 / 2.0;
+		td->fac2 = 2.0 * cos(2.0 * M_PI * (tone->f2 / 8000.0)) * 32768.0;
+		td->init_v2_2 = sin(-4.0 * M_PI * (tone->f2 / 8000.0)) * gain;
+		td->init_v3_2 = sin(-2.0 * M_PI * (tone->f2 / 8000.0)) * gain;
+
+		tone++;
+	}
+
+	return used;
+}
+
+int tone_zone_register_zone(int fd, struct tone_zone *z)
+{
+	char buf[MAX_SIZE];
+	int res;
+	int count = 0;
+	int x;
+	size_t space = MAX_SIZE;
+	void *ptr = buf;
+	int iopenedit = 1;
+	struct dahdi_tone_def_header *h;
+
+	memset(buf, 0, sizeof(buf));
+
+	h = ptr;
+	ptr += sizeof(*h);
+	space -= sizeof(*h);
+	h->zone = z->zone;
+
+	dahdi_copy_string(h->name, z->description, sizeof(h->name));
+
+	for (x = 0; x < DAHDI_MAX_CADENCE; x++) 
+		h->ringcadence[x] = z->ringcadence[x];
+
+	for (x = 0; x < DAHDI_TONE_MAX; x++) {
+		if (!strlen(z->tones[x].data))
+			continue;
+
+		PRINT_DEBUG("Tone: %d, string: %s\n", z->tones[x].toneid, z->tones[x].data);
+
+		if ((res = build_tone(ptr, space, &z->tones[x], &count)) < 0) {
+			fprintf(stderr, "Tone %d not built.\n", x);
+			return -1;
+		}
+		ptr += res;
+		space -= res;
+	}
+
+	if ((res = build_mf_tones(ptr, space, &count, dtmf_tones, z->dtmf_low_level, z->dtmf_high_level)) < 0) {
+		fprintf(stderr, "Could not build DTMF tones.\n");
+		return -1;
+	}
+	ptr += res;
+	space -= res;
+
+	if ((res = build_mf_tones(ptr, space, &count, mfr1_tones, z->mfr1_level, z->mfr1_level)) < 0) {
+		fprintf(stderr, "Could not build MFR1 tones.\n");
+		return -1;
+	}
+	ptr += res;
+	space -= res;
+
+	if ((res = build_mf_tones(ptr, space, &count, mfr2_fwd_tones, z->mfr2_level, z->mfr2_level)) < 0) {
+		fprintf(stderr, "Could not build MFR2 FWD tones.\n");
+		return -1;
+	}
+	ptr += res;
+	space -= res;
+
+	if ((res = build_mf_tones(ptr, space, &count, mfr2_rev_tones, z->mfr2_level, z->mfr2_level)) < 0) {
+		fprintf(stderr, "Could not build MFR2 REV tones.\n");
+		return -1;
+	}
+	ptr += res;
+	space -= res;
+
+	h->count = count;
+
+	if (fd < 0) {
+		if ((fd = open(DEFAULT_DAHDI_DEV, O_RDWR)) < 0) {
+			fprintf(stderr, "Unable to open %s and fd not provided\n", DEFAULT_DAHDI_DEV);
+			return -1;
+		}
+		iopenedit = 1;
+	}
+
+	x = z->zone;
+	if ((res = ioctl(fd, DAHDI_FREEZONE, &x))) {
+		if (errno != EBUSY)
+			fprintf(stderr, "ioctl(DAHDI_FREEZONE) failed: %s\n", strerror(errno));
+		return res;
+	}
+
+#if defined(TONEZONE_DRIVER)
+	dump_tone_zone(h, MAX_SIZE - space);
+#endif
+
+#if defined(__FreeBSD__)
+	if ((res = ioctl(fd, DAHDI_LOADZONE, &h))) {
+#else
+	if ((res = ioctl(fd, DAHDI_LOADZONE, h))) {
+#endif
+		fprintf(stderr, "ioctl(DAHDI_LOADZONE) failed: %s\n", strerror(errno));
+		return res;
+	}
+
+	if (iopenedit)
+		close(fd);
+
+	return res;
+}
+
+int tone_zone_register(int fd, char *country)
+{
+	struct tone_zone *z;
+	z = tone_zone_find(country);
+	if (z) {
+		return tone_zone_register_zone(-1, z);
+	} else {
+		return -1;
+	}
+}
+
+int tone_zone_set_zone(int fd, char *country)
+{
+	int res=-1;
+	struct tone_zone *z;
+	if (fd > -1) {
+		z = tone_zone_find(country);
+		if (z)
+			res = ioctl(fd, DAHDI_SETTONEZONE, &z->zone);
+		if ((res < 0) && (errno == ENODATA)) {
+			tone_zone_register_zone(fd, z);
+			res = ioctl(fd, DAHDI_SETTONEZONE, &z->zone);
+		}
+	}
+	return res;
+}
+
+int tone_zone_get_zone(int fd)
+{
+	int x=-1;
+	if (fd > -1) {
+		ioctl(fd, DAHDI_GETTONEZONE, &x);
+		return x;
+	}
+	return -1;
+}
+
+int tone_zone_play_tone(int fd, int tone)
+{
+	struct tone_zone *z;
+	int res = -1;
+	int zone;
+
+#if 0
+	fprintf(stderr, "Playing tone %d (%s) on %d\n", tone, tone_zone_tone_name(tone), fd);
+#endif
+	if (fd > -1) {
+		res = ioctl(fd, DAHDI_SENDTONE, &tone);
+		if ((res < 0) && (errno == ENODATA)) {
+			ioctl(fd, DAHDI_GETTONEZONE, &zone);
+			z = tone_zone_find_by_num(zone);
+			if (z) {
+				res = tone_zone_register_zone(fd, z);
+				/* Recall the zone */
+				ioctl(fd, DAHDI_SETTONEZONE, &zone);
+				if (res < 0) {
+					fprintf(stderr, "Failed to register zone '%s': %s\n", z->description, strerror(errno));
+				} else {
+					res = ioctl(fd, DAHDI_SENDTONE, &tone);
+				}
+			} else
+				fprintf(stderr, "Don't know anything about zone %d\n", zone);
+		}
+	}
+	return res;
+}
diff --git a/tonezone.h b/tonezone.h
new file mode 100644
index 0000000..07c5f98
--- /dev/null
+++ b/tonezone.h
@@ -0,0 +1,90 @@
+/*
+ * BSD Telephony Of Mexico "Tormenta" Tone Zone Support 2/22/01
+ * 
+ * Working with the "Tormenta ISA" Card 
+ *
+ * Copyright (C) 2001-2008, Digium, Inc.
+ *
+ * Primary Author: Mark Spencer <markster at digium.com>
+ *
+ */
+
+/*
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU Lesser General Public License Version 2.1 as published
+ * by the Free Software Foundation. See the LICENSE.LGPL file
+ * included with this program for more details.
+ *
+ * In addition, when this program is distributed with Asterisk in
+ * any form that would qualify as a 'combined work' or as a
+ * 'derivative work' (but not mere aggregation), you can redistribute
+ * and/or modify the combination under the terms of the license
+ * provided with that copy of Asterisk, instead of the license
+ * terms granted here.
+ */
+
+#ifndef _TONEZONE_H
+#define _TONEZONE_H
+
+#include <dahdi/user.h>
+
+struct tone_zone_sound {
+	int toneid;
+	char data[256];				/* Actual zone description */
+	/* Description is a series of tones of the format:
+	   [!]freq1[+freq2][/time] separated by commas.  There
+	   are no spaces.  The sequence is repeated back to the 
+	   first tone description not preceeded by !.  time is
+	   specified in milliseconds */
+};
+
+struct tone_zone {
+	int zone;				/* Zone number */
+	char country[10];			/* Country code */
+	char description[40];			/* Description */
+	int ringcadence[DAHDI_MAX_CADENCE];	/* Ring cadence */
+	struct tone_zone_sound tones[DAHDI_TONE_MAX];
+	int dtmf_high_level;			/* Power level of high frequency component
+						   of DTMF, expressed in dBm0. */
+	int dtmf_low_level;			/* Power level of low frequency component
+						   of DTMF, expressed in dBm0. */
+	int mfr1_level;				/* Power level of MFR1, expressed in dBm0. */
+	int mfr2_level;				/* Power level of MFR2, expressed in dBm0. */
+};
+
+extern struct tone_zone builtin_zones[];
+
+/* Register a given two-letter tone zone if we can */
+int tone_zone_register(int fd, char *country);
+
+/* Register a given two-letter tone zone if we can */
+int tone_zone_register_zone(int fd, struct tone_zone *z);
+
+/* Retrieve a raw tone zone structure */
+struct tone_zone *tone_zone_find(char *country);
+
+/* Retrieve a raw tone zone structure by id instead of country*/
+struct tone_zone *tone_zone_find_by_num(int id);
+
+/* Retrieve a string name for a given tone id */
+char *tone_zone_tone_name(int id);
+
+/* Set a given file descriptor into a given country -- USE THIS
+   INTERFACE INSTEAD OF THE IOCTL ITSELF.  Auto-loads tone
+   zone if necessary */
+int tone_zone_set_zone(int fd, char *country);
+
+/* Get the current tone zone */
+int tone_zone_get_zone(int fd);
+
+/* Play a given tone, loading tone zone automatically
+   if necessary */
+int tone_zone_play_tone(int fd, int toneid);
+
+#endif
diff --git a/wavformat.h b/wavformat.h
new file mode 100644
index 0000000..c7b1626
--- /dev/null
+++ b/wavformat.h
@@ -0,0 +1,48 @@
+/*
+ * wavformat.h -- data structures and associated definitions for wav files
+ *
+ * By Michael Spiceland (mspiceland at digium.com)
+ *
+ * (C) 2009 Digium, Inc.
+ */
+
+/*
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2 as published by the
+ * Free Software Foundation. See the LICENSE file included with
+ * this program for more details.
+ */
+
+#ifndef WAVFORMAT_H
+#define WAVFORMAT_H
+
+#include <stdint.h>
+
+struct wavheader {
+	/* riff type chunk */
+	char riff_chunk_id[4];
+	uint32_t riff_chunk_size;
+	char riff_type[4];
+
+	/* format chunk */
+	char  fmt_chunk_id[4];
+	uint32_t  fmt_data_size;
+	uint16_t fmt_compression_code;
+	uint16_t fmt_num_channels;
+	uint32_t  fmt_sample_rate;
+	uint32_t  fmt_avg_bytes_per_sec;
+	uint16_t fmt_block_align;
+	uint16_t fmt_significant_bps;
+
+	/* data chunk */
+	char data_chunk_id[4];
+	uint32_t data_data_size;
+} __attribute__((packed));
+
+#endif
diff --git a/xpp/Makefile b/xpp/Makefile
new file mode 100644
index 0000000..38b5956
--- /dev/null
+++ b/xpp/Makefile
@@ -0,0 +1,140 @@
+PEDANTIC	= -ansi -pedantic -std=c99
+
+INSTALL		= install
+INSTALL_DATA	= install -m 644
+
+#
+# Ugly hack to find kernel directories before/after the split
+# to kernel/user-space.
+#
+# These variables should be passed to us. But until then...
+#
+DAHDI_TOOLSDIR	?= ..
+DAHDI_KERNELDIR	=
+
+-include $(DAHDI_TOOLSDIR)/makeopts
+
+INSTALL_DATA	= $(INSTALL) -m 644
+
+# In 1.4 those are provided by autoconf through makeopts
+prefix		?= /usr
+datadir		?= $(prefix)/share
+mandir		?= $(datadir)/man
+INSTALL		?= install
+
+INSTALL_DATA	= $(INSTALL) -m 644
+
+SBINDIR		= $(prefix)/sbin
+DATADIR		= $(datadir)/dahdi
+MANDIR		= $(mandir)/man8
+HOTPLUG_USB_DIR	= $(sysconfdir)/hotplug/usb
+PERLLIBDIR	:= $(shell eval `perl -V:sitelib`; echo "$$sitelib")
+PERL_DIRS	:= $(shell cd perl_modules; find * -name '[A-Z]*' -type d| xargs)
+PERL_MODS_PAT	:= *.pm $(PERL_DIRS:%=%/*.pm)
+PERL_MODS	:= $(shell cd perl_modules; echo $(PERL_MODS_PAT))
+
+# Variables that should be defined above, but need sane defaults:
+# FIXME: Are those values really sane?
+HOSTCC		?= $(CC)
+
+
+CFLAGS		+= -g -Wall $(USB_INCLUDE)
+
+%.8: %
+	pod2man --section 8 $^ > $@ || $(RM) $@
+PERL_SCRIPTS	=	\
+		dahdi_registration	\
+		xpp_sync	\
+		lsdahdi		\
+		xpp_blink	\
+		dahdi_genconf	\
+		dahdi_hardware	\
+		twinstar	\
+		#
+
+PERL_MANS	= $(PERL_SCRIPTS:%=%.8)
+
+ABHEXLOAD_OBJS		= astribank_hexload.o hexfile.o pic_loader.o astribank_usb.o mpp_funcs.o debug.o
+ABTOOL_OBJS		= astribank_tool.o astribank_usb.o mpp_funcs.o debug.o
+ABALLOW_OBJS		= astribank_allow.o astribank_usb.o mpp_funcs.o debug.o
+
+TARGETS	= .perlcheck astribank_is_starting
+PROG_INSTALL	= astribank_is_starting
+MAN_INSTALL	= $(PROG_INSTALL:%=%.8)
+ifeq	(1,$(PBX_USB))
+TARGETS	+= fpga_load		\
+	   astribank_tool	\
+	   astribank_hexload	\
+	   astribank_allow	\
+	   test_parse
+PROG_INSTALL	+= fpga_load astribank_tool astribank_hexload astribank_allow
+endif
+ifneq	(,$(PERLLIBDIR))
+PROG_INSTALL	+= $(PERL_SCRIPTS)
+TARGETS		+= $(PERL_MANS)
+endif
+
+all: $(TARGETS)
+
+docs: $(PERL_MANS)
+
+install: all
+	$(INSTALL) -d $(DESTDIR)$(SBINDIR)
+	$(INSTALL) $(PROG_INSTALL) $(DESTDIR)$(SBINDIR)/
+	$(INSTALL) -d $(DESTDIR)$(DATADIR)
+	$(INSTALL) xpp_fxloader astribank_hook $(DESTDIR)$(DATADIR)/
+	$(INSTALL) waitfor_xpds $(DESTDIR)$(DATADIR)/
+	$(INSTALL) -d $(DESTDIR)$(MANDIR)
+	$(INSTALL_DATA) $(MAN_INSTALL) $(DESTDIR)$(MANDIR)/
+	$(INSTALL) -d $(DESTDIR)$(HOTPLUG_USB_DIR)
+	$(INSTALL_DATA) xpp_fxloader.usermap $(DESTDIR)$(HOTPLUG_USB_DIR)/
+	# for backward compatibility and for hotplug users:
+	ln -sf $(DATADIR)/xpp_fxloader $(DESTDIR)$(HOTPLUG_USB_DIR)/
+ifneq	(,$(PERLLIBDIR))
+	$(INSTALL) -d $(DESTDIR)$(PERLLIBDIR)
+	for i in $(PERL_DIRS); \
+	do \
+		$(INSTALL) -d "$(DESTDIR)$(PERLLIBDIR)/$$i"; \
+	done
+	for i in $(PERL_MODS); \
+	do \
+		$(INSTALL_DATA) "perl_modules/$$i" "$(DESTDIR)$(PERLLIBDIR)/$$i"; \
+	done
+endif
+
+fpga_load: fpga_load.o hexfile.o
+fpga_load: LIBS+=$(EXTRA_LIBS) $(USB_LIB)
+
+astribank_hexload: $(ABHEXLOAD_OBJS)
+astribank_hexload: LIBS+=$(EXTRA_LIBS) $(USB_LIB)
+
+astribank_tool: $(ABTOOL_OBJS)
+astribank_tool: LIBS+=$(EXTRA_LIBS) $(USB_LIB)
+
+astribank_allow: $(ABALLOW_OBJS)
+astribank_allow: LIBS+=$(EXTRA_LIBS) $(USB_LIB)
+
+astribank_is_starting: astribank_is_starting.o
+astribank_is_starting: LIBS+=$(EXTRA_LIBS)
+
+fpga_load.o: CFLAGS+=-D_GNU_SOURCE	# We use memrchr()
+
+test_parse: test_parse.o hexfile.o
+test_parse: LIBS+=$(EXTRA_LIBS) $(USB_LIB)
+
+%: %.o
+	$(CC) $(LDFLAGS) $^ $(LIBS) -o $@
+
+.perlcheck: $(PERL_SCRIPTS)
+	for i in $^; do perl -I./perl_modules -c $$i || exit 1; done
+	touch $@
+
+clean:
+	$(RM) .depend *.o $(TARGETS)
+
+.PHONY: depend
+depend: .depend
+.depend: *.c *.h
+	@$(CC) -MM *.c > $@ || rm -f $@
+
+include .depend
diff --git a/xpp/README.Astribank b/xpp/README.Astribank
new file mode 100644
index 0000000..cd46144
--- /dev/null
+++ b/xpp/README.Astribank
@@ -0,0 +1,1656 @@
+Xorcom Astribank Documentation
+==============================
+Xorcom Team <support at xorcom.com>
+$Revision$, $Date$
+
+This file documents the DAHDI drivers for the Xorcom Channel Bank.
+
+It is generally a more technical document than the 
+http://www.xorcom.com/product-manuals/product-manuals.html[Astribank 
+User Manual]
+
+An HTML version of the latest version of this document could be found at 
+http://docs.tzafrir.org.il/dahdi-tools/README.Astribank.html[]
+
+Introduction
+------------
+The Xorcom Astribank is a USB-connected channel-bank. An Astribank may
+have up to 4 modules:
+
+PRI:: 
+  1, 2 or 4 ports of E1 or T1. Can only be the first (left-most) module
+  of the Astribank. Note that each port has physically a pair of ports,
+  where the top one has crossed wiring.
+
+BRI::
+  2, 4 or 8 ports of BRI. Can only be used as the first (left-most)
+  module of the Astribank. 
+
+FXO::
+  8 ports of FXO (connector to an analog PSTN line).
+
+FXS::
+  8 ports of FXS (connector to an analog phone). If used as the first
+  (left-most) module, it will also have 2 output lines and 4 input lines
+  that will appear on DAHDI like standard DAHDI ports. The input and
+  output ports are connected from the two RJ-45 connectors on the right
+  side of the module.
+
+There is also a 6FXS-2FXO module that is essentially an FXS module with
+six lines instead of 8 (but still with the input and output ports) and
+an FXO module of two ports.
+
+
+Building and Installation
+-------------------------
+Apart from the standard DAHDI build requirements, you also need libusb
+development headers to build the fpga_load firmware loader. This is
+typically the package libusb-dev on Debian (and derivatives like Ubuntu)
+or libusb-devel on RedHat (and derivatives like CentOS/Trixbox).
+
+Patch for BRI
+~~~~~~~~~~~~~
+(As of DAHDI 2.2 this patch is no longer needed. Furthermore, it does
+not apply. The same directory has a newer patch that applies. This
+section is kept in the document for the time being for the benefit of
+those with older versions)
+
+In order for the BRI module (xpd_bri.ko) to build, you still need an
+external patch: 
+
+http://updates.xorcom.com/astribank/bristuff/dahdi_bri_dchan.diff[]
+
+You need to apply it to the dahdi-linux tarball before building:
+
+  wget http://updates.xorcom.com/astribank/bristuff/dahdi_bri_dchan.diff
+  patch -p1 <dahdi_bri_dchan.diff
+
+
+Installation Scenarios
+~~~~~~~~~~~~~~~~~~~~~~
+Below are some commented sequences of commands that can be used at some
+common scenarios. Those scenarios begin only after you installed the
+software (dahdi-linux, dahdi-tools, asterisk, etc.).
+
+New Installation Scenario
+^^^^^^^^^^^^^^^^^^^^^^^^^
+Installing Astribank on a system where there's no existing Astribank.
+You install the driver when the Astribank was already connected:
+
+--------------------------------------------
+# If you had the hardware already connected: Load just the USB firmware
+/usr/share/dahdi/xpp_fxloader usb
+# (you could use 'load' instead of 'usb' but this is also a good test
+# that automatic load through firmware is also in place)
+dahdi_hardware -v
+# wait until the Astribank has a product ID of 11x2
+sleep 5 # Just wait a little bit 
+dahdi_hardware -v # now that you see that all's well:
+/etc/init.d/dahdi start
+# generate configuration:
+dahdi_genconf
+# Apply it:
+dahdi_cfg
+
+# edit /etc/asterisk/chan_dahdi.conf to #include dahdi-channels.conf or
+# copy its content to the end of chan_dahdi.conf
+#
+# This stops existing DAHDI calls, if any, but does no other harm:
+asterisk -rx 'dahdi restart' 
+--------------------------------------------
+
+
+Upgrade Scenario
+^^^^^^^^^^^^^^^^
+Upgrading is roughly the same as a new installation. But in many cases 
+you begin with  resetting the firmware.
+
+I also assume here that the configuration is valid, and hence I don't
+generate it.
+
+--------------------------------------------
+# If you need to reset the firmware:
+/usr/share/dahdi/xpp_fxloader reset
+# (you could use 'load' instead of 'usb' but this is also a good test
+# that automatic load through firmware is also in place)
+dahdi_hardware -v
+# wait until the Astribank has a product ID of 11x2
+sleep 5 # Just wait a little bit
+dahdi_hardware -v # now that you see that all's well:
+/etc/init.d/dahdi start
+#
+# This stops existing DAHDI calls, if any, but does no other harm:
+asterisk -rx 'dahdi restart' 
+--------------------------------------------
+
+
+Sample Configurations
+---------------------
+We generally recommend to generate the configuration by using utility
+dahdi_genconf which are included with DAHDI. Nevertheless, the following 
+can serve as reference configurations for a system where Astribank devices 
+are used.
+
+Also refer to the general README for documentation of the other DAHDI
+configuration files.
+
+xpp.conf: Astribank Initialization
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+/etc/dahdi/xpp.conf is read by the initialization scripts of Astribank
+modules:
+-----------------------------------------------------------
+# /etc/dahdi/xpp.conf
+#
+# This file is used to configure the operation
+# of init_card_* initialization scripts.
+#
+
+# Adds many more tracing messages that are sent to syslog:
+#debug		1
+
+# xpd_pri: E1 or T1. The default is E1 for all the ports.
+#   Setting T1 instead:
+#pri_protocol	T1
+#
+#  Or if you actually want to mix E1 and T1:
+#pri_protocol/xbus-00/xpd-02	T1
+#pri_protocol/connector:usb-0000:00:1d.7-7/xpd-03	T1
+#pri_protocol/label:usb:0000183/xpd-03	T1
+# If several definitions can refer to a port, the last wins. 
+# If none applies, the default of E1 holds.
+
+#  FXO: country to adjust settings to:
+#opermode	FRANCE
+
+#  Don't run power calibration on the FXS units. This can save time
+#  but can also get you unit randomly disconnect, if badly used:
+#fxs_skip_calib	1
+-----------------------------------------------------------
+
+
+xpp_order: Explicitly order Astribanks
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+(This feature is available as of DAHDI 2.2)
+
+On a system with multiple Astribank you would normally want to guarantee
+that Astribanks are registered in the same order regardless of the order
+in which they are connected or detected. Assuming that you register them
+all at the same time. In order to do that, you should list the
+Astribanks explicitly under /etc/dahdi/xpp_order .
+
+Astribanks that are listed there are registered first (according to the
+order of lines in the files). Astribanks not listed there are added
+last, and sorted by the 'USB connector' string.
+
+You can identify an Astribank in two ways: 
+
+Label::
+  each Astribank (except some really old ones) has a label . This 
+  identifies the actual Astribank box.
+
+Connector::
+  Identify the path the Astribank is connected through. E.g.: to what
+  USB port you connected it.
+
+Identifying an Astribank by the label seems simpler and more
+predictable. Though it may have some slightly surprising effects if
+replace one Astribank with another.
+
+The sample configuration file:
+-----------------------------------------------------------
+#
+# This is an optional configuration file for ordering
+# Dahdi registration.
+#
+# It is read from /etc/dahdi/xpp_order. This location
+# may be overriden via the environment variable XPPORDER_CONF
+#
+# Lines may contain:
+#   - The Astribank label (verbatim)
+#   - The Astribank connector string (prefixed with @)
+# Ordering number of each listed Astribank is determined
+# by its position in this file.
+# Astribanks not listed in this file, get an ordering
+# number of 99 (last).
+#
+# Astribanks with same ordering number are sorted by their
+# connectors (to preserve legacy behaviour).
+#
+# Examples:
+#usb:1234
+#@usb-0000:06:02.2-2
+-----------------------------------------------------------
+
+In order to generate one that includes all the Astribanks in the system
+with the current order in which they are connected, use:
+
+  dahdi_genconf xpporder
+
+For more technical details see the section <<_registering_in_dahdi>>
+below.
+
+
+/etc/dahdi/system.conf
+~~~~~~~~~~~~~~~~~~~~~~
+
+Astribank 8
+^^^^^^^^^^^
+    fxoks=1-14
+
+Astribank 6FXS/2FXO
+^^^^^^^^^^^^^^^^^^^
+    fxoks=1-12
+    fxsks=13-14
+
+Astribank 16: 8FXS/8FXO
+^^^^^^^^^^^^^^^^^^^^^^^
+    fxoks=1-14
+    fxsks=15-22
+
+Astribank 4 BRI
+^^^^^^^^^^^^^^^
+    # Assumed ports settings:
+    # Ports 1,3: TE
+    # Ports 2,4: NT
+    span=1,1,1,ccs,ami
+    span=2,0,1,ccs,ami
+    span=3,2,1,ccs,ami
+    span=4,0,1,ccs,ami
+    bchan=1-2,4-5,7-8,10-11
+    ; if you applied the bri_dchan patch:
+    ;dchan=3,6,9,12
+    hardhdlc=3,6,9,12
+
+Astribank 4 PRI E1
+^^^^^^^^^^^^^^^^^^
+    # Assumed ports settings:
+    # Ports 1,3: TE (CPE)
+    # Ports 2,4: NT (Net)
+    span=1,1,1,ccs,hdb3,crc4
+    span=2,0,1,ccs,hdb3,crc4
+    span=3,2,1,ccs,hdb3,crc4
+    span=4,0,1,ccs,hdb3,crc4
+    bchan=1-15,17-30,31-45,47-60,61-75,77-90,91-105,107-120
+    dchan=16,46,76,106
+
+Astribank 4 PRI T1
+^^^^^^^^^^^^^^^^^^
+    # Assumed ports settings:
+    # Ports 1,3: TE (CPE)
+    # Ports 2,4: NT (Net)
+    span=1,1,1,esf,b8zs
+    span=2,0,1,esf,b8zs
+    span=3,2,1,esf,b8zs
+    span=4,0,1,esf,b8zs
+    bchan=1-23,25-47,49-71,73-95
+    dchan=24,48,72,96
+  
+
+/etc/asterisk/chan_dahdi.conf
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Astribank 8
+^^^^^^^^^^^   
+    [channels]
+    signalling=fxo_ks
+    ; The real analog ports:
+    context=from-internal
+    echocancel=yes
+    ; echocancelwhenbriged=yes
+    ; echotraining=no
+    channel => 1-8
+
+    ; output ports:
+    context=astbank-output
+    channel => 9-10
+    ; input ports:
+    immediate=yes
+    context=astbank-input
+    channel => 11-14
+    immediate=no
+
+Astribank 6FXS/2FXO
+^^^^^^^^^^^^^^^^^^^   
+    [channels]
+    signalling=fxo_ks
+    ; The real analog ports:
+    context=from-internal
+    echocancel=yes
+    ; echocancelwhenbriged=yes
+    ; echotraining=no
+    channel => 1-6
+
+    ; output ports:
+    context=astbank-output
+    channel => 7-8
+    ; input ports:
+    immediate=yes
+    context=astbank-input
+    channel => 9-12
+    immediate=no
+
+    ; FXO ports
+    signalling=fxs_ks
+    context=from-pstn
+    callerid=asreceived
+    channel => 13-14
+
+Astribank 16: 8FXS/8FXO
+^^^^^^^^^^^^^^^^^^^^^^^   
+    [channels]
+    signalling=fxo_ks
+    ; The real analog ports:
+    context=from-internal
+    echocancel=yes
+    ; echocancelwhenbriged=yes
+    ; echotraining=no
+    channel => 1-8
+
+    ; output ports:
+    context=astbank-output
+    channel => 9-10
+    ; input ports:
+    immediate=yes
+    context=astbank-input
+    channel => 11-14
+    immediate=no
+
+    ; FXO ports
+    signalling=fxs_ks
+    context=from-pstn
+    callerid=asreceived
+    channel => 15-22
+
+Astribank 4 BRI
+^^^^^^^^^^^^^^^    
+    ; Assumed ports settings:
+    ; Ports 1,3: TE
+    ; Ports 2,4: NT
+    [channels]
+    switchtype = euroisdn
+    callerid = asreceived
+    
+    ; TE ports:
+    signalling = bri_cpe_ptmp
+    ;signalling = bri_cpe
+    context = from-pstn
+    group = 1,11
+    channel => 1,2
+    
+    group = 1,13
+    channel => 7,8
+    
+    ; NT ports:
+    signalling = bri_net_ptmp
+    ;signalling = bri_net
+    context = from-internal
+    group = 2,12
+    channel => 4,5
+    
+    group = 2,14
+    channel => 10,11
+
+Astribank 4 PRI E1
+^^^^^^^^^^^^^^^^^^ 
+    ; Assumed ports settings:
+    ; Ports 1,3: TE
+    ; Ports 2,4: NT
+    [channels]
+    switchtype = euroisdn
+    callerid = asreceived
+    
+    ; TE ports:
+    signalling = pri_cpe
+    context = from-pstn
+    group = 1,11
+    channel => 1-15,17-30
+    
+    group = 1,13
+    channel => 61-75,77-90
+    
+    ; NT ports:
+    signalling = pri_net
+    ;signalling = pri_net
+    context = from-internal
+    group = 2,12
+    channel => 31-45,47-60
+    
+    group = 2,14
+    channel => 91-105,107-120
+
+Astribank 4 PRI T1
+^^^^^^^^^^^^^^^^^^ 
+    ; Assumed ports settings:
+    ; Ports 1,3: TE
+    ; Ports 2,4: NT
+    [channels]
+    switchtype = national
+    callerid = asreceived
+    
+    ; TE ports:
+    signalling = pri_cpe
+    context = from-pstn
+    group = 1,11
+    channel => 1-23
+    
+    group = 1,13
+    channel => 49-71
+    
+    ; NT ports:
+    signalling = pri_cpe
+    ;signalling = pri_net
+    context = from-internal
+    group = 2,12
+    channel => 25-47
+    
+    group = 2,14
+    channel => 73-95
+
+
+/etc/asterisk/extensions.conf
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Sample dialplan (extensions.conf) for all the above:
+
+-----------------------------------------------------------
+[phones-dahdi]
+; With Asterisk 1.4 you will may need to use here 'Zap' instead of
+; DAHDI. See Zaptel-to-DAHDI.txt .
+;
+; 6001 will dial to channel 1, 6020, to DAHDI channel 20, etc.
+exten => _6XXX,1,Dial(DAHDI/${EXTEN:1})
+; Useful for debugging trunks. Will potentially allow users to
+; bypass context limitations.
+;exten => _6XXX.,1,Dial(DAHDI/${EXTEN:1:3}/${EXTEN:4})
+
+[trunk]
+; A number that begins with 9: dial it through a trunk
+; (we put FXO channels and TE channels in group 0).
+; The leading 9 is stripped.
+exten => _9.,1,Dial(DAHDI/g0/${EXTEN:1})
+; dialing a number that begins with 83 will dial it through
+; span 3, and so forth. The two leading digits are stripped.
+; (Each digital span is also added to group 10+span number).
+exten => _8X.,1,Dial(DAHDI/g1${EXTEN:1:1}/${EXTEN:2})
+
+[from-internal] 
+; The context of FXS ports: analog phones.
+; They are allowed to dial to all other phones 
+include => phones-dahdi 
+; They are also allowed to call through the trunk: 
+include => trunk
+; some simple tests:
+include => astbank-test
+
+[from-pstn] 
+; Calls from the PSTN enter here. Redirect calls to an IVR 
+; or a default extension in the s context here. In this case we  
+; redirect calls to DAHDI channel 1: 
+exten => s,1,Dial(DAHDI/1) 
+
+; Alternatively, the following will redirect you to the demo IVR 
+; from the sample extensions.conf of Asterisk:
+include => demo
+
+; An extra context with some simple tests
+[astbank-test]
+; 200: echo test
+exten => 200,1,Answer
+exten => 200,n,Wait(1)
+exten => 200,n,Echo()
+exten => 200,n,Hangup
+
+; 203: say extension number. Will only work if caller ID 
+; is properly set in chan_dahdi.conf / dahdi-channels.conf
+exten => 203,1,Answer
+exten => 203,n,Wait(1)
+exten => 203,n,SayNumber(${CALLERID(num)})
+exten => 203,n,Hangup
+
+[astbank-input] 
+exten => s,1,Set(DAHDI_CHAN=${CUT(CHANNEL,-,1)}) 
+exten => s,n,Set(DAHDI_CHAN=${CUT(DAHDI_CHAN,/,2)}) 
+; 11 is the number of the first input port. At least in the sample 
+; configuration below. 
+;exten => s,n,Set(INPUT_NUM=$[${DAHDI_CHAN}-11)]) 
+; The sample below just logs the signal.  
+exten => s,n,NoOp(Got signal from DAHDI Channel ${DAHDI_CHAN}) 
+; Alternatively: 
+;exten => s,n,System(run something) 
+
+; No. We did not forget the context astbank-outputs. Output 
+; ports only get calls from the PBX. Thus they don't need a context 
+; of their own. Sending them to a context of their on makes 
+; 'dahdi show channels' in the CLI provide useful display, though.
+-----------------------------------------------------------
+
+
+Troubleshooting
+---------------
+The following commands provide useful information for debugging:
+
+lsusb Test
+~~~~~~~~~~
+Check USB level status. You can use one of the following utilities for it:
+
+  dahdi_hardware -v
+       or
+  lsusb | grep e4e4
+
+- Look for the USB Product ID (the second number after e4e4).
+- If you see *11x2* (e.g: 1152)- the FPGA firmware has been loaded.
+  Move on.
+  dahdi_hardware will also show you some more details if the driver
+  is loaded while the lsusb will just list the device.
+- If it shows something as product ID *11x0* - the USB firmware is not
+  loaded. Maybe you need to run fxload. Or maybe just unplug and plug again
+  the device. Also make sure that you have fxload installed.
+- If lsusb shows the Product ID as *11x1* - only the USB firmware is loaded 
+  and not the FPGA firmware is loaded. If this is still the case after 
+  a while - either the firmware loading has failed or you don't have
+  fpga_load. Make sure you have libusb-dev(el) installed when
+  building DAHDI. After you have installed it, you may need to re-run
+  ./configure .
+- It should list all of your Astribank devices. If it doesn't (for
+  more than period of time needed for the initial firmware
+  loading) - Check that the Astribank is connected indeed.
+
+
+DAHDI Registration
+~~~~~~~~~~~~~~~~~~
+Check if the Astribank spans are registered with DAHDI:
+
+  dahdi_registration
+
+- This should give useful results after the drivers have identified
+  and your devices are initialized.
+- It should list all Astribank XPDs. For each of them it should write
+  "on" or "off". If the registration status is "off", then it means that
+  the span has not been registered in DAHDI and therefore can not be used
+  yet.
+- Registration is normally done as part of `/etc/init.d/dahdi start`.
+  If you want to register the spans manually, then run command:
+  `dahdi_registration on` .
+
+
+DAHDI Level Information
+~~~~~~~~~~~~~~~~~~~~~~~
+You can get some information regarding DAHDI channels by running one of the
+following commands:
+
+    lsdahdi
+       or
+    cat /proc/dahdi/*
+
+- Those two are almost the same. The lsdahdi produced more correctly sorted
+  output if you have more than 10 spans, and also make the output listing
+  looks a little bit nicer.
+- You can see if your DAHDI spans and channels were loaded, if
+  they were configured by dahdi_cfg and if they are in use (typically by
+  Asterisk).
+  For example:
+  Not configured Astribank FXS channel will be displayed as:
+
+     42 FXS
+
+- When *dahdi_cfg* has applied the configuration of the channel (from 
+  /etc/dahdi/system.conf), you will see an extra column for the signalling
+  type of the channel. The same channel after it has been configured:
+
+    42 FXS        FXOKS
+
+- If a program (which is typically Asterisk) uses it, you'll see:
+
+    42 FXS        FXOKS      (In use)
+
+
+
+Asterisk Level Information
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+  asterisk -rx 'dahdi show channels'
+
+- If you get error "Unable to connect to remote asterisk" then it
+  means that the Asterisk is not running. It is possible that Asterisk
+  has failed to start due to misconfigured chan_dahdi.conf or whatever reason.
+  Check /var/log/asterisk/messages or /var/log/asterisk/full .
+- If you get the error that "there is no such command" then it means that
+  chan_dahdi.so is not loaded. There are two reasons for such problem:
+  * chan_dahdi.so is not even built. Check if the file exists:
+
+       ls -l /usr/lib/asterisk/modules/chan_dahdi.so
+
+  * the chan_dahdi.so file exists but it is not loaded. Try to load it manually:
+
+       asterisk -rx 'load module chan_dahdi.so'
+
+- You see "pseudo" channel only. It means that you have not configured any
+  channels. If you have configured channels in chan_dahdi.conf, you may
+  need either to restart the Asterisk or unload/load chan_dahdi.so manually.
+  You can use the following Asterisk CLI commands for it: `unload chan_dahdi.so` 
+  and `load chan_dahdi.so`
+
+
+Known Issues
+~~~~~~~~~~~~
+Empty /proc dir
+^^^^^^^^^^^^^^^
+.Symptoms:
+- Error message:
+
+  "ERR-xpd_fxo: XBUS-00/XPD-00: Failed initializing registers (-22)"
+  
+- Likewise for all XPDs. 
+- The directory /proc/xpp exists but is empty (not even the files 
+  'xbuses' and 'sync').
+
+.Cause:
+The driver failed to recreate the procfs directory /proc/xpp and hence
+everything under it. This is because it has already existed. And it
+existed because a process still uses it. This is typically because you
+have a shell whose working directory is /proc/xpp or somewhere under
+it:
+
+  # lsof /proc/xpp
+  COMMAND  PID USER   FD   TYPE DEVICE SIZE       NODE NAME
+  bash    2741 root  cwd    DIR    0,3    0 4026532684 /proc/xpp
+
+.Fix:
+Move that process from that directory, or close the file it uses from
+under /proc/xpp and reload the dahdi / xpp drivers.
+
+
+Bad Firmware Version
+^^^^^^^^^^^^^^^^^^^^
+.Symptoms:
+- An Astribank finishes initialization quickly, the /proc/XBUS-nn
+  directory has no XPD-mm subdirectories.
+- Error in the kernel logs about:
+
+  NOTICE-xpp: XBUS-00: XPD at 00: type=6.0 has bad firmware revision 2.6 
+
+.Cause:
+This is normally caused by an Astribank with an older firmware connected
+to a 
+
+The protocol version supported by the firmware will typically be the same 
+one as in the device initialization scripts installed to 
+/usr/share/dahdi . Hence if this version installed 
+`/usr/share/dahdi/init_card_3_29` it will probably include firmware of 
+protocol version 29.
+
+.Fix:
+Reset the firmware:
+
+  /usr/share/dahdi/xpp_fxloader reset
+
+Or disconnect the Astribank from the power and reocnnect. On some older 
+versions of the USB firmware resetting the firmware (or any operation of 
+fpga_load) would fail if the driver is loaded. Hence you would need to 
+run `rmmod xpp_usb` . In the end, reload the drivers.
+
+
+USB Errors at Shutdown
+^^^^^^^^^^^^^^^^^^^^^^
+.Symptoms:
+You see USB-related errors similar to the following whenever you shut
+down the drivers of the Astribank or disconnect its drivers:
+
+  ERR-xpp_usb: XBUS-00: Failed to submit a receive urb
+
+.Cause:
+This is a normal part of the shutdown of the USB connection. 
+
+.Fix:
+Ignore them. Unless the USB should not have disconnected at that time.
+
+
+BRI Layer 1 Down
+^^^^^^^^^^^^^^^^
+.Symptoms:
+With the BRI module only, and not in the middle of an active call, you
+notice that suddenly the line goes down. The LED of the port stops
+blinking, layer1 not listed as "active" in the bri_info file in
+/proc/xpp, and the span is in RED alarm in DAHDI.
+
+You may also see an error message such as:
+
+  NOTICE-xpd_bri: XBUS-00/XPD-02: D-Chan RX Bad checksum: [2A:01=FC] (252)
+
+from the exact time of the disconnecting.
+
+.Cause:
+This is expected with most european BRI PtMP providers. If they support
+PtMP, they are normally also expected to support ISDN phones, that get
+the power from the provider. And thus they shut down the line whenever
+there's no active call. 
+
+Sometimes the line is shut down in the middle of a layer 2 message. In
+the BRI driver the HDLC decoding/encoding is done in the card. In that
+case we may get the above error.
+
+.Fix:
+Normaly this is not a problem. The driver will re-establish a connection
+once a new call needs to be made.
+
+
+Astribank in lsusb but not in dahdi_hardware
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+.Symptoms:
+You fail to find an Astribank device in the output of lsusb . But you
+see it in `lsusb | grep e4e4`
+
+.Cause:
+The perl module Dahdi::Hardware currently relies on
+/proc/bus/usb/devices (from usbfs) whereas lsusb can use either that or
+/dev/bus/usb . 
+
+.Fix:
+Usbfs is generally deprecated and some distributions (OpenSUSE, Ubuntu) no 
+longer mount it by default. Try:
+
+  mount /proc/bus/usb
+
+and if that doesn't work:
+
+  mount -t usbfs usbfs /proc/bus/usbfs
+
+However this is generally a cosmetic issue that only affects the listing
+in dahdi_hardware.
+
+
+Astribank not initialized: Premature packet end
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+.Symptoms:
+After upgrading to Zaptel 1.4.12 / 1.2.25 the initialization of the
+Astribank times out. In the logs you see:
+
+  kernel: NOTICE-xpp: XBUS-00(00): FIRMWARE: ERROR_CODE CODE = 0x3 (Premature packet end) 
+
+.Cause:
+When an Astribank is detected, the driver asks it what is its version
+and what components it has. Normally if the version of the firmware and
+of the driver does not match the driver gives an ugly message and fails
+the initialization.
+
+However in the change of the protocol between versions 2.9 (29) and 3.0
+(30), the response that the new driver receives from a device with the
+old version is now considered to be an illegal packet and gets
+discarded. As a result, the Astribank waits till time-out for the
+initialization to end.
+
+.Fix:
+Reset the firmware of the Astribank by either:
+
+  /usr/share/dahdi/xpp_fxloader reset
+
+or disconnecting it from the power and reconnecting it.
+
+
+Reference
+---------
+LEDs Indication
+~~~~~~~~~~~~~~~
+The Astribank has 4 global indication leds and one or two per-port leds.
+On some of the models the LEDs are located on the left side on the front
+panel. If there are no separate LEDs there, then the red LEDs of the
+upper left-most ports of the device are used as the indication LEDs. Don't 
+confuse them with green port status LEDs.
+
+The first led is the "Power" led. It is on if the unit gets power.
+The second led is the "Active" led, which is on when there is at 
+least one "active" port (in a call / off-hook, though the meaning of this is 
+different in BRI).
+The last led is called "Hardware OK", but is actually only is on in case of  
+the hardware failure.
+
+The third led is the "Sync" led. If it blinks, the device is synchronized 
+with the driver on the computer. If the device is selected to be the  
+synchronization source for all of the Astribank devices then it will blink
+a quick single blink.
+If the device gets synchronization from the driver, it will blink in a 
+more steady frequency.
+
+"Double blink" indicates that the unit has an FXO module, and still is
+getting synchronization from the computer, and is not the synchronization
+source.
+
+The per-port green led on analog (both FXS and FXO) indicates that the
+port is off-hook.
+
+On the BRI, the green led indicates a TE port whereas an orange led
+indicates an NT port. If the led is solid, the port is down (not even
+layer-1 connection is up). If it is blinking a double blink, layer 1
+is up. A slower single blinking indicates that layer 2 is up as well
+(which means that Asterisk is driving the port).
+
+As for the leds of the PRI ports, see the next section.
+
+
+PRI Ports Configuration
+~~~~~~~~~~~~~~~~~~~~~~~
+Astribank PRI module has two RJ-45 sockets for each PRI port. The lower
+socket provides typical PRI CPE side wiring: Rx- pins 1,2; Tx - pins 
+4,5. The upper socket provides typical PRI Network side  wiring: Rx- pins
+4,5; Tx - pins 1,2. The both sockets are permanently active and you can 
+use any of them regardless of any configuration parameters (Both
+connectors are live. And connecting both of them with a flat 8-wire
+ethernet cable is a simple way to do a loop test for the port).
+
+Each port in the PRI module can be configured either as E1 or T1. 
+The default is E1, but it can be changed in xpp.conf (See the section
+above).
+
+In addition to that, a port defaults to consider itself a CPE, or
+rather, to accept timing from the remote party. To override that you
+need to set the timing value to 0 (second parameter in the 'span=' line
+in system.conf).
+
+Thus the following in system.conf will also set an orange LED:
+
+  span=2,0,3,ccs,hdb3,crc4
+
+Note that as this is only applied when dahdi_cfg is run, the port will have
+the default green LED lit at the bottom until it is configured.
+
+
+Voicemail Indication
+~~~~~~~~~~~~~~~~~~~~
+Asterisk supports several forms of voicemail message waiting indication
+(VMWI) on a phone connected to a FXS port. One of them is a stutter tone
+sent when the phone is picked up. Another one is an FSK tone that
+encodes the number of messages waiting (or 0, for none). Alternatively it
+may send an ioctl call on the channel (DAHDI_VMWI) to indicate the VMWI
+status on the channel.
+
+The DAHDI FXS device may implement any of extra three VMWI notification
+methods. The Astribank currently only supports one of them (AC neon LED).
+With Asterisk, as of 1.6.2 you can enable that using the following line
+in the channel's config in chan_dahdi.conf:
+
+ mwisendtype = neon 
+
+Versions of Asterisk before 1.6.0 did not support this ioctl. You will
+need to reset the module parameter <<_vmwi_ioctl,vmwi_ioctl>>.
+
+
+Device Startup
+~~~~~~~~~~~~~~
+This section describes in great depth the initialization of the Xorcom
+Astribank. Normally it would not be really needed, as the standard
+installation of DAHDI should put everything in place. This is generally
+some documentation to read when things fail.
+
+Terminology
+^^^^^^^^^^^
+There are some technical terms that are used in this document and in the
+driver / dahdi.
+
+span::
+  DAHDI breaks the channels it knows about to logical units called
+  "spans". A port in a E1/T1/ISDN card is usually a span. An whole
+  analog card is also a "span". You can see the list of spans as the list
+  of files under /proc/dahdi directory or in output of the dahdi_tool
+  utility.
+
+XBUS::
+  A funny way to call an Astribank device.
+
+XPD::
+  Basically this is a logical unit of the Astribank. It will be 
+  registered in DAHDI as a single span. This can be either an analog 
+  (FXS or FXO) module or a single port in case of a BRI module.
+
+
+Loading Firmware
+^^^^^^^^^^^^^^^^
+Normally this is done using the script /usr/share/dahdi/xpp_fxloader.
+If it works fine, you don't need to bother reading this section.
+Once the firmware is loaded the USB Vendor ID and Product ID of the Astribank
+became to be e4e4 11x2, and now the driver can pick it up.
+
+First and foremost: the simplest and most useful tool to debug problems
+is lsusb. The output of lsusb should show you if the device is connected
+if its firmware is loaded. 
+
+The firmware files are named *.hex. They are presented in the Intel hex
+format. The files are copied from xpp/utils to /usr/share/dahdi folder 
+during the DAHDI installation.
+
+The Astribank needs a firmware loaded into it. Without the firmware, 
+the device will appear in lsusb with Vendor ID e4e4 and Product ID 11x0
+(1130, 1140, 1150, 1160 or 1163. 1163 behaves almost exactly as 1160).
+The firmware loading process consists of two
+stages. In the first stage the "USB" firmware is loaded by using program
+fxload. When the first stage is completed the Vendor ID is e4e4 and the
+Product ID is 11x1. (e.g. 1151 if it were 1150 previously).
+
+You can use the following command in order to load the "USB" firmware
+manually:
+
+  fxload -t fx2 -D /dev/bus/usb/MMM/NNN -I /usr/share/dahdi/USB_FW.hex
+
+where,
+
+fxload::
+  A standard program that is typically part either of package 'fxload' 
+  or 'hotplug-utils' . 
+/dev/bus/usb::
+  On some old systems it is missing . /proc/bus/usb (usbfs) could be
+  used instead.
+MMM::
+  the first number (bus number)
+NNN::
+  the second number (device number) you see for the device in lsusb
+
+If the loading process has been completed successfully, the device 
+disconnects and then connects again itself with USB Product ID 11x1 
+(and a new device number).
+
+In the second stage, the "FPGA" firmware is loaded.
+The second-stage firmware loading is performed by using program fpga_load, 
+which is built in the directory xpp/utils and then copied to folder 
+/usr/sbin during DAHDI installation.
+
+The command syntax is similar to the syntax of fxload. You can use the 
+following command in order to load the FPGA firmware manually:
+
+  # pick the right name according to the device ID. FPGA_1161.hex is for
+  # 116x Astribanks:
+  astribank_hexload -D /dev/bus/usb/MMM/NNN -F /usr/share/dahdi/FPGA_1161.hex
+  # Note the shell expantion in this line:
+  astribank_hexload -D /dev/bus/usb/MMM/NNN -p /usr/share/dahdi/PIC_TYPE_[1-4].hex
+  # reenumerate (disconnect and reconnect)
+  astribank_tool  -D /dev/bus/usb/MMM/NNN -n
+
+With older USB firmwares (before the one included in e.g. dahdi-linux
+2.2) you needed to use instead of all the above:
+
+  # pick the right name according to the device ID. FPGA_1151.hex is for
+  # 115x Astribanks:
+  fpga_load -D /dev/bus/usb/MMM/NNN -I /usr/share/dahdi/FPGA_1151.hex
+
+Please note, that  NNN value differs from that that was used for the 
+fxload command due to the fact that device has "reconnected" itself 
+with another Product ID number. So you need to run lsusb again and get 
+the new NNN value. Usually, the new value is equal to the old value 
+incremented by 1.
+
+On newer systems (e.g. Centos 4) /dev/bus/usb may not be available. In
+that case, use /proc/bus/usb . usbfs should be mounted there.
+
+
+Automatic Firmware Loading
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+Udev is a framework for dynamic device nodes, which is supported in
+kernel 2.6. if your udev rules are properly  configured then the 
+firmware should be loaded automatically and you will see product ID 11x2
+(e.g.: 1152). 
+
+Udev is mostly configured by files under /etc/udev/rules.d . The
+installer of dahdi-linux installs drivers/dahdi/xpp/xpp.rules into that
+directory.
+
+This file instructs udev to run /usr/share/dahdi/xpp_fxloader for each
+time an Astribank connects and needs firmware. When the Astribank loads
+firmware or when it resets its firmware it "reenumerates" - disconnects
+and reconnects as a new device. 
+
+Below are kernel log messages of an Astribank loading firmware. It firs
+connects without any firmware (device no. 44). Udev tells it to load the
+USB firmware. It disconnects and reconnects (45). This Udev gets the
+FPGA firmware loaded into it. It disconnects again, and when it
+reconnects it is now ready to talk with the driver. The last message is
+from the driver.
+-------------------------------------
+usb 7-1: configuration #1 chosen from 1 choice
+usb 7-1: New USB device found, idVendor=e4e4, idProduct=1150
+usb 7-1: New USB device strings: Mfr=0, Product=0, SerialNumber =0
+usb 7-1: USB disconnect, address 44
+usb 7-1: new high speed USB device using ehci_hcd and address 45
+usb 7-1: configuration #1 chosen from 1 choice
+usb 7-1: New USB device found, idVendor=e4e4, idProduct=1151
+usb 7-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
+usb 7-1: Product: Astribank
+usb 7-1: Manufacturer: Xorcom LTD
+usb 7-1: SerialNumber: 00000123
+usb 7-1: USB disconnect, address 45
+usb 7-1: new high speed USB device using ehci_hcd and address 46
+usb 7-1: configuration #1 chosen from 1 choice
+usb 7-1: reset high speed USB device using ehci_hcd and address 46
+INFO-xpp_usb: XUSB: Xorcom LTD -- Astribank -- FPGA
+-------------------------------------
+
+Another useful tool for tracing UDEV-related issue is the udev monitor:
+
+  udevadm monitor
+
+Or with some older versions of udev:
+
+  udevmonitor
+
+
+Firmware Loading with Hotplug
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Hotplug is an obsolete framework for doing some of the things done by
+udev today. Specifically, handling kernel hotplug events. It is used in
+systems with kernel < 2.6.13 (e.g. RHEL4 / Centos4 and Debian 3.1). As
+such DAHDI still installs support for those. However if you package
+DAHDI for a more recent distribution, you should probably avoid
+including those obsolete config files.
+
+The relevant files installed under /etc/hotplug/usb and are
+xpp/xpp_fxloader.usermap and xpp_fxloader (which is a symlink to
+/usr/share/dahdi/xpp_fxloader). the usermap file has the same format as
+modules.usbmap in the main kernel modules directory: it is intended to
+identify a (hotplugged) device.
+
+
+Loading The Modules
+^^^^^^^^^^^^^^^^^^^
+Here is what should happen:
+In short: you should plug the Astribank device(s) or have them plugged in at
+the boot time. Then all the modules should be loaded automatically.
+You will see xpp_usb, xpp, and some xpd_* modules in the modules list 
+(the output of lsmod).
+
+After the module xpp is loaded, you'll also be able to see the directory
+/proc/xpp. For any Astribank device discovered, you will see there a 
+directory /proc/xpp/XBUS-n (where n is a number: typically 0). Once a unit have
+been discovered you'll see subdirectories: /proc/xpp/XBUS-n/XPD-m (where
+m may be another number: 0, 1 ,etc).
+
+Now to the ugly details:
+
+The driver of the Astribank is composed of several modules: 
+
+xpp::
+  The basic module, that communicates with DAHDI and provides some 
+  common services to other modules.
+xpd_fxs::
+  FXS modules (analog phones). Module type 1.
+xpd_fxo::
+  FXO modules (Analog PSTN lines). Module type 2.
+xpd_bri::
+  BRI ("ISDN") modules. Module type 3.
+xpd_pri::
+  The module for controlling E1/T1 modules. Module type 4.
+xpp_usb::
+  The functionality needed to connect to the USB bus.
+
+All modules depend on xpp, and modprobing them will install xpp as well.
+However the xpd_* modules are installed on-demand: no need to load 
+xpd_fxs if you have only Astribank FXS.
+
+Once an Astribank device connected and the firmware is loaded, the
+Vendor-ID/Product-ID of the device will be  e4e4/11x2 . The handler for that
+combination is listed as the kernel module xpp_usb. Therefore, the system
+runs 'modprobe xpp_usb' if that module is not already loaded.
+
+The module xpp_usb depends on the dahdi and xpp modules. Both of them 
+are loaded before xpp_usb. As usual, parameters and rules form
+/etc/modprobe.conf and/or from /etc/modprobe.d/* will be applied to 
+the module.
+
+When command 'modprobe xpp_usb' returns, the span type specific modules
+(e.g., xpd_fxs, xpd_fxo) may or may not have been loaded yet.
+
+At this point the xpp driver "asks" the box about its software
+(firmware) version) and the type of telephony modules it has. According 
+to the answers it receives, the xpp driver will "modprobe" the required 
+xpd_* modules. 
+
+When an Astribank connects, it tells the driver what ports it has. For
+instance, a system with 8BRI (=type 3) ports and 3 modules of 8FXS
+(=type 1) ports:
+----------------------------------------------
+INFO-xpp: XBUS-00: DESCRIPTOR: 4 cards, protocol revision 30
+INFO-xpp: XBUS-00:     CARD 0 type=3.0 ports=8 (2x4), port-dir=0xCC
+INFO-xpp: XBUS-00:     CARD 1 type=1.0 ports=8 (8x1), port-dir=0xFF
+INFO-xpp: XBUS-00:     CARD 2 type=1.0 ports=8 (8x1), port-dir=0xFF
+INFO-xpp: XBUS-00:     CARD 3 type=1.0 ports=8 (8x1), port-dir=0xFF
+----------------------------------------------
+
+If dahdi, xpp or xpp_usb is missing or defective, you'll get relatively
+clear error messages. However if an xpd_* module fails to load (e.g.:
+because it is missing), the error is less intuitive:
+--------------------------------------------------
+NOTICE-xpp: xproto_get: Failed to load module for type=3. exit status=256.
+NOTICE-xpp: XBUS-00: CARD 0: missing protocol table for type 3. Ignored.
+--------------------------------------------------
+In this case it was because I maliciously removed the module xpd_bri
+(type 3) from the system.
+
+This can also happen if you accidentally blacklist the relevant xpd-*
+module. 'blacklist some_module' in modprobe.conf or modprobe.d/*.conf
+means that a direct insmod or modprobe of their name will work, but any
+attempt to load a module through its aliases will fail. Recall that the
+cpd-* modules are loaded on-demand using the alias 'xpd-type-N' .
+
+
+Device Initializations Scripts
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The chips in the device need to be initialized. This requires sending a
+bunch of values to certain registers in those chips. We decided that
+hardwiring those values in the driver code is not a good idea.
+Before registering a XPD as a span in DAHDI, we run an initialization
+script: /usr/share/dahdi/init_card_N_MM where,
+
+* N  is telephony module type: 1 for an FXS span and 2 for an FXO span, 
+  3 for BRI and 4 for PRI.
+* MM - is a version number. Currently it equals 30.
+
+Those scripts must be executable. If they are not, the initiallization
+will do nothing but will give no error, and the device will work in an
+unexpected way, if at all.
+
+If because of some reasons this fails (the script is not in the place, 
+or the running it produced an error), then you will get an error message 
+in the logs and the XPD will then be removed (you won't see directory
+for that XPD under the corresponding /proc/xpp/XBUS-* directory) and 
+will not be registered with DAHDI.
+
+As the XPD is initialized, you'll see the green LEDs of the ports steadily 
+turn on and later off ("a train of lights"). This is a bit slower than the 
+faster "blinking" when the XPDs register as DAHDI spans. The initialization 
+of an FXS XPD may take a few seconds.
+
+
+Connect / Disconnect Hook
+^^^^^^^^^^^^^^^^^^^^^^^^^
+When the Astribank has finished initialization it also notifies
+userspace applications. This can be used to run a custom command when an
+Astribank is connected (after it has finished initialization) or when it
+has disconnected. The hook script is installed by default to
+/usr/share/dahdi/astribank_hook .
+
+
+Registering in DAHDI
+^^^^^^^^^^^^^^^^^^^^
+The XPDs will not automatically register as DAHDI spans. This is
+intended to allow you to set the registration order (and hence the order
+of DAHDI spans and channels) among multiple Astribank devices,
+or between an Astribank and a different DAHDI device.
+
+When the XPD registers with DAHDI, all the green LEDs will be lit for a
+short while. 
+
+Spans are normally registered with the utility dahdi_registration. Simply
+running 'dahdi_registration' shows the available XPDs and whether or not
+they are registered. To register: 
+
+  dahdi_registration on
+
+For a system with several spans you'll see a "fast train of lights".
+
+If you have multiple Astribank devices, dahdi_registration will
+register them by the ascending order of the USB connector ID. This
+means that as long as the same Astribank is connected to the same
+port, the order of plugging is not important.
+
+You can see the USB connector ID in the verbose output of the 
+dahdi_hardware utility when xpp drivers are loaded. See CONNECTOR value 
+in the example below:
+
+------------------------------------------------------
+# dahdi_hardware -v
+usb:004/006     xpp_usb+     e4e4:1152 Astribank-multi FPGA-firmware
+ LABEL=[usb:0000148]        CONNECTOR=usb-0000:00:03.3-2
+        XBUS-00/XPD-00: E1_TE    Span 1  DAHDI-SYNC
+        XBUS-00/XPD-10: FXS      Span 2
+        XBUS-00/XPD-20: FXS      Span 3
+usb:004/007     xpp_usb+     e4e4:1152 Astribank-multi FPGA-firmware
+ LABEL=[usb:0000150]        CONNECTOR=usb-0000:00:03.3-6
+        XBUS-01/XPD-00: FXS      Span 4
+        XBUS-01/XPD-10: FXO      Span 5
+------------------------------------------------------
+
+If you have multiple Astribank devices, dahdi_registration will register
+them by the order of the "connector" field. This means that as long as
+the same Astribank is connected to the same port, the order of plugging
+is not important. Alternatively you can set an explicit registration
+order using /etc/dahdi/xpp_order . See above in section about
+<<_xpp_order_explicitly_order_astribanks,xpp_order>>.
+
+The registration is performed through the sysfs interface. See below
+<<_sys_devices_xpp_xbus_nn_nn_m_p_span,the span attribute>>. Also note 
+that dahdi_registration also allows you to unregister spans, which will 
+work for all spans that are not in use (That is: none of their channels 
+is in use).
+
+By default, the Astribank drivers don't perform automatic span
+registration on DAHDI. It is in contrast to the all known drivers of
+PCI boards. Because of that, DAHDI channels  related to the PCI board
+spans will get lower numbers than the channels related to Astribank
+devices.
+
+You may choose to register the XPDs with DAHDI automatically. This may
+make the startup sequence a bit simpler, but is generally not
+recommended on a system with more than one Astribank or an Astribank and
+a different DAHDI device. This behavior may be defined by setting
+parameter <<_dahdi_autoreg>> in the modprobe configuration file (A file under
+/etc/modprobe.d or /etc/modprobe.conf):
+
+  options xpp dahdi_autoreg=1
+
+
+Astribanks Synchronization Source
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+If there is more than one Astribank on the system, all the Astribanks
+keep their clock in sync. Optionally the Astribanks can synchronize
+their clock to the master DAHDI device (in case it is a different DAHDI
+device). Normally you just use the default init.d script or run
+explicitly:
+
+  xpp_sync auto
+
+(For now see the man page of xpp_sync for more information)
+
+
+DAHDI And Above
+^^^^^^^^^^^^^^^
+From here you get a standard DAHDI span. The next step is to configure
+the span by running the dahdi_cfg utility. You would also need to 
+configure the channels in the Asterisk chan_dahdi.conf file. Only after 
+that you will be able to make calls through the telephony ports.
+
+You can use dahdi_genconf, which is included with dahdi-tools, to
+generate a DAHDI and Asterisk configuration for your system.
+For analog channels it works quite well, and likewise for BRI. For E1/T1 
+it will probably take some tuning.
+
+Please refer to the general DAHDI documentation for more deatils about
+DAHDI and Asterisk configuration. E.g, the README file in the
+top-level directory, and 
+
+  http://voip-info.org/wiki/view/Asterisk+config+chan_dahdi.conf[]
+
+Alternatively, write you own configuration, based on the sample from the
+"Sample Configurations" section.
+
+
+/proc Interface
+~~~~~~~~~~~~~~~
+The Astribank drivers provide their own /proc interface under /proc/xpp.
+Here we review the more useful details of the procfs interface. There
+are many other debugging details that are exposed through the procfs
+interface. 
+
+Also note that those details are subject to changes. Generally the
+recommended stable interface are the DAHDI-perl modules and utilities 
+from the xpp/ directory.
+
+
+/proc/xpp/xbuses
+^^^^^^^^^^^^^^^^
+File /proc/xpp/xbuses lists the connected Astribank devices (one line 
+per device).
+
+A device is normally has status "connected". The status "missing" means that
+the device has been disconnected, but Asterisk still holds channels from it
+open.
+
+
+For each Astribank device there is folder /proc/xpp/XBUS-nn and for each device
+module (span in the terms of DAHDI) there is folder /proc/XBUS-nn/XPD-mm.
+
+/proc/xpp/XBUS-nn/XPD-mm/summary 
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Contains detailed information about port statuses of the device module 
+(off-hook, on-hook etc.) For example, you can run the following command
+in order to monitor the port statuses in the real time:
+
+  watch -n1 cat /proc/xpp/XBUS-00/XPD-00/summary
+
+
+/proc/xpp/XBUS-nn/XPD-mm/fxo_info
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Only for FXO modules. Apart from showing the status of the LEDs, it also
+shows for each FXO port if it is connected to a provider: look for the
+value of "battery" for that specific port, and a bunch of other
+characteristics of the port.
+
+
+/proc/xpp/XBUS-nn/XPD-mm/bri_info
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+In addition to the usual information about the LEDs, this file also
+provides useful information regarding ISDN Layer 1 and Layer 2 status.
+For example, you can run the following command in order to monitor
+the Layer 1 port statuses for all BRI devices in the real time:
+
+  watch -n1 -d 'grep "Layer 1:" /proc/xpp/XBUS-*/XPD-*/bri_info'
+
+For the status of the D channel of the ports on all BRI spans, run:
+
+  watch -n1 -d 'grep D-Channel: /proc/xpp/XBUS-*/XPD-*/bri_info'
+
+
+/proc/xpp/XBUS-nn/XPD-mm/pri_info
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+In addition to the usual information about the LEDs, this file also
+provides useful information regarding ISDN Layer 1 and Layer 2 status.
+For example, you can run the following command in order to monitor
+the Layer 1 port statuses for all E1/T1 devices in the real time:
+
+  watch -n1 -d 'grep "Layer 1:" /proc/xpp/XBUS-*/XPD-*/pri_info'
+
+For the status of the D channel of the ports on all PRI spans, run:
+
+  watch -n1 -d 'grep D-Channel: /proc/xpp/XBUS-*/XPD-*/pri_info'
+
+Note: the layer 2 status is much more of a guesswork based on changes in
+the contents of the channel that is supposed to be the D channel.
+
+
+There are a bunch of other status files under /proc/xpp/.
+
+
+/sys Interface
+~~~~~~~~~~~~~~
+Astribanks on the system and the xpds themselves are also represented
+in SysFS. SysFS is a virtual file system mounted under /sys and provides 
+information in a more structured way than ProcFS. In sysfs objects are 
+represented as directories, simple attributes are shown as files in 
+the directory of the object and more complex objects are subdirectories 
+or symbolic links to other directories.
+
+As with the procfs interface, we only document some interesting
+attribuets. Some attributes are writable and hence writing to them
+without knowing what you do is not exactly wise.
+
+Like the procfs interface, this interface is subject to changes and
+should not be considered a stable interface. Please use the DAHDI-perl
+modules and utilities.
+
+
+Astribanks in SysFS
+^^^^^^^^^^^^^^^^^^^
+Each astribank is represented as a device under
+/sys/bus/astribanks/devices , with the name xbus-NN, where NN is its 
+two-digit number (e.g.: 00, 01).
+
+===== /sys/bus/astribanks/devices/xbus-NN/cls
+CLear Statistics: writing to this file clear the procfs statistics for
+this Astribank.
+
+===== /sys/bus/astribanks/devices/xbus-NN/connector
+Connector string for the device. The place to which the Astribank is
+connected. e.g: usb-0000:00:03.3-2
+
+===== /sys/bus/astribanks/devices/xbus-NN/label
+The label string of the Astribank unit. E.g: usb:00000135
+
+===== /sys/bus/astribanks/devices/xbus-NN/status
+'connected' (normal operation) or 'disconnected' (has been disconnected,
+some channels are still open).
+
+===== /sys/bus/astribanks/devices/xbus-NN/timing
+Provides some statistics in case the Astribank is not the sync source.
+The format of this file is subject to future changes.
+
+===== /sys/bus/astribanks/devices/xbus-NN/waitfor_xpds
+Reading from this file only returns when the Astribank has finished
+initialization of the XPDs or in case of a timeout. It prints the number
+of XPDs to initialize, and the number initialize. Unless something went
+wrong, those two numbers are the same. Once the span was initialized,
+reading from this file returns immediately:
+
+  XPDS_READY: XBUS-00: 3/3
+
+===== /sys/bus/astribanks/devices/xbus-NN/xbus_state
+Reading from it prints the name and number of the state of the
+Astribank. This file is also writable: you can write either 'stop' to
+disconnect the specific Astribank, or 'start' to reconnect it.
+
+===== /sys/bus/astribanks/drivers/xppdrv/sync
+(An attribute of the generic Astribanks driver)
+
+The synchronization source. Normally the number of the astribank that is
+the synchronization master, or 'SYNC=DAHDI' if Astribanks are
+synchronized from a different DAHDI device. Normally you should just use
+xpp_sync, though.
+
+Current possible writable values:
+
+<number>::
+  Make the Astribank XBUS-<number> the sync source for other Astribanks.
+
+DAHDI::
+  Make the Astribanks synchronize with the DAHDI timing master span.
+  You probably need this to get faxes from a non-Astribank adapter to an
+  Astribank.
+
+
+XPDs in SysFS
+^^^^^^^^^^^^^
+Under the Astribank you'll find a subdirectory for each of its XPDs
+("spans"). The name of the directory is composed of three numbers:
+
+<astribank>:<module>:<subunit>
+
+astribank::
+  Two-digit name of the Astribank in which this XPD is in. If it is
+  xbus-03, you will see there '03'.
+
+module::
+  The number of the Astribank module: from 0 (left-most) to 3
+  (right-most).
+
+subunit::
+  In a module that has several spans: the number of the span. In
+  practice this is only for BRI and PRI and hence the module number will
+  always be 0 in this case. 
+
+The two-digit number of the XPD in the procfs interface is in fact
+<module><subunit>.
+
+Under this you see several attributes.
+
+===== /sys/bus/astribanks/devices/xbus-NN/NN:M:P/blink
+You can write here a number which will be considered to be a bitmask
+of the ports that should blink (0 - no blinking). Reading from here
+shows that bitmask. If you think that this is complicated, just use
+xpp_blink.
+
+===== /sys/bus/astribanks/devices/xbus-NN/NN:M:P/chipregs
+Provides direct read/write interface to the registers of each chip. 
+Reading from the file shows the result of the last read request. To make
+either a read request or a write request you need to write to that file.
+
+It is mainly used by the initialization scripts (init_card_*).
+
+Incorrect usage of this file is one possible way of damaging the
+Astribank.
+
+===== /sys/bus/astribanks/devices/xbus-NN/NN:M:P/fxo_battery
+(Only on FXO) - shows ports that have (+) or don't have (-) battery
+current. That is: which ones are connected to an active FXS on the
+other side.
+
+current. That is: which ones are connected to an active FXS on the
+other side.
+
+===== /sys/bus/astribanks/devices/xbus-NN/NN:M:P/offhook
+Shows ports that are (1) or are not (0) off-hook. When a channel is
+not off-hook. For BRI and E1/T1 the value is 1 if the span is in use.
+This value can also be used to get the number of lines (channels) in
+this XPD: the count of items in this list.
+
+===== /sys/bus/astribanks/devices/xbus-NN/NN:M:P/span
+is a read/write file. Reading from it gives 0 if the span is
+unregistered, or the span number if it is registered.
+
+Writing to it allows manual registration / unregistration from DAHDI:
+writing 1 registers a span (if it wasn't already registered) and writing
+0 attempts to unregister it (if it is registered.  Span unregistration 
+will fail if some channels from the span are used  (e.g: by Asterisk).
+
+A more convenient interface to this is the command dahdi_registration that
+registers or unregisters all the spans at once with a predefined order,
+and this is what you should normally use.
+
+Alternatively you can use the parameter dahdi_autoreg to register spans
+automatically. But this is only recommended on a system with a single
+Astribank and no other DAHDI device.
+
+===== /sys/bus/astribanks/devices/xbus-NN/NN:M:P/driver
+This is a standard sysfs feature: from the directory of the device you
+have a link called "driver" to the directory of the driver that
+handles it. One specific interesting thing is that this allows you to
+easily see all the XPDs of the same type, as they are linked again
+from the driver's directory.
+
+
+===== /sys/bus/astribanks/devices/xbus-NN/NN:M:P/pri_protocol
+Can have either of those two:
+
+E1::
+  Provides 31 channels, of which channel 16 is normally the D-channel. 
+  Common in places outside of North America and Japan. This is the 
+  default setup.
+
+T1::
+  T1 provides 24 channels. The last one is normally the D-Channel.
+  Common in North America.
+
+This can also be set by writing the strings explicitly to the file. But
+can only be done when an XPD is not a registered span.
+
+This writing is normally done by the device initialization script, based
+on the 'pri_protocol' settings in 
+xref:_xpp_conf_astribank_initialization[/etc/dahdi/xpp.conf] .
+
+
+Useful Module Parameters
+~~~~~~~~~~~~~~~~~~~~~~~~
+Compilation-time defaults for the all modules can be shown as part of the
+description line for the parameter in the "modinfo" command output.
+
+==== dahdi_autoreg
+(xpp)
+
+Register spans automatically (1) or not (0). Default: 0. 
+Setting it simplifies operations with a single Astribank and no other 
+DAHDI hardware. However if you have such systems, automatic
+registration can cause the order of spans to be unpredictable.
+The standard startup scripts use 'dahdi_registration on' instead of this.
+
+==== initdir
+(xpp)
+
+This is the directory containing the initialization scripts.
+The default is /usr/share/dahdi .
+Setting this value could be useful if that location is inconvenient for you.
+
+==== rx_tasklet
+(xpp)
+
+Enable (1) or disable (0) doing most of the packets processing in
+separate tasklets. This should probably help on higher-end systems with
+multiple Astribanks.
+
+==== debug
+(all modules)
+
+It will make the driver to print tons of debugging messages. You can 
+set/unset the parameter at run-time. The parameter value is a bitmask 
+of several values. The different bits  meaning as it defined in 
+xpp/dahdi_debug.h: 
+
+* 0  - Disable debug messages
+* 1  - GENERAL - General debug comments.
+* 2  - PCM - PCM-related messages. Tends to flood logs.
+* 4  - LEDS - Anything related to the LEDs status control. The driver
+       produces a lot of messages when the option is enabled.
+* 8  - SYNC - Synchronization related messages.
+* 16 - SIGNAL - DAHDI signalling related messages.
+* 32 - PROC - Messages related to the procfs interface.
+* 64 - REGS - Reading and writing to chip registers. Tends to flood
+	 logs.
+* 128 - DEVICES - Device instantiation, destruction and such.
+* 256 - COMMANDS - Protocol commands. Tends to flood logs.
+
+For example,
+
+  echo 33 >/sys/modules/xpp/parameters/debug 
+
+forces module xpp to print general debugging messages (1) and procfs
+debugging messages (32).
+
+==== vmwi_ioctl
+(xpd_fxs)
+
+Does userspace support VMWI notification via ioctl? Default: 1 (yes).
+
+Disable this (0) to have the driver attempt to detect the voicemail
+message waiting indication status for this port from FSK messages
+userspace (Asterisk) sends. Set the ports to use AC neon-lamp style
+message waiting indication. The detection from the FSK messages takes
+extra CPU cycles but is required with e.g. Asterisk 1.4.x .
+
+Also note that in order for this parameter to take effect, it must be
+set before the span is registered. This practically means that it
+should be set through modprobe.d files.
+
+See also <<_voicemail_indication,Voicemail Indication>>.
+
+==== usb1
+(xpp_usb)
+
+Enable (1) or disable (0) support of USB1 devices. Disabled by default.
+
+USB1 devices are not well-tested. It seems that they don't work at all
+for Astribank BRI. Generally they should work with the current code, but
+we expect the voice quality issues. Hence we would like to make it
+very clear that you if you have a USB1 port (rather than a USB2 one, as 
+recommended) you will have to take an action to enable the device.
+
+==== poll intervals 
+(various)
+
+There are various values which the driver occasionally polls the
+device for. For instance, the parameter poll_battery_interval for
+xpd_fxo to poll the battery, in order to know if the telco line is
+actually connected.
+
+The value of those parameters is typically a number in milliseconds. 
+0 is used to disable polling. Under normal operation there should be 
+no reason to play with those parameters.
+
+==== dtmf_detection
+(xpd_fxs)
+
+Enable (1) or disable (0) support of hardware DTMF detection by the 
+Astribank.
+
+==== caller_id_style
+(xpd_fxo)
+
+Various types of caller ID signalling styles require knowing the PCM
+even when the line is on-hook (which is usually a waste of CPU and
+bandwidth). This parameter allows fine-tuning the behaviour here:
+
+* 0 (default) - Don't pass extra PCM when on-hook.
+* 1 ETSI-FSK: Wait for polarity reversal to come before a ring and 
+  then start passing PCM until the caller ID has been passed.
+* 2 Always: Always pass PCM.
+
+This parameter is read-only. It cannot be changed at run-time.
+
+==== battery_threshold
+(xpd_fxo)
+
+Minimum voltage that shows there is battery. Defaults to 3. Normally you
+should not need to change this, unless dealing with a funky PSTN
+provider.
+
+==== battery_debounce
+(xpd_fxo)
+
+Minimum interval (msec) for detection of battery off (as opposed to e.g.
+a temporary power denial to signal a hangup). Defaults to 1000. As with
+battery_threshold above, there's normally no need to tweak it.
+
+
+NOTE: XPP here does not stand for X Printing Panel, XML Pull Parser, 
+X-Windows Phase Plane or XML Professional Publisher. It is simply the 
+Xorcom Peripheral Protocol, which connects a computer to a XPD (Xorcom 
+Peripheral Device). An XBUS (originally XPP Bus) is actually a single
+Astribank device and the XPDs have become the single modules in it.
diff --git a/xpp/astribank_allow.8 b/xpp/astribank_allow.8
new file mode 100644
index 0000000..0fd48cc
--- /dev/null
+++ b/xpp/astribank_allow.8
@@ -0,0 +1,70 @@
+.TH "ASTRIBANK_ALLOW" "8" "29 March 2009" "" ""
+
+.SH NAME
+astribank_allow \- License Xorcom Astribank (xpp) capabilities.
+.SH SYNOPSIS
+.B astribank_allow \-D \fIdevice-path\fR [ options ]
+
+.B astribank_allow [\-h]
+
+.SH DESCRIPTION
+Modern Astribanks (with USB product id's 116x) contain capabilities
+that may be licensed.
+
+.B astribank_allow
+is used to upload/download the licensing information to/from the device.
+
+Uploading a valid license file to an Astribank, changes its capabilities.
+The change becomes effective after a firmware reset (either by powering
+the device off and on again, or via the \fBastribank_tool\fR full reset option).
+
+Downloading license from the device, produces a valid license file for its
+current capabilities. This may be backed up, so the device may be later
+restored to its previous capabilities.
+
+The license file contains both a human readable description of the
+device capabilities for the end user and a hash of the licensing
+information used by Xorcom to generate/modify licensed capabilities.
+
+.SH OPTIONS
+.B \-D
+.I device-path
+.RS
+Required. The device to read from/write to. On modern UDEV-based system
+this is usually /dev/bus/usb/\fIbus_num\fR/\fIdevice_num\fR,
+where \fIbus_num\fR and \fIdevice_num\fR are the first two numbers in the
+output of lsusb(8).
+On older systems that use usbfs, it is usually
+/proc/bus/usb/\fIbus_num\fR/\fIdevice_num\fR.
+.RE
+
+.B \-w
+.RS
+Write capabilities to EEPROM, otherwise read capabilities
+.RE
+
+.B \-f \fIfilename\fR
+.RS
+License filename (stdin/stdout if not specified)
+.RE
+
+.B \-v
+.RS
+Increase verbosity. May be used multiple times.
+.RE
+
+.B \-d \fImask\fR
+.RS
+Set debug mask to \fImask\fR. Default is 0, 0xFF is "everything".
+.RE
+
+.B \-h
+.RS
+Displays usage message.
+.RE
+
+.SH SEE ALSO
+fxload(8), lsusb(8), astribank_hexload(8), astribank_tool(8)
+
+.SH AUTHOR
+Alex Landau
diff --git a/xpp/astribank_allow.c b/xpp/astribank_allow.c
new file mode 100644
index 0000000..b87f6fa
--- /dev/null
+++ b/xpp/astribank_allow.c
@@ -0,0 +1,384 @@
+/*
+ * Written by Oron Peled <oron at actcom.co.il> and
+ *            Alex Landau <alex.landau at xorcom.com>
+ * Copyright (C) 2008, Xorcom
+ *
+ * All rights reserved.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <getopt.h>
+#include <time.h>
+#include <sys/types.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+#include "mpp.h"
+#include "mpp_funcs.h"
+#include "debug.h"
+
+static const char rcsid[] = "$Id$";
+
+#define	DBG_MASK	0x80
+
+static char	*progname;
+
+static void usage()
+{
+	fprintf(stderr, "Usage: %s [options...] -D {/proc/bus/usb|/dev/bus/usb}/<bus>/<dev> options\n", progname);
+	fprintf(stderr, "\tOptions:\n");
+	fprintf(stderr, "\t\t[-v]               # Increase verbosity\n");
+	fprintf(stderr, "\t\t[-d mask]          # Debug mask (0xFF for everything)\n");
+	fprintf(stderr, "\t\t[-w]               # Write capabilities to EEPROM, otherwise read capabilities\n");
+	fprintf(stderr, "\t\t[-f filename]      # License filename (stdin/stdout if not specified)\n\n");
+	exit(1);
+}
+
+static int capabilities_burn(
+		struct astribank_device *astribank,
+		struct eeprom_table *eeprom_table,
+		struct capabilities *capabilities,
+		struct capkey *key)
+{
+	int	ret;
+
+	INFO("Burning capabilities\n");
+	ret = mpp_caps_set(astribank, eeprom_table, capabilities, key);
+	if(ret < 0) {
+		ERR("Capabilities burning failed: %d\n", ret);
+		return ret;
+	}
+	INFO("Done\n");
+	return 0;
+}
+
+static int bin_to_file(void *buf, int len, FILE *f)
+{
+	static int bytes_on_line;
+	unsigned char *p = buf;
+	if (buf == NULL) {
+		if (bytes_on_line != 0) {
+			if (fprintf(f, "\n") != 1)
+				return -1;
+			bytes_on_line = 0;
+		}
+		return 0;
+	}
+	int i;
+	for (i = 0; i < len; i++) {
+		if (fprintf(f, "%02x", *p++) != 2)
+			return -1;
+		bytes_on_line++;
+		if (bytes_on_line >= 16) {
+			if (fprintf(f, "\n") != 1)
+				return -1;
+			bytes_on_line = 0;
+		}
+	}
+	return 0;
+}
+
+static int write_to_file(struct eeprom_table *eeprom_table, struct capabilities *caps, struct capkey *key, FILE *f)
+{
+	fprintf(f, "-----BEGIN XORCOM LICENSE BLOCK-----\n");
+	fprintf(f, "Version: 1.0\n");
+	fprintf(f, "Timestamp: %u\n", caps->timestamp);
+	fprintf(f, "Serial: %.*s\n", LABEL_SIZE, eeprom_table->label);
+	fprintf(f, "Capabilities.Port.FXS: %d\n", caps->ports_fxs);
+	fprintf(f, "Capabilities.Port.FXO: %d\n", caps->ports_fxo);
+	fprintf(f, "Capabilities.Port.BRI: %d\n", caps->ports_bri);
+	fprintf(f, "Capabilities.Port.PRI: %d\n", caps->ports_pri);
+	fprintf(f, "Capabilities.Twinstar: %d\n", CAP_EXTRA_TWINSTAR(caps));
+	fprintf(f, "Data:\n");
+	bin_to_file(eeprom_table, sizeof(*eeprom_table), f);
+	bin_to_file(caps, sizeof(*caps), f);
+	bin_to_file(key, sizeof(*key), f);
+	bin_to_file(NULL, 0, f);
+	fprintf(f, "-----END XORCOM LICENSE BLOCK-----\n");
+	return 0;
+}
+
+/*
+ * Removes whitespace on both sizes of the string.
+ * Returns a pointer to the first non-space char. The string
+ * is modified in place to trim trailing whitespace.
+ * If the whole string is whitespace, returns NULL.
+ */
+char *trim(char *s)
+{
+	int len = strlen(s);
+	while (len > 0 && isspace(s[len-1])) {
+		len--;
+	}
+	if (len == 0)
+		return NULL;
+	s[len] = '\0';
+	while (isspace(*s))
+		s++;
+	/* *s is not a space, since in this case we'd return NULL above */
+	return s;
+}
+
+int get_key_value(char *line, char **key, char **value)
+{
+	char *p = strchr(line, ':');
+	if (p == NULL)
+		return -1;
+	*p = '\0';
+	*key = trim(line);
+	*value = trim(p + 1);
+	return 0;
+}
+
+static int hex_digit_to_int(char c)
+{
+	if (c >= '0' && c <= '9')
+		return c - '0';
+	else if (c >= 'a' && c <= 'f')
+		return c - 'a' + 10;
+	else
+		return -1;
+}
+
+static int str_to_bin(char *line, void *buf, int maxlen)
+{
+	static int offset;
+	unsigned char *p = buf;
+	if (strlen(line) % 2 != 0)
+		return -1;
+	while (offset < maxlen && *line) {
+		uint8_t value;
+		char c = hex_digit_to_int(*line++);
+		if (c < 0 || *line == '\0')
+			return -1;
+		value = c << 4;
+		c = hex_digit_to_int(*line++);
+		if (c < 0)
+			return -1;
+		value |= c;
+		p[offset++] = value;
+	}
+	if (offset == maxlen && *line)
+		return -1;
+	return offset;
+}
+
+static int read_from_file(struct eeprom_table *eeprom_table, struct capabilities *caps, struct capkey *capkey, FILE *f)
+{
+	char buf[256];
+	char *line, *key, *value;
+	int state = 0;
+	int lineno = 0;
+	struct table {
+		struct eeprom_table eeprom_table;
+		struct capabilities capabilities;
+		struct capkey capkey;
+	} PACKED table;
+
+	memset(&table, 0, sizeof(struct table));
+	/*
+	 * states:
+	 * 0: start - before BEGIN_LICENSE_BLOCK line. on BEGIN_LICENSE_BLOCK line goto 1.
+	 * 1: read Version, goto 2. if not version line then error.
+	 * 2: after BEGIN line. split line into key:value. if line is Data:, goto 3.
+	 * 3: read binary data. if line is END_LICENSE_BLOCK goto 4.
+	 * 4: END_LICENSE_BLOCK - ignore lines.
+	 */
+	while (fgets(buf, 256, f) != NULL) {
+		lineno++;
+		int len = strlen(buf);
+		if (len > 0 && buf[len-1] != '\n') {
+			ERR("Line %d: Line too long\n", lineno);
+			return -1;
+		}
+		line = trim(buf);
+		if (line == NULL) {
+ 			if (state > 0 && state < 4) {
+				ERR("Line %d: Empty line\n", lineno);
+				return -1;
+			}
+			else
+				continue;
+		}
+		switch (state) {
+			case 0:
+				if (strcmp(line, "-----BEGIN XORCOM LICENSE BLOCK-----") == 0)
+					state = 1;
+				else {
+					ERR("Line %d: Invalid license begin block\n", lineno);
+					return -1;
+				}
+				break;
+			case 1:
+				if (get_key_value(line, &key, &value) < 0) {
+					ERR("Line %d: Can't parse line\n", lineno);
+					return -1;
+				}
+				if (strcmp(key, "Version") == 0) {
+					if (strcmp(value, "1.0") == 0) {
+						state = 2;
+					} else {
+						ERR("Line %d: Unknown license file version '%s', need version '1.0'\n", lineno, value);
+						return -1;
+					}
+				} else {
+					ERR("Line %d: No license file version\n", lineno);
+					return -1;
+				}
+				break;
+			case 2:
+				if (get_key_value(line, &key, &value) < 0) {
+					ERR("Line %d: Can't parse line\n", lineno);
+					return -1;
+				}
+				if (strcmp(key, "Data") == 0) {
+					state = 3;
+					break;
+				}
+				break;
+			case 3:
+				if (strcmp(line, "-----END XORCOM LICENSE BLOCK-----") == 0) {
+					state = 4;
+					break;
+				}
+				if (str_to_bin(line, &table, sizeof(table)) < 0) {
+					ERR("Line %d: Error in data block\n", lineno);
+					return -1;
+				}
+				break;
+			case 4:
+				break;
+
+		}
+	}
+	if (state != 4) {
+		ERR("Invalid license file\n");
+		return -1;
+	}
+	memcpy(eeprom_table, &table.eeprom_table, sizeof(*eeprom_table));
+	memcpy(caps, &table.capabilities, sizeof(*caps));
+	memcpy(capkey, &table.capkey, sizeof(*capkey));
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	char			*devpath = NULL;
+	struct astribank_device *astribank;
+	struct eeprom_table	eeprom_table;
+	struct capabilities	caps;
+	struct capkey		key;
+	const char		options[] = "vd:D:wf:";
+	int			do_write = 0;
+	FILE			*file;
+	char			*filename = NULL;
+	int			ret;
+
+	progname = argv[0];
+	while (1) {
+		int	c;
+
+		c = getopt (argc, argv, options);
+		if (c == -1)
+			break;
+
+		switch (c) {
+			case 'D':
+				devpath = optarg;
+				break;
+			case 'v':
+				verbose++;
+				break;
+			case 'd':
+				debug_mask = strtoul(optarg, NULL, 0);
+				break;
+			case 'w':
+				do_write = 1;
+				break;
+			case 'f':
+				filename = optarg;
+				break;
+			case 'h':
+			default:
+				ERR("Unknown option '%c'\n", c);
+				usage();
+		}
+	}
+	if(!devpath) {
+		ERR("Missing device path\n");
+		usage();
+	}
+	DBG("Startup %s\n", devpath);
+	if((astribank = mpp_init(devpath)) == NULL) {
+		ERR("Failed initializing MPP\n");
+		return 1;
+	}
+	if(astribank->eeprom_type != EEPROM_TYPE_LARGE) {
+		ERR("Cannot use this program with astribank EEPROM type %d (need %d)\n",
+			astribank->eeprom_type, EEPROM_TYPE_LARGE);
+		return 1;
+	}
+	ret = mpp_caps_get(astribank, &eeprom_table, &caps, &key);
+	if(ret < 0) {
+		ERR("Failed to get original capabilities: %d\n", ret);
+		return 1;
+	}
+	if (do_write) {
+		/* update capabilities based on input file */
+		file = stdin;
+		if (filename) {
+			file = fopen(filename, "r");
+			if (file == NULL) {
+				ERR("Can't open file '%s'\n", filename);
+				return 1;
+			}
+		}
+		ret = read_from_file(&eeprom_table, &caps, &key, file);
+		if (ret < 0) {
+			ERR("Failed to read capabilities from file: %d\n", ret);
+			return 1;
+		}
+		show_capabilities(&caps, stderr);
+		if (capabilities_burn(astribank, &eeprom_table, &caps, &key) < 0)
+			return 1;
+		if (file != stdin)
+			fclose(file);
+	} else {
+		/* print capabilities to stdout */
+		file = stdout;
+		if (filename) {
+			file = fopen(filename, "w");
+			if (file == NULL) {
+				ERR("Can't create file '%s'\n", filename);
+				return 1;
+			}
+		}
+		ret = write_to_file(&eeprom_table, &caps, &key, file);
+		if (ret < 0) {
+			ERR("Failed to write capabilities to file: %d\n", ret);
+			return 1;
+		}
+		if (file != stdout)
+			fclose(file);
+	}
+	mpp_exit(astribank);
+	return 0;
+}
diff --git a/xpp/astribank_hexload.8 b/xpp/astribank_hexload.8
new file mode 100644
index 0000000..6808927
--- /dev/null
+++ b/xpp/astribank_hexload.8
@@ -0,0 +1,66 @@
+.TH "ASTRIBANK_HEXLOAD" "8" "29 March 2009" "" ""
+
+.SH NAME
+astribank_tool \- Xorcom Astribank (xpp) firmware loader
+.SH SYNOPSIS
+.B astribank_tool \-D \fIdevice-path\fR <\fB\-F|\-p\fR> [\fIoptions\fR] \fIhexfile\fR
+
+.B astribank_tool [\-h]
+
+.SH DESCRIPTION
+.B astribank_hexload
+is a second-stage firmware loader for Xorcom Astribanks. Note that some 
+older models use fpga_load(8) instead.
+
+It is used to load a file in the Intel HEX format into a Xorcom
+Astribank. It can be used to load either an FPGA firmware or a PIC
+firmware. It is normally run by the script xpp_fxloader.
+
+.SH OPTIONS
+.B \-D 
+.I device-path
+.RS
+Required. The device to read from/write to. On modern UDEV-based system
+this is usually /dev/bus/usb/\fIbus_num\fR/\fIdevice_num\fR,
+where \fIbus_num\fR and \fIdevice_num\fR are the first two numbers in the
+output of lsusb(8).
+On older systems that use usbfs, it is usually
+/proc/bus/usb/\fIbus_num\fR/\fIdevice_num\fR.
+.RE
+
+.B \-F
+.RS
+The firmware to load is a FPGA firmware.
+.RE
+
+.B \-p
+.RS
+The firmware to load is a PIC firmware.
+.RE
+
+.B \-v
+.RS
+Increase verbosity. May be used multiple times.
+.RE
+
+.B \-d \fImask\fR
+.RS
+Set debug mask to \fImask\fR. Default is 0, 0xFF is "everything".
+.RE
+
+.B \-h
+.RS
+Displays usage message.
+.RE
+
+.SH SEE ALSO
+fxload(8), lsusb(8), astribank_tool(8), fpga_load(8)
+
+.SH AUTHOR
+This manual page was written by Tzafrir Cohen <tzafrir.cohen at xorcom.com> .
+Permission is granted to copy, distribute and/or modify this document under
+the terms of the GNU General Public License, Version 2 any 
+later version published by the Free Software Foundation.
+
+On Debian systems, the complete text of the GNU General Public
+License can be found in /usr/share/common\-licenses/GPL.
diff --git a/xpp/astribank_hexload.c b/xpp/astribank_hexload.c
new file mode 100644
index 0000000..b268e5d
--- /dev/null
+++ b/xpp/astribank_hexload.c
@@ -0,0 +1,229 @@
+/*
+ * Written by Oron Peled <oron at actcom.co.il>
+ * Copyright (C) 2008, Xorcom
+ *
+ * All rights reserved.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <arpa/inet.h>
+#include "debug.h"
+#include "hexfile.h"
+#include "mpp_funcs.h"
+#include "pic_loader.h"
+#include "astribank_usb.h"
+
+#define	DBG_MASK	0x80
+#define	MAX_HEX_LINES	10000
+
+static char	*progname;
+
+static void usage()
+{
+	fprintf(stderr, "Usage: %s [options...] -D {/proc/bus/usb|/dev/bus/usb}/<bus>/<dev> hexfile...\n", progname);
+	fprintf(stderr, "\tOptions: {-F|-p}\n");
+	fprintf(stderr, "\t\t[-E]               # Burn to EEPROM\n");
+	fprintf(stderr, "\t\t[-F]               # Load FPGA firmware\n");
+	fprintf(stderr, "\t\t[-p]               # Load PIC firmware\n");
+	fprintf(stderr, "\t\t[-v]               # Increase verbosity\n");
+	fprintf(stderr, "\t\t[-d mask]          # Debug mask (0xFF for everything)\n");
+	exit(1);
+}
+
+int handle_hexline(struct astribank_device *astribank, struct hexline *hexline)
+{
+	uint16_t	len;
+	uint16_t	offset_dummy;
+	uint8_t		*data;
+	int		ret;
+
+	assert(hexline);
+	assert(astribank);
+	if(hexline->d.content.header.tt != TT_DATA) {
+		DBG("Non data record type = %d\n", hexline->d.content.header.tt);
+		return 0;
+	}
+	len = hexline->d.content.header.ll;
+	offset_dummy = hexline->d.content.header.offset;
+	data = hexline->d.content.tt_data.data;
+	if((ret = mpp_send_seg(astribank, data, offset_dummy, len)) < 0) {
+		ERR("Failed hexfile send line: %d\n", ret);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int load_hexfile(struct astribank_device *astribank, const char *hexfile, enum dev_dest dest)
+{
+	struct hexdata		*hexdata = NULL;
+	int			finished = 0;
+	int			ret;
+	int			i;
+	char			star[] = "+\\+|+/+-";
+
+	if((hexdata  = parse_hexfile(hexfile, MAX_HEX_LINES)) == NULL) {
+		perror(hexfile);
+		return -errno;
+	}
+	INFO("Loading hexfile to %s: %s (version %s)\n",
+		dev_dest2str(dest),
+		hexdata->fname, hexdata->version_info);
+#if 0
+	FILE		*fp;
+	if((fp = fopen("fpga_dump_new.txt", "w")) == NULL) {
+		perror("dump");
+		exit(1);
+	}
+#endif
+	if((ret = mpp_send_start(astribank, dest, hexdata->version_info)) < 0) {
+		ERR("Failed hexfile send start: %d\n", ret);
+		return ret;
+	}
+	for(i = 0; i < hexdata->maxlines; i++) {
+		struct hexline	*hexline = hexdata->lines[i];
+
+		if(!hexline)
+			break;
+		if(verbose > LOG_INFO) {
+			printf("Sending: %4d%%    %c\r", (100 * i) / hexdata->last_line, star[i % sizeof(star)]);
+			fflush(stdout);
+		}
+		if(finished) {
+			ERR("Extra data after End Of Data Record (line %d)\n", i);
+			return 0;
+		}
+		if(hexline->d.content.header.tt == TT_EOF) {
+			DBG("End of data\n");
+			finished = 1;
+			continue;
+		}
+		if((ret = handle_hexline(astribank, hexline)) < 0) {
+			ERR("Failed hexfile sending in lineno %d (ret=%d)\n", i, ret);;
+			return ret;
+		}
+	}
+	if(verbose > LOG_INFO) {
+		putchar('\n');
+		fflush(stdout);
+	}
+	if((ret = mpp_send_end(astribank)) < 0) {
+		ERR("Failed hexfile send end: %d\n", ret);
+		return ret;
+	}
+#if 0
+	fclose(fp);
+#endif
+	free_hexdata(hexdata);
+	DBG("hexfile loaded successfully\n");
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	char			*devpath = NULL;
+	struct astribank_device *astribank;
+	int			opt_pic = 0;
+	int			opt_dest = 0;
+	enum dev_dest		dest = DEST_NONE;
+	const char		options[] = "vd:D:EFp";
+	int			iface_num;
+	int			ret;
+
+	progname = argv[0];
+	while (1) {
+		int	c;
+
+		c = getopt (argc, argv, options);
+		if (c == -1)
+			break;
+
+		switch (c) {
+			case 'D':
+				devpath = optarg;
+				break;
+			case 'E':
+				if(dest != DEST_NONE) {
+					ERR("The -F and -E options are mutually exclusive.\n");
+					usage();
+				}
+				opt_dest = 1;
+				dest = DEST_EEPROM;
+				break;
+			case 'F':
+				if(dest != DEST_NONE) {
+					ERR("The -F and -E options are mutually exclusive.\n");
+					usage();
+				}
+				opt_dest = 1;
+				dest = DEST_FPGA;
+				break;
+			case 'p':
+				opt_pic = 1;
+				break;
+			case 'v':
+				verbose++;
+				break;
+			case 'd':
+				debug_mask = strtoul(optarg, NULL, 0);
+				break;
+			case 'h':
+			default:
+				ERR("Unknown option '%c'\n", c);
+				usage();
+		}
+	}
+	if((opt_dest ^ opt_pic) == 0) {
+		ERR("The -F, -E and -p options are mutually exclusive.\n");
+		usage();
+	}
+	iface_num = (opt_dest) ? 1 : 0;
+	if(!opt_pic) {
+		if(optind != argc - 1) {
+			ERR("Got %d hexfile names (Need exactly one hexfile)\n",
+				argc - 1 - optind);
+			usage();
+		}
+	}
+	if(!devpath) {
+		ERR("Missing device path.\n");
+		usage();
+	}
+	if((astribank = astribank_open(devpath, iface_num)) == NULL) {
+		ERR("Opening astribank failed\n");
+		return 1;
+	}
+	show_astribank_info(astribank);
+	if(opt_dest) {
+		if(load_hexfile(astribank, argv[optind], dest) < 0) {
+			ERR("Loading firmware to %s failed\n", dev_dest2str(dest));
+			return 1;
+		}
+	} else if(opt_pic) {
+		if((ret = load_pic(astribank, argc - optind, argv + optind)) < 0) {
+			ERR("Loading PIC's failed\n");
+			return 1;
+		}
+	}
+	astribank_close(astribank, 0);
+	return 0;
+}
diff --git a/xpp/astribank_hook b/xpp/astribank_hook
new file mode 100755
index 0000000..ae38635
--- /dev/null
+++ b/xpp/astribank_hook
@@ -0,0 +1,114 @@
+#! /bin/sh
+
+me=`basename $0`
+dir=`dirname $0`
+LOGGER="logger -i -t '$me'"
+
+# Always redirect stderr somewhere, otherwise the shell script will die
+# when it tries to do I/O related stuff on closed file descriptor.
+# Our default is to throw it down the bit-bucket.
+#exec 2> /dev/console
+## If you wish to trace this script:
+#exec 2> "/tmp/${me}_$XBUS_NAME" 1>&2
+
+# Our directory in the beginning, so we can use local lab setup
+PATH="$dir:/usr/sbin:/sbin:/usr/bin:/bin"
+
+set -e
+
+[ -r /etc/dahdi/init.conf ] && . /etc/dahdi/init.conf
+
+# For lab testing
+liveconf="$dir/liveconf/dahdi"
+
+if [ -d "$liveconf" ]; then
+	dahdi_conf="$liveconf"
+else
+	dahdi_conf="/etc/dahdi"
+fi
+
+export XPPORDER_CONF="$dahdi_conf/xpp_order"
+if [ ! -r "$XPPORDER_CONF" ]; then
+	(
+		echo "Skip($ACTION): No '$XPPORDER_CONF'"
+		echo "Removing uneeded startup semaphore"
+		astribank_is_starting -v -r 2>&1
+	) 2>&1 | $LOGGER
+	exit 0
+fi
+export DAHDI_CFG_CMD="dahdi_cfg -c $dahdi_conf/system.conf"
+export CALLED_FROM_ATRIBANK_HOOK=yes
+
+clean_lines() {
+	sed -e 's/#.*//' -e 'y/\t/ /' -e 's/^ *//' -e 's/ *$//' -e '$s/$/\n/' "$XPPORDER_CONF"
+}
+
+matched_devices() {
+	ready=`grep -H READY /sys/bus/astribanks/devices/*/xbus_state | sed 's,/xbus_state.*,,'`
+	for dev in $ready
+	do
+		label=`cat "$dev/label"`
+		connector=`cat "$dev/connector"`
+		xbus=`echo "$dev" | sed 's,.*/,,'`
+		lineno=`clean_lines | egrep -n "^${label}$|^@${connector}$" | cut -d: -f1`
+		if [ "$lineno" != "" ]; then
+			#echo "$xbus: $XPPORDER_CONF:$lineno -- Match ${label} @${connector}" | $LOGGER
+			printf "${xbus}\t${label}\n"
+		else
+			echo "${xbus}: ${label} @${connector} not found in $XPPORDER_CONF: Ignore($ACTION)" | $LOGGER
+		fi
+	done
+}
+
+NUM_WANTED=`clean_lines | sed '/^$/d' | wc -l`
+NUM_GOOD=`matched_devices | wc -l`
+
+start_dahdi() {
+	script=/etc/init.d/dahdi
+	if [ "$XPP_HOTPLUG_DAHDI" = yes ]; then
+		echo "Starting $script."
+		"$script" start | logger -i -t "$script"
+		status=$?
+		echo "Status($script): $status"
+	else
+		echo "$0: Skip($script): No XPP_HOTPLUG_DAHDI=yes in /etc/dahdi/init.conf"
+		exit 0
+	fi
+	if [ -x "$dir/twinstar_hook" ]; then
+		"$dir/twinstar_hook"
+	fi
+	# Finished astribanks
+	echo "Removing semaphore"
+	astribank_is_starting -v -r
+}
+
+case "$ACTION" in
+add)
+	;;
+remove)
+	;;
+online)
+	echo "$ACTION($XBUS_NAME): $NUM_GOOD/$NUM_WANTED from $XPPORDER_CONF" | $LOGGER
+	if [ "$NUM_GOOD" -eq "$NUM_WANTED" ]; then
+		echo "START-DAHDI: Total $NUM_GOOD online." | $LOGGER
+		# Fork services
+		start_dahdi < /dev/null 2>&1 | $LOGGER &
+	fi
+	;;
+offline)
+	echo "$ACTION($XBUS_NAME): $NUM_GOOD/$NUM_WANTED from $XPPORDER_CONF" | $LOGGER
+	if [ "$NUM_GOOD" -eq 0 ]; then
+		echo "All Astribanks offline" | $LOGGER
+		if [ -x "$dir/twinstar_hook" ]; then
+			"$dir/twinstar_hook"
+		fi
+	fi
+	;;
+*)
+	echo "$0: Unknown ACTION='$ACTION'" | $LOGGER
+	echo "$0: ARGS='$*'" | $LOGGER
+	echo "$0: ENV:" | $LOGGER
+	env | $LOGGER
+	exit 1
+esac
+
diff --git a/xpp/astribank_is_starting.8 b/xpp/astribank_is_starting.8
new file mode 100644
index 0000000..5ad0be1
--- /dev/null
+++ b/xpp/astribank_is_starting.8
@@ -0,0 +1,100 @@
+.TH "ASTRIBANK_IS_STARTING" "8" "16 August 2009" "" ""
+
+.SH NAME
+astribank_is_starting \- Mark / check is a Xorcom Astribank (xpp) is starting
+.SH SYNOPSIS
+.B astribank_is_starting [\-d] [\-v] [\-t \fItimeout\fB] <\-a|\-r|\-w>
+
+.B astribank_is_starting [\-d] [\-v]
+
+.B astribank_is_starting \-h
+
+.SH DESCRIPTION
+.B astribank_is_starting
+is an internal tool used by various xpp scripts to mark that there may
+be an Astribank device currently initializing, and to check for that mark.
+
+Technically the mark is a SysV semaphore.
+
+.SH OPTIONS
+.B \-a
+.RS
+.B Add.
+Set the mark. Should return 0 unless there's an error.
+.RE
+
+.B \-r
+.RS
+.B Remove.
+Reset the mark. Should return 0 unless there's an error.
+.RE
+
+.BI \-t timeout
+.RS
+.B Timeout.
+Set the timeout value for the \fB\-w\fR option. Default is 60 seconds.
+.RE
+
+.B \-w
+.RS
+.B Wait.
+Wait for mark to be reset. Should return 0 unless there's an error.
+.RE
+
+Without \-a or \-r: return 0 if the mark has been set, or a non-zero value
+otherwise.
+
+.B \-d
+.RS
+Print debug information to stderr.
+.RE
+
+.B \-v
+.RS
+Verbose execution.
+.RE
+
+.B \-h
+.RS
+Displays usage message.
+.RE
+
+.SH FILES
+.B /proc/sysvipc/sem
+.RS
+If set, the astribank should appear there with the ID 11211168 (0xAB11A0).
+Naturally the ID (or rather, the usage of a semaphore in the first place)
+is an implementation detail that may change.
+.RE
+
+.SH NOTES
+.B astribank_is_starting
+is used to mark the fact that an Astribank may be currently reenumerating
+(technically: distonnecting and connecting as a new USB device) after
+loading the firmware. Thus the script that loads the firmware 
+(/usr/share/dahdi/xpp_fxloader) uses this utility to set the mark.
+
+The mark is reset by /usr/share/dahdi/waitfor_xpds , which is typically
+run by the DAHDI init script and waits for all Astribanks to finish
+loading.
+
+Q: Why do you use a semaphore?
+
+A: because, unlike the filesystem, it is writable at any given time.
+
+.SH BUGS
+Option ordering matter. The \fB\-v\fR and \fB\-d\fR options should preceed
+the actions (\fB\-a\fR, \fB\-r\fR and \fB\-w\fR).
+The \fB\-t\fItimeout\fR option should preceed the \fB\-w\fR option.
+
+.SH SEE ALSO
+semctl(3)
+
+.SH AUTHOR
+This manual page was written by Tzafrir Cohen <tzafrir.cohen at xorcom.com> .
+Permission is granted to copy, distribute and/or modify this document under
+the terms of the GNU General Public License, Version 2 any 
+later version published by the Free Software Foundation.
+
+On Debian systems, the complete text of the GNU General Public
+License can be found in /usr/share/common\-licenses/GPL.
diff --git a/xpp/astribank_is_starting.c b/xpp/astribank_is_starting.c
new file mode 100644
index 0000000..2ae1f73
--- /dev/null
+++ b/xpp/astribank_is_starting.c
@@ -0,0 +1,190 @@
+#include "../autoconfig.h"
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <errno.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+static char		*progname;
+static const key_t	key_astribanks = 0xAB11A0;
+static int		debug;
+static int		verbose;
+static int		timeout_seconds = 60;
+
+
+static void usage(void)
+{
+	fprintf(stderr, "Usage: %s [-d] [-t <seconds>] [-a|-r|-w]\n", progname);
+	exit(1);
+}
+
+static int absem_get(int createit)
+{
+	int	flags = (createit) ? IPC_CREAT | 0644 : 0;
+	int	absem;
+
+	if((absem = semget(key_astribanks, 1, flags)) < 0)
+		absem = -errno;
+	return absem;
+}
+
+static int absem_touch(void)
+{
+	int		absem;
+
+	if((absem = absem_get(1)) < 0) {
+		perror(__FUNCTION__);
+		return absem;
+	}
+	if(semctl(absem, 0, SETVAL, 0) < 0) {
+		perror("SETVAL");
+		return -errno;
+	}
+	if(debug)
+		fprintf(stderr, "%s: touched absem\n", progname);
+	if(verbose)
+		printf("Astribanks initialization is starting\n");
+	return 0;
+}
+
+static int absem_remove(void)
+{
+	int	absem;
+
+	if((absem = absem_get(0)) < 0) {
+		if(absem == -ENOENT) {
+			if(debug)
+				fprintf(stderr, "%s: absem already removed\n", progname);
+			return 0;
+		}
+		perror(__FUNCTION__);
+		return absem;
+	}
+	if(semctl(absem, 0, IPC_RMID, 0) < 0) {
+		perror("RMID");
+		return -errno;
+	}
+	if(debug)
+		fprintf(stderr, "%s: removed absem\n", progname);
+	if(verbose)
+		printf("Astribanks initialization is done\n");
+	return 0;
+}
+
+static int absem_wait(void)
+{
+	int		absem;
+	struct sembuf	sops;
+	long		now;
+	long		start_wait;
+	struct timespec	timeout;
+
+	if((absem = absem_get(0)) < 0) {
+		perror(__FUNCTION__);
+		return absem;
+	}
+	sops.sem_num = 0;
+	sops.sem_op = -1;
+	sops.sem_flg = 0;
+	start_wait = time(NULL);
+	timeout.tv_sec = timeout_seconds;
+	timeout.tv_nsec = 0;
+	if(semtimedop(absem, &sops, 1, &timeout) < 0) {
+		switch(errno) {
+		case EIDRM:	/* Removed -- OK */
+			break;
+		case EAGAIN:	/* Timeout -- Report */
+			fprintf(stderr, "Astribanks waiting timed out\n");
+			return -errno;
+		default:	/* Unexpected errors */
+			perror("semop");
+			return -errno;
+		}
+		/* fall-thgough */
+	}
+	now = time(NULL);
+	if(debug)
+		fprintf(stderr, "%s: waited on absem %ld seconds\n", progname, now - start_wait);
+	if(verbose)
+		printf("Finished after %ld seconds\n", now - start_wait);
+	return 0;
+}
+
+static int absem_detected(void)
+{
+	int	absem;
+
+	if((absem = absem_get(0)) < 0) {
+		if(debug)
+			fprintf(stderr, "%s: absem does not exist\n", progname);
+		return absem;
+	}
+	if(debug)
+		fprintf(stderr, "%s: absem exists\n", progname);
+	if(verbose)
+		printf("Astribanks are initializing...\n");
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	const char	options[] = "dvarwt:h";
+	int		val;
+
+	progname = argv[0];
+	while (1) {
+		int	c;
+		int	t;
+
+		c = getopt (argc, argv, options);
+		if (c == -1)
+			break;
+
+		switch (c) {
+			case 'd':
+				debug++;
+				break;
+			case 'v':
+				verbose++;
+				break;
+			case 't':
+				t = atoi(optarg);
+				if(t <= 0) {
+					fprintf(stderr,
+						"%s: -t expect a positive number of seconds: '%s'\n",
+						progname, optarg);
+					usage();
+				}
+				timeout_seconds = t;
+				break;
+			case 'a':
+				if((val = absem_touch()) < 0) {
+					fprintf(stderr, "%s: Add failed: %d\n", progname, val);
+					return 1;
+				}
+				return 0;
+			case 'r':
+				if((val = absem_remove()) < 0) {
+					fprintf(stderr, "%s: Remove failed: %d\n", progname, val);
+					return 1;
+				}
+				return 0;
+			case 'w':
+				if((val = absem_wait()) < 0) {
+					fprintf(stderr, "%s: Wait failed: %d\n", progname, val);
+					return 1;
+				}
+				return 0;
+			case 'h':
+			default:
+				fprintf(stderr, "Unknown option '%c'\n", c);
+				usage();
+		}
+	}
+	val = absem_detected();
+	return (val == 0) ? 0 : 1;
+}
diff --git a/xpp/astribank_tool.8 b/xpp/astribank_tool.8
new file mode 100644
index 0000000..d685470
--- /dev/null
+++ b/xpp/astribank_tool.8
@@ -0,0 +1,86 @@
+.TH "ASTRIBANK_TOOL" "8" "29 March 2009" "" ""
+
+.SH NAME
+astribank_tool \- Xorcom Astribank (xpp) control tool
+.SH SYNOPSIS
+.B astribank_tool [ options ] [ operation... ] \-D \fIdevice-path\fR
+
+.B astribank_tool [\-h]
+
+.SH DESCRIPTION
+.B astribank_tool
+is a tool to control the USB-level functionality of an Astribank.
+The tool operates on a single Astribank at a time (given as parameter
+to the \-D command line option).
+
+.SH OPTIONS
+.B \-D 
+.I device-path
+.RS
+Required. The device to read from/write to. On modern UDEV-based system
+this is usually /dev/bus/usb/\fIbus_num\fR/\fIdevice_num\fR,
+where \fIbus_num\fR and \fIdevice_num\fR are the first two numbers in the
+output of lsusb(8).
+On older systems that use usbfs, it is usually
+/proc/bus/usb/\fIbus_num\fR/\fIdevice_num\fR.
+.RE
+
+.B \-p \fInum\fR
+.RS
+Set the TwinStar port number. Either 0 or 1.
+
+(TODO: explain).
+.RE
+
+.B \-r \fItype\fR
+.RS
+Reset the Astribank and renumerate its USB connection to power on product ID.
+
+Tyep can be: \fBhalf\fR or \fBfull\fR.
+
+(TODO: explain those).
+.RE
+
+.B \-w 0|1
+.RS
+Enable (1) or disable (0) the TwinStar watchdog. When enabled, the
+Astribank will jump to the second port if this system is "not working"
+and the system on the second port is available.
+.RE
+
+.B \-Q
+.RS
+Query astribank properties via MPP protocol.
+.RE
+
+.B \-n
+.RS
+Renumerate the Astribank product number (e.g: from 1161 to 1162).
+.RE
+
+.B \-v
+.RS
+Increase verbosity. May be used multiple times.
+.RE
+
+.B \-d \fImask\fR
+.RS
+Set debug mask to \fImask\fR. Default is 0, 0xFF is "everything".
+.RE
+
+.B \-h
+.RS
+Displays usage message.
+.RE
+
+.SH SEE ALSO
+fxload(8), lsusb(8), astribank_hexload(8)
+
+.SH AUTHOR
+This manual page was written by Tzafrir Cohen <tzafrir.cohen at xorcom.com> .
+Permission is granted to copy, distribute and/or modify this document under
+the terms of the GNU General Public License, Version 2 any 
+later version published by the Free Software Foundation.
+
+On Debian systems, the complete text of the GNU General Public
+License can be found in /usr/share/common\-licenses/GPL.
diff --git a/xpp/astribank_tool.c b/xpp/astribank_tool.c
new file mode 100644
index 0000000..59ae94c
--- /dev/null
+++ b/xpp/astribank_tool.c
@@ -0,0 +1,274 @@
+/*
+ * Written by Oron Peled <oron at actcom.co.il>
+ * Copyright (C) 2008, Xorcom
+ *
+ * All rights reserved.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <arpa/inet.h>
+#include "mpp_funcs.h"
+#include "debug.h"
+
+#define	DBG_MASK	0x80
+/* if enabled, adds support for resetting pre-MPP USB firmware - if we 
+ * failed opening a device and we were asked to reset it, try also the
+ * old protocol.
+ */
+#define SUPPORT_OLD_RESET
+
+static char	*progname;
+
+static void usage()
+{
+	fprintf(stderr, "Usage: %s [options] -D {/proc/bus/usb|/dev/bus/usb}/<bus>/<dev> [operation...]\n", progname);
+	fprintf(stderr, "\tOptions:\n");
+	fprintf(stderr, "\t\t[-v]               # Increase verbosity\n");
+	fprintf(stderr, "\t\t[-d mask]          # Debug mask (0xFF for everything)\n");
+	fprintf(stderr, "\tOperations:\n");
+	fprintf(stderr, "\t\t[-n]               # Renumerate device\n");
+	fprintf(stderr, "\t\t[-r kind]          # Reset: kind = {half|full}\n");
+	fprintf(stderr, "\t\t[-p port]          # TwinStar: USB port number [0, 1]\n");
+	fprintf(stderr, "\t\t[-w (0|1)]         # TwinStar: Watchdog off or on guard\n");
+	fprintf(stderr, "\t\t[-Q]               # Query device properties\n");
+	exit(1);
+}
+
+static int reset_kind(const char *arg)
+{
+	static const struct {
+		const char	*name;
+		int		type_code;
+	} reset_kinds[] = {
+		{ "half",	0 },
+		{ "full",	1 },
+	};
+	int	i;
+
+	for(i = 0; i < sizeof(reset_kinds)/sizeof(reset_kinds[0]); i++) {
+		if(strcasecmp(reset_kinds[i].name, arg) == 0)
+			return reset_kinds[i].type_code;
+	}
+	ERR("Uknown reset kind '%s'\n", arg);
+	return -1;
+}
+
+
+static int show_hardware(struct astribank_device *astribank)
+{
+	uint8_t	unit;
+	uint8_t	card_status;
+	uint8_t	card_type;
+	int	ret;
+	struct eeprom_table	eeprom_table;
+	struct capabilities	capabilities;
+	struct extrainfo	extrainfo;
+
+	ret = mpp_caps_get(astribank, &eeprom_table, &capabilities, NULL);
+	if(ret < 0)
+		return ret;
+	show_eeprom(&eeprom_table, stdout);
+	show_astribank_status(astribank, stdout);
+	if(astribank->eeprom_type == EEPROM_TYPE_LARGE) {
+		show_capabilities(&capabilities, stdout);
+		if(STATUS_FPGA_LOADED(astribank->status)) {
+			for(unit = 0; unit < 4; unit++) {
+				ret = mpps_card_info(astribank, unit, &card_type, &card_status);
+				if(ret < 0)
+					return ret;
+				printf("CARD %d: type=%x.%x %s\n", unit,
+						((card_type >> 4) & 0xF), (card_type & 0xF),
+						((card_status & 0x1) ? "PIC" : "NOPIC"));
+			}
+		}
+		ret = mpp_extrainfo_get(astribank, &extrainfo);
+		if(ret < 0)
+			return ret;
+		show_extrainfo(&extrainfo, stdout);
+		if(CAP_EXTRA_TWINSTAR(&capabilities)) {
+			twinstar_show(astribank, stdout);
+		}
+	}
+	return 0;
+}
+
+#ifdef SUPPORT_OLD_RESET
+/* Try to reset a device using USB_FW.hex, up to Xorcom rev. 6885 */
+int old_reset(const char* devpath)
+{
+	struct astribank_device *astribank;
+	int ret;
+	struct {
+		uint8_t		op;
+	} PACKED header = {0x20}; /* PT_RESET */
+	char *buf = (char*) &header;
+
+	/* Note that the function re-opens the connection to the Astribank
+	 * as any reference to the previous connection was lost when mpp_open
+	 * returned NULL as the astribank reference. */
+	astribank = astribank_open(devpath, 1);
+	if (!astribank) {
+		DBG("Failed re-opening astribank device for old_reset\n");
+		return -ENODEV;
+	}
+	ret = send_usb(astribank, buf, 1, 5000);
+
+	/* If we just had a reenumeration, we may get -ENODEV */
+	if(ret < 0 && ret != -ENODEV)
+			return ret;
+	/* We don't astribank_close(), as it has likely been
+	 * reenumerated by now. */
+	return 0;
+}	
+#endif /* SUPPORT_OLD_RESET */
+
+int main(int argc, char *argv[])
+{
+	char			*devpath = NULL;
+	struct astribank_device *astribank;
+	const char		options[] = "vd:D:nr:p:w:Q";
+	int			opt_renumerate = 0;
+	char			*opt_port = NULL;
+	char			*opt_watchdog = NULL;
+	char			*opt_reset = NULL;
+	int			opt_query = 0;
+	int			ret;
+
+	progname = argv[0];
+	while (1) {
+		int	c;
+
+		c = getopt (argc, argv, options);
+		if (c == -1)
+			break;
+
+		switch (c) {
+			case 'D':
+				devpath = optarg;
+				break;
+			case 'n':
+				opt_renumerate++;
+				break;
+			case 'p':
+				opt_port = optarg;
+				break;
+			case 'w':
+				opt_watchdog = optarg;
+				break;
+			case 'r':
+				opt_reset = optarg;
+				/*
+				 * Sanity check so we can reject bad
+				 * arguments before device access.
+				 */
+				if(reset_kind(opt_reset) < 0)
+					usage();
+				break;
+			case 'Q':
+				opt_query = 1;
+				break;
+			case 'v':
+				verbose++;
+				break;
+			case 'd':
+				debug_mask = strtoul(optarg, NULL, 0);
+				break;
+			case 'h':
+			default:
+				ERR("Unknown option '%c'\n", c);
+				usage();
+		}
+	}
+	if(!devpath) {
+		ERR("Missing device path\n");
+		usage();
+	}
+	DBG("Startup %s\n", devpath);
+	if((astribank = mpp_init(devpath)) == NULL) {
+		ERR("Failed initializing MPP\n");
+#ifdef SUPPORT_OLD_RESET
+		DBG("opt_reset = %s\n", opt_reset);
+		if (opt_reset) {
+			DBG("Trying old reset method\n");
+			if ((ret = old_reset(devpath)) != 0) {
+				ERR("Old reset method failed as well: %d\n", ret);
+			}
+		}
+#endif /* SUPPORT_OLD_RESET */
+
+		return 1;
+	}
+	/*
+	 * First process reset options. We want to be able
+	 * to reset minimal USB firmwares even if they don't
+	 * implement the full MPP protocol (e.g: EEPROM_BURN)
+	 */
+	if(opt_reset) {
+		int	full_reset;
+
+		if((full_reset = reset_kind(opt_reset)) < 0) {
+			ERR("Bad reset kind '%s'\n", opt_reset);
+			return 1;
+		}
+		DBG("Reseting (%s)\n", opt_reset);
+		if((ret = mpp_reset(astribank, full_reset)) < 0) {
+			ERR("%s Reseting astribank failed: %d\n",
+				(full_reset) ? "Full" : "Half", ret);
+		}
+		goto out;
+	}
+	show_astribank_info(astribank);
+	if(opt_query) {
+		show_hardware(astribank);
+	} else if(opt_renumerate) {
+		DBG("Renumerate\n");
+		if((ret = mpp_renumerate(astribank)) < 0) {
+			ERR("Renumerating astribank failed: %d\n", ret);
+		}
+	} else if(opt_watchdog) {
+		int	watchdogstate = strtoul(opt_watchdog, NULL, 0);
+
+		DBG("TWINSTAR: Setting watchdog %s-guard\n",
+			(watchdogstate) ? "on" : "off");
+		if((ret = mpp_tws_setwatchdog(astribank, watchdogstate)) < 0) {
+			ERR("Failed to set watchdog to %d\n", watchdogstate);
+			return 1;
+		}
+	} else if(opt_port) {
+		int	new_portnum = strtoul(opt_port, NULL, 0);
+		int	tws_portnum = mpp_tws_portnum(astribank);
+		char	*msg = (new_portnum == tws_portnum)
+					? " Same same, never mind..."
+					: "";
+
+		DBG("TWINSTAR: Setting portnum to %d.%s\n", new_portnum, msg);
+		if((ret = mpp_tws_setportnum(astribank, new_portnum)) < 0) {
+			ERR("Failed to set USB portnum to %d\n", new_portnum);
+			return 1;
+		}
+	}
+out:
+	mpp_exit(astribank);
+	return 0;
+}
diff --git a/xpp/astribank_upgrade b/xpp/astribank_upgrade
new file mode 100755
index 0000000..71ae238
--- /dev/null
+++ b/xpp/astribank_upgrade
@@ -0,0 +1,150 @@
+#!/bin/bash
+
+# astribank_upgrade: force load Xorcom Astribank (XPP) USB firmware
+# A reduced version of xpp_fxloader for manual upgrades.
+#
+# Written by Oron Peled <oron at actcom.co.il>
+# Copyright (C) 2009 Xorcom
+#
+# All rights reserved.
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+set -e
+
+# Make sure fxload is in the path:
+PATH="$PATH:/usr/local/sbin:/sbin:/usr/sbin"
+export PATH
+
+me=`basename $0`
+
+if [ -t 2 ]; then
+	LOGGER="logger -i -t '$me' -s"
+else
+	LOGGER="logger -i -t '$me'"
+fi
+
+USBFS_PREFIX=/proc/bus/usb
+DEVUSB_PREFIX=/dev/bus/usb
+USB_PREFIX=
+
+USB_FW="${USB_FW:-USB_FW.hex}"
+
+if [ "$USB_PREFIX" = '' ]; then
+	if [ -d "$DEVUSB_PREFIX" ]; then
+		USB_PREFIX=$DEVUSB_PREFIX
+	elif [ -r "$USBFS_PREFIX/devices" ]; then
+		USB_PREFIX=$USBFS_PREFIX
+	fi
+fi
+
+# With Kernels older that 2.6.10 it seems to be possible
+# to trigger a race condition by running fxload or fpga_load 
+# immediately after the detection of the device.
+KERNEL_HAS_USB_RACE=0
+case "`uname -r`" in 2.6.[89]*) KERNEL_HAS_USB_RACE=1;; esac
+sleep_if_race() {
+  if [ "$KERNEL_HAS_USB_RACE" = '1' ]; then
+    sleep 2
+  fi
+}
+
+find_dev() {
+  v_id=$1
+  p_id=$2
+  
+  lsusb | tr -d : | awk "/ ID $v_id$p_id/{printf \"$USB_PREFIX/%s/%s \",\$2,\$4}"
+}
+
+run_fxload() {
+  sleep_if_race
+  fxload -t fx2 $* 2>&1 1>/dev/null | $LOGGER
+  status=$PIPESTATUS
+  if [ $status != 0 ]; then
+    $LOGGER "fxload failed with status $status"
+    exit 55
+  fi
+}
+
+load_usb_fw() {
+  v_id=$1
+  p_id=$2
+  fw=$3
+  
+  devices=`find_dev $v_id $p_id`
+  for dev in $devices
+  do
+    ver=$(awk '/\$Id:/ { print $4 }' $FIRMWARE_DIR/$fw)
+    $LOGGER "USB Firmware $FIRMWARE_DIR/$fw (Version=$ver) into $dev"
+    run_fxload -D $dev -I $FIRMWARE_DIR/$fw || exit 1
+  done
+}
+
+numdevs() {
+  v_ids="$1"
+  p_ids="$2"
+
+  for v in $v_ids
+  do
+    (
+      for p in $p_ids
+      do
+        find_dev $v $p
+      done
+    )
+  done | wc -w
+}
+
+wait_renumeration() {
+  num="$1"
+  v_ids="$2"
+  p_ids="$3"
+
+  while
+    n=`numdevs "$v_ids" "$p_ids"`
+    [ "$num" -gt "$n" ]
+  do
+    echo -n "."
+    sleep 1
+  done
+  echo "Got all $num devices"
+}
+
+if [ "$#" -ne 1 ]; then
+	echo >&2 "Usage: $0 <firmware_directory>"
+	exit 1
+fi
+FIRMWARE_DIR="$1"
+[ -f "$FIRMWARE_DIR/$USB_FW" ] || {
+	echo >&2 "$0: Could not find '$FIRMWARE_DIR/$USB_FW'"
+	exit 1
+}
+numdevs=`numdevs e4e4 '11[3456][01]'`
+$LOGGER -- "--------- LOADING NEW USB FIRMWARE: ($1) [$numdevs devices]"
+load_usb_fw e4e4 1130 $USB_FW
+load_usb_fw e4e4 1140 $USB_FW
+load_usb_fw e4e4 1150 $USB_FW
+load_usb_fw e4e4 1160 $USB_FW
+load_usb_fw e4e4 1131 $USB_FW
+load_usb_fw e4e4 1141 $USB_FW
+load_usb_fw e4e4 1151 $USB_FW
+load_usb_fw e4e4 1161 $USB_FW
+load_usb_fw e4e4 1132 $USB_FW
+load_usb_fw e4e4 1142 $USB_FW
+load_usb_fw e4e4 1152 $USB_FW
+load_usb_fw e4e4 1162 $USB_FW
+wait_renumeration $numdevs e4e4 '11[3456]1'
+$LOGGER -- "--------- NEW USB FIRMWARE IS LOADED"
diff --git a/xpp/astribank_usb.c b/xpp/astribank_usb.c
new file mode 100644
index 0000000..dce3d47
--- /dev/null
+++ b/xpp/astribank_usb.c
@@ -0,0 +1,555 @@
+/*
+ * Written by Oron Peled <oron at actcom.co.il>
+ * Copyright (C) 2008, Xorcom
+ *
+ * All rights reserved.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#define	_GNU_SOURCE	/* for memrchr() */
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <arpa/inet.h>
+#include "astribank_usb.h"
+#include "debug.h"
+
+static const char rcsid[] = "$Id$";
+
+#define	DBG_MASK	0x01
+#define	TIMEOUT	500
+
+#define	TYPE_ENTRY(t,ni,n,ne,out,in,...)	\
+	[t] = {					\
+		.type_code = (t),		\
+		.num_interfaces = (ni),		\
+		.my_interface_num = (n),	\
+		.num_endpoints = (ne),		\
+		.my_ep_in = (in),		\
+		.my_ep_out = (out),		\
+		.name = #t,			\
+		.endpoints = { __VA_ARGS__ },	\
+		}
+
+static const struct interface_type interface_types[] = {
+	TYPE_ENTRY(USB_11xx,		1, 0, 4, MP_EP_OUT, MP_EP_IN,
+		XPP_EP_OUT,
+		MP_EP_OUT,
+		XPP_EP_IN,
+		MP_EP_IN),
+	TYPE_ENTRY(USB_FIRMWARE_II,	2, 1, 2, MP_EP_OUT, MP_EP_IN,
+		MP_EP_OUT,
+		MP_EP_IN),
+	TYPE_ENTRY(USB_PIC,		2, 0, 2, XPP_EP_OUT, XPP_EP_IN, 
+		XPP_EP_OUT,
+		XPP_EP_IN),
+	 
+};
+#undef TYPE_ENTRY
+
+//static int	verbose = LOG_DEBUG;
+
+/*
+ * USB handling
+ */
+
+/* return 1 if:
+ * - str has a number
+ * - It is larger than 0
+ * - It equals num
+ */
+static int num_matches(int num, const char* str) {
+	int str_val = atoi(str);
+	if (str_val <= 0)
+		return 0;
+	return (str_val == num);
+}
+
+struct usb_device *dev_of_path(const char *path)
+{
+	struct usb_bus		*bus;
+	struct usb_device	*dev;
+	char			dirname[PATH_MAX];
+	char			filename[PATH_MAX];
+	const char		*p;
+	int			bnum;
+	int			dnum;
+	int			ret;
+
+	assert(path != NULL);
+	if(access(path, F_OK) < 0) {
+		perror(path);
+		return NULL;
+	}
+	/* Find last '/' */
+	if((p = memrchr(path, '/', strlen(path))) == NULL) {
+		ERR("Missing a '/' in %s\n", path);
+		return NULL;
+	}
+	/* Get the device number */
+	ret = sscanf(p + 1, "%d", &dnum);
+	if(ret != 1) {
+		ERR("Path tail is not a device number: '%s'\n", p);
+		return NULL;
+	}
+	/* Search for a '/' before that */
+	p = memrchr(path, '/', p - path);
+	if(p == NULL)
+		p = path;		/* Relative path */
+	else
+		p++;			/* skip '/' */
+	/* Get the bus number */
+	ret = sscanf(p, "%d", &bnum);
+	if(ret != 1) {
+		ERR("Path tail is not a bus number: '%s'\n", p);
+		return NULL;
+	}
+	sprintf(dirname, "%03d", bnum);
+	sprintf(filename, "%03d", dnum);
+	for (bus = usb_busses; bus; bus = bus->next) {
+		if (! num_matches(bnum, bus->dirname))
+		//if(strcmp(bus->dirname, dirname) != 0)
+			continue;
+		for (dev = bus->devices; dev; dev = dev->next) {
+			//if(strcmp(dev->filename, filename) == 0)
+			if (num_matches(dnum, dev->filename))
+				return dev;
+		}
+	}
+	ERR("no usb device match '%s'\n", path);
+	return NULL;
+}
+
+int get_usb_string(struct astribank_device *astribank, uint8_t item, char *buf, unsigned int len)
+{
+	char	tmp[BUFSIZ];
+	int	ret;
+
+	assert(astribank->handle);
+	if (!item)
+		return 0;
+	ret = usb_get_string_simple(astribank->handle, item, tmp, BUFSIZ);
+	if (ret <= 0)
+		return ret;
+	return snprintf(buf, len, "%s", tmp);
+}
+
+static int match_interface(const struct astribank_device *astribank,
+	const struct interface_type *itype)
+{
+	struct usb_interface		*interface;
+	struct usb_interface_descriptor	*iface_desc;
+	struct usb_config_descriptor	*config_desc;
+	int				i = itype - interface_types;
+	int				inum;
+	int				num_altsetting;
+
+	DBG("Checking[%d]: interfaces=%d interface num=%d endpoints=%d: \"%s\"\n",
+			i,
+			itype->num_interfaces,
+			itype->my_interface_num,
+			itype->num_endpoints,
+			itype->name);
+	config_desc = astribank->dev->config;
+	if (!config_desc) {
+		ERR("No configuration descriptor: strange USB1 controller?\n");
+		return 0;
+	}
+	if(config_desc->bNumInterfaces <= itype->my_interface_num) {
+		DBG("Too little interfaces: have %d need %d\n",
+			config_desc->bNumInterfaces, itype->my_interface_num + 1);
+		return 0;
+	}
+	if(astribank->my_interface_num != itype->my_interface_num) {
+		DBG("Wrong match -- not my interface num (wanted %d)\n", astribank->my_interface_num);
+		return 0;
+	}
+	inum = itype->my_interface_num;
+	interface = &config_desc->interface[inum];
+	assert(interface != NULL);
+	iface_desc = interface->altsetting;
+	num_altsetting = interface->num_altsetting;
+	assert(num_altsetting != 0);
+	assert(iface_desc != NULL);
+	if(iface_desc->bInterfaceClass != 0xFF) {
+		DBG("Bad interface class 0x%X\n", iface_desc->bInterfaceClass);
+		return 0;
+	}
+	if(iface_desc->bInterfaceNumber != itype->my_interface_num) {
+		DBG("Bad interface number %d\n", iface_desc->bInterfaceNumber);
+		return 0;
+	}
+	if(iface_desc->bNumEndpoints != itype->num_endpoints) {
+		DBG("Different number of endpoints %d\n", iface_desc->bNumEndpoints);
+		return 0;
+	}
+	return	1;
+}
+
+static int astribank_init(struct astribank_device *astribank)
+{
+	struct usb_device_descriptor	*dev_desc;
+	struct usb_config_descriptor	*config_desc;
+	struct usb_interface		*interface;
+	struct usb_interface_descriptor	*iface_desc;
+	struct usb_endpoint_descriptor	*endpoint;
+	const struct interface_type	*fwtype;
+	int				i;
+
+	assert(astribank);
+	astribank->handle = usb_open(astribank->dev);
+	if(!astribank->handle) {
+		ERR("Failed to open usb device '%s/%s': %s\n",
+			astribank->dev->bus->dirname, astribank->dev->filename, usb_strerror());
+		return 0;
+	}
+	fwtype = astribank->fwtype;
+	if(usb_claim_interface(astribank->handle, fwtype->my_interface_num) != 0) {
+		ERR("usb_claim_interface: %s\n", usb_strerror());
+		return 0;
+	}
+	dev_desc = &astribank->dev->descriptor;
+	config_desc = astribank->dev->config;
+	if (!config_desc) {
+		ERR("usb interface without a configuration\n");
+		return 0;
+	}
+	DBG("Got config_desc. Looking for interface %d\n", fwtype->my_interface_num);
+	interface = &config_desc->interface[fwtype->my_interface_num];
+	iface_desc = interface->altsetting;
+	endpoint = iface_desc->endpoint;
+	astribank->is_usb2 = (endpoint->wMaxPacketSize == 512);
+	for(i = 0; i < iface_desc->bNumEndpoints; i++, endpoint++) {
+		DBG("Validating endpoint @ %d (interface %d)\n", i, fwtype->my_interface_num);
+		if(endpoint->bEndpointAddress != fwtype->endpoints[i]) {
+			ERR("Wrong endpoint 0x%X != 0x%X (at index %d)\n",
+				endpoint->bEndpointAddress,
+				fwtype->endpoints[i],
+				i);
+			return 0;
+		}
+		if(endpoint->bEndpointAddress == MP_EP_OUT || endpoint->bEndpointAddress == MP_EP_IN) {
+			if(endpoint->wMaxPacketSize > PACKET_SIZE) {
+				ERR("Endpoint #%d wMaxPacketSize too large (%d)\n", i, endpoint->wMaxPacketSize);
+				return 0;
+			}
+		}
+	}
+	astribank->my_ep_in = fwtype->my_ep_in;
+	astribank->my_ep_out = fwtype->my_ep_out;
+	if(get_usb_string(astribank, dev_desc->iManufacturer, astribank->iManufacturer, BUFSIZ) < 0)
+		return 0;
+	if(get_usb_string(astribank, dev_desc->iProduct, astribank->iProduct, BUFSIZ) < 0)
+		return 0;
+	if(get_usb_string(astribank, dev_desc->iSerialNumber, astribank->iSerialNumber, BUFSIZ) < 0)
+		return 0;
+	if(get_usb_string(astribank, iface_desc->iInterface, astribank->iInterface, BUFSIZ) < 0)
+		return 0;
+	DBG("ID=%04X:%04X Manufacturer=[%s] Product=[%s] SerialNumber=[%s] Interface=[%s]\n",
+		dev_desc->idVendor,
+		dev_desc->idProduct,
+		astribank->iManufacturer,
+		astribank->iProduct,
+		astribank->iSerialNumber,
+		astribank->iInterface);
+	if(usb_clear_halt(astribank->handle, astribank->my_ep_out) != 0) {
+		ERR("Clearing output endpoint: %s\n", usb_strerror());
+		return 0;
+	}
+	if(usb_clear_halt(astribank->handle, astribank->my_ep_in) != 0) {
+		ERR("Clearing input endpoint: %s\n", usb_strerror());
+		return 0;
+	}
+	if((i = flush_read(astribank)) < 0) {
+		ERR("flush_read failed: %d\n", i);
+		return 0;
+	}
+	return 1;
+}
+
+struct astribank_device *astribank_open(const char devpath[], int iface_num)
+{
+	struct astribank_device		*astribank;
+	int				i;
+
+	DBG("devpath='%s' iface_num=%d\n", devpath, iface_num);
+	if((astribank = malloc(sizeof(*astribank))) == NULL) {
+		ERR("Out of memory");
+		return NULL;
+	}
+	memset(astribank, 0, sizeof(*astribank));
+	astribank->my_interface_num = iface_num;
+	usb_init();
+	usb_find_busses();
+	usb_find_devices();
+	astribank->dev = dev_of_path(devpath);
+	if(!astribank->dev) {
+		ERR("Bailing out\n");
+		goto fail;
+	}
+	DBG("Scan interface types (astribank has %d interfaces)\n", astribank->dev->config->bNumInterfaces);
+	for(i = 0; i < sizeof(interface_types)/sizeof(interface_types[0]); i++) {
+		if(match_interface(astribank, &interface_types[i])) {
+			DBG("Identified[%d]: interfaces=%d endpoints=%d: \"%s\"\n",
+				i,
+				interface_types[i].num_interfaces,
+				interface_types[i].num_endpoints,
+				interface_types[i].name);
+			astribank->fwtype = &interface_types[i];
+			goto found;
+		}
+	}
+	ERR("Didn't find suitable device\n");
+fail:
+	free(astribank);
+	return NULL;
+found:
+	if(!astribank_init(astribank))
+		goto fail;
+	astribank->tx_sequenceno = 1;
+	return astribank;
+}
+
+/*
+ * MP device handling
+ */
+void show_astribank_info(const struct astribank_device *astribank)
+{
+	struct usb_device_descriptor	*dev_desc;
+	struct usb_device		*dev;
+
+	assert(astribank != NULL);
+	dev = astribank->dev;
+	dev_desc = &dev->descriptor;
+	if(verbose <= LOG_INFO) {
+		INFO("usb:%s/%s: ID=%04X:%04X [%s / %s / %s]\n",
+			dev->bus->dirname,
+			dev->filename,
+			dev_desc->idVendor,
+			dev_desc->idProduct,
+			astribank->iManufacturer,
+			astribank->iProduct,
+			astribank->iSerialNumber);
+	} else {
+		printf("USB    Bus/Device:    [%s/%s]\n", dev->bus->dirname, dev->filename);
+		printf("USB    Firmware Type: [%s]\n", astribank->fwtype->name);
+		printf("USB    iManufacturer: [%s]\n", astribank->iManufacturer);
+		printf("USB    iProduct:      [%s]\n", astribank->iProduct);
+		printf("USB    iSerialNumber: [%s]\n", astribank->iSerialNumber);
+	}
+}
+
+void astribank_close(struct astribank_device *astribank, int disconnected)
+{
+	assert(astribank != NULL);
+	if(!astribank->handle)
+		return;	/* Nothing to do */
+	if(!disconnected) {
+		if(usb_release_interface(astribank->handle, astribank->fwtype->my_interface_num) != 0) {
+			ERR("Releasing interface: usb: %s\n", usb_strerror());
+		}
+	}
+	if(usb_close(astribank->handle) != 0) {
+		ERR("Closing device: usb: %s\n", usb_strerror());
+	}
+	astribank->tx_sequenceno = 0;
+	astribank->handle = NULL;
+}
+
+int send_usb(struct astribank_device *astribank, char *buf, int len, int timeout)
+{
+	int		ret;
+
+	dump_packet(LOG_DEBUG, __FUNCTION__, buf, len);
+	if(astribank->my_ep_out & USB_ENDPOINT_IN) {
+		ERR("send_usb called with an input endpoint 0x%x\n", astribank->my_ep_out);
+		return -EINVAL;
+	}
+	ret = usb_bulk_write(astribank->handle, astribank->my_ep_out, buf, len, timeout);
+	if(ret < 0) {
+		/*
+		 * If the device was gone, it may be the
+		 * result of renumeration. Ignore it.
+		 */
+		if(ret != -ENODEV) {
+			ERR("bulk_write to endpoint 0x%x failed: (%d) %s\n",
+				astribank->my_ep_out, ret, usb_strerror());
+			dump_packet(LOG_ERR, "send_usb[ERR]", buf, len);
+			exit(2);
+		} else {
+			DBG("bulk_write to endpoint 0x%x got ENODEV\n", astribank->my_ep_out);
+			astribank_close(astribank, 1);
+		}
+		return ret;
+	} else if(ret != len) {
+		ERR("bulk_write to endpoint 0x%x short write: (%d) %s\n",
+			astribank->my_ep_out, ret, usb_strerror());
+		dump_packet(LOG_ERR, "send_usb[ERR]", buf, len);
+		return -EFAULT;
+	}
+	return ret;
+}
+
+int recv_usb(struct astribank_device *astribank, char *buf, size_t len, int timeout)
+{
+	int	ret;
+
+	if(astribank->my_ep_in & USB_ENDPOINT_OUT) {
+		ERR("recv_usb called with an output endpoint 0x%x\n", astribank->my_ep_in);
+		return -EINVAL;
+	}
+	ret = usb_bulk_read(astribank->handle, astribank->my_ep_in, buf, len, timeout);
+	if(ret < 0) {
+		DBG("bulk_read from endpoint 0x%x failed: (%d) %s\n",
+			astribank->my_ep_in, ret, usb_strerror());
+		memset(buf, 0, len);
+		return ret;
+	}
+	dump_packet(LOG_DEBUG, __FUNCTION__, buf, ret);
+	return ret;
+}
+
+int flush_read(struct astribank_device *astribank)
+{
+	char		tmpbuf[BUFSIZ];
+	int		ret;
+
+	DBG("starting...\n");
+	memset(tmpbuf, 0, BUFSIZ);
+	ret = recv_usb(astribank, tmpbuf, BUFSIZ, 1);
+	if(ret < 0 && ret != -ETIMEDOUT) {
+		ERR("ret=%d\n", ret);
+		return ret;
+	} else if(ret > 0) {
+		DBG("Got %d bytes:\n", ret);
+		dump_packet(LOG_DEBUG, __FUNCTION__, tmpbuf, ret);
+	}
+	return 0;
+}
+
+
+int release_isvalid(uint16_t release)
+{
+	uint8_t	rmajor = (release >> 8) & 0xFF;
+	uint8_t	rminor = release & 0xFF;
+
+	return	(rmajor > 0) &&
+		(rmajor < 10) &&
+		(rminor > 0) &&
+		(rminor < 10);
+}
+
+int label_isvalid(const char *label)
+{
+	int		len;
+	int		goodlen;
+	const char	GOOD_CHARS[] =
+				"abcdefghijklmnopqrstuvwxyz"
+				"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+				"0123456789"
+				"-_.";
+
+	len = strlen(label);
+	goodlen = strspn(label, GOOD_CHARS);
+	if(len > LABEL_SIZE) {
+		ERR("Label too long (%d > %d)\n", len, LABEL_SIZE);
+		return 0;
+	}
+	if(goodlen != len) {
+		ERR("Bad character in label (pos=%d)\n", goodlen);
+		return 0;
+	}
+	return 1;
+}
+
+int eeprom_fill(struct eeprom_table *eprm,
+	const char *vendor,
+	const char *product,
+	const char *release,
+	const char *label)
+{
+	uint16_t	val;
+
+	eprm->source = 0xC0;
+	eprm->config_byte = 0;
+	if(vendor) {
+		val = strtoul(vendor, NULL, 0);
+		if(!val) {
+			ERR("Invalid vendor '%s'\n",
+				vendor);
+			return -EINVAL;
+		}
+		eprm->vendor = val;
+	}
+	if(product) {
+		val = strtoul(product, NULL, 0);
+		if(!val) {
+			ERR("Invalid product '%s'\n",
+				product);
+			return -EINVAL;
+		}
+		eprm->product = val;
+	}
+	if(release) {
+		int		release_major = 0;
+		int		release_minor = 0;
+		uint16_t	value;
+
+		if(sscanf(release, "%d.%d", &release_major, &release_minor) != 2) {
+			ERR("Failed to parse release number '%s'\n", release);
+			return -EINVAL;
+		}
+		value = (release_major << 8) | release_minor;
+		DBG("Parsed release(%d): major=%d, minor=%d\n",
+			value, release_major, release_minor);
+		if(!release_isvalid(value)) {
+			ERR("Invalid release number 0x%X\n", value);
+			return -EINVAL;
+		}
+		eprm->release = value;
+	}
+	if(label) {
+		/* padding */
+		if(!label_isvalid(label)) {
+			ERR("Invalid label '%s'\n", label);
+			return -EINVAL;
+		}
+		memset(eprm->label, 0, LABEL_SIZE);
+		memcpy(eprm->label, label, strlen(label));
+	}
+	return 0;
+}
+
+int astribank_has_twinstar(struct astribank_device *astribank)
+{
+	struct usb_device_descriptor	*dev_desc;
+	uint16_t			product_series;
+
+	assert(astribank != NULL);
+	dev_desc = &astribank->dev->descriptor;
+	product_series = dev_desc->idProduct;
+	product_series &= 0xFFF0;
+	if(product_series == 0x1160)	/* New boards */
+		return 1;
+	return 0;
+}
+
diff --git a/xpp/astribank_usb.h b/xpp/astribank_usb.h
new file mode 100644
index 0000000..b3b4d79
--- /dev/null
+++ b/xpp/astribank_usb.h
@@ -0,0 +1,103 @@
+#ifndef	ASTRIBANK_USB_H
+#define	ASTRIBANK_USB_H
+/*
+ * Written by Oron Peled <oron at actcom.co.il>
+ * Copyright (C) 2008, Xorcom
+ *
+ * All rights reserved.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <usb.h>
+#include "mpp.h"
+
+/*
+ * Astribank handling
+ */
+
+#define	PACKET_SIZE	512
+
+/* USB Endpoints */
+#define	MP_EP_OUT	0x04	/* Managment processor */
+#define	MP_EP_IN	0x88	/* Managment processor */
+
+#define	XPP_EP_OUT	0x02	/* XPP */
+#define	XPP_EP_IN	0x86	/* XPP */
+
+/* USB firmware types */
+#define	USB_11xx	0
+#define	USB_FIRMWARE_II	1
+#define	USB_PIC		2
+
+struct interface_type {
+	int	type_code;
+	int	num_interfaces;
+	int	my_interface_num;
+	int	num_endpoints;
+	int	my_ep_out;
+	int	my_ep_in;
+	char	*name;
+	int	endpoints[4];	/* for matching */
+};
+
+enum eeprom_burn_state {
+	BURN_STATE_NONE		= 0,
+	BURN_STATE_STARTED	= 1,
+	BURN_STATE_ENDED	= 2,
+	BURN_STATE_FAILED	= 3,
+};
+
+struct astribank_device {
+	struct usb_device	*dev;
+	usb_dev_handle		*handle;
+	int			my_interface_num;
+	int			my_ep_out;
+	int			my_ep_in;
+	char			iManufacturer[BUFSIZ];
+	char			iProduct[BUFSIZ];
+	char			iSerialNumber[BUFSIZ];
+	char			iInterface[BUFSIZ];
+	int			is_usb2;
+	enum eeprom_type	eeprom_type;
+	enum eeprom_burn_state	burn_state;
+	uint8_t			status;
+	uint8_t			mpp_proto_version;
+	struct eeprom_table	*eeprom;
+	struct firmware_versions	fw_versions;
+	const struct interface_type	*fwtype;
+	uint16_t		tx_sequenceno;
+};
+
+/*
+ * Prototypes
+ */
+struct astribank_device	*astribank_open(const char devpath[], int iface_num);
+void astribank_close(struct astribank_device *astribank, int disconnected);
+void show_astribank_info(const struct astribank_device *astribank);
+int send_usb(struct astribank_device *astribank, char *buf, int len, int timeout);
+int recv_usb(struct astribank_device *astribank, char *buf, size_t len, int timeout);
+int flush_read(struct astribank_device *astribank);
+int eeprom_fill(struct eeprom_table *eprm,
+		const char *vendor,
+		const char *product,
+		const char *release,
+		const char *label);
+int astribank_has_twinstar(struct astribank_device *astribank);
+int label_isvalid(const char *label);
+
+#endif	/* ASTRIBANK_USB_H */
diff --git a/xpp/dahdi.cgi b/xpp/dahdi.cgi
new file mode 100755
index 0000000..5b0e591
--- /dev/null
+++ b/xpp/dahdi.cgi
@@ -0,0 +1,265 @@
+#! /usr/bin/perl -wT
+
+# Written by Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+# Copyright (C) 2008, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+
+use strict;
+use File::Basename;
+BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/perl_modules"); }
+
+use CGI::Pretty qw/:standard start_ul start_li start_div start_pre/;
+use Dahdi;
+use Dahdi::Xpp;
+use Dahdi::Hardware;
+
+$ENV{'PATH'} = '/bin:/usr/bin';
+
+my $DEF_TOK = '<Default>';
+
+my $style=<<END;
+<!--
+body {
+  margin-left: 0em;
+  margin-right: 5em;
+  //color: navy;
+  background-color: #white;
+}
+
+dfn {
+  font-style: italic;
+  text-decoration: underline;
+}
+
+#content {
+  margin-left: 10em;
+}
+
+h1, h2, h3 {
+  color: #d03;
+  margin-top: 2ex;
+}
+
+h1 { 
+  text-align: center;
+  color: #d03;
+  background-color: #ccc;
+  margin-left:5em;
+}
+/*
+li:hover {
+  background-color: #44c;
+}
+
+li li:hover {
+  background-color: #448;
+}
+*/
+/*li.status-ok  */
+.status-noconf  {background-color: red; }
+.status-notused {background-color: pink; } 
+
+#toc {
+  position: fixed;
+  width: 9em;
+  top: 3ex;
+  bottom: 0pt;
+  height: 100%;
+  margins-left: 1em;
+  color: #448;
+
+}
+
+#toc p {
+  display: block;
+  //text-align: center;
+  height: 3ex;
+}
+
+#toc a {
+  text-decoration: none;
+  /*
+  background-color: #F0FFF0;
+  */
+  font-weight: bold; 
+  display: block; 
+  padding: 0.2em; 
+  width: 80%; 
+  margin-bottom: 0.2ex; 
+  border-top: 1px solid #8bd;
+  color: #8bd;
+  text-align: right;
+}
+
+-->
+END
+
+my @Toc = ();
+
+sub header_line($$) {
+	my ($text, $anchor) = @_;
+	print a({-name=>$anchor},h2($text));
+	push(@Toc, [$text, $anchor] );
+}
+
+print header,
+	start_html(
+		-title=>"DAHDI Information",
+		-style=>{-code=>$style}),
+	h1("DAHDI Information");
+
+print start_div({-id=>'content'});
+
+sub dahdi_spans() {
+	my %ChansStat = (num=>0, configured=>0, inuse=>0);
+
+	header_line("DAHDI Spans", 'spans');
+	
+	print p('Here we list the ',
+		dfn({-title=> 'A span is a logical unit of dahdi
+			channels. e.g.: all the channels that come from 
+			a specific port, or all the analog channels from 
+			a certain PCI card'},
+			'spans'),
+		' that DAHDI devices registered
+		with DAHDI. For each span we list all of its channels.'
+		),
+		p('A channel that appears in ',
+		span({-class=>'status-noconf'},'red text'),' ',
+		'is one that has not been configured at all. Either not
+		listed in system.conf, or dahdi_cfg was not run.'
+		),
+		p('A channel that appears in ',
+		span({-class=>'status-notused'},'pink text'),' ',
+		'is one that has been configured but is not used by any
+		application. This usually means that either Asterisk is
+		not running or Asterisk is not configured to use this
+		channel'
+		),
+		p('If a port is disconnected it will have a "RED" alarm.
+		For a FXO port this will only be on the specific port.
+		For a BRI, E1 or T1 port it will be an alarm on the apn
+		and all of the channels.'),
+		;
+
+
+
+	foreach my $span (Dahdi::spans()) {
+		my $spanno = $span->num;
+		my $index = 0;
+		
+		print h3(a({-name=>"zap_span_$spanno"}, "Span $spanno: ", 
+			$span->name, " ", $span->description)),
+			start_ul;
+		foreach my $chan ($span->chans()) {
+			my $batt = '';
+			$batt = "(battery)" if $chan->battery;
+			my $type = $chan->type;
+			my $sig = $chan->signalling;
+			my $info = $chan->info;
+			my $chan_stat = 'ok';
+			$ChansStat{num}++;
+			if (!$sig) {
+				$chan_stat = 'noconf';
+			} else {
+				$ChansStat{configured}++;
+				if ($info =~ /\(In use\)/) {
+					$ChansStat{inuse}++; 
+				} else {
+					$chan_stat = 'notused';
+				}
+			}
+			# TODO: color differently if no signalling and
+			# if not in-use and in alarm.
+			print li({-class=>"status-$chan_stat"}, 
+				$chan->num, " $type, $sig $info $batt");
+		}
+		print end_ul;
+	}
+}
+
+sub dahdi_hardware() {
+	header_line("DAHDI Hardware", 'zap_hard');
+
+	print p('Here we list all the DAHDI hardware devices on your 
+		system. If a device is not currently handled by a
+		driver, it will	appear as ',
+		span({-class=>'status-noconf'},'red text'),'.');
+
+	my $hardware = Dahdi::Hardware->scan;
+
+	print start_ul;
+	foreach my $device ($hardware->device_list) {
+		my $driver = $device->driver || "";
+		my $status = 'ok';
+
+		if (! $device->loaded) {
+			$status = 'noconf';
+		}
+
+		print li({-class=>"status-$status"}, 
+			$device->hardware_name, ": ", $driver, 
+			" [".$device->vendor,"/". $device->product. "]	",
+			$device->description);
+	}
+	print end_ul;
+}
+
+sub astribanks() {
+	header_line("Astribanks", 'astribanks');
+
+	print p('Here we list all the Astribank devices (That are
+		handled by the drivers). For each Astribank we list
+		its XPDs. A ',
+		dfn({-title=>
+			'a logical unit of the Astribank. It will '.
+			'be registered in DAHDI as a single span. This	'.
+			'can be either an analog (FXS or FXO) module or	'.
+			'a single port in case of a BRI and PRI modules.'
+			},
+			'XPD'),'. ',
+		' that is registered will have a link to the
+		information about the span below. One that is not
+		registered will appear as ',
+		span({-class=>'status-noconf'},'red text'),'.');
+
+	print start_ul;
+
+	foreach my $xbus (Dahdi::Xpp::xbuses()) {
+		print start_li, 
+		      $xbus->name." (".$xbus->label .", ".$xbus->connector .")",
+		      start_ul;
+		foreach my $xpd ($xbus->xpds) {
+			my $chan_stat = 'ok';
+			my $span_str = 'UNREGISTERED';
+			if ($xpd->spanno) {
+				my $spanno = $xpd->spanno;
+				$span_str =
+				a({-href=>"#zap_span_$spanno"},
+					"Span $spanno");
+			} else {
+				$chan_stat = 'noconf';
+			}
+			print li({-class=>"status-$chan_stat"}, 
+				'[', $xpd->type, '] ', $span_str, $xpd->fqn
+				);
+		}
+		print end_ul, end_li;
+	}
+	print end_ul;
+}
+
+
+dahdi_hardware();
+
+astribanks();
+
+dahdi_spans();
+
+print end_div(); # content
+
+print div({-id=>'toc'},
+	p( a{-href=>'/'},'[Homepage]' ),
+	( map {p( a({-href=> '#'.$_->[1]},$_->[0] ) )}  @Toc ),
+);
diff --git a/xpp/dahdi_drivers b/xpp/dahdi_drivers
new file mode 100755
index 0000000..863d7b1
--- /dev/null
+++ b/xpp/dahdi_drivers
@@ -0,0 +1,23 @@
+#! /usr/bin/perl -w
+use strict;
+use File::Basename;
+BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/perl_modules"); }
+
+use Dahdi::Hardware;
+
+my @drivers = Dahdi::Hardware->drivers;
+print join("\n", @drivers),"\n";
+__END__
+
+=head1 NAME
+
+dahdi_drivers - Show drivers required for installed dahdi devices.
+
+=head1 SYNOPSIS
+
+dahdi_drivers
+
+=head1 DESCRIPTION
+
+This script shows by default the list of drivers required for currently
+installed dahdi devices.
diff --git a/xpp/dahdi_genconf b/xpp/dahdi_genconf
new file mode 100755
index 0000000..49b9325
--- /dev/null
+++ b/xpp/dahdi_genconf
@@ -0,0 +1,196 @@
+#! /usr/bin/perl -w
+#
+# Written by Oron Peled <oron at actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use File::Basename;
+BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/perl_modules"); }
+
+use Getopt::Std;
+use Dahdi;
+use Dahdi::Xpp;
+use Dahdi::Config::Gen;
+use Dahdi::Config::Params;
+
+my $version = '1';	# Functionality version (integer)
+my $revision = '$Revision$';
+
+my %opts;
+
+sub set_defaults {
+	my $default_file = $ENV{GENCONF_PARAMETERS} || "/etc/dahdi/genconf_parameters";
+	my $params = Dahdi::Config::Params->new($default_file);
+	#$params->dump;
+	if($opts{v}) {
+		print "Default parameters from ", $params->{GENCONF_FILE}, "\n";
+	}
+	my $gconfig = Dahdi::Config::Gen->new($params);
+	#$gconfig->dump;
+	return $gconfig;
+}
+
+sub spans_prep($@) {
+	my $gconfig = shift || die;
+	my @spans = @_;
+	foreach my $span (@spans) {
+		if($span->is_pri) {
+			$span->pri_set_fromconfig($gconfig);
+		}
+	}
+}
+
+sub generator_list($) {
+	my $gconfig = shift || die;
+	my @genlist;
+
+	if (@ARGV) {
+		for my $gen (@ARGV) {
+			push @genlist, $gen;
+		}
+	} else {
+		# No files given. Use the defaults.
+		@genlist = ('system', 'chandahdi');
+		if($gconfig->{'pri_connection_type'} eq 'R2') {
+			push @genlist, 'unicall';
+		}
+	}
+	return @genlist;
+}
+
+sub parse_genopts($) {
+	my $optstr = shift;
+	my %genopts;
+
+	$optstr = '' unless defined $optstr;
+	foreach my $o (split(/,/, $optstr)) {
+		my ($k, $v) = split(/=/, $o, 2);
+		$v = 1 unless defined $v and $v;
+		$genopts{$k} = $v;
+	}
+	return %genopts;
+}
+
+sub generate_files($@) {
+	my $gconfig = shift || die;
+	my @spans = @_;
+	my @generators = generator_list($gconfig);
+
+	for my $gen (@generators) {
+		my ($name, $optstr) = split(/=/, $gen, 2);
+		die "Illegal name '$name'\n" unless $name =~ /^\w+$/;
+		$name =~ s/(.)(.*)/\u$1\L$2/;
+		my %genopts = parse_genopts($optstr);
+		$genopts{'freepbx'} = 'yes' if $opts{'F'};
+		if(defined $opts{'v'}) {
+			$genopts{'verbose'} = $opts{v};
+		}
+		$gconfig->run_generator($name, \%genopts, @spans);
+	}
+}
+
+getopts('vVF', \%opts) || die "$0: Bad option\n";
+if($opts{'V'}) {
+	my $revstr = $revision;
+	$revstr =~ s/[^$]*\$[^:]+:\s*//;
+	$revstr =~ s/\s*\$.*//;
+	print "$0: version=$version revision=$revstr\n";
+	exit 0;
+}
+
+my $gconfig = set_defaults;
+my @spans = Dahdi::spans();
+spans_prep($gconfig, @spans);
+generate_files($gconfig, @spans);
+
+__END__
+
+=head1 NAME
+
+dahdi_genconf - Generate configuration for dahdi channels.
+
+=head1 SYNOPSIS
+
+dahdi_genconf [options] [generator...]
+
+=head1 DESCRIPTION
+
+This script generate configuration files for Dahdi hardware.
+It uses two information sources:
+
+=over 4
+
+=item Hardware
+
+ The actual dahdi hardware is automatically detected on the host.
+
+=item /etc/dahdi/genconf_parameters
+
+A configuration file that supplements the hardware information.
+Its location may be overridden via the C<GENCONF_PARAMETERS> environment
+variable.
+
+=back
+
+The dahdi_genconf script can generate various kinds of configuration files
+as specificed by the generator arguments.  Each generator is a perl classes
+in Dahdi::Config::Gen namespace.  The generator names on the command line
+are the class names in lowercase.
+
+The following generators are currently implemented: system, chandahdi, unicall, users.
+For further documentation on each, please user perldoc on the relevant
+class. E.g: C<perldoc Dahdi::Config::Gen::Chandahdi>
+
+Each generator on the command line may be passed custom options by assigning
+a comma separated list of options to the generator name. E.g:
+
+ dahdi_genconf system chandahdi=verbose unicall
+
+=head2 Global options:
+
+=over 4
+
+=item -V
+
+Version -- print version string and exit.
+
+=item -v
+
+Verbose -- sets the C<'verbose'> option for all generators.
+
+=item -F
+
+Freepbx -- sets the C<'freepbx'> option for all generators.
+Currently, chandahdi is affected.
+
+
+=back
+
+=head2 Implementation notes:
+
+=over 4
+
+=item *
+
+F<genconf_parameters> parsing is done via C<Dahdi::Config::Params>.
+An object representing the parsed data is instanciated by:
+C<Dahdi::Config::Params-E<gt>new()>.
+The C<item()> method of this object contains all the hard coded
+defaults of the configuration directives.
+
+=item *
+
+A configuration object is instanciated by C<Dahdi::Config::Gen-E<gt>new($params)>.
+The mapping of configuration directives into semantic configuration is
+done in the constructor.
+
+=item *
+
+A single generator is run via the the C<run_generator()> method of the
+configuration object.
+
+=back
diff --git a/xpp/dahdi_hardware b/xpp/dahdi_hardware
new file mode 100755
index 0000000..867e897
--- /dev/null
+++ b/xpp/dahdi_hardware
@@ -0,0 +1,196 @@
+#! /usr/bin/perl -w
+#
+# Written by Oron Peled <oron at actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use File::Basename;
+use Getopt::Std;
+BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/perl_modules"); }
+
+use Dahdi;
+use Dahdi::Span;
+use Dahdi::Xpp;
+use Dahdi::Xpp::Xbus;
+use Dahdi::Hardware;
+use Dahdi::Xpp::Mpp;
+
+sub usage {
+	die "Usage: $0 [-v][-x][-t]\n";
+}
+
+my %opts;
+getopts('vxt', \%opts) || usage;
+ at ARGV == 0 or usage;
+
+my @spans = Dahdi::spans;
+
+sub show_xbus($) {
+	my $xbus = shift or die;
+	my @xpds = $xbus->xpds;
+	my $label = '[' . $xbus->label() . ']';
+	my $connector = ($xbus->status eq 'CONNECTED') ? $xbus->connector : "MISSING";
+	printf " LABEL=%-20s CONNECTOR=%-20s\n", $label, $connector;
+	foreach my $xpd (@xpds) {
+		my $reg = $xpd->dahdi_registration;
+		my $channels = '(' . $xpd->channels . ')';
+		my $span;
+		my $spanstr;
+		if($reg && @spans) {
+			($span) = grep { $_->name eq $xpd->fqn } @spans;
+			$spanstr = ($span) ? ("Span " . $span->num) : "";
+		} else {
+			$spanstr = "Unregistered";
+		}
+		my $master = '';
+		#$master = "XPP-SYNC" if $xpd->is_sync_master;
+		$master .= " DAHDI-SYNC" if defined($span) && $span->is_dahdi_sync_master;
+		printf "\t%-10s: %-8s %-5s %s %s\n", $xpd->fqn, $xpd->type, $channels, $spanstr, $master;
+	}
+}
+
+my %seen;
+my $format = "%-20s %-12s %4s:%4s %s\n";
+
+sub show_disconnected(%) {
+	my %seen = @_;
+
+	my $notified_lost = 0;
+	foreach my $xbus (Dahdi::Xpp::xbuses) {
+		if(!$seen{$xbus->name}) {
+			print "----------- XPP Spans with disconnected hardware -----------\n"
+				unless $notified_lost++;
+			printf($format, $xbus->name, '', '', '', "NO HARDWARE");
+			show_xbus($xbus) if $opts{'v'};
+		}
+	}
+}
+
+# FIXME: For verbose display we also need to see the XPP devices.
+# If no spans are registered, this won't happen. A brute-force
+# methood for making it happe:
+Dahdi::Xpp::xbuses if ($opts{'v'});
+
+my @devices = Dahdi::Hardware->device_list;
+foreach my $dev (@devices) {
+	my $driver = $dev->driver || "";
+	my $xbus;
+	my $loaded;
+	my $tws_port;
+	my $tws_power;
+	my $tws_watchdog;
+	my $mppinfo;
+	if($dev->is_astribank) {
+		$xbus = $dev->xbus;
+		if($opts{'v'} || $opts{'t'}) {
+			Dahdi::Xpp::Mpp->mpp_addinfo($dev);
+			$mppinfo = $dev->mppinfo;
+			if(defined $mppinfo) {
+				$tws_port = $mppinfo->{TWINSTAR_PORT};
+				$tws_power = $mppinfo->{TWINSTAR_POWER};
+				$tws_watchdog = $mppinfo->{TWINSTAR_WATCHDOG};
+			}
+		}
+	}
+	$loaded = $dev->loaded;
+	warn "driver should be '$driver' but is actually '$loaded'\n"
+		if defined($loaded) && $driver ne $loaded;
+	$driver = "$driver" . (($loaded) ? "+" : "-");
+	if(defined $tws_power && defined $tws_watchdog) {
+		my $tws_active = $tws_watchdog && $tws_power->[0] && $tws_power->[1];
+		$driver .= "[T]" if $tws_active;
+	}
+	my $description = $dev->description || "";
+	printf $format, $dev->hardware_name, $driver, $dev->vendor, $dev->product, $description;
+	if($opts{'v'} && defined $mppinfo && exists $mppinfo->{MPP_TALK}) {
+		printf " MPP: TWINSTAR_PORT=$tws_port\n" if defined $tws_port;
+		printf " MPP: TWINSTAR_WATCHDOG=$tws_watchdog\n" if defined $tws_watchdog;
+		for(my $i = 0; $i < 2; $i++) {
+			printf " MPP: TWINSTAR_POWER[%d]=%d\n",
+				$i, $tws_power->[$i] if defined $tws_power;
+		}
+	}
+	if(!defined $xbus || !$xbus) {
+		next;
+	}
+	$seen{$xbus->name} = 1;
+	show_xbus($xbus) if $opts{'v'};
+}
+
+show_disconnected(%seen) if $opts{'x'};
+
+__END__
+
+=head1 NAME
+
+dahdi_hardware - Shows Dahdi hardware devices. 
+
+=head1 SYNOPSIS
+
+dahdi_hardware [-v][-x]
+
+=head1 OPTIONS
+
+=over
+
+=item -v
+
+Verbose ouput - show spans used by each device etc. Currently only 
+implemented for the Xorcom Astribank.
+
+=item -x
+
+Show disconnected Astribank unit, if any.
+
+=back
+
+=head1 DESCRIPTION
+
+Show all dahdi hardware devices. Devices are recognized according to
+lists of PCI and USB IDs in Dahdi::Hardware::PCI.pm and 
+Dahdi::Hardware::USB.pm . For PCI it is possible to detect by
+sub-vendor and sub-product ID as well.
+
+The first output column is the connector: a bus specific field that
+shows where this device is. 
+
+The second field shows which driver should handle the device. a "-" sign
+marks that the device is not yet handled by this driver. A "+" sign
+means that the device is handled by the driver.
+
+For the Xorcom Astribank (and in the future: for other Dahdi devices)
+some further information is provided from the driver. Those extra lines
+always begin with spaces.
+
+Example output: 
+
+Without drivers loaded:
+
+  usb:001/002        xpp_usb-     e4e4:1152 Astribank-multi FPGA-firmware
+  usb:001/003        xpp_usb-     e4e4:1152 Astribank-multi FPGA-firmware
+  pci:0000:01:0b.0   wctdm-       e159:0001 Wildcard TDM400P REV H
+
+With drivers loaded, without -v:
+  usb:001/002        xpp_usb+     e4e4:1152 Astribank-multi FPGA-firmware
+  usb:001/003        xpp_usb+     e4e4:1152 Astribank-multi FPGA-firmware
+  pci:0000:01:0b.0   wctdm+       e159:0001  Wildcard TDM400P REV E/F
+
+With drivers loaded, with -v:
+  usb:001/002        xpp_usb+     e4e4:1152 Astribank-multi FPGA-firmware
+   LABEL=[usb:123] CONNECTOR=usb-0000:00:1d.7-1  
+          XBUS-00/XPD-00: FXS      Span 2 
+          XBUS-00/XPD-10: FXS      Span 3 
+          XBUS-00/XPD-20: FXS      Span 4 
+          XBUS-00/XPD-30: FXS      Span 5 
+  usb:001/003        xpp_usb+     e4e4:1152 Astribank-multi FPGA-firmware
+   LABEL=[usb:4567] CONNECTOR=usb-0000:00:1d.7-4  
+          XBUS-01/XPD-00: FXS      Span 6 XPP-SYNC
+          XBUS-01/XPD-10: FXO      Span 7 
+          XBUS-01/XPD-20: FXO      Span 8 
+          XBUS-01/XPD-30: FXO      Span 9 
+  pci:0000:01:0b.0   wctdm+       e159:0001  Wildcard TDM400P REV E/F
+
diff --git a/xpp/dahdi_registration b/xpp/dahdi_registration
new file mode 100755
index 0000000..87b89f1
--- /dev/null
+++ b/xpp/dahdi_registration
@@ -0,0 +1,166 @@
+#! /usr/bin/perl -w
+#
+# Written by Oron Peled <oron at actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use File::Basename;
+BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/perl_modules"); }
+
+use Dahdi;
+use Dahdi::Span;
+use Dahdi::Xpp;
+use Dahdi::Xpp::Xbus;
+use Getopt::Std;
+
+sub usage {
+	die "Usage: $0 [-s sort_order] [on|off|1|0]\n";
+}
+
+my %opts;
+getopts('s:', \%opts) || usage;
+
+my $sorter;
+my $sort_order = $opts{'s'};
+if(defined $sort_order) {
+	my $sorter = Dahdi::Xpp::sorters($sort_order);
+
+	if(!defined $sorter) {
+		my @sorter_names = Dahdi::Xpp::sorters;
+		print STDERR "Unknown sort order $sort_order. Select from:\n\t";
+		print STDERR join("\n\t", @sorter_names);
+		print STDERR "\n";
+		exit 1;
+	}
+}
+
+ at ARGV == 0 or @ARGV == 1 or usage;
+my $on = shift;
+my $verbose = 0;
+my $should_output = 1;
+
+if(defined($on)) {	# Translate to booleans
+	$on = uc($on);
+	$on =~ /^(ON|OFF|1|0)$/ or usage;
+	$on = ($on eq 'ON') ? 1 : 0;
+	$should_output = 0 unless $verbose;
+}
+
+sub state2str($) {
+	return (shift)?"on":"off";
+}
+
+sub myprintf {
+	printf @_ if $should_output;
+}
+
+my @spans = Dahdi::spans;
+
+foreach my $xbus (Dahdi::Xpp::xbuses($sorter)) {
+	myprintf "%-10s\t%3s-%s\t%s\n",
+		$xbus->name, $xbus->xpporder, $xbus->label, $xbus->connector;
+	next unless $xbus->status eq 'CONNECTED';
+	foreach my $xpd ($xbus->xpds()) {
+		my $prev = $xpd->dahdi_registration($on);
+		if(!defined($prev)) {			# Failure
+			printf "%s: Failed %s\n", $xpd->fqn, $!;
+			next;
+		}
+		myprintf "\t%-10s: ", $xpd->fqn;
+		if(!defined($on)) {			# Query only
+			my ($span) = grep { $_->name eq $xpd->fqn } @spans;
+			my $spanstr = ($span) ? ("Span " . $span->num) : "";
+			myprintf "%s %s\n", state2str($prev), $spanstr ;
+			next;
+		}
+		myprintf "%3s ==> %3s\n", state2str($prev), state2str($on);
+	}
+}
+myprintf "# Sorted: $sort_order\n" if defined $sort_order;
+
+__END__
+
+=head1 NAME
+
+dahdi_registration - Handle registration of Xorcom XPD modules in dahdi.
+
+=head1 SYNOPSIS
+
+dahdi_registration [-s sortorder] [on|off]
+
+=head1 DESCRIPTION
+
+Without parameters, show all connected XPDs sorted by physical connector order.
+Each one is show to be unregistered (off), or registered to a specific dahdi
+span (the span number is shown).
+
+All registerations/deregisterations are sorted by physical connector string.
+
+Span registration should generally always succeed. Span unregistration may 
+fail if channels from the span are in use by e.g. asterisk. In such a case
+you'll also see those channels as '(In use)' in the output of lsdahdi(8).
+
+=head2 Parameters
+
+off -- deregisters all XPD's from dahdi.
+
+on -- registers all XPD's to dahdi.
+
+=head2 Options
+
+=over
+
+=item -s I<sort_order>
+
+The sort order to use. 
+
+=back
+
+If the option is not used, the sort order is taken from the environment 
+variable XBUS_SORT and failing that: the hard-coded default of 
+SORT_XPPORDER.
+
+The available sorting orders are documented in Dahdi::Xpp manual.
+
+
+
+=head2 Sample Output
+
+An example of the output of dahdi_registration for some registered
+Astribanks:
+
+  $ dahdi_registration -s type
+  XBUS-01         usb:0000153     usb-0000:00:10.4-2
+	  XBUS-01/XPD-00: on Span 1
+	  XBUS-01/XPD-01: on Span 2
+  XBUS-00         usb:0000157     usb-0000:00:10.4-4
+	  XBUS-00/XPD-00: on Span 3
+	  XBUS-00/XPD-01: on Span 4
+	  XBUS-00/XPD-02: on Span 5
+	  XBUS-00/XPD-03: on Span 6
+	  XBUS-00/XPD-04: on Span 7
+	  XBUS-00/XPD-05: on Span 8
+	  XBUS-00/XPD-06: on Span 9
+	  XBUS-00/XPD-07: on Span 10
+  XBUS-02                 usb-0000:00:10.4-1
+	  XBUS-02/XPD-00: on Span 11
+	  XBUS-02/XPD-10: on Span 12
+  # Sorted: type
+
+=head1 FILES
+
+=over
+
+=item /proc/xpp/XBUS-nn/XPD-mm/dahdi_registration
+
+Reading from this file shows if if the if the specific XPD is
+registered. Writing to it 0 or 1 registers / unregisters the device.
+
+This should allow you to register / unregister a specific XPD rather
+than all of them. 
+
+=back
diff --git a/xpp/debug.c b/xpp/debug.c
new file mode 100644
index 0000000..b8d3a70
--- /dev/null
+++ b/xpp/debug.c
@@ -0,0 +1,53 @@
+/*
+ * Written by Oron Peled <oron at actcom.co.il>
+ * Copyright (C) 2008, Xorcom
+ *
+ * All rights reserved.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include "debug.h"
+
+int	verbose = LOG_INFO;
+int	debug_mask = 0;
+
+void log_function(int level, int mask, const char *msg, ...)
+{
+	va_list ap;
+
+	va_start(ap, msg);
+	if(verbose >= level) {
+		if(level < LOG_DEBUG || (mask & debug_mask))
+			vfprintf(stderr, msg, ap);
+	}
+	va_end(ap);
+}
+
+void dump_packet(int loglevel, const char *msg, const char *buf, int len)
+{
+	int	i;
+
+	log_function(loglevel, ~0, "%-15s:", msg);
+	for(i = 0; i < len; i++)
+		log_function(loglevel, ~0, " %02X", (uint8_t)buf[i]);
+	log_function(loglevel, ~0, "\n");
+}
+
diff --git a/xpp/debug.h b/xpp/debug.h
new file mode 100644
index 0000000..185848a
--- /dev/null
+++ b/xpp/debug.h
@@ -0,0 +1,46 @@
+#ifndef	DEBUG_H
+#define	DEBUG_H
+/*
+ * Written by Oron Peled <oron at actcom.co.il>
+ * Copyright (C) 2008, Xorcom
+ *
+ * All rights reserved.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <syslog.h>
+
+/*
+ * Each module should define a unique DBG_MASK
+ */
+
+extern	int	verbose;
+extern	int	debug_mask;
+
+/*
+ * Logging
+ */
+void log_function(int level, int mask, const char *msg, ...) __attribute__(( format(printf, 3, 4) ));
+
+#define	ERR(fmt, arg...) log_function(LOG_ERR, 0, "%s:%d: ERROR(%s): " fmt, __FILE__, __LINE__, __FUNCTION__, ## arg)
+#define	INFO(fmt, arg...) log_function(LOG_INFO, 0, "INFO: " fmt, ## arg)
+#define	DBG(fmt, arg...) log_function(LOG_DEBUG, DBG_MASK,	\
+		"%s:%d: DBG(%s): " fmt, __FILE__, __LINE__, __FUNCTION__, ## arg)
+
+void dump_packet(int loglevel, const char *msg, const char *buf, int len);
+
+#endif	/* DEBUG_H */
diff --git a/xpp/fpga_load.8 b/xpp/fpga_load.8
new file mode 100644
index 0000000..dd21db0
--- /dev/null
+++ b/xpp/fpga_load.8
@@ -0,0 +1,86 @@
+.TH "FPGA_LOAD" "8" "16 April 2006" "" ""
+
+.SH NAME
+fpga_load \- Xorcom Astribank (xpp) firmware tool
+.SH SYNOPSIS
+
+.B fpga_load 
+[\fB-g\fR] [\fB-r\fR] [\fB-v\fR] \fB-D \fR{/proc/bus/usb|/dev/bus/usb}/\fIBUS/DEV\fR 
+
+.B fpga_load 
+[\fB-g\fR] [\fB-v\fR] \fB-D \fR{/proc/bus/usb|/dev/bus/usb}/\fIBUS/DEV\fR \fB-I \fIfirmware.hex\fR [\fB-b \fIdump.bin\fR] [\fB-i\fR]
+
+.B fpga_load -h
+
+.SH DESCRIPTION
+.B fpga_load 
+loads the FPGA firmware to the Xorcom Astribank device.
+The syntax resembles that of fxload(8).
+
+.SH OPTIONS
+.B -b
+.I dump.bin
+.RS
+Before writing firmware, bump the processed binary file to 
+.I dump.bin\fR.
+.RE
+
+.B -D 
+.I DEVICE
+.RS
+Required. The device to read from/write to. On modern UDEV-based system
+this is usually /dev/bus/usb/\fIbus_num\fR/\fIdevice_num\fR,
+where \fIbus_num\fR and \fIdevice_num\fR are the first two numbers in the
+output of lsusb(8).
+On older systems that use usbfs, it is usually
+/proc/bus/usb/\fIbus_num\fR/\fIdevice_num\fR.
+.RE
+
+.B -r
+.RS
+Reset the Astribank and renumerate its USB connection to power on product ID.
+.RE
+
+.B -g
+.RS
+Dump all eeprom data to standard output.
+.RE
+
+.B -I
+.I fireware_file
+.RS
+The firmware file to write to the device.
+.RE
+
+.B -i
+.RS
+Show information about the firmware file (valid only with \fB-I\fR option).
+Example:
+.PP
+	./FPGA_1151.hex: Version=3297 Checksum=58270
+
+In particular, the calculated checksum should match the output of \fIsum(1)\fR
+on the binary firmware file generated by the \fB-b\fR option.
+.RE
+
+.B -v
+.RS
+Increase verbosity. May be used multiple times.
+.RE
+
+.B -h
+.RS
+Displays usage message.
+.RE
+
+.SH SEE ALSO
+fxload(8), lsusb(8)
+
+.SH AUTHOR
+This manual page was written by Tzafrir Cohen <tzafrir.cohen at xorcom.com> .
+Permission is granted to copy, distribute and/or modify this document under
+the terms of the GNU General Public License, Version 2 any 
+later version published by the Free Software Foundation.
+
+On Debian systems, the complete text of the GNU General Public
+License can be found in /usr/share/common-licenses/GPL.
diff --git a/xpp/fpga_load.c b/xpp/fpga_load.c
new file mode 100644
index 0000000..e120b26
--- /dev/null
+++ b/xpp/fpga_load.c
@@ -0,0 +1,1052 @@
+/*
+ * Written by Oron Peled <oron at actcom.co.il>
+ * Copyright (C) 2006-2008, Xorcom
+ *
+ * All rights reserved.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <usb.h>
+#include "hexfile.h"
+
+static const char rcsid[] = "$Id$";
+
+#define	ERR(fmt, arg...) do { \
+				if(verbose >= LOG_ERR) \
+					fprintf(stderr, "%s: ERROR (%d): " fmt, \
+						progname, __LINE__, ## arg); \
+			} while(0);
+#define	INFO(fmt, arg...) do { \
+				if(verbose >= LOG_INFO) \
+					fprintf(stderr, "%s: " fmt, \
+						progname, ## arg); \
+			} while(0);
+#define	DBG(fmt, arg...) do { \
+				if(verbose >= LOG_DEBUG) \
+					fprintf(stderr, "%s: DBG: " fmt, \
+						progname, ## arg); \
+			} while(0);
+
+static int	verbose = LOG_WARNING;
+static char	*progname;
+static int	disconnected = 0;
+
+#define	MAX_HEX_LINES	10000
+#define	PACKET_SIZE	512
+#define	EEPROM_SIZE	16
+#define	LABEL_SIZE	8
+#define	TIMEOUT		5000
+
+
+/* My device parameters */
+#define	MY_EP_OUT	0x04
+#define	MY_EP_IN	0x88
+
+#define	FPGA_EP_OUT	0x02
+#define	FPGA_EP_IN	0x86
+
+/* USB firmware types */
+#define	USB_11xx	0
+#define	USB_FIRMWARE_II	1
+
+#define	TYPE_ENTRY(t,ni,n,ne,out,in,...)	\
+	[t] = {					\
+		.type_code = (t),		\
+		.num_interfaces = (ni),		\
+		.my_interface_num = (n),	\
+		.num_endpoints = (ne),		\
+		.my_ep_in = (in),		\
+		.my_ep_out = (out),		\
+		.name = #t,			\
+		.endpoints = { __VA_ARGS__ },	\
+		}
+
+static const struct astribank_type {
+	int	type_code;
+	int	num_interfaces;
+	int	my_interface_num;
+	int	num_endpoints;
+	int	my_ep_out;
+	int	my_ep_in;
+	char	*name;
+	int	endpoints[4];	/* for matching */
+} astribank_types[] = {
+	TYPE_ENTRY(USB_11xx,		1, 0, 4, MY_EP_OUT, MY_EP_IN,
+		FPGA_EP_OUT,
+		MY_EP_OUT,
+		FPGA_EP_IN,
+		MY_EP_IN),
+	TYPE_ENTRY(USB_FIRMWARE_II,	2, 1, 2, MY_EP_OUT, MY_EP_IN,
+		MY_EP_OUT,
+		MY_EP_IN),
+};
+#undef TYPE_ENTRY
+
+enum fpga_load_packet_types {
+	PT_STATUS_REPLY	= 0x01,
+	PT_DATA_PACKET	= 0x01,
+#ifdef	XORCOM_INTERNAL
+	PT_EEPROM_SET	= 0x04,
+#endif
+	PT_EEPROM_GET	= 0x08,
+	PT_RENUMERATE	= 0x10,
+	PT_RESET	= 0x20,
+	PT_BAD_COMMAND	= 0xAA
+};
+
+struct myeeprom {
+	uint8_t		source;
+	uint16_t	vendor;
+	uint16_t	product;
+	uint8_t		release_major;
+	uint8_t		release_minor;
+	uint8_t		reserved;
+	uint8_t		label[LABEL_SIZE];
+} PACKED;
+
+struct fpga_packet_header {
+	struct {
+		uint8_t		op;
+	} PACKED header;
+	union {
+		struct {
+			uint16_t	seq;
+			uint8_t		status;
+		} PACKED status_reply;
+		struct {
+			uint16_t	seq;
+			uint8_t		reserved;
+			uint8_t		data[ZERO_SIZE];
+		} PACKED data_packet;
+		struct {
+			struct myeeprom		data;
+		} PACKED eeprom_set;
+		struct {
+			struct myeeprom		data;
+		} PACKED eeprom_get;
+	} d;
+} PACKED;
+
+enum fpga_load_status {
+	FW_FAIL_RESET	= 1,
+	FW_FAIL_TRANS	= 2,
+	FW_TRANS_OK	= 4,
+	FW_CONFIG_DONE	= 8
+};
+
+struct my_usb_device {
+	struct usb_device	*dev;
+	usb_dev_handle		*handle;
+	int			my_interface_num;
+	int			my_ep_out;
+	int			my_ep_in;
+	char			iManufacturer[BUFSIZ];
+	char			iProduct[BUFSIZ];
+	char			iSerialNumber[BUFSIZ];
+	char			iInterface[BUFSIZ];
+	int			is_usb2;
+	struct myeeprom		eeprom;
+	const struct astribank_type	*abtype;
+};
+
+const char *load_status2str(enum fpga_load_status s)
+{
+	switch(s) {
+		case FW_FAIL_RESET: return "FW_FAIL_RESET";
+		case FW_FAIL_TRANS: return "FW_FAIL_TRANS";
+		case FW_TRANS_OK: return "FW_TRANS_OK";
+		case FW_CONFIG_DONE: return "FW_CONFIG_DONE";
+		default: return "UNKNOWN";
+	}
+}
+
+/* return 1 if:
+ * - str has a number
+ * - It is larger than 0
+ * - It equals num
+ */
+int num_matches(int num, const char* str) {
+	int str_val = atoi(str);
+	if (str_val <= 0)
+		return 0;
+	return (str_val == num);
+}
+
+struct usb_device *dev_of_path(const char *path)
+{
+	struct usb_bus		*bus;
+	struct usb_device	*dev;
+	char			dirname[PATH_MAX];
+	char			filename[PATH_MAX];
+	const char		*p;
+	int			bnum;
+	int			dnum;
+	int			ret;
+
+	assert(path != NULL);
+	if(access(path, F_OK) < 0) {
+		perror(path);
+		return NULL;
+	}
+	/* Find last '/' */
+	if((p = (const char *)memrchr(path, '/', strlen(path))) == NULL) {
+		ERR("Missing a '/' in %s\n", path);
+		return NULL;
+	}
+	/* Get the device number */
+	ret = sscanf(p + 1, "%d", &dnum);
+	if(ret != 1) {
+		ERR("Path tail is not a device number: '%s'\n", p);
+		return NULL;
+	}
+	/* Search for a '/' before that */
+	p = (const char *)memrchr(path, '/', p - path);
+	if(p == NULL)
+		p = path;		/* Relative path */
+	else
+		p++;			/* skip '/' */
+	/* Get the bus number */
+	ret = sscanf(p, "%d", &bnum);
+	if(ret != 1) {
+		ERR("Path tail is not a bus number: '%s'\n", p);
+		return NULL;
+	}
+	sprintf(dirname, "%03d", bnum);
+	sprintf(filename, "%03d", dnum);
+	for (bus = usb_busses; bus; bus = bus->next) {
+		if (! num_matches(bnum, bus->dirname))
+		//if(strcmp(bus->dirname, dirname) != 0)
+			continue;
+		for (dev = bus->devices; dev; dev = dev->next) {
+			//if(strcmp(dev->filename, filename) == 0)
+			if (num_matches(dnum, dev->filename))
+				return dev;
+		}
+	}
+	ERR("no usb device match '%s'\n", path);
+	return NULL;
+}
+
+int get_usb_string(char *buf, unsigned int len, uint16_t item, usb_dev_handle *handle)
+{
+	char	tmp[BUFSIZ];
+	int	ret;
+
+	if (!item)
+		return 0;
+	ret = usb_get_string_simple(handle, item, tmp, BUFSIZ);
+	if (ret <= 0)
+		return ret;
+	return snprintf(buf, len, "%s", tmp);
+}
+
+void my_usb_device_cleanup(struct my_usb_device *mydev)
+{
+	assert(mydev != NULL);
+	if(!mydev->handle) {
+		return;	/* Nothing to do */
+	}
+	if(!disconnected) {
+		if(usb_release_interface(mydev->handle, mydev->abtype->my_interface_num) != 0) {
+			ERR("Releasing interface: usb: %s\n", usb_strerror());
+		}
+	}
+	if(usb_close(mydev->handle) != 0) {
+		ERR("Closing device: usb: %s\n", usb_strerror());
+	}
+	disconnected = 1;
+	mydev->handle = NULL;
+}
+
+static void show_device_info(const struct my_usb_device *mydev)
+{
+	const struct myeeprom	*eeprom;
+	uint8_t		data[LABEL_SIZE + 1];
+
+	assert(mydev != NULL);
+	eeprom = &mydev->eeprom;
+	memset(data, 0, LABEL_SIZE + 1);
+	memcpy(data, eeprom->label, LABEL_SIZE);
+	printf("USB    Firmware Type: [%s]\n", mydev->abtype->name);
+	printf("USB    iManufacturer: [%s]\n", mydev->iManufacturer);
+	printf("USB    iProduct:      [%s]\n", mydev->iProduct);
+	printf("USB    iSerialNumber: [%s]\n", mydev->iSerialNumber);
+	printf("EEPROM Source:        0x%02X\n", eeprom->source);
+	printf("EEPROM Vendor:        0x%04X\n", eeprom->vendor);
+	printf("EEPROM Product:       0x%04X\n", eeprom->product);
+	printf("EEPROM Release:       %d.%03d\n", eeprom->release_major, eeprom->release_minor);
+	printf("EEPROM Label:        HEX(%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X) [%s]\n",
+			data[0], data[1], data[2], data[3],
+			data[4], data[5], data[6], data[7], data); 
+}
+
+void dump_packet(const char *msg, const char *buf, int len)
+{
+	int	i;
+
+	for(i = 0; i < len; i++)
+		INFO("%s: %2d> 0x%02X\n", msg, i, (uint8_t)buf[i]);
+}
+
+int send_usb(const char *msg, struct my_usb_device *mydev, struct fpga_packet_header *phead, int len, int timeout)
+{
+	char	*p = (char *)phead;
+	int	ret;
+
+	if(verbose >= LOG_DEBUG)
+		dump_packet(msg, p, len);
+	if(mydev->my_ep_out & USB_ENDPOINT_IN) {
+		ERR("send_usb called with an input endpoint 0x%x\n", mydev->my_ep_out);
+		return -EINVAL;
+	}
+	ret = usb_bulk_write(mydev->handle, mydev->my_ep_out, p, len, timeout);
+	if(ret < 0) {
+		/*
+		 * If the device was gone, it may be the
+		 * result of renumeration. Ignore it.
+		 */
+		if(ret != -ENODEV) {
+			ERR("bulk_write to endpoint 0x%x failed: %s\n", mydev->my_ep_out, usb_strerror());
+			dump_packet("send_usb[ERR]", p, len);
+		} else {
+			disconnected = 1;
+			my_usb_device_cleanup(mydev);
+		}
+		return ret;
+	} else if(ret != len) {
+		ERR("bulk_write to endpoint 0x%x short write: %s\n", mydev->my_ep_out, usb_strerror());
+		dump_packet("send_usb[ERR]", p, len);
+		return -EFAULT;
+	}
+	return ret;
+}
+
+int recv_usb(const char *msg, struct my_usb_device *mydev, char *buf, size_t len, int timeout)
+{
+	int	ret;
+
+	if(mydev->my_ep_in & USB_ENDPOINT_OUT) {
+		ERR("recv_usb called with an output endpoint 0x%x\n", mydev->my_ep_in);
+		return -EINVAL;
+	}
+	ret = usb_bulk_read(mydev->handle, mydev->my_ep_in, buf, len, timeout);
+	if(ret < 0) {
+		ERR("bulk_read from endpoint 0x%x failed: %s\n", mydev->my_ep_in, usb_strerror());
+		return ret;
+	}
+	if(verbose >= LOG_DEBUG)
+		dump_packet(msg, buf, ret);
+	return ret;
+}
+
+int flush_read(struct my_usb_device *mydev)
+{
+	char		tmpbuf[BUFSIZ];
+	int		ret;
+
+	memset(tmpbuf, 0, BUFSIZ);
+	ret = recv_usb("flush_read", mydev, tmpbuf, sizeof(tmpbuf), TIMEOUT);
+	if(ret < 0 && ret != -ETIMEDOUT) {
+		ERR("ret=%d\n", ret);
+		return ret;
+	} else if(ret > 0) {
+		DBG("Got %d bytes:\n", ret);
+		dump_packet(__FUNCTION__, tmpbuf, ret);
+	}
+	return 0;
+}
+
+#ifdef	XORCOM_INTERNAL
+int eeprom_set(struct my_usb_device *mydev, const struct myeeprom *eeprom)
+{
+	int				ret;
+	int				len;
+	char				buf[PACKET_SIZE];
+	struct fpga_packet_header	*phead = (struct fpga_packet_header *)buf;
+
+	DBG("%s Start...\n", __FUNCTION__);
+	assert(mydev != NULL);
+	phead->header.op = PT_EEPROM_SET;
+	memcpy(&phead->d.eeprom_set.data, eeprom, EEPROM_SIZE);
+	len = sizeof(phead->d.eeprom_set) + sizeof(phead->header.op);
+	ret = send_usb("eeprom_set[W]", mydev, phead, len, TIMEOUT);
+	if(ret < 0)
+		return ret;
+	ret = recv_usb("eeprom_set[R]", mydev, buf, sizeof(buf), TIMEOUT);
+	if(ret <= 0)
+		return ret;
+	phead = (struct fpga_packet_header *)buf;
+	if(phead->header.op == PT_BAD_COMMAND) {
+		ERR("Firmware rejected PT_EEPROM_SET command\n");
+		return -EINVAL;
+	} else if(phead->header.op != PT_EEPROM_SET) {
+		ERR("Got unexpected reply op=%d\n", phead->header.op);
+		return -EINVAL;
+	}
+	return 0;
+}
+#endif
+
+int eeprom_get(struct my_usb_device *mydev)
+{
+	int				ret;
+	int				len;
+	char				buf[PACKET_SIZE];
+	struct fpga_packet_header	*phead = (struct fpga_packet_header *)buf;
+	struct myeeprom			*eeprom;
+
+	assert(mydev != NULL);
+	eeprom = &mydev->eeprom;
+	DBG("%s Start...\n", __FUNCTION__);
+	phead->header.op = PT_EEPROM_GET;
+	len = sizeof(phead->header.op);		/* warning: sending small packet */
+	ret = send_usb("eeprom_get[W]", mydev, phead, len, TIMEOUT);
+	if(ret < 0)
+		return ret;
+	ret = recv_usb("eeprom_get[R]", mydev, buf, sizeof(buf), TIMEOUT);
+	if(ret <= 0)
+		return ret;
+	phead = (struct fpga_packet_header *)buf;
+	if(phead->header.op == PT_BAD_COMMAND) {
+		ERR("PT_BAD_COMMAND\n");
+		return -EINVAL;
+	} else if(phead->header.op != PT_EEPROM_GET) {
+		ERR("Got unexpected reply op=%d\n", phead->header.op);
+		return -EINVAL;
+	}
+	memcpy(eeprom, &phead->d.eeprom_get.data, EEPROM_SIZE);
+	return 0;
+}
+
+int send_hexline(struct my_usb_device *mydev, struct hexline *hexline, int seq)
+{
+	int				ret;
+	int				len;
+	uint8_t				*data;
+	char				buf[PACKET_SIZE];
+	struct fpga_packet_header	*phead = (struct fpga_packet_header *)buf;
+	enum fpga_load_status		status;
+
+	assert(mydev != NULL);
+	assert(hexline != NULL);
+	if(hexline->d.content.header.tt != TT_DATA) {
+		DBG("Non data record %d type = %d\n", seq, hexline->d.content.header.tt);
+		return 0;
+	}
+	len = hexline->d.content.header.ll;	/* don't send checksum */
+	data = hexline->d.content.tt_data.data;
+	phead->header.op = PT_DATA_PACKET;
+	phead->d.data_packet.seq = seq;
+	phead->d.data_packet.reserved = 0x00;
+	memcpy(phead->d.data_packet.data, data, len);
+	len += sizeof(hexline->d.content.header);
+	DBG("%04d+\r", seq);
+	ret = send_usb("hexline[W]", mydev, phead, len, TIMEOUT);
+	if(ret < 0)
+		return ret;
+	ret = recv_usb("hexline[R]", mydev, buf, sizeof(buf), TIMEOUT);
+	if(ret <= 0)
+		return ret;
+	DBG("%04d-\r", seq);
+	phead = (struct fpga_packet_header *)buf;
+	if(phead->header.op != PT_STATUS_REPLY) {
+		ERR("Got unexpected reply op=%d\n", phead->header.op);
+		dump_packet("hexline[ERR]", buf, ret);
+		return -EINVAL;
+	}
+	status = (enum fpga_load_status)phead->d.status_reply.status;
+	switch(status) {
+		case FW_TRANS_OK:
+		case FW_CONFIG_DONE:
+			break;
+		case FW_FAIL_RESET:
+		case FW_FAIL_TRANS:
+			ERR("status reply %s (%d)\n", load_status2str(status), status);
+			dump_packet("hexline[ERR]", buf, ret);
+			return -EPROTO;
+		default:
+			ERR("Unknown status reply %d\n", status);
+			dump_packet("hexline[ERR]", buf, ret);
+			return -EPROTO;
+	}
+	return 0;
+}
+
+//. returns > 0 - ok, the number of lines sent
+//. returns < 0 - error number
+int send_splited_hexline(struct my_usb_device *mydev, struct hexline *hexline, int seq, uint8_t maxwidth)
+{
+	struct hexline *extraline;
+	int linessent = 0;
+	int allocsize;
+	int extra_offset = 0;
+	unsigned int this_line = 0;
+	uint8_t bytesleft = 0;
+	
+	assert(mydev != NULL);
+	if(!hexline) {
+		ERR("Bad record %d type = %d\n", seq, hexline->d.content.header.tt);
+		return -EINVAL;
+	}
+	bytesleft = hexline->d.content.header.ll;
+	// split the line into several lines
+	while (bytesleft > 0) {
+		int status;
+		this_line = (bytesleft >= maxwidth) ? maxwidth : bytesleft;
+		allocsize = sizeof(struct hexline) + this_line + 1;
+		// generate the new line
+		if((extraline = (struct hexline *)malloc(allocsize)) == NULL) {
+			ERR("Not enough memory for spliting the lines\n" );
+			return -EINVAL;
+		}
+		memset(extraline, 0, allocsize);
+		extraline->d.content.header.ll		= this_line;
+		extraline->d.content.header.offset	= hexline->d.content.header.offset + extra_offset;
+		extraline->d.content.header.tt		= hexline->d.content.header.tt;
+		memcpy( extraline->d.content.tt_data.data, hexline->d.content.tt_data.data+extra_offset, this_line);
+		status = send_hexline(mydev, extraline, seq+linessent );
+		// cleanups
+		free(extraline);
+		extra_offset += this_line;
+		bytesleft -= this_line;
+		if (status)
+			return status;
+		linessent++;
+	}
+	return linessent;
+}
+
+int match_usb_device_identity(const struct usb_config_descriptor *config_desc,
+	const struct astribank_type *ab)
+{
+	struct usb_interface		*interface;
+	struct usb_interface_descriptor	*iface_desc;
+
+	if(config_desc->bNumInterfaces <= ab->my_interface_num)
+		return 0;
+	interface = &config_desc->interface[ab->my_interface_num];
+	iface_desc = interface->altsetting;
+	
+	return	iface_desc->bInterfaceClass == 0xFF &&
+		iface_desc->bInterfaceNumber == ab->my_interface_num &&
+		iface_desc->bNumEndpoints == ab->num_endpoints;
+}
+
+const struct astribank_type *my_usb_device_identify(const char devpath[], struct my_usb_device *mydev)
+{
+	struct usb_device_descriptor	*dev_desc;
+	struct usb_config_descriptor	*config_desc;
+	int				i;
+
+	assert(mydev != NULL);
+	usb_init();
+	usb_find_busses();
+	usb_find_devices();
+	mydev->dev = dev_of_path(devpath);
+	if(!mydev->dev) {
+		ERR("Bailing out\n");
+		return 0;
+	}
+	dev_desc = &mydev->dev->descriptor;
+	config_desc = mydev->dev->config;
+	for(i = 0; i < sizeof(astribank_types)/sizeof(astribank_types[0]); i++) {
+		if(match_usb_device_identity(config_desc, &astribank_types[i])) {
+			DBG("Identified[%d]: interfaces=%d endpoints=%d: \"%s\"\n",
+				i,
+				astribank_types[i].num_interfaces,
+				astribank_types[i].num_endpoints,
+				astribank_types[i].name);
+			return &astribank_types[i];
+		}
+	}
+	return NULL;
+}
+
+int my_usb_device_init(const char devpath[], struct my_usb_device *mydev, const struct astribank_type *abtype)
+{
+	struct usb_device_descriptor	*dev_desc;
+	struct usb_config_descriptor	*config_desc;
+	struct usb_interface		*interface;
+	struct usb_interface_descriptor	*iface_desc;
+	struct usb_endpoint_descriptor	*endpoint;
+	int				ret;
+	int				i;
+
+	assert(mydev != NULL);
+	usb_init();
+	usb_find_busses();
+	usb_find_devices();
+	mydev->dev = dev_of_path(devpath);
+	if(!mydev->dev) {
+		ERR("Bailing out\n");
+		return 0;
+	}
+	mydev->handle = usb_open(mydev->dev);
+	if(!mydev->handle) {
+		ERR("Failed to open usb device '%s/%s': %s\n", mydev->dev->bus->dirname, mydev->dev->filename, usb_strerror());
+		return 0;
+	}
+	if(usb_claim_interface(mydev->handle, abtype->my_interface_num) != 0) {
+		ERR("usb_claim_interface: %s\n", usb_strerror());
+		return 0;
+	}
+	dev_desc = &mydev->dev->descriptor;
+	config_desc = mydev->dev->config;
+	if (!config_desc) {
+		ERR("usb interface without a configuration\n");
+		return 0;
+	}
+	interface = &config_desc->interface[abtype->my_interface_num];
+	iface_desc = interface->altsetting;
+	endpoint = iface_desc->endpoint;
+	mydev->is_usb2 = (endpoint->wMaxPacketSize == 512);
+	for(i = 0; i < iface_desc->bNumEndpoints; i++, endpoint++) {
+		if(endpoint->bEndpointAddress != abtype->endpoints[i]) {
+			ERR("Wrong endpoint 0x%X (at index %d)\n", endpoint->bEndpointAddress, i);
+			return 0;
+		}
+		if(endpoint->bEndpointAddress == MY_EP_OUT || endpoint->bEndpointAddress == MY_EP_IN) {
+			if(endpoint->wMaxPacketSize > PACKET_SIZE) {
+				ERR("Endpoint #%d wMaxPacketSize too large (%d)\n", i, endpoint->wMaxPacketSize);
+				return 0;
+			}
+		}
+	}
+	mydev->abtype = abtype;
+	mydev->my_ep_in = abtype->my_ep_in;
+	mydev->my_ep_out = abtype->my_ep_out;
+	ret = get_usb_string(mydev->iManufacturer, BUFSIZ, dev_desc->iManufacturer, mydev->handle);
+	ret = get_usb_string(mydev->iProduct, BUFSIZ, dev_desc->iProduct, mydev->handle);
+	ret = get_usb_string(mydev->iSerialNumber, BUFSIZ, dev_desc->iSerialNumber, mydev->handle);
+	ret = get_usb_string(mydev->iInterface, BUFSIZ, iface_desc->iInterface, mydev->handle);
+	INFO("ID=%04X:%04X Manufacturer=[%s] Product=[%s] SerialNumber=[%s] Interface=[%s]\n",
+		dev_desc->idVendor,
+		dev_desc->idProduct,
+		mydev->iManufacturer,
+		mydev->iProduct,
+		mydev->iSerialNumber,
+		mydev->iInterface);
+	if(usb_clear_halt(mydev->handle, mydev->my_ep_out) != 0) {
+		ERR("Clearing output endpoint: %s\n", usb_strerror());
+		return 0;
+	}
+	if(usb_clear_halt(mydev->handle, mydev->my_ep_in) != 0) {
+		ERR("Clearing input endpoint: %s\n", usb_strerror());
+		return 0;
+	}
+	if(flush_read(mydev) < 0) {
+		ERR("flush_read failed\n");
+		return 0;
+	}
+	return 1;
+}
+
+int renumerate_device(struct my_usb_device *mydev, enum fpga_load_packet_types pt)
+{
+	char				buf[PACKET_SIZE];
+	struct fpga_packet_header	*phead = (struct fpga_packet_header *)buf;
+	int				ret;
+
+	assert(mydev != NULL);
+	DBG("Renumerating with 0x%X\n", pt);
+	phead->header.op = pt;
+	ret = send_usb("renumerate[W]", mydev, phead, 1, TIMEOUT);
+	if(ret < 0 && ret != -ENODEV)
+			return ret;
+#if 0
+	/*
+	 * FIXME: we count on our USB firmware to reset the device... should we?
+	 */
+	ret = usb_reset(mydev->handle);
+	if(ret < 0) {
+		ERR("usb_reset: %s\n", usb_strerror());
+		return -ENODEV;
+	}
+#endif
+	return 0;
+}
+
+/*
+ * Returns: true on success, false on failure
+ */
+int fpga_load(struct my_usb_device *mydev, const struct hexdata *hexdata)
+{
+	unsigned int	i;
+	unsigned int	j = 0;
+	int		ret;
+	int		finished = 0;
+	const char	*v = hexdata->version_info;
+	
+	v = (v[0]) ? v : "Unknown";
+	assert(mydev != NULL);
+	INFO("FPGA_LOAD (version %s)\n", v);
+	/*
+	 * i - is the line number
+	 * j - is the sequence number, on USB 2, i=j, but on
+	 *     USB 1 send_splited_hexline may increase the sequence
+	 *     number, as it needs 
+	 */
+	for(i = 0; i < hexdata->maxlines; i++) {
+		struct hexline	*hexline = hexdata->lines[i];
+
+		if(!hexline)
+			break;
+		if(finished) {
+			ERR("Extra data after End Of Data Record (line %d)\n", i);
+			return 0;
+		}
+		if(hexline->d.content.header.tt == TT_EOF) {
+			DBG("End of data\n");
+			finished = 1;
+			continue;
+		}
+		if(mydev->is_usb2) {
+			if((ret = send_hexline(mydev, hexline, i)) != 0) {
+				perror("Failed sending hexline");
+				return 0;
+			}
+		} else {
+			if((ret = send_splited_hexline(mydev, hexline, j, 60)) < 0) {
+				perror("Failed sending hexline (splitting did not help)");
+				return 0;
+			}
+			j += ret;
+		}
+	}
+	DBG("Finished...\n");
+	return 1;
+}
+
+#include <getopt.h>
+
+void usage()
+{
+	fprintf(stderr, "Usage: %s -D {/proc/bus/usb|/dev/bus/usb}/<bus>/<dev> [options...]\n", progname);
+	fprintf(stderr, "\tOptions:\n");
+	fprintf(stderr, "\t\t[-r]		# Reset the device\n");
+	fprintf(stderr, "\t\t[-b <binfile>]	# Output to <binfile>\n");
+	fprintf(stderr, "\t\t[-I <hexfile>]	# Input from <hexfile>\n");
+	fprintf(stderr, "\t\t[-H <hexfile>]	# Output to <hexfile> ('-' is stdout)\n");
+	fprintf(stderr, "\t\t[-i]		# Show hexfile information\n");
+	fprintf(stderr, "\t\t[-g]		# Get eeprom from device\n");
+	fprintf(stderr, "\t\t[-v]		# Increase verbosity\n");
+#ifdef XORCOM_INTERNAL
+	fprintf(stderr, "\t\t[-C srC byte]	# Set Address sourCe (default: C0)\n");
+	fprintf(stderr, "\t\t[-V vendorid]	# Set Vendor id on device\n");
+	fprintf(stderr, "\t\t[-P productid]	# Set Product id on device\n");
+	fprintf(stderr, "\t\t[-R release]	# Set Release. 2 dot separated decimals\n");
+	fprintf(stderr, "\t\t[-L label]		# Set label.\n");
+#endif
+	exit(1);
+}
+
+static void parse_report_func(int level, const char *msg, ...)
+{
+	va_list ap;
+
+	va_start(ap, msg);
+	if(level <= verbose)
+		vfprintf(stderr, msg, ap);
+	va_end(ap);
+}
+
+#ifdef	XORCOM_INTERNAL
+static void eeprom_fill(struct myeeprom *myeeprom,
+	const char vendor[],
+	const char product[],
+	const char release[],
+	const char label[],
+	const char source[])
+{
+	// FF: address source is from device. C0: from eeprom
+	if (source)
+		myeeprom->source = strtoul(source, NULL, 0);
+	else
+		myeeprom->source = 0xC0;
+	if(vendor)
+		myeeprom->vendor = strtoul(vendor, NULL, 0);
+	if(product)
+		myeeprom->product = strtoul(product, NULL, 0);
+	if(release) {
+		int	release_major = 0;
+		int	release_minor = 0;
+
+		sscanf(release, "%d.%d", &release_major, &release_minor);
+		myeeprom->release_major = release_major;
+		myeeprom->release_minor = release_minor;
+	}
+	if(label) {
+		/* padding */
+		memset(myeeprom->label, 0, LABEL_SIZE);
+		memcpy(myeeprom->label, label, strlen(label));
+	}
+}
+#endif
+
+int main(int argc, char *argv[])
+{
+	const struct astribank_type	*abtype;
+	struct my_usb_device	mydev;
+	const char		*devpath = NULL;
+	const char		*binfile = NULL;
+	const char		*inhexfile = NULL;
+	const char		*outhexfile = NULL;
+	struct hexdata		*hexdata = NULL;
+	int			opt_reset = 0;
+	int			opt_info = 0;
+	int			opt_read_eeprom = 0;
+	int			opt_output_width = 0;
+	int			output_is_set = 0;
+#ifdef	XORCOM_INTERNAL
+	int			opt_write_eeprom = 0;
+	char			*vendor = NULL;
+	char			*source = NULL;
+	char			*product = NULL;
+	char			*release = NULL;
+	char			*label = NULL;
+	const char		options[] = "rib:D:ghH:I:vw:C:V:P:R:S:";
+#else
+	const char		options[] = "rib:D:ghH:I:vw:";
+#endif
+	int			ret = 0;
+
+	progname = argv[0];
+	assert(sizeof(struct fpga_packet_header) <= PACKET_SIZE);
+	assert(sizeof(struct myeeprom) == EEPROM_SIZE);
+	while (1) {
+		int	c;
+
+		c = getopt (argc, argv, options);
+		if (c == -1)
+			break;
+
+		switch (c) {
+			case 'D':
+				devpath = optarg;
+				if(output_is_set++) {
+					ERR("Cannot set -D. Another output option is already selected\n");
+					return 1;
+				}
+				break;
+			case 'r':
+				opt_reset = 1;
+				break;
+			case 'i':
+				opt_info = 1;
+				break;
+			case 'b':
+				binfile = optarg;
+				if(output_is_set++) {
+					ERR("Cannot set -b. Another output option is already selected\n");
+					return 1;
+				}
+				break;
+			case 'g':
+				opt_read_eeprom = 1;
+				break;
+			case 'H':
+				outhexfile = optarg;
+				if(output_is_set++) {
+					ERR("Cannot set -H. Another output option is already selected\n");
+					return 1;
+				}
+				break;
+			case 'I':
+				inhexfile = optarg;
+				break;
+#ifdef	XORCOM_INTERNAL
+			case 'V':
+				vendor = optarg;
+				break;
+			case 'C':
+				source = optarg;
+				break;
+			case 'P':
+				product = optarg;
+				break;
+			case 'R':
+				release = optarg;
+				break;
+			case 'S':
+				label = optarg;
+				{
+					const char	GOOD_CHARS[] =
+						"abcdefghijklmnopqrstuvwxyz"
+						"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+						"0123456789"
+						"-_.";
+					int	len = strlen(label);
+					int	goodlen = strspn(label, GOOD_CHARS);
+
+					if(len > LABEL_SIZE) {
+						ERR("Label too long (%d > %d)\n", len, LABEL_SIZE);
+						usage();
+					}
+					if(goodlen != len) {
+						ERR("Bad character in label number (pos=%d)\n", goodlen);
+						usage();
+					}
+				}
+				break;
+#endif
+			case 'w':
+				opt_output_width = strtoul(optarg, NULL, 0);
+				break;
+			case 'v':
+				verbose++;
+				break;
+			case 'h':
+			default:
+				ERR("Unknown option '%c'\n", c);
+				usage();
+		}
+	}
+
+	if (optind != argc) {
+		usage();
+	}
+	if(inhexfile) {
+#ifdef	XORCOM_INTERNAL
+		if(vendor || product || release || label || source ) {
+			ERR("The -I option is exclusive of -[VPRSC]\n");
+			return 1;
+		}
+#endif
+		parse_hexfile_set_reporting(parse_report_func);
+		hexdata = parse_hexfile(inhexfile, MAX_HEX_LINES);
+		if(!hexdata) {
+			ERR("Bailing out\n");
+			exit(1);
+		}
+		if(opt_info) {
+			printf("%s: Version=%s Checksum=%d\n",
+					inhexfile, hexdata->version_info,
+					bsd_checksum(hexdata));
+		}
+		if(binfile) {
+			dump_binary(hexdata, binfile);
+			return 0;
+		}
+		if(outhexfile) {
+			if(opt_output_width)
+				dump_hexfile2(hexdata, outhexfile, opt_output_width);
+			else
+				dump_hexfile(hexdata, outhexfile);
+			return 0;
+		}
+	}
+#ifdef	XORCOM_INTERNAL
+	else if(vendor || product || release || label || source ) {
+		if(outhexfile) {
+			FILE	*fp;
+
+			if(strcmp(outhexfile, "-") == 0)
+				fp = stdout;
+			else if((fp = fopen(outhexfile, "w")) == NULL) {
+				perror(outhexfile);
+				return 1;
+			}
+			memset(&mydev.eeprom, 0, sizeof(struct myeeprom));
+			eeprom_fill(&mydev.eeprom, vendor, product, release, label, source);
+			gen_hexline((uint8_t *)&mydev.eeprom, 0, sizeof(mydev.eeprom), fp);
+			gen_hexline(NULL, 0, 0, fp);	/* EOF */
+			return 0;
+		}
+	}
+#endif
+	if(!devpath) {
+		ERR("Missing device path\n");
+		usage();
+	}
+	DBG("Startup %s\n", devpath);
+	if((abtype = my_usb_device_identify(devpath, &mydev)) == NULL) {
+		ERR("Bad device. Does not match our types.\n");
+		usage();
+	}
+	INFO("FIRMWARE: %s (type=%d)\n", abtype->name, abtype->type_code);
+	if(!my_usb_device_init(devpath, &mydev, abtype)) {
+		ERR("Failed to initialize USB device '%s'\n", devpath);
+		ret = -ENODEV;
+		goto dev_err;
+	}
+	ret = eeprom_get(&mydev);
+	if(ret < 0) {
+		ERR("Failed reading eeprom\n");
+		goto dev_err;
+	}
+#ifdef	XORCOM_INTERNAL
+	if(vendor || product || release || label || source ) {
+		eeprom_fill(&mydev.eeprom, vendor, product, release, label, source);
+		opt_write_eeprom = 1;
+		opt_read_eeprom = 1;
+	}
+#endif
+	if(opt_read_eeprom) {
+		show_device_info(&mydev);
+	}
+	if(hexdata) {
+		if (!mydev.is_usb2)
+			INFO("Warning: working on a low end USB1 backend\n");
+		if(!fpga_load(&mydev, hexdata)) {
+			ERR("FPGA loading failed\n");
+			ret = -ENODEV;
+			goto dev_err;
+		}
+		ret = renumerate_device(&mydev, PT_RENUMERATE);
+		if(ret < 0) {
+			ERR("Renumeration failed: errno=%d\n", ret);
+			goto dev_err;
+		}
+	}
+#ifdef XORCOM_INTERNAL
+	else if(opt_write_eeprom) {
+		if(abtype->type_code == USB_FIRMWARE_II) {
+			ERR("No EEPROM burning command in %s. Use fxload for that\n",
+				abtype->name);
+			goto dev_err;
+		}
+		ret = eeprom_set(&mydev, &mydev.eeprom);
+		if(ret < 0) {
+			ERR("Failed writing eeprom: %s\n", strerror(-ret));
+			goto dev_err;
+		}
+		printf("------- RESULTS -------\n");
+		show_device_info(&mydev);
+	}
+#endif
+	if(opt_reset) {
+		DBG("Reseting to default\n");
+		ret = renumerate_device(&mydev, PT_RESET);
+		if(ret < 0) {
+			ERR("Renumeration to default failed: errno=%d\n", ret);
+			goto dev_err;
+		}
+	}
+	DBG("Exiting\n");
+dev_err:
+	my_usb_device_cleanup(&mydev);
+	return ret;
+}
diff --git a/xpp/genconf_parameters b/xpp/genconf_parameters
new file mode 100644
index 0000000..c27f960
--- /dev/null
+++ b/xpp/genconf_parameters
@@ -0,0 +1,169 @@
+#
+# /etc/dahdi/genconf_parameters
+#
+# This file contains parameters that affect the
+# dahdi_genconf configuration generator.
+#
+# Syntax:
+# 	* A comment from '#' to end of line
+# 	* Blank lines ignored
+# 	* Whitespace at end of line trimmed
+# 	* Single valued items:
+# 	     key <whitespace...> value
+# 	* List valued items:
+# 	     key
+# 	     <whitespace...>value1
+# 	     <whitespace...>value2
+# 	     ...
+#
+
+# When generating extensions for chan_dahdi.conf or users.conf etc: the 
+# extension number will be channel_number+base_exten . The default is:
+#base_exten		4000
+#
+# Make FXS (analog phones) extensions answer immediately (sets
+# 'immediate = yes' for them in chan_dahdi.conf). Don't enable this before 
+# you're read documentation about this option.
+#fxs_immediate		yes
+#
+# For FXS (analog phones) - use KS or LS? ks is the only method for
+# Asterisk to provide disconnect supervision and thus it would normally
+# be preferred and is the default.
+#fxs_default_start	ls
+#
+# For FXO (analog lines) - use KS or LS? KS is the default and is
+# normally the better choice as it allows detecting hang-ups on many
+# lines.
+#fxo_default_start	ls
+
+# Set tone zone values. This is used for playing tones (busy, dial-tone
+# and such). The default is 'us'. This sets the value for both loadzone
+# and defaultzone in system.conf .
+#lc_country		il
+
+# The dialplan context into which to send trunks in chan_dahdi.conf or
+# users.conf. The default value is:
+#context_lines		from-pstn
+#
+# The dialplan context into which to send extensions in chan_dahdi.conf or
+# users.conf. The default value is:
+#context_phones		from-internal
+#
+# Two extra contexts for the input ports and output ports of an
+# Astribank. Default values are:
+#context_input		astbank-input
+#context_output		astbank-output
+
+# A group to put all analog phones in. By default 0, so you can dial to
+# the 'first phone available' using Dahdi/g5 .
+#group_phones		5
+#
+# A group in which to put all the channels belonging to some trunk.
+# Thus you can dial through "some trunk" using Dahdi/G0/NUMBER
+#group_lines		0
+
+# Channels of digital trunk of span N are also added to group 10+N (that 
+# is: 14 for channels of span 4).
+
+# Do we want to use PtP ('bri') or PtMP ('bri_ptmp') for BRI? PtMP 
+# allows connecting several CPE devices on the same network device 
+# (several BRI phones on the same line, kind of like several analog 
+# phones on the same analog line). However it is generally brings 
+# unnecessary complexity for a pbx-pbx connection. It is still the 
+# default as this is normally what you get for a BRI PSTN connection.
+#bri_sig_style		bri
+#
+# If this option is set (that is: not remmed-out), BRI NT ports will 
+# also be set as overlap. This is useful if you want to connect ISDN 
+# phones.
+#brint_overlap
+
+# The echo canceler to use. If you have a hardware echo canceler, just 
+# leave it be, as this one won't be used anyway.
+#
+# The default is mg2, but it may change in the future. E.g: a packager
+# that bundles a better echo canceler may set it as the default, or
+# dahdi_genconf will scan for the "best" echo canceler.
+#
+#echo_can		hpec
+#echo_can		oslec
+#echo_can		none  # to avoid echo canceler altogether
+
+# bri_hardhdlc:
+#   'yes'  - forces BRI cards to use 'hardhdlc' signalling.
+#   'no'   - forces BRI cards to use 'dchan' (an alias for 'fcshdlc').
+#            It is usefull only for dahdi with the bristuff patch.
+#
+# If it is left out or set to 'auto':
+#   * Information supplied by the driver is used to decide:
+#     - Currently implemented for Astribanks.
+#     - Taken from /sys/bus/xpds/drivers/bri/dchan_hardhdlc.
+#   * Without this info, falls back to 'hardhdlc'.
+#bri_hardhdlc		auto
+
+# For MFC/R2 Support: 'R2' will make E1 spans CAS and with the
+# 'r2_idle_bits' bit in system.conf . It will also make dahdi_genconf default
+# to generating the channels of this card in unicall.conf rather than in
+# chan_dahdi.conf . The meaning of this may be extended somehow to support
+# R2 through openr2/chan_dahdi later on.
+#pri_connection_type	R2
+#pri_connection_type	CAS
+#
+# Explicitly set the idle bits for E1 CAS (Sample value is the default):
+#r2_idle_bits		1101
+#
+# Set T1 framing type to d4 instead of esf:
+#tdm_framing		d4
+#
+# Use E&M on CAS (default is FXS/FXO). If set, E1 spans will be used as
+# E&M-E1 and T1 will use the requested type:
+#em_signalling em
+#em_signalling em_w
+#em_signalling featd
+#em_signalling featdtmf
+#em_signalling featdtmf_ta
+#em_signalling featb
+#em_signalling fgccama
+#em_signalling fgccamamf
+#
+# pri_termtype contains a list of settings:
+# Currently the only setting is for TE or NT (the default is TE). This
+# sets two different but normally related configuration items:
+# 
+# A TE span will have *_cpe signalling in Asterisk and will also get
+# timing from the remote party.
+# 
+# A NT span will have *_new signalling in Asterisk and will provide
+# timing to the remote party.
+#
+# pri_termtype is a list if span specs and configuration (TE/NT) for
+# them. The first spec that matches is used. The matching is of perl
+# regular expressions, but with '*' and '?' have their meaning from
+# basic regular expressions.
+#pri_termtype
+#	SPAN/2		NT
+#	SPAN/4		NT
+#
+#pri_termtype
+#	SPAN/*		NT
+#
+# Astribanks can be matched by span and also by their:
+#    LABEL + XPD number:
+#      this is burned into the Astribank and won't change
+#      if it's connected via different USB port/hub
+#    CONNECTOR + XPD number:
+#      The USB path to which the Astribank is connected.
+#      Replacing an Astribank and connecting to the same USB port/hub
+#      would not change this property. However, any change in USB
+#      wiring (e.g: adding another hub) may alter this.
+#    NUM (XBUS number) + XPD number:
+#      The XBUS number. This is not stable and may even change
+#      between boots.
+#
+#pri_termtype
+#	LABEL/usb:INT01216/XPD-0[123]            NT
+#	LABEL/usb:INT00375/XPD-0[123]            NT
+#	CONNECTOR/@usb-0000:00:1d.7-1/XPD-0[123]            NT
+#	CONNECTOR/@usb-0000:00:1d.7-2/XPD-0[123]            NT
+#	NUM/XBUS-01/XPD-0[123]            NT
+#	NUM/XBUS-03/XPD-0[123]            NT
diff --git a/xpp/hexfile.c b/xpp/hexfile.c
new file mode 100644
index 0000000..1227b26
--- /dev/null
+++ b/xpp/hexfile.c
@@ -0,0 +1,568 @@
+/*
+ * Written by Oron Peled <oron at actcom.co.il>
+ * Copyright (C) 2006, 2007, 2008, Xorcom
+ *
+ * All rights reserved.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include "hexfile.h"
+
+static const char rcsid[] = "$Id$";
+
+static parse_hexfile_report_func_t	report_func = NULL;
+
+parse_hexfile_report_func_t parse_hexfile_set_reporting(parse_hexfile_report_func_t rf)
+{
+	parse_hexfile_report_func_t	old_rf = report_func;
+	report_func = rf;
+	return old_rf;
+}
+
+static void chomp(char buf[])
+{
+	size_t	last = strlen(buf) - 1;
+	while(last >= 0 && isspace(buf[last]))
+		buf[last--] = '\0';
+}
+
+static int hexline_checksum(struct hexline *hexline)
+{
+	unsigned int	i;
+	unsigned int	chksm = 0;
+	int		ll = hexline->d.content.header.ll;
+
+	for(i = 0; i <= sizeof(hexline->d.content.header) + ll; i++) {
+		chksm += hexline->d.raw[i];
+	}
+	return chksm & 0xFF;
+}
+
+int dump_hexline(int recordno, struct hexline *line, FILE *fp)
+{
+	uint8_t		ll;
+	uint16_t	offset;
+	uint8_t		tt;
+	uint8_t		old_chksum;
+	uint8_t		new_chksum;
+	uint8_t		*data;
+	unsigned int	i;
+
+	ll = line->d.content.header.ll;
+	offset = line->d.content.header.offset;
+	tt = line->d.content.header.tt;
+	fprintf(fp, ":%02X%04X%02X", ll, offset, tt);
+	data = line->d.content.tt_data.data;
+	for(i = 0; i < ll; i++) {
+		fprintf(fp, "%02X", data[i]);
+	}
+	old_chksum = data[ll];
+	data[ll] = 0;
+	new_chksum = 0xFF - hexline_checksum(line) + 1;
+	data[ll] = old_chksum;
+	fprintf(fp, "%02X\n", new_chksum);
+	if(new_chksum != old_chksum) {
+		if(report_func)
+			report_func(LOG_ERR, "record #%d: new_chksum(%02X) != old_chksum(%02X)\n",
+					recordno, new_chksum, old_chksum);
+		return 0;
+	}
+	return 1;
+}
+
+struct hexline	*new_hexline(uint8_t datalen, uint16_t offset, uint8_t tt)
+{
+	struct hexline	*hexline;
+	size_t		allocsize;
+
+	allocsize = sizeof(struct hexline) + datalen + 1; /* checksum byte */
+	if((hexline = malloc(allocsize)) == NULL) {
+		if(report_func)
+			report_func(LOG_ERR, "No more memory\n");
+		return NULL;
+	}
+	memset(hexline, 0, allocsize);
+	hexline->d.content.header.ll = datalen;
+	hexline->d.content.header.offset = offset;
+	hexline->d.content.header.tt = tt;
+	return hexline;
+}
+
+static int append_hexline(struct hexdata *hexdata, char *buf)
+{
+	int		ret;
+	unsigned int	ll, offset, tt;
+	char		*p;
+	struct hexline	*hexline;
+	unsigned int	i;
+
+	if(hexdata->got_eof) {
+		if(report_func)
+			report_func(LOG_ERR, "Extranous data after EOF record\n");
+		return -EINVAL;
+	}
+	if(hexdata->last_line >= hexdata->maxlines) {
+		if(report_func)
+			report_func(LOG_ERR, "Hexfile too large (maxline %d)\n", hexdata->maxlines);
+		return -ENOMEM;
+	}
+	ret = sscanf(buf, "%02X%04X%02X", &ll, &offset, &tt);
+	if(ret != 3) {
+		if(report_func)
+			report_func(LOG_ERR, "Bad line header (only %d items out of 3 parsed)\n", ret);
+		return -EINVAL;
+	}
+	switch(tt) {
+		case TT_DATA:
+			break;
+		case TT_EOF:
+			if(ll != 0) {
+				if(report_func)
+					report_func(LOG_ERR,
+						"%d: Record %d(EOF): Bad len = %d\n",
+						hexdata->last_line, tt, ll);
+				return -EINVAL;
+			}
+			if(offset != 0) {
+				if(report_func)
+					report_func(LOG_ERR,
+						"%d: Record %d(EOF): Bad offset = %d\n",
+						hexdata->last_line, tt, offset);
+				return -EINVAL;
+			}
+			hexdata->got_eof = 1;
+			break;
+		case TT_EXT_SEG:
+			if(ll != 2) {
+				if(report_func)
+					report_func(LOG_ERR,
+						"%d: Record %d(EXT_SEG): Bad len = %d\n",
+						hexdata->last_line, tt, ll);
+				return -EINVAL;
+			}
+			if(offset != 0) {
+				if(report_func)
+					report_func(LOG_ERR,
+						"%d: Record %d(EXT_SEG): Bad offset = %d\n",
+						hexdata->last_line, tt, offset);
+				return -EINVAL;
+			}
+			break;
+		case TT_START_SEG:
+			if(ll != 4) {
+				if(report_func)
+					report_func(LOG_ERR,
+						"%d: Record %d(START_SEG): Bad len = %d\n",
+						hexdata->last_line, tt, ll);
+				return -EINVAL;
+			}
+			if(offset != 0) {
+				if(report_func)
+					report_func(LOG_ERR,
+						"%d: Record %d(START_SEG): Bad offset = %d\n",
+						hexdata->last_line, tt, offset);
+				return -EINVAL;
+			}
+			break;
+		case TT_EXT_LIN:
+			if(ll != 2) {
+				if(report_func)
+					report_func(LOG_ERR,
+						"%d: Record %d(EXT_LIN): Bad len = %d\n",
+						hexdata->last_line, tt, ll);
+				return -EINVAL;
+			}
+			if(offset != 0) {
+				if(report_func)
+					report_func(LOG_ERR,
+						"%d: Record %d(EXT_LIN): Bad offset = %d\n",
+						hexdata->last_line, tt, ll);
+				return -EINVAL;
+			}
+			break;
+		case TT_START_LIN:	/* Unimplemented */
+			if(ll != 4) {
+				if(report_func)
+					report_func(LOG_ERR,
+						"%d: Record %d(EXT_LIN): Bad len = %d\n",
+						hexdata->last_line, tt, ll);
+				return -EINVAL;
+			}
+			if(offset != 0) {
+				if(report_func)
+					report_func(LOG_ERR,
+						"%d: Record %d(EXT_LIN): Bad offset = %d\n",
+						hexdata->last_line, tt, ll);
+				return -EINVAL;
+			}
+			break;
+		default:
+			if(report_func)
+				report_func(LOG_ERR, "%d: Unimplemented record type %d: %s\n",
+					hexdata->last_line, tt, buf);
+			return -EINVAL;
+	}
+	buf += 8;	/* Skip header */
+	if((hexline = new_hexline(ll, offset, tt)) == NULL) {
+		if(report_func)
+			report_func(LOG_ERR, "No more memory for hexfile lines\n");
+		return -EINVAL;
+	}
+	p = buf;
+	for(i = 0; i < ll + 1; i++) {	/* include checksum */
+		unsigned int	val;
+
+		if((*p == '\0') || (*(p+1) == '\0')) {
+			if(report_func)
+				report_func(LOG_ERR, "Short data string '%s'\n", buf);
+			return -EINVAL;
+		}
+		ret = sscanf(p, "%02X", &val);
+		if(ret != 1) {
+			if(report_func)
+				report_func(LOG_ERR, "Bad data byte #%d\n", i);
+			return -EINVAL;
+		}
+		hexline->d.content.tt_data.data[i] = val;
+		p += 2;
+	}
+	if(hexline_checksum(hexline) != 0) {
+		if(report_func) {
+			report_func(LOG_ERR, "Bad checksum (%d instead of 0)\n",
+				hexline_checksum(hexline));
+			dump_hexline(hexdata->last_line, hexline, stderr);
+		}
+		return -EINVAL;
+	}
+	hexdata->lines[hexdata->last_line] = hexline;
+	if(hexdata->got_eof)
+		return 0;
+	hexdata->last_line++;
+	return 1;
+}
+
+void free_hexdata(struct hexdata *hexdata)
+{
+	if(hexdata) {
+		unsigned int	i;
+
+		for(i = 0; i < hexdata->maxlines; i++)
+			if(hexdata->lines[i] != NULL)
+				free(hexdata->lines[i]);
+		free(hexdata);
+	}
+}
+
+int dump_hexfile(struct hexdata *hexdata, const char *outfile)
+{
+	FILE		*fp;
+	unsigned int	i;
+
+	if(report_func)
+		report_func(LOG_INFO, "Dumping hex data into '%s'\n", outfile);
+	if(!outfile || strcmp(outfile, "-") == 0)
+		fp = stdout;
+	else if((fp = fopen(outfile, "w")) == NULL) {
+		perror(outfile);
+		exit(1);
+	}
+	for(i = 0; i <= hexdata->last_line; i++) {
+		struct hexline	*line = hexdata->lines[i];
+		if(!line) {
+			if(report_func)
+				report_func(LOG_ERR, "Missing line at #%d\n", i);
+			return -EINVAL;
+		}
+		if(!dump_hexline(i, line, fp))
+			return -EINVAL;
+	}
+	return 0;
+}
+
+int dump_hexfile2(struct hexdata *hexdata, const char *outfile, uint8_t maxwidth)
+{
+	FILE		*fp;
+	uint8_t		tt;
+	unsigned int	i;
+	struct hexline	*line;
+
+	if(report_func)
+		report_func(LOG_INFO,
+			"Dumping hex data into '%s' (maxwidth=%d)\n",
+			outfile, maxwidth);
+	if(!outfile || strcmp(outfile, "-") == 0)
+		fp = stdout;
+	else if((fp = fopen(outfile, "w")) == NULL) {
+		perror(outfile);
+		exit(1);
+	}
+	if(maxwidth == 0)
+		maxwidth = UINT8_MAX;
+	for(i = 0; i <= hexdata->last_line; i++) {
+		int		bytesleft = 0;
+		int		extra_offset = 0;
+		int		base_offset;
+		uint8_t		*base_data;
+		
+		line = hexdata->lines[i];
+		if(!line) {
+			if(report_func)
+				report_func(LOG_ERR, "Missing line at #%d\n", i);
+			return -EINVAL;
+		}
+		bytesleft = line->d.content.header.ll;
+		/* split the line into several lines */
+		tt = line->d.content.header.tt;
+		base_offset = line->d.content.header.offset;
+		base_data = line->d.content.tt_data.data;
+		while (bytesleft > 0) {
+			struct hexline	*extraline;
+			uint8_t		new_chksum;
+			unsigned int	curr_bytes = (bytesleft >= maxwidth) ? maxwidth : bytesleft;
+
+			/* generate the new line */
+			if((extraline = new_hexline(curr_bytes, base_offset + extra_offset, tt)) == NULL) {
+				if(report_func)
+					report_func(LOG_ERR, "No more memory for hexfile lines\n");
+				return -EINVAL;
+			}
+			memcpy(extraline->d.content.tt_data.data, base_data + extra_offset, curr_bytes);
+			new_chksum = 0xFF - hexline_checksum(extraline) + 1;
+			extraline->d.content.tt_data.data[curr_bytes] = new_chksum;
+			/* print it */
+			dump_hexline(i, extraline, fp);
+			/* cleanups */
+			free(extraline);
+			extra_offset += curr_bytes;
+			bytesleft -= curr_bytes;
+		}
+	}
+	if(tt != TT_EOF) {
+		if(report_func)
+			report_func(LOG_ERR, "Missing EOF record\n");
+		return -EINVAL;
+	}
+	dump_hexline(i, line, fp);
+	return 0;
+}
+
+void process_comment(struct hexdata *hexdata, char buf[])
+{
+	char		*dollar_start;
+	char		*dollar_end;
+	const char	id_prefix[] = "Id: ";
+	char		tmp[BUFSIZ];
+	char		*p;
+	int		len;
+
+	if(report_func)
+		report_func(LOG_INFO, "Comment: %s\n", buf + 1);
+	/* Search for RCS keywords */
+	if((dollar_start = strchr(buf, '$')) == NULL)
+		return;
+	if((dollar_end = strchr(dollar_start + 1, '$')) == NULL)
+		return;
+	/* Crop the '$' signs */
+	len = dollar_end - dollar_start;
+	len -= 2;
+	memcpy(tmp, dollar_start + 1, len);
+	tmp[len] = '\0';
+	p = tmp;
+	if(strstr(tmp, id_prefix) == NULL)
+		return;
+	p += strlen(id_prefix);
+	if((p = strchr(p, ' ')) == NULL)
+		return;
+	p++;
+	snprintf(hexdata->version_info, BUFSIZ, "%s", p);
+	if((p = strchr(hexdata->version_info, ' ')) != NULL)
+		*p = '\0';
+}
+
+struct hexdata *parse_hexfile(const char *fname, unsigned int maxlines)
+{
+	FILE		*fp;
+	struct hexdata	*hexdata = NULL;
+	int		datasize;
+	char		buf[BUFSIZ];
+	int		line;
+	int		dos_eof = 0;
+	int		ret;
+
+	assert(fname != NULL);
+	if(report_func)
+		report_func(LOG_INFO, "Parsing %s\n", fname);
+	datasize = sizeof(struct hexdata) + maxlines * sizeof(char *);
+	hexdata = (struct hexdata *)malloc(datasize);
+	if(!hexdata) {
+		if(report_func)
+			report_func(LOG_ERR, "Failed to allocate %d bytes for hexfile contents\n", datasize);
+		goto err;
+	}
+	memset(hexdata, 0, datasize);
+	hexdata->maxlines = maxlines;
+	if((fp = fopen(fname, "r")) == NULL) {
+		if(report_func)
+			report_func(LOG_ERR, "Failed to open hexfile '%s'\n", fname);
+		goto err;
+	}
+	snprintf(hexdata->fname, PATH_MAX, "%s", fname);
+	for(line = 1; fgets(buf, BUFSIZ, fp); line++) {
+		if(dos_eof) {
+			if(report_func)
+				report_func(LOG_ERR, "%s:%d - Got DOS EOF character before true EOF\n", fname, line);
+			goto err;
+		}
+		if(buf[0] == 0x1A && buf[1] == '\0') { /* DOS EOF char */
+			dos_eof = 1;
+			continue;
+		}
+		chomp(buf);
+		if(buf[0] == '\0') {
+				if(report_func)
+					report_func(LOG_ERR, "%s:%d - Short line\n", fname, line);
+				goto err;
+		}
+		if(buf[0] == '#') {
+			process_comment(hexdata, buf);
+			continue;
+		}
+		if(buf[0] != ':') {
+			if(report_func)
+				report_func(LOG_ERR, "%s:%d - Line begins with 0x%X\n", fname, line, buf[0]);
+			goto err;
+		}
+		if((ret = append_hexline(hexdata, buf + 1)) < 0) {
+			if(report_func)
+				report_func(LOG_ERR, "%s:%d - Failed parsing.\n", fname, line);
+			goto err;
+		}
+	}
+	fclose(fp);
+	if(report_func)
+		report_func(LOG_INFO, "%s parsed OK\n", fname);
+	return hexdata;
+err:
+	free_hexdata(hexdata);
+	return NULL;
+}
+
+void dump_binary(struct hexdata *hexdata, const char *outfile)
+{
+	FILE		*fp;
+	unsigned int	i;
+	size_t		len;
+
+	if(report_func)
+		report_func(LOG_INFO, "Dumping binary data into '%s'\n", outfile);
+	if((fp = fopen(outfile, "w")) == NULL) {
+		perror(outfile);
+		exit(1);
+	}
+	for(i = 0; i < hexdata->maxlines; i++) {
+		struct hexline	*hexline = hexdata->lines[i];
+
+		if(!hexline)
+			break;
+		switch(hexline->d.content.header.tt) {
+		case TT_EOF:
+			if(report_func)
+				report_func(LOG_INFO, "\ndump: good EOF record");
+			break;
+		case TT_DATA:
+			if(report_func)
+				report_func(LOG_INFO, "dump: %6d\r", i);
+			len = hexline->d.content.header.ll;
+			if(fwrite(hexline->d.content.tt_data.data, 1, len, fp) != len) {
+				perror("write");
+				exit(1);
+			}
+			break;
+		case TT_EXT_SEG:
+		case TT_START_SEG:
+		case TT_EXT_LIN:
+		case TT_START_LIN:
+			if(report_func)
+				report_func(LOG_INFO,
+					"\ndump(%d): ignored record type %d",
+					i, hexline->d.content.header.tt);
+			break;
+		default:
+			if(report_func)
+				report_func(LOG_ERR, "dump: Unknown record type %d\n",
+					hexline->d.content.header.tt);
+			exit(1);
+		}
+	}
+	if(report_func)
+		report_func(LOG_INFO, "\nDump finished\n");
+	fclose(fp);
+}
+
+void gen_hexline(const uint8_t *data, uint16_t addr, size_t len, FILE *output)
+{
+	struct hexline	*hexline;
+
+	if(!data) {
+		fprintf(output, ":%02X%04X%02XFF\n", 0, 0, TT_EOF);
+		return;
+	}
+	if((hexline = new_hexline(len, addr, (!data) ? TT_EOF : TT_DATA)) == NULL) {
+		if(report_func)
+			report_func(LOG_ERR, "No more memory\n");
+		return;
+	}
+	if(data)
+		memcpy(&hexline->d.content.tt_data, data, len);
+	dump_hexline(0, hexline, output);
+	free(hexline);
+}
+
+/*
+ * Algorithm lifted of sum(1) implementation from coreutils.
+ * We chose the default algorithm (BSD style).
+ */
+int bsd_checksum(struct hexdata *hexdata)
+{
+	unsigned int	i;
+	size_t		len;
+	int		ck = 0;
+
+	for(i = 0; i < hexdata->maxlines; i++) {
+		struct hexline	*hexline = hexdata->lines[i];
+		unsigned char	*p;
+
+		if(!hexline)
+			break;
+		if(hexline->d.content.header.tt == TT_EOF)
+			continue;
+		len = hexline->d.content.header.ll;
+		p = hexline->d.content.tt_data.data;
+		for(; len; p++, len--) {
+			ck = (ck >> 1) + ((ck & 1) << 15);
+			ck += *p;
+			ck &= 0xffff;	/* Keep it within bounds. */
+		}
+	}
+	return ck;
+}
diff --git a/xpp/hexfile.h b/xpp/hexfile.h
new file mode 100644
index 0000000..27c71e7
--- /dev/null
+++ b/xpp/hexfile.h
@@ -0,0 +1,87 @@
+/*
+ * Written by Oron Peled <oron at actcom.co.il>
+ * Copyright (C) 2006, 2007, 2008, Xorcom
+ *
+ * All rights reserved.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef	PARSE_HEXFILE_H
+#define	PARSE_HEXFILE_H
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/param.h>
+#include <syslog.h>
+#define	PACKED	__attribute__((packed))
+#define	ZERO_SIZE	0
+
+/* Record types in hexfile */
+enum {
+	TT_DATA		= 0,
+	TT_EOF		= 1,
+	TT_EXT_SEG	= 2,
+	TT_START_SEG	= 3,
+	TT_EXT_LIN	= 4,
+	TT_START_LIN	= 5,
+	TT_NO_SUCH_TT
+};
+
+#pragma pack(1)
+struct hexline {
+	union {
+		uint8_t		raw[ZERO_SIZE];
+		struct content {
+			struct header {
+				uint8_t		ll;	/* len */
+				uint16_t	offset;	/* offset */
+				uint8_t		tt;	/* type */
+			} PACKED header;
+			struct tt_data {
+				uint8_t		data[ZERO_SIZE];
+			} tt_data;
+		} PACKED content;
+	} d;
+} PACKED;
+#pragma pack()
+
+struct hexdata {
+	unsigned int		maxlines;
+	unsigned int		last_line;
+	int			got_eof;
+	char			fname[PATH_MAX];
+	char			version_info[BUFSIZ];
+	struct hexline		*lines[ZERO_SIZE];
+};
+
+
+__BEGIN_DECLS
+
+typedef void (*parse_hexfile_report_func_t)(int level, const char *msg, ...);
+
+parse_hexfile_report_func_t parse_hexfile_set_reporting(parse_hexfile_report_func_t rf);
+void free_hexdata(struct hexdata *hexdata);
+struct hexdata *parse_hexfile(const char *fname, unsigned int maxlines);
+int dump_hexfile(struct hexdata *hexdata, const char *outfile);
+int dump_hexfile2(struct hexdata *hexdata, const char *outfile, uint8_t maxwidth);
+void dump_binary(struct hexdata *hexdata, const char *outfile);
+void gen_hexline(const uint8_t *data, uint16_t addr, size_t len, FILE *output);
+int bsd_checksum(struct hexdata *hexdata);
+__END_DECLS
+
+#endif
diff --git a/xpp/lsdahdi b/xpp/lsdahdi
new file mode 100755
index 0000000..e4d473c
--- /dev/null
+++ b/xpp/lsdahdi
@@ -0,0 +1,110 @@
+#! /usr/bin/perl -w
+#
+# Written by Oron Peled <oron at actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use File::Basename;
+BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/perl_modules"); }
+
+use Dahdi;
+use Dahdi::Span;
+use Dahdi::Xpp;
+use Dahdi::Xpp::Xbus;
+use Dahdi::Xpp::Xpd;
+
+my @xbuses = Dahdi::Xpp::xbuses;
+my @xpds = map { $_->xpds } @xbuses;
+
+foreach my $span (Dahdi::spans()) {
+	my $spanno = $span->num;
+	my $xpd = Dahdi::Xpp::xpd_of_span($span);
+	my @lines;
+	my $index = 0;
+
+	@lines = @{$xpd->lines} if defined $xpd;
+	printf "### Span %2d: %s %s\n", $span->num, $span->name, $span->description;
+	foreach my $chan ($span->chans()) {
+		my %type_map = (
+			OUT	=> 'Output',
+			IN	=> 'Input'
+			);
+		my ($type) = map { $type_map{$_} or $_ } $chan->type || ("unknown");
+		my $batt = "";
+		$batt = "(battery)" if $chan->battery;
+		my @alarms = $chan->alarms;
+		my $alarm_str = join(" ", @alarms);
+		printf "%3d %-10s %-10s %s %s %s\n",
+			$chan->num, $type, $chan->signalling, $chan->info, $batt, $alarm_str;
+		$index++;
+	}
+}
+
+__END__
+
+=head1 NAME
+
+lsdahdi - List all dahdi channels with their types and spans.
+
+=head1 SYNOPSIS
+
+lsdahdi
+
+=head1 DESCRIPTION
+
+Example output:
+
+	### Span  1: WCTDM/0 "Wildcard TDM400P REV E/F Board 1"
+	  1 FXO        FXOLS      (In use)
+	  2 FXS        FXSKS
+	  3 FXS        FXSKS
+	  4 FXS        FXSKS
+	### Span  2: XBUS-00/XPD-00 "Xorcom XPD #00/00: FXO"
+	  5 FXO        FXSKS      (In use)
+	  6 FXO        FXSKS      (In use) (no pcm)
+	  7 FXO        FXSKS      (In use) (no pcm)
+	  8 FXO        FXSKS      (In use) (no pcm)
+	  9 FXO        FXSKS      (In use) (no pcm)
+	 10 FXO        FXSKS      (In use) (no pcm)
+	 11 FXO        FXSKS      (In use) (no pcm)
+	 12 FXO        FXSKS      (In use) (no pcm)
+	### Span  3: XBUS-00/XPD-10 "Xorcom XPD #00/10: FXO"
+	 13 FXO        FXSKS      (In use) (no pcm)
+	 14 FXO        FXSKS      (In use) (no pcm)
+	 15 FXO        FXSKS      (In use) (no pcm)
+	 16 FXO        FXSKS      (In use) (no pcm)
+	 17 FXO        FXSKS      (In use) (no pcm)
+	 18 FXO        FXSKS      (In use) (no pcm)
+	 19 FXO        FXSKS      (In use) (no pcm)
+	 20 FXO        FXSKS      (In use) (no pcm)
+
+	...
+
+	### Span  6: XBUS-01/XPD-00 "Xorcom XPD #01/00: FXS"
+	 37 FXS        FXOLS      (In use)
+	 38 FXS        FXOLS      (In use) (no pcm)
+	 39 FXS        FXOLS      (In use) (no pcm)
+	 40 FXS        FXOLS      (In use) (no pcm)
+	 41 FXS        FXOLS      (In use) (no pcm)
+	 42 FXS        FXOLS      (In use) (no pcm)
+	 43 FXS        FXOLS      (In use) (no pcm)
+	 44 FXS        FXOLS      (In use) (no pcm)
+	 45 Output     FXOLS      (In use) (no pcm)
+	 46 Output     FXOLS      (In use) (no pcm)
+	 47 Input      FXOLS      (In use) (no pcm)
+	 48 Input      FXOLS      (In use) (no pcm)
+	 49 Input      FXOLS      (In use) (no pcm)
+	 50 Input      FXOLS      (In use) (no pcm)
+
+The first column is the type of the channel (port, for an analog device) 
+and the second one is the signalling (if set).
+
+=head1 FILES
+
+lsdahdi is a somewhat glorified 'cat /proc/dahdi/*' . Unlike that
+command, it sorts the spans with the proper order. It also formats the
+output slightly differently.
diff --git a/xpp/mpp.h b/xpp/mpp.h
new file mode 100644
index 0000000..45654b7
--- /dev/null
+++ b/xpp/mpp.h
@@ -0,0 +1,344 @@
+#ifndef	MPP_H
+#define	MPP_H
+/*
+ * Written by Oron Peled <oron at actcom.co.il>
+ * Copyright (C) 2008, Xorcom
+ *
+ * All rights reserved.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+ * MPP - Managment Processor Protocol definitions
+ */
+
+#ifdef	__GNUC__
+#define	PACKED	__attribute__((packed))
+#else
+#error "We do not know how your compiler packs structures"
+#endif
+
+#define	MK_PROTO_VERSION(major, minor)	(((major) << 4) | (0x0F & (minor)))
+
+#define	MPP_PROTOCOL_VERSION	MK_PROTO_VERSION(1,4)
+#define	MPP_SUPPORTED_VERSION(x)	((x) == MK_PROTO_VERSION(1,3) || (x) == MK_PROTO_VERSION(1,4))
+
+/*
+ * The eeprom_table is common to all eeprom types.
+ */
+#define	LABEL_SIZE	8
+struct eeprom_table {
+	uint8_t		source;		/* C0 - small eeprom, C2 - large eeprom */
+	uint16_t	vendor;
+	uint16_t	product;
+	uint16_t	release;	/* BCD encoded release */
+	uint8_t		config_byte;	/* Must be 0 */
+	uint8_t		label[LABEL_SIZE];
+} PACKED;
+
+#define	VERSION_LEN	6
+struct firmware_versions {
+	char	usb[VERSION_LEN];
+	char	fpga[VERSION_LEN];
+	char	eeprom[VERSION_LEN];
+} PACKED;
+
+struct capabilities {
+	uint8_t		ports_fxs;
+	uint8_t		ports_fxo;
+	uint8_t		ports_bri;
+	uint8_t		ports_pri;
+	uint8_t		extra_features;	/* BIT(0) - TwinStar */
+	uint8_t		reserved[3];
+	uint32_t	timestamp;
+} PACKED;
+
+#define	CAP_EXTRA_TWINSTAR(c)		((c)->extra_features & 0x01)
+#define	CAP_EXTRA_TWINSTAR_SET(c)	do {(c)->extra_features |= 0x01;} while (0)
+#define	CAP_EXTRA_TWINSTAR_CLR(c)	do {(c)->extra_features &= ~0x01;} while (0)
+
+#define	KEYSIZE	16
+
+struct capkey {
+	uint8_t	k[KEYSIZE];
+} PACKED;
+
+struct extrainfo {
+	char		text[24];
+} PACKED;
+
+enum mpp_command_ops {
+	/* MSB of op signifies a reply from device */
+	MPP_ACK			= 0x80,
+
+	MPP_PROTO_QUERY	= 0x01,
+	MPP_PROTO_REPLY	= 0x81,
+
+	MPP_RENUM		= 0x0B,	/* Trigger USB renumeration */
+
+	MPP_EEPROM_SET		= 0x0D,
+
+	MPP_CAPS_GET		= 0x0E,
+	MPP_CAPS_GET_REPLY	= 0x8E,
+	MPP_CAPS_SET		= 0x0F,	/* Set AB capabilities	*/
+
+	MPP_DEV_SEND_START	= 0x05,
+	MPP_DEV_SEND_SEG	= 0x07,
+	MPP_DEV_SEND_END	= 0x09,
+
+	MPP_STATUS_GET		= 0x11,	/* Get Astribank Status	*/
+	MPP_STATUS_GET_REPLY	= 0x91,
+	MPP_STATUS_GET_REPLY_V13	= 0x91,	/* backward compat */
+
+	MPP_EXTRAINFO_GET	= 0x13,	/* Get extra vendor information	*/
+	MPP_EXTRAINFO_GET_REPLY	= 0x93,
+	MPP_EXTRAINFO_SET	= 0x15,	/* Set extra vendor information	*/
+
+	MPP_EEPROM_BLK_RD	= 0x27,
+	MPP_EEPROM_BLK_RD_REPLY	= 0xA7,
+
+	MPP_SER_SEND		= 0x37,
+	MPP_SER_RECV		= 0xB7,
+
+	MPP_RESET		= 0x45,	/* Reset both FPGA and USB firmwares */
+	MPP_HALF_RESET		= 0x47,	/* Reset only FPGA firmware */
+
+	/* Twinstar */
+	MPP_TWS_WD_MODE_SET	= 0x31,	/* Set watchdog off/on guard	*/
+	MPP_TWS_WD_MODE_GET	= 0x32,	/* Current watchdog mode 	*/
+	MPP_TWS_WD_MODE_GET_REPLY = 0xB2,	/* Current watchdog mode 	*/
+	MPP_TWS_PORT_SET	= 0x34,	/* USB-[0/1]			*/
+	MPP_TWS_PORT_GET	= 0x35,	/* USB-[0/1]			*/
+	MPP_TWS_PORT_GET_REPLY	= 0xB5,	/* USB-[0/1]			*/
+	MPP_TWS_PWR_GET		= 0x36,	/* Power: bits -> USB ports	*/
+	MPP_TWS_PWR_GET_REPLY	= 0xB6,	/* Power: bits -> USB ports	*/
+};
+
+struct mpp_header {
+	uint16_t	len;
+	uint16_t	seq;
+	uint8_t		op;	/* MSB: 0 - to device, 1 - from device */
+} PACKED;
+
+enum mpp_ser_op {
+	SER_CARD_INFO_GET	= 0x1,
+	SER_STAT_GET		= 0x3,
+};
+
+/* Individual commands structure */
+
+#define	CMD_DEF(name, ...)	struct d_ ## name { __VA_ARGS__ } PACKED d_ ## name
+
+CMD_DEF(ACK,
+	uint8_t	stat;
+	);
+
+CMD_DEF(PROTO_QUERY,
+	uint8_t	proto_version;
+	uint8_t	reserved;
+	);
+
+CMD_DEF(PROTO_REPLY,
+	uint8_t	proto_version;
+	uint8_t	reserved;
+	);
+
+CMD_DEF(STATUS_GET);
+
+CMD_DEF(STATUS_GET_REPLY_V13,
+	uint8_t	i2cs_data;
+
+#define	STATUS_FPGA_LOADED(x)	((x) & 0x01)
+	uint8_t	status;		/* BIT(0) - FPGA is loaded */
+	);
+
+
+CMD_DEF(STATUS_GET_REPLY,
+	uint8_t	i2cs_data;
+
+#define	STATUS_FPGA_LOADED(x)	((x) & 0x01)
+	uint8_t	status;		/* BIT(0) - FPGA is loaded */
+	struct firmware_versions fw_versions;
+	);
+
+CMD_DEF(EEPROM_SET,
+	struct eeprom_table	data;
+	);
+
+CMD_DEF(CAPS_GET);
+
+CMD_DEF(CAPS_GET_REPLY,
+	struct eeprom_table	data;
+	struct capabilities	capabilities;
+	struct capkey		key;
+	);
+
+CMD_DEF(CAPS_SET,
+	struct eeprom_table	data;
+	struct capabilities	capabilities;
+	struct capkey		key;
+	);
+
+CMD_DEF(EXTRAINFO_GET);
+
+CMD_DEF(EXTRAINFO_GET_REPLY,
+	struct extrainfo	info;
+	);
+
+CMD_DEF(EXTRAINFO_SET,
+	struct extrainfo	info;
+	);
+
+CMD_DEF(RENUM);
+
+CMD_DEF(EEPROM_BLK_RD,
+	uint16_t	offset;
+	uint16_t	len;
+	);
+
+CMD_DEF(EEPROM_BLK_RD_REPLY,
+	uint16_t	offset;
+	uint8_t		data[0];
+	);
+
+CMD_DEF(DEV_SEND_START,
+	uint8_t		dest;
+	char		ihex_version[VERSION_LEN];
+	);
+
+CMD_DEF(DEV_SEND_END);
+
+CMD_DEF(DEV_SEND_SEG,
+	uint16_t	offset;
+	uint8_t		data[0];
+	);
+
+CMD_DEF(RESET);
+CMD_DEF(HALF_RESET);
+
+CMD_DEF(SER_SEND,
+	uint8_t	data[0];
+	);
+
+CMD_DEF(SER_RECV,
+	uint8_t	data[0];
+	);
+
+CMD_DEF(TWS_WD_MODE_SET,
+	uint8_t		wd_active;
+	);
+
+CMD_DEF(TWS_WD_MODE_GET);
+CMD_DEF(TWS_WD_MODE_GET_REPLY,
+	uint8_t		wd_active;
+	);
+
+CMD_DEF(TWS_PORT_SET,
+	uint8_t		portnum;
+	);
+
+CMD_DEF(TWS_PORT_GET);
+CMD_DEF(TWS_PORT_GET_REPLY,
+	uint8_t		portnum;
+	);
+
+CMD_DEF(TWS_PWR_GET);
+CMD_DEF(TWS_PWR_GET_REPLY,
+	uint8_t		power;
+	);
+
+#undef	CMD_DEF
+
+#define	MEMBER(n)	struct d_ ## n d_ ## n
+
+struct mpp_command {
+	struct mpp_header	header;
+	union {
+		MEMBER(ACK);
+		MEMBER(PROTO_QUERY);
+		MEMBER(PROTO_REPLY);
+		MEMBER(STATUS_GET);
+		MEMBER(STATUS_GET_REPLY_V13);
+		MEMBER(STATUS_GET_REPLY);
+		MEMBER(EEPROM_SET);
+		MEMBER(CAPS_GET);
+		MEMBER(CAPS_GET_REPLY);
+		MEMBER(CAPS_SET);
+		MEMBER(EXTRAINFO_GET);
+		MEMBER(EXTRAINFO_GET_REPLY);
+		MEMBER(EXTRAINFO_SET);
+		MEMBER(RENUM);
+		MEMBER(EEPROM_BLK_RD);
+		MEMBER(EEPROM_BLK_RD_REPLY);
+		MEMBER(DEV_SEND_START);
+		MEMBER(DEV_SEND_SEG);
+		MEMBER(DEV_SEND_END);
+		MEMBER(RESET);
+		MEMBER(HALF_RESET);
+		MEMBER(SER_SEND);
+		MEMBER(SER_RECV);
+		/* Twinstar */
+		MEMBER(TWS_WD_MODE_SET);
+		MEMBER(TWS_WD_MODE_GET);
+		MEMBER(TWS_WD_MODE_GET_REPLY);
+		MEMBER(TWS_PORT_SET);
+		MEMBER(TWS_PORT_GET);
+		MEMBER(TWS_PORT_GET_REPLY);
+		MEMBER(TWS_PWR_GET);
+		MEMBER(TWS_PWR_GET_REPLY);
+		uint8_t	raw_data[0];
+	} PACKED alt;
+} PACKED;
+#undef MEMBER
+
+#define	CMD_FIELD(cmd, name, field)	((cmd)->alt.d_ ## name.field)
+
+enum mpp_ack_stat {
+	STAT_OK		= 0x00,	/* acknowledges previous command	*/
+	STAT_FAIL	= 0x01,	/* Last command failed		*/
+	STAT_RESET_FAIL	= 0x02,	/* reset failed				*/
+	STAT_NODEST	= 0x03,	/* No destination is selected		*/
+	STAT_MISMATCH	= 0x04,	/* Data mismatch			*/
+	STAT_NOACCESS	= 0x05,	/* No access				*/
+	STAT_BAD_CMD	= 0x06,	/* Bad command				*/
+	STAT_TOO_SHORT	= 0x07,	/* Packet is too short			*/
+	STAT_ERROFFS	= 0x08,	/* Offset error				*/
+	STAT_NOCODE	= 0x09,	/* Source was not burned before		*/
+	STAT_NO_LEEPROM	= 0x0A,	/* Large EEPROM was not found		*/
+	STAT_NO_EEPROM	= 0x0B,	/* No EEPROM was found			*/
+	STAT_WRITE_FAIL	= 0x0C,	/* Writing to device failed		*/
+	STAT_FPGA_ERR	= 0x0D,	/* FPGA error				*/
+	STAT_KEY_ERR	= 0x0E,	/* Bad Capabilities Key			*/
+	STAT_NOCAPS_ERR	= 0x0F,	/* No matching capability		*/
+	STAT_NOPWR_ERR	= 0x10,	/* No power on USB connector		*/
+	STAT_CAPS_FPGA_ERR	= 0x11,	/* Setting of the capabilities while FPGA is loaded */
+};
+
+enum eeprom_type {	/* EEPROM_QUERY: i2cs(ID1, ID0) */
+	EEPROM_TYPE_NONE	= 0,
+	EEPROM_TYPE_SMALL	= 1,
+	EEPROM_TYPE_LARGE	= 2,
+	EEPROM_TYPE_UNUSED	= 3,
+};
+
+enum dev_dest {
+	DEST_NONE	= 0x00,
+	DEST_FPGA	= 0x01,
+	DEST_EEPROM	= 0x02,
+};
+
+#endif	/* MPP_H */
diff --git a/xpp/mpp_funcs.c b/xpp/mpp_funcs.c
new file mode 100644
index 0000000..457455a
--- /dev/null
+++ b/xpp/mpp_funcs.c
@@ -0,0 +1,1109 @@
+/*
+ * Written by Oron Peled <oron at actcom.co.il>
+ * Copyright (C) 2008, Xorcom
+ *
+ * All rights reserved.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include "hexfile.h"
+#include "astribank_usb.h"
+#include "mpp_funcs.h"
+#include "debug.h"
+
+static const char rcsid[] = "$Id$";
+
+#define	DBG_MASK	0x02
+
+const char *ack_status_msg(uint8_t status)
+{
+	const static char	*msgs[] = {
+		[STAT_OK] = "Acknowledges previous command",
+		[STAT_FAIL] = "Last command failed",
+		[STAT_RESET_FAIL] = "Reset failed",
+		[STAT_NODEST] = "No destination is selected",
+		[STAT_MISMATCH] = "Data mismatch",
+		[STAT_NOACCESS] = "No access",
+		[STAT_BAD_CMD] = "Bad command",
+		[STAT_TOO_SHORT] = "Packet is too short",
+		[STAT_ERROFFS] = "Offset error",
+		[STAT_NOCODE] = "Source was not burned before",
+		[STAT_NO_LEEPROM] = "Large EEPROM was not found",
+		[STAT_NO_EEPROM] = "No EEPROM was found",
+		[STAT_WRITE_FAIL] = "Writing to device failed",
+		[STAT_FPGA_ERR] = "FPGA error",
+		[STAT_KEY_ERR] = "Bad Capabilities Key",
+		[STAT_NOCAPS_ERR]	= "No matching capability",
+		[STAT_NOPWR_ERR]	= "No power on USB connector",
+		[STAT_CAPS_FPGA_ERR]	= "Setting of the capabilities while FPGA is loaded",
+	};
+	if(status > sizeof(msgs)/sizeof(msgs[0]))
+		return "ERROR CODE TOO LARGE";
+	if(!msgs[status])
+		return "MISSING ERROR CODE";
+	return msgs[status];
+}
+
+const char *eeprom_type2str(enum eeprom_type et)
+{
+	const static char	*msgs[] = {
+		[EEPROM_TYPE_NONE]	= "NONE",
+		[EEPROM_TYPE_SMALL]	= "SMALL",
+		[EEPROM_TYPE_LARGE]	= "LARGE",
+		[EEPROM_TYPE_UNUSED]	= "UNUSED",
+	};
+	if(et > sizeof(msgs)/sizeof(msgs[0]))
+		return NULL;
+	return msgs[et];
+};
+
+const char *dev_dest2str(enum dev_dest dest)
+{
+	const static char	*msgs[] = {
+		[DEST_NONE]	= "NONE",
+		[DEST_FPGA]	= "FPGA",
+		[DEST_EEPROM]	= "EEPROM",
+	};
+	if(dest > sizeof(msgs)/sizeof(msgs[0]))
+		return NULL;
+	return msgs[dest];
+};
+
+struct command_desc {
+	uint8_t		op;
+	const char	*name;
+	uint16_t	len;
+};
+
+#define	CMD_RECV(o)	[MPP_ ## o] {	\
+		.op = MPP_ ## o,	\
+		.name = #o,	\
+		.len = sizeof(struct mpp_header) + sizeof(struct d_ ## o),	\
+	}
+
+#define	CMD_SEND(o)	[MPP_ ## o] {	\
+		.op = MPP_ ## o,	\
+		.name = #o,	\
+		.len = sizeof(struct mpp_header) + sizeof(struct d_ ## o),	\
+	}
+
+static const struct command_desc	command_table[] = {
+	CMD_RECV(ACK),
+	CMD_SEND(PROTO_QUERY),
+	CMD_SEND(STATUS_GET),
+	CMD_RECV(STATUS_GET_REPLY),
+	CMD_SEND(EEPROM_SET),
+	CMD_SEND(CAPS_GET),
+	CMD_RECV(CAPS_GET_REPLY),
+	CMD_SEND(CAPS_SET),
+	CMD_SEND(EXTRAINFO_GET),
+	CMD_RECV(EXTRAINFO_GET_REPLY),
+	CMD_SEND(EXTRAINFO_SET),
+	CMD_RECV(PROTO_REPLY),
+	CMD_SEND(RENUM),
+	CMD_SEND(EEPROM_BLK_RD),
+	CMD_RECV(EEPROM_BLK_RD_REPLY),
+	CMD_SEND(DEV_SEND_SEG),
+	CMD_SEND(DEV_SEND_START),
+	CMD_SEND(DEV_SEND_END),
+	CMD_SEND(RESET),
+	CMD_SEND(HALF_RESET),
+	CMD_SEND(SER_SEND),
+	CMD_SEND(SER_RECV),
+	/* Twinstar */
+	CMD_SEND(TWS_WD_MODE_SET),
+	CMD_SEND(TWS_WD_MODE_GET),
+	CMD_RECV(TWS_WD_MODE_GET_REPLY),
+	CMD_SEND(TWS_PORT_SET),
+	CMD_SEND(TWS_PORT_GET),
+	CMD_RECV(TWS_PORT_GET_REPLY),
+	CMD_SEND(TWS_PWR_GET),
+	CMD_RECV(TWS_PWR_GET_REPLY),
+};
+
+static const struct command_desc	command_table_V13[] = {
+	CMD_RECV(ACK),
+	CMD_SEND(PROTO_QUERY),
+	CMD_SEND(STATUS_GET),
+	CMD_RECV(STATUS_GET_REPLY_V13),
+	CMD_SEND(EEPROM_SET),
+	CMD_SEND(CAPS_GET),
+	CMD_RECV(CAPS_GET_REPLY),
+	CMD_SEND(CAPS_SET),
+	CMD_SEND(EXTRAINFO_GET),
+	CMD_RECV(EXTRAINFO_GET_REPLY),
+	CMD_SEND(EXTRAINFO_SET),
+	CMD_RECV(PROTO_REPLY),
+	CMD_SEND(RENUM),
+	CMD_SEND(EEPROM_BLK_RD),
+	CMD_RECV(EEPROM_BLK_RD_REPLY),
+	CMD_SEND(DEV_SEND_SEG),
+	CMD_SEND(DEV_SEND_START),
+	CMD_SEND(DEV_SEND_END),
+	CMD_SEND(RESET),
+	CMD_SEND(HALF_RESET),
+	CMD_SEND(SER_SEND),
+	CMD_SEND(SER_RECV),
+	/* Twinstar */
+	CMD_SEND(TWS_WD_MODE_SET),
+	CMD_SEND(TWS_WD_MODE_GET),
+	CMD_RECV(TWS_WD_MODE_GET_REPLY),
+	CMD_SEND(TWS_PORT_SET),
+	CMD_SEND(TWS_PORT_GET),
+	CMD_RECV(TWS_PORT_GET_REPLY),
+	CMD_SEND(TWS_PWR_GET),
+	CMD_RECV(TWS_PWR_GET_REPLY),
+};
+
+#undef	CMD_SEND
+#undef	CMD_RECV
+
+struct cmd_queue {
+	struct cmd_queue	*next;
+	struct cmd_queue	*prev;
+	struct mpp_command	*cmd;
+};
+
+static struct cmd_queue	output_queue = {
+	.next = &output_queue,
+	.prev = &output_queue,
+	.cmd = NULL
+	};
+
+void free_command(struct mpp_command *cmd)
+{
+	memset(cmd, 0, cmd->header.len);
+	free(cmd);
+}
+
+const struct command_desc *get_command_desc(uint8_t protocol_version, uint8_t op)
+{
+	const struct command_desc	*desc;
+
+	switch(protocol_version) {
+		case MK_PROTO_VERSION(1,3):
+			if(op > sizeof(command_table_V13)/sizeof(command_table_V13[0])) {
+				//ERR("Invalid op=0x%X. Bigger than max valid op\n", op);
+				return NULL;
+			}
+			desc = &command_table_V13[op];
+			if(!desc->name)
+				return NULL;
+			break;
+		default:
+			if(op > sizeof(command_table)/sizeof(command_table[0])) {
+				//ERR("Invalid op=0x%X. Bigger than max valid op\n", op);
+				return NULL;
+			}
+			desc = &command_table[op];
+			if(!desc->name)
+				return NULL;
+			break;
+	}
+	return desc;
+}
+
+struct mpp_command *new_command(uint8_t protocol_version, uint8_t op, uint16_t extra_data)
+{
+	struct mpp_command		*cmd;
+	const struct command_desc	*desc;
+	uint16_t			len;
+
+	desc = get_command_desc(protocol_version, op);
+	if(!desc) {
+		ERR("Unknown op=0x%X.\n", op);
+		return NULL;
+	}
+	DBG("OP=0x%X [%s] (extra_data %d)\n", op, desc->name, extra_data);
+	len = desc->len + extra_data;
+	if((cmd = malloc(len)) == NULL) {
+		ERR("Out of memory\n");
+		return NULL;
+	}
+	cmd->header.op = op;
+	cmd->header.len = len;
+	cmd->header.seq = 0;	/* Overwritten in send_usb() */
+	return cmd;
+}
+
+void dump_command(struct mpp_command *cmd)
+{
+	uint16_t	len;
+	int		i;
+
+	len = cmd->header.len;
+	if(len < sizeof(struct mpp_header)) {
+		ERR("Command too short (%d)\n", len);
+		return;
+	}
+	INFO("DUMP: OP=0x%X len=%d seq=%d\n",
+		cmd->header.op, cmd->header.len, cmd->header.seq);
+	for(i = 0; i < len - sizeof(struct mpp_header); i++) {
+		INFO("  %2d. 0x%X\n", i, cmd->alt.raw_data[i]);
+	}
+}
+
+int send_command(struct astribank_device *astribank, struct mpp_command *cmd, int timeout)
+{
+	int		ret;
+	int		len;
+	char		*buf;
+
+	len = cmd->header.len;
+	cmd->header.seq = astribank->tx_sequenceno;
+
+	buf = (char *)cmd;
+	//printf("%s: len=%d\n", __FUNCTION__, len);
+#if 0
+	extern	FILE	*fp;
+	if(fp) {
+		int	i;
+
+		fprintf(fp, "%05d:", cmd->header.seq);
+		for(i = 0; i < len; i++)
+			fprintf(fp, " %02X", (uint8_t)buf[i]);
+		fprintf(fp, "\n");
+	}
+#endif
+	ret = send_usb(astribank, (char *)cmd, len, timeout);
+	if(ret < 0) {
+		DBG("send_usb failed ret=%d\n", ret);
+	}
+	astribank->tx_sequenceno++;
+	return ret;
+}
+
+struct mpp_command *recv_command(struct astribank_device *astribank, int timeout)
+{
+	struct mpp_command	*reply;
+	int			ret;
+
+	if((reply = malloc(PACKET_SIZE)) == NULL) {
+		ERR("Out of memory\n");
+		goto err;
+	}
+	reply->header.len = 0;
+	ret = recv_usb(astribank, (char *)reply, PACKET_SIZE, timeout);
+	if(ret < 0) {
+		ERR("Receive from usb failed.\n");
+		goto err;
+	} else if(ret == 0) {
+		goto err;	/* No reply */
+	}
+	if(ret != reply->header.len) {
+		ERR("Wrong length received: got %d bytes, but length field says %d bytes%s\n",
+				ret, reply->header.len,
+				(ret == 1)? ". Old USB firmware?": "");
+		goto err;
+	}
+	//dump_packet(LOG_DEBUG, __FUNCTION__, (char *)reply, ret);
+	return reply;
+err:
+	if(reply) {
+		memset(reply, 0, PACKET_SIZE);
+		free_command(reply);
+	}
+	return NULL;
+}
+
+
+__attribute__((warn_unused_result))
+int process_command(struct astribank_device *astribank, struct mpp_command *cmd, struct mpp_command **reply_ref)
+{
+	struct mpp_command		*reply = NULL;
+	const struct command_desc	*reply_desc;
+	const struct command_desc	*expected;
+	const struct command_desc	*cmd_desc;
+	uint8_t				reply_op;
+	int				ret;
+
+	if(reply_ref)
+		*reply_ref = NULL;	/* So the caller knows if a reply was received */
+	reply_op = cmd->header.op | 0x80;
+	if(cmd->header.op == MPP_PROTO_QUERY)
+		astribank->mpp_proto_version = MPP_PROTOCOL_VERSION;	/* bootstrap */
+	cmd_desc = get_command_desc(astribank->mpp_proto_version, cmd->header.op);
+	expected = get_command_desc(astribank->mpp_proto_version, reply_op);
+	//printf("%s: len=%d\n", __FUNCTION__, cmd->header.len);
+	ret = send_command(astribank, cmd, TIMEOUT);
+	if(!reply_ref) {
+		DBG("No reply requested\n");
+		goto out;
+	}
+	if(ret < 0) {
+		ERR("send_command failed: %d\n", ret);
+		goto out;
+	}
+	reply = recv_command(astribank, TIMEOUT);
+	if(!reply) {
+		ERR("recv_command failed\n");
+		ret = -EPROTO;
+		goto out;
+	}
+	*reply_ref = reply;
+	if((reply->header.op & 0x80) != 0x80) {
+		ERR("Unexpected reply op=0x%02X, should have MSB set.\n", reply->header.op);
+		ret = -EPROTO;
+		goto out;
+	}
+	DBG("REPLY OP: 0x%X\n", reply->header.op);
+	reply_desc = get_command_desc(astribank->mpp_proto_version, reply->header.op);
+	if(!reply_desc) {
+		ERR("Unknown reply op=0x%02X\n", reply->header.op);
+		ret = -EPROTO;
+		goto out;
+	}
+	DBG("REPLY NAME: %s\n", reply_desc->name);
+	if(reply->header.op == MPP_ACK) {
+		int	status = CMD_FIELD(reply, ACK, stat);
+
+		if(expected) {
+			ERR("Expected OP=0x%02X: Got ACK(%d): %s\n",
+				reply_op, status, ack_status_msg(status));
+			ret = -EPROTO;
+			goto out;
+		} else if(status != STAT_OK) {
+
+			ERR("Got ACK (for OP=0x%X [%s]): %d - %s\n",
+				cmd->header.op,
+				cmd_desc->name,
+				status,
+				ack_status_msg(status));
+#if 0
+			extern	FILE	*fp;
+			if(fp) {
+				fprintf(fp, "Got ACK(%d)\n", status);
+			}
+#endif
+			ret = -EPROTO;
+			goto out;
+		}
+		/* Good expected ACK ... */
+	} else if(reply->header.op != reply_op) {
+			ERR("Expected OP=0x%02X: Got OP=0x%02X\n",
+				reply_op, reply->header.op);
+			ret = -EPROTO;
+			goto out;
+	}
+	if(expected && expected->op != MPP_SER_RECV && expected->len != reply->header.len) {
+			ERR("Expected len=%d: Got len=%d\n",
+				expected->len, reply->header.len);
+			ret = -EPROTO;
+			goto out;
+	}
+	if(cmd->header.seq != reply->header.seq) {
+			ERR("Expected seq=%d: Got seq=%d\n",
+				cmd->header.seq, reply->header.seq);
+			ret = -EPROTO;
+			goto out;
+	}
+	ret = reply->header.len;	/* All good, return the length */
+	DBG("returning reply op 0x%X (%d bytes)\n", reply->header.op, ret);
+out:
+	free_command(cmd);
+	if(!reply_ref && reply)
+		free_command(reply);
+	return ret;
+}
+
+static int set_ihex_version(char *dst, const char *src)
+{
+	memcpy(dst, src, VERSION_LEN);
+	return 0;
+}
+
+/*
+ * Protocol Commands
+ */
+
+int mpp_proto_query(struct astribank_device *astribank)
+{
+	struct mpp_command	*cmd;
+	struct mpp_command	*reply;
+	int			ret;
+
+	DBG("\n");
+	assert(astribank != NULL);
+	if((cmd = new_command(astribank->mpp_proto_version, MPP_PROTO_QUERY, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	CMD_FIELD(cmd, PROTO_QUERY, proto_version) = MPP_PROTOCOL_VERSION;	/* Protocol Version */
+	ret = process_command(astribank, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	astribank->mpp_proto_version = CMD_FIELD(reply, PROTO_REPLY, proto_version);
+	if(! MPP_SUPPORTED_VERSION(astribank->mpp_proto_version)) {
+		ERR("Got mpp protocol version: %02x (expected %02x)\n",
+			astribank->mpp_proto_version,
+			MPP_PROTOCOL_VERSION);
+		ret = -EPROTO;
+		goto out;
+	}
+	if(astribank->mpp_proto_version != MPP_PROTOCOL_VERSION) {
+		ERR("Deprecated (but working) MPP protocol version [%X]. Please upgrade to [%X] ASAP\n",
+			astribank->mpp_proto_version, MPP_PROTOCOL_VERSION);
+	}
+	DBG("Protocol version: %02x\n", astribank->mpp_proto_version);
+	ret = astribank->mpp_proto_version;
+	free_command(reply);
+out:
+	return ret;
+}
+
+int mpp_status_query(struct astribank_device *astribank)
+{
+	struct mpp_command	*cmd;
+	struct mpp_command	*reply;
+	int			ret;
+
+	DBG("\n");
+	assert(astribank != NULL);
+	if((cmd = new_command(astribank->mpp_proto_version, MPP_STATUS_GET, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	ret = process_command(astribank, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	astribank->eeprom_type = 0x3 & (CMD_FIELD(reply, STATUS_GET_REPLY, i2cs_data) >> 3);
+	astribank->status = CMD_FIELD(reply, STATUS_GET_REPLY, status);
+	astribank->fw_versions = CMD_FIELD(reply, STATUS_GET_REPLY, fw_versions);
+	DBG("EEPROM TYPE: %02x\n", astribank->eeprom_type);
+	DBG("FPGA Firmware: %s\n", (astribank->status & 0x1) ? "Loaded" : "Empty");
+	DBG("Firmware Versions: USB='%s' FPGA='%s' EEPROM='%s'\n",
+		astribank->fw_versions.usb,
+		astribank->fw_versions.fpga,
+		astribank->fw_versions.eeprom);
+	free_command(reply);
+	return ret;
+}
+
+int mpp_eeprom_set(struct astribank_device *astribank, const struct eeprom_table *et)
+{
+	struct mpp_command	*cmd;
+	struct mpp_command	*reply;
+	int			ret;
+
+	DBG("\n");
+	assert(astribank != NULL);
+	if((cmd = new_command(astribank->mpp_proto_version, MPP_EEPROM_SET, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	memcpy(&CMD_FIELD(cmd, EEPROM_SET, data), et, sizeof(*et));
+	ret = process_command(astribank, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	free_command(reply);
+	return 0;
+}
+
+int mpp_renumerate(struct astribank_device *astribank)
+{
+	struct mpp_command	*cmd;
+	int			ret;
+
+	DBG("\n");
+	assert(astribank != NULL);
+	if((cmd = new_command(astribank->mpp_proto_version, MPP_RENUM, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	ret = process_command(astribank, cmd, NULL);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	return 0;
+}
+
+int mpp_caps_get(struct astribank_device *astribank,
+	struct eeprom_table *eeprom_table,
+	struct capabilities *capabilities,
+	struct capkey *key)
+{
+	struct mpp_command	*cmd;
+	struct mpp_command	*reply;
+	int			ret;
+
+	DBG("\n");
+	assert(astribank != NULL);
+	if((cmd = new_command(astribank->mpp_proto_version, MPP_CAPS_GET, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	ret = process_command(astribank, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	assert(reply->header.op == MPP_CAPS_GET_REPLY);
+	if(eeprom_table) {
+		memcpy(eeprom_table, (void *)&CMD_FIELD(reply, CAPS_GET_REPLY, data), sizeof(*eeprom_table));
+	}
+	if(capabilities) {
+		const struct capabilities	*cap = &CMD_FIELD(reply, CAPS_GET_REPLY, capabilities);
+
+		memcpy(capabilities, cap, sizeof(*capabilities));
+	}
+	if(key) {
+		const struct capkey	*k = &CMD_FIELD(reply, CAPS_GET_REPLY, key);
+
+		memcpy(key, k, sizeof(*key));
+	}
+	free_command(reply);
+	return 0;
+}
+
+int mpp_caps_set(struct astribank_device *astribank,
+	const struct eeprom_table *eeprom_table,
+	const struct capabilities *capabilities,
+	const struct capkey *key)
+{
+	struct mpp_command	*cmd;
+	struct mpp_command	*reply;
+	int			ret;
+
+	DBG("\n");
+	assert(astribank != NULL);
+	if((cmd = new_command(astribank->mpp_proto_version, MPP_CAPS_SET, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	memcpy(&CMD_FIELD(cmd, CAPS_SET, data), eeprom_table, sizeof(*eeprom_table));
+	memcpy(&CMD_FIELD(cmd, CAPS_SET, capabilities), capabilities, sizeof(*capabilities));
+	memcpy(&CMD_FIELD(cmd, CAPS_SET, key), key, sizeof(*key));
+	ret = process_command(astribank, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	free_command(reply);
+	return 0;
+}
+
+int mpp_extrainfo_get(struct astribank_device *astribank, struct extrainfo *info)
+{
+	struct mpp_command	*cmd;
+	struct mpp_command	*reply;
+	int			ret;
+
+	DBG("\n");
+	assert(astribank != NULL);
+	if((cmd = new_command(astribank->mpp_proto_version, MPP_EXTRAINFO_GET, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	ret = process_command(astribank, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	assert(reply->header.op == MPP_EXTRAINFO_GET_REPLY);
+	if(info) {
+		memcpy(info, (void *)&CMD_FIELD(reply, EXTRAINFO_GET_REPLY, info), sizeof(*info));
+	}
+	free_command(reply);
+	return 0;
+}
+
+int mpp_extrainfo_set(struct astribank_device *astribank, const struct extrainfo *info)
+{
+	struct mpp_command	*cmd;
+	struct mpp_command	*reply;
+	int			ret;
+
+	DBG("\n");
+	assert(astribank != NULL);
+	if((cmd = new_command(astribank->mpp_proto_version, MPP_EXTRAINFO_SET, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	memcpy(&CMD_FIELD(cmd, EXTRAINFO_SET, info), info, sizeof(*info));
+	ret = process_command(astribank, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	free_command(reply);
+	return 0;
+}
+
+int mpp_eeprom_blk_rd(struct astribank_device *astribank, uint8_t *buf, uint16_t offset, uint16_t len)
+{
+	struct mpp_command	*cmd;
+	struct mpp_command	*reply;
+	int			ret;
+	int			size;
+
+	DBG("len = %d, offset = %d\n", len, offset);
+	assert(astribank != NULL);
+	if((cmd = new_command(astribank->mpp_proto_version, MPP_EEPROM_BLK_RD, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	CMD_FIELD(cmd, EEPROM_BLK_RD, len) = len;
+	CMD_FIELD(cmd, EEPROM_BLK_RD, offset) = offset;
+	ret = process_command(astribank, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		size = ret;
+		goto out;
+	}
+	size = reply->header.len - sizeof(struct mpp_header) - sizeof(struct d_EEPROM_BLK_RD_REPLY);
+	INFO("size=%d offset=0x%X\n", size, CMD_FIELD(reply, EEPROM_BLK_RD_REPLY, offset));
+	dump_packet(LOG_DEBUG, "BLK_RD", (char *)reply, ret);
+	if(size > len) {
+		ERR("Truncating reply (was %d, now %d)\n", size, len);
+		size = len;
+	}
+	memcpy(buf, CMD_FIELD(reply, EEPROM_BLK_RD_REPLY, data), size);
+out:
+	free_command(reply);
+	return size;
+}
+
+int mpp_send_start(struct astribank_device *astribank, enum dev_dest dest, const char *ihex_version)
+{
+	struct mpp_command	*cmd;
+	struct mpp_command	*reply = NULL;
+	int			ret = 0;
+
+	DBG("dest = %s ihex_version = '%s'\n", dev_dest2str(dest), ihex_version);
+	assert(astribank != NULL);
+	if((cmd = new_command(astribank->mpp_proto_version, MPP_DEV_SEND_START, 0)) == NULL) {
+		ERR("new_command failed\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+	CMD_FIELD(cmd, DEV_SEND_START, dest) = dest;
+	set_ihex_version(CMD_FIELD(cmd, DEV_SEND_START, ihex_version), ihex_version);
+	ret = process_command(astribank, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		goto out;
+	}
+out:
+	if(reply)
+		free_command(reply);
+	astribank->burn_state = (ret == 0)
+		? BURN_STATE_STARTED
+		: BURN_STATE_FAILED;
+	return ret;
+}
+
+int mpp_send_end(struct astribank_device *astribank)
+{
+	struct mpp_command	*cmd;
+	struct mpp_command	*reply = NULL;
+	int			ret = 0;
+
+	DBG("\n");
+	assert(astribank != NULL);
+	if((cmd = new_command(astribank->mpp_proto_version, MPP_DEV_SEND_END, 0)) == NULL) {
+		ERR("new_command failed\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+	ret = process_command(astribank, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		goto out;
+	}
+out:
+	if(reply)
+		free_command(reply);
+	astribank->burn_state = (ret == 0)
+		? BURN_STATE_ENDED
+		: BURN_STATE_FAILED;
+	return ret;
+}
+
+int mpp_send_seg(struct astribank_device *astribank, const uint8_t *data, uint16_t offset, uint16_t len)
+{
+	struct mpp_command	*cmd;
+	struct mpp_command	*reply;
+	int			ret;
+
+	if(!astribank->burn_state == BURN_STATE_STARTED) {
+		ERR("Tried to send a segment while burn_state=%d\n",
+				astribank->burn_state);
+		return -EINVAL;
+	}
+	DBG("len = %d, offset = %d (0x%02X, 0x%02X)\n", len, offset, *data, *(data + 1));
+	assert(astribank != NULL);
+	if((cmd = new_command(astribank->mpp_proto_version, MPP_DEV_SEND_SEG, len)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	CMD_FIELD(cmd, DEV_SEND_SEG, offset) = offset;
+	memcpy(CMD_FIELD(cmd, DEV_SEND_SEG, data), data, len);
+#if 0
+	{
+		FILE			*fp;
+		if((fp = fopen("seg_data.bin", "a")) == NULL) {
+			perror("seg_data.bin");
+			exit(1);
+		}
+		if(fwrite(CMD_FIELD(cmd, DEV_SEND_SEG, data), len, 1, fp) != 1) {
+			perror("fwrite");
+			exit(1);
+		}
+		fclose(fp);
+	}
+#endif
+	ret = process_command(astribank, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	free_command(reply);
+	return 0;
+}
+
+int mpp_reset(struct astribank_device *astribank, int full_reset)
+{
+	struct mpp_command	*cmd;
+	int			ret;
+	int			op = (full_reset) ? MPP_RESET: MPP_HALF_RESET;
+
+	DBG("full = %s\n", (full_reset) ? "YES" : "NO");
+	assert(astribank != NULL);
+	if((cmd = new_command(astribank->mpp_proto_version, op, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	ret = process_command(astribank, cmd, NULL);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	return 0;
+}
+
+int mpp_serial_cmd(struct astribank_device *astribank, const uint8_t *in, uint8_t *out, uint16_t len)
+{
+	struct mpp_command	*cmd;
+	struct mpp_command	*reply;
+	int			ret;
+	uint8_t			*data;
+
+	DBG("len=%d\n", len);
+	assert(astribank != NULL);
+	if((cmd = new_command(astribank->mpp_proto_version, MPP_SER_SEND, len)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	data = CMD_FIELD(cmd, SER_SEND, data);
+	memcpy(data, in, len);
+	ret = process_command(astribank, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	assert(reply->header.op == MPP_SER_RECV);
+	data = CMD_FIELD(reply, SER_RECV, data);
+	memcpy(out, data, len);
+	free_command(reply);
+	return 0;
+}
+
+int mpps_card_info(struct astribank_device *astribank, int unit, uint8_t *card_type, uint8_t *card_status)
+{
+	struct card_info_send {
+		uint8_t	ser_op;
+		uint8_t	addr;
+	} *card_info_send;
+	struct card_info_recv {
+		uint8_t	ser_op_undef;	/* invalid data */
+		uint8_t	addr;
+		uint8_t	card_full_type;	/* (type << 4 | subtype) */
+		uint8_t	card_status;	/* BIT(0) - PIC burned */
+	} *card_info_recv;
+	uint8_t	in[sizeof(struct card_info_recv)];
+	uint8_t	out[sizeof(struct card_info_recv)];
+	int	len;
+	int	ret;
+
+	len = sizeof(struct card_info_recv);
+	memset(in, 0, len);
+	memset(out, 0, len);
+	card_info_send = (struct card_info_send *)∈
+	card_info_recv = (struct card_info_recv *)&out;
+	card_info_send->ser_op = SER_CARD_INFO_GET;
+	card_info_send->addr = (unit << 4);	/* low nibble is subunit */
+	ret = mpp_serial_cmd(astribank, in, out, len);
+	if(ret < 0)
+		return ret;
+	*card_type = card_info_recv->card_full_type;
+	*card_status = card_info_recv->card_status;
+	return 0;
+}
+
+int mpp_tws_watchdog(struct astribank_device *astribank)
+{
+	struct mpp_command	*cmd;
+	struct mpp_command	*reply;
+	int			ret;
+
+	DBG("\n");
+	assert(astribank != NULL);
+	if((cmd = new_command(astribank->mpp_proto_version, MPP_TWS_WD_MODE_GET, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	ret = process_command(astribank, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	ret = CMD_FIELD(reply, TWS_WD_MODE_GET_REPLY, wd_active);
+	DBG("wd_active=0x%X\n", ret);
+	free_command(reply);
+	return ret == 1;
+}
+
+int mpp_tws_setwatchdog(struct astribank_device *astribank, int yes)
+{
+	struct mpp_command	*cmd;
+	struct mpp_command	*reply;
+	int			ret;
+
+	DBG("%s\n", (yes) ? "YES" : "NO");
+	assert(astribank != NULL);
+	if((cmd = new_command(astribank->mpp_proto_version, MPP_TWS_WD_MODE_SET, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	CMD_FIELD(cmd, TWS_WD_MODE_SET, wd_active) = (yes) ? 1 : 0;
+	ret = process_command(astribank, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	free_command(reply);
+	return 0;
+}
+
+int mpp_tws_powerstate(struct astribank_device *astribank)
+{
+	struct mpp_command	*cmd;
+	struct mpp_command	*reply;
+	int			ret;
+
+	DBG("\n");
+	assert(astribank != NULL);
+	if((cmd = new_command(astribank->mpp_proto_version, MPP_TWS_PWR_GET, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	ret = process_command(astribank, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	ret = CMD_FIELD(reply, TWS_PWR_GET_REPLY, power);
+	DBG("power=0x%X\n", ret);
+	free_command(reply);
+	return ret;
+}
+
+int mpp_tws_portnum(struct astribank_device *astribank)
+{
+	struct mpp_command	*cmd;
+	struct mpp_command	*reply;
+	int			ret;
+
+	DBG("\n");
+	assert(astribank != NULL);
+	if((cmd = new_command(astribank->mpp_proto_version, MPP_TWS_PORT_GET, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	ret = process_command(astribank, cmd, &reply);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	ret = CMD_FIELD(reply, TWS_PORT_GET_REPLY, portnum);
+	DBG("portnum=0x%X\n", ret);
+	free_command(reply);
+	return ret;
+}
+
+int mpp_tws_setportnum(struct astribank_device *astribank, uint8_t portnum)
+{
+	struct mpp_command	*cmd;
+	int			ret;
+
+	DBG("\n");
+	assert(astribank != NULL);
+	if(portnum >= 2) {
+		ERR("Invalid portnum (%d)\n", portnum);
+		return -EINVAL;
+	}
+	if((cmd = new_command(astribank->mpp_proto_version, MPP_TWS_PORT_SET, 0)) == NULL) {
+		ERR("new_command failed\n");
+		return -ENOMEM;
+	}
+	CMD_FIELD(cmd, TWS_PORT_SET, portnum) = portnum;
+	ret = process_command(astribank, cmd, NULL);
+	if(ret < 0) {
+		ERR("process_command failed: %d\n", ret);
+		return ret;
+	}
+	return 0;
+}
+
+/*
+ * Wrappers
+ */
+
+struct astribank_device *mpp_init(const char devpath[])
+{
+	struct astribank_device *astribank;
+	int			ret;
+
+	DBG("devpath='%s'\n", devpath);
+	if((astribank = astribank_open(devpath, 1)) == NULL) {
+		ERR("Opening astribank failed\n");
+		return NULL;
+	}
+	ret = mpp_proto_query(astribank);
+	if(ret < 0) {
+		ERR("Protocol handshake failed: %d\n", ret);
+		goto err;
+	}
+	ret = mpp_status_query(astribank);
+	if(ret < 0) {
+		ERR("Status query failed: %d\n", ret);
+		goto err;
+	}
+	return astribank;
+
+err:
+	if (astribank)
+		astribank_close(astribank, 0);
+	return NULL;
+}
+
+void mpp_exit(struct astribank_device *astribank)
+{
+	DBG("\n");
+	astribank_close(astribank, 0);
+}
+
+/*
+ * data structures
+ */
+
+void show_eeprom(const struct eeprom_table *eprm, FILE *fp)
+{
+	int	rmajor = (eprm->release >> 8) & 0xFF;
+	int	rminor = eprm->release & 0xFF;;
+	char	buf[BUFSIZ];
+
+	memset(buf, 0, LABEL_SIZE + 1);
+	memcpy(buf, eprm->label, LABEL_SIZE);
+	fprintf(fp, "EEPROM: %-15s: 0x%02X\n", "Source", eprm->source);
+	fprintf(fp, "EEPROM: %-15s: 0x%04X\n", "Vendor", eprm->vendor);
+	fprintf(fp, "EEPROM: %-15s: 0x%04X\n", "Product", eprm->product);
+	fprintf(fp, "EEPROM: %-15s: %d.%d\n", "Release", rmajor, rminor);
+	fprintf(fp, "EEPROM: %-15s: 0x%02X\n", "Config", eprm->config_byte);
+	fprintf(fp, "EEPROM: %-15s: '%s'\n", "Label", buf);
+}
+
+void show_capabilities(const struct capabilities *capabilities, FILE *fp)
+{
+	fprintf(fp, "Capabilities: FXS ports: %2d\n", capabilities->ports_fxs);
+	fprintf(fp, "Capabilities: FXO ports: %2d\n", capabilities->ports_fxo);
+	fprintf(fp, "Capabilities: BRI ports: %2d\n", capabilities->ports_bri);
+	fprintf(fp, "Capabilities: PRI ports: %2d\n", capabilities->ports_pri);
+	fprintf(fp, "Capabilities: TwinStar : %s\n",
+		(CAP_EXTRA_TWINSTAR(capabilities)) ? "Yes" : "No");
+}
+
+void show_astribank_status(struct astribank_device *astribank, FILE *fp)
+{
+	char	version_buf[BUFSIZ];
+	int	is_loaded = STATUS_FPGA_LOADED(astribank->status);
+
+	fprintf(fp, "Astribank: EEPROM      : %s\n",
+		eeprom_type2str(astribank->eeprom_type));
+	fprintf(fp, "Astribank: FPGA status : %s\n",
+		is_loaded ? "Loaded" : "Empty");
+	if(is_loaded) {
+		memset(version_buf, 0, sizeof(version_buf));
+		memcpy(version_buf, astribank->fw_versions.fpga, VERSION_LEN);
+		fprintf(fp, "Astribank: FPGA version: %s\n",
+			version_buf);
+	}
+}
+
+void show_extrainfo(const struct extrainfo *extrainfo, FILE *fp)
+{
+	fprintf(fp, "Extrainfo:             : %s\n", (const char *)(extrainfo->text));
+}
+
+int twinstar_show(struct astribank_device *astribank, FILE *fp)
+{
+	int	watchdog;
+	int	powerstate;
+	int	portnum;
+	int	i;
+
+	if(!astribank_has_twinstar(astribank)) {
+		fprintf(fp, "TwinStar: NO\n");
+		return 0;
+	}
+	if((watchdog = mpp_tws_watchdog(astribank)) < 0) {
+		ERR("Failed getting TwinStar information\n");
+		return watchdog;
+	}
+	if((powerstate = mpp_tws_powerstate(astribank)) < 0) {
+		ERR("Failed getting TwinStar powerstate\n");
+		return powerstate;
+	}
+	if((portnum = mpp_tws_portnum(astribank)) < 0) {
+		ERR("Failed getting TwinStar portnum\n");
+		return portnum;
+	}
+	fprintf(fp, "TwinStar: Connected to : USB-%1d\n", portnum);
+	fprintf(fp, "TwinStar: Watchdog     : %s\n",
+		(watchdog) ? "on-guard" : "off-guard");
+	for(i = 0; i < 2; i++) {
+		int	pw = (1 << i) & powerstate; 
+
+		fprintf(fp, "TwinStar: USB-%1d POWER  : %s\n",
+			i, (pw) ? "ON" : "OFF");
+	}
+	return 0;
+}
+
diff --git a/xpp/mpp_funcs.h b/xpp/mpp_funcs.h
new file mode 100644
index 0000000..59bbc7d
--- /dev/null
+++ b/xpp/mpp_funcs.h
@@ -0,0 +1,80 @@
+#ifndef	MPP_FUNCS_H
+#define	MPP_FUNCS_H
+/*
+ * Written by Oron Peled <oron at actcom.co.il>
+ * Copyright (C) 2008, Xorcom
+ *
+ * All rights reserved.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "mpp.h"
+#include "astribank_usb.h"
+
+#define	TIMEOUT	2000
+
+/* high-level */
+struct astribank_device *mpp_init(const char devpath[]);
+void mpp_exit(struct astribank_device *astribank);
+int mpp_proto_query(struct astribank_device *astribank);
+int mpp_status_query(struct astribank_device *astribank);
+int mpp_eeprom_set(struct astribank_device *astribank, const struct eeprom_table *et);
+int mpp_renumerate(struct astribank_device *astribank);
+int mpp_caps_get(struct astribank_device *astribank,
+		struct eeprom_table *et,
+		struct capabilities *cap,
+		struct capkey *key);
+int mpp_caps_set(struct astribank_device *astribank,
+		const struct eeprom_table *eeprom_table,
+		const struct capabilities *capabilities,
+		const struct capkey *key);
+int mpp_extrainfo_get(struct astribank_device *astribank, struct extrainfo *info);
+int mpp_extrainfo_set(struct astribank_device *astribank, const struct extrainfo *info);
+int mpp_eeprom_blk_rd(struct astribank_device *astribank, uint8_t *buf, uint16_t offset, uint16_t len);
+int mpp_send_start(struct astribank_device *astribank, enum dev_dest dest, const char *ihex_version);
+int mpp_send_end(struct astribank_device *astribank);
+int mpp_send_seg(struct astribank_device *astribank, const uint8_t *data, uint16_t offset, uint16_t len);
+int mpp_reset(struct astribank_device *astribank, int full_reset);
+int mpp_serial_cmd(struct astribank_device *astribank, const uint8_t *in, uint8_t *out, uint16_t len);
+void show_eeprom(const struct eeprom_table *eprm, FILE *fp);
+void show_capabilities(const struct capabilities *capabilities, FILE *fp);
+void show_astribank_status(struct astribank_device *astribank, FILE *fp);
+void show_extrainfo(const struct extrainfo *extrainfo, FILE *fp);
+int twinstar_show(struct astribank_device *astribank, FILE *fp);
+
+/*
+ * Serial commands to FPGA
+ */
+int mpps_card_info(struct astribank_device *astribank, int unit, uint8_t *card_type, uint8_t *card_status);
+
+/*
+ * Twinstar
+ */
+int mpp_tws_watchdog(struct astribank_device *astribank);
+int mpp_tws_setwatchdog(struct astribank_device *astribank, int yes);
+int mpp_tws_powerstate(struct astribank_device *astribank);
+int mpp_tws_portnum(struct astribank_device *astribank);
+int mpp_tws_setportnum(struct astribank_device *astribank, uint8_t portnum);
+
+/* low-level */
+int process_command(struct astribank_device *astribank, struct mpp_command *cmd, struct mpp_command **reply_ref);
+struct mpp_command *new_command(uint8_t protocol_version, uint8_t op, uint16_t extra_data);
+void free_command(struct mpp_command *cmd);
+
+const char *dev_dest2str(enum dev_dest dest);
+
+#endif	/* MPP_FUNCS_H */
diff --git a/xpp/perl_modules/Dahdi.pm b/xpp/perl_modules/Dahdi.pm
new file mode 100644
index 0000000..e17b939
--- /dev/null
+++ b/xpp/perl_modules/Dahdi.pm
@@ -0,0 +1,79 @@
+package Dahdi;
+#
+# Written by Oron Peled <oron at actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use Dahdi::Span;
+
+=head1 NAME
+
+Dahdi - Perl interface to Dahdi information
+
+This package allows access from Perl to information about Dahdi
+hardware and loaded Dahdi devices.
+
+=head1 SYNOPSIS
+
+  # Listing channels in analog spans:
+  use Dahdi;
+  # scans system:
+  my @spans = Dahdi::spans();
+  for my $span (@spans) {
+    next if ($span->is_digital);
+     $span->num. " - [". $span->type ."] ". $span->name. "\n";
+    for my $chan ($span->chans) {
+      print " - ".$chan->num . " - [". $chan->type. "] ". $chan->fqn". \n";
+    }
+  }
+=cut
+
+our $virt_base;
+our $proc_dahdi_base;
+our $proc_xpp_base;
+our $proc_usb_base;
+our $sys_base;
+
+=head1 spans()
+
+Returns a list of span objects, ordered by span number.
+
+=cut
+
+sub spans() {
+	my @spans;
+
+	-d $proc_dahdi_base or return ();
+	foreach my $zfile (glob "$proc_dahdi_base/*") {
+		next unless ($zfile =~ m{^$proc_dahdi_base/\d+$});
+		my $span = Dahdi::Span->new($zfile);
+		push(@spans, $span);
+	}
+	@spans = sort { $a->num <=> $b->num } @spans;
+	return @spans;
+}
+
+=head1 ENVIRONMENT
+
+If C<DAHDI_VIRT_TOP> is set in the environment, it will be considered
+as a path to a directory that holds a dump (copy) of all the required
+files from /proc and /sys . You can generate that directory using the
+script C<build_tools/dump_sys_state> .
+
+=head1 SEE ALSO
+
+Span objects: L<Dahdi::Span>.
+
+Dahdi channels objects: L<Dahdi::Chan>.
+
+Dahdi hardware devices information: L<Dahdi::Hardware>.
+
+Xorcom Astribank -specific information: L<Dahdi::Xpp>.
+
+=cut
+
+1;
diff --git a/xpp/perl_modules/Dahdi/Chans.pm b/xpp/perl_modules/Dahdi/Chans.pm
new file mode 100644
index 0000000..a869ae4
--- /dev/null
+++ b/xpp/perl_modules/Dahdi/Chans.pm
@@ -0,0 +1,264 @@
+package Dahdi::Chans;
+#
+# Written by Oron Peled <oron at actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use Dahdi::Utils;
+
+=head1 NAME
+
+Dahdi::Chans - Perl interface to a Dahdi channel information
+
+This package allows access from perl to information about a Dahdi
+channel. It is part of the Dahdi Perl package.
+
+=head1 alarms()
+
+In an array context returns a list of alarm strings (RED, BLUE, etc.)
+for this channel (an empty list == false if there are no alarms).
+In scalar context returns the number of alarms for a specific channel.
+
+=head1 battery()
+
+Returns 1 if channel reports to have battery (A remote PBX connected to
+an FXO port), 0 if channel reports to not have battery and C<undef>
+otherwise.
+
+Currently only wcfxo and Astribank FXO modules report battery. For the
+rest of the channels 
+
+=head1 fqn()
+
+(Fully Qualified Name) Returns the full "name" of the channel.
+
+=head1 index()
+
+Returns the number of this channel (in the span).
+
+=head1 num()
+
+Returns the number of this channel as a Dahdi channel.
+
+=head signalling()
+
+Returns the signalling set for this channel through /etc/dahdi/system.conf .
+This is always empty before dahdi_cfg was run. And shows the "other" type
+for FXS and for FXO.
+
+=head1 span()
+
+Returns a reference to the span to which this channel belongs.
+
+=head1 type()
+
+Returns the type of the channel: 'FXS', 'FXO', 'EMPTY', etc.
+
+=cut
+
+my @alarm_types = qw(BLUE YELLOW RED LOOP RECOVERING NOTOPEN);
+
+# Taken from dahdi-base.c
+my @sigtypes = (
+	"FXSLS",
+	"FXSKS",
+	"FXSGS",
+	"FXOLS",
+	"FXOKS",
+	"FXOGS",
+	"E&M-E1",
+	"E&M",
+	"Clear",
+	"HDLCRAW",
+	"HDLCFCS",
+	"HDLCNET",
+	"Hardware-assisted HDLC",
+	"MTP2",
+	"Slave",
+	"CAS",
+	"DACS",
+	"DACS+RBS",
+	"SF (ToneOnly)",
+	"Unconfigured",
+	"Reserved"
+	);
+
+sub new($$$$$$) {
+	my $pack = shift or die "Wasn't called as a class method\n";
+	my $span = shift or die "Missing a span parameter\n";
+	my $index = shift;
+	my $line = shift or die "Missing an input line\n";
+	defined $index or die "Missing an index parameter\n";
+	my $self = {
+			'SPAN' => $span,
+			'INDEX' => $index,
+		};
+	bless $self, $pack;
+	my ($num, $fqn, $rest) = split(/\s+/, $line, 3);
+	$num or die "Missing a channel number parameter\n";
+	$fqn or die "Missing a channel fqn parameter\n";
+	my $signalling = '';
+	my @alarms = ();
+	my $info = '';
+	if(defined $rest) {
+		# remarks in parenthesis (In use), (no pcm)
+		while($rest =~ s/\s*(\([^)]+\))\s*/ /) {
+			$info .= " $1";
+		}
+		# Alarms
+		foreach my $alarm (@alarm_types) {
+			if($rest =~ s/\s*(\b${alarm}\b)\s*/ /) {
+				push(@alarms, $1);
+			}
+		}
+		foreach my $sig (@sigtypes) {
+			if($rest =~ s/^\Q$sig\E/ /) {
+				$signalling = $sig;
+				last;
+			}
+		}
+		warn "Unrecognized garbage '$rest' in $fqn\n"
+			if $rest =~ /\S/;
+	}
+	$self->{NUM} = $num;
+	$self->{FQN} = $fqn;
+	$self->{SIGNALLING} = $signalling;
+	$self->{ALARMS} = \@alarms;
+	$self->{INFO} = $info;
+	my $type;
+	if($fqn =~ m|\bXPP_(\w+)/.*$|) {
+		$type = $1;		# An Astribank
+	} elsif ($fqn =~ m{\bWCFXO/.*}) {
+		$type = "FXO"; # wcfxo - x100p and relatives.
+		# A single port card. The driver issue RED alarm when
+		# There's no better
+		$self->{BATTERY} = !($span->description =~ /\bRED\b/);
+	} elsif ($fqn =~ m{\bFXS/.*}) {
+		$type = "FXS"; # likely Rhino
+	} elsif ($fqn =~ m{\bFXO/.*}) {
+		$type = "FXO"; # likely Rhino
+	} elsif ($fqn =~ m{---/.*}) {
+		$type = "EMPTY"; # likely Rhino, empty slot.
+	} elsif ($fqn =~ m{\b(TE[24]|WCT1|Tor2|TorISA|WP[TE]1|cwain[12]|R[124]T1|AP40[124]|APE40[124])/.*}) {
+		# TE[24]: Digium wct4xxp
+		# WCT1: Digium single span card drivers?
+		# Tor2: Tor PCI cards
+		# TorISA: ISA ones (still used?) 
+		# WP[TE]1: Sangoma. TODO: this one tells us if it is TE or NT.
+		# cwain: Junghanns E1 card.
+		# R[124]: Rhino r1t1/rxt1 cards
+		# AP40[124]: Aligera AP40X cards
+		# APE40[124]: Aligera APE40X cards
+		$type = "PRI";
+	} elsif ($fqn =~ m{\b(WCBRI|B4|ZTHFC\d*|ztqoz\d*)/.*}) {
+		# WCBRI: The Digium Hx8 series cards with BRI module.
+		# B4: The Digium wcb4xxp DAHDI driver
+		# ZTHFC: HFC-s single-port card (zaphfc/vzaphfc)
+		# ztqoz: qozap (Junghanns) multi-port HFC card
+		$type = "BRI";
+        } elsif ($fqn =~ m{\bDYN/.*}) {
+                # DYN : Dynamic span (TDMOE)
+                $type = "DYN"
+	} elsif ($fqn =~ m{\bztgsm/.*}) {
+		# Junghanns GSM card
+		$type = "GSM";
+	} elsif($signalling ne '') {
+		$type = 'FXO' if $signalling =~ /^FXS/;
+		$type = 'FXS' if $signalling =~ /^FXO/;
+	} else {
+		$type = $self->probe_type();
+	}
+	$self->type($type);
+	$self->span()->type($type)
+		if ! defined($self->span()->type()) ||
+			$self->span()->type() eq 'UNKNOWN';
+	return $self;
+}
+
+=head1 probe_type()
+
+In the case of some cards, the information in /proc/dahdi is not good
+enough to tell the type of each channel. In this case an extra explicit
+probe is needed.
+
+Currently this is implemented by using some invocations of dahdi_cfg(8).
+
+It may later be replaced by dahdi_scan(8).
+
+=cut
+
+my $dahdi_cfg = $ENV{DAHDI_CFG} || '/usr/sbin/dahdi_cfg';
+sub probe_type($) {
+	my $self = shift;
+	my $fqn = $self->fqn;
+	my $num = $self->num;
+	my $type;
+
+	if($fqn =~ m:WCTDM/|WRTDM/|OPVXA1200/:) {
+		my %maybe;
+
+		undef %maybe;
+		foreach my $sig (qw(fxo fxs)) {
+			my $cmd = "echo ${sig}ks=$num | $dahdi_cfg -c /dev/fd/0";
+
+			$maybe{$sig} = system("$cmd >/dev/null 2>&1") == 0;
+		}
+		if($maybe{fxo} and $maybe{fxs}) {
+			$type = 'EMPTY';
+		} elsif($maybe{fxo}) {
+			$type = 'FXS';
+		} elsif($maybe{fxs}) {
+			$type = 'FXO';
+		} else {
+			$type = 'EMPTY';
+		}
+	} else {
+		$type = $self->type;
+	}
+	return $type;
+}
+
+sub battery($) {
+	my $self = shift or die;
+	my $span = $self->span or die;
+
+	return undef unless defined $self->type && $self->type eq 'FXO';
+	return $self->{BATTERY} if defined $self->{BATTERY};
+
+	my $xpd = $span->xpd;
+	my $index = $self->index;
+	return undef if !$xpd;
+
+	# It's an XPD (FXO)
+	my @lines = @{$xpd->lines};
+	my $line = $lines[$index];
+	return $line->battery;
+}
+
+sub alarms($) {
+	my $self = shift or die;
+	my @alarms = @{$self->{ALARMS}};
+
+	return @alarms;
+}
+
+sub blink($$) {
+	my $self = shift or die;
+	my $on = shift;
+	my $span = $self->span or die;
+
+	my $xpd = $span->xpd;
+	my $index = $self->index;
+	return undef if !$xpd;
+
+	my @lines = @{$xpd->lines};
+	my $line = $lines[$index];
+	return $line->blink($on);
+}
+
+
+1;
diff --git a/xpp/perl_modules/Dahdi/Config/Gen.pm b/xpp/perl_modules/Dahdi/Config/Gen.pm
new file mode 100644
index 0000000..cc439de
--- /dev/null
+++ b/xpp/perl_modules/Dahdi/Config/Gen.pm
@@ -0,0 +1,275 @@
+package Dahdi::Config::Gen;
+#
+# Written by Oron Peled <oron at actcom.co.il>
+# Copyright (C) 2009, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+
+=head1 NAME
+
+Dahdi::Config::Gen -- Wrapper class for configuration generators.
+
+=head1 SYNOPSIS
+
+ use Dahdi::Config::Gen qw(is_true);
+ my $params = Dahdi::Config::Params->new('the-config-file');
+ my $gconfig = Dahdi::Config::Gen->new($params);
+ my $num = $gconfig->{'base_exten'};
+ my $overlap = is_true($gconfig->{'brint_overlap'});
+ $gconfig->dump;	# For debugging
+ $gconfig->run_generator('system', {}, @spans);
+
+=head1 DESCRIPTION
+
+The constructor must be given an C<Dahdi::Config::Params> object.
+The returned object contains all data required for generation in the
+form of a hash.
+
+The constructor maps the C<item()>s from the parameter object into semantic
+configuration keys.  E.g: the C<lc_country> item is mapped to C<loadzone> and
+C<defaultzone> keys.
+
+The actual generation is done by delegation to one of the generators.
+This is done via the C<run_generator()> method which receive the
+generator name, a generator specific options hash and a list of
+span objects (from C<Dahdi::Span>) for which to generate configuration.
+
+This module contains few helper functions. E.g: C<is_true()>, C<bchan_range()>.
+
+=cut
+
+require Exporter;
+ at ISA = qw(Exporter);
+
+ at EXPORT_OK = qw(is_true);
+
+use strict;
+
+# Parse values as true/false 
+sub is_true($) {
+	my $val = shift;
+	return undef unless defined $val;
+	return $val =~ /^(1|y|yes)$/i;
+}
+
+sub range_string($$) {
+	my ($start, $end) = @_;
+
+	if($start == $end) {
+		sprintf "%d", $start;
+	} else {
+		sprintf "%d-%d", $start, $end;
+	}
+}
+
+# Generate channel range strings from arrays of chan numbers
+# E.g: "63-77,79-93"
+sub channo_range(@) {
+	my @channos = sort { $a <=> $b } @_;
+	my $first_num = $channos[0];
+	my $range_start = $first_num;
+	my @range;
+	my $prev = undef;
+
+	foreach my $c (@channos) {
+		my $curr = $c;
+		if(!defined($prev)) {
+			# First iteration
+			$prev = $curr;
+		} elsif($curr != $prev + 1) {
+			# New range
+			push(@range, range_string($range_start, $prev));
+			$range_start = $curr;
+		}
+		$prev = $curr;
+	}
+	if($prev >= $first_num) {
+		# Last range
+		push(@range, range_string($range_start, $prev));
+	}
+	return join(',', @range);
+}
+
+# Generate channel range strings from chan objects
+# E.g: "63-77,79-93"
+sub chan_range(@) {
+	my @chans = sort { $a->num <=> $b->num } @_;
+	my @channos = map { $_->num } @chans;
+	channo_range(@channos);
+}
+
+# Generate channel range strings from digital span objects
+# E.g: "63-77,79-93"
+sub bchan_range($) {
+	my $span = shift || die;
+	die unless $span->is_digital();
+	my $first_chan = ($span->chans())[0];
+	my $first_num = $first_chan->num();
+	my $bchan_ref = $span->bchan_list();
+	my @channos = map { $_ + $first_num } @{$bchan_ref};
+	channo_range(@channos);
+}
+
+# Returns a channel numbers array from a channel range string
+sub parse_chan_range($) {
+	my $rangestr = shift;
+	$rangestr =~ s/\s*//g;	# Squeeze
+	die "Bad characters in '$rangestr'" if $rangestr =~ /[^\d\s,-]/;
+	my @ranges = split(/,/, $rangestr);
+	my @channos;
+	my $last_end;
+
+	foreach my $range (@ranges) {
+		my ($start, $end) = split(/-/, $range, 2);
+		$end = $start unless defined $end;
+		die "Bad characters in '$start'" if $start =~ /\D/;
+		die "Bad characters in '$end'" if $end =~ /\D/;
+		die "Reversed range $end < $start" if $end < $start;
+		die "Channel number < 1" if $start < 1;
+		die "New range begins below previous $start <= $last_end" if defined($last_end) && $last_end >= $start;
+		for(my $i = $start + 0; $i <= $end; $i++) {
+			push(@channos, $i);
+		}
+		$last_end = $end;
+	}
+	return sort { $a <=> $b } @channos;
+}
+
+sub new($) {
+	my $pack = shift || die "$0: Missing package argument";
+	my $p = shift || die "$0: Missing parameters argument";
+
+	# Set defaults
+	my $fxs_default_start = $p->item('fxs_default_start');
+	my $fxo_default_start = $p->item('fxo_default_start');
+
+	my %default_context = (
+		FXO	=> $p->item('context_lines'),
+		FXS	=> $p->item('context_phones'),
+		IN	=> $p->item('context_input'),
+		OUT	=> $p->item('context_output'),
+		DYN	=> $p->item('context_lines'),
+		BRI_TE	=> $p->item('context_lines'),
+		BRI_NT	=> $p->item('context_lines'),
+		E1_TE	=> $p->item('context_lines'),
+		T1_TE	=> $p->item('context_lines'),
+		J1_TE	=> $p->item('context_lines'),
+		E1_NT	=> $p->item('context_lines'),
+		T1_NT	=> $p->item('context_lines'),
+		J1_NT	=> $p->item('context_lines'),
+		);
+	my %default_group = (
+		FXO	=> $p->item('group_lines'),
+		FXS	=> $p->item('group_phones'),
+		IN	=> '',
+		OUT	=> '',
+		DYN	=> '',
+		BRI_TE	=> $p->item('group_lines'),
+		BRI_NT	=> $p->item('group_lines'),
+		E1_TE	=> $p->item('group_lines'),
+		T1_TE	=> $p->item('group_lines'),
+		J1_TE	=> $p->item('group_lines'),
+		E1_NT	=> $p->item('group_lines'),
+		T1_NT	=> $p->item('group_lines'),
+		J1_NT	=> $p->item('group_lines'),
+		);
+	my %default_dahdi_signalling = (
+		FXO	=> "fxs$fxo_default_start",
+		FXS	=> "fxo$fxs_default_start",
+		IN	=> "fxo$fxs_default_start",
+		OUT	=> "fxo$fxs_default_start",
+		DYN	=> "clear",
+		);
+	my %default_chan_dahdi_signalling = (
+		FXO	=> "fxs_$fxo_default_start",
+		FXS	=> "fxo_$fxs_default_start",
+		IN	=> "fxo_$fxs_default_start",
+		OUT	=> "fxo_$fxs_default_start",
+		DYN	=> "auto", # Cheating. Won't really work
+		);
+
+	# First complex mapping
+	my $gconfig = {
+			PARAMETERS	=> $p,
+			'loadzone'	=> $p->item('lc_country'),
+			'defaultzone'	=> $p->item('lc_country'),
+			'context'	=> \%default_context,
+			'group'		=> \%default_group,
+			'dahdi_signalling'	=> \%default_dahdi_signalling,
+			'chan_dahdi_signalling'	=> \%default_chan_dahdi_signalling,
+		};
+	# Now add trivial mappings
+	my @trivial = qw(
+		base_exten
+		freepbx
+		fxs_immediate
+		bri_hardhdlc
+		bri_sig_style
+		r2_idle_bits
+		tdm_framing
+		echo_can
+		brint_overlap
+		pri_termtype
+		pri_connection_type
+		em_signalling
+		);
+	foreach my $k (@trivial) {
+		$gconfig->{$k} = $p->item($k);
+	}
+	bless $gconfig,$pack;
+
+	return $gconfig;
+}
+
+sub run_generator($$@) {
+	my $gconfig = shift || die;
+	my $name = shift || die "$0: Missing generator name argument";
+	my $genopts = shift || die "$0: Missing genopts argument";
+	ref($genopts) eq 'HASH' or die "$0: Bad genopts argument";
+	my @spans = @_;
+
+	my $module = "Dahdi::Config::Gen::$name";
+	#print STDERR "DEBUG: $module\n";
+	eval "use $module";
+	if($@) {
+		die "Failed to load configuration generator for '$name': $@\n";
+	}
+	my $cfg = $module->new($gconfig, $genopts);
+	$cfg->generate(@spans);
+}
+
+sub dump($) {
+	my $self = shift || die;
+	printf STDERR "%s dump:\n", ref $self;
+	my $width = 30;
+	foreach my $k (sort keys %$self) {
+		my $val = $self->{$k};
+		my $ref = ref $val;
+		#print STDERR "DEBUG: '$k', '$ref', '$val'\n";
+		if($ref eq '') {
+			printf STDERR "%-${width}s %s\n", $k, $val;
+		} elsif($ref eq 'SCALAR') {
+			printf STDERR "%-${width}s %s\n", $k, ${$val};
+		} elsif($ref eq 'ARRAY') {
+			#printf STDERR "%s:\n", $k;
+			my $i = 0;
+			foreach my $v (@{$val}) {
+				printf STDERR "%-${width}s %s\n", "$k\->[$i]", $v;
+				$i++;
+			}
+		} elsif($ref eq 'HASH') {
+			#printf STDERR "%s:\n", $k;
+			foreach my $k1 (keys %{$val}) {
+				printf STDERR "%-${width}s %s\n", "$k\->\{$k1\}", ${$val}{$k1};
+			}
+		} else {
+			printf STDERR "%-${width}s (-> %s)\n", $k, $ref;
+		}
+	}
+}
+
+
+1;
diff --git a/xpp/perl_modules/Dahdi/Config/Gen/Chandahdi.pm b/xpp/perl_modules/Dahdi/Config/Gen/Chandahdi.pm
new file mode 100644
index 0000000..7ade82a
--- /dev/null
+++ b/xpp/perl_modules/Dahdi/Config/Gen/Chandahdi.pm
@@ -0,0 +1,299 @@
+package Dahdi::Config::Gen::Chandahdi;
+use strict;
+
+use Dahdi::Config::Gen qw(is_true);
+
+sub new($$$) {
+	my $pack = shift || die;
+	my $gconfig = shift || die;
+	my $genopts = shift || die;
+	my $file = $ENV{CHAN_DAHDI_CHANNELS_FILE} || "/etc/asterisk/dahdi-channels.conf";
+	my $self = {
+			FILE	=> $file,
+			GCONFIG	=> $gconfig,
+			GENOPTS	=> $genopts,
+		};
+	bless $self, $pack;
+	return $self;
+}
+
+# Since chan_dahdi definitions "leak" to the next ones, we try
+# To reset some important definitions to their chan_dahdi defaults.
+my %chan_dahdi_defaults = (
+	context => 'default',
+	group => '63', # FIXME: should not be needed. 
+	overlapdial => 'no',
+	busydetect => 'no',
+	rxgain => 0,
+	txgain => 0,
+);
+
+sub reset_chandahdi_values {
+	foreach my $arg (@_) {
+		if (exists $chan_dahdi_defaults{$arg}) {
+			print "$arg = $chan_dahdi_defaults{$arg}\n";
+		} else {
+			print "$arg =\n";
+		}
+	}
+}
+
+sub gen_openr2($$$) {
+	my $self = shift || die;
+	my $gconfig = shift || die;
+	my $span = shift || die;
+	my $num = $span->num() || die;
+	my $termtype = $span->termtype() || die "$0: Span #$num -- unkown termtype [NT/TE]\n";
+	my $type = $span->type;
+	# Fake type for signalling
+	my $faketype = ($termtype eq 'TE') ? 'E1_TE' : 'E1_TE';
+	my $group = $gconfig->{'group'}{"$type"};
+	die "$0: missing default group (termtype=$termtype)\n" unless defined($group);
+	my $context = $gconfig->{'context'}{"$faketype"};
+	die "$0: missing default context\n" unless $context;
+	my @to_reset = qw/context group/;
+	my $chans = Dahdi::Config::Gen::bchan_range($span);
+	$group .= "," . (10 + $num);	# Invent unique group per span
+	my $country = $gconfig->{'loadzone'};
+	my @valid_countries = qw( ar br cn cz co ec itu mx ph ve );
+	die "Country '$country' is invalid for R2. Use one of: @valid_countries\n"
+		unless grep { $_ eq $country } @valid_countries;
+	printf "group=$group\n";
+	printf "context=$context\n";
+	printf "switchtype = %s\n", $span->switchtype;
+	printf "signalling = %s\n", 'mfcr2';
+	printf "caller = %s\n", ($termtype eq 'TE') ? 'no' : 'yes';
+	printf "mfcr2_logdir = span%d\n", $span->num;
+	print <<"EOF";
+mfcr2_variant=$country
+mfcr2_get_ani_first=no
+mfcr2_max_ani=10
+mfcr2_max_dnis=4
+mfcr2_category=national_subscriber
+mfcr2_call_files=yes
+mfcr2_logging=all
+mfcr2_mfback_timeout=-1
+mfcr2_metering_pulse_timeout=-1
+EOF
+	printf "channel => %s\n", $chans;
+
+	reset_chandahdi_values(@to_reset);
+}
+
+sub gen_cas($$$) {
+	my $self = shift || die;
+	my $gconfig = shift || die;
+	my $span = shift || die;
+	my $num = $span->num() || die;
+	my $termtype = $span->termtype() || die "$0: Span #$num -- unkown termtype [NT/TE]\n";
+	my $type = $span->type;
+	my $group = $gconfig->{'group'}{"$type"};
+	die "$0: missing default group (termtype=$termtype)\n" unless defined($group);
+	my $context = $gconfig->{'context'}{"$type"};
+	die "$0: missing default context\n" unless $context;
+	# Fake type for signalling
+	my $faketype = ($termtype eq 'TE') ? 'FXO' : 'FXS';
+	my $sig = $gconfig->{'chan_dahdi_signalling'}{$faketype};
+	my $em_signalling = $gconfig->{'em_signalling'};
+	if ($em_signalling ne 'none') {
+		$sig = $em_signalling;
+		# FIXME: but we don't handle E1 yet
+		$sig = 'em_e1' if $span->proto eq 'E1';
+	}
+	my @to_reset = qw/context group/;
+	my $chans = Dahdi::Config::Gen::chan_range($span->chans());
+	$group .= "," . (10 + $num);	# Invent unique group per span
+	printf "group=$group\n";
+	printf "context=$context\n";
+	printf "switchtype = %s\n", $span->switchtype;
+	printf "signalling = %s\n", $sig;
+	printf "channel => %s\n", $chans;
+	reset_chandahdi_values(@to_reset);
+}
+
+sub gen_digital($$$) {
+	my $self = shift || die;
+	my $gconfig = shift || die;
+	my $span = shift || die;
+	my $num = $span->num() || die;
+	die "Span #$num is analog" unless $span->is_digital();
+	if($span->is_pri && $gconfig->{'pri_connection_type'} eq 'R2') {
+		printf "; Skipped: $gconfig->{'pri_connection_type'}\n\n";
+		return;
+	}
+	my $type = $span->type() || die "$0: Span #$num -- unkown type\n";
+	my $termtype = $span->termtype() || die "$0: Span #$num -- unkown termtype [NT/TE]\n";
+	my $group = $gconfig->{'group'}{"$type"};
+	my $context = $gconfig->{'context'}{"$type"};
+	my @to_reset = qw/context group/;
+
+	die "$0: missing default group (termtype=$termtype)\n" unless defined($group);
+	die "$0: missing default context\n" unless $context;
+
+	my $sig = $span->signalling || die "missing signalling info for span #$num type $type";
+	grep($gconfig->{'bri_sig_style'} eq $_, 'bri', 'bri_ptmp', 'pri') or die "unknown signalling style for BRI";
+	if($span->is_bri() and $gconfig->{'bri_sig_style'} eq 'bri_ptmp') {
+		$sig .= '_ptmp';
+	}
+	if ($span->is_bri() && $termtype eq 'NT' && is_true($gconfig->{'brint_overlap'})) {
+		print "overlapdial = yes\n";
+		push(@to_reset, qw/overlapdial/);
+	}
+
+	$group .= "," . (10 + $num);	# Invent unique group per span
+	printf "group=$group\n";
+	printf "context=$context\n";
+	printf "switchtype = %s\n", $span->switchtype;
+	printf "signalling = %s\n", $sig;
+	printf "channel => %s\n", Dahdi::Config::Gen::bchan_range($span);
+	reset_chandahdi_values(@to_reset);
+}
+
+sub gen_channel($$) {
+	my $self = shift || die;
+	my $chan = shift || die;
+	my $gconfig = $self->{GCONFIG};
+	my $type = $chan->type;
+	my $num = $chan->num;
+	die "channel $num type $type is not an analog channel\n" if $chan->span->is_digital();
+	my $exten = $gconfig->{'base_exten'} + $num;
+	my $sig = $gconfig->{'chan_dahdi_signalling'}{$type};
+	my $context = $gconfig->{'context'}{$type};
+	my $group = $gconfig->{'group'}{$type};
+	my $callerid;
+	my $immediate;
+
+	return if $type eq 'EMPTY';
+	die "missing default_chan_dahdi_signalling for chan #$num type $type" unless $sig;
+	die "missing context for chan #$num type $type" unless $context;
+	$callerid = ($type eq 'FXO')
+			? 'asreceived'
+			: sprintf "\"Channel %d\" <%04d>", $num, $exten;
+	if($type eq 'IN') {
+		$immediate = 'yes';
+	}
+	# FIXME: $immediage should not be set for 'OUT' channels, but meanwhile
+	#        it's better to be compatible with genzaptelconf
+	$immediate = 'yes' if $gconfig->{'fxs_immediate'} eq 'yes' and $sig =~ /^fxo_/;
+	my $signalling = $chan->signalling;
+	$signalling = " " . $signalling if $signalling;
+	my $info = $chan->info;
+	$info = " " . $info if $info;
+	printf ";;; line=\"%d %s%s%s\"\n", $num, $chan->fqn, $signalling, $info;
+	printf "signalling=$sig\n";
+	printf "callerid=$callerid\n";
+	printf "mailbox=%04d\n", $exten unless $type eq 'FXO';
+	if(defined $group) {
+		printf "group=$group\n";
+	}
+	printf "context=$context\n";
+	printf "immediate=$immediate\n" if defined $immediate;
+	printf "channel => %d\n", $num;
+	# Reset following values to default
+	printf "callerid=\n";
+	printf "mailbox=\n" unless $type eq 'FXO';
+	if(defined $group) {
+		printf "group=\n";
+	}
+	printf "context=default\n";
+	printf "immediate=no\n" if defined $immediate;
+	print "\n";
+}
+
+sub generate($) {
+	my $self = shift || die;
+	my $file = $self->{FILE};
+	my $gconfig = $self->{GCONFIG};
+	my $genopts = $self->{GENOPTS};
+	#$gconfig->dump;
+	my @spans = @_;
+	warn "Empty configuration -- no spans\n" unless @spans;
+	rename "$file", "$file.bak"
+		or $! == 2	# ENOENT (No dependency on Errno.pm)
+		or die "Failed to backup old config: $!\n";
+	print "Generating $file\n" if $genopts->{verbose};
+	open(F, ">$file") || die "$0: Failed to open $file: $!\n";
+	my $old = select F;
+	printf "; Autogenerated by $0 on %s\n", scalar(localtime);
+	print  "; If you edit this file and execute $0 again,\n";
+	print  "; your manual changes will be LOST.\n";
+	print <<"HEAD";
+; Dahdi Channels Configurations (chan_dahdi.conf)
+;
+; This is not intended to be a complete chan_dahdi.conf. Rather, it is intended
+; to be #include-d by /etc/chan_dahdi.conf that will include the global settings
+;
+
+HEAD
+	foreach my $span (@spans) {
+		printf "; Span %d: %s %s\n", $span->num, $span->name, $span->description;
+		if($span->is_digital) {
+			if($span->is_pri) {
+				if($gconfig->{'pri_connection_type'} eq 'R2') {
+					$self->gen_openr2($gconfig, $span);
+				} elsif($gconfig->{'pri_connection_type'} eq 'CAS') {
+					$self->gen_cas($gconfig, $span);
+				} else {
+					$self->gen_digital($gconfig, $span);
+				}
+			} elsif($span->is_bri) {
+				$self->gen_digital($gconfig, $span);
+			}
+		} else {
+			foreach my $chan ($span->chans()) {
+				if(is_true($genopts->{'freepbx'}) || is_true($gconfig->{'freepbx'})) {
+					# Freepbx has its own idea about channels
+					my $type = $chan->type;
+					if($type eq 'FXS' || $type eq 'OUT' || $type eq 'IN') {
+						printf "; Skip channel=%s($type) -- freepbx option.\n",
+							$chan->num;
+						next;
+					}
+				}
+				$self->gen_channel($chan);
+			}
+		}
+		print "\n";
+	}
+	close F;
+	select $old;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+chandahdi - Generate configuration for chan_dahdi channels.
+
+=head1 SYNOPSIS
+
+ use Dahdi::Config::Gen::Chandahdi;
+
+ my $cfg = new Dahdi::Config::Gen::Chandahdi(\%global_config, \%genopts);
+ $cfg->generate(@span_list);
+
+=head1 DESCRIPTION
+
+Generate the F</etc/asterisk/dahdi-channels.conf>
+This is used as a configuration for asterisk(1).
+It should be included in the main F</etc/asterisk/chan_dahdi.conf>.
+
+Its location may be overriden via the environment variable 
+C<CHAN_DAHDI_CHANNELS_FILE>.
+
+=head1 OPTIONS
+
+=over 4
+
+=item freepbx
+
+With this option we do not generate channel definitions for FXS, Input and
+Output ports. This is done because these channel definitions need to be
+generated and inserted into I<freepbx> database anyway.
+
+=back
+
+The I<freepbx> option may be activated also by adding a C<freepbx yes> line
+to the C<genconf_parameters> file.
diff --git a/xpp/perl_modules/Dahdi/Config/Gen/Modules.pm b/xpp/perl_modules/Dahdi/Config/Gen/Modules.pm
new file mode 100644
index 0000000..c00e3eb
--- /dev/null
+++ b/xpp/perl_modules/Dahdi/Config/Gen/Modules.pm
@@ -0,0 +1,62 @@
+package Dahdi::Config::Gen::Modules;
+use strict;
+
+use Dahdi::Config::Gen qw(is_true);
+
+sub new($$$) {
+	my $pack = shift || die;
+	my $gconfig = shift || die;
+	my $genopts = shift || die;
+	my $file = $ENV{DAHDI_MODULES_FILE} || "/etc/dahdi/modules";
+	my $self = {
+			FILE	=> $file,
+			GCONFIG	=> $gconfig,
+			GENOPTS	=> $genopts,
+		};
+	bless $self, $pack;
+	return $self;
+}
+
+sub generate($$$) {
+	my $self = shift || die;
+	my $file = $self->{FILE};
+	my $gconfig = $self->{GCONFIG};
+	my $genopts = $self->{GENOPTS};
+	rename "$file", "$file.bak"
+		or $! == 2	# ENOENT (No dependency on Errno.pm)
+		or die "Failed to backup old config: $!\n";
+	#$gconfig->dump;
+	print "Generating $file\n" if $genopts->{verbose};
+	open(F, ">$file") || die "$0: Failed to open $file: $!\n";
+	my $old = select F;
+	printf "# Autogenerated by $0 (%s) on %s\n", __PACKAGE__, scalar(localtime);
+	print  "# If you edit this file and execute $0 again,\n";
+	print  "# your manual changes will be LOST.\n";
+	my @drivers = Dahdi::Hardware->drivers;
+	print join("\n", @drivers),"\n";
+	close F;
+	select $old;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+modules - Generate list of dahdi drivers to load at startup
+
+=head1 SYNOPSIS
+
+ use Dahdi::Config::Gen::Dahdi;
+
+ my $cfg = new Dahdi::Config::Gen::Modules(\%global_config, \%genopts);
+ $cfg->generate(@span_list);
+
+=head1 DESCRIPTION
+
+Generate the F</etc/dahdi/modules>. This is a list of modules, one per
+line. This list is normally used by F</etc/init.d/dahdi>.
+
+Its location may be overriden via the environment variable
+F<DAHDI_MODULES_FILE>.
diff --git a/xpp/perl_modules/Dahdi/Config/Gen/System.pm b/xpp/perl_modules/Dahdi/Config/Gen/System.pm
new file mode 100644
index 0000000..d7c2523
--- /dev/null
+++ b/xpp/perl_modules/Dahdi/Config/Gen/System.pm
@@ -0,0 +1,278 @@
+package Dahdi::Config::Gen::System;
+use strict;
+
+use Dahdi::Config::Gen qw(is_true);
+
+sub new($$$) {
+	my $pack = shift || die;
+	my $gconfig = shift || die;
+	my $genopts = shift || die;
+	my $file = $ENV{DAHDI_CONF_FILE} || "/etc/dahdi/system.conf";
+	my $self = {
+			FILE	=> $file,
+			GCONFIG	=> $gconfig,
+			GENOPTS	=> $genopts,
+		};
+	bless $self, $pack;
+	return $self;
+}
+
+my $bri_te_last_timing = 1;
+
+sub print_echo_can($$) {
+	my $gconfig = shift || die;
+	my $chans = shift || die; # channel or range of channels.
+	my $echo_can = $gconfig->{'echo_can'};
+	return if !defined($echo_can) || $echo_can eq 'none';
+
+	print "echocanceller=$echo_can,$chans\n";
+}
+
+sub gen_t1_cas($$) {
+	my $self = shift || die;
+	my $gconfig = shift || die;
+	my $parameters = $gconfig->{PARAMETERS} || die;
+	my $genconf_file = $parameters->{GENCONF_FILE} || die;
+	my $span = shift || die;
+	my $num = $span->num() || die;
+	my $proto = $span->proto || die;
+	die "Generate configuration for '$proto' is not possible. Maybe you meant R2?"
+		unless $proto eq 'T1';
+	my $pri_connection_type = $gconfig->{pri_connection_type} || die;
+	die "Span #$num is analog" unless $span->is_digital();
+	die "Span #$num is not CAS" unless $span->is_pri && $pri_connection_type eq 'CAS';
+	my $termtype = $span->termtype() || die "$0: Span #$num -- unkown termtype [NT/TE]\n";
+	my $timing;
+	my $lbo = 0;
+	my $framing = $gconfig->{tdm_framing};
+	if(!defined $framing) {
+		$framing = 'esf';
+	} elsif($framing ne 'esf' && $framing ne 'd4') {
+		die "T1-CAS valid framing is only 'esf' or 'd4'. Not '$framing'. Check '$genconf_file'\n";
+	}
+	my $coding =  $span->coding() || die "$0: No coding information for span #$num\n";
+	my $span_crc4 = $span->crc4();
+	$span_crc4 = (defined $span_crc4) ? ",$span_crc4" : '';
+	my $span_yellow = $span->yellow();
+	$span_yellow = (defined $span_yellow) ? ",$span_yellow" : '';
+	$timing = ($termtype eq 'NT') ? 0 : $bri_te_last_timing++;
+	printf "span=%d,%d,%d,%s,%s%s%s\n",
+			$num,
+			$timing,
+			$lbo,
+			$framing,
+			$coding,
+			$span_crc4,
+			$span_yellow;
+	printf "# termtype: %s\n", lc($termtype);
+	my $dchan_type;
+	my $chan_range;
+	if($span->is_pri()) {
+		if ($pri_connection_type eq 'PRI') {
+			$chan_range = Dahdi::Config::Gen::bchan_range($span);
+			printf "bchan=%s\n", $chan_range;
+			my $dchan = $span->dchan();
+			printf "dchan=%d\n", $dchan->num();
+		} elsif ($pri_connection_type eq 'R2' ) {
+			my $idle_bits = $gconfig->{'r2_idle_bits'};
+			$chan_range = Dahdi::Config::Gen::bchan_range($span);
+			printf "cas=%s:$idle_bits\n", $chan_range;
+			printf "dchan=%d\n", $span->dchan()->num();
+		} elsif ($pri_connection_type eq 'CAS' ) {
+			my $type = ($termtype eq 'TE') ? 'FXO' : 'FXS';
+			my $sig = $gconfig->{'dahdi_signalling'}{$type};
+			my $em_signalling = $gconfig->{'em_signalling'};
+			if ($em_signalling ne 'none') {
+				$sig = 'e&m';
+				# FIXME: but we don't handle E1 yet
+				$sig = 'e&me1' if $proto eq 'E1';
+			}
+			die "unknown default dahdi signalling for chan $num type $type" unless defined $sig;
+			$chan_range = Dahdi::Config::Gen::chan_range($span->chans());
+			printf "%s=%s\n", $sig, $chan_range;
+		}
+	} else {
+		die "Digital span $num is not PRI";
+	}
+	print_echo_can($gconfig, $chan_range);
+}
+
+sub gen_digital($$$) {
+	my $self = shift || die;
+	my $gconfig = shift || die;
+	my $span = shift || die;
+	my $num = $span->num() || die;
+	die "Span #$num is analog" unless $span->is_digital();
+	my $termtype = $span->termtype() || die "$0: Span #$num -- unkown termtype [NT/TE]\n";
+	my $timing;
+	my $lbo = 0;
+	my $framing = $span->framing() || die "$0: No framing information for span #$num\n";
+	my $coding =  $span->coding() || die "$0: No coding information for span #$num\n";
+	my $span_crc4 = $span->crc4();
+	$span_crc4 = (defined $span_crc4) ? ",$span_crc4" : '';
+	my $span_yellow = $span->yellow();
+	$span_yellow = (defined $span_yellow) ? ",$span_yellow" : '';
+	my $span_termination = $span->termination();
+	$span_termination = (defined $span_termination) ? ",$span_termination" : '';
+	my $span_softntte = $span->softntte();
+	$span_softntte = (defined $span_softntte) ? ",$span_softntte" : '';
+	# "MFC/R2 does not normally use CRC4"
+	# FIXME: a finer way to override:
+	if ($gconfig->{'pri_connection_type'} eq 'R2') { 
+		$span_crc4 = '';
+		$framing = 'cas';
+	}
+	$timing = ($termtype eq 'NT') ? 0 : $bri_te_last_timing++;
+	printf "span=%d,%d,%d,%s,%s%s%s%s%s\n",
+			$num,
+			$timing,
+			$lbo,
+			$framing,
+			$coding,
+			$span_crc4,
+			$span_yellow,
+			$span_termination,
+			$span_softntte;
+	printf "# termtype: %s\n", lc($termtype);
+	my $dchan_type;
+	if ($span->is_bri()) {
+		my $use_bristuff = 0;
+		my $cfg_hardhdlc = $gconfig->{'bri_hardhdlc'};
+		my $xpd = $span->xpd();
+		if(!defined($cfg_hardhdlc) || $cfg_hardhdlc =~ /AUTO/i) {
+			# Autodetect
+			if(defined($xpd)) {
+				# Bristuff?
+				if(defined($xpd->dchan_hardhdlc) && !is_true($xpd->dchan_hardhdlc)) {
+					$use_bristuff = 1;
+				}
+			}
+		} elsif(!is_true($cfg_hardhdlc)) {
+			$use_bristuff = 1;
+		}
+		if($use_bristuff) {
+			$dchan_type = 'dchan';
+		} else {
+			$dchan_type = 'hardhdlc';
+		}
+		printf "bchan=%s\n", Dahdi::Config::Gen::bchan_range($span);
+		my $dchan = $span->dchan();
+		printf "$dchan_type=%d\n", $dchan->num();
+	} elsif($span->is_pri()) {
+		if ($gconfig->{'pri_connection_type'} eq 'PRI') {
+			printf "bchan=%s\n", Dahdi::Config::Gen::bchan_range($span);
+			my $dchan = $span->dchan();
+			printf "dchan=%d\n", $dchan->num();
+		} elsif ($gconfig->{'pri_connection_type'} eq 'R2' ) {
+			my $idle_bits = $gconfig->{'r2_idle_bits'};
+			printf "cas=%s:$idle_bits\n", Dahdi::Config::Gen::bchan_range($span);
+			printf "dchan=%d\n", $span->dchan()->num();
+		}
+	} else {
+		die "Digital span $num is not BRI, nor PRI?";
+	}
+	print_echo_can($gconfig, Dahdi::Config::Gen::bchan_range($span));
+}
+
+sub gen_signalling($$) {
+	my $gconfig = shift || die;
+	my $chan = shift || die;
+	my $type = $chan->type;
+	my $num = $chan->num;
+
+	die "channel $num type $type is not an analog channel\n" if $chan->span->is_digital();
+	if($type eq 'EMPTY') {
+		printf "# channel %d, %s, no module.\n", $num, $chan->fqn;
+		return;
+	}
+	my $signalling = $gconfig->{'dahdi_signalling'};
+	my $sig = $signalling->{$type} || die "unknown default dahdi signalling for chan $num type $type";
+	if ($type eq 'IN') {
+		printf "# astbanktype: input\n";
+	} elsif ($type eq 'OUT') {
+		printf "# astbanktype: output\n";
+	}
+	printf "$sig=$num\n";
+	print_echo_can($gconfig, $num);
+}
+
+sub generate($$$) {
+	my $self = shift || die;
+	my $file = $self->{FILE};
+	my $gconfig = $self->{GCONFIG};
+	my $genopts = $self->{GENOPTS};
+	my @spans = @_;
+	warn "Empty configuration -- no spans\n" unless @spans;
+	rename "$file", "$file.bak"
+		or $! == 2	# ENOENT (No dependency on Errno.pm)
+		or die "Failed to backup old config: $!\n";
+	#$gconfig->dump;
+	print "Generating $file\n" if $genopts->{verbose};
+	open(F, ">$file") || die "$0: Failed to open $file: $!\n";
+	my $old = select F;
+	printf "# Autogenerated by $0 on %s\n", scalar(localtime);
+	print  "# If you edit this file and execute $0 again,\n";
+	print  "# your manual changes will be LOST.\n";
+	print <<"HEAD";
+# Dahdi Configuration File
+#
+# This file is parsed by the Dahdi Configurator, dahdi_cfg
+#
+HEAD
+	foreach my $span (@spans) {
+		printf "# Span %d: %s %s\n", $span->num, $span->name, $span->description;
+		if($span->is_digital) {
+			if($span->is_pri) {
+				if($gconfig->{'pri_connection_type'} eq 'CAS') {
+					$self->gen_t1_cas($gconfig, $span);
+				} else {
+					$self->gen_digital($gconfig, $span);
+				}
+			} elsif($span->is_bri) {
+				$self->gen_digital($gconfig, $span);
+			}
+		} else {
+			foreach my $chan ($span->chans()) {
+				if(1 || !defined $chan->type) {
+					my $type = $chan->probe_type;
+					my $num = $chan->num;
+					die "Failed probing type for channel $num"
+						unless defined $type;
+					$chan->type($type);
+				}
+				gen_signalling($gconfig, $chan);
+			}
+		}
+		print "\n";
+	}
+	print <<"TAIL";
+# Global data
+
+loadzone	= $gconfig->{'loadzone'}
+defaultzone	= $gconfig->{'defaultzone'}
+TAIL
+	close F;
+	select $old;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+dahdi - Generate configuration for dahdi drivers.
+
+=head1 SYNOPSIS
+
+ use Dahdi::Config::Gen::Dahdi;
+
+ my $cfg = new Dahdi::Config::Gen::Dahdi(\%global_config, \%genopts);
+ $cfg->generate(@span_list);
+
+=head1 DESCRIPTION
+
+Generate the F</etc/dahdi/system.conf>.
+This is the configuration for dahdi_cfg(1).
+
+Its location may be overriden via the environment variable F<DAHDI_CONF_FILE>.
diff --git a/xpp/perl_modules/Dahdi/Config/Gen/Unicall.pm b/xpp/perl_modules/Dahdi/Config/Gen/Unicall.pm
new file mode 100644
index 0000000..cb6bff0
--- /dev/null
+++ b/xpp/perl_modules/Dahdi/Config/Gen/Unicall.pm
@@ -0,0 +1,72 @@
+package Dahdi::Config::Gen::Unicall;
+use strict;
+
+use Dahdi::Config::Gen qw(is_true);
+
+sub new($$$) {
+	my $pack = shift || die;
+	my $gconfig = shift || die;
+	my $genopts = shift || die;
+	my $file = $ENV{UNICALL_CHANNELS_FILE} || "/etc/asterisk/unicall-channels.conf";
+	my $self = {
+			FILE	=> $file,
+			GCONFIG	=> $gconfig,
+			GENOPTS	=> $genopts,
+		};
+	bless $self, $pack;
+	return $self;
+}
+
+sub generate($) {
+	my $self = shift || die;
+	my $file = $self->{FILE};
+	my $gconfig = $self->{GCONFIG};
+	my $genopts = $self->{GENOPTS};
+	#$gconfig->dump;
+	my @spans = @_;
+	warn "Empty configuration -- no spans\n" unless @spans;
+	die "Only for R2" unless $gconfig->{'pri_connection_type'} eq 'R2';
+	rename "$file", "$file.bak"
+		or $! == 2	# ENOENT (No dependency on Errno.pm)
+		or die "Failed to backup old config: $!\n";
+	print "Generating $file\n" if $genopts->{verbose};
+	open(F, ">$file") || die "$0: Failed to open $file: $!\n";
+	my $old = select F;
+	printf "; Autogenerated by $0 on %s\n", scalar(localtime);
+	print  "; If you edit this file and execute $0 again,\n";
+	print  "; your manual changes will be LOST.\n";
+	print  "; This file should be #included in unicall.conf\n\n";
+	foreach my $span (@spans) {
+		next unless $span->is_digital();
+		printf "; Span %d: %s %s\n", $span->num, $span->name, $span->description;
+		my $idle_bits = $gconfig->{'r2_idle_bits'}; 
+		printf "protocolend=%s\n", ($span->termtype() eq 'TE') ? 'cpe' : 'co';
+		printf "channel=%s\n", Dahdi::Config::Gen::bchan_range($span);
+		print "\n";
+	}
+	close F;
+	select $old;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+unicall - Generate configuration for unicall channels.
+
+=head1 SYNOPSIS
+
+ use Dahdi::Config::Gen::Unicall;
+
+ my $cfg = new Dahdi::Config::Gen::Unicall(\%global_config, \%genopts);
+ $cfg->generate(@span_list);
+
+=head1 DESCRIPTION
+
+Generate the F</etc/asterisk/unicall-channels.conf> to be included in 
+F</etc/asterisk/unicall.conf>
+
+Its location may be overriden via the environment variable 
+C<UNICALL_CHANNELS_FILE>.
diff --git a/xpp/perl_modules/Dahdi/Config/Gen/Users.pm b/xpp/perl_modules/Dahdi/Config/Gen/Users.pm
new file mode 100644
index 0000000..05a345f
--- /dev/null
+++ b/xpp/perl_modules/Dahdi/Config/Gen/Users.pm
@@ -0,0 +1,227 @@
+package Dahdi::Config::Gen::Users;
+use strict;
+
+use File::Basename;
+use Dahdi::Config::Gen qw(is_true);
+
+# Generate a complete users.conf for the asterisk-gui
+# As the asterisk-gui provides no command-line interface of its own and
+# no decent support of #include, we have no choice but to nuke users.conf
+# if we're to provide a working system
+
+sub new($$$) {
+	my $pack = shift || die;
+	my $gconfig = shift || die;
+	my $genopts = shift || die;
+	my $file = $ENV{USERS_FILE} || "/etc/asterisk/users.conf";
+	my $self = {
+			FILE	=> $file,
+			GCONFIG	=> $gconfig,
+			GENOPTS	=> $genopts,
+		};
+	bless $self, $pack;
+	return $self;
+}
+
+# A single analog trunk for all the FXO channels
+sub gen_analog_trunk {
+	my @fxo_ports = @_;
+	return unless (@fxo_ports); # no ports
+
+	my $ports = join(',', @fxo_ports);
+
+	print << "EOF"
+[trunk_1]
+trunkname = analog
+hasexten = no
+hasiax = no
+hassip = no
+hasregisteriax = no
+hasregistersip = no
+trunkstyle = analog
+dahdichan = $ports
+
+EOF
+}
+
+# A digital trunk for a single span.
+# FIXME: how do I create the DID context?
+sub gen_digital_trunk($) {
+	my $span = shift;
+	my $num = $span->num;
+	my $sig = $span->signalling;
+	my $type = $span->type;
+	my $bchan_range = Dahdi::Config::Gen::bchan_range($span);
+
+	print << "EOF";
+[span_$num]
+group = $num
+hasexten = no
+signalling = $sig
+trunkname = Span $num $type
+trunkstyle = digital  ; GUI metadata
+hassip = no
+hasiax = no
+context = DID_span_$num
+dahdichan = $bchan_range
+
+EOF
+}
+
+my $ExtenNum;
+
+# A single user for a FXS channel
+sub gen_channel($$) {
+	my $self = shift || die;
+	my $chan = shift || die;
+	my $gconfig = $self->{GCONFIG};
+	my $type = $chan->type;
+	my $num = $chan->num;
+	die "channel $num type $type is not an analog channel\n" if $chan->span->is_digital();
+	my $exten = $ExtenNum++;
+	my $sig = $gconfig->{'chan_dahdi_signalling'}{$type};
+	my $full_name = "$type $num";
+
+	die "missing default_chan_dahdi_signalling for chan #$num type $type" unless $sig;
+	print << "EOF";
+[$exten]
+context = DLPN_DialPlan1
+callwaiting = yes
+fullname = $full_name
+cid_number = $exten
+hasagent = no
+hasdirectory = no
+hasiax = no
+hasmanager = no
+hassip = no
+hasvoicemail = yes
+mailbox = $exten
+threewaycalling = yes
+vmsecret = $exten
+signalling = $sig
+dahdichan = $num
+registeriax = no
+registersip = no
+canreinvite = no
+
+EOF
+}
+
+sub generate($) {
+	my $self = shift || die;
+	my $file = $self->{FILE};
+	my $gconfig = $self->{GCONFIG};
+	my $genopts = $self->{GENOPTS};
+	#$gconfig->dump;
+	my @spans = @_;
+	warn "Empty configuration -- no spans\n" unless @spans;
+	rename "$file", "$file.bak"
+		or $! == 2	# ENOENT (No dependency on Errno.pm)
+		or die "Failed to backup old config: $!\n";
+	print "Generating $file\n" if $genopts->{verbose};
+	open(F, ">$file") || die "$0: Failed to open $file: $!\n";
+	my $old = select F;
+	print <<"HEAD";
+;!
+;! Automatically generated configuration file
+;! Filename: @{[basename($file)]} ($file)
+;! Generator: $0
+;! Creation Date: @{[scalar(localtime)]}
+;! If you edit this file and execute $0 again,
+;! your manual changes will be LOST.
+;!
+[general]
+;
+; Starting point of allocation of extensions
+;
+userbase = @{[$gconfig->{'base_exten'}+1]}
+;
+; Create voicemail mailbox and use use macro-stdexten
+;
+hasvoicemail = yes
+;
+; Set voicemail mailbox @{[$gconfig->{'base_exten'}+1]} password to 1234
+;
+vmsecret = 1234
+;
+; Create SIP Peer
+;
+hassip = no
+;
+; Create IAX friend
+;
+hasiax = no
+;
+; Create Agent friend
+;
+hasagent = no
+;
+; Create H.323 friend
+;
+;hash323 = yes
+;
+; Create manager entry
+;
+hasmanager = no
+;
+; Remaining options are not specific to users.conf entries but are general.
+;
+callwaiting = yes
+threewaycalling = yes
+callwaitingcallerid = yes
+transfer = yes
+canpark = yes
+cancallforward = yes
+callreturn = yes
+callgroup = 1
+pickupgroup = 1
+localextenlength = @{[length($gconfig->{'base_exten'})]}
+
+
+HEAD
+	my @fxo_ports = ();
+	$ExtenNum = $self->{GCONFIG}->{'base_exten'};
+	foreach my $span (@spans) {
+		printf "; Span %d: %s %s\n", $span->num, $span->name, $span->description;
+		if ($span->type =~ /^(BRI_(NT|TE)|E1|T1)$/) {
+			gen_digital_trunk($span);
+			next;
+		}
+		foreach my $chan ($span->chans()) {
+			if (grep { $_ eq $span->type} ( 'FXS', 'IN', 'OUT' )) {
+				$self->gen_channel($chan);
+			} elsif ($chan->type eq 'FXO') {
+				# TODO: "$first_chan-$last_chan"
+				push @fxo_ports,($chan->num);
+			}
+		}
+		print "\n";
+	}
+	gen_analog_trunk(@fxo_ports);
+	close F;
+	select $old;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+users - Generate configuration for users.conf.
+
+=head1 SYNOPSIS
+
+ use Dahdi::Config::Gen::Users;
+
+ my $cfg = new Dahdi::Config::Gen::Users(\%global_config, \%genopts);
+ $cfg->generate(@span_list);
+
+=head1 DESCRIPTION
+
+Generate the F</etc/asterisk/users.conf> which is used by asterisk(1) 
+and AsteriskGUI. This will replace your entire configuration including
+any SIP/IAX users and trunks you may have set. Thus it's probably only
+appropriate for an initial setup.
+
+Its location may be overriden via the environment variable F<USERS_FILE>.
diff --git a/xpp/perl_modules/Dahdi/Config/Gen/Xpporder.pm b/xpp/perl_modules/Dahdi/Config/Gen/Xpporder.pm
new file mode 100644
index 0000000..e7bfb72
--- /dev/null
+++ b/xpp/perl_modules/Dahdi/Config/Gen/Xpporder.pm
@@ -0,0 +1,142 @@
+package Dahdi::Config::Gen::Xpporder;
+use strict;
+
+use Dahdi::Config::Gen qw(is_true);
+use Dahdi::Xpp;
+
+sub new($$$) {
+	my $pack = shift || die;
+	my $gconfig = shift || die;
+	my $genopts = shift || die;
+	my $file = $ENV{XPPORDER_CONF} || "/etc/dahdi/xpp_order";
+	my $self = {
+			FILE	=> $file,
+			GCONFIG	=> $gconfig,
+			GENOPTS	=> $genopts,
+		};
+	bless $self, $pack;
+	return $self;
+}
+
+#
+# Returns list of xbuses sorted by the span numbers assigned
+# to their XPD's. Also checks that each XBUS span numbers are sequential.
+sub get_sorted_xbuses(@) {
+	my @spans = @_;	# Verify our spans
+	my @xbuses = Dahdi::Xpp::xbuses;
+	my %xbus_of_span;
+	my %xbus_beginning;
+	my %seen_spans;
+	my @sorted_xbuses;
+	foreach my $xbus (@xbuses) {
+		my $last_spanno;
+		foreach my $xpd ($xbus->xpds) {
+			my $spanno = $xpd->spanno;
+			if(!$spanno) {
+				printf STDERR "%s: Is not registered. Skipping.\n", $xpd->fqn;
+				next;
+			}
+			$seen_spans{$spanno}++;
+			if($xbus_of_span{$spanno}) {
+				printf STDERR "%s: Span %d already seen on %s\n",
+					$xpd->fqn, $spanno, $xbus_of_span{$spanno}->name;
+				die;
+			}
+			$xbus_of_span{$spanno} = $xbus;
+			# Check XPD's sequential numbering
+			if(defined $last_spanno) {
+				if($last_spanno + 1 != $spanno) {
+					printf STDERR "%s: Bad span numbers (%d, %d)\n",
+						$xpd->fqn, $last_spanno, $spanno;
+					die;
+				}
+			} else {
+				$xbus_beginning{$xbus} = $spanno;
+			}
+			$last_spanno = $spanno;
+		}
+	}
+	foreach my $span (@spans) {
+		my $spanno = $span->num;
+		if(!defined($seen_spans{$spanno})) {
+			warn "Span $spanno: Ignored: Does not belong to any XPD\n";
+		}
+	}
+	@sorted_xbuses = sort { $xbus_beginning{$a} <=> $xbus_beginning{$b} } @xbuses;
+	return @sorted_xbuses;
+}
+
+sub generate($$$) {
+	my $self = shift || die;
+	my $file = $self->{FILE};
+	my $gconfig = $self->{GCONFIG};
+	my $genopts = $self->{GENOPTS};
+	my @spans = @_;		# Verify it's all our spans
+	my @xbuses = get_sorted_xbuses(@spans);
+	warn "Empty configuration -- no xbuses\n" unless @xbuses;
+	rename "$file", "$file.bak"
+		or $! == 2	# ENOENT (No dependency on Errno.pm)
+		or die "Failed to backup old config: $!\n";
+	#$gconfig->dump;
+	print "Generating $file\n" if $genopts->{verbose};
+	open(F, ">$file") || die "$0: Failed to open $file: $!\n";
+	my $old = select F;
+	printf "# Autogenerated by $0 on %s\n", scalar(localtime);
+	print  "# If you edit this file and execute $0 again,\n";
+	print  "# your manual changes will be LOST.\n";
+	print <<'HEAD';
+#
+# This is an optional configuration file for ordering
+# Dahdi registration.
+#
+# It is read from /etc/dahdi/xpp_order. This location
+# may be overridden via the environment variable XPPORDER_CONF
+#
+# Lines may contain:
+#   - The Astribank label (verbatim)
+#   - The Astribank connector string (prefixed with @)
+# Ordering number of each listed Astribank is determined
+# by its position in this file.
+# Astribanks not listed in this file, get an ordering
+# number of 99 (last).
+#
+# Astribanks with same ordering number are sorted by their
+# connectors (to preserve legacy behavior).
+#
+# Examples:
+#usb:1234
+#@usb-0000:06:02.2-2
+HEAD
+	foreach my $xbus (@xbuses) {
+		my $label = $xbus->label;
+		my $connector = $xbus->connector;
+		my $name = $xbus->name;
+		printf "%s\t# %s #(%s)\n", $label, $connector, $name;
+	}
+	close F;
+	select $old;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Xpporder - Generate Astribank ordering information for dahdi_registration.
+
+=head1 SYNOPSIS
+
+ use Dahdi::Config::Gen::Xpporder;
+
+ my $cfg = new Dahdi::Config::Gen::Xpporder(\%global_config, \%genopts);
+ $cfg->generate;
+
+=head1 DESCRIPTION
+
+Generate the F</etc/dahdi/xpp_order>.
+This is the configuration for dahdi_registration(1).
+The order is determined according to current Dahdi registration
+order.
+
+Its location may be overriden via the environment variable F<XPPORDER_CONF>.
diff --git a/xpp/perl_modules/Dahdi/Config/Params.pm b/xpp/perl_modules/Dahdi/Config/Params.pm
new file mode 100644
index 0000000..0cc0d88
--- /dev/null
+++ b/xpp/perl_modules/Dahdi/Config/Params.pm
@@ -0,0 +1,156 @@
+package Dahdi::Config::Params;
+#
+# Written by Oron Peled <oron at actcom.co.il>
+# Copyright (C) 2009, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+
+=head1 NAME
+
+Dahdi::Config::Params -- Object oriented representation of F<genconf_parameters> file.
+
+=head1 SYNOPSIS
+
+ use Dahdi::Config::Params;
+ my $params = Dahdi::Config::Params->new('the-config-file');
+ print $params->item{'some-key'};
+ print $params->item{'some-key', NODEFAULTS => 1};
+ $params->dump;	# For debugging
+
+=head1 DESCRIPTION
+
+The constructor must be given a configuration file name:
+
+=over 4
+
+=item * Missing file is B<not> an error.
+
+=item * Other opening errors cause a C<die> to be thrown.
+
+=item * The file name is saved as the value of C<GENCONF_FILE> key.
+
+=back
+
+The access to config keys should only be done via the C<item()> method:
+
+=over 4
+
+=item * It contains all hard-coded defaults.
+
+=item * All these values are overriden by directives in the config file.
+
+=item * Calling it with C<NODEFAULTS =E<gt> 1> option, returns C<undef> for keys that
+do not appear in the configuration file.
+
+=back
+
+=cut
+
+sub new($$) {
+	my $pack = shift || die;
+	my $cfg_file = shift || die;
+	my $self = {
+			GENCONF_FILE	=> $cfg_file,
+		};
+	bless $self, $pack;
+	if(!open(F, $cfg_file)) {
+		if(defined($!{ENOENT})) {
+			#print STDERR "No $cfg_file. Assume empty config\n";
+			return $self; # Empty configuration
+		}
+		die "$pack: Failed to open '$cfg_file': $!\n";
+	}
+	#print STDERR "$pack: $cfg_file\n";
+	my $array_key;
+	while(<F>) {
+		my ($key, $val);
+		chomp;
+		s/#.*$//;
+		s/\s+$//;	# trim tail whitespace
+		next unless /\S/;
+		if(defined $array_key && /^\s+/) {
+			s/^\s+//;	# trim beginning whitespace
+			push(@{$self->{$array_key}}, $_);
+			next; 
+		}
+		undef $array_key;
+		($key, $val) = split(/\s+/, $_, 2);
+		$key = lc($key);
+		if(! defined $val) {
+			$array_key = $key;
+			next;
+		}
+		die "$cfg_file:$.: Duplicate key '$key'\n", if exists $self->{$key};
+		$self->{$key} = $val;
+	}
+	close F;
+	return $self;
+}
+
+sub item($$@) {
+	my $self = shift || die;
+	my $key = shift || die;
+	my %options = @_;
+	my %defaults = (
+			base_exten		=> '4000',
+			freepbx			=> 'no',	# Better via -F command line
+			fxs_immediate		=> 'no',
+			fxs_default_start	=> 'ks',
+			fxo_default_start	=> 'ks',
+			em_signalling		=> 'none',
+			lc_country		=> 'us',
+			context_lines		=> 'from-pstn',
+			context_phones		=> 'from-internal',
+			context_input		=> 'astbank-input',
+			context_output		=> 'astbank-output',
+			group_phones		=> '5',
+			group_lines		=> '0',
+			brint_overlap		=> 'no',
+			bri_sig_style		=> 'bri_ptmp',
+			echo_can		=> 'mg2',
+			bri_hardhdlc		=> 'auto',
+			pri_connection_type	=> 'PRI',
+			r2_idle_bits		=> '1101',
+			tdm_framing		=> 'esf',
+			'pri_termtype'		=> [ 'SPAN/* TE' ],
+		);
+	return $self->{$key} if exists($self->{$key}) or $options{NODEFAULTS};
+	return $defaults{$key};
+}
+
+sub dump($) {
+	my $self = shift || die;
+	printf STDERR "%s dump:\n", ref $self;
+	my $width = 30;
+	foreach my $k (sort keys %$self) {
+		my $val = $self->{$k};
+		my $ref = ref $val;
+		#print STDERR "DEBUG: '$k', '$ref', '$val'\n";
+		if($ref eq '') {
+			printf STDERR "%-${width}s %s\n", $k, $val;
+		} elsif($ref eq 'SCALAR') {
+			printf STDERR "%-${width}s %s\n", $k, ${$val};
+		} elsif($ref eq 'ARRAY') {
+			#printf STDERR "%s:\n", $k;
+			my $i = 0;
+			foreach my $v (@{$val}) {
+				printf STDERR "%-${width}s %s\n", "$k\->[$i]", $v;
+				$i++;
+			}
+		} elsif($ref eq 'HASH') {
+			#printf STDERR "%s:\n", $k;
+			foreach my $k1 (keys %{$val}) {
+				printf STDERR "%-${width}s %s\n", "$k\->\{$k1\}", ${$val}{$k1};
+			}
+		} else {
+			printf STDERR "%-${width}s (-> %s)\n", $k, $ref;
+		}
+	}
+}
+
+1;
+
diff --git a/xpp/perl_modules/Dahdi/Hardware.pm b/xpp/perl_modules/Dahdi/Hardware.pm
new file mode 100644
index 0000000..ba89447
--- /dev/null
+++ b/xpp/perl_modules/Dahdi/Hardware.pm
@@ -0,0 +1,235 @@
+package Dahdi::Hardware;
+#
+# Written by Oron Peled <oron at actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+
+=head1 NAME
+
+Dahdi::Hardware - Perl interface to a Dahdi devices listing
+
+
+  use Dahdi::Hardware;
+  
+  my $hardware = Dahdi::Hardware->scan; 
+  
+  # mini dahdi_hardware:
+  foreach my $device ($hardware->device_list) {
+    print "Vendor: device->{VENDOR}, Product: $device->{PRODUCT}\n"
+  }
+
+  # let's see if there are devices without loaded drivers, and sugggest
+  # drivers to load:
+  my @to_load = ();
+  foreach my $device ($hardware->device_list) {
+    if (! $device->{LOADED} ) {
+      push @to_load, ($device->${DRIVER});
+    }
+  }
+  if (@to_load) {
+    print "To support the extra devices you probably need to run:\n"
+    print "  modprobe ". (join ' ', @to_load). "\n";
+  }
+
+
+This module provides information about available Dahdi devices on the
+system. It identifies devices by (USB/PCI) bus IDs.
+
+
+=head1 Device Attributes
+
+As usual, object attributes can be used in either upp-case or
+lower-case, or lower-case functions.
+
+=head2 bus_type
+
+'PCI' or 'USB'.
+
+
+=head2 description
+
+A one-line description of the device.
+
+
+=head2 driver
+
+Name of a Dahdi device driver that should handle this device. This is
+based on a pre-made list.
+
+
+=head2 vendor, product, subvendor, subproduct
+
+The PCI and USB vendor ID, product ID, sub-vendor ID and sub-product ID.
+(The standard short lspci and lsusb listings show only vendor and
+product IDs).
+
+
+=head2 loaded
+
+If the device is handled by a module - the name of the module. Else -
+undef.
+
+
+=head2 priv_device_name
+
+A string that shows the "location" of that device on the bus.
+
+
+=head2 is_astribank
+
+True if the device is a Xorcom Astribank (which may provide some extra
+attributes).
+
+=head2 serial
+
+(Astribank-specific attrribute) - the serial number string of the
+Astribank.
+
+=cut
+#
+# A global hardware handle
+#
+
+my %hardware_list = (
+			'PCI'	=> [],
+			'USB'	=> [],
+		);
+
+
+sub new($$) {
+	my $pack = shift || die "Wasn't called as a class method\n";
+	my $name =  shift || die "$0: Missing device name";
+	my $type =  shift || die "$0: Missing device type";
+	my $dev = {};
+	$dev->{'BUS_TYPE'} = $type;
+	$dev->{IS_ASTRIBANK} = 0 unless defined $dev->{'IS_ASTRIBANK'};
+	$dev->{'HARDWARE_NAME'} = $name;
+	return $dev;
+}
+
+=head1 device_list()
+
+Returns a list of the hardware devices on the system.
+
+You must run scan() first for this function to run meaningful output.
+
+=cut
+
+sub device_list($) {
+	my $pack = shift || die;
+	my @types = @_;
+	my @list;
+
+	@types = qw(USB PCI) unless @types;
+	foreach my $t (@types) {
+		my $lst = $hardware_list{$t};
+		@list = ( @list, @{$lst} );
+	}
+	return @list;
+}
+
+sub device_by_hwname($$) {
+	my $pack = shift || die;
+	my $name = shift || die;
+	my @list = device_list('localcall');
+
+	my @good = grep { $_->hardware_name eq $name } @list;
+	return undef unless @good;
+	@good > 1 && die "$pack: Multiple matches for '$name': @good";
+	return $good[0];
+}
+
+=head1 drivers()
+
+Returns a list of drivers (currently sorted by name) that are used by
+the devices in the current system (regardless to whether or not they are
+loaded.
+
+=cut
+
+sub drivers($) {
+	my $self = shift || die;
+	my @devs = device_list('localcall');
+	my @drvs = map { $_->{DRIVER} } @devs;
+	# Make unique
+	my %drivers;
+	@drivers{@drvs} = 1;
+	return sort keys %drivers;
+}
+
+
+=head1 scan()
+
+Scan the system for Dahdi devices (PCI and USB). Returns nothing but
+must be run to initialize the module.
+
+=cut
+
+my $hardware_scanned;
+
+sub scan($) {
+	my $pack = shift || die;
+
+	return if $hardware_scanned++;
+	foreach my $type (qw(PCI USB)) {
+		eval "use Dahdi::Hardware::$type";
+		die $@ if $@;
+		$hardware_list{$type} = [ "Dahdi::Hardware::$type"->scan_devices ];
+	}
+}
+
+=head1 rescan
+
+Rescan for devices. In case new devices became available since the script
+has started.
+
+=cut
+
+sub rescan($) {
+	my $pack = shift || die;
+
+	$hardware_scanned = 0;
+	$pack->scan();
+}
+
+sub import {
+	Dahdi::Hardware->scan unless grep(/\bnoscan\b/i, @_);
+}
+
+sub showall {
+	my $pack = shift || die;
+	my @devs;
+
+	my $printer = sub {
+			my $title = shift;
+			my @devs = @_;
+
+			return unless @devs;
+			printf "%s:\n", $title;
+			foreach my $dev (@devs) {
+				printf "\t%s\n", $dev->hardware_name;
+				foreach my $k (sort keys %{$dev}) {
+					my $v = $dev->{$k};
+					if($k eq 'MPPINFO') {
+						printf "\t\tMPPINFO:\n";
+						eval "use Dahdi::Xpp::Mpp";
+						die $@ if $@;
+						$v->showinfo("\t\t  ");
+					} else {
+						printf "\t\t%-20s %s\n", $k, $v;
+					}
+				}
+			}
+		};
+	foreach my $type (qw(USB PCI)) {
+		my $lst = $hardware_list{$type};
+		&$printer("$type devices", @{$lst});
+	}
+}
+
+1;
diff --git a/xpp/perl_modules/Dahdi/Hardware/PCI.pm b/xpp/perl_modules/Dahdi/Hardware/PCI.pm
new file mode 100644
index 0000000..1a4e36d
--- /dev/null
+++ b/xpp/perl_modules/Dahdi/Hardware/PCI.pm
@@ -0,0 +1,245 @@
+package Dahdi::Hardware::PCI;
+#
+# Written by Oron Peled <oron at actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use Dahdi::Utils;
+use Dahdi::Hardware;
+
+our @ISA = qw(Dahdi::Hardware);
+
+# Lookup algorithm:
+# 	First match 'vendor:product/subvendor:subproduct' key
+#	Else match 'vendor:product/subvendor' key
+#	Else match 'vendor:product' key
+#	Else not a dahdi hardware.
+my %pci_ids = (
+	# from wct4xxp
+	'10ee:0314'		=> { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE410P/TE405P (1st Gen)' },
+	'd161:1420'		=> { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE420 (5th Gen)' },
+	'd161:1410'		=> { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE410P (5th Gen)' },
+	'd161:1405'		=> { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE405P (5th Gen)' },
+	'd161:0420/0004'	=> { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE420 (4th Gen)' },
+	'd161:0410/0004'	=> { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE410P (4th Gen)' },
+	'd161:0405/0004'	=> { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE405P (4th Gen)' },
+	'd161:0410/0003'	=> { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE410P (3rd Gen)' },
+	'd161:0405/0003'	=> { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE405P (3rd Gen)' },
+	'd161:0410'		=> { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE410P (2nd Gen)' },
+	'd161:0405'		=> { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE405P (2nd Gen)' },
+	'd161:1220'		=> { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE220 (5th Gen)' },
+	'd161:1205'		=> { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE205P (5th Gen)' },
+	'd161:1210'		=> { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE210P (5th Gen)' },
+	'd161:0220/0004'	=> { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE220 (4th Gen)' },
+	'd161:0205/0004'	=> { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE205P (4th Gen)' },
+	'd161:0210/0004'	=> { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE210P (4th Gen)' },
+	'd161:0205/0003'	=> { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE205P (3rd Gen)' },
+	'd161:0210/0003'	=> { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE210P (3rd Gen)' },
+	'd161:0205'		=> { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE205P ' },
+	'd161:0210'		=> { DRIVER => 'wct4xxp', DESCRIPTION => 'Wildcard TE210P ' },
+
+	# from wctdm24xxp
+	'd161:2400'		=> { DRIVER => 'wctdm24xxp', DESCRIPTION => 'Wildcard TDM2400P' },
+	'd161:0800'		=> { DRIVER => 'wctdm24xxp', DESCRIPTION => 'Wildcard TDM800P' },
+	'd161:8002'		=> { DRIVER => 'wctdm24xxp', DESCRIPTION => 'Wildcard AEX800' },
+	'd161:8003'		=> { DRIVER => 'wctdm24xxp', DESCRIPTION => 'Wildcard AEX2400' },
+	'd161:8005'		=> { DRIVER => 'wctdm24xxp', DESCRIPTION => 'Wildcard TDM410P' },
+	'd161:8006'		=> { DRIVER => 'wctdm24xxp', DESCRIPTION => 'Wildcard AEX410P' },
+	'd161:8007'		=> { DRIVER => 'wctdm24xxp', DESCRIPTION => 'HA8-0000' },
+	'd161:8008'		=> { DRIVER => 'wctdm24xxp', DESCRIPTION => 'HB8-0000' },
+
+	# from pciradio
+	'e159:0001/e16b'	=> { DRIVER => 'pciradio', DESCRIPTION => 'PCIRADIO' },
+
+	# from wcfxo
+	'e159:0001/8084'	=> { DRIVER => 'wcfxo', DESCRIPTION => 'Wildcard X101P clone' },
+	'e159:0001/8085'	=> { DRIVER => 'wcfxo', DESCRIPTION => 'Wildcard X101P' },
+	'e159:0001/8086'	=> { DRIVER => 'wcfxo', DESCRIPTION => 'Wildcard X101P clone' },
+	'e159:0001/8087'	=> { DRIVER => 'wcfxo', DESCRIPTION => 'Wildcard X101P clone' },
+	'1057:5608'		=> { DRIVER => 'wcfxo', DESCRIPTION => 'Wildcard X100P' },
+
+	# from wct1xxp
+	'e159:0001/6159'	=> { DRIVER => 'wct1xxp', DESCRIPTION => 'Digium Wildcard T100P T1/PRI or E100P E1/PRA Board' },
+
+	# from wctdm
+	'e159:0001/a159'	=> { DRIVER => 'wctdm', DESCRIPTION => 'Wildcard S400P Prototype' },
+	'e159:0001/e159'	=> { DRIVER => 'wctdm', DESCRIPTION => 'Wildcard S400P Prototype' },
+	'e159:0001/b100'	=> { DRIVER => 'wctdm', DESCRIPTION => 'Wildcard TDM400P REV E/F' },
+	'e159:0001/b1d9'	=> { DRIVER => 'wctdm', DESCRIPTION => 'Wildcard TDM400P REV I' },
+	'e159:0001/b118'	=> { DRIVER => 'wctdm', DESCRIPTION => 'Wildcard TDM400P REV I' },
+	'e159:0001/b119'	=> { DRIVER => 'wctdm', DESCRIPTION => 'Wildcard TDM400P REV I' },
+	'e159:0001/a9fd'	=> { DRIVER => 'wctdm', DESCRIPTION => 'Wildcard TDM400P REV H' },
+	'e159:0001/a8fd'	=> { DRIVER => 'wctdm', DESCRIPTION => 'Wildcard TDM400P REV H' },
+	'e159:0001/a800'	=> { DRIVER => 'wctdm', DESCRIPTION => 'Wildcard TDM400P REV H' },
+	'e159:0001/a801'	=> { DRIVER => 'wctdm', DESCRIPTION => 'Wildcard TDM400P REV H' },
+	'e159:0001/a908'	=> { DRIVER => 'wctdm', DESCRIPTION => 'Wildcard TDM400P REV H' },
+	'e159:0001/a901'	=> { DRIVER => 'wctdm', DESCRIPTION => 'Wildcard TDM400P REV H' },
+	#'e159:0001'		=> { DRIVER => 'wctdm', DESCRIPTION => 'Wildcard TDM400P REV H' },
+
+	# from wcte11xp
+	'e159:0001/71fe'	=> { DRIVER => 'wcte11xp', DESCRIPTION => 'Digium Wildcard TE110P T1/E1 Board' },
+	'e159:0001/79fe'	=> { DRIVER => 'wcte11xp', DESCRIPTION => 'Digium Wildcard TE110P T1/E1 Board' },
+	'e159:0001/795e'	=> { DRIVER => 'wcte11xp', DESCRIPTION => 'Digium Wildcard TE110P T1/E1 Board' },
+	'e159:0001/79de'	=> { DRIVER => 'wcte11xp', DESCRIPTION => 'Digium Wildcard TE110P T1/E1 Board' },
+	'e159:0001/797e'	=> { DRIVER => 'wcte11xp', DESCRIPTION => 'Digium Wildcard TE110P T1/E1 Board' },
+
+	# from wcte12xp
+	'd161:0120'		=> { DRIVER => 'wcte12xp', DESCRIPTION => 'Wildcard TE12xP' },
+	'd161:8000'		=> { DRIVER => 'wcte12xp', DESCRIPTION => 'Wildcard TE121' },
+	'd161:8001'		=> { DRIVER => 'wcte12xp', DESCRIPTION => 'Wildcard TE122' },
+
+	# from wcb4xxp
+	'd161:b410'		=> { DRIVER => 'wcb4xxp', DESCRIPTION => 'Digium Wildcard B410P' },
+
+	# from tor2
+	'10b5:9030'		=> { DRIVER => 'tor2', DESCRIPTION => 'PLX 9030' },
+	'10b5:3001'		=> { DRIVER => 'tor2', DESCRIPTION => 'PLX Development Board' },
+	'10b5:d00d'		=> { DRIVER => 'tor2', DESCRIPTION => 'Tormenta 2 Quad T1/PRI or E1/PRA' },
+	'10b5:4000'		=> { DRIVER => 'tor2', DESCRIPTION => 'Tormenta 2 Quad T1/E1 (non-Digium clone)' },
+
+	# # from wctc4xxp
+	'd161:3400'		=> { DRIVER => 'wctc4xxp', DESCRIPTION => 'Wildcard TC400P' },
+	'd161:8004'		=> { DRIVER => 'wctc4xxp', DESCRIPTION => 'Wildcard TCE400P' },
+
+	# Cologne Chips:
+	# (Still a partial list)
+	'1397:08b4/1397:b540'	=> { DRIVER => 'wcb4xxp', DESCRIPTION => 'Swyx 4xS0 SX2 QuadBri' },
+	'1397:08b4/1397:b556'	=> { DRIVER => 'wcb4xxp', DESCRIPTION => 'Junghanns DuoBRI ISDN card' },
+	'1397:08b4/1397:b520'	=> { DRIVER => 'wcb4xxp', DESCRIPTION => 'Junghanns QuadBRI ISDN card' },
+	'1397:08b4/1397:b550'	=> { DRIVER => 'wcb4xxp', DESCRIPTION => 'Junghanns QuadBRI ISDN card' },
+	'1397:08b4/1397:b752'	=> { DRIVER => 'wcb4xxp', DESCRIPTION => 'Junghanns QuadBRI ISDN PCI-E card' },
+	'1397:16b8/1397:b552'	=> { DRIVER => 'wcb4xxp', DESCRIPTION => 'Junghanns OctoBRI ISDN card' },
+	'1397:16b8/1397:b55b'	=> { DRIVER => 'wcb4xxp', DESCRIPTION => 'Junghanns OctoBRI ISDN card' },
+	'1397:08b4/1397:e884'	=> { DRIVER => 'wcb4xxp', DESCRIPTION => 'OpenVox B200P' },
+	'1397:08b4/1397:e888'	=> { DRIVER => 'wcb4xxp', DESCRIPTION => 'OpenVox B400P' },
+	'1397:16b8/1397:e998'	=> { DRIVER => 'wcb4xxp', DESCRIPTION => 'OpenVox B800P' },
+	'1397:08b4/1397:b566'	=> { DRIVER => 'wcb4xxp', DESCRIPTION => 'BeroNet BN2S0' },
+	'1397:08b4/1397:b560'	=> { DRIVER => 'wcb4xxp', DESCRIPTION => 'BeroNet BN4S0' },
+	'1397:16b8/1397:b562'	=> { DRIVER => 'wcb4xxp', DESCRIPTION => 'BeroNet BN8S0' },
+	'1397:08b4'		=> { DRIVER => 'qozap', DESCRIPTION => 'Generic Cologne ISDN card' },
+	'1397:16b8'		=> { DRIVER => 'qozap', DESCRIPTION => 'Generic OctoBRI ISDN card' },
+	'1397:30b1'		=> { DRIVER => 'cwain', DESCRIPTION => 'HFC-E1 ISDN E1 card' },
+	'1397:2bd0'		=> { DRIVER => 'zaphfc', DESCRIPTION => 'HFC-S ISDN BRI card' },
+	# Has three submodels. Tested with 0675:1704:
+	'1043:0675'		=> { DRIVER => 'zaphfc', DESCRIPTION => 'ASUSTeK Computer Inc. ISDNLink P-IN100-ST-D' },
+	'1397:f001'		=> { DRIVER => 'ztgsm', DESCRIPTION => 'HFC-GSM Cologne Chips GSM' },
+
+	# Rhino cards (based on pci.ids)
+	'0b0b:0105'	=> { DRIVER => 'r1t1', DESCRIPTION => 'Rhino R1T1' },
+	'0b0b:0205'	=> { DRIVER => 'r4fxo', DESCRIPTION => 'Rhino R14FXO' },
+	'0b0b:0206'	=> { DRIVER => 'rcbfx', DESCRIPTION => 'Rhino RCB4FXO 4-channel FXO analog telphony card' },
+	'0b0b:0305'	=> { DRIVER => 'r1t1', DESCRIPTION => 'Rhino R1T1' },
+	'0b0b:0405'	=> { DRIVER => 'rcbfx', DESCRIPTION => 'Rhino R8FXX' },
+	'0b0b:0406'	=> { DRIVER => 'rcbfx', DESCRIPTION => 'Rhino RCB8FXX 8-channel modular analog telphony card' },
+	'0b0b:0505'	=> { DRIVER => 'rcbfx', DESCRIPTION => 'Rhino R24FXX' },
+	'0b0b:0506'	=> { DRIVER => 'rcbfx', DESCRIPTION => 'Rhino RCB24FXS 24-Channel FXS analog telphony card' },
+	'0b0b:0605'	=> { DRIVER => 'rxt1', DESCRIPTION => 'Rhino R2T1' },
+	'0b0b:0705'	=> { DRIVER => 'rcbfx', DESCRIPTION => 'Rhino R24FXS' },
+	'0b0b:0706'	=> { DRIVER => 'rcbfx', DESCRIPTION => 'Rhino RCB24FXO 24-Channel FXO analog telphony card' },
+	'0b0b:0906'	=> { DRIVER => 'rcbfx', DESCRIPTION => 'Rhino RCB24FXX 24-channel modular analog telphony card' },
+
+	# Sangoma cards (based on pci.ids)
+	'1923:0040'	=> { DRIVER => 'wanpipe', DESCRIPTION => 'Sangoma Technologies Corp. A200/Remora FXO/FXS Analog AFT card' },
+	'1923:0100'	=> { DRIVER => 'wanpipe', DESCRIPTION => 'Sangoma Technologies Corp. A104d QUAD T1/E1 AFT card' },
+	'1923:0300'	=> { DRIVER => 'wanpipe', DESCRIPTION => 'Sangoma Technologies Corp. A101 single-port T1/E1' },
+	'1923:0400'	=> { DRIVER => 'wanpipe', DESCRIPTION => 'Sangoma Technologies Corp. A104u Quad T1/E1 AFT' },
+
+	# Yeastar (from output of modinfo):
+	'e159:0001/2151' => { DRIVER => 'ystdm8xx', DESCRIPTION => 'Yeastar YSTDM8xx'},
+
+	'e159:0001/9500:0003' => { DRIVER => 'opvxa1200', DESCRIPTION => 'OpenVox A800P' },
+
+	# Aligera
+ 	'10ee:1004'		=> { DRIVER => 'ap400', DESCRIPTION => 'Aligera AP40X/APE40X 1E1/2E1/4E1 card' },
+	);
+
+$ENV{PATH} .= ":/usr/sbin:/sbin:/usr/bin:/bin";
+
+sub pci_sorter {
+	return $a->priv_device_name() cmp $b->priv_device_name();
+}
+
+sub new($@) {
+	my $pack = shift || die "Wasn't called as a class method\n";
+	my %attr = @_;
+	my $name = sprintf("pci:%s", $attr{PRIV_DEVICE_NAME});
+	my $self = Dahdi::Hardware->new($name, 'PCI');
+	%{$self} = (%{$self}, %attr);
+	bless $self, $pack;
+	return $self;
+}
+
+my %pci_devs;
+
+sub readfile($) {
+	my $name = shift || die;
+	open(F, $name) || die "Failed to open '$name': $!";
+	my $str = <F>;
+	close F;
+	chomp($str);
+	return $str;
+}
+
+sub scan_devices($) {
+	my @devices;
+
+	while(<$Dahdi::sys_base/bus/pci/devices/*>) {
+		m,([^/]+)$,,;
+		my $name = $1;
+		my $l = readlink $_ || die;
+		$pci_devs{$name}{PRIV_DEVICE_NAME} = $name;
+		$pci_devs{$name}{DEVICE} = $l;
+		$pci_devs{$name}{VENDOR} = readfile "$_/vendor";
+		$pci_devs{$name}{PRODUCT} = readfile "$_/device";
+		$pci_devs{$name}{SUBVENDOR} = readfile "$_/subsystem_vendor";
+		$pci_devs{$name}{SUBPRODUCT} = readfile "$_/subsystem_device";
+		my $dev = $pci_devs{$name};
+		grep(s/0x//, $dev->{VENDOR}, $dev->{PRODUCT}, $dev->{SUBVENDOR}, $dev->{SUBPRODUCT});
+		$pci_devs{$name}{DRIVER} = '';
+	}
+
+	while(</sys/bus/pci/drivers/*/[0-9]*>) {
+		m,^(.*?)/([^/]+)/([^/]+)$,;
+		my $prefix = $1;
+		my $drvname = $2;
+		my $id = $3;
+		my $l = readlink "$prefix/$drvname/module";
+		# Find the real module name (if we can).
+		if(defined $l) {
+			my $moduledir = "$prefix/$drvname/$l";
+			my $modname = $moduledir;
+			$modname =~ s:^.*/::;
+			$drvname = $modname;
+		}
+		$pci_devs{$id}{LOADED} = $drvname;
+	}
+	foreach (sort keys %pci_devs) {
+		my $dev = $pci_devs{$_};
+		my $key;
+		# Try to match
+		$key = "$dev->{VENDOR}:$dev->{PRODUCT}/$dev->{SUBVENDOR}:$dev->{SUBPRODUCT}";
+		$key = "$dev->{VENDOR}:$dev->{PRODUCT}/$dev->{SUBVENDOR}" if !defined($pci_ids{$key});
+		$key = "$dev->{VENDOR}:$dev->{PRODUCT}" if !defined($pci_ids{$key});
+		next unless defined $pci_ids{$key};
+
+		my $d = Dahdi::Hardware::PCI->new(
+			PRIV_DEVICE_NAME	=> $dev->{PRIV_DEVICE_NAME},
+			VENDOR			=> $dev->{VENDOR},
+			PRODUCT			=> $dev->{PRODUCT},
+			SUBVENDOR		=> $dev->{SUBVENDOR},
+			SUBPRODUCT		=> $dev->{SUBPRODUCT},
+			LOADED			=> $dev->{LOADED},
+			DRIVER			=> $pci_ids{$key}{DRIVER},
+			DESCRIPTION		=> $pci_ids{$key}{DESCRIPTION},
+			);
+		push(@devices, $d);
+	}
+	@devices = sort pci_sorter @devices;
+	return @devices;
+}
+
+1;
diff --git a/xpp/perl_modules/Dahdi/Hardware/USB.pm b/xpp/perl_modules/Dahdi/Hardware/USB.pm
new file mode 100644
index 0000000..edc0f4c
--- /dev/null
+++ b/xpp/perl_modules/Dahdi/Hardware/USB.pm
@@ -0,0 +1,206 @@
+package Dahdi::Hardware::USB;
+#
+# Written by Oron Peled <oron at actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use Dahdi::Utils;
+use Dahdi::Hardware;
+use Dahdi::Xpp::Mpp;
+
+our @ISA = qw(Dahdi::Hardware);
+
+my %usb_ids = (
+	# from wcusb
+	'06e6:831c'	=> { DRIVER => 'wcusb', DESCRIPTION => 'Wildcard S100U USB FXS Interface' },
+	'06e6:831e'	=> { DRIVER => 'wcusb2', DESCRIPTION => 'Wildcard S110U USB FXS Interface' },
+	'06e6:b210'	=> { DRIVER => 'wc_usb_phone', DESCRIPTION => 'Wildcard Phone Test driver' },
+
+	# from xpp_usb
+	'e4e4:1130'	=> { DRIVER => 'xpp_usb', DESCRIPTION => 'Astribank-8/16 no-firmware' },
+	'e4e4:1131'	=> { DRIVER => 'xpp_usb', DESCRIPTION => 'Astribank-8/16 USB-firmware' },
+	'e4e4:1132'	=> { DRIVER => 'xpp_usb', DESCRIPTION => 'Astribank-8/16 FPGA-firmware' },
+	'e4e4:1140'	=> { DRIVER => 'xpp_usb', DESCRIPTION => 'Astribank-BRI no-firmware' },
+	'e4e4:1141'	=> { DRIVER => 'xpp_usb', DESCRIPTION => 'Astribank-BRI USB-firmware' },
+	'e4e4:1142'	=> { DRIVER => 'xpp_usb', DESCRIPTION => 'Astribank-BRI FPGA-firmware' },
+	'e4e4:1150'	=> { DRIVER => 'xpp_usb', DESCRIPTION => 'Astribank-multi no-firmware' },
+	'e4e4:1151'	=> { DRIVER => 'xpp_usb', DESCRIPTION => 'Astribank-multi USB-firmware' },
+	'e4e4:1152'	=> { DRIVER => 'xpp_usb', DESCRIPTION => 'Astribank-multi FPGA-firmware' },
+	'e4e4:1160'	=> { DRIVER => 'xpp_usb', DESCRIPTION => 'Astribank-modular no-firmware' },
+	'e4e4:1161'	=> { DRIVER => 'xpp_usb', DESCRIPTION => 'Astribank-modular USB-firmware' },
+	'e4e4:1162'	=> { DRIVER => 'xpp_usb', DESCRIPTION => 'Astribank-modular FPGA-firmware' },
+	'e4e4:1163'	=> { DRIVER => 'xpp_usb', DESCRIPTION => 'Astribank-TwinStar monitor' },
+	
+	# Sangoma USB FXO:
+	'10c4:8461'	=> { DRIVER => 'wanpipe', DESCRIPTION => 'Sangoma WANPIPE USB-FXO Device' },
+	);
+
+
+$ENV{PATH} .= ":/usr/sbin:/sbin:/usr/bin:/bin";
+
+sub usb_sorter() {
+	return $a->hardware_name cmp $b->hardware_name;
+}
+
+sub mpp_addinfo($) {
+	my $self = shift || die;
+
+	my $mppinfo = Dahdi::Xpp::Mpp->new($self);
+	$self->{MPPINFO} = $mppinfo if defined $mppinfo;
+}
+
+sub new($@) {
+	my $pack = shift or die "Wasn't called as a class method\n";
+	my %attr = @_;
+	my $name = sprintf("usb:%s", $attr{PRIV_DEVICE_NAME});
+	my $self = Dahdi::Hardware->new($name, 'USB');
+	%{$self} = (%{$self}, %attr);
+	bless $self, $pack;
+	return $self;
+}
+
+sub readval($) {
+	my $fname = shift || warn;
+	open(F, $fname) || warn "Failed opening '$fname': $!";
+	my $val = <F>;
+	close F;
+	chomp $val;
+	warn "$fname is empty" unless defined $val and $val;
+	return $val;
+}
+
+sub set_transport($$) {
+	my $pack = shift || die;
+	my $xbus = shift || die;
+	my $xbus_dir = shift;
+	my $transportdir = "$xbus_dir/transport";
+	if(! -e "$transportdir/ep_00") {
+		warn "A trasnport in '$transportdir' is not USB";
+		return undef;
+	}
+	my ($usbdev) = glob("$transportdir/usb_device:*");
+	my $busnum;
+	my $devnum;
+	# Different kernels...
+	if(defined $usbdev) {	# It's USB
+		if($usbdev =~ /.*usb_device:usbdev(\d+)\.(\d+)/) {
+			$busnum = $1;
+			$devnum = $2;
+		} else {
+			warn "Bad USB transportdir='$transportdir' usbdev='$usbdev'\n";
+		}
+	} elsif(-f "$transportdir/idVendor" ) {
+		my $transport_link = readlink($transportdir);
+		$transport_link =~ m|/(\d+)-[\d.]+$|;
+		$busnum = $1;
+		$devnum = readval("$transportdir/devnum");
+	}
+	my $usbname = sprintf("%03d/%03d", $busnum, $devnum);
+	#printf STDERR "DEBUG: %03d/%03d\n", $busnum, $devnum;
+	$xbus->{USB_DEVNAME} = $usbname;
+	my $hwdev = Dahdi::Hardware->device_by_hwname("usb:$usbname");
+	if(defined $hwdev) {
+		#print "set_transport: ", $hwdev, "\n";
+		$xbus->{TRANSPORT} = $hwdev;
+		$hwdev->{XBUS} = $xbus;
+		$hwdev->{LOADED} = 'xpp_usb';
+		$xbus->{IS_TWINSTAR} = $hwdev->is_twinstar;
+	}
+	return $hwdev;
+}
+
+sub _get_attr($) {
+	my $attr_file = shift;
+
+	open(ATTR, $attr_file) or die "Failed to read SysFS attribute $attr_file\n";
+	my $value = <ATTR>;
+	chomp $value;
+	return $value;
+}
+
+sub _get_attr_optional($$) {
+	my ($attr_file, $def_val) = @_;
+
+	eval {return _get_attr($attr_file)};
+	
+	# If we got here, _get_attr exploded. Return the default value:
+	return $def_val;
+}
+
+sub scan_devices_sysfs($) {
+	my $pack = shift || die;
+	my @devices = ();
+
+	while (<$Dahdi::sys_base/bus/usb/devices/*-*>) {
+		next unless -r "$_/idVendor"; # endpoints
+
+		# Older kernels, e.g. 2.6.9, don't have the attribute
+		# busnum:
+		m|/(\d+)-[\d.]+$|;
+		my $busnum = $1 || next;
+		my $vendor = _get_attr("$_/idVendor");
+		my $product = _get_attr("$_/idProduct");
+		my $model = $usb_ids{"$vendor:$product"};
+		next unless defined $model;
+		my $devnum = _get_attr("$_/devnum");
+		my $serial = _get_attr_optional("$_/serial", '');
+		my $devname = sprintf("%03d/%03d", $busnum, $devnum);
+		my $d = Dahdi::Hardware::USB->new(
+			IS_ASTRIBANK		=> ($model->{DRIVER} eq 'xpp_usb')?1:0,
+			PRIV_DEVICE_NAME	=> $devname,
+			VENDOR			=> $vendor,
+			PRODUCT			=> $product,
+			SERIAL			=> $serial,
+			DESCRIPTION		=> $model->{DESCRIPTION},
+			DRIVER			=> $model->{DRIVER},
+			);
+		push(@devices, $d);
+	}
+	return @devices;
+}
+
+sub scan_devices($) {
+	my $pack = shift || die;
+	my $usb_device_list = "$Dahdi::proc_usb_base/devices";
+	return $pack->scan_devices_sysfs() unless (-r $usb_device_list);
+
+	my @devices;
+	open(F, $usb_device_list) || die "Failed to open $usb_device_list: $!";
+	local $/ = '';
+	while(<F>) {
+		my @lines = split(/\n/);
+		my ($tline) = grep(/^T/, @lines);
+		my ($pline) = grep(/^P/, @lines);
+		my ($sline) = grep(/^S:.*SerialNumber=/, @lines);
+		my ($busnum,$devnum) = ($tline =~ /Bus=(\w+)\W.*Dev#=\s*(\w+)\W/);
+		my $devname = sprintf("%03d/%03d", $busnum, $devnum);
+		my ($vendor,$product) = ($pline =~ /Vendor=(\w+)\W.*ProdID=(\w+)\W/);
+		my $serial;
+		if(defined $sline) {
+			$sline =~ /SerialNumber=(.*)/;
+			$serial = $1;
+			#$serial =~ s/[[:^print:]]/_/g;
+		}
+		my $model = $usb_ids{"$vendor:$product"};
+		next unless defined $model;
+		my $d = Dahdi::Hardware::USB->new(
+			IS_ASTRIBANK		=> ($model->{DRIVER} eq 'xpp_usb')?1:0,
+			PRIV_DEVICE_NAME	=> $devname,
+			VENDOR			=> $vendor,
+			PRODUCT			=> $product,
+			SERIAL			=> $serial,
+			DESCRIPTION		=> $model->{DESCRIPTION},
+			DRIVER			=> $model->{DRIVER},
+			);
+		push(@devices, $d);
+	}
+	close F;
+	@devices = sort usb_sorter @devices;
+	return @devices;
+}
+
+1;
diff --git a/xpp/perl_modules/Dahdi/Span.pm b/xpp/perl_modules/Dahdi/Span.pm
new file mode 100644
index 0000000..9dd3347
--- /dev/null
+++ b/xpp/perl_modules/Dahdi/Span.pm
@@ -0,0 +1,364 @@
+package Dahdi::Span;
+#
+# Written by Oron Peled <oron at actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use Dahdi::Utils;
+use Dahdi::Chans;
+
+=head1 NAME
+
+Dahdi::Spans - Perl interface to a Dahdi span information
+
+This package allows access from perl to information about a Dahdi
+channel. It is part of the Dahdi Perl package.
+
+A span is a logical unit of Dahdi channels. Normally a port in a
+digital card or a whole analog card.
+
+See documentation of module L<Dahdi> for usage example. Specifically
+C<Dahdi::spans()> must be run initially.
+
+=head1 by_number()
+
+Get a span by its Dahdi span number.
+
+=head1 Span Properties
+
+=head2 num()
+
+The span number.
+
+=head2 name()
+
+The name field of a Dahdi span. E.g.:
+
+  TE2/0/1
+
+=head2 description()
+
+The description field of the span. e.g:
+
+  "T2XXP (PCI) Card 0 Span 1" HDB3/CCS/CRC4 RED
+
+=head2 chans()
+
+The list of the channels (L<Dahdi::Chan> objects) of this span.
+In a scalar context returns the number of channels this span has.
+
+=head2 bchans()
+
+Likewise a list of bchannels (or a count in a scalar context).
+
+=head2 is_sync_master()
+
+Is this span the source of timing for Dahdi?
+
+=head2 type()
+
+Type of span, or "UNKNOWN" if could not be detected. Current known
+types: 
+
+BRI_TE, BRI_NT, E1_TE, E1_NT, J1_TE, J1_NT, T1_TE, T1_NT, FXS, FXO
+
+=head2 is_pri()
+
+Is this an E1/J1/T1 span?
+
+=head2 is_bri()
+
+Is this a BRI span?
+
+=head2 is_digital()
+
+Is this a digital (as opposed to analog) span?
+
+=head2 termtype()
+
+Set for digital spans. "TE" or "NT". Will probably be assumed to be "TE"
+if there's no information pointing either way.
+
+=head2 coding()
+
+Suggested sane coding type (e.g.: "hdb3", "b8zs") for this type of span. 
+
+=head2 framing()
+
+Suggested sane framing type (e.g.: "ccs", "esf") for this type of span. 
+
+=head2 yellow(), crc4()
+
+Likewise, suggestions ofr the respective fields in the span= line in
+/etc/dahdi/system.conf for this span.
+
+=head2 signalling()
+
+Suggested chan_dahdi.conf signalling for channels of this span.
+
+=head2 switchtype()
+
+Suggested chan_dahdi.conf switchtype for channels of this span.
+
+=head1 Note
+
+Most of those properties are normally used as lower-case functions, but
+actually set in the module as capital-letter propeties. To look at e.g.
+"signalling" is set, look for "SIGNALLING".
+
+=cut
+
+sub chans($) {
+	my $span = shift;
+	return @{$span->{CHANS}};
+}
+
+sub by_number($) {
+	my $span_number = shift;
+	die "Missing span number" unless defined $span_number;
+	my @spans = Dahdi::spans();
+
+	my ($span) = grep { $_->num == $span_number } @spans;
+	return $span;
+}
+
+my @bri_strings = (
+		'BRI_(NT|TE)',
+		'(?:quad|octo)BRI PCI ISDN Card.* \[(NT|TE)\]',
+		'octoBRI \[(NT|TE)\] ',
+		'HFC-S PCI A ISDN.* \[(NT|TE)\] ',
+		'(B4XXP) \(PCI\) Card', # Does not expose NT/TE type
+		'(WCBRI)', # has selectable NT/TE modes via dahdi_cfg
+		);
+
+my @pri_strings = (
+		'Tormenta 2 .*Quad (E1|T1)',       # tor2.
+		'Xorcom XPD.*: (E1|T1)',           # Astribank PRI
+		'Digium Wildcard .100P (T1|E1)/', # wct1xxp
+		'ISA Tormenta Span 1',	           # torisa
+		'TE110P T1/E1',                    # wcte11xp
+		'Wildcard TE120P',                 # wcte12xp
+		'Wildcard TE121',                  # wcte12xp
+		'Wildcard TE122',                  # wcte12xp
+		'T[24]XXP \(PCI\) Card ',          # wct4xxp
+		'R[24]T1 \(PCI\) Card',            # rxt1
+		'Rhino R1T1 (E1)/PRA Card',        # r1t1
+		'Rhino R1T1 (T1)/PRI Card',        # r1t1
+		'WP(E1|T1)/.* "wanpipe',           # Sangoma E1/T1
+		);
+
+our $DAHDI_BRI_NET = 'bri_net';
+our $DAHDI_BRI_CPE = 'bri_cpe';
+
+our $DAHDI_PRI_NET = 'pri_net';
+our $DAHDI_PRI_CPE = 'pri_cpe';
+
+sub init_proto($$) {
+	my $self = shift;
+	my $proto = shift;
+
+	$self->{PROTO} = $proto;
+	if($proto eq 'E1') {
+		$self->{DCHAN_IDX} = 15;
+		$self->{BCHAN_LIST} = [ 0 .. 14, 16 .. 30 ];
+	} elsif($proto eq 'T1') {
+		$self->{DCHAN_IDX} = 23;
+		$self->{BCHAN_LIST} = [ 0 .. 22 ];
+	}
+	$self->{TYPE} = "${proto}_$self->{TERMTYPE}";
+}
+
+sub new($$) {
+	my $pack = shift or die "Wasn't called as a class method\n";
+	my $proc_file = shift or die "Missing a proc file parameter\n";
+	$proc_file =~ m{[^/]*/(\d+)$};
+	my $num = $1 or die " Invalid span file name: $proc_file\n";
+	my $self = { NUM => $num };
+	bless $self, $pack;
+	$self->{TYPE} = "UNKNOWN";
+	open(F, "$proc_file") or die "Failed to open '$proc_file\n";
+	my $head = <F>;
+	chomp $head;
+	$self->{IS_DIGITAL} = 0;
+	$self->{IS_BRI} = 0;
+	$self->{IS_PRI} = 0;
+	foreach my $cardtype (@bri_strings) {
+		if($head =~ m/$cardtype/) {
+			my $termtype = $1;
+			$termtype = 'TE' if ( $1 eq 'B4XXP' or $1 eq 'WCBRI' );
+			$self->{IS_DIGITAL} = 1;
+			$self->{IS_BRI} = 1;
+			$self->{TERMTYPE} = $termtype;
+			$self->{TYPE} = "BRI_$termtype";
+			$self->{DCHAN_IDX} = 2;
+			$self->{BCHAN_LIST} = [ 0, 1 ];
+			last;
+		}
+	}
+	foreach my $cardtype (@pri_strings) {
+		if($head =~ m/$cardtype/) {
+			my @info;
+
+			push(@info, $1) if defined $1;
+			push(@info, $2) if defined $2;
+			my ($proto) = grep(/(E1|T1|J1)/, @info);
+			$proto = 'UNKNOWN' unless defined $proto;
+			my ($termtype) = grep(/(NT|TE)/, @info);
+			$termtype = 'UNKNOWN' unless defined $termtype;
+
+			$self->{IS_DIGITAL} = 1;
+			$self->{IS_PRI} = 1;
+			$self->{TERMTYPE} = $termtype;
+			$self->init_proto($proto);
+			last;
+		}
+	}
+	($self->{NAME}, $self->{DESCRIPTION}) = (split(/\s+/, $head, 4))[2, 3];
+	$self->{IS_DAHDI_SYNC_MASTER} =
+		($self->{DESCRIPTION} =~ /\(MASTER\)/) ? 1 : 0;
+	$self->{CHANS} = [];
+	my @channels;
+	my $index = 0;
+	while(<F>) {
+		chomp;
+		s/^\s*//;
+		s/\s*$//;
+		next unless /\S/;
+		next unless /^\s*\d+/; # must be a real channel string.
+		my $c = Dahdi::Chans->new($self, $index, $_);
+		push(@channels, $c);
+		$index++;
+	}
+	close F;
+	if($self->is_pri()) {
+		# Check for PRI with unknown type strings
+		if($index == 31) {
+			if($self->{PROTO} eq 'UNKNOWN') {
+				$self->init_proto('E1');
+			} elsif($self->{PROTO} ne 'E1')  {
+				die "$index channels in a $self->{PROTO} span";
+			}
+		} elsif($index == 24) {
+			if($self->{PROTO} eq 'UNKNOWN') {
+				$self->init_proto('T1');	# FIXME: J1?
+			} elsif($self->{PROTO} ne 'T1') {
+				die "$index channels in a $self->{PROTO} span";
+			}
+		}
+	}
+	@channels = sort { $a->num <=> $b->num } @channels;
+	$self->{CHANS} = \@channels;
+	$self->{YELLOW} = undef;
+	$self->{CRC4} = undef;
+	$self->{SOFTNTTE} = undef;
+	$self->{TERMINATION} = undef;
+	if($self->is_bri()) {
+		$self->{CODING} = 'ami';
+		$self->{DCHAN} = ($self->chans())[$self->{DCHAN_IDX}];
+		$self->{BCHANS} = [ ($self->chans())[@{$self->{BCHAN_LIST}}] ];
+		# Infer some info from channel name:
+		my $first_chan = ($self->chans())[0] || die "$0: No channels in span #$num\n";
+		my $chan_fqn = $first_chan->fqn();
+		if($chan_fqn =~ m(ZTHFC.*/|ztqoz.*/|XPP_BRI_.*|B4/.*|WCBRI/.*)) {		# BRI
+			if($chan_fqn =~ m(WCBRI/.*)) {		# make sure to set termination resistors on hybrid cards
+				$self->{TERMINATION} = 'term';
+				$self->{SOFTNTTE} = 'te';
+			}
+			$self->{FRAMING} = 'ccs';
+			$self->{SWITCHTYPE} = 'euroisdn';
+			$self->{SIGNALLING} = ($self->{TERMTYPE} eq 'NT') ? $DAHDI_BRI_NET : $DAHDI_BRI_CPE ;
+		} elsif($chan_fqn =~ m(ztgsm.*/)) {				# Junghanns's GSM cards. 
+			$self->{FRAMING} = 'ccs';
+			$self->{SIGNALLING} = 'gsm';
+		}
+	}
+	if($self->is_pri()) {
+		$self->{DCHAN} = ($self->chans())[$self->{DCHAN_IDX}];
+		$self->{BCHANS} = [ ($self->chans())[@{$self->{BCHAN_LIST}}] ];
+		if($self->{PROTO} eq 'E1') {
+			$self->{CODING} = 'hdb3';
+			$self->{FRAMING} = 'ccs';
+			$self->{SWITCHTYPE} = 'euroisdn';
+			$self->{CRC4} = 'crc4';
+		} elsif($self->{PROTO} eq 'T1') {
+			$self->{CODING} = 'b8zs';
+			$self->{FRAMING} = 'esf';
+			$self->{SWITCHTYPE} = 'national';
+		} else {
+			die "'$self->{PROTO}' unsupported yet";
+		}
+	}
+	return $self;
+}
+
+sub bchans($) {
+	my $self = shift || die;
+
+	return @{$self->{BCHANS}};
+}
+
+sub set_termtype($$) {
+	my $span = shift || die;
+	my $termtype = shift || die;
+	$span->{TERMTYPE} = $termtype;
+	$span->{SIGNALLING} = ($termtype eq 'NT') ? $DAHDI_PRI_NET : $DAHDI_PRI_CPE ;
+	$span->{TYPE} = $span->proto . "_$termtype";
+}
+
+sub pri_set_fromconfig($$) {
+	my $span = shift || die;
+	my $genconf = shift || die;
+	my $name = $span->name;
+#	if(defined $termtype) {
+#		die "Termtype for $name already defined as $termtype\n";
+#	}
+	my $pri_termtype = $genconf->{pri_termtype};
+	my @pri_specs;
+	if(defined $pri_termtype) {
+		@pri_specs = @{$pri_termtype};
+	}
+	push(@pri_specs , 'SPAN/* TE');		# Default
+	my @patlist = ( "SPAN/" . $span->num );
+	my $xpd = $span->{XPD};
+	if(defined $xpd) {
+		my $xbus = $xpd->xbus;
+		my $xbus_name = $xbus->name;
+		my $xpd_name = "XPD-" . $xpd->id;
+		my $label = $xbus->label;
+		my $connector = $xbus->connector;
+		#print "DEBUG: '$xbus_name/$xpd_name' LABEL='$label' CONNECTOR='$connector'\n";
+		push(@patlist, "NUM/$xbus_name/$xpd_name");
+		push(@patlist, "LABEL/$label/$xpd_name");
+		push(@patlist, "CONNECTOR/$connector/$xpd_name");
+	}
+	#print STDERR "PATLIST=@patlist\n";
+	my $match_termtype;
+SPEC:
+	for(my $i = 0; $i < @pri_specs; $i++) {
+		my $spec = $pri_specs[$i];
+		#print STDERR "spec: $spec\n";
+		my ($match, $termtype) = split(/\s+/, $spec);
+		next unless defined $match and defined $termtype;
+		# Convert "globs" to regex
+		$match =~ s/\*/.*/g;
+		$match =~ s/\?/./g;
+		#print STDERR "match: $match\n";
+		foreach my $pattern (@patlist) {
+			#print STDERR "testmatch: $pattern =~ $match\n";
+			if($pattern =~ $match) {
+				#print STDERR "MATCH '$pattern' ~ '$match' termtype=$termtype\n";
+				$match_termtype = $termtype;
+				last SPEC;
+			}
+		}
+	}
+	die "Unknown pri_termtype" unless defined $match_termtype;
+	$span->set_termtype($match_termtype);
+}
+
+
+1;
diff --git a/xpp/perl_modules/Dahdi/Utils.pm b/xpp/perl_modules/Dahdi/Utils.pm
new file mode 100644
index 0000000..4ca468b
--- /dev/null
+++ b/xpp/perl_modules/Dahdi/Utils.pm
@@ -0,0 +1,66 @@
+package Dahdi::Utils;
+
+# Accessors (miniperl does not have Class:Accessor)
+our $AUTOLOAD;
+sub AUTOLOAD {
+	my $self = shift;
+	my $name = $AUTOLOAD;
+	$name =~ s/.*://;   # strip fully-qualified portion
+	return if $name =~ /^[A-Z_]+$/;	# ignore special methods (DESTROY)
+	my $key = uc($name);
+	my $val = shift;
+	if (defined $val) {
+		#print STDERR "set: $key = $val\n";
+		return $self->{$key} = $val;
+	} else {
+		if(!exists $self->{$key}) {
+			#$self->xpp_dump;
+			#die "Trying to get uninitialized '$key'";
+		}
+		my $val = $self->{$key};
+		#print STDERR "get: $key ($val)\n";
+		return $val;
+	}
+}
+
+# Initialize ProcFS and SysFS pathes, in case the user set
+# DAHDI_VIRT_TOP
+BEGIN {
+	if (exists $ENV{DAHDI_VIRT_TOP}) {
+		$Dahdi::virt_base = $ENV{DAHDI_VIRT_TOP};
+	} else {
+		$Dahdi::virt_base = '';
+	}
+	$Dahdi::proc_dahdi_base = "$Dahdi::virt_base/proc/dahdi";
+	$Dahdi::proc_xpp_base = "$Dahdi::virt_base/proc/xpp";
+	$Dahdi::proc_usb_base = "$Dahdi::virt_base/proc/bus/usb";
+	$Dahdi::sys_base = "$Dahdi::virt_base/sys";
+}
+
+sub xpp_dump($) {
+	my $self = shift || die;
+	printf STDERR "Dump a %s\n", ref($self);
+	foreach my $k (sort keys %{$self}) {
+		my $val = $self->{$k};
+		$val = '**UNDEF**' if !defined $val;
+		printf STDERR "    %-20s %s\n", $k, $val;
+	}
+}
+
+# Based on Autoloader
+
+sub import {
+	my $pkg = shift;
+	my $callpkg = caller;
+
+	#print STDERR "import: $pkg, $callpkg\n";
+	#
+	# Export symbols, but not by accident of inheritance.
+	#
+	die "Sombody inherited Dahdi::Utils" if $pkg ne 'Dahdi::Utils';
+	no strict 'refs';
+	*{ $callpkg . '::AUTOLOAD' } = \&AUTOLOAD;
+	*{ $callpkg . '::xpp_dump' } = \&xpp_dump;
+}
+
+1;
diff --git a/xpp/perl_modules/Dahdi/Xpp.pm b/xpp/perl_modules/Dahdi/Xpp.pm
new file mode 100644
index 0000000..d4b315b
--- /dev/null
+++ b/xpp/perl_modules/Dahdi/Xpp.pm
@@ -0,0 +1,343 @@
+package Dahdi::Xpp;
+#
+# Written by Oron Peled <oron at actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use Dahdi::Hardware;
+use Dahdi::Xpp::Xbus;
+
+=head1 NAME
+
+Dahdi::Xpp - Perl interface to the Xorcom Astribank drivers.
+
+=head1 SYNOPSIS
+
+  # Listing all Astribanks:
+  use Dahdi::Xpp;
+  # scans hardware:
+  my @xbuses = Dahdi::Xpp::xbuses("SORT_CONNECTOR");
+  for my $xbus (@xbuses) {
+    print $xbus->name." (".$xbus->label .", ". $xbus->connector .")\n";
+    for my $xpd ($xbus->xpds) {
+      print " - ".$xpd->fqn,"\n";
+    }
+  }
+=cut
+
+#
+# A global handle for all xbuses
+#
+my @xbuses;
+
+our $sysfs_astribanks;
+our $sysfs_xpds;
+our $sysfs_ab_driver;
+
+BEGIN {
+	my $virt_base = $Dahdi::virt_base;
+	$sysfs_astribanks = "$virt_base/sys/bus/astribanks/devices";
+	$sysfs_xpds = "$virt_base/sys/bus/xpds/devices";
+	$sysfs_ab_driver = "$virt_base/sys/bus/astribanks/drivers/xppdrv";
+}
+
+sub scan($) {
+	my $pack = shift || die;
+
+	opendir(D, $sysfs_astribanks) || return();
+	while(my $entry = readdir D) {
+		next unless $entry =~ /xbus-(\d+)/;
+		my $xbus = Dahdi::Xpp::Xbus->new($1);
+		push(@xbuses, $xbus);
+	}
+	closedir D;
+	return @xbuses;
+}
+
+# Nominal sorters for xbuses
+sub by_name {
+	return $a->name cmp $b->name;
+}
+
+sub by_connector {
+	return $a->connector cmp $b->connector;
+}
+
+sub by_label {
+	my $cmp = $a->label cmp $b->label;
+	return $cmp if $cmp != 0;
+	return $a->connector cmp $b->connector;
+}
+
+sub score_type {
+	my $score;
+
+	return 1 if grep(/\b[ETJ]1/, @_);
+	return 2 if grep(/\bBRI/, @_);
+	return 3 if grep(/\bFXO/, @_);
+	return 4;	# FXS
+}
+
+sub by_type {
+	my @a_types = map { $_->type } $a->xpds();
+	my @b_types = map { $_->type } $b->xpds();
+	my $res;
+
+	my $a_score = score_type(@a_types);
+	my $b_score = score_type(@b_types);
+	#printf STDERR "DEBUG-a: %s %s %s\n", $a->name, $a_score, join(',', at a_types);
+	#printf STDERR "DEBUG-b: %s %s %s\n", $b->name, $b_score, join(',', at b_types);
+	$res = $a_score <=> $b_score;
+	$res = $a->connector cmp $b->connector if $res == 0;
+	return $res;
+}
+
+sub by_xpporder {
+	my $cmp = $a->xpporder cmp $b->xpporder;
+	return $cmp if $cmp != 0;
+	return $a->connector cmp $b->connector;
+}
+
+=head1 xbuses([sort_order])
+
+Scans system (/proc and /sys) and returns a list of Astribank (Xbus) 
+objects. The optional parameter sort_order is the order in which 
+the Astribanks will be returns:
+
+
+=head1 sorters([sort_order])
+
+With no parameters, returns the names of built in sorters.
+With a single parameter, returns a reference to the requested built in sorter.
+Also, for convenience, a reference to a custom sorter function may be passed
+and returned as is.
+
+The built in sorters are:
+
+=over
+
+=item SORT_XPPORDER
+
+Sort by ordering defined in F</etc/dahdi/xpp_order> file.
+Astribanks can be listed in this file by their label or by
+their connector string (prefixed with <@>).
+
+Astribanks not listed in the F<xpp_order> file are sorted
+via ordering number 999 -- So they come after the Astribanks
+that are listed.
+
+Astribanks with same ordering number (e.g: 999) are sorted
+by their connector string (to preserve legacy behaviour).
+
+=item SORT_CONNECTOR
+
+Sort by the connector string. For USB this defines the "path" to get to
+the device through controllers, hubs etc.
+
+=item SORT_LABEL
+
+Sorts by the label of the Astribank. The label field is unique to the
+Astribank. It can also be viewed through 'lsusb -v' without the drivers
+loaded (the iSerial field in the Device Descriptor). This is normally
+relieble, but some older Astribanks have an empty label.
+
+=item SORT_NAME
+
+Sort by the "name". e.g: "XBUS-00". The order of Astribank names depends
+on the load order, and hence may change between different runs.
+
+=item SORT_TYPE
+
+Sort by XPD types. First Astribanks with E1/T1/J1 XPDs, then with BRI,
+then with FXO, then ones with only FXS ports. Within each type they
+are sorted by the connector field (as in SORT_CONNECTOR above).
+
+=item custom function
+
+Instead of using a predefined sorter, you can pass your own sorting
+function. See the example sorters in the code of this module.
+
+=back
+
+=cut
+
+sub sorters {
+	my %sorter_table = (
+		SORT_CONNECTOR	=> \&by_connector,
+		SORT_NAME	=> \&by_name,
+		SORT_LABEL	=> \&by_label,
+		SORT_TYPE	=> \&by_type,
+		SORT_XPPORDER	=> \&by_xpporder,
+		# Aliases
+		connector	=> \&by_connector,
+		name		=> \&by_name,
+		label		=> \&by_label,
+		type		=> \&by_type,
+		xpporder	=> \&by_xpporder,
+	);
+	my $which_sorter = shift || return sort keys %sorter_table;
+	return $which_sorter if ref($which_sorter) eq 'CODE';
+	return $sorter_table{$which_sorter};
+}
+
+sub add_xpporder(@) {
+	my @xbuses = @_;
+	my $cfg = $ENV{XPPORDER_CONF} || '/etc/dahdi/xpp_order';
+	my %order;
+
+	# Set defaults
+	foreach my $xbus (@xbuses) {
+		$xbus->{XPPORDER} = 99;
+	}
+	# Read from optional config file
+	if(!open(F, $cfg)) {
+		warn "$0: Failed opening '$cfg': $!"
+			unless $! == 2;		# ENOENT
+		return;
+	}
+	my $count = 1;
+	while(<F>) {
+		chomp;
+		s/#.*//;
+		s/^\s*//;
+		s/\s*$//;
+		next unless /\S/;
+		$order{$_} = $count++;
+	}
+	close F;
+	# Overrides from config file
+	foreach my $xbus (@xbuses) {
+		my $label = $xbus->label;
+		my $val;
+		$val = $order{$label};
+		$val = $order{$xbus->connector} unless defined $val;
+		$xbus->{XPPORDER} = $val if defined $val;
+	}
+}
+
+sub xbuses {
+	my $optsort = shift || 'SORT_XPPORDER';
+	my @sorted_xbuses;
+
+	if(! @xbuses) {
+		@xbuses = Dahdi::Xpp->scan();
+	}
+	add_xpporder(@xbuses);
+	my $sorter = sorters($optsort);
+	die "Unknown optional sorter '$optsort'" unless defined $sorter;
+	@sorted_xbuses = sort $sorter @xbuses;
+	return @sorted_xbuses;
+}
+
+sub xpd_of_span($) {
+	my $span = shift or die "Missing span parameter";
+	return undef unless defined $span;
+	foreach my $xbus (Dahdi::Xpp::xbuses) {
+		foreach my $xpd ($xbus->xpds()) {
+			return $xpd if $xpd->fqn eq $span->name;
+		}
+	}
+	return undef;
+}
+
+=head1 sync([new_sync_source])
+
+Gets (and optionally sets) the internal Astribanks synchronization
+source. When used to set sync source, returns the original sync source.
+
+A synchronization source is a value valid writing into /proc/xpp/sync .
+For more information read that file and see README.Astribank .
+
+=cut
+
+sub sync_via_proc {
+	my $newsync = shift;
+	my $result;
+	my $newapi = 0;
+
+	my $proc_base = $Dahdi::proc_xpp_base;
+	my $file = "$proc_base/sync";
+	return '' unless -f $file;
+	# First query
+	open(F, "$file") or die "Failed to open $file for reading: $!";
+	while(<F>) {
+		chomp;
+		/SYNC=/ and $newapi = 1;
+		s/#.*//;
+		if(/\S/) {	# First non-comment line
+			s/^SYNC=\D*// if $newapi;
+			$result = $_;
+			last;
+		}
+	}
+	close F;
+	if(defined($newsync)) {		# Now change
+		$newsync =~ s/.*/\U$&/;
+		if($newsync =~ /^(\d+)$/) {
+			$newsync = ($newapi)? "SYNC=$1" : "$1 0";
+		} elsif($newsync ne 'DAHDI') {
+			die "Bad sync parameter '$newsync'";
+		}
+		open(F, ">$file") or die "Failed to open $file for writing: $!";
+		print F $newsync;
+		close(F) or die "Failed in closing $file: $!";
+	}
+	return $result;
+}
+
+sub sync {
+	my ($newsync) = @_;
+	my $result;
+	my $file = "$sysfs_ab_driver/sync";
+	if(! -f $file) {	# Old /proc interface
+		return sync_via_proc(@_);
+	}
+	open(F, "$file") or die "Failed to open $file for reading: $!";
+	$result = <F>;
+	close F;
+	chomp $result;
+	$result =~ s/^SYNC=\D*//;
+	if(defined $newsync) {		# Now change
+		$newsync =~ s/.*/\U$&/;
+		if($newsync =~ /^(\d+)$/) {
+			$newsync = "SYNC=$1";
+		} elsif($newsync ne 'DAHDI') {
+			die "Bad sync parameter '$newsync'";
+		}
+		open(F, ">$file") or die "Failed to open $file for writing: $!";
+		print F $newsync;
+		close(F) or die "Failed in closing $file: $!";
+	}
+	return $result;
+}
+
+=head1 SEE ALSO
+
+=over
+
+=item L<Dahdi::Xpp::Xbus>
+
+Xbus (Astribank) object.
+
+=item L<Dahdi::Xpp::Xpd>
+
+XPD (the rough equivalent of a Dahdi span) object.
+
+=item L<Dahdi::Xpp::Line>
+
+Object for a line: an analog port or a time-slot in a adapter. 
+Equivalent of a channel in Dahdi.
+
+=item L<Dahdi>
+
+General documentation in the master package.
+
+=back
+
+=cut
+
+1;
diff --git a/xpp/perl_modules/Dahdi/Xpp/Line.pm b/xpp/perl_modules/Dahdi/Xpp/Line.pm
new file mode 100644
index 0000000..1302a9e
--- /dev/null
+++ b/xpp/perl_modules/Dahdi/Xpp/Line.pm
@@ -0,0 +1,89 @@
+package Dahdi::Xpp::Line;
+#
+# Written by Oron Peled <oron at actcom.co.il>
+# Copyright (C) 2008, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use Dahdi::Utils;
+
+sub new($$$) {
+	my $pack = shift or die "Wasn't called as a class method\n";
+	my $xpd = shift or die;
+	my $index = shift;
+	defined $index or die;
+	my $self = {};
+	bless $self, $pack;
+	$self->{XPD} = $xpd;
+	$self->{INDEX} = $index;
+	return $self;
+}
+
+sub blink($$) {
+	my $self = shift;
+	my $on = shift;
+	my $xpd = $self->xpd;
+	my $result = $xpd->xpd_getattr("blink");
+	$result = hex($result);
+	if(defined($on)) {		# Now change
+		my $onbitmask = 1 << $self->index;
+		my $offbitmask = $result & ~$onbitmask;
+
+		$result = $offbitmask;
+		$result |= $onbitmask if $on;
+		$result = $xpd->xpd_setattr("blink", $result);
+	}
+	return $result;
+}
+
+sub create_all($$) {
+	my $pack = shift or die "Wasn't called as a class method\n";
+	my $xpd = shift || die;
+	my $procdir = shift || die;
+	local $/ = "\n";
+	my @lines;
+	for(my $i = 0; $i < $xpd->{CHANNELS}; $i++) {
+		my $line = Dahdi::Xpp::Line->new($xpd, $i);
+		push(@lines, $line);
+	}
+	$xpd->{LINES} = \@lines;
+	if($xpd->type eq 'FXO') {
+		my $battery = $xpd->xpd_getattr("fxo_battery");
+		if(defined $battery) {
+			my @batt = split(/\s+/, $battery);
+			foreach my $l (@lines) {
+				die unless @batt;
+				my $state = shift @batt;
+				$l->{BATTERY} = ($state eq '+') ? 1 : 0;
+			}
+		} else {
+			# Fallback to old interface
+			my ($infofile) = glob "$procdir/*_info";
+			die "Failed globbing '$procdir/*_info'" unless defined $infofile;
+			open(F, "$infofile") || die "Failed opening '$infofile': $!";
+			my $battery_info = 0;
+			while (<F>) {
+				chomp;
+				$battery_info = 1 if /^Battery:/;
+				if($battery_info && s/^\s*on\s*:\s*//) {
+					my @batt = split;
+					foreach my $l (@lines) {
+						die unless @batt;
+						my $state = shift @batt;
+						$l->{BATTERY} = ($state eq '+') ? 1 : 0;
+					}
+					$battery_info = 0;
+					die if @batt;
+				}
+			}
+			close F;
+		}
+	}
+	close F;
+}
+
+
+1;
diff --git a/xpp/perl_modules/Dahdi/Xpp/Mpp.pm b/xpp/perl_modules/Dahdi/Xpp/Mpp.pm
new file mode 100644
index 0000000..2c11a94
--- /dev/null
+++ b/xpp/perl_modules/Dahdi/Xpp/Mpp.pm
@@ -0,0 +1,222 @@
+package Dahdi::Xpp::Mpp;
+#
+# Written by Oron Peled <oron at actcom.co.il>
+# Copyright (C) 2009, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use File::Basename;
+use Getopt::Std;
+BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/perl_modules"); }
+
+use Dahdi::Utils;
+
+=head1 NAME
+
+Dahdi::Xpp::Mpp - Perl interface to C<astribank_tool(8)>
+
+=head1 DESCRIPTION
+
+This package uses C<astribank_tool(8)> to collect information
+about Astribanks via MPP (Management Processor Protocol).
+
+The binary default location is F</usr/sbin/astribank_tool>. It may be
+overridden via module parameter C<astribank_tool=> and the
+C<ASTRIBANK_TOOL> environment variable (higher priority).
+
+It may also be set/unset from code via the set_astribank_tool() method.
+
+=head1 METHODS
+
+=head2 mpp_addinfo()
+
+Called with a list of C<Dahdi::Hardware> objects and augment their
+data with C<Dahdi::Xpp::Mpp> objects.
+
+This method is the normal external interface of this class.
+
+=head2 new()
+
+Constructor. Receive as parameter an instance of C<Dahdi::Hardware> class
+and return a C<Dahdi::Xpp:Mpp> object.
+
+Normally, used indirectly via the mpp_addinfo() method.
+
+=head2 set_astribank_tool()
+
+Override default location of astribank_tool(8). It is legal
+to set it to C<undef>.
+
+=head2 showinfo()
+
+Dump an C<Dahdi::Xpp::Mpp> object for debugging.
+
+=cut
+
+my $astribank_tool = '/usr/sbin/astribank_tool';
+
+sub set_astribank_tool($$) {
+	my $pack = shift || die;
+	$pack eq 'Dahdi::Xpp::Mpp' or die "$0: Called from wrong package? ($pack)";
+	my $arg = shift;
+	$astribank_tool = $arg;
+	#print STDERR "Setting astribank_tool='$astribank_tool'\n";
+}
+
+sub import {
+	my ($param) = grep(/^astribank_tool=/, @_);
+	if(defined $param) {
+		$param =~ s/^astribank_tool=//;
+		$astribank_tool = $param;
+	}
+	if(defined $ENV{ASTRIBANK_TOOL}) {
+		$astribank_tool = $ENV{ASTRIBANK_TOOL};
+	}
+}
+
+sub showinfo($$) {
+	my $self = shift || die;
+	my $prefix = shift || die;
+
+	return unless defined $self;
+	foreach my $k (sort keys %{$self}) {
+		my $v = $self->{$k};
+		if(ref($v) eq 'ARRAY') {
+			my @a = @{$v};
+			my $i;
+			my $ki;
+			for($i = 0; $i < @a; $i++) {
+				$ki = sprintf "%s[%d]", $k, $i;
+				printf "$prefix%-20s %s\n", $ki, $a[$i];
+			}
+		} else {
+			if($k eq 'DEV') {
+				printf "$prefix%-20s -> %s\n", $k, $v->hardware_name;
+			} else {
+				printf "$prefix%-20s %s\n", $k, $v;
+			}
+		}
+	}
+}
+
+sub astribank_tool_cmd($@) {
+	my $dev = shift || die;
+	my @args = @_;
+	my $usb_top;
+
+	# Find USB bus toplevel
+	$usb_top = '/dev/bus/usb';
+	$usb_top = '/proc/bus/usb' unless -d $usb_top;
+	die "No USB toplevel found\n" unless -d $usb_top;
+	my $name = $dev->priv_device_name();
+	die "$0: Unkown private device name" unless defined $name;
+	my $path = "$usb_top/$name";
+	return ($astribank_tool, '-D', "$path", @args);
+}
+
+sub new($$$) {
+	my $pack = shift || die;
+	my $dev = shift || die;
+	my $product = $dev->product;
+
+	return undef unless $dev->is_astribank;
+	return undef unless $dev->bus_type eq 'USB';
+	return undef unless $product =~ /116./;
+	my $mppinfo = {
+			DEV	=> $dev,
+			HAS_MPP	=> 1,
+		};
+	bless $mppinfo, $pack;
+	#print STDERR "$astribank_tool($path) -- '$product'\n";
+	if(! -x $astribank_tool) {
+		warn "Could not run '$astribank_tool'\n";
+		return $mppinfo;
+	}
+	return $mppinfo unless $product =~ /116[12]/;
+	$mppinfo->{'MPP_TALK'} = 1;
+	my @cmd = astribank_tool_cmd($dev, '-Q');
+	my $name = $dev->priv_device_name();
+	my $dbg_file = "$name";
+	$dbg_file =~ s/\W/_/g;
+	#$dbg_file = "/tmp/twinstar-debug-$dbg_file";
+	$dbg_file = "/dev/null";
+	unless(open(F, "@cmd 2> '$dbg_file' |")) {
+		warn "Failed running '$astribank_tool': $!";
+		return undef;
+	}
+	local $/ = "\n";
+	local $_;
+	while(<F>) {
+		chomp;
+		#printf STDERR "'%s'\n", $_;
+		if(s/^INFO:\s*//) {
+			$mppinfo->{'PROTOCOL'} = $1 if /^protocol\s+version:\s*(\d+)/i;
+		} elsif(s/^EEPROM:\s*//) {
+			$mppinfo->{'EEPROM_RELEASE'} = $1 if /^release\s*:\s*([\d\.]+)/i;
+			$mppinfo->{'EEPROM_LABEL'} = $1 if /^label\s*:\s*([\w._'-]+)/i;
+		} elsif(s/^Extrainfo:\s+:\s*(.+?)$//) {
+			$mppinfo->{'EEPROM_EXTRAINFO'} = $1;
+		} elsif(s/^Capabilities:\s*TwinStar\s*:\s*(.+?)$//) {
+			my $cap = $1;
+			$mppinfo->{'TWINSTAR_CAPABLE'} = ($cap =~ /yes/i) ? 1 : 0;
+		} elsif(s/^TwinStar:\s*//) {
+			$mppinfo->{'TWINSTAR_PORT'} = $1 if /^connected\s+to\s*:\s*usb-(\d+)/i;
+			if(s/^USB-(\d+)\s*POWER\s*:\s*//) {
+				my $v = ($_ eq 'ON') ? 1 : 0;
+				$mppinfo->{'TWINSTAR_POWER'}->[$1] = $v;
+			}
+			if(s/^Watchdog[^:]+:\s*//) {
+				my $v = ($_ eq 'on-guard') ? 1 : 0;
+				$mppinfo->{'TWINSTAR_WATCHDOG'} = $v;
+			}
+			#printf STDERR "\t%s\n", $_;
+		} else {
+			#printf STDERR "\t%s\n", $_;
+		}
+	}
+	unless(close F) {
+		warn "Failed running '$astribank_tool': $!";
+		return undef;
+	}
+	#$mppinfo->showinfo;
+	return $mppinfo;
+}
+
+sub mpp_setwatchdog($$) {
+	my $mppinfo = shift || die;
+	my $on = shift;
+	die "$0: Bad value '$on'" unless defined($on) && $on =~ /^[0-1]$/;
+	my $dev = $mppinfo->dev || die;
+	return undef unless defined $mppinfo->mpp_talk;
+	my $old = $mppinfo->tws_watchdog;
+	my @cmd = astribank_tool_cmd($dev, '-w', $on);
+	print STDERR "DEBUG($on): '@cmd'\n";
+	system(@cmd);
+	die "Running $astribank_tool failed: $?" if $?;
+}
+
+sub mpp_jump($) {
+	my $mppinfo = shift || die;
+	my $dev = $mppinfo->dev || die;
+	return undef unless defined $mppinfo->mpp_talk;
+	my $port = $mppinfo->twinstar_port;
+	$port = ($port == 1) ? 0 : 1;
+	die "Unknown TwinStar port" unless defined $port;
+	my @cmd = astribank_tool_cmd($dev, '-p', $port);
+	system(@cmd);
+	die "Running $astribank_tool failed: $?" if $?;
+}
+
+sub mpp_addinfo($@) {
+	my $pack = shift || die;
+	my @devlist = @_;
+
+	foreach my $dev (@devlist) {
+		$dev->{MPPINFO} = $pack->new($dev);
+	}
+}
+
+1;
diff --git a/xpp/perl_modules/Dahdi/Xpp/Xbus.pm b/xpp/perl_modules/Dahdi/Xpp/Xbus.pm
new file mode 100644
index 0000000..b68d7cc
--- /dev/null
+++ b/xpp/perl_modules/Dahdi/Xpp/Xbus.pm
@@ -0,0 +1,213 @@
+package Dahdi::Xpp::Xbus;
+#
+# Written by Oron Peled <oron at actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use Dahdi::Utils;
+use Dahdi::Hardware;
+use Dahdi::Xpp::Xpd;
+
+sub xpds($) {
+	my $xbus = shift;
+	return @{$xbus->{XPDS}};
+}
+
+sub by_number($) {
+	my $busnumber = shift;
+	die "Missing xbus number parameter" unless defined $busnumber;
+	my @xbuses = Dahdi::Xpp::xbuses();
+
+	my ($xbus) = grep { $_->num == $busnumber } @xbuses;
+	return $xbus;
+}
+
+sub by_label($) {
+	my $label = shift;
+	die "Missing xbus label parameter" unless defined $label;
+	my @xbuses = Dahdi::Xpp::xbuses();
+
+	my ($xbus) = grep { $_->label eq $label } @xbuses;
+	return $xbus;
+}
+
+sub get_xpd_by_number($$) {
+	my $xbus = shift;
+	my $xpdid = shift;
+	die "Missing XPD id parameter" unless defined $xpdid;
+	$xpdid = sprintf("%02d", $xpdid);
+	my @xpds = $xbus->xpds;
+	my ($wanted) = grep { $_->id eq $xpdid } @xpds;
+	return $wanted;
+}
+
+my %file_warned;	# Prevent duplicate warnings about same file.
+
+sub xbus_attr_path($$) {
+	my ($busnum, @attr) = @_;
+	foreach my $attr (@attr) {
+		my $file = sprintf "$Dahdi::Xpp::sysfs_astribanks/xbus-%02d/$attr", $busnum;
+		unless(-f $file) {
+			my $procfile = sprintf "$Dahdi::proc_xpp_base/XBUS-%02d/$attr", $busnum;
+			warn "$0: warning - OLD DRIVER: missing '$file'. Fall back to '$procfile'\n"
+				unless $file_warned{$attr}++;
+			$file = $procfile;
+		}
+		next unless -f $file;
+		return $file;
+	}
+	return undef;
+}
+
+sub xbus_getattr($$) {
+	my $xbus = shift || die;
+	my $attr = shift || die;
+	$attr = lc($attr);
+	my $file = xbus_attr_path($xbus->num, lc($attr));
+
+	open(F, $file) || die "Failed opening '$file': $!";
+	my $val = <F>;
+	close F;
+	chomp $val;
+	return $val;
+}
+
+sub read_attrs() {
+	my $xbus = shift || die;
+	my @attrnames = qw(CONNECTOR LABEL STATUS);
+	my @attrs;
+
+	foreach my $attr (@attrnames) {
+		my $val = xbus_getattr($xbus, $attr);
+		if($attr eq 'STATUS') {
+			# Some values are in all caps as well
+			$val = uc($val);
+		} elsif($attr eq 'CONNECTOR') {
+			$val =~ s/^/@/;	# Add prefix
+		} elsif($attr eq 'LABEL') {
+			# Fix badly burned labels.
+			$val =~ s/[[:^print:]]/_/g;
+		}
+		$xbus->{$attr} = $val;
+	}
+}
+
+sub transport_type($$) {
+	my $xbus = shift || die;
+	my $xbus_dir = shift;
+	my $transport = "$xbus_dir/transport";
+	if(-e "$transport/ep_00") {	# It's USB
+		$xbus->{TRANSPORT_TYPE} = 'USB';
+	} else {
+		warn "Unkown transport in $xbus_dir\n";
+		undef $xbus->{TRANSPORT_TYPE};
+	}
+	return $xbus->{TRANSPORT_TYPE};
+}
+
+sub read_xpdnames_old($) {
+	my $xbus_num = shift || die;
+	my $pat = sprintf "$Dahdi::proc_xpp_base/XBUS-%02d/XPD-[0-9][0-9]", $xbus_num;
+	my @xpdnames;
+
+	#print STDERR "read_xpdnames_old($xbus_num): $pat\n";
+	foreach (glob $pat) {
+		die "Bad /proc entry: '$_'" unless /^.*XPD-([0-9])([0-9])$/;
+		my $name = sprintf("%02d:%1d:%1d", $xbus_num, $1, $2);
+		#print STDERR "\t> $_ ($name)\n";
+		push(@xpdnames, $name);
+	}
+	return @xpdnames;
+}
+
+sub read_xpdnames($) {
+	my $xbus_num = shift || die;
+	my $xbus_dir = "$Dahdi::Xpp::sysfs_astribanks/xbus-$xbus_num";
+	my $pat = sprintf "%s/xbus-%02d/[0-9][0-9]:[0-9]:[0-9]", $Dahdi::Xpp::sysfs_astribanks, $xbus_num;
+	my @xpdnames;
+
+	#print STDERR "read_xpdnames($xbus_num): $pat\n";
+	foreach (glob $pat) {
+		die "Bad /sys entry: '$_'" unless m/^.*\/([0-9][0-9]):([0-9]):([0-9])$/;
+		my ($busnum, $unit, $subunit) = ($1, $2, $3);
+		my $name = sprintf("%02d:%1d:%1d", $1, $2, $3);
+		#print STDERR "\t> $_ ($name)\n";
+		push(@xpdnames, $name);
+	}
+	return @xpdnames;
+}
+
+my $warned_notransport = 0;
+
+sub new($$) {
+	my $pack = shift or die "Wasn't called as a class method\n";
+	my $num = shift;
+	my $xbus_dir = "$Dahdi::Xpp::sysfs_astribanks/xbus-$num";
+	my $self = {
+		NUM		=> $num,
+		NAME		=> "XBUS-$num",
+		SYSFS_DIR	=> $xbus_dir,
+		};
+	bless $self, $pack;
+	$self->read_attrs;
+	# Get transport related info
+	my $transport = "$xbus_dir/transport";
+	my $transport_type = $self->transport_type($xbus_dir);
+	if(defined $transport_type) {
+		my $tt = "Dahdi::Hardware::$transport_type";
+		my $hw = $tt->set_transport($self, $xbus_dir);
+		#printf STDERR "Xbus::new transport($transport_type): %s\n", $hw->{HARDWARE_NAME};
+	}
+	my @xpdnames;
+	my @xpds;
+	if(-e $transport) {
+		@xpdnames = read_xpdnames($num);
+	} else {
+		@xpdnames = read_xpdnames_old($num);
+		warn "$0: warning - OLD DRIVER: missing '$transport'. Fall back to /proc\n"
+			unless $warned_notransport++;
+	}
+	foreach my $xpdstr (@xpdnames) {
+		my ($busnum, $unit, $subunit) = split(/:/, $xpdstr);
+		my $procdir = "$Dahdi::proc_xpp_base/XBUS-$busnum/XPD-$unit$subunit";
+		my $xpd = Dahdi::Xpp::Xpd->new($self, $unit, $subunit, $procdir, "$xbus_dir/$xpdstr");
+		push(@xpds, $xpd);
+	}
+	@{$self->{XPDS}} = sort { $a->id <=> $b->id } @xpds;
+	return $self;
+}
+
+sub pretty_xpds($) {
+		my $xbus = shift;
+		my @xpds = sort { $a->id <=> $b->id } $xbus->xpds();
+		my @xpd_types = map { $_->type } @xpds;
+		my $last_type = '';
+		my $mult = 0;
+		my $xpdstr = '';
+		foreach my $curr (@xpd_types) {
+			if(!$last_type || ($curr eq $last_type)) {
+				$mult++;
+			} else {
+				if($mult == 1) {
+					$xpdstr .= "$last_type ";
+				} elsif($mult) {
+					$xpdstr .= "$last_type*$mult ";
+				}
+				$mult = 1;
+			}
+			$last_type = $curr;
+		}
+		if($mult == 1) {
+			$xpdstr .= "$last_type ";
+		} elsif($mult) {
+			$xpdstr .= "$last_type*$mult ";
+		}
+		$xpdstr =~ s/\s*$//;	# trim trailing space
+		return $xpdstr;
+}
+
+1;
diff --git a/xpp/perl_modules/Dahdi/Xpp/Xpd.pm b/xpp/perl_modules/Dahdi/Xpp/Xpd.pm
new file mode 100644
index 0000000..6cd49a7
--- /dev/null
+++ b/xpp/perl_modules/Dahdi/Xpp/Xpd.pm
@@ -0,0 +1,387 @@
+package Dahdi::Xpp::Xpd;
+#
+# Written by Oron Peled <oron at actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use Dahdi::Utils;
+use Dahdi::Xpp;
+use Dahdi::Xpp::Line;
+
+=head1 NAME
+
+Dahdi::Xpp::Xpd - Perl interface to the Xorcom Astribank XPDs (spans)
+
+=head1 SYNOPSIS
+
+  # Listing all Astribanks:
+  use Dahdi::Xpp;
+  # scans hardware:
+  my @xbuses = Dahdi::Xpp::xbuses("SORT_CONNECTOR");
+  for my $xbus (@xbuses) {
+    print $xbus->name." (".$xbus->label .", ". $xbus->connector .")\n";
+    for my $xpd ($xbus->xpds) {
+      print " - ".$xpd->fqn,"\n";
+    }
+  }
+
+=head1 xbus
+
+The parent L<Dahdi::Xpp::Xbus>
+
+=head1 id
+
+The two-digit ID in the Xbus. Normally 0I<x> for digital spans and 
+I<x>0 for analog ones (for some digit, I<x>).
+
+=head1 unit
+
+First digit of the ID. Zero-based number of the module inside the
+Astribank,
+
+=head1 subunit
+
+Second digit of the ID. Zero-based sub-part inside the module.
+Applicable only to digital (BRI/PRI) modules and always 0 for others.
+
+=head1 FQN
+
+Textual name: E.g. C<XPD-10>.
+
+=head1 dir
+
+The ProcFS directory with information about the XPD. e.g.
+C</proc/xpp/XBUS-00/XPD-10>.
+
+=head1 sysfs_dir
+
+The SysFS directory with information about the module. E.g.
+C</sys/bus/astribanks/devices/xbus-00/00:1:0>.
+
+=head1 channels
+
+A list of L<Dahdi::Xpp:Chan> channels of this span. In a scalar context
+this will be the number of channels in the span.
+
+=head1 spanno
+
+0 if not registered with Dahdi. Otherwise, the number of the span it is
+registered as.
+
+=head1 type
+
+The type of the XPD. One of: C<FXS>, C<FXO>, C<BRI_TE>, C<BRI_NT>,
+C<E1>, C<T1>.
+
+=head1 is_bri
+
+True if this XPD is BRI.
+
+=head1 is_pri
+
+True if this XPD is PRI (E1/T1).
+
+=head1 is_digital
+
+True if this XPD is a digital port (BRI / PRI).
+
+=head1 termtype
+
+For a digital span: C<TE> or C<NT>.
+
+=head1 dchan_hardhdlc
+
+For a BRI port: true if the driver with hardhdlc support (rather than
+bri_dchan).
+
+=cut
+
+my %file_warned;	# Prevent duplicate warnings about same file.
+
+sub xpd_attr_path($@) {
+	my $self = shift || die;
+	my ($busnum, $unitnum, $subunitnum, @attr) = (
+		$self->xbus->num,
+		$self->unit,
+		$self->subunit,
+		@_);
+	foreach my $attr (@attr) {
+		my $file = sprintf "$Dahdi::Xpp::sysfs_xpds/%02d:%1d:%1d/$attr",
+		   $busnum, $unitnum, $subunitnum;
+		unless(-f $file) {
+			my $procfile = sprintf "/proc/xpp/XBUS-%02d/XPD-%1d%1d/$attr",
+			   $busnum, $unitnum, $subunitnum;
+			warn "$0: warning - OLD DRIVER: missing '$file'. Fall back to /proc\n"
+				unless $file_warned{$attr}++;
+			$file = $procfile;
+		}
+		next unless -f $file;
+		return $file;
+	}
+	return undef;
+}
+
+# Backward compat plug for old /proc interface...
+sub xpd_old_gettype($) {
+	my $xpd = shift || die;
+	my $summary = "/proc/xpp/" . $xpd->fqn . "/summary";
+	open(F, $summary) or die "Failed to open '$summary': $!";
+	my $head = <F>;
+	close F;
+	chomp $head;
+	$head =~ s/^XPD-\d+\s+\(//;
+	$head =~ s/,.*//;
+	return $head;
+}
+
+sub xpd_old_getspan($) {
+	my $xpd = shift || die;
+	my $dahdi_registration = "/proc/xpp/" . $xpd->fqn . "/dahdi_registration";
+	open(F, $dahdi_registration) or die "Failed to open '$dahdi_registration': $!";
+	my $head = <F>;
+	close F;
+	chomp $head;
+	return $head;
+}
+
+sub xpd_old_getoffhook($) {
+	my $xpd = shift || die;
+	my $summary = "/proc/xpp/" . $xpd->fqn . "/summary";
+	my $channels;
+
+	local $/ = "\n";
+	open(F, "$summary") || die "Failed opening $summary: $!\n";
+	my $head = <F>;
+	chomp $head;	# "XPD-00 (BRI_TE ,card present, span 3)"
+	my $offhook;
+	while(<F>) {
+		chomp;
+		if(s/^\s*offhook\s*:\s*//) {
+			s/\s*$//;
+			$offhook = $_;
+			$offhook || die "No channels in '$summary'";
+			last;
+		}
+	}
+	close F;
+	return $offhook;
+}
+
+my %attr_missing_warned;	# Prevent duplicate warnings
+
+sub xpd_driver_getattr($$) {
+	my $xpd = shift || die;
+	my $attr = shift || die;
+	$attr = lc($attr);
+	my ($busnum, $unitnum, $subunitnum) = ($xpd->xbus->num, $xpd->unit, $xpd->subunit);
+	my $file = sprintf "$Dahdi::Xpp::sysfs_xpds/%02d:%1d:%1d/driver/$attr",
+			$busnum, $unitnum, $subunitnum;
+	if(!defined($file)) {
+		warn "$0: xpd_driver_getattr($attr) -- Missing attribute.\n" if
+			$attr_missing_warned{$attr};
+		return undef;
+	}
+	open(F, $file) || return undef;
+	my $val = <F>;
+	close F;
+	chomp $val;
+	return $val;
+}
+
+sub xpd_getattr($$) {
+	my $xpd = shift || die;
+	my $attr = shift || die;
+	$attr = lc($attr);
+	my $file = $xpd->xpd_attr_path(lc($attr));
+
+	# Handle special cases for backward compat
+	return xpd_old_gettype($xpd) if $attr eq 'type' and !defined $file;
+	return xpd_old_getspan($xpd) if $attr eq 'span' and !defined $file;
+	return xpd_old_getoffhook($xpd) if $attr eq 'offhook' and !defined $file;
+	if(!defined($file)) {
+		warn "$0: xpd_getattr($attr) -- Missing attribute.\n" if
+			$attr_missing_warned{$attr};
+		return undef;
+	}
+	open(F, $file) || return undef;
+	my $val = <F>;
+	close F;
+	chomp $val;
+	return $val;
+}
+
+sub xpd_setattr($$$) {
+	my $xpd = shift || die;
+	my $attr = shift || die;
+	my $val = shift;
+	$attr = lc($attr);
+	my $file = xpd_attr_path($xpd, $attr);
+	my $oldval = $xpd->xpd_getattr($attr);
+	open(F, ">$file") or die "Failed to open $file for writing: $!";
+	print F "$val";
+	if(!close(F)) {
+		if($! == 17) {	# EEXISTS
+			# good
+		} else {
+			return undef;
+		}
+	}
+	return $oldval;
+}
+
+sub blink($$) {
+	my $self = shift;
+	my $on = shift;
+	my $result = $self->xpd_getattr("blink");
+	if(defined($on)) {		# Now change
+		$self->xpd_setattr("blink", ($on)?"0xFFFF":"0");
+	}
+	return $result;
+}
+
+sub dahdi_registration($$) {
+	my $self = shift;
+	my $on = shift;
+	my $result;
+	my $file = $self->xpd_attr_path("span", "dahdi_registration");
+	die "$file is missing" unless -f $file;
+	# First query
+	open(F, "$file") or die "Failed to open $file for reading: $!";
+	$result = <F>;
+	chomp $result;
+	close F;
+	if(defined($on) and $on ne $result) {		# Now change
+		open(F, ">$file") or die "Failed to open $file for writing: $!";
+		print F ($on)?"1":"0";
+		if(!close(F)) {
+			if($! == 17) {	# EEXISTS
+				# good
+			} else {
+				undef $result;
+			}
+		}
+	}
+	return $result;
+}
+
+sub xpds_by_spanno() {
+	my @xbuses = Dahdi::Xpp::xbuses();
+	my @xpds = map { $_->xpds } @xbuses;
+	@xpds = grep { $_->spanno } @xpds;
+	@xpds = sort { $a->spanno <=> $b->spanno } @xpds;
+	my @spanno = map { $_->spanno } @xpds;
+	my @idx;
+	@idx[@spanno] = @xpds;	# The spanno is the index now
+	return @idx;
+}
+
+sub new($$$$$) {
+	my $pack = shift or die "Wasn't called as a class method\n";
+	my $xbus = shift || die;
+	my $unit = shift;	# May be zero
+	my $subunit = shift;	# May be zero
+	my $procdir = shift || die;
+	my $sysfsdir = shift || die;
+	my $self = {
+		XBUS		=> $xbus,
+		ID		=> sprintf("%1d%1d", $unit, $subunit),
+		FQN		=> $xbus->name . "/" . "XPD-$unit$subunit",
+		UNIT		=> $unit,
+		SUBUNIT		=> $subunit,
+		DIR		=> $procdir,
+		SYSFS_DIR	=> $sysfsdir,
+		};
+	bless $self, $pack;
+	my @offhook = split / /, ($self->xpd_getattr('offhook'));
+	$self->{CHANNELS} = @offhook;
+	my $type = $self->xpd_getattr('type');
+	my $span = $self->xpd_getattr('span');
+	my $timing_priority = $self->xpd_getattr('timing_priority');
+	$self->{SPANNO} = $span;
+	$self->{TYPE} = $type;
+	$self->{TIMING_PRIORITY} = $timing_priority;
+	if($type =~ /BRI_(NT|TE)/) {
+		$self->{IS_BRI} = 1;
+		$self->{TERMTYPE} = $1;
+		$self->{DCHAN_HARDHDLC} = $self->xpd_driver_getattr('dchan_hardhdlc');
+	} elsif($type =~ /[ETJ]1/) {
+		$self->{IS_PRI} = 1;
+		# older drivers may not have 'timing_priority'
+		# attribute. Preserve original behaviour:
+		if(defined($timing_priority) && ($timing_priority == 0)) {
+			$self->{TERMTYPE} = 'NT';
+		} else {
+			$self->{TERMTYPE} = 'TE';
+		}
+	}
+	$self->{IS_DIGITAL} = ( $self->{IS_BRI} || $self->{IS_PRI} );
+	Dahdi::Xpp::Line->create_all($self, $procdir);
+	return $self;
+}
+
+#------------------------------------
+# static xpd related helper functions
+#------------------------------------
+
+sub format_rank($$) {
+	my ($rank, $prio) = @_;
+	my $width = 2;
+	# 0 is replaced with a character that is sorted *AFTER* numbers.
+	$prio = '_' x $width unless defined $prio && $prio;
+	return sprintf "%${width}s-%s", $prio, $rank;
+}
+
+sub sync_priority_rank($) {
+	my $xpd = shift || die;
+	my $prio = $xpd->timing_priority;
+	# The @rank array is ordered by priority of sync (good to bad)
+	# It is used when timing_priority is not defined (analog) or
+	# is 0 (NT).
+	my @rank = (
+		($xpd->is_pri and defined($xpd->termtype) and $xpd->termtype eq 'TE'),
+		($xpd->is_bri and defined($xpd->termtype) and $xpd->termtype eq 'TE'),
+		($xpd->type eq 'FXO'),
+		($xpd->is_pri),
+		($xpd->is_bri),
+		($xpd->type eq 'FXS'),
+		);
+	my $i;
+	for($i = 0; $i < @rank; $i++) {
+		last if $rank[$i];
+	}
+	return format_rank($i, $prio);
+}
+
+# An XPD sync priority comparator for sort()
+sub sync_priority_compare() {
+	my $rank_a = sync_priority_rank($a);
+	my $rank_b = sync_priority_rank($b);
+	#print STDERR "DEBUG(rank): $rank_a (", $a->fqn, ") $rank_b (", $b->fqn, ")\n";
+	return $rank_a cmp $rank_b;	# The easy case
+}
+
+# For debugging: show a list of XPD's with relevant sync info.
+sub show_xpd_rank(@) {
+	print STDERR "XPD's by rank\n";
+	foreach my $xpd (@_) {
+		my $type = $xpd->type;
+		my $extra = "";
+		my $rank = sync_priority_rank($xpd);
+		if($xpd->is_digital) {
+			$extra .= " termtype " . ($xpd->termtype || "UNKNOWN");
+		}
+		printf STDERR "%3s %-15s %s\n", $rank, $xpd->fqn, $extra;
+	}
+}
+
+sub xpds_by_rank(@) {
+	my @xpd_prio = sort sync_priority_compare @_;
+	#show_xpd_rank(@xpd_prio);
+	return @xpd_prio;
+}
+
+1;
diff --git a/xpp/pic_loader.c b/xpp/pic_loader.c
new file mode 100644
index 0000000..ed80f22
--- /dev/null
+++ b/xpp/pic_loader.c
@@ -0,0 +1,276 @@
+/*
+ * Written by Oron Peled <oron at actcom.co.il>
+ * Copyright (C) 2008, Xorcom
+ *
+ * All rights reserved.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <regex.h>
+#include "hexfile.h"
+#include "pic_loader.h"
+#include "debug.h"
+
+#define	DBG_MASK	0x03
+#define	MAX_HEX_LINES	10000
+#define	TIMEOUT		500
+
+enum xpp_packet_types {
+	PIC_REQ_XOP 	= 0x09,
+	PIC_REP_XOP 	= 0x0A
+};
+
+struct xpp_packet_header {
+	struct {
+		uint16_t	len;
+		uint8_t		op;
+		uint8_t		unit;
+	} PACKED header;
+	union {
+		struct {
+			struct {
+				uint8_t		flags;
+				uint8_t		card_type;
+				uint16_t	offs;
+			} pic_header;
+			uint8_t		data[3];
+		} PACKED pic_packet;
+	} d;
+} PACKED;
+
+int send_picline(struct astribank_device *astribank, uint8_t card_type, enum pic_command pcmd, int offs, uint8_t *data, int data_len)
+{
+	int				recv_answer = 0;
+	char				buf[PACKET_SIZE];
+	struct xpp_packet_header	*phead = (struct xpp_packet_header *)buf;
+	int				pack_len;
+	int				ret;
+
+	assert(astribank != NULL);
+	pack_len = data_len + sizeof(phead->header) + sizeof(phead->d.pic_packet.pic_header);
+	phead->header.len 		= pack_len;
+	phead->header.op 		= PIC_REQ_XOP;
+	phead->header.unit 		= 0x00;
+	phead->d.pic_packet.pic_header.flags = pcmd; 
+	phead->d.pic_packet.pic_header.card_type = card_type;
+	phead->d.pic_packet.pic_header.offs = offs;
+	if(data)
+		memcpy(phead->d.pic_packet.data, data, data_len);
+	switch (pcmd) {
+		case PIC_START_FLAG:
+			break;
+		case PIC_DATA_FLAG:
+			break;
+		case PIC_END_FLAG:
+			recv_answer = 1;
+			break;
+		case PIC_ENDS_FLAG:
+			break;
+	}
+
+	DBG("PICLINE: pack_len=%d pcmd=%d\n", pack_len, pcmd);
+	dump_packet(LOG_DEBUG, "dump:picline[W]", (char *)phead, pack_len);
+
+	ret = send_usb(astribank, buf, pack_len, TIMEOUT);
+	if(ret < 0) {
+		ERR("send_usb failed: %d\n", ret);
+		return ret;
+	}
+	DBG("send_usb: Written %d bytes\n", ret);
+	if (recv_answer) {
+		ret = recv_usb(astribank, buf, sizeof(buf), TIMEOUT);
+		if(ret <= 0) {
+			ERR("No USB packs to read\n");
+			return ret;
+		} else {
+			phead = (struct xpp_packet_header *)buf;
+			if(phead->header.op != PIC_REP_XOP) {
+				ERR("Got unexpected reply OP=0x%02X\n", phead->header.op);
+				dump_packet(LOG_ERR, "hexline[ERR]", buf, ret);
+				return -EINVAL;
+			}
+			DBG("received OP=0x%02X, checksum=%02X\n", phead->header.op, phead->d.pic_packet.data[0]);
+			if(phead->d.pic_packet.data[0] != 0) {
+				ERR("PIC burning, bad checksum\n");
+				return -EINVAL;
+			}
+		}
+	}
+	return 0;
+}
+
+static const char *pic_basename(const char *fname, uint8_t *card_type)
+{
+	const char	*basename;
+	regex_t		regex;
+	char		ebuf[BUFSIZ];
+	const char	re[] = "PIC_TYPE_([0-9]+)\\.hex";
+	regmatch_t	pmatch[2];	/* One for the whole match, one for the number */
+	int		nmatch = (sizeof(pmatch)/sizeof(pmatch[0]));
+	int		len;
+	int		ret;
+
+	basename = strrchr(fname, '/');
+	if(!basename)
+		basename = fname;
+	if((ret = regcomp(&regex, re, REG_ICASE | REG_EXTENDED)) != 0) {
+		regerror(ret, &regex, ebuf, sizeof(ebuf));
+		ERR("regcomp: %s\n", ebuf);
+		return NULL;
+	}
+	if((ret = regexec(&regex, basename, nmatch, pmatch, 0)) != 0) {
+		regerror(ret, &regex, ebuf, sizeof(ebuf));
+		ERR("regexec: %s\n", ebuf);
+		regfree(&regex);
+		return NULL;
+	}
+	/*
+	 * Should have both complete match and a parentheses match
+	 */
+	if(pmatch[0].rm_so == -1 || pmatch[1].rm_so == -1) {
+		ERR("pic_basename: Bad match: pmatch[0].rm_so=%d pmatch[1].rm_so=%d\n",
+			pmatch[0].rm_so, pmatch[1].rm_so == -1);
+		regfree(&regex);
+		return NULL;
+	}
+	len = pmatch[1].rm_eo - pmatch[1].rm_so;
+	if(len >= sizeof(ebuf) - 1)
+		len = sizeof(ebuf) - 1;
+	memcpy(ebuf, basename + pmatch[1].rm_so, len);
+	ebuf[len] = '\0';
+	DBG("match: %s\n", ebuf);
+	ret = atoi(ebuf);
+	if(ret <= 0 || ret > 9) {
+		ERR("pic_basename: Bad type number %d\n", ret);
+		regfree(&regex);
+		return NULL;
+	}
+	*card_type = ret;
+	regfree(&regex);
+	return basename;
+}
+
+/*
+ * Returns: true on success, false on failure
+ */
+static int pic_burn(struct astribank_device *astribank, const struct hexdata *hexdata)
+{
+	const char		*v = hexdata->version_info;
+	const char		*basename;
+	uint8_t			*data;
+	unsigned char		check_sum = 0;
+	uint8_t			card_type;
+	int			ret;
+	unsigned int		i;
+
+	v = (v[0]) ? v : "Unknown";
+	assert(astribank != NULL);
+	assert(hexdata != NULL);
+	if(!astribank->is_usb2) {
+		ERR("Skip PIC burning (not USB2)\n");
+		return 0;
+	}
+	INFO("Load PIC: %s (version %s)\n", hexdata->fname, hexdata->version_info);
+	basename = pic_basename(hexdata->fname, &card_type);
+	if(!basename) {
+		ERR("Bad PIC filename '%s'. Abort.\n", hexdata->fname);
+		return 0;
+	}
+	DBG("basename=%s card_type=%d maxlines=%d\n",
+		basename, card_type, hexdata->maxlines);
+	/*
+	 * Try to read extra left-overs from USB controller
+	 */
+	for(i = 2; i; i--) {
+		char	buf[PACKET_SIZE];
+
+		if(usb_bulk_read(astribank->handle, astribank->my_ep_in, buf, sizeof(buf), 1) <= 0)
+			break;
+	}
+	if((ret = send_picline(astribank, card_type, PIC_START_FLAG, 0, NULL, 0)) != 0) {
+		perror("Failed sending start hexline");
+		return 0;
+	}
+	for(i = 0; i < hexdata->maxlines; i++) { 
+		struct hexline	*hexline;
+		unsigned int	len;
+
+		hexline = hexdata->lines[i];
+		if(!hexline) {
+			ERR("hexdata finished early (line %d)", i);
+			return 0;
+		}
+		if(hexline->d.content.header.tt == TT_DATA) {
+			len = hexline->d.content.header.ll;	/* don't send checksum */
+			if(len != 3) {
+				ERR("Bad line len %d\n", len);
+				return 0;
+			}
+			data = hexline->d.content.tt_data.data;
+			check_sum ^= data[0] ^ data[1] ^ data[2];
+			ret = send_picline(astribank, card_type, PIC_DATA_FLAG,
+					hexline->d.content.header.offset, data, len);
+			if(ret) {
+				perror("Failed sending data hexline");
+				return 0;
+			}
+		} else if(hexline->d.content.header.tt == TT_EOF) {
+			break;
+		} else {
+			ERR("Unexpected TT = %d in line %d\n",
+					hexline->d.content.header.tt, i);
+			return 0;
+		}
+	}
+	if((ret = send_picline(astribank, card_type, PIC_END_FLAG, 0, &check_sum, 1)) != 0) {
+		perror("Failed sending end hexline");
+		return 0;
+	}
+	DBG("Finished...\n");
+	return 1;
+}
+
+int load_pic(struct astribank_device *astribank, int numfiles, char *filelist[])
+{
+	int	i;
+
+	DBG("Loading %d PIC files...\n", numfiles);
+	for(i = 0; i < numfiles; i++) {
+		struct hexdata	*picdata;
+		const char	*curr = filelist[i];
+
+		DBG("%s\n", curr);
+		if((picdata = parse_hexfile(curr, MAX_HEX_LINES)) == NULL) {
+			perror(curr);
+			return -errno;
+		}
+		if(!pic_burn(astribank, picdata)) {
+			ERR("PIC %s burning failed\n", curr);
+			return -ENODEV;
+		}
+		free_hexdata(picdata);
+	}
+	if((i = send_picline(astribank, 0, PIC_ENDS_FLAG, 0, NULL, 0)) != 0) {
+		ERR("PIC end burning failed\n");
+		return -ENODEV;
+	}
+	return 0;
+}
diff --git a/xpp/pic_loader.h b/xpp/pic_loader.h
new file mode 100644
index 0000000..f871bca
--- /dev/null
+++ b/xpp/pic_loader.h
@@ -0,0 +1,46 @@
+#ifndef	PIC_LOADER_H
+#define	PIC_LOADER_H
+/*
+ * Written by Oron Peled <oron at actcom.co.il>
+ * Copyright (C) 2008, Xorcom
+ *
+ * All rights reserved.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdint.h>
+#include "astribank_usb.h"
+
+/*
+ * Astribank PIC loading
+ */
+
+enum pic_command {
+	PIC_DATA_FLAG	= 0x00,
+	PIC_START_FLAG	= 0x01,
+	PIC_END_FLAG	= 0x02,
+	PIC_ENDS_FLAG	= 0x04,
+};
+
+#define	PIC_PACK_LEN 	0x0B
+#define PIC_LINE_LEN	0x03
+
+int send_picline(struct astribank_device *astribank, uint8_t card_type,
+		enum pic_command pcmd, int offs, uint8_t *data, int data_len);
+int load_pic(struct astribank_device *astribank, int numfiles, char *filelist[]);
+
+#endif	/* PIC_LOADER_H */
diff --git a/xpp/test_parse.c b/xpp/test_parse.c
new file mode 100644
index 0000000..4ae1038
--- /dev/null
+++ b/xpp/test_parse.c
@@ -0,0 +1,57 @@
+/*
+ * Written by Oron Peled <oron at actcom.co.il>
+ * Copyright (C) 2006, 2007, 2008, 2009 Xorcom
+ *
+ * All rights reserved.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include "hexfile.h"
+
+static void default_report_func(int level, const char *msg, ...)
+{
+	va_list ap;
+
+	va_start(ap, msg);
+	vfprintf(stderr, msg, ap);
+	va_end(ap);
+}
+
+int main(int argc, char *argv[])
+{
+	struct hexdata	*hd;
+	int		i;
+
+	if(argc < 2) {
+		fprintf(stderr, "Usage: program hexfile...\n");
+		return 1;
+	}
+	parse_hexfile_set_reporting(default_report_func);
+	for(i = 1; i < argc; i++) {
+		hd = parse_hexfile(argv[i], 2000);
+		if(!hd) {
+			fprintf(stderr, "Parsing failed\n");
+			return 1;
+		}
+		fprintf(stderr, "=== %s === (version: %s)\n", argv[i], hd->version_info);
+		dump_hexfile2(hd, "-", 60 );
+		free_hexdata(hd);
+	}
+	return 0;
+}
diff --git a/xpp/twinstar b/xpp/twinstar
new file mode 100755
index 0000000..287c9ef
--- /dev/null
+++ b/xpp/twinstar
@@ -0,0 +1,267 @@
+#! /usr/bin/perl -w
+#
+# Written by Oron Peled <oron at actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use File::Basename;
+use Getopt::Std;
+BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/perl_modules"); }
+
+use Dahdi;
+use Dahdi::Hardware;
+use Dahdi::Span;
+use Dahdi::Xpp;
+use Dahdi::Xpp::Xbus;
+use Dahdi::Xpp::Mpp;
+
+$Getopt::Std::STANDARD_HELP_VERSION = 1;
+$main::VERSION = '$Id$';
+
+sub HELP_MESSAGE() {
+	eval(usage());
+	return 0;
+}
+
+sub usage {
+	die "Usage: $0 {status|jump|enable-wd|disable-wd|ports}\n";
+}
+
+our ($opt_v, $opt_x);
+getopts('vx') || usage;
+ at ARGV == 1 or usage;
+
+
+# Find USB bus toplevel
+my $usb_top;
+$usb_top = '/dev/bus/usb';
+$usb_top = '/proc/bus/usb' unless -d $usb_top;
+die "No USB toplevel found\n" unless -d $usb_top;
+
+sub tws_devs() {
+	my @devs;
+	foreach my $dev (Dahdi::Hardware->device_list) {
+		next unless $dev->is_astribank;
+		next unless $dev->product =~ /116./;
+		push(@devs, $dev->hardware_name);
+	}
+	return @devs;
+}
+
+sub tws_usb_devfile($) {
+	my $name = shift || die;
+	# Remove prefix
+	if($name !~ s/usb://) {
+		die "$name is not a USB name\n";
+	}
+	return "$usb_top/$name";
+}
+
+sub tws_show(@) {
+	my @usb_devs = @_;
+	my $format = "%-15s %-10s %-15s %-10s %-10s\n";
+
+	printf $format, 'DEVICE', 'PORT', 'WATCHDOG', 'POWER0', 'POWER1';
+	foreach my $dev (@usb_devs) {
+		my $mppinfo = $dev->mppinfo;
+		if(!defined $mppinfo) {
+			printf STDERR "%s: no MPP information\n", $dev->hardware_name;
+			next;
+		}
+		if(!defined $mppinfo->{TWINSTAR_PORT}) {
+			printf STDERR "%s: no TWINSTAR_PORT information\n", $dev->hardware_name;
+			next;
+		}
+		my $power = $mppinfo->twinstar_power;
+		printf $format,
+			$dev->hardware_name,
+			$mppinfo->twinstar_port,
+			($mppinfo->twinstar_watchdog) ? "on" : "off",
+			($power->[0]) ? "yes" : "no",
+			($power->[1]) ? "yes" : "no";
+	}
+}
+
+sub tws_portnum($) {
+	my $dev = shift || die "Missing dev";
+	my $mppinfo = $dev->mppinfo;
+	if(!defined $mppinfo) {
+		printf STDERR "%s: no MPP information\n", $dev->hardware_name;
+		return undef;
+	}
+	return $mppinfo->twinstar_port;
+}
+
+sub tws_showports(@) {
+	my @usb_devs = @_;
+	foreach my $dev (@usb_devs) {
+		my $mppinfo = $dev->mppinfo;
+		if(!defined $mppinfo) {
+			printf STDERR "%s: no MPP information\n", $dev->hardware_name;
+			next;
+		}
+		if(!defined $mppinfo->{TWINSTAR_PORT}) {
+			printf STDERR "%s: no TWINSTAR_PORT information\n", $dev->hardware_name;
+			next;
+		}
+		printf "%s\n", $mppinfo->{TWINSTAR_PORT};
+	}
+}
+
+sub tws_watchdog($@) {
+	my $on = shift;
+	die "tws_watchdog() on/off?" unless defined $on;
+	my @usb_devs = @_;
+
+	foreach my $dev (@usb_devs) {
+		my $mppinfo = $dev->mppinfo;
+		if(!defined $mppinfo) {
+			printf STDERR "%s: no MPP information\n", $dev->hardware_name;
+			next;
+		}
+		$mppinfo->mpp_setwatchdog($on);
+	}
+}
+
+sub tws_jump(@) {
+	my @usb_devs = @_;
+
+	foreach my $dev (@usb_devs) {
+		my $mppinfo = $dev->mppinfo;
+		if(!defined $mppinfo) {
+			printf STDERR "%s: no MPP information\n", $dev->hardware_name;
+			next;
+		}
+		eval {
+			$mppinfo->mpp_jump;
+		};
+		warn $@ if $@;
+	}
+}
+
+sub dev_list() {
+	my @devs;
+	foreach my $dev (Dahdi::Hardware->device_list) {
+		next unless $dev->is_astribank;
+		next unless $dev->product =~ /116./;
+		Dahdi::Xpp::Mpp->mpp_addinfo($dev);
+		push(@devs, $dev);
+	}
+	return @devs;
+}
+
+my @usb_devices = dev_list();
+
+if($ARGV[0] eq 'status') {
+	tws_show(@usb_devices);
+} elsif($ARGV[0] eq 'jump') {
+	tws_jump(@usb_devices);
+} elsif($ARGV[0] eq 'disable-wd') {
+	tws_watchdog(0, @usb_devices);
+} elsif($ARGV[0] eq 'enable-wd') {
+	tws_watchdog(1, @usb_devices);
+} elsif($ARGV[0] eq 'ports') {
+	tws_showports(@usb_devices);
+} else {
+	usage;
+}
+
+__END__
+
+=head1 NAME
+
+twinstar - Control the Twinstar feature of a Xorcom Astribank
+
+=head1 SYNOPSIS
+
+twinstar {status|jump|enable-wd|disable-wd|ports}
+
+=head1 DESCRIPTION
+
+B<twinstar> is a tool to control the Twinstar (dual USB port) of a
+Xorcom Astribank. There is a single and mandatory argument which is the
+command to run. That command operates on all the Astribanks connected to
+the system.
+
+Technically all the commands are implemented using Dahdi::Xpp::Mpp which
+in turn uses astribank_tool. Thus using thus tool will require root
+permissions or otherwise read/write permissions to the USB device.
+
+The twinstar may be in I<watchdog mode>, which means that it will jump
+to the remote host if it loses contact with the local host. This can
+happen if the machine is powered down or hangs or even if the xpp
+drivers are unloaded. Which is why the standard twinstar scripts put the
+Astribanks in twinstar mode on startup and remove it on normal shutdown.
+
+An Astribank will only jump to the other host (either if asked
+explicitly or by the watchdog) only if there is a different Astribank
+connected to the other port and running. Which is why all of this has no
+effect on systems that don't need this functionality.
+
+The command are:
+
+=head2 status
+
+Shows the current status of all Astribanks. Note that it only shows
+Astribanks whose current active USB port is the one connected to this
+computer.
+
+Example output:
+
+ DEVICE          PORT       WATCHDOG        POWER0     POWER1
+ usb:001/010     0          on              yes        yes
+ usb:001/011     0          on              yes        yes
+
+For each Astribank on the system that has Twinstar support we get:
+
+=over 4
+
+=item Device
+
+The address of the device. This is the bus address, e.g. the address you 
+see in lsusb / dahdi_hardware.
+
+=item Port
+
+The active USB port on the Astribank. This should be always '0' on the
+master and always 1 on the slave.
+
+=item Watchdog
+
+I<on> if the watchdog is triggered in the Atribank or I<off> otherwise.
+
+=item Power0, Power1
+
+Shows which ports of this Astribank are connected to a USB port of a
+running computer. This only shows whether or not the USB host provides
+power.
+
+=back
+
+=head2 ports
+
+Shows the same 'Port' column of the B<status> command.
+
+=head2 jump
+
+Command all the Astribanks to jump to the other port. This works
+regardless the watchdog mode is enabled or not. But requires that there
+is power on the other port.
+
+=head2 enable-wd
+
+Enables watchdog mode.
+
+=head2 disable-wd
+
+Disables watchdog mode.
+
+=head1 FILES
+
+B<twinstar> mostly uses astribank_tool which in turn mostly uses USB
+files under /dev/bus/usb .
+
diff --git a/xpp/twinstar_hook b/xpp/twinstar_hook
new file mode 100755
index 0000000..712d572
--- /dev/null
+++ b/xpp/twinstar_hook
@@ -0,0 +1,86 @@
+#! /bin/sh
+#
+# twinstar_hook: Example twinstar-specific hook script
+# $Id$
+#
+# Written by Oron Peled <oron at actcom.co.il>
+# Copyright (C) 2009, Xorcom
+#
+# All rights reserved.
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+#
+# This is an experimental script to activate an Astribank TwinStar
+# during failover.
+#
+# The script assume that there is an /etc/dahdi/xpp_order file
+# specifying the Astribanks' labels according to the required
+# registration order.
+#
+# This file can be easily generated by running:
+#    dahdi_genconf xpporder
+# after the system is configured and working.
+#
+
+me=`basename $0`
+dir=`dirname $0`
+LOGGER="logger -i -t '$me'"
+
+# Always redirect stderr somewhere, otherwise the shell script will die
+# when it tries to do I/O related stuff on closed file descriptor.
+# Our default is to throw it down the bit-bucket.
+#exec 2> /dev/console
+## If you wish to trace this script:
+#exec 2> "/tmp/${me}_$XBUS_NAME" 1>&2
+
+# Our directory in the beginning, so we can use local lab setup
+PATH="$dir:/usr/sbin:/sbin:/usr/bin:/bin"
+
+set -e
+
+export XBUS_SORT='SORT_LABEL'
+
+case "$ACTION" in
+online)
+	echo "$ACTION($XBUS_NAME): " | $LOGGER
+	twinstar enable-wd
+	sleep 1	# Just for visual effect
+	asterisk -rx 'module load chan_dahdi.so' 2>&1 | $LOGGER
+	xpp_blink bzzt xpd "$XBUS_NUM"
+	ports=`twinstar ports`
+	if [ "$ports" = 0 ]; then
+		play /usr/share/dahdi/primary-pbx-is-ready.wav || :
+	elif [ "$ports" = 1 ]; then
+		play /usr/share/dahdi/backup-pbx-is-ready.wav || :
+	fi
+	echo "online: READY" | $LOGGER
+	;;
+offline)
+	echo "$ACTION($XBUS_NAME): " | $LOGGER
+	twinstar disable-wd
+	# If we want to disconnect everybody
+	twinstar jump
+	asterisk -rx 'module unload chan_dahdi.so'
+	;;
+*)
+	echo "$0: Unknown ACTION='$ACTION'" | $LOGGER
+	echo "$0: ARGS='$*'" | $LOGGER
+	echo "$0: ENV:" | $LOGGER
+	env | $LOGGER
+	exit 1
+esac
+
diff --git a/xpp/twinstar_setup b/xpp/twinstar_setup
new file mode 100755
index 0000000..0e53bdf
--- /dev/null
+++ b/xpp/twinstar_setup
@@ -0,0 +1,155 @@
+#! /usr/bin/perl -w
+#
+# Written by Oron Peled <oron at actcom.co.il>
+# Copyright (C) 2009, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use File::Basename;
+BEGIN {
+	my $dir = dirname($0); unshift(@INC, "$dir", "$dir/perl_modules");
+	$ENV{PATH} = "$dir:$ENV{PATH}";
+}
+
+use Dahdi::Config::Gen qw(is_true);
+use Dahdi::Hardware;
+use Dahdi::Xpp::Mpp;
+use Dahdi::Xpp::Xbus;
+
+my $xpporder_file = $ENV{XPPORDER_CONF} || "/etc/dahdi/xpp_order";
+
+my @devices = Dahdi::Hardware->device_list;
+my @xbuses = Dahdi::Xpp::xbuses;
+
+my $format = "%-20s %-10s        # %s\n";
+
+sub bad_xpds($) {
+	my $xbus = shift || die;
+	my $bad_xpds = 0;
+
+	foreach my $xpd ($xbus->xpds) {
+		if(! $xpd->spanno) {
+			my $fqn = $xpd->fqn;
+			warn "\t$fqn -- Not registered with DAHDI\n";
+			$bad_xpds++;
+		}
+	}
+	return $bad_xpds;
+}
+
+sub twinstar_checks() {
+	my @twinstar_good;
+	my $first_port;
+	if(! -d "/sys/bus/astribanks") {
+		die "CANNOT generate TwinStar setup -- xpp drivers are not loaded\n";
+	}
+	foreach my $dev (@devices) {
+		my $hwname = $dev->hardware_name;
+		my $xbus;
+		my $loaded;
+		my $tws_port;
+		my $tws_power;
+		my $tws_watchdog;
+		my $mppinfo;
+		if(! $dev->is_astribank) {
+			warn "SKIP $hwname -- Only Astribanks can be used for TwinStar\n";
+			next;
+		}
+		Dahdi::Xpp::Mpp->mpp_addinfo($dev);
+		$mppinfo = $dev->mppinfo;
+		if(! defined $mppinfo) {
+			warn "SKIP $hwname -- is not TwinStar ready\n";
+			next;
+		}
+		if(! defined $mppinfo->{MPP_TALK}) {
+			warn "SKIP $hwname -- USB firmware is not loaded\n";
+			next;
+		}
+		if(! $mppinfo->{TWINSTAR_CAPABLE}) {
+			warn "SKIP $hwname -- is not TwinStar capable\n";
+			next;
+		}
+		$xbus = $dev->xbus;
+		if(! defined $xbus) {
+			warn "SKIP $hwname -- No XBUS for this device (FPGA firmware? Initialization?)\n";
+			next;
+		}
+		my $dev = $xbus->transport;
+		my $connector = $xbus->connector;
+		my $label = $xbus->label;
+		my $xbusstr = sprintf "%s (%s) [%s]", $xbus->name, $connector, $label;
+		if(bad_xpds($xbus)) {
+			warn "SKIP $xbusstr -- Not registered with DAHDI\n";
+			next;
+		}
+		my $port = $mppinfo->{TWINSTAR_PORT};
+		if(! defined $port) {
+			warn "SKIP $xbusstr -- Cannot read USB port info\n";
+			next;
+		}
+		my $power = $mppinfo->{TWINSTAR_POWER};
+		if(! defined $power) {
+			warn "SKIP $xbusstr -- Cannot read USB power info\n";
+			next;
+		}
+		if(!$power->[0] || !$power->[1]) {
+			warn "WARNING: Only one cable: $xbusstr\n";
+		}
+		$first_port = $port unless defined $first_port;
+		printf "GOOD: %-15s port=%d %s\n", $label, $port, $connector;
+		push(@twinstar_good, $xbus);
+		if($first_port != $port) {
+			die
+				"$0: ",
+				"XBUS($connector, $label) ",
+				"connected to PORT $port ",
+				"(others to $first_port)\n";
+		}
+	}
+	return @twinstar_good;
+}
+
+my @twinstar_good = twinstar_checks;
+if(!@twinstar_good) {
+	print STDERR "Abort. No Twinstar capable Astribanks found\n";
+	exit 1;
+}
+print "Generating Configuration\n";
+system("dahdi_genconf -v xpporder");
+die "Failed: $?\n" if $?;
+
+1;
+
+__END__
+
+=head1 NAME
+
+twinstar_setup - Prepares a server for Astribank TwinStar operation.
+
+=head1 DESCRIPTION
+
+This script prepares a server for Astribank TwinStar operation.
+The stages are:
+
+=over
+
+=item Preliminary checks
+
+Check that we have only TwinStar capable Astribanks, that the drivers are already loaded.
+
+=item Configuration Generation
+
+Indirectly generate the F</etc/dahdi/xpp_order> file that describes the current configuration.
+This is done by running C<dahdi_genconf xpporder>
+
+This configuration file is used by twinstar_hook(8) to know when all Astribanks has reconnected
+to the backup server.
+
+=item Deployment to Backup Server
+
+Not implemented yet. Should be done manualy.
+
+=back
diff --git a/xpp/waitfor_xpds b/xpp/waitfor_xpds
new file mode 100755
index 0000000..30b3ac5
--- /dev/null
+++ b/xpp/waitfor_xpds
@@ -0,0 +1,93 @@
+#! /bin/sh
+
+# waitfor_xpds: wait until all Astribanks were initialized
+# $Id$
+
+# Written by Oron Peled <oron at actcom.co.il>
+# Copyright (C) 2008-2009, Xorcom
+#
+# All rights reserved.
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+
+set -e
+
+# For lab testing
+mydir=`dirname $0`
+PATH="${mydir}:${PATH}"
+
+[ -r /etc/dahdi/init.conf ] && . /etc/dahdi/init.conf
+
+ab_list() {
+	# Only check /sys info (don't use /proc anymore).
+	ab=`find /sys/bus/astribanks/devices/xbus-*/ -name waitfor_xpds 2> /dev/null || :`
+	echo $ab
+}
+
+# Any hardware?
+if ! dahdi_hardware="`which dahdi_hardware 2>/dev/null`"; then
+	echo >&2 "$0: Missing dahdi_hardware"
+	exit 0
+fi
+if ! astribank_is_starting="`which astribank_is_starting 2>/dev/null`"; then
+	echo >&2 "$0: Missing astribank_is_starting"
+	exit 0
+fi
+if [ "`$dahdi_hardware | grep xpp_usb`" != "" ]; then
+	astribank_is_starting -v -a
+fi
+if ! astribank_is_starting; then
+	exit 0
+fi
+
+# Wait for driver and first device
+echo -n 1>&2 "Astribanks detection "
+tries=10
+while [ ! -e "/sys/bus/astribanks/devices/xbus-00" ]
+do
+	if [ "$tries" -le 0 ]; then
+		echo 1>&2 "TIMEOUT"
+		exit 1
+	fi
+	echo -n 1>&2 "."
+	sleep 1
+	: $((tries-=1))
+done
+echo ""
+
+# Wait for device to stabilize and XPD's to finish initalizations
+echo 1>&2 "Astribanks initializing spans"
+while
+	if ! ab=`ab_list`; then
+		exit 1
+	fi
+	test "$oldab" != "$ab"
+do
+	oldab="$ab"
+	cat $ab
+done
+
+if [ "$XPP_HOTPLUG_DAHDI" = yes ]; then
+	if [ "$CALLED_FROM_ATRIBANK_HOOK" = '' ]; then
+		# Now we can wait until the hotplug run would remove the semaphore
+		echo -n 1>&2 "Other DAHDI initializations... "
+		astribank_is_starting -v -w 1>&2
+	fi
+else
+	# Non-hotplug -- Sequential initialization, remove semaphore
+	astribank_is_starting -v -r 1>&2
+fi
diff --git a/xpp/xpp_blink b/xpp/xpp_blink
new file mode 100755
index 0000000..ff63ae7
--- /dev/null
+++ b/xpp/xpp_blink
@@ -0,0 +1,168 @@
+#! /usr/bin/perl -w
+#
+# Written by Oron Peled <oron at actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use File::Basename;
+BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/perl_modules"); }
+
+use Dahdi;
+use Dahdi::Span;
+use Dahdi::Xpp;
+use Dahdi::Xpp::Xbus;
+
+sub usage {
+	die "Usage: $0 {on|off|bzzt} {span <number> | chan <number> | xpd <bus num> [<xpd num>] | label <label>}\n";
+}
+
+my $state = shift;
+my $selector = shift;
+usage unless defined($state) and $state =~ /^(on|off|bzzt)$/;
+usage unless defined($selector) and $selector =~ /^(span|chan|xpd|label)$/i;
+
+my $xpd;
+my @blinklist;
+my @channels;
+
+if($selector =~ /^span$/i) {
+	my $number = shift;
+	usage unless defined($number) and $number =~ /^\d+/;
+	my $span = Dahdi::Span::by_number($number);
+	die "Unkown Span $number\n" unless $span;
+	$xpd = Dahdi::Xpp::xpd_of_span($span);
+	die "Span $number is not an XPD\n" unless defined $xpd;
+	my $xpdname = $xpd->fqn;
+	my $connector = $xpd->xbus->connector;
+	die "$xpdname is not connected\n" unless defined $connector;
+	push(@blinklist, $xpd);
+	my @chans = $span->chans();
+	@channels = join(' ', map { $_->num } @chans);
+	printf "Using %s (connected via $connector): channels @channels\n", $xpd->fqn;
+} elsif($selector =~ /^chan$/i) {
+	my $channo = shift;
+	usage unless defined($channo) and $channo =~ /^\d+/;
+	my @spans = Dahdi::spans();
+	my @chans = map { $_->chans() } @spans;
+	my ($chan) = grep { $_->num eq $channo } @chans;
+	die "Channel $channo was not found\n" unless defined $chan;
+	die "Cannot blink Input ports\n" if $chan->type eq 'IN';
+	die "Cannot blink Output ports\n" if $chan->type eq 'OUT';
+	push(@blinklist, $chan);
+} elsif($selector =~ /^xpd$/i) {
+	my $busnum = shift;
+	my $xpdnum = shift;
+	my $linenum = shift;
+	usage unless defined($busnum) and $busnum =~ /^\d+/;
+	my $xbus = Dahdi::Xpp::Xbus::by_number($busnum);
+	die "Unkown XBUS number $busnum\n" unless defined $xbus;
+	if(defined $xpdnum) {
+		usage unless $xpdnum =~ /^\d+/;
+		$xpd = $xbus->get_xpd_by_number($xpdnum);
+		die "Unkown XPD number $xpdnum on XBUS number $busnum\n" unless defined $xpd;
+		if(defined $linenum) {
+			usage unless $linenum =~ /^\d+/;
+			my $lines = $xpd->lines;
+			my $l = @{$lines}[$linenum];
+			die "Bad line number $linenum on XPD $xpd->fqn\n" unless defined $l;
+			push(@blinklist, $l);
+		} else {
+			push(@blinklist, $xpd);
+		}
+	} else {
+		@blinklist = $xbus->xpds;
+		die "XBUS number $busnum has no XPDS!\n" unless @blinklist;
+	}
+} elsif($selector =~ /^label$/i) {
+	my $label = shift;
+	usage unless defined($label);
+	my $xbus = Dahdi::Xpp::Xbus::by_label($label);
+	die "Unkown XBUS label $label\n" unless defined $xbus;
+	@blinklist = $xbus->xpds;
+	die "XBUS label '$label' has no XPDS!\n" unless @blinklist;
+}
+
+if($state eq 'on') {
+	$_->blink(1) foreach (@blinklist);
+} elsif($state eq 'off') {
+	$_->blink(0) foreach (@blinklist);
+} elsif($state eq 'bzzt') {
+	$_->blink(1) foreach (@blinklist);
+	sleep 1;
+	$_->blink(0) foreach (@blinklist);
+}
+
+__END__
+
+=head1 NAME
+
+xpp_blink - Blink the leds of a specified XPD
+
+=head1 SYNOPSIS
+
+xpp_blink {on|off|bzzt} {span <number> | chan <number> | xpd <bus num> [<xpd num> [<lineno>]]}
+
+=head1 DESCRIPTION
+
+Blink all the leds of an XPD.
+
+=head2 Blink mode:
+
+=over
+
+=item on
+
+Turn on constant blink
+
+=item off
+
+Turn off blink
+
+=item bzzt
+
+Blink briefly for 1 second.
+
+=back
+
+=head2 Selector:
+
+=over
+
+=item span	
+
+Select by span number. This only work for XPD registered to dahdi.
+		
+will also print the dahdi channels of the span and the xbus/xpd this 
+span represents.
+
+=item chan
+
+Select by channel number. This only work for XPD registered to dahdi.
+
+=item xpd
+
+Select by xbus + xpd numbers. If only xbus number is given, all the
+XPDs of the selected xbus (Astribank) are blinked.
+
+=item label
+
+Select by xbus label. Affect the whole Astribank.
+
+=back
+
+=head1 EXAMPLES
+
+  $ xpp_blink bzzt span 2
+  Using XBUS-04/XPD-10 (connected via usb-0000:00:1d.7-1): channels 15 16 17 18 19 20 21 22
+
+  $ xpp_blink bzzt chan 18
+
+  $ xpp_blink on xpd 0 1 5
+
+  $ xpp_blink off xpd 0
+
+  $ xpp_blink bzzt label 'usb:00000238'
diff --git a/xpp/xpp_fxloader b/xpp/xpp_fxloader
new file mode 100644
index 0000000..284c5ab
--- /dev/null
+++ b/xpp/xpp_fxloader
@@ -0,0 +1,364 @@
+#!/bin/bash
+
+# xpp_fxloader: load Xorcom Astribank (XPP) firmware
+# $Id$
+#
+# Written by Tzafrir Cohen <tzafrir.cohen at xorcom.com>
+# Copyright (C) 2006-2009, Xorcom
+#
+# All rights reserved.
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+#
+# This script can be run manually or from hotplug/udev.
+#
+# Firmware files should be located in $FIRMWARE_DIR which defaults:
+# 	1. /usr/share/dahdi
+#	2. Can be overidden by setting $FIRMWARE_DIR in the environment
+#	3. Can be overidden by setting $FIRMWARE_DIR in /etc/dahdi/init.conf
+#
+# Manual Run
+# ##########
+#
+#   path/to/xpp_fxloader load
+#
+# Make sure the firmware files are in $FIRMWARE_DIR
+#
+
+set -e
+
+# Make sure fxload is in the path:
+PATH="$PATH:/usr/local/sbin:/sbin:/usr/sbin"
+export PATH
+
+me=`basename $0`
+dir=`dirname $0`
+PATH="$dir:$PATH"
+DEFAULTS="/etc/dahdi/init.conf"
+
+if [ -t 2 ]; then
+	LOGGER="logger -i -t '$me' -s"
+else
+	LOGGER="logger -i -t '$me'"
+fi
+
+debug() {
+	[ "$DEBUG" != "" ] && $LOGGER "$@"
+	return 0
+}
+
+USBFS_PREFIX=/proc/bus/usb
+DEVUSB_PREFIX=/dev/bus/usb
+USB_PREFIX=
+
+FIRMWARE_DIR="${FIRMWARE_DIR:-/usr/share/dahdi}"
+ASTRIBANK_HEXLOAD=${ASTRIBANK_HEXLOAD:-/usr/sbin/astribank_hexload}
+ASTRIBANK_TOOL=${ASTRIBANK_TOOL:-/usr/sbin/astribank_tool}
+XPP_UDEV_SLEEP_TIME="${XPP_UDEV_SLEEP_TIME:-15}"
+
+USB_FW="${USB_FW:-USB_FW.hex}"
+
+if [ -r "$DEFAULTS" ]; then
+	. "$DEFAULTS"
+fi
+
+if [ "$USB_PREFIX" = '' ]; then
+	if [ -d "$DEVUSB_PREFIX" ]; then
+		USB_PREFIX=$DEVUSB_PREFIX
+	elif [ -r "$USBFS_PREFIX/devices" ]; then
+		USB_PREFIX=$USBFS_PREFIX
+	fi
+fi
+
+# With Kernels older that 2.6.10 it seems to be possible
+# to trigger a race condition by running fxload or fpga_load 
+# immediately after the detection of the device.
+KERNEL_HAS_USB_RACE=0
+case "`uname -r`" in 2.6.[89]*) KERNEL_HAS_USB_RACE=1;; esac
+sleep_if_race() {
+  if [ "$KERNEL_HAS_USB_RACE" = '1' ]; then
+    sleep 2
+  fi
+}
+
+find_dev() {
+  v_id=$1
+  p_id=$2
+  
+  lsusb | tr -d : | awk "/ ID $v_id$p_id/{printf \"$USB_PREFIX/%s/%s \",\$2,\$4}"
+}
+
+run_fxload() {
+  sleep_if_race
+  fxload -t fx2 $* 2>&1 1>/dev/null | $LOGGER
+  status=$PIPESTATUS
+  if [ $status != 0 ]; then
+    $LOGGER "fxload failed with status $status"
+    exit 55
+  fi
+}
+
+run_astribank_hexload() {
+	debug "Running: $ASTRIBANK_HEXLOAD $*"
+	$ASTRIBANK_HEXLOAD "$@" | $LOGGER
+	status=$PIPESTATUS
+	if [ $status != 0 ]; then
+		$LOGGER "$ASTRIBANK_HEXLOAD failed with status $status"
+		exit 77
+	fi
+}
+
+run_astribank_tool() {
+	debug "Running: $ASTRIBANK_TOOL $*"
+	$ASTRIBANK_TOOL "$@" | $LOGGER
+	status=$PIPESTATUS
+	if [ $status != 0 ]; then
+		$LOGGER "$ASTRIBANK_TOOL failed with status $status"
+		exit 77
+	fi
+}
+
+load_usb_fw() {
+  v_id=$1
+  p_id=$2
+  fw=$3
+  
+  devices=`find_dev $v_id $p_id`
+  for dev in $devices
+  do
+    ver=$(awk '/\$Id:/ { print $4 }' $FIRMWARE_DIR/$fw)
+    debug "USB Firmware $FIRMWARE_DIR/$fw (Version=$ver) into $dev"
+    run_fxload -D $dev -I $FIRMWARE_DIR/$fw || exit 1
+  done
+}
+
+load_fw_device() {
+	dev=$1
+	fw=$2
+	debug "FPGA loading $fw into $dev"
+	run_astribank_hexload -D "$dev" -F "$FIRMWARE_DIR/$fw"
+	pic_files=`echo "$FIRMWARE_DIR"/PIC_TYPE_[1-4].hex`
+	debug "PIC burning into $dev: $pic_files"
+	run_astribank_hexload -D "$dev" -p $pic_files
+	run_astribank_tool -D "$dev" -n		# Do renumeration!
+	debug "PIC burning finished $pic_files"
+}
+
+#
+# Use in manual loading. Parallelize loading
+# firmwares to all of our devices
+#
+firmware_by_id() {
+  v_id=$1
+  p_id=$2
+  fw=$3
+  
+  devices=`find_dev $v_id $p_id`
+  childs=""
+  for dev in $devices
+  do
+	(
+	set -e
+
+	load_fw_device "$dev" "$fw"
+	sleep_if_race
+	) &
+	childs="$childs $!"
+	sleep 0.4
+  done
+  # Wait for specific childs to get their exit status
+  wait $childs
+}
+
+numdevs() {
+  v_ids="$1"
+  p_ids="$2"
+
+  for v in $v_ids
+  do
+    (
+      for p in $p_ids
+      do
+        find_dev $v $p
+      done
+    )
+  done | wc -w
+}
+
+wait_renumeration() {
+  num="$1"
+  v_ids="$2"
+  p_ids="$3"
+
+  while
+    n=`numdevs "$v_ids" "$p_ids"`
+    [ "$num" -gt "$n" ]
+  do
+    echo -n "."
+    sleep 1
+  done
+  echo "Got all $num devices"
+}
+
+reset_fpga() {
+  totaldevs=`numdevs e4e4 '11[3456][0123]'`
+  devices=`find_dev e4e4 '11[3456][12]'`
+  debug "Reseting devices [$totaldevs devices]"
+  for dev in $devices
+  do
+	debug "Resetting FPGA Firmware on $dev"
+	sleep_if_race
+	run_astribank_tool -D "$dev" -r full 2>&1 >/dev/null
+  done
+  if [ "$1" = 'wait' ]; then
+	  wait_renumeration $totaldevs e4e4 '11[3456][03]'
+  fi
+}
+
+usage() {
+	echo "$0: Astribank firmware loading script."
+	echo "Usage: "
+	echo "$0 load  : manual firmware loading."
+	echo "$0 usb   : manual firmware loading: USB firmware only."
+	echo "$0 help  : this text."
+}
+
+# We have a potential astribank
+astribank_is_starting -a
+
+#########################
+##
+## Manual run
+##
+
+# to run manually, pass the parameter 'xppdetect'
+case "$1" in
+udev) 
+	# Various kernel versions use different sets of variables.
+	# Here we want to make sure we have 'DEVICE' and 'PRODUCT' set
+	# up. DEVICE is now deprecated in favour of DEVNAME. It will
+	# likely to contain an invalid name if /proc/bus/usb is not
+	# mounted. So it needs further cooking.
+	DEVICE="${DEVNAME:-$DEVICE}"
+	case "$DEVICE" in /proc/*) DEVICE="/dev${DEVICE#/proc}" ;; esac
+	# PRODUCT contains 'vendor_id'/'product_id'/'version' . We
+	# currently pass it as a parameter, but might as well get it
+	# from the envirnment.
+	PRODUCT="${PRODUCT:-$2}"
+	# skip on to the rest of the script. Don't exit.
+	;;
+reset-wait)
+	reset_fpga wait
+	;;
+reset)
+	reset_fpga
+	;;
+xppdetect|load|usb)
+	numdevs=`numdevs e4e4 '11[3456][013]'`
+	$LOGGER -- "--------- FIRMWARE LOADING: ($1) [$numdevs devices]"
+
+	load_usb_fw e4e4 1130 $USB_FW
+	load_usb_fw e4e4 1140 $USB_FW
+	load_usb_fw e4e4 1150 $USB_FW
+	load_usb_fw e4e4 1160 $USB_FW
+	load_usb_fw e4e4 1163 $USB_FW
+	wait_renumeration $numdevs e4e4 '11[3456]1'
+	if [ "$1" != 'usb' ]
+	then
+		firmware_by_id e4e4 1131 FPGA_FXS.hex
+		firmware_by_id e4e4 1141 FPGA_1141.hex
+		firmware_by_id e4e4 1151 FPGA_1151.hex
+		firmware_by_id e4e4 1161 FPGA_1161.hex
+		wait_renumeration $numdevs e4e4 '11[3456]2'
+	fi
+
+	sleep 3		# Let it stabilize
+	$LOGGER -- "--------- FIRMWARE IS LOADED"
+	exit 0
+	;;
+help)
+	usage
+	exit 0
+	;;
+*)
+	if [ "$ACTION" = '' ]; then # not called from hotplug
+		echo "$0: Error: unknown command \"$1\""
+		echo ''
+		usage
+		exit 1
+	fi
+	;;
+esac
+
+#########################
+##
+## Hotplug run
+##
+
+# allow disabling automatic hotplugging:
+if [ "$XPP_HOTPLUG_DISABLED" != '' ]; then
+	$LOGGER -p kern.info "Exiting... XPP_HOTPLUG_DISABLED"
+	exit 0
+fi
+
+if [ "$ACTION" != add ]; then
+	exit 0;
+fi
+
+# This procedure is run in the background to do the actual work of loading the
+# firmware. Running it in the background allows udev to continue doing other tasks
+# and thus provide a faster startup.
+#
+# On some systems (e.g. CentOS 5) we get the relevant udev event before the device
+# file is ready. Which is why we want the background process to wait a bit first.
+udev_delayed_load() {
+	sleep 0.2
+	# Make sure the new device is writable:
+	usb_dev_writable=0
+	for i in `seq $XPP_UDEV_SLEEP_TIME`; do
+		if [ -w "$DEVICE" ]; then
+			usb_dev_writable=1;
+			break;
+		fi
+		sleep 1
+	done
+	if [ $usb_dev_writable != 1 ]; then
+		$LOGGER "Device $DEVICE not writable. Can't load firmware."
+		return;
+	fi
+
+	$LOGGER "Trying to find what to do for product $PRODUCT, device $DEVICE"
+	prod_id=`echo "$PRODUCT" | cut -d/ -f2`
+	case "$PRODUCT" in
+	e4e4/11[3456]0/*|e4e4/1163/*)
+		FIRM_USB="$FIRMWARE_DIR/$USB_FW"
+		$LOGGER "Loading firmware '$FIRM_USB' into '$DEVICE'"
+		run_fxload -D "$DEVICE" -I "$FIRM_USB"
+		;;
+	e4e4/11[3456]1/*)
+		if [ "$prod_id" = 1131 ]; then
+			FIRM_FPGA="FPGA_FXS.hex"	# Legacy
+		else
+			FIRM_FPGA="FPGA_$prod_id.hex"
+		fi
+		sleep_if_race
+		load_fw_device "$DEVICE" "$FIRM_FPGA"
+		;;
+	esac	
+}
+
+udev_delayed_load &
+
diff --git a/xpp/xpp_fxloader.usermap b/xpp/xpp_fxloader.usermap
new file mode 100644
index 0000000..8c14b72
--- /dev/null
+++ b/xpp/xpp_fxloader.usermap
@@ -0,0 +1,10 @@
+# module	match_flags	idVendor	idProduct	bcdDevice_lo	bcdDevice_hi	bDeviceClass	bDeviceSubClass	bDeviceProtocol	bInterfaceClass	bInterfaceSubClass	bInterfaceProtocol	driver_info
+xpp_fxloader	0x0003		0x04b4		0x8613		0x0000		0x0000		0x00		0x00		0x00		0x00		0x00			0x00			0x0
+xpp_fxloader	0x0003		0xe4e4		0x1130		0x0000		0x0000		0x00		0x00		0x00		0x00		0x00			0x00			0x0
+xpp_fxloader	0x0003		0xe4e4		0x1131		0x0000		0x0000		0x00		0x00		0x00		0x00		0x00			0x00			0x0
+xpp_fxloader	0x0003		0xe4e4		0x1140		0x0000		0x0000		0x00		0x00		0x00		0x00		0x00			0x00			0x0
+xpp_fxloader	0x0003		0xe4e4		0x1141		0x0000		0x0000		0x00		0x00		0x00		0x00		0x00			0x00			0x0
+xpp_fxloader	0x0003		0xe4e4		0x1150		0x0000		0x0000		0x00		0x00		0x00		0x00		0x00			0x00			0x0
+xpp_fxloader	0x0003		0xe4e4		0x1151		0x0000		0x0000		0x00		0x00		0x00		0x00		0x00			0x00			0x0
+xpp_fxloader	0x0003		0xe4e4		0x1160		0x0000		0x0000		0x00		0x00		0x00		0x00		0x00			0x00			0x0
+xpp_fxloader	0x0003		0xe4e4		0x1161		0x0000		0x0000		0x00		0x00		0x00		0x00		0x00			0x00			0x0
diff --git a/xpp/xpp_modprobe b/xpp/xpp_modprobe
new file mode 100644
index 0000000..e972bc3
--- /dev/null
+++ b/xpp/xpp_modprobe
@@ -0,0 +1,10 @@
+# Some debugging options for the brave of heart:
+#options dahdi debug=1
+#options wcfxo debug=1
+#options xpp debug=1 
+#options xpp_usb debug=1 
+#options xpd_fxs debug=1 
+#options xpd_fxo debug=1 
+
+# For pre-loading of card modules (e.g: xpp_fxs)
+#install xpp_usb /sbin/modprobe xpd_fxs && /sbin/modprobe --ignore-install xpp_usb
diff --git a/xpp/xpp_sync b/xpp/xpp_sync
new file mode 100755
index 0000000..41cfd61
--- /dev/null
+++ b/xpp/xpp_sync
@@ -0,0 +1,226 @@
+#! /usr/bin/perl -w
+#
+# Written by Oron Peled <oron at actcom.co.il>
+# Copyright (C) 2007, Xorcom
+# This program is free software; you can redistribute and/or
+# modify it under the same terms as Perl itself.
+#
+# $Id$
+#
+use strict;
+use File::Basename;
+use Getopt::Std;
+BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/perl_modules"); }
+
+use Dahdi::Xpp;
+use Dahdi::Xpp::Xbus;
+
+my $sync;
+my $autoselect;
+
+sub usage() {
+	print 
+		"$0: show / set Astribank sync source\n".
+		"\n".
+		"Usage: $0 [-v]                    Show sync source.\n".
+		"       $0 [-v] <auto|NN|dahdi>   Set sync source.\n".
+		"";
+	exit 1;
+}
+
+my %opts;
+getopts('hv', \%opts) || usage;
+
+$opts{h} && usage;
+if(@ARGV == 1) {
+	$sync = shift;
+	$autoselect = 1 if $sync =~ /^auto$/i;
+}
+
+
+sub get_sorted_xpds() {
+	my @good_xpds;
+
+	foreach my $xbus (Dahdi::Xpp::xbuses) {
+		next unless $xbus->status eq 'CONNECTED';
+		foreach my $xpd ($xbus->xpds()) {
+			my $isreg = $xpd->dahdi_registration();
+			if(!defined($isreg)) {			# Failure
+				printf STDERR "%s: Failed %s\n", $xpd->fqn, $!;
+				next;
+			}
+			next unless $isreg;			# Skip unregistered XPDs
+			push(@good_xpds, $xpd);
+		}
+	}
+	my @xpd_prio = Dahdi::Xpp::Xpd::xpds_by_rank(@good_xpds);
+	Dahdi::Xpp::Xpd::show_xpd_rank(@xpd_prio) if $opts{v};
+	return @xpd_prio;
+}
+
+sub do_select(@) {
+	my $found;
+
+	foreach my $xpd (@_) {
+		my $xbus = $xpd->xbus;
+		my $busnum = $xbus->name;
+		die "Uknown bus name" unless $busnum;
+		$busnum =~ s/XBUS-//;
+		die "bad bus name" unless $busnum =~ /^\d+$/;
+		#printf "Setting sync: %-10s (%s)\n", $xpd->fqn, $xpd->type;
+		if(Dahdi::Xpp::sync($busnum)) {
+			#print "SET $busnum\n";
+			$found = 1;
+			last;
+		} else {
+			print STDERR "Failed to set $busnum: $!\n";
+		}
+	}
+}
+
+sub do_set($) {
+	my $sync = shift;
+	die "Failed to set sync to '$sync'" unless Dahdi::Xpp::sync($sync);
+}
+
+sub unique_xbus(@) {
+	my %seen;
+
+	grep { !$seen{$_->xbus}++; } @_;
+}
+
+my $curr_sync = Dahdi::Xpp::sync;
+my @sync_xpds = unique_xbus(get_sorted_xpds());
+
+sub show_sync() {
+	foreach my $xpd (@sync_xpds) {
+		my $xbus = $xpd->xbus;
+		my $xpdstr = '[ ' . $xbus->pretty_xpds . ' ]';
+		my $label = '[' . $xbus->label() . ']';
+		my $connector = '(' . $xbus->connector . ')';
+		my $mark = ($curr_sync =~ /^\d+$/ and $xbus->num == $curr_sync)?"+":"";
+		my $padding = ' ' x (40 - length $xpdstr);
+		printf " %1s %s %-25s %-14s %s\n", $mark, $xbus->name, $connector, $label, $xpdstr;
+	}
+}
+
+sub check_fxo_host_sync() {
+	my @host_synced_xpds = grep { $_->xbus->num() ne $curr_sync } @sync_xpds;
+	my @host_synced_fxos = grep($_->type eq 'FXO', @host_synced_xpds);
+	if(@host_synced_fxos) {
+		my @bad_xbus = map { $_->xbus } unique_xbus(@host_synced_fxos);
+		our $lines = join("\n\t", map { $_->name } @bad_xbus);
+		print STDERR <<"END";
+==================================================
+WARNING: FXO which is not the syncer cause bad PCM
+	 Affected Astribanks are:
+--------------------------------------------------
+	$lines
+==================================================
+END
+	}
+}
+
+if(defined $sync) {
+	if($autoselect) {
+		do_select(@sync_xpds);
+	} else {
+		$sync = uc($sync);
+		do_set($sync);
+	}
+	$curr_sync = Dahdi::Xpp::sync;
+	#print "New sync: ", Dahdi::Xpp::sync, "\n";
+} else {
+	print "Current sync: ", $curr_sync, "\n";
+	print "Best Available Syncers:\n";
+	show_sync;
+	check_fxo_host_sync;
+}
+
+__END__
+
+=head1 NAME
+
+xpp_sync - Handle sync selection of Xorcom Astribanks.
+
+=head1 SYNOPSIS
+
+xpp_sync <auto|dahdi|nn>
+
+xpp_sync [-v]
+
+=head1 DESCRIPTION
+
+On a normal operation one Astribank device provides timing for all the
+other Astribank devices.
+
+When run without parameters, xpp_sync will display a list of Astribanks
+(xbuses) that are connected and registered as Dahdi spans. The current
+xpp sync master will be marked.
+
+If you this an Astribank is connected and yet it does not appear on the 
+output of xpp_sync, it may be unregistered. Try running dahdi_registration .
+
+=head2 Parameters
+
+=over
+
+=item auto
+
+Automatically selects the best Astribank for syncing.
+
+=item dahdi
+
+Gets synchronization from the Dahdi sync master.
+
+=item nn
+
+Sets XBUS-I<nn> as sync source.
+
+=item -v
+
+Also print the numeric xpp sync rank.
+
+=back
+
+(Parameter name is case-insensitive)
+
+=head2 Example output:
+
+	Setting SYNC
+	Current sync: 01
+	Best Available Syncers:
+	 + XBUS-01 (usb-0000:00:10.4-3) [usb:12345678]       [ PRI_TE PRI_NT PRI_TE PRI_NT ]
+	   XBUS-00 (usb-0000:00:10.4-2) [usb:QA-01]          [ FXS FXO ]
+	==================================================
+	WARNING: FXO which is not the syncer cause bad PCM
+		 Affected Astribanks are:
+	--------------------------------------------------
+		XBUS-00
+	==================================================
+
+In this example we see that the recommended xpp sync master is XBUS-02 - 
+it is the first on the list. It is also the actual syncer, as we can see
+from the '+' beside it.
+
+xpp_sync is normally called from the dahdi init.d script.
+The parameter it is called with defaults to 
+I<auto>, but it is possible to override that parameter (e.g: set it to
+I<dahdi>) through the value of XPP_SYNC in /etc/dahdi/init.conf .
+
+=head1 FILES
+
+=over
+
+=item /proc/xpp/sync
+
+(Deprecated: no longer supported)
+xpp_sync is essentially a nicer interface to /proc/xpp/sync . That file
+shows the current xpp sync master (and in what format you need to write
+to it to set the master).
+
+=back
+
+=head1 SEE ALSO
+
+dahdi_registration(1), dahdi_cfg(1), README.Astribank
diff --git a/xpp/xpp_timing b/xpp/xpp_timing
new file mode 100755
index 0000000..f87215c
--- /dev/null
+++ b/xpp/xpp_timing
@@ -0,0 +1,6 @@
+#! /bin/sh
+grep 'DRIFT:' /sys/bus/astribanks/devices/xbus-*/timing | sed \
+	-e 's,/sys/bus/astribanks/devices/,,' \
+	-e 's,/timing:,: ,' \
+	-e 's,DRIFT: ,,' \
+	-e 's/^[^:]*:/\U&/'
diff --git a/zonedata.c b/zonedata.c
new file mode 100644
index 0000000..d15f276
--- /dev/null
+++ b/zonedata.c
@@ -0,0 +1,983 @@
+/*
+ * BSD Telephony Of Mexico "Tormenta" Tone Zone Support 2/22/01
+ * 
+ * Working with the "Tormenta ISA" Card 
+ *
+ * Primary Author: Mark Spencer <markster at digium.com>
+ * 
+ * This information from ITU E.180 Supplement 2.
+ * UK information from BT SIN 350 Issue 1.1
+ * Helpful reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf
+ */
+
+/*
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU Lesser General Public License Version 2.1 as published
+ * by the Free Software Foundation. See the LICENSE.LGPL file
+ * included with this program for more details.
+ *
+ * In addition, when this program is distributed with Asterisk in
+ * any form that would qualify as a 'combined work' or as a
+ * 'derivative work' (but not mere aggregation), you can redistribute
+ * and/or modify the combination under the terms of the license
+ * provided with that copy of Asterisk, instead of the license
+ * terms granted here.
+ */
+
+#include "tonezone.h"
+
+struct tone_zone builtin_zones[] =
+{
+	{ .zone = 0,
+	  .country = "us",
+	  .description = "United States / North America",
+	  .ringcadence = { 2000, 4000 },
+	  .tones = {
+			{ DAHDI_TONE_DIALTONE, "350+440" },
+			{ DAHDI_TONE_BUSY, "480+620/500,0/500" },
+			{ DAHDI_TONE_RINGTONE, "440+480/2000,0/4000" },
+			{ DAHDI_TONE_CONGESTION, "480+620/250,0/250" },
+			{ DAHDI_TONE_CALLWAIT, "440/300,0/10000" },
+			{ DAHDI_TONE_DIALRECALL, "!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440" },
+			{ DAHDI_TONE_RECORDTONE, "1400/500,0/15000" },
+			{ DAHDI_TONE_INFO, "!950/330,!1400/330,!1800/330,0" },
+			{ DAHDI_TONE_STUTTER, "!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440" },
+		},
+	  .dtmf_high_level = -10,
+	  .dtmf_low_level = -10,
+	  .mfr1_level = -10,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 1,
+	  .country = "au",
+	  .description = "Australia",
+	  .ringcadence = {  400, 200, 400, 2000 },
+	  .tones = {
+			{ DAHDI_TONE_DIALTONE, "413+438" },
+			{ DAHDI_TONE_BUSY, "425/375,0/375" },
+			{ DAHDI_TONE_RINGTONE, "413+438/400,0/200,413+438/400,0/2000" },
+			/* XXX Congestion: Should reduce by 10 db every other cadence XXX */
+			{ DAHDI_TONE_CONGESTION, "425/375,0/375,420/375,0/375" },
+			{ DAHDI_TONE_CALLWAIT, "425/100,0/200,425/200,0/4400" },
+			{ DAHDI_TONE_DIALRECALL, "413+428" },
+			{ DAHDI_TONE_RECORDTONE, "!425/1000,!0/15000,425/360,0/15000" },
+			{ DAHDI_TONE_INFO, "425/2500,0/500" },
+			{ DAHDI_TONE_STUTTER, "413+438/100,0/40" },
+		},
+	  .dtmf_high_level = -10,
+	  .dtmf_low_level = -10,
+	  .mfr1_level = -10,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 2,
+	  .country = "fr",
+	  .description = "France",
+	  .ringcadence = { 1500, 3500 },
+	  .tones = {
+			/* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+			/* Dialtone can also be 440+330 */
+			{ DAHDI_TONE_DIALTONE, "440" },
+			{ DAHDI_TONE_BUSY, "440/500,0/500" },
+			{ DAHDI_TONE_RINGTONE, "440/1500,0/3500" },
+			/* CONGESTION - not specified */
+			{ DAHDI_TONE_CONGESTION, "440/250,0/250" },
+			{ DAHDI_TONE_CALLWAIT, "440/300,0/10000" },
+			/* DIALRECALL - not specified */
+			{ DAHDI_TONE_DIALRECALL, "!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440" },
+			/* RECORDTONE - not specified */
+			{ DAHDI_TONE_RECORDTONE, "1400/500,0/15000" },
+			{ DAHDI_TONE_INFO, "!950/330,!1400/330,!1800/330,0" },
+			{ DAHDI_TONE_STUTTER, "!440/100,!0/100,!440/100,!0/100,!440/100,!0/100,!440/100,!0/100,!440/100,!0/100,!440/100,!0/100,440" },
+		},
+	  .dtmf_high_level = -9,
+	  .dtmf_low_level = -11,
+	  .mfr1_level = -7,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 3,
+	  .country = "nl",
+	  .description = "Netherlands",
+	  .ringcadence = { 1000, 4000 },
+	  .tones = {
+			/* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+			/* Most of these 425's can also be 450's */
+			{ DAHDI_TONE_DIALTONE, "425" },
+			{ DAHDI_TONE_BUSY, "425/500,0/500" },
+			{ DAHDI_TONE_RINGTONE, "425/1000,0/4000" },
+			{ DAHDI_TONE_CONGESTION, "425/250,0/250" },
+			{ DAHDI_TONE_CALLWAIT, "425/500,0/9500" },
+			/* DIALRECALL - not specified */
+			{ DAHDI_TONE_DIALRECALL, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425" },
+			/* RECORDTONE - not specified */
+			{ DAHDI_TONE_RECORDTONE, "1400/500,0/15000" },
+			{ DAHDI_TONE_INFO, "950/330,1400/330,1800/330,0/1000" },
+			{ DAHDI_TONE_STUTTER, "425/500,0/50" },
+		},
+	  .dtmf_high_level = -9,
+	  .dtmf_low_level = -11,
+	  .mfr1_level = -7,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 4,
+	  .country = "uk",
+	  .description = "United Kingdom",
+	  .ringcadence = { 400, 200, 400, 2000 },
+	  .tones = {
+			/* From British Telecom SIN350 v1.2 */
+			{ DAHDI_TONE_DIALTONE, "350+440" },
+			{ DAHDI_TONE_BUSY, "400/375,0/375" },
+			{ DAHDI_TONE_RINGTONE, "400+450/400,0/200,400+450/400,0/2000" },
+			{ DAHDI_TONE_CONGESTION, "400/400,0/350,400/225,0/525" },
+			{ DAHDI_TONE_CALLWAIT, "400/100,0/4000" },
+			{ DAHDI_TONE_DIALRECALL, "350+440" },
+			{ DAHDI_TONE_RECORDTONE, "1400/500,0/60000" },
+			{ DAHDI_TONE_INFO, "950/330,0/15,1400/330,0/15,1800/330,0/1000" },
+			{ DAHDI_TONE_STUTTER, "350+440/750,440/750" },
+		},
+	  .dtmf_high_level = -9,
+	  .dtmf_low_level = -11,
+	  .mfr1_level = -7,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 5,
+	  .country = "fi",
+	  .description = "Finland",
+	  .ringcadence = { 1000, 4000 },
+	  .tones = {
+			{ DAHDI_TONE_DIALTONE, "425" },
+			{ DAHDI_TONE_BUSY, "425/300,0/300" },
+			{ DAHDI_TONE_RINGTONE, "425/1000,0/4000" },
+			{ DAHDI_TONE_CONGESTION, "425/200,0/200" },
+			{ DAHDI_TONE_CALLWAIT, "425/150,0/150,425/150,0/8000" },
+			{ DAHDI_TONE_DIALRECALL, "425/650,0/25" },
+			{ DAHDI_TONE_RECORDTONE, "1400/500,0/15000" },
+			{ DAHDI_TONE_INFO, "950/650,0/325,950/325,0/30,1400/1300,0/2600" },
+			{ DAHDI_TONE_STUTTER, "425/650,0/25" },
+		},
+	  .dtmf_high_level = -9,
+	  .dtmf_low_level = -11,
+	  .mfr1_level = -7,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 6,
+	  .country = "es",
+	  .description = "Spain",
+	  .ringcadence = { 1500, 3000},
+	  .tones = {
+			{ DAHDI_TONE_DIALTONE, "425" },
+			{ DAHDI_TONE_BUSY, "425/200,0/200" },
+			{ DAHDI_TONE_RINGTONE, "425/1500,0/3000" },
+			{ DAHDI_TONE_CONGESTION, "425/200,0/200,425/200,0/200,425/200,0/600" },
+			{ DAHDI_TONE_CALLWAIT, "425/175,0/175,425/175,0/3500" },
+			{ DAHDI_TONE_DIALRECALL, "!425/200,!0/200,!425/200,!0/200,!425/200,!0/200,425" },
+			{ DAHDI_TONE_RECORDTONE, "1400/500,0/15000" },
+			{ DAHDI_TONE_INFO, "950/330,0/1000" },
+			{ DAHDI_TONE_STUTTER, "425/500,0/50" },
+		},
+	  .dtmf_high_level = -9,
+	  .dtmf_low_level = -11,
+	  .mfr1_level = -7,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 7,
+	  .country = "jp",
+	  .description = "Japan",
+	  .ringcadence = { 1000, 2000 },
+	  .tones = {
+			{ DAHDI_TONE_DIALTONE, "400" },
+			{ DAHDI_TONE_BUSY, "400/500,0/500" },
+			{ DAHDI_TONE_RINGTONE, "400+15/1000,0/2000" },
+			{ DAHDI_TONE_CONGESTION, "400/500,0/500" },
+			{ DAHDI_TONE_CALLWAIT, "400+16/500,0/8000" },
+			{ DAHDI_TONE_DIALRECALL, "!400/200,!0/200,!400/200,!0/200,!400/200,!0/200,400" },
+			{ DAHDI_TONE_RECORDTONE, "1400/500,0/15000" },
+			{ DAHDI_TONE_INFO, "!950/330,!1400/330,!1800/330,0" },
+			{ DAHDI_TONE_STUTTER, "!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,400" },
+		},
+	  .dtmf_high_level = -7,
+	  .dtmf_low_level = -7,
+	  .mfr1_level = -7,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 8,
+	  .country = "no",
+	  .description = "Norway",
+	  .ringcadence = { 1000, 4000 },
+	  .tones = {
+			{ DAHDI_TONE_DIALTONE, "425" },
+			{ DAHDI_TONE_BUSY, "425/500,0/500" },
+			{ DAHDI_TONE_RINGTONE, "425/1000,0/4000" },
+			{ DAHDI_TONE_CONGESTION, "425/200,0/200" },
+			{ DAHDI_TONE_CALLWAIT, "425/200,0/600,425/200,0/10000" },
+			{ DAHDI_TONE_DIALRECALL, "470/400,425/400" },
+			{ DAHDI_TONE_RECORDTONE, "1400/400,0/15000" },
+			{ DAHDI_TONE_INFO, "!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,0" },
+			{ DAHDI_TONE_STUTTER, "470/400,425/400" },
+		},
+	  .dtmf_high_level = -10,
+	  .dtmf_low_level = -10,
+	  .mfr1_level = -10,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 9,
+	  .country =  "at",
+	  .description = "Austria",
+	  .ringcadence = { 1000, 5000 },
+	  .tones = {
+			/* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+			{ DAHDI_TONE_DIALTONE, "420" },
+			{ DAHDI_TONE_BUSY, "420/400,0/400" },
+			{ DAHDI_TONE_RINGTONE, "420/1000,0/5000" },
+			{ DAHDI_TONE_CONGESTION, "420/200,0/200" },
+			{ DAHDI_TONE_CALLWAIT, "420/40,0/1960" },
+			{ DAHDI_TONE_DIALRECALL, "420" },
+			/* RECORDTONE - not specified */
+			{ DAHDI_TONE_RECORDTONE, "1400/80,0/14920" },
+			{ DAHDI_TONE_INFO, "950/330,1450/330,1850/330,0/1000" },
+			{ DAHDI_TONE_STUTTER, "380+420" },
+		},
+	  .dtmf_high_level = -9,
+	  .dtmf_low_level = -11,
+	  .mfr1_level = -10,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 10,
+	  .country =  "nz",
+	  .description = "New Zealand",
+	  .ringcadence = { 400, 200, 400, 2000 },
+	  .tones = {
+			{ DAHDI_TONE_DIALTONE, "400" },
+			{ DAHDI_TONE_BUSY, "400/500,0/500" },
+			{ DAHDI_TONE_RINGTONE, "400+450/400,0/200,400+450/400,0/2000" },
+			{ DAHDI_TONE_CONGESTION, "400/250,0/250" },
+			{ DAHDI_TONE_CALLWAIT, "400/250,0/250,400/250,0/3250" },
+			{ DAHDI_TONE_DIALRECALL, "!400/100!0/100,!400/100,!0/100,!400/100,!0/100,400" },
+			{ DAHDI_TONE_RECORDTONE, "1400/425,0/15000" },
+			{ DAHDI_TONE_INFO, "400/750,0/100,400/750,0/100,400/750,0/100,400/750,0/400" },
+			{ DAHDI_TONE_STUTTER, "!400/100!0/100,!400/100,!0/100,!400/100,!0/100,!400/100!0/100,!400/100,!0/100,!400/100,!0/100,400" },
+		},
+	  .dtmf_high_level = -11,
+	  .dtmf_low_level = -9,
+	  .mfr1_level = -7,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 11,
+	  .country = "it",
+	  .description = "Italy",
+	  .ringcadence = { 1000, 4000 },
+	  .tones = {
+			/* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+			{ DAHDI_TONE_DIALTONE, "425/200,0/200,425/600,0/1000" },
+			{ DAHDI_TONE_BUSY, "425/500,0/500" },
+			{ DAHDI_TONE_RINGTONE, "425/1000,0/4000" },
+			{ DAHDI_TONE_CONGESTION, "425/200,0/200" },
+			{ DAHDI_TONE_CALLWAIT, "425/400,0/100,425/250,0/100,425/150,0/14000" },
+			{ DAHDI_TONE_DIALRECALL, "470/400,425/400" },
+			{ DAHDI_TONE_RECORDTONE, "1400/400,0/15000" },
+			{ DAHDI_TONE_INFO, "!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,0" },
+			{ DAHDI_TONE_STUTTER, "470/400,425/400" },
+		},
+	  .dtmf_high_level = -9,
+	  .dtmf_low_level = -11,
+	  .mfr1_level = -10,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 12,
+	  .country = "us-old",
+	  .description = "United States Circa 1950 / North America",
+	  .ringcadence = { 2000, 4000 },
+	  .tones = {
+			{ DAHDI_TONE_DIALTONE, "600*120" },
+			{ DAHDI_TONE_BUSY, "500*100/500,0/500" },
+			{ DAHDI_TONE_RINGTONE, "420*40/2000,0/4000" },
+			{ DAHDI_TONE_CONGESTION, "500*100/250,0/250" },
+			{ DAHDI_TONE_CALLWAIT, "440/300,0/10000" },
+			{ DAHDI_TONE_DIALRECALL, "!600*120/100,!0/100,!600*120/100,!0/100,!600*120/100,!0/100,600*120" },
+			{ DAHDI_TONE_RECORDTONE, "1400/500,0/15000" },
+			{ DAHDI_TONE_INFO, "!950/330,!1400/330,!1800/330,0" },
+			{ DAHDI_TONE_STUTTER, "!600*120/100,!0/100,!600*120/100,!0/100,!600*120/100,!0/100,!600*120/100,!0/100,!600*120/100,!0/100,!600*120/100,!0/100,600*120" },
+		},
+	  .dtmf_high_level = -10,
+	  .dtmf_low_level = -10,
+	  .mfr1_level = -10,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 13,
+	  .country = "gr",
+	  .description = "Greece",
+	  .ringcadence = { 1000, 4000 },
+	  .tones = {
+			{ DAHDI_TONE_DIALTONE, "425/200,0/300,425/700,0/800" },
+			{ DAHDI_TONE_BUSY, "425/300,0/300" },
+			{ DAHDI_TONE_RINGTONE, "425/1000,0/4000" },
+			{ DAHDI_TONE_CONGESTION, "425/200,0/200" },
+			{ DAHDI_TONE_CALLWAIT, "425/150,0/150,425/150,0/8000" },
+			{ DAHDI_TONE_DIALRECALL, "425/650,0/25" },
+			{ DAHDI_TONE_RECORDTONE, "1400/400,0/15000" },
+			{ DAHDI_TONE_INFO, "!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,0" },
+			{ DAHDI_TONE_STUTTER, "425/650,0/25" },
+		},
+	  .dtmf_high_level = -9,
+	  .dtmf_low_level = -11,
+	  .mfr1_level = -10,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 14,
+	  .country = "tw",
+	  .description = "Taiwan",
+	  .ringcadence = { 1000, 4000 },
+	  .tones = {
+			{ DAHDI_TONE_DIALTONE, "350+440" },
+			{ DAHDI_TONE_BUSY, "480+620/500,0/500" },
+			{ DAHDI_TONE_RINGTONE, "440+480/1000,0/2000" },
+			{ DAHDI_TONE_CONGESTION, "480+620/250,0/250" },
+			{ DAHDI_TONE_CALLWAIT, "350+440/250,0/250,350+440/250,0/3250" },
+			{ DAHDI_TONE_DIALRECALL, "300/1500,0/500" },
+			{ DAHDI_TONE_RECORDTONE, "1400/500,0/15000" },
+			{ DAHDI_TONE_INFO, "!950/330,!1400/330,!1800/330,0" },
+			{ DAHDI_TONE_STUTTER, "!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440" },
+		},
+	  .dtmf_high_level = -11,
+	  .dtmf_low_level = -9,
+	  .mfr1_level = -7,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 15,
+	  .country = "cl",
+	  .description = "Chile",
+	  .ringcadence = { 1000, 3000 },
+	  .tones = {
+			{ DAHDI_TONE_DIALTONE, "400" },
+			{ DAHDI_TONE_BUSY, "400/500,0/500" },
+			{ DAHDI_TONE_RINGTONE, "400/1000,0/3000" },
+			{ DAHDI_TONE_CONGESTION, "400/200,0/200" },
+			{ DAHDI_TONE_CALLWAIT, "400/250,0/8750" },
+			{ DAHDI_TONE_DIALRECALL, "!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,400" },
+			{ DAHDI_TONE_RECORDTONE, "1400/500,0/15000" },
+			{ DAHDI_TONE_INFO, "!950/333,!1400/333,!1800/333,0" },
+			{ DAHDI_TONE_STUTTER, "!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,!400/100,!0/100,400" },
+		},
+	  .dtmf_high_level = -10,
+	  .dtmf_low_level = -10,
+	  .mfr1_level = -10,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 16,
+	  .country = "se",
+	  .description = "Sweden",
+	  .ringcadence = { 1000, 5000 },
+	  .tones = {
+			{ DAHDI_TONE_DIALTONE, "425" },
+			{ DAHDI_TONE_BUSY, "425/250,0/250" },
+			{ DAHDI_TONE_RINGTONE, "425/1000,0/5000" },
+			{ DAHDI_TONE_CONGESTION, "425/250,0/750" },
+			{ DAHDI_TONE_CALLWAIT, "425/200,0/500,425/200,0/9100" },
+			{ DAHDI_TONE_DIALRECALL, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425" },
+			{ DAHDI_TONE_RECORDTONE, "1400/500,0/15000" },
+			{ DAHDI_TONE_INFO, "!950/332,!0/24,!1400/332,!0/24,!1800/332,!0/2024,"
+			  "!950/332,!0/24,!1400/332,!0/24,!1800/332,!0/2024,"
+			  "!950/332,!0/24,!1400/332,!0/24,!1800/332,!0/2024,"
+			  "!950/332,!0/24,!1400/332,!0/24,!1800/332,!0/2024,"
+			  "!950/332,!0/24,!1400/332,!0/24,!1800/332,0" },
+			/*{ DAHDI_TONE_STUTTER, "425/320,0/20" },              Real swedish standard, not used for now */
+			{ DAHDI_TONE_STUTTER, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425" },
+		},
+	  .dtmf_high_level = -9,
+	  .dtmf_low_level = -11,
+	  .mfr1_level = -7,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 17,
+	  .country = "be",
+	  .description = "Belgium",
+	  .ringcadence = { 1000, 3000 },
+	  .tones = {
+			/* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+			{ DAHDI_TONE_DIALTONE, "425" },
+			{ DAHDI_TONE_BUSY, "425/500,0/500" },
+			{ DAHDI_TONE_RINGTONE, "425/1000,0/3000" },
+			{ DAHDI_TONE_CONGESTION, "425/167,0/167" },
+			{ DAHDI_TONE_CALLWAIT, "1400/175,0/175,1400/175,0/3500" },
+			/* DIALRECALL - not specified */
+			{ DAHDI_TONE_DIALRECALL, "!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440" },
+			/* RECORDTONE - not specified */
+			{ DAHDI_TONE_RECORDTONE, "1400/500,0/15000" },
+			{ DAHDI_TONE_INFO, "900/330,1400/330,1800/330,0/1000" },
+			{ DAHDI_TONE_STUTTER, "425/1000,0/250" },
+		},
+	  .dtmf_high_level = -9,
+	  .dtmf_low_level = -11,
+	  .mfr1_level = -10,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 18,
+	  .country = "sg",
+	  .description = "Singapore",
+	  .ringcadence = { 400, 200, 400, 2000 },
+	  .tones = {
+			/* Reference: http://www.ida.gov.sg/idaweb/doc/download/I397/ida_ts_pstn1_i4r2.pdf */
+			{ DAHDI_TONE_DIALTONE,   "425" },
+			{ DAHDI_TONE_BUSY,       "425/750,0/750" },
+			{ DAHDI_TONE_RINGTONE,   "425*24/400,0/200,425*24/400,0/2000" },
+			{ DAHDI_TONE_CONGESTION, "425/250,0/250" },
+			{ DAHDI_TONE_CALLWAIT,   "425*24/300,0/200,425*24/300,0/3200" },
+			/* DIALRECALL - not specified - use repeating Holding Tone A,B*/
+			{ DAHDI_TONE_DIALRECALL, "425*24/500,0/500,425/500,0/2500" },
+			/* RECORDTONE - not specified */
+			{ DAHDI_TONE_RECORDTONE, "1400/500,0/15000" },
+			{ DAHDI_TONE_INFO,       "950/330,1400/330,1800/330,0/1000" },
+			{ DAHDI_TONE_STUTTER,    "!425/200,!0/200,!425/600,!0/200,!425/200,!0/200,!425/600,!0/200,!425/200,!0/200,!425/600,!0/200,!425/200,!0/200,!425/600,!0/200,425" },
+		},
+	  .dtmf_high_level = -11,
+	  .dtmf_low_level = -9,
+	  .mfr1_level = -7,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 19,
+	  .country = "il",
+	  .description = "Israel",
+	  .ringcadence = { 1000, 3000 },
+	  .tones = {
+			{ DAHDI_TONE_DIALTONE, "414" },
+			{ DAHDI_TONE_BUSY, "414/500,0/500" },
+			{ DAHDI_TONE_RINGTONE, "414/1000,0/3000" },
+			{ DAHDI_TONE_CONGESTION, "414/250,0/250" },
+			{ DAHDI_TONE_CALLWAIT, "414/100,0/100,414/100,0/100,414/600,0/3000" },
+			{ DAHDI_TONE_DIALRECALL, "!414/100,!0/100,!414/100,!0/100,!414/100,!0/100,414" },
+			{ DAHDI_TONE_RECORDTONE, "1400/500,0/15000" },
+			{ DAHDI_TONE_INFO, "1000/330,1400/330,1800/330,0/1000" },
+			{ DAHDI_TONE_STUTTER, "!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,!414/160,!0/160,414" },
+		},
+	  .dtmf_high_level = -10,
+	  .dtmf_low_level = -10,
+	  .mfr1_level = -10,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 20,
+	  .country = "br",
+	  .description = "Brazil",
+	  .ringcadence = { 1000, 4000 },
+	  .tones = {
+			{ DAHDI_TONE_DIALTONE, "425" },
+			{ DAHDI_TONE_BUSY, "425/250,0/250" },
+			{ DAHDI_TONE_RINGTONE, "425/1000,0/4000" },
+			{ DAHDI_TONE_CONGESTION, "425/250,0/250,425/750,0/250" },
+			{ DAHDI_TONE_CALLWAIT, "425/50,0/1000" },
+			{ DAHDI_TONE_DIALRECALL, "350+440" },
+			{ DAHDI_TONE_RECORDTONE, "425/250,0/250" },
+			{ DAHDI_TONE_INFO, "950/330,1400/330,1800/330" },
+			{ DAHDI_TONE_STUTTER, "350+440" } },
+	  .dtmf_high_level = -10,
+	  .dtmf_low_level = -12,
+	  .mfr1_level = -10,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 21,
+	  .country = "hu",
+	  .description = "Hungary",
+	  .ringcadence = { 1250, 3750 },
+	  .tones = {
+			/* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+			{ DAHDI_TONE_DIALTONE, "425" },
+			{ DAHDI_TONE_BUSY, "425/300,0/300" },
+			{ DAHDI_TONE_RINGTONE, "425/1250,0/3750" },
+			{ DAHDI_TONE_CONGESTION, "425/300,0/300" },
+			{ DAHDI_TONE_CALLWAIT, "425/40,0/1960" },
+			{ DAHDI_TONE_DIALRECALL, "425+450" },
+			/* RECORDTONE - not specified */
+			{ DAHDI_TONE_RECORDTONE, "1400/400,0/15000" },
+			{ DAHDI_TONE_INFO, "!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,0" },
+			{ DAHDI_TONE_STUTTER, "350+375+400" },
+		},
+	  .dtmf_high_level = -9,
+	  .dtmf_low_level = -11,
+	  .mfr1_level = -10,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 22,
+	  .country = "lt",
+	  .description = "Lithuania",
+	  .ringcadence = { 1000, 4000 },
+	  .tones = {
+			/* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+			{ DAHDI_TONE_DIALTONE, "425" },
+			{ DAHDI_TONE_BUSY, "425/350,0/350" },
+			{ DAHDI_TONE_RINGTONE, "425/1000,0/4000" },
+			{ DAHDI_TONE_CONGESTION, "425/200,0/200" },
+			{ DAHDI_TONE_CALLWAIT, "425/150,0/150,425/150,0/4000" },
+			/* DIALRECALL - not specified */
+			{ DAHDI_TONE_DIALRECALL, "!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440" },
+			/* RECORDTONE - not specified */
+			{ DAHDI_TONE_RECORDTONE, "1400/500,0/15000" },
+			{ DAHDI_TONE_INFO, "!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,0" },
+			/* STUTTER not specified */
+			{ DAHDI_TONE_STUTTER, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425" },
+		},
+	  .dtmf_high_level = -9,
+	  .dtmf_low_level = -11,
+	  .mfr1_level = -10,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 23,
+	  .country = "pl",
+	  .description = "Poland",
+	  .ringcadence = { 1000, 4000 },
+	  .tones = {
+			/* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+			{ DAHDI_TONE_DIALTONE, "425" },
+			{ DAHDI_TONE_BUSY, "425/500,0/500" },
+			{ DAHDI_TONE_RINGTONE, "425/1000,0/4000" },
+			{ DAHDI_TONE_CONGESTION, "425/500,0/500" },
+			{ DAHDI_TONE_CALLWAIT, "425/150,0/150,425/150,0/4000" },
+			/* DIALRECALL - not specified */
+			{ DAHDI_TONE_DIALRECALL, "!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440" },
+			/* RECORDTONE - not specified */
+			{ DAHDI_TONE_RECORDTONE, "1400/500,0/15000" },
+			{ DAHDI_TONE_INFO, "!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,0" },
+			/* STUTTER not specified */
+			{ DAHDI_TONE_STUTTER, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425" },
+		},
+	  .dtmf_high_level = -9,
+	  .dtmf_low_level = -11,
+	  .mfr1_level = -10,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 24,
+	  .country = "za",
+	  .description = "South Africa",
+	  .ringcadence = { 400, 200, 400, 2000 },
+	  .tones = {
+			{ DAHDI_TONE_DIALTONE, "400*33" },
+			{ DAHDI_TONE_BUSY, "400/500,0/500" },
+			{ DAHDI_TONE_RINGTONE, "400*33/400,0/200,400*33/400,0/2000" },
+			{ DAHDI_TONE_CONGESTION, "400/250,0/250" },
+			{ DAHDI_TONE_CALLWAIT, "400*33/250,0/250,400*33/250,0/250,400*33/250,0/250,400*33/250,0/250" },
+			/* DIALRECALL - not specified */
+			{ DAHDI_TONE_DIALRECALL, "350+440" },
+			/* RECORDTONE - not specified */
+			{ DAHDI_TONE_RECORDTONE, "1400/500,0/15000" },
+			{ DAHDI_TONE_INFO, "!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,!950/330,!1400/330,!1800/330,!0/1000,0" },
+			/* STUTTER not specified */
+			{ DAHDI_TONE_STUTTER, "!400*33/100,!0/100,!400*33/100,!0/100,!400*33/100,!0/100,!400*33/100,!0/100,!400*33/100,!0/100,!400*33/100,!0/100,400*33" },
+		},
+	  .dtmf_high_level = -11,
+	  .dtmf_low_level = -13,
+	  .mfr1_level = -7,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 25,
+	  .country = "pt",
+	  .description = "Portugal",
+	  .ringcadence = { 1000, 5000 },
+	  .tones = {
+			{ DAHDI_TONE_DIALTONE, "425" },
+			{ DAHDI_TONE_BUSY, "425/500,0/500" },
+			{ DAHDI_TONE_RINGTONE, "425/1000,0/5000" },
+			{ DAHDI_TONE_CONGESTION, "425/200,0/200" },
+			{ DAHDI_TONE_CALLWAIT, "425/200,425/200,425/200,0/5000" },
+			/* DIALRECALL - not specified */
+			{ DAHDI_TONE_DIALRECALL, "425/1000,0/200" },
+			/* RECORDTONE - not specified */
+			{ DAHDI_TONE_RECORDTONE, "1400/500,0/15000" },
+			{ DAHDI_TONE_INFO, "950/330,1400/330,1800/330,0/1000" },
+			/* STUTTER not specified */
+			{ DAHDI_TONE_STUTTER, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425" },
+		},
+	  .dtmf_high_level = -9,
+	  .dtmf_low_level = -11,
+	  .mfr1_level = -10,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 26,
+	  .country = "ee",
+	  .description = "Estonia",
+	  .ringcadence = { 1000, 4000 },
+	  .tones = {
+			/* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+			{ DAHDI_TONE_DIALTONE, "425" },
+			{ DAHDI_TONE_BUSY, "425/300,0/300" },
+			{ DAHDI_TONE_RINGTONE, "425/1000,0/4000" },
+			{ DAHDI_TONE_CONGESTION, "425/200,0/200" },
+			{ DAHDI_TONE_CALLWAIT, "950/650,0/325,950/325,0/30,1400/1300,0/2600" },
+			/* DIALRECALL - not specified */
+			{ DAHDI_TONE_DIALRECALL, "425/650,0/25" },
+			/* RECORDTONE - not specified */
+			{ DAHDI_TONE_RECORDTONE, "1400/500,0/15000" },
+			{ DAHDI_TONE_INFO, "950/0,0/325,950/325,0/30,1400/1300,0/2600" },
+			/* STUTTER not specified */
+			{ DAHDI_TONE_STUTTER, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425" },
+		},
+	  .dtmf_high_level = -9,
+	  .dtmf_low_level = -11,
+	  .mfr1_level = -10,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 27,
+	  .country = "mx",
+	  .description = "Mexico",
+	  .ringcadence = { 2000, 4000 },
+	  .tones = {
+			{ DAHDI_TONE_DIALTONE, "425" },
+			{ DAHDI_TONE_BUSY, "425/250,0/250" },
+			{ DAHDI_TONE_RINGTONE, "425/1000,0/4000" },
+			{ DAHDI_TONE_CONGESTION, "425/250,0/250" },
+			{ DAHDI_TONE_CALLWAIT, "425/200,0/600,425/200,0/10000" },
+			{ DAHDI_TONE_DIALRECALL, "!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440" },
+			{ DAHDI_TONE_RECORDTONE, "1400/500,0/15000" },
+			{ DAHDI_TONE_INFO, "950/330,0/30,1400/330,0/30,1800/330,0/1000" },
+			{ DAHDI_TONE_STUTTER, "!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440" },
+		},
+	  .dtmf_high_level = -8,
+	  .dtmf_low_level = -6,
+	  .mfr1_level = -7,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 28,
+	  .country = "in",
+	  .description = "India",
+	  .ringcadence = { 400, 200, 400, 2000 },
+	  .tones = {
+			/* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+			{ DAHDI_TONE_DIALTONE, "400*25" },
+			{ DAHDI_TONE_BUSY, "400/750,0/750" },
+			{ DAHDI_TONE_RINGTONE, "400*25/400,0/200,400*25/400,0/2000" },
+			{ DAHDI_TONE_CONGESTION, "400/250,0/250" },
+			{ DAHDI_TONE_CALLWAIT, "400/200,0/100,400/200,0/7500" },
+			/* DIALRECALL - not specified */
+			{ DAHDI_TONE_DIALRECALL, "!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440" },
+			/* RECORDTONE - not specified */
+			{ DAHDI_TONE_RECORDTONE, "1400/500,0/15000" },
+			/* INFO - not specified */
+			{ DAHDI_TONE_INFO, "!950/330,!1400/330,!1800/330,0/1000" },
+			/* STUTTER - not specified */
+			{ DAHDI_TONE_STUTTER, "!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440" },
+		},
+	  .dtmf_high_level = -10,
+	  .dtmf_low_level = -10,
+	  .mfr1_level = -10,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 29,
+	  .country = "de",
+	  .description = "Germany",
+	  .ringcadence = { 1000, 4000 },
+	  .tones = {
+			/* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+			{ DAHDI_TONE_DIALTONE, "425" },
+			{ DAHDI_TONE_BUSY, "425/480,0/480" },
+			{ DAHDI_TONE_RINGTONE, "425/1000,0/4000" },
+			{ DAHDI_TONE_CONGESTION, "425/240,0/240" },
+			{ DAHDI_TONE_CALLWAIT, "!425/200,!0/200,!425/200,!0/5000,!425/200,!0/200,!425/200,!0/5000,!425/200,!0/200,!425/200,!0/5000,!425/200,!0/200,!425/200,!0/5000,!425/200,!0/200,!425/200,0" },
+			/* DIALRECALL - not specified */
+			{ DAHDI_TONE_DIALRECALL, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425" },
+			/* RECORDTONE - not specified */
+			{ DAHDI_TONE_RECORDTONE, "1400/80,0/15000" },
+			{ DAHDI_TONE_INFO, "950/330,1400/330,1800/330,0/1000" },
+			{ DAHDI_TONE_STUTTER, "425+400" },
+		},
+	  .dtmf_high_level = -9,
+	  .dtmf_low_level = -11,
+	  .mfr1_level = -7,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 30,
+	  .country = "ch",
+	  .description = "Switzerland",
+	  .ringcadence = { 1000, 4000 },
+	  .tones = {
+			/* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+			{ DAHDI_TONE_DIALTONE, "425" },
+			{ DAHDI_TONE_BUSY, "425/500,0/500" },
+			{ DAHDI_TONE_RINGTONE, "425/1000,0/4000" },
+			{ DAHDI_TONE_CONGESTION, "425/200,0/200" },
+			{ DAHDI_TONE_CALLWAIT, "425/200,0/200,425/200,0/4000" },
+			/* DIALRECALL - not specified */
+			{ DAHDI_TONE_DIALRECALL, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425" },
+			/* RECORDTONE - not specified */
+			{ DAHDI_TONE_RECORDTONE, "1400/80,0/15000" },
+			{ DAHDI_TONE_INFO, "950/330,1400/330,1800/330,0/1000" },
+			{ DAHDI_TONE_STUTTER, "425+340/1100,0/1100" },
+		},
+	  .dtmf_high_level = -10,
+	  .dtmf_low_level = -10,
+	  .mfr1_level = -10,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 31,
+	  .country = "dk",
+	  .description = "Denmark",
+	  .ringcadence = { 1000, 4000 },
+	  .tones = {
+			/* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+			{ DAHDI_TONE_DIALTONE, "425" },
+			{ DAHDI_TONE_BUSY, "425/500,0/500" },
+			{ DAHDI_TONE_RINGTONE, "425/1000,0/4000" },
+			{ DAHDI_TONE_CONGESTION, "425/200,0/200" },
+			{ DAHDI_TONE_CALLWAIT, "!425/200,!0/600,!425/200,!0/3000,!425/200,!0/200,!425/200,0" },
+			/* DIALRECALL - not specified */
+			{ DAHDI_TONE_DIALRECALL, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425" },
+			/* RECORDTONE - not specified */
+			{ DAHDI_TONE_RECORDTONE, "1400/80,0/15000" },
+			{ DAHDI_TONE_INFO, "950/330,1400/330,1800/330,0/1000" },
+			/* STUTTER - not specified */
+			{ DAHDI_TONE_STUTTER, "425/450,0/50" },
+		},
+	  .dtmf_high_level = -9,
+	  .dtmf_low_level = -11,
+	  .mfr1_level = -10,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 32,
+	  .country = "cz",
+	  .description = "Czech Republic",
+	  .ringcadence = { 1000, 4000 },
+	  .tones = {
+			/* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+			{ DAHDI_TONE_DIALTONE, "425/330,0/330,425/660,0/660" },
+			{ DAHDI_TONE_BUSY, "425/330,0/330" },
+			{ DAHDI_TONE_RINGTONE, "425/1000,0/4000" },
+			{ DAHDI_TONE_CONGESTION, "425/165,0/165" },
+			{ DAHDI_TONE_CALLWAIT, "425/330,0/9000" },
+			/* DIALRECALL - not specified */
+			{ DAHDI_TONE_DIALRECALL, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425/330,0/330,425/660,0/660" },
+			/* RECORDTONE - not specified */
+			{ DAHDI_TONE_RECORDTONE, "1400/500,0/14000" },
+			{ DAHDI_TONE_INFO, "950/330,0/30,1400/330,0/30,1800/330,0/1000" },
+			/* STUTTER - not specified */
+			{ DAHDI_TONE_STUTTER, "425/450,0/50" },
+		},
+	  .dtmf_high_level = -9,
+	  .dtmf_low_level = -11,
+	  .mfr1_level = -10,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 33,
+	  .country = "cn",
+	  .description = "China",
+	  .ringcadence = { 1000, 4000 },
+	  .tones = {
+			/* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+			{ DAHDI_TONE_DIALTONE, "450" },
+			{ DAHDI_TONE_BUSY, "450/350,0/350" },
+			{ DAHDI_TONE_RINGTONE, "450/1000,0/4000" },
+			{ DAHDI_TONE_CONGESTION, "450/700,0/700" },
+			{ DAHDI_TONE_CALLWAIT, "450/400,0/4000" },
+			{ DAHDI_TONE_DIALRECALL, "450" },
+			{ DAHDI_TONE_RECORDTONE, "950/400,0/10000" },
+			{ DAHDI_TONE_INFO, "450/100,0/100,450/100,0/100,450/100,0/100,450/400,0/400" },
+			/* STUTTER - not specified */
+			{ DAHDI_TONE_STUTTER, "450+425" },
+		},
+	  .dtmf_high_level = -11,
+	  .dtmf_low_level = -9,
+	  .mfr1_level = -7,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 34,
+	  .country = "ar",
+	  .description = "Argentina",
+	  .ringcadence = { 1000, 4500 },
+	  .tones = {
+			{ DAHDI_TONE_DIALTONE, "425" },
+			{ DAHDI_TONE_BUSY, "425/300,0/300" },
+			{ DAHDI_TONE_RINGTONE, "425/1000,0/4500" },
+			{ DAHDI_TONE_CONGESTION, "425/200,0/300" },
+			{ DAHDI_TONE_CALLWAIT, "425/200,0/9000" },
+			{ DAHDI_TONE_DIALRECALL, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425/330,0/330,425/660,0/660" },
+			{ DAHDI_TONE_RECORDTONE, "1400/500,0/14000" },
+			{ DAHDI_TONE_INFO, "425/100,0/100" },
+			{ DAHDI_TONE_STUTTER, "425/450,0/50" },
+		},
+	  .dtmf_high_level = -11,
+	  .dtmf_low_level = -9,
+	  .mfr1_level = -7,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 35,
+	  .country = "my",
+	  .description = "Malaysia",
+	  .ringcadence = { 400, 200, 400, 2000 },
+	  .tones =   {
+			{ DAHDI_TONE_DIALTONE, "425" },
+			{ DAHDI_TONE_BUSY, "425/500,0/500" },
+			{ DAHDI_TONE_RINGTONE, "425/400,0/200,425/400,0/2000" },
+			{ DAHDI_TONE_CONGESTION, "425/500,0/500" },
+			{ DAHDI_TONE_CALLWAIT, "425/100,0/4000" },
+			{ DAHDI_TONE_DIALRECALL, "350+440" },
+			{ DAHDI_TONE_RECORDTONE, "1400/500,0/60000" },
+			{ DAHDI_TONE_INFO, "950/330,0/15,1400/330,0/15,1800/330,0/1000" },
+			{ DAHDI_TONE_STUTTER, "450+425" },
+		},
+	  .dtmf_high_level = -10,
+	  .dtmf_low_level = -10,
+	  .mfr1_level = -10,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 36,
+	  .country = "th",
+	  .description = "Thailand",
+	  .ringcadence = { 1000, 4000 },
+	  .tones =        {
+			/* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+			{ DAHDI_TONE_DIALTONE,   "400*50" },
+			{ DAHDI_TONE_BUSY,       "400/500,0/500" },
+			{ DAHDI_TONE_RINGTONE,   "400/1000,0/4000" },
+			{ DAHDI_TONE_CONGESTION, "400/300,0/300" },
+			{ DAHDI_TONE_CALLWAIT,   "1000/400,10000/400,1000/400" },
+			/* DIALRECALL - not specified - use special dial tone instead. */
+			{ DAHDI_TONE_DIALRECALL, "400*50/400,0/100,400*50/400,0/100" },
+			/* RECORDTONE - not specified */
+			{ DAHDI_TONE_RECORDTONE, "1400/500,0/15000" },
+			/* INFO - specified as an announcement - use tones instead. */
+			{ DAHDI_TONE_INFO,       "950/330,1400/330,1800/330" },
+			/* STUTTER - not specified */
+			{ DAHDI_TONE_STUTTER,    "!400/200,!0/200,!400/600,!0/200,!400/200,!0/200,!400/600,!0/200,!400/200,!0/200,!400/600,!0/200,!400/200,!0/200,!400/600,!0/200,400" },
+		},
+	  .dtmf_high_level = -11,
+	  .dtmf_low_level = -9,
+	  .mfr1_level = -7,
+	  .mfr2_level = -8,
+	},
+	{ .zone = 37,
+	  .country = "bg",
+	  .description = "Bulgaria",
+	  .ringcadence = { 1000, 4000 },
+	  .tones =        {
+			/* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+			{ DAHDI_TONE_DIALTONE,   "425" },
+			{ DAHDI_TONE_BUSY,       "425/500,0/500" },
+			{ DAHDI_TONE_RINGTONE,   "425/1000,0/4000" },
+			{ DAHDI_TONE_CONGESTION, "425/250,0/250" },
+			{ DAHDI_TONE_CALLWAIT,   "425/150,0/150,425/150,0/4000" },
+			{ DAHDI_TONE_DIALRECALL, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425" },
+			{ DAHDI_TONE_RECORDTONE, "1400/425,0/15000" },
+			{ DAHDI_TONE_INFO,       "950/330,1400/330,1800/330,0/1000" },
+			{ DAHDI_TONE_STUTTER,    "425/1500,0/100" },
+		},
+	  .dtmf_high_level = -9,
+	  .dtmf_low_level = -11,
+	  .mfr1_level = -10,
+	  .mfr2_level = -8,
+	},
+        { .zone = 38,
+	  .country = "ve",
+	  .description = "Venezuela",
+	  .ringcadence = { 1000, 4000 },
+	  .tones =        {
+			/* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+			{ DAHDI_TONE_DIALTONE, "425" },
+			{ DAHDI_TONE_BUSY, "425/500,0/500" },
+			{ DAHDI_TONE_RINGTONE, "425/1000,0/4000" },
+			{ DAHDI_TONE_CONGESTION, "425/250,0/250" },
+			{ DAHDI_TONE_CALLWAIT, "400+450/300,0/6000" },
+			{ DAHDI_TONE_DIALRECALL, "425" },
+			{ DAHDI_TONE_RECORDTONE, "1400/500,0/15000" },
+			{ DAHDI_TONE_INFO, "!950/330,!1440/330,!1800/330,0/1000" },
+			/* STUTTER - not specified */
+			{ DAHDI_TONE_STUTTER, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425" },
+		},
+	  .dtmf_high_level = -7,
+	  .dtmf_low_level = -9,
+	  .mfr1_level = -7,
+	  .mfr2_level = -8,
+        },
+        { .zone = 39,
+	  .country = "ph",
+	  .description = "Philippines",
+	  .ringcadence = { 1000, 4000 },
+	  .tones =        {
+			/* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+			{ DAHDI_TONE_DIALTONE, "425" },
+			{ DAHDI_TONE_BUSY, "480+620/500,0/500" },
+			{ DAHDI_TONE_RINGTONE, "425+480/1000,0/4000" },
+			{ DAHDI_TONE_CONGESTION, "480+620/250,0/250" },
+			{ DAHDI_TONE_CALLWAIT, "440/300,0/10000" },
+			/* DIAL RECALL - not specified */
+			{ DAHDI_TONE_DIALRECALL, "!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440" },
+			/* RECORD TONE - not specified */
+			{ DAHDI_TONE_RECORDTONE, "1400/500,0/15000" },
+			/* INFO TONE - not specified */
+			{ DAHDI_TONE_INFO, "!950/330,!1400/330,!1800/330,0" },
+			/* STUTTER TONE - not specified */
+			{ DAHDI_TONE_STUTTER, "!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,!350+440/100,!0/100,350+440" },
+		},
+	  .dtmf_high_level = -10,
+	  .dtmf_low_level = -10,
+	  .mfr1_level = -10,
+	  .mfr2_level = -8,
+        },
+	{ .zone = 40,
+	  .country = "ru",
+	  .description = "Russian Federation",
+	  .ringcadence = { 1000, 4000 },
+	  .tones = {
+			/* References:
+			   http://www.minsvyaz.ru/site.shtml?id=1806
+			   http://www.aboutphone.info/lib/gost/45-223-2001.html */
+			{ DAHDI_TONE_DIALTONE, "425" },
+			{ DAHDI_TONE_BUSY, "425/350,0/350" },
+			{ DAHDI_TONE_RINGTONE, "425/1000,0/4000" },
+			{ DAHDI_TONE_CONGESTION, "425/175,0/175" },
+			{ DAHDI_TONE_CALLWAIT, "425/200,0/5000" },
+			{ DAHDI_TONE_RECORDTONE, "1400/400,0/15000" },
+			{ DAHDI_TONE_INFO, "950/330,1440/330,1800/330,0/1000" },
+			{ DAHDI_TONE_STUTTER, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425" },
+		},
+	  .dtmf_high_level = -10,
+	  .dtmf_low_level = -10,
+	  .mfr1_level = -10,
+	  .mfr2_level = -8,
+	},
+	{
+		.zone = 41,
+		.country = "tr",
+		.description = "Turkey",
+		.ringcadence = { 2000, 4000 },
+		.tones = {
+			{ DAHDI_TONE_DIALTONE,   "450" },
+			{ DAHDI_TONE_BUSY,       "450/500,0/500" },
+			{ DAHDI_TONE_RINGTONE,   "450/2000,0/4000" },
+			{ DAHDI_TONE_CONGESTION, "!450/200,!0/200,!450/200,!0/200,!450/200,!0/200,450/600,0/200" },
+			{ DAHDI_TONE_CALLWAIT,   "450/200,0/600,450/200,0/800" },
+			/* This should actually be 950+1400+1800, but we only support 2 tones at a time */
+			{ DAHDI_TONE_INFO,       "!950+1400/300,!0/1000,!950+1400/300,!0/1000,!950+1400/1000,0" },
+			{ DAHDI_TONE_STUTTER,    "!450/100,!0/100,!450/100,!0/100,!450/100,!0/100,!450/100,!0/100,!450/100,!0/100,!450/100,!0/100,450" },
+		},
+		.dtmf_high_level = -10,
+		.dtmf_low_level = -10,
+		.mfr1_level = -10,
+		.mfr2_level = -8,
+	},
+	{
+		.zone = 42,
+		.country = "pa",
+		.description = "Panama",
+		.ringcadence = { 2000, 4000 },
+		.tones = {
+			/* Reference: http://www.itu.int/ITU-T/inr/forms/files/tones-0203.pdf */
+			{ DAHDI_TONE_DIALTONE, "425" },
+			{ DAHDI_TONE_BUSY, "425/320,0/320" },
+			{ DAHDI_TONE_RINGTONE, "425/1200,0/4650" },
+			{ DAHDI_TONE_CONGESTION, "425/320,0/320" },
+			{ DAHDI_TONE_CALLWAIT, "425/180,0/180,425/180" },
+			/* RECALL DIAL TONE - not specified */
+			{ DAHDI_TONE_DIALRECALL, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425" },
+			/* RECORD TONE - not specified */
+			{ DAHDI_TONE_RECORDTONE, "1400/500,0/15000" },
+			{ DAHDI_TONE_INFO, "!950/330,!1400/330,!1800/330,0" },
+			/* STUTTER TONE - not specified */
+			{ DAHDI_TONE_STUTTER, "!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,!425/100,!0/100,425" },
+		},
+		.dtmf_high_level = -9,
+		.dtmf_low_level = -11,
+		.mfr1_level = -7,
+		.mfr2_level = -8,
+	},
+	{ .zone = -1 }
+};

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-voip/dahdi-tools.git



More information about the Pkg-voip-commits mailing list