diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..21e5b75
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,46 @@
+# Name: Makefile
+# Project: USBaspLoader (updater)
+# Author: Stephan Bärwolf
+# Creation Date: 2012-09-01
+# Tabsize: 4
+# License: GNU GPL v2 (see License.txt)
+
+include Makefile.inc
+
+
+all: do_firmware do_updater
+
+flash:	firmware
+	$(MAKE) -C firmware flash
+fuse:	firmware
+	$(MAKE) -C firmware fuse
+lock:	firmware
+	$(MAKE) -C firmware lock
+update:	updater
+	$(MAKE) -C updater flash
+
+firmware: do_firmware
+updater: do_updater
+
+do_firmware:
+	$(ECHO) "."
+	$(ECHO) "."
+	$(ECHO) "======>BUILDING BOOTLOADER FIRMWARE"
+	$(ECHO) "."
+	$(MAKE) -C firmware all
+
+do_updater: firmware
+	$(ECHO) "."
+	$(ECHO) "."
+	$(ECHO) "======>BUILDING BOOTLOADER UPDATER (EXPERIMENTAL)"
+	$(ECHO) "."
+	$(MAKE) -C updater all
+
+deepclean: clean
+	$(RM) *~
+	$(MAKE) -C updater  deepclean
+	$(MAKE) -C firmware deepclean
+
+clean:
+	$(MAKE) -C updater  clean
+	$(MAKE) -C firmware clean
diff --git a/Makefile.inc b/Makefile.inc
new file mode 100644
index 0000000..f5a0a2b
--- /dev/null
+++ b/Makefile.inc
@@ -0,0 +1,326 @@
+# Name: Makefile.inc
+# Project: USBaspLoader (updater)
+# Author: Stephan Bärwolf
+# Creation Date: 2012-09-01
+# Tabsize: 4
+# License: GNU GPL v2 (see License.txt)
+
+F_CPU = 16000000
+DEVICE = atmega8
+
+# where the updating firmware should be located (starting address)
+FLASHADDRESS = 0x0000
+
+# some MCU independend defines...
+#...will be extended within MCU dependend configuration below...
+DEFINES = -DCONFIG_NO__CHIP_ERASE -DCONFIG_NO__ONDEMAND_PAGEERASE
+
+# some MCUs with small BLS (bootloader section) need to deactivate some
+# features in order to fit into BLS.
+# If this option is enabled, also essential features may become deactivated
+# Esp. you MUST ensure not to have watchdog initially enabled when using this!
+DANGEROUS=0
+
+# PROGRAMMER contains AVRDUDE options to address your programmer
+# PROGRAMMER = -c pony-stk200
+PROGRAMMER = -c usbasp
+
+#  since USBaspLoader supports HAVE_BLB11_SOFTW_LOCKBIT...
+LOCKOPT = -U lock:w:0x3f:m
+
+
+
+
+
+#untested devices (WARNING: may destroy ISP ability!)
+#device always should select maximum bootloader-section size
+#please mail tests-reports to matrixstorm@gmx.de
+#
+#some features may be deactivated to fit into bootloader section
+#ATTANTION: CONFIG_NO... feature deactivation may not be optimal!
+
+FUSEOPT_16              = -U lfuse:w:0x1f:m -U hfuse:w:0xc0:m
+BOOTLOADER_ADDRESS_16   = 0x3800
+DEFINES_16              = -DCONFIG_USE__EXCESSIVE_ASSEMBLER -DCONFIG_NO__NEED_WATCHDOG -DCONFIG_NO__PRECISESLEEP
+
+
+
+FUSEOPT_88              = -U lfuse:w:0xd7:m -U hfuse:w:0xd4:m -U efuse:w:0xf8:m
+BOOTLOADER_ADDRESS_88   = 0x1800
+DEFINES_88              = -DCONFIG_NO__FLASH_BYTE_READACCESS -DCONFIG_NO__HAVE_READ_LOCK_FUSE
+
+
+
+FUSEOPT_164             = -U lfuse:w:0xd7:m -U hfuse:w:0xd0:m -U efuse:w:0xfc:m
+BOOTLOADER_ADDRESS_164  = 0x3800
+DEFINES_164             = -DCONFIG_NO__FLASH_BYTE_READACCESS -DCONFIG_NO__HAVE_READ_LOCK_FUSE -DCONFIG_NO__BOOTLOADER_CAN_EXIT
+
+
+
+FUSEOPT_324             = $(FUSEOPT_164)
+BOOTLOADER_ADDRESS_324  = 0x7000
+DEFINES_324             = #-DEMPTY
+
+
+
+FUSEOPT_128             = -U lfuse:w:0x1f:m -U hfuse:w:0xc0:m -U efuse:w:0xfd:m
+BOOTLOADER_ADDRESS_128  = 0x1E000
+DEFINES_128             = #-DEMPTY
+
+
+
+FUSEOPT_640             = -U lfuse:w:0xd7:m -U hfuse:w:0xd0:m -U efuse:w:0xfc:m
+BOOTLOADER_ADDRESS_640  = 0xE000
+DEFINES_640             = #-DEMPTY
+
+
+
+FUSEOPT_1280             = $(FUSEOPT_640)
+BOOTLOADER_ADDRESS_1280  = 0x1E000
+DEFINES_1280             = #-DEMPTY
+
+
+
+FUSEOPT_1281             = $(FUSEOPT_1280)
+BOOTLOADER_ADDRESS_1281  = 0x1E000
+DEFINES_1281             = #-DEMPTY
+
+
+
+FUSEOPT_2561             = $(FUSEOPT_1281)
+BOOTLOADER_ADDRESS_2561  = 0x3E000
+DEFINES_2561             = #-DEMPTY
+
+
+
+
+#tested devices
+
+# standard atmega8 needs BODLEVEL to be programed, since it is a 5V device
+# you may also want to UNprogram  SUT1 to get a SLOWER bootup (lfuse then would be 0x3f)
+FUSEOPT_8            = -U lfuse:w:0x1f:m -U hfuse:w:0xc0:m
+BOOTLOADER_ADDRESS_8 = 0x1800
+DEFINES_8            = -DCONFIG_USE__EXCESSIVE_ASSEMBLER -DCONFIG_NO__NEED_WATCHDOG -DCONFIG_NO__PRECISESLEEP
+
+
+
+FUSEOPT_32              = $(FUSEOPT_16)
+BOOTLOADER_ADDRESS_32   = 0x7000
+DEFINES_32              = #-DEMPTY
+
+
+
+FUSEOPT_168             = $(FUSEOPT_88)
+BOOTLOADER_ADDRESS_168  = 0x3800
+ifeq ($(DANGEROUS), 1)
+DEFINES_168             = -DCONFIG_NO__FLASH_BYTE_READACCESS -DCONFIG_NO__HAVE_READ_LOCK_FUSE -DCONFIG_NO__NEED_WATCHDOG
+else
+DEFINES_168             = -DCONFIG_NO__FLASH_BYTE_READACCESS -DCONFIG_NO__HAVE_READ_LOCK_FUSE -DCONFIG_NO__BOOTLOADER_CAN_EXIT
+endif
+
+
+
+FUSEOPT_328             = -U lfuse:w:0xd7:m -U hfuse:w:0xd0:m -U efuse:w:0x04:m
+BOOTLOADER_ADDRESS_328  = 0x7000
+DEFINES_328             = #-DEMPTY
+
+
+
+FUSEOPT_644             = $(FUSEOPT_324)
+BOOTLOADER_ADDRESS_644  = 0xE000
+DEFINES_644             = #-DEMPTY
+
+
+
+FUSEOPT_1284            = -U lfuse:w:0xd7:m -U hfuse:w:0xd0:m -U efuse:w:0xfc:m
+BOOTLOADER_ADDRESS_1284 = 0x1E000
+DEFINES_1284            = #-DEMPTY
+
+
+
+FUSEOPT_2560             = $(FUSEOPT_1280)
+BOOTLOADER_ADDRESS_2560  = 0x3E000
+DEFINES_2560             = #-DEMPTY
+
+
+
+
+
+
+#http://www.nongnu.org/avr-libc/user-manual/using_tools.html
+#autoselect logic
+ifeq ($(DEVICE), atmega8)
+  FUSEOPT            = $(FUSEOPT_8)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_8) 
+  MCUARCH            = avr4
+  DEFINES	     += $(DEFINES_8)
+else ifeq ($(DEVICE), atmega16)
+  FUSEOPT            = $(FUSEOPT_16)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_16)
+  MCUARCH            = avr5
+  DEFINES	     += $(DEFINES_16)
+else ifeq ($(DEVICE), atmega32)
+  FUSEOPT            = $(FUSEOPT_32)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_32)
+  MCUARCH            = avr5
+  DEFINES	     += $(DEFINES_32)
+else ifeq ($(DEVICE), atmega88)
+  FUSEOPT            = $(FUSEOPT_88)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_88)
+  MCUARCH            = avr4
+  DEFINES	     += $(DEFINES_88)
+else ifeq ($(DEVICE), atmega88a)
+  FUSEOPT            = $(FUSEOPT_88)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_88)
+  MCUARCH            = avr4
+  DEFINES	     += $(DEFINES_88)
+else ifeq ($(DEVICE), atmega88p)
+  FUSEOPT            = $(FUSEOPT_88)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_88)
+  MCUARCH            = avr4
+  DEFINES	     += $(DEFINES_88)
+else ifeq ($(DEVICE), atmega88pa)
+  FUSEOPT            = $(FUSEOPT_88)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_88)
+  MCUARCH            = avr4
+  DEFINES	     += $(DEFINES_88)
+else ifeq ($(DEVICE), atmega164a)
+  FUSEOPT            = $(FUSEOPT_164)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_164)
+  MCUARCH            = avr5
+  DEFINES	     += $(DEFINES_164)
+else ifeq ($(DEVICE), atmega164p)
+  FUSEOPT            = $(FUSEOPT_164)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_164)
+  MCUARCH            = avr5
+  DEFINES	     += $(DEFINES_164)
+else ifeq ($(DEVICE), atmega164pa)
+  FUSEOPT            = $(FUSEOPT_164)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_164)
+  MCUARCH            = avr5
+  DEFINES	     += $(DEFINES_164)
+else ifeq ($(DEVICE), atmega168)
+  FUSEOPT            = $(FUSEOPT_168)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_168)
+  MCUARCH            = avr5
+  DEFINES	     += $(DEFINES_168)
+else ifeq ($(DEVICE), atmega168a)
+  FUSEOPT            = $(FUSEOPT_168)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_168)
+  MCUARCH            = avr5
+  DEFINES	     += $(DEFINES_168)
+else ifeq ($(DEVICE), atmega168p)
+  FUSEOPT            = $(FUSEOPT_168)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_168)
+  MCUARCH            = avr5
+  DEFINES	     += $(DEFINES_168)
+else ifeq ($(DEVICE), atmega168pa)
+  FUSEOPT            = $(FUSEOPT_168)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_168)
+  MCUARCH            = avr5
+  DEFINES	     += $(DEFINES_168)
+else ifeq ($(DEVICE), atmega324a)
+  FUSEOPT            = $(FUSEOPT_324)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_324)
+  MCUARCH            = avr5
+  DEFINES	     += $(DEFINES_324)
+else ifeq ($(DEVICE), atmega324p)
+  FUSEOPT            = $(FUSEOPT_324)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_324)
+  MCUARCH            = avr5
+  DEFINES	     += $(DEFINES_324)
+else ifeq ($(DEVICE), atmega324pa)
+  FUSEOPT            = $(FUSEOPT_324)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_324)
+  MCUARCH            = avr5
+  DEFINES	     += $(DEFINES_324)
+else ifeq ($(DEVICE), atmega328)
+  FUSEOPT            = $(FUSEOPT_328)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_328)
+  MCUARCH            = avr5
+  DEFINES	     += $(DEFINES_328)
+else ifeq ($(DEVICE), atmega328p)
+  FUSEOPT            = $(FUSEOPT_328)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_328)
+  MCUARCH            = avr5
+  DEFINES	     += $(DEFINES_328)
+else ifeq ($(DEVICE), atmega640)
+  FUSEOPT            = $(FUSEOPT_640)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_640)
+  MCUARCH            = avr5
+  DEFINES	     += $(DEFINES_640)
+else ifeq ($(DEVICE), atmega644)
+  FUSEOPT            = $(FUSEOPT_644)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_644)
+  MCUARCH            = avr5
+  DEFINES	     += $(DEFINES_644)
+else ifeq ($(DEVICE), atmega644a)
+  FUSEOPT            = $(FUSEOPT_644)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_644)
+  MCUARCH            = avr5
+  DEFINES	     += $(DEFINES_644)
+else ifeq ($(DEVICE), atmega644p)
+  FUSEOPT            = $(FUSEOPT_644)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_644)
+  MCUARCH            = avr5
+  DEFINES	     += $(DEFINES_644)
+else ifeq ($(DEVICE), atmega644pa)
+  FUSEOPT            = $(FUSEOPT_644)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_644)
+  MCUARCH            = avr5
+  DEFINES	     += $(DEFINES_644)
+else ifeq ($(DEVICE), atmega128)
+  FUSEOPT            = $(FUSEOPT_128)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_128)
+  MCUARCH            = avr51
+  DEFINES	     += $(DEFINES_128)
+else ifeq ($(DEVICE), atmega1280)
+  FUSEOPT            = $(FUSEOPT_1280)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_1280)
+  MCUARCH            = avr51
+  DEFINES	     += $(DEFINES_1280)
+else ifeq ($(DEVICE), atmega1281)
+  FUSEOPT            = $(FUSEOPT_1281)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_1281)
+  MCUARCH            = avr51
+  DEFINES	     += $(DEFINES_1281)
+else ifeq ($(DEVICE), atmega1284)
+  FUSEOPT            = $(FUSEOPT_1284)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_1284)
+  MCUARCH            = avr51
+  DEFINES	     += $(DEFINES_1284)
+else ifeq ($(DEVICE), atmega1284p)
+  FUSEOPT            = $(FUSEOPT_1284)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_1284)
+  MCUARCH            = avr51
+  DEFINES	     += $(DEFINES_1284)
+else ifeq ($(DEVICE), atmega2560)
+  FUSEOPT            = $(FUSEOPT_2560)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_2560)
+  MCUARCH            = avr6
+  DEFINES	     += $(DEFINES_2560)
+else ifeq ($(DEVICE), atmega2561)
+  FUSEOPT            = $(FUSEOPT_2561)
+  BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS_2561)
+  MCUARCH            = avr6
+  DEFINES	     += $(DEFINES_2561)
+else
+  FUSEOPT = unknown
+endif
+
+NEW_BOOTLOADER_ADDRESS = $(BOOTLOADER_ADDRESS)
+
+# Tools:
+AVRPATH = $(AVR8TOOLCHAINBINDIR)
+AVRDUDE = $(AVRDUDEBINDIR)avrdude $(PROGRAMMER) -p $(DEVICE)
+
+ECHO=@echo
+GCC=@gcc
+MAKE=@make
+RM=@rm -f
+
+CC=@$(AVRPATH)avr-gcc
+OBC=@$(AVRPATH)avr-objcopy
+OBD=@$(AVRPATH)avr-objdump
+SIZ=@$(AVRPATH)avr-size
+
diff --git a/Readme.txt b/Readme.txt
index 84b5514..60354b9 100644
--- a/Readme.txt
+++ b/Readme.txt
@@ -1,5 +1,22 @@
 This is the README file for bootloadHID.
 
+
+
+This version is a fork of original BootloadHID.
+Main differences are some migrated features from revised USBaspLoader
+(https://github.com/baerwolf/USBaspLoader).
+Migrated features are:
+
+		- improved build system
+		- Software protection of bootloader (no lockbits needed)
+		- Rev. 3 layout 
+		- Updatefeature (allows swapping between HID and USBasp)
+
+
+THIS IS AN ALPHA VERSION - IF ENOUGH INTEREST IT MAY BE FURTHER MAINTAINED
+
+
+
 BootloadHID is a USB boot loader for AVR microcontrollers. It can be used on
 all AVRs with at least 2 kB of boot loader section, e.g. the popular ATMega8.
 The firmware is flashed into the upper 2 kB of the flash memory and takes
diff --git a/firmware/Makefile b/firmware/Makefile
index ff9e9ab..1edbd32 100644
--- a/firmware/Makefile
+++ b/firmware/Makefile
@@ -7,43 +7,20 @@
 # License: GNU GPL v2 (see License.txt)
 # This Revision: $Id$
 
+include ../Makefile.inc
+
 ###############################################################################
 # Configure the following variables according to your AVR. The example below
 # is for an ATMega8. Program the device with
 #     make fuse    # to set the clock generator, boot section size etc.
 #     make flash   # to load the boot loader into flash
 #     make lock    # to protect the boot loader from overwriting
-
-DEVICE = atmega8
-BOOTLOADER_ADDRESS = 1800
-F_CPU = 12000000
-FUSEH = 0xc0
-FUSEL = 0x9f
-# Fuse high byte:
-# 0xc0 = 1 1 0 0   0 0 0 0 <-- BOOTRST (boot reset vector at 0x1800)
-#        ^ ^ ^ ^   ^ ^ ^------ BOOTSZ0
-#        | | | |   | +-------- BOOTSZ1
-#        | | | |   + --------- EESAVE (preserve EEPROM over chip erase)
-#        | | | +-------------- CKOPT (full output swing)
-#        | | +---------------- SPIEN (allow serial programming)
-#        | +------------------ WDTON (WDT not always on)
-#        +-------------------- RSTDISBL (reset pin is enabled)
-# Fuse low byte:
-# 0x9f = 1 0 0 1   1 1 1 1
-#        ^ ^ \ /   \--+--/
-#        | |  |       +------- CKSEL 3..0 (external >8M crystal)
-#        | |  +--------------- SUT 1..0 (crystal osc, BOD enabled)
-#        | +------------------ BODEN (BrownOut Detector enabled)
-#        +-------------------- BODLEVEL (2.7V)
-
 ###############################################################################
 
-AVRDUDE = avrdude -c stk500v2 -P avrdoper -p $(DEVICE)
-
 LDFLAGS += -Wl,--relax,--gc-sections -Wl,--section-start=.text=$(BOOTLOADER_ADDRESS)
 
 # Omit -fno-* options when using gcc 3, it does not support them.
-COMPILE = avr-gcc -Wall -Os -fno-move-loop-invariants -fno-tree-scev-cprop -fno-inline-small-functions -Iusbdrv -I. -mmcu=$(DEVICE) -DF_CPU=$(F_CPU) -DDEBUG_LEVEL=0 # -DTEST_MODE
+COMPILE = $(CC) -Wall -Os -fno-move-loop-invariants -fno-tree-scev-cprop -fno-inline-small-functions -Iusbdrv -I. -mmcu=$(DEVICE) -DF_CPU=$(F_CPU) -DBOOTLOADER_ADDRESS=$(BOOTLOADER_ADDRESS) -DDEBUG_LEVEL=0 # -DTEST_MODE $(DEFINES)
 # NEVER compile the final product with debugging! Any debug output will
 # distort timing so that the specs can't be met.
 
@@ -73,28 +50,31 @@ readflash:
 	$(AVRDUDE) -U flash:r:read.hex:i
 
 fuse:
-	$(AVRDUDE) -U hfuse:w:$(FUSEH):m -U lfuse:w:$(FUSEL):m
+	$(AVRDUDE) $(FUSEOPT)
 
 lock:
-	$(AVRDUDE) -U lock:w:0x2f:m
+	$(AVRDUDE) $(LOCKOPT)
 
 read_fuses:
 	$(UISP) --rd_fuses
 
+deepclean: clean
+	$(RM) *~
+
 clean:
-	rm -f main.hex main.bin *.o usbdrv/*.o main.s usbdrv/oddebug.s usbdrv/usbdrv.s
+	$(RM) -f main.hex main.bin *.o usbdrv/*.o main.s usbdrv/oddebug.s usbdrv/usbdrv.s
 
 # file targets:
 main.bin:	$(OBJECTS)
 	$(COMPILE) -o main.bin $(OBJECTS) $(LDFLAGS)
 
 main.hex:	main.bin
-	rm -f main.hex main.eep.hex
-	avr-objcopy -j .text -j .data -O ihex main.bin main.hex
-	avr-size main.hex
+	$(RM) -f main.hex main.eep.hex
+	$(OBC) -j .text -j .data -O ihex main.bin main.hex
+	$(SIZ) main.bin
 
 disasm:	main.bin
-	avr-objdump -d main.bin
+	$(OBD) -d main.bin
 
 cpp:
 	$(COMPILE) -E main.c
diff --git a/firmware/bootloaderconfig.h b/firmware/bootloaderconfig.h
index ff7cecf..0f5fd8f 100644
--- a/firmware/bootloaderconfig.h
+++ b/firmware/bootloaderconfig.h
@@ -37,13 +37,76 @@ names BOOTLOADER_INIT and BOOTLOADER_CONDITION for this functionality. If
 these macros are defined, the boot loader usees them.
 */
 
+
+
+#ifndef CONFIG_NO__HAVE_SPMINTEREFACE
+  #define HAVE_SPMINTEREFACE	    1
+#else
+  #define HAVE_SPMINTEREFACE	    0
+#endif
+/*
+ * Since code within normal section of application memory (rww-section) is
+ * not able to call spm for programming flash-pages, this option (when
+ * enabled) will insert a small subroutine into the bootloader-section
+ * to enable applications to circumvent this limitation and make them
+ * able to program the flash in a similar way as the bootloader does, too.
+ * For further details see "spminterface.h", which implements this 
+ * feature.
+ */
+
+#define HAVE_SPMINTEREFACE_NORETMAGIC	1
+/*
+ * If sth. went wrong within "bootloader__do_spm" and this macro is ACTIVATED,
+ * then "bootloader__do_spm" will not return the call and loop infinity instead.
+ * 
+ * This feature prevents old updaters to do sth. undefined on wrong magic.
+ */
+
+/* all boards should use a magic to make it safe to confuse updatefiles :-)  */
+#define HAVE_SPMINTEREFACE_MAGICVALUE    0
+/* If this feature is enabled (value != 0), the configured 32bit value is 
+ * used as a magic value within spminterface. "bootloader__do_spm" will check
+ * additional four (4) registers for this value and only proceed, if they contain
+ * the right value. With this feature you can identify your board and avoid
+ * updating the wrong bootloader to the wrong board!
+ * 
+ * Not all values are possible - "SPMINTEREFACE_MAGICVALUE" must be very sparse!
+ * To avoid collisions, magic-values will be organized centrally by Stephan
+ * Following values are definitly blocked or reserved and must not be used:
+ * 	0x00000000, 0x12345678,
+ * 	0x00a500a5, 0x00a5a500, 0xa50000a5, 0xa500a500,
+ * 	0x005a005a, 0x005a5a00, 0x5a00005a, 0x5a005a00,
+ * 	0x5aa55aa5, 0x5aa5a55a, 0xa55a5aa5, 0xa55aa55a,
+ * 	0x5a5a5a5a, 0xa5a5a5a5,
+ * 	0xffa5ffa5, 0xffa5a5ff, 0xa5ffffa5, 0xa5ffa5ff,
+ * 	0xff5aff5a, 0xff5a5aff, 0x5affff5a, 0x5aff5aff,
+ * 	0x00ff00ff, 0x00ffff00, 0xff0000ff, 0xff00ff00,
+ * 	0xffffffff
+ * 
+ * To request your own magic, please send at least following information
+ * about yourself and your board together within an informal request to:
+ * stephan@matrixstorm.com / matrixstorm@gmx.de / stephan.baerwolf@tu-ilmenau.de
+ * 	  - your name
+ * 	  - your e-mail
+ * 	  - your project (maybe an url?)
+ * 	  - your type of MCU used
+ * 	--> your used "BOOTLOADER_ADDRESS" (since same magics can be reused for different "BOOTLOADER_ADDRESS")
+ * 
+ * There may be no garanty for it, but Stephan will then send you an
+ * response with a "SPMINTEREFACE_MAGICVALUE" just for your board/project...
+ * WITH REQUESTING A MAGIC YOU AGREE TO PUBLISHED YOUR DATA SEND WITHIN THE REQUEST 
+ */
+
+
+
+
 /* ---------------------------- Hardware Config ---------------------------- */
 
 #define USB_CFG_IOPORTNAME      D
 /* This is the port where the USB bus is connected. When you configure it to
  * "B", the registers PORTB, PINB and DDRB will be used.
  */
-#define USB_CFG_DMINUS_BIT      0
+#define USB_CFG_DMINUS_BIT      7 /* Rev.3*/
 /* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected.
  * This may be any bit in the port.
  */
@@ -108,11 +171,11 @@ these macros are defined, the boot loader usees them.
 
 static inline void  bootLoaderInit(void)
 {
-    PORTD = 1 << 3; /* activate pull-up for key */
+    PORTD = 1 << PD6; /* activate pull-up for key */
     _delay_us(10);  /* wait for levels to stabilize */
 }
 
-#define bootLoaderCondition()   ((PIND & (1 << 3)) == 0)   /* True if jumper is set */
+#define bootLoaderCondition()   ((PIND & _BV(PIND6)) == 0)   /* True if jumper is set */
 
 #endif
 
diff --git a/firmware/main.c b/firmware/main.c
index e73f6e5..40ae858 100644
--- a/firmware/main.c
+++ b/firmware/main.c
@@ -8,6 +8,9 @@
  * This Revision: $Id$
  */
 
+
+#include "spminterface.h"
+
 #include <avr/io.h>
 #include <avr/interrupt.h>
 #include <avr/pgmspace.h>
@@ -21,6 +24,9 @@ static void leaveBootloader() __attribute__((__noreturn__));
 #include "bootloaderconfig.h"
 #include "usbdrv.c"
 
+//*****Software Lockbits***********************//
+#define BOOTLOADER_PAGEADDR        (BOOTLOADER_ADDRESS - (BOOTLOADER_ADDRESS % SPM_PAGESIZE))
+
 /* ------------------------------------------------------------------------ */
 
 #ifndef ulong
@@ -164,6 +170,13 @@ uchar   isLast;
 #endif
         DBG1(0x32, 0, 0);
         pageAddr = address.s[0] & (SPM_PAGESIZE - 1);
+
+	//*****Software Lockbits***********************//
+	if (address.l >= (addr_t)(BOOTLOADER_PAGEADDR)) {
+	  address.l += (addr_t)len;
+	  break;
+	}
+
         if(pageAddr == 0){              /* if page start: erase */
             DBG1(0x33, 0, 0);
 #ifndef TEST_MODE
@@ -243,7 +256,7 @@ int __attribute__((noreturn)) main(void)
                 }
             }
 #endif
-        }while(bootLoaderCondition());
+        }while(1);
     }
     leaveBootloader();
 }
diff --git a/firmware/main.hex b/firmware/main.hex
index d26b046..49c84de 100644
--- a/firmware/main.hex
+++ b/firmware/main.hex
@@ -1,111 +1,111 @@
-:1018000050C084C069C068C067C066C065C064C09D
-:1018100063C062C061C060C05FC05EC05DC05CC0CC
-:101820005BC05AC059C00600FF0901A1011500267E
-:10183000FF007508850195060900B2020185029531
-:10184000830900B20201C0090222000101008032B6
-:101850000904000001030000000921010100012228
-:101860002100070581030800C812011001000000D3
-:1018700008C016DF050001010200011003480049FD
-:1018800000440042006F006F00740012036F00629A
-:10189000006400650076002E0061007400040309F6
-:1018A000040011241FBECFE5D4E0DEBFCDBF10E0A1
-:1018B000A0E6B0E0EEEBFEE102C005900D92AA3684
-:1018C000B107D9F710E0AAE6B0E001C01D92AB392C
-:1018D000B107E1F74CD1F1C293CFA82FB92F80E027
-:1018E00090E041E050EA609530E009C02D918227F8
-:1018F0009795879510F084279527305EC8F36F5F22
-:10190000A8F30895EADF8D939D930895CF93CFB701
-:10191000CF93C395809BE9F7809B09C0809B07C04C
-:10192000809B05C0809B03C0809B01C0A3C0DF9348
-:10193000C0917E00DD27CB57DF4F809B02C0DF9137
-:10194000EBCF2F930F931F9300B32FEF00FB20F9E2
-:101950004F933F9310B34FEF012700FB21F93BE07A
-:1019600031C04E7F012F10B3216028C0102F4D7F52
-:101970002260000000B329C04B7F2460012F0000CB
-:1019800010B32BC010B3477F28602AC04F7E00B32E
-:1019900020612CC04F7D10B320622FC04F7B00B35D
-:1019A000206432C0422700B349934FEF0000102754
-:1019B00010FB20F910B31570C9F1297F91F20127AE
-:1019C00000FB21F900B3237F89F2315058F1102731
-:1019D00010FB22F910B3277E79F2012700FB23F9CF
-:1019E0002F7C81F200B3102710FB24F92F7971F2BC
-:1019F00000C010B3012700FB25F92F7359F200C076
-:101A000000B3102710FB26F9223040F200C010B3BB
-:101A1000012700FB27F9243028F64F77206810B300
-:101A20000000F9CF10E41ABF002719C03B503195D0
-:101A3000C31BD04010E41ABF0881033CF9F00B34FB
-:101A4000E9F020917C001981110F1213EDCF4A812A
-:101A5000441F093641F10D3211F0013E29F7009380
-:101A600083003F914F911F910F912F91DF91CAB742
-:101A7000C6FD4FCFCF91CFBFCF9118952091830056
-:101A8000222379F310918100112321F5343022F1C2
-:101A90003093810020937D0010917E003BE0311B4C
-:101AA00030937E0019C00091810001309CF40AE55A
-:101AB0004F7081F43091600034FD10C000936000DD
-:101AC000C1E7D0E00FC02795A8F45150A9F4220F28
-:101AD0000000F9CF4AE503C042ED01C0432FC4E145
-:101AE000D0E032E011B31560909A11BB02B320E44C
-:101AF00015E05F93012756E002BB279520F4515073
-:101B000021F4220FF9CF012756E000003B5A02BB17
-:101B1000D0F2279528F4515029F4220F0000F9CF74
-:101B2000012756E0279502BB20F4515021F4220FE3
-:101B3000F9CF012756E02991332302BB21F60A7F12
-:101B400010918200110FC651D04002BB11F01093CA
-:101B50007C0010E41ABF016011B31A7F402F4A7F46
-:101B60005F9100C000C002BB11BB42BB7ACF88E0CE
-:101B700082BB88E28A95F1F783998EC181E08BBFA1
-:101B800082E08BBF85B7836085BF8BB780648BBFD6
-:101B9000889A80E0A895E7EBFBE03197F1F700C069
-:101BA00000008150B9F788987894C0E0D0E0A895FB
-:101BB00060918100462F435047FD1BC120917E005C
-:101BC0008CE090E0821B9109DC01AB57BF4F209164
-:101BD0007D002D3209F0C0C0483009F008C123EC67
-:101BE000209371002AE52093600010926B003C91D5
-:101BF000432F407611962C9111974423E1F0293020
-:101C000079F412968C911297823031F410926C0014
-:101C100037FD8DC02FEF8EC081E080936A004BC1ED
-:101C2000213009F048C182E690E0909380008093D3
-:101C30007F0027E083C012963C91129710927A00A1
-:101C4000222331F410927B008AE790E022E06AC000
-:101C5000253019F43093820059C0263009F050C065
-:101C6000FC01E957FF4F208188579F4FFC0180817D
-:101C7000813019F489E698E11AC0823041F487E492
+:101800005FC093C078C077C076C075C074C073C025
+:1018100072C071C070C06FC06EC06DC06CC06BC054
+:101820006AC069C068C0EC2DFD2DB7B6B0FCFDCF15
+:1018300027BFE895B7B6B0FCFDCF21E1B7B6B6FC3F
+:10184000F4CF08950600FF0901A101150026FF004D
+:101850007508850195060900B20201850295830984
+:1018600000B20201C0090222000101008032090415
+:1018700000000103000000092101010001222100F4
+:10188000070581030800C81201100100000008C00C
+:1018900016DF050001010200011003480049004461
+:1018A0000042006F006F00740012036F006200645A
+:1018B00000650076002E0061007400040309040036
+:1018C00011241FBECFE5D4E0DEBFCDBF10E0A0E6FF
+:1018D000B0E0E8EBFEE102C005900D92AA36B10738
+:1018E000D9F720E0AAE6B0E001C01D92AB39B207FB
+:1018F000E1F733D1DFC284CFA82FB92F80E090E089
+:1019000041E050EA609530E009C02D91822797951B
+:10191000879510F084279527305EC8F36F5FA8F392
+:101920000895EADF8D939D930895CF93CFB7CF931A
+:10193000DF93C395879BE9F7879B0BC0879B09C003
+:10194000879B07C0879B05C0879B03C0879B01C0FF
+:101950008BC06F93C0917E00DD27CB57DF4F2F9355
+:1019600065E5879B03C02F916F91E6CF0F931F937F
+:101970004F9320E040E15F9300B3047807FB27F921
+:101980003F9350E03BE039C0147840642F77012F3B
+:101990005F5F1EC0406810B314782F7752501FC08D
+:1019A000406400B32F770478D1F15F5F00C023C09B
+:1019B000406210B32F77147891F15F5F00C025C0AB
+:1019C00004781027515012F45D5F000011502795E4
+:1019D0002C3F10B3C8F614780127015027952C3FEF
+:1019E000C8F64227499300B3047810274F7311506B
+:1019F00027952C3FA8F64695469510B3147879F0B4
+:101A00000127015027952C3F98F66B5A60F331500F
+:101A100000B3B0F600C010E41ABF002719C03B5055
+:101A20003195C31BD04010E41ABF0881033C09F173
+:101A30000B34F9F020917C001981110F1213EDCFB6
+:101A40004A81441F093651F10D3211F0013E29F748
+:101A5000009383003F915F914F911F910F912F91C0
+:101A60006F91CAB7C6FD65CFDF91CF91CFBFCF9140
+:101A7000189520918300222369F31091810011238E
+:101A800049F534304AF13093810020937D00109164
+:101A90007E003BE0311B30937E001EC00091810030
+:101AA0000130C4F40AE54F70A9F43091600034FDB0
+:101AB00014C000936000C1E7D0E013C0052710E018
+:101AC00000C0000002BB1AC0052710E0221F1DC085
+:101AD00010E021C04AE502C032ED432FC4E1D0E05E
+:101AE00032E011B31468979A02B311BB54E820E8AE
+:101AF00065E320FF052702BB279517951C3FF0F6ED
+:101B00006695B8F7B1F720FF052702BB2795179513
+:101B10001C3FD0F62795179517FF052700001C3F9F
+:101B200002BBB0F629913A9519F70B771091820014
+:101B3000110FC651D04002BB11F010937C0010E48D
+:101B40001ABF006811B31B77402F4B7754E05A95AA
+:101B5000F1F702BB11BB42BB7DCF80E482BB35E312
+:101B60003A95F1F70000869B0FC0F89481E18093CD
+:101B70005700E8951BBE15BE81E08BBF1BBEE091F0
+:101B80006F00F0917000099581E08BBF82E08BBF00
+:101B900085B7836085BF8BB780648BBF8F9A80E0E9
+:101BA000A895EFE9FFE03197F1F700C00000815000
+:101BB000B9F78F987894C0E0D0E0A8953091810073
+:101BC000432F435047FD1DC180917E00ACE0B0E043
+:101BD000A81BB109AB57BF4F80917D008D3209F032
+:101BE000BAC0483009F00BC183EC809371008AE5DC
+:101BF0008093600010926B009C91292F20761196A3
+:101C00008C9111972223E1F0893079F412968C910E
+:101C10001297823031F410926C0097FD89C02FEF3B
+:101C200089C081E080936A0043C1813009F040C1DE
+:101C300082E690E09093800080937F0027E07EC052
+:101C400012969C91129710927A00811106C0109200
+:101C50007B008AE790E022E066C0853019F490931B
+:101C6000820057C0863009F04BC013968C911397B1
+:101C7000813019F487E898E11AC0823041F485E692
 :101C800098E19093800080937F0022E235C08330FA
-:101C9000F1F4222341F48DE998E190938000809340
-:101CA0007F0024E029C0213041F48BE898E1909333
-:101CB000800080937F0022E11FC02230E1F48BE797
+:101C9000F1F4911108C08BEB98E190938000809350
+:101CA0007F0024E029C0913041F489EA98E19093C3
+:101CB000800080937F0022E11FC09230E1F489E927
 :101CC00098E19093800080937F0020E115C08132DD
-:101CD00041F489E598E19093800080937F0029E0AA
-:101CE0000BC0823241F486E298E1909380008093A9
+:101CD00041F487E798E19093800080937F0029E0AA
+:101CE0000BC0823241F484E498E1909380008093A9
 :101CF0007F0021E201C020E080E480936B001EC0E1
-:101D0000283069F0293029F4309384008AE790E084
-:101D100004C08AE790E02A3021F020E003C084E884
-:101D200090E021E09093800080937F0007C016969A
-:101D30002C91169780E880936B000BC017968C91BE
-:101D40001797882331F416968C911697821708F40A
-:101D5000282F209361004BC020916B0027FF47C0C4
-:101D600020916D0030916E0050916C00552359F414
-:101D7000FC01EA57FF4F208189579F4FFC013081BA
-:101D80001496462F4750540F50936C005078822F72
-:101D90008F7351F4F89483E0F90180935700E8952C
-:101DA000789407B600FCFDCFF8948D919D9161E089
-:101DB000F9010C0160935700E895112478942E5F87
-:101DC0003F4F822F8F7349F4F89485E0809357003A
-:101DD000E895789407B600FCFDCF4250C1F63093E9
-:101DE0006E0020936D00552311F010926100109247
-:101DF00081008091600084FF3BC0809161008F3F33
-:101E0000B9F1182F893008F018E0811B8093610028
-:101E10008091710098E88927809371001123E1F087
-:101E2000E0917F00F091800080916B0086FF09C0F7
-:101E3000812FA2E7B0E094919D9331968150D9F71C
-:101E400007C0812FA2E7B0E091919D938150E1F707
-:101E5000F0938000E0937F0082E790E0612F52DDF5
-:101E60001C5F1C3019F08FEF8093610010936000AD
-:101E700084E190B3957031F48150D9F710928200CB
-:101E800010927C0080916A00882321F0D15011F4D7
-:101E9000C15011F0839B8BCEF89481E18093570061
-:101EA000E8951BBE15BE81E08BBF1BBEE0916F00A5
-:0E1EB000F0917000099520E041CFF894FFCF2B
-:0A1EBE005AFF014000002000000060
+:101D0000883059F0893019F49093840002C08A30E9
+:101D100039F08AE790E020E006C084E890E002C055
+:101D20008AE790E021E09093800080937F0006C0D6
+:101D300016962C9180E880936B000AC017968C91C0
+:101D40001797811105C016968C91821708F4282FD9
+:101D50002093610054C080916B0087FF50C0809138
+:101D60006D0090916E0020916C00211109C01196B8
+:101D70008C91119712969C9112971496432F47506D
+:101D8000240F20936C00522F5078282F2F73811529
+:101D9000F8E19F0718F0840F911D2AC0222381F0DB
+:101DA000F8942D913D9161E0FC0109016093570089
+:101DB000E895112478940296282F2F7379F00BC0A0
+:101DC000F89423E0FC0120935700E895789407B637
+:101DD00000FCFDCFE5CF4250C1F60AC0F89425E0E3
+:101DE00020935700E895789407B600FCFDCFF3CF19
+:101DF00090936E0080936D005111109261001092CB
+:101E000081008091600084FF3DC0809161008F3F20
+:101E1000C9F1182F893008F018E0811B8093610008
+:101E20008091710098E88927809371001123F1F067
+:101E3000E0917F00F091800080916B00A2E7B0E01C
+:101E400086FF09C084918D93319682E790E0810FDF
+:101E50008A13F8CF07C081918D9382E790E0810FBC
+:101E60008A13F9CFF0938000E0937F00612F82E71F
+:101E700090E057DD1C5F1C3019F08FEF80936100FC
+:101E80001093600084E190B3947831F48150D9F7D5
+:101E90001092820010927C0080916A00882309F4DD
+:101EA0008CCED15009F089CEC15009F086CE5DCEDE
+:081EB00020E044CFF894FFCFBD
+:0A1EB8005AFF014000002000000066
 :0400000300001800E1
 :00000001FF
diff --git a/firmware/spminterface.h b/firmware/spminterface.h
new file mode 100644
index 0000000..c65df01
--- /dev/null
+++ b/firmware/spminterface.h
@@ -0,0 +1,773 @@
+/* Name: spminterface.h
+ * Project: USBaspLoader
+ * Author: Stephan Baerwolf
+ * Creation Date: 2012-08-01
+ * Copyright: (c) 2013 by Stephan Baerwolf
+ * License: GNU GPL v2 (see License.txt)
+ * Version: 0.96.4-rc5alpha
+ */
+
+#ifndef SPMINTERFACE_H_f70ba6adf7624275947e859bdbff0599
+#define SPMINTERFACE_H_f70ba6adf7624275947e859bdbff0599
+
+/*
+ * spminterface.h offers a lightweight interface by inserting
+ * an small machine-subroutine into the bootsection. (right 
+ * after the interrupt-vector-table)
+ * This subroutine can be called by normal code in order to 
+ * enable it to program the flash (and depending on BLB11-lockbit
+ * also the bootsection itself). Since SPM-calls from RWW-sections
+ * will fail to work. The routine will be called "bootloader__do_spm".
+ * Its principle assembler-code is depicted below (real code is a
+ * little machinedependend).
+ * Interfaces will be the 8-bit registers r10..r13, for details 
+ * also see below. As also the pageaddress-registes (Z and rampZ)
+ * are interfaced via different registers, it is possible to call
+ * this routine via indirect call (icall).
+ * Traditionally it is also possible to rcall, therefore you can
+ * define "bootloader__do_spm" for your normal code via defsym at 
+ * linking time.
+ * Example for an atmega8: "-Wl,--defsym=transfer_point=0x1826"
+ * (since BOOTLOADER_ADDRESS is 0x1800 and there are 
+ * 2x19 = 38 = 0x26 byte for interrupts)
+ * 
+
+bootloader__do_spm:
+;disable interrupts (if enabled) before calling!
+;you may also want to disable wdt, since this routine may busy-loop
+;==================================================================
+;-->INPUT:
+;#if HAVE_SPMINTEREFACE_MAGICVALUE
+;magicvalue in                                    r23:r22:r21:r20
+;#endif
+;spmcr (spmcrval determines SPM action) will be register:	r18
+;MCU dependend RA(MPZ should be transfered within register:	r11
+;lo8(Z) should be transfered within register:			r12
+;hi8(Z) should be transfered within register:			r13
+;( as definition of SPM low8bit of dataword are stored within	r0 )
+;( as definition of SPM hi8bit  of dataword are stored within	r1 )
+
+;<-->USED/CHANGED:
+;temp0 will be register:					r11
+;temp1 will be register:					r12
+;temp2 will be register:					r13
+;spmcrval (r18) may also be changed due to rww reenable-phase	r18
+;Z (r31:r30) wil be changed during operation
+
+;<--OUT:
+;==================================================================
+; TODO: waitA and waitB could be merged to subroutine saving 2 opc
+;==================================================================
+;<magicvalue specific code (not depicted here)>
+;load pageaddress (Z) from (r11:)r13:12 since it may was used for icall
+mov	rampZ,	r11
+mov	r30,	r12
+mov	r31,	r13
+
+waitA:			;check for pending SPM complete
+in	temp0, SPMCR
+sbrc	temp0, SPMEN
+rjmp	waitA
+
+out	SPMCR, spmcrval	;SPM timed sequence
+spm
+
+waitB:			;check for previous SPM complete
+in	temp0, SPMCR
+sbrc	temp0, SPMEN
+rjmp	waitB
+
+;avoid crash of userapplication
+ldi	spmcrval, ((1<<RWWSRE) | (1<<SPMEN)) 
+in	temp0,	  SPMCR
+sbrc	temp0,	  RWWSB
+rjmp	waitA
+
+ret
+
+*
+*/ 
+
+#include <avr/io.h>
+#include "bootloaderconfig.h"
+
+
+
+/*
+ * This MACRO commands the linker to place correspondig
+ * data on the top of the firmware. (Right after the 
+ * interrupt-vector-table)
+ * This is necessary to always locate the
+ * "bootloader__do_spm" for example at 0x1826, even if
+ * there are existing PROGMEM within the firmware...
+ */
+#define BOOTLIBLINK __attribute__ ((section (".vectors") ))
+
+
+#ifndef funcaddr___bootloader__do_spm
+  #if (defined(BOOTLOADER_ADDRESS)) && (!(defined(NEW_BOOTLOADER_ADDRESS)))
+    #if HAVE_SPMINTEREFACE
+      #define  funcaddr___bootloader__do_spm (&bootloader__do_spm)
+    #endif  
+  #else
+    #if defined (__AVR_ATmega8535__)
+      #define  funcaddr___bootloader__do_spm 0x182a
+    #elif defined (__AVR_ATmega8__) || defined (__AVR_ATmega8A__) || defined (__AVR_ATmega8HVA__)
+      #define  funcaddr___bootloader__do_spm 0x1826
+    #elif defined (__AVR_ATmega16__)
+      #define  funcaddr___bootloader__do_spm 0x3854
+    #elif defined (__AVR_ATmega32__)
+      #define  funcaddr___bootloader__do_spm 0x7054
+    #elif defined (__AVR_ATmega88__) || defined (__AVR_ATmega88P__) || defined (__AVR_ATmega88A__) || defined (__AVR_ATmega88PA__)  
+      #define  funcaddr___bootloader__do_spm 0x1834
+    #elif defined (__AVR_ATmega164A__) || defined (__AVR_ATmega164P__) || defined (__AVR_ATmega164PA__)  
+      #define  funcaddr___bootloader__do_spm 0x387c
+    #elif defined (__AVR_ATmega168__) || defined (__AVR_ATmega168P__) || defined (__AVR_ATmega168A__) || defined (__AVR_ATmega168PA__)  
+      #define  funcaddr___bootloader__do_spm 0x3868
+    #elif defined (__AVR_ATmega324A__) || defined (__AVR_ATmega324P__) || defined (__AVR_ATmega324PA__)
+      #define  funcaddr___bootloader__do_spm 0x707c
+    #elif defined (__AVR_ATmega328__) || defined (__AVR_ATmega328P__)
+      #define  funcaddr___bootloader__do_spm 0x7068
+    #elif defined (__AVR_ATmega640__)
+      #define  funcaddr___bootloader__do_spm 0xe0e4
+    #elif defined (__AVR_ATmega644__) || defined (__AVR_ATmega644A__) || defined (__AVR_ATmega644P__) || defined (__AVR_ATmega644PA__)
+      #define  funcaddr___bootloader__do_spm 0xe07c
+    #elif defined (__AVR_ATmega128__)
+      #define  funcaddr___bootloader__do_spm 0x1e08c
+    #elif defined (__AVR_ATmega1280__)
+      #define  funcaddr___bootloader__do_spm 0x1e0e4
+    #elif defined (__AVR_ATmega1281__)
+      #define  funcaddr___bootloader__do_spm 0x1e0cc
+    #elif defined (__AVR_ATmega1284__) || defined (__AVR_ATmega1284P__)
+      #define  funcaddr___bootloader__do_spm 0x1e08c
+    #elif defined (__AVR_ATmega2560__)
+      #define  funcaddr___bootloader__do_spm 0x3e0e4
+    #elif defined (__AVR_ATmega2561__)
+      #define  funcaddr___bootloader__do_spm 0x3e0cc
+    #else
+      #error "unknown MCU - where is bootloader__do_spm located?"
+    #endif
+
+    #if ((defined(_VECTORS_SIZE)) && (defined(BOOTLOADER_ADDRESS)))
+      #if (funcaddr___bootloader__do_spm != (BOOTLOADER_ADDRESS+_VECTORS_SIZE))
+	#error "bootloader__do_spm is not located after interrupts - sth. is very wrong here!" 
+      #endif
+    #endif  
+
+  #endif
+#endif
+
+
+#ifndef SPMEN
+#define SPMEN SELFPRGEN
+#endif
+
+/*
+ * Call the "bootloader__do_spm"-function, located within the BLS via comfortable C-interface
+ * During operation code will block - disable or reset watchdog before call.
+ * 
+ * ATTANTION:	Since the underlying "bootloader__do_spm" will automatically reenable the
+ * 		rww-section, only one way to program the flash will work.
+ * 		(First erase the page, then fill temp. buffer, finally program...)
+ * 		Since unblocking rww-section erases the temp. pagebuffer (which happens
+ * 		after a page-erase), first programming this buffer does not help !!
+ * 
+ * REMEMBER: interrupts have to be disabled! (otherwise code may crash non-deterministic)
+ * 
+ */
+
+#define __do_spm_Ex(arguments...)	__do_spm_GeneralEx(HAVE_SPMINTEREFACE_MAGICVALUE, ##arguments)
+
+
+#if HAVE_SPMINTEREFACE_MAGICVALUE
+#define __do_spm_GeneralEx	__do_spm_ExASMEx_magic
+#else
+#define __do_spm_GeneralEx	__do_spm_ExASMEx_
+#endif
+
+
+#if (defined(EIND) && ((FLASHEND)>131071))
+  /*
+  * Huge flash version using eicall (and EIND)
+  * MV defines the magic value to be send to bootloader_do_spm
+  */
+  #define __do_spm_ExASMEx_(MV, flash_wordaddress, spmcrval, dataword, ___bootloader__do_spm__ptr)	\
+  ({													\
+      asm volatile (											\
+      "push r0\n\t"  											\
+      "push r1\n\t"  											\
+													\
+      "mov r13, %B[flashaddress]\n\t"									\
+      "mov r12, %A[flashaddress]\n\t"									\
+      "mov r11, %C[flashaddress]\n\t"									\
+													\
+      /* prepare the EIND for following eicall */							\
+      "in r18, %[eind]\n\t"										\
+      "push r18\n\t" 											\
+      "ldi r18, %[spmfuncaddrEIND]\n\t"									\
+      "out %[eind], r18\n\t"										\
+													\
+      /* also load the spmcrval */									\
+      "mov r18, %[spmcrval]\n\t"									\
+													\
+													\
+      "mov r1, %B[data]\n\t"										\
+      "mov r0, %A[data]\n\t"										\
+													\
+      /* finally call the bootloader-function */							\
+      "eicall\n\t"											\
+      "pop r1\n\t"  											\
+      "out %[eind], r1\n\t"										\
+													\
+      /*												\
+      * bootloader__do_spm should change spmcrval (r18) to						\
+      * "((1<<RWWSRE) | (1<<SPMEN))" in case of success							\
+      */												\
+      "cpi r18, %[spmret]\n\t"										\
+      /* loop infitinte if not so, most likely we called an bootloader__do_spm				\
+	* with wrong magic! To avoid calls to wrong initialized pages, better crash here...		\
+	*/												\
+  "loop%=: \n\t"											\
+      "brne loop%= \n\t"										\
+													\
+      "pop  r1\n\t"  											\
+      "pop  r0\n\t"  											\
+													\
+      :													\
+      : [flashaddress]		"r" (flash_wordaddress),						\
+	[spmfunctionaddress]	"z" ((uint16_t)(___bootloader__do_spm__ptr)),				\
+	[spmfuncaddrEIND]	"M" ((uint8_t)(___bootloader__do_spm__ptr>>16)),			\
+	[eind]			"I" (_SFR_IO_ADDR(EIND)),						\
+	[spmcrval]		"r" (spmcrval),								\
+	[data]			"r" (dataword),								\
+	[spmret]		"M" ((1<<RWWSRE) | (1<<SPMEN))						\
+      : "r0","r1","r11","r12","r13","r18"								\
+      );												\
+  })
+
+  #define __do_spm_ExASMEx_magic(MV, flash_wordaddress, spmcrval, dataword, ___bootloader__do_spm__ptr)	\
+  ({													\
+      asm volatile (											\
+      "push r0\n\t"  											\
+      "push r1\n\t"  											\
+													\
+      "ldi r23, %[magicD] \n\t"										\
+      "ldi r22, %[magicC] \n\t"										\
+      "ldi r21, %[magicB] \n\t"										\
+      "ldi r20, %[magicA] \n\t"										\
+													\
+      "mov r13, %B[flashaddress]\n\t"									\
+      "mov r12, %A[flashaddress]\n\t"									\
+      "mov r11, %C[flashaddress]\n\t"									\
+													\
+      /* prepare the EIND for following eicall */							\
+      "in r18, %[eind]\n\t"										\
+      "push r18\n\t"  											\
+      "ldi r18, %[spmfuncaddrEIND]\n\t"									\
+      "out %[eind], r18\n\t"										\
+													\
+      /* also load the spmcrval */									\
+      "mov r18, %[spmcrval]\n\t"									\
+													\
+													\
+      "mov r1, %B[data]\n\t"										\
+      "mov r0, %A[data]\n\t"										\
+													\
+      /* finally call the bootloader-function */							\
+      "eicall\n\t"											\
+      "pop r1\n\t"  											\
+      "out %[eind], r1\n\t"										\
+													\
+      /*												\
+      * bootloader__do_spm should change spmcrval (r18) to						\
+      * "((1<<RWWSRE) | (1<<SPMEN))" in case of success							\
+      */												\
+      "cpi r18, %[spmret]\n\t"										\
+      /* loop infitinte if not so, most likely we called an bootloader__do_spm				\
+	* with wrong magic! To avoid calls to wrong initialized pages, better crash here...		\
+	*/												\
+  "loop%=: \n\t"											\
+      "brne loop%= \n\t"										\
+													\
+      "pop  r1\n\t"  											\
+      "pop  r0\n\t"  											\
+													\
+      :													\
+      : [flashaddress] "r" (flash_wordaddress),								\
+	[spmfunctionaddress] "z" ((uint16_t)(___bootloader__do_spm__ptr)),				\
+	[spmfuncaddrEIND]	"M" ((uint8_t)(___bootloader__do_spm__ptr>>16)),			\
+	[eind]			"I" (_SFR_IO_ADDR(EIND)),						\
+	[spmcrval] "r" (spmcrval),									\
+	[data] "r" (dataword),										\
+	[spmret] "M" ((1<<RWWSRE) | (1<<SPMEN)),							\
+	[magicD] "M" (((MV)>>24)&0xff),									\
+	[magicC] "M" (((MV)>>16)&0xff),									\
+	[magicB] "M" (((MV)>> 8)&0xff),									\
+	[magicA] "M" (((MV)>> 0)&0xff)									\
+      : "r0","r1","r11","r12","r13","r18","r20","r21","r22","r23"					\
+      );												\
+  })
+
+
+#else
+  /*
+  * Normal version for devices with <=128KiB flash (using icall)
+  */
+  #if ((FLASHEND)>131071)
+    #error "Using inappropriate code for device with more than 128kib flash"
+  #endif
+  
+  #define __do_spm_ExASMEx_(MV, flash_wordaddress, spmcrval, dataword, ___bootloader__do_spm__ptr)	\
+  ({													\
+      asm volatile (											\
+      "push r0\n\t"  											\
+      "push r1\n\t"  											\
+													\
+      "mov r13, %B[flashaddress]\n\t"									\
+      "mov r12, %A[flashaddress]\n\t"									\
+      "mov r11, %C[flashaddress]\n\t"									\
+													\
+      /* also load the spmcrval */									\
+      "mov r18, %[spmcrval]\n\t"									\
+													\
+													\
+      "mov r1, %B[data]\n\t"										\
+      "mov r0, %A[data]\n\t"										\
+													\
+      /* finally call the bootloader-function */							\
+      "icall\n\t"											\
+													\
+      /*												\
+      * bootloader__do_spm should change spmcrval (r18) to						\
+      * "((1<<RWWSRE) | (1<<SPMEN))" in case of success							\
+      */												\
+      "cpi r18, %[spmret]\n\t"										\
+      /* loop infitinte if not so, most likely we called an bootloader__do_spm				\
+	* with wrong magic! To avoid calls to wrong initialized pages, better crash here...		\
+	*/												\
+  "loop%=: \n\t"											\
+      "brne loop%= \n\t"										\
+													\
+      "pop  r1\n\t"  											\
+      "pop  r0\n\t"  											\
+													\
+      :													\
+      : [flashaddress] "r" (flash_wordaddress),								\
+	[spmfunctionaddress] "z" ((uint16_t)(___bootloader__do_spm__ptr)),				\
+	[spmcrval] "r" (spmcrval),									\
+	[data] "r" (dataword),										\
+	[spmret] "M" ((1<<RWWSRE) | (1<<SPMEN))								\
+      : "r0","r1","r11","r12","r13","r18"								\
+      );												\
+  })
+
+  #define __do_spm_ExASMEx_magic(MV, flash_wordaddress, spmcrval, dataword, ___bootloader__do_spm__ptr)	\
+  ({													\
+      asm volatile (											\
+      "push r0\n\t"  											\
+      "push r1\n\t"  											\
+													\
+      "ldi r23, %[magicD] \n\t"										\
+      "ldi r22, %[magicC] \n\t"										\
+      "ldi r21, %[magicB] \n\t"										\
+      "ldi r20, %[magicA] \n\t"										\
+													\
+      "mov r13, %B[flashaddress]\n\t"									\
+      "mov r12, %A[flashaddress]\n\t"									\
+      "mov r11, %C[flashaddress]\n\t"									\
+													\
+      /* also load the spmcrval */									\
+      "mov r18, %[spmcrval]\n\t"									\
+													\
+													\
+      "mov r1, %B[data]\n\t"										\
+      "mov r0, %A[data]\n\t"										\
+													\
+      /* finally call the bootloader-function */							\
+      "icall\n\t"											\
+													\
+      /*												\
+      * bootloader__do_spm should change spmcrval (r18) to						\
+      * "((1<<RWWSRE) | (1<<SPMEN))" in case of success							\
+      */												\
+      "cpi r18, %[spmret]\n\t"										\
+      /* loop infitinte if not so, most likely we called an bootloader__do_spm				\
+	* with wrong magic! To avoid calls to wrong initialized pages, better crash here...   		\
+	*/												\
+  "loop%=: \n\t"											\
+      "brne loop%= \n\t"										\
+													\
+      "pop  r1\n\t"  											\
+      "pop  r0\n\t"  											\
+													\
+      :													\
+      : [flashaddress] "r" (flash_wordaddress),								\
+	[spmfunctionaddress] "z" ((uint16_t)(___bootloader__do_spm__ptr)),				\
+	[spmcrval] "r" (spmcrval),									\
+	[data] "r" (dataword),										\
+	[spmret] "M" ((1<<RWWSRE) | (1<<SPMEN)),							\
+	[magicD] "M" (((MV)>>24)&0xff),									\
+	[magicC] "M" (((MV)>>16)&0xff),									\
+	[magicB] "M" (((MV)>> 8)&0xff),									\
+	[magicA] "M" (((MV)>> 0)&0xff)									\
+      : "r0","r1","r11","r12","r13","r18","r20","r21","r22","r23"					\
+      );												\
+  })
+#endif
+
+#if (!(defined(BOOTLOADER_ADDRESS))) || (defined(NEW_BOOTLOADER_ADDRESS))
+void do_spm(const uint32_t flash_byteaddress, const uint8_t spmcrval, const uint16_t dataword) {
+    __do_spm_Ex(flash_byteaddress, spmcrval, dataword, funcaddr___bootloader__do_spm >> 1);
+}
+#endif
+
+#if HAVE_SPMINTEREFACE_NORETMAGIC
+  #define bootloader__do_spm_magic_exitstrategy(a) (0xf7f9)
+#else
+  #define bootloader__do_spm_magic_exitstrategy(a) (a)
+#endif
+
+#if (HAVE_SPMINTEREFACE) && (defined(BOOTLOADER_ADDRESS)) && (!(defined(NEW_BOOTLOADER_ADDRESS)))
+
+/*
+ * insert architecture dependend "bootloader_do_spm"-code
+ * 
+ * try to make this array as big as possible
+ * (so bootloader always uses 2kbytes flash)
+ */
+#if defined (__AVR_ATmega8535__) || defined (__AVR_ATmega8__) || defined (__AVR_ATmega8A__) || defined (__AVR_ATmega8HVA__) || defined (__AVR_ATmega16__) || defined (__AVR_ATmega32__)
+
+#if defined (__AVR_ATmega8535__) || defined (__AVR_ATmega8__) || defined (__AVR_ATmega8A__) || defined (__AVR_ATmega8HVA__)
+  #if (BOOTLOADER_ADDRESS != 0x1800)
+    #error BOOTLOADER_ADDRESS!=0x1800, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use
+  #endif
+#elif defined (__AVR_ATmega16__)
+  #if (BOOTLOADER_ADDRESS != 0x3800)
+    #error BOOTLOADER_ADDRESS!=0x3800, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use
+  #endif
+#elif defined (__AVR_ATmega32__)
+  #if (BOOTLOADER_ADDRESS != 0x7000)
+    #error BOOTLOADER_ADDRESS!=0x7000, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use
+  #endif
+#else
+  #error undefined device selection - this should not happen! 
+#endif
+
+//assume  SPMCR==0x37, SPMEN==0x0, RWWSRE=0x4, RWWSB=0x6
+#if HAVE_SPMINTEREFACE_MAGICVALUE
+const uint16_t bootloader__do_spm[23] BOOTLIBLINK = {
+  (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE >> 28) & 0xf))<<8) | (0x70 | ((HAVE_SPMINTEREFACE_MAGICVALUE >> 24) & 0xf))), // r23
+  bootloader__do_spm_magic_exitstrategy(0xf4a1), // brne +20
+  (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE >> 20) & 0xf))<<8) | (0x60 | ((HAVE_SPMINTEREFACE_MAGICVALUE >> 16) & 0xf))), // r22
+  bootloader__do_spm_magic_exitstrategy(0xf491), // brne +18
+  (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE >> 12) & 0xf))<<8) | (0x50 | ((HAVE_SPMINTEREFACE_MAGICVALUE >>  8) & 0xf))), // r21
+  bootloader__do_spm_magic_exitstrategy(0xf481), // brne +16
+  (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE >>  4) & 0xf))<<8) | (0x40 | ((HAVE_SPMINTEREFACE_MAGICVALUE >>  0) & 0xf))), // r20
+  bootloader__do_spm_magic_exitstrategy(0xf471), // brne +14
+#else
+const uint16_t bootloader__do_spm[15] BOOTLIBLINK = {
+#endif
+  0x2dec, 0x2dfd, 0xb6b7, 0xfcb0, 0xcffd, 0xbf27, 0x95e8, 0xb6b7,
+  0xfcb0, 0xcffd, 0xe121, 0xb6b7, 0xfcb6, 0xcff4, 0x9508
+};
+
+/*
+00001826 <bootloader__do_spm>:
+    1828:	ec 2d       	mov	r30, r12
+    182a:	fd 2d       	mov	r31, r13
+
+0000182c <waitA>:
+    182c:	b7 b6       	in	r11, 0x37	; 55
+    182e:	b0 fc       	sbrc	r11, 0
+    1830:	fd cf       	rjmp	.-6      	; 0x182c <waitA>
+    1832:	27 bf       	out	0x37, r18	; 55
+    1834:	e8 95       	spm
+
+00001836 <waitB>:
+    1836:	b7 b6       	in	r11, 0x37	; 55
+    1838:	b0 fc       	sbrc	r11, 0
+    183a:	fd cf       	rjmp	.-6      	; 0x1836 <waitB>
+    183c:	21 e1       	ldi	r18, 0x11	; 17
+    183e:	b7 b6       	in	r11, 0x37	; 55
+    1840:	b6 fc       	sbrc	r11, 6
+    1842:	f4 cf       	rjmp	.-24     	; 0x182c <waitA>
+    1844:	08 95       	ret
+*/
+
+
+
+
+
+#elif defined (__AVR_ATmega48__) || defined (__AVR_ATmega48P__) || defined (__AVR_ATmega88__) || defined (__AVR_ATmega88P__) || defined (__AVR_ATmega168__) || defined (__AVR_ATmega168P__)
+
+#if defined (__AVR_ATmega88__) || defined (__AVR_ATmega88P__)
+  #if (BOOTLOADER_ADDRESS != 0x1800)
+    #error BOOTLOADER_ADDRESS!=0x1800, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use
+  #endif
+#elif defined (__AVR_ATmega168__) || defined (__AVR_ATmega168P__)
+  #if (BOOTLOADER_ADDRESS != 0x3800)
+    #error BOOTLOADER_ADDRESS!=0x3800, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use
+  #endif
+#else
+  #error undefined device selection - this should not happen! 
+#endif
+
+//assume  SPMCR:=SPMCSR==0x37, SPMEN:=SELFPRGEN==0x0, RWWSRE=0x4, RWWSB=0x6
+#if HAVE_SPMINTEREFACE_MAGICVALUE
+const uint16_t bootloader__do_spm[23] BOOTLIBLINK = {
+  (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE >> 28) & 0xf))<<8) | (0x70 | ((HAVE_SPMINTEREFACE_MAGICVALUE >> 24) & 0xf))), // r23
+  bootloader__do_spm_magic_exitstrategy(0xf4a1), // brne +20
+  (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE >> 20) & 0xf))<<8) | (0x60 | ((HAVE_SPMINTEREFACE_MAGICVALUE >> 16) & 0xf))), // r22
+  bootloader__do_spm_magic_exitstrategy(0xf491), // brne +18
+  (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE >> 12) & 0xf))<<8) | (0x50 | ((HAVE_SPMINTEREFACE_MAGICVALUE >>  8) & 0xf))), // r21
+  bootloader__do_spm_magic_exitstrategy(0xf481), // brne +16
+  (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE >>  4) & 0xf))<<8) | (0x40 | ((HAVE_SPMINTEREFACE_MAGICVALUE >>  0) & 0xf))), // r20
+  bootloader__do_spm_magic_exitstrategy(0xf471), // brne +14
+#else
+const uint16_t bootloader__do_spm[15] BOOTLIBLINK = {
+#endif
+  0x2dec, 0x2dfd, 0xb6b7, 0xfcb0, 0xcffd, 0xbf27, 0x95e8, 0xb6b7,
+  0xfcb0, 0xcffd, 0xe121, 0xb6b7, 0xfcb6, 0xcff4, 0x9508
+};
+/*
+00001826 <bootloader__do_spm>:
+    1828:	ec 2d       	mov	r30, r12
+    182a:	fd 2d       	mov	r31, r13
+
+0000182c <waitA>:
+    182c:	b7 b6       	in	r11, 0x37	; 55
+    182e:	b0 fc       	sbrc	r11, 0
+    1830:	fd cf       	rjmp	.-6      	; 0x182c <waitA>
+    1832:	27 bf       	out	0x37, r18	; 55
+    1834:	e8 95       	spm
+
+00001836 <waitB>:
+    1836:	b7 b6       	in	r11, 0x37	; 55
+    1838:	b0 fc       	sbrc	r11, 0
+    183a:	fd cf       	rjmp	.-6      	; 0x1836 <waitB>
+    183c:	21 e1       	ldi	r18, 0x11	; 17
+    183e:	b7 b6       	in	r11, 0x37	; 55
+    1840:	b6 fc       	sbrc	r11, 6
+    1842:	f4 cf       	rjmp	.-24     	; 0x182c <waitA>
+    1844:	08 95       	ret
+*/
+
+
+
+
+
+#elif defined (__AVR_ATmega48A__) || defined (__AVR_ATmega48PA__) || defined (__AVR_ATmega88A__) || defined (__AVR_ATmega88PA__) || defined (__AVR_ATmega168A__) || defined (__AVR_ATmega168PA__) || defined (__AVR_ATmega328__) || defined (__AVR_ATmega328P__)
+
+#if defined (__AVR_ATmega88A__) || defined (__AVR_ATmega88PA__)
+  #if (BOOTLOADER_ADDRESS != 0x1800)
+    #error BOOTLOADER_ADDRESS!=0x1800, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use
+  #endif
+#elif defined (__AVR_ATmega168A__) || defined (__AVR_ATmega168PA__)
+  #if (BOOTLOADER_ADDRESS != 0x3800)
+    #error BOOTLOADER_ADDRESS!=0x3800, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use
+  #endif
+#elif defined (__AVR_ATmega328__) || defined (__AVR_ATmega328P__)
+  #if (BOOTLOADER_ADDRESS != 0x7000)
+    #error BOOTLOADER_ADDRESS!=0x7000, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use
+  #endif
+#else
+  #error undefined device selection - this should not happen! 
+#endif
+
+//assume  SPMCR:=SPMCSR==0x37, SPMEN:=SELFPRGEN==0x0, RWWSRE=0x4, RWWSB=0x6
+#if HAVE_SPMINTEREFACE_MAGICVALUE
+const uint16_t bootloader__do_spm[23] BOOTLIBLINK = {
+  (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE >> 28) & 0xf))<<8) | (0x70 | ((HAVE_SPMINTEREFACE_MAGICVALUE >> 24) & 0xf))), // r23
+  bootloader__do_spm_magic_exitstrategy(0xf4a1), // brne +20
+  (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE >> 20) & 0xf))<<8) | (0x60 | ((HAVE_SPMINTEREFACE_MAGICVALUE >> 16) & 0xf))), // r22
+  bootloader__do_spm_magic_exitstrategy(0xf491), // brne +18
+  (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE >> 12) & 0xf))<<8) | (0x50 | ((HAVE_SPMINTEREFACE_MAGICVALUE >>  8) & 0xf))), // r21
+  bootloader__do_spm_magic_exitstrategy(0xf481), // brne +16
+  (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE >>  4) & 0xf))<<8) | (0x40 | ((HAVE_SPMINTEREFACE_MAGICVALUE >>  0) & 0xf))), // r20
+  bootloader__do_spm_magic_exitstrategy(0xf471), // brne +14
+#else
+const uint16_t bootloader__do_spm[15] BOOTLIBLINK = {
+#endif
+  0x2dec, 0x2dfd, 0xb6b7, 0xfcb0, 0xcffd, 0xbf27, 0x95e8, 0xb6b7,
+  0xfcb0, 0xcffd, 0xe121, 0xb6b7, 0xfcb6, 0xcff4, 0x9508
+};
+/*
+00001826 <bootloader__do_spm>:
+    1828:	ec 2d       	mov	r30, r12
+    182a:	fd 2d       	mov	r31, r13
+
+0000182c <waitA>:
+    182c:	b7 b6       	in	r11, 0x37	; 55
+    182e:	b0 fc       	sbrc	r11, 0
+    1830:	fd cf       	rjmp	.-6      	; 0x182c <waitA>
+    1832:	27 bf       	out	0x37, r18	; 55
+    1834:	e8 95       	spm
+
+00001836 <waitB>:
+    1836:	b7 b6       	in	r11, 0x37	; 55
+    1838:	b0 fc       	sbrc	r11, 0
+    183a:	fd cf       	rjmp	.-6      	; 0x1836 <waitB>
+    183c:	21 e1       	ldi	r18, 0x11	; 17
+    183e:	b7 b6       	in	r11, 0x37	; 55
+    1840:	b6 fc       	sbrc	r11, 6
+    1842:	f4 cf       	rjmp	.-24     	; 0x182c <waitA>
+    1844:	08 95       	ret
+*/
+
+
+
+
+
+#elif defined (__AVR_ATmega128__)
+
+#if defined (__AVR_ATmega128__)
+  #if (BOOTLOADER_ADDRESS != 0x1E000)
+    #error BOOTLOADER_ADDRESS!=0x1E000, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use
+  #endif
+#else
+  #error undefined device selection - this should not happen! 
+#endif
+
+//assume  SPMCR:=SPMCSR==0x68, SPMEN==0x0, RWWSRE=0x4, RWWSB=0x6 and rampZ=0x3b
+#if HAVE_SPMINTEREFACE_MAGICVALUE
+const uint16_t bootloader__do_spm[28] BOOTLIBLINK = {
+  (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE >> 28) & 0xf))<<8) | (0x70 | ((HAVE_SPMINTEREFACE_MAGICVALUE >> 24) & 0xf))), // r23
+  bootloader__do_spm_magic_exitstrategy(0xf4c9), // brne +21+4
+  (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE >> 20) & 0xf))<<8) | (0x60 | ((HAVE_SPMINTEREFACE_MAGICVALUE >> 16) & 0xf))), // r22
+  bootloader__do_spm_magic_exitstrategy(0xf4b9), // brne +19+4
+  (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE >> 12) & 0xf))<<8) | (0x50 | ((HAVE_SPMINTEREFACE_MAGICVALUE >>  8) & 0xf))), // r21
+  bootloader__do_spm_magic_exitstrategy(0xf4a9), // brne +17+4
+  (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE >>  4) & 0xf))<<8) | (0x40 | ((HAVE_SPMINTEREFACE_MAGICVALUE >>  0) & 0xf))), // r20
+  bootloader__do_spm_magic_exitstrategy(0xf499), // brne +15+4
+#else
+const uint16_t bootloader__do_spm[20] BOOTLIBLINK = {
+#endif
+  0xbebb, 0x2dec, 0x2dfd, 0x90b0, 0x0068, 0xfcb0, 0xcffc, 0x9320, 0x0068,
+  0x95e8, 0x90b0, 0x0068, 0xfcb0, 0xcffc, 0xe121, 0x90b0, 0x0068, 0xfcb6,
+  0xcff0, 0x9508
+};
+/*
+0001e08c <bootloader__do_spm>:
+   1e08c:       bb be           out     0x3b, r11       ; 59
+   1e08e:       ec 2d           mov     r30, r12
+   1e090:       fd 2d           mov     r31, r13
+
+0001e092 <waitA>:
+   1e092:       b0 90 68 00     lds     r11, 0x0068
+   1e096:       b0 fc           sbrc    r11, 0
+   1e098:       fc cf           rjmp    .-8             ; 0x1e092 <waitA>
+   1e09a:       20 93 68 00     sts     0x0068, r18
+   1e09e:       e8 95           spm
+
+0001e0a0 <waitB>:
+   1e0a0:       b0 90 68 00     lds     r11, 0x0068
+   1e0a4:       b0 fc           sbrc    r11, 0
+   1e0a6:       fc cf           rjmp    .-8             ; 0x1e0a0 <waitB>
+   1e0a8:       21 e1           ldi     r18, 0x11       ; 17
+   1e0aa:       b0 90 68 00     lds     r11, 0x0068
+   1e0ae:       b6 fc           sbrc    r11, 6
+   1e0b0:       f0 cf           rjmp    .-32            ; 0x1e092 <waitA>
+   1e0b2:       08 95           ret
+*/
+
+
+
+
+
+#elif defined (__AVR_ATmega164A__) || defined (__AVR_ATmega164P__) || defined (__AVR_ATmega164PA__) || defined (__AVR_ATmega324A__) || defined (__AVR_ATmega324P__) || defined (__AVR_ATmega324PA__) || defined (__AVR_ATmega640__) || defined (__AVR_ATmega644__) || defined (__AVR_ATmega644A__) || defined (__AVR_ATmega644P__) || defined (__AVR_ATmega644PA__) || defined (__AVR_ATmega1280__) || defined (__AVR_ATmega1281__) || defined (__AVR_ATmega1284__) || defined (__AVR_ATmega1284P__) || defined (__AVR_ATmega2560__) || defined (__AVR_ATmega2561__)
+
+#if defined (__AVR_ATmega164A__) || defined (__AVR_ATmega164P__) || defined (__AVR_ATmega164PA__)
+  #if (BOOTLOADER_ADDRESS != 0x3800)
+    #error BOOTLOADER_ADDRESS!=0x3800, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use
+  #endif
+#elif defined (__AVR_ATmega324A__) || defined (__AVR_ATmega324P__) || defined (__AVR_ATmega324PA__)
+  #if (BOOTLOADER_ADDRESS != 0x7000)
+    #error BOOTLOADER_ADDRESS!=0x7000, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use
+  #endif
+#elif defined (__AVR_ATmega640__)
+  #if (BOOTLOADER_ADDRESS != 0xE000)
+    #error BOOTLOADER_ADDRESS!=0xE000, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use
+  #endif
+#elif defined (__AVR_ATmega644__) || defined (__AVR_ATmega644A__) || defined (__AVR_ATmega644P__) || defined (__AVR_ATmega644PA__)
+  #if (BOOTLOADER_ADDRESS != 0xE000)
+    #error BOOTLOADER_ADDRESS!=0xE000, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use
+  #endif
+#elif defined (__AVR_ATmega1280__)
+  #if (BOOTLOADER_ADDRESS != 0x1E000)
+    #error BOOTLOADER_ADDRESS!=0x1E000, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use
+  #endif
+#elif defined (__AVR_ATmega1281__)
+  #if (BOOTLOADER_ADDRESS != 0x1E000)
+    #error BOOTLOADER_ADDRESS!=0x1E000, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use
+  #endif
+#elif defined (__AVR_ATmega1284__) || defined (__AVR_ATmega1284P__)
+  #if (BOOTLOADER_ADDRESS != 0x1E000)
+    #error BOOTLOADER_ADDRESS!=0x1E000, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use
+  #endif
+#elif defined (__AVR_ATmega2560__)
+  #if (BOOTLOADER_ADDRESS != 0x3E000)
+    #error BOOTLOADER_ADDRESS!=0x3E000, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use
+  #endif
+#elif defined (__AVR_ATmega2561__)
+  #if (BOOTLOADER_ADDRESS != 0x3E000)
+    #error BOOTLOADER_ADDRESS!=0x3E000, on current MCU "funcaddr___bootloader__do_spm" might be currupted - please edit spminterface.h for nonstandard use
+  #endif
+#else
+  #error undefined device selection - this should not happen! 
+#endif
+
+//assume  SPMCR:=SPCSR==0x37, SPMEN==0x0, RWWSRE=0x4, RWWSB=0x6 and rampZ=0x3b
+#if HAVE_SPMINTEREFACE_MAGICVALUE
+const uint16_t bootloader__do_spm[24] BOOTLIBLINK = {
+  (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE >> 28) & 0xf))<<8) | (0x70 | ((HAVE_SPMINTEREFACE_MAGICVALUE >> 24) & 0xf))), // r23
+  bootloader__do_spm_magic_exitstrategy(0xf4a9), // brne +21
+  (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE >> 20) & 0xf))<<8) | (0x60 | ((HAVE_SPMINTEREFACE_MAGICVALUE >> 16) & 0xf))), // r22
+  bootloader__do_spm_magic_exitstrategy(0xf499), // brne +19
+  (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE >> 12) & 0xf))<<8) | (0x50 | ((HAVE_SPMINTEREFACE_MAGICVALUE >>  8) & 0xf))), // r21
+  bootloader__do_spm_magic_exitstrategy(0xf489), // brne +17
+  (((0x30 | ((HAVE_SPMINTEREFACE_MAGICVALUE >>  4) & 0xf))<<8) | (0x40 | ((HAVE_SPMINTEREFACE_MAGICVALUE >>  0) & 0xf))), // r20
+  bootloader__do_spm_magic_exitstrategy(0xf479), // brne +15
+#else
+const uint16_t bootloader__do_spm[16] BOOTLIBLINK = {
+#endif
+  0xbebb,
+  0x2dec, 0x2dfd, 0xb6b7, 0xfcb0, 0xcffd, 0xbf27, 0x95e8, 0xb6b7,
+  0xfcb0, 0xcffd, 0xe121, 0xb6b7, 0xfcb6, 0xcff4, 0x9508
+};
+/*
+00001826 <bootloader__do_spm>:
+    1826:	bb be       	out	0x3b,r11	; rampZ=r11; (rampZ is at IO 0x3b)
+    1828:	ec 2d       	mov	r30, r12
+    182a:	fd 2d       	mov	r31, r13
+
+0000182c <waitA>:
+    182c:	b7 b6       	in	r11, 0x37	; 55
+    182e:	b0 fc       	sbrc	r11, 0
+    1830:	fd cf       	rjmp	.-6      	; 0x182c <waitA>
+    1832:	27 bf       	out	0x37, r18	; 55
+    1834:	e8 95       	spm
+
+00001836 <waitB>:
+    1836:	b7 b6       	in	r11, 0x37	; 55
+    1838:	b0 fc       	sbrc	r11, 0
+    183a:	fd cf       	rjmp	.-6      	; 0x1836 <waitB>
+    183c:	21 e1       	ldi	r18, 0x11	; 17
+    183e:	b7 b6       	in	r11, 0x37	; 55
+    1840:	b6 fc       	sbrc	r11, 6
+    1842:	f4 cf       	rjmp	.-24     	; 0x182c <waitA>
+    1844:	08 95       	ret
+*/
+
+
+
+
+
+#else
+  #error "bootloader__do_spm has to be adapted, since there is no architecture code, yet"
+#endif  
+
+
+#endif
+
+#endif
+						 
diff --git a/updater/Makefile b/updater/Makefile
new file mode 100644
index 0000000..7764cad
--- /dev/null
+++ b/updater/Makefile
@@ -0,0 +1,80 @@
+# Name: Makefile
+# Project: USBaspLoader (updater)
+# Author: Stephan Bärwolf
+# Creation Date: 2012-09-01
+# Tabsize: 4
+# License: GNU GPL v2 (see License.txt)
+
+include ../Makefile.inc
+
+# elsewise gcc would complain unnecessary
+CFLAGS = -Wall -Wno-pointer-to-int-cast -Os -fno-move-loop-invariants -fno-tree-scev-cprop -fno-inline-small-functions -I. -mmcu=$(DEVICE) -DF_CPU=$(F_CPU) -DBOOTLOADER_ADDRESS=$(BOOTLOADER_ADDRESS) -DNEW_BOOTLOADER_ADDRESS=$(NEW_BOOTLOADER_ADDRESS) $(DEFINES)
+LDFLAGS = -Wl,--relax,--gc-sections
+
+ifneq ($(FLASHADDRESS), 0)
+ifneq ($(FLASHADDRESS), 00)
+ifneq ($(FLASHADDRESS), 000)
+ifneq ($(FLASHADDRESS), 0000)
+ifneq ($(FLASHADDRESS), 00000)
+ifneq ($(FLASHADDRESS), 0x0)
+ifneq ($(FLASHADDRESS), 0x00)
+ifneq ($(FLASHADDRESS), 0x000)
+ifneq ($(FLASHADDRESS), 0x0000)
+ifneq ($(FLASHADDRESS), 0x00000)
+FLASHPREAMBLE = 0x0000
+LDFLAGS += -Wl,--section-start=.text=$(FLASHADDRESS)
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+
+all:  updater.hex
+
+flash:	all
+	$(ECHO) "."
+	$(AVRDUDE) -D -U flash:w:updater.hex:i
+	$(ECHO) "."
+	$(ECHO) "."
+
+
+../firmware/main.bin:
+	$(MAKE) -C ../firmware main.hex
+
+
+usbasploader.raw: ../firmware/main.bin
+	$(OBC) -j .text -j .data -O binary ../firmware/main.bin usbasploader.raw
+
+usbasploader.o: usbasploader.raw
+	$(OBC) -B $(MCUARCH) -I binary -O elf32-avr --rename-section .data=.text --redefine-sym _binary_usbasploader_raw_start=usbasploader  usbasploader.raw usbasploader.o
+
+
+updater.o: updater.c usbasploader.h usbasploader.raw usbasploader.o
+	$(CC) updater.c -c -o updater.o -DSIZEOF_new_firmware=$(shell stat -c %s usbasploader.raw) $(CFLAGS)
+# 	$(CC) updater.c -c -o updater.o $(CFLAGS)
+
+updater.elf: updater.o usbasploader.o
+	$(CC) updater.o usbasploader.o -o updater.elf $(CFLAGS) $(LDFLAGS)
+
+updater.hex: updater.elf
+	$(OBC) -j .text -j .data -O ihex updater.elf updater.hex
+	$(ECHO) "."
+	$(ECHO) "."
+	$(SIZ) updater.elf
+	$(ECHO) "."
+
+deepclean: clean
+	$(RM) *~
+
+clean:
+	$(RM) usbasploader.o
+	$(RM) updater.o
+	$(RM) usbasploader.raw
+	$(RM) updater.hex
+	$(RM) updater.elf
+	$(RM) usbasploader.raw
\ No newline at end of file
diff --git a/updater/updater.c b/updater/updater.c
new file mode 100644
index 0000000..75f0996
--- /dev/null
+++ b/updater/updater.c
@@ -0,0 +1,338 @@
+#ifndef F_CPU
+  #define F_CPU 1000000UL /* 1 Mhz-Takt; hier richtigen Wert eintragen */
+#endif
+
+#include "../firmware/spminterface.h"
+#include "usbasploader.h"
+
+// activate updaters full set of features
+#ifndef CONFIG_UPDATER_REDUCEWRITES
+  #define CONFIG_UPDATER_REDUCEWRITES
+#endif
+
+#ifndef CONFIG_UPDATER_CLEANMEMCLEAR
+  #define CONFIG_UPDATER_CLEANMEMCLEAR
+#endif
+
+
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <avr/wdt.h>
+
+#include <avr/pgmspace.h>
+
+#include <stdint.h>
+
+#include <util/delay.h>
+#include <string.h>
+
+#define	updater_pagefillcode	((1<<SPMEN))
+#define	updater_pageerasecode	((1<<PGERS) | (1<<SPMEN))
+#define	updater_pagewritecode	((1<<PGWRT) | (1<<SPMEN))
+
+
+#include "../firmware/bootloaderconfig.h"
+#if !HAVE_SPMINTEREFACE
+  #error "bootloader does not support updating itself! (HAVE_SPMINTEREFACE)"
+#endif
+
+// helpful definitions and makros ////
+
+#ifndef NEW_BOOTLOADER_ADDRESS
+  #error "where should the new bootloader be positioned?"
+#endif
+
+
+
+#if (NEW_BOOTLOADER_ADDRESS != (funcaddr___bootloader__do_spm-(funcaddr___bootloader__do_spm % SPM_PAGESIZE)))
+  #warning the new bootloader seems to be located elsewhere, than the current one!
+#endif
+
+#ifndef NEW_SPM_ADDRESS
+  #warning I do not know where new "bootloader__do_spm" is located - assuming "NEW_BOOTLOADER_ADDRESS+(funcaddr___bootloader__do_spm % SPM_PAGESIZE)"
+  #define NEW_SPM_ADDRESS (NEW_BOOTLOADER_ADDRESS+(funcaddr___bootloader__do_spm % SPM_PAGESIZE))
+#endif
+
+// TEMP_SPM supports up to 4 pages for "bootloader__do_spm"...
+#define TEMP_SPM_NUMPAGE 4
+#define TEMP_SPM_BLKSIZE (TEMP_SPM_NUMPAGE*SPM_PAGESIZE)
+#ifndef TEMP_SPM_PAGEADR
+  #warning "TEMP_SPM_PAGEADR" is not defined explicitly - will choose END OF FLASH !
+  #define TEMP_SPM_PAGEADR ((FLASHEND+1) - TEMP_SPM_BLKSIZE)
+#endif
+#define TEMP_SPM_ADDRESS ((TEMP_SPM_PAGEADR) + (funcaddr___bootloader__do_spm % SPM_PAGESIZE))
+
+
+#if (NEW_SPM_ADDRESS == funcaddr___bootloader__do_spm)
+  #define new_do_spm	do_spm
+#else
+void new_do_spm(const uint32_t flash_byteaddress, const uint8_t spmcrval, const uint16_t dataword) {
+    __do_spm_Ex(flash_byteaddress, spmcrval, dataword, NEW_SPM_ADDRESS >> 1);
+}
+#endif
+
+void temp_do_spm(const uint32_t flash_byteaddress, const uint8_t spmcrval, const uint16_t dataword) {
+    __do_spm_Ex(flash_byteaddress, spmcrval, dataword, TEMP_SPM_ADDRESS >> 1);
+}
+
+
+
+// some important consistency checks ////
+
+//check if "NEW_BOOTLOADER_ADDRESS" is page-aligned
+#if (NEW_BOOTLOADER_ADDRESS % SPM_PAGESIZE != 0) 
+  #error "NEW_BOOTLOADER_ADDRESS" is not aligned to pages!
+#endif
+
+//check, if NEW_SPM_ADDRESS is an even address
+#if ((NEW_SPM_ADDRESS % 2) != 0)
+  #error NEW_SPM_ADDRESS must be an even address, since it contains executable code!
+#endif
+
+
+
+//check, if TEMP_SPM somehow overlaps with old SPM
+#if (((TEMP_SPM_ADDRESS + TEMP_SPM_BLKSIZE + SPM_PAGESIZE) >= funcaddr___bootloader__do_spm) && (TEMP_SPM_ADDRESS <= (funcaddr___bootloader__do_spm + TEMP_SPM_BLKSIZE + SPM_PAGESIZE)))
+  #error TEMP_SPM_ADDRESS overlaps "funcaddr___bootloader__do_spm"!
+#endif
+
+//check, if TEMP_SPM somehow overlaps with new SPM
+#if (((TEMP_SPM_ADDRESS + TEMP_SPM_BLKSIZE + SPM_PAGESIZE) >= NEW_SPM_ADDRESS) && (TEMP_SPM_ADDRESS <= (NEW_SPM_ADDRESS + TEMP_SPM_BLKSIZE + SPM_PAGESIZE)))
+  #error TEMP_SPM_ADDRESS overlaps "NEW_SPM_ADDRESS"!
+#endif
+
+//check, if TEMP_SPM_ADDRESS is an even address
+#if ((TEMP_SPM_ADDRESS % 2) != 0)
+  #error TEMP_SPM_ADDRESS must be an even address, since it contains executable code!
+#endif
+
+//check, if TEMP_SPM_ADDRESS fits into flash
+#if ((TEMP_SPM_PAGEADR + TEMP_SPM_BLKSIZE) > (FLASHEND+1))
+  #error TEMP_SPM_ADDRESS exceeds flashend!
+#endif
+
+//check if size too low
+#if (SIZEOF_new_firmware <= (TEMP_SPM_BLKSIZE + (NEW_SPM_ADDRESS - NEW_BOOTLOADER_ADDRESS)))
+  #error empty firmware!
+#endif
+
+//check if size too high
+#if (SIZEOF_new_firmware > ((FLASHEND+1)-NEW_BOOTLOADER_ADDRESS))
+  #error firmware too big! firmware does not fit into flash memory!
+#endif
+
+// main code ////
+
+/*
+ * in this case a near address
+ */
+typedef uint32_t mypgm_addr_t;
+typedef void (*mypgm_spminterface)(const uint32_t flash_byteaddress, const uint8_t spmcrval, const uint16_t dataword);
+
+#if FLASHEND > 65535
+#	define	mymemcpy_PF mymemcpy_PF_far
+void *mymemcpy_PF_far (void *dest, mypgm_addr_t src, size_t n) {
+  uint8_t	*pagedata	= (void*)dest;
+  mypgm_addr_t	 pageaddr	= src;
+  size_t	i;
+
+  for (i=0;i<n;i+=1) {
+    pagedata[i]=pgm_read_byte_far(pageaddr);
+    pageaddr+=1;
+  }
+
+  return dest;
+}
+#else
+#	define	mymemcpy_PF memcpy_PF 
+#endif
+
+#if 0
+size_t mypgm_readpage(const mypgm_addr_t byteaddress,const void* buffer, const size_t bufferbytesize) {
+  size_t	result		= (bufferbytesize < SPM_PAGESIZE)?bufferbytesize:SPM_PAGESIZE;
+  size_t	pagesize	= result >> 1;
+  uint16_t	*pagedata	= (void*)buffer;
+  mypgm_addr_t	pageaddr	= byteaddress - (byteaddress % SPM_PAGESIZE);
+  size_t	i;
+  
+  for (i=0;i<pagesize;i+=1) {
+    pagedata[i]=pgm_read_word_far(pageaddr);
+    pageaddr+=2;
+  }
+  
+  return result;
+}
+#else
+// replace it somehow with "memcpy_PF" in order to save some ops...
+size_t mypgm_readpage(const mypgm_addr_t byteaddress,const void* buffer, const size_t bufferbytesize) {
+  size_t	result		= (bufferbytesize < SPM_PAGESIZE)?bufferbytesize:SPM_PAGESIZE;
+  mypgm_addr_t	pageaddr	= byteaddress - (byteaddress % SPM_PAGESIZE);
+  
+  mymemcpy_PF((void*)buffer, (uint_farptr_t)pageaddr, result);
+  
+  return result;
+}
+#endif
+
+#ifdef CONFIG_UPDATER_REDUCEWRITES
+size_t mypgm_WRITEpage(const mypgm_addr_t byteaddress,const void* buffer, const size_t bufferbytesize, mypgm_spminterface spmfunc) {
+  size_t	result		= (bufferbytesize < SPM_PAGESIZE)?bufferbytesize:SPM_PAGESIZE;
+  size_t	pagesize	= result >> 1;
+  uint16_t	*pagedata	= (void*)buffer;
+  mypgm_addr_t	pageaddr_bakup	= byteaddress - (byteaddress % SPM_PAGESIZE);
+  mypgm_addr_t	pageaddr	= pageaddr_bakup;
+  
+  uint8_t	changed=0, needs_erase=0;
+  uint16_t	deeword;
+  size_t	i;
+  
+  // just check, if page needs a rewrite or an erase...
+  for (i=0;i<pagesize;i+=1) {
+#if (FLASHEND > 65535)
+    deeword=pgm_read_word_far(pageaddr);
+#else
+    deeword=pgm_read_word(pageaddr);
+#endif
+
+    if (deeword != pagedata[i]) changed=1;
+
+    /*
+     *  deeword = x
+     *  buffer  = y
+     * 
+     *  1 ? 1 ==> 1
+     *  1 ? 0 ==> 1
+     *  0 ? 1 ==> 0
+     *  0 ? 0 ==> 1
+     * 
+     * ==> /(/x * y) ==> x + /y
+     */
+    deeword |= ~pagedata[i];
+    if ((~deeword) != 0) needs_erase=1;
+      
+    pageaddr+=2;
+  }
+
+  if (changed) {
+    
+    if (needs_erase) {
+      //do a page-erase, ATTANTION: flash only can be erased a limited number of times !
+      spmfunc(pageaddr_bakup, updater_pageerasecode, 0);
+    }
+    
+    // from now on, the page is assumed empty !! (hopefully our code is located somewhere else!)
+    // now, fill the tempoary buffer
+    // ATTANTION: see comment on "do_spm" !
+    pageaddr	= pageaddr_bakup;
+    for (i=0;i<pagesize;i+=1) {
+      spmfunc(pageaddr, updater_pagefillcode, pagedata[i]);
+      pageaddr+=2;
+    }
+    
+    // so, now finally write the page to the FLASH
+    spmfunc(pageaddr_bakup, updater_pagewritecode, 0);
+  } else {
+    // no change - no write...
+    result = 0;
+  }
+  
+  
+  return result;
+}
+#else
+size_t mypgm_WRITEpage(const mypgm_addr_t byteaddress,const void* buffer, const size_t bufferbytesize, mypgm_spminterface spmfunc) {
+  size_t	result		= (bufferbytesize < SPM_PAGESIZE)?bufferbytesize:SPM_PAGESIZE;
+  size_t	pagesize	= result >> 1;
+  uint16_t	*pagedata	= (void*)buffer;
+  mypgm_addr_t	pageaddr_bakup	= byteaddress - (byteaddress % SPM_PAGESIZE);
+  mypgm_addr_t	pageaddr	= pageaddr_bakup;
+
+  size_t	i;
+    
+  //do a page-erase, ATTANTION: flash only can be erased a limited number of times !
+  spmfunc(pageaddr_bakup, updater_pageerasecode, 0);
+    
+  // from now on, the page is assumed empty !! (hopefully our code is located somewhere else!)
+  // now, fill the tempoary buffer
+  // ATTANTION: see comment on "do_spm" !
+  pageaddr	= pageaddr_bakup;
+  for (i=0;i<pagesize;i+=1) {
+    spmfunc(pageaddr, updater_pagefillcode, pagedata[i]);
+    pageaddr+=2;
+  }
+    
+  // so, now finally write the page to the FLASH
+  spmfunc(pageaddr_bakup, updater_pagewritecode, 0);
+  
+  return result;
+}
+#endif
+
+// #pragma GCC diagnostic ignored "-Wno-pointer-to-int-cast"
+int main(void)
+{
+    size_t  i;
+    uint8_t buffer[SPM_PAGESIZE];
+    
+    wdt_disable();
+    cli();
+
+    // check if firmware would change...
+    buffer[0]=0;
+    for (i=0;i<SIZEOF_new_firmware;i+=2) {
+      uint16_t a, b;
+#if (FLASHEND > 65535)
+      a=pgm_read_word_far((void*)&new_firmware[i]);
+      b=pgm_read_word_far(NEW_BOOTLOADER_ADDRESS+i);
+#else
+      a=pgm_read_word((void*)&new_firmware[i]);
+      b=pgm_read_word(NEW_BOOTLOADER_ADDRESS+i);
+#endif
+      if (a!=b) {
+	buffer[0]=1;
+	break;
+      }
+    }
+
+
+
+    // need to change the firmware...
+    if (buffer[0]) {
+
+      // A
+      // copy the current "bootloader__do_spm" to tempoary position via std. "bootloader__do_spm"
+      for (i=0;i<TEMP_SPM_BLKSIZE;i+=SPM_PAGESIZE) {
+	mypgm_WRITEpage(TEMP_SPM_PAGEADR+i, buffer, mypgm_readpage(funcaddr___bootloader__do_spm+i, buffer, sizeof(buffer)), do_spm);
+      }
+
+      // B
+      // start updating the firmware to "NEW_BOOTLOADER_ADDRESS" until at least "TEMP_SPM_BLKSIZE"-bytes after "NEW_SPM_ADDRESS" were written
+      // therefore use the tempoary "bootloader__do_spm" (since we most probably will overwrite the default do_spm)
+      for (i=0;;i+=SPM_PAGESIZE) {
+#ifdef CONFIG_UPDATER_CLEANMEMCLEAR
+	memset((void*)buffer, 0xff, sizeof(buffer));
+#endif
+	mymemcpy_PF((void*)buffer, (uint_farptr_t)((void*)&new_firmware[i]), ((SIZEOF_new_firmware-i)>sizeof(buffer))?sizeof(buffer):(SIZEOF_new_firmware-i));
+	
+	mypgm_WRITEpage(NEW_BOOTLOADER_ADDRESS+i, buffer, sizeof(buffer), temp_do_spm);
+	
+	if ((NEW_BOOTLOADER_ADDRESS+i) > (NEW_SPM_ADDRESS+TEMP_SPM_BLKSIZE)) break;
+      }
+
+      // C
+      // continue writeing the new_firmware after "NEW_SPM_ADDRESS+TEMP_SPM_BLKSIZE" this time use the "new_do_spm"
+      for (;i<SIZEOF_new_firmware;i+=SPM_PAGESIZE) {
+#ifdef CONFIG_UPDATER_CLEANMEMCLEAR
+	memset((void*)buffer, 0xff, sizeof(buffer));
+#endif
+	mymemcpy_PF((void*)buffer, (uint_farptr_t)((void*)&new_firmware[i]), ((SIZEOF_new_firmware-i)>sizeof(buffer))?sizeof(buffer):(SIZEOF_new_firmware-i));
+
+	mypgm_WRITEpage(NEW_BOOTLOADER_ADDRESS+i, buffer, sizeof(buffer), new_do_spm);
+	
+      }
+
+
+
+    }
+
+}
diff --git a/updater/usbasploader.h b/updater/usbasploader.h
new file mode 100644
index 0000000..5400b36
--- /dev/null
+++ b/updater/usbasploader.h
@@ -0,0 +1,23 @@
+
+#ifndef USBASPLOADER_H_5f27a7e9840141b1aa57eef07c1d939f
+#define USBASPLOADER_H_5f27a7e9840141b1aa57eef07c1d939f 1
+
+#include <stdint.h>
+#include <avr/io.h>
+#include <avr/pgmspace.h>
+#include "../firmware/spminterface.h"
+
+#ifndef SIZEOF_new_firmware
+  #ifdef BOOTLOADER_ADDRESS
+    #define SIZEOF_new_firmware (((FLASHEND)+1)-(BOOTLOADER_ADDRESS))
+  #else
+    #error unable to determine binary size of firmware
+  #endif
+#endif
+
+
+extern const const uint16_t usbasploader[SIZEOF_new_firmware>>1] PROGMEM;
+const uint8_t *new_firmware	=	(void*)&usbasploader;
+
+#endif
+
