USBasp 2005.04.21.
authorPeter Henn <Peter.Henn@web.de>
Thu, 21 Apr 2005 10:00:00 +0000 (12:00 +0200)
committerPeter Henn <Peter.Henn@web.de>
Thu, 21 Apr 2005 10:00:00 +0000 (12:00 +0200)
unmodified content from archive usbasp.2005-04-21.tar.gz

29 files changed:
.gitattributes [new file with mode: 0644]
Readme.txt [new file with mode: 0644]
bin/firmware/usbasp.2005-04-21.hex [new file with mode: 0644]
bin/win-avrdude/avrdude.conf [new file with mode: 0644]
bin/win-avrdude/avrdude.exe [new file with mode: 0755]
bin/win-driver/libusb0.dll [new file with mode: 0755]
bin/win-driver/libusb0.sys [new file with mode: 0755]
bin/win-driver/usbasp.inf [new file with mode: 0644]
circuit/usbasp_5V_circuit.pdf [new file with mode: 0644]
firmware/Makefile [new file with mode: 0644]
firmware/clock.c [new file with mode: 0644]
firmware/clock.h [new file with mode: 0644]
firmware/isp.c [new file with mode: 0644]
firmware/isp.h [new file with mode: 0644]
firmware/main.c [new file with mode: 0644]
firmware/usbconfig.h [new file with mode: 0644]
firmware/usbdrv/Changelog.txt [new file with mode: 0644]
firmware/usbdrv/License.txt [new file with mode: 0644]
firmware/usbdrv/oddebug.c [new file with mode: 0644]
firmware/usbdrv/oddebug.h [new file with mode: 0644]
firmware/usbdrv/oddebug.o [new file with mode: 0644]
firmware/usbdrv/usbdrv.c [new file with mode: 0644]
firmware/usbdrv/usbdrv.h [new file with mode: 0644]
firmware/usbdrv/usbdrv.o [new file with mode: 0644]
firmware/usbdrv/usbdrvasm.S [new file with mode: 0644]
firmware/usbdrv/usbdrvasm.o [new file with mode: 0644]
software/avrdude_usbasp.2005-04-21.patch [new file with mode: 0644]
software/usbasp.c [new file with mode: 0644]
software/usbasp.h [new file with mode: 0644]

diff --git a/.gitattributes b/.gitattributes
new file mode 100644 (file)
index 0000000..9803a03
--- /dev/null
@@ -0,0 +1,9 @@
+# Declare files that will always have CRLF line endings on checkout.
+*.inf text eol=crlf
+
+# Declare pathc and diff files allow trailing whitespace
+*.diff text=auto -whitespace
+*.patch        text=auto -whitespace
+
+# ignore .git
+.git*  text export-ignore
diff --git a/Readme.txt b/Readme.txt
new file mode 100644 (file)
index 0000000..a3ef940
--- /dev/null
@@ -0,0 +1,140 @@
+This is the README file for USBasp.
+
+USBasp is a USB in-circuit programmer for Atmel AVR controllers. It simply
+consists of an ATMega8 and a couple of passive components. The programmer
+uses a firmware-only USB driver, no special USB controller is needed.
+
+Features:
+- Works under multiple platforms. Linux, Mac OS X and Windows are tested.
+- No special controllers or smd components are needed.
+- Programming speed is up to 5kBytes/sec.
+- SCK option to support targets with low clock speed (< 1,5MHz).
+- Planned: serial interface to target (e.g. for debugging).
+
+
+LICENSE
+
+The project is built with AVR USB driver by Objective Development, which is
+published under a proprietary Open Source license. To conform with this
+license, USBasp is distributed under the same license conditions. See the
+file "firmware/usbdrv/License.txt" for details.
+
+
+LIMITATIONS
+
+Hardware:
+"circuit/usbasp_5V_circuit.pdf" shows a simple circuit. It doesn't meet the
+voltage range on the data lines specified in USB 1.1. Also this circuit can
+only be used for programming 5V target systems. For other systems a level
+converter is needed.
+
+Firmware:
+The firmware dosn't support USB Suspend Mode. A bidirectional serial
+interface to slave exists in hardware but the firmware doesn't support it yet.
+
+
+USE PRECOMPILED VERSION
+
+Firmware:
+Flash "bin/firmware/usbasp.xxxx-xx-xx.hex" to the ATMega8 with a working
+programmer (e.g. with avrdude, uisp, ...). Set jumper J2 to activate
+USBasp firmware update function.
+
+Windows:
+Start Windows and connect USBasp to the system. When Windows asks for a
+driver, choose "bin/win-driver". On Win2k and WinXP systems, Windows will
+warn that the driver is is not 'digitally signed'. Ignore this message and
+continue with the installation.
+Now you can run the precompiled version of avrdude: change in command line
+mode to "bin/win-avrdude" and start the program. Consult the documentation
+of avrdude for details. Examples:
+1. Enter terminal mode with an AT90S2313 connected to the programmer:
+   avrdude -c usbasp -p at90s2313 -t
+2. Write main.hex to the flash of an ATmega8:
+   avrdude -c usbasp -p atmega8 -U flash:w:main.hex
+
+Setting jumpers:
+J1 Power target
+   Supply target with 5V (USB voltage). Be careful with this option, the
+   circuit isn't protected against short circuit!
+J2 Jumper for firmware upgrade (not self-upgradable)
+   Set this jumper for flashing the ATMega8 of USBasp with another working
+   programmer.
+J3 SCK option
+   If the target clock is lower than 1,5 MHz, you have to set this jumper.
+   Then SCK is scaled down from 375 kHz to about 8 kHz.
+
+
+BUILDING AND INSTALLING FROM SOURCE CODE
+
+Firmware:
+To compile the firmware
+1. install the GNU toolchain for AVR microcontrollers (avr-gcc, avr-libc),
+2. change directory to firmware/
+3. run "make"
+4. flash "main.hex" to the ATMega8. E.g. with uisp or avrdude (check
+the Makefile option "make avrdude"). To flash the firmware you have
+to set jumper J2 and connect USBasp to a working programmer.
+
+Software (avrdude):
+An extension to avrdude (http://www.nongnu.org/avrdude/) was written.
+To compile the software:
+1. install libusb: http://libusb.sourceforge.net/
+2. get the csv version of avrdude:
+   export CVS_RSH="ssh"
+   cvs -z3 -d:ext:anoncvs@savannah.nongnu.org:/cvsroot/avrdude co avrdude
+3. cp usbasp/software/usbasp.* avrdude/
+4. cd avrdude
+5. apply the patch:
+   patch < ../usbasp/software/avrdude_usbasp.xxxx-xx-xx.patch
+6. configure to your environment:
+   ./bootstrap (I had to comment out the two if-blocks which verify the
+                installed versions of autoconf and automake)
+   ./configure
+7. compile and install it:
+   make
+   make install
+
+Notes on Windows (Cygwin):
+Download libusb-win32-device-bin-x.x.x.x.tar.gz from
+http://libusb-win32.sourceforge.net/ and unpack it.
+-> copy lib/gcc/libusb.a to lib-path
+-> copy include/usb.h to include-path
+cd avrdude
+./configure LDFLAGS="-static" --enable-versioned-doc=no
+make
+
+Notes on Darwin/MacOS X:
+after "./configure" I had to edit Makefile:
+change "avrdude_CPPFLAGS" to "AM_CPPFLAGS"
+(why is this needed only on mac? bug in configure.ac?)
+
+
+FILES IN THE DISTRIBUTION
+
+Readme.txt ...................... The file you are currently reading
+firmware ........................ Source code of the controller firmware
+firmware/usbdrv ................. AVR USB driver by Objective Development
+firmware/usbdrv/License.txt ..... Public license for AVR USB driver and USBasp
+software ........................ Source code of the host software
+circuit ......................... Circuit diagram in PDF
+bin ............................. Precompiled programs
+bin/win-driver .................. Windows driver
+bin/win-avrdude ................. avrdude compiled for Windows
+
+
+MORE INFORMATION
+
+For more information on USBasp and it's components please visit the
+following URLs:
+
+USBasp .......................... http://www.fischl.de/usbasp/
+
+Firmware-only AVR USB driver .... http://www.obdev.at/products/avrusb/
+avrdude ......................... http://www.nongnu.org/avrdude/
+libusb .......................... http://libusb.sourceforge.net/
+libusb-win32 .................... http://libusb-win32.sourceforge.net/
+
+
+2005-04-21 Thomas Fischl <tfischl@gmx.de>
+http://www.fischl.de
diff --git a/bin/firmware/usbasp.2005-04-21.hex b/bin/firmware/usbasp.2005-04-21.hex
new file mode 100644 (file)
index 0000000..eeb499c
--- /dev/null
@@ -0,0 +1,204 @@
+:100000003BC072C153C052C051C050C04FC04EC05F
+:100010004DC04CC04BC04AC049C048C047C046C094
+:1000200045C044C043C00E03550053004200610068
+:10003000730070001C037700770077002E006600C5
+:1000400069007300630068006C002E00610074009A
+:1000500004030904090212000101008019090400C7
+:1000600000000000000012010101FF000008EB0386
+:10007000B4C700010102000111241FBECFE5D4E086
+:10008000DEBFCDBF10E0A0E6B0E0EAE9FCE002C0D0
+:1000900005900D92A436B107D9F710E0A4E6B0E0C0
+:1000A00001C01D92A23AB107E1F7E2C5A9CF1F93A3
+:1000B000CF93FC0180919B008D3269F080917A0092
+:1000C00087FD04C0CF0145D58F3F71F010926300CA
+:1000D00010927A0066C0C0E010E8683061F0C0930A
+:1000E000630010937A005DC08EE180938D0082E002
+:1000F0008093620056C080818076F9F426E930E072
+:10010000C093960081818823A1F08530E9F0863084
+:10011000F9F0883061F18A3071F130939D002093BD
+:100120009C0087818823D9F686818C17C0F6C82F5A
+:10013000D6CFC0939700C2E0F0CFC681CF01FCD3E9
+:100140008F3FA9F710E0CBCF828180937B00E5CF72
+:1001500010EC8381813089F0823099F08330E9F6A8
+:100160008281882391F4C4E020E530E0D6CFC1E05D
+:10017000C0939600D2CFC1E0D0CFC2E126E630E0F6
+:10018000CCCFC2E124E530E0C8CF813031F08230FD
+:1001900021F6CEE026E230E0C0CFCCE124E330E02F
+:1001A000BCCFCF911F910895CF9360919E0066239D
+:1001B00051F0635067FD05C0809199009927019621
+:1001C00076DF10929E008091620087FD1AC086B390
+:1001D000837019F010927C0077C080917C00882396
+:1001E00009F072C094E686B3837009F06DC0915037
+:1001F000D1F781E080937C009093980090937B00EE
+:1002000063C0809163008F3F31F12BE490917A00BD
+:1002100090FD23EC9F5F90937A0020938D00682FD0
+:10022000893008F068E0861B80936300AEE8B0E098
+:1002300097FD30C0662349F560E070E0C62F693055
+:10024000A0F08EE180938D0092E08FEF80936300A9
+:1002500090936200BCCF80917B00882309F4B7CFD4
+:100260008093980010927B00B2CF8EE890E0B9D1D5
+:10027000EC2FFF27E357FF4F818392839C2F9C5FD6
+:10028000C83018F390936200A2CFCD0125D4682F17
+:100290007727D4CFE0919C00F0919D0096FF0DC090
+:1002A000962F03C084918D9331969150D8F7F09397
+:1002B0009D00E0939C007727C1CF962F02C08191CB
+:1002C0008D939150E0F7F3CFCF91089584E690E0BD
+:1002D00080939A000B968093990085B7836085BFC1
+:1002E0008BB780648BBF08950F930FB70F9305E012
+:1002F000B09BFECF0A95B099E9F71F933F932F93D8
+:1003000031E012E006B3102710FD32E0102F3A95CD
+:10031000C9F700FDE0C006B3102717952FE7279512
+:10032000DF9316B3012707952795CF93C0919A00C5
+:1003300006B31027179527953BE0DD274F9316B39B
+:100340000127079527954FEF000051C005E0B09BAE
+:10035000FECF0A95B099E9F7DF9100C0D1CF16B36F
+:10036000137079F1407C2C6F13C006B3037049F110
+:1003700041782C6F15C0037021F1102F2C6F06B33C
+:1003800019C006B30370E9F04E7F2C6F18C038F324
+:1003900006B30370B1F0102717952795243028F382
+:1003A00016B3012707952795422749934FEF06B3C8
+:1003B000243008F3102717952795243010F316B32F
+:1003C0001370E1F10127079527952430F0F006B36B
+:1003D0000370A1F11027179527952430E0F016B38C
+:1003E0000127079527953A9541F12430D0F006B3BF
+:1003F000037021F11027179527952430C0F016B30C
+:100400000127079527952430C2CF16B31370B1F09A
+:100410004C7F2C6FDCCF06B3037081F0487F2C6FCC
+:10042000DECF16B3137051F0407F2C6FE0CF06B3D0
+:10043000037021F0407E2C6FE2CF3AC03C2FC09178
+:100440009A003C1B00E433300ABF90F10881198107
+:10045000412F1F77209198000D3271F1013E61F11B
+:100460000936B9F0033C11F00B3411F510919F00DF
+:100470001123F1F000919E000030B1F530939E0001
+:1004800010939B0000919900C093990000939A00EB
+:100490002EC0121769F4309162003F3F29F10FEF2F
+:1004A00000936200CDE8D0E025C0002700939F00B4
+:1004B0004F91CF91DF910FC01217B9F700939F00B2
+:1004C0000FEF00936300009362004F91CF910AB742
+:1004D00006FD3CCFDF9100E40ABF2F913F911F91B1
+:1004E0000F910FBF0F911895C0E6D0E002C0C1E692
+:1004F000D0E032E05F9308B30C7F016008BB53E0AB
+:1005000017B3136017BB20E80FC0052710E008BB26
+:1005100010C0052710E0089408BB13C0052710E0A1
+:1005200015C0052710E019C020FF052708BB279537
+:1005300017951C3F50F720FF0527279508BB1795F7
+:100540001C3F38F720FF05272795179508BB1C3F50
+:1005500028F720FF0527279517951C3F08BB08F7AC
+:1005600000C0499120FF052708BB279517951C3F20
+:1005700048F520FF0527279508BB17951C3F30F548
+:1005800020FF05272795179508BB1C3F20F520FF66
+:100590000527279517951C3F08BB00F5242F3A9592
+:1005A00019F60C7F5F9108BB34E03A95F1F70160D2
+:1005B00017B31C7F08BB0C7F4F91CF9117BB08BBB3
+:1005C000DF9189CF052710E008BBD1CF052710E0C8
+:1005D000089408BBD4CF052710E0D6CF052710E03C
+:1005E000DACFA82FB92F8FEF9FEF41E050EA61508B
+:1005F00070F02D9138E0722F782796958795269583
+:1006000070FF02C0842795273A95A9F7F0CF80950F
+:100610009095089582E58DB981E08EB9089588237B
+:1006200039F480E493E09093A1008093A0000895B2
+:100630008DE593E09093A1008093A000089592B778
+:1006400082B7891B8C30E0F3089587B38C6287BB37
+:10065000C298C598F4DFC29AF2DFC2988091A000D8
+:100660009091A1008D55934009F00895D3DF08952E
+:1006700087B3837D87BB88B3837D88BB1DB808950E
+:100680000F931F93CF93C82F00E017E00CC0C398BF
+:10069000CC0F000FB4990F5FC59AD1DFC598CFDF9B
+:1006A000115017FD04C0C7FFF2CFC39AF1CF802FBE
+:1006B0009927CF911F910F9108958FB9779BFECF06
+:1006C0008FB1992708951F93CF93CFE103C0C150F5
+:1006D000CF3F51F1E091A000F091A1008CEA099583
+:1006E000E091A000F091A10083E50995E091A000C0
+:1006F000F091A10080E00995182FE091A000F09101
+:10070000A10080E00995133591F01DB8C59A97DFD7
+:10071000C59895DF8091A0009091A1008D559340E0
+:10072000B1F678DFC150B0F681E090E002C080E021
+:1007300090E0CF911F9108950F931F938C018170CA
+:10074000880F880F880FE091A000F091A1008062CF
+:100750000995C801892F99278695E091A000F0910D
+:10076000A100099516950795E091A000F091A100D0
+:10077000802F0995E091A000F091A10080E00995FB
+:1007800099271F910F9108950F931F93CF93DF9394
+:10079000EC01062F142F8170880F880F880FE091CD
+:1007A000A000F091A10080640995CE01892F9927BE
+:1007B0008695E091A000F091A1000995CE01969553
+:1007C0008795E091A000F091A1000995E091A0002B
+:1007D000F091A100802F09951123A9F00F3789F01E
+:1007E0001EE102B7CE01A8DF8F3769F482B7801B04
+:1007F0008D3310F002B711501123A1F781E090E082
+:1008000004C08FE08CD080E090E0DF91CF911F9109
+:100810000F9108950F931F93CF93DF93EC01162F41
+:10082000E091A000F091A1008CE40995CE01892F00
+:1008300099278695E091A000F091A1000995CE013D
+:1008400096958795E091A000F091A1000995E0911F
+:10085000A000F091A10080E009951F3F89F01EE102
+:1008600002B7CE0169DF8F3F69F482B7801B8D33F9
+:1008700010F002B711501123A1F781E090E004C0FD
+:100880008FE04DD080E090E0DF91CF911F910F91EC
+:1008900008950F931F938C01E091A000F091A100A7
+:1008A00080EA0995812F9927E091A000F091A1009D
+:1008B0000995E091A000F091A100802F0995E091A9
+:1008C000A000F091A10080E0099599271F910F9158
+:1008D0000895FF920F931F938C01F62EE091A000D4
+:1008E000F091A10080EC0995812F9927E091A0005B
+:1008F000F091A1000995E091A000F091A100802F56
+:100900000995E091A000F091A1008F2D09958EE14D
+:1009100006D080E090E01F910F91FF900895382F4E
+:1009200020E0231740F492B782B7891B8C33E0F3A1
+:100930002F5F2317C0F308951F93CF93DF93EC012C
+:1009400010E089818130A1F0823009F472C08330D7
+:1009500009F472C0843091F0873009F450C08530BA
+:1009600009F4AAC0863039F1883009F0A9C086C0E0
+:100970009A9B812F54DE69DEA998A2C08B819927AA
+:10098000982F88272A813327822B932B90938900D5
+:10099000809388008F819927982F88272E8133276D
+:1009A000822B932B90937E0080937D0082E0809336
+:1009B0007F001FEF85C08B819927982F88272A8178
+:1009C0003327822B932B90938900809388009C81FE
+:1009D00090938A008D8180938B0080FF02C090935A
+:1009E0008C008F819927982F88272E813327822B7F
+:1009F000932B90937E0080937D0081E0D8CF8B81F4
+:100A00009927982F88272A813327822B932B90931D
+:100A10008900809388008F819927982F88272E81BD
+:100A20003327822B932B90937E0080937D0083E06D
+:100A3000BECF1EDEA99A44C0E091A000F091A100B3
+:100A40008A81099580938000E091A000F091A10037
+:100A50008B81099580938100E091A000F091A10025
+:100A60008C81099580938200E091A000F091A10013
+:100A70008D8109958093830014E022C08B81992792
+:100A8000982F88272A813327822B932B90938900D4
+:100A90008093880010938A0010938B008F81992790
+:100AA000982F88272E813327822B932B90937E00BB
+:100AB00080937D0084E07BCF06DE8093800011E090
+:100AC00080E890E090939D0080939C00812F99276F
+:100AD000DF91CF911F910895EF92FF921F93CF93D3
+:100AE0007C01162F90917F00892F8250823050F523
+:100AF000C0E0C617C0F01FC08091880090918900A7
+:100B0000C8DEF701EC0FF11D808380918800909181
+:100B1000890001969093890080938800CF5FC11768
+:100B200050F490917F00923039F780918800909135
+:100B3000890002DEE6CF183010F410927F00812F7A
+:100B4000992702C08FEF90E0CF911F91FF90EF9017
+:100B50000895CF92DF92EF92FF920F931F93CF935E
+:100B6000DF936C01062F40917F00413019F0443033
+:100B700009F073C010E01017F0F16CC080918A008A
+:100B8000882309F046C0C12FDD27FE01EC0DFD1DB5
+:100B900060818091880090918900F6DD80917D00D0
+:100BA00090917E00019790937E0080937D00892B29
+:100BB000A1F410927F0080918B0081FF0EC0909174
+:100BC0008C0080918A00981741F0CC0DDD1D688162
+:100BD00080918800909189001DDE8091880090911D
+:100BE0008900019690938900809388001F5F1017F9
+:100BF00088F540917F00413009F2C12FDD27FE01C9
+:100C0000EC0DFD1D6081809188009091890061DE6E
+:100C1000C5CFC12FDD277E01EC0CFD1C40E0F701A4
+:100C200060818091880090918900AEDD80918C0078
+:100C3000815080938C00882309F0B0CFF701608148
+:100C40008091880090918900E5DD80918A008093F1
+:100C50008C00A4CF80E090E002C08FEF90E0DF91A5
+:100C6000CF911F910F91FF90EF90DF90CF9008955B
+:100C7000CFE5D4E0DEBFCDBF12BA18BA8BEF81BB8F
+:100C800017BA93E094BB8EEF85BB93BF81E0C7DCBE
+:0A0C90001DDB789489DA88DAFDCFC5
+:040C9A005AD2FFFF2C
+:00000001FF
diff --git a/bin/win-avrdude/avrdude.conf b/bin/win-avrdude/avrdude.conf
new file mode 100644 (file)
index 0000000..a74de19
--- /dev/null
@@ -0,0 +1,3317 @@
+# $Id: avrdude.conf.in,v 1.36 2004/12/22 01:30:30 bdean Exp $
+#
+# 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 | avr910;           # 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
+#       devicecode       = <num> ;            # deprecated, use stk500_devcode
+#       stk500_devcode   = <num> ;                # numeric
+#       avr910_devcode   = <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> ;
+#         ;
+#     ;
+#
+# 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
+#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 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 AT86RF401   0xD0
+
+#define AT89START   0xE0
+#define AT89S51            0xE0
+#define AT89S52            0xE1
+
+
+#
+# Overall avrdude defaults
+#
+default_parallel   = "/dev/parport0";
+default_serial     = "/dev/ttyS0";
+
+
+#
+# PROGRAMMER DEFINITIONS
+#
+
+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    = "avrisp";
+  desc  = "Atmel AVR ISP";
+  type  = stk500;
+;
+
+programmer
+  id    = "usbasp";
+  desc  = "usbasp";
+  type  = usbasp;
+;
+
+programmer
+  id    = "stk500";
+  desc  = "Atmel STK500";
+  type  = stk500;
+;
+
+programmer
+  id    = "avr910";
+  desc  = "Atmel Low Cost Serial Programmer";
+  type  = avr910;
+;
+
+programmer
+  id    = "butterfly";
+  desc  = "Atmel Butterfly Development Board";
+  type  = butterfly;
+;
+
+programmer
+  id    = "pavr";
+  desc  = "Jason Kyle's pAVR Serial Programmer";
+  type  = avr910;
+;
+
+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;
+;
+
+
+#
+# PART DEFINITIONS
+#
+
+#------------------------------------------------------------
+# ATtiny12
+#------------------------------------------------------------
+
+part
+    id                  = "t12";
+    desc                = "ATtiny12";
+    stk500_devcode      = 0x12;
+    avr910_devcode      = 0x55;
+    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";
+
+    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";
+    ;
+
+    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";
+    ;
+
+    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";
+    ;
+
+    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";
+    ;
+;
+
+#------------------------------------------------------------
+# ATtiny13
+#------------------------------------------------------------
+
+part
+    id                  = "t13";
+    desc                = "ATtiny13";
+    stk500_devcode      = 0x14;
+    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";
+
+    memory "eeprom"
+        size            = 64;
+        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";
+    ;
+
+    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";
+    ;
+
+    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            = 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 "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;
+    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";
+
+    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";
+    ;
+
+    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";
+    ;
+
+    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";
+    ;
+
+    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";
+    ;
+;
+
+
+#------------------------------------------------------------
+# AT90s1200
+#------------------------------------------------------------
+
+part
+    id               = "1200";
+    desc             = "AT90S1200";
+    stk500_devcode   = 0x33;
+    avr910_devcode   = 0x13;
+    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";
+
+    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";
+      ;
+    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";
+      ;
+    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";
+      ;
+  ;
+
+#------------------------------------------------------------
+# AT90s4414
+#------------------------------------------------------------
+
+part
+    id               = "4414";
+    desc             = "AT90S4414";
+    stk500_devcode   = 0x50;
+    avr910_devcode   = 0x28;
+    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     = 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";
+      ;
+    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";
+      ;
+    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";
+      ;
+  ;
+
+#------------------------------------------------------------
+# AT90s2313
+#------------------------------------------------------------
+
+part
+    id               = "2313";
+    desc             = "AT90S2313";
+    stk500_devcode   = 0x40;
+    avr910_devcode   = 0x20;
+    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            = 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";
+      ;
+    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";
+      ;
+    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 "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";
+      ;
+  ;
+
+#------------------------------------------------------------
+# AT90s2333
+#------------------------------------------------------------
+
+part
+    id               = "2333";
+    desc             = "AT90S2333";
+    stk500_devcode   = 0x42;
+    avr910_devcode   = 0x34;
+    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            = 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";
+      ;
+    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";
+      ;
+    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
+#------------------------------------------------------------
+
+part
+    id               = "2343";
+    desc             = "AT90S2343";
+    stk500_devcode   = 0x43;
+    avr910_devcode   = 0x4c;
+    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";
+
+    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";
+      ;
+    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";
+      ;
+    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;
+    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;
+        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";
+    desc             = "AT90S4434";
+    stk500_devcode   = 0x52;
+    avr910_devcode   = 0x6c;
+    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;
+    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";
+
+    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";
+      ;
+    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";
+      ;
+    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";
+      ;
+    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";
+      ;
+  ;
+
+#------------------------------------------------------------
+# AT90s8535
+#------------------------------------------------------------
+
+part
+    id               = "8535";
+    desc             = "AT90S8535";
+    stk500_devcode   = 0x61;
+    avr910_devcode   = 0x68;
+    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            = 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";
+      ;
+    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";
+      ;
+    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";
+      ;
+    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";
+      ;
+  ;
+
+#------------------------------------------------------------
+# ATmega103
+#------------------------------------------------------------
+
+part
+    id               = "m103";
+    desc             = "ATMEGA103";
+    stk500_devcode   = 0xB1;
+    avr910_devcode   = 0x41;
+    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";
+
+    memory "eeprom"
+        size            = 4096;
+        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    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";
+      ;
+
+    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";
+      ;
+
+    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";
+      ;
+
+    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";
+      ;
+
+    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";
+    stk500_devcode   = 0xA0;
+    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";
+
+    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";
+      ;
+
+    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";
+      ;
+
+    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";
+      ;
+
+    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";
+      ;
+
+    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";
+      ;
+
+    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";
+      ;
+
+    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";
+      ;
+  ;
+
+
+
+
+#------------------------------------------------------------
+# ATmega128
+#------------------------------------------------------------
+
+part
+    id               = "m128";
+    desc             = "ATMEGA128";
+    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";
+
+    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";
+      ;
+
+    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";
+      ;
+
+    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";
+      ;
+
+    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";
+      ;
+
+    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";
+      ;
+
+    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";
+      ;
+
+    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";
+      ;
+  ;
+
+#------------------------------------------------------------
+# AT90CAN128
+#------------------------------------------------------------
+
+part
+    id               = "c128";
+    desc             = "AT90CAN128";
+    stk500_devcode   = 0xB3;
+#    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 x  x x x x",
+                       "x x x x  x x x x    x x x x  x x x x";
+
+    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";
+      ;
+
+    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";
+      ;
+
+    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";
+      ;
+
+    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";
+      ;
+
+    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;
+        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   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";
+    stk500_devcode   = 0x82;
+    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",
+                       "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 "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  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";
+      ;
+
+    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";
+      ;
+
+    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";
+      ;
+
+    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";
+      ;
+
+    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";
+      ;
+    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";
+      ;
+  ;
+
+
+#------------------------------------------------------------
+# ATmega162
+#------------------------------------------------------------
+
+part
+    id               = "m162";
+    desc             = "ATMEGA162";
+    stk500_devcode   = 0x83;
+    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";
+
+    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";
+      ;
+
+    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  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";
+        ;
+
+    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 i  i i i 1";
+      ;
+
+    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;
+    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";
+   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";
+      ;
+
+    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";
+      ;
+
+    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";
+    stk500_devcode   = 0x85;
+    avr910_devcode   = 0x75;
+    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";
+   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",
+                          "  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";
+      ;
+
+    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";
+      ;
+
+    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 x";
+
+        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";
+      ;
+  ;
+
+#------------------------------------------------------------
+# ATmega32
+#------------------------------------------------------------
+
+part
+    id               = "m32";
+    desc             = "ATMEGA32";
+    stk500_devcode   = 0x91;
+    avr910_devcode   = 0x72;
+    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";
+   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";
+      ;
+
+    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";
+      ;
+
+    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            = 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";
+      ;
+  ;
+
+#------------------------------------------------------------
+# ATmega161
+#------------------------------------------------------------
+
+part
+    id               = "m161";
+    desc             = "ATMEGA161";
+    stk500_devcode   = 0x80;
+    avr910_devcode   = 0x60;
+    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";
+   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";
+      ;
+
+    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";
+      ;
+
+    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;
+    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";
+
+    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";
+      ;
+    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";
+      ;
+
+    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;
+    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";
+
+    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";
+      ;
+    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";
+      ;
+
+    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            = 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";
+      ;
+
+    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;
+    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";
+
+    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";
+      ;
+    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";
+      ;
+
+    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            = 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";
+      ;
+
+    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;
+    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";
+
+    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";
+    ;
+
+    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";
+    ;
+
+    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";
+    ;
+
+    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";
+      ;
+
+    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";
+      ;
+
+    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";
+    ;
+
+;
+
+
+#------------------------------------------------------------
+# ATmega48
+#------------------------------------------------------------
+
+part
+    id               = "m48";
+    desc             = "ATMEGA48";
+    stk500_devcode   = 0x59;
+#    avr910_devcode   = 0x;
+    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";
+
+    memory "eeprom"
+        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";
+      ;
+    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";
+      ;
+
+    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   i i 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";
+    stk500_devcode   = 0x73;
+#    avr910_devcode   = 0x;
+    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";
+
+    memory "eeprom"
+        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";
+      ;
+    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";
+      ;
+
+    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   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            = 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";
+     stk500_devcode   = 0x23;
+##  avr910_devcode   = ?;
+##  Try the AT90S2313 devcode:
+     avr910_devcode   = 0x20;
+     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";
+
+     memory "eeprom"
+         size            = 128;
+         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";
+       ;
+     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";
+       ;
+#   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";
+       ;
+
+     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";
+       ;
+
+     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";
+       ;
+
+     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";
+     ;
+# 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";
+     ;
+  ;
diff --git a/bin/win-avrdude/avrdude.exe b/bin/win-avrdude/avrdude.exe
new file mode 100755 (executable)
index 0000000..a564048
Binary files /dev/null and b/bin/win-avrdude/avrdude.exe differ
diff --git a/bin/win-driver/libusb0.dll b/bin/win-driver/libusb0.dll
new file mode 100755 (executable)
index 0000000..8f0d9f7
Binary files /dev/null and b/bin/win-driver/libusb0.dll differ
diff --git a/bin/win-driver/libusb0.sys b/bin/win-driver/libusb0.sys
new file mode 100755 (executable)
index 0000000..3d36966
Binary files /dev/null and b/bin/win-driver/libusb0.sys differ
diff --git a/bin/win-driver/usbasp.inf b/bin/win-driver/usbasp.inf
new file mode 100644 (file)
index 0000000..82ca9e1
--- /dev/null
@@ -0,0 +1,90 @@
+[Version]
+Signature = "$Chicago$"
+provider  = %manufacturer%
+DriverVer = 03/09/2005,0.1.10.1
+CatalogFile = usbasp.cat
+
+Class = LibUsbDevices
+ClassGUID = {EB781AAF-9C70-4523-A5DF-642A87ECA567}
+
+[ClassInstall]
+AddReg=ClassInstall.AddReg
+
+[ClassInstall32]
+AddReg=ClassInstall.AddReg
+
+[ClassInstall.AddReg]
+HKR,,,,"LibUSB-Win32 Devices"
+HKR,,Icon,,"-20"
+
+[Manufacturer]
+%manufacturer%=Devices
+
+;--------------------------------------------------------------------------
+; Files
+;--------------------------------------------------------------------------
+
+[SourceDisksNames]
+1 = "Libusb-Win32 Driver Installation Disk",,
+
+[SourceDisksFiles]
+libusb0.sys = 1,,
+libusb0.dll = 1,,
+
+[DestinationDirs]
+LIBUSB.Files.Sys = 10,System32\Drivers
+LIBUSB.Files.Dll = 10,System32
+
+[LIBUSB.Files.Sys]
+libusb0.sys
+
+[LIBUSB.Files.Dll]
+libusb0.dll
+
+;--------------------------------------------------------------------------
+; Device driver
+;--------------------------------------------------------------------------
+
+[LIBUSB_DEV]
+CopyFiles = LIBUSB.Files.Sys, LIBUSB.Files.Dll
+AddReg    = LIBUSB_DEV.AddReg
+
+[LIBUSB_DEV.NT]
+CopyFiles = LIBUSB.Files.Sys, LIBUSB.Files.Dll
+
+[LIBUSB_DEV.HW]
+DelReg = LIBUSB_DEV.DelReg.HW
+
+[LIBUSB_DEV.NT.HW]
+DelReg = LIBUSB_DEV.DelReg.HW
+
+[LIBUSB_DEV.NT.Services]
+AddService = libusb0, 0x00000002, LIBUSB.AddService
+
+[LIBUSB_DEV.AddReg]
+HKR,,DevLoader,,*ntkern
+HKR,,NTMPDriver,,libusb0.sys
+
+[LIBUSB_DEV.DelReg.HW]
+HKR,,"LowerFilters"
+
+;--------------------------------------------------------------------------
+; Services
+;--------------------------------------------------------------------------
+
+[LIBUSB.AddService]
+DisplayName    = "LibUsb-Win32 - Kernel Driver 03/09/2005, 0.1.10.1"
+ServiceType    = 1
+StartType      = 3
+ErrorControl   = 0
+ServiceBinary  = %12%\libusb0.sys
+
+;--------------------------------------------------------------------------
+; Devices
+;--------------------------------------------------------------------------
+
+[Devices]
+"USBasp"=LIBUSB_DEV, USB\VID_03eb&PID_c7b4
+
+[Strings]
+manufacturer = "www.fischl.de"
diff --git a/circuit/usbasp_5V_circuit.pdf b/circuit/usbasp_5V_circuit.pdf
new file mode 100644 (file)
index 0000000..76a220e
Binary files /dev/null and b/circuit/usbasp_5V_circuit.pdf differ
diff --git a/firmware/Makefile b/firmware/Makefile
new file mode 100644 (file)
index 0000000..02bbbca
--- /dev/null
@@ -0,0 +1,56 @@
+SERIAL = `echo /dev/tty.USA19QI*`
+UISP = uisp -dprog=avr910 -dserial=$(SERIAL) -dpart=auto
+TARGET = atmega8
+#TARGET = at90s2313
+# The two lines above are for "uisp" and the AVR910 serial programmer connected
+# to a Keyspan USB to serial converter to a Mac running Mac OS X.
+# Choose your favorite programmer and interface.
+
+COMPILE = avr-gcc -Wall -O2 -Iusbdrv -I. -mmcu=$(TARGET) # -DDEBUG_LEVEL=2
+
+OBJECTS = usbdrv/usbdrv.o usbdrv/usbdrvasm.o usbdrv/oddebug.o isp.o clock.o main.o
+
+
+# symbolic targets:
+all:   main.hex
+
+.c.o:
+       $(COMPILE) -c $< -o $@
+#-Wa,-ahlms=$<.lst
+
+.S.o:
+       $(COMPILE) -x assembler-with-cpp -c $< -o $@
+# "-x assembler-with-cpp" should not be necessary since this is the default
+# file type for the .S (with capital S) extension. However, upper case
+# characters are not always preserved on Windows. To ensure WinAVR
+# compatibility define the file type manually.
+
+.c.s:
+       $(COMPILE) -S $< -o $@
+
+clean:
+       rm -f main.hex main.lst main.obj main.cof main.list main.map main.eep.hex main.bin *.o main.s usbdrv.s
+
+# file targets:
+main.bin:      $(OBJECTS)
+       $(COMPILE) -o main.bin $(OBJECTS) -Wl,-Map,main.map
+
+main.hex:      main.bin
+       rm -f main.hex main.eep.hex
+       avr-objcopy -j .text -j .data -O ihex main.bin main.hex
+#      ./checksize main.bin
+# do the checksize script as our last action to allow successful compilation
+# on Windows with WinAVR where the Unix commands will fail.
+
+disasm:        main.bin
+       avr-objdump -d main.bin
+
+cpp:
+       $(COMPILE) -E main.c
+
+avrdude:
+       avrdude -c butterfly -p $(TARGET) -U flash:w:main.hex
+
+uisp:  all
+       $(UISP) --erase
+       $(UISP) --upload --verify if=main.hex
diff --git a/firmware/clock.c b/firmware/clock.c
new file mode 100644 (file)
index 0000000..1397493
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+  clock.c - part of USBasp
+
+  Autor..........: Thomas Fischl <tfischl@gmx.de>
+  Description....: Provides functions for timing/waiting
+  Licence........: Free under certain conditions. See Documentation.
+  Creation Date..: 2005-02-23
+  Last change....: 2005-04-20
+*/
+
+#include <inttypes.h>
+#include <avr/io.h>
+#include "clock.h"
+
+/* wait time * 320 us */
+void clockWait(uint8_t time) {
+
+  uint8_t i;
+  for (i = 0; i < time; i++) {
+    uint8_t starttime = TIMERVALUE;
+    while ((uint8_t) (TIMERVALUE - starttime) < CLOCK_T_320us) {}
+  }
+}
diff --git a/firmware/clock.h b/firmware/clock.h
new file mode 100644 (file)
index 0000000..89eb868
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+  clock.h - part of USBasp
+
+  Autor..........: Thomas Fischl <tfischl@gmx.de>
+  Description....: Provides functions for timing/waiting
+  Licence........: Free under certain conditions. See Documentation.
+  Creation Date..: 2005-02-23
+  Last change....: 2005-04-20
+*/
+
+#ifndef __clock_h_included__
+#define        __clock_h_included__
+
+#define F_CPU           12000000L   /* 12MHz */
+#define TIMERVALUE      TCNT0
+#define CLOCK_T_320us  60
+
+/* set prescaler to 64 */
+#define clockInit()  TCCR0 = (1 << CS01) | (1 << CS00);
+
+/* wait time * 320 us */
+void clockWait(uint8_t time);
+
+#endif /* __clock_h_included__ */
diff --git a/firmware/isp.c b/firmware/isp.c
new file mode 100644 (file)
index 0000000..1bd41d3
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+  isp.c - part of USBasp
+
+  Autor..........: Thomas Fischl <tfischl@gmx.de>
+  Description....: Provides functions for communication/programming
+                   over ISP interface
+  Licence........: Free under certain conditions. See Documentation.
+  Creation Date..: 2005-02-23
+  Last change....: 2005-04-20
+*/
+
+#include <avr/io.h>
+#include "isp.h"
+#include "clock.h"
+
+#define spiHWdisable() SPCR = 0
+
+void spiHWenable() {
+
+  /* enable SPI, master, 375kHz SCK */
+  SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1);
+  SPSR = (1 << SPI2X);
+}
+
+void ispSetSCKOption(uchar option) {
+
+  if (option == 0) {
+
+    /* use software spi */
+    ispTransmit = ispTransmit_sw;
+    //    spiHWdisable();
+
+  } else {
+
+    /* use hardware spi */
+    ispTransmit = ispTransmit_hw;
+
+  }
+}
+
+void ispDelay() {
+
+  uint8_t starttime = TIMERVALUE;
+  while ((uint8_t) (TIMERVALUE - starttime) < 12) { }
+}
+
+void ispConnect() {
+
+  /* all ISP pins are inputs before */
+  /* now set output pins */
+  ISP_DDR |= (1 << ISP_RST) | (1 << ISP_SCK) | (1 << ISP_MOSI);
+
+  /* reset device */
+  ISP_OUT &= ~(1 << ISP_RST);   /* RST low */
+  ISP_OUT &= ~(1 << ISP_SCK);   /* SCK low */
+
+  /* positive reset pulse > 2 SCK (target) */
+  ispDelay();
+  ISP_OUT |= (1 << ISP_RST);    /* RST high */
+  ispDelay();
+  ISP_OUT &= ~(1 << ISP_RST);   /* RST low */
+
+  if (ispTransmit == ispTransmit_hw) {
+    spiHWenable();
+  }
+}
+
+void ispDisconnect() {
+
+  /* set all ISP pins inputs */
+  ISP_DDR &= ~((1 << ISP_RST) | (1 << ISP_SCK) | (1 << ISP_MOSI));
+  /* switch pullups off */
+  ISP_OUT &= ~((1 << ISP_RST) | (1 << ISP_SCK) | (1 << ISP_MOSI));
+
+  /* disable hardware SPI */
+  spiHWdisable();
+}
+
+uchar ispTransmit_sw(uchar send_byte) {
+
+  uchar rec_byte = 0;
+  uchar i;
+  for (i = 0; i < 8; i++) {
+
+    /* set MSB to MOSI-pin */
+    if ((send_byte & 0x80) != 0) {
+      ISP_OUT |= (1 << ISP_MOSI);  /* MOSI high */
+    } else {
+      ISP_OUT &= ~(1 << ISP_MOSI); /* MOSI low */
+    }
+    /* shift to next bit */
+    send_byte  = send_byte << 1;
+
+    /* receive data */
+    rec_byte = rec_byte << 1;
+    if ((ISP_IN & (1 << ISP_MISO)) != 0) {
+      rec_byte++;
+    }
+
+    /* pulse SCK */
+    ISP_OUT |= (1 << ISP_SCK);     /* SCK high */
+    ispDelay();
+    ISP_OUT &= ~(1 << ISP_SCK);    /* SCK low */
+    ispDelay();
+  }
+
+  return rec_byte;
+}
+
+uchar ispTransmit_hw(uchar send_byte) {
+  SPDR = send_byte;
+
+  while (!(SPSR & (1 << SPIF)));
+  return SPDR;
+}
+
+uchar ispEnterProgrammingMode() {
+  uchar check;
+  uchar count = 32;
+
+  while (count--) {
+    ispTransmit(0xAC);
+    ispTransmit(0x53);
+    check = ispTransmit(0);
+    ispTransmit(0);
+
+    if (check == 0x53) {
+      return 0;
+    }
+
+    spiHWdisable();
+
+    /* pulse SCK */
+    ISP_OUT |= (1 << ISP_SCK);     /* SCK high */
+    ispDelay();
+    ISP_OUT &= ~(1 << ISP_SCK);    /* SCK low */
+    ispDelay();
+
+    if (ispTransmit == ispTransmit_hw) {
+      spiHWenable();
+    }
+
+  }
+
+  return 1;  /* error: device dosn't answer */
+}
+
+uchar ispReadFlash(unsigned int address) {
+  ispTransmit(0x20 | ((address & 1) << 3));
+  ispTransmit(address >> 9);
+  ispTransmit(address >> 1);
+  return ispTransmit(0);
+}
+
+
+uchar ispWriteFlash(unsigned int address, uchar data, uchar pollmode) {
+
+  /* 0xFF is value after chip erase, so skip programming
+  if (data == 0xFF) {
+    return 0;
+  }
+  */
+
+  ispTransmit(0x40 | ((address & 1) << 3));
+  ispTransmit(address >> 9);
+  ispTransmit(address >> 1);
+  ispTransmit(data);
+
+  if (pollmode == 0)
+    return 0;
+
+  if (data == 0x7F) {
+    clockWait(15); /* wait 4,8 ms */
+    return 0;
+  } else {
+
+    /* polling flash */
+    uchar retries = 30;
+    uint8_t starttime = TIMERVALUE;
+    while (retries != 0) {
+      if (ispReadFlash(address) != 0x7F) {
+       return 0;
+      };
+
+      if ((uint8_t) (TIMERVALUE - starttime) > CLOCK_T_320us) {
+       starttime = TIMERVALUE;
+       retries --;
+      }
+
+    }
+    return 1; /* error */
+  }
+
+}
+
+
+uchar ispFlushPage(unsigned int address, uchar pollvalue) {
+  ispTransmit(0x4C);
+  ispTransmit(address >> 9);
+  ispTransmit(address >> 1);
+  ispTransmit(0);
+
+
+  if (pollvalue == 0xFF) {
+    clockWait(15);
+    return 0;
+  } else {
+
+    /* polling flash */
+    uchar retries = 30;
+    uint8_t starttime = TIMERVALUE;
+
+    while (retries != 0) {
+      if (ispReadFlash(address) != 0xFF) {
+       return 0;
+      };
+
+      if ((uint8_t) (TIMERVALUE - starttime) > CLOCK_T_320us) {
+       starttime = TIMERVALUE;
+       retries --;
+      }
+
+    }
+
+    return 1; /* error */
+  }
+
+}
+
+
+uchar ispReadEEPROM(unsigned int address) {
+  ispTransmit(0xA0);
+  ispTransmit(address >> 8);
+  ispTransmit(address);
+  return ispTransmit(0);
+}
+
+
+uchar ispWriteEEPROM(unsigned int address, uchar data) {
+
+  ispTransmit(0xC0);
+  ispTransmit(address >> 8);
+  ispTransmit(address);
+  ispTransmit(data);
+
+  clockWait(30); // wait 9,6 ms
+
+  return 0;
+  /*
+  if (data == 0xFF) {
+    clockWait(30); // wait 9,6 ms
+    return 0;
+  } else {
+
+    // polling eeprom
+    uchar retries = 30; // about 9,6 ms
+    uint8_t starttime = TIMERVALUE;
+
+    while (retries != 0) {
+      if (ispReadEEPROM(address) != 0xFF) {
+       return 0;
+      };
+
+      if ((uint8_t) (TIMERVALUE - starttime) > CLOCK_T_320us) {
+       starttime = TIMERVALUE;
+       retries --;
+      }
+
+    }
+    return 1; // error
+  }
+  */
+
+}
diff --git a/firmware/isp.h b/firmware/isp.h
new file mode 100644 (file)
index 0000000..7b83201
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+  isp.h - part of USBasp
+
+  Autor..........: Thomas Fischl <tfischl@gmx.de>
+  Description....: Provides functions for communication/programming
+                   over ISP interface
+  Licence........: Free under certain conditions. See Documentation.
+  Creation Date..: 2005-02-23
+  Last change....: 2005-04-20
+*/
+
+#ifndef __isp_h_included__
+#define        __isp_h_included__
+
+#ifndef uchar
+#define        uchar   unsigned char
+#endif
+
+#define        ISP_OUT   PORTB
+#define ISP_IN    PINB
+#define ISP_DDR   DDRB
+#define ISP_RST   PB2
+#define ISP_MOSI  PB3
+#define ISP_MISO  PB4
+#define ISP_SCK   PB5
+
+#define ISP_DELAY 1
+#define ISP_SCK_SLOW 0
+#define ISP_SCK_FAST 1
+
+/* Prepare connection to target device */
+void ispConnect();
+
+/* Close connection to target device */
+void ispDisconnect();
+
+/* read an write a byte from isp using software (slow) */
+uchar ispTransmit_sw(uchar send_byte);
+
+/* read an write a byte from isp using hardware (fast) */
+uchar ispTransmit_hw(uchar send_byte);
+
+/* enter programming mode */
+uchar ispEnterProgrammingMode();
+
+/* read byte from eeprom at given address */
+uchar ispReadEEPROM(unsigned int address);
+
+/* write byte to flash at given address */
+uchar ispWriteFlash(unsigned int address, uchar data, uchar pollmode);
+
+uchar ispFlushPage(unsigned int address, uchar pollvalue);
+
+/* read byte from flash at given address */
+uchar ispReadFlash(unsigned int address);
+
+/* write byte to eeprom at given address */
+uchar ispWriteEEPROM(unsigned int address, uchar data);
+
+/* pointer to sw or hw transmit function */
+uchar (*ispTransmit)(uchar);
+
+/* set SCK speed. call before ispConnect! */
+void ispSetSCKOption(uchar sckoption);
+
+#endif /* __isp_h_included__ */
diff --git a/firmware/main.c b/firmware/main.c
new file mode 100644 (file)
index 0000000..9d79354
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+  USBasp - USB in-circuit programmer for Atmel AVR controllers
+
+  Thomas Fischl <tfischl@gmx.de>
+
+  License:
+  The project is built with AVR USB driver by Objective Development, which is
+  published under an own licence based on the GNU General Public License (GPL).
+  USBasp is also distributed under this enhanced licence. See Documentation.
+
+  Target.........: ATMega8 at 12 MHz
+  Creation Date..: 2005-02-20
+  Last change....: 2005-04-20
+
+  PC2 SCK speed option. GND  -> slow (8khz SCK),
+                        open -> fast (375kHz SCK)
+*/
+
+#include <avr/io.h>
+#include <avr/signal.h>
+#include <avr/interrupt.h>
+#include <avr/pgmspace.h>
+#include <avr/wdt.h>
+
+#include "usbdrv.h"
+#include "isp.h"
+#include "clock.h"
+
+#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 PROG_STATE_IDLE         0
+#define PROG_STATE_WRITEFLASH   1
+#define PROG_STATE_READFLASH    2
+#define PROG_STATE_READEEPROM   3
+#define PROG_STATE_WRITEEEPROM  4
+
+#define PROG_BLOCKFLAG_FIRST    1
+#define PROG_BLOCKFLAG_LAST     2
+
+#define ledRedOn()    PORTC &= ~(1 << PC1)
+#define ledRedOff()   PORTC |= (1 << PC1)
+#define ledGreenOn()  PORTC &= ~(1 << PC0)
+#define ledGreenOff() PORTC |= (1 << PC0)
+
+static uchar replyBuffer[8];
+
+static uchar prog_state = PROG_STATE_IDLE;
+
+static unsigned int prog_address;
+static unsigned int prog_nbytes = 0;
+static uchar prog_pagesize;
+static uchar prog_blockflags;
+static uchar prog_pagecounter;
+
+
+uchar usbFunctionSetup(uchar data[8]) {
+
+  uchar len = 0;
+
+  if(data[1] == USBASP_FUNC_CONNECT){
+
+    /* set SCK speed */
+    if ((PINC & (1 << PC2)) == 0) {
+      ispSetSCKOption(ISP_SCK_SLOW);
+    } else {
+      ispSetSCKOption(ISP_SCK_FAST);
+    }
+
+    ispConnect();
+    ledRedOn();
+
+  } else if (data[1] == USBASP_FUNC_DISCONNECT) {
+    ispDisconnect();
+    ledRedOff();
+
+  } else if (data[1] == USBASP_FUNC_TRANSMIT) {
+    replyBuffer[0] = ispTransmit(data[2]);
+    replyBuffer[1] = ispTransmit(data[3]);
+    replyBuffer[2] = ispTransmit(data[4]);
+    replyBuffer[3] = ispTransmit(data[5]);
+    len = 4;
+
+  } else if (data[1] == USBASP_FUNC_READFLASH) {
+    prog_address = (data[3] << 8) | data[2];
+    prog_nbytes = (data[7] << 8) | data[6];
+    prog_state = PROG_STATE_READFLASH;
+    len = 0xff; /* multiple in */
+
+  } else if (data[1] == USBASP_FUNC_READEEPROM) {
+    prog_address = (data[3] << 8) | data[2];
+    prog_nbytes = (data[7] << 8) | data[6];
+    prog_state = PROG_STATE_READEEPROM;
+    len = 0xff; /* multiple in */
+
+  } else if (data[1] == USBASP_FUNC_ENABLEPROG) {
+    replyBuffer[0] = ispEnterProgrammingMode();;
+    len = 1;
+
+  } else if (data[1] == USBASP_FUNC_WRITEFLASH) {
+    prog_address = (data[3] << 8) | data[2];
+    prog_pagesize = data[4];
+    prog_blockflags = data[5];
+    if (prog_blockflags & PROG_BLOCKFLAG_FIRST) {
+      prog_pagecounter = prog_pagesize;
+    }
+    prog_nbytes = (data[7] << 8) | data[6];
+    prog_state = PROG_STATE_WRITEFLASH;
+    len = 0xff; /* multiple out */
+
+  } else if (data[1] == USBASP_FUNC_WRITEEEPROM) {
+    prog_address = (data[3] << 8) | data[2];
+    prog_pagesize = 0;
+    prog_blockflags = 0;
+    prog_nbytes = (data[7] << 8) | data[6];
+    prog_state = PROG_STATE_WRITEEEPROM;
+    len = 0xff; /* multiple out */
+  }
+
+  usbMsgPtr = replyBuffer;
+
+  return len;
+}
+
+
+uchar usbFunctionRead(uchar *data, uchar len) {
+
+  uchar i;
+
+  /* check if programmer is in correct read state */
+  if ((prog_state != PROG_STATE_READFLASH) &&
+      (prog_state != PROG_STATE_READEEPROM)) {
+    return 0xff;
+  }
+
+  /* fill packet */
+  for (i = 0; i < len; i++) {
+    if (prog_state == PROG_STATE_READFLASH) {
+      data[i] = ispReadFlash(prog_address);
+    } else {
+      data[i] = ispReadEEPROM(prog_address);
+    }
+    prog_address++;
+  }
+
+  /* last packet? */
+  if (len < 8) {
+    prog_state = PROG_STATE_IDLE;
+  }
+
+  return len;
+}
+
+
+uchar usbFunctionWrite(uchar *data, uchar len) {
+
+  uchar i;
+
+  /* check if programmer is in correct write state */
+  if ((prog_state != PROG_STATE_WRITEFLASH) &&
+      (prog_state != PROG_STATE_WRITEEEPROM)) {
+    return 0xff;
+  }
+
+
+  for (i = 0; i < len; i++) {
+
+    if (prog_state == PROG_STATE_WRITEFLASH) {
+      /* Flash */
+
+      if (prog_pagesize == 0) {
+       /* not paged */
+       ispWriteFlash(prog_address, data[i], 1);
+      } else {
+       /* paged */
+       ispWriteFlash(prog_address, data[i], 0);
+       prog_pagecounter --;
+       if (prog_pagecounter == 0) {
+         ispFlushPage(prog_address, data[i]);
+         prog_pagecounter = prog_pagesize;
+       }
+      }
+
+    } else {
+      /* EEPROM */
+      ispWriteEEPROM(prog_address, data[i]);
+    }
+
+    prog_nbytes --;
+
+    if (prog_nbytes == 0) {
+      prog_state = PROG_STATE_IDLE;
+      if ((prog_blockflags & PROG_BLOCKFLAG_LAST) &&
+         (prog_pagecounter != prog_pagesize)) {
+
+       /* last block and page flush pending, so flush it now */
+       ispFlushPage(prog_address, data[i]);
+      }
+    }
+
+    prog_address ++;
+  }
+
+  return 0;
+}
+
+
+int main(void)
+{
+  PORTD = 0;
+  PORTB = 0;           /* no pullups on USB and ISP pins */
+  DDRD = ~(1 << 2);    /* all outputs except PD2 = INT0 */
+  DDRB = 0;             /* all USB and ISP pins inputs */
+
+  DDRC = 0x03;          /* all inputs except PC0, PC1 */
+  PORTC = 0xfe;
+
+  clockInit();          /* init timer */
+
+  ispSetSCKOption(ISP_SCK_FAST);
+
+  usbInit();
+  sei();
+  for(;;){             /* main event loop */
+    usbPoll();
+  }
+  return 0;
+}
diff --git a/firmware/usbconfig.h b/firmware/usbconfig.h
new file mode 100644 (file)
index 0000000..04b9749
--- /dev/null
@@ -0,0 +1,117 @@
+/* Name: usbconfig.h
+ * Project: AVR USB driver
+ * Author: Christian Starkjohann
+ * Creation Date: 2005-04-01
+ * Tabsize: 4
+ * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
+ * License: Proprietary, free under certain conditions. See Documentation.
+ * This Revision: $Id: usbconfig.h 43 2005-04-10 21:04:36Z cs $
+ */
+
+#ifndef __usbconfig_h_included__
+#define        __usbconfig_h_included__
+
+/*
+General Description:
+This file contains parts of the USB driver which can be configured and can or
+must be adapted to your hardware.
+*/
+
+/* ---------------------------- Hardware Config ---------------------------- */
+
+#define        USB_CFG_IOPORT                  PORTB
+/* This is the port where the USB bus is connected. When you configure it to
+ * "PORTB", the registers PORTB, PINB (=PORTB+2) and DDRB (=PORTB+1) will be
+ * used.
+ */
+#define        USB_CFG_DMINUS_BIT              0
+/* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected.
+ * This MUST be bit 0. All other values will result in a compile error!
+ */
+#define        USB_CFG_DPLUS_BIT               1
+/* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected.
+ * This may be any bit in the port. Please note that D+ must also be connected
+ * to interrupt pin INT0!
+ */
+
+/* --------------------------- Functional Range ---------------------------- */
+
+#define        USB_CFG_HAVE_INTRIN_ENDPOINT    0
+/* Define this to 1 if you want to compile a version with two endpoints: The
+ * default control endpoint 0 and an interrupt-in endpoint 1.
+ */
+#define        USB_CFG_INTR_POLL_INTERVAL              10
+/* If you compile a version with endpoint 1 (interrupt-in), this is the poll
+ * interval. The value is in milliseconds and must not be less than 10 ms for
+ * low speed devices.
+ */
+#define        USB_CFG_IS_SELF_POWERED                 0
+/* Define this to 1 if the device has its own power supply. Set it to 0 if the
+ * device is powered from the USB bus.
+ */
+#define        USB_CFG_MAX_BUS_POWER                   50
+/* Set this variable to the maximum USB bus power consumption of your device.
+ * The value is in milliamperes. [It will be divided by two since USB
+ * communicates power requirements in units of 2 mA.]
+ */
+#define        USB_CFG_SAMPLE_EXACT                    0
+/* This variable affects Sampling Jitter for USB receiving. When it is 0, the
+ * driver guarantees a sampling window of 1/2 bit. The USB spec requires
+ * that the receiver has at most 1/4 bit sampling window. The 1/2 bit window
+ * should still work reliably enough because we work at low speed. If you want
+ * to meet the spec, set this value to 1. This will unroll a loop which
+ * results in bigger code size.
+ * If you have problems with long cables, try setting this value to 1.
+ */
+#define USB_CFG_IMPLEMENT_FN_WRITE             1
+/* Set this to 1 if you want usbFunctionWrite() to be called for control-out
+ * transfers. Set it to 0 if you don't need it and want to save a couple of
+ * bytes.
+ */
+#define USB_CFG_IMPLEMENT_FN_READ              1
+/* Set this to 1 if you need to send control replies which are generated
+ * "on the fly" when usbFunctionRead() is called. If you only want to send
+ * data from a static buffer, set it to 0 and return the data from
+ * usbFunctionSetup(). This saves a couple of bytes.
+ */
+
+/* -------------------------- Device Description --------------------------- */
+
+#define        USB_CFG_VENDOR_ID               0xeb, 0x03
+/* USB vendor ID for the device, low byte first. 0xeb, 0x03 is Atmel's vendor
+ * ID. Don't use it for hardware you sell or publish!
+ */
+#define        USB_CFG_DEVICE_ID               0xb4, 0xc7
+/* This is the ID of the device, low byte first. It is interpreted in the
+ * scope of the vendor ID. The only requirement is that no two devices may
+ * share the same product and vendor IDs. Not even if the devices are never
+ * on the same bus together!
+ */
+#define        USB_CFG_DEVICE_VERSION  0x00, 0x01
+/* Version number of the device: Minor number first, then major number.
+ */
+#define        USB_CFG_VENDOR_NAME             'w', 'w', 'w', '.', 'f', 'i', 's', 'c', 'h', 'l', '.', 'a', 't'
+#define        USB_CFG_VENDOR_NAME_LEN 13
+/* These two values define the vendor name returned by the USB device. The name
+ * must be given as a list of characters under single quotes. The characters
+ * are interpreted as Unicode (UTF-16) entities.
+ * If you don't want a vendor name string, undefine these macros.
+ */
+#define        USB_CFG_DEVICE_NAME             'U', 'S', 'B', 'a', 's', 'p'
+#define        USB_CFG_DEVICE_NAME_LEN 6
+/* Same as above for the device name. If you don't want a device name, undefine
+ * the macros.
+ */
+#define        USB_CFG_DEVICE_CLASS    0xff
+#define        USB_CFG_DEVICE_SUBCLASS 0
+/* See USB specification if you want to conform to an existing device class.
+ */
+#define        USB_CFG_INTERFACE_CLASS         0
+#define        USB_CFG_INTERFACE_SUBCLASS      0
+#define        USB_CFG_INTERFACE_PROTOCOL      0
+/* See USB specification if you want to conform to an existing device class or
+ * protocol.
+ */
+
+
+#endif /* __usbconfig_h_included__ */
diff --git a/firmware/usbdrv/Changelog.txt b/firmware/usbdrv/Changelog.txt
new file mode 100644 (file)
index 0000000..3b641d2
--- /dev/null
@@ -0,0 +1,18 @@
+This file documents changes in the software, firmware and hardware of the
+"Remote Sensor" device. New entries are always appended to the end of the file.
+Scroll down to the bottom to see the most recent changes.
+
+2005-04-01:
+  - Implemented endpoint 1 as interrupt-in endpoint.
+  - Moved all configuration options to usbconfig.h which is not part of the
+    driver.
+  - Changed interface for usbVendorSetup().
+  - Fixed compatibility with ATMega8 device.
+  - Various minor optimizations.
+
+2005-04-11:
+  - Changed interface to application: Use usbFunctionSetup(), usbFunctionRead()
+    and usbFunctionWrite() now. Added configuration options to choose which
+    of these functions to compile in.
+  - Assembler module delivers receive data non-inverted now.
+  - Made register and bit names compatible with more AVR devices.
diff --git a/firmware/usbdrv/License.txt b/firmware/usbdrv/License.txt
new file mode 100644 (file)
index 0000000..93432ee
--- /dev/null
@@ -0,0 +1,457 @@
+PREFACE
+
+Conceiving and understanding a new license is not an easy task. To make things
+easier for both, the author and the licensee, we have decided to base our
+license for the USB driver on an existing license with well-understood
+properties.
+
+Our favorite choice for the base license was the GNU General Public License
+(GPL). However, we cannot use the GNU GPL directly for the following reasons:
+
+(1) It was not intended for projects involving hardware -- we must extend the
+    term "source code" to at least the circuit diagram.
+(2) The GNU GPL does not require publication. Only if a binary is published,
+    it requires that the source is published as well. This is reasonable for
+    software because unpublished software is of little relevance. For projects
+    involving hardware, we want to REQUIRE publication. More than that, we
+    even want to define HOW the publication must be done (files contained,
+    file formats etc).
+(3) As the author of the software, we can distribute it under more than one
+    license. For people who don't want to meet the obligations of the GNU GPL,
+    we want to offer pay-by-unit business licenses. To avoid a split in
+    revisions of the driver, we need special privileges to distribute
+    contributed modifications under other licenses.
+
+We can not simply modify the GNU GPL and incorporate our changes because the
+Free Software Foundation (FSF) who holds the copyright for the text of the
+GNU GPL does not allow modifications. We therefore set up our own small
+license which incorporates the GNU GPL by reference:
+
+
+
+LICENSE FOR PROJECTS BUILT WITH "OBJECTIVE DEVELOPMENT'S
+FIRMWARE-ONLY USB-DRIVER FOR ATMEL'S AVR MICROCONTROLLERS"
+Version 2005-02
+
+
+I. Definitions
+
+"OBDEV" shall mean OBJECTIVE DEVELOPMENT Software GmbH or any legal successor
+thereof.
+
+"Software Source Code" shall mean the preferred form of the software for
+making modifications to it.
+
+"USB Driver" shall mean the Software Source Code for OBDEV's firmware-only
+USB-driver for Atmel's AVR microcontrollers.
+
+"Function" shall mean the Software Source Code for all software executed on
+the microcontroller except the USB Driver.
+
+"Host Software" shall mean the Software Source Code for all software required
+to control the USB device from the USB host running any operating system.
+
+"Project" shall mean the USB Driver, the Function, the Host Software, circuit
+diagrams of the controller based hardware and accompanying documentation.
+
+"source code" shall have the same meaning as the term "Project" above.
+
+"Web Site" shall mean a collection of text and multimedia documents accessible
+worldwide over internet through the HyperText Transfer Protocol (HTTP) on
+TCP port 80 (standard HTTP port).
+
+
+II. General License Terms
+The general terms of this license consist of the GNU General Public License
+Version 2 (GNU GPL2) which is hereby incorporated into this section as though
+it were fully set forth here. A copy of the GNU GPL2 is included for your
+convenience in appendix A of this license.
+
+The term "source code" in the GNU GPL2 is to be understood as defined in
+section I above. If any term or definition in section I, III, IV or V
+conflicts with the GNU GPL2, the term or definition in section I, III, IV or
+V has precedence of the GNU GPL2.
+
+
+III. Distribution of the Project
+The distributed form of a Project must contain at least the following files:
+(a) Software Source Code files for the USB Driver, the Function and the Host
+    Software.
+(b) Circuit diagrams for the hardware in PDF, PNG or GIF image file format.
+(c) A file with name "Readme.txt" in ASCII format with at least the following
+    content (in English language):
+    - An explanation what the Project does.
+    - What to do with the distributed files (installation procedure etc.).
+    - A reference to Objective Development's USB driver.
+    - Your (author's) name and contact information. E-mail and/or URL is
+      sufficient.
+(d) Optionally a text file with a description of the circuit diagram, an
+    explanation of special (software) techniques used etc.
+(e) A copy of this license in a file with the name "License.txt".
+
+
+IV. Requirement for Publication
+All modifications and derived work (Projects using the USB Driver) MUST be
+distributed (published) as described in section III above on a Web Site. The
+main page must reproduce at least a description of the Project (e.g. as
+contained in the "Readme.txt" file distributed) and a download link for the
+entire Project. The URL of the main page must be submitted to OBDEV. OBDEV
+will provide a mechanism for submitting Project URLs and for publishing
+Projects on their Web Site. The Project must remain available for at least
+twelve (12) months after the initial publication or at least six (6) months
+after a subsequent version of that particular Project has been published.
+
+
+V. Author Privileges
+OBDEV reserves the right to distribute the USB Driver and all modified
+versions under other (proprietary) licenses. If you modify the USB Driver
+under the grants of this license, you therefore grant OBDEV (in addition to
+the grants of the GNU GPL2) a worldwide, perpetual, irrevocable royalty free
+license for your modifications. OBDEV shall not automatically gain rights
+other than those of the GNU GPL2 in the other parts of the Project. This
+section V overrides possibly contradicting terms in the GNU GPL2 referenced
+in section II.
+
+
+APPENDIX A
+
+                   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.
+\f
+                   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.)
+\f
+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.
+\f
+  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.
+\f
+  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
+\f
+           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/firmware/usbdrv/oddebug.c b/firmware/usbdrv/oddebug.c
new file mode 100644 (file)
index 0000000..5c5e7b1
--- /dev/null
@@ -0,0 +1,51 @@
+/* Name: oddebug.c
+ * Project: AVR library
+ * Author: Christian Starkjohann
+ * Creation Date: 2005-01-16
+ * Tabsize: 4
+ * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
+ * License: Proprietary, free under certain conditions. See Documentation.
+ * This Revision: $Id: oddebug.c 52 2005-04-12 16:57:29Z cs $
+ */
+
+#include <avr/io.h>
+#include "oddebug.h"
+
+#if    DEBUG_LEVEL > 0
+
+static void    uartPutc(char c)
+{
+       while(!(ODDBG_USR & (1 << UDRE)));      /* wait for data register empty */
+       ODDBG_UDR = c;
+}
+
+static uchar   hexAscii(uchar h)
+{
+       h &= 0xf;
+       if(h < 10){
+               h += '0';
+       }else{
+               h += 'a' - (uchar)10;
+       }
+       return h;
+}
+
+static void    printHex(uchar c)
+{
+       uartPutc(hexAscii(c >> 4));
+       uartPutc(hexAscii(c));
+}
+
+void   odDebug(uchar prefix, uchar *data, uchar len)
+{
+       printHex(prefix);
+       uartPutc(':');
+       while(len--){
+               uartPutc(' ');
+               printHex(*data++);
+       }
+       uartPutc('\r');
+       uartPutc('\n');
+}
+
+#endif
diff --git a/firmware/usbdrv/oddebug.h b/firmware/usbdrv/oddebug.h
new file mode 100644 (file)
index 0000000..28d5f94
--- /dev/null
@@ -0,0 +1,110 @@
+/* Name: oddebug.h
+ * Project: AVR library
+ * Author: Christian Starkjohann
+ * Creation Date: 2005-01-16
+ * Tabsize: 4
+ * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
+ * License: Proprietary, free under certain conditions. See Documentation.
+ * This Revision: $Id: oddebug.h 52 2005-04-12 16:57:29Z cs $
+ */
+
+#ifndef __oddebug_h_included__
+#define __oddebug_h_included__
+
+#include <avr/io.h>
+
+/*
+General Description:
+This module implements a function for debug logs on the serial line of the
+AVR microcontroller. Debugging can be configured with the define
+'DEBUG_LEVEL'. If this macro is not defined or defined to 0, all debugging
+calls are no-ops. If it is 1, DBG1 logs will appear, but not DBG2. If it is
+2, DBG1 and DBG2 logs will be printed.
+
+A debug log consists of a label ('prefix') to indicate which debug log created
+the output and a memory block to dump in hex ('data' and 'len').
+*/
+
+
+#ifndef F_CPU
+#      define  F_CPU   12000000        /* 12 MHz */
+#endif
+
+#ifndef uchar
+#      define  uchar   unsigned char
+#endif
+
+#if DEBUG_LEVEL > 0 && !defined TXEN   /* no UART in device */
+#      warning "Debugging disabled because device has no UART"
+#      undef   DEBUG_LEVEL
+#endif
+
+#ifndef DEBUG_LEVEL
+#      define  DEBUG_LEVEL     0
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+#if DEBUG_LEVEL > 0
+#      define  DBG1(prefix, data, len) odDebug(prefix, data, len)
+#else
+#      define  DBG1(prefix, data, len)
+#endif
+
+#if DEBUG_LEVEL > 1
+#      define  DBG2(prefix, data, len) odDebug(prefix, data, len)
+#else
+#      define  DBG2(prefix, data, len)
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+#if    DEBUG_LEVEL > 0
+extern void    odDebug(uchar prefix, uchar *data, uchar len);
+
+/* Try to find our control registers; ATMEL likes to rename these */
+
+#if defined UBRR
+#      define  ODDBG_UBRR      UBRR
+#elif defined UBRRL
+#      define  ODDBG_UBRR      UBRRL
+#elif defined UBRR1
+#      define  ODDBG_UBRR      UBRR1
+#elif defined UBRR1L
+#      define  ODDBG_UBRR      UBRR1L
+#endif
+
+#if defined UCR
+#      define  ODDBG_UCR       UCR
+#elif defined UCSRB
+#      define  ODDBG_UCR       UCSRB
+#elif defined UCSR1B
+#      define  ODDBG_UCR       UCSR1B
+#endif
+
+#if defined    USR
+#      define  ODDBG_USR       USR
+#elif defined UCSRA
+#      define  ODDBG_USR       UCSRA
+#elif defined UCSR1A
+#      define  ODDBG_USR       UCSR1A
+#endif
+
+#if defined UDR
+#      define  ODDBG_UDR       UDR
+#elif defined UDR1
+#      define  ODDBG_UDR       UDR1
+#endif
+
+static inline void     odDebugInit(void)
+{
+       ODDBG_UCR |= (1<<TXEN);
+       ODDBG_UBRR = F_CPU / (19200 * 16L) - 1;
+}
+#else
+#      define odDebugInit()
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+#endif /* __oddebug_h_included__ */
diff --git a/firmware/usbdrv/oddebug.o b/firmware/usbdrv/oddebug.o
new file mode 100644 (file)
index 0000000..ed64069
Binary files /dev/null and b/firmware/usbdrv/oddebug.o differ
diff --git a/firmware/usbdrv/usbdrv.c b/firmware/usbdrv/usbdrv.c
new file mode 100644 (file)
index 0000000..7145fdd
--- /dev/null
@@ -0,0 +1,429 @@
+/* Name: usbdrv.c
+ * Project: AVR USB driver
+ * Author: Christian Starkjohann
+ * Creation Date: 2004-12-29
+ * Tabsize: 4
+ * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
+ * License: Proprietary, free under certain conditions. See Documentation.
+ * This Revision: $Id: usbdrv.c 53 2005-04-12 17:11:29Z cs $
+ */
+
+#include <avr/io.h>
+#include <avr/pgmspace.h>
+#include "usbdrv.h"
+#include "oddebug.h"
+
+/*
+General Description:
+This module implements the C-part of the USB driver. See usbdrv.h for a
+documentation of the entire driver.
+*/
+
+/* ------------------------------------------------------------------------- */
+
+/* raw USB registers / interface to assembler code: */
+/* usbRxBuf MUST be in 1 byte addressable range (because usbInputBuf is only 1 byte) */
+static char    usbRxBuf[2][USB_BUFSIZE];/* raw RX buffer: PID, 8 bytes data, 2 bytes CRC */
+uchar          usbDeviceId;            /* assigned during enumeration, defaults to 0 */
+uchar          usbInputBuf;            /* ptr to raw buffer used for receiving */
+uchar          usbAppBuf;                      /* ptr to raw buffer passed to app for processing */
+volatile char usbRxLen;                        /* = 0; number of bytes in usbAppBuf; 0 means free */
+uchar          usbCurrentTok;          /* last token received */
+uchar          usbRxToken;                     /* token for data we received */
+uchar          usbMsgLen = 0xff;       /* remaining number of bytes, no msg to send if -1 (see usbMsgPtr) */
+volatile char usbTxLen = -1;   /* number of bytes to transmit with next IN token */
+uchar          usbTxBuf[USB_BUFSIZE];/* data to transmit with next IN, free if usbTxLen == -1 */
+#if USB_CFG_HAVE_INTRIN_ENDPOINT
+/* uchar               usbRxEndp;              endpoint which was addressed (1 bit in MSB) [not impl] */
+volatile char usbTxLen1 = -1;  /* TX count for endpoint 1 */
+uchar          usbTxBuf1[USB_BUFSIZE];/* TX data for endpoint 1 */
+#endif
+uchar          usbAckBuf[1] = {USBPID_ACK};    /* transmit buffer for ack tokens */
+uchar          usbNakBuf[1] = {USBPID_NAK};    /* transmit buffer for nak tokens */
+
+/* USB status registers / not shared with asm code */
+uchar                  *usbMsgPtr;             /* data to transmit next -- ROM or RAM address */
+static uchar   usbMsgFlags;    /* flag values see below */
+static uchar   usbNewDeviceId; /* = 0; device ID which should be set after status phase */
+static uchar   usbIsReset;             /* = 0; USB bus is in reset phase */
+
+#define        USB_FLG_TX_PACKET               (1<<0)
+/* Leave free 6 bits after TX_PACKET. This way we can increment usbMsgFlags to toggle TX_PACKET */
+#define        USB_FLG_MSGPTR_IS_ROM   (1<<6)
+#define        USB_FLG_USE_DEFAULT_RW  (1<<7)
+
+/*
+optimizing hints:
+- do not post/pre inc/dec integer values in operations
+- assign value of PRG_RDB() to register variables and don't use side effects in arg
+- use narrow scope for variables which should be in X/Y/Z register
+- assign char sized expressions to variables to force 8 bit arithmetics
+*/
+
+/* ------------------------------------------------------------------------- */
+
+static char    usbDescrDevice[] PROGMEM = {    /* USB device descriptor */
+       18,                     /* sizeof(usbDescrDevice): length of descriptor in bytes */
+       1,                      /* descriptor type */
+       0x01, 0x01,     /* USB version supported */
+       USB_CFG_DEVICE_CLASS,
+       USB_CFG_DEVICE_SUBCLASS,
+       0,                      /* protocol */
+       8,                      /* max packet size */
+       USB_CFG_VENDOR_ID,      /* 2 bytes */
+       USB_CFG_DEVICE_ID,      /* 2 bytes */
+       USB_CFG_DEVICE_VERSION, /* 2 bytes */
+#if USB_CFG_VENDOR_NAME_LEN
+       1,                      /* manufacturer string index */
+#else
+       0,                      /* manufacturer string index */
+#endif
+#if USB_CFG_DEVICE_NAME_LEN
+       2,                      /* product string index */
+#else
+       0,                      /* product string index */
+#endif
+       0,                      /* serial number string index */
+       1,                      /* number of configurations */
+};
+
+static char    usbDescrConfig[] PROGMEM = {    /* USB configuration descriptor */
+       9,                      /* sizeof(usbDescrConfig): length of descriptor in bytes */
+       2,                      /* descriptor type */
+       (18 + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT), 0,     /* total length of data returned (including inlined descriptors) */
+       1,                      /* number of interfaces in this configuration */
+       1,                      /* index of this configuration */
+       0,                      /* configuration name string index */
+#if USB_CFG_IS_SELF_POWERED
+       USBATTR_SELFPOWER,      /* attributes */
+#else
+       USBATTR_BUSPOWER,       /* attributes */
+#endif
+       USB_CFG_MAX_BUS_POWER/2,                        /* max USB current in 2mA units */
+/* interface descriptor follows inline: */
+       9,                      /* sizeof(usbDescrInterface): length of descriptor in bytes */
+       4,                      /* descriptor type */
+       0,                      /* index of this interface */
+       0,                      /* alternate setting for this interface */
+       USB_CFG_HAVE_INTRIN_ENDPOINT,   /* endpoints excl 0: number of endpoint descriptors to follow */
+       USB_CFG_INTERFACE_CLASS,
+       USB_CFG_INTERFACE_SUBCLASS,
+       USB_CFG_INTERFACE_PROTOCOL,
+       0,                      /* string index for interface */
+#if USB_CFG_HAVE_INTRIN_ENDPOINT       /* endpoint descriptor for endpoint 1 */
+       7,                      /* sizeof(usbDescrEndpoint) */
+       5,                      /* descriptor type = endpoint */
+       0x81,           /* IN endpoint number 1 */
+       0x03,           /* attrib: Interrupt endpoint */
+       8, 0,           /* maximum packet size */
+       USB_CFG_INTR_POLL_INTERVAL,     /* in ms */
+#endif
+};
+
+static char    usbDescrString0[] PROGMEM = {   /* language descriptor */
+       4,                      /* sizeof(usbDescrString0): length of descriptor in bytes */
+       3,                      /* descriptor type */
+       0x09, 0x04,     /* language index (0x0409 = US-English) */
+};
+
+#if USB_CFG_VENDOR_NAME_LEN
+static int     usbDescrString1[] PROGMEM = {
+       (2 * USB_CFG_VENDOR_NAME_LEN + 2) | (3<<8),     /* length of descriptor in bytes | descriptor type */
+       USB_CFG_VENDOR_NAME
+};
+#endif
+#if USB_CFG_DEVICE_NAME_LEN
+static int     usbDescrString2[] PROGMEM = {
+       (2 * USB_CFG_DEVICE_NAME_LEN + 2) | (3<<8),     /* length of descriptor in bytes | descriptor type */
+       USB_CFG_DEVICE_NAME
+};
+#endif
+
+/* We don't use prog_int or prog_int16_t for compatibility with various libc
+ * versions. Here's an other compatibility hack:
+ */
+#ifndef PRG_RDB
+#define        PRG_RDB(addr)   pgm_read_byte(addr)
+#endif
+
+typedef union{
+       unsigned        word;
+       uchar           *ptr;
+       uchar           bytes[2];
+}converter_t;
+/* We use this union to do type conversions. This is better optimized than
+ * type casts in gcc 3.4.3 and much better than using bit shifts to build
+ * ints from chars. Byte ordering is not a problem on an 8 bit platform.
+ */
+
+/* ------------------------------------------------------------------------- */
+
+#if USB_CFG_HAVE_INTRIN_ENDPOINT
+static uchar   usbTxPacketCnt1;
+
+void   usbSetInterrupt(uchar *data, uchar len)
+{
+uchar          *p, i;
+converter_t    crc;
+
+       if(len > 7)
+               len = 7;
+       i = USBPID_DATA1;
+       if(usbTxPacketCnt1 & 1)
+               i = USBPID_DATA0;
+       if(usbTxLen1 < 0){              /* packet buffer was empty */
+               usbTxPacketCnt1++;
+       }else{
+               usbTxLen1 = -1;         /* avoid sending incomplete interrupt data */
+       }
+       p = usbTxBuf1;
+       *p++ = i;
+       for(i=len;i--;)
+               *p++ = *data++;
+       crc.word = usbCrc16(&usbTxBuf1[1], len);
+       usbTxBuf1[len + 1] = crc.bytes[0];
+       usbTxBuf1[len + 2] = crc.bytes[1];
+       usbTxLen1 = len + 4;    /* len must be given including sync byte */
+}
+#endif
+
+static void    usbWrite(uchar *data, uchar len)
+{
+#if USB_CFG_IMPLEMENT_FN_WRITE
+       if(!(usbMsgFlags & USB_FLG_USE_DEFAULT_RW)){
+               if(usbFunctionWrite(data, len) == 0xff){        /* an error occurred */
+                       /* usbMsgLen = 0xff; cancel potentially pending ACK [has been done by ASM module when OUT token arrived] */
+                       usbTxBuf[0] = USBPID_STALL;
+                       usbTxLen = 2;           /* length including sync byte */
+                       return;
+               }
+       }
+#endif
+       usbMsgLen = 0;          /* send zero-sized block as ACK */
+       usbMsgFlags = 0;        /* start with a DATA1 package */
+}
+
+static uchar   usbRead(uchar *data, uchar len)
+{
+#if USB_CFG_IMPLEMENT_FN_READ
+       if(usbMsgFlags & USB_FLG_USE_DEFAULT_RW){
+#endif
+               uchar i = len, *r = usbMsgPtr;
+               if(usbMsgFlags & USB_FLG_MSGPTR_IS_ROM){        /* ROM data */
+                       while(i--){
+                               char c = PRG_RDB(r);    /* assign to char size variable to enforce byte ops */
+                               *data++ = c;
+                               r++;
+                       }
+               }else{                                  /* RAM data */
+                       while(i--)
+                               *data++ = *r++;
+               }
+               usbMsgPtr = r;
+               return len;
+#if USB_CFG_IMPLEMENT_FN_READ
+       }else{
+               if(len != 0)    /* don't bother app with 0 sized reads */
+                       return usbFunctionRead(data, len);
+               return 0;
+       }
+#endif
+}
+
+/* Don't make this function static to avoid inlining.
+ * The entire function would become too large and exceed the range of
+ * relative jumps.
+ */
+void   usbProcessRx(uchar *data, uchar len)
+{
+/* We use if() cascades because the compare is done byte-wise while switch()
+ * is int-based. The if() cascades are therefore more efficient.
+ */
+       DBG2(0x10 + (usbRxToken == (uchar)USBPID_SETUP), data, len);
+       if(usbRxToken == (uchar)USBPID_SETUP){
+               uchar replyLen = 0, flags = USB_FLG_USE_DEFAULT_RW;
+               if(len == 8){   /* Setup size must be always 8 bytes. Ignore otherwise. */
+                       uchar type = data[0] & (3 << 5);
+                       if(type == USBRQ_TYPE_STANDARD << 5){
+                               uchar *replyData = usbTxBuf + 9; /* there is 3 bytes free space at the end of the buffer */
+                               replyData[0] = 0;
+                               if(data[1] == 0){/* GET_STATUS */
+#if USB_CFG_IS_SELF_POWERED
+                                       uchar recipient = data[0] & 0x1f;       /* assign arith ops to variables to enforce byte size */
+                                       if(recipient == USBRQ_RCPT_DEVICE)
+                                               replyData[0] =  USB_CFG_IS_SELF_POWERED;
+#endif
+                                       replyData[1] = 0;
+                                       replyLen = 2;
+                               }else if(data[1] == 5){         /* SET_ADDRESS */
+                                       usbNewDeviceId = data[2];
+                               }else if(data[1] == 6){         /* GET_DESCRIPTOR */
+                                       flags = USB_FLG_MSGPTR_IS_ROM | USB_FLG_USE_DEFAULT_RW;
+                                       if(data[3] == 1){               /* descriptor type requested */
+                                               replyLen = sizeof(usbDescrDevice);
+                                               replyData = (uchar *)usbDescrDevice;
+                                       }else if(data[3] == 2){
+                                               replyLen = sizeof(usbDescrConfig);
+                                               replyData = (uchar *)usbDescrConfig;
+                                       }else if(data[3] == 3){ /* string descriptor */
+                                               if(data[2] == 0){       /* descriptor index */
+                                                       replyLen = sizeof(usbDescrString0);
+                                                       replyData = (uchar *)usbDescrString0;
+#if USB_CFG_VENDOR_NAME_LEN
+                                               }else if(data[2] == 1){
+                                                       replyLen = sizeof(usbDescrString1);
+                                                       replyData = (uchar *)usbDescrString1;
+#endif
+#if USB_CFG_DEVICE_NAME_LEN
+                                               }else if(data[2] == 2){
+                                                       replyLen = sizeof(usbDescrString2);
+                                                       replyData = (uchar *)usbDescrString2;
+#endif
+                                               }
+                                       }
+                               }else if(data[1] == 8){         /* GET_CONFIGURATION */
+                                       replyLen = 1;
+                                       replyData[0] = 1;       /* config is always 1, no setConfig required */
+                               }else if(data[1] == 10){        /* GET_INTERFACE */
+                                       replyLen = 1;
+#if USB_CFG_HAVE_INTRIN_ENDPOINT
+                               }else if(data[1] == 11){        /* SET_INTERFACE */
+                                       usbTxPacketCnt1 = 0;    /* reset data toggling for interrupt socket */
+#endif
+                               }else{
+                                       /* the following requests can be ignored, send default reply */
+                                       /* 1: CLEAR_FEATURE, 3: SET_FEATURE, 7: SET_DESCRIPTOR */
+                                       /* 9: SET_CONFIGURATION, 11: SET_INTERFACE, 12: SYNCH_FRAME */
+                               }
+                               usbMsgPtr = replyData;
+                               if(!data[7] && replyLen > data[6])      /* max length is in data[7]:data[6] */
+                                       replyLen = data[6];
+                       }else{  /* not a standard request -- must be vendor or class request */
+#if USB_CFG_IMPLEMENT_FN_READ || USB_CFG_IMPLEMENT_FN_WRITE
+                               uchar   len;
+                               replyLen = data[6];     /* if this is an OUT operation, the next token will reset usbMsgLen */
+                               if((len = usbFunctionSetup(data)) != 0xff){
+                                       replyLen = len;
+                               }else{
+                                       flags = 0;      /* we have no valid msg, use read/write functions */
+                               }
+#else
+                               replyLen = usbFunctionSetup(data);
+#endif
+                       }
+               }
+               usbMsgLen = replyLen;
+               usbMsgFlags = flags;
+       }else{  /* out request */
+               usbWrite(data, len);
+       }
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void    usbBuildTxBlock(void)
+{
+uchar          wantLen, len, txLen, x;
+converter_t    crc;
+
+       x = USBPID_DATA1;
+       if(usbMsgFlags & USB_FLG_TX_PACKET)
+               x = USBPID_DATA0;
+       usbMsgFlags++;
+       usbTxBuf[0] = x;
+       wantLen = usbMsgLen;
+       if(wantLen > 8)
+               wantLen = 8;
+       usbMsgLen -= wantLen;
+       len = usbRead(usbTxBuf + 1, wantLen);
+       if(len <= 8){   /* valid data packet */
+               crc.word = usbCrc16(&usbTxBuf[1], len);
+               usbTxBuf[len + 1] = crc.bytes[0];
+               usbTxBuf[len + 2] = crc.bytes[1];
+               txLen = len + 4;        /* length including sync byte */
+               if(len < 8)             /* a partial package identifies end of message */
+                       usbMsgLen = 0xff;
+       }else{
+               usbTxBuf[0] = USBPID_STALL;
+               txLen = 2;      /* length including sync byte */
+               usbMsgLen = 0xff;
+       }
+       usbTxLen = txLen;
+       DBG2(0x20, usbTxBuf, txLen-1);
+}
+
+static inline uchar    isNotSE0(void)
+{
+uchar  rval;
+/* We want to do
+ *     return (USBIN & USBMASK);
+ * here, but the compiler does int-expansion acrobatics.
+ * We can avoid this by assigning to a char-sized variable.
+ */
+       rval = USBIN & USBMASK;
+       return rval;
+}
+
+/* ------------------------------------------------------------------------- */
+
+void   usbPoll(void)
+{
+uchar  len;
+
+       if((len = usbRxLen) > 0){
+/* We could check CRC16 here -- but ACK has already been sent anyway. If you
+ * need data integrity checks with this driver, check the CRC in your app
+ * code and report errors back to the host. Since the ACK was already sent,
+ * retries must be handled on application level.
+ * unsigned crc = usbCrc16((uchar *)(unsigned)(usbAppBuf + 1), usbRxLen - 3);
+ */
+               len -= 3;       /* remove PID and CRC */
+               if(len < 128){
+                       usbProcessRx((uchar *)(unsigned)(usbAppBuf + 1), len);
+               }
+               usbRxLen = 0;   /* mark rx buffer as available */
+       }
+       if(usbTxLen < 0){       /* TX system is idle */
+               if(usbMsgLen != 0xff){
+                       usbBuildTxBlock();
+               }else if(usbNewDeviceId){
+                       usbDeviceId = usbNewDeviceId;
+                       DBG1(1, &usbNewDeviceId, 1);
+                       usbNewDeviceId = 0;
+               }
+       }
+       if(isNotSE0()){ /* SE0 state */
+               usbIsReset = 0;
+       }else{
+               /* check whether SE0 lasts for more than 2.5us (3.75 bit times) */
+               if(!usbIsReset){
+                       uchar i;
+                       for(i=100;i;i--){
+                               if(isNotSE0())
+                                       goto notUsbReset;
+                       }
+                       usbIsReset = 1;
+                       usbDeviceId = 0;
+                       usbNewDeviceId = 0;
+                       DBG1(0xff, 0, 0);
+notUsbReset:;
+               }
+       }
+}
+
+/* ------------------------------------------------------------------------- */
+
+void   usbInit(void)
+{
+       usbInputBuf = (uchar)usbRxBuf[0];
+       usbAppBuf = (uchar)usbRxBuf[1];
+#if USB_INTR_CFG_SET != 0
+       USB_INTR_CFG |= USB_INTR_CFG_SET;
+#endif
+#if USB_INTR_CFG_CLR != 0
+       USB_INTR_CFG &= ~(USB_INTR_CFG_CLR);
+#endif
+       USB_INTR_ENABLE |= (1 << USB_INTR_ENABLE_BIT);
+}
+
+/* ------------------------------------------------------------------------- */
diff --git a/firmware/usbdrv/usbdrv.h b/firmware/usbdrv/usbdrv.h
new file mode 100644 (file)
index 0000000..66be5ed
--- /dev/null
@@ -0,0 +1,286 @@
+/* Name: usbdrv.h
+ * Project: AVR USB driver
+ * Author: Christian Starkjohann
+ * Creation Date: 2004-12-29
+ * Tabsize: 4
+ * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
+ * License: Proprietary, free under certain conditions. See Documentation.
+ * This Revision: $Id: usbdrv.h 52 2005-04-12 16:57:29Z cs $
+ */
+
+#ifndef __usbdrv_h_included__
+#define        __usbdrv_h_included__
+#include "usbconfig.h"
+
+/*
+Hardware Prerequisites:
+=======================
+USB lines D+ and D- MUST be wired to the same I/O port. Line D- MUST be wired
+to bit number 0. D+ must also be connected to INT0. D- requires a pullup of
+1.5k to +3.5V (and the device must be powered at 3.5V) to identify as
+low-speed USB device. A pullup of 1M SHOULD be connected from D+ to +3.5V to
+prevent interference when no USB master is connected. We use D+ as interrupt
+source and not D- because it does not trigger on keep-alive and RESET states.
+
+Please adapt the values in usbconfig.h according to your hardware!
+
+The device MUST be clocked at 12 MHz. This is more than the 10 MHz allowed by
+an AT90S2313 powered at 4.5V. However, if the supply voltage to maximum clock
+relation is interpolated linearly, an ATtiny2313 meets the requirement by
+specification. In practice, the AT90S2313 can be overclocked and works well.
+
+
+Limitations:
+============
+Compiling:
+The bss segment of the driver must be in the first 256 bytes of the address
+space because byte wide variables are used as pointers for efficiency reasons.
+This is not a problem on devices with 128 byte RAM since the entire RAM
+meets this condition. For larger devices please link usbdrv first.
+
+Robustness with respect to communication errors:
+The driver assumes error-free communication. It DOES check for errors in
+the PID, but does NOT check bit stuffing errors, SE0 in middle of a byte,
+token CRC (5 bit) and data CRC (16 bit). CRC checks can not be performed due
+to timing constraints: We must start sending a reply within 7 bit times.
+Bit stuffing and misplaced SE0 would have to be checked in real-time, but CPU
+performance does not permit that. The driver does not check Data0/Data1
+toggling, but application software can implement the check.
+
+Sampling jitter:
+The driver guarantees a sampling window of 1/2 bit. The USB spec requires
+that the receiver has at most 1/4 bit sampling window. The 1/2 bit window
+should still work reliably enough because we work at low speed. If you want
+to meet the spec, define the macro "USB_CFG_SAMPLE_EXACT" to 1 in usbconfig.h.
+This will unroll a loop which results in bigger code size.
+
+Input characteristics:
+Since no differential receiver circuit is used, electrical interference
+robustness may suffer. The driver samples only one of the data lines with
+an ordinary I/O pin's input characteristics. However, since this is only a
+low speed USB implementation and the specification allows for 8 times the
+bit rate over the same hardware, we should be on the safe side. Even the spec
+requires detection of asymmetric states at high bit rate for SE0 detection.
+
+Number of endpoints:
+The driver supports up to two endpoints: One control endpoint (endpoint 0) and
+one interrupt-in endpoint (endpoint 1) where the device can send interrupt
+data to the host. Endpoint 1 is only compiled in if
+USB_CFG_HAVE_INTRIN_ENDPOINT is defined to 1 in usbconfig.h.
+
+Maximum data payload:
+Data payload of control in and out transfers may be up to 255 bytes. In order
+to accept payload data of out transfers, you need to implement
+'usbFunctionWrite()'.
+
+USB Suspend Mode supply current:
+The USB standard limits power consumption to 500uA when the bus is in suspend
+mode. This is not a problem for self-powered devices since they don't need
+bus power anyway. Bus-powered devices can achieve this only by putting the
+CPU in sleep mode. The driver does not implement suspend handling by itself.
+However, the application may implement activity monitoring and wakeup from
+sleep. The host sends regular SE0 states on the bus to keep it active. These
+SE0 states can be detected by wiring the INT1 pin to D+. It is not necessary
+to enable the interrupt, checking the interrupt pending flag should suffice.
+Before entering sleep mode, the application should enable INT1 for a wakeup
+on the next bus activity.
+
+Operation without an USB master:
+The driver behaves neutral without connection to an USB master if D- reads
+as 1. To avoid spurious interrupts, we recommend a high impedance (e.g. 1M)
+pullup resistor on D+. If D- becomes statically 0, the driver may block in
+the interrupt routine.
+
+Interrupt latency:
+The application must ensure that the USB interrupt is not disabled for more
+than 20 cycles.
+
+Maximum interrupt duration / CPU cycle consumption:
+The driver handles all USB communication during the interrupt service
+routine. The routine will not return before an entire USB message is received
+and the reply is sent. This may be up to ca. 1200 cycles = 100us if the host
+conforms to the standard. The driver will consume CPU cycles for all USB
+messages, even if they address an other (low-speed) device on the same bus.
+
+*/
+
+/* ------------------------------------------------------------------------- */
+/* --------------------------- Module Interface ---------------------------- */
+/* ------------------------------------------------------------------------- */
+
+#ifndef __ASSEMBLER__
+
+#ifndef uchar
+#define        uchar   unsigned char
+#endif
+
+#if USB_CFG_HAVE_INTRIN_ENDPOINT
+void   usbSetInterrupt(uchar *data, uchar len);
+/* This function sets the message which will be sent during the next interrupt
+ * IN transfer. The message is copied to an internal buffer and must not exceed
+ * a length of 7 bytes. The message may be 0 bytes long just to indicate the
+ * interrupt status to the host.
+ * If you need to transfer more bytes, use a control read after the interrupt.
+ */
+#endif /* USB_CFG_HAVE_INTRIN_ENDPOINT */
+
+extern void            usbInit(void);
+/* This function must be called before interrupts are enabled and the main
+ * loop is entered.
+ */
+extern void            usbPoll(void);
+/* This function must be called at regular intervals from the main loop.
+ * Maximum delay between calls is somewhat less than 50ms (USB timeout between
+ * packages of a message).
+ */
+extern uchar   *usbMsgPtr;
+/* This variable may be used to pass transmit data to the driver from the
+ * implementation of usbFunctionWrite(). It is also used internally by the
+ * driver for standard control requests.
+ */
+extern uchar   usbFunctionSetup(uchar data[8]);
+/* This function is called for all setup requests which are not of type
+ * "Standard" (in practice: class and vendor requests). The 8 bytes setup
+ * data is passed in 'data'. Data for control-out transfers is passed to the
+ * application in separate calls to usbFunctionWrite() (unless you have turned
+ * this option off). You should store the setup context in global/static
+ * variables to have it available in usbFunctionWrite(). Data for control-in
+ * transfers can be provided in two ways: (1) immediately as a result of
+ * usbFunctionSetup() or (2) on demand of the driver in calls to the separate
+ * function usbFunctionRead() (if enabled). For (1) write the data to a static
+ * buffer, set the global variable 'usbMsgPtr' to this buffer and return the
+ * data length (may be 0). To implement (2), simply return 0xff (== -1) in
+ * usbFunctionSetup(). The driver will call usbFunctionRead() when data is
+ * needed. You may use 'usbMsgPtr' to save your own status in this case.
+ * The data passed in 'data' has the following content (see USB 1.1 spec):
+ *     struct usbControlData{
+ *             uchar           requestType;    //[0]
+ *             uchar           request;                //[1]
+ *             unsigned        value;                  //[2], [3]
+ *             unsigned        index;                  //[4], [5]
+ *             unsigned        length;                 //[6], [7]
+ *     };
+ */
+#if USB_CFG_IMPLEMENT_FN_WRITE
+extern uchar   usbFunctionWrite(uchar *data, uchar len);
+/* This function is called by the driver to provide a control transfer's
+ * payload data (control-out). It is called in chunks of up to 8 bytes. The
+ * total count provided in the current control transfer can be obtained from
+ * the 'length' property in the setup data. If an error occurred during
+ * processing, return 0xff (== -1). The driver will answer the entire transfer
+ * with a STALL token in this case. Otherwise return any number which is not
+ * 0xff. NOTE: Only the return value of the LAST usbFunctionWrite() call
+ * (the one immediately before the status phase) is used.
+ */
+#endif /* USB_CFG_IMPLEMENT_FN_WRITE */
+#if USB_CFG_IMPLEMENT_FN_READ
+extern uchar usbFunctionRead(uchar *data, uchar len);
+/* This function is called by the driver to ask the application for a control
+ * transfer's payload data (control-in). You should supply up to 'len' bytes of
+ * data in this chunk. 'len' will be 8 bytes for all but the last chunk. If
+ * you return less than 8 bytes, the control transfer ends. If you return an
+ * invalid value (e.g. -1), the driver sends a STALL token.
+ */
+#endif /* USB_CFG_IMPLEMENT_FN_READ */
+extern unsigned        usbCrc16(uchar *data, uchar len);
+/* This function calculates the binary complement of the data CRC used in
+ * USB data packets. The value is used to build raw transmit packets.
+ * You may want to use this function for data checksums.
+ */
+
+#endif /* __ASSEMBLER__ */
+
+/* ------------------------------------------------------------------------- */
+/* ------------------------- Constant definitions -------------------------- */
+/* ------------------------------------------------------------------------- */
+
+/* I/O definitions for assembler module */
+#define        USBOUT          USB_CFG_IOPORT                  /* output port for USB bits */
+#ifdef __ASSEMBLER__
+#define        USBIN           (USB_CFG_IOPORT - 2)    /* input port for USB bits */
+#define        USBDDR          (USB_CFG_IOPORT - 1)    /* data direction for USB bits */
+#else
+#define        USBIN           (*(&USB_CFG_IOPORT - 2))        /* input port for USB bits */
+#define        USBDDR          (*(&USB_CFG_IOPORT - 1))        /* data direction for USB bits */
+#endif
+#if USB_CFG_DMINUS_BIT != 0
+#      error "USB_CFG_DMINUS_BIT MUST be 0!"
+#endif
+#define        USBMINUS        0               /* D- MUST be on bit 0 */
+#define        USBIDLE         0x01    /* value representing J state */
+#define        USBMASK         ((1<<USB_CFG_DPLUS_BIT) | 1)    /* mask for USB I/O bits */
+
+#define        USB_BUFSIZE             11      /* PID, 8 bytes data, 2 bytes CRC */
+
+/* Try to find registers and bits responsible for ext interrupt 0 */
+
+#if defined EICRA
+#      define  USB_INTR_CFG    EICRA
+#else
+#      define  USB_INTR_CFG    MCUCR
+#endif
+#define        USB_INTR_CFG_SET        ((1 << ISC00) | (1 << ISC01))   /* cfg for rising edge */
+#define        USB_INTR_CFG_CLR        0       /* no bits to clear */
+
+#if defined GIMSK
+#      define  USB_INTR_ENABLE         GIMSK
+#elif defined EIMSK
+#      define  USB_INTR_ENABLE         EIMSK
+#else
+#      define  USB_INTR_ENABLE         GICR
+#endif
+#define        USB_INTR_ENABLE_BIT             INT0
+
+#if defined EIFR
+#      define  USB_INTR_PENDING        EIFR
+#else
+#      define  USB_INTR_PENDING        GIFR
+#endif
+#define        USB_INTR_PENDING_BIT    INTF0
+
+/*
+The defines above don't work for the following chips
+at90c8534: no ISC0?, no PORTB, can't find a data sheet
+at86rf401: no PORTB, no MCUCR etc
+atmega103: no ISC0? (maybe omission in header, can't find data sheet)
+atmega603: not defined in avr-libc
+at43usb320, at43usb355, at76c711: have USB anyway
+at94k: is different...
+
+at90s1200, attiny11, attiny12, attiny15, attiny28: these have no RAM
+*/
+
+/* ------------------------------------------------------------------------- */
+/* ---------------------- USB Specification Constants ---------------------- */
+/* ------------------------------------------------------------------------- */
+
+/* USB Token values */
+#define        USBPID_SETUP    0x2d
+#define        USBPID_OUT              0xe1
+#define        USBPID_IN               0x69
+#define        USBPID_DATA0    0xc3
+#define        USBPID_DATA1    0x4b
+
+#define        USBPID_ACK              0xd2
+#define        USBPID_NAK              0x5a
+#define        USBPID_STALL    0x1e
+
+/* USB descriptor constants */
+#define        USBATTR_BUSPOWER        0x80
+#define        USBATTR_SELFPOWER       0x40
+#define        USBATTR_REMOTEWAKE      0x20
+
+/* USB setup recipient values */
+#define        USBRQ_RCPT_DEVICE               0
+#define        USBRQ_RCPT_INTERFACE    1
+#define        USBRQ_RCPT_ENDPOINT             2
+
+/* USB request type values */
+#define        USBRQ_TYPE_STANDARD             0
+#define        USBRQ_TYPE_CLASS                1
+#define        USBRQ_TYPE_VENDOR               2
+
+
+/* ------------------------------------------------------------------------- */
+
+#endif /* __usbdrv_h_included__ */
diff --git a/firmware/usbdrv/usbdrv.o b/firmware/usbdrv/usbdrv.o
new file mode 100644 (file)
index 0000000..7b5dc51
Binary files /dev/null and b/firmware/usbdrv/usbdrv.o differ
diff --git a/firmware/usbdrv/usbdrvasm.S b/firmware/usbdrv/usbdrvasm.S
new file mode 100644 (file)
index 0000000..d46ef92
--- /dev/null
@@ -0,0 +1,648 @@
+/* Name: usbdrvasm.S
+ * Project: AVR USB driver
+ * Author: Christian Starkjohann
+ * Creation Date: 2004-12-29
+ * Tabsize: 4
+ * Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
+ * License: Proprietary, free under certain conditions. See Documentation.
+ * This Revision: $Id: usbdrvasm.S 52 2005-04-12 16:57:29Z cs $
+ */
+
+/*
+General Description:
+This module implements the assembler part of the USB driver. See usbdrv.h
+for a description of the entire driver.
+Since almost all of this code is timing critical, don't change unless you
+really know what you are doing! Many parts require not only a maximum number
+of CPU cycles, but even an exact number of cycles!
+*/
+
+/* configs for io.h */
+#define __SFR_OFFSET 0
+#define _VECTOR(N) __vector_ ## N      /* io.h does not define this for asm */
+
+#include <avr/io.h>    /* for CPU I/O register definitions and vectors */
+#include "usbdrv.h"    /* for common defs */
+
+
+/* register names */
+#define        x1              r16
+#define        x2              r17
+#define        shift   r18
+#define        cnt             r19
+#define        x3              r20
+#define        x4              r21
+
+#define        nop2    rjmp    .+0     /* jump to next instruction */
+
+.text
+
+.global        SIG_INTERRUPT0
+       .type   SIG_INTERRUPT0, @function
+SIG_INTERRUPT0:
+;Software-receiver engine. Strict timing! Don't change unless you can preserve timing!
+;interrupt response time: 4 cycles + insn running = 7 max if interrupts always enabled
+;max allowable interrupt latency: 32 cycles -> max 25 cycles interrupt disable
+;max stack usage: [ret(2), x1, SREG, x2, cnt, shift, YH, YL, x3, x4] = 11 bytes
+usbInterrupt:
+;order of registers pushed:
+;x1, SREG, x2, cnt, shift, [YH, YL, x3]
+       push    x1                              ;2  push only what is necessary to sync with edge ASAP
+       in              x1, SREG                ;1
+       push    x1                              ;2
+;sync byte (D-) pattern LSb to MSb: 01010100 [1 = idle = J, 0 = K]
+;sync up with J to K edge during sync pattern -- use fastest possible loops
+;first part has no timeout because it waits for IDLE or SE1 (== disconnected)
+#if !USB_CFG_SAMPLE_EXACT
+       ldi             x1, 5                   ;1 setup a timeout for waitForK
+#endif
+waitForJ:
+       sbis    USBIN, USBMINUS ;1 wait for D- == 1
+       rjmp    waitForJ                ;2
+#if USB_CFG_SAMPLE_EXACT
+;The following code represents the unrolled loop in the else branch. It
+;results in a sampling window of 1/4 bit which meets the spec.
+       sbis    USBIN, USBMINUS
+       rjmp    foundK
+       sbis    USBIN, USBMINUS
+       rjmp    foundK
+       sbis    USBIN, USBMINUS
+       rjmp    foundK
+       nop
+       nop2
+foundK:
+#else
+waitForK:
+       dec             x1                              ;1
+       sbic    USBIN, USBMINUS ;1 wait for D- == 0
+       brne    waitForK                ;2
+#endif
+;{2, 6} after falling D- edge, average delay: 4 cycles [we want 4 for center sampling]
+;we have 1 bit time for setup purposes, then sample again:
+       push    x2                              ;2
+       push    cnt                             ;2
+       push    shift                   ;2
+shortcutEntry:
+       ldi             cnt, 1                  ;1 pre-init bit counter (-1 because no dec follows, -1 because 1 bit already sampled)
+       ldi             x2, 1<<USB_CFG_DPLUS_BIT        ;1 -> 8   edge sync ended with D- == 0
+;now wait until SYNC byte is over. Wait for either 2 bits low (success) or 2 bits high (failure)
+waitNoChange:
+       in              x1, USBIN               ;1 <-- sample, timing: edge + {2, 6} cycles
+       eor             x2, x1                  ;1
+       sbrc    x2, 0                   ;1 | 2
+       ldi             cnt, 2                  ;1 | 0 cnt = numBits - 1 (because dec follows)
+       mov             x2, x1                  ;1
+       dec             cnt                             ;1
+       brne    waitNoChange    ;2 | 1
+       sbrc    x1, USBMINUS    ;2
+       rjmp    sofError                ;0 two consecutive "1" bits -> framing error
+;start reading data, but don't check for bitstuffing because these are the
+;first bits. Use the cycles for initialization instead. Note that we read and
+;store the binary complement of the data stream because eor results in 1 for
+;a change and 0 for no change.
+       in              x1, USBIN               ;1 <-- sample bit 0, timing: edge + {3, 7} cycles
+       eor             x2, x1                  ;1
+       ror             x2                              ;1
+       ldi             shift, 0x7f             ;1 The last bit of the sync pattern was a "no change"
+       ror             shift                   ;1
+       push    YH                              ;2 -> 7
+       in              x2, USBIN               ;1 <-- sample bit 1, timing: edge + {2, 6} cycles
+       eor             x1, x2                  ;1
+       ror             x1                              ;1
+       ror             shift                   ;1
+       push    YL                              ;2
+       lds             YL, usbInputBuf ;2 -> 8
+       in              x1, USBIN               ;1 <-- sample bit 2, timing: edge + {2, 6} cycles
+       eor             x2, x1                  ;1
+       ror             x2                              ;1
+       ror             shift                   ;1
+       ldi             cnt, USB_BUFSIZE;1
+       clr             YH                              ;1
+       push    x3                              ;2 -> 8
+       in              x2, USBIN               ;1 <-- sample bit 3, timing: edge + {2, 6} cycles
+       eor             x1, x2                  ;1
+       ror             x1                              ;1
+       ror             shift                   ;1
+       ser             x3                              ;1
+       nop                                             ;1
+       rjmp    rxbit4                  ;2 -> 8
+
+shortcutToStart:                       ;{,43} into next frame: max 5.5 sync bits missed
+#if !USB_CFG_SAMPLE_EXACT
+       ldi             x1, 5                   ;2 setup timeout
+#endif
+waitForJ1:
+       sbis    USBIN, USBMINUS ;1 wait for D- == 1
+       rjmp    waitForJ1               ;2
+#if USB_CFG_SAMPLE_EXACT
+;The following code represents the unrolled loop in the else branch. It
+;results in a sampling window of 1/4 bit which meets the spec.
+       sbis    USBIN, USBMINUS
+       rjmp    foundK1
+       sbis    USBIN, USBMINUS
+       rjmp    foundK1
+       sbis    USBIN, USBMINUS
+       rjmp    foundK1
+       nop
+       nop2
+foundK1:
+#else
+waitForK1:
+       dec             x1                              ;1
+       sbic    USBIN, USBMINUS ;1 wait for D- == 0
+       brne    waitForK1               ;2
+#endif
+       pop             YH                              ;2 correct stack alignment
+       nop2                                    ;2 delay for the same time as the pushes in the original code
+       rjmp    shortcutEntry   ;2
+
+; ################# receiver loop #################
+; extra jobs done during bit interval:
+; bit 6:       se0 check
+; bit 7:       or, store, clear
+; bit 0:       recover from delay      [SE0 is unreliable here due to bit dribbling in hubs]
+; bit 1:       se0 check
+; bit 2:       se0 check
+; bit 3:       overflow check
+; bit 4:       se0 check
+; bit 5:       rjmp
+
+; stuffed* helpers have the functionality of a subroutine, but we can't afford
+; the overhead of a call. We therefore need a separate routine for each caller
+; which jumps back appropriately.
+
+stuffed5:                              ;1 for branch taken
+       in              x2, USBIN       ;1 <-- sample @ +1
+       andi    x2, USBMASK     ;1
+       breq    se0a            ;1
+       andi    x3, 0xc0        ;1 (0xff03 >> 2) & 0xff
+       ori             shift, 0xfc     ;1
+       rjmp    rxbit6          ;2
+
+stuffed6:                              ;1 for branch taken
+       in              x1, USBIN       ;1 <-- sample @ +1
+       andi    x1, USBMASK     ;1
+       breq    se0a            ;1
+       andi    x3, 0x81        ;1 (0xff03 >> 1) & 0xff
+       ori             shift, 0xfc     ;1
+       rjmp    rxbit7          ;2
+
+; This is somewhat special because it has to compensate for the delay in bit 7
+stuffed7:                              ;1 for branch taken
+       andi    x1, USBMASK     ;1 already sampled by caller
+       breq    se0a            ;1
+       mov             x2, x1          ;1 ensure correct NRZI sequence [we can save andi x3 here]
+       ori             shift, 0xfc     ;1
+       in              x1, USBIN       ;1 <-- sample bit 0
+       rjmp    unstuffed7      ;2
+
+stuffed0:                              ;1 for branch taken
+       in              x1, USBIN       ;1 <-- sample @ +1
+       andi    x1, USBMASK     ;1
+       breq    se0a            ;1
+       andi    x3, 0xfe        ;1 (0xff03 >> 7) & 0xff
+       ori             shift, 0xfc     ;1
+       rjmp    rxbit1          ;2
+
+;-----------------------------
+rxLoop:
+       brlo    stuffed5        ;1
+rxbit6:
+       in              x1, USBIN       ;1 <-- sample bit 6
+       andi    x1, USBMASK     ;1
+       breq    se0a            ;1
+       eor             x2, x1          ;1
+       ror             x2                      ;1
+       ror             shift           ;1
+       cpi             shift, 4        ;1
+       brlo    stuffed6        ;1
+rxbit7:
+       in              x2, USBIN       ;1 <-- sample bit 7
+       eor             x1, x2          ;1
+       ror             x1                      ;1
+       ror             shift           ;1
+       eor             x3,     shift   ;1 x3 is 0 at bit locations we changed, 1 at others
+       st              y+, x3          ;2 the eor above reconstructed modified bits and inverted rx data
+       ser             x3                      ;1
+rxbit0:
+       in              x1, USBIN       ;1 <-- sample bit 0
+       cpi             shift, 4        ;1
+       brlo    stuffed7        ;1
+unstuffed7:
+       eor             x2, x1          ;1
+       ror             x2                      ;1
+       ror             shift           ;1
+       cpi             shift, 4        ;1
+       brlo    stuffed0        ;1
+rxbit1:
+       in              x2, USBIN       ;1 <-- sample bit 1
+       andi    x2, USBMASK     ;1
+se0a:                                  ; enlarge jump range to SE0
+       breq    se0                     ;1 check for SE0 more often close to start of byte
+       eor             x1, x2          ;1
+       ror             x1                      ;1
+       ror             shift           ;1
+       cpi             shift, 4        ;1
+       brlo    stuffed1        ;1
+rxbit2:
+       in              x1, USBIN       ;1 <-- sample bit 2
+       andi    x1, USBMASK     ;1
+       breq    se0                     ;1
+       eor             x2, x1          ;1
+       ror             x2                      ;1
+       ror             shift           ;1
+       cpi             shift, 4        ;1
+       brlo    stuffed2        ;1
+rxbit3:
+       in              x2, USBIN       ;1 <-- sample bit 3
+       eor             x1, x2          ;1
+       ror             x1                      ;1
+       ror             shift           ;1
+       dec             cnt                     ;1      check for buffer overflow
+       breq    overflow        ;1
+       cpi             shift, 4        ;1
+       brlo    stuffed3        ;1
+rxbit4:
+       in              x1, USBIN       ;1 <-- sample bit 4
+       andi    x1, USBMASK     ;1
+       breq    se0                     ;1
+       eor             x2, x1          ;1
+       ror             x2                      ;1
+       ror             shift           ;1
+       cpi             shift, 4        ;1
+       brlo    stuffed4        ;1
+rxbit5:
+       in              x2, USBIN       ;1 <-- sample bit 5
+       eor             x1, x2          ;1
+       ror             x1                      ;1
+       ror             shift           ;1
+       cpi             shift, 4        ;1
+       rjmp    rxLoop          ;2
+;-----------------------------
+
+stuffed1:                              ;1 for branch taken
+       in              x2, USBIN       ;1 <-- sample @ +1
+       andi    x2, USBMASK     ;1
+       breq    se0                     ;1
+       andi    x3, 0xfc        ;1 (0xff03 >> 6) & 0xff
+       ori             shift, 0xfc     ;1
+       rjmp    rxbit2          ;2
+
+stuffed2:                              ;1 for branch taken
+       in              x1, USBIN       ;1 <-- sample @ +1
+       andi    x1, USBMASK     ;1
+       breq    se0                     ;1
+       andi    x3, 0xf8        ;1 (0xff03 >> 5) & 0xff
+       ori             shift, 0xfc     ;1
+       rjmp    rxbit3          ;2
+
+stuffed3:                              ;1 for branch taken
+       in              x2, USBIN       ;1 <-- sample @ +1
+       andi    x2, USBMASK     ;1
+       breq    se0                     ;1
+       andi    x3, 0xf0        ;1 (0xff03 >> 4) & 0xff
+       ori             shift, 0xfc     ;1
+       rjmp    rxbit4          ;2
+
+stuffed4:                              ;1 for branch taken
+       in              x1, USBIN       ;1 <-- sample @ +1
+       andi    x1, USBMASK     ;1
+       breq    se0                     ;1
+       andi    x3, 0xe0        ;1 (0xff03 >> 3) & 0xff
+       ori             shift, 0xfc     ;1
+       rjmp    rxbit5          ;2
+
+;################ end receiver loop ###############
+
+overflow:                                      ; ignore package if buffer overflow
+       rjmp    rxDoReturn              ; enlarge jump range
+
+;This is the only non-error exit point for the software receiver loop
+;{4, 20} cycles after start of SE0, typically {10, 18} after SE0 start = {-6, 2} from end of SE0
+;next sync starts {16,} cycles after SE0 -> worst case start: +4 from next sync start
+;we don't check any CRCs here because there is no time left.
+se0:                                                   ;{-6, 2} from end of SE0 / {,4} into next frame
+       mov             cnt, YL                         ;1 assume buffer in lower 256 bytes of memory
+       lds             YL, usbInputBuf         ;2 reposition to buffer start
+       sub             cnt, YL                         ;1 length of message
+       ldi             x1, 1<<USB_INTR_PENDING_BIT     ;1
+       cpi             cnt, 3                          ;1
+       out             USB_INTR_PENDING, x1;1 clear pending intr and check flag later. SE0 must be over. {,10} into next frame
+       brlo    rxDoReturn                      ;1 ensure valid packet size, ignore others
+       ld              x1, y                           ;2 PID
+       ldd             x2, y+1                         ;2 ADDR + 1 bit endpoint number
+       mov             x3, x2                          ;1 store for endpoint number
+       andi    x2, 0x7f                        ;1 mask endpoint number bit
+       lds             shift, usbDeviceId      ;2
+       cpi             x1, USBPID_SETUP        ;1
+       breq    isSetupOrOut            ;2 -> 19 = {13, 21} from SE0 end
+       cpi             x1, USBPID_OUT          ;1
+       breq    isSetupOrOut            ;2 -> 22 = {16, 24} from SE0 end / {,24} into next frame
+       cpi             x1, USBPID_IN           ;1
+       breq    handleIn                        ;1
+       cpi             x1, USBPID_DATA0        ;1
+       breq    isData                          ;1
+       cpi             x1, USBPID_DATA1        ;1
+       brne    rxDoReturn                      ;1 ignore all other PIDs
+isData:
+       lds             x2, usbCurrentTok       ;2
+       tst             x2                                      ;1
+       breq    rxDoReturn                      ;1 for other device or spontaneous data -- ignore
+       lds             x1, usbRxLen            ;2
+       cpi             x1, 0                           ;1
+       brne    sendNakAndReti          ;1 no buffer space available / {30, 38} from SE0 end
+       sts             usbRxLen, cnt           ;2 store received data, swap buffers
+       sts             usbRxToken, x2          ;2
+       lds             x1, usbAppBuf           ;2
+       sts             usbAppBuf, YL           ;2
+       sts             usbInputBuf, x1         ;2 buffers now swapped
+       rjmp    sendAckAndReti          ;2 -> {42, 50} from SE0 end
+
+handleIn:                                              ; {18, 26} from SE0 end
+       cp              x2, shift                       ;1 shift contains our device ID
+       brne    rxDoReturn                      ;1 other device
+#if USB_CFG_HAVE_INTRIN_ENDPOINT
+       sbrc    x3, 7                           ;2
+       rjmp    handleIn1                       ;0
+#endif
+       lds             cnt, usbTxLen           ;2
+       cpi             cnt, -1                         ;1
+       breq    sendNakAndReti          ;1 -> {27, 35} from SE0 end
+       ldi             x1, -1                          ;1
+       sts             usbTxLen, x1            ;2 buffer is now free
+       ldi             YL, lo8(usbTxBuf)       ;1
+       ldi             YH, hi8(usbTxBuf)       ;1
+       rjmp    usbSendAndReti          ;2 -> {34, 43} from SE0 end
+
+; Comment about when to set usbTxLen to -1:
+; We should set it back to -1 when we receive the ACK from the host. This would
+; be simple to implement: One static variable which stores whether the last
+; tx was for endpoint 0 or 1 and a compare in the receiver to distinguish the
+; ACK. However, we set it back to -1 immediately when we send the package,
+; assuming that no error occurs and the host sends an ACK. We save one byte
+; RAM this way and avoid potential problems with endless retries. The rest of
+; the driver assumes error-free transfers anyway.
+
+otherOutOrSetup:
+       clr             x1
+       sts             usbCurrentTok, x1
+rxDoReturn:
+       pop             x3                                      ;2
+       pop             YL                                      ;2
+       pop             YH                                      ;2
+       rjmp    sofError                        ;2
+
+isSetupOrOut:                                  ; we must be fast here -- a data package may follow / {,24} into next frame
+       cp              x2, shift                       ;1 shift contains our device ID
+       brne    otherOutOrSetup         ;1 other device -- ignore
+       sts             usbCurrentTok, x1       ;2
+#if 0  /* we implement only one rx endpoint */
+       sts             usbRxEndp, x3           ;2 only stored if we may have to distinguish endpoints
+#endif
+;A transmission can still have data in the output buffer while we receive a
+;SETUP package with an IN phase. To avoid that the old data is sent as a reply,
+;we abort transmission. ### This mechanism assumes that NO OUT OR SETUP package
+;is ever sent to endpoint 1. We would abort transmission for endpoint 0
+;in this case.
+       ldi             x1, -1                          ;1
+       sts             usbMsgLen, x1           ;2
+       sts             usbTxLen, x1            ;2 abort transmission
+       pop             x3                                      ;2
+       pop             YL                                      ;2
+       in              x1, USB_INTR_PENDING;1
+       sbrc    x1, USB_INTR_PENDING_BIT;1 check whether data is already arriving {,41} into next frame
+       rjmp    shortcutToStart         ;2 save the pops and pushes -- a new interrupt is aready pending
+;If the jump above was not taken, we can be at {,2} into the next frame here
+       pop             YH                                      ;2
+sofError:                                              ; error in start of frame -- ignore frame
+       ldi             x1, 1<<USB_INTR_PENDING_BIT;1 many int0 events occurred during our processing -- clear pending flag
+       out             USB_INTR_PENDING, x1;1
+       pop             shift                           ;2
+       pop             cnt                                     ;2
+       pop             x2                                      ;2
+       pop             x1                                      ;2
+       out             SREG, x1                        ;1
+       pop             x1                                      ;2
+       reti                                            ;4 -> {,21} into next frame -> up to 3 sync bits missed
+
+
+sendNakAndReti:                                        ; 21 cycles until SOP
+       ldi             YL, lo8(usbNakBuf)      ;1
+       ldi             YH, hi8(usbNakBuf)      ;1
+       rjmp    usbSendToken            ;2
+
+sendAckAndReti:                                        ; 19 cycles until SOP
+       ldi             YL, lo8(usbAckBuf)      ;1
+       ldi             YH, hi8(usbAckBuf)      ;1
+usbSendToken:
+       ldi             cnt, 2                          ;1
+;;;;rjmp       usbSendAndReti          fallthrough
+
+; USB spec says:
+; idle = J
+; J = (D+ = 0), (D- = 1) or USBOUT = 0x01
+; K = (D+ = 1), (D- = 0) or USBOUT = 0x02
+; Spec allows 7.5 bit times from EOP to SOP for replies (= 60 cycles)
+
+;usbSend:
+;pointer to data in 'Y'
+;number of bytes in 'cnt'
+;uses: x1...x4, shift, cnt, Y
+usbSendAndReti:                                ; SOP starts 16 cycles after call
+       push    x4                              ;2
+       in              x1, USBOUT              ;1
+       cbr             x1,     USBMASK         ;1 mask out data bits
+       ori             x1, USBIDLE             ;1 idle
+       out             USBOUT, x1              ;1 prepare idle state
+       ldi             x4, USBMASK             ;1 exor mask
+       in              x2, USBDDR              ;1
+       ori             x2, USBMASK             ;1 set both pins to output
+       out             USBDDR, x2              ;1 <-- acquire bus now
+; need not init x2 (bitstuff history) because sync starts with 0
+       ldi             shift, 0x80             ;1 sync byte is first byte sent
+       rjmp    txLoop                  ;2 -> 13 + 3 = 16 cycles until SOP
+
+#if USB_CFG_HAVE_INTRIN_ENDPOINT       /* placed here due to relative jump range */
+handleIn1:
+       lds             cnt, usbTxLen1
+       cpi             cnt, -1
+       breq    sendNakAndReti
+       ldi             x1, -1
+       sts             usbTxLen1, x1
+       ldi             YL, lo8(usbTxBuf1)
+       ldi             YH, hi8(usbTxBuf1)
+       rjmp    usbSendAndReti
+#endif
+
+bitstuff0:                                     ;1 (for branch taken)
+       eor             x1, x4                  ;1
+       ldi             x2, 0                   ;1
+       out             USBOUT, x1              ;1 <-- out
+       rjmp    didStuff0               ;2 branch back 2 cycles earlier
+bitstuff1:                                     ;1 (for branch taken)
+       eor             x1, x4                  ;1
+       ldi             x2, 0                   ;1
+       sec                                             ;1 set carry so that brsh will not jump
+       out             USBOUT, x1              ;1 <-- out
+       rjmp    didStuff1               ;2 jump back 1 cycle earler
+bitstuff2:                                     ;1 (for branch taken)
+       eor             x1, x4                  ;1
+       ldi             x2, 0                   ;1
+       rjmp    didStuff2               ;2 jump back 3 cycles earlier and do out
+bitstuff3:                                     ;1 (for branch taken)
+       eor             x1, x4                  ;1
+       ldi             x2, 0                   ;1
+       rjmp    didStuff3               ;2 jump back earlier
+
+txLoop:
+       sbrs    shift, 0                ;1
+       eor             x1, x4                  ;1
+       out             USBOUT, x1              ;1 <-- out
+       ror             shift                   ;1
+       ror             x2                              ;1
+didStuff0:
+       cpi             x2, 0xfc                ;1
+       brsh    bitstuff0               ;1
+       sbrs    shift, 0                ;1
+       eor             x1, x4                  ;1
+       ror             shift                   ;1
+       out             USBOUT, x1              ;1 <-- out
+       ror             x2                              ;1
+       cpi             x2, 0xfc                ;1
+didStuff1:
+       brsh    bitstuff1               ;1
+       sbrs    shift, 0                ;1
+       eor             x1, x4                  ;1
+       ror             shift                   ;1
+       ror             x2                              ;1
+didStuff2:
+       out             USBOUT, x1              ;1 <-- out
+       cpi             x2, 0xfc                ;1
+       brsh    bitstuff2               ;1
+       sbrs    shift, 0                ;1
+       eor             x1, x4                  ;1
+       ror             shift                   ;1
+       ror             x2                              ;1
+didStuff3:
+       cpi             x2, 0xfc                ;1
+       out             USBOUT, x1              ;1 <-- out
+       brsh    bitstuff3               ;1
+       nop2                                    ;2
+       ld              x3, y+                  ;2
+       sbrs    shift, 0                ;1
+       eor             x1, x4                  ;1
+       out             USBOUT, x1              ;1 <-- out
+       ror             shift                   ;1
+       ror             x2                              ;1
+didStuff4:
+       cpi             x2, 0xfc                ;1
+       brsh    bitstuff4               ;1
+       sbrs    shift, 0                ;1
+       eor             x1, x4                  ;1
+       ror             shift                   ;1
+       out             USBOUT, x1              ;1 <-- out
+       ror             x2                              ;1
+       cpi             x2, 0xfc                ;1
+didStuff5:
+       brsh    bitstuff5               ;1
+       sbrs    shift, 0                ;1
+       eor             x1, x4                  ;1
+       ror             shift                   ;1
+       ror             x2                              ;1
+didStuff6:
+       out             USBOUT, x1              ;1 <-- out
+       cpi             x2, 0xfc                ;1
+       brsh    bitstuff6               ;1
+       sbrs    shift, 0                ;1
+       eor             x1, x4                  ;1
+       ror             shift                   ;1
+       ror             x2                              ;1
+didStuff7:
+       cpi             x2, 0xfc                ;1
+       out             USBOUT, x1              ;1 <-- out
+       brsh    bitstuff7               ;1
+       mov             shift, x3               ;1
+       dec             cnt                             ;1
+       brne    txLoop                  ;2 | 1
+       cbr             x1, USBMASK             ;1 prepare SE0
+       pop             x4                              ;2
+       out             USBOUT, x1              ;1 <-- out SE0
+       ldi             cnt, 4                  ;1 two bits = 16 cycles
+se0Delay:
+       dec             cnt                             ;1
+       brne    se0Delay                ;2 | 1
+       ori             x1, USBIDLE             ;1
+       in              x2, USBDDR              ;1
+       cbr             x2, USBMASK             ;1 set both pins to input
+       out             USBOUT, x1              ;1 <-- out J (idle)
+       cbr             x1, USBMASK             ;1 configure no pullup on both pins
+       pop             x3                              ;2
+       pop             YL                              ;2
+       out             USBDDR, x2              ;1 <-- release bus now
+       out             USBOUT, x1              ;1 set pullup state
+       pop             YH                              ;2
+       rjmp    sofError                ;2 [we want to jump to rxDoReturn, but this saves cycles]
+
+bitstuff4:                                     ;1 (for branch taken)
+       eor             x1, x4                  ;1
+       ldi             x2, 0                   ;1
+       out             USBOUT, x1              ;1 <-- out
+       rjmp    didStuff4               ;2 jump back 2 cycles earlier
+bitstuff5:                                     ;1 (for branch taken)
+       eor             x1, x4                  ;1
+       ldi             x2, 0                   ;1
+       sec                                             ;1 set carry so that brsh is not taken
+       out             USBOUT, x1              ;1 <-- out
+       rjmp    didStuff5               ;2 jump back 1 cycle earlier
+bitstuff6:                                     ;1 (for branch taken)
+       eor             x1, x4                  ;1
+       ldi             x2, 0                   ;1
+       rjmp    didStuff6               ;2 jump back 3 cycles earlier and do out there
+bitstuff7:                                     ;1 (for branch taken)
+       eor             x1, x4                  ;1
+       ldi             x2, 0                   ;1
+       rjmp    didStuff7               ;2 jump back 4 cycles earlier
+
+; ######################## utility functions ########################
+
+; extern unsigned usbCrc16(unsigned char *data, unsigned char len);
+; data: r24/25
+; len: r22
+; temp variables:
+;   r18: data byte
+;   r19: bit counter
+;   r20/21: polynomial
+;   r23: scratch
+;   r24/25: crc-sum
+;   r26/27=X: ptr
+.global        usbCrc16
+usbCrc16:
+       mov             XL, r24
+       mov             XH, r25
+       ldi             r24, 0xff
+       ldi             r25, 0xff
+       ldi             r20, lo8(0xa001)
+       ldi             r21, hi8(0xa001)
+crcByteLoop:
+       subi    r22, 1
+       brcs    crcReady
+       ld              r18, x+
+       ldi             r19, 8
+crcBitLoop:
+       mov             r23, r18
+       eor             r23, r24
+       lsr             r25
+       ror             r24
+       lsr             r18
+       sbrs    r23, 0
+       rjmp    crcNoXor
+       eor             r24, r20
+       eor             r25, r21
+crcNoXor:
+       dec             r19
+       brne    crcBitLoop
+       rjmp    crcByteLoop
+crcReady:
+       com             r24
+       com             r25
+       ret
diff --git a/firmware/usbdrv/usbdrvasm.o b/firmware/usbdrv/usbdrvasm.o
new file mode 100644 (file)
index 0000000..9b0215d
Binary files /dev/null and b/firmware/usbdrv/usbdrvasm.o differ
diff --git a/software/avrdude_usbasp.2005-04-21.patch b/software/avrdude_usbasp.2005-04-21.patch
new file mode 100644 (file)
index 0000000..ebe923d
--- /dev/null
@@ -0,0 +1,125 @@
+? usbasp.c
+? usbasp.h
+Index: Makefile.am
+===================================================================
+RCS file: /cvsroot/avrdude/avrdude/Makefile.am,v
+retrieving revision 1.23
+diff -u -r1.23 Makefile.am
+--- Makefile.am        10 Feb 2005 14:54:57 -0000      1.23
++++ Makefile.am        9 Apr 2005 09:04:02 -0000
+@@ -85,6 +85,8 @@
+       stk500.c \
+       stk500.h \
+       stk500_private.h \
++      usbasp.c \
++      usbasp.h \
+       term.c \
+       term.h
+Index: avrdude.conf.in
+===================================================================
+RCS file: /cvsroot/avrdude/avrdude/avrdude.conf.in,v
+retrieving revision 1.36
+diff -u -r1.36 avrdude.conf.in
+--- avrdude.conf.in    22 Dec 2004 01:30:30 -0000      1.36
++++ avrdude.conf.in    9 Apr 2005 09:04:10 -0000
+@@ -243,6 +243,12 @@
+   miso  = 10;
+ ;
++programmer
++  id    = "usbasp";
++  desc  = "usbasp";
++  type  = usbasp;
++;
++
+ # 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
+@@ -337,7 +343,6 @@
+   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
+Index: config_gram.y
+===================================================================
+RCS file: /cvsroot/avrdude/avrdude/config_gram.y,v
+retrieving revision 1.39
+diff -u -r1.39 config_gram.y
+--- config_gram.y      22 Dec 2004 01:52:45 -0000      1.39
++++ config_gram.y      9 Apr 2005 09:04:11 -0000
+@@ -34,6 +34,7 @@
+ #include "pgm.h"
+ #include "stk500.h"
+ #include "avr910.h"
++#include "usbasp.h"
+ #include "butterfly.h"
+ #include "avr.h"
+@@ -112,6 +113,7 @@
+ %token K_SIZE
+ %token K_STK500
+ %token K_AVR910
++%token K_USBASP
+ %token K_BUTTERFLY
+ %token K_TYPE
+ %token K_VCC
+@@ -302,6 +304,11 @@
+     }
+   } |
++  K_TYPE TKN_EQUAL K_USBASP {
++    { 
++      usbasp_initpgm(current_prog);
++    }
++  } |
+   K_TYPE TKN_EQUAL K_BUTTERFLY {
+     { 
+       butterfly_initpgm(current_prog);
+Index: configure.ac
+===================================================================
+RCS file: /cvsroot/avrdude/avrdude/configure.ac,v
+retrieving revision 1.22
+diff -u -r1.22 configure.ac
+--- configure.ac       10 Feb 2005 15:39:42 -0000      1.22
++++ configure.ac       9 Apr 2005 09:04:11 -0000
+@@ -104,6 +104,21 @@
+ AC_SUBST(SUBDIRS_AC, $SUBDIRS_AC)     
+ AC_SUBST(DIST_SUBDIRS_AC, $DIST_SUBDIRS_AC)
++# USB stuff
++AH_TEMPLATE([HAVE_LIBUSB],
++      [Define if USB support is enabled via libusb])
++AC_CHECK_LIB(usb, main, have_libusb=yes)
++if test x$have_libusb = xyes; then
++   case $target in
++      *-*-darwin*)
++              LIBS="$LIBS -lusb -framework CoreFoundation -framework IOKit"
++              ;;
++      *)
++              LIBS="$LIBS -lusb"
++              ;;
++   esac
++   AC_DEFINE([HAVE_LIBUSB])
++fi
+ # Find the parallel serial device files based on target system
+ # If a system doesn't have a PC style parallel, mark it as unknown.
+Index: lexer.l
+===================================================================
+RCS file: /cvsroot/avrdude/avrdude/lexer.l,v
+retrieving revision 1.30
+diff -u -r1.30 lexer.l
+--- lexer.l    22 Dec 2004 01:52:45 -0000      1.30
++++ lexer.l    9 Apr 2005 09:04:12 -0000
+@@ -156,6 +156,7 @@
+ size             { yylval=NULL; return K_SIZE; }
+ stk500           { yylval=NULL; return K_STK500; }
+ avr910           { yylval=NULL; return K_AVR910; }
++usbasp           { yylval=NULL; return K_USBASP; }
+ butterfly        { yylval=NULL; return K_BUTTERFLY; }
+ type             { yylval=NULL; return K_TYPE; }
+ vcc              { yylval=NULL; return K_VCC; }
diff --git a/software/usbasp.c b/software/usbasp.c
new file mode 100644 (file)
index 0000000..439fa3b
--- /dev/null
@@ -0,0 +1,329 @@
+#include "ac_cfg.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "avr.h"
+#include "pgm.h"
+#include "usbasp.h"
+
+#ifdef HAVE_LIBUSB
+#include <usb.h>       /* this is libusb, see http://libusb.sourceforge.net/ */
+
+extern char * progname;
+extern int do_cycles;
+
+static usb_dev_handle *usbhandle;
+
+/*
+ * wrapper for usb_control_msg call
+ */
+static int usbasp_transmit(unsigned char receive, unsigned char functionid,
+                          unsigned char send[4], unsigned char * buffer, int buffersize)
+{
+  int nbytes;
+  nbytes = usb_control_msg(usbhandle,
+                          USB_TYPE_VENDOR | USB_RECIP_DEVICE | (receive << 7),
+                          functionid,
+                          (send[1] << 8) | send[0],
+                          (send[3] << 8) | send[2],
+                          buffer, buffersize,
+                          5000);
+  if(nbytes < 0){
+    fprintf(stderr, "%s: error: usbasp_transmit: %s\n", progname, usb_strerror());
+    exit(1);
+  }
+
+  return nbytes;
+}
+
+static int usbasp_open(PROGRAMMER * pgm, char * port)
+{
+  struct usb_bus       *bus;
+  struct usb_device *dev = 0;
+
+  usb_init();
+  usb_find_busses();
+  usb_find_devices();
+  for(bus=usb_busses; bus; bus=bus->next){
+    for(dev=bus->devices; dev; dev=dev->next){
+      if(dev->descriptor.idVendor == USBDEV_VENDOR && dev->descriptor.idProduct == USBDEV_PRODUCT)
+       break;
+    }
+    if(dev)
+      break;
+  }
+  if(!dev){
+    fprintf(stderr, "%s: error: could not find USB device vendor=0x%x product=0x%x\n",
+           progname, USBDEV_VENDOR, USBDEV_PRODUCT);
+    exit(1);
+  }
+
+  usbhandle = usb_open(dev);
+  if(!usbhandle){
+    fprintf(stderr, "%s: error: opening usb device: %s\n",
+           progname, usb_strerror());
+    exit(1);
+  }
+
+  return 0;
+}
+
+
+static void usbasp_close(PROGRAMMER * pgm)
+{
+  unsigned char temp[4];
+  memset(temp, 0, sizeof(temp));
+  usbasp_transmit(1, USBASP_FUNC_DISCONNECT, temp, temp, sizeof(temp));
+
+  usb_close(usbhandle);
+}
+
+
+static int usbasp_initialize(PROGRAMMER * pgm, AVRPART * p)
+{
+
+  unsigned char temp[4];
+  memset(temp, 0, sizeof(temp));
+  usbasp_transmit(1, USBASP_FUNC_CONNECT, temp, temp, sizeof(temp));
+
+  usleep(100000);
+
+  pgm->program_enable(pgm, p);
+  return 0;
+}
+
+static void usbasp_disable(PROGRAMMER * pgm)
+{
+  /* Do nothing. */
+
+  return;
+}
+
+static void usbasp_enable(PROGRAMMER * pgm)
+{
+  /* Do nothing. */
+
+  return;
+}
+
+static void usbasp_display(PROGRAMMER * pgm, char * p)
+{
+  return;
+}
+
+
+static int usbasp_cmd(PROGRAMMER * pgm, unsigned char cmd[4],
+                   unsigned char res[4])
+{
+  int nbytes =
+    usbasp_transmit(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(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;
+  }
+
+  while (wbytes) {
+    if (wbytes > USBASP_READBLOCKSIZE) {
+      blocksize = USBASP_READBLOCKSIZE;
+      wbytes -= USBASP_READBLOCKSIZE;
+    } else {
+      blocksize = wbytes;
+      wbytes = 0;
+    }
+
+    cmd[0] = address & 0xFF;
+    cmd[1] = address >> 8;
+
+    n = usbasp_transmit(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;
+  }
+
+  while (wbytes) {
+    if (wbytes > USBASP_WRITEBLOCKSIZE) {
+      blocksize = USBASP_WRITEBLOCKSIZE;
+      wbytes -= USBASP_WRITEBLOCKSIZE;
+    } else {
+      blocksize = wbytes;
+      wbytes = 0;
+      blockflags |= USBASP_BLOCKFLAG_LAST;
+    }
+
+    cmd[0] = address & 0xFF;
+    cmd[1] = address >> 8;
+    cmd[2] = page_size & 0xFF;
+    cmd[3] = blockflags;
+    blockflags = 0;
+
+    n = usbasp_transmit(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;
+}
+
+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;
+
+  /*
+   * optional functions
+   */
+
+  pgm->paged_write = usbasp_paged_write;
+  pgm->paged_load = usbasp_paged_load;
+
+}
+
+
+#else /* HAVE_LIBUSB */
+
+extern char * progname;
+
+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/software/usbasp.h b/software/usbasp.h
new file mode 100644 (file)
index 0000000..0592d5b
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef __usbasp_h__
+#define __usbasp_h__
+
+#include "avrpart.h"
+
+
+#define        USBDEV_VENDOR   0x03eb  /* ATMEL */
+#define        USBDEV_PRODUCT  0xc7B4  /* USBasp */
+
+#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_BLOCKFLAG_FIRST    1
+#define USBASP_BLOCKFLAG_LAST     2
+
+#define USBASP_READBLOCKSIZE   200
+#define USBASP_WRITEBLOCKSIZE  200
+
+
+void usbasp_initpgm (PROGRAMMER * pgm);
+
+#endif /* __usbasp_h__ */