diff --git a/avrdude/.cvsignore b/avrdude/.cvsignore
new file mode 100644
index 00000000..059edf8b
--- /dev/null
+++ b/avrdude/.cvsignore
@@ -0,0 +1,33 @@
+*.diff
+*.patch
+y.output
+y.tab.h
+lexer.c
+config_gram.c
+config_gram.h
+.cvsignore
+.depend
+.deps
+INSTALL
+Makefile.in
+Makefile
+ac_cfg.h.in
+aclocal.m4
+autom4te.cache
+configure
+depcomp
+install-sh
+compile
+missing
+mkinstalldirs
+stamp-h.in
+stamp-h1
+ac_cfg.h
+avrdude.conf
+avrdude.conf.tmp
+avrdude.spec
+config.guess
+config.log
+config.status
+config.sub
+avrdude
diff --git a/avrdude/AUTHORS b/avrdude/AUTHORS
new file mode 100644
index 00000000..3b32d005
--- /dev/null
+++ b/avrdude/AUTHORS
@@ -0,0 +1,20 @@
+AVRDUDE was written by:
+
+	Brian S. Dean  <bsd@bdmicro.com>
+
+Contributors:
+
+	Joerg Wunsch <j@uriah.heep.sax.de>
+	Eric Weddington <ericw@evcohs.com>
+	Jan-Hinnerk Reichert <hinni@despammed.com>
+	Alex Shepherd <maillists@ajsystems.co.nz>
+	Martin Thomas <mthomas@rhrk.uni-kl.de>
+	Theodore A. Roth <troth@openavr.org>
+	Michael Holzt <kju-avr@fqdn.org>
+	Colin O'Flynn <coflynn@newae.com>
+	Thomas Fischl <tfischl@gmx.de>
+	David Hoerl <dhoerl@mac.com>
+	Michal Ludvig <mludvig@logix.net.nz>
+
+For minor contributions, please see the ChangeLog files.
+
diff --git a/avrdude/COPYING b/avrdude/COPYING
new file mode 100644
index 00000000..d60c31a9
--- /dev/null
+++ b/avrdude/COPYING
@@ -0,0 +1,340 @@
+		    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) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 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) year  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/avrdude/ChangeLog b/avrdude/ChangeLog
new file mode 100644
index 00000000..2bfa1aa9
--- /dev/null
+++ b/avrdude/ChangeLog
@@ -0,0 +1,227 @@
+2010-01-15  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Submitted by Soren Jorvang:
+	bug #28611: -i delay not being applied to all serial port
+	bit banging state transitions
+	* serbb_win32.c: Apply ispdelay everywhere.
+	* serbb_posix.c: (Dito.)
+
+2010-01-15  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* stk500v2_private.h: Implement TPI mode for AVRISPmkII/STK600
+	* config_gram.y: (Dito.)
+	* avrpart.h: (Dito.)
+	* stk500v2.c: (Dito.)
+	* main.c: (Dito.)
+	* lexer.l: (Dito.)
+	* avrdude.conf.in: Add ATtiny4/5/9/10
+	* avrdude.1: Document TPI and new device support.
+	* doc/avrdude.texi: (Dito.)
+
+2010-01-14  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Submitted by clint fisher:
+	patch #7038: Adding Atmega32U4 Device to avrdude.conf.in
+	* avrdude.conf.in (atmega32u4): New device.
+	* avrdude.1: Document the new device support.
+	* doc/avrdude.texi: (Dito.)
+
+2010-01-14  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Submitted by Thomas Pircher:
+	patch #6927: Documentation patches
+	* doc/avrdude.texi: Fix various typos, and remove the last
+	remnants of obsoleted options -i/-o/-m/-f.
+	* avrdude.1: Merge typo fixes from avrdude.texi where
+	applicable.
+
+2010-01-14  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* avrdude.1: Update documentation to match the reality (device
+	support, memory areas).
+	* doc/avrdude.texi: Update documentation to match the
+	reality (device support, programmer support, memory areas).
+	Merge buspirate-specific comments from avrdude.1.
+	* jtagmkII.c: Add some firmware feature checks.
+
+2010-01-13  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* jtagmkII.c: Implement PDI mode support for the JTAG ICE mkII
+	and the AVR Dragon.
+	* jtagmkII.h: (Dito.)
+	* config_gram.y: (Dito.)
+	* jtagmkII_private.h: (Dito.)
+	* avrdude.conf.in: (Dito.)
+	* lexer.l: (Dito.)
+
+2010-01-13  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* stk500v2.c: Update STK600 routing and socket card data from XML
+	file.
+
+2010-01-13  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* stk500v2.c: Cleanup the open/close handling to avoid accessing
+	unallocated memory (in the atexit handler) in case of bailing out.
+	* main.c: (Ditto.)
+
+2010-01-13  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* jtagmkII.c: Stylistic changes: move #defines out into
+	jtagmkII_private.h, drop all #if 0 blocks, fold overly long lines,
+	move the *_initpgm() functions to the end of the file; while being
+	here, remove all trailing whitespace.
+	* jtagmkII_private.h: move AVR32 #defines here.
+
+2010-01-12  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* bootstrap: autoconf 2.62 works well.
+
+2010-01-12  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Various fixes for Xmega devices.
+	* avrdude.conf.in: Correctly declare EEPROM page sizes for
+	all Xmega devices (0x20 instead of 0x100).
+	* avr.c: If a memory region has a page size declared, try
+	using the paged IO routines regardless of the target memory
+	name.  Xmega EEPROM requires to be written in paged mode.
+	Correctly use a long (rather than unsigned long) variable to
+	evaluate the success status of the paged mode write attempt.
+	* stk500v2.c: Don't apply TIF space offsets twice (bug #27995:
+	AVRDUDE 5.8svn fails to program and read XMEGA); use
+	stk500v2_loadaddr() prior to paged mode (EEPROM and flash) writes,
+	otherwise programming of flash areas will fail; while being there,
+	check the return value of stk500v2_loadaddr() everywhere; use the
+	correct write/erase mode bits (same as AVR Studio does).
+
+2010-01-12  Michal Ludvig  <mludvig@logix.net.nz>
+
+	* buspirate.c: Initialise firmware version to v0.0
+	prior to parsing the buspirate banner.
+
+2010-01-11  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Clean-up the Xmega erase functions.
+	* jtagmkII_private.h: Add CMND_XMEGA_ERASE as well as
+	the various XMEGA_ERASE_* definitions (from updated
+	appnote AVR067)
+	* jtagmkII.c (jtagmkII_chip_erase): Correctly implement Xmega chip
+	erase based on CMND_XMEGA_ERASE.  After erasing an Xmega part, do
+	*not* reinitialize the world, as a subsequent programming
+	operation will fail (for unknown reasons).  Actually, this was
+	really only required for ancient AVRs, but doesn't hurt on mega
+	and tiny devices.
+	* jtagmkII.c (jtagmkII_pre_write): Remove, this turned out
+	to be just a chip erase.
+	* jtagmkII.c (jtagmkII_program_disable): Don't try reading
+	"hfuse" for Xmega parts; they don't have it.
+	* main.c (main): Re-enable auto-erase.  It's been done
+	before (as "jtagmkII_pre_write") in jtagmkII_paged_write()
+	anyway.  Xmega boot and application flash areas should be
+	handled separately in the future, so auto_erase can only
+	affect the area just being programmed.
+
+2010-01-11  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* main.c (main): disable safemode for Xmega parts.
+
+2010-01-12  Michal Ludvig  <mludvig@logix.net.nz>
+
+	* buspirate.c: If the BusPirate doesn't respond
+	to a standard a reset command assume it was in binmode
+	and attempt to exit to text mode first.
+
+2010-01-08  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* bitbang.c: Fix Win32 build error: move freq up to the file
+	level.
+	* buspirate.c: Fix Win32 build warning: include <malloc.h> to
+	to get a declaration for alloca().
+
+2010-01-08  Thomas Fischl <tfischl@gmx.de>
+
+	bug #28520: Programming with USBasp with low clock speed fails
+	* usbasp.c: Change blocksize depending on sck frequency to
+	avoid usb transmition timeouts.
+
+2010-01-08  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	bug #27505: serbb_posix does not cope with inverted pins
+	* serbb_posix (serbb_highpulsepin): apply PIN_MASK when
+	checking pin numbers.
+	* serbb_win32 (serbb_highpulsepin): (Dito.)
+
+2010-01-08  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	bug #28516: Linux/Dragon: Error message on exit
+	* stk500v2.c: Fix the "bad response to GO command:
+	RSP_ILLEGAL_EMULATOR_MODE" message.  jtagmkII_close()
+	has been called with the wrong pgm->cookie.  Wrap it
+	inside stk500v2_jtagmkII_close(), adjusting the cookie
+	data appropriately.
+
+2010-01-08  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Submitted by Doug:
+	patch #7010: Win32 enhanced bitbang_delay
+	* bitbang.c (bitbang_calibrate_delay, bitbang_delay): On Win32,
+	use the high-resolution performance counter rather than the
+	uneducated delay loop guess if it is available on the target
+	hardware.
+
+2010-01-08  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Submitted by Gerard:
+	patch #6828: Using arbitrary BAUD rates
+	* ser_posix.c (serial_baud_lookup): Allow non-standard baud
+	rates.
+	* ser_win32.c (serial_baud_lookup): (Dito.)
+
+2010-01-07  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Submitted by Eric Trein:
+	bug #27596: AT90s2333 is not correctly supported in avrdude.conf
+	* avrdude.conf.in (at90s2333): add various STK500v2 parameters.
+
+2010-01-07  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Submitted by Gyorgy Szekely:
+	bug #28458: Buffer line is incorrectly released for PP programmers
+	* par.c (par_close): use par_setmany() rather than par_setpin()
+	for PPI_AVR_BUFF.
+
+2010-01-07  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Submitted by Lukasz Goralczyk:
+	bug #27507: SIGSEGV when using avrdragon (avrdude 5.8)
+	* stk500v2.c (stk500v2_dragon_isp_initpgm): Use
+	stk500v2_jtagmkII_setup/stk500v2_jtagmkII_rather than their
+	jtagII counterparts, to get the private data properly
+	initialized.
+
+2010-01-07  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* buspirate.c: Cosmetics: remove UTF-8 dashes, adjust for 8-column
+	hard tabs.
+
+2010-01-07  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* buspirate.c: add $ Id $ line.
+	* buspirate.h: add $ Id $ line.
+
+2010-01-07  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Fix a few warnings that came up recently (some of them only triggered
+	by recent GCC versions).
+	* config_gram.y (parse_cmdbits): "brkt possibly used uninitialized"
+	(GCC errs here)
+	* jtagmkII.c (jtagmkII_reset32): "status possibly used uninitialized"
+	(I think GCC errs, too)
+	* buspirate.c: "pointers differ in signedness" (mismatch between
+	string processing and the use of "unsigned char" throughought the
+	AVRDUDE API)
+
+2010-01-01  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* jtagmkII.c (jtagmkII_smc_init32): replace sleep() by usleep() for
+	win32 compatibility.
diff --git a/avrdude/ChangeLog-2001 b/avrdude/ChangeLog-2001
new file mode 100644
index 00000000..048dcf1c
--- /dev/null
+++ b/avrdude/ChangeLog-2001
@@ -0,0 +1,598 @@
+2001-12-30  Brian S. Dean  <bsd@bsdhome.com>
+
+	* main.c: Update version.
+
+	* avrdude.conf.sample: Clarify a comment.
+
+	* avrdude.conf.sample: fix address bits
+
+	* avrdude.1: Bring up to date.
+
+2001-12-29  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrdude.conf.sample: Add the AVR3 progammer.
+
+	* avr.c, avrdude.conf.sample, config_gram.y, main.c, pindefs.h:
+	Fix VCC assertion.
+
+	Make the BUFF pin a mask like VCC to allow multiple pins to be
+	asserted at the same time (STK200 has two buffer enable lines).
+
+	Add the STK200 programmer.
+
+	Fix EEPROM address line selection for several parts.
+
+2001-12-15  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrdude.conf.sample: fix spelling error
+
+2001-11-24  Brian S. Dean  <bsd@bsdhome.com>
+
+	* Makefile:
+	Change "WARNING" to "NOTE" when overwriting the avrprog.conf file.
+
+	* avrdude.1: Add my e-mail address.
+
+	* avrdude.conf.sample:
+	Add comments about instruction formats.  Correct an instruction
+	specification (cut&paste error).
+
+2001-11-21  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avr.c, config_gram.y, lexer.l, term.c:
+	In interactive mode, reset the address and length if we start dumping
+	a memory type different than the previous one.
+
+	* avr.c, avrdude.conf.sample, config_gram.y:
+	Allow instruction data to be specified more flexibly, which can be
+	used to make the instruction input more readable in the config file.
+
+	* main.c: Bump version number.
+
+	* Makefile, avr.c, avr.h, avrdude.conf.sample, config.c, config.h:
+	* config_gram.y, fileio.c, fileio.h, lexer.l, main.c, term.c:
+	This is a major re-write of the programming algorithms.  The Atmel
+	serial programming instructions are not very orthoganal, i.e., the
+	"read fuse bits" instruction on an ATMega103 is an entirely different
+	opcode and data format from the _same_ instruction for an ATMega163!
+	Thus, it becomes impossible to have a single instruction encoding
+	(varying the data) across the chip lines.
+
+	This set of changes allows and requires instruction encodings to be
+	defined on a per-part basis within the configuration file.  Hopefully
+	I've defined the encoding scheme in a general enough way so it is
+	useful in describing the instruction formats for yet-to-be invented
+	Atmel chips.  I've tried hard to make it match very closely with the
+	specification in Atmel's data sheets for their parts.  It's a little
+	more verbose than what I initially hoped for, but I've tried to keep
+	it as concise as I could, while still remaining reasonably flexible.
+
+2001-11-19  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avr.c, avr.h, avrdude.conf.sample, main.c, ppi.c, term.c:
+	Add support for ATMega163.
+
+	Add support for reading/writing ATMega163 lock and fuse bits.
+	Unfortunately, in looking at the specs for other ATMega parts, they
+	use entirely different instruction formats for these commands.  Thus,
+	these routines won't work for the ATMega103, for example.
+
+	Add support for sending raw command bytes via the interactive terminal
+	interface.  This allows one to execute any programming instruction on
+	the target device, whether or not avrprog supports it explicitly or
+	not.  Thus, one can use this feature to program fuse / lock bits, or
+	access any other feature of a current or future device that avrprog
+	does not know how to do.
+
+	Add in comments, an experimental instruction format in the
+	configuration file.  If this works out, it would allow supporting new
+	parts and non-orthoganal instructions across existing parts without
+	making avrprog code changes.
+
+2001-11-17  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrdude.conf.sample: Add ATMEGA163 part.
+
+2001-11-11  Brian S. Dean  <bsd@bsdhome.com>
+
+	* main.c: output formatting
+
+2001-11-05  Brian S. Dean  <bsd@bsdhome.com>
+
+	* ppi.c: Get ppi.h from /usr/include, not /sys.
+
+2001-10-31  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avr.c, avrdude.conf.sample, main.c: Correct version string.
+	Update read/write status more frequently.
+	Prefix ATMega parts with an 'm'.
+
+2001-10-16  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avr.c: Change ording for memory display.
+
+	* config_gram.y: comment
+
+	* avr.c, avr.h, avrdude.conf.sample, config_gram.y, lexer.l, term.c:
+	Fix (again, hopefully) page addressing for the ATMega parts.
+
+	Rename the poorly chosen name "bank" to "page" for page addressing.
+	Atmel calls it "page" in their documentation.
+
+	* config_gram.y, main.c: Fix an (non)exit.
+	Silence a couple of compiler warnings.
+
+	* avr.c, avr.h, avrdude.conf.sample, config_gram.y, main.c:
+	Fix ATMega flash addressing.  Add an ATMEGA16 part.  Perform sanity
+	checking on the memory parameters for parts that do bank addressing.
+
+2001-10-15  Brian S. Dean  <bsd@bsdhome.com>
+
+	* config.c, config.h, lists.h: Add copyright.
+
+	* config_gram.y, lexer.l, lists.c: Add copyrights.
+
+	* Makefile: Attempt to install avrprog.conf.
+
+	* avrdude.conf.sample: Correct dt006 pinout.
+
+	* Makefile, lexer.l:
+	Try and detect an old-style config file and print an appropriate error
+	message and a suggestion for correcting it.
+
+	* Makefile, avr.c, avrdude.1, avrdude.conf.sample: Update the man page.
+
+	Miscellaneous minor cleanups.
+
+2001-10-14  Brian S. Dean  <bsd@bsdhome.com>
+
+	* Makefile, Makefile.inc, avr.c, avr.h, avrdude.conf.sample:
+	* config.c, config.h, config_gram.y, lexer.l, lists.c, lists.h:
+	* main.c, pindefs.h, term.c:
+	Use lex/yacc for parsing the config file.  Re-work the config file
+	format using a more human-readable format.
+
+	Read part descriptions from the config file now instead of hard-coding
+	them.
+
+	Update usage().
+
+	Cleanup unused code.
+
+	* Makefile, avr.c, avr.h, fileio.c, term.c:
+	First cut at supporting the ATmega 103 which uses bank addressing and
+	has a 128K flash.
+
+	Due to the bank addressing required, interactive update of the flash
+	is not supported, though the eeprom can be updated interactively.
+	Both memories can be programmed via non-interactive mode.
+
+	Intel Hex Record type '04' is now generated as required for outputing
+	memory contents that go beyond 64K.
+
+2001-10-13  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avr.c, avr.h, fileio.c, fileio.h, main.c, ppi.c, ppi.h, term.c:
+	* term.h:
+	Style fixes.
+
+	* avr.c, avr.h, fileio.c, fileio.h, main.c, term.c:
+	Commit changes in preparation for support the ATMega line.
+
+2001-10-01  Brian S. Dean  <bsd@bsdhome.com>
+
+	* Makefile: Don't override CFLAGS.
+
+	* avrdude.1: Correct default pin assignment.
+
+	* avr.c, fileio.c, main.c, ppi.c, term.c:
+	Remove debugging code - it served its purpose.
+
+	Update copyrights.
+
+2001-09-21  Brian S. Dean  <bsd@bsdhome.com>
+
+	* main.c:
+	Be sure to read the exit specs after the pin configuration has been
+	assigned, otherwise, we may apply the exit specs to the wrong pins.
+
+	* main.c: debugging
+
+2001-09-20  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrdude.1, avrdude.conf.sample, main.c:
+	Prefix pin config entries in the config file with a "c:".  Later, I
+	might make part descriptions read in this way and we can use a
+	different letter for those (p).  This will make the parsing easier to
+	distinguish between the entry types.
+
+	* main.c: Initialize pin configuration description.
+
+2001-09-19  Brian S. Dean  <bsd@bsdhome.com>
+
+	* AVRprog.pdf, Makefile, avr.c, avrdude.1, avrdude.conf.sample:
+	* avrdude.pdf, fileio.c, fileio.h, main.c, pindefs.h, term.c:
+	Make the pin definitions configurable based on entries in a config
+	file.  This makes supporting other programmers much easier.
+
+	Rename AVRprog.pdf to avrprog.pdf.
+
+2001-04-29  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrprog-programmer.jpg: Remove this image file from the repository.
+
+2001-04-26  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrprog-schematic.jpg:
+	Remove this image, use AVRprog.pdf as the preferred schematic for the
+	programmer.
+
+2001-04-25  Brian S. Dean  <bsd@bsdhome.com>
+
+	* AVRprog.pdf, Makefile, avrdude.1:
+	Add a schematic provided by Joerg Wunch and also update the manual
+	page (also updated by Joerg) to reference the schematic.
+
+2001-02-25  Brian S. Dean  <bsd@bsdhome.com>
+
+	* Makefile, Makefile.inc: Automate dependency generation.
+
+2001-02-08  Brian S. Dean  <bsd@bsdhome.com>
+
+	* main.c: Turn off ready led when finished programming.
+
+	* main.c: update version
+
+	* avr.c, main.c: Correct a few comments.
+
+	* Makefile, avr.c, term.c: Makefile : update dependencies
+
+	avr.c : correct status led updates
+
+	term.c : update status leds on write, make the address and length
+	         arguments for dump optional.
+
+2001-01-26  Brian S. Dean  <bsd@bsdhome.com>
+
+	* main.c: Version 1.1
+
+	* main.c:
+	Hmmm ... cvs co -D <timestamp> does not work.  Change the revision
+	timestamp to a full date/time value.
+
+	* avr.c, fileio.c, main.c, ppi.c, term.c:
+	Add a -V option to display the version information about each
+	component module.  This is intended for support purposes, so that I
+	can tell unambiguously what version a binary out in the field is.
+
+	Additionally, display a revision timestamp along with the version
+	number.  This also is intended for aiding in support and is the Unix
+	time of the latest component module.  Having this, should allow me to
+	do a "cvs co -D timestamp avrprog" and get exactly the source of the
+	version that is being reported.
+
+	* fileio.c:
+	Return the maximum address (+1) written as opposed to the actual
+	number of bytes written.  The presence of an Intel Hex address
+	record can cause these two number to be different; but the callers
+	of this routine need the former.
+
+	* main.c:
+	Fix a place where we were exiting without applying the exit-specs.
+
+	Wrap a long line.
+
+	* avr.c, fileio.c: avr.c: Update a comment.
+
+	fileio.c: Properly handle all the Intel Hex record types that I can
+	          find information about.
+
+2001-01-25  Brian S. Dean  <bsd@bsdhome.com>
+
+	* Usage, avr.h: Get rid of the Usage file.
+
+2001-01-24  Brian S. Dean  <bsd@bsdhome.com>
+
+	* Makefile, avr.c, avr.h, main.c, pindefs.h, ppi.c:
+	Move pin definitions to their own file.
+
+	First pass at providing feedback via the optionally connected leds.  I
+	don't actually have any of these attached to my programmer, so I can
+	only guess as whether this is toggling them on and off correctly.
+
+	Also, enable and disable the optional 74367 buffer.
+
+	* avr.h, main.c, ppi.c, ppi.h, avr.c:
+	Rearrange the pinout for the programmer to be a little more logical.
+	Provide hooks to support a buffered programmer, pin 6 is now used to
+	enable a buffer that can be used to isolate the target system from the
+	parallel port pins.  This is important when programming the target
+	in-system.
+
+	Totally change the way the pin definitions are defined.  Actually
+	set/clear pins based on the way more intuitive pin number, instead of
+	PPI data register, bit number combination.  A table of pin data is
+	used so that any hardware inversion done by the parallel port is
+	accounted for, what you set is actually what appears at the pin.
+	Retain the old method for handling Vcc, however, because the hold
+	method is much easier to use when setting / retrieving multiple pins
+	simultaneously.
+
+2001-01-22  Brian S. Dean  <bsd@bsdhome.com>
+
+	* Makefile: Don't gzip the man page.
+
+	* avrdude.1: .Nm macro fix.  Submitted by Joerg.
+
+	* main.c: Cosmetic, don't output a preceding linefeed for usage().
+
+	* Makefile, avr.c, avr.h, fileio.c, term.c:
+	Makefile : use gzip -f for man page installation so that we don't get
+	           prompted.
+
+	avr.c avr.h fileio.c term.c :
+
+	     Change the avrpart data structure so that the typedef AVRMEM is
+	     used as an index into an array for the sizes of the memory types
+	     and also for pointers to buffers that represent the chip data for
+	     that memory type.  This removes a lot of conditional code of the
+	     form:
+
+			switch (memtype) {
+				case AVR_FLASH :
+			 	...
+			}
+
+	     Also, re-code avr_read_byte() and avr_write_byte() to properly
+	     handle the flash memory type without having to tell them whether
+	     they should program the high byte or the low byte - figure that
+	     out from the address itself.  For flash memory type, these
+	     routines now take the actual byte address instead of the word
+	     address.  This _greatly_ simplifies many otherwise simple
+	     operations, such a reading or writing a range of memory, by not
+	     having to worry about whether the address starts on an odd byte
+	     or an even byte.
+
+2001-01-20  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avr.c, avr.h, fileio.c, fileio.h, main.c:
+	Return error codes instead of exiting, thus making sure that we exit
+	only via main() so that the exitspecs are properly applied.
+
+	When reading input data from a file, remember how many bytes were read
+	and write and verify only that many bytes.
+
+	Don't complain when an input file size is smaller than the memory size
+	we are programming.  This is normal.
+
+	* fileio.c:
+	Correct checksum calculation; failure to account for the value of the
+	record type was causing non-zero record types to be calculated
+	incorrectly.
+
+	* Makefile, main.c: Makefile : install the man page
+
+	main.c : drop the giant usage text now that we have a man page.
+
+	* avrdude.1:
+	Add initial man page graciously contributed by Joerg Wunsch.  Thanks
+	Joerg!
+
+2001-01-19  Brian S. Dean  <bsd@bsdhome.com>
+
+	* term.c:
+	Accept abbreviations for eeprom and flash for the dump and write
+	commands.
+
+	Fix small bug keeping 1 character command lines from being added to
+	the history.
+
+	* term.c:
+	Implement enough state in cmd_dump so that if it is called with no
+	arguments, it successively dumps the next chunk of data of the same
+	previously specified length.
+
+	* term.c, term.h, fileio.c, fileio.h, main.c, ppi.c, ppi.h:
+	* Makefile, avr.c, avr.h, avrprog.c:
+	The program was getting too large for a single file.  Split it up into
+	more modular pieces.
+
+	Also, accept command abbreviations as long as they are not ambiguous.
+
+	* avrprog.c:
+	Add ability to specify the state of the power and reset pins on
+	program exit.  Default to leaving the pins in the state they were when
+	we found them.
+
+	Contributed by: Joerg Wunsch
+
+2001-01-18  Brian S. Dean  <bsd@bsdhome.com>
+
+	* Makefile, avrprog.c:
+	Switch to using readline() for getting terminal input.  I can't seem
+	to get the history capabilities working yet, but even so, it does
+	better handling of the prompt and strips newlines for us, so it's
+	still a win.
+
+	Add a few new commands for terminal mode: help, sig, part, erase.
+	Display rudimentory help using the help command.
+
+	Add some function prototypes.
+
+	* Usage, avrprog.c:
+	Change -c (interactive command mode) to the more intuitive -t
+	(terminal mode).
+
+	Make binary format the default for output.
+
+	Update the parts table with corrections for old values and add some
+	new values.
+
+2001-01-15  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrprog.c:
+	Automatically verify on-chip data with what we just programmed.
+
+	* avrprog.c, Makefile:
+	Prepare the Makefile for integration into the FreeBSD ports tree.
+
+	Fix a few "may be used uninitialized" bugs found by -Wall.
+
+2001-01-14  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrprog.c: Free a buffer.
+
+	* avrprog.c:
+	Use a smarter programming algorithm - read the existing data byte
+	first and only write the new one if it is different.
+
+	Add -n option which is a test mode in which the chip is not actually
+	updated.  This option does not affect writes in interactive mode.
+
+	* avrprog.c: Add the "dump" and "write" interactive commands.
+
+	* avrprog.c:
+	Correctly produce and handle "end of record" for intel hex files.
+
+2001-01-13  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrprog.c:
+	Re-enable writing to the chip.  I should probably should make this a
+	command-line selectable option so that I don't keep forgetting and
+	committing it with it disabled.
+
+	* avrprog.c:
+	Add a newline before exiting due to command line errors.  Perform a
+	bit more option compatibility testing between -c, -i, and -o.
+
+	* avrprog.c: Add input file format auto-detection support.
+
+	* Usage, avrprog.c: Say what the defaults are.
+
+	* avrprog-programmer.jpg, Usage, avrprog-schematic.jpg: New files.
+
+	* avrprog.c: Correct usage text.
+
+	* avrprog.c:
+	Parameterize a few additional items per chip.  Print out all per-chip
+	parameters on startup.  Use the per-chip parameters in the code
+	instead of hard-coded values for the 2313.
+
+	* avrprog.c: Fix filename assignment error.
+
+	Clean up debugging code a little, utilize fileio() instead of making
+	direct calls to b2ihex().
+
+	* avrprog.c: A lot of general code cleanup.
+
+	Re-work command line options to be more intuitive.
+
+	Support Intel Hex input and output file formats.  Provide hooks to
+	support Motorola S-Record as well.
+
+	Add a few more part-specific parameters to the avrpart structure.
+
+	Only write the flash or eeprom if the data to be written is not 0xff.
+
+2000-12-31  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrprog.c: Update a comment.
+
+	* avrprog.c:
+	Provide the ability to tie additionally tie pins 6-9 of the parallel
+	port to Vcc in order to supply more current.
+
+	Fix a typo on the size of the S1200's Flash.
+
+	Bring RESET low when programming is completed.
+
+	* avrprog.c:
+	Correct pin connection comments.  Elaborate a bit on Vcc connection.
+
+	* avrprog.c:
+	Update after receiving some good feedback from Joerg Wunsch.  We
+	should now be able to program AT90S1200's.
+
+2000-12-30  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrprog.c: Don't limit eeprom addresses.
+
+2000-12-20  Brian S. Dean  <bsd@bsdhome.com>
+
+	* Makefile, avrprog.c:
+	Add support for the 8515.  Make the addition for other devices easier.
+
+2000-08-27  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrprog.c:
+	Clear all bits except AVR_RESET when finished reading or programming
+	the Atmel device.
+
+2000-08-07  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrprog.c: update announcement message
+
+	* avrprog.c: Update announcement message.
+
+	* avrprog.c: Return the correct return code from 'main()'.
+
+	* avrprog.c:
+	Add ppi_pulse() function and fix ppi_toggle() to actully toggle
+	instead of pulse.
+
+	Make all abnormal returns after the parallel port has been opened go
+	through a single exit point at the bottom of 'main()'.
+
+2000-08-06  Brian S. Dean  <bsd@bsdhome.com>
+
+	* Makefile, avrprog.c: Makefile: add --pedantic compiler option
+
+	avrprog.c:
+
+		Add lots of comments, move getop() variable declarations to
+		the top of the program.
+
+		Add a typedef name to the AVR memory type and use it for
+		function declarations.
+
+		Add a usleep() delay in the sense loop to avoid becoming a cpu
+		hog.
+
+		Print out a version string so that folks know what version of
+		the software they are running.
+
+		Be sure and close the parallel device and the i/o file when
+		terminating abnormally.
+
+	* avrprog.c: Print out version information when invoked.
+
+	* Makefile, avrprog.c: Makefile: Add an install target.
+
+	avrprog.c:
+
+	  Add license.
+
+	  Document the header a bit better.
+
+	  Add capability to read out and display the device signature bytes.
+
+	  Add capability to power the device from the parallel port.
+
+	  Eliminate debug print facility.
+
+	  Provide 'avr_cmd()' function.
+
+	  When memory locations don't program, generate a newline so that the
+	  information is not overwritten and lost.
+
+	  Don't print out the message about needing to specify a file if the
+	  user is not requesting an operation that requires the file.
+
+2000-08-05  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrprog.c: Pring usage when no arguments are supplied.
+
+	* Makefile, avrprog.c: Initial check-in
+
+	* Makefile, avrprog.c: New file.
+
diff --git a/avrdude/ChangeLog-2002 b/avrdude/ChangeLog-2002
new file mode 100644
index 00000000..9bfa030a
--- /dev/null
+++ b/avrdude/ChangeLog-2002
@@ -0,0 +1,237 @@
+2002-12-12  Brian S. Dean  <bsd@bsdhome.com>
+
+	* main.c: minor cleanup
+
+2002-12-07  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrdude.1, main.c:
+	If the stk500 is being used, default to using the first serial port.
+
+2002-12-03  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrdude.1: Mention STK500 support.
+
+2002-12-01  Brian S. Dean  <bsd@bsdhome.com>
+
+	* stk500.c: Remove unused code.
+
+	* CHANGELOG, stk500.c:
+	Document changes since the previous version in the CHANGELOG.
+
+	Cleanup stk500.c a bit.
+
+	* stk500.c: Fix cut and paste braino.
+
+	* avr.c, avrdude.conf.sample, main.c, pgm.h, stk500.c:
+	The STK500 can perform paged read/write operations even on standard
+	"non-paged" parts.  Take advantage of that and use the faster internal
+	routines of the STK500 for those parts as well.
+
+	* avr.c, avr.h, avrpart.h, main.c, pgm.c, pgm.h, stk500.c:
+	Optimize reading and writing for the STK500 programmer if the part
+	supports paged reads and writes.  This greatly decreases the
+	program/verify time from about 4.5 minutes down to about 10 seconds in
+	a 12K program size test case.
+
+	Print out the hardware and firmware version for the STK500 if verbose
+	is enabled.
+
+	* avrdude.conf.sample, avrpart.h, config_gram.y, lexer.l, pgm.h:
+	* ppi.c, ppi.h, stk500.c, stk500.h, stk500_private.h:
+	Add basic support for STK500.
+
+2002-11-30  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrdude.conf.sample, config.c, config.h, config_gram.y, lexer.l:
+	* main.c, pgm.c, pgm.h, ppi.c, ppi.h, term.c, term.h, Makefile:
+	* avr.c, avr.h:
+	Seperate programmer operations out into a driver-like interface so
+	that programmers other than the direct parallel port connection can be
+	supported.
+
+2002-11-23  Brian S. Dean  <bsd@bsdhome.com>
+
+	* CHANGELOG, main.c, term.c:
+	term.c - when in interactive terminal mode and dumping memory using
+	         the 'dump <memtype>' command without any address information,
+	         and the end of memory is reached, wrap back around to zero on
+	         the next invocation.
+
+	CHANGELOG - describe changes
+
+	main.c - update version number
+
+	* main.c:
+	When getting ready to initiate communications with the AVR device,
+	first pull /RESET low for a short period of time before enabling the
+	buffer chip.  This sequence allows the AVR to be reset before the
+	buffer is enabled to avoid a short period of time where the AVR may be
+	driving the programming lines at the same time the programmer tries
+	to.  Of course, if a buffer is being used, then the /RESET line from
+	the programmer needs to be directly connected to the AVR /RESET line
+	and not via the buffer chip.
+
+2002-11-06  Brian S. Dean  <bsd@bsdhome.com>
+
+	* CHANGELOG: Update changelog.
+
+	* avr.c, avr.h, main.c: Fix -Y option.  Reported by Joerg Wunsch.
+
+2002-11-01  Brian S. Dean  <bsd@bsdhome.com>
+
+	* CHANGELOG, main.c: Version update and CHANGELOG entry.
+
+	* avr.c:
+	Be backward compatible with the 2-byte rewrite cycle counter which
+	appeared in version 2.1.0, but was changed to a 4 byte counter in
+	version 2.1.1.  Reminded by Joerg Wunsch.
+
+2002-10-29  Brian S. Dean  <bsd@bsdhome.com>
+
+	* CHANGELOG, avrdude.1, main.c:
+	Add '-V' (no verify) flag requested by Joerg Wunsch.  Update the man
+	page.
+
+2002-10-13  Brian S. Dean  <bsd@bsdhome.com>
+
+	* CHANGELOG, avrdude.1: Update man page and changelog.
+
+	* main.c: Update version number.
+
+2002-10-12  Brian S. Dean  <bsd@bsdhome.com>
+
+	* Makefile: Remove --pedantic and -g from the compiler options.
+
+2002-10-11  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avr.c, term.c:
+	Use a four byte value instead of a two byte value for the programming
+	cycle count stored at the end of EEPROM.  It seems as though Atmel was
+	greatly conservative in claiming a 1000 count reliability for the
+	FLASH.  I current have a part that has been reprogrammed 173330 times,
+	and counting.
+
+	Fix a compiler warning.
+
+	* avrdude.conf.sample:
+	Fix ATMega128 instruction encoding for reading the low and high fuse
+	bits.  Thanks to Joerg Wunsch for tripping over this.
+
+2002-08-01  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avr.c, avrdude.1, main.c:
+	Move erase-rewrite cycle increment to within the chip erase routine so
+	that it is tracked no matter where the erase was initiated: command
+	line mode or interactive mode, without code duplicaiton.
+
+	* CHANGELOG: Recent updates.
+
+	* avr.c: Eliminate unused variables.
+
+	* avr.c, avr.h, avrdude.1, fileio.c, main.c:
+	Implement a way of tracking how many erase-rewrite cycles a part has
+	undergone.  This utilizes the last two bytes of EEPROM to maintain a
+	counter that is incremented each time the part is erased.
+
+2002-07-27  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avr.c, main.c:
+	Fix a typo in a comment.  Display the size of memory being written.
+	Display the correct memory name in an error message (previously
+	hardcoded).
+
+2002-06-22  Brian S. Dean  <bsd@bsdhome.com>
+
+	* CHANGELOG, avrdude.conf.sample:
+	Add support for ATtiny15 - contributed by Asher Hoskins
+	<asher@crumbly.freeserve.co.uk>
+
+2002-04-23  Brian S. Dean  <bsd@bsdhome.com>
+
+	* CHANGELOG: Say what changed.
+
+2002-04-07  Brian S. Dean  <bsd@bsdhome.com>
+
+	* Makefile, avrdude.conf.sample:
+	Backup the config file to a timestamped name to keep from possibly
+	overwriting user-modified configs.
+
+	Add read/write instructions for all memory types for ATMEGA103,
+	ATMEGA128, ATMEGA16, and ATMEGA8.
+
+2002-04-05  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrdude.conf.sample:
+	Add support for ATMEGA128; untested; requested by Jeff Gardner
+	<gardner@journey.com>.
+
+2002-02-15  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrdude.conf.sample: Minor ordering.
+
+	* CHANGELOG, main.c: Update version numbers.
+
+2002-02-14  Brian S. Dean  <bsd@bsdhome.com>
+
+	* CHANGELOG: Summarize latest updates.
+
+	* avrdude.conf.sample, config_gram.y:
+	Make pwroff_after_write a yes/no field instead of a numeric.
+
+	* avrdude.conf.sample: Document the pwroff_after_write flag.
+
+	* avr.c: Enable the extra part verbosity when verbosity >= 3.
+
+	* avr.c, avr.h, avrdude.conf.sample, config_gram.y, lexer.l:
+	* main.c, term.c:
+	Fix error reporting by avr_write_byte().
+
+	Fix setting of status LEDs under various write-fail conditions.
+
+	Add a flag to indicate that a memory type requires the device to
+	possibly be powered off and back on after a write to it.  This is due
+	to a hardware problem on some Atmel devices, see:
+
+		http://www.atmel.com/atmel/acrobat/doc1280.pdf
+
+	Add greater verbosity to the part-display code when verbose>1 to
+	display avrprog's encoding of the defined programming instructions.
+	This is primarily for debugging purposes.
+
+
+	Part updates:
+
+	  * add the AT90S4414 part
+
+	  * add fuse and lock bit access instructions for the AT90S1200,
+	    AT90S4434, and AT90S8515.
+
+	  * add the pwroff_after_write flag to the fuse bits for the AT90S2333
+	    and AT90S4433 parts
+
+2002-02-09  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrdude.conf.sample:
+	Updates to the 2333 and 4433 parts, contributed by Joerg Wunsh.
+
+2002-01-18  Brian S. Dean  <bsd@bsdhome.com>
+
+	* CHANGELOG: Add changelog.
+
+2002-01-12  Brian S. Dean  <bsd@bsdhome.com>
+
+	* main.c: Add (c) to copyright.
+
+	* fileio.c, fileio.h, lexer.l, lists.c, lists.h, main.c:
+	* pindefs.h, ppi.c, ppi.h, term.c, term.h, avr.c, avr.h:
+	* config.c, config.h, config_gram.y:
+	Update version number.  Update copyright.
+
+	* avrdude.1: Update copyright and add description of "default".
+
+	Submitted by: Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avr.c, term.c:
+	Fix programming of write-only memories (such as lock bits on the
+	2313).
+
diff --git a/avrdude/ChangeLog-2003 b/avrdude/ChangeLog-2003
new file mode 100644
index 00000000..1115bdfb
--- /dev/null
+++ b/avrdude/ChangeLog-2003
@@ -0,0 +1,1095 @@
+2003-12-01  Eric B. Weddington  <eric@ecentral.com>
+
+	* doc/avrdude.texi: Update devices and programmers supported.
+
+2003-12-01  Eric B. Weddington  <eric@ecentral.com>
+
+	* doc/avrdude.texi: Add missing -D option to user manual.
+	[This fixes bug #6804]
+
+2003-11-30  Jan-Hinnerk Reichert  <hinni@despammed.com>
+
+	* avrpart.c,main.c: Moved list_parts() and locate_part()
+	from main.c to avrpart.c.
+	* avrpart.h: Added prototypes for list_parts() and
+	locate_part().
+
+2003-11-30  Jan-Hinnerk Reichert  <hinni@despammed.com>
+
+	* avrpart.c, avr.c: Moved elementary functions on types
+	OPCODE, AVRMEM and AVRPART from avr.c to new file avrpart.c.
+	* avr.h: Removed prototypes for moved functions.
+	* avrpart.h: Added prototypes for functions in avrpart.c.
+	* Makefile.am: Added new file avrpart.c.
+
+2003-11-28  Michael Mayer  <michael-mayer@gmx.de>
+
+	* lexer.l: New programmer type "butterfly".
+	* config_gram.y: New token K_BUTTERFLY.
+	* avrdude.conf.in: Added programmer definition.
+	* butterfly.c, butterfly.h: Cloned from avr910.?, changed to work
+	with the Atmel Butterfly device.
+	* Makefile.am: Added butterfly.[ch] to avrdude_SOURCES.
+
+2003-11-26  Joerg Wunsch  <j@uriah.heep.sax.de>
+
+	* main.c: Make the -U parser tolerate colons in filenames.
+	* avrdude.1, doc/avrdude.texi: Document the -U changes.
+
+2003-11-21  Jan-Hinnerk Reichert  <hinni@despammed.com>
+
+	* ppi.c: Major speed tuning. Since ioctl() is expensive read from
+	shadowregisters where possible.
+
+2003-11-19  Eric B. Weddington  <eric@ecentral.com>
+
+	* NEWS: Update news from items in ChangeLog.
+
+2003-11-19  Theodore A. Roth  <troth@openavr.org>
+[Contributed by Jan-Hinnerk Reichert <jan-hinnerk_reichert@hamburg.de>]
+
+	* avr.c (avr_write_byte_default): Improve polling algorithm to speed up
+	programming of byte oriented parallel programmers.
+
+2003-11-14  Brian S. Dean  <bsd@bsdhome.com>
+[Contributed by Erik Christiansen <erik@dd.nec.com.au>]
+
+	* avrdude.conf.in:
+	Add ATmega64 part.
+
+2003-11-08  Joerg Wunsch  <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in:
+	Add "fuse" and "lock" definitions for the AT90S8535.  Actually,
+	this is stolen from the AT90S8515 since the datasheet says it's
+	the same there.
+
+2003-10-13  Bill Somerville  <bill@classdesign.com>
+
+	* stk500.c (stk500_paged_write): Limit blocks written to no bigger
+	than memory device size.
+	(stk500_paged_write): Send whole block at once.
+	(stk500_paged_load): Limit blocks read to no bigger than memory
+	device size.
+	[This fixes bug #5713.]
+
+2003-10-13  Eric B. Weddington  <eric@ecentral.com>
+
+	* avrdude.conf.in: Fix for unterminated character error.
+
+2003-10-13  Eric B. Weddington  <eric@ecentral.com>
+
+	* avrdude.conf.in: Add ATmega8515 definition.
+	Contributed by: Matthias Wei�er <matthias@matwei.de>
+	* NEWS: Add note about ATmega8515 definition.
+
+2003-09-24  Eric B. Weddington  <eric@ecentral.com>
+
+	* doc/TODO: Updated TODO list.
+
+2003-09-22  Eric B. Weddington  <eric@ecentral.com>
+
+	* windows/Makefile.am: Correct makefile so loaddrv does not link
+	to Cygwin DLL.
+
+2003-09-18  Eric B. Weddington  <eric@ecentral.com>
+
+	* doc/avrdude.texi: Minor corrections. Change description of -P
+	to reference platform dependencies.
+
+2003-09-16  Eric B. Weddington  <eric@ecentral.com>
+
+	* stk500.c: If writing flash, skip empty pages in paged write.
+
+2003-09-06  Theodore A. Roth  <troth@openavr.org>
+
+	* NEWS: Add 'Current:' header.
+	* configure.ac (AC_INIT): Add cvs back to version since we're
+	back in dev cycle (post release).
+
+2003-09-06  Theodore A. Roth  <troth@openavr.org>
+
+	* AVRDUDE 4.2.0 has been released (cvs release tag is "release_4_2_0").
+
+2003-09-06  Theodore A. Roth  <troth@openavr.org>
+
+	* NEWS: Update for 4.2.0 release. Add note about read/write of fuses
+	support for avr910.
+	* configure.ac (AC_INIT): Set version to 4.2.0.
+
+2003-09-05  Theodore A. Roth  <troth@openavr.org>
+[Contributed by Jan-Hinnerk Reichert <jan-hinnerk_reichert@hamburg.de>]
+
+	* avr.c (avr_read_byte): If pgm->read_byte method fails, retry with
+	avr_read_byte_default.
+	* avr.c (avr_write_byte): If pgm->write_byte method fails, retry with
+	avr_write_byte_default.
+	* avr910.c (avr910_cmd): Implement using universal command.
+
+2003-09-04  Theodore A. Roth  <troth@openavr.org>
+
+	* Makefile.am: Change AM_CPPFLAGS to avrdude_CPPFLAGS.
+	Define avrdude_CFLAGS.
+	* configure.ac: Set ENABLE_WARNINGS to "-Wall" if using gcc.
+
+2003-09-02  Eric B. Weddington <eric@ecentral.com>
+
+	* doc/avrdude.texi: Add note about privileges needed to load 
+	the giveio driver for Windows.
+
+2003-08-29  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrdude.1:
+	* main.c:
+	Perform an auto erase before programming if the flash memory is
+	anywhere specified to be written by any of the -U requests.
+
+	To remain backward compatible with previous versions, disable this
+	feature if any of the old-style memory specification operations are
+	specified (-i, -o).
+
+	Implement the -D option to explicitly disable the auto erase default.
+
+	Deprecate the old-style memory specification options (-f, -i, -I, -m,
+	and -o) in favor of the new -U option which allows one to operate on
+	multiple memories on a single command line.
+
+2003-08-28  Eric B. Weddington  <eric@ecentral.com>
+
+	* avr910.c:
+	* fileio.c:
+	* main.c:
+	* stk500.c:
+	More code cleanup to remove warnings.
+
+2003-08-27  Theodore A. Roth  <troth@openavr.org>
+
+	* main.c (update_progress_no_tty): Properly terminate progress. Also
+	fixes stk500 problem where number of bytes written is less than a page.
+
+2003-08-27  Theodore A. Roth  <troth@openavr.org>
+
+	* avrdude.spec.in: Fix broken rpmbuild on RedHat-9.
+
+2003-08-25  Eric B. Weddington  <eric@ecentral.com>
+
+	* fileio.c: 
+	* main.c: 
+	* ppiwin.c:
+	* ser_posix.c:
+	* stk500.c:
+	Minor code cleanup to remove warnings.
+
+2003-08-21  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrdude.1:
+	* main.c:
+
+	Introduce a new option, -U, for performing memory operions.
+	Its argument is a 4 field string (fields seperated by colons)
+	which indicate what memory type to operate on, what operation
+	to perform is (read, write, or verify), the filename to read
+	from, write to, or verify against, and an optional file format
+	field.  Multple -U options can be specified to operate on more
+	than one memory at a time with a single invocation.  For
+	example, to update both the flash and the eeprom at the same
+	time one can now specify the following:
+
+	avrdude -p -e -U flash:w:main.hex:i -U eeprom:w:eeprom.hex:i
+
+2003-08-20  Brian S. Dean  <bsd@bsdhome.com>
+
+	* ppiwin.c:
+	Timing related fixes for the Windows platform.  Several folks have
+	reported that this patch fixes verify errors on the Windows platform
+	that are apparently timing related.  Submitted by: Alex Shepherd
+	<ashepherd@wave.co.nz>, who indicates that this patch was based on
+	code from the UISP project.
+
+2003-08-01  Theodore A. Roth  <troth@openavr.org>
+
+	* avrdude.1: Document the -q option.
+	* doc/avrdude.texi: Document the -q option.
+	Fix some typos left over from pasting in man output.
+
+2003-07-30  Brian S. Dean  <bsd@bsdhome.com>
+
+	* main.c: Add elapsed time information to the new progress bar.
+
+2003-07-29  Theodore A. Roth  <troth@openavr.org>
+
+	* avr.c:
+	* avr.h:
+	* avr910.c:
+	* main.c:
+	* stk500.c:
+	New progress reporting implementation.
+
+2003-07-24  Joerg Wunsch  <j@uriah.heep.sax.de>
+
+	* avrdude.1:
+	* doc/avrdude.texi:
+	* pgm.c:
+	* pgm.h:
+	* stk500.c:
+	* stk500_private.h:
+	* term.c: Add support for displaying and setting the various
+	operational parameters of the STK500 (Vtarget, Varef, clock).
+
+2003/07/22  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrdude.conf.in:
+	  Add 'picoweb' programming cable programmer.
+	  Contributed by Rune Christensen <rune.christensen@adslhome.dk>.
+
+2003-06-18  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrdude.conf.in:
+	Add the 'sp12' (Steve Bolt's) programmer.
+	Submitted by Larry Barello <larryba@barello.net>.
+
+2003-06-17  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrdude.conf.in:
+	Properly identify the "ALF" programmer.
+	
+	Extend ATmega8 calibration memory to support all 4 calibration bytes.
+	Savannah bug #3835.  Submitted by Francisco T. A. Silva
+	<ftas@geodigitus.com.br>.
+	
+	Add a few AVR910 programmer device codes.  Savannah bug #3569 - sorry
+	I can't tell who submitted this to give proper credit.
+	
+	Add support for the ATtiny12.  Submitted by Pontifex <pontifex@isys.ca>
+
+2003-05-22  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avr.c:
+	* avr.h:
+	* fileio.c:
+	Optimize flash memory handling a little bit by ignoring 0xff data that
+	resides above the last non-0xff data value in the address space.  Only
+	do this for flash memory since writing a 0xff to flash is a no-op.
+	This has the affect of creating smaller output files when dumping
+	memory contents from flash if the program in flash does not consume
+	the whole memory space.  It also results in shorter programming times
+	when avrdude is asked to load a file into flash that has lots of 0xff
+	filled data past the last non-0xff data value.
+
+2003-05-13  Theodore A. Roth  <troth@openavr.org>
+
+	* avr910.c (avr910_paged_write_flash): Add code to send the 'm'
+	command ("issue page write" cmd) for each page.
+
+2003-05-13  Theodore A. Roth  <troth@openavr.org>
+
+	* avrdude.conf.in: Add pagel and bs2 entries for at90s1200 device.
+
+2003-05-13  Theodore A. Roth  <troth@openavr.org>
+
+	* doc/TODO: Add note about avr910 device codes.
+
+2003-05-04  Theodore A. Roth  <troth@openavr.org>
+
+	* configure.ac: Check for ncurses library (since it can be a
+	replacement for termcap).
+
+2003-05-02  Theodore A. Roth  <troth@openavr.org>
+
+	* avrdude.conf.in: Add avr decodes for devices known in avr910
+	firmware version 2.3.
+	Add missing stk500 devocde for 2343.
+
+2003-04-23  Eric B. Weddington  <eric@ecentral.com>
+
+	* fileio.c: Fix for bug #3293. Set correct open mode for raw format
+	for Windows.
+
+2003-04-19  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrdude.1:
+	* fileio.c:
+	* fileio.h:
+	* main.c:
+	Implement and "immediate mode" for file input - this allows
+	one to specify byte values on the command line instead of via
+	a file.  This can be good for specifying fuse bytes and
+	eliminates the need to create single-byte files or using
+	interactive terminal mode for these single-byte memories.
+	Requested by several folks on the mailing list.
+
+2003-04-18  Theodore A. Roth  <troth@openavr.org>
+
+	* configure.ac: Add cvs suffix back to version.
+	* doc/TODO: Add a few items.
+
+2003-04-18  Theodore A. Roth  <troth@openavr.org>
+
+	* AVRDUDE 4.1.0 has been released (cvs release tag is "release_4_1_0").
+
+2003-04-17  Theodore A. Roth  <troth@openavr.org>
+
+	* configure.ac: Set version to 4.1.0.
+	* doc/avrdude.texi: Add note about avr910 programmer type.
+
+2003-04-17  Eric B. Weddington  <eric@ecentral.com>
+
+	* NEWS: Replace TBD with new release version.
+
+2003-04-17  Eric B. Weddington  <eric@ecentral.com>
+
+	* avrdude.conf.in: Change name of pony programmer to pony-stk200
+	to better describe the hardware (PonyProg is software that works
+	with various hardware).
+
+2003-04-16  Eric B. Weddington  <eric@ecentral.com>
+
+	* avrdude.conf.in: Add support for ATtiny26
+	Submitted by Artur Lipowski <LAL@pro.onet.pl>
+	* NEWS: List new devices supported: ATtiny26
+
+2003-04-16  Eric B. Weddington <eric@ecentral.com>
+
+	* avrdude.conf.in: Add support for ATmega8535
+	Submitted by Alexander Peter <apeter@gmx.de>
+	* NEWS: List new devices supported: ATmega8535
+
+2003-04-09  Theodore A. Roth  <troth@openavr.org>
+
+	* avr910.c: Reading a 16 bit word in paged load needs to swap the
+	bytes since the 'R' command returns MSB first and the internal buffer
+	stores LSB first.
+
+2003-04-07  Theodore A. Roth  <troth@openavr.org>
+
+	* stk500.c: Don't print out read/write byte progress unless the verbose
+	option is given.
+
+2003-04-05  Theodore A. Roth  <troth@openavr.org>
+
+	* avr910.c: Re-add the avr910 byte read/write methods which were 
+	removed in my previous patch. Terminal mode read/writes are broken
+	without those methods. D'oh!
+
+2003-04-05  Theodore A. Roth  <troth@openavr.org>
+
+	* avr910.c: Refactor to allow probing for auto addr increment. If auto
+	incr supported by programmer hw, don't send addr for every byte.
+
+2003-04-03  Eric B. Weddington <eric@ecentral.com>
+	
+	* confwin.c: Fix bug that allows garbage for non-existent user
+	config filename on Windows.
+
+2003-03-29  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrdude.conf.in:
+	Add the ATmega32 part.  This part definition was contributed by:
+	Daniel Williamson <dannyw@maconmgt.co.uk> and
+	Ruwan Jayanetti <rjayanetti@sri.crossvue.com>	  
+	The resulting part definition used was actually somewhat of a merge of
+	the two submitted definitions.
+
+2003-03-24  Theodore A. Roth  <troth@openavr.org>
+
+	* NEWS: Add note about avr910 support.
+
+2003-03-23  Theodore A. Roth  <troth@openavr.org>
+
+	* avr.c (avr_write): Add call to pgm->write_setup() before the write
+	loop.
+	* avr910.c: Change all show_func_info() calls to no_show_func_info().
+	Add read/write to/from flash/eeprom memory functionality.
+	* pgm.c: Initialize pgm->write_setup.
+	* pgm.h: Add write_setup field to PROGRAMMER structure.
+	* ser_posix.c: Remove unneeded cast in verbosity code.
+
+2003-03-23  Theodore A. Roth  <troth@openavr.org>
+
+	* ser_posix.c: Limit verbose output to 2 chars.
+
+2003-03-23  Theodore A. Roth  <troth@openavr.org>
+
+	* ser_posix.c: Add verbose level > 3 output for send and recv functions.
+
+2003-03-23  Theodore A. Roth  <troth@openavr.org>
+
+	* avr.c: Add avr_read_byte_default().
+	Have avr_read_byte() call pgm->read_byte() or avr_read_byte_default().
+	Add avr_write_byte_default().
+	Have avr_write_byte() call pgm->write_byte or avr_write_byte_default().
+	* pgm.c: Initialize pgm->write_byte and pgm->read_byte.
+	* pgm.h: Add write_byte and read_byte fields to struct programmer_t.
+
+2003-03-17  Theodore A. Roth  <troth@openavr.org>
+
+	* avrdude.conf.in: Fix typo for devicecode deprecation comment.
+
+2003-03-17  Eric B. Weddington  <eric@ecentral.com>
+
+	* avrdude.conf.in: Add Bascom SAMPLE programmer. 
+	Submitted by Larry Barello <larryba@barrello.net>
+
+2003-03-16  Theodore A. Roth  <troth@openavr.org>
+
+	* avr.c (avr_read): Use pgm->read_sig_bytes to read signature bytes if
+	available.
+	* avr910.c (avr910_vfy_cmd_sent): New function.
+	(avr910_chip_erase): Add support for chip erase.
+	(avr910_enter_prog_mode): New function.
+	(avr910_leave_prog_mode): New function.
+	(avr910_initialize): Add code to select device type and enter prog mode.
+	(avr910_close): Leave programming mode before closing serial port.
+	(avr910_read_sig_bytes): New function.
+	(avr910_initpgm): Add avr910_read_sig_bytes method to pgm initializer.
+	* avrdude.conf.in: Add note about deprecating devicecode.
+	Change all occurences of devicecode to stk500_devcode.
+	Add avr910_devcode to a few parts for testing.
+	* avrpart.h (struct avrpart): Change devicecode field to stk500_devcode.
+	(struct avrpart): Add avr910_devcode field.
+	* config_gram.y: Add K_STK500_DEVCODE and K_AVR910_DEVCODE tokens.
+	Generate an error if devicecode is found in the config file.
+	Handle parsing of avr910_devcode and stk500_devcode.
+	* lexer.l: Handle parsing of avr910_devcode and stk500_devcode.
+	* pgm.c: Initialize pgm->read_sig_bytes field.
+	* pgm.h: Add pgm->read_sig_bytes field.
+	* stk500.c: Use stk500_devcode instead of devicecode.
+
+2003-03-16  Theodore A. Roth  <troth@openavr.org>
+
+	* avrdude.conf.in: Add avr910 and pavr programmers.
+	* config_gram.y: Add parsing of avr910 programmer.
+	* lexer.l: Add avr910 token.
+	* avr910.c: [this is still work in progress]
+	Add some debug output.
+	Add probe for programmer presense.
+	* main.c: Set port to default_serial if programmer type is avr910.
+
+2003-03-13  Theodore A. Roth  <troth@openavr.org>
+
+	* ser_posix.c, ser_win32.c, serial.h:
+	Change baud from int to long to avoid a 16-bit int overflow.
+
+2003-03-12  Theodore A. Roth  <troth@openavr.org>
+
+	* Makefile.am (avrdude_SOURCES): Add avr910.[ch], serial.h and
+	ser_posix.c files.
+	* avr910.c: New file (stubs for avr910 serial programmer).
+	* avr910.h: New file.
+	* ser_posix.c: New file.
+	* ser_win32.c: New file (just stubs for now).
+	* serial.h: New file.
+	* stk500.c: Move all the code for accessing the posix serial ports
+	into ser_posix. This will make a native win32 port easier and allows
+	the avr910 programmer to share the serial code.
+
+2003-03-12  Theodore A. Roth  <troth@openavr.org>
+
+	* configure.ac (AC_INIT): Set version to 4.0.0cvs since we're done
+	with 4.0.0 release.
+
+2003-03-12
+
+	* AVRDUDE 4.0.0 has been released (cvs release tag is "release_4_0_0").
+
+2003-03-11  Theodore A. Roth  <troth@openavr.org>
+
+	* Makefile.am: Add CLEANFILES to remove all files from a make.
+	* doc/Makefile.am: Ditto
+
+2003-03-11  Theodore A. Roth  <troth@openavr.org>
+
+	* windows/Makefile.am: Fix uninstall-local rule (forget the $$file
+	part of the rm command).
+
+2003-03-11  Theodore A. Roth  <troth@openavr.org>
+
+	* AUTHORS: Updated.
+	* CHANGELOG: Move contents to NEWS and remove file.
+	* ChangeLog: All of the changes for this year.
+	* ChangeLog-2001: All 2001 changes.
+	* ChangeLog-2002: All 2002 changes.
+	* Makefile.am (EXTRA_DIST): Remove CHANGELOG and and Change-200[12].
+	* NEWS: Moved contents of CHANGELOG file here.
+	* README: Add note pointing to savannah site.
+
+2003-03-11  Eric Weddington <eric@ecentral.com>
+
+	* doc/avrdude.texi:
+	Add Install and Documentation sections for Windows. Fix typo.
+
+2003-03-10  Theodore A. Roth  <troth@openavr.org>
+
+	* Makefile.am: * Makefile.am (EXTRA_DIST): Add CHANGELOG.
+
+2003-03-10  Brian S. Dean  <bsd@bsdhome.com>
+
+	* stk500.c: Disable debugging printf.
+
+	* configure.ac: Update version number in preparation for release.
+
+2003-03-10  Theodore A. Roth  <troth@openavr.org>
+
+	* doc/avrdude.texi:
+	Add comment before each node to make them stand out better.
+	Use @option{} command for options instead of @code{}.
+	Merge FreeBSD and Linux platform dependent information.
+
+2003-03-10  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrdude.1: Minor man page updates to better reflect reality.
+
+2003-03-10  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* bootstrap:
+	Export all the AUTO* variables.  Hopefully, that way the generated
+	Makefile might get them correctly.
+
+	* bootstrap:
+	Export ${AUTOCONF} so automake will find it by whatever name it will be
+	called today.
+
+2003-03-06  Eric Weddington <eric@ecentral.com>
+
+	* doc/avrdude.texi:
+	Add notes about ability to list parts and list programmers in the
+	config file in -p and -c descriptions. Change info about where to
+	find Windows search method in -C description.
+
+	* main.c:
+	Change software version from hardcoded value to getting it from
+	the configuration.
+
+2003-03-06  Theodore A. Roth  <troth@openavr.org>
+
+	* avrdude.spec.in: * avrdude.spec.in: Add docs sub-package.
+	Add %post and %preun scriptlets for handling info files.
+
+	* configure.ac, doc/Makefile.am:
+	* configure.ac: Add --enable-versioned-doc option and set DOC_INST_DIR.
+	* doc/Makefile.am: Add rules to install docs in DOC_INST_DIR.
+
+	* doc/Makefile.am:
+	Delete the lines which where commented out in previous commit.
+
+	* configure.ac, doc/Makefile.am:
+	* configure.ac: Remove hack to make work with automake-1.5.
+	* doc/Makefile.am: Remove extra rules that were needed to work with
+		automake-1.5.
+
+	* bootstrap:
+	* bootstrap: Force use of autoconf-2.57 and automake-1.7.x.
+
+2003-03-05  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Add a definition for the popular Ponyprog dongle.
+
+	Submitted by:	Daniel Williamson <dannyw@maconmgt.co.uk>
+
+2003-03-05  Brian S. Dean  <bsd@bsdhome.com>
+
+	* main.c:
+	Check the programmer type against 'STK500' instead of the programmer
+	name when checking to see if we should default to the default_serial
+	port instead of the default_parallel port.  This has us do the right
+	thing for the new 'avrisp' programmer.
+
+	* stk500.c:
+	Make the page size used for non-paged parts for the 'paged_write'
+	command be 128 bytes.  This cuts 6 seconds off the programming time
+	for uploading a 6K file into an AT90S8515 vs the time loading the same
+	file using a 16 byte buffer, and the response feedback is still good.
+
+	* avr.c, stk500.c:
+	Fix stk500 page write (Program Page command).  This is supported after
+	all on non-paged-memory parts.  The problem was that the page size was
+	defaulting to 256 (maximum for the stk500), but the timeout for a
+	response from the stk500 before declaring it dead was only 0.5
+	seconds.  But it takes much longer than 0.5 seconds to program 256
+	bytes, so we just weren't waiting long enough.
+
+	Fix this in two ways - increase the timeout to 5 seconds, and decrease
+	the page size to 16 bytes for non-paged parts.  The programming time
+	for 16 bytes is short enough to provide the user with some feedback
+	that something is happening.
+
+	* avr.c, stk500.c:
+	Don't call the programmer's 'paged_write' routine unless the memory
+	itself is paged as it doesn't appear to work otherwise.
+
+	* avrdude.conf.in: Fix device codes for at90s8515 and at90s8535.
+
+	* avrdude.conf.in:
+	Add PAGEL and BS2 parms for parts I have datasheets for.
+
+	* config_gram.y:
+	Do that last commit slightly differently - this way results in no
+	shift-reduce conflicts.
+
+	* config_gram.y:
+	It shouldn't be an error to have an empty configuration file.  This
+	causes some shift-reduce conflicts, but I think they are OK.
+
+	* main.c:
+	Print out a list of valid parts for '-p ?' and a list of valid
+	programmers for '-c ?'.
+
+2003-03-04  Eric Weddington <eric@ecentral.com>
+
+	* doc/avrdude.texi: Minor Windows doc corrections.
+
+	* doc/TODO: Add TODO file.
+
+	* avrdude.conf.in: Add AVR ISP programmer.
+
+2003-03-04  Brian S. Dean  <bsd@bsdhome.com>
+
+	* stk500.c:
+	Don't try to set extended device programming parameters if they
+	haven't been specified in the config file for the part.
+
+	* stk500.c: Set extended device parameters for all firmware versions.
+
+	* stk500.c:
+	First attempt at supporting STK500 firmware past 1.10.  Thanks to
+	Jason Kyle for the needed protocol information.
+
+2003-03-03  Theodore A. Roth  <troth@openavr.org>
+
+	* doc/Makefile.am:
+	* doc/Makefile.am: Add ps and pdf rules since they aren't supplied by
+	automake versions prior to 1.7.
+
+	* doc/avrdude.texi:
+	* doc/avrdude.texi: Add node and menu information for the info system.
+
+	* Makefile.am, configure.ac, doc/Makefile.am, doc/avrdude.texi:
+	* Makefile.am (SUBDIRS): Add doc dir.
+	* configure.ac (AC_CONFIG_FILES): Add doc/Makefile.
+	* doc/Makefile.am: New file.
+	* doc/avrdude.texi: Use automatically generated version.texi.
+
+2003-03-02  Brian S. Dean  <bsd@bsdhome.com>
+
+	* doc/avrdude.texi: Initial manual.
+
+2003-02-27  Theodore A. Roth  <troth@openavr.org>
+
+	* term.c: * term.c: Use fgets() if readline() is not available.
+
+2003-02-27  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* bootstrap:
+	Oops, accidentally spammed the repository with my private version of
+	"bootstrap".  Back out that change.
+
+	* bootstrap, lexer.l:
+	Ignore \r as white space, to make the Windows people happy.
+
+2003-02-27  Theodore A. Roth  <troth@openavr.org>
+
+	* Makefile.am (EXTRA_DIST): Add avrdude.spec and make entries one
+	per line so future patches are obvious as to what changed.
+	* avrdude.spec.in: New file to support creation of binaries in rpm
+	format.
+	* configure.ac (AC_OUTPUT): Add avrdude.spec.  Reorder so that
+	Makefile is the last entry.
+
+2003-02-26  Theodore A. Roth  <troth@openavr.org>
+
+	* Makefile.am (SUBDIRS): Add windows dir.
+	* configure.ac: If $target is a windows system, build whats in
+	windows sub dir.
+	* windows/Makefile.am: New file.
+
+2003-02-25  Theodore A. Roth  <troth@openavr.org>
+
+	* ChangeLog: Point reader to the CHANGELOG file.
+	* Makefile.am (EXTRA_DIST): Rename avrdude.conf.sample to
+	avrdude.conf.in.
+	Remove avrdude.conf and distclean-local rules.
+	Add install-exec-local and backup-avrdude-conf rules.
+	* avrdude.conf.in:
+	Set default_parallel to "@DEFAULT_PAR_PORT@" for autoconf expansion.
+	Set default_serial to "@DEFAULT_SER_PORT@" for autoconf expansion.
+	* configure.ac: Add call to AC_CANONICAL_{BUILD,HOST,TARGET} macros.
+	Set DEFAULT_PAR_PORT and DEFAULT_SER_PORT based on $host.
+	Add copyright header.
+	Define avrdude_version so AC_INIT and AM_INIT_AUTOMAKE are sure
+	to get the same version.
+
+	* avrdude.conf.in, avrdude.conf.sample:
+	Renamed avrdude.conf.sample to avrdude.conf.in.
+
+2003-02-25  Eric Weddington <eric@ecentral.com>
+
+	* ppiwin.c: CRs again.
+
+	* confwin.c, confwin.h: Get rid of CRs.
+
+	* main.c, Makefile.am: Get rid of CRs again.
+
+2003-02-24  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.1: Atmel has rearranged their web site, so now the AVR
+	docs have been moved to a more logically sounding URL.
+
+2003-02-24  Eric Weddington <eric@ecentral.com>
+
+	* Makefile.am, main.c: Integrate Windows search of config files.
+
+	* confwin.c, confwin.h: config file search on Windows.
+
+	* ppiwin.c: Change port value from lpt1alt to lpt3. Other
+	formatting changes.
+
+	* windows/giveio.c:
+	Add giveio device driver source. Requires MS DDK to build.
+
+	* windows/giveio.sys: Add giveio device driver binary.
+
+	* giveio.sys, install_giveio.bat, remove_giveio.bat, status_giveio.bat:
+	Move Windows specific files.
+
+	* windows/loaddrv.c, windows/loaddrv.h, windows/remove_giveio.bat:
+	* windows/status_giveio.bat, windows/install_giveio.bat:
+	Add Windows specific files.
+
+	* main.c: Usage back to stderr.
+
+2003-02-22  Brian S. Dean  <bsd@bsdhome.com>
+
+	* CHANGELOG: Add note about .avrduderc.
+
+	* avr.c, avrdude.conf.sample, avrpart.h, config_gram.y, main.c,
+	* par.c, pgm.c, pgm.h:
+	Add the ability to read a per-user config file located at
+	$HOME/.avrduderc.  Entries from .avrduderc take precedence over those
+	from the system wide config file in ${PREFIX}/etc/avrdude.conf.
+
+	Track and display the config file name and line number when we print
+	out the available parts and programmers.  This is useful in case
+	someone has overridden a definition in their .avrduderc file and is
+	wondering why the definition in the system wide config file is not
+	being used.
+
+	Remove the default programmer 'stk500' from the distributed config
+	file.
+
+	* CHANGELOG: Spelling.
+
+2003-02-21  Brian S. Dean  <bsd@bsdhome.com>
+
+	* CHANGELOG:
+	Put some stuff in the CHANGELOG for this upcoming new version before I
+	forget.
+
+	* main.c:
+	Update comment due to removal of the default parallel port pin config.
+
+	* config.c, config.h, config_gram.y, lexer.l, main.c:
+	* avrdude.conf.sample:
+	Introduce 'default_programmer' to the config file instead of requiring
+	one of the programmers to be tagged "default" within its definition.
+
+	Also, axe the notion of a compiled-in default programmer.  It is
+	kind've pointless now that nearly all configuration comes from the
+	config file, thus, avrdude is not very useful without the config file,
+	and thus, having a programmer compiled-in offers little or no benefit.
+
+2003-02-21  Eric Weddington <eric@ecentral.com>
+
+	* main.c: Change usage text to be verbose.
+
+	* giveio.sys: Add Windows parallel port device driver (binary).
+
+	* install_giveio.bat, remove_giveio.bat, status_giveio.bat:
+	Windows batch files to work with giveio.sys.
+
+2003-02-21  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrdude.conf.sample, config.c, config.h, config_gram.y, lexer.l:
+	* main.c:
+	Add port name defaults to the config file instead of hard-coding.
+	This adds 'default_parallel' and 'default_serial' keywords to the
+	grammar, which take quoted string arguments.
+
+	* avrdude.conf.sample:
+	Document the recent additions to the config file.
+
+	* stk500.c, avr.c, avrpart.h, config_gram.y, lexer.l, par.c:
+	Add the ability to specify which pin to pulse when retrying entry into
+	programming mode.  Use 'retry_pulse' in the per-part specification
+	that can currently take values of 'reset' or 'sck', the default being
+	'sck' which preserves the previous behaviour.  Some newer parts
+	indicate that /RESET should be pulsed, while older parts say to pulse
+	SCK.
+
+2003-02-20  Eric Weddington <eric@ecentral.com>
+
+	* main.c, par.c:
+	Make verbose global. Make debug code in par_cmd() based on verbose=2.
+
+2003-02-20  Brian S. Dean  <bsd@bsdhome.com>
+
+	* stk500.c: Fix pseudo/full parallel mode selection logic.
+
+	* avrdude.conf.sample:
+	Woops, didn't really mean to commit those changes that slipped in with
+	the last commit.  Those were just there for testing.
+
+	* avr.c, avrdude.conf.sample, avrpart.h, config_gram.y, lexer.l:
+	* stk500.c:
+	Add 'serial' and 'parallel' keywords to the grammar so that one can
+	say whether parts support these programming modes or not.  Possible
+	values for 'serial' are 'yes' or 'no'.  Possible values for 'parallel'
+	are 'yes', 'no', or 'pseudo'.  Add a bit mask of flags to the AVRPART
+	structure to capture these settings.  Use these within
+	stk500_initialize() to set the device parameters correctly.
+
+	Defaults for 'serial' and 'parallel' are 'yes' unless specified
+	otherwise.
+
+2003-02-20  Eric Weddington <eric@ecentral.com>
+
+	* Makefile.am, ppiwin.c: Get rid of CRs.
+
+	* Makefile.am: Add ppiwin.c to avrdude_SOURCES.
+
+	* ppiwin.c: Added ppiwin.c: Windows parallel port driver.
+
+	* stk500.c:
+	Add error message for fail to enter programming mode. Fix typos.
+
+2003-02-20  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avr.c, avrdude.conf.sample, avrpart.h, config_gram.y, lexer.l:
+	Add a few parameters needed for parallel programming: assignment of
+	PAGEL and BS2 signals and the disposition of the reset pin
+	('dedicated' or 'io').
+
+2003-02-20  Theodore A. Roth  <troth@openavr.org>
+
+	* avrdude.1: Fix spacing for m169 entry. (tabs not spaces ;-)
+
+2003-02-20  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrdude.1, fileio.c, main.c: Add Motorola S-record support.
+
+	Submitted by:		"Alexey V.Levdikov" <tsar@kemford.com>
+
+2003-02-19  Theodore A. Roth  <troth@openavr.org>
+
+	* avrdude.1: Add m169 to list of supported targets.
+
+2003-02-19  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.sample, avrdude.1:
+	My colleague contributed a part definition for the AT90S2343.
+
+	Submitted by:	Mirko Kaffka <mirko@mkaffka.de>
+
+2003-02-18  Theodore A. Roth  <troth@openavr.org>
+
+	* avrdude.conf.sample:
+	Add support for mega169. (tested with stk500 with 1.7 firmware)
+
+	* avrdude.conf.sample:
+	Add commments to separate parts (makes it easier for the eye to parse).
+
+2003-02-15  Theodore A. Roth  <troth@openavr.org>
+
+	* Makefile.am: Add $srcdir to sample config filename so that
+	building in a separate dir works.
+
+2003-02-15  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* Makefile.am:
+	Only GNU make sets $< in non-inference rules, so rather explicitly
+	spell the source file(s) to remain compatible.
+
+2003-02-14  Theodore A. Roth  <troth@openavr.org>
+
+	* Makefile.am: Add distclean rule and EXTRA_DIST list to get 'make
+	distcheck' to succeed.
+
+	These changes add basic support for a autoconf/automake based
+	build system.
+
+	* .cvsignore: Ignore autoconf files.
+	* AUTHORS: New file.
+	* ChangeLog: New file.
+	* Makefile: Removed file.
+	* Makefile.am: New file.
+	* NEWS: New file.
+	* README: New file.
+	* bootstrap: New file.
+	* configure.ac: New file.
+	* avr.c: Include ac_cfg.h (generated by autoconf).
+	* config.c: Include ac_cfg.h.
+	Include config_gram.h instead of y.tab.h.
+	* config.h: If HAS_YYSTYPE is not defined, define YYSTYPE.
+	* config_gram.y: Include ac_cfg.h.
+	* fileio.c: Include ac_cfg.h.
+	* lexer.l: Include config_gram.h instead of y.tab.h.
+	* lists.c: Include ac_cfg.h.
+	* main.c: Include ac_cfg.h.
+	* par.c: Include ac_cfg.h.
+	* pgm.c: Include ac_cfg.h.
+	* ppi.c: Include ac_cfg.h.
+	* stk500.c: Include ac_cfg.h.
+	* term.c: Include ac_cfg.h.
+
+2003-02-14  Brian S. Dean  <bsd@bsdhome.com>
+
+	* stk500.c: Fix typos.  Fix error messages.
+
+2003-02-13  Brian S. Dean  <bsd@bsdhome.com>
+
+	* Makefile, avrdude.conf.sample, config_gram.y, lexer.l, main.c:
+	* par.c, par.h, ppi.c, ppi.h, stk500.c:
+	Split higher level parallel port programmer code off from ppi.c into
+	its own file par.c, leaving low level parallel port accessor routines
+	in ppi.c to help with portability.  Change the programmer type to
+	'PAR' now instead of 'PPI' - 'PAR' represents the parallel port
+	programmer type.
+
+	Be more liberal with 'static' function declarations within the
+	programmer implimentation files - these functions should never be
+	called directly - always use the programmer function references.
+
+	There are still a few places in 'main.c' that directly reference the
+	parallel programmer explicitly (par_getpinmask).  These should be
+	fixed somehow.
+
+	Axe a few unused functions.
+
+2003-02-12  Theodore A. Roth  <troth@openavr.org>
+
+	* .cvsignore: New file.
+
+	* stk500.c: Remove need for inttypes.h.
+
+	* lexer.l: Define YY_NO_UNPUT to quell a compiler warning.
+
+	* Makefile: Remove YACC assignment.
+	Add '-b y' options to YACC invocation.
+	Remove leading '-' from 'include .depend'.
+
+2003-02-12  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* config_gram.y:
+	Declare the internally used static functions on top, to get rid of the
+	compiler warnings.
+
+	Reported by:	bison-generated parsers
+
+2003-02-11  Theodore A. Roth  <troth@openavr.org>
+
+	* linux_ppdev.h: New file.
+	* ppi.c: Include system dependant parallel port interface file.
+	(ppi_open): Add call to ppi_claim().
+	(ppi_close): Add call to ppi_release().
+	* ppi.h: Define ppi_claim() and ppi_release() as NOPs if not previously
+	defined.
+	* stk500.c: Include inttypes header to quell compiler warning.
+
+2003-02-11  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* pgm.c, ppi.c, stk500.c: Fix some implicit declaration warnings.
+
+	* config_gram.y:
+	Move the C declarations to the top of the file.  While [b]yacc doesn't
+	care, bison does, and this is normally the way it's meant to be
+	anyway.
+
+2003-02-11  Theodore A. Roth  <troth@openavr.org>
+
+	* Makefile: Generate dependencies specific to the target system.
+	Explicitly use byacc.
+
+	* Makefile:
+	Remove reference to avr-gcc in depend rule (cut & paste error).
+
+2003-02-09  Brian S. Dean  <bsd@bsdhome.com>
+
+	* main.c, pgm.c, pgm.h, pindefs.h, ppi.c, ppi.h, stk500.c:
+	* stk500.h, stk500_private.h, term.c, term.h, CHANGELOG, COPYING:
+	* Makefile, avr.c, avr.h, avrdude.1, avrdude.conf.sample:
+	* avrdude.pdf, avrpart.h, config.c, config.h, config_gram.y:
+	* fileio.c, fileio.h, lexer.l, lists.c, lists.h:
+	Test commit in new public repository.  Before this time this repo
+	existed on a private system.  Commits made by 'bsd' on the old system
+	were made by Brian Dean (bdean on the current system).
+
+2003-02-08  Brian S. Dean  <bsd@bsdhome.com>
+
+	* Makefile, avr.c, avr.h, avrdude.1, avrpart.h, config.c,
+	* config.h, config_gram.y, fileio.c, fileio.h, lexer.l, lists.c:
+	* lists.h, main.c, pgm.c, pgm.h, pindefs.h, ppi.c, ppi.h:
+	* stk500.c, stk500.h, term.c, term.h:
+	The last part of that last commit message should read:
+
+		All others - modify program description.
+
+	* Makefile, avr.c, avr.h, avrdude.1, avrpart.h, config.c:
+	* config.h, config_gram.y, fileio.c, fileio.h, lexer.l, lists.c:
+	* lists.h, main.c, pgm.c, pgm.h, pindefs.h, ppi.c, ppi.h:
+	* stk500.c, stk500.h, term.c, term.h:
+	Makefile: include a target to automatically generate the dependency
+	          list.
+
+	All others
+
+2003-02-06  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrdude.1: Update license to GPL, permission by Joerg Wunsch.
+
+	* lexer.l: Add GPL.
+
+	* Makefile, config_gram.y: Add GPL to the Makefile and config_gram.y.
+
+	* Makefile, stk500.h:
+	Add stk500.h as a dependency for stk500.c.  Remove carraige returns
+	from stk500.h - don't know how those got in there (pointed out by Ted
+	Roth).
+
+	* COPYING, avr.c, avr.h, avrpart.h, config.c, config.h, fileio.c:
+	* fileio.h, lists.c, lists.h, main.c, pgm.c, pgm.h, pindefs.h:
+	* ppi.c, ppi.h, stk500.c, stk500.h, term.c, term.h:
+	Re-license using the GNU GPL.  Thanks to Ted Roth for the patch.
+
+	* avr.c, avr.h, config.c, config.h, config_gram.y, fileio.c:
+	* fileio.h, lexer.l, lists.c, lists.h, main.c, pgm.c, pgm.h:
+	* pindefs.h, ppi.c, ppi.h, stk500.c, stk500.h, term.c, term.h:
+	Get rid of the verbose printing of individual file CVS version ids.
+	This was intended to be used for identifying code in the field for
+	incoming bug reports, but I've never really found it all that useful.
+
+	* CHANGELOG, Makefile, Makefile.inc, avr.c, avrdude.1:
+	* avrdude.conf.sample, config_gram.y, lexer.l, main.c, stk500.c:
+	* term.c:
+	Change the name from AVRPROG to AVRDUDE.
+
+	This change represents a name change only.  There is currently an
+	effort to port AVRPROG to other platforms including Linux and Windows.
+	Since Atmel's programmer binary that's included within their AVR
+	Studio software is named AVRPROG.EXE on the Windows OS, there is the
+	chance for confusion if we keep calling this program AVRPROG as well.
+	Up until now the name hasn't really been a problem since there was no
+	chance to confuse 'avrprog' on Unix with Atmel's AVRPROG because
+	Atmel's tools only run on Windows.  But with the Unix 'avrprog'
+	possibly being ported to Windows, I felt a name change was the best
+	way to avoid problems.
+
+	So - from this point forward, my FreeBSD Unix program formerly
+	known as AVRPROG will subsequently be known as AVRDUDE (AVR
+	Downloader/UploaDEr).
+
+	This change also represents a time when the AVRDUDE sources move from
+	my own private repository to a public repository.  This will give
+	other developers a chance to port AVRDUDE to other platforms and
+	extend its functionality to support additional programming hardware,
+	etc.
+
+	So goodbye AVRPROG, welcome AVRDUDE!
diff --git a/avrdude/ChangeLog-2004-2006 b/avrdude/ChangeLog-2004-2006
new file mode 100644
index 00000000..20e5b2e8
--- /dev/null
+++ b/avrdude/ChangeLog-2004-2006
@@ -0,0 +1,1644 @@
+2006-12-23 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* configure.ac (AC_INIT): Bump version to 5.3cvs (again).
+
+2006-12-22 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* configure.ac (AC_INIT): Bump version to 5.3.1.
+	* avrdude.conf.in (frank-stk200): Fix syntax error.
+	* ser_avrdoper.c: Make #ifdef for Win32/libhid
+	consistent with the initial check: use the HID driver
+	only iff found, otherwise use libusb.
+
+2006-12-21 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* configure.ac (AC_INIT): Bump version to 5.3cvs.
+
+2006-12-21 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Released AVRDUDE 5.3.
+
+2006-12-21 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* configure.ac (AC_INIT): Bump version to 5.3.
+
+2006-12-21 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Submitted by Vince VG:
+	* avrdude.conf.in (frank-stk200): New programmer added.
+	* doc/avrdude.texi: Mention frank-stk200.
+	Closes patch #5502: one other programmer
+
+2006-12-21 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Submitted by Christian Starkjohann:
+	* ser_avrdoper.c (usbOpenDevice): clear the error code when
+	returning successfully.
+
+2006-12-21 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Submitted by Christian Starkjohann:
+	patch #5507: Support for AVR-Doper USB programmer in HID mode
+	* configure.ac: Add hooks to detect the Win32 HID library,
+	as well as the existence of <ddk/hidsdi.h>.
+	* Makefile.am: Add new files.
+	* my_ddk_hidsdi.h: (New file.)
+	* ser_avrdoper.c: (New file.)
+	* serial.h: Add declaration for avrdoper_serdev.
+	* stk500v2.c: Add hook to divert to the AVR Doper code.
+	* avrdude.1: Document the AVR Doper support.
+	* doc/avrdude.texi: (Ditto.)
+
+2006-12-15 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Submitted by ivanv at netman.ru
+	* jtagmkI.c: fix length for single-byte write operations.
+	Closes bug #18527 JTAG ICE: fuse bits have been writen incorrectly
+
+2006-12-11 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* jtagmkII.c (jtagmkII_paged_write): Remove a debugging
+	usleep(1000000) that accidentally crept in in rev 1.19.
+
+2006-12-11 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* ser_posix.c (ser_open): Do fill in fdp->ifd before already
+	using it in ser_setspeed().
+
+2006-12-11 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* jtagmkI.c (jtagmkI_close): revert baud rate to the initial
+	value in case we had changed it.
+	Fixes bug #18262: JTAGMKI/JTAG1 Reset Bug
+
+2006-12-11 Colin O'Flynn <coflynn@newae.com>
+
+	* safemode.c: Stop ignoring return values!
+	  Closes bug #18339
+
+2006-12-11 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Submitted by Nick Lott:
+	* avrdude.conf.in: Fix signature for ATmega8515.
+	Closes bug #18348: ATMEGA8515 Signature is wrong in avrdude.conf
+
+2006-12-11 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avr.c: Fix a bug introduced in rev. 1.69, when implementing the
+	fallback from each programmer's paged_load() or paged_write()
+	method, respectively.  The return value needs to be checked for
+	being greater or equal than 0 rather equal to 0 in order to
+	assume the operation has been successful.
+	Fixes bug #18489: avrdude is too slow (20 byte/s)
+
+2006-12-11 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avr910.c: Make the code compile warning-free:  
+	- declare a dummy "struct timezone" for some Win32 systems (MinGW)
+	- fix a few printf() argument types
+	- get rid off the prevailing "all filedescriptors are of type int"
+	  attitude
+	The last item required a large sweep across the code, in order to
+	replace all "int fd"s by "struct filedescriptor *fd"s, and pass
+	pointers (as we cannot pass a union directly).  In return, the
+	code is now supposed to be fully 64-bit safe, rather than relying
+	on a 64-bit pointer being converted to a (32-bit) int and back
+	to a pointer as we did previously.
+	* butterfly.c: (Ditto.)
+	* jtagmkI.c: (Ditto.)
+	* jtagmkII.c: (Ditto.)
+	* lists.c: (Ditto.)
+	* par.c: (Ditto.)
+	* pgm.h: (Ditto.)
+	* ppi.c: (Ditto.)
+	* ppi.h: (Ditto.)
+	* ppiwin.c: (Ditto.)
+	* ser_posix.c: (Ditto.)
+	* ser_win32.c: (Ditto.)
+	* serbb_posix.c: (Ditto.)
+	* serbb_win32.c: (Ditto.)
+	* serial.h: (Ditto.)
+	* stk500.c: (Ditto.)
+	* stk500v2.c: (Ditto.)
+	* usb_libusb.c: (Ditto.)
+
+2006-11-23 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Implement EEPROM access through debugWire.
+	* jtagmkII.c: Extend the jtagmkII_read_byte() and
+	jtagmkII_write_byte() methods to handle EEPROM through
+	debugWire.
+	* avrpart.h: Implement the "flash instruction" parameter.
+	* config_gram.y: (Ditto.)
+	* lexer.l: (Ditto.)
+	* avrdude.conf.in: (Ditto.)
+	* avrdude.1: Document the EEPROM access through dW.
+	* doc/avrdude.texi: (Ditto.)
+	* tools/get-dw-params.xsl: Extend to extract the flash
+	instruction field.
+
+2006-11-23 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avr.c (avr_read, avr_write): if the paged access returns a
+	failure, fall back to byte access.
+
+2006-11-21 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* jtagmkII.c: In jtagmkII_read_byte() and jtagmkII_write_byte(),
+	return an error upon failure now that the upper layers won't fall
+	back to the cmd() method anymore in that case.
+
+2006-11-21 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Implement debugWire programming support.
+	* avrpart.h: Implement debugWire support.
+	* config_gram.y: (Ditto.)
+	* jtagmkII.c: (Ditto.)
+	* jtagmkII.h: (Ditto.)
+	* lexer.l: (Ditto.)
+	* avrdude.conf.in: Add the new dW programmers.
+	* avrdude.1: Document the dW support.
+	* doc/avrdude.texi: (Ditto.)
+	* tools/get-dw-params.xsl: XSL stylesheet to extract the dW
+	parameters from the XML files.
+
+2006-11-20 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* jtagmkI.c (jtagmkI_close): remove two unused variables.
+
+2006-11-20 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avr.c: Replace the fallback of avr_read_byte() and avr_write_byte() to
+	avr_read_byte_default() and avr_write_byte_default (resp.) by directly
+	calling the latter functions from within all programmers that don't
+	implement their own read_byte()/write_byte() methods.  In turn, make the
+	read_byte() and write_byte() methods mandatory, and the cmd() method
+	(direct ISP command) optional instead (it's effectively mandatory for
+	any programmer using avr_read_byte_default()/avr_write_byte_default()
+	though).  Remove all the pointless cmd() method stubs from those programmers
+	that don't need it.
+	Eliminate avr_read_byte() as it was now completely identical to
+	pgm->read_byte().
+	* avr.h: (Ditto.)
+	* bitbang.c: (Ditto.)
+	* butterfly.c: (Ditto.)
+	* jtagmkI.c: (Ditto.)
+	* jtagmkII.c: (Ditto.)
+	* par.c: (Ditto.)
+	* pgm.c: (Ditto.)
+	* safemode.c: (Ditto.)
+	* serbb_posix.c: (Ditto.)
+	* serbb_win32.c: (Ditto.)
+	* stk500.c: (Ditto.)
+	* stk500v2.c: (Ditto.)
+	* term.c: (Ditto.)
+	* usbasp.c: (Ditto.)
+
+2006-11-13 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* jtagmkI.c: Avoid sending a CMD_RESET when leaving programming
+	mode, and CMD_GO when closing the connection.  They cause the
+	activity LED on the ICE to continue to flicker, and are not
+	necessary anyway (the target starts to run by itself when leaving
+	programmng mode).
+	This is a partial fix for bug #18262: JTAGMKI/JTAG1 Reset Bug
+
+2006-11-12 Colin O'Flunn <coflynn@newae.com>
+
+	* avrdude.conf.in: Add read command for lockbits for Tiny2313.
+	Applies patch #5538
+
+2006-11-10 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Add signatures for ATmega325/3250/645/6450.
+
+2006-11-08 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* configure.ac: Preserve ${LDFLAGS} inherited from environment
+	for Win32 environments.
+
+2006-11-07 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* configure.ac: Don't pretend --enable-doc were the default.
+
+2006-11-02 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Fix the width of the efuse memory area for a
+	number of AVRs.
+	Closes bug #18182: Wrong setting of eFuse configuration for
+	mega640/1280/1281/2560/2561 in avrdude 5.2
+
+2006-11-01 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Implement HVSP and PP modes for the AVR Dragon.
+	* config_gram.y: (Ditto.)
+	* jtagmkII.c: (Ditto.)
+	* jtagmkII_private.h: (Ditto.)
+	* lexer.l: (Ditto.)
+	* stk500v2.c: (Ditto.)
+	* stk500v2.h: (Ditto.)
+	* avrdude.1: Document the HVSP and PP support for the Dragon.
+	* doc/avrdude.texi: (Ditto.)
+
+2006-10-27 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* jtagmkI.c: Implement a flags field in struct serdev, and populate it
+	with a flag that indicates whether the underlying communication can
+	dynamically change its speed or not.  This flag is set for true serial
+	communication but clear for USB communication.  Don't try to adjust
+	the speed when talking over a communication channel that doesn't
+	support it.  (The Dragon does not even support the respective parameter.)
+	* jtagmkII.c: (Ditto.)
+	* ser_posix.c: (Ditto.)
+	* ser_win32.c: (Ditto.)
+	* serial.h: (Ditto.)
+	* usb_libusb.c: (Ditto.)
+
+2006-10-26 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Add support for the AVR Dragon (JTAG and ISP mode).
+	* config_gram.y: (Ditto.)
+	* jtagmkII.c: (Ditto.)
+	* jtagmkII.h: (Ditto.)
+	* lexer.l: (Ditto.)
+	* stk500v2.c: (Ditto.)
+	* stk500v2.h: (Ditto.)
+	* usbdevs.h: (Ditto.)
+	* avrdude.1: Document the AVR Dragon support.
+	* doc/avrdude.texi: (Ditto.)
+
+2006-10-09 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Released AVRDUDE 5.2.
+
+2006-10-09 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* configure.ac: Bump version to 5.2
+
+2006-10-09 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Submitted by John Voltz: add AVR053 oscillator calibration.
+	* main.c: Add the -O option.
+	* pgm.c: Add the hook for the perform_osccal() method.
+	* pgm.h: (Ditto.)
+	* stk500v2.c: Implement perform_osccal().
+	* avrdude.1: Document the -O option.
+	* doc/avrdude.texi: (Ditto.)
+	Partially closes bug #17487: AVR RC oscillator calibration
+	routine not supported (feature request)
+
+2006-10-09 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Submitted by freckle@sf.net:
+	* stk500.c (stk500_paged_write): Send the command and the data
+	payload within a single write().
+	patch #5025: Improve stk500.c robustness
+
+	Submitted by Matthias Ringwald:
+	* stk500.c (stk500_open): do not flush the serial line after
+	getting in sync with the programmer.
+	patch #5293: stk500.c: no drain after sync (-> allow BTnode
+	Bootloader to work on cygwin)
+
+2006-09-29 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* pgm.h: Fix prototype for gettimeofday().
+	Closes bug #17884: another gettimeofday conflict under win32/cygwin
+
+2006-09-24 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Submitted by Thomas Fischl (initially):
+	* configure.ac: Add the CoreFoundation and IOKit framework
+	linker flags on MacOS X when configuring for USB support.
+	patch #4685: Libusb on MacOS X: detection and additional includes
+
+2006-09-20 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avr910.c: As there is a lot of ambiguity about the AVR910
+	device codes, allow the user to override the device code
+	verification with the -F option.
+	* main.c: Make ovsigck a global variable.
+
+2006-09-20 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Add the "stk500generic" programmer that auto-probes for STK500
+	either firmware version 1 or 2.
+	* Makefile.am (avrdude_SOURCES): add the new files
+	stk500generic.c and stk500generic.h.
+	* avrdude.conf.in: Add the stk500generic programmer type, and
+	change the "stk500" entry to point to this programmer.
+	* config_gram.y: Add the stk500generic keyword.
+	* lexer.l: (Ditto.)
+	* stk500.c: Change the stk500v1 code to not call exit()
+	prematurely when failing to open the programmer, but instead
+	return an error status.
+	* stk500generic.c: (New file.) Stub programmer implementation.
+	Probe for either stk500v1 or stk500v2, and adjust the current pgm
+	appropriately.
+	* stk500generic.h: (New file.) Declare the public interface(s)
+	of stk500generic.c.
+	* doc/avrdude.texi: Document the changed behaviour of stk500.
+
+2006-09-18 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Various fixes for ancient processors and their
+	capabilities.  For the AT90S1200 and the AT90S8515, fuse bit
+	handling via ISP, and lock bit reading via ISP are not supported
+	at all.  For the AT90S4414 (small brother of the AT90S8515), add
+	the ability to write the lock bits, and add a definition for the
+	fuse bits (usable for HV programming).  For the AT90S2313, add the
+	"fuse" memory range, so it's available for HV programming.
+
+	Resolves bug #17796: avrdude will not program or verify lockbits
+	with Atmel STK protocol programmers
+
+2006-09-17 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Submitted by Thomas Fischl:
+	* usbasp.c: Check for USBasp with new as well as old VID/PID
+	pair, warn the user about upgrading the firmware in case an
+	old one has been found.
+	* usbasp.h: Add new VID/PID.
+
+2006-09-15 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Fix some mistakes for the ATtinyX61 family:
+	. high fuse has 8 bits
+	. there is an extended fuse (just one bit)
+	. the calibration area is only 1 byte
+
+2006-09-12 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* doc/avrdude.texi: Convert some of the tables to multitables
+	in order to beautify the result.
+
+2006-09-10 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Contributed by Thomas Fischl: add support for USBasp.
+	patch #4686: Add support for USBasp, a simple USB programmer
+	* usbasp.c: New file, implement the USBasp driver.
+	* usbasp.h: New file, interface declarations for USBasp.
+	* Makefile.am: Wire the new files into the build.
+	* avrdude.conf.in: Add the usbasp programmer entry.
+	* config_gram.y: Add the usbasp token.
+	* lexer.l: (Ditto.)
+	* avrdude.1: Document the USBasp programmer.
+	* doc/avrdude.texi: (Ditto.)
+
+2006-09-08 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* main.c: Implement -U filename as a shorthand for
+	-U flash:w:filename:a.
+	* avrdude.1: Document this.
+	* doc/avrdude.texi: (Ditto.)
+
+2006-09-08 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Implement numerical output formats for decimal, hexadecimal,
+	octal, and binary numbers.
+	Closes bug #16129: more output formats for fuse bits
+	(avrdude enhancement request)
+	* fileio.c: Implement fileio_num() and the itoa_simple()
+	helper function.
+	* fileio.h: Add new file formats to FILEFMT.
+	* main.c: Parse the new file formats.
+	* avrdude.1: Document all this.
+	* doc/avrdude.texi: (Ditto.)
+
+2006-09-08 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* fileio.c: CPP statements start in column #1.
+	* stk500v2.c: Hide two debug/trace statements behind "verbose".
+
+2006-09-07 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.1: Describe how to disable the DWEN fuse.
+	* doc/avrdude.texi: (Ditto.)
+
+2006-09-07 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* jtagmkII.c: Translate numerical response codes to strings.
+
+2006-09-07 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.1: The avr109 programmer type no longer chokes on
+	a wrong avr910 device ID, so remove that description.
+	* doc/avrdude.texi: (Ditto.)
+
+2006-09-07 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* jtagmkII.c: When failing to start in ISP mode, try
+	debugWire instead.  This requires the user to eventually
+	restart AVRDUE from scratch then.
+
+2006-09-06 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Add support for the JTAG ICE mkII in ISP mode.
+	* avrdude.conf.in (jtag2isp): New programmer entry.
+	* config_gram.y: Add K_JTAG_MKII_ISP.
+	* jtagmkII.c: Restructure and export some more functions.
+	* jtagmkII.h: Declare exported functions.
+	* jtagmkII_private.h: Prepare file to be included in stk500v2.c.
+	* lexer.l: Add jtagmkii_isp token.
+	* stk500v2.c: Implement glue to jtagmkII.c.
+	* stk500v2.h: Declare stk500v2_jtagmkII_initpgm().
+	* avrdude.1: Document the new programmer support.
+	* doc/avrdude.texi: (Ditto.)
+
+2006-09-01 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* main.c: Add date and time of compilation to the verbose
+	greeting message.
+	Idea taken from patch #3172: Adds date and time of compile
+	to usage message
+
+2006-09-01 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Contributed by <avrdude@zevv.nl> as
+	patch #4372: Better synchronization for stk500
+	* stk500.c: Sync three times, and drop any noise inbetween.
+
+2006-09-01 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in (ATtiny261, ATtiny461, ATtiny861): new
+	entries.
+
+2006-09-01 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* butterfly.c: Remove the device support decision based on
+	the old AVR910 device codes; we've got signature verification
+	now so better rely on that.
+	* avr910.c: Revert the signature bytes returned, as it already
+	happened in butterfly.c.  This closes bug #14998: Signature Bytes
+	read in wrong order (avr910 mode)
+
+2006-09-01 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Submitted by Wim Lewis.
+	* serbb_posix.c: Improve error handling.
+	patch #4923: Better error reporting for serial-bitbang programmers
+
+2006-08-31 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Introduce a "stk500v1" entry, so we
+	can switch the default "stk500" to "stk500v2" some day.
+
+2006-08-31 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	The major part of this change has been contributed by
+	<andyw@pobox.com>.
+	Implements patch #4635: Add support for terminal/console
+	servers for serial programmers
+	* ser_posix.c: Add net_open(), and divert to it for net:host:port.
+	* ser_win32.c: Recognize net:host:port, and bail out.
+	* avrdude.1: Document the net:host:port connection option.
+	* doc/avrdude.texi: (Ditto.)
+
+2006-08-31 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Fix for bug #16627: Butterfly programmer does not reset after
+	programming
+	* butterfly.c: Wait for the device's response after sending
+	an "E" command.
+
+2006-08-31 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Tentative fix for bug #16156: Problem with Si-Prog
+	* serbb_posix.c: Disable reset before closing.
+	* serbb_win32.c: (Ditto.)
+
+2006-08-30 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Rewrite the serbb code so the pin numbering matches the
+	DB9 connector, and fix some related bugs in serbb_posix.c.
+	Closes bug #16265: dasa2 does not work under posix
+	* avrdude.conf.in: New serbb pin numbering; added "siprog"
+	as an alias for "ponyser".
+	* serbb_posix.c: New pin numbering, fix some confusion.
+	* serbb_win32.c: New pin numbering.
+	The generic and Posix-related parts of these changes have
+	been contributed by Hanns-Konrad Unger
+
+2006-08-30 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Contributed by the anonymous developer of patch #5096:
+	* avrdude.conf.in (blaster): Add an entry for the Altera
+	byteblaster.
+
+2006-08-30 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Rework the exit specs so they actually work again.  It should be
+	possible to extend them for other programmers than PPI now (serbb,
+	stk500*).
+	* pgm.h: Keep the exit specs in an abstract form inside struct
+	programmer_t.  (Should be moved out into some programmer-specific
+	structure.)  Rename the getexitspecs() method into
+	parseexitspecs().
+	* main.c: Move the exit specs stuff out to the programmer
+	implementation.
+	* par.c: Implement the new exit spec handling.  Everything is now
+	done using the generic abstraction layer.
+	Closes bug #16443: No disable Resetsignal at the end of
+	Programming Session
+	Obviates need for patch #5057: quick and dirty Hack to unset Reset
+	after Programming
+
+2006-08-29 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	This patch has been contributed by an anonymous developer
+	via the patch tracking system.
+	patch #5096: Allow VCC and BUFF to be any pin in parallel mode
+	* config_gram.y: Release the restriction to PPIDATA pins.
+	* par.c: Rework the code to introduce a function par_setmany()
+	that builds on top of par_setpin(), and use that function for the
+	PPI_AVR_VCC and PPI_AVR_BUFF pin collections.  This also abstracts
+	the polarity of these signals appropriately.
+
+2006-08-28 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Contributed by Ned Konz:
+	* ser_posix.c: Open the serial port with O_NONBLOCK, and
+	save and restore the port state before exiting.
+	patch #5008: Patch for (5.1) ser_posix.c for O_NONBLOCK open
+	and restoring serial port state on close
+	Closes bug #12622: avrdude hangs on macosx/darwin with PL-2303
+	usb-to-serial and Butterfly
+
+2006-08-22 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* bitbang.c: Move the bitbang prerequisite checks out from
+	main() into their own bitbang_check_prerequisites().
+	* bitbang.h: (Ditto.)
+	* main.c: (Ditto.)
+	* par.c: (Ditto.)
+	* serbb_posix.c: (Ditto.)
+	* serbb_win32.c: (Ditto.)
+
+2006-08-22 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Add page mode parameters for all "eeprom"
+	memory definitions that are organized in pages.
+	* avr.c (avr_write_byte_default): Consider using the loadpage
+	instructions only if the respective memory is marked "paged".
+	Closes bug #17199: EEPROM fails verification on ATmega645 with
+	pony-stk200 hardware
+	Closes bug #16849: EEPROM write fails for AT90USB1287 with
+	mode 0x41
+	Closes bug #15146: stk500v2_paged_write: loadpage instruction
+	not defined for part
+
+2006-08-22 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* doc/avrdude.info (-c): Change "avrispmk2" into "avrisp2" as that
+	is the programmer actually supported by avrdude.conf.in.
+	Closes bug #15677: documentation mentions wrong programmer-id
+	"avrispmk2"
+
+2006-08-21 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Fix various AVR910 device codes.  Add the code
+	tables from both, AVR910 and AVR109.  Change avr910_devcode of
+	the ATtiny2313 to 0x5e (ATtiny26).
+	Closes bug #16671: Tiny2313 avr910_devcode is bad
+	Closes bug #15826: avr910 device type for ATmega8 wrong
+
+2006-08-21 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Add (rather conservative) write delay timing
+	values to the *fuse and lock memory spaces of all devices where
+	they have been missing.  Add the lock memory space to the ATmega48
+	section.
+	Closes bug #14920: tiny2313 fuses and AVRDUDE 5.0
+	Closes bug #15751: atmega48: no lock bits defined
+
+2006-08-21 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Fix the size of the calibration memory space
+	for ATtiny13, ATmega64, ATmega16, ATmega32, ATmega8535, ATtiny25,
+	ATtiny45, ATtiny85.
+	Closes bug #17383: Wrong calibration section in avrdude.conf...
+
+2006-08-21 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in (ATmega324): Correct the pagesize from 256 to
+	128.
+	This closes bug #16410: ATMega164/324/644 cannot be programmed
+
+2006-08-20 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* configure.ac: Check for gettimeofday().
+	* ppiwin.c (gettimeofday): Define gettimeofday() replacement
+	only if !defined(HAVE_GETTIMEOFDAY); use correct protype.
+
+2006-08-18 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* stk500v2: Minor cosmetic changes: STK500 firmware version
+	numbers are M.NN, so always display the minor number as two
+	digits.  Examine the response to the sign-on command to see which
+	programmer hardware we are talking to, and then restrict the
+	STK500 topcard display to devices detected as STK500.
+
+2006-08-18 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* Makefile.am: Add a dist-hook, and make it remove lexer.c,
+	config_gram.c, and config_gram.h from the source distribution
+	archive.  These files are supposed to be generated on the target
+	system.
+	Closes bug #15536: avrdude-5.1 compilation fails on Gentoo/amd64
+
+2006-08-17 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* stk500v2.c: unreverse the argument order for
+	CMD_CHIP_ERASE_HVSP; Atmel says AVR068 is right, and
+	stk500.exe is wrong.
+	* configure.ac (AC_CHECK_LIB[usb]): Fix the generation
+	of HAVE_LIBUSB in ac_cfg.h.
+
+2006-08-17 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Submitted by Neil Davey:
+	patch #4539: Ability to control the bit clock (usleep) delay
+	for ppi interface
+	* bitbang.c: Implement bitbang_delay() and its calibration.
+	* bitbang.h: Declare bitbang_delay().
+	* main.c: Add the ispdelay option (-i).
+	* pgm.h (struct programmer_t): Add the ispdelay parameter.
+	* par.c: Add calls to bitbang_delay() when requested.
+	* serbb_posix.c: (Ditto.)
+	* serbb_win32.c: (Ditto.)
+	* avrdude.1: Document the new -i option.
+	* doc/avrdude.texi: (Ditto.)
+
+2006-08-14 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Submitted by <chris@awaretechs.com>:
+	* avrdude.conf.in (ATmega48, ATmega88, ATmega168): patch #5100:
+	mega88 EEPROM support (extended for ATmega48 and ATmega168 - jw).
+
+2006-08-14 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Submitted by <eolson@mit.edu>:
+	* stk500v2.c (stk500v2_open): patch #5273: Emit error message
+	if user requests usb and no libusb support
+
+2006-08-14 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Add HVSP/PP mode parameters for all AVRs.
+
+2006-08-13 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* tools: New directory.
+	* tools/get-hv-params.xsl: New file, extract high-voltage
+	programming parameters from Atmel XML files, and produce
+	an avrdude.conf[.in] snippet.
+
+2006-08-11 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* configure.ac (AC_CHECK_LIB([usb]): implement a private LIBUSB
+	macro to add this library to, to prevent it from being
+	automatically linked to all binaries.  This should fix the Win32
+	build of loaddrv.
+	* Makefile.am (avrdude_LDADD): add LIBUSB here.
+
+2006-08-10 Eric B. Weddington <eweddington@cso.atmel.com>
+
+	Contributed by Bob Paddock <graceindustries@gmail.com>
+	* avrdude.conf.in: Patch #4780. Provide support for mega325,
+	mega3250, mega645, mega6450.
+
+2006-08-10 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in (ATtiny11): fix the HVSP control stack,
+	add delay values required for flash and EEPROM.
+	* stk500v2.c: reverse the argument order for
+	CMD_CHIP_ERASE_HVSP; AVR068 and stk500.exe differ here.
+
+2006-08-09 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* stk500v2.c (stk500v2_program_enable): Fix a typo
+	(synchloops vs. synchcycles).
+
+2006-08-04 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Add parallel programming definitions for
+	the ATmega8/48/88/168.
+
+2006-07-22 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Add the ATtiny11, an HVSP-only device.
+
+2006-07-21 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Implement STK500 (v2) HVSP mode.
+	* stk500v2.c: Add new functions for HVSP support.
+	* stk500v2.h: Add prototype for the stk500hvsp programmer.
+	* avrpart.h: Add fields to struct avrpart for new features.
+	* config_gram.y: Extend the configuration syntax for new
+	features required for HVSP support.
+	* lexer.l: (Ditto.)
+	* avrdude.conf.in: Add HVSP support for ATtiny13 and
+	ATtiny45 as an example.
+	* avrdude.1: Document stk500hvsp.
+	* doc/avrdude.texi: (Ditto.)
+
+2006-07-21 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrpart.c: Print the very verbose memory details only
+	in debug level > 4.
+
+2006-07-19 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* stk500v2.c: Add more parameters for PP mode.  Fix the
+	non-paged write operations for old AVRs.
+	* lexer.l: Add more parameters for PP mode.
+	* config_gram.y: (Ditto.)
+	* avrpart.h: (Ditto.)
+	* avrdude.conf.in: Use the new PP mode parameters; add PP mode
+	definitions for AT90S8515.
+	* avrdude.1: Document the stk500pp support.
+	* doc/avrdude.texi: (Ditto.)
+
+2006-07-19 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* stk500v2.c: Hide stk500v2_set_sck_period_mk2() behind an #if
+	defined(HAVE_LIBUSB) as it is only used there (for the AVRISP
+	mkII).
+
+2006-07-17 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* stk500v2.c: Fix all bugs in stk500pp.  Eliminate pagebuf, and
+	use a stack-allocated buffer instead, as the pagesize can be at
+	most 256 for all current AVRs anyway.
+
+2006-07-17 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* main.c: Use mem->desc in place of upd->memtype in more places to
+	give the full name of the respective memory area, instead of
+	the (possibly abbreviated) name the user typed in the -U option.
+
+2006-07-16 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	First stab at an implementation of the STK500 parallel programming
+	feature (v2 firmware only), named "stk500pp".  Still not yet
+	complete: EEPROM writes not working, documentation missing, only
+	ATmega16 parameters available in avrdude.conf.in, some parameters
+	not yet implemented.
+	* avrdude.conf.in: Add sample parameters for PP mode to ATmega16.
+	* avrpart.h: Add the parallel programming control parameters.
+	* avrpart.c: (Ditto.)
+	* config_gram.y: Add stk500pp configuration grammar.
+	* lexer.l: Add stk500pp token recognition.
+	* stk500v2.h: Add declaration for stk500pp_initpgm().
+	* stk500v2.c: Add stk500pp implementation.
+
+2006-07-11 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Fix the signatures for the
+	ATmega164/324 devices.
+
+2006-07-10 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Enter the signatures for the
+	ATmega164/324/644 devices.
+
+2006-05-25 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* stk500v2.c: Implement extended addressing needed
+	for the ATmega256x devices.
+	* avrdude.1: Document ATmega256x support.
+	* doc/avrdude.texi: Document ATmega256x support.
+	Also document Solaris port defaults.
+
+2006-05-24 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avr.c: Start implementing support for ATmega256x;
+	jtag2 and bitbang programmers are working, stk500v2
+	still needs to be done.
+	* avrdude.conf.in: (Ditto.)
+	* avrpart.c: (Ditto.)
+	* avrpart.h: (Ditto.)
+	* config_gram.y: (Ditto.)
+	* lexer.l: (Ditto.)
+
+2006-04-18 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Contributed by Julius Luukko <Julius.Luukko@lut.fi>:
+	* avrdude.conf.in: Add the "ere-isp-avr" programmer.
+
+2006-04-13 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* par.c: Add logic to negate parallel-port signals in
+	avrdude.conf using a tilde.
+
+	Contributed by Bram Daams:
+	* avrdude.conf.in: Add the "atisp" programmer entry that
+	makes use of negated signals.
+
+2006-03-28 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Add entries for AT90USB{64,128}{6,7}
+
+2006-03-23 Colin O'Flynn <coflynn@newae.com>
+
+	Contributed by Wim Lewis, fix a few typos (patch #4987)
+	* avrdude.1: Typo fix
+
+2006-02-27 Colin O'Flynn <coflynn@newae.com>
+
+	Contributed by Wim Lewis, add support for checking device
+	signatures in detail (patch #4924 and #4925)
+	* avrdude.conf.in: Add signatures
+	* avrpart.c: Set default signature
+	* avrpart.h: Variable for signature
+	* config_gram.y: More signature reading
+	* lexer.l: Define that signatures exist
+	* main.c: Read signatures and check them against hardware
+
+2006-02-21 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Fix paged flash write for AT90PWMx
+	(error in datasheet).
+
+2006-01-23 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* configure.in: Bump version.
+
+2006-01-17 Colin O'Flynn <coflynn@newae.com>
+
+	* main.c: Fixed a typo in safemode variable names, fixed bug 15113
+	* avrdude.conf.in : Added BS2 and pagel to M162, Patch 4766
+	* main.c, stk500v2.c: Added patch 4804 from eolson@mit.edu
+	Which stops sck from being writtend needlessly
+
+2006-01-13  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Contributed by David Moore: add support for the
+	AVRISP mkII device. (Savannah patch #4789.)
+	* serial.h: Declare usb_serdev_frame device descriptor.
+	* stk500v2.c: Implementation of the AVRISP mkII handling.
+	* usb_libusb.c: Add USB handling for short-frame delimited
+	AVRISP mkII USB protocol; add distinction of different
+	devices in usbdev_open().
+	* jtagmkII.c: Tell usbdev_open() to search for the JTAG ICE mkII.
+	* usbdevs.h: (New file.)
+	* Makefile.am: Add usbdevs.h, as well as some other forgotten
+	files "make distcheck" complained about.
+	* avrdude.conf.in: Add more aliases for the AVRISP mkII.
+	* avrdude.1: Document how to use the AVRISP mkII.
+	* doc/avrdude.texi: (Ditto.)
+
+2006-01-12  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Add EEPROM page instructions for the
+	ATmega169 so it will work for STK500v2.
+
+2005-12-16  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Added support for ATtiny24/44/84.
+
+2005-12-05  Colin O'Flynn <coflynn@newae.com>
+
+	* avrdude.conf.in: Added m162 support for stk500v2
+
+2005-12-01  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: fix the number of significant bits for
+	the efuse memory in ATmega48/88/168; the datasheet is a bit
+	off here as well.
+
+2005-11-29  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.1: update for JTAG ICE mkI support.
+	* doc/avrdude.texi: (Ditto.)
+
+2005-11-29  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Submitted by Galen Seitz:
+	patch #4459: Fix for rpm package builds
+	* avrdude.spec.in: update the RPM spec file:
+	  - Default to enable-doc=yes during configure.
+	  - Move info file to docs package.
+	  - Make building of docs package conditional.  Basic
+	    idea copied from avr-gcc.
+
+2005-11-29  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Submitted by someone who thinks he's called "Daper":
+	Fix bug #15013: Wrong use of PPICLAIM (kernel: ppdev0: claim the
+	port first)
+	* par.c: don't claim/release here (thus win_ppdev.h not needed
+	anymore)
+	* ppi.c: claim/release here.
+	* freebsd_ppi.h: ppi_claim/ppi_release now take an fd as parameter.
+	* solaris_ecpp.h: (Ditto.)
+	* linux_ppdev.h: (Ditto.)  (Also add copyright.)
+	* win_ppdev.h: Not needed anymore, remove.
+
+2005-11-28  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* jtagmkI.c: Improve the communication startup with the ICE.
+
+2005-11-28  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* configure.ac: enable parport access on x86_64 Linux and
+	FreeBSD systems.
+
+2005-11-27  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: add the "calibration" space to ATmega16.
+
+2005-11-25 Colin O'Flynn <coflynn@newae.com>
+
+	Fixed bug 15051, building for Windows breaks.
+	* par.c: ppi_claim and ppi_release definitions now in a Windows header file
+	* ppi.c: Only included if you are building for Windows
+	* win_ppdev.h: Initial Commit, see par.c
+
+2005-11-24  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Add basic support for the Atmel JTAG ICE mkI:
+	* config_gram.y: add mkI support to config sytax.
+	* lexer.l: (Ditto.)
+	* avrdude.conf.in: add sample programmer entries.
+	* jtagmkI.c: New file
+	* jtagmkI.h: New file
+	* jtagmkI_private.h: New file
+	* Makefile.am: include new files in build.
+
+2005-11-24 Colin O'Flynn <coflynn@newae.com>
+
+	Fix bug 14681 - Serial Communication Fails on -vvvv with Windows
+	* ser_win32.c: Patched with Brian Dean's patch
+
+2005-11-05 Colin O'Flynn <coflynn@newae.com>
+
+	Patch #4532 by Manfred Bartz
+	* avrdude.conf.in: added support for ATMega168 (also added support
+	for the stk500v2 protocol which was not in the patch).
+
+2005-11-03  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Add ecpp(7D) (parallel port) for Solaris.
+	* configure.ac: add Solaris' default parallel port.
+	* linux_ppdev.h: change parallel port access to the new style.
+	* freebsd_ppi.h: New file, abstract FreeBSD's ppi(4).
+	* solaris_ecpp.h: New file, abstract Solaris' ecpp(7D).
+	* par.c: change header inclusion sequence.
+	* pgm.h: remove obsolete ppi_claim() and ppi_release() dummies.
+	* ppi.c: change header inclusion sequence, use new parport
+	abstraction, drop obsolete dummy implementation.
+
+2005-11-02  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* config.h: change YYSTYPE to be a single word, to work around
+	a bug in Solaris' yacc.
+	* lexer.l: remove incompatibilities with Solaris' default lex,
+	bump resource limits for lex.
+
+2005-11-01  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Make avrdude Solaris-compatible.
+	* Makefile.am: distclean avrdude.conf.
+	* avrdude.conf.in: make the parallel-port programmers optional.
+	* bitbang.c: move the bitbang features out into PROGRAMMER.
+	* configure.ac: introduce --enable-parport, add Solaris.
+	* lexer.l: replace str by strng to work around problems in some
+	versions of flex.
+	* main.c: move getexitspecs into the respective programmer's
+	domain; replace rindex by the C-standard strrchr.
+	* par.c: make parallel port optional.
+	* par.h: everything but par_initpgm() is private now.
+	* pgm.h: add setping/getping/highpulsepin/getexitspecs.
+	* serbb_posix.c: generalize bitbang interface; replace
+	cfmakeraw() by explicit code.
+	* serbb_win32.c: generalize bitbang interface.
+
+2005-10-20  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* butterfly.c: fix yet another sign extension bug.
+
+2005-10-14  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in (ATmega8515): fix size of calibration
+	memory.
+
+2005-10-09  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: add support for ATmega640/1280/1281.
+	* avrdude.1: document the above.
+	* doc/avrdude.texi: (Ditto.)
+
+2005-09-27  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* doc/avrdude.texi: Polish up the docs a bit.  Use smallexample
+	instead of example for wide tty output.  Document a trick to
+	find out about the serial numbers of all JTAG ICEs attached
+	to USB.
+
+2005-09-26  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* jtagmkII.c (jtagmkII_paged_write): default the page size early so the
+	buffer will be allocated correctly.
+	* usb_libusb.c: fix libusb handling; now it works with libusb-win32 as
+	well.
+
+2005-09-21  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* main.c(do_op): use mem->desc in place of upd->memtype to
+	give the full name of the respective memory area, instead of
+	the (possibly abbreviated) name the user typed in the -U option.
+
+2005-09-21  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* main.c: Add the forgotten -B option to the option string in
+	getopt(); sort the -s option into order.
+
+2005/09/21  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avr.c:
+	* main.c:
+	* safemode.c:
+	* safemode.h:
+	* term.h:
+	  This is Colin O'Flynn's mega patch for updating safemode support:
+
+	  * add support for parts with just 'fuse' memory
+
+	  * if any fuse memories are altered, reflect those changes in the
+	  post-programming safemode check so that safemode no longer
+	  complains about fuses which were intentionally altered; this
+	  eliminates the need to completely disable safemode using -u in
+	  order to program fuses.
+
+	  * provide -s option which will not ask to restore fuses, it will
+	  just do it
+
+2005-09-19  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* butterfly.c (butterfly_initialize): make the device code unsigned so
+	it wouldn't sign-extend when >= 0x80.
+
+2005-09-18  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Add the serial bit-bang driver, contributed by Michael Holzt.
+	* bitbang.h: New file.
+	* bitbang.c: New file.
+	* serbb.h: New file.
+	* serbb_posix.c: New file.
+	* serbb_win32.c: New file.
+	* Makefile.am: Include new files.
+	* config_gram.y: Add serbb to configuration language.
+	* lexer.l: (Ditto.)
+	* par.c: Centralize bit-bang code in bitbang.c.
+	* par.h: Declare newly published functions.
+	* pgm.h (struct programmer_t): Add a flag field for private use
+	  by the programmer.
+	* pindefs.h: Add definitions for negated serbb pins.
+	* avrdude.conf.in: Add serbb programmers ponyser, dasa, and dasa3.
+	* avrdude.1: Document serbb code.
+	* doc/avrdude.texi: (Ditto.)
+
+2005/09/18  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrdude.conf.in: Patch #4078: add VCC pin definition for DAPA
+	  programmer.
+
+2005/09/18  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avr910.c: This is patch #3277 which appears to fix a number of
+	  issues with the avr910 programmer.
+
+	  Fixes the following problems with paged writes in avr910.c:
+	    - failure to re-set address after page writes;
+	    - no polling or delay after page writes;
+	    - no page writes when not using auto-increment;
+	    - an extraneous page write when data ends on page boundary.
+
+2005-09-17  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Fix the poll values for the ATmega103's EEPROM
+	so they eventually match the XML file.
+	This fixes bug #7492: EEPROM writing fail on atmega103 with
+	atavrisp
+
+2005-09-17  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: The ATmega128 has four oscillator calibration
+	bytes, not only a single one.
+	This closes bug #11496: Memory bank calibration on atmega128
+	should have 4 bytes
+
+2005/09/17  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrdude.1:
+	  Document -q -q.  Expand a little on the description of the 'part'
+	  command.
+
+2005/09/16  Brian S. Dean  <bsd@bsdhome.com>
+
+	* fileio.c:
+	* main.c:
+	  Implement -q -q to be very very quiet.
+
+2005/09/16  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrdude.conf.in:
+	  Add DAPA programmer.
+
+2005/09/16  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrdude.conf.in:
+	* stk500v2.c:
+	  This fixes EEPROM access using the STK500V2 programmer, partially
+	  undoing part of a previous general fixup commit.  Choose the correct
+	  read/write operations with the stk500v2 program function - the correct
+	  one depends on the memory type.  EEPROM is byte addressable so uses
+	  read/write.  FLASH is word addressable and so uses read_lo/write_lo.
+
+2005-09-16  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.1: document the memtypes for -U
+	* doc/avrdude.texi: (Ditto.)
+	Closes bug #13501: <memtype> should be listed in the man page
+
+2005-09-16  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* doc/Makefile.am: add logic to detect the misf^H^H^H^H
+	gratitous API change in recent versions of texi2html where
+	the output directory has changed names.
+	Fix for:
+	bug #13026: The build fails with texi2html 1.76
+	bug #12715: make issues during install
+	patch #3091: commandline fix for latest version of texi2html
+
+2005-09-16  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* usb_libusb.c (usbdev_drain): actually implement draining to aid
+	synchronizing against a JTAG ICE in weird state.
+
+2005-09-16  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* butterfly.c: improve the butterfly initialization so it is more likely
+	to synchonize; [bug #9787: avrdude 4.4.0 correct butterfly interface]
+
+2005-09-14  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* jtagmkII.c (jtagmkII_paged_load): return the number of bytes read.
+	This makes EEPROM block reads work again.
+
+2005-09-14  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: add a jtag2slow programmer alias, and make
+	"jtag2" default to 115200 Bd.
+	* doc/avrdude.texi: document the above changes.
+
+2005/09/14  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrdude.conf.in:
+	  Change bit 0 of the ATmega169 efuse 'write' opcode from 'x' (ignore)
+	  to 'i' (input).  Even though this bit should be ignored, it should not
+	  be changed.  The 'x' setting sets the bit to zero which programs it
+	  and could cause undefined behaviour.  Setting to 'i' enables it to be
+	  rewritten to its old value.
+
+	  A better solution might be to read the fuse byte, apply the new value
+	  while leaving the 'x' bit alone, then writing the value back.  The
+	  current fix is a workaround which allows the developer to change the
+	  bit as desired.
+
+2005-08-30  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* usb_libusb.c: Consistently use unsigned char for buffers.
+
+2005-08-29  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avr910.c: Eliminate compiler warnings.  GCC 4.x elicits many
+	signedness warnings when passing unsigned char * when char * is in
+	the prototype and vice versa.  Clean these up along with a few
+	others.
+	* butterfly.c: (Ditto.)
+	* jtagmkII.c: (Ditto.)
+	* safemode.c: (Ditto.)
+	* safemode.h: (Ditto.)
+	* ser_posix.c: (Ditto.)
+	* serial.h: (Ditto.)
+	* stk500.c: (Ditto.)
+	* stk500v2.c: (Ditto.)
+
+2005-08-28  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Add support for the ATtiny25/45/85.  Note that
+	only the ATtiny45 appears to have a complete XML description right
+	now.
+	* avrdude.1: Mention all the recently added device support: AT90PWM2/3,
+	ATmega164/324/644, ATmega329x/649x, ATtiny25/45/85.
+	* doc/avrdude.texi: (Ditto.)
+
+2005/08/28  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrdude.conf.in:
+	* stk500v2.c:
+	  This is patch # 4338, obsoletes patch #4327, provides fixes for bugs
+	  #13693, #13871, and #14212.
+
+	  This provides bug fixes to the STK500V2 programmer type.
+
+	    - incorrect token used from avrdude.conf.in
+	    - wrong command sent to programmer, hence no write to eeprom.
+	    - programmer was said to start writing at 0x0000 and continue
+	      page by page and was not repositionned when a gap was found
+	      in the hex file, or when the hex file start address was not
+	      0x0000. Hence the verify procedure was correct, not the
+	      write procedure.
+	    - speed up of flash write to skip empty pages (full of 0xFF)
+	      by re-enabling a dedicated function for that task.
+	    - stk500v2_paged_load() was not returning the number of byte
+	      read, so empty hex files were generated when reading memory.
+
+2005-08-17  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: fix the EEPROM size for ATmega329x/649x.
+
+2005-08-16  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Add support for the AT90PWM2/3.
+
+2005-07-27  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	(This work has been done as part of a contract with Atmel, Dresden.)
+	* butterfly.c: Implement full support for AVR109 boot loaders.
+	* avrdude.conf.in: add avr109 and avr911 as alias for butterfly.
+	* avrdude.1: Document the AVR109 addition.
+	* doc/avrdude.texi: (Ditto.)
+
+2005-07-26  Brian S. Dean  <bsd@bsdhome.com>
+
+	* main.c:
+	  Don't call exit() directly here - set the exit value and jump to the
+	  main_exit: label to ensure the programmer is released correctly.
+
+	* stk500v2.c:
+	  The stk500v2_getsync() function was improperly checking for success,
+	  thus it was falsely reporting that it failed when it was actually
+	  working correctly.  Fixed.
+
+2005-07-25  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* usb_libusb.c: Catch benign errors when reading the serial #.
+
+2005-06-19  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* Makefile.am: Implement libusb-base USB transport for the
+	JTAG ICE mkII.
+	* configure.ac: ditto.
+	* jtagmkII.c: ditto.
+	* ser_posix.c: ditto.
+	* ser_win32.c: ditto.
+	* serial.h: ditto.
+	* usb_libusb.c: ditto (New file).
+	* avrdude.1: document the USB transport.
+	* doc/avrdude.texi: ditto.
+
+2005-06-15  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: The AT90CAN128 has AllowFullPageBitstream = no.
+
+2005-06-14  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Add support for the ATmega164/324/644.
+	* jtagmkII.c: If enter_progmode fails with RSP_ILLEGAL_JTAG_ID, give
+	the user a hint that the JTAGEN fuse might be unset.
+
+2005-06-11  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Add support for the ATmega329x/649x.
+
+2005-05-27  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* jtagmkII.c: fix a signedness bug when shifting bits; when
+	discarding a packet for being overly long, restart the state
+	machine instead of attempting to drop a preposterous amount
+	of data.
+
+2005-05-19  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.1:
+	* doc/avrdude.texi: Document that the JTAG ICE mkII code currently
+	cannot write to flash one byte at a time.  Also mention the bug
+	tracker interface on savannah.
+
+2005/05/14  Brian S. Dean  <bsd@bsdhome.com>
+
+	* configure.ac:
+	* main.c:
+	  Update version for beta release and copyright message.
+	  Change the default port to 'serial' for the newly added serial
+	  programmers stk500v2 and jtagmkii.
+
+2005-05-10  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* Makefile.am:
+	* avr910.c:
+	* avrdude.1:
+	* avrdude.conf.in:
+	* avrpart.c:
+	* avrpart.h:
+	* butterfly.c:
+	* config_gram.y:
+	* crc16.c:
+	* crc16.h:
+	* jtagmkII.c:
+	* jtagmkII.h:
+	* jtagmkII_private.h:
+	* lexer.l:
+	* main.c:
+	* pgm.h:
+	* serial.h:
+	* ser_posix.c:
+	* ser_win32.c:
+	* stk500.c:
+	* stk500v2.c:
+	* stk500v2.h:
+	* stk500v2_private.h:
+	* doc/avrdude.texi:
+
+	Mega-commit to bring in both, the STK500v2 support from Erik
+	Walthinsen, as well as JTAG ICE mkII support (by me).
+
+	Note that for the JTAG ICE, I did change a few things in the
+	internal API.  Notably I made the serial receive timeout
+	configurable by the backends via an exported variable (done in
+	both the Posix and the Win32 implementation), and I made the
+	serial_recv() function return a -1 instead of bailing out with
+	exit(1) upon encountering a receive timeout (currently only done
+	in the Posix implementation).  Both measures together allow me to
+	receive a datastreem from the ICE at 115 kbps on a somewhat lossy
+	PCI multi-UART card that occasionally drops a character.  The JTAG
+	ICE mkII protocol has enough of safety layers to allow recovering
+	from these events, but the previous code wasn't prepared for any
+	kind of recovery.  The Win32 change for this still has to be done.
+
+2005/02/11  Brian S. Dean  <bsd@bsdhome.com>
+
+	* main.c:
+	  Exit non-zero if safe-mode reverts fuse bits that were requested on
+	  the command-line.
+
+	  Variable declarations must only appear at the beginning of a block.
+
+2005/02/10  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrdude.1:
+	  Document -u option to disable safe mode.
+
+2005/02/10  Brian S. Dean  <bsd@bsdhome.com>
+
+	* configure.ac:
+	  doc/Makefile is now dependent on whether or not doc is enabled.
+
+2005/02/10  Brian S. Dean  <bsd@bsdhome.com>
+
+	* Makefile.am:
+	* configure.ac:
+	  Disable the doc build by default; the tools needed to build
+	  doc are either not available on all systems or are at best
+	  inconvenient to build and install.  The doc can still be built, one
+	  just needs to specify --enable-doc at configure time.
+
+2005-01-24  Colin O'Flynn  <coflynn@newae.com>
+
+	* main.c: Add "safe mode". Fuse settings will be restored at the end
+	of a programming session unless the -u switch is specified.
+	* safemode.c: New file. Safe mode support.
+	* safemode.h: New file. Safe mode support.
+	* Makefile.am: Add new files.
+	* doc/avrdude.texi: Document new Safe Mode feature and switch.
+
+2004/12/22  Brian S. Dean  <bsd@bsdhome.com>
+
+	* avrdude.conf.in:
+	  Add support for "Xilinx JTAG cable". Contributed by:
+	  Tymm <tymm@booyaka.com>
+
+	  Add support for the AT90CAN128.  Not sure if all the instruction
+	  encoding is correct, specifically the address bits don't exactly match
+	  those of the preliminary datasheet that I have, but I don't see how
+	  they could be right.  Tested with STK500 and it works there.
+	  Instruction encodings have not been tested due to lack of a parallel
+	  port on my Mac development box.
+
+2004-07-19  Theodore A. Roth  <troth@openavr.org>
+
+	* avrdude.1: Remove reference to ppi programmer schematic.
+	* configure.ac (AC_INIT): Set version to "4.4.0cvs".
+
+2004-07-18  Theodore A. Roth  <troth@openavr.org>
+
+	* AVRDUDE 4.4.0 has been released (cvs release tag is "release_4_4_0").
+
+2004-07-18  Theodore A. Roth  <troth@openavr.org>
+
+	* Makefile.am (EXTRA_DIST): Remove avrdude.pdf since it is no longer
+	supplied.
+	* NEWS: Fix typo.
+	* bootstrap: Delete the autom4te.cache dir before running the
+	autotools.
+	* configure.ac (AC_INIT): Set version to 4.4.0.
+
+2004-07-17  Jan-Hinnerk Reichert  <hinni@despammed.com>
+
+	* avrdude.1: Fixed obvious copy and paste error
+	(Patch #3199 contributed by Galen Seitz)
+
+2004-07-15  Theodore A. Roth  <troth@openavr.org>
+
+	* main.c (main): Don't indent CPP directives.
+	When showing update progress in a no tty situation, use unbuffered IO
+	for all systems, not just win32 native.
+	Update copyright year when printing version.
+	Remove warning about native win32 being experimental.
+	Split a line string.
+	* ppiwin.c: Update copyright year.
+	Add cvs Id keyword.
+	(usleep): Cleanup debug CPP directives to improve readability.
+	* ser_win32.c: Include <stdio.h> to fix failing build.
+
+2004-07-08  Theodore A. Roth  <troth@openavr.org>
+
+	* AUTHORS: Add names of recent major contributors.
+	* ser_win32.c: Assign copyright to Martin J. Thomas since he did all
+	real work on this file.
+
+2004-07-07  Jan-Hinnerk Reichert  <hinni@despammed.com>
+
+	* NEWS, doc/TODO: Updated NEWS and TODO
+
+2004-07-07  Jan-Hinnerk Reichert  <hinni@despammed.com>
+
+	* stk500.c, term.c, doc/avrdude.texi, avrdude.1:
+	added "sck"-command to the terminal mode.
+	This command allows slowing down of the SCK of
+	STK500-programmers.
+
+2004-07-05  Jan-Hinnerk Reichert  <hinni@despammed.com>
+
+	* *.c, *.h: Removed unnecessary includes of
+	config.h
+
+2004-07-04  Jan-Hinnerk Reichert  <hinni@despammed.com>
+
+	* avr.h: Removed some unused prototypes
+
+2004-07-04  Jan-Hinnerk Reichert  <hinni@despammed.com>
+
+	* stk500.c: Fixed fosc behaviour for values exceeding
+	maximum frequency (contributed by Galen Seitz)
+
+2004-07-04  Jan-Hinnerk Reichert  <hinni@despammed.com>
+	* avrdude.conf.in: Added support for
+	ATtiny2313 (contributed by Bob Paddock)
+
+2004-06-25  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Fix efuse bits for ATmega169.
+
+2004-06-24  Alex Shepherd <maillists@ajsystems.co.nz>
+
+	Merged in Win32 Native changes contributed by Martin Thomas
+	Changed all instances of __CYGWIN__ conditional compilation to
+	WIN32NATIVE
+
+	* ser_win32.c: fleshed out all the previous stubs
+	* ser_posix.c: added WIN32NATIVE conditional compilation to skip
+	all function to allow ser_win32.c functions to operate
+	* ppi.h: removed commented code
+	* pgh.h: added usleep macros
+	* main.c: stdout,stderr tweaks for Win32
+	* configure.ac: added CFLAGS and LDFLAGS for Win32Native
+	* config_gram.y: added strtok_r macro
+	* buterfly.c: added various stub functions and EXIT processing
+	* avr910.c: added return 0 to avr910_open() and included time headers
+	* term.c: added warning about libreadline not supported in WIN32NATIVE
+
+2004-06-17  Jan-Hinnerk Reichert  <hinni@despammed.com>
+
+	* avrdude.conf.in: Added support for
+	  - tiny13 (contributed by Pawel Moll)
+	  - mega48 and mega88 (contributed by Galen Seitz)
+	However, the STK500-code for mega8 remains unchanged.
+
+2004-05-19  Brian S. Dean  <bsd@bsdhome.com>
+
+	* main.c:
+	* stk500.c: Allow the baud rate to be specified on the command
+	line with a new -b switch.  The specified baud rate will
+	override the default serial port baud rate for a particular
+	programmer.
+
+2004-05-19  Brian S. Dean  <bsd@bsdhome.com>
+
+	* ppi.c: Stub-out the ppi_* functions in ppi.c with empty
+	wrappers that simply return an error code in order to build
+	successfully on MacOS X.  This allows avrdude to work on MacOS
+	X and was tested using a USB<->RS232 cable adapter,
+	specifically Keyspan model USA-19HS.
+
+2004-04-23  Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* lists.h, lists.c: Drop LISTSZ and the check for
+	it in lcreat().
+
+2004-04-17  Jan-Hinnerk Reichert  <hinni@despammed.com>
+
+	* avr910.c: Hopefully fixed that weird "first byte not
+	programmed"-error in a good way (previous fix was not
+	working with all firmwares)
+
+2004-02-10  Jan-Hinnerk Reichert  <hinni@despammed.com>
+
+	* avrdude.1, doc/avrdude.texi, doc/TODO:
+	Removed the deprecated options from documentation
+
+2004-02-10  Jan-Hinnerk Reichert  <hinni@despammed.com>
+
+	* main.c: Removed deprecated options.
+
+2004-01-28  Jan-Hinnerk Reichert  <hinni@despammed.com>
+
+	* pgm.c, main.c, avr910.c, butterfly.c, stk500.c:
+	Changed default for powerup, powerdown and LED-commands
+	to do nothing and return OK. Then removed these commands
+	from avr910, butterfly and stk500.
+	* pgm.c: Fixed wrong type for default_open introduced by
+	the cleanup yesterday.
+
+2004-01-29  Jan-Hinnerk Reichert  <hinni@despammed.com>
+
+	* par.c: changed order of port-read/writes in par_txrx().
+	This change should increase immunity to delays in the
+	programmer-hardware.
+	Also did some unrelated cleanup in par_txrx().
+
+2004-01-28  Jan-Hinnerk Reichert  <hinni@despammed.com>
+
+	* pgm.[ch], main.c, par.c, avr910.c, butterfly.c, stk500.c:
+	Move save/restore-functionality into open/close.
+	* par.c: open/close now saves/restores PPICTRL, too.
+	* TODO: exitspecs don't work if RESET is in PPICTRL.
+
+2004-01-26  Theodore A. Roth  <troth@openavr.org>
+
+	* configure.ac (AC_INIT): Post release version update.
+
+2004-01-26  Theodore A. Roth  <troth@openavr.org>
+
+	* AVRDUDE 4.3.0 has been released (cvs release tag is "release_4_3_0").
+
+2004-01-26  Theodore A. Roth  <troth@openavr.org>
+
+	* configure.ac: Update copyright year.
+	(AC_INIT): Set version to 4.3.0.
+
+2004-01-25  Theodore A. Roth  <troth@openavr.org>
+
+	* ChangeLog: Minor formatting cleanups.
+	Move to all 2003 entries to ChangeLog-2003.
+	* ChangeLog-2003: New file.
+	* Makefile.am: Update copyright year.
+	(EXTRA_DIST): Add ChangeLog-2003.
+
+2004-01-17  Jan-Hinnerk Reichert  <hinni@despammed.com>
+
+	* doc/avrdude.texi: Get rid of those black boxes marking "overfull
+	hbox".
+
+2004-01-17  Jan-Hinnerk Reichert  <hinni@despammed.com>
+
+	* doc/avrdude.texi: New appendix "Troubleshooting".
+
+2004-01-12  Jan-Hinnerk Reichert  <hinni@despammed.com>
+
+	* avr910.c, avrpart.c, avrpart.h, doc/TODO:
+	Look up devicecode and report device.
+
+2004-01-03  Jan-Hinnerk Reichert  <hinni@despammed.com>
+
+	* avr910.c, pgm.c, pgm.h, config_gram.y, lexer.l: Add new configuration
+	parameter baudrate to support avr910-programmers with non-standard
+	baudrates.
+	* avrdude.conf.in, doc/avrdude.texi: Added "baudrate" to documentation.
+
+2004-01-03  Jan-Hinnerk Reichert  <hinni@despammed.com>
+
+	* avr910.c: Removed debugging stuff that is no longer needed.
+
+2004-01-03  Jan-Hinnerk Reichert  <hinni@despammed.com>
+
+	* doc/TODO: Removed two items.
+
+2004-01-03  Jan-Hinnerk Reichert  <hinni@despammed.com>
+
+	* main.c, avr.c, avr.h, par.c, stk500.c: Add function
+	avr_chip_erase() to unify handling of cycle-count.
+	Makes cycle-count work for avr910-programmers.
+
diff --git a/avrdude/ChangeLog-2007 b/avrdude/ChangeLog-2007
new file mode 100644
index 00000000..3514da7e
--- /dev/null
+++ b/avrdude/ChangeLog-2007
@@ -0,0 +1,364 @@
+2007-11-08 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* main.c: Partially revert the line buffered output change,
+	and turn stderr into unbuffered output while producing the
+	progress report.
+
+2007-11-07 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* main.c: Add setup and teardown hooks to the programmer
+	definition.  If present, call the setup hook immediately after
+	finding the respective programmer object, and schedule the
+	teardown hook to be called upon exit.  This allows the
+	programmer implementation to dynamically allocate private
+	programmer data.
+	* pgm.c: (Ditto.)
+	* pgm.h: (Ditto.)
+	* avr910.c: Convert static programmer data into dynamically
+	allocated data.
+	* butterfly.c: (Ditto.)
+	* jtagmkI.c: (Ditto.)
+	* jtagmkII.c: (Ditto.)
+	* stk500v2.c: (Ditto.)
+	* usbasp.c: (Ditto.)
+	* usbtiny.c: (Ditto.)
+
+2007-11-06 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* butterfly.c: Remove the no_show_func_info() calls, as Brian
+	promised some 4 years ago.
+
+2007-11-06 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* main.c: Add the -x option to pass extended parameters to
+	the programmer backend.
+	* pgm.c: (Ditto.)
+	* pgm.h: (Ditto.)
+	* jtagmkII.c: Implement the extended parameter jtagchain=
+	to support JTAG daisy-chains.
+	* avrdude.1: Document all of the above.
+	* doc/avrdude.texi: (Ditto.)
+
+2007-10-30 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* configure.ac (AC_INIT): Bump version for post-release.
+
+2007-10-29 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* configure.ac (AC_INIT): Bump version, releasing avrdude-5.5.
+
+2007-10-29 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Submitted by <bikenomad@gmail.com>:
+	patch #5007: Patch for line-buffering of stdout and stderr
+	* main.c: call setvbuf() for stdout and stderr.
+
+2007-10-29 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Submitted by <graceindustries@gmail.com>:
+	patch #5953: Add AT90CAN64 and AT90CAN32 to avrdude.conf
+	* avrdude.conf.in: Add entry for AT90CAN64 and AT90CAN32.
+
+2007-10-29 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Submitted by Wolfgang Moser:
+	patch #6121: ISP support for the C2N232I device (serial port
+	bitbanging)
+	* avrdude.conf.in: Add entry for c2n232i.
+
+2007-10-29 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Submitted by <karl.yerkes@gmail.com>:
+	patch #6141: accept binary format immediate values
+	* fileio.c: Detect a 0b prefix, and call strtoul() differently
+	in that case.
+
+2007-10-29 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	bug #21076: -vvvv serial receive prints are empty in Win32 build
+	* ser_win32.c (ser_recv): Drop the essentially unused variable
+	"len", and use the variable "read" in order to track how many
+	bytes have just been read in.
+
+2007-10-29 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	bug #21145: atmega329p not recognized
+	* avrdude.conf.in: Add definitions for the ATmega329P/3290P.
+	Same as ATmega329/3290 except of the different signature.
+
+2007-10-29 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	bug #21152: Unable to program atmega324p with avrdude 5.4 and AVRISP
+	using default configuration file.
+	* avrdude.conf.in: Uncomment the (bogus) stk500_devcode lines for
+	the ATmega164P, ATmega324P, ATmega644, and ATmega644P definitions.
+	This only affects users of STK500v1 firmware.
+
+2007-10-29 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Submitted by <ladyada@gmail.com>:
+	Patch #6233: Add support for USBtinyISP programmer
+	* usbtiny.c: New file.
+	* usbtiny.h: (Ditto.)
+	* Makefile.am: Include usbtiny into the build.
+	* avrdude.conf.in: (Ditto.)
+	* config_gram.y: (Ditto.)
+	* lexer.l: (Ditto.)
+	* avrdude.1: Document the usbtiny support.
+	* doc/avrdude.texi: (Ditto.)
+
+2007-10-29 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* doc/avrdude.texi: Sort list of supported programmers into
+	alphabetical order, add all missing programmers.
+
+2007-07-24 Thomas Fischl <tfischl@gmx.de>
+
+	* usbasp.c: Added long addresses to support devices with more
+        than 64kB flash. Closes bug #20558: Long address problem with
+        USBasp.
+
+2007-06-27 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* Makefile.am (EXTRA_DIST): Add ChangeLog-2004-2006.
+
+2007-05-16 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* configure.ac (AC_INIT): Bump version for post-release.
+
+2007-05-16 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* configure.ac (AC_INIT): Bump version, releasing avrdude-5.4.
+
+2007-05-16 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Fix AVR910 devcodes.  It seems that the AVR109
+	listing refers to "BOOT"-type code, while the standard codes are
+	different (usually one below).
+
+2007-05-16 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avr.c (avr_read, avr_write): only use the paged_load and
+	paged_write backend functions iff the memory area in question has
+	a page_size != 0.
+	This is supposed to fix bug #19234: avrdude-5.3.1 segfaults when
+	stk500v1 tries to program an ATtiny15
+
+2007-05-15 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avr910.c: Fall back to avr_{read,write}_byte_default().  Fixes
+	bug #18803: Fuse reading regression in avrdude 5.3.1 with avr910
+	programmer
+
+2007-05-15 Colin O'Flynn <coflynn@newae.com>
+
+	* avrdude.conf.in: Rename the ATmega164 and ATmega324 into
+	ATmega164P and ATmega324P, resp.  Add an entry for the ATmega644P.
+	Fixes bug #19769: ATmega164p not recognized
+
+2007-05-15 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* ser_posix.c (ser_send): Don't select() on the output fd before
+	trying to write something to the serial line.  That kind of
+	polling isn't very useful anyway, and it seems it breaks for the
+	Linux CP210x USB<->RS-232 bridge driver which is certainly a bug
+	in the driver, but we can just avoid that bug alltogether.
+
+2007-05-15 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Fix the STK500v2 ISP delay parameter for
+	ATmega640/1280/1281/2560/2561.  Atmel has changed the XML
+	files after the initial release.
+
+2007-05-01 Colin O'Flynn <coflynn@newae.com>
+
+	* safemode.c: -Oops - bug in verbose output. Fixed.
+	-Fixed handling of cases where programmer cannot read fuses (AVR910)
+	* main.c: -Also fixing handling of cases where programmer cannot
+	read fuses
+	This should close one or more bugs (18803, 19570)
+
+2007-05-01 Colin O'Flynn <coflynn@newae.com>
+
+	* safemode.c: Added verbose output from safemode routines.
+
+2007-03-25 Colin O'Flynn <coflynn@newae.com>
+
+	* stk500generic.c: Forgot to close the serial port before trying to
+	open it again, caused problems on Windows machines.
+	Closes bug #19411
+
+2007-02-26 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Add the AT90PWM2/3B devices.
+
+2007-02-02 Thomas Fischl <tfischl@gmx.de>
+
+	* usbasp.c: Changed return value of function usbasp_initialize to stop
+	avrdude on communication errors between programmer and target.
+	Closes bug #18581: safemode destroys fuse bits
+
+2007-02-01 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* config_gram.y: Remove duplicate definition of token K_WRITEPAGE
+
+2007-01-30 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* butterfly.c: Implement ATmega256x support for butterfly/avr109.
+
+2007-01-30 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* configure.ac: Fix subdir handling.  Now finally, "make
+	distcheck" will include the documentation into the tarball even if
+	the configure had been run without the --enable-doc.
+
+2007-01-30 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* safemode.c: Obtain progname from avrdude.h rather than trying to
+	roll our own (duplicate) copy of it.
+	* avr910.c: Constify char pointers.
+	* avrpart.c: (Ditto.)
+	* avrpart.h: (Ditto.)
+	* butterfly.c: (Ditto.)
+	* config.c: (Ditto.)
+	* config.h: (Ditto.)
+	* jtagmkI.c: (Ditto.)
+	* jtagmkII.c: (Ditto.)
+	* par.c: (Ditto.)
+	* pgm.c: (Ditto.)
+	* pgm.h: (Ditto.)
+	* serbb_posix.c: (Ditto.)
+	* serbb_win32.c: (Ditto.)
+	* stk500.c: (Ditto.)
+	* stk500v2.c: (Ditto.)
+	* usbasp.c: (Ditto.)
+
+2007-01-29 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrpart.c: More backend/library abstraction and generalization:
+	turn the list_parts() and list_programmers() functions into
+	general list iteration functions that call a caller-supplied
+	callback for each element.  Implement list_parts() and
+	list_programmers() as private functions in main.c based on that
+	approach.
+	* avrpart.h: (Ditto.)
+	* main.c: (Ditto.)
+	* pgm.c: (Ditto.)
+	* pgm.h: (Ditto.)
+
+2007-01-25 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* Makefile.am: Rearrange everything so it is now built into a
+	libavrdude.a library, and link main.c against that library.
+	* configure.ac: Add AC_PROG_RANLIB as we are building a library
+	now.
+
+2007-01-24 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Major code cleanup.
+	- Make all internal functions "static".
+	- Make sure each module's header and implementation file match.
+	- Remove all library-like functionality from main.c, so only
+	  the actual frontend remains in main.c.
+	- Add C++ brackets to all header files.
+	* avr.c: (Ditto.)
+	* avr.h: (Ditto.)
+	* avr910.c: (Ditto.)
+	* avr910.h: (Ditto.)
+	* avrdude.h: (Ditto.)
+	* avrpart.c: (Ditto.)
+	* avrpart.h: (Ditto.)
+	* bitbang.h: (Ditto.)
+	* butterfly.h: (Ditto.)
+	* config.c: (Ditto.)
+	* config.h: (Ditto.)
+	* confwin.h: (Ditto.)
+	* crc16.c: (Ditto.)
+	* crc16.h: (Ditto.)
+	* fileio.c: (Ditto.)
+	* fileio.h: (Ditto.)
+	* jtagmkI.h: (Ditto.)
+	* jtagmkII.h: (Ditto.)
+	* lexer.l: (Ditto.)
+	* lists.h: (Ditto.)
+	* main.c: (Ditto.)
+	* par.h: (Ditto.)
+	* pgm.c: (Ditto.)
+	* pgm.h: (Ditto.)
+	* ppi.c: (Ditto.)
+	* ppi.h: (Ditto.)
+	* safemode.h: (Ditto.)
+	* serbb.h: (Ditto.)
+	* serial.h: (Ditto.)
+	* stk500.h: (Ditto.)
+	* stk500v2.c: (Ditto.)
+	* stk500v2.h: (Ditto.)
+	* term.c: (Ditto.)
+	* term.h: (Ditto.)
+	* usbasp.h: (Ditto.)
+	* update.c: New file.
+	* update.h: New file.
+	* Makefile.am: Include update.c and update.h.
+
+2007-01-24 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Move all "extern" declarations into a centreal header file.
+	* Makefile.am: Add new avrdude.h.
+	* avrdude.h: New file.
+	* avr.c: Replace private extern decl's by #include "avrdude.h".
+	* avr910.c: (Ditto.)
+	* avrpart.c: (Ditto.)
+	* bitbang.c: (Ditto.)
+	* butterfly.c: (Ditto.)
+	* config.c: (Ditto.)
+	* config_gram.y: (Ditto.)
+	* fileio.c: (Ditto.)
+	* jtagmkI.c: (Ditto.)
+	* jtagmkII.c: (Ditto.)
+	* lexer.l: (Ditto.)
+	* main.c: (Ditto.)
+	* par.c: (Ditto.)
+	* pgm.c: (Ditto.)
+	* ppi.c: (Ditto.)
+	* ppiwin.c: (Ditto.)
+	* ser_avrdoper.c: (Ditto.)
+	* ser_posix.c: (Ditto.)
+	* ser_win32.c: (Ditto.)
+	* serbb_posix.c: (Ditto.)
+	* serbb_win32.c: (Ditto.)
+	* stk500.c: (Ditto.)
+	* stk500generic.c: (Ditto.)
+	* stk500v2.c: (Ditto.)
+	* term.c: (Ditto.)
+	* usb_libusb.c: (Ditto.)
+	* usbasp.c: (Ditto.)
+
+2007-01-13 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* avrdude.conf.in (ATmega8): Bump the delay values for flash
+	and EEPROM, based on the current Atmel XML file.
+
+2007-01-12 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* configure.ac: Improve the detection of the Win32 HID library,
+	and the presence of the header ddk/hidsdi.h.  It now works
+	correctly under Cygwin and several flavours of MinGW.
+	* Makefile.am: Add new LIBHID pattern.
+
+2007-01-11 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	* butterfly.c (butterfly_initialize): when sending the 'T'
+	command (which is ignored by current AVR109 bootloaders),
+	send the first reply from the list of supported device
+	codes back rather than using avrdude.conf's idea about
+	an AVR910 device code.  Apparently, this solves disagreements
+	between different versions of at least the ATmega8 AVR910
+	device code.
+	Closes bug #18727: Writing flash failed
+
+2007-01-07 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Reported by Till Harbaum:
+	* avrdude.conf.in (ATtiny25/45/85): Change HVSP reset from
+	500 microseconds to 1 ms, matching the most recent Atmel XML
+	specs.
diff --git a/avrdude/ChangeLog-2008 b/avrdude/ChangeLog-2008
new file mode 100644
index 00000000..f43a10ab
--- /dev/null
+++ b/avrdude/ChangeLog-2008
@@ -0,0 +1,185 @@
+2008-11-20  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* avrdude.h: Change the prototype for usleep() to be more Cygwin-
+	friendly.
+	* ppiwin.c: (Ditto.)
+
+2008-11-06  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Submitted by limor <limor@ladyada.net>
+	* usbtiny.c (usbtiny_cmd): Replace sizeof() by a fixed constant
+	4 for the result array, because otherwise it would take the size
+	of a pointer which miserably fails on 64-bit machines.
+
+2008-11-05  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	patch #6609: Using PCI parallel port cards on Windows
+	* ppiwin.c (ppi_open): If the port parameter passed from the
+	-p option is neither lpt1/2/3, try interpreting it directly as
+	a base address.
+	* avrdude.1: Document the change.
+	* doc/avrdude.texi: (Ditto.)
+
+2008-11-04  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	bug #22882: Erase Cycle Counter does not work for stk500v2
+	* stk500v2.c (stk500v2_chip_erase,stk500hv_chip_erase): Return
+	the expected 0 for success rather than a protocol-dependant
+	number.
+ 
+2008-11-04  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	bug #22883: Chip Erase performed even with no-write flag (-n)
+	* main.c: Do not erase the chip if both, -e and -n options have
+	been specified.
+
+2008-11-04  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	bug #24589: AT90USB64* have wrong signature
+	* avrdude.conf.in: Uncomment the correct, and delete the wrong
+	signature for AT90USB646/647.  Alas, the datasheet has never been
+	corrected for years.
+
+2008-10-31  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* jtagmkII.c: Fix a serious memory corruption that happened when
+	using the JTAG ICE mkII (or AVR Dragon) in ISP mode.  The wrong
+	set of per-programmer private data had been allocated (stk500v2
+	vs. jtagmkII) which was too small to hold the actual data.
+	* jtagmkII.h: (Ditto.)
+	* stk500v2.c: (Ditto.)
+
+2008-07-29  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* jtagmkII.c: Implement Xmega JTAG support.
+	* jtagmkII_private.h: Add EMULATOR_MODE_JTAG_XMEGA.
+
+2008-07-29  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* main.c: Remember whether the device initialization worked, and
+	allow to continue with -F if it failed yet do not attempt to
+	perform anything on the device itself.  That way, -tF could be
+	specified for programmers like the STK500/STK600 even without a
+	device connected, just in order to allow changing parameters on
+	the programmer itself.
+	* avrdude.1: Document that possible use of the -F option.
+	* doc/avrdude.texi: (Ditto.)
+
+2008-07-29  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* stk500v2.c (stk600_xprog_paged_write): Fix a fatal miscalculation
+	of the number of bytes to be written which caused a malloc chunk
+	corruption.
+
+2008-07-27  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	First implementation of ATxmega support.  By now, only the
+	PDI mode of the STK600 is supported.  Single-byte EEPROM
+	(and flash) updates do not work yet.
+	* avr.c: "boot" memory is a candidate memory region for paged
+	operations, besides "flash" and "eeprom".
+	* avrdude.conf.in: add ATxmega128A1 and ATxmega128A1revD
+	* avrpart.h: add the AVRPART_HAS_PDI flag (used to distinguish
+	ATxmega parts from classic AVRs), the nvm_base part field, and
+	the offset field for a memory region.
+	* config_gram.y: add "has_pdi", "nvm_base", and "offset"
+	* lexer.l: (Ditto.)
+	* main.c: disable auto_erase for ATxmega parts
+	* stk500v2.c: implement the XPROG functionality, and divert to
+	this for ATxmega parts
+	* avrdude.1: Document the changes.
+	* doc/avrdude.texi: (Ditto.)
+
+2008-07-25  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Fix a bunch of warnings.
+	* avr910.c (avr910_paged_load): possible unitialized use of
+	rd_size
+	* jtagmkI.c (jtagmkI_initialize): pointer signedness mixup
+	* jtagmkII.c (jtagmkII_print_parms1): propagate const'ness
+	of parameter
+	* usbasp.c (usbasp_transmit): pointer signedness mixup
+	* ser_avrdoper.c (usbGetReport): remove useless pointer deref
+
+2008-07-25  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Contributed by Ville Voipio:
+	patch #6501: New autotools support for avrdude
+	* Makefile.am: add @WINDOWS_DIRS@ to SUBDIR
+	* bootstrap: allow for autconf-2.61 and automake-1.10, too
+	* configure.ac: fix @WINDOWS_DIRS@ recursion, replace
+	AC_PROG_CC by AM_PROG_CC_C_O, for esoteric reasons
+
+2008-06-13  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Contributed by Janos Sallai <janos.sallai@vanderbilt.edu>:
+	patch #6074: added support for crossbow's MIB510 programmer
+	* avrdude.conf.in: Add entry for mib510.
+	* stk500.c: Add special hooks to handle the MIB510 programmer.
+	It mostly talks STK500v1 protocol but has a special hello and
+	goodbye sequence, and uses a fixed block size of 256 bytes.
+	* doc/avrdude.texi: Document support for mib510.
+
+2008-06-07  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Contributed by Klaus Leidinger <klaus@mikrocontroller-projekte.de>:
+	* main.c: Realign verbose messages.
+	* avrpart.c: (Ditto.)
+	* avr910.c: Print the device code selected in verbose mode.
+	* butterfly.c: (Ditto.)
+
+2008-06-07  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Contributed by Klaus Leidinger <klaus@mikrocontroller-projekte.de>:
+	Add check for buffermode feature, and use it if present.  Can be
+	turned off using -x no_blockmode.
+	* avr910.c: Implement buffermode test and usage.
+	* avrdude.1: Document -x no_blockmode.
+	* doc/avrdude.texi: (Ditto.)
+
+2008-03-24  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* usb_libusb.c: #undef interface for Win32
+
+2008-03-24  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* avr910.c: Add support for the -x devcode option.
+	* avrdude.1: Document -x devcode for avr910.
+	* doc/avrdude.texi: (Ditto.)
+
+2008-03-14  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Add initial support for the Atmel STK600, for
+	"classic" AVRs (AT90, ATtiny, ATmega) in both,
+	ISP and high-voltage programming modes.
+	* Makefile.am: Add -lm.
+	* avrdude.conf.in: Add stk600, stk600pp, and stk600hvsp.
+	* config_gram.y: Add support for the stk600* keywords.
+	* lexer.l: (Ditto.)
+	* pgm.h: Add the "chan" parameter to set_varef().
+	* stk500.c: (Ditto.)
+	* serial.h: Add USB endpoint support to struct filedescriptor.
+	* stk500v2.c: Implement the meat of the STK600 support.
+	* stk500v2.h: Add new prototypes for stk600*() programmers.
+	* stk500v2_private.h: Add new constants used in the STK600.
+	* term.c: Add AREF channel support.
+	* usb_libusb.c: Automatically determine the correct write
+	endpoint ID, the STK600 uses 0x83 while all other tools use
+	0x82.  Propagate the EP to use through struct filedescriptor.
+	* usbdevs.h: Add the STK600 USB product ID.
+	* tools/get-stk600-cards.xsl: XSL transformation for
+	targetboards.xml to obtain the list of socket and routing
+	card IDs, to be used in stk500v2.c (for displaying the
+	names).
+	* tools/get-stk600-devices.xsl: XSL transformation for
+	targetboards.xml to obtain the table of socket/routing cards
+	and their respective AVR device support for doc/avrdude.texi.
+	* avrdude.1: Document all the STK600 stuff.
+	* doc/avrdude.texi: Ditto.  Added a new chapter for
+	Programmer Specific Information.
+
+2008-01-26  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* stk500v2.c (stk500v2_recv): Make length computation unsigned so
+	it cannot accidentally become negative.
+
diff --git a/avrdude/ChangeLog-2009 b/avrdude/ChangeLog-2009
new file mode 100644
index 00000000..1f993cbc
--- /dev/null
+++ b/avrdude/ChangeLog-2009
@@ -0,0 +1,411 @@
+2009-11-09  David Hoerl <dhoerl@mac.com>
+
+	* fileio.c: ihex2bin did not properly handle files > 64K bytes
+	* usb_libusb.c: re-enabled usb_reset for Macs (no reset causes lots of failures)
+	* avrdude.1: spacing issue for avr32 fixed.
+
+2009-11-09  Michal Ludvig  <mludvig@logix.net.nz>
+
+	* buspirate.c: Implemented reset= and speed= extended parameters.
+	* avrdude.1: Document the change.
+
+2009-11-04  Michal Ludvig  <mludvig@logix.net.nz>
+
+	* configure.ac, Makefile.am: Test if GCC accepts -Wno-pointer-sign
+
+2009-11-04  Michal Ludvig  <mludvig@logix.net.nz>
+
+	* buspirate.c: Implemented 'BinMode' support for
+	  firmware 2.7 and higher.
+	* avrdude.1: Added info about BusPirate.
+
+2009-11-03  Michal Ludvig  <mludvig@logix.net.nz>
+
+	* arduino.c: Add on to bug #26703 / patch #6866 - clear DTR/RTS
+	  when closing the port.
+	* Makefile.am: Silent warnings about signedness - they're useless
+	  and annoying, especially for 'char' vars.
+
+2009-10-22  David Hoerl <dhoerl@mac.com>
+
+	* usb_libusb.c: disabled usb_reset for Macs (same as FreeBSD)
+
+2009-10-12  Michal Ludvig  <mludvig@logix.net.nz>
+
+	* main.c: Re-added default to serial port for BusPirate.
+
+2009-10-12  David Hoerl <dhoerl@mac.com>
+
+	*  main.c: removed some avr32 code that was pushed into jtagmkII.c
+	*  jtagmkII.c: consolodated the avr32 reset code and avr32_chipreset
+	*  avrpart.h: modified AVRPART flags for avr32
+	*  lexer.l: added is_avr32 flag - only way to get yacc code to set flag
+	*  avrdude.conf.in: updated avr32 section to include "is_avr32" flag
+
+2009-10-12  David Hoerl <dhoerl@mac.com>
+
+	*  config_gram.y: Restored inadvertantly removed buspirate entry
+	*  lexer.l: Restored inadvertantly removed buspirate entry
+
+2009-10-12  Michal Ludvig  <mludvig@logix.net.nz>
+
+	* buspirate.c: Replace GNU-only %as with %s in sscanf call.
+	* ser_win32.c(ser_set_dtr_rts): Fixed typo in parameter name.
+	* NEWS: Announce BusPirate.
+
+2009-10-11  David Hoerl <dhoerl@mac.com>
+
+	Support for AVR32
+
+	* AUTHORS: added myself
+	* NEWS: announced AVR32 support
+	* main.c: AVR32 flag tests to avoid several code blocks
+	* fileio.c: mods to ihex read function to handle address offsets and 
+	  size of avr32
+	* jtagmkI.c: added cast to printf call to remove warning
+	* arduino.c: added header file to bring in prototype for usleep()
+	* config_gram.y: added defines for avr32, new jtag_mkii variant for avr32
+	* jtagmkII_private.h: new jtag_mkii message types defined (used by
+	  avr32program)
+	* jtagmkII.h: extern jtagmkII_avr32_initpgm() addition
+	* jtagmkII.c: huge amount of code in support of avr32
+	* avrpart.h: additional flags to AVRPART for avr32
+	* usb_libusb.c: modified verbose test for USB read per-byte messages by
+	  by one, so with verbose=3 you get just full messages, 4 gives you bytes
+	  too
+	* lexer.l: additions for avr32
+
+2009-10-10  Michal Ludvig  <mludvig@logix.net.nz>
+
+	Support for Arduino auto-reset:
+	* serial.h, ser_avrdoper.c, ser_posix.c, ser_win32.c: Added 
+	  serial_device.set_dtr_rts implementations.
+	* arduino.c, stk500.c, stk500.h: Call serial_set_dtr_rts()
+	  to reset Arduino board before program upload.
+	Inspired by patch #6866, resolves bug #26703
+
+2009-10-08  Michal Ludvig  <mludvig@logix.net.nz>
+
+	* buspirate.c: Optimised buspirate_cmd() - reading 1kB EEPROM now
+	  takes only 14 sec instead of almost 2 mins with the original
+	  implementation.
+
+2009-10-08  Michal Ludvig  <mludvig@logix.net.nz>
+
+	* buspirate.c, buspirate.h: Support for the BusPirate programmer
+	* config_gram.y, avrdude.conf.in, main.c, lexer.l, Makefile.am:
+	  Glue for BusPirate.
+
+2009-08-17  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* usb_libusb.c (usbdev_close): Repair the logic around the
+	conditional compilation of usb_reset() introduced in r798.
+
+2009-07-11  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* configure.ac: We are post-5.8 now.
+
+2009-07-11  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* configure.ac: Prepare for releasing version 5.8
+
+2009-07-11  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Submitted by Roger Wolff:
+	bug #26527: bug in unicode conversion
+	* ser_avrdoper.c (convertUniToAscii): when encountering a UTF-16
+	character that cannot be converted to ASCII, increment the UTF-16
+	pointer anyway when proceeding.
+
+2009-07-11  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* jtagmkI.c (jtagmkI_send): Replace %zd format by %u since not all
+	implementations do understand the C99 formatting options (sigh).
+	* jtagmkII.c (jtagmkII_send): (Ditto.)
+	* stk500v2.c (stk500v2_recv): (Ditto.)
+
+2009-07-11  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	bug #26002: HVPP of EEPROM with AVR Dragon and ATmega8 Fails
+	* avrdude.conf.in (ATmega8): add page size for EEPROM.
+
+2009-07-07  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* stk500v2.c: Fix a serious memory corruption problem resulting
+	out of the chaining of both, the stk500v2 and the jtagmkII
+	programmers for some programming hardware (JTAG ICE mkII and AVR
+	Dragon running in ISP, HVSP or PP mode), where both programmers
+	have to maintain their private programmer data.
+
+2009-07-02  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* configure.ac: Post-release (is pre-release...)
+
+2009-07-02  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* configure.ac: Prepare for releasing version 5.7
+
+2009-07-02  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* main.c: Add my name to the copyright output when being verbose.
+
+2009-07-02  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Contributed by Shaun Jackman  <sjackman@gmail.com>
+	bug #21798: Fix both XSLT scripts
+	* tools/get-dw-params.xsl (format-hex): Add the parameter count.
+	* tools/get-hv-params.xsl (format_cstack): Ditto.
+
+2009-07-02  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	bug #21922: ATmega163 still not working in version 5.5
+	* avrdude.conf.in (atmega163): fill in stk500v2 parameters, correct
+	some flash programming parameters as well.
+
+2009-07-02  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	bug #22206: avrdude: ser_setspeed(): tcsetattr() failed
+	* ser_posix.c (ser_setspeed): Don't pass TCSAFLUSH to tcsetattr() as
+	it apparently fails to work on Solaris.  After reading the
+	documentation again, it seems TCSAFLUSH and TCSANOW are indeed
+	mutually exclusive.
+
+2009-07-02  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	bug #22234: WINDOWS version: HOWTO: Specify Serial Ports Larger than COM9
+	* ser_win32.c (ser_open): prepend \\.\ to any COM port name, so it is
+	safe to be used for COM ports above 9.
+
+2009-07-02  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	bug #26408: Crash in stk500v2_open()
+	* stk500generic.c: Implement setup and teardown hooks, calling in turn
+	the respective hooks of the stk500v2 implementation.
+
+2009-07-02  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	bug #26130: Avrdude doesn't display it's version.
+	* main.c (usage): add a version number display to the default usage
+	message.
+
+2009-07-01  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	bug #26412: avrdude segfaults when called with a programmer that does not
+	support it
+	* main.c: do not call pgm->perform_osccal() unless it is != 0.
+
+2009-06-24  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Contributed by Zoltan Laday:
+	patch #6825: xmega problems with JTAGICEmkII
+	* jtagmkII.c: Many fixes for Xmega devices.
+	* jtagmkII_private.h: Add various new constants required for
+	Xmega devices.
+	* avrdude.conf.in: New devices: ATXMEGA64A1, ATXMEGA192A1,
+	ATXMEGA256A1, ATXMEGA64A3, ATXMEGA128A3, ATXMEGA192A3,
+	ATXMEGA256A3, ATXMEGA256A3B, ATXMEGA16A4, ATXMEGA32A4,
+	ATXMEGA64A4, ATXMEGA128A4
+	* avr.c (avr_read, avr_write): Add more names for (Xmega)
+	memory areas that require paged operation.
+
+2009-06-24  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* stk500v2.c (stk600_xprog_write_byte): Handle writing fuse bytes.
+
+2009-04-28  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Submitted by Carl Hamilton:
+	* update.c (parse_op): correctly \0-terminate buf after filling
+	it, before it is potentially used as the source of a call to
+	strlen or strcpy.
+
+2009-04-14  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* doc/avrdude.texi: Merge the -P 0xXXX option description from
+	avrdude.1.
+
+2009-04-14  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* configure.ac: declare AM_PROG_CC_C_O to avoid the warning
+	"compiling `config_gram.c' with per-target flags
+	requires `AM_PROG_CC_C_O' in `configure.ac'"
+
+2009-03-22  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	bug #25971: "error writing to <stdout>" with multiple -U params.
+	* fileio.c: Do not close the input/output stream when working on an
+	stdio stream.
+
+2009-02-28  Thomas Fischl <tfischl@gmx.de>
+
+	Based on patch #6484 commited by Jurgis Brigmanis:
+	* usbasp.c: added software control for ISP speed
+	* usbasp.h: (Ditto.)
+
+2009-02-28  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* avr910.c (avr910_read_byte_flash): Eliminate a static variable that
+	hasn't been in use for 5 years.
+
+2009-02-27  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* configure.ac: Post-release 5.6.
+
+2009-02-27  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* configure.ac: Prepare for releasing version 5.6.
+
+2009-02-27  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Submitted by Ed Okerson:
+	* jtagmkII.c (jtagmkII_read_byte): Fix signature reading of
+	Xmega.
+
+2009-02-26  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Submitted by Mikael Hermansson:
+	* avrdude.conf.in (ATxmega256A3): new device.
+	* stk500v2 (stk500v2_initialize): Enable the AVRISPmkII as a
+	PDI-capable device for ATxmega parts.
+
+2009-02-25  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Submitted by Lars Immisch:
+	patch #6750: Arduino support - new programmer-id
+	* arduino.c: New file, inherits stk500.c.
+	* arduino.h: New file.
+	* Makefile.am: Add arduino.c and arduino.h.
+	* config_gram.y: Add arduino keyword.
+	* lexer.l: (Ditto.)
+	* avrdude.conf.in: (Ditto.)
+	* avrdude.1: Document the new programmer type.
+	* doc/avrdude.texi: (Ditto.)
+
+2009-02-25  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* stk500v2.c: Turn all non-const static data into instance data.
+
+2009-02-25  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* Makefile.am: Move term.[ch] from the library into the CLI
+	application section, as it is not useful for anything else but
+	the CLI frontend.
+
+2009-02-25  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* avrdude.conf.in (ATmega1284P): new device.
+
+2009-02-23  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	More fixes for Solaris, including fixes for the Sunpro compiler:
+	* avr.h: Remove stray semicolon.
+	* configure.ac: Add check for predefined types uint_t and ulong_t.
+	* confwin.c: Include "avrdude.h" on top to avoid empty translation
+	unit warning.
+	* ppwin.c: (Ditto.)
+	* ser_win32.c: (Ditto.)
+	* serbb_win32.c: (Ditto.)
+	* jtagmkII.c (jtagmkII_recv): remove unreachable "return".
+	* stk500.c (stk500_initialize): (Ditto.)
+	* par.c: Test for both, __sun__ and __sun to see whether we are
+	being compiled on Solaris.
+	* ppi.c: (Ditto.)
+	* stk500v2.c: Implement the DEBUG and DEBUGRECV macros in a way
+	that is compatible with the ISO C99 standard.
+	* usbtiny.c: Only typedef uint_t and ulong_t if they have not
+	been found already by the autoconf checks.
+
+2009-02-23  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	bug #22204: Solaris10/11 Undefiniertes Symbol gethostbyname socket
+	connect
+	* configure.ac: Add checks for gethostent() and socket().
+	While being here, remove some old cruft left from ancient days.
+
+2009-02-22  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* lexer.l: Bump the %p size so AT&T lex will continue to work.
+
+2009-02-19  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	(Partially) submitted by John Voltz:
+	bug #20004: AVRDUDE update (-U) operations do not close files
+	* fileio.c (fmt_autodetect, fileio): fclose() files.
+
+2009-02-18  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* usbtiny.c: Replace all but one (very unlikely to trigger) exit(1)
+	by return -1.
+
+2009-02-18  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Submitted by Dick Streefland:
+	patch #6749: make reading from the USBtinyISP programmer more robust
+	* usbtiny.c: Add code to retry failed communication attempts.
+
+2009-02-17  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Submitted by Nick Hibma:
+	bug #22271: usb_reset in usb_libusb.c not necessary in FreeBSD 6.x
+	* usb_libusb.c (usbdev_close): Do not call usb_reset() on FreeBSD.
+	It is not necessary there.
+
+2009-02-17  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Submitted by Andrew O. Shadoura:
+	bug #25156: add direct SPI transfer mode
+	* bitbang.c: Implement direct SPI transfers.
+	* bitbang.h: (Ditto.)
+	* par.c: (Ditto.)
+	* pgm.c: (Ditto.)
+	* pgm.h: (Ditto.)
+	* term.c: Add the "spi" and "pgm" commands.
+	* avrdude.1: Document the changes.
+	* doc/avrdude.texi: (Ditto.)
+
+2009-02-17  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Submitted by Limor ("Lady Ada"):
+	bug #24749: add support for '328p
+	* avrdude.conf.in (ATmega328P): new device support.
+
+2009-02-17  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Submitted by "Womo":
+	bug #25241: AT90USB162, AT90USB82 device support patch for avrdude-5.5
+	(also: bug #21745: AT90USBxx2 support)
+	* avrdude.conf.in (AT90USB162, AT90USB82): new device support.
+
+2009-02-17  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Submitted by Evangelos Arkalis:
+	patch #6069: Atmel AT89ISP Cable
+	* avrdude.conf.in (89isp): new programmer support.
+
+2009-02-16  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Submitted by Bob Paddock:
+	patch #6748: ATTiny88 Config
+	* avrdude.conf.in (ATtiny88): new device support.
+
+2009-02-16  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Submitted by Mark Litwack:
+	patch #6261: avrdude won't use dragon/debugwire to write a file
+	to eeprom
+	* jtagmkII.c (jtagmkII_paged_write): when in debugWire mode,
+	implement a paged write to EEPROM as a series of byte writes.
+
+2009-02-16  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Submitted by Janos Sallai:
+	patch #6542: paged_load fails on the MIB510 programming board
+	* stk500.c: Add a workaround for the different signon sequence on
+	MIB510 programmers.
+
+2009-02-05  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	* avrdude.conf.in: Add the ATmega128RFA1.
+	* avrdude.1: document the addition of ATmega128RFA1.
+	* doc/avrdude.texi: (Ditto.)
+
diff --git a/avrdude/Makefile.am b/avrdude/Makefile.am
new file mode 100644
index 00000000..9a68852d
--- /dev/null
+++ b/avrdude/Makefile.am
@@ -0,0 +1,169 @@
+#
+# avrdude - A Downloader/Uploader for AVR device programmers
+# Copyright (C) 2003, 2004  Theodore A. Roth  <troth@openavr.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+#
+# $Id$
+#
+
+EXTRA_DIST   = \
+	ChangeLog \
+	ChangeLog-2001 \
+	ChangeLog-2002 \
+	ChangeLog-2003 \
+	ChangeLog-2004-2006 \
+	avrdude.1 \
+	avrdude.spec \
+	bootstrap
+
+CLEANFILES = \
+	config_gram.c \
+	config_gram.h \
+	lexer.c
+
+#SUBDIRS      = doc @WINDOWS_DIRS@
+#DIST_SUBDIRS = doc windows
+
+SUBDIRS = @SUBDIRS_AC@
+SUBDIRS += @WINDOWS_DIRS@
+DIST_SUBDIRS = @DIST_SUBDIRS_AC@
+
+AM_YFLAGS    = -d
+
+avrdude_CPPFLAGS = -DCONFIG_DIR=\"$(sysconfdir)\"
+
+libavrdude_a_CPPFLAGS = -DCONFIG_DIR=\"$(sysconfdir)\"
+
+avrdude_CFLAGS   = @ENABLE_WARNINGS@
+
+libavrdude_a_CFLAGS   = @ENABLE_WARNINGS@
+
+avrdude_LDADD  = $(top_builddir)/$(noinst_LIBRARIES) @LIBUSB@ @LIBHID@ -lm
+
+bin_PROGRAMS = avrdude
+
+noinst_LIBRARIES = libavrdude.a
+
+# automake thinks these generated files should be in the distribution,
+# but this might cause trouble for some users, so we rather don't want
+# to have them there.
+#
+# See
+#
+# https://savannah.nongnu.org/bugs/index.php?func=detailitem&item_id=15536
+#
+# for why we don't want to have them.
+dist-hook:
+	rm -f \
+	$(distdir)/lexer.c \
+	$(distdir)/config_gram.c \
+	$(distdir)/config_gram.h
+
+libavrdude_a_SOURCES = \
+	config_gram.y \
+	lexer.l \
+	arduino.h \
+	arduino.c \
+	avr.c \
+	avr.h \
+	avr910.c \
+	avr910.h \
+	avrdude.h \
+	avrpart.c \
+	avrpart.h \
+	bitbang.c \
+	bitbang.h \
+	buspirate.c \
+	buspirate.h \
+	butterfly.c \
+	butterfly.h \
+	config.c \
+	config.h \
+	confwin.c \
+	confwin.h \
+	crc16.c \
+	crc16.h \
+	fileio.c \
+	fileio.h \
+	freebsd_ppi.h \
+	jtagmkI.c \
+	jtagmkI.h \
+	jtagmkI_private.h \
+	jtagmkII.c \
+	jtagmkII.h \
+	jtagmkII_private.h \
+	linux_ppdev.h \
+	lists.c \
+	lists.h \
+	my_ddk_hidsdi.h \
+	par.c \
+	par.h \
+	pgm.c \
+	pgm.h \
+	pindefs.h \
+	ppi.c \
+	ppi.h \
+	ppiwin.c \
+	safemode.c \
+	safemode.h \
+	serial.h \
+	serbb.h \
+	serbb_posix.c \
+	serbb_win32.c \
+	ser_avrdoper.c \
+	ser_posix.c \
+	ser_win32.c \
+	solaris_ecpp.h \
+	stk500.c \
+	stk500.h \
+	stk500_private.h \
+	stk500v2.c \
+	stk500v2.h \
+	stk500v2_private.h \
+	stk500generic.c \
+	stk500generic.h \
+	usbasp.c \
+	usbasp.h \
+	usbdevs.h \
+	usb_libusb.c \
+	usbtiny.h \
+	usbtiny.c \
+	update.h \
+	update.c
+
+avrdude_SOURCES = \
+	main.c \
+	term.c \
+	term.h
+
+man_MANS = avrdude.1
+
+sysconf_DATA = avrdude.conf
+
+install-exec-local: backup-avrdude-conf
+
+distclean-local:
+	rm -f avrdude.conf
+
+# This will get run before the config file is installed.
+backup-avrdude-conf:
+	@echo "Backing up avrdude.conf in ${DESTDIR}${sysconfdir}"
+	@if test -e ${DESTDIR}${sysconfdir}/avrdude.conf; then \
+		cp -pR ${DESTDIR}${sysconfdir}/avrdude.conf \
+			${DESTDIR}${sysconfdir}/avrdude.conf.bak; \
+	fi
diff --git a/avrdude/NEWS b/avrdude/NEWS
new file mode 100644
index 00000000..9d65c887
--- /dev/null
+++ b/avrdude/NEWS
@@ -0,0 +1,544 @@
+$Id$
+
+Approximate change log for AVRDUDE by version.
+
+(For more detailed changes, see the ChangeLog file.)
+
+----------------------------------------------------------------------
+Version 5.9:
+
+  * New devices supported:
+
+      - AVR32A0512 (JTAGMKII only)
+      - ATmega32U4
+      - ATtiny4
+      - ATtiny5
+      - ATtiny9
+      - ATtiny10
+
+  * New programmers supported:
+
+      - BusPirate
+      - Arduino
+      - JTAGICEmkII and AVR Dragon in PDI mode (ATxmega devices)
+      - STK600 and AVRISP mkII in TPI mode (ATtiny4/5/9/10)
+
+  * Bugfixes
+
+      - see ChangeLog and ChangeLog-2009 for details
+
+Version 5.8:
+
+  * Bugfixes; most importantly, fix a serious memory corruption for
+    that JTAG ICE mkII and AVR Dragon in ISP/HVSP/PP mode.
+
+Version 5.7:
+
+  * New devices supported:
+
+      - ATXMEGA64A1
+      - ATXMEGA192A1
+      -	ATXMEGA256A1
+      - ATXMEGA64A3
+      - ATXMEGA128A3
+      - ATXMEGA192A3
+      -	ATXMEGA256A3
+      - ATXMEGA256A3B
+      - ATXMEGA16A4
+      - ATXMEGA32A4
+      - ATXMEGA64A4
+      - ATXMEGA128A4
+
+  * Major Xmega fixes for the JTAG ICE mkII (patch #6825)
+
+  * Bugfixes.
+
+Version 5.6:
+
+  * New devices supported:
+
+      - AT90USB82
+      - AT90USB162
+      - ATtiny88
+      - ATmega328P
+      - ATmega1284P
+      - ATmega128RFA1
+      - ATxmega128A1 rev D
+      - ATxmega128A1
+      - ATxmega256A3
+
+  * New programmers supported:
+
+      - AT89ISP cable (patch #6069)
+      - Arduino
+
+  * Add support for the -x option to pass extended parameters to the
+    programmer backend.
+
+  * Add support for JTAG daisy-chains, using the -x daisychain=
+    option.
+
+  * Add support for the Atmel STK600 for "classic" AVRs (AT90, ATtiny,
+    ATmega), using either ISP or high-voltage programming modes.
+
+  * Add support for the -x devcode extended parameter to the avr910
+    programmer, to allow overriding the device code sent to the
+    programmer.
+
+  * Add support for the Crossbow MIB510 programmer (patch #6074, #6542).
+
+  * Add support to bootstrap with GNU autoconf 2.61, and automake 1.10,
+    respectively.
+
+  * Add support for ATxmega128A1 (including the revision D engineering
+    samples) for STK600 and AVRISPmkII tools using PDI
+
+  * The option combination -tF now enters terminal mode even if the
+    device initialization failed, so the user can modify programmer
+    parameters (like Vtarget).
+
+  * Add preliminary support for ATxmega128A1 for the JTAG ICE mkII using
+    JTAG.
+
+  * Add support for direct SPI transfers (bug #25156).
+
+  * Bugfixes.
+
+Version 5.5:
+
+  * Add support for the USBtinyISP programmer (patch #6233)
+
+  * Add support for the C2N232I serial bitbang programmer (patch #6121)
+
+  * Bugfixes.
+
+Version 5.4:
+
+  * New devices supported:
+
+      - AT90PWM2B/AT90PWM3B
+
+  * Bugfixes.
+
+  * Source code rearranged so that the functionality is now built
+    into a libavrdude.a library where main.c is currently the only
+    existing frontend.
+
+  * Implement ATmega256x support for butterfly/avr109.
+
+Version 5.3.1:
+
+  * Add support for the AVR Dragon (all modes: ISP, JTAG, HVSP, PP,
+    debugWire).
+
+  * Add support for debugWire (both, JTAG ICE mkII, and AVR Dragon).
+
+  * Add support for the AVR Doper USB HID-class programmer.
+
+  * Bugfixes.
+
+Version 5.2:
+
+  * New devices supported:
+
+      - AT90USB646/647/1286/1287
+      - ATmega2560/2561
+      - ATmega325/3250/645/6450
+      - ATtiny11 (HVSP only device)
+      - ATtiny261/461/861
+
+  * Fixed paged flash write operations for AT90PWMx devices
+    (error in datasheet).
+
+  * Add signature verification.
+
+  * Add high-voltage mode programming for the STK500 (both,
+    parallel, and high-voltage serial programming).
+
+  * Add support for using the JTAG ICE mkII as a generic ISP
+    programmer.
+
+  * Allow for specifying the ISP clock delay as an option for
+    bit-bang programming adapters.
+
+  * Add support for Thomas Fischl's USBasp low-cost USB-attached
+    programmer.
+
+  * The "stk500" programmer type is now implemented as a stub
+    that tries to probe for either "stk500v1" or "stk500v2".
+
+  * Many bugfixes.
+
+Version 5.1:
+
+  * New devices supported:
+
+      - ATmega640/1280/1281
+      - ATtiny24/44/84
+
+  * JTAG mkII support now works with libusb-win32, too
+
+  * JTAG ICE mkI support has been added
+
+  * Solaris support has been added (including ecpp(7D) parallel-port
+    bit-bang mode)
+
+
+Version 5.0:
+
+  * Support for JTAGICE MkII device
+
+  * Support for STK500 Version 2 Protocol
+
+  * New devices supported:
+
+      - AT90CAN128
+      - ATmega329x/649x
+      - ATmega164/324/644
+      - AT90PWM2/3,
+      - ATmega164/324/644
+      - ATmega329x/649x
+      - ATtiny25/45/85
+
+  * Support for serial bit-bang adapters: Ponyprog serial, UISP DASA,
+    UISP DASA3.
+
+  * DAPA programmer pinout supported
+
+  * New "safemode" feature where fuse bits are verified before exit
+    and if possible recovered if they have changed.  This is intended
+    to protect against changed fuses which were not requested which is
+    reported to sometimes happen due to improper power supply or other
+    reasons.
+
+  * Various fixes for avr910 and butterfly programmers
+
+  * Full support for AVR109 boot loaders (butterfly)
+
+  * Adding -q -q suppresses most terminal output
+
+
+Version 4.4.0:
+
+  * Native Win32 support: The windows build doesn't need Cygwin
+    anymore. Additionally, the delay timing on windows should be
+    more accurate now.
+    Contributed by Martin Thomas
+
+  * Add support for
+    - ATmega48, ATmega88 (contributed by Galen Seitz)
+    - ATtiny2313 (contributed by Bob Paddock)
+    - ATtiny13 (contributed by Pawel Moll)
+
+  * Added command to change the SCK of STK500-programmers. Now it
+    is possible to program uC with slow oscillator.
+    Contributed by Galen Seitz
+
+  * Baudrate for serial programmers (STK500 and AVR910) is
+    configurable in the config or at the command-line.
+    This way some more tweaked bootloaders and programmers can be used.
+
+  * Deprecated options have been removed.
+    Now the "-U" option must be used.
+
+  * MacOS X now supported by default.
+
+Version 4.3.0:
+
+  * Added support for "Butterfly" evaluation board.
+
+  * Make cycle-count work with AVR910-programmers.
+
+  * Added "Troubleshooting"-Appendix to the manual.
+
+  * Add ATmega8515 support.
+    Contributed by: Matthias Wei�er <matthias@matwei.de>
+
+  * Add ATmega64 support.
+    Contributed by: Erik Christiansen <erik@dd.nec.com.au>
+
+  * Improved polling algorithm to speed up
+    programming of byte oriented parallel programmers.
+    Contributed by: Jan-Hinnerk Reichert <jan-hinnerk_reichert@hamburg.de>
+
+  * Add "fuse" and "lock" definitions for the AT90S8535.
+
+  * STK500 skips empty pages in paged write resulting in faster downloads
+    when there are empty blocks in between code (such as files that contain
+    application code and bootloader code).
+
+Version 4.2.0:
+
+  * Add basic support for reading and writing fuses via SPI with avr910
+    programmers. Submitted by
+    Jan-Hinnerk Reichert <jan-hinnerk_reichert@hamburg.de>.
+
+  * Perform an auto erase before programming if the flash memory is
+    anywhere specified to be written by any of the -U requests.  Old
+    style memory specification options (-f, -i, -I, -m, and -o) are
+    deprecated in favor of the new -U options.  Auto erase is disabled
+    if any of the old-style options (specifically -i and -o) are
+    specified.
+
+  * Add new -U option for specifying programming operations - allows
+    multiple memory operations on a single command line.
+
+  * New progress reporting, looks nicer and is nicer to wrapper
+    environments such as emacs.
+
+  * Fix long-standing timing (verify) problems on Windows platform.
+    Submitted by Alex Shepherd <ashepherd@wave.co.nz>.
+
+  * Add new file format option - 'm' for "immediate mode."  In this
+    case, the filename argument of the -o, -i, or -U options is
+    treated as the data for uploading - useful for specifying fuse
+    bits without having to create a single-byte file for uploading.
+
+  * Add support for displaying and setting the various STK500 operational
+    parameters (Vtarget, Varef, Master clock).
+
+  * Add 'picoweb' programming cable programmer.
+    Contributed by Rune Christensen <rune.christensen@adslhome.dk>.
+
+  * Add support for the sp12 programmer.  Submitted by
+    Larry Barello <larryba@barrello.net>.
+
+
+Version 4.1.0
+
+  * Add support for the Bascom SAMPLE programmer. Submitted by
+    Larry Barello <larryba@barrello.net>.
+
+  * Add support for avr910 type programmers (mcu00100, pavr avr910, etc).
+
+  * Support new devices: ATmega8535, ATtiny26
+  
+
+Version 4.0.0
+
+  * Now support Linux - added by "Theodore A. Roth" <troth@openavr.org>.
+
+  * Now support Windows - added by "Eric B. Weddington" <eric@ecentral.com>.
+
+  * Use 'configure' scripts to tailor the code to the system avrdude
+    is getting ready to be compiled on - added by "Theodore A. Roth"
+    <troth@openavr.org>.
+
+  * Motorola S-Record support - submitted by "Alexey V.Levdikov "
+    <tsar@kemford.com>.
+
+  * Support parallel programming on the STK500.  Introduce 'pagel' and
+    'bs2' keywords to the config file for this purpose.
+
+  * Add support for the AT90S2343
+
+  * Add support for the ATmega169
+
+  * Add ability to specify system defaults within the config file
+    (default parallel port, default serial port).
+
+  * Specify the default programmer seperately from the programmer
+    definition.  This is now done in the config file using the
+    'default_programmer' keyword.
+
+  * Support a per-user config file (~/.avrduderc) so that one can
+    override system wide defaults if desired.
+
+  * Follow the datasheet more closely for several parts in the "retry"
+    code when entering programming mode fails initially.  Introduce
+    'retry_pulse' to the config file for this purpose.
+
+
+
+Version 3.1.0
+
+  * This change represents a name change only.  There is currently an
+    effort to port AVRPROG to other platforms including Linux and
+    Windows.  Since Atmel's programmer binary that's included within
+    their AVR Studio software is named AVRPROG.EXE on the Windows OS,
+    there is the chance for confusion if we keep calling this program
+    AVRPROG as well.  Up until now the name hasn't really been a
+    problem since there was no chance to confuse 'avrprog' on Unix
+    with Atmel's AVRPROG because Atmel's tools only run on Windows.
+    But with the Unix 'avrprog' possibly being ported to Windows, I
+    felt a name change was the best way to avoid problems.
+
+    So - from this point forward, my FreeBSD Unix program formerly
+    known as AVRPROG will subsequently be known as AVRDUDE (AVR
+    Downloader/UploaDEr).
+
+    This change also represents a time when the AVRDUDE sources move
+    from my own private repository to a public repository.  This will
+    give other developers a chance to port AVRDUDE to other platforms
+    and extend its functionality to support additional programming
+    hardware, etc.
+
+    So goodbye AVRPROG, welcome AVRDUDE!
+
+Version 3.0.0
+
+  * Rewrite parts of the code to make it easy to support other types
+    of programmers besides the directly connected parallel port
+    programmer (PPI).
+
+  * Add support for Atmel's STK500 programmer/development board.  The
+    STK500's "paged mode" read/write is supported which makes this
+    programmer very fast.  This is sorely needed on parts with large
+    memories such as the ATmega128.  My 12K test program burns in
+    about 5 seconds, add another 5 to read it back out for
+    verification.
+
+
+Version 2.1.5:
+
+  * When getting ready to initiate communications with the AVR device,
+    first pull /RESET low for a short period of time before enabling
+    the buffer chip.  This sequence allows the AVR to be reset before
+    the buffer is enabled to avoid a short period of time where the
+    AVR may be driving the programming lines at the same time the
+    programmer tries to.  Of course, if a buffer is being used, then
+    the /RESET line from the programmer needs to be directly connected
+    to the AVR /RESET line and not via the buffer chip.
+
+    Feature contributed by Rick C. Petty <rick@KIWI-Computer.com>.
+
+  * When in interactive terminal mode and dumping memory using the
+    'dump <memtype>' command without any address information, and the
+    end of memory is reached, wrap back around to zero on the next
+    invocation.
+
+
+Version 2.1.4:
+
+  * Fix -Y option.
+
+
+Version 2.1.3:
+
+  * Be backward compatible when reading 2-byte rewrite cycle counters
+    as written by avrprog version 2.1.0.  Version 2.1.1 changed over
+    to a 4-byte counter, which caused avrprog versions 2.1.1 and 2.1.2
+    to report a negative count for parts that were initialized using
+    version 2.1.0.  Thanks to Joerg Wunsch for noticing this.
+
+
+Version 2.1.2:
+
+  * Add '-V' option to disable automatic verify check with uploading
+    data.
+
+
+Version 2.1.1:
+
+  * Fix ATmega128 instruction sequences for reading fuse bits -
+    contributed by Joerg Wunsch.
+
+  * Modify erase-rewrite cycle counter code to use a 4 byte counter
+    instead of a two byte counter.
+
+
+Version 2.1.0:
+
+  * Implement a per-part erase-rewrite cycle counter; requires the use
+    of two bytes of EEPROM memory.
+
+
+Version 2.0.5:
+
+  * Support for ATtiny15 - contributed by Asher Hoskins
+
+
+Version 2.0.4:
+
+  * Config file fixes for various parts.
+
+
+Version 2.0.3:
+
+  * Work around problem programming fuse bits on parts like the
+    at90s4433 as described in the following errata:
+
+      http://www.atmel.com/atmel/acrobat/doc1280.pdf
+
+  * Add part definition for at90s4414, at90s4433.
+
+  * Add fuse/lock bit memory instructions for the at90s1200,
+    at90s2333, at90s4433 and at90s8515.
+
+  * Fix setting of programmer status LEDs under certain write-fail
+    conditions.
+
+
+Version 2.0.2 :
+
+  * Fix writing to read-only memories such as the lock bits of the
+    AT90S2313.
+
+  * Copyright updates.
+
+
+Version 2.0.1 :
+
+  * Use correct parallel port pins for VCC.
+
+  * Add programmer definition for Atmel's STK200.
+
+  * Add programmer definition for the AVR3 board.
+
+  * Fix address bit encoding for many parts.
+
+  * Allow the ``BUFF'' signal to be asserted by multiple pins of the
+    parallel port (like VCC) instead of just one.  The STK200 appears
+    to need this feature.
+
+
+Version 2.0.0 :
+
+  * Add support for programming fuse and lock bits if supported by the
+    part.
+
+  * Move instruction encoding into the config file.  Now any part can
+    be supported as long as it uses the same basic serial programming
+    instruction format.
+
+  * Add part definitions for the ATMega163 and ATMega8 devices.
+
+
+Version 1.4.3 :
+
+  * Mostly internal code cleanup.
+
+
+Version 1.4.2 :
+
+  * Fixes for ATMega paged memory support.
+
+  * Support for ATMega16 device.
+
+
+Version 1.4.1 :
+
+  * No functional changes, update to Copyrights only.
+
+
+Version 1.4.0 :
+
+  * Add part definitions to the config file.
+
+  * Add initial support for Atmel's ATMega paged memory parts.
+
+  * Config file documentation added.
+
+  * Add a definition for the Dontronics DT006 programmer.
+
+  * Fix Intel Hex support for addresses larger than 64k.
+
+
+Version 1.3.0 :
+
+  * Make programmer pin assignments configurable.
+
+
+Version 1.2.2 :
+
+  * Initial public release.
diff --git a/avrdude/README b/avrdude/README
new file mode 100644
index 00000000..ec04fb58
--- /dev/null
+++ b/avrdude/README
@@ -0,0 +1,6 @@
+See the documentation file for the details.
+
+The latest version of AVRDUDE is always available here:
+
+  http://savannah.nongnu.org/projects/avrdude
+
diff --git a/avrdude/arduino.c b/avrdude/arduino.c
new file mode 100644
index 00000000..b60954a6
--- /dev/null
+++ b/avrdude/arduino.c
@@ -0,0 +1,129 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2009 Lars Immisch
+ *
+ * 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
+ */
+
+/* $Id$ */
+
+/*
+ * avrdude interface for Arduino programmer
+ *
+ * The Arduino programmer is mostly a STK500v1, just the signature bytes
+ * are read differently.
+ */
+
+#include "ac_cfg.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "avrdude.h"
+#include "pgm.h"
+#include "stk500_private.h"
+#include "stk500.h"
+#include "serial.h"
+
+/* read signature bytes - arduino version */
+static int arduino_read_sig_bytes(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m)
+{
+  unsigned char buf[32];
+
+  /* Signature byte reads are always 3 bytes. */
+
+  if (m->size < 3) {
+    fprintf(stderr, "%s: memsize too small for sig byte read", progname);
+    return -1;
+  }
+
+  buf[0] = Cmnd_STK_READ_SIGN;
+  buf[1] = Sync_CRC_EOP;
+
+  serial_send(&pgm->fd, buf, 2);
+
+  if (serial_recv(&pgm->fd, buf, 5) < 0)
+    return -1;
+  if (buf[0] == Resp_STK_NOSYNC) {
+    fprintf(stderr, "%s: stk500_cmd(): programmer is out of sync\n",
+			progname);
+	return -1;
+  } else if (buf[0] != Resp_STK_INSYNC) {
+    fprintf(stderr,
+			"\n%s: arduino_read_sig_bytes(): (a) protocol error, "
+			"expect=0x%02x, resp=0x%02x\n",
+			progname, Resp_STK_INSYNC, buf[0]);
+	return -2;
+  }
+  if (buf[4] != Resp_STK_OK) {
+    fprintf(stderr,
+			"\n%s: arduino_read_sig_bytes(): (a) protocol error, "
+			"expect=0x%02x, resp=0x%02x\n",
+			progname, Resp_STK_OK, buf[4]);
+    return -3;
+  }
+
+  m->buf[0] = buf[1];
+  m->buf[1] = buf[2];
+  m->buf[2] = buf[3];
+
+  return 3;
+}
+
+static int arduino_open(PROGRAMMER * pgm, char * port)
+{
+  strcpy(pgm->port, port);
+  serial_open(port, pgm->baudrate? pgm->baudrate: 115200, &pgm->fd);
+
+  /* Clear DTR and RTS to unload the RESET capacitor 
+   * (for example in Arduino) */
+  serial_set_dtr_rts(&pgm->fd, 0);
+  usleep(50*1000);
+  /* Set DTR and RTS back to high */
+  serial_set_dtr_rts(&pgm->fd, 1);
+  usleep(50*1000);
+
+  /*
+   * drain any extraneous input
+   */
+  stk500_drain(pgm, 0);
+
+  if (stk500_getsync(pgm) < 0)
+    return -1;
+
+  return 0;
+}
+
+static void arduino_close(PROGRAMMER * pgm)
+{
+  serial_set_dtr_rts(&pgm->fd, 0);
+  serial_close(&pgm->fd);
+  pgm->fd.ifd = -1;
+}
+
+void arduino_initpgm(PROGRAMMER * pgm)
+{
+	/* This is mostly a STK500; just the signature is read
+     differently than on real STK500v1 
+     and the DTR signal is set when opening the serial port
+     for the Auto-Reset feature */
+  stk500_initpgm(pgm);
+
+  strcpy(pgm->type, "Arduino");
+  pgm->read_sig_bytes = arduino_read_sig_bytes;
+  pgm->open = arduino_open;
+  pgm->close = arduino_close;
+}
diff --git a/avrdude/arduino.h b/avrdude/arduino.h
new file mode 100644
index 00000000..a5819ee1
--- /dev/null
+++ b/avrdude/arduino.h
@@ -0,0 +1,29 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2009 Lars Immisch
+ *
+ * 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
+ */
+
+/* $Id$ */
+
+#ifndef arduino_h__
+#define arduino_h__
+
+void arduino_initpgm (PROGRAMMER * pgm);
+
+#endif
+
+
diff --git a/avrdude/avr.c b/avrdude/avr.c
new file mode 100644
index 00000000..6fd8bc7a
--- /dev/null
+++ b/avrdude/avr.c
@@ -0,0 +1,856 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2000-2004  Brian S. Dean <bsd@bsdhome.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id$ */
+
+#include "ac_cfg.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "avrdude.h"
+
+#include "avr.h"
+#include "lists.h"
+#include "pindefs.h"
+#include "ppi.h"
+#include "safemode.h"
+#include "update.h"
+
+FP_UpdateProgress update_progress;
+
+#define DEBUG 0
+
+int avr_read_byte_default(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, 
+                          unsigned long addr, unsigned char * value)
+{
+  unsigned char cmd[4];
+  unsigned char res[4];
+  unsigned char data;
+  OPCODE * readop, * lext;
+
+  if (pgm->cmd == NULL) {
+    fprintf(stderr,
+	    "%s: Error: %s programmer uses avr_read_byte_default() but does not\n"
+	    "provide a cmd() method.\n",
+	    progname, pgm->type);
+    return -1;
+  }
+
+  pgm->pgm_led(pgm, ON);
+  pgm->err_led(pgm, OFF);
+
+  /*
+   * figure out what opcode to use
+   */
+  if (mem->op[AVR_OP_READ_LO]) {
+    if (addr & 0x00000001)
+      readop = mem->op[AVR_OP_READ_HI];
+    else
+      readop = mem->op[AVR_OP_READ_LO];
+    addr = addr / 2;
+  }
+  else {
+    readop = mem->op[AVR_OP_READ];
+  }
+
+  if (readop == NULL) {
+#if DEBUG
+    fprintf(stderr, 
+            "avr_read_byte(): operation not supported on memory type \"%s\"\n",
+            p->desc);
+#endif
+    return -1;
+  }
+
+  /*
+   * If this device has a "load extended address" command, issue it.
+   */
+  lext = mem->op[AVR_OP_LOAD_EXT_ADDR];
+  if (lext != NULL) {
+    memset(cmd, 0, sizeof(cmd));
+
+    avr_set_bits(lext, cmd);
+    avr_set_addr(lext, cmd, addr);
+    pgm->cmd(pgm, cmd, res);
+  }
+
+  memset(cmd, 0, sizeof(cmd));
+
+  avr_set_bits(readop, cmd);
+  avr_set_addr(readop, cmd, addr);
+  pgm->cmd(pgm, cmd, res);
+  data = 0;
+  avr_get_output(readop, res, &data);
+
+  pgm->pgm_led(pgm, OFF);
+
+  *value = data;
+
+  return 0;
+}
+
+
+/*
+ * Return the number of "interesting" bytes in a memory buffer,
+ * "interesting" being defined as up to the last non-0xff data
+ * value. This is useful for determining where to stop when dealing
+ * with "flash" memory, since writing 0xff to flash is typically a
+ * no-op. Always return an even number since flash is word addressed.
+ */
+int avr_mem_hiaddr(AVRMEM * mem)
+{
+  int i, n;
+
+  /* return the highest non-0xff address regardless of how much
+     memory was read */
+  for (i=mem->size-1; i>0; i--) {
+    if (mem->buf[i] != 0xff) {
+      n = i+1;
+      if (n & 0x01)
+        return n+1;
+      else
+        return n;
+    }
+  }
+
+  return 0;
+}
+
+
+/*
+ * Read the entirety of the specified memory type into the
+ * corresponding buffer of the avrpart pointed to by 'p'.  If size =
+ * 0, read the entire contents, otherwise, read 'size' bytes.
+ *
+ * Return the number of bytes read, or < 0 if an error occurs.  
+ */
+int avr_read(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size, 
+             int verbose)
+{
+  unsigned char    rbyte;
+  unsigned long    i;
+  unsigned char  * buf;
+  AVRMEM * mem;
+  int rc;
+
+  mem = avr_locate_mem(p, memtype);
+  if (mem == NULL) {
+    fprintf(stderr, "No \"%s\" memory for part %s\n",
+            memtype, p->desc);
+    return -1;
+  }
+
+  buf  = mem->buf;
+  if (size == 0) {
+    size = mem->size;
+  }
+
+  /*
+   * start with all 0xff
+   */
+  memset(buf, 0xff, size);
+
+  if (pgm->paged_load != NULL && mem->page_size != 0) {
+    /*
+     * the programmer supports a paged mode read, perhaps more
+     * efficiently than we can read it directly, so use its routine
+     * instead
+     */
+    rc = pgm->paged_load(pgm, p, mem, mem->page_size, size);
+    if (rc >= 0) {
+      if (strcasecmp(mem->desc, "flash") == 0)
+        return avr_mem_hiaddr(mem);
+      else
+        return rc;
+    }
+  }
+
+  if (strcmp(mem->desc, "signature") == 0) {
+    if (pgm->read_sig_bytes) {
+      return pgm->read_sig_bytes(pgm, p, mem);
+    }
+  }
+
+  for (i=0; i<size; i++) {
+    rc = pgm->read_byte(pgm, p, mem, i, &rbyte);
+    if (rc != 0) {
+      fprintf(stderr, "avr_read(): error reading address 0x%04lx\n", i);
+      if (rc == -1) 
+        fprintf(stderr, 
+                "    read operation not supported for memory \"%s\"\n",
+                memtype);
+      return -2;
+    }
+    buf[i] = rbyte;
+    report_progress(i, size, NULL);
+  }
+
+  if (strcasecmp(mem->desc, "flash") == 0)
+    return avr_mem_hiaddr(mem);
+  else
+    return i;
+}
+
+
+/*
+ * write a page data at the specified address
+ */
+int avr_write_page(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem, 
+                   unsigned long addr)
+{
+  unsigned char cmd[4];
+  unsigned char res[4];
+  OPCODE * wp, * lext;
+
+  if (pgm->cmd == NULL) {
+    fprintf(stderr,
+	    "%s: Error: %s programmer uses avr_write_page() but does not\n"
+	    "provide a cmd() method.\n",
+	    progname, pgm->type);
+    return -1;
+  }
+
+  wp = mem->op[AVR_OP_WRITEPAGE];
+  if (wp == NULL) {
+    fprintf(stderr, 
+            "avr_write_page(): memory \"%s\" not configured for page writes\n",
+            mem->desc);
+    return -1;
+  }
+
+  /*
+   * if this memory is word-addressable, adjust the address
+   * accordingly
+   */
+  if ((mem->op[AVR_OP_LOADPAGE_LO]) || (mem->op[AVR_OP_READ_LO]))
+    addr = addr / 2;
+
+  pgm->pgm_led(pgm, ON);
+  pgm->err_led(pgm, OFF);
+
+  /*
+   * If this device has a "load extended address" command, issue it.
+   */
+  lext = mem->op[AVR_OP_LOAD_EXT_ADDR];
+  if (lext != NULL) {
+    memset(cmd, 0, sizeof(cmd));
+
+    avr_set_bits(lext, cmd);
+    avr_set_addr(lext, cmd, addr);
+    pgm->cmd(pgm, cmd, res);
+  }
+
+  memset(cmd, 0, sizeof(cmd));
+
+  avr_set_bits(wp, cmd);
+  avr_set_addr(wp, cmd, addr);
+  pgm->cmd(pgm, cmd, res);
+
+  /*
+   * since we don't know what voltage the target AVR is powered by, be
+   * conservative and delay the max amount the spec says to wait
+   */
+  usleep(mem->max_write_delay);
+
+  pgm->pgm_led(pgm, OFF);
+  return 0;
+}
+
+
+int avr_write_byte_default(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+                   unsigned long addr, unsigned char data)
+{
+  unsigned char cmd[4];
+  unsigned char res[4];
+  unsigned char r;
+  int ready;
+  int tries;
+  unsigned long start_time;
+  unsigned long prog_time;
+  unsigned char b;
+  unsigned short caddr;
+  OPCODE * writeop;
+  int rc;
+  int readok=0;
+  struct timeval tv;
+
+  if (pgm->cmd == NULL) {
+    fprintf(stderr,
+	    "%s: Error: %s programmer uses avr_write_byte_default() but does not\n"
+	    "provide a cmd() method.\n",
+	    progname, pgm->type);
+    return -1;
+  }
+
+  if (!mem->paged) {
+    /* 
+     * check to see if the write is necessary by reading the existing
+     * value and only write if we are changing the value; we can't
+     * use this optimization for paged addressing.
+     */
+    rc = pgm->read_byte(pgm, p, mem, addr, &b);
+    if (rc != 0) {
+      if (rc != -1) {
+        return -2;
+      }
+      /*
+       * the read operation is not support on this memory type
+       */
+    }
+    else {
+      readok = 1;
+      if (b == data) {
+        return 0;
+      }
+    }
+  }
+
+  /*
+   * determine which memory opcode to use
+   */
+  if (mem->op[AVR_OP_WRITE_LO]) {
+    if (addr & 0x01)
+      writeop = mem->op[AVR_OP_WRITE_HI];
+    else
+      writeop = mem->op[AVR_OP_WRITE_LO];
+    caddr = addr / 2;
+  }
+  else if (mem->paged && mem->op[AVR_OP_LOADPAGE_LO]) {
+    if (addr & 0x01)
+      writeop = mem->op[AVR_OP_LOADPAGE_HI];
+    else
+      writeop = mem->op[AVR_OP_LOADPAGE_LO];
+    caddr = addr / 2;
+  }
+  else {
+    writeop = mem->op[AVR_OP_WRITE];
+    caddr = addr;
+  }
+
+  if (writeop == NULL) {
+#if DEBUG
+    fprintf(stderr, 
+            "avr_write_byte(): write not supported for memory type \"%s\"\n",
+            mem->desc);
+#endif
+    return -1;
+  }
+
+
+  pgm->pgm_led(pgm, ON);
+  pgm->err_led(pgm, OFF);
+
+  memset(cmd, 0, sizeof(cmd));
+
+  avr_set_bits(writeop, cmd);
+  avr_set_addr(writeop, cmd, caddr);
+  avr_set_input(writeop, cmd, data);
+  pgm->cmd(pgm, cmd, res);
+
+  if (mem->paged) {
+    /*
+     * in paged addressing, single bytes to be written to the memory
+     * page complete immediately, we only need to delay when we commit
+     * the whole page via the avr_write_page() routine.
+     */
+    pgm->pgm_led(pgm, OFF);
+    return 0;
+  }
+
+  if (readok == 0) {
+    /*
+     * read operation not supported for this memory type, just wait
+     * the max programming time and then return 
+     */
+    usleep(mem->max_write_delay); /* maximum write delay */
+    pgm->pgm_led(pgm, OFF);
+    return 0;
+  }
+
+  tries = 0;
+  ready = 0;
+  while (!ready) {
+
+    if ((data == mem->readback[0]) ||
+        (data == mem->readback[1])) {
+      /* 
+       * use an extra long delay when we happen to be writing values
+       * used for polled data read-back.  In this case, polling
+       * doesn't work, and we need to delay the worst case write time
+       * specified for the chip.
+       */
+      usleep(mem->max_write_delay);
+      rc = pgm->read_byte(pgm, p, mem, addr, &r);
+      if (rc != 0) {
+        pgm->pgm_led(pgm, OFF);
+        pgm->err_led(pgm, OFF);
+        return -5;
+      }
+    }
+    else {
+      gettimeofday (&tv, NULL);
+      start_time = (tv.tv_sec * 1000000) + tv.tv_usec;
+      do {
+        /*
+         * Do polling, but timeout after max_write_delay.
+	 */
+        rc = pgm->read_byte(pgm, p, mem, addr, &r);
+        if (rc != 0) {
+          pgm->pgm_led(pgm, OFF);
+          pgm->err_led(pgm, ON);
+          return -4;
+        }
+        gettimeofday (&tv, NULL);
+        prog_time = (tv.tv_sec * 1000000) + tv.tv_usec;
+      } while ((r != data) &&
+               ((prog_time-start_time) < mem->max_write_delay));
+    }
+
+    /*
+     * At this point we either have a valid readback or the
+     * max_write_delay is expired.
+     */
+    
+    if (r == data) {
+      ready = 1;
+    }
+    else if (mem->pwroff_after_write) {
+      /*
+       * The device has been flagged as power-off after write to this
+       * memory type.  The reason we don't just blindly follow the
+       * flag is that the power-off advice may only apply to some
+       * memory bits but not all.  We only actually power-off the
+       * device if the data read back does not match what we wrote.
+       */
+      pgm->pgm_led(pgm, OFF);
+      fprintf(stderr,
+              "%s: this device must be powered off and back on to continue\n",
+              progname);
+      if (pgm->pinno[PPI_AVR_VCC]) {
+        fprintf(stderr, "%s: attempting to do this now ...\n", progname);
+        pgm->powerdown(pgm);
+        usleep(250000);
+        rc = pgm->initialize(pgm, p);
+        if (rc < 0) {
+          fprintf(stderr, "%s: initialization failed, rc=%d\n", progname, rc);
+          fprintf(stderr, 
+                  "%s: can't re-initialize device after programming the "
+                  "%s bits\n", progname, mem->desc);
+          fprintf(stderr,
+                  "%s: you must manually power-down the device and restart\n"
+                  "%s:   %s to continue.\n",
+                  progname, progname, progname);
+          return -3;
+        }
+        
+        fprintf(stderr, "%s: device was successfully re-initialized\n",
+                progname);
+        return 0;
+      }
+    }
+
+    tries++;
+    if (!ready && tries > 5) {
+      /*
+       * we wrote the data, but after waiting for what should have
+       * been plenty of time, the memory cell still doesn't match what
+       * we wrote.  Indicate a write error.
+       */
+      pgm->pgm_led(pgm, OFF);
+      pgm->err_led(pgm, ON);
+      
+      return -6;
+    }
+  }
+
+  pgm->pgm_led(pgm, OFF);
+  return 0;
+}
+
+
+/*
+ * write a byte of data at the specified address
+ */
+int avr_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+                   unsigned long addr, unsigned char data)
+{
+
+  unsigned char safemode_lfuse;
+  unsigned char safemode_hfuse;
+  unsigned char safemode_efuse;
+  unsigned char safemode_fuse;
+
+  /* If we write the fuses, then we need to tell safemode that they *should* change */
+  safemode_memfuses(0, &safemode_lfuse, &safemode_hfuse, &safemode_efuse, &safemode_fuse);
+
+  if (strcmp(mem->desc, "fuse")==0) {
+      safemode_fuse = data;
+  }
+  if (strcmp(mem->desc, "lfuse")==0) {
+      safemode_lfuse = data;
+  }
+  if (strcmp(mem->desc, "hfuse")==0) {
+      safemode_hfuse = data;
+  }
+  if (strcmp(mem->desc, "efuse")==0) {
+      safemode_efuse = data;
+  }
+  
+  safemode_memfuses(1, &safemode_lfuse, &safemode_hfuse, &safemode_efuse, &safemode_fuse);
+
+  return pgm->write_byte(pgm, p, mem, addr, data);
+}
+
+
+/*
+ * Write the whole memory region of the specified memory from the
+ * corresponding buffer of the avrpart pointed to by 'p'.  Write up to
+ * 'size' bytes from the buffer.  Data is only written if the new data
+ * value is different from the existing data value.  Data beyond
+ * 'size' bytes is not affected.
+ *
+ * Return the number of bytes written, or -1 if an error occurs.
+ */
+int avr_write(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size, 
+              int verbose)
+{
+  int              rc;
+  int              wsize;
+  long             i;
+  unsigned char    data;
+  int              werror;
+  AVRMEM         * m;
+
+  m = avr_locate_mem(p, memtype);
+  if (m == NULL) {
+    fprintf(stderr, "No \"%s\" memory for part %s\n",
+            memtype, p->desc);
+    return -1;
+  }
+
+  pgm->err_led(pgm, OFF);
+
+  werror  = 0;
+
+  wsize = m->size;
+  if (size < wsize) {
+    wsize = size;
+  }
+  else if (size > wsize) {
+    fprintf(stderr, 
+            "%s: WARNING: %d bytes requested, but memory region is only %d"
+            "bytes\n"
+            "%sOnly %d bytes will actually be written\n",
+            progname, size, wsize,
+            progbuf, wsize);
+  }
+
+  if (pgm->paged_write != NULL && m->page_size != 0) {
+    /*
+     * the programmer supports a paged mode write, perhaps more
+     * efficiently than we can read it directly, so use its routine
+     * instead
+     */
+    if ((i = pgm->paged_write(pgm, p, m, m->page_size, size)) >= 0)
+      return i;
+  }
+
+  if (pgm->write_setup) {
+      pgm->write_setup(pgm, p, m);
+  }
+
+  for (i=0; i<wsize; i++) {
+    data = m->buf[i];
+    report_progress(i, wsize, NULL);
+
+    rc = avr_write_byte(pgm, p, m, i, data);
+    if (rc) {
+      fprintf(stderr, " ***failed;  ");
+      fprintf(stderr, "\n");
+      pgm->err_led(pgm, ON);
+      werror = 1;
+    }
+
+    if (m->paged) {
+      /*
+       * check to see if it is time to flush the page with a page
+       * write
+       */
+      if (((i % m->page_size) == m->page_size-1) ||
+          (i == wsize-1)) {
+        rc = avr_write_page(pgm, p, m, i);
+        if (rc) {
+          fprintf(stderr,
+                  " *** page %ld (addresses 0x%04lx - 0x%04lx) failed "
+                  "to write\n",
+                  i % m->page_size, 
+                  i - m->page_size + 1, i);
+          fprintf(stderr, "\n");
+          pgm->err_led(pgm, ON);
+          werror = 1;
+        }
+      }
+    }
+
+    if (werror) {
+      /* 
+       * make sure the error led stay on if there was a previous write
+       * error, otherwise it gets cleared in avr_write_byte()
+       */
+      pgm->err_led(pgm, ON);
+    }
+  }
+
+  return i;
+}
+
+
+
+/*
+ * read the AVR device's signature bytes
+ */
+int avr_signature(PROGRAMMER * pgm, AVRPART * p)
+{
+  int rc;
+
+  report_progress (0,1,"Reading");
+  rc = avr_read(pgm, p, "signature", 0, 0);
+  if (rc < 0) {
+    fprintf(stderr,
+            "%s: error reading signature data for part \"%s\", rc=%d\n",
+            progname, p->desc, rc);
+    return -1;
+  }
+  report_progress (1,1,NULL);
+
+  return 0;
+}
+
+
+/*
+ * Verify the memory buffer of p with that of v.  The byte range of v,
+ * may be a subset of p.  The byte range of p should cover the whole
+ * chip's memory size.
+ *
+ * Return the number of bytes verified, or -1 if they don't match.
+ */
+int avr_verify(AVRPART * p, AVRPART * v, char * memtype, int size)
+{
+  int i;
+  unsigned char * buf1, * buf2;
+  int vsize;
+  AVRMEM * a, * b;
+
+  a = avr_locate_mem(p, memtype);
+  if (a == NULL) {
+    fprintf(stderr, 
+            "avr_verify(): memory type \"%s\" not defined for part %s\n",
+            memtype, p->desc);
+    return -1;
+  }
+
+  b = avr_locate_mem(v, memtype);
+  if (b == NULL) {
+    fprintf(stderr, 
+            "avr_verify(): memory type \"%s\" not defined for part %s\n",
+            memtype, v->desc);
+    return -1;
+  }
+
+  buf1  = a->buf;
+  buf2  = b->buf;
+  vsize = a->size;
+
+  if (vsize < size) {
+    fprintf(stderr, 
+            "%s: WARNING: requested verification for %d bytes\n"
+            "%s%s memory region only contains %d bytes\n"
+            "%sOnly %d bytes will be verified.\n",
+            progname, size,
+            progbuf, memtype, vsize,
+            progbuf, vsize);
+    size = vsize;
+  }
+
+  for (i=0; i<size; i++) {
+    if (buf1[i] != buf2[i]) {
+      fprintf(stderr, 
+              "%s: verification error, first mismatch at byte 0x%04x\n"
+              "%s0x%02x != 0x%02x\n",
+              progname, i, 
+              progbuf, buf1[i], buf2[i]);
+      return -1;
+    }
+  }
+
+  return size;
+}
+
+
+int avr_get_cycle_count(PROGRAMMER * pgm, AVRPART * p, int * cycles)
+{
+  AVRMEM * a;
+  unsigned int cycle_count = 0;
+  unsigned char v1;
+  int rc;
+  int i;
+
+  a = avr_locate_mem(p, "eeprom");
+  if (a == NULL) {
+    return -1;
+  }
+
+  for (i=4; i>0; i--) {
+    rc = pgm->read_byte(pgm, p, a, a->size-i, &v1);
+  if (rc < 0) {
+    fprintf(stderr, "%s: WARNING: can't read memory for cycle count, rc=%d\n",
+            progname, rc);
+    return -1;
+  }
+    cycle_count = (cycle_count << 8) | v1;
+  }
+
+   /*
+   * If the EEPROM is erased, the cycle count reads 0xffffffff.
+   * In this case we return a cycle_count of zero.
+   * So, the calling function don't have to care about whether or not
+   * the cycle count was initialized.
+   */
+  if (cycle_count == 0xffffffff) {
+    cycle_count = 0;
+  }
+
+  *cycles = (int) cycle_count;
+
+  return 0;
+}
+
+
+int avr_put_cycle_count(PROGRAMMER * pgm, AVRPART * p, int cycles)
+{
+  AVRMEM * a;
+  unsigned char v1;
+  int rc;
+  int i;
+
+  a = avr_locate_mem(p, "eeprom");
+  if (a == NULL) {
+    return -1;
+  }
+
+  for (i=1; i<=4; i++) {
+    v1 = cycles & 0xff;
+    cycles = cycles >> 8;
+
+    rc = avr_write_byte(pgm, p, a, a->size-i, v1);
+    if (rc < 0) {
+      fprintf(stderr, "%s: WARNING: can't write memory for cycle count, rc=%d\n",
+              progname, rc);
+      return -1;
+    }
+  }
+
+  return 0;
+  }
+
+int avr_chip_erase(PROGRAMMER * pgm, AVRPART * p)
+{
+  int cycles;
+  int rc;
+
+  if (do_cycles) {
+    rc = avr_get_cycle_count(pgm, p, &cycles);
+    /*
+     * Don't update the cycle counter, if read failed
+     */
+    if(rc != 0) {
+      do_cycles = 0;
+    }
+  }
+
+  rc = pgm->chip_erase(pgm, p);
+
+  /*
+   * Don't update the cycle counter, if erase failed
+   */
+  if (do_cycles && (rc == 0)) {
+    cycles++;
+    fprintf(stderr, "%s: erase-rewrite cycle count is now %d\n",
+            progname, cycles);
+    avr_put_cycle_count(pgm, p, cycles);
+  }
+
+  return rc;
+}
+
+/*
+ * Report the progress of a read or write operation from/to the
+ * device.
+ *
+ * The first call of report_progress() should look like this (for a write op):
+ *
+ * report_progress (0, 1, "Writing");
+ *
+ * Then hdr should be passed NULL on subsequent calls while the
+ * operation is progressing. Once the operation is complete, a final
+ * call should be made as such to ensure proper termination of the
+ * progress report:
+ *
+ * report_progress (1, 1, NULL);
+ *
+ * It would be nice if we could reduce the usage to one and only one
+ * call for each of start, during and end cases. As things stand now,
+ * that is not possible and makes maintenance a bit more work.
+ */
+void report_progress (int completed, int total, char *hdr)
+{
+  static int last = 0;
+  static double start_time;
+  int percent = (completed * 100) / total;
+  struct timeval tv;
+  double t;
+
+  if (update_progress == NULL)
+    return;
+
+  gettimeofday(&tv, NULL);
+  t = tv.tv_sec + ((double)tv.tv_usec)/1000000;
+
+  if (hdr) {
+    last = 0;
+    start_time = t;
+    update_progress (percent, t - start_time, hdr);
+  }
+
+  if (percent > 100)
+    percent = 100;
+
+  if (percent > last) {
+    last = percent;
+    update_progress (percent, t - start_time, hdr);
+  }
+
+  if (percent == 100)
+    last = 0;                   /* Get ready for next time. */
+}
diff --git a/avrdude/avr.h b/avrdude/avr.h
new file mode 100644
index 00000000..9be67ce1
--- /dev/null
+++ b/avrdude/avr.h
@@ -0,0 +1,76 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2000-2004  Brian S. Dean <bsd@bsdhome.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id$ */
+
+#ifndef __avr_h__
+#define __avr_h__
+
+#include <stdio.h>
+
+#include "avrpart.h"
+#include "pgm.h"
+
+typedef void (*FP_UpdateProgress)(int percent, double etime, char *hdr);
+
+extern struct avrpart parts[];
+
+extern FP_UpdateProgress update_progress;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int avr_read_byte_default(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+			  unsigned long addr, unsigned char * value);
+
+int avr_read(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size,
+             int verbose);
+
+int avr_write_page(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+                   unsigned long addr);
+
+int avr_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+                   unsigned long addr, unsigned char data);
+
+int avr_write_byte_default(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+			   unsigned long addr, unsigned char data);
+
+int avr_write(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size,
+              int verbose);
+
+int avr_signature(PROGRAMMER * pgm, AVRPART * p);
+
+int avr_verify(AVRPART * p, AVRPART * v, char * memtype, int size);
+
+int avr_get_cycle_count(PROGRAMMER * pgm, AVRPART * p, int * cycles);
+
+int avr_put_cycle_count(PROGRAMMER * pgm, AVRPART * p, int cycles);
+
+int avr_mem_hiaddr(AVRMEM * mem);
+
+int avr_chip_erase(PROGRAMMER * pgm, AVRPART * p);
+
+void report_progress (int completed, int total, char *hdr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/avrdude/avr910.c b/avrdude/avr910.c
new file mode 100644
index 00000000..9b3642ef
--- /dev/null
+++ b/avrdude/avr910.c
@@ -0,0 +1,796 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2003-2004  Theodore A. Roth  <troth@openavr.org>
+ * Copyright 2007 Joerg Wunsch <j@uriah.heep.sax.de>
+ * Copyright 2008 Klaus Leidinger <klaus@mikrocontroller-projekte.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id$ */
+
+/*
+ * avrdude interface for Atmel Low Cost Serial programmers which adher to the
+ * protocol described in application note avr910.
+ */
+
+#include "ac_cfg.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "avrdude.h"
+#include "avr.h"
+#include "config.h"
+#include "pgm.h"
+#include "avr910.h"
+#include "serial.h"
+
+/*
+ * Private data for this programmer.
+ */
+struct pdata
+{
+  char has_auto_incr_addr;
+  unsigned char devcode;
+  unsigned int buffersize;
+  unsigned char test_blockmode;
+  unsigned char use_blockmode;
+};
+
+#define PDATA(pgm) ((struct pdata *)(pgm->cookie))
+
+static void avr910_setup(PROGRAMMER * pgm)
+{
+  if ((pgm->cookie = malloc(sizeof(struct pdata))) == 0) {
+    fprintf(stderr,
+	    "%s: avr910_setup(): Out of memory allocating private data\n",
+	    progname);
+    exit(1);
+  }
+  memset(pgm->cookie, 0, sizeof(struct pdata));
+  PDATA(pgm)->test_blockmode = 1;
+}
+
+static void avr910_teardown(PROGRAMMER * pgm)
+{
+  free(pgm->cookie);
+}
+
+
+static int avr910_send(PROGRAMMER * pgm, char * buf, size_t len)
+{
+  return serial_send(&pgm->fd, (unsigned char *)buf, len);
+}
+
+
+static int avr910_recv(PROGRAMMER * pgm, char * buf, size_t len)
+{
+  int rv;
+
+  rv = serial_recv(&pgm->fd, (unsigned char *)buf, len);
+  if (rv < 0) {
+    fprintf(stderr,
+	    "%s: avr910_recv(): programmer is not responding\n",
+	    progname);
+    exit(1);
+  }
+  return 0;
+}
+
+
+static int avr910_drain(PROGRAMMER * pgm, int display)
+{
+  return serial_drain(&pgm->fd, display);
+}
+
+
+static void avr910_vfy_cmd_sent(PROGRAMMER * pgm, char * errmsg)
+{
+  char c;
+
+  avr910_recv(pgm, &c, 1);
+  if (c != '\r') {
+    fprintf(stderr, "%s: error: programmer did not respond to command: %s\n",
+            progname, errmsg);
+    exit(1);
+  }
+}
+
+
+/*
+ * issue the 'chip erase' command to the AVR device
+ */
+static int avr910_chip_erase(PROGRAMMER * pgm, AVRPART * p)
+{
+  avr910_send(pgm, "e", 1);
+  avr910_vfy_cmd_sent(pgm, "chip erase");
+
+  /*
+   * avr910 firmware may not delay long enough
+   */
+  usleep (p->chip_erase_delay);
+
+  return 0;
+}
+
+
+static void avr910_enter_prog_mode(PROGRAMMER * pgm)
+{
+  avr910_send(pgm, "P", 1);
+  avr910_vfy_cmd_sent(pgm, "enter prog mode");
+}
+
+
+static void avr910_leave_prog_mode(PROGRAMMER * pgm)
+{
+  avr910_send(pgm, "L", 1);
+  avr910_vfy_cmd_sent(pgm, "leave prog mode");
+}
+
+
+/*
+ * issue the 'program enable' command to the AVR device
+ */
+static int avr910_program_enable(PROGRAMMER * pgm, AVRPART * p)
+{
+  return -1;
+}
+
+
+/*
+ * initialize the AVR device and prepare it to accept commands
+ */
+static int avr910_initialize(PROGRAMMER * pgm, AVRPART * p)
+{
+  char id[8];
+  char sw[2];
+  char hw[2];
+  char buf[10];
+  char type;
+  char c, devtype_1st;
+  int dev_supported = 0;
+  AVRPART * part;
+
+  /* Get the programmer identifier. Programmer returns exactly 7 chars
+     _without_ the null.*/
+
+  avr910_send(pgm, "S", 1);
+  memset (id, 0, sizeof(id));
+  avr910_recv(pgm, id, sizeof(id)-1);
+
+  /* Get the HW and SW versions to see if the programmer is present. */
+
+  avr910_send(pgm, "V", 1);
+  avr910_recv(pgm, sw, sizeof(sw));
+
+  avr910_send(pgm, "v", 1);
+  avr910_recv(pgm, hw, sizeof(hw));
+
+  /* Get the programmer type (serial or parallel). Expect serial. */
+
+  avr910_send(pgm, "p", 1);
+  avr910_recv(pgm, &type, 1);
+
+  fprintf(stderr, "Found programmer: Id = \"%s\"; type = %c\n", id, type);
+  fprintf(stderr, "    Software Version = %c.%c; ", sw[0], sw[1]);
+  fprintf(stderr, "Hardware Version = %c.%c\n", hw[0], hw[1]);
+
+  /* See if programmer supports autoincrement of address. */
+
+  avr910_send(pgm, "a", 1);
+  avr910_recv(pgm, &PDATA(pgm)->has_auto_incr_addr, 1);
+  if (PDATA(pgm)->has_auto_incr_addr == 'Y')
+      fprintf(stderr, "Programmer supports auto addr increment.\n");
+
+  /* Check support for buffered memory access, ignore if not available */
+
+  if (PDATA(pgm)->test_blockmode == 1) {
+    avr910_send(pgm, "b", 1);
+    avr910_recv(pgm, &c, 1);
+    if (c == 'Y') {
+      avr910_recv(pgm, &c, 1);
+      PDATA(pgm)->buffersize = (unsigned int)(unsigned char)c<<8;
+      avr910_recv(pgm, &c, 1);
+      PDATA(pgm)->buffersize += (unsigned int)(unsigned char)c;
+      fprintf(stderr,
+	      "Programmer supports buffered memory access with "
+	      "buffersize = %u bytes.\n",
+	      PDATA(pgm)->buffersize);
+      PDATA(pgm)->use_blockmode = 1;
+    } else {
+      PDATA(pgm)->use_blockmode = 0;
+    }
+  } else {
+    PDATA(pgm)->use_blockmode = 0;
+  }
+
+  if (PDATA(pgm)->devcode == 0) {
+
+    /* Get list of devices that the programmer supports. */
+
+    avr910_send(pgm, "t", 1);
+    fprintf(stderr, "\nProgrammer supports the following devices:\n");
+    devtype_1st = 0;
+    while (1) {
+      avr910_recv(pgm, &c, 1);
+      if (devtype_1st == 0)
+	devtype_1st = c;
+      if (c == 0)
+	break;
+      part = locate_part_by_avr910_devcode(part_list, c);
+
+      fprintf(stderr, "    Device code: 0x%02x = %s\n", c, part ?  part->desc : "(unknown)");
+
+      /* FIXME: Need to lookup devcode and report the device. */
+
+      if (p->avr910_devcode == c)
+	dev_supported = 1;
+    };
+    fprintf(stderr,"\n");
+
+    if (!dev_supported) {
+      fprintf(stderr,
+	      "%s: %s: selected device is not supported by programmer: %s\n",
+	      progname, ovsigck? "warning": "error", p->id);
+      if (!ovsigck)
+	exit(1);
+    }
+    /* If the user forced the selection, use the first device
+       type that is supported by the programmer. */
+    buf[1] = ovsigck? devtype_1st: p->avr910_devcode;
+  } else {
+    /* devcode overridden by -x devcode= option */
+    buf[1] = (char)(PDATA(pgm)->devcode);
+  }
+
+  /* Tell the programmer which part we selected. */
+  buf[0] = 'T';
+  /* buf[1] has been set up above */
+
+  avr910_send(pgm, buf, 2);
+  avr910_vfy_cmd_sent(pgm, "select device");
+
+  if (verbose)
+    fprintf(stderr,
+	    "%s: avr910_devcode selected: 0x%02x\n",
+	    progname, (unsigned)buf[1]);
+
+  avr910_enter_prog_mode(pgm);
+
+  return 0;
+}
+
+
+static void avr910_disable(PROGRAMMER * pgm)
+{
+  /* Do nothing. */
+
+  return;
+}
+
+
+static void avr910_enable(PROGRAMMER * pgm)
+{
+  /* Do nothing. */
+
+  return;
+}
+
+
+/*
+ * transmit an AVR device command and return the results; 'cmd' and
+ * 'res' must point to at least a 4 byte data buffer
+ */
+static int avr910_cmd(PROGRAMMER * pgm, unsigned char cmd[4], 
+                      unsigned char res[4])
+{
+  char buf[5];
+
+  /* FIXME: Insert version check here */
+
+  buf[0] = '.';                 /* New Universal Command */
+  buf[1] = cmd[0];
+  buf[2] = cmd[1];
+  buf[3] = cmd[2];
+  buf[4] = cmd[3];
+
+  avr910_send (pgm, buf, 5);
+  avr910_recv (pgm, buf, 2);
+
+  res[0] = 0x00;                /* Dummy value */
+  res[1] = cmd[0];
+  res[2] = cmd[1];
+  res[3] = buf[0];
+
+  return 0;
+}
+
+
+static int avr910_parseextparms(PROGRAMMER * pgm, LISTID extparms)
+{
+  LNODEID ln;
+  const char *extended_param;
+  int rv = 0;
+
+  for (ln = lfirst(extparms); ln; ln = lnext(ln)) {
+    extended_param = ldata(ln);
+
+    if (strncmp(extended_param, "devcode=", strlen("devcode=")) == 0) {
+      int devcode;
+      if (sscanf(extended_param, "devcode=%i", &devcode) != 1 ||
+	  devcode <= 0 || devcode > 255) {
+        fprintf(stderr,
+                "%s: avr910_parseextparms(): invalid devcode '%s'\n",
+                progname, extended_param);
+        rv = -1;
+        continue;
+      }
+      if (verbose >= 2) {
+        fprintf(stderr,
+                "%s: avr910_parseextparms(): devcode overwritten as 0x%02x\n",
+                progname, devcode);
+      }
+      PDATA(pgm)->devcode = devcode;
+
+      continue;
+    }
+    if (strncmp(extended_param, "no_blockmode", strlen("no_blockmode")) == 0) {
+      if (verbose >= 2) {
+        fprintf(stderr,
+                "%s: avr910_parseextparms(-x): no testing for Blockmode\n",
+                progname);
+      }
+      PDATA(pgm)->test_blockmode = 0;
+
+      continue;
+    }
+
+    fprintf(stderr,
+            "%s: avr910_parseextparms(): invalid extended parameter '%s'\n",
+            progname, extended_param);
+    rv = -1;
+  }
+
+  return rv;
+}
+
+
+static int avr910_open(PROGRAMMER * pgm, char * port)
+{
+  /*
+   *  If baudrate was not specified use 19.200 Baud
+   */
+  if(pgm->baudrate == 0) {
+    pgm->baudrate = 19200;
+  }
+
+  strcpy(pgm->port, port);
+  serial_open(port, pgm->baudrate, &pgm->fd);
+
+  /*
+   * drain any extraneous input
+   */
+  avr910_drain (pgm, 0);
+	
+  return 0;
+}
+
+static void avr910_close(PROGRAMMER * pgm)
+{
+  avr910_leave_prog_mode(pgm);
+
+  serial_close(&pgm->fd);
+  pgm->fd.ifd = -1;
+}
+
+
+static void avr910_display(PROGRAMMER * pgm, const char * p)
+{
+  return;
+}
+
+
+static void avr910_set_addr(PROGRAMMER * pgm, unsigned long addr)
+{
+  char cmd[3];
+
+  cmd[0] = 'A';
+  cmd[1] = (addr >> 8) & 0xff;
+  cmd[2] = addr & 0xff;
+  
+  avr910_send(pgm, cmd, sizeof(cmd));
+  avr910_vfy_cmd_sent(pgm, "set addr");
+}
+
+
+static int avr910_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+                             unsigned long addr, unsigned char value)
+{
+  char cmd[2];
+
+  if (strcmp(m->desc, "flash") == 0) {
+    if (addr & 0x01) {
+      cmd[0] = 'C';             /* Write Program Mem high byte */
+    }
+    else {
+      cmd[0] = 'c';
+    }
+
+    addr >>= 1;
+  }
+  else if (strcmp(m->desc, "eeprom") == 0) {
+    cmd[0] = 'D';
+  }
+  else {
+    return avr_write_byte_default(pgm, p, m, addr, value);
+  }
+
+  cmd[1] = value;
+
+  avr910_set_addr(pgm, addr);
+
+  avr910_send(pgm, cmd, sizeof(cmd));
+  avr910_vfy_cmd_sent(pgm, "write byte");
+
+  return 0;
+}
+
+
+static int avr910_read_byte_flash(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+                                  unsigned long addr, unsigned char * value)
+{
+  char buf[2];
+
+  avr910_set_addr(pgm, addr >> 1);
+
+  avr910_send(pgm, "R", 1);
+
+  /* Read back the program mem word (MSB first) */
+  avr910_recv(pgm, buf, sizeof(buf));
+
+  if ((addr & 0x01) == 0) {
+    *value = buf[1];
+  }
+  else {
+    *value = buf[0];
+  }
+
+  return 0;
+}
+
+
+static int avr910_read_byte_eeprom(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+                                   unsigned long addr, unsigned char * value)
+{
+  avr910_set_addr(pgm, addr);
+  avr910_send(pgm, "d", 1);
+  avr910_recv(pgm, (char *)value, 1);
+
+  return 0;
+}
+
+
+static int avr910_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+                            unsigned long addr, unsigned char * value)
+{
+  if (strcmp(m->desc, "flash") == 0) {
+    return avr910_read_byte_flash(pgm, p, m, addr, value);
+  }
+
+  if (strcmp(m->desc, "eeprom") == 0) {
+    return avr910_read_byte_eeprom(pgm, p, m, addr, value);
+  }
+
+  return avr_read_byte_default(pgm, p, m, addr, value);
+}
+
+
+static int avr910_paged_write_flash(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, 
+                                    int page_size, int n_bytes)
+{
+  unsigned char cmd[] = {'c', 'C'};
+  char buf[2];
+  unsigned int addr = 0;
+  unsigned int max_addr = n_bytes;
+  unsigned int page_addr;
+  int page_bytes = page_size;
+  int page_wr_cmd_pending = 0;
+
+  page_addr = addr;
+  avr910_set_addr(pgm, addr>>1);
+
+  while (addr < max_addr) {
+    page_wr_cmd_pending = 1;
+    buf[0] = cmd[addr & 0x01];
+    buf[1] = m->buf[addr];
+    avr910_send(pgm, buf, sizeof(buf));
+    avr910_vfy_cmd_sent(pgm, "write byte");
+
+    addr++;
+    page_bytes--;
+
+    if (m->paged && (page_bytes == 0)) {
+      /* Send the "Issue Page Write" if we have sent a whole page. */
+
+      avr910_set_addr(pgm, page_addr>>1);
+      avr910_send(pgm, "m", 1);
+      avr910_vfy_cmd_sent(pgm, "flush page");
+
+      page_wr_cmd_pending = 0;
+      usleep(m->max_write_delay);
+      avr910_set_addr(pgm, addr>>1);
+
+      /* Set page address for next page. */
+
+      page_addr = addr;
+      page_bytes = page_size;
+    }
+    else if ((PDATA(pgm)->has_auto_incr_addr != 'Y') && ((addr & 0x01) == 0)) {
+      avr910_set_addr(pgm, addr>>1);
+    }
+
+    report_progress (addr, max_addr, NULL);
+  }
+
+  /* If we didn't send the page wr cmd after the last byte written in the
+     loop, send it now. */
+
+  if (page_wr_cmd_pending) {
+    avr910_set_addr(pgm, page_addr>>1);
+    avr910_send(pgm, "m", 1);
+    avr910_vfy_cmd_sent(pgm, "flush final page");
+    usleep(m->max_write_delay);
+  }
+
+  return addr;
+}
+
+
+static int avr910_paged_write_eeprom(PROGRAMMER * pgm, AVRPART * p,
+                                     AVRMEM * m, int page_size, int n_bytes)
+{
+  char cmd[2];
+  unsigned int addr = 0;
+  unsigned int max_addr = n_bytes;
+
+  avr910_set_addr(pgm, addr);
+
+  cmd[0] = 'D';
+
+  while (addr < max_addr) {
+    cmd[1] = m->buf[addr];
+    avr910_send(pgm, cmd, sizeof(cmd));
+    avr910_vfy_cmd_sent(pgm, "write byte");
+    usleep(m->max_write_delay);
+
+    addr++;
+
+    if (PDATA(pgm)->has_auto_incr_addr != 'Y') {
+      avr910_set_addr(pgm, addr);
+    }
+
+    report_progress (addr, max_addr, NULL);
+  }
+
+  return addr;
+}
+
+
+static int avr910_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+                              int page_size, int n_bytes)
+{
+  int rval = 0;
+  if (PDATA(pgm)->use_blockmode == 0) {
+    if (strcmp(m->desc, "flash") == 0) {
+      rval = avr910_paged_write_flash(pgm, p, m, page_size, n_bytes);
+    } else if (strcmp(m->desc, "eeprom") == 0) {
+      rval = avr910_paged_write_eeprom(pgm, p, m, page_size, n_bytes);
+    } else {
+      rval = -2;
+    }
+  }
+
+  if (PDATA(pgm)->use_blockmode == 1) {
+    unsigned int addr = 0;
+    unsigned int max_addr = n_bytes;
+    char *cmd;
+    unsigned int blocksize = PDATA(pgm)->buffersize;
+
+    if (strcmp(m->desc, "flash") && strcmp(m->desc, "eeprom"))
+      rval = -2;
+
+    if (m->desc[0] == 'e')
+      blocksize = 1;		/* Write to eeprom single bytes only */
+    avr910_set_addr(pgm, addr);
+
+    cmd = malloc(4 + blocksize);
+    if (!cmd) rval = -1;
+    cmd[0] = 'B';
+    cmd[3] = toupper(m->desc[0]);
+
+    while (addr < max_addr) {
+      if ((max_addr - addr) < blocksize) {
+        blocksize = max_addr - addr;
+      };
+      memcpy(&cmd[4], &m->buf[addr], blocksize);
+      cmd[1] = (blocksize >> 8) & 0xff;
+      cmd[2] = blocksize & 0xff;
+
+      avr910_send(pgm, cmd, 4 + blocksize);
+      avr910_vfy_cmd_sent(pgm, "write block");
+
+      addr += blocksize;
+
+      report_progress (addr, max_addr, NULL);
+    } /* while */
+    free(cmd);
+
+    rval = addr;
+  }
+  return rval;
+}
+
+
+static int avr910_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, 
+                             int page_size, int n_bytes)
+{
+  char cmd;
+  int rd_size = 1;
+  unsigned int addr = 0;
+  unsigned int max_addr;
+  char buf[2];
+  int rval=0;
+
+  if (PDATA(pgm)->use_blockmode == 0) {
+
+    if (strcmp(m->desc, "flash") == 0) {
+      cmd = 'R';
+      rd_size = 2;                /* read two bytes per addr */
+    } else if (strcmp(m->desc, "eeprom") == 0) {
+      cmd = 'd';
+      rd_size = 1;
+    } else {
+      rval = -2;
+    }
+
+    max_addr = n_bytes/rd_size;
+
+    avr910_set_addr(pgm, addr);
+
+    while (addr < max_addr) {
+      avr910_send(pgm, &cmd, 1);
+      if (cmd == 'R') {
+        /* The 'R' command returns two bytes, MSB first, we need to put the data
+           into the memory buffer LSB first. */
+        avr910_recv(pgm, buf, 2);
+        m->buf[addr*2]   = buf[1];  /* LSB */
+        m->buf[addr*2+1] = buf[0];  /* MSB */
+      }
+      else {
+        avr910_recv(pgm, (char *)&m->buf[addr], 1);
+      }
+
+      addr++;
+
+      if (PDATA(pgm)->has_auto_incr_addr != 'Y') {
+        avr910_set_addr(pgm, addr);
+      }
+
+      report_progress (addr, max_addr, NULL);
+    }
+
+    rval = addr * rd_size;
+  }
+
+  if (PDATA(pgm)->use_blockmode == 1) {
+    unsigned int addr = 0;
+    unsigned int max_addr = n_bytes;
+    int rd_size = 1;
+
+    /* check parameter syntax: only "flash" or "eeprom" is allowed */
+    if (strcmp(m->desc, "flash") && strcmp(m->desc, "eeprom"))
+      rval = -2;
+
+  	/* use buffered mode */
+    char cmd[4];
+    int blocksize = PDATA(pgm)->buffersize;
+
+    cmd[0] = 'g';
+    cmd[3] = toupper(m->desc[0]);
+
+    avr910_set_addr(pgm, addr);
+
+    while (addr < max_addr) {
+      if ((max_addr - addr) < blocksize) {
+        blocksize = max_addr - addr;
+      };
+      cmd[1] = (blocksize >> 8) & 0xff;
+      cmd[2] = blocksize & 0xff;
+
+      avr910_send(pgm, cmd, 4);
+      avr910_recv(pgm, (char *)&m->buf[addr], blocksize);
+
+      addr += blocksize;
+
+      report_progress (addr, max_addr, NULL);
+    }
+
+    rval = addr * rd_size;
+  }
+
+  return rval;
+}
+
+/* Signature byte reads are always 3 bytes. */
+
+static int avr910_read_sig_bytes(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m)
+{
+  unsigned char tmp;
+
+  if (m->size < 3) {
+    fprintf(stderr, "%s: memsize too small for sig byte read", progname);
+    return -1;
+  }
+
+  avr910_send(pgm, "s", 1);
+  avr910_recv(pgm, (char *)m->buf, 3);
+  /* Returned signature has wrong order. */
+  tmp = m->buf[2];
+  m->buf[2] = m->buf[0];
+  m->buf[0] = tmp;
+
+  return 3;
+}
+
+
+void avr910_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "avr910");
+
+  /*
+   * mandatory functions
+   */
+  pgm->initialize     = avr910_initialize;
+  pgm->display        = avr910_display;
+  pgm->enable         = avr910_enable;
+  pgm->disable        = avr910_disable;
+  pgm->program_enable = avr910_program_enable;
+  pgm->chip_erase     = avr910_chip_erase;
+  pgm->cmd            = avr910_cmd;
+  pgm->open           = avr910_open;
+  pgm->close          = avr910_close;
+
+  /*
+   * optional functions
+   */
+
+  pgm->write_byte = avr910_write_byte;
+  pgm->read_byte = avr910_read_byte;
+
+  pgm->paged_write = avr910_paged_write;
+  pgm->paged_load = avr910_paged_load;
+
+  pgm->read_sig_bytes = avr910_read_sig_bytes;
+
+  pgm->parseextparams = avr910_parseextparms;
+  pgm->setup          = avr910_setup;
+  pgm->teardown       = avr910_teardown;
+}
diff --git a/avrdude/avr910.h b/avrdude/avr910.h
new file mode 100644
index 00000000..ed8b2c56
--- /dev/null
+++ b/avrdude/avr910.h
@@ -0,0 +1,37 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2003-2004  Theodore A. Roth  <troth@openavr.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id$ */
+
+#ifndef avr910_h
+#define avr910_h
+
+#include "avrpart.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void avr910_initpgm (PROGRAMMER * pgm);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* avr910_h */
diff --git a/avrdude/avrdude.1 b/avrdude/avrdude.1
new file mode 100644
index 00000000..3da8b556
--- /dev/null
+++ b/avrdude/avrdude.1
@@ -0,0 +1,1037 @@
+.\"
+.\" avrdude - A Downloader/Uploader for AVR device programmers
+.\" Copyright (C) 2001, 2002, 2003, 2005 - 2010  Joerg Wunsch
+.\"
+.\" 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
+.\"
+.\"
+.\" $Id$
+.\"
+.Dd DATE January 14, 2010
+.Os
+.Dt AVRDUDE 1
+.Sh NAME
+.Nm avrdude
+.Nd driver program for ``simple'' Atmel AVR MCU programmer
+.Sh SYNOPSIS
+.Nm
+.Fl p Ar partno
+.Op Fl b Ar baudrate
+.Op Fl B Ar bitclock
+.Op Fl c Ar programmer-id
+.Op Fl C Ar config-file
+.Op Fl D
+.Op Fl e
+.Oo Fl E Ar exitspec Ns
+.Op \&, Ns Ar exitspec
+.Oc
+.Op Fl F
+.Op Fl i Ar delay
+.Op Fl n
+.Op Fl O
+.Op Fl P Ar port
+.Op Fl q
+.Op Fl s
+.Op Fl t
+.Op Fl u
+.Op Fl U Ar memtype:op:filename:filefmt
+.Op Fl v
+.Op Fl x Ar extended_param
+.Op Fl V
+.Op Fl y
+.Op Fl Y
+.Sh DESCRIPTION
+.Nm Avrdude
+is a program for downloading code and data to Atmel AVR
+microcontrollers.
+.Nm Avrdude
+supports Atmel's STK500 programmer,
+Atmel's AVRISP and AVRISP mkII devices,
+Atmel's STK600,
+Atmel's JTAG ICE (both mkI and mkII, the latter also in ISP mode),
+programmers complying to AppNote AVR910 and AVR109 (including the Butterfly),
+as well as a simple hard-wired
+programmer connected directly to a
+.Xr ppi 4
+or
+.Xr parport 4
+parallel port, or to a standard serial port.
+In the simplest case, the hardware consists just of a
+cable connecting the respective AVR signal lines to the parallel port.
+.Pp
+The MCU is programmed in
+.Em serial programming mode ,
+so, for the
+.Xr ppi 4
+based programmer, the MCU signals
+.Ql /RESET ,
+.Ql SCK ,
+.Ql MISO
+and
+.Ql MOSI
+need to be connected to the parallel port.  Optionally, some otherwise
+unused output pins of the parallel port can be used to supply power
+for the MCU part, so it is also possible to construct a passive
+stand-alone programming device.  Some status LEDs indicating the
+current operating state of the programmer can be connected, and a
+signal is available to control a buffer/driver IC 74LS367 (or
+74HCT367).  The latter can be useful to decouple the parallel port
+from the MCU when in-system programming is used.
+.Pp
+A number of equally simple bit-bang programming adapters that connect
+to a serial port are supported as well, among them the popular
+Ponyprog serial adapter, and the DASA and DASA3 adapters that used to
+be supported by uisp(1).
+Note that these adapters are meant to be attached to a physical serial
+port.
+Connecting to a serial port emulated on top of USB is likely to not
+work at all, or to work abysmally slow.
+.Pp
+Atmel's STK500 programmer is also supported and connects to a serial
+port.
+Both, firmware versions 1.x and 2.x can be handled, but require a
+different programmer type specification (by now).
+Using firmware version 2, high-voltage programming is also supported,
+both parallel and serial
+(programmer types stk500pp and stk500hvsp).
+.Pp
+The Arduino (which is very similar to the STK500 1.x) is supported via
+its own programmer type specification ``arduino''.
+.Pp
+The BusPirate is a versatile tool that can also be used as an AVR programmer.
+A single BusPirate can be connected to up to 3 independent AVRs. See
+the section on
+.Em extended parameters
+below for details.
+.Pp
+Atmel's STK600 programmer is supported in ISP and high-voltage
+programming modes, and connects through the USB.
+For ATxmega devices, the STK600 is supported in PDI mode.
+For ATtiny4/5/9/10 devices, the STK600 and AVRISP mkII are supported in TPI mode.
+.Pp
+The simple serial programmer described in Atmel's application note
+AVR910, and the bootloader described in Atmel's application note
+AVR109 (which is also used by the AVR Butterfly evaluation board), are
+supported on a serial port.
+.Pp
+Atmel's JTAG ICE (both mkI and mkII) is supported as well to up- or download memory
+areas from/to an AVR target (no support for on-chip debugging).
+For the JTAG ICE mkII, JTAG, debugWire and ISP mode are supported, provided
+it has a firmware revision of at least 4.14 (decimal).
+See below for the limitations of debugWire.
+For ATxmega devices, the JTAG ICE mkII is supported in PDI mode, provided it
+has a revision 1 hardware and firmware version of at least 5.37 (decimal).
+.Pp
+The AVR Dragon is supported in all modes (ISP, JTAG, HVSP, PP, debugWire).
+When used in JTAG and debugWire mode, the AVR Dragon behaves similar to a
+JTAG ICE mkII, so all device-specific comments for that device
+will apply as well.
+When used in ISP mode, the AVR Dragon behaves similar to an
+AVRISP mkII (or JTAG ICE mkII in ISP mode), so all device-specific
+comments will apply there.
+In particular, the Dragon starts out with a rather fast ISP clock
+frequency, so the
+.Fl B Ar bitclock
+option might be required to achieve a stable ISP communication.
+For ATxmega devices, the AVR Dragon is supported in PDI mode, provided it
+has a firmware version of at least 6.11 (decimal).
+.Pp
+The USBasp ISP and USBtinyISP adapters are also supported, provided
+.Nm avrdude
+has been compiled with libusb support.
+They both feature simple firmware-only USB implementations, running on
+an ATmega8 (or ATmega88), or ATtiny2313, respectively.
+.Pp
+Input files can be provided, and output files can be written in
+different file formats, such as raw binary files containing the data
+to download to the chip, Intel hex format, or Motorola S-record
+format.  There are a number of tools available to produce those files,
+like
+.Xr asl 1
+as a standalone assembler, or
+.Xr avr-objcopy 1
+for the final stage of the GNU toolchain for the AVR microcontroller.
+.Pp
+.Nm Avrdude
+can program the EEPROM and flash ROM memory cells of supported AVR
+parts.  Where supported by the serial instruction set, fuse bits and
+lock bits can be programmed as well.  These are implemented within
+.Nm
+as separate memory types and can be programmed using data from a file
+(see the
+.Fl m
+option) or from terminal mode (see the
+.Ar dump
+and
+.Ar write
+commands).  It is also possible to read the chip (provided it has not
+been code-protected previously, of course) and store the data in a
+file.  Finally, a ``terminal'' mode is available that allows one to
+interactively communicate with the MCU, and to display or program
+individual memory cells.
+On the STK500 and STK600 programmer, several operational parameters (target supply
+voltage, target Aref voltage, master clock) can be examined and changed
+from within terminal mode as well.
+.Ss Options
+In order to control all the different operation modi, a number of options
+need to be specified to
+.Nm avrdude .
+.Bl -tag -offset indent -width indent
+.It Fl p Ar partno
+This is the only option that is mandatory for every invocation of
+.Nm avrdude .
+It specifies the type of the MCU connected to the programmer.  These are read from the config file.  If
+.Nm avrdude
+does not know about a part that you have, simply add it to the config
+file (be sure and submit a patch back to the author so that it can be
+incorporated for the next version).  See the sample config file for
+the format.  Currently, the following MCU types are understood:
+.Pp
+.TS
+ll.
+\fBOption tag\fP	\fBOfficial part name\fP
+1200	AT90S1200
+2313	AT90S2313
+2333	AT90S2333
+2343	AT90S2343 (*)
+4414	AT90S4414
+4433	AT90S4433
+4434	AT90S4434
+8515	AT90S8515
+8535	AT90S8535
+c128	AT90CAN128
+c32	AT90CAN32
+c64	AT90CAN64
+m103	ATmega103
+m128	ATmega128
+m1280	ATmega1280
+m1281	ATmega1281
+m1284p	ATmega1284P
+m128rfa1	ATmega128RFA1
+m16	ATmega16
+m161	ATmega161
+m162	ATmega162
+m163	ATmega163
+m164	ATmega164
+m164p	ATmega164P
+m168	ATmega168
+m169	ATmega169
+m2560	ATmega2560 (**)
+m2561	ATmega2561 (**)
+m32	ATmega32
+m324p	ATmega324P
+m325	ATmega325
+m3250	ATmega3250
+m328p	ATmega328P
+m329	ATmega329
+m3290	ATmega3290
+m329p	ATmega329P
+m3290p	ATmega3290P
+m32u4	ATmega32U4
+m48	ATmega48
+m64	ATmega64
+m640	ATmega640
+m644p	ATmega644P
+m644	ATmega644
+m645	ATmega645
+m6450	ATmega6450
+m649	ATmega649
+m6490	ATmega6490
+m8	ATmega8
+m8515	ATmega8515
+m8535	ATmega8535
+m88	ATmega88
+pwm2	AT90PWM2
+pwm2b	AT90PWM2B
+pwm3	AT90PWM3
+pwm3b	AT90PWM3B
+t10	ATtiny10
+t12	ATtiny12 (***)
+t13	ATtiny13
+t15	ATtiny15
+t2313	ATtiny2313
+t25	ATtiny25
+t26	ATtiny26
+t261	ATtiny261
+t4	ATtiny4
+t44	ATtiny44
+t45	ATtiny45
+t461	ATtiny461
+t5	ATtiny5
+t84	ATtiny84
+t85	ATtiny85
+t861	ATtiny861
+t88	ATtiny88
+t9	ATtiny9
+ucr2	AT32uca0512
+usb1286	ATmega1286
+usb1287	ATmega1287
+usb162	ATmega162
+usb646	ATmega647
+usb647	ATmega647
+usb82	ATmega82
+x128a1	ATxmega128A1
+x128a1d	ATxmega128A1revD
+x128a3	ATxmega128A3
+x128a4	ATxmega128A4
+x16a4	ATxmega16A4
+x192a1	ATxmega192A1
+x192a3	ATxmega192A3
+x256a1	ATxmega256A1
+x256a3	ATxmega256A3
+x256a3b	ATxmega256A3B
+x32a4	ATxmega32A4
+x64a1	ATxmega64A1
+x64a3	ATxmega64A3
+x64a4	ATxmega64A4
+.TE
+.Bl -tag -width "(**) "
+.It "(*)"
+The AT90S2323 and ATtiny22 use the same algorithm.
+.It "(**)"
+Flash addressing above 128 KB is not supported by all
+programming hardware.  Known to work are jtag2, stk500v2,
+and bit-bang programmers.
+.It "(***)"
+The ATtiny11 uses the same algorithm, but can only be
+programmed in high-voltage serial mode.
+.El
+.It Fl b Ar baudrate
+Override the RS-232 connection baud rate specified in the respective
+programmer's entry of the configuration file.
+.It Fl B Ar bitclock
+Specify the bit clock period for the JTAG interface or the ISP clock (JTAG ICE only).
+The value is a floating-point number in microseconds.
+The default value of the JTAG ICE results in about 1 microsecond bit
+clock period, suitable for target MCUs running at 4 MHz clock and
+above.
+Unlike certain parameters in the STK500, the JTAG ICE resets all its
+parameters to default values when the programming software signs
+off from the ICE, so for MCUs running at lower clock speeds, this
+parameter must be specified on the command-line.
+.It Fl c Ar programmer-id
+Use the pin configuration specified by the argument.  Pin
+configurations are read from the config file (see the
+.Fl C
+option).  New pin configurations can be easily added or modified
+through the use of a config file to make
+.Nm avrdude
+work with different programmers as long as the programmer supports the
+Atmel AVR serial program method.  You can use the 'default_programmer'
+keyword in your
+.Pa ${HOME}/.avrduderc
+file to assign a default programmer to keep from having to specify
+this option on every invocation.
+.It Fl C Ar config-file
+Use the specified config file to load configuration data.  This file
+contains all programmer and part definitions that
+.Nm avrdude
+knows about.  If you have a programmer or part that
+.Nm avrdude
+does not know about, you can add it to the config file (be sure and
+submit a patch back to the author so that it can be incorporated for
+the next version).  See the config file, located at
+.Pa ${PREFIX}/etc/avrdude.conf ,
+which contains a description of the format.
+.It Fl D
+Disable auto erase for flash.  When the
+.Fl U
+option with flash memory is specified,
+.Nm
+will perform a chip erase before starting any of the programming
+operations, since it generally is a mistake to program the flash
+without performing an erase first.  This option disables that.
+Auto erase is not used for ATxmega devices as these devices can
+use page erase before writing each page so no explicit chip erase
+is required.
+Note however that any page not affected by the current operation
+will retain its previous contents.
+.It Fl e
+Causes a chip erase to be executed.  This will reset the contents of the
+flash ROM and EEPROM to the value
+.Ql 0xff ,
+and clear all lock bits.
+Except for ATxmega devices which can use page erase,
+it is basically a prerequisite command before the flash ROM can be
+reprogrammed again.  The only exception would be if the new
+contents would exclusively cause bits to be programmed from the value
+.Ql 1
+to
+.Ql 0 .
+Note that in order to reprogram EERPOM cells, no explicit prior chip
+erase is required since the MCU provides an auto-erase cycle in that
+case before programming the cell.
+.It Xo Fl E Ar exitspec Ns
+.Op \&, Ns Ar exitspec
+.Xc
+By default,
+.Nm
+leaves the parallel port in the same state at exit as it has been
+found at startup.  This option modifies the state of the
+.Ql /RESET
+and
+.Ql Vcc
+lines the parallel port is left at, according to the
+.Ar exitspec
+arguments provided, as follows:
+.Bl -tag -width noreset
+.It Ar reset
+The
+.Ql /RESET
+signal will be left activated at program exit, that is it will be held
+.Em low ,
+in order to keep the MCU in reset state afterwards.  Note in particular
+that the programming algorithm for the AT90S1200 device mandates that
+the
+.Ql /RESET
+signal is active
+.Em before
+powering up the MCU, so in case an external power supply is used for this
+MCU type, a previous invocation of
+.Nm
+with this option specified is one of the possible ways to guarantee this
+condition.
+.It Ar noreset
+The
+.Ql /RESET
+line will be deactivated at program exit, thus allowing the MCU target
+program to run while the programming hardware remains connected.
+.It Ar vcc
+This option will leave those parallel port pins active
+.Pq \&i. \&e. Em high
+that can be used to supply
+.Ql Vcc
+power to the MCU.
+.It Ar novcc
+This option will pull the
+.Ql Vcc
+pins of the parallel port down at program exit.
+.El
+.Pp
+Multiple
+.Ar exitspec
+arguments can be separated with commas.
+.It Fl F
+Normally,
+.Nm
+tries to verify that the device signature read from the part is
+reasonable before continuing.  Since it can happen from time to time
+that a device has a broken (erased or overwritten) device signature
+but is otherwise operating normally, this options is provided to
+override the check.
+Also, for programmers like the Atmel STK500 and STK600 which can
+adjust parameters local to the programming tool (independent of an
+actual connection to a target controller), this option can be used
+together with
+.Fl t
+to continue in terminal mode.
+.It Fl i Ar delay
+For bitbang-type programmers, delay for approximately
+.Ar delay
+microseconds between each bit state change.
+If the host system is very fast, or the target runs off a slow clock
+(like a 32 kHz crystal, or the 128 kHz internal RC oscillator), this
+can become necessary to satisfy the requirement that the ISP clock
+frequency must not be higher than 1/4 of the CPU clock frequency.
+This is implemented as a spin-loop delay to allow even for very
+short delays.
+On Unix-style operating systems, the spin loop is initially calibrated
+against a system timer, so the number of microseconds might be rather
+realistic, assuming a constant system load while
+.Nm
+is running.
+On Win32 operating systems, a preconfigured number of cycles per
+microsecond is assumed that might be off a bit for very fast or very
+slow machines.
+.It Fl n
+No-write - disables actually writing data to the MCU (useful for debugging
+.Nm avrdude
+).
+.It Fl O
+Perform a RC oscillator run-time calibration according to Atmel
+application note AVR053.
+This is only supported on the STK500v2, AVRISP mkII, and JTAG ICE mkII
+hardware.
+Note that the result will be stored in the EEPROM cell at address 0.
+.It Fl P Ar port
+Use
+.Ar port
+to identify the device to which the programmer is attached.  By
+default the
+.Pa /dev/ppi0
+port is used, but if the programmer type normally connects to the
+serial port, the
+.Pa /dev/cuaa0
+port is the default.  If you need to use a different parallel or
+serial port, use this option to specify the alternate port name.
+.Pp
+On Win32 operating systems, the parallel ports are referred to as lpt1
+through lpt3, referring to the addresses 0x378, 0x278, and 0x3BC,
+respectively.  If the parallel port can be accessed through a different
+address, this address can be specified directly, using the common C
+language notation (i. e., hexadecimal values are prefixed by
+.Ql 0x
+).
+.Pp
+For the JTAG ICE mkII, if
+.Nm
+has been configured with libusb support,
+.Ar port
+can alternatively be specified as
+.Pa usb Ns Op \&: Ns Ar serialno .
+This will cause
+.Nm
+to search a JTAG ICE mkII on USB.
+If
+.Ar serialno
+is also specified, it will be matched against the serial number read
+from any JTAG ICE mkII found on USB.
+The match is done after stripping any existing colons from the given
+serial number, and right-to-left, so only the least significant bytes
+from the serial number need to be given.
+.Pp
+As the AVRISP mkII device can only be talked to over USB, the very
+same method of specifying the port is required there.
+.Pp
+For the USB programmer "AVR-Doper" running in HID mode, the port must
+be specified as
+.Ar avrdoper.
+Libusb support is required on Unix but not on Windows. For more
+information about AVR-Doper see http://www.obdev.at/avrusb/avrdoper.html.
+.Pp
+For programmers that attach to a serial port using some kind of
+higher level protocol (as opposed to bit-bang style programmers),
+.Ar port
+can be specified as
+.Pa net Ns \&: Ns Ar host Ns \&: Ns Ar port .
+In this case, instead of trying to open a local device, a TCP
+network connection to (TCP)
+.Ar port
+on
+.Ar host
+is established.
+The remote endpoint is assumed to be a terminal or console server
+that connects the network stream to a local serial port where the
+actual programmer has been attached to.
+The port is assumed to be properly configured, for example using a
+transparent 8-bit data connection without parity at 115200 Baud
+for a STK500.
+.Em This feature is currently not implemented for Win32 systems.
+.It Fl q
+Disable (or quell) output of the progress bar while reading or writing
+to the device.  Specify it a second time for even quieter operation.
+.It Fl s
+Disable safemode prompting.  When safemode discovers that one or more
+fuse bits have unintentionally changed, it will prompt for
+confirmation regarding whether or not it should attempt to recover the
+fuse bit(s).  Specifying this flag disables the prompt and assumes
+that the fuse bit(s) should be recovered without asking for
+confirmation first.
+.It Fl t
+Tells
+.Nm
+to enter the interactive ``terminal'' mode instead of up- or downloading
+files.  See below for a detailed description of the terminal mode.
+.It Fl u
+Disable the safemode fuse bit checks.  Safemode is enabled by default
+and is intended to prevent unintentional fuse bit changes.  When
+enabled, safemode will issue a warning if the any fuse bits are found
+to be different at program exit than they were when
+.Nm
+was invoked.  Safemode won't alter fuse bits itself, but rather will
+prompt for instructions, unless the terminal is non-interactive, in
+which case safemode is disabled.  See the
+.Fl s
+option to disable safemode prompting.
+.It Xo Fl U Ar memtype Ns
+.Ar \&: Ns Ar op Ns
+.Ar \&: Ns Ar filename Ns
+.Op \&: Ns Ar format
+.Xc
+Perform a memory operation as indicated.  The
+.Ar memtype
+field specifies the memory type to operate on.
+The available memory types are device-dependent, the actual
+configuration can be viewed with the
+.Cm part
+command in terminal mode.
+Typically, a device's memory configuration at least contains
+the memory types
+.Ar flash
+and
+.Ar eeprom .
+All memory types currently known are:
+.Bl -tag -width "calibration" -compact
+.It calibration
+One or more bytes of RC oscillator calibration data.
+.It eeprom
+The EEPROM of the device.
+.It efuse
+The extended fuse byte.
+.It flash
+The flash ROM of the device.
+.It fuse
+The fuse byte in devices that have only a single fuse byte.
+.It hfuse
+The high fuse byte.
+.It lfuse
+The low fuse byte.
+.It lock
+The lock byte.
+.It signature
+The three device signature bytes (device ID).
+.It fuse Ns Em N
+The fuse bytes of ATxmega devices,
+.Em N
+is an integer number
+for each fuse supported by the device.
+.It application
+The application flash area of ATxmega devices.
+.It apptable
+The application table flash area of ATxmega devices.
+.It boot
+The boot flash area of ATxmega devices.
+.It prodsig
+The production signature (calibration) area of ATxmega devices.
+.It usersig
+The user signature area of ATxmega devices.
+.El
+.Pp
+The
+.Ar op
+field specifies what operation to perform:
+.Bl -tag -width noreset
+.It Ar r
+read device memory and write to the specified file
+.It Ar w
+read data from the specified file and write to the device memory
+.It Ar v
+read data from both the device and the specified file and perform a verify
+.El
+.Pp
+The
+.Ar filename
+field indicates the name of the file to read or write.
+The
+.Ar format
+field is optional and contains the format of the file to read or
+write.
+.Ar Format
+can be one of:
+.Bl -tag -width sss
+.It Ar i
+Intel Hex
+.It Ar s
+Motorola S-record
+.It Ar r
+raw binary; little-endian byte order, in the case of the flash ROM data
+.It Ar m
+immediate; actual byte values specified on the command line, separated
+by commas or spaces.  This is good for programming fuse bytes without
+having to create a single-byte file or enter terminal mode.
+.It Ar a
+auto detect; valid for input only, and only if the input is not
+provided at
+.Em stdin .
+.It Ar d
+decimal; this and the following formats are only valid on output.
+They generate one line of output for the respective memory section,
+forming a comma-separated list of the values.
+This can be particularly useful for subsequent processing, like for
+fuse bit settings.
+.It Ar h
+hexadecimal; each value will get the string
+.Em 0x
+prepended.
+.It Ar o
+octal; each value will get a
+.Em 0
+prepended unless it is less than 8 in which case it gets no prefix.
+.It Ar b
+binary; each value will get the string
+.Em 0b
+prepended.
+.El
+.Pp
+The default is to use auto detection for input files, and raw binary
+format for output files.
+Note that if
+.Ar filename
+contains a colon, the
+.Ar format
+field is no longer optional since the filename part following the colon
+would otherwise be misinterpreted as
+.Ar format .
+.Pp
+As an abbreviation, the form
+.Fl U Ar filename
+is equivalent to specifying
+.Fl U Em flash:w: Ns Ar filename Ns :a .
+This will only work if
+.Ar filename
+does not have a colon in it.
+.It Fl v
+Enable verbose output.
+.It Fl V
+Disable automatic verify check when uploading data.
+.It Fl x Ar extended_param
+Pass
+.Ar extended_param
+to the chosen programmer implementation as an extended parameter.
+The interpretation of the extended parameter depends on the
+programmer itself.
+See below for a list of programmers accepting extended parameters.
+.It Fl y
+Tells
+.Nm
+to use the last four bytes of the connected parts' EEPROM memory to
+track the number of times the device has been erased.  When this
+option is used and the
+.Fl e
+flag is specified to generate a chip erase, the previous counter will
+be saved before the chip erase, it is then incremented, and written
+back after the erase cycle completes.  Presumably, the device would
+only be erased just before being programmed, and thus, this can be
+utilized to give an indication of how many erase-rewrite cycles the
+part has undergone.  Since the FLASH memory can only endure a finite
+number of erase-rewrite cycles, one can use this option to track when
+a part is nearing the limit.  The typical limit for Atmel AVR FLASH is
+1000 cycles.  Of course, if the application needs the last four bytes
+of EEPROM memory, this option should not be used.
+.It Fl Y Ar cycles
+Instructs
+.Nm
+to initialize the erase-rewrite cycle counter residing at the last four
+bytes of EEPROM memory to the specified value.  If the application
+needs the last four bytes of EEPROM memory, this option should not be
+used.
+.El
+.Ss Terminal mode
+In this mode,
+.Nm
+only initializes communication with the MCU, and then awaits user
+commands on standard input.  Commands and parameters may be
+abbreviated to the shortest unambiguous form.  Terminal mode provides
+a command history using
+.Xr readline 3 ,
+so previously entered command lines can be recalled and edited.  The
+following commands are currently implemented:
+.Bl -tag -offset indent -width indent
+.It Ar dump memtype addr nbytes
+Read
+.Ar nbytes
+bytes from the specified memory area, and display them in the usual
+hexadecimal and ASCII form.
+.It Ar dump
+Continue dumping the memory contents for another
+.Ar nbytes
+where the previous
+.Ar dump
+command left off.
+.It Ar write memtype addr byte1 ... byteN
+Manually program the respective memory cells, starting at address
+.Ar addr ,
+using the values
+.Ar byte1
+through
+.Ar byteN .
+This feature is not implemented for bank-addressed memories such as
+the flash memory of ATMega devices.
+.It Ar erase
+Perform a chip erase.
+.It Ar send b1 b2 b3 b4
+Send raw instruction codes to the AVR device.  If you need access to a
+feature of an AVR part that is not directly supported by
+.Nm ,
+this command allows you to use it, even though
+.Nm
+does not implement the command. When using direct SPI mode, up to 3 bytes
+can be omitted.
+.It Ar sig
+Display the device signature bytes.
+.It Ar spi
+Enter direct SPI mode.  The
+.Em pgmled
+pin acts as slave select.
+.Em Only supported on parallel bitbang programmers.
+.It Ar part
+Display the current part settings and parameters.  Includes chip
+specific information including all memory types supported by the
+device, read/write timing, etc.
+.It Ar pgm
+Return to programming mode (from direct SPI mode).
+.It Ar vtarg voltage
+Set the target's supply voltage to
+.Ar voltage
+Volts.
+.Em Only supported on the STK500 and STK600 programmer.
+.It Ar varef Oo Ar channel Oc Ar voltage
+Set the adjustable voltage source to
+.Ar voltage
+Volts.
+This voltage is normally used to drive the target's
+.Em Aref
+input on the STK500.
+On the Atmel STK600, two reference voltages are available, which
+can be selected by the optional
+.Ar channel
+argument (either 0 or 1).
+.Em Only supported on the STK500 and STK600 programmer.
+.It Ar fosc freq Ns Op M Ns \&| Ns k
+Set the master oscillator to
+.Ar freq
+Hz.
+An optional trailing letter
+.Ar \&M
+multiplies by 1E6, a trailing letter
+.Ar \&k
+by 1E3.
+.Em Only supported on the STK500 and STK600 programmer.
+.It Ar fosc off
+Turn the master oscillator off.
+.Em Only supported on the STK500 and STK600 programmer.
+.It Ar sck period
+.Em STK500 and STK600 programmer only:
+Set the SCK clock period to
+.Ar period
+microseconds.
+.Pp
+.Em JTAG ICE only:
+Set the JTAG ICE bit clock period to
+.Ar period
+microseconds.
+Note that unlike STK500 settings, this setting will be reverted to
+its default value (approximately 1 microsecond) when the programming
+software signs off from the JTAG ICE.
+This parameter can also be used on the JTAG ICE mkII to specify the
+ISP clock period when operating the ICE in ISP mode.
+.It Ar parms
+.Em STK500 and STK600 programmer only:
+Display the current voltage and master oscillator parameters.
+.Pp
+.Em JTAG ICE only:
+Display the current target supply voltage and JTAG bit clock rate/period.
+.It Ar \&?
+.It Ar help
+Give a short on-line summary of the available commands.
+.It Ar quit
+Leave terminal mode and thus
+.Nm avrdude .
+.El
+.Ss Default Parallel port pin connections
+(these can be changed, see the
+.Fl c
+option)
+.TS
+ll.
+\fBPin number\fP	\fBFunction\fP
+2-5	Vcc (optional power supply to MCU)
+7	/RESET (to MCU)
+8	SCK (to MCU)
+9	MOSI (to MCU)
+10	MISO (from MCU)
+18-25	GND
+.TE
+.Ss debugWire limitations
+The debugWire protocol is Atmel's proprietary one-wire (plus ground)
+protocol to allow an in-circuit emulation of the smaller AVR devices,
+using the
+.Ql /RESET
+line.
+DebugWire mode is initiated by activating the
+.Ql DWEN
+fuse, and then power-cycling the target.
+While this mode is mainly intended for debugging/emulation, it
+also offers limited programming capabilities.
+Effectively, the only memory areas that can be read or programmed
+in this mode are flash ROM and EEPROM.
+It is also possible to read out the signature.
+All other memory areas cannot be accessed.
+There is no
+.Em chip erase
+functionality in debugWire mode; instead, while reprogramming the
+flash ROM, each flash ROM page is erased right before updating it.
+This is done transparently by the JTAG ICE mkII (or AVR Dragon).
+The only way back from debugWire mode is to initiate a special
+sequence of commands to the JTAG ICE mkII (or AVR Dragon), so the
+debugWire mode will be temporarily disabled, and the target can
+be accessed using normal ISP programming.
+This sequence is automatically initiated by using the JTAG ICE mkII
+or AVR Dragon in ISP mode, when they detect that ISP mode cannot be
+entered.
+.Ss Programmers accepting extended parameters
+.Bl -tag -offset indent -width indent
+.It Ar JTAG ICE mkII
+.It Ar AVR Dragon
+When using the JTAG ICE mkII or AVR Dragon in JTAG mode, the
+following extended parameter is accepted:
+.Bl -tag -offset indent -width indent
+.It Ar jtagchain=UB,UA,BB,BA
+Setup the JTAG scan chain for
+.Ar UB
+units before,
+.Ar UA
+units after,
+.Ar BB
+bits before, and
+.Ar BA
+bits after the target AVR, respectively.
+Each AVR unit within the chain shifts by 4 bits.
+Other JTAG units might require a different bit shift count.
+.El
+.It Ar AVR910
+.Bl -tag -offset indent -width indent
+.It Ar devcode=VALUE
+Override the device code selection by using
+.Ar VALUE
+as the device code.
+The programmer is not queried for the list of supported
+device codes, and the specified
+.Ar VALUE
+is not verified but used directly within the
+.Ql T
+command sent to the programmer.
+.Ar VALUE
+can be specified using the conventional number notation of the
+C programming language.
+.El
+.Bl -tag -offset indent -width indent
+.It Ar no_blockmode
+Disables the default checking for block transfer capability.
+Use 
+.Ar no_blockmode
+only if your
+.Ar AVR910
+programmer creates errors during initial sequence. 
+.El
+.It Ar buspirate
+.Bl -tag -offset indent -width indent
+.It Ar reset={cs,aux,aux2}
+The default setup assumes the BusPirate's CS output pin connected to 
+the RESET pin on AVR side. It is however possible to have multiple AVRs
+connected to the same BP with MISO, MOSI and SCK lines common for all of them.
+In such a case one AVR should have its RESET connected to BusPirate's
+.Pa CS
+pin, second AVR's RESET connected to BusPirate's
+.Pa AUX
+pin and if your BusPirate has an
+.Pa AUX2
+pin (only available on BusPirate version v1a with firmware 3.0 or newer)
+use that to activate RESET on the third AVR.
+.Pp
+It may be a good idea to decouple the BusPirate and the AVR's SPI buses from 
+each other using a 3-state bus buffer. For example 74HC125 or 74HC244 are some
+good candidates with the latches driven by the appropriate reset pin (cs, 
+aux or aux2). Otherwise the SPI traffic in one active circuit may interfere
+with programming the AVR in the other design.
+.It Ar speed=<0..7>
+BusPirate to AVR SPI speed:
+.Bd -literal
+0 ..  30 kHz   (default)
+1 .. 125 kHz
+2 .. 250 kHz
+3 ..   1 MHz
+4 ..   2 MHz
+5 ..   2.6 MHz
+6 ..   4 MHz
+7 ..   8 MHz
+.Ed
+.It Ar ascii
+Use ASCII mode even when the firmware supports BinMode (binary mode). 
+BinMode is supported in firmware 2.7 and newer, older FW's either don't
+have BinMode or their BinMode is buggy. ASCII mode is slower and makes 
+the above
+.Ar reset=
+and 
+.Ar speed=
+parameters unavailable. 
+.El
+.El
+.Sh FILES
+.Bl -tag -offset indent -width /dev/ppi0XXX
+.It Pa /dev/ppi0
+default device to be used for communication with the programming
+hardware
+.It Pa ${PREFIX}/etc/avrdude.conf
+programmer and parts configuration file
+.It Pa ${HOME}/.avrduderc
+programmer and parts configuration file (per-user overrides)
+.It Pa ~/.inputrc
+Initialization file for the
+.Xr readline 3
+library
+.It Pa ${PREFIX}/share/doc/avrdude/avrdude.pdf
+Schematic of programming hardware
+.El
+.\" .Sh EXAMPLES
+.Sh DIAGNOSTICS
+.Bd -literal
+avrdude: jtagmkII_setparm(): bad response to set parameter command: RSP_FAILED
+avrdude: jtagmkII_getsync(): ISP activation failed, trying debugWire
+avrdude: Target prepared for ISP, signed off.
+avrdude: Please restart avrdude without power-cycling the target.
+.Ed
+.Pp
+If the target AVR has been set up for debugWire mode (i. e. the
+.Em DWEN
+fuse is programmed), normal ISP connection attempts will fail as
+the
+.Em /RESET
+pin is not available.
+When using the JTAG ICE mkII in ISP mode, the message shown indicates
+that
+.Nm
+has guessed this condition, and tried to initiate a debugWire reset
+to the target.
+When successful, this will leave the target AVR in a state where it
+can respond to normal ISP communication again (until the next power
+cycle).
+Typically, the same command is going to be retried again immediately
+afterwards, and will then succeed connecting to the target using
+normal ISP communication.
+.Sh SEE ALSO
+.Xr avr-objcopy 1 ,
+.Xr ppi 4 ,
+.Xr readline 3
+.Pp
+The AVR microcontroller product description can be found at
+.Pp
+.Dl "http://www.atmel.com/products/AVR/"
+.\" .Sh HISTORY
+.Sh AUTHORS
+.Nm Avrdude
+was written by Brian S. Dean <bsd@bsdhome.com>.
+.Pp
+This man page by
+.ie t J\(:org Wunsch.
+.el Joerg Wunsch.
+.Sh BUGS
+Please report bugs via
+.Dl "http://savannah.nongnu.org/bugs/?group=avrdude" .
+.Pp
+The JTAG ICE programmers currently cannot write to the flash ROM
+one byte at a time.
+For that reason, updating the flash ROM from terminal mode does not
+work.
+.Pp
+Page-mode programming the EEPROM through JTAG (i.e. through an
+.Fl U
+option) requires a prior chip erase.
+This is an inherent feature of the way JTAG EEPROM programming works.
+This also applies to the STK500 and STK600 in parallel programming mode.
+.Pp
+The USBasp and USBtinyISP drivers do not offer any option to distinguish multiple
+devices connected simultaneously, so effectively only a single device
+is supported.
diff --git a/avrdude/avrdude.conf.in b/avrdude/avrdude.conf.in
new file mode 100644
index 00000000..24f30320
--- /dev/null
+++ b/avrdude/avrdude.conf.in
@@ -0,0 +1,15480 @@
+# $Id$
+#
+# AVRDUDE Configuration File
+#
+# This file contains configuration data used by AVRDUDE which describes
+# the programming hardware pinouts and also provides part definitions.
+# AVRDUDE's "-C" command line option specifies the location of the
+# configuration file.  The "-c" option names the programmer configuration
+# which must match one of the entry's "id" parameter.  The "-p" option
+# identifies which part AVRDUDE is going to be programming and must match
+# one of the parts' "id" parameter.
+#
+# Possible entry formats are:
+#
+#   programmer
+#       id       = <id1> [, <id2> [, <id3>] ...] ;  # <idN> are quoted strings
+#       desc     = <description> ;                  # quoted string
+#       type     = par | stk500 | stk500v2 | stk500pp | stk500hvsp | stk500generic |
+#                  stk600 | stk600pp | stk600hvsp |
+#                  avr910 | butterfly | usbasp |
+#                  jtagmki | jtagmkii | jtagmkii_isp | jtagmkii_dw |
+#                  jtagmkII_avr32 | jtagmkii_pdi |
+#                  dragon_dw | dragon_jtag | dragon_isp | dragon_pp |
+#                  dragon_hvsp | dragon_pdi | arduino; # programmer type
+#       baudrate = <num> ;                          # baudrate for avr910-programmer
+#       vcc      = <num1> [, <num2> ... ] ;         # pin number(s)
+#       reset    = <num> ;                          # pin number
+#       sck      = <num> ;                          # pin number
+#       mosi     = <num> ;                          # pin number
+#       miso     = <num> ;                          # pin number
+#       errled   = <num> ;                          # pin number
+#       rdyled   = <num> ;                          # pin number
+#       pgmled   = <num> ;                          # pin number
+#       vfyled   = <num> ;                          # pin number
+#     ;
+#
+#   part
+#       id               = <id> ;                 # quoted string
+#       desc             = <description> ;        # quoted string
+#       has_jtag         = <yes/no> ;             # part has JTAG i/f
+#       has_debugwire    = <yes/no> ;             # part has debugWire i/f
+#       has_pdi          = <yes/no> ;             # part has PDI i/f
+#       has_tpi          = <yes/no> ;             # part has TPI i/f
+#       devicecode       = <num> ;            # deprecated, use stk500_devcode
+#       stk500_devcode   = <num> ;                # numeric
+#       avr910_devcode   = <num> ;                # numeric
+#       signature        = <num> <num> <num> ;    # signature bytes
+#       chip_erase_delay = <num> ;                # micro-seconds
+#       reset            = dedicated | io;
+#       retry_pulse      = reset | sck;
+#       pgm_enable       = <instruction format> ;
+#       chip_erase       = <instruction format> ;
+#       chip_erase_delay = <num> ;                # chip erase delay (us)
+#       # STK500 parameters (parallel programming IO lines)
+#       pagel            = <num> ;                # pin name in hex, i.e., 0xD7
+#       bs2              = <num> ;                # pin name in hex, i.e., 0xA0
+#       serial           = <yes/no> ;             # can use serial downloading
+#       parallel         = <yes/no/pseudo>;       # can use par. programming
+#       # STK500v2 parameters, to be taken from Atmel's XML files
+#       timeout          = <num> ;
+#       stabdelay        = <num> ;
+#       cmdexedelay      = <num> ;
+#       synchloops       = <num> ;
+#       bytedelay        = <num> ;
+#       pollvalue        = <num> ;
+#       pollindex        = <num> ;
+#       predelay         = <num> ;
+#       postdelay        = <num> ;
+#       pollmethod       = <num> ;
+#       mode             = <num> ;
+#       delay            = <num> ;
+#       blocksize        = <num> ;
+#       readsize         = <num> ;
+#       hvspcmdexedelay  = <num> ;
+#       # STK500v2 HV programming parameters, from XML
+#       pp_controlstack  = <num>, <num>, ...;   # PP only
+#       hvsp_controlstack = <num>, <num>, ...;  # HVSP only
+#       hventerstabdelay = <num>;
+#       progmodedelay    = <num>;               # PP only
+#       latchcycles      = <num>;
+#       togglevtg        = <num>;
+#       poweroffdelay    = <num>;
+#       resetdelayms     = <num>;
+#       resetdelayus     = <num>;
+#       hvleavestabdelay = <num>;
+#       resetdelay       = <num>;
+#       synchcycles      = <num>;               # HVSP only
+#       chiperasepulsewidth = <num>;            # PP only
+#       chiperasepolltimeout = <num>;
+#       chiperasetime    = <num>;               # HVSP only
+#       programfusepulsewidth = <num>;          # PP only
+#       programfusepolltimeout = <num>;
+#       programlockpulsewidth = <num>;          # PP only
+#       programlockpolltimeout = <num>;
+#       # JTAG ICE mkII parameters, also from XML files
+#       allowfullpagebitstream = <yes/no> ;
+#       enablepageprogramming = <yes/no> ;
+#       idr              = <num> ;                # IO addr of IDR (OCD) reg.
+#       rampz            = <num> ;                # IO addr of RAMPZ reg.
+#       spmcr            = <num> ;                # mem addr of SPMC[S]R reg.
+#       eecr             = <num> ;                # mem addr of EECR reg.
+#                                                 # (only when != 0x3c)
+#       is_avr32         = <yes/no> ;             # AVR32 part
+#
+#       memory <memtype>
+#           paged           = <yes/no> ;          # yes / no
+#           size            = <num> ;             # bytes
+#           page_size       = <num> ;             # bytes
+#           num_pages       = <num> ;             # numeric
+#           min_write_delay = <num> ;             # micro-seconds
+#           max_write_delay = <num> ;             # micro-seconds
+#           readback_p1     = <num> ;             # byte value
+#           readback_p2     = <num> ;             # byte value
+#           pwroff_after_write = <yes/no> ;       # yes / no
+#           read            = <instruction format> ;
+#           write           = <instruction format> ;
+#           read_lo         = <instruction format> ;
+#           read_hi         = <instruction format> ;
+#           write_lo        = <instruction format> ;
+#           write_hi        = <instruction format> ;
+#           loadpage_lo     = <instruction format> ;
+#           loadpage_hi     = <instruction format> ;
+#           writepage       = <instruction format> ;
+#         ;
+#     ;
+#
+# If any of the above parameters are not specified, the default value
+# of 0 is used for numerics or the empty string ("") for string
+# values.  If a required parameter is left empty, AVRDUDE will
+# complain.
+#
+# NOTES:
+#   * 'devicecode' is the device code used by the STK500 (see codes 
+#       listed below)
+#   * Not all memory types will implement all instructions.
+#   * AVR Fuse bits and Lock bits are implemented as a type of memory.
+#   * Example memory types are:
+#       "flash", "eeprom", "fuse", "lfuse" (low fuse), "hfuse" (high
+#       fuse), "signature", "calibration", "lock"
+#   * The memory type specified on the avrdude command line must match
+#     one of the memory types defined for the specified chip.
+#   * The pwroff_after_write flag causes avrdude to attempt to
+#     power the device off and back on after an unsuccessful write to
+#     the affected memory area if VCC programmer pins are defined.  If
+#     VCC pins are not defined for the programmer, a message
+#     indicating that the device needs a power-cycle is printed out.
+#     This flag was added to work around a problem with the
+#     at90s4433/2333's; see the at90s4433 errata at:
+#
+#         http://www.atmel.com/atmel/acrobat/doc1280.pdf
+#
+# INSTRUCTION FORMATS
+#
+#    Instruction formats are specified as a comma seperated list of
+#    string values containing information (bit specifiers) about each
+#    of the 32 bits of the instruction.  Bit specifiers may be one of
+#    the following formats:
+#
+#       '1'  = the bit is always set on input as well as output
+#
+#       '0'  = the bit is always clear on input as well as output
+#
+#       'x'  = the bit is ignored on input and output
+#
+#       'a'  = the bit is an address bit, the bit-number matches this bit
+#              specifier's position within the current instruction byte
+#
+#       'aN' = the bit is the Nth address bit, bit-number = N, i.e., a12
+#              is address bit 12 on input, a0 is address bit 0.
+#
+#       'i'  = the bit is an input data bit
+#
+#       'o'  = the bit is an output data bit
+#
+#    Each instruction must be composed of 32 bit specifiers.  The
+#    instruction specification closely follows the instruction data
+#    provided in Atmel's data sheets for their parts.
+#
+# See below for some examples.
+#
+#
+# The following are STK500 part device codes to use for the
+# "devicecode" field of the part.  These came from Atmel's software
+# section avr061.zip which accompanies the application note
+# AVR061 available from:
+#
+#      http://www.atmel.com/atmel/acrobat/doc2525.pdf
+#
+
+#define ATTINY10    0x10  /* the _old_ one that never existed! */
+#define ATTINY11    0x11
+#define ATTINY12    0x12
+#define ATTINY15    0x13
+#define ATTINY13    0x14
+
+#define ATTINY22    0x20
+#define ATTINY26    0x21
+#define ATTINY28    0x22
+#define ATTINY2313  0x23
+
+#define AT90S1200   0x33
+
+#define AT90S2313   0x40
+#define AT90S2323   0x41
+#define AT90S2333   0x42
+#define AT90S2343   0x43
+
+#define AT90S4414   0x50
+#define AT90S4433   0x51
+#define AT90S4434   0x52
+#define ATMEGA48    0x59
+
+#define AT90S8515   0x60
+#define AT90S8535   0x61
+#define AT90C8534   0x62
+#define ATMEGA8515  0x63
+#define ATMEGA8535  0x64
+
+#define ATMEGA8     0x70
+#define ATMEGA88    0x73
+#define ATMEGA168   0x86
+
+#define ATMEGA161   0x80
+#define ATMEGA163   0x81
+#define ATMEGA16    0x82
+#define ATMEGA162   0x83
+#define ATMEGA169   0x84
+
+#define ATMEGA323   0x90
+#define ATMEGA32    0x91
+
+#define ATMEGA64    0xA0
+
+#define ATMEGA103   0xB1
+#define ATMEGA128   0xB2
+#define AT90CAN128  0xB3
+#define AT90CAN64   0xB3
+#define AT90CAN32   0xB3
+
+#define AT86RF401   0xD0
+
+#define AT89START   0xE0
+#define AT89S51	    0xE0
+#define AT89S52	    0xE1
+
+# The following table lists the devices in the original AVR910
+# appnote:
+# |Device |Signature | Code |
+# +-------+----------+------+
+# |tiny12 | 1E 90 05 | 0x55 |
+# |tiny15 | 1E 90 06 | 0x56 |
+# |       |          |      |
+# | S1200 | 1E 90 01 | 0x13 |
+# |       |          |      |
+# | S2313 | 1E 91 01 | 0x20 |
+# | S2323 | 1E 91 02 | 0x48 |
+# | S2333 | 1E 91 05 | 0x34 |
+# | S2343 | 1E 91 03 | 0x4C |
+# |       |          |      |
+# | S4414 | 1E 92 01 | 0x28 |
+# | S4433 | 1E 92 03 | 0x30 |
+# | S4434 | 1E 92 02 | 0x6C |
+# |       |          |      |
+# | S8515 | 1E 93 01 | 0x38 |
+# | S8535 | 1E 93 03 | 0x68 |
+# |       |          |      |
+# |mega32 | 1E 95 01 | 0x72 |
+# |mega83 | 1E 93 05 | 0x65 |
+# |mega103| 1E 97 01 | 0x41 |
+# |mega161| 1E 94 01 | 0x60 |
+# |mega163| 1E 94 02 | 0x64 |
+
+# Appnote AVR109 also has a table of AVR910 device codes, which
+# lists:
+# dev         avr910   signature
+# ATmega8     0x77     0x1E 0x93 0x07
+# ATmega8515  0x3B     0x1E 0x93 0x06
+# ATmega8535  0x6A     0x1E 0x93 0x08
+# ATmega16    0x75     0x1E 0x94 0x03
+# ATmega162   0x63     0x1E 0x94 0x04
+# ATmega163   0x66     0x1E 0x94 0x02
+# ATmega169   0x79     0x1E 0x94 0x05
+# ATmega32    0x7F     0x1E 0x95 0x02
+# ATmega323   0x73     0x1E 0x95 0x01
+# ATmega64    0x46     0x1E 0x96 0x02
+# ATmega128   0x44     0x1E 0x97 0x02
+#
+# These codes refer to "BOOT" device codes which are apparently
+# different than standard device codes, for whatever reasons
+# (often one above the standard code).
+
+# There are several extended versions of AVR910 implementations around
+# in the Internet.  These add the following codes (only devices that
+# actually exist are listed):
+
+# ATmega8515	0x3A
+# ATmega128	0x43
+# ATmega64	0x45
+# ATtiny26	0x5E
+# ATmega8535	0x69
+# ATmega32	0x72
+# ATmega16	0x74
+# ATmega8	0x76
+# ATmega169	0x78
+
+#
+# Overall avrdude defaults
+#
+default_parallel   = "@DEFAULT_PAR_PORT@";
+default_serial     = "@DEFAULT_SER_PORT@";
+
+
+#
+# PROGRAMMER DEFINITIONS
+#
+
+programmer
+  id    = "arduino";
+  desc  = "Arduino";
+  type  = arduino;
+;
+
+programmer
+  id    = "avrisp";
+  desc  = "Atmel AVR ISP";
+  type  = stk500;
+;
+
+programmer
+  id    = "avrispv2";
+  desc  = "Atmel AVR ISP V2";
+  type  =  stk500v2;
+;
+
+programmer
+  id    = "avrispmkII";
+  desc  = "Atmel AVR ISP mkII";
+  type  =  stk500v2;
+;
+
+programmer
+  id    = "avrisp2";
+  desc  = "Atmel AVR ISP mkII";
+  type  =  stk500v2;
+;
+
+programmer
+  id    = "buspirate";
+  desc  = "The Bus Pirate";
+  type  = buspirate;
+;
+
+# This is supposed to be the "default" STK500 entry.
+# Attempts to select the correct firmware version
+# by probing for it.  Better use one of the entries
+# below instead.
+programmer
+  id    = "stk500";
+  desc  = "Atmel STK500";
+  type  = stk500generic;
+;
+
+programmer
+  id    = "stk500v1";
+  desc  = "Atmel STK500 Version 1.x firmware";
+  type  = stk500;
+;
+
+programmer
+  id    = "mib510";
+  desc  = "Crossbow MIB510 programming board";
+  type  = stk500;
+;
+
+programmer
+  id    = "stk500v2";
+  desc  = "Atmel STK500 Version 2.x firmware";
+  type  = stk500v2;
+;
+
+programmer
+  id    = "stk500pp";
+  desc  = "Atmel STK500 V2 in parallel programming mode";
+  type  = stk500pp;
+;
+
+programmer
+  id    = "stk500hvsp";
+  desc  = "Atmel STK500 V2 in high-voltage serial programming mode";
+  type  = stk500hvsp;
+;
+
+programmer
+  id    = "stk600";
+  desc  = "Atmel STK600";
+  type  = stk600;
+;
+
+programmer
+  id    = "stk600pp";
+  desc  = "Atmel STK600 in parallel programming mode";
+  type  = stk600pp;
+;
+
+programmer
+  id    = "stk600hvsp";
+  desc  = "Atmel STK600 in high-voltage serial programming mode";
+  type  = stk600hvsp;
+;
+
+programmer
+  id    = "avr910";
+  desc  = "Atmel Low Cost Serial Programmer";
+  type  = avr910;
+;
+
+programmer
+  id    = "usbasp";
+  desc  = "USBasp, http://www.fischl.de/usbasp/";
+  type  = usbasp;
+;
+
+programmer
+  id    = "usbtiny";
+  desc  = "USBtiny simple USB programmer, http://www.ladyada.net/make/usbtinyisp/";
+  type  = usbtiny;
+;
+
+programmer
+  id    = "butterfly";
+  desc  = "Atmel Butterfly Development Board";
+  type  = butterfly;
+;
+
+programmer
+  id    = "avr109";
+  desc  = "Atmel AppNote AVR109 Boot Loader";
+  type  = butterfly;
+;
+
+programmer
+  id    = "avr911";
+  desc  = "Atmel AppNote AVR911 AVROSP";
+  type  = butterfly;
+;
+
+programmer
+  id    = "jtagmkI";
+  desc  = "Atmel JTAG ICE (mkI)";
+  baudrate = 115200;    # default is 115200
+  type  = jtagmki;
+;
+
+# easier to type
+programmer
+  id    = "jtag1";
+  desc  = "Atmel JTAG ICE (mkI)";
+  baudrate = 115200;    # default is 115200
+  type  = jtagmki;
+;
+
+# easier to type
+programmer
+  id    = "jtag1slow";
+  desc  = "Atmel JTAG ICE (mkI)";
+  baudrate = 19200;
+  type  = jtagmki;
+;
+
+programmer
+  id    = "jtagmkII";
+  desc  = "Atmel JTAG ICE mkII";
+  baudrate = 19200;    # default is 19200
+  type  = jtagmkii;
+;
+
+# easier to type
+programmer
+  id    = "jtag2slow";
+  desc  = "Atmel JTAG ICE mkII";
+  baudrate = 19200;    # default is 19200
+  type  = jtagmkii;
+;
+
+# JTAG ICE mkII @ 115200 Bd
+programmer
+  id    = "jtag2fast";
+  desc  = "Atmel JTAG ICE mkII";
+  baudrate = 115200;
+  type  = jtagmkii;
+;
+
+# make the fast one the default, people will love that
+programmer
+  id    = "jtag2";
+  desc  = "Atmel JTAG ICE mkII";
+  baudrate = 115200;
+  type  = jtagmkii;
+;
+
+# JTAG ICE mkII in ISP mode
+programmer
+  id    = "jtag2isp";
+  desc  = "Atmel JTAG ICE mkII in ISP mode";
+  baudrate = 115200;
+  type  = jtagmkii_isp;
+;
+
+# JTAG ICE mkII in debugWire mode
+programmer
+  id    = "jtag2dw";
+  desc  = "Atmel JTAG ICE mkII in debugWire mode";
+  baudrate = 115200;
+  type  = jtagmkii_dw;
+;
+
+# JTAG ICE mkII in AVR32 mode
+programmer
+  id    = "jtagmkII_avr32";
+  desc  = "Atmel JTAG ICE mkII im AVR32 mode";
+  baudrate = 115200;
+  type  = jtagmkii_avr32;
+;
+
+# JTAG ICE mkII in AVR32 mode
+programmer
+  id    = "jtag2avr32";
+  desc  = "Atmel JTAG ICE mkII im AVR32 mode";
+  baudrate = 115200;
+  type  = jtagmkii_avr32;
+;
+
+# JTAG ICE mkII in PDI mode
+programmer
+  id    = "jtag2pdi";
+  desc  = "Atmel JTAG ICE mkII PDI mode";
+  baudrate = 115200;
+  type  = jtagmkii_pdi;
+;
+
+# AVR Dragon in JTAG mode
+programmer
+  id    = "dragon_jtag";
+  desc  = "Atmel AVR Dragon in JTAG mode";
+  baudrate = 115200;
+  type  = dragon_jtag;
+;
+
+# AVR Dragon in ISP mode
+programmer
+  id    = "dragon_isp";
+  desc  = "Atmel AVR Dragon in ISP mode";
+  baudrate = 115200;
+  type  = dragon_isp;
+;
+
+# AVR Dragon in PP mode
+programmer
+  id    = "dragon_pp";
+  desc  = "Atmel AVR Dragon in PP mode";
+  baudrate = 115200;
+  type  = dragon_pp;
+;
+
+# AVR Dragon in HVSP mode
+programmer
+  id    = "dragon_hvsp";
+  desc  = "Atmel AVR Dragon in HVSP mode";
+  baudrate = 115200;
+  type  = dragon_hvsp;
+;
+
+# AVR Dragon in debugWire mode
+programmer
+  id    = "dragon_dw";
+  desc  = "Atmel AVR Dragon in debugWire mode";
+  baudrate = 115200;
+  type  = dragon_dw;
+;
+
+# AVR Dragon in PDI mode
+programmer
+  id    = "dragon_pdi";
+  desc  = "Atmel AVR Dragon in PDI mode";
+  baudrate = 115200;
+  type  = dragon_pdi;
+;
+
+programmer
+  id    = "pavr";
+  desc  = "Jason Kyle's pAVR Serial Programmer";
+  type  = avr910;
+;
+
+@HAVE_PARPORT_BEGIN@  Inclusion of the following depends on --enable-parport
+# Parallel port programmers.
+
+programmer
+  id    = "bsd";
+  desc  = "Brian Dean's Programmer, http://www.bsdhome.com/avrdude/";
+  type  = par;
+  vcc   = 2, 3, 4, 5;
+  reset = 7;
+  sck   = 8;
+  mosi  = 9;
+  miso  = 10;
+;
+
+programmer
+  id    = "stk200";
+  desc  = "STK200";
+  type  = par;
+  buff  = 4, 5;
+  sck   = 6;
+  mosi  = 7;
+  reset = 9;
+  miso  = 10;
+;
+
+# The programming dongle used by the popular Ponyprog
+# utility.  It is almost similar to the STK200 one,
+# except that there is a LED indicating that the
+# programming is currently in progress.
+
+programmer
+  id    = "pony-stk200";
+  desc  = "Pony Prog STK200";
+  type  = par;
+  buff  = 4, 5;
+  sck   = 6;
+  mosi  = 7;
+  reset = 9;
+  miso  = 10;
+  pgmled = 8; 
+;
+
+programmer
+  id    = "dt006";
+  desc  = "Dontronics DT006";
+  type  = par;
+  reset = 4;
+  sck   = 5;
+  mosi  = 2;
+  miso  = 11;
+;
+
+programmer
+  id    = "bascom";
+  desc  = "Bascom SAMPLE programming cable";
+  type  = par;
+  reset = 4;
+  sck   = 5;
+  mosi  = 2;
+  miso  = 11;
+;
+
+programmer
+  id     = "alf";
+  desc   = "Nightshade ALF-PgmAVR, http://nightshade.homeip.net/";
+  type   = par;
+  vcc    = 2, 3, 4, 5;
+  buff   = 6;
+  reset  = 7;
+  sck    = 8;
+  mosi   = 9;
+  miso   = 10;
+  errled = 1;
+  rdyled = 14;
+  pgmled = 16;
+  vfyled = 17;
+;
+
+programmer
+  id    = "sp12";
+  desc  = "Steve Bolt's Programmer";
+  type  = par;
+  vcc   = 4,5,6,7,8;
+  reset = 3;
+  sck   = 2;
+  mosi  = 9;
+  miso  = 11;
+;
+
+programmer
+  id     = "picoweb";
+  desc   = "Picoweb Programming Cable, http://www.picoweb.net/";
+  type   = par;
+  reset  = 2;
+  sck    = 3;
+  mosi   = 4;
+  miso   = 13;
+;
+
+programmer
+  id    = "abcmini";
+  desc  = "ABCmini Board, aka Dick Smith HOTCHIP";
+  type  = par;
+  reset = 4;
+  sck   = 3;
+  mosi  = 2;
+  miso  = 10;
+;
+
+programmer
+  id    = "futurlec";
+  desc  = "Futurlec.com programming cable.";
+  type  = par;
+  reset = 3;
+  sck   = 2;
+  mosi  = 1;
+  miso  = 10;
+;
+
+
+# From the contributor of the "xil" jtag cable:
+# The "vcc" definition isn't really vcc (the cable gets its power from
+# the programming circuit) but is necessary to switch one of the
+# buffer lines (trying to add it to the "buff" lines doesn't work).
+# With this, TMS connects to RESET, TDI to MOSI, TDO to MISO and TCK
+# to SCK (plus vcc/gnd of course)
+programmer
+  id    = "xil";
+  desc  = "Xilinx JTAG cable";
+  type  = par;
+  mosi  = 2;
+  sck   = 3;
+  reset = 4;
+  buff  = 5;
+  miso  = 13;
+  vcc   = 6;
+;
+
+
+programmer
+  id = "dapa";
+  desc = "Direct AVR Parallel Access cable";
+  type = par;
+  vcc   = 3;
+  reset = 16;
+  sck = 1;
+  mosi = 2;
+  miso = 11;
+;
+
+programmer
+  id    = "atisp";
+  desc  = "AT-ISP V1.1 programming cable for AVR-SDK1 from <http://micro-research.co.th/> micro-research.co.th";
+  type  = par;
+  reset = ~6;
+  sck   = ~8;
+  mosi  = ~7;
+  miso  = ~10;
+;
+
+programmer
+  id    = "ere-isp-avr";
+  desc  = "ERE ISP-AVR <http://www.ere.co.th/download/sch050713.pdf>";
+  type  = par;
+  reset = ~4;
+  sck   = 3;
+  mosi  = 2;
+  miso  = 10;
+;
+
+programmer
+  id    = "blaster";
+  desc  = "Altera ByteBlaster";
+  type  = par;
+  sck   = 2;
+  miso  = 11;
+  reset = 3;
+  mosi  = 8;
+  buff  = 14;
+;
+
+# It is almost same as pony-stk200, except vcc on pin 5 to auto
+# disconnect port (download on http://electropol.free.fr)
+programmer
+  id    = "frank-stk200";
+  desc  = "Frank STK200";
+  type  = par;
+  vcc   = 5;
+  sck   = 6;
+  mosi  = 7;
+  reset = 9;
+  miso  = 10;
+  pgmled = 8;
+;
+
+# The AT98ISP Cable is a simple parallel dongle for AT89 family.
+# http://www.atmel.com/dyn/products/tools_card.asp?tool_id=2877
+programmer
+id = "89isp";
+desc = "Atmel at89isp cable";
+type = par;
+reset = 17;
+sck = 1;
+mosi = 2;
+miso = 10;
+;
+
+@HAVE_PARPORT_END@
+
+#
+# some ultra cheap programmers use bitbanging on the 
+# serialport.
+#
+# PC - DB9 - Pins for RS232:
+#
+# GND   5   -- |O
+#              |   O| <-   9   RI
+# DTR   4   <- |O   |
+#              |   O| <-   8   CTS
+# TXD   3   <- |O   |
+#              |   O| ->   7   RTS
+# RXD   2   -> |O   |
+#              |   O| <-   6   DSR
+# DCD   1   -> |O
+#
+# Using RXD is currently not supported.
+# Using RI is not supported under Win32 but is supported under Posix.
+
+# serial ponyprog design (dasa2 in uisp)
+# reset=!txd sck=rts mosi=dtr miso=cts
+
+programmer
+  id    = "ponyser";
+  desc  = "design ponyprog serial, reset=!txd sck=rts mosi=dtr miso=cts";
+  type  = serbb;
+  reset = ~3;
+  sck   = 7;
+  mosi  = 4;
+  miso  = 8;
+;
+
+# Same as above, different name
+# reset=!txd sck=rts mosi=dtr miso=cts
+
+programmer
+  id    = "siprog";
+  desc  = "Lancos SI-Prog <http://www.lancos.com/siprogsch.html>";
+  type  = serbb;
+  reset = ~3;
+  sck   = 7;
+  mosi  = 4;
+  miso  = 8;
+;
+
+# unknown (dasa in uisp)
+# reset=rts sck=dtr mosi=txd miso=cts
+
+programmer
+  id    = "dasa";
+  desc  = "serial port banging, reset=rts sck=dtr mosi=txd miso=cts";
+  type  = serbb;
+  reset = 7;
+  sck   = 4;
+  mosi  = 3;
+  miso  = 8;
+;
+
+# unknown (dasa3 in uisp)
+# reset=!dtr sck=rts mosi=txd miso=cts
+
+programmer
+  id    = "dasa3";
+  desc  = "serial port banging, reset=!dtr sck=rts mosi=txd miso=cts";
+  type  = serbb;
+  reset = ~4;
+  sck   = 7;
+  mosi  = 3;
+  miso  = 8;
+;
+
+# C2N232i (jumper configuration "auto")
+# reset=dtr sck=!rts mosi=!txd miso=!cts
+
+programmer
+  id    = "c2n232i";
+  desc  = "serial port banging, reset=dtr sck=!rts mosi=!txd miso=!cts";
+  type  = serbb;
+  reset = 4;
+  sck   = ~7;
+  mosi  = ~3;
+  miso  = ~8;
+;
+
+#
+# PART DEFINITIONS
+#
+
+#------------------------------------------------------------
+# ATtiny11
+#------------------------------------------------------------
+
+# This is an HVSP-only device.
+
+part
+    id                  = "t11";
+    desc                = "ATtiny11";
+    stk500_devcode      = 0x11;
+    signature           = 0x1e 0x90 0x04;
+    chip_erase_delay    = 20000;
+
+    timeout		= 200;
+    hvsp_controlstack     =
+        0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x00,
+        0x68, 0x78, 0x68, 0x68, 0x00, 0x00, 0x68, 0x78,
+        0x78, 0x00, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10,
+        0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    hvspcmdexedelay     = 0;
+    synchcycles         = 6;
+    latchcycles         = 1;
+    togglevtg           = 1;
+    poweroffdelay       = 25;
+    resetdelayms        = 0;
+    resetdelayus        = 50;
+    hvleavestabdelay    = 100;
+    resetdelay          = 25;
+    chiperasepolltimeout = 40;
+    chiperasetime       = 0;
+    programfusepolltimeout = 25;
+    programlockpolltimeout = 25;
+
+    memory "eeprom"
+        size            = 64;
+	blocksize	= 64;
+	readsize	= 256;
+	delay		= 5;
+    ;
+
+    memory "flash"
+        size            = 1024;
+	blocksize	= 128;
+	readsize	= 256;
+	delay		= 3;
+    ;
+
+    memory "signature"
+        size            = 3;
+    ;
+
+    memory "lock"
+        size            = 1;
+    ;
+
+    memory "calibration"
+        size            = 1;
+    ;
+
+    memory "fuse"
+        size            = 1;
+    ;
+;
+
+#------------------------------------------------------------
+# ATtiny12
+#------------------------------------------------------------
+
+part
+    id                  = "t12";
+    desc                = "ATtiny12";
+    stk500_devcode      = 0x12;
+    avr910_devcode      = 0x55;
+    signature           = 0x1e 0x90 0x05;
+    chip_erase_delay    = 20000;
+    pgm_enable          = "1 0 1 0  1 1 0 0   0 1 0 1  0 0 1 1",
+                          "x x x x  x x x x   x x x x  x x x x";
+
+    chip_erase          = "1 0 1 0  1 1 0 0   1 0 0 x  x x x x",
+                          "x x x x  x x x x   x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 0;
+
+    hvsp_controlstack   =
+        0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x00,
+        0x68, 0x78, 0x68, 0x68, 0x00, 0x00, 0x68, 0x78,
+        0x78, 0x00, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10,
+        0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00;
+    hventerstabdelay    = 100;
+    hvspcmdexedelay     = 0;
+    synchcycles         = 6;
+    latchcycles         = 1;
+    togglevtg           = 1;
+    poweroffdelay       = 25;
+    resetdelayms        = 0;
+    resetdelayus        = 50;
+    hvleavestabdelay    = 100;
+    resetdelay          = 25;
+    chiperasepolltimeout = 40;
+    chiperasetime       = 0;
+    programfusepolltimeout = 25;
+    programlockpolltimeout = 25;
+
+    memory "eeprom"
+        size            = 64;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read            = "1  0  1  0   0  0  0  0    x x x x  x x x x",
+                          "x  x a5 a4  a3 a2 a1 a0    o o o o  o o o o";
+
+        write           = "1  1  0  0   0  0  0  0    x x x x  x x x x",
+                          "x  x a5 a4  a3 a2 a1 a0    i i i i  i i i i";
+
+	mode		= 0x04;
+	delay		= 8;
+	blocksize	= 64;
+	readsize	= 256;
+    ;
+
+    memory "flash"
+        size            = 1024;
+        min_write_delay = 4500;
+        max_write_delay = 20000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0  0  1  0   0  0  0  0",
+                          "  x  x  x  x   x  x  x a8",
+                          " a7 a6 a5 a4  a3 a2 a1 a0",
+                          "  o  o  o  o   o  o  o  o";
+
+        read_hi         = "  0  0  1  0   1  0  0  0",
+                          "  x  x  x  x   x  x  x a8",
+                          " a7 a6 a5 a4  a3 a2 a1 a0",
+                          "  o  o  o  o   o  o  o  o";
+
+        write_lo        = "  0  1  0  0   0  0  0  0",
+                          "  x  x  x  x   x  x  x a8",
+                          " a7 a6 a5 a4  a3 a2 a1 a0",
+                          "  i  i  i  i   i  i  i  i";
+
+        write_hi        = "  0  1  0  0   1  0  0  0",
+                          "  x  x  x  x   x  x  x a8",
+                          " a7 a6 a5 a4  a3 a2 a1 a0",
+                          "  i  i  i  i   i  i  i  i";
+
+	mode		= 0x04;
+	delay		= 5;
+	blocksize	= 128;
+	readsize	= 256;
+    ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0    x x x x  x x x x",
+                          "0  0  0  0   0  0 a1 a0    o o o o  o o o o";
+    ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0  1  0  1   1  0  0  0    x x x x  x x x x",
+                          "x  x  x  x   x  x  x  x    x x x x  x o o x";
+
+        write           = "1  0  1  0   1  1  0  0    1 1 1 1  1 i i 1",
+                          "x  x  x  x   x  x  x  x    x x x x  x x x x";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+    ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0  0  1  1   1  0  0  0    x x x x  x x x x",
+                          "0  0  0  0   0  0  0  0    o o o o  o o o o";
+    ;
+
+    memory "fuse"
+        size            = 1;
+        read            = "0  1  0  1   0  0  0  0    x x x x  x x x x",
+                          "x  x  x  x   x  x  x  x    o o o o  o o o o";
+
+        write           = "1  0  1  0   1  1  0  0    1 0 1 x  x x x x",
+                          "x  x  x  x   x  x  x  x    i i i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+    ;
+;
+
+#------------------------------------------------------------
+# ATtiny13
+#------------------------------------------------------------
+
+part
+    id                  = "t13";
+    desc                = "ATtiny13";
+     has_debugwire = yes;
+     flash_instr   = 0xB4, 0x0E, 0x1E;
+     eeprom_instr  = 0xBB, 0xFE, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D,
+	             0xBC, 0x0E, 0xB4, 0x0E, 0xBA, 0x0D, 0xBB, 0xBC,
+	             0x99, 0xE1, 0xBB, 0xAC;
+    stk500_devcode      = 0x14;
+    signature           = 0x1e 0x90 0x07;
+    chip_erase_delay    = 4000;
+    pgm_enable          = "1 0 1 0  1 1 0 0   0 1 0 1  0 0 1 1",
+                          "x x x x  x x x x   x x x x  x x x x";
+
+    chip_erase          = "1 0 1 0  1 1 0 0   1 0 0 x  x x x x",
+                          "x x x x  x x x x   x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    hvsp_controlstack     =
+	0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66,
+        0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78,
+        0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10,
+        0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    hvspcmdexedelay     = 0;
+    synchcycles         = 6;
+    latchcycles         = 1;
+    togglevtg           = 1;
+    poweroffdelay       = 25;
+    resetdelayms        = 0;
+    resetdelayus        = 90;
+    hvleavestabdelay    = 100;
+    resetdelay          = 25;
+    chiperasepolltimeout = 40;
+    chiperasetime       = 0;
+    programfusepolltimeout = 25;
+    programlockpolltimeout = 25;
+
+    memory "eeprom"
+        size            = 64;
+        page_size       = 4;
+        min_write_delay = 4000;
+        max_write_delay = 4000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read            = "1  0  1  0   0  0  0  0    0 0 0 x  x x x x",
+                          "x  x a5 a4  a3 a2 a1 a0    o o o o  o o o o";
+
+        write           = "1  1  0  0   0  0  0  0    0 0 0 x  x x x x",
+                          "x  x a5 a4  a3 a2 a1 a0    i i i i  i i i i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x   x   x",
+			  "  x   x  a5  a4     a3  a2   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 5;
+	blocksize	= 4;
+	readsize	= 256;
+    ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 1024;
+        page_size       = 32;
+        num_pages       = 32;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0  0  1  0   0  0  0  0",
+                          "  0  0  0  0   0  0  0 a8",
+                          " a7 a6 a5 a4  a3 a2 a1 a0",
+                          "  o  o  o  o   o  o  o  o";
+
+        read_hi         = "  0  0  1  0   1  0  0  0",
+                          "  0  0  0  0   0  0  0 a8",
+                          " a7 a6 a5 a4  a3 a2 a1 a0",
+                          "  o  o  o  o   o  o  o  o";
+
+        loadpage_lo     = "  0  1  0  0   0  0  0  0",
+                          "  0  0  0  x   x  x  x  x",
+                          "  x  x  x  x  a3 a2 a1 a0",
+                          "  i  i  i  i   i  i  i  i";
+
+        loadpage_hi     = "  0  1  0  0   1  0  0  0",
+                          "  0  0  0  x   x  x  x  x",
+                          "  x  x  x  x  a3 a2 a1 a0",
+                          "  i  i  i  i   i  i  i  i";
+
+        writepage       = "  0  1  0  0   1  1  0  0",
+                          "  0  0  0  0   0  0  0 a8",
+                          " a7 a6 a5 a4   x  x  x  x",
+                          "  x  x  x  x   x  x  x  x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 32;
+	readsize	= 256;
+    ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0    0 0 0 x  x x x x",
+                          "x  x  x  x   x  x a1 a0    o o o o  o o o o";
+    ;
+
+    memory "lock"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+
+	read            = "0  1  0  1   1  0  0  0    0 0 0 0  0 0 0 0",
+                          "x  x  x  x   x  x  x  x    x x o o  o o o o";
+
+        write           = "1  0  1  0   1  1  0  0    1 1 1 x  x x x x",
+                          "x  x  x  x   x  x  x  x    1 1 i i  i i i i";
+    ;
+
+    memory "calibration"
+        size            = 2;
+        read            = "0  0  1  1   1  0  0  0    0 0 0 x  x x x x",
+                          "0  0  0  0   0  0  0 a0    o o o o  o o o o";
+    ;
+
+    memory "lfuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+      ;
+
+;
+
+
+#------------------------------------------------------------
+# ATtiny15
+#------------------------------------------------------------
+
+part
+    id                  = "t15";
+    desc                = "ATtiny15";
+    stk500_devcode      = 0x13;
+    avr910_devcode      = 0x56;
+    signature           = 0x1e 0x90 0x06;
+    chip_erase_delay    = 8200;
+    pgm_enable          = "1 0 1 0  1 1 0 0   0 1 0 1  0 0 1 1",
+                          "x x x x  x x x x   x x x x  x x x x";
+
+    chip_erase          = "1 0 1 0  1 1 0 0   1 0 0 x  x x x x",
+                          "x x x x  x x x x   x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 0;
+
+    hvsp_controlstack   =
+        0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x00,
+        0x68, 0x78, 0x68, 0x68, 0x00, 0x00, 0x68, 0x78,
+        0x78, 0x00, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10,
+        0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00;
+    hventerstabdelay    = 100;
+    hvspcmdexedelay     = 5;
+    synchcycles         = 6;
+    latchcycles         = 16;
+    togglevtg           = 1;
+    poweroffdelay       = 25;
+    resetdelayms        = 0;
+    resetdelayus        = 50;
+    hvleavestabdelay    = 100;
+    resetdelay          = 25;
+    chiperasepolltimeout = 40;
+    chiperasetime       = 0;
+    programfusepolltimeout = 25;
+    programlockpolltimeout = 25;
+
+    memory "eeprom"
+        size            = 64;
+        min_write_delay = 8200;
+        max_write_delay = 8200;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read            = "1  0  1  0   0  0  0  0    x x x x  x x x x",
+                          "x  x a5 a4  a3 a2 a1 a0    o o o o  o o o o";
+
+        write           = "1  1  0  0   0  0  0  0    x x x x  x x x x",
+                          "x  x a5 a4  a3 a2 a1 a0    i i i i  i i i i";
+
+	mode		= 0x04;
+	delay		= 10;
+	blocksize	= 64;
+	readsize	= 256;
+    ;
+
+    memory "flash"
+        size            = 1024;
+        min_write_delay = 4100;
+        max_write_delay = 4100;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0  0  1  0   0  0  0  0",
+                          "  x  x  x  x   x  x  x a8",
+                          " a7 a6 a5 a4  a3 a2 a1 a0",
+                          "  o  o  o  o   o  o  o  o";
+
+        read_hi         = "  0  0  1  0   1  0  0  0",
+                          "  x  x  x  x   x  x  x a8",
+                          " a7 a6 a5 a4  a3 a2 a1 a0",
+                          "  o  o  o  o   o  o  o  o";
+
+        write_lo        = "  0  1  0  0   0  0  0  0",
+                          "  x  x  x  x   x  x  x a8",
+                          " a7 a6 a5 a4  a3 a2 a1 a0",
+                          "  i  i  i  i   i  i  i  i";
+
+        write_hi        = "  0  1  0  0   1  0  0  0",
+                          "  x  x  x  x   x  x  x a8",
+                          " a7 a6 a5 a4  a3 a2 a1 a0",
+                          "  i  i  i  i   i  i  i  i";
+
+	mode		= 0x04;
+	delay		= 5;
+	blocksize	= 128;
+	readsize	= 256;
+    ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0    x x x x  x x x x",
+                          "0  0  0  0   0  0 a1 a0    o o o o  o o o o";
+    ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0  1  0  1   1  0  0  0    x x x x  x x x x",
+                          "x  x  x  x   x  x  x  x    x x x x  x o o x";
+
+        write           = "1  0  1  0   1  1  0  0    1 1 1 1  1 i i 1",
+                          "x  x  x  x   x  x  x  x    x x x x  x x x x";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+    ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0  0  1  1   1  0  0  0    x x x x  x x x x",
+                          "0  0  0  0   0  0  0  0    o o o o  o o o o";
+    ;
+
+    memory "fuse"
+        size            = 1;
+        read            = "0  1  0  1   0  0  0  0    x x x x  x x x x",
+                          "x  x  x  x   x  x  x  x    o o o o  x x o o";
+
+        write           = "1  0  1  0   1  1  0  0    1 0 1 x  x x x x",
+                          "x  x  x  x   x  x  x  x    i i i i  1 1 i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+    ;
+;
+
+#------------------------------------------------------------
+# AT90s1200
+#------------------------------------------------------------
+
+part
+    id               = "1200";
+    desc             = "AT90S1200";
+    stk500_devcode   = 0x33;
+    avr910_devcode   = 0x13;
+    signature        = 0x1e 0x90 0x01;
+    pagel            = 0xd7;
+    bs2              = 0xa0;
+    chip_erase_delay = 20000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 1;
+    bytedelay		= 0;
+    pollindex		= 0;
+    pollvalue		= 0xFF;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 0;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 0;
+    togglevtg           = 0;
+    poweroffdelay       = 0;
+    resetdelayms        = 0;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 15;
+    chiperasepolltimeout = 0;
+    programfusepulsewidth = 2;
+    programfusepolltimeout = 0;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 1;
+
+    memory "eeprom"
+        size            = 64;
+        min_write_delay = 4000;
+        max_write_delay = 9000;
+        readback_p1     = 0x00;
+        readback_p2     = 0xff;
+        read            = "1 0  1  0   0  0  0  0   x x x x  x x x x", 
+                          "x x a5 a4  a3 a2 a1 a0   o o o o  o o o o";
+
+        write           = "1 1  0  0   0  0  0  0   x x x x  x x x x",
+                          "x x a5 a4  a3 a2 a1 a0   i i i i  i i i i";
+
+	mode		= 0x04;
+	delay		= 20;
+	blocksize	= 32;
+	readsize	= 256;
+      ;
+    memory "flash"
+        size            = 1024;
+        min_write_delay = 4000;
+        max_write_delay = 9000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0    0   0   0   0",
+                          "  x   x   x   x    x   x   x  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        read_hi         = "  0   0   1   0    1   0   0   0",
+                          "  x   x   x   x    x   x   x  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        write_lo        = "  0   1   0   0    0   0   0   0",
+                          "  x   x   x   x    x   x   x  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  i   i   i   i    i   i   i   i";
+
+        write_hi        = "  0   1   0   0    1   0   0   0",
+                          "  x   x   x   x    x   x   x  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  i   i   i   i    i   i   i   i";
+
+	mode		= 0x02;
+	delay		= 15;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+    memory "fuse"
+        size            = 1;
+      ;
+    memory "lock"
+        size            = 1;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        write           = "1 0 1 0  1 1 0 0   1 1 1 1  1 i i 1",
+                          "x x x x  x x x x   x x x x  x x x x";
+      ;
+  ;
+
+#------------------------------------------------------------
+# AT90s4414
+#------------------------------------------------------------
+
+part
+    id               = "4414";
+    desc             = "AT90S4414";
+    stk500_devcode   = 0x50;
+    avr910_devcode   = 0x28;
+    signature        = 0x1e 0x92 0x01;
+    chip_erase_delay = 20000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 0;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 0;
+    togglevtg           = 0;
+    poweroffdelay       = 0;
+    resetdelayms        = 0;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 15;
+    chiperasepolltimeout = 0;
+    programfusepulsewidth = 2;
+    programfusepolltimeout = 0;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 1;
+
+    memory "eeprom"
+        size            = 256;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        readback_p1     = 0x80;
+        readback_p2     = 0x7f;
+        read            = " 1  0  1  0   0  0  0  0  x x x x  x x x a8", 
+                          "a7 a6 a5 a4 a3 a2 a1 a0   o o o o  o o o o";
+
+        write           = " 1  1  0  0   0  0  0  0   x x x x  x x x a8",
+                          "a7 a6 a5 a4  a3 a2 a1 a0   i i i i  i i i i";
+
+	mode		= 0x04;
+	delay		= 12;
+	blocksize	= 64;
+	readsize	= 256;
+      ;
+    memory "flash"
+        size            = 4096;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        readback_p1     = 0x7f;
+        readback_p2     = 0x7f;
+        read_lo         = "  0   0   1   0    0   0   0   0",
+                          "  x   x   x   x  a11 a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        read_hi         = "  0   0   1   0    1   0   0   0",
+                          "  x   x   x   x  a11 a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        write_lo        = "  0   1   0   0    0   0   0   0",
+                          "  x   x   x   x  a11 a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  i   i   i   i    i   i   i   i";
+
+        write_hi        = "  0   1   0   0    1   0   0   0",
+                          "  x   x   x   x  a11 a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  i   i   i   i    i   i   i   i";
+
+	mode		= 0x04;
+	delay		= 12;
+	blocksize	= 64;
+	readsize	= 256;
+      ;
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+    memory "fuse"
+	size		= 1;
+      ;
+    memory "lock"
+	size		= 1;
+	write		= "1  0  1  0   1  1  0  0   1  1  1  1   1  i  i  1",
+			  "x  x  x  x   x  x  x  x   x  x  x  x   x  x  x  x";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+  ;
+
+#------------------------------------------------------------
+# AT90s2313
+#------------------------------------------------------------
+
+part
+    id               = "2313";
+    desc             = "AT90S2313";
+    stk500_devcode   = 0x40;
+    avr910_devcode   = 0x20;
+    signature        = 0x1e 0x91 0x01;
+    chip_erase_delay = 20000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 0;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 0;
+    togglevtg           = 0;
+    poweroffdelay       = 0;
+    resetdelayms        = 0;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 15;
+    chiperasepolltimeout = 0;
+    programfusepulsewidth = 2;
+    programfusepolltimeout = 0;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 1;
+
+    memory "eeprom"
+        size            = 128;
+        min_write_delay = 4000;
+        max_write_delay = 9000;
+        readback_p1     = 0x80;
+        readback_p2     = 0x7f;
+        read            = "1  0  1  0   0  0  0  0   x x x x  x x x x", 
+                          "x a6 a5 a4  a3 a2 a1 a0   o o o o  o o o o";
+
+        write           = "1  1  0  0   0  0  0  0   x x x x  x x x x",
+                          "x a6 a5 a4  a3 a2 a1 a0   i i i i  i i i i";
+
+	mode		= 0x04;
+	delay		= 12;
+	blocksize	= 64;
+	readsize	= 256;
+      ;
+    memory "flash"
+        size            = 2048;
+        min_write_delay = 4000;
+        max_write_delay = 9000;
+        readback_p1     = 0x7f;
+        readback_p2     = 0x7f;
+        read_lo         = "  0   0   1   0    0   0   0   0",
+                          "  x   x   x   x    x   x  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        read_hi         = "  0   0   1   0    1   0   0   0",
+                          "  x   x   x   x    x   x  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        write_lo        = "  0   1   0   0    0   0   0   0",
+                          "  x   x   x   x    x   x  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  i   i   i   i    i   i   i   i";
+
+        write_hi        = "  0   1   0   0    1   0   0   0",
+                          "  x   x   x   x    x   x  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  i   i   i   i    i   i   i   i";
+
+	mode		= 0x04;
+	delay		= 12;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+    memory "fuse"
+        size            = 1;
+      ;
+    memory "lock"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 1 1 x  x i i x",
+                          "x x x x  x x x x  x x x x  x x x x";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+  ;
+
+#------------------------------------------------------------
+# AT90s2333
+#------------------------------------------------------------
+
+part
+    id               = "2333";
+##### WARNING: No XML file for device 'AT90S2333'! #####
+    desc             = "AT90S2333";
+    stk500_devcode   = 0x42;
+    avr910_devcode   = 0x34;
+    signature        = 0x1e 0x91 0x05;
+    chip_erase_delay = 20000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 0;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 0;
+    togglevtg           = 0;
+    poweroffdelay       = 0;
+    resetdelayms        = 0;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 15;
+    chiperasepolltimeout = 0;
+    programfusepulsewidth = 2;
+    programfusepolltimeout = 0;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 1;
+
+    memory "eeprom"
+        size            = 128;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        readback_p1     = 0x00;
+        readback_p2     = 0xff;
+        read            = "1  0  1  0   0  0  0  0   x x x x  x x x x", 
+                          "x a6 a5 a4  a3 a2 a1 a0   o o o o  o o o o";
+
+        write           = "1  1  0  0   0  0  0  0   x x x x  x x x x",
+                          "x a6 a5 a4  a3 a2 a1 a0   i i i i  i i i i";
+
+	mode		= 0x04;
+	delay		= 12;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        size            = 2048;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0    0   0   0   0",
+                          "  x   x   x   x    x   x  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        read_hi         = "  0   0   1   0    1   0   0   0",
+                          "  x   x   x   x    x   x  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        write_lo        = "  0   1   0   0    0   0   0   0",
+                          "  x   x   x   x    x   x  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  i   i   i   i    i   i   i   i";
+
+        write_hi        = "  0   1   0   0    1   0   0   0",
+                          "  x   x   x   x    x   x  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  i   i   i   i    i   i   i   i";
+
+	mode		= 0x04;
+	delay		= 12;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+    memory "fuse"
+        size            = 1;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        pwroff_after_write = yes;
+        read            = "0 1 0 1  0 0 0 0   x x x x  x x x x",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 i  i i i i",
+                          "x x x x  x x x x   x x x x  x x x x";
+      ;
+    memory "lock"
+        size            = 1;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        read            = "0 1 0 1  1 0 0 0   x x x x  x x x x",
+                          "x x x x  x x x x   x x x x  x o o x";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 1  1 i i 1",
+                          "x x x x  x x x x   x x x x  x x x x";
+      ;
+  ;
+
+
+#------------------------------------------------------------
+# AT90s2343 (also AT90s2323 and ATtiny22)
+#------------------------------------------------------------
+
+part
+    id               = "2343";
+    desc             = "AT90S2343";
+    stk500_devcode   = 0x43;
+    avr910_devcode   = 0x4c;
+    signature        = 0x1e 0x91 0x03;
+    chip_erase_delay = 18000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 0;
+
+    hvsp_controlstack   =
+        0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x00,
+        0x68, 0x78, 0x68, 0x68, 0x00, 0x00, 0x68, 0x78,
+        0x78, 0x00, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10,
+        0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00;
+    hventerstabdelay    = 100;
+    hvspcmdexedelay     = 0;
+    synchcycles         = 6;
+    latchcycles         = 1;
+    togglevtg           = 0;
+    poweroffdelay       = 25;
+    resetdelayms        = 0;
+    resetdelayus        = 50;
+    hvleavestabdelay    = 100;
+    resetdelay          = 25;
+    chiperasepolltimeout = 40;
+    chiperasetime       = 0;
+    programfusepolltimeout = 25;
+    programlockpolltimeout = 25;
+
+    memory "eeprom"
+        size            = 128;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        readback_p1     = 0x00;
+        readback_p2     = 0xff;
+        read            = "1  0  1  0   0  0  0  0   0 0 0 0  0 0 0 0", 
+                          "x a6 a5 a4  a3 a2 a1 a0   o o o o  o o o o";
+
+        write           = "1  1  0  0   0  0  0  0   0 0 0 0  0 0 0 0",
+                          "x a6 a5 a4  a3 a2 a1 a0   i i i i  i i i i";
+
+	mode		= 0x04;
+	delay		= 12;
+	blocksize	= 64;
+	readsize	= 256;
+      ;
+    memory "flash"
+        size            = 2048;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0    0   0   0   0",
+                          "  x   x   x   x    x   x  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        read_hi         = "  0   0   1   0    1   0   0   0",
+                          "  x   x   x   x    x   x  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        write_lo        = "  0   1   0   0    0   0   0   0",
+                          "  x   x   x   x    x   x  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  i   i   i   i    i   i   i   i";
+
+        write_hi        = "  0   1   0   0    1   0   0   0",
+                          "  x   x   x   x    x   x  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  i   i   i   i    i   i   i   i";
+
+	mode		= 0x04;
+	delay		= 12;
+	blocksize	= 128;
+	readsize	= 128;
+      ;
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+    memory "fuse"
+        size            = 1;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        read            = "0 1 0 1  1 0 0 0   x x x x  x x x x",
+                          "x x x x  x x x x   o o o x  x x x o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 1  1 1 1 i",
+                          "x x x x  x x x x   x x x x  x x x x";
+      ;
+    memory "lock"
+        size            = 1;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        read            = "0 1 0 1  1 0 0 0   x x x x  x x x x",
+                          "x x x x  x x x x   o o o x  x x x o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 1  1 i i 1",
+                          "x x x x  x x x x   x x x x  x x x x";
+      ;
+  ;
+
+
+#------------------------------------------------------------
+# AT90s4433
+#------------------------------------------------------------
+
+part
+    id               = "4433";
+    desc             = "AT90S4433";
+    stk500_devcode   = 0x51;
+    avr910_devcode   = 0x30;
+    signature        = 0x1e 0x92 0x03;
+    chip_erase_delay = 20000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 0;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 0;
+    togglevtg           = 0;
+    poweroffdelay       = 0;
+    resetdelayms        = 0;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 15;
+    chiperasepolltimeout = 0;
+    programfusepulsewidth = 2;
+    programfusepolltimeout = 0;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 1;
+
+    memory "eeprom"
+        size            = 256;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        readback_p1     = 0x00;
+        readback_p2     = 0xff;
+        read            = " 1  0  1  0   0  0  0  0   x x x x  x x x x", 
+                          "a7 a6 a5 a4  a3 a2 a1 a0   o o o o  o o o o";
+
+        write           = " 1  1  0  0   0  0  0  0   x x x x  x x x x",
+                          "a7 a6 a5 a4  a3 a2 a1 a0   i i i i  i i i i";
+
+	mode		= 0x04;
+	delay		= 12;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+    memory "flash"
+        size            = 4096;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0    0   0   0   0",
+                          "  x   x   x   x    x a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        read_hi         = "  0   0   1   0    1   0   0   0",
+                          "  x   x   x   x    x a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        write_lo        = "  0   1   0   0    0   0   0   0",
+                          "  x   x   x   x    x a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  i   i   i   i    i   i   i   i";
+
+        write_hi        = "  0   1   0   0    1   0   0   0",
+                          "  x   x   x   x    x a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  i   i   i   i    i   i   i   i";
+
+	mode		= 0x04;
+	delay		= 12;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+    memory "fuse"
+        size            = 1;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        pwroff_after_write = yes;
+        read            = "0 1 0 1  0 0 0 0   x x x x  x x x x",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 i  i i i i",
+                          "x x x x  x x x x   x x x x  x x x x";
+      ;
+    memory "lock"
+        size            = 1;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        read            = "0 1 0 1  1 0 0 0   x x x x  x x x x",
+                          "x x x x  x x x x   x x x x  x o o x";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 1  1 i i 1",
+                          "x x x x  x x x x   x x x x  x x x x";
+      ;
+  ;
+
+#------------------------------------------------------------
+# AT90s4434
+#------------------------------------------------------------
+
+part
+    id               = "4434";
+##### WARNING: No XML file for device 'AT90S4434'! #####
+    desc             = "AT90S4434";
+    stk500_devcode   = 0x52;
+    avr910_devcode   = 0x6c;
+    signature        = 0x1e 0x92 0x02;
+    chip_erase_delay = 20000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    memory "eeprom"
+        size            = 256;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        readback_p1     = 0x00;
+        readback_p2     = 0xff;
+        read            = " 1  0  1  0   0  0  0  0   x x x x  x x x x", 
+                          "a7 a6 a5 a4  a3 a2 a1 a0   o o o o  o o o o";
+
+        write           = " 1  1  0  0   0  0  0  0   x x x x  x x x x",
+                          "a7 a6 a5 a4  a3 a2 a1 a0   i i i i  i i i i";
+      ;
+    memory "flash"
+        size            = 4096;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0    0   0   0   0",
+                          "  x   x   x   x    x a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        read_hi         = "  0   0   1   0    1   0   0   0",
+                          "  x   x   x   x    x a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        write_lo        = "  0   1   0   0    0   0   0   0",
+                          "  x   x   x   x    x a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  i   i   i   i    i   i   i   i";
+
+        write_hi        = "  0   1   0   0    1   0   0   0",
+                          "  x   x   x   x    x a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  i   i   i   i    i   i   i   i";
+      ;
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+    memory "fuse"
+        size            = 1;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        read            = "0 1 0 1  0 0 0 0   x x x x  x x x x",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 i  i i i i",
+                          "x x x x  x x x x   x x x x  x x x x";
+      ;
+    memory "lock"
+        size            = 1;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        read            = "0 1 0 1  1 0 0 0   x x x x  x x x x",
+                          "x x x x  x x x x   x x x x  x o o x";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 1  1 i i 1",
+                          "x x x x  x x x x   x x x x  x x x x";
+      ;
+  ;
+
+#------------------------------------------------------------
+# AT90s8515
+#------------------------------------------------------------
+
+part
+    id               = "8515";
+    desc             = "AT90S8515";
+    stk500_devcode   = 0x60;
+    avr910_devcode   = 0x38;
+    signature        = 0x1e 0x93 0x01;
+    chip_erase_delay = 20000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 0;
+
+    pp_controlstack     =
+	0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+	0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+	0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+	0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 0;
+    togglevtg           = 0;
+    poweroffdelay       = 0;
+    resetdelayms        = 0;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    resetdelay          = 15;
+    chiperasepulsewidth = 15;
+    chiperasepolltimeout = 0;
+    programfusepulsewidth = 2;
+    programfusepolltimeout = 0;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 1;
+
+    memory "eeprom"
+        size            = 512;
+        min_write_delay = 4000;
+        max_write_delay = 9000;
+        readback_p1     = 0x80;
+        readback_p2     = 0x7f;
+        read            = " 1  0  1  0   0  0  0  0  x x x x  x x x a8", 
+                          "a7 a6 a5 a4 a3 a2 a1 a0   o o o o  o o o o";
+
+        write           = " 1  1  0  0   0  0  0  0   x x x x  x x x a8",
+                          "a7 a6 a5 a4  a3 a2 a1 a0   i i i i  i i i i";
+
+	mode		= 0x04;
+	delay		= 12;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+    memory "flash"
+        size            = 8192;
+        min_write_delay = 4000;
+        max_write_delay = 9000;
+        readback_p1     = 0x7f;
+        readback_p2     = 0x7f;
+        read_lo         = "  0   0   1   0    0   0   0   0",
+                          "  x   x   x   x  a11 a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        read_hi         = "  0   0   1   0    1   0   0   0",
+                          "  x   x   x   x  a11 a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        write_lo        = "  0   1   0   0    0   0   0   0",
+                          "  x   x   x   x  a11 a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  i   i   i   i    i   i   i   i";
+
+        write_hi        = "  0   1   0   0    1   0   0   0",
+                          "  x   x   x   x  a11 a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  i   i   i   i    i   i   i   i";
+
+	mode		= 0x04;
+	delay		= 12;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+    memory "fuse"
+	size		= 1;
+      ;
+    memory "lock"
+	size		= 1;
+	write		= "1  0  1  0   1  1  0  0   1  1  1  1   1  i  i  1",
+			  "x  x  x  x   x  x  x  x   x  x  x  x   x  x  x  x";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+  ;
+
+#------------------------------------------------------------
+# AT90s8535
+#------------------------------------------------------------
+
+part
+    id               = "8535";
+    desc             = "AT90S8535";
+    stk500_devcode   = 0x61;
+    avr910_devcode   = 0x68;
+    signature        = 0x1e 0x93 0x03;
+    chip_erase_delay = 20000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 0;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 0;
+    togglevtg           = 0;
+    poweroffdelay       = 0;
+    resetdelayms        = 0;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 15;
+    chiperasepolltimeout = 0;
+    programfusepulsewidth = 2;
+    programfusepolltimeout = 0;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 1;
+
+    memory "eeprom"
+        size            = 512;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        readback_p1     = 0x00;
+        readback_p2     = 0xff;
+        read            = " 1  0  1  0   0  0  0  0   x x x x  x x x a8", 
+                          "a7 a6 a5 a4  a3 a2 a1 a0   o o o o  o o o o";
+
+        write           = " 1  1  0  0   0  0  0  0   x x x x  x x x a8",
+                          "a7 a6 a5 a4  a3 a2 a1 a0   i i i i  i i i i";
+
+	mode		= 0x04;
+	delay		= 12;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+    memory "flash"
+        size            = 8192;
+        min_write_delay = 9000;
+        max_write_delay = 20000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0    0   0   0   0",
+                          "  x   x   x   x  a11 a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        read_hi         = "  0   0   1   0    1   0   0   0",
+                          "  x   x   x   x  a11 a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        write_lo        = "  0   1   0   0    0   0   0   0",
+                          "  x   x   x   x  a11 a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  i   i   i   i    i   i   i   i";
+
+        write_hi        = "  0   1   0   0    1   0   0   0",
+                          "  x   x   x   x  a11 a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  i   i   i   i    i   i   i   i";
+
+	mode		= 0x04;
+	delay		= 12;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+    memory "fuse"
+	size		= 1;
+	read		= "0  1  0  1   1  0  0  0   x  x  x  x   x  x  x  x",
+			  "x  x  x  x   x  x  x  x   x  x  x  x   x  x  x  o";
+	write		= "1  0  1  0   1  1  0  0   1  0  1  1   1  1  1  i",
+			  "x  x  x  x   x  x  x  x   x  x  x  x   x  x  x  x";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+    memory "lock"
+	size		= 1;
+	read		= "0  1  0  1   1  0  0  0   x  x  x  x   x  x  x  x",
+			  "x  x  x  x   x  x  x  x   o  o  x  x   x  x  x  x";
+	write		= "1  0  1  0   1  1  0  0   1  1  1  1   1  i  i  1",
+			  "x  x  x  x   x  x  x  x   x  x  x  x   x  x  x  x";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+  ;
+
+#------------------------------------------------------------
+# ATmega103
+#------------------------------------------------------------
+
+part
+    id               = "m103";
+    desc             = "ATMEGA103";
+    stk500_devcode   = 0xB1;
+    avr910_devcode   = 0x41;
+    signature        = 0x1e 0x97 0x01;
+    chip_erase_delay = 112000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 0;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x8E, 0x9E, 0x2E, 0x3E, 0xAE, 0xBE,
+        0x4E, 0x5E, 0xCE, 0xDE, 0x6E, 0x7E, 0xEE, 0xDE,
+        0x66, 0x76, 0xE6, 0xF6, 0x6A, 0x7A, 0xEA, 0x7A,
+        0x7F, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 0;
+    togglevtg           = 0;
+    poweroffdelay       = 0;
+    resetdelayms        = 0;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 15;
+    chiperasepolltimeout = 0;
+    programfusepulsewidth = 2;
+    programfusepolltimeout = 0;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 10;
+
+    memory "eeprom"
+        size            = 4096;
+        min_write_delay = 4000;
+        max_write_delay = 9000;
+        readback_p1     = 0x80;
+        readback_p2     = 0x7f;
+	read            = "  1   0   1   0      0   0   0   0",
+                          "  x   x   x   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+	write           = "  1   1   0   0      0   0   0   0",
+                          "  x   x   x   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0", 
+                          "  i   i   i   i      i   i   i   i";
+
+	mode		= 0x04;
+	delay		= 12;
+	blocksize	= 64;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 131072;
+        page_size       = 256;
+        num_pages       = 512;
+        min_write_delay = 22000;
+        max_write_delay = 56000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7   x   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x11;
+	delay		= 70;
+	blocksize	= 256;
+	readsize	= 256;
+      ;
+
+    memory "fuse"
+        size            = 1;
+        read            = "0 1 0 1  0 0 0 0  x x x x  x x x x",
+                          "x x x x  x x x x  x x o x  o 1 o o";
+
+        write           = "1 0 1 0  1 1 0 0  1 0 1 1  i 1 i i",
+                          "x x x x  x x x x  x x x x  x x x x";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   x x x x  x x x x",
+                          "x x x x  x x x x   x x x x  x o o x";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 1  1 i i 1",
+                          "x x x x  x x x x   x x x x  x x x x";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+  ;
+
+
+#------------------------------------------------------------
+# ATmega64
+#------------------------------------------------------------
+
+part
+    id               = "m64";
+    desc             = "ATMEGA64";
+    has_jtag         = yes;
+    stk500_devcode   = 0xA0;
+    avr910_devcode   = 0x45;
+    signature        = 0x1e 0x96 0x02;
+    chip_erase_delay = 9000;
+    pagel            = 0xD7;
+    bs2              = 0xA0;
+    reset            = dedicated;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 0;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 6;
+    togglevtg           = 0;
+    poweroffdelay       = 0;
+    resetdelayms        = 0;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x22;
+    spmcr               = 0x68;
+    allowfullpagebitstream = yes;
+
+    memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 8;  /* for parallel programming */
+        size            = 2048;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read            = "  1   0   1   0      0   0   0   0",
+                          "  x   x   x   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        write           = "  1   1   0   0      0   0   0   0",
+                          "  x   x   x   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0", 
+                          "  i   i   i   i      i   i   i   i";
+
+	mode		= 0x04;
+	delay		= 20;
+	blocksize	= 64;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 65536;
+        page_size       = 256;
+        num_pages       = 256;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "  x a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "  x a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "  x a14 a13 a12    a11 a10  a9  a8",
+                          " a7   x   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x21;
+	delay		= 6;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "efuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x  x x x x  x x i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "calibration"
+        size            = 4;
+        read            = "0 0 1 1  1 0 0 0    x x x x  x x x x",
+                          "0 0 0 0  0 0 a1 a0  o o o o  o o o o";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+  ;
+
+
+
+
+#------------------------------------------------------------
+# ATmega128
+#------------------------------------------------------------
+
+part
+    id               = "m128";
+    desc             = "ATMEGA128";
+    has_jtag         = yes;
+    stk500_devcode   = 0xB2;
+    avr910_devcode   = 0x43;
+    signature        = 0x1e 0x97 0x02;
+    chip_erase_delay = 9000;
+    pagel            = 0xD7;
+    bs2              = 0xA0;
+    reset            = dedicated;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 0;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 6;
+    togglevtg           = 0;
+    poweroffdelay       = 0;
+    resetdelayms        = 0;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x22;
+    spmcr               = 0x68;
+    rampz               = 0x3b;
+    allowfullpagebitstream = yes;
+
+    memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 8;  /* for parallel programming */
+        size            = 4096;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read            = "  1   0   1   0      0   0   0   0",
+                          "  x   x   x   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        write           = "  1   1   0   0      0   0   0   0",
+                          "  x   x   x   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0", 
+                          "  i   i   i   i      i   i   i   i";
+
+	mode		= 0x04;
+	delay		= 12;
+	blocksize	= 64;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 131072;
+        page_size       = 256;
+        num_pages       = 512;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7   x   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x21;
+	delay		= 6;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "efuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x  x x x x  x x i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "calibration"
+        size            = 4;
+        read            = "0 0 1 1  1 0 0 0    x x x x  x x x x",
+                          "0 0 0 0  0 0 a1 a0  o o o o  o o o o";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+  ;
+
+#------------------------------------------------------------
+# AT90CAN128
+#------------------------------------------------------------
+
+part
+    id               = "c128";
+    desc             = "AT90CAN128";
+    has_jtag         = yes;
+    stk500_devcode   = 0xB3;
+#    avr910_devcode   = 0x43;
+    signature        = 0x1e 0x97 0x81;
+    chip_erase_delay = 9000;
+    pagel            = 0xD7;
+    bs2              = 0xA0;
+    reset            = dedicated;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 6;
+    togglevtg           = 0;
+    poweroffdelay       = 0;
+    resetdelayms        = 0;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+    rampz               = 0x3b;
+    eecr                = 0x3f;
+    allowfullpagebitstream = no;
+
+    memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 8;  /* for parallel programming */
+        size            = 4096;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+	read            = "  1   0   1   0      0   0   0   0",
+                          "  0   0   0   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+	write           = "  1   1   0   0      0   0   0   0",
+                          "  0   0   0   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0", 
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0  a2  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x    a11 a10  a9  a8",
+			  " a7  a6  a5  a4     a3   0   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+
+	mode		= 0x41;
+	delay		= 20;
+	blocksize	= 8;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 131072;
+        page_size       = 256;
+        num_pages       = 512;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  0   0   0   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  0   0   0   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7   x   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 256;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "efuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x  x x x x  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0 0 1 1  1 0 0 0  0 0 0 x  x x x x",
+                          "0 0 0 0  0 0 0 0  o o o o  o o o o";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+  ;
+
+#------------------------------------------------------------
+# AT90CAN64
+#------------------------------------------------------------
+
+part
+    id               = "c64";
+    desc             = "AT90CAN64";
+    has_jtag         = yes;
+    stk500_devcode   = 0xB3;
+#    avr910_devcode   = 0x43;
+    signature        = 0x1e 0x96 0x81;
+    chip_erase_delay = 9000;
+    pagel            = 0xD7;
+    bs2              = 0xA0;
+    reset            = dedicated;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 6;
+    togglevtg           = 0;
+    poweroffdelay       = 0;
+    resetdelayms        = 0;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+    rampz               = 0x3b;
+    eecr                = 0x3f;
+    allowfullpagebitstream = no;
+
+    memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 8;  /* for parallel programming */
+        size            = 2048;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+	read            = "  1   0   1   0      0   0   0   0",
+                          "  0   0   0   x      x a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+	write           = "  1   1   0   0      0   0   0   0",
+                          "  0   0   0   x      x a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0  a2  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x a10  a9  a8",
+			  " a7  a6  a5  a4     a3   0   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+
+	mode		= 0x41;
+	delay		= 20;
+	blocksize	= 8;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 65536;
+        page_size       = 256;
+        num_pages       = 256;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  0   0   0   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  0   0   0   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7   x   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 256;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "efuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x  x x x x  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0 0 1 1  1 0 0 0  0 0 0 x  x x x x",
+                          "0 0 0 0  0 0 0 0  o o o o  o o o o";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+  ;
+
+#------------------------------------------------------------
+# AT90CAN32
+#------------------------------------------------------------
+
+part
+    id               = "c32";
+    desc             = "AT90CAN32";
+    has_jtag         = yes;
+    stk500_devcode   = 0xB3;
+#    avr910_devcode   = 0x43;
+    signature        = 0x1e 0x95 0x81;
+    chip_erase_delay = 9000;
+    pagel            = 0xD7;
+    bs2              = 0xA0;
+    reset            = dedicated;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 6;
+    togglevtg           = 0;
+    poweroffdelay       = 0;
+    resetdelayms        = 0;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+    rampz               = 0x3b;
+    eecr                = 0x3f;
+    allowfullpagebitstream = no;
+
+    memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 8;  /* for parallel programming */
+        size            = 1024;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+	read            = "  1   0   1   0      0   0   0   0",
+                          "  0   0   0   x      x   x  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+	write           = "  1   1   0   0      0   0   0   0",
+                          "  0   0   0   x      x   x  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0  a2  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x  a9  a8",
+			  " a7  a6  a5  a4     a3   0   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+
+	mode		= 0x41;
+	delay		= 20;
+	blocksize	= 8;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 32768;
+        page_size       = 256;
+        num_pages       = 128;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  0   0   0   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  0   0   0   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7   x   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 256;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "efuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x  x x x x  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0 0 1 1  1 0 0 0  0 0 0 x  x x x x",
+                          "0 0 0 0  0 0 0 0  o o o o  o o o o";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+  ;
+
+
+#------------------------------------------------------------
+# ATmega16
+#------------------------------------------------------------
+
+part
+    id               = "m16";
+    desc             = "ATMEGA16";
+    has_jtag         = yes;
+    stk500_devcode   = 0x82;
+    avr910_devcode   = 0x74;
+    signature        = 0x1e 0x94 0x03;
+    pagel            = 0xd7;
+    bs2              = 0xa0;
+    chip_erase_delay = 9000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 0;
+
+    pp_controlstack     =
+	0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+	0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+	0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+	0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 100;
+    latchcycles         = 6;
+    togglevtg           = 0;
+    poweroffdelay       = 0;
+    resetdelayms        = 0;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    resetdelay          = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+    allowfullpagebitstream = yes;
+
+    memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 4;  /* for parallel programming */
+        size            = 512;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+	read            = "  1   0   1   0      0   0   0   0",
+                          "  0   0   x   x      x   x  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+	write           = "  1   1   0   0      0   0   0   0",
+                          "  0   0   x   x      x   x  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0", 
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x  a9  a8",
+			  " a7  a6  a5  a4     a3  a2   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x04;
+	delay		= 10;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 16384;
+        page_size       = 128;
+        num_pages       = 128;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "  0   0 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "  0   0 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  0   0   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  0   0   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "  0   0 a13 a12    a11 a10  a9  a8",
+                          " a7  a6   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x21;
+	delay		= 6;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+    memory "calibration"
+        size            = 4;
+
+        read            = "0 0 1 1  1 0 0 0   0 0 0 x  x x x x",
+                          "0 0 0 0  0 0 a1 a0 o o o o  o o o o";
+        ;
+  ;
+
+
+#------------------------------------------------------------
+# ATmega164P
+#------------------------------------------------------------
+
+# close to ATmega16
+
+part
+    id               = "m164p";
+    desc             = "ATMEGA164P";
+    has_jtag         = yes;
+    stk500_devcode   = 0x82; # no STK500v1 support, use the ATmega16 one
+    avr910_devcode   = 0x74;
+    signature        = 0x1e 0x94 0x0a;
+    pagel            = 0xd7;
+    bs2              = 0xa0;
+    chip_erase_delay = 9000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 0;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+    allowfullpagebitstream = no;
+
+    memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 4;  /* for parallel programming */
+        size            = 512;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+	read            = "  1   0   1   0      0   0   0   0",
+                          "  0   0   x   x      x   x  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+	write           = "  1   1   0   0      0   0   0   0",
+                          "  0   0   x   x      x   x  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0", 
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x  a9  a8",
+			  " a7  a6  a5  a4     a3  a2   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 10;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 16384;
+        page_size       = 128;
+        num_pages       = 128;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "  0   0 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "  0   0 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  0   0   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  0   0   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "  0   0 a13 a12    a11 a10  a9  a8",
+                          " a7  a6   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x21;
+	delay		= 6;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "efuse"
+        size            = 1;
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x  1 1 1 1  1 i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+
+    memory "calibration"
+        size            = 1;
+
+        read            = "0 0 1 1  1 0 0 0   0 0 0 x  x x x x",
+                          "0 0 0 0  0 0 0 0   o o o o  o o o o";
+        ;
+  ;
+
+
+#------------------------------------------------------------
+# ATmega324P
+#------------------------------------------------------------
+
+# similar to ATmega164P
+
+part
+    id               = "m324p";
+    desc             = "ATMEGA324P";
+    has_jtag         = yes;
+    stk500_devcode   = 0x82; # no STK500v1 support, use the ATmega16 one
+    avr910_devcode   = 0x74;
+    signature        = 0x1e 0x95 0x08;
+    pagel            = 0xd7;
+    bs2              = 0xa0;
+    chip_erase_delay = 9000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 0;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+    allowfullpagebitstream = no;
+
+    memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 4;  /* for parallel programming */
+        size            = 1024;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+	read            = "  1   0   1   0      0   0   0   0",
+                          "  0   0   x   x      x a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+	write           = "  1   1   0   0      0   0   0   0",
+                          "  0   0   x   x      x a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0", 
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x a10  a9  a8",
+			  " a7  a6  a5  a4     a3  a2   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 10;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 32768;
+        page_size       = 128;
+        num_pages       = 256;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "  0 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "  0 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  0   0   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  0   0   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "  0 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x21;
+	delay		= 6;
+	blocksize	= 256;
+	readsize	= 256;
+      ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "efuse"
+        size            = 1;
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x  1 1 1 1  1 i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+
+    memory "calibration"
+        size            = 1;
+
+        read            = "0 0 1 1  1 0 0 0   0 0 0 x  x x x x",
+                          "0 0 0 0  0 0 0 0   o o o o  o o o o";
+        ;
+  ;
+
+
+#------------------------------------------------------------
+# ATmega644
+#------------------------------------------------------------
+
+# similar to ATmega164
+
+part
+    id               = "m644";
+    desc             = "ATMEGA644";
+    has_jtag         = yes;
+    stk500_devcode   = 0x82; # no STK500v1 support, use the ATmega16 one
+    avr910_devcode   = 0x74;
+    signature        = 0x1e 0x96 0x09;
+    pagel            = 0xd7;
+    bs2              = 0xa0;
+    chip_erase_delay = 9000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 0;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 6;
+    togglevtg           = 0;
+    poweroffdelay       = 0;
+    resetdelayms        = 0;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+    allowfullpagebitstream = no;
+
+    memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 8;  /* for parallel programming */
+        size            = 2048;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+	read            = "  1   0   1   0      0   0   0   0",
+                          "  0   0   x   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+	write           = "  1   1   0   0      0   0   0   0",
+                          "  0   0   x   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0", 
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0  a2  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x    a11 a10  a9  a8",
+			  " a7  a6  a5  a4     a3   0   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 10;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 65536;
+        page_size       = 256;
+        num_pages       = 256;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  0   0   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  0   0   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7   x   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x21;
+	delay		= 6;
+	blocksize	= 256;
+	readsize	= 256;
+      ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "efuse"
+        size            = 1;
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x  1 1 1 1  1 i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+
+    memory "calibration"
+        size            = 1;
+
+        read            = "0 0 1 1  1 0 0 0   0 0 0 x  x x x x",
+                          "0 0 0 0  0 0 0 0   o o o o  o o o o";
+        ;
+  ;
+
+#------------------------------------------------------------
+# ATmega644P
+#------------------------------------------------------------
+
+# similar to ATmega164p
+
+part
+    id               = "m644p";
+    desc             = "ATMEGA644P";
+    has_jtag         = yes;
+    stk500_devcode   = 0x82; # no STK500v1 support, use the ATmega16 one
+    avr910_devcode   = 0x74;
+    signature        = 0x1e 0x96 0x0a;
+    pagel            = 0xd7;
+    bs2              = 0xa0;
+    chip_erase_delay = 9000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 0;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 6;
+    togglevtg           = 0;
+    poweroffdelay       = 0;
+    resetdelayms        = 0;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+    allowfullpagebitstream = no;
+
+    memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 8;  /* for parallel programming */
+        size            = 2048;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+	read            = "  1   0   1   0      0   0   0   0",
+                          "  0   0   x   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+	write           = "  1   1   0   0      0   0   0   0",
+                          "  0   0   x   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0", 
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0  a2  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x    a11 a10  a9  a8",
+			  " a7  a6  a5  a4     a3   0   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 10;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 65536;
+        page_size       = 256;
+        num_pages       = 256;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  0   0   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  0   0   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7   x   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x21;
+	delay		= 6;
+	blocksize	= 256;
+	readsize	= 256;
+      ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "efuse"
+        size            = 1;
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x  1 1 1 1  1 i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+
+    memory "calibration"
+        size            = 1;
+
+        read            = "0 0 1 1  1 0 0 0   0 0 0 x  x x x x",
+                          "0 0 0 0  0 0 0 0   o o o o  o o o o";
+        ;
+  ;
+
+
+
+#------------------------------------------------------------
+# ATmega1284P
+#------------------------------------------------------------
+
+# similar to ATmega164p
+
+part
+    id               = "m1284p";
+    desc             = "ATMEGA1284P";
+    has_jtag         = yes;
+    stk500_devcode   = 0x82; # no STK500v1 support, use the ATmega16 one
+    avr910_devcode   = 0x74;
+    signature        = 0x1e 0x97 0x05;
+    pagel            = 0xd7;
+    bs2              = 0xa0;
+    chip_erase_delay = 9000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 6;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+    allowfullpagebitstream = no;
+
+    memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 8;  /* for parallel programming */
+        size            = 4096;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+	read            = "  1   0   1   0      0   0   0   0",
+                          "  0   0   x   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+	write           = "  1   1   0   0      0   0   0   0",
+                          "  0   0   x   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0", 
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0  a2  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x    a11 a10  a9  a8",
+			  " a7  a6  a5  a4     a3   0   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 10;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 131072;
+        page_size       = 256;
+        num_pages       = 512;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  0   0   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  0   0   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7   x   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 10;
+	blocksize	= 256;
+	readsize	= 256;
+      ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "efuse"
+        size            = 1;
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x  1 1 1 1  1 i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+
+    memory "calibration"
+        size            = 1;
+
+        read            = "0 0 1 1  1 0 0 0   0 0 0 x  x x x x",
+                          "0 0 0 0  0 0 0 0   o o o o  o o o o";
+        ;
+  ;
+
+
+
+#------------------------------------------------------------
+# ATmega162
+#------------------------------------------------------------
+
+part
+    id               = "m162";
+    desc             = "ATMEGA162";
+    has_jtag         = yes;
+    stk500_devcode   = 0x83;
+    avr910_devcode   = 0x63;
+    signature        = 0x1e 0x94 0x04;
+    chip_erase_delay = 9000;
+    pagel            = 0xd7;
+    bs2              = 0xa0;
+
+    idr              = 0x04;
+    spmcr            = 0x57;
+    allowfullpagebitstream = yes;
+
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    memory "flash"
+        paged           = yes;
+        size            = 16384;
+        page_size       = 128;
+        num_pages       = 128;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "  0   0 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "  0   0 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  0   0   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  0   0   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "  0   0 a13 a12    a11 a10  a9  a8",
+                          " a7  a6   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+       mode        = 0x41;
+    delay       = 10;
+    blocksize   = 128;
+    readsize    = 256;  
+
+        ;
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 0;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 6;
+    togglevtg           = 0;
+    poweroffdelay       = 0;
+    resetdelayms        = 0;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 4;  /* for parallel programming */
+        size            = 512;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+
+                read            = "  1   0   1   0      0   0   0   0",
+                          "  0   0   x   x      x   x  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+                write           = "  1   1   0   0      0   0   0   0",
+                          "  0   0   x   x      x   x  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x  a9  a8",
+			  " a7  a6  a5  a4     a3  a2   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 20;
+	blocksize	= 4;
+	readsize	= 256;
+        ;
+
+    memory "lfuse"
+        size            = 1;
+        min_write_delay = 16000;
+        max_write_delay = 16000;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+        ;
+
+    memory "hfuse"
+        size            = 1;
+        min_write_delay = 16000;
+        max_write_delay = 16000;
+
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+        ;
+
+    memory "efuse"
+        size            = 1;
+        min_write_delay = 16000;
+        max_write_delay = 16000;
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x  1 1 1 1  1 i i i";
+      ;
+
+    memory "lock"
+        size            = 1;
+        min_write_delay = 16000;
+        max_write_delay = 16000;
+
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+        ;
+
+    memory "signature"
+        size            = 3;
+
+        read            = "0  0  1  1   0  0  0  0   0  0  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+        ;
+
+    memory "calibration"
+        size            = 1;
+
+        read            = "0 0 1 1  1 0 0 0   0 0 x x  x x x x",
+                          "0 0 0 0  0 0 0 0   o o o o  o o o o";
+        ;
+;
+
+
+
+#------------------------------------------------------------
+# ATmega163
+#------------------------------------------------------------
+
+part
+    id               = "m163";
+    desc             = "ATMEGA163";
+    stk500_devcode   = 0x81;
+    avr910_devcode   = 0x64;
+    signature        = 0x1e 0x94 0x02;
+    chip_erase_delay = 32000;
+    pagel            = 0xd7;
+    bs2              = 0xa0;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout             = 200;
+    stabdelay           = 100;
+    cmdexedelay         = 25;
+    synchloops          = 32;
+    bytedelay           = 0;
+    pollindex           = 3;
+    pollvalue           = 0x53;
+    predelay            = 1;
+    postdelay           = 1;
+    pollmethod          = 0;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 0;
+    togglevtg           = 0;
+    poweroffdelay       = 0;
+    resetdelayms        = 0;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 30;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 2;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 2;
+
+
+   memory "eeprom"
+        size            = 512;
+        min_write_delay = 4000;
+        max_write_delay = 4000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+	read            = "  1   0   1   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+	write           = "  1   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+        mode            = 0x41;
+        delay           = 20;
+        blocksize       = 4;
+        readsize        = 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 16384;
+        page_size       = 128;
+        num_pages       = 128;
+        min_write_delay = 16000;
+        max_write_delay = 16000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "  x   x   x a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "  x   x   x a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "  x   x   x a12    a11 a10  a9  a8",
+                          " a7  a6   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x11;
+	delay		= 20;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        min_write_delay = 2000;
+        max_write_delay = 2000;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   o o x x  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x   i i 1 1  i i i i";
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        min_write_delay = 2000;
+        max_write_delay = 2000;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   x x x x  1 o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x   1 1 1 1  1 i i i";
+      ;
+
+    memory "lock"
+        size            = 1;
+        min_write_delay = 2000;
+        max_write_delay = 2000;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  0 x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0 0 1 1  1 0 0 0   x x x x  x x x x",
+                          "0 0 0 0  0 0 0 0   o o o o  o o o o";
+      ;
+  ;
+
+#------------------------------------------------------------
+# ATmega169
+#------------------------------------------------------------
+
+part
+    id               = "m169";
+    desc             = "ATMEGA169";
+    has_jtag         = yes;
+    stk500_devcode   = 0x85;
+    avr910_devcode   = 0x78;
+    signature        = 0x1e 0x94 0x05;
+    chip_erase_delay = 9000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+
+   memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 4;  /* for parallel programming */
+        size            = 512;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+	read            = "  1   0   1   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+	write           = "  1   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0", 
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x   x  a8",
+			  " a7  a6  a5  a4     a3  a2   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 20;
+	blocksize	= 4;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 16384;
+        page_size       = 128;
+        num_pages       = 128;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "  x   x   x a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "  x   x   x a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "  x   x   x a12    a11 a10  a9  a8",
+                          " a7  a6   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        min_write_delay = 2000;
+        max_write_delay = 2000;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        min_write_delay = 2000;
+        max_write_delay = 2000;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+      ;
+
+    memory "efuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x  x x x x  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+      ;
+
+    memory "lock"
+        size            = 1;
+        min_write_delay = 2000;
+        max_write_delay = 2000;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   0  0  0  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0 0 1 1  1 0 0 0   0 0 0 x  x x x x",
+                          "0 0 0 0  0 0 0 0   o o o o  o o o o";
+      ;
+  ;
+
+#------------------------------------------------------------
+# ATmega329
+#------------------------------------------------------------
+
+part
+    id               = "m329";
+    desc             = "ATMEGA329";
+    has_jtag         = yes;
+#    stk500_devcode   = 0x85; # no STK500 support, only STK500v2
+#    avr910_devcode   = 0x?;  # try the ATmega169 one:
+    avr910_devcode   = 0x75;
+    signature        = 0x1e 0x95 0x03;
+    chip_erase_delay = 9000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+
+   memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 4;  /* for parallel programming */
+        size            = 1024;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+	read            = "  1   0   1   0      0   0   0   0",
+                          "  x   x   x   x      x   x  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+	write           = "  1   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x  a9  a8",
+			  " a7  a6  a5  a4     a3  a2   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 20;
+	blocksize	= 8;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 32768;
+        page_size       = 128;
+        num_pages       = 256;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "  x a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "  x a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "  x   x   x a12    a11 a10  a9  a8",
+                          " a7  a6   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 256;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+      ;
+
+    memory "efuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x   x x x x  x i i i";
+      ;
+
+    memory "lock"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   0  0  0  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0 0 1 1  1 0 0 0   0 0 0 x  x x x x",
+                          "0 0 0 0  0 0 0 0   o o o o  o o o o";
+      ;
+  ;
+
+#------------------------------------------------------------
+# ATmega329P
+#------------------------------------------------------------
+# Identical to ATmega329 except of the signature
+
+part
+    id               = "m329p";
+    desc             = "ATMEGA329P";
+    has_jtag         = yes;
+#    stk500_devcode   = 0x85; # no STK500 support, only STK500v2
+#    avr910_devcode   = 0x?;  # try the ATmega169 one:
+    avr910_devcode   = 0x75;
+    signature        = 0x1e 0x95 0x0b;
+    chip_erase_delay = 9000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+
+   memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 4;  /* for parallel programming */
+        size            = 1024;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+	read            = "  1   0   1   0      0   0   0   0",
+                          "  x   x   x   x      x   x  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+	write           = "  1   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x  a9  a8",
+			  " a7  a6  a5  a4     a3  a2   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 20;
+	blocksize	= 8;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 32768;
+        page_size       = 128;
+        num_pages       = 256;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "  x a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "  x a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "  x   x   x a12    a11 a10  a9  a8",
+                          " a7  a6   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 256;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+      ;
+
+    memory "efuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x   x x x x  x i i i";
+      ;
+
+    memory "lock"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   0  0  0  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0 0 1 1  1 0 0 0   0 0 0 x  x x x x",
+                          "0 0 0 0  0 0 0 0   o o o o  o o o o";
+      ;
+  ;
+
+#------------------------------------------------------------
+# ATmega3290
+#------------------------------------------------------------
+
+# identical to ATmega329
+
+part
+    id               = "m3290";
+    desc             = "ATMEGA3290";
+    has_jtag         = yes;
+#    stk500_devcode   = 0x85; # no STK500 support, only STK500v2
+#    avr910_devcode   = 0x?;  # try the ATmega169 one:
+    avr910_devcode   = 0x75;
+    signature        = 0x1e 0x95 0x04;
+    chip_erase_delay = 9000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+
+   memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 4;  /* for parallel programming */
+        size            = 1024;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+	read            = "  1   0   1   0      0   0   0   0",
+                          "  x   x   x   x      x   x  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+	write           = "  1   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x  a9  a8",
+			  " a7  a6  a5  a4     a3  a3   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 20;
+	blocksize	= 8;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 32768;
+        page_size       = 128;
+        num_pages       = 256;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "  x a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "  x a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "  x   x   x a12    a11 a10  a9  a8",
+                          " a7  a6   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 256;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+      ;
+
+    memory "efuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x   x x x x  x i i i";
+      ;
+
+    memory "lock"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   0  0  0  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0 0 1 1  1 0 0 0   0 0 0 x  x x x x",
+                          "0 0 0 0  0 0 0 0   o o o o  o o o o";
+      ;
+  ;
+
+#------------------------------------------------------------
+# ATmega3290P
+#------------------------------------------------------------
+
+# identical to ATmega3290 except of the signature
+
+part
+    id               = "m3290p";
+    desc             = "ATMEGA3290P";
+    has_jtag         = yes;
+#    stk500_devcode   = 0x85; # no STK500 support, only STK500v2
+#    avr910_devcode   = 0x?;  # try the ATmega169 one:
+    avr910_devcode   = 0x75;
+    signature        = 0x1e 0x95 0x0c;
+    chip_erase_delay = 9000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+
+   memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 4;  /* for parallel programming */
+        size            = 1024;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+	read            = "  1   0   1   0      0   0   0   0",
+                          "  x   x   x   x      x   x  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+	write           = "  1   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x  a9  a8",
+			  " a7  a6  a5  a4     a3  a3   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 20;
+	blocksize	= 8;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 32768;
+        page_size       = 128;
+        num_pages       = 256;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "  x a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "  x a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "  x   x   x a12    a11 a10  a9  a8",
+                          " a7  a6   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 256;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+      ;
+
+    memory "efuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x   x x x x  x i i i";
+      ;
+
+    memory "lock"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   0  0  0  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0 0 1 1  1 0 0 0   0 0 0 x  x x x x",
+                          "0 0 0 0  0 0 0 0   o o o o  o o o o";
+      ;
+  ;
+
+#------------------------------------------------------------
+# ATmega649
+#------------------------------------------------------------
+
+part
+    id               = "m649";
+    desc             = "ATMEGA649";
+    has_jtag         = yes;
+#    stk500_devcode   = 0x85; # no STK500 support, only STK500v2
+#    avr910_devcode   = 0x?;  # try the ATmega169 one:
+    avr910_devcode   = 0x75;
+    signature        = 0x1e 0x96 0x03;
+    chip_erase_delay = 9000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+
+   memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 8;  /* for parallel programming */
+        size            = 2048;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+	read            = "  1   0   1   0      0   0   0   0",
+                          "  x   x   x   x      x a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+	write           = "  1   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0  a2  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x a10  a9  a8",
+			  " a7  a6  a5  a4     a3   0   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 20;
+	blocksize	= 8;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 65536;
+        page_size       = 256;
+        num_pages       = 256;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "  x   x   x a12    a11 a10  a9  a8",
+                          " a7   x   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 256;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+      ;
+
+    memory "efuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x   x x x x  x i i i";
+      ;
+
+    memory "lock"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   0  0  0  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0 0 1 1  1 0 0 0   0 0 0 x  x x x x",
+                          "0 0 0 0  0 0 0 0   o o o o  o o o o";
+      ;
+  ;
+
+#------------------------------------------------------------
+# ATmega6490
+#------------------------------------------------------------
+
+# identical to ATmega649
+
+part
+    id               = "m6490";
+    desc             = "ATMEGA6490";
+    has_jtag         = yes;
+#    stk500_devcode   = 0x85; # no STK500 support, only STK500v2
+#    avr910_devcode   = 0x?;  # try the ATmega169 one:
+    avr910_devcode   = 0x75;
+    signature        = 0x1e 0x96 0x04;
+    chip_erase_delay = 9000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+
+   memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 8;  /* for parallel programming */
+        size            = 2048;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+	read            = "  1   0   1   0      0   0   0   0",
+                          "  x   x   x   x      x a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+	write           = "  1   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0  a2  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x   x  a8",
+			  " a7  a6  a5  a4     a3   0   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0  a2  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x a10  a9  a8",
+			  " a7  a6  a5  a4     a3   0   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 20;
+	blocksize	= 8;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 65536;
+        page_size       = 256;
+        num_pages       = 256;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "  x   x   x a12    a11 a10  a9  a8",
+                          " a7   x   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 256;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+      ;
+
+    memory "efuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x   x x x x  x i i i";
+      ;
+
+    memory "lock"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   0  0  0  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0 0 1 1  1 0 0 0   0 0 0 x  x x x x",
+                          "0 0 0 0  0 0 0 0   o o o o  o o o o";
+      ;
+  ;
+
+#------------------------------------------------------------
+# ATmega32
+#------------------------------------------------------------
+
+part
+    id               = "m32";
+    desc             = "ATMEGA32";
+    has_jtag         = yes;
+    stk500_devcode   = 0x91;
+    avr910_devcode   = 0x72;
+    signature        = 0x1e 0x95 0x02;
+    chip_erase_delay = 9000;
+    pagel            = 0xd7;
+    bs2              = 0xa0;
+    reset            = dedicated;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 0;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 6;
+    togglevtg           = 0;
+    poweroffdelay       = 0;
+    resetdelayms        = 0;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+    allowfullpagebitstream = yes;
+
+   memory "eeprom"
+        paged           = no;   /* leave this "no" */
+        page_size       = 4;    /* for parallel programming */
+        size            = 1024;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read            = "  1   0   1   0      0   0   0   0",
+                          "  0   0   x   x      x   x  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        write           = "  1   1   0   0      0   0   0   0",
+                          "  0   0   x   x      x   x  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x  a9  a8",
+			  " a7  a6  a5  a4     a3  a2   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x04;
+	delay		= 10;
+	blocksize	= 64;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 32768;
+        page_size       = 128;
+        num_pages       = 256;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "  0   0 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "  0   0 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  0   0   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  0   0   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "  0   0 a13 a12    a11 a10  a9  a8",
+                          " a7  a6   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x21;
+	delay		= 6;
+	blocksize	= 64;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        min_write_delay = 2000;
+        max_write_delay = 2000;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        min_write_delay = 2000;
+        max_write_delay = 2000;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+      ;
+
+    memory "lock"
+        size            = 1;
+        min_write_delay = 2000;
+        max_write_delay = 2000;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o o";
+      ;
+
+    memory "calibration"
+        size            = 4;
+        read            = "0 0 1 1  1 0 0 0    0 0 x x  x x x x",
+                          "0 0 0 0  0 0 a1 a0  o o o o  o o o o";
+      ;
+  ;
+
+#------------------------------------------------------------
+# ATmega161
+#------------------------------------------------------------
+
+part
+    id               = "m161";
+    desc             = "ATMEGA161";
+    stk500_devcode   = 0x80;
+    avr910_devcode   = 0x60;
+    signature        = 0x1e 0x94 0x01;
+    chip_erase_delay = 28000;
+    pagel            = 0xd7;
+    bs2              = 0xa0;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 0;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 0;
+    togglevtg           = 0;
+    poweroffdelay       = 0;
+    resetdelayms        = 0;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 30;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 2;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 2;
+
+   memory "eeprom"
+        size            = 512;
+        min_write_delay = 3400;
+        max_write_delay = 3400;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+	read            = "  1   0   1   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+	write           = "  1   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+	mode		= 0x04;
+	delay		= 5;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 16384;
+        page_size       = 128;
+        num_pages       = 128;
+        min_write_delay = 14000;
+        max_write_delay = 14000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "  x   x   x a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "  x   x   x a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "  x   x   x a12    a11 a10  a9  a8",
+                          " a7  a6   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x21;
+	delay		= 16;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+
+    memory "fuse"
+        size            = 1;
+        min_write_delay = 2000;
+        max_write_delay = 2000;
+        read            = "0 1 0 1  0 0 0 0   x x x x  x x x x",
+                          "x x x x  x x x x   x o x o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 x  x x x x",
+                          "x x x x  x x x x   1 i 1 i  i i i i";
+      ;
+
+    memory "lock"
+        size            = 1;
+        min_write_delay = 2000;
+        max_write_delay = 2000;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+      ;
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+  ;
+
+
+#------------------------------------------------------------
+# ATmega8
+#------------------------------------------------------------
+
+part
+    id               = "m8";
+    desc             = "ATMEGA8";
+    stk500_devcode   = 0x70;
+    avr910_devcode   = 0x76;
+    signature        = 0x1e 0x93 0x07;
+    pagel            = 0xd7;
+    bs2              = 0xc2;
+    chip_erase_delay = 10000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 0;
+
+    pp_controlstack     =
+	0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+	0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+	0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+	0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 2;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    resetdelay          = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    memory "eeprom"
+        size            = 512;
+        page_size       = 4;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+	read            = "  1   0   1   0      0   0   0   0",
+                          "  0   0   x   x      x   x   x  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+	write           = "  1   1   0   0      0   0   0   0",
+                          "  0   0   x   x      x   x   x  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0", 
+                          "  i   i   i   i      i   i   i   i";
+
+	mode		= 0x04;
+	delay		= 20;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+    memory "flash"
+        paged           = yes;
+        size            = 8192;
+        page_size       = 64;
+        num_pages       = 128;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0x00;
+        read_lo         = "  0   0   1   0    0   0   0   0",
+                          "  0   0   0   0  a11 a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        read_hi         = "  0   0   1   0    1   0   0   0",
+                          "  0   0   0   0  a11 a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  0   0   0   0      x   x   x   x",
+                          "  x   x   x  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  0   0   0   0      x   x   x   x",
+                          "  x   x   x  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "  0   0   0   0    a11 a10  a9  a8",
+                          " a7  a6  a5   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x21;
+	delay		= 10;
+	blocksize	= 64;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        min_write_delay = 2000;
+        max_write_delay = 2000;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        min_write_delay = 2000;
+        max_write_delay = 2000;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+      ;
+
+    memory "lock"
+        size            = 1;
+        min_write_delay = 2000;
+        max_write_delay = 2000;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+      ;
+
+    memory "calibration"
+        size            = 4;
+        read            = "0  0  1  1   1  0  0  0   0  0  x  x   x  x  x  x",
+                          "0  0  0  0   0  0 a1 a0   o  o  o  o   o  o  o  o";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+  ;
+
+
+
+#------------------------------------------------------------
+# ATmega8515
+#------------------------------------------------------------
+
+part
+    id               = "m8515";
+    desc             = "ATMEGA8515";
+    stk500_devcode   = 0x63;
+    avr910_devcode   = 0x3A;
+    signature        = 0x1e 0x93 0x06;
+    chip_erase_delay = 9000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 0;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 6;
+    togglevtg           = 0;
+    poweroffdelay       = 0;
+    resetdelayms        = 0;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    memory "eeprom"
+        size            = 512;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+ read            = "  1   0   1   0      0   0   0   0",
+                          "  0   0   x   x      x   x   x  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+ write           = "  1   1   0   0      0   0   0   0",
+                          "  0   0   x   x      x   x   x  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+	mode		= 0x04;
+	delay		= 10;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+    memory "flash"
+        paged           = yes;
+        size            = 8192;
+        page_size       = 64;
+        num_pages       = 128;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0    0   0   0   0",
+                          "  0   0   0   0  a11 a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        read_hi         = "  0   0   1   0    1   0   0   0",
+                          "  0   0   0   0  a11 a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  0   0   0   0      x   x   x   x",
+                          "  x   x   x  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  0   0   0   0      x   x   x   x",
+                          "  x   x   x  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "  0   0   0   0    a11 a10  a9  a8",
+                          " a7  a6  a5   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x21;
+	delay		= 6;
+	blocksize	= 64;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+      ;
+
+    memory "lock"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+      ;
+
+    memory "calibration"
+        size            = 4;
+        read            = "0 0 1 1  1 0 0 0     0 0 x x  x x x x",
+                          "0 0 0 0  0 0 a1 a0   o o o o  o o o o";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+  ;
+
+
+
+
+#------------------------------------------------------------
+# ATmega8535
+#------------------------------------------------------------
+
+part
+    id               = "m8535";
+    desc             = "ATMEGA8535";
+    stk500_devcode   = 0x64;
+    avr910_devcode   = 0x69;
+    signature        = 0x1e 0x93 0x08;
+    pagel            = 0xd7;
+    bs2              = 0xa0;
+    chip_erase_delay = 9000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 0;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 6;
+    togglevtg           = 0;
+    poweroffdelay       = 0;
+    resetdelayms        = 0;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    memory "eeprom"
+        size            = 512;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+	read            = "  1   0   1   0      0   0   0   0",
+                          "  0   0   x   x      x   x   x  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+	write           = "  1   1   0   0      0   0   0   0",
+                          "  0   0   x   x      x   x   x  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+	mode		= 0x04;
+	delay		= 10;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+    memory "flash"
+        paged           = yes;
+        size            = 8192;
+        page_size       = 64;
+        num_pages       = 128;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0    0   0   0   0",
+                          "  0   0   0   0  a11 a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        read_hi         = "  0   0   1   0    1   0   0   0",
+                          "  0   0   0   0  a11 a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  0   0   0   0      x   x   x   x",
+                          "  x   x   x  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  0   0   0   0      x   x   x   x",
+                          "  x   x   x  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "  0   0   0   0    a11 a10  a9  a8",
+                          " a7  a6  a5   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x21;
+	delay		= 6;
+	blocksize	= 64;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        min_write_delay = 2000;
+        max_write_delay = 2000;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        min_write_delay = 2000;
+        max_write_delay = 2000;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+      ;
+
+    memory "lock"
+        size            = 1;
+        min_write_delay = 2000;
+        max_write_delay = 2000;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+      ;
+
+    memory "calibration"
+        size            = 4;
+        read            = "0 0 1 1  1 0 0 0   0 0 x x  x x x x",
+                          "0 0 0 0  0 0 a1 a0 o o o o  o o o o";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+  ;
+
+
+#------------------------------------------------------------
+# ATtiny26
+#------------------------------------------------------------
+
+part
+    id                  = "t26";
+    desc                = "ATTINY26";
+    stk500_devcode      = 0x21;
+    avr910_devcode      = 0x5e;
+    signature           = 0x1e 0x91 0x09;
+    pagel               = 0xb3;
+    bs2                 = 0xb2;
+    chip_erase_delay    = 9000;
+    pgm_enable          = "1 0 1 0  1 1 0 0   0 1 0 1  0 0 1 1",
+                          "x x x x  x x x x   x x x x  x x x x";
+
+    chip_erase          = "1 0 1 0  1 1 0 0   1 0 0 x  x x x x",
+                          "x x x x  x x x x   x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 0;
+
+    pp_controlstack     =
+        0xC4, 0xE4, 0xC4, 0xE4, 0xCC, 0xEC, 0xCC, 0xEC,
+        0xD4, 0xF4, 0xD4, 0xF4, 0xDC, 0xFC, 0xDC, 0xFC,
+        0xC8, 0xE8, 0xD8, 0xF8, 0x4C, 0x6C, 0x5C, 0x7C,
+        0xEC, 0xBC, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 2;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    memory "eeprom"
+        size            = 128;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read            = "1  0  1  0   0  0  0  0    x x x x  x x x x",
+                          "x a6 a5 a4  a3 a2 a1 a0    o o o o  o o o o";
+
+        write           = "1  1  0  0   0  0  0  0    x x x x  x x x x",
+                          "x a6 a5 a4  a3 a2 a1 a0    i i i i  i i i i";
+
+	mode		= 0x04;
+	delay		= 10;
+	blocksize	= 64;
+	readsize	= 256;
+    ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 2048;
+        page_size       = 32;
+        num_pages       = 64;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0  0  1  0   0  0  0  0",
+                          "  x  x  x  x   x  x a9 a8",
+                          " a7 a6 a5 a4  a3 a2 a1 a0",
+                          "  o  o  o  o   o  o  o  o";
+
+        read_hi         = "  0  0  1  0   1  0  0  0",
+                          "  x  x  x  x   x  x a9 a8",
+                          " a7 a6 a5 a4  a3 a2 a1 a0",
+                          "  o  o  o  o   o  o  o  o";
+
+        loadpage_lo     = "  0  1  0  0   0  0  0  0",
+                          "  x  x  x  x   x  x  x  x",
+                          "  x  x  x  x  a3 a2 a1 a0",
+                          "  i  i  i  i   i  i  i  i";
+
+        loadpage_hi     = "  0  1  0  0   1  0  0  0",
+                          "  x  x  x  x   x  x  x  x",
+                          "  x  x  x  x  a3 a2 a1 a0",
+                          "  i  i  i  i   i  i  i  i";
+
+        writepage       = "  0  1  0  0   1  1  0  0",
+                          "  x  x  x  x   x  x a9 a8",
+                          " a7 a6 a5 a4   x  x  x  x",
+                          "  x  x  x  x   x  x  x  x";
+
+	mode		= 0x21;
+	delay		= 6;
+	blocksize	= 16;
+	readsize	= 256;
+    ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0    x x x x  x x x x",
+                          "0  0  0  0   0  0 a1 a0    o o o o  o o o o";
+    ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0  1  0  1   1  0  0  0    x x x x  x x x x",
+                          "x  x  x  x   x  x  x  x    x x x x  x x o o";
+
+        write           = "1  0  1  0   1  1  0  0    1 1 1 1  1 1 i i",
+                          "x  x  x  x   x  x  x  x    x x x x  x x x x";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+    ;
+
+    memory "lfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x  x x x i  i i i i";
+
+        read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  x x x o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "calibration"
+        size            = 4;
+        read            = "0  0  1  1   1  0  0  0    x x x x  x x x x",
+                          "0  0  0  0   0  0 a1 a0    o o o o  o o o o";
+    ;
+
+;
+
+
+#------------------------------------------------------------
+# ATtiny261
+#------------------------------------------------------------
+# Close to ATtiny26
+
+part
+    id                  = "t261";
+    desc                = "ATTINY261";
+     has_debugwire = yes;
+     flash_instr   = 0xB4, 0x00, 0x10;
+     eeprom_instr  = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D,
+	             0xBC, 0x00, 0xB4, 0x00, 0xBA, 0x0D, 0xBB, 0xBC,
+	             0x99, 0xE1, 0xBB, 0xAC;
+#    stk500_devcode      = 0x21;
+#    avr910_devcode      = 0x5e;
+    signature           = 0x1e 0x91 0x0c;
+    pagel               = 0xb3;
+    bs2                 = 0xb2;
+    chip_erase_delay    = 4000;
+
+    pgm_enable          = "1 0 1 0  1 1 0 0   0 1 0 1  0 0 1 1",
+                          "x x x x  x x x x   x x x x  x x x x";
+
+    chip_erase          = "1 0 1 0  1 1 0 0   1 0 0 x  x x x x",
+                          "x x x x  x x x x   x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 0;
+
+    pp_controlstack     =
+        0xC4, 0xE4, 0xC4, 0xE4, 0xCC, 0xEC, 0xCC, 0xEC,
+        0xD4, 0xF4, 0xD4, 0xF4, 0xDC, 0xFC, 0xDC, 0xFC,
+        0xC8, 0xE8, 0xD8, 0xF8, 0x4C, 0x6C, 0x5C, 0x7C,
+        0xEC, 0xBC, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 2;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    memory "eeprom"
+        paged           = no;
+        size            = 128;
+        page_size       = 4;
+        num_pages       = 32;
+        min_write_delay = 4000;
+        max_write_delay = 4000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+
+        read            = "1  0  1  0   0  0  0  0    x x x x  x x x x",
+                          "x a6 a5 a4  a3 a2 a1 a0    o o o o  o o o o";
+
+        write           = "1  1  0  0   0  0  0  0    x x x x  x x x x",
+                          "x a6 a5 a4  a3 a2 a1 a0    i i i i  i i i i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x   x   x",
+			  "  x  a6  a5  a4     a3  a2   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 10;
+	blocksize	= 4;
+	readsize	= 256;
+    ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 2048;
+        page_size       = 32;
+        num_pages       = 64;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+
+        read_lo         = "  0  0  1  0   0  0  0  0",
+                          "  x  x  x  x   x  x a9 a8",
+                          " a7 a6 a5 a4  a3 a2 a1 a0",
+                          "  o  o  o  o   o  o  o  o";
+
+        read_hi         = "  0  0  1  0   1  0  0  0",
+                          "  x  x  x  x   x  x a9 a8",
+                          " a7 a6 a5 a4  a3 a2 a1 a0",
+                          "  o  o  o  o   o  o  o  o";
+
+        loadpage_lo     = "  0  1  0  0   0  0  0  0",
+                          "  x  x  x  x   x  x  x  x",
+                          "  x  x  x  x  a3 a2 a1 a0",
+                          "  i  i  i  i   i  i  i  i";
+
+        loadpage_hi     = "  0  1  0  0   1  0  0  0",
+                          "  x  x  x  x   x  x  x  x",
+                          "  x  x  x  x  a3 a2 a1 a0",
+                          "  i  i  i  i   i  i  i  i";
+
+        writepage       = "  0  1  0  0   1  1  0  0",
+                          "  x  x  x  x   x  x a9 a8",
+                          " a7 a6 a5 a4   x  x  x  x",
+                          "  x  x  x  x   x  x  x  x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 32;
+	readsize	= 256;
+    ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0    x x x x  x x x x",
+                          "0  0  0  0   0  0 a1 a0    o o o o  o o o o";
+    ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0  1  0  1   1  0  0  0    x x x x  x x x x",
+                          "x  x  x  x   x  x  x  x    x x x x  x x o o";
+
+        write           = "1  0  1  0   1  1  0  0    1 1 1 1  1 1 i i",
+                          "x  x  x  x   x  x  x  x    x x x x  x x x x";
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+    ;
+
+    memory "lfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+      ;
+
+    memory "efuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x   x x x x  x x x i";
+
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   x x x x  x x x o";
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0  0  1  1   1  0  0  0    x x x x  x x x x",
+                          "0  0  0  0   0  0  0  0    o o o o  o o o o";
+    ;
+
+;
+
+
+#------------------------------------------------------------
+# ATtiny461
+#------------------------------------------------------------
+# Close to ATtiny261
+
+part
+    id                  = "t461";
+    desc                = "ATTINY461";
+     has_debugwire = yes;
+     flash_instr   = 0xB4, 0x00, 0x10;
+     eeprom_instr  = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D,
+	             0xBC, 0x00, 0xB4, 0x00, 0xBA, 0x0D, 0xBB, 0xBC,
+	             0x99, 0xE1, 0xBB, 0xAC;
+#    stk500_devcode      = 0x21;
+#    avr910_devcode      = 0x5e;
+    signature           = 0x1e 0x92 0x08;
+    pagel               = 0xb3;
+    bs2                 = 0xb2;
+    chip_erase_delay    = 4000;
+
+    pgm_enable          = "1 0 1 0  1 1 0 0   0 1 0 1  0 0 1 1",
+                          "x x x x  x x x x   x x x x  x x x x";
+
+    chip_erase          = "1 0 1 0  1 1 0 0   1 0 0 x  x x x x",
+                          "x x x x  x x x x   x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 0;
+
+    pp_controlstack     =
+        0xC4, 0xE4, 0xC4, 0xE4, 0xCC, 0xEC, 0xCC, 0xEC,
+        0xD4, 0xF4, 0xD4, 0xF4, 0xDC, 0xFC, 0xDC, 0xFC,
+        0xC8, 0xE8, 0xD8, 0xF8, 0x4C, 0x6C, 0x5C, 0x7C,
+        0xEC, 0xBC, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 2;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    memory "eeprom"
+        paged           = no;
+        size            = 256;
+        page_size       = 4;
+        num_pages       = 64;
+        min_write_delay = 4000;
+        max_write_delay = 4000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+
+        read            = " 1  0  1  0   0  0  0  0    x x x x  x x x x",
+                          "a7 a6 a5 a4  a3 a2 a1 a0    o o o o  o o o o";
+
+        write           = " 1  1  0  0   0  0  0  0    x x x x  x x x x",
+                          "a7 a6 a5 a4  a3 a2 a1 a0    i i i i  i i i i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x   x   x",
+			  " a7  a6  a5  a4     a3  a2   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 10;
+	blocksize	= 4;
+	readsize	= 256;
+    ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 4096;
+        page_size       = 64;
+        num_pages       = 64;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+
+        read_lo         = "  0  0  1  0   0   0  0  0",
+                          "  x  x  x  x   x a10 a9 a8",
+                          " a7 a6 a5 a4  a3  a2 a1 a0",
+                          "  o  o  o  o   o   o  o  o";
+
+        read_hi         = "  0  0  1  0   1   0  0  0",
+                          "  x  x  x  x   x a10 a9 a8",
+                          " a7 a6 a5 a4  a3  a2 a1 a0",
+                          "  o  o  o  o   o   o  o  o";
+
+        loadpage_lo     = "  0  1  0  0   0  0  0  0",
+                          "  x  x  x  x   x  x  x  x",
+                          "  x  x  x a4  a3 a2 a1 a0",
+                          "  i  i  i  i   i  i  i  i";
+
+        loadpage_hi     = "  0  1  0  0   1  0  0  0",
+                          "  x  x  x  x   x  x  x  x",
+                          "  x  x  x a4  a3 a2 a1 a0",
+                          "  i  i  i  i   i  i  i  i";
+
+        writepage       = "  0  1  0  0   1   1  0  0",
+                          "  x  x  x  x   x a10 a9 a8",
+                          " a7 a6 a5  x   x   x  x  x",
+                          "  x  x  x  x   x   x  x  x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 64;
+	readsize	= 256;
+    ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0    x x x x  x x x x",
+                          "0  0  0  0   0  0 a1 a0    o o o o  o o o o";
+    ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0  1  0  1   1  0  0  0    x x x x  x x x x",
+                          "x  x  x  x   x  x  x  x    x x x x  x x o o";
+
+        write           = "1  0  1  0   1  1  0  0    1 1 1 1  1 1 i i",
+                          "x  x  x  x   x  x  x  x    x x x x  x x x x";
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+    ;
+
+    memory "lfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+      ;
+
+    memory "efuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x   x x x x  x x x i";
+
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   x x x x  x x x o";
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0  0  1  1   1  0  0  0    x x x x  x x x x",
+                          "0  0  0  0   0  0  0  0    o o o o  o o o o";
+    ;
+
+;
+
+
+#------------------------------------------------------------
+# ATtiny861
+#------------------------------------------------------------
+# Close to ATtiny461
+
+part
+    id                  = "t861";
+    desc                = "ATTINY861";
+     has_debugwire = yes;
+     flash_instr   = 0xB4, 0x00, 0x10;
+     eeprom_instr  = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D,
+	             0xBC, 0x00, 0xB4, 0x00, 0xBA, 0x0D, 0xBB, 0xBC,
+	             0x99, 0xE1, 0xBB, 0xAC;
+#    stk500_devcode      = 0x21;
+#    avr910_devcode      = 0x5e;
+    signature           = 0x1e 0x93 0x0d;
+    pagel               = 0xb3;
+    bs2                 = 0xb2;
+    chip_erase_delay    = 4000;
+
+    pgm_enable          = "1 0 1 0  1 1 0 0   0 1 0 1  0 0 1 1",
+                          "x x x x  x x x x   x x x x  x x x x";
+
+    chip_erase          = "1 0 1 0  1 1 0 0   1 0 0 x  x x x x",
+                          "x x x x  x x x x   x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 0;
+
+    pp_controlstack     =
+        0xC4, 0xE4, 0xC4, 0xE4, 0xCC, 0xEC, 0xCC, 0xEC,
+        0xD4, 0xF4, 0xD4, 0xF4, 0xDC, 0xFC, 0xDC, 0xFC,
+        0xC8, 0xE8, 0xD8, 0xF8, 0x4C, 0x6C, 0x5C, 0x7C,
+        0xEC, 0xBC, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 2;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    memory "eeprom"
+        paged           = no;
+        size            = 512;
+        num_pages       = 128;
+        page_size       = 4;
+        min_write_delay = 4000;
+        max_write_delay = 4000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+
+        read            = " 1  0  1  0   0  0  0  0    x x x x  x x x a8",
+                          "a7 a6 a5 a4  a3 a2 a1 a0    o o o o  o o o  o";
+
+        write           = " 1  1  0  0   0  0  0  0    x x x x  x x x a8",
+                          "a7 a6 a5 a4  a3 a2 a1 a0    i i i i  i i i  i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x   x  a8",
+			  " a7  a6  a5  a4     a3  a2   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 10;
+	blocksize	= 4;
+	readsize	= 256;
+    ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 8192;
+        page_size       = 64;
+        num_pages       = 128;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+
+        read_lo         = "  0  0  1  0   0   0  0  0",
+                          "  x  x  x  x a11 a10 a9 a8",
+                          " a7 a6 a5 a4  a3  a2 a1 a0",
+                          "  o  o  o  o   o   o  o  o";
+
+        read_hi         = "  0  0  1  0   1   0  0  0",
+                          "  x  x  x  x a11 a10 a9 a8",
+                          " a7 a6 a5 a4  a3  a2 a1 a0",
+                          "  o  o  o  o   o   o  o  o";
+
+        loadpage_lo     = "  0  1  0  0   0  0  0  0",
+                          "  x  x  x  x   x  x  x  x",
+                          "  x  x  x a4  a3 a2 a1 a0",
+                          "  i  i  i  i   i  i  i  i";
+
+        loadpage_hi     = "  0  1  0  0   1  0  0  0",
+                          "  x  x  x  x   x  x  x  x",
+                          "  x  x  x a4  a3 a2 a1 a0",
+                          "  i  i  i  i   i  i  i  i";
+
+        writepage       = "  0  1  0  0   1   1  0  0",
+                          "  x  x  x  x a11 a10 a9 a8",
+                          " a7 a6 a5  x   x   x  x  x",
+                          "  x  x  x  x   x   x  x  x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 64;
+	readsize	= 256;
+    ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0    x x x x  x x x x",
+                          "0  0  0  0   0  0 a1 a0    o o o o  o o o o";
+    ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0  1  0  1   1  0  0  0    x x x x  x x x x",
+                          "x  x  x  x   x  x  x  x    x x x x  x x o o";
+
+        write           = "1  0  1  0   1  1  0  0    1 1 1 1  1 1 i i",
+                          "x  x  x  x   x  x  x  x    x x x x  x x x x";
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+    ;
+
+    memory "lfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+      ;
+
+    memory "efuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x   x x x x  x x x i";
+
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   x x x x  x x x o";
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0  0  1  1   1  0  0  0    x x x x  x x x x",
+                          "0  0  0  0   0  0  0  0    o o o o  o o o o";
+    ;
+
+;
+
+
+#------------------------------------------------------------
+# ATmega48
+#------------------------------------------------------------
+
+part
+    id               = "m48";
+    desc             = "ATMEGA48";
+     has_debugwire = yes;
+     flash_instr   = 0xB6, 0x01, 0x11;
+     eeprom_instr  = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00,
+	             0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF,
+	             0x99, 0xF9, 0xBB, 0xAF;
+    stk500_devcode   = 0x59;
+#    avr910_devcode   = 0x;
+    signature        = 0x1e 0x92 0x05;
+    pagel            = 0xd7;
+    bs2              = 0xc2;
+    chip_erase_delay = 45000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+	0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+	0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+	0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+	0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    resetdelay          = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    memory "eeprom"
+        paged           = no;
+        page_size       = 4;
+        size            = 256;
+        min_write_delay = 3600;
+        max_write_delay = 3600;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+	read            = "  1   0   1   0      0   0   0   0",
+                          "  0   0   0   x      x   x   x   x",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+	write           = "  1   1   0   0      0   0   0   0",
+                          "  0   0   0   x      x   x   x   x",
+                          " a7  a6  a5  a4     a3  a2  a1  a0", 
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x   x   x",
+			  " a7  a6  a5  a4     a3  a2   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 5;
+	blocksize	= 4;
+	readsize	= 256;
+      ;
+    memory "flash"
+        paged           = yes;
+        size            = 4096;
+        page_size       = 64;
+        num_pages       = 64;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0x00;
+        readback_p2     = 0x00;
+        read_lo         = "  0   0   1   0    0   0   0   0",
+                          "  0   0   0   0    0 a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        read_hi         = "  0   0   1   0    1   0   0   0",
+                          "  0   0   0   0    0 a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  0   0   0   x      x   x   x   x",
+                          "  x   x   x  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  0   0   0   x      x   x   x   x",
+                          "  x   x   x  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "  0   0   0   0      0 a10  a9  a8",
+                          " a7  a6  a5   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 64;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+      ;
+
+    memory "efuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   x x x x  x x x o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x   x x x x  x x x i";
+      ;
+
+    memory "lock"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0  0  1  1   1  0  0  0   0  0  0  x   x  x  x  x",
+                          "0  0  0  0   0  0  0  0   o  o  o  o   o  o  o  o";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   0  0  0  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+  ;
+
+
+#------------------------------------------------------------
+# ATmega88
+#------------------------------------------------------------
+
+part
+    id               = "m88";
+    desc             = "ATMEGA88";
+     has_debugwire = yes;
+     flash_instr   = 0xB6, 0x01, 0x11;
+     eeprom_instr  = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00,
+	             0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF,
+	             0x99, 0xF9, 0xBB, 0xAF;
+    stk500_devcode   = 0x73;
+#    avr910_devcode   = 0x;
+    signature        = 0x1e 0x93 0x0a;
+    pagel            = 0xd7;
+    bs2              = 0xc2;
+    chip_erase_delay = 9000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+	0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+	0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+	0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+	0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    resetdelay          = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    memory "eeprom"
+        paged           = no;
+        page_size       = 4;
+        size            = 512;
+        min_write_delay = 3600;
+        max_write_delay = 3600;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+	read            = "  1   0   1   0      0   0   0   0",
+                          "  0   0   0   x      x   x   x  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+	write           = "  1   1   0   0      0   0   0   0",
+                          "  0   0   0   x      x   x   x  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0", 
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x   x  a8",
+			  " a7  a6  a5  a4     a3  a2   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 5;
+	blocksize	= 4;
+	readsize	= 256;
+      ;
+    memory "flash"
+        paged           = yes;
+        size            = 8192;
+        page_size       = 64;
+        num_pages       = 128;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0    0   0   0   0",
+                          "  0   0   0   0  a11 a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        read_hi         = "  0   0   1   0    1   0   0   0",
+                          "  0   0   0   0  a11 a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  0   0   0   x      x   x   x   x",
+                          "  x   x   x  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  0   0   0   x      x   x   x   x",
+                          "  x   x   x  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "  0   0   0   0    a11 a10  a9  a8",
+                          " a7  a6  a5   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 64;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+      ;
+
+    memory "efuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   x x x x  x o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x   x x x x  x i i i";
+      ;
+
+    memory "lock"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0  0  1  1   1  0  0  0   0  0  0  x   x  x  x  x",
+                          "0  0  0  0   0  0  0  0   o  o  o  o   o  o  o  o";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   0  0  0  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+  ;
+
+#------------------------------------------------------------
+# ATmega168
+#------------------------------------------------------------
+
+part
+    id              = "m168";
+    desc            = "ATMEGA168";
+     has_debugwire = yes;
+     flash_instr   = 0xB6, 0x01, 0x11;
+     eeprom_instr  = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00,
+	             0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF,
+	             0x99, 0xF9, 0xBB, 0xAF;
+    stk500_devcode  = 0x86;
+    # avr910_devcode = 0x;
+    signature       = 0x1e 0x94 0x06;
+    pagel           = 0xd7;
+    bs2             = 0xc2;
+    chip_erase_delay = 9000;
+    pgm_enable       = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1",
+                       "x x x x x x x x x x x x x x x x";
+
+    chip_erase       = "1 0 1 0 1 1 0 0 1 0 0 x x x x x",
+                       "x x x x x x x x x x x x x x x x";
+
+    timeout         = 200;
+    stabdelay       = 100;
+    cmdexedelay     = 25;
+    synchloops      = 32;
+    bytedelay       = 0;
+    pollindex       = 3;
+    pollvalue       = 0x53;
+    predelay        = 1;
+    postdelay       = 1;
+    pollmethod      = 1;
+
+    pp_controlstack     =
+	0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+	0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+	0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+	0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    resetdelay          = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    memory "eeprom"
+        paged           = no;
+        page_size       = 4;
+        size            = 512;
+        min_write_delay = 3600;
+        max_write_delay = 3600;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read            = " 1 0 1 0 0 0 0 0",
+                          " 0 0 0 x x x x a8",
+                          " a7 a6 a5 a4 a3 a2 a1 a0",
+                          " o o o o o o o o";
+    
+        write           = " 1 1 0 0 0 0 0 0",
+                          " 0 0 0 x x x x a8",
+                          " a7 a6 a5 a4 a3 a2 a1 a0",
+                          " i i i i i i i i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x   x  a8",
+			  " a7  a6  a5  a4     a3  a2   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 5;
+	blocksize	= 4;
+	readsize	= 256;
+        ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 16384;
+        page_size       = 128;
+        num_pages       = 128;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = " 0 0 1 0 0 0 0 0",
+                          " 0 0 0 a12 a11 a10 a9 a8",
+                          " a7 a6 a5 a4 a3 a2 a1 a0",
+                          " o o o o o o o o";
+        
+        read_hi          = " 0 0 1 0 1 0 0 0",
+                           " 0 0 0 a12 a11 a10 a9 a8",
+                           " a7 a6 a5 a4 a3 a2 a1 a0",
+                           " o o o o o o o o";
+        
+        loadpage_lo     = " 0 1 0 0 0 0 0 0",
+                          " 0 0 0 x x x x x",
+                          " x x a5 a4 a3 a2 a1 a0",
+                          " i i i i i i i i";
+        
+        loadpage_hi     = " 0 1 0 0 1 0 0 0",
+                          " 0 0 0 x x x x x",
+                          " x x a5 a4 a3 a2 a1 a0",
+                          " i i i i i i i i";
+        
+        writepage       = " 0 1 0 0 1 1 0 0",
+                          " 0 0 0 a12 a11 a10 a9 a8",
+                          " a7 a6 x x x x x x",
+                          " x x x x x x x x";
+
+        mode        = 0x41;
+        delay       = 6;
+        blocksize   = 128;
+        readsize    = 256;
+
+        ;
+        
+    memory "lfuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0",
+                          "x x x x x x x x o o o o o o o o";
+        
+        write           = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0",
+                          "x x x x x x x x i i i i i i i i";
+        ;
+    
+    memory "hfuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0",
+                          "x x x x x x x x o o o o o o o o";
+        
+        write           = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0",
+                          "x x x x x x x x i i i i i i i i";
+        ;
+    
+    memory "efuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0",
+                          "x x x x x x x x x x x x x o o o";
+        
+        write           = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0",
+                          "x x x x x x x x x x x x x i i i";
+        ;
+    
+    memory "lock"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0",
+                          "x x x x x x x x x x o o o o o o";
+        
+        write           = "1 0 1 0 1 1 0 0 1 1 1 x x x x x",
+                          "x x x x x x x x 1 1 i i i i i i";
+        ;
+    
+    memory "calibration"
+        size            = 1;
+        read            = "0 0 1 1 1 0 0 0 0 0 0 x x x x x",
+                          "0 0 0 0 0 0 0 0 o o o o o o o o";
+        ;
+    
+    memory "signature"
+        size            = 3;
+        read            = "0 0 1 1 0 0 0 0 0 0 0 x x x x x",
+                          "x x x x x x a1 a0 o o o o o o o o";
+        ;
+;
+
+#------------------------------------------------------------
+# ATtiny88
+#------------------------------------------------------------
+
+part
+    id               = "t88";
+    desc             = "attiny88";
+     has_debugwire = yes;
+     flash_instr   = 0xB6, 0x01, 0x11;
+     eeprom_instr  = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00,
+	             0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF,
+	             0x99, 0xF9, 0xBB, 0xAF;
+    stk500_devcode   = 0x73;
+#    avr910_devcode   = 0x;
+    signature        = 0x1e 0x93 0x11;
+    pagel            = 0xd7;
+    bs2              = 0xc2;
+    chip_erase_delay = 9000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+	0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+	0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+	0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+	0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    resetdelay          = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    memory "eeprom"
+        paged           = no;
+        page_size       = 4;
+        size            = 64;
+        min_write_delay = 3600;
+        max_write_delay = 3600;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+	read            = "  1   0   1   0      0   0   0   0",
+                          "  0   0   0   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+	write           = "  1   1   0   0      0   0   0   0",
+                          "  0   0   0   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x   x   x",
+			  "  x  a6  a5  a4     a3  a2   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 5;
+	blocksize	= 4;
+	readsize	= 64;
+      ;
+    memory "flash"
+        paged           = yes;
+        size            = 8192;
+        page_size       = 64;
+        num_pages       = 128;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0    0   0   0   0",
+                          "  0   0   0   0  a11 a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        read_hi         = "  0   0   1   0    1   0   0   0",
+                          "  0   0   0   0  a11 a10  a9  a8",
+                          " a7  a6  a5  a4   a3  a2  a1  a0",
+                          "  o   o   o   o    o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  0   0   0   x      x   x   x   x",
+                          "  x   x   x  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  0   0   0   x      x   x   x   x",
+                          "  x   x   x  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "  0   0   0   0    a11 a10  a9  a8",
+                          " a7  a6  a5   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 64;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x   i i i i  i i i i";
+      ;
+
+    memory "efuse"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x   x x x x  x o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x   x x x x  x x x i";
+      ;
+
+    memory "lock"
+        size            = 1;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0  0  1  1   1  0  0  0   0  0  0  x   x  x  x  x",
+                          "0  0  0  0   0  0  0  0   o  o  o  o   o  o  o  o";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   0  0  0  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+  ;
+
+#------------------------------------------------------------
+# ATmega328P
+#------------------------------------------------------------
+
+part
+    id			= "m328p";
+    desc		= "ATMEGA328P";
+    has_debugwire	= yes;
+    flash_instr		= 0xB6, 0x01, 0x11;
+    eeprom_instr	= 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00,
+			  0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF,
+			  0x99, 0xF9, 0xBB, 0xAF;
+    stk500_devcode	= 0x86;
+    # avr910_devcode	= 0x;
+    signature		= 0x1e 0x95 0x0F;
+    pagel		= 0xd7;
+    bs2			= 0xc2;
+    chip_erase_delay	= 9000;
+    pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1",
+		 "x x x x x x x x x x x x x x x x";
+
+    chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x",
+		 "x x x x x x x x x x x x x x x x";
+
+    timeout	= 200;
+    stabdelay	= 100;
+    cmdexedelay	= 25;
+    synchloops	= 32;
+    bytedelay	= 0;
+    pollindex	= 3;
+    pollvalue	= 0x53;
+    predelay	= 1;
+    postdelay	= 1;
+    pollmethod	= 1;
+
+    pp_controlstack =
+	0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+	0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+	0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+	0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay	= 100;
+    progmodedelay	= 0;
+    latchcycles		= 5;
+    togglevtg		= 1;
+    poweroffdelay	= 15;
+    resetdelayms	= 1;
+    resetdelayus	= 0;
+    hvleavestabdelay	= 15;
+    resetdelay		= 15;
+    chiperasepulsewidth	= 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    memory "eeprom"
+	paged		= no;
+	page_size	= 4;
+	size		= 1024;
+	min_write_delay = 3600;
+	max_write_delay = 3600;
+	readback_p1	= 0xff;
+	readback_p2	= 0xff;
+	read = " 1 0 1 0 0 0 0 0",
+	       " 0 0 0 x x x a9 a8",
+	       " a7 a6 a5 a4 a3 a2 a1 a0",
+	       " o o o o o o o o";
+
+	write = " 1 1 0 0 0 0 0 0",
+	      	" 0 0 0 x x x a9 a8",
+		" a7 a6 a5 a4 a3 a2 a1 a0",
+		" i i i i i i i i";
+
+	loadpage_lo = " 1 1 0 0 0 0 0 1",
+		      " 0 0 0 0 0 0 0 0",
+		      " 0 0 0 0 0 0 a1 a0",
+		      " i i i i i i i i";
+
+	writepage = " 1 1 0 0 0 0 1 0",
+		    " 0 0 x x x x a9 a8",
+		    " a7 a6 a5 a4 a3 a2 0 0",
+		    " x x x x x x x x";
+
+	mode		= 0x41;
+	delay		= 5;
+	blocksize	= 4;
+	readsize	= 256;
+    ;
+
+    memory "flash"
+	paged		= yes;
+	size		= 32768;
+	page_size	= 128;
+	num_pages	= 256;
+	min_write_delay = 4500;
+	max_write_delay = 4500;
+	readback_p1	= 0xff;
+	readback_p2	= 0xff;
+	read_lo = " 0 0 1 0 0 0 0 0",
+		  " 0 0 a13 a12 a11 a10 a9 a8",
+		  " a7 a6 a5 a4 a3 a2 a1 a0",
+		  " o o o o o o o o";
+
+	read_hi = " 0 0 1 0 1 0 0 0",
+		  " 0 0 a13 a12 a11 a10 a9 a8",
+		  " a7 a6 a5 a4 a3 a2 a1 a0",
+		  " o o o o o o o o";
+
+	loadpage_lo = " 0 1 0 0 0 0 0 0",
+		      " 0 0 0 x x x x x",
+		      " x x a5 a4 a3 a2 a1 a0",
+		      " i i i i i i i i";
+
+	loadpage_hi = " 0 1 0 0 1 0 0 0",
+		      " 0 0 0 x x x x x",
+		      " x x a5 a4 a3 a2 a1 a0",
+		      " i i i i i i i i";
+
+	writepage = " 0 1 0 0 1 1 0 0",
+		    " 0 0 a13 a12 a11 a10 a9 a8",
+		    " a7 a6 x x x x x x",
+		    " x x x x x x x x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 128;
+	readsize	= 256;
+
+    ;
+
+    memory "lfuse"
+	size = 1;
+	min_write_delay = 4500;
+	max_write_delay = 4500;
+	read = "0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0",
+	       "x x x x x x x x o o o o o o o o";
+
+	write = "1 0 1 0 1 1 0 0 1 0 1 0 0 0 0 0",
+	      	"x x x x x x x x i i i i i i i i";
+    ;
+
+    memory "hfuse"
+	size = 1;
+	min_write_delay = 4500;
+	max_write_delay = 4500;
+	read = "0 1 0 1 1 0 0 0 0 0 0 0 1 0 0 0",
+	       "x x x x x x x x o o o o o o o o";
+
+	write = "1 0 1 0 1 1 0 0 1 0 1 0 1 0 0 0",
+	      	"x x x x x x x x i i i i i i i i";
+    ;
+
+    memory "efuse"
+	size = 1;
+	min_write_delay = 4500;
+	max_write_delay = 4500;
+	read = "0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0",
+	       "x x x x x x x x x x x x x o o o";
+
+	write = "1 0 1 0 1 1 0 0 1 0 1 0 0 1 0 0",
+	      	"x x x x x x x x x x x x x i i i";
+    ;
+
+    memory "lock"
+	size = 1;
+	min_write_delay = 4500;
+	max_write_delay = 4500;
+	read = "0 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0",
+	       "x x x x x x x x x x o o o o o o";
+
+	write = "1 0 1 0 1 1 0 0 1 1 1 x x x x x",
+	      	"x x x x x x x x 1 1 i i i i i i";
+    ;
+
+    memory "calibration"
+	size = 1;
+	read = "0 0 1 1 1 0 0 0 0 0 0 x x x x x",
+	       "0 0 0 0 0 0 0 0 o o o o o o o o";
+    ;
+
+    memory "signature"
+	size = 3;
+	read = "0 0 1 1 0 0 0 0 0 0 0 x x x x x",
+	       "x x x x x x a1 a0 o o o o o o o o";
+    ;
+;
+
+#------------------------------------------------------------
+# ATtiny2313
+#------------------------------------------------------------
+
+part
+     id            = "t2313";
+     desc          = "ATtiny2313";
+     has_debugwire = yes;
+     flash_instr   = 0xB2, 0x0F, 0x1F;
+     eeprom_instr  = 0xBB, 0xFE, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D,
+	             0xBA, 0x0F, 0xB2, 0x0F, 0xBA, 0x0D, 0xBB, 0xBC,
+	             0x99, 0xE1, 0xBB, 0xAC;
+     stk500_devcode   = 0x23;
+##   Use the ATtiny26 devcode:
+     avr910_devcode   = 0x5e;
+     signature        = 0x1e 0x91 0x0a;
+     pagel            = 0xD4;
+     bs2              = 0xD6;
+     reset            = io;
+     chip_erase_delay = 9000;
+
+     pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                        "x x x x  x x x x    x x x x  x x x x";
+
+     chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                        "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0E, 0x1E, 0x2E, 0x3E, 0x2E, 0x3E,
+        0x4E, 0x5E, 0x4E, 0x5E, 0x6E, 0x7E, 0x6E, 0x7E,
+        0x26, 0x36, 0x66, 0x76, 0x2A, 0x3A, 0x6A, 0x7A,
+        0x2E, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+     memory "eeprom"
+         size            = 128;
+        paged           = no;
+        page_size       = 4;
+         min_write_delay = 4000;
+         max_write_delay = 4500;
+         readback_p1     = 0xff;
+         readback_p2     = 0xff;
+         read            = "1  0  1  0   0  0  0  0   0 0 0 x  x x x x",
+                           "x a6 a5 a4  a3 a2 a1 a0   o o o o  o o o o";
+
+         write           = "1  1  0  0   0  0  0  0   0 0 0 x  x x x x",
+                           "x a6 a5 a4  a3 a2 a1 a0   i i i i  i i i i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x   x   x",
+			  "  x  a6  a5  a4     a3  a2   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 4;
+	readsize	= 256;
+       ;
+     memory "flash"
+         paged           = yes;
+         size            = 2048;
+         page_size       = 32;
+         num_pages       = 64;
+         min_write_delay = 4500;
+         max_write_delay = 4500;
+         readback_p1     = 0xff;
+         readback_p2     = 0xff;
+         read_lo         = "  0   0   1   0    0   0   0   0",
+                           "  0   0   0   0    0   0  a9  a8",
+                           " a7  a6  a5  a4   a3  a2  a1  a0",
+                           "  o   o   o   o    o   o   o   o";
+
+         read_hi         = "  0   0   1   0    1   0   0   0",
+                           "  0   0   0   0    0   0  a9  a8",
+                           " a7  a6  a5  a4   a3  a2  a1  a0",
+                           "  o   o   o   o    o   o   o   o";
+
+# The information in the data sheet of April/2004 is wrong, this works:
+         loadpage_lo     = "  0   1   0   0    0   0   0   0",
+                           "  0   0   0   x    x   x   x   x",
+                           "  x   x   x   x   a3  a2  a1  a0",
+                           "  i   i   i   i    i   i   i   i";
+
+# The information in the data sheet of April/2004 is wrong, this works:
+         loadpage_hi     = "  0   1   0   0    1   0   0   0",
+                           "  0   0   0   x    x   x   x   x",
+                           "  x   x   x   x   a3  a2  a1  a0",
+                           "  i   i   i   i    i   i   i   i";
+
+# The information in the data sheet of April/2004 is wrong, this works:
+         writepage       = "  0  1  0  0   1  1  0  0",
+                           "  0  0  0  0   0  0 a9 a8",
+                           " a7 a6 a5 a4   x  x  x  x",
+                           "  x  x  x  x   x  x  x  x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 32;
+	readsize	= 256;
+       ;
+#   ATtiny2313 has Signature Bytes: 0x1E 0x91 0x0A.
+     memory "signature"
+         size            = 3;
+         read            = "0  0  1  1   0  0  0  0   0  0  0  x   x  x  x  x",
+                           "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+       ;
+     memory "lock"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 1 1 x  x x x x",
+                           "x x x x  x x x x  1 1 i i  i i i i";
+         read           = "0 1 0 1  1 0 0 0  0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x  x x o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "lfuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                           "x x x x  x x x x  i i i i  i i i i";
+
+         read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "hfuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                           "x x x x  x x x x  i i i i  i i i i";
+
+         read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "efuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                           "x x x x  x x x x  x x x x  x x x i";
+
+         read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+     ;
+# The Tiny2313 has calibration data for both 4 MHz and 8 MHz.
+# The information in the data sheet of April/2004 is wrong, this works:
+
+     memory "calibration"
+         size            = 2;
+         read            = "0  0  1  1   1  0  0  0    0 0 0 x  x x x x",
+                           "0  0  0  0   0  0  0  a0   o o o o  o o o o";
+     ;
+  ;
+
+#------------------------------------------------------------
+# AT90PWM2
+#------------------------------------------------------------
+
+part
+     id            = "pwm2";
+     desc          = "AT90PWM2";
+     has_debugwire = yes;
+     flash_instr   = 0xB6, 0x01, 0x11;
+     eeprom_instr  = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00,
+	             0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF,
+	             0x99, 0xF9, 0xBB, 0xAF;
+     stk500_devcode   = 0x65;
+##  avr910_devcode   = ?;
+     signature        = 0x1e 0x93 0x81;
+     pagel            = 0xD8;
+     bs2              = 0xE2;
+     reset            = io;
+     chip_erase_delay = 9000;
+
+     pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                        "x x x x  x x x x    x x x x  x x x x";
+
+     chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                        "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+     memory "eeprom"
+         size            = 512;
+        paged           = no;
+        page_size       = 4;
+         min_write_delay = 4000;
+         max_write_delay = 4500;
+         readback_p1     = 0xff;
+         readback_p2     = 0xff;
+         read            = "1  0  1  0   0  0  0  0   0 0 0 x  x x x a8",
+                           "a7 a6 a5 a4  a3 a2 a1 a0  o o o o  o o o o";
+
+         write           = "1  1  0  0   0  0  0  0   0 0 0 x  x x x a8",
+                           "a7 a6 a5 a4  a3 a2 a1 a0  i i i i  i i i i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x   x   x",
+			  " a7  a6  a5  a4     a3  a2   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 4;
+	readsize	= 256;
+       ;
+     memory "flash"
+         paged           = yes;
+         size            = 8192;
+         page_size       = 64;
+         num_pages       = 128;
+         min_write_delay = 4500;
+         max_write_delay = 4500;
+         readback_p1     = 0xff;
+         readback_p2     = 0xff;
+         read_lo         = "  0   0   1   0    0   0   0   0",
+                           "  0   0   0   0   a11 a10 a9  a8",
+                           " a7  a6  a5  a4   a3  a2  a1  a0",
+                           "  o   o   o   o    o   o   o   o";
+
+         read_hi         = "  0   0   1   0    1   0   0   0",
+                           "  0   0   0   0   a11 a10 a9  a8",
+                           " a7  a6  a5  a4   a3  a2  a1  a0",
+                           "  o   o   o   o    o   o   o   o";
+
+         loadpage_lo     = "  0   1   0   0    0   0   0   0",
+                           "  0   0   0   x    x   x   x   x",
+                           "  x   x   x  a4   a3  a2  a1  a0",
+                           "  i   i   i   i    i   i   i   i";
+
+         loadpage_hi     = "  0   1   0   0    1   0   0   0",
+                           "  0   0   0   x    x   x   x   x",
+                           "  x   x   x  a4   a3  a2  a1  a0",
+                           "  i   i   i   i    i   i   i   i";
+
+         writepage       = "  0  1  0  0   1   1   0   0",
+                           "  0  0  0  0   a11 a10 a9  a8",
+                           " a7 a6 a5  x   x   x   x   x",
+                           "  x  x  x  x   x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 64;
+	readsize	= 256;
+       ;
+#   AT90PWM2 has Signature Bytes: 0x1E 0x93 0x81.
+     memory "signature"
+         size            = 3;
+         read            = "0  0  1  1   0  0  0  0   0  0  x  x   x  x  x  x",
+                           "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+       ;
+     memory "lock"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 1 1 x  x x x x",
+                           "x x x x  x x x x  1 1 i i  i i i i";
+
+         read            = "0 1 0 1  1 0 0 0  0 0 0 0  0 0 0 0",
+                           "x x x x  x x x x  x x o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "lfuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                           "x x x x  x x x x  i i i i  i i i i";
+
+         read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "hfuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                           "x x x x  x x x x  i i i i  i i i i";
+
+         read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "efuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                           "x x x x  x x x x  x x x x  x x x i";
+
+         read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+     ;
+
+     memory "calibration"
+         size            = 1;
+         read            = "0  0  1  1   1  0  0  0    0 0 0 x  x x x x",
+                           "0  0  0  0   0  0  0  0    o o o o  o o o o";
+     ;
+  ;
+
+#------------------------------------------------------------
+# AT90PWM3
+#------------------------------------------------------------
+
+# Completely identical to AT90PWM2 (including the signature!)
+
+part
+     id            = "pwm3";
+     desc          = "AT90PWM3";
+     has_debugwire = yes;
+     flash_instr   = 0xB6, 0x01, 0x11;
+     eeprom_instr  = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00,
+	             0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF,
+	             0x99, 0xF9, 0xBB, 0xAF;
+     stk500_devcode   = 0x65;
+##  avr910_devcode   = ?;
+     signature        = 0x1e 0x93 0x81;
+     pagel            = 0xD8;
+     bs2              = 0xE2;
+     reset            = io;
+     chip_erase_delay = 9000;
+
+     pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                        "x x x x  x x x x    x x x x  x x x x";
+
+     chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                        "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+     memory "eeprom"
+         size            = 512;
+        paged           = no;
+        page_size       = 4;
+         min_write_delay = 4000;
+         max_write_delay = 4500;
+         readback_p1     = 0xff;
+         readback_p2     = 0xff;
+         read            = "1  0  1  0   0  0  0  0   0 0 0 x  x x x a8",
+                           "a7 a6 a5 a4  a3 a2 a1 a0  o o o o  o o o o";
+
+         write           = "1  1  0  0   0  0  0  0   0 0 0 x  x x x a8",
+                           "a7 a6 a5 a4  a3 a2 a1 a0  i i i i  i i i i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x   x   x",
+			  " a7  a6  a5  a4     a3  a2   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 4;
+	readsize	= 256;
+       ;
+     memory "flash"
+         paged           = yes;
+         size            = 8192;
+         page_size       = 64;
+         num_pages       = 128;
+         min_write_delay = 4500;
+         max_write_delay = 4500;
+         readback_p1     = 0xff;
+         readback_p2     = 0xff;
+         read_lo         = "  0   0   1   0    0   0   0   0",
+                           "  0   0   0   0   a11 a10 a9  a8",
+                           " a7  a6  a5  a4   a3  a2  a1  a0",
+                           "  o   o   o   o    o   o   o   o";
+
+         read_hi         = "  0   0   1   0    1   0   0   0",
+                           "  0   0   0   0   a11 a10 a9  a8",
+                           " a7  a6  a5  a4   a3  a2  a1  a0",
+                           "  o   o   o   o    o   o   o   o";
+
+         loadpage_lo     = "  0   1   0   0    0   0   0   0",
+                           "  0   0   0   x    x   x   x   x",
+                           "  x   x   x  a4   a3  a2  a1  a0",
+                           "  i   i   i   i    i   i   i   i";
+
+         loadpage_hi     = "  0   1   0   0    1   0   0   0",
+                           "  0   0   0   x    x   x   x   x",
+                           "  x   x   x  a4   a3  a2  a1  a0",
+                           "  i   i   i   i    i   i   i   i";
+
+         writepage       = "  0  1  0  0   1   1   0   0",
+                           "  0  0  0  0   a11 a10 a9  a8",
+                           " a7 a6 a5  x   x   x   x   x",
+                           "  x  x  x  x   x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 64;
+	readsize	= 256;
+       ;
+#   AT90PWM2 has Signature Bytes: 0x1E 0x93 0x81.
+     memory "signature"
+         size            = 3;
+         read            = "0  0  1  1   0  0  0  0   0  0  x  x   x  x  x  x",
+                           "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+       ;
+     memory "lock"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 1 1 x  x x x x",
+                           "x x x x  x x x x  1 1 i i  i i i i";
+
+         read            = "0 1 0 1  1 0 0 0  0 0 0 0  0 0 0 0",
+                           "x x x x  x x x x  x x o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "lfuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                           "x x x x  x x x x  i i i i  i i i i";
+
+         read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "hfuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                           "x x x x  x x x x  i i i i  i i i i";
+
+         read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "efuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                           "x x x x  x x x x  x x x x  x x x i";
+
+         read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+     ;
+
+     memory "calibration"
+         size            = 1;
+         read            = "0  0  1  1   1  0  0  0    0 0 0 x  x x x x",
+                           "0  0  0  0   0  0  0  0    o o o o  o o o o";
+     ;
+  ;
+
+#------------------------------------------------------------
+# AT90PWM2B
+#------------------------------------------------------------
+# Same as AT90PWM2 but different signature.
+
+part
+     id            = "pwm2b";
+     desc          = "AT90PWM2B";
+     has_debugwire = yes;
+     flash_instr   = 0xB6, 0x01, 0x11;
+     eeprom_instr  = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00,
+	             0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF,
+	             0x99, 0xF9, 0xBB, 0xAF;
+     stk500_devcode   = 0x65;
+##  avr910_devcode   = ?;
+     signature        = 0x1e 0x93 0x83;
+     pagel            = 0xD8;
+     bs2              = 0xE2;
+     reset            = io;
+     chip_erase_delay = 9000;
+
+     pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                        "x x x x  x x x x    x x x x  x x x x";
+
+     chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                        "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+     memory "eeprom"
+         size            = 512;
+        paged           = no;
+        page_size       = 4;
+         min_write_delay = 4000;
+         max_write_delay = 4500;
+         readback_p1     = 0xff;
+         readback_p2     = 0xff;
+         read            = "1  0  1  0   0  0  0  0   0 0 0 x  x x x a8",
+                           "a7 a6 a5 a4  a3 a2 a1 a0  o o o o  o o o o";
+
+         write           = "1  1  0  0   0  0  0  0   0 0 0 x  x x x a8",
+                           "a7 a6 a5 a4  a3 a2 a1 a0  i i i i  i i i i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x   x   x",
+			  " a7  a6  a5  a4     a3  a2   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 4;
+	readsize	= 256;
+       ;
+     memory "flash"
+         paged           = yes;
+         size            = 8192;
+         page_size       = 64;
+         num_pages       = 128;
+         min_write_delay = 4500;
+         max_write_delay = 4500;
+         readback_p1     = 0xff;
+         readback_p2     = 0xff;
+         read_lo         = "  0   0   1   0    0   0   0   0",
+                           "  0   0   0   0   a11 a10 a9  a8",
+                           " a7  a6  a5  a4   a3  a2  a1  a0",
+                           "  o   o   o   o    o   o   o   o";
+
+         read_hi         = "  0   0   1   0    1   0   0   0",
+                           "  0   0   0   0   a11 a10 a9  a8",
+                           " a7  a6  a5  a4   a3  a2  a1  a0",
+                           "  o   o   o   o    o   o   o   o";
+
+         loadpage_lo     = "  0   1   0   0    0   0   0   0",
+                           "  0   0   0   x    x   x   x   x",
+                           "  x   x   x  a4   a3  a2  a1  a0",
+                           "  i   i   i   i    i   i   i   i";
+
+         loadpage_hi     = "  0   1   0   0    1   0   0   0",
+                           "  0   0   0   x    x   x   x   x",
+                           "  x   x   x  a4   a3  a2  a1  a0",
+                           "  i   i   i   i    i   i   i   i";
+
+         writepage       = "  0  1  0  0   1   1   0   0",
+                           "  0  0  0  0   a11 a10 a9  a8",
+                           " a7 a6 a5  x   x   x   x   x",
+                           "  x  x  x  x   x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 64;
+	readsize	= 256;
+       ;
+     memory "signature"
+         size            = 3;
+         read            = "0  0  1  1   0  0  0  0   0  0  x  x   x  x  x  x",
+                           "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+       ;
+     memory "lock"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 1 1 x  x x x x",
+                           "x x x x  x x x x  1 1 i i  i i i i";
+
+         read            = "0 1 0 1  1 0 0 0  0 0 0 0  0 0 0 0",
+                           "x x x x  x x x x  x x o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "lfuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                           "x x x x  x x x x  i i i i  i i i i";
+
+         read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "hfuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                           "x x x x  x x x x  i i i i  i i i i";
+
+         read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "efuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                           "x x x x  x x x x  x x x x  x x x i";
+
+         read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+     ;
+
+     memory "calibration"
+         size            = 1;
+         read            = "0  0  1  1   1  0  0  0    0 0 0 x  x x x x",
+                           "0  0  0  0   0  0  0  0    o o o o  o o o o";
+     ;
+  ;
+
+#------------------------------------------------------------
+# AT90PWM3B
+#------------------------------------------------------------
+
+# Completely identical to AT90PWM2B (including the signature!)
+
+part
+     id            = "pwm3b";
+     desc          = "AT90PWM3B";
+     has_debugwire = yes;
+     flash_instr   = 0xB6, 0x01, 0x11;
+     eeprom_instr  = 0xBD, 0xF2, 0xBD, 0xE1, 0xBB, 0xCF, 0xB4, 0x00,
+	             0xBE, 0x01, 0xB6, 0x01, 0xBC, 0x00, 0xBB, 0xBF,
+	             0x99, 0xF9, 0xBB, 0xAF;
+     stk500_devcode   = 0x65;
+##  avr910_devcode   = ?;
+     signature        = 0x1e 0x93 0x83;
+     pagel            = 0xD8;
+     bs2              = 0xE2;
+     reset            = io;
+     chip_erase_delay = 9000;
+
+     pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                        "x x x x  x x x x    x x x x  x x x x";
+
+     chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                        "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+     memory "eeprom"
+         size            = 512;
+        paged           = no;
+        page_size       = 4;
+         min_write_delay = 4000;
+         max_write_delay = 4500;
+         readback_p1     = 0xff;
+         readback_p2     = 0xff;
+         read            = "1  0  1  0   0  0  0  0   0 0 0 x  x x x a8",
+                           "a7 a6 a5 a4  a3 a2 a1 a0  o o o o  o o o o";
+
+         write           = "1  1  0  0   0  0  0  0   0 0 0 x  x x x a8",
+                           "a7 a6 a5 a4  a3 a2 a1 a0  i i i i  i i i i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x   x   x",
+			  " a7  a6  a5  a4     a3  a2   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 4;
+	readsize	= 256;
+       ;
+     memory "flash"
+         paged           = yes;
+         size            = 8192;
+         page_size       = 64;
+         num_pages       = 128;
+         min_write_delay = 4500;
+         max_write_delay = 4500;
+         readback_p1     = 0xff;
+         readback_p2     = 0xff;
+         read_lo         = "  0   0   1   0    0   0   0   0",
+                           "  0   0   0   0   a11 a10 a9  a8",
+                           " a7  a6  a5  a4   a3  a2  a1  a0",
+                           "  o   o   o   o    o   o   o   o";
+
+         read_hi         = "  0   0   1   0    1   0   0   0",
+                           "  0   0   0   0   a11 a10 a9  a8",
+                           " a7  a6  a5  a4   a3  a2  a1  a0",
+                           "  o   o   o   o    o   o   o   o";
+
+         loadpage_lo     = "  0   1   0   0    0   0   0   0",
+                           "  0   0   0   x    x   x   x   x",
+                           "  x   x   x  a4   a3  a2  a1  a0",
+                           "  i   i   i   i    i   i   i   i";
+
+         loadpage_hi     = "  0   1   0   0    1   0   0   0",
+                           "  0   0   0   x    x   x   x   x",
+                           "  x   x   x  a4   a3  a2  a1  a0",
+                           "  i   i   i   i    i   i   i   i";
+
+         writepage       = "  0  1  0  0   1   1   0   0",
+                           "  0  0  0  0   a11 a10 a9  a8",
+                           " a7 a6 a5  x   x   x   x   x",
+                           "  x  x  x  x   x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 64;
+	readsize	= 256;
+       ;
+     memory "signature"
+         size            = 3;
+         read            = "0  0  1  1   0  0  0  0   0  0  x  x   x  x  x  x",
+                           "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+       ;
+     memory "lock"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 1 1 x  x x x x",
+                           "x x x x  x x x x  1 1 i i  i i i i";
+
+         read            = "0 1 0 1  1 0 0 0  0 0 0 0  0 0 0 0",
+                           "x x x x  x x x x  x x o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "lfuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                           "x x x x  x x x x  i i i i  i i i i";
+
+         read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "hfuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                           "x x x x  x x x x  i i i i  i i i i";
+
+         read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "efuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                           "x x x x  x x x x  x x x x  x x x i";
+
+         read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+     ;
+
+     memory "calibration"
+         size            = 1;
+         read            = "0  0  1  1   1  0  0  0    0 0 0 x  x x x x",
+                           "0  0  0  0   0  0  0  0    o o o o  o o o o";
+     ;
+  ;
+
+#------------------------------------------------------------
+# ATtiny25
+#------------------------------------------------------------
+
+part
+     id            = "t25";
+     desc          = "ATtiny25";
+     has_debugwire = yes;
+     flash_instr   = 0xB4, 0x02, 0x12;
+     eeprom_instr  = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D,
+	             0xBC, 0x02, 0xB4, 0x02, 0xBA, 0x0D, 0xBB, 0xBC,
+	             0x99, 0xE1, 0xBB, 0xAC;
+## no STK500 devcode in XML file, use the ATtiny45 one
+     stk500_devcode   = 0x14;
+##  avr910_devcode   = ?;
+##  Try the AT90S2313 devcode:
+     avr910_devcode   = 0x20;
+     signature        = 0x1e 0x91 0x08;
+     reset            = io;
+     chip_erase_delay = 4500;
+
+     pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                        "x x x x  x x x x    x x x x  x x x x";
+
+     chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                        "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    hvsp_controlstack   =
+        0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66,
+        0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78,
+        0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10,
+        0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00;
+    hventerstabdelay    = 100;
+    hvspcmdexedelay     = 0;
+    synchcycles         = 6;
+    latchcycles         = 1;
+    togglevtg           = 1;
+    poweroffdelay       = 25;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 100;
+    resetdelay          = 25;
+    chiperasepolltimeout = 40;
+    chiperasetime       = 0;
+    programfusepolltimeout = 25;
+    programlockpolltimeout = 25;
+
+     memory "eeprom"
+         size            = 128;
+        paged           = no;
+        page_size       = 4;
+         min_write_delay = 4000;
+         max_write_delay = 4500;
+         readback_p1     = 0xff;
+         readback_p2     = 0xff;
+         read            = "1  0  1  0   0  0  0  0   0 0 0 x  x x x x",
+                           "x a6 a5 a4  a3 a2 a1 a0   o o o o  o o o o";
+
+         write           = "1  1  0  0   0  0  0  0   0 0 0 x  x x x x",
+                           "x a6 a5 a4  a3 a2 a1 a0   i i i i  i i i i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x   x   x",
+			  "  x  a6  a5  a4     a3  a2   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 4;
+	readsize	= 256;
+       ;
+     memory "flash"
+         paged           = yes;
+         size            = 2048;
+         page_size       = 32;
+         num_pages       = 64;
+         min_write_delay = 4500;
+         max_write_delay = 4500;
+         readback_p1     = 0xff;
+         readback_p2     = 0xff;
+         read_lo         = "  0   0   1   0    0   0   0   0",
+                           "  0   0   0   0    0   0  a9  a8",
+                           " a7  a6  a5  a4   a3  a2  a1  a0",
+                           "  o   o   o   o    o   o   o   o";
+
+         read_hi         = "  0   0   1   0    1   0   0   0",
+                           "  0   0   0   0    0   0  a9  a8",
+                           " a7  a6  a5  a4   a3  a2  a1  a0",
+                           "  o   o   o   o    o   o   o   o";
+
+         loadpage_lo     = "  0   1   0   0    0   0   0   0",
+                           "  0   0   0   x    x   x   x   x",
+                           "  x   x   x   x   a3  a2  a1  a0",
+                           "  i   i   i   i    i   i   i   i";
+
+         loadpage_hi     = "  0   1   0   0    1   0   0   0",
+                           "  0   0   0   x    x   x   x   x",
+                           "  x   x   x   x   a3  a2  a1  a0",
+                           "  i   i   i   i    i   i   i   i";
+
+         writepage       = "  0  1  0  0   1  1  0  0",
+                           "  0  0  0  0   0  0 a9 a8",
+                           " a7 a6 a5 a4   x  x  x  x",
+                           "  x  x  x  x   x  x  x  x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 32;
+	readsize	= 256;
+       ;
+#   ATtiny25 has Signature Bytes: 0x1E 0x91 0x08.
+     memory "signature"
+         size            = 3;
+         read            = "0  0  1  1   0  0  0  0   0  0  0  x   x  x  x  x",
+                           "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+       ;
+     memory "lock"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 1 1 x  x x x x",
+                           "x x x x  x x x x  1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "lfuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                           "x x x x  x x x x  i i i i  i i i i";
+
+         read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "hfuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                           "x x x x  x x x x  i i i i  i i i i";
+
+         read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "efuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                           "x x x x  x x x x  x x x x  x x x i";
+
+         read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+     ;
+
+     memory "calibration"
+         size            = 2;
+         read            = "0  0  1  1   1  0  0  0    0 0 0 x  x x x x",
+                           "0  0  0  0   0  0  0  a0   o o o o  o o o o";
+     ;
+  ;
+
+#------------------------------------------------------------
+# ATtiny45
+#------------------------------------------------------------
+
+part
+     id            = "t45";
+     desc          = "ATtiny45";
+     has_debugwire = yes;
+     flash_instr   = 0xB4, 0x02, 0x12;
+     eeprom_instr  = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D,
+	             0xBC, 0x02, 0xB4, 0x02, 0xBA, 0x0D, 0xBB, 0xBC,
+	             0x99, 0xE1, 0xBB, 0xAC;
+     stk500_devcode   = 0x14;
+##  avr910_devcode   = ?;
+##  Try the AT90S2313 devcode:
+     avr910_devcode   = 0x20;
+     signature        = 0x1e 0x92 0x06;
+     reset            = io;
+     chip_erase_delay = 4500;
+
+     pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                        "x x x x  x x x x    x x x x  x x x x";
+
+     chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                        "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    hvsp_controlstack     =
+	0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66,
+        0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78,
+        0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10,
+        0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    hvspcmdexedelay     = 0;
+    synchcycles         = 6;
+    latchcycles         = 1;
+    togglevtg           = 1;
+    poweroffdelay       = 25;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 100;
+    resetdelay          = 25;
+    chiperasepolltimeout = 40;
+    chiperasetime       = 0;
+    programfusepolltimeout = 25;
+    programlockpolltimeout = 25;
+
+     memory "eeprom"
+         size            = 256;
+         page_size       = 4;
+         min_write_delay = 4000;
+         max_write_delay = 4500;
+         readback_p1     = 0xff;
+         readback_p2     = 0xff;
+         read            = "1  0  1  0   0  0  0  0    0 0 0 x  x x x x",
+                           "a7 a6 a5 a4  a3 a2 a1 a0   o o o o  o o o o";
+
+         write           = "1  1  0  0   0  0  0  0    0 0 0 x  x x x x",
+                           "a7 a6 a5 a4  a3 a2 a1 a0   i i i i  i i i i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x   x   x",
+			  " a7  a6  a5  a4     a3  a2   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 4;
+	readsize	= 256;
+       ;
+     memory "flash"
+         paged           = yes;
+         size            = 4096;
+         page_size       = 64;
+         num_pages       = 64;
+         min_write_delay = 4500;
+         max_write_delay = 4500;
+         readback_p1     = 0xff;
+         readback_p2     = 0xff;
+         read_lo         = "  0   0   1   0    0   0   0   0",
+                           "  0   0   0   0    0  a10 a9  a8",
+                           " a7  a6  a5  a4   a3  a2  a1  a0",
+                           "  o   o   o   o    o   o   o   o";
+
+         read_hi         = "  0   0   1   0    1   0   0   0",
+                           "  0   0   0   0    0  a10 a9  a8",
+                           " a7  a6  a5  a4   a3  a2  a1  a0",
+                           "  o   o   o   o    o   o   o   o";
+
+         loadpage_lo     = "  0   1   0   0    0   0   0   0",
+                           "  0   0   0   x    x   x   x   x",
+                           "  x   x   x  a4   a3  a2  a1  a0",
+                           "  i   i   i   i    i   i   i   i";
+
+         loadpage_hi     = "  0   1   0   0    1   0   0   0",
+                           "  0   0   0   x    x   x   x   x",
+                           "  x   x   x  a4   a3  a2  a1  a0",
+                           "  i   i   i   i    i   i   i   i";
+
+         writepage       = "  0  1  0  0   1  1  0  0",
+                           "  0  0  0  0   0 a10 a9 a8",
+                           " a7 a6 a5  x   x  x  x  x",
+                           "  x  x  x  x   x  x  x  x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 32;
+	readsize	= 256;
+       ;
+#   ATtiny45 has Signature Bytes: 0x1E 0x92 0x08. (Data sheet 2586C-AVR-06/05 (doc2586.pdf) indicates otherwise!)
+     memory "signature"
+         size            = 3;
+         read            = "0  0  1  1   0  0  0  0   0  0  0  x   x  x  x  x",
+                           "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+       ;
+     memory "lock"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 1 1 x  x x x x",
+                           "x x x x  x x x x  1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "lfuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                           "x x x x  x x x x  i i i i  i i i i";
+
+         read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "hfuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                           "x x x x  x x x x  i i i i  i i i i";
+
+         read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "efuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                           "x x x x  x x x x  x x x x  x x x i";
+
+         read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+     ;
+
+     memory "calibration"
+         size            = 2;
+         read            = "0  0  1  1   1  0  0  0    0 0 0 x  x x x x",
+                           "0  0  0  0   0  0  0  a0   o o o o  o o o o";
+     ;
+  ;
+
+#------------------------------------------------------------
+# ATtiny85
+#------------------------------------------------------------
+
+part
+     id            = "t85";
+     desc          = "ATtiny85";
+     has_debugwire = yes;
+     flash_instr   = 0xB4, 0x02, 0x12;
+     eeprom_instr  = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D,
+	             0xBC, 0x02, 0xB4, 0x02, 0xBA, 0x0D, 0xBB, 0xBC,
+	             0x99, 0xE1, 0xBB, 0xAC;
+## no STK500 devcode in XML file, use the ATtiny45 one
+     stk500_devcode   = 0x14;
+##  avr910_devcode   = ?;
+##  Try the AT90S2313 devcode:
+     avr910_devcode   = 0x20;
+     signature        = 0x1e 0x93 0x0b;
+     reset            = io;
+     chip_erase_delay = 4500;
+
+     pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                        "x x x x  x x x x    x x x x  x x x x";
+
+     chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                        "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    hvsp_controlstack   =
+        0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66,
+        0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78,
+        0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10,
+        0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x00;
+    hventerstabdelay    = 100;
+    hvspcmdexedelay     = 0;
+    synchcycles         = 6;
+    latchcycles         = 1;
+    togglevtg           = 1;
+    poweroffdelay       = 25;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 100;
+    resetdelay          = 25;
+    chiperasepolltimeout = 40;
+    chiperasetime       = 0;
+    programfusepolltimeout = 25;
+    programlockpolltimeout = 25;
+
+     memory "eeprom"
+         size            = 512;
+        paged           = no;
+        page_size       = 4;
+         min_write_delay = 4000;
+         max_write_delay = 4500;
+         readback_p1     = 0xff;
+         readback_p2     = 0xff;
+         read            = "1  0  1  0   0  0  0  0    0 0 0 x  x x x a8",
+                           "a7 a6 a5 a4  a3 a2 a1 a0   o o o o  o o o o";
+
+         write           = "1  1  0  0   0  0  0  0    0 0 0 x  x x x a8",
+                           "a8 a6 a5 a4  a3 a2 a1 a0   i i i i  i i i i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x   x  a8",
+			  " a7  a6  a5  a4     a3  a2   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 4;
+	readsize	= 256;
+       ;
+     memory "flash"
+         paged           = yes;
+         size            = 8192;
+         page_size       = 64;
+         num_pages       = 128;
+         min_write_delay = 4500;
+         max_write_delay = 4500;
+         readback_p1     = 0xff;
+         readback_p2     = 0xff;
+         read_lo         = "  0   0   1   0    0   0   0   0",
+                           "  0   0   0   0  a11 a10  a9  a8",
+                           " a7  a6  a5  a4   a3  a2  a1  a0",
+                           "  o   o   o   o    o   o   o   o";
+
+         read_hi         = "  0   0   1   0    1   0   0   0",
+                           "  0   0   0   0  a11 a10  a9  a8",
+                           " a7  a6  a5  a4   a3  a2  a1  a0",
+                           "  o   o   o   o    o   o   o   o";
+
+         loadpage_lo     = "  0   1   0   0    0   0   0   0",
+                           "  0   0   0   x    x   x   x   x",
+                           "  x   x   x  a4   a3  a2  a1  a0",
+                           "  i   i   i   i    i   i   i   i";
+
+         loadpage_hi     = "  0   1   0   0    1   0   0   0",
+                           "  0   0   0   x    x   x   x   x",
+                           "  x   x   x  a4   a3  a2  a1  a0",
+                           "  i   i   i   i    i   i   i   i";
+
+         writepage       = "  0  1  0  0   1   1   0  0",
+                           "  0  0  0  0  a11 a10 a9 a8",
+                           " a7 a6 a5  x   x  x  x  x",
+                           "  x  x  x  x   x  x  x  x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 32;
+	readsize	= 256;
+       ;
+#   ATtiny85 has Signature Bytes: 0x1E 0x93 0x08.
+     memory "signature"
+         size            = 3;
+         read            = "0  0  1  1   0  0  0  0   0  0  0  x   x  x  x  x",
+                           "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+       ;
+     memory "lock"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 1 1 x  x x x x",
+                           "x x x x  x x x x  1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "lfuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                           "x x x x  x x x x  i i i i  i i i i";
+
+         read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "hfuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                           "x x x x  x x x x  i i i i  i i i i";
+
+         read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "efuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                           "x x x x  x x x x  x x x x  x x x i";
+
+         read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+     ;
+
+     memory "calibration"
+         size            = 2;
+         read            = "0  0  1  1   1  0  0  0    0 0 0 x  x x x x",
+                           "0  0  0  0   0  0  0  a0   o o o o  o o o o";
+     ;
+  ;
+
+#------------------------------------------------------------
+# ATmega640
+#------------------------------------------------------------
+# Almost same as ATmega1280, except for different memory sizes
+
+part
+    id               = "m640";
+    desc             = "ATMEGA640";
+    signature        = 0x1e 0x96 0x08;
+    has_jtag         = yes;
+#    stk500_devcode   = 0xB2;
+#    avr910_devcode   = 0x43;
+    chip_erase_delay = 9000;
+    pagel            = 0xD7;
+    bs2              = 0xA0;
+    reset            = dedicated;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+    rampz               = 0x3b;
+    allowfullpagebitstream = no;
+
+    memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 8;  /* for parallel programming */
+        size            = 4096;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0x00;
+        readback_p2     = 0x00;
+        read            = "  1   0   1   0      0   0   0   0",
+                          "  x   x   x   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        write           = "  1   1   0   0      0   0   0   0",
+                          "  x   x   x   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0", 
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0  a2  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x    a11 a10  a9  a8",
+			  " a7  a6  a5  a4     a3   0   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 10;
+	blocksize	= 8;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 65536;
+        page_size       = 256;
+        num_pages       = 256;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0x00;
+        readback_p2     = 0x00;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "  0 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "  0 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "  0 a14 a13 a12    a11 a10  a9  a8",
+                          " a7   x   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 10;
+	blocksize	= 256;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "efuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x  x x x x  x i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0 0 1 1  1 0 0 0    x x x x  x x x x",
+                          "0 0 0 0  0 0 0 0    o o o o  o o o o";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+  ;
+
+#------------------------------------------------------------
+# ATmega1280
+#------------------------------------------------------------
+
+part
+    id               = "m1280";
+    desc             = "ATMEGA1280";
+    signature        = 0x1e 0x97 0x03;
+    has_jtag         = yes;
+#    stk500_devcode   = 0xB2;
+#    avr910_devcode   = 0x43;
+    chip_erase_delay = 9000;
+    pagel            = 0xD7;
+    bs2              = 0xA0;
+    reset            = dedicated;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+    rampz               = 0x3b;
+    allowfullpagebitstream = no;
+
+    memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 8;  /* for parallel programming */
+        size            = 4096;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0x00;
+        readback_p2     = 0x00;
+        read            = "  1   0   1   0      0   0   0   0",
+                          "  x   x   x   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        write           = "  1   1   0   0      0   0   0   0",
+                          "  x   x   x   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0", 
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0  a2  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x    a11 a10  a9  a8",
+			  " a7  a6  a5  a4     a3   0   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 10;
+	blocksize	= 8;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 131072;
+        page_size       = 256;
+        num_pages       = 512;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0x00;
+        readback_p2     = 0x00;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7   x   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 10;
+	blocksize	= 256;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "efuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x  x x x x  x i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0 0 1 1  1 0 0 0    x x x x  x x x x",
+                          "0 0 0 0  0 0 0 0    o o o o  o o o o";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+  ;
+
+#------------------------------------------------------------
+# ATmega1281
+#------------------------------------------------------------
+# Identical to ATmega1280
+
+part
+    id               = "m1281";
+    desc             = "ATMEGA1281";
+    signature        = 0x1e 0x97 0x04;
+    has_jtag         = yes;
+#    stk500_devcode   = 0xB2;
+#    avr910_devcode   = 0x43;
+    chip_erase_delay = 9000;
+    pagel            = 0xD7;
+    bs2              = 0xA0;
+    reset            = dedicated;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+    rampz               = 0x3b;
+    allowfullpagebitstream = no;
+
+    memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 8;  /* for parallel programming */
+        size            = 4096;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0x00;
+        readback_p2     = 0x00;
+        read            = "  1   0   1   0      0   0   0   0",
+                          "  x   x   x   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        write           = "  1   1   0   0      0   0   0   0",
+                          "  x   x   x   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0", 
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0  a2  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x    a11 a10  a9  a8",
+			  " a7  a6  a5  a4     a3   0   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 10;
+	blocksize	= 8;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 131072;
+        page_size       = 256;
+        num_pages       = 512;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0x00;
+        readback_p2     = 0x00;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7   x   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 10;
+	blocksize	= 256;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "efuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x  x x x x  x i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0 0 1 1  1 0 0 0    x x x x  x x x x",
+                          "0 0 0 0  0 0 0 0    o o o o  o o o o";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+  ;
+
+#------------------------------------------------------------
+# ATmega2560
+#------------------------------------------------------------
+
+part
+    id               = "m2560";
+    desc             = "ATMEGA2560";
+    signature        = 0x1e 0x98 0x01;
+    has_jtag         = yes;
+#    stk500_devcode   = 0xB2;
+#    avr910_devcode   = 0x43;
+    chip_erase_delay = 9000;
+    pagel            = 0xD7;
+    bs2              = 0xA0;
+    reset            = dedicated;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+    rampz               = 0x3b;
+    allowfullpagebitstream = no;
+
+    memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 8;  /* for parallel programming */
+        size            = 4096;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0x00;
+        readback_p2     = 0x00;
+        read            = "  1   0   1   0      0   0   0   0",
+                          "  x   x   x   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        write           = "  1   1   0   0      0   0   0   0",
+                          "  x   x   x   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0", 
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0  a2  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x    a11 a10  a9  a8",
+			  " a7  a6  a5  a4     a3   0   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 10;
+	blocksize	= 8;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 262144;
+        page_size       = 256;
+        num_pages       = 1024;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0x00;
+        readback_p2     = 0x00;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7   x   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+        load_ext_addr   = "  0   1   0   0      1   1   0   1",
+                          "  0   0   0   0      0   0   0   0",
+                          "  0   0   0   0      0   0   0 a16",
+                          "  0   0   0   0      0   0   0   0";
+
+	mode		= 0x41;
+	delay		= 10;
+	blocksize	= 256;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "efuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x  x x x x  x i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0 0 1 1  1 0 0 0    x x x x  x x x x",
+                          "0 0 0 0  0 0 0 0    o o o o  o o o o";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+  ;
+
+#------------------------------------------------------------
+# ATmega2561
+#------------------------------------------------------------
+
+part
+    id               = "m2561";
+    desc             = "ATMEGA2561";
+    signature        = 0x1e 0x98 0x02;
+    has_jtag         = yes;
+#    stk500_devcode   = 0xB2;
+#    avr910_devcode   = 0x43;
+    chip_erase_delay = 9000;
+    pagel            = 0xD7;
+    bs2              = 0xA0;
+    reset            = dedicated;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+    rampz               = 0x3b;
+    allowfullpagebitstream = no;
+
+    memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 8;  /* for parallel programming */
+        size            = 4096;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0x00;
+        readback_p2     = 0x00;
+        read            = "  1   0   1   0      0   0   0   0",
+                          "  x   x   x   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        write           = "  1   1   0   0      0   0   0   0",
+                          "  x   x   x   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0", 
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0  a2  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x    a11 a10  a9  a8",
+			  " a7  a6  a5  a4     a3   0   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 10;
+	blocksize	= 8;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 262144;
+        page_size       = 256;
+        num_pages       = 1024;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0x00;
+        readback_p2     = 0x00;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7   x   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+        load_ext_addr   = "  0   1   0   0      1   1   0   1",
+                          "  0   0   0   0      0   0   0   0",
+                          "  0   0   0   0      0   0   0 a16",
+                          "  0   0   0   0      0   0   0   0";
+
+	mode		= 0x41;
+	delay		= 10;
+	blocksize	= 256;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "efuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x  x x x x  x i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0 0 1 1  1 0 0 0    x x x x  x x x x",
+                          "0 0 0 0  0 0 0 0    o o o o  o o o o";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+  ;
+
+#------------------------------------------------------------
+# ATmega128RFA1
+#------------------------------------------------------------
+# Identical to ATmega2561 but half the ROM
+
+part
+    id               = "m128rfa1";
+    desc             = "ATMEGA128RFA1";
+    signature        = 0x1e 0xa7 0x01;
+    has_jtag         = yes;
+#    stk500_devcode   = 0xB2;
+#    avr910_devcode   = 0x43;
+    chip_erase_delay = 9000;
+    pagel            = 0xD7;
+    bs2              = 0xE2;
+    reset            = dedicated;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+    rampz               = 0x3b;
+    allowfullpagebitstream = no;
+
+    memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 8;  /* for parallel programming */
+        size            = 4096;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0x00;
+        readback_p2     = 0x00;
+        read            = "  1   0   1   0      0   0   0   0",
+                          "  x   x   x   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        write           = "  1   1   0   0      0   0   0   0",
+                          "  x   x   x   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0", 
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0  a2  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x    a11 a10  a9  a8",
+			  " a7  a6  a5  a4     a3   0   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 10;
+	blocksize	= 8;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 131072;
+        page_size       = 256;
+        num_pages       = 512;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0x00;
+        readback_p2     = 0x00;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7   x   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 10;
+	blocksize	= 256;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "efuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x  x x x x  x i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0 0 1 1  1 0 0 0    x x x x  x x x x",
+                          "0 0 0 0  0 0 0 0    o o o o  o o o o";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+  ;
+
+#------------------------------------------------------------
+# ATtiny24
+#------------------------------------------------------------
+
+part
+     id            = "t24";
+     desc          = "ATtiny24";
+     has_debugwire = yes;
+     flash_instr   = 0xB4, 0x07, 0x17;
+     eeprom_instr  = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D,
+	             0xBC, 0x07, 0xB4, 0x07, 0xBA, 0x0D, 0xBB, 0xBC,
+	             0x99, 0xE1, 0xBB, 0xAC;
+## no STK500 devcode in XML file, use the ATtiny45 one
+     stk500_devcode   = 0x14;
+##  avr910_devcode   = ?;
+##  Try the AT90S2313 devcode:
+     avr910_devcode   = 0x20;
+     signature        = 0x1e 0x91 0x0b;
+     reset            = io;
+     chip_erase_delay = 4500;
+
+     pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                        "x x x x  x x x x    x x x x  x x x x";
+
+     chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                        "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    hvsp_controlstack   =
+        0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66,
+        0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78,
+        0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10,
+        0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x0F;
+    hventerstabdelay    = 100;
+    hvspcmdexedelay     = 0;
+    synchcycles         = 6;
+    latchcycles         = 1;
+    togglevtg           = 1;
+    poweroffdelay       = 25;
+    resetdelayms        = 0;
+    resetdelayus        = 70;
+    hvleavestabdelay    = 100;
+    resetdelay          = 25;
+    chiperasepolltimeout = 40;
+    chiperasetime       = 0;
+    programfusepolltimeout = 25;
+    programlockpolltimeout = 25;
+
+     memory "eeprom"
+         size            = 128;
+        paged           = no;
+        page_size       = 4;
+         min_write_delay = 4000;
+         max_write_delay = 4500;
+         readback_p1     = 0xff;
+         readback_p2     = 0xff;
+         read            = "1  0  1  0   0  0  0  0   0 0 0 x  x x x x",
+                           "x a6 a5 a4  a3 a2 a1 a0   o o o o  o o o o";
+
+         write           = "1  1  0  0   0  0  0  0   0 0 0 x  x x x x",
+                           "x a6 a5 a4  a3 a2 a1 a0   i i i i  i i i i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x   x   x",
+			  "  x  a6  a5  a4     a3  a2   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 4;
+	readsize	= 256;
+       ;
+     memory "flash"
+         paged           = yes;
+         size            = 2048;
+         page_size       = 32;
+         num_pages       = 64;
+         min_write_delay = 4500;
+         max_write_delay = 4500;
+         readback_p1     = 0xff;
+         readback_p2     = 0xff;
+         read_lo         = "  0   0   1   0    0   0   0   0",
+                           "  0   0   0   0    0   0  a9  a8",
+                           " a7  a6  a5  a4   a3  a2  a1  a0",
+                           "  o   o   o   o    o   o   o   o";
+
+         read_hi         = "  0   0   1   0    1   0   0   0",
+                           "  0   0   0   0    0   0  a9  a8",
+                           " a7  a6  a5  a4   a3  a2  a1  a0",
+                           "  o   o   o   o    o   o   o   o";
+
+         loadpage_lo     = "  0   1   0   0    0   0   0   0",
+                           "  0   0   0   x    x   x   x   x",
+                           "  x   x   x   x   a3  a2  a1  a0",
+                           "  i   i   i   i    i   i   i   i";
+
+         loadpage_hi     = "  0   1   0   0    1   0   0   0",
+                           "  0   0   0   x    x   x   x   x",
+                           "  x   x   x   x   a3  a2  a1  a0",
+                           "  i   i   i   i    i   i   i   i";
+
+         writepage       = "  0  1  0  0   1  1  0  0",
+                           "  0  0  0  0   0  0 a9 a8",
+                           " a7 a6 a5 a4   x  x  x  x",
+                           "  x  x  x  x   x  x  x  x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 32;
+	readsize	= 256;
+       ;
+#   ATtiny24 has Signature Bytes: 0x1E 0x91 0x0B.
+     memory "signature"
+         size            = 3;
+         read            = "0  0  1  1   0  0  0  0   0  0  0  x   x  x  x  x",
+                           "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+       ;
+     memory "lock"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 1 1 x  x x x x",
+                           "x x x x  x x x x  x x x x  x x i i";
+         read            = "0 1 0 1  1 0 0 0  0 0 0 0  0 0 0 0",
+                           "0 0 0 0  0 0 0 0  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "lfuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                           "x x x x  x x x x  i i i i  i i i i";
+
+         read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "hfuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                           "x x x x  x x x x  i i i i  i i i i";
+
+         read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "efuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                           "x x x x  x x x x  x x x x  x x x i";
+
+         read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+     ;
+
+     memory "calibration"
+         size            = 1;
+         read            = "0  0  1  1   1  0  0  0    0 0 0 x  x x x x",
+                           "0  0  0  0   0  0  0  a0   o o o o  o o o o";
+     ;
+  ;
+
+#------------------------------------------------------------
+# ATtiny44
+#------------------------------------------------------------
+
+part
+     id            = "t44";
+     desc          = "ATtiny44";
+     has_debugwire = yes;
+     flash_instr   = 0xB4, 0x07, 0x17;
+     eeprom_instr  = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D,
+                     0xBC, 0x07, 0xB4, 0x07, 0xBA, 0x0D, 0xBB, 0xBC,
+                     0x99, 0xE1, 0xBB, 0xAC;
+## no STK500 devcode in XML file, use the ATtiny45 one
+     stk500_devcode   = 0x14;
+##  avr910_devcode   = ?;
+##  Try the AT90S2313 devcode:
+     avr910_devcode   = 0x20;
+     signature        = 0x1e 0x92 0x07;
+     reset            = io;
+     chip_erase_delay = 4500;
+
+     pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                        "x x x x  x x x x    x x x x  x x x x";
+
+     chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                        "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    hvsp_controlstack   =
+        0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66,
+        0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78,
+        0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10,
+        0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x0F;
+    hventerstabdelay    = 100;
+    hvspcmdexedelay     = 0;
+    synchcycles         = 6;
+    latchcycles         = 1;
+    togglevtg           = 1;
+    poweroffdelay       = 25;
+    resetdelayms        = 0;
+    resetdelayus        = 70;
+    hvleavestabdelay    = 100;
+    resetdelay          = 25;
+    chiperasepolltimeout = 40;
+    chiperasetime       = 0;
+    programfusepolltimeout = 25;
+    programlockpolltimeout = 25;
+
+     memory "eeprom"
+         size            = 256;
+        paged           = no;
+        page_size       = 4;
+         min_write_delay = 4000;
+         max_write_delay = 4500;
+         readback_p1     = 0xff;
+         readback_p2     = 0xff;
+         read            = "1  0  1  0   0  0  0  0    0 0 0 x  x x x x",
+                           "a7 a6 a5 a4  a3 a2 a1 a0   o o o o  o o o o";
+
+         write           = "1  1  0  0   0  0  0  0    0 0 0 x  x x x x",
+                           "a7 a6 a5 a4  a3 a2 a1 a0   i i i i  i i i i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x   x   x",
+			  "  x  a6  a5  a4     a3  a2   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 4;
+	readsize	= 256;
+       ;
+     memory "flash"
+         paged           = yes;
+         size            = 4096;
+         page_size       = 64;
+         num_pages       = 64;
+         min_write_delay = 4500;
+         max_write_delay = 4500;
+         readback_p1     = 0xff;
+         readback_p2     = 0xff;
+         read_lo         = "  0   0   1   0    0   0   0   0",
+                           "  0   0   0   0    0  a10 a9  a8",
+                           " a7  a6  a5  a4   a3  a2  a1  a0",
+                           "  o   o   o   o    o   o   o   o";
+
+         read_hi         = "  0   0   1   0    1   0   0   0",
+                           "  0   0   0   0    0  a10 a9  a8",
+                           " a7  a6  a5  a4   a3  a2  a1  a0",
+                           "  o   o   o   o    o   o   o   o";
+
+         loadpage_lo     = "  0   1   0   0    0   0   0   0",
+                           "  0   0   0   x    x   x   x   x",
+                           "  x   x   x  a4   a3  a2  a1  a0",
+                           "  i   i   i   i    i   i   i   i";
+
+         loadpage_hi     = "  0   1   0   0    1   0   0   0",
+                           "  0   0   0   x    x   x   x   x",
+                           "  x   x   x  a4   a3  a2  a1  a0",
+                           "  i   i   i   i    i   i   i   i";
+
+         writepage       = "  0  1  0  0   1  1  0  0",
+                           "  0  0  0  0   0 a10 a9 a8",
+                           " a7 a6 a5  x   x  x  x  x",
+                           "  x  x  x  x   x  x  x  x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 32;
+	readsize	= 256;
+       ;
+#   ATtiny44 has Signature Bytes: 0x1E 0x92 0x07.
+     memory "signature"
+         size            = 3;
+         read            = "0  0  1  1   0  0  0  0   0  0  0  x   x  x  x  x",
+                           "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+       ;
+     memory "lock"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 1 1 x  x x x x",
+                           "x x x x  x x x x  x x x x  x x i i";
+         read            = "0 1 0 1  1 0 0 0  0 0 0 0  0 0 0 0",
+                           "0 0 0 0  0 0 0 0  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "lfuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                           "x x x x  x x x x  i i i i  i i i i";
+
+         read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "hfuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                           "x x x x  x x x x  i i i i  i i i i";
+
+         read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "efuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                           "x x x x  x x x x  x x x x  x x x i";
+
+         read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+     ;
+
+     memory "calibration"
+         size            = 1;
+         read            = "0  0  1  1   1  0  0  0    0 0 0 x  x x x x",
+                           "0  0  0  0   0  0  0  a0   o o o o  o o o o";
+     ;
+  ;
+
+#------------------------------------------------------------
+# ATtiny84
+#------------------------------------------------------------
+
+part
+     id            = "t84";
+     desc          = "ATtiny84";
+     has_debugwire = yes;
+     flash_instr   = 0xB4, 0x07, 0x17;
+     eeprom_instr  = 0xBB, 0xFF, 0xBB, 0xEE, 0xBB, 0xCC, 0xB2, 0x0D,
+	             0xBC, 0x07, 0xB4, 0x07, 0xBA, 0x0D, 0xBB, 0xBC,
+	             0x99, 0xE1, 0xBB, 0xAC;
+## no STK500 devcode in XML file, use the ATtiny45 one
+     stk500_devcode   = 0x14;
+##  avr910_devcode   = ?;
+##  Try the AT90S2313 devcode:
+     avr910_devcode   = 0x20;
+     signature        = 0x1e 0x93 0x0c;
+     reset            = io;
+     chip_erase_delay = 4500;
+
+     pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                        "x x x x  x x x x    x x x x  x x x x";
+
+     chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                        "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    hvsp_controlstack   =
+        0x4C, 0x0C, 0x1C, 0x2C, 0x3C, 0x64, 0x74, 0x66,
+        0x68, 0x78, 0x68, 0x68, 0x7A, 0x6A, 0x68, 0x78,
+        0x78, 0x7D, 0x6D, 0x0C, 0x80, 0x40, 0x20, 0x10,
+        0x11, 0x08, 0x04, 0x02, 0x03, 0x08, 0x04, 0x0F;
+    hventerstabdelay    = 100;
+    hvspcmdexedelay     = 0;
+    synchcycles         = 6;
+    latchcycles         = 1;
+    togglevtg           = 1;
+    poweroffdelay       = 25;
+    resetdelayms        = 0;
+    resetdelayus        = 70;
+    hvleavestabdelay    = 100;
+    resetdelay          = 25;
+    chiperasepolltimeout = 40;
+    chiperasetime       = 0;
+    programfusepolltimeout = 25;
+    programlockpolltimeout = 25;
+
+     memory "eeprom"
+         size            = 512;
+        paged           = no;
+        page_size       = 4;
+         min_write_delay = 4000;
+         max_write_delay = 4500;
+         readback_p1     = 0xff;
+         readback_p2     = 0xff;
+         read            = "1  0  1  0   0  0  0  0    0 0 0 x  x x x a8",
+                           "a7 a6 a5 a4  a3 a2 a1 a0   o o o o  o o o o";
+
+         write           = "1  1  0  0   0  0  0  0    0 0 0 x  x x x a8",
+                           "a8 a6 a5 a4  a3 a2 a1 a0   i i i i  i i i i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x   x   x   x",
+			  "  x  a6  a5  a4     a3  a2   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 4;
+	readsize	= 256;
+       ;
+     memory "flash"
+         paged           = yes;
+         size            = 8192;
+         page_size       = 64;
+         num_pages       = 128;
+         min_write_delay = 4500;
+         max_write_delay = 4500;
+         readback_p1     = 0xff;
+         readback_p2     = 0xff;
+         read_lo         = "  0   0   1   0    0   0   0   0",
+                           "  0   0   0   0  a11 a10  a9  a8",
+                           " a7  a6  a5  a4   a3  a2  a1  a0",
+                           "  o   o   o   o    o   o   o   o";
+
+         read_hi         = "  0   0   1   0    1   0   0   0",
+                           "  0   0   0   0  a11 a10  a9  a8",
+                           " a7  a6  a5  a4   a3  a2  a1  a0",
+                           "  o   o   o   o    o   o   o   o";
+
+         loadpage_lo     = "  0   1   0   0    0   0   0   0",
+                           "  0   0   0   x    x   x   x   x",
+                           "  x   x   x  a4   a3  a2  a1  a0",
+                           "  i   i   i   i    i   i   i   i";
+
+         loadpage_hi     = "  0   1   0   0    1   0   0   0",
+                           "  0   0   0   x    x   x   x   x",
+                           "  x   x   x  a4   a3  a2  a1  a0",
+                           "  i   i   i   i    i   i   i   i";
+
+         writepage       = "  0  1  0  0   1   1   0  0",
+                           "  0  0  0  0  a11 a10 a9 a8",
+                           " a7 a6 a5  x   x  x  x  x",
+                           "  x  x  x  x   x  x  x  x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 32;
+	readsize	= 256;
+       ;
+#   ATtiny84 has Signature Bytes: 0x1E 0x93 0x0C.
+     memory "signature"
+         size            = 3;
+         read            = "0  0  1  1   0  0  0  0   0  0  0  x   x  x  x  x",
+                           "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+       ;
+
+     memory "lock"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 1 1 x  x x x x",
+                           "x x x x  x x x x  x x x x  x x i i";
+         read            = "0 1 0 1  1 0 0 0  0 0 0 0  0 0 0 0",
+                           "0 0 0 0  0 0 0 0  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "lfuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                           "x x x x  x x x x  i i i i  i i i i";
+
+         read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "hfuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                           "x x x x  x x x x  i i i i  i i i i";
+
+         read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+       ;
+
+     memory "efuse"
+         size            = 1;
+         write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                           "x x x x  x x x x  x x x x  x x x i";
+
+         read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                           "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+     ;
+
+     memory "calibration"
+         size            = 1;
+         read            = "0  0  1  1   1  0  0  0    0 0 0 x  x x x x",
+                           "0  0  0  0   0  0  0  a0   o o o o  o o o o";
+     ;
+  ;
+
+#------------------------------------------------------------
+# ATmega32u4
+#------------------------------------------------------------
+
+part
+    id               = "m32u4";
+    desc             = "ATmega32U4";
+    signature        = 0x1e 0x95 0x87;
+    has_jtag         = yes;
+#    stk500_devcode   = 0xB2;
+#    avr910_devcode   = 0x43;
+    chip_erase_delay = 9000;
+    pagel            = 0xD7;
+    bs2              = 0xA0;
+    reset            = dedicated;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+    rampz               = 0x3b;
+    allowfullpagebitstream = no;
+
+    memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 8;  /* for parallel programming */
+        size            = 1024;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0x00;
+        readback_p2     = 0x00;
+        read            = "  1   0   1   0      0   0   0   0",
+                          "  x   x   x   x      x a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        write           = "  1   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0", 
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0  a2  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x a10  a9  a8",
+			  " a7  a6  a5  a4     a3   0   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 10;
+	blocksize	= 8;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 32768;
+        page_size       = 128;
+        num_pages       = 256;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0x00;
+        readback_p2     = 0x00;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "  0 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "  0 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          " a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "efuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x  x x x x  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0 0 1 1  1 0 0 0    x x x x  x x x x",
+                          "0 0 0 0  0 0 0 0    o o o o  o o o o";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+  ;
+
+#------------------------------------------------------------
+# AT90USB646
+#------------------------------------------------------------
+
+part
+    id               = "usb646";
+    desc             = "AT90USB646";
+    signature        = 0x1e 0x96 0x82;
+    has_jtag         = yes;
+#    stk500_devcode   = 0xB2;
+#    avr910_devcode   = 0x43;
+    chip_erase_delay = 9000;
+    pagel            = 0xD7;
+    bs2              = 0xA0;
+    reset            = dedicated;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+    rampz               = 0x3b;
+    allowfullpagebitstream = no;
+
+    memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 8;  /* for parallel programming */
+        size            = 2048;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0x00;
+        readback_p2     = 0x00;
+        read            = "  1   0   1   0      0   0   0   0",
+                          "  x   x   x   x      x a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        write           = "  1   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0", 
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0  a2  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x a10  a9  a8",
+			  " a7  a6  a5  a4     a3   0   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 10;
+	blocksize	= 8;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 65536;
+        page_size       = 256;
+        num_pages       = 256;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0x00;
+        readback_p2     = 0x00;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "  0 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "  0 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "  0 a14 a13 a12    a11 a10  a9  a8",
+                          " a7   x   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 256;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "efuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x  x x x x  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0 0 1 1  1 0 0 0    x x x x  x x x x",
+                          "0 0 0 0  0 0 0 0    o o o o  o o o o";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+  ;
+
+#------------------------------------------------------------
+# AT90USB647
+#------------------------------------------------------------
+# identical to AT90USB646
+
+part
+    id               = "usb647";
+    desc             = "AT90USB647";
+    signature        = 0x1e 0x96 0x82;
+    has_jtag         = yes;
+#    stk500_devcode   = 0xB2;
+#    avr910_devcode   = 0x43;
+    chip_erase_delay = 9000;
+    pagel            = 0xD7;
+    bs2              = 0xA0;
+    reset            = dedicated;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+    rampz               = 0x3b;
+    allowfullpagebitstream = no;
+
+    memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 8;  /* for parallel programming */
+        size            = 2048;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0x00;
+        readback_p2     = 0x00;
+        read            = "  1   0   1   0      0   0   0   0",
+                          "  x   x   x   x      x a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        write           = "  1   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0", 
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0  a2  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x a10  a9  a8",
+			  " a7  a6  a5  a4     a3   0   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 10;
+	blocksize	= 8;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 65536;
+        page_size       = 256;
+        num_pages       = 256;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0x00;
+        readback_p2     = 0x00;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "  0 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "  0 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "  0 a14 a13 a12    a11 a10  a9  a8",
+                          " a7   x   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 256;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "efuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x  x x x x  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0 0 1 1  1 0 0 0    x x x x  x x x x",
+                          "0 0 0 0  0 0 0 0    o o o o  o o o o";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+  ;
+
+#------------------------------------------------------------
+# AT90USB1286
+#------------------------------------------------------------
+
+part
+    id               = "usb1286";
+    desc             = "AT90USB1286";
+    signature        = 0x1e 0x97 0x82;
+    has_jtag         = yes;
+#    stk500_devcode   = 0xB2;
+#    avr910_devcode   = 0x43;
+    chip_erase_delay = 9000;
+    pagel            = 0xD7;
+    bs2              = 0xA0;
+    reset            = dedicated;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+    rampz               = 0x3b;
+    allowfullpagebitstream = no;
+
+    memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 8;  /* for parallel programming */
+        size            = 4096;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0x00;
+        readback_p2     = 0x00;
+        read            = "  1   0   1   0      0   0   0   0",
+                          "  x   x   x   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        write           = "  1   1   0   0      0   0   0   0",
+                          "  x   x   x   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0", 
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0  a2  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x a10  a9  a8",
+			  " a7  a6  a5  a4     a3   0   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 10;
+	blocksize	= 8;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 131072;
+        page_size       = 256;
+        num_pages       = 512;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0x00;
+        readback_p2     = 0x00;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7   x   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 256;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "efuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x  x x x x  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0 0 1 1  1 0 0 0    x x x x  x x x x",
+                          "0 0 0 0  0 0 0 0    o o o o  o o o o";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+  ;
+
+#------------------------------------------------------------
+# AT90USB1287
+#------------------------------------------------------------
+# identical to AT90USB1286
+
+part
+    id               = "usb1287";
+    desc             = "AT90USB1287";
+    signature        = 0x1e 0x97 0x82;
+    has_jtag         = yes;
+#    stk500_devcode   = 0xB2;
+#    avr910_devcode   = 0x43;
+    chip_erase_delay = 9000;
+    pagel            = 0xD7;
+    bs2              = 0xA0;
+    reset            = dedicated;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+    rampz               = 0x3b;
+    allowfullpagebitstream = no;
+
+    memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 8;  /* for parallel programming */
+        size            = 4096;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0x00;
+        readback_p2     = 0x00;
+        read            = "  1   0   1   0      0   0   0   0",
+                          "  x   x   x   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        write           = "  1   1   0   0      0   0   0   0",
+                          "  x   x   x   x    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0", 
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0  a2  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+			  "  0   0   x   x      x a10  a9  a8",
+			  " a7  a6  a5  a4     a3   0   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 10;
+	blocksize	= 8;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 131072;
+        page_size       = 256;
+        num_pages       = 512;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0x00;
+        readback_p2     = 0x00;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7   x   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 256;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "efuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x  x x x x  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0 0 1 1  1 0 0 0    x x x x  x x x x",
+                          "0 0 0 0  0 0 0 0    o o o o  o o o o";
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   x  x  x  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+  ;
+
+
+#------------------------------------------------------------
+# AT90USB162
+#------------------------------------------------------------
+
+part
+    id               = "usb162";
+    desc             = "AT90USB162";
+    has_jtag         = no;
+    has_debugwire    = yes;
+    signature        = 0x1e 0x94 0x82;
+    chip_erase_delay = 9000;
+    reset            = io;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                       "x x x x  x x x x    x x x x  x x x x";
+    pagel            = 0xD7;
+    bs2              = 0xC6;
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 4;  /* for parallel programming */
+        size            = 512;
+        num_pages       = 128;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0x00;
+        readback_p2     = 0x00;
+        read            = "  1   0   1   0      0   0   0   0",
+                          "  0   0   0   0    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        write           = "  1   1   0   0      0   0   0   0",
+                          "  0   0   0   0    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+                          "  0   0   0   0    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 20;
+	blocksize	= 4;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 16384;
+        page_size       = 128;
+        num_pages       = 128;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0x00;
+        readback_p2     = 0x00;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "efuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0 0 1 1  1 0 0 0    0 0 0 x  x x x x",
+                          "0 0 0 0  0 0 0 0    o o o o  o o o o";
+      ;
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   0  0  0  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+  ;
+
+#------------------------------------------------------------
+# AT90USB82
+#------------------------------------------------------------
+# Changes against AT90USB162 (beside IDs)
+#    memory "flash"
+#        size            = 8192;
+#        num_pages       = 64;
+
+part
+    id               = "usb82";
+    desc             = "AT90USB82";
+    has_jtag         = no;
+    has_debugwire    = yes;
+    signature        = 0x1e 0x93 0x82;
+    chip_erase_delay = 9000;
+    reset            = io;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "x x x x  x x x x    x x x x  x x x x";
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 x  x x x x",
+                       "x x x x  x x x x    x x x x  x x x x";
+    pagel            = 0xD7;
+    bs2              = 0xC6;
+
+    timeout		= 200;
+    stabdelay		= 100;
+    cmdexedelay		= 25;
+    synchloops		= 32;
+    bytedelay		= 0;
+    pollindex		= 3;
+    pollvalue		= 0x53;
+    predelay		= 1;
+    postdelay		= 1;
+    pollmethod		= 1;
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 4;  /* for parallel programming */
+        size            = 512;
+        num_pages       = 128;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0x00;
+        readback_p2     = 0x00;
+        read            = "  1   0   1   0      0   0   0   0",
+                          "  0   0   0   0    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        write           = "  1   1   0   0      0   0   0   0",
+                          "  0   0   0   0    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+	loadpage_lo	= "  1   1   0   0      0   0   0   1",
+			  "  0   0   0   0      0   0   0   0",
+			  "  0   0   0   0      0   0  a1  a0",
+			  "  i   i   i   i      i   i   i   i";
+
+	writepage	= "  1   1   0   0      0   0   1   0",
+                          "  0   0   0   0    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2   0   0",
+			  "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 20;
+	blocksize	= 4;
+	readsize	= 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 8192;
+        page_size       = 128;
+        num_pages       = 64;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0x00;
+        readback_p2     = 0x00;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  x   x   x   x      x   x   x   x",
+                          "  x   x  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "a15 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6   x   x      x   x   x   x",
+                          "  x   x   x   x      x   x   x   x";
+
+	mode		= 0x41;
+	delay		= 6;
+	blocksize	= 128;
+	readsize	= 256;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  1 0 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  1 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "efuse"
+        size            = 1;
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                          "x x x x  x x x x  i i i i  i i i i";
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                          "x x x x  x x x x  o o o o  o o o o";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 x  x x x x",
+                          "x x x x  x x x x   1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "calibration"
+        size            = 1;
+        read            = "0 0 1 1  1 0 0 0    0 0 0 x  x x x x",
+                          "0 0 0 0  0 0 0 0    o o o o  o o o o";
+      ;
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   0  0  0  x   x  x  x  x",
+                          "x  x  x  x   x  x a1 a0   o  o  o  o   o  o  o  o";
+      ;
+  ;
+
+#------------------------------------------------------------
+# ATmega325
+#------------------------------------------------------------
+
+part
+    id               = "m325";
+    desc             = "ATMEGA325";
+    signature        = 0x1e 0x95 0x05;
+    has_jtag         = yes;
+#   stk500_devcode   = 0x??; # No STK500v1 support?
+#   avr910_devcode   = 0x??; # Try the ATmega16 one
+    avr910_devcode   = 0x74;
+    pagel            = 0xd7;
+    bs2              = 0xa0;
+    chip_erase_delay = 9000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "0 0 0 0  0 0 0 0    0 0 0 0  0 0 0 0";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "0 0 0 0  0 0 0 0    0 0 0 0  0 0 0 0";
+
+    timeout             = 200;
+    stabdelay           = 100;
+    cmdexedelay         = 25;
+    synchloops          = 32;
+    bytedelay           = 0;
+    pollindex           = 3;
+    pollvalue           = 0x53;
+    predelay            = 1;
+    postdelay           = 1;
+    pollmethod          = 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+    allowfullpagebitstream = no;
+
+    memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 4;  /* for parallel programming */
+        size            = 1024;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read            = "  1   0   1   0      0   0   0   0",
+                          "  0   0   0   0      0   0  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        write           = "  1   1   0   0      0   0   0   0",
+                          "  0   0   0   0      0   0  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_lo     = "  1   1   0   0      0   0   0   1",
+                          "  0   0   0   0      0   0   0   0",
+                          "  0   0   0   0      0   0  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  1   1   0   0      0   0   1   0",
+                          "  0   0   0   0      0   0  a9  a8",
+                          " a7  a6  a5  a4     a3  a2   0   0",
+                          "  x   x   x   x      x   x   x   x";
+
+        mode            = 0x41;
+        delay           = 10;
+        blocksize       = 4;
+        readsize        = 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 32768;
+        page_size       = 128;
+        num_pages       = 256;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "  0 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "  0 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  0   0   0   0      0   0   0   0",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  0   0   0   0      0   0   0   0",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "  0 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  x   x   x   x      x   x   x   x";
+
+        mode            = 0x41;
+        delay           = 10;
+        blocksize       = 128;
+        readsize        = 256;
+      ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 0  0 0 0 0",
+                          "0 0 0 0  0 0 0 0   1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  0 0 0 0",
+                          "0 0 0 0  0 0 0 0   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 0 0 0",
+                          "0 0 0 0  0 0 0 0   i i i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  1 0 0 0",
+                          "0 0 0 0  0 0 0 0   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  1 0 0 0",
+                          "0 0 0 0  0 0 0 0   i i i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "efuse"
+        size            = 1;
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                          "0 0 0 0  0 0 0 0  o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                          "0 0 0 0  0 0 0 0  1 1 1 1  1 i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   0  0  0  0   0  0  0  0",
+                          "0  0  0  0   0  0 a1 a0   o  o  o  o   o  o  o  o";
+      ;
+
+    memory "calibration"
+        size            = 1;
+
+        read            = "0 0 1 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "0 0 0 0  0 0 0 0   o o o o  o o o o";
+        ;
+  ;
+
+#------------------------------------------------------------
+# ATmega645
+#------------------------------------------------------------
+
+part
+    id               = "m645";
+    desc             = "ATMEGA645";
+    signature        = 0x1E 0x96 0x05;
+    has_jtag         = yes;
+#   stk500_devcode   = 0x??; # No STK500v1 support?
+#   avr910_devcode   = 0x??; # Try the ATmega16 one
+    avr910_devcode   = 0x74;
+    pagel            = 0xd7;
+    bs2              = 0xa0;
+    chip_erase_delay = 9000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "0 0 0 0  0 0 0 0    0 0 0 0  0 0 0 0";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "0 0 0 0  0 0 0 0    0 0 0 0  0 0 0 0";
+
+    timeout             = 200;
+    stabdelay           = 100;
+    cmdexedelay         = 25;
+    synchloops          = 32;
+    bytedelay           = 0;
+    pollindex           = 3;
+    pollvalue           = 0x53;
+    predelay            = 1;
+    postdelay           = 1;
+    pollmethod          = 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+    allowfullpagebitstream = no;
+
+    memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 8;  /* for parallel programming */
+        size            = 2048;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read            = "  1   0   1   0      0   0   0   0",
+                          "  0   0   0   0      0 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        write           = "  1   1   0   0      0   0   0   0",
+                          "  0   0   0   0      0 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_lo     = "  1   1   0   0      0   0   0   1",
+                          "  0   0   0   0      0   0   0   0",
+                          "  0   0   0   0      0  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  1   1   0   0      0   0   1   0",
+                          "  0   0   0   0      0 a10  a9  a8",
+                          " a7  a6  a5  a4     a3   0   0   0",
+                          "  x   x   x   x      x   x   x   x";
+
+        mode            = 0x41;
+        delay           = 10;
+        blocksize       = 8;
+        readsize        = 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 65536;
+        page_size       = 256;
+        num_pages       = 256;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "   0   0   1   0      0   0   0   0",
+                          " a15 a14 a13 a12    a11 a10  a9  a8",
+                          "  a7  a6  a5  a4     a3  a2  a1  a0",
+                          "   o   o   o   o      o   o   o   o";
+
+        read_hi         = "   0   0   1   0      1   0   0   0",
+                          " a15 a14 a13 a12    a11 a10  a9  a8",
+                          "  a7  a6  a5  a4     a3  a2  a1  a0",
+                          "   o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  0   0   0   0      0   0   0   0",
+                          "  a7 a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  0   0   0   0      0   0   0   0",
+                          "  a7 a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "   0   1   0   0      1   1   0   0",
+                          " a15 a14 a13 a12    a11 a10  a9  a8",
+                          "  a7  a6  a5  a4     a3  a2  a1  a0",
+                          "   0   0   0   0      0   0   0   0";
+
+        mode            = 0x41;
+        delay           = 10;
+        blocksize       = 128;
+        readsize        = 256;
+      ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 0  0 0 0 0",
+                          "0 0 0 0  0 0 0 0   1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  0 0 0 0",
+                          "0 0 0 0  0 0 0 0   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 0 0 0",
+                          "0 0 0 0  0 0 0 0   i i i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  1 0 0 0",
+                          "0 0 0 0  0 0 0 0   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  1 0 0 0",
+                          "0 0 0 0  0 0 0 0   i i i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "efuse"
+        size            = 1;
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                          "0 0 0 0  0 0 0 0  o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                          "0 0 0 0  0 0 0 0  1 1 1 1  1 i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   0  0  0  0   0  0  0  0",
+                          "0  0  0  0   0  0 a1 a0   o  o  o  o   o  o  o  o";
+      ;
+
+    memory "calibration"
+        size            = 1;
+
+        read            = "0 0 1 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "0 0 0 0  0 0 0 0   o o o o  o o o o";
+        ;
+  ;
+
+#------------------------------------------------------------
+# ATmega3250
+#------------------------------------------------------------
+
+part
+    id               = "m3250";
+    desc             = "ATMEGA3250";
+    signature        = 0x1E 0x95 0x06;
+    has_jtag         = yes;
+#   stk500_devcode   = 0x??; # No STK500v1 support?
+#   avr910_devcode   = 0x??; # Try the ATmega16 one
+    avr910_devcode   = 0x74;
+    pagel            = 0xd7;
+    bs2              = 0xa0;
+    chip_erase_delay = 9000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "0 0 0 0  0 0 0 0    0 0 0 0  0 0 0 0";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "0 0 0 0  0 0 0 0    0 0 0 0  0 0 0 0";
+
+    timeout             = 200;
+    stabdelay           = 100;
+    cmdexedelay         = 25;
+    synchloops          = 32;
+    bytedelay           = 0;
+    pollindex           = 3;
+    pollvalue           = 0x53;
+    predelay            = 1;
+    postdelay           = 1;
+    pollmethod          = 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+    allowfullpagebitstream = no;
+
+    memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 4;  /* for parallel programming */
+        size            = 1024;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read            = "  1   0   1   0      0   0   0   0",
+                          "  0   0   0   0      0   0  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        write           = "  1   1   0   0      0   0   0   0",
+                          "  0   0   0   0      0   0  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_lo     = "  1   1   0   0      0   0   0   1",
+                          "  0   0   0   0      0   0   0   0",
+                          "  0   0   0   0      0   0  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  1   1   0   0      0   0   1   0",
+                          "  0   0   0   0      0   0  a9  a8",
+                          " a7  a6  a5  a4     a3  a2   0   0",
+                          "  x   x   x   x      x   x   x   x";
+
+        mode            = 0x41;
+        delay           = 10;
+        blocksize       = 4;
+        readsize        = 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 32768;
+        page_size       = 128;
+        num_pages       = 256;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "  0   0   1   0      0   0   0   0",
+                          "  0 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        read_hi         = "  0   0   1   0      1   0   0   0",
+                          "  0 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  0   0   0   0      0   0   0   0",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  0   0   0   0      0   0   0   0",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  0   1   0   0      1   1   0   0",
+                          "  0 a14 a13 a12    a11 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  x   x   x   x      x   x   x   x";
+
+        mode            = 0x41;
+        delay           = 10;
+        blocksize       = 128;
+        readsize        = 256;
+      ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 0  0 0 0 0",
+                          "0 0 0 0  0 0 0 0   1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  0 0 0 0",
+                          "0 0 0 0  0 0 0 0   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 0 0 0",
+                          "0 0 0 0  0 0 0 0   i i i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  1 0 0 0",
+                          "0 0 0 0  0 0 0 0   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  1 0 0 0",
+                          "0 0 0 0  0 0 0 0   i i i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "efuse"
+        size            = 1;
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                          "0 0 0 0  0 0 0 0  o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                          "0 0 0 0  0 0 0 0  1 1 1 1  1 i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   0  0  0  0   0  0  0  0",
+                          "0  0  0  0   0  0 a1 a0   o  o  o  o   o  o  o  o";
+      ;
+
+    memory "calibration"
+        size            = 1;
+
+        read            = "0 0 1 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "0 0 0 0  0 0 0 0   o o o o  o o o o";
+        ;
+  ;
+
+#------------------------------------------------------------
+# ATmega6450
+#------------------------------------------------------------
+
+part
+    id               = "m6450";
+    desc             = "ATMEGA6450";
+    signature        = 0x1E 0x96 0x06;
+    has_jtag         = yes;
+#   stk500_devcode   = 0x??; # No STK500v1 support?
+#   avr910_devcode   = 0x??; # Try the ATmega16 one
+    avr910_devcode   = 0x74;
+    pagel            = 0xd7;
+    bs2              = 0xa0;
+    chip_erase_delay = 9000;
+    pgm_enable       = "1 0 1 0  1 1 0 0    0 1 0 1  0 0 1 1",
+                       "0 0 0 0  0 0 0 0    0 0 0 0  0 0 0 0";
+
+    chip_erase       = "1 0 1 0  1 1 0 0    1 0 0 0  0 0 0 0",
+                       "0 0 0 0  0 0 0 0    0 0 0 0  0 0 0 0";
+
+    timeout             = 200;
+    stabdelay           = 100;
+    cmdexedelay         = 25;
+    synchloops          = 32;
+    bytedelay           = 0;
+    pollindex           = 3;
+    pollvalue           = 0x53;
+    predelay            = 1;
+    postdelay           = 1;
+    pollmethod          = 1;
+
+    pp_controlstack     =
+        0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
+        0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
+        0x66, 0x76, 0x67, 0x77, 0x6A, 0x7A, 0x6B, 0x7B,
+        0xBE, 0xFD, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00;
+    hventerstabdelay    = 100;
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    resetdelayus        = 0;
+    hvleavestabdelay    = 15;
+    chiperasepulsewidth = 0;
+    chiperasepolltimeout = 10;
+    programfusepulsewidth = 0;
+    programfusepolltimeout = 5;
+    programlockpulsewidth = 0;
+    programlockpolltimeout = 5;
+
+    idr                 = 0x31;
+    spmcr               = 0x57;
+    allowfullpagebitstream = no;
+
+    memory "eeprom"
+        paged           = no; /* leave this "no" */
+        page_size       = 8;  /* for parallel programming */
+        size            = 2048;
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read            = "  1   0   1   0      0   0   0   0",
+                          "  0   0   0   0      0 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  o   o   o   o      o   o   o   o";
+
+        write           = "  1   1   0   0      0   0   0   0",
+                          "  0   0   0   0      0 a10  a9  a8",
+                          " a7  a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_lo     = "  1   1   0   0      0   0   0   1",
+                          "  0   0   0   0      0   0   0   0",
+                          "  0   0   0   0      0  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "  1   1   0   0      0   0   1   0",
+                          "  0   0   0   0      0 a10  a9  a8",
+                          " a7  a6  a5  a4     a3   0   0   0",
+                          "  x   x   x   x      x   x   x   x";
+
+        mode            = 0x41;
+        delay           = 10;
+        blocksize       = 4;
+        readsize        = 256;
+      ;
+
+    memory "flash"
+        paged           = yes;
+        size            = 65536;
+        page_size       = 256;
+        num_pages       = 256;
+        min_write_delay = 4500;
+        max_write_delay = 4500;
+        readback_p1     = 0xff;
+        readback_p2     = 0xff;
+        read_lo         = "   0   0   1   0      0   0   0   0",
+                          " a15 a14 a13 a12    a11 a10  a9  a8",
+                          "  a7  a6  a5  a4     a3  a2  a1  a0",
+                          "   o   o   o   o      o   o   o   o";
+
+        read_hi         = "   0   0   1   0      1   0   0   0",
+                          " a15 a14 a13 a12    a11 a10  a9  a8",
+                          "  a7  a6  a5  a4     a3  a2  a1  a0",
+                          "   o   o   o   o      o   o   o   o";
+
+        loadpage_lo     = "  0   1   0   0      0   0   0   0",
+                          "  0   0   0   0      0   0   0   0",
+                          "  a7 a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        loadpage_hi     = "  0   1   0   0      1   0   0   0",
+                          "  0   0   0   0      0   0   0   0",
+                          "  a7 a6  a5  a4     a3  a2  a1  a0",
+                          "  i   i   i   i      i   i   i   i";
+
+        writepage       = "   0   1   0   0      1   1   0   0",
+                          " a15 a14 a13 a12    a11 a10  a9  a8",
+                          "  a7  a6  a5  a4     a3  a2  a1  a0",
+                          "   0   0   0   0      0   0   0   0";
+
+        mode            = 0x41;
+        delay           = 10;
+        blocksize       = 128;
+        readsize        = 256;
+      ;
+
+    memory "lock"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "x x x x  x x x x   x x o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 1 1 0  0 0 0 0",
+                          "0 0 0 0  0 0 0 0   1 1 i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "lfuse"
+        size            = 1;
+        read            = "0 1 0 1  0 0 0 0   0 0 0 0  0 0 0 0",
+                          "0 0 0 0  0 0 0 0   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  0 0 0 0",
+                          "0 0 0 0  0 0 0 0   i i i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "hfuse"
+        size            = 1;
+        read            = "0 1 0 1  1 0 0 0   0 0 0 0  1 0 0 0",
+                          "0 0 0 0  0 0 0 0   o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0   1 0 1 0  1 0 0 0",
+                          "0 0 0 0  0 0 0 0   i i i i  i i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "efuse"
+        size            = 1;
+
+        read            = "0 1 0 1  0 0 0 0  0 0 0 0  1 0 0 0",
+                          "0 0 0 0  0 0 0 0  o o o o  o o o o";
+
+        write           = "1 0 1 0  1 1 0 0  1 0 1 0  0 1 0 0",
+                          "0 0 0 0  0 0 0 0  1 1 1 1  1 i i i";
+        min_write_delay = 9000;
+        max_write_delay = 9000;
+      ;
+
+    memory "signature"
+        size            = 3;
+        read            = "0  0  1  1   0  0  0  0   0  0  0  0   0  0  0  0",
+                          "0  0  0  0   0  0 a1 a0   o  o  o  o   o  o  o  o";
+      ;
+
+    memory "calibration"
+        size            = 1;
+
+        read            = "0 0 1 1  1 0 0 0   0 0 0 0  0 0 0 0",
+                          "0 0 0 0  0 0 0 0   o o o o  o o o o";
+        ;
+  ;
+
+#------------------------------------------------------------
+# ATXMEGA64A1
+#------------------------------------------------------------
+
+part
+    id		= "x64a1";
+    desc	= "ATXMEGA64A1";
+    signature	= 0x1e 0x96 0x4e;
+    has_jtag	= yes;
+    has_pdi	= yes;
+    nvm_base	= 0x01c0;
+
+    memory "eeprom"
+        size		= 0x0800;
+        offset		= 0x08c0000;
+        page_size	= 0x20;
+        readsize	= 0x100;
+    ;
+
+    memory "application"
+        size		= 0x00010000;
+        offset		= 0x0800000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "apptable"
+        size		= 0x00001000;
+        offset		= 0x0080f000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "boot"
+        size		= 0x00001000;
+        offset		= 0x00810000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "flash"
+        size		= 0x00011000;
+        offset		= 0x0800000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "prodsig"
+        size		= 0x200;
+        offset		= 0x8e0200;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "usersig"
+        size		= 0x200;
+        offset		= 0x8e0400;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "signature"
+        size		= 3;
+        offset		= 0x1000090;
+    ;
+
+    memory "fuse0"
+        size		= 1;
+        offset		= 0x8f0020;
+    ;
+
+    memory "fuse1"
+        size		= 1;
+        offset		= 0x8f0021;
+    ;
+
+    memory "fuse2"
+        size		= 1;
+        offset		= 0x8f0022;
+    ;
+
+    memory "fuse4"
+        size		= 1;
+        offset		= 0x8f0024;
+    ;
+
+    memory "fuse5"
+        size		= 1;
+        offset		= 0x8f0025;
+    ;
+
+    memory "lock"
+        size		= 1;
+        offset		= 0x8f0027;
+    ;
+;
+
+#------------------------------------------------------------
+# ATXMEGA128A1
+#------------------------------------------------------------
+
+part
+    id		= "x128a1";
+    desc	= "ATXMEGA128A1";
+    signature	= 0x1e 0x97 0x4c;
+    has_jtag	= yes;
+    has_pdi	= yes;
+    nvm_base	= 0x01c0;
+
+    memory "eeprom"
+        size		= 0x0800;
+        offset		= 0x08c0000;
+        page_size	= 0x20;
+        readsize	= 0x100;
+    ;
+
+    memory "application"
+        size		= 0x00020000;
+        offset		= 0x0800000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "apptable"
+        size		= 0x00002000;
+        offset		= 0x0081e000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "boot"
+        size		= 0x00002000;
+        offset		= 0x00820000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "flash"
+        size		= 0x00022000;
+        offset		= 0x0800000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "prodsig"
+        size		= 0x200;
+        offset		= 0x8e0200;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "usersig"
+        size		= 0x200;
+        offset		= 0x8e0400;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "signature"
+        size		= 3;
+        offset		= 0x1000090;
+    ;
+
+    memory "fuse0"
+        size		= 1;
+        offset		= 0x8f0020;
+    ;
+
+    memory "fuse1"
+        size		= 1;
+        offset		= 0x8f0021;
+    ;
+
+    memory "fuse2"
+        size		= 1;
+        offset		= 0x8f0022;
+    ;
+
+    memory "fuse4"
+        size		= 1;
+        offset		= 0x8f0024;
+    ;
+
+    memory "fuse5"
+        size		= 1;
+        offset		= 0x8f0025;
+    ;
+
+    memory "lock"
+        size		= 1;
+        offset		= 0x8f0027;
+    ;
+;
+
+#------------------------------------------------------------
+# ATXMEGA128A1REVD
+#------------------------------------------------------------
+
+part
+    id		= "x128a1d";
+    desc	= "ATXMEGA128A1REVD";
+    signature	= 0x1e 0x97 0x41;
+    has_jtag	= yes;
+    has_pdi	= yes;
+    nvm_base	= 0x01c0;
+
+    memory "eeprom"
+        size		= 0x0800;
+        offset		= 0x08c0000;
+        page_size	= 0x20;
+        readsize	= 0x100;
+    ;
+
+    memory "application"
+        size		= 0x00020000;
+        offset		= 0x0800000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "apptable"
+        size		= 0x00002000;
+        offset		= 0x0081e000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "boot"
+        size		= 0x00002000;
+        offset		= 0x00820000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "flash"
+        size		= 0x00022000;
+        offset		= 0x0800000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "prodsig"
+        size		= 0x200;
+        offset		= 0x8e0200;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "usersig"
+        size		= 0x200;
+        offset		= 0x8e0400;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "signature"
+        size		= 3;
+        offset		= 0x1000090;
+    ;
+
+    memory "fuse0"
+        size		= 1;
+        offset		= 0x8f0020;
+    ;
+
+    memory "fuse1"
+        size		= 1;
+        offset		= 0x8f0021;
+    ;
+
+    memory "fuse2"
+        size		= 1;
+        offset		= 0x8f0022;
+    ;
+
+    memory "fuse4"
+        size		= 1;
+        offset		= 0x8f0024;
+    ;
+
+    memory "fuse5"
+        size		= 1;
+        offset		= 0x8f0025;
+    ;
+
+    memory "lock"
+        size		= 1;
+        offset		= 0x8f0027;
+    ;
+;
+
+#------------------------------------------------------------
+# ATXMEGA192A1
+#------------------------------------------------------------
+
+part
+    id		= "x192a1";
+    desc	= "ATXMEGA192A1";
+    signature	= 0x1e 0x97 0x4e;
+    has_jtag	= yes;
+    has_pdi	= yes;
+    nvm_base	= 0x01c0;
+
+    memory "eeprom"
+        size		= 0x0800;
+        offset		= 0x08c0000;
+        page_size	= 0x20;
+        readsize	= 0x100;
+    ;
+
+    memory "application"
+        size		= 0x00030000;
+        offset		= 0x0800000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "apptable"
+        size		= 0x00002000;
+        offset		= 0x0082e000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "boot"
+        size		= 0x00002000;
+        offset		= 0x00830000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "flash"
+        size		= 0x00032000;
+        offset		= 0x0800000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "prodsig"
+        size		= 0x200;
+        offset		= 0x8e0200;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "usersig"
+        size		= 0x200;
+        offset		= 0x8e0400;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "signature"
+        size		= 3;
+        offset		= 0x1000090;
+    ;
+
+    memory "fuse0"
+        size		= 1;
+        offset		= 0x8f0020;
+    ;
+
+    memory "fuse1"
+        size		= 1;
+        offset		= 0x8f0021;
+    ;
+
+    memory "fuse2"
+        size		= 1;
+        offset		= 0x8f0022;
+    ;
+
+    memory "fuse4"
+        size		= 1;
+        offset		= 0x8f0024;
+    ;
+
+    memory "fuse5"
+        size		= 1;
+        offset		= 0x8f0025;
+    ;
+
+    memory "lock"
+        size		= 1;
+        offset		= 0x8f0027;
+    ;
+;
+
+#------------------------------------------------------------
+# ATXMEGA256A1
+#------------------------------------------------------------
+
+part
+    id		= "x256a1";
+    desc	= "ATXMEGA256A1";
+    signature	= 0x1e 0x98 0x46;
+    has_jtag	= yes;
+    has_pdi	= yes;
+    nvm_base	= 0x01c0;
+
+    memory "eeprom"
+        size		= 0x1000;
+        offset		= 0x08c0000;
+        page_size	= 0x20;
+        readsize	= 0x100;
+    ;
+
+    memory "application"
+        size		= 0x00040000;
+        offset		= 0x0800000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "apptable"
+        size		= 0x00002000;
+        offset		= 0x0083e000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "boot"
+        size		= 0x00002000;
+        offset		= 0x00840000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "flash"
+        size		= 0x00042000;
+        offset		= 0x0800000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "prodsig"
+        size		= 0x200;
+        offset		= 0x8e0200;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "usersig"
+        size		= 0x200;
+        offset		= 0x8e0400;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "signature"
+        size		= 3;
+        offset		= 0x1000090;
+    ;
+
+    memory "fuse0"
+        size		= 1;
+        offset		= 0x8f0020;
+    ;
+
+    memory "fuse1"
+        size		= 1;
+        offset		= 0x8f0021;
+    ;
+
+    memory "fuse2"
+        size		= 1;
+        offset		= 0x8f0022;
+    ;
+
+    memory "fuse4"
+        size		= 1;
+        offset		= 0x8f0024;
+    ;
+
+    memory "fuse5"
+        size		= 1;
+        offset		= 0x8f0025;
+    ;
+
+    memory "lock"
+        size		= 1;
+        offset		= 0x8f0027;
+    ;
+;
+
+#------------------------------------------------------------
+# ATXMEGA64A3
+#------------------------------------------------------------
+
+part
+    id		= "x64a3";
+    desc	= "ATXMEGA64A3";
+    signature	= 0x1e 0x96 0x42;
+    has_jtag	= yes;
+    has_pdi	= yes;
+    nvm_base	= 0x01c0;
+
+    memory "eeprom"
+        size		= 0x0800;
+        offset		= 0x08c0000;
+        page_size	= 0x20;
+        readsize	= 0x100;
+    ;
+
+    memory "application"
+        size		= 0x00010000;
+        offset		= 0x0800000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "apptable"
+        size		= 0x00001000;
+        offset		= 0x0080f000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "boot"
+        size		= 0x00001000;
+        offset		= 0x00810000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "flash"
+        size		= 0x00011000;
+        offset		= 0x0800000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "prodsig"
+        size		= 0x200;
+        offset		= 0x8e0200;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "usersig"
+        size		= 0x200;
+        offset		= 0x8e0400;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "signature"
+        size		= 3;
+        offset		= 0x1000090;
+    ;
+
+    memory "fuse0"
+        size		= 1;
+        offset		= 0x8f0020;
+    ;
+
+    memory "fuse1"
+        size		= 1;
+        offset		= 0x8f0021;
+    ;
+
+    memory "fuse2"
+        size		= 1;
+        offset		= 0x8f0022;
+    ;
+
+    memory "fuse4"
+        size		= 1;
+        offset		= 0x8f0024;
+    ;
+
+    memory "fuse5"
+        size		= 1;
+        offset		= 0x8f0025;
+    ;
+
+    memory "lock"
+        size		= 1;
+        offset		= 0x8f0027;
+    ;
+;
+
+#------------------------------------------------------------
+# ATXMEGA128A3
+#------------------------------------------------------------
+
+part
+    id		= "x128a3";
+    desc	= "ATXMEGA128A3";
+    signature	= 0x1e 0x97 0x42;
+    has_jtag	= yes;
+    has_pdi	= yes;
+    nvm_base	= 0x01c0;
+
+    memory "eeprom"
+        size		= 0x0800;
+        offset		= 0x08c0000;
+        page_size	= 0x20;
+        readsize	= 0x100;
+    ;
+
+    memory "application"
+        size		= 0x00020000;
+        offset		= 0x0800000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "apptable"
+        size		= 0x00002000;
+        offset		= 0x0081e000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "boot"
+        size		= 0x00002000;
+        offset		= 0x00820000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "flash"
+        size		= 0x00022000;
+        offset		= 0x0800000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "prodsig"
+        size		= 0x200;
+        offset		= 0x8e0200;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "usersig"
+        size		= 0x200;
+        offset		= 0x8e0400;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "signature"
+        size		= 3;
+        offset		= 0x1000090;
+    ;
+
+    memory "fuse0"
+        size		= 1;
+        offset		= 0x8f0020;
+    ;
+
+    memory "fuse1"
+        size		= 1;
+        offset		= 0x8f0021;
+    ;
+
+    memory "fuse2"
+        size		= 1;
+        offset		= 0x8f0022;
+    ;
+
+    memory "fuse4"
+        size		= 1;
+        offset		= 0x8f0024;
+    ;
+
+    memory "fuse5"
+        size		= 1;
+        offset		= 0x8f0025;
+    ;
+
+    memory "lock"
+        size		= 1;
+        offset		= 0x8f0027;
+    ;
+;
+
+#------------------------------------------------------------
+# ATXMEGA192A3
+#------------------------------------------------------------
+
+part
+    id		= "x192a3";
+    desc	= "ATXMEGA192A3";
+    signature	= 0x1e 0x97 0x44;
+    has_jtag	= yes;
+    has_pdi	= yes;
+    nvm_base	= 0x01c0;
+
+    memory "eeprom"
+        size		= 0x0800;
+        offset		= 0x08c0000;
+        page_size	= 0x20;
+        readsize	= 0x100;
+    ;
+
+    memory "application"
+        size		= 0x00030000;
+        offset		= 0x0800000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "apptable"
+        size		= 0x00002000;
+        offset		= 0x0082e000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "boot"
+        size		= 0x00002000;
+        offset		= 0x00830000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "flash"
+        size		= 0x00032000;
+        offset		= 0x0800000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "prodsig"
+        size		= 0x200;
+        offset		= 0x8e0200;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "usersig"
+        size		= 0x200;
+        offset		= 0x8e0400;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "signature"
+        size		= 3;
+        offset		= 0x1000090;
+    ;
+
+    memory "fuse0"
+        size		= 1;
+        offset		= 0x8f0020;
+    ;
+
+    memory "fuse1"
+        size		= 1;
+        offset		= 0x8f0021;
+    ;
+
+    memory "fuse2"
+        size		= 1;
+        offset		= 0x8f0022;
+    ;
+
+    memory "fuse4"
+        size		= 1;
+        offset		= 0x8f0024;
+    ;
+
+    memory "fuse5"
+        size		= 1;
+        offset		= 0x8f0025;
+    ;
+
+    memory "lock"
+        size		= 1;
+        offset		= 0x8f0027;
+    ;
+;
+
+#------------------------------------------------------------
+# ATXMEGA256A3
+#------------------------------------------------------------
+
+part
+    id		= "x256a3";
+    desc	= "ATXMEGA256A3";
+    signature	= 0x1e 0x98 0x42;
+    has_jtag	= yes;
+    has_pdi	= yes;
+    nvm_base	= 0x01c0;
+
+    memory "eeprom"
+        size		= 0x1000;
+        offset		= 0x08c0000;
+        page_size	= 0x20;
+        readsize	= 0x100;
+    ;
+
+    memory "application"
+        size		= 0x00040000;
+        offset		= 0x0800000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "apptable"
+        size		= 0x00002000;
+        offset		= 0x0083e000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "boot"
+        size		= 0x00002000;
+        offset		= 0x00840000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "flash"
+        size		= 0x00042000;
+        offset		= 0x0800000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "prodsig"
+        size		= 0x200;
+        offset		= 0x8e0200;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "usersig"
+        size		= 0x200;
+        offset		= 0x8e0400;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "signature"
+        size		= 3;
+        offset		= 0x1000090;
+    ;
+
+    memory "fuse0"
+        size		= 1;
+        offset		= 0x8f0020;
+    ;
+
+    memory "fuse1"
+        size		= 1;
+        offset		= 0x8f0021;
+    ;
+
+    memory "fuse2"
+        size		= 1;
+        offset		= 0x8f0022;
+    ;
+
+    memory "fuse4"
+        size		= 1;
+        offset		= 0x8f0024;
+    ;
+
+    memory "fuse5"
+        size		= 1;
+        offset		= 0x8f0025;
+    ;
+
+    memory "lock"
+        size		= 1;
+        offset		= 0x8f0027;
+    ;
+;
+
+#------------------------------------------------------------
+# ATXMEGA256A3B
+#------------------------------------------------------------
+
+part
+    id		= "x256a3b";
+    desc	= "ATXMEGA256A3B";
+    signature	= 0x1e 0x98 0x43;
+    has_jtag	= yes;
+    has_pdi	= yes;
+    nvm_base	= 0x01c0;
+
+    memory "eeprom"
+        size		= 0x1000;
+        offset		= 0x08c0000;
+        page_size	= 0x20;
+        readsize	= 0x100;
+    ;
+
+    memory "application"
+        size		= 0x00040000;
+        offset		= 0x0800000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "apptable"
+        size		= 0x00002000;
+        offset		= 0x0083e000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "boot"
+        size		= 0x00002000;
+        offset		= 0x00840000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "flash"
+        size		= 0x00042000;
+        offset		= 0x0800000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "prodsig"
+        size		= 0x200;
+        offset		= 0x8e0200;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "usersig"
+        size		= 0x200;
+        offset		= 0x8e0400;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "signature"
+        size		= 3;
+        offset		= 0x1000090;
+    ;
+
+    memory "fuse0"
+        size		= 1;
+        offset		= 0x8f0020;
+    ;
+
+    memory "fuse1"
+        size		= 1;
+        offset		= 0x8f0021;
+    ;
+
+    memory "fuse2"
+        size		= 1;
+        offset		= 0x8f0022;
+    ;
+
+    memory "fuse4"
+        size		= 1;
+        offset		= 0x8f0024;
+    ;
+
+    memory "fuse5"
+        size		= 1;
+        offset		= 0x8f0025;
+    ;
+
+    memory "lock"
+        size		= 1;
+        offset		= 0x8f0027;
+    ;
+;
+
+#------------------------------------------------------------
+# ATXMEGA16A4
+#------------------------------------------------------------
+
+part
+    id		= "x16a4";
+    desc	= "ATXMEGA16A4";
+    signature	= 0x1e 0x94 0x41;
+    has_jtag	= yes;
+    has_pdi	= yes;
+    nvm_base	= 0x01c0;
+
+    memory "eeprom"
+        size		= 0x0400;
+        offset		= 0x08c0000;
+        page_size	= 0x20;
+        readsize	= 0x100;
+    ;
+
+    memory "application"
+        size		= 0x00004000;
+        offset		= 0x0800000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "apptable"
+        size		= 0x00001000;
+        offset		= 0x00803000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "boot"
+        size		= 0x00001000;
+        offset		= 0x00804000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "flash"
+        size		= 0x00005000;
+        offset		= 0x0800000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "prodsig"
+        size		= 0x200;
+        offset		= 0x8e0200;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "usersig"
+        size		= 0x200;
+        offset		= 0x8e0400;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "signature"
+        size		= 3;
+        offset		= 0x1000090;
+    ;
+
+    memory "fuse0"
+        size		= 1;
+        offset		= 0x8f0020;
+    ;
+
+    memory "fuse1"
+        size		= 1;
+        offset		= 0x8f0021;
+    ;
+
+    memory "fuse2"
+        size		= 1;
+        offset		= 0x8f0022;
+    ;
+
+    memory "fuse4"
+        size		= 1;
+        offset		= 0x8f0024;
+    ;
+
+    memory "fuse5"
+        size		= 1;
+        offset		= 0x8f0025;
+    ;
+
+    memory "lock"
+        size		= 1;
+        offset		= 0x8f0027;
+    ;
+;
+
+#------------------------------------------------------------
+# ATXMEGA32A4
+#------------------------------------------------------------
+
+part
+    id		= "x32a4";
+    desc	= "ATXMEGA32A4";
+    signature	= 0x1e 0x95 0x41;
+    has_jtag	= yes;
+    has_pdi	= yes;
+    nvm_base	= 0x01c0;
+
+    memory "eeprom"
+        size		= 0x0400;
+        offset		= 0x08c0000;
+        page_size	= 0x20;
+        readsize	= 0x100;
+    ;
+
+    memory "application"
+        size		= 0x00008000;
+        offset		= 0x0800000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "apptable"
+        size		= 0x00001000;
+        offset		= 0x00807000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "boot"
+        size		= 0x00001000;
+        offset		= 0x00808000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "flash"
+        size		= 0x00009000;
+        offset		= 0x0800000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "prodsig"
+        size		= 0x200;
+        offset		= 0x8e0200;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "usersig"
+        size		= 0x200;
+        offset		= 0x8e0400;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "signature"
+        size		= 3;
+        offset		= 0x1000090;
+    ;
+
+    memory "fuse0"
+        size		= 1;
+        offset		= 0x8f0020;
+    ;
+
+    memory "fuse1"
+        size		= 1;
+        offset		= 0x8f0021;
+    ;
+
+    memory "fuse2"
+        size		= 1;
+        offset		= 0x8f0022;
+    ;
+
+    memory "fuse4"
+        size		= 1;
+        offset		= 0x8f0024;
+    ;
+
+    memory "fuse5"
+        size		= 1;
+        offset		= 0x8f0025;
+    ;
+
+    memory "lock"
+        size		= 1;
+        offset		= 0x8f0027;
+    ;
+;
+
+#------------------------------------------------------------
+# ATXMEGA64A4
+#------------------------------------------------------------
+
+part
+    id		= "x64a4";
+    desc	= "ATXMEGA64A4";
+    signature	= 0x1e 0x96 0x46;
+    has_jtag	= yes;
+    has_pdi	= yes;
+    nvm_base	= 0x01c0;
+
+    memory "eeprom"
+        size		= 0x0800;
+        offset		= 0x08c0000;
+        page_size	= 0x20;
+        readsize	= 0x100;
+    ;
+
+    memory "application"
+        size		= 0x00010000;
+        offset		= 0x0800000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "apptable"
+        size		= 0x00001000;
+        offset		= 0x0080f000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "boot"
+        size		= 0x00001000;
+        offset		= 0x00810000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "flash"
+        size		= 0x00011000;
+        offset		= 0x0800000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "prodsig"
+        size		= 0x200;
+        offset		= 0x8e0200;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "usersig"
+        size		= 0x200;
+        offset		= 0x8e0400;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "signature"
+        size		= 3;
+        offset		= 0x1000090;
+    ;
+
+    memory "fuse0"
+        size		= 1;
+        offset		= 0x8f0020;
+    ;
+
+    memory "fuse1"
+        size		= 1;
+        offset		= 0x8f0021;
+    ;
+
+    memory "fuse2"
+        size		= 1;
+        offset		= 0x8f0022;
+    ;
+
+    memory "fuse4"
+        size		= 1;
+        offset		= 0x8f0024;
+    ;
+
+    memory "fuse5"
+        size		= 1;
+        offset		= 0x8f0025;
+    ;
+
+    memory "lock"
+        size		= 1;
+        offset		= 0x8f0027;
+    ;
+;
+
+#------------------------------------------------------------
+# ATXMEGA128A4
+#------------------------------------------------------------
+
+part
+    id		= "x128a4";
+    desc	= "ATXMEGA128A4";
+    signature	= 0x1e 0x97 0x46;
+    has_jtag	= yes;
+    has_pdi	= yes;
+    nvm_base	= 0x01c0;
+
+    memory "eeprom"
+        size		= 0x0800;
+        offset		= 0x08c0000;
+        page_size	= 0x20;
+        readsize	= 0x100;
+    ;
+
+    memory "application"
+        size		= 0x00020000;
+        offset		= 0x0800000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "apptable"
+        size		= 0x00002000;
+        offset		= 0x0081e000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "boot"
+        size		= 0x00002000;
+        offset		= 0x00820000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "flash"
+        size		= 0x00022000;
+        offset		= 0x0800000;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "prodsig"
+        size		= 0x200;
+        offset		= 0x8e0200;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "usersig"
+        size		= 0x200;
+        offset		= 0x8e0400;
+        page_size	= 0x100;
+        readsize	= 0x100;
+    ;
+
+    memory "signature"
+        size		= 3;
+        offset		= 0x1000090;
+    ;
+
+    memory "fuse0"
+        size		= 1;
+        offset		= 0x8f0020;
+    ;
+
+    memory "fuse1"
+        size		= 1;
+        offset		= 0x8f0021;
+    ;
+
+    memory "fuse2"
+        size		= 1;
+        offset		= 0x8f0022;
+    ;
+
+    memory "fuse4"
+        size		= 1;
+        offset		= 0x8f0024;
+    ;
+
+    memory "fuse5"
+        size		= 1;
+        offset		= 0x8f0025;
+    ;
+
+    memory "lock"
+        size		= 1;
+        offset		= 0x8f0027;
+    ;
+;
+
+
+#------------------------------------------------------------
+# AVR32UC3A0512
+#------------------------------------------------------------
+
+part
+    id		= "ucr2";
+    desc	= "32UC3A0512";
+    signature	= 0xED 0xC0 0x3F;
+    has_jtag	= yes;
+    is_avr32    = yes;
+
+    memory "flash"
+        paged           = yes;
+        page_size		= 512;               # bytes
+        readsize		= 512;				 # bytes
+        num_pages       = 1024;              # could be set dynamicly
+        size			= 0x00080000;		 # could be set dynamicly
+        offset			= 0x80000000;
+    ;
+;
+
+#------------------------------------------------------------
+# ATtiny4
+#------------------------------------------------------------
+
+part
+    id		= "t4";
+    desc	= "ATtiny4";
+    signature	= 0x1e 0x8f 0x0a;
+    has_tpi	= yes;
+
+    memory "flash"
+        size		= 512;
+        offset		= 0x4000;
+        page_size	= 16;
+        blocksize	= 128;
+    ;
+
+    memory "signature"
+        size		= 3;
+        offset		= 0x3fc0;
+    ;
+
+    memory "fuse"
+        size		= 1;
+        offset		= 0x3f40;
+	blocksize	= 4;
+    ;
+
+    memory "calibration"
+        size		= 1;
+        offset		= 0x3f80;
+    ;
+
+    memory "lockbits"
+        size		= 1;
+        offset		= 0x3f00;
+    ;
+;
+
+
+#------------------------------------------------------------
+# ATtiny5
+#------------------------------------------------------------
+
+part
+    id		= "t5";
+    desc	= "ATtiny5";
+    signature	= 0x1e 0x8f 0x09;
+    has_tpi	= yes;
+
+    memory "flash"
+        size		= 512;
+        offset		= 0x4000;
+        page_size	= 16;
+        blocksize	= 128;
+    ;
+
+    memory "signature"
+        size		= 3;
+        offset		= 0x3fc0;
+    ;
+
+    memory "fuse"
+        size		= 1;
+        offset		= 0x3f40;
+	blocksize	= 4;
+    ;
+
+    memory "calibration"
+        size		= 1;
+        offset		= 0x3f80;
+    ;
+
+    memory "lockbits"
+        size		= 1;
+        offset		= 0x3f00;
+    ;
+;
+
+
+#------------------------------------------------------------
+# ATtiny9
+#------------------------------------------------------------
+
+part
+    id		= "t8";
+    desc	= "ATtiny9";
+    signature	= 0x1e 0x90 0x08;
+    has_tpi	= yes;
+
+    memory "flash"
+        size		= 1024;
+        offset		= 0x4000;
+        page_size	= 16;
+        blocksize	= 128;
+    ;
+
+    memory "signature"
+        size		= 3;
+        offset		= 0x3fc0;
+    ;
+
+    memory "fuse"
+        size		= 1;
+        offset		= 0x3f40;
+	blocksize	= 4;
+    ;
+
+    memory "calibration"
+        size		= 1;
+        offset		= 0x3f80;
+    ;
+
+    memory "lockbits"
+        size		= 1;
+        offset		= 0x3f00;
+    ;
+;
+
+
+#------------------------------------------------------------
+# ATtiny10
+#------------------------------------------------------------
+
+part
+    id		= "t10";
+    desc	= "ATtiny10";
+    signature	= 0x1e 0x90 0x03;
+    has_tpi	= yes;
+
+    memory "flash"
+        size		= 1024;
+        offset		= 0x4000;
+        page_size	= 16;
+        blocksize	= 128;
+    ;
+
+    memory "signature"
+        size		= 3;
+        offset		= 0x3fc0;
+    ;
+
+    memory "fuse"
+        size		= 1;
+        offset		= 0x3f40;
+	blocksize	= 4;
+    ;
+
+    memory "calibration"
+        size		= 1;
+        offset		= 0x3f80;
+    ;
+
+    memory "lockbits"
+        size		= 1;
+        offset		= 0x3f00;
+    ;
+;
+
+
diff --git a/avrdude/avrdude.h b/avrdude/avrdude.h
new file mode 100644
index 00000000..2db9c9bd
--- /dev/null
+++ b/avrdude/avrdude.h
@@ -0,0 +1,61 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2007 Joerg Wunsch
+ *
+ * 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
+ */
+
+/* $Id$ */
+
+#ifndef avrdude_h
+#define avrdude_h
+
+extern char * progname;		/* name of program, for messages */
+extern char progbuf[];		/* spaces same length as progname */
+
+extern int do_cycles;		/* track erase-rewrite cycles (-y) */
+extern int ovsigck;		/* override signature check (-F) */
+extern int verbose;		/* verbosity level (-v, -vv, ...) */
+extern int quell_progress;	/* quiteness level (-q, -qq) */
+
+#if defined(WIN32NATIVE)
+
+#include "ac_cfg.h"
+#include <windows.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* usleep replacements */
+/* sleep Windows in ms, Unix usleep in us
+ #define usleep(us) Sleep((us)<20000?20:us/1000)
+ #define usleep(us) Sleep(us/1000)
+ #define ANTIWARP 3
+ #define usleep(us) Sleep(us/1000*ANTIWARP)
+*/
+int usleep(unsigned int us);
+
+#if !defined(HAVE_GETTIMEOFDAY)
+struct timezone;
+int gettimeofday(struct timeval *tv, struct timezone *tz);
+#ifdef __cplusplus
+}
+#endif
+#endif /* HAVE_GETTIMEOFDAY */
+
+#endif /* defined(WIN32NATIVE) */
+
+#endif
diff --git a/avrdude/avrdude.spec.in b/avrdude/avrdude.spec.in
new file mode 100644
index 00000000..ff9879f6
--- /dev/null
+++ b/avrdude/avrdude.spec.in
@@ -0,0 +1,113 @@
+## -*- mode: rpm-spec; -*-
+##
+## $Id$
+##
+## @configure_input@
+##
+
+%define debug_package %{nil}
+
+%define _with_docs 1
+%{?_without_docs: %define _with_docs 0}
+
+Summary: AVRDUDE is software for programming Atmel AVR Microcontrollers.
+Name: avrdude
+Version: @VERSION@
+Release: 1
+URL: http://savannah.nongnu.org/projects/avrdude
+Source0: %{name}-%{version}.tar.gz
+License: GPL
+Group: Development/Tools
+BuildRoot: %{_tmppath}/%{name}-%{version}-root
+
+%description
+AVRDUDE is software for programming Atmel AVR Microcontrollers.
+
+%if %{_with_docs}
+## The avrdude-docs subpackage
+%package docs
+Summary: Documentation for AVRDUDE.
+Group: Documentation
+%description docs
+Documentation for avrdude in info, html, postscript and pdf formats.
+%endif
+
+%prep
+%setup -q
+
+%build
+
+./configure --prefix=%{_prefix} --sysconfdir=/etc --mandir=%{_mandir} \
+	--infodir=%{_infodir} \
+%if %{_with_docs}
+	--enable-doc=yes
+%else
+	--enable-doc=no
+%endif
+
+make
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make prefix=$RPM_BUILD_ROOT%{_prefix} \
+	sysconfdir=$RPM_BUILD_ROOT/etc \
+	mandir=$RPM_BUILD_ROOT%{_mandir} \
+	infodir=$RPM_BUILD_ROOT%{_infodir} \
+	install
+
+rm -rf $RPM_BUILD_ROOT%{_datadir}/doc/%{name}-%{version}
+rm -f $RPM_BUILD_ROOT%{_infodir}/dir
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%if %{_with_docs}
+%post docs
+[ -f %{_infodir}/avrdude.info ] && \
+	/sbin/install-info %{_infodir}/avrdude.info %{_infodir}/dir || :
+[ -f %{_infodir}/avrdude.info.gz ] && \
+	/sbin/install-info %{_infodir}/avrdude.info.gz %{_infodir}/dir || :
+
+%preun docs
+if [ $1 = 0 ]; then
+	[ -f %{_infodir}/avrdude.info ] && \
+		/sbin/install-info --delete %{_infodir}/avrdude.info %{_infodir}/dir || :
+	[ -f %{_infodir}/avrdude.info.gz ] && \
+		/sbin/install-info --delete %{_infodir}/avrdude.info.gz %{_infodir}/dir || :
+fi
+%endif
+
+%files
+%defattr(-,root,root)
+%{_prefix}/bin/avrdude
+%{_mandir}/man1/avrdude.1.gz
+%attr(0644,root,root)   %config /etc/avrdude.conf
+
+%if %{_with_docs}
+%files docs
+%doc %{_infodir}/*info*
+%doc doc/avrdude-html/*.html
+%doc doc/TODO
+%doc doc/avrdude.ps
+%doc doc/avrdude.pdf
+%endif
+
+%changelog
+* Fri Sep 23 2005 Galen Seitz <galens@seitzassoc.com>
+- Default to enable-doc=yes during configure.
+- Move info file to docs package.
+- Make building of docs package conditional.  Basic idea copied from avr-gcc.
+
+* Wed Aug 27 2003 Theodore A. Roth <troth@openavr.org>
+  [Thanks to Artur Lipowski <LAL@pro.onet.pl>]
+- Do not build debug package.
+- Remove files not packaged to quell RH9 rpmbuild complaints.
+
+* Wed Mar 05 2003 Theodore A. Roth <troth@openavr.org>
+- Add docs sub-package.
+- Add %post and %preun scriptlets for handling info files.
+
+* Wed Feb 26 2003 Theodore A. Roth <troth@openavr.org>
+- Initial build.
+
+
diff --git a/avrdude/avrpart.c b/avrdude/avrpart.c
new file mode 100644
index 00000000..61994aac
--- /dev/null
+++ b/avrdude/avrpart.c
@@ -0,0 +1,547 @@
+
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2000-2004  Brian S. Dean <bsd@bsdhome.com>
+ * Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 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
+ */
+
+/* $Id$ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "avrdude.h"
+#include "avrpart.h"
+#include "pindefs.h"
+
+/***
+ *** Elementary functions dealing with OPCODE structures
+ ***/
+
+OPCODE * avr_new_opcode(void)
+{
+  OPCODE * m;
+
+  m = (OPCODE *)malloc(sizeof(*m));
+  if (m == NULL) {
+    fprintf(stderr, "avr_new_opcode(): out of memory\n");
+    exit(1);
+  }
+
+  memset(m, 0, sizeof(*m));
+
+  return m;
+}
+
+
+/*
+ * avr_set_bits()
+ *
+ * Set instruction bits in the specified command based on the opcode.
+ */
+int avr_set_bits(OPCODE * op, unsigned char * cmd)
+{
+  int i, j, bit;
+  unsigned char mask;
+
+  for (i=0; i<32; i++) {
+    if (op->bit[i].type == AVR_CMDBIT_VALUE) {
+      j = 3 - i / 8;
+      bit = i % 8;
+      mask = 1 << bit;
+      if (op->bit[i].value)
+        cmd[j] = cmd[j] | mask;
+      else
+        cmd[j] = cmd[j] & ~mask;
+    }
+  }
+
+  return 0;
+}
+
+
+/*
+ * avr_set_addr()
+ *
+ * Set address bits in the specified command based on the opcode, and
+ * the address.
+ */
+int avr_set_addr(OPCODE * op, unsigned char * cmd, unsigned long addr)
+{
+  int i, j, bit;
+  unsigned long value;
+  unsigned char mask;
+
+  for (i=0; i<32; i++) {
+    if (op->bit[i].type == AVR_CMDBIT_ADDRESS) {
+      j = 3 - i / 8;
+      bit = i % 8;
+      mask = 1 << bit;
+      value = addr >> op->bit[i].bitno & 0x01;
+      if (value)
+        cmd[j] = cmd[j] | mask;
+      else
+        cmd[j] = cmd[j] & ~mask;
+    }
+  }
+
+  return 0;
+}
+
+
+/*
+ * avr_set_input()
+ *
+ * Set input data bits in the specified command based on the opcode,
+ * and the data byte.
+ */
+int avr_set_input(OPCODE * op, unsigned char * cmd, unsigned char data)
+{
+  int i, j, bit;
+  unsigned char value;
+  unsigned char mask;
+
+  for (i=0; i<32; i++) {
+    if (op->bit[i].type == AVR_CMDBIT_INPUT) {
+      j = 3 - i / 8;
+      bit = i % 8;
+      mask = 1 << bit;
+      value = data >> op->bit[i].bitno & 0x01;
+      if (value)
+        cmd[j] = cmd[j] | mask;
+      else
+        cmd[j] = cmd[j] & ~mask;
+    }
+  }
+
+  return 0;
+}
+
+
+/*
+ * avr_get_output()
+ *
+ * Retreive output data bits from the command results based on the
+ * opcode data.
+ */
+int avr_get_output(OPCODE * op, unsigned char * res, unsigned char * data)
+{
+  int i, j, bit;
+  unsigned char value;
+  unsigned char mask;
+
+  for (i=0; i<32; i++) {
+    if (op->bit[i].type == AVR_CMDBIT_OUTPUT) {
+      j = 3 - i / 8;
+      bit = i % 8;
+      mask = 1 << bit;
+      value = ((res[j] & mask) >> bit) & 0x01;
+      value = value << op->bit[i].bitno;
+      if (value)
+        *data = *data | value;
+      else
+        *data = *data & ~value;
+    }
+  }
+
+  return 0;
+}
+
+
+static char * avr_op_str(int op)
+{
+  switch (op) {
+    case AVR_OP_READ        : return "READ"; break;
+    case AVR_OP_WRITE       : return "WRITE"; break;
+    case AVR_OP_READ_LO     : return "READ_LO"; break;
+    case AVR_OP_READ_HI     : return "READ_HI"; break;
+    case AVR_OP_WRITE_LO    : return "WRITE_LO"; break;
+    case AVR_OP_WRITE_HI    : return "WRITE_HI"; break;
+    case AVR_OP_LOADPAGE_LO : return "LOADPAGE_LO"; break;
+    case AVR_OP_LOADPAGE_HI : return "LOADPAGE_HI"; break;
+    case AVR_OP_LOAD_EXT_ADDR : return "LOAD_EXT_ADDR"; break;
+    case AVR_OP_WRITEPAGE   : return "WRITEPAGE"; break;
+    case AVR_OP_CHIP_ERASE  : return "CHIP_ERASE"; break;
+    case AVR_OP_PGM_ENABLE  : return "PGM_ENABLE"; break;
+    default : return "<unknown opcode>"; break;
+  }
+}
+
+
+static char * bittype(int type)
+{
+  switch (type) {
+    case AVR_CMDBIT_IGNORE  : return "IGNORE"; break;
+    case AVR_CMDBIT_VALUE   : return "VALUE"; break;
+    case AVR_CMDBIT_ADDRESS : return "ADDRESS"; break;
+    case AVR_CMDBIT_INPUT   : return "INPUT"; break;
+    case AVR_CMDBIT_OUTPUT  : return "OUTPUT"; break;
+    default : return "<unknown bit type>"; break;
+  }
+}
+
+
+
+/***
+ *** Elementary functions dealing with AVRMEM structures
+ ***/
+
+AVRMEM * avr_new_memtype(void)
+{
+  AVRMEM * m;
+
+  m = (AVRMEM *)malloc(sizeof(*m));
+  if (m == NULL) {
+    fprintf(stderr, "avr_new_memtype(): out of memory\n");
+    exit(1);
+  }
+
+  memset(m, 0, sizeof(*m));
+
+  return m;
+}
+
+
+/*
+ * Allocate and initialize memory buffers for each of the device's
+ * defined memory regions.
+ */
+int avr_initmem(AVRPART * p)
+{
+  LNODEID ln;
+  AVRMEM * m;
+
+  for (ln=lfirst(p->mem); ln; ln=lnext(ln)) {
+    m = ldata(ln);
+    m->buf = (unsigned char *) malloc(m->size);
+    if (m->buf == NULL) {
+      fprintf(stderr, "%s: can't alloc buffer for %s size of %d bytes\n",
+              progname, m->desc, m->size);
+      return -1;
+    }
+  }
+
+  return 0;
+}
+
+
+AVRMEM * avr_dup_mem(AVRMEM * m)
+{
+  AVRMEM * n;
+
+  n = avr_new_memtype();
+
+  *n = *m;
+
+  n->buf = (unsigned char *)malloc(n->size);
+  if (n->buf == NULL) {
+    fprintf(stderr,
+            "avr_dup_mem(): out of memory (memsize=%d)\n",
+            n->size);
+    exit(1);
+  }
+  memset(n->buf, 0, n->size);
+
+  return n;
+}
+
+
+AVRMEM * avr_locate_mem(AVRPART * p, char * desc)
+{
+  AVRMEM * m, * match;
+  LNODEID ln;
+  int matches;
+  int l;
+
+  l = strlen(desc);
+  matches = 0;
+  match = NULL;
+  for (ln=lfirst(p->mem); ln; ln=lnext(ln)) {
+    m = ldata(ln);
+    if (strncmp(desc, m->desc, l) == 0) {
+      match = m;
+      matches++;
+    }
+  }
+
+  if (matches == 1)
+    return match;
+
+  return NULL;
+}
+
+
+void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, int type,
+                     int verbose)
+{
+  int i, j;
+  char * optr;
+
+  if (m == NULL) {
+      fprintf(f,
+              "%s                       Block Poll               Page                       Polled\n"
+              "%sMemory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack\n"
+              "%s----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------\n",
+            prefix, prefix, prefix);
+  }
+  else {
+    if (verbose > 2) {
+      fprintf(f,
+              "%s                       Block Poll               Page                       Polled\n"
+              "%sMemory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack\n"
+              "%s----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------\n",
+              prefix, prefix, prefix);
+    }
+    fprintf(f,
+            "%s%-11s %4d %5d %5d %4d %-6s %6d %4d %6d %5d %5d 0x%02x 0x%02x\n",
+            prefix, m->desc, m->mode, m->delay, m->blocksize, m->pollindex,
+            m->paged ? "yes" : "no",
+            m->size,
+            m->page_size,
+            m->num_pages,
+            m->min_write_delay,
+            m->max_write_delay,
+            m->readback[0],
+            m->readback[1]);
+    if (verbose > 4) {
+      fprintf(stderr,
+              "%s  Memory Ops:\n"
+              "%s    Oeration     Inst Bit  Bit Type  Bitno  Value\n"
+              "%s    -----------  --------  --------  -----  -----\n",
+              prefix, prefix, prefix);
+      for (i=0; i<AVR_OP_MAX; i++) {
+        if (m->op[i]) {
+          for (j=31; j>=0; j--) {
+            if (j==31)
+              optr = avr_op_str(i);
+            else
+              optr = " ";
+          fprintf(f,
+                  "%s    %-11s  %8d  %8s  %5d  %5d\n",
+                  prefix, optr, j,
+                  bittype(m->op[i]->bit[j].type),
+                  m->op[i]->bit[j].bitno,
+                  m->op[i]->bit[j].value);
+          }
+        }
+      }
+    }
+  }
+}
+
+
+
+/*
+ * Elementary functions dealing with AVRPART structures
+ */
+
+
+AVRPART * avr_new_part(void)
+{
+  AVRPART * p;
+
+  p = (AVRPART *)malloc(sizeof(AVRPART));
+  if (p == NULL) {
+    fprintf(stderr, "new_part(): out of memory\n");
+    exit(1);
+  }
+
+  memset(p, 0, sizeof(*p));
+
+  p->id[0]   = 0;
+  p->desc[0] = 0;
+  p->reset_disposition = RESET_DEDICATED;
+  p->retry_pulse = PIN_AVR_SCK;
+  p->flags = AVRPART_SERIALOK | AVRPART_PARALLELOK | AVRPART_ENABLEPAGEPROGRAMMING;
+  p->config_file[0] = 0;
+  p->lineno = 0;
+  memset(p->signature, 0xFF, 3);
+  p->ctl_stack_type = CTL_STACK_NONE;
+
+  p->mem = lcreat(NULL, 0);
+
+  return p;
+}
+
+
+AVRPART * avr_dup_part(AVRPART * d)
+{
+  AVRPART * p;
+  LISTID save;
+  LNODEID ln;
+
+  p = avr_new_part();
+  save = p->mem;
+
+  *p = *d;
+
+  p->mem = save;
+
+  for (ln=lfirst(d->mem); ln; ln=lnext(ln)) {
+    ladd(p->mem, avr_dup_mem(ldata(ln)));
+  }
+
+  return p;
+}
+
+
+AVRPART * locate_part(LISTID parts, char * partdesc)
+{
+  LNODEID ln1;
+  AVRPART * p = NULL;
+  int found;
+
+  found = 0;
+
+  for (ln1=lfirst(parts); ln1 && !found; ln1=lnext(ln1)) {
+    p = ldata(ln1);
+    if ((strcasecmp(partdesc, p->id) == 0) ||
+        (strcasecmp(partdesc, p->desc) == 0))
+      found = 1;
+  }
+
+  if (found)
+    return p;
+
+  return NULL;
+}
+
+AVRPART * locate_part_by_avr910_devcode(LISTID parts, int devcode)
+{
+  LNODEID ln1;
+  AVRPART * p = NULL;
+
+  for (ln1=lfirst(parts); ln1; ln1=lnext(ln1)) {
+    p = ldata(ln1);
+    if (p->avr910_devcode == devcode)
+      return p;
+  }
+
+  return NULL;
+}
+
+/*
+ * Iterate over the list of avrparts given as "avrparts", and
+ * call the callback function cb for each entry found.  cb is being
+ * passed the following arguments:
+ * . the name of the avrpart (for -p)
+ * . the descriptive text given in the config file
+ * . the name of the config file this avrpart has been defined in
+ * . the line number of the config file this avrpart has been defined at
+ * . the "cookie" passed into walk_avrparts() (opaque client data)
+ */
+void walk_avrparts(LISTID avrparts, walk_avrparts_cb cb, void *cookie)
+{
+  LNODEID ln1;
+  AVRPART * p;
+
+  for (ln1 = lfirst(avrparts); ln1; ln1 = lnext(ln1)) {
+    p = ldata(ln1);
+    cb(p->id, p->desc, p->config_file, p->lineno, cookie);
+  }
+}
+
+
+
+static char * reset_disp_str(int r)
+{
+  switch (r) {
+    case RESET_DEDICATED : return "dedicated";
+    case RESET_IO        : return "possible i/o";
+    default              : return "<invalid>";
+  }
+}
+
+
+static char * pin_name(int pinno)
+{
+  switch (pinno) {
+    case PIN_AVR_RESET : return "RESET";
+    case PIN_AVR_MISO  : return "MISO";
+    case PIN_AVR_MOSI  : return "MOSI";
+    case PIN_AVR_SCK   : return "SCK";
+    default : return "<unknown>";
+  }
+}
+
+
+void avr_display(FILE * f, AVRPART * p, const char * prefix, int verbose)
+{
+  int i;
+  char * buf;
+  const char * px;
+  LNODEID ln;
+  AVRMEM * m;
+
+  fprintf(f,
+          "%sAVR Part                      : %s\n"
+          "%sChip Erase delay              : %d us\n"
+          "%sPAGEL                         : P%02X\n"
+          "%sBS2                           : P%02X\n"
+          "%sRESET disposition             : %s\n"
+          "%sRETRY pulse                   : %s\n"
+          "%sserial program mode           : %s\n"
+          "%sparallel program mode         : %s\n"
+          "%sTimeout                       : %d\n"
+          "%sStabDelay                     : %d\n"
+          "%sCmdexeDelay                   : %d\n"
+          "%sSyncLoops                     : %d\n"
+          "%sByteDelay                     : %d\n"
+          "%sPollIndex                     : %d\n"
+          "%sPollValue                     : 0x%02x\n"
+          "%sMemory Detail                 :\n\n",
+          prefix, p->desc,
+          prefix, p->chip_erase_delay,
+          prefix, p->pagel,
+          prefix, p->bs2,
+          prefix, reset_disp_str(p->reset_disposition),
+          prefix, pin_name(p->retry_pulse),
+          prefix, (p->flags & AVRPART_SERIALOK) ? "yes" : "no",
+          prefix, (p->flags & AVRPART_PARALLELOK) ?
+            ((p->flags & AVRPART_PSEUDOPARALLEL) ? "psuedo" : "yes") : "no",
+          prefix, p->timeout,
+          prefix, p->stabdelay,
+          prefix, p->cmdexedelay,
+          prefix, p->synchloops,
+          prefix, p->bytedelay,
+          prefix, p->pollindex,
+          prefix, p->pollvalue,
+          prefix);
+
+  px = prefix;
+  i = strlen(prefix) + 5;
+  buf = (char *)malloc(i);
+  if (buf == NULL) {
+    /* ugh, this is not important enough to bail, just ignore it */
+  }
+  else {
+    strcpy(buf, prefix);
+    strcat(buf, "  ");
+    px = buf;
+  }
+
+  if (verbose <= 2) {
+    avr_mem_display(px, f, NULL, 0, verbose);
+  }
+  for (ln=lfirst(p->mem); ln; ln=lnext(ln)) {
+    m = ldata(ln);
+    avr_mem_display(px, f, m, i, verbose);
+  }
+
+  if (buf)
+    free(buf);
+}
diff --git a/avrdude/avrpart.h b/avrdude/avrpart.h
new file mode 100644
index 00000000..04334609
--- /dev/null
+++ b/avrdude/avrpart.h
@@ -0,0 +1,225 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2003-2004  Brian S. Dean <bsd@bsdhome.com>
+ * Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 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
+ */
+
+/* $Id$ */
+
+#ifndef avrpart_h
+#define avrpart_h
+
+#include <limits.h>
+
+#include "lists.h"
+
+
+/*
+ * AVR serial programming instructions
+ */
+enum {
+  AVR_OP_READ,
+  AVR_OP_WRITE,
+  AVR_OP_READ_LO,
+  AVR_OP_READ_HI,
+  AVR_OP_WRITE_LO,
+  AVR_OP_WRITE_HI,
+  AVR_OP_LOADPAGE_LO,
+  AVR_OP_LOADPAGE_HI,
+  AVR_OP_LOAD_EXT_ADDR,
+  AVR_OP_WRITEPAGE,
+  AVR_OP_CHIP_ERASE,
+  AVR_OP_PGM_ENABLE,
+  AVR_OP_MAX
+};
+
+
+enum {
+  AVR_CMDBIT_IGNORE,  /* bit is ignored on input and output */
+  AVR_CMDBIT_VALUE,   /* bit is set to 0 or 1 for input or output */
+  AVR_CMDBIT_ADDRESS, /* this bit represents an input address bit */
+  AVR_CMDBIT_INPUT,   /* this bit is an input bit */
+  AVR_CMDBIT_OUTPUT   /* this bit is an output bit */
+};
+
+enum { /* these are assigned to reset_disposition of AVRPART */
+  RESET_DEDICATED,    /* reset pin is dedicated */
+  RESET_IO            /* reset pin might be configured as an I/O pin */
+};
+
+enum ctl_stack_t {
+  CTL_STACK_NONE,     /* no control stack defined */
+  CTL_STACK_PP,	      /* parallel programming control stack */
+  CTL_STACK_HVSP      /* high voltage serial programming control stack */
+};
+
+/*
+ * serial programming instruction bit specifications
+ */
+typedef struct cmdbit {
+  int          type;  /* AVR_CMDBIT_* */
+  int          bitno; /* which input bit to use for this command bit */
+  int          value; /* bit value if type == AVR_CMDBIT_VALUD */
+} CMDBIT;
+
+typedef struct opcode {
+  CMDBIT        bit[32]; /* opcode bit specs */
+} OPCODE;
+
+
+#define AVRPART_SERIALOK       0x0001  /* part supports serial programming */
+#define AVRPART_PARALLELOK     0x0002  /* part supports parallel programming */
+#define AVRPART_PSEUDOPARALLEL 0x0004  /* part has pseudo parallel support */
+#define AVRPART_HAS_JTAG       0x0008  /* part has a JTAG i/f */
+#define AVRPART_ALLOWFULLPAGEBITSTREAM 0x0010 /* JTAG ICE mkII param. */
+#define AVRPART_ENABLEPAGEPROGRAMMING 0x0020 /* JTAG ICE mkII param. */
+#define AVRPART_HAS_DW         0x0040  /* part has a debugWire i/f */
+#define AVRPART_HAS_PDI        0x0080  /* part has PDI i/f rather than ISP (ATxmega) */
+#define AVRPART_AVR32          0x0100  /* part is in AVR32 family */
+#define AVRPART_INIT_SMC       0x0200  /* part will undergo chip erase */
+#define AVRPART_WRITE          0x0400  /* at least one write operation specified */
+#define AVRPART_HAS_TPI        0x0800  /* part has TPI i/f rather than ISP (ATtiny4/5/9/10) */
+
+#define AVR_DESCLEN 64
+#define AVR_IDLEN   32
+#define CTL_STACK_SIZE 32
+#define FLASH_INSTR_SIZE 3
+#define EEPROM_INSTR_SIZE 20
+typedef struct avrpart {
+  char          desc[AVR_DESCLEN];  /* long part name */
+  char          id[AVR_IDLEN];      /* short part name */
+  int           stk500_devcode;     /* stk500 device code */
+  int           avr910_devcode;     /* avr910 device code */
+  int           chip_erase_delay;   /* microseconds */
+  unsigned char pagel;              /* for parallel programming */
+  unsigned char bs2;                /* for parallel programming */
+  unsigned char signature[3];       /* expected value of signature bytes */
+  int           reset_disposition;  /* see RESET_ enums */
+  int           retry_pulse;        /* retry program enable by pulsing
+                                       this pin (PIN_AVR_*) */
+  unsigned      flags;              /* see AVRPART_ masks */
+
+  int           timeout;            /* stk500 v2 xml file parameter */
+  int           stabdelay;          /* stk500 v2 xml file parameter */
+  int           cmdexedelay;        /* stk500 v2 xml file parameter */
+  int           synchloops;         /* stk500 v2 xml file parameter */
+  int           bytedelay;          /* stk500 v2 xml file parameter */
+  int           pollindex;          /* stk500 v2 xml file parameter */
+  unsigned char pollvalue;          /* stk500 v2 xml file parameter */
+  int           predelay;           /* stk500 v2 xml file parameter */
+  int           postdelay;          /* stk500 v2 xml file parameter */
+  int           pollmethod;         /* stk500 v2 xml file parameter */
+
+  enum ctl_stack_t ctl_stack_type;  /* what to use the ctl stack for */
+  unsigned char controlstack[CTL_STACK_SIZE]; /* stk500v2 PP/HVSP ctl stack */
+  unsigned char flash_instr[FLASH_INSTR_SIZE]; /* flash instructions (debugWire, JTAG) */
+  unsigned char eeprom_instr[EEPROM_INSTR_SIZE]; /* EEPROM instructions (debugWire, JTAG) */
+
+  int           hventerstabdelay;   /* stk500 v2 hv mode parameter */
+  int           progmodedelay;      /* stk500 v2 hv mode parameter */
+  int           latchcycles;        /* stk500 v2 hv mode parameter */
+  int           togglevtg;          /* stk500 v2 hv mode parameter */
+  int           poweroffdelay;      /* stk500 v2 hv mode parameter */
+  int           resetdelayms;       /* stk500 v2 hv mode parameter */
+  int           resetdelayus;       /* stk500 v2 hv mode parameter */
+  int           hvleavestabdelay;   /* stk500 v2 hv mode parameter */
+  int           resetdelay;         /* stk500 v2 hv mode parameter */
+  int           chiperasepulsewidth; /* stk500 v2 hv mode parameter */
+  int           chiperasepolltimeout; /* stk500 v2 hv mode parameter */
+  int           chiperasetime;      /* stk500 v2 hv mode parameter */
+  int           programfusepulsewidth; /* stk500 v2 hv mode parameter */
+  int           programfusepolltimeout; /* stk500 v2 hv mode parameter */
+  int           programlockpulsewidth; /* stk500 v2 hv mode parameter */
+  int           programlockpolltimeout; /* stk500 v2 hv mode parameter */
+  int           synchcycles;        /* stk500 v2 hv mode parameter */
+  int           hvspcmdexedelay;    /* stk500 v2 xml file parameter */
+
+  unsigned char idr;                /* JTAG ICE mkII XML file parameter */
+  unsigned char rampz;              /* JTAG ICE mkII XML file parameter */
+  unsigned char spmcr;              /* JTAG ICE mkII XML file parameter */
+  unsigned short eecr;              /* JTAC ICE mkII XML file parameter */
+  unsigned int nvm_base;            /* Base address of NVM controller in ATxmega devices */
+
+  OPCODE      * op[AVR_OP_MAX];     /* opcodes */
+
+  LISTID        mem;                /* avr memory definitions */
+  char          config_file[PATH_MAX]; /* config file where defined */
+  int           lineno;                /* config file line number */
+} AVRPART;
+
+#define AVR_MEMDESCLEN 64
+typedef struct avrmem {
+  char desc[AVR_MEMDESCLEN];  /* memory description ("flash", "eeprom", etc) */
+  int paged;                  /* page addressed (e.g. ATmega flash) */
+  int size;                   /* total memory size in bytes */
+  int page_size;              /* size of memory page (if page addressed) */
+  int num_pages;              /* number of pages (if page addressed) */
+  unsigned int offset;        /* offset in IO memory (ATxmega) */
+  int min_write_delay;        /* microseconds */
+  int max_write_delay;        /* microseconds */
+  int pwroff_after_write;     /* after this memory type is written to,
+                                 the device must be powered off and
+                                 back on, see errata
+                                 http://www.atmel.com/atmel/acrobat/doc1280.pdf */
+  unsigned char readback[2];  /* polled read-back values */
+
+  int mode;                   /* stk500 v2 xml file parameter */
+  int delay;                  /* stk500 v2 xml file parameter */
+  int blocksize;              /* stk500 v2 xml file parameter */
+  int readsize;               /* stk500 v2 xml file parameter */
+  int pollindex;              /* stk500 v2 xml file parameter */
+
+  unsigned char * buf;        /* pointer to memory buffer */
+  OPCODE * op[AVR_OP_MAX];    /* opcodes */
+} AVRMEM;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Functions for OPCODE structures */
+OPCODE * avr_new_opcode(void);
+int avr_set_bits(OPCODE * op, unsigned char * cmd);
+int avr_set_addr(OPCODE * op, unsigned char * cmd, unsigned long addr);
+int avr_set_input(OPCODE * op, unsigned char * cmd, unsigned char data);
+int avr_get_output(OPCODE * op, unsigned char * res, unsigned char * data);
+
+/* Functions for AVRMEM structures */
+AVRMEM * avr_new_memtype(void);
+int avr_initmem(AVRPART * p);
+AVRMEM * avr_dup_mem(AVRMEM * m);
+AVRMEM * avr_locate_mem(AVRPART * p, char * desc);
+void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, int type,
+                     int verbose);
+
+/* Functions for AVRPART structures */
+AVRPART * avr_new_part(void);
+AVRPART * avr_dup_part(AVRPART * d);
+AVRPART * locate_part(LISTID parts, char * partdesc);
+AVRPART * locate_part_by_avr910_devcode(LISTID parts, int devcode);
+void avr_display(FILE * f, AVRPART * p, const char * prefix, int verbose);
+
+typedef void (*walk_avrparts_cb)(const char *name, const char *desc,
+                                 const char *cfgname, int cfglineno,
+                                 void *cookie);
+void walk_avrparts(LISTID programmers, walk_avrparts_cb cb, void *cookie);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* avrpart_h */
diff --git a/avrdude/bitbang.c b/avrdude/bitbang.c
new file mode 100644
index 00000000..24b85183
--- /dev/null
+++ b/avrdude/bitbang.c
@@ -0,0 +1,436 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2000, 2001, 2002, 2003  Brian S. Dean <bsd@bsdhome.com>
+ * Copyright (C) 2005 Michael Holzt <kju-avr@fqdn.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+/* $Id$ */
+
+#include "ac_cfg.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#if !defined(WIN32NATIVE)
+#  include <signal.h>
+#  include <sys/time.h>
+#endif
+
+#include "avrdude.h"
+#include "avr.h"
+#include "pindefs.h"
+#include "pgm.h"
+#include "par.h"
+#include "serbb.h"
+
+static int delay_decrement;
+
+#if defined(WIN32NATIVE)
+static int has_perfcount;
+static LARGE_INTEGER freq;
+#else
+static volatile int done;
+
+typedef void (*mysighandler_t)(int);
+static mysighandler_t saved_alarmhandler;
+
+static void alarmhandler(int signo)
+{
+  done = 1;
+  signal(SIGALRM, saved_alarmhandler);
+}
+#endif /* WIN32NATIVE */
+
+/*
+ * Calibrate the microsecond delay loop below.
+ */
+static void bitbang_calibrate_delay(void)
+{
+#if defined(WIN32NATIVE)
+  /*
+   * If the hardware supports a high-resolution performance counter,
+   * we ultimately prefer that one, as it gives quite accurate delays
+   * on modern high-speed CPUs.
+   */
+  if (QueryPerformanceFrequency(&freq))
+  {
+    has_perfcount = 1;
+    if (verbose >= 2)
+      fprintf(stderr,
+              "%s: Using performance counter for bitbang delays\n",
+              progname);
+  }
+  else
+  {
+    /*
+     * If a high-resolution performance counter is not available, we
+     * don't have any Win32 implementation for setting up the
+     * per-microsecond delay count, so we can only run on a
+     * preconfigured delay stepping there.  The figure below should at
+     * least be correct within an order of magnitude, judging from the
+     * auto-calibration figures seen on various Unix systems on
+     * comparable hardware.
+     */
+    if (verbose >= 2)
+      fprintf(stderr,
+      "%s: Using guessed per-microsecond delay count for bitbang delays\n",
+              progname);
+    delay_decrement = 100;
+  }
+#else  /* !WIN32NATIVE */
+  struct itimerval itv;
+  volatile int i;
+
+  if (verbose >= 2)
+    fprintf(stderr,
+	    "%s: Calibrating delay loop...",
+	    progname);
+  i = 0;
+  done = 0;
+  saved_alarmhandler = signal(SIGALRM, alarmhandler);
+  /*
+   * Set ITIMER_REAL to 100 ms.  All known systems have a timer
+   * granularity of 10 ms or better, so counting the delay cycles
+   * accumulating over 100 ms should give us a rather realistic
+   * picture, without annoying the user by a lengthy startup time (as
+   * an alarm(1) would do).  Of course, if heavy system activity
+   * happens just during calibration but stops before the remaining
+   * part of AVRDUDE runs, this will yield wrong values.  There's not
+   * much we can do about this.
+   */
+  itv.it_value.tv_sec = 0;
+  itv.it_value.tv_usec = 100000;
+  itv.it_interval.tv_sec = itv.it_interval.tv_usec = 0;
+  setitimer(ITIMER_REAL, &itv, 0);
+  while (!done)
+    i--;
+  itv.it_value.tv_sec = itv.it_value.tv_usec = 0;
+  setitimer(ITIMER_REAL, &itv, 0);
+  /*
+   * Calculate back from 100 ms to 1 us.
+   */
+  delay_decrement = -i / 100000;
+  if (verbose >= 2)
+    fprintf(stderr,
+	    " calibrated to %d cycles per us\n",
+	    delay_decrement);
+#endif /* WIN32NATIVE */
+}
+
+/*
+ * Delay for approximately the number of microseconds specified.
+ * usleep()'s granularity is usually like 1 ms or 10 ms, so it's not
+ * really suitable for short delays in bit-bang algorithms.
+ */
+void bitbang_delay(int us)
+{
+#if defined(WIN32NATIVE)
+  LARGE_INTEGER countNow, countEnd;
+
+  if (has_perfcount)
+  {
+    QueryPerformanceCounter(&countNow);
+    countEnd.QuadPart = countNow.QuadPart + freq.QuadPart * us / 1000000ll;
+
+    while (countNow.QuadPart < countEnd.QuadPart)
+      QueryPerformanceCounter(&countNow);
+  }
+  else /* no performance counters -- run normal uncalibrated delay */
+  {
+#endif  /* WIN32NATIVE */
+  volatile int del = us * delay_decrement;
+
+  while (del > 0)
+    del--;
+#if defined(WIN32NATIVE)
+  }
+#endif /* WIN32NATIVE */
+}
+
+/*
+ * transmit and receive a byte of data to/from the AVR device
+ */
+static unsigned char bitbang_txrx(PROGRAMMER * pgm, unsigned char byte)
+{
+  int i;
+  unsigned char r, b, rbyte;
+
+  rbyte = 0;
+  for (i=7; i>=0; i--) {
+    /*
+     * Write and read one bit on SPI.
+     * Some notes on timing: Let T be the time it takes to do
+     * one pgm->setpin()-call resp. par clrpin()-call, then
+     * - SCK is high for 2T
+     * - SCK is low for 2T
+     * - MOSI setuptime is 1T
+     * - MOSI holdtime is 3T
+     * - SCK low to MISO read is 2T to 3T
+     * So we are within programming specs (expect for AT90S1200),
+     * if and only if T>t_CLCL (t_CLCL=clock period of target system).
+     *
+     * Due to the delay introduced by "IN" and "OUT"-commands,
+     * T is greater than 1us (more like 2us) on x86-architectures.
+     * So programming works safely down to 1MHz target clock.
+    */
+
+    b = (byte >> i) & 0x01;
+
+    /* set the data input line as desired */
+    pgm->setpin(pgm, pgm->pinno[PIN_AVR_MOSI], b);
+
+    pgm->setpin(pgm, pgm->pinno[PIN_AVR_SCK], 1);
+
+    /*
+     * read the result bit (it is either valid from a previous falling
+     * edge or it is ignored in the current context)
+     */
+    r = pgm->getpin(pgm, pgm->pinno[PIN_AVR_MISO]);
+
+    pgm->setpin(pgm, pgm->pinno[PIN_AVR_SCK], 0);
+
+    rbyte |= r << i;
+  }
+
+  return rbyte;
+}
+
+
+int bitbang_rdy_led(PROGRAMMER * pgm, int value)
+{
+  pgm->setpin(pgm, pgm->pinno[PIN_LED_RDY], !value);
+  return 0;
+}
+
+int bitbang_err_led(PROGRAMMER * pgm, int value)
+{
+  pgm->setpin(pgm, pgm->pinno[PIN_LED_ERR], !value);
+  return 0;
+}
+
+int bitbang_pgm_led(PROGRAMMER * pgm, int value)
+{
+  pgm->setpin(pgm, pgm->pinno[PIN_LED_PGM], !value);
+  return 0;
+}
+
+int bitbang_vfy_led(PROGRAMMER * pgm, int value)
+{
+  pgm->setpin(pgm, pgm->pinno[PIN_LED_VFY], !value);
+  return 0;
+}
+
+
+/*
+ * transmit an AVR device command and return the results; 'cmd' and
+ * 'res' must point to at least a 4 byte data buffer
+ */
+int bitbang_cmd(PROGRAMMER * pgm, unsigned char cmd[4],
+                   unsigned char res[4])
+{
+  int i;
+
+  for (i=0; i<4; i++) {
+    res[i] = bitbang_txrx(pgm, cmd[i]);
+  }
+
+    if(verbose >= 2)
+	{
+        fprintf(stderr, "bitbang_cmd(): [ ");
+        for(i = 0; i < 4; i++)
+            fprintf(stderr, "%02X ", cmd[i]);
+        fprintf(stderr, "] [ ");
+        for(i = 0; i < 4; i++)
+		{
+            fprintf(stderr, "%02X ", res[i]);
+		}
+        fprintf(stderr, "]\n");
+	}
+
+  return 0;
+}
+
+/*
+ * transmit bytes via SPI and return the results; 'cmd' and
+ * 'res' must point to data buffers
+ */
+int bitbang_spi(PROGRAMMER * pgm, unsigned char cmd[],
+                   unsigned char res[], int count)
+{
+  int i;
+
+  pgm->setpin(pgm, pgm->pinno[PIN_LED_PGM], 0);
+
+  for (i=0; i<count; i++) {
+    res[i] = bitbang_txrx(pgm, cmd[i]);
+  }
+
+  pgm->setpin(pgm, pgm->pinno[PIN_LED_PGM], 1);
+
+  if(verbose >= 2)
+	{
+        fprintf(stderr, "bitbang_cmd(): [ ");
+        for(i = 0; i < count; i++)
+            fprintf(stderr, "%02X ", cmd[i]);
+        fprintf(stderr, "] [ ");
+        for(i = 0; i < count; i++)
+		{
+            fprintf(stderr, "%02X ", res[i]);
+		}
+        fprintf(stderr, "]\n");
+	}
+
+  return 0;
+}
+
+
+/*
+ * issue the 'chip erase' command to the AVR device
+ */
+int bitbang_chip_erase(PROGRAMMER * pgm, AVRPART * p)
+{
+  unsigned char cmd[4];
+  unsigned char res[4];
+
+  if (p->op[AVR_OP_CHIP_ERASE] == NULL) {
+    fprintf(stderr, "chip erase instruction not defined for part \"%s\"\n",
+            p->desc);
+    return -1;
+  }
+
+  pgm->pgm_led(pgm, ON);
+
+  memset(cmd, 0, sizeof(cmd));
+
+  avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd);
+  pgm->cmd(pgm, cmd, res);
+  usleep(p->chip_erase_delay);
+  pgm->initialize(pgm, p);
+
+  pgm->pgm_led(pgm, OFF);
+
+  return 0;
+}
+
+/*
+ * issue the 'program enable' command to the AVR device
+ */
+int bitbang_program_enable(PROGRAMMER * pgm, AVRPART * p)
+{
+  unsigned char cmd[4];
+  unsigned char res[4];
+
+  if (p->op[AVR_OP_PGM_ENABLE] == NULL) {
+    fprintf(stderr, "program enable instruction not defined for part \"%s\"\n",
+            p->desc);
+    return -1;
+  }
+
+  memset(cmd, 0, sizeof(cmd));
+  avr_set_bits(p->op[AVR_OP_PGM_ENABLE], cmd);
+  pgm->cmd(pgm, cmd, res);
+
+  if (res[2] != cmd[1])
+    return -2;
+
+  return 0;
+}
+
+/*
+ * initialize the AVR device and prepare it to accept commands
+ */
+int bitbang_initialize(PROGRAMMER * pgm, AVRPART * p)
+{
+  int rc;
+  int tries;
+
+  bitbang_calibrate_delay();
+
+  pgm->powerup(pgm);
+  usleep(20000);
+
+  pgm->setpin(pgm, pgm->pinno[PIN_AVR_SCK], 0);
+  pgm->setpin(pgm, pgm->pinno[PIN_AVR_RESET], 0);
+  usleep(20000);
+
+  pgm->highpulsepin(pgm, pgm->pinno[PIN_AVR_RESET]);
+
+  usleep(20000); /* 20 ms XXX should be a per-chip parameter */
+
+  /*
+   * Enable programming mode.  If we are programming an AT90S1200, we
+   * can only issue the command and hope it worked.  If we are using
+   * one of the other chips, the chip will echo 0x53 when issuing the
+   * third byte of the command.  In this case, try up to 32 times in
+   * order to possibly get back into sync with the chip if we are out
+   * of sync.
+   */
+  if (strcmp(p->desc, "AT90S1200")==0) {
+    pgm->program_enable(pgm, p);
+  }
+  else {
+    tries = 0;
+    do {
+      rc = pgm->program_enable(pgm, p);
+      if ((rc == 0)||(rc == -1))
+        break;
+      pgm->highpulsepin(pgm, pgm->pinno[p->retry_pulse/*PIN_AVR_SCK*/]);
+      tries++;
+    } while (tries < 65);
+
+    /*
+     * can't sync with the device, maybe it's not attached?
+     */
+    if (rc) {
+      fprintf(stderr, "%s: AVR device not responding\n", progname);
+      return -1;
+    }
+  }
+
+  return 0;
+}
+
+static void verify_pin_assigned(PROGRAMMER * pgm, int pin, char * desc)
+{
+  if (pgm->pinno[pin] == 0) {
+    fprintf(stderr, "%s: error: no pin has been assigned for %s\n",
+            progname, desc);
+    exit(1);
+  }
+}
+
+
+/*
+ * Verify all prerequisites for a bit-bang programmer are present.
+ */
+void bitbang_check_prerequisites(PROGRAMMER *pgm)
+{
+
+  verify_pin_assigned(pgm, PIN_AVR_RESET, "AVR RESET");
+  verify_pin_assigned(pgm, PIN_AVR_SCK,   "AVR SCK");
+  verify_pin_assigned(pgm, PIN_AVR_MISO,  "AVR MISO");
+  verify_pin_assigned(pgm, PIN_AVR_MOSI,  "AVR MOSI");
+
+  if (pgm->cmd == NULL) {
+    fprintf(stderr, "%s: error: no cmd() method defined for bitbang programmer\n",
+            progname);
+    exit(1);
+  }
+}
diff --git a/avrdude/bitbang.h b/avrdude/bitbang.h
new file mode 100644
index 00000000..eb959c7d
--- /dev/null
+++ b/avrdude/bitbang.h
@@ -0,0 +1,56 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2000, 2001, 2002, 2003  Brian S. Dean <bsd@bsdhome.com>
+ * Copyright (C) 2005 Michael Holzt <kju-avr@fqdn.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+/* $Id$ */
+
+#ifndef bitbang_h
+#define bitbang_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int bitbang_setpin(int fd, int pin, int value);
+int bitbang_getpin(int fd, int pin);
+int bitbang_highpulsepin(int fd, int pin);
+void bitbang_delay(unsigned int us);
+
+void bitbang_check_prerequisites(PROGRAMMER *pgm);
+
+int  bitbang_rdy_led        (PROGRAMMER * pgm, int value);
+int  bitbang_err_led        (PROGRAMMER * pgm, int value);
+int  bitbang_pgm_led        (PROGRAMMER * pgm, int value);
+int  bitbang_vfy_led        (PROGRAMMER * pgm, int value);
+int  bitbang_cmd            (PROGRAMMER * pgm, unsigned char cmd[4],
+                                unsigned char res[4]);
+int  bitbang_spi            (PROGRAMMER * pgm, unsigned char cmd[],
+                                unsigned char res[], int count);
+int  bitbang_chip_erase     (PROGRAMMER * pgm, AVRPART * p);
+int  bitbang_program_enable (PROGRAMMER * pgm, AVRPART * p);
+void bitbang_powerup        (PROGRAMMER * pgm);
+void bitbang_powerdown      (PROGRAMMER * pgm);
+int  bitbang_initialize     (PROGRAMMER * pgm, AVRPART * p);
+void bitbang_disable        (PROGRAMMER * pgm);
+void bitbang_enable         (PROGRAMMER * pgm);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/avrdude/bootstrap b/avrdude/bootstrap
new file mode 100755
index 00000000..cacf4434
--- /dev/null
+++ b/avrdude/bootstrap
@@ -0,0 +1,44 @@
+#! /bin/sh
+
+# autoconf-2.59 or 2.61, 2.62 is known to work
+
+: ${AUTOHEADER="autoheader${AC_VER}"}
+: ${AUTOCONF="autoconf${AC_VER}"}
+
+# automake-1.9.x or 1.10 is known to work
+
+: ${ACLOCAL="aclocal${AM_VER}"}
+: ${AUTOMAKE="automake${AM_VER}"}
+
+# Verify autoconf version
+
+AUTOCONF_VER=`(${AUTOCONF} --version 2>/dev/null | head -n 1 | \
+              cut -d ' ' -f 4) 2>/dev/null`
+if [ "$AUTOCONF_VER" != "2.59" -a "$AUTOCONF_VER" != "2.61" -a "$AUTOCONF_VER" != "2.62" ]
+then
+	echo "Warning: This program is tested with autoconf version 2.59, 2.61 and 2.62."
+	echo "You are using `${AUTOCONF} --version | head -n 1`."
+fi
+
+# Verify automake version
+
+AUTOMAKE_VER=`(${AUTOMAKE} --version | head -n 1 | \
+              cut -d ' ' -f 4 | cut -d '.' -f -2) 2>/dev/null`
+if [ "$AUTOMAKE_VER" != "1.9" -a "$AUTOMAKE_VER" != "1.10" ]
+then
+	echo "Warning: This program is tested with automake version 1.9 and 1.10."
+	echo "You are using `${AUTOMAKE} --version | head -n 1`."
+fi
+
+export ACLOCAL AUTOHEADER AUTOCONF AUTOMAKE
+
+# Bootstrap the build system.
+
+set -x
+
+rm -rf autom4te.cache
+
+${ACLOCAL}
+${AUTOHEADER}
+${AUTOCONF}
+${AUTOMAKE} -a -c
diff --git a/avrdude/buspirate.c b/avrdude/buspirate.c
new file mode 100644
index 00000000..32863d0b
--- /dev/null
+++ b/avrdude/buspirate.c
@@ -0,0 +1,786 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ *
+ * avrdude support for The Bus Pirate - universal serial interface
+ *
+ * Copyright (C) 2009 Michal Ludvig <mludvig@logix.net.nz>
+ *
+ * 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
+ */
+
+/*
+ * BusPirate       AVR Chip
+ * ---------       --------
+ *       GND  <->  GND
+ *       +5V  <->  Vcc
+ *        CS  <->  RESET
+ *      MOSI  <->  MOSI
+ *      MISO  <->  MISO
+ *   SCL/CLK  <->  SCK
+ *
+ * Tested with BusPirate PTH, firmware version 2.1 programming ATmega328P
+ */
+
+/* $Id$ */
+
+#include "ac_cfg.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#if defined(WIN32NATIVE)
+#  include <malloc.h>  /* for alloca() */
+#endif
+
+#include "avrdude.h"
+#include "avr.h"
+#include "pgm.h"
+#include "serial.h"
+
+/* ====== Private data structure ====== */
+/* CS and AUX pin bitmasks in
+ * 0100wxyz - Configure peripherals command */
+#define BP_RESET_CS     0x01
+#define BP_RESET_AUX    0x02
+#define BP_RESET_AUX2   0x04
+
+#define BP_FLAG_IN_BINMODE          (1<<0)
+#define BP_FLAG_XPARM_FORCE_ASCII   (1<<1)
+#define BP_FLAG_XPARM_RESET         (1<<2)
+#define BP_FLAG_XPARM_SPIFREQ       (1<<3)
+
+struct pdata
+{
+	char	hw_version[10];
+	int	fw_version;		/* = 100*fw_major + fw_minor */
+	int	binmode_version;
+	int	bin_spi_version;
+	int	current_peripherals_config;
+	int	spifreq;		/* 0..7 - see buspirate manual for what freq each value means */
+	int	reset;			/* See BP_RESET_* above */
+};
+#define PDATA(pgm) ((struct pdata *)(pgm->cookie))
+
+/* Binary mode is available from firmware v2.7 on */
+#define FW_BINMODE_VER	207
+
+/* ====== Feature checks ====== */
+static inline int
+buspirate_has_aux2(struct programmer_t *pgm)
+{
+	return ((PDATA(pgm)->fw_version >= 300) &&
+		strcmp(PDATA(pgm)->hw_version, "v1a") == 0);
+}
+
+static inline int
+buspirate_uses_ascii(struct programmer_t *pgm)
+{
+	return (pgm->flag & BP_FLAG_XPARM_FORCE_ASCII) ||
+		(PDATA(pgm)->fw_version < FW_BINMODE_VER);
+}
+
+/* ====== Serial talker functions - binmode ====== */
+
+static void dump_mem(char *buf, size_t len)
+{
+	size_t i;
+
+	for (i = 0; i<len; i++) {
+		if (i % 8 == 0)
+			fprintf(stderr, "\t");
+		fprintf(stderr, "0x%02x ", (unsigned)buf[i] & 0xFF);
+		if (i % 8 == 3)
+			fprintf(stderr, "  ");
+		else if (i % 8 == 7)
+			fprintf(stderr, "\n");
+	}
+	if (i % 8 != 7)
+		fprintf(stderr, "\n");
+}
+
+static int buspirate_send_bin(struct programmer_t *pgm, char *data, size_t len)
+{
+	int rc;
+
+	if (verbose > 1) {
+		fprintf(stderr, "%s: buspirate_send_bin():\n", progname);
+		dump_mem(data, len);
+	}
+
+	rc = serial_send(&pgm->fd, (unsigned char *)data, len);
+
+	return rc;
+}
+
+static int buspirate_recv_bin(struct programmer_t *pgm, char *buf, size_t len)
+{
+	int rc;
+
+	rc = serial_recv(&pgm->fd, (unsigned char *)buf, len);
+	if (rc < 0)
+		return EOF;
+	if (verbose > 1) {
+		fprintf(stderr, "%s: buspirate_recv_bin():\n", progname);
+		dump_mem(buf, len);
+	}
+
+	return len;
+}
+
+static int buspirate_expect_bin(struct programmer_t *pgm,
+				char *send_data, size_t send_len,
+				char *expect_data, size_t expect_len)
+{
+	char *recv_buf = alloca(expect_len);
+	if (!pgm->flag & BP_FLAG_IN_BINMODE) {
+		fprintf(stderr, "BusPirate: Internal error: buspirate_send_bin() called from ascii mode");
+		exit(1);
+	}
+
+	buspirate_send_bin(pgm, send_data, send_len);
+	buspirate_recv_bin(pgm, recv_buf, expect_len);
+	if (memcmp(expect_data, recv_buf, expect_len) != 0)
+		return 0;
+	return 1;
+}
+
+static int buspirate_expect_bin_byte(struct programmer_t *pgm,
+					char send_byte, char expect_byte)
+{
+	return buspirate_expect_bin(pgm, &send_byte, 1, &expect_byte, 1);
+}
+
+/* ====== Serial talker functions - ascii mode ====== */
+
+static int buspirate_getc(struct programmer_t *pgm)
+{
+	int rc;
+	unsigned char ch = 0;
+
+	if (pgm->flag & BP_FLAG_IN_BINMODE) {
+		fprintf(stderr, "BusPirate: Internal error: buspirate_getc() called from binmode");
+		exit(1);
+	}
+
+	rc = serial_recv(&pgm->fd, &ch, 1);
+	if (rc < 0)
+		return EOF;
+	return ch;
+}
+
+static char *buspirate_readline_noexit(struct programmer_t *pgm, char *buf, size_t len)
+{
+	char *buf_p;
+	long orig_serial_recv_timeout = serial_recv_timeout;
+
+	/* Static local buffer - this may come handy at times */
+	static char buf_local[100];
+
+	if (buf == NULL) {
+		buf = buf_local;
+		len = sizeof(buf_local);
+	}
+	buf_p = buf;
+	memset(buf, 0, len);
+	while (buf_p < (buf + len - 1)) { /* keep the very last byte == 0 */
+		*buf_p = buspirate_getc(pgm);
+		if (*buf_p == '\r')
+			continue;
+		if (*buf_p == '\n')
+			break;
+		if (*buf_p == EOF) {
+			*buf_p = '\0';
+			break;
+		}
+		buf_p++;
+		serial_recv_timeout = 100;
+	}
+	serial_recv_timeout = orig_serial_recv_timeout;
+	if (verbose)
+		fprintf(stderr, "%s: buspirate_readline(): %s%s",
+			progname, buf,
+			buf[strlen(buf) - 1] == '\n' ? "" : "\n");
+	if (! buf[0])
+		return NULL;
+
+	return buf;
+}
+
+static char *buspirate_readline(struct programmer_t *pgm, char *buf, size_t len)
+{
+	char *ret;
+	
+	ret = buspirate_readline_noexit(pgm, buf, len);
+	if (! ret) {
+		fprintf(stderr,
+			"%s: buspirate_readline(): programmer is not responding\n",
+			progname);
+		exit(1);
+	}
+	return ret;
+}
+static int buspirate_send(struct programmer_t *pgm, char *str)
+{
+	int rc;
+
+	if (verbose)
+		fprintf(stderr, "%s: buspirate_send(): %s", progname, str);
+
+	if (pgm->flag & BP_FLAG_IN_BINMODE) {
+		fprintf(stderr, "BusPirate: Internal error: buspirate_send() called from binmode");
+		exit(1);
+	}
+
+	rc = serial_send(&pgm->fd, (unsigned char *)str, strlen(str));
+	if (rc)
+		return rc;
+	while (strcmp(buspirate_readline(pgm, NULL, 0), str) != 0)
+		/* keep reading until we get what we sent there */
+		;
+	/* by now we should be in sync */
+	return 0;
+}
+
+static int buspirate_is_prompt(char *str)
+{
+	/* Prompt ends with '>' all other input probably ends with '\n' */
+	return (str[strlen(str) - 1] == '>');
+}
+
+static int buspirate_expect(struct programmer_t *pgm, char *send,
+				char *expect, int wait_for_prompt)
+{
+	int got_it = 0;
+	size_t expect_len = strlen(expect);
+	char *rcvd;
+
+	buspirate_send(pgm, send);
+	while (1) {
+		rcvd = buspirate_readline(pgm, NULL, 0);
+
+		if (strncmp(rcvd, expect, expect_len) == 0)
+			got_it = 1;
+
+		if (buspirate_is_prompt(rcvd))
+			break;
+	}
+	return got_it;
+}
+
+/* ====== Do-nothing functions ====== */
+static void buspirate_dummy_6(struct programmer_t *pgm,
+				const char *p)
+{
+}
+
+/* ====== Config / parameters handling functions ====== */
+static int
+buspirate_parseextparms(struct programmer_t *pgm, LISTID extparms)
+{
+	LNODEID ln;
+	const char *extended_param;
+	char reset[10];
+	char *preset = reset;	/* for strtok() */
+	int spifreq;
+
+	for (ln = lfirst(extparms); ln; ln = lnext(ln)) {
+    	extended_param = ldata(ln);
+		if (strcmp(extended_param, "ascii") == 0) {
+			pgm->flag |= BP_FLAG_XPARM_FORCE_ASCII;
+			continue;
+		}
+		if (sscanf(extended_param, "spifreq=%d", &spifreq) == 1) {
+			if (spifreq & (~0x07)) {
+				fprintf(stderr, "BusPirate: spifreq must be between 0 and 7.\n");
+				fprintf(stderr, "BusPirate: see BusPirate manual for details.\n");
+				return -1;
+			}
+			PDATA(pgm)->spifreq = spifreq;
+			pgm->flag |= BP_FLAG_XPARM_SPIFREQ;
+			continue;
+		}
+
+		if (sscanf(extended_param, "reset=%s", reset) == 1) {
+			char *resetpin;
+			while ((resetpin = strtok(preset, ","))) {
+				preset = NULL;	/* for subsequent strtok() calls */
+				if (strcasecmp(resetpin, "cs") == 0)
+					PDATA(pgm)->reset |= BP_RESET_CS;
+				else if (strcasecmp(resetpin, "aux") == 0 || strcasecmp(reset, "aux1") == 0)
+					PDATA(pgm)->reset |= BP_RESET_AUX;
+				else if (strcasecmp(resetpin, "aux2") == 0)
+					PDATA(pgm)->reset |= BP_RESET_AUX2;
+				else {
+					fprintf(stderr, "BusPirate: reset must be either CS or AUX.\n");
+					return -1;
+				}
+			}
+			pgm->flag |= BP_FLAG_XPARM_RESET;
+			continue;
+		}
+	}
+
+	return 0;
+}
+
+static int
+buspirate_verifyconfig(struct programmer_t *pgm)
+{
+	/* Default reset pin is CS */
+	if (PDATA(pgm)->reset == 0x00)
+		PDATA(pgm)->reset |= BP_RESET_CS;
+
+	/* reset=AUX2 is only available on HW=v1a and FW>=3.0 */
+	if ((PDATA(pgm)->reset & BP_RESET_AUX2) && !buspirate_has_aux2(pgm)) {
+		fprintf(stderr, "BusPirate: Pin AUX2 is only available in binary mode\n");
+		fprintf(stderr, "BusPirate: with hardware==v1a && firmware>=3.0\n");
+		fprintf(stderr, "BusPirate: Your hardware==%s and firmware==%d.%d\n",
+				PDATA(pgm)->hw_version, PDATA(pgm)->fw_version/100, PDATA(pgm)->fw_version%100);
+		return -1;
+	}
+
+	if ((PDATA(pgm)->reset != BP_RESET_CS) && buspirate_uses_ascii(pgm)) {
+		fprintf(stderr, "BusPirate: RESET pin other than CS is not supported in ASCII mode\n");
+		return -1;
+	}
+
+	if ((pgm->flag & BP_FLAG_XPARM_SPIFREQ) && buspirate_uses_ascii(pgm)) {
+		fprintf(stderr, "BusPirate: SPI speed selection is not supported in ASCII mode\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+/* ====== Programmer methods ======= */
+static int buspirate_open(struct programmer_t *pgm, char * port)
+{
+	/* BusPirate runs at 115200 by default */
+	if(pgm->baudrate == 0)
+		pgm->baudrate = 115200;
+
+	strcpy(pgm->port, port);
+	serial_open(port, pgm->baudrate, &pgm->fd);
+
+	/* drain any extraneous input */
+	serial_drain(&pgm->fd, 0);
+
+	return 0;
+}
+
+static void buspirate_close(struct programmer_t *pgm)
+{
+	serial_close(&pgm->fd);
+	pgm->fd.ifd = -1;
+}
+
+static void buspirate_reset_from_binmode(struct programmer_t *pgm)
+{
+	char buf[10];
+
+	buf[0] = 0x00;	/* BinMode: revert to HiZ */
+	buspirate_send_bin(pgm, buf, 1);
+
+	buf[0] = 0x0F;	/* BinMode: reset */
+	buspirate_send_bin(pgm, buf, 1);
+
+	/* read back all output */
+	memset(buf, '\0', sizeof(buf));
+	for (;;) {
+		int rc;
+		rc = buspirate_recv_bin(pgm, buf, sizeof(buf) - 1);
+
+		if (buspirate_is_prompt(buf)) {
+			pgm->flag &= ~BP_FLAG_IN_BINMODE;
+			break;
+		}
+		if (rc == EOF)
+			break;
+		memset(buf, '\0', sizeof(buf));
+	}
+
+	if (pgm->flag & BP_FLAG_IN_BINMODE) {
+		fprintf(stderr, "BusPirate reset failed. You may need to powercycle it.\n");
+		exit(1);
+	}
+
+	if (verbose)
+		printf("BusPirate is back in the text mode\n");
+}
+
+static int buspirate_start_spi_mode_bin(struct programmer_t *pgm)
+{
+	char buf[20] = { '\0' };
+
+	/* == Switch to binmode - send 20x '\0' == */
+	buspirate_send_bin(pgm, buf, sizeof(buf));
+
+	/* Expecting 'BBIOx' reply */
+	memset(buf, 0, sizeof(buf));
+	buspirate_recv_bin(pgm, buf, 5);
+	if (sscanf(buf, "BBIO%d", &PDATA(pgm)->binmode_version) != 1) {
+		fprintf(stderr, "Binary mode not confirmed: '%s'\n", buf);
+		buspirate_reset_from_binmode(pgm);
+		return -1;
+	}
+	if (verbose)
+		printf("BusPirate binmode version: %d\n", PDATA(pgm)->binmode_version);
+
+	pgm->flag |= BP_FLAG_IN_BINMODE;
+
+	/* == Enter SPI mode == */
+	buf[0] = 0x01;	/* Enter raw SPI mode */
+	buspirate_send_bin(pgm, buf, 1);
+	memset(buf, 0, sizeof(buf));
+	buspirate_recv_bin(pgm, buf, 4);
+	if (sscanf(buf, "SPI%d", &PDATA(pgm)->bin_spi_version) != 1) {
+		fprintf(stderr, "SPI mode not confirmed: '%s'\n", buf);
+		buspirate_reset_from_binmode(pgm);
+		return -1;
+	}
+	if (verbose)
+		printf("BusPirate SPI version: %d\n", PDATA(pgm)->bin_spi_version);
+
+	/* 0b0100wxyz - Configure peripherals w=power, x=pull-ups/aux2, y=AUX, z=CS
+	 * we want power (0x48) and all reset pins high. */
+	PDATA(pgm)->current_peripherals_config  = 0x48;
+	PDATA(pgm)->current_peripherals_config |= BP_RESET_CS;
+	PDATA(pgm)->current_peripherals_config |= BP_RESET_AUX;
+	if (buspirate_has_aux2(pgm))
+		PDATA(pgm)->current_peripherals_config |= BP_RESET_AUX2;
+	buspirate_expect_bin_byte(pgm, PDATA(pgm)->current_peripherals_config, 0x01);
+	usleep(50000);	// sleep for 50ms after power up
+
+	/* 01100xxx -  SPI speed
+	 * xxx = 000=30kHz, 001=125kHz, 010=250kHz, 011=1MHz,
+	 *       100=2MHz, 101=2.6MHz, 110=4MHz, 111=8MHz
+	 * use 30kHz = 0x60 */
+	buspirate_expect_bin_byte(pgm, 0x60 | PDATA(pgm)->spifreq, 0x01);
+
+	/* 1000wxyz - SPI config, w=HiZ(0)/3.3v(1), x=CLK idle, y=CLK edge, z=SMP sample
+	 * we want: 3.3V(1), idle low(0), data change on trailing edge (1),
+	 *          sample in the middle of the pulse (0)
+	 *       => 0b10001010 = 0x8a */
+	buspirate_expect_bin_byte(pgm, 0x8A, 0x01);
+
+	return 0;
+}
+
+static int buspirate_start_spi_mode_ascii(struct programmer_t *pgm)
+{
+	int spi_cmd = -1;
+	int cmd;
+	char *rcvd, mode[11], buf[5];
+
+	buspirate_send(pgm, "M\n");
+	while(1) {
+		rcvd = buspirate_readline(pgm, NULL, 0);
+		if (spi_cmd == -1 && sscanf(rcvd, "%d. %10s", &cmd, mode)) {
+			if (strcmp(mode, "SPI") == 0)
+				spi_cmd = cmd;
+		}
+		if (buspirate_is_prompt(rcvd))
+			break;
+	}
+	if (spi_cmd == -1) {
+		fprintf(stderr,
+				"%s: SPI mode number not found. Does your BusPirate support SPI?\n",
+				progname);
+		fprintf(stderr, "%s: Try powercycling your BusPirate and try again.\n",
+				progname);
+		return -1;
+	}
+	snprintf(buf, sizeof(buf), "%d\n", spi_cmd);
+	buspirate_send(pgm, buf);
+	buf[0] = '\0';
+	while (1) {
+		rcvd = buspirate_readline(pgm, NULL, 0);
+		if (strstr(rcvd, "Normal (H=3.3V, L=GND)")) {
+			/* BP firmware 2.1 defaults to Open-drain output.
+			 * That doesn't work on my board, even with pull-up
+			 * resistors. Select 3.3V output mode instead. */
+			sscanf(rcvd, " %d.", &cmd);
+			snprintf(buf, sizeof(buf), "%d\n", cmd);
+		}
+		if (buspirate_is_prompt(rcvd)) {
+			if (strncmp(rcvd, "SPI>", 4) == 0) {
+				printf("BusPirate is now configured for SPI\n");
+				break;
+			}
+			/* Not yet 'SPI>' prompt */
+			if (buf[0]) {
+				buspirate_send(pgm, buf);
+				buf[0] = '\0';
+			} else
+				buspirate_send(pgm, "\n");
+		}
+	}
+	return 0;
+}
+
+static void buspirate_enable(struct programmer_t *pgm)
+{
+	unsigned char *reset_str = "#\n";
+	char *rcvd;
+	int fw_v1 = 0, fw_v2 = 0;
+	int rc, print_banner = 0;
+
+	printf("Detecting BusPirate...\n");
+
+	/* Call buspirate_send_bin() instead of buspirate_send() 
+	 * because we don't know if BP is in text or bin mode */
+	rc = buspirate_send_bin(pgm, reset_str, strlen(reset_str));
+	if (rc) {
+		fprintf(stderr, "BusPirate is not responding. Serial port error: %d\n", rc);
+		exit(1);
+	}
+
+	while(1) {
+		rcvd = buspirate_readline_noexit(pgm, NULL, 0);
+		if (! rcvd) {
+			fprintf(stderr, "BusPirate is not responding. Attempting reset.\n");
+			buspirate_reset_from_binmode(pgm);
+			/* re-run buspirate_enable() */
+			buspirate_enable(pgm);
+			return;
+		}
+		if (strncmp(rcvd, "RESET", 5) == 0) {
+			print_banner = 1;
+			continue;
+		}
+		if (buspirate_is_prompt(rcvd)) {
+			puts("**");
+			break;
+		}
+		sscanf(rcvd, "Bus Pirate %9s", PDATA(pgm)->hw_version);
+		sscanf(rcvd, "Firmware v%d.%d", &fw_v1, &fw_v2);
+		if (print_banner)
+			printf("**  %s", rcvd);
+	}
+
+	PDATA(pgm)->fw_version = 100 * fw_v1 + fw_v2;
+	if (PDATA(pgm)->hw_version[0] == 0 || PDATA(pgm)->fw_version == 0) {
+		fprintf(stderr, "BusPirate not detected. Aborting.\n");
+		exit(1);
+	}
+
+	if (buspirate_verifyconfig(pgm) < 0)
+		exit(1);
+
+	if (PDATA(pgm)->fw_version >= FW_BINMODE_VER && !(pgm->flag & BP_FLAG_XPARM_FORCE_ASCII)) {
+		printf("BusPirate: using BINARY mode\n");
+		if (buspirate_start_spi_mode_bin(pgm) < 0)
+			fprintf(stderr, "%s: Failed to start binary SPI mode\n", progname);
+	}
+	if (!pgm->flag & BP_FLAG_IN_BINMODE) {
+		printf("BusPirate: using ASCII mode\n");
+		if (buspirate_start_spi_mode_ascii(pgm) < 0) {
+			fprintf(stderr, "%s: Failed to start ascii SPI mode\n", progname);
+			exit(1);
+		}
+	}
+}
+
+static void buspirate_disable(struct programmer_t *pgm)
+{
+	if (pgm->flag & BP_FLAG_IN_BINMODE) {
+		serial_recv_timeout = 100;
+		buspirate_reset_from_binmode(pgm);
+	} else
+		buspirate_expect(pgm, "#\n", "RESET", 1);
+}
+
+static int buspirate_initialize(struct programmer_t *pgm, AVRPART * p)
+{
+	pgm->powerup(pgm);
+
+	return pgm->program_enable(pgm, p);
+}
+
+static void buspirate_powerup(struct programmer_t *pgm)
+{
+	if (pgm->flag & BP_FLAG_IN_BINMODE) {
+		/* Powerup in BinMode is handled in SPI init */
+		return;
+	} else
+		if (buspirate_expect(pgm, "W\n", "POWER SUPPLIES ON", 1))
+			return;
+
+	fprintf(stderr, "%s: warning: did not get a response to PowerUp command.\n", progname);
+	fprintf(stderr, "%s: warning: Trying to continue anyway...\n", progname);
+}
+
+static void buspirate_powerdown(struct programmer_t *pgm)
+{
+	if (pgm->flag & BP_FLAG_IN_BINMODE) {
+		/* 0b0100wxyz - Configure peripherals w=power, x=pull-ups, y=AUX, z=CS
+		 * we want everything off -- 0b01000000 = 0x40 */
+		if (buspirate_expect_bin_byte(pgm, 0x40, 0x01))
+			return;
+	} else
+		if (buspirate_expect(pgm, "w\n", "POWER SUPPLIES OFF", 1))
+			return;
+
+	fprintf(stderr, "%s: warning: did not get a response to PowerDown command.\n", progname);
+}
+
+static int buspirate_cmd_bin(struct programmer_t *pgm,
+				unsigned char cmd[4],
+				unsigned char res[4])
+{
+	/* 0001xxxx - Bulk SPI transfer, send/read 1-16 bytes (0=1byte!)
+	 * we are sending 4 bytes -> 0x13 */
+	if (!buspirate_expect_bin_byte(pgm, 0x13, 0x01))
+		return -1;
+
+	buspirate_send_bin(pgm, (char *)cmd, 4);
+	buspirate_recv_bin(pgm, (char *)res, 4);
+
+	return 0;
+}
+
+static int buspirate_cmd_ascii(struct programmer_t *pgm,
+				unsigned char cmd[4],
+				unsigned char res[4])
+{
+	char buf[25];
+	char *rcvd;
+	int spi_write, spi_read, i = 0;
+
+	snprintf(buf, sizeof(buf), "0x%02x 0x%02x 0x%02x 0x%02x\n",
+		cmd[0], cmd[1], cmd[2], cmd[3]);
+	buspirate_send(pgm, buf);
+	while (i < 4) {
+		rcvd = buspirate_readline(pgm, NULL, 0);
+		/* WRITE: 0xAC READ: 0x04 */
+		if (sscanf(rcvd, "WRITE: 0x%x READ: 0x%x", &spi_write, &spi_read) == 2) {
+			res[i++] = spi_read;
+		}
+		if (buspirate_is_prompt(rcvd))
+			break;
+	}
+
+	if (i != 4) {
+		fprintf(stderr, "%s: error: SPI has not read 4 bytes back\n", progname);
+		return -1;
+	}
+
+	/* wait for prompt */
+	while (buspirate_getc(pgm) != '>')
+		/* do nothing */;
+
+	return 0;
+}
+
+static int buspirate_cmd(struct programmer_t *pgm,
+				unsigned char cmd[4],
+				unsigned char res[4])
+{
+	if (pgm->flag & BP_FLAG_IN_BINMODE)
+		return buspirate_cmd_bin(pgm, cmd, res);
+	else
+		return buspirate_cmd_ascii(pgm, cmd, res);
+}
+
+static int buspirate_program_enable(struct programmer_t *pgm, AVRPART * p)
+{
+	unsigned char cmd[4];
+	unsigned char res[4];
+
+	if (pgm->flag & BP_FLAG_IN_BINMODE) {
+		/* Clear configured reset pin(s): CS and/or AUX and/or AUX2 */
+		PDATA(pgm)->current_peripherals_config &= ~PDATA(pgm)->reset;
+		buspirate_expect_bin_byte(pgm, PDATA(pgm)->current_peripherals_config, 0x01);
+	}
+	else
+		buspirate_expect(pgm, "{\n", "CS ENABLED", 1);
+
+	if (p->op[AVR_OP_PGM_ENABLE] == NULL) {
+		fprintf(stderr,
+			"program enable instruction not defined for part \"%s\"\n",
+			p->desc);
+		return -1;
+	}
+
+	memset(cmd, 0, sizeof(cmd));
+	avr_set_bits(p->op[AVR_OP_PGM_ENABLE], cmd);
+	pgm->cmd(pgm, cmd, res);
+
+	if (res[2] != cmd[1])
+		return -2;
+
+	return 0;
+}
+
+static int buspirate_chip_erase(struct programmer_t *pgm, AVRPART * p)
+{
+	unsigned char cmd[4];
+	unsigned char res[4];
+
+	if (p->op[AVR_OP_CHIP_ERASE] == NULL) {
+		fprintf(stderr,
+			"chip erase instruction not defined for part \"%s\"\n",
+			p->desc);
+		return -1;
+	}
+
+	pgm->pgm_led(pgm, ON);
+
+	memset(cmd, 0, sizeof(cmd));
+
+	avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd);
+	pgm->cmd(pgm, cmd, res);
+	usleep(p->chip_erase_delay);
+	pgm->initialize(pgm, p);
+
+	pgm->pgm_led(pgm, OFF);
+
+	return 0;
+}
+
+void buspirate_initpgm(struct programmer_t *pgm)
+{
+	strcpy(pgm->type, "BusPirate");
+
+	pgm->display        = buspirate_dummy_6;
+
+	/* BusPirate itself related methods */
+	pgm->open           = buspirate_open;
+	pgm->close          = buspirate_close;
+	pgm->enable         = buspirate_enable;
+	pgm->disable        = buspirate_disable;
+	pgm->initialize     = buspirate_initialize;
+
+	/* Chip related methods */
+	pgm->powerup        = buspirate_powerup;
+	pgm->powerdown      = buspirate_powerdown;
+	pgm->program_enable = buspirate_program_enable;
+	pgm->chip_erase     = buspirate_chip_erase;
+	pgm->cmd            = buspirate_cmd;
+	pgm->read_byte      = avr_read_byte_default;
+	pgm->write_byte     = avr_write_byte_default;
+
+	/* Support functions */
+	pgm->parseextparams = buspirate_parseextparms;
+
+	/* Allocate private data */
+	if ((pgm->cookie = calloc(1, sizeof(struct pdata))) == 0) {
+		fprintf(stderr, "%s: buspirate_initpgm(): Out of memory allocating private data\n",
+			progname);
+		exit(1);
+	}
+}
+
diff --git a/avrdude/buspirate.h b/avrdude/buspirate.h
new file mode 100644
index 00000000..a0d6095f
--- /dev/null
+++ b/avrdude/buspirate.h
@@ -0,0 +1,30 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ *
+ * avrdude support for The Bus Pirate - universal serial interface
+ *
+ * Copyright (C) 2009 Michal Ludvig <mludvig@logix.net.nz>
+ *
+ * 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
+ */
+
+/* $Id$ */
+
+#ifndef buspirate_h
+#define buspirate_h
+
+void buspirate_initpgm (struct programmer_t *pgm);
+
+#endif
diff --git a/avrdude/butterfly.c b/avrdude/butterfly.c
new file mode 100644
index 00000000..bf9cf664
--- /dev/null
+++ b/avrdude/butterfly.c
@@ -0,0 +1,699 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2003-2004  Theodore A. Roth  <troth@openavr.org>
+ * Copyright (C) 2005, 2007 Joerg Wunsch <j@uriah.heep.sax.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 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
+ */
+
+/* $Id$ */
+
+/*
+ * avrdude interface for the serial programming mode of the Atmel butterfly
+ * evaluation board. This board features a bootloader which uses a protocol
+ * very similar, but not identical, to the one described in application note
+ * avr910.
+ *
+ * Actually, the butterfly uses a predecessor of the avr910 protocol
+ * which is described in application notes avr109 (generic AVR
+ * bootloader) and avr911 (opensource programmer).  This file now
+ * fully handles the features present in avr109.  It should probably
+ * be renamed to avr109, but we rather stick with the old name inside
+ * the file.  We'll provide aliases for "avr109" and "avr911" in
+ * avrdude.conf so users could call it by these name as well.
+ */
+
+
+#include "ac_cfg.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "avrdude.h"
+#include "avr.h"
+#include "pgm.h"
+#include "butterfly.h"
+#include "serial.h"
+
+/*
+ * Private data for this programmer.
+ */
+struct pdata
+{
+  char has_auto_incr_addr;
+  unsigned int buffersize;
+};
+
+#define PDATA(pgm) ((struct pdata *)(pgm->cookie))
+
+static void butterfly_setup(PROGRAMMER * pgm)
+{
+  if ((pgm->cookie = malloc(sizeof(struct pdata))) == 0) {
+    fprintf(stderr,
+	    "%s: butterfly_setup(): Out of memory allocating private data\n",
+	    progname);
+    exit(1);
+  }
+  memset(pgm->cookie, 0, sizeof(struct pdata));
+}
+
+static void butterfly_teardown(PROGRAMMER * pgm)
+{
+  free(pgm->cookie);
+}
+
+static int butterfly_send(PROGRAMMER * pgm, char * buf, size_t len)
+{
+  return serial_send(&pgm->fd, (unsigned char *)buf, len);
+}
+
+
+static int butterfly_recv(PROGRAMMER * pgm, char * buf, size_t len)
+{
+  int rv;
+
+  rv = serial_recv(&pgm->fd, (unsigned char *)buf, len);
+  if (rv < 0) {
+    fprintf(stderr,
+	    "%s: butterfly_recv(): programmer is not responding\n",
+	    progname);
+    exit(1);
+  }
+  return 0;
+}
+
+
+static int butterfly_drain(PROGRAMMER * pgm, int display)
+{
+  return serial_drain(&pgm->fd, display);
+}
+
+
+static void butterfly_vfy_cmd_sent(PROGRAMMER * pgm, char * errmsg)
+{
+  char c;
+
+  butterfly_recv(pgm, &c, 1);
+  if (c != '\r') {
+    fprintf(stderr, "%s: error: programmer did not respond to command: %s\n",
+            progname, errmsg);
+    exit(1);
+  }
+}
+
+
+static int butterfly_rdy_led(PROGRAMMER * pgm, int value)
+{
+  /* Do nothing. */
+
+  return 0;
+}
+
+
+static int butterfly_err_led(PROGRAMMER * pgm, int value)
+{
+  /* Do nothing. */
+
+  return 0;
+}
+
+
+static int butterfly_pgm_led(PROGRAMMER * pgm, int value)
+{
+  /* Do nothing. */
+
+  return 0;
+}
+
+
+static int butterfly_vfy_led(PROGRAMMER * pgm, int value)
+{
+  /* Do nothing. */
+
+  return 0;
+}
+
+
+/*
+ * issue the 'chip erase' command to the butterfly board
+ */
+static int butterfly_chip_erase(PROGRAMMER * pgm, AVRPART * p)
+{
+  butterfly_send(pgm, "e", 1);
+  butterfly_vfy_cmd_sent(pgm, "chip erase");
+
+  return 0;
+}
+
+
+static void butterfly_enter_prog_mode(PROGRAMMER * pgm)
+{
+  butterfly_send(pgm, "P", 1);
+  butterfly_vfy_cmd_sent(pgm, "enter prog mode");
+}
+
+
+static void butterfly_leave_prog_mode(PROGRAMMER * pgm)
+{
+  butterfly_send(pgm, "L", 1);
+  butterfly_vfy_cmd_sent(pgm, "leave prog mode");
+}
+
+
+/*
+ * issue the 'program enable' command to the AVR device
+ */
+static int butterfly_program_enable(PROGRAMMER * pgm, AVRPART * p)
+{
+  return -1;
+}
+
+
+/*
+ * apply power to the AVR processor
+ */
+static void butterfly_powerup(PROGRAMMER * pgm)
+{
+  /* Do nothing. */
+
+  return;
+}
+
+
+/*
+ * remove power from the AVR processor
+ */
+static void butterfly_powerdown(PROGRAMMER * pgm)
+{
+  /* Do nothing. */
+
+  return;
+}
+
+
+/*
+ * initialize the AVR device and prepare it to accept commands
+ */
+static int butterfly_initialize(PROGRAMMER * pgm, AVRPART * p)
+{
+  char id[8];
+  char sw[2];
+  char hw[2];
+  char buf[10];
+  char type;
+  char c, devtype_1st;
+
+  /*
+   * Send some ESC to activate butterfly bootloader.  This is not needed
+   * for plain avr109 bootloaders but does not harm there either.
+   */
+  fprintf(stderr, "Connecting to programmer: ");
+  do {
+    putc('.', stderr);
+    butterfly_send(pgm, "\033", 1);
+    butterfly_drain(pgm, 0);
+    butterfly_send(pgm, "S", 1);
+    butterfly_recv(pgm, &c, 1);
+    if (c != '?') {
+        putc('\n', stderr);
+        /*
+         * Got a useful response, continue getting the programmer
+         * identifier. Programmer returns exactly 7 chars _without_
+         * the null.
+         */
+      id[0] = c;
+      butterfly_recv(pgm, &id[1], sizeof(id)-2);
+      id[sizeof(id)-1] = '\0';
+    }
+  } while (c == '?');
+
+  /* Get the HW and SW versions to see if the programmer is present. */
+
+  butterfly_send(pgm, "V", 1);
+  butterfly_recv(pgm, sw, sizeof(sw));
+
+  butterfly_send(pgm, "v", 1);
+  butterfly_recv(pgm, hw, 1);	/* first, read only _one_ byte */
+  if (hw[0]!='?') {
+    butterfly_recv(pgm, &hw[1], 1);/* now, read second byte */
+  };
+
+  /* Get the programmer type (serial or parallel). Expect serial. */
+
+  butterfly_send(pgm, "p", 1);
+  butterfly_recv(pgm, &type, 1);
+
+  fprintf(stderr, "Found programmer: Id = \"%s\"; type = %c\n", id, type);
+  fprintf(stderr, "    Software Version = %c.%c; ", sw[0], sw[1]);
+  if (hw[0]=='?') {
+    fprintf(stderr, "No Hardware Version given.\n");
+  } else {
+    fprintf(stderr, "Hardware Version = %c.%c\n", hw[0], hw[1]);
+  };
+
+  /* See if programmer supports autoincrement of address. */
+
+  butterfly_send(pgm, "a", 1);
+  butterfly_recv(pgm, &PDATA(pgm)->has_auto_incr_addr, 1);
+  if (PDATA(pgm)->has_auto_incr_addr == 'Y')
+      fprintf(stderr, "Programmer supports auto addr increment.\n");
+
+  /* Check support for buffered memory access, abort if not available */
+
+  butterfly_send(pgm, "b", 1);
+  butterfly_recv(pgm, &c, 1);
+  if (c != 'Y') {
+    fprintf(stderr,
+            "%s: error: buffered memory access not supported. Maybe it isn't\n"\
+            "a butterfly/AVR109 but a AVR910 device?\n", progname);
+    exit(1);
+  };
+  butterfly_recv(pgm, &c, 1);
+  PDATA(pgm)->buffersize = (unsigned int)(unsigned char)c<<8;
+  butterfly_recv(pgm, &c, 1);
+  PDATA(pgm)->buffersize += (unsigned int)(unsigned char)c;
+  fprintf(stderr,
+    "Programmer supports buffered memory access with buffersize=%i bytes.\n",
+     PDATA(pgm)->buffersize);
+
+  /* Get list of devices that the programmer supports. */
+
+  butterfly_send(pgm, "t", 1);
+  fprintf(stderr, "\nProgrammer supports the following devices:\n");
+  devtype_1st = 0;
+  while (1) {
+    butterfly_recv(pgm, &c, 1);
+    if (devtype_1st == 0)
+      devtype_1st = c;
+
+    if (c == 0)
+      break;
+    fprintf(stderr, "    Device code: 0x%02x\n", (unsigned int)(unsigned char)c);
+  };
+  fprintf(stderr,"\n");
+
+  /* Tell the programmer which part we selected.
+     According to the AVR109 code, this is ignored by the bootloader.  As
+     some early versions might not properly ignore it, rather pick up the
+     first device type as reported above than anything out of avrdude.conf,
+     so to avoid a potential conflict.  There appears to be no general
+     agreement on AVR910 device IDs beyond the ones from the original
+     appnote 910. */
+
+  buf[0] = 'T';
+  buf[1] = devtype_1st;
+
+  butterfly_send(pgm, buf, 2);
+  butterfly_vfy_cmd_sent(pgm, "select device");
+
+  if (verbose)
+    fprintf(stderr,
+	    "%s: devcode selected: 0x%02x\n",
+	    progname, (unsigned)buf[1]);
+
+  butterfly_enter_prog_mode(pgm);
+
+  return 0;
+}
+
+
+
+static void butterfly_disable(PROGRAMMER * pgm)
+{
+  butterfly_leave_prog_mode(pgm);
+
+  return;
+}
+
+
+static void butterfly_enable(PROGRAMMER * pgm)
+{
+  return;
+}
+
+
+static int butterfly_open(PROGRAMMER * pgm, char * port)
+{
+  strcpy(pgm->port, port);
+  /*
+   *  If baudrate was not specified use 19200 Baud
+   */
+  if(pgm->baudrate == 0) {
+    pgm->baudrate = 19200;
+  }
+  serial_open(port, pgm->baudrate, &pgm->fd);
+
+  /*
+   * drain any extraneous input
+   */
+  butterfly_drain (pgm, 0);
+
+  return 0;
+}
+
+
+static void butterfly_close(PROGRAMMER * pgm)
+{
+  /* "exit programmer" */
+  butterfly_send(pgm, "E", 1);
+  butterfly_vfy_cmd_sent(pgm, "exit bootloader");
+
+  serial_close(&pgm->fd);
+  pgm->fd.ifd = -1;
+}
+
+
+static void butterfly_display(PROGRAMMER * pgm, const char * p)
+{
+  return;
+}
+
+
+static void butterfly_set_addr(PROGRAMMER * pgm, unsigned long addr)
+{
+  char cmd[3];
+
+  cmd[0] = 'A';
+  cmd[1] = (addr >> 8) & 0xff;
+  cmd[2] = addr & 0xff;
+  
+  butterfly_send(pgm, cmd, sizeof(cmd));
+  butterfly_vfy_cmd_sent(pgm, "set addr");
+}
+
+
+static void butterfly_set_extaddr(PROGRAMMER * pgm, unsigned long addr)
+{
+  char cmd[4];
+
+  cmd[0] = 'H';
+  cmd[1] = (addr >> 16) & 0xff;
+  cmd[2] = (addr >> 8) & 0xff;
+  cmd[3] = addr & 0xff;
+
+  butterfly_send(pgm, cmd, sizeof(cmd));
+  butterfly_vfy_cmd_sent(pgm, "set extaddr");
+}
+
+
+
+static int butterfly_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+                             unsigned long addr, unsigned char value)
+{
+  char cmd[6];
+  int size;
+  int use_ext_addr = m->op[AVR_OP_LOAD_EXT_ADDR] != NULL;
+
+  if ((strcmp(m->desc, "flash") == 0) || (strcmp(m->desc, "eeprom") == 0))
+  {
+    cmd[0] = 'B';
+    cmd[1] = 0;
+    if ((cmd[3] = toupper(m->desc[0])) == 'E') {	/* write to eeprom */
+      cmd[2] = 1;
+      cmd[4] = value;
+      size = 5;
+    } else {						/* write to flash */
+      /* @@@ not yet implemented */
+      cmd[2] = 2;
+      size = 6;
+      return -1;
+    }
+    if (use_ext_addr) {
+      butterfly_set_extaddr(pgm, addr);
+    } else {
+      butterfly_set_addr(pgm, addr);
+    }
+  }
+  else if (strcmp(m->desc, "lock") == 0)
+  {
+    cmd[0] = 'l';
+    cmd[1] = value;
+    size = 2;
+  }
+  else
+    return -1;
+
+  butterfly_send(pgm, cmd, size);
+  butterfly_vfy_cmd_sent(pgm, "write byte");
+
+  return 0;
+}
+
+
+static int butterfly_read_byte_flash(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+                                  unsigned long addr, unsigned char * value)
+{
+  static int cached = 0;
+  static unsigned char cvalue;
+  static unsigned long caddr;
+  int use_ext_addr = m->op[AVR_OP_LOAD_EXT_ADDR] != NULL;
+
+  if (cached && ((caddr + 1) == addr)) {
+    *value = cvalue;
+    cached = 0;
+  }
+  else {
+    char buf[2];
+
+    if (use_ext_addr) {
+      butterfly_set_extaddr(pgm, addr >> 1);
+    } else {
+      butterfly_set_addr(pgm, addr >> 1);
+    }
+
+    butterfly_send(pgm, "g\000\002F", 4);
+
+    /* Read back the program mem word (MSB first) */
+    butterfly_recv(pgm, buf, sizeof(buf));
+
+    if ((addr & 0x01) == 0) {
+      *value = buf[1];
+      cached = 1;
+      cvalue = buf[0];
+      caddr = addr;
+    }
+    else {
+      *value = buf[0];
+    }
+  }
+
+  return 0;
+}
+
+
+static int butterfly_read_byte_eeprom(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+                                   unsigned long addr, unsigned char * value)
+{
+  butterfly_set_addr(pgm, addr);
+  butterfly_send(pgm, "g\000\001E", 4);
+  butterfly_recv(pgm, (char *)value, 1);
+  return 0;
+}
+
+
+static int butterfly_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+                            unsigned long addr, unsigned char * value)
+{
+  char cmd;
+
+  if (strcmp(m->desc, "flash") == 0) {
+    return butterfly_read_byte_flash(pgm, p, m, addr, value);
+  }
+
+  if (strcmp(m->desc, "eeprom") == 0) {
+    return butterfly_read_byte_eeprom(pgm, p, m, addr, value);
+  }
+
+  if (strcmp(m->desc, "lfuse") == 0) {
+    cmd = 'F';
+  }
+  else if (strcmp(m->desc, "hfuse") == 0) {
+    cmd = 'N';
+  }
+  else if (strcmp(m->desc, "efuse") == 0) {
+    cmd = 'Q';
+  }
+  else if (strcmp(m->desc, "lock") == 0) {
+    cmd = 'r';
+  }
+  else
+    return -1;
+
+  butterfly_send(pgm, &cmd, 1);
+  butterfly_recv(pgm, (char *)value, 1);
+
+  return *value == '?'? -1: 0;
+}
+
+
+
+static int butterfly_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, 
+                              int page_size, int n_bytes)
+{
+  unsigned int addr = 0;
+  unsigned int max_addr = n_bytes;
+  char *cmd;
+  unsigned int blocksize = PDATA(pgm)->buffersize;
+  int use_ext_addr = m->op[AVR_OP_LOAD_EXT_ADDR] != NULL;
+
+  if (strcmp(m->desc, "flash") && strcmp(m->desc, "eeprom")) 
+    return -2;
+
+  if (m->desc[0] == 'e')
+    blocksize = 1;		/* Write to eeprom single bytes only */
+
+  if (use_ext_addr) {
+    butterfly_set_extaddr(pgm, addr);
+  } else {
+    butterfly_set_addr(pgm, addr);
+  }
+
+#if 0
+  usleep(1000000);
+  butterfly_send(pgm, "y", 1);
+  butterfly_vfy_cmd_sent(pgm, "clear LED");
+#endif
+
+  cmd = malloc(4+blocksize);
+  if (!cmd) return -1;
+  cmd[0] = 'B';
+  cmd[3] = toupper(m->desc[0]);
+
+  while (addr < max_addr) {
+    if ((max_addr - addr) < blocksize) {
+      blocksize = max_addr - addr;
+    };
+    memcpy(&cmd[4], &m->buf[addr], blocksize);
+    cmd[1] = (blocksize >> 8) & 0xff;
+    cmd[2] = blocksize & 0xff;
+
+    butterfly_send(pgm, cmd, 4+blocksize);
+    butterfly_vfy_cmd_sent(pgm, "write block");
+
+    addr += blocksize;
+
+    report_progress (addr, max_addr, NULL);
+  } /* while */
+  free(cmd);
+
+  return addr;
+}
+
+
+
+static int butterfly_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, 
+                             int page_size, int n_bytes)
+{
+  unsigned int addr = 0;
+  unsigned int max_addr = n_bytes;
+  int rd_size = 1;
+  int use_ext_addr = m->op[AVR_OP_LOAD_EXT_ADDR] != NULL;
+
+  /* check parameter syntax: only "flash" or "eeprom" is allowed */
+  if (strcmp(m->desc, "flash") && strcmp(m->desc, "eeprom")) 
+    return -2;
+
+  {		/* use buffered mode */
+    char cmd[4];
+    int blocksize = PDATA(pgm)->buffersize;
+
+    cmd[0] = 'g';
+    cmd[3] = toupper(m->desc[0]);
+
+    if (use_ext_addr) {
+      butterfly_set_extaddr(pgm, addr);
+    } else {
+      butterfly_set_addr(pgm, addr);
+    }
+    while (addr < max_addr) {
+      if ((max_addr - addr) < blocksize) {
+        blocksize = max_addr - addr;
+      };
+      cmd[1] = (blocksize >> 8) & 0xff;
+      cmd[2] = blocksize & 0xff;
+
+      butterfly_send(pgm, cmd, 4);
+      butterfly_recv(pgm, (char *)&m->buf[addr], blocksize);
+
+      addr += blocksize;
+
+      report_progress (addr, max_addr, NULL);
+    } /* while */
+  }
+
+  return addr * rd_size;
+}
+
+
+/* Signature byte reads are always 3 bytes. */
+static int butterfly_read_sig_bytes(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m)
+{
+  unsigned char tmp;
+
+  if (m->size < 3) {
+    fprintf(stderr, "%s: memsize too small for sig byte read", progname);
+    return -1;
+  }
+
+  butterfly_send(pgm, "s", 1);
+  butterfly_recv(pgm, (char *)m->buf, 3);
+  /* Returned signature has wrong order. */
+  tmp = m->buf[2];
+  m->buf[2] = m->buf[0];
+  m->buf[0] = tmp;
+
+  return 3;
+}
+
+
+void butterfly_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "avr910");
+
+  /*
+   * mandatory functions
+   */
+  pgm->rdy_led        = butterfly_rdy_led;
+  pgm->err_led        = butterfly_err_led;
+  pgm->pgm_led        = butterfly_pgm_led;
+  pgm->vfy_led        = butterfly_vfy_led;
+  pgm->initialize     = butterfly_initialize;
+  pgm->display        = butterfly_display;
+  pgm->enable         = butterfly_enable;
+  pgm->disable        = butterfly_disable;
+  pgm->powerup        = butterfly_powerup;
+  pgm->powerdown      = butterfly_powerdown;
+  pgm->program_enable = butterfly_program_enable;
+  pgm->chip_erase     = butterfly_chip_erase;
+  pgm->open           = butterfly_open;
+  pgm->close          = butterfly_close;
+  pgm->read_byte      = butterfly_read_byte;
+  pgm->write_byte     = butterfly_write_byte;
+
+  /*
+   * optional functions
+   */
+
+  pgm->paged_write = butterfly_paged_write;
+  pgm->paged_load = butterfly_paged_load;
+
+  pgm->read_sig_bytes = butterfly_read_sig_bytes;
+
+  pgm->setup          = butterfly_setup;
+  pgm->teardown       = butterfly_teardown;
+}
diff --git a/avrdude/butterfly.h b/avrdude/butterfly.h
new file mode 100644
index 00000000..51abdc0a
--- /dev/null
+++ b/avrdude/butterfly.h
@@ -0,0 +1,35 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2003-2004  Theodore A. Roth  <troth@openavr.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id$ */
+
+#ifndef butterfly_h
+#define butterfly_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void butterfly_initpgm (PROGRAMMER * pgm);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* butterfly_h */
diff --git a/avrdude/config.c b/avrdude/config.c
new file mode 100644
index 00000000..7105884a
--- /dev/null
+++ b/avrdude/config.c
@@ -0,0 +1,306 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2000-2004  Brian S. Dean <bsd@bsdhome.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id$ */
+
+#include "ac_cfg.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "avrdude.h"
+#include "avr.h"
+#include "config.h"
+#include "config_gram.h"
+
+char default_programmer[MAX_STR_CONST];
+char default_parallel[PATH_MAX];
+char default_serial[PATH_MAX];
+
+char string_buf[MAX_STR_CONST];
+char *string_buf_ptr;
+
+LISTID       string_list;
+LISTID       number_list;
+PROGRAMMER * current_prog;
+AVRPART    * current_part;
+AVRMEM     * current_mem;
+LISTID       part_list;
+LISTID       programmers;
+
+int    lineno;
+const char * infile;
+
+extern char * yytext;
+
+#define DEBUG 0
+
+
+int init_config(void)
+{
+  string_list  = lcreat(NULL, 0);
+  number_list  = lcreat(NULL, 0);
+  current_prog = NULL;
+  current_part = NULL;
+  current_mem  = 0;
+  part_list    = lcreat(NULL, 0);
+  programmers  = lcreat(NULL, 0);
+
+  lineno       = 1;
+  infile       = NULL;
+
+  return 0;
+}
+
+
+
+int yywrap()
+{
+  return 1;
+}
+
+
+int yyerror(char * errmsg)
+{
+  fprintf(stderr, "%s at %s:%d\n", errmsg, infile, lineno);
+  exit(1);
+}
+
+
+TOKEN * new_token(int primary)
+{
+  TOKEN * tkn;
+
+  tkn = (TOKEN *)malloc(sizeof(TOKEN));
+  if (tkn == NULL) {
+    fprintf(stderr, "new_token(): out of memory\n");
+    exit(1);
+  }
+
+  memset(tkn, 0, sizeof(TOKEN));
+
+  tkn->primary = primary;
+
+  return tkn;
+}
+
+
+void free_token(TOKEN * tkn)
+{
+  if (tkn) {
+    switch (tkn->primary) {
+      case TKN_STRING:
+      case TKN_ID:
+        if (tkn->value.string)
+          free(tkn->value.string);
+        tkn->value.string = NULL;
+        break;
+    }
+    
+    free(tkn);
+  }
+}
+
+
+void free_tokens(int n, ...)
+{
+  TOKEN * t;
+  va_list ap;
+
+  va_start(ap, n);
+  while (n--) {
+    t = va_arg(ap, TOKEN *);
+    free_token(t);
+  }
+  va_end(ap);
+}
+
+
+
+TOKEN * number(char * text)
+{
+  struct token_t * tkn;
+
+  tkn = new_token(TKN_NUMBER);
+  tkn->value.type   = V_NUM;
+  tkn->value.number = atof(text);
+
+#if DEBUG
+  fprintf(stderr, "NUMBER(%g)\n", tkn->value.number);
+#endif
+
+  return tkn;
+}
+
+
+TOKEN * hexnumber(char * text)
+{
+  struct token_t * tkn;
+  char * e;
+
+  tkn = new_token(TKN_NUMBER);
+  tkn->value.type   = V_NUM;
+  tkn->value.number = strtoul(text, &e, 16);
+  if ((e == text) || (*e != 0)) {
+    fprintf(stderr, "error at %s:%d: can't scan hex number \"%s\"\n",
+            infile, lineno, text);
+    exit(1);
+  }
+  
+#if DEBUG
+  fprintf(stderr, "HEXNUMBER(%g)\n", tkn->value.number);
+#endif
+
+  return tkn;
+}
+
+
+TOKEN * string(char * text)
+{
+  struct token_t * tkn;
+  int len;
+
+  tkn = new_token(TKN_STRING);
+
+  len = strlen(text);
+
+  tkn->value.type   = V_STR;
+  tkn->value.string = (char *) malloc(len+1);
+  if (tkn->value.string == NULL) {
+    fprintf(stderr, "id(): out of memory\n");
+    exit(1);
+  }
+  strcpy(tkn->value.string, text);
+
+#if DEBUG
+  fprintf(stderr, "STRING(%s)\n", tkn->value.string);
+#endif
+
+  return tkn;
+}
+
+
+TOKEN * id(char * text)
+{
+  struct token_t * tkn;
+  int len;
+
+  tkn = new_token(TKN_ID);
+
+  len = strlen(text);
+
+  tkn->value.type   = V_STR;
+  tkn->value.string = (char *) malloc(len+1);
+  if (tkn->value.string == NULL) {
+    fprintf(stderr, "id(): out of memory\n");
+    exit(1);
+  }
+  strcpy(tkn->value.string, text);
+
+#if DEBUG
+  fprintf(stderr, "ID(%s)\n", tkn->value.string);
+#endif
+
+  return tkn;
+}
+
+
+TOKEN * keyword(int primary)
+{
+  struct token_t * tkn;
+
+  tkn = new_token(primary);
+
+  return tkn;
+}
+
+
+void print_token(TOKEN * tkn)
+{
+  if (!tkn)
+    return;
+
+  fprintf(stderr, "token = %d = ", tkn->primary);
+  switch (tkn->primary) {
+    case TKN_NUMBER: 
+      fprintf(stderr, "NUMBER, value=%g", tkn->value.number); 
+      break;
+
+    case TKN_STRING: 
+      fprintf(stderr, "STRING, value=%s", tkn->value.string); 
+      break;
+
+    case TKN_ID:  
+      fprintf(stderr, "ID,     value=%s", tkn->value.string); 
+      break;
+
+    default:     
+      fprintf(stderr, "<other>"); 
+      break;
+  }
+
+  fprintf(stderr, "\n");
+}
+
+
+void pyytext(void)
+{
+#if DEBUG
+  fprintf(stderr, "TOKEN: \"%s\"\n", yytext);
+#endif
+}
+
+
+char * dup_string(const char * str)
+{
+  char * s;
+
+  s = strdup(str);
+  if (s == NULL) {
+    fprintf(stderr, "dup_string(): out of memory\n");
+    exit(1);
+  }
+
+  return s;
+}
+
+int read_config(const char * file)
+{
+  FILE * f;
+
+  f = fopen(file, "r");
+  if (f == NULL) {
+    fprintf(stderr, "%s: can't open config file \"%s\": %s\n",
+            progname, file, strerror(errno));
+    return -1;
+  }
+
+  lineno = 1;
+  infile = file;
+  yyin   = f;
+
+  yyparse();
+
+  fclose(f);
+
+  return 0;
+}
diff --git a/avrdude/config.h b/avrdude/config.h
new file mode 100644
index 00000000..e557bf4d
--- /dev/null
+++ b/avrdude/config.h
@@ -0,0 +1,108 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2000-2004  Brian S. Dean <bsd@bsdhome.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id$ */
+
+#ifndef config_h
+#define config_h
+
+#include "lists.h"
+#include "pindefs.h"
+#include "avr.h"
+
+
+#define MAX_STR_CONST 1024
+
+enum { V_NONE, V_NUM, V_STR };
+typedef struct value_t {
+  int      type;
+  double   number;
+  char   * string;
+} VALUE;
+
+
+typedef struct token_t {
+  int primary;
+  VALUE value;
+} TOKEN;
+typedef struct token_t *token_p;
+
+
+extern FILE       * yyin;
+extern PROGRAMMER * current_prog;
+extern AVRPART    * current_part;
+extern AVRMEM     * current_mem;
+extern int          lineno;
+extern const char * infile;
+extern LISTID       string_list;
+extern LISTID       number_list;
+extern LISTID       part_list;
+extern LISTID       programmers;
+extern char         default_programmer[];
+extern char         default_parallel[];
+extern char         default_serial[];
+
+
+
+#if !defined(HAS_YYSTYPE)
+#define YYSTYPE token_p
+#endif
+extern YYSTYPE yylval;
+
+extern char string_buf[MAX_STR_CONST];
+extern char *string_buf_ptr;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int yyparse(void);
+
+
+int init_config(void);
+
+TOKEN * new_token(int primary);
+
+void free_token(TOKEN * tkn);
+
+void free_tokens(int n, ...);
+
+TOKEN * number(char * text);
+
+TOKEN * hexnumber(char * text);
+
+TOKEN * string(char * text);
+
+TOKEN * id(char * text);
+
+TOKEN * keyword(int primary);
+
+void print_token(TOKEN * tkn);
+
+void pyytext(void);
+
+char * dup_string(const char * str);
+
+int read_config(const char * file);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/avrdude/config_gram.y b/avrdude/config_gram.y
new file mode 100644
index 00000000..2ff8452a
--- /dev/null
+++ b/avrdude/config_gram.y
@@ -0,0 +1,1523 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2000-2004  Brian S. Dean <bsd@bsdhome.com>
+ * Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 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
+ */
+
+/* $Id$ */
+%{
+
+#include "ac_cfg.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "avrdude.h"
+
+#include "config.h"
+#include "lists.h"
+#include "par.h"
+#include "serbb.h"
+#include "pindefs.h"
+#include "ppi.h"
+#include "pgm.h"
+#include "stk500.h"
+#include "arduino.h"
+#include "buspirate.h"
+#include "stk500v2.h"
+#include "stk500generic.h"
+#include "avr910.h"
+#include "butterfly.h"
+#include "usbasp.h"
+#include "usbtiny.h"
+#include "avr.h"
+#include "jtagmkI.h"
+#include "jtagmkII.h"
+
+#if defined(WIN32NATIVE)
+#define strtok_r( _s, _sep, _lasts ) \
+    ( *(_lasts) = strtok( (_s), (_sep) ) )
+#endif
+
+int yylex(void);
+int yyerror(char * errmsg);
+
+static int assign_pin(int pinno, TOKEN * v, int invert);
+static int which_opcode(TOKEN * opcode);
+static int parse_cmdbits(OPCODE * op);
+ 
+%}
+
+%token K_READ
+%token K_WRITE
+%token K_READ_LO
+%token K_READ_HI
+%token K_WRITE_LO
+%token K_WRITE_HI
+%token K_LOADPAGE_LO
+%token K_LOADPAGE_HI
+%token K_LOAD_EXT_ADDR
+%token K_WRITEPAGE
+%token K_CHIP_ERASE
+%token K_PGM_ENABLE
+
+%token K_MEMORY
+
+%token K_PAGE_SIZE
+%token K_PAGED
+
+%token K_ARDUINO
+%token K_BAUDRATE
+%token K_BS2
+%token K_BUFF
+%token K_BUSPIRATE
+%token K_CHIP_ERASE_DELAY
+%token K_DEDICATED
+%token K_DEFAULT_PARALLEL
+%token K_DEFAULT_PROGRAMMER
+%token K_DEFAULT_SERIAL
+%token K_DESC
+%token K_DEVICECODE
+%token K_DRAGON_DW
+%token K_DRAGON_HVSP
+%token K_DRAGON_ISP
+%token K_DRAGON_JTAG
+%token K_DRAGON_PDI
+%token K_DRAGON_PP
+%token K_STK500_DEVCODE
+%token K_AVR910_DEVCODE
+%token K_EEPROM
+%token K_ERRLED
+%token K_FLASH
+%token K_ID
+%token K_IO
+%token K_JTAG_MKI
+%token K_JTAG_MKII
+%token K_JTAG_MKII_AVR32
+%token K_JTAG_MKII_DW
+%token K_JTAG_MKII_ISP
+%token K_JTAG_MKII_PDI
+%token K_LOADPAGE
+%token K_MAX_WRITE_DELAY
+%token K_MIN_WRITE_DELAY
+%token K_MISO
+%token K_MOSI
+%token K_NUM_PAGES
+%token K_NVM_BASE
+%token K_OFFSET
+%token K_PAGEL
+%token K_PAR
+%token K_PARALLEL
+%token K_PART
+%token K_PGMLED
+%token K_PROGRAMMER
+%token K_PSEUDO
+%token K_PWROFF_AFTER_WRITE
+%token K_RDYLED
+%token K_READBACK_P1
+%token K_READBACK_P2
+%token K_READMEM
+%token K_RESET
+%token K_RETRY_PULSE
+%token K_SERBB
+%token K_SERIAL
+%token K_SCK
+%token K_SIGNATURE
+%token K_SIZE
+%token K_STK500
+%token K_STK500HVSP
+%token K_STK500PP
+%token K_STK500V2
+%token K_STK500GENERIC
+%token K_STK600
+%token K_STK600HVSP
+%token K_STK600PP
+%token K_AVR910
+%token K_USBASP
+%token K_USBTINY
+%token K_BUTTERFLY
+%token K_TYPE
+%token K_VCC
+%token K_VFYLED
+
+%token K_NO
+%token K_YES
+
+/* stk500 v2 xml file parameters */
+/* ISP */
+%token K_TIMEOUT
+%token K_STABDELAY
+%token K_CMDEXEDELAY
+%token K_HVSPCMDEXEDELAY
+%token K_SYNCHLOOPS
+%token K_BYTEDELAY
+%token K_POLLVALUE
+%token K_POLLINDEX
+%token K_PREDELAY
+%token K_POSTDELAY
+%token K_POLLMETHOD
+%token K_MODE
+%token K_DELAY
+%token K_BLOCKSIZE
+%token K_READSIZE
+/* HV mode */
+%token K_HVENTERSTABDELAY
+%token K_PROGMODEDELAY
+%token K_LATCHCYCLES
+%token K_TOGGLEVTG
+%token K_POWEROFFDELAY
+%token K_RESETDELAYMS
+%token K_RESETDELAYUS
+%token K_HVLEAVESTABDELAY
+%token K_RESETDELAY
+%token K_SYNCHCYCLES
+%token K_HVCMDEXEDELAY
+
+%token K_CHIPERASEPULSEWIDTH
+%token K_CHIPERASEPOLLTIMEOUT
+%token K_CHIPERASETIME
+%token K_PROGRAMFUSEPULSEWIDTH
+%token K_PROGRAMFUSEPOLLTIMEOUT
+%token K_PROGRAMLOCKPULSEWIDTH
+%token K_PROGRAMLOCKPOLLTIMEOUT
+
+%token K_PP_CONTROLSTACK
+%token K_HVSP_CONTROLSTACK
+
+/* JTAG ICE mkII specific parameters */
+%token K_ALLOWFULLPAGEBITSTREAM	/*
+				 * Internal parameter for the JTAG
+				 * ICE; describes the internal JTAG
+				 * streaming behaviour inside the MCU.
+				 * 1 for all older chips, 0 for newer
+				 * MCUs.
+				 */
+%token K_ENABLEPAGEPROGRAMMING	/* ? yes for mega256*, mega406 */
+%token K_HAS_JTAG		/* MCU has JTAG i/f. */
+%token K_HAS_DW			/* MCU has debugWire i/f. */
+%token K_HAS_PDI                /* MCU has PDI i/f rather than ISP (ATxmega). */
+%token K_HAS_TPI                /* MCU has TPI i/f rather than ISP (ATtiny4/5/9/10). */
+%token K_IDR			/* address of OCD register in IO space */
+%token K_IS_AVR32               /* chip is in the avr32 family */
+%token K_RAMPZ			/* address of RAMPZ reg. in IO space */
+%token K_SPMCR			/* address of SPMC[S]R in memory space */
+%token K_EECR    		/* address of EECR in memory space */
+%token K_FLASH_INSTR		/* flash instructions */
+%token K_EEPROM_INSTR		/* EEPROM instructions */
+
+%token TKN_COMMA
+%token TKN_EQUAL
+%token TKN_SEMI
+%token TKN_TILDE
+%token TKN_NUMBER
+%token TKN_STRING
+%token TKN_ID
+
+%start configuration
+
+%%
+
+configuration :
+  /* empty */ | config
+;
+
+config :
+  def |
+  config def
+;
+
+
+def :
+  prog_def TKN_SEMI |
+
+  part_def TKN_SEMI |
+
+  K_DEFAULT_PROGRAMMER TKN_EQUAL TKN_STRING TKN_SEMI {
+    strncpy(default_programmer, $3->value.string, MAX_STR_CONST);
+    default_programmer[MAX_STR_CONST-1] = 0;
+    free_token($3);
+  } |
+
+  K_DEFAULT_PARALLEL TKN_EQUAL TKN_STRING TKN_SEMI {
+    strncpy(default_parallel, $3->value.string, PATH_MAX);
+    default_parallel[PATH_MAX-1] = 0;
+    free_token($3);
+  } |
+
+  K_DEFAULT_SERIAL TKN_EQUAL TKN_STRING TKN_SEMI {
+    strncpy(default_serial, $3->value.string, PATH_MAX);
+    default_serial[PATH_MAX-1] = 0;
+    free_token($3);
+  }
+;
+
+
+prog_def :
+  K_PROGRAMMER 
+    { current_prog = pgm_new();
+      strcpy(current_prog->config_file, infile);
+      current_prog->lineno = lineno;
+    }
+    prog_parms
+    { 
+      if (lsize(current_prog->id) == 0) {
+        fprintf(stderr,
+                "%s: error at %s:%d: required parameter id not specified\n",
+                progname, infile, lineno);
+        exit(1);
+      }
+      if (current_prog->type[0] == 0) {
+        fprintf(stderr, "%s: error at %s:%d: programmer type not specified\n",
+                progname, infile, lineno);
+        exit(1);
+      }
+      PUSH(programmers, current_prog); 
+      current_prog = NULL; 
+    }
+;
+
+
+part_def :
+  K_PART
+    {
+      current_part = avr_new_part();
+      strcpy(current_part->config_file, infile);
+      current_part->lineno = lineno;
+    }
+    part_parms 
+    { 
+      LNODEID ln;
+      AVRMEM * m;
+
+      if (current_part->id[0] == 0) {
+        fprintf(stderr,
+                "%s: error at %s:%d: required parameter id not specified\n",
+                progname, infile, lineno);
+        exit(1);
+      }
+
+      /*
+       * perform some sanity checking, and compute the number of bits
+       * to shift a page for constructing the page address for
+       * page-addressed memories.
+       */
+      for (ln=lfirst(current_part->mem); ln; ln=lnext(ln)) {
+        m = ldata(ln);
+        if (m->paged) {
+          if (m->page_size == 0) {
+            fprintf(stderr, 
+                    "%s: error at %s:%d: must specify page_size for paged "
+                    "memory\n",
+                    progname, infile, lineno);
+            exit(1);
+          }
+          if (m->num_pages == 0) {
+            fprintf(stderr, 
+                    "%s: error at %s:%d: must specify num_pages for paged "
+                    "memory\n",
+                    progname, infile, lineno);
+            exit(1);
+          }
+          if (m->size != m->page_size * m->num_pages) {
+            fprintf(stderr, 
+                    "%s: error at %s:%d: page size (%u) * num_pages (%u) = "
+                    "%u does not match memory size (%u)\n",
+                    progname, infile, lineno,
+                    m->page_size, 
+                    m->num_pages, 
+                    m->page_size * m->num_pages,
+                    m->size);
+            exit(1);
+          }
+
+        }
+      }
+
+      PUSH(part_list, current_part); 
+      current_part = NULL; 
+    }
+;
+
+
+string_list :
+  TKN_STRING { ladd(string_list, $1); } |
+  string_list TKN_COMMA TKN_STRING { ladd(string_list, $3); }
+;
+
+
+num_list :
+  TKN_NUMBER { ladd(number_list, $1); } |
+  num_list TKN_COMMA TKN_NUMBER { ladd(number_list, $3); }
+;
+
+
+prog_parms :
+  prog_parm TKN_SEMI |
+  prog_parms prog_parm TKN_SEMI
+;
+
+
+prog_parm :
+  K_ID TKN_EQUAL string_list {
+    { 
+      TOKEN * t;
+      while (lsize(string_list)) {
+        t = lrmv_n(string_list, 1);
+        ladd(current_prog->id, dup_string(t->value.string));
+        free_token(t);
+      }
+    }
+  } |
+
+  K_TYPE TKN_EQUAL K_PAR {
+    { 
+      par_initpgm(current_prog);
+    }
+  } |
+
+  K_TYPE TKN_EQUAL K_SERBB {
+    {
+      serbb_initpgm(current_prog);
+    }
+  } |
+
+  K_TYPE TKN_EQUAL K_STK500 {
+    { 
+      stk500_initpgm(current_prog);
+    }
+  } |
+
+  K_TYPE TKN_EQUAL K_STK500V2 {
+    {
+      stk500v2_initpgm(current_prog);
+    }
+  } |
+
+  K_TYPE TKN_EQUAL K_STK500HVSP {
+    {
+      stk500hvsp_initpgm(current_prog);
+    }
+  } |
+
+  K_TYPE TKN_EQUAL K_STK500PP {
+    {
+      stk500pp_initpgm(current_prog);
+    }
+  } |
+
+  K_TYPE TKN_EQUAL K_STK500GENERIC {
+    {
+      stk500generic_initpgm(current_prog);
+    }
+  } |
+
+  K_TYPE TKN_EQUAL K_ARDUINO {
+    { 
+      arduino_initpgm(current_prog);
+    }
+  } |
+
+  K_TYPE TKN_EQUAL K_BUSPIRATE {
+    {
+      buspirate_initpgm(current_prog);
+    }
+  } |
+
+  K_TYPE TKN_EQUAL K_STK600 {
+    {
+      stk600_initpgm(current_prog);
+    }
+  } |
+
+  K_TYPE TKN_EQUAL K_STK600HVSP {
+    {
+      stk600hvsp_initpgm(current_prog);
+    }
+  } |
+
+  K_TYPE TKN_EQUAL K_STK600PP {
+    {
+      stk600pp_initpgm(current_prog);
+    }
+  } |
+
+  K_TYPE TKN_EQUAL K_AVR910 {
+    { 
+      avr910_initpgm(current_prog);
+    }
+  } |
+
+  K_TYPE TKN_EQUAL K_USBASP {
+    {
+      usbasp_initpgm(current_prog);
+    }
+  } |
+
+  K_TYPE TKN_EQUAL K_USBTINY {
+    {
+      usbtiny_initpgm(current_prog);
+    }
+  } |
+
+  K_TYPE TKN_EQUAL K_BUTTERFLY {
+    { 
+      butterfly_initpgm(current_prog);
+    }
+  } |
+
+  K_TYPE TKN_EQUAL K_JTAG_MKI {
+    {
+      jtagmkI_initpgm(current_prog);
+    }
+  } |
+
+  K_TYPE TKN_EQUAL K_JTAG_MKII {
+    {
+      jtagmkII_initpgm(current_prog);
+    }
+  } |
+  K_TYPE TKN_EQUAL K_JTAG_MKII_AVR32 {
+    {
+      jtagmkII_avr32_initpgm(current_prog);
+    }
+  } |
+
+  K_TYPE TKN_EQUAL K_JTAG_MKII_DW {
+    {
+      jtagmkII_dw_initpgm(current_prog);
+    }
+  } |
+
+  K_TYPE TKN_EQUAL K_JTAG_MKII_ISP {
+    {
+      stk500v2_jtagmkII_initpgm(current_prog);
+    }
+  } |
+
+  K_TYPE TKN_EQUAL K_JTAG_MKII_PDI {
+    {
+      jtagmkII_pdi_initpgm(current_prog);
+    }
+  } |
+
+  K_TYPE TKN_EQUAL K_DRAGON_DW {
+    {
+      jtagmkII_dragon_dw_initpgm(current_prog);
+    }
+  } |
+
+  K_TYPE TKN_EQUAL K_DRAGON_HVSP {
+    {
+      stk500v2_dragon_hvsp_initpgm(current_prog);
+    }
+  } |
+
+  K_TYPE TKN_EQUAL K_DRAGON_ISP {
+    {
+      stk500v2_dragon_isp_initpgm(current_prog);
+    }
+  } |
+
+  K_TYPE TKN_EQUAL K_DRAGON_JTAG {
+    {
+      jtagmkII_dragon_initpgm(current_prog);
+    }
+  } |
+
+  K_TYPE TKN_EQUAL K_DRAGON_PDI {
+    {
+      jtagmkII_dragon_pdi_initpgm(current_prog);
+    }
+  } |
+
+  K_TYPE TKN_EQUAL K_DRAGON_PP {
+    {
+      stk500v2_dragon_pp_initpgm(current_prog);
+    }
+  } |
+
+  K_DESC TKN_EQUAL TKN_STRING {
+    strncpy(current_prog->desc, $3->value.string, PGM_DESCLEN);
+    current_prog->desc[PGM_DESCLEN-1] = 0;
+    free_token($3);
+  } |
+
+  K_VCC TKN_EQUAL num_list {
+    { 
+      TOKEN * t;
+      int pin;
+
+      current_prog->pinno[PPI_AVR_VCC] = 0;
+
+      while (lsize(number_list)) {
+        t = lrmv_n(number_list, 1);
+        pin = t->value.number;
+        current_prog->pinno[PPI_AVR_VCC] |= (1 << pin);
+
+        free_token(t);
+      }
+    }
+  } |
+
+  K_BUFF TKN_EQUAL num_list {
+    { 
+      TOKEN * t;
+      int pin;
+
+      current_prog->pinno[PPI_AVR_BUFF] = 0;
+
+      while (lsize(number_list)) {
+        t = lrmv_n(number_list, 1);
+        pin = t->value.number;
+        current_prog->pinno[PPI_AVR_BUFF] |= (1 << pin);
+
+        free_token(t);
+      }
+    }
+  } |
+
+  K_BAUDRATE TKN_EQUAL TKN_NUMBER {
+    {
+      current_prog->baudrate = $3->value.number;
+    }
+  } |
+
+  K_RESET  TKN_EQUAL TKN_NUMBER { free_token($1); 
+                                  assign_pin(PIN_AVR_RESET, $3, 0); } |
+  K_SCK    TKN_EQUAL TKN_NUMBER { free_token($1); 
+                                  assign_pin(PIN_AVR_SCK, $3, 0); } |
+  K_MOSI   TKN_EQUAL TKN_NUMBER { assign_pin(PIN_AVR_MOSI, $3, 0); } |
+  K_MISO   TKN_EQUAL TKN_NUMBER { assign_pin(PIN_AVR_MISO, $3, 0); } |
+  K_ERRLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_ERR, $3, 0); } |
+  K_RDYLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_RDY, $3, 0); } |
+  K_PGMLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_PGM, $3, 0); } |
+  K_VFYLED TKN_EQUAL TKN_NUMBER { assign_pin(PIN_LED_VFY, $3, 0); } |
+
+  K_RESET  TKN_EQUAL TKN_TILDE TKN_NUMBER { free_token($1); 
+                                  assign_pin(PIN_AVR_RESET, $4, 1); } |
+  K_SCK    TKN_EQUAL TKN_TILDE TKN_NUMBER { free_token($1); 
+                                  assign_pin(PIN_AVR_SCK, $4, 1); } |
+  K_MOSI   TKN_EQUAL TKN_TILDE TKN_NUMBER { assign_pin(PIN_AVR_MOSI, $4, 1); } |
+  K_MISO   TKN_EQUAL TKN_TILDE TKN_NUMBER { assign_pin(PIN_AVR_MISO, $4, 1); } |
+  K_ERRLED TKN_EQUAL TKN_TILDE TKN_NUMBER { assign_pin(PIN_LED_ERR, $4, 1); } |
+  K_RDYLED TKN_EQUAL TKN_TILDE TKN_NUMBER { assign_pin(PIN_LED_RDY, $4, 1); } |
+  K_PGMLED TKN_EQUAL TKN_TILDE TKN_NUMBER { assign_pin(PIN_LED_PGM, $4, 1); } |
+  K_VFYLED TKN_EQUAL TKN_TILDE TKN_NUMBER { assign_pin(PIN_LED_VFY, $4, 1); }
+;
+
+
+opcode :
+  K_READ         |
+  K_WRITE        |
+  K_READ_LO      |
+  K_READ_HI      |
+  K_WRITE_LO     |
+  K_WRITE_HI     |
+  K_LOADPAGE_LO  |
+  K_LOADPAGE_HI  |
+  K_LOAD_EXT_ADDR |
+  K_WRITEPAGE    |
+  K_CHIP_ERASE   |
+  K_PGM_ENABLE
+;
+
+
+part_parms :
+  part_parm TKN_SEMI |
+  part_parms part_parm TKN_SEMI
+;
+
+
+reset_disposition :
+  K_DEDICATED | K_IO
+;
+
+parallel_modes :
+  yesno | K_PSEUDO
+;
+
+retry_lines :
+  K_RESET | K_SCK
+;
+
+part_parm :
+  K_ID TKN_EQUAL TKN_STRING 
+    {
+      strncpy(current_part->id, $3->value.string, AVR_IDLEN);
+      current_part->id[AVR_IDLEN-1] = 0;
+      free_token($3);
+    } |
+
+  K_DESC TKN_EQUAL TKN_STRING 
+    {
+      strncpy(current_part->desc, $3->value.string, AVR_DESCLEN);
+      current_part->desc[AVR_DESCLEN-1] = 0;
+      free_token($3);
+    } |
+
+  K_DEVICECODE TKN_EQUAL TKN_NUMBER {
+    {
+      fprintf(stderr, 
+              "%s: error at %s:%d: devicecode is deprecated, use "
+              "stk500_devcode instead\n",
+              progname, infile, lineno);
+      exit(1);
+    }
+  } |
+
+  K_STK500_DEVCODE TKN_EQUAL TKN_NUMBER {
+    {
+      current_part->stk500_devcode = $3->value.number;
+      free_token($3);
+    }
+  } |
+
+  K_AVR910_DEVCODE TKN_EQUAL TKN_NUMBER {
+    {
+      current_part->avr910_devcode = $3->value.number;
+      free_token($3);
+    }
+  } |
+
+  K_SIGNATURE TKN_EQUAL TKN_NUMBER TKN_NUMBER TKN_NUMBER {
+    {
+      current_part->signature[0] = $3->value.number;
+      current_part->signature[1] = $4->value.number;
+      current_part->signature[2] = $5->value.number;
+      free_token($3);
+      free_token($4);
+      free_token($5);
+    }
+  } |
+
+  K_PP_CONTROLSTACK TKN_EQUAL num_list {
+    {
+      TOKEN * t;
+      unsigned nbytes;
+      int ok;
+
+      if (current_part->ctl_stack_type != CTL_STACK_NONE)
+	{
+	  fprintf(stderr,
+		  "%s: error at line %d of %s: "
+		  "control stack already defined\n",
+		  progname, lineno, infile);
+	  exit(1);
+	}
+
+      current_part->ctl_stack_type = CTL_STACK_PP;
+      nbytes = 0;
+      ok = 1;
+
+      while (lsize(number_list)) {
+        t = lrmv_n(number_list, 1);
+	if (nbytes < CTL_STACK_SIZE)
+	  {
+	    current_part->controlstack[nbytes] = t->value.number;
+	    nbytes++;
+	  }
+	else
+	  {
+	    ok = 0;
+	  }
+        free_token(t);
+      }
+      if (!ok)
+	{
+	  fprintf(stderr,
+                  "%s: Warning: line %d of %s: "
+		  "too many bytes in control stack\n",
+                  progname, lineno, infile);
+        }
+    }
+  } |
+
+  K_HVSP_CONTROLSTACK TKN_EQUAL num_list {
+    {
+      TOKEN * t;
+      unsigned nbytes;
+      int ok;
+
+      if (current_part->ctl_stack_type != CTL_STACK_NONE)
+	{
+	  fprintf(stderr,
+		  "%s: error at line %d of %s: "
+		  "control stack already defined\n",
+		  progname, lineno, infile);
+	  exit(1);
+	}
+
+      current_part->ctl_stack_type = CTL_STACK_HVSP;
+      nbytes = 0;
+      ok = 1;
+
+      while (lsize(number_list)) {
+        t = lrmv_n(number_list, 1);
+	if (nbytes < CTL_STACK_SIZE)
+	  {
+	    current_part->controlstack[nbytes] = t->value.number;
+	    nbytes++;
+	  }
+	else
+	  {
+	    ok = 0;
+	  }
+        free_token(t);
+      }
+      if (!ok)
+	{
+	  fprintf(stderr,
+                  "%s: Warning: line %d of %s: "
+		  "too many bytes in control stack\n",
+                  progname, lineno, infile);
+        }
+    }
+  } |
+
+  K_FLASH_INSTR TKN_EQUAL num_list {
+    {
+      TOKEN * t;
+      unsigned nbytes;
+      int ok;
+
+      nbytes = 0;
+      ok = 1;
+
+      while (lsize(number_list)) {
+        t = lrmv_n(number_list, 1);
+	if (nbytes < FLASH_INSTR_SIZE)
+	  {
+	    current_part->flash_instr[nbytes] = t->value.number;
+	    nbytes++;
+	  }
+	else
+	  {
+	    ok = 0;
+	  }
+        free_token(t);
+      }
+      if (!ok)
+	{
+	  fprintf(stderr,
+                  "%s: Warning: line %d of %s: "
+		  "too many bytes in flash instructions\n",
+                  progname, lineno, infile);
+        }
+    }
+  } |
+
+  K_EEPROM_INSTR TKN_EQUAL num_list {
+    {
+      TOKEN * t;
+      unsigned nbytes;
+      int ok;
+
+      nbytes = 0;
+      ok = 1;
+
+      while (lsize(number_list)) {
+        t = lrmv_n(number_list, 1);
+	if (nbytes < EEPROM_INSTR_SIZE)
+	  {
+	    current_part->eeprom_instr[nbytes] = t->value.number;
+	    nbytes++;
+	  }
+	else
+	  {
+	    ok = 0;
+	  }
+        free_token(t);
+      }
+      if (!ok)
+	{
+	  fprintf(stderr,
+                  "%s: Warning: line %d of %s: "
+		  "too many bytes in EEPROM instructions\n",
+                  progname, lineno, infile);
+        }
+    }
+  } |
+
+  K_CHIP_ERASE_DELAY TKN_EQUAL TKN_NUMBER
+    {
+      current_part->chip_erase_delay = $3->value.number;
+      free_token($3);
+    } |
+
+  K_PAGEL TKN_EQUAL TKN_NUMBER
+    {
+      current_part->pagel = $3->value.number;
+      free_token($3);
+    } |
+
+  K_BS2 TKN_EQUAL TKN_NUMBER
+    {
+      current_part->bs2 = $3->value.number;
+      free_token($3);
+    } |
+
+  K_RESET TKN_EQUAL reset_disposition
+    {
+      if ($3->primary == K_DEDICATED)
+        current_part->reset_disposition = RESET_DEDICATED;
+      else if ($3->primary == K_IO)
+        current_part->reset_disposition = RESET_IO;
+
+      free_tokens(2, $1, $3);
+    } |
+
+  K_TIMEOUT TKN_EQUAL TKN_NUMBER
+    {
+      current_part->timeout = $3->value.number;
+      free_token($3);
+    } |
+
+  K_STABDELAY TKN_EQUAL TKN_NUMBER
+    {
+      current_part->stabdelay = $3->value.number;
+      free_token($3);
+    } |
+
+  K_CMDEXEDELAY TKN_EQUAL TKN_NUMBER
+    {
+      current_part->cmdexedelay = $3->value.number;
+      free_token($3);
+    } |
+
+  K_HVSPCMDEXEDELAY TKN_EQUAL TKN_NUMBER
+    {
+      current_part->hvspcmdexedelay = $3->value.number;
+      free_token($3);
+    } |
+
+  K_SYNCHLOOPS TKN_EQUAL TKN_NUMBER
+    {
+      current_part->synchloops = $3->value.number;
+      free_token($3);
+    } |
+
+  K_BYTEDELAY TKN_EQUAL TKN_NUMBER
+    {
+      current_part->bytedelay = $3->value.number;
+      free_token($3);
+    } |
+
+  K_POLLVALUE TKN_EQUAL TKN_NUMBER
+    {
+      current_part->pollvalue = $3->value.number;
+      free_token($3);
+    } |
+
+  K_POLLINDEX TKN_EQUAL TKN_NUMBER
+    {
+      current_part->pollindex = $3->value.number;
+      free_token($3);
+    } |
+
+  K_PREDELAY TKN_EQUAL TKN_NUMBER
+    {
+      current_part->predelay = $3->value.number;
+      free_token($3);
+    } |
+
+  K_POSTDELAY TKN_EQUAL TKN_NUMBER
+    {
+      current_part->postdelay = $3->value.number;
+      free_token($3);
+    } |
+
+  K_POLLMETHOD TKN_EQUAL TKN_NUMBER
+    {
+      current_part->pollmethod = $3->value.number;
+      free_token($3);
+    } |
+
+  K_HVENTERSTABDELAY TKN_EQUAL TKN_NUMBER
+    {
+      current_part->hventerstabdelay = $3->value.number;
+      free_token($3);
+    } |
+
+  K_PROGMODEDELAY TKN_EQUAL TKN_NUMBER
+    {
+      current_part->progmodedelay = $3->value.number;
+      free_token($3);
+    } |
+
+  K_LATCHCYCLES TKN_EQUAL TKN_NUMBER
+    {
+      current_part->latchcycles = $3->value.number;
+      free_token($3);
+    } |
+
+  K_TOGGLEVTG TKN_EQUAL TKN_NUMBER
+    {
+      current_part->togglevtg = $3->value.number;
+      free_token($3);
+    } |
+
+  K_POWEROFFDELAY TKN_EQUAL TKN_NUMBER
+    {
+      current_part->poweroffdelay = $3->value.number;
+      free_token($3);
+    } |
+
+  K_RESETDELAYMS TKN_EQUAL TKN_NUMBER
+    {
+      current_part->resetdelayms = $3->value.number;
+      free_token($3);
+    } |
+
+  K_RESETDELAYUS TKN_EQUAL TKN_NUMBER
+    {
+      current_part->resetdelayus = $3->value.number;
+      free_token($3);
+    } |
+
+  K_HVLEAVESTABDELAY TKN_EQUAL TKN_NUMBER
+    {
+      current_part->hvleavestabdelay = $3->value.number;
+      free_token($3);
+    } |
+
+  K_RESETDELAY TKN_EQUAL TKN_NUMBER
+    {
+      current_part->resetdelay = $3->value.number;
+      free_token($3);
+    } |
+
+  K_CHIPERASEPULSEWIDTH TKN_EQUAL TKN_NUMBER
+    {
+      current_part->chiperasepulsewidth = $3->value.number;
+      free_token($3);
+    } |
+
+  K_CHIPERASEPOLLTIMEOUT TKN_EQUAL TKN_NUMBER
+    {
+      current_part->chiperasepolltimeout = $3->value.number;
+      free_token($3);
+    } |
+
+  K_CHIPERASETIME TKN_EQUAL TKN_NUMBER
+    {
+      current_part->chiperasetime = $3->value.number;
+      free_token($3);
+    } |
+
+  K_PROGRAMFUSEPULSEWIDTH TKN_EQUAL TKN_NUMBER
+    {
+      current_part->programfusepulsewidth = $3->value.number;
+      free_token($3);
+    } |
+
+  K_PROGRAMFUSEPOLLTIMEOUT TKN_EQUAL TKN_NUMBER
+    {
+      current_part->programfusepolltimeout = $3->value.number;
+      free_token($3);
+    } |
+
+  K_PROGRAMLOCKPULSEWIDTH TKN_EQUAL TKN_NUMBER
+    {
+      current_part->programlockpulsewidth = $3->value.number;
+      free_token($3);
+    } |
+
+  K_PROGRAMLOCKPOLLTIMEOUT TKN_EQUAL TKN_NUMBER
+    {
+      current_part->programlockpolltimeout = $3->value.number;
+      free_token($3);
+    } |
+
+  K_SYNCHCYCLES TKN_EQUAL TKN_NUMBER
+    {
+      current_part->synchcycles = $3->value.number;
+      free_token($3);
+    } |
+
+  K_HAS_JTAG TKN_EQUAL yesno
+    {
+      if ($3->primary == K_YES)
+        current_part->flags |= AVRPART_HAS_JTAG;
+      else if ($3->primary == K_NO)
+        current_part->flags &= ~AVRPART_HAS_JTAG;
+
+      free_token($3);
+    } |
+
+  K_HAS_DW TKN_EQUAL yesno
+    {
+      if ($3->primary == K_YES)
+        current_part->flags |= AVRPART_HAS_DW;
+      else if ($3->primary == K_NO)
+        current_part->flags &= ~AVRPART_HAS_DW;
+
+      free_token($3);
+    } |
+
+  K_HAS_PDI TKN_EQUAL yesno
+    {
+      if ($3->primary == K_YES)
+        current_part->flags |= AVRPART_HAS_PDI;
+      else if ($3->primary == K_NO)
+        current_part->flags &= ~AVRPART_HAS_PDI;
+
+      free_token($3);
+    } |
+
+  K_HAS_TPI TKN_EQUAL yesno
+    {
+      if ($3->primary == K_YES)
+        current_part->flags |= AVRPART_HAS_TPI;
+      else if ($3->primary == K_NO)
+        current_part->flags &= ~AVRPART_HAS_TPI;
+
+      free_token($3);
+    } |
+
+  K_IS_AVR32 TKN_EQUAL yesno
+    {
+      if ($3->primary == K_YES)
+        current_part->flags |= AVRPART_AVR32;
+      else if ($3->primary == K_NO)
+        current_part->flags &= AVRPART_AVR32;
+
+      free_token($3);
+    } |
+    
+  K_ALLOWFULLPAGEBITSTREAM TKN_EQUAL yesno
+    {
+      if ($3->primary == K_YES)
+        current_part->flags |= AVRPART_ALLOWFULLPAGEBITSTREAM;
+      else if ($3->primary == K_NO)
+        current_part->flags &= ~AVRPART_ALLOWFULLPAGEBITSTREAM;
+
+      free_token($3);
+    } |
+
+  K_ENABLEPAGEPROGRAMMING TKN_EQUAL yesno
+    {
+      if ($3->primary == K_YES)
+        current_part->flags |= AVRPART_ENABLEPAGEPROGRAMMING;
+      else if ($3->primary == K_NO)
+        current_part->flags &= ~AVRPART_ENABLEPAGEPROGRAMMING;
+
+      free_token($3);
+    } |
+
+  K_IDR TKN_EQUAL TKN_NUMBER
+    {
+      current_part->idr = $3->value.number;
+      free_token($3);
+    } |
+
+  K_RAMPZ TKN_EQUAL TKN_NUMBER
+    {
+      current_part->rampz = $3->value.number;
+      free_token($3);
+    } |
+
+  K_SPMCR TKN_EQUAL TKN_NUMBER
+    {
+      current_part->spmcr = $3->value.number;
+      free_token($3);
+    } |
+
+  K_EECR TKN_EQUAL TKN_NUMBER
+    {
+      current_part->eecr = $3->value.number;
+      free_token($3);
+    } |
+
+  K_NVM_BASE TKN_EQUAL TKN_NUMBER
+    {
+      current_part->nvm_base = $3->value.number;
+      free_token($3);
+    } |
+
+  K_SERIAL TKN_EQUAL yesno
+    {
+      if ($3->primary == K_YES)
+        current_part->flags |= AVRPART_SERIALOK;
+      else if ($3->primary == K_NO)
+        current_part->flags &= ~AVRPART_SERIALOK;
+
+      free_token($3);
+    } |
+
+  K_PARALLEL TKN_EQUAL parallel_modes
+    {
+      if ($3->primary == K_YES) {
+        current_part->flags |= AVRPART_PARALLELOK;
+        current_part->flags &= ~AVRPART_PSEUDOPARALLEL;
+      }
+      else if ($3->primary == K_NO) {
+        current_part->flags &= ~AVRPART_PARALLELOK;
+        current_part->flags &= ~AVRPART_PSEUDOPARALLEL;
+      }
+      else if ($3->primary == K_PSEUDO) {
+        current_part->flags |= AVRPART_PARALLELOK;
+        current_part->flags |= AVRPART_PSEUDOPARALLEL;
+      }
+
+
+      free_token($3);
+    } |
+
+  K_RETRY_PULSE TKN_EQUAL retry_lines
+    {
+      switch ($3->primary) {
+        case K_RESET :
+          current_part->retry_pulse = PIN_AVR_RESET;
+          break;
+        case K_SCK :
+          current_part->retry_pulse = PIN_AVR_SCK;
+          break;
+      }
+
+      free_token($1);
+    } |
+
+
+/*
+  K_EEPROM { current_mem = AVR_M_EEPROM; }
+    mem_specs |
+
+  K_FLASH { current_mem = AVR_M_FLASH; }
+    mem_specs | 
+*/
+
+  K_MEMORY TKN_STRING 
+    { 
+      current_mem = avr_new_memtype(); 
+      strcpy(current_mem->desc, strdup($2->value.string)); 
+      free_token($2); 
+    } 
+    mem_specs 
+    { 
+      ladd(current_part->mem, current_mem); 
+      current_mem = NULL; 
+    } |
+
+  opcode TKN_EQUAL string_list {
+    { 
+      int opnum;
+      OPCODE * op;
+
+      opnum = which_opcode($1);
+      op = avr_new_opcode();
+      parse_cmdbits(op);
+      current_part->op[opnum] = op;
+
+      free_token($1);
+    }
+  }
+;
+
+
+yesno :
+  K_YES | K_NO
+;
+
+
+mem_specs :
+  mem_spec TKN_SEMI |
+  mem_specs mem_spec TKN_SEMI
+;
+
+
+mem_spec :
+  K_PAGED          TKN_EQUAL yesno
+    {
+      current_mem->paged = $3->primary == K_YES ? 1 : 0;
+      free_token($3);
+    } |
+
+  K_SIZE            TKN_EQUAL TKN_NUMBER
+    {
+      current_mem->size = $3->value.number;
+      free_token($3);
+    } |
+
+
+  K_PAGE_SIZE       TKN_EQUAL TKN_NUMBER
+    {
+      current_mem->page_size = $3->value.number;
+      free_token($3);
+    } |
+
+  K_NUM_PAGES       TKN_EQUAL TKN_NUMBER
+    {
+      current_mem->num_pages = $3->value.number;
+      free_token($3);
+    } |
+
+  K_OFFSET          TKN_EQUAL TKN_NUMBER
+    {
+      current_mem->offset = $3->value.number;
+      free_token($3);
+    } |
+
+  K_MIN_WRITE_DELAY TKN_EQUAL TKN_NUMBER
+    {
+      current_mem->min_write_delay = $3->value.number;
+      free_token($3);
+    } |
+
+  K_MAX_WRITE_DELAY TKN_EQUAL TKN_NUMBER
+    {
+      current_mem->max_write_delay = $3->value.number;
+      free_token($3);
+    } |
+
+  K_PWROFF_AFTER_WRITE TKN_EQUAL yesno
+    {
+      current_mem->pwroff_after_write = $3->primary == K_YES ? 1 : 0;
+      free_token($3);
+    } |
+
+  K_READBACK_P1     TKN_EQUAL TKN_NUMBER
+    {
+      current_mem->readback[0] = $3->value.number;
+      free_token($3);
+    } |
+
+  K_READBACK_P2     TKN_EQUAL TKN_NUMBER
+    {
+      current_mem->readback[1] = $3->value.number;
+      free_token($3);
+    } |
+
+
+  K_MODE TKN_EQUAL TKN_NUMBER
+    {
+      current_mem->mode = $3->value.number;
+      free_token($3);
+    } |
+
+  K_DELAY TKN_EQUAL TKN_NUMBER
+    {
+      current_mem->delay = $3->value.number;
+      free_token($3);
+    } |
+
+  K_BLOCKSIZE TKN_EQUAL TKN_NUMBER
+    {
+      current_mem->blocksize = $3->value.number;
+      free_token($3);
+    } |
+
+  K_READSIZE TKN_EQUAL TKN_NUMBER
+    {
+      current_mem->readsize = $3->value.number;
+      free_token($3);
+    } |
+
+  K_POLLINDEX TKN_EQUAL TKN_NUMBER
+    {
+      current_mem->pollindex = $3->value.number;
+      free_token($3);
+    } |
+
+
+  opcode TKN_EQUAL string_list {
+    { 
+      int opnum;
+      OPCODE * op;
+
+      opnum = which_opcode($1);
+      op = avr_new_opcode();
+      parse_cmdbits(op);
+      current_mem->op[opnum] = op;
+
+      free_token($1);
+    }
+  }
+;
+
+
+%%
+
+#if 0
+static char * vtypestr(int type)
+{
+  switch (type) {
+    case V_NUM : return "NUMERIC";
+    case V_STR : return "STRING";
+    default:
+      return "<UNKNOWN>";
+  }
+}
+#endif
+
+
+static int assign_pin(int pinno, TOKEN * v, int invert)
+{
+  int value;
+
+  value = v->value.number;
+
+  if ((value <= 0) || (value >= 18)) {
+    fprintf(stderr, 
+            "%s: error at line %d of %s: pin must be in the "
+            "range 1-17\n",
+            progname, lineno, infile);
+    exit(1);
+  }
+  if (invert)
+    value |= PIN_INVERSE;
+
+  current_prog->pinno[pinno] = value;
+
+  return 0;
+}
+
+
+static int which_opcode(TOKEN * opcode)
+{
+  switch (opcode->primary) {
+    case K_READ        : return AVR_OP_READ; break;
+    case K_WRITE       : return AVR_OP_WRITE; break;
+    case K_READ_LO     : return AVR_OP_READ_LO; break;
+    case K_READ_HI     : return AVR_OP_READ_HI; break;
+    case K_WRITE_LO    : return AVR_OP_WRITE_LO; break;
+    case K_WRITE_HI    : return AVR_OP_WRITE_HI; break;
+    case K_LOADPAGE_LO : return AVR_OP_LOADPAGE_LO; break;
+    case K_LOADPAGE_HI : return AVR_OP_LOADPAGE_HI; break;
+    case K_LOAD_EXT_ADDR : return AVR_OP_LOAD_EXT_ADDR; break;
+    case K_WRITEPAGE   : return AVR_OP_WRITEPAGE; break;
+    case K_CHIP_ERASE  : return AVR_OP_CHIP_ERASE; break;
+    case K_PGM_ENABLE  : return AVR_OP_PGM_ENABLE; break;
+    default :
+      fprintf(stderr, 
+              "%s: error at %s:%d: invalid opcode\n",
+              progname, infile, lineno);
+      exit(1);
+      break;
+  }
+}
+
+
+static int parse_cmdbits(OPCODE * op)
+{
+  TOKEN * t;
+  int bitno;
+  char ch;
+  char * e;
+  char * q;
+  int len;
+  char * s, *brkt = NULL;
+
+  bitno = 32;
+  while (lsize(string_list)) {
+
+    t = lrmv_n(string_list, 1);
+
+    s = strtok_r(t->value.string, " ", &brkt);
+    while (s != NULL) {
+
+      bitno--;
+      if (bitno < 0) {
+        fprintf(stderr, 
+                "%s: error at %s:%d: too many opcode bits for instruction\n",
+                progname, infile, lineno);
+        exit(1);
+      }
+
+      len = strlen(s);
+
+      if (len == 0) {
+        fprintf(stderr, 
+                "%s: error at %s:%d: invalid bit specifier \"\"\n",
+                progname, infile, lineno);
+        exit(1);
+      }
+
+      ch = s[0];
+
+      if (len == 1) {
+        switch (ch) {
+          case '1':
+            op->bit[bitno].type  = AVR_CMDBIT_VALUE;
+            op->bit[bitno].value = 1;
+            op->bit[bitno].bitno = bitno % 8;
+            break;
+          case '0':
+            op->bit[bitno].type  = AVR_CMDBIT_VALUE;
+            op->bit[bitno].value = 0;
+            op->bit[bitno].bitno = bitno % 8;
+            break;
+          case 'x':
+            op->bit[bitno].type  = AVR_CMDBIT_IGNORE;
+            op->bit[bitno].value = 0;
+            op->bit[bitno].bitno = bitno % 8;
+            break;
+          case 'a':
+            op->bit[bitno].type  = AVR_CMDBIT_ADDRESS;
+            op->bit[bitno].value = 0;
+            op->bit[bitno].bitno = 8*(bitno/8) + bitno % 8;
+            break;
+          case 'i':
+            op->bit[bitno].type  = AVR_CMDBIT_INPUT;
+            op->bit[bitno].value = 0;
+            op->bit[bitno].bitno = bitno % 8;
+            break;
+          case 'o':
+            op->bit[bitno].type  = AVR_CMDBIT_OUTPUT;
+            op->bit[bitno].value = 0;
+            op->bit[bitno].bitno = bitno % 8;
+            break;
+          default :
+            fprintf(stderr, 
+                    "%s: error at %s:%d: invalid bit specifier '%c'\n",
+                    progname, infile, lineno, ch);
+            exit(1);
+            break;
+        }
+      }
+      else {
+        if (ch == 'a') {
+          q = &s[1];
+          op->bit[bitno].bitno = strtol(q, &e, 0);
+          if ((e == q)||(*e != 0)) {
+            fprintf(stderr, 
+                    "%s: error at %s:%d: can't parse bit number from \"%s\"\n",
+                    progname, infile, lineno, q);
+            exit(1);
+          }
+          op->bit[bitno].type = AVR_CMDBIT_ADDRESS;
+          op->bit[bitno].value = 0;
+        }
+        else {
+          fprintf(stderr, 
+                  "%s: error at %s:%d: invalid bit specifier \"%s\"\n",
+                  progname, infile, lineno, s);
+          exit(1);
+        }
+      }
+
+      s = strtok_r(NULL, " ", &brkt);
+    }
+
+    free_token(t);
+
+  }  /* while */
+
+  return 0;
+}
+
+
diff --git a/avrdude/configure.ac b/avrdude/configure.ac
new file mode 100644
index 00000000..5b40f002
--- /dev/null
+++ b/avrdude/configure.ac
@@ -0,0 +1,296 @@
+#
+# avrdude - A Downloader/Uploader for AVR device programmers
+# Copyright (C) 2003, 2004  Theodore A. Roth  <troth@openavr.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+#
+# $Id$
+#
+
+# Process this file with autoconf to produce a configure script.
+
+AC_PREREQ(2.57)
+AC_INIT(avrdude, 5.9, avrdude-dev@nongnu.org)
+
+AC_CANONICAL_BUILD
+AC_CANONICAL_HOST
+AC_CANONICAL_TARGET
+
+AC_CONFIG_SRCDIR([main.c])
+AM_INIT_AUTOMAKE
+AM_CONFIG_HEADER(ac_cfg.h)
+
+# Checks for programs.
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_YACC
+AC_PROG_LEX
+AC_PROG_RANLIB
+
+dnl Makefile.am:77: compiling `config_gram.c' with per-target flags requires `AM_PROG_CC_C_O' in `configure.ac'
+AM_PROG_CC_C_O
+
+# Checks for libraries.
+AC_CHECK_LIB([termcap], [tputs])
+AC_CHECK_LIB([ncurses], [tputs])
+AC_CHECK_LIB([readline], [readline])
+AC_SEARCH_LIBS([gethostent], [nsl])
+AC_SEARCH_LIBS([setsockopt], [socket])
+AH_TEMPLATE([HAVE_LIBUSB],
+            [Define if USB support is enabled via libusb])
+AC_CHECK_LIB([usb], [usb_get_string_simple], [have_libusb=yes])
+if test x$have_libusb = xyes; then
+   case $target in
+       *-*-darwin*)
+               LIBUSB="-lusb -framework CoreFoundation -framework IOKit"
+               ;;
+       *)
+               LIBUSB="-lusb"
+               ;;
+   esac
+   AC_DEFINE([HAVE_LIBUSB])
+fi
+AC_SUBST(LIBUSB, $LIBUSB)
+
+# Checks for header files.
+AC_CHECK_HEADERS([limits.h stdlib.h string.h])
+AC_CHECK_HEADERS([fcntl.h sys/ioctl.h sys/time.h termios.h unistd.h])
+AC_CHECK_HEADERS([ddk/hidsdi.h],,,[#include <windows.h>
+#include <setupapi.h>])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_HEADER_TIME
+
+# Checks for library functions.
+AC_CHECK_FUNCS([memset select strcasecmp strdup strerror strncasecmp strtol strtoul gettimeofday])
+
+AC_MSG_CHECKING([for a Win32 HID libray])
+SAVED_LIBS="${LIBS}"
+case $target in
+        *-*-mingw32* | *-*-cygwin* | *-*-windows*)
+		LIBHID="-lhid -lsetupapi"
+		if test $ac_cv_header_ddk_hidsdi_h = yes
+		then
+			HIDINCLUDE="#include <ddk/hidsdi.h>"
+		else
+			HIDINCLUDE="#include \"my_ddk_hidsdi.h\""
+		fi
+		;;
+	*)
+		LIBHID=""
+		;;
+esac
+LIBS="${LIBS} ${LIBHID}"
+
+AH_TEMPLATE([HAVE_LIBHID],
+            [Define if HID support is enabled via the Win32 DDK])
+AC_TRY_RUN([#include <windows.h>
+#include <setupapi.h>
+$HIDINCLUDE
+
+int
+main(void)
+{
+    GUID hidGuid;
+    HidD_GetHidGuid(&hidGuid);
+
+    return 0;
+}
+], [have_libhid=yes], [have_libhid=no], [have_libhid=no])
+AC_MSG_RESULT([$have_libhid])
+if test x$have_libhid = xyes; then
+   AC_DEFINE([HAVE_LIBHID])
+else
+   LIBHID=""
+fi
+LIBS="${SAVED_LIBS}"
+AC_SUBST(LIBHID, $LIBHID)
+
+# Check for types
+
+# Solaris has uint_t and ulong_t typedefs in <sys/types.h>, avoid
+# the redeclaration in usbtiny.c.
+AC_CHECK_TYPES([uint_t], [], [], [#include <sys/types.h>])
+AC_CHECK_TYPES([ulong_t], [], [], [#include <sys/types.h>])
+
+# Checks for misc stuff.
+
+AC_ARG_ENABLE(
+	[versioned-doc],
+	AC_HELP_STRING(
+		[--enable-versioned-doc],
+		[install docs in directory with version name (default)]),
+	[case "${enableval}" in
+		yes) versioned_doc=yes ;;
+		no)  versioned_doc=no ;;
+		*)   AC_MSG_ERROR(bad value ${enableval} for versioned-doc option) ;;
+		esac],
+	[versioned_doc=yes])
+
+if test "$versioned_doc" = "yes"; then
+    DOC_INST_DIR='$(DESTDIR)$(datadir)/doc/avrdude-$(VERSION)'
+else
+    DOC_INST_DIR='$(DESTDIR)$(datadir)/doc/avrdude'
+fi
+
+AC_ARG_ENABLE(
+	[doc],
+	AC_HELP_STRING(
+		[--enable-doc],
+		[Enable building documents]),
+	[case "${enableval}" in
+		yes) enabled_doc=yes ;;
+		no)  enabled_doc=no ;;
+		*)   AC_MSG_ERROR(bad value ${enableval} for disable-doc option) ;;
+		esac],
+	[enabled_doc=no])
+
+AC_ARG_ENABLE(
+	[parport],
+	AC_HELP_STRING(
+		[--enable-parport],
+		[Enable accessing parallel ports(default)]),
+	[case "${enableval}" in
+		yes) enabled_parport=yes ;;
+		no)  enabled_parport=no ;;
+		*)   AC_MSG_ERROR(bad value ${enableval} for enable-parport option) ;;
+		esac],
+	[enabled_parport=yes])
+
+DIST_SUBDIRS_AC='doc windows'
+
+if test "$enabled_doc" = "yes"; then
+	SUBDIRS_AC='doc'
+else
+	SUBDIRS_AC=''
+fi
+
+AC_SUBST(DOC_INST_DIR, $DOC_INST_DIR)
+AC_SUBST(SUBDIRS_AC, $SUBDIRS_AC)
+AC_SUBST(DIST_SUBDIRS_AC, $DIST_SUBDIRS_AC)
+
+
+# Find the parallel serial device files based on target system
+# If a system doesn't have a PC style parallel, mark it as unknown.
+case $target in
+	i[[3456]]86-*-linux*|x86_64-*-linux*)
+		DEFAULT_PAR_PORT="/dev/parport0"
+		DEFAULT_SER_PORT="/dev/ttyS0"
+		;;
+	*-*-linux*)
+		DEFAULT_PAR_PORT="unknown"
+		DEFAULT_SER_PORT="/dev/ttyS0"
+		;;
+	i[[3456]]86-*-freebsd*|amd64-*-freebsd*)
+		DEFAULT_PAR_PORT="/dev/ppi0"
+		DEFAULT_SER_PORT="/dev/cuaa0"
+		;;
+	*-*-freebsd*)
+		DEFAULT_PAR_PORT="unknown"
+		DEFAULT_SER_PORT="/dev/cuaa0"
+		;;
+	*-*-solaris*)
+		DEFAULT_PAR_PORT="/dev/printers/0"
+		DEFAULT_SER_PORT="/dev/term/a"
+		;;
+	*-*-msdos* | *-*-mingw32* | *-*-cygwin* | *-*-windows*)
+		DEFAULT_PAR_PORT="lpt1"
+		DEFAULT_SER_PORT="com1"
+		;;
+	*)
+		DEFAULT_PAR_PORT="unknown"
+		DEFAULT_SER_PORT="unknown"
+		;;
+esac
+
+if test "$enabled_parport" = "yes"; then
+	AC_MSG_CHECKING([for parallel device])
+	if test "$DEFAULT_PAR_PORT" = "unknown"; then
+		AC_MSG_NOTICE([parallel port access disabled for this system])
+		enabled_parport=no
+	else
+		AC_MSG_RESULT([$DEFAULT_PAR_PORT])
+	fi
+	AC_SUBST(DEFAULT_PAR_PORT, $DEFAULT_PAR_PORT)
+fi
+
+AC_MSG_CHECKING([for serial device])
+AC_MSG_RESULT([$DEFAULT_SER_PORT])
+AC_SUBST(DEFAULT_SER_PORT, $DEFAULT_SER_PORT)
+
+if test "$enabled_parport" = "yes"; then
+	AC_DEFINE(HAVE_PARPORT, 1, [parallel port access enabled])
+	confsubst="-e /^@HAVE_PARPORT_/d"
+else
+	confsubst="-e /^@HAVE_PARPORT_BEGIN@/,/^@HAVE_PARPORT_END@/d"
+fi
+export confsubst
+
+# See if we need to drop into the windows subdir.
+case $target in
+        *-*-mingw32* | *-*-cygwin* | *-*-windows*)
+		WINDOWS_DIRS="windows"
+		CFLAGS="${CFLAGS} -mno-cygwin -DWIN32NATIVE"
+		LDFLAGS="${LDFLAGS} -static"
+		;;
+esac
+AC_SUBST(WINDOWS_DIRS,$WINDOWS_DIRS)
+
+# If we are compiling with gcc, enable all warning and make warnings errors.
+if test "$GCC" = yes; then
+    ENABLE_WARNINGS="-Wall"
+
+	# does this compiler support -Wno-pointer-sign ?
+	AC_MSG_CHECKING([if gcc accepts -Wno-pointer-sign ])
+
+	safe_CFLAGS=$CFLAGS
+	CFLAGS="$ENABLE_WARNINGS -Wno-pointer-sign"
+
+	AC_TRY_COMPILE(, [ int main () { return 0 ; } ], [
+		no_pointer_sign=yes
+		AC_MSG_RESULT([yes]) 
+		], [
+		no_pointer_sign=no
+		AC_MSG_RESULT([no]) 
+		])
+	CFLAGS=$safe_CFLAGS
+
+	if test x$no_pointer_sign = xyes; then
+		ENABLE_WARNINGS="$ENABLE_WARNINGS -Wno-pointer-sign"
+	fi
+fi
+AC_SUBST(ENABLE_WARNINGS,$ENABLE_WARNINGS)
+
+AC_CONFIG_FILES([
+       doc/Makefile
+       windows/Makefile
+       avrdude.spec
+       Makefile
+])
+
+# The procedure to create avrdude.conf involves two steps.  First,
+# normal autoconf substitution will be applied, resulting in
+# avrdude.conf.tmp.  Finally, a sed command will be applied to filter
+# out unwanted parts (currently the parallel port programmer types)
+# based on previous configuration results, thereby producing the final
+# avrdude.conf file.
+
+AC_CONFIG_FILES([avrdude.conf.tmp:avrdude.conf.in],
+		[sed $confsubst avrdude.conf.tmp > avrdude.conf])
+
+AC_OUTPUT
diff --git a/avrdude/confwin.c b/avrdude/confwin.c
new file mode 100644
index 00000000..0ae373ae
--- /dev/null
+++ b/avrdude/confwin.c
@@ -0,0 +1,54 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2003-2004  Eric B. Weddington <eric@ecentral.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "avrdude.h"
+
+#if defined(WIN32NATIVE)
+
+#include <limits.h>
+#include <windows.h>
+
+
+static char *filename;
+
+
+void win_sys_config_set(char sys_config[PATH_MAX])
+{
+    sys_config[0] = 0;
+    
+    /* Use Windows API call to search for the Windows default system config file.*/
+    SearchPath(NULL, "avrdude.conf", NULL, PATH_MAX, sys_config, &filename);
+    return;
+}
+
+
+void win_usr_config_set(char usr_config[PATH_MAX])
+{
+    usr_config[0] = 0;
+    
+    /* Use Windows API call to search for the Windows default user config file. */
+	SearchPath(NULL, "avrdude.rc", NULL, PATH_MAX, usr_config, &filename);
+    return;
+}
+
+
+#endif
+
+
diff --git a/avrdude/confwin.h b/avrdude/confwin.h
new file mode 100644
index 00000000..7ab33385
--- /dev/null
+++ b/avrdude/confwin.h
@@ -0,0 +1,40 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2003-2004  Eric B. Weddington <eric@ecentral.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+
+#if defined(WIN32NATIVE)
+#ifndef confwin_h
+#define confwin_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void win_sys_config_set(char sys_config[PATH_MAX]);
+void win_usr_config_set(char usr_config[PATH_MAX]);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+#endif
+
+
diff --git a/avrdude/crc16.c b/avrdude/crc16.c
new file mode 100644
index 00000000..0177c9da
--- /dev/null
+++ b/avrdude/crc16.c
@@ -0,0 +1,83 @@
+/*
+ * Derived from CRC algorithm for JTAG ICE mkII, published in Atmel
+ * Appnote AVR067.  Converted from C++ to C.
+ */
+#include "crc16.h"
+
+/* CRC16 Definitions */
+static const unsigned short crc_table[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
+};
+
+/* CRC calculation macros */
+#define CRC_INIT 0xFFFF
+#define CRC(crcval,newchar) crcval = (crcval >> 8) ^ \
+	crc_table[(crcval ^ newchar) & 0x00ff]
+
+unsigned short
+crcsum(const unsigned char* message, unsigned long length,
+       unsigned short crc)
+{
+  unsigned long i;
+
+  for(i = 0; i < length; i++)
+    {
+      CRC(crc, message[i]);
+    }
+  return crc;
+}
+
+int
+crcverify(const unsigned char* message, unsigned long length)
+{
+  /*
+   * Returns true if the last two bytes in a message is the crc of the
+   * preceding bytes.
+   */
+  unsigned short expected;
+
+  expected = crcsum(message, length - 2, CRC_INIT);
+  return (expected & 0xff) == message[length - 2] &&
+    ((expected >> 8) & 0xff) == message[length - 1];
+}
+
+void
+crcappend(unsigned char* message, unsigned long length)
+{
+  unsigned long crc;
+
+  crc = crcsum(message, length, CRC_INIT);
+  message[length] = (unsigned char)(crc & 0xff);
+  message[length+1] = (unsigned char)((crc >> 8) & 0xff);
+}
diff --git a/avrdude/crc16.h b/avrdude/crc16.h
new file mode 100644
index 00000000..db10131d
--- /dev/null
+++ b/avrdude/crc16.h
@@ -0,0 +1,34 @@
+#ifndef CRC16_H
+#define CRC16_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Derived from CRC algorithm for JTAG ICE mkII, published in Atmel
+ * Appnote AVR067.  Converted from C++ to C.
+ */
+
+extern unsigned short crcsum(const unsigned char* message,
+			     unsigned long length,
+			     unsigned short crc);
+/*
+ * Verify that the last two bytes is a (LSB first) valid CRC of the
+ * message.
+ */
+extern int crcverify(const unsigned char* message,
+		     unsigned long length);
+/*
+ * Append a two byte CRC (LSB first) to message.  length is size of
+ * message excluding crc.  Space for the CRC bytes must be allocated
+ * in advance!
+ */
+extern void crcappend(unsigned char* message,
+		      unsigned long length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/avrdude/doc/.cvsignore b/avrdude/doc/.cvsignore
new file mode 100644
index 00000000..ecbe8063
--- /dev/null
+++ b/avrdude/doc/.cvsignore
@@ -0,0 +1,22 @@
+.cvsignore
+Makefile
+Makefile.in
+avrdude-html
+avrdude.aux
+avrdude.cp
+avrdude.cps
+avrdude.dvi
+avrdude.fn
+avrdude.info
+avrdude.ky
+avrdude.log
+avrdude.pdf
+avrdude.pg
+avrdude.ps
+avrdude.toc
+avrdude.tp
+avrdude.vr
+mdate-sh
+stamp-vti
+texinfo.tex
+version.texi
diff --git a/avrdude/doc/Makefile.am b/avrdude/doc/Makefile.am
new file mode 100644
index 00000000..c8c6634e
--- /dev/null
+++ b/avrdude/doc/Makefile.am
@@ -0,0 +1,60 @@
+#
+# avrdude - A Downloader/Uploader for AVR device programmers
+# Copyright (C) 2003  Theodore A. Roth  <troth@openavr.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+#
+# $Id$
+#
+
+CLEANFILES = \
+	version.texi \
+	stamp-vti
+
+info_TEXINFOS = avrdude.texi
+
+all-local: info html ps pdf
+
+html: avrdude-html/avrdude.html
+
+avrdude-html/avrdude.html: $(srcdir)/$(info_TEXINFOS)
+	texi2html -split_node $(srcdir)/$(info_TEXINFOS)
+	if [ -e ./avrdude.html -o -e ./avrdude_1.html ]; then \
+	 mkdir -p avrdude-html ; \
+	 mv -f *.html avrdude-html ; \
+	else \
+	 mv -f avrdude avrdude-html; \
+	fi;
+
+clean-local:
+	rm -rf avrdude-html *.info
+
+install-data-local: install-docs
+
+install-docs: html ps pdf
+	$(mkinstalldirs) $(DOC_INST_DIR)
+	$(INSTALL_DATA) avrdude.ps $(DOC_INST_DIR)/avrdude.ps
+	$(INSTALL_DATA) avrdude.pdf $(DOC_INST_DIR)/avrdude.pdf
+	$(mkinstalldirs) $(DOC_INST_DIR)/avrdude-html
+	@list=`echo avrdude-html/*.html`; \
+		for file in $$list; \
+		do \
+			$(INSTALL_DATA) $$file $(DOC_INST_DIR)/$$file; \
+		done
+
+uninstall-local:
+	rm -rf $(DOC_INST_DIR)
diff --git a/avrdude/doc/TODO b/avrdude/doc/TODO
new file mode 100644
index 00000000..6c57c5ad
--- /dev/null
+++ b/avrdude/doc/TODO
@@ -0,0 +1,26 @@
+
+- Man page needs updated for avr910 info.
+
+- Website needs to link to docs:
+  http://savannah.nongnu.org/download/avrdude/doc/avrdude-html/
+
+- Add "skip empty pages" optimization on avr910 paged write. The stk500 has
+  this optimization already.
+
+- Fix "overfull \hbox" issues in building documentation.
+
+- FIXME: term.c: terminal_get_input(): strip newlines in non-readline input
+  code.
+
+- FIXME: avr910.c: avr910_cmd(): Insert version check here.
+
+- FIXME: ser_posix.c: serial_close(): Should really restore the terminal to
+  original state here.
+
+- FIXME: main.c, par.c: exitspecs don't work if RESET-pin is controlled over
+  PPICTRL.
+
+- transfer ppi-speedtuning to the windows version (CAVEAT: This will make
+  programming too fast for chips with 500kHz clock)
+
+- make SCK-period configurable for PPI-programmers
diff --git a/avrdude/doc/avrdude.texi b/avrdude/doc/avrdude.texi
new file mode 100644
index 00000000..f187845a
--- /dev/null
+++ b/avrdude/doc/avrdude.texi
@@ -0,0 +1,2414 @@
+%% -*-texinfo-*-
+\input texinfo
+
+@c $Id$
+
+@setfilename avrdude.info
+@settitle AVRDUDE
+@finalout
+
+@include version.texi
+
+@c
+@c These are set in version.texi which is automatically generated by automake.
+@c
+@c @set UPDATED 26 Febuary 2003
+@c @set EDITION 3.2.0
+@c @set VERSION 3.2.0
+
+@c This is a dir.info fragment to support semi-automated addition of
+@c manuals to an info tree.
+@dircategory AVR Programming & development tools.
+@direntry
+* AvrDude: (avrdude).            AVR program downloader/uploader.
+@end direntry
+
+@ifinfo
+This file documents the avrdude program.
+
+For avrdude version @value{VERSION}, @value{UPDATED}.
+
+Copyright @copyright{} 2003, 2005 Brian Dean
+
+Copyright @copyright{} 2006 - 2010 J@"org Wunsch
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Free Software Foundation.
+@end ifinfo
+
+@titlepage
+@title AVRDUDE
+@subtitle A program for download/uploading AVR microcontroller flash and eeprom.
+@subtitle For AVRDUDE, Version @value{VERSION}, @value{UPDATED}.
+@author by Brian S. Dean
+
+@page
+Send comments on AVRDUDE to @w{@email{avrdude-dev@@nongnu.org}}.
+
+Use @uref{http://savannah.nongnu.org/bugs/?group=avrdude} to report bugs.
+
+Copyright @copyright{} 2003,2005 Brian S. Dean
+
+Copyright @copyright{} 2006 - 2008 J@"org Wunsch
+@sp 2
+
+Permission is granted to make and distribute verbatim copies of
+this manual provided the copyright notice and this permission notice
+are preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+manual under the conditions for verbatim copying, provided that the entire
+resulting derived work is distributed under the terms of a permission
+notice identical to this one.
+
+Permission is granted to copy and distribute translations of this manual
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by the Free Software Foundation.
+@end titlepage
+
+@contents
+
+@c
+@c Top Node
+@c
+@node Top, Introduction, (dir), (dir)
+@comment  node-name,  next,  previous,  up
+
+@ifinfo
+This file documents the avrdude program for downloading/uploading
+programs to Atmel AVR microcontrollers.
+
+For avrdude version @value{VERSION}, @value{UPDATED}.
+
+Send comments on AVRDUDE to @w{@email{avrdude-dev@@nongnu.org}}.
+
+Use @uref{http://savannah.nongnu.org/bugs/?group=avrdude} to report bugs.
+
+Copyright @copyright{} 2003,2005 Brian S. Dean
+
+Copyright @copyright{} 2006 J@"org Wunsch
+@end ifinfo
+
+@menu
+* Introduction::                
+* Command Line Options::
+* Terminal Mode Operation::
+* Configuration File::          
+* Programmer Specific Information::
+* Platform Dependent Information::
+* Troubleshooting::
+@end menu
+
+@c
+@c Node
+@c
+@node Introduction, Command Line Options, Top, Top
+@comment  node-name,  next,  previous,  up
+@chapter Introduction
+@cindex introduction
+
+AVRDUDE - AVR Downloader Uploader - is a program for downloading and
+uploading the on-chip memories of Atmel's AVR microcontrollers. It can
+program the Flash and EEPROM, and where supported by the serial
+programming protocol, it can program fuse and lock bits. AVRDUDE also
+supplies a direct instruction mode allowing one to issue any programming
+instruction to the AVR chip regardless of whether AVRDUDE implements
+that specific feature of a particular chip.
+
+AVRDUDE can be used effectively via the command line to read or write
+all chip memory types (eeprom, flash, fuse bits, lock bits, signature
+bytes) or via an interactive (terminal) mode. Using AVRDUDE from the
+command line works well for programming the entire memory of the chip
+from the contents of a file, while interactive mode is useful for
+exploring memory contents, modifying individual bytes of eeprom,
+programming fuse/lock bits, etc.
+
+AVRDUDE supports the following basic programmer types: Atmel's STK500,
+Atmel's AVRISP and AVRISP mkII devices,
+Atmel's STK600,
+Atmel's JTAG ICE (both mkI and mkII, the latter also in ISP mode), appnote
+avr910, appnote avr109 (including the AVR Butterfly),
+serial bit-bang adapters,
+and the PPI (parallel port interface). PPI represents a class
+of simple programmers where the programming lines are directly
+connected to the PC parallel port. Several pin configurations exist
+for several variations of the PPI programmers, and AVRDUDE can be be
+configured to work with them by either specifying the appropriate
+programmer on the command line or by creating a new entry in its
+configuration file. All that's usually required for a new entry is to
+tell AVRDUDE which pins to use for each programming function.
+
+A number of equally simple bit-bang programming adapters that connect
+to a serial port are supported as well, among them the popular
+Ponyprog serial adapter, and the DASA and DASA3 adapters that used to
+be supported by uisp(1).  Note that these adapters are meant to be
+attached to a physical serial port.  Connecting to a serial port
+emulated on top of USB is likely to not work at all, or to work
+abysmally slow.
+
+The STK500, JTAG ICE, avr910, and avr109/butterfly use the serial port to communicate with the PC.
+The STK600, JTAG ICE mkII, AVRISP mkII, USBasp, and USBtinyISP
+programmers communicate through the USB, using @code{libusb} as a
+platform abstraction layer.
+The STK500, STK600, JTAG ICE, and avr910 contain on-board logic to control the programming of the target
+device.
+The avr109 bootloader implements a protocol similar to avr910, but is
+actually implemented in the boot area of the target's flash ROM, as
+opposed to being an external device.
+The fundamental difference between the two types lies in the
+protocol used to control the programmer. The avr910 protocol is very
+simplistic and can easily be used as the basis for a simple, home made
+programmer since the firmware is available online. On the other hand,
+the STK500 protocol is more robust and complicated and the firmware is
+not openly available.
+The JTAG ICE also uses a serial communication protocol which is similar
+to the STK500 firmware version 2 one.  However, as the JTAG ICE is
+intended to allow on-chip debugging as well as memory programming, the
+protocol is more sophisticated.
+(The JTAG ICE mkII protocol can also be run on top of USB.)
+Only the memory programming functionality of the JTAG ICE is supported
+by AVRDUDE.
+For the JTAG ICE mkII, JTAG, debugWire and ISP mode are supported, provided
+it has a firmware revision of at least 4.14 (decimal).
+See below for the limitations of debugWire.
+For ATxmega devices, the JTAG ICE mkII is supported in PDI mode, provided it
+has a revision 1 hardware and firmware version of at least 5.37 (decimal).
+
+The AVR Dragon is supported in all modes (ISP, JTAG, HVSP, PP, debugWire).
+When used in JTAG and debugWire mode, the AVR Dragon behaves similar to a
+JTAG ICE mkII, so all device-specific comments for that device
+will apply as well.
+When used in ISP mode, the AVR Dragon behaves similar to an
+AVRISP mkII (or JTAG ICE mkII in ISP mode), so all device-specific
+comments will apply there.
+In particular, the Dragon starts out with a rather fast ISP clock
+frequency, so the @code{-B @var{bitclock}}
+option might be required to achieve a stable ISP communication.
+For ATxmega devices, the AVR Dragon is supported in PDI mode, provided it
+has a firmware version of at least 6.11 (decimal).
+
+The Arduino (which is very similar to the STK500 1.x) is supported via
+its own programmer type specification ``arduino''.
+
+The BusPirate is a versatile tool that can also be used as an AVR programmer.
+A single BusPirate can be connected to up to 3 independent AVRs. See
+the section on
+@emph{extended parameters}
+below for details.
+
+The USBasp ISP and USBtinyISP adapters are also supported, provided AVRDUDE
+has been compiled with libusb support.
+They both feature simple firmware-only USB implementations, running on
+an ATmega8 (or ATmega88), or ATtiny2313, respectively.
+
+
+@menu
+* History::                     
+@end menu
+
+@c
+@c Node
+@c
+@node History,  , Introduction, Introduction
+@section History and Credits
+
+AVRDUDE was written by Brian S. Dean under the name of AVRPROG to run on
+the FreeBSD Operating System.  Brian renamed the software to be called
+AVRDUDE when interest grew in a Windows port of the software so that the
+name did not conflict with AVRPROG.EXE which is the name of Atmel's
+Windows programming software.
+
+The AVRDUDE source now resides in the public CVS repository on
+savannah.gnu.org (@url{http://savannah.gnu.org/projects/avrdude/}),
+where it continues to be enhanced and ported to other systems.  In
+addition to FreeBSD, AVRDUDE now runs on Linux and Windows.  The
+developers behind the porting effort primarily were Ted Roth, Eric
+Weddington, and Joerg Wunsch.
+
+And in the spirit of many open source projects, this manual also draws
+on the work of others.  The initial revision was composed of parts of
+the original Unix manual page written by Joerg Wunsch, the original web
+site documentation by Brian Dean, and from the comments describing the
+fields in the AVRDUDE configuration file by Brian Dean.  The texi
+formatting was modeled after that of the Simulavr documentation by Ted
+Roth.
+
+
+@c
+@c Node
+@c
+@node Command Line Options, Terminal Mode Operation, Introduction, Top
+@chapter Command Line Options
+@cindex options
+
+@menu
+* Option Descriptions::
+* Programmers accepting extended parameters::
+* Example Command Line Invocations::
+@end menu
+
+@c
+@c Node
+@c
+@node Option Descriptions, Programmers accepting extended parameters, Command Line Options, Command Line Options
+@section Option Descriptions
+
+@noindent
+AVRDUDE is a command line tool, used as follows:
+
+@smallexample
+avrdude -p partno @var{options} @dots{}
+@end smallexample
+
+@noindent
+Command line options are used to control AVRDUDE's behaviour.  The
+following options are recognized:
+
+@table @code
+@item -p @var{partno}
+This is the only mandatory option and it tells AVRDUDE what type of part
+(MCU) that is connected to the programmer.  The @var{partno} parameter
+is the part's id listed in the configuration file.  Specify -p ? to list
+all parts in the configuration file.  If a part is unknown
+to AVRDUDE, it means that there is no config file entry for that part,
+but it can be added to the configuration file if you have the Atmel
+datasheet so that you can enter the programming specifications.
+Currently, the following MCU types are understood:
+
+@multitable @columnfractions .15 .3
+@item @code{1200}  @tab AT90S1200
+@item @code{2313}  @tab AT90S2313
+@item @code{2333}  @tab AT90S2333
+@item @code{2343}  @tab AT90S2343 (*)
+@item @code{4414}  @tab AT90S4414
+@item @code{4433}  @tab AT90S4433
+@item @code{4434}  @tab AT90S4434
+@item @code{8515}  @tab AT90S8515
+@item @code{8535}  @tab AT90S8535
+@item @code{c128}  @tab AT90CAN128
+@item @code{c32}   @tab AT90CAN32
+@item @code{c64}   @tab AT90CAN64
+@item @code{m103}  @tab ATmega103
+@item @code{m128}  @tab ATmega128
+@item @code{m1280} @tab ATmega1280
+@item @code{m1281} @tab ATmega1281
+@item @code{m1284p} @tab ATmega1284P
+@item @code{m128rfa1} @tab ATmega128RFA1
+@item @code{m16}   @tab ATmega16
+@item @code{m161}  @tab ATmega161
+@item @code{m162}  @tab ATmega162
+@item @code{m163}  @tab ATmega163
+@item @code{m164}  @tab ATmega164
+@item @code{m164p} @tab ATmega164P
+@item @code{m168}  @tab ATmega168
+@item @code{m169}  @tab ATmega169
+@item @code{m2560} @tab ATmega2560 (**)
+@item @code{m2561} @tab ATmega2561 (**)
+@item @code{m32}   @tab ATmega32
+@item @code{m324p} @tab ATmega324P
+@item @code{m325}  @tab ATmega325
+@item @code{m3250} @tab ATmega3250
+@item @code{m328p} @tab ATmega328P
+@item @code{m329}  @tab ATmega329
+@item @code{m3290} @tab ATmega3290
+@item @code{m329p} @tab ATmega329P
+@item @code{m3290p} @tab ATmega3290P
+@item @code{m32u4} @tab ATmega32U4
+@item @code{m48}   @tab ATmega48
+@item @code{m64}   @tab ATmega64
+@item @code{m640}  @tab ATmega640
+@item @code{m644p} @tab ATmega644P
+@item @code{m644}  @tab ATmega644
+@item @code{m645}  @tab ATmega645
+@item @code{m6450} @tab ATmega6450
+@item @code{m649}  @tab ATmega649
+@item @code{m6490} @tab ATmega6490
+@item @code{m8}    @tab ATmega8
+@item @code{m8515} @tab ATmega8515
+@item @code{m8535} @tab ATmega8535
+@item @code{m88}   @tab ATmega88
+@item @code{pwm2}  @tab AT90PWM2
+@item @code{pwm2b} @tab AT90PWM2B
+@item @code{pwm3}  @tab AT90PWM3
+@item @code{pwm3b} @tab AT90PWM3B
+@item @code{t10}   @tab ATtiny10
+@item @code{t12}   @tab ATtiny12 (***)
+@item @code{t13}   @tab ATtiny13
+@item @code{t15}   @tab ATtiny15
+@item @code{t2313} @tab ATtiny2313
+@item @code{t25}   @tab ATtiny25
+@item @code{t26}   @tab ATtiny26
+@item @code{t261}  @tab ATtiny261
+@item @code{t4}    @tab ATtiny4
+@item @code{t44}   @tab ATtiny44
+@item @code{t45}   @tab ATtiny45
+@item @code{t461}  @tab ATtiny461
+@item @code{t5}    @tab ATtiny5
+@item @code{t84}   @tab ATtiny84
+@item @code{t85}   @tab ATtiny85
+@item @code{t861}  @tab ATtiny861
+@item @code{t88}   @tab ATtiny88
+@item @code{t9}    @tab ATtiny9
+@item @code{ucr2}  @tab AT32uca0512
+@item @code{usb1286} @tab ATmega1286
+@item @code{usb1287} @tab ATmega1287
+@item @code{usb162}  @tab ATmega162
+@item @code{usb646}  @tab ATmega647
+@item @code{usb647}  @tab ATmega647
+@item @code{usb82}   @tab ATmega82
+@item @code{x128a1}  @tab ATxmega128A1
+@item @code{x128a1d} @tab ATxmega128A1revD
+@item @code{x128a3}  @tab ATxmega128A3
+@item @code{x128a4}  @tab ATxmega128A4
+@item @code{x16a4}   @tab ATxmega16A4
+@item @code{x192a1}  @tab ATxmega192A1
+@item @code{x192a3}  @tab ATxmega192A3
+@item @code{x256a1}  @tab ATxmega256A1
+@item @code{x256a3}  @tab ATxmega256A3
+@item @code{x256a3b} @tab ATxmega256A3B
+@item @code{x32a4}   @tab ATxmega32A4
+@item @code{x64a1}   @tab ATxmega64A1
+@item @code{x64a3}   @tab ATxmega64A3
+@item @code{x64a4}   @tab ATxmega64A4
+@end multitable
+
+(*)   The AT90S2323 and ATtiny22 use the same algorithm.
+
+(**)  Flash addressing above 128 KB is not supported by all
+programming hardware.  Known to work are jtag2, stk500v2,
+and bit-bang programmers.
+
+(***)
+The ATtiny11 uses the same algorithm, but can only be
+programmed in high-voltage serial mode.
+
+@item -b @var{baudrate}
+Override the RS-232 connection baud rate specified in the respective
+programmer's entry of the configuration file.
+
+@item -B @var{bitclock}
+Specify the bit clock period for the JTAG interface or the ISP clock (JTAG ICE only).
+The value is a floating-point number in microseconds.
+The default value of the JTAG ICE results in about 1 microsecond bit
+clock period, suitable for target MCUs running at 4 MHz clock and
+above.
+Unlike certain parameters in the STK500, the JTAG ICE resets all its
+parameters to default values when the programming software signs
+off from the ICE, so for MCUs running at lower clock speeds, this
+parameter must be specified on the command-line.
+
+@item -c @var{programmer-id}
+Specify the programmer to be used.  AVRDUDE knows about several common
+programmers.  Use this option to specify which one to use.  The
+@var{programmer-id} parameter is the programmer's id listed in the
+configuration file.  Specify -c ? to list all programmers in the
+configuration file.  If you have a programmer that is unknown to
+AVRDUDE, and the programmer is controlled via the PC parallel port,
+there's a good chance that it can be easily added to the configuration
+file without any code changes to AVRDUDE.  Simply copy an existing entry
+and change the pin definitions to match that of the unknown programmer.
+Currently, the following programmer ids are understood and supported:
+
+@multitable @columnfractions .2 .6
+@item @code{abcmini}     @tab
+ABCmini Board, aka Dick Smith HOTCHIP
+@item @code{alf}         @tab
+Nightshade ALF-PgmAVR,@*
+@url{http://nightshade.homeip.net/}
+@item @code{arduino}
+Arduino board, protocol similar to STK500 1.x
+@item @code{atisp}       @tab
+AT-ISP V1.1 programming cable for AVR-SDK1 from,@*
+@url{http://micro-research.co.th/}
+@item @code{avr109}      @tab
+Atmel AppNote AVR109 Boot Loader
+@item @code{avr910}      @tab
+Atmel Low Cost Serial Programmer
+@item @code{avr911}      @tab
+Atmel AppNote AVR911 AVROSP (an alias for avr109)
+@item @code{avrisp}      @tab
+Atmel AVR ISP (an alias for stk500)
+@item @code{avrisp2}     @tab
+Atmel AVR ISP mkII in ISP mode, in PDI mode for ATxmega devices, or
+in TPI mode for ATtiny4/5/9/10
+@item @code{avrispmkII}  @tab
+Atmel AVR ISP mkII (alias for stk500v2)
+@item @code{avrispv2}    @tab
+Atmel AVR ISP, running a version 2.x firmware (an alias for stk500v2)
+@item @code{bascom}      @tab
+Bascom SAMPLE programming cable
+@item @code{blaster}     @tab
+Altera ByteBlaster
+@item @code{bsd}         @tab
+Brian Dean's Programmer,@*
+@url{http://www.bsdhome.com/avrdude/}
+@item @code{buspirate}   @tab
+The Bus Pirate
+@item @code{butterfly}   @tab
+Atmel Butterfly Development Board
+@item @code{c2n232i}     @tab
+C2N232I, reset=dtr sck=!rts mosi=!txd miso=!cts,@*
+@url{http://www.ktverkko.fi/~msmakela/8bit/c2n232/hardware/index.en.html}
+@item @code{dapa}        @tab
+Direct AVR Parallel Access cable
+@item @code{dasa}        @tab
+serial port banging, reset=rts sck=dtr mosi=txd miso=cts
+@item @code{dasa3}       @tab
+serial port banging, reset=!dtr sck=rts mosi=txd miso=cts
+@item @code{dragon_dw}   @tab
+AVR Dragon in debugWire mode
+@item @code{dragon_hvsp} @tab
+AVR Dragon in high-voltage serial programming mode
+@item @code{dragon_isp}  @tab
+AVR Dragon in ISP mode
+@item @code{dragon_jtag} @tab
+AVR Dragon in JTAG mode
+@item @code{dragon_pdi} @tab
+AVR Dragon in PDI mode
+@item @code{dragon_pp}   @tab
+AVR Dragon in (high-voltage) parallel programming mode
+@item @code{dt006}       @tab
+Dontronics DT006
+@item @code{ere-isp-avr} @tab
+ERE ISP-AVR,@*
+@url{http://www.ere.co.th/download/sch050713.pdf}
+@item @code{frank-stk200}@tab
+Frank's STK200 clone,@*
+@url{http://electropol.free.fr/spip/spip.php?article15}
+@item @code{futurlec}    @tab
+Futurlec.com programming cable
+@item @code{jtag1}       @tab
+Atmel JTAG ICE mkI, running at 115200 Bd
+@item @code{jtag1slow}   @tab
+Atmel JTAG ICE mkI, running at 19200 Bd
+@item @code{jtag2}       @tab
+Atmel JTAG ICE mkII, running at 115200 Bd
+@item @code{jtag2avr32}  @tab
+Atmel JTAG ICE mkII in AVR32 mode.
+@item @code{jtag2dw}     @tab
+Atmel JTAG ICE mkII in debugWire mode.
+@item @code{jtag2fast}   @tab
+Atmel JTAG ICE mkII, running at 115200 Bd
+@item @code{jtag2isp}    @tab
+Atmel JTAG ICE mkII in ISP mode.
+@item @code{jtag2pdi}    @tab
+Atmel JTAG ICE mkII in PDI mode.
+@item @code{jtag2slow}   @tab
+Atmel JTAG ICE mkII (default speed 19200 Bd)
+@item @code{jtagmkI}     @tab
+Atmel JTAG ICE mkI, running at 115200 Bd
+@item @code{jtagmkII}    @tab
+Atmel JTAG ICE mkII (default speed 19200 Bd)
+@item @code{jtagmkII_avr32} @tab
+Atmel JTAG ICE mkII in AVR32 mode.
+@item @code{mib510}      @tab
+Crossbow MIB510 programming board
+@item @code{pavr}        @tab
+Jason Kyle's pAVR Serial Programmer
+@item @code{picoweb}     @tab
+Picoweb Programming Cable,@*
+@url{http://www.picoweb.net/}
+@item @code{pony-stk200} @tab
+Pony Prog STK200
+@item @code{ponyser}     @tab
+design ponyprog serial, reset=!txd sck=rts mosi=dtr miso=cts
+@item @code{siprog}      @tab
+Lancos SI-Prog,@*
+@url{http://www.lancos.com/siprogsch.html}
+@item @code{sp12}        @tab
+Steve Bolt's Programmer
+@item @code{stk200}      @tab
+STK200
+@item @code{stk500}      @tab
+Atmel STK500, probing for either version 1.x or 2.x firmware
+@item @code{stk500hvsp}  @tab
+Atmel STK500 in high-voltage serial programming mode(version 2.x firmware only)
+@item @code{stk500pp}    @tab
+Atmel STK500 in parallel programming mode (version 2.xfirmware only)
+@item @code{stk500v1}    @tab
+Atmel STK500, running a version 1.x firmware
+@item @code{stk500v2}    @tab
+Atmel STK500, running a version 2.x firmware
+@item @code{stk600}      @tab
+Atmel STK600 in ISP mode, in PDI mode for ATxmega devices, or
+in TPI mode for ATtiny4/5/9/10
+@item @code{stk600hvsp}  @tab
+Atmel STK600 in high-voltage serial programming mode
+@item @code{stk600pp}    @tab
+Atmel STK600 in parallel programming mode
+@item @code{usbasp}      @tab
+USBasp,@*
+@url{http://www.fischl.de/usbasp/}
+@item @code{usbtiny}     @tab
+USBtiny simple USB programmer,@*
+@url{http://www.ladyada.net/make/usbtinyisp/}
+@item @code{xil}         @tab
+Xilinx JTAG cable
+@end multitable
+
+
+
+@item -C @var{config-file}
+Use the specified config file for configuration data.  This file
+contains all programmer and part definitions that AVRDUDE knows about.
+If you have a programmer or part that AVRDUDE does not know about, you
+can add it to the config file (be sure and submit a patch back to the
+author so that it can be incorporated for the next version).  If not
+specified, AVRDUDE reads the configuration file from
+/usr/local/etc/avrdude.conf (FreeBSD and Linux). See Appendix A for
+the method of searching for the configuration file for Windows.
+
+@item -D
+Disable auto erase for flash.  When the -U option with flash memory is 
+specified, avrdude will perform a chip erase before starting any of the 
+programming operations, since it generally is a mistake to program the flash
+without performing an erase first.  This option disables that.
+Auto erase is not used for ATxmega devices as these devices can
+use page erase before writing each page so no explicit chip erase
+is required.
+Note however that any page not affected by the current operation
+will retain its previous contents.
+
+@item -e
+Causes a chip erase to be executed.  This will reset the contents of the
+flash ROM and EEPROM to the value `0xff', and clear all lock bits.
+Except for ATxmega devices which can use page erase,
+it is basically a
+prerequisite command before the flash ROM can be reprogrammed again.
+The only exception would be if the new contents would exclusively cause
+bits to be programmed from the value `1' to `0'.  Note that in order
+to reprogram EERPOM cells, no explicit prior chip erase is required
+since the MCU provides an auto-erase cycle in that case before
+programming the cell.
+
+
+@item -E @var{exitspec}[,@dots{}]
+By default, AVRDUDE leaves the parallel port in the same state at exit
+as it has been found at startup.  This option modifies the state of the
+`/RESET' and `Vcc' lines the parallel port is left at, according to
+the exitspec arguments provided, as follows:
+
+@table @code
+@itemx reset
+The `/RESET' signal will be left activated at program exit, that is it
+will be held low, in order to keep the MCU in reset state afterwards.
+Note in particular that the programming algorithm for the AT90S1200
+device mandates that the `/RESET' signal is active before powering up
+the MCU, so in case an external power supply is used for this MCU type,
+a previous invocation of AVRDUDE with this option specified is one of
+the possible ways to guarantee this condition.
+
+@itemx noreset
+The `/RESET' line will be deactivated at program exit, thus allowing the
+MCU target program to run while the programming hardware remains
+connected.
+
+@itemx vcc
+This option will leave those parallel port pins active (i. e. high) that
+can be used to supply `Vcc' power to the MCU.
+
+@itemx novcc
+This option will pull the `Vcc' pins of the parallel port down at
+program exit.
+
+@end table
+
+Multiple @var{exitspec} arguments can be separated with commas.
+
+
+@item -F
+Normally, AVRDUDE tries to verify that the device signature read from
+the part is reasonable before continuing.  Since it can happen from time
+to time that a device has a broken (erased or overwritten) device
+signature but is otherwise operating normally, this options is provided
+to override the check.
+Also, for programmers like the Atmel STK500 and STK600 which can
+adjust parameters local to the programming tool (independent of an
+actual connection to a target controller), this option can be used
+together with @option{-t} to continue in terminal mode.
+
+@item -i @var{delay}
+For bitbang-type programmers, delay for approximately
+@var{delay}
+microseconds between each bit state change.
+If the host system is very fast, or the target runs off a slow clock
+(like a 32 kHz crystal, or the 128 kHz internal RC oscillator), this
+can become necessary to satisfy the requirement that the ISP clock
+frequency must not be higher than 1/4 of the CPU clock frequency.
+This is implemented as a spin-loop delay to allow even for very
+short delays.
+On Unix-style operating systems, the spin loop is initially calibrated
+against a system timer, so the number of microseconds might be rather
+realistic, assuming a constant system load while AVRDUDE is running.
+On Win32 operating systems, a preconfigured number of cycles per
+microsecond is assumed that might be off a bit for very fast or very
+slow machines.
+
+@item -n
+No-write - disables actually writing data to the MCU (useful for
+debugging AVRDUDE).
+
+@item -O
+Perform a RC oscillator run-time calibration according to Atmel
+application note AVR053.
+This is only supported on the STK500v2, AVRISP mkII, and JTAG ICE mkII
+hardware.
+Note that the result will be stored in the EEPROM cell at address 0.
+
+@item -P @var{port}
+Use port to identify the device to which the programmer is attached.
+Normally, the default parallel port is used, but if the programmer type
+normally connects to the serial port, the default serial port will be
+used. See Appendix A, Platform Dependent Information, to find out the
+default port names for your platform. If you need to use a different
+parallel or serial port, use this option to specify the alternate port name.
+
+On Win32 operating systems, the parallel ports are referred to as lpt1
+through lpt3, referring to the addresses 0x378, 0x278, and 0x3BC,
+respectively.  If the parallel port can be accessed through a different
+address, this address can be specified directly, using the common C
+language notation (i. e., hexadecimal values are prefixed by @var{0x}).
+
+For the JTAG ICE mkII, if AVRDUDE has been built with libusb support,
+@var{port} may alternatively be specified as
+@code{usb}[:@var{serialno}].  In that case, the JTAG ICE mkII will be
+looked up on USB.  If @var{serialno} is also specified, it will be
+matched against the serial number read from any JTAG ICE mkII found on
+USB.  The match is done after stripping any existing colons from the
+given serial number, and right-to-left, so only the least significant
+bytes from the serial number need to be given.
+For a trick how to find out the serial numbers of all JTAG ICEs
+attached to USB, see @ref{Example Command Line Invocations}.
+
+As the AVRISP mkII device can only be talked to over USB, the very
+same method of specifying the port is required there.
+
+For the USB programmer "AVR-Doper" running in HID mode, the port must
+be specified as @var{avrdoper}. Libusb support is required on Unix
+but not on Windows. For more information about AVR-Doper see
+@url{http://www.obdev.at/avrusb/avrdoper.html}.
+
+For programmers that attach to a serial port using some kind of
+higher level protocol (as opposed to bit-bang style programmers),
+@var{port} can be specified as @code{net}:@var{host}:@var{port}.
+In this case, instead of trying to open a local device, a TCP
+network connection to (TCP) @var{port} on @var{host}
+is established.
+The remote endpoint is assumed to be a terminal or console server
+that connects the network stream to a local serial port where the
+actual programmer has been attached to.
+The port is assumed to be properly configured, for example using a
+transparent 8-bit data connection without parity at 115200 Baud
+for a STK500.
+
+@emph{This feature is currently not implemented for Win32 systems.}
+
+
+@item -q
+Disable (or quell) output of the progress bar while reading or writing
+to the device.  Specify it a second time for even quieter operation.
+
+@item -u
+Disables the default behaviour of reading out the fuses three times before
+programming, then verifying at the end of programming that the fuses have not
+changed. If you want to change fuses you will need to specify this option,
+as avrdude will see the fuses have changed (even though you wanted to) and
+will change them back for your "safety". This option was designed to
+prevent cases of fuse bits magically changing (usually called @emph{safemode}).
+
+@item -t
+Tells AVRDUDE to enter the interactive ``terminal'' mode instead of up-
+or downloading files.  See below for a detailed description of the
+terminal mode.
+
+@item -U @var{memtype}:@var{op}:@var{filename}[:@var{format}]
+Perform a memory operation.
+Multiple @option{-U} options can be specified in order to operate on
+multiple memories on the same command-line invocation.  The
+@var{memtype} field specifies the memory type to operate on. Use
+the @option{-v} option on the command line or the @code{part} command from
+terminal mode to display all the memory types supported by a particular
+device.
+Typically, a device's memory configuration at least contains
+the memory types
+@code{flash}
+and
+@code{eeprom}.
+All memory types currently known are:
+@table @code
+@item calibration
+One or more bytes of RC oscillator calibration data.
+@item eeprom
+The EEPROM of the device.
+@item efuse
+The extended fuse byte.
+@item flash
+The flash ROM of the device.
+@item fuse
+The fuse byte in devices that have only a single fuse byte.
+@item hfuse
+The high fuse byte.
+@item lfuse
+The low fuse byte.
+@item lock
+The lock byte.
+@item signature
+The three device signature bytes (device ID).
+@item fuse@emph{N}
+The fuse bytes of ATxmega devices, @emph{N} is an integer number
+for each fuse supported by the device.
+@item application
+The application flash area of ATxmega devices.
+@item apptable
+The application table flash area of ATxmega devices.
+@item boot
+The boot flash area of ATxmega devices.
+@item prodsig
+The production signature (calibration) area of ATxmega devices.
+@item usersig
+The user signature area of ATxmega devices.
+@end table
+
+The @var{op} field specifies what operation to perform:
+
+@table @code
+@itemx r
+read the specified device memory and write to the specified file
+
+@itemx w
+read the specified file and write it to the specified device memory
+
+@itemx v
+read the specified device memory and the specified file and perform a verify operation
+
+@end table
+
+The @var{filename} field indicates the name of the file to read or
+write.  The @var{format} field is optional and contains the format of
+the file to read or write.  Possible values are:
+
+@table @code
+@itemx i
+Intel Hex
+
+@itemx s
+Motorola S-record
+
+@itemx r
+raw binary; little-endian byte order, in the case of the flash ROM data
+
+@itemx m
+immediate mode; actual byte values specified on the command line,
+separated by commas or spaces in place of the @var{filename} field of
+the @option{-U} option.  This is useful
+for programming fuse bytes without having to create a single-byte file
+or enter terminal mode.  If the number specified begins with @code{0x},
+it is treated as a hex value.  If the number otherwise begins with a
+leading zero (@code{0}) it is treated as octal.  Otherwise, the value is
+treated as decimal.
+
+@itemx a
+auto detect; valid for input only, and only if the input is not provided
+at stdin.
+
+@itemx d
+decimal; this and the following formats are only valid on output.
+They generate one line of output for the respective memory section,
+forming a comma-separated list of the values.
+This can be particularly useful for subsequent processing, like for
+fuse bit settings.
+
+@itemx h
+hexadecimal; each value will get the string @emph{0x} prepended.
+
+@itemx o
+octal; each value will get a @emph{0}
+prepended unless it is less than 8 in which case it gets no prefix.
+
+@itemx b
+binary; each value will get the string @emph{0b} prepended.
+
+@end table
+
+The default is to use auto detection for input files, and raw binary
+format for output files.
+
+Note that if @var{filename} contains a colon, the @var{format} field is
+no longer optional since the filename part following the colon would
+otherwise be misinterpreted as @var{format}.
+
+As an abbreviation, the form @code{-U} @var{filename}
+is equivalent to specifying
+@code{-U} @emph{flash:w:}@var{filename}@emph{:a}.
+This will only work if @var{filename} does not have a colon in it.
+
+@item -v
+Enable verbose output.
+
+@item -V
+Disable automatic verify check when uploading data.
+
+@item -x @var{extended_param}
+Pass @var{extended_param} to the chosen programmer implementation as
+an extended parameter.  The interpretation of the extended parameter
+depends on the programmer itself.  See below for a list of programmers
+accepting extended parameters.
+
+@item -y
+Tells AVRDUDE to use the last four bytes of the connected parts' EEPROM
+memory to track the number of times the device has been erased.  When
+this option is used and the @option{-e} flag is specified to generate a
+chip erase, the previous counter will be saved before the chip erase, it
+is then incremented, and written back after the erase cycle completes.
+Presumably, the device would only be erased just before being
+programmed, and thus, this can be utilized to give an indication of how
+many erase-rewrite cycles the part has undergone.  Since the FLASH
+memory can only endure a finite number of erase-rewrite cycles, one can
+use this option to track when a part is nearing the limit.  The typical
+limit for Atmel AVR FLASH is 1000 cycles.  Of course, if the
+application needs the last four bytes of EEPROM memory, this option
+should not be used.
+
+@item -Y @var{cycles}
+Instructs AVRDUDE to initialize the erase-rewrite cycle counter residing
+at the last four bytes of EEPROM memory to the specified value.  If the
+application needs the last four bytes of EEPROM memory, this option
+should not be used.
+
+@end table
+
+@page
+@c
+@c Node
+@c
+@node Programmers accepting extended parameters, Example Command Line Invocations, Option Descriptions, Command Line Options
+@section Programmers accepting extended parameters
+
+@table @code
+
+@item JTAG ICE mkII
+@itemx AVR Dragon
+
+When using the JTAG ICE mkII or AVR Dragon in JTAG mode, the
+following extended parameter is accepted:
+@table @code
+@item @samp{jtagchain=UB,UA,BB,BA}
+Setup the JTAG scan chain for @var{UB} units before, @var{UA} units
+after, @var{BB} bits before, and @var{BA} bits after the target AVR,
+respectively.
+Each AVR unit within the chain shifts by 4 bits.
+Other JTAG units might require a different bit shift count.
+@end table
+
+@item AVR910
+
+The AVR910 programmer type accepts the following extended parameter:
+@table @code
+@item @samp{devcode=VALUE}
+Override the device code selection by using @var{VALUE}
+as the device code.
+The programmer is not queried for the list of supported
+device codes, and the specified @var{VALUE}
+is not verified but used directly within the
+@code{T} command sent to the programmer.
+@var{VALUE} can be specified using the conventional number notation of the
+C programming language.
+@item @samp{no_blockmode}
+Disables the default checking for block transfer capability.
+Use 
+@samp{no_blockmode} only if your @samp{AVR910} 
+programmer creates errors during initial sequence.
+@end table
+
+@item BusPirate
+
+The BusPirate programmer type accepts the following extended parameters:
+@table @code
+@item @samp{reset=cs,aux,aux2}
+The default setup assumes the BusPirate's CS output pin connected to
+the RESET pin on AVR side. It is however possible to have multiple AVRs
+connected to the same BP with MISO, MOSI and SCK lines common for all of them.
+In such a case one AVR should have its RESET connected to BusPirate's
+@emph{CS}
+pin, second AVR's RESET connected to BusPirate's
+@emph{AUX}
+pin and if your BusPirate has an
+@emph{AUX2}
+pin (only available on BusPirate version v1a with firmware 3.0 or newer)
+use that to activate RESET on the third AVR.
+
+It may be a good idea to decouple the BusPirate and the AVR's SPI buses from
+each other using a 3-state bus buffer. For example 74HC125 or 74HC244 are some
+good candidates with the latches driven by the appropriate reset pin (cs,
+aux or aux2). Otherwise the SPI traffic in one active circuit may interfere
+with programming the AVR in the other design.
+
+@item @samp{speed=@var{0..7}}
+@table @code
+@item 0
+30 kHz (default)
+@item 1
+125 kHz
+@item 2
+250 kHz
+@item 3
+1 MHz
+@item 4
+2 MHz
+@item 5
+2.6 MHz
+@item 6
+4 MHz
+@item 7
+8 MHz
+@end table
+
+@item @samp{ascii}
+Use ASCII mode even when the firmware supports BinMode (binary mode).
+BinMode is supported in firmware 2.7 and newer, older FW's either don't
+have BinMode or their BinMode is buggy. ASCII mode is slower and makes
+the above
+@samp{reset=}
+and
+@samp{speed=}
+parameters unavailable.
+@end table
+
+@end table
+
+@page
+@c
+@c Node
+@c
+@node Example Command Line Invocations,  , Programmers accepting extended parameters, Command Line Options
+@section Example Command Line Invocations
+
+@noindent
+Download the file @code{diag.hex} to the ATmega128 chip using the
+STK500 programmer connected to the default serial port:
+
+@smallexample
+@cartouche
+% avrdude -p m128 -c stk500 -e -U flash:w:diag.hex 
+
+avrdude: AVR device initialized and ready to accept instructions
+
+Reading | ################################################## | 100% 0.03s
+
+avrdude: Device signature = 0x1e9702
+avrdude: erasing chip
+avrdude: done.
+avrdude: performing op: 1, flash, 0, diag.hex
+avrdude: reading input file "diag.hex"
+avrdude: input file diag.hex auto detected as Intel Hex
+avrdude: writing flash (19278 bytes):
+
+Writing | ################################################## | 100% 7.60s
+
+avrdude: 19456 bytes of flash written
+avrdude: verifying flash memory against diag.hex:
+avrdude: load data flash data from input file diag.hex:
+avrdude: input file diag.hex auto detected as Intel Hex
+avrdude: input file diag.hex contains 19278 bytes
+avrdude: reading on-chip flash data:
+
+Reading | ################################################## | 100% 6.83s
+
+avrdude: verifying ...
+avrdude: 19278 bytes of flash verified
+
+avrdude: safemode: Fuses OK
+
+avrdude done.  Thank you.
+
+%
+@end cartouche
+@end smallexample
+
+@page
+@noindent
+Upload the flash memory from the ATmega128 connected to the STK500
+programmer and save it in raw binary format in the file named
+@code{c:/diag flash.bin}:
+
+@smallexample
+@cartouche
+% avrdude -p m128 -c stk500 -U flash:r:"c:/diag flash.bin":r 
+
+avrdude: AVR device initialized and ready to accept instructions
+
+Reading | ################################################## | 100% 0.03s
+
+avrdude: Device signature = 0x1e9702
+avrdude: reading flash memory:
+
+Reading | ################################################## | 100% 46.10s
+
+avrdude: writing output file "c:/diag flash.bin"
+
+avrdude: safemode: Fuses OK
+
+avrdude done.  Thank you.
+
+% 
+@end cartouche
+@end smallexample
+
+@page
+@noindent
+Using the default programmer, download the file @code{diag.hex} to
+flash, @code{eeprom.hex} to EEPROM, and set the Extended, High, and Low
+fuse bytes to 0xff, 0x89, and 0x2e respectively:
+
+@smallexample
+@cartouche
+
+% avrdude -p m128 -u -U flash:w:diag.hex \
+>                 -U eeprom:w:eeprom.hex \
+>                 -U efuse:w:0xff:m      \
+>                 -U hfuse:w:0x89:m      \
+>                 -U lfuse:w:0x2e:m
+
+avrdude: AVR device initialized and ready to accept instructions
+
+Reading | ################################################## | 100% 0.03s
+
+avrdude: Device signature = 0x1e9702
+avrdude: NOTE: FLASH memory has been specified, an erase cycle will be performed
+         To disable this feature, specify the -D option.
+avrdude: erasing chip
+avrdude: reading input file "diag.hex"
+avrdude: input file diag.hex auto detected as Intel Hex
+avrdude: writing flash (19278 bytes):
+
+Writing | ################################################## | 100% 7.60s
+
+avrdude: 19456 bytes of flash written
+avrdude: verifying flash memory against diag.hex:
+avrdude: load data flash data from input file diag.hex:
+avrdude: input file diag.hex auto detected as Intel Hex
+avrdude: input file diag.hex contains 19278 bytes
+avrdude: reading on-chip flash data:
+
+Reading | ################################################## | 100% 6.84s
+
+avrdude: verifying ...
+avrdude: 19278 bytes of flash verified
+
+[ ... other memory status output skipped for brevity ... ]
+
+avrdude done.  Thank you.
+
+% 
+@end cartouche
+@end smallexample
+
+@page
+@noindent
+Connect to the JTAG ICE mkII which serial number ends up in 1C37 via
+USB, and enter terminal mode:
+
+@smallexample
+@cartouche
+
+% avrdude -c jtag2 -p m649 -P usb:1c:37 -t
+
+avrdude: AVR device initialized and ready to accept instructions
+
+Reading | ################################################## | 100% 0.03s
+
+avrdude: Device signature = 0x1e9603
+
+[ ... terminal mode output skipped for brevity ... ]
+
+avrdude done.  Thank you.
+
+@end cartouche
+@end smallexample
+
+@noindent
+List the serial numbers of all JTAG ICEs attached to USB.  This is
+done by specifying an invalid serial number, and increasing the
+verbosity level.
+
+@smallexample
+@cartouche
+
+% avrdude -c jtag2 -p m128 -P usb:xx -v
+[...]
+         Using Port            : usb:xxx
+         Using Programmer      : jtag2
+avrdude: usbdev_open(): Found JTAG ICE, serno: 00A000001C6B
+avrdude: usbdev_open(): Found JTAG ICE, serno: 00A000001C3A
+avrdude: usbdev_open(): Found JTAG ICE, serno: 00A000001C30
+avrdude: usbdev_open(): did not find any (matching) USB device "usb:xxx"
+
+@end cartouche
+@end smallexample
+
+
+@c
+@c Node
+@c
+@node Terminal Mode Operation, Configuration File, Command Line Options, Top
+@chapter Terminal Mode Operation
+
+AVRDUDE has an interactive mode called @var{terminal mode} that is
+enabled by the @option{-t} option.  This mode allows one to enter
+interactive commands to display and modify the various device memories,
+perform a chip erase, display the device signature bytes and part
+parameters, and to send raw programming commands.  Commands and
+parameters may be abbreviated to their shortest unambiguous form.
+Terminal mode also supports a command history so that previously entered
+commands can be recalled and edited.
+
+@menu
+* Terminal Mode Commands::      
+* Terminal Mode Examples::      
+@end menu
+
+@node Terminal Mode Commands, Terminal Mode Examples, Terminal Mode Operation, Terminal Mode Operation
+@section Terminal Mode Commands
+
+@noindent
+The following commands are implemented:
+
+@table @code
+
+@item dump @var{memtype} @var{addr} @var{nbytes}
+Read @var{nbytes} from the specified memory area, and display them in
+the usual hexadecimal and ASCII form.
+
+@item dump
+Continue dumping the memory contents for another @var{nbytes} where the
+previous dump command left off.
+
+@item write @var{memtype} @var{addr} @var{byte1} @dots{} @var{byteN}
+Manually program the respective memory cells, starting at address addr,
+using the values @var{byte1} through @var{byteN}.  This feature is not
+implemented for bank-addressed memories such as the flash memory of
+ATMega devices.
+
+@item erase
+Perform a chip erase.
+
+@item send @var{b1} @var{b2} @var{b3} @var{b4}
+Send raw instruction codes to the AVR device.  If you need access to a
+feature of an AVR part that is not directly supported by AVRDUDE, this
+command allows you to use it, even though AVRDUDE does not implement the
+command.   When using direct SPI mode, up to 3 bytes
+can be omitted.
+
+@item sig
+Display the device signature bytes.
+
+@item spi
+Enter direct SPI mode.  The @emph{pgmled} pin acts as slave select.
+@emph{Only supported on parallel bitbang programmers.}
+
+@item part
+Display the current part settings and parameters.  Includes chip
+specific information including all memory types supported by the
+device, read/write timing, etc.
+
+@item pgm
+Return to programming mode (from direct SPI mode).
+
+@item ?
+@itemx help
+Give a short on-line summary of the available commands.
+
+@item quit
+Leave terminal mode and thus AVRDUDE.
+
+@end table
+
+@noindent
+In addition, the following commands are supported on the STK500
+and STK600 programmer:
+
+@table @code
+
+@item vtarg @var{voltage}
+Set the target's supply voltage to @var{voltage} Volts.
+
+@item varef [@var{channel}] @var{voltage}
+Set the adjustable voltage source to @var{voltage} Volts.
+This voltage is normally used to drive the target's
+@emph{Aref} input on the STK500 and STK600.
+The STK600 offers two reference voltages, which can be
+selected by the optional parameter @var{channel} (either
+0 or 1).
+
+@item fosc @var{freq}[@code{M}|@code{k}]
+Set the master oscillator to @var{freq} Hz.
+An optional trailing letter @code{M}
+multiplies by 1E6, a trailing letter @code{k} by 1E3.
+
+@item fosc off
+Turn the master oscillator off.
+
+@item sck @var{period}
+@emph{STK500 and STK600 only:}
+Set the SCK clock period to @var{period} microseconds.
+
+@emph{JTAG ICE only:}
+Set the JTAG ICE bit clock period to @var{period} microseconds.
+Note that unlike STK500 settings, this setting will be reverted to
+its default value (approximately 1 microsecond) when the programming
+software signs off from the JTAG ICE.
+This parameter can also be used on the JTAG ICE mkII to specify the
+ISP clock period when operating the ICE in ISP mode.
+
+@item parms
+@emph{STK500 and STK600 only:}
+Display the current voltage and master oscillator parameters.
+
+@emph{JTAG ICE only:}
+Display the current target supply voltage and JTAG bit clock rate/period.
+
+@end table
+
+@c
+@c Node
+@c
+@node Terminal Mode Examples,  , Terminal Mode Commands, Terminal Mode Operation
+@section Terminal Mode Examples
+
+@noindent
+Display part parameters, modify eeprom cells, perform a chip erase:
+
+@smallexample
+@cartouche
+% avrdude -p m128 -c stk500 -t
+
+avrdude: AVR device initialized and ready to accept instructions
+avrdude: Device signature = 0x1e9702
+avrdude: current erase-rewrite cycle count is 52 (if being tracked)
+avrdude> part
+>>> part 
+
+AVR Part              : ATMEGA128
+Chip Erase delay      : 9000 us
+PAGEL                 : PD7
+BS2                   : PA0
+RESET disposition     : dedicated
+RETRY pulse           : SCK
+serial program mode   : yes
+parallel program mode : yes
+Memory Detail         :
+
+                            Page                       Polled
+  Memory Type Paged  Size   Size #Pages MinW  MaxW   ReadBack
+  ----------- ------ ------ ---- ------ ----- ----- ---------
+  eeprom      no       4096    8     0  9000  9000 0xff 0xff
+  flash       yes    131072  256   512  4500  9000 0xff 0x00
+  lfuse       no          1    0     0     0     0 0x00 0x00
+  hfuse       no          1    0     0     0     0 0x00 0x00
+  efuse       no          1    0     0     0     0 0x00 0x00
+  lock        no          1    0     0     0     0 0x00 0x00
+  calibration no          1    0     0     0     0 0x00 0x00
+  signature   no          3    0     0     0     0 0x00 0x00
+
+avrdude> dump eeprom 0 16
+>>> dump eeprom 0 16 
+0000  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
+
+avrdude> write eeprom 0 1 2 3 4
+>>> write eeprom 0 1 2 3 4 
+
+avrdude> dump eeprom 0 16
+>>> dump eeprom 0 16 
+0000  01 02 03 04 ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
+
+avrdude> erase
+>>> erase 
+avrdude: erasing chip
+avrdude> dump eeprom 0 16
+>>> dump eeprom 0 16 
+0000  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
+
+avrdude> 
+@end cartouche
+@end smallexample
+
+
+@noindent
+Program the fuse bits of an ATmega128 (disable M103 compatibility,
+enable high speed external crystal, enable brown-out detection, slowly
+rising power).  Note since we are working with fuse bits the -u (unsafe)
+option is specified, which allows you to modify the fuse bits. First 
+display the factory defaults, then reprogram:
+
+@smallexample
+@cartouche
+% avrdude -p m128 -u -c stk500 -t
+
+avrdude: AVR device initialized and ready to accept instructions
+avrdude: Device signature = 0x1e9702
+avrdude: current erase-rewrite cycle count is 52 (if being tracked)
+avrdude> d efuse
+>>> d efuse 
+0000  fd                                                |.               |
+
+avrdude> d hfuse
+>>> d hfuse 
+0000  99                                                |.               |
+
+avrdude> d lfuse
+>>> d lfuse 
+0000  e1                                                |.               |
+
+avrdude> w efuse 0 0xff
+>>> w efuse 0 0xff 
+
+avrdude> w hfuse 0 0x89
+>>> w hfuse 0 0x89 
+
+avrdude> w lfuse 0 0x2f
+>>> w lfuse 0 0x2f 
+
+avrdude> 
+@end cartouche
+@end smallexample
+
+
+@c
+@c Node
+@c
+@node Configuration File, Programmer Specific Information, Terminal Mode Operation, Top
+@chapter Configuration File
+
+@noindent
+AVRDUDE reads a configuration file upon startup which describes all of
+the parts and programmers that it knows about.  The advantage of this is
+that if you have a chip that is not currently supported by AVRDUDE, you
+can add it to the configuration file without waiting for a new release
+of AVRDUDE.  Likewise, if you have a parallel port programmer that is
+not supported by AVRDUDE, chances are good that you can copy and
+existing programmer definition, and with only a few changes, make your
+programmer work with AVRDUDE.
+
+AVRDUDE first looks for a system wide configuration file in a platform
+dependent location.  On Unix, this is usually
+@code{/usr/local/etc/avrdude.conf}, while on Windows it is usally in the
+same location as the executable file.  The name of this file can be
+changed using the @option{-C} command line option.  After the system wide
+configuration file is parsed, AVRDUDE looks for a per-user configuration
+file to augment or override the system wide defaults.  On Unix, the
+per-user file is @code{.avrduderc} within the user's home directory.  On
+Windows, this file is the @code{avrdude.rc} file located in the same
+directory as the executable.
+
+@menu
+* AVRDUDE Defaults::            
+* Programmer Definitions::      
+* Part Definitions::            
+* Other Notes::                 
+@end menu
+
+@c
+@c Node
+@c
+@node AVRDUDE Defaults, Programmer Definitions, Configuration File, Configuration File
+@section AVRDUDE Defaults
+
+@table @code
+
+@item default_parallel = "@var{default-parallel-device}";
+Assign the default parallel port device.  Can be overridden using the
+@option{-P} option.
+
+@item default_serial = "@var{default-serial-device}";
+Assign the default serial port device.  Can be overridden using the
+@option{-P} option.
+
+@item default_programmer = "@var{default-programmer-id}";
+Assign the default programmer id.  Can be overridden using the @option{-c}
+option.
+
+@end table
+
+
+@c
+@c Node
+@c
+@node Programmer Definitions, Part Definitions, AVRDUDE Defaults, Configuration File
+@section Programmer Definitions
+
+@noindent
+The format of the programmer definition is as follows:
+
+@smallexample
+programmer
+    id     = <id1> [, <id2> [, <id3>] ...] ;  # <idN> are quoted strings
+    desc     = <description> ;                  # quoted string
+    type     = par | stk500 ;                   # programmer type
+    baudrate = <num> ;                          # baudrate for serial ports
+    vcc      = <num1> [, <num2> ... ] ;         # pin number(s)
+    reset    = <num> ;                          # pin number
+    sck      = <num> ;                          # pin number
+    mosi     = <num> ;                          # pin number
+    miso     = <num> ;                          # pin number
+    errled   = <num> ;                          # pin number
+    rdyled   = <num> ;                          # pin number
+    pgmled   = <num> ;                          # pin number
+    vfyled   = <num> ;                          # pin number
+  ;
+@end smallexample
+
+
+@c
+@c Node
+@c
+@node Part Definitions, Other Notes, Programmer Definitions, Configuration File
+@section Part Definitions
+
+@smallexample
+part
+    id               = <id> ;                 # quoted string
+    desc             = <description> ;        # quoted string
+    devicecode       = <num> ;                # numeric
+    chip_erase_delay = <num> ;                # micro-seconds
+    pagel            = <num> ;                # pin name in hex, i.e., 0xD7
+    bs2              = <num> ;                # pin name in hex, i.e., 0xA0
+    reset            = dedicated | io;
+    retry_pulse      = reset | sck;
+    pgm_enable       = <instruction format> ;
+    chip_erase       = <instruction format> ;
+    memory <memtype>
+        paged           = <yes/no> ;          # yes / no
+        size            = <num> ;             # bytes
+        page_size       = <num> ;             # bytes
+        num_pages       = <num> ;             # numeric
+        min_write_delay = <num> ;             # micro-seconds
+        max_write_delay = <num> ;             # micro-seconds
+        readback_p1     = <num> ;             # byte value
+        readback_p2     = <num> ;             # byte value
+        pwroff_after_write = <yes/no> ;       # yes / no
+        read            = <instruction format> ;
+        write           = <instruction format> ;
+        read_lo         = <instruction format> ;
+        read_hi         = <instruction format> ;
+        write_lo        = <instruction format> ;
+        write_hi        = <instruction format> ;
+        loadpage_lo     = <instruction format> ;
+        loadpage_hi     = <instruction format> ;
+        writepage       = <instruction format> ;
+      ;
+  ;
+@end smallexample
+
+@menu
+* Instruction Format::
+@end menu
+
+@c
+@c Node
+@c
+@node Instruction Format,  , Part Definitions, Part Definitions
+@subsection Instruction Format
+
+@noindent
+Instruction formats are specified as a comma separated list of string
+values containing information (bit specifiers) about each of the 32 bits
+of the instruction.  Bit specifiers may be one of the following formats:
+
+@table @code
+
+@item 1
+The bit is always set on input as well as output
+
+@item 0
+the bit is always clear on input as well as output
+
+@item x
+the bit is ignored on input and output
+
+@item a
+the bit is an address bit, the bit-number matches this bit specifier's
+position within the current instruction byte
+
+@item a@var{N}
+the bit is the @var{N}th address bit, bit-number = N, i.e., @code{a12}
+is address bit 12 on input, @code{a0} is address bit 0.
+
+@item i
+the bit is an input data bit
+
+@item o
+the bit is an output data bit
+
+@end table
+
+Each instruction must be composed of 32 bit specifiers.  The instruction
+specification closely follows the instruction data provided in Atmel's
+data sheets for their parts.  For example, the EEPROM read and write
+instruction for an AT90S2313 AVR part could be encoded as:
+
+@smallexample
+
+read  = "1  0  1  0   0  0  0  0   x x x x  x x x x",
+        "x a6 a5 a4  a3 a2 a1 a0   o o o o  o o o o";
+
+write = "1  1  0  0   0  0  0  0   x x x x  x x x x",
+        "x a6 a5 a4  a3 a2 a1 a0   i i i i  i i i i";
+
+@end smallexample
+
+
+
+@c
+@c Node
+@c
+@node Other Notes,  , Part Definitions, Configuration File
+@section Other Notes
+
+
+@itemize @bullet
+@item
+The @code{devicecode} parameter is the device code used by the STK500
+and is obtained from the software section (@code{avr061.zip}) of
+Atmel's AVR061 application note available from
+@url{http://www.atmel.com/atmel/acrobat/doc2525.pdf}.
+
+@item
+Not all memory types will implement all instructions.
+
+@item
+AVR Fuse bits and Lock bits are implemented as a type of memory.
+
+@item
+Example memory types are: @code{flash}, @code{eeprom}, @code{fuse},
+@code{lfuse} (low fuse), @code{hfuse} (high fuse), @code{efuse}
+(extended fuse), @code{signature}, @code{calibration}, @code{lock}.
+
+@item
+The memory type specified on the AVRDUDE command line must match one of
+the memory types defined for the specified chip.
+
+@item
+The @code{pwroff_after_write} flag causes AVRDUDE to attempt to power
+the device off and back on after an unsuccessful write to the affected
+memory area if VCC programmer pins are defined.  If VCC pins are not
+defined for the programmer, a message indicating that the device needs a
+power-cycle is printed out.  This flag was added to work around a
+problem with the at90s4433/2333's; see the at90s4433 errata at:
+
+         @url{http://www.atmel.com/atmel/acrobat/doc1280.pdf}
+
+@item
+The boot loader from application note AVR109 (and thus also the AVR
+Butterfly) does not support writing of fuse bits.  Writing lock bits
+is supported, but is restricted to the boot lock bits (BLBxx).  These
+are restrictions imposed by the underlying SPM instruction that is used
+to program the device from inside the boot loader.  Note that programming
+the boot lock bits can result in a ``shoot-into-your-foot'' scenario as
+the only way to unprogram these bits is a chip erase, which will also
+erase the boot loader code.
+
+The boot loader implements the ``chip erase'' function by erasing the
+flash pages of the application section.
+
+Reading fuse and lock bits is fully supported.
+
+Note that due to the unability to write the fuse bits, the safemode
+functionality does not make sense for these boot loaders.
+
+@end itemize
+
+@c
+@c Node
+@c
+@node Programmer Specific Information, Platform Dependent Information, Configuration File, Top
+@chapter Programmer Specific Information
+
+@menu
+* Atmel STK600::
+@end menu
+
+@c
+@c Node
+@c
+@node Atmel STK600, , Programmer Specific Information, Programmer Specific Information
+@section Atmel STK600
+
+@c
+@c Update the table below by running the tools/get-stk600-devices.xsl
+@c XSLT transformation on targetboard.xml as shipped by the latest
+@c release of AVR Studio.
+@c
+The following devices are supported by the respective STK600 routing
+and socket card:
+
+@multitable @columnfractions .25 .25 .5
+Routing card @tab Socket card @tab Devices
+@item @code{} @tab @code{STK600-ATTINY10} @tab ATtiny4 ATtiny5 ATtiny9 ATtiny10
+@item @code{STK600-RC008T-2} @tab @code{STK600-DIP} @tab ATtiny11 ATtiny12 ATtiny13 ATtiny13A ATtiny25 ATtiny45 ATtiny85
+@item @code{STK600-RC008T-7} @tab @code{STK600-DIP} @tab ATtiny15
+@item @code{STK600-RC014T-42} @tab @code{STK600-SOIC} @tab ATtiny20
+@item @code{STK600-RC020T-1} @tab @code{STK600-DIP} @tab ATtiny2313 ATtiny2313A ATtiny4313
+@item @code{} @tab @code{STK600-TinyX3U} @tab ATtiny43U
+@item @code{STK600-RC014T-12} @tab @code{STK600-DIP} @tab ATtiny24 ATtiny44 ATtiny84 ATtiny24A ATtiny44A
+@item @code{STK600-RC020T-8} @tab @code{STK600-DIP} @tab ATtiny26 ATtiny261 ATtiny261A ATtiny461 ATtiny861 ATtiny861A
+@item @code{STK600-RC020T-43} @tab @code{STK600-SOIC} @tab ATtiny261 ATtiny261A ATtiny461 ATtiny461A ATtiny861 ATtiny861A
+@item @code{STK600-RC020T-23} @tab @code{STK600-SOIC} @tab ATtiny87 ATtiny167
+@item @code{STK600-RC028T-3} @tab @code{STK600-DIP} @tab ATtiny28
+@item @code{STK600-RC028M-6} @tab @code{STK600-DIP} @tab ATtiny48 ATtiny88 ATmega8 ATmega8A ATmega48 ATmega88 ATmega168 ATmega48P ATmega48PA ATmega88P ATmega88PA ATmega168P ATmega168PA ATmega328P
+@item @code{} @tab @code{QT600-ATTINY88-QT8} @tab ATtiny88
+@item @code{STK600-RC040M-4} @tab @code{STK600-DIP} @tab ATmega8515 ATmega162
+@item @code{STK600-RC044M-30} @tab @code{STK600-TQFP44} @tab ATmega8515 ATmega162
+@item @code{STK600-RC040M-5} @tab @code{STK600-DIP} @tab ATmega8535 ATmega16 ATmega16A ATmega32 ATmega32A ATmega164P ATmega164PA ATmega324P ATmega324PA ATmega644 ATmega644P ATmega644PA ATmega1284P
+@item @code{STK600-RC044M-31} @tab @code{STK600-TQFP44} @tab ATmega8535 ATmega16 ATmega16A ATmega32 ATmega32A ATmega164P ATmega164PA ATmega324P ATmega324PA ATmega644 ATmega644P ATmega644PA ATmega1284P
+@item @code{} @tab @code{QT600-ATMEGA324-QM64} @tab ATmega324PA
+@item @code{STK600-RC032M-29} @tab @code{STK600-TQFP32} @tab ATmega8 ATmega8A ATmega48 ATmega88 ATmega168 ATmega48P ATmega48PA ATmega88P ATmega88PA ATmega168P ATmega168PA ATmega328P
+@item @code{STK600-RC064M-9} @tab @code{STK600-TQFP64} @tab ATmega64 ATmega64A ATmega128 ATmega128A ATmega1281 ATmega2561 AT90CAN32 AT90CAN64 AT90CAN128
+@item @code{STK600-RC064M-10} @tab @code{STK600-TQFP64} @tab ATmega165 ATmega165P ATmega169 ATmega169P ATmega169PA ATmega325 ATmega325P ATmega329 ATmega329P ATmega645 ATmega649 ATmega649P
+@item @code{STK600-RC100M-11} @tab @code{STK600-TQFP100} @tab ATmega640 ATmega1280 ATmega2560
+@item @code{} @tab @code{STK600-ATMEGA2560} @tab ATmega2560
+@item @code{STK600-RC100M-18} @tab @code{STK600-TQFP100} @tab ATmega3250 ATmega3250P ATmega3290 ATmega3290P ATmega6450 ATmega6490
+@item @code{STK600-RC032U-20} @tab @code{STK600-TQFP32} @tab AT90USB82 AT90USB162 ATmega8U2 ATmega16U2 ATmega32U2 
+@item @code{STK600-RC044U-25} @tab @code{STK600-TQFP44} @tab ATmega16U4 ATmega32U4
+@item @code{STK600-RC064U-17} @tab @code{STK600-TQFP64} @tab ATmega32U6 AT90USB646 AT90USB1286 AT90USB647 AT90USB1287
+@item @code{STK600-RCPWM-22} @tab @code{STK600-TQFP32} @tab ATmega32C1 ATmega64C1 ATmega16M1 ATmega32M1 ATmega64M1
+@item @code{STK600-RCPWM-19} @tab @code{STK600-SOIC} @tab AT90PWM2 AT90PWM3 AT90PWM2B AT90PWM3B AT90PWM216 AT90PWM316
+@item @code{STK600-RCPWM-26} @tab @code{STK600-SOIC} @tab AT90PWM81
+@item @code{STK600-RC044M-24} @tab @code{STK600-TSSOP44} @tab ATmega16HVB ATmega32HVB
+@item @code{} @tab @code{STK600-HVE2} @tab ATmega64HVE
+@item @code{} @tab @code{STK600-ATMEGA128RFA1} @tab ATmega128RFA1
+@item @code{STK600-RC100X-13} @tab @code{STK600-TQFP100} @tab ATxmega64A1 ATxmega128A1 ATxmega128A1_revD ATxmega128A1U
+@item @code{} @tab @code{STK600-ATXMEGA1281A1} @tab ATxmega128A1
+@item @code{} @tab @code{QT600-ATXMEGA128A1-QT16} @tab ATxmega128A1
+@item @code{STK600-RC064X-14} @tab @code{STK600-TQFP64} @tab ATxmega64A3 ATxmega128A3 ATxmega256A3 ATxmega64D3 ATxmega128D3 ATxmega192D3 ATxmega256D3
+@item @code{STK600-RC064X-14} @tab @code{STK600-MLF64} @tab ATxmega256A3B
+@item @code{STK600-RC044X-15} @tab @code{STK600-TQFP44} @tab ATxmega32A4 ATxmega16A4 ATxmega16D4 ATxmega32D4
+@item @code{} @tab @code{STK600-ATXMEGAT0} @tab ATxmega32T0
+@item @code{} @tab @code{STK600-uC3-144} @tab AT32UC3A0512 AT32UC3A0256 AT32UC3A0128
+@item @code{STK600-RCUC3A144-33} @tab @code{STK600-TQFP144} @tab AT32UC3A0512 AT32UC3A0256 AT32UC3A0128
+@item @code{STK600-RCuC3A100-28} @tab @code{STK600-TQFP100} @tab AT32UC3A1512 AT32UC3A1256 AT32UC3A1128
+@item @code{STK600-RCuC3B0-21} @tab @code{STK600-TQFP64-2} @tab AT32UC3B0256 AT32UC3B0512RevC AT32UC3B0512 AT32UC3B0128 AT32UC3B064 AT32UC3D1128
+@item @code{STK600-RCuC3B48-27} @tab @code{STK600-TQFP48} @tab AT32UC3B1256 AT32UC3B164
+@item @code{STK600-RCUC3A144-32} @tab @code{STK600-TQFP144} @tab AT32UC3A3512 AT32UC3A3256 AT32UC3A3128 AT32UC3A364 AT32UC3A3256S AT32UC3A3128S AT32UC3A364S
+@item @code{STK600-RCUC3C0-36} @tab @code{STK600-TQFP144} @tab AT32UC3C0512 AT32UC3C0256 AT32UC3C0128 AT32UC3C064
+@item @code{STK600-RCUC3C1-38} @tab @code{STK600-TQFP100} @tab AT32UC3C1512 AT32UC3C1256 AT32UC3C1128 AT32UC3C164
+@item @code{STK600-RCUC3C2-40} @tab @code{STK600-TQFP64-2} @tab AT32UC3C2512 AT32UC3C2256 AT32UC3C2128 AT32UC3C264
+@item @code{STK600-RCUC3C0-37} @tab @code{STK600-TQFP144} @tab AT32UC3C0512 AT32UC3C0256 AT32UC3C0128 AT32UC3C064
+@item @code{STK600-RCUC3C1-39} @tab @code{STK600-TQFP100} @tab AT32UC3C1512 AT32UC3C1256 AT32UC3C1128 AT32UC3C164
+@item @code{STK600-RCUC3C2-41} @tab @code{STK600-TQFP64-2} @tab AT32UC3C2512 AT32UC3C2256 AT32UC3C2128 AT32UC3C264
+@item @code{STK600-RCUC3L0-34} @tab @code{STK600-TQFP48} @tab AT32UC3L064 AT32UC3L032 AT32UC3L016
+@item @code{} @tab @code{QT600-AT32UC3L-QM64} @tab AT32UC3L064
+@end multitable
+
+Ensure the correct socket and routing card are mounted @emph{before}
+powering on the STK600.  While the STK600 firmware ensures the socket
+and routing card mounted match each other (using a table stored
+internally in nonvolatile memory), it cannot handle the case where a
+wrong routing card is used, e. g. the routing card
+@code{STK600-RC040M-5} (which is meant for 40-pin DIP AVRs that have
+an ADC, with the power supply pins in the center of the package) was
+used but an ATmega8515 inserted (which uses the ``industry standard''
+pinout with Vcc and GND at opposite corners).
+
+Note that for devices that use the routing card @code{STK600-RC008T-2},
+in order to use ISP mode, the jumper for @code{AREF0} must be removed
+as it would otherwise block one of the ISP signals.  High-voltage
+serial programming can be used even with that jumper installed.
+
+The ISP system of the STK600 contains a detection against shortcuts
+and other wiring errors.  AVRDUDE initiates a connection check before
+trying to enter ISP programming mode, and display the result if the
+target is not found ready to be ISP programmed.
+
+High-voltage programming requires the target voltage to be set to at
+least 4.5 V in order to work.  This can be done using
+@emph{Terminal Mode}, see @ref{Terminal Mode Operation}.
+
+@c
+@c Node
+@c
+@node Platform Dependent Information, Troubleshooting, Programmer Specific Information, Top
+@appendix Platform Dependent Information
+
+@menu
+* Unix::
+* Windows::
+@end menu
+
+@c
+@c Node
+@c
+@node Unix, Windows, Platform Dependent Information, Platform Dependent Information
+@section Unix
+
+@menu
+* Unix Installation::           
+* Unix Configuration Files::    
+* Unix Port Names::             
+* Unix Documentation::          
+@end menu
+
+@c
+@c Node
+@c
+@node Unix Installation, Unix Configuration Files, Unix, Unix
+@subsection Unix Installation
+
+@noindent
+To build and install from the source tarball on Unix like systems:
+
+@example
+$ gunzip -c avrdude-@value{VERSION}.tar.gz | tar xf -
+$ cd avrdude-@value{VERSION}
+$ ./configure
+$ make
+$ su root -c 'make install'
+@end example
+
+The default location of the install is into @code{/usr/local} so you
+will need to be sure that @code{/usr/local/bin} is in your @code{PATH}
+environment variable.
+
+If you do not have root access to your system, you can do the the
+following instead:
+
+@example
+$ gunzip -c avrdude-@value{VERSION}.tar.gz | tar xf -
+$ cd avrdude-@value{VERSION}
+$ ./configure --prefix=$HOME/local
+$ make
+$ make install
+@end example
+
+@menu
+* FreeBSD Installation::        
+* Linux Installation::          
+@end menu
+
+@c
+@c Node
+@c
+@node FreeBSD Installation, Linux Installation, Unix Installation, Unix Installation
+@subsubsection FreeBSD Installation
+
+@noindent
+AVRDUDE is installed via the FreeBSD Ports Tree as follows:
+
+@example
+% su - root
+# cd /usr/ports/devel/avrdude
+# make install
+@end example
+
+If you wish to install from a pre-built package instead of the source,
+you can use the following instead:
+
+@example
+% su - root
+# pkg_add -r avrdude
+@end example
+
+Of course, you must be connected to the Internet for these methods to
+work, since that is where the source as well as the pre-built package is
+obtained.
+
+@c
+@c Node
+@c
+@node Linux Installation,  , FreeBSD Installation, Unix Installation
+@subsubsection Linux Installation
+
+@noindent
+On rpm based Linux systems (such as RedHat, SUSE, Mandrake, etc), you
+can build and install the rpm binaries directly from the tarball:
+
+@example
+$ su - root
+# rpmbuild -tb avrdude-@value{VERSION}.tar.gz
+# rpm -Uvh /usr/src/redhat/RPMS/i386/avrdude-@value{VERSION}-1.i386.rpm
+@end example
+
+Note that the path to the resulting rpm package, differs from system
+to system. The above example is specific to RedHat.
+
+@c
+@c Node
+@c
+@node Unix Configuration Files, Unix Port Names, Unix Installation, Unix
+@subsection Unix Configuration Files
+
+@noindent
+When AVRDUDE is build using the default @option{--prefix} configure
+option, the default configuration file for a Unix system is located at
+@code{/usr/local/etc/avrdude.conf}.  This can be overridden by using the
+@option{-C} command line option.  Additionally, the user's home directory
+is searched for a file named @code{.avrduderc}, and if found, is used to
+augment the system default configuration file.
+
+@menu
+* FreeBSD Configuration Files::  
+* Linux Configuration Files::   
+@end menu
+
+@c
+@c Node
+@c
+@node FreeBSD Configuration Files, Linux Configuration Files, Unix Configuration Files, Unix Configuration Files
+@subsubsection FreeBSD Configuration Files
+
+@noindent
+When AVRDUDE is installed using the FreeBSD ports system, the system
+configuration file is always @code{/usr/local/etc/avrdude.conf}.
+
+@c
+@c Node
+@c
+@node Linux Configuration Files,  , FreeBSD Configuration Files, Unix Configuration Files
+@subsubsection Linux Configuration Files
+
+@noindent
+When AVRDUDE is installed using from an rpm package, the system
+configuration file will be always be @code{/etc/avrdude.conf}.
+
+@c
+@c Node
+@c
+@node Unix Port Names, Unix Documentation, Unix Configuration Files, Unix
+@subsection Unix Port Names
+
+@noindent
+The parallel and serial port device file names are system specific.
+The following table lists the default names for a given system.
+
+@multitable @columnfractions .30 .30 .30
+@item @strong{System}
+  @tab @strong{Default Parallel Port}
+  @tab @strong{Default Serial Port}
+@item FreeBSD
+  @tab @code{/dev/ppi0}
+  @tab @code{/dev/cuaa0}
+@item Linux
+  @tab @code{/dev/parport0}
+  @tab @code{/dev/ttyS0}
+@item Solaris
+  @tab @code{/dev/printers/0}
+  @tab @code{/dev/term/a}
+@end multitable
+
+On FreeBSD systems, AVRDUDE uses the ppi(4) interface for
+accessing the parallel port and the sio(4) driver for serial port
+access.
+
+On Linux systems, AVRDUDE uses the ppdev interface for
+accessing the parallel port and the tty driver for serial port
+access.
+
+On Solaris systems, AVRDUDE uses the ecpp(7D) driver for
+accessing the parallel port and the asy(7D) driver for serial port
+access.
+
+@c
+@c Node
+@c
+@node Unix Documentation,  , Unix Port Names, Unix
+@subsection Unix Documentation
+
+@noindent
+AVRDUDE installs a manual page as well as info, HTML and PDF
+documentation.  The manual page is installed in
+@code{/usr/local/man/man1} area, while the HTML and PDF documentation
+is installed in @code{/usr/local/share/doc/avrdude} directory.  The
+info manual is installed in @code{/usr/local/info/avrdude.info}.
+
+Note that these locations can be altered by various configure options
+such as @option{--prefix}.
+
+@c
+@c Node
+@c
+@node Windows,  , Unix, Platform Dependent Information
+@section Windows
+
+@menu
+* Windows Installation::        
+* Windows Configuration Files::  
+* Windows Port Names::          
+* Using the parallel port::     
+* Documentation::               
+* Credits.::                    
+@end menu
+
+@c
+@c Node
+@c
+@node Windows Installation, Windows Configuration Files, Windows, Windows
+@subsection Installation
+
+@noindent
+A Windows executable of avrdude is included in WinAVR which can be found at
+@url{http://sourceforge.net/projects/winavr}. WinAVR is a suite of executable, 
+open source software development tools for the AVR for the Windows platform.
+
+To build avrdude from the source You must have Cygwin (@url{http://www.cygwin.com/}).
+
+To build and install from the source tarball for Windows (using Cygwin):
+
+@example
+$ set PREFIX=<your install directory path>
+$ export PREFIX
+$ gunzip -c avrdude-@value{VERSION}.tar.gz | tar xf -
+$ cd avrdude-@value{VERSION}
+$ ./configure LDFLAGS="-static" --prefix=$PREFIX --datadir=$PREFIX 
+--sysconfdir=$PREFIX/bin --enable-versioned-doc=no
+$ make
+$ make install
+@end example
+
+
+@c
+@c Node
+@c
+@node Windows Configuration Files, Windows Port Names, Windows Installation, Windows
+@subsection Configuration Files
+
+@menu
+* Configuration file names::    
+* How AVRDUDE finds the configuration files.::  
+@end menu
+
+@c
+@c Node
+@c
+@node Configuration file names, How AVRDUDE finds the configuration files., Windows Configuration Files, Windows Configuration Files
+@subsubsection Configuration file names
+
+@noindent
+AVRDUDE on Windows looks for a system configuration file name of
+@code{avrdude.conf} and looks for a user override configuration file of
+@code{avrdude.rc}.
+
+@c
+@c Node
+@c
+@node How AVRDUDE finds the configuration files.,  , Configuration file names, Windows Configuration Files
+@subsubsection How AVRDUDE finds the configuration files.
+ 
+@noindent
+AVRDUDE on Windows has a different way of searching for the system and
+user configuration files. Below is the search method for locating the
+configuration files:
+
+@enumerate
+
+@item
+The directory from which the application loaded.
+
+@item
+The current directory.
+
+@item
+The Windows system directory. On Windows NT, the name of this directory
+is @code{SYSTEM32}.
+
+@item
+Windows NT: The 16-bit Windows system directory. The name of this
+directory is @code{SYSTEM}.
+
+@item
+The Windows directory.
+
+@item
+The directories that are listed in the PATH environment variable.
+
+@end enumerate
+
+
+@c
+@c Node
+@c
+@node Windows Port Names, Using the parallel port, Windows Configuration Files, Windows
+@subsection Port Names
+
+@menu
+* Serial Ports::                
+* Parallel Ports::              
+@end menu
+
+@c
+@c Node
+@c
+@node Serial Ports, Parallel Ports, Windows Port Names, Windows Port Names
+@subsubsection Serial Ports
+ 
+@noindent
+When you select a serial port (i.e. when using an STK500) use the
+Windows serial port device names such as: com1, com2, etc.
+ 
+@c
+@c Node
+@c
+@node Parallel Ports,  , Serial Ports, Windows Port Names
+@subsubsection Parallel Ports
+
+@noindent
+AVRDUDE will accept 3 Windows parallel port names: lpt1, lpt2, or
+lpt3.  Each of these names corresponds to a fixed parallel port base
+address:
+
+@table @code
+@item lpt1
+0x378
+
+@item lpt2
+0x278
+
+@item lpt3
+0x3BC
+
+@end table
+
+On your desktop PC, lpt1 will be the most common choice. If you are
+using a laptop, you might have to use lpt3 instead of lpt1. Select the
+name of the port the corresponds to the base address of the parallel
+port that you want.
+
+If the parallel port can be accessed through a different
+address, this address can be specified directly, using the common C
+language notation (i. e., hexadecimal values are prefixed by @code{0x}).
+
+@c
+@c Node
+@c 
+@node Using the parallel port, Documentation, Windows Port Names, Windows
+@subsection Using the parallel port
+
+@menu
+* Windows NT/2K/XP::            
+* Windows 95/98::               
+@end menu
+
+@c
+@c Node
+@c
+@node Windows NT/2K/XP, Windows 95/98, Using the parallel port, Using the parallel port
+@subsubsection Windows NT/2K/XP
+
+@noindent
+On Windows NT, 2000, and XP user applications cannot directly access the
+parallel port. However, kernel mode drivers can access the parallel port.
+giveio.sys is a driver that can allow user applications to set the state
+of the parallel port pins.
+
+Before using AVRDUDE, the giveio.sys driver must be loaded. The
+accompanying command-line program, loaddrv.exe, can do just that.
+
+To make things even easier there are 3 batch files that are also
+included:
+
+@enumerate
+@item install_giveio.bat
+Install and start the giveio driver.
+
+@item status_giveio.bat
+Check on the status of the giveio driver.
+
+@item remove_giveio.bat
+Stop and remove the giveio driver from memory.
+@end enumerate
+
+These 3 batch files calls the loaddrv program with various options to
+install, start, stop, and remove the driver.
+
+When you first execute install_giveio.bat, loaddrv.exe and giveio.sys
+must be in the current directory. When install_giveio.bat is executed it
+will copy giveio.sys from your current directory to your Windows
+directory. It will then load the driver from the Windows directory. This
+means that after the first time install_giveio is executed, you should 
+be able to subsequently execute the batch file from any directory and have
+it successfully start the driver.
+
+Note that you must have administrator privilege to load the giveio driver.
+
+@c
+@c Node
+@c
+@node Windows 95/98,  , Windows NT/2K/XP, Using the parallel port
+@subsubsection Windows 95/98
+
+@noindent
+On Windows 95 and 98 the giveio.sys driver is not needed.
+
+
+@c
+@c Node
+@c
+@node Documentation, Credits., Using the parallel port, Windows
+@subsection Documentation
+
+@noindent
+AVRDUDE installs a manual page as well as info, HTML and PDF
+documentation.  The manual page is installed in
+@code{/usr/local/man/man1} area, while the HTML and PDF documentation
+is installed in @code{/usr/local/share/doc/avrdude} directory.  The
+info manual is installed in @code{/usr/local/info/avrdude.info}.
+
+Note that these locations can be altered by various configure options
+such as @option{--prefix} and @option{--datadir}.
+
+
+@c
+@c Node
+@c
+@node Credits.,  , Documentation, Windows
+@subsection Credits.
+
+@noindent
+Thanks to:
+
+@itemize @bullet
+@item
+Dale Roberts for the giveio driver.
+
+@item
+Paula Tomlinson for the loaddrv sources.
+
+@item
+Chris Liechti <cliechti@@gmx.net> for modifying loaddrv to be command
+line driven and for writing the batch files.
+
+@end itemize
+
+@c
+@c Node
+@c
+@node Troubleshooting, ,Platform Dependent Information ,Top
+@appendix Troubleshooting
+
+@noindent
+In general, please report any bugs encountered via
+@*
+@url{http://savannah.nongnu.org/bugs/?group=avrdude}.
+
+
+@itemize @bullet
+
+@item
+Problem: I'm using a serial programmer under Windows and get the following
+error:
+
+@code{avrdude: serial_open(): can't set attributes for device "com1"},
+
+Solution: This problem seems to appear with certain versions of Cygwin. Specifying
+@code{"/dev/com1"} instead of @code{"com1"} should help.
+
+
+@item
+Problem: I'm using Linux and my AVR910 programmer is really slow.
+
+Solution (short): @code{setserial @var{port} low_latency}
+
+Solution (long):
+There are two problems here. First, the system may wait some time before it
+passes data from the serial port to the program. Under Linux the following
+command works around this (you may need root privileges for this).
+
+@code{setserial @var{port} low_latency}
+
+Secondly, the serial interface chip may delay the interrupt for some time.
+This behaviour can be changed by setting the FIFO-threshold to one. Under Linux this
+can only be done by changing the kernel source in @code{drivers/char/serial.c}.
+Search the file for @code{UART_FCR_TRIGGER_8} and replace it with @code{UART_FCR_TRIGGER_1}. Note that overall performance might suffer if there
+is high throughput on serial lines. Also note that you are modifying the kernel at
+your own risk.
+
+
+@item
+Problem: I'm not using Linux and my AVR910 programmer is really slow.
+
+Solutions: The reasons for this are the same as above.
+If you know how to work around this on your OS, please let us know.
+
+@item
+Problem: Updating the flash ROM from terminal mode does not work with the
+JTAG ICEs.
+
+Solution: None at this time.  Currently, the JTAG ICE code cannot
+write to the flash ROM one byte at a time.
+
+@item
+Problem: Page-mode programming the EEPROM (using the -U option) does
+not erase EEPROM cells before writing, and thus cannot overwrite any
+previous value != 0xff.
+
+Solution: None.  This is an inherent feature of the way JTAG EEPROM
+programming works, and is documented that way in the Atmel AVR
+datasheets.
+In order to successfully program the EEPROM that way, a prior chip
+erase (with the EESAVE fuse unprogrammed) is required.
+This also applies to the STK500 and STK600 in high-voltage programming mode.
+
+@item
+Problem: How do I turn off the @var{DWEN} fuse?
+
+Solution: If the @var{DWEN} (debugWire enable) fuse is activated,
+the @var{/RESET} pin is not functional anymore, so normal ISP
+communication cannot be established.
+There are two options to deactivate that fuse again: high-voltage
+programming, or getting the JTAG ICE mkII talk debugWire, and
+prepare the target AVR to accept normal ISP communication again.
+
+The first option requires a programmer that is capable of high-voltage
+programming (either serial or parallel, depending on the AVR device),
+for example the STK500.  In high-voltage programming mode, the
+@var{/RESET} pin is activated initially using a 12 V pulse (thus the
+name @emph{high voltage}), so the target AVR can subsequently be
+reprogrammed, and the @var{DWEN} fuse can be cleared.  Typically, this
+operation cannot be performed while the AVR is located in the target
+circuit though.
+
+The second option requires a JTAG ICE mkII that can talk the debugWire
+protocol.  The ICE needs to be connected to the target using the
+JTAG-to-ISP adapter, so the JTAG ICE mkII can be used as a debugWire
+initiator as well as an ISP programmer.  AVRDUDE will then be activated
+using the @var{jtag2isp} programmer type.  The initial ISP
+communication attempt will fail, but AVRDUDE then tries to initiate a
+debugWire reset.  When successful, this will leave the target AVR in a
+state where it can accept standard ISP communication.  The ICE is then
+signed off (which will make it signing off from the USB as well), so
+AVRDUDE has to be called again afterwards.  This time, standard ISP
+communication can work, so the @var{DWEN} fuse can be cleared.
+
+The pin mapping for the JTAG-to-ISP adapter is:
+
+@multitable @columnfractions .2 .2
+@item @strong{JTAG pin} @tab @strong{ISP pin}
+@item 1 @tab 3
+@item 2 @tab 6
+@item 3 @tab 1
+@item 4 @tab 2
+@item 6 @tab 5
+@item 9 @tab 4
+@end multitable
+
+@item
+Problem: Multiple USBasp or USBtinyISP programmers connected simultaneously are not
+found.
+
+Solution: none at this time.  The simplicity of these programmers
+doesn't offer a method to distinguish multiple programmers that are
+connected simultaneously, so effectively only one of them is supported.
+
+@item
+Problem: I cannot do @dots{} when the target is in debugWire mode.
+
+Solution: debugWire mode imposes several limitations.
+
+The debugWire protocol is Atmel's proprietary one-wire (plus ground)
+protocol to allow an in-circuit emulation of the smaller AVR devices,
+using the @var{/RESET} line.
+DebugWire mode is initiated by activating the @var{DWEN}
+fuse, and then power-cycling the target.
+While this mode is mainly intended for debugging/emulation, it
+also offers limited programming capabilities.
+Effectively, the only memory areas that can be read or programmed
+in this mode are flash ROM and EEPROM.
+It is also possible to read out the signature.
+All other memory areas cannot be accessed.
+There is no
+@emph{chip erase}
+functionality in debugWire mode; instead, while reprogramming the
+flash ROM, each flash ROM page is erased right before updating it.
+This is done transparently by the JTAG ICE mkII (or AVR Dragon).
+The only way back from debugWire mode is to initiate a special
+sequence of commands to the JTAG ICE mkII (or AVR Dragon), so the
+debugWire mode will be temporarily disabled, and the target can
+be accessed using normal ISP programming.
+This sequence is automatically initiated by using the JTAG ICE mkII
+or AVR Dragon in ISP mode, when they detect that ISP mode cannot be
+entered.
+
+@item
+Problem: I want to use my JTAG ICE mkII or AVR Dragon to program an
+Xmega device through PDI.  The documentation tells me to use the
+@emph{XMEGA PDI adapter for JTAGICE mkII} that is supposed to ship
+with the kit, yet I don't have it.
+
+Solution: Use the following pin mapping:
+
+@multitable @columnfractions .2 .2 .2 .2
+@item @strong{JTAGICE} @tab @strong{Target} @tab @strong{Squid cab-} @tab @strong{PDI}
+@item @strong{mkII probe} @tab @strong{pins} @tab @strong{le colors} @tab @strong{header}
+@item 1 (TCK)   @tab         @tab Black  @tab
+@item 2 (GND)   @tab GND     @tab White  @tab 6
+@item 3 (TDO)   @tab         @tab Grey   @tab
+@item 4 (VTref) @tab VTref   @tab Purple @tab 2
+@item 5 (TMS)   @tab         @tab Blue   @tab
+@item 6 (nSRST) @tab PDI_CLK @tab Green  @tab 5
+@item 7 (N.C.)  @tab         @tab Yellow @tab
+@item 8 (nTRST) @tab         @tab Orange @tab
+@item 9 (TDI)   @tab PDI_DATA @tab Red   @tab 1
+@item 10 (GND)  @tab         @tab Brown  @tab
+@end multitable
+
+
+@item
+Problem: I want to use my AVRISP mkII to program an
+ATtiny4/5/9/10 device through TPI.  How to connect the pins?
+
+Solution: Use the following pin mapping:
+
+@multitable @columnfractions .2 .2 .2
+@item @strong{AVRISP} @tab @strong{Target} @tab @strong{ATtiny}
+@item @strong{connector} @tab @strong{pins} @tab @strong{pin #}
+@item 1 (MISO)  @tab TPIDATA  @tab 1
+@item 2 (VTref) @tab Vcc      @tab 5
+@item 3 (SCK)   @tab TPICLK   @tab 3
+@item 4 (MOSI)  @tab          @tab
+@item 5 (RESET) @tab /RESET   @tab 6
+@item 6 (GND)   @tab GND      @tab 2
+@end multitable
+
+@item
+Problem: My ATtiny4/5/9/10 reads out fine, but any attempt to program
+it (through TPI) fails.  Instead, the memory retains the old contents.
+
+Solution: Mind the limited programming supply voltage range of these
+devices.
+
+In-circuit programming through TPI is only guaranteed by the datasheet
+at Vcc = 5 V.
+
+@item
+Problem: My ATxmega@dots{}A1/A2/A3 cannot be programmed through PDI with
+my AVR Dragon.  Programming through a JTAG ICE mkII works though, as does
+programming through JTAG.
+
+Solution: None by this time (2010 Q1).
+
+It is said that the AVR Dragon can only program devices from the A4
+Xmega sub-family.
+
+@end itemize
+
+
+
+@bye
+
diff --git a/avrdude/fileio.c b/avrdude/fileio.c
new file mode 100644
index 00000000..421de457
--- /dev/null
+++ b/avrdude/fileio.c
@@ -0,0 +1,1160 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2000-2004  Brian S. Dean <bsd@bsdhome.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id$ */
+
+#include "ac_cfg.h"
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "avrdude.h"
+#include "avr.h"
+#include "fileio.h"
+
+
+#define IHEX_MAXDATA 256
+
+#define MAX_LINE_LEN 256  /* max line length for ASCII format input files */
+
+
+struct ihexrec {
+  unsigned char    reclen;
+  unsigned int     loadofs;
+  unsigned char    rectyp;
+  unsigned char    data[IHEX_MAXDATA];
+  unsigned char    cksum;
+};
+
+
+static int b2ihex(unsigned char * inbuf, int bufsize, 
+             int recsize, int startaddr,
+             char * outfile, FILE * outf);
+
+static int ihex2b(char * infile, FILE * inf,
+             unsigned char * outbuf, int bufsize);
+
+static int b2srec(unsigned char * inbuf, int bufsize, 
+           int recsize, int startaddr,
+           char * outfile, FILE * outf);
+
+static int srec2b(char * infile, FILE * inf,
+             unsigned char * outbuf, int bufsize);
+
+static int ihex_readrec(struct ihexrec * ihex, char * rec);
+
+static int srec_readrec(struct ihexrec * srec, char * rec);
+
+static int fileio_rbin(struct fioparms * fio,
+                  char * filename, FILE * f, unsigned char * buf, int size);
+
+static int fileio_ihex(struct fioparms * fio, 
+                  char * filename, FILE * f, unsigned char * buf, int size);
+
+static int fileio_srec(struct fioparms * fio,
+                  char * filename, FILE * f, unsigned char * buf, int size);
+
+static int fileio_num(struct fioparms * fio,
+		char * filename, FILE * f, unsigned char * buf, int size,
+		FILEFMT fmt);
+
+static int fmt_autodetect(char * fname);
+
+
+
+char * fmtstr(FILEFMT format)
+{
+  switch (format) {
+    case FMT_AUTO : return "auto-detect"; break;
+    case FMT_SREC : return "Motorola S-Record"; break;
+    case FMT_IHEX : return "Intel Hex"; break;
+    case FMT_RBIN : return "raw binary"; break;
+    default       : return "invalid format"; break;
+  };
+}
+
+
+
+static int b2ihex(unsigned char * inbuf, int bufsize, 
+           int recsize, int startaddr,
+           char * outfile, FILE * outf)
+{
+  unsigned char * buf;
+  unsigned int nextaddr;
+  int n, nbytes, n_64k;
+  int i;
+  unsigned char cksum;
+
+  if (recsize > 255) {
+    fprintf(stderr, "%s: recsize=%d, must be < 256\n",
+              progname, recsize);
+    return -1;
+  }
+
+  n_64k    = 0;
+  nextaddr = startaddr;
+  buf      = inbuf;
+  nbytes   = 0;
+
+  while (bufsize) {
+    n = recsize;
+    if (n > bufsize)
+      n = bufsize;
+
+    if ((nextaddr + n) > 0x10000)
+      n = 0x10000 - nextaddr;
+
+    if (n) {
+      cksum = 0;
+      fprintf(outf, ":%02X%04X00", n, nextaddr);
+      cksum += n + ((nextaddr >> 8) & 0x0ff) + (nextaddr & 0x0ff);
+      for (i=0; i<n; i++) {
+        fprintf(outf, "%02X", buf[i]);
+        cksum += buf[i];
+      }
+      cksum = -cksum;
+      fprintf(outf, "%02X\n", cksum);
+      
+      nextaddr += n;
+      nbytes   += n;
+    }
+
+    if (nextaddr >= 0x10000) {
+      int lo, hi;
+      /* output an extended address record */
+      n_64k++;
+      lo = n_64k & 0xff;
+      hi = (n_64k >> 8) & 0xff;
+      cksum = 0;
+      fprintf(outf, ":02000004%02X%02X", hi, lo);
+      cksum += 2 + 0 + 4 + hi + lo;
+      cksum = -cksum;
+      fprintf(outf, "%02X\n", cksum);
+      nextaddr = 0;
+    }
+
+    /* advance to next 'recsize' bytes */
+    buf += n;
+    bufsize -= n;
+  }
+
+  /*-----------------------------------------------------------------
+    add the end of record data line
+    -----------------------------------------------------------------*/
+  cksum = 0;
+  n = 0;
+  nextaddr = 0;
+  fprintf(outf, ":%02X%04X01", n, nextaddr);
+  cksum += n + ((nextaddr >> 8) & 0x0ff) + (nextaddr & 0x0ff) + 1;
+  cksum = -cksum;
+  fprintf(outf, "%02X\n", cksum);
+
+  return nbytes;
+}
+
+
+static int ihex_readrec(struct ihexrec * ihex, char * rec)
+{
+  int i, j;
+  char buf[8];
+  int offset, len;
+  char * e;
+  unsigned char cksum;
+  int rc;
+
+  len    = strlen(rec);
+  offset = 1;
+  cksum  = 0;
+
+  /* reclen */
+  if (offset + 2 > len)
+    return -1;
+  for (i=0; i<2; i++)
+    buf[i] = rec[offset++];
+  buf[i] = 0;
+  ihex->reclen = strtoul(buf, &e, 16);
+  if (e == buf || *e != 0)
+    return -1;
+
+  /* load offset */
+  if (offset + 4 > len)
+    return -1;
+  for (i=0; i<4; i++)
+    buf[i] = rec[offset++];
+  buf[i] = 0;
+  ihex->loadofs = strtoul(buf, &e, 16);
+  if (e == buf || *e != 0)
+    return -1;
+
+  /* record type */
+  if (offset + 2 > len)
+    return -1;
+  for (i=0; i<2; i++)
+    buf[i] = rec[offset++];
+  buf[i] = 0;
+  ihex->rectyp = strtoul(buf, &e, 16);
+  if (e == buf || *e != 0)
+    return -1;
+
+  cksum = ihex->reclen + ((ihex->loadofs >> 8) & 0x0ff) + 
+    (ihex->loadofs & 0x0ff) + ihex->rectyp;
+
+  /* data */
+  for (j=0; j<ihex->reclen; j++) {
+    if (offset + 2 > len)
+      return -1;
+    for (i=0; i<2; i++)
+      buf[i] = rec[offset++];
+    buf[i] = 0;
+    ihex->data[j] = strtoul(buf, &e, 16);
+    if (e == buf || *e != 0)
+      return -1;
+    cksum += ihex->data[j];
+  }
+
+  /* cksum */
+  if (offset + 2 > len)
+    return -1;
+  for (i=0; i<2; i++)
+    buf[i] = rec[offset++];
+  buf[i] = 0;
+  ihex->cksum = strtoul(buf, &e, 16);
+  if (e == buf || *e != 0)
+    return -1;
+
+  rc = -cksum & 0x000000ff;
+
+  return rc;
+}
+
+
+
+/*
+ * Intel Hex to binary buffer
+ *
+ * Given an open file 'inf' which contains Intel Hex formated data,
+ * parse the file and lay it out within the memory buffer pointed to
+ * by outbuf.  The size of outbuf, 'bufsize' is honored; if data would
+ * fall outsize of the memory buffer outbuf, an error is generated.
+ *
+ * Return the maximum memory address within 'outbuf' that was written.
+ * If an error occurs, return -1.
+ *
+ * */
+static int ihex2b(char * infile, FILE * inf,
+             unsigned char * outbuf, int bufsize)
+{
+  char buffer [ MAX_LINE_LEN ];
+  unsigned char * buf;
+  unsigned int nextaddr, baseaddr, maxaddr, offsetaddr;
+  int i;
+  int lineno;
+  int len;
+  struct ihexrec ihex;
+  int rc;
+
+  lineno      = 0;
+  buf         = outbuf;
+  baseaddr    = 0;
+  maxaddr     = 0;
+  offsetaddr  = 0;
+  nextaddr    = 0;
+
+  while (fgets((char *)buffer,MAX_LINE_LEN,inf)!=NULL) {
+    lineno++;
+    len = strlen(buffer);
+    if (buffer[len-1] == '\n') 
+      buffer[--len] = 0;
+    if (buffer[0] != ':')
+      continue;
+    rc = ihex_readrec(&ihex, buffer);
+    if (rc < 0) {
+      fprintf(stderr, "%s: invalid record at line %d of \"%s\"\n",
+              progname, lineno, infile);
+      return -1;
+    }
+    else if (rc != ihex.cksum) {
+      fprintf(stderr, "%s: ERROR: checksum mismatch at line %d of \"%s\"\n",
+              progname, lineno, infile);
+      fprintf(stderr, "%s: checksum=0x%02x, computed checksum=0x%02x\n",
+              progname, ihex.cksum, rc);
+      return -1;
+    }
+
+    switch (ihex.rectyp) {
+      case 0: /* data record */
+        nextaddr = ihex.loadofs + baseaddr;
+        if ((nextaddr + ihex.reclen) > (bufsize+offsetaddr)) {
+          fprintf(stderr, 
+                  "%s: ERROR: address 0x%04x out of range at line %d of %s\n",
+                  progname, nextaddr+ihex.reclen, lineno, infile);
+          return -1;
+        }
+        for (i=0; i<ihex.reclen; i++) {
+          buf[nextaddr+i-offsetaddr] = ihex.data[i];
+        }
+        if (nextaddr+ihex.reclen > maxaddr)
+          maxaddr = nextaddr+ihex.reclen;
+        break;
+
+      case 1: /* end of file record */
+        return maxaddr-offsetaddr;
+        break;
+
+      case 2: /* extended segment address record */
+        // note: shift values use to be 8 and 4 - the first had to be wrong
+        baseaddr = (ihex.data[0] << 12 | ihex.data[1]) << 4;
+        break;
+
+      case 3: /* start segment address record */
+        /* we don't do anything with the start address */
+        break;
+
+      case 4: /* extended linear address record */
+        baseaddr = (ihex.data[0] << 24 | ihex.data[1]) << 16;
+        if(nextaddr == 0) offsetaddr = baseaddr;	// if provided before any data, then remember it
+        break;
+
+      case 5: /* start linear address record */
+        /* we don't do anything with the start address */
+        break;
+
+      default:
+        fprintf(stderr, 
+                "%s: don't know how to deal with rectype=%d " 
+                "at line %d of %s\n",
+                progname, ihex.rectyp, lineno, infile);
+        return -1;
+        break;
+    }
+
+  } /* while */
+
+  fprintf(stderr, 
+          "%s: WARNING: no end of file record found for Intel Hex "
+          "file \"%s\"\n",
+          progname, infile);
+
+  return maxaddr-offsetaddr;
+}
+
+static int b2srec(unsigned char * inbuf, int bufsize, 
+           int recsize, int startaddr,
+           char * outfile, FILE * outf)
+{
+  unsigned char * buf;
+  unsigned int nextaddr;
+  int n, nbytes, addr_width;
+  int i;
+  unsigned char cksum;
+
+  char * tmpl=0;
+
+  if (recsize > 255) {
+    fprintf(stderr, "%s: ERROR: recsize=%d, must be < 256\n",
+            progname, recsize);
+    return -1;
+  }
+  
+  nextaddr = startaddr;
+  buf = inbuf;
+  nbytes = 0;    
+
+  addr_width = 0;
+
+  while (bufsize) {
+
+    n = recsize;
+
+    if (n > bufsize) 
+      n = bufsize;
+
+    if (n) {
+      cksum = 0;
+      if (nextaddr + n <= 0xffff) {
+        addr_width = 2;
+        tmpl="S1%02X%04X";
+      }
+      else if (nextaddr + n <= 0xffffff) {
+        addr_width = 3;
+        tmpl="S2%02X%06X";
+      }
+      else if (nextaddr + n <= 0xffffffff) {
+        addr_width = 4;
+        tmpl="S3%02X%08X";
+      }
+      else {
+        fprintf(stderr, "%s: ERROR: address=%d, out of range\n",
+                progname, nextaddr);
+        return -1;
+      }
+
+      fprintf(outf, tmpl, n + addr_width + 1, nextaddr);		
+
+      cksum += n + addr_width + 1;
+
+      for (i=addr_width; i>0; i--) 
+        cksum += (nextaddr >> (i-1) * 8) & 0xff;
+
+      for (i=nextaddr; i<nextaddr + n; i++) {
+        fprintf(outf, "%02X", buf[i]);
+        cksum += buf[i];
+      }
+
+      cksum = 0xff - cksum;
+      fprintf(outf, "%02X\n", cksum);
+
+      nextaddr += n;
+      nbytes +=n;
+    }
+
+    /* advance to next 'recsize' bytes */
+    bufsize -= n;
+  }
+
+  /*-----------------------------------------------------------------
+    add the end of record data line
+    -----------------------------------------------------------------*/
+  cksum = 0;
+  n = 0;
+  nextaddr = 0;
+
+  if (startaddr <= 0xffff) {
+    addr_width = 2;
+    tmpl="S9%02X%04X";
+  }
+  else if (startaddr <= 0xffffff) {
+    addr_width = 3;
+    tmpl="S9%02X%06X";
+  }
+  else if (startaddr <= 0xffffffff) {
+    addr_width = 4;
+    tmpl="S9%02X%08X";
+  }
+
+  fprintf(outf, tmpl, n + addr_width + 1, nextaddr);
+
+  cksum += n + addr_width +1;
+  for (i=addr_width; i>0; i--) 
+    cksum += (nextaddr >> (i - 1) * 8) & 0xff;
+  cksum = 0xff - cksum;
+  fprintf(outf, "%02X\n", cksum);
+
+  return nbytes; 
+}
+
+
+static int srec_readrec(struct ihexrec * srec, char * rec)
+{
+  int i, j;
+  char buf[8];
+  int offset, len, addr_width;
+  char * e;
+  unsigned char cksum;
+  int rc;
+
+  len = strlen(rec);
+  offset = 1;
+  cksum = 0;
+  addr_width = 2;
+
+  /* record type */
+  if (offset + 1 > len) 
+    return -1;
+  srec->rectyp = rec[offset++];
+  if (srec->rectyp == 0x32 || srec->rectyp == 0x38) 
+    addr_width = 3;	/* S2,S8-record */
+  else if (srec->rectyp == 0x33 || srec->rectyp == 0x37) 
+    addr_width = 4;	/* S3,S7-record */
+
+  /* reclen */
+  if (offset + 2 > len) 
+    return -1;
+  for (i=0; i<2; i++) 
+    buf[i] = rec[offset++];
+  buf[i] = 0;
+  srec->reclen = strtoul(buf, &e, 16);
+  cksum += srec->reclen;
+  srec->reclen -= (addr_width+1);
+  if (e == buf || *e != 0) 
+    return -1;
+
+  /* load offset */
+  if (offset + addr_width > len) 
+    return -1;
+  for (i=0; i<addr_width*2; i++) 
+    buf[i] = rec[offset++];
+  buf[i] = 0;
+  srec->loadofs = strtoull(buf, &e, 16);
+  if (e == buf || *e != 0) 
+    return -1;
+
+  for (i=addr_width; i>0; i--)
+    cksum += (srec->loadofs >> (i - 1) * 8) & 0xff;
+
+  /* data */
+  for (j=0; j<srec->reclen; j++) {
+    if (offset+2  > len) 
+      return -1;
+    for (i=0; i<2; i++) 
+      buf[i] = rec[offset++];
+    buf[i] = 0;
+    srec->data[j] = strtoul(buf, &e, 16);
+    if (e == buf || *e != 0) 
+      return -1;
+    cksum += srec->data[j];
+  }
+
+  /* cksum */
+  if (offset + 2 > len) 
+    return -1;
+  for (i=0; i<2; i++) 
+    buf[i] = rec[offset++];
+  buf[i] = 0;
+  srec->cksum = strtoul(buf, &e, 16);
+  if (e == buf || *e != 0) 
+    return -1;
+
+  rc = 0xff - cksum;
+  return rc;
+}
+
+
+static int srec2b(char * infile, FILE * inf,
+           unsigned char * outbuf, int bufsize)
+{
+  char buffer [ MAX_LINE_LEN ];
+  unsigned char * buf;
+  unsigned int nextaddr, baseaddr, maxaddr;
+  int i;
+  int lineno;
+  int len;
+  struct ihexrec srec;
+  int rc;
+  int reccount;
+  unsigned char datarec;
+
+  char * msg = 0;
+
+  lineno   = 0;
+  buf      = outbuf;
+  baseaddr = 0;
+  maxaddr  = 0;
+  reccount = 0;
+
+  while (fgets((char *)buffer,MAX_LINE_LEN,inf)!=NULL) {
+    lineno++;
+    len = strlen(buffer);
+    if (buffer[len-1] == '\n') 
+      buffer[--len] = 0;
+    if (buffer[0] != 0x53)
+      continue;
+    rc = srec_readrec(&srec, buffer);
+
+    if (rc < 0) {
+      fprintf(stderr, "%s: ERROR: invalid record at line %d of \"%s\"\n",
+              progname, lineno, infile);
+      return -1;
+    }
+    else if (rc != srec.cksum) {
+      fprintf(stderr, "%s: ERROR: checksum mismatch at line %d of \"%s\"\n",
+              progname, lineno, infile);
+      fprintf(stderr, "%s: checksum=0x%02x, computed checksum=0x%02x\n",
+              progname, srec.cksum, rc);
+      return -1;
+    }
+
+    datarec=0;	
+    switch (srec.rectyp) {
+      case 0x30: /* S0 - header record*/
+        /* skip */
+        break;
+
+      case 0x31: /* S1 - 16 bit address data record */
+        datarec=1;
+        msg="%s: ERROR: address 0x%04x out of range at line %d of %s\n";    
+        break;
+
+      case 0x32: /* S2 - 24 bit address data record */
+        datarec=1;
+        msg="%s: ERROR: address 0x%06x out of range at line %d of %s\n";
+        break;
+
+      case 0x33: /* S3 - 32 bit address data record */
+        datarec=1;
+        msg="%s: ERROR: address 0x%08x out of range at line %d of %s\n";
+        break;
+
+      case 0x34: /* S4 - symbol record (LSI extension) */
+        fprintf(stderr, 
+                "%s: ERROR: not supported record at line %d of %s\n",
+                progname, lineno, infile);
+        return -1;
+
+      case 0x35: /* S5 - count of S1,S2 and S3 records previously tx'd */
+        if (srec.loadofs != reccount){
+          fprintf(stderr, 
+                  "%s: ERROR: count of transmitted data records mismatch "
+                  "at line %d of \"%s\"\n",
+                  progname, lineno, infile);
+          fprintf(stderr, "%s: transmitted data records= %d, expected "
+                  "value= %d\n",
+                  progname, reccount, srec.loadofs);
+          return -1;
+        }
+        break;
+
+      case 0x37: /* S7 Record - end record for 32 bit address data */
+      case 0x38: /* S8 Record - end record for 24 bit address data */
+      case 0x39: /* S9 Record - end record for 16 bit address data */
+        return maxaddr;
+
+      default:
+        fprintf(stderr, 
+                "%s: ERROR: don't know how to deal with rectype S%d " 
+                "at line %d of %s\n",
+                progname, srec.rectyp, lineno, infile);
+        return -1;
+    }
+
+    if (datarec == 1) {
+      nextaddr = srec.loadofs + baseaddr;
+      if (nextaddr + srec.reclen > bufsize) {
+        fprintf(stderr, msg, progname, nextaddr+srec.reclen, lineno, infile);
+        return -1;
+      }
+      for (i=0; i<srec.reclen; i++) 
+        buf[nextaddr+i] = srec.data[i];
+      if (nextaddr+srec.reclen > maxaddr)
+        maxaddr = nextaddr+srec.reclen;
+      reccount++;	
+    }
+
+  } 
+
+  fprintf(stderr, 
+          "%s: WARNING: no end of file record found for Motorola S-Records "
+          "file \"%s\"\n",
+          progname, infile);
+
+  return maxaddr;
+}
+
+/*
+ * Simple itoa() implementation.  Caller needs to allocate enough
+ * space in buf.  Only positive integers are handled.
+ */
+static char *itoa_simple(int n, char *buf, int base)
+{
+  div_t q;
+  char c, *cp, *cp2;
+
+  cp = buf;
+  /*
+   * Divide by base until the number disappeared, but ensure at least
+   * one digit will be emitted.
+   */
+  do {
+    q = div(n, base);
+    n = q.quot;
+    if (q.rem >= 10)
+      c = q.rem - 10 + 'a';
+    else
+      c = q.rem + '0';
+    *cp++ = c;
+  } while (q.quot != 0);
+
+  /* Terminate the string. */
+  *cp-- = '\0';
+
+  /* Now revert the result string. */
+  cp2 = buf;
+  while (cp > cp2) {
+    c = *cp;
+    *cp-- = *cp2;
+    *cp2++ = c;
+  }
+
+  return buf;
+}
+
+
+
+static int fileio_rbin(struct fioparms * fio,
+                  char * filename, FILE * f, unsigned char * buf, int size)
+{
+  int rc;
+
+  switch (fio->op) {
+    case FIO_READ:
+      rc = fread(buf, 1, size, f);
+      break;
+    case FIO_WRITE:
+      rc = fwrite(buf, 1, size, f);
+      break;
+    default:
+      fprintf(stderr, "%s: fileio: invalid operation=%d\n",
+              progname, fio->op);
+      return -1;
+  }
+
+  if (rc < 0 || (fio->op == FIO_WRITE && rc < size)) {
+    fprintf(stderr, 
+            "%s: %s error %s %s: %s; %s %d of the expected %d bytes\n", 
+            progname, fio->iodesc, fio->dir, filename, strerror(errno),
+            fio->rw, rc, size);
+    return -1;
+  }
+
+  return rc;
+}
+
+
+static int fileio_imm(struct fioparms * fio,
+               char * filename, FILE * f, unsigned char * buf, int size)
+{
+  int rc = 0;
+  char * e, * p;
+  unsigned long b;
+  int loc;
+
+  switch (fio->op) {
+    case FIO_READ:
+      loc = 0;
+      p = strtok(filename, " ,");
+      while (p != NULL && loc < size) {
+        b = strtoul(p, &e, 0);
+	/* check for binary formated (0b10101001) strings */
+	b = (strncmp (p, "0b", 2))?
+	    strtoul (p, &e, 0):
+	    strtoul (p + 2, &e, 2);
+        if (*e != 0) {
+          fprintf(stderr,
+                  "%s: invalid byte value (%s) specified for immediate mode\n",
+                  progname, p);
+          return -1;
+        }
+        buf[loc++] = b;
+        p = strtok(NULL, " ,");
+        rc = loc;
+      }
+      break;
+    default:
+      fprintf(stderr, "%s: fileio: invalid operation=%d\n",
+              progname, fio->op);
+      return -1;
+  }
+
+  if (rc < 0 || (fio->op == FIO_WRITE && rc < size)) {
+    fprintf(stderr, 
+            "%s: %s error %s %s: %s; %s %d of the expected %d bytes\n", 
+            progname, fio->iodesc, fio->dir, filename, strerror(errno),
+            fio->rw, rc, size);
+    return -1;
+  }
+
+  return rc;
+}
+
+
+static int fileio_ihex(struct fioparms * fio, 
+                  char * filename, FILE * f, unsigned char * buf, int size)
+{
+  int rc;
+
+  switch (fio->op) {
+    case FIO_WRITE:
+      rc = b2ihex(buf, size, 32, 0, filename, f);
+      if (rc < 0) {
+        return -1;
+      }
+      break;
+
+    case FIO_READ:
+      rc = ihex2b(filename, f, buf, size);
+      if (rc < 0)
+        return -1;
+      break;
+
+    default:
+      fprintf(stderr, "%s: invalid Intex Hex file I/O operation=%d\n",
+              progname, fio->op);
+      return -1;
+      break;
+  }
+
+  return rc;
+}
+
+
+static int fileio_srec(struct fioparms * fio,
+                  char * filename, FILE * f, unsigned char * buf, int size)
+{
+  int rc;
+
+  switch (fio->op) {
+    case FIO_WRITE:
+      rc = b2srec(buf, size, 32, 0, filename, f);
+      if (rc < 0) {
+        return -1;
+      }
+      break;
+
+    case FIO_READ:
+      rc = srec2b(filename, f, buf, size);
+      if (rc < 0)
+        return -1;
+      break;
+
+    default:
+      fprintf(stderr, "%s: ERROR: invalid Motorola S-Records file I/O "
+              "operation=%d\n",
+              progname, fio->op);
+      return -1;
+      break;
+  }
+
+  return rc;
+}
+
+
+static int fileio_num(struct fioparms * fio,
+	       char * filename, FILE * f, unsigned char * buf, int size,
+	       FILEFMT fmt)
+{
+  const char *prefix;
+  char cbuf[20];
+  int base, i, num;
+
+  switch (fmt) {
+    case FMT_HEX:
+      prefix = "0x";
+      base = 16;
+      break;
+
+    default:
+    case FMT_DEC:
+      prefix = "";
+      base = 10;
+      break;
+
+    case FMT_OCT:
+      prefix = "0";
+      base = 8;
+      break;
+
+    case FMT_BIN:
+      prefix = "0b";
+      base = 2;
+      break;
+
+  }
+
+  switch (fio->op) {
+    case FIO_WRITE:
+      break;
+    default:
+      fprintf(stderr, "%s: fileio: invalid operation=%d\n",
+              progname, fio->op);
+      return -1;
+  }
+
+  for (i = 0; i < size; i++) {
+    if (i > 0) {
+      if (putc(',', f) == EOF)
+	goto writeerr;
+    }
+    num = (unsigned int)buf[i];
+    /*
+     * For a base of 8 and a value < 8 to convert, don't write the
+     * prefix.  The conversion will be indistinguishable from a
+     * decimal one then.
+     */
+    if (prefix[0] != '\0' && !(base == 8 && num < 8)) {
+      if (fputs(prefix, f) == EOF)
+	goto writeerr;
+    }
+    itoa_simple(num, cbuf, base);
+    if (fputs(cbuf, f) == EOF)
+      goto writeerr;
+  }
+  if (putc('\n', f) == EOF)
+    goto writeerr;
+
+  return 0;
+
+ writeerr:
+  fprintf(stderr, "%s: error writing to %s: %s\n",
+	  progname, filename, strerror(errno));
+  return -1;
+}
+
+
+int fileio_setparms(int op, struct fioparms * fp)
+{
+  fp->op = op;
+
+  switch (op) {
+    case FIO_READ:
+      fp->mode   = "r";
+      fp->iodesc = "input";
+      fp->dir    = "from";
+      fp->rw     = "read";
+      break;
+
+    case FIO_WRITE:
+      fp->mode   = "w";
+      fp->iodesc = "output";
+      fp->dir    = "to";
+      fp->rw     = "wrote";
+      break;
+
+    default:
+      fprintf(stderr, "%s: invalid I/O operation %d\n",
+              progname, op);
+      return -1;
+      break;
+  }
+
+  return 0;
+}
+
+
+
+static int fmt_autodetect(char * fname)
+{
+  FILE * f;
+  unsigned char buf[MAX_LINE_LEN];
+  int i;
+  int len;
+  int found;
+
+  f = fopen(fname, "r");
+  if (f == NULL) {
+    fprintf(stderr, "%s: error opening %s: %s\n",
+            progname, fname, strerror(errno));
+    return -1;
+  }
+
+  while (fgets((char *)buf, MAX_LINE_LEN, f)!=NULL) {
+    buf[MAX_LINE_LEN-1] = 0;
+    len = strlen((char *)buf);
+    if (buf[len-1] == '\n')
+      buf[--len] = 0;
+
+    /* check for binary data */
+    found = 0;
+    for (i=0; i<len; i++) {
+      if (buf[i] > 127) {
+        found = 1;
+        break;
+      }
+    }
+    if (found) {
+      fclose(f);
+      return FMT_RBIN;
+    }
+
+    /* check for lines that look like intel hex */
+    if ((buf[0] == ':') && (len >= 11)) {
+      found = 1;
+      for (i=1; i<len; i++) {
+        if (!isxdigit(buf[1])) {
+          found = 0;
+          break;
+        }
+      }
+      if (found) {
+        fclose(f);
+        return FMT_IHEX;
+      }
+    }
+
+    /* check for lines that look like motorola s-record */
+    if ((buf[0] == 'S') && (len >= 10) && isdigit(buf[1])) {
+      found = 1;
+      for (i=1; i<len; i++) {
+        if (!isxdigit(buf[1])) {
+          found = 0;
+          break;
+        }
+      }
+      if (found) {
+        fclose(f);
+        return FMT_SREC;
+      }
+    }
+  }
+
+  fclose(f);
+  return -1;
+}
+
+
+
+int fileio(int op, char * filename, FILEFMT format, 
+             struct avrpart * p, char * memtype, int size)
+{
+  int rc;
+  FILE * f;
+  char * fname;
+  unsigned char * buf;
+  struct fioparms fio;
+  AVRMEM * mem;
+  int using_stdio;
+
+  mem = avr_locate_mem(p, memtype);
+  if (mem == NULL) {
+    fprintf(stderr, 
+            "fileio(): memory type \"%s\" not configured for device \"%s\"\n",
+            memtype, p->desc);
+    return -1;
+  }
+
+  rc = fileio_setparms(op, &fio);
+  if (rc < 0)
+    return -1;
+
+#if defined(WIN32NATIVE)
+  /* Open Raw Binary format in binary mode on Windows.*/
+  if(format == FMT_RBIN)
+  {
+      if(fio.op == FIO_READ)
+      {
+          fio.mode = "rb";
+      }
+      if(fio.op == FIO_WRITE)
+      {
+          fio.mode = "wb";
+      }
+  }
+#endif
+
+  /* point at the requested memory buffer */
+  buf = mem->buf;
+  if (fio.op == FIO_READ)
+    size = mem->size;
+
+  if (fio.op == FIO_READ) {
+    /* 0xff fill unspecified memory */
+    memset(buf, 0xff, size);
+  }
+
+  using_stdio = 0;
+
+  if (strcmp(filename, "-")==0) {
+    if (fio.op == FIO_READ) {
+      fname = "<stdin>";
+      f = stdin;
+    }
+    else {
+      fname = "<stdout>";
+      f = stdout;
+    }
+    using_stdio = 1;
+  }
+  else {
+    fname = filename;
+    f = NULL;
+  }
+
+  if (format == FMT_AUTO) {
+    if (using_stdio) {
+      fprintf(stderr, 
+              "%s: can't auto detect file format when using stdin/out.\n"
+              "     Please specify a file format using the -f option and try again.\n", 
+              progname);
+      exit(1);
+    }
+
+    format = fmt_autodetect(fname);
+    if (format < 0) {
+      fprintf(stderr, 
+              "%s: can't determine file format for %s, specify explicitly\n",
+              progname, fname);
+      return -1;
+    }
+
+    if (quell_progress < 2) {
+      fprintf(stderr, "%s: %s file %s auto detected as %s\n", 
+              progname, fio.iodesc, fname, fmtstr(format));
+    }
+  }
+
+  if (format != FMT_IMM) {
+    if (!using_stdio) {
+      f = fopen(fname, fio.mode);
+      if (f == NULL) {
+        fprintf(stderr, "%s: can't open %s file %s: %s\n",
+                progname, fio.iodesc, fname, strerror(errno));
+        return -1;
+      }
+    }
+  }
+
+  switch (format) {
+    case FMT_IHEX:
+      rc = fileio_ihex(&fio, fname, f, buf, size);
+      break;
+
+    case FMT_SREC:
+      rc = fileio_srec(&fio, fname, f, buf, size);
+      break;
+
+    case FMT_RBIN:
+      rc = fileio_rbin(&fio, fname, f, buf, size);
+      break;
+
+    case FMT_IMM:
+      rc = fileio_imm(&fio, fname, f, buf, size);
+      break;
+
+    case FMT_HEX:
+    case FMT_DEC:
+    case FMT_OCT:
+    case FMT_BIN:
+      rc = fileio_num(&fio, fname, f, buf, size, format);
+      break;
+
+    default:
+      fprintf(stderr, "%s: invalid %s file format: %d\n",
+              progname, fio.iodesc, format);
+      return -1;
+  }
+
+  if (rc > 0) {
+    if ((op == FIO_READ) && (strcasecmp(mem->desc, "flash") == 0)) {
+      /*
+       * if we are reading flash, just mark the size as being the
+       * highest non-0xff byte
+       */
+      rc = avr_mem_hiaddr(mem);
+    }
+  }
+  if (format != FMT_IMM && !using_stdio) {
+    fclose(f);
+  }
+
+  return rc;
+}
+
diff --git a/avrdude/fileio.h b/avrdude/fileio.h
new file mode 100644
index 00000000..2fe3f209
--- /dev/null
+++ b/avrdude/fileio.h
@@ -0,0 +1,65 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2000-2004  Brian S. Dean <bsd@bsdhome.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id$ */
+
+#ifndef fileio_h
+#define fileio_h
+
+typedef enum {
+  FMT_AUTO,
+  FMT_SREC,
+  FMT_IHEX,
+  FMT_RBIN,
+  FMT_IMM,
+  FMT_HEX,
+  FMT_DEC,
+  FMT_OCT,
+  FMT_BIN
+} FILEFMT;
+
+struct fioparms {
+  int    op;
+  char * mode;
+  char * iodesc;
+  char * dir;
+  char * rw;
+};
+
+enum {
+  FIO_READ,
+  FIO_WRITE
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+char * fmtstr(FILEFMT format);
+
+int fileio_setparms(int op, struct fioparms * fp);
+
+int fileio(int op, char * filename, FILEFMT format,
+           struct avrpart * p, char * memtype, int size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/avrdude/freebsd_ppi.h b/avrdude/freebsd_ppi.h
new file mode 100644
index 00000000..0885fc43
--- /dev/null
+++ b/avrdude/freebsd_ppi.h
@@ -0,0 +1,40 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2005 Joerg Wunsch
+ *
+ * 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
+ */
+
+/* $Id$ */
+
+#ifndef freebsd_ppi_h
+#define freebsd_ppi_h
+
+#include <dev/ppbus/ppi.h>
+
+#define ppi_claim(fd) {}
+
+#define ppi_release(fd) {}
+
+#define DO_PPI_READ(fd, reg, valp) \
+	(void)ioctl(fd, \
+		(reg) == PPIDATA? PPIGDATA: ((reg) == PPICTRL? PPIGCTRL: PPIGSTATUS), \
+		    valp)
+#define DO_PPI_WRITE(fd, reg, valp) \
+	(void)ioctl(fd, \
+		(reg) == PPIDATA? PPISDATA: ((reg) == PPICTRL? PPISCTRL: PPISSTATUS), \
+		    valp)
+
+#endif /* freebsd_ppi_h */
diff --git a/avrdude/jtagmkI.c b/avrdude/jtagmkI.c
new file mode 100644
index 00000000..85f12811
--- /dev/null
+++ b/avrdude/jtagmkI.c
@@ -0,0 +1,1402 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2005, 2007 Joerg Wunsch <j@uriah.heep.sax.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 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
+ */
+
+/* $Id$ */
+
+/*
+ * avrdude interface for Atmel JTAG ICE (mkI) programmer
+ */
+
+#include "ac_cfg.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "avrdude.h"
+#include "avr.h"
+#include "crc16.h"
+#include "pgm.h"
+#include "jtagmkI_private.h"
+#include "serial.h"
+
+/*
+ * Private data for this programmer.
+ */
+struct pdata
+{
+  int initial_baudrate;
+
+  /*
+   * See jtagmkI_read_byte() for an explanation of the flash and
+   * EEPROM page caches.
+   */
+  unsigned char *flash_pagecache;
+  unsigned long flash_pageaddr;
+  unsigned int flash_pagesize;
+
+  unsigned char *eeprom_pagecache;
+  unsigned long eeprom_pageaddr;
+  unsigned int eeprom_pagesize;
+
+  int prog_enabled;	/* Cached value of PROGRAMMING status. */
+};
+
+#define PDATA(pgm) ((struct pdata *)(pgm->cookie))
+
+/*
+ * The OCDEN fuse is bit 7 of the high fuse (hfuse).  In order to
+ * perform memory operations on MTYPE_SPM and MTYPE_EEPROM, OCDEN
+ * needs to be programmed.
+ *
+ * OCDEN should probably rather be defined via the configuration, but
+ * if this ever changes to a different fuse byte for one MCU, quite
+ * some code here needs to be generalized anyway.
+ */
+#define OCDEN (1 << 7)
+
+/*
+ * Table of baud rates supported by the mkI ICE, accompanied by their
+ * internal parameter value.
+ *
+ * 19200 is the initial value of the ICE after powerup, and virtually
+ * all connections then switch to 115200.  As the table is also used
+ * to try connecting at startup, we keep these two entries on top to
+ * speedup the program start.
+ */
+const static struct {
+  long baud;
+  unsigned char val;
+} baudtab[] = {
+  {  19200L, 0xfa },
+  { 115200L, 0xff },
+  {   9600L, 0xf4 },
+  {  38400L, 0xfd },
+  {  57600L, 0xfe },
+/*  {  14400L, 0xf8 }, */ /* not supported by serial driver */
+};
+
+static int jtagmkI_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+			      unsigned long addr, unsigned char * value);
+static int jtagmkI_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+			       unsigned long addr, unsigned char data);
+static int jtagmkI_set_sck_period(PROGRAMMER * pgm, double v);
+static int jtagmkI_getparm(PROGRAMMER * pgm, unsigned char parm,
+			    unsigned char * value);
+static int jtagmkI_setparm(PROGRAMMER * pgm, unsigned char parm,
+			    unsigned char value);
+static void jtagmkI_print_parms1(PROGRAMMER * pgm, const char * p);
+
+static int jtagmkI_resync(PROGRAMMER *pgm, int maxtries, int signon);
+
+static void jtagmkI_setup(PROGRAMMER * pgm)
+{
+  if ((pgm->cookie = malloc(sizeof(struct pdata))) == 0) {
+    fprintf(stderr,
+	    "%s: jtagmkI_setup(): Out of memory allocating private data\n",
+	    progname);
+    exit(1);
+  }
+  memset(pgm->cookie, 0, sizeof(struct pdata));
+}
+
+static void jtagmkI_teardown(PROGRAMMER * pgm)
+{
+  free(pgm->cookie);
+}
+
+
+static void
+u32_to_b3(unsigned char *b, unsigned long l)
+{
+  b[2] = l & 0xff;
+  b[1] = (l >> 8) & 0xff;
+  b[0] = (l >> 16) & 0xff;
+}
+
+static void
+u16_to_b2(unsigned char *b, unsigned short l)
+{
+  b[0] = l & 0xff;
+  b[1] = (l >> 8) & 0xff;
+}
+
+static void jtagmkI_prmsg(PROGRAMMER * pgm, unsigned char * data, size_t len)
+{
+  int i;
+
+  if (verbose >= 4) {
+    fprintf(stderr, "Raw message:\n");
+
+    for (i = 0; i < len; i++) {
+      fprintf(stderr, "0x%02x ", data[i]);
+      if (i % 16 == 15)
+	putc('\n', stderr);
+      else
+	putchar(' ');
+    }
+    if (i % 16 != 0)
+      putc('\n', stderr);
+  }
+
+  switch (data[0]) {
+  case RESP_OK:
+    fprintf(stderr, "OK\n");
+    break;
+
+  case RESP_FAILED:
+    fprintf(stderr, "FAILED\n");
+    break;
+
+  case RESP_BREAK:
+    fprintf(stderr, "breakpoint hit\n");
+    break;
+
+  case RESP_INFO:
+    fprintf(stderr, "IDR dirty\n");
+    break;
+
+  case RESP_SYNC_ERROR:
+    fprintf(stderr, "Synchronization lost\n");
+    break;
+
+  case RESP_SLEEP:
+    fprintf(stderr, "sleep instruction hit\n");
+    break;
+
+  case RESP_POWER:
+    fprintf(stderr, "target power lost\n");
+
+  default:
+    fprintf(stderr, "unknown message 0x%02x\n", data[0]);
+  }
+
+  putc('\n', stderr);
+}
+
+
+static int jtagmkI_send(PROGRAMMER * pgm, unsigned char * data, size_t len)
+{
+  unsigned char *buf;
+
+  if (verbose >= 3)
+    fprintf(stderr, "\n%s: jtagmkI_send(): sending %u bytes\n",
+	    progname, (unsigned int)len);
+
+  if ((buf = malloc(len + 2)) == NULL)
+    {
+      fprintf(stderr, "%s: jtagmkI_send(): out of memory",
+	      progname);
+      exit(1);
+    }
+
+  memcpy(buf, data, len);
+  buf[len] = ' ';		/* "CRC" */
+  buf[len + 1] = ' ';		/* EOP */
+
+  if (serial_send(&pgm->fd, buf, len + 2) != 0) {
+    fprintf(stderr,
+	    "%s: jtagmkI_send(): failed to send command to serial port\n",
+	    progname);
+    exit(1);
+  }
+
+  free(buf);
+
+  return 0;
+}
+
+static void jtagmkI_recv(PROGRAMMER * pgm, unsigned char * buf, size_t len)
+{
+  if (serial_recv(&pgm->fd, buf, len) != 0) {
+    fprintf(stderr,
+	    "\n%s: jtagmkI_recv(): failed to send command to serial port\n",
+	    progname);
+    exit(1);
+  }
+  if (verbose >= 3) {
+    putc('\n', stderr);
+    jtagmkI_prmsg(pgm, buf, len);
+  }
+}
+
+
+static int jtagmkI_drain(PROGRAMMER * pgm, int display)
+{
+  return serial_drain(&pgm->fd, display);
+}
+
+
+static int jtagmkI_resync(PROGRAMMER * pgm, int maxtries, int signon)
+{
+  int tries;
+  unsigned char buf[4], resp[9];
+  long otimeout = serial_recv_timeout;
+
+  serial_recv_timeout = 200;
+
+  if (verbose >= 3)
+    fprintf(stderr, "%s: jtagmkI_resync()\n", progname);
+
+  jtagmkI_drain(pgm, 0);
+
+  for (tries = 0; tries < maxtries; tries++) {
+
+    /* Get the sign-on information. */
+    buf[0] = CMD_GET_SYNC;
+    if (verbose >= 2)
+      fprintf(stderr, "%s: jtagmkI_resync(): Sending sync command: ",
+	      progname);
+
+    if (serial_send(&pgm->fd, buf, 1) != 0) {
+      fprintf(stderr,
+	      "\n%s: jtagmkI_resync(): failed to send command to serial port\n",
+	      progname);
+      serial_recv_timeout = otimeout;
+      return -1;
+    }
+    if (serial_recv(&pgm->fd, resp, 1) == 0 && resp[0] == RESP_OK) {
+      if (verbose >= 2)
+	fprintf(stderr, "got RESP_OK\n");
+      break;
+    }
+
+    if (signon) {
+      /*
+       * The following is black magic, the idea has been taken from
+       * AVaRICE.
+       *
+       * Apparently, the ICE behaves differently right after a
+       * power-up vs. when reconnecting to an ICE that has already
+       * been worked with.  The undocumented 'E' command (or
+       * subcommand) occasionally helps in getting the connection into
+       * sync.
+       */
+      buf[0] = CMD_GET_SIGNON;
+      buf[1] = 'E';
+      buf[2] = ' ';
+      buf[3] = ' ';
+      if (verbose >= 2)
+	fprintf(stderr, "%s: jtagmkI_resync(): Sending sign-on command: ",
+		progname);
+
+      if (serial_send(&pgm->fd, buf, 4) != 0) {
+	fprintf(stderr,
+		"\n%s: jtagmkI_resync(): failed to send command to serial port\n",
+		progname);
+	serial_recv_timeout = otimeout;
+	return -1;
+      }
+      if (serial_recv(&pgm->fd, resp, 9) == 0 && resp[0] == RESP_OK) {
+	if (verbose >= 2)
+	  fprintf(stderr, "got RESP_OK\n");
+	break;
+      }
+    }
+  }
+  if (tries >= maxtries) {
+    if (verbose >= 2)
+      fprintf(stderr,
+	      "%s: jtagmkI_resync(): "
+	      "timeout/error communicating with programmer\n",
+	      progname);
+    serial_recv_timeout = otimeout;
+    return -1;
+  }
+
+  serial_recv_timeout = otimeout;
+  return 0;
+}
+
+static int jtagmkI_getsync(PROGRAMMER * pgm)
+{
+  unsigned char buf[1], resp[9];
+
+  if (jtagmkI_resync(pgm, 5, 1) < 0) {
+    jtagmkI_drain(pgm, 0);
+    return -1;
+  }
+
+  jtagmkI_drain(pgm, 0);
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkI_getsync(): Sending sign-on command: ",
+	    progname);
+
+  buf[0] = CMD_GET_SIGNON;
+  jtagmkI_send(pgm, buf, 1);
+  jtagmkI_recv(pgm, resp, 9);
+  if (verbose >= 2) {
+    resp[8] = '\0';
+    fprintf(stderr, "got %s\n", resp + 1);
+  }
+
+  return 0;
+}
+
+/*
+ * issue the 'chip erase' command to the AVR device
+ */
+static int jtagmkI_chip_erase(PROGRAMMER * pgm, AVRPART * p)
+{
+  unsigned char buf[1], resp[2];
+
+  buf[0] = CMD_CHIP_ERASE;
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkI_chip_erase(): Sending chip erase command: ",
+	    progname);
+  jtagmkI_send(pgm, buf, 1);
+  jtagmkI_recv(pgm, resp, 2);
+  if (resp[0] != RESP_OK) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkI_chip_erase(): "
+	    "timeout/error communicating with programmer (resp %c)\n",
+	    progname, resp[0]);
+    return -1;
+  } else {
+    if (verbose == 2)
+      fprintf(stderr, "OK\n");
+  }
+
+  pgm->initialize(pgm, p);
+
+  return 0;
+}
+
+static void jtagmkI_set_devdescr(PROGRAMMER * pgm, AVRPART * p)
+{
+  unsigned char resp[2];
+  LNODEID ln;
+  AVRMEM * m;
+  struct {
+    unsigned char cmd;
+    struct device_descriptor dd;
+  } sendbuf;
+
+  memset(&sendbuf, 0, sizeof sendbuf);
+  sendbuf.cmd = CMD_SET_DEVICE_DESCRIPTOR;
+  sendbuf.dd.ucSPMCRAddress = p->spmcr;
+  sendbuf.dd.ucRAMPZAddress = p->rampz;
+  sendbuf.dd.ucIDRAddress = p->idr;
+  for (ln = lfirst(p->mem); ln; ln = lnext(ln)) {
+    m = ldata(ln);
+    if (strcmp(m->desc, "flash") == 0) {
+      PDATA(pgm)->flash_pagesize = m->page_size;
+      u16_to_b2(sendbuf.dd.uiFlashPageSize, PDATA(pgm)->flash_pagesize);
+    } else if (strcmp(m->desc, "eeprom") == 0) {
+      sendbuf.dd.ucEepromPageSize = PDATA(pgm)->eeprom_pagesize = m->page_size;
+    }
+  }
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkI_set_devdescr(): "
+	    "Sending set device descriptor command: ",
+	    progname);
+  jtagmkI_send(pgm, (unsigned char *)&sendbuf, sizeof(sendbuf));
+
+  jtagmkI_recv(pgm, resp, 2);
+  if (resp[0] != RESP_OK) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkI_set_devdescr(): "
+	    "timeout/error communicating with programmer (resp %c)\n",
+	    progname, resp[0]);
+  } else {
+    if (verbose == 2)
+      fprintf(stderr, "OK\n");
+  }
+}
+
+/*
+ * Reset the target.
+ */
+static int jtagmkI_reset(PROGRAMMER * pgm)
+{
+  unsigned char buf[1], resp[2];
+
+  buf[0] = CMD_RESET;
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkI_reset(): Sending reset command: ",
+	    progname);
+  jtagmkI_send(pgm, buf, 1);
+
+  jtagmkI_recv(pgm, resp, 2);
+  if (resp[0] != RESP_OK) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkI_reset(): "
+	    "timeout/error communicating with programmer (resp %c)\n",
+	    progname, resp[0]);
+    return -1;
+  } else {
+    if (verbose == 2)
+      fprintf(stderr, "OK\n");
+  }
+
+  return 0;
+}
+
+static int jtagmkI_program_enable_dummy(PROGRAMMER * pgm, AVRPART * p)
+{
+
+  return 0;
+}
+
+static int jtagmkI_program_enable(PROGRAMMER * pgm)
+{
+  unsigned char buf[1], resp[2];
+
+  if (PDATA(pgm)->prog_enabled)
+    return 0;
+
+  buf[0] = CMD_ENTER_PROGMODE;
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkI_program_enable(): "
+	    "Sending enter progmode command: ",
+	    progname);
+  jtagmkI_send(pgm, buf, 1);
+
+  jtagmkI_recv(pgm, resp, 2);
+  if (resp[0] != RESP_OK) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkI_program_enable(): "
+	    "timeout/error communicating with programmer (resp %c)\n",
+	    progname, resp[0]);
+    return -1;
+  } else {
+    if (verbose == 2)
+      fprintf(stderr, "OK\n");
+  }
+
+  PDATA(pgm)->prog_enabled = 1;
+
+  return 0;
+}
+
+static int jtagmkI_program_disable(PROGRAMMER * pgm)
+{
+  unsigned char buf[1], resp[2];
+
+  if (!PDATA(pgm)->prog_enabled)
+    return 0;
+
+  if (pgm->fd.ifd != -1) {
+    buf[0] = CMD_LEAVE_PROGMODE;
+    if (verbose >= 2)
+      fprintf(stderr, "%s: jtagmkI_program_disable(): "
+              "Sending leave progmode command: ",
+              progname);
+    jtagmkI_send(pgm, buf, 1);
+
+    jtagmkI_recv(pgm, resp, 2);
+    if (resp[0] != RESP_OK) {
+      if (verbose >= 2)
+        putc('\n', stderr);
+      fprintf(stderr,
+              "%s: jtagmkI_program_disable(): "
+              "timeout/error communicating with programmer (resp %c)\n",
+              progname, resp[0]);
+      return -1;
+    } else {
+      if (verbose == 2)
+        fprintf(stderr, "OK\n");
+    }
+  }
+  PDATA(pgm)->prog_enabled = 0;
+
+  return 0;
+}
+
+static unsigned char jtagmkI_get_baud(long baud)
+{
+  int i;
+
+  for (i = 0; i < sizeof baudtab / sizeof baudtab[0]; i++)
+    if (baud == baudtab[i].baud)
+      return baudtab[i].val;
+
+  return 0;
+}
+
+/*
+ * initialize the AVR device and prepare it to accept commands
+ */
+static int jtagmkI_initialize(PROGRAMMER * pgm, AVRPART * p)
+{
+  AVRMEM hfuse;
+  unsigned char cmd[1], resp[5];
+  unsigned char b;
+
+  if (!(p->flags & AVRPART_HAS_JTAG)) {
+    fprintf(stderr, "%s: jtagmkI_initialize(): part %s has no JTAG interface\n",
+	    progname, p->desc);
+    return -1;
+  }
+
+  jtagmkI_drain(pgm, 0);
+
+  if ((serdev->flags & SERDEV_FL_CANSETSPEED) && PDATA(pgm)->initial_baudrate != pgm->baudrate) {
+    if ((b = jtagmkI_get_baud(pgm->baudrate)) == 0) {
+      fprintf(stderr, "%s: jtagmkI_initialize(): unsupported baudrate %d\n",
+              progname, pgm->baudrate);
+    } else {
+      if (verbose >= 2)
+        fprintf(stderr, "%s: jtagmkI_initialize(): "
+	      "trying to set baudrate to %d\n",
+                progname, pgm->baudrate);
+      if (jtagmkI_setparm(pgm, PARM_BITRATE, b) == 0) {
+        PDATA(pgm)->initial_baudrate = pgm->baudrate; /* don't adjust again later */
+        serial_setspeed(&pgm->fd, pgm->baudrate);
+      }
+    }
+  }
+
+  if (pgm->bitclock != 0.0) {
+    if (verbose >= 2)
+      fprintf(stderr, "%s: jtagmkI_initialize(): "
+	      "trying to set JTAG clock period to %.1f us\n",
+	      progname, pgm->bitclock);
+    if (jtagmkI_set_sck_period(pgm, pgm->bitclock) != 0)
+      return -1;
+  }
+
+  cmd[0] = CMD_STOP;
+  jtagmkI_send(pgm, cmd, 1);
+  jtagmkI_recv(pgm, resp, 5);
+  if (resp[0] != RESP_OK) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkI_initialize(): "
+	    "timeout/error communicating with programmer (resp %c)\n",
+	    progname, resp[0]);
+  } else {
+    if (verbose == 2)
+      fprintf(stderr, "OK\n");
+  }
+
+  /*
+   * Must set the device descriptor before entering programming mode.
+   */
+  jtagmkI_set_devdescr(pgm, p);
+
+  jtagmkI_setparm(pgm, PARM_FLASH_PAGESIZE_LOW, PDATA(pgm)->flash_pagesize & 0xff);
+  jtagmkI_setparm(pgm, PARM_FLASH_PAGESIZE_HIGH, PDATA(pgm)->flash_pagesize >> 8);
+  jtagmkI_setparm(pgm, PARM_EEPROM_PAGESIZE, PDATA(pgm)->eeprom_pagesize & 0xff);
+
+  free(PDATA(pgm)->flash_pagecache);
+  free(PDATA(pgm)->eeprom_pagecache);
+  if ((PDATA(pgm)->flash_pagecache = malloc(PDATA(pgm)->flash_pagesize)) == NULL) {
+    fprintf(stderr, "%s: jtagmkI_initialize(): Out of memory\n",
+	    progname);
+    return -1;
+  }
+  if ((PDATA(pgm)->eeprom_pagecache = malloc(PDATA(pgm)->eeprom_pagesize)) == NULL) {
+    fprintf(stderr, "%s: jtagmkI_initialize(): Out of memory\n",
+	    progname);
+    free(PDATA(pgm)->flash_pagecache);
+    return -1;
+  }
+  PDATA(pgm)->flash_pageaddr = PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L;
+
+  if (jtagmkI_reset(pgm) < 0)
+    return -1;
+
+  strcpy(hfuse.desc, "hfuse");
+  if (jtagmkI_read_byte(pgm, p, &hfuse, 1, &b) < 0)
+    return -1;
+  if ((b & OCDEN) != 0)
+    fprintf(stderr,
+	    "%s: jtagmkI_initialize(): warning: OCDEN fuse not programmed, "
+	    "single-byte EEPROM updates not possible\n",
+	    progname);
+
+  return 0;
+}
+
+
+static void jtagmkI_disable(PROGRAMMER * pgm)
+{
+
+  free(PDATA(pgm)->flash_pagecache);
+  PDATA(pgm)->flash_pagecache = NULL;
+  free(PDATA(pgm)->eeprom_pagecache);
+  PDATA(pgm)->eeprom_pagecache = NULL;
+
+  (void)jtagmkI_program_disable(pgm);
+}
+
+static void jtagmkI_enable(PROGRAMMER * pgm)
+{
+  return;
+}
+
+
+static int jtagmkI_open(PROGRAMMER * pgm, char * port)
+{
+  size_t i;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkI_open()\n", progname);
+
+  strcpy(pgm->port, port);
+  PDATA(pgm)->initial_baudrate = -1L;
+
+  for (i = 0; i < sizeof(baudtab) / sizeof(baudtab[0]); i++) {
+    if (verbose >= 2)
+      fprintf(stderr,
+              "%s: jtagmkI_open(): trying to sync at baud rate %ld:\n",
+              progname, baudtab[i].baud);
+    serial_open(port, baudtab[i].baud, &pgm->fd);
+
+    /*
+     * drain any extraneous input
+     */
+    jtagmkI_drain(pgm, 0);
+
+    if (jtagmkI_getsync(pgm) == 0) {
+      PDATA(pgm)->initial_baudrate = baudtab[i].baud;
+      if (verbose >= 2)
+        fprintf(stderr, "%s: jtagmkI_open(): succeeded\n", progname);
+      return 0;
+    }
+
+    serial_close(&pgm->fd);
+  }
+
+  fprintf(stderr,
+          "%s: jtagmkI_open(): failed to synchronize to ICE\n",
+          progname);
+  pgm->fd.ifd = -1;
+
+  return -1;
+}
+
+
+static void jtagmkI_close(PROGRAMMER * pgm)
+{
+  unsigned char b;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkI_close()\n", progname);
+
+  /*
+   * Revert baud rate to what it used to be when we started.  This
+   * appears to make AVR Studio happier when it is about to access the
+   * ICE later on.
+   */
+  if ((serdev->flags & SERDEV_FL_CANSETSPEED) && PDATA(pgm)->initial_baudrate != pgm->baudrate) {
+    if ((b = jtagmkI_get_baud(PDATA(pgm)->initial_baudrate)) == 0) {
+      fprintf(stderr, "%s: jtagmkI_close(): unsupported baudrate %d\n",
+              progname, PDATA(pgm)->initial_baudrate);
+    } else {
+      if (verbose >= 2)
+        fprintf(stderr, "%s: jtagmkI_close(): "
+                "trying to set baudrate to %d\n",
+                progname, PDATA(pgm)->initial_baudrate);
+      if (jtagmkI_setparm(pgm, PARM_BITRATE, b) == 0) {
+        serial_setspeed(&pgm->fd, pgm->baudrate);
+      }
+    }
+  }
+
+  if (pgm->fd.ifd != -1) {
+    serial_close(&pgm->fd);
+  }
+
+  pgm->fd.ifd = -1;
+}
+
+
+static int jtagmkI_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+				int page_size, int n_bytes)
+{
+  int addr, block_size, send_size, tries;
+  unsigned char cmd[6], *datacmd;
+  unsigned char resp[2];
+  int is_flash = 0;
+  long otimeout = serial_recv_timeout;
+#define MAXTRIES 3
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkI_paged_write(.., %s, %d, %d)\n",
+	    progname, m->desc, page_size, n_bytes);
+
+  if (jtagmkI_program_enable(pgm) < 0)
+    return -1;
+
+  if (page_size == 0) page_size = 256;
+
+  if (page_size > 256) {
+    fprintf(stderr, "%s: jtagmkI_paged_write(): page size %d too large\n",
+	    progname, page_size);
+    return -1;
+  }
+
+  if ((datacmd = malloc(page_size + 1)) == NULL) {
+    fprintf(stderr, "%s: jtagmkI_paged_write(): Out of memory\n",
+	    progname);
+    return -1;
+  }
+
+  cmd[0] = CMD_WRITE_MEM;
+  if (strcmp(m->desc, "flash") == 0) {
+    cmd[1] = MTYPE_FLASH_PAGE;
+    PDATA(pgm)->flash_pageaddr = (unsigned long)-1L;
+    page_size = PDATA(pgm)->flash_pagesize;
+    is_flash = 1;
+  } else if (strcmp(m->desc, "eeprom") == 0) {
+    cmd[1] = MTYPE_EEPROM_PAGE;
+    PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L;
+    page_size = PDATA(pgm)->eeprom_pagesize;
+  }
+  datacmd[0] = CMD_DATA;
+
+  serial_recv_timeout = 1000;
+  for (addr = 0; addr < n_bytes; addr += page_size) {
+    report_progress(addr, n_bytes,NULL);
+
+    tries = 0;
+    again:
+
+    if (tries != 0 && jtagmkI_resync(pgm, 2000, 0) < 0) {
+      fprintf(stderr,
+	      "%s: jtagmkI_paged_write(): sync loss, retries exhausted\n",
+	      progname);
+      return -1;
+    }
+
+    if ((n_bytes-addr) < page_size)
+      block_size = n_bytes - addr;
+    else
+      block_size = page_size;
+    if (verbose >= 3)
+      fprintf(stderr, "%s: jtagmkI_paged_write(): "
+	      "block_size at addr %d is %d\n",
+	      progname, addr, block_size);
+
+    /* We always write full pages. */
+    send_size = page_size;
+    if (is_flash) {
+      cmd[2] = send_size / 2 - 1;
+      u32_to_b3(cmd + 3, addr / 2);
+    } else {
+      cmd[2] = send_size - 1;
+      u32_to_b3(cmd + 3, addr);
+    }
+
+    if (verbose >= 2)
+      fprintf(stderr, "%s: jtagmkI_paged_write(): "
+	      "Sending write memory command: ",
+	      progname);
+
+    /* First part, send the write command. */
+    jtagmkI_send(pgm, cmd, 6);
+    jtagmkI_recv(pgm, resp, 1);
+    if (resp[0] != RESP_OK) {
+      if (verbose >= 2)
+        putc('\n', stderr);
+      fprintf(stderr,
+              "%s: jtagmkI_paged_write(): "
+              "timeout/error communicating with programmer (resp %c)\n",
+              progname, resp[0]);
+      if (tries++ < MAXTRIES)
+	goto again;
+      serial_recv_timeout = otimeout;
+      return -1;
+    } else {
+      if (verbose == 2)
+        fprintf(stderr, "OK\n");
+    }
+
+    /*
+     * The JTAG ICE will refuse to write anything but a full page, at
+     * least for the flash ROM.  If a partial page has been requested,
+     * set the remainder to 0xff.  (Maybe we should rather read back
+     * the existing contents instead before?  Doesn't matter much, as
+     * bits cannot be written to 1 anyway.)
+     */
+    memset(datacmd + 1, 0xff, page_size);
+    memcpy(datacmd + 1, m->buf + addr, block_size);
+
+    /* Second, send the data command. */
+    jtagmkI_send(pgm, datacmd, send_size + 1);
+    jtagmkI_recv(pgm, resp, 2);
+    if (resp[1] != RESP_OK) {
+      if (verbose >= 2)
+        putc('\n', stderr);
+      fprintf(stderr,
+              "%s: jtagmkI_paged_write(): "
+              "timeout/error communicating with programmer (resp %c)\n",
+              progname, resp[0]);
+      if (tries++ < MAXTRIES)
+	goto again;
+      serial_recv_timeout = otimeout;
+      return -1;
+    } else {
+      if (verbose == 2)
+        fprintf(stderr, "OK\n");
+    }
+  }
+
+  free(datacmd);
+  serial_recv_timeout = otimeout;
+
+#undef MAXTRIES
+  return n_bytes;
+}
+
+static int jtagmkI_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+			       int page_size, int n_bytes)
+{
+  int addr, block_size, read_size, is_flash = 0, tries;
+  unsigned char cmd[6], resp[256 * 2 + 3];
+  long otimeout = serial_recv_timeout;
+#define MAXTRIES 3
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkI_paged_load(.., %s, %d, %d)\n",
+	    progname, m->desc, page_size, n_bytes);
+
+  if (jtagmkI_program_enable(pgm) < 0)
+    return -1;
+
+  page_size = m->readsize;
+
+  cmd[0] = CMD_READ_MEM;
+  if (strcmp(m->desc, "flash") == 0) {
+    cmd[1] = MTYPE_FLASH_PAGE;
+    is_flash = 1;
+  } else if (strcmp(m->desc, "eeprom") == 0) {
+    cmd[1] = MTYPE_EEPROM_PAGE;
+  }
+
+  if (page_size > (is_flash? 512: 256)) {
+    fprintf(stderr, "%s: jtagmkI_paged_load(): page size %d too large\n",
+	    progname, page_size);
+    return -1;
+  }
+
+  serial_recv_timeout = 1000;
+  for (addr = 0; addr < n_bytes; addr += page_size) {
+    report_progress(addr, n_bytes,NULL);
+
+    tries = 0;
+    again:
+    if (tries != 0 && jtagmkI_resync(pgm, 2000, 0) < 0) {
+      fprintf(stderr,
+	      "%s: jtagmkI_paged_load(): sync loss, retries exhausted\n",
+	      progname);
+      return -1;
+    }
+
+    if ((n_bytes-addr) < page_size)
+      block_size = n_bytes - addr;
+    else
+      block_size = page_size;
+    if (verbose >= 3)
+      fprintf(stderr, "%s: jtagmkI_paged_load(): "
+	      "block_size at addr %d is %d\n",
+	      progname, addr, block_size);
+
+    if (is_flash) {
+      read_size = 2 * ((block_size + 1) / 2); /* round up */
+      cmd[2] = read_size / 2 - 1;
+      u32_to_b3(cmd + 3, addr / 2);
+    } else {
+      read_size = page_size;
+      cmd[2] = page_size - 1;
+      u32_to_b3(cmd + 3, addr);
+    }
+
+    if (verbose >= 2)
+      fprintf(stderr, "%s: jtagmkI_paged_load(): Sending read memory command: ",
+	      progname);
+
+    jtagmkI_send(pgm, cmd, 6);
+    jtagmkI_recv(pgm, resp, read_size + 3);
+
+    if (resp[read_size + 3 - 1] != RESP_OK) {
+      if (verbose >= 2)
+        putc('\n', stderr);
+      fprintf(stderr,
+              "%s: jtagmkI_paged_load(): "
+              "timeout/error communicating with programmer (resp %c)\n",
+              progname, resp[read_size + 3 - 1]);
+      if (tries++ < MAXTRIES)
+	goto again;
+
+      serial_recv_timeout = otimeout;
+      return -1;
+    } else {
+      if (verbose == 2)
+        fprintf(stderr, "OK\n");
+    }
+
+    memcpy(m->buf + addr, resp + 1, block_size);
+  }
+  serial_recv_timeout = otimeout;
+
+#undef MAXTRIES
+  return n_bytes;
+}
+
+static int jtagmkI_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+			      unsigned long addr, unsigned char * value)
+{
+  unsigned char cmd[6];
+  unsigned char resp[256 * 2 + 3], *cache_ptr = NULL;
+  unsigned long paddr = 0UL, *paddr_ptr = NULL;
+  unsigned int pagesize = 0;
+  int respsize = 3 + 1;
+  int is_flash = 0;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkI_read_byte(.., %s, 0x%lx, ...)\n",
+	    progname, mem->desc, addr);
+
+  if (jtagmkI_program_enable(pgm) < 0)
+    return -1;
+
+  cmd[0] = CMD_READ_MEM;
+
+  if (strcmp(mem->desc, "flash") == 0) {
+    cmd[1] = MTYPE_FLASH_PAGE;
+    pagesize = mem->page_size;
+    paddr = addr & ~(pagesize - 1);
+    paddr_ptr = &PDATA(pgm)->flash_pageaddr;
+    cache_ptr = PDATA(pgm)->flash_pagecache;
+    is_flash = 1;
+  } else if (strcmp(mem->desc, "eeprom") == 0) {
+    cmd[1] = MTYPE_EEPROM_PAGE;
+    pagesize = mem->page_size;
+    paddr = addr & ~(pagesize - 1);
+    paddr_ptr = &PDATA(pgm)->eeprom_pageaddr;
+    cache_ptr = PDATA(pgm)->eeprom_pagecache;
+  } else if (strcmp(mem->desc, "lfuse") == 0) {
+    cmd[1] = MTYPE_FUSE_BITS;
+    addr = 0;
+  } else if (strcmp(mem->desc, "hfuse") == 0) {
+    cmd[1] = MTYPE_FUSE_BITS;
+    addr = 1;
+  } else if (strcmp(mem->desc, "efuse") == 0) {
+    cmd[1] = MTYPE_FUSE_BITS;
+    addr = 2;
+  } else if (strcmp(mem->desc, "lock") == 0) {
+    cmd[1] = MTYPE_LOCK_BITS;
+  } else if (strcmp(mem->desc, "calibration") == 0) {
+    cmd[1] = MTYPE_OSCCAL_BYTE;
+  } else if (strcmp(mem->desc, "signature") == 0) {
+    cmd[1] = MTYPE_SIGN_JTAG;
+  }
+
+  /*
+   * To improve the read speed, we used paged reads for flash and
+   * EEPROM, and cache the results in a page cache.
+   *
+   * Page cache validation is based on "{flash,eeprom}_pageaddr"
+   * (holding the base address of the most recent cache fill
+   * operation).  This variable is set to (unsigned long)-1L when the
+   * cache needs to be invalidated.
+   */
+  if (pagesize && paddr == *paddr_ptr) {
+    *value = cache_ptr[addr & (pagesize - 1)];
+    return 0;
+  }
+
+  if (pagesize) {
+    if (is_flash) {
+      cmd[2] = pagesize / 2 - 1;
+      u32_to_b3(cmd + 3, paddr / 2);
+    } else {
+      cmd[2] = pagesize - 1;
+      u32_to_b3(cmd + 3, paddr);
+    }
+    respsize = 3 + pagesize;
+  } else {
+    if (cmd[1] == MTYPE_FUSE_BITS) {
+      /*
+       * The mkI ICE has a bug where it doesn't read efuse correctly
+       * when reading it as a single byte @offset 2, while reading all
+       * fuses at once does work.
+       */
+      cmd[2] = 3 - 1;
+      u32_to_b3(cmd + 3, 0);
+      respsize = 3 + 3;
+    } else {
+      cmd[2] = 1 - 1;
+      u32_to_b3(cmd + 3, addr);
+    }
+  }
+
+  jtagmkI_send(pgm, cmd, 6);
+  jtagmkI_recv(pgm, resp, respsize);
+
+  if (resp[respsize - 1] != RESP_OK) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkI_read_byte(): "
+	    "timeout/error communicating with programmer (resp %c)\n",
+	    progname, resp[respsize - 1]);
+    exit(1);
+  } else {
+    if (verbose == 2)
+      fprintf(stderr, "OK\n");
+  }
+
+  if (pagesize) {
+    *paddr_ptr = paddr;
+    memcpy(cache_ptr, resp + 1, pagesize);
+    *value = cache_ptr[addr & (pagesize - 1)];
+  } else if (cmd[1] == MTYPE_FUSE_BITS) {
+    /* extract the desired fuse */
+    *value = resp[1 + addr];
+  } else
+    *value = resp[1];
+
+  return 0;
+}
+
+static int jtagmkI_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+			       unsigned long addr, unsigned char data)
+{
+  unsigned char cmd[6], datacmd[1 * 2 + 1];
+  unsigned char resp[1], writedata;
+  int len, need_progmode = 1;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkI_write_byte(.., %s, 0x%lx, ...)\n",
+	    progname, mem->desc, addr);
+
+  writedata = data;
+  cmd[0] = CMD_WRITE_MEM;
+  if (strcmp(mem->desc, "flash") == 0) {
+    cmd[1] = MTYPE_SPM;
+    need_progmode = 0;
+    PDATA(pgm)->flash_pageaddr = (unsigned long)-1L;
+  } else if (strcmp(mem->desc, "eeprom") == 0) {
+    cmd[1] = MTYPE_EEPROM;
+    need_progmode = 0;
+    PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L;
+  } else if (strcmp(mem->desc, "lfuse") == 0) {
+    cmd[1] = MTYPE_FUSE_BITS;
+    addr = 0;
+  } else if (strcmp(mem->desc, "hfuse") == 0) {
+    cmd[1] = MTYPE_FUSE_BITS;
+    addr = 1;
+  } else if (strcmp(mem->desc, "efuse") == 0) {
+    cmd[1] = MTYPE_FUSE_BITS;
+    addr = 2;
+  } else if (strcmp(mem->desc, "lock") == 0) {
+    cmd[1] = MTYPE_LOCK_BITS;
+  } else if (strcmp(mem->desc, "calibration") == 0) {
+    cmd[1] = MTYPE_OSCCAL_BYTE;
+  } else if (strcmp(mem->desc, "signature") == 0) {
+    cmd[1] = MTYPE_SIGN_JTAG;
+  }
+
+  if (need_progmode) {
+    if (jtagmkI_program_enable(pgm) < 0)
+      return -1;
+  } else {
+    if (jtagmkI_program_disable(pgm) < 0)
+      return -1;
+  }
+
+  cmd[2] = 1 - 1;
+  if (cmd[1] == MTYPE_SPM) {
+    /*
+     * Flash is word-addressed, but we cannot handle flash anyway
+     * here, as it needs to be written one page at a time...
+     */
+    u32_to_b3(cmd + 3, addr / 2);
+  } else {
+    u32_to_b3(cmd + 3, addr);
+  }
+  /* First part, send the write command. */
+  jtagmkI_send(pgm, cmd, 6);
+  jtagmkI_recv(pgm, resp, 1);
+  if (resp[0] != RESP_OK) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkI_write_byte(): "
+	    "timeout/error communicating with programmer (resp %c)\n",
+	    progname, resp[0]);
+    return -1;
+  } else {
+    if (verbose == 2)
+      fprintf(stderr, "OK\n");
+  }
+
+  /* Now, send the data buffer. */
+  datacmd[0] = CMD_DATA;
+  if (cmd[1] == MTYPE_SPM) {
+    len = 3;
+    if ((addr & 1) != 0) {
+      datacmd[1] = 0;
+      datacmd[2] = writedata;
+    } else {
+      datacmd[1] = writedata;
+      datacmd[2] = 0;
+    }
+  } else {
+    len = 2;
+    datacmd[1] = writedata;
+  }
+  jtagmkI_send(pgm, datacmd, len);
+  jtagmkI_recv(pgm, resp, 1);
+  if (resp[0] != RESP_OK) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkI_write_byte(): "
+	    "timeout/error communicating with programmer (resp %c)\n",
+	    progname, resp[0]);
+    return -1;
+  } else {
+    if (verbose == 2)
+      fprintf(stderr, "OK\n");
+  }
+
+  return 0;
+}
+
+
+/*
+ * Set the JTAG clock.  The actual frequency is quite a bit of
+ * guesswork, based on the values claimed by AVR Studio.  Inside the
+ * JTAG ICE, the value is the delay count of a delay loop between the
+ * JTAG clock edges.  A count of 0 bypasses the delay loop.
+ *
+ * As the STK500 expresses it as a period length (and we actualy do
+ * program a period length as well), we rather call it by that name.
+ */
+static int jtagmkI_set_sck_period(PROGRAMMER * pgm, double v)
+{
+  unsigned char dur;
+
+  v = 1 / v;			/* convert to frequency */
+  if (v >= 1e6)
+    dur = JTAG_BITRATE_1_MHz;
+  else if (v >= 499e3)
+    dur = JTAG_BITRATE_500_kHz;
+  else if (v >= 249e3)
+    dur = JTAG_BITRATE_250_kHz;
+  else
+    dur = JTAG_BITRATE_125_kHz;
+
+  return jtagmkI_setparm(pgm, PARM_CLOCK, dur);
+}
+
+
+/*
+ * Read an emulator parameter.  The result is exactly one byte,
+ * multi-byte parameters get two different parameter names for
+ * their components.
+ */
+static int jtagmkI_getparm(PROGRAMMER * pgm, unsigned char parm,
+			    unsigned char * value)
+{
+  unsigned char buf[2], resp[3];
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkI_getparm()\n", progname);
+
+  buf[0] = CMD_GET_PARAM;
+  buf[1] = parm;
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkI_getparm(): "
+	    "Sending get parameter command (parm 0x%02x): ",
+	    progname, parm);
+  jtagmkI_send(pgm, buf, 2);
+
+  jtagmkI_recv(pgm, resp, 3);
+  if (resp[0] != RESP_OK) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkI_getparm(): "
+	    "timeout/error communicating with programmer (resp %c)\n",
+	    progname, resp[0]);
+    return -1;
+  } else if (resp[2] != RESP_OK) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkI_getparm(): "
+	    "unknown parameter 0x%02x\n",
+	    progname, parm);
+    return -1;
+  } else {
+    if (verbose == 2)
+      fprintf(stderr, "OK, value 0x%02x\n", resp[1]);
+  }
+
+  *value = resp[1];
+
+  return 0;
+}
+
+/*
+ * Write an emulator parameter.
+ */
+static int jtagmkI_setparm(PROGRAMMER * pgm, unsigned char parm,
+			    unsigned char value)
+{
+  unsigned char buf[3], resp[2];
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkI_setparm()\n", progname);
+
+  buf[0] = CMD_SET_PARAM;
+  buf[1] = parm;
+  buf[2] = value;
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkI_setparm(): "
+	    "Sending set parameter command (parm 0x%02x): ",
+	    progname, parm);
+  jtagmkI_send(pgm, buf, 3);
+  jtagmkI_recv(pgm, resp, 2);
+  if (resp[0] != RESP_OK) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkI_setparm(): "
+	    "timeout/error communicating with programmer (resp %c)\n",
+	    progname, resp[0]);
+    return -1;
+  } else {
+    if (verbose == 2)
+      fprintf(stderr, "OK\n");
+  }
+
+  return 0;
+}
+
+
+static void jtagmkI_display(PROGRAMMER * pgm, const char * p)
+{
+
+  unsigned char hw, fw;
+
+  if (jtagmkI_getparm(pgm, PARM_HW_VERSION, &hw) < 0 ||
+      jtagmkI_getparm(pgm, PARM_SW_VERSION, &fw) < 0)
+    return;
+
+  fprintf(stderr, "%sICE hardware version: 0x%02x\n", p, hw);
+  fprintf(stderr, "%sICE firmware version: 0x%02x\n", p, fw);
+
+  jtagmkI_print_parms1(pgm, p);
+
+  return;
+}
+
+
+static void jtagmkI_print_parms1(PROGRAMMER * pgm, const char * p)
+{
+  unsigned char vtarget, jtag_clock;
+  const char *clkstr;
+  double clk;
+
+  if (jtagmkI_getparm(pgm, PARM_OCD_VTARGET, &vtarget) < 0 ||
+      jtagmkI_getparm(pgm, PARM_CLOCK, &jtag_clock) < 0)
+    return;
+
+  switch ((unsigned)jtag_clock) {
+  case JTAG_BITRATE_1_MHz:
+    clkstr = "1 MHz";
+    clk = 1e6;
+    break;
+
+  case JTAG_BITRATE_500_kHz:
+    clkstr = "500 kHz";
+    clk = 500e3;
+    break;
+
+  case JTAG_BITRATE_250_kHz:
+    clkstr = "250 kHz";
+    clk = 250e3;
+    break;
+
+  case JTAG_BITRATE_125_kHz:
+    clkstr = "125 kHz";
+    clk = 125e3;
+    break;
+
+  default:
+    clkstr = "???";
+    clk = 1e6;
+  }
+
+  fprintf(stderr, "%sVtarget         : %.1f V\n", p,
+	  6.25 * (unsigned)vtarget / 255.0);
+  fprintf(stderr, "%sJTAG clock      : %s (%.1f us)\n", p, clkstr,
+	  1.0e6 / clk);
+
+  return;
+}
+
+
+static void jtagmkI_print_parms(PROGRAMMER * pgm)
+{
+  jtagmkI_print_parms1(pgm, "");
+}
+
+
+void jtagmkI_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "JTAGMKI");
+
+  /*
+   * mandatory functions
+   */
+  pgm->initialize     = jtagmkI_initialize;
+  pgm->display        = jtagmkI_display;
+  pgm->enable         = jtagmkI_enable;
+  pgm->disable        = jtagmkI_disable;
+  pgm->program_enable = jtagmkI_program_enable_dummy;
+  pgm->chip_erase     = jtagmkI_chip_erase;
+  pgm->open           = jtagmkI_open;
+  pgm->close          = jtagmkI_close;
+  pgm->read_byte      = jtagmkI_read_byte;
+  pgm->write_byte     = jtagmkI_write_byte;
+
+  /*
+   * optional functions
+   */
+  pgm->paged_write    = jtagmkI_paged_write;
+  pgm->paged_load     = jtagmkI_paged_load;
+  pgm->print_parms    = jtagmkI_print_parms;
+  pgm->set_sck_period = jtagmkI_set_sck_period;
+  pgm->setup          = jtagmkI_setup;
+  pgm->teardown       = jtagmkI_teardown;
+  pgm->page_size      = 256;
+}
diff --git a/avrdude/jtagmkI.h b/avrdude/jtagmkI.h
new file mode 100644
index 00000000..d6669b11
--- /dev/null
+++ b/avrdude/jtagmkI.h
@@ -0,0 +1,36 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2002-2004  Brian S. Dean <bsd@bsdhome.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id$ */
+
+#ifndef jtagmkI_h
+#define jtagmkI_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void jtagmkI_initpgm (PROGRAMMER * pgm);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/avrdude/jtagmkII.c b/avrdude/jtagmkII.c
new file mode 100644
index 00000000..eb13c7d2
--- /dev/null
+++ b/avrdude/jtagmkII.c
@@ -0,0 +1,3767 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2005-2007 Joerg Wunsch <j@uriah.heep.sax.de>
+ *
+ * Derived from stk500 code which is:
+ * Copyright (C) 2002-2004 Brian S. Dean <bsd@bsdhome.com>
+ * Copyright (C) 2005 Erik Walthinsen
+ *
+ *
+ * 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
+ */
+
+/* $Id$ */
+
+/*
+ * avrdude interface for Atmel JTAG ICE mkII programmer
+ *
+ * The AVR Dragon also uses the same protocol, so it is handled here
+ * as well.
+ */
+
+#include "ac_cfg.h"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "avrdude.h"
+#include "avr.h"
+#include "crc16.h"
+#include "pgm.h"
+#include "jtagmkII.h"
+#include "jtagmkII_private.h"
+#include "serial.h"
+#include "usbdevs.h"
+
+/*
+ * Private data for this programmer.
+ */
+struct pdata
+{
+  unsigned short command_sequence; /* Next cmd seqno to issue. */
+
+  /*
+   * See jtagmkII_read_byte() for an explanation of the flash and
+   * EEPROM page caches.
+   */
+  unsigned char *flash_pagecache;
+  unsigned long flash_pageaddr;
+  unsigned int flash_pagesize;
+
+  unsigned char *eeprom_pagecache;
+  unsigned long eeprom_pageaddr;
+  unsigned int eeprom_pagesize;
+
+  int prog_enabled;	     /* Cached value of PROGRAMMING status. */
+  unsigned char serno[6];	/* JTAG ICE serial number. */
+
+  /* JTAG chain stuff */
+  unsigned char jtagchain[4];
+
+  /* The length of the device descriptor is firmware-dependent. */
+  size_t device_descriptor_length;
+};
+
+#define PDATA(pgm) ((struct pdata *)(pgm->cookie))
+
+/*
+ * The OCDEN fuse is bit 7 of the high fuse (hfuse).  In order to
+ * perform memory operations on MTYPE_SPM and MTYPE_EEPROM, OCDEN
+ * needs to be programmed.
+ *
+ * OCDEN should probably rather be defined via the configuration, but
+ * if this ever changes to a different fuse byte for one MCU, quite
+ * some code here needs to be generalized anyway.
+ */
+#define OCDEN (1 << 7)
+
+#define RC(x) { x, #x },
+static struct {
+  unsigned int code;
+  const char *descr;
+} jtagresults[] = {
+  RC(RSP_DEBUGWIRE_SYNC_FAILED)
+  RC(RSP_FAILED)
+  RC(RSP_ILLEGAL_BREAKPOINT)
+  RC(RSP_ILLEGAL_COMMAND)
+  RC(RSP_ILLEGAL_EMULATOR_MODE)
+  RC(RSP_ILLEGAL_JTAG_ID)
+  RC(RSP_ILLEGAL_MCU_STATE)
+  RC(RSP_ILLEGAL_MEMORY_TYPE)
+  RC(RSP_ILLEGAL_MEMORY_RANGE)
+  RC(RSP_ILLEGAL_PARAMETER)
+  RC(RSP_ILLEGAL_POWER_STATE)
+  RC(RSP_ILLEGAL_VALUE)
+  RC(RSP_NO_TARGET_POWER)
+  RC(RSP_SET_N_PARAMETERS)
+};
+
+/*
+ * pgm->flag is marked as "for private use of the programmer".
+ * The following defines this programmer's use of that field.
+ */
+#define PGM_FL_IS_DW		(0x0001)
+#define PGM_FL_IS_PDI           (0x0002)
+#define PGM_FL_IS_JTAG          (0x0004)
+
+static int jtagmkII_open(PROGRAMMER * pgm, char * port);
+
+static int jtagmkII_initialize(PROGRAMMER * pgm, AVRPART * p);
+static int jtagmkII_chip_erase(PROGRAMMER * pgm, AVRPART * p);
+static int jtagmkII_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+                                unsigned long addr, unsigned char * value);
+static int jtagmkII_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+                                unsigned long addr, unsigned char data);
+static int jtagmkII_reset(PROGRAMMER * pgm, unsigned char flags);
+static int jtagmkII_set_sck_period(PROGRAMMER * pgm, double v);
+static int jtagmkII_setparm(PROGRAMMER * pgm, unsigned char parm,
+                            unsigned char * value);
+static void jtagmkII_print_parms1(PROGRAMMER * pgm, const char * p);
+static int jtagmkII_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+                                int page_size, int n_bytes);
+
+// AVR32
+#define ERROR_SAB 0xFFFFFFFF
+
+static int jtagmkII_open32(PROGRAMMER * pgm, char * port);
+static void jtagmkII_close32(PROGRAMMER * pgm);
+static int jtagmkII_reset32(PROGRAMMER * pgm, unsigned short flags);
+static int jtagmkII_initialize32(PROGRAMMER * pgm, AVRPART * p);
+static int jtagmkII_chip_erase32(PROGRAMMER * pgm, AVRPART * p);
+static unsigned long jtagmkII_read_SABaddr(PROGRAMMER * pgm, unsigned long addr,
+                      unsigned int prefix); // ERROR_SAB illegal
+static int jtagmkII_write_SABaddr(PROGRAMMER * pgm, unsigned long addr,
+                                  unsigned int prefix, unsigned long val);
+static int jtagmkII_avr32_reset(PROGRAMMER * pgm, unsigned char val,
+                                  unsigned char ret1, unsigned char ret2);
+static int jtagmkII_smc_init32(PROGRAMMER * pgm);
+static int jtagmkII_paged_write32(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+                                  int page_size, int n_bytes);
+static int jtagmkII_flash_lock32(PROGRAMMER * pgm, unsigned char lock,
+                                  unsigned int page);
+static int jtagmkII_flash_erase32(PROGRAMMER * pgm, unsigned int page);
+static int jtagmkII_flash_write_page32(PROGRAMMER * pgm, unsigned int page);
+static int jtagmkII_flash_clear_pagebuffer32(PROGRAMMER * pgm);
+static int jtagmkII_paged_load32(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+			       int page_size, int n_bytes);
+
+void jtagmkII_setup(PROGRAMMER * pgm)
+{
+  if ((pgm->cookie = malloc(sizeof(struct pdata))) == 0) {
+    fprintf(stderr,
+	    "%s: jtagmkII_setup(): Out of memory allocating private data\n",
+	    progname);
+    exit(1);
+  }
+  memset(pgm->cookie, 0, sizeof(struct pdata));
+}
+
+void jtagmkII_teardown(PROGRAMMER * pgm)
+{
+  free(pgm->cookie);
+}
+
+
+static unsigned long
+b4_to_u32(unsigned char *b)
+{
+  unsigned long l;
+  l = b[0];
+  l += (unsigned)b[1] << 8;
+  l += (unsigned)b[2] << 16;
+  l += (unsigned)b[3] << 24;
+
+  return l;
+}
+static unsigned long
+b4_to_u32r(unsigned char *b)
+{
+  unsigned long l;
+  l = b[3];
+  l += (unsigned)b[2] << 8;
+  l += (unsigned)b[1] << 16;
+  l += (unsigned)b[0] << 24;
+
+  return l;
+}
+
+static void
+u32_to_b4(unsigned char *b, unsigned long l)
+{
+  b[0] = l & 0xff;
+  b[1] = (l >> 8) & 0xff;
+  b[2] = (l >> 16) & 0xff;
+  b[3] = (l >> 24) & 0xff;
+}
+static void
+u32_to_b4r(unsigned char *b, unsigned long l)
+{
+  b[3] = l & 0xff;
+  b[2] = (l >> 8) & 0xff;
+  b[1] = (l >> 16) & 0xff;
+  b[0] = (l >> 24) & 0xff;
+}
+
+static unsigned short
+b2_to_u16(unsigned char *b)
+{
+  unsigned short l;
+  l = b[0];
+  l += (unsigned)b[1] << 8;
+
+  return l;
+}
+
+static void
+u16_to_b2(unsigned char *b, unsigned short l)
+{
+  b[0] = l & 0xff;
+  b[1] = (l >> 8) & 0xff;
+}
+
+static const char *
+jtagmkII_get_rc(unsigned int rc)
+{
+  int i;
+  static char msg[50];
+
+  for (i = 0; i < sizeof jtagresults / sizeof jtagresults[0]; i++)
+    if (jtagresults[i].code == rc)
+      return jtagresults[i].descr;
+
+  sprintf(msg, "Unknown JTAG ICE mkII result code 0x%02x", rc);
+  return msg;
+}
+
+
+static void jtagmkII_print_memory(unsigned char *b, size_t s)
+{
+  int i;
+
+  if (s < 2)
+    return;
+
+  for (i = 0; i < s - 1; i++) {
+    fprintf(stderr, "0x%02x ", b[i + 1]);
+    if (i % 16 == 15)
+      putc('\n', stderr);
+    else
+      putc(' ', stderr);
+  }
+  if (i % 16 != 0)
+    putc('\n', stderr);
+}
+
+static void jtagmkII_prmsg(PROGRAMMER * pgm, unsigned char * data, size_t len)
+{
+  int i;
+
+  if (verbose >= 4) {
+    fprintf(stderr, "Raw message:\n");
+
+    for (i = 0; i < len; i++) {
+      fprintf(stderr, "0x%02x", data[i]);
+      if (i % 16 == 15)
+	putc('\n', stderr);
+      else
+	putchar(' ');
+    }
+    if (i % 16 != 0)
+      putc('\n', stderr);
+  }
+
+  switch (data[0]) {
+  case RSP_OK:
+    fprintf(stderr, "OK\n");
+    break;
+
+  case RSP_FAILED:
+    fprintf(stderr, "FAILED\n");
+    break;
+
+  case RSP_ILLEGAL_BREAKPOINT:
+    fprintf(stderr, "Illegal breakpoint\n");
+    break;
+
+  case RSP_ILLEGAL_COMMAND:
+    fprintf(stderr, "Illegal command\n");
+    break;
+
+  case RSP_ILLEGAL_EMULATOR_MODE:
+    fprintf(stderr, "Illegal emulator mode");
+    if (len > 1)
+      switch (data[1]) {
+      case EMULATOR_MODE_DEBUGWIRE: fprintf(stderr, ": DebugWire"); break;
+      case EMULATOR_MODE_JTAG:      fprintf(stderr, ": JTAG"); break;
+      case EMULATOR_MODE_HV:        fprintf(stderr, ": HVSP/PP"); break;
+      case EMULATOR_MODE_SPI:       fprintf(stderr, ": SPI"); break;
+      case EMULATOR_MODE_JTAG_XMEGA: fprintf(stderr, ": JTAG/Xmega"); break;
+      }
+    putc('\n', stderr);
+    break;
+
+  case RSP_ILLEGAL_JTAG_ID:
+    fprintf(stderr, "Illegal JTAG ID\n");
+    break;
+
+  case RSP_ILLEGAL_MCU_STATE:
+    fprintf(stderr, "Illegal MCU state");
+    if (len > 1)
+      switch (data[1]) {
+      case STOPPED:     fprintf(stderr, ": Stopped"); break;
+      case RUNNING:     fprintf(stderr, ": Running"); break;
+      case PROGRAMMING: fprintf(stderr, ": Programming"); break;
+      }
+    putc('\n', stderr);
+    break;
+
+  case RSP_ILLEGAL_MEMORY_TYPE:
+    fprintf(stderr, "Illegal memory type\n");
+    break;
+
+  case RSP_ILLEGAL_MEMORY_RANGE:
+    fprintf(stderr, "Illegal memory range\n");
+    break;
+
+  case RSP_ILLEGAL_PARAMETER:
+    fprintf(stderr, "Illegal parameter\n");
+    break;
+
+  case RSP_ILLEGAL_POWER_STATE:
+    fprintf(stderr, "Illegal power state\n");
+    break;
+
+  case RSP_ILLEGAL_VALUE:
+    fprintf(stderr, "Illegal value\n");
+    break;
+
+  case RSP_NO_TARGET_POWER:
+    fprintf(stderr, "No target power\n");
+    break;
+
+  case RSP_SIGN_ON:
+    fprintf(stderr, "Sign-on succeeded\n");
+    /* Sign-on data will be printed below anyway. */
+    break;
+
+  case RSP_MEMORY:
+    fprintf(stderr, "memory contents:\n");
+    jtagmkII_print_memory(data, len);
+    break;
+
+  case RSP_PARAMETER:
+    fprintf(stderr, "parameter values:\n");
+    jtagmkII_print_memory(data, len);
+    break;
+
+  case RSP_SPI_DATA:
+    fprintf(stderr, "SPI data returned:\n");
+    for (i = 1; i < len; i++)
+      fprintf(stderr, "0x%02x ", data[i]);
+    putc('\n', stderr);
+    break;
+
+  case EVT_BREAK:
+    fprintf(stderr, "BREAK event");
+    if (len >= 6) {
+      fprintf(stderr, ", PC = 0x%lx, reason ", b4_to_u32(data + 1));
+      switch (data[5]) {
+      case 0x00:
+	fprintf(stderr, "unspecified");
+	break;
+      case 0x01:
+	fprintf(stderr, "program break");
+	break;
+      case 0x02:
+	fprintf(stderr, "data break PDSB");
+	break;
+      case 0x03:
+	fprintf(stderr, "data break PDMSB");
+	break;
+      default:
+	fprintf(stderr, "unknown: 0x%02x", data[5]);
+      }
+    }
+    putc('\n', stderr);
+    break;
+
+  default:
+    fprintf(stderr, "unknown message 0x%02x\n", data[0]);
+  }
+
+  putc('\n', stderr);
+}
+
+
+int jtagmkII_send(PROGRAMMER * pgm, unsigned char * data, size_t len)
+{
+  unsigned char *buf;
+
+  if (verbose >= 3)
+    fprintf(stderr, "\n%s: jtagmkII_send(): sending %lu bytes\n",
+	    progname, (unsigned long)len);
+
+  if ((buf = malloc(len + 10)) == NULL)
+    {
+      fprintf(stderr, "%s: jtagmkII_send(): out of memory",
+	      progname);
+      return -1;
+    }
+
+  buf[0] = MESSAGE_START;
+  u16_to_b2(buf + 1, PDATA(pgm)->command_sequence);
+  u32_to_b4(buf + 3, len);
+  buf[7] = TOKEN;
+  memcpy(buf + 8, data, len);
+
+  crcappend(buf, len + 8);
+
+  if (serial_send(&pgm->fd, buf, len + 10) != 0) {
+    fprintf(stderr,
+	    "%s: jtagmkII_send(): failed to send command to serial port\n",
+	    progname);
+    exit(1);
+  }
+
+  free(buf);
+
+  return 0;
+}
+
+
+static int jtagmkII_drain(PROGRAMMER * pgm, int display)
+{
+  return serial_drain(&pgm->fd, display);
+}
+
+
+/*
+ * Receive one frame, return it in *msg.  Received sequence number is
+ * returned in seqno.  Any valid frame will be returned, regardless
+ * whether it matches the expected sequence number, including event
+ * notification frames (seqno == 0xffff).
+ *
+ * Caller must eventually free the buffer.
+ */
+static int jtagmkII_recv_frame(PROGRAMMER * pgm, unsigned char **msg,
+			       unsigned short * seqno) {
+  enum states { sSTART,
+		/* NB: do NOT change the sequence of the following: */
+		sSEQNUM1, sSEQNUM2,
+		sSIZE1, sSIZE2, sSIZE3, sSIZE4,
+		sTOKEN,
+		sDATA,
+		sCSUM1, sCSUM2,
+		/* end NB */
+		sDONE
+  }  state = sSTART;
+  unsigned long msglen = 0, l = 0;
+  int headeridx = 0;
+  int timeout = 0;
+  int ignorpkt = 0;
+  int rv;
+  unsigned char c, *buf = NULL, header[8];
+  unsigned short r_seqno = 0;
+  unsigned short checksum = 0;
+
+  struct timeval tv;
+  double timeoutval = 5;	/* seconds */
+  double tstart, tnow;
+
+  if (verbose >= 4)
+    fprintf(stderr, "%s: jtagmkII_recv():\n", progname);
+
+  gettimeofday(&tv, NULL);
+  tstart = tv.tv_sec;
+
+  while ( (state != sDONE ) && (!timeout) ) {
+    if (state == sDATA) {
+      rv = 0;
+      if (ignorpkt) {
+	/* skip packet's contents */
+	for(l = 0; l < msglen; l++)
+	  rv += serial_recv(&pgm->fd, &c, 1);
+      } else {
+	rv += serial_recv(&pgm->fd, buf + 8, msglen);
+      }
+      if (rv != 0) {
+	timedout:
+	/* timeout in receive */
+	if (verbose > 1)
+	  fprintf(stderr,
+		  "%s: jtagmkII_recv(): Timeout receiving packet\n",
+		  progname);
+	free(buf);
+	return -1;
+      }
+    } else {
+      if (serial_recv(&pgm->fd, &c, 1) != 0)
+	goto timedout;
+    }
+    checksum ^= c;
+
+    if (state < sDATA)
+      header[headeridx++] = c;
+
+    switch (state) {
+      case sSTART:
+        if (c == MESSAGE_START) {
+          state = sSEQNUM1;
+        } else {
+	  headeridx = 0;
+	}
+        break;
+      case sSEQNUM1:
+      case sSEQNUM2:
+	r_seqno >>= 8;
+	r_seqno |= ((unsigned)c << 8);
+	state++;
+	break;
+      case sSIZE1:
+      case sSIZE2:
+      case sSIZE3:
+      case sSIZE4:
+	msglen >>= 8;
+	msglen |= ((unsigned)c << 24);
+        state++;
+        break;
+      case sTOKEN:
+        if (c == TOKEN) {
+	  state = sDATA;
+	  if (msglen > MAX_MESSAGE) {
+	    fprintf(stderr,
+		    "%s: jtagmkII_recv(): msglen %lu exceeds max message "
+		    "size %u, ignoring message\n",
+		    progname, msglen, MAX_MESSAGE);
+	    state = sSTART;
+	    headeridx = 0;
+	  } else if ((buf = malloc(msglen + 10)) == NULL) {
+	    fprintf(stderr, "%s: jtagmkII_recv(): out of memory\n",
+		    progname);
+	    ignorpkt++;
+	  } else {
+	    memcpy(buf, header, 8);
+	  }
+	} else {
+	  state = sSTART;
+	  headeridx = 0;
+	}
+        break;
+      case sDATA:
+	/* The entire payload has been read above. */
+	l = msglen + 8;
+        state = sCSUM1;
+        break;
+      case sCSUM1:
+      case sCSUM2:
+	buf[l++] = c;
+	if (state == sCSUM2) {
+	  if (crcverify(buf, msglen + 10)) {
+	    if (verbose >= 9)
+	      fprintf(stderr, "%s: jtagmkII_recv(): CRC OK",
+		      progname);
+	    state = sDONE;
+	  } else {
+	    fprintf(stderr, "%s: jtagmkII_recv(): checksum error\n",
+		    progname);
+	    free(buf);
+	    return -4;
+	  }
+	} else
+	  state++;
+        break;
+      default:
+        fprintf(stderr, "%s: jtagmkII_recv(): unknown state\n",
+                progname);
+	free(buf);
+        return -5;
+     }
+
+     gettimeofday(&tv, NULL);
+     tnow = tv.tv_sec;
+     if (tnow - tstart > timeoutval) {
+       fprintf(stderr, "%s: jtagmkII_recv_frame(): timeout\n",
+               progname);
+       return -1;
+     }
+
+  }
+  if (verbose >= 3)
+    fprintf(stderr, "\n");
+
+  *seqno = r_seqno;
+  *msg = buf;
+
+  return msglen;
+}
+
+int jtagmkII_recv(PROGRAMMER * pgm, unsigned char **msg) {
+  unsigned short r_seqno;
+  int rv;
+
+  for (;;) {
+    if ((rv = jtagmkII_recv_frame(pgm, msg, &r_seqno)) <= 0)
+      return rv;
+    if (verbose >= 3)
+      fprintf(stderr, "%s: jtagmkII_recv(): "
+	      "Got message seqno %d (command_sequence == %d)\n",
+	      progname, r_seqno, PDATA(pgm)->command_sequence);
+    if (r_seqno == PDATA(pgm)->command_sequence) {
+      if (++(PDATA(pgm)->command_sequence) == 0xffff)
+	PDATA(pgm)->command_sequence = 0;
+      /*
+       * We move the payload to the beginning of the buffer, to make
+       * the job easier for the caller.  We have to return the
+       * original pointer though, as the caller must free() it.
+       */
+      memmove(*msg, *msg + 8, rv);
+
+      if (verbose == 4)
+      {
+          int i = rv;
+          unsigned char *p = *msg;
+          fprintf(stderr, "%s: Recv: ", progname);
+
+          while (i) {
+            unsigned char c = *p;
+            if (isprint(c)) {
+              fprintf(stderr, "%c ", c);
+            }
+            else {
+              fprintf(stderr, ". ");
+            }
+            fprintf(stderr, "[%02x] ", c);
+
+            p++;
+            i--;
+          }
+          fprintf(stderr, "\n");
+      }
+      return rv;
+    }
+    if (r_seqno == 0xffff) {
+      if (verbose >= 3)
+	fprintf(stderr, "%s: jtagmkII_recv(): got asynchronous event\n",
+		progname);
+    } else {
+      if (verbose >= 2)
+	fprintf(stderr, "%s: jtagmkII_recv(): "
+		"got wrong sequence number, %u != %u\n",
+		progname, r_seqno, PDATA(pgm)->command_sequence);
+    }
+    free(*msg);
+  }
+}
+
+
+int jtagmkII_getsync(PROGRAMMER * pgm, int mode) {
+  int tries;
+#define MAXTRIES 33
+  unsigned char buf[3], *resp, c = 0xff;
+  int status;
+  unsigned int fwver, hwver;
+  int is_dragon;
+
+  if (verbose >= 3)
+    fprintf(stderr, "%s: jtagmkII_getsync()\n", progname);
+
+  if (strncmp(pgm->type, "JTAG", strlen("JTAG")) == 0) {
+    is_dragon = 0;
+  } else if (strncmp(pgm->type, "DRAGON", strlen("DRAGON")) == 0) {
+    is_dragon = 1;
+  } else {
+    fprintf(stderr,
+            "%s: Programmer is neither JTAG ICE mkII nor AVR Dragon\n",
+            progname);
+    return -1;
+  }
+  for (tries = 0; tries < MAXTRIES; tries++) {
+
+    /* Get the sign-on information. */
+    buf[0] = CMND_GET_SIGN_ON;
+    if (verbose >= 2)
+      fprintf(stderr, "%s: jtagmkII_getsync(): Sending sign-on command: ",
+	      progname);
+    jtagmkII_send(pgm, buf, 1);
+
+    status = jtagmkII_recv(pgm, &resp);
+    if (status <= 0) {
+	fprintf(stderr, "%s: jtagmkII_getsync(): sign-on command: "
+		"status %d\n",
+		progname, status);
+    } else if (verbose >= 3) {
+      putc('\n', stderr);
+      jtagmkII_prmsg(pgm, resp, status);
+    } else if (verbose == 2)
+      fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+
+    if (status > 0) {
+      if ((c = resp[0]) == RSP_SIGN_ON) {
+	fwver = ((unsigned)resp[8] << 8) | (unsigned)resp[7];
+	hwver = (unsigned)resp[9];
+	memcpy(PDATA(pgm)->serno, resp + 10, 6);
+	if (verbose >= 1 && status > 17) {
+	  fprintf(stderr, "JTAG ICE mkII sign-on message:\n");
+	  fprintf(stderr, "Communications protocol version: %u\n",
+		  (unsigned)resp[1]);
+	  fprintf(stderr, "M_MCU:\n");
+	  fprintf(stderr, "  boot-loader FW version:        %u\n",
+		  (unsigned)resp[2]);
+	  fprintf(stderr, "  firmware version:              %u.%02u\n",
+		  (unsigned)resp[4], (unsigned)resp[3]);
+	  fprintf(stderr, "  hardware version:              %u\n",
+		  (unsigned)resp[5]);
+	  fprintf(stderr, "S_MCU:\n");
+	  fprintf(stderr, "  boot-loader FW version:        %u\n",
+		  (unsigned)resp[6]);
+	  fprintf(stderr, "  firmware version:              %u.%02u\n",
+		  (unsigned)resp[8], (unsigned)resp[7]);
+	  fprintf(stderr, "  hardware version:              %u\n",
+		  (unsigned)resp[9]);
+	  fprintf(stderr, "Serial number:                   "
+		  "%02x:%02x:%02x:%02x:%02x:%02x\n",
+		  PDATA(pgm)->serno[0], PDATA(pgm)->serno[1], PDATA(pgm)->serno[2], PDATA(pgm)->serno[3], PDATA(pgm)->serno[4], PDATA(pgm)->serno[5]);
+	  resp[status - 1] = '\0';
+	  fprintf(stderr, "Device ID:                       %s\n",
+		  resp + 16);
+	}
+	break;
+      }
+      free(resp);
+    }
+  }
+  if (tries >= MAXTRIES) {
+    if (status <= 0)
+      fprintf(stderr,
+	      "%s: jtagmkII_getsync(): "
+	      "timeout/error communicating with programmer (status %d)\n",
+	      progname, status);
+    else
+      fprintf(stderr,
+	      "%s: jtagmkII_getsync(): "
+	      "bad response to sign-on command: %s\n",
+	      progname, jtagmkII_get_rc(c));
+    return -1;
+  }
+
+  PDATA(pgm)->device_descriptor_length = sizeof(struct device_descriptor);
+  /*
+   * There's no official documentation from Atmel about what firmware
+   * revision matches what device descriptor length.  The algorithm
+   * below has been found empirically.
+   */
+#define FWVER(maj, min) ((maj << 8) | (min))
+  if (!is_dragon && fwver < FWVER(3, 16)) {
+    PDATA(pgm)->device_descriptor_length -= 2;
+    fprintf(stderr,
+	    "%s: jtagmkII_getsync(): "
+	    "S_MCU firmware version might be too old to work correctly\n",
+	    progname);
+  } else if (!is_dragon && fwver < FWVER(4, 0)) {
+    PDATA(pgm)->device_descriptor_length -= 2;
+  }
+  if (verbose >= 2 && mode != EMULATOR_MODE_SPI)
+    fprintf(stderr,
+	    "%s: jtagmkII_getsync(): Using a %u-byte device descriptor\n",
+	    progname, (unsigned)PDATA(pgm)->device_descriptor_length);
+  if (mode == EMULATOR_MODE_SPI) {
+    PDATA(pgm)->device_descriptor_length = 0;
+    if (!is_dragon && fwver < FWVER(4, 14)) {
+      fprintf(stderr,
+	      "%s: jtagmkII_getsync(): ISP functionality requires firmware "
+	      "version >= 4.14\n",
+	      progname);
+      return -1;
+    }
+  }
+  if (mode == EMULATOR_MODE_PDI || mode == EMULATOR_MODE_JTAG_XMEGA) {
+    if (!is_dragon && mode == EMULATOR_MODE_PDI && hwver < 1) {
+      fprintf(stderr,
+	      "%s: jtagmkII_getsync(): Xmega PDI support requires hardware "
+	      "revision >= 1\n",
+	      progname);
+      return -1;
+    }
+    if (!is_dragon && fwver < FWVER(5, 37)) {
+      fprintf(stderr,
+	      "%s: jtagmkII_getsync(): Xmega support requires firmware "
+	      "version >= 5.37\n",
+	      progname);
+      return -1;
+    }
+    if (is_dragon && fwver < FWVER(6, 11)) {
+      fprintf(stderr,
+	      "%s: jtagmkII_getsync(): Xmega support requires firmware "
+	      "version >= 6.11\n",
+	      progname);
+      return -1;
+    }
+  }
+#undef FWVER
+
+  if(mode < 0) return 0;  // for AVR32
+
+  /* Turn the ICE into JTAG or ISP mode as requested. */
+  buf[0] = mode;
+  if (jtagmkII_setparm(pgm, PAR_EMULATOR_MODE, buf) < 0) {
+    if (mode == EMULATOR_MODE_SPI) {
+      fprintf(stderr,
+	      "%s: jtagmkII_getsync(): "
+	      "ISP activation failed, trying debugWire\n",
+	      progname);
+      buf[0] = EMULATOR_MODE_DEBUGWIRE;
+      if (jtagmkII_setparm(pgm, PAR_EMULATOR_MODE, buf) < 0)
+	return -1;
+      else {
+	/*
+	 * We are supposed to send a CMND_RESET with the
+	 * MONCOM_DISABLE flag set right now, and then
+	 * restart from scratch.
+	 *
+	 * As this will make the ICE sign off from USB, so
+	 * we risk losing our USB connection, it's easier
+	 * to instruct the user to restart AVRDUDE rather
+	 * than trying to cope with all this inside the
+	 * program.
+	 */
+	(void)jtagmkII_reset(pgm, 0x04);
+	jtagmkII_close(pgm);
+	fprintf(stderr,
+		"%s: Target prepared for ISP, signed off.\n"
+		"%s: Please restart %s without power-cycling the target.\n",
+		progname, progname, progname);
+	exit(0);
+      }
+    } else {
+      return -1;
+    }
+  }
+
+  /* GET SYNC forces the target into STOPPED mode */
+  buf[0] = CMND_GET_SYNC;
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_getsync(): Sending get sync command: ",
+	    progname);
+  jtagmkII_send(pgm, buf, 1);
+
+  status = jtagmkII_recv(pgm, &resp);
+  if (status <= 0) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkII_getsync(): "
+	    "timeout/error communicating with programmer (status %d)\n",
+	    progname, status);
+    return -1;
+  }
+  if (verbose >= 3) {
+    putc('\n', stderr);
+    jtagmkII_prmsg(pgm, resp, status);
+  } else if (verbose == 2)
+    fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+  c = resp[0];
+  free(resp);
+  if (c != RSP_OK) {
+    fprintf(stderr,
+	    "%s: jtagmkII_getsync(): "
+	    "bad response to set parameter command: %s\n",
+	    progname, jtagmkII_get_rc(c));
+    return -1;
+  }
+
+  return 0;
+}
+
+/*
+ * issue the 'chip erase' command to the AVR device
+ */
+static int jtagmkII_chip_erase(PROGRAMMER * pgm, AVRPART * p)
+{
+  int status, len;
+  unsigned char buf[6], *resp, c;
+
+  if (p->flags & AVRPART_HAS_PDI) {
+    buf[0] = CMND_XMEGA_ERASE;
+    buf[1] = XMEGA_ERASE_CHIP;
+    memset(buf + 2, 0, 4);      /* address of area to be erased */
+    len = 6;
+  } else {
+    buf[0] = CMND_CHIP_ERASE;
+    len = 1;
+  }
+  if (verbose >= 2)
+    fprintf(stderr,
+            "%s: jtagmkII_chip_erase(): Sending %schip erase command: ",
+	    progname,
+            (p->flags & AVRPART_HAS_PDI)? "Xmega ": "");
+  jtagmkII_send(pgm, buf, len);
+
+  status = jtagmkII_recv(pgm, &resp);
+  if (status <= 0) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkII_chip_erase(): "
+	    "timeout/error communicating with programmer (status %d)\n",
+	    progname, status);
+    return -1;
+  }
+  if (verbose >= 3) {
+    putc('\n', stderr);
+    jtagmkII_prmsg(pgm, resp, status);
+  } else if (verbose == 2)
+    fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+  c = resp[0];
+  free(resp);
+  if (c != RSP_OK) {
+    fprintf(stderr,
+	    "%s: jtagmkII_chip_erase(): "
+	    "bad response to chip erase command: %s\n",
+	    progname, jtagmkII_get_rc(c));
+    return -1;
+  }
+
+  if (!(p->flags & AVRPART_HAS_PDI))
+      pgm->initialize(pgm, p);
+
+  return 0;
+}
+
+/*
+ * There is no chip erase functionality in debugWire mode.
+ */
+static int jtagmkII_chip_erase_dw(PROGRAMMER * pgm, AVRPART * p)
+{
+
+  fprintf(stderr, "%s: Chip erase not supported in debugWire mode\n",
+	  progname);
+
+  return 0;
+}
+
+static void jtagmkII_set_devdescr(PROGRAMMER * pgm, AVRPART * p)
+{
+  int status;
+  unsigned char *resp, c;
+  LNODEID ln;
+  AVRMEM * m;
+  struct {
+    unsigned char cmd;
+    struct device_descriptor dd;
+  } sendbuf;
+
+  memset(&sendbuf, 0, sizeof sendbuf);
+  sendbuf.cmd = CMND_SET_DEVICE_DESCRIPTOR;
+  sendbuf.dd.ucSPMCRAddress = p->spmcr;
+  sendbuf.dd.ucRAMPZAddress = p->rampz;
+  sendbuf.dd.ucIDRAddress = p->idr;
+  u16_to_b2(sendbuf.dd.EECRAddress, p->eecr);
+  sendbuf.dd.ucAllowFullPageBitstream =
+    (p->flags & AVRPART_ALLOWFULLPAGEBITSTREAM) != 0;
+  sendbuf.dd.EnablePageProgramming =
+    (p->flags & AVRPART_ENABLEPAGEPROGRAMMING) != 0;
+  for (ln = lfirst(p->mem); ln; ln = lnext(ln)) {
+    m = ldata(ln);
+    if (strcmp(m->desc, "flash") == 0) {
+      PDATA(pgm)->flash_pagesize = m->page_size;
+      u32_to_b4(sendbuf.dd.ulFlashSize, m->size);
+      u16_to_b2(sendbuf.dd.uiFlashPageSize, PDATA(pgm)->flash_pagesize);
+      u16_to_b2(sendbuf.dd.uiFlashpages, m->size / PDATA(pgm)->flash_pagesize);
+      if (p->flags & AVRPART_HAS_DW) {
+	memcpy(sendbuf.dd.ucFlashInst, p->flash_instr, FLASH_INSTR_SIZE);
+	memcpy(sendbuf.dd.ucEepromInst, p->eeprom_instr, EEPROM_INSTR_SIZE);
+      }
+    } else if (strcmp(m->desc, "eeprom") == 0) {
+      sendbuf.dd.ucEepromPageSize = PDATA(pgm)->eeprom_pagesize = m->page_size;
+    }
+  }
+  sendbuf.dd.ucCacheType =
+    (p->flags & AVRPART_HAS_PDI)? 0x02 /* ATxmega */: 0x00;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_set_devdescr(): "
+	    "Sending set device descriptor command: ",
+	    progname);
+  jtagmkII_send(pgm, (unsigned char *)&sendbuf,
+		PDATA(pgm)->device_descriptor_length + sizeof(unsigned char));
+
+  status = jtagmkII_recv(pgm, &resp);
+  if (status <= 0) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkII_set_devdescr(): "
+	    "timeout/error communicating with programmer (status %d)\n",
+	    progname, status);
+    return;
+  }
+  if (verbose >= 3) {
+    putc('\n', stderr);
+    jtagmkII_prmsg(pgm, resp, status);
+  } else if (verbose == 2)
+    fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+  c = resp[0];
+  free(resp);
+  if (c != RSP_OK) {
+    fprintf(stderr,
+	    "%s: jtagmkII_set_devdescr(): "
+	    "bad response to set device descriptor command: %s\n",
+	    progname, jtagmkII_get_rc(c));
+  }
+}
+
+/*
+ * Reset the target.
+ */
+static int jtagmkII_reset(PROGRAMMER * pgm, unsigned char flags)
+{
+  int status;
+  unsigned char buf[2], *resp, c;
+
+  /*
+   * In debugWire mode, don't reset.  Do a forced stop, and tell the
+   * ICE to stop any timers, too.
+   */
+  if (pgm->flag & PGM_FL_IS_DW) {
+    unsigned char parm[] = { 0 };
+
+    (void)jtagmkII_setparm(pgm, PAR_TIMERS_RUNNING, parm);
+  }
+
+  buf[0] = (pgm->flag & PGM_FL_IS_DW)? CMND_FORCED_STOP: CMND_RESET;
+  buf[1] = (pgm->flag & PGM_FL_IS_DW)? 1: flags;
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_reset(): Sending %s command: ",
+	    progname, (pgm->flag & PGM_FL_IS_DW)? "stop": "reset");
+  jtagmkII_send(pgm, buf, 2);
+
+  status = jtagmkII_recv(pgm, &resp);
+  if (status <= 0) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkII_reset(): "
+	    "timeout/error communicating with programmer (status %d)\n",
+	    progname, status);
+    return -1;
+  }
+  if (verbose >= 3) {
+    putc('\n', stderr);
+    jtagmkII_prmsg(pgm, resp, status);
+  } else if (verbose == 2)
+    fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+  c = resp[0];
+  free(resp);
+  if (c != RSP_OK) {
+    fprintf(stderr,
+	    "%s: jtagmkII_reset(): "
+	    "bad response to reset command: %s\n",
+	    progname, jtagmkII_get_rc(c));
+    return -1;
+  }
+
+  return 0;
+}
+
+static int jtagmkII_program_enable_dummy(PROGRAMMER * pgm, AVRPART * p)
+{
+  return 0;
+}
+
+static int jtagmkII_program_enable(PROGRAMMER * pgm)
+{
+  int status;
+  unsigned char buf[1], *resp, c;
+
+  if (PDATA(pgm)->prog_enabled)
+    return 0;
+
+  buf[0] = CMND_ENTER_PROGMODE;
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_program_enable(): "
+	    "Sending enter progmode command: ",
+	    progname);
+  jtagmkII_send(pgm, buf, 1);
+
+  status = jtagmkII_recv(pgm, &resp);
+  if (status <= 0) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkII_program_enable(): "
+	    "timeout/error communicating with programmer (status %d)\n",
+	    progname, status);
+    return -1;
+  }
+  if (verbose >= 3) {
+    putc('\n', stderr);
+    jtagmkII_prmsg(pgm, resp, status);
+  } else if (verbose == 2)
+    fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+  c = resp[0];
+  free(resp);
+  if (c != RSP_OK) {
+    fprintf(stderr,
+	    "%s: jtagmkII_program_enable(): "
+	    "bad response to enter progmode command: %s\n",
+	    progname, jtagmkII_get_rc(c));
+    if (c == RSP_ILLEGAL_JTAG_ID)
+      fprintf(stderr, "%s: JTAGEN fuse disabled?\n", progname);
+    return -1;
+  }
+
+  PDATA(pgm)->prog_enabled = 1;
+  return 0;
+}
+
+static int jtagmkII_program_disable(PROGRAMMER * pgm)
+{
+  int status;
+  unsigned char buf[1], *resp, c;
+
+  if (!PDATA(pgm)->prog_enabled)
+    return 0;
+
+  buf[0] = CMND_LEAVE_PROGMODE;
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_program_disable(): "
+	    "Sending leave progmode command: ",
+	    progname);
+  jtagmkII_send(pgm, buf, 1);
+
+  status = jtagmkII_recv(pgm, &resp);
+  if (status <= 0) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkII_program_disable(): "
+	    "timeout/error communicating with programmer (status %d)\n",
+	    progname, status);
+    return -1;
+  }
+  if (verbose >= 3) {
+    putc('\n', stderr);
+    jtagmkII_prmsg(pgm, resp, status);
+  } else if (verbose == 2)
+    fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+  c = resp[0];
+  free(resp);
+  if (c != RSP_OK) {
+    fprintf(stderr,
+	    "%s: jtagmkII_program_disable(): "
+	    "bad response to leave progmode command: %s\n",
+	    progname, jtagmkII_get_rc(c));
+    return -1;
+  }
+
+  PDATA(pgm)->prog_enabled = 0;
+  (void)jtagmkII_reset(pgm, 0x01);
+
+  return 0;
+}
+
+static unsigned char jtagmkII_get_baud(long baud)
+{
+  static struct {
+    long baud;
+    unsigned char val;
+  } baudtab[] = {
+    { 2400L, PAR_BAUD_2400 },
+    { 4800L, PAR_BAUD_4800 },
+    { 9600L, PAR_BAUD_9600 },
+    { 19200L, PAR_BAUD_19200 },
+    { 38400L, PAR_BAUD_38400 },
+    { 57600L, PAR_BAUD_57600 },
+    { 115200L, PAR_BAUD_115200 },
+    { 14400L, PAR_BAUD_14400 },
+  };
+  int i;
+
+  for (i = 0; i < sizeof baudtab / sizeof baudtab[0]; i++)
+    if (baud == baudtab[i].baud)
+      return baudtab[i].val;
+
+  return 0;
+}
+
+/*
+ * initialize the AVR device and prepare it to accept commands
+ */
+static int jtagmkII_initialize(PROGRAMMER * pgm, AVRPART * p)
+{
+  AVRMEM hfuse;
+  unsigned char b;
+  int ok;
+  const char *ifname;
+
+  ok = 0;
+  if (pgm->flag & PGM_FL_IS_DW) {
+    ifname = "debugWire";
+    if (p->flags & AVRPART_HAS_DW)
+      ok = 1;
+  } else if (pgm->flag & PGM_FL_IS_PDI) {
+    ifname = "PDI";
+    if (p->flags & AVRPART_HAS_PDI)
+      ok = 1;
+  } else {
+    ifname = "JTAG";
+    if (p->flags & AVRPART_HAS_JTAG)
+      ok = 1;
+  }
+
+  if (!ok) {
+    fprintf(stderr, "%s: jtagmkII_initialize(): part %s has no %s interface\n",
+	    progname, p->desc, ifname);
+    return -1;
+  }
+
+  if ((serdev->flags & SERDEV_FL_CANSETSPEED) && pgm->baudrate && pgm->baudrate != 19200) {
+    if ((b = jtagmkII_get_baud(pgm->baudrate)) == 0) {
+      fprintf(stderr, "%s: jtagmkII_initialize(): unsupported baudrate %d\n",
+	      progname, pgm->baudrate);
+    } else {
+      if (verbose >= 2)
+	fprintf(stderr, "%s: jtagmkII_initialize(): "
+		"trying to set baudrate to %d\n",
+		progname, pgm->baudrate);
+      if (jtagmkII_setparm(pgm, PAR_BAUD_RATE, &b) == 0)
+	serial_setspeed(&pgm->fd, pgm->baudrate);
+    }
+  }
+  if ((pgm->flag & PGM_FL_IS_JTAG) && pgm->bitclock != 0.0) {
+    if (verbose >= 2)
+      fprintf(stderr, "%s: jtagmkII_initialize(): "
+	      "trying to set JTAG clock period to %.1f us\n",
+	      progname, pgm->bitclock);
+    if (jtagmkII_set_sck_period(pgm, pgm->bitclock) != 0)
+      return -1;
+  }
+
+  if (jtagmkII_setparm(pgm, PAR_DAISY_CHAIN_INFO, PDATA(pgm)->jtagchain) < 0) {
+    fprintf(stderr, "%s: jtagmkII_initialize(): Failed to setup JTAG chain\n",
+            progname);
+    return -1;
+  }
+
+  /*
+   * Must set the device descriptor before entering programming mode.
+   */
+  jtagmkII_set_devdescr(pgm, p);
+
+  /*
+   * If this is an ATxmega device in JTAG mode, change the emulator
+   * mode from JTAG to JTAG_XMEGA.
+   */
+  if ((pgm->flag & PGM_FL_IS_JTAG) &&
+      (p->flags & AVRPART_HAS_PDI)) {
+    if (jtagmkII_getsync(pgm, EMULATOR_MODE_JTAG_XMEGA) < 0)
+      return -1;
+  }
+
+  free(PDATA(pgm)->flash_pagecache);
+  free(PDATA(pgm)->eeprom_pagecache);
+  if ((PDATA(pgm)->flash_pagecache = malloc(PDATA(pgm)->flash_pagesize)) == NULL) {
+    fprintf(stderr, "%s: jtagmkII_initialize(): Out of memory\n",
+	    progname);
+    return -1;
+  }
+  if ((PDATA(pgm)->eeprom_pagecache = malloc(PDATA(pgm)->eeprom_pagesize)) == NULL) {
+    fprintf(stderr, "%s: jtagmkII_initialize(): Out of memory\n",
+	    progname);
+    free(PDATA(pgm)->flash_pagecache);
+    return -1;
+  }
+  PDATA(pgm)->flash_pageaddr = PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L;
+
+  if (jtagmkII_reset(pgm, 0x01) < 0)
+    return -1;
+
+  if ((pgm->flag & PGM_FL_IS_JTAG) && !(p->flags & AVRPART_HAS_PDI)) {
+    strcpy(hfuse.desc, "hfuse");
+    if (jtagmkII_read_byte(pgm, p, &hfuse, 1, &b) < 0)
+      return -1;
+    if ((b & OCDEN) != 0)
+      fprintf(stderr,
+	      "%s: jtagmkII_initialize(): warning: OCDEN fuse not programmed, "
+	      "single-byte EEPROM updates not possible\n",
+	      progname);
+  }
+
+  return 0;
+}
+
+static void jtagmkII_disable(PROGRAMMER * pgm)
+{
+
+  free(PDATA(pgm)->flash_pagecache);
+  PDATA(pgm)->flash_pagecache = NULL;
+  free(PDATA(pgm)->eeprom_pagecache);
+  PDATA(pgm)->eeprom_pagecache = NULL;
+
+  /*
+   * jtagmkII_program_disable() doesn't do anything if the
+   * device is currently not in programming mode, so just
+   * call it unconditionally here.
+   */
+  (void)jtagmkII_program_disable(pgm);
+}
+
+static void jtagmkII_enable(PROGRAMMER * pgm)
+{
+  return;
+}
+
+static int jtagmkII_parseextparms(PROGRAMMER * pgm, LISTID extparms)
+{
+  LNODEID ln;
+  const char *extended_param;
+  int rv = 0;
+
+  for (ln = lfirst(extparms); ln; ln = lnext(ln)) {
+    extended_param = ldata(ln);
+
+    if (strncmp(extended_param, "jtagchain=", strlen("jtagchain=")) == 0) {
+      unsigned int ub, ua, bb, ba;
+      if (sscanf(extended_param, "jtagchain=%u,%u,%u,%u", &ub, &ua, &bb, &ba)
+          != 4) {
+        fprintf(stderr,
+                "%s: jtagmkII_parseextparms(): invalid JTAG chain '%s'\n",
+                progname, extended_param);
+        rv = -1;
+        continue;
+      }
+      if (verbose >= 2) {
+        fprintf(stderr,
+                "%s: jtagmkII_parseextparms(): JTAG chain parsed as:\n"
+                "%s %u units before, %u units after, %u bits before, %u bits after\n",
+                progname,
+                progbuf, ub, ua, bb, ba);
+      }
+      PDATA(pgm)->jtagchain[0] = ub;
+      PDATA(pgm)->jtagchain[1] = ua;
+      PDATA(pgm)->jtagchain[2] = bb;
+      PDATA(pgm)->jtagchain[3] = ba;
+
+      continue;
+    }
+
+    fprintf(stderr,
+            "%s: jtagmkII_parseextparms(): invalid extended parameter '%s'\n",
+            progname, extended_param);
+    rv = -1;
+  }
+
+  return rv;
+}
+
+
+static int jtagmkII_open(PROGRAMMER * pgm, char * port)
+{
+  long baud;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_open()\n", progname);
+
+  /*
+   * The JTAG ICE mkII always starts with a baud rate of 19200 Bd upon
+   * attaching.  If the config file or command-line parameters specify
+   * a higher baud rate, we switch to it later on, after establishing
+   * the connection with the ICE.
+   */
+  baud = 19200;
+
+  /*
+   * If the port name starts with "usb", divert the serial routines
+   * to the USB ones.  The serial_open() function for USB overrides
+   * the meaning of the "baud" parameter to be the USB device ID to
+   * search for.
+   */
+  if (strncmp(port, "usb", 3) == 0) {
+#if defined(HAVE_LIBUSB)
+    serdev = &usb_serdev;
+    baud = USB_DEVICE_JTAGICEMKII;
+#else
+    fprintf(stderr, "avrdude was compiled without usb support.\n");
+    return -1;
+#endif
+  }
+
+  strcpy(pgm->port, port);
+  serial_open(port, baud, &pgm->fd);
+
+  /*
+   * drain any extraneous input
+   */
+  jtagmkII_drain(pgm, 0);
+
+  if (jtagmkII_getsync(pgm, EMULATOR_MODE_JTAG) < 0)
+    return -1;
+
+  return 0;
+}
+
+static int jtagmkII_open_dw(PROGRAMMER * pgm, char * port)
+{
+  long baud;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_open_dw()\n", progname);
+
+  /*
+   * The JTAG ICE mkII always starts with a baud rate of 19200 Bd upon
+   * attaching.  If the config file or command-line parameters specify
+   * a higher baud rate, we switch to it later on, after establishing
+   * the connection with the ICE.
+   */
+  baud = 19200;
+
+  /*
+   * If the port name starts with "usb", divert the serial routines
+   * to the USB ones.  The serial_open() function for USB overrides
+   * the meaning of the "baud" parameter to be the USB device ID to
+   * search for.
+   */
+  if (strncmp(port, "usb", 3) == 0) {
+#if defined(HAVE_LIBUSB)
+    serdev = &usb_serdev;
+    baud = USB_DEVICE_JTAGICEMKII;
+#else
+    fprintf(stderr, "avrdude was compiled without usb support.\n");
+    return -1;
+#endif
+  }
+
+  strcpy(pgm->port, port);
+  serial_open(port, baud, &pgm->fd);
+
+  /*
+   * drain any extraneous input
+   */
+  jtagmkII_drain(pgm, 0);
+
+  if (jtagmkII_getsync(pgm, EMULATOR_MODE_DEBUGWIRE) < 0)
+    return -1;
+
+  return 0;
+}
+
+static int jtagmkII_open_pdi(PROGRAMMER * pgm, char * port)
+{
+  long baud;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_open_pdi()\n", progname);
+
+  /*
+   * The JTAG ICE mkII always starts with a baud rate of 19200 Bd upon
+   * attaching.  If the config file or command-line parameters specify
+   * a higher baud rate, we switch to it later on, after establishing
+   * the connection with the ICE.
+   */
+  baud = 19200;
+
+  /*
+   * If the port name starts with "usb", divert the serial routines
+   * to the USB ones.  The serial_open() function for USB overrides
+   * the meaning of the "baud" parameter to be the USB device ID to
+   * search for.
+   */
+  if (strncmp(port, "usb", 3) == 0) {
+#if defined(HAVE_LIBUSB)
+    serdev = &usb_serdev;
+    baud = USB_DEVICE_JTAGICEMKII;
+#else
+    fprintf(stderr, "avrdude was compiled without usb support.\n");
+    return -1;
+#endif
+  }
+
+  strcpy(pgm->port, port);
+  serial_open(port, baud, &pgm->fd);
+
+  /*
+   * drain any extraneous input
+   */
+  jtagmkII_drain(pgm, 0);
+
+  if (jtagmkII_getsync(pgm, EMULATOR_MODE_PDI) < 0)
+    return -1;
+
+  return 0;
+}
+
+
+static int jtagmkII_dragon_open(PROGRAMMER * pgm, char * port)
+{
+  long baud;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_dragon_open()\n", progname);
+
+  /*
+   * The JTAG ICE mkII always starts with a baud rate of 19200 Bd upon
+   * attaching.  If the config file or command-line parameters specify
+   * a higher baud rate, we switch to it later on, after establishing
+   * the connection with the ICE.
+   */
+  baud = 19200;
+
+  /*
+   * If the port name starts with "usb", divert the serial routines
+   * to the USB ones.  The serial_open() function for USB overrides
+   * the meaning of the "baud" parameter to be the USB device ID to
+   * search for.
+   */
+  if (strncmp(port, "usb", 3) == 0) {
+#if defined(HAVE_LIBUSB)
+    serdev = &usb_serdev;
+    baud = USB_DEVICE_AVRDRAGON;
+#else
+    fprintf(stderr, "avrdude was compiled without usb support.\n");
+    return -1;
+#endif
+  }
+
+  strcpy(pgm->port, port);
+  serial_open(port, baud, &pgm->fd);
+
+  /*
+   * drain any extraneous input
+   */
+  jtagmkII_drain(pgm, 0);
+
+  if (jtagmkII_getsync(pgm, EMULATOR_MODE_JTAG) < 0)
+    return -1;
+
+  return 0;
+}
+
+
+static int jtagmkII_dragon_open_dw(PROGRAMMER * pgm, char * port)
+{
+  long baud;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_dragon_open_dw()\n", progname);
+
+  /*
+   * The JTAG ICE mkII always starts with a baud rate of 19200 Bd upon
+   * attaching.  If the config file or command-line parameters specify
+   * a higher baud rate, we switch to it later on, after establishing
+   * the connection with the ICE.
+   */
+  baud = 19200;
+
+  /*
+   * If the port name starts with "usb", divert the serial routines
+   * to the USB ones.  The serial_open() function for USB overrides
+   * the meaning of the "baud" parameter to be the USB device ID to
+   * search for.
+   */
+  if (strncmp(port, "usb", 3) == 0) {
+#if defined(HAVE_LIBUSB)
+    serdev = &usb_serdev;
+    baud = USB_DEVICE_AVRDRAGON;
+#else
+    fprintf(stderr, "avrdude was compiled without usb support.\n");
+    return -1;
+#endif
+  }
+
+  strcpy(pgm->port, port);
+  serial_open(port, baud, &pgm->fd);
+
+  /*
+   * drain any extraneous input
+   */
+  jtagmkII_drain(pgm, 0);
+
+  if (jtagmkII_getsync(pgm, EMULATOR_MODE_DEBUGWIRE) < 0)
+    return -1;
+
+  return 0;
+}
+
+
+static int jtagmkII_dragon_open_pdi(PROGRAMMER * pgm, char * port)
+{
+  long baud;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_dragon_open_pdi()\n", progname);
+
+  /*
+   * The JTAG ICE mkII always starts with a baud rate of 19200 Bd upon
+   * attaching.  If the config file or command-line parameters specify
+   * a higher baud rate, we switch to it later on, after establishing
+   * the connection with the ICE.
+   */
+  baud = 19200;
+
+  /*
+   * If the port name starts with "usb", divert the serial routines
+   * to the USB ones.  The serial_open() function for USB overrides
+   * the meaning of the "baud" parameter to be the USB device ID to
+   * search for.
+   */
+  if (strncmp(port, "usb", 3) == 0) {
+#if defined(HAVE_LIBUSB)
+    serdev = &usb_serdev;
+    baud = USB_DEVICE_AVRDRAGON;
+#else
+    fprintf(stderr, "avrdude was compiled without usb support.\n");
+    return -1;
+#endif
+  }
+
+  strcpy(pgm->port, port);
+  serial_open(port, baud, &pgm->fd);
+
+  /*
+   * drain any extraneous input
+   */
+  jtagmkII_drain(pgm, 0);
+
+  if (jtagmkII_getsync(pgm, EMULATOR_MODE_PDI) < 0)
+    return -1;
+
+  return 0;
+}
+
+
+void jtagmkII_close(PROGRAMMER * pgm)
+{
+  int status;
+  unsigned char buf[1], *resp, c;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_close()\n", progname);
+
+  if (PDATA(pgm)->device_descriptor_length) {
+    /* When in JTAG mode, restart target. */
+    buf[0] = CMND_GO;
+    if (verbose >= 2)
+      fprintf(stderr, "%s: jtagmkII_close(): Sending GO command: ",
+	      progname);
+    jtagmkII_send(pgm, buf, 1);
+
+    status = jtagmkII_recv(pgm, &resp);
+    if (status <= 0) {
+      if (verbose >= 2)
+	putc('\n', stderr);
+      fprintf(stderr,
+	      "%s: jtagmkII_close(): "
+	      "timeout/error communicating with programmer (status %d)\n",
+	      progname, status);
+    } else {
+      if (verbose >= 3) {
+	putc('\n', stderr);
+	jtagmkII_prmsg(pgm, resp, status);
+      } else if (verbose == 2)
+	fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+      c = resp[0];
+      free(resp);
+      if (c != RSP_OK) {
+	fprintf(stderr,
+		"%s: jtagmkII_close(): "
+		"bad response to GO command: %s\n",
+		progname, jtagmkII_get_rc(c));
+      }
+    }
+  }
+
+  buf[0] = CMND_SIGN_OFF;
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_close(): Sending sign-off command: ",
+	    progname);
+  jtagmkII_send(pgm, buf, 1);
+
+  status = jtagmkII_recv(pgm, &resp);
+  if (status <= 0) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkII_close(): "
+	    "timeout/error communicating with programmer (status %d)\n",
+	    progname, status);
+    return;
+  }
+  if (verbose >= 3) {
+    putc('\n', stderr);
+    jtagmkII_prmsg(pgm, resp, status);
+  } else if (verbose == 2)
+    fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+  c = resp[0];
+  free(resp);
+  if (c != RSP_OK) {
+    fprintf(stderr,
+	    "%s: jtagmkII_close(): "
+	    "bad response to sign-off command: %s\n",
+	    progname, jtagmkII_get_rc(c));
+  }
+
+  serial_close(&pgm->fd);
+  pgm->fd.ifd = -1;
+}
+
+static int jtagmkII_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+				int page_size, int n_bytes)
+{
+  int addr, block_size;
+  unsigned char *cmd;
+  unsigned char *resp;
+  unsigned char par[4];
+  int status, tries;
+  long otimeout = serial_recv_timeout;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_paged_write(.., %s, %d, %d)\n",
+	    progname, m->desc, page_size, n_bytes);
+
+  if (!(pgm->flag & PGM_FL_IS_DW) && jtagmkII_program_enable(pgm) < 0)
+    return -1;
+
+  if (page_size == 0) page_size = 256;
+
+  if ((cmd = malloc(page_size + 10)) == NULL) {
+    fprintf(stderr, "%s: jtagmkII_paged_write(): Out of memory\n",
+	    progname);
+    return -1;
+  }
+  if ( p->flags & AVRPART_HAS_PDI )
+  {
+   u32_to_b4( par, m->offset );
+   (void) jtagmkII_setparm( pgm, PAR_PDI_OFFSET_START, par );
+   u32_to_b4( par, m->offset + m->size );
+   (void) jtagmkII_setparm( pgm, PAR_PDI_OFFSET_END, par );
+  }
+
+  cmd[0] = CMND_WRITE_MEMORY;
+  cmd[1] = ( p->flags & AVRPART_HAS_PDI ) ? MTYPE_FLASH : MTYPE_FLASH_PAGE;
+  if (strcmp(m->desc, "flash") == 0) {
+    PDATA(pgm)->flash_pageaddr = (unsigned long)-1L;
+    page_size = PDATA(pgm)->flash_pagesize;
+  } else if (strcmp(m->desc, "eeprom") == 0) {
+    if (pgm->flag & PGM_FL_IS_DW) {
+      /*
+       * jtagmkII_paged_write() to EEPROM attempted while in
+       * DW mode.  Use jtagmkII_write_byte() instead.
+       */
+      for (addr = 0; addr < n_bytes; addr++) {
+	status = jtagmkII_write_byte(pgm, p, m, addr, m->buf[addr]);
+	report_progress(addr, n_bytes, NULL);
+	if (status < 0) {
+	  free(cmd);
+	  return -1;
+	}
+      }
+      free(cmd);
+      return n_bytes;
+    }
+    cmd[1] = ( p->flags & AVRPART_HAS_PDI ) ? MTYPE_EEPROM : MTYPE_EEPROM_PAGE;
+    PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L;
+    page_size = PDATA(pgm)->eeprom_pagesize;
+  }
+  serial_recv_timeout = 100;
+  for (addr = 0; addr < n_bytes; addr += page_size) {
+    report_progress(addr, n_bytes,NULL);
+
+    if ((n_bytes-addr) < page_size)
+      block_size = n_bytes - addr;
+    else
+      block_size = page_size;
+    if (verbose >= 3)
+      fprintf(stderr, "%s: jtagmkII_paged_write(): "
+	      "block_size at addr %d is %d\n",
+	      progname, addr, block_size);
+
+    u32_to_b4(cmd + 2, page_size);
+    u32_to_b4(cmd + 6, addr+m->offset );
+
+    /*
+     * The JTAG ICE will refuse to write anything but a full page, at
+     * least for the flash ROM.  If a partial page has been requested,
+     * set the remainder to 0xff.  (Maybe we should rather read back
+     * the existing contents instead before?  Doesn't matter much, as
+     * bits cannot be written to 1 anyway.)
+     */
+    memset(cmd + 10, 0xff, page_size);
+    memcpy(cmd + 10, m->buf + addr, block_size);
+
+    tries = 0;
+
+    retry:
+    if (verbose >= 2)
+      fprintf(stderr, "%s: jtagmkII_paged_write(): "
+	      "Sending write memory command: ",
+	      progname);
+    jtagmkII_send(pgm, cmd, page_size + 10);
+
+    status = jtagmkII_recv(pgm, &resp);
+    if (status <= 0) {
+      if (verbose >= 2)
+	putc('\n', stderr);
+      if (verbose >= 1)
+	fprintf(stderr,
+		"%s: jtagmkII_paged_write(): "
+		"timeout/error communicating with programmer (status %d)\n",
+		progname, status);
+      if (tries++ < 4) {
+	serial_recv_timeout *= 2;
+	goto retry;
+      }
+      fprintf(stderr,
+	      "%s: jtagmkII_paged_write(): fatal timeout/"
+	      "error communicating with programmer (status %d)\n",
+	      progname, status);
+      free(cmd);
+      serial_recv_timeout = otimeout;
+      return -1;
+    }
+    if (verbose >= 3) {
+      putc('\n', stderr);
+      jtagmkII_prmsg(pgm, resp, status);
+    } else if (verbose == 2)
+      fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+    if (resp[0] != RSP_OK) {
+      fprintf(stderr,
+	      "%s: jtagmkII_paged_write(): "
+	      "bad response to write memory command: %s\n",
+	      progname, jtagmkII_get_rc(resp[0]));
+      free(resp);
+      free(cmd);
+      serial_recv_timeout = otimeout;
+      return -1;
+    }
+    free(resp);
+  }
+
+  free(cmd);
+  serial_recv_timeout = otimeout;
+
+  return n_bytes;
+}
+
+static int jtagmkII_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+			       int page_size, int n_bytes)
+{
+  int addr, block_size;
+  unsigned char cmd[10];
+  unsigned char *resp;
+  int status, tries;
+  long otimeout = serial_recv_timeout;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_paged_load(.., %s, %d, %d)\n",
+	    progname, m->desc, page_size, n_bytes);
+
+  if (!(pgm->flag & PGM_FL_IS_DW) && jtagmkII_program_enable(pgm) < 0)
+    return -1;
+
+  page_size = m->readsize;
+
+  cmd[0] = CMND_READ_MEMORY;
+  cmd[1] = ( p->flags & AVRPART_HAS_PDI ) ? MTYPE_FLASH : MTYPE_FLASH_PAGE;
+  if (strcmp(m->desc, "eeprom") == 0) {
+    cmd[1] = ( p->flags & AVRPART_HAS_PDI ) ? MTYPE_EEPROM : MTYPE_EEPROM_PAGE;
+    if (pgm->flag & PGM_FL_IS_DW)
+      return -1;
+  } else if ( ( strcmp(m->desc, "prodsig") == 0 ) ) {
+    cmd[1] = MTYPE_PRODSIG;
+  } else if ( ( strcmp(m->desc, "usersig") == 0 ) ) {
+    cmd[1] = MTYPE_USERSIG;
+  }
+  serial_recv_timeout = 100;
+  for (addr = 0; addr < n_bytes; addr += page_size) {
+    report_progress(addr, n_bytes,NULL);
+
+    if ((n_bytes-addr) < page_size)
+      block_size = n_bytes - addr;
+    else
+      block_size = page_size;
+    if (verbose >= 3)
+      fprintf(stderr, "%s: jtagmkII_paged_load(): "
+	      "block_size at addr %d is %d\n",
+	      progname, addr, block_size);
+
+    u32_to_b4(cmd + 2, block_size);
+    u32_to_b4(cmd + 6, addr+m->offset );
+
+    tries = 0;
+
+    retry:
+    if (verbose >= 2)
+      fprintf(stderr, "%s: jtagmkII_paged_load(): Sending read memory command: ",
+	      progname);
+    jtagmkII_send(pgm, cmd, 10);
+
+    status = jtagmkII_recv(pgm, &resp);
+    if (status <= 0) {
+      if (verbose >= 2)
+	putc('\n', stderr);
+      if (verbose >= 1)
+	fprintf(stderr,
+		"%s: jtagmkII_paged_load(): "
+		"timeout/error communicating with programmer (status %d)\n",
+		progname, status);
+      if (tries++ < 4) {
+	serial_recv_timeout *= 2;
+	goto retry;
+      }
+      fprintf(stderr,
+	      "%s: jtagmkII_paged_load(): fatal timeout/"
+	      "error communicating with programmer (status %d)\n",
+	      progname, status);
+      serial_recv_timeout = otimeout;
+      return -1;
+    }
+    if (verbose >= 3) {
+      putc('\n', stderr);
+      jtagmkII_prmsg(pgm, resp, status);
+    } else if (verbose == 2)
+      fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+    if (resp[0] != RSP_MEMORY) {
+      fprintf(stderr,
+	      "%s: jtagmkII_paged_load(): "
+	      "bad response to read memory command: %s\n",
+	      progname, jtagmkII_get_rc(resp[0]));
+      free(resp);
+      serial_recv_timeout = otimeout;
+      return -1;
+    }
+    memcpy(m->buf + addr, resp + 1, status-1);
+    free(resp);
+  }
+  serial_recv_timeout = otimeout;
+
+  return n_bytes;
+}
+
+static int jtagmkII_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+			      unsigned long addr, unsigned char * value)
+{
+  unsigned char cmd[10];
+  unsigned char *resp = NULL, *cache_ptr = NULL;
+  int status, tries, unsupp;
+  unsigned long paddr = 0UL, *paddr_ptr = NULL;
+  unsigned int pagesize = 0;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_read_byte(.., %s, 0x%lx, ...)\n",
+	    progname, mem->desc, addr);
+
+  if (!(pgm->flag & PGM_FL_IS_DW) && jtagmkII_program_enable(pgm) < 0)
+    return -1;
+
+  cmd[0] = CMND_READ_MEMORY;
+  unsupp = 0;
+
+  addr += mem->offset;
+  cmd[1] = ( p->flags & AVRPART_HAS_PDI ) ? MTYPE_FLASH : MTYPE_FLASH_PAGE;
+  if (strcmp(mem->desc, "flash") == 0) {
+    pagesize = mem->page_size;
+    paddr = addr & ~(pagesize - 1);
+    paddr_ptr = &PDATA(pgm)->flash_pageaddr;
+    cache_ptr = PDATA(pgm)->flash_pagecache;
+  } else if (strcmp(mem->desc, "eeprom") == 0) {
+    if ( (pgm->flag & PGM_FL_IS_DW) || ( p->flags & AVRPART_HAS_PDI ) ) {
+      /* debugWire cannot use page access for EEPROM */
+      cmd[1] = MTYPE_EEPROM;
+    } else {
+      cmd[1] = MTYPE_EEPROM_PAGE;
+      pagesize = mem->page_size;
+      paddr = addr & ~(pagesize - 1);
+      paddr_ptr = &PDATA(pgm)->eeprom_pageaddr;
+      cache_ptr = PDATA(pgm)->eeprom_pagecache;
+    }
+  } else if (strcmp(mem->desc, "lfuse") == 0) {
+    cmd[1] = MTYPE_FUSE_BITS;
+    addr = 0;
+    if (pgm->flag & PGM_FL_IS_DW)
+      unsupp = 1;
+  } else if (strcmp(mem->desc, "hfuse") == 0) {
+    cmd[1] = MTYPE_FUSE_BITS;
+    addr = 1;
+    if (pgm->flag & PGM_FL_IS_DW)
+      unsupp = 1;
+  } else if (strcmp(mem->desc, "efuse") == 0) {
+    cmd[1] = MTYPE_FUSE_BITS;
+    addr = 2;
+    if (pgm->flag & PGM_FL_IS_DW)
+      unsupp = 1;
+  } else if (strcmp(mem->desc, "lock") == 0) {
+    cmd[1] = MTYPE_LOCK_BITS;
+    if (pgm->flag & PGM_FL_IS_DW)
+      unsupp = 1;
+  } else if (strncmp(mem->desc, "fuse", strlen("fuse")) == 0) {
+    cmd[1] = MTYPE_FUSE_BITS;
+  } else if (strcmp(mem->desc, "usersig") == 0) {
+    cmd[1] = MTYPE_USERSIG;
+  } else if (strcmp(mem->desc, "prodsig") == 0) {
+    cmd[1] = MTYPE_PRODSIG;
+  } else if (strcmp(mem->desc, "calibration") == 0) {
+    cmd[1] = MTYPE_OSCCAL_BYTE;
+    if (pgm->flag & PGM_FL_IS_DW)
+      unsupp = 1;
+  } else if (strcmp(mem->desc, "signature") == 0) {
+    cmd[1] = MTYPE_SIGN_JTAG;
+
+    if (pgm->flag & PGM_FL_IS_DW) {
+      /*
+       * In debugWire mode, there is no accessible memory area to read
+       * the signature from, but the essential two bytes can be read
+       * as a parameter from the ICE.
+       */
+      unsigned char parm[4];
+
+      switch (addr) {
+      case 0:
+	*value = 0x1E;		/* Atmel vendor ID */
+	break;
+
+      case 1:
+      case 2:
+	if (jtagmkII_getparm(pgm, PAR_TARGET_SIGNATURE, parm) < 0)
+	  return -1;
+	*value = parm[2 - addr];
+	break;
+
+      default:
+	fprintf(stderr, "%s: illegal address %lu for signature memory\n",
+		progname, addr);
+	return -1;
+      }
+      return 0;
+    }
+
+  }
+
+  /*
+   * If the respective memory area is not supported under debugWire,
+   * leave here.
+   */
+  if (unsupp) {
+    *value = 42;
+    return -1;
+  }
+
+  /*
+   * To improve the read speed, we used paged reads for flash and
+   * EEPROM, and cache the results in a page cache.
+   *
+   * Page cache validation is based on "{flash,eeprom}_pageaddr"
+   * (holding the base address of the most recent cache fill
+   * operation).  This variable is set to (unsigned long)-1L when the
+   * cache needs to be invalidated.
+   */
+  if (pagesize && paddr == *paddr_ptr) {
+    *value = cache_ptr[addr & (pagesize - 1)];
+    return 0;
+  }
+
+  if (pagesize) {
+    u32_to_b4(cmd + 2, pagesize);
+    u32_to_b4(cmd + 6, paddr);
+  } else {
+    u32_to_b4(cmd + 2, 1);
+    u32_to_b4(cmd + 6, addr);
+  }
+
+  tries = 0;
+  retry:
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_read_byte(): Sending read memory command: ",
+	    progname);
+  jtagmkII_send(pgm, cmd, 10);
+
+  status = jtagmkII_recv(pgm, &resp);
+  if (status <= 0) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    if (verbose >= 1)
+      fprintf(stderr,
+	      "%s: jtagmkII_read_byte(): "
+	      "timeout/error communicating with programmer (status %d)\n",
+	      progname, status);
+    if (tries++ < 3)
+      goto retry;
+    fprintf(stderr,
+	    "%s: jtagmkII_read_byte(): "
+	    "fatal timeout/error communicating with programmer (status %d)\n",
+	    progname, status);
+    if (status < 0)
+      resp = 0;
+    goto fail;
+  }
+  if (verbose >= 3) {
+    putc('\n', stderr);
+    jtagmkII_prmsg(pgm, resp, status);
+  } else if (verbose == 2)
+    fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+  if (resp[0] != RSP_MEMORY) {
+    fprintf(stderr,
+	    "%s: jtagmkII_read_byte(): "
+	    "bad response to read memory command: %s\n",
+	    progname, jtagmkII_get_rc(resp[0]));
+    goto fail;
+  }
+
+  if (pagesize) {
+    *paddr_ptr = paddr;
+    memcpy(cache_ptr, resp + 1, pagesize);
+    *value = cache_ptr[addr & (pagesize - 1)];
+  } else
+    *value = resp[1];
+
+  free(resp);
+  return 0;
+
+fail:
+  free(resp);
+  return -1;
+}
+
+static int jtagmkII_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+			       unsigned long addr, unsigned char data)
+{
+  unsigned char cmd[11];
+  unsigned char *resp = NULL, writedata;
+  int status, tries, need_progmode = 1, unsupp = 0;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_write_byte(.., %s, 0x%lx, ...)\n",
+	    progname, mem->desc, addr);
+
+  addr += mem->offset;
+
+  writedata = data;
+  cmd[0] = CMND_WRITE_MEMORY;
+  cmd[1] = ( p->flags & AVRPART_HAS_PDI ) ? MTYPE_FLASH : MTYPE_SPM;
+  if (strcmp(mem->desc, "flash") == 0) {
+     need_progmode = 0;
+     PDATA(pgm)->flash_pageaddr = (unsigned long)-1L;
+     if (pgm->flag & PGM_FL_IS_DW)
+       unsupp = 1;
+  } else if (strcmp(mem->desc, "eeprom") == 0) {
+    cmd[1] = MTYPE_EEPROM;
+    need_progmode = 0;
+    PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L;
+  } else if (strcmp(mem->desc, "lfuse") == 0) {
+    cmd[1] = MTYPE_FUSE_BITS;
+    addr = 0;
+    if (pgm->flag & PGM_FL_IS_DW)
+      unsupp = 1;
+  } else if (strcmp(mem->desc, "hfuse") == 0) {
+    cmd[1] = MTYPE_FUSE_BITS;
+    addr = 1;
+    if (pgm->flag & PGM_FL_IS_DW)
+      unsupp = 1;
+  } else if (strcmp(mem->desc, "efuse") == 0) {
+    cmd[1] = MTYPE_FUSE_BITS;
+    addr = 2;
+    if (pgm->flag & PGM_FL_IS_DW)
+      unsupp = 1;
+  } else if (strncmp(mem->desc, "fuse", strlen("fuse")) == 0) {
+    cmd[1] = MTYPE_FUSE_BITS;
+  } else if (strcmp(mem->desc, "usersig") == 0) {
+    cmd[1] = MTYPE_USERSIG;
+  } else if (strcmp(mem->desc, "prodsig") == 0) {
+    cmd[1] = MTYPE_PRODSIG;
+  } else if (strcmp(mem->desc, "lock") == 0) {
+    cmd[1] = MTYPE_LOCK_BITS;
+    if (pgm->flag & PGM_FL_IS_DW)
+      unsupp = 1;
+  } else if (strcmp(mem->desc, "calibration") == 0) {
+    cmd[1] = MTYPE_OSCCAL_BYTE;
+    if (pgm->flag & PGM_FL_IS_DW)
+      unsupp = 1;
+  } else if (strcmp(mem->desc, "signature") == 0) {
+    cmd[1] = MTYPE_SIGN_JTAG;
+    if (pgm->flag & PGM_FL_IS_DW)
+      unsupp = 1;
+  }
+
+  if (unsupp)
+    return -1;
+
+  if (need_progmode) {
+    if (jtagmkII_program_enable(pgm) < 0)
+      return -1;
+  } else {
+    if (jtagmkII_program_disable(pgm) < 0)
+      return -1;
+  }
+
+  u32_to_b4(cmd + 2, 1);
+  u32_to_b4(cmd + 6, addr);
+  cmd[10] = writedata;
+
+  tries = 0;
+  retry:
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_write_byte(): Sending write memory command: ",
+	    progname);
+  jtagmkII_send(pgm, cmd, 11);
+
+  status = jtagmkII_recv(pgm, &resp);
+  if (status <= 0) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    if (verbose > 1)
+      fprintf(stderr,
+	      "%s: jtagmkII_write_byte(): "
+	      "timeout/error communicating with programmer (status %d)\n",
+	      progname, status);
+    if (tries++ < 3)
+      goto retry;
+    fprintf(stderr,
+	    "%s: jtagmkII_write_byte(): "
+	    "fatal timeout/error communicating with programmer (status %d)\n",
+	    progname, status);
+    goto fail;
+  }
+  if (verbose >= 3) {
+    putc('\n', stderr);
+    jtagmkII_prmsg(pgm, resp, status);
+  } else if (verbose == 2)
+    fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+  if (resp[0] != RSP_OK) {
+    fprintf(stderr,
+	    "%s: jtagmkII_write_byte(): "
+	    "bad response to write memory command: %s\n",
+	    progname, jtagmkII_get_rc(resp[0]));
+    goto fail;
+  }
+
+  free(resp);
+  return 0;
+
+fail:
+  free(resp);
+  return -1;
+}
+
+
+/*
+ * Set the JTAG clock.  The actual frequency is quite a bit of
+ * guesswork, based on the values claimed by AVR Studio.  Inside the
+ * JTAG ICE, the value is the delay count of a delay loop between the
+ * JTAG clock edges.  A count of 0 bypasses the delay loop.
+ *
+ * As the STK500 expresses it as a period length (and we actualy do
+ * program a period length as well), we rather call it by that name.
+ */
+static int jtagmkII_set_sck_period(PROGRAMMER * pgm, double v)
+{
+  unsigned char dur;
+
+  v = 1 / v;			/* convert to frequency */
+  if (v >= 6.4e6)
+    dur = 0;
+  else if (v >= 2.8e6)
+    dur = 1;
+  else if (v >= 20.9e3)
+    dur = (unsigned char)(5.35e6 / v);
+  else
+    dur = 255;
+
+  return jtagmkII_setparm(pgm, PAR_OCD_JTAG_CLK, &dur);
+}
+
+
+/*
+ * Read an emulator parameter.  As the maximal parameter length is 4
+ * bytes by now, we always copy out 4 bytes to *value, so the caller
+ * must have allocated sufficient space.
+ */
+int jtagmkII_getparm(PROGRAMMER * pgm, unsigned char parm,
+		     unsigned char * value)
+{
+  int status;
+  unsigned char buf[2], *resp, c;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_getparm()\n", progname);
+
+  buf[0] = CMND_GET_PARAMETER;
+  buf[1] = parm;
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_getparm(): "
+	    "Sending get parameter command (parm 0x%02x): ",
+	    progname, parm);
+  jtagmkII_send(pgm, buf, 2);
+
+  status = jtagmkII_recv(pgm, &resp);
+  if (status <= 0) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkII_getparm(): "
+	    "timeout/error communicating with programmer (status %d)\n",
+	    progname, status);
+    return -1;
+  }
+  if (verbose >= 3) {
+    putc('\n', stderr);
+    jtagmkII_prmsg(pgm, resp, status);
+  } else if (verbose == 2)
+    fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+  c = resp[0];
+  if (c != RSP_PARAMETER) {
+    fprintf(stderr,
+	    "%s: jtagmkII_getparm(): "
+	    "bad response to get parameter command: %s\n",
+	    progname, jtagmkII_get_rc(c));
+    free(resp);
+    return -1;
+  }
+
+  memcpy(value, resp + 1, 4);
+  free(resp);
+
+  return 0;
+}
+
+/*
+ * Write an emulator parameter.
+ */
+static int jtagmkII_setparm(PROGRAMMER * pgm, unsigned char parm,
+			    unsigned char * value)
+{
+  int status;
+  /*
+   * As the maximal parameter length is 4 bytes, we use a fixed-length
+   * buffer, as opposed to malloc()ing it.
+   */
+  unsigned char buf[2 + 4], *resp, c;
+  size_t size;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_setparm()\n", progname);
+
+  switch (parm) {
+  case PAR_HW_VERSION: size = 2; break;
+  case PAR_FW_VERSION: size = 4; break;
+  case PAR_EMULATOR_MODE: size = 1; break;
+  case PAR_BAUD_RATE: size = 1; break;
+  case PAR_OCD_VTARGET: size = 2; break;
+  case PAR_OCD_JTAG_CLK: size = 1; break;
+  case PAR_TIMERS_RUNNING: size = 1; break;
+  case PAR_DAISY_CHAIN_INFO: size = 4; break;
+  case PAR_PDI_OFFSET_START:
+  case PAR_PDI_OFFSET_END: size = 4; break;
+  default:
+    fprintf(stderr, "%s: jtagmkII_setparm(): unknown parameter 0x%02x\n",
+	    progname, parm);
+    return -1;
+  }
+
+  buf[0] = CMND_SET_PARAMETER;
+  buf[1] = parm;
+  memcpy(buf + 2, value, size);
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_setparm(): "
+	    "Sending set parameter command (parm 0x%02x, %u bytes): ",
+	    progname, parm, (unsigned)size);
+  jtagmkII_send(pgm, buf, size + 2);
+
+  status = jtagmkII_recv(pgm, &resp);
+  if (status <= 0) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkII_setparm(): "
+	    "timeout/error communicating with programmer (status %d)\n",
+	    progname, status);
+    return -1;
+  }
+  if (verbose >= 3) {
+    putc('\n', stderr);
+    jtagmkII_prmsg(pgm, resp, status);
+  } else if (verbose == 2)
+    fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+  c = resp[0];
+  free(resp);
+  if (c != RSP_OK) {
+    fprintf(stderr,
+	    "%s: jtagmkII_setparm(): "
+	    "bad response to set parameter command: %s\n",
+	    progname, jtagmkII_get_rc(c));
+    return -1;
+  }
+
+  return 0;
+}
+
+
+static void jtagmkII_display(PROGRAMMER * pgm, const char * p)
+{
+  unsigned char hw[4], fw[4];
+
+  if (jtagmkII_getparm(pgm, PAR_HW_VERSION, hw) < 0 ||
+      jtagmkII_getparm(pgm, PAR_FW_VERSION, fw) < 0)
+    return;
+
+  fprintf(stderr, "%sM_MCU hardware version: %d\n", p, hw[0]);
+  fprintf(stderr, "%sM_MCU firmware version: %d.%02d\n", p, fw[1], fw[0]);
+  fprintf(stderr, "%sS_MCU hardware version: %d\n", p, hw[1]);
+  fprintf(stderr, "%sS_MCU firmware version: %d.%02d\n", p, fw[3], fw[2]);
+  fprintf(stderr, "%sSerial number:          %02x:%02x:%02x:%02x:%02x:%02x\n",
+	  p, PDATA(pgm)->serno[0], PDATA(pgm)->serno[1], PDATA(pgm)->serno[2], PDATA(pgm)->serno[3], PDATA(pgm)->serno[4], PDATA(pgm)->serno[5]);
+
+  jtagmkII_print_parms1(pgm, p);
+
+  return;
+}
+
+
+static void jtagmkII_print_parms1(PROGRAMMER * pgm, const char * p)
+{
+  unsigned char vtarget[4], jtag_clock[4];
+  char clkbuf[20];
+  double clk;
+
+  if (jtagmkII_getparm(pgm, PAR_OCD_VTARGET, vtarget) < 0)
+    return;
+
+  fprintf(stderr, "%sVtarget         : %.1f V\n", p,
+	  b2_to_u16(vtarget) / 1000.0);
+
+  if ((pgm->flag & PGM_FL_IS_JTAG)) {
+    if (jtagmkII_getparm(pgm, PAR_OCD_JTAG_CLK, jtag_clock) < 0)
+      return;
+
+    if (jtag_clock[0] == 0) {
+      strcpy(clkbuf, "6.4 MHz");
+      clk = 6.4e6;
+    } else if (jtag_clock[0] == 1) {
+      strcpy(clkbuf, "2.8 MHz");
+      clk = 2.8e6;
+    } else if (jtag_clock[0] <= 5) {
+      sprintf(clkbuf, "%.1f MHz", 5.35 / (double)jtag_clock[0]);
+      clk = 5.35e6 / (double)jtag_clock[0];
+    } else {
+      sprintf(clkbuf, "%.1f kHz", 5.35e3 / (double)jtag_clock[0]);
+      clk = 5.35e6 / (double)jtag_clock[0];
+
+      fprintf(stderr, "%sJTAG clock      : %s (%.1f us)\n", p, clkbuf,
+	      1.0e6 / clk);
+    }
+  }
+
+  return;
+}
+
+static void jtagmkII_print_parms(PROGRAMMER * pgm)
+{
+  jtagmkII_print_parms1(pgm, "");
+}
+
+#ifdef __OBJC__
+#pragma mark -
+#endif
+
+static int jtagmkII_avr32_reset(PROGRAMMER * pgm, unsigned char val,
+                                unsigned char ret1, unsigned char ret2)
+{
+  int status;
+  unsigned char buf[3], *resp;
+
+  if(verbose) fprintf(stderr,
+          "%s: jtagmkII_avr32_reset(%2.2x)\n",
+          progname, val);
+
+  buf[0] = CMND_GET_IR;
+  buf[1] = 0x0C;
+  status = jtagmkII_send(pgm, buf, 2);
+  if(status < 0) return -1;
+
+  status = jtagmkII_recv(pgm, &resp);
+  if (status != 2 || resp[0] != 0x87 || resp[1] != ret1) {
+    if(verbose) fprintf(stderr,
+	      "%s: jtagmkII_avr32_reset(): "
+	      "Get_IR, expecting %2.2x but got %2.2x\n",
+	      progname, ret1, resp[1]);
+
+    //return -1;
+  }
+
+  buf[0] = CMND_GET_xxx;
+  buf[1] = 5;
+  buf[2] = val;
+  status = jtagmkII_send(pgm, buf, 3);
+  if(status < 0) return -1;
+
+  status = jtagmkII_recv(pgm, &resp);
+  if (status != 2 || resp[0] != 0x87 || resp[1] != ret2) {
+    if(verbose) fprintf(stderr,
+	      "%s: jtagmkII_avr32_reset(): "
+	      "Get_XXX, expecting %2.2x but got %2.2x\n",
+	      progname, ret2, resp[1]);
+    //return -1;
+  }
+
+  return 0;
+}
+
+// At init: AVR32_RESET_READ_IR | AVR32_RESET_READ_READ_CHIPINFO
+static int jtagmkII_reset32(PROGRAMMER * pgm, unsigned short flags)
+{
+  int status, j, lineno;
+  unsigned char *resp, buf[3];
+  unsigned long val=0;
+  unsigned long config0, config1;
+
+  if(verbose) fprintf(stderr,
+          "%s: jtagmkII_reset32(%2.2x)\n",
+          progname, flags);
+
+  status = -1;
+
+  // Happens at the start of a programming operation
+  if(flags & AVR32_RESET_READ) {
+    buf[0] = CMND_GET_IR;
+    buf[1] = 0x11;
+    status = jtagmkII_send(pgm, buf, 2);
+    if(status < 0) {lineno = __LINE__; goto eRR;}
+
+    status = jtagmkII_recv(pgm, &resp);
+    if (status != 2 || resp[0] != 0x87 || resp[1] != 01)
+      {lineno = __LINE__; goto eRR;};
+  }
+
+  if(flags & (AVR32_RESET_WRITE | AVR32_SET4RUNNING)) {
+    // AVR_RESET(0x1F)
+    status = jtagmkII_avr32_reset(pgm, 0x1F, 0x01, 0x00);
+    if(status < 0) {lineno = __LINE__; goto eRR;}
+    // AVR_RESET(0x07)
+    status = jtagmkII_avr32_reset(pgm, 0x07, 0x11, 0x1F);
+    if(status < 0) {lineno = __LINE__; goto eRR;}
+  }
+
+  //if(flags & AVR32_RESET_COMMON)
+  {
+    val = jtagmkII_read_SABaddr(pgm, AVR32_DS, 0x01);
+    if(val != 0) {lineno = __LINE__; goto eRR;}
+    val = jtagmkII_read_SABaddr(pgm, AVR32_DC, 0x01);
+    if(val != 0) {lineno = __LINE__; goto eRR;}
+  }
+
+  if(flags & (AVR32_RESET_READ | AVR32_RESET_CHIP_ERASE)) {
+    status = jtagmkII_write_SABaddr(pgm, AVR32_DC, 0x01,
+                                    AVR32_DC_DBE | AVR32_DC_DBR);
+    if(status < 0) return -1;
+  }
+
+  if(flags & (AVR32_RESET_WRITE | AVR32_SET4RUNNING)) {
+    status = jtagmkII_write_SABaddr(pgm, AVR32_DC, 0x01,
+             AVR32_DC_ABORT | AVR32_DC_RESET | AVR32_DC_DBE | AVR32_DC_DBR);
+    if(status < 0) return -1;
+    for(j=0; j<21; ++j) {
+      val = jtagmkII_read_SABaddr(pgm, AVR32_DS, 0x01);
+    }
+    if(val != 0x04000000) {lineno = __LINE__; goto eRR;}
+
+    // AVR_RESET(0x00)
+    status = jtagmkII_avr32_reset(pgm, 0x00, 0x01, 0x07);
+    if(status < 0) {lineno = __LINE__; goto eRR;}
+  }
+//  if(flags & (AVR32_RESET_READ | AVR32_RESET_WRITE))
+  {
+    for(j=0; j<2; ++j) {
+      val = jtagmkII_read_SABaddr(pgm, AVR32_DS, 0x01);
+      if(val == ERROR_SAB) {lineno = __LINE__; goto eRR;}
+      if((val&0x05000020) != 0x05000020) {lineno = __LINE__; goto eRR;}
+    }
+  }
+
+  //if(flags & (AVR32_RESET_READ | AVR32_RESET_WRITE | AVR32_RESET_CHIP_ERASE))
+  {
+    status = jtagmkII_write_SABaddr(pgm, AVR32_DINST, 0x01, 0xe7b00044);  // mtdr 272, R0
+    if(status < 0) {lineno = __LINE__; goto eRR;}
+
+    val = jtagmkII_read_SABaddr(pgm, AVR32_DCSR, 0x01);
+    if(val != 0x00000001) {lineno = __LINE__; goto eRR;}
+
+    val = jtagmkII_read_SABaddr(pgm, AVR32_DCCPU, 0x01);
+    if(val != 0x00000000) {lineno = __LINE__; goto eRR;}
+  }
+
+  // Read chip configuration - common for all
+  if(flags & (AVR32_RESET_READ | AVR32_RESET_WRITE | AVR32_RESET_CHIP_ERASE)) {
+    for(j=0; j<2; ++j) {
+      val = jtagmkII_read_SABaddr(pgm, AVR32_DS, 0x01);
+      if(val == ERROR_SAB) {lineno = __LINE__; goto eRR;}
+      if((val&0x05000020) != 0x05000020) {lineno = __LINE__; goto eRR;}
+    }
+
+    status = jtagmkII_write_SABaddr(pgm, AVR32_DINST, 0x01, 0xe7b00044);  // mtdr 272, R0
+    if(status < 0) {lineno = __LINE__; goto eRR;}
+
+    val = jtagmkII_read_SABaddr(pgm, AVR32_DCSR, 0x01);
+    if(val != 0x00000001) {lineno = __LINE__; goto eRR;}
+
+    val = jtagmkII_read_SABaddr(pgm, AVR32_DCCPU, 0x01);
+    if(val != 0x00000000) {lineno = __LINE__; goto eRR;}
+
+    status = jtagmkII_write_SABaddr(pgm, AVR32_DINST, 0x01, 0xe1b00040);  // mfsr R0, 256
+    if(status < 0) {lineno = __LINE__; goto eRR;}
+
+    status = jtagmkII_write_SABaddr(pgm, AVR32_DINST, 0x01, 0xe7b00044);  // mtdr 272, R0
+    if(status < 0) {lineno = __LINE__; goto eRR;}
+
+    val = jtagmkII_read_SABaddr(pgm, AVR32_DCSR, 0x01);
+    if(val != 0x00000001) {lineno = __LINE__; goto eRR;}
+
+    val = jtagmkII_read_SABaddr(pgm, AVR32_DCCPU, 0x01);
+    if(val == ERROR_SAB) {lineno = __LINE__; goto eRR;}
+    config0 = val;  // 0x0204098b
+
+    status = jtagmkII_write_SABaddr(pgm, AVR32_DCEMU, 0x01, 0x00000000);
+    if(status < 0) {lineno = __LINE__; goto eRR;}
+
+    status = jtagmkII_write_SABaddr(pgm, AVR32_DINST, 0x01, 0xe5b00045);  // mtdr R0, 276
+    if(status < 0) {lineno = __LINE__; goto eRR;}
+
+    val = jtagmkII_read_SABaddr(pgm, AVR32_DS, 0x01);
+    if(val == ERROR_SAB) {lineno = __LINE__; goto eRR;}
+    if((val&0x05000020) != 0x05000020) {lineno = __LINE__; goto eRR;}
+
+    status = jtagmkII_write_SABaddr(pgm, AVR32_DINST, 0x01, 0xe7b00044);  // mtdr 272, R0
+    if(status < 0) {lineno = __LINE__; goto eRR;}
+
+    val = jtagmkII_read_SABaddr(pgm, AVR32_DCSR, 0x01);
+    if(val != 0x00000001) {lineno = __LINE__; goto eRR;}
+
+    val = jtagmkII_read_SABaddr(pgm, AVR32_DCCPU, 0x01);
+    if(val != 0x00000000) {lineno = __LINE__; goto eRR;}
+
+    status = jtagmkII_write_SABaddr(pgm, AVR32_DINST, 0x01, 0xe1b00041);  // mfsr R0, 260
+    if(status < 0) {lineno = __LINE__; goto eRR;}
+    status = jtagmkII_write_SABaddr(pgm, AVR32_DINST, 0x01, 0xe7b00044);  // mtdr 272, R0
+    if(status < 0) {lineno = __LINE__; goto eRR;}
+
+    val = jtagmkII_read_SABaddr(pgm, AVR32_DCSR, 0x01);
+    if(val != 0x00000001) {lineno = __LINE__; goto eRR;}
+    val = jtagmkII_read_SABaddr(pgm, AVR32_DCCPU, 0x01);
+    if(val == ERROR_SAB) {lineno = __LINE__; goto eRR;}
+    config1 = val;  // 0x00800000
+
+    status = jtagmkII_write_SABaddr(pgm, AVR32_DCEMU, 0x01, 0x00000000);
+    if(status < 0) {lineno = __LINE__; goto eRR;}
+    status = jtagmkII_write_SABaddr(pgm, AVR32_DINST, 0x01, 0xe5b00045);  // mtdr R0, 276
+    if(status < 0) {lineno = __LINE__; goto eRR;}
+
+    val = jtagmkII_read_SABaddr(pgm, 0x00000010, 0x06); // need to recheck who does this...
+    if(val != 0x00000000) {lineno = __LINE__; goto eRR;}
+  }
+
+  if(flags & AVR32_RESET_CHIP_ERASE) {
+    status = jtagmkII_avr32_reset(pgm, 0x1f, 0x01, 0x00);
+    if(status < 0) {lineno = __LINE__; goto eRR;}
+    status = jtagmkII_avr32_reset(pgm, 0x01, 0x11, 0x1f);
+    if(status < 0) {lineno = __LINE__; goto eRR;}
+  }
+
+  if(flags & AVR32_SET4RUNNING) {
+    status = jtagmkII_write_SABaddr(pgm, AVR32_DINST, 0x01, 0xe1b00014);  // mfsr R0, 80
+    if(status < 0) {lineno = __LINE__; goto eRR;}
+
+    status = jtagmkII_write_SABaddr(pgm, AVR32_DINST, 0x01, 0xe7b00044);  // mtdr 272, R0
+    if(status < 0) {lineno = __LINE__; goto eRR;}
+
+    val = jtagmkII_read_SABaddr(pgm, AVR32_DCSR, 0x01);
+    if(val != 0x00000001) {lineno = __LINE__; goto eRR;}
+
+    val = jtagmkII_read_SABaddr(pgm, AVR32_DCCPU, 0x01);
+    if(val == ERROR_SAB) {lineno = __LINE__; goto eRR;}
+    config0 = val;  // 0x0204098b
+
+    status = jtagmkII_write_SABaddr(pgm, AVR32_DCEMU, 0x01, 0x00000000);
+    if(status < 0) {lineno = __LINE__; goto eRR;}
+
+    status = jtagmkII_write_SABaddr(pgm, AVR32_DINST, 0x01, 0xe5b00045);  // mfdr R0, 276
+    if(status < 0) {lineno = __LINE__; goto eRR;}
+
+    val = jtagmkII_read_SABaddr(pgm, AVR32_DS, 0x01);
+    if(val == ERROR_SAB) {lineno = __LINE__; goto eRR;}
+    if((val&0x05000020) != 0x05000020) {lineno = __LINE__; goto eRR;}
+
+    status = jtagmkII_write_SABaddr(pgm, AVR32_DINST, 0x01, 0xd623d703);  // retd
+    if(status < 0) {lineno = __LINE__; goto eRR;}
+  }
+
+  return 0;
+
+  eRR:
+    fprintf(stderr,
+	    "%s: jtagmkII_reset32(): "
+	    "failed at line %d (status=%x val=%lx)\n",
+	    progname, lineno, status, val);
+    return -1;
+}
+
+static int jtagmkII_smc_init32(PROGRAMMER * pgm)
+{
+  int status, lineno;
+  unsigned long val;
+
+  // HMATRIX 0xFFFF1000
+  status = jtagmkII_write_SABaddr(pgm, 0xffff1018, 0x05, 0x04000000);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+  status = jtagmkII_write_SABaddr(pgm, 0xffff1024, 0x05, 0x04000000);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+  status = jtagmkII_write_SABaddr(pgm, 0xffff1008, 0x05, 0x04000000);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+  status = jtagmkII_write_SABaddr(pgm, 0xffff1078, 0x05, 0x04000000);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+  status = jtagmkII_write_SABaddr(pgm, 0xffff1088, 0x05, 0x04000000);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+
+  status = jtagmkII_write_SABaddr(pgm, 0xffff1018, 0x05, 0x08000000);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+  status = jtagmkII_write_SABaddr(pgm, 0xffff1024, 0x05, 0x08000000);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+  status = jtagmkII_write_SABaddr(pgm, 0xffff1008, 0x05, 0x08000000);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+  status = jtagmkII_write_SABaddr(pgm, 0xffff1078, 0x05, 0x08000000);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+  status = jtagmkII_write_SABaddr(pgm, 0xffff1088, 0x05, 0x08000000);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+
+  status = jtagmkII_write_SABaddr(pgm, 0xffff1018, 0x05, 0x10000000);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+  status = jtagmkII_write_SABaddr(pgm, 0xffff1024, 0x05, 0x10000000);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+  status = jtagmkII_write_SABaddr(pgm, 0xffff1008, 0x05, 0x10000000);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+  status = jtagmkII_write_SABaddr(pgm, 0xffff1078, 0x05, 0x10000000);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+  status = jtagmkII_write_SABaddr(pgm, 0xffff1088, 0x05, 0x10000000);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+
+  status = jtagmkII_write_SABaddr(pgm, 0xffff1018, 0x05, 0x00020000);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+  status = jtagmkII_write_SABaddr(pgm, 0xffff1024, 0x05, 0x00020000);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+  status = jtagmkII_write_SABaddr(pgm, 0xffff1008, 0x05, 0x00020000);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+  status = jtagmkII_write_SABaddr(pgm, 0xffff1078, 0x05, 0x00020000);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+  status = jtagmkII_write_SABaddr(pgm, 0xffff1088, 0x05, 0x00020000);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+
+  status = jtagmkII_write_SABaddr(pgm, 0xffff1018, 0x05, 0x02000000);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+  status = jtagmkII_write_SABaddr(pgm, 0xffff1024, 0x05, 0x02000000);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+  status = jtagmkII_write_SABaddr(pgm, 0xffff1008, 0x05, 0x02000000);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+  status = jtagmkII_write_SABaddr(pgm, 0xffff1078, 0x05, 0x02000000);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+  status = jtagmkII_write_SABaddr(pgm, 0xffff1088, 0x05, 0x02000000);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+
+  status = jtagmkII_write_SABaddr(pgm, 0xfffe1c00, 0x05, 0x00010001);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+  status = jtagmkII_write_SABaddr(pgm, 0xfffe1c04, 0x05, 0x05070a0b);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+  status = jtagmkII_write_SABaddr(pgm, 0xfffe1c08, 0x05, 0x000b000c);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+  status = jtagmkII_write_SABaddr(pgm, 0xfffe1c0c, 0x05, 0x00031103);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+
+  // switchToClockSource
+  val = jtagmkII_read_SABaddr(pgm, 0xffff0c28, 0x05);
+  if (val != 0x00000000) {lineno = __LINE__; goto eRR;} // OSC 0
+  status = jtagmkII_write_SABaddr(pgm, 0xffff0c28, 0x05, 0x0000607);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+  val = jtagmkII_read_SABaddr(pgm, 0xffff0c00, 0x05);
+  if (val != 0x00000000) {lineno = __LINE__; goto eRR;} // PLL 0
+  status = jtagmkII_write_SABaddr(pgm, 0xffff0c00, 0x05, 0x0000004);
+  if (status < 0) {lineno = __LINE__; goto eRR;} // Power Manager
+  status = jtagmkII_write_SABaddr(pgm, 0xffff0c00, 0x05, 0x0000005);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+
+  usleep(1000000);
+
+  val = jtagmkII_read_SABaddr(pgm, 0xfffe1408, 0x05);
+  if (val != 0x0000a001) {lineno = __LINE__; goto eRR;} // PLL 0
+
+  // need a small delay to let clock stabliize
+  usleep(50*1000);
+
+  return 0;
+
+  eRR:
+    fprintf(stderr,
+	    "%s: jtagmkII_smc_init32(): "
+	    "failed at line %d\n",
+	    progname, lineno);
+    return -1;
+}
+
+
+/*
+ * initialize the AVR device and prepare it to accept commands
+ */
+static int jtagmkII_initialize32(PROGRAMMER * pgm, AVRPART * p)
+{
+  int status, j;
+  unsigned char buf[6], *resp;
+
+  if (jtagmkII_setparm(pgm, PAR_DAISY_CHAIN_INFO, PDATA(pgm)->jtagchain) < 0) {
+    fprintf(stderr, "%s: jtagmkII_initialize(): Failed to setup JTAG chain\n",
+            progname);
+    return -1;
+  }
+
+  free(PDATA(pgm)->flash_pagecache);
+  free(PDATA(pgm)->eeprom_pagecache);
+  if ((PDATA(pgm)->flash_pagecache = malloc(PDATA(pgm)->flash_pagesize)) == NULL) {
+    fprintf(stderr, "%s: jtagmkII_initialize(): Out of memory\n",
+	    progname);
+    return -1;
+  }
+  if ((PDATA(pgm)->eeprom_pagecache = malloc(PDATA(pgm)->eeprom_pagesize)) == NULL) {
+    fprintf(stderr, "%s: jtagmkII_initialize32(): Out of memory\n",
+	    progname);
+    free(PDATA(pgm)->flash_pagecache);
+    return -1;
+  }
+  PDATA(pgm)->flash_pageaddr = PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L;
+
+  for(j=0; j<2; ++j) {
+    buf[0] = CMND_GET_IR;
+    buf[1] = 0x1;
+    if(jtagmkII_send(pgm, buf, 2) < 0)
+      return -1;
+    status = jtagmkII_recv(pgm, &resp);
+    if(status <= 0 || resp[0] != 0x87) {
+      if (verbose >= 2)
+        putc('\n', stderr);
+      fprintf(stderr,
+                "%s: jtagmkII_initialize32(): "
+                "timeout/error communicating with programmer (status %d)\n",
+                progname, status);
+      return -1;
+    }
+    free(resp);
+
+    memset(buf, 0, sizeof(buf));
+    buf[0] = CMND_GET_xxx;
+    buf[1] = 0x20;
+    if(jtagmkII_send(pgm, buf, 6) < 0)
+      return -1;
+    status = jtagmkII_recv(pgm, &resp);
+    if(status <= 0 || resp[0] != 0x87) {
+      if (verbose >= 2)
+        putc('\n', stderr);
+      fprintf(stderr,
+                "%s: jtagmkII_initialize32(): "
+                "timeout/error communicating with programmer (status %d)\n",
+                progname, status);
+      return -1;
+    }
+
+    if (status != 5 ||
+    resp[2] != p->signature[0] ||
+    resp[3] != p->signature[1] ||
+    resp[4] != p->signature[2]) {
+      fprintf(stderr,
+          "%s: Expected signature for %s is %02X %02X %02X\n",
+          progname, p->desc,
+          p->signature[0], p->signature[1], p->signature[2]);
+      if (!ovsigck) {
+        fprintf(stderr, "%sDouble check chip, "
+        "or use -F to override this check.\n",
+                progbuf);
+        return -1;
+      }
+    }
+    free(resp);
+  }
+
+  return 0;
+}
+
+static int jtagmkII_chip_erase32(PROGRAMMER * pgm, AVRPART * p)
+{
+  int status=0, loops;
+  unsigned char *resp, buf[3], x, ret[4], *retP;
+  unsigned long val=0;
+  unsigned int lineno;
+
+  if(verbose) fprintf(stderr,
+          "%s: jtagmkII_chip_erase32()\n",
+          progname);
+
+  status = jtagmkII_reset32(pgm, AVR32_RESET_CHIP_ERASE);
+  if(status != 0) {lineno = __LINE__; goto eRR;}
+
+  // sequence of IR transitions
+  ret[0] = 0x01;
+  ret[1] = 0x05;
+  ret[2] = 0x01;
+  ret[3] = 0x00;
+
+  retP = ret;
+  for(loops=0; loops<1000; ++loops) {
+    buf[0] = CMND_GET_IR;
+    buf[1] = 0x0F;
+    status = jtagmkII_send(pgm, buf, 2);
+    if(status < 0) {lineno = __LINE__; goto eRR;}
+
+    status = jtagmkII_recv(pgm, &resp);
+    if (status != 2 || resp[0] != 0x87) {
+      {lineno = __LINE__; goto eRR;}
+    }
+    x = resp[1];
+    free(resp);
+    if(x == *retP) ++retP;
+    if(*retP == 0x00) break;
+  }
+  if(loops == 1000) {lineno = __LINE__; goto eRR;}
+
+  status = jtagmkII_avr32_reset(pgm, 0x00, 0x01, 0x01);
+  if(status < 0) {lineno = __LINE__; goto eRR;}
+
+  val = jtagmkII_read_SABaddr(pgm, 0x00000010, 0x06);
+  if(val != 0x00000000) {lineno = __LINE__; goto eRR;}
+
+  // AVR32 "special"
+  buf[0] = CMND_SET_PARAMETER;
+  buf[1] = 0x03;
+  buf[2] = 0x02;
+  jtagmkII_send(pgm, buf, 3);
+  status = jtagmkII_recv(pgm, &resp);
+  if(status < 0 || resp[0] != RSP_OK) {lineno = __LINE__; goto eRR;}
+  free(resp);
+
+  return 0;
+
+  eRR:
+    fprintf(stderr,
+	    "%s: jtagmkII_reset32(): "
+	    "failed at line %d (status=%x val=%lx)\n",
+	    progname, lineno, status, val);
+    return -1;
+}
+
+static unsigned long jtagmkII_read_SABaddr(PROGRAMMER * pgm, unsigned long addr,
+                                           unsigned int prefix)
+{
+  unsigned char buf[6], *resp;
+  int status;
+  unsigned long val;
+  unsigned long otimeout = serial_recv_timeout;
+
+  serial_recv_timeout = 256;
+
+  buf[0] = CMND_READ_SAB;
+  buf[1] = prefix;
+  u32_to_b4r(&buf[2], addr);
+
+  if(jtagmkII_send(pgm, buf, 6) < 0)
+    return ERROR_SAB;
+
+  status = jtagmkII_recv(pgm, &resp);
+  if(status <= 0 || resp[0] != 0x87) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	      "%s: jtagmkII_read_SABaddr(): "
+	      "timeout/error communicating with programmer (status %d) resp=%x\n",
+	      progname, status, resp[0]);
+    serial_recv_timeout = otimeout;
+
+    if(status > 0) {
+      int i;
+      fprintf(stderr, "Cmd: ");
+      for(i=0; i<6; ++i) fprintf(stderr, "%2.2x ", buf[i]);
+      fprintf(stderr, "\n");
+      fprintf(stderr, "Data: ");
+      for(i=0; i<status; ++i) fprintf(stderr, "%2.2x ", resp[i]);
+      fprintf(stderr, "\n");
+    }
+    return ERROR_SAB;
+  }
+
+  if(status != 5) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	      "%s: jtagmkII_read_SABaddr(): "
+	      "wrong number of bytes (status %d)\n",
+	      progname, status);
+    serial_recv_timeout = otimeout;
+    return ERROR_SAB;
+  }
+
+  val = b4_to_u32r(&resp[1]);
+  free(resp);
+
+  if (verbose) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	      "%s: jtagmkII_read_SABaddr(): "
+	      "OCD Register %lx -> %4.4lx\n",
+	      progname, addr, val);
+  }
+  serial_recv_timeout = otimeout;
+  return val;
+}
+
+static int jtagmkII_write_SABaddr(PROGRAMMER * pgm, unsigned long addr,
+                                  unsigned int prefix, unsigned long val)
+{
+  unsigned char buf[10], *resp;
+  int status;
+
+  buf[0] = CMND_WRITE_SAB;
+  buf[1] = prefix;
+  u32_to_b4r(&buf[2], addr);
+  u32_to_b4r(&buf[6], val);
+
+  if(jtagmkII_send(pgm, buf, 10) < 0)
+    return -1;
+
+  status = jtagmkII_recv(pgm, &resp);
+  if(status <= 0 || resp[0] != RSP_OK) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	      "%s: jtagmkII_write_SABaddr(): "
+	      "timeout/error communicating with programmer (status %d)\n",
+	      progname, status);
+    return -1;
+  }
+
+
+  if (verbose) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	      "%s: jtagmkII_write_SABaddr(): "
+	      "OCD Register %lx -> %4.4lx\n",
+	      progname, addr, val);
+  }
+  return 0;
+}
+
+static int jtagmkII_open32(PROGRAMMER * pgm, char * port)
+{
+  int status;
+  unsigned char buf[6], *resp;
+  long baud;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_open32()\n", progname);
+
+  /*
+   * The JTAG ICE mkII always starts with a baud rate of 19200 Bd upon
+   * attaching.  If the config file or command-line parameters specify
+   * a higher baud rate, we switch to it later on, after establishing
+   * the connection with the ICE.
+   */
+  baud = 19200;
+
+  /*
+   * If the port name starts with "usb", divert the serial routines
+   * to the USB ones.  The serial_open() function for USB overrides
+   * the meaning of the "baud" parameter to be the USB device ID to
+   * search for.
+   */
+  if (strncmp(port, "usb", 3) == 0) {
+#if defined(HAVE_LIBUSB)
+    serdev = &usb_serdev;
+    baud = USB_DEVICE_JTAGICEMKII;
+#else
+    fprintf(stderr, "avrdude was compiled without usb support.\n");
+    return -1;
+#endif
+  }
+
+  strcpy(pgm->port, port);
+  serial_open(port, baud, &pgm->fd);
+
+  /*
+   * drain any extraneous input
+   */
+  jtagmkII_drain(pgm, 0);
+
+  status = jtagmkII_getsync(pgm, -1);
+  if(status < 0) return -1;
+
+  // AVR32 "special"
+  buf[0] = CMND_SET_PARAMETER;
+  buf[1] = 0x2D;
+  buf[2] = 0x03;
+  jtagmkII_send(pgm, buf, 3);
+  status = jtagmkII_recv(pgm, &resp);
+  if(status < 0 || resp[0] != RSP_OK)
+    return -1;
+  free(resp);
+
+  buf[1] = 0x03;
+  buf[2] = 0x02;
+  jtagmkII_send(pgm, buf, 3);
+  status = jtagmkII_recv(pgm, &resp);
+  if(status < 0 || resp[0] != RSP_OK)
+    return -1;
+  free(resp);
+
+  buf[1] = 0x03;
+  buf[2] = 0x04;
+  jtagmkII_send(pgm, buf, 3);
+  status = jtagmkII_recv(pgm, &resp);
+  if(status < 0 || resp[0] != RSP_OK)
+    return -1;
+  free(resp);
+
+  return 0;
+}
+
+static void jtagmkII_close32(PROGRAMMER * pgm)
+{
+  int status, lineno;
+  unsigned char *resp, buf[3], c;
+  unsigned long val=0;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_close32()\n", progname);
+
+  // AVR32 "special"
+  buf[0] = CMND_SET_PARAMETER;
+  buf[1] = 0x03;
+  buf[2] = 0x02;
+  jtagmkII_send(pgm, buf, 3);
+  status = jtagmkII_recv(pgm, &resp);
+  if(status < 0 || resp[0] != RSP_OK) {lineno = __LINE__; goto eRR;}
+  free(resp);
+
+  buf[0] = CMND_SIGN_OFF;
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_close(): Sending sign-off command: ",
+	    progname);
+  jtagmkII_send(pgm, buf, 1);
+
+  status = jtagmkII_recv(pgm, &resp);
+  if (status <= 0) {
+    if (verbose >= 2)
+      putc('\n', stderr);
+    fprintf(stderr,
+	    "%s: jtagmkII_close(): "
+	    "timeout/error communicating with programmer (status %d)\n",
+	    progname, status);
+    return;
+  }
+  if (verbose >= 3) {
+    putc('\n', stderr);
+    jtagmkII_prmsg(pgm, resp, status);
+  } else if (verbose == 2)
+    fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+  c = resp[0];
+  free(resp);
+  if (c != RSP_OK) {
+    fprintf(stderr,
+	    "%s: jtagmkII_close(): "
+	    "bad response to sign-off command: %s\n",
+	    progname, jtagmkII_get_rc(c));
+  }
+
+  ret:
+    serial_close(&pgm->fd);
+    pgm->fd.ifd = -1;
+    return;
+
+  eRR:
+    fprintf(stderr,
+	    "%s: jtagmkII_reset32(): "
+	    "failed at line %d (status=%x val=%lx)\n",
+	    progname, lineno, status, val);
+    goto ret;
+}
+
+static int jtagmkII_paged_load32(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+			       int page_size, int n_bytes)
+{
+  unsigned int addr, block_size;
+  unsigned char cmd[7];
+  unsigned char *resp;
+  int lineno, status;
+  unsigned long val=0;
+  long otimeout = serial_recv_timeout;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: jtagmkII_paged_load32(.., %s, %d, %d)\n",
+	    progname, m->desc, page_size, n_bytes);
+
+  serial_recv_timeout = 256;
+
+  if(!(p->flags & AVRPART_WRITE)) {
+    status = jtagmkII_reset32(pgm, AVR32_RESET_READ);
+    if(status != 0) {lineno = __LINE__; goto eRR;}
+  }
+
+  // Init SMC and set clocks
+  if(!(p->flags & AVRPART_INIT_SMC)) {
+    status = jtagmkII_smc_init32(pgm);
+    if(status != 0) {lineno = __LINE__; goto eRR;} // PLL 0
+    p->flags |= AVRPART_INIT_SMC;
+  }
+
+  // Init SMC and set clocks
+  if(!(p->flags & AVRPART_INIT_SMC)) {
+    status = jtagmkII_smc_init32(pgm);
+    if(status != 0) {lineno = __LINE__; goto eRR;} // PLL 0
+    p->flags |= AVRPART_INIT_SMC;
+  }
+
+  //fprintf(stderr, "\n pageSize=%d bytes=%d pages=%d m->offset=0x%x pgm->page_size %d\n",
+  //        page_size, n_bytes, pages, m->offset, pgm->page_size);
+
+  cmd[0] = CMND_READ_MEMORY32;
+  cmd[1] = 0x40;
+  cmd[2] = 0x05;
+
+  addr = 0;
+  for (addr = 0; addr < n_bytes; addr += block_size) {
+    report_progress(addr, n_bytes, NULL);
+
+    block_size = ((n_bytes-addr) < pgm->page_size) ? (n_bytes - addr) : pgm->page_size;
+    if (verbose >= 3)
+      fprintf(stderr, "%s: jtagmkII_paged_load32(): "
+              "block_size at addr %d is %d\n",
+              progname, addr, block_size);
+
+    u32_to_b4r(cmd + 3, m->offset + addr);
+
+    status = jtagmkII_send(pgm, cmd, 7);
+    if(status<0) {lineno = __LINE__; goto eRR;}
+    status = jtagmkII_recv(pgm, &resp);
+    if(status<0) {lineno = __LINE__; goto eRR;}
+
+    if (verbose >= 3) {
+      putc('\n', stderr);
+      jtagmkII_prmsg(pgm, resp, status);
+    } else if (verbose == 2)
+      fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+    if (resp[0] != 0x87) {
+      fprintf(stderr,
+              "%s: jtagmkII_paged_load32(): "
+              "bad response to write memory command: %s\n",
+              progname, jtagmkII_get_rc(resp[0]));
+      free(resp);
+      return -1;
+    }
+    memcpy(m->buf + addr, resp + 1, block_size);
+    free(resp);
+
+  }
+
+  serial_recv_timeout = otimeout;
+
+  status = jtagmkII_reset32(pgm, AVR32_SET4RUNNING);
+  if(status < 0) {lineno = __LINE__; goto eRR;}
+
+  return addr;
+
+  eRR:
+    serial_recv_timeout = otimeout;
+    fprintf(stderr,
+	    "%s: jtagmkII_paged_load32(): "
+	    "failed at line %d (status=%x val=%lx)\n",
+	    progname, lineno, status, val);
+    return -1;
+}
+
+static int jtagmkII_paged_write32(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+				int page_size, int n_bytes)
+{
+  unsigned int addr, block_size;
+  unsigned char *cmd=NULL;
+  unsigned char *resp;
+  int lineno, status, pages, pageNum, blocks;
+  unsigned long val=0;
+  unsigned long otimeout = serial_recv_timeout;
+
+  serial_recv_timeout = 256;
+
+  if(n_bytes == 0) return -1;
+
+  status = jtagmkII_reset32(pgm, AVR32_RESET_WRITE);
+  if(status != 0) {lineno = __LINE__; goto eRR;}
+  p->flags |= AVRPART_WRITE;
+
+  pages = (n_bytes-1)/page_size + 1;
+  //fprintf(stderr, "\n pageSize=%d bytes=%d pages=%d m->offset=0x%x pgm->page_size %d\n",
+  //        page_size, n_bytes, pages, m->offset, pgm->page_size);
+
+  // Before any errors can happen
+  if ((cmd = malloc(pgm->page_size + 10)) == NULL) {
+    fprintf(stderr, "%s: jtagmkII_paged_write32(): Out of memory\n", progname);
+    return -1;
+  }
+
+  // Init SMC and set clocks
+  if(!(p->flags & AVRPART_INIT_SMC)) {
+    status = jtagmkII_smc_init32(pgm);
+    if(status != 0) {lineno = __LINE__; goto eRR;} // PLL 0
+    p->flags |= AVRPART_INIT_SMC;
+  }
+
+  // First unlock the pages
+  for(pageNum=0; pageNum < pages; ++pageNum) {
+    status =jtagmkII_flash_lock32(pgm, 0, pageNum);
+    if(status < 0) {lineno = __LINE__; goto eRR;}
+  }
+
+  // Then erase them (guess could do this in the same loop above?)
+  for(pageNum=0; pageNum < pages; ++pageNum) {
+    status =jtagmkII_flash_erase32(pgm, pageNum);
+    if(status < 0) {lineno = __LINE__; goto eRR;}
+  }
+
+  cmd[0] = CMND_WRITE_MEMORY32;
+  u32_to_b4r(&cmd[1], 0x40000000);  // who knows
+  cmd[5] = 0x5;
+
+  addr = 0;
+  for(pageNum=0; pageNum < pages; ++pageNum) {
+
+    report_progress(addr, n_bytes, NULL);
+
+    status = jtagmkII_flash_clear_pagebuffer32(pgm);
+    if(status != 0) {lineno = __LINE__; goto eRR;}
+
+    for(blocks=0; blocks<2; ++blocks) {
+      block_size = ((n_bytes-addr) < pgm->page_size) ? (n_bytes - addr) : pgm->page_size;
+      if (verbose >= 3)
+        fprintf(stderr, "%s: jtagmkII_paged_write32(): "
+                "block_size at addr %d is %d\n",
+                progname, addr, block_size);
+
+      u32_to_b4r(cmd + 6, m->offset + addr);
+      memset(cmd + 10, 0xff, pgm->page_size);
+      memcpy(cmd + 10, m->buf + addr, block_size);
+
+      status = jtagmkII_send(pgm, cmd, pgm->page_size + 10);
+      if(status<0) {lineno = __LINE__; goto eRR;}
+      status = jtagmkII_recv(pgm, &resp);
+      if (status<0) {lineno = __LINE__; goto eRR;}
+
+      if (verbose >= 3) {
+        putc('\n', stderr);
+        jtagmkII_prmsg(pgm, resp, status);
+      } else if (verbose == 2)
+        fprintf(stderr, "0x%02x (%d bytes msg)\n", resp[0], status);
+      if (resp[0] != RSP_OK) {
+        fprintf(stderr,
+                "%s: jtagmkII_paged_write32(): "
+                "bad response to write memory command: %s\n",
+                progname, jtagmkII_get_rc(resp[0]));
+        free(resp);
+        free(cmd);
+        return -1;
+      }
+      free(resp);
+
+      addr += block_size;
+
+
+    }
+    status = jtagmkII_flash_write_page32(pgm, pageNum);
+    if(status < 0) {lineno = __LINE__; goto eRR;}
+  }
+  free(cmd);
+  serial_recv_timeout = otimeout;
+
+  status = jtagmkII_reset32(pgm, AVR32_SET4RUNNING);  // AVR32_SET4RUNNING | AVR32_RELEASE_JTAG
+  if(status < 0) {lineno = __LINE__; goto eRR;}
+
+  return addr;
+
+  eRR:
+    serial_recv_timeout = otimeout;
+    free(cmd);
+    fprintf(stderr,
+	    "%s: jtagmkII_paged_write32(): "
+	    "failed at line %d (status=%x val=%lx)\n",
+	    progname, lineno, status, val);
+    return -1;
+}
+
+
+static int jtagmkII_flash_lock32(PROGRAMMER * pgm, unsigned char lock, unsigned int page)
+{
+  int status, lineno, i;
+  unsigned long val, cmd=0;
+
+  for(i=0; i<256; ++i) {
+    val = jtagmkII_read_SABaddr(pgm, AVR32_FLASHC_FSR, 0x05);
+    if(val == ERROR_SAB) continue;
+    if(val & AVR32_FLASHC_FSR_RDY) break;
+  }
+  if(val == ERROR_SAB) {lineno = __LINE__; goto eRR;}
+  if(!(val&AVR32_FLASHC_FSR_RDY)) {lineno = __LINE__; goto eRR;} // Flash better be ready
+
+  page <<= 8;
+  cmd = AVR32_FLASHC_FCMD_KEY | page | (lock ? AVR32_FLASHC_FCMD_LOCK : AVR32_FLASHC_FCMD_UNLOCK);
+  status = jtagmkII_write_SABaddr(pgm, AVR32_FLASHC_FCMD, 0x05, cmd);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+
+  return 0;
+
+  eRR:
+    fprintf(stderr,
+	    "%s: jtagmkII_flash_lock32(): "
+	    "failed at line %d page %d cmd %8.8lx\n",
+	    progname, lineno, page, cmd);
+    return -1;
+}
+
+static int jtagmkII_flash_erase32(PROGRAMMER * pgm, unsigned int page)
+{
+  int status, lineno, i;
+  unsigned long val=0, cmd=0, err=0;
+
+  for(i=0; i<256; ++i) {
+    val = jtagmkII_read_SABaddr(pgm, AVR32_FLASHC_FSR, 0x05);
+    if(val == ERROR_SAB) continue;
+    if(val & AVR32_FLASHC_FSR_RDY) break;
+  }
+  if(val == ERROR_SAB) {lineno = __LINE__; goto eRR;}
+  if(!(val&AVR32_FLASHC_FSR_RDY)) {lineno = __LINE__; goto eRR;} // Flash better be ready
+
+  page <<= 8;
+  cmd = AVR32_FLASHC_FCMD_KEY | page | AVR32_FLASHC_FCMD_ERASE_PAGE;
+  status = jtagmkII_write_SABaddr(pgm, AVR32_FLASHC_FCMD, 0x05, cmd);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+
+//fprintf(stderr, "ERASE %x -> %x\n", cmd, AVR32_FLASHC_FCMD);
+
+  err = 0;
+  for(i=0; i<256; ++i) {
+    val = jtagmkII_read_SABaddr(pgm, AVR32_FLASHC_FSR, 0x05);
+    if(val == ERROR_SAB) continue;
+    err |= val;
+    if(val & AVR32_FLASHC_FSR_RDY) break;
+  }
+  if(val == ERROR_SAB) {lineno = __LINE__; goto eRR;}
+  if(!(val & AVR32_FLASHC_FSR_RDY)) {lineno = __LINE__; goto eRR;}
+  if(err & AVR32_FLASHC_FSR_ERR) {lineno = __LINE__; goto eRR;}
+
+  return 0;
+
+  eRR:
+    fprintf(stderr,
+	    "%s: jtagmkII_flash_erase32(): "
+	    "failed at line %d page %d cmd %8.8lx val %lx\n",
+	    progname, lineno, page, cmd, val);
+    return -1;
+}
+
+static int jtagmkII_flash_write_page32(PROGRAMMER * pgm, unsigned int page)
+{
+  int status, lineno, i;
+  unsigned long val=0, cmd, err;
+
+  page <<= 8;
+  cmd = AVR32_FLASHC_FCMD_KEY | page | AVR32_FLASHC_FCMD_WRITE_PAGE;
+  status = jtagmkII_write_SABaddr(pgm, AVR32_FLASHC_FCMD, 0x05, cmd);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+
+  err = 0;
+  for(i=0; i<256; ++i) {
+    val = jtagmkII_read_SABaddr(pgm, AVR32_FLASHC_FSR, 0x05);
+    if(val == ERROR_SAB) continue;
+    err |= val;
+    if(val & AVR32_FLASHC_FSR_RDY) break;
+  }
+  if(val == ERROR_SAB) {lineno = __LINE__; goto eRR;}
+  if(!(val & AVR32_FLASHC_FSR_RDY)) {lineno = __LINE__; goto eRR;}
+  if(err & AVR32_FLASHC_FSR_ERR) {lineno = __LINE__; goto eRR;}
+
+  return 0;
+
+  eRR:
+    fprintf(stderr,
+	    "%s: jtagmkII_flash_write_page32(): "
+	    "failed at line %d page %d cmd %8.8lx val %lx\n",
+	    progname, lineno, page, cmd, val);
+    return -1;
+}
+
+static int jtagmkII_flash_clear_pagebuffer32(PROGRAMMER * pgm)
+{
+  int status, lineno, i;
+  unsigned long val=0, cmd, err;
+
+  cmd = AVR32_FLASHC_FCMD_KEY | AVR32_FLASHC_FCMD_CLEAR_PAGE_BUFFER;
+  status = jtagmkII_write_SABaddr(pgm, AVR32_FLASHC_FCMD, 0x05, cmd);
+  if (status < 0) {lineno = __LINE__; goto eRR;}
+
+  err = 0;
+  for(i=0; i<256; ++i) {
+    val = jtagmkII_read_SABaddr(pgm, AVR32_FLASHC_FSR, 0x05);
+    if(val == ERROR_SAB) continue;
+    err |= val;
+    if(val & AVR32_FLASHC_FSR_RDY) break;
+  }
+  if(val == ERROR_SAB) {lineno = __LINE__; goto eRR;}
+  if(!(val & AVR32_FLASHC_FSR_RDY)) {lineno = __LINE__; goto eRR;}
+  if(err & AVR32_FLASHC_FSR_ERR) {lineno = __LINE__; goto eRR;}
+
+  return 0;
+
+  eRR:
+    fprintf(stderr,
+	    "%s: jtagmkII_flash_clear_pagebuffer32(): "
+	    "failed at line %d cmd %8.8lx val %lx\n",
+	    progname, lineno, cmd, val);
+    return -1;
+}
+
+#ifdef __OBJC__
+#pragma mark -
+#endif
+
+void jtagmkII_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "JTAGMKII");
+
+  /*
+   * mandatory functions
+   */
+  pgm->initialize     = jtagmkII_initialize;
+  pgm->display        = jtagmkII_display;
+  pgm->enable         = jtagmkII_enable;
+  pgm->disable        = jtagmkII_disable;
+  pgm->program_enable = jtagmkII_program_enable_dummy;
+  pgm->chip_erase     = jtagmkII_chip_erase;
+  pgm->open           = jtagmkII_open;
+  pgm->close          = jtagmkII_close;
+  pgm->read_byte      = jtagmkII_read_byte;
+  pgm->write_byte     = jtagmkII_write_byte;
+
+  /*
+   * optional functions
+   */
+  pgm->paged_write    = jtagmkII_paged_write;
+  pgm->paged_load     = jtagmkII_paged_load;
+  pgm->print_parms    = jtagmkII_print_parms;
+  pgm->set_sck_period = jtagmkII_set_sck_period;
+  pgm->parseextparams = jtagmkII_parseextparms;
+  pgm->setup          = jtagmkII_setup;
+  pgm->teardown       = jtagmkII_teardown;
+  pgm->page_size      = 256;
+  pgm->flag           = PGM_FL_IS_JTAG;
+}
+
+void jtagmkII_dw_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "JTAGMKII_DW");
+
+  /*
+   * mandatory functions
+   */
+  pgm->initialize     = jtagmkII_initialize;
+  pgm->display        = jtagmkII_display;
+  pgm->enable         = jtagmkII_enable;
+  pgm->disable        = jtagmkII_disable;
+  pgm->program_enable = jtagmkII_program_enable_dummy;
+  pgm->chip_erase     = jtagmkII_chip_erase_dw;
+  pgm->open           = jtagmkII_open_dw;
+  pgm->close          = jtagmkII_close;
+  pgm->read_byte      = jtagmkII_read_byte;
+  pgm->write_byte     = jtagmkII_write_byte;
+
+  /*
+   * optional functions
+   */
+  pgm->paged_write    = jtagmkII_paged_write;
+  pgm->paged_load     = jtagmkII_paged_load;
+  pgm->print_parms    = jtagmkII_print_parms;
+  pgm->setup          = jtagmkII_setup;
+  pgm->teardown       = jtagmkII_teardown;
+  pgm->page_size      = 256;
+  pgm->flag           = PGM_FL_IS_DW;
+}
+
+
+void jtagmkII_pdi_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "JTAGMKII_PDI");
+
+  /*
+   * mandatory functions
+   */
+  pgm->initialize     = jtagmkII_initialize;
+  pgm->display        = jtagmkII_display;
+  pgm->enable         = jtagmkII_enable;
+  pgm->disable        = jtagmkII_disable;
+  pgm->program_enable = jtagmkII_program_enable_dummy;
+  pgm->chip_erase     = jtagmkII_chip_erase;
+  pgm->open           = jtagmkII_open_pdi;
+  pgm->close          = jtagmkII_close;
+  pgm->read_byte      = jtagmkII_read_byte;
+  pgm->write_byte     = jtagmkII_write_byte;
+
+  /*
+   * optional functions
+   */
+  pgm->paged_write    = jtagmkII_paged_write;
+  pgm->paged_load     = jtagmkII_paged_load;
+  pgm->print_parms    = jtagmkII_print_parms;
+  pgm->setup          = jtagmkII_setup;
+  pgm->teardown       = jtagmkII_teardown;
+  pgm->page_size      = 256;
+  pgm->flag           = PGM_FL_IS_PDI;
+}
+
+
+void jtagmkII_dragon_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "DRAGON_JTAG");
+
+  /*
+   * mandatory functions
+   */
+  pgm->initialize     = jtagmkII_initialize;
+  pgm->display        = jtagmkII_display;
+  pgm->enable         = jtagmkII_enable;
+  pgm->disable        = jtagmkII_disable;
+  pgm->program_enable = jtagmkII_program_enable_dummy;
+  pgm->chip_erase     = jtagmkII_chip_erase;
+  pgm->open           = jtagmkII_dragon_open;
+  pgm->close          = jtagmkII_close;
+  pgm->read_byte      = jtagmkII_read_byte;
+  pgm->write_byte     = jtagmkII_write_byte;
+
+  /*
+   * optional functions
+   */
+  pgm->paged_write    = jtagmkII_paged_write;
+  pgm->paged_load     = jtagmkII_paged_load;
+  pgm->print_parms    = jtagmkII_print_parms;
+  pgm->set_sck_period = jtagmkII_set_sck_period;
+  pgm->parseextparams = jtagmkII_parseextparms;
+  pgm->setup          = jtagmkII_setup;
+  pgm->teardown       = jtagmkII_teardown;
+  pgm->page_size      = 256;
+  pgm->flag           = PGM_FL_IS_JTAG;
+}
+
+
+void jtagmkII_dragon_dw_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "DRAGON_DW");
+
+  /*
+   * mandatory functions
+   */
+  pgm->initialize     = jtagmkII_initialize;
+  pgm->display        = jtagmkII_display;
+  pgm->enable         = jtagmkII_enable;
+  pgm->disable        = jtagmkII_disable;
+  pgm->program_enable = jtagmkII_program_enable_dummy;
+  pgm->chip_erase     = jtagmkII_chip_erase_dw;
+  pgm->open           = jtagmkII_dragon_open_dw;
+  pgm->close          = jtagmkII_close;
+  pgm->read_byte      = jtagmkII_read_byte;
+  pgm->write_byte     = jtagmkII_write_byte;
+
+  /*
+   * optional functions
+   */
+  pgm->paged_write    = jtagmkII_paged_write;
+  pgm->paged_load     = jtagmkII_paged_load;
+  pgm->print_parms    = jtagmkII_print_parms;
+  pgm->setup          = jtagmkII_setup;
+  pgm->teardown       = jtagmkII_teardown;
+  pgm->page_size      = 256;
+  pgm->flag           = PGM_FL_IS_DW;
+}
+
+void jtagmkII_avr32_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "JTAGMKII_AVR32");
+
+  /*
+   * mandatory functions
+   */
+  pgm->initialize     = jtagmkII_initialize32;
+  pgm->display        = jtagmkII_display;
+  pgm->enable         = jtagmkII_enable;
+  pgm->disable        = jtagmkII_disable;
+  pgm->program_enable = jtagmkII_program_enable_dummy;
+  pgm->chip_erase     = jtagmkII_chip_erase32;
+  pgm->open           = jtagmkII_open32;
+  pgm->close          = jtagmkII_close32;
+  pgm->read_byte      = jtagmkII_read_byte;
+  pgm->write_byte     = jtagmkII_write_byte;
+
+  /*
+   * optional functions
+   */
+  pgm->paged_write    = jtagmkII_paged_write32;
+  pgm->paged_load     = jtagmkII_paged_load32;
+  pgm->print_parms    = jtagmkII_print_parms;
+  //pgm->set_sck_period = jtagmkII_set_sck_period;
+  //pgm->parseextparams = jtagmkII_parseextparms;
+  pgm->setup          = jtagmkII_setup;
+  pgm->teardown       = jtagmkII_teardown;
+  pgm->page_size      = 256;
+  pgm->flag           = PGM_FL_IS_JTAG;
+}
+
+void jtagmkII_dragon_pdi_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "DRAGON_PDI");
+
+  /*
+   * mandatory functions
+   */
+  pgm->initialize     = jtagmkII_initialize;
+  pgm->display        = jtagmkII_display;
+  pgm->enable         = jtagmkII_enable;
+  pgm->disable        = jtagmkII_disable;
+  pgm->program_enable = jtagmkII_program_enable_dummy;
+  pgm->chip_erase     = jtagmkII_chip_erase;
+  pgm->open           = jtagmkII_dragon_open_pdi;
+  pgm->close          = jtagmkII_close;
+  pgm->read_byte      = jtagmkII_read_byte;
+  pgm->write_byte     = jtagmkII_write_byte;
+
+  /*
+   * optional functions
+   */
+  pgm->paged_write    = jtagmkII_paged_write;
+  pgm->paged_load     = jtagmkII_paged_load;
+  pgm->print_parms    = jtagmkII_print_parms;
+  pgm->setup          = jtagmkII_setup;
+  pgm->teardown       = jtagmkII_teardown;
+  pgm->page_size      = 256;
+  pgm->flag           = PGM_FL_IS_PDI;
+}
+
diff --git a/avrdude/jtagmkII.h b/avrdude/jtagmkII.h
new file mode 100644
index 00000000..22a15f82
--- /dev/null
+++ b/avrdude/jtagmkII.h
@@ -0,0 +1,57 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2002-2004, 2006  Brian S. Dean <bsd@bsdhome.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id$ */
+
+#ifndef jtagmkII_h
+#define jtagmkII_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int  jtagmkII_send(PROGRAMMER * pgm, unsigned char * data, size_t len);
+int  jtagmkII_recv(PROGRAMMER * pgm, unsigned char **msg);
+void jtagmkII_close(PROGRAMMER * pgm);
+int  jtagmkII_getsync(PROGRAMMER * pgm, int mode);
+int  jtagmkII_getparm(PROGRAMMER * pgm, unsigned char parm,
+		      unsigned char * value);
+
+void jtagmkII_initpgm (PROGRAMMER * pgm);
+void jtagmkII_avr32_initpgm (PROGRAMMER * pgm);
+void jtagmkII_dw_initpgm (PROGRAMMER * pgm);
+void jtagmkII_pdi_initpgm (PROGRAMMER * pgm);
+void jtagmkII_dragon_initpgm (PROGRAMMER * pgm);
+void jtagmkII_dragon_dw_initpgm (PROGRAMMER * pgm);
+void jtagmkII_dragon_pdi_initpgm (PROGRAMMER * pgm);
+
+/*
+ * These functions are referenced from stk500v2.c for JTAG ICE mkII
+ * and AVR Dragon programmers running in one of the STK500v2
+ * modi.
+ */
+void jtagmkII_setup(PROGRAMMER * pgm);
+void jtagmkII_teardown(PROGRAMMER * pgm);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/avrdude/jtagmkII_private.h b/avrdude/jtagmkII_private.h
new file mode 100644
index 00000000..de12c214
--- /dev/null
+++ b/avrdude/jtagmkII_private.h
@@ -0,0 +1,358 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2005, 2006 Joerg Wunsch <j@uriah.heep.sax.de>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 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
+ */
+
+/* $Id$ */
+
+
+/*
+ * JTAG ICE mkII definitions
+ * Taken from Appnote AVR067
+ */
+
+#if !defined(JTAGMKII_PRIVATE_EXPORTED)
+/*
+ * Communication with the JTAG ICE works in frames.  The protocol
+ * somewhat resembles the STK500v2 protocol, yet it is sufficiently
+ * different to prevent a direct code reuse. :-(
+ *
+ * Frame format:
+ *
+ *  +---------------------------------------------------------------+
+ *  |   0   |  1  .  2  |  3 . 4 . 5 . 6  |   7   | ... | N-1 .  N  |
+ *  |       |           |                 |       |     |           |
+ *  | start | LSB   MSB | LSB ....... MSB | token | msg | LSB   MSB |
+ *  | 0x1B  | sequence# | message size    | 0x0E  |     |   CRC16   |
+ *  +---------------------------------------------------------------+
+ *
+ * Each request message will be returned by a response with a matching
+ * sequence #.  Sequence # 0xffff is reserved for asynchronous event
+ * notifications that will be sent by the ICE without a request
+ * message (e.g. when the target hit a breakpoint).
+ *
+ * The message size excludes the framing overhead (10 bytes).
+ *
+ * The first byte of the message is always the request or response
+ * code, which is roughly classified as:
+ *
+ * . Messages (commands) use 0x00 through 0x3f.  (The documentation
+ *   claims that messages start at 0x01, but actually CMND_SIGN_OFF is
+ *   0x00.)
+ * . Internal commands use 0x40 through 0x7f (not documented).
+ * . Success responses use 0x80 through 0x9f.
+ * . Failure responses use 0xa0 through 0xbf.
+ * . Events use 0xe0 through 0xff.
+ */
+#define MESSAGE_START 0x1b
+#define TOKEN 0x0e
+
+/*
+ * Max message size we are willing to accept.  Prevents us from trying
+ * to allocate too much VM in case we received a nonsensical packet
+ * length.  We have to allocate the buffer as soon as we've got the
+ * length information (and thus have to trust that information by that
+ * time at first), as the final CRC check can only be done once the
+ * entire packet came it.
+ */
+#define MAX_MESSAGE 100000
+
+#endif /* JTAGMKII_PRIVATE_EXPORTED */
+
+/* ICE command codes */
+#define CMND_CHIP_ERASE 0x13
+#define CMND_CLEAR_EVENTS 0x22
+#define CMND_CLR_BREAK 0x1A
+#define CMND_ENTER_PROGMODE 0x14
+#define CMND_ERASEPAGE_SPM 0x0D
+#define CMND_FORCED_STOP 0x0A
+#define CMND_GET_BREAK 0x12
+#define CMND_GET_PARAMETER 0x03
+#define CMND_GET_SIGN_ON 0x01
+#define CMND_GET_SYNC 0x0f
+#define CMND_GO 0x08
+#define CMND_ISP_PACKET 0x2F
+#define CMND_LEAVE_PROGMODE 0x15
+#define CMND_READ_MEMORY 0x05
+#define CMND_READ_PC 0x07
+#define CMND_RESET 0x0B
+#define CMND_RESTORE_TARGET 0x23
+#define CMND_RUN_TO_ADDR 0x1C
+#define CMND_SELFTEST 0x10
+#define CMND_SET_BREAK 0x11
+#define CMND_SET_DEVICE_DESCRIPTOR 0x0C
+#define CMND_SET_N_PARAMETERS 0x16
+#define CMND_SET_PARAMETER 0x02
+#define CMND_SIGN_OFF 0x00
+#define CMND_SINGLE_STEP 0x09
+#define CMND_SPI_CMD 0x1D
+#define CMND_WRITE_MEMORY 0x04
+#define CMND_WRITE_PC 0x06
+#define CMND_XMEGA_ERASE 0x34
+// AVR32 - DFH
+#define CMND_GET_IR 0x24
+#define CMND_GET_xxx 0x25
+#define CMND_WRITE_SAB 0x28
+#define CMND_READ_SAB 0x29
+#define CMND_RESET_AVR 0x2B
+#define CMND_READ_MEMORY32 0x2C
+#define CMND_WRITE_MEMORY32 0x2D
+
+
+/* ICE responses */
+#define RSP_DEBUGWIRE_SYNC_FAILED 0xAC
+#define RSP_FAILED 0xA0
+#define RSP_GET_BREAK 0x83
+#define RSP_ILLEGAL_BREAKPOINT 0xA8
+#define RSP_ILLEGAL_COMMAND 0xAA
+#define RSP_ILLEGAL_EMULATOR_MODE 0xA4
+#define RSP_ILLEGAL_JTAG_ID 0xA9
+#define RSP_ILLEGAL_MCU_STATE 0xA5
+#define RSP_ILLEGAL_MEMORY_TYPE 0xA2
+#define RSP_ILLEGAL_MEMORY_RANGE 0xA3
+#define RSP_ILLEGAL_PARAMETER 0xA1
+#define RSP_ILLEGAL_POWER_STATE 0xAD
+#define RSP_ILLEGAL_VALUE 0xA6
+#define RSP_MEMORY 0x82
+#define RSP_NO_TARGET_POWER 0xAB
+#define RSP_OK 0x80
+#define RSP_PARAMETER 0x81
+#define RSP_PC 0x84
+#define RSP_SELFTEST 0x85
+#define RSP_SET_N_PARAMETERS 0xA7
+#define RSP_SIGN_ON 0x86
+#define RSP_SPI_DATA 0x88
+
+/* ICE events */
+#define EVT_BREAK 0xE0
+#define EVT_DEBUG 0xE6
+#define EVT_ERROR_PHY_FORCE_BREAK_TIMEOUT 0xE2
+#define EVT_ERROR_PHY_MAX_BIT_LENGTH_DIFF 0xED
+#define EVT_ERROR_PHY_OPT_RECEIVE_TIMEOUT 0xF9
+#define EVT_ERROR_PHY_OPT_RECEIVED_BREAK 0xFA
+#define EVT_ERROR_PHY_RECEIVED_BREAK 0xF8
+#define EVT_ERROR_PHY_RECEIVE_TIMEOUT 0xF7
+#define EVT_ERROR_PHY_RELEASE_BREAK_TIMEOUT 0xE3
+#define EVT_ERROR_PHY_SYNC_OUT_OF_RANGE 0xF5
+#define EVT_ERROR_PHY_SYNC_TIMEOUT 0xF0
+#define EVT_ERROR_PHY_SYNC_TIMEOUT_BAUD 0xF4
+#define EVT_ERROR_PHY_SYNC_WAIT_TIMEOUT 0xF6
+#define EVT_RESULT_PHY_NO_ACTIVITY 0xFB
+#define EVT_EXT_RESET 0xE7
+#define EVT_ICE_POWER_ERROR_STATE 0xEA
+#define EVT_ICE_POWER_OK 0xEB
+#define EVT_IDR_DIRTY 0xEC
+#define EVT_NONE 0xEF
+#define EVT_PDSB_BREAK 0xF2
+#define EVT_PDSMB_BREAK 0xF3
+#define EVT_PROGRAM_BREAK 0xF1
+#define EVT_RUN 0xE1
+#define EVT_TARGET_POWER_OFF 0xE5
+#define EVT_TARGET_POWER_ON 0xE4
+#define EVT_TARGET_SLEEP 0xE8
+#define EVT_TARGET_WAKEUP 0xE9
+
+/* memory types for CMND_{READ,WRITE}_MEMORY */
+#define MTYPE_IO_SHADOW 0x30	/* cached IO registers? */
+#define MTYPE_SRAM 0x20		/* target's SRAM or [ext.] IO registers */
+#define MTYPE_EEPROM 0x22	/* EEPROM, what way? */
+#define MTYPE_EVENT 0x60	/* ICE event memory */
+#define MTYPE_SPM 0xA0		/* flash through LPM/SPM */
+#define MTYPE_FLASH_PAGE 0xB0	/* flash in programming mode */
+#define MTYPE_EEPROM_PAGE 0xB1	/* EEPROM in programming mode */
+#define MTYPE_FUSE_BITS 0xB2	/* fuse bits in programming mode */
+#define MTYPE_LOCK_BITS 0xB3	/* lock bits in programming mode */
+#define MTYPE_SIGN_JTAG 0xB4	/* signature in programming mode */
+#define MTYPE_OSCCAL_BYTE 0xB5	/* osccal cells in programming mode */
+#define MTYPE_CAN 0xB6		/* CAN mailbox */
+#define MTYPE_FLASH 0xc0	/* xmega flash - undocumented in AVR067 */
+#define MTYPE_USERSIG 0xc5	/* xmega user signature - undocumented in AVR067 */
+#define MTYPE_PRODSIG 0xc6	/* xmega production signature - undocumented in AVR067 */
+
+/* (some) ICE parameters, for CMND_{GET,SET}_PARAMETER */
+#define PAR_HW_VERSION 0x01
+#define PAR_FW_VERSION 0x02
+#define PAR_EMULATOR_MODE 0x03
+# define EMULATOR_MODE_DEBUGWIRE 0x00
+# define EMULATOR_MODE_JTAG 0x01
+# define EMULATOR_MODE_HV 0x02	/* HVSP or PP mode of AVR Dragon */
+# define EMULATOR_MODE_SPI 0x03
+# define EMULATOR_MODE_JTAG_AVR32 0x04
+# define EMULATOR_MODE_JTAG_XMEGA 0x05
+# define EMULATOR_MODE_PDI 0x06
+#define PAR_IREG 0x04
+#define PAR_BAUD_RATE 0x05
+# define PAR_BAUD_2400 0x01
+# define PAR_BAUD_4800 0x02
+# define PAR_BAUD_9600 0x03
+# define PAR_BAUD_19200 0x04	/* default */
+# define PAR_BAUD_38400 0x05
+# define PAR_BAUD_57600 0x06
+# define PAR_BAUD_115200 0x07
+# define PAR_BAUD_14400 0x08
+#define PAR_OCD_VTARGET 0x06
+#define PAR_OCD_JTAG_CLK 0x07
+#define PAR_OCD_BREAK_CAUSE 0x08
+#define PAR_TIMERS_RUNNING 0x09
+#define PAR_BREAK_ON_CHANGE_FLOW 0x0A
+#define PAR_BREAK_ADDR1 0x0B
+#define PAR_BREAK_ADDR2 0x0C
+#define PAR_COMBBREAKCTRL 0x0D
+#define PAR_JTAGID 0x0E
+#define PAR_UNITS_BEFORE 0x0F
+#define PAR_UNITS_AFTER 0x10
+#define PAR_BIT_BEFORE 0x11
+#define PAR_BIT_ATER 0x12
+#define PAR_EXTERNAL_RESET 0x13
+#define PAR_FLASH_PAGE_SIZE 0x14
+#define PAR_EEPROM_PAGE_SIZE 0x15
+#define PAR_UNUSED1 0x16
+#define PAR_PSB0 0x17
+#define PAR_PSB1 0x18
+#define PAR_PROTOCOL_DEBUG_EVENT 0x19
+#define PAR_MCU_STATE 0x1A
+# define STOPPED 0x00
+# define RUNNING 0x01
+# define PROGRAMMING 0x02
+#define PAR_DAISY_CHAIN_INFO 0x1B
+#define PAR_BOOT_ADDRESS 0x1C
+#define PAR_TARGET_SIGNATURE 0x1D
+#define PAR_DEBUGWIRE_BAUDRATE 0x1E
+#define PAR_PROGRAM_ENTRY_POINT 0x1F
+#define PAR_PDI_OFFSET_START 0x32
+#define PAR_PDI_OFFSET_END 0x33
+#define PAR_PACKET_PARSING_ERRORS 0x40
+#define PAR_VALID_PACKETS_RECEIVED 0x41
+#define PAR_INTERCOMMUNICATION_TX_FAILURES 0x42
+#define PAR_INTERCOMMUNICATION_RX_FAILURES 0x43
+#define PAR_CRC_ERRORS 0x44
+#define PAR_POWER_SOURCE 0x45
+# define POWER_EXTERNAL 0x00
+# define POWER_USB 0x01
+#define PAR_CAN_FLAG 0x22
+# define DONT_READ_CAN_MAILBOX 0x00
+# define READ_CAN_MAILBOX 0x01
+#define PAR_ENABLE_IDR_IN_RUN_MODE 0x23
+# define ACCESS_OSCCAL 0x00
+# define ACCESS_IDR 0x01
+#define PAR_ALLOW_PAGEPROGRAMMING_IN_SCANCHAIN 0x24
+# define PAGEPROG_NOT_ALLOWED 0x00
+# define PAGEPROG_ALLOWED 0x01
+
+/* Xmega erase memory types, for CMND_XMEGA_ERASE */
+#define XMEGA_ERASE_CHIP 0x00
+#define XMEGA_ERASE_APP 0x01
+#define XMEGA_ERASE_BOOT 0x02
+#define XMEGA_ERASE_EEPROM 0x03
+#define XMEGA_ERASE_APP_PAGE 0x04
+#define XMEGA_ERASE_BOOT_PAGE 0x05
+#define XMEGA_ERASE_EEPROM_PAGE 0x06
+#define XMEGA_ERASE_USERSIG 0x07
+
+/* AVR32 related definitions */
+#define AVR32_FLASHC_FCR                  0xFFFE1400
+#define AVR32_FLASHC_FCMD                 0xFFFE1404
+#define   AVR32_FLASHC_FCMD_KEY           0xA5000000
+#define   AVR32_FLASHC_FCMD_WRITE_PAGE             1
+#define   AVR32_FLASHC_FCMD_ERASE_PAGE             2
+#define   AVR32_FLASHC_FCMD_CLEAR_PAGE_BUFFER      3
+#define   AVR32_FLASHC_FCMD_LOCK                   4
+#define   AVR32_FLASHC_FCMD_UNLOCK                 5
+#define AVR32_FLASHC_FSR                  0xFFFE1408
+#define   AVR32_FLASHC_FSR_RDY            0x00000001
+#define   AVR32_FLASHC_FSR_ERR            0x00000008
+#define AVR32_FLASHC_FGPFRHI              0xFFFE140C
+#define AVR32_FLASHC_FGPFRLO              0xFFFE1410
+
+#define AVR32_DC                          0x00000008
+#define AVR32_DS                          0x00000010
+#define AVR32_DINST                       0x00000104
+#define AVR32_DCCPU                       0x00000110
+#define AVR32_DCEMU                       0x00000114
+#define AVR32_DCSR                        0x00000118
+
+#define AVR32_DC_ABORT                    0x80000000
+#define AVR32_DC_RESET                    0x40000000
+#define AVR32_DC_DBE                      0x00002000
+#define AVR32_DC_DBR                      0x00001000
+
+#define AVR32_RESET_READ             0x0001
+#define AVR32_RESET_WRITE            0x0002
+#define AVR32_RESET_CHIP_ERASE       0x0004
+#define AVR32_SET4RUNNING            0x0008
+//#define AVR32_RESET_COMMON           (AVR32_RESET_READ | AVR32_RESET_WRITE | AVR32_RESET_CHIP_ERASE )
+
+
+#if !defined(JTAGMKII_PRIVATE_EXPORTED)
+/*
+ * In appnote AVR067, struct device_descriptor is written with
+ * int/long field types.  We cannot use them directly, as they were
+ * neither properly aligned for portability, nor did they care for
+ * endianess issues.  We thus use arrays of unsigned chars, plus
+ * conversion macros.
+ */
+struct device_descriptor
+{
+  unsigned char ucReadIO[8]; /*LSB = IOloc 0, MSB = IOloc63 */
+  unsigned char ucReadIOShadow[8]; /*LSB = IOloc 0, MSB = IOloc63 */
+  unsigned char ucWriteIO[8]; /*LSB = IOloc 0, MSB = IOloc63 */
+  unsigned char ucWriteIOShadow[8]; /*LSB = IOloc 0, MSB = IOloc63 */
+  unsigned char ucReadExtIO[52]; /*LSB = IOloc 96, MSB = IOloc511 */
+  unsigned char ucReadIOExtShadow[52]; /*LSB = IOloc 96, MSB = IOloc511 */
+  unsigned char ucWriteExtIO[52]; /*LSB = IOloc 96, MSB = IOloc511 */
+  unsigned char ucWriteIOExtShadow[52];/*LSB = IOloc 96, MSB = IOloc511 */
+  unsigned char ucIDRAddress; /*IDR address */
+  unsigned char ucSPMCRAddress; /*SPMCR Register address and dW BasePC */
+  unsigned char ucRAMPZAddress; /*RAMPZ Register address in SRAM I/O */
+				/*space */
+  unsigned char uiFlashPageSize[2]; /*Device Flash Page Size, Size = */
+				/*2 exp ucFlashPageSize */
+  unsigned char ucEepromPageSize; /*Device Eeprom Page Size in bytes */
+  unsigned char ulBootAddress[4]; /*Device Boot Loader Start Address */
+  unsigned char uiUpperExtIOLoc[2]; /*Topmost (last) extended I/O */
+				/*location, 0 if no external I/O */
+  unsigned char ulFlashSize[4]; /*Device Flash Size */
+  unsigned char ucEepromInst[20]; /*Instructions for W/R EEPROM */
+  unsigned char ucFlashInst[3]; /*Instructions for W/R FLASH */
+  unsigned char ucSPHaddr; /* stack pointer high */
+  unsigned char ucSPLaddr; /* stack pointer low */
+  /* new as of 16-02-2004 */
+  unsigned char uiFlashpages[2]; /* number of pages in flash */
+  unsigned char ucDWDRAddress; /* DWDR register address */
+  unsigned char ucDWBasePC; /* base/mask value of the PC */
+  /* new as of 30-04-2004 */
+  unsigned char ucAllowFullPageBitstream; /* FALSE on ALL new */
+				/*parts */
+  unsigned char uiStartSmallestBootLoaderSection[2]; /* */
+  /* new as of 18-10-2004 */
+  unsigned char EnablePageProgramming; /* For JTAG parts only, */
+				/* default TRUE */
+  unsigned char ucCacheType;	/* CacheType_Normal 0x00, */
+				/* CacheType_CAN 0x01, */
+				/* CacheType_HEIMDALL 0x02 */
+				/* new as of 27-10-2004 */
+  unsigned char uiSramStartAddr[2]; /* Start of SRAM */
+  unsigned char ucResetType; /* Selects reset type. ResetNormal = 0x00 */
+                             /* ResetAT76CXXX = 0x01 */
+  unsigned char ucPCMaskExtended; /* For parts with extended PC */
+  unsigned char ucPCMaskHigh; /* PC high mask */
+  unsigned char ucEindAddress; /* Selects reset type. [EIND address...] */
+  /* new as of early 2005, firmware 4.x */
+  unsigned char EECRAddress[2]; /* EECR memory-mapped IO address */
+};
+#endif /* JTAGMKII_PRIVATE_EXPORTED */
diff --git a/avrdude/jtagmkI_private.h b/avrdude/jtagmkI_private.h
new file mode 100644
index 00000000..ec185c99
--- /dev/null
+++ b/avrdude/jtagmkI_private.h
@@ -0,0 +1,169 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2005 Joerg Wunsch <j@uriah.heep.sax.de>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 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
+ */
+
+/* $Id$ */
+
+
+/*
+ * JTAG ICE mkI definitions
+ */
+
+/* ICE command codes */
+/* 0x20 Get Synch [Resp_OK] */
+#define CMD_GET_SYNC ' '
+
+/* 0x31 Single Step [Sync_CRC/EOP] [Resp_OK] */
+/* 0x32 Read PC [Sync_CRC/EOP] [Resp_OK] [program counter]
+ * [Resp_OK] */
+/* 0x33 Write PC [program counter] [Sync_CRC/EOP] [Resp_OK]
+ * [Resp_OK] */
+/* 0xA2 Firmware Upgrade [upgrade string] [Sync_CRC/EOP] [Resp_OK]
+ * [Resp_OK] */
+/* 0xA0 Set Device Descriptor [device info] [Sync_CRC/EOP] [Resp_OK]
+ * [Resp_OK] */
+#define CMD_SET_DEVICE_DESCRIPTOR 0xA0
+
+/* 0x42 Set Parameter [parameter] [setting] [Sync_CRC/EOP] [Resp_OK]
+ * [Resp_OK] */
+#define CMD_SET_PARAM 'B'
+
+/* 0x46 Forced Stop [Sync_CRC/EOP] [Resp_OK] [checksum][program
+ * counter] [Resp_OK] */
+#define CMD_STOP 'F'
+
+/* 0x47 Go [Sync_CRC/EOP] [Resp_OK] */
+#define CMD_GO 'G'
+
+/* 0x52 Read Memory [memory type] [word count] [start address]
+ * [Sync_CRC/EOP] [Resp_OK] [word 0] ... [word n] [checksum]
+ * [Resp_OK] */
+#define CMD_READ_MEM 'R'
+
+/* 0x53 Get Sign On [Sync_CRC/EOP] [Resp_OK] ["AVRNOCD"] [Resp_OK] */
+#define CMD_GET_SIGNON 'S'
+
+/* 0XA1 Erase Page spm [address] [Sync_CRC/EOP] [Resp_OK] [Resp_OK] */
+
+/* 0x57 Write Memory [memory type] [word count] [start address]
+ * [Sync_CRC/EOP] [Resp_OK] [Cmd_DATA] [word 0] ... [word n] */
+#define CMD_WRITE_MEM 'W'
+
+/* Second half of write memory: the data command.  Undocumented. */
+#define CMD_DATA 'h'
+
+/* 0x64 Get Debug Info [Sync_CRC/EOP] [Resp_OK] [0x00] [Resp_OK] */
+/* 0x71 Get Parameter [parameter] [Sync_CRC/EOP] [Resp_OK] [setting]
+ * [Resp_OK] */
+#define CMD_GET_PARAM 'q'
+
+/* 0x78 Reset [Sync_CRC/EOP] [Resp_OK] [Resp_OK] */
+#define CMD_RESET 'x'
+
+/* 0xA3 Enter Progmode [Sync_CRC/EOP] [Resp_OK] [Resp_OK] */
+#define CMD_ENTER_PROGMODE 0xa3
+
+/* 0xA4 Leave Progmode [Sync_CRC/EOP] [Resp_OK] [Resp_OK] */
+#define CMD_LEAVE_PROGMODE 0xa4
+
+/* 0xA5 Chip Erase [Sync_CRC/EOP] [Resp_OK] [Resp_OK] */
+#define CMD_CHIP_ERASE 0xa5
+
+
+/* ICE responses */
+#define RESP_OK 'A'
+#define RESP_BREAK 'B'
+#define RESP_INFO 'G'
+#define RESP_FAILED 'F'
+#define RESP_SYNC_ERROR 'E'
+#define RESP_SLEEP 'H'
+#define RESP_POWER 'I'
+
+#define PARM_BITRATE 'b'
+#define PARM_SW_VERSION 0x7b
+#define PARM_HW_VERSION 0x7a
+#define PARM_IREG_HIGH 0x81
+#define PARM_IREG_LOW 0x82
+#define PARM_OCD_VTARGET 0x84
+#define PARM_OCD_BREAK_CAUSE 0x85
+#define PARM_CLOCK 0x86
+#define PARM_EXTERNAL_RESET 0x8b
+#define PARM_FLASH_PAGESIZE_LOW 0x88
+#define PARM_FLASH_PAGESIZE_HIGH 0x89
+#define PARM_EEPROM_PAGESIZE 0x8a
+#define PARM_TIMERS_RUNNING 0xa0
+#define PARM_BP_FLOW 0xa1
+#define PARM_BP_X_HIGH 0xa2
+#define PARM_BP_X_LOW 0xa3
+#define PARM_BP_Y_HIGH 0xa4
+#define PARM_BP_Y_LOW 0xa5
+#define PARM_BP_MODE 0xa6
+#define PARM_JTAGID_BYTE0 0xa7
+#define PARM_JTAGID_BYTE1 0xa8
+#define PARM_JTAGID_BYTE2 0xa9
+#define PARM_JTAGID_BYTE3 0xaa
+#define PARM_UNITS_BEFORE 0xab
+#define PARM_UNITS_AFTER 0xac
+#define PARM_BIT_BEFORE 0xad
+#define PARM_BIT_AFTER 0xae
+#define PARM_PSB0_LOW 0xaf
+#define PARM_PSBO_HIGH 0xb0
+#define PARM_PSB1_LOW 0xb1
+#define PARM_PSB1_HIGH 0xb2
+#define PARM_MCU_MODE 0xb3
+
+#define JTAG_BITRATE_1_MHz   0xff
+#define JTAG_BITRATE_500_kHz 0xfe
+#define JTAG_BITRATE_250_kHz 0xfd
+#define JTAG_BITRATE_125_kHz 0xfb
+
+/* memory types for CMND_{READ,WRITE}_MEMORY */
+#define MTYPE_IO_SHADOW 0x30	/* cached IO registers? */
+#define MTYPE_SRAM 0x20		/* target's SRAM or [ext.] IO registers */
+#define MTYPE_EEPROM 0x22	/* EEPROM, what way? */
+#define MTYPE_EVENT 0x60	/* ICE event memory */
+#define MTYPE_SPM 0xA0		/* flash through LPM/SPM */
+#define MTYPE_FLASH_PAGE 0xB0	/* flash in programming mode */
+#define MTYPE_EEPROM_PAGE 0xB1	/* EEPROM in programming mode */
+#define MTYPE_FUSE_BITS 0xB2	/* fuse bits in programming mode */
+#define MTYPE_LOCK_BITS 0xB3	/* lock bits in programming mode */
+#define MTYPE_SIGN_JTAG 0xB4	/* signature in programming mode */
+#define MTYPE_OSCCAL_BYTE 0xB5	/* osccal cells in programming mode */
+
+struct device_descriptor
+{
+  unsigned char ucReadIO[8]; /*LSB = IOloc 0, MSB = IOloc63 */
+  unsigned char ucWriteIO[8]; /*LSB = IOloc 0, MSB = IOloc63 */
+  unsigned char ucReadIOShadow[8]; /*LSB = IOloc 0, MSB = IOloc63 */
+  unsigned char ucWriteIOShadow[8]; /*LSB = IOloc 0, MSB = IOloc63 */
+  unsigned char ucReadExtIO[20]; /*LSB = IOloc 96, MSB = IOloc255 */
+  unsigned char ucWriteExtIO[20]; /*LSB = IOloc 96, MSB = IOloc255 */
+  unsigned char ucReadIOExtShadow[20]; /*LSB = IOloc 96, MSB = IOloc255 */
+  unsigned char ucWriteIOExtShadow[20];/*LSB = IOloc 96, MSB = IOloc255 */
+  unsigned char ucIDRAddress; /*IDR address */
+  unsigned char ucSPMCRAddress; /*SPMCR Register address and dW BasePC */
+  unsigned char ucRAMPZAddress; /*RAMPZ Register address in SRAM I/O */
+                                /*space */
+  unsigned char uiFlashPageSize[2]; /*Device Flash Page Size, Size = */
+                                /*2 exp ucFlashPageSize */
+  unsigned char ucEepromPageSize; /*Device Eeprom Page Size in bytes */
+  unsigned char ulBootAddress[4]; /*Device Boot Loader Start Address */
+  unsigned char uiUpperExtIOLoc; /*Topmost (last) extended I/O */
+                                /*location, 0 if no external I/O */
+};
diff --git a/avrdude/lexer.l b/avrdude/lexer.l
new file mode 100644
index 00000000..926aca1c
--- /dev/null
+++ b/avrdude/lexer.l
@@ -0,0 +1,281 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2000-2004  Brian S. Dean <bsd@bsdhome.com>
+ * Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 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
+ */
+
+/* $Id$ */
+
+%{
+/* need this for the call to atof() below */
+#include <math.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "avrdude.h"
+
+#include "config.h"
+#include "config_gram.h"
+#include "lists.h"
+
+#define YY_NO_UNPUT
+
+%}
+
+DIGIT    [0-9]
+HEXDIGIT [0-9a-fA-F]
+ID       [_a-zA-Z][_a-zA-Z0-9]*
+SIGN     [+-]
+
+%x strng
+%x incl
+%x comment
+
+/* Bump resources for classic lex. */
+%e2000
+%p10000
+%n1000
+
+%%
+
+{SIGN}*{DIGIT}+            { yylval = number(yytext); return TKN_NUMBER; }
+{SIGN}*{DIGIT}+"."{DIGIT}* { yylval = number(yytext); return TKN_NUMBER; }
+{SIGN}*"."{DIGIT}*         { yylval = number(yytext); return TKN_NUMBER; }
+
+"\""      { string_buf_ptr = string_buf; BEGIN(strng); }
+
+0x{HEXDIGIT}+ { yylval = hexnumber(yytext); return TKN_NUMBER; }
+
+
+
+#   { /* The following eats '#' style comments to end of line */
+       BEGIN(comment); }
+<comment>[^\n] { /* eat comments */ }
+<comment>\n { lineno++; BEGIN(INITIAL); }
+
+
+"/*" {  /* The following eats multiline C style comments */
+        int c;
+        int comment_start;
+        
+        comment_start = lineno;
+        while (1) {
+          while (((c = input()) != '*') && (c != EOF)) {
+            /* eat up text of comment, but keep counting lines */
+            if (c == '\n')
+              lineno++;
+          }
+          
+          if (c == '*') {
+            while ((c = input()) == '*')
+              ;
+            if (c == '/')
+              break;    /* found the end */
+          }
+          
+          if (c == EOF) {
+            fprintf(stderr, "error at %s:%d: EOF in comment\n", 
+                    infile, lineno);
+            fprintf(stderr, "    comment started on line %d\n", 
+                    comment_start);
+            exit(1);
+            break;
+          }
+        }
+     }
+
+
+<strng>\" { *string_buf_ptr = 0; string_buf_ptr = string_buf;
+             yylval = string(string_buf_ptr); BEGIN(INITIAL); return TKN_STRING; }
+<strng>\\n  *string_buf_ptr++ = '\n';
+<strng>\\t  *string_buf_ptr++ = '\t';
+<strng>\\r  *string_buf_ptr++ = '\r';
+<strng>\\b  *string_buf_ptr++ = '\b';
+<strng>\\f  *string_buf_ptr++ = '\f';
+<strng>\\(.|\n)  *(string_buf_ptr++) = yytext[1];
+<strng>[^\\\n\"]+ { char *yptr = yytext; while (*yptr) 
+                                         *(string_buf_ptr++) = *(yptr++); }
+<strng>\n { fprintf(stderr, "error at line %d: unterminated character constant\n",
+            lineno); 
+            exit(1); }
+
+allowfullpagebitstream { yylval=NULL; return K_ALLOWFULLPAGEBITSTREAM; }
+arduino          { yylval=NULL; return K_ARDUINO; }
+avr910           { yylval=NULL; return K_AVR910; }
+avr910_devcode   { yylval=NULL; return K_AVR910_DEVCODE; }
+usbasp           { yylval=NULL; return K_USBASP; }
+usbtiny          { yylval=NULL; return K_USBTINY; }
+bank_size        { yylval=NULL; return K_PAGE_SIZE; }
+banked           { yylval=NULL; return K_PAGED; }
+baudrate         { yylval=NULL; return K_BAUDRATE; }
+bs2              { yylval=NULL; return K_BS2; }
+buff             { yylval=NULL; return K_BUFF; }
+buspirate        { yylval=NULL; return K_BUSPIRATE; }
+butterfly        { yylval=NULL; return K_BUTTERFLY; }
+chip_erase_delay { yylval=NULL; return K_CHIP_ERASE_DELAY; }
+desc             { yylval=NULL; return K_DESC; }
+default_parallel { yylval=NULL; return K_DEFAULT_PARALLEL; }
+default_programmer { yylval=NULL; return K_DEFAULT_PROGRAMMER; }
+default_serial   { yylval=NULL; return K_DEFAULT_SERIAL; }
+devicecode       { yylval=NULL; return K_DEVICECODE; }
+dragon_dw        { yylval=NULL; return K_DRAGON_DW; }
+dragon_hvsp      { yylval=NULL; return K_DRAGON_HVSP; }
+dragon_isp       { yylval=NULL; return K_DRAGON_ISP; }
+dragon_jtag      { yylval=NULL; return K_DRAGON_JTAG; }
+dragon_pdi       { yylval=NULL; return K_DRAGON_PDI; }
+dragon_pp        { yylval=NULL; return K_DRAGON_PP; }
+eecr             { yylval=NULL; return K_EECR; }
+eeprom           { yylval=NULL; return K_EEPROM; }
+enablepageprogramming { yylval=NULL; return K_ENABLEPAGEPROGRAMMING; }
+errled           { yylval=NULL; return K_ERRLED; }
+flash            { yylval=NULL; return K_FLASH; }
+has_jtag         { yylval=NULL; return K_HAS_JTAG; }
+has_debugwire    { yylval=NULL; return K_HAS_DW; }
+has_pdi          { yylval=NULL; return K_HAS_PDI; }
+has_tpi          { yylval=NULL; return K_HAS_TPI; }
+id               { yylval=NULL; return K_ID; }
+idr              { yylval=NULL; return K_IDR; }
+is_avr32         { yylval=NULL; return K_IS_AVR32; }
+jtagmki          { yylval=NULL; return K_JTAG_MKI; }
+jtagmkii         { yylval=NULL; return K_JTAG_MKII; }
+jtagmkii_avr32   { yylval=NULL; return K_JTAG_MKII_AVR32; }
+jtagmkii_dw      { yylval=NULL; return K_JTAG_MKII_DW; }
+jtagmkii_isp     { yylval=NULL; return K_JTAG_MKII_ISP; }
+jtagmkii_pdi     { yylval=NULL; return K_JTAG_MKII_PDI; }
+max_write_delay  { yylval=NULL; return K_MAX_WRITE_DELAY; }
+memory           { yylval=NULL; return K_MEMORY; }
+min_write_delay  { yylval=NULL; return K_MIN_WRITE_DELAY; }
+miso             { yylval=NULL; return K_MISO; }
+mosi             { yylval=NULL; return K_MOSI; }
+num_banks        { yylval=NULL; return K_NUM_PAGES; }
+num_pages        { yylval=NULL; return K_NUM_PAGES; }
+nvm_base         { yylval=NULL; return K_NVM_BASE; }
+offset           { yylval=NULL; return K_OFFSET; }
+page_size        { yylval=NULL; return K_PAGE_SIZE; }
+paged            { yylval=NULL; return K_PAGED; }
+pagel            { yylval=NULL; return K_PAGEL; }
+par              { yylval=NULL; return K_PAR; }
+parallel         { yylval=NULL; return K_PARALLEL; }
+part             { yylval=NULL; return K_PART; }
+pgmled           { yylval=NULL; return K_PGMLED; }
+programmer       { yylval=NULL; return K_PROGRAMMER; }
+pwroff_after_write { yylval=NULL; return K_PWROFF_AFTER_WRITE; }
+rampz            { yylval=NULL; return K_RAMPZ; }
+rdyled           { yylval=NULL; return K_RDYLED; }
+readback_p1      { yylval=NULL; return K_READBACK_P1; }
+readback_p2      { yylval=NULL; return K_READBACK_P2; }
+retry_pulse      { yylval=NULL; return K_RETRY_PULSE; }
+serbb            { yylval=NULL; return K_SERBB; }
+serial           { yylval=NULL; return K_SERIAL; }
+signature        { yylval=NULL; return K_SIGNATURE; }
+size             { yylval=NULL; return K_SIZE; }
+spmcr            { yylval=NULL; return K_SPMCR; }
+stk500           { yylval=NULL; return K_STK500; }
+stk500hvsp       { yylval=NULL; return K_STK500HVSP; }
+stk500pp         { yylval=NULL; return K_STK500PP; }
+stk500v2         { yylval=NULL; return K_STK500V2; }
+stk500generic    { yylval=NULL; return K_STK500GENERIC; }
+stk500_devcode   { yylval=NULL; return K_STK500_DEVCODE; }
+stk600           { yylval=NULL; return K_STK600; }
+stk600hvsp       { yylval=NULL; return K_STK600HVSP; }
+stk600pp         { yylval=NULL; return K_STK600PP; }
+type             { yylval=NULL; return K_TYPE; }
+vcc              { yylval=NULL; return K_VCC; }
+vfyled           { yylval=NULL; return K_VFYLED; }
+
+timeout          { yylval=NULL; return K_TIMEOUT; }
+stabdelay        { yylval=NULL; return K_STABDELAY; }
+cmdexedelay      { yylval=NULL; return K_CMDEXEDELAY; }
+hvspcmdexedelay  { yylval=NULL; return K_HVSPCMDEXEDELAY; }
+synchloops       { yylval=NULL; return K_SYNCHLOOPS; }
+bytedelay        { yylval=NULL; return K_BYTEDELAY; }
+pollvalue        { yylval=NULL; return K_POLLVALUE; }
+pollindex        { yylval=NULL; return K_POLLINDEX; }
+predelay         { yylval=NULL; return K_PREDELAY; }
+postdelay        { yylval=NULL; return K_POSTDELAY; }
+pollmethod       { yylval=NULL; return K_POLLMETHOD; }
+mode             { yylval=NULL; return K_MODE; }
+delay            { yylval=NULL; return K_DELAY; }
+blocksize        { yylval=NULL; return K_BLOCKSIZE; }
+readsize        { yylval=NULL; return K_READSIZE; }
+pp_controlstack  { yylval=NULL; return K_PP_CONTROLSTACK; }
+hvsp_controlstack  { yylval=NULL; return K_HVSP_CONTROLSTACK; }
+hventerstabdelay { yylval=NULL; return K_HVENTERSTABDELAY; }
+progmodedelay    { yylval=NULL; return K_PROGMODEDELAY; }
+latchcycles      { yylval=NULL; return K_LATCHCYCLES; }
+togglevtg        { yylval=NULL; return K_TOGGLEVTG; }
+poweroffdelay    { yylval=NULL; return K_POWEROFFDELAY; }
+resetdelayms     { yylval=NULL; return K_RESETDELAYMS; }
+resetdelayus     { yylval=NULL; return K_RESETDELAYUS; }
+hvleavestabdelay { yylval=NULL; return K_HVLEAVESTABDELAY; }
+resetdelay       { yylval=NULL; return K_RESETDELAY; }
+synchcycles      { yylval=NULL; return K_SYNCHCYCLES; }
+chiperasepulsewidth { yylval=NULL; return K_CHIPERASEPULSEWIDTH; }
+chiperasepolltimeout { yylval=NULL; return K_CHIPERASEPOLLTIMEOUT; }
+chiperasetime    { yylval=NULL; return K_CHIPERASETIME; }
+programfusepulsewidth { yylval=NULL; return K_PROGRAMFUSEPULSEWIDTH; }
+programfusepolltimeout { yylval=NULL; return K_PROGRAMFUSEPOLLTIMEOUT; }
+programlockpulsewidth { yylval=NULL; return K_PROGRAMLOCKPULSEWIDTH; }
+programlockpolltimeout { yylval=NULL; return K_PROGRAMLOCKPOLLTIMEOUT; }
+flash_instr      { yylval=NULL; return K_FLASH_INSTR; }
+eeprom_instr     { yylval=NULL; return K_EEPROM_INSTR; }
+
+dedicated        { yylval=new_token(K_DEDICATED); return K_DEDICATED; }
+io               { yylval=new_token(K_IO); return K_IO; }
+pseudo           { yylval=new_token(K_PSEUDO); return K_PSEUDO; }
+
+reset            { yylval=new_token(K_RESET); return K_RESET; }
+sck              { yylval=new_token(K_SCK); return K_SCK; }
+
+read             { yylval=new_token(K_READ); return K_READ; }
+write            { yylval=new_token(K_WRITE); return K_WRITE; }
+read_lo          { yylval=new_token(K_READ_LO); return K_READ_LO; }
+read_hi          { yylval=new_token(K_READ_HI); return K_READ_HI; }
+write_lo         { yylval=new_token(K_WRITE_LO); return K_WRITE_LO; }
+write_hi         { yylval=new_token(K_WRITE_HI); return K_WRITE_HI; }
+loadpage_lo      { yylval=new_token(K_LOADPAGE_LO); return K_LOADPAGE_LO; }
+loadpage_hi      { yylval=new_token(K_LOADPAGE_HI); return K_LOADPAGE_HI; }
+load_ext_addr    { yylval=new_token(K_LOAD_EXT_ADDR); return K_LOAD_EXT_ADDR; }
+writepage        { yylval=new_token(K_WRITEPAGE); return K_WRITEPAGE; }
+chip_erase       { yylval=new_token(K_CHIP_ERASE); return K_CHIP_ERASE; }
+pgm_enable       { yylval=new_token(K_PGM_ENABLE); return K_PGM_ENABLE; }
+
+no               { yylval=new_token(K_NO); return K_NO; }
+yes              { yylval=new_token(K_YES); return K_YES; }
+
+","       { yylval = NULL; pyytext(); return TKN_COMMA; }
+"="       { yylval = NULL; pyytext(); return TKN_EQUAL; }
+";"       { yylval = NULL; pyytext(); return TKN_SEMI; }
+"~"       { yylval = NULL; pyytext(); return TKN_TILDE; }
+
+"\n"      { lineno++; }
+[ \r\t]+  { /* ignore whitespace */ }
+
+c: { fprintf(stderr, "error at %s:%d: possible old-style config file entry\n",
+             infile, lineno);
+     fprintf(stderr, "  Update your config file (see %s%s for a sample)\n",
+             CONFIG_DIR, "/avrdude.conf.sample");
+     exit(1); }
+
+. { fprintf(stderr, "error at %s:%d unrecognized character: \"%s\"\n", 
+            infile, lineno, yytext); exit(1); }
+
+%%
+
diff --git a/avrdude/linux_ppdev.h b/avrdude/linux_ppdev.h
new file mode 100644
index 00000000..15043961
--- /dev/null
+++ b/avrdude/linux_ppdev.h
@@ -0,0 +1,57 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2003, 2005 Theodore A. Roth
+ *
+ * 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
+ */
+
+/* $Id$ */
+
+#ifndef linux_ppdev_h
+#define linux_ppdev_h
+
+#define OBSOLETE__IOW _IOW
+
+#include <sys/ioctl.h>
+#include <linux/parport.h>
+#include <linux/ppdev.h>
+
+#include <stdlib.h>
+
+#define ppi_claim(fd)                                        \
+  if (ioctl(fd, PPCLAIM)) {                                  \
+    fprintf(stderr, "%s: can't claim device \"%s\": %s\n\n", \
+            progname, port, strerror(errno));                \
+    close(fd);                                               \
+    exit(1);                                                 \
+  }
+
+#define ppi_release(fd)                                      \
+  if (ioctl(fd, PPRELEASE)) {                                \
+    fprintf(stderr, "%s: can't release device: %s\n\n",      \
+            progname, strerror(errno));                      \
+    exit(1);                                                 \
+  }
+
+#define DO_PPI_READ(fd, reg, valp) \
+	(void)ioctl(fd, \
+		(reg) == PPIDATA? PPRDATA: ((reg) == PPICTRL? PPRCONTROL: PPRSTATUS), \
+		    valp)
+#define DO_PPI_WRITE(fd, reg, valp) \
+	(void)ioctl(fd, \
+		(reg) == PPIDATA? PPWDATA: ((reg) == PPICTRL? PPWCONTROL: PPWSTATUS), \
+		    valp)
+
+#endif /* linux_ppdev_h */
diff --git a/avrdude/lists.c b/avrdude/lists.c
new file mode 100644
index 00000000..3d1cfc64
--- /dev/null
+++ b/avrdude/lists.c
@@ -0,0 +1,1371 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 1990-2004  Brian S. Dean <bsd@bsdhome.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+ /* $Id$ */
+
+
+
+/*----------------------------------------------------------------------
+  Id: lists.c,v 1.4 2001/08/19 23:26:20 bsd Exp $
+  ----------------------------------------------------------------------*/
+/*------------------------------------------------------------------------
+  lists.c
+
+  General purpose linked list routines.  These routines implement a
+  generic doubly linked list.  Any data type may be placed in the
+  lists.  Stacking and Queuing routines are provided via #defines
+  declared in 'lists.h'.
+
+  Author : Brian Dean
+  Date   : 10 January, 1990
+  ------------------------------------------------------------------------*/
+
+#include "ac_cfg.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "lists.h"
+
+#define MAGIC 0xb05b05b0
+
+#define CHECK_MAGIC 0 /* set to 1 to enable memory overwrite detection */
+
+#ifdef BOS
+#define MALLOC(size,x) kmalloc(size,x)
+#define FREE           kfree
+#else
+#define MALLOC(size,x) malloc(size)
+#define FREE           free
+#endif
+
+
+/*------------------------------------------------------------
+|  required private data structures
+ ------------------------------------------------------------*/
+typedef struct LISTNODE {
+#if CHECK_MAGIC
+  unsigned int      magic1;
+#endif
+  struct LISTNODE * next; /* chain to next item in the list */
+  struct LISTNODE * prev; /* chain to previous item in the list */
+  void            * data; /* pointer to user data */
+#if CHECK_MAGIC
+  unsigned int      magic2;
+#endif
+} LISTNODE;
+
+
+typedef struct NODEPOOL {
+#if CHECK_MAGIC
+  unsigned int      magic1;
+#endif
+  struct NODEPOOL * chain_next;  /* chain to next node pool */
+  struct NODEPOOL * chain_prev;  /* chain to previous node pool */
+#if CHECK_MAGIC
+  unsigned int      magic2;
+#endif
+} NODEPOOL;
+
+
+typedef struct LIST {
+#if CHECK_MAGIC
+  unsigned int magic1;
+#endif
+  int        num;           /* number of elements in the list    */
+  short int  free_on_close; /* free the LIST memory on close T/F */
+  short int  poolsize;      /* list node allocation size         */
+  int        n_ln_pool;     /* number of listnodes in a pool     */
+  LISTNODE * top;           /* top of the list                   */
+  LISTNODE * bottom;        /* bottom of the list                */
+  LISTNODE * next_ln;       /* next available list node          */
+  NODEPOOL * np_top;        /* top of the node pool chain        */
+  NODEPOOL * np_bottom;     /* bottom of the node pool chain     */
+#if CHECK_MAGIC
+  unsigned int magic2;
+#endif
+} LIST;
+
+
+/* allocate list nodes in 512 byte chunks, giving 42 elements */
+#define DEFAULT_POOLSIZE 512
+
+
+#if CHECK_MAGIC
+#define CKMAGIC(p) { if (p->magic1 != MAGIC) breakpoint(); \
+                     if (p->magic2 != MAGIC) breakpoint(); }
+
+#define CKNPMAGIC(p) cknpmagic(p)
+
+#define CKLNMAGIC(p) cklnmagic(p)
+
+#define CKLMAGIC(p)  cklmagic(p)
+#else
+#define CKMAGIC(p)
+
+#define CKNPMAGIC(p)
+
+#define CKLNMAGIC(p)
+
+#define CKLMAGIC(p)
+#endif
+
+
+static int insert_ln ( LIST * l, LISTNODE * ln, void * data_ptr );
+
+
+#if CHECK_MAGIC
+static int cknpmagic ( LIST * l )
+{
+  NODEPOOL * np;
+  int i;
+
+  i = 0;
+  np = l->np_top;
+  while (np) {
+    i++;
+    CKMAGIC(np);
+    np = np->chain_next;
+  }
+
+  i = 0;
+  np = l->np_bottom;
+  while (np) {
+    i++;
+    CKMAGIC(np);
+    np = np->chain_prev;
+  }
+
+  return 0;
+}
+
+
+
+static int cklnmagic ( LIST * l )
+{
+  LISTNODE * ln;
+  int i;
+
+  i = 0;
+  ln = l->top;
+  while (ln) {
+    i++;
+    CKMAGIC(ln);
+    ln = ln->next;
+  }
+
+  i = 0;
+  ln = l->bottom;
+  while (ln) {
+    i++;
+    CKMAGIC(ln);
+    ln = ln->prev;
+  }
+
+  return 0;
+}
+
+
+static int cklmagic ( LIST * l )
+{
+  CKMAGIC(l);
+  CKNPMAGIC(l);
+  CKLNMAGIC(l);
+  CKMAGIC(l);
+  return 0;
+}
+#endif
+
+
+/*------------------------------------------------------------
+|  new_node_pool
+|
+|  Create and initialize a new pool of list nodes.  This is
+|  just a big block of memory with the first sizeof(NODEPOOL)
+|  bytes reserved.  The first available list node resides at
+|  offset sizeof(NODEPOOL).
+ ------------------------------------------------------------*/
+static
+NODEPOOL * 
+new_nodepool ( LIST * l )
+{
+  NODEPOOL * np;
+  LISTNODE * ln;
+  int i;
+
+  CKLMAGIC(l);
+
+  /*--------------------------------------------------
+  |  get a block of memory for the new pool
+   --------------------------------------------------*/
+  np = (NODEPOOL *) MALLOC ( l->poolsize, "list node pool" );
+  if (np == NULL) {
+    return NULL;
+  }
+
+  /*--------------------------------------------------
+  |  initialize the chaining information at the
+  |  beginning of the pool.
+   --------------------------------------------------*/
+#if CHECK_MAGIC
+  np->magic1 = MAGIC;
+#endif
+  np->chain_next = NULL;
+  np->chain_prev = NULL;
+#if CHECK_MAGIC
+  np->magic2 = MAGIC;
+#endif
+
+  /*--------------------------------------------------
+  |  initialize all the list nodes within the node
+  |  pool, which begin just after the NODEPOOL
+  |  structure at the beginning of the memory block
+   --------------------------------------------------*/
+  ln = (LISTNODE *) (&np[1]);
+
+#if CHECK_MAGIC
+  ln[0].magic1 = MAGIC;
+#endif
+  ln[0].data = NULL;
+  ln[0].next = &ln[1];
+  ln[0].prev = NULL;
+#if CHECK_MAGIC
+  ln[0].magic2 = MAGIC;
+#endif
+
+  for (i=1; i<l->n_ln_pool-1; i++) {
+#if CHECK_MAGIC
+    ln[i].magic1 = MAGIC;
+#endif
+    ln[i].data = NULL;
+    ln[i].next = &ln[i+1];
+    ln[i].prev = &ln[i-1];
+#if CHECK_MAGIC
+    ln[i].magic2 = MAGIC;
+#endif
+  }
+
+#if CHECK_MAGIC
+  ln[l->n_ln_pool-1].magic1 = MAGIC;
+#endif
+  ln[l->n_ln_pool-1].data = NULL;
+  ln[l->n_ln_pool-1].next = NULL;
+  ln[l->n_ln_pool-1].prev = &ln[l->n_ln_pool-2];
+#if CHECK_MAGIC
+  ln[l->n_ln_pool-1].magic2 = MAGIC;
+#endif
+
+  CKMAGIC(np);
+
+  CKLMAGIC(l);
+
+  return np;
+}
+
+
+
+/*------------------------------------------------------------
+|  get_listnode
+|
+|  Get the next available list node.  If there are no more
+|  list nodes, another pool of list nodes is allocated.  If
+|  that fails, NULL is returned.
+ ------------------------------------------------------------*/
+static
+LISTNODE * 
+get_listnode ( LIST * l )
+{
+  LISTNODE * ln;
+  NODEPOOL * np;
+
+  CKLMAGIC(l);
+
+  if (l->next_ln == NULL) {
+    /*--------------------------------------------------
+    | allocate a new node pool and chain to the others
+     --------------------------------------------------*/
+    np = new_nodepool(l);
+    if (np == NULL) {
+      CKLMAGIC(l);
+      return NULL;
+    }
+
+    if (l->np_top == NULL) {
+      /*--------------------------------------------------
+      |  this is the first node pool for this list,
+      |  directly assign to the top and bottom.
+       --------------------------------------------------*/
+      l->np_top = np;
+      l->np_bottom = np;
+      np->chain_next = NULL;
+      np->chain_prev = NULL;
+    }
+    else {
+      /*--------------------------------------------------
+      |  this is an additional node pool, add it to the
+      |  chain.
+       --------------------------------------------------*/
+      np->chain_next = NULL;
+      np->chain_prev = l->np_bottom;
+      l->np_bottom->chain_next = np;
+      l->np_bottom = np;
+    }
+
+    /*--------------------------------------------------
+    |  set the list's pointer to the next available
+    |  list node to the first list node in this new
+    |  pool.
+     --------------------------------------------------*/
+    l->next_ln = (LISTNODE *)&np[1];
+
+    CKMAGIC(np);
+  }
+
+  /*--------------------------------------------------
+  |  get the next available list node, set the list's
+  |  next available list node to the next one in the
+  |  list.
+   --------------------------------------------------*/
+  ln = l->next_ln;
+  l->next_ln = ln->next;
+
+  CKMAGIC(ln);
+
+  /*--------------------------------------------------
+  |  initialize the new list node and return
+   --------------------------------------------------*/
+  ln->next = NULL;
+  ln->prev = NULL;
+  ln->data = NULL;
+
+  CKLMAGIC(l);
+
+  return ln;
+}
+
+
+
+/*------------------------------------------------------------
+|  free_listnode
+|
+|  Return a list node to the pool of list nodes.  This puts
+|  the node at the head of the free list, so that the next
+|  call to 'get_listnode', with return the most recently
+|  freed one.
+ ------------------------------------------------------------*/
+static
+int 
+free_listnode ( LIST * l, LISTNODE * ln )
+{
+  CKLMAGIC(l);
+
+  /*--------------------------------------------------
+  |  insert the list node at the head of the list of
+  |  free list nodes.
+   --------------------------------------------------*/
+  ln->prev = NULL;
+  ln->data = NULL;
+  ln->next = l->next_ln;
+  l->next_ln = ln;
+
+  CKLMAGIC(l);
+
+  return 0;
+}
+
+
+
+/*----------------------------------------------------------------------
+  lcreat
+
+  Create a new list data structure.  
+  
+  If liststruct is not NULL, it is used to provide the memory space
+  for the list structure instance, otherwise, the necessary memory is
+  malloc'd.
+
+  If elements is zero, the default poolsize is used, otherwise,
+  poolsizes of 'elements' elements are malloc'd to obtain the memory
+  for list nodes.  Minimum element count is 5.
+
+  The first node pool is not preallocated; instead it is malloc'd at
+  the time of the first use.
+  ----------------------------------------------------------------------*/
+LISTID
+lcreat ( void * liststruct, int elements )
+{
+  LIST * l;
+
+  if (liststruct == NULL) {
+    /*--------------------------------------------------
+      allocate memory for the list itself
+      --------------------------------------------------*/
+    l = (LIST *) MALLOC ( sizeof(LIST), "list struct" );
+    if (l == NULL) {
+      return NULL;
+    }
+    l->free_on_close = 1;
+  }
+  else {
+    /*-----------------------------------------------------------------
+      use the memory given to us for the list structure
+      -----------------------------------------------------------------*/
+    l = liststruct;
+    l->free_on_close = 0;
+  }
+
+  /*--------------------------------------------------
+  |  initialize the list
+   --------------------------------------------------*/
+#if CHECK_MAGIC
+  l->magic1 = MAGIC;
+  l->magic2 = MAGIC;
+#endif
+  l->top = NULL;
+  l->bottom = NULL;
+  l->num = 0;
+
+  if (elements == 0) {
+    l->poolsize = DEFAULT_POOLSIZE;
+  }
+  else {
+    l->poolsize = elements*sizeof(LISTNODE)+sizeof(NODEPOOL);
+  }
+
+  l->n_ln_pool = (l->poolsize-sizeof(NODEPOOL))/sizeof(LISTNODE);
+
+  if (l->n_ln_pool < 5) {
+    if (!liststruct) {
+      FREE(l);
+    }
+    return NULL;
+  }
+
+  l->np_top = NULL;
+  l->np_bottom = NULL;
+  l->next_ln = NULL;
+
+  CKLMAGIC(l);
+
+  return (LISTID)l;
+}
+
+
+/*--------------------------------------------------
+|  ldestroy_cb
+|
+|  destroy an existing list data structure, calling
+|  the user routine 'ucleanup' on the data pointer
+|  of each list element.  Allows the user to free
+|  up a list data structure and have this routine
+|  call their function to free up each list element
+|  at the same time.
+ --------------------------------------------------*/
+void 
+ldestroy_cb ( LISTID lid, void (*ucleanup)() )
+{
+  LIST * l;
+  LISTNODE * ln;
+
+  l = (LIST *)lid;
+
+  CKLMAGIC(l);
+
+  ln = l->top;
+  while (ln != NULL) {
+    ucleanup ( ln->data );
+    ln = ln->next;
+  }
+
+  ldestroy ( l );
+}
+
+
+
+/*--------------------------------------------------
+|  ldestroy
+|
+|  destroy an existing list data structure.
+|
+|  assumes that each data element does not need to
+|  be freed.
+ --------------------------------------------------*/
+void 
+ldestroy ( LISTID lid )
+{
+  LIST * l;
+  NODEPOOL * p1, * p2;
+
+  l = (LIST *)lid;
+
+  CKLMAGIC(l);
+
+  /*--------------------------------------------------
+  |  free each node pool - start at the first node
+  |  pool and free each successive until there are
+  |  no more.
+   --------------------------------------------------*/
+  p1 = l->np_top;
+  while (p1 != NULL) {
+    p2 = p1->chain_next;
+    FREE(p1);
+    p1 = p2;
+  }
+
+  /*--------------------------------------------------
+  |  now free the memory occupied by the list itself
+   --------------------------------------------------*/
+  if (l->free_on_close) {
+    FREE ( l );
+  }
+}
+
+
+
+
+/*------------------------------------------------------------
+|  ladd
+|
+|  add list - add item p to the list
+ ------------------------------------------------------------*/
+int 
+ladd ( LISTID lid, void * p )
+{
+  LIST * l;
+  LISTNODE *lnptr;
+
+  l = (LIST *)lid;
+
+  CKLMAGIC(l);
+
+  lnptr = get_listnode(l);
+  if (lnptr==NULL) {
+#ifdef BOS
+    breakpoint();
+#endif
+    return -1;
+  }
+
+  CKMAGIC(lnptr);
+
+  lnptr->data = p;
+
+  if (l->top == NULL) {
+    l->top = lnptr;
+    l->bottom = lnptr;
+    lnptr->next = NULL;
+    lnptr->prev = NULL;
+  }
+  else {
+    lnptr->prev = l->bottom;
+    lnptr->next = NULL;
+    l->bottom->next = lnptr;
+    l->bottom = lnptr;
+  }
+  l->num++;
+
+  CKLMAGIC(l);
+
+  return 0;
+}
+
+
+
+/*------------------------------------------------------------
+|  laddo
+|
+|  add list, ordered - add item p to the list, use 'compare'
+|  function to place 'p' when the comparison 'p' is less than
+|  the next item.  Return 0 if this was a unique entry,
+|  else return 1 indicating a duplicate entry, i.e., the
+|  compare function returned 0 while inserting the element.
+ ------------------------------------------------------------*/
+int 
+laddo ( LISTID lid, void * p, int (*compare)(const void *p1,const void *p2), 
+	LNODEID * firstdup )
+{
+  LIST * l;
+  LISTNODE * ln;
+  int dup, cmp;
+
+  l = (LIST *)lid;
+
+  CKLMAGIC(l);
+
+  dup = 0;
+  ln = l->top;
+
+  while (ln!=NULL) {
+    CKMAGIC(ln);
+    cmp = compare(p,ln->data);
+    if (cmp == 0) {
+      dup = 1;
+      if (firstdup)
+	*firstdup = ln;
+    }
+    if (cmp < 0) {
+      insert_ln(l,ln,p);
+      CKLMAGIC(l);
+      return dup;
+    }
+    else {
+      ln = ln->next;
+    }
+  }
+
+  ladd(l,p);
+
+  CKLMAGIC(l);
+
+  return dup;
+}
+
+
+/*---------------------------------------------------------------------------
+|  laddu
+|
+|  add list, ordered, unique - add item p to the list, use 'compare'
+|  function to place 'p' when the comparison 'p' is less than the next
+|  item.  Return 1 if the item was added, 0 if not.
+|
+ --------------------------------------------------------------------------*/
+int 
+laddu ( LISTID lid, void * p, int (*compare)(const void *p1,const void *p2) )
+{
+  LIST * l;
+  LISTNODE * ln;
+  int cmp;
+
+  l = (LIST *)lid;
+
+  CKLMAGIC(l);
+
+  ln = l->top;
+
+  while (ln!=NULL) {
+    CKMAGIC(ln);
+    cmp = compare(p,ln->data);
+    if (cmp == 0) {
+      CKLMAGIC(l);
+      return 0;
+    }
+    if (cmp < 0) {
+      insert_ln(l,ln,p);
+      CKLMAGIC(l);
+      return 1;
+    }
+    else {
+      ln = ln->next;
+    }
+  }
+
+  ladd(l,p);
+
+  CKLMAGIC(l);
+
+  return 1;
+}
+
+
+
+
+LNODEID 
+lfirst ( LISTID lid )
+{
+  CKLMAGIC(((LIST *)lid));
+  return ((LIST *)lid)->top;
+}
+
+
+LNODEID 
+llast  ( LISTID lid )
+{
+  CKLMAGIC(((LIST *)lid));
+  return ((LIST *)lid)->bottom;
+}
+
+
+LNODEID 
+lnext  ( LNODEID lnid )
+{
+  CKMAGIC(((LISTNODE *)lnid));
+  return ((LISTNODE *)lnid)->next;
+}
+
+
+LNODEID 
+lprev  ( LNODEID lnid )
+{
+  CKMAGIC(((LISTNODE *)lnid));
+  return ((LISTNODE *)lnid)->prev;
+}
+
+
+void * 
+ldata ( LNODEID lnid )
+{
+  CKMAGIC(((LISTNODE *)lnid));
+  return ((LISTNODE *)lnid)->data;
+}
+
+
+
+int
+lsize ( LISTID lid )
+{
+  CKLMAGIC(((LIST *)lid));
+  return ((LIST *)lid)->num;
+}
+
+
+
+/*------------------------------------------------------------
+|  lcat
+|
+|  catenate - catenate l2 to l1, return pointer to l1.
+ ------------------------------------------------------------*/
+LISTID
+lcat ( LISTID lid1, LISTID lid2 )
+{
+  CKLMAGIC(((LIST *)lid1));
+  CKLMAGIC(((LIST *)lid2));
+  while (lsize(lid2)) {
+    ladd ( lid1, lrmv_n(lid2,1) );
+  }
+
+  CKLMAGIC(((LIST *)lid1));
+  CKLMAGIC(((LIST *)lid2));
+
+  return lid1;
+}
+
+
+
+/*----------------------------------------------------------------------
+|  lget
+|
+|  get from list, last item - return pointer to the data of the last
+|  item in the list, non-destructive
+ ----------------------------------------------------------------------*/
+void * 
+lget ( LISTID lid )
+{
+  LIST * l;
+  LISTNODE * p;
+
+  l = (LIST *)lid;
+
+  CKLMAGIC(l);
+
+  p = l->bottom;
+
+  if (p == NULL) {
+    CKLMAGIC(l);
+    return NULL;
+  }
+  else {
+    CKLMAGIC(l);
+    return p->data;
+  }
+}
+
+
+
+/*---------------------------------------------------------------
+|  lget_n
+|
+|  get from list, index - return the nth list item, 
+|  non-destructive
+ ---------------------------------------------------------------*/
+void * 
+lget_n ( LISTID lid, unsigned int n )
+{
+  int i;
+  LIST * l;
+  LISTNODE * ln;
+
+  l = (LIST *)lid;
+
+  CKLMAGIC(l);
+
+  if ((n<1)||(n>lsize(l))) {
+    return NULL;
+  }
+
+  ln = l->top;
+  i = 1;
+  while (ln && (i!=n)) {
+    CKMAGIC(ln);
+    ln = ln->next;
+    i++;
+  }
+
+  if (ln) {
+    CKLMAGIC(l);
+    return ln->data;
+  }
+  else {
+    CKLMAGIC(l);
+    return NULL;
+  }
+}
+
+
+
+/*---------------------------------------------------------------
+|  lget_ln
+|
+|  get from list, listnode - return the nth list item, the
+|  listnode is returned instead of the data, non-destructive
+ ---------------------------------------------------------------*/
+LNODEID
+lget_ln ( LISTID lid, unsigned int n )
+{
+  int i;
+  LIST * l;
+  LISTNODE * ln;
+
+  l = (LIST *)lid;
+
+  CKLMAGIC(l);
+
+  if ((n<1)||(n>lsize(l))) {
+    return NULL;
+  }
+
+  ln = l->top;
+  i = 1;
+  while (i!=n) {
+    CKMAGIC(ln);
+    ln = ln->next;
+    i++;
+  }
+
+  CKLMAGIC(l);
+  return (LNODEID)ln;
+}
+
+
+
+/*----------------------------------------------------------------------
+|  insert_ln
+|
+|  insert data, listnode - insert data just before the list item 
+|  pointed to by 'ln'.
+|
+|  This routine is not intended to be called directly by the user
+|  because the validity of ln is not checked.  This routine is called
+|  by list manipulation routines within this module, in which ln is
+|  known to point to a valid list node.
+ ----------------------------------------------------------------------*/
+static 
+int 
+insert_ln ( LIST * l, LISTNODE * ln, void * data_ptr )
+{
+  LISTNODE * lnptr;
+
+  CKLMAGIC(l);
+
+  if (ln==NULL) {
+    ladd ( l, data_ptr );
+    CKLMAGIC(l);
+    return 0;
+  }
+
+  lnptr = get_listnode(l);
+  if (lnptr == NULL) {
+#ifdef BOS
+    breakpoint();
+#endif
+    return -1;
+  }
+
+  CKMAGIC(lnptr);
+
+  lnptr->data = data_ptr;
+
+  if (ln==l->top) {
+    /*------------------------------
+    |  insert before the list head
+     ------------------------------*/
+    lnptr->next = ln;
+    lnptr->prev = NULL;
+    ln->prev = lnptr;
+    l->top = lnptr;
+  }
+  else if (ln==NULL) {
+    /*-----------------
+    |  list was empty
+     -----------------*/
+    lnptr->next = NULL;
+    lnptr->prev = l->bottom;
+    l->bottom->next = lnptr;
+    l->bottom = lnptr;
+  }
+  else {
+    /*-----------------------------------
+    |  insert in the middle of the list
+     -----------------------------------*/
+    lnptr->next = ln;
+    lnptr->prev = ln->prev;
+    lnptr->next->prev = lnptr;
+    lnptr->prev->next = lnptr;
+  }
+
+  l->num++;
+
+  CKLMAGIC(l);
+
+  return 0;
+}
+
+
+
+/*-----------------------------------------------------------------
+|  lins_n
+|
+|  Insert data before the nth item in the list.
+ -----------------------------------------------------------------*/
+int 
+lins_n ( LISTID lid, void * data_ptr, unsigned int n )
+{
+  int i;
+  LIST * l;
+  LISTNODE * ln;
+
+  l = (LIST *)lid;
+
+  CKLMAGIC(l);
+
+  if ((n<1)||(n>(l->num+1))) {
+    return -1;
+  }
+
+  if (l->num == 0) {
+    return ladd ( lid, data_ptr );
+  }
+
+  /*----------------------------------
+  |  locate the nth item in the list
+   ----------------------------------*/
+  ln = l->top;
+  i = 1;
+  while (ln && (i!=n)) {
+    CKMAGIC(ln);
+    ln = ln->next;
+    i++;
+  }
+
+  if (!ln) {
+    CKLMAGIC(l);
+    return -1;
+  }
+
+  CKLMAGIC(l);
+
+  /*-----------------------------------------
+  |  insert before the nth item in the list
+   -----------------------------------------*/
+  return insert_ln ( l, ln, data_ptr );
+}
+
+
+/*-----------------------------------------------------------------
+|  lins_ln
+|
+|  Insert data before the list node pointed to by ln.
+ -----------------------------------------------------------------*/
+int 
+lins_ln ( LISTID lid, LNODEID lnid, void * data_ptr )
+{
+  LIST * l;
+  LISTNODE * ln;
+  LISTNODE * ln_ptr;
+
+  l = (LIST *)lid;
+  ln = (LISTNODE *)lnid;
+
+  CKLMAGIC(l);
+
+  CKMAGIC(ln);
+
+  /*-----------------------------------------
+  |  validate that ln is indeed in the list
+   -----------------------------------------*/
+  ln_ptr = l->top;
+  while ((ln_ptr!=NULL)&&(ln_ptr!=ln)) {
+    CKMAGIC(ln_ptr);
+    ln_ptr = ln_ptr->next;
+  }
+
+  if (ln_ptr == NULL) {
+    CKLMAGIC(l);
+    return -1;
+  }
+
+  CKLMAGIC(l);
+
+  /*--------------------------------
+  |  insert the data into the list
+   --------------------------------*/
+  return insert_ln ( l, ln, data_ptr );
+}
+
+
+
+/*----------------------------------------------------------------------
+|  remove_ln
+|
+|  Remove the item in the list pointed to by ln.  This routine is not
+|  intended to be called directly by the user because the validity
+|  of ln is not checked.  This routine is called by list manipulation
+|  routines within this module, in which ln is known to point to a
+|  valid list node.
+ ----------------------------------------------------------------------*/
+static
+void * 
+remove_ln ( LIST * l, LISTNODE * ln )
+{
+  void * r;
+
+  CKLMAGIC(l);
+
+  CKMAGIC(ln);
+
+  if (ln==l->top) {
+    /*------------------------------
+    |  remove the head of the list
+     ------------------------------*/
+    l->top = ln->next;
+    if (l->top != NULL) {
+      l->top->prev = NULL;
+    }
+    else {
+      /*----------------------------------------
+      |  this was the only item in the list
+       ----------------------------------------*/
+      l->bottom = NULL;
+    }
+  }
+  else if (ln==l->bottom) {
+    /*------------------------------
+    |  remove the tail of the list
+     ------------------------------*/
+    l->bottom = ln->prev;
+    if (l->bottom != NULL) {
+      l->bottom->next = NULL;
+    }
+  }
+  else {
+    /*-------------------------------------
+    |  remove from the middle of the list
+     -------------------------------------*/
+    ln->prev->next = ln->next;
+    ln->next->prev = ln->prev;
+  }
+
+  /*-----------------------------
+  |  prepare to return the data
+   -----------------------------*/
+  r = ln->data;
+
+  /*-----------------------------------------------
+  |  free the listnode for re-use
+   -----------------------------------------------*/
+  free_listnode(l,ln);
+
+  /*------------------------------------
+  |  adjust the item count of the list
+   ------------------------------------*/
+  l->num--;
+
+  CKLMAGIC(l);
+
+  return r;
+}
+
+
+
+/*-------------------------------------------------------------------------
+|  lrmv_d
+|
+|  remove from list, data - removes the data element from the list,
+|  destructive
+ -------------------------------------------------------------------------*/
+void * 
+lrmv_d ( LISTID lid, void * data_ptr )
+{
+  LIST * l;
+  LISTNODE * ln;
+  int i;
+
+  l = (LIST *)lid;
+
+  CKLMAGIC(l);
+
+  i = 0;
+  ln = l->top;
+  while (ln && (ln->data != data_ptr)) {
+    i++;
+    CKMAGIC(ln);
+    ln = ln->next;
+  }
+
+  if (ln == NULL) {
+    CKLMAGIC(l);
+    return NULL;
+  }
+  else {
+    CKLMAGIC(l);
+    return remove_ln ( l, ln );
+  }
+}
+
+
+
+/*-------------------------------------------------------------------------
+|  lrmv_ln
+|
+|  remove from list, by list node - remove the data element pointed to
+|  by 'ln' from the list, destructive
+ -------------------------------------------------------------------------*/
+void * 
+lrmv_ln ( LISTID lid, LNODEID lnid )
+{
+  LIST * l;
+  LISTNODE * ln;
+  LISTNODE * p;
+
+  l = (LIST *)lid;
+  ln = (LISTNODE *)lnid;
+
+  CKLMAGIC(l);
+
+  CKMAGIC(ln);
+
+  p = l->top;
+  while ((p!=NULL)&&(p!=ln)) {
+    CKMAGIC(p);
+    p = p->next;
+  }
+  
+  if (p==NULL) {
+    CKLMAGIC(l);
+    return NULL;
+  }
+  else {
+    CKLMAGIC(l);
+    return remove_ln ( l, p );
+  }
+}
+
+
+
+/*----------------------------------------------------------------------
+|  lrmv_n
+|
+|  remove from list, by item number - remove the nth element from
+|  the list.
+ ----------------------------------------------------------------------*/
+void * 
+lrmv_n ( LISTID lid, unsigned int n )
+{
+  int i;
+  LIST * l;
+  LISTNODE * ln;
+
+  l = (LIST *)lid;
+
+  CKLMAGIC(l);
+
+  if ((n<1)||(n>l->num)) {
+    return NULL;
+  }
+
+  ln = l->top;
+  i = 1;
+  while (ln && (i!=n)) {
+    CKMAGIC(ln);
+    ln = ln->next;
+    i++;
+  }
+
+  if (ln) {
+    CKLMAGIC(l);
+    return remove_ln ( l, ln );
+  }
+  else {
+    CKLMAGIC(l);
+    return NULL;
+  }
+}
+
+
+/*----------------------------------------------------------------------
+|  lrmv
+|
+|  remove from list, last item - remove the last item from the list,
+|  destructive
+ ----------------------------------------------------------------------*/
+void * 
+lrmv ( LISTID lid )
+{
+  LIST * l;
+  LISTNODE * p;
+
+  l = (LIST *)lid;
+
+  CKLMAGIC(l);
+
+  p = l->bottom;
+
+  if (p == NULL) {
+    CKLMAGIC(l);
+    return NULL;
+  }
+  else {
+    CKLMAGIC(l);
+    return remove_ln ( l, p );
+  }
+}
+
+
+
+/*----------------------------------------------------------------------
+|  lsrch
+|
+|  search list - return data element pointed to by 'p', NULL if not
+|  found
+ ----------------------------------------------------------------------*/
+void * 
+lsrch ( LISTID lid, void * p, int (* compare)(void * p1, void * p2) )
+{
+  LIST * l;
+  LISTNODE * ln;
+
+  l = (LIST *)lid;
+
+  CKLMAGIC(l);
+
+  ln = l->top;
+
+  while (ln!=NULL) {
+    CKMAGIC(ln);
+    if (compare(p,ln->data) == 0) {
+      CKLMAGIC(l);
+      return ln->data;
+    }
+    else {
+      ln = ln->next;
+    }
+  }
+
+  CKLMAGIC(l);
+  return NULL;
+}
+
+
+int lprint ( FILE * f, LISTID lid )
+{
+  LIST * l;
+  LISTNODE * ln;
+  NODEPOOL * np;
+  int count;
+
+  l = (LIST *)lid;
+
+  fprintf ( f, "list id %p internal data structures:\n", 
+            lid );
+#if CHECK_MAGIC
+  if ((l->magic1 != MAGIC) || (l->magic2 != MAGIC)) {
+    fprintf ( f, "  *** WARNING: LIST MAGIC IS CORRUPT ***\n" );
+  }
+  fprintf ( f, 
+            "  magic1=0x%08x\n"
+            "  magic2=0x%08x\n",
+            l->magic1, l->magic2 );
+#endif
+  fprintf ( f, "   num f pool n_ln        top     bottom    next_ln     np_top  np_bottom\n" );
+  fprintf ( f, "  ---- - ---- ---- ---------- ---------- ---------- ---------- ----------\n" );
+  fprintf ( f, "  %4d %1d %4d %4d %10p %10p %10p %10p %10p\n",
+            l->num, l->free_on_close, l->poolsize, l->n_ln_pool, 
+            l->top, l->bottom,
+            l->next_ln, l->np_top, l->np_bottom );
+  
+
+  fprintf ( f, 
+            "  node pools:\n"
+            "     idx         np     magic1       next       prev     magic2\n"
+            "    ---- ---------- ---------- ---------- ---------- ----------\n" );
+  count = 0;
+  np = l->np_top;
+  while (np != NULL) {
+    count++;
+    fprintf ( f, "    %4d %10p 0x%08x %10p %10p 0x%08x\n", 
+              count, np, 
+#if CHECK_MAGIC
+              np->magic1, 
+#else
+              0,
+#endif
+              np->chain_next, np->chain_prev, 
+#if CHECK_MAGIC
+              np->magic2
+#else
+              0
+#endif
+      );
+    np = np->chain_next;
+  }
+
+  if (f) {
+    fprintf ( f, 
+              "  list elements:\n"
+              "       n         ln     magic1       next       prev       data     magic2\n"
+              "    ---- ---------- ---------- ---------- ---------- ---------- ----------\n" );
+    count = 0;
+    ln = l->top;
+    while (ln != NULL) {
+      count++;
+      fprintf ( f, "    %4d %10p %10x %10p %10p %10p %10x\n", 
+                count, ln, 
+#if CHECK_MAGIC
+                ln->magic1,
+#else
+                0,
+#endif
+                ln->next, ln->prev, ln->data, 
+#if CHECK_MAGIC
+                ln->magic2
+#else
+                0
+#endif
+        );
+      ln = lnext(ln);
+    }
+    if (count != l->num) {
+      fprintf ( f, 
+                "  *** list count is not correct\n"
+                "  *** list id indicates %d, counted items = %d\n", 
+                l->num, count );
+    }
+  }
+
+  return 0;
+}
diff --git a/avrdude/lists.h b/avrdude/lists.h
new file mode 100644
index 00000000..bae43ffd
--- /dev/null
+++ b/avrdude/lists.h
@@ -0,0 +1,115 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 1990-2004  Brian S. Dean <bsd@bsdhome.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id$ */
+
+/*----------------------------------------------------------------------
+  Id: lists.h,v 1.2 2001/08/19 23:13:17 bsd Exp $
+  ----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------
+  General purpose linked list routines - header file declarations.
+
+  Author : Brian Dean
+  Date   : 10 January, 1990
+  ----------------------------------------------------------------------*/
+#ifndef lists_h
+#define lists_h
+
+#include <stdio.h>
+
+typedef void * LISTID;
+typedef void * LNODEID;
+
+
+/*----------------------------------------------------------------------
+  several defines to access the LIST structure as as stack or a queue
+  --- use for program readability
+  ----------------------------------------------------------------------*/
+#define STACKID LISTID
+#define SNODEID LNODEID
+#define QUEUEID LISTID
+#define QNODEID LNODEID
+
+
+#define PUSH(s,d)    lins_n(s,d,1)   /* push 'd' onto the stack */
+#define POP(s)       lrmv_n(s,1)     /* pop the stack */
+#define LOOKSTACK(s) lget_n(s,1)     /* look at the top of the stack, 
+					but don't pop */
+
+
+#define ENQUEUE(q,d) lins_n(q,d,1)   /* put 'd' on the end of the queue */
+#define DEQUEUE(q)   lrmv(q)         /* remove next item from the front of 
+					the queue */
+#define REQUEUE(q,d) ladd(q,d)       /* re-insert (push) item back on the
+					front of the queue */
+#define LOOKQUEUE(q) lget(q)         /* return next item on the queue, 
+					but don't dequeue */
+#define QUEUELEN(q)  lsize(q)       /* length of the queue */
+
+
+#define LISTADD(l,d) ladd(l,d)       /* add to end of the list */
+#define LISTRMV(l,d) lrmv_d(l,d)     /* remove from end of the list */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* .................... Function Prototypes .................... */
+
+LISTID     lcreat      ( void * liststruct, int poolsize );
+void       ldestroy    ( LISTID lid );
+void       ldestroy_cb ( LISTID lid, void (*ucleanup)() );
+
+LNODEID    lfirst ( LISTID  ); /* head of the list */
+LNODEID    llast  ( LISTID  ); /* tail of the list */
+LNODEID    lnext  ( LNODEID ); /* next item in the list */
+LNODEID    lprev  ( LNODEID ); /* previous item in the list */
+void     * ldata  ( LNODEID ); /* data at the current position */
+int        lsize  ( LISTID  ); /* number of elements in the list */
+
+int        ladd     ( LISTID lid, void * p );
+int        laddo    ( LISTID lid, void *p, 
+		      int (*compare)(const void *p1,const void *p2),
+		      LNODEID * firstdup );
+int        laddu    ( LISTID lid, void * p, 
+		      int (*compare)(const void *p1,const void *p2));
+int        lins_n   ( LISTID lid, void * d, unsigned int n );
+int        lins_ln  ( LISTID lid, LNODEID lnid, void * data_ptr );
+
+void     * lget    ( LISTID lid );
+void     * lget_n  ( LISTID lid, unsigned int n );
+LNODEID    lget_ln ( LISTID lid, unsigned int n );
+
+void     * lrmv    ( LISTID lid );
+void     * lrmv_n  ( LISTID lid, unsigned int n );
+void     * lrmv_ln ( LISTID lid, LNODEID lnid );
+void     * lrmv_d  ( LISTID lid, void * data_ptr );
+
+LISTID     lcat    ( LISTID lid1, LISTID lid2 );
+
+void     * lsrch   ( LISTID lid, void * p, int (*compare)(void *p1,void *p2));
+
+int        lprint  ( FILE * f, LISTID lid );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/avrdude/main.c b/avrdude/main.c
new file mode 100644
index 00000000..98af95c5
--- /dev/null
+++ b/avrdude/main.c
@@ -0,0 +1,1264 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2000-2005  Brian S. Dean <bsd@bsdhome.com>
+ * Copyright 2007-2009 Joerg Wunsch <j@uriah.heep.sax.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 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
+ */
+
+/* $Id$ */
+
+/*
+ * Code to program an Atmel AVR device through one of the supported
+ * programmers.
+ *
+ * For parallel port connected programmers, the pin definitions can be
+ * changed via a config file.  See the config file for instructions on
+ * how to add a programmer definition.
+ *  
+ */
+
+#include "ac_cfg.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include "avr.h"
+#include "config.h"
+#include "confwin.h"
+#include "fileio.h"
+#include "lists.h"
+#include "par.h"
+#include "pindefs.h"
+#include "term.h"
+#include "safemode.h"
+#include "update.h"
+
+
+/* Get VERSION from ac_cfg.h */
+char * version      = VERSION;
+
+char * progname;
+char   progbuf[PATH_MAX]; /* temporary buffer of spaces the same
+                             length as progname; used for lining up
+                             multiline messages */
+
+struct list_walk_cookie
+{
+    FILE *f;
+    const char *prefix;
+};
+
+static LISTID updates;
+
+static LISTID extended_params;
+
+static PROGRAMMER * pgm;
+
+/*
+ * global options
+ */
+int    do_cycles;   /* track erase-rewrite cycles */
+int    verbose;     /* verbose output */
+int    quell_progress; /* un-verebose output */
+int    ovsigck;     /* 1=override sig check, 0=don't */
+
+
+/*
+ * usage message
+ */
+static void usage(void)
+{
+  fprintf(stderr,
+ "Usage: %s [options]\n"
+ "Options:\n"
+ "  -p <partno>                Required. Specify AVR device.\n"
+ "  -b <baudrate>              Override RS-232 baud rate.\n"
+ "  -B <bitclock>              Specify JTAG/STK500v2 bit clock period (us).\n"
+ "  -C <config-file>           Specify location of configuration file.\n"
+ "  -c <programmer>            Specify programmer type.\n"
+ "  -D                         Disable auto erase for flash memory\n"
+ "  -i <delay>                 ISP Clock Delay [in microseconds]\n"
+ "  -P <port>                  Specify connection port.\n"
+ "  -F                         Override invalid signature check.\n"
+ "  -e                         Perform a chip erase.\n"
+ "  -O                         Perform RC oscillator calibration (see AVR053). \n"
+ "  -U <memtype>:r|w|v:<filename>[:format]\n"
+ "                             Memory operation specification.\n"
+ "                             Multiple -U options are allowed, each request\n"
+ "                             is performed in the order specified.\n"
+ "  -n                         Do not write anything to the device.\n"
+ "  -V                         Do not verify.\n"
+ "  -u                         Disable safemode, default when running from a script.\n"
+ "  -s                         Silent safemode operation, will not ask you if\n"
+ "                             fuses should be changed back.\n"
+ "  -t                         Enter terminal mode.\n"
+ "  -E <exitspec>[,<exitspec>] List programmer exit specifications.\n"
+ "  -x <extended_param>        Pass <extended_param> to programmer.\n"
+ "  -y                         Count # erase cycles in EEPROM.\n"
+ "  -Y <number>                Initialize erase cycle # in EEPROM.\n"
+ "  -v                         Verbose output. -v -v for more.\n"
+ "  -q                         Quell progress output. -q -q for less.\n"
+ "  -?                         Display this usage.\n"
+ "\navrdude version %s, URL: <http://savannah.nongnu.org/projects/avrdude/>\n"
+          ,progname, version);
+}
+
+
+static void update_progress_tty (int percent, double etime, char *hdr)
+{
+  static char hashes[51];
+  static char *header;
+  static int last = 0;
+  int i;
+
+  setvbuf(stderr, (char*)NULL, _IONBF, 0);
+
+  hashes[50] = 0;
+
+  memset (hashes, ' ', 50);
+  for (i=0; i<percent; i+=2) {
+    hashes[i/2] = '#';
+  }
+
+  if (hdr) {
+    fprintf (stderr, "\n");
+    last = 0;
+    header = hdr;
+  }
+
+  if (last == 0) {
+    fprintf(stderr, "\r%s | %s | %d%% %0.2fs", 
+            header, hashes, percent, etime);
+  }
+
+  if (percent == 100) {
+    last = 1;
+    fprintf (stderr, "\n\n");
+  }
+
+  setvbuf(stderr, (char*)NULL, _IOLBF, 0);
+}
+
+static void update_progress_no_tty (int percent, double etime, char *hdr)
+{
+  static int done = 0;
+  static int last = 0;
+  int cnt = (percent>>1)*2;
+
+  setvbuf(stderr, (char*)NULL, _IONBF, 0);
+
+  if (hdr) {
+    fprintf (stderr, "\n%s | ", hdr);
+    last = 0;
+    done = 0;
+  }
+  else {
+    while ((cnt > last) && (done == 0)) {
+      fprintf (stderr, "#");
+      cnt -=  2;
+    }
+  }
+
+  if ((percent == 100) && (done == 0)) {
+    fprintf (stderr, " | 100%% %0.2fs\n\n", etime);
+    last = 0;
+    done = 1;
+  }
+  else
+    last = (percent>>1)*2;    /* Make last a multiple of 2. */
+
+  setvbuf(stderr, (char*)NULL, _IOLBF, 0);
+}
+
+static void list_programmers_callback(const char *name, const char *desc,
+                                      const char *cfgname, int cfglineno,
+                                      void *cookie)
+{
+    struct list_walk_cookie *c = (struct list_walk_cookie *)cookie;
+
+    fprintf(c->f, "%s%-8s = %-30s [%s:%d]\n",
+            c->prefix, name, desc, cfgname, cfglineno);
+}
+
+static void list_programmers(FILE * f, const char *prefix, LISTID programmers)
+{
+    struct list_walk_cookie c;
+
+    c.f = f;
+    c.prefix = prefix;
+
+    walk_programmers(programmers, list_programmers_callback, &c);
+}
+
+static void list_avrparts_callback(const char *name, const char *desc,
+                                   const char *cfgname, int cfglineno,
+                                   void *cookie)
+{
+    struct list_walk_cookie *c = (struct list_walk_cookie *)cookie;
+
+    fprintf(c->f, "%s%-4s = %-15s [%s:%d]\n",
+            c->prefix, name, desc, cfgname, cfglineno);
+}
+
+static void list_parts(FILE * f, const char *prefix, LISTID avrparts)
+{
+    struct list_walk_cookie c;
+
+    c.f = f;
+    c.prefix = prefix;
+
+    walk_avrparts(avrparts, list_avrparts_callback, &c);
+}
+
+static void exithook(void)
+{
+    if (pgm->teardown)
+        pgm->teardown(pgm);
+}
+
+/*
+ * main routine
+ */
+int main(int argc, char * argv [])
+{
+  int              rc;          /* general return code checking */
+  int              exitrc;      /* exit code for main() */
+  int              i;           /* general loop counter */
+  int              ch;          /* options flag */
+  int              len;         /* length for various strings */
+  struct avrpart * p;           /* which avr part we are programming */
+  struct avrpart * v;           /* used for verify */
+  AVRMEM         * sig;         /* signature data */
+  struct stat      sb;
+  UPDATE         * upd;
+  LNODEID        * ln;
+
+
+  /* options / operating mode variables */
+  int     erase;       /* 1=erase chip, 0=don't */
+  int     calibrate;   /* 1=calibrate RC oscillator, 0=don't */
+  int     auto_erase;  /* 0=never erase unless explicity told to do
+                          so, 1=erase if we are going to program flash */
+  char  * port;        /* device port (/dev/xxx) */
+  int     terminal;    /* 1=enter terminal mode, 0=don't */
+  int     nowrite;     /* don't actually write anything to the chip */
+  int     verify;      /* perform a verify operation */
+  char  * exitspecs;   /* exit specs string from command line */
+  char  * programmer;  /* programmer id */
+  char  * partdesc;    /* part id */
+  char    sys_config[PATH_MAX]; /* system wide config file */
+  char    usr_config[PATH_MAX]; /* per-user config file */
+  int     cycles;      /* erase-rewrite cycles */
+  int     set_cycles;  /* value to set the erase-rewrite cycles to */
+  char  * e;           /* for strtol() error checking */
+  int     baudrate;    /* override default programmer baud rate */
+  double  bitclock;    /* Specify programmer bit clock (JTAG ICE) */
+  int     ispdelay;    /* Specify the delay for ISP clock */
+  int     safemode;    /* Enable safemode, 1=safemode on, 0=normal */
+  int     silentsafe;  /* Don't ask about fuses, 1=silent, 0=normal */
+  int     init_ok;     /* Device initialization worked well */
+  int     is_open;     /* Device open succeeded */
+  unsigned char safemode_lfuse = 0xff;
+  unsigned char safemode_hfuse = 0xff;
+  unsigned char safemode_efuse = 0xff;
+  unsigned char safemode_fuse = 0xff;
+
+  char * safemode_response;
+  int fuses_specified = 0;
+  int fuses_updated = 0;
+#if !defined(WIN32NATIVE)
+  char  * homedir;
+#endif
+
+  /*
+   * Set line buffering for file descriptors so we see stdout and stderr
+   * properly interleaved.
+   */
+  setvbuf(stdout, (char*)NULL, _IOLBF, 0);
+  setvbuf(stderr, (char*)NULL, _IOLBF, 0);
+
+  progname = strrchr(argv[0],'/');
+
+#if defined (WIN32NATIVE)
+  /* take care of backslash as dir sep in W32 */
+  if (!progname) progname = strrchr(argv[0],'\\');
+#endif /* WIN32NATIVE */
+
+  if (progname)
+    progname++;
+  else
+    progname = argv[0];
+
+  default_parallel[0] = 0;
+  default_serial[0]   = 0;
+
+  init_config();
+
+  updates = lcreat(NULL, 0);
+  if (updates == NULL) {
+    fprintf(stderr, "%s: cannot initialize updater list\n", progname);
+    exit(1);
+  }
+
+  extended_params = lcreat(NULL, 0);
+  if (extended_params == NULL) {
+    fprintf(stderr, "%s: cannot initialize extended parameter list\n", progname);
+    exit(1);
+  }
+
+  partdesc      = NULL;
+  port          = default_parallel;
+  erase         = 0;
+  calibrate     = 0;
+  auto_erase    = 1;
+  p             = NULL;
+  ovsigck       = 0;
+  terminal      = 0;
+  nowrite       = 0;
+  verify        = 1;        /* on by default */
+  quell_progress = 0;
+  exitspecs     = NULL;
+  pgm           = NULL;
+  programmer    = default_programmer;
+  verbose       = 0;
+  do_cycles     = 0;
+  set_cycles    = -1;
+  baudrate      = 0;
+  bitclock      = 0.0;
+  ispdelay      = 0;
+  safemode      = 1;       /* Safemode on by default */
+  silentsafe    = 0;       /* Ask by default */
+  is_open       = 0;
+
+  if (isatty(STDIN_FILENO) == 0)
+      safemode  = 0;       /* Turn off safemode if this isn't a terminal */
+
+
+
+#if defined(WIN32NATIVE)
+
+  win_sys_config_set(sys_config);
+  win_usr_config_set(usr_config);
+
+#else
+
+  strcpy(sys_config, CONFIG_DIR);
+  i = strlen(sys_config);
+  if (i && (sys_config[i-1] != '/'))
+    strcat(sys_config, "/");
+  strcat(sys_config, "avrdude.conf");
+
+  usr_config[0] = 0;
+  homedir = getenv("HOME");
+  if (homedir != NULL) {
+    strcpy(usr_config, homedir);
+    i = strlen(usr_config);
+    if (i && (usr_config[i-1] != '/'))
+      strcat(usr_config, "/");
+    strcat(usr_config, ".avrduderc");
+  }
+
+#endif
+
+  len = strlen(progname) + 2;
+  for (i=0; i<len; i++)
+    progbuf[i] = ' ';
+  progbuf[i] = 0;
+
+  /*
+   * check for no arguments
+   */
+  if (argc == 1) {
+    usage();
+    return 0;
+  }
+
+
+  /*
+   * process command line arguments
+   */
+  while ((ch = getopt(argc,argv,"?b:B:c:C:DeE:Fi:np:OP:qstU:uvVx:yY:")) != -1) {
+
+    switch (ch) {
+      case 'b': /* override default programmer baud rate */
+        baudrate = strtol(optarg, &e, 0);
+        if ((e == optarg) || (*e != 0)) {
+          fprintf(stderr, "%s: invalid baud rate specified '%s'\n",
+                  progname, optarg);
+          exit(1);
+        }
+        break;
+
+      case 'B':	/* specify JTAG ICE bit clock period */
+	bitclock = strtod(optarg, &e);
+	if ((e == optarg) || (*e != 0) || bitclock == 0.0) {
+	  fprintf(stderr, "%s: invalid bit clock period specified '%s'\n",
+                  progname, optarg);
+          exit(1);
+        }
+        break;
+
+      case 'i':	/* specify isp clock delay */
+	ispdelay = strtol(optarg, &e,10);
+	if ((e == optarg) || (*e != 0) || ispdelay == 0) {
+	  fprintf(stderr, "%s: invalid isp clock delay specified '%s'\n",
+                  progname, optarg);
+          exit(1);
+        }
+        break;
+
+      case 'c': /* programmer id */
+        programmer = optarg;
+        break;
+
+      case 'C': /* system wide configuration file */
+        strncpy(sys_config, optarg, PATH_MAX);
+        sys_config[PATH_MAX-1] = 0;
+        break;
+
+      case 'D': /* disable auto erase */
+        auto_erase = 0;
+        break;
+
+      case 'e': /* perform a chip erase */
+        erase = 1;
+        break;
+
+      case 'E':
+        exitspecs = optarg;
+        break;
+
+      case 'F': /* override invalid signature check */
+        ovsigck = 1;
+        break;
+
+      case 'n':
+        nowrite = 1;
+        break;
+
+      case 'O': /* perform RC oscillator calibration */
+	calibrate = 1;
+	break;
+
+      case 'p' : /* specify AVR part */
+        partdesc = optarg;
+        break;
+
+      case 'P':
+        port = optarg;
+        break;
+
+      case 'q' : /* Quell progress output */
+        quell_progress++ ;
+        break;
+
+      case 's' : /* Silent safemode */
+        silentsafe = 1;
+        safemode = 1;
+        break;
+        
+      case 't': /* enter terminal mode */
+        terminal = 1;
+        break;
+
+      case 'u' : /* Disable safemode */
+        safemode = 0;
+        break;
+
+      case 'U':
+        upd = parse_op(optarg);
+        if (upd == NULL) {
+          fprintf(stderr, "%s: error parsing update operation '%s'\n",
+                  progname, optarg);
+          exit(1);
+        }
+        ladd(updates, upd);
+
+        if (verify && upd->op == DEVICE_WRITE) {
+          upd = dup_update(upd);
+          upd->op = DEVICE_VERIFY;
+          ladd(updates, upd);
+        }
+        break;
+
+      case 'v':
+        verbose++;
+        break;
+
+      case 'V':
+        verify = 0;
+        break;
+
+      case 'x':
+        ladd(extended_params, optarg);
+        break;
+
+      case 'y':
+        do_cycles = 1;
+        break;
+
+      case 'Y':
+        set_cycles = strtol(optarg, &e, 0);
+        if ((e == optarg) || (*e != 0)) {
+          fprintf(stderr, "%s: invalid cycle count '%s'\n",
+                  progname, optarg);
+          exit(1);
+        }
+        do_cycles = 1;
+        break;
+
+      case '?': /* help */
+        usage();
+        exit(0);
+        break;
+
+      default:
+        fprintf(stderr, "%s: invalid option -%c\n\n", progname, ch);
+        usage();
+        exit(1);
+        break;
+    }
+
+  }
+
+
+  if (quell_progress == 0) {
+    if (isatty (STDERR_FILENO))
+      update_progress = update_progress_tty;
+    else {
+      update_progress = update_progress_no_tty;
+      /* disable all buffering of stderr for compatibility with
+         software that captures and redirects output to a GUI
+         i.e. Programmers Notepad */
+      setvbuf( stderr, NULL, _IONBF, 0 );
+      setvbuf( stdout, NULL, _IONBF, 0 );
+    }
+  }
+
+  if (verbose) {
+    /*
+     * Print out an identifying string so folks can tell what version
+     * they are running
+     */
+    fprintf(stderr,
+            "\n%s: Version %s, compiled on %s at %s\n"
+            "%sCopyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/\n"
+	    "%sCopyright (c) 2007-2009 Joerg Wunsch\n\n",
+            progname, version, __DATE__, __TIME__, progbuf, progbuf);
+  }
+
+  if (verbose) {
+    fprintf(stderr, "%sSystem wide configuration file is \"%s\"\n",
+            progbuf, sys_config);
+  }
+
+  rc = read_config(sys_config);
+  if (rc) {
+    fprintf(stderr,
+            "%s: error reading system wide configuration file \"%s\"\n",
+            progname, sys_config);
+    exit(1);
+  }
+
+  if (usr_config[0] != 0) {
+    if (verbose) {
+      fprintf(stderr, "%sUser configuration file is \"%s\"\n",
+              progbuf, usr_config);
+    }
+
+    rc = stat(usr_config, &sb);
+    if ((rc < 0) || ((sb.st_mode & S_IFREG) == 0)) {
+      if (verbose) {
+        fprintf(stderr,
+                "%sUser configuration file does not exist or is not a "
+                "regular file, skipping\n",
+                progbuf);
+      }
+    }
+    else {
+      rc = read_config(usr_config);
+      if (rc) {
+        fprintf(stderr, "%s: error reading user configuration file \"%s\"\n",
+                progname, usr_config);
+        exit(1);
+      }
+    }
+  }
+
+  if (verbose) {
+    fprintf(stderr, "\n");
+  }
+
+  if (partdesc) {
+    if (strcmp(partdesc, "?") == 0) {
+      fprintf(stderr, "\n");
+      fprintf(stderr,"Valid parts are:\n");
+      list_parts(stderr, "  ", part_list);
+      fprintf(stderr, "\n");
+      exit(1);
+    }
+  }
+
+  if (programmer) {
+    if (strcmp(programmer, "?") == 0) {
+      fprintf(stderr, "\n");
+      fprintf(stderr,"Valid programmers are:\n");
+      list_programmers(stderr, "  ", programmers);
+      fprintf(stderr,"\n");
+      exit(1);
+    }
+  }
+
+
+  if (programmer[0] == 0) {
+    fprintf(stderr,
+            "\n%s: no programmer has been specified on the command line "
+            "or the config file\n",
+            progname);
+    fprintf(stderr,
+            "%sSpecify a programmer using the -c option and try again\n\n",
+            progbuf);
+    exit(1);
+  }
+
+  pgm = locate_programmer(programmers, programmer);
+  if (pgm == NULL) {
+    fprintf(stderr,"\n");
+    fprintf(stderr,
+            "%s: Can't find programmer id \"%s\"\n",
+            progname, programmer);
+    fprintf(stderr,"\nValid programmers are:\n");
+    list_programmers(stderr, "  ", programmers);
+    fprintf(stderr,"\n");
+    exit(1);
+  }
+
+  if (pgm->setup) {
+    pgm->setup(pgm);
+  }
+  if (pgm->teardown) {
+    atexit(exithook);
+  }
+
+  if (lsize(extended_params) > 0) {
+    if (pgm->parseextparams == NULL) {
+      fprintf(stderr,
+              "%s: WARNING: Programmer doesn't support extended parameters,"
+              " -x option(s) ignored\n",
+              progname);
+    } else {
+      if (pgm->parseextparams(pgm, extended_params) < 0) {
+        fprintf(stderr,
+              "%s: Error parsing extended parameter list\n",
+              progname);
+        exit(1);
+      }
+    }
+  }
+
+  if ((strcmp(pgm->type, "STK500") == 0) ||
+      (strcmp(pgm->type, "avr910") == 0) ||
+      (strcmp(pgm->type, "BusPirate") == 0) ||
+      (strcmp(pgm->type, "STK500V2") == 0) ||
+      (strcmp(pgm->type, "JTAGMKII") == 0)) {
+    if (port == default_parallel) {
+      port = default_serial;
+    }
+  }
+  
+  if (partdesc == NULL) {
+    fprintf(stderr,
+            "%s: No AVR part has been specified, use \"-p Part\"\n\n",
+            progname);
+    fprintf(stderr,"Valid parts are:\n");
+    list_parts(stderr, "  ", part_list);
+    fprintf(stderr, "\n");
+    exit(1);
+  }
+
+
+  p = locate_part(part_list, partdesc);
+  if (p == NULL) {
+    fprintf(stderr,
+            "%s: AVR Part \"%s\" not found.\n\n",
+            progname, partdesc);
+    fprintf(stderr,"Valid parts are:\n");
+    list_parts(stderr, "  ", part_list);
+    fprintf(stderr, "\n");
+    exit(1);
+  }
+
+
+  if (exitspecs != NULL) {
+    if (pgm->parseexitspecs == NULL) {
+      fprintf(stderr,
+              "%s: WARNING: -E option not supported by this programmer type\n",
+              progname);
+      exitspecs = NULL;
+    }
+    else if (pgm->parseexitspecs(pgm, exitspecs) < 0) {
+      usage();
+      exit(1);
+    }
+  }
+
+  if(p->flags & AVRPART_AVR32) {
+    safemode = 0;
+    auto_erase = 0;
+  }
+
+  if(p->flags & (AVRPART_HAS_PDI | AVRPART_HAS_TPI)) {
+    safemode = 0;
+  }
+
+  /*
+   * set up seperate instances of the avr part, one for use in
+   * programming, one for use in verifying.  These are separate
+   * because they need separate flash and eeprom buffer space
+   */
+  p = avr_dup_part(p);
+  v = avr_dup_part(p);
+
+  /*
+   * open the programmer
+   */
+  if (port[0] == 0) {
+    fprintf(stderr, "\n%s: no port has been specified on the command line "
+            "or the config file\n",
+            progname);
+    fprintf(stderr, "%sSpecify a port using the -P option and try again\n\n",
+            progbuf);
+    exit(1);
+  }
+
+  if (verbose) {
+    fprintf(stderr, "%sUsing Port                    : %s\n", progbuf, port);
+    fprintf(stderr, "%sUsing Programmer              : %s\n", progbuf, programmer);
+    if ((strcmp(pgm->type, "avr910") == 0)) {
+	  fprintf(stderr, "%savr910_devcode (avrdude.conf) : ", progbuf);
+      if(p->avr910_devcode)fprintf(stderr, "0x%x\n", p->avr910_devcode);
+	  else fprintf(stderr, "none\n");
+    }  
+  }
+
+  if (baudrate != 0) {
+    if (verbose) {
+      fprintf(stderr, "%sOverriding Baud Rate          : %d\n", progbuf, baudrate);
+    }
+    pgm->baudrate = baudrate;
+  }
+
+  if (bitclock != 0.0) {
+    if (verbose) {
+      fprintf(stderr, "%sSetting bit clk period        : %.1f\n", progbuf, bitclock);
+    }
+    pgm->bitclock = bitclock * 1e-6;
+  }
+
+  if (ispdelay != 0) {
+    if (verbose) {
+      fprintf(stderr, "%sSetting isp clock delay        : %3i\n", progbuf, ispdelay);
+    }
+    pgm->ispdelay = ispdelay;
+  }
+
+  rc = pgm->open(pgm, port);
+  if (rc < 0) {
+    exitrc = 1;
+    pgm->ppidata = 0; /* clear all bits at exit */
+    goto main_exit;
+  }
+  is_open = 1;
+
+  if (calibrate) {
+    /*
+     * perform an RC oscillator calibration
+     * as outlined in appnote AVR053
+     */
+    if (pgm->perform_osccal == 0) {
+      fprintf(stderr,
+              "%s: programmer does not support RC oscillator calibration\n",
+	      progname);
+      exitrc = 1;
+    } else {
+      fprintf(stderr, "%s: performing RC oscillator calibration\n", progname);
+      exitrc = pgm->perform_osccal(pgm);
+    }
+    if (exitrc == 0 && quell_progress < 2) {
+      fprintf(stderr,
+              "%s: calibration value is now stored in EEPROM at address 0\n",
+              progname);
+    }
+    goto main_exit;
+  }
+
+  if (verbose) {
+    avr_display(stderr, p, progbuf, verbose);
+    fprintf(stderr, "\n");
+    programmer_display(pgm, progbuf);
+  }
+
+  if (quell_progress < 2) {
+    fprintf(stderr, "\n");
+  }
+
+  exitrc = 0;
+
+  /*
+   * enable the programmer
+   */
+  pgm->enable(pgm);
+
+  /*
+   * turn off all the status leds
+   */
+  pgm->rdy_led(pgm, OFF);
+  pgm->err_led(pgm, OFF);
+  pgm->pgm_led(pgm, OFF);
+  pgm->vfy_led(pgm, OFF);
+
+  /*
+   * initialize the chip in preperation for accepting commands
+   */
+  init_ok = (rc = pgm->initialize(pgm, p)) >= 0;
+  if (!init_ok) {
+    fprintf(stderr, "%s: initialization failed, rc=%d\n", progname, rc);
+    if (!ovsigck) {
+      fprintf(stderr, "%sDouble check connections and try again, "
+              "or use -F to override\n"
+              "%sthis check.\n\n",
+              progbuf, progbuf);
+      exitrc = 1;
+      goto main_exit;
+    }
+  }
+
+  /* indicate ready */
+  pgm->rdy_led(pgm, ON);
+
+  if (quell_progress < 2) {
+    fprintf(stderr,
+            "%s: AVR device initialized and ready to accept instructions\n",
+            progname);
+  }
+
+  /*
+   * Let's read the signature bytes to make sure there is at least a
+   * chip on the other end that is responding correctly.  A check
+   * against 0xffffff / 0x000000 should ensure that the signature bytes
+   * are valid.
+   */
+  if(!(p->flags & AVRPART_AVR32)) {
+    if (init_ok) {
+      rc = avr_signature(pgm, p);
+      if (rc != 0) {
+        fprintf(stderr, "%s: error reading signature data, rc=%d\n",
+          progname, rc);
+        exitrc = 1;
+        goto main_exit;
+      }
+    }
+  
+    sig = avr_locate_mem(p, "signature");
+    if (sig == NULL) {
+      fprintf(stderr,
+              "%s: WARNING: signature data not defined for device \"%s\"\n",
+              progname, p->desc);
+    }
+
+    if (sig != NULL) {
+      int ff, zz;
+
+      if (quell_progress < 2) {
+        fprintf(stderr, "%s: Device signature = 0x", progname);
+      }
+      ff = zz = 1;
+      for (i=0; i<sig->size; i++) {
+        if (quell_progress < 2) {
+          fprintf(stderr, "%02x", sig->buf[i]);
+        }
+        if (sig->buf[i] != 0xff)
+          ff = 0;
+        if (sig->buf[i] != 0x00)
+          zz = 0;
+      }
+      if (quell_progress < 2) {
+        fprintf(stderr, "\n");
+      }
+
+      if (ff || zz) {
+        fprintf(stderr,
+                "%s: Yikes!  Invalid device signature.\n", progname);
+        if (!ovsigck) {
+          fprintf(stderr, "%sDouble check connections and try again, "
+                  "or use -F to override\n"
+                  "%sthis check.\n\n",
+                  progbuf, progbuf);
+          exitrc = 1;
+          goto main_exit;
+        }
+      }
+    }
+    
+    if (sig->size != 3 ||
+    sig->buf[0] != p->signature[0] ||
+    sig->buf[1] != p->signature[1] ||
+    sig->buf[2] != p->signature[2]) {
+      fprintf(stderr,
+          "%s: Expected signature for %s is %02X %02X %02X\n",
+          progname, p->desc,
+          p->signature[0], p->signature[1], p->signature[2]);
+      if (!ovsigck) {
+        fprintf(stderr, "%sDouble check chip, "
+        "or use -F to override this check.\n",
+                progbuf);
+        exitrc = 1;
+        goto main_exit;
+      }
+    }
+  }
+
+  if (init_ok && safemode == 1) {
+    /* If safemode is enabled, go ahead and read the current low, high,
+       and extended fuse bytes as needed */
+
+    rc = safemode_readfuses(&safemode_lfuse, &safemode_hfuse,
+                           &safemode_efuse, &safemode_fuse, pgm, p, verbose);
+
+    if (rc != 0) {
+
+	  //Check if the programmer just doesn't support reading
+  	  if (rc == -5)
+			{
+			  if (verbose > 0)
+				{
+				fprintf(stderr, "%s: safemode: Fuse reading not support by programmer.\n"
+                	            "              Safemode disabled.\n", progname);
+				}
+	  		safemode = 0;
+			}
+      else
+			{
+
+      		fprintf(stderr, "%s: safemode: To protect your AVR the programming "
+            				    "will be aborted\n",
+               					 progname);
+      		exitrc = 1;
+		    goto main_exit;
+			}
+    } else {
+      //Save the fuses as default
+      safemode_memfuses(1, &safemode_lfuse, &safemode_hfuse, &safemode_efuse, &safemode_fuse);
+    }
+  }
+
+  if ((erase == 0) && (auto_erase == 1)) {
+    AVRMEM * m;
+    for (ln=lfirst(updates); ln; ln=lnext(ln)) {
+      upd = ldata(ln);
+      m = avr_locate_mem(p, upd->memtype);
+      if (m == NULL)
+        continue;
+      if ((strcasecmp(m->desc, "flash") == 0) && (upd->op == DEVICE_WRITE)) {
+        erase = 1;
+        if (quell_progress < 2) {
+          fprintf(stderr,
+                "%s: NOTE: FLASH memory has been specified, an erase cycle "
+                "will be performed\n"
+                "%sTo disable this feature, specify the -D option.\n",
+                progname, progbuf);
+        }
+        break;
+      }
+    }
+  }
+
+  /*
+   * Display cycle count, if and only if it is not set later on.
+   *
+   * The cycle count will be displayed anytime it will be changed later.
+   */
+  if (init_ok && !(p->flags & AVRPART_AVR32) && 
+      (set_cycles == -1) && ((erase == 0) || (do_cycles == 0))) {
+    /*
+     * see if the cycle count in the last four bytes of eeprom seems
+     * reasonable
+     */
+    rc = avr_get_cycle_count(pgm, p, &cycles);
+    if (quell_progress < 2) {
+      if ((rc >= 0) && (cycles != 0)) {
+        fprintf(stderr,
+              "%s: current erase-rewrite cycle count is %d%s\n",
+              progname, cycles,
+              do_cycles ? "" : " (if being tracked)");
+      }
+    }
+  }
+
+  if (init_ok && set_cycles != -1 && !(p->flags & AVRPART_AVR32)) {
+    rc = avr_get_cycle_count(pgm, p, &cycles);
+    if (rc == 0) {
+      /*
+       * only attempt to update the cycle counter if we can actually
+       * read the old value
+       */
+      cycles = set_cycles;
+      if (quell_progress < 2) {
+        fprintf(stderr, "%s: setting erase-rewrite cycle count to %d\n",
+              progname, cycles);
+      }
+      rc = avr_put_cycle_count(pgm, p, cycles);
+      if (rc < 0) {
+        fprintf(stderr,
+                "%s: WARNING: failed to update the erase-rewrite cycle "
+                "counter\n",
+                progname);
+      }
+    }
+  }
+
+  if (init_ok && erase) {
+    /*
+     * erase the chip's flash and eeprom memories, this is required
+     * before the chip can accept new programming
+     */
+    if (nowrite) {
+      fprintf(stderr,
+	      "%s: conflicting -e and -n options specified, NOT erasing chip\n",
+	      progname);
+    } else {
+      if (quell_progress < 2) {
+      	fprintf(stderr, "%s: erasing chip\n", progname);
+      }
+      exitrc = avr_chip_erase(pgm, p);
+      if(exitrc) goto main_exit;
+    }
+  }
+
+  if (terminal) {
+    /*
+     * terminal mode
+     */
+    exitrc = terminal_mode(pgm, p);
+  }
+
+  if (!init_ok) {
+    /*
+     * If we came here by the -tF options, bail out now.
+     */
+    exitrc = 1;
+    goto main_exit;
+  }
+
+
+  for (ln=lfirst(updates); ln; ln=lnext(ln)) {
+    upd = ldata(ln);
+    rc = do_op(pgm, p, upd, nowrite, verify);
+    if (rc) {
+      exitrc = 1;
+      break;
+    }
+  }
+
+  /* Right before we exit programming mode, which will make the fuse
+     bits active, check to make sure they are still correct */
+  if (safemode == 1) {
+    /* If safemode is enabled, go ahead and read the current low,
+     * high, and extended fuse bytes as needed */
+    unsigned char safemodeafter_lfuse = 0xff;
+    unsigned char safemodeafter_hfuse = 0xff;
+    unsigned char safemodeafter_efuse = 0xff;
+    unsigned char safemodeafter_fuse  = 0xff;
+    unsigned char failures = 0;
+    char yes[1] = {'y'};
+
+    if (quell_progress < 2) {
+      fprintf(stderr, "\n");
+    }
+
+    //Restore the default fuse values
+    safemode_memfuses(0, &safemode_lfuse, &safemode_hfuse, &safemode_efuse, &safemode_fuse);
+
+    /* Try reading back fuses, make sure they are reliable to read back */
+    if (safemode_readfuses(&safemodeafter_lfuse, &safemodeafter_hfuse,
+                           &safemodeafter_efuse, &safemodeafter_fuse, pgm, p, verbose) != 0) {
+      /* Uh-oh.. try once more to read back fuses */
+      if (safemode_readfuses(&safemodeafter_lfuse, &safemodeafter_hfuse,
+                             &safemodeafter_efuse, &safemodeafter_fuse, pgm, p, verbose) != 0) { 
+        fprintf(stderr,
+                "%s: safemode: Sorry, reading back fuses was unreliable. "
+                "I have given up and exited programming mode\n",
+                progname);
+        exitrc = 1;
+        goto main_exit;		  
+      }
+    }
+    
+    /* Now check what fuses are against what they should be */
+    if (safemodeafter_fuse != safemode_fuse) {
+      fuses_updated = 1;
+      fprintf(stderr, "%s: safemode: fuse changed! Was %x, and is now %x\n",
+              progname, safemode_fuse, safemodeafter_fuse);
+
+              
+      /* Ask user - should we change them */
+       
+       if (silentsafe == 0)
+            safemode_response = terminal_get_input("Would you like this fuse to be changed back? [y/n] ");
+       else
+            safemode_response = yes;
+       
+       if (tolower(safemode_response[0]) == 'y') {
+              
+            /* Enough chit-chat, time to program some fuses and check them */
+            if (safemode_writefuse (safemode_fuse, "fuse", pgm, p,
+                                    10, verbose) == 0) {
+                fprintf(stderr, "%s: safemode: and is now rescued\n", progname);
+            }
+            else {
+                fprintf(stderr, "%s: and COULD NOT be changed\n", progname);
+                failures++;
+            }
+      }
+    }
+
+    /* Now check what fuses are against what they should be */
+    if (safemodeafter_lfuse != safemode_lfuse) {
+      fuses_updated = 1;
+      fprintf(stderr, "%s: safemode: lfuse changed! Was %x, and is now %x\n",
+              progname, safemode_lfuse, safemodeafter_lfuse);
+
+              
+      /* Ask user - should we change them */
+       
+       if (silentsafe == 0)
+            safemode_response = terminal_get_input("Would you like this fuse to be changed back? [y/n] ");
+       else
+            safemode_response = yes;
+       
+       if (tolower(safemode_response[0]) == 'y') {
+              
+            /* Enough chit-chat, time to program some fuses and check them */
+            if (safemode_writefuse (safemode_lfuse, "lfuse", pgm, p,
+                                    10, verbose) == 0) {
+                fprintf(stderr, "%s: safemode: and is now rescued\n", progname);
+            }
+            else {
+                fprintf(stderr, "%s: and COULD NOT be changed\n", progname);
+                failures++;
+            }
+      }
+    }
+
+    /* Now check what fuses are against what they should be */
+    if (safemodeafter_hfuse != safemode_hfuse) {
+      fuses_updated = 1;
+      fprintf(stderr, "%s: safemode: hfuse changed! Was %x, and is now %x\n",
+              progname, safemode_hfuse, safemodeafter_hfuse);
+              
+      /* Ask user - should we change them */
+       if (silentsafe == 0)
+            safemode_response = terminal_get_input("Would you like this fuse to be changed back? [y/n] ");
+       else
+            safemode_response = yes;
+       if (tolower(safemode_response[0]) == 'y') {
+
+            /* Enough chit-chat, time to program some fuses and check them */
+            if (safemode_writefuse(safemode_hfuse, "hfuse", pgm, p,
+                                    10, verbose) == 0) {
+                fprintf(stderr, "%s: safemode: and is now rescued\n", progname);
+            }
+            else {
+                fprintf(stderr, "%s: and COULD NOT be changed\n", progname);
+                failures++;
+            }
+      }
+    }
+
+    /* Now check what fuses are against what they should be */
+    if (safemodeafter_efuse != safemode_efuse) {
+      fuses_updated = 1;
+      fprintf(stderr, "%s: safemode: efuse changed! Was %x, and is now %x\n",
+              progname, safemode_efuse, safemodeafter_efuse);
+
+      /* Ask user - should we change them */
+       if (silentsafe == 0)
+            safemode_response = terminal_get_input("Would you like this fuse to be changed back? [y/n] ");
+       else
+            safemode_response = yes;
+       if (tolower(safemode_response[0]) == 'y') {
+              
+            /* Enough chit-chat, time to program some fuses and check them */
+            if (safemode_writefuse (safemode_efuse, "efuse", pgm, p,
+                                    10, verbose) == 0) {
+                fprintf(stderr, "%s: safemode: and is now rescued\n", progname);
+            }
+            else {
+                fprintf(stderr, "%s: and COULD NOT be changed\n", progname);
+                failures++;
+            }
+       }
+    }
+
+    if (quell_progress < 2) {
+      fprintf(stderr, "%s: safemode: ", progname);
+      if (failures == 0) {
+        fprintf(stderr, "Fuses OK\n");
+      }
+      else {
+        fprintf(stderr, "Fuses not recovered, sorry\n");
+      }
+    }
+
+    if (fuses_updated && fuses_specified) {
+      exitrc = 1;
+    }
+
+  }
+
+
+main_exit:
+
+  /*
+   * program complete
+   */
+
+  if (is_open) {
+    pgm->powerdown(pgm);
+
+    pgm->disable(pgm);
+
+    pgm->rdy_led(pgm, OFF);
+  }
+
+  pgm->close(pgm);
+
+  if (quell_progress < 2) {
+    fprintf(stderr, "\n%s done.  Thank you.\n\n", progname);
+  }
+
+  return exitrc;
+}
diff --git a/avrdude/my_ddk_hidsdi.h b/avrdude/my_ddk_hidsdi.h
new file mode 100644
index 00000000..99859d06
--- /dev/null
+++ b/avrdude/my_ddk_hidsdi.h
@@ -0,0 +1,49 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2006 Christian Starkjohann
+ *
+ * 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
+ */
+
+/* $Id$ */
+
+/*
+The following is a replacement for hidsdi.h from the Windows DDK. It defines some
+of the types and function prototypes of this header for our project. If you
+have the Windows DDK version of this file or a version shipped with MinGW, use
+that instead.
+*/
+#ifndef MY_DDK_HIDSDI_H
+#define MY_DDK_HIDSDI_H
+#include <pshpack4.h>
+#include <ddk/hidusage.h>
+#include <ddk/hidpi.h>
+typedef struct{
+    ULONG   Size;
+    USHORT  VendorID;
+    USHORT  ProductID;
+    USHORT  VersionNumber;
+}HIDD_ATTRIBUTES;
+void __stdcall      HidD_GetHidGuid(OUT LPGUID hidGuid);
+BOOLEAN __stdcall   HidD_GetAttributes(IN HANDLE device, OUT HIDD_ATTRIBUTES *attributes);
+BOOLEAN __stdcall   HidD_GetManufacturerString(IN HANDLE device, OUT void *buffer, IN ULONG bufferLen);
+BOOLEAN __stdcall   HidD_GetProductString(IN HANDLE device, OUT void *buffer, IN ULONG bufferLen);
+BOOLEAN __stdcall   HidD_GetSerialNumberString(IN HANDLE device, OUT void *buffer, IN ULONG bufferLen);
+BOOLEAN __stdcall   HidD_GetFeature(IN HANDLE device, OUT void *reportBuffer, IN ULONG bufferLen);
+BOOLEAN __stdcall   HidD_SetFeature(IN HANDLE device, IN void *reportBuffer, IN ULONG bufferLen);
+BOOLEAN __stdcall   HidD_GetNumInputBuffers(IN HANDLE device, OUT ULONG *numBuffers);
+BOOLEAN __stdcall   HidD_SetNumInputBuffers(IN HANDLE device, OUT ULONG numBuffers);
+#include <poppack.h>
+#endif /* MY_DDK_HIDSDI_H */
diff --git a/avrdude/par.c b/avrdude/par.c
new file mode 100644
index 00000000..6b8bca46
--- /dev/null
+++ b/avrdude/par.c
@@ -0,0 +1,439 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2000-2006  Brian S. Dean <bsd@bsdhome.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id$ */
+
+#include "ac_cfg.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#if defined(__FreeBSD__)
+# include "freebsd_ppi.h"
+#elif defined(__linux__)
+# include "linux_ppdev.h"
+#elif defined(__sun__) || defined(__sun) /* Solaris */
+# include "solaris_ecpp.h"
+#endif
+
+#include "avrdude.h"
+#include "avr.h"
+#include "pindefs.h"
+#include "pgm.h"
+#include "ppi.h"
+#include "bitbang.h"
+
+#if HAVE_PARPORT
+
+struct ppipins_t {
+  int pin;
+  int reg;
+  int bit;
+  int inverted;
+};
+
+static struct ppipins_t ppipins[] = {
+  {  1, PPICTRL,   0x01, 1 },
+  {  2, PPIDATA,   0x01, 0 },
+  {  3, PPIDATA,   0x02, 0 },
+  {  4, PPIDATA,   0x04, 0 },
+  {  5, PPIDATA,   0x08, 0 },
+  {  6, PPIDATA,   0x10, 0 },
+  {  7, PPIDATA,   0x20, 0 },
+  {  8, PPIDATA,   0x40, 0 },
+  {  9, PPIDATA,   0x80, 0 },
+  { 10, PPISTATUS, 0x40, 0 },
+  { 11, PPISTATUS, 0x80, 1 },
+  { 12, PPISTATUS, 0x20, 0 },
+  { 13, PPISTATUS, 0x10, 0 },
+  { 14, PPICTRL,   0x02, 1 }, 
+  { 15, PPISTATUS, 0x08, 0 },
+  { 16, PPICTRL,   0x04, 0 }, 
+  { 17, PPICTRL,   0x08, 1 }
+};
+
+#define NPINS (sizeof(ppipins)/sizeof(struct ppipins_t))
+
+static int par_setpin(PROGRAMMER * pgm, int pin, int value)
+{
+  int inverted;
+
+  inverted = pin & PIN_INVERSE;
+  pin &= PIN_MASK;
+
+  if (pin < 1 || pin > 17)
+    return -1;
+
+  pin--;
+
+  if (ppipins[pin].inverted)
+    inverted = !inverted;
+
+  if (inverted)
+    value = !value;
+
+  if (value)
+    ppi_set(&pgm->fd, ppipins[pin].reg, ppipins[pin].bit);
+  else
+    ppi_clr(&pgm->fd, ppipins[pin].reg, ppipins[pin].bit);
+
+  if (pgm->ispdelay > 1)
+    bitbang_delay(pgm->ispdelay);
+
+  return 0;
+}
+
+static void par_setmany(PROGRAMMER * pgm, unsigned int pinset, int value)
+{
+  int pin;
+
+  for (pin = 1; pin <= 17; pin++) {
+    if (pinset & (1 << pin))
+      par_setpin(pgm, pin, value);
+  }
+}
+
+static int par_getpin(PROGRAMMER * pgm, int pin)
+{
+  int value;
+  int inverted;
+
+  inverted = pin & PIN_INVERSE;
+  pin &= PIN_MASK;
+
+  if (pin < 1 || pin > 17)
+    return -1;
+
+  pin--;
+
+  value = ppi_get(&pgm->fd, ppipins[pin].reg, ppipins[pin].bit);
+
+  if (value)
+    value = 1;
+    
+  if (ppipins[pin].inverted)
+    inverted = !inverted;
+
+  if (inverted)
+    value = !value;
+
+  return value;
+}
+
+
+static int par_highpulsepin(PROGRAMMER * pgm, int pin)
+{
+  int inverted;
+
+  inverted = pin & PIN_INVERSE;
+  pin &= PIN_MASK;
+
+  if (pin < 1 || pin > 17)
+    return -1;
+
+  pin--;
+
+  if (ppipins[pin].inverted)
+    inverted = !inverted;
+
+  if (inverted) {
+    ppi_clr(&pgm->fd, ppipins[pin].reg, ppipins[pin].bit);
+    if (pgm->ispdelay > 1)
+      bitbang_delay(pgm->ispdelay);
+
+    ppi_set(&pgm->fd, ppipins[pin].reg, ppipins[pin].bit);
+    if (pgm->ispdelay > 1)
+      bitbang_delay(pgm->ispdelay);
+  } else {
+    ppi_set(&pgm->fd, ppipins[pin].reg, ppipins[pin].bit);
+    if (pgm->ispdelay > 1)
+      bitbang_delay(pgm->ispdelay);
+
+    ppi_clr(&pgm->fd, ppipins[pin].reg, ppipins[pin].bit);
+    if (pgm->ispdelay > 1)
+      bitbang_delay(pgm->ispdelay);
+  }
+
+  return 0;
+}
+
+static char * pins_to_str(unsigned int pmask)
+{
+  static char buf[64];
+  int pin;
+  char b2[8];
+
+  buf[0] = 0;
+  for (pin = 1; pin <= 17; pin++) {
+    if (pmask & (1 << pin)) {
+      sprintf(b2, "%d", pin);
+      if (buf[0] != 0)
+        strcat(buf, ",");
+      strcat(buf, b2);
+    }
+  }
+
+  return buf;
+}
+
+/*
+ * apply power to the AVR processor
+ */
+static void par_powerup(PROGRAMMER * pgm)
+{
+  par_setmany(pgm, pgm->pinno[PPI_AVR_VCC], 1);	/* power up */
+  usleep(100000);
+}
+
+
+/*
+ * remove power from the AVR processor
+ */
+static void par_powerdown(PROGRAMMER * pgm)
+{
+  par_setmany(pgm, pgm->pinno[PPI_AVR_VCC], 0);	/* power down */
+}
+
+static void par_disable(PROGRAMMER * pgm)
+{
+  par_setmany(pgm, pgm->pinno[PPI_AVR_BUFF], 1); /* turn off */
+}
+
+static void par_enable(PROGRAMMER * pgm)
+{
+  /*
+   * Prepare to start talking to the connected device - pull reset low
+   * first, delay a few milliseconds, then enable the buffer.  This
+   * sequence allows the AVR to be reset before the buffer is enabled
+   * to avoid a short period of time where the AVR may be driving the
+   * programming lines at the same time the programmer tries to.  Of
+   * course, if a buffer is being used, then the /RESET line from the
+   * programmer needs to be directly connected to the AVR /RESET line
+   * and not via the buffer chip.
+   */
+
+  par_setpin(pgm, pgm->pinno[PIN_AVR_RESET], 0);
+  usleep(1);
+
+  /*
+   * enable the 74367 buffer, if connected; this signal is active low
+   */
+  par_setmany(pgm, pgm->pinno[PPI_AVR_BUFF], 0);
+}
+
+static int par_open(PROGRAMMER * pgm, char * port)
+{
+  int rc;
+
+  bitbang_check_prerequisites(pgm);
+
+  ppi_open(port, &pgm->fd);
+  if (pgm->fd.ifd < 0) {
+    fprintf(stderr, "%s: failed to open parallel port \"%s\"\n\n",
+            progname, port);
+    exit(1);
+  }
+
+  /*
+   * save pin values, so they can be restored when device is closed
+   */
+  rc = ppi_getall(&pgm->fd, PPIDATA);
+  if (rc < 0) {
+    fprintf(stderr, "%s: error reading status of ppi data port\n", progname);
+    return -1;
+  }
+  pgm->ppidata = rc;
+
+  rc = ppi_getall(&pgm->fd, PPICTRL);
+  if (rc < 0) {
+    fprintf(stderr, "%s: error reading status of ppi ctrl port\n", progname);
+    return -1;
+  }
+  pgm->ppictrl = rc;
+
+  return 0;
+}
+
+
+static void par_close(PROGRAMMER * pgm)
+{
+
+  /*
+   * Restore pin values before closing,
+   * but ensure that buffers are turned off.
+   */
+  ppi_setall(&pgm->fd, PPIDATA, pgm->ppidata);
+  ppi_setall(&pgm->fd, PPICTRL, pgm->ppictrl);
+
+  par_setmany(pgm, pgm->pinno[PPI_AVR_BUFF], 1);
+
+  /*
+   * Handle exit specs.
+   */
+  switch (pgm->exit_reset) {
+  case EXIT_RESET_ENABLED:
+    par_setpin(pgm, pgm->pinno[PIN_AVR_RESET], 0);
+    break;
+
+  case EXIT_RESET_DISABLED:
+    par_setpin(pgm, pgm->pinno[PIN_AVR_RESET], 1);
+    break;
+
+  case EXIT_RESET_UNSPEC:
+    /* Leave it alone. */
+    break;
+  }
+  switch (pgm->exit_vcc) {
+  case EXIT_VCC_ENABLED:
+    par_setmany(pgm, pgm->pinno[PPI_AVR_VCC], 1);
+    break;
+
+  case EXIT_VCC_DISABLED:
+    par_setmany(pgm, pgm->pinno[PPI_AVR_VCC], 0);
+    break;
+
+  case EXIT_VCC_UNSPEC:
+    /* Leave it alone. */
+    break;
+  }
+
+  ppi_close(&pgm->fd);
+  pgm->fd.ifd = -1;
+}
+
+static void par_display(PROGRAMMER * pgm, const char * p)
+{
+  char vccpins[64];
+  char buffpins[64];
+
+  if (pgm->pinno[PPI_AVR_VCC]) {
+    snprintf(vccpins, sizeof(vccpins), "%s",
+             pins_to_str(pgm->pinno[PPI_AVR_VCC]));
+  }
+  else {
+    strcpy(vccpins, " (not used)");
+  }
+
+  if (pgm->pinno[PPI_AVR_BUFF]) {
+    snprintf(buffpins, sizeof(buffpins), "%s",
+             pins_to_str(pgm->pinno[PPI_AVR_BUFF]));
+  }
+  else {
+    strcpy(buffpins, " (not used)");
+  }
+
+  fprintf(stderr, 
+          "%s  VCC     = %s\n"
+          "%s  BUFF    = %s\n"
+          "%s  RESET   = %d\n"
+          "%s  SCK     = %d\n"
+          "%s  MOSI    = %d\n"
+          "%s  MISO    = %d\n"
+          "%s  ERR LED = %d\n"
+          "%s  RDY LED = %d\n"
+          "%s  PGM LED = %d\n"
+          "%s  VFY LED = %d\n",
+
+          p, vccpins,
+          p, buffpins,
+          p, pgm->pinno[PIN_AVR_RESET],
+          p, pgm->pinno[PIN_AVR_SCK],
+          p, pgm->pinno[PIN_AVR_MOSI],
+          p, pgm->pinno[PIN_AVR_MISO],
+          p, pgm->pinno[PIN_LED_ERR],
+          p, pgm->pinno[PIN_LED_RDY],
+          p, pgm->pinno[PIN_LED_PGM],
+          p, pgm->pinno[PIN_LED_VFY]);
+}
+
+
+/*
+ * parse the -E string
+ */
+static int par_parseexitspecs(PROGRAMMER * pgm, char *s)
+{
+  char *cp;
+
+  while ((cp = strtok(s, ","))) {
+    if (strcmp(cp, "reset") == 0) {
+      pgm->exit_reset = EXIT_RESET_ENABLED;
+    }
+    else if (strcmp(cp, "noreset") == 0) {
+      pgm->exit_reset = EXIT_RESET_DISABLED;
+    }
+    else if (strcmp(cp, "vcc") == 0) {
+      pgm->exit_vcc = EXIT_VCC_ENABLED;
+    }
+    else if (strcmp(cp, "novcc") == 0) {
+      pgm->exit_vcc = EXIT_VCC_DISABLED;
+    }
+    else {
+      return -1;
+    }
+    s = 0; /* strtok() should be called with the actual string only once */
+  }
+
+  return 0;
+}
+
+void par_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "PPI");
+
+  pgm->exit_vcc = EXIT_VCC_UNSPEC;
+  pgm->exit_reset = EXIT_RESET_UNSPEC;
+
+  pgm->rdy_led        = bitbang_rdy_led;
+  pgm->err_led        = bitbang_err_led;
+  pgm->pgm_led        = bitbang_pgm_led;
+  pgm->vfy_led        = bitbang_vfy_led;
+  pgm->initialize     = bitbang_initialize;
+  pgm->display        = par_display;
+  pgm->enable         = par_enable;
+  pgm->disable        = par_disable;
+  pgm->powerup        = par_powerup;
+  pgm->powerdown      = par_powerdown;
+  pgm->program_enable = bitbang_program_enable;
+  pgm->chip_erase     = bitbang_chip_erase;
+  pgm->cmd            = bitbang_cmd;
+  pgm->spi            = bitbang_spi;
+  pgm->open           = par_open;
+  pgm->close          = par_close;
+  pgm->setpin         = par_setpin;
+  pgm->getpin         = par_getpin;
+  pgm->highpulsepin   = par_highpulsepin;
+  pgm->parseexitspecs = par_parseexitspecs;
+  pgm->read_byte      = avr_read_byte_default;
+  pgm->write_byte     = avr_write_byte_default;
+}
+
+#else  /* !HAVE_PARPORT */
+
+void par_initpgm(PROGRAMMER * pgm)
+{
+  fprintf(stderr,
+	  "%s: parallel port access not available in this configuration\n",
+	  progname);
+}
+
+#endif /* HAVE_PARPORT */
diff --git a/avrdude/par.h b/avrdude/par.h
new file mode 100644
index 00000000..7d9b2416
--- /dev/null
+++ b/avrdude/par.h
@@ -0,0 +1,35 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2000-2004  Brian S. Dean <bsd@bsdhome.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id$ */
+
+#ifndef par_h
+#define par_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void par_initpgm        (PROGRAMMER * pgm);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/avrdude/pgm.c b/avrdude/pgm.c
new file mode 100644
index 00000000..07fa34cf
--- /dev/null
+++ b/avrdude/pgm.c
@@ -0,0 +1,227 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2002-2004  Brian S. Dean <bsd@bsdhome.com>
+ * Copyright 2007 Joerg Wunsch <j@uriah.heep.sax.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 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
+ */
+
+/* $Id$ */
+
+#include "ac_cfg.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "avrdude.h"
+#include "pgm.h"
+
+static int  pgm_default_2 (struct programmer_t *, AVRPART *);
+static int  pgm_default_3 (struct programmer_t * pgm, AVRPART * p, AVRMEM * mem,
+			   unsigned long addr, unsigned char * value);
+static void pgm_default_4 (struct programmer_t *);
+static int  pgm_default_5 (struct programmer_t * pgm, AVRPART * p, AVRMEM * mem,
+			   unsigned long addr, unsigned char data);
+static void pgm_default_6 (struct programmer_t *, const char *);
+
+
+static int pgm_default_open (struct programmer_t *pgm, char * name)
+{
+  fprintf (stderr, "\n%s: Fatal error: Programmer does not support open()",
+               progname);
+  exit(1);
+}
+
+static int  pgm_default_led (struct programmer_t * pgm, int value)
+{
+  /*
+   * If programmer has no LEDs, just do nothing.
+   */
+  return 0;
+}
+
+
+static void pgm_default_powerup_powerdown (struct programmer_t * pgm)
+{
+  /*
+   * If programmer does not support powerup/down, just do nothing.
+   */
+}
+
+
+PROGRAMMER * pgm_new(void)
+{
+  int i;
+  PROGRAMMER * pgm;
+
+  pgm = (PROGRAMMER *)malloc(sizeof(*pgm));
+  if (pgm == NULL) {
+    fprintf(stderr, "%s: out of memory allocating programmer structure\n",
+            progname);
+    exit(1);
+  }
+
+  memset(pgm, 0, sizeof(*pgm));
+
+  pgm->id = lcreat(NULL, 0);
+  pgm->desc[0] = 0;
+  pgm->type[0] = 0;
+  pgm->config_file[0] = 0;
+  pgm->lineno = 0;
+  pgm->baudrate = 0;
+
+  for (i=0; i<N_PINS; i++)
+    pgm->pinno[i] = 0;
+
+  /*
+   * mandatory functions - these are called without checking to see
+   * whether they are assigned or not
+   */
+  pgm->initialize     = pgm_default_2;
+  pgm->display        = pgm_default_6;
+  pgm->enable         = pgm_default_4;
+  pgm->disable        = pgm_default_4;
+  pgm->powerup        = pgm_default_powerup_powerdown;
+  pgm->powerdown      = pgm_default_powerup_powerdown;
+  pgm->program_enable = pgm_default_2;
+  pgm->chip_erase     = pgm_default_2;
+  pgm->open           = pgm_default_open;
+  pgm->close          = pgm_default_4;
+  pgm->read_byte      = pgm_default_3;
+  pgm->write_byte     = pgm_default_5;
+
+  /*
+   * predefined functions - these functions have a valid default
+   * implementation. Hence, they don't need to be defined in
+   * the programmer.
+   */
+  pgm->rdy_led        = pgm_default_led;
+  pgm->err_led        = pgm_default_led;
+  pgm->pgm_led        = pgm_default_led;
+  pgm->vfy_led        = pgm_default_led;
+
+  /*
+   * optional functions - these are checked to make sure they are
+   * assigned before they are called
+   */
+  pgm->cmd            = NULL;
+  pgm->spi            = NULL;
+  pgm->paged_write    = NULL;
+  pgm->paged_load     = NULL;
+  pgm->write_setup    = NULL;
+  pgm->read_sig_bytes = NULL;
+  pgm->set_vtarget    = NULL;
+  pgm->set_varef      = NULL;
+  pgm->set_fosc       = NULL;
+  pgm->perform_osccal = NULL;
+  pgm->parseextparams = NULL;
+  pgm->setup          = NULL;
+  pgm->teardown       = NULL;
+
+  return pgm;
+}
+
+
+static void pgm_default(void)
+{
+  fprintf(stderr, "%s: programmer operation not supported\n", progname);
+}
+
+
+static int  pgm_default_2 (struct programmer_t * pgm, AVRPART * p)
+{
+  pgm_default();
+  return -1;
+}
+
+static int  pgm_default_3 (struct programmer_t * pgm, AVRPART * p, AVRMEM * mem,
+			   unsigned long addr, unsigned char * value)
+{
+  pgm_default();
+  return -1;
+}
+
+static void pgm_default_4 (struct programmer_t * pgm)
+{
+  pgm_default();
+}
+
+static int  pgm_default_5 (struct programmer_t * pgm, AVRPART * p, AVRMEM * mem,
+			   unsigned long addr, unsigned char data)
+{
+  pgm_default();
+  return -1;
+}
+
+static void pgm_default_6 (struct programmer_t * pgm, const char * p)
+{
+  pgm_default();
+}
+
+
+void programmer_display(PROGRAMMER * pgm, const char * p)
+{
+  fprintf(stderr, "%sProgrammer Type : %s\n", p, pgm->type);
+  fprintf(stderr, "%sDescription     : %s\n", p, pgm->desc);
+
+  pgm->display(pgm, p);
+}
+
+PROGRAMMER * locate_programmer(LISTID programmers, const char * configid)
+{
+  LNODEID ln1, ln2;
+  PROGRAMMER * p = NULL;
+  const char * id;
+  int found;
+
+  found = 0;
+
+  for (ln1=lfirst(programmers); ln1 && !found; ln1=lnext(ln1)) {
+    p = ldata(ln1);
+    for (ln2=lfirst(p->id); ln2 && !found; ln2=lnext(ln2)) {
+      id = ldata(ln2);
+      if (strcasecmp(configid, id) == 0)
+        found = 1;
+    }
+  }
+
+  if (found)
+    return p;
+
+  return NULL;
+}
+
+/*
+ * Iterate over the list of programmers given as "programmers", and
+ * call the callback function cb for each entry found.  cb is being
+ * passed the following arguments:
+ * . the name of the programmer (for -c)
+ * . the descriptive text given in the config file
+ * . the name of the config file this programmer has been defined in
+ * . the line number of the config file this programmer has been defined at
+ * . the "cookie" passed into walk_programmers() (opaque client data)
+ */
+void walk_programmers(LISTID programmers, walk_programmers_cb cb, void *cookie)
+{
+  LNODEID ln1;
+  PROGRAMMER * p;
+
+  for (ln1 = lfirst(programmers); ln1; ln1 = lnext(ln1)) {
+    p = ldata(ln1);
+    cb((char *)ldata(lfirst(p->id)), p->desc, p->config_file, p->lineno, cookie);
+  }
+}
+
diff --git a/avrdude/pgm.h b/avrdude/pgm.h
new file mode 100644
index 00000000..2bd125be
--- /dev/null
+++ b/avrdude/pgm.h
@@ -0,0 +1,132 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2002-2004  Brian S. Dean <bsd@bsdhome.com>
+ * Copyright 2007 Joerg Wunsch <j@uriah.heep.sax.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 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
+ */
+
+/* $Id$ */
+
+#ifndef pgm_h
+#define pgm_h
+
+#include <limits.h>
+
+#include "avrpart.h"
+#include "lists.h"
+#include "pindefs.h"
+#include "serial.h"
+
+#define ON  1
+#define OFF 0
+
+#define PGM_DESCLEN 80
+#define PGM_PORTLEN PATH_MAX
+#define PGM_TYPELEN 32
+
+typedef enum {
+  EXIT_VCC_UNSPEC,
+  EXIT_VCC_ENABLED,
+  EXIT_VCC_DISABLED
+} exit_vcc_t;
+
+typedef enum {
+  EXIT_RESET_UNSPEC,
+  EXIT_RESET_ENABLED,
+  EXIT_RESET_DISABLED
+} exit_reset_t;
+
+typedef struct programmer_t {
+  LISTID id;
+  char desc[PGM_DESCLEN];
+  char type[PGM_TYPELEN];
+  char port[PGM_PORTLEN];
+  unsigned int pinno[N_PINS];
+  exit_vcc_t exit_vcc;
+  exit_reset_t exit_reset;
+  int ppidata;
+  int ppictrl;
+  int baudrate;
+  double bitclock;    /* JTAG ICE clock period in microseconds */
+  int ispdelay;    /* ISP clock delay */
+  union filedescriptor fd;
+  int  page_size;  /* page size if the programmer supports paged write/load */
+  int  (*rdy_led)        (struct programmer_t * pgm, int value);
+  int  (*err_led)        (struct programmer_t * pgm, int value);
+  int  (*pgm_led)        (struct programmer_t * pgm, int value);
+  int  (*vfy_led)        (struct programmer_t * pgm, int value);
+  int  (*initialize)     (struct programmer_t * pgm, AVRPART * p);
+  void (*display)        (struct programmer_t * pgm, const char * p);
+  void (*enable)         (struct programmer_t * pgm);
+  void (*disable)        (struct programmer_t * pgm);
+  void (*powerup)        (struct programmer_t * pgm);
+  void (*powerdown)      (struct programmer_t * pgm);
+  int  (*program_enable) (struct programmer_t * pgm, AVRPART * p);
+  int  (*chip_erase)     (struct programmer_t * pgm, AVRPART * p);
+  int  (*cmd)            (struct programmer_t * pgm, unsigned char cmd[4], 
+                          unsigned char res[4]);
+  int  (*spi)            (struct programmer_t * pgm, unsigned char cmd[], 
+                          unsigned char res[], int count);
+  int  (*open)           (struct programmer_t * pgm, char * port);
+  void (*close)          (struct programmer_t * pgm);
+  int  (*paged_write)    (struct programmer_t * pgm, AVRPART * p, AVRMEM * m, 
+                          int page_size, int n_bytes);
+  int  (*paged_load)     (struct programmer_t * pgm, AVRPART * p, AVRMEM * m,
+                          int page_size, int n_bytes);
+  void (*write_setup)    (struct programmer_t * pgm, AVRPART * p, AVRMEM * m);
+  int  (*write_byte)     (struct programmer_t * pgm, AVRPART * p, AVRMEM * m,
+                          unsigned long addr, unsigned char value);
+  int  (*read_byte)      (struct programmer_t * pgm, AVRPART * p, AVRMEM * m,
+                          unsigned long addr, unsigned char * value);
+  int  (*read_sig_bytes) (struct programmer_t * pgm, AVRPART * p, AVRMEM * m);
+  void (*print_parms)    (struct programmer_t * pgm);
+  int  (*set_vtarget)    (struct programmer_t * pgm, double v);
+  int  (*set_varef)      (struct programmer_t * pgm, unsigned int chan, double v);
+  int  (*set_fosc)       (struct programmer_t * pgm, double v);
+  int  (*set_sck_period) (struct programmer_t * pgm, double v);
+  int  (*setpin)         (struct programmer_t * pgm, int pin, int value);
+  int  (*getpin)         (struct programmer_t * pgm, int pin);
+  int  (*highpulsepin)   (struct programmer_t * pgm, int pin);
+  int  (*parseexitspecs) (struct programmer_t * pgm, char *s);
+  int  (*perform_osccal) (struct programmer_t * pgm);
+  int  (*parseextparams) (struct programmer_t * pgm, LISTID xparams);
+  void (*setup)          (struct programmer_t * pgm);
+  void (*teardown)       (struct programmer_t * pgm);
+  char config_file[PATH_MAX]; /* config file where defined */
+  int  lineno;                /* config file line number */
+  void *cookie;		      /* for private use by the programmer */
+  char flag;		      /* for private use of the programmer */
+} PROGRAMMER;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+PROGRAMMER * pgm_new(void);
+
+void programmer_display(PROGRAMMER * pgm, const char * p);
+PROGRAMMER * locate_programmer(LISTID programmers, const char * configid);
+
+typedef void (*walk_programmers_cb)(const char *name, const char *desc,
+                                    const char *cfgname, int cfglineno,
+                                    void *cookie);
+void walk_programmers(LISTID programmers, walk_programmers_cb cb, void *cookie);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/avrdude/pindefs.h b/avrdude/pindefs.h
new file mode 100644
index 00000000..9c16ed1c
--- /dev/null
+++ b/avrdude/pindefs.h
@@ -0,0 +1,44 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2000-2004  Brian S. Dean <bsd@bsdhome.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id$ */
+
+#ifndef __pindefs_h__
+#define __pindefs_h__
+
+enum {
+  PPI_AVR_VCC=1,
+  PPI_AVR_BUFF,
+  PIN_AVR_RESET,
+  PIN_AVR_SCK,
+  PIN_AVR_MOSI,
+  PIN_AVR_MISO,
+  PIN_LED_ERR,
+  PIN_LED_RDY,
+  PIN_LED_PGM,
+  PIN_LED_VFY,
+  N_PINS
+};
+#define PIN_INVERSE 0x80	/* flag for inverted pin in serbb */
+#define PIN_MASK    0x7f
+
+#define LED_ON(fd,pin)  ppi_setpin(fd,pin,0)
+#define LED_OFF(fd,pin) ppi_setpin(fd,pin,1)
+
+#endif
diff --git a/avrdude/ppi.c b/avrdude/ppi.c
new file mode 100644
index 00000000..4397d000
--- /dev/null
+++ b/avrdude/ppi.c
@@ -0,0 +1,238 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2000-2004  Brian S. Dean <bsd@bsdhome.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id$ */
+
+
+#if !defined(WIN32NATIVE)
+
+#include "ac_cfg.h"
+
+#if HAVE_PARPORT
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#if defined(__FreeBSD__)
+# include "freebsd_ppi.h"
+#elif defined(__linux__)
+# include "linux_ppdev.h"
+#elif defined(__sun__) || defined(__sun) /* Solaris */
+# include "solaris_ecpp.h"
+#endif
+
+#include "avrdude.h"
+#include "avr.h"
+#include "pindefs.h"
+#include "pgm.h"
+#include "ppi.h"
+
+enum {
+  PPI_READ,
+  PPI_WRITE,
+  PPI_SHADOWREAD
+};
+
+static int ppi_shadow_access(union filedescriptor *fdp, int reg,
+			     unsigned char *v, unsigned char action)
+{
+  static unsigned char shadow[3];
+  int shadow_num;
+
+  switch (reg) {
+    case PPIDATA:
+      shadow_num = 0;
+      break;
+    case PPICTRL:
+      shadow_num = 1;
+      break;
+    case PPISTATUS:
+      shadow_num = 2;
+      break;
+    default:
+      fprintf(stderr, "%s: avr_set(): invalid register=%d\n",
+              progname, reg);
+      return -1;
+      break;
+  }
+
+  switch (action) {
+    case PPI_SHADOWREAD:
+      *v = shadow[shadow_num];
+      break;
+    case PPI_READ:
+      DO_PPI_READ(fdp->ifd, reg, v);
+      shadow[shadow_num]=*v;
+      break;
+    case PPI_WRITE:
+      shadow[shadow_num]=*v;
+      DO_PPI_WRITE(fdp->ifd, reg, v);
+      break;
+  }
+  return 0;
+}
+
+/*
+ * set the indicated bit of the specified register.
+ */
+int ppi_set(union filedescriptor *fdp, int reg, int bit)
+{
+  unsigned char v;
+  int rc;
+
+  rc = ppi_shadow_access(fdp, reg, &v, PPI_SHADOWREAD);
+  v |= bit;
+  rc |= ppi_shadow_access(fdp, reg, &v, PPI_WRITE);
+
+  if (rc)
+    return -1;
+
+  return 0;
+}
+
+
+/*
+ * clear the indicated bit of the specified register.
+ */
+int ppi_clr(union filedescriptor *fdp, int reg, int bit)
+{
+  unsigned char v;
+  int rc;
+
+  rc = ppi_shadow_access(fdp, reg, &v, PPI_SHADOWREAD);
+  v &= ~bit;
+  rc |= ppi_shadow_access(fdp, reg, &v, PPI_WRITE);
+
+  if (rc)
+    return -1;
+
+  return 0;
+}
+
+
+/*
+ * get the indicated bit of the specified register.
+ */
+int ppi_get(union filedescriptor *fdp, int reg, int bit)
+{
+  unsigned char v;
+  int rc;
+
+  rc = ppi_shadow_access(fdp, reg, &v, PPI_READ);
+  v &= bit;
+
+  if (rc)
+    return -1;
+
+  return v; /* v == bit */
+}
+
+/*
+ * toggle the indicated bit of the specified register.
+ */
+int ppi_toggle(union filedescriptor *fdp, int reg, int bit)
+{
+  unsigned char v;
+  int rc;
+
+  rc = ppi_shadow_access(fdp, reg, &v, PPI_SHADOWREAD);
+  v ^= bit;
+  rc |= ppi_shadow_access(fdp, reg, &v, PPI_WRITE);
+
+  if (rc)
+    return -1;
+
+  return 0;
+}
+
+
+/*
+ * get all bits of the specified register.
+ */
+int ppi_getall(union filedescriptor *fdp, int reg)
+{
+  unsigned char v;
+  int rc;
+
+  rc = ppi_shadow_access(fdp, reg, &v, PPI_READ);
+
+  if (rc)
+    return -1;
+
+  return v; /* v == bit */
+}
+
+/*
+ * set all bits of the specified register to val.
+ */
+int ppi_setall(union filedescriptor *fdp, int reg, int val)
+{
+  unsigned char v;
+  int rc;
+
+  v = val;
+  rc = ppi_shadow_access(fdp, reg, &v, PPI_WRITE);
+
+  if (rc)
+    return -1;
+
+  return 0;
+}
+
+
+void ppi_open(char * port, union filedescriptor *fdp)
+{
+  int fd;
+  unsigned char v;
+
+  fd = open(port, O_RDWR);
+  if (fd < 0) {
+    fprintf(stderr, "%s: can't open device \"%s\": %s\n",
+              progname, port, strerror(errno));
+    fdp->ifd = -1;
+    return;
+  }
+
+  ppi_claim (fd);
+
+  /*
+   * Initialize shadow registers
+   */
+
+  ppi_shadow_access (fdp, PPIDATA, &v, PPI_READ);
+  ppi_shadow_access (fdp, PPICTRL, &v, PPI_READ);
+  ppi_shadow_access (fdp, PPISTATUS, &v, PPI_READ);
+
+  fdp->ifd = fd;
+}
+
+
+void ppi_close(union filedescriptor *fdp)
+{
+  ppi_release (fdp->ifd);
+  close(fdp->ifd);
+}
+
+#endif /* HAVE_PARPORT */
+
+#endif /* !WIN32NATIVE */
diff --git a/avrdude/ppi.h b/avrdude/ppi.h
new file mode 100644
index 00000000..f12b839b
--- /dev/null
+++ b/avrdude/ppi.h
@@ -0,0 +1,60 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2000-2004  Brian S. Dean <bsd@bsdhome.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id$ */
+
+#ifndef ppi_h
+#define ppi_h
+
+/*
+ * PPI registers
+ */
+enum {
+  PPIDATA,
+  PPICTRL,
+  PPISTATUS
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int ppi_get       (union filedescriptor *fdp, int reg, int bit);
+
+int ppi_set       (union filedescriptor *fdp, int reg, int bit);
+
+int ppi_clr       (union filedescriptor *fdp, int reg, int bit);
+
+int ppi_getall    (union filedescriptor *fdp, int reg);
+
+int ppi_setall    (union filedescriptor *fdp, int reg, int val);
+
+int ppi_toggle    (union filedescriptor *fdp, int reg, int bit);
+
+void ppi_open     (char * port, union filedescriptor *fdp);
+
+void ppi_close    (union filedescriptor *fdp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/avrdude/ppiwin.c b/avrdude/ppiwin.c
new file mode 100644
index 00000000..f9c51b54
--- /dev/null
+++ b/avrdude/ppiwin.c
@@ -0,0 +1,416 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2003, 2004, 2006
+ *    Eric B. Weddington <eweddington@cso.atmel.com>
+ * Copyright 2008, Joerg Wunsch
+ *
+ * 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
+ */
+
+/* $Id$ */
+
+/*
+This is the parallel port interface for Windows built using Cygwin.
+
+In the ppi_* functions that access the parallel port registers,
+fd = parallel port address
+reg = register as defined in an enum in ppi.h. This must be converted
+   to a proper offset of the base address.
+*/
+
+
+#include "ac_cfg.h"
+#include "avrdude.h"
+
+#if defined (WIN32NATIVE)
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <windows.h>
+#include <sys/time.h>
+#include <windows.h>
+
+#include "serial.h"
+#include "ppi.h"
+
+#define DEVICE_LPT1 "lpt1"
+#define DEVICE_LPT2 "lpt2"
+#define DEVICE_LPT3 "lpt3"
+
+#define DEVICE_MAX	3
+
+typedef struct
+{
+    const char *name;
+    int base_address;
+} winpp;
+
+static const winpp winports[DEVICE_MAX] = 
+{
+    {DEVICE_LPT1, 0x378},
+    {DEVICE_LPT2, 0x278},
+    {DEVICE_LPT3, 0x3BC},
+};
+
+
+
+
+
+/* FUNCTION PROTOTYPES */
+static int winnt_pp_open(void);
+static unsigned short port_get(union filedescriptor *fdp, int reg);
+static unsigned char reg2offset(int reg);
+static unsigned char inb(unsigned short port);
+static void outb(unsigned char value, unsigned short port);
+
+
+
+/* FUNCTION DEFINITIONS */
+
+void ppi_open(char *port, union filedescriptor *fdp)
+{
+    unsigned char i;
+    int fd;
+	
+    fd = winnt_pp_open();
+
+    if(fd < 0)
+    {
+        fprintf(stderr, "%s: can't open device \"giveio\"\n\n", progname);
+        fdp->ifd = -1;
+        return;
+    }
+
+    /* Search the windows port names for a match */
+    fd = -1;
+    for(i = 0; i < DEVICE_MAX; i++)
+    {
+        if(strcmp(winports[i].name, port) == 0)
+        {
+            /* Set the file descriptor with the Windows parallel port base address. */
+            fd = winports[i].base_address;
+            break;
+        }
+    }
+    if(fd == -1)
+    {
+	/*
+	 * Supplied port name did not match any of the pre-defined
+	 * names.  Try interpreting it as a numeric
+	 * (hexadecimal/decimal/octal) address.
+	 */
+	char *cp;
+
+	fd = strtol(port, &cp, 0);
+	if(*port == '\0' || *cp != '\0')
+	{
+	    fprintf(stderr,
+		    "%s: port name \"%s\" is neither lpt1/2/3 nor valid number\n",
+		    progname, port);
+	    fd = -1;
+	}
+    }
+    if(fd < 0)
+    {
+        fprintf(stderr, "%s: can't open device \"%s\"\n\n", progname, port);
+        fdp->ifd = -1;
+        return;
+    }
+
+    fdp->ifd = fd;
+}
+
+
+#define DRIVERNAME      "\\\\.\\giveio"
+static int winnt_pp_open(void)
+{
+    // Only try to use giveio under Windows NT/2000/XP.
+    OSVERSIONINFO ver_info;
+
+    memset(&ver_info, 0, sizeof(ver_info));
+
+    ver_info.dwOSVersionInfoSize = sizeof(ver_info);
+
+    if(!GetVersionEx(&ver_info))
+    {
+        return(-1);
+    }
+    else if(ver_info.dwPlatformId == VER_PLATFORM_WIN32_NT) 
+    {
+        HANDLE h = CreateFile(DRIVERNAME,
+            GENERIC_READ,
+            0,
+            NULL,
+            OPEN_EXISTING,
+            FILE_ATTRIBUTE_NORMAL,
+            NULL);
+
+        if(h == INVALID_HANDLE_VALUE)
+        {
+            return(-1);
+        }
+
+        /* Close immediately. The process now has the rights it needs. */
+        if(h != NULL)
+        {
+            CloseHandle(h);
+        }
+    }
+    return(0);
+}
+
+
+
+
+void ppi_close(union filedescriptor *fdp)
+{
+    return;
+}
+
+
+
+/*
+ * set the indicated bit of the specified register.
+ */
+int ppi_set(union filedescriptor *fdp, int reg, int bit)
+{
+    unsigned char v;
+    unsigned short port;
+
+    port = port_get(fdp, reg);
+    v = inb(port);
+    v |= bit;
+    outb(v, port);
+    return 0;
+}
+
+
+/*
+ * clear the indicated bit of the specified register.
+ */
+int ppi_clr(union filedescriptor *fdp, int reg, int bit)
+{
+    unsigned char v;
+    unsigned short port;
+
+    port = port_get(fdp, reg);
+    v = inb(port);
+    v &= ~bit;
+    outb(v, port);
+
+    return 0;
+}
+
+
+/*
+ * get the indicated bit of the specified register.
+ */
+int ppi_get(union filedescriptor *fdp, int reg, int bit)
+{
+    unsigned char v;
+
+    v = inb(port_get(fdp, reg));
+    v &= bit;
+
+    return(v);
+}
+
+
+
+
+/*
+ * toggle the indicated bit of the specified register.
+ */
+int ppi_toggle(union filedescriptor *fdp, int reg, int bit)
+{
+    unsigned char v;
+    unsigned short port;
+
+    port = port_get(fdp, reg);
+
+    v = inb(port);
+    v ^= bit;
+    outb(v, port);
+
+    return 0;
+}
+
+
+/*
+ * get all bits of the specified register.
+ */
+int ppi_getall(union filedescriptor *fdp, int reg)
+{
+    unsigned char v;
+
+    v = inb(port_get(fdp, reg));
+
+    return((int)v);
+}
+
+
+
+
+/*
+ * set all bits of the specified register to val.
+ */
+int ppi_setall(union filedescriptor *fdp, int reg, int val)
+{
+    outb((unsigned char)val, port_get(fdp, reg));
+    return 0;
+}
+
+
+
+
+/* Calculate port address to access. */
+static unsigned short port_get(union filedescriptor *fdp, int reg)
+{
+    return((unsigned short)(fdp->ifd + reg2offset(reg)));
+}
+
+
+/* Convert register enum to offset of base address. */
+static unsigned char reg2offset(int reg)
+{
+    unsigned char offset = 0;
+
+    switch(reg)
+    {
+        case PPIDATA:
+        {
+            offset = 0;
+            break;
+        }
+        case PPISTATUS:
+        {
+            offset = 1;
+            break;
+        }
+        case PPICTRL:
+        {
+            offset = 2;
+            break;
+        }
+    }
+
+    return(offset);
+}
+
+
+/* Read in value from port. */
+static unsigned char inb(unsigned short port)
+{
+    unsigned char t;
+    
+	asm volatile ("in %1, %0"
+        : "=a" (t)
+        : "d" (port));
+    
+	return t;
+}
+
+
+/* Write value to port. */
+static void outb(unsigned char value, unsigned short port)
+{
+    asm volatile ("out %1, %0"
+        :
+        : "d" (port), "a" (value) );
+
+    return;
+}
+
+#if !defined(HAVE_GETTIMEOFDAY)
+struct timezone;
+int gettimeofday(struct timeval *tv, struct timezone *unused){
+// i've found only ms resolution, avrdude expects us
+
+	SYSTEMTIME st;
+	GetSystemTime(&st);
+  
+	tv->tv_sec=(long)(st.wSecond+st.wMinute*60+st.wHour*3600);
+	tv->tv_usec=(long)(st.wMilliseconds*1000);
+
+	return 0;
+}
+#endif /* HAVE_GETTIMEOFDAY */
+
+// #define W32USLEEPDBG
+
+#ifdef W32USLEEPDBG
+
+#  define DEBUG_QueryPerformanceCounter(arg) QueryPerformanceCounter(arg)
+#  define DEBUG_DisplayTimingInfo(start, stop, freq, us, has_highperf)     \
+     do {                                                                  \
+       unsigned long dt;                                                   \
+       dt = (unsigned long)((stop.QuadPart - start.QuadPart) * 1000 * 1000 \
+                            / freq.QuadPart);                              \
+       fprintf(stderr,                                                     \
+               "hpt:%i usleep usec:%lu sleep msec:%lu timed usec:%lu\n",   \
+               has_highperf, us, ((us + 999) / 1000), dt);                 \
+     } while (0)
+
+#else
+
+#  define DEBUG_QueryPerformanceCounter(arg)
+#  define DEBUG_DisplayTimingInfo(start, stop, freq, us, has_highperf)
+
+#endif
+
+int usleep(unsigned int us)
+{
+	int has_highperf;
+	LARGE_INTEGER freq,start,stop,loopend;
+
+	// workaround: although usleep is very precise if using
+	// high-performance-timers there are sometimes problems with
+	// verify - increasing the delay helps sometimes but not
+	// realiably. There must be some other problem. Maybe just
+	// with my test-hardware maybe in the code-base.
+	//// us=(unsigned long) (us*1.5);	
+
+	has_highperf=QueryPerformanceFrequency(&freq);
+
+	//has_highperf=0; // debug
+
+	if (has_highperf) {
+		QueryPerformanceCounter(&start);
+		loopend.QuadPart=start.QuadPart+freq.QuadPart*us/(1000*1000);
+		do { 
+			QueryPerformanceCounter(&stop);
+		} while (stop.QuadPart<=loopend.QuadPart);
+	}
+	else {
+		DEBUG_QueryPerformanceCounter(&start);
+
+		Sleep(1);
+		Sleep( (DWORD)((us+999)/1000) );
+
+		DEBUG_QueryPerformanceCounter(&stop);
+	}
+	
+    DEBUG_DisplayTimingInfo(start, stop, freq, us, has_highperf);
+
+    return 0;
+}
+
+#endif
+
+
diff --git a/avrdude/safemode.c b/avrdude/safemode.c
new file mode 100644
index 00000000..62d02afa
--- /dev/null
+++ b/avrdude/safemode.c
@@ -0,0 +1,363 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * avrdude is Copyright (C) 2000-2004  Brian S. Dean <bsd@bsdhome.com>
+ *
+ * This file: Copyright (C) 2005-2007 Colin O'Flynn <coflynn@newae.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include <stdio.h>
+
+#include "ac_cfg.h"
+#include "avrdude.h"
+#include "avr.h"
+#include "pgm.h"
+#include "safemode.h"
+
+/* This value from ac_cfg.h */
+/* 
+ * Writes the specified fuse in fusename (can be "lfuse", "hfuse", or
+ * "efuse") and verifies it. Will try up to tries amount of times
+ * before giving up 
+ */
+int safemode_writefuse (unsigned char fuse, char * fusename, PROGRAMMER * pgm,
+                        AVRPART * p, int tries, int verbose)
+{
+  AVRMEM * m;
+  unsigned char fuseread;
+  int returnvalue = -1;
+  
+  m = avr_locate_mem(p, fusename);
+  if (m == NULL) {
+    return -1;
+    }
+ 
+  /* Keep trying to write then read back the fuse values */   
+  while (tries > 0) {
+    if (avr_write_byte(pgm, p, m, 0, fuse) != 0)
+        {
+        continue;
+        }
+    if (pgm->read_byte(pgm, p, m, 0, &fuseread) != 0)
+        {
+        continue;
+        }
+        
+    /* Report information to user if needed */
+    if (verbose > 0) {
+      fprintf(stderr, 
+              "%s: safemode: Wrote %s to %x, read as %x. %d attempts left\n",
+              progname, fusename, fuse, fuseread, tries-1);
+    }
+    
+    /* If fuse wrote OK, no need to keep going */
+    if (fuse == fuseread) {
+       tries = 0;
+       returnvalue = 0;
+    }
+    tries--;
+  }
+  
+  return returnvalue;
+}
+
+/* 
+ * Reads the fuses three times, checking that all readings are the
+ * same. This will ensure that the before values aren't in error! 
+ */
+int safemode_readfuses (unsigned char * lfuse, unsigned char * hfuse, 
+                        unsigned char * efuse, unsigned char * fuse, 
+                        PROGRAMMER * pgm, AVRPART * p, int verbose)  
+{
+
+  unsigned char value;
+  unsigned char fusegood = 0;
+  unsigned char allowfuseread = 1;
+  unsigned char safemode_lfuse;
+  unsigned char safemode_hfuse;
+  unsigned char safemode_efuse;
+  unsigned char safemode_fuse;
+  AVRMEM * m;
+  
+  safemode_lfuse = *lfuse;
+  safemode_hfuse = *hfuse;
+  safemode_efuse = *efuse;
+  safemode_fuse  = *fuse;
+
+
+  /* Read fuse three times */ 
+  fusegood = 2; /* If AVR device doesn't support this fuse, don't want
+                   to generate a verify error */
+  m = avr_locate_mem(p, "fuse");
+  if (m != NULL) {
+    fusegood = 0; /* By default fuse is a failure */
+    if(pgm->read_byte(pgm, p, m, 0, &safemode_fuse) != 0)
+        {
+        allowfuseread = 0;
+        }
+	if (verbose > 2)
+		{
+		fprintf(stderr, "%s: safemode read 1, fuse value: %x\n",progname, safemode_fuse);
+		}
+    if(pgm->read_byte(pgm, p, m, 0, &value) != 0)
+        {
+        allowfuseread = 0;
+        }
+	if (verbose > 2)
+		{
+		fprintf(stderr, "%s: safemode read 2, fuse value: %x\n",progname,  value);
+		}
+    if (value == safemode_fuse) {
+        if (pgm->read_byte(pgm, p, m, 0, &value) != 0)
+            {
+            allowfuseread = 0;
+            }
+		if (verbose > 2)
+			{
+			fprintf(stderr, "%s: safemode read 3, fuse value: %x\n",progname,  value);
+			}
+        if (value == safemode_fuse)
+            {
+            fusegood = 1; /* Fuse read OK three times */
+            }
+    }
+  } 
+
+	//Programmer does not allow fuse reading.... no point trying anymore
+    if (allowfuseread == 0)
+		{
+		return -5;
+		}
+
+    if (fusegood == 0)   {
+        fprintf(stderr,
+           "%s: safemode: Verify error - unable to read fuse properly. "
+           "Programmer may not be reliable.\n", progname);
+        return -1;
+    }
+    else if ((fusegood == 1) && (verbose > 0)) {
+        printf("%s: safemode: fuse reads as %X\n", progname, safemode_fuse);
+    }
+
+
+  /* Read lfuse three times */  
+  fusegood = 2; /* If AVR device doesn't support this fuse, don't want
+                   to generate a verify error */
+  m = avr_locate_mem(p, "lfuse");
+  if (m != NULL) {
+    fusegood = 0; /* By default fuse is a failure */
+    if (pgm->read_byte(pgm, p, m, 0, &safemode_lfuse) != 0)
+        {
+        allowfuseread = 0;
+        }
+	if (verbose > 2)
+		{
+		fprintf(stderr, "%s: safemode read 1, lfuse value: %x\n",progname,  safemode_lfuse);
+		}
+    if (pgm->read_byte(pgm, p, m, 0, &value) != 0)
+        {
+        allowfuseread = 0;
+        }
+	if (verbose > 2)
+		{
+		fprintf(stderr, "%s: safemode read 2, lfuse value: %x\n",progname,  value);
+		}
+    if (value == safemode_lfuse) {
+        if (pgm->read_byte(pgm, p, m, 0, &value) != 0)
+            {
+            allowfuseread = 0;
+            }
+		if (verbose > 2)
+			{
+			fprintf(stderr, "%s: safemode read 3, lfuse value: %x\n",progname,  value);
+			}
+        if (value == safemode_lfuse){
+        fusegood = 1; /* Fuse read OK three times */
+        }
+    }
+  }
+
+	//Programmer does not allow fuse reading.... no point trying anymore
+    if (allowfuseread == 0)
+		{
+		return -5;
+		}
+
+
+    if (fusegood == 0)	 {
+        fprintf(stderr,
+           "%s: safemode: Verify error - unable to read lfuse properly. "
+           "Programmer may not be reliable.\n", progname);
+        return -1;
+    }
+    else if ((fusegood == 1) && (verbose > 0)) {
+        printf("%s: safemode: lfuse reads as %X\n", progname, safemode_lfuse);
+    }
+
+  /* Read hfuse three times */  
+  fusegood = 2; /* If AVR device doesn't support this fuse, don't want
+                   to generate a verify error */
+  m = avr_locate_mem(p, "hfuse");
+  if (m != NULL) {
+    fusegood = 0; /* By default fuse is a failure */
+    if (pgm->read_byte(pgm, p, m, 0, &safemode_hfuse) != 0)
+        {
+        allowfuseread = 0;
+        }
+	if (verbose > 2)
+		{
+		fprintf(stderr, "%s: safemode read 1, hfuse value: %x\n",progname,  safemode_hfuse);
+		}
+    if (pgm->read_byte(pgm, p, m, 0, &value) != 0)
+        {
+        allowfuseread = 0;
+        }
+	if (verbose > 2)
+		{
+		fprintf(stderr, "%s: safemode read 2, hfuse value: %x\n",progname,  value);
+		}
+    if (value == safemode_hfuse) {
+        if (pgm->read_byte(pgm, p, m, 0, &value) != 0)
+            {
+            allowfuseread = 0;
+            }
+		if (verbose > 2)
+			{
+			fprintf(stderr, "%s: safemode read 3, hfuse value: %x\n",progname, value);
+			}
+        if (value == safemode_hfuse){
+             fusegood = 1; /* Fuse read OK three times */
+        }
+    }
+  }
+
+	//Programmer does not allow fuse reading.... no point trying anymore
+    if (allowfuseread == 0)
+		{
+		return -5;
+		}
+
+    if (fusegood == 0)	 {
+            fprintf(stderr,
+           "%s: safemode: Verify error - unable to read hfuse properly. "
+           "Programmer may not be reliable.\n", progname);
+       return -2;
+    }
+    else if ((fusegood == 1) && (verbose > 0)){
+        printf("%s: safemode: hfuse reads as %X\n", progname, safemode_hfuse);
+    }
+
+  /* Read efuse three times */  
+  fusegood = 2; /* If AVR device doesn't support this fuse, don't want
+                   to generate a verify error */
+  m = avr_locate_mem(p, "efuse");
+  if (m != NULL) {
+    fusegood = 0; /* By default fuse is a failure */
+    if (pgm->read_byte(pgm, p, m, 0, &safemode_efuse) != 0)
+        {
+        allowfuseread = 0;
+        }
+	if (verbose > 2)
+		{
+		fprintf(stderr, "%s: safemode read 1, efuse value: %x\n",progname, safemode_efuse);
+		}
+    if (pgm->read_byte(pgm, p, m, 0, &value) != 0)
+        {
+        allowfuseread = 0;
+        }
+	if (verbose > 2)
+		{
+		fprintf(stderr, "%s: safemode read 2, efuse value: %x\n",progname,  value);
+		}
+    if (value == safemode_efuse) {
+        if (pgm->read_byte(pgm, p, m, 0, &value) != 0)
+            {
+            allowfuseread = 0;
+            }
+		if (verbose > 2)
+			{
+			fprintf(stderr, "%s: safemode read 3, efuse value: %x\n",progname, value);
+			}
+        if (value == safemode_efuse){
+             fusegood = 1; /* Fuse read OK three times */
+        }
+    }
+  }
+   
+	//Programmer does not allow fuse reading.... no point trying anymore
+    if (allowfuseread == 0)
+		{
+		return -5;
+		}
+ 
+    if (fusegood == 0)	 {
+        fprintf(stderr,
+           "%s: safemode: Verify error - unable to read efuse properly. "
+           "Programmer may not be reliable.\n", progname);
+        return -3;
+        }
+    else if ((fusegood == 1) && (verbose > 0)) {
+        printf("%s: safemode: efuse reads as %X\n", progname, safemode_efuse);
+        }
+
+  *lfuse = safemode_lfuse;
+  *hfuse = safemode_hfuse;
+  *efuse = safemode_efuse;
+  *fuse  = safemode_fuse;
+
+  return 0;
+}
+
+
+/*
+ * This routine will store the current values pointed to by lfuse,
+ * hfuse, and efuse into an internal buffer in this routine when save
+ * is set to 1. When save is 0 (or not 1 really) it will copy the
+ * values from the internal buffer into the locations pointed to be
+ * lfuse, hfuse, and efuse. This allows you to change the fuse bits if
+ * needed from another routine (ie: have it so if user requests fuse
+ * bits are changed, the requested value is now verified 
+ */
+int safemode_memfuses (int save, unsigned char * lfuse, unsigned char * hfuse,
+                       unsigned char * efuse, unsigned char * fuse)
+{
+  static unsigned char safemode_lfuse = 0xff;
+  static unsigned char safemode_hfuse = 0xff;
+  static unsigned char safemode_efuse = 0xff;
+  static unsigned char safemode_fuse = 0xff;
+  
+  switch (save) {
+    
+    /* Save the fuses as safemode setting */
+    case 1:  
+        safemode_lfuse = *lfuse;
+        safemode_hfuse = *hfuse;
+        safemode_efuse = *efuse;
+        safemode_fuse  = *fuse;
+
+        break;
+    /* Read back the fuses */
+    default:
+        *lfuse = safemode_lfuse;
+        *hfuse = safemode_hfuse;
+        *efuse = safemode_efuse;
+        *fuse  = safemode_fuse;
+        break;
+  }
+  
+  return 0;
+}
diff --git a/avrdude/safemode.h b/avrdude/safemode.h
new file mode 100644
index 00000000..4c8ba4fa
--- /dev/null
+++ b/avrdude/safemode.h
@@ -0,0 +1,47 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * avrdude is Copyright (C) 2000-2004  Brian S. Dean <bsd@bsdhome.com>
+ *
+ * This file: Copyright (C) 2005 Colin O'Flynn <coflynn@newae.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+ 
+#ifndef safemode_h
+#define safemode_h
+ 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Writes the specified fuse in fusename (can be "lfuse", "hfuse", or "efuse") and verifies it. Will try up to tries
+amount of times before giving up */
+int safemode_writefuse (unsigned char fuse, char * fusename, PROGRAMMER * pgm, AVRPART * p, int tries, int verbose);
+
+/* Reads the fuses three times, checking that all readings are the same. This will ensure that the before values aren't in error! */
+int safemode_readfuses (unsigned char * lfuse, unsigned char * hfuse, unsigned char * efuse, unsigned char * fuse, PROGRAMMER * pgm, AVRPART * p, int verbose);
+  
+/* This routine will store the current values pointed to by lfuse, hfuse, and efuse into an internal buffer in this routine
+when save is set to 1. When save is 0 (or not 1 really) it will copy the values from the internal buffer into the locations
+pointed to be lfuse, hfuse, and efuse. This allows you to change the fuse bits if needed from another routine (ie: have it so
+if user requests fuse bits are changed, the requested value is now verified */
+int safemode_memfuses (int save, unsigned char * lfuse, unsigned char * hfuse, unsigned char * efuse, unsigned char * fuse);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* safemode_h */
diff --git a/avrdude/ser_avrdoper.c b/avrdude/ser_avrdoper.c
new file mode 100644
index 00000000..ed0af07a
--- /dev/null
+++ b/avrdude/ser_avrdoper.c
@@ -0,0 +1,656 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2003-2004  Theodore A. Roth  <troth@openavr.org>
+ * Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
+ * Copyright (C) 2006 Christian Starkjohann
+ *
+ * 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
+ */
+
+/* $Id$ */
+
+/*
+ * Serial Interface emulation for USB programmer "AVR-Doper" in HID mode.
+ */
+
+#include "ac_cfg.h"
+
+#if defined(HAVE_LIBUSB) || (defined(WIN32NATIVE) && defined(HAVE_LIBHID))
+
+#include <stdio.h>
+#include <string.h>
+
+#include "avrdude.h"
+#include "serial.h"
+
+/* ------------------------------------------------------------------------ */
+
+/* Numeric constants for 'reportType' parameters */
+#define USB_HID_REPORT_TYPE_INPUT   1
+#define USB_HID_REPORT_TYPE_OUTPUT  2
+#define USB_HID_REPORT_TYPE_FEATURE 3
+
+/* These are the error codes which can be returned by functions of this
+ * module.
+ */
+#define USB_ERROR_NONE      0
+#define USB_ERROR_ACCESS    1
+#define USB_ERROR_NOTFOUND  2
+#define USB_ERROR_BUSY      16
+#define USB_ERROR_IO        5
+
+#define USB_VENDOR_ID   0x16c0
+#define USB_PRODUCT_ID  0x05df
+
+static int  reportDataSizes[4] = {13, 29, 61, 125};
+
+static unsigned char    avrdoperRxBuffer[280];  /* buffer for receive data */
+static int              avrdoperRxLength = 0;   /* amount of valid bytes in rx buffer */
+static int              avrdoperRxPosition = 0; /* amount of bytes already consumed in rx buffer */
+
+/* ------------------------------------------------------------------------ */
+/* ------------------------------------------------------------------------ */
+/* ------------------------------------------------------------------------ */
+
+#if defined(WIN32NATIVE) && defined(HAVE_LIBHID)
+
+#include <windows.h>
+#include <setupapi.h>
+
+#if defined(HAVE_DDK_HIDSDI_H)
+#  include <ddk/hidsdi.h>
+#else
+#  include "my_ddk_hidsdi.h"
+#endif
+#include <ddk/hidpi.h>
+
+#ifdef USB_DEBUG
+#define DEBUG_PRINT(arg)    printf arg
+#else
+#define DEBUG_PRINT(arg)
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+static void convertUniToAscii(char *buffer)
+{
+    unsigned short  *uni = (void *)buffer;
+    char            *ascii = buffer;
+
+    while(*uni != 0){
+        if(*uni >= 256){
+            *ascii++ = '?';
+            uni++;
+        }else{
+            *ascii++ = *uni++;
+        }
+    }
+    *ascii++ = 0;
+}
+
+static int usbOpenDevice(union filedescriptor *fdp, int vendor, char *vendorName,
+			 int product, char *productName, int usesReportIDs)
+{
+    GUID                                hidGuid;        /* GUID for HID driver */
+    HDEVINFO                            deviceInfoList;
+    SP_DEVICE_INTERFACE_DATA            deviceInfo;
+    SP_DEVICE_INTERFACE_DETAIL_DATA     *deviceDetails = NULL;
+    DWORD                               size;
+    int                                 i, openFlag = 0;  /* may be FILE_FLAG_OVERLAPPED */
+    int                                 errorCode = USB_ERROR_NOTFOUND;
+    HANDLE                              handle = INVALID_HANDLE_VALUE;
+    HIDD_ATTRIBUTES                     deviceAttributes;
+
+    HidD_GetHidGuid(&hidGuid);
+    deviceInfoList = SetupDiGetClassDevs(&hidGuid, NULL, NULL,
+					 DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
+    deviceInfo.cbSize = sizeof(deviceInfo);
+    for(i=0;;i++){
+        if(handle != INVALID_HANDLE_VALUE){
+            CloseHandle(handle);
+            handle = INVALID_HANDLE_VALUE;
+        }
+        if(!SetupDiEnumDeviceInterfaces(deviceInfoList, 0, &hidGuid, i, &deviceInfo))
+            break;  /* no more entries */
+        /* first do a dummy call just to determine the actual size required */
+        SetupDiGetDeviceInterfaceDetail(deviceInfoList, &deviceInfo, NULL, 0, &size, NULL);
+        if(deviceDetails != NULL)
+            free(deviceDetails);
+        deviceDetails = malloc(size);
+        deviceDetails->cbSize = sizeof(*deviceDetails);
+        /* this call is for real: */
+        SetupDiGetDeviceInterfaceDetail(deviceInfoList, &deviceInfo, deviceDetails,
+					size, &size, NULL);
+        DEBUG_PRINT(("checking HID path \"%s\"\n", deviceDetails->DevicePath));
+        /* attempt opening for R/W -- we don't care about devices which can't be accessed */
+        handle = CreateFile(deviceDetails->DevicePath, GENERIC_READ|GENERIC_WRITE,
+			    FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
+			    openFlag, NULL);
+        if(handle == INVALID_HANDLE_VALUE){
+            DEBUG_PRINT(("opening failed: %d\n", (int)GetLastError()));
+            /* errorCode = USB_ERROR_ACCESS; opening will always fail for mouse -- ignore */
+            continue;
+        }
+        deviceAttributes.Size = sizeof(deviceAttributes);
+        HidD_GetAttributes(handle, &deviceAttributes);
+        DEBUG_PRINT(("device attributes: vid=%d pid=%d\n",
+		     deviceAttributes.VendorID, deviceAttributes.ProductID));
+        if(deviceAttributes.VendorID != vendor || deviceAttributes.ProductID != product)
+            continue;   /* ignore this device */
+        errorCode = USB_ERROR_NOTFOUND;
+        if(vendorName != NULL && productName != NULL){
+            char    buffer[512];
+            if(!HidD_GetManufacturerString(handle, buffer, sizeof(buffer))){
+                DEBUG_PRINT(("error obtaining vendor name\n"));
+                errorCode = USB_ERROR_IO;
+                continue;
+            }
+            convertUniToAscii(buffer);
+            DEBUG_PRINT(("vendorName = \"%s\"\n", buffer));
+            if(strcmp(vendorName, buffer) != 0)
+                continue;
+            if(!HidD_GetProductString(handle, buffer, sizeof(buffer))){
+                DEBUG_PRINT(("error obtaining product name\n"));
+                errorCode = USB_ERROR_IO;
+                continue;
+            }
+            convertUniToAscii(buffer);
+            DEBUG_PRINT(("productName = \"%s\"\n", buffer));
+            if(strcmp(productName, buffer) != 0)
+                continue;
+        }
+        break;  /* we have found the device we are looking for! */
+    }
+    SetupDiDestroyDeviceInfoList(deviceInfoList);
+    if(deviceDetails != NULL)
+        free(deviceDetails);
+    if(handle != INVALID_HANDLE_VALUE){
+	fdp->pfd = (void *)handle;
+	errorCode = 0;
+    }
+    return errorCode;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static void    usbCloseDevice(union filedescriptor *fdp)
+{
+    CloseHandle((HANDLE)fdp->pfd);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int usbSetReport(union filedescriptor *fdp, int reportType, char *buffer, int len)
+{
+    HANDLE  handle = (HANDLE)fdp->pfd;
+    BOOLEAN rval = 0;
+    DWORD   bytesWritten;
+
+    switch(reportType){
+    case USB_HID_REPORT_TYPE_INPUT:
+        break;
+    case USB_HID_REPORT_TYPE_OUTPUT:
+        rval = WriteFile(handle, buffer, len, &bytesWritten, NULL);
+        break;
+    case USB_HID_REPORT_TYPE_FEATURE:
+        rval = HidD_SetFeature(handle, buffer, len);
+        break;
+    }
+    return rval == 0 ? USB_ERROR_IO : 0;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int usbGetReport(union filedescriptor *fdp, int reportType, int reportNumber,
+			char *buffer, int *len)
+{
+    HANDLE  handle = (HANDLE)fdp->pfd;
+    BOOLEAN rval = 0;
+    DWORD   bytesRead;
+
+    switch(reportType){
+    case USB_HID_REPORT_TYPE_INPUT:
+        buffer[0] = reportNumber;
+        rval = ReadFile(handle, buffer, *len, &bytesRead, NULL);
+        if(rval)
+            *len = bytesRead;
+        break;
+    case USB_HID_REPORT_TYPE_OUTPUT:
+        break;
+    case USB_HID_REPORT_TYPE_FEATURE:
+        buffer[0] = reportNumber;
+        rval = HidD_GetFeature(handle, buffer, *len);
+        break;
+    }
+    return rval == 0 ? USB_ERROR_IO : 0;
+}
+
+/* ------------------------------------------------------------------------ */
+/* ------------------------------------------------------------------------ */
+/* ------------------------------------------------------------------------ */
+
+#else /* !(WIN32NATIVE && HAVE_LIBHID) */
+
+/* ------------------------------------------------------------------------ */
+/* ------------------------------------------------------------------------ */
+/* ------------------------------------------------------------------------ */
+
+#include <usb.h>
+
+/* ------------------------------------------------------------------------- */
+
+#define USBRQ_HID_GET_REPORT    0x01
+#define USBRQ_HID_SET_REPORT    0x09
+
+static int  usesReportIDs;
+
+/* ------------------------------------------------------------------------- */
+
+static int  usbGetStringAscii(usb_dev_handle *dev, int index, int langid, char *buf, int buflen)
+{
+    char    buffer[256];
+    int     rval, i;
+
+    if((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
+			       (USB_DT_STRING << 8) + index, langid, buffer,
+			       sizeof(buffer), 1000)) < 0)
+        return rval;
+    if(buffer[1] != USB_DT_STRING)
+        return 0;
+    if((unsigned char)buffer[0] < rval)
+        rval = (unsigned char)buffer[0];
+    rval /= 2;
+    /* lossy conversion to ISO Latin1 */
+    for(i=1;i<rval;i++){
+        if(i > buflen)  /* destination buffer overflow */
+            break;
+        buf[i-1] = buffer[2 * i];
+        if(buffer[2 * i + 1] != 0)  /* outside of ISO Latin1 range */
+            buf[i-1] = '?';
+    }
+    buf[i-1] = 0;
+    return i-1;
+}
+
+static int usbOpenDevice(union filedescriptor *fdp, int vendor, char *vendorName,
+			 int product, char *productName, int doReportIDs)
+{
+    struct usb_bus      *bus;
+    struct usb_device   *dev;
+    usb_dev_handle      *handle = NULL;
+    int                 errorCode = USB_ERROR_NOTFOUND;
+    static int          didUsbInit = 0;
+
+    if(!didUsbInit){
+        usb_init();
+        didUsbInit = 1;
+    }
+    usb_find_busses();
+    usb_find_devices();
+    for(bus=usb_get_busses(); bus; bus=bus->next){
+        for(dev=bus->devices; dev; dev=dev->next){
+            if(dev->descriptor.idVendor == vendor && dev->descriptor.idProduct == product){
+                char    string[256];
+                int     len;
+                handle = usb_open(dev); /* we need to open the device in order to query strings */
+                if(!handle){
+                    errorCode = USB_ERROR_ACCESS;
+                    fprintf(stderr, "Warning: cannot open USB device: %s\n",
+			    usb_strerror());
+                    continue;
+                }
+                if(vendorName == NULL && productName == NULL){  /* name does not matter */
+                    break;
+                }
+                /* now check whether the names match: */
+                len = usbGetStringAscii(handle, dev->descriptor.iManufacturer,
+					0x0409, string, sizeof(string));
+                if(len < 0){
+                    errorCode = USB_ERROR_IO;
+                    fprintf(stderr,
+			    "Warning: cannot query manufacturer for device: %s\n",
+			    usb_strerror());
+                }else{
+                    errorCode = USB_ERROR_NOTFOUND;
+                    /* fprintf(stderr, "seen device from vendor ->%s<-\n", string); */
+                    if(strcmp(string, vendorName) == 0){
+                        len = usbGetStringAscii(handle, dev->descriptor.iProduct,
+						0x0409, string, sizeof(string));
+                        if(len < 0){
+                            errorCode = USB_ERROR_IO;
+                            fprintf(stderr,
+				    "Warning: cannot query product for device: %s\n",
+				    usb_strerror());
+                        }else{
+                            errorCode = USB_ERROR_NOTFOUND;
+                            /* fprintf(stderr, "seen product ->%s<-\n", string); */
+                            if(strcmp(string, productName) == 0)
+                                break;
+                        }
+                    }
+                }
+                usb_close(handle);
+                handle = NULL;
+            }
+        }
+        if(handle)
+            break;
+    }
+    if(handle != NULL){
+        int rval, retries = 3;
+        if(usb_set_configuration(handle, 1)){
+            fprintf(stderr, "Warning: could not set configuration: %s\n",
+		    usb_strerror());
+        }
+        /* now try to claim the interface and detach the kernel HID driver on
+         * linux and other operating systems which support the call.
+         */
+        while((rval = usb_claim_interface(handle, 0)) != 0 && retries-- > 0){
+#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
+            if(usb_detach_kernel_driver_np(handle, 0) < 0){
+                fprintf(stderr, "Warning: could not detach kernel HID driver: %s\n",
+			usb_strerror());
+            }
+#endif
+        }
+        if(rval != 0)
+            fprintf(stderr, "Warning: could not claim interface\n");
+/* Continue anyway, even if we could not claim the interface. Control transfers
+ * should still work.
+ */
+        errorCode = 0;
+        fdp->pfd = (void *)handle;
+        usesReportIDs = doReportIDs;
+    }
+    return errorCode;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void    usbCloseDevice(union filedescriptor *fdp)
+{
+    usb_close((usb_dev_handle *)fdp->pfd);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int usbSetReport(union filedescriptor *fdp, int reportType, char *buffer, int len)
+{
+    int bytesSent;
+
+    if(!usesReportIDs){
+        buffer++;   /* skip dummy report ID */
+        len--;
+    }
+    bytesSent = usb_control_msg((usb_dev_handle *)fdp->pfd, USB_TYPE_CLASS |
+				USB_RECIP_INTERFACE | USB_ENDPOINT_OUT, USBRQ_HID_SET_REPORT,
+				reportType << 8 | buffer[0], 0, buffer, len, 5000);
+    if(bytesSent != len){
+        if(bytesSent < 0)
+            fprintf(stderr, "Error sending message: %s\n", usb_strerror());
+        return USB_ERROR_IO;
+    }
+    return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int usbGetReport(union filedescriptor *fdp, int reportType, int reportNumber,
+			char *buffer, int *len)
+{
+    int bytesReceived, maxLen = *len;
+
+    if(!usesReportIDs){
+        buffer++;   /* make room for dummy report ID */
+        maxLen--;
+    }
+    bytesReceived = usb_control_msg((usb_dev_handle *)fdp->pfd, USB_TYPE_CLASS |
+				    USB_RECIP_INTERFACE | USB_ENDPOINT_IN, USBRQ_HID_GET_REPORT,
+				    reportType << 8 | reportNumber, 0, buffer, maxLen, 5000);
+    if(bytesReceived < 0){
+        fprintf(stderr, "Error sending message: %s\n", usb_strerror());
+        return USB_ERROR_IO;
+    }
+    *len = bytesReceived;
+    if(!usesReportIDs){
+        buffer[-1] = reportNumber;  /* add dummy report ID */
+        len++;
+    }
+    return 0;
+}
+
+#endif  /* WIN32NATIVE */
+
+/* ------------------------------------------------------------------------ */
+/* ------------------------------------------------------------------------ */
+/* ------------------------------------------------------------------------ */
+
+/* ------------------------------------------------------------------------- */
+
+static void dumpBlock(char *prefix, unsigned char *buf, int len)
+{
+    int i;
+
+    if(len <= 8){   /* more compact format for short blocks */
+        fprintf(stderr, "%s: %d bytes: ", prefix, len);
+        for(i = 0; i < len; i++){
+            fprintf(stderr, "%02x ", buf[i]);
+        }
+        fprintf(stderr, " \"");
+        for(i = 0; i < len; i++){
+            if(buf[i] >= 0x20 && buf[i] < 0x7f){
+                fputc(buf[i], stderr);
+            }else{
+                fputc('.', stderr);
+            }
+        }
+        fprintf(stderr, "\"\n");
+    }else{
+        fprintf(stderr, "%s: %d bytes:\n", prefix, len);
+        while(len > 0){
+            for(i = 0; i < 16; i++){
+                if(i < len){
+                    fprintf(stderr, "%02x ", buf[i]);
+                }else{
+                    fprintf(stderr, "   ");
+                }
+                if(i == 7)
+                    fputc(' ', stderr);
+            }
+            fprintf(stderr, "  \"");
+            for(i = 0; i < 16; i++){
+                if(i < len){
+                    if(buf[i] >= 0x20 && buf[i] < 0x7f){
+                        fputc(buf[i], stderr);
+                    }else{
+                        fputc('.', stderr);
+                    }
+                }
+            }
+            fprintf(stderr, "\"\n");
+            buf += 16;
+            len -= 16;
+        }
+    }
+}
+
+static char *usbErrorText(int usbErrno)
+{
+    static char buffer[32];
+
+    switch(usbErrno){
+        case USB_ERROR_NONE:    return "Success.";
+        case USB_ERROR_ACCESS:  return "Access denied.";
+        case USB_ERROR_NOTFOUND:return "Device not found.";
+        case USB_ERROR_BUSY:    return "Device is busy.";
+        case USB_ERROR_IO:      return "I/O Error.";
+        default:
+            sprintf(buffer, "Unknown error %d.", usbErrno);
+            return buffer;
+    }
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void avrdoper_open(char *port, long baud, union filedescriptor *fdp)
+{
+    int rval;
+    char *vname = "obdev.at";
+    char *devname = "AVR-Doper";
+
+    rval = usbOpenDevice(fdp, USB_VENDOR_ID, vname, USB_PRODUCT_ID, devname, 1);
+    if(rval != 0){
+        fprintf(stderr, "%s: avrdoper_open(): %s\n", progname, usbErrorText(rval));
+        exit(1);
+    }
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void avrdoper_close(union filedescriptor *fdp)
+{
+    usbCloseDevice(fdp);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int  chooseDataSize(int len)
+{
+    int i;
+
+    for(i = 0; i < sizeof(reportDataSizes)/sizeof(reportDataSizes[0]); i++){
+        if(reportDataSizes[i] >= len)
+            return i;
+    }
+    return i - 1;
+}
+
+static int avrdoper_send(union filedescriptor *fdp, unsigned char *buf, size_t buflen)
+{
+    if(verbose > 3)
+        dumpBlock("Send", buf, buflen);
+    while(buflen > 0){
+        unsigned char buffer[256];
+        int rval, lenIndex = chooseDataSize(buflen);
+        int thisLen = buflen > reportDataSizes[lenIndex] ?
+	    reportDataSizes[lenIndex] : buflen;
+        buffer[0] = lenIndex + 1;   /* report ID */
+        buffer[1] = thisLen;
+        memcpy(buffer + 2, buf, thisLen);
+        if(verbose > 3)
+            fprintf(stderr, "Sending %d bytes data chunk\n", thisLen);
+        rval = usbSetReport(fdp, USB_HID_REPORT_TYPE_FEATURE, (char *)buffer,
+			    reportDataSizes[lenIndex] + 2);
+        if(rval != 0){
+            fprintf(stderr, "%s: avrdoper_send(): %s\n", progname, usbErrorText(rval));
+            exit(1);
+        }
+        buflen -= thisLen;
+        buf += thisLen;
+    }
+    return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void avrdoperFillBuffer(union filedescriptor *fdp)
+{
+    int bytesPending = reportDataSizes[1];  /* guess how much data is buffered in device */
+
+    avrdoperRxPosition = avrdoperRxLength = 0;
+    while(bytesPending > 0){
+        int len, usbErr, lenIndex = chooseDataSize(bytesPending);
+        unsigned char buffer[128];
+        len = sizeof(avrdoperRxBuffer) - avrdoperRxLength;  /* bytes remaining */
+        if(reportDataSizes[lenIndex] + 2 > len) /* requested data would not fit into buffer */
+            break;
+        len = reportDataSizes[lenIndex] + 2;
+        usbErr = usbGetReport(fdp, USB_HID_REPORT_TYPE_FEATURE, lenIndex + 1,
+			      (char *)buffer, &len);
+        if(usbErr != 0){
+            fprintf(stderr, "%s: avrdoperFillBuffer(): %s\n", progname, usbErrorText(usbErr));
+            exit(1);
+        }
+        if(verbose > 3)
+            fprintf(stderr, "Received %d bytes data chunk of total %d\n", len - 2, buffer[1]);
+        len -= 2;   /* compensate for report ID and length byte */
+        bytesPending = buffer[1] - len; /* amount still buffered */
+        if(len > buffer[1])             /* cut away padding */
+            len = buffer[1];
+        if(avrdoperRxLength + len > sizeof(avrdoperRxBuffer)){
+            fprintf(stderr,
+		    "%s: avrdoperFillBuffer(): internal error: buffer overflow\n",
+		    progname);
+            exit(1);
+        }
+        memcpy(avrdoperRxBuffer + avrdoperRxLength, buffer + 2, len);
+        avrdoperRxLength += len;
+    }
+}
+
+static int avrdoper_recv(union filedescriptor *fdp, unsigned char *buf, size_t buflen)
+{
+    unsigned char   *p = buf;
+    int             remaining = buflen;
+
+    while(remaining > 0){
+        int len, available = avrdoperRxLength - avrdoperRxPosition;
+        if(available <= 0){ /* buffer is empty */
+            avrdoperFillBuffer(fdp);
+            continue;
+        }
+        len = remaining < available ? remaining : available;
+        memcpy(p, avrdoperRxBuffer + avrdoperRxPosition, len);
+        p += len;
+        remaining -= len;
+        avrdoperRxPosition += len;
+    }
+    if(verbose > 3)
+        dumpBlock("Receive", buf, buflen);
+    return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int avrdoper_drain(union filedescriptor *fdp, int display)
+{
+    do{
+        avrdoperFillBuffer(fdp);
+    }while(avrdoperRxLength > 0);
+    return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int avrdoper_set_dtr_rts(union filedescriptor *fdp, int is_on)
+{
+	fprintf(stderr, "%s: AVR-Doper doesn't support DTR/RTS setting\n", progname);
+    return -1;
+}
+
+/* ------------------------------------------------------------------------- */
+
+struct serial_device avrdoper_serdev =
+{
+  .open = avrdoper_open,
+  .close = avrdoper_close,
+  .send = avrdoper_send,
+  .recv = avrdoper_recv,
+  .drain = avrdoper_drain,
+  .set_dtr_rts = avrdoper_set_dtr_rts,
+  .flags = SERDEV_FL_NONE,
+};
+
+#endif /* defined(HAVE_LIBUSB) || (defined(WIN32NATIVE) && defined(HAVE_LIBHID)) */
diff --git a/avrdude/ser_posix.c b/avrdude/ser_posix.c
new file mode 100644
index 00000000..a37e5290
--- /dev/null
+++ b/avrdude/ser_posix.c
@@ -0,0 +1,501 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2003-2004  Theodore A. Roth  <troth@openavr.org>
+ * Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 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
+ */
+
+/* $Id$ */
+
+/*
+ * Posix serial interface for avrdude.
+ */
+
+#if !defined(WIN32NATIVE)
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+
+#include <fcntl.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "avrdude.h"
+#include "serial.h"
+
+long serial_recv_timeout = 5000; /* ms */
+
+struct baud_mapping {
+  long baud;
+  speed_t speed;
+};
+
+/* There are a lot more baud rates we could handle, but what's the point? */
+
+static struct baud_mapping baud_lookup_table [] = {
+  { 1200,   B1200 },
+  { 2400,   B2400 },
+  { 4800,   B4800 },
+  { 9600,   B9600 },
+  { 19200,  B19200 },
+  { 38400,  B38400 },
+  { 57600,  B57600 },
+  { 115200, B115200 },
+  { 230400, B230400 },
+  { 0,      0 }                 /* Terminator. */
+};
+
+static struct termios original_termios;
+static int saved_original_termios;
+
+static speed_t serial_baud_lookup(long baud)
+{
+  struct baud_mapping *map = baud_lookup_table;
+
+  while (map->baud) {
+    if (map->baud == baud)
+      return map->speed;
+    map++;
+  }
+
+  /*
+   * If a non-standard BAUD rate is used, issue
+   * a warning (if we are verbose) and return the raw rate
+   */
+  if (verbose > 0)
+      fprintf(stderr, "%s: serial_baud_lookup(): Using non-standard baud rate: %ld",
+              progname, baud);
+
+  return baud;
+}
+
+static int ser_setspeed(union filedescriptor *fd, long baud)
+{
+  int rc;
+  struct termios termios;
+  speed_t speed = serial_baud_lookup (baud);
+  
+  if (!isatty(fd->ifd))
+    return -ENOTTY;
+  
+  /*
+   * initialize terminal modes
+   */
+  rc = tcgetattr(fd->ifd, &termios);
+  if (rc < 0) {
+    fprintf(stderr, "%s: ser_setspeed(): tcgetattr() failed",
+            progname);
+    return -errno;
+  }
+
+  /*
+   * copy termios for ser_close if we haven't already
+   */
+  if (! saved_original_termios++) {
+    original_termios = termios;
+  }
+
+  termios.c_iflag = IGNBRK;
+  termios.c_oflag = 0;
+  termios.c_lflag = 0;
+  termios.c_cflag = (CS8 | CREAD | CLOCAL);
+  termios.c_cc[VMIN]  = 1;
+  termios.c_cc[VTIME] = 0;
+
+  cfsetospeed(&termios, speed);
+  cfsetispeed(&termios, speed);
+
+  rc = tcsetattr(fd->ifd, TCSANOW, &termios);
+  if (rc < 0) {
+    fprintf(stderr, "%s: ser_setspeed(): tcsetattr() failed\n",
+            progname);
+    return -errno;
+  }
+
+  /*
+   * Everything is now set up for a local line without modem control
+   * or flow control, so clear O_NONBLOCK again.
+   */
+  rc = fcntl(fd->ifd, F_GETFL, 0);
+  if (rc != -1)
+    fcntl(fd->ifd, F_SETFL, rc & ~O_NONBLOCK);
+
+  return 0;
+}
+
+/*
+ * Given a port description of the form <host>:<port>, open a TCP
+ * connection to the specified destination, which is assumed to be a
+ * terminal/console server with serial parameters configured
+ * appropriately (e. g. 115200-8-N-1 for a STK500.)
+ */
+static void
+net_open(const char *port, union filedescriptor *fdp)
+{
+  char *hstr, *pstr, *end;
+  unsigned int pnum;
+  int fd;
+  struct sockaddr_in sockaddr;
+  struct hostent *hp;
+
+  if ((hstr = strdup(port)) == NULL) {
+    fprintf(stderr, "%s: net_open(): Out of memory!\n",
+	    progname);
+    exit(1);
+  }
+
+  if (((pstr = strchr(hstr, ':')) == NULL) || (pstr == hstr)) {
+    fprintf(stderr, "%s: net_open(): Mangled host:port string \"%s\"\n",
+	    progname, hstr);
+    free(hstr);
+    exit(1);
+  }
+
+  /*
+   * Terminate the host section of the description.
+   */
+  *pstr++ = '\0';
+
+  pnum = strtoul(pstr, &end, 10);
+
+  if ((*pstr == '\0') || (*end != '\0') || (pnum == 0) || (pnum > 65535)) {
+    fprintf(stderr, "%s: net_open(): Bad port number \"%s\"\n",
+	    progname, pstr);
+    free(hstr);
+    exit(1);
+  }
+
+  if ((hp = gethostbyname(hstr)) == NULL) {
+    fprintf(stderr, "%s: net_open(): unknown host \"%s\"\n",
+	    progname, hstr);
+    free(hstr);
+    exit(1);
+  }
+
+  free(hstr);
+
+  if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
+    fprintf(stderr, "%s: net_open(): Cannot open socket: %s\n",
+	    progname, strerror(errno));
+    exit(1);
+  }
+
+  memset(&sockaddr, 0, sizeof(struct sockaddr_in));
+  sockaddr.sin_family = AF_INET;
+  sockaddr.sin_port = htons(pnum);
+  memcpy(&(sockaddr.sin_addr.s_addr), hp->h_addr, sizeof(struct in_addr));
+
+  if (connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) {
+    fprintf(stderr, "%s: net_open(): Connect failed: %s\n",
+	    progname, strerror(errno));
+    exit(1);
+  }
+
+  fdp->ifd = fd;
+}
+
+
+static int ser_set_dtr_rts(union filedescriptor *fdp, int is_on)
+{
+  unsigned int	ctl;
+  int           r;
+
+  r = ioctl(fdp->ifd, TIOCMGET, &ctl);
+  if (r < 0) {
+    perror("ioctl(\"TIOCMGET\")");
+    return -1;
+  }
+
+  if (is_on) {
+    /* Clear DTR and RTS */
+    ctl &= ~(TIOCM_DTR | TIOCM_RTS);
+  }
+  else {
+    /* Set DTR and RTS */
+    ctl |= (TIOCM_DTR | TIOCM_RTS);
+  }
+
+  r = ioctl(fdp->ifd, TIOCMSET, &ctl);
+  if (r < 0) {
+    perror("ioctl(\"TIOCMSET\")");
+    return -1;
+  }
+
+  return 0;
+}
+
+static void ser_open(char * port, long baud, union filedescriptor *fdp)
+{
+  int rc;
+  int fd;
+
+  /*
+   * If the port is of the form "net:<host>:<port>", then
+   * handle it as a TCP connection to a terminal server.
+   */
+  if (strncmp(port, "net:", strlen("net:")) == 0) {
+    net_open(port + strlen("net:"), fdp);
+    return;
+  }
+
+  /*
+   * open the serial port
+   */
+  fd = open(port, O_RDWR | O_NOCTTY | O_NONBLOCK);
+  if (fd < 0) {
+    fprintf(stderr, "%s: ser_open(): can't open device \"%s\": %s\n",
+            progname, port, strerror(errno));
+    exit(1);
+  }
+
+  fdp->ifd = fd;
+
+  /*
+   * set serial line attributes
+   */
+  rc = ser_setspeed(fdp, baud);
+  if (rc) {
+    fprintf(stderr, 
+            "%s: ser_open(): can't set attributes for device \"%s\": %s\n",
+            progname, port, strerror(-rc));
+    exit(1);
+  }
+}
+
+
+static void ser_close(union filedescriptor *fd)
+{
+  /*
+   * restore original termios settings from ser_open
+   */
+  if (saved_original_termios) {
+    int rc = tcsetattr(fd->ifd, TCSANOW | TCSADRAIN, &original_termios);
+    if (rc) {
+      fprintf(stderr, 
+              "%s: ser_close(): can't reset attributes for device: %s\n",
+              progname, strerror(errno));
+    }
+    saved_original_termios = 0;
+  }
+
+  close(fd->ifd);
+}
+
+
+static int ser_send(union filedescriptor *fd, unsigned char * buf, size_t buflen)
+{
+  struct timeval timeout, to2;
+  int rc;
+  unsigned char * p = buf;
+  size_t len = buflen;
+
+  if (!len)
+    return 0;
+
+  if (verbose > 3)
+  {
+      fprintf(stderr, "%s: Send: ", progname);
+
+      while (buflen) {
+        unsigned char c = *buf;
+        if (isprint(c)) {
+          fprintf(stderr, "%c ", c);
+        }
+        else {
+          fprintf(stderr, ". ");
+        }
+        fprintf(stderr, "[%02x] ", c);
+
+        buf++;
+        buflen--;
+      }
+
+      fprintf(stderr, "\n");
+  }
+
+  timeout.tv_sec = 0;
+  timeout.tv_usec = 500000;
+  to2 = timeout;
+
+  while (len) {
+    rc = write(fd->ifd, p, (len > 1024) ? 1024 : len);
+    if (rc < 0) {
+      fprintf(stderr, "%s: ser_send(): write error: %s\n",
+              progname, strerror(errno));
+      exit(1);
+    }
+    p += rc;
+    len -= rc;
+  }
+
+  return 0;
+}
+
+
+static int ser_recv(union filedescriptor *fd, unsigned char * buf, size_t buflen)
+{
+  struct timeval timeout, to2;
+  fd_set rfds;
+  int nfds;
+  int rc;
+  unsigned char * p = buf;
+  size_t len = 0;
+
+  timeout.tv_sec  = serial_recv_timeout / 1000L;
+  timeout.tv_usec = (serial_recv_timeout % 1000L) * 1000;
+  to2 = timeout;
+
+  while (len < buflen) {
+  reselect:
+    FD_ZERO(&rfds);
+    FD_SET(fd->ifd, &rfds);
+
+    nfds = select(fd->ifd + 1, &rfds, NULL, NULL, &to2);
+    if (nfds == 0) {
+      if (verbose > 1)
+	fprintf(stderr,
+		"%s: ser_recv(): programmer is not responding\n",
+		progname);
+      return -1;
+    }
+    else if (nfds == -1) {
+      if (errno == EINTR || errno == EAGAIN) {
+	fprintf(stderr,
+		"%s: ser_recv(): programmer is not responding,reselecting\n",
+		progname);
+        goto reselect;
+      }
+      else {
+        fprintf(stderr, "%s: ser_recv(): select(): %s\n",
+                progname, strerror(errno));
+        exit(1);
+      }
+    }
+
+    rc = read(fd->ifd, p, (buflen - len > 1024) ? 1024 : buflen - len);
+    if (rc < 0) {
+      fprintf(stderr, "%s: ser_recv(): read error: %s\n",
+              progname, strerror(errno));
+      exit(1);
+    }
+    p += rc;
+    len += rc;
+  }
+
+  p = buf;
+
+  if (verbose > 3)
+  {
+      fprintf(stderr, "%s: Recv: ", progname);
+
+      while (len) {
+        unsigned char c = *p;
+        if (isprint(c)) {
+          fprintf(stderr, "%c ", c);
+        }
+        else {
+          fprintf(stderr, ". ");
+        }
+        fprintf(stderr, "[%02x] ", c);
+
+        p++;
+        len--;
+      }
+      fprintf(stderr, "\n");
+  }
+
+  return 0;
+}
+
+
+static int ser_drain(union filedescriptor *fd, int display)
+{
+  struct timeval timeout;
+  fd_set rfds;
+  int nfds;
+  int rc;
+  unsigned char buf;
+
+  timeout.tv_sec = 0;
+  timeout.tv_usec = 250000;
+
+  if (display) {
+    fprintf(stderr, "drain>");
+  }
+
+  while (1) {
+    FD_ZERO(&rfds);
+    FD_SET(fd->ifd, &rfds);
+
+  reselect:
+    nfds = select(fd->ifd + 1, &rfds, NULL, NULL, &timeout);
+    if (nfds == 0) {
+      if (display) {
+        fprintf(stderr, "<drain\n");
+      }
+      
+      break;
+    }
+    else if (nfds == -1) {
+      if (errno == EINTR) {
+        goto reselect;
+      }
+      else {
+        fprintf(stderr, "%s: ser_drain(): select(): %s\n",
+                progname, strerror(errno));
+        exit(1);
+      }
+    }
+
+    rc = read(fd->ifd, &buf, 1);
+    if (rc < 0) {
+      fprintf(stderr, "%s: ser_drain(): read error: %s\n",
+              progname, strerror(errno));
+      exit(1);
+    }
+    if (display) {
+      fprintf(stderr, "%02x ", buf);
+    }
+  }
+
+  return 0;
+}
+
+struct serial_device serial_serdev =
+{
+  .open = ser_open,
+  .setspeed = ser_setspeed,
+  .close = ser_close,
+  .send = ser_send,
+  .recv = ser_recv,
+  .drain = ser_drain,
+  .set_dtr_rts = ser_set_dtr_rts,
+  .flags = SERDEV_FL_CANSETSPEED,
+};
+
+struct serial_device *serdev = &serial_serdev;
+
+#endif  /* WIN32NATIVE */
diff --git a/avrdude/ser_win32.c b/avrdude/ser_win32.c
new file mode 100644
index 00000000..9d8bf7aa
--- /dev/null
+++ b/avrdude/ser_win32.c
@@ -0,0 +1,407 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2003, 2004  Martin J. Thomas  <mthomas@rhrk.uni-kl.de>
+ * Copyright (C) 2006  Joerg Wunsch <j@uriah.heep.sax.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 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
+ */
+
+/* $Id$ */
+
+/*
+ * Native Win32 serial interface for avrdude.
+ */
+
+#include "avrdude.h"
+
+#if defined(WIN32NATIVE)
+
+#include <windows.h>
+#include <stdio.h>
+#include <ctype.h>   /* for isprint */
+
+#include "serial.h"
+
+long serial_recv_timeout = 5000; /* ms */
+
+#define W32SERBUFSIZE 1024
+
+struct baud_mapping {
+  long baud;
+  DWORD speed;
+};
+
+/* HANDLE hComPort=INVALID_HANDLE_VALUE; */
+
+static struct baud_mapping baud_lookup_table [] = {
+  { 1200,   CBR_1200 },
+  { 2400,   CBR_2400 },
+  { 4800,   CBR_4800 },
+  { 9600,   CBR_9600 },
+  { 19200,  CBR_19200 },
+  { 38400,  CBR_38400 },
+  { 57600,  CBR_57600 },
+  { 115200, CBR_115200 },
+  { 0,      0 }                 /* Terminator. */
+};
+
+static DWORD serial_baud_lookup(long baud)
+{
+  struct baud_mapping *map = baud_lookup_table;
+
+  while (map->baud) {
+    if (map->baud == baud)
+      return map->speed;
+    map++;
+  }
+
+  /*
+   * If a non-standard BAUD rate is used, issue
+   * a warning (if we are verbose) and return the raw rate
+   */
+  if (verbose > 0)
+      fprintf(stderr, "%s: serial_baud_lookup(): Using non-standard baud rate: %ld",
+              progname, baud);
+
+  return baud;
+}
+
+
+static BOOL serial_w32SetTimeOut(HANDLE hComPort, DWORD timeout) // in ms
+{
+	COMMTIMEOUTS ctmo;
+	ZeroMemory (&ctmo, sizeof(COMMTIMEOUTS));
+	ctmo.ReadIntervalTimeout = timeout;
+	ctmo.ReadTotalTimeoutMultiplier = timeout;
+	ctmo.ReadTotalTimeoutConstant = timeout;
+
+	return SetCommTimeouts(hComPort, &ctmo);
+}
+
+static int ser_setspeed(union filedescriptor *fd, long baud)
+{
+	DCB dcb;
+	HANDLE hComPort = (HANDLE)fd->pfd;
+
+	ZeroMemory (&dcb, sizeof(DCB));
+	dcb.DCBlength = sizeof(DCB);
+	dcb.BaudRate = serial_baud_lookup (baud);
+	dcb.fBinary = 1;
+	dcb.fDtrControl = DTR_CONTROL_DISABLE;
+	dcb.fRtsControl = RTS_CONTROL_DISABLE;
+	dcb.ByteSize = 8;
+	dcb.Parity = NOPARITY;
+	dcb.StopBits = ONESTOPBIT;
+
+	if (!SetCommState(hComPort, &dcb))
+		return -1;
+
+	return 0;
+}
+
+
+static void ser_open(char * port, long baud, union filedescriptor *fdp)
+{
+	LPVOID lpMsgBuf;
+	HANDLE hComPort=INVALID_HANDLE_VALUE;
+	char *newname = 0;
+
+	/*
+	 * If the port is of the form "net:<host>:<port>", then
+	 * handle it as a TCP connection to a terminal server.
+	 *
+	 * This is curently not implemented for Win32.
+	 */
+	if (strncmp(port, "net:", strlen("net:")) == 0) {
+		fprintf(stderr,
+			"%s: ser_open(): network connects are currently not"
+			"implemented for Win32 environments\n",
+			progname);
+		exit(1);
+	}
+
+	if (strncasecmp(port, "com", strlen("com")) == 0) {
+
+	    // prepend "\\\\.\\" to name, required for port # >= 10
+	    newname = malloc(strlen("\\\\.\\") + strlen(port) + 1);
+
+	    if (newname == 0) {
+		fprintf(stderr,
+			"%s: ser_open(): out of memory\n",
+			progname);
+		exit(1);
+	    }
+	    strcpy(newname, "\\\\.\\");
+	    strcat(newname, port);
+
+	    port = newname;
+	}
+
+	hComPort = CreateFile(port, GENERIC_READ | GENERIC_WRITE, 0, NULL,
+		OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+	if (hComPort == INVALID_HANDLE_VALUE) {
+		FormatMessage( 
+			FORMAT_MESSAGE_ALLOCATE_BUFFER | 
+			FORMAT_MESSAGE_FROM_SYSTEM | 
+			FORMAT_MESSAGE_IGNORE_INSERTS,
+			NULL,
+			GetLastError(),
+			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+			(LPTSTR) &lpMsgBuf,
+			0,
+			NULL);
+		fprintf(stderr, "%s: ser_open(): can't open device \"%s\": %s\n",
+				progname, port, (char*)lpMsgBuf);
+		LocalFree( lpMsgBuf );
+		exit(1);
+	}
+
+	if (!SetupComm(hComPort, W32SERBUFSIZE, W32SERBUFSIZE))
+	{
+		CloseHandle(hComPort);
+		fprintf(stderr, "%s: ser_open(): can't set buffers for \"%s\"\n",
+				progname, port);
+		exit(1);
+	}
+
+        fdp->pfd = (void *)hComPort;
+	if (ser_setspeed(fdp, baud) != 0)
+	{
+		CloseHandle(hComPort);
+		fprintf(stderr, "%s: ser_open(): can't set com-state for \"%s\"\n",
+				progname, port);
+		exit(1);
+	}
+
+	if (!serial_w32SetTimeOut(hComPort,0))
+	{
+		CloseHandle(hComPort);
+		fprintf(stderr, "%s: ser_open(): can't set initial timeout for \"%s\"\n",
+				progname, port);
+		exit(1);
+	}
+
+	if (newname != 0) {
+	    free(newname);
+	}
+}
+
+
+static void ser_close(union filedescriptor *fd)
+{
+	HANDLE hComPort=(HANDLE)fd->pfd;
+	if (hComPort != INVALID_HANDLE_VALUE)
+		CloseHandle (hComPort);
+
+	hComPort = INVALID_HANDLE_VALUE;
+}
+
+static int ser_set_dtr_rts(union filedescriptor *fd, int is_on)
+{
+	HANDLE hComPort=(HANDLE)fd->pfd;
+
+	if (is_on) {
+		EscapeCommFunction(hComPort, SETDTR);
+		EscapeCommFunction(hComPort, SETRTS);
+	} else {
+		EscapeCommFunction(hComPort, CLRDTR);
+		EscapeCommFunction(hComPort, CLRRTS);
+	}
+	return 0;
+}
+
+
+static int ser_send(union filedescriptor *fd, unsigned char * buf, size_t buflen)
+{
+	size_t len = buflen;
+	unsigned char c='\0';
+	DWORD written;
+        unsigned char * b = buf;
+
+	HANDLE hComPort=(HANDLE)fd->pfd;
+
+	if (hComPort == INVALID_HANDLE_VALUE) {
+		fprintf(stderr, "%s: ser_send(): port not open\n",
+              progname); 
+		exit(1);
+	}
+
+	if (!len)
+  return 0;
+
+	if (verbose > 3)
+	{
+		fprintf(stderr, "%s: Send: ", progname);
+
+		while (len) {
+			c = *b;
+			if (isprint(c)) {
+				fprintf(stderr, "%c ", c);
+			}
+			else {
+				fprintf(stderr, ". ");
+			}
+			fprintf(stderr, "[%02x] ", c);
+			b++;
+			len--;
+		}
+      fprintf(stderr, "\n");
+	}
+	
+	serial_w32SetTimeOut(hComPort,500);
+
+	if (!WriteFile (hComPort, buf, buflen, &written, NULL)) {
+		fprintf(stderr, "%s: ser_send(): write error: %s\n",
+              progname, "sorry no info avail"); // TODO
+		exit(1);
+	}
+
+	if (written != buflen) {
+		fprintf(stderr, "%s: ser_send(): size/send mismatch\n",
+              progname); 
+		exit(1);
+	}
+
+	return 0;
+}
+
+
+static int ser_recv(union filedescriptor *fd, unsigned char * buf, size_t buflen)
+{
+	unsigned char c;
+	unsigned char * p = buf;
+	DWORD read;
+
+	HANDLE hComPort=(HANDLE)fd->pfd;
+	
+	if (hComPort == INVALID_HANDLE_VALUE) {
+		fprintf(stderr, "%s: ser_read(): port not open\n",
+              progname); 
+		exit(1);
+	}
+	
+	serial_w32SetTimeOut(hComPort, serial_recv_timeout);
+	
+	if (!ReadFile(hComPort, buf, buflen, &read, NULL)) {
+		LPVOID lpMsgBuf;
+		FormatMessage( 
+			FORMAT_MESSAGE_ALLOCATE_BUFFER | 
+			FORMAT_MESSAGE_FROM_SYSTEM | 
+			FORMAT_MESSAGE_IGNORE_INSERTS,
+			NULL,
+			GetLastError(),
+			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+			(LPTSTR) &lpMsgBuf,
+			0,
+			NULL 	);
+		fprintf(stderr, "%s: ser_recv(): read error: %s\n",
+			      progname, (char*)lpMsgBuf);
+		LocalFree( lpMsgBuf );
+		exit(1);
+	}
+
+	p = buf;
+
+	if (verbose > 3)
+	{
+		fprintf(stderr, "%s: Recv: ", progname);
+
+		while (read) {
+			c = *p;
+			if (isprint(c)) {
+				fprintf(stderr, "%c ", c);
+			}
+			else {
+				fprintf(stderr, ". ");
+			}
+			fprintf(stderr, "[%02x] ", c);
+
+			p++;
+			read--;
+		}
+		fprintf(stderr, "\n");
+	}
+  return 0;
+}
+
+
+static int ser_drain(union filedescriptor *fd, int display)
+{
+	// int rc;
+	unsigned char buf[10];
+	BOOL readres;
+	DWORD read;
+
+	HANDLE hComPort=(HANDLE)fd->pfd;
+
+  	if (hComPort == INVALID_HANDLE_VALUE) {
+		fprintf(stderr, "%s: ser_drain(): port not open\n",
+              progname); 
+		exit(1);
+	}
+
+	serial_w32SetTimeOut(hComPort,250);
+  
+	if (display) {
+		fprintf(stderr, "drain>");
+	}
+
+	while (1) {
+		readres=ReadFile(hComPort, buf, 1, &read, NULL);
+		if (!readres) {
+			LPVOID lpMsgBuf;
+			FormatMessage( 
+				FORMAT_MESSAGE_ALLOCATE_BUFFER | 
+				FORMAT_MESSAGE_FROM_SYSTEM | 
+				FORMAT_MESSAGE_IGNORE_INSERTS,
+				NULL,
+				GetLastError(),
+				MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+				(LPTSTR) &lpMsgBuf,
+				0,
+				NULL 	);
+			fprintf(stderr, "%s: ser_drain(): read error: %s\n",
+					  progname, (char*)lpMsgBuf);
+			LocalFree( lpMsgBuf );
+			exit(1);
+		}
+
+		if (read) { // data avail
+			if (display) fprintf(stderr, "%02x ", buf[0]);
+		}
+		else { // no more data
+			if (display) fprintf(stderr, "<drain\n");
+			break;
+		}
+	} // while
+  return 0;
+}
+
+struct serial_device serial_serdev =
+{
+  .open = ser_open,
+  .setspeed = ser_setspeed,
+  .close = ser_close,
+  .send = ser_send,
+  .recv = ser_recv,
+  .drain = ser_drain,
+  .set_dtr_rts = ser_set_dtr_rts,
+  .flags = SERDEV_FL_CANSETSPEED,
+};
+
+struct serial_device *serdev = &serial_serdev;
+
+#endif /* WIN32NATIVE */
diff --git a/avrdude/serbb.h b/avrdude/serbb.h
new file mode 100644
index 00000000..f466569c
--- /dev/null
+++ b/avrdude/serbb.h
@@ -0,0 +1,37 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2000, 2001, 2002, 2003  Brian S. Dean <bsd@bsdhome.com>
+ * Copyright (C) 2005 Michael Holzt <kju-avr@fqdn.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+/* $Id$ */
+
+#ifndef serbb_h
+#define serbb_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void serbb_initpgm        (PROGRAMMER * pgm);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/avrdude/serbb_posix.c b/avrdude/serbb_posix.c
new file mode 100644
index 00000000..5f886c42
--- /dev/null
+++ b/avrdude/serbb_posix.c
@@ -0,0 +1,312 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2000, 2001, 2002, 2003  Brian S. Dean <bsd@bsdhome.com>
+ * Copyright (C) 2005 Michael Holzt <kju-avr@fqdn.org>
+ * Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 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
+ */
+/* $Id$ */
+
+/*
+ * Posix serial bitbanging interface for avrdude.
+ */
+
+#if !defined(WIN32NATIVE)
+
+#include "ac_cfg.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+
+#include "avrdude.h"
+#include "avr.h"
+#include "pindefs.h"
+#include "pgm.h"
+#include "bitbang.h"
+
+#undef DEBUG
+
+static struct termios oldmode;
+
+/*
+  serial port/pin mapping
+
+  1	cd	<-
+  2	(rxd)	<-
+  3	txd	->
+  4	dtr	->
+  5	GND
+  6	dsr	<-
+  7	rts	->
+  8	cts	<-
+  9	ri	<-
+*/
+
+#define DB9PINS 9
+
+static int serregbits[DB9PINS + 1] =
+{ 0, TIOCM_CD, 0, 0, TIOCM_DTR, 0, TIOCM_DSR, TIOCM_RTS, TIOCM_CTS, TIOCM_RI };
+
+#ifdef DEBUG
+static char *serpins[DB9PINS + 1] =
+  { "NONE", "CD", "RXD", "TXD", "DTR", "GND", "DSR", "RTS", "CTS", "RI" };
+#endif
+
+static int serbb_setpin(PROGRAMMER * pgm, int pin, int value)
+{
+  unsigned int	ctl;
+  int           r;
+
+  if (pin & PIN_INVERSE)
+  {
+    value  = !value;
+    pin   &= PIN_MASK;
+  }
+
+  if ( pin < 1 || pin > DB9PINS )
+    return -1;
+
+#ifdef DEBUG
+  printf("%s to %d\n",serpins[pin],value);
+#endif
+
+  switch ( pin )
+  {
+    case 3:  /* txd */
+	     r = ioctl(pgm->fd.ifd, value ? TIOCSBRK : TIOCCBRK, 0);
+	     if (r < 0) {
+	       perror("ioctl(\"TIOCxBRK\")");
+	       return -1;
+	     }
+             break;
+
+    case 4:  /* dtr */
+    case 7:  /* rts */
+             r = ioctl(pgm->fd.ifd, TIOCMGET, &ctl);
+ 	     if (r < 0) {
+	       perror("ioctl(\"TIOCMGET\")");
+	       return -1;
+ 	     }
+             if ( value )
+               ctl |= serregbits[pin];
+             else
+               ctl &= ~(serregbits[pin]);
+	     r = ioctl(pgm->fd.ifd, TIOCMSET, &ctl);
+ 	     if (r < 0) {
+	       perror("ioctl(\"TIOCMSET\")");
+	       return -1;
+ 	     }
+             break;
+
+    default: /* impossible */
+             return -1;
+  }
+
+  if (pgm->ispdelay > 1)
+    bitbang_delay(pgm->ispdelay);
+
+  return 0;
+}
+
+static int serbb_getpin(PROGRAMMER * pgm, int pin)
+{
+  unsigned int	ctl;
+  unsigned char invert;
+  int           r;
+
+  if (pin & PIN_INVERSE)
+  {
+    invert = 1;
+    pin   &= PIN_MASK;
+  } else
+    invert = 0;
+
+  if ( pin < 1 || pin > DB9PINS )
+    return(-1);
+
+  switch ( pin )
+  {
+    case 2:  /* rxd, currently not implemented, FIXME */
+             return(-1);
+
+    case 1:  /* cd  */
+    case 6:  /* dsr */
+    case 8:  /* cts */
+    case 9:  /* ri  */
+             r = ioctl(pgm->fd.ifd, TIOCMGET, &ctl);
+ 	     if (r < 0) {
+	       perror("ioctl(\"TIOCMGET\")");
+	       return -1;
+ 	     }
+             if ( !invert )
+             {
+#ifdef DEBUG
+               printf("%s is %d\n",serpins[pin],(ctl & serregbits[pin]) ? 1 : 0 );
+#endif
+               return ( (ctl & serregbits[pin]) ? 1 : 0 );
+             }
+             else
+             {
+#ifdef DEBUG
+               printf("%s is %d (~)\n",serpins[pin],(ctl & serregbits[pin]) ? 0 : 1 );
+#endif
+               return (( ctl & serregbits[pin]) ? 0 : 1 );
+             }
+
+    default: /* impossible */
+             return(-1);
+  }
+}
+
+static int serbb_highpulsepin(PROGRAMMER * pgm, int pin)
+{
+  if ( (pin & PIN_MASK) < 1 || (pin & PIN_MASK) > DB9PINS )
+    return -1;
+
+  serbb_setpin(pgm, pin, 1);
+  serbb_setpin(pgm, pin, 0);
+
+  return 0;
+}
+
+
+
+static void serbb_display(PROGRAMMER *pgm, const char *p)
+{
+  /* MAYBE */
+}
+
+static void serbb_enable(PROGRAMMER *pgm)
+{
+  /* nothing */
+}
+
+static void serbb_disable(PROGRAMMER *pgm)
+{
+  /* nothing */
+}
+
+static void serbb_powerup(PROGRAMMER *pgm)
+{
+  /* nothing */
+}
+
+static void serbb_powerdown(PROGRAMMER *pgm)
+{
+  /* nothing */
+}
+
+static int serbb_open(PROGRAMMER *pgm, char *port)
+{
+  struct termios mode;
+  int flags;
+  int r;
+
+  bitbang_check_prerequisites(pgm);
+
+  /* adapted from uisp code */
+
+  pgm->fd.ifd = open(port, O_RDWR | O_NOCTTY | O_NONBLOCK);
+
+  if (pgm->fd.ifd < 0) {
+    perror(port);
+    return(-1);
+  }
+
+  r = tcgetattr(pgm->fd.ifd, &mode);
+  if (r < 0) {
+    fprintf(stderr, "%s: ", port);
+    perror("tcgetattr");
+    return(-1);
+  }
+  oldmode = mode;
+
+  mode.c_iflag = IGNBRK | IGNPAR;
+  mode.c_oflag = 0;
+  mode.c_cflag = CLOCAL | CREAD | CS8 | B9600;
+  mode.c_cc [VMIN] = 1;
+  mode.c_cc [VTIME] = 0;
+
+  r = tcsetattr(pgm->fd.ifd, TCSANOW, &mode);
+  if (r < 0) {
+      fprintf(stderr, "%s: ", port);
+      perror("tcsetattr");
+      return(-1);
+  }
+
+  /* Clear O_NONBLOCK flag.  */
+  flags = fcntl(pgm->fd.ifd, F_GETFL, 0);
+  if (flags == -1)
+    {
+      fprintf(stderr, "%s: Can not get flags: %s\n",
+	      progname, strerror(errno));
+      return(-1);
+    }
+  flags &= ~O_NONBLOCK;
+  if (fcntl(pgm->fd.ifd, F_SETFL, flags) == -1)
+    {
+      fprintf(stderr, "%s: Can not clear nonblock flag: %s\n",
+	      progname, strerror(errno));
+      return(-1);
+    }
+
+  return(0);
+}
+
+static void serbb_close(PROGRAMMER *pgm)
+{
+  if (pgm->fd.ifd != -1)
+  {
+	  (void)tcsetattr(pgm->fd.ifd, TCSANOW, &oldmode);
+	  pgm->setpin(pgm, pgm->pinno[PIN_AVR_RESET], 1);
+	  close(pgm->fd.ifd);
+  }
+  return;
+}
+
+void serbb_initpgm(PROGRAMMER *pgm)
+{
+  strcpy(pgm->type, "SERBB");
+
+  pgm->rdy_led        = bitbang_rdy_led;
+  pgm->err_led        = bitbang_err_led;
+  pgm->pgm_led        = bitbang_pgm_led;
+  pgm->vfy_led        = bitbang_vfy_led;
+  pgm->initialize     = bitbang_initialize;
+  pgm->display        = serbb_display;
+  pgm->enable         = serbb_enable;
+  pgm->disable        = serbb_disable;
+  pgm->powerup        = serbb_powerup;
+  pgm->powerdown      = serbb_powerdown;
+  pgm->program_enable = bitbang_program_enable;
+  pgm->chip_erase     = bitbang_chip_erase;
+  pgm->cmd            = bitbang_cmd;
+  pgm->open           = serbb_open;
+  pgm->close          = serbb_close;
+  pgm->setpin         = serbb_setpin;
+  pgm->getpin         = serbb_getpin;
+  pgm->highpulsepin   = serbb_highpulsepin;
+  pgm->read_byte      = avr_read_byte_default;
+  pgm->write_byte     = avr_write_byte_default;
+}
+
+#endif  /* WIN32NATIVE */
diff --git a/avrdude/serbb_win32.c b/avrdude/serbb_win32.c
new file mode 100644
index 00000000..62c70405
--- /dev/null
+++ b/avrdude/serbb_win32.c
@@ -0,0 +1,373 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2003, 2004  Martin J. Thomas  <mthomas@rhrk.uni-kl.de>
+ * Copyright (C) 2005 Michael Holzt <kju-avr@fqdn.org>
+ * Copyright (C) 2005, 2006 Joerg Wunsch <j@uriah.heep.sax.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 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
+ */
+/* $Id$ */
+
+/*
+ * Win32 serial bitbanging interface for avrdude.
+ */
+
+#include "avrdude.h"
+
+#if defined(WIN32NATIVE)
+
+
+#include "ac_cfg.h"
+
+#include <windows.h>
+#include <stdio.h>
+
+#include "avr.h"
+#include "pindefs.h"
+#include "pgm.h"
+#include "bitbang.h"
+
+/* cached status lines */
+static int dtr, rts, txd;
+
+#define W32SERBUFSIZE 1024
+
+/*
+  serial port/pin mapping
+
+  1	cd	<-
+  2	(rxd)	<-
+  3	txd	->
+  4	dtr	->
+  5	GND
+  6	dsr	<-
+  7	rts	->
+  8	cts	<-
+  9	ri	<-
+*/
+
+#define DB9PINS 9
+
+static int serbb_setpin(PROGRAMMER * pgm, int pin, int value)
+{
+	HANDLE hComPort = (HANDLE)pgm->fd.pfd;
+        LPVOID lpMsgBuf;
+        DWORD dwFunc;
+        const char *name;
+
+        if (pin & PIN_INVERSE)
+        {
+                value = !value;
+                pin &= PIN_MASK;
+        }
+
+        if (pin < 1 || pin > DB9PINS)
+                return -1;
+
+        switch (pin)
+        {
+        case 3:  /* txd */
+                dwFunc = value? SETBREAK: CLRBREAK;
+                name = value? "SETBREAK": "CLRBREAK";
+                txd = value;
+                break;
+
+        case 4:  /* dtr */
+                dwFunc = value? SETDTR: CLRDTR;
+                name = value? "SETDTR": "CLRDTR";
+                dtr = value;
+                break;
+
+        case 7:  /* rts */
+                dwFunc = value? SETRTS: CLRRTS;
+                name = value? "SETRTS": "CLRRTS";
+                break;
+
+        default:
+                if (verbose)
+                        fprintf(stderr,
+                                "%s: serbb_setpin(): unknown pin %d\n",
+                                progname, pin + 1);
+                return -1;
+        }
+        if (verbose > 4)
+                fprintf(stderr,
+                        "%s: serbb_setpin(): EscapeCommFunction(%s)\n",
+                        progname, name);
+        if (!EscapeCommFunction(hComPort, dwFunc))
+        {
+                FormatMessage(
+                        FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                        FORMAT_MESSAGE_FROM_SYSTEM |
+                        FORMAT_MESSAGE_IGNORE_INSERTS,
+                        NULL,
+                        GetLastError(),
+                        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+                        (LPTSTR) &lpMsgBuf,
+                        0,
+                        NULL);
+                fprintf(stderr,
+                        "%s: serbb_setpin(): SetCommState() failed: %s\n",
+                        progname, (char *)lpMsgBuf);
+                CloseHandle(hComPort);
+                LocalFree(lpMsgBuf);
+                exit(1);
+        }
+
+	if (pgm->ispdelay > 1)
+	  bitbang_delay(pgm->ispdelay);
+
+        return 0;
+}
+
+static int serbb_getpin(PROGRAMMER * pgm, int pin)
+{
+	HANDLE hComPort = (HANDLE)pgm->fd.pfd;
+        LPVOID lpMsgBuf;
+        int invert, rv;
+        const char *name;
+        DWORD modemstate;
+
+        if (pin & PIN_INVERSE)
+        {
+                invert = 1;
+                pin &= PIN_MASK;
+        } else
+                invert = 0;
+
+        if (pin < 1 || pin > DB9PINS)
+                return -1;
+
+        if (pin == 1 /* cd */ || pin == 6 /* dsr */ || pin == 8 /* cts */)
+        {
+                if (!GetCommModemStatus(hComPort, &modemstate))
+                {
+                        FormatMessage(
+                                FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                                FORMAT_MESSAGE_FROM_SYSTEM |
+                                FORMAT_MESSAGE_IGNORE_INSERTS,
+                                NULL,
+                                GetLastError(),
+                                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+                                (LPTSTR) &lpMsgBuf,
+                                0,
+                                NULL);
+                        fprintf(stderr,
+                                "%s: serbb_setpin(): GetCommModemStatus() failed: %s\n",
+                                progname, (char *)lpMsgBuf);
+                        CloseHandle(hComPort);
+                        LocalFree(lpMsgBuf);
+                        exit(1);
+                }
+                if (verbose > 4)
+                        fprintf(stderr,
+                                "%s: serbb_getpin(): GetCommState() => 0x%lx\n",
+                                progname, modemstate);
+                switch (pin)
+                {
+                case 1:
+                        modemstate &= MS_RLSD_ON;
+                        break;
+                case 6:
+                        modemstate &= MS_DSR_ON;
+                        break;
+                case 8:
+                        modemstate &= MS_CTS_ON;
+                        break;
+                }
+                rv = modemstate != 0;
+                if (invert)
+                        rv = !rv;
+
+                return rv;
+        }
+
+        switch (pin)
+        {
+        case 3: /* txd */
+                rv = txd;
+                name = "TXD";
+                break;
+        case 4: /* dtr */
+                rv = dtr;
+                name = "DTR";
+                break;
+        case 7: /* rts */
+                rv = rts;
+                name = "RTS";
+                break;
+        default:
+                if (verbose)
+                        fprintf(stderr,
+                                "%s: serbb_getpin(): unknown pin %d\n",
+                                progname, pin + 1);
+                return -1;
+        }
+        if (verbose > 4)
+                fprintf(stderr,
+                        "%s: serbb_getpin(): return cached state for %s\n",
+                        progname, name);
+        if (invert)
+                rv = !rv;
+
+        return rv;
+}
+
+static int serbb_highpulsepin(PROGRAMMER * pgm, int pin)
+{
+        if ( (pin & PIN_MASK) < 1 || (pin & PIN_MASK) > DB9PINS )
+          return -1;
+
+        serbb_setpin(pgm, pin, 1);
+        serbb_setpin(pgm, pin, 0);
+
+        return 0;
+}
+
+
+static void serbb_display(PROGRAMMER *pgm, const char *p)
+{
+  /* MAYBE */
+}
+
+static void serbb_enable(PROGRAMMER *pgm)
+{
+  /* nothing */
+}
+
+static void serbb_disable(PROGRAMMER *pgm)
+{
+  /* nothing */
+}
+
+static void serbb_powerup(PROGRAMMER *pgm)
+{
+  /* nothing */
+}
+
+static void serbb_powerdown(PROGRAMMER *pgm)
+{
+  /* nothing */
+}
+
+static int serbb_open(PROGRAMMER *pgm, char *port)
+{
+        DCB dcb;
+	LPVOID lpMsgBuf;
+	HANDLE hComPort = INVALID_HANDLE_VALUE;
+
+	bitbang_check_prerequisites(pgm);
+
+	hComPort = CreateFile(port, GENERIC_READ | GENERIC_WRITE, 0, NULL,
+                              OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+
+	if (hComPort == INVALID_HANDLE_VALUE) {
+		FormatMessage(
+			FORMAT_MESSAGE_ALLOCATE_BUFFER |
+			FORMAT_MESSAGE_FROM_SYSTEM |
+			FORMAT_MESSAGE_IGNORE_INSERTS,
+			NULL,
+			GetLastError(),
+			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+			(LPTSTR) &lpMsgBuf,
+			0,
+			NULL);
+		fprintf(stderr, "%s: ser_open(): can't open device \"%s\": %s\n",
+                        progname, port, (char*)lpMsgBuf);
+		LocalFree(lpMsgBuf);
+                return -1;
+	}
+
+	if (!SetupComm(hComPort, W32SERBUFSIZE, W32SERBUFSIZE))
+	{
+		CloseHandle(hComPort);
+		fprintf(stderr, "%s: ser_open(): can't set buffers for \"%s\"\n",
+                        progname, port);
+                return -1;
+	}
+
+
+	ZeroMemory(&dcb, sizeof(DCB));
+	dcb.DCBlength = sizeof(DCB);
+	dcb.BaudRate = CBR_9600;
+	dcb.fBinary = 1;
+	dcb.fDtrControl = DTR_CONTROL_DISABLE;
+	dcb.fRtsControl = RTS_CONTROL_DISABLE;
+	dcb.ByteSize = 8;
+	dcb.Parity = NOPARITY;
+	dcb.StopBits = ONESTOPBIT;
+
+	if (!SetCommState(hComPort, &dcb))
+	{
+		CloseHandle(hComPort);
+		fprintf(stderr, "%s: ser_open(): can't set com-state for \"%s\"\n",
+                        progname, port);
+                return -1;
+	}
+        if (verbose > 2)
+                fprintf(stderr,
+                        "%s: ser_open(): opened comm port \"%s\", handle 0x%x\n",
+                        progname, port, (int)hComPort);
+
+        pgm->fd.pfd = (void *)hComPort;
+
+        dtr = rts = txd = 0;
+
+        return 0;
+}
+
+static void serbb_close(PROGRAMMER *pgm)
+{
+	HANDLE hComPort=(HANDLE)pgm->fd.pfd;
+	if (hComPort != INVALID_HANDLE_VALUE)
+	{
+		pgm->setpin(pgm, pgm->pinno[PIN_AVR_RESET], 1);
+		CloseHandle (hComPort);
+	}
+        if (verbose > 2)
+                fprintf(stderr,
+                        "%s: ser_close(): closed comm port handle 0x%x\n",
+                        progname, (int)hComPort);
+
+	hComPort = INVALID_HANDLE_VALUE;
+}
+
+void serbb_initpgm(PROGRAMMER *pgm)
+{
+  strcpy(pgm->type, "SERBB");
+
+  pgm->rdy_led        = bitbang_rdy_led;
+  pgm->err_led        = bitbang_err_led;
+  pgm->pgm_led        = bitbang_pgm_led;
+  pgm->vfy_led        = bitbang_vfy_led;
+  pgm->initialize     = bitbang_initialize;
+  pgm->display        = serbb_display;
+  pgm->enable         = serbb_enable;
+  pgm->disable        = serbb_disable;
+  pgm->powerup        = serbb_powerup;
+  pgm->powerdown      = serbb_powerdown;
+  pgm->program_enable = bitbang_program_enable;
+  pgm->chip_erase     = bitbang_chip_erase;
+  pgm->cmd            = bitbang_cmd;
+  pgm->open           = serbb_open;
+  pgm->close          = serbb_close;
+  pgm->setpin         = serbb_setpin;
+  pgm->getpin         = serbb_getpin;
+  pgm->highpulsepin   = serbb_highpulsepin;
+  pgm->read_byte      = avr_read_byte_default;
+  pgm->write_byte     = avr_write_byte_default;
+}
+
+#endif  /* WIN32NATIVE */
diff --git a/avrdude/serial.h b/avrdude/serial.h
new file mode 100644
index 00000000..4a52f19b
--- /dev/null
+++ b/avrdude/serial.h
@@ -0,0 +1,76 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2003-2004  Theodore A. Roth  <troth@openavr.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id$ */
+
+/* This is the API for the generic serial interface. The implementations are
+   actually provided by the target dependant files:
+
+   ser_posix.c : posix serial interface.
+   ser_win32.c : native win32 serial interface.
+
+   The target file will be selected at configure time. */
+
+#ifndef serial_h
+#define serial_h
+
+extern long serial_recv_timeout;
+union filedescriptor
+{
+  int ifd;
+  void *pfd;
+  struct
+  {
+    void *handle;
+    int ep;
+  } usb;
+};
+
+struct serial_device
+{
+  void (*open)(char * port, long baud, union filedescriptor *fd);
+  int (*setspeed)(union filedescriptor *fd, long baud);
+  void (*close)(union filedescriptor *fd);
+
+  int (*send)(union filedescriptor *fd, unsigned char * buf, size_t buflen);
+  int (*recv)(union filedescriptor *fd, unsigned char * buf, size_t buflen);
+  int (*drain)(union filedescriptor *fd, int display);
+
+  int (*set_dtr_rts)(union filedescriptor *fd, int is_on);
+
+  int flags;
+#define SERDEV_FL_NONE         0x0000 /* no flags */
+#define SERDEV_FL_CANSETSPEED  0x0001 /* device can change speed */
+};
+
+extern struct serial_device *serdev;
+extern struct serial_device serial_serdev;
+extern struct serial_device usb_serdev;
+extern struct serial_device usb_serdev_frame;
+extern struct serial_device avrdoper_serdev;
+
+#define serial_open (serdev->open)
+#define serial_setspeed (serdev->setspeed)
+#define serial_close (serdev->close)
+#define serial_send (serdev->send)
+#define serial_recv (serdev->recv)
+#define serial_drain (serdev->drain)
+#define serial_set_dtr_rts (serdev->set_dtr_rts)
+
+#endif /* serial_h */
diff --git a/avrdude/solaris_ecpp.h b/avrdude/solaris_ecpp.h
new file mode 100644
index 00000000..b6812439
--- /dev/null
+++ b/avrdude/solaris_ecpp.h
@@ -0,0 +1,51 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2005 Joerg Wunsch
+ *
+ * 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
+ */
+
+/* $Id$ */
+
+#ifndef solaris_ecpp_h
+#define solaris_ecpp_h
+
+#include <sys/ecppio.h>
+
+#define ppi_claim(fd) \
+	do { \
+		struct ecpp_transfer_parms p; \
+		(void)ioctl(fd, ECPPIOC_GETPARMS, &p); \
+		p.mode = ECPP_DIAG_MODE; \
+		(void)ioctl(fd, ECPPIOC_SETPARMS, &p); \
+	} while(0);
+
+#define ppi_release(fd)
+
+#define DO_PPI_READ(fd, reg, valp) \
+	do { struct ecpp_regs r; \
+	if ((reg) == PPIDATA) { (void)ioctl(fd, ECPPIOC_GETDATA, valp); } \
+	else { (void)ioctl(fd, ECPPIOC_GETREGS, &r); \
+		*(valp) = ((reg) == PPICTRL)? r.dcr: r.dsr; } \
+	} while(0)
+#define DO_PPI_WRITE(fd, reg, valp) \
+	do { struct ecpp_regs r; \
+	if ((reg) == PPIDATA) { (void)ioctl(fd, ECPPIOC_SETDATA, valp); } \
+	else { if ((reg) == PPICTRL) r.dcr = *(valp); else r.dsr = *(valp); \
+		(void)ioctl(fd, ECPPIOC_SETREGS, &r); } \
+	} while(0)
+
+
+#endif /* solaris_ecpp_h */
diff --git a/avrdude/stk500.c b/avrdude/stk500.c
new file mode 100644
index 00000000..4e7c4fff
--- /dev/null
+++ b/avrdude/stk500.c
@@ -0,0 +1,1362 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2002-2004 Brian S. Dean <bsd@bsdhome.com>
+ * Copyright (C) 2008 Joerg Wunsch
+ *
+ * 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
+ */
+
+/* $Id$ */
+
+/*
+ * avrdude interface for Atmel STK500 programmer
+ *
+ * Note: most commands use the "universal command" feature of the
+ * programmer in a "pass through" mode, exceptions are "program
+ * enable", "paged read", and "paged write".
+ *
+ */
+
+#include "ac_cfg.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "avrdude.h"
+#include "avr.h"
+#include "pgm.h"
+#include "stk500_private.h"
+#include "serial.h"
+
+#define STK500_XTAL 7372800U
+
+static int stk500_getparm(PROGRAMMER * pgm, unsigned parm, unsigned * value);
+static int stk500_setparm(PROGRAMMER * pgm, unsigned parm, unsigned value);
+static void stk500_print_parms1(PROGRAMMER * pgm, const char * p);
+static int stk500_is_page_empty(unsigned int address, int page_size, 
+    const unsigned char *buf);
+
+
+static int stk500_send(PROGRAMMER * pgm, unsigned char * buf, size_t len)
+{
+  return serial_send(&pgm->fd, buf, len);
+}
+
+
+static int stk500_recv(PROGRAMMER * pgm, unsigned char * buf, size_t len)
+{
+  int rv;
+
+  rv = serial_recv(&pgm->fd, buf, len);
+  if (rv < 0) {
+    fprintf(stderr,
+	    "%s: stk500_recv(): programmer is not responding\n",
+	    progname);
+    return -1;
+  }
+  return 0;
+}
+
+
+int stk500_drain(PROGRAMMER * pgm, int display)
+{
+  return serial_drain(&pgm->fd, display);
+}
+
+
+int stk500_getsync(PROGRAMMER * pgm)
+{
+  unsigned char buf[32], resp[32];
+
+  /*
+   * get in sync */
+  buf[0] = Cmnd_STK_GET_SYNC;
+  buf[1] = Sync_CRC_EOP;
+  
+  /*
+   * First send and drain a few times to get rid of line noise 
+   */
+   
+  stk500_send(pgm, buf, 2);
+  stk500_drain(pgm, 0);
+  stk500_send(pgm, buf, 2);
+  stk500_drain(pgm, 0);
+
+  stk500_send(pgm, buf, 2);
+  if (stk500_recv(pgm, resp, 1) < 0)
+    return -1;
+  if (resp[0] != Resp_STK_INSYNC) {
+    fprintf(stderr, 
+            "%s: stk500_getsync(): not in sync: resp=0x%02x\n",
+            progname, resp[0]);
+    stk500_drain(pgm, 0);
+    return -1;
+  }
+
+  if (stk500_recv(pgm, resp, 1) < 0)
+    return -1;
+  if (resp[0] != Resp_STK_OK) {
+    fprintf(stderr, 
+            "%s: stk500_getsync(): can't communicate with device: "
+            "resp=0x%02x\n",
+            progname, resp[0]);
+    return -1;
+  }
+
+  return 0;
+}
+
+
+/*
+ * transmit an AVR device command and return the results; 'cmd' and
+ * 'res' must point to at least a 4 byte data buffer
+ */
+static int stk500_cmd(PROGRAMMER * pgm, unsigned char cmd[4],
+                      unsigned char res[4])
+{
+  unsigned char buf[32];
+
+  buf[0] = Cmnd_STK_UNIVERSAL;
+  buf[1] = cmd[0];
+  buf[2] = cmd[1];
+  buf[3] = cmd[2];
+  buf[4] = cmd[3];
+  buf[5] = Sync_CRC_EOP;
+
+  stk500_send(pgm, buf, 6);
+
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
+  if (buf[0] != Resp_STK_INSYNC) {
+    fprintf(stderr, "%s: stk500_cmd(): programmer is out of sync\n", progname);
+    exit(1);
+  }
+
+  res[0] = cmd[1];
+  res[1] = cmd[2];
+  res[2] = cmd[3];
+  if (stk500_recv(pgm, &res[3], 1) < 0)
+    exit(1);
+
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
+  if (buf[0] != Resp_STK_OK) {
+    fprintf(stderr, "%s: stk500_cmd(): protocol error\n", progname);
+    exit(1);
+  }
+
+  return 0;
+}
+
+
+
+/*
+ * issue the 'chip erase' command to the AVR device
+ */
+static int stk500_chip_erase(PROGRAMMER * pgm, AVRPART * p)
+{
+  unsigned char cmd[4];
+  unsigned char res[4];
+
+  if (pgm->cmd == NULL) {
+    fprintf(stderr,
+	    "%s: Error: %s programmer uses stk500_chip_erase() but does not\n"
+	    "provide a cmd() method.\n",
+	    progname, pgm->type);
+    return -1;
+  }
+
+  if (p->op[AVR_OP_CHIP_ERASE] == NULL) {
+    fprintf(stderr, "chip erase instruction not defined for part \"%s\"\n",
+            p->desc);
+    return -1;
+  }
+
+  pgm->pgm_led(pgm, ON);
+
+  memset(cmd, 0, sizeof(cmd));
+
+  avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd);
+  pgm->cmd(pgm, cmd, res);
+  usleep(p->chip_erase_delay);
+  pgm->initialize(pgm, p);
+
+  pgm->pgm_led(pgm, OFF);
+
+  return 0;
+}
+
+/*
+ * issue the 'program enable' command to the AVR device
+ */
+static int stk500_program_enable(PROGRAMMER * pgm, AVRPART * p)
+{
+  unsigned char buf[16];
+  int tries=0;
+
+ retry:
+  
+  tries++;
+
+  buf[0] = Cmnd_STK_ENTER_PROGMODE;
+  buf[1] = Sync_CRC_EOP;
+
+  stk500_send(pgm, buf, 2);
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
+  if (buf[0] == Resp_STK_NOSYNC) {
+    if (tries > 33) {
+      fprintf(stderr, "%s: stk500_program_enable(): can't get into sync\n",
+              progname);
+      return -1;
+    }
+    if (stk500_getsync(pgm) < 0)
+      return -1;
+    goto retry;
+  }
+  else if (buf[0] != Resp_STK_INSYNC) {
+    fprintf(stderr,
+            "%s: stk500_program_enable(): protocol error, "
+            "expect=0x%02x, resp=0x%02x\n", 
+            progname, Resp_STK_INSYNC, buf[0]);
+    return -1;
+  }
+
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
+  if (buf[0] == Resp_STK_OK) {
+    return 0;
+  }
+  else if (buf[0] == Resp_STK_NODEVICE) {
+    fprintf(stderr, "%s: stk500_program_enable(): no device\n",
+            progname);
+    return -1;
+  }
+
+  if(buf[0] == Resp_STK_FAILED)
+  {
+      fprintf(stderr, 
+	      "%s: stk500_program_enable(): failed to enter programming mode\n", 
+		  progname);
+	  return -1;
+  }
+
+
+  fprintf(stderr, "%s: stk500_program_enable(): unknown response=0x%02x\n",
+          progname, buf[0]);
+
+  return -1;
+}
+
+
+
+static int stk500_set_extended_parms(PROGRAMMER * pgm, int n,
+                                     unsigned char * cmd)
+{
+  unsigned char buf[16];
+  int tries=0;
+  int i;
+
+ retry:
+  
+  tries++;
+
+  buf[0] = Cmnd_STK_SET_DEVICE_EXT;
+  for (i=0; i<n; i++) {
+    buf[1+i] = cmd[i];
+  }
+  i++;
+  buf[i] = Sync_CRC_EOP;
+
+  stk500_send(pgm, buf, i+1);
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
+  if (buf[0] == Resp_STK_NOSYNC) {
+    if (tries > 33) {
+      fprintf(stderr, "%s: stk500_set_extended_parms(): can't get into sync\n",
+              progname);
+      return -1;
+    }
+    if (stk500_getsync(pgm) < 0)
+      return -1;
+    goto retry;
+  }
+  else if (buf[0] != Resp_STK_INSYNC) {
+    fprintf(stderr,
+            "%s: stk500_set_extended_parms(): protocol error, "
+            "expect=0x%02x, resp=0x%02x\n", 
+            progname, Resp_STK_INSYNC, buf[0]);
+    return -1;
+  }
+
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
+  if (buf[0] == Resp_STK_OK) {
+    return 0;
+  }
+  else if (buf[0] == Resp_STK_NODEVICE) {
+    fprintf(stderr, "%s: stk500_set_extended_parms(): no device\n",
+            progname);
+    return -1;
+  }
+
+  if(buf[0] == Resp_STK_FAILED)
+  {
+      fprintf(stderr, 
+	      "%s: stk500_set_extended_parms(): failed to set extended "
+              "device programming parameters\n", 
+              progname);
+	  return -1;
+  }
+
+
+  fprintf(stderr, "%s: stk500_set_extended_parms(): unknown response=0x%02x\n",
+          progname, buf[0]);
+
+  return -1;
+}
+
+/*
+ * Crossbow MIB510 initialization and shutdown.  Use cmd = 1 to
+ * initialize, cmd = 0 to close.
+ */
+static int mib510_isp(PROGRAMMER * pgm, unsigned char cmd)
+{
+  unsigned char buf[9];
+  int tries = 0;
+
+  buf[0] = 0xaa;
+  buf[1] = 0x55;
+  buf[2] = 0x55;
+  buf[3] = 0xaa;
+  buf[4] = 0x17;
+  buf[5] = 0x51;
+  buf[6] = 0x31;
+  buf[7] = 0x13;
+  buf[8] = cmd;
+
+
+ retry:
+
+  tries++;
+
+  stk500_send(pgm, buf, 9);
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
+  if (buf[0] == Resp_STK_NOSYNC) {
+    if (tries > 33) {
+      fprintf(stderr, "%s: mib510_isp(): can't get into sync\n",
+              progname);
+      return -1;
+    }
+    if (stk500_getsync(pgm) < 0)
+      return -1;
+    goto retry;
+  }
+  else if (buf[0] != Resp_STK_INSYNC) {
+    fprintf(stderr,
+            "%s: mib510_isp(): protocol error, "
+            "expect=0x%02x, resp=0x%02x\n",
+            progname, Resp_STK_INSYNC, buf[0]);
+    return -1;
+  }
+
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
+  if (buf[0] == Resp_STK_OK) {
+    return 0;
+  }
+  else if (buf[0] == Resp_STK_NODEVICE) {
+    fprintf(stderr, "%s: mib510_isp(): no device\n",
+            progname);
+    return -1;
+  }
+
+  if (buf[0] == Resp_STK_FAILED)
+  {
+      fprintf(stderr,
+          "%s: mib510_isp(): command %d failed\n",
+              progname, cmd);
+      return -1;
+  }
+
+
+  fprintf(stderr, "%s: mib510_isp(): unknown response=0x%02x\n",
+          progname, buf[0]);
+
+  return -1;
+}
+
+
+/*
+ * initialize the AVR device and prepare it to accept commands
+ */
+static int stk500_initialize(PROGRAMMER * pgm, AVRPART * p)
+{
+  unsigned char buf[32];
+  AVRMEM * m;
+  int tries;
+  unsigned maj, min;
+  int rc;
+  int n_extparms;
+
+  stk500_getparm(pgm, Parm_STK_SW_MAJOR, &maj);
+  stk500_getparm(pgm, Parm_STK_SW_MINOR, &min);
+
+  // MIB510 does not need extparams
+  if (strcmp(ldata(lfirst(pgm->id)), "mib510") == 0)
+    n_extparms = 0;
+  else if ((maj > 1) || ((maj == 1) && (min > 10)))
+    n_extparms = 4;
+  else
+    n_extparms = 3;
+
+  tries = 0;
+
+ retry:
+  tries++;
+
+  memset(buf, 0, sizeof(buf));
+
+  /*
+   * set device programming parameters
+   */
+  buf[0] = Cmnd_STK_SET_DEVICE;
+
+  buf[1] = p->stk500_devcode;
+  buf[2] = 0; /* device revision */
+
+  if ((p->flags & AVRPART_SERIALOK) && (p->flags & AVRPART_PARALLELOK))
+    buf[3] = 0; /* device supports parallel and serial programming */
+  else
+    buf[3] = 1; /* device supports parallel only */
+
+  if (p->flags & AVRPART_PARALLELOK) {
+    if (p->flags & AVRPART_PSEUDOPARALLEL) {
+      buf[4] = 0; /* pseudo parallel interface */
+      n_extparms = 0;
+    }
+    else {
+      buf[4] = 1; /* full parallel interface */
+    }
+  }
+
+#if 0
+  fprintf(stderr, "%s: stk500_initialize(): n_extparms = %d\n", 
+          progname, n_extparms);
+#endif
+    
+  buf[5] = 1; /* polling supported - XXX need this in config file */
+  buf[6] = 1; /* programming is self-timed - XXX need in config file */
+
+  m = avr_locate_mem(p, "lock");
+  if (m)
+    buf[7] = m->size;
+  else
+    buf[7] = 0;
+
+  /*
+   * number of fuse bytes
+   */
+  buf[8] = 0;
+  m = avr_locate_mem(p, "fuse");
+  if (m)
+    buf[8] += m->size;
+  m = avr_locate_mem(p, "lfuse");
+  if (m)
+    buf[8] += m->size;
+  m = avr_locate_mem(p, "hfuse");
+  if (m)
+    buf[8] += m->size;
+  m = avr_locate_mem(p, "efuse");
+  if (m)
+    buf[8] += m->size;
+
+  m = avr_locate_mem(p, "flash");
+  if (m) {
+    buf[9] = m->readback[0];
+    buf[10] = m->readback[1];
+    if (m->paged) {
+      buf[13] = (m->page_size >> 8) & 0x00ff;
+      buf[14] = m->page_size & 0x00ff;
+    }
+    buf[17] = (m->size >> 24) & 0xff;
+    buf[18] = (m->size >> 16) & 0xff;
+    buf[19] = (m->size >> 8) & 0xff;
+    buf[20] = m->size & 0xff;
+  }
+  else {
+    buf[9]  = 0xff;
+    buf[10]  = 0xff;
+    buf[13] = 0;
+    buf[14] = 0;
+    buf[17] = 0;
+    buf[18] = 0;
+    buf[19] = 0;
+    buf[20] = 0;
+  }
+
+  m = avr_locate_mem(p, "eeprom");
+  if (m) {
+    buf[11] = m->readback[0];
+    buf[12] = m->readback[1];
+    buf[15] = (m->size >> 8) & 0x00ff;
+    buf[16] = m->size & 0x00ff;
+  }
+  else {
+    buf[11] = 0xff;
+    buf[12] = 0xff;
+    buf[15] = 0;
+    buf[16] = 0;
+  }
+
+  buf[21] = Sync_CRC_EOP;
+
+  stk500_send(pgm, buf, 22);
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
+  if (buf[0] == Resp_STK_NOSYNC) {
+    fprintf(stderr,
+            "%s: stk500_initialize(): programmer not in sync, resp=0x%02x\n", 
+            progname, buf[0]);
+    if (tries > 33)
+      return -1;
+    if (stk500_getsync(pgm) < 0)
+      return -1;
+    goto retry;
+  }
+  else if (buf[0] != Resp_STK_INSYNC) {
+    fprintf(stderr,
+            "%s: stk500_initialize(): (a) protocol error, "
+            "expect=0x%02x, resp=0x%02x\n", 
+            progname, Resp_STK_INSYNC, buf[0]);
+    return -1;
+  }
+
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
+  if (buf[0] != Resp_STK_OK) {
+    fprintf(stderr,
+            "%s: stk500_initialize(): (b) protocol error, "
+            "expect=0x%02x, resp=0x%02x\n", 
+            progname, Resp_STK_OK, buf[0]);
+    return -1;
+  }
+
+  if (n_extparms) {
+    if ((p->pagel == 0) || (p->bs2 == 0)) {
+      fprintf(stderr, 
+              "%s: please define PAGEL and BS2 signals in the configuration "
+              "file for part %s\n", 
+              progname, p->desc);
+    }
+    else {
+      buf[0] = n_extparms+1;
+
+      /*
+       * m is currently pointing to eeprom memory if the part has it
+       */
+      if (m)
+        buf[1] = m->page_size;
+      else
+        buf[1] = 0;
+      
+      buf[2] = p->pagel;
+      buf[3] = p->bs2;
+      
+      if (n_extparms == 4) {
+        if (p->reset_disposition == RESET_DEDICATED)
+          buf[4] = 0;
+        else
+          buf[4] = 1;
+      }
+      
+      rc = stk500_set_extended_parms(pgm, n_extparms+1, buf);
+      if (rc) {
+        fprintf(stderr, "%s: stk500_initialize(): failed\n", progname);
+        exit(1);
+      }
+    }
+  }
+
+  return pgm->program_enable(pgm, p);
+}
+
+
+static void stk500_disable(PROGRAMMER * pgm)
+{
+  unsigned char buf[16];
+  int tries=0;
+
+ retry:
+  
+  tries++;
+
+  buf[0] = Cmnd_STK_LEAVE_PROGMODE;
+  buf[1] = Sync_CRC_EOP;
+
+  stk500_send(pgm, buf, 2);
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
+  if (buf[0] == Resp_STK_NOSYNC) {
+    if (tries > 33) {
+      fprintf(stderr, "%s: stk500_disable(): can't get into sync\n",
+              progname);
+      return;
+    }
+    if (stk500_getsync(pgm) < 0)
+      return;
+    goto retry;
+  }
+  else if (buf[0] != Resp_STK_INSYNC) {
+    fprintf(stderr,
+            "%s: stk500_disable(): protocol error, expect=0x%02x, "
+            "resp=0x%02x\n", 
+            progname, Resp_STK_INSYNC, buf[0]);
+    return;
+  }
+
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
+  if (buf[0] == Resp_STK_OK) {
+    return;
+  }
+  else if (buf[0] == Resp_STK_NODEVICE) {
+    fprintf(stderr, "%s: stk500_disable(): no device\n",
+            progname);
+    return;
+  }
+
+  fprintf(stderr, "%s: stk500_disable(): unknown response=0x%02x\n",
+          progname, buf[0]);
+
+  return;
+}
+
+static void stk500_enable(PROGRAMMER * pgm)
+{
+  return;
+}
+
+
+static int stk500_open(PROGRAMMER * pgm, char * port)
+{
+  strcpy(pgm->port, port);
+  serial_open(port, pgm->baudrate? pgm->baudrate: 115200, &pgm->fd);
+
+  /*
+   * drain any extraneous input
+   */
+  stk500_drain(pgm, 0);
+
+  // MIB510 init
+  if (strcmp(ldata(lfirst(pgm->id)), "mib510") == 0 &&
+      mib510_isp(pgm, 1) != 0)
+    return -1;
+
+  if (stk500_getsync(pgm) < 0)
+    return -1;
+
+  return 0;
+}
+
+
+static void stk500_close(PROGRAMMER * pgm)
+{
+  // MIB510 close
+  if (strcmp(ldata(lfirst(pgm->id)), "mib510") == 0)
+    (void)mib510_isp(pgm, 0);
+
+  serial_close(&pgm->fd);
+  pgm->fd.ifd = -1;
+}
+
+
+static int stk500_loadaddr(PROGRAMMER * pgm, unsigned int addr)
+{
+  unsigned char buf[16];
+  int tries;
+
+  tries = 0;
+ retry:
+  tries++;
+  buf[0] = Cmnd_STK_LOAD_ADDRESS;
+  buf[1] = addr & 0xff;
+  buf[2] = (addr >> 8) & 0xff;
+  buf[3] = Sync_CRC_EOP;
+
+  stk500_send(pgm, buf, 4);
+
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
+  if (buf[0] == Resp_STK_NOSYNC) {
+    if (tries > 33) {
+      fprintf(stderr, "%s: stk500_loadaddr(): can't get into sync\n",
+              progname);
+      return -1;
+    }
+    if (stk500_getsync(pgm) < 0)
+      return -1;
+    goto retry;
+  }
+  else if (buf[0] != Resp_STK_INSYNC) {
+    fprintf(stderr,
+            "%s: stk500_loadaddr(): (a) protocol error, "
+            "expect=0x%02x, resp=0x%02x\n", 
+            progname, Resp_STK_INSYNC, buf[0]);
+    return -1;
+  }
+
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
+  if (buf[0] == Resp_STK_OK) {
+    return 0;
+  }
+
+  fprintf(stderr,
+          "%s: loadaddr(): (b) protocol error, "
+          "expect=0x%02x, resp=0x%02x\n", 
+          progname, Resp_STK_INSYNC, buf[0]);
+
+  return -1;
+}
+
+
+static int stk500_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, 
+                              int page_size, int n_bytes)
+{
+  unsigned char buf[page_size + 16];
+  int memtype;
+  unsigned int addr;
+  int a_div;
+  int block_size;
+  int tries;
+  unsigned int n;
+  unsigned int i;
+  int flash;
+
+  if (page_size == 0) {
+    // MIB510 uses page size of 256 bytes
+    if (strcmp(ldata(lfirst(pgm->id)), "mib510") == 0) {
+      page_size = 256;
+    }
+    else {
+      page_size = 128;
+    }
+  }
+
+  if (strcmp(m->desc, "flash") == 0) {
+    memtype = 'F';
+    flash = 1;
+  }
+  else if (strcmp(m->desc, "eeprom") == 0) {
+    memtype = 'E';
+    flash = 0;
+  }
+  else {
+    return -2;
+  }
+
+  if ((m->op[AVR_OP_LOADPAGE_LO]) || (m->op[AVR_OP_READ_LO]))
+    a_div = 2;
+  else
+    a_div = 1;
+
+  if (n_bytes > m->size) {
+    n_bytes = m->size;
+    n = m->size;
+  }
+  else {
+    if ((n_bytes % page_size) != 0) {
+      n = n_bytes + page_size - (n_bytes % page_size);
+    }
+    else {
+      n = n_bytes;
+    }
+  }
+
+#if 0
+  fprintf(stderr, 
+          "n_bytes   = %d\n"
+          "n         = %u\n"
+          "a_div     = %d\n"
+          "page_size = %d\n",
+          n_bytes, n, a_div, page_size);
+#endif     
+
+  for (addr = 0; addr < n; addr += page_size) {
+    report_progress (addr, n_bytes, NULL);
+    
+    // MIB510 uses fixed blocks size of 256 bytes
+    if ((strcmp(ldata(lfirst(pgm->id)), "mib510") != 0) &&
+	(addr + page_size > n_bytes)) {
+	   block_size = n_bytes % page_size;
+	}
+	else {
+	   block_size = page_size;
+	}
+  
+    /* Only skip on empty page if programming flash. */
+    if (flash) {
+      if (stk500_is_page_empty(addr, block_size, m->buf)) {
+          continue;
+      }
+    }
+    tries = 0;
+  retry:
+    tries++;
+    stk500_loadaddr(pgm, addr/a_div);
+
+    /* build command block and avoid multiple send commands as it leads to a crash
+        of the silabs usb serial driver on mac os x */
+    i = 0;
+    buf[i++] = Cmnd_STK_PROG_PAGE;
+    buf[i++] = (block_size >> 8) & 0xff;
+    buf[i++] = block_size & 0xff;
+    buf[i++] = memtype;
+    memcpy(&buf[i], &m->buf[addr], block_size);
+    i += block_size;
+    buf[i++] = Sync_CRC_EOP;
+    stk500_send( pgm, buf, i);
+
+    if (stk500_recv(pgm, buf, 1) < 0)
+      exit(1);
+    if (buf[0] == Resp_STK_NOSYNC) {
+      if (tries > 33) {
+        fprintf(stderr, "\n%s: stk500_paged_write(): can't get into sync\n",
+                progname);
+        return -3;
+      }
+      if (stk500_getsync(pgm) < 0)
+	return -1;
+      goto retry;
+    }
+    else if (buf[0] != Resp_STK_INSYNC) {
+      fprintf(stderr,
+              "\n%s: stk500_paged_write(): (a) protocol error, "
+              "expect=0x%02x, resp=0x%02x\n", 
+              progname, Resp_STK_INSYNC, buf[0]);
+      return -4;
+    }
+    
+    if (stk500_recv(pgm, buf, 1) < 0)
+      exit(1);
+    if (buf[0] != Resp_STK_OK) {
+      fprintf(stderr,
+              "\n%s: stk500_paged_write(): (a) protocol error, "
+              "expect=0x%02x, resp=0x%02x\n", 
+              progname, Resp_STK_INSYNC, buf[0]);
+      return -5;
+    }
+  }
+
+  return n_bytes;
+}
+
+static int stk500_is_page_empty(unsigned int address, int page_size, 
+                                const unsigned char *buf)
+{
+    int i;
+    for(i = 0; i < page_size; i++) {
+        if(buf[address + i] != 0xFF) {
+            /* Page is not empty. */
+            return(0);
+        }
+    }
+    
+    /* Page is empty. */
+    return(1);
+}
+
+static int stk500_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, 
+                             int page_size, int n_bytes)
+{
+  unsigned char buf[16];
+  int memtype;
+  unsigned int addr;
+  int a_div;
+  int tries;
+  unsigned int n;
+  int block_size;
+
+  if (strcmp(m->desc, "flash") == 0) {
+    memtype = 'F';
+  }
+  else if (strcmp(m->desc, "eeprom") == 0) {
+    memtype = 'E';
+  }
+  else {
+    return -2;
+  }
+
+  if ((m->op[AVR_OP_LOADPAGE_LO]) || (m->op[AVR_OP_READ_LO]))
+    a_div = 2;
+  else
+    a_div = 1;
+
+  if (n_bytes > m->size) {
+    n_bytes = m->size;
+    n = m->size;
+  }
+  else {
+    if ((n_bytes % page_size) != 0) {
+      n = n_bytes + page_size - (n_bytes % page_size);
+    }
+    else {
+      n = n_bytes;
+    }
+  }
+
+  for (addr = 0; addr < n; addr += page_size) {
+    report_progress (addr, n_bytes, NULL);
+
+    // MIB510 uses fixed blocks size of 256 bytes
+    if ((strcmp(ldata(lfirst(pgm->id)), "mib510") != 0) &&
+	(addr + page_size > n_bytes)) {
+	   block_size = n_bytes % page_size;
+	}
+	else {
+	   block_size = page_size;
+	}
+  
+    tries = 0;
+  retry:
+    tries++;
+    stk500_loadaddr(pgm, addr/a_div);
+    buf[0] = Cmnd_STK_READ_PAGE;
+    buf[1] = (block_size >> 8) & 0xff;
+    buf[2] = block_size & 0xff;
+    buf[3] = memtype;
+    buf[4] = Sync_CRC_EOP;
+    stk500_send(pgm, buf, 5);
+
+    if (stk500_recv(pgm, buf, 1) < 0)
+      exit(1);
+    if (buf[0] == Resp_STK_NOSYNC) {
+      if (tries > 33) {
+        fprintf(stderr, "\n%s: stk500_paged_load(): can't get into sync\n",
+                progname);
+        return -3;
+      }
+      if (stk500_getsync(pgm) < 0)
+	return -1;
+      goto retry;
+    }
+    else if (buf[0] != Resp_STK_INSYNC) {
+      fprintf(stderr,
+              "\n%s: stk500_paged_load(): (a) protocol error, "
+              "expect=0x%02x, resp=0x%02x\n", 
+              progname, Resp_STK_INSYNC, buf[0]);
+      return -4;
+    }
+
+    if (stk500_recv(pgm, &m->buf[addr], block_size) < 0)
+      exit(1);
+
+    if (stk500_recv(pgm, buf, 1) < 0)
+      exit(1);
+
+    if(strcmp(ldata(lfirst(pgm->id)), "mib510") == 0) {
+      if (buf[0] != Resp_STK_INSYNC) {
+      fprintf(stderr,
+              "\n%s: stk500_paged_load(): (a) protocol error, "
+              "expect=0x%02x, resp=0x%02x\n", 
+              progname, Resp_STK_INSYNC, buf[0]);
+      return -5;
+    }
+  }
+    else {
+      if (buf[0] != Resp_STK_OK) {
+        fprintf(stderr,
+                "\n%s: stk500_paged_load(): (a) protocol error, "
+                "expect=0x%02x, resp=0x%02x\n",
+                progname, Resp_STK_OK, buf[0]);
+        return -5;
+      }
+    }
+  }
+
+  return n_bytes;
+}
+
+
+static int stk500_set_vtarget(PROGRAMMER * pgm, double v)
+{
+  unsigned uaref, utarg;
+
+  utarg = (unsigned)((v + 0.049) * 10);
+
+  if (stk500_getparm(pgm, Parm_STK_VADJUST, &uaref) != 0) {
+    fprintf(stderr,
+	    "%s: stk500_set_vtarget(): cannot obtain V[aref]\n",
+	    progname);
+    return -1;
+  }
+
+  if (uaref > utarg) {
+    fprintf(stderr,
+	    "%s: stk500_set_vtarget(): reducing V[aref] from %.1f to %.1f\n",
+	    progname, uaref / 10.0, v);
+    if (stk500_setparm(pgm, Parm_STK_VADJUST, utarg)
+	!= 0)
+      return -1;
+  }
+  return stk500_setparm(pgm, Parm_STK_VTARGET, utarg);
+}
+
+
+static int stk500_set_varef(PROGRAMMER * pgm, unsigned int chan /* unused */,
+                            double v)
+{
+  unsigned uaref, utarg;
+
+  uaref = (unsigned)((v + 0.049) * 10);
+
+  if (stk500_getparm(pgm, Parm_STK_VTARGET, &utarg) != 0) {
+    fprintf(stderr,
+	    "%s: stk500_set_varef(): cannot obtain V[target]\n",
+	    progname);
+    return -1;
+  }
+
+  if (uaref > utarg) {
+    fprintf(stderr,
+	    "%s: stk500_set_varef(): V[aref] must not be greater than "
+	    "V[target] = %.1f\n",
+	    progname, utarg / 10.0);
+    return -1;
+  }
+  return stk500_setparm(pgm, Parm_STK_VADJUST, uaref);
+}
+
+
+static int stk500_set_fosc(PROGRAMMER * pgm, double v)
+{
+  unsigned prescale, cmatch, fosc;
+  static unsigned ps[] = {
+    1, 8, 32, 64, 128, 256, 1024
+  };
+  int idx, rc;
+
+  prescale = cmatch = 0;
+  if (v > 0.0) {
+    if (v > STK500_XTAL / 2) {
+      const char *unit;
+      if (v > 1e6) {
+        v /= 1e6;
+        unit = "MHz";
+      } else if (v > 1e3) {
+        v /= 1e3;
+        unit = "kHz";
+      } else
+        unit = "Hz";
+      fprintf(stderr,
+          "%s: stk500_set_fosc(): f = %.3f %s too high, using %.3f MHz\n",
+          progname, v, unit, STK500_XTAL / 2e6);
+      fosc = STK500_XTAL / 2;
+    } else
+      fosc = (unsigned)v;
+    
+    for (idx = 0; idx < sizeof(ps) / sizeof(ps[0]); idx++) {
+      if (fosc >= STK500_XTAL / (256 * ps[idx] * 2)) {
+        /* this prescaler value can handle our frequency */
+        prescale = idx + 1;
+        cmatch = (unsigned)(STK500_XTAL / (2 * fosc * ps[idx])) - 1;
+        break;
+      }
+    }
+    if (idx == sizeof(ps) / sizeof(ps[0])) {
+      fprintf(stderr, "%s: stk500_set_fosc(): f = %u Hz too low, %u Hz min\n",
+          progname, fosc, STK500_XTAL / (256 * 1024 * 2));
+      return -1;
+    }
+  }
+  
+  if ((rc = stk500_setparm(pgm, Parm_STK_OSC_PSCALE, prescale)) != 0
+      || (rc = stk500_setparm(pgm, Parm_STK_OSC_CMATCH, cmatch)) != 0)
+    return rc;
+  
+  return 0;
+}
+
+
+/* This code assumes that each count of the SCK duration parameter
+   represents 8/f, where f is the clock frequency of the STK500 master
+   processors (not the target).  This number comes from Atmel
+   application note AVR061.  It appears that the STK500 bit bangs SCK.
+   For small duration values, the actual SCK width is larger than
+   expected.  As the duration value increases, the SCK width error
+   diminishes. */
+static int stk500_set_sck_period(PROGRAMMER * pgm, double v)
+{
+  int dur;
+  double min, max;
+
+  min = 8.0 / STK500_XTAL;
+  max = 255 * min;
+  dur = v / min + 0.5;
+  
+  if (v < min) {
+      dur = 1;
+      fprintf(stderr,
+	      "%s: stk500_set_sck_period(): p = %.1f us too small, using %.1f us\n",
+	      progname, v / 1e-6, dur * min / 1e-6);
+  } else if (v > max) {
+      dur = 255;
+      fprintf(stderr,
+	      "%s: stk500_set_sck_period(): p = %.1f us too large, using %.1f us\n",
+	      progname, v / 1e-6, dur * min / 1e-6);
+  }
+  
+  return stk500_setparm(pgm, Parm_STK_SCK_DURATION, dur);
+}
+
+
+static int stk500_getparm(PROGRAMMER * pgm, unsigned parm, unsigned * value)
+{
+  unsigned char buf[16];
+  unsigned v;
+  int tries = 0;
+
+ retry:
+  tries++;
+  buf[0] = Cmnd_STK_GET_PARAMETER;
+  buf[1] = parm;
+  buf[2] = Sync_CRC_EOP;
+
+  stk500_send(pgm, buf, 3);
+
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
+  if (buf[0] == Resp_STK_NOSYNC) {
+    if (tries > 33) {
+      fprintf(stderr, "\n%s: stk500_getparm(): can't get into sync\n",
+              progname);
+      return -1;
+    }
+    if (stk500_getsync(pgm) < 0)
+      return -1;
+    goto retry;
+  }
+  else if (buf[0] != Resp_STK_INSYNC) {
+    fprintf(stderr,
+            "\n%s: stk500_getparm(): (a) protocol error, "
+            "expect=0x%02x, resp=0x%02x\n", 
+            progname, Resp_STK_INSYNC, buf[0]);
+    return -2;
+  }
+
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
+  v = buf[0];
+
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
+  if (buf[0] == Resp_STK_FAILED) {
+    fprintf(stderr,
+            "\n%s: stk500_getparm(): parameter 0x%02x failed\n",
+            progname, v);
+    return -3;
+  }
+  else if (buf[0] != Resp_STK_OK) {
+    fprintf(stderr,
+            "\n%s: stk500_getparm(): (a) protocol error, "
+            "expect=0x%02x, resp=0x%02x\n", 
+            progname, Resp_STK_INSYNC, buf[0]);
+    return -3;
+  }
+
+  *value = v;
+
+  return 0;
+}
+
+  
+static int stk500_setparm(PROGRAMMER * pgm, unsigned parm, unsigned value)
+{
+  unsigned char buf[16];
+  int tries = 0;
+
+ retry:
+  tries++;
+  buf[0] = Cmnd_STK_SET_PARAMETER;
+  buf[1] = parm;
+  buf[2] = value;
+  buf[3] = Sync_CRC_EOP;
+
+  stk500_send(pgm, buf, 4);
+
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
+  if (buf[0] == Resp_STK_NOSYNC) {
+    if (tries > 33) {
+      fprintf(stderr, "\n%s: stk500_setparm(): can't get into sync\n",
+              progname);
+      return -1;
+    }
+    if (stk500_getsync(pgm) < 0)
+      return -1;
+    goto retry;
+  }
+  else if (buf[0] != Resp_STK_INSYNC) {
+    fprintf(stderr,
+            "\n%s: stk500_setparm(): (a) protocol error, "
+            "expect=0x%02x, resp=0x%02x\n", 
+            progname, Resp_STK_INSYNC, buf[0]);
+    return -2;
+  }
+
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
+  if (buf[0] == Resp_STK_OK)
+    return 0;
+
+  parm = buf[0];	/* if not STK_OK, we've been echoed parm here */
+  if (stk500_recv(pgm, buf, 1) < 0)
+    exit(1);
+  if (buf[0] == Resp_STK_FAILED) {
+    fprintf(stderr,
+            "\n%s: stk500_setparm(): parameter 0x%02x failed\n",
+            progname, parm);
+    return -3;
+  }
+  else {
+    fprintf(stderr,
+            "\n%s: stk500_setparm(): (a) protocol error, "
+            "expect=0x%02x, resp=0x%02x\n", 
+            progname, Resp_STK_INSYNC, buf[0]);
+    return -3;
+  }
+}
+
+  
+static void stk500_display(PROGRAMMER * pgm, const char * p)
+{
+  unsigned maj, min, hdw, topcard;
+
+  stk500_getparm(pgm, Parm_STK_HW_VER, &hdw);
+  stk500_getparm(pgm, Parm_STK_SW_MAJOR, &maj);
+  stk500_getparm(pgm, Parm_STK_SW_MINOR, &min);
+  stk500_getparm(pgm, Param_STK500_TOPCARD_DETECT, &topcard);
+
+  fprintf(stderr, "%sHardware Version: %d\n", p, hdw);
+  fprintf(stderr, "%sFirmware Version: %d.%d\n", p, maj, min);
+  if (topcard < 3) {
+    const char *n = "Unknown";
+
+    switch (topcard) {
+      case 1:
+	n = "STK502";
+	break;
+
+      case 2:
+	n = "STK501";
+	break;
+    }
+    fprintf(stderr, "%sTopcard         : %s\n", p, n);
+  }
+  stk500_print_parms1(pgm, p);
+
+  return;
+}
+
+
+static void stk500_print_parms1(PROGRAMMER * pgm, const char * p)
+{
+  unsigned vtarget, vadjust, osc_pscale, osc_cmatch, sck_duration;
+
+  stk500_getparm(pgm, Parm_STK_VTARGET, &vtarget);
+  stk500_getparm(pgm, Parm_STK_VADJUST, &vadjust);
+  stk500_getparm(pgm, Parm_STK_OSC_PSCALE, &osc_pscale);
+  stk500_getparm(pgm, Parm_STK_OSC_CMATCH, &osc_cmatch);
+  stk500_getparm(pgm, Parm_STK_SCK_DURATION, &sck_duration);
+
+  fprintf(stderr, "%sVtarget         : %.1f V\n", p, vtarget / 10.0);
+  fprintf(stderr, "%sVaref           : %.1f V\n", p, vadjust / 10.0);
+  fprintf(stderr, "%sOscillator      : ", p);
+  if (osc_pscale == 0)
+    fprintf(stderr, "Off\n");
+  else {
+    int prescale = 1;
+    double f = STK500_XTAL / 2;
+    const char *unit;
+
+    switch (osc_pscale) {
+      case 2: prescale = 8; break;
+      case 3: prescale = 32; break;
+      case 4: prescale = 64; break;
+      case 5: prescale = 128; break;
+      case 6: prescale = 256; break;
+      case 7: prescale = 1024; break;
+    }
+    f /= prescale;
+    f /= (osc_cmatch + 1);
+    if (f > 1e6) {
+      f /= 1e6;
+      unit = "MHz";
+    } else if (f > 1e3) {
+      f /= 1000;
+      unit = "kHz";
+    } else
+      unit = "Hz";
+    fprintf(stderr, "%.3f %s\n", f, unit);
+  }
+  fprintf(stderr, "%sSCK period      : %.1f us\n", p, 
+	  sck_duration * 8.0e6 / STK500_XTAL + 0.05);
+
+  return;
+}
+
+
+static void stk500_print_parms(PROGRAMMER * pgm)
+{
+  stk500_print_parms1(pgm, "");
+}
+
+
+void stk500_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "STK500");
+
+  /*
+   * mandatory functions
+   */
+  pgm->initialize     = stk500_initialize;
+  pgm->display        = stk500_display;
+  pgm->enable         = stk500_enable;
+  pgm->disable        = stk500_disable;
+  pgm->program_enable = stk500_program_enable;
+  pgm->chip_erase     = stk500_chip_erase;
+  pgm->cmd            = stk500_cmd;
+  pgm->open           = stk500_open;
+  pgm->close          = stk500_close;
+  pgm->read_byte      = avr_read_byte_default;
+  pgm->write_byte     = avr_write_byte_default;
+
+  /*
+   * optional functions
+   */
+  pgm->paged_write    = stk500_paged_write;
+  pgm->paged_load     = stk500_paged_load;
+  pgm->print_parms    = stk500_print_parms;
+  pgm->set_vtarget    = stk500_set_vtarget;
+  pgm->set_varef      = stk500_set_varef;
+  pgm->set_fosc       = stk500_set_fosc;
+  pgm->set_sck_period = stk500_set_sck_period;
+  pgm->page_size      = 256;
+}
diff --git a/avrdude/stk500.h b/avrdude/stk500.h
new file mode 100644
index 00000000..4b22ee05
--- /dev/null
+++ b/avrdude/stk500.h
@@ -0,0 +1,41 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2002-2004  Brian S. Dean <bsd@bsdhome.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id$ */
+
+#ifndef stk500_h
+#define stk500_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void stk500_initpgm (PROGRAMMER * pgm);
+
+/* used by arduino.c to avoid duplicate code */
+int stk500_getsync(PROGRAMMER * pgm);
+int stk500_drain(PROGRAMMER * pgm, int display);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/avrdude/stk500_private.h b/avrdude/stk500_private.h
new file mode 100644
index 00000000..7efe866c
--- /dev/null
+++ b/avrdude/stk500_private.h
@@ -0,0 +1,103 @@
+//**** ATMEL AVR - A P P L I C A T I O N   N O T E  ************************
+//*
+//* Title:		AVR061 - STK500 Communication Protocol
+//* Filename:		command.h
+//* Version:		1.0
+//* Last updated:	09.09.2002
+//*
+//* Support E-mail:	avr@atmel.com
+//*
+//**************************************************************************
+
+// *****************[ STK Message constants ]***************************
+
+#define STK_SIGN_ON_MESSAGE "AVR STK"   // Sign on string for Cmnd_STK_GET_SIGN_ON
+
+// *****************[ STK Response constants ]***************************
+
+#define Resp_STK_OK                0x10  // ' '
+#define Resp_STK_FAILED            0x11  // ' '
+#define Resp_STK_UNKNOWN           0x12  // ' '
+#define Resp_STK_NODEVICE          0x13  // ' '
+#define Resp_STK_INSYNC            0x14  // ' '
+#define Resp_STK_NOSYNC            0x15  // ' '
+
+#define Resp_ADC_CHANNEL_ERROR     0x16  // ' '
+#define Resp_ADC_MEASURE_OK        0x17  // ' '
+#define Resp_PWM_CHANNEL_ERROR     0x18  // ' '
+#define Resp_PWM_ADJUST_OK         0x19  // ' '
+
+// *****************[ STK Special constants ]***************************
+
+#define Sync_CRC_EOP               0x20  // 'SPACE'
+
+// *****************[ STK Command constants ]***************************
+
+#define Cmnd_STK_GET_SYNC          0x30  // ' '
+#define Cmnd_STK_GET_SIGN_ON       0x31  // ' '
+
+#define Cmnd_STK_SET_PARAMETER     0x40  // ' '
+#define Cmnd_STK_GET_PARAMETER     0x41  // ' '
+#define Cmnd_STK_SET_DEVICE        0x42  // ' '
+#define Cmnd_STK_SET_DEVICE_EXT    0x45  // ' '			
+
+#define Cmnd_STK_ENTER_PROGMODE    0x50  // ' '
+#define Cmnd_STK_LEAVE_PROGMODE    0x51  // ' '
+#define Cmnd_STK_CHIP_ERASE        0x52  // ' '
+#define Cmnd_STK_CHECK_AUTOINC     0x53  // ' '
+#define Cmnd_STK_LOAD_ADDRESS      0x55  // ' '
+#define Cmnd_STK_UNIVERSAL         0x56  // ' '
+#define Cmnd_STK_UNIVERSAL_MULTI   0x57  // ' '
+
+#define Cmnd_STK_PROG_FLASH        0x60  // ' '
+#define Cmnd_STK_PROG_DATA         0x61  // ' '
+#define Cmnd_STK_PROG_FUSE         0x62  // ' '
+#define Cmnd_STK_PROG_LOCK         0x63  // ' '
+#define Cmnd_STK_PROG_PAGE         0x64  // ' '
+#define Cmnd_STK_PROG_FUSE_EXT     0x65  // ' '		
+
+#define Cmnd_STK_READ_FLASH        0x70  // ' '
+#define Cmnd_STK_READ_DATA         0x71  // ' '
+#define Cmnd_STK_READ_FUSE         0x72  // ' '
+#define Cmnd_STK_READ_LOCK         0x73  // ' '
+#define Cmnd_STK_READ_PAGE         0x74  // ' '
+#define Cmnd_STK_READ_SIGN         0x75  // ' '
+#define Cmnd_STK_READ_OSCCAL       0x76  // ' '
+#define Cmnd_STK_READ_FUSE_EXT     0x77  // ' '		
+#define Cmnd_STK_READ_OSCCAL_EXT   0x78  // ' '     
+
+// *****************[ STK Parameter constants ]***************************
+
+#define Parm_STK_HW_VER            0x80  // ' ' - R
+#define Parm_STK_SW_MAJOR          0x81  // ' ' - R
+#define Parm_STK_SW_MINOR          0x82  // ' ' - R
+#define Parm_STK_LEDS              0x83  // ' ' - R/W
+#define Parm_STK_VTARGET           0x84  // ' ' - R/W
+#define Parm_STK_VADJUST           0x85  // ' ' - R/W
+#define Parm_STK_OSC_PSCALE        0x86  // ' ' - R/W
+#define Parm_STK_OSC_CMATCH        0x87  // ' ' - R/W
+#define Parm_STK_RESET_DURATION    0x88  // ' ' - R/W
+#define Parm_STK_SCK_DURATION      0x89  // ' ' - R/W
+
+#define Parm_STK_BUFSIZEL          0x90  // ' ' - R/W, Range {0..255}
+#define Parm_STK_BUFSIZEH          0x91  // ' ' - R/W, Range {0..255}
+#define Parm_STK_DEVICE            0x92  // ' ' - R/W, Range {0..255}
+#define Parm_STK_PROGMODE          0x93  // ' ' - 'P' or 'S'
+#define Parm_STK_PARAMODE          0x94  // ' ' - TRUE or FALSE
+#define Parm_STK_POLLING           0x95  // ' ' - TRUE or FALSE
+#define Parm_STK_SELFTIMED         0x96  // ' ' - TRUE or FALSE
+#define Param_STK500_TOPCARD_DETECT 0x98  // ' ' - Detect top-card attached
+
+// *****************[ STK status bit definitions ]***************************
+
+#define Stat_STK_INSYNC            0x01  // INSYNC status bit, '1' - INSYNC
+#define Stat_STK_PROGMODE          0x02  // Programming mode,  '1' - PROGMODE
+#define Stat_STK_STANDALONE        0x04  // Standalone mode,   '1' - SM mode
+#define Stat_STK_RESET             0x08  // RESET button,      '1' - Pushed
+#define Stat_STK_PROGRAM           0x10  // Program button, '   1' - Pushed
+#define Stat_STK_LEDG              0x20  // Green LED status,  '1' - Lit
+#define Stat_STK_LEDR              0x40  // Red LED status,    '1' - Lit
+#define Stat_STK_LEDBLINK          0x80  // LED blink ON/OFF,  '1' - Blink
+
+
+// *****************************[ End Of COMMAND.H ]**************************
diff --git a/avrdude/stk500generic.c b/avrdude/stk500generic.c
new file mode 100644
index 00000000..12125393
--- /dev/null
+++ b/avrdude/stk500generic.c
@@ -0,0 +1,91 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 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
+ */
+
+/* $Id$ */
+
+/*
+ * avrdude interface for Atmel STK500 programmer
+ *
+ * This is a wrapper around the STK500[v1] and STK500v2 programmers.
+ * Try to select the programmer type that actually responds, and
+ * divert to the actual programmer implementation if successful.
+ */
+
+#include "ac_cfg.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "avrdude.h"
+#include "pgm.h"
+#include "stk500.h"
+#include "stk500v2.h"
+
+static int stk500generic_open(PROGRAMMER * pgm, char * port)
+{
+  stk500_initpgm(pgm);
+  if (pgm->open(pgm, port) >= 0)
+    {
+      fprintf(stderr,
+	      "%s: successfully opened stk500v1 device -- please use -c stk500v1\n",
+	      progname);
+      return 0;
+    }
+
+  pgm->close(pgm);
+
+  stk500v2_initpgm(pgm);
+  if (pgm->open(pgm, port) >= 0)
+    {
+      fprintf(stderr,
+	      "%s: successfully opened stk500v2 device -- please use -c stk500v2\n",
+	      progname);
+      return 0;
+    }
+
+  fprintf(stderr,
+	  "%s: cannot open either stk500v1 or stk500v2 programmer\n",
+	  progname);
+  return -1;
+}
+
+static void stk500generic_setup(PROGRAMMER * pgm)
+{
+  /*
+   * Only STK500v2 needs setup/teardown.
+   */
+  stk500v2_initpgm(pgm);
+  pgm->setup(pgm);
+}
+
+static void stk500generic_teardown(PROGRAMMER * pgm)
+{
+  stk500v2_initpgm(pgm);
+  pgm->teardown(pgm);
+}
+
+
+void stk500generic_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "STK500GENERIC");
+
+  pgm->open           = stk500generic_open;
+  pgm->setup          = stk500generic_setup;
+  pgm->teardown       = stk500generic_teardown;
+}
diff --git a/avrdude/stk500generic.h b/avrdude/stk500generic.h
new file mode 100644
index 00000000..89af83b1
--- /dev/null
+++ b/avrdude/stk500generic.h
@@ -0,0 +1,29 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 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
+ */
+
+/* $Id$ */
+
+#ifndef stk500generic_h__
+#define stk500generic_h__
+
+void stk500generic_initpgm (PROGRAMMER * pgm);
+
+#endif
+
+
diff --git a/avrdude/stk500v2.c b/avrdude/stk500v2.c
new file mode 100644
index 00000000..3956223e
--- /dev/null
+++ b/avrdude/stk500v2.c
@@ -0,0 +1,3924 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2005 Erik Walthinsen
+ * Copyright (C) 2002-2004 Brian S. Dean <bsd@bsdhome.com>
+ * Copyright (C) 2006 David Moore
+ * Copyright (C) 2006,2007,2010 Joerg Wunsch <j@uriah.heep.sax.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 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
+ */
+
+/* $Id$ */
+/* Based on Id: stk500.c,v 1.46 2004/12/22 01:52:45 bdean Exp */
+
+/*
+ * avrdude interface for Atmel STK500V2 programmer
+ *
+ * As the AVRISP mkII device is basically an STK500v2 one that can
+ * only talk across USB, and that misses any kind of framing protocol,
+ * this is handled here as well.
+ *
+ * Note: most commands use the "universal command" feature of the
+ * programmer in a "pass through" mode, exceptions are "program
+ * enable", "paged read", and "paged write".
+ *
+ */
+
+#include "ac_cfg.h"
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "avrdude.h"
+#include "avr.h"
+#include "pgm.h"
+#include "stk500_private.h"	// temp until all code converted
+#include "stk500v2_private.h"
+#include "serial.h"
+#include "usbdevs.h"
+
+/*
+ * We need to import enough from the JTAG ICE mkII definitions to be
+ * able to talk to the ICE, query some parameters etc.  The macro
+ * JTAGMKII_PRIVATE_EXPORTED limits the amount of definitions that
+ * jtagmkII_private.h will export, so to avoid conflicts with those
+ * names that are identical to the STK500v2 ones.
+ */
+#include "jtagmkII.h"           // public interfaces from jtagmkII.c
+#define JTAGMKII_PRIVATE_EXPORTED
+#include "jtagmkII_private.h"
+
+#define STK500V2_XTAL 7372800U
+
+#if 0
+#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
+#else
+#define DEBUG(...)
+#endif
+
+#if 0
+#define DEBUGRECV(...) fprintf(stderr, __VA_ARGS__)
+#else
+#define DEBUGRECV(...)
+#endif
+
+enum hvmode
+{
+  PPMODE, HVSPMODE
+};
+
+
+/*
+ * Private data for this programmer.
+ */
+struct pdata
+{
+  /*
+   * See stk500pp_read_byte() for an explanation of the flash and
+   * EEPROM page caches.
+   */
+  unsigned char *flash_pagecache;
+  unsigned long flash_pageaddr;
+  unsigned int flash_pagesize;
+
+  unsigned char *eeprom_pagecache;
+  unsigned long eeprom_pageaddr;
+  unsigned int eeprom_pagesize;
+
+  unsigned char command_sequence;
+
+    enum
+    {
+        PGMTYPE_UNKNOWN,
+        PGMTYPE_STK500,
+        PGMTYPE_AVRISP,
+        PGMTYPE_AVRISP_MKII,
+        PGMTYPE_JTAGICE_MKII,
+        PGMTYPE_STK600,
+    }
+        pgmtype;
+
+  AVRPART *lastpart;
+
+  /*
+   * Chained pdata for the JTAG ICE mkII backend.  This is used when
+   * calling the backend functions for ISP/HVSP/PP programming
+   * functionality of the JTAG ICE mkII and AVR Dragon.
+   */
+  void *chained_pdata;
+};
+
+#define PDATA(pgm) ((struct pdata *)(pgm->cookie))
+
+
+/*
+ * Data structure for displaying STK600 routing and socket cards.
+ */
+struct carddata
+{
+  int id;
+  const char *name;
+};
+
+static const char *pgmname[] =
+{
+  "unknown",
+  "STK500",
+  "AVRISP",
+  "AVRISP mkII",
+  "JTAG ICE mkII",
+  "STK600",
+};
+
+struct jtagispentry
+{
+  unsigned char cmd;
+  unsigned short size;
+#define SZ_READ_FLASH_EE USHRT_MAX
+#define SZ_SPI_MULTI     (USHRT_MAX - 1)
+};
+
+static const struct jtagispentry jtagispcmds[] = {
+  /* generic */
+  { CMD_SET_PARAMETER, 2 },
+  { CMD_GET_PARAMETER, 3 },
+  { CMD_OSCCAL, 2 },
+  { CMD_LOAD_ADDRESS, 2 },
+  /* ISP mode */
+  { CMD_ENTER_PROGMODE_ISP, 2 },
+  { CMD_LEAVE_PROGMODE_ISP, 2 },
+  { CMD_CHIP_ERASE_ISP, 2 },
+  { CMD_PROGRAM_FLASH_ISP, 2 },
+  { CMD_READ_FLASH_ISP, SZ_READ_FLASH_EE },
+  { CMD_PROGRAM_EEPROM_ISP, 2 },
+  { CMD_READ_EEPROM_ISP, SZ_READ_FLASH_EE },
+  { CMD_PROGRAM_FUSE_ISP, 3 },
+  { CMD_READ_FUSE_ISP, 4 },
+  { CMD_PROGRAM_LOCK_ISP, 3 },
+  { CMD_READ_LOCK_ISP, 4 },
+  { CMD_READ_SIGNATURE_ISP, 4 },
+  { CMD_READ_OSCCAL_ISP, 4 },
+  { CMD_SPI_MULTI, SZ_SPI_MULTI },
+  /* all HV modes */
+  { CMD_SET_CONTROL_STACK, 2 },
+  /* HVSP mode */
+  { CMD_ENTER_PROGMODE_HVSP, 2 },
+  { CMD_LEAVE_PROGMODE_HVSP, 2 },
+  { CMD_CHIP_ERASE_HVSP, 2 },
+  { CMD_PROGRAM_FLASH_HVSP, 2 },
+  { CMD_READ_FLASH_HVSP, SZ_READ_FLASH_EE },
+  { CMD_PROGRAM_EEPROM_HVSP, 2 },
+  { CMD_READ_EEPROM_HVSP, SZ_READ_FLASH_EE },
+  { CMD_PROGRAM_FUSE_HVSP, 2 },
+  { CMD_READ_FUSE_HVSP, 3 },
+  { CMD_PROGRAM_LOCK_HVSP, 2 },
+  { CMD_READ_LOCK_HVSP, 3 },
+  { CMD_READ_SIGNATURE_HVSP, 3 },
+  { CMD_READ_OSCCAL_HVSP, 3 },
+  /* PP mode */
+  { CMD_ENTER_PROGMODE_PP, 2 },
+  { CMD_LEAVE_PROGMODE_PP, 2 },
+  { CMD_CHIP_ERASE_PP, 2 },
+  { CMD_PROGRAM_FLASH_PP, 2 },
+  { CMD_READ_FLASH_PP, SZ_READ_FLASH_EE },
+  { CMD_PROGRAM_EEPROM_PP, 2 },
+  { CMD_READ_EEPROM_PP, SZ_READ_FLASH_EE },
+  { CMD_PROGRAM_FUSE_PP, 2 },
+  { CMD_READ_FUSE_PP, 3 },
+  { CMD_PROGRAM_LOCK_PP, 2 },
+  { CMD_READ_LOCK_PP, 3 },
+  { CMD_READ_SIGNATURE_PP, 3 },
+  { CMD_READ_OSCCAL_PP, 3 },
+};
+
+/*
+ * From XML file:
+  <REVISION>
+    <RC_ID_MAJOR>0</RC_ID_MAJOR>
+    <RC_ID_MINOR>56</RC_ID_MINOR>
+    <EC_ID_MAJOR>0</EC_ID_MAJOR>
+    <EC_ID_MINOR>1</EC_ID_MINOR>
+  </REVISION>
+ */
+/*
+ * These two tables can be semi-automatically updated from
+ * targetboards.xml using tools/get-stk600-cards.xsl.
+ */
+static const struct carddata routing_cards[] =
+{
+  { 0x01, "STK600-RC020T-1" },
+  { 0x03, "STK600-RC028T-3" },
+  { 0x05, "STK600-RC040M-5" },
+  { 0x08, "STK600-RC020T-8" },
+  { 0x0A, "STK600-RC040M-4" },
+  { 0x0C, "STK600-RC008T-2" },
+  { 0x0D, "STK600-RC028M-6" },
+  { 0x10, "STK600-RC064M-10" },
+  { 0x11, "STK600-RC100M-11" },
+  { 0x13, "STK600-RC100X-13" },
+  { 0x15, "STK600-RC044X-15" },
+  { 0x18, "STK600-RC100M-18" },
+  { 0x19, "STK600-RCPWM-19" },
+  { 0x1A, "STK600-RC064X-14" },
+  { 0x1B, "STK600-RC032U-20" },
+  { 0x1C, "STK600-RC014T-12" },
+  { 0x1E, "STK600-RC064U-17" },
+  { 0x1F, "STK600-RCuC3B0-21" },
+  { 0x20, "STK600-RCPWM-22" },
+  { 0x21, "STK600-RC020T-23" },
+  { 0x22, "STK600-RC044M-24" },
+  { 0x23, "STK600-RC044U-25" },
+  { 0x24, "STK600-RCPWM-26" },
+  { 0x25, "STK600-RCuC3B48-27" },
+  { 0x27, "STK600-RC032M-29" },
+  { 0x28, "STK600-RC044M-30" },
+  { 0x29, "STK600-RC044M-31" },
+  { 0x2A, "STK600-RC014T-42" },
+  { 0x2B, "STK600-RC020T-43" },
+  { 0x30, "STK600-RCUC3A144-32" },
+  { 0x34, "STK600-RCUC3L0-34" },
+  { 0x38, "STK600-RCUC3C0-36" },
+  { 0x3B, "STK600-RCUC3C0-37" },
+  { 0x3E, "STK600-RCUC3A144-33" },
+  { 0x46, "STK600-RCuC3A100-28" },
+  { 0x55, "STK600-RC064M-9" },
+  { 0x88, "STK600-RCUC3C1-38" },
+  { 0x8B, "STK600-RCUC3C1-39" },
+  { 0xA0, "STK600-RC008T-7" },
+  { 0xB8, "STK600-RCUC3C2-40" },
+  { 0xBB, "STK600-RCUC3C2-41" },
+};
+
+static const struct carddata socket_cards[] =
+{
+  { 0x01, "STK600-TQFP48" },
+  { 0x02, "STK600-TQFP32" },
+  { 0x03, "STK600-TQFP100" },
+  { 0x04, "STK600-SOIC" },
+  { 0x06, "STK600-TQFP144" },
+  { 0x09, "STK600-TinyX3U" },
+  { 0x0C, "STK600-TSSOP44" },
+  { 0x0D, "STK600-TQFP44" },
+  { 0x0E, "STK600-TQFP64-2" },
+  { 0x0F, "STK600-ATMEGA2560" },
+  { 0x15, "STK600-MLF64" },
+  { 0x16, "STK600-ATXMEGAT0" },
+  { 0x18, "QT600-ATMEGA324-QM64" },
+  { 0x19, "STK600-ATMEGA128RFA1" },
+  { 0x1A, "QT600-ATTINY88-QT8" },
+  { 0x1B, "QT600-ATXMEGA128A1-QT16" },
+  { 0x1C, "QT600-AT32UC3L-QM64" },
+  { 0x1D, "STK600-HVE2" },
+  { 0x1E, "STK600-ATTINY10" },
+  { 0x55, "STK600-TQFP64" },
+  { 0x69, "STK600-uC3-144" },
+  { 0xF0, "STK600-ATXMEGA1281A1" },
+  { 0xF1, "STK600-DIP" },
+};
+
+static int stk500v2_getparm(PROGRAMMER * pgm, unsigned char parm, unsigned char * value);
+static int stk500v2_setparm(PROGRAMMER * pgm, unsigned char parm, unsigned char value);
+static int stk500v2_getparm2(PROGRAMMER * pgm, unsigned char parm, unsigned int * value);
+static int stk500v2_setparm2(PROGRAMMER * pgm, unsigned char parm, unsigned int value);
+static int stk500v2_setparm_real(PROGRAMMER * pgm, unsigned char parm, unsigned char value);
+static void stk500v2_print_parms1(PROGRAMMER * pgm, const char * p);
+static int stk500v2_is_page_empty(unsigned int address, int page_size,
+                                  const unsigned char *buf);
+
+static unsigned int stk500v2_mode_for_pagesize(unsigned int pagesize);
+
+static int stk500v2_set_sck_period_mk2(PROGRAMMER * pgm, double v);
+
+static int stk600_set_sck_period(PROGRAMMER * pgm, double v);
+
+static void stk600_setup_xprog(PROGRAMMER * pgm);
+static void stk600_setup_isp(PROGRAMMER * pgm);
+static int stk600_xprog_program_enable(PROGRAMMER * pgm, AVRPART * p);
+
+static void stk500v2_setup(PROGRAMMER * pgm)
+{
+  if ((pgm->cookie = malloc(sizeof(struct pdata))) == 0) {
+    fprintf(stderr,
+	    "%s: stk500v2_setup(): Out of memory allocating private data\n",
+	    progname);
+    exit(1);
+  }
+  memset(pgm->cookie, 0, sizeof(struct pdata));
+  PDATA(pgm)->command_sequence = 1;
+}
+
+static void stk500v2_jtagmkII_setup(PROGRAMMER * pgm)
+{
+  void *mycookie, *theircookie;
+
+  if ((pgm->cookie = malloc(sizeof(struct pdata))) == 0) {
+    fprintf(stderr,
+	    "%s: stk500v2_setup(): Out of memory allocating private data\n",
+	    progname);
+    exit(1);
+  }
+  memset(pgm->cookie, 0, sizeof(struct pdata));
+  PDATA(pgm)->command_sequence = 1;
+
+  /*
+   * Now, have the JTAG ICE mkII backend allocate its own private
+   * data.  Store our own cookie in a safe place for the time being.
+   */
+  mycookie = pgm->cookie;
+  jtagmkII_setup(pgm);
+  theircookie = pgm->cookie;
+  pgm->cookie = mycookie;
+  PDATA(pgm)->chained_pdata = theircookie;
+}
+
+static void stk500v2_teardown(PROGRAMMER * pgm)
+{
+  free(pgm->cookie);
+}
+
+static void stk500v2_jtagmkII_teardown(PROGRAMMER * pgm)
+{
+  void *mycookie;
+
+  mycookie = pgm->cookie;
+  pgm->cookie = PDATA(pgm)->chained_pdata;
+  jtagmkII_teardown(pgm);
+
+  free(mycookie);
+}
+
+
+static unsigned short
+b2_to_u16(unsigned char *b)
+{
+  unsigned short l;
+  l = b[0];
+  l += (unsigned)b[1] << 8;
+
+  return l;
+}
+
+static int stk500v2_send_mk2(PROGRAMMER * pgm, unsigned char * data, size_t len)
+{
+  if (serial_send(&pgm->fd, data, len) != 0) {
+    fprintf(stderr,"%s: stk500_send_mk2(): failed to send command to serial port\n",progname);
+    exit(1);
+  }
+
+  return 0;
+}
+
+static unsigned short get_jtagisp_return_size(unsigned char cmd)
+{
+  int i;
+
+  for (i = 0; i < sizeof jtagispcmds / sizeof jtagispcmds[0]; i++)
+    if (jtagispcmds[i].cmd == cmd)
+      return jtagispcmds[i].size;
+
+  return 0;
+}
+
+/*
+ * Send the data as a JTAG ICE mkII encapsulated ISP packet.
+ * Unlike what AVR067 says, the packet gets a length of our
+ * response buffer prepended, and replies with RSP_SPI_DATA
+ * if successful.
+ */
+static int stk500v2_jtagmkII_send(PROGRAMMER * pgm, unsigned char * data, size_t len)
+{
+  unsigned char *cmdbuf;
+  int rv;
+  unsigned short sz;
+  void *mycookie;
+
+  sz = get_jtagisp_return_size(data[0]);
+  if (sz == 0) {
+    fprintf(stderr, "%s: unsupported encapsulated ISP command: %#x\n",
+	    progname, data[0]);
+    return -1;
+  }
+  if (sz == SZ_READ_FLASH_EE) {
+    /*
+     * For CMND_READ_FLASH_ISP and CMND_READ_EEPROM_ISP, extract the
+     * size of the return data from the request.  Note that the
+     * request itself has the size in big endian format, while we are
+     * supposed to deliver it in little endian.
+     */
+    sz = 3 + (data[1] << 8) + data[2];
+  } else if (sz == SZ_SPI_MULTI) {
+    /*
+     * CMND_SPI_MULTI has the Rx size encoded in its 3rd byte.
+     */
+    sz = 3 + data[2];
+  }
+
+  if ((cmdbuf = malloc(len + 3)) == NULL) {
+    fprintf(stderr, "%s: out of memory for command packet\n",
+            progname);
+    exit(1);
+  }
+  mycookie = pgm->cookie;
+  pgm->cookie = PDATA(pgm)->chained_pdata;
+  cmdbuf[0] = CMND_ISP_PACKET;
+  cmdbuf[1] = sz & 0xff;
+  cmdbuf[2] = (sz >> 8) & 0xff;
+  memcpy(cmdbuf + 3, data, len);
+  rv = jtagmkII_send(pgm, cmdbuf, len + 3);
+  free(cmdbuf);
+  pgm->cookie = mycookie;
+
+  return rv;
+}
+
+static int stk500v2_send(PROGRAMMER * pgm, unsigned char * data, size_t len)
+{
+  unsigned char buf[275 + 6];		// max MESSAGE_BODY of 275 bytes, 6 bytes overhead
+  int i;
+
+  if (PDATA(pgm)->pgmtype == PGMTYPE_AVRISP_MKII ||
+      PDATA(pgm)->pgmtype == PGMTYPE_STK600)
+    return stk500v2_send_mk2(pgm, data, len);
+  else if (PDATA(pgm)->pgmtype == PGMTYPE_JTAGICE_MKII)
+    return stk500v2_jtagmkII_send(pgm, data, len);
+
+  buf[0] = MESSAGE_START;
+  buf[1] = PDATA(pgm)->command_sequence;
+  buf[2] = len / 256;
+  buf[3] = len % 256;
+  buf[4] = TOKEN;
+  memcpy(buf+5, data, len);
+
+  // calculate the XOR checksum
+  buf[5+len] = 0;
+  for (i=0;i<5+len;i++)
+    buf[5+len] ^= buf[i];
+
+  DEBUG("STK500V2: stk500v2_send(");
+  for (i=0;i<len+6;i++) DEBUG("0x%02x ",buf[i]);
+  DEBUG(", %d)\n",len+6);
+
+  if (serial_send(&pgm->fd, buf, len+6) != 0) {
+    fprintf(stderr,"%s: stk500_send(): failed to send command to serial port\n",progname);
+    exit(1);
+  }
+
+  return 0;
+}
+
+
+static int stk500v2_drain(PROGRAMMER * pgm, int display)
+{
+  return serial_drain(&pgm->fd, display);
+}
+
+static int stk500v2_recv_mk2(PROGRAMMER * pgm, unsigned char msg[],
+			     size_t maxsize)
+{
+  int rv;
+
+  rv = serial_recv(&pgm->fd, msg, maxsize);
+  if (rv < 0) {
+    fprintf(stderr, "%s: stk500v2_recv_mk2: error in USB receive\n", progname);
+    return -1;
+  }
+
+  return rv;
+}
+
+static int stk500v2_jtagmkII_recv(PROGRAMMER * pgm, unsigned char msg[],
+                                  size_t maxsize)
+{
+  int rv;
+  unsigned char *jtagmsg;
+  void *mycookie;
+
+  mycookie = pgm->cookie;
+  pgm->cookie = PDATA(pgm)->chained_pdata;
+  rv = jtagmkII_recv(pgm, &jtagmsg);
+  pgm->cookie = mycookie;
+  if (rv <= 0) {
+    fprintf(stderr, "%s: stk500v2_jtagmkII_recv(): error in jtagmkII_recv()\n",
+            progname);
+    return -1;
+  }
+  if (rv - 1 > maxsize) {
+    fprintf(stderr,
+            "%s: stk500v2_jtagmkII_recv(): got %u bytes, have only room for %u bytes\n",
+            progname, (unsigned)rv - 1, (unsigned)maxsize);
+    rv = maxsize;
+  }
+  switch (jtagmsg[0]) {
+  case RSP_SPI_DATA:
+    break;
+  case RSP_FAILED:
+    fprintf(stderr, "%s: stk500v2_jtagmkII_recv(): failed\n",
+	    progname);
+    return -1;
+  case RSP_ILLEGAL_MCU_STATE:
+    fprintf(stderr, "%s: stk500v2_jtagmkII_recv(): illegal MCU state\n",
+	    progname);
+    return -1;
+  default:
+    fprintf(stderr, "%s: stk500v2_jtagmkII_recv(): unknown status %d\n",
+	    progname, jtagmsg[0]);
+    return -1;
+  }
+  memcpy(msg, jtagmsg + 1, rv - 1);
+  return rv;
+}
+
+static int stk500v2_recv(PROGRAMMER * pgm, unsigned char msg[], size_t maxsize) {
+  enum states { sINIT, sSTART, sSEQNUM, sSIZE1, sSIZE2, sTOKEN, sDATA, sCSUM, sDONE }  state = sSTART;
+  unsigned int msglen = 0;
+  unsigned int curlen = 0;
+  int timeout = 0;
+  unsigned char c, checksum = 0;
+
+  long timeoutval = 5;		// seconds
+  struct timeval tv;
+  double tstart, tnow;
+
+  if (PDATA(pgm)->pgmtype == PGMTYPE_AVRISP_MKII ||
+      PDATA(pgm)->pgmtype == PGMTYPE_STK600)
+    return stk500v2_recv_mk2(pgm, msg, maxsize);
+  else if (PDATA(pgm)->pgmtype == PGMTYPE_JTAGICE_MKII)
+    return stk500v2_jtagmkII_recv(pgm, msg, maxsize);
+
+  DEBUG("STK500V2: stk500v2_recv(): ");
+
+  gettimeofday(&tv, NULL);
+  tstart = tv.tv_sec;
+
+  while ( (state != sDONE ) && (!timeout) ) {
+    if (serial_recv(&pgm->fd, &c, 1) < 0)
+      goto timedout;
+    DEBUG("0x%02x ",c);
+    checksum ^= c;
+
+    switch (state) {
+      case sSTART:
+        DEBUGRECV("hoping for start token...");
+        if (c == MESSAGE_START) {
+          DEBUGRECV("got it\n");
+          checksum = MESSAGE_START;
+          state = sSEQNUM;
+        } else
+          DEBUGRECV("sorry\n");
+        break;
+      case sSEQNUM:
+        DEBUGRECV("hoping for sequence...\n");
+        if (c == PDATA(pgm)->command_sequence) {
+          DEBUGRECV("got it, incrementing\n");
+          state = sSIZE1;
+          PDATA(pgm)->command_sequence++;
+        } else {
+          DEBUGRECV("sorry\n");
+          state = sSTART;
+        }
+        break;
+      case sSIZE1:
+        DEBUGRECV("hoping for size LSB\n");
+        msglen = (unsigned)c * 256;
+        state = sSIZE2;
+        break;
+      case sSIZE2:
+        DEBUGRECV("hoping for size MSB...");
+        msglen += (unsigned)c;
+        DEBUG(" msg is %u bytes\n",msglen);
+        state = sTOKEN;
+        break;
+      case sTOKEN:
+        if (c == TOKEN) state = sDATA;
+        else state = sSTART;
+        break;
+      case sDATA:
+        if (curlen < maxsize) {
+          msg[curlen] = c;
+        } else {
+          fprintf(stderr, "%s: stk500v2_recv(): buffer too small, received %d byte into %u byte buffer\n",
+                  progname,curlen,(unsigned int)maxsize);
+          return -2;
+        }
+        if ((curlen == 0) && (msg[0] == ANSWER_CKSUM_ERROR)) {
+          fprintf(stderr, "%s: stk500v2_recv(): previous packet sent with wrong checksum\n",
+                  progname);
+          return -3;
+        }
+        curlen++;
+        if (curlen == msglen) state = sCSUM;
+        break;
+      case sCSUM:
+        if (checksum == 0) {
+          state = sDONE;
+        } else {
+          state = sSTART;
+          fprintf(stderr, "%s: stk500v2_recv(): checksum error\n",
+                  progname);
+          return -4;
+        }
+        break;
+      default:
+        fprintf(stderr, "%s: stk500v2_recv(): unknown state\n",
+                progname);
+        return -5;
+     } /* switch */
+
+     gettimeofday(&tv, NULL);
+     tnow = tv.tv_sec;
+     if (tnow-tstart > timeoutval) {			// wuff - signed/unsigned/overflow
+      timedout:
+       fprintf(stderr, "%s: stk500_2_ReceiveMessage(): timeout\n",
+               progname);
+       return -1;
+     }
+
+  } /* while */
+  DEBUG("\n");
+
+  return (int)(msglen+6);
+}
+
+
+
+static int stk500v2_getsync(PROGRAMMER * pgm) {
+  int tries = 0;
+  unsigned char buf[1], resp[32];
+  int status;
+
+  DEBUG("STK500V2: stk500v2_getsync()\n");
+
+  if (PDATA(pgm)->pgmtype == PGMTYPE_JTAGICE_MKII)
+    return 0;
+
+retry:
+  tries++;
+
+  // send the sync command and see if we can get there
+  buf[0] = CMD_SIGN_ON;
+  stk500v2_send(pgm, buf, 1);
+
+  // try to get the response back and see where we got
+  status = stk500v2_recv(pgm, resp, sizeof(resp));
+
+  // if we got bytes returned, check to see what came back
+  if (status > 0) {
+    if ((resp[0] == CMD_SIGN_ON) && (resp[1] == STATUS_CMD_OK) &&
+	(status > 3)) {
+      // success!
+      unsigned int siglen = resp[2];
+      if (siglen >= strlen("STK500_2") &&
+	  memcmp(resp + 3, "STK500_2", strlen("STK500_2")) == 0) {
+	PDATA(pgm)->pgmtype = PGMTYPE_STK500;
+      } else if (siglen >= strlen("AVRISP_2") &&
+		 memcmp(resp + 3, "AVRISP_2", strlen("AVRISP_2")) == 0) {
+	PDATA(pgm)->pgmtype = PGMTYPE_AVRISP;
+      } else if (siglen >= strlen("AVRISP_MK2") &&
+		 memcmp(resp + 3, "AVRISP_MK2", strlen("AVRISP_MK2")) == 0) {
+	PDATA(pgm)->pgmtype = PGMTYPE_AVRISP_MKII;
+      } else if (siglen >= strlen("STK600") &&
+	  memcmp(resp + 3, "STK600", strlen("STK600")) == 0) {
+	PDATA(pgm)->pgmtype = PGMTYPE_STK600;
+      } else {
+	resp[siglen + 3] = 0;
+	if (verbose)
+	  fprintf(stderr,
+		  "%s: stk500v2_getsync(): got response from unknown "
+		  "programmer %s, assuming STK500\n",
+		  progname, resp + 3);
+	PDATA(pgm)->pgmtype = PGMTYPE_STK500;
+      }
+      if (verbose >= 3)
+	fprintf(stderr,
+		"%s: stk500v2_getsync(): found %s programmer\n",
+		progname, pgmname[PDATA(pgm)->pgmtype]);
+      return 0;
+    } else {
+      if (tries > 33) {
+        fprintf(stderr,
+                "%s: stk500v2_getsync(): can't communicate with device: resp=0x%02x\n",
+                progname, resp[0]);
+        return -6;
+      } else
+        goto retry;
+    }
+
+  // or if we got a timeout
+  } else if (status == -1) {
+    if (tries > 33) {
+      fprintf(stderr,"%s: stk500v2_getsync(): timeout communicating with programmer\n",
+              progname);
+      return -1;
+    } else
+      goto retry;
+
+  // or any other error
+  } else {
+    if (tries > 33) {
+      fprintf(stderr,"%s: stk500v2_getsync(): error communicating with programmer: (%d)\n",
+              progname,status);
+    } else
+      goto retry;
+  }
+
+  return 0;
+}
+
+static int stk500v2_command(PROGRAMMER * pgm, unsigned char * buf,
+                            size_t len, size_t maxlen) {
+  int i;
+  int tries = 0;
+  int status;
+
+  DEBUG("STK500V2: stk500v2_command(");
+  for (i=0;i<len;i++) DEBUG("0x%02hhx ",buf[i]);
+  DEBUG(", %d)\n",len);
+
+retry:
+  tries++;
+
+  // send the command to the programmer
+  stk500v2_send(pgm,buf,len);
+  // attempt to read the status back
+  status = stk500v2_recv(pgm,buf,maxlen);
+
+  // if we got a successful readback, return
+  if (status > 0) {
+    DEBUG(" = %d\n",status);
+    if (status < 2) {
+      fprintf(stderr, "%s: stk500v2_command(): short reply\n", progname);
+      return -1;
+    }
+    if (buf[0] == CMD_XPROG_SETMODE || buf[0] == CMD_XPROG) {
+        /*
+         * Decode XPROG wrapper errors.
+         */
+        const char *msg;
+        int i;
+
+        /*
+         * For CMD_XPROG_SETMODE, the status is returned in buf[1].
+         * For CMD_XPROG, buf[1] contains the XPRG_CMD_* command, and
+         * buf[2] contains the status.
+         */
+        i = buf[0] == CMD_XPROG_SETMODE? 1: 2;
+
+        if (buf[i] != XPRG_ERR_OK) {
+            switch (buf[i]) {
+            case XPRG_ERR_FAILED:   msg = "Failed"; break;
+            case XPRG_ERR_COLLISION: msg = "Collision"; break;
+            case XPRG_ERR_TIMEOUT:  msg = "Timeout"; break;
+            default:                msg = "Unknown"; break;
+            }
+            fprintf(stderr, "%s: stk500v2_command(): error in %s: %s\n",
+                    progname,
+                    (buf[0] == CMD_XPROG_SETMODE? "CMD_XPROG_SETMODE": "CMD_XPROG"),
+                    msg);
+            return -1;
+        }
+        return 0;
+    } else {
+        /*
+         * Decode STK500v2 errors.
+         */
+        if (buf[1] == STATUS_CMD_OK)
+            return status;
+        if (buf[1] == STATUS_CMD_FAILED)
+            fprintf(stderr, "%s: stk500v2_command(): command failed\n", progname);
+        else
+            fprintf(stderr, "%s: stk500v2_command(): unknown status 0x%02x\n",
+                    progname, buf[1]);
+        return -1;
+    }
+  }
+
+  // otherwise try to sync up again
+  status = stk500v2_getsync(pgm);
+  if (status != 0) {
+    if (tries > 33) {
+      fprintf(stderr,"%s: stk500v2_command(): failed miserably to execute command 0x%02x\n",
+              progname,buf[0]);
+      return -1;
+    } else
+      goto retry;
+  }
+
+  DEBUG(" = 0\n");
+  return 0;
+}
+
+static int stk500v2_cmd(PROGRAMMER * pgm, unsigned char cmd[4],
+                        unsigned char res[4])
+{
+  unsigned char buf[8];
+  int result;
+
+  DEBUG("STK500V2: stk500v2_cmd(%02x,%02x,%02x,%02x)\n",cmd[0],cmd[1],cmd[2],cmd[3]);
+
+  buf[0] = CMD_SPI_MULTI;
+  buf[1] = 4;
+  buf[2] = 4;
+  buf[3] = 0;
+  buf[4] = cmd[0];
+  buf[5] = cmd[1];
+  buf[6] = cmd[2];
+  buf[7] = cmd[3];
+
+  result = stk500v2_command(pgm, buf, 8, sizeof(buf));
+  if (result < 0) {
+    fprintf(stderr, "%s: stk500v2_cmd(): failed to send command\n",
+            progname);
+    return -1;
+  } else if (result < 6) {
+    fprintf(stderr, "%s: stk500v2_cmd(): short reply, len = %d\n",
+            progname, result);
+    return -1;
+  }
+
+  res[0] = buf[2];
+  res[1] = buf[3];
+  res[2] = buf[4];
+  res[3] = buf[5];
+
+  return 0;
+}
+
+
+/*
+ * issue the 'chip erase' command to the AVR device
+ */
+static int stk500v2_chip_erase(PROGRAMMER * pgm, AVRPART * p)
+{
+  int result;
+  unsigned char buf[16];
+
+  if (p->op[AVR_OP_CHIP_ERASE] == NULL) {
+    fprintf(stderr, "%s: stk500v2_chip_erase: chip erase instruction not defined for part \"%s\"\n",
+            progname, p->desc);
+    return -1;
+  }
+
+  pgm->pgm_led(pgm, ON);
+
+  buf[0] = CMD_CHIP_ERASE_ISP;
+  buf[1] = p->chip_erase_delay / 1000;
+  buf[2] = 0;	// use delay (?)
+  avr_set_bits(p->op[AVR_OP_CHIP_ERASE], buf+3);
+  result = stk500v2_command(pgm, buf, 7, sizeof(buf));
+  usleep(p->chip_erase_delay);
+  pgm->initialize(pgm, p);
+
+  pgm->pgm_led(pgm, OFF);
+
+  return result >= 0? 0: -1;
+}
+
+/*
+ * issue the 'chip erase' command to the AVR device, generic HV mode
+ */
+static int stk500hv_chip_erase(PROGRAMMER * pgm, AVRPART * p, enum hvmode mode)
+{
+  int result;
+  unsigned char buf[3];
+
+  pgm->pgm_led(pgm, ON);
+
+  if (mode == PPMODE) {
+    buf[0] = CMD_CHIP_ERASE_PP;
+    buf[1] = p->chiperasepulsewidth;
+    buf[2] = p->chiperasepolltimeout;
+  } else {
+    buf[0] = CMD_CHIP_ERASE_HVSP;
+    buf[1] = p->chiperasepolltimeout;
+    buf[2] = p->chiperasetime;
+  }
+  result = stk500v2_command(pgm, buf, 3, sizeof(buf));
+  usleep(p->chip_erase_delay);
+  pgm->initialize(pgm, p);
+
+  pgm->pgm_led(pgm, OFF);
+
+  return result >= 0? 0: -1;
+}
+
+/*
+ * issue the 'chip erase' command to the AVR device, parallel mode
+ */
+static int stk500pp_chip_erase(PROGRAMMER * pgm, AVRPART * p)
+{
+  return stk500hv_chip_erase(pgm, p, PPMODE);
+}
+
+/*
+ * issue the 'chip erase' command to the AVR device, HVSP mode
+ */
+static int stk500hvsp_chip_erase(PROGRAMMER * pgm, AVRPART * p)
+{
+  return stk500hv_chip_erase(pgm, p, HVSPMODE);
+}
+
+static struct
+{
+  unsigned int state;
+  const char *description;
+} connection_status[] =
+{
+  { STATUS_CONN_FAIL_MOSI, "MOSI fail" },
+  { STATUS_CONN_FAIL_RST, "RST fail" },
+  { STATUS_CONN_FAIL_SCK, "SCK fail" },
+  { STATUS_TGT_NOT_DETECTED, "Target not detected" },
+  { STATUS_TGT_REVERSE_INSERTED, "Target reverse inserted" },
+  { STATUS_CONN_FAIL_MOSI | STATUS_CONN_FAIL_RST,
+    "MOSI and RST fail" },
+  { STATUS_CONN_FAIL_MOSI | STATUS_CONN_FAIL_RST | STATUS_CONN_FAIL_SCK,
+    "MOSI, RST, and SCK fail" },
+  { STATUS_CONN_FAIL_RST | STATUS_CONN_FAIL_SCK,
+    "RST and SCK fail" },
+  { STATUS_CONN_FAIL_MOSI | STATUS_CONN_FAIL_SCK,
+    "MOSI and SCK fail" },
+};
+
+/*
+ * issue the 'program enable' command to the AVR device
+ */
+static int stk500v2_program_enable(PROGRAMMER * pgm, AVRPART * p)
+{
+  unsigned char buf[16];
+  size_t i;
+  const char *msg;
+  int rv;
+
+  PDATA(pgm)->lastpart = p;
+
+  if (p->op[AVR_OP_PGM_ENABLE] == NULL) {
+    fprintf(stderr, "%s: stk500v2_program_enable(): program enable instruction not defined for part \"%s\"\n",
+	    progname, p->desc);
+    return -1;
+  }
+
+  if (PDATA(pgm)->pgmtype == PGMTYPE_STK500 ||
+      PDATA(pgm)->pgmtype == PGMTYPE_STK600)
+      /* Activate AVR-style (low active) RESET */
+      stk500v2_setparm_real(pgm, PARAM_RESET_POLARITY, 0x01);
+
+  if (PDATA(pgm)->pgmtype == PGMTYPE_STK600) {
+    buf[0] = CMD_CHECK_TARGET_CONNECTION;
+    if (stk500v2_command(pgm, buf, 1, sizeof(buf)) < 0) {
+      fprintf(stderr, "%s: stk500v2_program_enable(): cannot get connection status\n",
+            progname);
+      return -1;
+    }
+    if (buf[2] != STATUS_ISP_READY) {
+      msg = "Unknown";
+
+      for (i = 0;
+           i < sizeof connection_status / sizeof connection_status[0];
+           i++)
+        if (connection_status[i].state == (unsigned)buf[2]) {
+          msg = connection_status[i].description;
+          break;
+        }
+
+      fprintf(stderr, "%s: stk500v2_program_enable():"
+              " bad STK600 connection status: %s (0x%02x)\n",
+            progname, msg, buf[2]);
+      return -1;
+    }
+  }
+
+  buf[0] = CMD_ENTER_PROGMODE_ISP;
+  buf[1] = p->timeout;
+  buf[2] = p->stabdelay;
+  buf[3] = p->cmdexedelay;
+  buf[4] = p->synchloops;
+  buf[5] = p->bytedelay;
+  buf[6] = p->pollvalue;
+  buf[7] = p->pollindex;
+  avr_set_bits(p->op[AVR_OP_PGM_ENABLE], buf+8);
+  buf[10] = buf[11] = 0;
+
+  rv = stk500v2_command(pgm, buf, 12, sizeof(buf));
+
+  if (rv < 0) {
+    buf[0] = CMD_CHECK_TARGET_CONNECTION;
+    if (stk500v2_command(pgm, buf, 1, sizeof(buf)) < 0) {
+      fprintf(stderr, "%s: stk500v2_program_enable(): cannot get connection status\n",
+            progname);
+      return -1;
+    }
+
+    msg = "Unknown";
+
+    for (i = 0;
+	 i < sizeof connection_status / sizeof connection_status[0];
+	 i++)
+      if (connection_status[i].state == (unsigned)buf[2]) {
+	msg = connection_status[i].description;
+	break;
+      }
+
+    fprintf(stderr, "%s: stk500v2_program_enable():"
+	    " bad STK600 connection status: %s (0x%02x)\n",
+            progname, msg, buf[2]);
+  }
+
+  return rv;
+}
+
+/*
+ * issue the 'program enable' command to the AVR device, parallel mode
+ */
+static int stk500pp_program_enable(PROGRAMMER * pgm, AVRPART * p)
+{
+  unsigned char buf[16];
+
+  PDATA(pgm)->lastpart = p;
+
+  buf[0] = CMD_ENTER_PROGMODE_PP;
+  buf[1] = p->hventerstabdelay;
+  buf[2] = p->progmodedelay;
+  buf[3] = p->latchcycles;
+  buf[4] = p->togglevtg;
+  buf[5] = p->poweroffdelay;
+  buf[6] = p->resetdelayms;
+  buf[7] = p->resetdelayus;
+
+  return stk500v2_command(pgm, buf, 8, sizeof(buf));
+}
+
+/*
+ * issue the 'program enable' command to the AVR device, HVSP mode
+ */
+static int stk500hvsp_program_enable(PROGRAMMER * pgm, AVRPART * p)
+{
+  unsigned char buf[16];
+
+  PDATA(pgm)->lastpart = p;
+
+  buf[0] = PDATA(pgm)->pgmtype == PGMTYPE_STK600?
+  CMD_ENTER_PROGMODE_HVSP_STK600:
+  CMD_ENTER_PROGMODE_HVSP;
+  buf[1] = p->hventerstabdelay;
+  buf[2] = p->hvspcmdexedelay;
+  buf[3] = p->synchcycles;
+  buf[4] = p->latchcycles;
+  buf[5] = p->togglevtg;
+  buf[6] = p->poweroffdelay;
+  buf[7] = p->resetdelayms;
+  buf[8] = p->resetdelayus;
+
+  return stk500v2_command(pgm, buf, 9, sizeof(buf));
+}
+
+
+
+/*
+ * initialize the AVR device and prepare it to accept commands
+ */
+static int stk500v2_initialize(PROGRAMMER * pgm, AVRPART * p)
+{
+
+  if ((PDATA(pgm)->pgmtype == PGMTYPE_STK600 ||
+       PDATA(pgm)->pgmtype == PGMTYPE_AVRISP_MKII ||
+       PDATA(pgm)->pgmtype == PGMTYPE_JTAGICE_MKII) != 0
+      && (p->flags & (AVRPART_HAS_PDI | AVRPART_HAS_TPI)) != 0) {
+    /*
+     * This is an ATxmega device, must use XPROG protocol for the
+     * remaining actions.
+     */
+    stk600_setup_xprog(pgm);
+  } else {
+    stk600_setup_isp(pgm);
+  }
+
+  return pgm->program_enable(pgm, p);
+}
+
+
+/*
+ * initialize the AVR device and prepare it to accept commands, generic HV mode
+ */
+static int stk500hv_initialize(PROGRAMMER * pgm, AVRPART * p, enum hvmode mode)
+{
+  unsigned char buf[CTL_STACK_SIZE + 1];
+  int result;
+  LNODEID ln;
+  AVRMEM * m;
+
+  if (p->ctl_stack_type != (mode == PPMODE? CTL_STACK_PP: CTL_STACK_HVSP)) {
+    fprintf(stderr,
+	    "%s: stk500hv_initialize(): "
+	    "%s programming control stack not defined for part \"%s\"\n",
+            progname,
+	    (mode == PPMODE? "parallel": "high-voltage serial"),
+	    p->desc);
+    return -1;
+  }
+
+  buf[0] = CMD_SET_CONTROL_STACK;
+  memcpy(buf + 1, p->controlstack, CTL_STACK_SIZE);
+
+  result = stk500v2_command(pgm, buf, CTL_STACK_SIZE + 1, sizeof(buf));
+
+  if (result < 0) {
+    fprintf(stderr,
+	    "%s: stk500pp_initalize(): "
+	    "failed to set control stack\n",
+            progname);
+    return -1;
+  }
+
+  /*
+   * Examine the avrpart's memory definitions, and initialize the page
+   * caches.  For devices/memory that are not page oriented, treat
+   * them as page size 1 for EEPROM, and 2 for flash.
+   */
+  PDATA(pgm)->flash_pagesize = 2;
+  PDATA(pgm)->eeprom_pagesize = 1;
+  for (ln = lfirst(p->mem); ln; ln = lnext(ln)) {
+    m = ldata(ln);
+    if (strcmp(m->desc, "flash") == 0) {
+      if (m->page_size > 0)
+	PDATA(pgm)->flash_pagesize = m->page_size;
+    } else if (strcmp(m->desc, "eeprom") == 0) {
+      if (m->page_size > 0)
+	PDATA(pgm)->eeprom_pagesize = m->page_size;
+    }
+  }
+  free(PDATA(pgm)->flash_pagecache);
+  free(PDATA(pgm)->eeprom_pagecache);
+  if ((PDATA(pgm)->flash_pagecache = malloc(PDATA(pgm)->flash_pagesize)) == NULL) {
+    fprintf(stderr, "%s: stk500pp_initialize(): Out of memory\n",
+	    progname);
+    return -1;
+  }
+  if ((PDATA(pgm)->eeprom_pagecache = malloc(PDATA(pgm)->eeprom_pagesize)) == NULL) {
+    fprintf(stderr, "%s: stk500pp_initialize(): Out of memory\n",
+	    progname);
+    free(PDATA(pgm)->flash_pagecache);
+    return -1;
+  }
+  PDATA(pgm)->flash_pageaddr = PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L;
+
+  return pgm->program_enable(pgm, p);
+}
+
+/*
+ * initialize the AVR device and prepare it to accept commands, PP mode
+ */
+static int stk500pp_initialize(PROGRAMMER * pgm, AVRPART * p)
+{
+  return stk500hv_initialize(pgm, p, PPMODE);
+}
+
+/*
+ * initialize the AVR device and prepare it to accept commands, HVSP mode
+ */
+static int stk500hvsp_initialize(PROGRAMMER * pgm, AVRPART * p)
+{
+  return stk500hv_initialize(pgm, p, HVSPMODE);
+}
+
+static void stk500v2_disable(PROGRAMMER * pgm)
+{
+  unsigned char buf[16];
+  int result;
+
+  buf[0] = CMD_LEAVE_PROGMODE_ISP;
+  buf[1] = 1; // preDelay;
+  buf[2] = 1; // postDelay;
+
+  result = stk500v2_command(pgm, buf, 3, sizeof(buf));
+
+  if (result < 0) {
+    fprintf(stderr,
+            "%s: stk500v2_disable(): failed to leave programming mode\n",
+            progname);
+  }
+
+  return;
+}
+
+/*
+ * Leave programming mode, generic HV mode
+ */
+static void stk500hv_disable(PROGRAMMER * pgm, enum hvmode mode)
+{
+  unsigned char buf[16];
+  int result;
+
+  free(PDATA(pgm)->flash_pagecache);
+  PDATA(pgm)->flash_pagecache = NULL;
+  free(PDATA(pgm)->eeprom_pagecache);
+  PDATA(pgm)->eeprom_pagecache = NULL;
+
+  buf[0] = mode == PPMODE? CMD_LEAVE_PROGMODE_PP:
+  (PDATA(pgm)->pgmtype == PGMTYPE_STK600?
+   CMD_LEAVE_PROGMODE_HVSP_STK600:
+   CMD_LEAVE_PROGMODE_HVSP);
+  buf[1] = 15;  // p->hvleavestabdelay;
+  buf[2] = 15;  // p->resetdelay;
+
+  result = stk500v2_command(pgm, buf, 3, sizeof(buf));
+
+  if (result < 0) {
+    fprintf(stderr,
+	    "%s: stk500hv_disable(): "
+	    "failed to leave programming mode\n",
+            progname);
+    exit(1);
+  }
+
+  return;
+}
+
+/*
+ * Leave programming mode, PP mode
+ */
+static void stk500pp_disable(PROGRAMMER * pgm)
+{
+  stk500hv_disable(pgm, PPMODE);
+}
+
+/*
+ * Leave programming mode, HVSP mode
+ */
+static void stk500hvsp_disable(PROGRAMMER * pgm)
+{
+  stk500hv_disable(pgm, HVSPMODE);
+}
+
+static void stk500v2_enable(PROGRAMMER * pgm)
+{
+  return;
+}
+
+
+static int stk500v2_open(PROGRAMMER * pgm, char * port)
+{
+  long baud = 115200;
+
+  DEBUG("STK500V2: stk500v2_open()\n");
+
+  if (pgm->baudrate)
+    baud = pgm->baudrate;
+
+  PDATA(pgm)->pgmtype = PGMTYPE_UNKNOWN;
+
+  if(strcasecmp(port, "avrdoper") == 0){
+#if defined(HAVE_LIBUSB) || defined(WIN32NATIVE)
+    serdev = &avrdoper_serdev;
+    PDATA(pgm)->pgmtype = PGMTYPE_STK500;
+#else
+    fprintf(stderr, "avrdude was compiled without usb support.\n");
+    return -1;
+#endif
+  }
+
+  /*
+   * If the port name starts with "usb", divert the serial routines
+   * to the USB ones.  The serial_open() function for USB overrides
+   * the meaning of the "baud" parameter to be the USB device ID to
+   * search for.
+   */
+  if (strncmp(port, "usb", 3) == 0) {
+#if defined(HAVE_LIBUSB)
+    serdev = &usb_serdev_frame;
+    baud = USB_DEVICE_AVRISPMKII;
+    PDATA(pgm)->pgmtype = PGMTYPE_AVRISP_MKII;
+    pgm->set_sck_period = stk500v2_set_sck_period_mk2;
+#else
+    fprintf(stderr, "avrdude was compiled without usb support.\n");
+    return -1;
+#endif
+  }
+
+  strcpy(pgm->port, port);
+  serial_open(port, baud, &pgm->fd);
+
+  /*
+   * drain any extraneous input
+   */
+  stk500v2_drain(pgm, 0);
+
+  stk500v2_getsync(pgm);
+
+  stk500v2_drain(pgm, 0);
+
+  if (pgm->bitclock != 0.0) {
+    if (pgm->set_sck_period(pgm, pgm->bitclock) != 0)
+      return -1;
+  }
+
+  return 0;
+}
+
+
+static int stk600_open(PROGRAMMER * pgm, char * port)
+{
+  long baud = 115200;
+
+  DEBUG("STK500V2: stk600_open()\n");
+
+  if (pgm->baudrate)
+    baud = pgm->baudrate;
+
+  PDATA(pgm)->pgmtype = PGMTYPE_UNKNOWN;
+
+  /*
+   * If the port name starts with "usb", divert the serial routines
+   * to the USB ones.  The serial_open() function for USB overrides
+   * the meaning of the "baud" parameter to be the USB device ID to
+   * search for.
+   */
+  if (strncmp(port, "usb", 3) == 0) {
+#if defined(HAVE_LIBUSB)
+    serdev = &usb_serdev_frame;
+    baud = USB_DEVICE_STK600;
+    PDATA(pgm)->pgmtype = PGMTYPE_STK600;
+    pgm->set_sck_period = stk600_set_sck_period;
+#else
+    fprintf(stderr, "avrdude was compiled without usb support.\n");
+    return -1;
+#endif
+  }
+
+  strcpy(pgm->port, port);
+  serial_open(port, baud, &pgm->fd);
+
+  /*
+   * drain any extraneous input
+   */
+  stk500v2_drain(pgm, 0);
+
+  stk500v2_getsync(pgm);
+
+  stk500v2_drain(pgm, 0);
+
+  if (pgm->bitclock != 0.0) {
+    if (pgm->set_sck_period(pgm, pgm->bitclock) != 0)
+      return -1;
+  }
+
+  return 0;
+}
+
+
+static void stk500v2_close(PROGRAMMER * pgm)
+{
+  DEBUG("STK500V2: stk500v2_close()\n");
+
+  serial_close(&pgm->fd);
+  pgm->fd.ifd = -1;
+}
+
+
+static int stk500v2_loadaddr(PROGRAMMER * pgm, unsigned int addr)
+{
+  unsigned char buf[16];
+  int result;
+
+  DEBUG("STK500V2: stk500v2_loadaddr(%d)\n",addr);
+
+  buf[0] = CMD_LOAD_ADDRESS;
+  buf[1] = (addr >> 24) & 0xff;
+  buf[2] = (addr >> 16) & 0xff;
+  buf[3] = (addr >> 8) & 0xff;
+  buf[4] = addr & 0xff;
+
+  result = stk500v2_command(pgm, buf, 5, sizeof(buf));
+
+  if (result < 0) {
+    fprintf(stderr,
+            "%s: stk500v2_loadaddr(): failed to set load address\n",
+            progname);
+    return -1;
+  }
+
+  return 0;
+}
+
+
+/*
+ * Read a single byte, generic HV mode
+ */
+static int stk500hv_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+			      unsigned long addr, unsigned char * value,
+			      enum hvmode mode)
+{
+  int result, cmdlen = 2;
+  unsigned char buf[266];
+  unsigned long paddr = 0UL, *paddr_ptr = NULL;
+  unsigned int pagesize = 0, use_ext_addr = 0, addrshift = 0;
+  unsigned char *cache_ptr = NULL;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: stk500hv_read_byte(.., %s, 0x%lx, ...)\n",
+	    progname, mem->desc, addr);
+
+  if (strcmp(mem->desc, "flash") == 0) {
+    buf[0] = mode == PPMODE? CMD_READ_FLASH_PP: CMD_READ_FLASH_HVSP;
+    cmdlen = 3;
+    pagesize = mem->page_size;
+    if (pagesize == 0)
+      pagesize = 2;
+    paddr = addr & ~(pagesize - 1);
+    paddr_ptr = &PDATA(pgm)->flash_pageaddr;
+    cache_ptr = PDATA(pgm)->flash_pagecache;
+    addrshift = 1;
+    /*
+     * If bit 31 is set, this indicates that the following read/write
+     * operation will be performed on a memory that is larger than
+     * 64KBytes. This is an indication to STK500 that a load extended
+     * address must be executed.
+     */
+    if (mem->op[AVR_OP_LOAD_EXT_ADDR] != NULL) {
+      use_ext_addr = (1U << 31);
+    }
+  } else if (strcmp(mem->desc, "eeprom") == 0) {
+    buf[0] = mode == PPMODE? CMD_READ_EEPROM_PP: CMD_READ_EEPROM_HVSP;
+    cmdlen = 3;
+    pagesize = mem->page_size;
+    if (pagesize == 0)
+      pagesize = 1;
+    paddr = addr & ~(pagesize - 1);
+    paddr_ptr = &PDATA(pgm)->eeprom_pageaddr;
+    cache_ptr = PDATA(pgm)->eeprom_pagecache;
+  } else if (strcmp(mem->desc, "lfuse") == 0 ||
+	     strcmp(mem->desc, "fuse") == 0) {
+    buf[0] = mode == PPMODE? CMD_READ_FUSE_PP: CMD_READ_FUSE_HVSP;
+    addr = 0;
+  } else if (strcmp(mem->desc, "hfuse") == 0) {
+    buf[0] = mode == PPMODE? CMD_READ_FUSE_PP: CMD_READ_FUSE_HVSP;
+    addr = 1;
+  } else if (strcmp(mem->desc, "efuse") == 0) {
+    buf[0] = mode == PPMODE? CMD_READ_FUSE_PP: CMD_READ_FUSE_HVSP;
+    addr = 2;
+  } else if (strcmp(mem->desc, "lock") == 0) {
+    buf[0] = mode == PPMODE? CMD_READ_LOCK_PP: CMD_READ_LOCK_HVSP;
+  } else if (strcmp(mem->desc, "calibration") == 0) {
+    buf[0] = mode == PPMODE? CMD_READ_OSCCAL_PP: CMD_READ_OSCCAL_HVSP;
+  } else if (strcmp(mem->desc, "signature") == 0) {
+    buf[0] = mode == PPMODE? CMD_READ_SIGNATURE_PP: CMD_READ_SIGNATURE_HVSP;
+  }
+
+  /*
+   * In HV mode, we have to use paged reads for flash and
+   * EEPROM, and cache the results in a page cache.
+   *
+   * Page cache validation is based on "{flash,eeprom}_pageaddr"
+   * (holding the base address of the most recent cache fill
+   * operation).  This variable is set to (unsigned long)-1L when the
+   * cache needs to be invalidated.
+   */
+  if (pagesize && paddr == *paddr_ptr) {
+    *value = cache_ptr[addr & (pagesize - 1)];
+    return 0;
+  }
+
+  if (cmdlen == 3) {
+    /* long command, fill in # of bytes */
+    buf[1] = (pagesize >> 8) & 0xff;
+    buf[2] = pagesize & 0xff;
+
+    /* flash and EEPROM reads require the load address command */
+    if (stk500v2_loadaddr(pgm, use_ext_addr | (paddr >> addrshift)) < 0)
+        return -1;
+  } else {
+    buf[1] = addr;
+  }
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: stk500hv_read_byte(): Sending read memory command: ",
+	    progname);
+
+  result = stk500v2_command(pgm, buf, cmdlen, sizeof(buf));
+
+  if (result < 0) {
+    fprintf(stderr,
+	    "%s: stk500hv_read_byte(): "
+	    "timeout/error communicating with programmer\n",
+	    progname);
+    return -1;
+  }
+
+  if (pagesize) {
+    *paddr_ptr = paddr;
+    memcpy(cache_ptr, buf + 2, pagesize);
+    *value = cache_ptr[addr & (pagesize - 1)];
+  } else {
+    *value = buf[2];
+  }
+
+  return 0;
+}
+
+/*
+ * Read a single byte, PP mode
+ */
+static int stk500pp_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+			      unsigned long addr, unsigned char * value)
+{
+  return stk500hv_read_byte(pgm, p, mem, addr, value, PPMODE);
+}
+
+/*
+ * Read a single byte, HVSP mode
+ */
+static int stk500hvsp_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+				unsigned long addr, unsigned char * value)
+{
+  return stk500hv_read_byte(pgm, p, mem, addr, value, HVSPMODE);
+}
+
+/*
+ * Write one byte, generic HV mode
+ */
+static int stk500hv_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+			       unsigned long addr, unsigned char data,
+			       enum hvmode mode)
+{
+  int result, cmdlen, timeout = 0, pulsewidth = 0;
+  unsigned char buf[266];
+  unsigned long paddr = 0UL, *paddr_ptr = NULL;
+  unsigned int pagesize = 0, use_ext_addr = 0, addrshift = 0;
+  unsigned char *cache_ptr = NULL;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: stk500hv_write_byte(.., %s, 0x%lx, ...)\n",
+	    progname, mem->desc, addr);
+
+  if (strcmp(mem->desc, "flash") == 0) {
+    buf[0] = mode == PPMODE? CMD_PROGRAM_FLASH_PP: CMD_PROGRAM_FLASH_HVSP;
+    pagesize = mem->page_size;
+    if (pagesize == 0)
+      pagesize = 2;
+    paddr = addr & ~(pagesize - 1);
+    paddr_ptr = &PDATA(pgm)->flash_pageaddr;
+    cache_ptr = PDATA(pgm)->flash_pagecache;
+    addrshift = 1;
+    /*
+     * If bit 31 is set, this indicates that the following read/write
+     * operation will be performed on a memory that is larger than
+     * 64KBytes. This is an indication to STK500 that a load extended
+     * address must be executed.
+     */
+    if (mem->op[AVR_OP_LOAD_EXT_ADDR] != NULL) {
+      use_ext_addr = (1U << 31);
+    }
+  } else if (strcmp(mem->desc, "eeprom") == 0) {
+    buf[0] = mode == PPMODE? CMD_PROGRAM_EEPROM_PP: CMD_PROGRAM_EEPROM_HVSP;
+    pagesize = mem->page_size;
+    if (pagesize == 0)
+      pagesize = 1;
+    paddr = addr & ~(pagesize - 1);
+    paddr_ptr = &PDATA(pgm)->eeprom_pageaddr;
+    cache_ptr = PDATA(pgm)->eeprom_pagecache;
+  } else if (strcmp(mem->desc, "lfuse") == 0 ||
+	     strcmp(mem->desc, "fuse") == 0) {
+    buf[0] = mode == PPMODE? CMD_PROGRAM_FUSE_PP: CMD_PROGRAM_FUSE_HVSP;
+    addr = 0;
+    pulsewidth = p->programfusepulsewidth;
+    timeout = p->programfusepolltimeout;
+  } else if (strcmp(mem->desc, "hfuse") == 0) {
+    buf[0] = mode == PPMODE? CMD_PROGRAM_FUSE_PP: CMD_PROGRAM_FUSE_HVSP;
+    addr = 1;
+    pulsewidth = p->programfusepulsewidth;
+    timeout = p->programfusepolltimeout;
+  } else if (strcmp(mem->desc, "efuse") == 0) {
+    buf[0] = mode == PPMODE? CMD_PROGRAM_FUSE_PP: CMD_PROGRAM_FUSE_HVSP;
+    addr = 2;
+    pulsewidth = p->programfusepulsewidth;
+    timeout = p->programfusepolltimeout;
+  } else if (strcmp(mem->desc, "lock") == 0) {
+    buf[0] = mode == PPMODE? CMD_PROGRAM_LOCK_PP: CMD_PROGRAM_LOCK_HVSP;
+    pulsewidth = p->programlockpulsewidth;
+    timeout = p->programlockpolltimeout;
+  } else {
+    fprintf(stderr,
+	    "%s: stk500hv_write_byte(): "
+	    "unsupported memory type: %s\n",
+	    progname, mem->desc);
+    return -1;
+  }
+
+  cmdlen = 5 + pagesize;
+
+  /*
+   * In HV mode, we have to use paged writes for flash and
+   * EEPROM.  As both, flash and EEPROM cells can only be programmed
+   * from `1' to `0' bits (even EEPROM does not support auto-erase in
+   * parallel mode), we just pre-fill the page cache with 0xff, so all
+   * those cells that are outside our current address will remain
+   * unaffected.
+   */
+  if (pagesize) {
+    memset(cache_ptr, 0xff, pagesize);
+    cache_ptr[addr & (pagesize - 1)] = data;
+
+    /* long command, fill in # of bytes */
+    buf[1] = (pagesize >> 8) & 0xff;
+    buf[2] = pagesize & 0xff;
+
+    /*
+     * Synthesize the mode byte.  This is simpler than adding yet
+     * another parameter to the avrdude.conf file.  We calculate the
+     * bits corresponding to the page size, as explained in AVR068.
+     * We set bit 7, to indicate this is to actually write the page to
+     * the target device.  We set bit 6 to indicate this is the very
+     * last page to be programmed, whatever this means -- we just
+     * pretend we don't know any better. ;-)  Bit 0 is set if this is
+     * a paged memory, which means it has a page size of more than 2.
+     */
+    buf[3] = 0x80 | 0x40;
+    if (pagesize > 2) {
+      buf[3] |= stk500v2_mode_for_pagesize(pagesize);
+      buf[3] |= 0x01;
+    }
+    buf[4] = mem->delay;
+    memcpy(buf + 5, cache_ptr, pagesize);
+
+    /* flash and EEPROM reads require the load address command */
+    if (stk500v2_loadaddr(pgm, use_ext_addr | (paddr >> addrshift)) < 0)
+        return -1;
+  } else {
+    buf[1] = addr;
+    buf[2] = data;
+    if (mode == PPMODE) {
+      buf[3] = pulsewidth;
+      buf[4] = timeout;
+    } else {
+      buf[3] = timeout;
+      cmdlen--;
+    }
+  }
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: stk500hv_write_byte(): Sending write memory command: ",
+	    progname);
+
+  result = stk500v2_command(pgm, buf, cmdlen, sizeof(buf));
+
+  if (result < 0) {
+    fprintf(stderr,
+	    "%s: stk500hv_write_byte(): "
+	    "timeout/error communicating with programmer\n",
+	    progname);
+    return -1;
+  }
+
+  if (pagesize) {
+    /* Invalidate the page cache. */
+    *paddr_ptr = (unsigned long)-1L;
+  }
+
+  return 0;
+}
+
+/*
+ * Write one byte, PP mode
+ */
+static int stk500pp_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+			       unsigned long addr, unsigned char data)
+{
+  return stk500hv_write_byte(pgm, p, mem, addr, data, PPMODE);
+}
+
+/*
+ * Write one byte, HVSP mode
+ */
+static int stk500hvsp_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+			       unsigned long addr, unsigned char data)
+{
+  return stk500hv_write_byte(pgm, p, mem, addr, data, HVSPMODE);
+}
+
+
+static int stk500v2_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, 
+                              int page_size, int n_bytes)
+{
+  unsigned int addr, block_size, last_addr, hiaddr, addrshift, use_ext_addr;
+  unsigned char commandbuf[10];
+  unsigned char buf[266];
+  unsigned char cmds[4];
+  int result;
+  OPCODE * rop, * wop;
+
+  DEBUG("STK500V2: stk500v2_paged_write(..,%s,%d,%d)\n",m->desc,page_size,n_bytes);
+
+  if (page_size == 0) page_size = 256;
+  hiaddr = UINT_MAX;
+  addrshift = 0;
+  use_ext_addr = 0;
+
+  // determine which command is to be used
+  if (strcmp(m->desc, "flash") == 0) {
+    addrshift = 1;
+    commandbuf[0] = CMD_PROGRAM_FLASH_ISP;
+    /*
+     * If bit 31 is set, this indicates that the following read/write
+     * operation will be performed on a memory that is larger than
+     * 64KBytes. This is an indication to STK500 that a load extended
+     * address must be executed.
+     */
+    if (m->op[AVR_OP_LOAD_EXT_ADDR] != NULL) {
+      use_ext_addr = (1U << 31);
+    }
+  } else if (strcmp(m->desc, "eeprom") == 0) {
+    commandbuf[0] = CMD_PROGRAM_EEPROM_ISP;
+  }
+  commandbuf[4] = m->delay;
+
+  if (addrshift == 0) {
+    wop = m->op[AVR_OP_WRITE];
+    rop = m->op[AVR_OP_READ];
+  }
+  else {
+    wop = m->op[AVR_OP_WRITE_LO];
+    rop = m->op[AVR_OP_READ_LO];
+  }
+
+  // if the memory is paged, load the appropriate commands into the buffer
+  if (m->mode & 0x01) {
+    commandbuf[3] = m->mode | 0x80;		// yes, write the page to flash
+
+    if (m->op[AVR_OP_LOADPAGE_LO] == NULL) {
+      fprintf(stderr, "%s: stk500v2_paged_write: loadpage instruction not defined for part \"%s\"\n",
+              progname, p->desc);
+      return -1;
+    }
+    avr_set_bits(m->op[AVR_OP_LOADPAGE_LO], cmds);
+    commandbuf[5] = cmds[0];
+
+    if (m->op[AVR_OP_WRITEPAGE] == NULL) {
+      fprintf(stderr, "%s: stk500v2_paged_write: write page instruction not defined for part \"%s\"\n",
+              progname, p->desc);
+      return -1;
+    }
+    avr_set_bits(m->op[AVR_OP_WRITEPAGE], cmds);
+    commandbuf[6] = cmds[0];
+
+  // otherwise, we need to load different commands in
+  } 
+  else {
+    commandbuf[3] = m->mode | 0x80;		// yes, write the words to flash
+
+    if (wop == NULL) {
+      fprintf(stderr, "%s: stk500v2_paged_write: write instruction not defined for part \"%s\"\n",
+              progname, p->desc);
+      return -1;
+    }
+    avr_set_bits(wop, cmds);
+    commandbuf[5] = cmds[0];
+    commandbuf[6] = 0;
+  }
+
+  // the read command is common to both methods
+  if (rop == NULL) {
+    fprintf(stderr, "%s: stk500v2_paged_write: read instruction not defined for part \"%s\"\n",
+            progname, p->desc);
+    return -1;
+  }
+  avr_set_bits(rop, cmds);
+  commandbuf[7] = cmds[0];
+
+  commandbuf[8] = m->readback[0];
+  commandbuf[9] = m->readback[1];
+
+  last_addr=UINT_MAX;		/* impossible address */
+
+  for (addr=0; addr < n_bytes; addr += page_size) {
+    report_progress(addr,n_bytes,NULL);
+
+    if ((n_bytes-addr) < page_size)
+      block_size = n_bytes - addr;
+    else
+      block_size = page_size;
+
+    DEBUG("block_size at addr %d is %d\n",addr,block_size);
+
+    if(commandbuf[0] == CMD_PROGRAM_FLASH_ISP){
+      if (stk500v2_is_page_empty(addr, block_size, m->buf)) {
+          continue;
+      }
+    }
+
+    memcpy(buf,commandbuf,sizeof(commandbuf));
+
+    buf[1] = block_size >> 8;
+    buf[2] = block_size & 0xff;
+
+    if((last_addr==UINT_MAX)||(last_addr+block_size != addr)){
+      if (stk500v2_loadaddr(pgm, use_ext_addr | (addr >> addrshift)) < 0)
+        return -1;
+    }
+    last_addr=addr;
+
+    memcpy(buf+10,m->buf+addr, block_size);
+
+    result = stk500v2_command(pgm,buf,block_size+10, sizeof(buf));
+    if (result < 0) {
+      fprintf(stderr,
+              "%s: stk500v2_paged_write: write command failed\n",
+              progname);
+      return -1;
+    }
+  }
+
+  return n_bytes;
+}
+
+/*
+ * Write pages of flash/EEPROM, generic HV mode
+ */
+static int stk500hv_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+				  int page_size, int n_bytes,
+				  enum hvmode mode)
+{
+  unsigned int addr, block_size, last_addr, hiaddr, addrshift, use_ext_addr;
+  unsigned char commandbuf[5], buf[266];
+  int result;
+
+  DEBUG("STK500V2: stk500hv_paged_write(..,%s,%d,%d)\n",m->desc,page_size,n_bytes);
+
+  hiaddr = UINT_MAX;
+  addrshift = 0;
+  use_ext_addr = 0;
+
+  // determine which command is to be used
+  if (strcmp(m->desc, "flash") == 0) {
+    addrshift = 1;
+    PDATA(pgm)->flash_pageaddr = (unsigned long)-1L;
+    commandbuf[0] = mode == PPMODE? CMD_PROGRAM_FLASH_PP: CMD_PROGRAM_FLASH_HVSP;
+    /*
+     * If bit 31 is set, this indicates that the following read/write
+     * operation will be performed on a memory that is larger than
+     * 64KBytes. This is an indication to STK500 that a load extended
+     * address must be executed.
+     */
+    if (m->op[AVR_OP_LOAD_EXT_ADDR] != NULL) {
+      use_ext_addr = (1U << 31);
+    }
+  } else if (strcmp(m->desc, "eeprom") == 0) {
+    PDATA(pgm)->eeprom_pageaddr = (unsigned long)-1L;
+    commandbuf[0] = mode == PPMODE? CMD_PROGRAM_EEPROM_PP: CMD_PROGRAM_EEPROM_HVSP;
+  }
+  /*
+   * Synthesize the mode byte.  This is simpler than adding yet
+   * another parameter to the avrdude.conf file.  We calculate the
+   * bits corresponding to the page size, as explained in AVR068.  We
+   * set bit 7, to indicate this is to actually write the page to the
+   * target device.  We set bit 6 to indicate this is the very last
+   * page to be programmed, whatever this means -- we just pretend we
+   * don't know any better. ;-)  Finally, we set bit 0 to say this is
+   * a paged memory, after all, that's why we got here at all.
+   */
+  commandbuf[3] = 0x80 | 0x40;
+  if (page_size > 2) {
+    commandbuf[3] |= stk500v2_mode_for_pagesize(page_size);
+    commandbuf[3] |= 0x01;
+  }
+  commandbuf[4] = m->delay;
+
+  if (page_size == 0) page_size = 256;
+
+  last_addr = UINT_MAX;		/* impossible address */
+
+  for (addr = 0; addr < n_bytes; addr += page_size) {
+    report_progress(addr,n_bytes,NULL);
+
+    if ((n_bytes-addr) < page_size)
+      block_size = n_bytes - addr;
+    else
+      block_size = page_size;
+
+    DEBUG("block_size at addr %d is %d\n",addr,block_size);
+
+    if (addrshift == 1) {
+      if (stk500v2_is_page_empty(addr, block_size, m->buf)) {
+          continue;
+      }
+    }
+
+    memcpy(buf, commandbuf, sizeof(commandbuf));
+
+    buf[1] = page_size >> 8;
+    buf[2] = page_size & 0xff;
+
+    if ((last_addr == UINT_MAX) || (last_addr + block_size != addr)) {
+      if (stk500v2_loadaddr(pgm, use_ext_addr | (addr >> addrshift)) < 0)
+        return -1;
+    }
+    last_addr=addr;
+
+    memcpy(buf + 5, m->buf + addr, block_size);
+    if (block_size != page_size)
+      memset(buf + 5 + block_size, 0xff, page_size - block_size);
+
+    result = stk500v2_command(pgm, buf, page_size + 5, sizeof(buf));
+    if (result < 0) {
+      fprintf(stderr,
+              "%s: stk500hv_paged_write: write command failed\n",
+              progname);
+      return -1;
+    }
+  }
+
+  return n_bytes;
+}
+
+/*
+ * Write pages of flash/EEPROM, PP mode
+ */
+static int stk500pp_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+				int page_size, int n_bytes)
+{
+  return stk500hv_paged_write(pgm, p, m, page_size, n_bytes, PPMODE);
+}
+
+/*
+ * Write pages of flash/EEPROM, HVSP mode
+ */
+static int stk500hvsp_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+				  int page_size, int n_bytes)
+{
+  return stk500hv_paged_write(pgm, p, m, page_size, n_bytes, HVSPMODE);
+}
+
+static int stk500v2_is_page_empty(unsigned int address, int page_size,
+                                const unsigned char *buf)
+{
+    int i;
+    for(i = 0; i < page_size; i++) {
+        if(buf[address + i] != 0xFF) {
+            /* Page is not empty. */
+            return(0);
+        }
+    }
+
+    /* Page is empty. */
+    return(1);
+}
+
+static int stk500v2_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+                             int page_size, int n_bytes)
+{
+  unsigned int addr, block_size, hiaddr, addrshift, use_ext_addr;
+  unsigned char commandbuf[4];
+  unsigned char buf[275];	// max buffer size for stk500v2 at this point
+  unsigned char cmds[4];
+  int result;
+  OPCODE * rop;
+
+  DEBUG("STK500V2: stk500v2_paged_load(..,%s,%d,%d)\n",m->desc,page_size,n_bytes);
+
+  page_size = m->readsize;
+
+  rop = m->op[AVR_OP_READ];
+
+  hiaddr = UINT_MAX;
+  addrshift = 0;
+  use_ext_addr = 0;
+
+  // determine which command is to be used
+  if (strcmp(m->desc, "flash") == 0) {
+    commandbuf[0] = CMD_READ_FLASH_ISP;
+    rop = m->op[AVR_OP_READ_LO];
+    addrshift = 1;
+    /*
+     * If bit 31 is set, this indicates that the following read/write
+     * operation will be performed on a memory that is larger than
+     * 64KBytes. This is an indication to STK500 that a load extended
+     * address must be executed.
+     */
+    if (m->op[AVR_OP_LOAD_EXT_ADDR] != NULL) {
+      use_ext_addr = (1U << 31);
+    }
+  }
+  else if (strcmp(m->desc, "eeprom") == 0) {
+    commandbuf[0] = CMD_READ_EEPROM_ISP;
+  }
+
+  // the read command is common to both methods
+  if (rop == NULL) {
+    fprintf(stderr, "%s: stk500v2_paged_load: read instruction not defined for part \"%s\"\n",
+            progname, p->desc);
+    return -1;
+  }
+  avr_set_bits(rop, cmds);
+  commandbuf[3] = cmds[0];
+
+  for (addr=0; addr < n_bytes; addr += page_size) {
+    report_progress(addr, n_bytes,NULL);
+
+    if ((n_bytes-addr) < page_size)
+      block_size = n_bytes - addr;
+    else
+      block_size = page_size;
+    DEBUG("block_size at addr %d is %d\n",addr,block_size);
+
+    memcpy(buf,commandbuf,sizeof(commandbuf));
+
+    buf[1] = block_size >> 8;
+    buf[2] = block_size & 0xff;
+
+    // Ensure a new "load extended address" will be issued
+    // when crossing a 64 KB boundary in flash.
+    if (hiaddr != (addr & ~0xFFFF)) {
+      hiaddr = addr & ~0xFFFF;
+      if (stk500v2_loadaddr(pgm, use_ext_addr | (addr >> addrshift)) < 0)
+        return -1;
+    }
+
+    result = stk500v2_command(pgm,buf,4,sizeof(buf));
+    if (result < 0) {
+      fprintf(stderr,
+              "%s: stk500v2_paged_load: read command failed\n",
+              progname);
+      return -1;
+    }
+#if 0
+    for (i=0;i<page_size;i++) {
+      fprintf(stderr,"%02X",buf[2+i]);
+      if (i%16 == 15) fprintf(stderr,"\n");
+    }
+#endif
+
+    memcpy(&m->buf[addr], &buf[2], block_size);
+  }
+
+  return n_bytes;
+}
+
+
+/*
+ * Read pages of flash/EEPROM, generic HV mode
+ */
+static int stk500hv_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+			       int page_size, int n_bytes,
+			       enum hvmode mode)
+{
+  unsigned int addr, block_size, hiaddr, addrshift, use_ext_addr;
+  unsigned char commandbuf[3], buf[266];
+  int result;
+
+  DEBUG("STK500V2: stk500hv_paged_load(..,%s,%d,%d)\n",m->desc,page_size,n_bytes);
+
+  page_size = m->readsize;
+
+  hiaddr = UINT_MAX;
+  addrshift = 0;
+  use_ext_addr = 0;
+
+  // determine which command is to be used
+  if (strcmp(m->desc, "flash") == 0) {
+    commandbuf[0] = mode == PPMODE? CMD_READ_FLASH_PP: CMD_READ_FLASH_HVSP;
+    addrshift = 1;
+    /*
+     * If bit 31 is set, this indicates that the following read/write
+     * operation will be performed on a memory that is larger than
+     * 64KBytes. This is an indication to STK500 that a load extended
+     * address must be executed.
+     */
+    if (m->op[AVR_OP_LOAD_EXT_ADDR] != NULL) {
+      use_ext_addr = (1U << 31);
+    }
+  }
+  else if (strcmp(m->desc, "eeprom") == 0) {
+    commandbuf[0] = mode == PPMODE? CMD_READ_EEPROM_PP: CMD_READ_EEPROM_HVSP;
+  }
+
+  for (addr = 0; addr < n_bytes; addr += page_size) {
+    report_progress(addr, n_bytes, NULL);
+
+    if ((n_bytes-addr) < page_size)
+      block_size = n_bytes - addr;
+    else
+      block_size = page_size;
+    DEBUG("block_size at addr %d is %d\n",addr,block_size);
+
+    memcpy(buf, commandbuf, sizeof(commandbuf));
+
+    buf[1] = block_size >> 8;
+    buf[2] = block_size & 0xff;
+
+    // Ensure a new "load extended address" will be issued
+    // when crossing a 64 KB boundary in flash.
+    if (hiaddr != (addr & ~0xFFFF)) {
+      hiaddr = addr & ~0xFFFF;
+      if (stk500v2_loadaddr(pgm, use_ext_addr | (addr >> addrshift)) < 0)
+        return -1;
+    }
+
+    result = stk500v2_command(pgm, buf, 3, sizeof(buf));
+    if (result < 0) {
+      fprintf(stderr,
+              "%s: stk500hv_paged_load: read command failed\n",
+              progname);
+      return -1;
+    }
+#if 0
+    for (i = 0; i < page_size; i++) {
+      fprintf(stderr, "%02X", buf[2 + i]);
+      if (i % 16 == 15) fprintf(stderr, "\n");
+    }
+#endif
+
+    memcpy(&m->buf[addr], &buf[2], block_size);
+  }
+
+  return n_bytes;
+}
+
+/*
+ * Read pages of flash/EEPROM, PP mode
+ */
+static int stk500pp_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+			       int page_size, int n_bytes)
+{
+  return stk500hv_paged_load(pgm, p, m, page_size, n_bytes, PPMODE);
+}
+
+/*
+ * Read pages of flash/EEPROM, HVSP mode
+ */
+static int stk500hvsp_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+				 int page_size, int n_bytes)
+{
+  return stk500hv_paged_load(pgm, p, m, page_size, n_bytes, HVSPMODE);
+}
+
+
+static int stk500v2_set_vtarget(PROGRAMMER * pgm, double v)
+{
+  unsigned char uaref, utarg;
+
+  utarg = (unsigned)((v + 0.049) * 10);
+
+  if (stk500v2_getparm(pgm, PARAM_VADJUST, &uaref) != 0) {
+    fprintf(stderr,
+	    "%s: stk500v2_set_vtarget(): cannot obtain V[aref]\n",
+	    progname);
+    return -1;
+  }
+
+  if (uaref > utarg) {
+    fprintf(stderr,
+	    "%s: stk500v2_set_vtarget(): reducing V[aref] from %.1f to %.1f\n",
+	    progname, uaref / 10.0, v);
+    if (stk500v2_setparm(pgm, PARAM_VADJUST, utarg)
+	!= 0)
+      return -1;
+  }
+  return stk500v2_setparm(pgm, PARAM_VTARGET, utarg);
+}
+
+
+static int stk500v2_set_varef(PROGRAMMER * pgm, unsigned int chan /* unused */,
+                              double v)
+{
+  unsigned char uaref, utarg;
+
+  uaref = (unsigned)((v + 0.049) * 10);
+
+  if (stk500v2_getparm(pgm, PARAM_VTARGET, &utarg) != 0) {
+    fprintf(stderr,
+	    "%s: stk500v2_set_varef(): cannot obtain V[target]\n",
+	    progname);
+    return -1;
+  }
+
+  if (uaref > utarg) {
+    fprintf(stderr,
+	    "%s: stk500v2_set_varef(): V[aref] must not be greater than "
+	    "V[target] = %.1f\n",
+	    progname, utarg / 10.0);
+    return -1;
+  }
+  return stk500v2_setparm(pgm, PARAM_VADJUST, uaref);
+}
+
+
+static int stk500v2_set_fosc(PROGRAMMER * pgm, double v)
+{
+  int fosc;
+  unsigned char prescale, cmatch;
+  static unsigned ps[] = {
+    1, 8, 32, 64, 128, 256, 1024
+  };
+  int idx, rc;
+
+  prescale = cmatch = 0;
+  if (v > 0.0) {
+    if (v > STK500V2_XTAL / 2) {
+      const char *unit;
+      if (v > 1e6) {
+        v /= 1e6;
+        unit = "MHz";
+      } else if (v > 1e3) {
+        v /= 1e3;
+        unit = "kHz";
+      } else
+        unit = "Hz";
+      fprintf(stderr,
+          "%s: stk500v2_set_fosc(): f = %.3f %s too high, using %.3f MHz\n",
+          progname, v, unit, STK500V2_XTAL / 2e6);
+      fosc = STK500V2_XTAL / 2;
+    } else
+      fosc = (unsigned)v;
+
+    for (idx = 0; idx < sizeof(ps) / sizeof(ps[0]); idx++) {
+      if (fosc >= STK500V2_XTAL / (256 * ps[idx] * 2)) {
+        /* this prescaler value can handle our frequency */
+        prescale = idx + 1;
+        cmatch = (unsigned)(STK500V2_XTAL / (2 * fosc * ps[idx])) - 1;
+        break;
+      }
+    }
+    if (idx == sizeof(ps) / sizeof(ps[0])) {
+      fprintf(stderr, "%s: stk500v2_set_fosc(): f = %u Hz too low, %u Hz min\n",
+          progname, fosc, STK500V2_XTAL / (256 * 1024 * 2));
+      return -1;
+    }
+  }
+
+  if ((rc = stk500v2_setparm(pgm, PARAM_OSC_PSCALE, prescale)) != 0
+      || (rc = stk500v2_setparm(pgm, PARAM_OSC_CMATCH, cmatch)) != 0)
+    return rc;
+
+  return 0;
+}
+
+/* The list of SCK frequencies supported by the AVRISP mkII, as listed
+ * in AVR069 */
+static double avrispmkIIfreqs[] = {
+	8000000, 4000000, 2000000, 1000000, 500000, 250000, 125000,
+	96386, 89888, 84211, 79208, 74767, 70797, 67227, 64000,
+	61069, 58395, 55945, 51613, 49690, 47905, 46243, 43244,
+	41885, 39409, 38278, 36200, 34335, 32654, 31129, 29740,
+	28470, 27304, 25724, 24768, 23461, 22285, 21221, 20254,
+	19371, 18562, 17583, 16914, 16097, 15356, 14520, 13914,
+	13224, 12599, 12031, 11511, 10944, 10431, 9963, 9468,
+	9081, 8612, 8239, 7851, 7498, 7137, 6809, 6478, 6178,
+	5879, 5607, 5359, 5093, 4870, 4633, 4418, 4209, 4019,
+	3823, 3645, 3474, 3310, 3161, 3011, 2869, 2734, 2611,
+	2484, 2369, 2257, 2152, 2052, 1956, 1866, 1779, 1695,
+	1615, 1539, 1468, 1398, 1333, 1271, 1212, 1155, 1101,
+	1049, 1000, 953, 909, 866, 826, 787, 750, 715, 682,
+	650, 619, 590, 563, 536, 511, 487, 465, 443, 422,
+	402, 384, 366, 349, 332, 317, 302, 288, 274, 261,
+	249, 238, 226, 216, 206, 196, 187, 178, 170, 162,
+	154, 147, 140, 134, 128, 122, 116, 111, 105, 100,
+	95.4, 90.9, 86.6, 82.6, 78.7, 75.0, 71.5, 68.2,
+	65.0, 61.9, 59.0, 56.3, 53.6, 51.1
+};
+
+static int stk500v2_set_sck_period_mk2(PROGRAMMER * pgm, double v)
+{
+  int i;
+
+  for (i = 0; i < sizeof(avrispmkIIfreqs); i++) {
+    if (1 / avrispmkIIfreqs[i] >= v)
+      break;
+  }
+
+  if (verbose > 2)
+    fprintf(stderr, "Using p = %.2f us for SCK (param = %d)\n",
+	    1000000 / avrispmkIIfreqs[i], i);
+
+  return stk500v2_setparm(pgm, PARAM_SCK_DURATION, i);
+}
+
+/*
+ * Return the "mode" value for the parallel and HVSP modes that
+ * corresponds to the pagesize.
+ */
+static unsigned int stk500v2_mode_for_pagesize(unsigned int pagesize)
+{
+  switch (pagesize)
+    {
+    case 256:  return 0u << 1;
+    case 2:    return 1u << 1;
+    case 4:    return 2u << 1;
+    case 8:    return 3u << 1;
+    case 16:   return 4u << 1;
+    case 32:   return 5u << 1;
+    case 64:   return 6u << 1;
+    case 128:  return 7u << 1;
+    }
+  fprintf(stderr,
+	  "%s: stk500v2_mode_for_pagesize(): invalid pagesize: %u\n",
+	  progname, pagesize);
+  exit(1);
+}
+
+/* This code assumes that each count of the SCK duration parameter
+   represents 8/f, where f is the clock frequency of the STK500V2 master
+   processors (not the target).  This number comes from Atmel
+   application note AVR061.  It appears that the STK500V2 bit bangs SCK.
+   For small duration values, the actual SCK width is larger than
+   expected.  As the duration value increases, the SCK width error
+   diminishes. */
+static int stk500v2_set_sck_period(PROGRAMMER * pgm, double v)
+{
+  unsigned char dur;
+  double min, max;
+
+  min = 8.0 / STK500V2_XTAL;
+  max = 255 * min;
+  dur = v / min + 0.5;
+
+  if (v < min) {
+      dur = 1;
+      fprintf(stderr,
+	      "%s: stk500v2_set_sck_period(): p = %.1f us too small, using %.1f us\n",
+	      progname, v / 1e-6, dur * min / 1e-6);
+  } else if (v > max) {
+      dur = 255;
+      fprintf(stderr,
+	      "%s: stk500v2_set_sck_period(): p = %.1f us too large, using %.1f us\n",
+	      progname, v / 1e-6, dur * min / 1e-6);
+  }
+
+  return stk500v2_setparm(pgm, PARAM_SCK_DURATION, dur);
+}
+
+
+static int stk600_set_vtarget(PROGRAMMER * pgm, double v)
+{
+  unsigned char utarg;
+  unsigned int uaref;
+  int rv;
+
+  utarg = (unsigned)((v + 0.049) * 10);
+
+  if (stk500v2_getparm2(pgm, PARAM2_AREF0, &uaref) != 0) {
+    fprintf(stderr,
+	    "%s: stk500v2_set_vtarget(): cannot obtain V[aref][0]\n",
+	    progname);
+    return -1;
+  }
+
+  if (uaref > (unsigned)utarg * 10) {
+    fprintf(stderr,
+	    "%s: stk500v2_set_vtarget(): reducing V[aref][0] from %.2f to %.1f\n",
+	    progname, uaref / 100.0, v);
+    uaref = 10 * (unsigned)utarg;
+    if (stk500v2_setparm2(pgm, PARAM2_AREF0, uaref)
+	!= 0)
+      return -1;
+  }
+
+  if (stk500v2_getparm2(pgm, PARAM2_AREF1, &uaref) != 0) {
+    fprintf(stderr,
+	    "%s: stk500v2_set_vtarget(): cannot obtain V[aref][1]\n",
+	    progname);
+    return -1;
+  }
+
+  if (uaref > (unsigned)utarg * 10) {
+    fprintf(stderr,
+	    "%s: stk500v2_set_vtarget(): reducing V[aref][1] from %.2f to %.1f\n",
+	    progname, uaref / 100.0, v);
+    uaref = 10 * (unsigned)utarg;
+    if (stk500v2_setparm2(pgm, PARAM2_AREF1, uaref)
+	!= 0)
+      return -1;
+  }
+
+  /*
+   * Vtarget on the STK600 can only be adjusted while not being in
+   * programming mode.
+   */
+  if (PDATA(pgm)->lastpart)
+      pgm->disable(pgm);
+  rv = stk500v2_setparm(pgm, PARAM_VTARGET, utarg);
+  if (PDATA(pgm)->lastpart)
+      pgm->program_enable(pgm, PDATA(pgm)->lastpart);
+
+  return rv;
+}
+
+
+static int stk600_set_varef(PROGRAMMER * pgm, unsigned int chan, double v)
+{
+  unsigned char utarg;
+  unsigned int uaref;
+
+  uaref = (unsigned)((v + 0.0049) * 100);
+
+  if (stk500v2_getparm(pgm, PARAM_VTARGET, &utarg) != 0) {
+    fprintf(stderr,
+	    "%s: stk500v2_set_varef(): cannot obtain V[target]\n",
+	    progname);
+    return -1;
+  }
+
+  if (uaref > (unsigned)utarg * 10) {
+    fprintf(stderr,
+	    "%s: stk500v2_set_varef(): V[aref] must not be greater than "
+	    "V[target] = %.1f\n",
+	    progname, utarg / 10.0);
+    return -1;
+  }
+
+  switch (chan)
+  {
+  case 0:
+    return stk500v2_setparm2(pgm, PARAM2_AREF0, uaref);
+
+  case 1:
+    return stk500v2_setparm2(pgm, PARAM2_AREF1, uaref);
+
+  default:
+    fprintf(stderr,
+	    "%s: stk500v2_set_varef(): invalid channel %d\n",
+	    progname, chan);
+    return -1;
+  }
+}
+
+
+static int stk600_set_fosc(PROGRAMMER * pgm, double v)
+{
+  unsigned int oct, dac;
+
+  oct = 1.443 * log(v / 1039.0);
+  dac = 2048 - (2078.0 * pow(2, (double)(10 + oct))) / v;
+
+  return stk500v2_setparm2(pgm, PARAM2_CLOCK_CONF, (oct << 12) | (dac << 2));
+}
+
+static int stk600_set_sck_period(PROGRAMMER * pgm, double v)
+{
+  unsigned int sck;
+
+  sck = ceil((16e6 / (2 * 1.0 / v)) - 1);
+
+  if (sck >= 4096)
+    sck = 4095;
+
+  return stk500v2_setparm2(pgm, PARAM2_SCK_DURATION, sck);
+}
+
+
+static int stk500v2_getparm(PROGRAMMER * pgm, unsigned char parm, unsigned char * value)
+{
+  unsigned char buf[32];
+
+  buf[0] = CMD_GET_PARAMETER;
+  buf[1] = parm;
+
+  if (stk500v2_command(pgm, buf, 2, sizeof(buf)) < 0) {
+    fprintf(stderr,"%s: stk500v2_getparm(): failed to get parameter 0x%02x\n",
+            progname, parm);
+    return -1;
+  }
+
+  *value = buf[2];
+
+  return 0;
+}
+
+static int stk500v2_setparm_real(PROGRAMMER * pgm, unsigned char parm, unsigned char value)
+{
+  unsigned char buf[32];
+
+  buf[0] = CMD_SET_PARAMETER;
+  buf[1] = parm;
+  buf[2] = value;
+
+  if (stk500v2_command(pgm, buf, 3, sizeof(buf)) < 0) {
+    fprintf(stderr, "\n%s: stk500v2_setparm(): failed to set parameter 0x%02x\n",
+            progname, parm);
+    return -1;
+  }
+
+  return 0;
+}
+
+static int stk500v2_setparm(PROGRAMMER * pgm, unsigned char parm, unsigned char value)
+{
+  unsigned char current_value;
+  int res;
+
+  res = stk500v2_getparm(pgm, parm, &current_value);
+  if (res < 0)
+    fprintf(stderr, "%s: Unable to get parameter 0x%02x\n", progname, parm);
+
+  // don't issue a write if the correct value is already set.
+  if (value == current_value && verbose > 2) {
+    fprintf(stderr, "%s: Skipping paramter write; parameter value already set.\n", progname);
+    return 0;
+  }
+
+  return stk500v2_setparm_real(pgm, parm, value);
+}
+
+static int stk500v2_getparm2(PROGRAMMER * pgm, unsigned char parm, unsigned int * value)
+{
+  unsigned char buf[32];
+
+  buf[0] = CMD_GET_PARAMETER;
+  buf[1] = parm;
+
+  if (stk500v2_command(pgm, buf, 2, sizeof(buf)) < 0) {
+    fprintf(stderr,"%s: stk500v2_getparm2(): failed to get parameter 0x%02x\n",
+            progname, parm);
+    return -1;
+  }
+
+  *value = ((unsigned)buf[2] << 8) | buf[3];
+
+  return 0;
+}
+
+static int stk500v2_setparm2(PROGRAMMER * pgm, unsigned char parm, unsigned int value)
+{
+  unsigned char buf[32];
+
+  buf[0] = CMD_SET_PARAMETER;
+  buf[1] = parm;
+  buf[2] = value >> 8;
+  buf[3] = value;
+
+  if (stk500v2_command(pgm, buf, 4, sizeof(buf)) < 0) {
+    fprintf(stderr, "\n%s: stk500v2_setparm2(): failed to set parameter 0x%02x\n",
+            progname, parm);
+    return -1;
+  }
+
+  return 0;
+}
+
+static const char *stk600_get_cardname(const struct carddata *table,
+				       size_t nele, int id)
+{
+  const struct carddata *cdp;
+
+  if (id == 0xFF)
+    /* 0xFF means this card is not present at all. */
+    return "Not present";
+
+  for (cdp = table; nele > 0; cdp++, nele--)
+    if (cdp->id == id)
+      return cdp->name;
+
+  return "Unknown";
+}
+
+
+static void stk500v2_display(PROGRAMMER * pgm, const char * p)
+{
+  unsigned char maj, min, hdw, topcard, maj_s1, min_s1, maj_s2, min_s2;
+  unsigned int rev;
+  const char *topcard_name, *pgmname;
+
+  switch (PDATA(pgm)->pgmtype) {
+    case PGMTYPE_UNKNOWN:     pgmname = "Unknown"; break;
+    case PGMTYPE_STK500:      pgmname = "STK500"; break;
+    case PGMTYPE_AVRISP:      pgmname = "AVRISP"; break;
+    case PGMTYPE_AVRISP_MKII: pgmname = "AVRISP mkII"; break;
+    case PGMTYPE_STK600:      pgmname = "STK600"; break;
+    default:                  pgmname = "None";
+  }
+  if (PDATA(pgm)->pgmtype != PGMTYPE_JTAGICE_MKII) {
+    fprintf(stderr, "%sProgrammer Model: %s\n", p, pgmname);
+    stk500v2_getparm(pgm, PARAM_HW_VER, &hdw);
+    stk500v2_getparm(pgm, PARAM_SW_MAJOR, &maj);
+    stk500v2_getparm(pgm, PARAM_SW_MINOR, &min);
+    fprintf(stderr, "%sHardware Version: %d\n", p, hdw);
+    fprintf(stderr, "%sFirmware Version Master : %d.%02d\n", p, maj, min);
+    if (PDATA(pgm)->pgmtype == PGMTYPE_STK600) {
+      stk500v2_getparm(pgm, PARAM_SW_MAJOR_SLAVE1, &maj_s1);
+      stk500v2_getparm(pgm, PARAM_SW_MINOR_SLAVE1, &min_s1);
+      stk500v2_getparm(pgm, PARAM_SW_MAJOR_SLAVE2, &maj_s2);
+      stk500v2_getparm(pgm, PARAM_SW_MINOR_SLAVE2, &min_s2);
+      fprintf(stderr, "%sFirmware Version Slave 1: %d.%02d\n", p, maj_s1, min_s1);
+      fprintf(stderr, "%sFirmware Version Slave 2: %d.%02d\n", p, maj_s2, min_s2);
+    }
+  }
+
+  if (PDATA(pgm)->pgmtype == PGMTYPE_STK500) {
+    stk500v2_getparm(pgm, PARAM_TOPCARD_DETECT, &topcard);
+    switch (topcard) {
+      case 0xAA: topcard_name = "STK501"; break;
+      case 0x55: topcard_name = "STK502"; break;
+      case 0xFA: topcard_name = "STK503"; break;
+      case 0xEE: topcard_name = "STK504"; break;
+      case 0xE4: topcard_name = "STK505"; break;
+      case 0xDD: topcard_name = "STK520"; break;
+      default: topcard_name = "Unknown"; break;
+    }
+    fprintf(stderr, "%sTopcard         : %s\n", p, topcard_name);
+  } else if (PDATA(pgm)->pgmtype == PGMTYPE_STK600) {
+    stk500v2_getparm(pgm, PARAM_ROUTINGCARD_ID, &topcard);
+    fprintf(stderr, "%sRouting card    : %s\n", p,
+	    stk600_get_cardname(routing_cards,
+				sizeof routing_cards / sizeof routing_cards[0],
+				topcard));
+    stk500v2_getparm(pgm, PARAM_SOCKETCARD_ID, &topcard);
+    fprintf(stderr, "%sSocket card     : %s\n", p,
+	    stk600_get_cardname(socket_cards,
+				sizeof socket_cards / sizeof socket_cards[0],
+				topcard));
+    stk500v2_getparm2(pgm, PARAM2_RC_ID_TABLE_REV, &rev);
+    fprintf(stderr, "%sRC_ID table rev : %d\n", p, rev);
+    stk500v2_getparm2(pgm, PARAM2_EC_ID_TABLE_REV, &rev);
+    fprintf(stderr, "%sEC_ID table rev : %d\n", p, rev);
+  }
+  stk500v2_print_parms1(pgm, p);
+
+  return;
+}
+
+static double
+f_to_kHz_MHz(double f, const char **unit)
+{
+  if (f > 1e6) {
+    f /= 1e6;
+    *unit = "MHz";
+  } else if (f > 1e3) {
+    f /= 1000;
+    *unit = "kHz";
+  } else
+    *unit = "Hz";
+
+  return f;
+}
+
+static void stk500v2_print_parms1(PROGRAMMER * pgm, const char * p)
+{
+  unsigned char vtarget, vadjust, osc_pscale, osc_cmatch, sck_duration;
+  unsigned int sck_stk600, clock_conf, dac, oct, varef;
+  unsigned char vtarget_jtag[4];
+  int prescale;
+  double f;
+  const char *unit;
+  void *mycookie;
+
+  if (PDATA(pgm)->pgmtype == PGMTYPE_JTAGICE_MKII) {
+    mycookie = pgm->cookie;
+    pgm->cookie = PDATA(pgm)->chained_pdata;
+    jtagmkII_getparm(pgm, PAR_OCD_VTARGET, vtarget_jtag);
+    pgm->cookie = mycookie;
+    fprintf(stderr, "%sVtarget         : %.1f V\n", p,
+	    b2_to_u16(vtarget_jtag) / 1000.0);
+  } else {
+    stk500v2_getparm(pgm, PARAM_VTARGET, &vtarget);
+    fprintf(stderr, "%sVtarget         : %.1f V\n", p, vtarget / 10.0);
+  }
+
+  switch (PDATA(pgm)->pgmtype) {
+  case PGMTYPE_STK500:
+    stk500v2_getparm(pgm, PARAM_SCK_DURATION, &sck_duration);
+    stk500v2_getparm(pgm, PARAM_VADJUST, &vadjust);
+    stk500v2_getparm(pgm, PARAM_OSC_PSCALE, &osc_pscale);
+    stk500v2_getparm(pgm, PARAM_OSC_CMATCH, &osc_cmatch);
+    fprintf(stderr, "%sSCK period      : %.1f us\n", p,
+	  sck_duration * 8.0e6 / STK500V2_XTAL + 0.05);
+    fprintf(stderr, "%sVaref           : %.1f V\n", p, vadjust / 10.0);
+    fprintf(stderr, "%sOscillator      : ", p);
+    if (osc_pscale == 0)
+      fprintf(stderr, "Off\n");
+    else {
+      prescale = 1;
+      f = STK500V2_XTAL / 2;
+
+      switch (osc_pscale) {
+        case 2: prescale = 8; break;
+        case 3: prescale = 32; break;
+        case 4: prescale = 64; break;
+        case 5: prescale = 128; break;
+        case 6: prescale = 256; break;
+        case 7: prescale = 1024; break;
+      }
+      f /= prescale;
+      f /= (osc_cmatch + 1);
+      f = f_to_kHz_MHz(f, &unit);
+      fprintf(stderr, "%.3f %s\n", f, unit);
+    }
+    break;
+
+  case PGMTYPE_AVRISP_MKII:
+  case PGMTYPE_JTAGICE_MKII:
+    stk500v2_getparm(pgm, PARAM_SCK_DURATION, &sck_duration);
+    fprintf(stderr, "%sSCK period      : %.2f us\n", p,
+	    (float) 1000000 / avrispmkIIfreqs[sck_duration]);
+    break;
+
+  case PGMTYPE_STK600:
+    stk500v2_getparm2(pgm, PARAM2_AREF0, &varef);
+    fprintf(stderr, "%sVaref 0         : %.2f V\n", p, varef / 100.0);
+    stk500v2_getparm2(pgm, PARAM2_AREF1, &varef);
+    fprintf(stderr, "%sVaref 1         : %.2f V\n", p, varef / 100.0);
+    stk500v2_getparm2(pgm, PARAM2_SCK_DURATION, &sck_stk600);
+    fprintf(stderr, "%sSCK period      : %.2f us\n", p,
+	    (float) (sck_stk600 + 1) / 8.0);
+    stk500v2_getparm2(pgm, PARAM2_CLOCK_CONF, &clock_conf);
+    oct = (clock_conf & 0xf000) >> 12u;
+    dac = (clock_conf & 0x0ffc) >> 2u;
+    f = pow(2, (double)oct) * 2078.0 / (2 - (double)dac / 1024.0);
+    f = f_to_kHz_MHz(f, &unit);
+    fprintf(stderr, "%sOscillator      : %.3f %s\n",
+            p, f, unit);
+    break;
+
+  default:
+    fprintf(stderr, "%sSCK period      : %.1f us\n", p,
+	  sck_duration * 8.0e6 / STK500V2_XTAL + 0.05);
+    break;
+  }
+
+  return;
+}
+
+
+static void stk500v2_print_parms(PROGRAMMER * pgm)
+{
+  stk500v2_print_parms1(pgm, "");
+}
+
+static int stk500v2_perform_osccal(PROGRAMMER * pgm)
+{
+  unsigned char buf[32];
+  int rv;
+
+  buf[0] = CMD_OSCCAL;
+
+  rv = stk500v2_command(pgm, buf, 1, sizeof(buf));
+  if (rv < 0) {
+    fprintf(stderr, "%s: stk500v2_perform_osccal(): failed\n",
+            progname);
+    return -1;
+  }
+
+  return 0;
+}
+
+/*
+ * Wrapper functions for the JTAG ICE mkII in ISP mode.  This mode
+ * uses the normal JTAG ICE mkII packet stream to communicate with the
+ * ICE, but then encapsulates AVRISP mkII commands using
+ * CMND_ISP_PACKET.
+ */
+
+/*
+ * Open a JTAG ICE mkII in ISP mode.
+ */
+static int stk500v2_jtagmkII_open(PROGRAMMER * pgm, char * port)
+{
+  long baud;
+  void *mycookie;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: stk500v2_jtagmkII_open()\n", progname);
+
+  /*
+   * The JTAG ICE mkII always starts with a baud rate of 19200 Bd upon
+   * attaching.  If the config file or command-line parameters specify
+   * a higher baud rate, we switch to it later on, after establishing
+   * the connection with the ICE.
+   */
+  baud = 19200;
+
+  /*
+   * If the port name starts with "usb", divert the serial routines
+   * to the USB ones.  The serial_open() function for USB overrides
+   * the meaning of the "baud" parameter to be the USB device ID to
+   * search for.
+   */
+  if (strncmp(port, "usb", 3) == 0) {
+#if defined(HAVE_LIBUSB)
+    serdev = &usb_serdev;
+    baud = USB_DEVICE_JTAGICEMKII;
+#else
+    fprintf(stderr, "avrdude was compiled without usb support.\n");
+    return -1;
+#endif
+  }
+
+  strcpy(pgm->port, port);
+  serial_open(port, baud, &pgm->fd);
+
+  /*
+   * drain any extraneous input
+   */
+  stk500v2_drain(pgm, 0);
+
+  mycookie = pgm->cookie;
+  pgm->cookie = PDATA(pgm)->chained_pdata;
+  if (jtagmkII_getsync(pgm, EMULATOR_MODE_SPI) != 0) {
+    fprintf(stderr, "%s: failed to sync with the JTAG ICE mkII in ISP mode\n",
+            progname);
+    pgm->cookie = mycookie;
+    return -1;
+  }
+  pgm->cookie = mycookie;
+
+  PDATA(pgm)->pgmtype = PGMTYPE_JTAGICE_MKII;
+
+  if (pgm->bitclock != 0.0) {
+    if (pgm->set_sck_period(pgm, pgm->bitclock) != 0)
+      return -1;
+  }
+
+  return 0;
+}
+
+
+/*
+ * Close an AVR Dragon or JTAG ICE mkII in ISP/HVSP/PP mode.
+ */
+static void stk500v2_jtagmkII_close(PROGRAMMER * pgm)
+{
+  void *mycookie;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: stk500v2_jtagmkII_close()\n", progname);
+
+  mycookie = pgm->cookie;
+  pgm->cookie = PDATA(pgm)->chained_pdata;
+  jtagmkII_close(pgm);
+  pgm->cookie = mycookie;
+}
+
+
+/*
+ * Wrapper functions for the AVR Dragon in ISP mode.  This mode
+ * uses the normal JTAG ICE mkII packet stream to communicate with the
+ * ICE, but then encapsulates AVRISP mkII commands using
+ * CMND_ISP_PACKET.
+ */
+
+/*
+ * Open an AVR Dragon in ISP mode.
+ */
+static int stk500v2_dragon_isp_open(PROGRAMMER * pgm, char * port)
+{
+  long baud;
+  void *mycookie;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: stk500v2_dragon_isp_open()\n", progname);
+
+  /*
+   * The JTAG ICE mkII always starts with a baud rate of 19200 Bd upon
+   * attaching.  If the config file or command-line parameters specify
+   * a higher baud rate, we switch to it later on, after establishing
+   * the connection with the ICE.
+   */
+  baud = 19200;
+
+  /*
+   * If the port name starts with "usb", divert the serial routines
+   * to the USB ones.  The serial_open() function for USB overrides
+   * the meaning of the "baud" parameter to be the USB device ID to
+   * search for.
+   */
+  if (strncmp(port, "usb", 3) == 0) {
+#if defined(HAVE_LIBUSB)
+    serdev = &usb_serdev;
+    baud = USB_DEVICE_AVRDRAGON;
+#else
+    fprintf(stderr, "avrdude was compiled without usb support.\n");
+    return -1;
+#endif
+  }
+
+  strcpy(pgm->port, port);
+  serial_open(port, baud, &pgm->fd);
+
+  /*
+   * drain any extraneous input
+   */
+  stk500v2_drain(pgm, 0);
+
+  mycookie = pgm->cookie;
+  pgm->cookie = PDATA(pgm)->chained_pdata;
+  if (jtagmkII_getsync(pgm, EMULATOR_MODE_SPI) != 0) {
+    fprintf(stderr, "%s: failed to sync with the AVR Dragon in ISP mode\n",
+            progname);
+    pgm->cookie = mycookie;
+    return -1;
+  }
+  pgm->cookie = mycookie;
+
+  PDATA(pgm)->pgmtype = PGMTYPE_JTAGICE_MKII;
+
+  if (pgm->bitclock != 0.0) {
+    if (pgm->set_sck_period(pgm, pgm->bitclock) != 0)
+      return -1;
+  }
+
+  return 0;
+}
+
+
+/*
+ * Wrapper functions for the AVR Dragon in HV mode.  This mode
+ * uses the normal JTAG ICE mkII packet stream to communicate with the
+ * ICE, but then encapsulates AVRISP mkII commands using
+ * CMND_ISP_PACKET.
+ */
+
+/*
+ * Open an AVR Dragon in HV mode (HVSP or parallel).
+ */
+static int stk500v2_dragon_hv_open(PROGRAMMER * pgm, char * port)
+{
+  long baud;
+  void *mycookie;
+
+  if (verbose >= 2)
+    fprintf(stderr, "%s: stk500v2_dragon_hv_open()\n", progname);
+
+  /*
+   * The JTAG ICE mkII always starts with a baud rate of 19200 Bd upon
+   * attaching.  If the config file or command-line parameters specify
+   * a higher baud rate, we switch to it later on, after establishing
+   * the connection with the ICE.
+   */
+  baud = 19200;
+
+  /*
+   * If the port name starts with "usb", divert the serial routines
+   * to the USB ones.  The serial_open() function for USB overrides
+   * the meaning of the "baud" parameter to be the USB device ID to
+   * search for.
+   */
+  if (strncmp(port, "usb", 3) == 0) {
+#if defined(HAVE_LIBUSB)
+    serdev = &usb_serdev;
+    baud = USB_DEVICE_AVRDRAGON;
+#else
+    fprintf(stderr, "avrdude was compiled without usb support.\n");
+    return -1;
+#endif
+  }
+
+  strcpy(pgm->port, port);
+  serial_open(port, baud, &pgm->fd);
+
+  /*
+   * drain any extraneous input
+   */
+  stk500v2_drain(pgm, 0);
+
+  mycookie = pgm->cookie;
+  pgm->cookie = PDATA(pgm)->chained_pdata;
+  if (jtagmkII_getsync(pgm, EMULATOR_MODE_HV) != 0) {
+    fprintf(stderr, "%s: failed to sync with the AVR Dragon in HV mode\n",
+            progname);
+    pgm->cookie = mycookie;
+    return -1;
+  }
+  pgm->cookie = mycookie;
+
+  PDATA(pgm)->pgmtype = PGMTYPE_JTAGICE_MKII;
+
+  if (pgm->bitclock != 0.0) {
+    if (pgm->set_sck_period(pgm, pgm->bitclock) != 0)
+      return -1;
+  }
+
+  return 0;
+}
+
+/*
+ * XPROG wrapper
+ */
+static int stk600_xprog_command(PROGRAMMER * pgm, unsigned char *b,
+                                unsigned int cmdsize, unsigned int responsesize)
+{
+    unsigned char *newb;
+    unsigned int s;
+    int rv;
+
+    if (cmdsize < responsesize)
+        s = responsesize;
+    else
+        s = cmdsize;
+
+    if ((newb = malloc(s + 1)) == 0) {
+        fprintf(stderr, "%s: stk600_xprog_cmd(): out of memory\n",
+                progname);
+        return -1;
+    }
+
+    newb[0] = CMD_XPROG;
+    memcpy(newb + 1, b, cmdsize);
+    rv = stk500v2_command(pgm, newb, cmdsize + 1, responsesize + 1);
+    if (rv == 0) {
+        memcpy(b, newb + 1, responsesize);
+    }
+
+    free(newb);
+
+    return rv;
+}
+
+
+/*
+ * issue the 'program enable' command to the AVR device, XPROG version
+ */
+static int stk600_xprog_program_enable(PROGRAMMER * pgm, AVRPART * p)
+{
+    unsigned char buf[16];
+    unsigned int eepagesize = 42;
+    unsigned int nvm_base;
+    AVRMEM *mem = NULL;
+    int use_tpi;
+
+    use_tpi = (p->flags & AVRPART_HAS_TPI) != 0;
+
+    if (!use_tpi) {
+        if (p->nvm_base == 0) {
+            fprintf(stderr,
+            "%s: stk600_xprog_program_enable(): no nvm_base parameter for PDI device\n",
+                    progname);
+            return -1;
+        }
+        if ((mem = avr_locate_mem(p, "eeprom")) != NULL) {
+            if (mem->page_size == 0) {
+                fprintf(stderr,
+                "%s: stk600_xprog_program_enable(): no EEPROM page_size parameter for PDI device\n",
+                        progname);
+                return -1;
+            }
+            eepagesize = mem->page_size;
+        }
+    }
+
+    buf[0] = CMD_XPROG_SETMODE;
+    buf[1] = use_tpi? XPRG_MODE_TPI: XPRG_MODE_PDI;
+    if (stk500v2_command(pgm, buf, 2, sizeof(buf)) < 0) {
+        fprintf(stderr,
+        "%s: stk600_xprog_program_enable(): CMD_XPROG_SETMODE(XPRG_MODE_%s) failed\n",
+                progname, use_tpi? "TPI": "PDI");
+        return -1;
+    }
+
+    buf[0] = XPRG_CMD_ENTER_PROGMODE;
+    if (stk600_xprog_command(pgm, buf, 1, 2) < 0) {
+        fprintf(stderr,
+        "%s: stk600_xprog_program_enable(): XPRG_CMD_ENTER_PROGMODE failed\n",
+                progname);
+        return -1;
+    }
+
+    if (use_tpi) {
+        /*
+         * Whatever all that might mean, it matches what AVR Studio
+         * does.
+         */
+        if (stk500v2_setparm_real(pgm, PARAM_DISCHARGEDELAY, 232) < 0)
+            return -1;
+
+        buf[0] = XPRG_CMD_SET_PARAM;
+        buf[1] = XPRG_PARAM_TPI_3;
+        buf[2] = 51;
+        if (stk600_xprog_command(pgm, buf, 3, 2) < 0) {
+            fprintf(stderr,
+            "%s: stk600_xprog_program_enable(): XPRG_CMD_SET_PARAM(XPRG_PARAM_TPI_3) failed\n",
+                    progname);
+            return -1;
+        }
+
+        buf[0] = XPRG_CMD_SET_PARAM;
+        buf[1] = XPRG_PARAM_TPI_4;
+        buf[2] = 50;
+        if (stk600_xprog_command(pgm, buf, 3, 2) < 0) {
+            fprintf(stderr,
+            "%s: stk600_xprog_program_enable(): XPRG_CMD_SET_PARAM(XPRG_PARAM_TPI_4) failed\n",
+                    progname);
+            return -1;
+        }
+    } else {
+        buf[0] = XPRG_CMD_SET_PARAM;
+        buf[1] = XPRG_PARAM_NVMBASE;
+        nvm_base = p->nvm_base;
+        /*
+         * The 0x01000000 appears to be an indication to the programmer
+         * that the respective address is located in IO (i.e., SRAM)
+         * memory address space rather than flash.  This is not documented
+         * anywhere in AVR079 but matches what AVR Studio does.
+         */
+        nvm_base |= 0x01000000;
+        buf[2] = nvm_base >> 24;
+        buf[3] = nvm_base >> 16;
+        buf[4] = nvm_base >> 8;
+        buf[5] = nvm_base;
+        if (stk600_xprog_command(pgm, buf, 6, 2) < 0) {
+            fprintf(stderr,
+            "%s: stk600_xprog_program_enable(): XPRG_CMD_SET_PARAM(XPRG_PARAM_NVMBASE) failed\n",
+                    progname);
+            return -1;
+        }
+
+        if (mem != NULL) {
+            buf[0] = XPRG_CMD_SET_PARAM;
+            buf[1] = XPRG_PARAM_EEPPAGESIZE;
+            buf[2] = eepagesize >> 8;
+            buf[3] = eepagesize;
+            if (stk600_xprog_command(pgm, buf, 4, 2) < 0) {
+                fprintf(stderr,
+                "%s: stk600_xprog_program_enable(): XPRG_CMD_SET_PARAM(XPRG_PARAM_EEPPAGESIZE) failed\n",
+                        progname);
+                return -1;
+            }
+        }
+    }
+
+    return 0;
+}
+
+static void stk600_xprog_disable(PROGRAMMER * pgm)
+{
+    unsigned char buf[2];
+
+    buf[0] = XPRG_CMD_LEAVE_PROGMODE;
+    if (stk600_xprog_command(pgm, buf, 1, 2) < 0) {
+        fprintf(stderr,
+                "%s: stk600_xprog_program_disable(): XPRG_CMD_LEAVE_PROGMODE failed\n",
+                progname);
+    }
+}
+
+static int stk600_xprog_write_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+				   unsigned long addr, unsigned char data)
+{
+    unsigned char b[9 + 256];
+    int need_erase = 0;
+    unsigned char write_size = 1;
+    unsigned char memcode;
+
+    memset(b, 0, sizeof(b));
+
+    if (strcmp(mem->desc, "flash") == 0) {
+        memcode = XPRG_MEM_TYPE_APPL;
+    } else if (strcmp(mem->desc, "boot") == 0) {
+        memcode = XPRG_MEM_TYPE_BOOT;
+    } else if (strcmp(mem->desc, "eeprom") == 0) {
+        memcode = XPRG_MEM_TYPE_EEPROM;
+    } else if (strcmp(mem->desc, "lockbits") == 0) {
+        memcode = XPRG_MEM_TYPE_LOCKBITS;
+    } else if (strncmp(mem->desc, "fuse", strlen("fuse")) == 0) {
+        memcode = XPRG_MEM_TYPE_FUSE;
+        if (p->flags & AVRPART_HAS_TPI)
+            /*
+             * TPI devices need a mystic erase prior to writing their
+             * fuses.
+             */
+            need_erase = 1;
+    } else if (strcmp(mem->desc, "usersig") == 0) {
+        memcode = XPRG_MEM_TYPE_USERSIG;
+    } else {
+        fprintf(stderr,
+                "%s: stk600_xprog_write_byte(): unknown memory \"%s\"\n",
+                progname, mem->desc);
+        return -1;
+    }
+    addr += mem->offset;
+
+    if (need_erase) {
+        b[0] = XPRG_CMD_ERASE;
+        b[1] = XPRG_ERASE_CONFIG;
+        b[2] = mem->offset >> 24;
+        b[3] = mem->offset >> 16;
+        b[4] = mem->offset >> 8;
+        b[5] = mem->offset + 1;
+        if (stk600_xprog_command(pgm, b, 6, 2) < 0) {
+	    fprintf(stderr,
+	    "%s: stk600_xprog_chip_erase(): XPRG_CMD_ERASE(XPRG_ERASE_CONFIG) failed\n",
+		    progname);
+	    return -1;
+	}
+    }
+
+    if (p->flags & AVRPART_HAS_TPI) {
+        /*
+         * Some TPI memories (configuration aka. fuse) require a
+         * larger write block size.  We record that as a blocksize in
+         * avrdude.conf.
+         */
+        if (mem->blocksize != 0)
+            write_size = mem->blocksize;
+    }
+
+    b[0] = XPRG_CMD_WRITE_MEM;
+    b[1] = memcode;
+    b[2] = 0;			/* pagemode: non-paged write */
+    b[3] = addr >> 24;
+    b[4] = addr >> 16;
+    b[5] = addr >> 8;
+    b[6] = addr;
+    b[7] = 0;
+    b[8] = write_size;
+    b[9] = data;
+    if (stk600_xprog_command(pgm, b, 9 + write_size, 2) < 0) {
+        fprintf(stderr,
+                "%s: stk600_xprog_write_byte(): XPRG_CMD_WRITE_MEM failed\n",
+                progname);
+        return -1;
+    }
+    return 0;
+}
+
+
+static int stk600_xprog_read_byte(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+                                  unsigned long addr, unsigned char * value)
+{
+    unsigned char b[8];
+
+    if (strcmp(mem->desc, "flash") == 0) {
+        b[1] = XPRG_MEM_TYPE_APPL;
+    } else if (strcmp(mem->desc, "boot") == 0) {
+        b[1] = XPRG_MEM_TYPE_BOOT;
+    } else if (strcmp(mem->desc, "eeprom") == 0) {
+        b[1] = XPRG_MEM_TYPE_EEPROM;
+    } else if (strcmp(mem->desc, "signature") == 0) {
+        b[1] = XPRG_MEM_TYPE_APPL;
+    } else if (strncmp(mem->desc, "fuse", strlen("fuse")) == 0) {
+        b[1] = XPRG_MEM_TYPE_FUSE;
+    } else if (strcmp(mem->desc, "lockbits") == 0) {
+        b[1] = XPRG_MEM_TYPE_LOCKBITS;
+    } else if (strcmp(mem->desc, "calibration") == 0) {
+        b[1] = XPRG_MEM_TYPE_FACTORY_CALIBRATION;
+    } else if (strcmp(mem->desc, "usersig") == 0) {
+        b[1] = XPRG_MEM_TYPE_USERSIG;
+    } else {
+        fprintf(stderr,
+                "%s: stk600_xprog_read_byte(): unknown memory \"%s\"\n",
+                progname, mem->desc);
+        return -1;
+    }
+    addr += mem->offset;
+
+    b[0] = XPRG_CMD_READ_MEM;
+    b[2] = addr >> 24;
+    b[3] = addr >> 16;
+    b[4] = addr >> 8;
+    b[5] = addr;
+    b[6] = 0;
+    b[7] = 1;
+    if (stk600_xprog_command(pgm, b, 8, 3) < 0) {
+        fprintf(stderr,
+                "%s: stk600_xprog_read_byte(): XPRG_CMD_READ_MEM failed\n",
+                progname);
+        return -1;
+    }
+    *value = b[2];
+    return 0;
+}
+
+
+static int stk600_xprog_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+				   int page_size, int n_bytes)
+{
+    unsigned char *b;
+    unsigned int addr;
+    unsigned int offset;
+    unsigned char memtype;
+    int n_bytes_orig = n_bytes;
+    unsigned long use_ext_addr = 0;
+
+    /*
+     * The XPROG read command supports at most 256 bytes in one
+     * transfer.
+     */
+    if (page_size > 256)
+	page_size = 256;	/* not really a page size anymore */
+
+    /*
+     * Fancy offsets everywhere.
+     * This is probably what AVR079 means when writing about the
+     * "TIF address space".
+     */
+    if (strcmp(mem->desc, "flash") == 0) {
+        memtype = XPRG_MEM_TYPE_APPL;
+        if (mem->size > 64 * 1024)
+            use_ext_addr = (1UL << 31);
+    } else if (strcmp(mem->desc, "boot") == 0) {
+        memtype = XPRG_MEM_TYPE_BOOT;
+        // Do we have to consider the total amount of flash
+        // instead to decide whether to use extended addressing?
+        if (mem->size > 64 * 1024)
+            use_ext_addr = (1UL << 31);
+    } else if (strcmp(mem->desc, "eeprom") == 0) {
+        memtype = XPRG_MEM_TYPE_EEPROM;
+    } else {
+        fprintf(stderr,
+                "%s: stk600_xprog_paged_load(): unknown paged memory \"%s\"\n",
+                progname, mem->desc);
+        return -1;
+    }
+    addr = mem->offset;
+
+    if ((b = malloc(page_size + 2)) == NULL) {
+	fprintf(stderr,
+                "%s: stk600_xprog_paged_load(): out of memory\n",
+                progname);
+        return -1;
+    }
+
+    if (stk500v2_loadaddr(pgm, use_ext_addr) < 0)
+        return -1;
+
+    offset = 0;
+    while (n_bytes != 0) {
+	report_progress(offset, n_bytes_orig, NULL);
+	b[0] = XPRG_CMD_READ_MEM;
+	b[1] = memtype;
+	b[2] = addr >> 24;
+	b[3] = addr >> 16;
+	b[4] = addr >> 8;
+	b[5] = addr;
+	b[6] = page_size >> 8;
+	b[7] = page_size;
+	if (stk600_xprog_command(pgm, b, 8, page_size + 2) < 0) {
+	    fprintf(stderr,
+		    "%s: stk600_xprog_paged_load(): XPRG_CMD_READ_MEM failed\n",
+		    progname);
+	    return -1;
+	}
+	memcpy(mem->buf + offset, b + 2, page_size);
+	if (n_bytes < page_size) {
+	    n_bytes = page_size;
+	}
+	offset += page_size;
+	addr += page_size;
+	n_bytes -= page_size;
+    }
+    free(b);
+
+    return n_bytes_orig;
+}
+
+static int stk600_xprog_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+				    int page_size, int n_bytes)
+{
+    unsigned char *b;
+    unsigned int addr;
+    unsigned int offset;
+    unsigned char memtype;
+    int n_bytes_orig = n_bytes;
+    size_t writesize;
+    unsigned long use_ext_addr = 0;
+    unsigned char writemode;
+
+    /*
+     * The XPROG read command supports at most 256 bytes in one
+     * transfer.
+     */
+    if (page_size > 512) {
+	fprintf(stderr,
+		"%s: stk600_xprog_paged_write(): cannot handle page size > 512\n",
+		progname);
+	return -1;
+    }
+
+    /*
+     * Fancy offsets everywhere.
+     * This is probably what AVR079 means when writing about the
+     * "TIF address space".
+     */
+    if (strcmp(mem->desc, "flash") == 0) {
+        memtype = XPRG_MEM_TYPE_APPL;
+        writemode = (1 << XPRG_MEM_WRITE_WRITE);
+        if (mem->size > 64 * 1024)
+            use_ext_addr = (1UL << 31);
+    } else if (strcmp(mem->desc, "boot") == 0) {
+        memtype = XPRG_MEM_TYPE_BOOT;
+        writemode = (1 << XPRG_MEM_WRITE_WRITE);
+        // Do we have to consider the total amount of flash
+        // instead to decide whether to use extended addressing?
+        if (mem->size > 64 * 1024)
+            use_ext_addr = (1UL << 31);
+    } else if (strcmp(mem->desc, "eeprom") == 0) {
+        memtype = XPRG_MEM_TYPE_EEPROM;
+        writemode = (1 << XPRG_MEM_WRITE_WRITE) | (1 << XPRG_MEM_WRITE_ERASE);
+    } else {
+        fprintf(stderr,
+                "%s: stk600_xprog_paged_write(): unknown paged memory \"%s\"\n",
+                progname, mem->desc);
+        return -1;
+    }
+    addr = mem->offset;
+
+    if ((b = malloc(page_size + 9)) == NULL) {
+	fprintf(stderr,
+                "%s: stk600_xprog_paged_write(): out of memory\n",
+                progname);
+        return -1;
+    }
+
+    if (stk500v2_loadaddr(pgm, use_ext_addr) < 0)
+        return -1;
+
+    offset = 0;
+    while (n_bytes != 0) {
+	report_progress(offset, n_bytes_orig, NULL);
+
+	if (page_size > 256) {
+	    /*
+	     * AVR079 is not quite clear.  While it suggests that
+	     * downloading up to 512 bytes (256 words) were OK, it
+	     * obviously isn't -- 512-byte pages on the ATxmega128A1
+	     * are getting corrupted when written as a single piece.
+	     * It writes random junk somewhere beyond byte 256.
+	     * Splitting it into 256 byte chunks, and only setting the
+	     * erase page / write page bits in the final chunk helps.
+	     */
+	    if (page_size % 256 != 0) {
+		fprintf(stderr,
+			"%s: stk600_xprog_paged_write(): page size not multiple of 256\n",
+			progname);
+		return -1;
+	    }
+	    unsigned int chunk;
+	    for (chunk = 0; chunk < page_size; chunk += 256) {
+                if (n_bytes < 256) {
+                    memset(b + 9 + n_bytes, 0xff, 256 - n_bytes);
+                    writesize = n_bytes;
+                } else {
+                    writesize = 256;
+                }
+		b[0] = XPRG_CMD_WRITE_MEM;
+		b[1] = memtype;
+		if (chunk + 256 == page_size) {
+		    b[2] = writemode;	/* last chunk */
+		} else {
+		    b[2] = 0;	/* initial/intermediate chunk: just download */
+		}
+		b[3] = addr >> 24;
+		b[4] = addr >> 16;
+		b[5] = addr >> 8;
+		b[6] = addr;
+		b[7] = 1;
+		b[8] = 0;
+		memcpy(b + 9, mem->buf + offset, writesize);
+		if (stk600_xprog_command(pgm, b, 256 + 9, 2) < 0) {
+		    fprintf(stderr,
+			    "%s: stk600_xprog_paged_write(): XPRG_CMD_WRITE_MEM failed\n",
+			    progname);
+		    return -1;
+		}
+		if (n_bytes < 256)
+		    n_bytes = 256;
+
+		offset += 256;
+		addr += 256;
+		n_bytes -= 256;
+	    }
+	} else {
+	    if (n_bytes < page_size) {
+		/*
+		 * This can easily happen if the input file was not a
+		 * multiple of the page size.
+		 */
+		memset(b + 9 + n_bytes, 0xff, page_size - n_bytes);
+                writesize = n_bytes;
+            } else {
+                writesize = page_size;
+            }
+	    b[0] = XPRG_CMD_WRITE_MEM;
+	    b[1] = memtype;
+	    b[2] = writemode;
+	    b[3] = addr >> 24;
+	    b[4] = addr >> 16;
+	    b[5] = addr >> 8;
+	    b[6] = addr;
+	    b[7] = page_size >> 8;
+	    b[8] = page_size;
+	    memcpy(b + 9, mem->buf + offset, writesize);
+	    if (stk600_xprog_command(pgm, b, page_size + 9, 2) < 0) {
+		fprintf(stderr,
+			"%s: stk600_xprog_paged_write(): XPRG_CMD_WRITE_MEM failed\n",
+			progname);
+		return -1;
+	    }
+	    if (n_bytes < page_size)
+		n_bytes = page_size;
+
+	    offset += page_size;
+	    addr += page_size;
+	    n_bytes -= page_size;
+	}
+    }
+    free(b);
+
+    return n_bytes_orig;
+}
+
+static int stk600_xprog_chip_erase(PROGRAMMER * pgm, AVRPART * p)
+{
+    unsigned char b[6];
+    AVRMEM *mem;
+    unsigned int addr = 0;
+
+    if (p->flags & AVRPART_HAS_TPI) {
+        if ((mem = avr_locate_mem(p, "flash")) == NULL) {
+            fprintf(stderr,
+            "%s: stk600_xprog_chip_erase(): no FLASH definition found for TPI device\n",
+                    progname);
+            return -1;
+        }
+        addr = mem->offset + 1;
+    }
+
+    b[0] = XPRG_CMD_ERASE;
+    b[1] = XPRG_ERASE_CHIP;
+    b[2] = addr >> 24;
+    b[3] = addr >> 16;
+    b[4] = addr >> 8;
+    b[5] = addr;
+    if (stk600_xprog_command(pgm, b, 6, 2) < 0) {
+	    fprintf(stderr,
+		    "%s: stk600_xprog_chip_erase(): XPRG_CMD_ERASE(XPRG_ERASE_CHIP) failed\n",
+		    progname);
+	    return -1;
+	}
+    return 0;
+}
+
+/*
+ * Modify pgm's methods for XPROG operation.
+ */
+static void stk600_setup_xprog(PROGRAMMER * pgm)
+{
+    pgm->program_enable = stk600_xprog_program_enable;
+    pgm->disable = stk600_xprog_disable;
+    pgm->read_byte = stk600_xprog_read_byte;
+    pgm->write_byte = stk600_xprog_write_byte;
+    pgm->paged_load = stk600_xprog_paged_load;
+    pgm->paged_write = stk600_xprog_paged_write;
+    pgm->chip_erase = stk600_xprog_chip_erase;
+}
+
+
+/*
+ * Modify pgm's methods for ISP operation.
+ */
+static void stk600_setup_isp(PROGRAMMER * pgm)
+{
+    pgm->program_enable = stk500v2_program_enable;
+    pgm->disable = stk500v2_disable;
+    pgm->read_byte = avr_read_byte_default;
+    pgm->write_byte = avr_write_byte_default;
+    pgm->paged_load = stk500v2_paged_load;
+    pgm->paged_write = stk500v2_paged_write;
+    pgm->chip_erase = stk500v2_chip_erase;
+}
+
+
+void stk500v2_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "STK500V2");
+
+  /*
+   * mandatory functions
+   */
+  pgm->initialize     = stk500v2_initialize;
+  pgm->display        = stk500v2_display;
+  pgm->enable         = stk500v2_enable;
+  pgm->disable        = stk500v2_disable;
+  pgm->program_enable = stk500v2_program_enable;
+  pgm->chip_erase     = stk500v2_chip_erase;
+  pgm->cmd            = stk500v2_cmd;
+  pgm->open           = stk500v2_open;
+  pgm->close          = stk500v2_close;
+  pgm->read_byte      = avr_read_byte_default;
+  pgm->write_byte     = avr_write_byte_default;
+
+  /*
+   * optional functions
+   */
+  pgm->paged_write    = stk500v2_paged_write;
+  pgm->paged_load     = stk500v2_paged_load;
+  pgm->print_parms    = stk500v2_print_parms;
+  pgm->set_vtarget    = stk500v2_set_vtarget;
+  pgm->set_varef      = stk500v2_set_varef;
+  pgm->set_fosc       = stk500v2_set_fosc;
+  pgm->set_sck_period = stk500v2_set_sck_period;
+  pgm->perform_osccal = stk500v2_perform_osccal;
+  pgm->setup          = stk500v2_setup;
+  pgm->teardown       = stk500v2_teardown;
+  pgm->page_size      = 256;
+}
+
+void stk500pp_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "STK500PP");
+
+  /*
+   * mandatory functions
+   */
+  pgm->initialize     = stk500pp_initialize;
+  pgm->display        = stk500v2_display;
+  pgm->enable         = stk500v2_enable;
+  pgm->disable        = stk500pp_disable;
+  pgm->program_enable = stk500pp_program_enable;
+  pgm->chip_erase     = stk500pp_chip_erase;
+  pgm->open           = stk500v2_open;
+  pgm->close          = stk500v2_close;
+  pgm->read_byte      = stk500pp_read_byte;
+  pgm->write_byte     = stk500pp_write_byte;
+
+  /*
+   * optional functions
+   */
+  pgm->paged_write    = stk500pp_paged_write;
+  pgm->paged_load     = stk500pp_paged_load;
+  pgm->print_parms    = stk500v2_print_parms;
+  pgm->set_vtarget    = stk500v2_set_vtarget;
+  pgm->set_varef      = stk500v2_set_varef;
+  pgm->set_fosc       = stk500v2_set_fosc;
+  pgm->set_sck_period = stk500v2_set_sck_period;
+  pgm->setup          = stk500v2_setup;
+  pgm->teardown       = stk500v2_teardown;
+  pgm->page_size      = 256;
+}
+
+void stk500hvsp_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "STK500HVSP");
+
+  /*
+   * mandatory functions
+   */
+  pgm->initialize     = stk500hvsp_initialize;
+  pgm->display        = stk500v2_display;
+  pgm->enable         = stk500v2_enable;
+  pgm->disable        = stk500hvsp_disable;
+  pgm->program_enable = stk500hvsp_program_enable;
+  pgm->chip_erase     = stk500hvsp_chip_erase;
+  pgm->open           = stk500v2_open;
+  pgm->close          = stk500v2_close;
+  pgm->read_byte      = stk500hvsp_read_byte;
+  pgm->write_byte     = stk500hvsp_write_byte;
+
+  /*
+   * optional functions
+   */
+  pgm->paged_write    = stk500hvsp_paged_write;
+  pgm->paged_load     = stk500hvsp_paged_load;
+  pgm->print_parms    = stk500v2_print_parms;
+  pgm->set_vtarget    = stk500v2_set_vtarget;
+  pgm->set_varef      = stk500v2_set_varef;
+  pgm->set_fosc       = stk500v2_set_fosc;
+  pgm->set_sck_period = stk500v2_set_sck_period;
+  pgm->setup          = stk500v2_setup;
+  pgm->teardown       = stk500v2_teardown;
+  pgm->page_size      = 256;
+}
+
+void stk500v2_jtagmkII_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "JTAGMKII_ISP");
+
+  /*
+   * mandatory functions
+   */
+  pgm->initialize     = stk500v2_initialize;
+  pgm->display        = stk500v2_display;
+  pgm->enable         = stk500v2_enable;
+  pgm->disable        = stk500v2_disable;
+  pgm->program_enable = stk500v2_program_enable;
+  pgm->chip_erase     = stk500v2_chip_erase;
+  pgm->cmd            = stk500v2_cmd;
+  pgm->open           = stk500v2_jtagmkII_open;
+  pgm->close          = stk500v2_jtagmkII_close;
+  pgm->read_byte      = avr_read_byte_default;
+  pgm->write_byte     = avr_write_byte_default;
+
+  /*
+   * optional functions
+   */
+  pgm->paged_write    = stk500v2_paged_write;
+  pgm->paged_load     = stk500v2_paged_load;
+  pgm->print_parms    = stk500v2_print_parms;
+  pgm->set_sck_period = stk500v2_set_sck_period_mk2;
+  pgm->perform_osccal = stk500v2_perform_osccal;
+  pgm->setup          = stk500v2_jtagmkII_setup;
+  pgm->teardown       = stk500v2_jtagmkII_teardown;
+  pgm->page_size      = 256;
+}
+
+void stk500v2_dragon_isp_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "DRAGON_ISP");
+
+  /*
+   * mandatory functions
+   */
+  pgm->initialize     = stk500v2_initialize;
+  pgm->display        = stk500v2_display;
+  pgm->enable         = stk500v2_enable;
+  pgm->disable        = stk500v2_disable;
+  pgm->program_enable = stk500v2_program_enable;
+  pgm->chip_erase     = stk500v2_chip_erase;
+  pgm->cmd            = stk500v2_cmd;
+  pgm->open           = stk500v2_dragon_isp_open;
+  pgm->close          = stk500v2_jtagmkII_close;
+  pgm->read_byte      = avr_read_byte_default;
+  pgm->write_byte     = avr_write_byte_default;
+
+  /*
+   * optional functions
+   */
+  pgm->paged_write    = stk500v2_paged_write;
+  pgm->paged_load     = stk500v2_paged_load;
+  pgm->print_parms    = stk500v2_print_parms;
+  pgm->set_sck_period = stk500v2_set_sck_period_mk2;
+  pgm->setup          = stk500v2_jtagmkII_setup;
+  pgm->teardown       = stk500v2_jtagmkII_teardown;
+  pgm->page_size      = 256;
+}
+
+void stk500v2_dragon_pp_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "DRAGON_PP");
+
+  /*
+   * mandatory functions
+   */
+  pgm->initialize     = stk500pp_initialize;
+  pgm->display        = stk500v2_display;
+  pgm->enable         = stk500v2_enable;
+  pgm->disable        = stk500pp_disable;
+  pgm->program_enable = stk500pp_program_enable;
+  pgm->chip_erase     = stk500pp_chip_erase;
+  pgm->open           = stk500v2_dragon_hv_open;
+  pgm->close          = stk500v2_jtagmkII_close;
+  pgm->read_byte      = stk500pp_read_byte;
+  pgm->write_byte     = stk500pp_write_byte;
+
+  /*
+   * optional functions
+   */
+  pgm->paged_write    = stk500pp_paged_write;
+  pgm->paged_load     = stk500pp_paged_load;
+  pgm->print_parms    = stk500v2_print_parms;
+  pgm->set_vtarget    = stk500v2_set_vtarget;
+  pgm->set_varef      = stk500v2_set_varef;
+  pgm->set_fosc       = stk500v2_set_fosc;
+  pgm->set_sck_period = stk500v2_set_sck_period_mk2;
+  pgm->setup          = stk500v2_jtagmkII_setup;
+  pgm->teardown       = stk500v2_jtagmkII_teardown;
+  pgm->page_size      = 256;
+}
+
+void stk500v2_dragon_hvsp_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "DRAGON_HVSP");
+
+  /*
+   * mandatory functions
+   */
+  pgm->initialize     = stk500hvsp_initialize;
+  pgm->display        = stk500v2_display;
+  pgm->enable         = stk500v2_enable;
+  pgm->disable        = stk500hvsp_disable;
+  pgm->program_enable = stk500hvsp_program_enable;
+  pgm->chip_erase     = stk500hvsp_chip_erase;
+  pgm->open           = stk500v2_dragon_hv_open;
+  pgm->close          = stk500v2_jtagmkII_close;
+  pgm->read_byte      = stk500hvsp_read_byte;
+  pgm->write_byte     = stk500hvsp_write_byte;
+
+  /*
+   * optional functions
+   */
+  pgm->paged_write    = stk500hvsp_paged_write;
+  pgm->paged_load     = stk500hvsp_paged_load;
+  pgm->print_parms    = stk500v2_print_parms;
+  pgm->set_vtarget    = stk500v2_set_vtarget;
+  pgm->set_varef      = stk500v2_set_varef;
+  pgm->set_fosc       = stk500v2_set_fosc;
+  pgm->set_sck_period = stk500v2_set_sck_period_mk2;
+  pgm->setup          = stk500v2_jtagmkII_setup;
+  pgm->teardown       = stk500v2_jtagmkII_teardown;
+  pgm->page_size      = 256;
+}
+
+void stk600_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "STK600");
+
+  /*
+   * mandatory functions
+   */
+  pgm->initialize     = stk500v2_initialize;
+  pgm->display        = stk500v2_display;
+  pgm->enable         = stk500v2_enable;
+  pgm->disable        = stk500v2_disable;
+  pgm->program_enable = stk500v2_program_enable;
+  pgm->chip_erase     = stk500v2_chip_erase;
+  pgm->cmd            = stk500v2_cmd;
+  pgm->open           = stk600_open;
+  pgm->close          = stk500v2_close;
+  pgm->read_byte      = avr_read_byte_default;
+  pgm->write_byte     = avr_write_byte_default;
+
+  /*
+   * optional functions
+   */
+  pgm->paged_write    = stk500v2_paged_write;
+  pgm->paged_load     = stk500v2_paged_load;
+  pgm->print_parms    = stk500v2_print_parms;
+  pgm->set_vtarget    = stk600_set_vtarget;
+  pgm->set_varef      = stk600_set_varef;
+  pgm->set_fosc       = stk600_set_fosc;
+  pgm->set_sck_period = stk600_set_sck_period;
+  pgm->perform_osccal = stk500v2_perform_osccal;
+  pgm->setup          = stk500v2_setup;
+  pgm->teardown       = stk500v2_teardown;
+  pgm->page_size      = 256;
+}
+
+void stk600pp_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "STK600PP");
+
+  /*
+   * mandatory functions
+   */
+  pgm->initialize     = stk500pp_initialize;
+  pgm->display        = stk500v2_display;
+  pgm->enable         = stk500v2_enable;
+  pgm->disable        = stk500pp_disable;
+  pgm->program_enable = stk500pp_program_enable;
+  pgm->chip_erase     = stk500pp_chip_erase;
+  pgm->open           = stk600_open;
+  pgm->close          = stk500v2_close;
+  pgm->read_byte      = stk500pp_read_byte;
+  pgm->write_byte     = stk500pp_write_byte;
+
+  /*
+   * optional functions
+   */
+  pgm->paged_write    = stk500pp_paged_write;
+  pgm->paged_load     = stk500pp_paged_load;
+  pgm->print_parms    = stk500v2_print_parms;
+  pgm->set_vtarget    = stk600_set_vtarget;
+  pgm->set_varef      = stk600_set_varef;
+  pgm->set_fosc       = stk600_set_fosc;
+  pgm->set_sck_period = stk600_set_sck_period;
+  pgm->setup          = stk500v2_setup;
+  pgm->teardown       = stk500v2_teardown;
+  pgm->page_size      = 256;
+}
+
+void stk600hvsp_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "STK600HVSP");
+
+  /*
+   * mandatory functions
+   */
+  pgm->initialize     = stk500hvsp_initialize;
+  pgm->display        = stk500v2_display;
+  pgm->enable         = stk500v2_enable;
+  pgm->disable        = stk500hvsp_disable;
+  pgm->program_enable = stk500hvsp_program_enable;
+  pgm->chip_erase     = stk500hvsp_chip_erase;
+  pgm->open           = stk600_open;
+  pgm->close          = stk500v2_close;
+  pgm->read_byte      = stk500hvsp_read_byte;
+  pgm->write_byte     = stk500hvsp_write_byte;
+
+  /*
+   * optional functions
+   */
+  pgm->paged_write    = stk500hvsp_paged_write;
+  pgm->paged_load     = stk500hvsp_paged_load;
+  pgm->print_parms    = stk500v2_print_parms;
+  pgm->set_vtarget    = stk600_set_vtarget;
+  pgm->set_varef      = stk600_set_varef;
+  pgm->set_fosc       = stk600_set_fosc;
+  pgm->set_sck_period = stk600_set_sck_period;
+  pgm->setup          = stk500v2_setup;
+  pgm->teardown       = stk500v2_teardown;
+  pgm->page_size      = 256;
+}
+
diff --git a/avrdude/stk500v2.h b/avrdude/stk500v2.h
new file mode 100644
index 00000000..70e41cc2
--- /dev/null
+++ b/avrdude/stk500v2.h
@@ -0,0 +1,47 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2002-2005  Brian S. Dean <bsd@bsdhome.com>
+ * Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 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
+ */
+
+/* $Id$ */
+
+#ifndef stk500v2_h
+#define stk500v2_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void stk500v2_initpgm (PROGRAMMER * pgm);
+void stk500hvsp_initpgm (PROGRAMMER * pgm);
+void stk500pp_initpgm (PROGRAMMER * pgm);
+void stk500v2_jtagmkII_initpgm(PROGRAMMER * pgm);
+void stk500v2_dragon_hvsp_initpgm(PROGRAMMER * pgm);
+void stk500v2_dragon_isp_initpgm(PROGRAMMER * pgm);
+void stk500v2_dragon_pp_initpgm(PROGRAMMER * pgm);
+void stk600_initpgm (PROGRAMMER * pgm);
+void stk600hvsp_initpgm (PROGRAMMER * pgm);
+void stk600pp_initpgm (PROGRAMMER * pgm);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/avrdude/stk500v2_private.h b/avrdude/stk500v2_private.h
new file mode 100644
index 00000000..d0079801
--- /dev/null
+++ b/avrdude/stk500v2_private.h
@@ -0,0 +1,280 @@
+//**** ATMEL AVR - A P P L I C A T I O N   N O T E  ************************
+//*
+//* Title:		AVR068 - STK500 Communication Protocol
+//* Filename:		command.h
+//* Version:		1.0
+//* Last updated:	10.01.2005
+//*
+//* Support E-mail:	avr@atmel.com
+//*
+//**************************************************************************
+
+// *****************[ STK message constants ]***************************
+
+#define MESSAGE_START                       0x1B        //= ESC = 27 decimal
+#define TOKEN                               0x0E
+
+// *****************[ STK general command constants ]**************************
+
+#define CMD_SIGN_ON                         0x01
+#define CMD_SET_PARAMETER                   0x02
+#define CMD_GET_PARAMETER                   0x03
+#define CMD_SET_DEVICE_PARAMETERS           0x04
+#define CMD_OSCCAL                          0x05
+#define CMD_LOAD_ADDRESS                    0x06
+#define CMD_FIRMWARE_UPGRADE                0x07
+#define CMD_CHECK_TARGET_CONNECTION         0x0D
+#define CMD_LOAD_RC_ID_TABLE                0x0E
+#define CMD_LOAD_EC_ID_TABLE                0x0F
+
+
+// *****************[ STK ISP command constants ]******************************
+
+#define CMD_ENTER_PROGMODE_ISP              0x10
+#define CMD_LEAVE_PROGMODE_ISP              0x11
+#define CMD_CHIP_ERASE_ISP                  0x12
+#define CMD_PROGRAM_FLASH_ISP               0x13
+#define CMD_READ_FLASH_ISP                  0x14
+#define CMD_PROGRAM_EEPROM_ISP              0x15
+#define CMD_READ_EEPROM_ISP                 0x16
+#define CMD_PROGRAM_FUSE_ISP                0x17
+#define CMD_READ_FUSE_ISP                   0x18
+#define CMD_PROGRAM_LOCK_ISP                0x19
+#define CMD_READ_LOCK_ISP                   0x1A
+#define CMD_READ_SIGNATURE_ISP              0x1B
+#define CMD_READ_OSCCAL_ISP                 0x1C
+#define CMD_SPI_MULTI                       0x1D
+
+// *****************[ STK PP command constants ]*******************************
+
+#define CMD_ENTER_PROGMODE_PP               0x20
+#define CMD_LEAVE_PROGMODE_PP               0x21
+#define CMD_CHIP_ERASE_PP                   0x22
+#define CMD_PROGRAM_FLASH_PP                0x23
+#define CMD_READ_FLASH_PP                   0x24
+#define CMD_PROGRAM_EEPROM_PP               0x25
+#define CMD_READ_EEPROM_PP                  0x26
+#define CMD_PROGRAM_FUSE_PP                 0x27
+#define CMD_READ_FUSE_PP                    0x28
+#define CMD_PROGRAM_LOCK_PP                 0x29
+#define CMD_READ_LOCK_PP                    0x2A
+#define CMD_READ_SIGNATURE_PP               0x2B
+#define CMD_READ_OSCCAL_PP                  0x2C
+
+#define CMD_SET_CONTROL_STACK               0x2D
+
+// *****************[ STK HVSP command constants ]*****************************
+
+#define CMD_ENTER_PROGMODE_HVSP             0x30
+#define CMD_LEAVE_PROGMODE_HVSP             0x31
+#define CMD_CHIP_ERASE_HVSP                 0x32
+#define CMD_PROGRAM_FLASH_HVSP              0x33
+#define CMD_READ_FLASH_HVSP                 0x34
+#define CMD_PROGRAM_EEPROM_HVSP             0x35
+#define CMD_READ_EEPROM_HVSP                0x36
+#define CMD_PROGRAM_FUSE_HVSP               0x37
+#define CMD_READ_FUSE_HVSP                  0x38
+#define CMD_PROGRAM_LOCK_HVSP               0x39
+#define CMD_READ_LOCK_HVSP                  0x3A
+#define CMD_READ_SIGNATURE_HVSP             0x3B
+#define CMD_READ_OSCCAL_HVSP                0x3C
+// These two are redefined since 0x30/0x31 collide
+// with the STK600 bootloader.
+#define CMD_ENTER_PROGMODE_HVSP_STK600      0x3D
+#define CMD_LEAVE_PROGMODE_HVSP_STK600      0x3E
+
+// *** XPROG command constants ***
+
+#define CMD_XPROG                           0x50
+#define CMD_XPROG_SETMODE                   0x51
+
+
+// *** AVR32 JTAG Programming command ***
+
+#define CMD_JTAG_AVR32                      0x80
+#define CMD_ENTER_PROGMODE_JTAG_AVR32       0x81
+#define CMD_LEAVE_PROGMODE_JTAG_AVR32       0x82
+
+
+// *** AVR JTAG Programming command ***
+
+#define CMD_JTAG_AVR                        0x90
+
+// *****************[ STK test command constants ]***************************
+
+#define CMD_ENTER_TESTMODE                  0x60
+#define CMD_LEAVE_TESTMODE                  0x61
+#define CMD_CHIP_WRITE                      0x62
+#define CMD_PROGRAM_FLASH_PARTIAL           0x63
+#define CMD_PROGRAM_EEPROM_PARTIAL          0x64
+#define CMD_PROGRAM_SIGNATURE_ROW           0x65
+#define CMD_READ_FLASH_MARGIN               0x66
+#define CMD_READ_EEPROM_MARGIN              0x67
+#define CMD_READ_SIGNATURE_ROW_MARGIN       0x68
+#define CMD_PROGRAM_TEST_FUSE               0x69
+#define CMD_READ_TEST_FUSE                  0x6A
+#define CMD_PROGRAM_HIDDEN_FUSE_LOW         0x6B
+#define CMD_READ_HIDDEN_FUSE_LOW            0x6C
+#define CMD_PROGRAM_HIDDEN_FUSE_HIGH        0x6D
+#define CMD_READ_HIDDEN_FUSE_HIGH           0x6E
+#define CMD_PROGRAM_HIDDEN_FUSE_EXT         0x6F
+#define CMD_READ_HIDDEN_FUSE_EXT            0x70
+
+// *****************[ STK status constants ]***************************
+
+// Success
+#define STATUS_CMD_OK                       0x00
+
+// Warnings
+#define STATUS_CMD_TOUT                     0x80
+#define STATUS_RDY_BSY_TOUT                 0x81
+#define STATUS_SET_PARAM_MISSING            0x82
+
+// Errors
+#define STATUS_CMD_FAILED                   0xC0
+#define STATUS_CKSUM_ERROR                  0xC1
+#define STATUS_CMD_UNKNOWN                  0xC9
+#define STATUS_CMD_ILLEGAL_PARAMETER        0xCA
+
+// Status
+#define STATUS_CONN_FAIL_MOSI               0x01
+#define STATUS_CONN_FAIL_RST                0x02
+#define STATUS_CONN_FAIL_SCK                0x04
+#define STATUS_TGT_NOT_DETECTED             0x00
+#define STATUS_ISP_READY                    0x10
+#define STATUS_TGT_REVERSE_INSERTED         0x20
+
+// hw_status
+// Bits in status variable
+// Bit 0-3: Slave MCU
+// Bit 4-7: Master MCU
+
+#define STATUS_AREF_ERROR    0
+// Set to '1' if AREF is short circuited
+
+#define STATUS_VTG_ERROR     4
+// Set to '1' if VTG is short circuited
+
+#define STATUS_RC_CARD_ERROR 5
+// Set to '1' if board id changes when board is powered
+
+#define STATUS_PROGMODE      6
+// Set to '1' if board is in programming mode
+
+#define STATUS_POWER_SURGE   7
+// Set to '1' if board draws excessive current
+
+// *****************[ STK parameter constants ]***************************
+#define PARAM_BUILD_NUMBER_LOW              0x80 /* ??? */
+#define PARAM_BUILD_NUMBER_HIGH             0x81 /* ??? */
+#define PARAM_HW_VER                        0x90
+#define PARAM_SW_MAJOR                      0x91
+#define PARAM_SW_MINOR                      0x92
+#define PARAM_VTARGET                       0x94
+#define PARAM_VADJUST                       0x95 /* STK500 only */
+#define PARAM_OSC_PSCALE                    0x96 /* STK500 only */
+#define PARAM_OSC_CMATCH                    0x97 /* STK500 only */
+#define PARAM_SCK_DURATION                  0x98 /* STK500 only */
+#define PARAM_TOPCARD_DETECT                0x9A /* STK500 only */
+#define PARAM_STATUS                        0x9C /* STK500 only */
+#define PARAM_DATA                          0x9D /* STK500 only */
+#define PARAM_RESET_POLARITY                0x9E /* STK500 only, and STK600 FW
+                                                  * version <= 2.0.3 */
+#define PARAM_CONTROLLER_INIT               0x9F
+
+/* STK600 parameters */
+#define PARAM_STATUS_TGT_CONN               0xA1
+#define PARAM_DISCHARGEDELAY                0xA4
+#define PARAM_SOCKETCARD_ID                 0xA5
+#define PARAM_ROUTINGCARD_ID                0xA6
+#define PARAM_EXPCARD_ID                    0xA7
+#define PARAM_SW_MAJOR_SLAVE1               0xA8
+#define PARAM_SW_MINOR_SLAVE1               0xA9
+#define PARAM_SW_MAJOR_SLAVE2               0xAA
+#define PARAM_SW_MINOR_SLAVE2               0xAB
+#define PARAM_BOARD_ID_STATUS               0xAD
+#define PARAM_RESET                         0xB4
+
+#define PARAM_JTAG_ALLOW_FULL_PAGE_STREAM   0x50
+#define PARAM_JTAG_EEPROM_PAGE_SIZE         0x52
+#define PARAM_JTAG_DAISY_BITS_BEFORE        0x53
+#define PARAM_JTAG_DAISY_BITS_AFTER         0x54
+#define PARAM_JTAG_DAISY_UNITS_BEFORE       0x55
+#define PARAM_JTAG_DAISY_UNITS_AFTER        0x56
+
+// *** Parameter constants for 2 byte values ***
+#define PARAM2_SCK_DURATION                 0xC0
+#define PARAM2_CLOCK_CONF                   0xC1
+#define PARAM2_AREF0                        0xC2
+#define PARAM2_AREF1                        0xC3
+
+#define PARAM2_JTAG_FLASH_SIZE_H            0xC5
+#define PARAM2_JTAG_FLASH_SIZE_L            0xC6
+#define PARAM2_JTAG_FLASH_PAGE_SIZE         0xC7
+#define PARAM2_RC_ID_TABLE_REV              0xC8
+#define PARAM2_EC_ID_TABLE_REV              0xC9
+
+/* STK600 XPROG section */
+// XPROG modes
+#define XPRG_MODE_PDI                       0
+#define XPRG_MODE_JTAG                      1
+#define XPRG_MODE_TPI                       2
+
+// XPROG commands
+#define XPRG_CMD_ENTER_PROGMODE             0x01
+#define XPRG_CMD_LEAVE_PROGMODE             0x02
+#define XPRG_CMD_ERASE                      0x03
+#define XPRG_CMD_WRITE_MEM                  0x04
+#define XPRG_CMD_READ_MEM                   0x05
+#define XPRG_CMD_CRC                        0x06
+#define XPRG_CMD_SET_PARAM                  0x07
+
+// Memory types
+#define XPRG_MEM_TYPE_APPL                   1
+#define XPRG_MEM_TYPE_BOOT                   2
+#define XPRG_MEM_TYPE_EEPROM                 3
+#define XPRG_MEM_TYPE_FUSE                   4
+#define XPRG_MEM_TYPE_LOCKBITS               5
+#define XPRG_MEM_TYPE_USERSIG                6
+#define XPRG_MEM_TYPE_FACTORY_CALIBRATION    7
+
+// Erase types
+#define XPRG_ERASE_CHIP                      1
+#define XPRG_ERASE_APP                       2
+#define XPRG_ERASE_BOOT                      3
+#define XPRG_ERASE_EEPROM                    4
+#define XPRG_ERASE_APP_PAGE                  5
+#define XPRG_ERASE_BOOT_PAGE                 6
+#define XPRG_ERASE_EEPROM_PAGE               7
+#define XPRG_ERASE_USERSIG                   8
+#define XPRG_ERASE_CONFIG                    9  // TPI only, prepare fuse write
+
+// Write mode flags
+#define XPRG_MEM_WRITE_ERASE                 0
+#define XPRG_MEM_WRITE_WRITE                 1
+
+// CRC types
+#define XPRG_CRC_APP                         1
+#define XPRG_CRC_BOOT                        2
+#define XPRG_CRC_FLASH                       3
+
+// Error codes
+#define XPRG_ERR_OK                          0
+#define XPRG_ERR_FAILED                      1
+#define XPRG_ERR_COLLISION                   2
+#define XPRG_ERR_TIMEOUT                     3
+
+// XPROG parameters of different sizes
+// 4-byte address
+#define XPRG_PARAM_NVMBASE                  0x01
+// 2-byte page size
+#define XPRG_PARAM_EEPPAGESIZE              0x02
+// 1-byte, undocumented TPI param
+#define XPRG_PARAM_TPI_3                    0x03
+// 1-byte, undocumented TPI param
+#define XPRG_PARAM_TPI_4                    0x04
+
+// *****************[ STK answer constants ]***************************
+
+#define ANSWER_CKSUM_ERROR                  0xB0
+
diff --git a/avrdude/term.c b/avrdude/term.c
new file mode 100644
index 00000000..2edd857d
--- /dev/null
+++ b/avrdude/term.c
@@ -0,0 +1,940 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2000-2004  Brian S. Dean <bsd@bsdhome.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id$ */
+
+#include "ac_cfg.h"
+
+#include <ctype.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#if defined(HAVE_LIBREADLINE)
+#if !defined(WIN32NATIVE)
+#  include <readline/readline.h>
+#  include <readline/history.h>
+#endif
+#endif
+
+#include "avrdude.h"
+#include "avr.h"
+#include "config.h"
+#include "lists.h"
+#include "pgm.h"
+#include "pindefs.h"
+#include "ppi.h"
+
+struct command {
+  char * name;
+  int (*func)(PROGRAMMER * pgm, struct avrpart * p, int argc, char *argv[]);
+  char * desc;
+};
+
+
+static int cmd_dump  (PROGRAMMER * pgm, struct avrpart * p,
+		      int argc, char *argv[]);
+
+static int cmd_write (PROGRAMMER * pgm, struct avrpart * p,
+		      int argc, char *argv[]);
+
+static int cmd_erase (PROGRAMMER * pgm, struct avrpart * p,
+		      int argc, char *argv[]);
+
+static int cmd_sig   (PROGRAMMER * pgm, struct avrpart * p,
+		      int argc, char *argv[]);
+
+static int cmd_part  (PROGRAMMER * pgm, struct avrpart * p,
+		      int argc, char *argv[]);
+
+static int cmd_help  (PROGRAMMER * pgm, struct avrpart * p,
+		      int argc, char *argv[]);
+
+static int cmd_quit  (PROGRAMMER * pgm, struct avrpart * p,
+		      int argc, char *argv[]);
+
+static int cmd_send  (PROGRAMMER * pgm, struct avrpart * p,
+		      int argc, char *argv[]);
+
+static int cmd_parms (PROGRAMMER * pgm, struct avrpart * p,
+		      int argc, char *argv[]);
+
+static int cmd_vtarg (PROGRAMMER * pgm, struct avrpart * p,
+		      int argc, char *argv[]);
+
+static int cmd_varef (PROGRAMMER * pgm, struct avrpart * p,
+		      int argc, char *argv[]);
+
+static int cmd_fosc  (PROGRAMMER * pgm, struct avrpart * p,
+		      int argc, char *argv[]);
+
+static int cmd_sck   (PROGRAMMER * pgm, struct avrpart * p,
+		      int argc, char *argv[]);
+
+static int cmd_spi   (PROGRAMMER * pgm, struct avrpart * p,
+		      int argc, char *argv[]);
+
+static int cmd_pgm   (PROGRAMMER * pgm, struct avrpart * p,
+		      int argc, char *argv[]);
+
+struct command cmd[] = {
+  { "dump",  cmd_dump,  "dump memory  : %s <memtype> <addr> <N-Bytes>" },
+  { "read",  cmd_dump,  "alias for dump" },
+  { "write", cmd_write, "write memory : %s <memtype> <addr> <b1> <b2> ... <bN>" },
+  { "erase", cmd_erase, "perform a chip erase" },
+  { "sig",   cmd_sig,   "display device signature bytes" },
+  { "part",  cmd_part,  "display the current part information" },
+  { "send",  cmd_send,  "send a raw command : %s <b1> <b2> <b3> <b4>" },
+  { "parms", cmd_parms, "display adjustable parameters (STK500 only)" },
+  { "vtarg", cmd_vtarg, "set <V[target]> (STK500 only)" },
+  { "varef", cmd_varef, "set <V[aref]> (STK500 only)" },
+  { "fosc",  cmd_fosc,  "set <oscillator frequency> (STK500 only)" },
+  { "sck",   cmd_sck,   "set <SCK period> (STK500 only)" },
+  { "spi",   cmd_spi,   "enter direct SPI mode" },
+  { "pgm",   cmd_pgm,   "return to programming mode" },
+  { "help",  cmd_help,  "help" },
+  { "?",     cmd_help,  "help" },
+  { "quit",  cmd_quit,  "quit" }
+};
+
+#define NCMDS (sizeof(cmd)/sizeof(struct command))
+
+
+
+static int spi_mode = 0;
+
+static int nexttok(char * buf, char ** tok, char ** next)
+{
+  char * q, * n;
+
+  q = buf;
+  while (isspace(*q))
+    q++;
+  
+  /* isolate first token */
+  n = q+1;
+  while (*n && !isspace(*n))
+    n++;
+
+  if (*n) {
+    *n = 0;
+    n++;
+  }
+
+  /* find start of next token */
+  while (isspace(*n))
+    n++;
+
+  *tok  = q;
+  *next = n;
+
+  return 0;
+}
+
+
+static int hexdump_line(char * buffer, unsigned char * p, int n, int pad)
+{
+  char * hexdata = "0123456789abcdef";
+  char * b;
+  int i, j;
+
+  b = buffer;
+
+  j = 0;
+  for (i=0; i<n; i++) {
+    if (i && ((i % 8) == 0))
+      b[j++] = ' ';
+    b[j++] = hexdata[(p[i] & 0xf0) >> 4];
+    b[j++] = hexdata[(p[i] & 0x0f)];
+    if (i < 15)
+      b[j++] = ' ';
+  }
+
+  for (i=j; i<pad; i++)
+    b[i] = ' ';
+
+  b[i] = 0;
+
+  for (i=0; i<pad; i++) {
+    if (!((b[i] == '0') || (b[i] == ' ')))
+      return 0;
+  }
+
+  return 1;
+}
+
+
+static int chardump_line(char * buffer, unsigned char * p, int n, int pad)
+{
+  int i;
+  char b [ 128 ];
+
+  for (i=0; i<n; i++) {
+    memcpy(b, p, n);
+    buffer[i] = '.';
+    if (isalpha(b[i]) || isdigit(b[i]) || ispunct(b[i]))
+      buffer[i] = b[i];
+    else if (isspace(b[i]))
+      buffer[i] = ' ';
+  }
+
+  for (i=n; i<pad; i++)
+    buffer[i] = ' ';
+
+  buffer[i] = 0;
+
+  return 0;
+}
+
+
+static int hexdump_buf(FILE * f, int startaddr, unsigned char * buf, int len)
+{
+  int addr;
+  int i, n;
+  unsigned char * p;
+  char dst1[80];
+  char dst2[80];
+
+  addr = startaddr;
+  i = 0;
+  p = (unsigned char *)buf;
+  while (len) {
+    n = 16;
+    if (n > len)
+      n = len;
+    hexdump_line(dst1, p, n, 48);
+    chardump_line(dst2, p, n, 16);
+    fprintf(stdout, "%04x  %s  |%s|\n", addr, dst1, dst2);
+    len -= n;
+    addr += n;
+    p += n;
+  }
+
+  return 0;
+}
+
+
+static int cmd_dump(PROGRAMMER * pgm, struct avrpart * p,
+		    int argc, char * argv[])
+{
+  static char prevmem[128] = {0};
+  char * e;
+  unsigned char * buf;
+  int maxsize;
+  unsigned long i;
+  static unsigned long addr=0;
+  static int len=64;
+  AVRMEM * mem;
+  char * memtype = NULL;
+  int rc;
+
+  if (!((argc == 2) || (argc == 4))) {
+    fprintf(stderr, "Usage: dump <memtype> [<addr> <len>]\n");
+    return -1;
+  }
+
+  memtype = argv[1];
+
+  if (strncmp(prevmem, memtype, strlen(memtype)) != 0) {
+    addr = 0;
+    len  = 64;
+    strncpy(prevmem, memtype, sizeof(prevmem)-1);
+    prevmem[sizeof(prevmem)-1] = 0;
+  }
+
+  mem = avr_locate_mem(p, memtype);
+  if (mem == NULL) {
+    fprintf(stderr, "\"%s\" memory type not defined for part \"%s\"\n",
+            memtype, p->desc);
+    return -1;
+  }
+
+  if (argc == 4) {
+    addr = strtoul(argv[2], &e, 0);
+    if (*e || (e == argv[2])) {
+      fprintf(stderr, "%s (dump): can't parse address \"%s\"\n",
+              progname, argv[2]);
+      return -1;
+    }
+
+    len = strtol(argv[3], &e, 0);
+    if (*e || (e == argv[3])) {
+      fprintf(stderr, "%s (dump): can't parse length \"%s\"\n",
+              progname, argv[3]);
+      return -1;
+    }
+  }
+
+  maxsize = mem->size;
+
+  if (addr >= maxsize) {
+    if (argc == 2) {
+      /* wrap around */
+      addr = 0;
+    }
+    else {
+      fprintf(stderr, 
+              "%s (dump): address 0x%05lx is out of range for %s memory\n",
+              progname, addr, mem->desc);
+      return -1;
+    }
+  }
+
+  /* trim len if nessary to not read past the end of memory */
+  if ((addr + len) > maxsize)
+    len = maxsize - addr;
+
+  buf = malloc(len);
+  if (buf == NULL) {
+    fprintf(stderr, "%s (dump): out of memory\n", progname);
+    return -1;
+  }
+
+  for (i=0; i<len; i++) {
+    rc = pgm->read_byte(pgm, p, mem, addr+i, &buf[i]);
+    if (rc != 0) {
+      fprintf(stderr, "error reading %s address 0x%05lx of part %s\n",
+              mem->desc, addr+i, p->desc);
+      if (rc == -1)
+        fprintf(stderr, "read operation not supported on memory type \"%s\"\n",
+                mem->desc);
+      return -1;
+    }
+  }
+
+  hexdump_buf(stdout, addr, buf, len);
+
+  fprintf(stdout, "\n");
+
+  free(buf);
+
+  addr = addr + len;
+
+  return 0;
+}
+
+
+static int cmd_write(PROGRAMMER * pgm, struct avrpart * p,
+		     int argc, char * argv[])
+{
+  char * e;
+  int len, maxsize;
+  char * memtype;
+  unsigned long addr, i;
+  unsigned char * buf;
+  unsigned char b;
+  int rc;
+  int werror;
+  AVRMEM * mem;
+
+  if (argc < 4) {
+    fprintf(stderr, "Usage: write <memtype> <addr> <byte1> "
+            "<byte2> ... byteN>\n");
+    return -1;
+  }
+
+  memtype = argv[1];
+
+  mem = avr_locate_mem(p, memtype);
+  if (mem == NULL) {
+    fprintf(stderr, "\"%s\" memory type not defined for part \"%s\"\n",
+            memtype, p->desc);
+    return -1;
+  }
+
+  maxsize = mem->size;
+
+  addr = strtoul(argv[2], &e, 0);
+  if (*e || (e == argv[2])) {
+    fprintf(stderr, "%s (write): can't parse address \"%s\"\n",
+            progname, argv[2]);
+    return -1;
+  }
+
+  if (addr > maxsize) {
+    fprintf(stderr, 
+            "%s (write): address 0x%05lx is out of range for %s memory\n",
+            progname, addr, memtype);
+    return -1;
+  }
+
+  /* number of bytes to write at the specified address */
+  len = argc - 3;
+
+  if ((addr + len) > maxsize) {
+    fprintf(stderr, 
+            "%s (write): selected address and # bytes exceed "
+            "range for %s memory\n", 
+            progname, memtype);
+    return -1;
+  }
+
+  buf = malloc(len);
+  if (buf == NULL) {
+    fprintf(stderr, "%s (write): out of memory\n", progname);
+    return -1;
+  }
+
+  for (i=3; i<argc; i++) {
+    buf[i-3] = strtoul(argv[i], &e, 0);
+    if (*e || (e == argv[i])) {
+      fprintf(stderr, "%s (write): can't parse byte \"%s\"\n",
+              progname, argv[i]);
+      free(buf);
+      return -1;
+    }
+  }
+
+  pgm->err_led(pgm, OFF);
+  for (werror=0, i=0; i<len; i++) {
+
+    rc = avr_write_byte(pgm, p, mem, addr+i, buf[i]);
+    if (rc) {
+      fprintf(stderr, "%s (write): error writing 0x%02x at 0x%05lx, rc=%d\n",
+              progname, buf[i], addr+i, rc);
+      if (rc == -1)
+        fprintf(stderr, 
+                "write operation not supported on memory type \"%s\"\n",
+                mem->desc);
+      werror = 1;
+    }
+
+    rc = pgm->read_byte(pgm, p, mem, addr+i, &b);
+    if (b != buf[i]) {
+      fprintf(stderr, 
+              "%s (write): error writing 0x%02x at 0x%05lx cell=0x%02x\n",
+              progname, buf[i], addr+i, b);
+      werror = 1;
+    }
+
+    if (werror) {
+      pgm->err_led(pgm, ON);
+    }
+  }
+
+  free(buf);
+
+  fprintf(stdout, "\n");
+
+  return 0;
+}
+
+
+static int cmd_send(PROGRAMMER * pgm, struct avrpart * p,
+		    int argc, char * argv[])
+{
+  unsigned char cmd[4], res[4];
+  char * e;
+  int i;
+  int len;
+
+  if (pgm->cmd == NULL) {
+    fprintf(stderr,
+	    "The %s programmer does not support direct ISP commands.\n",
+	    pgm->type);
+    return -1;
+  }
+
+  if (spi_mode && (pgm->spi == NULL)) {
+    fprintf(stderr,
+	    "The %s programmer does not support direct SPI transfers.\n",
+	    pgm->type);
+    return -1;
+  }
+
+
+  if ((argc > 5) || ((argc < 5) && (!spi_mode))) {
+    fprintf(stderr, spi_mode?
+      "Usage: send <byte1> [<byte2> [<byte3> [<byte4>]]]\n":
+      "Usage: send <byte1> <byte2> <byte3> <byte4>\n");
+    return -1;
+  }
+
+  /* number of bytes to write at the specified address */
+  len = argc - 1;
+
+  /* load command bytes */
+  for (i=1; i<argc; i++) {
+    cmd[i-1] = strtoul(argv[i], &e, 0);
+    if (*e || (e == argv[i])) {
+      fprintf(stderr, "%s (send): can't parse byte \"%s\"\n",
+              progname, argv[i]);
+      return -1;
+    }
+  }
+
+  pgm->err_led(pgm, OFF);
+
+  if (spi_mode)
+    pgm->spi(pgm, cmd, res, argc-1);
+  else
+    pgm->cmd(pgm, cmd, res);
+
+  /*
+   * display results
+   */
+  fprintf(stderr, "results:");
+  for (i=0; i<len; i++)
+    fprintf(stderr, " %02x", res[i]);
+  fprintf(stderr, "\n");
+
+  fprintf(stdout, "\n");
+
+  return 0;
+}
+
+
+static int cmd_erase(PROGRAMMER * pgm, struct avrpart * p,
+		     int argc, char * argv[])
+{
+  fprintf(stderr, "%s: erasing chip\n", progname);
+  pgm->chip_erase(pgm, p);
+  return 0;
+}
+
+
+static int cmd_part(PROGRAMMER * pgm, struct avrpart * p,
+		    int argc, char * argv[])
+{
+  fprintf(stdout, "\n");
+  avr_display(stdout, p, "", 0);
+  fprintf(stdout, "\n");
+
+  return 0;
+}
+
+
+static int cmd_sig(PROGRAMMER * pgm, struct avrpart * p,
+		   int argc, char * argv[])
+{
+  int i;
+  int rc;
+  AVRMEM * m;
+
+  rc = avr_signature(pgm, p);
+  if (rc != 0) {
+    fprintf(stderr, "error reading signature data, rc=%d\n",
+            rc);
+  }
+
+  m = avr_locate_mem(p, "signature");
+  if (m == NULL) {
+    fprintf(stderr,
+            "signature data not defined for device \"%s\"\n",
+            p->desc);
+  }
+  else {
+    fprintf(stdout, "Device signature = 0x");
+    for (i=0; i<m->size; i++)
+      fprintf(stdout, "%02x", m->buf[i]);
+    fprintf(stdout, "\n\n");
+  }
+
+  return 0;
+}
+
+
+static int cmd_quit(PROGRAMMER * pgm, struct avrpart * p,
+		    int argc, char * argv[])
+{
+  return 1;
+}
+
+
+static int cmd_parms(PROGRAMMER * pgm, struct avrpart * p,
+		     int argc, char * argv[])
+{
+  if (pgm->print_parms == NULL) {
+    fprintf(stderr,
+	    "%s (parms): the %s programmer does not support "
+	    "adjustable parameters\n",
+	    progname, pgm->type);
+    return -1;
+  }
+  pgm->print_parms(pgm);
+
+  return 0;
+}
+
+
+static int cmd_vtarg(PROGRAMMER * pgm, struct avrpart * p,
+		     int argc, char * argv[])
+{
+  int rc;
+  double v;
+  char *endp;
+
+  if (argc != 2) {
+    fprintf(stderr, "Usage: vtarg <value>\n");
+    return -1;
+  }
+  v = strtod(argv[1], &endp);
+  if (endp == argv[1]) {
+    fprintf(stderr, "%s (vtarg): can't parse voltage \"%s\"\n",
+            progname, argv[1]);
+    return -1;
+  }
+  if (pgm->set_vtarget == NULL) {
+    fprintf(stderr, "%s (vtarg): the %s programmer cannot set V[target]\n",
+	    progname, pgm->type);
+    return -2;
+  }
+  if ((rc = pgm->set_vtarget(pgm, v)) != 0) {
+    fprintf(stderr, "%s (vtarg): failed to set V[target] (rc = %d)\n",
+	    progname, rc);
+    return -3;
+  }
+  return 0;
+}
+
+
+static int cmd_fosc(PROGRAMMER * pgm, struct avrpart * p,
+		    int argc, char * argv[])
+{
+  int rc;
+  double v;
+  char *endp;
+
+  if (argc != 2) {
+    fprintf(stderr, "Usage: fosc <value>[M|k] | off\n");
+    return -1;
+  }
+  v = strtod(argv[1], &endp);
+  if (endp == argv[1]) {
+    if (strcmp(argv[1], "off") == 0)
+      v = 0.0;
+    else {
+      fprintf(stderr, "%s (fosc): can't parse frequency \"%s\"\n",
+	      progname, argv[1]);
+      return -1;
+    }
+  }
+  if (*endp == 'm' || *endp == 'M')
+    v *= 1e6;
+  else if (*endp == 'k' || *endp == 'K')
+    v *= 1e3;
+  if (pgm->set_fosc == NULL) {
+    fprintf(stderr,
+	    "%s (fosc): the %s programmer cannot set oscillator frequency\n",
+	    progname, pgm->type);
+    return -2;
+  }
+  if ((rc = pgm->set_fosc(pgm, v)) != 0) {
+    fprintf(stderr, "%s (fosc): failed to set oscillator_frequency (rc = %d)\n",
+	    progname, rc);
+    return -3;
+  }
+  return 0;
+}
+
+
+static int cmd_sck(PROGRAMMER * pgm, struct avrpart * p,
+		   int argc, char * argv[])
+{
+  int rc;
+  double v;
+  char *endp;
+
+  if (argc != 2) {
+    fprintf(stderr, "Usage: sck <value>\n");
+    return -1;
+  }
+  v = strtod(argv[1], &endp);
+  if (endp == argv[1]) {
+    fprintf(stderr, "%s (sck): can't parse period \"%s\"\n",
+	    progname, argv[1]);
+    return -1;
+  }
+  v *= 1e-6;			/* Convert from microseconds to seconds. */
+  if (pgm->set_sck_period == NULL) {
+    fprintf(stderr,
+	    "%s (sck): the %s programmer cannot set SCK period\n",
+	    progname, pgm->type);
+    return -2;
+  }
+  if ((rc = pgm->set_sck_period(pgm, v)) != 0) {
+    fprintf(stderr, "%s (sck): failed to set SCK period (rc = %d)\n",
+	    progname, rc);
+    return -3;
+  }
+  return 0;
+}
+
+
+static int cmd_varef(PROGRAMMER * pgm, struct avrpart * p,
+		     int argc, char * argv[])
+{
+  int rc;
+  unsigned int chan;
+  double v;
+  char *endp;
+
+  if (argc != 2 && argc != 3) {
+    fprintf(stderr, "Usage: varef [channel] <value>\n");
+    return -1;
+  }
+  if (argc == 2) {
+    chan = 0;
+    v = strtod(argv[1], &endp);
+    if (endp == argv[1]) {
+      fprintf(stderr, "%s (varef): can't parse voltage \"%s\"\n",
+              progname, argv[1]);
+      return -1;
+    }
+  } else {
+    chan = strtoul(argv[1], &endp, 10);
+    if (endp == argv[1]) {
+      fprintf(stderr, "%s (varef): can't parse channel \"%s\"\n",
+              progname, argv[1]);
+      return -1;
+    }
+    v = strtod(argv[2], &endp);
+    if (endp == argv[2]) {
+      fprintf(stderr, "%s (varef): can't parse voltage \"%s\"\n",
+              progname, argv[2]);
+      return -1;
+    }
+  }
+  if (pgm->set_varef == NULL) {
+    fprintf(stderr, "%s (varef): the %s programmer cannot set V[aref]\n",
+	    progname, pgm->type);
+    return -2;
+  }
+  if ((rc = pgm->set_varef(pgm, chan, v)) != 0) {
+    fprintf(stderr, "%s (varef): failed to set V[aref] (rc = %d)\n",
+	    progname, rc);
+    return -3;
+  }
+  return 0;
+}
+
+
+static int cmd_help(PROGRAMMER * pgm, struct avrpart * p,
+		    int argc, char * argv[])
+{
+  int i;
+
+  fprintf(stdout, "Valid commands:\n\n");
+  for (i=0; i<NCMDS; i++) {
+    fprintf(stdout, "  %-6s : ", cmd[i].name);
+    fprintf(stdout, cmd[i].desc, cmd[i].name);
+    fprintf(stdout, "\n");
+  }
+  fprintf(stdout, 
+          "\nUse the 'part' command to display valid memory types for use with the\n"
+          "'dump' and 'write' commands.\n\n");
+
+  return 0;
+}
+
+static int cmd_spi(PROGRAMMER * pgm, struct avrpart * p,
+        int argc, char * argv[])
+{
+  pgm->setpin(pgm, pgm->pinno[PIN_AVR_RESET], 1);
+  spi_mode = 1;
+  return 0;
+}
+
+static int cmd_pgm(PROGRAMMER * pgm, struct avrpart * p,
+        int argc, char * argv[])
+{
+  pgm->setpin(pgm, pgm->pinno[PIN_AVR_RESET], 0);
+  spi_mode = 0;
+  pgm->initialize(pgm, p);
+  return 0;
+}
+
+static int tokenize(char * s, char *** argv)
+{
+  int     i, n, l, nargs, offset;
+  int     len, slen;
+  char  * buf;
+  int     bufsize;
+  char ** bufv;
+  char  * q, * r;
+  char  * nbuf;
+  char ** av;
+
+  slen = strlen(s);
+
+  /* 
+   * initialize allow for 20 arguments, use realloc to grow this if
+   * necessary 
+   */
+  nargs   = 20;
+  bufsize = slen + 20;
+  buf     = malloc(bufsize);
+  bufv    = (char **) malloc(nargs*sizeof(char *));
+  for (i=0; i<nargs; i++) {
+    bufv[i] = NULL;
+  }
+  buf[0] = 0;
+
+  n    = 0;
+  l    = 0;
+  nbuf = buf;
+  r    = s;
+  while (*r) {
+    nexttok(r, &q, &r);
+    strcpy(nbuf, q);
+    bufv[n]  = nbuf;
+    len      = strlen(q);
+    l       += len + 1;
+    nbuf    += len + 1;
+    nbuf[0]  = 0;
+    n++;
+    if ((n % 20) == 0) {
+      /* realloc space for another 20 args */
+      bufsize += 20;
+      nargs   += 20;
+      buf      = realloc(buf, bufsize);
+      bufv     = realloc(bufv, nargs*sizeof(char *));
+      nbuf     = &buf[l];
+      for (i=n; i<nargs; i++)
+        bufv[i] = NULL;
+    }
+  }
+
+  /* 
+   * We have parsed all the args, n == argc, bufv contains an array of
+   * pointers to each arg, and buf points to one memory block that
+   * contains all the args, back to back, seperated by a nul
+   * terminator.  Consilidate bufv and buf into one big memory block
+   * so that the code that calls us, will have an easy job of freeing
+   * this memory.
+   */
+  av = (char **) malloc(slen + n + (n+1)*sizeof(char *));
+  q  = (char *)&av[n+1];
+  memcpy(q, buf, l);
+  for (i=0; i<n; i++) {
+    offset = bufv[i] - buf;
+    av[i] = q + offset;
+  }
+  av[i] = NULL;
+
+  free(buf);
+  free(bufv);
+
+  *argv = av;
+
+  return n;
+}
+
+
+static int do_cmd(PROGRAMMER * pgm, struct avrpart * p,
+		  int argc, char * argv[])
+{
+  int i;
+  int hold;
+  int len;
+
+  len = strlen(argv[0]);
+  hold = -1;
+  for (i=0; i<NCMDS; i++) {
+    if (strcasecmp(argv[0], cmd[i].name) == 0) {
+      return cmd[i].func(pgm, p, argc, argv);
+    }
+    else if (strncasecmp(argv[0], cmd[i].name, len)==0) {
+      if (hold != -1) {
+        fprintf(stderr, "%s: command \"%s\" is ambiguous\n",
+                progname, argv[0]);
+        return -1;
+      }
+      hold = i;
+    }
+  }
+
+  if (hold != -1)
+    return cmd[hold].func(pgm, p, argc, argv);
+
+  fprintf(stderr, "%s: invalid command \"%s\"\n",
+          progname, argv[0]);
+
+  return -1;
+}
+
+
+char * terminal_get_input(const char *prompt)
+{
+#if defined(HAVE_LIBREADLINE) && !defined(WIN32NATIVE)
+  char *input;
+  input = readline(prompt);
+  if ((input != NULL) && (strlen(input) >= 1))
+    add_history(input);
+
+  return input;
+#else
+  char input[256];
+  printf("%s", prompt);
+  if (fgets(input, sizeof(input), stdin))
+  {
+    /* FIXME: readline strips the '\n', should this too? */
+    return strdup(input);
+  }
+  else
+    return NULL;
+#endif
+}
+
+
+int terminal_mode(PROGRAMMER * pgm, struct avrpart * p)
+{
+  char  * cmdbuf;
+  int     i;
+  char  * q;
+  int     rc;
+  int     argc;
+  char ** argv;
+
+  rc = 0;
+  while ((cmdbuf = terminal_get_input("avrdude> ")) != NULL) {
+    /* 
+     * find the start of the command, skipping any white space
+     */
+    q = cmdbuf;
+    while (*q && isspace(*q))
+      q++;
+
+    /* skip blank lines and comments */
+    if (!*q || (*q == '#'))
+      continue;
+
+    /* tokenize command line */
+    argc = tokenize(q, &argv);
+
+    fprintf(stdout, ">>> ");
+    for (i=0; i<argc; i++)
+      fprintf(stdout, "%s ", argv[i]);
+    fprintf(stdout, "\n");
+
+    /* run the command */
+    rc = do_cmd(pgm, p, argc, argv);
+    free(argv);
+    if (rc > 0) {
+      rc = 0;
+      break;
+    }
+    free(cmdbuf);
+  }
+
+  return rc;
+}
+
+
diff --git a/avrdude/term.h b/avrdude/term.h
new file mode 100644
index 00000000..42d8a7a2
--- /dev/null
+++ b/avrdude/term.h
@@ -0,0 +1,39 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2000-2004  Brian S. Dean <bsd@bsdhome.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id$ */
+
+#ifndef term_h
+#define term_h
+
+#include "avr.h"
+#include "pgm.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int terminal_mode(PROGRAMMER * pgm, struct avrpart * p);
+char * terminal_get_input(const char *prompt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/avrdude/tools/get-dw-params.xsl b/avrdude/tools/get-dw-params.xsl
new file mode 100644
index 00000000..457617bc
--- /dev/null
+++ b/avrdude/tools/get-dw-params.xsl
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding='ISO-8859-1' ?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<!--
+ * Copyright (c) 2006 Joerg Wunsch
+ *
+ * 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
+ *
+ * $Id$
+-->
+<!--
+ * Extract the debugWire parameters
+ * from the XML, and format it the way src/devdescr.cc needs it.
+ *
+ * Run this file together with the respective AVR's XML file through
+ * an XSLT processor (xsltproc, saxon), and capture the output for
+ * inclusion into avrdude.conf.in.
+-->
+    <xsl:output method="text"/>
+    <xsl:template match="/">
+      <!-- Extract everything we need out of the XML. -->
+      <xsl:variable name="devname_orig"
+                    select="/AVRPART/ADMIN/PART_NAME" />
+      <xsl:variable name="devname"
+                    select="translate(/AVRPART/ADMIN/PART_NAME,
+                                      'abcdefghijklmnopqrstuvwxyz',
+                                      'ABCDEFGHIJKLMNOPQRSTUVWXYZ')" />
+      <xsl:variable name="devname_lower"
+                    select="translate(/AVRPART/ADMIN/PART_NAME,
+                                      'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
+                                      'abcdefghijklmnopqrstuvwxyz')" />
+      <xsl:variable name="ucEepromInst"
+                    select="//AVRPART/ICE_SETTINGS/JTAGICEmkII/ucEepromInst" />
+      <xsl:variable name="ucFlashInst"
+                    select="//AVRPART/ICE_SETTINGS/JTAGICEmkII/ucFlashInst" />
+
+      <!-- If there's a JTAGICEmkII node indicating debugWire, emit the entry. -->
+      <xsl:if test='//AVRPART/ICE_SETTINGS/JTAGICEmkII/Interface="DebugWire"'>
+
+      <!-- start of new entry -->
+      <xsl:text>#------------------------------------------------------------&#010;</xsl:text>
+      <xsl:text># </xsl:text>
+      <xsl:value-of select="$devname_orig" />
+      <xsl:text>&#010;</xsl:text>
+      <xsl:text>#------------------------------------------------------------&#010;</xsl:text>
+      <xsl:text>part&#010;     desc          = &quot;</xsl:text>
+      <xsl:value-of select="$devname_orig" />
+      <xsl:text>&quot;;&#010;     has_debugwire = yes;&#010;</xsl:text>
+
+      <xsl:text>     flash_instr   = </xsl:text>
+      <xsl:call-template name="format-hex">
+        <xsl:with-param name="arg" select="$ucFlashInst" />
+        <xsl:with-param name="count" select="0" />
+      </xsl:call-template>
+      <xsl:text>;&#010;</xsl:text>
+
+      <xsl:text>     eeprom_instr  = </xsl:text>
+      <xsl:call-template name="format-hex">
+        <xsl:with-param name="arg" select="$ucEepromInst" />
+        <xsl:with-param name="count" select="0" />
+      </xsl:call-template>
+      <xsl:text>;&#010;</xsl:text>
+
+      </xsl:if> <!-- JTAGICEmkII uses debugWire -->
+
+    </xsl:template>
+
+    <xsl:template name="toupper">
+    </xsl:template>
+
+    <!-- return argument $arg if non-empty, 0 otherwise -->
+    <xsl:template name="maybezero">
+      <xsl:param name="arg" />
+      <xsl:choose>
+        <xsl:when test="string-length($arg) = 0"><xsl:text>0</xsl:text></xsl:when>
+        <xsl:otherwise><xsl:value-of select="$arg" /></xsl:otherwise>
+      </xsl:choose>
+    </xsl:template> <!-- maybezero -->
+
+    <!-- convert $XX hex number in $arg (if any) into 0xXX; -->
+    <!-- return 0 if $arg is empty -->
+    <xsl:template name="dollar-to-0x">
+      <xsl:param name="arg" />
+      <xsl:choose>
+        <xsl:when test="string-length($arg) = 0">
+          <xsl:text>0</xsl:text>
+        </xsl:when>
+        <xsl:when test="substring($arg, 1, 1) = '&#036;'">
+          <xsl:text>0x</xsl:text>
+          <xsl:value-of select="substring($arg, 2)" />
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="$arg" />
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:template> <!-- dollar-to-0x -->
+
+    <!-- Format a string of 0xXX numbers: start a new line -->
+    <!-- after each 8 hex numbers -->
+    <!-- call with parameter $count = 0, calls itself -->
+    <!-- recursively then until everything has been done -->
+    <xsl:template name="format-hex">
+      <xsl:param name="arg" />
+      <xsl:param name="count" />
+      <xsl:choose>
+        <xsl:when test="string-length($arg) &lt;= 4">
+          <!-- Last element, print it, and leave template. -->
+          <xsl:value-of select="$arg" />
+        </xsl:when>
+        <xsl:otherwise>
+          <!--
+            * More arguments follow, print first value,
+            * followed by a comma, decide whether a space
+            * or a newline needs to be emitted, and recurse
+            * with the remaining part of $arg.
+          -->
+          <xsl:value-of select="substring($arg, 1, 4)" />
+          <xsl:choose>
+            <xsl:when test="$count mod 8 = 7">
+              <xsl:text>,&#010;&#009;             </xsl:text>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:text>, </xsl:text>
+            </xsl:otherwise>
+          </xsl:choose>
+          <xsl:variable name="newarg">
+            <!-- see whether there is a space after comma -->
+            <xsl:choose>
+              <xsl:when test="substring($arg, 6, 1) = ' '">
+                <xsl:value-of select="substring($arg, 7)" />
+              </xsl:when>
+              <xsl:otherwise>
+                <xsl:value-of select="substring($arg, 6)" />
+              </xsl:otherwise>
+            </xsl:choose>
+          </xsl:variable>
+          <xsl:call-template name="format-hex">
+            <xsl:with-param name="arg" select="$newarg" />
+            <xsl:with-param name="count" select="$count + 1" />
+          </xsl:call-template>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:template>
+
+</xsl:stylesheet>
diff --git a/avrdude/tools/get-hv-params.xsl b/avrdude/tools/get-hv-params.xsl
new file mode 100644
index 00000000..f86bd2b0
--- /dev/null
+++ b/avrdude/tools/get-hv-params.xsl
@@ -0,0 +1,255 @@
+<?xml version="1.0" encoding='ISO-8859-1' ?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<!--
+ * Copyright (c) 2006 Joerg Wunsch
+ *
+ * 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
+ *
+ * $Id$
+-->
+<!--
+ * Extract high-voltage (parallel and serial) programming parameters
+ * out of the Atmel XML files, and convert them into avrdude.conf
+ * snippets.
+ *
+ * Run this file together with the respective AVR's XML file through
+ * an XSLT processor (xsltproc, saxon), and capture the output for
+ * inclusion into avrdude.conf.in.
+-->
+    <xsl:output method="text"/>
+    <xsl:template match="/">
+    <xsl:for-each select="//*">
+    <xsl:if test='name() = "STK500_2"'>
+
+    <!--
+     * High-voltage parallel programming parameters.
+    -->
+    <xsl:for-each
+     select="*[starts-with(translate(name(),
+                                     'abcdefghijklmnopqrstuvwxyz',
+                                     'ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
+                                     'PP')]">
+        <xsl:if test="self::node()[name() = 'PPControlStack']"
+        >    pp_controlstack     =
+        <xsl:call-template name="format_cstack">
+            <xsl:with-param name="stack" select="." />
+            <xsl:with-param name="count" select="0" />
+        </xsl:call-template>;
+</xsl:if> <!-- PPControlStack -->
+
+	<xsl:if test="self::node()[name() = 'PpEnterProgMode']">
+            <xsl:for-each select="*">
+                <xsl:if test="self::node()[name() = 'stabDelay']"
+                >    hventerstabdelay    = <xsl:value-of select="." />;
+</xsl:if>
+                <xsl:if test="self::node()[name() = 'progModeDelay']"
+                >    progmodedelay       = <xsl:value-of select="." />;
+</xsl:if>
+                <xsl:if test="self::node()[name() = 'latchCycles']"
+                >    latchcycles         = <xsl:value-of select="." />;
+</xsl:if>
+                <xsl:if test="self::node()[name() = 'toggleVtg']"
+                >    togglevtg           = <xsl:value-of select="." />;
+</xsl:if>
+                <xsl:if test="self::node()[name() = 'powerOffDelay']"
+                >    poweroffdelay       = <xsl:value-of select="." />;
+</xsl:if>
+                <xsl:if test="self::node()[name() = 'resetDelayMs']"
+                >    resetdelayms        = <xsl:value-of select="." />;
+</xsl:if>
+                <xsl:if test="self::node()[name() = 'resetDelayUs']"
+                >    resetdelayus        = <xsl:value-of select="." />;
+</xsl:if>
+            </xsl:for-each>
+        </xsl:if> <!-- PpEnterProgMode -->
+
+        <xsl:if test="self::node()[name() = 'PpLeaveProgMode']">
+            <xsl:for-each select="*">
+                <xsl:if test="self::node()[name() = 'stabDelay']"
+                >    hvleavestabdelay    = <xsl:value-of select="." />;
+</xsl:if>
+            </xsl:for-each>
+        </xsl:if> <!-- PpLeaveProgMode -->
+
+        <xsl:if test="self::node()[name() = 'PpChipErase']">
+            <xsl:for-each select="*">
+                <xsl:if test="self::node()[name() = 'pulseWidth']"
+                >    chiperasepulsewidth = <xsl:value-of select="." />;
+</xsl:if>
+                <xsl:if test="self::node()[name() = 'pollTimeout']"
+                >    chiperasepolltimeout = <xsl:value-of select="." />;
+</xsl:if>
+            </xsl:for-each>
+        </xsl:if> <!-- PpChipErase -->
+
+        <xsl:if test="self::node()[name() = 'PpProgramFuse']">
+            <xsl:for-each select="*">
+                <xsl:if test="self::node()[name() = 'pulseWidth']"
+                >    programfusepulsewidth = <xsl:value-of select="." />;
+</xsl:if>
+                <xsl:if test="self::node()[name() = 'pollTimeout']"
+                >    programfusepolltimeout = <xsl:value-of select="." />;
+</xsl:if>
+            </xsl:for-each>
+        </xsl:if> <!-- PpProgramFuse -->
+
+        <xsl:if test="self::node()[name() = 'PpProgramLock']">
+            <xsl:for-each select="*">
+                <xsl:if test="self::node()[name() = 'pulseWidth']"
+                >    programlockpulsewidth = <xsl:value-of select="." />;
+</xsl:if>
+                <xsl:if test="self::node()[name() = 'pollTimeout']"
+                >    programlockpolltimeout = <xsl:value-of select="." />;
+</xsl:if>
+            </xsl:for-each>
+        </xsl:if> <!-- PpProgramLock -->
+
+   </xsl:for-each> <!-- PP parameters -->
+
+   <!--
+    * High-voltage serial programming parameters.
+   -->
+   <xsl:for-each
+    select="*[starts-with(translate(name(),
+                          'abcdefghijklmnopqrstuvwxyz',
+                          'ABCDEFGHIJKLMNOPQRSTUVWXYZ'),
+                          'HVSP')]">
+
+        <xsl:if test="self::node()[name() = 'HvspControlStack']"
+        >    hvsp_controlstack   =
+        <xsl:call-template name="format_cstack">
+            <xsl:with-param name="stack" select="." />
+            <xsl:with-param name="count" select="0" />
+        </xsl:call-template>;
+</xsl:if> <!-- HvspControlStack -->
+
+        <xsl:if test="self::node()[name() = 'HvspEnterProgMode']">
+            <xsl:for-each select="*">
+                <xsl:if test="self::node()[name() = 'stabDelay']"
+                >    hventerstabdelay    = <xsl:value-of select="." />;
+</xsl:if>
+                <xsl:if test="self::node()[name() = 'cmdexeDelay']"
+                >    hvspcmdexedelay     = <xsl:value-of select="." />;
+</xsl:if>
+                <xsl:if test="self::node()[name() = 'synchCycles']"
+                >    synchcycles         = <xsl:value-of select="." />;
+</xsl:if>
+                <xsl:if test="self::node()[name() = 'latchCycles']"
+                >    latchcycles         = <xsl:value-of select="." />;
+</xsl:if>
+                <xsl:if test="self::node()[name() = 'toggleVtg']"
+                >    togglevtg           = <xsl:value-of select="." />;
+</xsl:if>
+                <xsl:if test="self::node()[name() = 'powoffDelay']"
+                >    poweroffdelay       = <xsl:value-of select="." />;
+</xsl:if>
+                <xsl:if test="self::node()[name() = 'resetDelay1']"
+                >    resetdelayms        = <xsl:value-of select="." />;
+</xsl:if>
+                <xsl:if test="self::node()[name() = 'resetDelay2']"
+                >    resetdelayus        = <xsl:value-of select="." />;
+</xsl:if>
+            </xsl:for-each>
+        </xsl:if> <!-- HvspEnterProgMode -->
+
+        <xsl:if test="self::node()[name() = 'HvspLeaveProgMode']">
+            <xsl:for-each select="*">
+                <xsl:if test="self::node()[name() = 'stabDelay']"
+                >    hvleavestabdelay    = <xsl:value-of select="." />;
+</xsl:if>
+                <xsl:if test="self::node()[name() = 'resetDelay']"
+                >    resetdelay          = <xsl:value-of select="." />;
+</xsl:if>
+              </xsl:for-each>
+        </xsl:if> <!-- HvspLeaveProgMode -->
+
+        <xsl:if test="self::node()[name() = 'HvspChipErase']">
+            <xsl:for-each select="*">
+                <xsl:if test="self::node()[name() = 'pollTimeout']"
+                >    chiperasepolltimeout = <xsl:value-of select="." />;
+</xsl:if>
+                <xsl:if test="self::node()[name() = 'eraseTime']"
+                >    chiperasetime       = <xsl:value-of select="." />;
+</xsl:if>
+            </xsl:for-each>
+        </xsl:if> <!-- HvspChipErase -->
+
+        <xsl:if test="self::node()[name() = 'HvspProgramFuse']">
+            <xsl:for-each select="*">
+                <xsl:if test="self::node()[name() = 'pollTimeout']"
+                >    programfusepolltimeout = <xsl:value-of select="." />;
+</xsl:if>
+            </xsl:for-each>
+        </xsl:if> <!-- HvspProgramFuse -->
+
+        <xsl:if test="self::node()[name() = 'HvspProgramLock']">
+            <xsl:for-each select="*">
+                <xsl:if test="self::node()[name() = 'pollTimeout']"
+                >    programlockpolltimeout = <xsl:value-of select="." />;
+</xsl:if>
+            </xsl:for-each>
+        </xsl:if> <!-- HvspProgramLock -->
+
+    </xsl:for-each> <!-- HVSP parameters -->
+
+    </xsl:if>  <!-- STK500_2 parameters -->
+    </xsl:for-each>  <!-- All nodes -->
+
+    </xsl:template>
+
+    <!--
+     * Format the control stack argument: replace space-separated
+     * list by a list separated with commas, followed by either
+     * a space or a newline, dependend on the current argument
+     * count.
+     * This template calls itself recursively, until the entire
+     * argument $stack has been processed.
+    -->
+    <xsl:template name="format_cstack">
+        <xsl:param name="stack" />
+        <xsl:param name="count" />
+        <xsl:choose>
+            <xsl:when test="string-length($stack) &lt;= 4">
+                <!-- Last element, print it, and leave template. -->
+                <xsl:value-of select="$stack" />
+            </xsl:when>
+            <xsl:otherwise>
+                <!--
+                  * More arguments follow, print first value,
+                  * followed by a comma, decide whether a space
+                  * or a newline needs to be emitted, and recurse
+                  * with the remaining part of $stack.
+                -->
+                <xsl:value-of select="substring($stack, 1, 4)" />
+                <xsl:choose>
+                    <xsl:when test="$count mod 8 = 7">
+                        <!-- comma, newline, 8 spaces indentation -->
+                        <xsl:text>,
+        </xsl:text>
+                    </xsl:when>
+                    <xsl:otherwise>
+                        <!-- comma, space -->
+                        <xsl:text>, </xsl:text>
+                    </xsl:otherwise>
+                </xsl:choose>
+                <xsl:call-template name="format_cstack">
+                    <xsl:with-param name="stack" select="substring($stack, 6)"
+                    />
+                    <xsl:with-param name="count" select="$count + 1" />
+                </xsl:call-template>
+            </xsl:otherwise>
+        </xsl:choose>
+    </xsl:template>
+</xsl:stylesheet>
diff --git a/avrdude/tools/get-stk600-cards.xsl b/avrdude/tools/get-stk600-cards.xsl
new file mode 100644
index 00000000..c71d5147
--- /dev/null
+++ b/avrdude/tools/get-stk600-cards.xsl
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding='ISO-8859-1' ?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<!--
+ * Copyright (c) 2008 Joerg Wunsch
+ *
+ * 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
+ *
+ * $Id$
+-->
+<!--
+    * Extract STK600 routing and socket card information out of
+    * targetboards.xml.
+    *
+    * Run this like:
+    *
+    * xsltproc -param what "'RC'" \
+    *   tools/get-stk600-cards.xsl targetboard.xml | sort -u
+    *
+    * xsltproc -param what "'SC'" \
+    *   tools/get-stk600-cards.xsl targetboard.xml | sort -u
+    *
+    * and copy&paste the results into the respective tables.
+-->
+<xsl:output method="text"/>
+<xsl:template match="/">
+  <xsl:if test="$what = 'RC'">
+    <xsl:for-each select="/STK600/ROUTING/CARD">
+      <xsl:if test="RC_NAME != ''">
+	<xsl:text>  { </xsl:text>
+	<xsl:value-of select="RC_ID" />
+	<xsl:text>, &#034;</xsl:text>
+	<xsl:value-of select="RC_NAME" />
+	<xsl:text>&#034; },&#010;</xsl:text>
+      </xsl:if>
+    </xsl:for-each>  <!-- All cards -->
+  </xsl:if> <!-- Routing cards -->
+
+  <xsl:if test="$what = 'SC'">
+  <xsl:for-each select="/STK600/ROUTING/CARD">
+    <xsl:if test="SC_NAME != ''">
+      <xsl:text>  { </xsl:text>
+      <xsl:value-of select="SC_ID" />
+      <xsl:text>, &#034;</xsl:text>
+      <xsl:value-of select="SC_NAME" />
+      <xsl:text>&#034; },&#010;</xsl:text>
+    </xsl:if>
+  </xsl:for-each>  <!-- All cards -->
+  </xsl:if> <!-- Socket cards -->
+
+</xsl:template>
+</xsl:stylesheet>
diff --git a/avrdude/tools/get-stk600-devices.xsl b/avrdude/tools/get-stk600-devices.xsl
new file mode 100644
index 00000000..241994b9
--- /dev/null
+++ b/avrdude/tools/get-stk600-devices.xsl
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding='ISO-8859-1' ?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<!--
+ * Copyright (c) 2008 Joerg Wunsch
+ *
+ * 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
+ *
+ * $Id$
+-->
+<!--
+    * Extract STK600 device support out of
+    * targetboards.xml.
+    *
+    * Run this like:
+    *
+    * xsltproc \
+    *   tools/get-stk600-devices.xsl targetboard.xml
+    *
+    * and copy&paste the results into the respective table.
+-->
+<xsl:output method="text"/>
+<xsl:template match="/">
+    <xsl:text>@multitable @columnfractions .15 .15 .6&#010;</xsl:text>
+    <xsl:text>Routing card @tab Socket card @tab Devices&#010;</xsl:text>
+    <xsl:for-each select="/STK600/ROUTING/CARD">
+	<xsl:text>@item @code{</xsl:text>
+	<xsl:value-of select="RC_NAME" />
+	<xsl:text>} @tab @code{</xsl:text>
+	<xsl:value-of select="SC_NAME" />
+	<xsl:text>} @tab</xsl:text>
+        <xsl:for-each select="TARGET">
+           <xsl:text> </xsl:text>
+           <xsl:value-of select="NAME" />
+        </xsl:for-each>
+        <xsl:text>&#010;</xsl:text>
+    </xsl:for-each>  <!-- All cards -->
+    <xsl:text>@end multitable&#010;</xsl:text>
+
+</xsl:template>
+</xsl:stylesheet>
diff --git a/avrdude/update.c b/avrdude/update.c
new file mode 100644
index 00000000..22c9de7d
--- /dev/null
+++ b/avrdude/update.c
@@ -0,0 +1,372 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2000-2005  Brian S. Dean <bsd@bsdhome.com>
+ * Copyright (C) 2007 Joerg Wunsch
+ *
+ * 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
+ */
+
+/* $Id$ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+
+#include "avrdude.h"
+#include "avr.h"
+#include "config.h"
+#include "confwin.h"
+#include "fileio.h"
+#include "update.h"
+
+UPDATE * parse_op(char * s)
+{
+  char buf[1024];
+  char * p, * cp, c;
+  UPDATE * upd;
+  int i;
+  size_t fnlen;
+
+  upd = (UPDATE *)malloc(sizeof(UPDATE));
+  if (upd == NULL) {
+    fprintf(stderr, "%s: out of memory\n", progname);
+    exit(1);
+  }
+
+  i = 0;
+  p = s;
+  while ((i < (sizeof(buf)-1) && *p && (*p != ':')))
+    buf[i++] = *p++;
+  buf[i] = 0;
+
+  if (*p != ':') {
+    upd->memtype = (char *)malloc(strlen("flash")+1);
+    if (upd->memtype == NULL) {
+      outofmem:
+      fprintf(stderr, "%s: out of memory\n", progname);
+      exit(1);
+    }
+    strcpy(upd->memtype, "flash");
+    upd->op = DEVICE_WRITE;
+    upd->filename = (char *)malloc(strlen(buf) + 1);
+    if (upd->filename == NULL)
+      goto outofmem;
+    strcpy(upd->filename, buf);
+    upd->format = FMT_AUTO;
+    return upd;
+  }
+
+  upd->memtype = (char *)malloc(strlen(buf)+1);
+  if (upd->memtype == NULL) {
+    fprintf(stderr, "%s: out of memory\n", progname);
+    exit(1);
+  }
+  strcpy(upd->memtype, buf);
+
+  p++;
+  if (*p == 'r') {
+    upd->op = DEVICE_READ;
+  }
+  else if (*p == 'w') {
+    upd->op = DEVICE_WRITE;
+  }
+  else if (*p == 'v') {
+    upd->op = DEVICE_VERIFY;
+  }
+  else {
+    fprintf(stderr, "%s: invalid I/O mode '%c' in update specification\n",
+            progname, *p);
+    fprintf(stderr,
+            "  allowed values are:\n"
+            "    r = read device\n"
+            "    w = write device\n"
+            "    v = verify device\n");
+    free(upd->memtype);
+    free(upd);
+    return NULL;
+  }
+
+  p++;
+
+  if (*p != ':') {
+    fprintf(stderr, "%s: invalid update specification\n", progname);
+    free(upd->memtype);
+    free(upd);
+    return NULL;
+  }
+
+  p++;
+
+  /*
+   * Now, parse the filename component.  Instead of looking for the
+   * leftmost possible colon delimiter, we look for the rightmost one.
+   * If we found one, we do have a trailing :format specifier, and
+   * process it.  Otherwise, the remainder of the string is our file
+   * name component.  That way, the file name itself is allowed to
+   * contain a colon itself (e. g. C:/some/file.hex), except the
+   * optional format specifier becomes mandatory then.
+   */
+  cp = p;
+  p = strrchr(cp, ':');
+  if (p == NULL) {
+    upd->format = FMT_AUTO;
+    fnlen = strlen(cp);
+    upd->filename = (char *)malloc(fnlen + 1);
+  } else {
+    fnlen = p - cp;
+    upd->filename = (char *)malloc(fnlen +1);
+    c = *++p;
+    if (c && p[1])
+      /* More than one char - force failure below. */
+      c = '?';
+    switch (c) {
+      case 'a': upd->format = FMT_AUTO; break;
+      case 's': upd->format = FMT_SREC; break;
+      case 'i': upd->format = FMT_IHEX; break;
+      case 'r': upd->format = FMT_RBIN; break;
+      case 'm': upd->format = FMT_IMM; break;
+      case 'b': upd->format = FMT_BIN; break;
+      case 'd': upd->format = FMT_DEC; break;
+      case 'h': upd->format = FMT_HEX; break;
+      case 'o': upd->format = FMT_OCT; break;
+      default:
+        fprintf(stderr, "%s: invalid file format '%s' in update specifier\n",
+                progname, p);
+        free(upd->memtype);
+        free(upd);
+        return NULL;
+    }
+  }
+
+  if (upd->filename == NULL) {
+    fprintf(stderr, "%s: out of memory\n", progname);
+    free(upd->memtype);
+    free(upd);
+    return NULL;
+  }
+  memcpy(upd->filename, cp, fnlen);
+  upd->filename[fnlen] = 0;
+
+  return upd;
+}
+
+UPDATE * dup_update(UPDATE * upd)
+{
+  UPDATE * u;
+
+  u = (UPDATE *)malloc(sizeof(UPDATE));
+  if (u == NULL) {
+    fprintf(stderr, "%s: out of memory\n", progname);
+    exit(1);
+  }
+
+  memcpy(u, upd, sizeof(UPDATE));
+
+  u->memtype = strdup(upd->memtype);
+  u->filename = strdup(upd->filename);
+
+  return u;
+}
+
+UPDATE * new_update(int op, char * memtype, int filefmt, char * filename)
+{
+  UPDATE * u;
+
+  u = (UPDATE *)malloc(sizeof(UPDATE));
+  if (u == NULL) {
+    fprintf(stderr, "%s: out of memory\n", progname);
+    exit(1);
+  }
+
+  u->memtype = strdup(memtype);
+  u->filename = strdup(filename);
+  u->op = op;
+  u->format = filefmt;
+
+  return u;
+}
+
+int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, int nowrite,
+          int verify)
+{
+  struct avrpart * v;
+  AVRMEM * mem;
+  int size, vsize;
+  int rc;
+
+  mem = avr_locate_mem(p, upd->memtype);
+  if (mem == NULL) {
+    fprintf(stderr, "\"%s\" memory type not defined for part \"%s\"\n",
+            upd->memtype, p->desc);
+    return -1;
+  }
+
+  if (upd->op == DEVICE_READ) {
+    /*
+     * read out the specified device memory and write it to a file
+     */
+    if (quell_progress < 2) {
+      fprintf(stderr, "%s: reading %s memory:\n",
+            progname, mem->desc);
+	  }
+    report_progress(0,1,"Reading");
+    rc = avr_read(pgm, p, upd->memtype, 0, 1);
+    if (rc < 0) {
+      fprintf(stderr, "%s: failed to read all of %s memory, rc=%d\n",
+              progname, mem->desc, rc);
+      return -1;
+    }
+    report_progress(1,1,NULL);
+    size = rc;
+
+    if (quell_progress < 2) {
+      fprintf(stderr,
+            "%s: writing output file \"%s\"\n",
+            progname,
+            strcmp(upd->filename, "-")==0 ? "<stdout>" : upd->filename);
+    }
+    rc = fileio(FIO_WRITE, upd->filename, upd->format, p, upd->memtype, size);
+    if (rc < 0) {
+      fprintf(stderr, "%s: write to file '%s' failed\n",
+              progname, upd->filename);
+      return -1;
+    }
+  }
+  else if (upd->op == DEVICE_WRITE) {
+    /*
+     * write the selected device memory using data from a file; first
+     * read the data from the specified file
+     */
+    if (quell_progress < 2) {
+      fprintf(stderr,
+            "%s: reading input file \"%s\"\n",
+            progname,
+            strcmp(upd->filename, "-")==0 ? "<stdin>" : upd->filename);
+    }
+    rc = fileio(FIO_READ, upd->filename, upd->format, p, upd->memtype, -1);
+    if (rc < 0) {
+      fprintf(stderr, "%s: write to file '%s' failed\n",
+              progname, upd->filename);
+      return -1;
+    }
+    size = rc;
+
+    /*
+     * write the buffer contents to the selected memory type
+     */
+    if (quell_progress < 2) {
+      fprintf(stderr, "%s: writing %s (%d bytes):\n",
+            progname, mem->desc, size);
+	  }
+
+    if (!nowrite) {
+      report_progress(0,1,"Writing");
+      rc = avr_write(pgm, p, upd->memtype, size, 1);
+      report_progress(1,1,NULL);
+    }
+    else {
+      /*
+       * test mode, don't actually write to the chip, output the buffer
+       * to stdout in intel hex instead
+       */
+      rc = fileio(FIO_WRITE, "-", FMT_IHEX, p, upd->memtype, size);
+    }
+
+    if (rc < 0) {
+      fprintf(stderr, "%s: failed to write %s memory, rc=%d\n",
+              progname, mem->desc, rc);
+      return -1;
+    }
+
+    vsize = rc;
+
+    if (quell_progress < 2) {
+      fprintf(stderr, "%s: %d bytes of %s written\n", progname,
+            vsize, mem->desc);
+    }
+
+  }
+  else if (upd->op == DEVICE_VERIFY) {
+    /*
+     * verify that the in memory file (p->mem[AVR_M_FLASH|AVR_M_EEPROM])
+     * is the same as what is on the chip
+     */
+    pgm->vfy_led(pgm, ON);
+
+    v = avr_dup_part(p);
+
+    if (quell_progress < 2) {
+      fprintf(stderr, "%s: verifying %s memory against %s:\n",
+            progname, mem->desc, upd->filename);
+
+      fprintf(stderr, "%s: load data %s data from input file %s:\n",
+            progname, mem->desc, upd->filename);
+    }
+
+    rc = fileio(FIO_READ, upd->filename, upd->format, p, upd->memtype, -1);
+    if (rc < 0) {
+      fprintf(stderr, "%s: read from file '%s' failed\n",
+              progname, upd->filename);
+      return -1;
+    }
+    size = rc;
+    if (quell_progress < 2) {
+      fprintf(stderr, "%s: input file %s contains %d bytes\n",
+            progname, upd->filename, size);
+      fprintf(stderr, "%s: reading on-chip %s data:\n",
+            progname, mem->desc);
+    }
+
+    report_progress (0,1,"Reading");
+    rc = avr_read(pgm, v, upd->memtype, size, 1);
+    if (rc < 0) {
+      fprintf(stderr, "%s: failed to read all of %s memory, rc=%d\n",
+              progname, mem->desc, rc);
+      pgm->err_led(pgm, ON);
+      return -1;
+    }
+    report_progress (1,1,NULL);
+
+
+
+    if (quell_progress < 2) {
+      fprintf(stderr, "%s: verifying ...\n", progname);
+    }
+    rc = avr_verify(p, v, upd->memtype, size);
+    if (rc < 0) {
+      fprintf(stderr, "%s: verification error; content mismatch\n",
+              progname);
+      pgm->err_led(pgm, ON);
+      return -1;
+    }
+
+    if (quell_progress < 2) {
+      fprintf(stderr, "%s: %d bytes of %s verified\n",
+              progname, rc, mem->desc);
+    }
+
+    pgm->vfy_led(pgm, OFF);
+  }
+  else {
+    fprintf(stderr, "%s: invalid update operation (%d) requested\n",
+            progname, upd->op);
+    return -1;
+  }
+
+  return 0;
+}
+
diff --git a/avrdude/update.h b/avrdude/update.h
new file mode 100644
index 00000000..32e445d4
--- /dev/null
+++ b/avrdude/update.h
@@ -0,0 +1,55 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2000-2005  Brian S. Dean <bsd@bsdhome.com>
+ * Copyright (C) 2007 Joerg Wunsch
+ *
+ * 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
+ */
+
+/* $Id$ */
+
+#ifndef update_h
+#define update_h
+
+enum {
+  DEVICE_READ,
+  DEVICE_WRITE,
+  DEVICE_VERIFY
+};
+
+
+typedef struct update_t {
+  char * memtype;
+  int    op;
+  char * filename;
+  int    format;
+} UPDATE;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern UPDATE * parse_op(char * s);
+extern UPDATE * dup_update(UPDATE * upd);
+extern UPDATE * new_update(int op, char * memtype, int filefmt,
+			   char * filename);
+extern int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd,
+		 int nowrite, int verify);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/avrdude/usb_libusb.c b/avrdude/usb_libusb.c
new file mode 100644
index 00000000..679f2eff
--- /dev/null
+++ b/avrdude/usb_libusb.c
@@ -0,0 +1,483 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2005,2006 Joerg Wunsch
+ * Copyright (C) 2006 David Moore
+ *
+ * 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
+ */
+
+/* $Id$ */
+
+/*
+ * USB interface via libusb for avrdude.
+ */
+
+#include "ac_cfg.h"
+#if defined(HAVE_LIBUSB)
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <usb.h>
+
+#include "avrdude.h"
+#include "serial.h"
+#include "usbdevs.h"
+
+#if defined(WIN32NATIVE)
+/* someone has defined "interface" to "struct" in Cygwin */
+#  undef interface
+#endif
+
+static char usbbuf[USBDEV_MAX_XFER];
+static int buflen = -1, bufptr;
+
+static int usb_interface;
+
+/*
+ * The "baud" parameter is meaningless for USB devices, so we reuse it
+ * to pass the desired USB device ID.
+ */
+static void usbdev_open(char * port, long baud, union filedescriptor *fd)
+{
+  char string[256];
+  char product[256];
+  struct usb_bus *bus;
+  struct usb_device *dev;
+  usb_dev_handle *udev;
+  char *serno, *cp2;
+  int i;
+  size_t x;
+
+  /*
+   * The syntax for usb devices is defined as:
+   *
+   * -P usb[:serialnumber]
+   *
+   * See if we've got a serial number passed here.  The serial number
+   * might contain colons which we remove below, and we compare it
+   * right-to-left, so only the least significant nibbles need to be
+   * specified.
+   */
+  if ((serno = strchr(port, ':')) != NULL)
+    {
+      /* first, drop all colons there if any */
+      cp2 = ++serno;
+
+      while ((cp2 = strchr(cp2, ':')) != NULL)
+	{
+	  x = strlen(cp2) - 1;
+	  memmove(cp2, cp2 + 1, x);
+	  cp2[x] = '\0';
+	}
+
+      if (strlen(serno) > 12)
+	{
+	  fprintf(stderr,
+		  "%s: usbdev_open(): invalid serial number \"%s\"\n",
+		  progname, serno);
+	  exit(1);
+	}
+    }
+
+  usb_init();
+
+  usb_find_busses();
+  usb_find_devices();
+
+  for (bus = usb_get_busses(); bus; bus = bus->next)
+    {
+      for (dev = bus->devices; dev; dev = dev->next)
+	{
+	  udev = usb_open(dev);
+	  if (udev)
+	    {
+	      if (dev->descriptor.idVendor == USB_VENDOR_ATMEL &&
+		  dev->descriptor.idProduct == (unsigned short)baud)
+		{
+		  /* yeah, we found something */
+		  if (usb_get_string_simple(udev,
+					    dev->descriptor.iSerialNumber,
+					    string, sizeof(string)) < 0)
+		    {
+		      fprintf(stderr,
+			      "%s: usb_open(): cannot read serial number \"%s\"\n",
+			      progname, usb_strerror());
+		      /*
+		       * On some systems, libusb appears to have
+		       * problems sending control messages.  Catch the
+		       * benign case where the user did not request a
+		       * particular serial number, so we could
+		       * continue anyway.
+		       */
+		      if (serno != NULL)
+			exit(1); /* no chance */
+		      else
+			strcpy(string, "[unknown]");
+		    }
+
+		  if (usb_get_string_simple(udev,
+					    dev->descriptor.iProduct,
+					    product, sizeof(product)) < 0)
+		    {
+		      fprintf(stderr,
+			      "%s: usb_open(): cannot read product name \"%s\"\n",
+			      progname, usb_strerror());
+		      strcpy(product, "[unnamed product]");
+		    }
+
+		  if (verbose)
+		    fprintf(stderr,
+			    "%s: usbdev_open(): Found %s, serno: %s\n",
+			    progname, product, string);
+		  if (serno != NULL)
+		    {
+		      /*
+		       * See if the serial number requested by the
+		       * user matches what we found, matching
+		       * right-to-left.
+		       */
+		      x = strlen(string) - strlen(serno);
+		      if (strcasecmp(string + x, serno) != 0)
+			{
+			  if (verbose > 2)
+			    fprintf(stderr,
+				    "%s: usbdev_open(): serial number doesn't match\n",
+				    progname);
+			  usb_close(udev);
+			      continue;
+			}
+		    }
+
+		  if (dev->config == NULL)
+		    {
+		      fprintf(stderr,
+			      "%s: usbdev_open(): USB device has no configuration\n",
+			      progname);
+		      goto trynext;
+		    }
+
+		  if (usb_set_configuration(udev, dev->config[0].bConfigurationValue))
+		    {
+		      fprintf(stderr,
+			      "%s: usbdev_open(): error setting configuration %d: %s\n",
+			      progname, dev->config[0].bConfigurationValue,
+			      usb_strerror());
+		      goto trynext;
+		    }
+
+		  usb_interface = dev->config[0].interface[0].altsetting[0].bInterfaceNumber;
+		  if (usb_claim_interface(udev, usb_interface))
+		    {
+		      fprintf(stderr,
+			      "%s: usbdev_open(): error claiming interface %d: %s\n",
+			      progname, usb_interface, usb_strerror());
+		      goto trynext;
+		    }
+
+		  fd->usb.handle = udev;
+		  fd->usb.ep = -1;
+		  /* Try finding out what our read endpoint is. */
+		  for (i = 0; i < dev->config[0].interface[0].altsetting[0].bNumEndpoints; i++)
+		    {
+		      int possible_ep = dev->config[0].interface[0].altsetting[0].
+		      endpoint[i].bEndpointAddress;
+
+		      if ((possible_ep & USB_ENDPOINT_DIR_MASK) != 0)
+			{
+			  if (verbose > 1)
+			    {
+			      fprintf(stderr,
+				      "%s: usbdev_open(): using read endpoint 0x%02x\n",
+				      progname, possible_ep);
+			    }
+			  fd->usb.ep = possible_ep;
+			  break;
+			}
+		    }
+		  if (fd->usb.ep == -1)
+		    {
+		      fprintf(stderr,
+			      "%s: usbdev_open(): cannot find a read endpoint, using 0x%02x\n",
+			      progname, USBDEV_BULK_EP_READ);
+		      fd->usb.ep = USBDEV_BULK_EP_READ;
+		    }
+                  return;
+		}
+	      trynext:
+	      usb_close(udev);
+	    }
+	}
+    }
+
+  fprintf(stderr, "%s: usbdev_open(): did not find any%s USB device \"%s\"\n",
+	  progname, serno? " (matching)": "", port);
+  exit(1);
+}
+
+static void usbdev_close(union filedescriptor *fd)
+{
+  usb_dev_handle *udev = (usb_dev_handle *)fd->usb.handle;
+
+  (void)usb_release_interface(udev, usb_interface);
+
+#if !( defined(__FreeBSD__) ) // || ( defined(__APPLE__) && defined(__MACH__) ) )
+  /*
+   * Without this reset, the AVRISP mkII seems to stall the second
+   * time we try to connect to it.  This is not necessary on
+   * FreeBSD.
+   */
+  usb_reset(udev);
+#endif
+
+  usb_close(udev);
+}
+
+
+static int usbdev_send(union filedescriptor *fd, unsigned char *bp, size_t mlen)
+{
+  usb_dev_handle *udev = (usb_dev_handle *)fd->usb.handle;
+  int rv;
+  int i = mlen;
+  unsigned char * p = bp;
+  int tx_size;
+
+  /*
+   * Split the frame into multiple packets.  It's important to make
+   * sure we finish with a short packet, or else the device won't know
+   * the frame is finished.  For example, if we need to send 64 bytes,
+   * we must send a packet of length 64 followed by a packet of length
+   * 0.
+   */
+  do {
+    tx_size = (mlen < USBDEV_MAX_XFER)? mlen: USBDEV_MAX_XFER;
+    rv = usb_bulk_write(udev, USBDEV_BULK_EP_WRITE, (char *)bp, tx_size, 5000);
+    if (rv != tx_size)
+    {
+        fprintf(stderr, "%s: usbdev_send(): wrote %d out of %d bytes, err = %s\n",
+                progname, rv, tx_size, usb_strerror());
+        return -1;
+    }
+    bp += tx_size;
+    mlen -= tx_size;
+  } while (tx_size == USBDEV_MAX_XFER);
+
+  if (verbose > 3)
+  {
+      fprintf(stderr, "%s: Sent: ", progname);
+
+      while (i) {
+        unsigned char c = *p;
+        if (isprint(c)) {
+          fprintf(stderr, "%c ", c);
+        }
+        else {
+          fprintf(stderr, ". ");
+        }
+        fprintf(stderr, "[%02x] ", c);
+
+        p++;
+        i--;
+      }
+      fprintf(stderr, "\n");
+  }
+  return 0;
+}
+
+/*
+ * As calls to usb_bulk_read() result in exactly one USB request, we
+ * have to buffer the read results ourselves, so the single-char read
+ * requests performed by the upper layers will be handled.  In order
+ * to do this, we maintain a private buffer of what we've got so far,
+ * and transparently issue another USB read request if the buffer is
+ * empty and more data are requested.
+ */
+static int
+usb_fill_buf(usb_dev_handle *udev, int ep)
+{
+  int rv;
+
+  rv = usb_bulk_read(udev, ep, usbbuf, USBDEV_MAX_XFER, 5000);
+  if (rv < 0)
+    {
+      if (verbose > 1)
+	fprintf(stderr, "%s: usb_fill_buf(): usb_bulk_read() error %s\n",
+		progname, usb_strerror());
+      return -1;
+    }
+
+  buflen = rv;
+  bufptr = 0;
+
+  return 0;
+}
+
+static int usbdev_recv(union filedescriptor *fd, unsigned char *buf, size_t nbytes)
+{
+  usb_dev_handle *udev = (usb_dev_handle *)fd->usb.handle;
+  int i, amnt;
+  unsigned char * p = buf;
+
+  for (i = 0; nbytes > 0;)
+    {
+      if (buflen <= bufptr)
+	{
+	  if (usb_fill_buf(udev, fd->usb.ep) < 0)
+	    return -1;
+	}
+      amnt = buflen - bufptr > nbytes? nbytes: buflen - bufptr;
+      memcpy(buf + i, usbbuf + bufptr, amnt);
+      bufptr += amnt;
+      nbytes -= amnt;
+      i += amnt;
+    }
+
+  if (verbose > 4)
+  {
+      fprintf(stderr, "%s: Recv: ", progname);
+
+      while (i) {
+        unsigned char c = *p;
+        if (isprint(c)) {
+          fprintf(stderr, "%c ", c);
+        }
+        else {
+          fprintf(stderr, ". ");
+        }
+        fprintf(stderr, "[%02x] ", c);
+
+        p++;
+        i--;
+      }
+      fprintf(stderr, "\n");
+  }
+
+  return 0;
+}
+
+/*
+ * This version of recv keeps reading packets until we receive a short
+ * packet.  Then, the entire frame is assembled and returned to the
+ * user.  The length will be unknown in advance, so we return the
+ * length as the return value of this function, or -1 in case of an
+ * error.
+ *
+ * This is used for the AVRISP mkII device.
+ */
+static int usbdev_recv_frame(union filedescriptor *fd, unsigned char *buf, size_t nbytes)
+{
+  usb_dev_handle *udev = (usb_dev_handle *)fd->usb.handle;
+  int rv, n;
+  int i;
+  unsigned char * p = buf;
+
+  n = 0;
+  do
+    {
+      rv = usb_bulk_read(udev, fd->usb.ep, usbbuf,
+			 USBDEV_MAX_XFER, 10000);
+      if (rv < 0)
+	{
+	  if (verbose > 1)
+	    fprintf(stderr, "%s: usbdev_recv_frame(): usb_bulk_read(): %s\n",
+		    progname, usb_strerror());
+	  return -1;
+	}
+
+      if (rv <= nbytes)
+	{
+	  memcpy (buf, usbbuf, rv);
+	  buf += rv;
+	}
+
+      n += rv;
+      nbytes -= rv;
+    }
+  while (rv == USBDEV_MAX_XFER);
+
+  if (nbytes < 0)
+    return -1;
+
+  if (verbose > 3)
+  {
+      i = n;
+      fprintf(stderr, "%s: Recv: ", progname);
+
+      while (i) {
+        unsigned char c = *p;
+        if (isprint(c)) {
+          fprintf(stderr, "%c ", c);
+        }
+        else {
+          fprintf(stderr, ". ");
+        }
+        fprintf(stderr, "[%02x] ", c);
+
+        p++;
+        i--;
+      }
+      fprintf(stderr, "\n");
+  }
+  return n;
+}
+
+static int usbdev_drain(union filedescriptor *fd, int display)
+{
+  usb_dev_handle *udev = (usb_dev_handle *)fd->usb.handle;
+  int rv;
+
+  do {
+    rv = usb_bulk_read(udev, fd->usb.ep, usbbuf, USBDEV_MAX_XFER, 100);
+    if (rv > 0 && verbose >= 4)
+      fprintf(stderr, "%s: usbdev_drain(): flushed %d characters\n",
+	      progname, rv);
+  } while (rv > 0);
+
+  return 0;
+}
+
+/*
+ * Device descriptor for the JTAG ICE mkII.
+ */
+struct serial_device usb_serdev =
+{
+  .open = usbdev_open,
+  .close = usbdev_close,
+  .send = usbdev_send,
+  .recv = usbdev_recv,
+  .drain = usbdev_drain,
+  .flags = SERDEV_FL_NONE,
+};
+
+/*
+ * Device descriptor for the AVRISP mkII.
+ */
+struct serial_device usb_serdev_frame =
+{
+  .open = usbdev_open,
+  .close = usbdev_close,
+  .send = usbdev_send,
+  .recv = usbdev_recv_frame,
+  .drain = usbdev_drain,
+  .flags = SERDEV_FL_NONE,
+};
+
+#endif  /* HAVE_LIBUSB */
diff --git a/avrdude/usbasp.c b/avrdude/usbasp.c
new file mode 100644
index 00000000..ff7d71e2
--- /dev/null
+++ b/avrdude/usbasp.c
@@ -0,0 +1,599 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2006  Thomas Fischl
+ * Copyright 2007 Joerg Wunsch <j@uriah.heep.sax.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 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
+ */
+
+/* $Id$ */
+
+/*
+ * Interface to the USBasp programmer.
+ *
+ * See http://www.fischl.de/usbasp/
+ */
+#include "ac_cfg.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "avrdude.h"
+#include "avr.h"
+#include "pgm.h"
+#include "usbasp.h"
+
+#ifdef HAVE_LIBUSB
+#include <usb.h>
+
+/*
+ * Private data for this programmer.
+ */
+struct pdata
+{
+  usb_dev_handle *usbhandle;
+  int sckfreq_hz; 
+};
+
+#define PDATA(pgm) ((struct pdata *)(pgm->cookie))
+
+static void usbasp_setup(PROGRAMMER * pgm)
+{
+  if ((pgm->cookie = malloc(sizeof(struct pdata))) == 0) {
+    fprintf(stderr,
+	    "%s: usbasp_setup(): Out of memory allocating private data\n",
+	    progname);
+    exit(1);
+  }
+  memset(pgm->cookie, 0, sizeof(struct pdata));
+}
+
+static void usbasp_teardown(PROGRAMMER * pgm)
+{
+  free(pgm->cookie);
+}
+
+
+/*
+ * wrapper for usb_control_msg call
+ */
+static int usbasp_transmit(PROGRAMMER * pgm,
+			   unsigned char receive, unsigned char functionid,
+			   unsigned char send[4], unsigned char * buffer, int buffersize)
+{
+  int nbytes;
+  nbytes = usb_control_msg(PDATA(pgm)->usbhandle,
+			   USB_TYPE_VENDOR | USB_RECIP_DEVICE | (receive << 7),
+			   functionid,
+			   (send[1] << 8) | send[0],
+			   (send[3] << 8) | send[2],
+			   (char *)buffer, buffersize,
+			   5000);
+  if(nbytes < 0){
+    fprintf(stderr, "%s: error: usbasp_transmit: %s\n", progname, usb_strerror());
+    exit(1);
+  }
+
+  return nbytes;
+}
+
+
+/*
+ * Try to open USB device with given VID, PID, vendor and product name
+ * Parts of this function were taken from an example code by OBJECTIVE
+ * DEVELOPMENT Software GmbH (www.obdev.at) to meet conditions for
+ * shared VID/PID
+ */
+static int usbOpenDevice(usb_dev_handle **device, int vendor,
+			 char *vendorName, int product, char *productName)
+{
+struct usb_bus      *bus;
+struct usb_device   *dev;
+usb_dev_handle      *handle = NULL;
+int                 errorCode = USB_ERROR_NOTFOUND;
+static int          didUsbInit = 0;
+
+    if(!didUsbInit){
+        didUsbInit = 1;
+        usb_init();
+    }
+    usb_find_busses();
+    usb_find_devices();
+    for(bus=usb_get_busses(); bus; bus=bus->next){
+        for(dev=bus->devices; dev; dev=dev->next){
+            if(dev->descriptor.idVendor == vendor &&
+	       dev->descriptor.idProduct == product){
+                char    string[256];
+                int     len;
+		/* we need to open the device in order to query strings */
+                handle = usb_open(dev);
+                if(!handle){
+                    errorCode = USB_ERROR_ACCESS;
+                    fprintf(stderr,
+			    "%s: Warning: cannot open USB device: %s\n",
+			    progname, usb_strerror());
+                    continue;
+                }
+                if(vendorName == NULL && productName == NULL){
+		    /* name does not matter */
+                    break;
+                }
+                /* now check whether the names match: */
+                len = usb_get_string_simple(handle, dev->descriptor.iManufacturer,
+					    string, sizeof(string));
+                if(len < 0){
+                    errorCode = USB_ERROR_IO;
+                    fprintf(stderr,
+			    "%s: Warning: cannot query manufacturer for device: %s\n",
+			    progname, usb_strerror());
+                }else{
+                    errorCode = USB_ERROR_NOTFOUND;
+		    if (verbose > 1)
+		        fprintf(stderr,
+				"%s: seen device from vendor ->%s<-\n",
+				progname, string);
+                    if(strcmp(string, vendorName) == 0){
+                        len = usb_get_string_simple(handle, dev->descriptor.iProduct,
+						    string, sizeof(string));
+                        if(len < 0){
+                            errorCode = USB_ERROR_IO;
+                            fprintf(stderr,
+				    "%s: Warning: cannot query product for device: %s\n",
+				    progname, usb_strerror());
+                        }else{
+                            errorCode = USB_ERROR_NOTFOUND;
+			    if (verbose > 1)
+			        fprintf(stderr,
+					"%s: seen product ->%s<-\n",
+					progname, string);
+                            if(strcmp(string, productName) == 0)
+                                break;
+                        }
+                    }
+                }
+                usb_close(handle);
+                handle = NULL;
+            }
+        }
+        if(handle)
+            break;
+    }
+    if(handle != NULL){
+        errorCode = 0;
+        *device = handle;
+    }
+    return errorCode;
+}
+
+
+static int usbasp_open(PROGRAMMER * pgm, char * port)
+{
+  usb_init();
+
+  if (usbOpenDevice(&PDATA(pgm)->usbhandle, USBASP_SHARED_VID, "www.fischl.de",
+		    USBASP_SHARED_PID, "USBasp") != 0) {
+
+    /* check if device with old VID/PID is available */
+    if (usbOpenDevice(&PDATA(pgm)->usbhandle, USBASP_OLD_VID, "www.fischl.de",
+		      USBASP_OLD_PID, "USBasp") != 0) {
+
+      /* no USBasp found */
+      fprintf(stderr,
+	      "%s: error: could not find USB device "
+	      "\"USBasp\" with vid=0x%x pid=0x%x\n",
+  	      progname, USBASP_SHARED_VID, USBASP_SHARED_PID);
+      exit(1);
+
+    } else {
+
+      /* found USBasp with old IDs */
+      fprintf(stderr,
+	      "%s: Warning: Found USB device \"USBasp\" with "
+	      "old VID/PID! Please update firmware of USBasp!\n",
+  	      progname);
+    }
+  }
+
+  return 0;
+}
+
+
+static void usbasp_close(PROGRAMMER * pgm)
+{
+  unsigned char temp[4];
+  memset(temp, 0, sizeof(temp));
+  usbasp_transmit(pgm, 1, USBASP_FUNC_DISCONNECT, temp, temp, sizeof(temp));
+
+  usb_close(PDATA(pgm)->usbhandle);
+}
+
+
+static int usbasp_initialize(PROGRAMMER * pgm, AVRPART * p)
+{
+
+  unsigned char temp[4];
+  memset(temp, 0, sizeof(temp));
+
+  /* set sck period */
+  pgm->set_sck_period(pgm, pgm->bitclock);
+
+  /* connect to target device */
+  usbasp_transmit(pgm, 1, USBASP_FUNC_CONNECT, temp, temp, sizeof(temp));
+
+  /* wait, so device is ready to receive commands */
+  usleep(100000);
+
+  return pgm->program_enable(pgm, p);
+}
+
+static void usbasp_disable(PROGRAMMER * pgm)
+{
+  /* Do nothing. */
+
+  return;
+}
+
+static void usbasp_enable(PROGRAMMER * pgm)
+{
+  /* Do nothing. */
+
+  return;
+}
+
+static void usbasp_display(PROGRAMMER * pgm, const char * p)
+{
+  return;
+}
+
+
+static int usbasp_cmd(PROGRAMMER * pgm, unsigned char cmd[4],
+                   unsigned char res[4])
+{
+  int nbytes =
+    usbasp_transmit(pgm, 1, USBASP_FUNC_TRANSMIT, cmd, res, sizeof(res));
+
+  if(nbytes != 4){
+    fprintf(stderr, "%s: error: wrong responds size\n",
+	    progname);
+    return -1;
+  }
+
+  return 0;
+}
+
+
+static int usbasp_program_enable(PROGRAMMER * pgm, AVRPART * p)
+{
+  unsigned char res[4];
+  unsigned char cmd[4];
+  memset(cmd, 0, sizeof(cmd));
+  memset(res, 0, sizeof(res));
+
+  cmd[0] = 0;
+
+  int nbytes =
+    usbasp_transmit(pgm, 1, USBASP_FUNC_ENABLEPROG, cmd, res, sizeof(res));
+
+  if ((nbytes != 1) | (res[0] != 0)) {
+    fprintf(stderr, "%s: error: programm enable: target doesn't answer. %x \n",
+	    progname, res[0]);
+    return -1;
+  }
+
+  return 0;
+}
+
+
+static int usbasp_chip_erase(PROGRAMMER * pgm, AVRPART * p)
+{
+  unsigned char cmd[4];
+  unsigned char res[4];
+
+  if (p->op[AVR_OP_CHIP_ERASE] == NULL) {
+    fprintf(stderr, "chip erase instruction not defined for part \"%s\"\n",
+            p->desc);
+    return -1;
+  }
+
+  memset(cmd, 0, sizeof(cmd));
+
+  avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd);
+  pgm->cmd(pgm, cmd, res);
+  usleep(p->chip_erase_delay);
+  pgm->initialize(pgm, p);
+
+  return 0;
+}
+
+
+static int usbasp_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+                             int page_size, int n_bytes)
+{
+  int n;
+  unsigned char cmd[4];
+  int address = 0;
+  int wbytes = n_bytes;
+  int blocksize;
+  unsigned char * buffer = m->buf;
+  int function;
+
+  if (strcmp(m->desc, "flash") == 0) {
+    function = USBASP_FUNC_READFLASH;
+  } else if (strcmp(m->desc, "eeprom") == 0) {
+    function = USBASP_FUNC_READEEPROM;
+  } else {
+    return -2;
+  }
+
+  /* set blocksize depending on sck frequency */  
+  if ((PDATA(pgm)->sckfreq_hz > 0) && (PDATA(pgm)->sckfreq_hz < 10000)) {
+     blocksize = USBASP_READBLOCKSIZE / 10;
+  } else {
+     blocksize = USBASP_READBLOCKSIZE;
+  }
+
+  while (wbytes) {
+    if (wbytes <= blocksize) {
+      blocksize = wbytes;
+    }
+    wbytes -= blocksize;
+
+    /* set address (new mode) - if firmware on usbasp support newmode, then they use address from this command */
+    unsigned char temp[4];
+    memset(temp, 0, sizeof(temp));
+    cmd[0] = address & 0xFF;
+    cmd[1] = address >> 8;
+    cmd[2] = address >> 16;
+    cmd[3] = address >> 24;
+    usbasp_transmit(pgm, 1, USBASP_FUNC_SETLONGADDRESS, cmd, temp, sizeof(temp));
+
+    /* send command with address (compatibility mode) - if firmware on
+	  usbasp doesn't support newmode, then they use address from this */
+    cmd[0] = address & 0xFF;
+    cmd[1] = address >> 8;
+    // for compatibility - previous version of usbasp.c doesn't initialize this fields (firmware ignore it)
+    cmd[2] = 0;
+    cmd[3] = 0;
+
+    n = usbasp_transmit(pgm, 1, function, cmd, buffer, blocksize);
+
+    if (n != blocksize) {
+      fprintf(stderr, "%s: error: wrong reading bytes %x\n",
+	      progname, n);
+      exit(1);
+    }
+
+    buffer += blocksize;
+    address += blocksize;
+
+    report_progress (address, n_bytes, NULL);
+  }
+
+  return n_bytes;
+}
+
+static int usbasp_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+                              int page_size, int n_bytes)
+{
+  int n;
+  unsigned char cmd[4];
+  int address = 0;
+  int wbytes = n_bytes;
+  int blocksize;
+  unsigned char * buffer = m->buf;
+  unsigned char blockflags = USBASP_BLOCKFLAG_FIRST;
+  int function;
+
+  if (strcmp(m->desc, "flash") == 0) {
+    function = USBASP_FUNC_WRITEFLASH;
+  } else if (strcmp(m->desc, "eeprom") == 0) {
+    function = USBASP_FUNC_WRITEEEPROM;
+  } else {
+    return -2;
+  }
+
+  /* set blocksize depending on sck frequency */  
+  if ((PDATA(pgm)->sckfreq_hz > 0) && (PDATA(pgm)->sckfreq_hz < 10000)) {
+     blocksize = USBASP_WRITEBLOCKSIZE / 10;
+  } else {
+     blocksize = USBASP_WRITEBLOCKSIZE;
+  }
+
+  while (wbytes) {
+
+    if (wbytes <= blocksize) {
+      blocksize = wbytes;
+      blockflags |= USBASP_BLOCKFLAG_LAST;
+    }
+    wbytes -= blocksize;
+
+
+    /* set address (new mode) - if firmware on usbasp support newmode, then
+      they use address from this command */
+    unsigned char temp[4];
+    memset(temp, 0, sizeof(temp));
+    cmd[0] = address & 0xFF;
+    cmd[1] = address >> 8;
+    cmd[2] = address >> 16;
+    cmd[3] = address >> 24;
+    usbasp_transmit(pgm, 1, USBASP_FUNC_SETLONGADDRESS, cmd, temp, sizeof(temp));
+
+    /* normal command - firmware what support newmode - use address from previous command,
+      firmware what doesn't support newmode - ignore previous command and use address from this command */
+
+    cmd[0] = address & 0xFF;
+    cmd[1] = address >> 8;
+    cmd[2] = page_size & 0xFF;
+    cmd[3] = (blockflags & 0x0F) + ((page_size & 0xF00) >> 4); //TP: Mega128 fix
+    blockflags = 0;
+
+    n = usbasp_transmit(pgm, 0, function, cmd, buffer, blocksize);
+
+    if (n != blocksize) {
+      fprintf(stderr, "%s: error: wrong count at writing %x\n",
+	      progname, n);
+      exit(1);
+    }
+
+
+    buffer += blocksize;
+    address += blocksize;
+
+    report_progress (address, n_bytes, NULL);
+  }
+
+  return n_bytes;
+}
+
+
+/* The list of SCK frequencies in Hz supported by USBasp */
+static struct sckoptions_t usbaspSCKoptions[] = {
+  { USBASP_ISP_SCK_1500, 1500000 },
+  { USBASP_ISP_SCK_750, 750000 },
+  { USBASP_ISP_SCK_375, 375000 },
+  { USBASP_ISP_SCK_187_5, 187500 },
+  { USBASP_ISP_SCK_93_75, 93750 },
+  { USBASP_ISP_SCK_32, 32000 },
+  { USBASP_ISP_SCK_16, 16000 },
+  { USBASP_ISP_SCK_8, 8000 },
+  { USBASP_ISP_SCK_4, 4000 },
+  { USBASP_ISP_SCK_2, 2000 },
+  { USBASP_ISP_SCK_1, 1000 },
+  { USBASP_ISP_SCK_0_5, 500 }
+};
+
+
+/*
+ * Set sck period (in seconds)
+ * Find next possible sck period and write it to the programmer.
+ */
+static int usbasp_set_sck_period(PROGRAMMER *pgm, double sckperiod)
+{
+  char clockoption = USBASP_ISP_SCK_AUTO;
+  unsigned char res[4];
+  unsigned char cmd[4];
+
+  memset(cmd, 0, sizeof(cmd));
+  memset(res, 0, sizeof(res));
+
+  /* reset global sck frequency to auto */
+  PDATA(pgm)->sckfreq_hz = 0;
+
+  if (sckperiod == 0) {
+    /* auto sck set */
+
+    if (verbose >= 1)
+      fprintf(stderr, "%s: auto set sck period (because given equals null)\n", progname);
+
+  } else {
+
+    int sckfreq = 1 / sckperiod; /* sck in Hz */
+    int usefreq = 0;
+
+    if (verbose >= 2)
+      fprintf(stderr, "%s: try to set SCK period to %g s (= %i Hz)\n", progname, sckperiod, sckfreq);
+
+    if (sckfreq >= usbaspSCKoptions[0].frequency) {
+      clockoption = usbaspSCKoptions[0].id;
+      usefreq = usbaspSCKoptions[0].frequency;
+    } else {
+
+      /* find clock option next to given clock */
+      int i;
+      for (i = 0; i < sizeof(usbaspSCKoptions) / sizeof(usbaspSCKoptions[0]); i++) {
+        if (sckfreq >= usbaspSCKoptions[i].frequency - 1) { /* subtract 1 to compensate round errors */
+          clockoption = usbaspSCKoptions[i].id;
+          usefreq = usbaspSCKoptions[i].frequency;
+          break;
+        }
+      }
+    }
+
+    /* save used sck frequency */
+    PDATA(pgm)->sckfreq_hz = usefreq;
+
+    fprintf(stderr, "%s: set SCK frequency to %i Hz\n", progname, usefreq);
+  }
+
+  cmd[0] = clockoption;
+
+  int nbytes =
+    usbasp_transmit(pgm, 1, USBASP_FUNC_SETISPSCK, cmd, res, sizeof(res));
+
+  if ((nbytes != 1) | (res[0] != 0)) {
+    fprintf(stderr, "%s: warning: cannot set sck period. please check for usbasp firmware update.\n",
+      progname);
+    return -1;
+  }
+
+  return 0;
+}
+
+
+void usbasp_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "usbasp");
+
+  /*
+   * mandatory functions
+   */
+
+  pgm->initialize     = usbasp_initialize;
+  pgm->display        = usbasp_display;
+  pgm->enable         = usbasp_enable;
+  pgm->disable        = usbasp_disable;
+  pgm->program_enable = usbasp_program_enable;
+  pgm->chip_erase     = usbasp_chip_erase;
+  pgm->cmd            = usbasp_cmd;
+  pgm->open           = usbasp_open;
+  pgm->close          = usbasp_close;
+  pgm->read_byte      = avr_read_byte_default;
+  pgm->write_byte     = avr_write_byte_default;
+
+  /*
+   * optional functions
+   */
+
+  pgm->paged_write = usbasp_paged_write;
+  pgm->paged_load = usbasp_paged_load;
+  pgm->setup          = usbasp_setup;
+  pgm->teardown       = usbasp_teardown;
+  pgm->set_sck_period	= usbasp_set_sck_period;
+
+}
+
+
+#else /* HAVE_LIBUSB */
+
+static int usbasp_nousb_open (struct programmer_t *pgm, char * name)
+{
+  fprintf(stderr, "%s: error: no usb support. please compile again with libusb installed.\n",
+	  progname);
+
+  exit(1);
+}
+
+void usbasp_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "usbasp");
+
+  pgm->open           = usbasp_nousb_open;
+}
+
+#endif  /* HAVE_LIBUSB */
diff --git a/avrdude/usbasp.h b/avrdude/usbasp.h
new file mode 100644
index 00000000..c0d4468f
--- /dev/null
+++ b/avrdude/usbasp.h
@@ -0,0 +1,89 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2006  Thomas Fischl
+ *
+ * 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
+ */
+
+/* $Id$ */
+
+#ifndef usbasp_h
+#define usbasp_h
+
+#include "avrpart.h"
+
+/* USB identifiers */
+#define	USBASP_SHARED_VID   0x16C0  /* VOTI */
+#define	USBASP_SHARED_PID   0x05DC  /* Obdev's free shared PID */
+
+#define	USBASP_OLD_VID      0x03EB  /* ATMEL */
+#define	USBASP_OLD_PID	    0xC7B4  /* (unoffical) USBasp */
+
+/* USB function call identifiers */
+#define USBASP_FUNC_CONNECT    1
+#define USBASP_FUNC_DISCONNECT 2
+#define USBASP_FUNC_TRANSMIT   3
+#define USBASP_FUNC_READFLASH  4
+#define USBASP_FUNC_ENABLEPROG 5
+#define USBASP_FUNC_WRITEFLASH 6
+#define USBASP_FUNC_READEEPROM 7
+#define USBASP_FUNC_WRITEEEPROM 8
+#define USBASP_FUNC_SETLONGADDRESS 9
+#define USBASP_FUNC_SETISPSCK 10
+
+/* Block mode flags */
+#define USBASP_BLOCKFLAG_FIRST    1
+#define USBASP_BLOCKFLAG_LAST     2
+
+/* Block mode data size */
+#define USBASP_READBLOCKSIZE   200
+#define USBASP_WRITEBLOCKSIZE  200
+
+/* ISP SCK speed identifiers */
+#define USBASP_ISP_SCK_AUTO   0
+#define USBASP_ISP_SCK_0_5    1   /* 500 Hz */
+#define USBASP_ISP_SCK_1      2   /*   1 kHz */
+#define USBASP_ISP_SCK_2      3   /*   2 kHz */
+#define USBASP_ISP_SCK_4      4   /*   4 kHz */
+#define USBASP_ISP_SCK_8      5   /*   8 kHz */
+#define USBASP_ISP_SCK_16     6   /*  16 kHz */
+#define USBASP_ISP_SCK_32     7   /*  32 kHz */
+#define USBASP_ISP_SCK_93_75  8   /*  93.75 kHz */
+#define USBASP_ISP_SCK_187_5  9   /* 187.5  kHz */
+#define USBASP_ISP_SCK_375    10  /* 375 kHz   */
+#define USBASP_ISP_SCK_750    11  /* 750 kHz   */
+#define USBASP_ISP_SCK_1500   12  /* 1.5 MHz   */
+
+typedef struct sckoptions_t {
+  int id;
+  double frequency;
+} CLOCKOPTIONS;
+
+/* USB error identifiers */
+#define USB_ERROR_NOTFOUND  1
+#define USB_ERROR_ACCESS    2
+#define USB_ERROR_IO        3
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void usbasp_initpgm (PROGRAMMER * pgm);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* usbasp_h */
diff --git a/avrdude/usbdevs.h b/avrdude/usbdevs.h
new file mode 100644
index 00000000..0c36f816
--- /dev/null
+++ b/avrdude/usbdevs.h
@@ -0,0 +1,43 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2006 Joerg Wunsch
+ *
+ * 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
+ */
+
+/* $Id$ */
+
+/*
+ * defines for the USB interface
+ */
+
+#ifndef usbdevs_h
+#define usbdevs_h
+
+#define USB_VENDOR_ATMEL 1003
+#define USB_DEVICE_JTAGICEMKII 0x2103
+#define USB_DEVICE_AVRISPMKII  0x2104
+#define USB_DEVICE_STK600      0x2106
+#define USB_DEVICE_AVRDRAGON   0x2107
+
+/*
+ * Should we query the endpoint number and max transfer size from USB?
+ * After all, the JTAG ICE mkII docs document these values.
+ */
+#define USBDEV_BULK_EP_WRITE 0x02
+#define USBDEV_BULK_EP_READ  0x82
+#define USBDEV_MAX_XFER 64
+
+#endif  /* usbdevs_h */
diff --git a/avrdude/usbtiny.c b/avrdude/usbtiny.c
new file mode 100644
index 00000000..a2e15b0c
--- /dev/null
+++ b/avrdude/usbtiny.c
@@ -0,0 +1,552 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2007 Dick Streefland, adapted for 5.4 by Limor Fried
+ *
+ * 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
+ */
+
+/*
+ * Driver for "usbtiny"-type programmers
+ * Please see http://www.xs4all.nl/~dicks/avr/usbtiny/
+ *        and http://www.ladyada.net/make/usbtinyisp/
+ * For example schematics and detailed documentation
+ */
+
+#include "ac_cfg.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "avrdude.h"
+#include "avr.h"
+#include "pgm.h"
+#include "usbtiny.h"
+
+#if defined(HAVE_LIBUSB)      // we use LIBUSB to talk to the board
+#include <usb.h>
+
+#ifndef HAVE_UINT_T
+typedef	unsigned int	uint_t;
+#endif
+#ifndef HAVE_ULONG_T
+typedef	unsigned long	ulong_t;
+#endif
+
+extern int avr_write_byte_default ( PROGRAMMER* pgm, AVRPART* p,
+				    AVRMEM* mem, ulong_t addr,
+				    unsigned char data );
+/*
+ * Private data for this programmer.
+ */
+struct pdata
+{
+  usb_dev_handle *usb_handle;
+  int sck_period;
+  int chunk_size;
+  int retries;
+};
+
+#define PDATA(pgm) ((struct pdata *)(pgm->cookie))
+
+// ----------------------------------------------------------------------
+
+static void usbtiny_setup(PROGRAMMER * pgm)
+{
+  if ((pgm->cookie = malloc(sizeof(struct pdata))) == 0) {
+    fprintf(stderr,
+	    "%s: usbtiny_setup(): Out of memory allocating private data\n",
+	    progname);
+    exit(1);
+  }
+  memset(pgm->cookie, 0, sizeof(struct pdata));
+}
+
+static void usbtiny_teardown(PROGRAMMER * pgm)
+{
+  free(pgm->cookie);
+}
+
+// Wrapper for simple usb_control_msg messages
+static int usb_control (PROGRAMMER * pgm,
+			unsigned int requestid, unsigned int val, unsigned int index )
+{
+  int nbytes;
+  nbytes = usb_control_msg( PDATA(pgm)->usb_handle,
+			    USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			    requestid,
+			    val, index,           // 2 bytes each of data
+			    NULL, 0,              // no data buffer in control messge
+			    USB_TIMEOUT );        // default timeout
+  if(nbytes < 0){
+    fprintf(stderr, "\n%s: error: usbtiny_transmit: %s\n", progname, usb_strerror());
+    return -1;
+  }
+
+  return nbytes;
+}
+
+// Wrapper for simple usb_control_msg messages to receive data from programmer
+static int usb_in (PROGRAMMER * pgm,
+		   unsigned int requestid, unsigned int val, unsigned int index,
+		   unsigned char* buffer, int buflen, int bitclk )
+{
+  int nbytes;
+  int timeout;
+  int i;
+
+  // calculate the amout of time we expect the process to take by
+  // figuring the bit-clock time and buffer size and adding to the standard USB timeout.
+  timeout = USB_TIMEOUT + (buflen * bitclk) / 1000;
+
+  for (i = 0; i < 10; i++) {
+    nbytes = usb_control_msg( PDATA(pgm)->usb_handle,
+			      USB_ENDPOINT_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			      requestid,
+			      val, index,
+			      (char *)buffer, buflen,
+			      timeout);
+    if (nbytes == buflen) {
+      return nbytes;
+    }
+    PDATA(pgm)->retries++;
+  }
+  fprintf(stderr, "\n%s: error: usbtiny_receive: %s (expected %d, got %d)\n",
+          progname, usb_strerror(), buflen, nbytes);
+  return -1;
+}
+
+// Report the number of retries, and reset the counter.
+static void check_retries (PROGRAMMER * pgm, const char* operation)
+{
+  if (PDATA(pgm)->retries > 0 && quell_progress < 2) {
+    printf("%s: %d retries during %s\n", progname,
+           PDATA(pgm)->retries, operation);
+  }
+  PDATA(pgm)->retries = 0;
+}
+
+// Wrapper for simple usb_control_msg messages to send data to programmer
+static int usb_out (PROGRAMMER * pgm,
+		    unsigned int requestid, unsigned int val, unsigned int index,
+		    unsigned char* buffer, int buflen, int bitclk )
+{
+  int nbytes;
+  int timeout;
+
+  // calculate the amout of time we expect the process to take by
+  // figuring the bit-clock time and buffer size and adding to the standard USB timeout.
+  timeout = USB_TIMEOUT + (buflen * bitclk) / 1000;
+
+  nbytes = usb_control_msg( PDATA(pgm)->usb_handle,
+			    USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+			    requestid,
+			    val, index,
+			    (char *)buffer, buflen,
+			    timeout);
+  if (nbytes != buflen) {
+    fprintf(stderr, "\n%s: error: usbtiny_send: %s (expected %d, got %d)\n",
+	    progname, usb_strerror(), buflen, nbytes);
+    return -1;
+  }
+
+  return nbytes;
+}
+
+// Sometimes we just need to know the SPI command for the part to perform
+// a function. Here we wrap this request for an operation so that we
+// can just specify the part and operation and it'll do the right stuff
+// to get the information from AvrDude and send to the USBtiny
+static int usbtiny_avr_op (PROGRAMMER * pgm, AVRPART * p,
+			   int op,
+			   unsigned char res[4])
+{
+  unsigned char	cmd[4];
+
+  if (p->op[op] == NULL) {
+    fprintf( stderr, "Operation %d not defined for this chip!\n", op );
+    return -1;
+  }
+  memset(cmd, 0, sizeof(cmd));
+  avr_set_bits(p->op[op], cmd);
+
+  return pgm->cmd(pgm, cmd, res);
+}
+
+// ----------------------------------------------------------------------
+
+/* Find a device with the correct VID/PID match for USBtiny */
+
+static	int	usbtiny_open(PROGRAMMER* pgm, char* name)
+{
+  struct usb_bus      *bus;
+  struct usb_device   *dev = 0;
+
+  usb_init();                    // initialize the libusb system
+  usb_find_busses();             // have libusb scan all the usb busses available
+  usb_find_devices();            // have libusb scan all the usb devices available
+
+  PDATA(pgm)->usb_handle = NULL;
+
+  // now we iterate through all the busses and devices
+  for ( bus = usb_busses; bus; bus = bus->next ) {
+    for	( dev = bus->devices; dev; dev = dev->next ) {
+      if (dev->descriptor.idVendor == USBTINY_VENDOR
+	  && dev->descriptor.idProduct == USBTINY_PRODUCT ) {   // found match?
+
+	PDATA(pgm)->usb_handle = usb_open(dev);           // attempt to connect to device
+
+	// wrong permissions or something?
+	if (!PDATA(pgm)->usb_handle) {
+	  fprintf(stderr, "%s: Warning: cannot open USB device: %s\n",
+		  progname, usb_strerror());
+	  continue;
+	}
+      }
+    }
+  }
+
+  if (!PDATA(pgm)->usb_handle) {
+    fprintf( stderr, "%s: Error: Could not find USBtiny device (0x%x/0x%x)\n",
+	     progname, USBTINY_VENDOR, USBTINY_PRODUCT );
+    return -1;
+  }
+
+  return 0;                  // If we got here, we must have found a good USB device
+}
+
+/* Clean up the handle for the usbtiny */
+static	void usbtiny_close ( PROGRAMMER* pgm )
+{
+  if (! PDATA(pgm)->usb_handle) {
+    return;                // not a valid handle, bail!
+  }
+  usb_close(PDATA(pgm)->usb_handle);   // ask libusb to clean up
+  PDATA(pgm)->usb_handle = NULL;
+}
+
+/* A simple calculator function determines the maximum size of data we can
+   shove through a USB connection without getting errors */
+static void usbtiny_set_chunk_size (PROGRAMMER * pgm, int period)
+{
+  PDATA(pgm)->chunk_size = CHUNK_SIZE;       // start with the maximum (default)
+  while	(PDATA(pgm)->chunk_size > 8 && period > 16) {
+    // Reduce the chunk size for a slow SCK to reduce
+    // the maximum time of a single USB transfer.
+    PDATA(pgm)->chunk_size >>= 1;
+    period >>= 1;
+  }
+}
+
+/* Given a SCK bit-clock speed (in useconds) we verify its an OK speed and tell the
+   USBtiny to update itself to the new frequency */
+static int usbtiny_set_sck_period (PROGRAMMER *pgm, double v)
+{
+  PDATA(pgm)->sck_period = (int)(v * 1e6 + 0.5);   // convert from us to 'int', the 0.5 is for rounding up
+
+  // Make sure its not 0, as that will confuse the usbtiny
+  if (PDATA(pgm)->sck_period < SCK_MIN)
+    PDATA(pgm)->sck_period = SCK_MIN;
+
+  // We can't go slower, due to the byte-size of the clock variable
+  if  (PDATA(pgm)->sck_period > SCK_MAX)
+    PDATA(pgm)->sck_period = SCK_MAX;
+
+  if (verbose) {
+    printf( "%s: Setting SCK period to %d usec\n", progname,
+	    PDATA(pgm)->sck_period );
+  }
+
+  // send the command to the usbtiny device.
+  // MEME: for at90's fix resetstate?
+  if (usb_control(pgm, USBTINY_POWERUP, PDATA(pgm)->sck_period, RESET_LOW) < 0)
+    return -1;
+
+  // with the new speed, we'll have to update how much data we send per usb transfer
+  usbtiny_set_chunk_size(pgm, PDATA(pgm)->sck_period);
+  return 0;
+}
+
+
+static int usbtiny_initialize (PROGRAMMER *pgm, AVRPART *p )
+{
+  unsigned char res[4];        // store the response from usbtinyisp
+
+  // Check for bit-clock and tell the usbtiny to adjust itself
+  if (pgm->bitclock > 0.0) {
+    // -B option specified: convert to valid range for sck_period
+    usbtiny_set_sck_period(pgm, pgm->bitclock);
+  } else {
+    // -B option not specified: use default
+    PDATA(pgm)->sck_period = SCK_DEFAULT;
+    if	(verbose) {
+      printf( "%s: Using SCK period of %d usec\n",
+	      progname, PDATA(pgm)->sck_period );
+    }
+    if (usb_control(pgm,  USBTINY_POWERUP,
+		    PDATA(pgm)->sck_period, RESET_LOW ) < 0)
+      return -1;
+    usbtiny_set_chunk_size(pgm, PDATA(pgm)->sck_period);
+  }
+
+  // Let the device wake up.
+  usleep(50000);
+
+  // Attempt to use the underlying avrdude methods to connect (MEME: is this kosher?)
+  if (! usbtiny_avr_op(pgm, p, AVR_OP_PGM_ENABLE, res)) {
+    // no response, RESET and try again
+    if (usb_control(pgm, USBTINY_POWERUP,
+		    PDATA(pgm)->sck_period, RESET_HIGH) < 0 ||
+	usb_control(pgm, USBTINY_POWERUP,
+		    PDATA(pgm)->sck_period, RESET_LOW) < 0)
+      return -1;
+    usleep(50000);
+    if	( ! usbtiny_avr_op( pgm, p, AVR_OP_PGM_ENABLE, res)) {
+      // give up
+      return -1;
+    }
+  }
+  return 0;
+}
+
+/* Tell the USBtiny to release the output pins, etc */
+static void usbtiny_powerdown(PROGRAMMER * pgm)
+{
+  if (!PDATA(pgm)->usb_handle) {
+    return;                 // wasn't connected in the first place
+  }
+  usb_control(pgm, USBTINY_POWERDOWN, 0, 0);      // Send USB control command to device
+}
+
+/* Send a 4-byte SPI command to the USBtinyISP for execution
+   This procedure is used by higher-level Avrdude procedures */
+static int usbtiny_cmd(PROGRAMMER * pgm, unsigned char cmd[4], unsigned char res[4])
+{
+  int nbytes;
+
+  // Make sure its empty so we don't read previous calls if it fails
+  memset(res, '\0', 4 );
+
+  nbytes = usb_in( pgm, USBTINY_SPI,
+		   (cmd[1] << 8) | cmd[0],  // convert to 16-bit words
+		   (cmd[3] << 8) | cmd[2],  //  "
+			res, 4, 8 * PDATA(pgm)->sck_period );
+  if (nbytes < 0)
+    return -1;
+  check_retries(pgm, "SPI command");
+  if (verbose > 1) {
+    // print out the data we sent and received
+    printf( "CMD: [%02x %02x %02x %02x] [%02x %02x %02x %02x]\n",
+	    cmd[0], cmd[1], cmd[2], cmd[3],
+	    res[0], res[1], res[2], res[3] );
+  }
+  return ((nbytes == 4) &&      // should have read 4 bytes
+	  res[2] == cmd[1]);              // AVR's do a delayed-echo thing
+}
+
+/* Send the chip-erase command */
+static int usbtiny_chip_erase(PROGRAMMER * pgm, AVRPART * p)
+{
+  unsigned char res[4];
+
+  if (p->op[AVR_OP_CHIP_ERASE] == NULL) {
+    fprintf(stderr, "Chip erase instruction not defined for part \"%s\"\n",
+            p->desc);
+    return -1;
+  }
+
+  // get the command for erasing this chip and transmit to avrdude
+  if (! usbtiny_avr_op( pgm, p, AVR_OP_CHIP_ERASE, res )) {
+    return -1;
+  }
+  usleep( p->chip_erase_delay );
+
+  // prepare for further instruction
+  pgm->initialize(pgm, p);
+
+  return 0;
+}
+
+// These are required functions but don't actually do anything
+static	void	usbtiny_enable ( PROGRAMMER* pgm ) {}
+
+static void usbtiny_disable ( PROGRAMMER* pgm ) {}
+
+
+/* To speed up programming and reading, we do a 'chunked' read.
+ *  We request just the data itself and the USBtiny uses the SPI function
+ *  given to read in the data. Much faster than sending a 4-byte SPI request
+ *  per byte
+*/
+static int usbtiny_paged_load (PROGRAMMER * pgm, AVRPART * p, AVRMEM* m,
+				    int page_size, int n_bytes )
+{
+  int i;
+  int chunk;
+  int function;
+
+
+  // First determine what we're doing
+  if (strcmp( m->desc, "flash" ) == 0) {
+    function = USBTINY_FLASH_READ;
+  } else {
+    function = USBTINY_EEPROM_READ;
+  }
+
+  for (i = 0; i < n_bytes; i += chunk) {
+    chunk = PDATA(pgm)->chunk_size;         // start with the maximum chunk size possible
+
+    // If we want to xmit less than a chunk, thats OK
+    if	(chunk > n_bytes-i)
+      chunk = n_bytes - i;
+
+    // Send the chunk of data to the USBtiny with the function we want
+    // to perform
+    if (usb_in(pgm,
+	       function,          // EEPROM or flash
+	       0,                 // delay between SPI commands
+	       i,                 // index
+	       m->buf + i,        // pointer to where we store data
+	       chunk,             // number of bytes
+	       32 * PDATA(pgm)->sck_period)  // each byte gets turned into a 4-byte SPI cmd
+	< 0) {
+                              // usb_in() multiplies this per byte.
+      return -1;
+    }
+
+    // Tell avrdude how we're doing to provide user feedback
+    report_progress(i + chunk, n_bytes, NULL );
+  }
+
+  check_retries(pgm, "read");
+  return n_bytes;
+}
+
+/* To speed up programming and reading, we do a 'chunked' write.
+ *  We send just the data itself and the USBtiny uses the SPI function
+ *  given to write the data. Much faster than sending a 4-byte SPI request
+ *  per byte.
+*/
+static int usbtiny_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m,
+			       int page_size, int n_bytes)
+{
+  int i;
+  int chunk;        // Size of data to write at once
+  int next;
+  int function;     // which SPI command to use
+  int delay;        // delay required between SPI commands
+
+  // First determine what we're doing
+  if (strcmp( m->desc, "flash" ) == 0) {
+    function = USBTINY_FLASH_WRITE;
+  } else {
+    function = USBTINY_EEPROM_WRITE;
+  }
+
+  delay = 0;
+  if (! m->paged) {
+    // Does this chip not support paged writes?
+    i = (m->readback[1] << 8) | m->readback[0];
+    if (usb_control(pgm, USBTINY_POLL_BYTES, i, 0 ) < 0)
+      return -1;
+    delay = m->max_write_delay;
+  }
+
+  for (i=0; i < n_bytes; i=next) {
+    // start with the max chunk size
+    chunk = PDATA(pgm)->chunk_size;
+
+    // we can only write a page at a time anyways
+    if (m->paged && chunk > page_size)
+      chunk = page_size;
+
+    // if there's less data remaining than one chunk
+    if (chunk > n_bytes-i)
+      chunk = n_bytes - i;
+
+    if (usb_out(pgm,
+		function,       // Flash or EEPROM
+		delay,          // How much to wait between each byte
+		i,              // Index of data
+		m->buf + i,     // Pointer to data
+		chunk,          // Number of bytes to write
+		32 * PDATA(pgm)->sck_period + delay  // each byte gets turned into a
+	                             // 4-byte SPI cmd  usb_out() multiplies
+	                             // this per byte. Then add the cmd-delay
+		) < 0) {
+      return -1;
+    }
+
+    next = i + chunk;       // Calculate what address we're at now
+    if (m->paged
+	&& ((next % page_size) == 0 || next == n_bytes) ) {
+      // If we're at a page boundary, send the SPI command to flush it.
+      avr_write_page(pgm, p, m, (unsigned long) i);
+    }
+
+    report_progress( next, n_bytes, NULL );
+  }
+  return n_bytes;
+}
+
+extern void usbtiny_initpgm ( PROGRAMMER* pgm )
+{
+  strcpy(pgm->type, "USBtiny");
+
+  /* Mandatory Functions */
+  pgm->initialize	= usbtiny_initialize;
+  pgm->enable	        = usbtiny_enable;
+  pgm->disable	        = usbtiny_disable;
+  pgm->program_enable	= NULL;
+  pgm->chip_erase	= usbtiny_chip_erase;
+  pgm->cmd		= usbtiny_cmd;
+  pgm->open		= usbtiny_open;
+  pgm->close		= usbtiny_close;
+  pgm->read_byte        = avr_read_byte_default;
+  pgm->write_byte       = avr_write_byte_default;
+
+  /* Optional Functions */
+  pgm->powerup	        = NULL;
+  pgm->powerdown	= usbtiny_powerdown;
+  pgm->paged_load	= usbtiny_paged_load;
+  pgm->paged_write	= usbtiny_paged_write;
+  pgm->set_sck_period	= usbtiny_set_sck_period;
+  pgm->setup            = usbtiny_setup;
+  pgm->teardown         = usbtiny_teardown;
+}
+
+#else  /* !HAVE_LIBUSB */
+
+// Give a proper error if we were not compiled with libusb
+
+static int usbtiny_nousb_open(struct programmer_t *pgm, char * name)
+{
+  fprintf(stderr, "%s: error: no usb support. Please compile again with libusb installed.\n",
+	  progname);
+
+  return -1;
+}
+
+void usbtiny_initpgm(PROGRAMMER * pgm)
+{
+  strcpy(pgm->type, "usbtiny");
+
+  pgm->open = usbtiny_nousb_open;
+}
+
+#endif /* HAVE_LIBUSB */
diff --git a/avrdude/usbtiny.h b/avrdude/usbtiny.h
new file mode 100644
index 00000000..77f9a42e
--- /dev/null
+++ b/avrdude/usbtiny.h
@@ -0,0 +1,76 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2007 Limor Fried
+ *
+ * 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
+ */
+
+
+#ifndef usbtiny_h
+#define usbtiny_h
+
+#include "avrpart.h"
+
+// these are specifically assigned to USBtiny,
+// if you need your own VID and PIDs you can get them for cheap from
+// www.mecanique.co.uk so please don't reuse these. Thanks!
+#define USBTINY_VENDOR  0x1781
+#define USBTINY_PRODUCT 0x0C9F
+
+// Generic requests to the USBtiny
+#define	USBTINY_ECHO 	     0      // echo test
+#define	USBTINY_READ         1	    // read byte (wIndex:address)
+#define	USBTINY_WRITE 	     2	    // write byte (wIndex:address, wValue:value)
+#define	USBTINY_CLR          3	    // clear bit (wIndex:address, wValue:bitno)
+#define	USBTINY_SET          4	    // set bit (wIndex:address, wValue:bitno)
+
+// Programming requests
+#define	USBTINY_POWERUP      5	    // apply power (wValue:SCK-period, wIndex:RESET)
+#define	USBTINY_POWERDOWN    6	    // remove power from chip
+#define	USBTINY_SPI          7	    // issue SPI command (wValue:c1c0, wIndex:c3c2)
+#define	USBTINY_POLL_BYTES   8	    // set poll bytes for write (wValue:p1p2)
+#define	USBTINY_FLASH_READ   9	    // read flash (wIndex:address)
+#define	USBTINY_FLASH_WRITE  10	    // write flash (wIndex:address, wValue:timeout)
+#define	USBTINY_EEPROM_READ  11	    // read eeprom (wIndex:address)
+#define	USBTINY_EEPROM_WRITE 12	    // write eeprom (wIndex:address, wValue:timeout)
+
+
+
+// Flags to indicate how to set RESET on power up
+#define	RESET_LOW	0
+#define	RESET_HIGH	1
+
+// The SCK speed can be set by avrdude, to allow programming of slow-clocked parts
+#define	SCK_MIN		1	// usec delay (target clock >= 4 MHz)
+#define	SCK_MAX		250	// usec (target clock >= 16 KHz)
+#define	SCK_DEFAULT	10	// usec (target clock >= 0.4 MHz)
+
+// How much data, max, do we want to send in one USB packet?
+#define	CHUNK_SIZE	128	// must be power of 2 less than 256
+
+// The default USB Timeout
+#define	USB_TIMEOUT	500	// msec
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void usbtiny_initpgm (PROGRAMMER * pgm);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* usbtiny_h */
diff --git a/avrdude/windows/.cvsignore b/avrdude/windows/.cvsignore
new file mode 100644
index 00000000..601c4fbf
--- /dev/null
+++ b/avrdude/windows/.cvsignore
@@ -0,0 +1,4 @@
+.cvsignore
+.deps
+Makefile
+Makefile.in
diff --git a/avrdude/windows/Makefile.am b/avrdude/windows/Makefile.am
new file mode 100644
index 00000000..875e0440
--- /dev/null
+++ b/avrdude/windows/Makefile.am
@@ -0,0 +1,60 @@
+#
+# avrdude - A Downloader/Uploader for AVR device programmers
+# Copyright (C) 2003  Theodore A. Roth  <troth@openavr.org>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+#
+# $Id$
+#
+
+#
+# This Makefile will only be used on windows based systems.
+#
+
+local_install_list = \
+	giveio.sys \
+	install_giveio.bat \
+	remove_giveio.bat \
+	status_giveio.bat
+
+EXTRA_DIST   = \
+	giveio.c \
+	$(local_install_list)
+
+bin_PROGRAMS = loaddrv
+
+loaddrv_LDFLAGS = -mno-cygwin
+
+loaddrv_SOURCES = \
+	loaddrv.c \
+	loaddrv.h
+
+install-exec-local:
+	$(mkinstalldirs) $(DESTDIR)$(bindir)
+	@list='$(local_install_list)'; for file in $$list; do \
+		echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) \
+			$(srcdir)/$$file $(DESTDIR)$(bindir)/$$file"; \
+		$(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $(srcdir)/$$file \
+			$(DESTDIR)$(bindir)/$$file; \
+	done
+
+uninstall-local:
+	@for file in $(local_install_list); do \
+		echo " rm -f $(DESTDIR)$(bindir)/$$file"; \
+		rm -f $(DESTDIR)$(bindir)/$$file; \
+	done
+
diff --git a/avrdude/windows/giveio.c b/avrdude/windows/giveio.c
new file mode 100644
index 00000000..f752a293
--- /dev/null
+++ b/avrdude/windows/giveio.c
@@ -0,0 +1,168 @@
+/*********************************************************************
+
+Author:     Dale Roberts
+Date:       8/30/95
+Program:    GIVEIO.SYS
+Compile:    Use DDK BUILD facility
+
+Purpose:    Give direct port I/O access to a user mode process.
+
+*********************************************************************/
+#include <ntddk.h>
+
+/*
+ *  The name of our device driver.
+ */
+#define DEVICE_NAME_STRING	L"giveio"
+
+/*
+ *  This is the "structure" of the IOPM.  It is just a simple
+ * character array of length 0x2000.
+ *
+ *  This holds 8K * 8 bits -> 64K bits of the IOPM, which maps the
+ * entire 64K I/O space of the x86 processor.  Any 0 bits will give
+ * access to the corresponding port for user mode processes.  Any 1
+ * bits will disallow I/O access to the corresponding port.
+ */
+#define	IOPM_SIZE	0x2000
+typedef UCHAR IOPM[IOPM_SIZE];
+
+/*
+ *  This will hold simply an array of 0's which will be copied
+ * into our actual IOPM in the TSS by Ke386SetIoAccessMap().
+ * The memory is allocated at driver load time.
+ */
+IOPM *IOPM_local = 0;
+
+/*
+ *  These are the two undocumented calls that we will use to give
+ * the calling process I/O access.
+ *
+ *  Ke386IoSetAccessMap() copies the passed map to the TSS.
+ *
+ *  Ke386IoSetAccessProcess() adjusts the IOPM offset pointer so that
+ * the newly copied map is actually used.  Otherwise, the IOPM offset
+ * points beyond the end of the TSS segment limit, causing any I/O
+ * access by the user mode process to generate an exception.
+ */
+void Ke386SetIoAccessMap(int, IOPM *);
+void Ke386QueryIoAccessMap(int, IOPM *);
+void Ke386IoSetAccessProcess(PEPROCESS, int);
+
+/*********************************************************************
+  Release any allocated objects.
+*********************************************************************/
+VOID GiveioUnload(IN PDRIVER_OBJECT DriverObject)
+{
+	WCHAR DOSNameBuffer[] = L"\\DosDevices\\" DEVICE_NAME_STRING;
+	UNICODE_STRING uniDOSString;
+
+	if(IOPM_local)
+		MmFreeNonCachedMemory(IOPM_local, sizeof(IOPM));
+
+	RtlInitUnicodeString(&uniDOSString, DOSNameBuffer);
+	IoDeleteSymbolicLink (&uniDOSString);
+	IoDeleteDevice(DriverObject->DeviceObject);
+}
+
+/*********************************************************************
+  Set the IOPM (I/O permission map) of the calling process so that it
+is given full I/O access.  Our IOPM_local[] array is all zeros, so
+the IOPM will be all zeros.  If OnFlag is 1, the process is given I/O
+access.  If it is 0, access is removed.
+*********************************************************************/
+VOID SetIOPermissionMap(int OnFlag)
+{
+	Ke386IoSetAccessProcess(PsGetCurrentProcess(), OnFlag);
+	Ke386SetIoAccessMap(1, IOPM_local);
+}
+
+void GiveIO(void)
+{
+	SetIOPermissionMap(1);
+}
+
+/*********************************************************************
+  Service handler for a CreateFile() user mode call.
+
+  This routine is entered in the driver object function call table by
+the DriverEntry() routine.  When the user mode application calls
+CreateFile(), this routine gets called while still in the context of
+the user mode application, but with the CPL (the processor's Current
+Privelege Level) set to 0.  This allows us to do kernel mode
+operations.  GiveIO() is called to give the calling process I/O
+access.  All the user mode application needs do to obtain I/O access
+is open this device with CreateFile().  No other operations are
+required.
+*********************************************************************/
+NTSTATUS GiveioCreateDispatch(
+    IN  PDEVICE_OBJECT  DeviceObject,
+    IN  PIRP            Irp
+    )
+{
+	GiveIO();			// give the calling process I/O access
+
+    Irp->IoStatus.Information = 0;
+    Irp->IoStatus.Status = STATUS_SUCCESS;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    return STATUS_SUCCESS;
+}
+
+/*********************************************************************
+  Driver Entry routine.
+
+  This routine is called only once after the driver is initially
+loaded into memory.  It allocates everything necessary for the
+driver's operation.  In our case, it allocates memory for our IOPM
+array, and creates a device which user mode applications can open.
+It also creates a symbolic link to the device driver.  This allows
+a user mode application to access our driver using the \\.\giveio
+notation.
+*********************************************************************/
+NTSTATUS DriverEntry(
+    IN PDRIVER_OBJECT DriverObject,
+    IN PUNICODE_STRING RegistryPath
+    )
+{
+	PDEVICE_OBJECT deviceObject;
+	NTSTATUS status;
+	WCHAR NameBuffer[] = L"\\Device\\" DEVICE_NAME_STRING;
+	WCHAR DOSNameBuffer[] = L"\\DosDevices\\" DEVICE_NAME_STRING;
+	UNICODE_STRING uniNameString, uniDOSString;
+
+	//
+	//  Allocate a buffer for the local IOPM and zero it.
+	//
+	IOPM_local = MmAllocateNonCachedMemory(sizeof(IOPM));
+	if(IOPM_local == 0)
+		return STATUS_INSUFFICIENT_RESOURCES;
+	RtlZeroMemory(IOPM_local, sizeof(IOPM));
+
+	//
+	//  Set up device driver name and device object.
+	//
+	RtlInitUnicodeString(&uniNameString, NameBuffer);
+	RtlInitUnicodeString(&uniDOSString, DOSNameBuffer);
+
+	status = IoCreateDevice(DriverObject, 0,
+					&uniNameString,
+					FILE_DEVICE_UNKNOWN,
+					0, FALSE, &deviceObject);
+
+	if(!NT_SUCCESS(status))
+		return status;
+
+	status = IoCreateSymbolicLink (&uniDOSString, &uniNameString);
+
+	if (!NT_SUCCESS(status))
+		return status;
+
+    //
+    //  Initialize the Driver Object with driver's entry points.
+	// All we require are the Create and Unload operations.
+    //
+    DriverObject->MajorFunction[IRP_MJ_CREATE] = GiveioCreateDispatch;
+	DriverObject->DriverUnload = GiveioUnload;
+    return STATUS_SUCCESS;
+}
+
diff --git a/avrdude/windows/giveio.sys b/avrdude/windows/giveio.sys
new file mode 100644
index 00000000..62a0cb66
Binary files /dev/null and b/avrdude/windows/giveio.sys differ
diff --git a/avrdude/windows/install_giveio.bat b/avrdude/windows/install_giveio.bat
new file mode 100755
index 00000000..4a02b093
--- /dev/null
+++ b/avrdude/windows/install_giveio.bat
@@ -0,0 +1,34 @@
+@set DIRVERNAME=giveio
+@set DIRVERFILE=%DIRVERNAME%.sys
+
+@echo Copying the driver to the windows directory
+@echo target file: %WINDIR%\%DIRVERFILE%
+@copy %DIRVERFILE% %WINDIR%\%DIRVERFILE%
+
+@echo Remove a running service if needed...
+@loaddrv stop %DIRVERNAME% >NUL
+@if errorlevel 2 goto install
+
+@loaddrv remove %DIRVERNAME% >NUL
+@if errorlevel 1 goto install
+
+:install
+@echo Installing Windows NT/2k/XP driver: %DIRVERNAME%
+
+@loaddrv install %DIRVERNAME% %WINDIR%\%DIRVERFILE%
+@if errorlevel 3 goto error
+
+@loaddrv start %DIRVERNAME%
+@if errorlevel 1 goto error
+
+@loaddrv starttype %DIRVERNAME% auto
+@if errorlevel 1 goto error
+
+@echo Success
+@goto exit
+
+:error
+@echo ERROR: Installation of %DIRVERNAME% failed
+
+:exit
+
diff --git a/avrdude/windows/loaddrv.c b/avrdude/windows/loaddrv.c
new file mode 100644
index 00000000..ca92a2a1
--- /dev/null
+++ b/avrdude/windows/loaddrv.c
@@ -0,0 +1,460 @@
+// loaddrv.c - Dynamic driver install/start/stop/remove
+// based on Paula Tomlinson's LOADDRV program. 
+// She describes it in her May 1995 article in Windows/DOS Developer's
+// Journal (now Windows Developer's Journal).
+// Modified by Chris Liechti <cliechti@gmx.net>
+// I removed the old/ugly dialog, it now accepts command line options and
+// prints error messages with textual description from the OS.
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "loaddrv.h"
+
+// globals
+SC_HANDLE hSCMan = NULL;
+
+//get ext messages for windows error codes:
+void DisplayErrorText(DWORD dwLastError) {
+    LPSTR MessageBuffer;
+    DWORD dwBufferLength;
+    
+    DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
+        FORMAT_MESSAGE_IGNORE_INSERTS |
+        FORMAT_MESSAGE_FROM_SYSTEM;
+    
+    dwBufferLength = FormatMessageA(
+        dwFormatFlags,
+        NULL, // module to get message from (NULL == system)
+        dwLastError,
+        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
+        (LPSTR) &MessageBuffer,
+        0,
+        NULL
+    );
+    if (dwBufferLength) {
+        // Output message
+        puts(MessageBuffer);
+        // Free the buffer allocated by the system.
+        LocalFree(MessageBuffer);
+    }
+}
+
+int exists(char *filename) {
+    FILE * pFile;
+    pFile = fopen(filename, "r");
+    return pFile != NULL;
+}
+
+void usage(void) {
+    printf("USGAE: loaddrv command drivername [args...]\n\n"
+           "NT/2k/XP Driver and Service modification tool.\n"
+           "(C)2002 Chris Liechti <cliechti@gmx.net>\n\n"
+           "Suported commands:\n\n"
+           "  install [fullpathforinstall]\n"
+           "      Install new service. Loaded from given path. If path is not present,\n"
+           "      the local directory is searched for a .sys file. If the service\n"
+           "      already exists, it must be removed first.\n"
+           "  start\n"
+           "      Start service. It must be installed in advance.\n"
+           "  stop\n"
+           "      Stop service.\n"
+           "  remove\n"
+           "      Remove service. It must be stopped in advance.\n"
+           "  status\n"
+           "      Show status information about service.\n"
+           "  starttype auto|manual|system|disable\n"
+           "      Change startup type to the given type.\n"
+    );
+}
+
+int main(int argc, char *argv[]) {
+    DWORD status = 0;
+    int level = 0;
+    if (argc < 3) {
+        usage();
+        exit(1);
+    }
+    LoadDriverInit();
+    if (strcmp(argv[1], "start") == 0) {
+        printf("starting %s... ", argv[2]);
+        status = DriverStart(argv[2]);
+        if ( status != OKAY) {
+            printf("start failed (status %ld):\n", status);
+            level = 1;
+        } else {
+            printf("ok.\n");
+        }
+    } else if (strcmp(argv[1], "stop") == 0) {
+        printf("stoping %s... ", argv[2]);
+        status = DriverStop(argv[2]);
+        if ( status != OKAY) {
+            printf("stop failed (status %ld):\n", status);
+            level = 1;
+        } else {
+            printf("ok.\n");
+        }
+    } else if (strcmp(argv[1], "install") == 0) {
+        char path[MAX_PATH*2];
+        if (argc<4) {
+            char cwd[MAX_PATH];
+            getcwd(cwd, sizeof cwd);
+            sprintf(path, "%s\\%s.sys", cwd, argv[2]);
+        } else {
+            strncpy(path, argv[3], MAX_PATH);
+        }
+        if (exists(path)) {
+            printf("installing %s from %s... ", argv[2], path);
+            status = DriverInstall(path, argv[2]);
+            if ( status != OKAY) {
+                printf("install failed (status %ld):\n", status);
+                level = 2;
+            } else {
+                printf("ok.\n");
+            }
+        } else {
+            printf("install failed, file not found: %s\n", path);
+            level = 1;
+        }
+    } else if (strcmp(argv[1], "remove") == 0) {
+        printf("removing %s... ", argv[2]);
+        status = DriverRemove(argv[2]);
+        if ( status != OKAY) {
+            printf("remove failed (status %ld):\n", status);
+            level = 1;
+        } else {
+            printf("ok.\n");
+        }
+    } else if (strcmp(argv[1], "status") == 0) {
+        printf("status of %s:\n", argv[2]);
+        status = DriverStatus(argv[2]);
+        if ( status != OKAY) {
+            printf("stat failed (status %ld):\n", status);
+            level = 1;
+        } else {
+            printf("ok.\n");
+        }
+    } else if (strcmp(argv[1], "starttype") == 0) {
+        if (argc < 4) {
+            printf("Error: need start type (string) as argument.\n");
+            level = 2;
+        } else {
+            DWORD type = 0;
+            printf("set start type of %s to %s... ", argv[2], argv[3]);
+            if (strcmp(argv[1], "boot") == 0) {
+                type = SERVICE_BOOT_START;
+            } else if (strcmp(argv[3], "system") == 0) {
+                type = SERVICE_SYSTEM_START;
+            } else if (strcmp(argv[3], "auto") == 0) {
+                type = SERVICE_AUTO_START;
+            } else if (strcmp(argv[3], "manual") == 0) {
+                type = SERVICE_DEMAND_START;
+            } else if (strcmp(argv[3], "disabled") == 0) {
+                type = SERVICE_DISABLED;
+            } else {
+                printf("unknown type\n");
+                level = 1;
+            }
+            if (level == 0) {
+                status = DriverStartType(argv[2], type);
+                if ( status != OKAY) {
+                    printf("set start type failed (status %ld):\n", status);
+                    level = 1;
+                } else {
+                    printf("ok.\n");
+                }
+            }
+        }
+    } else {
+        usage();
+        level = 1;
+    }
+    if (status) DisplayErrorText(status);
+    LoadDriverCleanup();
+    exit(level);
+    return 0;
+}
+
+
+DWORD LoadDriverInit(void) {
+    // connect to local service control manager
+    if ((hSCMan = OpenSCManager(NULL, NULL, 
+        SC_MANAGER_ALL_ACCESS)) == NULL) {
+        return -1;
+    }
+    return OKAY;
+}
+
+void LoadDriverCleanup(void) {
+    if (hSCMan != NULL) CloseServiceHandle(hSCMan);
+}
+
+/**-----------------------------------------------------**/
+DWORD DriverInstall(LPSTR lpPath, LPSTR lpDriver) {
+   BOOL dwStatus = OKAY;
+   SC_HANDLE hService = NULL;
+
+   // add to service control manager's database
+   if ((hService = CreateService(hSCMan, lpDriver, 
+      lpDriver, SERVICE_ALL_ACCESS, SERVICE_KERNEL_DRIVER,
+      SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, lpPath, 
+      NULL, NULL, NULL, NULL, NULL)) == NULL)
+         dwStatus = GetLastError();
+   else CloseServiceHandle(hService);
+
+   return dwStatus;
+} // DriverInstall
+
+/**-----------------------------------------------------**/
+DWORD DriverStart(LPSTR lpDriver) {
+   BOOL dwStatus = OKAY;
+   SC_HANDLE hService = NULL;
+
+   // get a handle to the service
+   if ((hService = OpenService(hSCMan, lpDriver, 
+      SERVICE_ALL_ACCESS)) != NULL) 
+   {
+      // start the driver
+      if (!StartService(hService, 0, NULL))
+         dwStatus = GetLastError();
+   } else dwStatus = GetLastError();
+
+   if (hService != NULL) CloseServiceHandle(hService);
+   return dwStatus;
+} // DriverStart
+
+/**-----------------------------------------------------**/
+DWORD DriverStop(LPSTR lpDriver)
+{
+   BOOL dwStatus = OKAY;
+   SC_HANDLE hService = NULL;
+   SERVICE_STATUS serviceStatus;
+
+   // get a handle to the service
+   if ((hService = OpenService(hSCMan, lpDriver, 
+      SERVICE_ALL_ACCESS)) != NULL) 
+   {
+      // stop the driver
+      if (!ControlService(hService, SERVICE_CONTROL_STOP,
+         &serviceStatus))
+            dwStatus = GetLastError();
+   } else dwStatus = GetLastError();
+
+   if (hService != NULL) CloseServiceHandle(hService);
+   return dwStatus;
+} // DriverStop
+
+/**-----------------------------------------------------**/
+DWORD DriverRemove(LPSTR lpDriver)
+{
+   BOOL dwStatus = OKAY;
+   SC_HANDLE hService = NULL;
+
+   // get a handle to the service
+   if ((hService = OpenService(hSCMan, lpDriver, 
+      SERVICE_ALL_ACCESS)) != NULL) 
+   {  // remove the driver
+      if (!DeleteService(hService))
+         dwStatus = GetLastError();
+   } else dwStatus = GetLastError();
+
+   if (hService != NULL) CloseServiceHandle(hService);
+   return dwStatus;
+} // DriverRemove
+
+/**-----------------------------------------------------**/
+////extensions by Lch
+/**-----------------------------------------------------**/
+DWORD DriverStatus(LPSTR lpDriver) {
+    BOOL dwStatus = OKAY;
+    SC_HANDLE hService = NULL;
+    DWORD dwBytesNeeded;
+
+    // get a handle to the service
+    if ((hService = OpenService(hSCMan, lpDriver, 
+                                SERVICE_ALL_ACCESS)) != NULL) 
+    {
+        LPQUERY_SERVICE_CONFIG lpqscBuf;
+        //~ LPSERVICE_DESCRIPTION lpqscBuf2;
+        // Allocate a buffer for the configuration information. 
+        if ((lpqscBuf = (LPQUERY_SERVICE_CONFIG) LocalAlloc( 
+            LPTR, 4096)) != NULL)
+        {
+            //~ if ((lpqscBuf2 = (LPSERVICE_DESCRIPTION) LocalAlloc( 
+                //~ LPTR, 4096)) != NULL)
+            {
+                // Get the configuration information. 
+                if (QueryServiceConfig(
+                        hService,
+                        lpqscBuf,
+                        4096,
+                        &dwBytesNeeded) //&&
+                    //~ QueryServiceConfig2( 
+                        //~ hService,
+                        //~ SERVICE_CONFIG_DESCRIPTION,
+                        //~ lpqscBuf2,
+                        //~ 4096, 
+                        //~ &dwBytesNeeded
+                )
+                {
+                    // Print the configuration information. 
+                    printf("Type:           [0x%02lx] ", lpqscBuf->dwServiceType);
+                    switch (lpqscBuf->dwServiceType) {
+                        case SERVICE_WIN32_OWN_PROCESS:
+                            printf("The service runs in its own process.");
+                            break;
+                        case SERVICE_WIN32_SHARE_PROCESS:
+                            printf("The service shares a process with other services.");
+                            break;
+                        case SERVICE_KERNEL_DRIVER:
+                            printf("Kernel driver.");
+                            break;
+                        case SERVICE_FILE_SYSTEM_DRIVER:
+                            printf("File system driver.");
+                            break;
+                        case SERVICE_INTERACTIVE_PROCESS:
+                            printf("The service can interact with the desktop.");
+                            break;
+                        default:
+                            printf("Unknown type.");
+                    }
+                    printf("\nStart Type:     [0x%02lx] ", lpqscBuf->dwStartType); 
+                    switch (lpqscBuf->dwStartType) {
+                        case SERVICE_BOOT_START:
+                            printf("Boot");
+                            break;
+                        case SERVICE_SYSTEM_START:
+                            printf("System");
+                            break;
+                        case SERVICE_AUTO_START:
+                            printf("Automatic");
+                            break;
+                        case SERVICE_DEMAND_START:
+                            printf("Manual");
+                            break;
+                        case SERVICE_DISABLED:
+                            printf("Disabled");
+                            break;
+                        default:
+                            printf("Unknown.");
+                    }
+                    printf("\nError Control:  [0x%02lx] ", lpqscBuf->dwErrorControl); 
+                    switch (lpqscBuf->dwErrorControl) {
+                        case SERVICE_ERROR_IGNORE:
+                            printf("IGNORE: Ignore.");
+                            break;
+                        case SERVICE_ERROR_NORMAL:
+                            printf("NORMAL: Display a message box.");
+                            break;
+                        case SERVICE_ERROR_SEVERE:
+                            printf("SEVERE: Restart with last-known-good config.");
+                            break;
+                        case SERVICE_ERROR_CRITICAL:
+                            printf("CRITICAL: Restart w/ last-known-good config.");
+                            break;
+                        default:
+                            printf("Unknown.");
+                    }
+                    printf("\nBinary path:    %s\n", lpqscBuf->lpBinaryPathName); 
+                    
+                    if (lpqscBuf->lpLoadOrderGroup != NULL) 
+                        printf("Load order grp: %s\n", lpqscBuf->lpLoadOrderGroup); 
+                    if (lpqscBuf->dwTagId != 0) 
+                        printf("Tag ID:         %ld\n", lpqscBuf->dwTagId); 
+                    if (lpqscBuf->lpDependencies != NULL) 
+                        printf("Dependencies:   %s\n", lpqscBuf->lpDependencies); 
+                    if (lpqscBuf->lpServiceStartName != NULL) 
+                        printf("Start Name:     %s\n", lpqscBuf->lpServiceStartName); 
+                    //~ if (lpqscBuf2->lpDescription != NULL) 
+                        //~ printf("Description:    %s\n", lpqscBuf2->lpDescription); 
+                }
+                //~ LocalFree(lpqscBuf2);
+            }
+            LocalFree(lpqscBuf);
+        } else {
+            dwStatus = GetLastError();
+        }
+    } else {
+        dwStatus = GetLastError();
+    }
+
+   if (hService != NULL) CloseServiceHandle(hService);
+   return dwStatus;
+} // DriverStatus
+
+/**-----------------------------------------------------**/
+DWORD DriverStartType(LPSTR lpDriver, DWORD dwStartType) {
+    BOOL dwStatus = OKAY;
+    SC_HANDLE hService = NULL;
+
+    SC_LOCK sclLock;
+    LPQUERY_SERVICE_LOCK_STATUS lpqslsBuf;
+    DWORD dwBytesNeeded;
+    
+    // Need to acquire database lock before reconfiguring.
+    sclLock = LockServiceDatabase(hSCMan);
+
+    // If the database cannot be locked, report the details.
+    if (sclLock == NULL) {
+        // Exit if the database is not locked by another process.
+        if (GetLastError() == ERROR_SERVICE_DATABASE_LOCKED) {
+            
+            // Allocate a buffer to get details about the lock.
+            lpqslsBuf = (LPQUERY_SERVICE_LOCK_STATUS) LocalAlloc(
+                LPTR, sizeof(QUERY_SERVICE_LOCK_STATUS)+256);
+            if (lpqslsBuf != NULL) {
+                // Get and print the lock status information.
+                if (QueryServiceLockStatus(
+                    hSCMan,
+                    lpqslsBuf,
+                    sizeof(QUERY_SERVICE_LOCK_STATUS)+256,
+                    &dwBytesNeeded) )
+                {
+                    if (lpqslsBuf->fIsLocked) {
+                        printf("Locked by: %s, duration: %ld seconds\n",
+                            lpqslsBuf->lpLockOwner,
+                            lpqslsBuf->dwLockDuration
+                        );
+                    } else {
+                        printf("No longer locked\n");
+                    }
+                }
+                LocalFree(lpqslsBuf);
+            }
+        }
+        dwStatus = GetLastError();
+    } else {
+        // The database is locked, so it is safe to make changes.
+        // Open a handle to the service.
+        hService = OpenService(
+            hSCMan,                 // SCManager database
+            lpDriver,               // name of service
+            SERVICE_CHANGE_CONFIG
+        ); // need CHANGE access
+        if (hService != NULL) {
+            // Make the changes.
+            if (!ChangeServiceConfig(
+                hService,          // handle of service
+                SERVICE_NO_CHANGE, // service type: no change
+                dwStartType,       // change service start type
+                SERVICE_NO_CHANGE, // error control: no change
+                NULL,              // binary path: no change
+                NULL,              // load order group: no change
+                NULL,              // tag ID: no change
+                NULL,              // dependencies: no change
+                NULL,              // account name: no change
+                NULL,              // password: no change
+                NULL) )            // display name: no change
+            {
+                dwStatus = GetLastError();
+            }
+        }
+        // Release the database lock.
+        UnlockServiceDatabase(sclLock);
+    }
+
+    if (hService != NULL) CloseServiceHandle(hService);
+    return dwStatus;
+} // DriverStartType
diff --git a/avrdude/windows/loaddrv.h b/avrdude/windows/loaddrv.h
new file mode 100644
index 00000000..d7d102b9
--- /dev/null
+++ b/avrdude/windows/loaddrv.h
@@ -0,0 +1,20 @@
+#ifndef LOADDRV_H
+#define LOADDRV_H
+
+#include <windows.h>
+
+#define OKAY                   0
+#define UNEXPECTED_ERROR       9999
+
+//prototypes
+DWORD LoadDriverInit(void);
+void LoadDriverCleanup(void);
+DWORD DriverInstall(LPSTR, LPSTR);
+DWORD DriverStart(LPSTR);
+DWORD DriverStop(LPSTR);
+DWORD DriverRemove(LPSTR);
+DWORD DriverStatus(LPSTR);
+DWORD DriverStartType(LPSTR, DWORD);
+#endif //LOADDRV_H
+
+
diff --git a/avrdude/windows/remove_giveio.bat b/avrdude/windows/remove_giveio.bat
new file mode 100755
index 00000000..024427db
--- /dev/null
+++ b/avrdude/windows/remove_giveio.bat
@@ -0,0 +1,14 @@
+@set DIRVERNAME=giveio
+
+@loaddrv stop %DIRVERNAME%
+@if errorlevel 2 goto error
+
+@loaddrv remove %DIRVERNAME%
+@if errorlevel 1 goto error
+
+@goto exit
+
+:error
+@echo ERROR: Deinstallation of %DIRVERNAME% failed
+
+:exit
diff --git a/avrdude/windows/status_giveio.bat b/avrdude/windows/status_giveio.bat
new file mode 100755
index 00000000..bc821474
--- /dev/null
+++ b/avrdude/windows/status_giveio.bat
@@ -0,0 +1,12 @@
+@set DIRVERNAME=giveio
+
+@loaddrv status %DIRVERNAME%
+@if errorlevel 1 goto error
+
+@goto exit
+
+:error
+@echo ERROR: Status querry for %DIRVERNAME% failed
+
+:exit
+