summaryrefslogtreecommitdiffstats
path: root/utils/hwstub/stub
diff options
context:
space:
mode:
Diffstat (limited to 'utils/hwstub/stub')
-rw-r--r--utils/hwstub/stub/SOURCES12
-rw-r--r--utils/hwstub/stub/config.h49
-rw-r--r--utils/hwstub/stub/crt0.S17
-rw-r--r--utils/hwstub/stub/format.c223
-rw-r--r--utils/hwstub/stub/format.h29
-rw-r--r--utils/hwstub/stub/hwstub.lds71
-rw-r--r--utils/hwstub/stub/hwstub.make49
-rw-r--r--utils/hwstub/stub/logf.c69
-rw-r--r--utils/hwstub/stub/logf.h31
-rw-r--r--utils/hwstub/stub/memcpy.S176
-rw-r--r--utils/hwstub/stub/memmove.S190
-rw-r--r--utils/hwstub/stub/memory.h30
-rw-r--r--utils/hwstub/stub/memset.S98
-rw-r--r--utils/hwstub/stub/protocol.h1
-rw-r--r--utils/hwstub/stub/stddef.h32
-rw-r--r--utils/hwstub/stub/stdint.h40
-rw-r--r--utils/hwstub/stub/stmp/Makefile14
-rw-r--r--utils/hwstub/stub/stmp/target-config.h9
-rw-r--r--utils/hwstub/stub/stmp/target.c205
-rw-r--r--utils/hwstub/stub/string.c29
-rw-r--r--utils/hwstub/stub/string.h28
-rw-r--r--utils/hwstub/stub/system.h118
-rw-r--r--utils/hwstub/stub/target.h31
-rw-r--r--utils/hwstub/stub/usb_ch9.h454
-rw-r--r--utils/hwstub/stub/usb_drv.h47
-rw-r--r--utils/hwstub/stub/usb_drv_arc.c364
26 files changed, 2416 insertions, 0 deletions
diff --git a/utils/hwstub/stub/SOURCES b/utils/hwstub/stub/SOURCES
new file mode 100644
index 0000000000..bfb847c21b
--- /dev/null
+++ b/utils/hwstub/stub/SOURCES
@@ -0,0 +1,12 @@
+main.c
+crt0.S
+logf.c
+memcpy.S
+memmove.S
+memset.S
+string.c
+format.c
+#ifdef CONFIG_STMP
+usb_drv_arc.c
+stmp/target.c
+#endif
diff --git a/utils/hwstub/stub/config.h b/utils/hwstub/stub/config.h
new file mode 100644
index 0000000000..3cd2deeeb3
--- /dev/null
+++ b/utils/hwstub/stub/config.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2012 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __HWSTUB_CONFIG__
+#define __HWSTUB_CONFIG__
+
+#include "target-config.h"
+
+#define STACK_SIZE 0x1000
+#define MAX_LOGF_SIZE 128
+
+#if defined(CPU_ARM) && defined(__ASSEMBLER__)
+/* ARMv4T doesn't switch the T bit when popping pc directly, we must use BX */
+.macro ldmpc cond="", order="ia", regs
+#if ARM_ARCH == 4 && defined(USE_THUMB)
+ ldm\cond\order sp!, { \regs, lr }
+ bx\cond lr
+#else
+ ldm\cond\order sp!, { \regs, pc }
+#endif
+.endm
+.macro ldrpc cond=""
+#if ARM_ARCH == 4 && defined(USE_THUMB)
+ ldr\cond lr, [sp], #4
+ bx\cond lr
+#else
+ ldr\cond pc, [sp], #4
+#endif
+.endm
+#endif
+
+#endif /* __HWSTUB_CONFIG__ */
diff --git a/utils/hwstub/stub/crt0.S b/utils/hwstub/stub/crt0.S
new file mode 100644
index 0000000000..e2d4742d36
--- /dev/null
+++ b/utils/hwstub/stub/crt0.S
@@ -0,0 +1,17 @@
+.section .text,"ax",%progbits
+.code 32
+.align 0x04
+.global start
+start:
+ msr cpsr_c, #0xd3 /* enter supervisor mode, disable IRQ/FIQ */
+ ldr sp, =oc_stackend
+ /* clear bss */
+ ldr r2, =bss_start
+ ldr r3, =bss_end
+ mov r4, #0
+1:
+ cmp r3, r2
+ strhi r4, [r2], #4
+ bhi 1b
+ /* jump to C code */
+ b main
diff --git a/utils/hwstub/stub/format.c b/utils/hwstub/stub/format.c
new file mode 100644
index 0000000000..f5783159c0
--- /dev/null
+++ b/utils/hwstub/stub/format.c
@@ -0,0 +1,223 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2002 by Gary Czvitkovicz
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+
+#include <stdarg.h>
+#include <limits.h>
+#include "stddef.h"
+#include "string.h"
+#include "format.h"
+
+static const char hexdigit[] = "0123456789ABCDEF";
+
+void vuprintf(
+ /* call 'push()' for each output letter */
+ int (*push)(void *userp, unsigned char data),
+ void *userp,
+ const char *fmt,
+ va_list ap)
+{
+ char *str;
+ char tmpbuf[12], pad;
+ int ch, width, val, sign, precision;
+ long lval, lsign;
+ unsigned int uval;
+ unsigned long ulval;
+ size_t uszval;
+ ssize_t szval, szsign;
+ bool ok = true;
+
+ tmpbuf[sizeof tmpbuf - 1] = '\0';
+
+ while ((ch = *fmt++) != '\0' && ok)
+ {
+ if (ch == '%')
+ {
+ ch = *fmt++;
+ pad = ' ';
+ if (ch == '0')
+ pad = '0';
+
+ width = 0;
+ while (ch >= '0' && ch <= '9')
+ {
+ width = 10*width + ch - '0';
+ ch = *fmt++;
+ }
+
+ precision = 0;
+ if(ch == '.')
+ {
+ ch = *fmt++;
+ while (ch >= '0' && ch <= '9')
+ {
+ precision = 10*precision + ch - '0';
+ ch = *fmt++;
+ }
+ } else {
+ precision = INT_MAX;
+ }
+
+ str = tmpbuf + sizeof tmpbuf - 1;
+ switch (ch)
+ {
+ case 'c':
+ *--str = va_arg (ap, int);
+ break;
+
+ case 's':
+ str = va_arg (ap, char*);
+ break;
+
+ case 'd':
+ val = sign = va_arg (ap, int);
+ if (val < 0)
+ val = -val;
+ do
+ {
+ *--str = (val % 10) + '0';
+ val /= 10;
+ }
+ while (val > 0);
+ if (sign < 0)
+ *--str = '-';
+ break;
+
+ case 'u':
+ uval = va_arg(ap, unsigned int);
+ do
+ {
+ *--str = (uval % 10) + '0';
+ uval /= 10;
+ }
+ while (uval > 0);
+ break;
+
+ case 'x':
+ case 'X':
+ pad='0';
+ uval = va_arg (ap, int);
+ do
+ {
+ *--str = hexdigit[uval & 0xf];
+ uval >>= 4;
+ }
+ while (uval);
+ break;
+
+ case 'l':
+ ch = *fmt++;
+ switch(ch) {
+ case 'x':
+ case 'X':
+ pad='0';
+ ulval = va_arg (ap, long);
+ do
+ {
+ *--str = hexdigit[ulval & 0xf];
+ ulval >>= 4;
+ }
+ while (ulval);
+ break;
+ case 'd':
+ lval = lsign = va_arg (ap, long);
+ if (lval < 0)
+ lval = -lval;
+ do
+ {
+ *--str = (lval % 10) + '0';
+ lval /= 10;
+ }
+ while (lval > 0);
+ if (lsign < 0)
+ *--str = '-';
+ break;
+
+ case 'u':
+ ulval = va_arg(ap, unsigned long);
+ do
+ {
+ *--str = (ulval % 10) + '0';
+ ulval /= 10;
+ }
+ while (ulval > 0);
+ break;
+
+ default:
+ *--str = 'l';
+ *--str = ch;
+ }
+
+ break;
+
+ case 'z':
+ ch = *fmt++;
+ switch(ch) {
+ case 'd':
+ szval = szsign = va_arg (ap, ssize_t);
+ if (szval < 0)
+ szval = -szval;
+ do
+ {
+ *--str = (szval % 10) + '0';
+ szval /= 10;
+ }
+ while (szval > 0);
+ if (szsign < 0)
+ *--str = '-';
+ break;
+
+ case 'u':
+ uszval = va_arg(ap, size_t);
+ do
+ {
+ *--str = (uszval % 10) + '0';
+ uszval /= 10;
+ }
+ while (uszval > 0);
+ break;
+
+ default:
+ *--str = 'z';
+ *--str = ch;
+ }
+
+ break;
+
+ default:
+ *--str = ch;
+ break;
+ }
+
+ if (width > 0)
+ {
+ width -= strlen (str);
+ while (width-- > 0 && ok)
+ ok=push(userp, pad);
+ }
+ while (*str != '\0' && ok && precision--)
+ ok=push(userp, *str++);
+ }
+ else
+ ok=push(userp, ch);
+ }
+}
+
diff --git a/utils/hwstub/stub/format.h b/utils/hwstub/stub/format.h
new file mode 100644
index 0000000000..2ad4229f1e
--- /dev/null
+++ b/utils/hwstub/stub/format.h
@@ -0,0 +1,29 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2012 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __HWSTUB_FORMAT__
+#define __HWSTUB_FORMAT__
+
+#include <stdarg.h>
+
+void vuprintf(int (*push)(void *userp, unsigned char data),
+ void *userp, const char *fmt, va_list ap);
+
+#endif /* __HWSTUB_FORMAT__ */
diff --git a/utils/hwstub/stub/hwstub.lds b/utils/hwstub/stub/hwstub.lds
new file mode 100644
index 0000000000..61504a3e75
--- /dev/null
+++ b/utils/hwstub/stub/hwstub.lds
@@ -0,0 +1,71 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2012 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "config.h"
+
+ENTRY(start)
+OUTPUT_FORMAT(elf32-littlearm)
+OUTPUT_ARCH(arm)
+STARTUP(crt0.o)
+
+#define IRAM_END_ADDR (IRAM_ORIG + IRAM_SIZE)
+
+MEMORY
+{
+ OCRAM : ORIGIN = IRAM_ORIG, LENGTH = IRAM_SIZE
+}
+
+SECTIONS
+{
+ .octext :
+ {
+ oc_codestart = .;
+ *(.text*)
+ *(.icode*)
+ *(.data*)
+ *(.rodata*)
+ } > OCRAM
+
+ .bss (NOLOAD) :
+ {
+ bss_start = .;
+ *(.bss)
+ bss_end = .;
+ } > OCRAM
+
+ .stack (NOLOAD) :
+ {
+ oc_codeend = .;
+ oc_stackstart = .;
+ . += STACK_SIZE;
+ oc_stackend = .;
+ oc_bufferstart = .;
+ } > OCRAM
+
+ .ocend IRAM_END_ADDR (NOLOAD) :
+ {
+ oc_bufferend = .;
+ } > OCRAM
+
+ /DISCARD/ :
+ {
+ *(.eh_frame)
+ }
+}
diff --git a/utils/hwstub/stub/hwstub.make b/utils/hwstub/stub/hwstub.make
new file mode 100644
index 0000000000..b46a2736ef
--- /dev/null
+++ b/utils/hwstub/stub/hwstub.make
@@ -0,0 +1,49 @@
+INCLUDES+=-I$(ROOT_DIR)
+LINKER_FILE=$(ROOT_DIR)/hwstub.lds
+TMP_LDS=$(BUILD_DIR)/link.lds
+TMP_MAP=$(BUILD_DIR)/hwstub.map
+CFLAGS=$(GCCOPTS) $(DEFINES) -W -Wall -Wundef -O -nostdlib -ffreestanding -Wstrict-prototypes -pipe -std=gnu99 -fomit-frame-pointer -Wno-pointer-sign -Wno-override-init $(INCLUDES)
+ASFLAGS=$(CFLAGS) -D__ASSEMBLER__
+LDFLAGS=-lgcc -Os -nostdlib -T$(TMP_LDS) -Wl,-Map,$(TMP_MAP) $(INCLUDES) -L$(BUILD_DIR)
+
+SRC:=$(shell cat $(ROOT_DIR)/SOURCES | $(CC) $(INCLUDES) \
+ $(DEFINES) -E -P -include "config.h" - 2>/dev/null \
+ | grep -v "^\#")
+SRC:=$(foreach src,$(SRC),$(BUILD_DIR)/$(src))
+OBJ=$(SRC:.c=.o)
+OBJ:=$(OBJ:.S=.o)
+OBJ_EXCEPT_CRT0=$(filter-out $(BUILD_DIR)/crt0.o,$(OBJ))
+EXEC_ELF=$(BUILD_DIR)/hwstub.elf
+DEPS=$(foreach obj,$(OBJ),$(obj).d)
+
+EXEC=$(EXEC_ELF)
+
+SILENT?=@
+PRINTS=$(SILENT)$(call info,$(1))
+
+all: $(EXEC)
+
+# pull in dependency info for *existing* .o files
+-include $(DEPS)
+
+$(BUILD_DIR)/%.o: $(ROOT_DIR)/%.c
+ $(SILENT)mkdir -p $(dir $@)
+ $(call PRINTS,CC $(<F))
+ $(SILENT)$(CC) $(CFLAGS) -c -o $@ $<
+ $(SILENT)$(CC) -MM $(CFLAGS) $< -MT $@ > $@.d
+
+$(BUILD_DIR)/%.o: $(ROOT_DIR)/%.S
+ $(call PRINTS,AS $(<F))
+ $(SILENT)mkdir -p $(dir $@)
+ $(SILENT)$(AS) $(ASFLAGS) -c -o $@ $<
+
+$(TMP_LDS): $(LINKER_FILE)
+ $(call PRINTS,PP $(<F))
+ $(SILENT)$(CC) $(CFLAGS) -E -x c - < $< | sed '/#/d' > $@
+
+$(EXEC_ELF): $(OBJ) $(TMP_LDS)
+ $(call PRINTS,LD $(@F))
+ $(SILENT)$(LD) $(LDFLAGS) -o $@ $(OBJ_EXCEPT_CRT0)
+
+clean:
+ $(SILENT)rm -rf $(OBJ) $(DEPS) $(EXEC) $(TMP_LDS) $(TMP_MAP)
diff --git a/utils/hwstub/stub/logf.c b/utils/hwstub/stub/logf.c
new file mode 100644
index 0000000000..623ddb1c6c
--- /dev/null
+++ b/utils/hwstub/stub/logf.c
@@ -0,0 +1,69 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2012 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "config.h"
+#include "logf.h"
+#include "format.h"
+#include "string.h"
+#include "memory.h"
+
+static unsigned char logfbuffer[MAX_LOGF_SIZE];
+static int logfread = 0;
+static int logfwrite = 0;
+static int logfen = true;
+
+void enable_logf(bool en)
+{
+ logfen = en;
+}
+
+static int logf_push(void *userp, unsigned char c)
+{
+ (void)userp;
+
+ logfbuffer[logfwrite++] = c;
+ if(logfwrite == MAX_LOGF_SIZE)
+ logfwrite = 0;
+ return true;
+}
+
+void logf(const char *fmt, ...)
+{
+ if(!logfen) return;
+ va_list ap;
+ va_start(ap, fmt);
+ vuprintf(logf_push, NULL, fmt, ap);
+ va_end(ap);
+}
+
+size_t logf_readback(char *buf, size_t max_size)
+{
+ if(logfread == logfwrite)
+ return 0;
+ if(logfread < logfwrite)
+ max_size = MIN(max_size, (size_t)(logfwrite - logfread));
+ else
+ max_size = MIN(max_size, (size_t)(MAX_LOGF_SIZE - logfread));
+ memcpy(buf, &logfbuffer[logfread], max_size);
+ logfread += max_size;
+ if(logfread == MAX_LOGF_SIZE)
+ logfread = 0;
+ return max_size;
+}
diff --git a/utils/hwstub/stub/logf.h b/utils/hwstub/stub/logf.h
new file mode 100644
index 0000000000..48c8c2c9b9
--- /dev/null
+++ b/utils/hwstub/stub/logf.h
@@ -0,0 +1,31 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2012 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __HWSTUB_LOGF__
+#define __HWSTUB_LOGF__
+
+#include "stddef.h"
+#include <stdarg.h>
+
+void enable_logf(bool en);
+void logf(const char *fmt, ...);
+size_t logf_readback(char *buf, size_t max_size);
+
+#endif /* __HWSTUB_LOGF__ */
diff --git a/utils/hwstub/stub/memcpy.S b/utils/hwstub/stub/memcpy.S
new file mode 100644
index 0000000000..2a55fb5656
--- /dev/null
+++ b/utils/hwstub/stub/memcpy.S
@@ -0,0 +1,176 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2006 Free Software Foundation, Inc.
+ * This file was originally part of the GNU C Library
+ * Contributed to glibc by MontaVista Software, Inc. (written by Nicolas Pitre)
+ * Adapted for Rockbox by Daniel Ankers
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "config.h"
+
+/*
+ * Endian independent macros for shifting bytes within registers.
+ */
+#ifndef __ARMEB__
+#define pull lsr
+#define push lsl
+#else
+#define pull lsl
+#define push lsr
+#endif
+
+/* Prototype: void *memcpy(void *dest, const void *src, size_t n); */
+
+ .section .icode,"ax",%progbits
+
+ .align 2
+ .global memcpy
+ .type memcpy,%function
+
+memcpy:
+ stmfd sp!, {r0, r4, lr}
+
+ subs r2, r2, #4
+ blt 8f
+ ands ip, r0, #3
+ bne 9f
+ ands ip, r1, #3
+ bne 10f
+
+1: subs r2, r2, #(28)
+ stmfd sp!, {r5 - r8}
+ blt 5f
+
+2:
+3:
+4: ldmia r1!, {r3, r4, r5, r6, r7, r8, ip, lr}
+ subs r2, r2, #32
+ stmia r0!, {r3, r4, r5, r6, r7, r8, ip, lr}
+ bge 3b
+
+5: ands ip, r2, #28
+ rsb ip, ip, #32
+ addne pc, pc, ip @ C is always clear here
+ b 7f
+6: nop
+ ldr r3, [r1], #4
+ ldr r4, [r1], #4
+ ldr r5, [r1], #4
+ ldr r6, [r1], #4
+ ldr r7, [r1], #4
+ ldr r8, [r1], #4
+ ldr lr, [r1], #4
+
+ add pc, pc, ip
+ nop
+ nop
+ str r3, [r0], #4
+ str r4, [r0], #4
+ str r5, [r0], #4
+ str r6, [r0], #4
+ str r7, [r0], #4
+ str r8, [r0], #4
+ str lr, [r0], #4
+
+7: ldmfd sp!, {r5 - r8}
+
+8: movs r2, r2, lsl #31
+ ldrneb r3, [r1], #1
+ ldrcsb r4, [r1], #1
+ ldrcsb ip, [r1]
+ strneb r3, [r0], #1
+ strcsb r4, [r0], #1
+ strcsb ip, [r0]
+
+ ldmpc regs="r0, r4"
+
+9: rsb ip, ip, #4
+ cmp ip, #2
+ ldrgtb r3, [r1], #1
+ ldrgeb r4, [r1], #1
+ ldrb lr, [r1], #1
+ strgtb r3, [r0], #1
+ strgeb r4, [r0], #1
+ subs r2, r2, ip
+ strb lr, [r0], #1
+ blt 8b
+ ands ip, r1, #3
+ beq 1b
+
+10: bic r1, r1, #3
+ cmp ip, #2
+ ldr lr, [r1], #4
+ beq 17f
+ bgt 18f
+
+
+ .macro forward_copy_shift pull push
+
+ subs r2, r2, #28
+ blt 14f
+
+11: stmfd sp!, {r5 - r9}
+
+12:
+13: ldmia r1!, {r4, r5, r6, r7}
+ mov r3, lr, pull #\pull
+ subs r2, r2, #32
+ ldmia r1!, {r8, r9, ip, lr}
+ orr r3, r3, r4, push #\push
+ mov r4, r4, pull #\pull
+ orr r4, r4, r5, push #\push
+ mov r5, r5, pull #\pull
+ orr r5, r5, r6, push #\push
+ mov r6, r6, pull #\pull
+ orr r6, r6, r7, push #\push
+ mov r7, r7, pull #\pull
+ orr r7, r7, r8, push #\push
+ mov r8, r8, pull #\pull
+ orr r8, r8, r9, push #\push
+ mov r9, r9, pull #\pull
+ orr r9, r9, ip, push #\push
+ mov ip, ip, pull #\pull
+ orr ip, ip, lr, push #\push
+ stmia r0!, {r3, r4, r5, r6, r7, r8, r9, ip}
+ bge 12b
+
+ ldmfd sp!, {r5 - r9}
+
+14: ands ip, r2, #28
+ beq 16f
+
+15: mov r3, lr, pull #\pull
+ ldr lr, [r1], #4
+ subs ip, ip, #4
+ orr r3, r3, lr, push #\push
+ str r3, [r0], #4
+ bgt 15b
+
+16: sub r1, r1, #(\push / 8)
+ b 8b
+
+ .endm
+
+
+ forward_copy_shift pull=8 push=24
+
+17: forward_copy_shift pull=16 push=16
+
+18: forward_copy_shift pull=24 push=8
+
diff --git a/utils/hwstub/stub/memmove.S b/utils/hwstub/stub/memmove.S
new file mode 100644
index 0000000000..d8cab048be
--- /dev/null
+++ b/utils/hwstub/stub/memmove.S
@@ -0,0 +1,190 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2006 Free Software Foundation, Inc.
+ * This file was originally part of the GNU C Library
+ * Contributed to glibc by MontaVista Software, Inc. (written by Nicolas Pitre)
+ * Adapted for Rockbox by Daniel Ankers
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "config.h"
+
+/*
+ * Endian independent macros for shifting bytes within registers.
+ */
+#ifndef __ARMEB__
+#define pull lsr
+#define push lsl
+#else
+#define pull lsl
+#define push lsr
+#endif
+
+ .text
+
+/*
+ * Prototype: void *memmove(void *dest, const void *src, size_t n);
+ *
+ * Note:
+ *
+ * If the memory regions don't overlap, we simply branch to memcpy which is
+ * normally a bit faster. Otherwise the copy is done going downwards.
+ */
+
+ .section .icode,"ax",%progbits
+
+ .align 2
+ .global memmove
+ .type memmove,%function
+
+memmove:
+
+ subs ip, r0, r1
+ cmphi r2, ip
+ bls memcpy
+
+ stmfd sp!, {r0, r4, lr}
+ add r1, r1, r2
+ add r0, r0, r2
+ subs r2, r2, #4
+ blt 8f
+ ands ip, r0, #3
+ bne 9f
+ ands ip, r1, #3
+ bne 10f
+
+1: subs r2, r2, #(28)
+ stmfd sp!, {r5 - r8}
+ blt 5f
+
+2:
+3:
+4: ldmdb r1!, {r3, r4, r5, r6, r7, r8, ip, lr}
+ subs r2, r2, #32
+ stmdb r0!, {r3, r4, r5, r6, r7, r8, ip, lr}
+ bge 3b
+
+5: ands ip, r2, #28
+ rsb ip, ip, #32
+ addne pc, pc, ip @ C is always clear here
+ b 7f
+6: nop
+ ldr r3, [r1, #-4]!
+ ldr r4, [r1, #-4]!
+ ldr r5, [r1, #-4]!
+ ldr r6, [r1, #-4]!
+ ldr r7, [r1, #-4]!
+ ldr r8, [r1, #-4]!
+ ldr lr, [r1, #-4]!
+
+ add pc, pc, ip
+ nop
+ nop
+ str r3, [r0, #-4]!
+ str r4, [r0, #-4]!
+ str r5, [r0, #-4]!
+ str r6, [r0, #-4]!
+ str r7, [r0, #-4]!
+ str r8, [r0, #-4]!
+ str lr, [r0, #-4]!
+
+7: ldmfd sp!, {r5 - r8}
+
+8: movs r2, r2, lsl #31
+ ldrneb r3, [r1, #-1]!
+ ldrcsb r4, [r1, #-1]!
+ ldrcsb ip, [r1, #-1]
+ strneb r3, [r0, #-1]!
+ strcsb r4, [r0, #-1]!
+ strcsb ip, [r0, #-1]
+ ldmpc regs="r0, r4"
+
+9: cmp ip, #2
+ ldrgtb r3, [r1, #-1]!
+ ldrgeb r4, [r1, #-1]!
+ ldrb lr, [r1, #-1]!
+ strgtb r3, [r0, #-1]!
+ strgeb r4, [r0, #-1]!
+ subs r2, r2, ip
+ strb lr, [r0, #-1]!
+ blt 8b
+ ands ip, r1, #3
+ beq 1b
+
+10: bic r1, r1, #3
+ cmp ip, #2
+ ldr r3, [r1, #0]
+ beq 17f
+ blt 18f
+
+
+ .macro backward_copy_shift push pull
+
+ subs r2, r2, #28
+ blt 14f
+
+11: stmfd sp!, {r5 - r9}
+
+12:
+13: ldmdb r1!, {r7, r8, r9, ip}
+ mov lr, r3, push #\push
+ subs r2, r2, #32
+ ldmdb r1!, {r3, r4, r5, r6}
+ orr lr, lr, ip, pull #\pull
+ mov ip, ip, push #\push
+ orr ip, ip, r9, pull #\pull
+ mov r9, r9, push #\push
+ orr r9, r9, r8, pull #\pull
+ mov r8, r8, push #\push
+ orr r8, r8, r7, pull #\pull
+ mov r7, r7, push #\push
+ orr r7, r7, r6, pull #\pull
+ mov r6, r6, push #\push
+ orr r6, r6, r5, pull #\pull
+ mov r5, r5, push #\push
+ orr r5, r5, r4, pull #\pull
+ mov r4, r4, push #\push
+ orr r4, r4, r3, pull #\pull
+ stmdb r0!, {r4 - r9, ip, lr}
+ bge 12b
+
+ ldmfd sp!, {r5 - r9}
+
+14: ands ip, r2, #28
+ beq 16f
+
+15: mov lr, r3, push #\push
+ ldr r3, [r1, #-4]!
+ subs ip, ip, #4
+ orr lr, lr, r3, pull #\pull
+ str lr, [r0, #-4]!
+ bgt 15b
+
+16: add r1, r1, #(\pull / 8)
+ b 8b
+
+ .endm
+
+
+ backward_copy_shift push=8 pull=24
+
+17: backward_copy_shift push=16 pull=16
+
+18: backward_copy_shift push=24 pull=8
+
+
diff --git a/utils/hwstub/stub/memory.h b/utils/hwstub/stub/memory.h
new file mode 100644
index 0000000000..206ed8604a
--- /dev/null
+++ b/utils/hwstub/stub/memory.h
@@ -0,0 +1,30 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2013 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __HWSTUB_MEMORY__
+#define __HWSTUB_MEMORY__
+
+#include "stddef.h"
+
+void memset(void *dst, int c, size_t n);
+void memcpy(void *dst, const void *src, size_t n);
+void memmove(void *dst, const void *src, size_t n);
+
+#endif /* __HWSTUB_MEMORY__ */ \ No newline at end of file
diff --git a/utils/hwstub/stub/memset.S b/utils/hwstub/stub/memset.S
new file mode 100644
index 0000000000..682da874ce
--- /dev/null
+++ b/utils/hwstub/stub/memset.S
@@ -0,0 +1,98 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2006 by Thom Johansen
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "config.h"
+
+ .section .icode,"ax",%progbits
+
+ .align 2
+
+/* The following code is based on code found in Linux kernel version 2.6.15.3
+ * linux/arch/arm/lib/memset.S
+ *
+ * Copyright (C) 1995-2000 Russell King
+ */
+
+/* This code will align a pointer for memset, if needed */
+1: cmp r2, #4 @ 1 do we have enough
+ blt 5f @ 1 bytes to align with?
+ cmp r3, #2 @ 1
+ strgtb r1, [r0, #-1]! @ 1
+ strgeb r1, [r0, #-1]! @ 1
+ strb r1, [r0, #-1]! @ 1
+ sub r2, r2, r3 @ 1 r2 = r2 - r3
+ b 2f
+
+ .global memset
+ .type memset,%function
+memset:
+ add r0, r0, r2 @ we'll write backwards in memory
+ ands r3, r0, #3 @ 1 unaligned?
+ bne 1b @ 1
+2:
+/*
+ * we know that the pointer in r0 is aligned to a word boundary.
+ */
+ orr r1, r1, r1, lsl #8
+ orr r1, r1, r1, lsl #16
+ mov r3, r1
+ cmp r2, #16
+ blt 5f
+/*
+ * We need an extra register for this loop - save the return address and
+ * use the LR
+ */
+ str lr, [sp, #-4]!
+ mov ip, r1
+ mov lr, r1
+
+3: subs r2, r2, #64
+ stmgedb r0!, {r1, r3, ip, lr} @ 64 bytes at a time.
+ stmgedb r0!, {r1, r3, ip, lr}
+ stmgedb r0!, {r1, r3, ip, lr}
+ stmgedb r0!, {r1, r3, ip, lr}
+ bgt 3b
+ ldrpc cond=eq @ Now <64 bytes to go.
+/*
+ * No need to correct the count; we're only testing bits from now on
+ */
+ tst r2, #32
+ stmnedb r0!, {r1, r3, ip, lr}
+ stmnedb r0!, {r1, r3, ip, lr}
+ tst r2, #16
+ stmnedb r0!, {r1, r3, ip, lr}
+ ldr lr, [sp], #4
+
+5: tst r2, #8
+ stmnedb r0!, {r1, r3}
+ tst r2, #4
+ strne r1, [r0, #-4]!
+/*
+ * When we get here, we've got less than 4 bytes to zero. We
+ * may have an unaligned pointer as well.
+ */
+6: tst r2, #2
+ strneb r1, [r0, #-1]!
+ strneb r1, [r0, #-1]!
+ tst r2, #1
+ strneb r1, [r0, #-1]!
+ bx lr
+.end:
+ .size memset,.end-memset
diff --git a/utils/hwstub/stub/protocol.h b/utils/hwstub/stub/protocol.h
new file mode 100644
index 0000000000..35510fa9b2
--- /dev/null
+++ b/utils/hwstub/stub/protocol.h
@@ -0,0 +1 @@
+#include "../hwstub_protocol.h"
diff --git a/utils/hwstub/stub/stddef.h b/utils/hwstub/stub/stddef.h
new file mode 100644
index 0000000000..9bfd767750
--- /dev/null
+++ b/utils/hwstub/stub/stddef.h
@@ -0,0 +1,32 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2012 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __HWSTUB_STDDEF__
+#define __HWSTUB_STDDEF__
+
+#include "stdint.h"
+
+typedef uint32_t size_t;
+typedef int32_t ssize_t;
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+#endif /* __HWSTUB_STDDEF__ */
diff --git a/utils/hwstub/stub/stdint.h b/utils/hwstub/stub/stdint.h
new file mode 100644
index 0000000000..393ff3fffd
--- /dev/null
+++ b/utils/hwstub/stub/stdint.h
@@ -0,0 +1,40 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2005 by Dave Chapman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef __STDINT_H__
+#define __STDINT_H__
+
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef short int16_t;
+typedef unsigned short uint16_t;
+typedef long int32_t;
+typedef unsigned long uint32_t;
+typedef unsigned long long uint64_t;
+typedef uint32_t intptr_t;
+typedef char bool;
+
+#define true 1
+#define false 0
+
+#define NULL (void *)0
+
+#endif /* __STDINT_H__ */
diff --git a/utils/hwstub/stub/stmp/Makefile b/utils/hwstub/stub/stmp/Makefile
new file mode 100644
index 0000000000..14e6d0fbba
--- /dev/null
+++ b/utils/hwstub/stub/stmp/Makefile
@@ -0,0 +1,14 @@
+#
+# common
+#
+CC=arm-elf-eabi-gcc
+LD=arm-elf-eabi-gcc
+AS=arm-elf-eabi-gcc
+OC=arm-elf-eabi-objcopy
+DEFINES=
+INCLUDES=-I$(CURDIR)
+GCCOPTS=-mcpu=arm926ej-s
+BUILD_DIR=$(CURDIR)/build/
+ROOT_DIR=$(CURDIR)/..
+
+include ../hwstub.make \ No newline at end of file
diff --git a/utils/hwstub/stub/stmp/target-config.h b/utils/hwstub/stub/stmp/target-config.h
new file mode 100644
index 0000000000..aba2cf564b
--- /dev/null
+++ b/utils/hwstub/stub/stmp/target-config.h
@@ -0,0 +1,9 @@
+#define CONFIG_STMP
+#define IRAM_ORIG 0
+#define IRAM_SIZE 0x8000
+#define DRAM_ORIG 0x40000000
+#define DRAM_SIZE (MEMORYSIZE * 0x100000)
+#define CPU_ARM
+#define ARM_ARCH 5
+#define USB_BASE 0x80080000
+#define USB_NUM_ENDPOINTS 2 \ No newline at end of file
diff --git a/utils/hwstub/stub/stmp/target.c b/utils/hwstub/stub/stmp/target.c
new file mode 100644
index 0000000000..60411f908e
--- /dev/null
+++ b/utils/hwstub/stub/stmp/target.c
@@ -0,0 +1,205 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2013 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "stddef.h"
+#include "target.h"
+#include "system.h"
+#include "logf.h"
+
+#define __REG_SET(reg) (*((volatile uint32_t *)(&reg + 1)))
+#define __REG_CLR(reg) (*((volatile uint32_t *)(&reg + 2)))
+#define __REG_TOG(reg) (*((volatile uint32_t *)(&reg + 3)))
+
+#define __BLOCK_SFTRST (1 << 31)
+#define __BLOCK_CLKGATE (1 << 30)
+
+#define __XTRACT(reg, field) ((reg & reg##__##field##_BM) >> reg##__##field##_BP)
+#define __XTRACT_EX(val, field) (((val) & field##_BM) >> field##_BP)
+#define __FIELD_SET(reg, field, val) reg = (reg & ~reg##__##field##_BM) | (val << reg##__##field##_BP)
+
+/**
+ *
+ * Global
+ *
+ */
+
+enum stmp_family_t
+{
+ UNKNOWN,
+ STMP3600,
+ STMP3700,
+ STMP3770,
+ STMP3780
+};
+
+enum stmp_family_t g_stmp_family = UNKNOWN;
+
+/**
+ *
+ * Clkctrl
+ *
+ */
+
+#define HW_CLKCTRL_BASE 0x80040000
+
+#define HW_CLKCTRL_PLLCTRL0 (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x0))
+#define HW_CLKCTRL_PLLCTRL0__BYPASS (1 << 17) /* STMP3600 only */
+#define HW_CLKCTRL_PLLCTRL0__POWER (1 << 16)
+#define HW_CLKCTRL_PLLCTRL0__EN_USB_CLKS (1 << 18)
+
+#define HW_CLKCTRL_PLLCTRL1 (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x10))
+#define HW_CLKCTRL_PLLCTRL1__LOCK (1 << 31)
+
+/* STMP3600 only */
+#define HW_CLKCTRL_CPUCLKCTRL (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x20))
+#define HW_CLKCTRL_CPUCLKCTRL__DIV_BP 0
+#define HW_CLKCTRL_CPUCLKCTRL__DIV_BM 0x3ff
+#define HW_CLKCTRL_CPUCLKCTRL__WAIT_PLL_LOCK (1 << 30)
+
+/* STMP3600 */
+#define HW_CLKCTRL_HBUSCLKCTRL (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x30))
+
+/* STMP3600 only */
+#define HW_CLKCTRL_XBUSCLKCTRL (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x40))
+#define HW_CLKCTRL_XBUSCLKCTRL__DIV_BP 0
+#define HW_CLKCTRL_XBUSCLKCTRL__DIV_BM 0x3ff
+
+/* STMP3600 only */
+#define HW_CLKCTRL_UTMICLKCTRL (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x70))
+#define HW_CLKCTRL_UTMICLKCTRL__UTMI_CLK30M_GATE (1 << 30)
+#define HW_CLKCTRL_UTMICLKCTRL__UTMI_CLK120M_GATE (1 << 31)
+
+/**
+ *
+ * Digctl
+ *
+ */
+
+/* Digital control */
+#define HW_DIGCTL_BASE 0x8001C000
+#define HW_DIGCTL_CTRL (*(volatile uint32_t *)(HW_DIGCTL_BASE + 0))
+#define HW_DIGCTL_CTRL__USB_CLKGATE (1 << 2)
+
+#define HW_DIGCTL_MICROSECONDS (*(volatile uint32_t *)(HW_DIGCTL_BASE + 0xC0))
+
+#define HW_DIGCTL_CHIPID (*(volatile uint32_t *)(HW_DIGCTL_BASE + 0x310))
+#define HW_DIGCTL_CHIPID__PRODUCT_CODE_BP 16
+#define HW_DIGCTL_CHIPID__PRODUCT_CODE_BM 0xffff0000
+#define HW_DIGCTL_CHIPID__REVISION_BP 0
+#define HW_DIGCTL_CHIPID__REVISION_BM 0xff
+
+#define HZ 1000000
+
+/**
+ *
+ * USB PHY
+ *
+ */
+/* USB Phy */
+#define HW_USBPHY_BASE 0x8007C000
+#define HW_USBPHY_PWD (*(volatile uint32_t *)(HW_USBPHY_BASE + 0))
+
+#define HW_USBPHY_CTRL (*(volatile uint32_t *)(HW_USBPHY_BASE + 0x30))
+
+void target_init(void)
+{
+ /* detect family */
+ uint16_t product_code = __XTRACT(HW_DIGCTL_CHIPID, PRODUCT_CODE);
+ if(product_code >= 0x3600 && product_code < 0x3700)
+ {
+ logf("identified STMP3600 family\n");
+ g_stmp_family = STMP3600;
+ }
+ else if(product_code == 0x3700)
+ {
+ logf("identified STMP3700 family\n");
+ g_stmp_family = STMP3700;
+ }
+ else if(product_code == 0x37b0)
+ {
+ logf("identified STMP3770 family\n");
+ g_stmp_family = STMP3770;
+ }
+ else if(product_code == 0x3780)
+ {
+ logf("identified STMP3780 family\n");
+ g_stmp_family = STMP3780;
+ }
+ else
+ logf("cannot identify family: 0x%x\n", product_code);
+
+ if(g_stmp_family == STMP3600)
+ {
+ /* CPU clock is always derived from PLL, if we switch to PLL, cpu will
+ * run at 480 MHz unprepared ! That's bad so prepare to run at slow sleed
+ * (1.2MHz) for a safe transition */
+ HW_CLKCTRL_CPUCLKCTRL = HW_CLKCTRL_CPUCLKCTRL__WAIT_PLL_LOCK | 400;
+ /* We need to ensure that XBUS < HBUS but HBUS will be 1.2 MHz after the
+ * switch so lower XBUS too */
+ HW_CLKCTRL_XBUSCLKCTRL = 20;
+ /* Power PLL */
+ __REG_SET(HW_CLKCTRL_PLLCTRL0) = HW_CLKCTRL_PLLCTRL0__POWER;
+ HW_CLKCTRL_PLLCTRL0 = (HW_CLKCTRL_PLLCTRL0 & ~0x3ff) | 480;
+ /* Wait lock */
+ while(!(HW_CLKCTRL_PLLCTRL1 & HW_CLKCTRL_PLLCTRL1__LOCK));
+ /* Switch to PLL source */
+ __REG_CLR(HW_CLKCTRL_PLLCTRL0) = HW_CLKCTRL_PLLCTRL0__BYPASS;
+ /* Get back XBUS = 24 MHz and CPU = HBUS = 64MHz */
+ HW_CLKCTRL_CPUCLKCTRL = 7;
+ HW_CLKCTRL_HBUSCLKCTRL = 7;
+ HW_CLKCTRL_XBUSCLKCTRL = 1;
+ __REG_CLR(HW_CLKCTRL_UTMICLKCTRL) = HW_CLKCTRL_UTMICLKCTRL__UTMI_CLK120M_GATE;
+ __REG_CLR(HW_CLKCTRL_UTMICLKCTRL) = HW_CLKCTRL_UTMICLKCTRL__UTMI_CLK30M_GATE;
+ }
+ else
+ __REG_SET(HW_CLKCTRL_PLLCTRL0) = HW_CLKCTRL_PLLCTRL0__POWER;
+ /* enable USB PHY PLL */
+ __REG_SET(HW_CLKCTRL_PLLCTRL0) = HW_CLKCTRL_PLLCTRL0__EN_USB_CLKS;
+ /* power up USB PHY */
+ __REG_CLR(HW_USBPHY_CTRL) = __BLOCK_CLKGATE | __BLOCK_SFTRST;
+ HW_USBPHY_PWD = 0;
+ /* enable USB controller */
+ __REG_CLR(HW_DIGCTL_CTRL) = HW_DIGCTL_CTRL__USB_CLKGATE;
+}
+
+static struct usb_resp_info_stmp_t g_stmp;
+static struct usb_resp_info_target_t g_target =
+{
+ .id = HWSTUB_TARGET_STMP,
+ .name = "STMP3600 / STMP3700 / STMP3780 (i.MX233)"
+};
+
+int target_get_info(int info, void **buffer)
+{
+ if(info == HWSTUB_INFO_STMP)
+ {
+ g_stmp.chipid = __XTRACT(HW_DIGCTL_CHIPID, PRODUCT_CODE);
+ g_stmp.rev = __XTRACT(HW_DIGCTL_CHIPID, REVISION);
+ g_stmp.is_supported = g_stmp_family != 0;
+ *buffer = &g_stmp;
+ return sizeof(g_stmp);
+ }
+ else
+ return -1;
+}
+
+void target_exit(void)
+{
+}
diff --git a/utils/hwstub/stub/string.c b/utils/hwstub/stub/string.c
new file mode 100644
index 0000000000..1f8c415a99
--- /dev/null
+++ b/utils/hwstub/stub/string.c
@@ -0,0 +1,29 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2012 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "string.h"
+
+size_t strlen(const char *s)
+{
+ size_t len = 0;
+ while(*s++)
+ len++;
+ return len;
+}
diff --git a/utils/hwstub/stub/string.h b/utils/hwstub/stub/string.h
new file mode 100644
index 0000000000..ae352fe50e
--- /dev/null
+++ b/utils/hwstub/stub/string.h
@@ -0,0 +1,28 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2012 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __HWSTUB_STRING__
+#define __HWSTUB_STRING__
+
+#include "stddef.h"
+
+size_t strlen(const char *s);
+
+#endif /* __HWSTUB_STRING__ */
diff --git a/utils/hwstub/stub/system.h b/utils/hwstub/stub/system.h
new file mode 100644
index 0000000000..e5aea12051
--- /dev/null
+++ b/utils/hwstub/stub/system.h
@@ -0,0 +1,118 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2012 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __HWSTUB_SYSTEM__
+#define __HWSTUB_SYSTEM__
+
+#define IRQ_ENABLED 0x00
+#define IRQ_DISABLED 0x80
+#define IRQ_STATUS 0x80
+#define FIQ_ENABLED 0x00
+#define FIQ_DISABLED 0x40
+#define FIQ_STATUS 0x40
+#define IRQ_FIQ_ENABLED 0x00
+#define IRQ_FIQ_DISABLED 0xc0
+#define IRQ_FIQ_STATUS 0xc0
+#define HIGHEST_IRQ_LEVEL IRQ_DISABLED
+
+#define set_irq_level(status) \
+ set_interrupt_status((status), IRQ_STATUS)
+#define set_fiq_status(status) \
+ set_interrupt_status((status), FIQ_STATUS)
+
+#define disable_irq_save() \
+ disable_interrupt_save(IRQ_STATUS)
+#define disable_fiq_save() \
+ disable_interrupt_save(FIQ_STATUS)
+
+#define restore_irq(cpsr) \
+ restore_interrupt(cpsr)
+#define restore_fiq(cpsr) \
+ restore_interrupt(cpsr)
+
+#define disable_irq() \
+ disable_interrupt(IRQ_STATUS)
+#define enable_irq() \
+ enable_interrupt(IRQ_STATUS)
+#define disable_fiq() \
+ disable_interrupt(FIQ_STATUS)
+#define enable_fiq() \
+ enable_interrupt(FIQ_STATUS)
+
+static inline int set_interrupt_status(int status, int mask)
+{
+ unsigned long cpsr;
+ int oldstatus;
+ /* Read the old levels and set the new ones */
+ asm volatile (
+ "mrs %1, cpsr \n"
+ "bic %0, %1, %[mask] \n"
+ "orr %0, %0, %2 \n"
+ "msr cpsr_c, %0 \n"
+ : "=&r,r"(cpsr), "=&r,r"(oldstatus)
+ : "r,i"(status & mask), [mask]"i,i"(mask));
+
+ return oldstatus;
+}
+
+static inline void restore_interrupt(int cpsr)
+{
+ /* Set cpsr_c from value returned by disable_interrupt_save
+ * or set_interrupt_status */
+ asm volatile ("msr cpsr_c, %0" : : "r"(cpsr));
+}
+
+static inline void enable_interrupt(int mask)
+{
+ /* Clear I and/or F disable bit */
+ int tmp;
+ asm volatile (
+ "mrs %0, cpsr \n"
+ "bic %0, %0, %1 \n"
+ "msr cpsr_c, %0 \n"
+ : "=&r"(tmp) : "i"(mask));
+}
+
+static inline void disable_interrupt(int mask)
+{
+ /* Set I and/or F disable bit */
+ int tmp;
+ asm volatile (
+ "mrs %0, cpsr \n"
+ "orr %0, %0, %1 \n"
+ "msr cpsr_c, %0 \n"
+ : "=&r"(tmp) : "i"(mask));
+}
+
+static inline int disable_interrupt_save(int mask)
+{
+ /* Set I and/or F disable bit and return old cpsr value */
+ int cpsr, tmp;
+ asm volatile (
+ "mrs %1, cpsr \n"
+ "orr %0, %1, %2 \n"
+ "msr cpsr_c, %0 \n"
+ : "=&r"(tmp), "=&r"(cpsr)
+ : "i"(mask));
+ return cpsr;
+}
+
+#endif /* __HWSTUB_SYSTEM__ */
+
diff --git a/utils/hwstub/stub/target.h b/utils/hwstub/stub/target.h
new file mode 100644
index 0000000000..3f1551c72d
--- /dev/null
+++ b/utils/hwstub/stub/target.h
@@ -0,0 +1,31 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2013 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __TARGET_H__
+#define __TARGET_H__
+
+#include "protocol.h"
+
+void target_init(void);
+void target_exit(void);
+/* return actual size or -1 if error */
+int target_get_info(int info, void **buffer);
+
+#endif /* __TARGET_H__ */
diff --git a/utils/hwstub/stub/usb_ch9.h b/utils/hwstub/stub/usb_ch9.h
new file mode 100644
index 0000000000..09141b93bd
--- /dev/null
+++ b/utils/hwstub/stub/usb_ch9.h
@@ -0,0 +1,454 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) by Linux Kernel Developers
+ *
+ * Based on code from the Linux Kernel
+ * available at http://www.kernel.org
+ * Original file: <kernel>/include/linux/usb/ch9.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+/*
+ * This file holds USB constants and structures that are needed for
+ * USB device APIs. These are used by the USB device model, which is
+ * defined in chapter 9 of the USB 2.0 specification and in the
+ * Wireless USB 1.0 (spread around). Linux has several APIs in C that
+ * need these:
+ *
+ * - the master/host side Linux-USB kernel driver API;
+ * - the "usbfs" user space API; and
+ * - the Linux "gadget" slave/device/peripheral side driver API.
+ *
+ * USB 2.0 adds an additional "On The Go" (OTG) mode, which lets systems
+ * act either as a USB master/host or as a USB slave/device. That means
+ * the master and slave side APIs benefit from working well together.
+ *
+ * There's also "Wireless USB", using low power short range radios for
+ * peripheral interconnection but otherwise building on the USB framework.
+ *
+ * Note all descriptors are declared '__attribute__((packed))' so that:
+ *
+ * [a] they never get padded, either internally (USB spec writers
+ * probably handled that) or externally;
+ *
+ * [b] so that accessing bigger-than-a-bytes fields will never
+ * generate bus errors on any platform, even when the location of
+ * its descriptor inside a bundle isn't "naturally aligned", and
+ *
+ * [c] for consistency, removing all doubt even when it appears to
+ * someone that the two other points are non-issues for that
+ * particular descriptor type.
+ */
+
+#ifndef _CH9_H_
+#define _CH9_H_
+
+#include "stdint.h"
+
+/*-------------------------------------------------------------------------*/
+
+/* CONTROL REQUEST SUPPORT */
+
+/*
+ * USB directions
+ *
+ * This bit flag is used in endpoint descriptors' bEndpointAddress field.
+ * It's also one of three fields in control requests bRequestType.
+ */
+#define USB_DIR_OUT 0 /* to device */
+#define USB_DIR_IN 0x80 /* to host */
+
+/*
+ * USB types, the second of three bRequestType fields
+ */
+#define USB_TYPE_MASK (0x03 << 5)
+#define USB_TYPE_STANDARD (0x00 << 5)
+#define USB_TYPE_CLASS (0x01 << 5)
+#define USB_TYPE_VENDOR (0x02 << 5)
+#define USB_TYPE_RESERVED (0x03 << 5)
+
+/*
+ * USB recipients, the third of three bRequestType fields
+ */
+#define USB_RECIP_MASK 0x1f
+#define USB_RECIP_DEVICE 0x00
+#define USB_RECIP_INTERFACE 0x01
+#define USB_RECIP_ENDPOINT 0x02
+#define USB_RECIP_OTHER 0x03
+
+/*
+ * Standard requests, for the bRequest field of a SETUP packet.
+ *
+ * These are qualified by the bRequestType field, so that for example
+ * TYPE_CLASS or TYPE_VENDOR specific feature flags could be retrieved
+ * by a GET_STATUS request.
+ */
+#define USB_REQ_GET_STATUS 0x00
+#define USB_REQ_CLEAR_FEATURE 0x01
+#define USB_REQ_SET_FEATURE 0x03
+#define USB_REQ_SET_ADDRESS 0x05
+#define USB_REQ_GET_DESCRIPTOR 0x06
+#define USB_REQ_SET_DESCRIPTOR 0x07
+#define USB_REQ_GET_CONFIGURATION 0x08
+#define USB_REQ_SET_CONFIGURATION 0x09
+#define USB_REQ_GET_INTERFACE 0x0A
+#define USB_REQ_SET_INTERFACE 0x0B
+#define USB_REQ_SYNCH_FRAME 0x0C
+/*
+ * USB feature flags are written using USB_REQ_{CLEAR,SET}_FEATURE, and
+ * are read as a bit array returned by USB_REQ_GET_STATUS. (So there
+ * are at most sixteen features of each type.) Hubs may also support a
+ * new USB_REQ_TEST_AND_SET_FEATURE to put ports into L1 suspend.
+ */
+#define USB_DEVICE_SELF_POWERED 0 /* (read only) */
+#define USB_DEVICE_REMOTE_WAKEUP 1 /* dev may initiate wakeup */
+#define USB_DEVICE_TEST_MODE 2 /* (wired high speed only) */
+#define USB_DEVICE_BATTERY 2 /* (wireless) */
+#define USB_DEVICE_B_HNP_ENABLE 3 /* (otg) dev may initiate HNP */
+#define USB_DEVICE_WUSB_DEVICE 3 /* (wireless)*/
+#define USB_DEVICE_A_HNP_SUPPORT 4 /* (otg) RH port supports HNP */
+#define USB_DEVICE_A_ALT_HNP_SUPPORT 5 /* (otg) other RH port does */
+#define USB_DEVICE_DEBUG_MODE 6 /* (special devices only) */
+
+#define USB_ENDPOINT_HALT 0 /* IN/OUT will STALL */
+
+
+/**
+ * struct usb_ctrlrequest - SETUP data for a USB device control request
+ * @bRequestType: matches the USB bmRequestType field
+ * @bRequest: matches the USB bRequest field
+ * @wValue: matches the USB wValue field (le16 byte order)
+ * @wIndex: matches the USB wIndex field (le16 byte order)
+ * @wLength: matches the USB wLength field (le16 byte order)
+ *
+ * This structure is used to send control requests to a USB device. It matches
+ * the different fields of the USB 2.0 Spec section 9.3, table 9-2. See the
+ * USB spec for a fuller description of the different fields, and what they are
+ * used for.
+ *
+ * Note that the driver for any interface can issue control requests.
+ * For most devices, interfaces don't coordinate with each other, so
+ * such requests may be made at any time.
+ */
+struct usb_ctrlrequest {
+ uint8_t bRequestType;
+ uint8_t bRequest;
+ uint16_t wValue;
+ uint16_t wIndex;
+ uint16_t wLength;
+} __attribute__ ((packed));
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * STANDARD DESCRIPTORS ... as returned by GET_DESCRIPTOR, or
+ * (rarely) accepted by SET_DESCRIPTOR.
+ *
+ * Note that all multi-byte values here are encoded in little endian
+ * byte order "on the wire". But when exposed through Linux-USB APIs,
+ * they've been converted to cpu byte order.
+ */
+
+/*
+ * Descriptor types ... USB 2.0 spec table 9.5
+ */
+#define USB_DT_DEVICE 0x01
+#define USB_DT_CONFIG 0x02
+#define USB_DT_STRING 0x03
+#define USB_DT_INTERFACE 0x04
+#define USB_DT_ENDPOINT 0x05
+#define USB_DT_DEVICE_QUALIFIER 0x06
+#define USB_DT_OTHER_SPEED_CONFIG 0x07
+#define USB_DT_INTERFACE_POWER 0x08
+/* these are from a minor usb 2.0 revision (ECN) */
+#define USB_DT_OTG 0x09
+#define USB_DT_DEBUG 0x0a
+#define USB_DT_INTERFACE_ASSOCIATION 0x0b
+/* these are from the Wireless USB spec */
+#define USB_DT_SECURITY 0x0c
+#define USB_DT_KEY 0x0d
+#define USB_DT_ENCRYPTION_TYPE 0x0e
+#define USB_DT_BOS 0x0f
+#define USB_DT_DEVICE_CAPABILITY 0x10
+#define USB_DT_WIRELESS_ENDPOINT_COMP 0x11
+#define USB_DT_WIRE_ADAPTER 0x21
+#define USB_DT_RPIPE 0x22
+#define USB_DT_CS_RADIO_CONTROL 0x23
+
+/* Conventional codes for class-specific descriptors. The convention is
+ * defined in the USB "Common Class" Spec (3.11). Individual class specs
+ * are authoritative for their usage, not the "common class" writeup.
+ */
+#define USB_DT_CS_DEVICE (USB_TYPE_CLASS | USB_DT_DEVICE)
+#define USB_DT_CS_CONFIG (USB_TYPE_CLASS | USB_DT_CONFIG)
+#define USB_DT_CS_STRING (USB_TYPE_CLASS | USB_DT_STRING)
+#define USB_DT_CS_INTERFACE (USB_TYPE_CLASS | USB_DT_INTERFACE)
+#define USB_DT_CS_ENDPOINT (USB_TYPE_CLASS | USB_DT_ENDPOINT)
+
+/* All standard descriptors have these 2 fields at the beginning */
+struct usb_descriptor_header {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+} __attribute__ ((packed));
+
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_DEVICE: Device descriptor */
+struct usb_device_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+
+ uint16_t bcdUSB;
+ uint8_t bDeviceClass;
+ uint8_t bDeviceSubClass;
+ uint8_t bDeviceProtocol;
+ uint8_t bMaxPacketSize0;
+ uint16_t idVendor;
+ uint16_t idProduct;
+ uint16_t bcdDevice;
+ uint8_t iManufacturer;
+ uint8_t iProduct;
+ uint8_t iSerialNumber;
+ uint8_t bNumConfigurations;
+} __attribute__ ((packed));
+
+#define USB_DT_DEVICE_SIZE 18
+
+
+/*
+ * Device and/or Interface Class codes
+ * as found in bDeviceClass or bInterfaceClass
+ * and defined by www.usb.org documents
+ */
+#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */
+#define USB_CLASS_AUDIO 1
+#define USB_CLASS_COMM 2
+#define USB_CLASS_HID 3
+#define USB_CLASS_PHYSICAL 5
+#define USB_CLASS_STILL_IMAGE 6
+#define USB_CLASS_PRINTER 7
+#define USB_CLASS_MASS_STORAGE 8
+#define USB_CLASS_HUB 9
+#define USB_CLASS_CDC_DATA 0x0a
+#define USB_CLASS_CSCID 0x0b /* chip+ smart card */
+#define USB_CLASS_CONTENT_SEC 0x0d /* content security */
+#define USB_CLASS_VIDEO 0x0e
+#define USB_CLASS_WIRELESS_CONTROLLER 0xe0
+#define USB_CLASS_MISC 0xef
+#define USB_CLASS_APP_SPEC 0xfe
+#define USB_CLASS_VENDOR_SPEC 0xff
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_CONFIG: Configuration descriptor information.
+ *
+ * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the
+ * descriptor type is different. Highspeed-capable devices can look
+ * different depending on what speed they're currently running. Only
+ * devices with a USB_DT_DEVICE_QUALIFIER have any OTHER_SPEED_CONFIG
+ * descriptors.
+ */
+struct usb_config_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+
+ uint16_t wTotalLength;
+ uint8_t bNumInterfaces;
+ uint8_t bConfigurationValue;
+ uint8_t iConfiguration;
+ uint8_t bmAttributes;
+ uint8_t bMaxPower;
+} __attribute__ ((packed));
+
+#define USB_DT_CONFIG_SIZE 9
+
+/* from config descriptor bmAttributes */
+#define USB_CONFIG_ATT_ONE (1 << 7) /* must be set */
+#define USB_CONFIG_ATT_SELFPOWER (1 << 6) /* self powered */
+#define USB_CONFIG_ATT_WAKEUP (1 << 5) /* can wakeup */
+#define USB_CONFIG_ATT_BATTERY (1 << 4) /* battery powered */
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_STRING: String descriptor */
+struct usb_string_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+
+ uint16_t wString[]; /* UTF-16LE encoded */
+} __attribute__ ((packed));
+
+/* note that "string" zero is special, it holds language codes that
+ * the device supports, not Unicode characters.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_INTERFACE: Interface descriptor */
+struct usb_interface_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+
+ uint8_t bInterfaceNumber;
+ uint8_t bAlternateSetting;
+ uint8_t bNumEndpoints;
+ uint8_t bInterfaceClass;
+ uint8_t bInterfaceSubClass;
+ uint8_t bInterfaceProtocol;
+ uint8_t iInterface;
+} __attribute__ ((packed));
+
+#define USB_DT_INTERFACE_SIZE 9
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_ENDPOINT: Endpoint descriptor */
+struct usb_endpoint_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+
+ uint8_t bEndpointAddress;
+ uint8_t bmAttributes;
+ uint16_t wMaxPacketSize;
+ uint8_t bInterval;
+} __attribute__ ((packed));
+
+#define USB_DT_ENDPOINT_SIZE 7
+#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */
+
+
+/*
+ * Endpoints
+ */
+#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */
+#define USB_ENDPOINT_DIR_MASK 0x80
+
+#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */
+#define USB_ENDPOINT_XFER_CONTROL 0
+#define USB_ENDPOINT_XFER_ISOC 1
+#define USB_ENDPOINT_XFER_BULK 2
+#define USB_ENDPOINT_XFER_INT 3
+#define USB_ENDPOINT_MAX_ADJUSTABLE 0x80
+
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */
+struct usb_qualifier_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+
+ uint16_t bcdUSB;
+ uint8_t bDeviceClass;
+ uint8_t bDeviceSubClass;
+ uint8_t bDeviceProtocol;
+ uint8_t bMaxPacketSize0;
+ uint8_t bNumConfigurations;
+ uint8_t bRESERVED;
+} __attribute__ ((packed));
+
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_OTG (from OTG 1.0a supplement) */
+struct usb_otg_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+
+ uint8_t bmAttributes; /* support for HNP, SRP, etc */
+} __attribute__ ((packed));
+
+/* from usb_otg_descriptor.bmAttributes */
+#define USB_OTG_SRP (1 << 0)
+#define USB_OTG_HNP (1 << 1) /* swap host/device roles */
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_DEBUG: for special highspeed devices, replacing serial console */
+struct usb_debug_descriptor {
+ uint8_t bLength;
+ uint8_t bDescriptorType;
+
+ /* bulk endpoints with 8 byte maxpacket */
+ uint8_t bDebugInEndpoint;
+ uint8_t bDebugOutEndpoint;
+} __attribute__((packed));
+
+/*-------------------------------------------------------------------------*/
+/* USB 2.0 defines three speeds, here's how Linux identifies them */
+
+enum usb_device_speed {
+ USB_SPEED_UNKNOWN = 0, /* enumerating */
+ USB_SPEED_LOW, USB_SPEED_FULL, /* usb 1.1 */
+ USB_SPEED_HIGH, /* usb 2.0 */
+ USB_SPEED_VARIABLE, /* wireless (usb 2.5) */
+};
+
+enum usb_device_state {
+ /* NOTATTACHED isn't in the USB spec, and this state acts
+ * the same as ATTACHED ... but it's clearer this way.
+ */
+ USB_STATE_NOTATTACHED = 0,
+
+ /* chapter 9 and authentication (wireless) device states */
+ USB_STATE_ATTACHED,
+ USB_STATE_POWERED, /* wired */
+ USB_STATE_UNAUTHENTICATED, /* auth */
+ USB_STATE_RECONNECTING, /* auth */
+ USB_STATE_DEFAULT, /* limited function */
+ USB_STATE_ADDRESS,
+ USB_STATE_CONFIGURED, /* most functions */
+
+ USB_STATE_SUSPENDED
+
+ /* NOTE: there are actually four different SUSPENDED
+ * states, returning to POWERED, DEFAULT, ADDRESS, or
+ * CONFIGURED respectively when SOF tokens flow again.
+ * At this level there's no difference between L1 and L2
+ * suspend states. (L2 being original USB 1.1 suspend.)
+ */
+};
+
+/**
+ * struct usb_string - wraps a C string and its USB id
+ * @id:the (nonzero) ID for this string
+ * @s:the string, in UTF-8 encoding
+ *
+ * If you're using usb_gadget_get_string(), use this to wrap a string
+ * together with its ID.
+ */
+struct usb_string {
+ uint8_t id;
+ const char* s;
+};
+
+/**
+ * struct usb_gadget_strings - a set of USB strings in a given language
+ * @language:identifies the strings' language (0x0409 for en-us)
+ * @strings:array of strings with their ids
+ *
+ * If you're using usb_gadget_get_string(), use this to wrap all the
+ * strings for a given language.
+ */
+struct usb_gadget_strings {
+ uint16_t language; /* 0x0409 for en-us */
+ struct usb_string* strings;
+};
+
+#endif /*_CH9_H_*/
diff --git a/utils/hwstub/stub/usb_drv.h b/utils/hwstub/stub/usb_drv.h
new file mode 100644
index 0000000000..00f22d8e1a
--- /dev/null
+++ b/utils/hwstub/stub/usb_drv.h
@@ -0,0 +1,47 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2007 by Björn Stenberg
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef _USB_DRV_H
+#define _USB_DRV_H
+
+#include "usb_ch9.h"
+
+#define EP_CONTROL 0
+
+#define DIR_OUT 0
+#define DIR_IN 1
+
+#define EP_DIR(ep) (((ep) & USB_ENDPOINT_DIR_MASK) ? DIR_IN : DIR_OUT)
+#define EP_NUM(ep) ((ep) & USB_ENDPOINT_NUMBER_MASK)
+
+void usb_drv_init(void);
+void usb_drv_exit(void);
+void usb_drv_stall(int endpoint, bool stall,bool in);
+int usb_drv_send(int endpoint, void* ptr, int length);
+int usb_drv_send_nonblocking(int endpoint, void* ptr, int length);
+int usb_drv_recv(int endpoint, void* ptr, int length);// blocking !
+int usb_drv_recv_nonblocking(int endpoint, void* ptr, int length);
+int usb_drv_recv_setup(struct usb_ctrlrequest *req);
+void usb_drv_set_address(int address);
+int usb_drv_port_speed(void);
+void usb_drv_configure_endpoint(int ep_num, int type);
+
+#endif /* _USB_DRV_H */
+
diff --git a/utils/hwstub/stub/usb_drv_arc.c b/utils/hwstub/stub/usb_drv_arc.c
new file mode 100644
index 0000000000..32275b6adb
--- /dev/null
+++ b/utils/hwstub/stub/usb_drv_arc.c
@@ -0,0 +1,364 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Driver for ARC USBOTG Device Controller
+ *
+ * Copyright (C) 2007 by Björn Stenberg
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "usb_drv.h"
+#include "config.h"
+#include "memory.h"
+
+#define MAX_PKT_SIZE 1024
+#define MAX_PKT_SIZE_EP0 64
+
+/* USB device mode registers (Little Endian) */
+#define REG_USBCMD (*(volatile unsigned int *)(USB_BASE+0x140))
+#define REG_DEVICEADDR (*(volatile unsigned int *)(USB_BASE+0x154))
+#define REG_ENDPOINTLISTADDR (*(volatile unsigned int *)(USB_BASE+0x158))
+#define REG_PORTSC1 (*(volatile unsigned int *)(USB_BASE+0x184))
+#define REG_USBMODE (*(volatile unsigned int *)(USB_BASE+0x1a8))
+#define REG_ENDPTSETUPSTAT (*(volatile unsigned int *)(USB_BASE+0x1ac))
+#define REG_ENDPTPRIME (*(volatile unsigned int *)(USB_BASE+0x1b0))
+#define REG_ENDPTSTATUS (*(volatile unsigned int *)(USB_BASE+0x1b8))
+#define REG_ENDPTCOMPLETE (*(volatile unsigned int *)(USB_BASE+0x1bc))
+#define REG_ENDPTCTRL0 (*(volatile unsigned int *)(USB_BASE+0x1c0))
+#define REG_ENDPTCTRL1 (*(volatile unsigned int *)(USB_BASE+0x1c4))
+#define REG_ENDPTCTRL2 (*(volatile unsigned int *)(USB_BASE+0x1c8))
+#define REG_ENDPTCTRL(_x_) (*(volatile unsigned int *)(USB_BASE+0x1c0+4*(_x_)))
+
+/* USB CMD Register Bit Masks */
+#define USBCMD_RUN (0x00000001)
+#define USBCMD_CTRL_RESET (0x00000002)
+#define USBCMD_PERIODIC_SCHEDULE_EN (0x00000010)
+#define USBCMD_ASYNC_SCHEDULE_EN (0x00000020)
+#define USBCMD_INT_AA_DOORBELL (0x00000040)
+#define USBCMD_ASP (0x00000300)
+#define USBCMD_ASYNC_SCH_PARK_EN (0x00000800)
+#define USBCMD_SUTW (0x00002000)
+#define USBCMD_ATDTW (0x00004000)
+#define USBCMD_ITC (0x00FF0000)
+
+/* Device Address bit masks */
+#define USBDEVICEADDRESS_MASK (0xFE000000)
+#define USBDEVICEADDRESS_BIT_POS (25)
+
+/* Endpoint Setup Status bit masks */
+#define EPSETUP_STATUS_EP0 (0x00000001)
+
+/* PORTSCX Register Bit Masks */
+#define PORTSCX_CURRENT_CONNECT_STATUS (0x00000001)
+#define PORTSCX_CONNECT_STATUS_CHANGE (0x00000002)
+#define PORTSCX_PORT_ENABLE (0x00000004)
+#define PORTSCX_PORT_EN_DIS_CHANGE (0x00000008)
+#define PORTSCX_OVER_CURRENT_ACT (0x00000010)
+#define PORTSCX_OVER_CURRENT_CHG (0x00000020)
+#define PORTSCX_PORT_FORCE_RESUME (0x00000040)
+#define PORTSCX_PORT_SUSPEND (0x00000080)
+#define PORTSCX_PORT_RESET (0x00000100)
+#define PORTSCX_LINE_STATUS_BITS (0x00000C00)
+#define PORTSCX_PORT_POWER (0x00001000)
+#define PORTSCX_PORT_INDICTOR_CTRL (0x0000C000)
+#define PORTSCX_PORT_TEST_CTRL (0x000F0000)
+#define PORTSCX_WAKE_ON_CONNECT_EN (0x00100000)
+#define PORTSCX_WAKE_ON_CONNECT_DIS (0x00200000)
+#define PORTSCX_WAKE_ON_OVER_CURRENT (0x00400000)
+#define PORTSCX_PHY_LOW_POWER_SPD (0x00800000)
+#define PORTSCX_PORT_FORCE_FULL_SPEED (0x01000000)
+#define PORTSCX_PORT_SPEED_MASK (0x0C000000)
+#define PORTSCX_PORT_WIDTH (0x10000000)
+#define PORTSCX_PHY_TYPE_SEL (0xC0000000)
+
+/* bit 11-10 are line status */
+#define PORTSCX_LINE_STATUS_SE0 (0x00000000)
+#define PORTSCX_LINE_STATUS_JSTATE (0x00000400)
+#define PORTSCX_LINE_STATUS_KSTATE (0x00000800)
+#define PORTSCX_LINE_STATUS_UNDEF (0x00000C00)
+#define PORTSCX_LINE_STATUS_BIT_POS (10)
+
+/* bit 15-14 are port indicator control */
+#define PORTSCX_PIC_OFF (0x00000000)
+#define PORTSCX_PIC_AMBER (0x00004000)
+#define PORTSCX_PIC_GREEN (0x00008000)
+#define PORTSCX_PIC_UNDEF (0x0000C000)
+#define PORTSCX_PIC_BIT_POS (14)
+
+/* bit 19-16 are port test control */
+#define PORTSCX_PTC_DISABLE (0x00000000)
+#define PORTSCX_PTC_JSTATE (0x00010000)
+#define PORTSCX_PTC_KSTATE (0x00020000)
+#define PORTSCX_PTC_SE0NAK (0x00030000)
+#define PORTSCX_PTC_PACKET (0x00040000)
+#define PORTSCX_PTC_FORCE_EN (0x00050000)
+#define PORTSCX_PTC_BIT_POS (16)
+
+/* bit 27-26 are port speed */
+#define PORTSCX_PORT_SPEED_FULL (0x00000000)
+#define PORTSCX_PORT_SPEED_LOW (0x04000000)
+#define PORTSCX_PORT_SPEED_HIGH (0x08000000)
+#define PORTSCX_PORT_SPEED_UNDEF (0x0C000000)
+#define PORTSCX_SPEED_BIT_POS (26)
+
+/* bit 28 is parallel transceiver width for UTMI interface */
+#define PORTSCX_PTW (0x10000000)
+#define PORTSCX_PTW_8BIT (0x00000000)
+#define PORTSCX_PTW_16BIT (0x10000000)
+
+/* bit 31-30 are port transceiver select */
+#define PORTSCX_PTS_UTMI (0x00000000)
+#define PORTSCX_PTS_CLASSIC (0x40000000)
+#define PORTSCX_PTS_ULPI (0x80000000)
+#define PORTSCX_PTS_FSLS (0xC0000000)
+#define PORTSCX_PTS_BIT_POS (30)
+
+/* USB MODE Register Bit Masks */
+#define USBMODE_CTRL_MODE_IDLE (0x00000000)
+#define USBMODE_CTRL_MODE_DEVICE (0x00000002)
+#define USBMODE_CTRL_MODE_HOST (0x00000003)
+#define USBMODE_CTRL_MODE_RSV (0x00000001)
+#define USBMODE_SETUP_LOCK_OFF (0x00000008)
+#define USBMODE_STREAM_DISABLE (0x00000010)
+
+/* ENDPOINTCTRLx Register Bit Masks */
+#define EPCTRL_TX_ENABLE (0x00800000)
+#define EPCTRL_TX_DATA_TOGGLE_RST (0x00400000) /* Not EP0 */
+#define EPCTRL_TX_DATA_TOGGLE_INH (0x00200000) /* Not EP0 */
+#define EPCTRL_TX_TYPE (0x000C0000)
+#define EPCTRL_TX_DATA_SOURCE (0x00020000) /* Not EP0 */
+#define EPCTRL_TX_EP_STALL (0x00010000)
+#define EPCTRL_RX_ENABLE (0x00000080)
+#define EPCTRL_RX_DATA_TOGGLE_RST (0x00000040) /* Not EP0 */
+#define EPCTRL_RX_DATA_TOGGLE_INH (0x00000020) /* Not EP0 */
+#define EPCTRL_RX_TYPE (0x0000000C)
+#define EPCTRL_RX_DATA_SINK (0x00000002) /* Not EP0 */
+#define EPCTRL_RX_EP_STALL (0x00000001)
+
+/* bit 19-18 and 3-2 are endpoint type */
+#define EPCTRL_TX_EP_TYPE_SHIFT (18)
+#define EPCTRL_RX_EP_TYPE_SHIFT (2)
+
+#define QH_MULT_POS (30)
+#define QH_ZLT_SEL (0x20000000)
+#define QH_MAX_PKT_LEN_POS (16)
+#define QH_IOS (0x00008000)
+#define QH_NEXT_TERMINATE (0x00000001)
+#define QH_IOC (0x00008000)
+#define QH_MULTO (0x00000C00)
+#define QH_STATUS_HALT (0x00000040)
+#define QH_STATUS_ACTIVE (0x00000080)
+#define EP_QUEUE_CURRENT_OFFSET_MASK (0x00000FFF)
+#define EP_QUEUE_HEAD_NEXT_POINTER_MASK (0xFFFFFFE0)
+#define EP_QUEUE_FRINDEX_MASK (0x000007FF)
+#define EP_MAX_LENGTH_TRANSFER (0x4000)
+
+#define DTD_NEXT_TERMINATE (0x00000001)
+#define DTD_IOC (0x00008000)
+#define DTD_STATUS_ACTIVE (0x00000080)
+#define DTD_STATUS_HALTED (0x00000040)
+#define DTD_STATUS_DATA_BUFF_ERR (0x00000020)
+#define DTD_STATUS_TRANSACTION_ERR (0x00000008)
+#define DTD_RESERVED_FIELDS (0x80007300)
+#define DTD_ADDR_MASK (0xFFFFFFE0)
+#define DTD_PACKET_SIZE (0x7FFF0000)
+#define DTD_LENGTH_BIT_POS (16)
+#define DTD_ERROR_MASK (DTD_STATUS_HALTED | \
+ DTD_STATUS_DATA_BUFF_ERR | \
+ DTD_STATUS_TRANSACTION_ERR)
+/*-------------------------------------------------------------------------*/
+/* manual: 32.13.2 Endpoint Transfer Descriptor (dTD) */
+struct transfer_descriptor {
+ unsigned int next_td_ptr; /* Next TD pointer(31-5), T(0) set
+ indicate invalid */
+ unsigned int size_ioc_sts; /* Total bytes (30-16), IOC (15),
+ MultO(11-10), STS (7-0) */
+ unsigned int buff_ptr0; /* Buffer pointer Page 0 */
+ unsigned int buff_ptr1; /* Buffer pointer Page 1 */
+ unsigned int buff_ptr2; /* Buffer pointer Page 2 */
+ unsigned int buff_ptr3; /* Buffer pointer Page 3 */
+ unsigned int buff_ptr4; /* Buffer pointer Page 4 */
+ unsigned int reserved;
+} __attribute__ ((packed));
+
+static struct transfer_descriptor td_array[USB_NUM_ENDPOINTS*2]
+ __attribute__((aligned(32)));
+
+/* manual: 32.13.1 Endpoint Queue Head (dQH) */
+struct queue_head {
+ unsigned int max_pkt_length; /* Mult(31-30) , Zlt(29) , Max Pkt len
+ and IOS(15) */
+ unsigned int curr_dtd_ptr; /* Current dTD Pointer(31-5) */
+ struct transfer_descriptor dtd; /* dTD overlay */
+ unsigned int setup_buffer[2]; /* Setup data 8 bytes */
+ unsigned int reserved; /* for software use, pointer to the first TD */
+ unsigned int status; /* for software use, status of chain in progress */
+ unsigned int length; /* for software use, transfered bytes of chain in progress */
+ unsigned int wait; /* for softwate use, indicates if the transfer is blocking */
+} __attribute__((packed));
+
+static struct queue_head qh_array[USB_NUM_ENDPOINTS*2] __attribute__((aligned(2048)));
+
+static const unsigned int pipe2mask[] = {
+ 0x01, 0x010000,
+ 0x02, 0x020000,
+ 0x04, 0x040000,
+ 0x08, 0x080000,
+ 0x10, 0x100000,
+};
+
+/* return transfered size if wait=true */
+static int prime_transfer(int ep_num, void *ptr, int len, bool send, bool wait)
+{
+ int pipe = ep_num * 2 + (send ? 1 : 0);
+ unsigned mask = pipe2mask[pipe];
+ struct transfer_descriptor *td = &td_array[pipe];
+ struct queue_head* qh = &qh_array[pipe];
+
+ /* prepare TD */
+ td->next_td_ptr = DTD_NEXT_TERMINATE;
+ td->size_ioc_sts = (len<< DTD_LENGTH_BIT_POS) | DTD_STATUS_ACTIVE;
+ td->buff_ptr0 = (unsigned int)ptr;
+ td->buff_ptr1 = ((unsigned int)ptr & 0xfffff000) + 0x1000;
+ td->buff_ptr2 = ((unsigned int)ptr & 0xfffff000) + 0x2000;
+ td->buff_ptr3 = ((unsigned int)ptr & 0xfffff000) + 0x3000;
+ td->buff_ptr4 = ((unsigned int)ptr & 0xfffff000) + 0x4000;
+ td->reserved = 0;
+ /* prime */
+ qh->dtd.next_td_ptr = (unsigned int)td;
+ qh->dtd.size_ioc_sts &= ~(QH_STATUS_HALT | QH_STATUS_ACTIVE);
+ REG_ENDPTPRIME |= mask;
+ /* wait for priming to be taken into account */
+ while(!(REG_ENDPTSTATUS & mask));
+ /* wait for completion */
+ if(wait)
+ {
+ while(!(REG_ENDPTCOMPLETE & mask));
+ REG_ENDPTCOMPLETE = mask;
+ /* memory barrier */
+ asm volatile("":::"memory");
+ /* return transfered size */
+ return len - (td->size_ioc_sts >> DTD_LENGTH_BIT_POS);
+ }
+ else
+ return 0;
+}
+
+void usb_drv_set_address(int address)
+{
+ REG_DEVICEADDR = address << USBDEVICEADDRESS_BIT_POS;
+}
+
+/* endpoints */
+
+int usb_drv_send_nonblocking(int endpoint, void* ptr, int length)
+{
+ return prime_transfer(EP_NUM(endpoint), ptr, length, true, false);
+}
+
+int usb_drv_send(int endpoint, void* ptr, int length)
+{
+ return prime_transfer(EP_NUM(endpoint), ptr, length, true, true);
+}
+
+int usb_drv_recv(int endpoint, void* ptr, int length)
+{
+ return prime_transfer(EP_NUM(endpoint), ptr, length, false, true);
+}
+
+int usb_drv_recv_nonblocking(int endpoint, void* ptr, int length)
+{
+ return prime_transfer(EP_NUM(endpoint), ptr, length, false, false);
+}
+
+int usb_drv_port_speed(void)
+{
+ return (REG_PORTSC1 & 0x08000000) ? 1 : 0;
+}
+
+void usb_drv_stall(int endpoint, bool stall, bool in)
+{
+ int ep_num = EP_NUM(endpoint);
+
+ if(in)
+ {
+ if(stall)
+ REG_ENDPTCTRL(ep_num) |= EPCTRL_TX_EP_STALL;
+ else
+ REG_ENDPTCTRL(ep_num) &= ~EPCTRL_TX_EP_STALL;
+ }
+ else
+ {
+ if (stall)
+ REG_ENDPTCTRL(ep_num) |= EPCTRL_RX_EP_STALL;
+ else
+ REG_ENDPTCTRL(ep_num) &= ~EPCTRL_RX_EP_STALL;
+ }
+}
+
+void usb_drv_configure_endpoint(int ep_num, int type)
+{
+ REG_ENDPTCTRL(ep_num) =
+ EPCTRL_RX_DATA_TOGGLE_RST | EPCTRL_RX_ENABLE |
+ EPCTRL_TX_DATA_TOGGLE_RST | EPCTRL_TX_ENABLE |
+ (type << EPCTRL_RX_EP_TYPE_SHIFT) |
+ (type << EPCTRL_TX_EP_TYPE_SHIFT);
+}
+
+void usb_drv_init(void)
+{
+ /* we don't know if USB was connected or not. In USB recovery mode it will
+ * but in other cases it might not be. In doubt, disconnect */
+ REG_USBCMD &= ~USBCMD_RUN;
+ /* reset the controller */
+ REG_USBCMD |= USBCMD_CTRL_RESET;
+ while (REG_USBCMD & USBCMD_CTRL_RESET);
+ /* put it in device mode */
+ REG_USBMODE = USBMODE_CTRL_MODE_DEVICE;
+ /* reset address */
+ REG_DEVICEADDR = 0;
+ /* prepare qh array */
+ qh_array[0].max_pkt_length = 1 << 29 | MAX_PKT_SIZE_EP0 << 16;
+ qh_array[1].max_pkt_length = 1 << 29 | MAX_PKT_SIZE_EP0 << 16;
+ qh_array[2].max_pkt_length = 1 << 29 | MAX_PKT_SIZE << 16;
+ qh_array[3].max_pkt_length = 1 << 29 | MAX_PKT_SIZE << 16;
+ /* setup qh */
+ REG_ENDPOINTLISTADDR = (unsigned int)qh_array;
+ /* clear setup status */
+ REG_ENDPTSETUPSTAT = EPSETUP_STATUS_EP0;
+ /* run! */
+ REG_USBCMD |= USBCMD_RUN;
+}
+
+void usb_drv_exit(void)
+{
+ REG_USBCMD &= ~USBCMD_RUN;
+ REG_USBCMD |= USBCMD_CTRL_RESET;
+}
+
+int usb_drv_recv_setup(struct usb_ctrlrequest *req)
+{
+ /* wait for setup */
+ while(!(REG_ENDPTSETUPSTAT & EPSETUP_STATUS_EP0))
+ ;
+ /* clear setup status */
+ REG_ENDPTSETUPSTAT = EPSETUP_STATUS_EP0;
+ /* check request */
+ asm volatile("":::"memory");
+ /* copy */
+ memcpy(req, (void *)&qh_array[0].setup_buffer[0], sizeof(struct usb_ctrlrequest));
+ return 0;
+}