
Property changes on: apps\resetvoltages
___________________________________________________________________
Added: svn:ignore
   + build


Index: apps/resetvoltages/ls.x
===================================================================
--- apps/resetvoltages/ls.x	(revision 0)
+++ apps/resetvoltages/ls.x	(revision 0)
@@ -0,0 +1,42 @@
+ENTRY(__emcore_entrypoint)
+OUTPUT_FORMAT(elf32-littlearm)
+OUTPUT_ARCH(arm)
+
+MEMORY
+{
+    VIRTUAL : ORIGIN = 0x00000000, LENGTH = 0x10000000
+}
+
+SECTIONS
+{
+    .text :
+    {
+        __emcore_app_base = .;
+	KEEP(.emcoreentrypoint*)
+	*(.emcoreentrypoint*)
+        *(.text*)
+        *(.glue_7)
+        *(.glue_7t)
+        . = ALIGN(0x10);
+    } > VIRTUAL
+
+    .data :
+    {
+        *(.rodata*)
+        . = ALIGN(0x4);
+        *(.data*)
+        . = ALIGN(0x10);
+    } > VIRTUAL
+
+    .bss (NOLOAD) :
+    {
+        *(.bss*)
+        *(COMMON)
+    } > VIRTUAL
+
+    /DISCARD/ :
+    {
+        *(.eh_frame)
+    }
+
+}
Index: apps/resetvoltages/main.c
===================================================================
--- apps/resetvoltages/main.c	(revision 0)
+++ apps/resetvoltages/main.c	(revision 0)
@@ -0,0 +1,46 @@
+//
+//
+//    Copyright 2011 TheSeven
+//
+//
+//    This file is part of emCORE.
+//
+//    emCORE is free software: you can 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.
+//
+//    emCORE is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+//
+//    You should have received a copy of the GNU General Public License along
+//    with emCORE.  If not, see <http://www.gnu.org/licenses/>.
+//
+//
+
+
+#include "emcoreapp.h"
+#include "libboot.h"
+
+
+static void main(int argc, const char** argv)
+{
+    i2c_sendbyte(0, 0xe6, 0x1e, 0x17);
+    i2c_sendbyte(0, 0xe6, 0x22, 0x2f);
+    i2c_sendbyte(0, 0xe6, 0x31, 0x15);
+    void* firmware = NULL;
+    int size = 0;
+    struct emcorelib_header* lib = get_library(LIBBOOT_IDENTIFIER, LIBBOOT_API_VERSION, LIBSOURCE_BOOTFLASH, "libboot ");
+    if (!lib) panicf(PANIC_KILLTHREAD, "Could not load libboot");
+    struct libboot_api* boot = (struct libboot_api*)lib->api;
+    boot->load_from_flash(&firmware, &size, false, "bootmenu", 0);
+    release_library(lib);
+    library_unload(lib);
+    if (!firmware || execimage(firmware, false) == NULL)
+        panic(PANIC_KILLTHREAD, "Failed to launch boot menu");
+}
+
+
+EMCORE_APP_HEADER("iPod Classic voltage configuration resetter", main, 127)
Index: apps/resetvoltages/Makefile
===================================================================
--- apps/resetvoltages/Makefile	(revision 0)
+++ apps/resetvoltages/Makefile	(revision 0)
@@ -0,0 +1,121 @@
+NAME := resetvoltages
+STACKSIZE := 4096
+COMPRESS := true
+
+EMCOREDIR ?= ../../emcore/trunk/
+LIBBOOTDIR ?= ../../libs/boot/
+
+ifeq ($(shell uname),WindowsNT)
+CCACHE :=
+else
+CCACHE := $(shell which ccache)
+endif
+
+CROSS   ?= arm-elf-eabi-
+CC      := $(CCACHE) $(CROSS)gcc
+AS      := $(CROSS)as
+LD      := $(CROSS)ld
+OBJCOPY := $(CROSS)objcopy
+ELF2ECA := $(CROSS)elf2emcoreapp
+
+LIBINCLUDES := -I$(LIBBOOTDIR)/export
+
+CFLAGS  += -Os -fno-pie -fno-stack-protector -fomit-frame-pointer -I. -I$(EMCOREDIR)/export $(LIBINCLUDES) -ffunction-sections -fdata-sections -mcpu=arm940t -DARM_ARCH=4
+LDFLAGS += "$(shell $(CC) -print-libgcc-file-name)" --emit-relocs --gc-sections
+
+preprocess = $(shell $(CC) $(PPCFLAGS) $(2) -E -P -x c $(1) | grep -v "^\#")
+preprocesspaths = $(shell $(CC) $(PPCFLAGS) $(2) -E -P -x c $(1) | grep -v "^\#" | sed -e "s:^..*:$(dir $(1))&:" | sed -e "s:^\\./::")
+
+REVISION := $(shell svnversion .)
+REVISIONINT := $(shell echo $(REVISION) | sed -e "s/[^0-9].*$$//")
+
+HELPERS := build/__emcore_armhelpers.o
+
+SRC := $(call preprocesspaths,SOURCES,-I. -I..)
+OBJ := $(SRC:%.c=build/%.o)
+OBJ := $(OBJ:%.S=build/%.o) $(HELPERS)
+
+all: $(NAME)
+
+-include $(OBJ:%=%.dep)
+
+$(NAME): build/$(NAME).emcoreapp
+
+build/$(NAME).emcoreapp: build/$(NAME).elf
+	@echo [EMCAPP] $<
+ifeq ($(COMPRESS),true)
+	@$(ELF2ECA) -z -s $(STACKSIZE) -o $@ $^
+else
+	@$(ELF2ECA) -s $(STACKSIZE) -o $@ $^
+endif
+
+build/$(NAME).elf: ls.x $(OBJ)
+	@echo [LD]     $@
+	@$(LD) $(LDFLAGS) -o $@ -T ls.x $(OBJ)
+
+build/%.o: %.c build/version.h
+	@echo [CC]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
+else
+	@-mkdir -p $(dir $@)
+endif
+	@$(CC) -c $(CFLAGS) -o $@ $<
+	@$(CC) -MM $(CFLAGS) $< > $@.dep.tmp
+	@sed -e "s|.*:|$@:|" < $@.dep.tmp > $@.dep
+ifeq ($(shell uname),WindowsNT)
+	@sed -e "s/.*://" -e "s/\\$$//" < $@.dep.tmp | fmt -1 | sed -e "s/^ *//" -e "s/$$/:/" >> $@.dep
+else
+	@sed -e 's/.*://' -e 's/\\$$//' < $@.dep.tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $@.dep
+endif
+	@rm -f $@.dep.tmp
+
+build/%.o: %.S build/version.h
+	@echo [CC]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
+else
+	@-mkdir -p $(dir $@)
+endif
+	@$(CC) -c $(CFLAGS) -o $@ $<
+	@$(CC) -MM $(CFLAGS) $< > $@.dep.tmp
+	@sed -e "s|.*:|$@:|" < $@.dep.tmp > $@.dep
+ifeq ($(shell uname),WindowsNT)
+	@sed -e "s/.*://" -e "s/\\$$//" < $@.dep.tmp | fmt -1 | sed -e "s/^ *//" -e "s/$$/:/" >> $@.dep
+else
+	@sed -e 's/.*://' -e 's/\\$$//' < $@.dep.tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $@.dep
+endif
+	@rm -f $@.dep.tmp
+
+build/__emcore_%.o: $(EMCOREDIR)/export/%.c
+	@echo [CC]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
+else
+	@-mkdir -p $(dir $@)
+endif
+	@$(CC) -c $(CFLAGS) -o $@ $<
+
+build/__emcore_%.o: $(EMCOREDIR)/export/%.S
+	@echo [CC]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
+else
+	@-mkdir -p $(dir $@)
+endif
+	@$(CC) -c $(CFLAGS) -o $@ $<
+
+build/version.h: version.h .svn/entries
+	@echo [PP]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist build md build
+	@sed -e "s/\$$REVISION\$$/$(REVISION)/" -e "s/\$$REVISIONINT\$$/$(REVISIONINT)/" < $< > $@
+else
+	@-mkdir -p build
+	@sed -e 's/\$$REVISION\$$/$(REVISION)/' -e 's/\$$REVISIONINT\$$/$(REVISIONINT)/' < $< > $@
+endif
+
+clean:
+	@rm -rf build
+
+.PHONY: all clean $(NAME)
Index: apps/resetvoltages/SOURCES
===================================================================
--- apps/resetvoltages/SOURCES	(revision 0)
+++ apps/resetvoltages/SOURCES	(revision 0)
@@ -0,0 +1 @@
+main.c
Index: apps/resetvoltages/version.h
===================================================================
--- apps/resetvoltages/version.h	(revision 0)
+++ apps/resetvoltages/version.h	(revision 0)
@@ -0,0 +1,36 @@
+//
+//
+//    Copyright 2010 TheSeven
+//
+//
+//    This file is part of emCORE.
+//
+//    emCORE is free software: you can 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.
+//
+//    emCORE is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+//
+//    You should have received a copy of the GNU General Public License along
+//    with emCORE.  If not, see <http://www.gnu.org/licenses/>.
+//
+//
+
+
+#ifndef __VERSION_H__
+#define __VERSION_H__
+
+
+#define VERSION "0.1.0"
+#define VERSION_MAJOR 0
+#define VERSION_MINOR 1
+#define VERSION_PATCH 0
+#define VERSION_SVN "$REVISION$"
+#define VERSION_SVN_INT $REVISIONINT$
+
+
+#endif
\ No newline at end of file

Property changes on: emcore\trunk\loader\ipodnano4g
___________________________________________________________________
Added: svn:ignore
   + build


Index: emcore/trunk/loader/ipodnano4g/ls.x
===================================================================
--- emcore/trunk/loader/ipodnano4g/ls.x	(revision 0)
+++ emcore/trunk/loader/ipodnano4g/ls.x	(revision 0)
@@ -0,0 +1,21 @@
+OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm",
+	      "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+
+SECTIONS
+{
+  . = 0x22000050;
+
+  .text : { *(.text) } 
+
+  __data_start__ = . ;
+  .data : { *(.data) *(.rodata) }
+
+  __bss_start__ = .;
+  .bss : {
+    *(.bss) *(COMMON);
+    __bss_end__ = . ;
+  }
+
+}
\ No newline at end of file
Index: emcore/trunk/loader/ipodnano4g/main.S
===================================================================
--- emcore/trunk/loader/ipodnano4g/main.S	(revision 0)
+++ emcore/trunk/loader/ipodnano4g/main.S	(revision 0)
@@ -0,0 +1,1228 @@
+@
+@
+@    emCORE Loader for iPod Nano 4G
+@
+@    Copyright 2011 TheSeven, Farthen
+@
+@
+@    This file is part of emCORE.
+@
+@    emCORE is free software: you can 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.
+@
+@    emCORE is distributed in the hope that it will be useful,
+@    but WITHOUT ANY WARRANTY; without even the implied warranty of
+@    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+@    See the GNU General Public License for more details.
+@
+@    You should have received a copy of the GNU General Public License along
+@    with emCORE.  If not, see <http://www.gnu.org/licenses/>.
+@
+@
+
+
+#include "build/version.h"
+
+
+.global _start
+_start:
+	msr	cpsr_c, #0xd3
+	mrc	p15, 0, r0,c1,c0
+	bic	r0, r0, #1
+	mcr	p15, 0, r0,c1,c0 @ disable mmu
+
+	mov	lr, #0
+	adr	sp, values1
+	mcr	p15, 0, lr,c7,c14,0 @ clean & invalidate data cache
+	mcr	p15, 0, lr,c7,c10,4 @ drain write buffer
+	mcr	p15, 0, lr,c7,c5    @ invalidate instruction cache
+	mcr	p15, 0, lr,c7,c5,4  @ flush prefetch buffer
+	mcr	p15, 0, lr,c8,c7    @ invalidate all unlocked entries in the TLB
+	mcr	p15, 0, lr,c13,c0,0 @ disable context id register
+    
+
+.macro block0_constpool    @ Block 0 (MMU, DMA) register map:
+                           @ R0: Unused
+                           @ R1: Unused
+                           @ R2: Unused
+                           @ R3: Scratchpad
+	.word	0x00000FFF @ R4: DMA maximum transfer size
+	.word	0x00012C00 @ R5: LCD framebuffer pixel count
+	.word	0x22006800 @ R6: LCD framebuffer address
+	.word	0x38300040 @ R7: LCD data port address
+	.word	0x2202D000 @ R8: LCD DMA linked list address
+	.word	0x74240000 @ R9: LCD DMA channel settings
+	.word	0x0005187D @ R10: CP15r1
+	.word	0x2202C000 @ R11: First level page table
+	.word	0x00000C1E @ R12: Default segment flags
+                           @ R13: Constant pool pointer
+.endm                      @ R14: 0
+
+	ldmia	sp!, {r4-r12}
+	mcr	p15, 0, r11,c2,c0 @ set first level translation table
+	mov	r3, #-1
+	mcr	p15, 0, r3,c3,c0 @ disable domain access control                  @ R3: Unused
+	orr	r0, r12, #0x22000000
+	str	r0, [r11], #4
+	add	r12, r12, #0x00100000
+mmuloop:
+	str	r12, [r11], #4
+	add	r12, r12, #0x00100000
+	cmp	r12, #0x38000000
+	biccs	r12, r12, #0xc
+	tst	r12, #0x40000000
+	beq	mmuloop
+                                                                                  @ R11: LCD DMA descriptor head
+                                                                                  @ R12: Unused
+	mcr	p15, 0, r10,c1,c0                                                 @ R10: Unused
+
+dmaloop:
+	add	r8, r8, #0x10
+	bic	r9, r9, r4
+	cmp	r4, r5
+	movcs	r4, r5
+	movcs	r8, #0
+	orr	r9, r9, r4
+	stmia	r11!, {r6-r9}
+	add	r6, r6, r4,lsl#1
+	subs	r5, r5, r4
+	bne	dmaloop
+
+.macro block1_constpool    @ Block 1 (SYSCON) register map:
+	.word	0x000327E5 @ R0: PWRCON(0)
+	.word	0xFE2BED6D @ R1: PWRCON(1)
+	.word	0x00DCF779 @ R2: PWRCON(4)
+	.word	0x003E3E00 @ R3
+	.word	0x06008501 @ R4
+	.word	0x00009DBC @ R5
+	.word	0x00404040 @ R6
+	.word	0x40001000 @ R7
+	.word	0x80008000 @ R8
+	.word	0x38501000 @ R9
+	.word	0xE02BED4D @ R10: PWRCON(1) during timer setup
+	.word	0x001CF700 @ R11: PWRCON(4) during timer setup
+	.word	0x3C500000 @ R12: SYSCON base address
+                           @ R13: Constant pool pointer
+.endm                      @ R14: 0
+
+	ldmia	sp!, {r0-r12}
+	str	r0, [r12,#0x48]  @ PWRCON0 ...                                    @ R0: Scratchpad
+	str	r1, [r12,#0x4c]
+	mov	r0, #0x73
+	str	r0, [r12,#0x58]
+	mov	r0, #0xff
+	str	r0, [r12,#0x68]
+	str	r2, [r12,#0x6c]  @ ... PWRCON4
+	str	lr, [r12]
+sysconwait1:
+	ldr	r0, [r12]
+	tst	r0, #0xf
+	bne	sysconwait1      @ while ([SYSCON] & 0xf)
+    
+	str	lr, [r12,#0x04]
+sysconwait2:
+	ldr	r0, [r12,#0x04]
+	tst	r0, r3
+	bne	sysconwait2      @ while ([SYSCON+4] & 0x003E3E00)
+    
+	mov	r0, #0x7
+	str	r0, [r12,#0x44]
+	str	lr, [r12,#0x44]
+	str	lr, [r12,#0x3c]
+	str	r4, [r12,#0x20]                                                   @ R4: Scratchpad
+	str	r5, [r12,#0x30]
+	mov	r5, #1                                                            @ R5: 1
+	str	r5, [r12,#0x44]
+	orr	r4, r0, #0x10000
+	str	r4, [r12,#0x44]
+sysconwait3:
+	ldr	r4, [r12,#0x40]
+	tst	r4, #0x1
+	beq	sysconwait3      @ while (!([SYSCON+0x40] & 1))
+    
+	str	r6, [r12,#0x04]                                                   @ R6: Unused
+	add	r3, r3, #0x3e                                                     @ R3: 0x003E3E3E
+sysconwait4:
+	ldr	r4, [r12,#0x04]
+	tst	r4, r3                                                            @ R3: Unused
+	bne	sysconwait4
+    
+	str	r7, [r12]                                                         @ R7: Unused
+sysconwait5:
+	ldr	r2, [r12]
+	tst	r4, #0xf
+	bne	sysconwait5
+    
+	str	r8, [r12,#0x08]
+	orr	r4, r8, r8,lsr#1                                                  @ R8: Unused
+	str	r4, [r12,#0x0c]
+	mov	r4, #0xc000
+	str	r4, [r12,#0x10]
+	mov	r4, #0x8000
+	str	r4, [r12,#0x14]
+	str	r4, [r12,#0x70]
+	mov	r4, #2
+	str	r4, [r9]                                                          @ R9: Unused
+	mov	r0, #0x10                                                         @ R5: 0x10
+
+                           @ Block 2 (TIMER) register map:
+                           @ R0: 1
+                           @ R1: PWRCON(1)
+                           @ R2: PWRCON(4)
+                           @ R3: Scratchpad
+                           @ R4: Scratchpad
+                           @ R5: 0x10
+                           @ R6: Unused
+                           @ R7: Unused
+                           @ R8: Unused
+                           @ R9: Unused
+                           @ R10: PWRCON(1) during timer setup
+                           @ R11: PWRCON(4) during timer setup
+                           @ R12: SYSCON base address
+                           @ R13: Constant pool pointer
+                           @ R14: 0
+
+	str	r10, [r12,#0x4c]     @ PWRCON(1) for timer setup                  @ R10: Unused
+	mov	r4, #0x13
+	str	r4, [r12,#0x58]             @ PWRCON(2) for timer setup
+	str	r11, [r12,#0x6c]     @ PWRCON(4) for timer setup                  @ R11: Unused
+	orr     r11, r12, #0x00200000                                             @ R11: TIMER base address
+	str	r0, [r11,#0x4]       @ TACMD = 0x10
+	str	r0, [r11,#0x24]      @ TBCMD = 0x10
+	str	r0, [r11,#0x44]      @ TCCMD = 0x10
+	str	r0, [r11,#0x64]      @ TDCMD = 0x10
+	mov	r3, #0x40
+	str	r3, [r11,#0xa0]      @ TECON = 0x40
+	mov	r3, #0xb
+	str	r3, [r11,#0xb0]      @ TEPRE = 0xb
+	mov	r4, #-1                                                           @ R4: -1
+	str	r4, [r11,#0xa8]      @ TEDATA0 = 0xFFFFFFFF
+	mov	r3, #0x3
+	str	r3, [r11,#0xa4]      @ TECMD = 0x3
+	str	r0, [r11,#0xc4]      @ TFCMD = 0x10
+	str	r0, [r11,#0xe4]      @ TGCMD = 0x10
+	str	r0, [r11,#0x104]     @ THCMD = 0x10
+	str	r4, [r11,#0x118]     @ THCMD = 0xFFFFFFFF
+	str	r1, [r12,#0x4c]      @ PWRCON(1)                                  @ R1: Unused
+	mov	r3, #0x73
+	str	r3, [r12,#0x58]      @ PWRCON(2)
+	str	r2, [r12,#0x6c]      @ PWRCON(4)                                  @ R2: Unused
+	orr	r10, r11, #0x00800000                                             @ R10: GPIO base address
+
+                           @ Block 3 (GPIO) register map:
+                           @ R0: Unused
+                           @ R1: Unused
+                           @ R2: Unused
+                           @ R3: Scratchpad
+                           @ R4: -1
+                           @ R5: 1
+                           @ R6: Unused
+                           @ R7: Unused
+                           @ R8: Unused
+                           @ R9: Unused
+                           @ R10: GPIO base address
+                           @ R11: TIMER base address
+                           @ R12: SYSCON base address
+                           @ R13: Constant pool pointer
+                           @ R14: 0
+
+.macro gpio_initdata
+	.word	0x3202EEEE @ PCON0
+	.word	0xE0EE2253 @ PCON1
+	.word	0x2223EEEE @ PCON2
+	.word	0x33333332 @ PCON3
+	.word	0xFF333E33 @ PCON4
+	.word	0xE0FEE200 @ PCON5
+	.word	0x2222222E @ PCON6
+	.word	0x22222222 @ PCON7
+	.word	0xEEEEEEE2 @ PCON8
+	.word	0xEEE0EEEE @ PCON9
+	.word	0x2EEEEEEE @ PCONA
+	.word	0xEEEE0222 @ PCONB
+	.word	0xEEEEE00E @ PCONC
+	.word	0xEEEEEEEE @ PCOND
+	.word	0xEEEEEEEE @ PCONE
+.endm
+
+	ldr	r3, [sp], #0x4
+	str	r3, [r10], #0xc                                                   @ R10: PCONx iterator
+	mov	r3, #0x20
+	str	r3, [r10], #0x4     @ PCON0 + 0xc = 0x20
+	mov	r3, #0x40
+	str	r3, [r10], #0x10    @ PCON0 + 0x10 = 0x40
+	add	r9, r10, #0x1a0                                                   @ R9: Iterator limit
+gpioloop1:
+	ldr	r3, [sp], #0x4
+	str	r3, [r10], #0xc
+	str	lr, [r10], #0x4     @ PCON + 0xc = 0
+	str	lr, [r10], #0x10    @ PCON + 0x10 = 0
+	cmp	r10, r9
+	bls	gpioloop1
+                                                                                  @ R10: 0x3CF001E0
+	ldr	r3, [r10,#0x1a8]
+	bic	r3, r3, #2
+	orr	r3, r3, #1
+	str	r3, [r10,#0x1a8]
+	sub	r8, r11, #0x00300000                                              @ R8: 0x39700000 (iterator)
+	mov	r9, #6                                                            @ R9: Iterations remaining
+gpioloop2:
+	str	r14, [r8,#0x80]
+	str	r4, [r8,#0xa0]
+	str	r14, [r8,#0xc0]
+	str	r14, [r8,#0xe0]
+	add	r8, r8, #4
+	subs	r9, r9, #1
+	bne	gpioloop2
+                                                                                  @ R9: 0
+	ldr	r8, [r10,#-0x180]                                                 @ R8: PCON3 backup
+	and	r3, r8, #0xff
+	str	r3, [r10,#-0x180]   @ *PCON3 &= 0xff
+	mov	r0, #0x3e8                                                        @ R0: Scratchpad
+	bl	udelay                                                            @ R14: Return address
+	ldr	r3, [r10,#-0x17c]
+	and	r3, r3, #0xfc
+	mov	r6, r3, lsr #0x2                                                  @ R6: Data for first PMU access
+	str	r8, [r10,#-0x180]
+	bic	r10, r11, #0x00100000                                             @ R10: I2C base address
+
+                           @ Block 4 (I2C) register map:
+                           @ R0: Scratchpad
+                           @ R1: Scratchpad
+                           @ R2: Unused
+                           @ R3: Unused
+                           @ R4: -1
+                           @ R5: 1
+                           @ R6: Data for first PMU access
+                           @ R7: Unused
+                           @ R8: Unused
+                           @ R9: 0
+                           @ R10: I2C base address
+                           @ R11: TIMER base address
+                           @ R12: SYSCON base address
+                           @ R13: Constant pool pointer
+                           @ R14: Return address / Scratchpad
+
+	bl	i2cwaitrdy
+	mov	r1, #0x40
+	str	r1, [r10,#0x08]
+	bl	i2cwaitrdy
+	str	r5, [r10,#0x14]
+	bl	i2cwaitrdy
+	str	r9, [r10,#0x18]
+	bl	i2cwaitrdy
+	mov	r0, #0x80
+	str	r0, [r10,#0x04]
+	bl	i2cwaitrdy
+	str	r9, [r10]
+	bl	i2cwaitrdy
+	str	r9, [r10,#0x04]
+	bl	i2cwaitrdy
+	str	r1, [r10,#0x0c]
+	bl	i2cwaitrdy
+	orr	r0, r5, #0x180
+	str	r0, [r10]
+	bl	i2cwaitrdy
+	mov	r0, #0x10
+	str	r0, [r10,#0x04]
+	bl	i2cwaitrdy
+    
+                           @ Block 5 (PMU) register map:
+                           @ R0: Address / Scratchpad (trashed by pmubatch)
+                           @ R1: Data / Scratchpad (trashed by pmubatch)
+                           @ R2: Scratchpad (set to 0xb7 by pmu accesses)
+                           @ R3: Scratchpad (set to 0x10 by pmu accesses)
+                           @ R4: Scratchpad (trashed by pmu accesses)
+                           @ R5: 1
+                           @ R6: Data for first PMU access
+                           @ R7: Scratchpad (trashed by pmubatch)
+                           @ R8: Used to store warmboot flag
+                           @ R9: 0 / pmubatch transfer count (reset to 0 by pmubatch)
+                           @ R10: I2C base address
+                           @ R11: TIMER base address
+                           @ R12: SYSCON base address
+                           @ R13: Constant pool / pmubatch data pointer
+                           @ R14: Return address / Scratchpad
+
+	mov	r0, #0x7f
+	mov	r1, r6
+	bl	pmuwrite
+	mov	r0, #0x02
+	bl	pmuread
+	ands	r8, r1, #0x80                                                     @ R8: Warmboot flag
+	beq	pmu_coldboot
+	mov	r1, #0x80
+	bl	pmuwrite
+pmu_coldboot:
+.macro pmu_batch_1
+pmu_batch_1_begin:
+	.byte	0x14, 0x13
+	.byte	0x15, 0x0d
+	.byte	0x0b, 0x22
+pmu_batch_1_end:
+.endm
+	mov	r9, #(pmu_batch_1_end - pmu_batch_1_begin) / 2
+	bl	pmubatch
+	tst	r6, #1                                                            @ R6: Unused
+	beq	pmu_skip
+	mov	r0, #0x0d
+	bl	pmuread
+	and	r1, r1, #0xdf
+	bl	pmuwrite
+pmu_skip:
+.macro pmu_batch_2
+pmu_batch_2_begin:
+	.byte	0x1f, 0x14
+	.byte	0x1a, 0xb2
+	.byte	0x1a, 0xb2
+	.byte	0x19, 0x14
+	.byte	0x21, 0x06
+	.byte	0x1d, 0x12
+pmu_batch_2_end:
+.endm
+	mov	r9, #(pmu_batch_2_end - pmu_batch_2_begin) / 2
+	bl	pmubatch
+	mov	r0, #0x10
+	bl	pmuread
+	bic	r1, r1, #0x80
+	orr	r1, r1, #0x60
+	bl	pmuwrite
+.macro pmu_batch_3
+pmu_batch_3_begin:
+	.byte	0x44, 0x72
+pmu_batch_3_end:
+.endm
+	mov	r9, #(pmu_batch_3_end - pmu_batch_3_begin) / 2
+	bl	pmubatch
+	mov	r0, #0x40
+	bl	pmuread
+	orr	r1, r1, #0x40
+	bl	pmuwrite
+	mov	r0, #0x33
+	bl	pmuread
+	and	r1, r1, #0x03
+	orr	r1, r1, #0x50
+	bl	pmuwrite
+	mov	r0, #0x34
+	bl	pmuread
+	and	r1, r1, #0x80
+	orr	r1, r1, #0x54
+	bl	pmuwrite
+.macro pmu_batch_4
+pmu_batch_4_begin:
+	.byte	0x22, 0x00
+	.byte	0x07, 0x50
+	.byte	0x08, 0xfe
+	.byte	0x09, 0x2b
+	.byte	0x01, 0xff
+	.byte	0x02, 0xff
+	.byte	0x03, 0xff
+pmu_batch_4_end:
+.endm
+	mov	r9, #(pmu_batch_4_end - pmu_batch_4_begin) / 2
+	bl	pmubatch
+	cmp	r8, #0
+	bne	pmu_warmboot
+	mov	r0, #0x30
+	mov	r1, #0x64
+	bl	pmuwrite
+pmu_warmboot:
+	mov	r0, #0x31
+	bl	pmuread
+	bic	r1, r1, #0x01
+	bl	pmuwrite
+.macro pmu_batch_5
+pmu_batch_5_begin:
+	.byte	0x0a, 0x70
+	.byte	0x13, 0x02
+pmu_batch_5_end:
+.endm
+	mov	r9, #(pmu_batch_5_end - pmu_batch_5_begin) / 2
+	bl	pmubatch
+
+	orr	lr, r11, #0x00800000                                              @ R14: GPIO base address
+	str	r9, [lr,#0x384]
+	orr	lr, r11, #0x01000000                                              @ R14: MIU base address
+	str	r5, [lr]
+	ldrh	r0, [sp], #2
+	str	r0, [lr,#0x100]
+	mov	r0, #0xff
+	str	r0, [lr,#0x11c]
+	str	r0, [lr,#0x120]
+	
+.macro block6_constpool           @ Block 6 (SDRAM) register map:
+	.hword	0x1030
+	.word	0x008AAC25 @ R0
+	.word	0x050D67E5 @ R1
+	.word	0x0002000B @ R2
+	.word	0x0003B3B2 @ R3
+	.word	0xFF53B3B0 @ R4
+	.word	0x00008040 @ R5
+	.word	0x8000100F @ R6: For LCD init at end of block
+	.word	0x41000c20 @ R7: For LCD init at end of block
+                           @ R8: Warmboot flag
+                           @ R9: 0
+                           @ R10: I2C base address
+                           @ R11: TIMER base address
+                           @ R12: SYSCON base address
+                           @ R13: Constant pool pointer
+.endm                      @ R14: MIU base address
+
+	ldmia	sp!, {r0-r7}
+	str	r0, [lr,#0x114]                                                   @ R0: Unused
+	str	r1, [lr,#0x124]                                                   @ R1: Unused
+	mov	r0, #8                                                            @ R0: Scratchpad
+	str	r0, [lr,#0x118]
+	str	r2, [lr,#0x108]
+	mov	r0, #4
+	str	r0, [lr,#0x148]
+	str	r9, [lr,#0x14c]
+	str	r3, [lr,#0x140]
+miu_wait1:
+	ldr	r0, [lr,#0x140]
+	tst	r0, #2
+	beq	miu_wait1
+	add	r0, r3, #1                                                        @ R3: Unused
+	str	r0, [lr,#0x140]
+miu_wait2:
+	ldr	r0, [lr,#0x144]
+	mvn	r0, r0
+	tst	r0, #3
+	bne	miu_wait2
+	ldr	r1, [lr,#0x144]                                                   @ R1: Scratchpad
+	mov	r0, #0x0ff00000
+	and	r0, r0, r1, lsl#2
+	add	r0, r0, r4                                                        @ R4: Unused
+	str	r0, [lr,#0x140]
+	mov	r0, #0x10
+	str	r0, [lr,#0x150]
+	cmp	r8, #0                                                            @ R8: Unused
+	sub	r8, r10, #0x04300000                                              @ R8: LCD base address
+	str	r6, [r12,#0x08]                                                   @ R6: Unused
+	str	r7, [r8]                                                          @ R7: Unused
+	mov	r0, #0x11
+	str	r0, [r8,#0x20]
+	mov	r3, #0x33                                                         @ R3: 0x33
+	beq	miu_coldboot
+	str	r0, [lr,#0x104]
+	b	miu_common
+miu_coldboot:
+	str	r3, [lr,#0x104]
+	orr	r0, r3, #0x200
+	str	r0, [lr,#0x104]
+miu_wait3:
+	ldr	r0, [lr,#0x104]
+	tst	r0, #0x110000
+	bne	miu_wait3
+	str	r3, [lr,#0x104]
+	str	r3, [lr,#0x104]
+	str	r3, [lr,#0x104]
+	orr	r1, r3, #0x300
+	str	r1, [lr,#0x104]
+miu_wait4:
+	ldr	r0, [lr,#0x104]
+	tst	r0, #0x110000
+	bne	miu_wait4
+	str	r3, [lr,#0x104]
+	str	r3, [lr,#0x104]
+	str	r3, [lr,#0x104]
+	str	r1, [lr,#0x104]
+miu_wait5:
+	ldr	r0, [lr,#0x104]
+	tst	r0, #0x110000
+	bne	miu_wait5
+	str	r3, [lr,#0x104]
+	str	r3, [lr,#0x104]
+	str	r3, [lr,#0x104]
+	str	r3, [lr,#0x110]
+	orr	r0, r3, #0x100
+	str	r0, [lr,#0x104]
+miu_wait6:
+	ldr	r0, [lr,#0x104]
+	tst	r0, #0x110000
+	bne	miu_wait6
+	str	r3, [lr,#0x104]
+	str	r3, [lr,#0x104]
+	str	r3, [lr,#0x104]
+	str	r5, [lr,#0x110]                                                   @ R5: Unused
+	str	r1, [lr,#0x104]
+miu_wait7:
+	ldr	r0, [lr,#0x104]
+	tst	r0, #0x110000
+	bne	miu_wait7
+	str	r3, [lr,#0x104]
+	str	r3, [lr,#0x104]
+miu_common:
+	str	r3, [lr,#0x104]                                                   @ R3: Unused
+	mov	r0, #0x40
+	str	r0, [lr,#0x10c]
+	ldr	r0, [lr,#0x100]
+	orr	r0, r0, #0x9100000
+	str	r0, [lr,#0x100]
+	mov	r0, #0x19
+	str	r0, [lr,#0x11c]
+	mov	r0, #1
+	str	r0, [lr,#0x120]
+	orr	r1, r2, #0x1000                                                   @ R2: Unused
+	str	r1, [lr,#0x108]
+	str	r0, [lr,#0x08]
+	mov	r1, #0x3e000000
+	mov	r0, #0x1f
+	str	r0, [r1,#0x08]
+
+                           @ Block 7 (LCD) register map:
+                           @ R0: Cmd/Data to be written / Scratchpad
+                           @ R1: Scratchpad
+                           @ R2: Scratchpad
+                           @ R3: Scratchpad
+                           @ R4: Scratchpad
+                           @ R5: Scratchpad
+                           @ R6: Unused
+                           @ R7: Unused
+                           @ R8: LCD base address
+                           @ R9: 0
+                           @ R10: I2C base address
+                           @ R11: TIMER base address
+                           @ R12: SYSCON base address
+                           @ R13: LCD init script pointer / Scratchpad
+                           @ R14: Return address / Scratchpad
+
+.macro lcd_sequences
+lcd_sequences_begin:
+	.word	lcd_sequence_c4 - lcd_sequences_begin
+	.word	lcd_sequence_d5 - lcd_sequences_begin
+	.word	lcd_sequence_e6 - lcd_sequences_begin
+	.word	lcd_sequence_b3 - lcd_sequences_begin
+lcd_sequence_b3:
+.byte 0x01, 0x11, 0xf8, 0x01, 0x13, 0x01, 0x29, 0x80
+	.byte	0x01, 0x11
+	.byte	0xf8
+	.byte	0x02, 0xfe, 0x00
+	.byte	0x02, 0xef, 0x80
+	.byte	0x02, 0xc0, 0x0c
+	.byte	0x02, 0xc1, 0x03
+	.byte	0x03, 0xc2, 0x12, 0x00
+	.byte	0x03, 0xc3, 0x12, 0x00
+	.byte	0x03, 0xc4, 0x12, 0x00
+	.byte	0x03, 0xc5, 0x3a, 0x3e
+	.byte	0x03, 0xb1, 0x6a, 0x15
+	.byte	0x03, 0xb2, 0x5f, 0x3f
+	.byte	0x03, 0xb3, 0x5f, 0x3f
+	.byte	0x02, 0xb4, 0x02
+	.byte	0x03, 0xb6, 0x12, 0x02
+	.byte	0x02, 0x35, 0x00
+	.byte	0x02, 0x26, 0x10
+	.byte	0x0c, 0xe0, 0x0f, 0x42, 0x24, 0x01, 0x00, 0x02, 0xa6, 0x98, 0x05, 0x04, 0x15
+	.byte	0x0c, 0xe1, 0x00, 0x21, 0x44, 0x02, 0x0f, 0x05, 0x89, 0x6a, 0x02, 0x15, 0x04
+	.byte	0x0c, 0xe2, 0x7e, 0x04, 0x43, 0x40, 0x00, 0x02, 0x13, 0x00, 0x00, 0x01, 0x0b
+	.byte	0x0c, 0xe3, 0x40, 0x40, 0x03, 0x74, 0x0e, 0x00, 0x00, 0x31, 0x02, 0x0b, 0x01
+	.byte	0x0c, 0xe4, 0x5a, 0x43, 0x67, 0x56, 0x00, 0x02, 0x67, 0x72, 0x00, 0x05, 0x12
+	.byte	0x0c, 0xe5, 0x50, 0x66, 0x47, 0x53, 0x0a, 0x00, 0x27, 0x76, 0x02, 0x12, 0x05
+	.byte	0x02, 0x3a, 0x06
+	.byte	0x01, 0x13
+	.byte	0x01, 0x29
+	.byte	0x80
+lcd_sequence_c4:
+	.byte	0x01, 0x01
+	.byte	0x85
+	.byte	0x02, 0xc0, 0x00
+	.byte	0x02, 0xc1, 0x03
+	.byte	0x02, 0xc2, 0x34
+	.byte	0x03, 0xc3, 0x72, 0x03
+	.byte	0x03, 0xc4, 0x73, 0x03
+	.byte	0x03, 0xc5, 0x3c, 0x3c
+	.byte	0x02, 0xfe, 0x00
+	.byte	0x03, 0xb1, 0x6a, 0x15
+	.byte	0x03, 0xb2, 0x6a, 0x15
+	.byte	0x03, 0xb3, 0x6a, 0x15
+	.byte	0x02, 0xb4, 0x02
+	.byte	0x03, 0xb6, 0x12, 0x02
+	.byte	0x02, 0x35, 0x00
+	.byte	0x02, 0x26, 0x10
+	.byte	0x0c, 0xe0, 0x77, 0x52, 0x76, 0x53, 0x03, 0x03, 0x57, 0x42, 0x10, 0x18, 0x09
+	.byte	0x0c, 0xe1, 0x0d, 0x00, 0x23, 0x66, 0x0f, 0x15, 0x4d, 0x85, 0x08, 0x02, 0x10
+	.byte	0x0c, 0xe2, 0x39, 0x60, 0x77, 0x05, 0x03, 0x07, 0x96, 0x64, 0x0d, 0x1a, 0x0a
+	.byte	0x0c, 0xe3, 0x3f, 0x10, 0x16, 0x44, 0x0e, 0x04, 0x6c, 0x44, 0x04, 0x03, 0x0b
+	.byte	0x0c, 0xe4, 0x00, 0x61, 0x77, 0x04, 0x02, 0x04, 0x72, 0x32, 0x09, 0x19, 0x06
+	.byte	0x0c, 0xe5, 0x4f, 0x42, 0x27, 0x67, 0x0f, 0x02, 0x26, 0x33, 0x01, 0x03, 0x09
+	.byte	0x02, 0x36, 0x00
+	.byte	0x01, 0x11
+	.byte	0x01, 0x29
+	.byte	0x80
+lcd_sequence_d5:
+.byte 0x01, 0x01, 0x85, 0x01, 0x11, 0x01, 0x29, 0x80
+	.byte	0x02, 0xfe, 0x00
+	.byte	0x02, 0xc0, 0x01
+	.byte	0x02, 0xc1, 0x01
+	.byte	0x03, 0xc2, 0x03, 0x00
+	.byte	0x03, 0xc3, 0x01, 0x00
+	.byte	0x03, 0xc4, 0x03, 0x00
+	.byte	0x03, 0xc5, 0x34, 0x34
+	.byte	0x02, 0xc7, 0x00
+	.byte	0x03, 0xb1, 0x6d, 0x15
+	.byte	0x03, 0xb2, 0x6d, 0x15
+	.byte	0x03, 0xb3, 0x6d, 0x15
+	.byte	0x02, 0xb4, 0x03
+	.byte	0x03, 0xb6, 0x11, 0x02
+	.byte	0x02, 0x35, 0x00
+	.byte	0x02, 0x26, 0x10
+	.byte	0x0c, 0xe0, 0x23, 0x42, 0x20, 0x42, 0x0e, 0x01, 0xf5, 0xeb, 0x1e, 0x05, 0x18
+	.byte	0x0c, 0xe1, 0x5f, 0x22, 0x36, 0x21, 0x03, 0x1e, 0xfe, 0x7b, 0x02, 0x07, 0x18
+	.byte	0x0c, 0xe2, 0x5f, 0x34, 0x53, 0x77, 0x0a, 0x00, 0x70, 0xf4, 0x14, 0x06, 0x0f
+	.byte	0x0c, 0xe3, 0x0f, 0x23, 0x31, 0x54, 0x0f, 0x0b, 0x8e, 0x08, 0x00, 0x05, 0x15
+	.byte	0x0c, 0xe4, 0x5f, 0x33, 0x42, 0x14, 0x0e, 0x04, 0xa6, 0xf7, 0x0e, 0x00, 0x14
+	.byte	0x0c, 0xe5, 0x0c, 0x43, 0x44, 0x44, 0x0d, 0x0d, 0x7f, 0x39, 0x03, 0x02, 0x10
+	.byte	0x02, 0x3a, 0x66
+	.byte	0x02, 0x36, 0x00
+	.byte	0x01, 0x11
+	.byte	0x01, 0x29
+	.byte	0x80
+lcd_sequence_e6:
+.byte 0x01, 0x11, 0xf8, 0x01, 0x13, 0x01, 0x29, 0x80
+	.byte	0x01, 0x11
+	.byte	0xf8
+	.byte	0x02, 0xfe, 0x00
+	.byte	0x02, 0xef, 0x80
+	.byte	0x02, 0xc0, 0x13
+	.byte	0x02, 0xc1, 0x03
+	.byte	0x03, 0xc2, 0x12, 0x00
+	.byte	0x03, 0xc3, 0x12, 0x00
+	.byte	0x03, 0xc4, 0x12, 0x00
+	.byte	0x03, 0xc5, 0x2a, 0x3c
+	.byte	0x03, 0xb1, 0x6a, 0x15
+	.byte	0x03, 0xb2, 0x5f, 0x3f
+	.byte	0x03, 0xb3, 0x5f, 0x3f
+	.byte	0x02, 0xb4, 0x02
+	.byte	0x03, 0xb6, 0x12, 0x02
+	.byte	0x02, 0x35, 0x00
+	.byte	0x02, 0x26, 0x10
+	.byte	0x0c, 0xe0, 0x0f, 0x53, 0x45, 0x07, 0x00, 0x00, 0xb9, 0xf6, 0x08, 0x04, 0x18
+	.byte	0x0c, 0xe1, 0x00, 0x47, 0x55, 0x03, 0x0f, 0x08, 0x6f, 0x9b, 0x00, 0x18, 0x04
+	.byte	0x0c, 0xe2, 0x7e, 0x03, 0x54, 0x75, 0x00, 0x00, 0x3a, 0x52, 0x03, 0x02, 0x10
+	.byte	0x0c, 0xe3, 0x70, 0x55, 0x04, 0x73, 0x0e, 0x03, 0x25, 0xa3, 0x00, 0x10, 0x02
+	.byte	0x0c, 0xe4, 0x1a, 0x72, 0x33, 0x76, 0x00, 0x00, 0xeb, 0x97, 0x03, 0x05, 0x17
+	.byte	0x0c, 0xe5, 0x70, 0x36, 0x73, 0x12, 0x0a, 0x03, 0x79, 0xbe, 0x00, 0x17, 0x05
+	.byte	0x02, 0x3a, 0x06
+	.byte	0x01, 0x13
+	.byte	0x01, 0x29
+	.byte	0x80
+lcd_sequences_end:
+.endm
+
+	mov	r0, #4
+	bl	sendlcdc
+	bl	readlcd
+	bl	readlcd
+	bl	readlcd
+	and	r0, r0, #3
+	ldr	r0, [sp,r0,lsl#2]
+	add	sp, sp, r0
+lcdloop:
+	ldrb	r1, [sp], #1
+	tst	r1, #0x80
+	beq	lcddata
+	bics	r1, r1, #0x80
+	beq	lcddone
+	mov	r0, r1,lsl#10
+	bl	udelay
+	b	lcdloop
+lcddata:
+	ldrb	r0, [sp], #1
+	bl	sendlcdc
+lcdbyte:
+	subs	r1, r1, #1
+	beq	lcdloop
+	ldrb	r0, [sp], #1
+	bl	sendlcdd
+	b	lcdbyte
+
+values1:
+	block0_constpool
+	block1_constpool
+	gpio_initdata
+	pmu_batch_1
+	pmu_batch_2
+	pmu_batch_3
+	pmu_batch_4
+	pmu_batch_5
+	block6_constpool
+	lcd_sequences
+	
+	.align	1
+	.code	16
+thumb_nrv2e_d8:
+	mov r7,r2
+        mov r4,#1; neg r5,r4 @ r5= -1 initial condition
+        lsl r4,#31 @ 1<<31: refill next time
+        mov r6,#5
+        lsl r6,#8 @ 0x500 @ nrv2e M2_MAX_OFFSET
+        b top_n2e
+
+nrv2e_done:
+	blx execfirmware
+
+get1_n2e: @ In: Carry set [from adding 0x80000000 (1<<31) to itself]
+        ldrb r4,[r0] @ zero-extend next byte
+        adc r4,r4 @ double and insert CarryIn as low bit
+        add r0,#1
+        lsl r4,#24 @ move to top byte, and set CarryOut from old bit 8
+        mov pc,lr @ return, stay in current (THUMB) mode
+
+lit_n2e:
+        ldrb r3,[r0]; add r0,#1
+        strb r3,[r2]; add r2,#1
+top_n2e:
+        add r4,r4; mov lr,pc; beq get1_n2e; bcs lit_n2e
+        mov r1,#1; b getoff_n2e
+
+off_n2e:
+        sub r1,#1
+        add r4,r4; mov lr,pc; beq get1_n2e; adc r1,r1
+getoff_n2e:
+        add r4,r4; mov lr,pc; beq get1_n2e; adc r1,r1
+        add r4,r4; mov lr,pc; beq get1_n2e; bcc off_n2e
+
+        sub r3,r1,#3 @ set Carry
+        mov r1,#0 @ Carry unaffected
+        blo offprev_n2e @ r1 was 2; tests Carry only
+        lsl r3,#8
+        ldrb r5,[r0]; add r0,#1 @ low 7+1 r4
+        orr r5,r3
+        mvn r5,r5; beq nrv2e_done @ r5= ~r5
+        asr r5,#1; bcs lenlast_n2e
+        b lenmore_n2e
+
+offprev_n2e:
+        add r4,r4; mov lr,pc; beq get1_n2e; bcs lenlast_n2e
+lenmore_n2e:
+        mov r1,#1
+        add r4,r4; mov lr,pc; beq get1_n2e; bcs lenlast_n2e
+len_n2e:
+        add r4,r4; mov lr,pc; beq get1_n2e; adc r1,r1
+        add r4,r4; mov lr,pc; beq get1_n2e; bcc len_n2e
+        add r1,#6-2
+        b gotlen_n2e
+
+lenlast_n2e:
+        add r4,r4; mov lr,pc; beq get1_n2e; adc r1,r1 @ 0,1,2,3
+        add r1,#2
+gotlen_n2e: @ 'cmn': add the inputs, set condition codes, discard the sum
+        cmn r6,r5; bcs near_n2e @ within M2_MAX_OFFSET
+        add r1,#1 @ too far away, so minimum match length is 3
+near_n2e:
+        ldrb r3,[r2] @ force cacheline allocate
+copy_n2e:
+        ldrb r3,[r2,r5]
+        strb r3,[r2]; add r2,#1
+        sub r1,#1; bne copy_n2e
+        b top_n2e
+	.code	32
+
+font:
+	.byte	0, 0, 0, 0, 0
+	.byte	0, 0, 95, 0, 0
+	.byte	0, 7, 0, 7, 0
+	.byte	20, 127, 20, 127, 20
+	.byte	36, 42, 127, 42, 18
+	.byte	35, 19, 8, 100, 98
+	.byte	54, 73, 85, 34, 80
+	.byte	5, 3, 0, 0, 0
+	.byte	28, 34, 65, 0, 0
+	.byte	0, 0, 65, 34, 28
+	.byte	20, 8, 62, 8, 20
+	.byte	8, 8, 62, 8, 8
+	.byte	0, -96, 96, 0, 0
+	.byte	8, 8, 8, 8, 8
+	.byte	0, 96, 96, 0, 0
+	.byte	32, 16, 8, 4, 2
+	.byte	62, 81, 73, 69, 62
+	.byte	0, 66, 127, 64, 0
+	.byte	66, 97, 81, 73, 70
+	.byte	33, 65, 69, 75, 49
+	.byte	24, 20, 18, 127, 16
+	.byte	39, 69, 69, 69, 57
+	.byte	60, 74, 73, 73, 48
+	.byte	1, 113, 9, 5, 3
+	.byte	54, 73, 73, 73, 54
+	.byte	6, 73, 73, 41, 30
+	.byte	0, 54, 54, 0, 0
+	.byte	0, 86, 54, 0, 0
+	.byte	8, 20, 34, 65, 0
+	.byte	20, 20, 20, 20, 20
+	.byte	0, 65, 34, 20, 8
+	.byte	2, 1, 81, 9, 6
+	.byte	50, 73, 121, 65, 62
+	.byte	124, 18, 17, 18, 124
+	.byte	127, 73, 73, 73, 62
+	.byte	62, 65, 65, 65, 34
+	.byte	127, 65, 65, 34, 28
+	.byte	127, 73, 73, 73, 65
+	.byte	127, 9, 9, 9, 1
+	.byte	62, 65, 73, 73, 58
+	.byte	127, 8, 8, 8, 127
+	.byte	0, 65, 127, 65, 0
+	.byte	32, 64, 65, 63, 1
+	.byte	127, 8, 20, 34, 65
+	.byte	127, 64, 64, 64, 64
+	.byte	127, 2, 12, 2, 127
+	.byte	127, 4, 8, 16, 127
+	.byte	62, 65, 65, 65, 62
+	.byte	127, 9, 9, 9, 6
+	.byte	62, 65, 81, 33, 94
+	.byte	127, 9, 25, 41, 70
+	.byte	38, 73, 73, 73, 50
+	.byte	1, 1, 127, 1, 1
+	.byte	63, 64, 64, 64, 63
+	.byte	31, 32, 64, 32, 31
+	.byte	127, 32, 24, 32, 127
+	.byte	99, 20, 8, 20, 99
+	.byte	3, 4, 120, 4, 3
+	.byte	97, 81, 73, 69, 67
+	.byte	0, 127, 65, 65, 0
+	.byte	2, 4, 8, 16, 32
+	.byte	0, 65, 65, 127, 0
+	.byte	4, 2, 1, 2, 4
+	.byte	64, 64, 64, 64, 64
+	.byte	1, 2, 4, 0, 0
+	.byte	32, 84, 84, 84, 120
+	.byte	127, 68, 68, 68, 56
+	.byte	56, 68, 68, 68, 40
+	.byte	56, 68, 68, 68, 127
+	.byte	56, 84, 84, 84, 24
+	.byte	8, 126, 9, 1, 2
+	.byte	8, 84, 84, 84, 60
+	.byte	127, 4, 4, 4, 120
+	.byte	0, 68, 125, 64, 0
+	.byte	32, 64, 64, 61, 0
+	.byte	127, 16, 40, 68, 0
+	.byte	0, 65, 127, 64, 0
+	.byte	124, 4, 24, 4, 120
+	.byte	124, 8, 4, 4, 120
+	.byte	56, 68, 68, 68, 56
+	.byte	124, 20, 20, 20, 24
+	.byte	8, 20, 20, 20, 124
+	.byte	124, 8, 4, 4, 8
+	.byte	72, 84, 84, 84, 32
+	.byte	4, 63, 68, 64, 32
+	.byte	60, 64, 64, 32, 124
+	.byte	28, 32, 64, 32, 28
+	.byte	60, 64, 56, 64, 60
+	.byte	68, 40, 16, 40, 68
+	.byte	12, 80, 80, 80, 60
+	.byte	68, 100, 84, 76, 68
+	.byte	0, 8, 54, 65, 0
+	.byte	0, 0, 119, 0, 0
+	.byte	0, 65, 54, 8, 0
+	.byte	2, 1, 2, 4, 2
+
+errormessage:
+	.ascii "File not found!\0"
+
+bootfilename:
+	.ascii "emcore  "
+
+text:
+	.ascii "emCORE Loader v"
+	.ascii VERSION
+	.ascii " r"
+	.ascii VERSION_SVN
+	.ascii "\0"
+	.ascii "Loading emCORE...\0"
+
+	.align	2
+
+execfirmware:
+	mcr	p15, 0, r9,c7,c14,0 @ clean & invalidate data cache
+	bx	r7
+
+                           @ rendertext register map:
+                           @ R0: Pointer to string, will be incremented
+                           @ R1: Framebuffer address, will be incremented
+                           @ R2: Color
+                           @ R3: Trashed
+                           @ R4: Trashed
+                           @ R4: Trashed
+                           @ R9: Set to 0
+                           @ R14: Return address
+
+rendertext:
+	ldrb	r3, [r0], #1
+	cmp	r3, #0
+	moveq	pc, lr
+	adr	r5, font
+	sub	r3, r3, #0x20
+	cmp	r3, #0x5f
+	addcc	r5, r3,lsl#2
+	addcc	r5, r3
+	mov	r3, #5
+rendertext_col:
+	mov	r4, r1
+	ldrb	r9, [r5], #1
+rendertext_row:
+	tst	r9, #1
+	strneh	r2, [r4]
+	add	r4, r4, #480
+	movs	r9, r9,lsr#1
+	bne	rendertext_row
+	add	r1, r1, #2
+	subs	r3, r3, #1
+	bne	rendertext_col
+	add	r1, r1, #2
+	b	rendertext
+
+lcd_mode:
+	.word	0x41100db8
+
+
+                           @ Block 8 (DRAW) register map:
+                           @ R0: Scratchpad
+                           @ R1: Scratchpad
+                           @ R2: Scratchpad
+                           @ R3: Scratchpad
+                           @ R4: Scratchpad
+                           @ R5: Scratchpad
+                           @ R6: Unused
+                           @ R7: Unused
+                           @ R8: LCD base address
+                           @ R9: 0
+                           @ R10: I2C base address
+                           @ R11: TIMER base address
+                           @ R12: SYSCON base address
+                           @ R13: Scratchpad
+                           @ R14: Return address / Scratchpad
+
+lcddone:
+	ldr	r0, lcd_mode
+	str	r0, [r8]
+	mov	r1, #0x22000000
+	orr	r1, r1, #0x6800
+	add	r2, r1, #0x25800
+	mov	r0, #-1
+fillbuff:
+	str	r0, [r2,#-4]!
+	cmp	r1, r2
+	bne	fillbuff
+	mov	sp, r1
+	adr	r0, text
+	mov	r2, #0
+	bl	rendertext
+	add	r1, sp, #0x1e00
+printerror:
+	bl	rendertext
+	mcr	p15, 0, r9,c7,c10,0 @ clean data cache
+	mcr	p15, 0, r9,c7,c10,4 @ drain write buffer
+	mov	r0, #0x2a
+	bl	sendlcdc
+	mov	r0, #0
+	bl	sendlcdd
+	mov	r0, #0xef
+	bl	sendlcdd
+	mov	r0, #0x2b
+	bl	sendlcdc
+	mov	r0, #0
+	bl	sendlcdd
+	mov	r0, #0x200
+	orr	r0, r0, #0x3f
+	bl	sendlcdd
+	mov	r0, #0x2c
+	bl	sendlcdc
+blit:
+	sub	lr, r8, #0x00100000
+	mov	sp, #1
+	str	sp, [lr,#0x30]
+	mov	sp, #0x22000000
+	orr	sp, sp, #0x2d000
+	add	lr, lr, #0x100
+	mov	r4, #0x8800
+	orr	r4, r4, #0xc1
+	ldmia	sp, {r0-r3}
+	stmia	lr, {r0-r4}
+@	tst	r5, #0xff
+@failed:
+@	bne	failed
+	mov	r0, #0x30
+	mov	r1, #120
+	bl	pmuwrite
+	mov	r0, #0x31
+	mov	r1, #1
+	bl	pmuwrite
+
+
+hang: b hang
+
+                           @ udelay register map:
+                           @ R0: Microseconds
+                           @ R1: Trashed
+                           @ R11: TIMER base address
+                           @ R14: Return address
+
+udelay:
+	ldr	r1, [r11,#0xb4]
+	add	r0, r0, r1
+udelayloop:
+	ldr	r1, [r11,#0xb4]
+	cmp	r1, r0
+	bmi	udelayloop
+	mov	pc, lr
+
+                           @ i2cwaitrdy register map:
+                           @ R9: Set to 0
+                           @ R10: I2C base address
+                           @ R14: Return address
+
+i2cwaitrdy:
+	ldr	r9, [r10,#0x10]
+	cmp	r9, #0
+	bne	i2cwaitrdy
+	mov	pc, lr
+
+                           @ i2cwait register map:
+                           @ R3: Set to 0x10
+                           @ R10: I2C base address
+                           @ R14: Return address
+
+i2cwait:
+	ldr	r3, [r10]
+	ands	r3, #0x10
+	beq	i2cwait
+	mov	pc, lr
+
+                           @ pmuwrite register map:
+                           @ R0: Address
+                           @ R1: Data
+                           @ R2: Set to 0xb7
+                           @ R3: Set to 0x10
+                           @ R4: Return address backup
+                           @ R10: I2C base address
+                           @ R14: Return address / Scratchpad
+
+pmuwrite:
+	mov	r4, lr
+	mov	lr, #0xe6
+	str	lr, [r10,#0x0c]
+	mov	lr, #0xf0
+	str	lr, [r10,#0x04]
+	mov	r2, #0xb7
+	str	r2, [r10]
+	bl	i2cwait
+	str	r0, [r10,#0x0c]
+	str	r2, [r10]
+	bl	i2cwait
+	str	r1, [r10,#0x0c]
+	str	r2, [r10]
+	bl	i2cwait
+	mov	lr, #0xd0
+	str	lr, [r10,#0x04]
+	str	r2, [r10]
+pmuwrite_wait:
+	ldr	lr, [r10,#0x04]
+	tst	lr, #0x20
+	bne	pmuwrite_wait
+	mov	pc, r4
+
+                           @ pmuread register map:
+                           @ R0: Address
+                           @ R1: Data
+                           @ R2: Set to 0xb7
+                           @ R3: Set to 0x10
+                           @ R4: Return address backup
+                           @ R10: I2C base address
+                           @ R14: Return address / Scratchpad
+
+pmuread:
+	mov	r4, lr
+	mov	lr, #0xe6
+	str	lr, [r10,#0x0c]
+	mov	lr, #0xf0
+	str	lr, [r10,#0x04]
+	mov	r2, #0xb7
+	str	r2, [r10]
+	bl	i2cwait
+	str	r0, [r10,#0x0c]
+	str	r2, [r10]
+	bl	i2cwait
+	mov	r1, #0xe7
+	str	r1, [r10,#0x0c]
+	mov	r1, #0xb0
+	str	r1, [r10,#0x04]
+	str	r2, [r10]
+	bl	i2cwait
+	mov	r1, #0x37
+	str	r1, [r10]
+	bl	i2cwait
+	ldr	r1, [r10,#0x0c]
+	mov	lr, #0x90
+	str	lr, [r10,#0x04]
+	str	r2, [r10]
+pmuread_wait:
+	ldr	lr, [r10,#0x04]
+	tst	lr, #0x20
+	bne	pmuread_wait
+	mov	pc, r4
+
+                           @ pmubatch register map:
+                           @ R0: Scratchpad
+                           @ R1: Scratchpad
+                           @ R2: Set to 0xb7
+                           @ R3: Set to 0x10
+                           @ R4: Inner return address backup
+                           @ R7: Outer return address backup
+                           @ R9: Number of address-data pairs to be sent (must be >0), will be reset to 0
+                           @ R10: I2C base address
+                           @ R13: Address-data pair list pointer (will be incremented)
+                           @ R14: Return address / Scratchpad
+
+pmubatch:
+	mov	r7, lr
+pmubatch_loop:
+	ldrb	r0, [sp], #1
+	ldrb	r1, [sp], #1
+	bl	pmuwrite
+	subs	r9, r9, #1
+	bne	pmubatch_loop
+	mov	pc, r7
+
+                           @ sendlcdc register map:
+                           @ R0: Command to be sent
+                           @ R8: LCD base address
+                           @ R9: Will be set to 0
+                           @ R14: Return address
+
+sendlcdc:
+	ldr	r9, [r8,#0x1c]
+	ands	r9, r9, #0x10
+	bne	sendlcdc
+	str	r0, [r8,#0x04]
+	mov	pc, lr
+
+                           @ sendlcdd register map:
+                           @ R0: Data to be sent
+                           @ R8: LCD base address
+                           @ R9: Will be set to 0
+                           @ R14: Return address
+
+sendlcdd:
+	ldr	r9, [r8,#0x1c]
+	ands	r9, r9, #0x10
+	bne	sendlcdd
+	str	r0, [r8,#0x40]
+	mov	pc, lr
+	
+                           @ readlcd register map:
+                           @ R0: Result data
+                           @ R8: LCD base address
+                           @ R14: Return address
+
+readlcd:
+	ldr	r0, [r8,#0x1c]
+	tst	r0, #2
+	beq	readlcd
+	str	r0, [r8,#0x10]
+readlcd_wait:
+	ldr	r0, [r8,#0x1c]
+	tst	r0, #0x1
+	beq	readlcd_wait
+	ldr	r0, [r8,#0x14]
+	mov	r0, r0,lsr#1
+	mov	pc, lr
Index: emcore/trunk/loader/ipodnano4g/Makefile
===================================================================
--- emcore/trunk/loader/ipodnano4g/Makefile	(revision 0)
+++ emcore/trunk/loader/ipodnano4g/Makefile	(revision 0)
@@ -0,0 +1,101 @@
+NAME := emcoreldr-ipodnano4g
+
+EMCOREDIR ?= ../../
+
+ifeq ($(shell uname),WindowsNT)
+CCACHE :=
+else
+CCACHE := $(shell which ccache)
+endif
+
+CROSS   ?= arm-elf-eabi-
+CC      := $(CCACHE) $(CROSS)gcc
+AS      := $(CROSS)as
+LD      := $(CROSS)ld
+OBJCOPY := $(CROSS)objcopy
+UCLPACK := ucl2e10singleblk
+
+CFLAGS  += -Os -fno-pie -fno-stack-protector -fomit-frame-pointer -I. -ffunction-sections -fdata-sections -mcpu=arm1176jz-s
+LDFLAGS += "$(shell $(CC) -print-libgcc-file-name)" --gc-sections
+
+preprocess = $(shell $(CC) $(PPCFLAGS) $(2) -E -P -x c $(1) | grep -v "^\#")
+preprocesspaths = $(shell $(CC) $(PPCFLAGS) $(2) -E -P -x c $(1) | grep -v "^\#" | sed -e "s:^..*:$(dir $(1))&:" | sed -e "s:^\\./::")
+
+REVISION := $(shell svnversion .)
+REVISIONINT := $(shell echo $(REVISION) | sed -e "s/[^0-9].*$$//")
+
+SRC := $(call preprocesspaths,SOURCES,-I. -I..)
+OBJ := $(SRC:%.c=build/%.o)
+OBJ := $(OBJ:%.S=build/%.o) $(HELPERS)
+
+all: $(NAME)
+
+-include $(OBJ:%=%.dep)
+
+$(NAME): build/$(NAME).bin
+
+build/$(NAME).bin: build/$(NAME).elf
+	@echo [OC]     $<
+	@$(OBJCOPY) -O binary $^ $@
+
+build/$(NAME).elf: ls.x $(OBJ)
+	@echo [LD]     $@
+	@$(LD) $(LDFLAGS) -o $@ -T ls.x $(OBJ)
+
+build/%.o: %.c build/version.h
+	@echo [CC]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
+else
+	@-mkdir -p $(dir $@)
+endif
+	@$(CC) -c $(CFLAGS) -o $@ $<
+	@$(CC) -MM $(CFLAGS) $< > $@.dep.tmp
+	@sed -e "s|.*:|$@:|" < $@.dep.tmp > $@.dep
+ifeq ($(shell uname),WindowsNT)
+	@sed -e "s/.*://" -e "s/\\$$//" < $@.dep.tmp | fmt -1 | sed -e "s/^ *//" -e "s/$$/:/" >> $@.dep
+else
+	@sed -e 's/.*://' -e 's/\\$$//' < $@.dep.tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $@.dep
+endif
+	@rm -f $@.dep.tmp
+
+build/%.o: %.S build/version.h
+	@echo [CC]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
+else
+	@-mkdir -p $(dir $@)
+endif
+	@$(CC) -c $(CFLAGS) -o $@ $<
+	@$(CC) -MM $(CFLAGS) $< > $@.dep.tmp
+	@sed -e "s|.*:|$@:|" < $@.dep.tmp > $@.dep
+ifeq ($(shell uname),WindowsNT)
+	@sed -e "s/.*://" -e "s/\\$$//" < $@.dep.tmp | fmt -1 | sed -e "s/^ *//" -e "s/$$/:/" >> $@.dep
+else
+	@sed -e 's/.*://' -e 's/\\$$//' < $@.dep.tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $@.dep
+endif
+	@rm -f $@.dep.tmp
+
+build/__emcore_%.o: $(EMCOREDIR)/export/%.S
+	@echo [CC]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
+else
+	@-mkdir -p $(dir $@)
+endif
+	@$(CC) -c $(CFLAGS) -o $@ $<
+
+build/version.h: version.h .svn/entries
+	@echo [PP]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist build md build
+	@sed -e "s/\$$REVISION\$$/$(REVISION)/" -e "s/\$$REVISIONINT\$$/$(REVISIONINT)/" < $< > $@
+else
+	@-mkdir -p build
+	@sed -e 's/\$$REVISION\$$/$(REVISION)/' -e 's/\$$REVISIONINT\$$/$(REVISIONINT)/' < $< > $@
+endif
+
+clean:
+	@rm -rf build
+
+.PHONY: all clean $(NAME)
Index: emcore/trunk/loader/ipodnano4g/SOURCES
===================================================================
--- emcore/trunk/loader/ipodnano4g/SOURCES	(revision 0)
+++ emcore/trunk/loader/ipodnano4g/SOURCES	(revision 0)
@@ -0,0 +1 @@
+main.c
Index: emcore/trunk/loader/ipodnano4g/version.h
===================================================================
--- emcore/trunk/loader/ipodnano4g/version.h	(revision 0)
+++ emcore/trunk/loader/ipodnano4g/version.h	(revision 0)
@@ -0,0 +1,36 @@
+//
+//
+//    Copyright 2010 TheSeven
+//
+//
+//    This file is part of emCORE.
+//
+//    emCORE is free software: you can 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.
+//
+//    emCORE is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+//
+//    You should have received a copy of the GNU General Public License along
+//    with emCORE.  If not, see <http://www.gnu.org/licenses/>.
+//
+//
+
+
+#ifndef __VERSION_H__
+#define __VERSION_H__
+
+
+#define VERSION "0.0.1"
+#define VERSION_MAJOR 0
+#define VERSION_MINOR 0
+#define VERSION_PATCH 1
+#define VERSION_SVN "$REVISION$"
+#define VERSION_SVN_INT $REVISIONINT$
+
+
+#endif
Index: emcore/trunk/tools/lcdtest.py
===================================================================
--- emcore/trunk/tools/lcdtest.py	(revision 0)
+++ emcore/trunk/tools/lcdtest.py	(revision 0)
@@ -0,0 +1,476 @@
+#!/usr/bin/env python
+
+import sys
+import os
+import time
+import struct
+import locale
+
+from functools import wraps
+
+import libemcore
+import libemcoredata
+from misc import Error, ArgumentError, ArgumentTypeError, Logger, getfuncdoc, gethwname, to_bool, to_int
+
+class Interface(object):
+    def __init__(self):
+        self.logger = Logger()
+        try:
+            self.emcore = libemcore.Emcore(logger = self.logger)
+        except libemcore.DeviceNotFoundError:
+            self.logger.error("No emCORE device found!\n")
+            exit(1)
+    def lcdcmd(self, cmd):
+        data = struct.pack("<I", cmd)
+        self.emcore.write(0x38300004, data)        
+    def lcddata(self, data):
+        data = struct.pack("<I", data)
+        self.emcore.write(0x38300040, data)        
+
+if __name__ == "__main__":
+    try:
+        interface = Interface()
+        interface.emcore.write(0x38300000, struct.pack("<I", 0x41000c20))
+#        interface.emcore.write(0x38300000, struct.pack("<I", 0x41100db8))
+        interface.emcore.i2cwrite(0, 0xe6, 0x30, struct.pack("B", 200))
+        if len(sys.argv) > 1:
+            interface.lcdcmd(int(sys.argv[1], 16))
+            for i in range(2, len(sys.argv)):
+                interface.lcddata(int(sys.argv[1], 16))
+            exit(0)
+#        '''
+        print("Software Reset?")
+        raw_input()
+        interface.lcdcmd(0x01)
+        print("Sleep Out?")
+        raw_input()
+        interface.lcdcmd(0x11)
+        print("Display ON?")
+        raw_input()
+        interface.lcdcmd(0x29)
+        print("Power Control 1?")
+        raw_input()
+        interface.lcdcmd(0xc0)
+        print("Data: 00 (unknown)?")
+        raw_input()
+        interface.lcddata(0x00)
+        print("Power Control 2?")
+        raw_input()
+        interface.lcdcmd(0xc1)
+        print("Data: 03 (unknown)?")
+        raw_input()
+        interface.lcddata(0x03)
+        print("Power Control 3?")
+        raw_input()
+        interface.lcdcmd(0xc2)
+        print("Data: 34 (unknown)?")
+        raw_input()
+        interface.lcddata(0x34)
+        print("Power Control 4?")
+        raw_input()
+        interface.lcdcmd(0xc3)
+        print("Data: 72 (unknown)?")
+        raw_input()
+        interface.lcddata(0x72)
+        print("Data: 03 (unknown)?")
+        raw_input()
+        interface.lcddata(0x03)
+        print("Power Control 5?")
+        raw_input()
+        interface.lcdcmd(0xc4)
+        print("Data: 73 (unknown)?")
+        raw_input()
+        interface.lcddata(0x73)
+        print("Data: 03 (unknown)?")
+        raw_input()
+        interface.lcddata(0x03)
+        print("VCOM Control 1?")
+        raw_input()
+        interface.lcdcmd(0xc5)
+        print("Data: 3c (unknown)?")
+        raw_input()
+        interface.lcddata(0x3c)
+        print("Data: 3c (unknown)?")
+        raw_input()
+        interface.lcddata(0x3c)
+        print("Command: fe (unknown)?")
+        raw_input()
+        interface.lcdcmd(0xfe)
+        print("Data: 00 (unknown)?")
+        raw_input()
+        interface.lcddata(0x00)
+        print("Command: b1 (unknown)?")
+        raw_input()
+        interface.lcdcmd(0xb1)
+        print("Data: 6a (unknown)?")
+        raw_input()
+        interface.lcddata(0x6a)
+        print("Data: 15 (unknown)?")
+        raw_input()
+        interface.lcddata(0x15)
+        print("Command: b2 (unknown)?")
+        raw_input()
+        interface.lcdcmd(0xb2)
+        print("Data: 6a (unknown)?")
+        raw_input()
+        interface.lcddata(0x00)
+        print("Data: 15 (unknown)?")
+        raw_input()
+        interface.lcddata(0x15)
+        print("Command: b3 (unknown)?")
+        raw_input()
+        interface.lcdcmd(0xb3)
+        print("Data: 6a (unknown)?")
+        raw_input()
+        interface.lcddata(0x00)
+        print("Data: 15 (unknown)?")
+        raw_input()
+        interface.lcddata(0x15)
+        print("Command: b4 (unknown)?")
+        raw_input()
+        interface.lcdcmd(0xb4)
+        print("Data: 02 (unknown)?")
+        raw_input()
+        interface.lcddata(0x02)
+        print("Command: b6 (unknown)?")
+        raw_input()
+        interface.lcdcmd(0xb6)
+        print("Data: 12 (unknown)?")
+        raw_input()
+        interface.lcddata(0x12)
+        print("Data: 02 (unknown)?")
+        raw_input()
+        interface.lcddata(0x02)
+        print("Command: 35 (unknown)?")
+        raw_input()
+        interface.lcdcmd(0x35)
+        print("Data: 00 (unknown)?")
+        raw_input()
+        interface.lcddata(0x00)
+        print("Command: 26 (unknown)?")
+        raw_input()
+        interface.lcdcmd(0x26)
+        print("Data: 10 (unknown)?")
+        raw_input()
+        interface.lcddata(0x10)
+        print("Command: e0 (unknown)?")
+        raw_input()
+        interface.lcdcmd(0xe0)
+        print("Data: 77 (unknown)?")
+        raw_input()
+        interface.lcddata(0x77)
+        print("Data: 52 (unknown)?")
+        raw_input()
+        interface.lcddata(0x52)
+        print("Data: 76 (unknown)?")
+        raw_input()
+        interface.lcddata(0x76)
+        print("Data: 53 (unknown)?")
+        raw_input()
+        interface.lcddata(0x53)
+        print("Data: 03 (unknown)?")
+        raw_input()
+        interface.lcddata(0x03)
+        print("Data: 03 (unknown)?")
+        raw_input()
+        interface.lcddata(0x03)
+        print("Data: 57 (unknown)?")
+        raw_input()
+        interface.lcddata(0x57)
+        print("Data: 42 (unknown)?")
+        raw_input()
+        interface.lcddata(0x42)
+        print("Data: 10 (unknown)?")
+        raw_input()
+        interface.lcddata(0x10)
+        print("Data: 18 (unknown)?")
+        raw_input()
+        interface.lcddata(0x18)
+        print("Data: 09 (unknown)?")
+        raw_input()
+        interface.lcddata(0x09)
+        print("Command: e1 (unknown)?")
+        raw_input()
+        interface.lcdcmd(0xe1)
+        print("Data: 0d (unknown)?")
+        raw_input()
+        interface.lcddata(0x0d)
+        print("Data: 00 (unknown)?")
+        raw_input()
+        interface.lcddata(0x00)
+        print("Data: 23 (unknown)?")
+        raw_input()
+        interface.lcddata(0x23)
+        print("Data: 66 (unknown)?")
+        raw_input()
+        interface.lcddata(0x66)
+        print("Data: 0f (unknown)?")
+        raw_input()
+        interface.lcddata(0x0f)
+        print("Data: 15 (unknown)?")
+        raw_input()
+        interface.lcddata(0x15)
+        print("Data: 4d (unknown)?")
+        raw_input()
+        interface.lcddata(0x4d)
+        print("Data: 85 (unknown)?")
+        raw_input()
+        interface.lcddata(0x85)
+        print("Data: 08 (unknown)?")
+        raw_input()
+        interface.lcddata(0x08)
+        print("Data: 02 (unknown)?")
+        raw_input()
+        interface.lcddata(0x02)
+        print("Data: 10 (unknown)?")
+        raw_input()
+        interface.lcddata(0x10)
+        print("Command: e2 (unknown)?")
+        raw_input()
+        interface.lcdcmd(0xe2)
+        print("Data: 39 (unknown)?")
+        raw_input()
+        interface.lcddata(0x39)
+        print("Data: 60 (unknown)?")
+        raw_input()
+        interface.lcddata(0x60)
+        print("Data: 77 (unknown)?")
+        raw_input()
+        interface.lcddata(0x77)
+        print("Data: 05 (unknown)?")
+        raw_input()
+        interface.lcddata(0x05)
+        print("Data: 03 (unknown)?")
+        raw_input()
+        interface.lcddata(0x03)
+        print("Data: 07 (unknown)?")
+        raw_input()
+        interface.lcddata(0x07)
+        print("Data: 96 (unknown)?")
+        raw_input()
+        interface.lcddata(0x96)
+        print("Data: 64 (unknown)?")
+        raw_input()
+        interface.lcddata(0x64)
+        print("Data: 0d (unknown)?")
+        raw_input()
+        interface.lcddata(0x0d)
+        print("Data: 1a (unknown)?")
+        raw_input()
+        interface.lcddata(0x1a)
+        print("Data: 0a (unknown)?")
+        raw_input()
+        interface.lcddata(0x0a)
+        print("Command: e3 (unknown)?")
+        raw_input()
+        interface.lcdcmd(0xe3)
+        print("Data: 3f (unknown)?")
+        raw_input()
+        interface.lcddata(0x3f)
+        print("Data: 10 (unknown)?")
+        raw_input()
+        interface.lcddata(0x10)
+        print("Data: 16 (unknown)?")
+        raw_input()
+        interface.lcddata(0x16)
+        print("Data: 44 (unknown)?")
+        raw_input()
+        interface.lcddata(0x44)
+        print("Data: 0e (unknown)?")
+        raw_input()
+        interface.lcddata(0x0e)
+        print("Data: 04 (unknown)?")
+        raw_input()
+        interface.lcddata(0x04)
+        print("Data: 6c (unknown)?")
+        raw_input()
+        interface.lcddata(0x6c)
+        print("Data: 44 (unknown)?")
+        raw_input()
+        interface.lcddata(0x44)
+        print("Data: 04 (unknown)?")
+        raw_input()
+        interface.lcddata(0x04)
+        print("Data: 03 (unknown)?")
+        raw_input()
+        interface.lcddata(0x03)
+        print("Data: 0b (unknown)?")
+        raw_input()
+        interface.lcddata(0x0b)
+        print("Command: e4 (unknown)?")
+        raw_input()
+        interface.lcdcmd(0xe4)
+        print("Data: 00 (unknown)?")
+        raw_input()
+        interface.lcddata(0x00)
+        print("Data: 61 (unknown)?")
+        raw_input()
+        interface.lcddata(0x61)
+        print("Data: 77 (unknown)?")
+        raw_input()
+        interface.lcddata(0x77)
+        print("Data: 04 (unknown)?")
+        raw_input()
+        interface.lcddata(0x04)
+        print("Data: 02 (unknown)?")
+        raw_input()
+        interface.lcddata(0x02)
+        print("Data: 04 (unknown)?")
+        raw_input()
+        interface.lcddata(0x04)
+        print("Data: 72 (unknown)?")
+        raw_input()
+        interface.lcddata(0x72)
+        print("Data: 32 (unknown)?")
+        raw_input()
+        interface.lcddata(0x32)
+        print("Data: 09 (unknown)?")
+        raw_input()
+        interface.lcddata(0x09)
+        print("Data: 19 (unknown)?")
+        raw_input()
+        interface.lcddata(0x19)
+        print("Data: 06 (unknown)?")
+        raw_input()
+        interface.lcddata(0x06)
+        print("Command: e5 (unknown)?")
+        raw_input()
+        interface.lcdcmd(0xe5)
+        print("Data: 4f (unknown)?")
+        raw_input()
+        interface.lcddata(0x4f)
+        print("Data: 42 (unknown)?")
+        raw_input()
+        interface.lcddata(0x42)
+        print("Data: 27 (unknown)?")
+        raw_input()
+        interface.lcddata(0x27)
+        print("Data: 67 (unknown)?")
+        raw_input()
+        interface.lcddata(0x67)
+        print("Data: 0f (unknown)?")
+        raw_input()
+        interface.lcddata(0x0f)
+        print("Data: 03 (unknown)?")
+        raw_input()
+        interface.lcddata(0x03)
+        print("Data: 26 (unknown)?")
+        raw_input()
+        interface.lcddata(0x26)
+        print("Data: 33 (unknown)?")
+        raw_input()
+        interface.lcddata(0x33)
+        print("Data: 01 (unknown)?")
+        raw_input()
+        interface.lcddata(0x01)
+        print("Data: 03 (unknown)?")
+        raw_input()
+        interface.lcddata(0x03)
+        print("Data: 09 (unknown)?")
+        raw_input()
+        interface.lcddata(0x09)
+#        print("Command: 3a (unknown)?")
+#        raw_input()
+#        interface.lcdcmd(0x3a)
+#        print("Data: 66 (unknown)?")
+#        raw_input()
+#        interface.lcddata(0x66)
+        print("Command: 36 (unknown)?")
+        raw_input()
+        interface.lcdcmd(0x36)
+        print("Data: 00 (unknown)?")
+        raw_input()
+        interface.lcddata(0x00)
+        print("Sleep Out?")
+        raw_input()
+        interface.lcdcmd(0x11)
+        print("Display ON?")
+        raw_input()
+        interface.lcdcmd(0x29)
+#        '''
+        print("Write pattern?")
+        raw_input()
+        interface.emcore.write(0x38300000, struct.pack("<I", 0x41100db8))
+        interface.lcdcmd(0x2a)
+        interface.lcddata(64)
+        interface.lcddata(191)
+        interface.lcdcmd(0x2b)
+        interface.lcddata(8)
+        interface.lcddata(0x237)
+        interface.lcdcmd(0x2c)
+#        interface.emcore.write(0x38300000, struct.pack("<I", 0x41000c20))
+#        interface.lcdcmd(0x210)
+#        interface.lcddata(64)
+#        interface.lcdcmd(0x211)
+#        interface.lcddata(191)
+#        interface.lcdcmd(0x212)
+#        interface.lcddata(8)
+#        interface.lcdcmd(0x213)
+#        interface.lcddata(239)
+#        interface.lcdcmd(0x2c)
+#        interface.lcdcmd(0x200)
+#        interface.lcddata(64)
+#        interface.lcdcmd(0x201)
+#        interface.lcddata(8)
+#        interface.lcdcmd(0x202)
+        interface.emcore.write(0x38300000, struct.pack("<I", 0x41104eb8))
+        for r in range(8):
+            for y in range(32):
+                for x in range(32):
+                    interface.lcddata(1 << (r + 24))
+                for x in range(32):
+                    interface.lcddata(1 << (r + 16))
+                for x in range(32):
+                    interface.lcddata(1 << (r + 8))
+                for x in range(32):
+                    interface.lcddata(1 << r)
+        for y in range(32):
+            for x in range(32):
+                interface.lcddata(0xff000000)
+            for x in range(32):
+                interface.lcddata(0xff0000)
+            for x in range(32):
+                interface.lcddata(0xff00)
+            for x in range(32):
+                interface.lcddata(0xff)
+        interface.emcore.write(0x38300000, struct.pack("<I", 0x41100db8))
+        interface.lcdcmd(0x2a)
+        interface.lcddata(8)
+        interface.lcddata(63)
+        interface.lcdcmd(0x2b)
+        interface.lcddata(8)
+        interface.lcddata(0x237)
+        interface.lcdcmd(0x2c)
+#        interface.emcore.write(0x38300000, struct.pack("<I", 0x41000da8))
+#        interface.lcdcmd(0x210)
+#        interface.lcddata(8)
+#        interface.lcdcmd(0x211)
+#        interface.lcddata(63)
+#        interface.lcdcmd(0x212)
+#        interface.lcddata(8)
+#        interface.lcdcmd(0x213)
+#        interface.lcddata(239)
+#        interface.lcdcmd(0x2c)
+#        interface.lcdcmd(0x200)
+#        interface.lcddata(8)
+#        interface.lcdcmd(0x201)
+#        interface.lcddata(8)
+#        interface.lcdcmd(0x202)
+        interface.emcore.write(0x38300000, struct.pack("<I", 0x41104eb8))
+        for y in range(256):
+            for k in range(8):
+                interface.lcddata(y << 16)
+            for k in range(8):
+                interface.lcddata(y << 8)
+            for k in range(8):
+                interface.lcddata(y)
+            for k in range(8):
+                interface.lcddata((y << 8) | y)
+            for k in range(8):
+                interface.lcddata((y << 16) | y)
+            for k in range(8):
+                interface.lcddata((y << 16) | (y << 8))
+            for k in range(8):
+                interface.lcddata((y << 16) | (y << 8) | y)
+    except KeyboardInterrupt:
+        sys.exit()
\ No newline at end of file
Index: testapps/ceatatest/ceata.c
===================================================================
--- testapps/ceatatest/ceata.c	(revision 0)
+++ testapps/ceatatest/ceata.c	(revision 0)
@@ -0,0 +1,455 @@
+//
+//
+//    Copyright 2011 TheSeven
+//
+//
+//    This file is part of emCORE.
+//
+//    emCORE is free software: you can 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.
+//
+//    emCORE is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+//
+//    You should have received a copy of the GNU General Public License along
+//    with emCORE.  If not, see <http://www.gnu.org/licenses/>.
+//
+//
+
+
+#include "emcoreapp.h"
+#include "ceata.h"
+
+
+uint8_t ceata_taskfile[16] __attribute__((aligned(16)));
+uint16_t ata_identify_data[0x100];
+struct wakeup mmc_wakeup;
+struct wakeup mmc_comp_wakeup;
+
+
+int mmc_dsta_check_command_success(bool disable_crc)
+{
+    int rc = 0;
+    uint32_t dsta = SDCI_DSTA;
+    if (dsta & SDCI_DSTA_RESTOUTE) rc |= 1; 
+    if (dsta & SDCI_DSTA_RESENDE) rc |= 2;
+    if (dsta & SDCI_DSTA_RESINDE) rc |= 4;
+    if (!disable_crc)
+        if (dsta & SDCI_DSTA_RESCRCE)
+            rc |= 8;
+    if (rc) RET_ERR(rc);
+    return 0;
+}
+
+bool mmc_send_command(uint32_t cmd, uint32_t arg, uint32_t* result, int timeout)
+{
+    long starttime = USEC_TIMER;
+    while ((SDCI_STATE & SDCI_STATE_CMD_STATE_MASK) != SDCI_STATE_CMD_STATE_CMD_IDLE)
+    {
+        if (timeout_expired(starttime, timeout)) RET_ERR(0);
+        yield();
+    }
+    SDCI_STAC = SDCI_STAC_CLR_CMDEND | SDCI_STAC_CLR_BIT_3
+              | SDCI_STAC_CLR_RESEND | SDCI_STAC_CLR_DATEND
+              | SDCI_STAC_CLR_DAT_CRCEND | SDCI_STAC_CLR_CRC_STAEND
+              | SDCI_STAC_CLR_RESTOUTE | SDCI_STAC_CLR_RESENDE
+              | SDCI_STAC_CLR_RESINDE | SDCI_STAC_CLR_RESCRCE
+              | SDCI_STAC_CLR_WR_DATCRCE | SDCI_STAC_CLR_RD_DATCRCE
+              | SDCI_STAC_CLR_RD_DATENDE0 | SDCI_STAC_CLR_RD_DATENDE1
+              | SDCI_STAC_CLR_RD_DATENDE2 | SDCI_STAC_CLR_RD_DATENDE3
+              | SDCI_STAC_CLR_RD_DATENDE4 | SDCI_STAC_CLR_RD_DATENDE5
+              | SDCI_STAC_CLR_RD_DATENDE6 | SDCI_STAC_CLR_RD_DATENDE7;
+    SDCI_ARGU = arg;
+    SDCI_CMD = cmd;
+    if (!(SDCI_DSTA & SDCI_DSTA_CMDRDY)) RET_ERR(1);
+    SDCI_CMD = cmd | SDCI_CMD_CMDSTR;
+    sleep(200);
+    while (!(SDCI_DSTA & SDCI_DSTA_CMDEND))
+    {
+        if (timeout_expired(starttime, timeout)) RET_ERR(2);
+        yield();
+    }
+    if ((cmd & SDCI_CMD_RES_TYPE_MASK) != SDCI_CMD_RES_TYPE_NONE)
+    {
+        while (!(SDCI_DSTA & SDCI_DSTA_RESEND))
+        {
+            if (timeout_expired(starttime, timeout)) RET_ERR(3);
+            yield();
+        }
+        if (cmd & SDCI_CMD_RES_BUSY)
+            while (SDCI_DSTA & SDCI_DSTA_DAT_BUSY)
+            {
+                if (timeout_expired(starttime, CEATA_DAT_NONBUSY_TIMEOUT)) RET_ERR(4);
+                yield();
+            }
+    }
+    bool nocrc = (cmd & SDCI_CMD_RES_SIZE_MASK) == SDCI_CMD_RES_SIZE_136;
+    PASS_RC(mmc_dsta_check_command_success(nocrc), 3, 5);
+    if (result) *result = SDCI_RESP0;
+    return 0;
+}
+
+int mmc_get_card_status(uint32_t* result)
+{
+    return mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SEND_STATUS)
+                          | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1
+                          | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
+                            MMC_CMD_SEND_STATUS_RCA(CEATA_MMC_RCA), result, CEATA_COMMAND_TIMEOUT);
+}
+
+int mmc_init()
+{
+    PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_GO_IDLE_STATE)
+                           | SDCI_CMD_CMD_TYPE_BC | SDCI_CMD_RES_TYPE_NONE
+                           | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NID,
+                             0, NULL, CEATA_COMMAND_TIMEOUT), 3, 0);
+    long startusec = USEC_TIMER;
+    uint32_t result;
+    do
+    {
+        if (timeout_expired(startusec, CEATA_POWERUP_TIMEOUT)) RET_ERR(1);
+        sleep(1000);
+        PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SEND_OP_COND)
+                               | SDCI_CMD_CMD_TYPE_BCR | SDCI_CMD_RES_TYPE_R3
+                               | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NID,
+                                 MMC_CMD_SEND_OP_COND_OCR(MMC_OCR_270_360),
+                                 NULL, CEATA_COMMAND_TIMEOUT), 3, 2);
+        result = SDCI_RESP0;
+    }
+    while (!(result & MMC_OCR_POWER_UP_DONE));
+    PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_ALL_SEND_CID)
+                           | SDCI_CMD_CMD_TYPE_BCR | SDCI_CMD_RES_TYPE_R2
+                           | SDCI_CMD_RES_SIZE_136 | SDCI_CMD_NCR_NID_NID,
+                             0, NULL, CEATA_COMMAND_TIMEOUT), 3, 3);
+    PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SET_RELATIVE_ADDR)
+                           | SDCI_CMD_CMD_TYPE_BCR | SDCI_CMD_RES_TYPE_R1
+                           | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
+                             MMC_CMD_SET_RELATIVE_ADDR_RCA(CEATA_MMC_RCA),
+                             NULL, CEATA_COMMAND_TIMEOUT), 3, 4);
+    PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SELECT_CARD)
+                           | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1
+                           | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
+                             MMC_CMD_SELECT_CARD_RCA(CEATA_MMC_RCA),
+                             NULL, CEATA_COMMAND_TIMEOUT), 3, 5);
+    PASS_RC(mmc_get_card_status(&result), 3, 6);
+    if ((result & MMC_STATUS_CURRENT_STATE_MASK) != MMC_STATUS_CURRENT_STATE_TRAN) RET_ERR(7);
+    return 0;
+}
+
+int mmc_fastio_write(uint32_t addr, uint32_t data)
+{
+    return mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_FAST_IO)
+                          | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R4
+                          | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
+                            MMC_CMD_FAST_IO_RCA(CEATA_MMC_RCA) | MMC_CMD_FAST_IO_DIRECTION_WRITE
+                          | MMC_CMD_FAST_IO_ADDRESS(addr) | MMC_CMD_FAST_IO_DATA(data),
+                            NULL, CEATA_COMMAND_TIMEOUT);
+}
+
+int mmc_fastio_read(uint32_t addr, uint32_t* data)
+{
+    return mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_FAST_IO)
+                          | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R4
+                          | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
+                            MMC_CMD_FAST_IO_RCA(CEATA_MMC_RCA) | MMC_CMD_FAST_IO_DIRECTION_READ
+                          | MMC_CMD_FAST_IO_ADDRESS(addr), data, CEATA_COMMAND_TIMEOUT);
+}
+
+int ceata_soft_reset()
+{
+    PASS_RC(mmc_fastio_write(6, 4), 2, 0);
+    sleep(1000);
+    PASS_RC(mmc_fastio_write(6, 0), 2, 1);
+    sleep(10000);
+    long startusec = USEC_TIMER;
+    uint32_t status;
+    do
+    {
+        PASS_RC(mmc_fastio_read(0xf, &status), 2, 2);
+        if (timeout_expired(startusec, CEATA_POWERUP_TIMEOUT)) RET_ERR(3);
+        sleep(1000);
+    }
+    while (status & 0x80);
+    return 0;
+}
+
+int mmc_dsta_check_data_success()
+{
+    int rc = 0;
+    uint32_t dsta = SDCI_DSTA;
+    if (dsta & (SDCI_DSTA_WR_DATCRCE | SDCI_DSTA_RD_DATCRCE))
+    {
+        if (dsta & SDCI_DSTA_WR_DATCRCE) rc |= 1;
+        if (dsta & SDCI_DSTA_RD_DATCRCE) rc |= 2;
+        if ((dsta & SDCI_DSTA_WR_CRC_STATUS_MASK) == SDCI_DSTA_WR_CRC_STATUS_TXERR) rc |= 4;
+        else if ((dsta & SDCI_DSTA_WR_CRC_STATUS_MASK) == SDCI_DSTA_WR_CRC_STATUS_CARDERR) rc |= 8;
+    }
+    if (dsta & (SDCI_DSTA_RD_DATENDE0 | SDCI_DSTA_RD_DATENDE1 | SDCI_DSTA_RD_DATENDE2
+              | SDCI_DSTA_RD_DATENDE3 | SDCI_DSTA_RD_DATENDE4 | SDCI_DSTA_RD_DATENDE5
+              | SDCI_DSTA_RD_DATENDE6 | SDCI_DSTA_RD_DATENDE7))
+        rc |= 16;
+    if (rc) RET_ERR(rc);
+    return 0;
+}
+
+void mmc_discard_irq()
+{
+    SDCI_IRQ = SDCI_IRQ_DAT_DONE_INT | SDCI_IRQ_MASK_MASK_IOCARD_IRQ_INT
+             | SDCI_IRQ_MASK_MASK_READ_WAIT_INT;
+    wakeup_wait(&mmc_wakeup, TIMEOUT_NONE);
+}
+
+int ceata_read_multiple_register(uint32_t addr, void* dest, uint32_t size)
+{
+    if (size > 0x10) RET_ERR(0);
+    mmc_discard_irq();
+    SDCI_DMASIZE = size;
+    SDCI_DMACOUNT = 1;
+    SDCI_DMAADDR = dest;
+    SDCI_DCTRL = SDCI_DCTRL_TXFIFORST | SDCI_DCTRL_RXFIFORST;
+    PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_CEATA_RW_MULTIPLE_REG)
+                           | SDCI_CMD_CMD_TYPE_ADTC | SDCI_CMD_RES_TYPE_R1
+                           | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
+                             MMC_CMD_CEATA_RW_MULTIPLE_REG_DIRECTION_READ
+                           | MMC_CMD_CEATA_RW_MULTIPLE_REG_ADDRESS(addr & 0xfc)
+                           | MMC_CMD_CEATA_RW_MULTIPLE_REG_COUNT(size & 0xfc),
+                             NULL, CEATA_COMMAND_TIMEOUT), 2, 1);
+    long startusec = USEC_TIMER;
+    if (wakeup_wait(&mmc_wakeup, CEATA_COMMAND_TIMEOUT) == THREAD_TIMEOUT) RET_ERR(2);
+    invalidate_dcache();
+    PASS_RC(mmc_dsta_check_data_success(), 2, 3);
+    return 0;
+}
+
+int ceata_write_multiple_register(uint32_t addr, void* dest, uint32_t size)
+{
+    int i;
+    if (size > 0x10) RET_ERR(0);
+    mmc_discard_irq();
+    SDCI_DMASIZE = size;
+    SDCI_DMACOUNT = 0;
+    SDCI_DCTRL = SDCI_DCTRL_TXFIFORST | SDCI_DCTRL_RXFIFORST;
+    PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_CEATA_RW_MULTIPLE_REG)
+                           | SDCI_CMD_CMD_TYPE_ADTC | SDCI_CMD_CMD_RD_WR
+                           | SDCI_CMD_RES_BUSY | SDCI_CMD_RES_TYPE_R1
+                           | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
+                             MMC_CMD_CEATA_RW_MULTIPLE_REG_DIRECTION_WRITE
+                           | MMC_CMD_CEATA_RW_MULTIPLE_REG_ADDRESS(addr & 0xfc)
+                           | MMC_CMD_CEATA_RW_MULTIPLE_REG_COUNT(size & 0xfc),
+                             NULL, CEATA_COMMAND_TIMEOUT), 3, 1);
+    SDCI_DCTRL = SDCI_DCTRL_TRCONT_TX;
+    for (i = 0; i < size / 4; i++) SDCI_DATA = ((uint32_t*)dest)[i];
+    long startusec = USEC_TIMER;
+    if (wakeup_wait(&mmc_wakeup, CEATA_COMMAND_TIMEOUT) == THREAD_TIMEOUT) RET_ERR(2);
+    while ((SDCI_STATE & SDCI_STATE_DAT_STATE_MASK) != SDCI_STATE_DAT_STATE_IDLE)
+    {
+        if (timeout_expired(startusec, CEATA_COMMAND_TIMEOUT)) RET_ERR(3);
+        yield();
+    }
+    PASS_RC(mmc_dsta_check_data_success(), 3, 4);
+    return 0;
+}
+
+int ceata_init(int buswidth)
+{
+    uint32_t result;
+    PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SWITCH) | SDCI_CMD_RES_BUSY
+                           | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1 
+                           | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
+                             MMC_CMD_SWITCH_ACCESS_WRITE_BYTE
+                           | MMC_CMD_SWITCH_INDEX(MMC_CMD_SWITCH_FIELD_HS_TIMING)
+                           | MMC_CMD_SWITCH_VALUE(MMC_CMD_SWITCH_FIELD_HS_TIMING_HIGH_SPEED),
+                             &result, CEATA_COMMAND_TIMEOUT), 3, 0);
+    if (result & MMC_STATUS_SWITCH_ERROR) RET_ERR(1);
+    if (buswidth > 1)
+    {
+        int setting;
+        if (buswidth == 4) setting = MMC_CMD_SWITCH_FIELD_BUS_WIDTH_4BIT;
+        else if (buswidth == 8) setting = MMC_CMD_SWITCH_FIELD_BUS_WIDTH_8BIT;
+        else setting = MMC_CMD_SWITCH_FIELD_BUS_WIDTH_1BIT;
+        PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_SWITCH) | SDCI_CMD_RES_BUSY
+                               | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1
+                               | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
+                                 MMC_CMD_SWITCH_ACCESS_WRITE_BYTE
+                               | MMC_CMD_SWITCH_INDEX(MMC_CMD_SWITCH_FIELD_BUS_WIDTH)
+                               | MMC_CMD_SWITCH_VALUE(setting),
+                                 &result, CEATA_COMMAND_TIMEOUT), 3, 2);
+        if (result & MMC_STATUS_SWITCH_ERROR) RET_ERR(3);
+        if (buswidth == 4)
+            SDCI_CTRL = (SDCI_CTRL & ~SDCI_CTRL_BUS_WIDTH_MASK) | SDCI_CTRL_BUS_WIDTH_4BIT;
+        else if (buswidth == 8)
+            SDCI_CTRL = (SDCI_CTRL & ~SDCI_CTRL_BUS_WIDTH_MASK) | SDCI_CTRL_BUS_WIDTH_8BIT;
+    }
+    PASS_RC(ceata_soft_reset(), 3, 4);
+    PASS_RC(ceata_read_multiple_register(0, ceata_taskfile, 0x10), 3, 5);
+    if (ceata_taskfile[0xc] != 0xce || ceata_taskfile[0xd] != 0xaa) RET_ERR(6);
+    PASS_RC(mmc_fastio_write(6, 0), 3, 7);
+    return 0;
+}
+
+int ceata_check_error()
+{
+    uint32_t status, error;
+    PASS_RC(mmc_fastio_read(0xf, &status), 2, 0);
+    if (status & 1)
+    {
+        PASS_RC(mmc_fastio_read(0x9, &error), 2, 1);
+        RET_ERR((error << 2) | 2);
+    }
+    return 0;
+}
+
+int ceata_wait_idle()
+{
+    long startusec = USEC_TIMER;
+    while (true)
+    {
+        uint32_t status;
+        PASS_RC(mmc_fastio_read(0xf, &status), 1, 0);
+        if (!(status & 0x88)) return 0;
+        if (timeout_expired(startusec, CEATA_DAT_NONBUSY_TIMEOUT)) RET_ERR(1);
+        sleep(50000);
+    }
+}
+
+int ceata_cancel_command()
+{
+    *((uint32_t volatile*)0x3cf00200) = 0x9000e;
+    sleep(1);
+    *((uint32_t volatile*)0x3cf00200) = 0x9000f;
+    sleep(1);
+    *((uint32_t volatile*)0x3cf00200) = 0x90003;
+    sleep(1);
+    PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_STOP_TRANSMISSION)
+                           | SDCI_CMD_CMD_TYPE_AC | SDCI_CMD_RES_TYPE_R1 | SDCI_CMD_RES_BUSY
+                           | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
+                             0, NULL, CEATA_COMMAND_TIMEOUT), 1, 0);
+    PASS_RC(ceata_wait_idle(), 1, 1);
+    return 0;
+}
+
+int ceata_rw_multiple_block(bool dir_write, void* buf, uint32_t count, long timeout)
+{
+    mmc_discard_irq();
+    uint32_t responsetype;
+    uint32_t cmdtype;
+    uint32_t direction;
+    if (dir_write)
+    {
+        clean_dcache();
+        cmdtype = SDCI_CMD_CMD_TYPE_ADTC | SDCI_CMD_CMD_RD_WR;
+        responsetype = SDCI_CMD_RES_TYPE_R1 | SDCI_CMD_RES_BUSY;
+        direction = MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_DIRECTION_WRITE;
+    }
+    else
+    {
+        cmdtype = SDCI_CMD_CMD_TYPE_ADTC;
+        responsetype = SDCI_CMD_RES_TYPE_R1;
+        direction = MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_DIRECTION_READ;
+    }
+    SDCI_DMASIZE = 0x200;
+    SDCI_DMAADDR = buf;
+    SDCI_DMACOUNT = count;
+    SDCI_DCTRL = SDCI_DCTRL_TXFIFORST | SDCI_DCTRL_RXFIFORST;
+    PASS_RC(mmc_send_command(SDCI_CMD_CMD_NUM(MMC_CMD_CEATA_RW_MULTIPLE_BLOCK)
+                           | SDCI_CMD_CMD_TYPE_ADTC | cmdtype | responsetype
+                           | SDCI_CMD_RES_SIZE_48 | SDCI_CMD_NCR_NID_NCR,
+                             direction | MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_COUNT(count),
+                             NULL, CEATA_COMMAND_TIMEOUT), 4, 0);
+    if (dir_write) SDCI_DCTRL = SDCI_DCTRL_TRCONT_TX;
+    if (wakeup_wait(&mmc_wakeup, timeout) == THREAD_TIMEOUT)
+    {
+        PASS_RC(ceata_cancel_command(), 4, 1);
+        RET_ERR(2);
+    }
+    if (!dir_write) invalidate_dcache();
+    PASS_RC(mmc_dsta_check_data_success(), 4, 3);
+    if (wakeup_wait(&mmc_comp_wakeup, timeout) == THREAD_TIMEOUT)
+    {
+        PASS_RC(ceata_cancel_command(), 4, 4);
+        RET_ERR(4);
+    }
+    PASS_RC(ceata_check_error(), 4, 5);
+    return 0;
+}
+
+int ceata_identify(uint16_t* buf)
+{
+    int i;
+    memset(ceata_taskfile, 0, 16);
+    ceata_taskfile[0xf] = 0xec;
+    PASS_RC(ceata_wait_idle(), 2, 0);
+    PASS_RC(ceata_write_multiple_register(0, ceata_taskfile, 16), 2, 1);
+    PASS_RC(ceata_rw_multiple_block(false, buf, 1, CEATA_COMMAND_TIMEOUT), 2, 2);
+    return 0;
+}
+
+int ceata_rw_sectors(bool do_write, uint64_t sector, uint32_t count, void* buf)
+{
+    sector <<= 3;
+    count <<= 3;
+    memset(ceata_taskfile, 0, 16);
+    ceata_taskfile[0x2] = count >> 8;
+    ceata_taskfile[0x3] = sector >> 24;
+    ceata_taskfile[0x4] = sector >> 32;
+    ceata_taskfile[0x5] = sector >> 40;
+    ceata_taskfile[0xa] = count;
+    ceata_taskfile[0xb] = sector;
+    ceata_taskfile[0xc] = sector >> 8;
+    ceata_taskfile[0xd] = sector >> 16;
+    ceata_taskfile[0xf] = do_write ? 0x35 : 0x25;
+    PASS_RC(ceata_wait_idle(), 2, 0);
+    PASS_RC(ceata_write_multiple_register(0, ceata_taskfile, 16), 2, 1);
+    PASS_RC(ceata_rw_multiple_block(do_write, buf, count, CEATA_COMMAND_TIMEOUT), 2, 2);
+    return 0;
+}
+
+int hdd_init()
+{
+    int i;
+    i2c_sendbyte(0, 0xe6, 0x1b, 1);
+    clockgate_enable(9, true);
+    wakeup_init(&mmc_wakeup);
+    wakeup_init(&mmc_comp_wakeup);
+    *((uint32_t volatile*)0x3cf00100) = 0x33333333;
+    *((uint32_t volatile*)0x3cf00120) = ((*((uint32_t volatile*)0x3cf00120)) & ~0xff) | 0x33;
+    *((uint32_t volatile*)0x3cf00160) |= 0xf;
+    *((uint32_t volatile*)0x38a00000) = 0;
+    *((uint32_t volatile*)0x38700000) = 0;
+    SDCI_RESET = 0xa5;
+    sleep(1000);
+    if (SDCI_CTRL) return 0;
+    *((uint32_t volatile*)0x3cf00380) = 0;
+    *((uint32_t volatile*)0x3cf0010c) = 0xff;
+    SDCI_CTRL = SDCI_CTRL_SDCIEN | SDCI_CTRL_CLK_SEL_SDCLK | SDCI_CTRL_BIT_8 | SDCI_CTRL_BIT_14;
+    SDCI_CDIV = SDCI_CDIV_CLKDIV(260);
+    *((uint32_t volatile*)0x3cf00200) = 0xb000f;
+    SDCI_IRQ_MASK = SDCI_IRQ_MASK_MASK_DAT_DONE_INT | SDCI_IRQ_MASK_MASK_IOCARD_IRQ_INT;
+    PASS_RC(mmc_init(), 3, 0);
+    SDCI_CDIV = SDCI_CDIV_CLKDIV(4);
+    sleep(100000);
+    PASS_RC(ceata_init(8), 3, 1);
+    PASS_RC(ceata_identify(ata_identify_data), 3, 2);
+    void* buffer = memalign(0x10, 0x1000);
+    for (i = 0; i < 2048; i++) ((uint16_t*)buffer)[i] = i;
+    PASS_RC(ceata_rw_sectors(true, 0, 1, buffer), 3, 3);
+    cprintf(3, "Buffer 1 at 0x%08X\n", buffer);
+    void* buffer2 = memalign(0x10, 0x1000);
+    PASS_RC(ceata_rw_sectors(false, 0, 1, buffer2), 3, 4);
+    cprintf(3, "Buffer 2 at 0x%08X\n", buffer2);
+    free(buffer2);
+    free(buffer);
+    return 0;
+}
+
+void INT_MMC()
+{
+    uint32_t irq = SDCI_IRQ;
+    if (irq & SDCI_IRQ_DAT_DONE_INT) wakeup_signal(&mmc_wakeup);
+    if (irq & SDCI_IRQ_IOCARD_IRQ_INT) wakeup_signal(&mmc_comp_wakeup);
+    SDCI_IRQ = irq;
+}
Index: testapps/ceatatest/ceata.h
===================================================================
--- testapps/ceatatest/ceata.h	(revision 0)
+++ testapps/ceatatest/ceata.h	(revision 0)
@@ -0,0 +1,461 @@
+#define debug_printf(msg, args...) cprintf(3, msg, ##args)
+#define timeout_expired(start, timeout) TIMEOUT_EXPIRED(start, timeout)
+
+#define SDCI_REG(x) (*((uint32_t volatile*)(0x38b00000 + (x))))
+
+#define SDCI_CTRL SDCI_REG(0x00)
+#define SDCI_DCTRL SDCI_REG(0x04)
+#define SDCI_CMD SDCI_REG(0x08)
+#define SDCI_ARGU SDCI_REG(0x0c)
+#define SDCI_STATE SDCI_REG(0x10)
+#define SDCI_STAC SDCI_REG(0x14)
+#define SDCI_DSTA SDCI_REG(0x18)
+#define SDCI_FSTA SDCI_REG(0x1c)
+#define SDCI_RESP0 SDCI_REG(0x20)
+#define SDCI_RESP1 SDCI_REG(0x24)
+#define SDCI_RESP2 SDCI_REG(0x28)
+#define SDCI_RESP3 SDCI_REG(0x2c)
+#define SDCI_CDIV SDCI_REG(0x30)
+#define SDCI_SDIO_CSR SDCI_REG(0x34)
+#define SDCI_IRQ SDCI_REG(0x38)
+#define SDCI_IRQ_MASK SDCI_REG(0x3c)
+#define SDCI_DATA SDCI_REG(0x40)
+#define SDCI_DMAADDR SDCI_REG(0x44)
+#define SDCI_DMASIZE SDCI_REG(0x48)
+#define SDCI_DMACOUNT SDCI_REG(0x4c)
+#define SDCI_RESET SDCI_REG(0x6c)
+
+#define SDCI_CTRL_SDCIEN BIT(0)
+#define SDCI_CTRL_CARD_TYPE_MASK BIT(1)
+#define SDCI_CTRL_CARD_TYPE_SD 0
+#define SDCI_CTRL_CARD_TYPE_MMC BIT(1)
+#define SDCI_CTRL_BUS_WIDTH_MASK BITRANGE(2, 3)
+#define SDCI_CTRL_BUS_WIDTH_1BIT 0
+#define SDCI_CTRL_BUS_WIDTH_4BIT BIT(2)
+#define SDCI_CTRL_BUS_WIDTH_8BIT BIT(3)
+#define SDCI_CTRL_DMA_EN BIT(4)
+#define SDCI_CTRL_L_ENDIAN BIT(5)
+#define SDCI_CTRL_DMA_REQ_CON_MASK BIT(6)
+#define SDCI_CTRL_DMA_REQ_CON_NEMPTY 0
+#define SDCI_CTRL_DMA_REQ_CON_FULL BIT(6)
+#define SDCI_CTRL_CLK_SEL_MASK BIT(7)
+#define SDCI_CTRL_CLK_SEL_PCLK 0
+#define SDCI_CTRL_CLK_SEL_SDCLK BIT(7)
+#define SDCI_CTRL_BIT_8 BIT(8)
+#define SDCI_CTRL_BIT_14 BIT(14)
+
+#define SDCI_DCTRL_TXFIFORST BIT(0)
+#define SDCI_DCTRL_RXFIFORST BIT(1)
+#define SDCI_DCTRL_TRCONT_MASK BITRANGE(4, 5)
+#define SDCI_DCTRL_TRCONT_TX BIT(4)
+#define SDCI_DCTRL_BUS_TEST_MASK BITRANGE(6, 7)
+#define SDCI_DCTRL_BUS_TEST_TX BIT(6)
+#define SDCI_DCTRL_BUS_TEST_RX BIT(7)
+
+#define SDCI_CDIV_CLKDIV_MASK BITRANGE(0, 7)
+#define SDCI_CDIV_CLKDIV(x) ((x) >> 1)
+#define SDCI_CDIV_CLKDIV_2 BIT(0)
+#define SDCI_CDIV_CLKDIV_4 BIT(1)
+#define SDCI_CDIV_CLKDIV_8 BIT(2)
+#define SDCI_CDIV_CLKDIV_16 BIT(3)
+#define SDCI_CDIV_CLKDIV_32 BIT(4)
+#define SDCI_CDIV_CLKDIV_64 BIT(5)
+#define SDCI_CDIV_CLKDIV_128 BIT(6)
+#define SDCI_CDIV_CLKDIV_256 BIT(7)
+
+#define SDCI_CMD_CMD_NUM_MASK BITRANGE(0, 5)
+#define SDCI_CMD_CMD_NUM_SHIFT 0
+#define SDCI_CMD_CMD_NUM(x) (x)
+#define SDCI_CMD_CMD_TYPE_MASK BITRANGE(6, 7)
+#define SDCI_CMD_CMD_TYPE_BC 0
+#define SDCI_CMD_CMD_TYPE_BCR BIT(6)
+#define SDCI_CMD_CMD_TYPE_AC BIT(7)
+#define SDCI_CMD_CMD_TYPE_ADTC (BIT(6) | BIT(7))
+#define SDCI_CMD_CMD_RD_WR BIT(8)
+#define SDCI_CMD_RES_TYPE_MASK BITRANGE(16, 18)
+#define SDCI_CMD_RES_TYPE_NONE 0
+#define SDCI_CMD_RES_TYPE_R1 BIT(16)
+#define SDCI_CMD_RES_TYPE_R2 BIT(17)
+#define SDCI_CMD_RES_TYPE_R3 (BIT(16) | BIT(17))
+#define SDCI_CMD_RES_TYPE_R4 BIT(18)
+#define SDCI_CMD_RES_TYPE_R5 (BIT(16) | BIT(18))
+#define SDCI_CMD_RES_TYPE_R6 (BIT(17) | BIT(18))
+#define SDCI_CMD_RES_BUSY BIT(19)
+#define SDCI_CMD_RES_SIZE_MASK BIT(20)
+#define SDCI_CMD_RES_SIZE_48 0
+#define SDCI_CMD_RES_SIZE_136 BIT(20)
+#define SDCI_CMD_NCR_NID_MASK BIT(21)
+#define SDCI_CMD_NCR_NID_NCR 0
+#define SDCI_CMD_NCR_NID_NID BIT(21)
+#define SDCI_CMD_CMDSTR BIT(31)
+
+#define SDCI_STATE_DAT_STATE_MASK BITRANGE(0, 3)
+#define SDCI_STATE_DAT_STATE_IDLE 0
+#define SDCI_STATE_DAT_STATE_DAT_RCV BIT(0)
+#define SDCI_STATE_DAT_STATE_CRC_RCV BIT(1)
+#define SDCI_STATE_DAT_STATE_DAT_END (BIT(0) | BIT(1))
+#define SDCI_STATE_DAT_STATE_DAT_SET BIT(2)
+#define SDCI_STATE_DAT_STATE_DAT_OUT (BIT(0) | BIT(2))
+#define SDCI_STATE_DAT_STATE_CRC_TIME (BIT(1) | BIT(2))
+#define SDCI_STATE_DAT_STATE_CRC_OUT (BIT(0) | BIT(1) | BIT(2))
+#define SDCI_STATE_DAT_STATE_ENDB_OUT BIT(3)
+#define SDCI_STATE_DAT_STATE_ENDB_STOD (BIT(0) | BIT(3))
+#define SDCI_STATE_DAT_STATE_DAT_CRCR (BIT(1) | BIT(3))
+#define SDCI_STATE_DAT_STATE_CARD_PRG (BIT(0) | BIT(1) | BIT(3))
+#define SDCI_STATE_DAT_STATE_DAT_BUSY (BIT(2) | BIT(3))
+#define SDCI_STATE_CMD_STATE_MASK (BIT(4) | BIT(5) | BIT(6))
+#define SDCI_STATE_CMD_STATE_CMD_IDLE 0
+#define SDCI_STATE_CMD_STATE_CMD_CMDO BIT(4)
+#define SDCI_STATE_CMD_STATE_CMD_CRCO BIT(5)
+#define SDCI_STATE_CMD_STATE_CMD_TOUT (BIT(4) | BIT(5))
+#define SDCI_STATE_CMD_STATE_CMD_RESR BIT(6)
+#define SDCI_STATE_CMD_STATE_CMD_INTV (BIT(4) | BIT(6))
+
+#define SDCI_STAC_CLR_CMDEND BIT(2)
+#define SDCI_STAC_CLR_BIT_3 BIT(3)
+#define SDCI_STAC_CLR_RESEND BIT(4)
+#define SDCI_STAC_CLR_DATEND BIT(6)
+#define SDCI_STAC_CLR_DAT_CRCEND BIT(7)
+#define SDCI_STAC_CLR_CRC_STAEND BIT(8)
+#define SDCI_STAC_CLR_RESTOUTE BIT(15)
+#define SDCI_STAC_CLR_RESENDE BIT(16)
+#define SDCI_STAC_CLR_RESINDE BIT(17)
+#define SDCI_STAC_CLR_RESCRCE BIT(18)
+#define SDCI_STAC_CLR_WR_DATCRCE BIT(22)
+#define SDCI_STAC_CLR_RD_DATCRCE BIT(23)
+#define SDCI_STAC_CLR_RD_DATENDE0 BIT(24)
+#define SDCI_STAC_CLR_RD_DATENDE1 BIT(25)
+#define SDCI_STAC_CLR_RD_DATENDE2 BIT(26)
+#define SDCI_STAC_CLR_RD_DATENDE3 BIT(27)
+#define SDCI_STAC_CLR_RD_DATENDE4 BIT(28)
+#define SDCI_STAC_CLR_RD_DATENDE5 BIT(29)
+#define SDCI_STAC_CLR_RD_DATENDE6 BIT(30)
+#define SDCI_STAC_CLR_RD_DATENDE7 BIT(31)
+
+#define SDCI_DSTA_CMDRDY BIT(0)
+#define SDCI_DSTA_CMDPRO BIT(1)
+#define SDCI_DSTA_CMDEND BIT(2)
+#define SDCI_DSTA_RESPRO BIT(3)
+#define SDCI_DSTA_RESEND BIT(4)
+#define SDCI_DSTA_DATPRO BIT(5)
+#define SDCI_DSTA_DATEND BIT(6)
+#define SDCI_DSTA_DAT_CRCEND BIT(7)
+#define SDCI_DSTA_CRC_STAEND BIT(8)
+#define SDCI_DSTA_DAT_BUSY BIT(9)
+#define SDCI_DSTA_SDCLK_HOLD BIT(12)
+#define SDCI_DSTA_DAT0_STATUS BIT(13)
+#define SDCI_DSTA_WP_DECT_INPUT BIT(14)
+#define SDCI_DSTA_RESTOUTE BIT(15)
+#define SDCI_DSTA_RESENDE BIT(16)
+#define SDCI_DSTA_RESINDE BIT(17)
+#define SDCI_DSTA_RESCRCE BIT(18)
+#define SDCI_DSTA_WR_CRC_STATUS_MASK BITRANGE(19, 21)
+#define SDCI_DSTA_WR_CRC_STATUS_OK BIT(20)
+#define SDCI_DSTA_WR_CRC_STATUS_TXERR (BIT(19) | BIT(21))
+#define SDCI_DSTA_WR_CRC_STATUS_CARDERR (BIT(19) | BIT(20) | BIT(21))
+#define SDCI_DSTA_WR_DATCRCE BIT(22)
+#define SDCI_DSTA_RD_DATCRCE BIT(23)
+#define SDCI_DSTA_RD_DATENDE0 BIT(24)
+#define SDCI_DSTA_RD_DATENDE1 BIT(25)
+#define SDCI_DSTA_RD_DATENDE2 BIT(26)
+#define SDCI_DSTA_RD_DATENDE3 BIT(27)
+#define SDCI_DSTA_RD_DATENDE4 BIT(28)
+#define SDCI_DSTA_RD_DATENDE5 BIT(29)
+#define SDCI_DSTA_RD_DATENDE6 BIT(30)
+#define SDCI_DSTA_RD_DATENDE7 BIT(31)
+
+#define SDCI_FSTA_RX_FIFO_EMPTY BIT(0)
+#define SDCI_FSTA_RX_FIFO_FULL BIT(1)
+#define SDCI_FSTA_TX_FIFO_EMPTY BIT(2)
+#define SDCI_FSTA_TX_FIFO_FULL BIT(3)
+
+#define SDCI_SDIO_CSR_SDIO_RW_EN BIT(0)
+#define SDCI_SDIO_CSR_SDIO_INT_EN BIT(1)
+#define SDCI_SDIO_CSR_SDIO_RW_REQ BIT(2)
+#define SDCI_SDIO_CSR_SDIO_RW_STOP BIT(3)
+#define SDCI_SDIO_CSR_SDIO_INT_PERIOD_MASK BIT(4)
+#define SDCI_SDIO_CSR_SDIO_INT_PERIOD_MORE 0
+#define SDCI_SDIO_CSR_SDIO_INT_PERIOD_XACT BIT(4)
+
+#define SDCI_IRQ_DAT_DONE_INT BIT(0)
+#define SDCI_IRQ_IOCARD_IRQ_INT BIT(1)
+#define SDCI_IRQ_READ_WAIT_INT BIT(2)
+
+#define SDCI_IRQ_MASK_MASK_DAT_DONE_INT BIT(0)
+#define SDCI_IRQ_MASK_MASK_IOCARD_IRQ_INT BIT(1)
+#define SDCI_IRQ_MASK_MASK_READ_WAIT_INT BIT(2)
+
+#define MMC_CMD_GO_IDLE_STATE 0
+#define MMC_CMD_SEND_OP_COND 1
+#define MMC_CMD_ALL_SEND_CID 2
+#define MMC_CMD_SET_RELATIVE_ADDR 3
+#define MMC_CMD_SET_DSR 4
+#define MMC_CMD_SLEEP_AWAKE 5
+#define MMC_CMD_SWITCH 6
+#define MMC_CMD_SELECT_CARD 7
+#define MMC_CMD_SEND_EXT_CSD 8
+#define MMC_CMD_SEND_CSD 9
+#define MMC_CMD_SEND_CID 10
+#define MMC_CMD_READ_DAT_UNTIL_STOP 11
+#define MMC_CMD_STOP_TRANSMISSION 12
+#define MMC_CMD_SEND_STATUS 13
+#define MMC_CMD_BUSTEST_R 14
+#define MMC_CMD_GO_INAVTIVE_STATE 15
+#define MMC_CMD_SET_BLOCKLEN 16
+#define MMC_CMD_READ_SINGLE_BLOCK 17
+#define MMC_CMD_READ_MULTIPLE_BLOCK 18
+#define MMC_CMD_BUSTEST_W 19
+#define MMC_CMD_WRITE_DAT_UNTIL_STOP 20
+#define MMC_CMD_SET_BLOCK_COUNT 23
+#define MMC_CMD_WRITE_BLOCK 24
+#define MMC_CMD_WRITE_MULTIPLE_BLOCK 25
+#define MMC_CMD_PROGRAM_CID 26
+#define MMC_CMD_PROGRAM_CSD 27
+#define MMC_CMD_SET_WRITE_PROT 28
+#define MMC_CMD_CLR_WRITE_PROT 29
+#define MMC_CMD_SEND_WRITE_PROT 30
+#define MMC_CMD_ERASE_GROUP_START 35
+#define MMC_CMD_ERASE_GROUP_END 36
+#define MMC_CMD_ERASE 38
+#define MMC_CMD_FAST_IO 39
+#define MMC_CMD_GO_IRQ_STATE 40
+#define MMC_CMD_LOCK_UNLOCK 42
+#define MMC_CMD_APP_CMD 55
+#define MMC_CMD_GEN_CMD 56
+#define MMC_CMD_CEATA_RW_MULTIPLE_REG 60
+#define MMC_CMD_CEATA_RW_MULTIPLE_BLOCK 61
+
+#define MMC_CMD_SEND_OP_COND_OCR_MASK BITRANGE(0, 31)
+#define MMC_CMD_SEND_OP_COND_OCR_SHIFT 0
+#define MMC_CMD_SEND_OP_COND_OCR(x) (x)
+
+#define MMC_CMD_SET_RELATIVE_ADDR_RCA_MASK BITRANGE(16, 31)
+#define MMC_CMD_SET_RELATIVE_ADDR_RCA_SHIFT 16
+#define MMC_CMD_SET_RELATIVE_ADDR_RCA(x) ((x) << 16)
+
+#define MMC_CMD_SET_DSR_DSR_MASK BITRANGE(16, 31)
+#define MMC_CMD_SET_DSR_DSR_SHIFT 16
+#define MMC_CMD_SET_DSR_DSR(x) ((x) << 16)
+
+#define MMC_CMD_SLEEP_AWAKE_SLEEP_AWAKE_MASK BIT(15)
+#define MMC_CMD_SLEEP_AWAKE_SLEEP_AWAKE_AWAKE 0
+#define MMC_CMD_SLEEP_AWAKE_SLEEP_AWAKE_SLEEP BIT(15)
+#define MMC_CMD_SLEEP_AWAKE_RCA_MASK BITRANGE(16, 31)
+#define MMC_CMD_SLEEP_AWAKE_RCA_SHIFT 16
+#define MMC_CMD_SLEEP_AWAKE_RCA(x) ((x) << 16)
+
+#define MMC_CMD_SWITCH_ACCESS_MASK BITRANGE(24, 25);
+#define MMC_CMD_SWITCH_ACCESS_CMDSET 0
+#define MMC_CMD_SWITCH_ACCESS_SET_BITS BIT(24)
+#define MMC_CMD_SWITCH_ACCESS_CLEAR_BITS BIT(25)
+#define MMC_CMD_SWITCH_ACCESS_WRITE_BYTE (BIT(24) | BIT(25))
+#define MMC_CMD_SWTICH_INDEX_MASK BITRANGE(16, 23);
+#define MMC_CMD_SWITCH_INDEX_SHIFT 16
+#define MMC_CMD_SWITCH_INDEX(x) ((x) << 16)
+#define MMC_CMD_SWTICH_VALUE_MASK BITRANGE(8, 15);
+#define MMC_CMD_SWITCH_VALUE_SHIFT 8
+#define MMC_CMD_SWITCH_VALUE(x) ((x) << 8)
+#define MMC_CMD_SWTICH_CMDSET_MASK BITRANGE(0, 2);
+#define MMC_CMD_SWITCH_CMDSET_STANDARD_MMC 0
+
+#define MMC_CMD_SELECT_CARD_RCA_MASK BITRANGE(16, 31)
+#define MMC_CMD_SELECT_CARD_RCA_SHIFT 16
+#define MMC_CMD_SELECT_CARD_RCA(x) ((x) << 16)
+
+#define MMC_CMD_SEND_CSD_RCA_MASK BITRANGE(16, 31)
+#define MMC_CMD_SEND_CSD_RCA_SHIFT 16
+#define MMC_CMD_SEND_CSD_RCA(x) ((x) << 16)
+
+#define MMC_CMD_SEND_CID_RCA_MASK BITRANGE(16, 31)
+#define MMC_CMD_SEND_CID_RCA_SHIFT 16
+#define MMC_CMD_SEND_CID_RCA(x) ((x) << 16)
+
+#define MMC_CMD_READ_DAT_UNTIL_STOP_ADDRESS_MASK BITRANGE(0, 31)
+#define MMC_CMD_READ_DAT_UNTIL_STOP_ADDRESS_SHIFT 0
+#define MMC_CMD_READ_DAT_UNTIL_STOP_ADDRESS(x) (x)
+
+#define MMC_CMD_SEND_STATUS_RCA_MASK BITRANGE(16, 31)
+#define MMC_CMD_SEND_STATUS_RCA_SHIFT 16
+#define MMC_CMD_SEND_STATUS_RCA(x) ((x) << 16)
+
+#define MMC_CMD_GO_INACTIVE_STATE_RCA_MASK BITRANGE(16, 31)
+#define MMC_CMD_GO_INACTIVE_STATE_RCA_SHIFT 16
+#define MMC_CMD_GO_INACTIVE_STATE_RCA(x) ((x) << 16)
+
+#define MMC_CMD_SET_BLOCKLEN_LENGTH_MASK BITRANGE(0, 31)
+#define MMC_CMD_SET_BLOCKLEN_LENGTH_SHIFT 0
+#define MMC_CMD_SET_BLOCKLEN_LENGTH(x) (x)
+
+#define MMC_CMD_READ_SINGLE_BLOCK_ADDRESS_MASK BITRANGE(0, 31)
+#define MMC_CMD_READ_SINGLE_BLOCK_ADDRESS_SHIFT 0
+#define MMC_CMD_READ_SINGLE_BLOCK_ADDRESS(x) (x)
+
+#define MMC_CMD_READ_MULTIPLE_BLOCK_ADDRESS_MASK BITRANGE(0, 31)
+#define MMC_CMD_READ_MULTIPLE_BLOCK_ADDRESS_SHIFT 0
+#define MMC_CMD_READ_MULTIPLE_BLOCK_ADDRESS(x) (x)
+
+#define MMC_CMD_WRITE_DAT_UNTIL_STOP_ADDRESS_MASK BITRANGE(0, 31)
+#define MMC_CMD_WRITE_DAT_UNTIL_STOP_ADDRESS_SHIFT 0
+#define MMC_CMD_WRITE_DAT_UNTIL_STOP_ADDRESS(x) (x)
+
+#define MMC_CMD_SET_BLOCK_COUNT_RELIABLE BIT(31)
+#define MMC_CMD_SET_BLOCK_COUNT_COUNT_MASK BITRANGE(0, 15)
+#define MMC_CMD_SET_BLOCK_COUNT_COUNT_SHIFT 0
+#define MMC_CMD_SET_BLOCK_COUNT_COUNT(x) (x)
+
+#define MMC_CMD_WRITE_BLOCK_ADDRESS_MASK BITRANGE(0, 31)
+#define MMC_CMD_WRITE_BLOCK_ADDRESS_SHIFT 0
+#define MMC_CMD_WRITE_BLOCK_ADDRESS(x) (x)
+
+#define MMC_CMD_WRITE_MULTIPLE_BLOCK_ADDRESS_MASK BITRANGE(0, 31)
+#define MMC_CMD_WRITE_MULTIPLE_BLOCK_ADDRESS_SHIFT 0
+#define MMC_CMD_WRITE_MULTIPLE_BLOCK_ADDRESS(x) (x)
+
+#define MMC_CMD_SET_WRITE_PROT_ADDRESS_MASK BITRANGE(0, 31)
+#define MMC_CMD_SET_WRITE_PROT_ADDRESS_SHIFT 0
+#define MMC_CMD_SET_WRITE_PROT_ADDRESS(x) (x)
+
+#define MMC_CMD_CLR_WRITE_PROT_ADDRESS_MASK BITRANGE(0, 31)
+#define MMC_CMD_CLR_WRITE_PROT_ADDRESS_SHIFT 0
+#define MMC_CMD_CLR_WRITE_PROT_ADDRESS(x) (x)
+
+#define MMC_CMD_SEND_WRITE_PROT_ADDRESS_MASK BITRANGE(0, 31)
+#define MMC_CMD_SEND_WRITE_PROT_ADDRESS_SHIFT 0
+#define MMC_CMD_SEND_WRITE_PROT_ADDRESS(x) (x)
+
+#define MMC_CMD_ERASE_GROUP_START_ADDRESS_MASK BITRANGE(0, 31)
+#define MMC_CMD_ERASE_GROUP_START_ADDRESS_SHIFT 0
+#define MMC_CMD_ERASE_GROUP_START_ADDRESS(x) (x)
+
+#define MMC_CMD_ERASE_GROUP_END_ADDRESS_MASK BITRANGE(0, 31)
+#define MMC_CMD_ERASE_GROUP_END_ADDRESS_SHIFT 0
+#define MMC_CMD_ERASE_GROUP_END_ADDRESS(x) (x)
+
+#define MMC_CMD_FAST_IO_RCA_MASK BITRANGE(16, 31)
+#define MMC_CMD_FAST_IO_RCA_SHIFT 16
+#define MMC_CMD_FAST_IO_RCA(x) ((x) << 16)
+#define MMC_CMD_FAST_IO_DIRECTION_MASK BIT(15)
+#define MMC_CMD_FAST_IO_DIRECTION_READ 0
+#define MMC_CMD_FAST_IO_DIRECTION_WRITE BIT(15)
+#define MMC_CMD_FAST_IO_ADDRESS_MASK BITRANGE(8, 14)
+#define MMC_CMD_FAST_IO_ADDRESS_SHIFT 8
+#define MMC_CMD_FAST_IO_ADDRESS(x) ((x) << 8)
+#define MMC_CMD_FAST_IO_DATA_MASK BITRANGE(0, 7)
+#define MMC_CMD_FAST_IO_DATA_SHIFT 0
+#define MMC_CMD_FAST_IO_DATA(x) (x)
+
+#define MMC_CMD_APP_CMD_RCA_MASK BITRANGE(16, 31)
+#define MMC_CMD_APP_CMD_RCA_SHIFT 16
+#define MMC_CMD_APP_CMD_RCA(x) ((x) << 16)
+
+#define MMC_CMD_GEN_CMD_DIRECTION_MASK BIT(0)
+#define MMC_CMD_GEN_CMD_DIRECTION_READ 0
+#define MMC_CMD_GEN_CMD_DIRECTION_WRITE BIT(0)
+
+#define MMC_CMD_CEATA_RW_MULTIPLE_REG_DIRECTION_MASK BIT(31)
+#define MMC_CMD_CEATA_RW_MULTIPLE_REG_DIRECTION_READ 0
+#define MMC_CMD_CEATA_RW_MULTIPLE_REG_DIRECTION_WRITE BIT(31)
+#define MMC_CMD_CEATA_RW_MULTIPLE_REG_ADDRESS_MASK BITRANGE(16, 23)
+#define MMC_CMD_CEATA_RW_MULTIPLE_REG_ADDRESS_SHIFT 16
+#define MMC_CMD_CEATA_RW_MULTIPLE_REG_ADDRESS(x) ((x) << 16)
+#define MMC_CMD_CEATA_RW_MULTIPLE_REG_COUNT_MASK BITRANGE(0, 7)
+#define MMC_CMD_CEATA_RW_MULTIPLE_REG_COUNT_SHIFT 0
+#define MMC_CMD_CEATA_RW_MULTIPLE_REG_COUNT(x) (x)
+
+#define MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_DIRECTION_MASK BIT(31)
+#define MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_DIRECTION_READ 0
+#define MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_DIRECTION_WRITE BIT(31)
+#define MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_COUNT_MASK BITRANGE(0, 15)
+#define MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_COUNT_SHIFT 0
+#define MMC_CMD_CEATA_RW_MULTIPLE_BLOCK_COUNT(x) (x)
+
+#define MMC_CMD_SWITCH_FIELD_ERASE_GROUP_DEF 175
+#define MMC_CMD_SWITCH_FIELD_BOOT_BUS_WIDTH 177
+#define MMC_CMD_SWITCH_FIELD_BOOT_CONFIG 179
+#define MMC_CMD_SWITCH_FIELD_ERASED_MEM_CONT 181
+#define MMC_CMD_SWITCH_FIELD_BUS_WIDTH 183
+#define MMC_CMD_SWITCH_FIELD_HS_TIMING 185
+#define MMC_CMD_SWITCH_FIELD_POWER_CLASS 187
+#define MMC_CMD_SWITCH_FIELD_CMD_SET_REV 189
+#define MMC_CMD_SWITCH_FIELD_CMD_SET 191
+#define MMC_CMD_SWITCH_FIELD_EXT_CSD_REV 192
+#define MMC_CMD_SWITCH_FIELD_CSD_STRUCTURE 194
+#define MMC_CMD_SWITCH_FIELD_CARD_TYPE 196
+#define MMC_CMD_SWITCH_FIELD_PWR_CL_52_195 200
+#define MMC_CMD_SWITCH_FIELD_PWR_CL_26_195 201
+#define MMC_CMD_SWITCH_FIELD_PWR_CL_52_360 202
+#define MMC_CMD_SWITCH_FIELD_PWR_CL_26_360 203
+#define MMC_CMD_SWITCH_FIELD_MIN_PERF_R_4_26 205
+#define MMC_CMD_SWITCH_FIELD_MIN_PERF_W_4_26 206
+#define MMC_CMD_SWITCH_FIELD_MIN_PERF_R_8_26_4_52 207
+#define MMC_CMD_SWITCH_FIELD_MIN_PERF_W_8_26_4_52 208
+#define MMC_CMD_SWITCH_FIELD_MIN_PERF_R_8_52 209
+#define MMC_CMD_SWITCH_FIELD_MIN_PERF_W_8_52 210
+#define MMC_CMD_SWITCH_FIELD_SEC_COUNT_0 212
+#define MMC_CMD_SWITCH_FIELD_SEC_COUNT_1 213
+#define MMC_CMD_SWITCH_FIELD_SEC_COUNT_2 214
+#define MMC_CMD_SWITCH_FIELD_SEC_COUNT_3 215
+#define MMC_CMD_SWITCH_FIELD_S_A_TIMEOUT 217
+#define MMC_CMD_SWITCH_FIELD_S_C_VCCQ 219
+#define MMC_CMD_SWITCH_FIELD_S_C_VCC 220
+#define MMC_CMD_SWITCH_FIELD_HC_WP_GRP_SIZE 221
+#define MMC_CMD_SWITCH_FIELD_REL_WR_SEC_C 222
+#define MMC_CMD_SWITCH_FIELD_ERASE_TIMEOUT_MULT 223
+#define MMC_CMD_SWITCH_FIELD_HC_ERASE_GRP_SIZE 224
+#define MMC_CMD_SWITCH_FIELD_ACC_SIZE 225
+#define MMC_CMD_SWITCH_FIELD_BOOT_SIZE_MULTI 226
+#define MMC_CMD_SWITCH_FIELD_S_CMD_SET 504
+
+#define MMC_CMD_SWITCH_FIELD_BUS_WIDTH_1BIT 0
+#define MMC_CMD_SWITCH_FIELD_BUS_WIDTH_4BIT 1
+#define MMC_CMD_SWITCH_FIELD_BUS_WIDTH_8BIT 2
+
+#define MMC_CMD_SWITCH_FIELD_HS_TIMING_LOW_SPEED 0
+#define MMC_CMD_SWITCH_FIELD_HS_TIMING_HIGH_SPEED 1
+
+#define MMC_STATUS_APP_CMD BIT(5)
+#define MMC_STATUS_SWITCH_ERROR BIT(7)
+#define MMC_STATUS_READY_FOR_DATA BIT(8)
+#define MMC_STATUS_CURRENT_STATE_MASK BITRANGE(9, 12)
+#define MMC_STATUS_CURRENT_STATE_IDLE 0
+#define MMC_STATUS_CURRENT_STATE_READY BIT(9)
+#define MMC_STATUS_CURRENT_STATE_IDENT BIT(10)
+#define MMC_STATUS_CURRENT_STATE_STBY (BIT(9) | BIT(10))
+#define MMC_STATUS_CURRENT_STATE_TRAN BIT(11)
+#define MMC_STATUS_CURRENT_STATE_DATA (BIT(9) | BIT(11))
+#define MMC_STATUS_CURRENT_STATE_RCV (BIT(10) | BIT(11))
+#define MMC_STATUS_CURRENT_STATE_PRG (BIT(9) | BIT(10) | BIT(11))
+#define MMC_STATUS_CURRENT_STATE_DIS BIT(12)
+#define MMC_STATUS_CURRENT_STATE_BTST (BIT(9) | BIT(12))
+#define MMC_STATUS_CURRENT_STATE_SLP (BIT(10) | BIT(12))
+#define MMC_STATUS_ERASE_RESET BIT(13)
+#define MMC_STATUS_WP_ERASE_SKIP BIT(15)
+#define MMC_STATUS_CID_CSD_OVERWRITE BIT(16)
+#define MMC_STATUS_OVERRUN BIT(17)
+#define MMC_STATUS_UNDERRUN BIT(18)
+#define MMC_STATUS_ERROR BIT(19)
+#define MMC_STATUS_CC_ERROR BIT(20)
+#define MMC_STATUS_CARD_ECC_FAILED BIT(21)
+#define MMC_STATUS_ILLEGAL_COMMAND BIT(22)
+#define MMC_STATUS_COM_CRC_ERROR BIT(23)
+#define MMC_STATUS_LOCK_UNLOCK_FAILED BIT(24)
+#define MMC_STATUS_CARD_IS_LOCKED BIT(25)
+#define MMC_STATUS_WP_VIOLATION BIT(26)
+#define MMC_STATUS_ERASE_PARAM BIT(27)
+#define MMC_STATUS_ERASE_SEQ_ERROR BIT(28)
+#define MMC_STATUS_BLOCK_LEN_ERROR BIT(29)
+#define MMC_STATUS_ADDRESS_MISALIGN BIT(30)
+#define MMC_STATUS_ADDRESS_OUT_OF_RANGE BIT(31)
+
+#define MMC_OCR_170_195 BIT(7)
+#define MMC_OCR_200_260 BITRANGE(8, 14)
+#define MMC_OCR_270_360 BITRANGE(15, 23)
+#define MMC_OCR_ACCESS_MODE_MASK BITRANGE(29, 30)
+#define MMC_OCR_ACCESS_MODE_BYTE 0
+#define MMC_OCR_ACCESS_MODE_SECTOR BIT(30)
+#define MMC_OCR_POWER_UP_DONE BIT(31)
+
+#define CEATA_POWERUP_TIMEOUT 30000000
+#define CEATA_COMMAND_TIMEOUT 1000000
+#define CEATA_DAT_NONBUSY_TIMEOUT 5000000
+#define CEATA_MMC_RCA 1
Index: testapps/ceatatest/ls.x
===================================================================
--- testapps/ceatatest/ls.x	(revision 0)
+++ testapps/ceatatest/ls.x	(revision 0)
@@ -0,0 +1,42 @@
+ENTRY(__emcore_entrypoint)
+OUTPUT_FORMAT(elf32-littlearm)
+OUTPUT_ARCH(arm)
+
+MEMORY
+{
+    VIRTUAL : ORIGIN = 0x00000000, LENGTH = 0x10000000
+}
+
+SECTIONS
+{
+    .text :
+    {
+        __emcore_app_base = .;
+	KEEP(.emcoreentrypoint*)
+	*(.emcoreentrypoint*)
+        *(.text*)
+        *(.glue_7)
+        *(.glue_7t)
+        . = ALIGN(0x10);
+    } > VIRTUAL
+
+    .data :
+    {
+        *(.rodata*)
+        . = ALIGN(0x4);
+        *(.data*)
+        . = ALIGN(0x10);
+    } > VIRTUAL
+
+    .bss (NOLOAD) :
+    {
+        *(.bss*)
+        *(COMMON)
+    } > VIRTUAL
+
+    /DISCARD/ :
+    {
+        *(.eh_frame)
+    }
+
+}
Index: testapps/ceatatest/main.c
===================================================================
--- testapps/ceatatest/main.c	(revision 0)
+++ testapps/ceatatest/main.c	(revision 0)
@@ -0,0 +1,42 @@
+//
+//
+//    Copyright 2011 TheSeven
+//
+//
+//    This file is part of emCORE.
+//
+//    emCORE is free software: you can 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.
+//
+//    emCORE is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+//
+//    You should have received a copy of the GNU General Public License along
+//    with emCORE.  If not, see <http://www.gnu.org/licenses/>.
+//
+//
+
+
+#include "emcoreapp.h"
+#include "ceata.h"
+
+
+void main();
+EMCORE_APP_HEADER("CE-ATA Test application", main, 127)
+
+
+extern void INT_MMC();
+
+
+void main(int argc, const char** argv)
+{
+    interrupt_set_handler(44, INT_MMC);
+    interrupt_enable(44, true);
+    cprintf(3, "Done: %08X\n", hdd_init());
+    interrupt_enable(44, false);
+    interrupt_set_handler(44, NULL);
+}
Index: testapps/ceatatest/Makefile
===================================================================
--- testapps/ceatatest/Makefile	(revision 0)
+++ testapps/ceatatest/Makefile	(revision 0)
@@ -0,0 +1,120 @@
+NAME := ceatatest
+STACKSIZE := 4096
+COMPRESS := true
+
+EMCOREDIR ?= ../../emcore/trunk/
+
+ifeq ($(shell uname),WindowsNT)
+CCACHE :=
+else
+CCACHE := $(shell which ccache)
+endif
+
+CROSS   ?= arm-elf-eabi-
+CC      := $(CCACHE) $(CROSS)gcc
+AS      := $(CROSS)as
+LD      := $(CROSS)ld
+OBJCOPY := $(CROSS)objcopy
+ELF2ECA := $(CROSS)elf2emcoreapp
+
+LIBINCLUDES := 
+
+CFLAGS  += -Os -fno-pie -fno-stack-protector -fomit-frame-pointer -I. -I$(EMCOREDIR)/export $(LIBINCLUDES) -ffunction-sections -fdata-sections -mcpu=arm940t -DARM_ARCH=4
+LDFLAGS += "$(shell $(CC) -print-libgcc-file-name)" --emit-relocs --gc-sections
+
+preprocess = $(shell $(CC) $(PPCFLAGS) $(2) -E -P -x c $(1) | grep -v "^\#")
+preprocesspaths = $(shell $(CC) $(PPCFLAGS) $(2) -E -P -x c $(1) | grep -v "^\#" | sed -e "s:^..*:$(dir $(1))&:" | sed -e "s:^\\./::")
+
+REVISION := $(shell svnversion .)
+REVISIONINT := $(shell echo $(REVISION) | sed -e "s/[^0-9].*$$//")
+
+HELPERS := build/__emcore_armhelpers.o
+
+SRC := $(call preprocesspaths,SOURCES,-I. -I..)
+OBJ := $(SRC:%.c=build/%.o)
+OBJ := $(OBJ:%.S=build/%.o) $(HELPERS)
+
+all: $(NAME)
+
+-include $(OBJ:%=%.dep)
+
+$(NAME): build/$(NAME).emcoreapp
+
+build/$(NAME).emcoreapp: build/$(NAME).elf
+	@echo [EMCAPP] $<
+ifeq ($(COMPRESS),true)
+	@$(ELF2ECA) -z -s $(STACKSIZE) -o $@ $^
+else
+	@$(ELF2ECA) -s $(STACKSIZE) -o $@ $^
+endif
+
+build/$(NAME).elf: ls.x $(OBJ)
+	@echo [LD]     $@
+	@$(LD) $(LDFLAGS) -o $@ -T ls.x $(OBJ)
+
+build/%.o: %.c build/version.h
+	@echo [CC]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
+else
+	@-mkdir -p $(dir $@)
+endif
+	@$(CC) -c $(CFLAGS) -o $@ $<
+	@$(CC) -MM $(CFLAGS) $< > $@.dep.tmp
+	@sed -e "s|.*:|$@:|" < $@.dep.tmp > $@.dep
+ifeq ($(shell uname),WindowsNT)
+	@sed -e "s/.*://" -e "s/\\$$//" < $@.dep.tmp | fmt -1 | sed -e "s/^ *//" -e "s/$$/:/" >> $@.dep
+else
+	@sed -e 's/.*://' -e 's/\\$$//' < $@.dep.tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $@.dep
+endif
+	@rm -f $@.dep.tmp
+
+build/%.o: %.S build/version.h
+	@echo [CC]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
+else
+	@-mkdir -p $(dir $@)
+endif
+	@$(CC) -c $(CFLAGS) -o $@ $<
+	@$(CC) -MM $(CFLAGS) $< > $@.dep.tmp
+	@sed -e "s|.*:|$@:|" < $@.dep.tmp > $@.dep
+ifeq ($(shell uname),WindowsNT)
+	@sed -e "s/.*://" -e "s/\\$$//" < $@.dep.tmp | fmt -1 | sed -e "s/^ *//" -e "s/$$/:/" >> $@.dep
+else
+	@sed -e 's/.*://' -e 's/\\$$//' < $@.dep.tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $@.dep
+endif
+	@rm -f $@.dep.tmp
+
+build/__emcore_%.o: $(EMCOREDIR)/export/%.c
+	@echo [CC]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
+else
+	@-mkdir -p $(dir $@)
+endif
+	@$(CC) -c $(CFLAGS) -o $@ $<
+
+build/__emcore_%.o: $(EMCOREDIR)/export/%.S
+	@echo [CC]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
+else
+	@-mkdir -p $(dir $@)
+endif
+	@$(CC) -c $(CFLAGS) -o $@ $<
+
+build/version.h: version.h .svn/entries
+	@echo [PP]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist build md build
+	@sed -e "s/\$$REVISION\$$/$(REVISION)/" -e "s/\$$REVISIONINT\$$/$(REVISIONINT)/" < $< > $@
+else
+	@-mkdir -p build
+	@sed -e 's/\$$REVISION\$$/$(REVISION)/' -e 's/\$$REVISIONINT\$$/$(REVISIONINT)/' < $< > $@
+endif
+
+clean:
+	@rm -rf build
+
+.PHONY: all clean $(NAME)
Index: testapps/ceatatest/SOURCES
===================================================================
--- testapps/ceatatest/SOURCES	(revision 0)
+++ testapps/ceatatest/SOURCES	(revision 0)
@@ -0,0 +1,2 @@
+main.c
+ceata.c
Index: testapps/ceatatest/version.h
===================================================================
--- testapps/ceatatest/version.h	(revision 0)
+++ testapps/ceatatest/version.h	(revision 0)
@@ -0,0 +1,36 @@
+//
+//
+//    Copyright 2010 TheSeven
+//
+//
+//    This file is part of emCORE.
+//
+//    emCORE is free software: you can 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.
+//
+//    emCORE is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+//
+//    You should have received a copy of the GNU General Public License along
+//    with emCORE.  If not, see <http://www.gnu.org/licenses/>.
+//
+//
+
+
+#ifndef __VERSION_H__
+#define __VERSION_H__
+
+
+#define VERSION "0.0.1pre"
+#define VERSION_MAJOR 0
+#define VERSION_MINOR 0
+#define VERSION_PATCH 1
+#define VERSION_SVN "$REVISION$"
+#define VERSION_SVN_INT $REVISIONINT$
+
+
+#endif
\ No newline at end of file

Property changes on: testapps\hddscan
___________________________________________________________________
Added: svn:ignore
   + build



Property changes on: testapps\hddscan2
___________________________________________________________________
Added: svn:ignore
   + build


Index: testapps/hddscan2/ls.x
===================================================================
--- testapps/hddscan2/ls.x	(revision 0)
+++ testapps/hddscan2/ls.x	(revision 0)
@@ -0,0 +1,42 @@
+ENTRY(__emcore_entrypoint)
+OUTPUT_FORMAT(elf32-littlearm)
+OUTPUT_ARCH(arm)
+
+MEMORY
+{
+    VIRTUAL : ORIGIN = 0x00000000, LENGTH = 0x10000000
+}
+
+SECTIONS
+{
+    .text :
+    {
+        __emcore_app_base = .;
+	KEEP(.emcoreentrypoint*)
+	*(.emcoreentrypoint*)
+        *(.text*)
+        *(.glue_7)
+        *(.glue_7t)
+        . = ALIGN(0x10);
+    } > VIRTUAL
+
+    .data :
+    {
+        *(.rodata*)
+        . = ALIGN(0x4);
+        *(.data*)
+        . = ALIGN(0x10);
+    } > VIRTUAL
+
+    .bss (NOLOAD) :
+    {
+        *(.bss*)
+        *(COMMON)
+    } > VIRTUAL
+
+    /DISCARD/ :
+    {
+        *(.eh_frame)
+    }
+
+}
Index: testapps/hddscan2/main.c
===================================================================
--- testapps/hddscan2/main.c	(revision 0)
+++ testapps/hddscan2/main.c	(revision 0)
@@ -0,0 +1,656 @@
+//
+//
+//    Copyright 2011 TheSeven
+//
+//
+//    This file is part of emCORE.
+//
+//    emCORE is free software: you can 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.
+//
+//    emCORE is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+//
+//    You should have received a copy of the GNU General Public License along
+//    with emCORE.  If not, see <http://www.gnu.org/licenses/>.
+//
+//
+
+
+#include "emcoreapp.h"
+#include "version.h"
+#include "../../emcore/trunk/target/ipodclassic/storage_ata-target.h"
+
+
+enum phase_t
+{
+    PHASE_WRITE,
+    PHASE_WRITE_SYNC,
+    PHASE_READ,
+    PHASE_GENERATE_BBT,
+    PHASE_WRITE_BBT,
+    PHASE_FORMAT,
+    PHASE_WRITE_RESULT,
+    PHASE_FINISHED,
+    NUM_PHASES
+};
+
+char* phasenames[] =
+{
+    [PHASE_WRITE] = "WRITE",
+    [PHASE_WRITE_SYNC] = "WRITE SYNC",
+    [PHASE_READ] = "READ",
+    [PHASE_GENERATE_BBT] = "GENERATE BBT",
+    [PHASE_WRITE_BBT] = "WRITE BBT",
+    [PHASE_FORMAT] = "FORMAT",
+    [PHASE_WRITE_RESULT] = "WRITE RESULT",
+    [PHASE_FINISHED] = "FINISHED"
+};
+
+enum state_t
+{
+    STATE_INITIAL = 0,
+    STATE_WRITE_OK,
+    STATE_WRITE_SUSPECT,
+    STATE_WRITE_SUSPECT_LOCKUP,
+    STATE_WRITE_SLOW,
+    STATE_WRITE_ERROR,
+    STATE_WRITE_LOCKUP,
+    STATE_READ_SUSPECT,
+    STATE_READ_OK,
+    STATE_READ_SLOW,
+    STATE_READ_ERROR,
+    STATE_READ_LOCKUP,
+    STATE_READ_DATA_ERROR,
+    STATE_READ_SLOW_DATA_ERROR,
+    NUM_STATES
+};
+
+char* statenames[] =
+{
+    [STATE_INITIAL] = "INITIAL",
+    [STATE_WRITE_OK] = "WRITE OK",
+    [STATE_WRITE_SUSPECT] = "WRITE SUSPECT",
+    [STATE_WRITE_SUSPECT_LOCKUP] = "WRITE SUSPECT LOCKUP",
+    [STATE_WRITE_SLOW] = "WRITE SLOW",
+    [STATE_WRITE_ERROR] = "WRITE ERROR",
+    [STATE_WRITE_LOCKUP] = "WRITE LOCKUP",
+    [STATE_READ_SUSPECT] = "READ SUSPECT",
+    [STATE_READ_OK] = "READ OK",
+    [STATE_READ_SLOW] = "READ SLOW",
+    [STATE_READ_ERROR] = "READ ERROR",
+    [STATE_READ_LOCKUP] = "READ LOCKUP",
+    [STATE_READ_DATA_ERROR] = "READ DATA ERROR",
+    [STATE_READ_SLOW_DATA_ERROR] = "READ SLOW DATA ERROR"
+};
+
+
+volatile enum phase_t phase = PHASE_WRITE;
+uint8_t* state;
+int totalsectors;
+int s;
+volatile int pass = 0;
+volatile int clean = 0;
+volatile int pwrcycles = 0;
+void* wrbuf;
+void* rdbuf;
+void* framebuf;
+bool done = false;
+bool paused = false;
+long lastbattcheck = 0;
+struct wakeup monitor_wakeup;
+struct wakeup join_wakeup;
+
+
+void mkfat32(void* buf, int sectors)
+{
+    uint32_t i, j, rc;
+    uint32_t rootdirclus = 2;
+    uint32_t secperclus = 1;
+    uint32_t fatsectors = 1;
+    uint32_t oldfatsectors = 0;
+    uint32_t clustercount;
+    uint32_t reserved = 2;
+    while (fatsectors != oldfatsectors)
+    {
+        oldfatsectors = fatsectors;
+        clustercount = (sectors - fatsectors - reserved) / secperclus;
+        fatsectors = (clustercount + 1025) >> 10;
+    }
+    uint32_t database = fatsectors + reserved;
+    uint32_t clusoffset = 0;
+    memset(buf, 0, 0x1000);
+    memcpy(buf, "\xeb\x58\x00MSWIN5.0\0\x10", 0xd);
+    ((uint8_t*)buf)[0xd] = secperclus;
+    ((uint16_t*)buf)[7] = reserved;
+    memcpy(&((uint8_t*)buf)[0x10], "\x01\0\0\0\0\xf8\0\0\x3f\0\xff", 0xb);
+    ((uint32_t*)buf)[8] = sectors;
+    ((uint32_t*)buf)[9] = fatsectors;
+    ((uint32_t*)buf)[0xb] = rootdirclus + clusoffset;
+    ((uint16_t*)buf)[0x18] = 1;
+    ((uint8_t*)buf)[0x40] = 0x80;
+    ((uint8_t*)buf)[0x42] = 0x29;
+    memcpy(&((uint8_t*)buf)[0x43], "\0\0\0\0iPodClassic", 0xf);
+    memcpy(&((uint8_t*)buf)[0x52], "FAT32   ", 8);
+    ((uint16_t*)buf)[0xff] = 0xaa55;
+    if (rc = storage_write_sectors_md(0, 0, 1, buf))
+        panicf(PANIC_KILLTHREAD, "Error writing MBR: %08X", rc);
+    memset(buf, 0, 0x1000);
+    ((uint32_t*)buf)[0] = 0x41615252;
+    ((uint32_t*)buf)[0x79] = 0x61417272;
+    ((uint32_t*)buf)[0x7a] = clustercount - 1;
+    ((uint32_t*)buf)[0x7b] = 2;
+    ((uint32_t*)buf)[0x7f] = 0xaa550000;
+    if (rc = storage_write_sectors_md(0, 1, 1, buf))
+        panicf(PANIC_KILLTHREAD, "Error writing FSINFO: %08X", rc);
+    uint32_t cursect = 0;
+    for (i = 0; i < fatsectors; i++)
+    {
+        memset(buf, 0, 0x1000);
+        if (!i) memcpy(buf, "\xf8\xff\xff\x0f\xff\xff\xff\xff\xff\xff\xff\x0f", 12);
+        if (rc = storage_write_sectors_md(0, reserved + i, 1, buf))
+            panicf(PANIC_KILLTHREAD, "Error writing FAT sector %d: %08X", i, rc);
+        s = i;
+    }
+    memset(buf, 0, secperclus * 0x1000);
+    memcpy(buf, "iPodClassic\x08", 12);
+    if (rc = storage_write_sectors_md(0, database, secperclus, buf))
+        panicf(PANIC_KILLTHREAD, "Error writing root directory sectors: %08X", i, rc);
+    free(buf);
+    disk_mount(0);
+}
+
+static void monitor()
+{
+    int i;
+    char textbuf[0x40];
+    int count[NUM_STATES];
+    bool done_latch = false;
+    while (!done_latch)
+    {
+        int y = 1;
+        memset(framebuf, 0xff, 320 * 240 * 3);
+        rendertext(framebuf, 6, y++ * 8, 320, 0xff000000, 0xffffffff,
+                   "HDD bad sector scanner v. " VERSION);
+        y++;
+        snprintf(textbuf, 0x40, "Pass %d (%d clean)", pass + 1, clean);
+        rendertext(framebuf, 6, y++ * 8, 320, 0xff000000, 0xffffffff, textbuf);
+        snprintf(textbuf, 0x40, "Phase: %s (%d of %d)",
+                 phasenames[phase], phase + 1, NUM_PHASES);
+        rendertext(framebuf, 6, y++ * 8, 320, 0xff000000, 0xffffffff, textbuf);
+        snprintf(textbuf, 0x40, "Processing sector %d of %d", s, totalsectors);
+        rendertext(framebuf, 6, y++ * 8, 320, 0xff000000, 0xffffffff, textbuf);
+        snprintf(textbuf, 0x40, "Hard resets needed: %d", pwrcycles);
+        rendertext(framebuf, 6, y++ * 8, 320, 0xff000000, 0xffffffff, textbuf);
+        y++;
+        rendertext(framebuf, 6, y++ * 8, 320, 0xff000000, 0xffffffff, "Sector counts:");
+        for (i = STATE_INITIAL; i < NUM_STATES; i++) count[i] = 0;
+        for (i = 0; i < totalsectors; i++) count[state[i] & 0xf]++;
+        for (i = STATE_INITIAL; i < NUM_STATES; i++)
+        {
+            snprintf(textbuf, 0x400, "%20s: %d", statenames[i], count[i]);
+            rendertext(framebuf, 6, y++ * 8, 320, 0xff000000, 0xffffffff, textbuf);
+        }
+        if (paused)
+        {
+            y++;
+            rendertext(framebuf, 6, y++ * 8, 320, 0xff000000, 0xffffffff, "Paused (low battery)");
+        }
+        displaylcd(0, 0, 320, 240, framebuf, 0, 0, 320);
+        done_latch = done;
+        if (!done_latch) wakeup_wait(&monitor_wakeup, 5000000);
+    }
+    wakeup_signal(&join_wakeup);
+}
+
+static int soft_reset()
+{
+    int rc = 0;
+    while (storage_soft_reset())
+    {
+        storage_sleep();
+        cputs(2, "LOCKUP!\n");
+        rc = -1;
+        pwrcycles++;
+        sleep(1000000);
+        storage_spin();
+    }
+    return rc;
+}
+
+static void checkbatt()
+{
+    if (USEC_TIMER - lastbattcheck > 30000000)
+    {
+        int percent = 0;
+        while (percent < 50)
+        {
+            percent = 100 * read_battery_mwh_current(0) / read_battery_mwh_full(0);
+            if (percent < 50)
+            {
+                paused = true;
+                sleep(10000000);
+            }
+        }
+        paused = false;
+        lastbattcheck = USEC_TIMER;
+    }
+}
+
+static bool is_good(int sector)
+{
+    return (state[sector] & 0xf) == STATE_READ_OK;
+}
+
+static void writestr(int fd, char* string)
+{
+    int len = strlen(string);
+    if (write(fd, string, len) != len)
+        panicf(PANIC_KILLTHREAD, "Failed to write to hddscan_summary.txt!");
+}
+
+static void main(int argc, const char** argv)
+{
+    int i, j;
+    int count[NUM_STATES];
+    char textbuf[0x80];
+    struct storage_info storageinfo;
+    storage_get_info(0, &storageinfo);
+    struct ata_target_driverinfo* drv = storageinfo.driverinfo;
+    drv->bbt_disable();
+    storage_get_info(0, &storageinfo);
+    totalsectors = storageinfo.num_sectors;
+    wakeup_init(&monitor_wakeup);
+    wakeup_init(&join_wakeup);
+    state = malloc(totalsectors);
+    memset(state, STATE_INITIAL, totalsectors);
+    cprintf(3, "State information at 0x%08X\n", state);
+    sleep(10000000);
+    framebuf = malloc(320 * 240 * 3);
+    wrbuf = memalign(0x10, 0x1000);
+    rdbuf = memalign(0x10, 0x1000);
+    struct scheduler_thread* thread = thread_create(NULL, "HDD scanner monitor", monitor,
+                                                    NULL, 0x1000, USER_THREAD, 127, false);
+    if (!state || !wrbuf || !rdbuf || !framebuf || !thread)
+    {
+        if (thread) thread_terminate(thread);
+        panicf(PANIC_KILLTHREAD, "Not enough RAM (need %d bytes)!",
+               totalsectors + 0x3400 + 320 * 240 * 3);
+    }
+    memset(wrbuf, 0xa5, 0x1000);
+    drv->set_retries(0);
+    drv->srst_after_error(false);
+    thread_resume(thread);
+    bool resetdone;
+    bool suspectmode;
+    long start;
+    long time;
+    int result;
+    int rstres;
+    int compare;
+    int newstate;
+    int base = 0;
+    while (true)
+    {
+        if (clean == 5 && phase == PHASE_WRITE)
+        {
+            base += 8192;
+            clean = 0;
+        }
+        if (base >= totalsectors) break;
+        int limit = MIN(totalsectors, base + 16384);
+        switch (phase)
+        {
+        case PHASE_WRITE:
+            clean++;
+            for (s = base; s < limit; s++)
+            {
+                checkbatt();
+                switch (state[s] & 0xf)
+                {
+                case STATE_INITIAL:
+                case STATE_READ_OK:
+                    snprintf(wrbuf, 0x1000, "#HDDSCAN#SECTOR%8d#PASS%03d#", s, pass);
+                    start = USEC_TIMER;
+                    result = storage_write_sectors_md(0, s, 1, wrbuf);
+	                time = USEC_TIMER - start;
+                    if (result < 0/* || time > 1000000*/)
+                    {
+                        if (soft_reset())
+                        {
+                            cprintf(2, "PASS %d WRITE %d RC %08X TIME %d LOCKUP!\n",
+                                    pass, s, result, time);
+                            clean = 0;
+                            newstate = STATE_WRITE_SUSPECT_LOCKUP;
+                        }
+                        else
+                        {
+                            cprintf(2, "PASS %d WRITE %d RC %08X TIME %d\n",
+                                    pass, s, result, time);
+                            if (clean > 1) newstate = STATE_READ_SUSPECT;
+                            else newstate = STATE_WRITE_SUSPECT;
+                        }
+                        i = s;
+                        j = 128;
+                        while (i >= base && j)
+                        {
+                            if ((state[i] & 0xf) == STATE_WRITE_OK || i == s)
+                            {
+                                state[i] = (pass << 4) | newstate;
+                                j--;
+                            }
+                            i--;
+                        }
+                        if (newstate == STATE_READ_SUSPECT)
+                            state[s] = (pass << 4) | STATE_WRITE_SUSPECT;
+                    }
+                    else state[s] = (pass << 4) | STATE_WRITE_OK;
+                }
+            }
+            phase = PHASE_WRITE_SYNC;
+            break;
+        case PHASE_WRITE_SYNC:
+            soft_reset();
+            for (s = base; s < limit; s++)
+            {
+                checkbatt();
+                switch (state[s] & 0xf)
+                {
+                case STATE_WRITE_SUSPECT:
+                case STATE_WRITE_SUSPECT_LOCKUP:
+                    snprintf(wrbuf, 0x1000, "#HDDSCAN#SECTOR%8d#PASS%03d#", s, pass);
+                    start = USEC_TIMER;
+                    result = storage_write_sectors_md(0, s, 1, wrbuf);
+                    rstres = soft_reset();
+	                time = USEC_TIMER - start;
+                    if (rstres)
+                    {
+                        cprintf(2, "PASS %d WRITESYNC %d RC %08X TIME %d LOCKUP!\n",
+                                pass, s, result, time);
+                        clean = 0;
+                        newstate = STATE_WRITE_LOCKUP;
+                    }
+                    else if (result < 0/* || time > 1000000*/)
+                    {
+                        cprintf(2, "PASS %d WRITESYNC %d RC %08X TIME %d\n",
+                                pass, s, result, time);
+                        clean = 0;
+                        if (result < 0) newstate = STATE_WRITE_ERROR;
+                        else newstate = STATE_WRITE_SLOW;
+                    }
+                    else newstate = STATE_WRITE_OK;
+                    state[s] = (pass << 4) | newstate;
+                }
+            }
+            phase = PHASE_READ;
+            break;
+        case PHASE_READ:
+            suspectmode = false;
+            for (s = base; s < limit; s++)
+            {
+                checkbatt();
+                switch (state[s] & 0xf)
+                {
+                case STATE_WRITE_OK:
+                    suspectmode = false;
+                case STATE_READ_SUSPECT:
+                    resetdone = false;
+                    snprintf(wrbuf, 0x1000, "#HDDSCAN#SECTOR%8d#PASS%03d#", s, pass);
+                    start = USEC_TIMER;
+                    result = storage_read_sectors_md(0, s, 1, rdbuf);
+	                time = USEC_TIMER - start;
+                    compare = memcmp(wrbuf, rdbuf, 0x1000);
+                    if (result < 0 || compare/* || time > 1000000*/)
+                    {
+                        clean = 0;
+                        if (result < 0 && soft_reset())
+                        {
+                            cprintf(2, "PASS %d READ %d RC %08X DATA %d TIME %d LOCKUP!\n",
+                                    pass, s, result, compare, time);
+                            newstate = STATE_READ_LOCKUP;
+                        }
+                        else
+                        {
+                            cprintf(2, "PASS %d READ %d RC %08X DATA %d TIME %d\n",
+                                    pass, s, result, compare, time);
+                            if (suspectmode) newstate = STATE_INITIAL;
+                            if (result < 0) newstate = STATE_READ_ERROR;
+                            else if (compare && time > 200000)
+                                newstate = STATE_READ_SLOW_DATA_ERROR;
+                            else if (compare) newstate = STATE_READ_DATA_ERROR;
+                            else newstate = STATE_READ_SLOW;
+                            if ((state[s] & 0xf) == STATE_READ_SUSPECT) suspectmode = true;
+                        }
+                    }
+                    else newstate = STATE_READ_OK;
+                    state[s] = (pass << 4) | newstate;
+                    break;
+                default:
+                    if (!resetdone) soft_reset();
+                    resetdone = true;
+                }
+            }
+            pass++;
+            phase = PHASE_WRITE;
+        }
+    }
+    free(rdbuf);
+    phase = PHASE_GENERATE_BBT;
+    s = 0;
+    int l0count = (totalsectors + 0xfffff) >> 19;
+    int l1count;
+    int l2count;
+    int l3count;
+    int logical;
+    int bbtpages = 64 + ((l0count + 0x3f) & ~0x3f);
+    int bbtsize;
+    int bbtgood;
+    uint16_t (*bbt)[0x20];
+    bool success = false;
+    while (bbtpages <= 32832)
+    {
+        bbtsize = bbtpages << 6;
+        l0count = (totalsectors - bbtsize + 0xfffff) >> 19;
+        bbt = memalign(0x10, bbtsize);
+        if (!bbt) panicf(PANIC_KILLTHREAD, "Failed to allocate memory for BBT!");
+        memset(bbt, 0, bbtsize);
+        logical = 0;
+        int physical = 1;
+        int remapbase;
+        for (bbtgood = 0; bbtgood < (bbtpages >> 6) - 1; physical++)
+            if (is_good(physical))
+            {
+                ((uint32_t*)bbt)[0x200 + bbtgood] = physical;
+                bbtgood++;
+            }
+        int bbtused = 64 + l0count;
+        int level;
+        uint16_t *l1, *l2, *l3;
+        l1count = 0;
+        l2count = 0;
+        l3count = 0;
+        while (!success)
+        {
+            if (!(logical & 0x7fff)) level = 0;
+            else if (!(logical & 0x3ff)) level = 1;
+            else if (!(logical & 0x1f)) level = 2;
+            else level = 3;
+            if (!level) remapbase = (physical - logical) & ~0xfff;
+            if (physical - logical - remapbase > 0x7fff || remapbase > 0xffff000)
+                panicf(PANIC_KILLTHREAD, "Failed to generate BBT: "
+                       "Need to remap across too high distance!");
+            int clean;
+            for (clean = 0; clean < (1 << ((3 - level) * 5))
+                         && physical + clean < totalsectors; clean++)
+                if (!is_good(physical + clean))
+                    break;
+            if (clean >= 32768)
+            {
+                bbt[64][(logical >> 15) << 1] = physical - logical - remapbase;
+                bbt[64][((logical >> 15) << 1) | 1] = remapbase >> 12;
+                physical += 32768;
+                logical += 32768;
+            }
+            else if (clean >= 1024)
+            {
+                if (level == 0)
+                {
+                    if (bbtused == bbtpages) break;
+                    level = 1;
+                    l1 = bbt[bbtused];
+                    bbt[64][(logical >> 15) << 1] = 0x8000 | (bbtused - 64);
+                    bbt[64][((logical >> 15) << 1) | 1] = remapbase >> 12;
+                    bbtused++;
+                    l1count++;
+                }
+                l1[(logical >> 10) & 0x1f] = physical - logical - remapbase;
+                physical += 1024;
+                logical += 1024;
+            }
+            else if (clean >= 32)
+            {
+                if (level == 0)
+                {
+                    if (bbtused == bbtpages) break;
+                    level = 1;
+                    l1 = bbt[bbtused];
+                    bbt[64][(logical >> 15) << 1] = 0x8000 | (bbtused - 64);
+                    bbt[64][((logical >> 15) << 1) | 1] = remapbase >> 12;
+                    bbtused++;
+                    l1count++;
+                }
+                if (level == 1)
+                {
+                    if (bbtused == bbtpages) break;
+                    level = 2;
+                    l2 = bbt[bbtused];
+                    l1[(logical >> 10) & 0x1f] = 0x8000 | (bbtused - 64);
+                    bbtused++;
+                    l2count++;
+                }
+                l2[(logical >> 5) & 0x1f] = physical - logical - remapbase;
+                physical += 32;
+                logical += 32;
+            }
+            else if (clean >= 1)
+            {
+                if (level == 0)
+                {
+                    if (bbtused == bbtpages) break;
+                    level = 1;
+                    l1 = bbt[bbtused];
+                    bbt[64][(logical >> 15) << 1] = 0x8000 | (bbtused - 64);
+                    bbt[64][((logical >> 15) << 1) | 1] = remapbase >> 12;
+                    bbtused++;
+                    l1count++;
+                }
+                if (level == 1)
+                {
+                    if (bbtused == bbtpages) break;
+                    level = 2;
+                    l2 = bbt[bbtused];
+                    l1[(logical >> 10) & 0x1f] = 0x8000 | (bbtused - 64);
+                    bbtused++;
+                    l2count++;
+                }
+                if (level == 2)
+                {
+                    if (bbtused == bbtpages) break;
+                    level = 3;
+                    l3 = bbt[bbtused];
+                    l2[(logical >> 5) & 0x1f] = 0x8000 | (bbtused - 64);
+                    bbtused++;
+                    l3count++;
+                }
+                l3[logical & 0x1f] = physical - logical - remapbase;
+                physical++;
+                logical++;
+            }
+            else physical++;
+            if (physical >= totalsectors) success = true;
+            s = physical;
+        }
+        if (success)
+        {        
+            memcpy(bbt, "emBIbbth", 8);
+            ((uint32_t*)bbt)[0x1fc] = logical;
+            ((uint32_t*)bbt)[0x1ff] = bbtgood;
+            break;
+        }
+        free(bbt);
+        bbtpages += 64;
+    }
+    if (!success) panicf(PANIC_KILLTHREAD, "Can't fit BBT into 2052 KiB!");
+    phase = PHASE_WRITE_BBT;
+    s = 0;
+    drv->srst_after_error(true);
+    drv->set_retries(3);
+    result = storage_write_sectors_md(0, 0, 1, bbt);
+    if (result < 0) panicf(PANIC_KILLTHREAD, "Failed to write BBT sector 0!");
+    for (i = 0; i < bbtgood; i++)
+    {
+        storage_write_sectors_md(0, ((uint32_t*)bbt)[0x200 + i], 1, &bbt[(i + 1) * 0x40]);
+        if (result < 0) panicf(PANIC_KILLTHREAD, "Failed to write BBT sector %d!", i);
+        s = i;
+    }
+    drv->bbt_reload();
+    phase = PHASE_FORMAT;
+    s = 0;
+    mkfat32(wrbuf, logical);
+    free(wrbuf);
+    phase = PHASE_WRITE_RESULT;
+    s = 0;
+    for (i = STATE_INITIAL; i < NUM_STATES; i++) count[i] = 0;
+    for (i = 0; i < totalsectors; i++) count[state[i] & 0xf]++;
+    int fd = file_creat("/hddscan_result.bin");
+    if (fd < 0) panicf(PANIC_KILLTHREAD, "Failed to create hddscan_result.bin");
+    if (write(fd, state, totalsectors) != totalsectors)
+        panicf(PANIC_KILLTHREAD, "Failed to write to hddscan_result.bin!");
+    close(fd);
+    s = 1;
+    fd = file_creat("/hddscan_bbt.bin");
+    if (fd < 0) panicf(PANIC_KILLTHREAD, "Failed to create hddscan_bbt.bin");
+    if (write(fd, bbt, bbtsize) != bbtsize)
+        panicf(PANIC_KILLTHREAD, "Failed to write to hddscan_bbt.bin!");
+    close(fd);
+    free(bbt);
+    s = 2;
+    fd = file_creat("/hddscan_summary.txt");
+    writestr(fd, "HDD bad sector scanner v. " VERSION "\n\n");
+    snprintf(textbuf, 0x80, "Finished after pass %d (%d clean)\n", pass, clean);
+    writestr(fd, textbuf);
+    snprintf(textbuf, 0x80, "%d out of %d sectors bad\n",
+             totalsectors - count[STATE_READ_OK], totalsectors);
+    writestr(fd, textbuf);
+    snprintf(textbuf, 0x80, "Hard resets needed: %d\n", pwrcycles);
+    writestr(fd, textbuf);
+    writestr(fd, "\nSector counts:\n");
+    for (i = STATE_INITIAL; i < NUM_STATES; i++)
+    {
+        snprintf(textbuf, 0x400, "%20s: %d\n", statenames[i], count[i]);
+        writestr(fd, textbuf);
+    }
+    snprintf(textbuf, 0x80, "\nBBT using %d sectors (%d KiB)\n", bbtgood + 1, bbtsize >> 10);
+    writestr(fd, textbuf);
+    snprintf(textbuf, 0x80, "Level 0: %d pages, Level 1: %d pages, Level 2: %d pages, "
+                            "Level 3: %d pages\n", l0count, l1count, l2count, l3count);
+    writestr(fd, textbuf);
+    snprintf(textbuf, 0x80, "User data sectors: %d (%d KiB)\n", logical, logical << 2);
+    writestr(fd, textbuf);
+    close(fd);
+    s = 3;
+    phase = PHASE_FINISHED;
+    s = 0;
+    done = true;
+    wakeup_signal(&monitor_wakeup);
+    wakeup_wait(&join_wakeup, TIMEOUT_BLOCK);
+    free(state);
+    free(framebuf);
+}
+
+EMCORE_APP_HEADER("HDD scanner", main, 63)
+
Index: testapps/hddscan2/Makefile
===================================================================
--- testapps/hddscan2/Makefile	(revision 0)
+++ testapps/hddscan2/Makefile	(revision 0)
@@ -0,0 +1,120 @@
+NAME := hddscan2
+STACKSIZE := 8192
+COMPRESS := true
+
+EMCOREDIR ?= ../../emcore/trunk/
+
+ifeq ($(shell uname),WindowsNT)
+CCACHE :=
+else
+CCACHE := $(shell which ccache)
+endif
+
+CROSS   ?= arm-elf-eabi-
+CC      := $(CCACHE) $(CROSS)gcc
+AS      := $(CROSS)as
+LD      := $(CROSS)ld
+OBJCOPY := $(CROSS)objcopy
+ELF2ECA := $(CROSS)elf2emcoreapp
+
+LIBINCLUDES := 
+
+CFLAGS  += -Os -fno-pie -fno-stack-protector -fomit-frame-pointer -I. -I$(EMCOREDIR)/export $(LIBINCLUDES) -ffunction-sections -fdata-sections -mcpu=arm940t -DARM_ARCH=4
+LDFLAGS += "$(shell $(CC) -print-libgcc-file-name)" --emit-relocs --gc-sections
+
+preprocess = $(shell $(CC) $(PPCFLAGS) $(2) -E -P -x c $(1) | grep -v "^\#")
+preprocesspaths = $(shell $(CC) $(PPCFLAGS) $(2) -E -P -x c $(1) | grep -v "^\#" | sed -e "s:^..*:$(dir $(1))&:" | sed -e "s:^\\./::")
+
+REVISION := $(shell svnversion .)
+REVISIONINT := $(shell echo $(REVISION) | sed -e "s/[^0-9].*$$//")
+
+HELPERS := build/__emcore_armhelpers.o
+
+SRC := $(call preprocesspaths,SOURCES,-I. -I..)
+OBJ := $(SRC:%.c=build/%.o)
+OBJ := $(OBJ:%.S=build/%.o) $(HELPERS)
+
+all: $(NAME)
+
+-include $(OBJ:%=%.dep)
+
+$(NAME): build/$(NAME).emcoreapp
+
+build/$(NAME).emcoreapp: build/$(NAME).elf
+	@echo [EMCAPP] $<
+ifeq ($(COMPRESS),true)
+	@$(ELF2ECA) -z -s $(STACKSIZE) -o $@ $^
+else
+	@$(ELF2ECA) -s $(STACKSIZE) -o $@ $^
+endif
+
+build/$(NAME).elf: ls.x $(OBJ)
+	@echo [LD]     $@
+	@$(LD) $(LDFLAGS) -o $@ -T ls.x $(OBJ)
+
+build/%.o: %.c build/version.h
+	@echo [CC]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
+else
+	@-mkdir -p $(dir $@)
+endif
+	@$(CC) -c $(CFLAGS) -o $@ $<
+	@$(CC) -MM $(CFLAGS) $< > $@.dep.tmp
+	@sed -e "s|.*:|$@:|" < $@.dep.tmp > $@.dep
+ifeq ($(shell uname),WindowsNT)
+	@sed -e "s/.*://" -e "s/\\$$//" < $@.dep.tmp | fmt -1 | sed -e "s/^ *//" -e "s/$$/:/" >> $@.dep
+else
+	@sed -e 's/.*://' -e 's/\\$$//' < $@.dep.tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $@.dep
+endif
+	@rm -f $@.dep.tmp
+
+build/%.o: %.S build/version.h
+	@echo [CC]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
+else
+	@-mkdir -p $(dir $@)
+endif
+	@$(CC) -c $(CFLAGS) -o $@ $<
+	@$(CC) -MM $(CFLAGS) $< > $@.dep.tmp
+	@sed -e "s|.*:|$@:|" < $@.dep.tmp > $@.dep
+ifeq ($(shell uname),WindowsNT)
+	@sed -e "s/.*://" -e "s/\\$$//" < $@.dep.tmp | fmt -1 | sed -e "s/^ *//" -e "s/$$/:/" >> $@.dep
+else
+	@sed -e 's/.*://' -e 's/\\$$//' < $@.dep.tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $@.dep
+endif
+	@rm -f $@.dep.tmp
+
+build/__emcore_%.o: $(EMCOREDIR)/export/%.c
+	@echo [CC]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
+else
+	@-mkdir -p $(dir $@)
+endif
+	@$(CC) -c $(CFLAGS) -o $@ $<
+
+build/__emcore_%.o: $(EMCOREDIR)/export/%.S
+	@echo [CC]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
+else
+	@-mkdir -p $(dir $@)
+endif
+	@$(CC) -c $(CFLAGS) -o $@ $<
+
+build/version.h: version.h .svn/entries
+	@echo [PP]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist build md build
+	@sed -e "s/\$$REVISION\$$/$(REVISION)/" -e "s/\$$REVISIONINT\$$/$(REVISIONINT)/" < $< > $@
+else
+	@-mkdir -p build
+	@sed -e 's/\$$REVISION\$$/$(REVISION)/' -e 's/\$$REVISIONINT\$$/$(REVISIONINT)/' < $< > $@
+endif
+
+clean:
+	@rm -rf build
+
+.PHONY: all clean $(NAME)
Index: testapps/hddscan2/SOURCES
===================================================================
--- testapps/hddscan2/SOURCES	(revision 0)
+++ testapps/hddscan2/SOURCES	(revision 0)
@@ -0,0 +1 @@
+main.c
Index: testapps/hddscan2/version.h
===================================================================
--- testapps/hddscan2/version.h	(revision 0)
+++ testapps/hddscan2/version.h	(revision 0)
@@ -0,0 +1,36 @@
+//
+//
+//    Copyright 2010 TheSeven
+//
+//
+//    This file is part of emCORE.
+//
+//    emCORE is free software: you can 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.
+//
+//    emCORE is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+//
+//    You should have received a copy of the GNU General Public License along
+//    with emCORE.  If not, see <http://www.gnu.org/licenses/>.
+//
+//
+
+
+#ifndef __VERSION_H__
+#define __VERSION_H__
+
+
+#define VERSION "0.0.1pre"
+#define VERSION_MAJOR 0
+#define VERSION_MINOR 0
+#define VERSION_PATCH 1
+#define VERSION_SVN "$REVISION$"
+#define VERSION_SVN_INT $REVISIONINT$
+
+
+#endif
\ No newline at end of file
Index: testapps/hddscan/ls.x
===================================================================
--- testapps/hddscan/ls.x	(revision 0)
+++ testapps/hddscan/ls.x	(revision 0)
@@ -0,0 +1,42 @@
+ENTRY(__emcore_entrypoint)
+OUTPUT_FORMAT(elf32-littlearm)
+OUTPUT_ARCH(arm)
+
+MEMORY
+{
+    VIRTUAL : ORIGIN = 0x00000000, LENGTH = 0x10000000
+}
+
+SECTIONS
+{
+    .text :
+    {
+        __emcore_app_base = .;
+	KEEP(.emcoreentrypoint*)
+	*(.emcoreentrypoint*)
+        *(.text*)
+        *(.glue_7)
+        *(.glue_7t)
+        . = ALIGN(0x10);
+    } > VIRTUAL
+
+    .data :
+    {
+        *(.rodata*)
+        . = ALIGN(0x4);
+        *(.data*)
+        . = ALIGN(0x10);
+    } > VIRTUAL
+
+    .bss (NOLOAD) :
+    {
+        *(.bss*)
+        *(COMMON)
+    } > VIRTUAL
+
+    /DISCARD/ :
+    {
+        *(.eh_frame)
+    }
+
+}
Index: testapps/hddscan/main.c
===================================================================
--- testapps/hddscan/main.c	(revision 0)
+++ testapps/hddscan/main.c	(revision 0)
@@ -0,0 +1,656 @@
+//
+//
+//    Copyright 2011 TheSeven
+//
+//
+//    This file is part of emCORE.
+//
+//    emCORE is free software: you can 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.
+//
+//    emCORE is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+//
+//    You should have received a copy of the GNU General Public License along
+//    with emCORE.  If not, see <http://www.gnu.org/licenses/>.
+//
+//
+
+
+#include "emcoreapp.h"
+#include "version.h"
+#include "../../emcore/trunk/target/ipodclassic/storage_ata-target.h"
+
+
+enum phase_t
+{
+    PHASE_WRITE,
+    PHASE_WRITE_SYNC,
+    PHASE_READ,
+    PHASE_GENERATE_BBT,
+    PHASE_WRITE_BBT,
+    PHASE_FORMAT,
+    PHASE_WRITE_RESULT,
+    PHASE_FINISHED,
+    NUM_PHASES
+};
+
+char* phasenames[] =
+{
+    [PHASE_WRITE] = "WRITE",
+    [PHASE_WRITE_SYNC] = "WRITE SYNC",
+    [PHASE_READ] = "READ",
+    [PHASE_GENERATE_BBT] = "GENERATE BBT",
+    [PHASE_WRITE_BBT] = "WRITE BBT",
+    [PHASE_FORMAT] = "FORMAT",
+    [PHASE_WRITE_RESULT] = "WRITE RESULT",
+    [PHASE_FINISHED] = "FINISHED"
+};
+
+enum state_t
+{
+    STATE_INITIAL = 0,
+    STATE_WRITE_OK,
+    STATE_WRITE_SUSPECT,
+    STATE_WRITE_SUSPECT_LOCKUP,
+    STATE_WRITE_SLOW,
+    STATE_WRITE_ERROR,
+    STATE_WRITE_LOCKUP,
+    STATE_READ_SUSPECT,
+    STATE_READ_OK,
+    STATE_READ_SLOW,
+    STATE_READ_ERROR,
+    STATE_READ_LOCKUP,
+    STATE_READ_DATA_ERROR,
+    STATE_READ_SLOW_DATA_ERROR,
+    NUM_STATES
+};
+
+char* statenames[] =
+{
+    [STATE_INITIAL] = "INITIAL",
+    [STATE_WRITE_OK] = "WRITE OK",
+    [STATE_WRITE_SUSPECT] = "WRITE SUSPECT",
+    [STATE_WRITE_SUSPECT_LOCKUP] = "WRITE SUSPECT LOCKUP",
+    [STATE_WRITE_SLOW] = "WRITE SLOW",
+    [STATE_WRITE_ERROR] = "WRITE ERROR",
+    [STATE_WRITE_LOCKUP] = "WRITE LOCKUP",
+    [STATE_READ_SUSPECT] = "READ SUSPECT",
+    [STATE_READ_OK] = "READ OK",
+    [STATE_READ_SLOW] = "READ SLOW",
+    [STATE_READ_ERROR] = "READ ERROR",
+    [STATE_READ_LOCKUP] = "READ LOCKUP",
+    [STATE_READ_DATA_ERROR] = "READ DATA ERROR",
+    [STATE_READ_SLOW_DATA_ERROR] = "READ SLOW DATA ERROR"
+};
+
+
+volatile enum phase_t phase = PHASE_WRITE;
+uint8_t* state;
+int totalsectors;
+int s;
+volatile int pass = 0;
+volatile int clean = 0;
+volatile int pwrcycles = 0;
+void* wrbuf;
+void* rdbuf;
+void* framebuf;
+bool done = false;
+bool paused = false;
+long lastbattcheck = 0;
+struct wakeup monitor_wakeup;
+struct wakeup join_wakeup;
+
+
+void mkfat32(void* buf, int sectors)
+{
+    uint32_t i, j, rc;
+    uint32_t rootdirclus = 2;
+    uint32_t secperclus = 1;
+    uint32_t fatsectors = 1;
+    uint32_t oldfatsectors = 0;
+    uint32_t clustercount;
+    uint32_t reserved = 2;
+    while (fatsectors != oldfatsectors)
+    {
+        oldfatsectors = fatsectors;
+        clustercount = (sectors - fatsectors - reserved) / secperclus;
+        fatsectors = (clustercount + 1025) >> 10;
+    }
+    uint32_t database = fatsectors + reserved;
+    uint32_t clusoffset = 0;
+    memset(buf, 0, 0x1000);
+    memcpy(buf, "\xeb\x58\x00MSWIN5.0\0\x10", 0xd);
+    ((uint8_t*)buf)[0xd] = secperclus;
+    ((uint16_t*)buf)[7] = reserved;
+    memcpy(&((uint8_t*)buf)[0x10], "\x01\0\0\0\0\xf8\0\0\x3f\0\xff", 0xb);
+    ((uint32_t*)buf)[8] = sectors;
+    ((uint32_t*)buf)[9] = fatsectors;
+    ((uint32_t*)buf)[0xb] = rootdirclus + clusoffset;
+    ((uint16_t*)buf)[0x18] = 1;
+    ((uint8_t*)buf)[0x40] = 0x80;
+    ((uint8_t*)buf)[0x42] = 0x29;
+    memcpy(&((uint8_t*)buf)[0x43], "\0\0\0\0iPodClassic", 0xf);
+    memcpy(&((uint8_t*)buf)[0x52], "FAT32   ", 8);
+    ((uint16_t*)buf)[0xff] = 0xaa55;
+    if (rc = storage_write_sectors_md(0, 0, 1, buf))
+        panicf(PANIC_KILLTHREAD, "Error writing MBR: %08X", rc);
+    memset(buf, 0, 0x1000);
+    ((uint32_t*)buf)[0] = 0x41615252;
+    ((uint32_t*)buf)[0x79] = 0x61417272;
+    ((uint32_t*)buf)[0x7a] = clustercount - 1;
+    ((uint32_t*)buf)[0x7b] = 2;
+    ((uint32_t*)buf)[0x7f] = 0xaa550000;
+    if (rc = storage_write_sectors_md(0, 1, 1, buf))
+        panicf(PANIC_KILLTHREAD, "Error writing FSINFO: %08X", rc);
+    uint32_t cursect = 0;
+    for (i = 0; i < fatsectors; i++)
+    {
+        memset(buf, 0, 0x1000);
+        if (!i) memcpy(buf, "\xf8\xff\xff\x0f\xff\xff\xff\xff\xff\xff\xff\x0f", 12);
+        if (rc = storage_write_sectors_md(0, reserved + i, 1, buf))
+            panicf(PANIC_KILLTHREAD, "Error writing FAT sector %d: %08X", i, rc);
+        s = i;
+    }
+    memset(buf, 0, secperclus * 0x1000);
+    memcpy(buf, "iPodClassic\x08", 12);
+    if (rc = storage_write_sectors_md(0, database, secperclus, buf))
+        panicf(PANIC_KILLTHREAD, "Error writing root directory sectors: %08X", i, rc);
+    free(buf);
+    disk_mount(0);
+}
+
+static void monitor()
+{
+    int i;
+    char textbuf[0x40];
+    int count[NUM_STATES];
+    bool done_latch = false;
+    while (!done_latch)
+    {
+        int y = 1;
+        memset(framebuf, 0xff, 320 * 240 * 3);
+        rendertext(framebuf, 6, y++ * 8, 320, 0xff000000, 0xffffffff,
+                   "HDD bad sector scanner v. " VERSION);
+        y++;
+        snprintf(textbuf, 0x40, "Pass %d (%d clean)", pass + 1, clean);
+        rendertext(framebuf, 6, y++ * 8, 320, 0xff000000, 0xffffffff, textbuf);
+        snprintf(textbuf, 0x40, "Phase: %s (%d of %d)",
+                 phasenames[phase], phase + 1, NUM_PHASES);
+        rendertext(framebuf, 6, y++ * 8, 320, 0xff000000, 0xffffffff, textbuf);
+        snprintf(textbuf, 0x40, "Processing sector %d of %d", s, totalsectors);
+        rendertext(framebuf, 6, y++ * 8, 320, 0xff000000, 0xffffffff, textbuf);
+        snprintf(textbuf, 0x40, "Hard resets needed: %d", pwrcycles);
+        rendertext(framebuf, 6, y++ * 8, 320, 0xff000000, 0xffffffff, textbuf);
+        y++;
+        rendertext(framebuf, 6, y++ * 8, 320, 0xff000000, 0xffffffff, "Sector counts:");
+        for (i = STATE_INITIAL; i < NUM_STATES; i++) count[i] = 0;
+        for (i = 0; i < totalsectors; i++) count[state[i] & 0xf]++;
+        for (i = STATE_INITIAL; i < NUM_STATES; i++)
+        {
+            snprintf(textbuf, 0x400, "%20s: %d", statenames[i], count[i]);
+            rendertext(framebuf, 6, y++ * 8, 320, 0xff000000, 0xffffffff, textbuf);
+        }
+        if (paused)
+        {
+            y++;
+            rendertext(framebuf, 6, y++ * 8, 320, 0xff000000, 0xffffffff, "Paused (low battery)");
+        }
+        displaylcd(0, 0, 320, 240, framebuf, 0, 0, 320);
+        done_latch = done;
+        if (!done_latch) wakeup_wait(&monitor_wakeup, 5000000);
+    }
+    wakeup_signal(&join_wakeup);
+}
+
+static int soft_reset()
+{
+    int rc = 0;
+    while (storage_soft_reset())
+    {
+        storage_sleep();
+        cputs(2, "LOCKUP!\n");
+        rc = -1;
+        pwrcycles++;
+        sleep(1000000);
+        storage_spin();
+    }
+    return rc;
+}
+
+static void checkbatt()
+{
+    if (USEC_TIMER - lastbattcheck > 30000000)
+    {
+        int percent = 0;
+        while (percent < 50)
+        {
+            percent = 100 * read_battery_mwh_current(0) / read_battery_mwh_full(0);
+            if (percent < 50)
+            {
+                paused = true;
+                sleep(10000000);
+            }
+        }
+        paused = false;
+        lastbattcheck = USEC_TIMER;
+    }
+}
+
+static bool is_good(int sector)
+{
+    return (state[sector] & 0xf) == STATE_READ_OK;
+}
+
+static void writestr(int fd, char* string)
+{
+    int len = strlen(string);
+    if (write(fd, string, len) != len)
+        panicf(PANIC_KILLTHREAD, "Failed to write to hddscan_summary.txt!");
+}
+
+static void main(int argc, const char** argv)
+{
+    int i, j;
+    int count[NUM_STATES];
+    char textbuf[0x80];
+    struct storage_info storageinfo;
+    storage_get_info(0, &storageinfo);
+    struct ata_target_driverinfo* drv = storageinfo.driverinfo;
+    drv->bbt_disable();
+    storage_get_info(0, &storageinfo);
+    totalsectors = storageinfo.num_sectors;
+    wakeup_init(&monitor_wakeup);
+    wakeup_init(&join_wakeup);
+    state = malloc(totalsectors);
+    memset(state, STATE_INITIAL, totalsectors);
+    cprintf(3, "State information at 0x%08X\n", state);
+    sleep(10000000);
+    framebuf = malloc(320 * 240 * 3);
+    sleep(1000000);
+    wrbuf = memalign(0x10, 0x1000);
+    sleep(1000000);
+    rdbuf = memalign(0x10, 0x1000);
+    sleep(1000000);
+    struct scheduler_thread* thread = thread_create(NULL, "HDD scanner monitor", monitor,
+                                                    NULL, 0x1000, USER_THREAD, 127, false);
+    sleep(1000000);
+    if (!state || !wrbuf || !rdbuf || !framebuf || !thread)
+    {
+    sleep(1000000);
+        if (thread) thread_terminate(thread);
+    sleep(1000000);
+        panicf(PANIC_KILLTHREAD, "Not enough RAM (need %d bytes)!",
+               totalsectors + 0x3400 + 320 * 240 * 3);
+    }
+    sleep(1000000);
+    memset(wrbuf, 0xa5, 0x1000);
+    sleep(1000000);
+    drv->set_retries(0);
+    drv->srst_after_error(false);
+    thread_resume(thread);
+    bool resetdone;
+    bool suspectmode;
+    long start;
+    long time;
+    int result;
+    int rstres;
+    int compare;
+    int newstate;
+    while (clean < 5 || phase != PHASE_WRITE)
+    {
+        switch (phase)
+        {
+        case PHASE_WRITE:
+            clean++;
+            for (s = 0; s < totalsectors; s++)
+            {
+                checkbatt();
+                switch (state[s] & 0xf)
+                {
+                case STATE_INITIAL:
+                case STATE_READ_OK:
+                    snprintf(wrbuf, 0x1000, "#HDDSCAN#SECTOR%8d#PASS%03d#", s, pass);
+                    start = USEC_TIMER;
+                    result = storage_write_sectors_md(0, s, 1, wrbuf);
+	                time = USEC_TIMER - start;
+                    if (result < 0 || time > 1000000)
+                    {
+                        if (soft_reset())
+                        {
+                            cprintf(2, "PASS %d WRITE %d RC %08X TIME %d LOCKUP!\n",
+                                    pass, s, result, time);
+                            clean = 0;
+                            newstate = STATE_WRITE_SUSPECT_LOCKUP;
+                        }
+                        else
+                        {
+                            cprintf(2, "PASS %d WRITE %d RC %08X TIME %d\n",
+                                    pass, s, result, time);
+                            if (clean > 1) newstate = STATE_READ_SUSPECT;
+                            else newstate = STATE_WRITE_SUSPECT;
+                        }
+                        i = s;
+                        j = 128;
+                        while (i && j)
+                        {
+                            if ((state[i] & 0xf) == STATE_WRITE_OK || i == s)
+                            {
+                                state[i] = (pass << 4) | newstate;
+                                j--;
+                            }
+                            i--;
+                        }
+                        if (newstate == STATE_READ_SUSPECT)
+                            state[s] = (pass << 4) | STATE_WRITE_SUSPECT;
+                    }
+                    else state[s] = (pass << 4) | STATE_WRITE_OK;
+                }
+            }
+            phase = PHASE_WRITE_SYNC;
+            break;
+        case PHASE_WRITE_SYNC:
+            soft_reset();
+            for (s = 0; s < totalsectors; s++)
+            {
+                checkbatt();
+                switch (state[s] & 0xf)
+                {
+                case STATE_WRITE_SUSPECT:
+                case STATE_WRITE_SUSPECT_LOCKUP:
+                    snprintf(wrbuf, 0x1000, "#HDDSCAN#SECTOR%8d#PASS%03d#", s, pass);
+                    start = USEC_TIMER;
+                    result = storage_write_sectors_md(0, s, 1, wrbuf);
+                    rstres = soft_reset();
+	                time = USEC_TIMER - start;
+                    if (rstres)
+                    {
+                        cprintf(2, "PASS %d WRITESYNC %d RC %08X TIME %d LOCKUP!\n",
+                                pass, s, result, time);
+                        clean = 0;
+                        newstate = STATE_WRITE_LOCKUP;
+                    }
+                    else if (result < 0 || time > 1000000)
+                    {
+                        cprintf(2, "PASS %d WRITESYNC %d RC %08X TIME %d\n",
+                                pass, s, result, time);
+                        clean = 0;
+                        if (result < 0) newstate = STATE_WRITE_ERROR;
+                        else newstate = STATE_WRITE_SLOW;
+                    }
+                    else newstate = STATE_WRITE_OK;
+                    state[s] = (pass << 4) | newstate;
+                }
+            }
+            phase = PHASE_READ;
+            break;
+        case PHASE_READ:
+            suspectmode = false;
+            for (s = 0; s < totalsectors; s++)
+            {
+                checkbatt();
+                switch (state[s] & 0xf)
+                {
+                case STATE_WRITE_OK:
+                    suspectmode = false;
+                case STATE_READ_SUSPECT:
+                    resetdone = false;
+                    snprintf(wrbuf, 0x1000, "#HDDSCAN#SECTOR%8d#PASS%03d#", s, pass);
+                    start = USEC_TIMER;
+                    result = storage_read_sectors_md(0, s, 1, rdbuf);
+	                time = USEC_TIMER - start;
+                    compare = memcmp(wrbuf, rdbuf, 0x1000);
+                    if (result < 0 || compare || time > 1000000)
+                    {
+                        clean = 0;
+                        if (result < 0 && soft_reset())
+                        {
+                            cprintf(2, "PASS %d READ %d RC %08X DATA %d TIME %d LOCKUP!\n",
+                                    pass, s, result, compare, time);
+                            newstate = STATE_READ_LOCKUP;
+                        }
+                        else
+                        {
+                            cprintf(2, "PASS %d READ %d RC %08X DATA %d TIME %d\n",
+                                    pass, s, result, compare, time);
+                            if (suspectmode) newstate = STATE_INITIAL;
+                            if (result < 0) newstate = STATE_READ_ERROR;
+                            else if (compare && time > 200000)
+                                newstate = STATE_READ_SLOW_DATA_ERROR;
+                            else if (compare) newstate = STATE_READ_DATA_ERROR;
+                            else newstate = STATE_READ_SLOW;
+                            if ((state[s] & 0xf) == STATE_READ_SUSPECT) suspectmode = true;
+                        }
+                    }
+                    else newstate = STATE_READ_OK;
+                    state[s] = (pass << 4) | newstate;
+                    break;
+                default:
+                    if (!resetdone) soft_reset();
+                    resetdone = true;
+                }
+            }
+            pass++;
+            phase = PHASE_WRITE;
+        }
+    }
+    free(rdbuf);
+    phase = PHASE_GENERATE_BBT;
+    s = 0;
+    int l0count = (totalsectors + 0xfffff) >> 19;
+    int l1count;
+    int l2count;
+    int l3count;
+    int logical;
+    int bbtpages = 64 + ((l0count + 0x3f) & ~0x3f);
+    int bbtsize;
+    int bbtgood;
+    uint16_t (*bbt)[0x20];
+    bool success = false;
+    while (bbtpages <= 32832)
+    {
+        bbtsize = bbtpages << 6;
+        l0count = (totalsectors - bbtsize + 0xfffff) >> 19;
+        bbt = memalign(0x10, bbtsize);
+        if (!bbt) panicf(PANIC_KILLTHREAD, "Failed to allocate memory for BBT!");
+        memset(bbt, 0, bbtsize);
+        logical = 0;
+        int physical = 1;
+        int remapbase;
+        for (bbtgood = 0; bbtgood < (bbtpages >> 6) - 1; physical++)
+            if (is_good(physical))
+            {
+                ((uint32_t*)bbt)[0x200 + bbtgood] = physical;
+                bbtgood++;
+            }
+        int bbtused = 64 + l0count;
+        int level;
+        uint16_t *l1, *l2, *l3;
+        l1count = 0;
+        l2count = 0;
+        l3count = 0;
+        while (!success)
+        {
+            if (!(logical & 0x7fff)) level = 0;
+            else if (!(logical & 0x3ff)) level = 1;
+            else if (!(logical & 0x1f)) level = 2;
+            else level = 3;
+            if (!level) remapbase = (physical - logical) & ~0xfff;
+            if (physical - logical - remapbase > 0x7fff || remapbase > 0xffff000)
+                panicf(PANIC_KILLTHREAD, "Failed to generate BBT: "
+                       "Need to remap across too high distance!");
+            int clean;
+            for (clean = 0; clean < (1 << ((3 - level) * 5))
+                         && physical + clean < totalsectors; clean++)
+                if (!is_good(physical + clean))
+                    break;
+            if (clean >= 32768)
+            {
+                bbt[64][(logical >> 15) << 1] = physical - logical - remapbase;
+                bbt[64][((logical >> 15) << 1) | 1] = remapbase >> 12;
+                physical += 32768;
+                logical += 32768;
+            }
+            else if (clean >= 1024)
+            {
+                if (level == 0)
+                {
+                    if (bbtused == bbtpages) break;
+                    level = 1;
+                    l1 = bbt[bbtused];
+                    bbt[64][(logical >> 15) << 1] = 0x8000 | (bbtused - 64);
+                    bbt[64][((logical >> 15) << 1) | 1] = remapbase >> 12;
+                    bbtused++;
+                    l1count++;
+                }
+                l1[(logical >> 10) & 0x1f] = physical - logical - remapbase;
+                physical += 1024;
+                logical += 1024;
+            }
+            else if (clean >= 32)
+            {
+                if (level == 0)
+                {
+                    if (bbtused == bbtpages) break;
+                    level = 1;
+                    l1 = bbt[bbtused];
+                    bbt[64][(logical >> 15) << 1] = 0x8000 | (bbtused - 64);
+                    bbt[64][((logical >> 15) << 1) | 1] = remapbase >> 12;
+                    bbtused++;
+                    l1count++;
+                }
+                if (level == 1)
+                {
+                    if (bbtused == bbtpages) break;
+                    level = 2;
+                    l2 = bbt[bbtused];
+                    l1[(logical >> 10) & 0x1f] = 0x8000 | (bbtused - 64);
+                    bbtused++;
+                    l2count++;
+                }
+                l2[(logical >> 5) & 0x1f] = physical - logical - remapbase;
+                physical += 32;
+                logical += 32;
+            }
+            else if (clean >= 1)
+            {
+                if (level == 0)
+                {
+                    if (bbtused == bbtpages) break;
+                    level = 1;
+                    l1 = bbt[bbtused];
+                    bbt[64][(logical >> 15) << 1] = 0x8000 | (bbtused - 64);
+                    bbt[64][((logical >> 15) << 1) | 1] = remapbase >> 12;
+                    bbtused++;
+                    l1count++;
+                }
+                if (level == 1)
+                {
+                    if (bbtused == bbtpages) break;
+                    level = 2;
+                    l2 = bbt[bbtused];
+                    l1[(logical >> 10) & 0x1f] = 0x8000 | (bbtused - 64);
+                    bbtused++;
+                    l2count++;
+                }
+                if (level == 2)
+                {
+                    if (bbtused == bbtpages) break;
+                    level = 3;
+                    l3 = bbt[bbtused];
+                    l2[(logical >> 5) & 0x1f] = 0x8000 | (bbtused - 64);
+                    bbtused++;
+                    l3count++;
+                }
+                l3[logical & 0x1f] = physical - logical - remapbase;
+                physical++;
+                logical++;
+            }
+            else physical++;
+            if (physical >= totalsectors) success = true;
+            s = physical;
+        }
+        if (success)
+        {        
+            memcpy(bbt, "emBIbbth", 8);
+            ((uint32_t*)bbt)[0x1fc] = logical;
+            ((uint32_t*)bbt)[0x1ff] = bbtgood;
+            break;
+        }
+        free(bbt);
+        bbtpages += 64;
+    }
+    if (!success) panicf(PANIC_KILLTHREAD, "Can't fit BBT into 2052 KiB!");
+    phase = PHASE_WRITE_BBT;
+    s = 0;
+    drv->srst_after_error(true);
+    drv->set_retries(3);
+    result = storage_write_sectors_md(0, 0, 1, bbt);
+    if (result < 0) panicf(PANIC_KILLTHREAD, "Failed to write BBT sector 0!");
+    for (i = 0; i < bbtgood; i++)
+    {
+        storage_write_sectors_md(0, ((uint32_t*)bbt)[0x200 + i], 1, &bbt[(i + 1) * 0x40]);
+        if (result < 0) panicf(PANIC_KILLTHREAD, "Failed to write BBT sector %d!", i);
+        s = i;
+    }
+    drv->bbt_reload();
+    phase = PHASE_FORMAT;
+    s = 0;
+    mkfat32(wrbuf, logical);
+    free(wrbuf);
+    phase = PHASE_WRITE_RESULT;
+    s = 0;
+    for (i = STATE_INITIAL; i < NUM_STATES; i++) count[i] = 0;
+    for (i = 0; i < totalsectors; i++) count[state[i] & 0xf]++;
+    int fd = file_creat("/hddscan_result.bin");
+    if (fd < 0) panicf(PANIC_KILLTHREAD, "Failed to create hddscan_result.bin");
+    if (write(fd, state, totalsectors) != totalsectors)
+        panicf(PANIC_KILLTHREAD, "Failed to write to hddscan_result.bin!");
+    close(fd);
+    s = 1;
+    fd = file_creat("/hddscan_bbt.bin");
+    if (fd < 0) panicf(PANIC_KILLTHREAD, "Failed to create hddscan_bbt.bin");
+    if (write(fd, bbt, bbtsize) != bbtsize)
+        panicf(PANIC_KILLTHREAD, "Failed to write to hddscan_bbt.bin!");
+    close(fd);
+    free(bbt);
+    s = 2;
+    fd = file_creat("/hddscan_summary.txt");
+    writestr(fd, "HDD bad sector scanner v. " VERSION "\n\n");
+    snprintf(textbuf, 0x80, "Finished after pass %d (%d clean)\n", pass, clean);
+    writestr(fd, textbuf);
+    snprintf(textbuf, 0x80, "%d out of %d sectors bad\n",
+             totalsectors - count[STATE_READ_OK], totalsectors);
+    writestr(fd, textbuf);
+    snprintf(textbuf, 0x80, "Hard resets needed: %d\n", pwrcycles);
+    writestr(fd, textbuf);
+    writestr(fd, "\nSector counts:\n");
+    for (i = STATE_INITIAL; i < NUM_STATES; i++)
+    {
+        snprintf(textbuf, 0x400, "%20s: %d\n", statenames[i], count[i]);
+        writestr(fd, textbuf);
+    }
+    snprintf(textbuf, 0x80, "\nBBT using %d sectors (%d KiB)\n", bbtgood + 1, bbtsize >> 10);
+    writestr(fd, textbuf);
+    snprintf(textbuf, 0x80, "Level 0: %d pages, Level 1: %d pages, Level 2: %d pages, "
+                            "Level 3: %d pages\n", l0count, l1count, l2count, l3count);
+    writestr(fd, textbuf);
+    snprintf(textbuf, 0x80, "User data sectors: %d (%d KiB)\n", logical, logical << 2);
+    writestr(fd, textbuf);
+    close(fd);
+    s = 3;
+    phase = PHASE_FINISHED;
+    s = 0;
+    done = true;
+    wakeup_signal(&monitor_wakeup);
+    wakeup_wait(&join_wakeup, TIMEOUT_BLOCK);
+    free(state);
+    free(framebuf);
+}
+
+EMCORE_APP_HEADER("HDD scanner", main, 63)
+
Index: testapps/hddscan/Makefile
===================================================================
--- testapps/hddscan/Makefile	(revision 0)
+++ testapps/hddscan/Makefile	(revision 0)
@@ -0,0 +1,120 @@
+NAME := hddscan
+STACKSIZE := 8192
+COMPRESS := true
+
+EMCOREDIR ?= ../../emcore/trunk/
+
+ifeq ($(shell uname),WindowsNT)
+CCACHE :=
+else
+CCACHE := $(shell which ccache)
+endif
+
+CROSS   ?= arm-elf-eabi-
+CC      := $(CCACHE) $(CROSS)gcc
+AS      := $(CROSS)as
+LD      := $(CROSS)ld
+OBJCOPY := $(CROSS)objcopy
+ELF2ECA := $(CROSS)elf2emcoreapp
+
+LIBINCLUDES := 
+
+CFLAGS  += -Os -fno-pie -fno-stack-protector -fomit-frame-pointer -I. -I$(EMCOREDIR)/export $(LIBINCLUDES) -ffunction-sections -fdata-sections -mcpu=arm940t -DARM_ARCH=4
+LDFLAGS += "$(shell $(CC) -print-libgcc-file-name)" --emit-relocs --gc-sections
+
+preprocess = $(shell $(CC) $(PPCFLAGS) $(2) -E -P -x c $(1) | grep -v "^\#")
+preprocesspaths = $(shell $(CC) $(PPCFLAGS) $(2) -E -P -x c $(1) | grep -v "^\#" | sed -e "s:^..*:$(dir $(1))&:" | sed -e "s:^\\./::")
+
+REVISION := $(shell svnversion .)
+REVISIONINT := $(shell echo $(REVISION) | sed -e "s/[^0-9].*$$//")
+
+HELPERS := build/__emcore_armhelpers.o
+
+SRC := $(call preprocesspaths,SOURCES,-I. -I..)
+OBJ := $(SRC:%.c=build/%.o)
+OBJ := $(OBJ:%.S=build/%.o) $(HELPERS)
+
+all: $(NAME)
+
+-include $(OBJ:%=%.dep)
+
+$(NAME): build/$(NAME).emcoreapp
+
+build/$(NAME).emcoreapp: build/$(NAME).elf
+	@echo [EMCAPP] $<
+ifeq ($(COMPRESS),true)
+	@$(ELF2ECA) -z -s $(STACKSIZE) -o $@ $^
+else
+	@$(ELF2ECA) -s $(STACKSIZE) -o $@ $^
+endif
+
+build/$(NAME).elf: ls.x $(OBJ)
+	@echo [LD]     $@
+	@$(LD) $(LDFLAGS) -o $@ -T ls.x $(OBJ)
+
+build/%.o: %.c build/version.h
+	@echo [CC]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
+else
+	@-mkdir -p $(dir $@)
+endif
+	@$(CC) -c $(CFLAGS) -o $@ $<
+	@$(CC) -MM $(CFLAGS) $< > $@.dep.tmp
+	@sed -e "s|.*:|$@:|" < $@.dep.tmp > $@.dep
+ifeq ($(shell uname),WindowsNT)
+	@sed -e "s/.*://" -e "s/\\$$//" < $@.dep.tmp | fmt -1 | sed -e "s/^ *//" -e "s/$$/:/" >> $@.dep
+else
+	@sed -e 's/.*://' -e 's/\\$$//' < $@.dep.tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $@.dep
+endif
+	@rm -f $@.dep.tmp
+
+build/%.o: %.S build/version.h
+	@echo [CC]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
+else
+	@-mkdir -p $(dir $@)
+endif
+	@$(CC) -c $(CFLAGS) -o $@ $<
+	@$(CC) -MM $(CFLAGS) $< > $@.dep.tmp
+	@sed -e "s|.*:|$@:|" < $@.dep.tmp > $@.dep
+ifeq ($(shell uname),WindowsNT)
+	@sed -e "s/.*://" -e "s/\\$$//" < $@.dep.tmp | fmt -1 | sed -e "s/^ *//" -e "s/$$/:/" >> $@.dep
+else
+	@sed -e 's/.*://' -e 's/\\$$//' < $@.dep.tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $@.dep
+endif
+	@rm -f $@.dep.tmp
+
+build/__emcore_%.o: $(EMCOREDIR)/export/%.c
+	@echo [CC]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
+else
+	@-mkdir -p $(dir $@)
+endif
+	@$(CC) -c $(CFLAGS) -o $@ $<
+
+build/__emcore_%.o: $(EMCOREDIR)/export/%.S
+	@echo [CC]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
+else
+	@-mkdir -p $(dir $@)
+endif
+	@$(CC) -c $(CFLAGS) -o $@ $<
+
+build/version.h: version.h .svn/entries
+	@echo [PP]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist build md build
+	@sed -e "s/\$$REVISION\$$/$(REVISION)/" -e "s/\$$REVISIONINT\$$/$(REVISIONINT)/" < $< > $@
+else
+	@-mkdir -p build
+	@sed -e 's/\$$REVISION\$$/$(REVISION)/' -e 's/\$$REVISIONINT\$$/$(REVISIONINT)/' < $< > $@
+endif
+
+clean:
+	@rm -rf build
+
+.PHONY: all clean $(NAME)
Index: testapps/hddscan/SOURCES
===================================================================
--- testapps/hddscan/SOURCES	(revision 0)
+++ testapps/hddscan/SOURCES	(revision 0)
@@ -0,0 +1 @@
+main.c
Index: testapps/hddscan/version.h
===================================================================
--- testapps/hddscan/version.h	(revision 0)
+++ testapps/hddscan/version.h	(revision 0)
@@ -0,0 +1,36 @@
+//
+//
+//    Copyright 2010 TheSeven
+//
+//
+//    This file is part of emCORE.
+//
+//    emCORE is free software: you can 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.
+//
+//    emCORE is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+//
+//    You should have received a copy of the GNU General Public License along
+//    with emCORE.  If not, see <http://www.gnu.org/licenses/>.
+//
+//
+
+
+#ifndef __VERSION_H__
+#define __VERSION_H__
+
+
+#define VERSION "0.0.1pre"
+#define VERSION_MAJOR 0
+#define VERSION_MINOR 0
+#define VERSION_PATCH 1
+#define VERSION_SVN "$REVISION$"
+#define VERSION_SVN_INT $REVISIONINT$
+
+
+#endif
\ No newline at end of file
Index: testapps/pngtest/ls.x
===================================================================
--- testapps/pngtest/ls.x	(revision 0)
+++ testapps/pngtest/ls.x	(revision 0)
@@ -0,0 +1,42 @@
+ENTRY(__emcore_entrypoint)
+OUTPUT_FORMAT(elf32-littlearm)
+OUTPUT_ARCH(arm)
+
+MEMORY
+{
+    VIRTUAL : ORIGIN = 0x00000000, LENGTH = 0x10000000
+}
+
+SECTIONS
+{
+    .text :
+    {
+        __emcore_app_base = .;
+	KEEP(.emcoreentrypoint*)
+	*(.emcoreentrypoint*)
+        *(.text*)
+        *(.glue_7)
+        *(.glue_7t)
+        . = ALIGN(0x10);
+    } > VIRTUAL
+
+    .data :
+    {
+        *(.rodata*)
+        . = ALIGN(0x4);
+        *(.data*)
+        . = ALIGN(0x10);
+    } > VIRTUAL
+
+    .bss (NOLOAD) :
+    {
+        *(.bss*)
+        *(COMMON)
+    } > VIRTUAL
+
+    /DISCARD/ :
+    {
+        *(.eh_frame)
+    }
+
+}
Index: testapps/pngtest/main.c
===================================================================
--- testapps/pngtest/main.c	(revision 0)
+++ testapps/pngtest/main.c	(revision 0)
@@ -0,0 +1,68 @@
+//
+//
+//    Copyright 2011 TheSeven
+//
+//
+//    This file is part of emCORE.
+//
+//    emCORE is free software: you can 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.
+//
+//    emCORE is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+//
+//    You should have received a copy of the GNU General Public License along
+//    with emCORE.  If not, see <http://www.gnu.org/licenses/>.
+//
+//
+
+
+#include "emcoreapp.h"
+#include "libpng.h"
+#include "libui.h"
+
+
+static void main(int argc, const char** argv)
+{
+    struct emcorelib_header* libpng = get_library(LIBPNG_IDENTIFIER, LIBPNG_API_VERSION, LIBSOURCE_BOOTFLASH, "libpng  ");
+    if (!libpng) panicf(PANIC_KILLTHREAD, "Could not load PNG decoder library!");
+    struct libpng_api* png = (struct libpng_api*)libpng->api;
+//    struct emcorelib_header* libui = get_library(LIBUI_IDENTIFIER, LIBUI_API_VERSION, LIBSOURCE_BOOTFLASH, "libui   ");
+//    if (!libui) panicf(PANIC_KILLTHREAD, "Could not load user interface library!");
+//    struct libui_api* ui = (struct libui_api*)libui->api;
+    int fd = file_open("/test.png", O_RDONLY);
+    if (fd <= 0) panicf(PANIC_KILLTHREAD, "Could not open test.png!");
+    int size = filesize(fd);
+    if (size < 0) panicf(PANIC_KILLTHREAD, "Could not get test.png file size!");
+    void* buf = memalign(0x10, size);
+    if (!buf) panicf(PANIC_KILLTHREAD, "Could not allocate memory for test.png!");
+    if (read(fd, buf, size) != size) panicf(PANIC_KILLTHREAD, "Could not read test.png!");
+    close(fd);
+    struct png_info* handle = png->png_open(buf, size);
+    if (!handle) panicf(PANIC_KILLTHREAD, "Could not parse test.png!");
+    int width = png->png_get_width(handle);
+    int height = png->png_get_height(handle);
+    cprintf(3, "Image dimensions: %dx%d\n", width, height);
+    struct png_rgb* decoded = png->png_decode_rgb(handle);
+    if (!decoded) panicf(PANIC_KILLTHREAD, "Could not decode test.png!");
+    png->png_destroy(handle);
+    free(buf);
+    int lcdwidth = lcd_get_width();
+    int lcdheight = lcd_get_height();
+    int displaywidth = MIN(lcdwidth, width);
+    int displayheight = MIN(lcdheight, height);
+    int xoffset = (lcdwidth - displaywidth) / 2;
+    int yoffset = (lcdheight - displayheight) / 2;
+    displaylcd(xoffset, yoffset, displaywidth, displayheight, decoded, 0, 0, width);
+//    release_library(libui);
+    release_library(libpng);
+//    library_unload(libui);
+    library_unload(libpng);
+}
+
+
+EMCORE_APP_HEADER("PNG decoder test", main, 127)
Index: testapps/pngtest/Makefile
===================================================================
--- testapps/pngtest/Makefile	(revision 0)
+++ testapps/pngtest/Makefile	(revision 0)
@@ -0,0 +1,122 @@
+NAME := pngtest
+STACKSIZE := 4096
+COMPRESS := true
+
+EMCOREDIR ?= ../../emcore/trunk/
+LIBPNGDIR ?= ../../libs/png/
+LIBUIDIR ?= ../../libs/ui/
+
+ifeq ($(shell uname),WindowsNT)
+CCACHE :=
+else
+CCACHE := $(shell which ccache)
+endif
+
+CROSS   ?= arm-elf-eabi-
+CC      := $(CCACHE) $(CROSS)gcc
+AS      := $(CROSS)as
+LD      := $(CROSS)ld
+OBJCOPY := $(CROSS)objcopy
+ELF2ECA := $(CROSS)elf2emcoreapp
+
+LIBINCLUDES := -I$(LIBPNGDIR)/export -I$(LIBUIDIR)/export
+
+CFLAGS  += -Os -fno-pie -fno-stack-protector -fomit-frame-pointer -I. -I$(EMCOREDIR)/export $(LIBINCLUDES) -ffunction-sections -fdata-sections -mcpu=arm940t -DARM_ARCH=4
+LDFLAGS += "$(shell $(CC) -print-libgcc-file-name)" --emit-relocs --gc-sections
+
+preprocess = $(shell $(CC) $(PPCFLAGS) $(2) -E -P -x c $(1) | grep -v "^\#")
+preprocesspaths = $(shell $(CC) $(PPCFLAGS) $(2) -E -P -x c $(1) | grep -v "^\#" | sed -e "s:^..*:$(dir $(1))&:" | sed -e "s:^\\./::")
+
+REVISION := $(shell svnversion .)
+REVISIONINT := $(shell echo $(REVISION) | sed -e "s/[^0-9].*$$//")
+
+HELPERS := build/__emcore_armhelpers.o
+
+SRC := $(call preprocesspaths,SOURCES,-I. -I..)
+OBJ := $(SRC:%.c=build/%.o)
+OBJ := $(OBJ:%.S=build/%.o) $(HELPERS)
+
+all: $(NAME)
+
+-include $(OBJ:%=%.dep)
+
+$(NAME): build/$(NAME).emcoreapp
+
+build/$(NAME).emcoreapp: build/$(NAME).elf
+	@echo [EMCAPP] $<
+ifeq ($(COMPRESS),true)
+	@$(ELF2ECA) -z -s $(STACKSIZE) -o $@ $^
+else
+	@$(ELF2ECA) -s $(STACKSIZE) -o $@ $^
+endif
+
+build/$(NAME).elf: ls.x $(OBJ)
+	@echo [LD]     $@
+	@$(LD) $(LDFLAGS) -o $@ -T ls.x $(OBJ)
+
+build/%.o: %.c build/version.h
+	@echo [CC]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
+else
+	@-mkdir -p $(dir $@)
+endif
+	@$(CC) -c $(CFLAGS) -o $@ $<
+	@$(CC) -MM $(CFLAGS) $< > $@.dep.tmp
+	@sed -e "s|.*:|$@:|" < $@.dep.tmp > $@.dep
+ifeq ($(shell uname),WindowsNT)
+	@sed -e "s/.*://" -e "s/\\$$//" < $@.dep.tmp | fmt -1 | sed -e "s/^ *//" -e "s/$$/:/" >> $@.dep
+else
+	@sed -e 's/.*://' -e 's/\\$$//' < $@.dep.tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $@.dep
+endif
+	@rm -f $@.dep.tmp
+
+build/%.o: %.S build/version.h
+	@echo [CC]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
+else
+	@-mkdir -p $(dir $@)
+endif
+	@$(CC) -c $(CFLAGS) -o $@ $<
+	@$(CC) -MM $(CFLAGS) $< > $@.dep.tmp
+	@sed -e "s|.*:|$@:|" < $@.dep.tmp > $@.dep
+ifeq ($(shell uname),WindowsNT)
+	@sed -e "s/.*://" -e "s/\\$$//" < $@.dep.tmp | fmt -1 | sed -e "s/^ *//" -e "s/$$/:/" >> $@.dep
+else
+	@sed -e 's/.*://' -e 's/\\$$//' < $@.dep.tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $@.dep
+endif
+	@rm -f $@.dep.tmp
+
+build/__emcore_%.o: $(EMCOREDIR)/export/%.c
+	@echo [CC]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
+else
+	@-mkdir -p $(dir $@)
+endif
+	@$(CC) -c $(CFLAGS) -o $@ $<
+
+build/__emcore_%.o: $(EMCOREDIR)/export/%.S
+	@echo [CC]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
+else
+	@-mkdir -p $(dir $@)
+endif
+	@$(CC) -c $(CFLAGS) -o $@ $<
+
+build/version.h: version.h .svn/entries
+	@echo [PP]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist build md build
+	@sed -e "s/\$$REVISION\$$/$(REVISION)/" -e "s/\$$REVISIONINT\$$/$(REVISIONINT)/" < $< > $@
+else
+	@-mkdir -p build
+	@sed -e 's/\$$REVISION\$$/$(REVISION)/' -e 's/\$$REVISIONINT\$$/$(REVISIONINT)/' < $< > $@
+endif
+
+clean:
+	@rm -rf build
+
+.PHONY: all clean $(NAME)
Index: testapps/pngtest/SOURCES
===================================================================
--- testapps/pngtest/SOURCES	(revision 0)
+++ testapps/pngtest/SOURCES	(revision 0)
@@ -0,0 +1 @@
+main.c
Index: testapps/pngtest/version.h
===================================================================
--- testapps/pngtest/version.h	(revision 0)
+++ testapps/pngtest/version.h	(revision 0)
@@ -0,0 +1,36 @@
+//
+//
+//    Copyright 2010 TheSeven
+//
+//
+//    This file is part of emCORE.
+//
+//    emCORE is free software: you can 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.
+//
+//    emCORE is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+//
+//    You should have received a copy of the GNU General Public License along
+//    with emCORE.  If not, see <http://www.gnu.org/licenses/>.
+//
+//
+
+
+#ifndef __VERSION_H__
+#define __VERSION_H__
+
+
+#define VERSION "0.0.1pre"
+#define VERSION_MAJOR 0
+#define VERSION_MINOR 0
+#define VERSION_PATCH 1
+#define VERSION_SVN "$REVISION$"
+#define VERSION_SVN_INT $REVISIONINT$
+
+
+#endif
\ No newline at end of file
Index: testapps/synopsysoff/ls.x
===================================================================
--- testapps/synopsysoff/ls.x	(revision 0)
+++ testapps/synopsysoff/ls.x	(revision 0)
@@ -0,0 +1,42 @@
+ENTRY(__emcore_entrypoint)
+OUTPUT_FORMAT(elf32-littlearm)
+OUTPUT_ARCH(arm)
+
+MEMORY
+{
+    VIRTUAL : ORIGIN = 0x00000000, LENGTH = 0x10000000
+}
+
+SECTIONS
+{
+    .text :
+    {
+        __emcore_app_base = .;
+	KEEP(.emcoreentrypoint*)
+	*(.emcoreentrypoint*)
+        *(.text*)
+        *(.glue_7)
+        *(.glue_7t)
+        . = ALIGN(0x10);
+    } > VIRTUAL
+
+    .data :
+    {
+        *(.rodata*)
+        . = ALIGN(0x4);
+        *(.data*)
+        . = ALIGN(0x10);
+    } > VIRTUAL
+
+    .bss (NOLOAD) :
+    {
+        *(.bss*)
+        *(COMMON)
+    } > VIRTUAL
+
+    /DISCARD/ :
+    {
+        *(.eh_frame)
+    }
+
+}
Index: testapps/synopsysoff/main.c
===================================================================
--- testapps/synopsysoff/main.c	(revision 0)
+++ testapps/synopsysoff/main.c	(revision 0)
@@ -0,0 +1,46 @@
+//
+//
+//    Copyright 2011 TheSeven
+//
+//
+//    This file is part of emCORE.
+//
+//    emCORE is free software: you can 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.
+//
+//    emCORE is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+//
+//    You should have received a copy of the GNU General Public License along
+//    with emCORE.  If not, see <http://www.gnu.org/licenses/>.
+//
+//
+
+
+#include "emcoreapp.h"
+
+
+#define OTGBASE 0x38400000
+#define PHYBASE 0x3C400000
+#define OPHYPWR     (*((uint32_t volatile*)(PHYBASE + 0x000)))
+#define ORSTCON     (*((uint32_t volatile*)(PHYBASE + 0x008)))
+#define DCTL        (*((uint32_t volatile*)(OTGBASE + 0x804)))
+#define PCGCCTL     (*((uint32_t volatile*)(OTGBASE + 0xE00)))
+
+
+static void main(int argc, const char** argv)
+{
+    DCTL = 0x802;
+    ORSTCON = 1;
+    PCGCCTL = 1;
+    OPHYPWR = 0xF;
+    clockgate_enable(2, false);
+    clockgate_enable(35, false);
+}
+
+
+EMCORE_APP_HEADER("Synopsys power off", main, 127)
Index: testapps/synopsysoff/Makefile
===================================================================
--- testapps/synopsysoff/Makefile	(revision 0)
+++ testapps/synopsysoff/Makefile	(revision 0)
@@ -0,0 +1,120 @@
+NAME := synopsysoff
+STACKSIZE := 4096
+COMPRESS := true
+
+EMCOREDIR ?= ../../emcore/trunk/
+
+ifeq ($(shell uname),WindowsNT)
+CCACHE :=
+else
+CCACHE := $(shell which ccache)
+endif
+
+CROSS   ?= arm-elf-eabi-
+CC      := $(CCACHE) $(CROSS)gcc
+AS      := $(CROSS)as
+LD      := $(CROSS)ld
+OBJCOPY := $(CROSS)objcopy
+ELF2ECA := $(CROSS)elf2emcoreapp
+
+LIBINCLUDES := 
+
+CFLAGS  += -Os -fno-pie -fno-stack-protector -fomit-frame-pointer -I. -I$(EMCOREDIR)/export $(LIBINCLUDES) -ffunction-sections -fdata-sections -mcpu=arm940t -DARM_ARCH=4
+LDFLAGS += "$(shell $(CC) -print-libgcc-file-name)" --emit-relocs --gc-sections
+
+preprocess = $(shell $(CC) $(PPCFLAGS) $(2) -E -P -x c $(1) | grep -v "^\#")
+preprocesspaths = $(shell $(CC) $(PPCFLAGS) $(2) -E -P -x c $(1) | grep -v "^\#" | sed -e "s:^..*:$(dir $(1))&:" | sed -e "s:^\\./::")
+
+REVISION := $(shell svnversion .)
+REVISIONINT := $(shell echo $(REVISION) | sed -e "s/[^0-9].*$$//")
+
+HELPERS := build/__emcore_armhelpers.o
+
+SRC := $(call preprocesspaths,SOURCES,-I. -I..)
+OBJ := $(SRC:%.c=build/%.o)
+OBJ := $(OBJ:%.S=build/%.o) $(HELPERS)
+
+all: $(NAME)
+
+-include $(OBJ:%=%.dep)
+
+$(NAME): build/$(NAME).emcoreapp
+
+build/$(NAME).emcoreapp: build/$(NAME).elf
+	@echo [EMCAPP] $<
+ifeq ($(COMPRESS),true)
+	@$(ELF2ECA) -z -s $(STACKSIZE) -o $@ $^
+else
+	@$(ELF2ECA) -s $(STACKSIZE) -o $@ $^
+endif
+
+build/$(NAME).elf: ls.x $(OBJ)
+	@echo [LD]     $@
+	@$(LD) $(LDFLAGS) -o $@ -T ls.x $(OBJ)
+
+build/%.o: %.c build/version.h
+	@echo [CC]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
+else
+	@-mkdir -p $(dir $@)
+endif
+	@$(CC) -c $(CFLAGS) -o $@ $<
+	@$(CC) -MM $(CFLAGS) $< > $@.dep.tmp
+	@sed -e "s|.*:|$@:|" < $@.dep.tmp > $@.dep
+ifeq ($(shell uname),WindowsNT)
+	@sed -e "s/.*://" -e "s/\\$$//" < $@.dep.tmp | fmt -1 | sed -e "s/^ *//" -e "s/$$/:/" >> $@.dep
+else
+	@sed -e 's/.*://' -e 's/\\$$//' < $@.dep.tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $@.dep
+endif
+	@rm -f $@.dep.tmp
+
+build/%.o: %.S build/version.h
+	@echo [CC]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
+else
+	@-mkdir -p $(dir $@)
+endif
+	@$(CC) -c $(CFLAGS) -o $@ $<
+	@$(CC) -MM $(CFLAGS) $< > $@.dep.tmp
+	@sed -e "s|.*:|$@:|" < $@.dep.tmp > $@.dep
+ifeq ($(shell uname),WindowsNT)
+	@sed -e "s/.*://" -e "s/\\$$//" < $@.dep.tmp | fmt -1 | sed -e "s/^ *//" -e "s/$$/:/" >> $@.dep
+else
+	@sed -e 's/.*://' -e 's/\\$$//' < $@.dep.tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $@.dep
+endif
+	@rm -f $@.dep.tmp
+
+build/__emcore_%.o: $(EMCOREDIR)/export/%.c
+	@echo [CC]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
+else
+	@-mkdir -p $(dir $@)
+endif
+	@$(CC) -c $(CFLAGS) -o $@ $<
+
+build/__emcore_%.o: $(EMCOREDIR)/export/%.S
+	@echo [CC]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist $(subst /,\,$(dir $@)) md $(subst /,\,$(dir $@))
+else
+	@-mkdir -p $(dir $@)
+endif
+	@$(CC) -c $(CFLAGS) -o $@ $<
+
+build/version.h: version.h .svn/entries
+	@echo [PP]     $<
+ifeq ($(shell uname),WindowsNT)
+	@-if not exist build md build
+	@sed -e "s/\$$REVISION\$$/$(REVISION)/" -e "s/\$$REVISIONINT\$$/$(REVISIONINT)/" < $< > $@
+else
+	@-mkdir -p build
+	@sed -e 's/\$$REVISION\$$/$(REVISION)/' -e 's/\$$REVISIONINT\$$/$(REVISIONINT)/' < $< > $@
+endif
+
+clean:
+	@rm -rf build
+
+.PHONY: all clean $(NAME)
Index: testapps/synopsysoff/SOURCES
===================================================================
--- testapps/synopsysoff/SOURCES	(revision 0)
+++ testapps/synopsysoff/SOURCES	(revision 0)
@@ -0,0 +1 @@
+main.c
Index: testapps/synopsysoff/version.h
===================================================================
--- testapps/synopsysoff/version.h	(revision 0)
+++ testapps/synopsysoff/version.h	(revision 0)
@@ -0,0 +1,36 @@
+//
+//
+//    Copyright 2010 TheSeven
+//
+//
+//    This file is part of emCORE.
+//
+//    emCORE is free software: you can 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.
+//
+//    emCORE is distributed in the hope that it will be useful,
+//    but WITHOUT ANY WARRANTY; without even the implied warranty of
+//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+//    See the GNU General Public License for more details.
+//
+//    You should have received a copy of the GNU General Public License along
+//    with emCORE.  If not, see <http://www.gnu.org/licenses/>.
+//
+//
+
+
+#ifndef __VERSION_H__
+#define __VERSION_H__
+
+
+#define VERSION "0.0.1pre"
+#define VERSION_MAJOR 0
+#define VERSION_MINOR 0
+#define VERSION_PATCH 1
+#define VERSION_SVN "$REVISION$"
+#define VERSION_SVN_INT $REVISIONINT$
+
+
+#endif
\ No newline at end of file
