Removing obsolete directory, moved to cpu/arm/at91sam7s/
This commit is contained in:
parent
217eaaa071
commit
cd30fa2b50
60 changed files with 0 additions and 8724 deletions
|
@ -1,172 +0,0 @@
|
||||||
/***********************************************************************/
|
|
||||||
/* */
|
|
||||||
/* Linker Script File for the AT91SAM7S64 - Code in ROM */
|
|
||||||
/* */
|
|
||||||
/***********************************************************************/
|
|
||||||
/* modified for arm-elf-gcc by Martin Thomas */
|
|
||||||
/* extensions: - Section for Functions in RAM, */
|
|
||||||
/* Exeception-Vector remapping */
|
|
||||||
/* modifications Copyright Martin Thomas 2005 */
|
|
||||||
/* */
|
|
||||||
/* */
|
|
||||||
/* Based on file that has been a part of the uVision/ARM development */
|
|
||||||
/* tools, Copyright KEIL ELEKTRONIK GmbH 2002-2004 */
|
|
||||||
/***********************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
//*** <<< Use Configuration Wizard in Context Menu >>> ***
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
// <h> Memory Configuration
|
|
||||||
// <h> Code (Read Only)
|
|
||||||
// <o> Start <0x0-0xFFFFFFFF>
|
|
||||||
// <o1> Size <0x0-0xFFFFFFFF>
|
|
||||||
// </h>
|
|
||||||
// <h> Data (Read/Write)
|
|
||||||
// <o2> Start <0x0-0xFFFFFFFF>
|
|
||||||
// <o3> Size <0x0-0xFFFFFFFF>
|
|
||||||
// </h>
|
|
||||||
// </h>
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Memory Definitions */
|
|
||||||
|
|
||||||
MEMORY
|
|
||||||
{
|
|
||||||
CODE (rx) : ORIGIN = 0x00100000, LENGTH = 0x00010000
|
|
||||||
DATA (rw) : ORIGIN = 0x00200000, LENGTH = 0x00004000
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Section Definitions */
|
|
||||||
|
|
||||||
SECTIONS
|
|
||||||
{
|
|
||||||
|
|
||||||
/* first section is .text which is used for code */
|
|
||||||
|
|
||||||
.text :
|
|
||||||
{
|
|
||||||
/* *startup.o (.text) */ /* Startup code */
|
|
||||||
KEEP(*(.vectrom)) /* added by mthomas */
|
|
||||||
KEEP(*(.init))
|
|
||||||
*(.text .text.*)
|
|
||||||
*(.gnu.linkonce.t.*)
|
|
||||||
*(.glue_7t .glue_7)
|
|
||||||
KEEP(*(.fini))
|
|
||||||
*(.gcc_except_table)
|
|
||||||
} >CODE =0
|
|
||||||
|
|
||||||
. = ALIGN(4);
|
|
||||||
|
|
||||||
|
|
||||||
/* .ctors .dtors are used for c++ constructors/destructors */
|
|
||||||
/* added by mthomas, based on an Anglia-Designs example for STR7 */
|
|
||||||
|
|
||||||
.ctors :
|
|
||||||
{
|
|
||||||
PROVIDE(__ctors_start__ = .);
|
|
||||||
KEEP(*(SORT(.ctors.*)))
|
|
||||||
KEEP(*(.ctors))
|
|
||||||
PROVIDE(__ctors_end__ = .);
|
|
||||||
} >CODE
|
|
||||||
|
|
||||||
.dtors :
|
|
||||||
{
|
|
||||||
PROVIDE(__dtors_start__ = .);
|
|
||||||
KEEP(*(SORT(.dtors.*)))
|
|
||||||
KEEP(*(.dtors))
|
|
||||||
PROVIDE(__dtors_end__ = .);
|
|
||||||
} >CODE
|
|
||||||
|
|
||||||
/* .rodata section which is used for read-only data (constants) */
|
|
||||||
|
|
||||||
.rodata :
|
|
||||||
{
|
|
||||||
*(.rodata .rodata.*)
|
|
||||||
*(.gnu.linkonce.r.*)
|
|
||||||
} >CODE
|
|
||||||
|
|
||||||
. = ALIGN(4);
|
|
||||||
_etext = . ;
|
|
||||||
PROVIDE (etext = .);
|
|
||||||
|
|
||||||
.data : AT (_etext)
|
|
||||||
{
|
|
||||||
_data = . ;
|
|
||||||
KEEP(*(.vectram)) /* added by mthomas */
|
|
||||||
*(.data)
|
|
||||||
SORT(CONSTRUCTORS)
|
|
||||||
. = ALIGN(4);
|
|
||||||
*(.fastrun) /* "RAM-Functions" */ /* added by mthomas */
|
|
||||||
} >DATA
|
|
||||||
. = ALIGN(4);
|
|
||||||
|
|
||||||
_edata = . ;
|
|
||||||
PROVIDE (edata = .);
|
|
||||||
|
|
||||||
/* .bss section which is used for uninitialized data */
|
|
||||||
|
|
||||||
.bss :
|
|
||||||
{
|
|
||||||
__bss_start = . ;
|
|
||||||
__bss_start__ = . ;
|
|
||||||
*(.bss)
|
|
||||||
*(COMMON)
|
|
||||||
} >DATA
|
|
||||||
. = ALIGN(4);
|
|
||||||
__bss_end__ = . ;
|
|
||||||
__bss_end__ = . ;
|
|
||||||
_end = .;
|
|
||||||
PROVIDE (end = .);
|
|
||||||
|
|
||||||
.stack ORIGIN(DATA) + LENGTH(DATA) - 0x0a0c :
|
|
||||||
{
|
|
||||||
__stack_start__ = . ;
|
|
||||||
*(.stack)
|
|
||||||
. = ALIGN(4);
|
|
||||||
__stack_end__ = . ;
|
|
||||||
} >DATA
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
__heap_start__ = __bss_end__ ;
|
|
||||||
__heap_end__ = __stack_start__ ;
|
|
||||||
|
|
||||||
/* Stabs debugging sections. */
|
|
||||||
.stab 0 : { *(.stab) }
|
|
||||||
.stabstr 0 : { *(.stabstr) }
|
|
||||||
.stab.excl 0 : { *(.stab.excl) }
|
|
||||||
.stab.exclstr 0 : { *(.stab.exclstr) }
|
|
||||||
.stab.index 0 : { *(.stab.index) }
|
|
||||||
.stab.indexstr 0 : { *(.stab.indexstr) }
|
|
||||||
.comment 0 : { *(.comment) }
|
|
||||||
/* DWARF debug sections.
|
|
||||||
Symbols in the DWARF debugging sections are relative to the beginning
|
|
||||||
of the section so we begin them at 0. */
|
|
||||||
/* DWARF 1 */
|
|
||||||
.debug 0 : { *(.debug) }
|
|
||||||
.line 0 : { *(.line) }
|
|
||||||
/* GNU DWARF 1 extensions */
|
|
||||||
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
|
||||||
.debug_sfnames 0 : { *(.debug_sfnames) }
|
|
||||||
/* DWARF 1.1 and DWARF 2 */
|
|
||||||
.debug_aranges 0 : { *(.debug_aranges) }
|
|
||||||
.debug_pubnames 0 : { *(.debug_pubnames) }
|
|
||||||
/* DWARF 2 */
|
|
||||||
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
|
||||||
.debug_abbrev 0 : { *(.debug_abbrev) }
|
|
||||||
.debug_line 0 : { *(.debug_line) }
|
|
||||||
.debug_frame 0 : { *(.debug_frame) }
|
|
||||||
.debug_str 0 : { *(.debug_str) }
|
|
||||||
.debug_loc 0 : { *(.debug_loc) }
|
|
||||||
.debug_macinfo 0 : { *(.debug_macinfo) }
|
|
||||||
/* SGI/MIPS DWARF 2 extensions */
|
|
||||||
.debug_weaknames 0 : { *(.debug_weaknames) }
|
|
||||||
.debug_funcnames 0 : { *(.debug_funcnames) }
|
|
||||||
.debug_typenames 0 : { *(.debug_typenames) }
|
|
||||||
.debug_varnames 0 : { *(.debug_varnames) }
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,182 +0,0 @@
|
||||||
# Adapted from Makefile.msp430
|
|
||||||
|
|
||||||
### Defin the CPU directory
|
|
||||||
CONTIKI_CPU=$(CONTIKI)/cpu/at91sam7s
|
|
||||||
|
|
||||||
### Define the source files we have in the AT91SAM7S port
|
|
||||||
|
|
||||||
CONTIKI_CPU_DIRS = . dbg-io loader usb
|
|
||||||
|
|
||||||
AT91SAM7S = clock.c debug-uart.c interrupt-utils.c newlib-syscalls.c sys-interrupt.c rtimer-arch.c rtimer-arch-interrupt.c uip-log.c
|
|
||||||
|
|
||||||
SYSAPPS = codeprop-otf.c
|
|
||||||
APPDIRS += $(CONTIKI)/cpu/at91sam7s/loader
|
|
||||||
|
|
||||||
ELFLOADER = elfloader-otf.c elfloader-arm.c symtab.c cfs-ram.c
|
|
||||||
|
|
||||||
USB = usb-proto.c usb-handler.c usb-interrupt.c cdc-acm.c descriptors.c string-descriptors.c
|
|
||||||
|
|
||||||
TARGETLIBS = random.c dbg-printf.c dbg-puts.c dbg-putchar.c dbg-sprintf.c strformat.c
|
|
||||||
|
|
||||||
CONTIKI_TARGET_SOURCEFILES += $(AT91SAM7S) $(SYSAPPS) $(ELFLOADER) \
|
|
||||||
$(TARGETLIBS) $(UIPDRIVERS) $(USB)
|
|
||||||
|
|
||||||
CONTIKI_SOURCEFILES += $(CONTIKI_TARGET_SOURCEFILES)
|
|
||||||
|
|
||||||
|
|
||||||
THREADS =
|
|
||||||
|
|
||||||
### Compiler definitions
|
|
||||||
CC = arm-elf-gcc
|
|
||||||
LD = arm-elf-ld
|
|
||||||
AS = arm-elf-as
|
|
||||||
AR = arm-elf-ar
|
|
||||||
NM = arm-elf-nm
|
|
||||||
OBJCOPY = arm-elf-objcopy
|
|
||||||
STRIP = arm-elf-strip
|
|
||||||
|
|
||||||
XSLTPROC=xsltproc
|
|
||||||
|
|
||||||
PROJECT_OBJECTFILES += ${addprefix $(OBJECTDIR)/,$(CONTIKI_TARGET_MAIN:.c=.o)}
|
|
||||||
|
|
||||||
LINKERSCRIPT = $(CONTIKI_CPU)/AT91SAM7S64-ROM.ld
|
|
||||||
|
|
||||||
STARTUP=${addprefix $(OBJECTDIR)/,startup-SAM7S.o}
|
|
||||||
|
|
||||||
# JTAG program upload
|
|
||||||
OPENOCD = openocd
|
|
||||||
OPENOCD_FLASH_CFG = arm7_wig_flash.cfg
|
|
||||||
OPENOCD_RESET = arm7_wig_reset.cfg
|
|
||||||
|
|
||||||
# USB program upload
|
|
||||||
SAMIAM=Sam_I_Am
|
|
||||||
SAMIAM_TTY=/dev/ttyACM0
|
|
||||||
|
|
||||||
ARCH_FLAGS= -mcpu=arm7tdmi -mthumb-interwork
|
|
||||||
THUMB_FLAGS=-mthumb
|
|
||||||
ARM_FLAGS=
|
|
||||||
|
|
||||||
|
|
||||||
CFLAGSNO = -I. -I$(CONTIKI)/core -I$(CONTIKI_CPU) -I$(CONTIKI_CPU)/loader \
|
|
||||||
-I$(CONTIKI_CPU)/dbg-io \
|
|
||||||
-I$(CONTIKI)/platform/$(TARGET) \
|
|
||||||
${addprefix -I,$(APPDIRS)} \
|
|
||||||
-DWITH_UIP -DWITH_ASCII -DMCK=$(MCK) \
|
|
||||||
-Wall -Werror $(ARCH_FLAGS) -g
|
|
||||||
|
|
||||||
CFLAGS += $(CFLAGSNO) -O -DRUN_AS_SYSTEM -DROM_RUN
|
|
||||||
LDFLAGS += -T $(LINKERSCRIPT) -nostartfiles
|
|
||||||
|
|
||||||
CDEPFLAGS = $(CFLAGS) -D __MAKING_DEPS__
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Setup directory search path for source files
|
|
||||||
|
|
||||||
CUSTOM_RULE_C_TO_OBJECTDIR_O=yes
|
|
||||||
CUSTOM_RULE_C_TO_O=yes
|
|
||||||
|
|
||||||
%-interrupt.o: %-interrupt.c
|
|
||||||
$(CC) $(CFLAGS) $(ARM_FLAGS) $< -c
|
|
||||||
|
|
||||||
$(OBJECTDIR)/%-interrupt.o: %-interrupt.c
|
|
||||||
$(CC) $(CFLAGS) $(ARM_FLAGS) -c $< -o $@
|
|
||||||
|
|
||||||
%-arm.o: %-arm.c
|
|
||||||
$(CC) $(CFLAGS) $(ARM_FLAGS) $< -c
|
|
||||||
|
|
||||||
$(OBJECTDIR)/%-arm.o: %-arm.c
|
|
||||||
$(CC) $(CFLAGS) $(ARM_FLAGS) -c $< -o $@
|
|
||||||
|
|
||||||
$(OBJECTDIR)/interrupt-utils.o: interrupt-utils.c
|
|
||||||
$(CC) $(CFLAGS) $(ARM_FLAGS) $< -c -o $@
|
|
||||||
|
|
||||||
%.o: %.c
|
|
||||||
$(CC) $(CFLAGS) $(THUMB_FLAGS) $< -c
|
|
||||||
|
|
||||||
$(OBJECTDIR)/%.o: %.c
|
|
||||||
$(CC) $(CFLAGS) $(THUMB_FLAGS) -c $< -o $@
|
|
||||||
|
|
||||||
CUSTOM_RULE_S_TO_OBJECTDIR_O = yes
|
|
||||||
%.o: %.S
|
|
||||||
$(CC) $(CFLAGS) $(ARM_FLAGS) $< -c
|
|
||||||
|
|
||||||
$(OBJECTDIR)/%.o: %.S
|
|
||||||
$(CC) $(CFLAGS) $(ARM_FLAGS) $< -c -o $@
|
|
||||||
|
|
||||||
|
|
||||||
CUSTOM_RULE_C_TO_CO=yes
|
|
||||||
|
|
||||||
%.co: %.c
|
|
||||||
$(CC) $(CFLAGS) $(THUMB_FLAGS) $< -c -o $@
|
|
||||||
|
|
||||||
CUSTOM_RULE_C_TO_CE=yes
|
|
||||||
|
|
||||||
%.ce: %.o
|
|
||||||
$(LD) $(LDFLAGS) --relocatable -T $(CONTIKI_CPU)/merge-rodata.ld $< -o $@
|
|
||||||
$(STRIP) -K _init -K _fini --strip-unneeded -g -x $@
|
|
||||||
|
|
||||||
CUSTOM_RULE_LINK=yes
|
|
||||||
|
|
||||||
%-stripped.o: %.c
|
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
|
||||||
$(STRIP) --strip-unneeded -g -x $@
|
|
||||||
|
|
||||||
%-stripped.o: %.o
|
|
||||||
$(STRIP) --strip-unneeded -g -x -o $@ $<
|
|
||||||
|
|
||||||
%.o: ${CONTIKI_TARGET}/loader/%.S
|
|
||||||
$(AS) -o $(notdir $(<:.S=.o)) $<
|
|
||||||
|
|
||||||
%-nosyms.$(TARGET): %.co $(PROJECT_OBJECTFILES) contiki-$(TARGET).a $(STARTUP) $(OBJECTDIR)/empty-symbols.o
|
|
||||||
$(CC) $(LDFLAGS) $(CFLAGS) -nostartfiles -o $@ $(filter-out %.a,$^) $(filter %.a,$^) -lc $(filter %.a,$^)
|
|
||||||
|
|
||||||
|
|
||||||
%.ihex: %.$(TARGET)
|
|
||||||
$(OBJCOPY) $^ -O ihex $@
|
|
||||||
|
|
||||||
%.bin: %.$(TARGET)
|
|
||||||
$(OBJCOPY) -O binary $< $@
|
|
||||||
|
|
||||||
.PHONY: symbols.c
|
|
||||||
ifdef CORE
|
|
||||||
%.$(TARGET): %.co $(PROJECT_OBJECTFILES) contiki-$(TARGET).a $(STARTUP) $(OBJECTDIR)/symbols.o
|
|
||||||
$(CC) $(LDFLAGS) $(CFLAGS) -nostartfiles -o $@ $(filter-out %.a,$^) $(filter %.a,$^) -lc $(filter %.a,$^)
|
|
||||||
|
|
||||||
symbols.c: $(CORE)
|
|
||||||
$(NM) $< | awk -f $(CONTIKI_CPU)/builtins.awk -f $(CONTIKI)/tools/mknmlist > symbols.c
|
|
||||||
|
|
||||||
else
|
|
||||||
%.$(TARGET): %-nosyms.$(TARGET)
|
|
||||||
ln -sf $< $@
|
|
||||||
endif
|
|
||||||
|
|
||||||
empty-symbols.c:
|
|
||||||
@${CONTIKI}/tools/make-empty-symbols
|
|
||||||
|
|
||||||
$(CONTIKI_CPU)/usb/string-descriptors.c: \
|
|
||||||
$(CONTIKI_CPU)/usb/string-descriptors.xml
|
|
||||||
$(XSLTPROC) $(CONTIKI_CPU)/usb/string-descriptors.xslt $^ >$@
|
|
||||||
|
|
||||||
upload_ocd_%: %.bin
|
|
||||||
cp $< /tmp/openocd_write.bin
|
|
||||||
# Clear lock bits
|
|
||||||
cd $(CONTIKI_CPU)/openocd;$(OPENOCD) -f $(OPENOCD_FLASH_CFG)
|
|
||||||
-rm /tmp/openocd_write.bin
|
|
||||||
|
|
||||||
|
|
||||||
upload_%: %.ihex
|
|
||||||
# Clear lock bits
|
|
||||||
$(SAMIAM) "open $(SAMIAM_TTY) , writew 0xffffff64 5a000004"
|
|
||||||
$(SAMIAM) "open $(SAMIAM_TTY) , writew 0xffffff64 5a002004"
|
|
||||||
$(SAMIAM) "open $(SAMIAM_TTY) , flash $< , go"
|
|
||||||
|
|
||||||
ocd_reset:
|
|
||||||
cd $(CONTIKI_CPU)/openocd;$(OPENOCD) -f $(OPENOCD_RESET)
|
|
||||||
|
|
||||||
# Don't use core/loader/elfloader.c, use elfloader-otf.c instead
|
|
||||||
$(OBJECTDIR)/elfloader.o:
|
|
||||||
echo -n >$@
|
|
||||||
|
|
||||||
.PRECIOUS: %-nosyms.$(TARGET)
|
|
|
@ -1,4 +0,0 @@
|
||||||
BEGIN {
|
|
||||||
builtin["_exit"] = "void _exit()";
|
|
||||||
builtin["strlen"] = "unsigned long strlen()";
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
#include <sys/clock.h>
|
|
||||||
#include <sys/cc.h>
|
|
||||||
#include <sys/etimer.h>
|
|
||||||
#include <debug-uart.h>
|
|
||||||
|
|
||||||
#include <AT91SAM7S64.h>
|
|
||||||
#include <sys-interrupt.h>
|
|
||||||
|
|
||||||
static volatile clock_time_t current_clock = 0;
|
|
||||||
|
|
||||||
#define PIV ((MCK/CLOCK_SECOND/16)-1)
|
|
||||||
|
|
||||||
static int pit_handler_func()
|
|
||||||
{
|
|
||||||
if (!(*AT91C_PITC_PISR & AT91C_PITC_PITS)) return 0; /* Check PIT
|
|
||||||
Interrupt */
|
|
||||||
current_clock++;
|
|
||||||
if(etimer_pending() && etimer_next_expiration_time() <= current_clock) {
|
|
||||||
etimer_request_poll();
|
|
||||||
/* dbg_printf("%d,%d\n", clock_time(),etimer_next_expiration_time ()); */
|
|
||||||
|
|
||||||
}
|
|
||||||
(void)*AT91C_PITC_PIVR;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static SystemInterruptHandler pit_handler = {NULL, pit_handler_func};
|
|
||||||
|
|
||||||
void
|
|
||||||
clock_init()
|
|
||||||
{
|
|
||||||
sys_interrupt_append_handler(&pit_handler);
|
|
||||||
*AT91C_PITC_PIMR = (AT91C_PITC_PITIEN | /* PIT Interrupt Enable */
|
|
||||||
AT91C_PITC_PITEN | /* PIT Enable */
|
|
||||||
PIV);
|
|
||||||
sys_interrupt_enable();
|
|
||||||
}
|
|
||||||
|
|
||||||
clock_time_t
|
|
||||||
clock_time(void)
|
|
||||||
{
|
|
||||||
return current_clock;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The inner loop takes 4 cycles. The outer 5+SPIN_COUNT*4. */
|
|
||||||
|
|
||||||
#define SPIN_TIME 2 /* us */
|
|
||||||
#define SPIN_COUNT (((MCK*SPIN_TIME/1000000)-5)/4)
|
|
||||||
|
|
||||||
#ifndef __MAKING_DEPS__
|
|
||||||
|
|
||||||
void
|
|
||||||
clock_delay(unsigned int t)
|
|
||||||
{
|
|
||||||
#ifdef __THUMBEL__
|
|
||||||
asm volatile("1: mov r1,%2\n2:\tsub r1,#1\n\tbne 2b\n\tsub %0,#1\n\tbne 1b\n":"=l"(t):"0"(t),"l"(SPIN_COUNT));
|
|
||||||
#else
|
|
||||||
#error Must be compiled in thumb mode
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* __MAKING_DEPS__ */
|
|
|
@ -1,30 +0,0 @@
|
||||||
#include <stdio.h>
|
|
||||||
#include <debug-uart.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <strformat.h>
|
|
||||||
|
|
||||||
static StrFormatResult
|
|
||||||
write_str(void *user_data, const char *data, unsigned int len)
|
|
||||||
{
|
|
||||||
dbg_send_bytes((unsigned char*)data, len);
|
|
||||||
return STRFORMAT_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static StrFormatContext ctxt =
|
|
||||||
{
|
|
||||||
write_str,
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
int
|
|
||||||
printf(const char *fmt, ...)
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
va_list ap;
|
|
||||||
va_start(ap, fmt);
|
|
||||||
res = format_str_v(&ctxt, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
#include <stdio.h>
|
|
||||||
#include <debug-uart.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#undef putchar
|
|
||||||
#undef putc
|
|
||||||
|
|
||||||
int
|
|
||||||
putchar(int c)
|
|
||||||
{
|
|
||||||
dbg_putchar(c);
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
putc(int c, FILE *f)
|
|
||||||
{
|
|
||||||
dbg_putchar(c);
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
__sp(struct _reent *_ptr, int c, FILE *_p) {
|
|
||||||
dbg_putchar(c);
|
|
||||||
return c;
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
#include <stdio.h>
|
|
||||||
#include <debug-uart.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
int
|
|
||||||
puts(const char *str)
|
|
||||||
{
|
|
||||||
dbg_send_bytes((unsigned char*)str, strlen(str));
|
|
||||||
dbg_putchar('\n');
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
#include <stdio.h>
|
|
||||||
#include <strformat.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
static StrFormatResult
|
|
||||||
buffer_str(void *user_data, const char *data, unsigned int len)
|
|
||||||
{
|
|
||||||
memcpy(*(char**)user_data, data, len);
|
|
||||||
(*(char**)user_data) += len;
|
|
||||||
return STRFORMAT_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
sprintf(char *str, const char *format, ...)
|
|
||||||
{
|
|
||||||
StrFormatContext ctxt;
|
|
||||||
int res;
|
|
||||||
va_list ap;
|
|
||||||
va_start(ap, format);
|
|
||||||
ctxt.write_str = buffer_str;
|
|
||||||
ctxt.user_data = &str;
|
|
||||||
res = format_str_v(&ctxt, format, ap);
|
|
||||||
*str = '\0';
|
|
||||||
va_end(ap);
|
|
||||||
return res;
|
|
||||||
}
|
|
|
@ -1,615 +0,0 @@
|
||||||
#include <strformat.h>
|
|
||||||
|
|
||||||
#define HAVE_DOUBLE
|
|
||||||
|
|
||||||
#define HAVE_LONGLONG
|
|
||||||
#ifndef LARGEST_SIGNED
|
|
||||||
#ifdef HAVE_LONGLONG
|
|
||||||
#define LARGEST_SIGNED long long int
|
|
||||||
#else
|
|
||||||
#define LARGEST_UNSIGNED long int
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef LARGEST_UNSIGNED
|
|
||||||
#ifdef HAVE_LONGLONG
|
|
||||||
#define LARGEST_UNSIGNED unsigned long long int
|
|
||||||
#else
|
|
||||||
#define LARGEST_UNSIGNED unsigned long int
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef POINTER_INT
|
|
||||||
#define POINTER_INT unsigned long
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef unsigned int FormatFlags;
|
|
||||||
|
|
||||||
#define MAKE_MASK(shift,size) (((1 << size) - 1) << (shift))
|
|
||||||
|
|
||||||
#define JUSTIFY_SHIFT 0
|
|
||||||
#define JUSTIFY_SIZE 1
|
|
||||||
#define JUSTIFY_RIGHT 0x0000
|
|
||||||
#define JUSTIFY_LEFT 0x0001
|
|
||||||
#define JUSTIFY_MASK MAKE_MASK(JUSTIFY_SHIFT,JUSTIFY_SIZE)
|
|
||||||
|
|
||||||
|
|
||||||
/* How a positive number is prefixed */
|
|
||||||
#define POSITIVE_SHIFT (JUSTIFY_SHIFT + JUSTIFY_SIZE)
|
|
||||||
#define POSITIVE_NONE (0x0000 << POSITIVE_SHIFT)
|
|
||||||
#define POSITIVE_SPACE (0x0001 << POSITIVE_SHIFT)
|
|
||||||
#define POSITIVE_PLUS (0x0003 << POSITIVE_SHIFT)
|
|
||||||
#define POSITIVE_MASK MAKE_MASK(POSITIVE_SHIFT, POSITIVE_SIZE)
|
|
||||||
|
|
||||||
#define POSITIVE_SIZE 2
|
|
||||||
|
|
||||||
#define ALTERNATE_FORM_SHIFT (POSITIVE_SHIFT + POSITIVE_SIZE)
|
|
||||||
#define ALTERNATE_FORM_SIZE 1
|
|
||||||
#define ALTERNATE_FORM (0x0001 << ALTERNATE_FORM_SHIFT)
|
|
||||||
|
|
||||||
|
|
||||||
#define PAD_SHIFT (ALTERNATE_FORM_SHIFT + ALTERNATE_FORM_SIZE)
|
|
||||||
#define PAD_SIZE 1
|
|
||||||
#define PAD_SPACE (0x0000 << PAD_SHIFT)
|
|
||||||
#define PAD_ZERO (0x0001 << PAD_SHIFT)
|
|
||||||
|
|
||||||
#define SIZE_SHIFT (PAD_SHIFT + PAD_SIZE)
|
|
||||||
#define SIZE_SIZE 3
|
|
||||||
#define SIZE_CHAR (0x0001 << SIZE_SHIFT)
|
|
||||||
#define SIZE_SHORT (0x0002 << SIZE_SHIFT)
|
|
||||||
#define SIZE_INT (0x0000 << SIZE_SHIFT)
|
|
||||||
#define SIZE_LONG (0x0003 << SIZE_SHIFT)
|
|
||||||
#define SIZE_LONGLONG (0x0004 << SIZE_SHIFT)
|
|
||||||
#define SIZE_MASK MAKE_MASK(SIZE_SHIFT,SIZE_SIZE)
|
|
||||||
|
|
||||||
#define CONV_SHIFT (SIZE_SHIFT + SIZE_SIZE)
|
|
||||||
#define CONV_SIZE 3
|
|
||||||
#define CONV_INTEGER (0x0001 << CONV_SHIFT)
|
|
||||||
#define CONV_FLOAT (0x0002 << CONV_SHIFT)
|
|
||||||
#define CONV_POINTER (0x0003 << CONV_SHIFT)
|
|
||||||
#define CONV_STRING (0x0004 << CONV_SHIFT)
|
|
||||||
#define CONV_CHAR (0x0005 << CONV_SHIFT)
|
|
||||||
#define CONV_PERCENT (0x0006 << CONV_SHIFT)
|
|
||||||
#define CONV_WRITTEN (0x0007 << CONV_SHIFT)
|
|
||||||
#define CONV_MASK MAKE_MASK(CONV_SHIFT, CONV_SIZE)
|
|
||||||
|
|
||||||
#define RADIX_SHIFT (CONV_SHIFT + CONV_SIZE)
|
|
||||||
#define RADIX_SIZE 2
|
|
||||||
#define RADIX_DECIMAL (0x0001 << RADIX_SHIFT)
|
|
||||||
#define RADIX_OCTAL (0x0002 << RADIX_SHIFT)
|
|
||||||
#define RADIX_HEX (0x0003 << RADIX_SHIFT)
|
|
||||||
#define RADIX_MASK MAKE_MASK(RADIX_SHIFT,RADIX_SIZE)
|
|
||||||
|
|
||||||
#define SIGNED_SHIFT (RADIX_SHIFT + RADIX_SIZE)
|
|
||||||
#define SIGNED_SIZE 1
|
|
||||||
#define SIGNED_NO (0x0000 << SIGNED_SHIFT)
|
|
||||||
#define SIGNED_YES (0x0001 << SIGNED_SHIFT)
|
|
||||||
#define SIGNED_MASK MAKE_MASK(SIGNED_SHIFT,SIGNED_SIZE)
|
|
||||||
|
|
||||||
#define CAPS_SHIFT (SIGNED_SHIFT + SIGNED_SIZE)
|
|
||||||
#define CAPS_SIZE 1
|
|
||||||
#define CAPS_NO (0x0000 << CAPS_SHIFT)
|
|
||||||
#define CAPS_YES (0x0001 << CAPS_SHIFT)
|
|
||||||
#define CAPS_MASK MAKE_MASK(CAPS_SHIFT,CAPS_SIZE)
|
|
||||||
|
|
||||||
#define FLOAT_SHIFT (CAPS_SHIFT + CAPS_SIZE)
|
|
||||||
#define FLOAT_SIZE 2
|
|
||||||
#define FLOAT_NORMAL (0x0000 << FLOAT_SHIFT)
|
|
||||||
#define FLOAT_EXPONENT (0x0001 << FLOAT_SHIFT)
|
|
||||||
#define FLOAT_DEPENDANT (0x0002 << FLOAT_SHIFT)
|
|
||||||
#define FLOAT_HEX (0x0003 << FLOAT_SHIFT)
|
|
||||||
#define FLOAT_MASK MAKE_MASK(FLOAT_SHIFT, FLOAT_SIZE)
|
|
||||||
|
|
||||||
static FormatFlags
|
|
||||||
parse_flags(const char **posp)
|
|
||||||
{
|
|
||||||
FormatFlags flags = 0;
|
|
||||||
const char *pos = *posp;
|
|
||||||
while (1) {
|
|
||||||
switch(*pos) {
|
|
||||||
case '-':
|
|
||||||
flags |= JUSTIFY_LEFT;
|
|
||||||
break;
|
|
||||||
case '+':
|
|
||||||
flags |= POSITIVE_PLUS;
|
|
||||||
break;
|
|
||||||
case ' ':
|
|
||||||
flags |= POSITIVE_SPACE;
|
|
||||||
break;
|
|
||||||
case '#':
|
|
||||||
flags |= ALTERNATE_FORM;
|
|
||||||
break;
|
|
||||||
case '0':
|
|
||||||
flags |= PAD_ZERO;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
*posp = pos;
|
|
||||||
return flags;
|
|
||||||
}
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int
|
|
||||||
parse_uint(const char **posp)
|
|
||||||
{
|
|
||||||
unsigned v = 0;
|
|
||||||
const char *pos = *posp;
|
|
||||||
char ch;
|
|
||||||
while((ch = *pos) >= '0' && ch <= '9') {
|
|
||||||
v = v * 10 + (ch - '0');
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
*posp = pos;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MAXCHARS_HEX ((sizeof(LARGEST_UNSIGNED) * 8) / 4 )
|
|
||||||
|
|
||||||
/* Largest number of characters needed for converting an unsigned integer.
|
|
||||||
*/
|
|
||||||
#define MAXCHARS ((sizeof(LARGEST_UNSIGNED) * 8 + 2) / 3 )
|
|
||||||
|
|
||||||
static unsigned int
|
|
||||||
output_uint_decimal(char **posp, LARGEST_UNSIGNED v)
|
|
||||||
{
|
|
||||||
unsigned int len;
|
|
||||||
char *pos = *posp;
|
|
||||||
while (v > 0) {
|
|
||||||
*--pos = (v % 10) + '0';
|
|
||||||
v /= 10;
|
|
||||||
}
|
|
||||||
len = *posp - pos;
|
|
||||||
*posp = pos;
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int
|
|
||||||
output_uint_hex(char **posp, LARGEST_UNSIGNED v, unsigned int flags)
|
|
||||||
{
|
|
||||||
unsigned int len;
|
|
||||||
const char *hex = (flags & CAPS_YES) ?"0123456789ABCDEF":"0123456789abcdef";
|
|
||||||
char *pos = *posp;
|
|
||||||
while (v > 0) {
|
|
||||||
*--pos = hex[(v % 16)];
|
|
||||||
v /= 16;
|
|
||||||
}
|
|
||||||
len = *posp - pos;
|
|
||||||
*posp = pos;
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int
|
|
||||||
output_uint_octal(char **posp, LARGEST_UNSIGNED v)
|
|
||||||
{
|
|
||||||
unsigned int len;
|
|
||||||
char *pos = *posp;
|
|
||||||
while (v > 0) {
|
|
||||||
*--pos = (v % 8) + '0';
|
|
||||||
v /= 8;
|
|
||||||
}
|
|
||||||
len = *posp - pos;
|
|
||||||
*posp = pos;
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static StrFormatResult
|
|
||||||
fill_space(const StrFormatContext *ctxt, unsigned int len)
|
|
||||||
{
|
|
||||||
StrFormatResult res;
|
|
||||||
static const char buffer[16] = " ";
|
|
||||||
while(len > 16) {
|
|
||||||
res = ctxt->write_str(ctxt->user_data, buffer, 16);
|
|
||||||
if (res != STRFORMAT_OK) return res;
|
|
||||||
len -= 16;
|
|
||||||
}
|
|
||||||
if (len == 0) return STRFORMAT_OK;
|
|
||||||
return ctxt->write_str(ctxt->user_data, buffer, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static StrFormatResult
|
|
||||||
fill_zero(const StrFormatContext *ctxt, unsigned int len)
|
|
||||||
{
|
|
||||||
StrFormatResult res;
|
|
||||||
static const char buffer[16] = "0000000000000000";
|
|
||||||
while(len > 16) {
|
|
||||||
res = ctxt->write_str(ctxt->user_data, buffer, 16);
|
|
||||||
if (res != STRFORMAT_OK) return res;
|
|
||||||
len -= 16;
|
|
||||||
}
|
|
||||||
if (len == 0) return STRFORMAT_OK;
|
|
||||||
return ctxt->write_str(ctxt->user_data, buffer, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define CHECKCB(res) {if ((res) != STRFORMAT_OK) {va_end(ap); return -1;}}
|
|
||||||
|
|
||||||
int
|
|
||||||
format_str(const StrFormatContext *ctxt, const char *format, ...)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
va_list ap;
|
|
||||||
va_start(ap, format);
|
|
||||||
ret = format_str_v(ctxt, format, ap);
|
|
||||||
va_end(ap);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
format_str_v(const StrFormatContext *ctxt, const char *format, va_list ap)
|
|
||||||
{
|
|
||||||
unsigned int written = 0;
|
|
||||||
const char *pos = format;
|
|
||||||
while(*pos != '\0') {
|
|
||||||
FormatFlags flags;
|
|
||||||
unsigned int minwidth = 0;
|
|
||||||
int precision = -1; /* Negative means no precision */
|
|
||||||
char ch;
|
|
||||||
const char *start = pos;
|
|
||||||
while( (ch = *pos) != '\0' && ch != '%') pos++;
|
|
||||||
if (pos != start) {
|
|
||||||
CHECKCB(ctxt->write_str(ctxt->user_data, start, pos - start));
|
|
||||||
written += pos - start;
|
|
||||||
}
|
|
||||||
if (*pos == '\0') {
|
|
||||||
va_end(ap);
|
|
||||||
return written;
|
|
||||||
}
|
|
||||||
pos++;
|
|
||||||
if (*pos == '\0') {
|
|
||||||
va_end(ap);
|
|
||||||
return written;
|
|
||||||
}
|
|
||||||
flags = parse_flags(&pos);
|
|
||||||
|
|
||||||
/* parse width */
|
|
||||||
if (*pos >= '1' && *pos <= '9') {
|
|
||||||
minwidth = parse_uint(&pos);
|
|
||||||
} else if (*pos == '*') {
|
|
||||||
int w = va_arg(ap,int);
|
|
||||||
if (w < 0) {
|
|
||||||
flags |= JUSTIFY_LEFT;
|
|
||||||
minwidth = w;
|
|
||||||
} else {
|
|
||||||
minwidth = w;
|
|
||||||
}
|
|
||||||
pos ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* parse precision */
|
|
||||||
if (*pos == '.') {
|
|
||||||
pos++;
|
|
||||||
if (*pos >= '0' && *pos <= '9') {
|
|
||||||
precision = parse_uint(&pos);
|
|
||||||
} else if (*pos == '*') {
|
|
||||||
precision = va_arg(ap,int);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (*pos == 'l') {
|
|
||||||
pos++;
|
|
||||||
if (*pos == 'l') {
|
|
||||||
flags |= SIZE_LONGLONG;
|
|
||||||
pos++;
|
|
||||||
} else {
|
|
||||||
flags |= SIZE_LONG;
|
|
||||||
}
|
|
||||||
} else if (*pos == 'h') {
|
|
||||||
pos++;
|
|
||||||
if (*pos == 'h') {
|
|
||||||
flags |= SIZE_CHAR;
|
|
||||||
pos++;
|
|
||||||
} else {
|
|
||||||
flags |= SIZE_SHORT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* parse conversion specifier */
|
|
||||||
switch(*pos) {
|
|
||||||
case 'd':
|
|
||||||
case 'i':
|
|
||||||
flags |= CONV_INTEGER | RADIX_DECIMAL | SIGNED_YES;
|
|
||||||
break;
|
|
||||||
case 'u':
|
|
||||||
flags |= CONV_INTEGER | RADIX_DECIMAL | SIGNED_NO;
|
|
||||||
break;
|
|
||||||
case 'o':
|
|
||||||
flags |= CONV_INTEGER | RADIX_OCTAL | SIGNED_NO;
|
|
||||||
break;
|
|
||||||
case 'x':
|
|
||||||
flags |= CONV_INTEGER | RADIX_HEX | SIGNED_NO;
|
|
||||||
break;
|
|
||||||
case 'X':
|
|
||||||
flags |= CONV_INTEGER | RADIX_HEX | SIGNED_NO | CAPS_YES;
|
|
||||||
break;
|
|
||||||
#ifdef HAVE_DOUBLE
|
|
||||||
case 'f':
|
|
||||||
flags |= CONV_FLOAT | FLOAT_NORMAL;
|
|
||||||
break;
|
|
||||||
case 'F':
|
|
||||||
flags |= CONV_FLOAT | FLOAT_NORMAL | CAPS_YES;
|
|
||||||
break;
|
|
||||||
case 'e':
|
|
||||||
flags |= CONV_FLOAT | FLOAT_EXPONENT;
|
|
||||||
break;
|
|
||||||
case 'E':
|
|
||||||
flags |= CONV_FLOAT | FLOAT_EXPONENT | CAPS_YES;
|
|
||||||
break;
|
|
||||||
case 'g':
|
|
||||||
flags |= CONV_FLOAT | FLOAT_DEPENDANT;
|
|
||||||
break;
|
|
||||||
case 'G':
|
|
||||||
flags |= CONV_FLOAT | FLOAT_DEPENDANT | CAPS_YES;
|
|
||||||
break;
|
|
||||||
case 'a':
|
|
||||||
flags |= CONV_FLOAT | FLOAT_HEX;
|
|
||||||
break;
|
|
||||||
case 'A':
|
|
||||||
flags |= CONV_FLOAT | FLOAT_HEX | CAPS_YES;
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
case 'c':
|
|
||||||
flags |= CONV_CHAR;
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
flags |= CONV_STRING;
|
|
||||||
break;
|
|
||||||
case 'p':
|
|
||||||
flags |= CONV_POINTER;
|
|
||||||
break;
|
|
||||||
case 'n':
|
|
||||||
flags |= CONV_WRITTEN;
|
|
||||||
break;
|
|
||||||
case '%':
|
|
||||||
flags |= CONV_PERCENT;
|
|
||||||
break;
|
|
||||||
case '\0':
|
|
||||||
va_end(ap);
|
|
||||||
return written;
|
|
||||||
}
|
|
||||||
pos++;
|
|
||||||
switch(flags & CONV_MASK) {
|
|
||||||
case CONV_PERCENT:
|
|
||||||
CHECKCB(ctxt->write_str(ctxt->user_data, "%", 1));
|
|
||||||
written++;
|
|
||||||
break;
|
|
||||||
case CONV_INTEGER:
|
|
||||||
{
|
|
||||||
/* unsigned integers */
|
|
||||||
char *prefix = 0; /* sign, "0x" or "0X" */
|
|
||||||
unsigned int prefix_len = 0;
|
|
||||||
char buffer[MAXCHARS];
|
|
||||||
char *conv_pos = buffer + MAXCHARS;
|
|
||||||
unsigned int conv_len = 0;
|
|
||||||
unsigned int width = 0;
|
|
||||||
unsigned int precision_fill;
|
|
||||||
unsigned int field_fill;
|
|
||||||
LARGEST_UNSIGNED uvalue = 0;
|
|
||||||
int negative = 0;
|
|
||||||
|
|
||||||
if (precision < 0) precision = 1;
|
|
||||||
else flags &= ~PAD_ZERO;
|
|
||||||
|
|
||||||
if (flags & SIGNED_YES) {
|
|
||||||
/* signed integers */
|
|
||||||
LARGEST_SIGNED value = 0;
|
|
||||||
switch(flags & SIZE_MASK) {
|
|
||||||
case SIZE_CHAR:
|
|
||||||
value = (signed char)va_arg(ap, int);
|
|
||||||
break;
|
|
||||||
case SIZE_SHORT:
|
|
||||||
value = (short)va_arg(ap, int);
|
|
||||||
break;
|
|
||||||
case SIZE_INT:
|
|
||||||
value = va_arg(ap, int);
|
|
||||||
break;
|
|
||||||
#ifndef HAVE_LONGLONG
|
|
||||||
case SIZE_LONGLONG: /* Treat long long the same as long */
|
|
||||||
#endif
|
|
||||||
case SIZE_LONG:
|
|
||||||
value = va_arg(ap, long);
|
|
||||||
break;
|
|
||||||
#ifdef HAVE_LONGLONG
|
|
||||||
case SIZE_LONGLONG:
|
|
||||||
value = va_arg(ap, long long);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
if (value < 0) {
|
|
||||||
uvalue = -value;
|
|
||||||
negative = 1;
|
|
||||||
} else {
|
|
||||||
uvalue = value;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
|
|
||||||
switch(flags & SIZE_MASK) {
|
|
||||||
case SIZE_CHAR:
|
|
||||||
uvalue = (unsigned char)va_arg(ap,unsigned int);
|
|
||||||
break;
|
|
||||||
case SIZE_SHORT:
|
|
||||||
uvalue = (unsigned short)va_arg(ap,unsigned int);
|
|
||||||
break;
|
|
||||||
case SIZE_INT:
|
|
||||||
uvalue = va_arg(ap,unsigned int);
|
|
||||||
break;
|
|
||||||
#ifndef HAVE_LONGLONG
|
|
||||||
case SIZE_LONGLONG: /* Treat long long the same as long */
|
|
||||||
#endif
|
|
||||||
case SIZE_LONG:
|
|
||||||
uvalue = va_arg(ap,unsigned long);
|
|
||||||
break;
|
|
||||||
#ifdef HAVE_LONGLONG
|
|
||||||
case SIZE_LONGLONG:
|
|
||||||
uvalue = va_arg(ap,unsigned long long);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(flags & (RADIX_MASK)) {
|
|
||||||
case RADIX_DECIMAL:
|
|
||||||
conv_len = output_uint_decimal(&conv_pos,uvalue);
|
|
||||||
break;
|
|
||||||
case RADIX_OCTAL:
|
|
||||||
conv_len = output_uint_octal(&conv_pos,uvalue);
|
|
||||||
break;
|
|
||||||
case RADIX_HEX:
|
|
||||||
conv_len = output_uint_hex(&conv_pos,uvalue, flags);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
width += conv_len;
|
|
||||||
precision_fill = (precision > conv_len) ? precision - conv_len : 0;
|
|
||||||
if ((flags & (RADIX_MASK | ALTERNATE_FORM))
|
|
||||||
== (RADIX_OCTAL | ALTERNATE_FORM)) {
|
|
||||||
if (precision_fill < 1) precision_fill = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
width += precision_fill;
|
|
||||||
|
|
||||||
if ((flags & (RADIX_MASK | ALTERNATE_FORM))
|
|
||||||
== (RADIX_HEX | ALTERNATE_FORM) && uvalue != 0) {
|
|
||||||
prefix_len = 2;
|
|
||||||
if (flags & CAPS_YES) {
|
|
||||||
prefix = "0X";
|
|
||||||
} else {
|
|
||||||
prefix = "0x";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & SIGNED_YES) {
|
|
||||||
if (negative) {
|
|
||||||
prefix = "-";
|
|
||||||
prefix_len = 1;
|
|
||||||
} else {
|
|
||||||
switch(flags & POSITIVE_MASK) {
|
|
||||||
case POSITIVE_SPACE:
|
|
||||||
prefix = " ";
|
|
||||||
prefix_len = 1;
|
|
||||||
break;
|
|
||||||
case POSITIVE_PLUS:
|
|
||||||
prefix = "+";
|
|
||||||
prefix_len = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
width += prefix_len;
|
|
||||||
|
|
||||||
field_fill = (minwidth > width) ? minwidth - width : 0;
|
|
||||||
|
|
||||||
if ((flags & JUSTIFY_MASK) == JUSTIFY_RIGHT) {
|
|
||||||
if (flags & PAD_ZERO) {
|
|
||||||
precision_fill += field_fill;
|
|
||||||
} else {
|
|
||||||
CHECKCB(fill_space(ctxt,field_fill));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prefix_len > 0)
|
|
||||||
CHECKCB(ctxt->write_str(ctxt->user_data, prefix, prefix_len));
|
|
||||||
written += prefix_len;
|
|
||||||
|
|
||||||
CHECKCB(fill_zero(ctxt,precision_fill));
|
|
||||||
written += prefix_len;
|
|
||||||
|
|
||||||
CHECKCB(ctxt->write_str(ctxt->user_data, conv_pos,conv_len));
|
|
||||||
written += conv_len;
|
|
||||||
|
|
||||||
if ((flags & JUSTIFY_MASK) == JUSTIFY_LEFT) {
|
|
||||||
CHECKCB(fill_space(ctxt,field_fill));
|
|
||||||
}
|
|
||||||
written += field_fill;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CONV_STRING:
|
|
||||||
{
|
|
||||||
unsigned int field_fill;
|
|
||||||
unsigned int len;
|
|
||||||
char *str = va_arg(ap,char *);
|
|
||||||
if (str) {
|
|
||||||
char *pos = str;
|
|
||||||
while(*pos != '\0') pos++;
|
|
||||||
len = pos - str;
|
|
||||||
} else {
|
|
||||||
str = "(null)";
|
|
||||||
len = 6;
|
|
||||||
}
|
|
||||||
if (precision >= 0 && precision < len) len = precision;
|
|
||||||
field_fill = (minwidth > len) ? minwidth - len : 0;
|
|
||||||
if ((flags & JUSTIFY_MASK) == JUSTIFY_RIGHT) {
|
|
||||||
CHECKCB(fill_space(ctxt,field_fill));
|
|
||||||
}
|
|
||||||
CHECKCB(ctxt->write_str(ctxt->user_data, str,len));
|
|
||||||
written += len;
|
|
||||||
if ((flags & JUSTIFY_MASK) == JUSTIFY_LEFT) {
|
|
||||||
CHECKCB(fill_space(ctxt,field_fill));
|
|
||||||
}
|
|
||||||
written += field_fill;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CONV_POINTER:
|
|
||||||
{
|
|
||||||
LARGEST_UNSIGNED uvalue =
|
|
||||||
(LARGEST_UNSIGNED)(POINTER_INT)va_arg(ap,void *);
|
|
||||||
char buffer[MAXCHARS_HEX + 3];
|
|
||||||
char *conv_pos = buffer + MAXCHARS_HEX+3;
|
|
||||||
unsigned int conv_len;
|
|
||||||
unsigned int field_fill;
|
|
||||||
|
|
||||||
conv_len = output_uint_hex(&conv_pos,uvalue,flags);
|
|
||||||
if (conv_len == 0) {
|
|
||||||
*--conv_pos = '0';
|
|
||||||
conv_len++;
|
|
||||||
}
|
|
||||||
*--conv_pos = 'x';
|
|
||||||
*--conv_pos = '0';
|
|
||||||
*--conv_pos = '#';
|
|
||||||
conv_len += 3;
|
|
||||||
|
|
||||||
field_fill = (minwidth > conv_len) ? minwidth - conv_len : 0;
|
|
||||||
|
|
||||||
if ((flags & JUSTIFY_MASK) == JUSTIFY_RIGHT) {
|
|
||||||
CHECKCB(fill_space(ctxt,field_fill));
|
|
||||||
}
|
|
||||||
|
|
||||||
CHECKCB(ctxt->write_str(ctxt->user_data, conv_pos,conv_len));
|
|
||||||
written += conv_len;
|
|
||||||
|
|
||||||
if ((flags & JUSTIFY_MASK) == JUSTIFY_LEFT) {
|
|
||||||
CHECKCB(fill_space(ctxt,field_fill));
|
|
||||||
}
|
|
||||||
written += field_fill;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CONV_CHAR:
|
|
||||||
{
|
|
||||||
char ch = va_arg(ap,int);
|
|
||||||
unsigned int field_fill = (minwidth > 1) ? minwidth - 1 : 0;
|
|
||||||
if ((flags & JUSTIFY_MASK) == JUSTIFY_RIGHT) {
|
|
||||||
CHECKCB(fill_space(ctxt,field_fill));
|
|
||||||
written += field_fill;
|
|
||||||
}
|
|
||||||
|
|
||||||
CHECKCB(ctxt->write_str(ctxt->user_data, &ch, 1));
|
|
||||||
written++;
|
|
||||||
|
|
||||||
if ((flags & JUSTIFY_MASK) == JUSTIFY_LEFT) {
|
|
||||||
CHECKCB(fill_space(ctxt,field_fill));
|
|
||||||
}
|
|
||||||
written+= field_fill;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CONV_WRITTEN:
|
|
||||||
{
|
|
||||||
int *p = va_arg(ap,int*);
|
|
||||||
*p = written;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return written;
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
#ifndef __STRFORMAT_H__
|
|
||||||
#define __STRFORMAT_H__
|
|
||||||
|
|
||||||
#include <stdarg.h>
|
|
||||||
|
|
||||||
#define STRFORMAT_OK 0
|
|
||||||
#define STRFORMAT_FAILED 1
|
|
||||||
typedef unsigned int StrFormatResult;
|
|
||||||
|
|
||||||
/* The data argument may only be considered valid during the function call */
|
|
||||||
typedef StrFormatResult (*StrFormatWrite)(void *user_data, const char *data, unsigned int len);
|
|
||||||
|
|
||||||
typedef struct _StrFormatContext
|
|
||||||
{
|
|
||||||
StrFormatWrite write_str;
|
|
||||||
void *user_data;
|
|
||||||
} StrFormatContext;
|
|
||||||
|
|
||||||
int format_str(const StrFormatContext *ctxt, const char *format, ...)
|
|
||||||
__attribute__ ((__format__ (__printf__, 2,3)));
|
|
||||||
|
|
||||||
int
|
|
||||||
format_str_v(const StrFormatContext *ctxt, const char *format, va_list ap);
|
|
||||||
|
|
||||||
#endif /* __STRFORMAT_H__ */
|
|
|
@ -1,196 +0,0 @@
|
||||||
#include <debug-uart.h>
|
|
||||||
#include <sys-interrupt.h>
|
|
||||||
/* #include <strformat.h> */
|
|
||||||
#include <AT91SAM7S64.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <interrupt-utils.h>
|
|
||||||
|
|
||||||
#ifndef DBG_XMIT_BUFFER_LEN
|
|
||||||
#define DBG_XMIT_BUFFER_LEN 256
|
|
||||||
#endif
|
|
||||||
#ifndef DBG_RECV_BUFFER_LEN
|
|
||||||
#define DBG_RECV_BUFFER_LEN 256
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static unsigned char dbg_xmit_buffer[DBG_XMIT_BUFFER_LEN];
|
|
||||||
static unsigned char dbg_recv_buffer[DBG_RECV_BUFFER_LEN];
|
|
||||||
static unsigned int dbg_recv_buffer_len = 0;
|
|
||||||
|
|
||||||
void
|
|
||||||
dbg_setup_uart()
|
|
||||||
{
|
|
||||||
/* Setup PIO ports */
|
|
||||||
*AT91C_PIOA_OER = AT91C_PA10_DTXD;
|
|
||||||
*AT91C_PIOA_ODR = AT91C_PA9_DRXD;
|
|
||||||
*AT91C_PIOA_ASR = AT91C_PA10_DTXD | AT91C_PA9_DRXD;
|
|
||||||
*AT91C_PIOA_PDR = AT91C_PA10_DTXD | AT91C_PA9_DRXD;
|
|
||||||
|
|
||||||
*AT91C_DBGU_MR = AT91C_US_PAR_NONE | AT91C_US_CHMODE_NORMAL;
|
|
||||||
*AT91C_DBGU_IDR= 0xffffffff;
|
|
||||||
|
|
||||||
*AT91C_DBGU_BRGR = MCK / (115200 * 16);
|
|
||||||
*AT91C_DBGU_CR = AT91C_US_RXEN | AT91C_US_TXEN;
|
|
||||||
|
|
||||||
*AT91C_DBGU_TPR = (unsigned int)dbg_xmit_buffer;
|
|
||||||
*AT91C_DBGU_TNPR = (unsigned int)dbg_xmit_buffer;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void (*input_func)(const char *inp, unsigned int len) = NULL;
|
|
||||||
|
|
||||||
static int dbg_recv_handler_func()
|
|
||||||
{
|
|
||||||
if (!(*AT91C_DBGU_CSR & AT91C_US_RXRDY)) return 0;
|
|
||||||
unsigned char c = *AT91C_DBGU_RHR;
|
|
||||||
/* Leave one byte for '\0' */
|
|
||||||
if (dbg_recv_buffer_len < (DBG_RECV_BUFFER_LEN -1)) {
|
|
||||||
dbg_recv_buffer[dbg_recv_buffer_len++] = c;
|
|
||||||
}
|
|
||||||
if (c == '\n') {
|
|
||||||
dbg_recv_buffer[dbg_recv_buffer_len] = '\0';
|
|
||||||
if (input_func) input_func((char*)dbg_recv_buffer, dbg_recv_buffer_len);
|
|
||||||
dbg_recv_buffer_len = 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static SystemInterruptHandler dbg_recv_handler = {NULL, dbg_recv_handler_func};
|
|
||||||
|
|
||||||
void
|
|
||||||
dbg_set_input_handler(void (*handler)(const char *inp, unsigned int len))
|
|
||||||
{
|
|
||||||
input_func = handler;
|
|
||||||
sys_interrupt_append_handler(&dbg_recv_handler);
|
|
||||||
sys_interrupt_enable();
|
|
||||||
*AT91C_DBGU_IER = AT91C_US_RXRDY;
|
|
||||||
}
|
|
||||||
static volatile unsigned char mutex = 0;
|
|
||||||
|
|
||||||
unsigned int
|
|
||||||
dbg_send_bytes(const unsigned char *seq, unsigned int len)
|
|
||||||
{
|
|
||||||
unsigned short next_count;
|
|
||||||
unsigned short current_count;
|
|
||||||
unsigned short left;
|
|
||||||
unsigned int save = disableIRQ();
|
|
||||||
if (mutex) {
|
|
||||||
restoreIRQ(save);
|
|
||||||
return 0; /* Buffer being updated */
|
|
||||||
}
|
|
||||||
mutex = 1; /* Prevent interrupts from messing up the transmission */
|
|
||||||
*AT91C_DBGU_PTCR =AT91C_PDC_TXTDIS; /* Stop transmitting */
|
|
||||||
while(*AT91C_DBGU_PTSR & AT91C_PDC_TXTEN); /* Wait until stopped */
|
|
||||||
next_count = *AT91C_DBGU_TNCR;
|
|
||||||
current_count = *AT91C_DBGU_TCR;
|
|
||||||
|
|
||||||
left = DBG_XMIT_BUFFER_LEN - next_count - current_count;
|
|
||||||
if (left > 0) {
|
|
||||||
if (left < len) len = left;
|
|
||||||
if (next_count > 0) {
|
|
||||||
/* Buffer is wrapped */
|
|
||||||
memcpy(&dbg_xmit_buffer[next_count], seq, len);
|
|
||||||
*AT91C_DBGU_TNCR = next_count + len;
|
|
||||||
} else {
|
|
||||||
unsigned char *to = ((unsigned char*)*AT91C_DBGU_TPR) + current_count;
|
|
||||||
left = &dbg_xmit_buffer[DBG_XMIT_BUFFER_LEN] - to;
|
|
||||||
if (len > left) {
|
|
||||||
unsigned int wrapped = len - left;
|
|
||||||
memcpy(to, seq, left);
|
|
||||||
memcpy(dbg_xmit_buffer, &seq[left], wrapped);
|
|
||||||
*AT91C_DBGU_TCR = current_count + left;
|
|
||||||
*AT91C_DBGU_TNCR = wrapped;
|
|
||||||
} else {
|
|
||||||
memcpy(to, seq, len);
|
|
||||||
*AT91C_DBGU_TCR = current_count + len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
len = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
*AT91C_DBGU_PTCR =AT91C_PDC_TXTEN; /* Restart transmission */
|
|
||||||
mutex = 0;
|
|
||||||
restoreIRQ(save);
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
static unsigned char dbg_write_overrun = 0;
|
|
||||||
|
|
||||||
void
|
|
||||||
dbg_putchar(const char ch)
|
|
||||||
{
|
|
||||||
if (dbg_write_overrun) {
|
|
||||||
if (dbg_send_bytes((const unsigned char*)"^",1) != 1) return;
|
|
||||||
}
|
|
||||||
dbg_write_overrun = 0;
|
|
||||||
if (dbg_send_bytes((const unsigned char*)&ch,1) != 1) {
|
|
||||||
dbg_write_overrun = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
dbg_blocking_putchar(const char ch)
|
|
||||||
{
|
|
||||||
if (dbg_write_overrun) {
|
|
||||||
while (dbg_send_bytes((const unsigned char*)"^",1) != 1);
|
|
||||||
}
|
|
||||||
dbg_write_overrun = 0;
|
|
||||||
while (dbg_send_bytes((const unsigned char*)&ch,1) != 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
static StrFormatResult
|
|
||||||
dbg_write_cb(void *user_data, const char *data, unsigned int len)
|
|
||||||
{
|
|
||||||
if (dbg_send_bytes((const unsigned char*)data, len) != len) {
|
|
||||||
dbg_write_overrun = 1;
|
|
||||||
return STRFORMAT_FAILED;
|
|
||||||
}
|
|
||||||
return STRFORMAT_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
dbg_printf(const char *format, ...)
|
|
||||||
{
|
|
||||||
static const StrFormatContext ctxt = {dbg_write_cb, NULL};
|
|
||||||
va_list ap;
|
|
||||||
if (dbg_write_overrun) {
|
|
||||||
if (dbg_send_bytes((const unsigned char*)"^",1) != 1) return;
|
|
||||||
}
|
|
||||||
dbg_write_overrun = 0;
|
|
||||||
va_start(ap, format);
|
|
||||||
format_str_v(&ctxt, format, ap);
|
|
||||||
va_end(ap);
|
|
||||||
}
|
|
||||||
|
|
||||||
static StrFormatResult
|
|
||||||
dbg_write_blocking_cb(void *user_data, const char *data, unsigned int len)
|
|
||||||
{
|
|
||||||
unsigned int left = len;
|
|
||||||
while(left > 0) {
|
|
||||||
unsigned int sent = dbg_send_bytes((const unsigned char*)data, left);
|
|
||||||
left -= sent;
|
|
||||||
data += sent;
|
|
||||||
}
|
|
||||||
return STRFORMAT_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
dbg_blocking_printf(const char *format, ...)
|
|
||||||
{
|
|
||||||
static const StrFormatContext ctxt = {dbg_write_blocking_cb, NULL};
|
|
||||||
va_list ap;
|
|
||||||
if (dbg_write_overrun) {
|
|
||||||
while (dbg_send_bytes((const unsigned char*)"^",1) != 1);
|
|
||||||
}
|
|
||||||
dbg_write_overrun = 0;
|
|
||||||
va_start(ap, format);
|
|
||||||
format_str_v(&ctxt, format, ap);
|
|
||||||
va_end(ap);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
void
|
|
||||||
dbg_drain()
|
|
||||||
{
|
|
||||||
while(!(*AT91C_DBGU_CSR & AT91C_US_TXBUFE));
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
#ifndef __DEBUG_UART_H__1V2039076V__
|
|
||||||
#define __DEBUG_UART_H__1V2039076V__
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
dbg_setup_uart();
|
|
||||||
|
|
||||||
void
|
|
||||||
dbg_set_input_handler(void (*handler)(const char *inp, unsigned int len));
|
|
||||||
|
|
||||||
unsigned int
|
|
||||||
dbg_send_bytes(const unsigned char *seq, unsigned int len);
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
void
|
|
||||||
dbg_printf(const char *format, ...)
|
|
||||||
__attribute__ ((__format__ (__printf__, 1,2)));
|
|
||||||
|
|
||||||
void
|
|
||||||
dbg_blocking_printf(const char *format, ...)
|
|
||||||
__attribute__ ((__format__ (__printf__, 1,2)));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void
|
|
||||||
dbg_putchar(const char ch);
|
|
||||||
|
|
||||||
void
|
|
||||||
dbg_blocking_putchar(const char ch);
|
|
||||||
|
|
||||||
void
|
|
||||||
dbg_drain();
|
|
||||||
|
|
||||||
#endif /* __DEBUG_UART_H__1V2039076V__ */
|
|
|
@ -1,96 +0,0 @@
|
||||||
#include <stdlib.h>
|
|
||||||
#include <malloc.h>
|
|
||||||
#include <loader/elfloader-arch-otf.h>
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
#include <stdio.h>
|
|
||||||
#define PRINTF(...) printf(__VA_ARGS__)
|
|
||||||
#else
|
|
||||||
#define PRINTF(...) do {} while (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define ELF32_R_TYPE(info) ((unsigned char)(info))
|
|
||||||
|
|
||||||
/* Supported relocations */
|
|
||||||
|
|
||||||
#define R_ARM_ABS32 2
|
|
||||||
#define R_ARM_THM_CALL 10
|
|
||||||
|
|
||||||
/* Adapted from elfloader-avr.c */
|
|
||||||
|
|
||||||
int
|
|
||||||
elfloader_arch_relocate(int input_fd,
|
|
||||||
struct elfloader_output *output,
|
|
||||||
unsigned int sectionoffset,
|
|
||||||
char *sectionaddr,
|
|
||||||
struct elf32_rela *rela, char *addr)
|
|
||||||
{
|
|
||||||
unsigned int type;
|
|
||||||
|
|
||||||
type = ELF32_R_TYPE(rela->r_info);
|
|
||||||
|
|
||||||
cfs_seek(input_fd, sectionoffset + rela->r_offset, CFS_SEEK_SET);
|
|
||||||
|
|
||||||
/* PRINTF("elfloader_arch_relocate: type %d\n", type); */
|
|
||||||
/* PRINTF("Addr: %p, Addend: %ld\n", addr, rela->r_addend); */
|
|
||||||
switch(type) {
|
|
||||||
case R_ARM_ABS32:
|
|
||||||
{
|
|
||||||
int32_t addend;
|
|
||||||
cfs_read(input_fd, (char*)&addend, 4);
|
|
||||||
addr += addend;
|
|
||||||
elfloader_output_write_segment(output,(char*) &addr, 4);
|
|
||||||
PRINTF("%p: addr: %p\n", sectionaddr +rela->r_offset,
|
|
||||||
addr);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case R_ARM_THM_CALL:
|
|
||||||
{
|
|
||||||
uint16_t instr[2];
|
|
||||||
int32_t offset;
|
|
||||||
char *base;
|
|
||||||
cfs_read(input_fd, (char*)instr, 4);
|
|
||||||
/* Ignore the addend since it will be zero for calls to symbols,
|
|
||||||
and I can't think of a case when doing a relative call to
|
|
||||||
a non-symbol position */
|
|
||||||
base = sectionaddr + (rela->r_offset + 4);
|
|
||||||
|
|
||||||
if (((instr[1]) & 0xe800) == 0xe800) {
|
|
||||||
/* BL or BLX */
|
|
||||||
if (((uint32_t)addr) & 0x1) {
|
|
||||||
/* BL */
|
|
||||||
instr[1] |= 0x1800;
|
|
||||||
} else {
|
|
||||||
#if defined(__ARM_ARCH_4T__)
|
|
||||||
return ELFLOADER_UNHANDLED_RELOC;
|
|
||||||
#else
|
|
||||||
/* BLX */
|
|
||||||
instr[1] &= ~0x1800;
|
|
||||||
instr[1] |= 0x0800;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Adjust address for BLX */
|
|
||||||
if ((instr[1] & 0x1800) == 0x0800) {
|
|
||||||
addr = (char*)((((uint32_t)addr) & 0xfffffffd)
|
|
||||||
| (((uint32_t)base) & 0x00000002));
|
|
||||||
}
|
|
||||||
offset = addr - (sectionaddr + (rela->r_offset + 4));
|
|
||||||
if (offset < -(1<<22) || offset >= (1<<22)) {
|
|
||||||
PRINTF("elfloader-arm.c: offset %d too large for relative call\n",
|
|
||||||
(int)offset);
|
|
||||||
}
|
|
||||||
/* PRINTF("%p: %04x %04x offset: %d addr: %p\n", sectionaddr +rela->r_offset, instr[0], instr[1], (int)offset, addr); */
|
|
||||||
instr[0] = (instr[0] & 0xf800) | ((offset>>12)&0x07ff);
|
|
||||||
instr[1] = (instr[1] & 0xf800) | ((offset>>1)&0x07ff);
|
|
||||||
elfloader_output_write_segment(output, (char*)instr, 4);
|
|
||||||
/* PRINTF("cfs_write: %04x %04x\n",instr[0], instr[1]); */
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
PRINTF("elfloader-arm.c: unsupported relocation type %d\n", type);
|
|
||||||
return ELFLOADER_UNHANDLED_RELOC;
|
|
||||||
}
|
|
||||||
return ELFLOADER_OK;
|
|
||||||
}
|
|
|
@ -1,84 +0,0 @@
|
||||||
/******************************************************************************
|
|
||||||
*
|
|
||||||
* $RCSfile: interrupt-utils.c,v $
|
|
||||||
* $Revision: 1.2 $
|
|
||||||
*
|
|
||||||
* This module provides the interface routines for setting up and
|
|
||||||
* controlling the various interrupt modes present on the ARM processor.
|
|
||||||
* Copyright 2004, R O SoftWare
|
|
||||||
* No guarantees, warrantees, or promises, implied or otherwise.
|
|
||||||
* May be used for hobby or commercial purposes provided copyright
|
|
||||||
* notice remains intact.
|
|
||||||
*
|
|
||||||
*****************************************************************************/
|
|
||||||
#include "interrupt-utils.h"
|
|
||||||
|
|
||||||
#define IRQ_MASK 0x00000080
|
|
||||||
#define FIQ_MASK 0x00000040
|
|
||||||
#define INT_MASK (IRQ_MASK | FIQ_MASK)
|
|
||||||
|
|
||||||
static inline unsigned __get_cpsr(void)
|
|
||||||
{
|
|
||||||
unsigned long retval;
|
|
||||||
asm volatile (" mrs %0, cpsr" : "=r" (retval) : /* no inputs */ );
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void __set_cpsr(unsigned val)
|
|
||||||
{
|
|
||||||
asm volatile (" msr cpsr_c, %0" : /* no outputs */ : "r" (val) );
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned disableIRQ(void)
|
|
||||||
{
|
|
||||||
unsigned _cpsr;
|
|
||||||
|
|
||||||
_cpsr = __get_cpsr();
|
|
||||||
__set_cpsr(_cpsr | IRQ_MASK);
|
|
||||||
return _cpsr;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned restoreIRQ(unsigned oldCPSR)
|
|
||||||
{
|
|
||||||
unsigned _cpsr;
|
|
||||||
|
|
||||||
_cpsr = __get_cpsr();
|
|
||||||
__set_cpsr((_cpsr & ~IRQ_MASK) | (oldCPSR & IRQ_MASK));
|
|
||||||
return _cpsr;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned enableIRQ(void)
|
|
||||||
{
|
|
||||||
unsigned _cpsr;
|
|
||||||
|
|
||||||
_cpsr = __get_cpsr();
|
|
||||||
__set_cpsr(_cpsr & ~IRQ_MASK);
|
|
||||||
return _cpsr;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned disableFIQ(void)
|
|
||||||
{
|
|
||||||
unsigned _cpsr;
|
|
||||||
|
|
||||||
_cpsr = __get_cpsr();
|
|
||||||
__set_cpsr(_cpsr | FIQ_MASK);
|
|
||||||
return _cpsr;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned restoreFIQ(unsigned oldCPSR)
|
|
||||||
{
|
|
||||||
unsigned _cpsr;
|
|
||||||
|
|
||||||
_cpsr = __get_cpsr();
|
|
||||||
__set_cpsr((_cpsr & ~FIQ_MASK) | (oldCPSR & FIQ_MASK));
|
|
||||||
return _cpsr;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned enableFIQ(void)
|
|
||||||
{
|
|
||||||
unsigned _cpsr;
|
|
||||||
|
|
||||||
_cpsr = __get_cpsr();
|
|
||||||
__set_cpsr(_cpsr & ~FIQ_MASK);
|
|
||||||
return _cpsr;
|
|
||||||
}
|
|
|
@ -1,272 +0,0 @@
|
||||||
/*
|
|
||||||
* Defines and Macros for Interrupt-Service-Routines
|
|
||||||
* collected and partly created by
|
|
||||||
* Martin Thomas <mthomas@rhrk.uni-kl.de>
|
|
||||||
*
|
|
||||||
* Copyright 2005 M. Thomas
|
|
||||||
* No guarantees, warrantees, or promises, implied or otherwise.
|
|
||||||
* May be used for hobby or commercial purposes provided copyright
|
|
||||||
* notice remains intact.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef interrupt_utils_
|
|
||||||
#define interrupt_utils_
|
|
||||||
|
|
||||||
/*
|
|
||||||
The following defines are usefull for
|
|
||||||
interrupt service routine declarations.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
RAMFUNC
|
|
||||||
Attribute which defines a function to be located
|
|
||||||
in memory section .fastrun and called via "long calls".
|
|
||||||
See linker-skript and startup-code to see how the
|
|
||||||
.fastrun-section is handled.
|
|
||||||
The definition is not only useful for ISRs but since
|
|
||||||
ISRs should be executed fast the macro is defined in
|
|
||||||
this header.
|
|
||||||
*/
|
|
||||||
#define RAMFUNC __attribute__ ((long_call, section (".fastrun")))
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
INTFUNC
|
|
||||||
standard attribute for arm-elf-gcc which marks
|
|
||||||
a function as ISR (for the VIC). Since gcc seems
|
|
||||||
to produce wrong code if this attribute is used in
|
|
||||||
thumb/thumb-interwork the attribute should only be
|
|
||||||
used for "pure ARM-mode" binaries.
|
|
||||||
*/
|
|
||||||
#define INTFUNC __attribute__ ((interrupt("IRQ")))
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
NACKEDFUNC
|
|
||||||
gcc will not add any code to a function declared
|
|
||||||
"nacked". The user has to take care to save registers
|
|
||||||
and add the needed code for ISR functions. Some
|
|
||||||
macros for this tasks are provided below.
|
|
||||||
*/
|
|
||||||
#define NACKEDFUNC __attribute__((naked))
|
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
*
|
|
||||||
* MACRO Name: ISR_STORE()
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* This MACRO is used upon entry to an ISR with interrupt nesting.
|
|
||||||
* Should be used together with ISR_ENABLE_NEST(). The MACRO
|
|
||||||
* performs the following steps:
|
|
||||||
*
|
|
||||||
* 1 - Save the non-banked registers r0-r12 and lr onto the IRQ stack.
|
|
||||||
*
|
|
||||||
*****************************************************************************/
|
|
||||||
#define ISR_STORE() asm volatile( \
|
|
||||||
"STMDB SP!,{R0-R12,LR}\n" )
|
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
*
|
|
||||||
* MACRO Name: ISR_RESTORE()
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* This MACRO is used upon exit from an ISR with interrupt nesting.
|
|
||||||
* Should be used together with ISR_DISABLE_NEST(). The MACRO
|
|
||||||
* performs the following steps:
|
|
||||||
*
|
|
||||||
* 1 - Load the non-banked registers r0-r12 and lr from the IRQ stack.
|
|
||||||
* 2 - Adjusts resume adress
|
|
||||||
*
|
|
||||||
*****************************************************************************/
|
|
||||||
#define ISR_RESTORE() asm volatile( \
|
|
||||||
"LDMIA SP!,{R0-R12,LR}\n" \
|
|
||||||
"SUBS R15,R14,#0x0004\n" )
|
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
*
|
|
||||||
* MACRO Name: ISR_ENABLE_NEST()
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* This MACRO is used upon entry from an ISR with interrupt nesting.
|
|
||||||
* Should be used after ISR_STORE.
|
|
||||||
*
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
#define ISR_ENABLE_NEST() asm volatile( \
|
|
||||||
"MRS LR, SPSR \n" \
|
|
||||||
"STMFD SP!, {LR} \n" \
|
|
||||||
"MSR CPSR_c, #0x1f \n" \
|
|
||||||
"STMFD SP!, {LR} " )
|
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
*
|
|
||||||
* MACRO Name: ISR_DISABLE_NEST()
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* This MACRO is used upon entry from an ISR with interrupt nesting.
|
|
||||||
* Should be used before ISR_RESTORE.
|
|
||||||
*
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
#define ISR_DISABLE_NEST() asm volatile( \
|
|
||||||
"LDMFD SP!, {LR} \n" \
|
|
||||||
"MSR CPSR_c, #0x92 \n" \
|
|
||||||
"LDMFD SP!, {LR} \n" \
|
|
||||||
"MSR SPSR_cxsf, LR \n" )
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The following marcos are from the file "armVIC.h" by:
|
|
||||||
*
|
|
||||||
* Copyright 2004, R O SoftWare
|
|
||||||
* No guarantees, warrantees, or promises, implied or otherwise.
|
|
||||||
* May be used for hobby or commercial purposes provided copyright
|
|
||||||
* notice remains intact.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
*
|
|
||||||
* MACRO Name: ISR_ENTRY()
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* This MACRO is used upon entry to an ISR. The current version of
|
|
||||||
* the gcc compiler for ARM does not produce correct code for
|
|
||||||
* interrupt routines to operate properly with THUMB code. The MACRO
|
|
||||||
* performs the following steps:
|
|
||||||
*
|
|
||||||
* 1 - Adjust address at which execution should resume after servicing
|
|
||||||
* ISR to compensate for IRQ entry
|
|
||||||
* 2 - Save the non-banked registers r0-r12 and lr onto the IRQ stack.
|
|
||||||
* 3 - Get the status of the interrupted program is in SPSR.
|
|
||||||
* 4 - Push it onto the IRQ stack as well.
|
|
||||||
*
|
|
||||||
*****************************************************************************/
|
|
||||||
#define ISR_ENTRY() asm volatile(" sub lr, lr,#4\n" \
|
|
||||||
" stmfd sp!,{r0-r12,lr}\n" \
|
|
||||||
" mrs r1, spsr\n" \
|
|
||||||
" stmfd sp!,{r1}")
|
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
*
|
|
||||||
* MACRO Name: ISR_EXIT()
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* This MACRO is used to exit an ISR. The current version of the gcc
|
|
||||||
* compiler for ARM does not produce correct code for interrupt
|
|
||||||
* routines to operate properly with THUMB code. The MACRO performs
|
|
||||||
* the following steps:
|
|
||||||
*
|
|
||||||
* 1 - Recover SPSR value from stack
|
|
||||||
* 2 - and restore its value
|
|
||||||
* 3 - Pop the return address & the saved general registers from
|
|
||||||
* the IRQ stack & return
|
|
||||||
*
|
|
||||||
*****************************************************************************/
|
|
||||||
#define ISR_EXIT() asm volatile(" ldmfd sp!,{r1}\n" \
|
|
||||||
" msr spsr_c,r1\n" \
|
|
||||||
" ldmfd sp!,{r0-r12,pc}^")
|
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
*
|
|
||||||
* Function Name: disableIRQ()
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* This function sets the IRQ disable bit in the status register
|
|
||||||
*
|
|
||||||
* Calling Sequence:
|
|
||||||
* void
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* previous value of CPSR
|
|
||||||
*
|
|
||||||
*****************************************************************************/
|
|
||||||
unsigned disableIRQ(void);
|
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
*
|
|
||||||
* Function Name: enableIRQ()
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* This function clears the IRQ disable bit in the status register
|
|
||||||
*
|
|
||||||
* Calling Sequence:
|
|
||||||
* void
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* previous value of CPSR
|
|
||||||
*
|
|
||||||
*****************************************************************************/
|
|
||||||
unsigned enableIRQ(void);
|
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
*
|
|
||||||
* Function Name: restoreIRQ()
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* This function restores the IRQ disable bit in the status register
|
|
||||||
* to the value contained within passed oldCPSR
|
|
||||||
*
|
|
||||||
* Calling Sequence:
|
|
||||||
* void
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* previous value of CPSR
|
|
||||||
*
|
|
||||||
*****************************************************************************/
|
|
||||||
unsigned restoreIRQ(unsigned oldCPSR);
|
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
*
|
|
||||||
* Function Name: disableFIQ()
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* This function sets the FIQ disable bit in the status register
|
|
||||||
*
|
|
||||||
* Calling Sequence:
|
|
||||||
* void
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* previous value of CPSR
|
|
||||||
*
|
|
||||||
*****************************************************************************/
|
|
||||||
unsigned disableFIQ(void);
|
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
*
|
|
||||||
* Function Name: enableFIQ()
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* This function clears the FIQ disable bit in the status register
|
|
||||||
*
|
|
||||||
* Calling Sequence:
|
|
||||||
* void
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* previous value of CPSR
|
|
||||||
*
|
|
||||||
*****************************************************************************/
|
|
||||||
unsigned enableFIQ(void);
|
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
*
|
|
||||||
* Function Name: restoreFIQ()
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* This function restores the FIQ disable bit in the status register
|
|
||||||
* to the value contained within passed oldCPSR
|
|
||||||
*
|
|
||||||
* Calling Sequence:
|
|
||||||
* void
|
|
||||||
*
|
|
||||||
* Returns:
|
|
||||||
* previous value of CPSR
|
|
||||||
*
|
|
||||||
*****************************************************************************/
|
|
||||||
unsigned restoreFIQ(unsigned oldCPSR);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
#ifndef __IO_H__7UTLUP9AG6__
|
|
||||||
#define __IO_H__7UTLUP9AG6__
|
|
||||||
|
|
||||||
#include <AT91SAM7S64.h>
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef BV
|
|
||||||
#define BV(x) (1<<(x))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int splhigh(void);
|
|
||||||
|
|
||||||
void splx(int saved);
|
|
||||||
|
|
||||||
#endif /* __IO_H__7UTLUP9AG6__ */
|
|
|
@ -1,523 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2005, Swedish Institute of Computer Science
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the Institute nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the Contiki operating system.
|
|
||||||
*
|
|
||||||
* @(#)$Id: codeprop-otf.c,v 1.3 2009/02/27 14:28:02 nvt-se Exp $
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** \addtogroup esb
|
|
||||||
* @{ */
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* \file
|
|
||||||
* Code propagation and storage.
|
|
||||||
* \author
|
|
||||||
* Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
* This file implements a simple form of code propagation, which
|
|
||||||
* allows a binary program to be downloaded and propagated throughout
|
|
||||||
* a network of devices.
|
|
||||||
*
|
|
||||||
* Features:
|
|
||||||
*
|
|
||||||
* Commands: load code, start code
|
|
||||||
* Point-to-point download over TCP
|
|
||||||
* Point-to-multipoint delivery over UDP broadcasts
|
|
||||||
* Versioning of code modules
|
|
||||||
*
|
|
||||||
* Procedure:
|
|
||||||
*
|
|
||||||
* 1. Receive code over TCP
|
|
||||||
* 2. Send code packets over UDP
|
|
||||||
*
|
|
||||||
* When a code packet is deemed to be missed, a NACK is sent. If a
|
|
||||||
* NACK is received, the sending restarts at the point in the
|
|
||||||
* binary where the NACK pointed to. (This is *not* very efficient,
|
|
||||||
* but simple to implement...)
|
|
||||||
*
|
|
||||||
* States:
|
|
||||||
*
|
|
||||||
* Receiving code header -> receiving code -> sending code
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "contiki-net.h"
|
|
||||||
#include "cfs/cfs.h"
|
|
||||||
#include "codeprop-otf.h"
|
|
||||||
#include "loader/elfloader-otf.h"
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
static const char *err_msgs[] =
|
|
||||||
{"OK\r\n", "Bad ELF header\r\n", "No symtab\r\n", "No strtab\r\n",
|
|
||||||
"No text\r\n", "Symbol not found\r\n", "Segment not found\r\n",
|
|
||||||
"No startpoint\r\n", "Unhandled relocation\r\n",
|
|
||||||
"Relocation out of range\r\n", "Relocations not sorted\r\n",
|
|
||||||
"Input error\r\n" , "Ouput error\r\n" };
|
|
||||||
|
|
||||||
#define CODEPROP_DATA_PORT 6510
|
|
||||||
|
|
||||||
/*static int random_rand(void) { return 1; }*/
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
#define PRINTF(x) printf x
|
|
||||||
#else
|
|
||||||
#define PRINTF(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define START_TIMEOUT 12 * CLOCK_SECOND
|
|
||||||
#define MISS_NACK_TIMEOUT (CLOCK_SECOND / 8) * (random_rand() % 8)
|
|
||||||
#define HIT_NACK_TIMEOUT (CLOCK_SECOND / 8) * (8 + random_rand() % 16)
|
|
||||||
#define NACK_REXMIT_TIMEOUT CLOCK_SECOND * (4 + random_rand() % 4)
|
|
||||||
|
|
||||||
#define WAITING_TIME CLOCK_SECOND * 10
|
|
||||||
|
|
||||||
#define NUM_SEND_DUPLICATES 2
|
|
||||||
|
|
||||||
#define UDPHEADERSIZE 8
|
|
||||||
#define UDPDATASIZE 32
|
|
||||||
|
|
||||||
struct codeprop_udphdr {
|
|
||||||
u16_t id;
|
|
||||||
u16_t type;
|
|
||||||
#define TYPE_DATA 0x0001
|
|
||||||
#define TYPE_NACK 0x0002
|
|
||||||
u16_t addr;
|
|
||||||
u16_t len;
|
|
||||||
u8_t data[UDPDATASIZE];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct codeprop_tcphdr {
|
|
||||||
u16_t len;
|
|
||||||
u16_t pad;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void uipcall(void *state);
|
|
||||||
|
|
||||||
PROCESS(codeprop_process, "Code propagator");
|
|
||||||
|
|
||||||
struct codeprop_state {
|
|
||||||
u8_t state;
|
|
||||||
#define STATE_NONE 0
|
|
||||||
#define STATE_RECEIVING_TCPDATA 1
|
|
||||||
#define STATE_RECEIVING_UDPDATA 2
|
|
||||||
#define STATE_SENDING_UDPDATA 3
|
|
||||||
u16_t count;
|
|
||||||
u16_t addr;
|
|
||||||
u16_t len;
|
|
||||||
u16_t id;
|
|
||||||
struct etimer sendtimer;
|
|
||||||
struct timer nacktimer, timer, starttimer;
|
|
||||||
u8_t received;
|
|
||||||
u8_t send_counter;
|
|
||||||
struct pt tcpthread_pt;
|
|
||||||
struct pt udpthread_pt;
|
|
||||||
struct pt recv_udpthread_pt;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int fd;
|
|
||||||
|
|
||||||
static struct uip_udp_conn *udp_conn;
|
|
||||||
|
|
||||||
static struct codeprop_state s;
|
|
||||||
|
|
||||||
void system_log(char *msg);
|
|
||||||
|
|
||||||
static clock_time_t send_time;
|
|
||||||
|
|
||||||
#define CONNECTION_TIMEOUT (30 * CLOCK_SECOND)
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------*/
|
|
||||||
void
|
|
||||||
codeprop_set_rate(clock_time_t time)
|
|
||||||
{
|
|
||||||
send_time = time;
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------*/
|
|
||||||
PROCESS_THREAD(codeprop_process, ev, data)
|
|
||||||
{
|
|
||||||
PROCESS_BEGIN();
|
|
||||||
|
|
||||||
elfloader_init();
|
|
||||||
|
|
||||||
s.id = 0/*random_rand()*/;
|
|
||||||
|
|
||||||
send_time = CLOCK_SECOND/4;
|
|
||||||
|
|
||||||
PT_INIT(&s.udpthread_pt);
|
|
||||||
PT_INIT(&s.recv_udpthread_pt);
|
|
||||||
|
|
||||||
tcp_listen(HTONS(CODEPROP_DATA_PORT));
|
|
||||||
|
|
||||||
udp_conn = udp_broadcast_new(HTONS(CODEPROP_DATA_PORT), NULL);
|
|
||||||
|
|
||||||
s.state = STATE_NONE;
|
|
||||||
s.received = 0;
|
|
||||||
s.addr = 0;
|
|
||||||
s.len = 0;
|
|
||||||
|
|
||||||
fd = cfs_open("codeprop-image", CFS_READ | CFS_WRITE);
|
|
||||||
|
|
||||||
while(1) {
|
|
||||||
|
|
||||||
PROCESS_YIELD();
|
|
||||||
|
|
||||||
if(ev == tcpip_event) {
|
|
||||||
uipcall(data);
|
|
||||||
} else if(ev == PROCESS_EVENT_TIMER) {
|
|
||||||
tcpip_poll_udp(udp_conn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PROCESS_END();
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------*/
|
|
||||||
static u16_t
|
|
||||||
send_udpdata(struct codeprop_udphdr *uh)
|
|
||||||
{
|
|
||||||
u16_t len;
|
|
||||||
|
|
||||||
uh->type = HTONS(TYPE_DATA);
|
|
||||||
uh->addr = htons(s.addr);
|
|
||||||
uh->id = htons(s.id);
|
|
||||||
|
|
||||||
if(s.len - s.addr > UDPDATASIZE) {
|
|
||||||
len = UDPDATASIZE;
|
|
||||||
} else {
|
|
||||||
len = s.len - s.addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
cfs_seek(fd, s.addr, CFS_SEEK_SET);
|
|
||||||
cfs_read(fd, (char*)&uh->data[0], len);
|
|
||||||
/* eeprom_read(EEPROMFS_ADDR_CODEPROP + s.addr,
|
|
||||||
&uh->data[0], len);*/
|
|
||||||
|
|
||||||
uh->len = htons(s.len);
|
|
||||||
|
|
||||||
PRINTF(("codeprop: sending packet from address 0x%04x\n", s.addr));
|
|
||||||
uip_udp_send(len + UDPHEADERSIZE);
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------*/
|
|
||||||
static
|
|
||||||
PT_THREAD(send_udpthread(struct pt *pt))
|
|
||||||
{
|
|
||||||
int len;
|
|
||||||
struct codeprop_udphdr *uh = (struct codeprop_udphdr *)uip_appdata;
|
|
||||||
|
|
||||||
|
|
||||||
PT_BEGIN(pt);
|
|
||||||
|
|
||||||
while(1) {
|
|
||||||
PT_WAIT_UNTIL(pt, s.state == STATE_SENDING_UDPDATA);
|
|
||||||
|
|
||||||
for(s.addr = 0; s.addr < s.len; ) {
|
|
||||||
len = send_udpdata(uh);
|
|
||||||
s.addr += len;
|
|
||||||
|
|
||||||
etimer_set(&s.sendtimer, CLOCK_SECOND/4);
|
|
||||||
do {
|
|
||||||
PT_WAIT_UNTIL(pt, uip_newdata() || etimer_expired(&s.sendtimer));
|
|
||||||
|
|
||||||
if(uip_newdata()) {
|
|
||||||
if(uh->type == HTONS(TYPE_NACK)) {
|
|
||||||
PRINTF(("send_udpthread: got NACK for address 0x%x (now 0x%x)\n",
|
|
||||||
htons(uh->addr), s.addr));
|
|
||||||
/* Only accept a NACK if it points to a lower byte. */
|
|
||||||
if(htons(uh->addr) <= s.addr) {
|
|
||||||
/* beep();*/
|
|
||||||
s.addr = htons(uh->addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PT_YIELD(pt);
|
|
||||||
}
|
|
||||||
} while(!etimer_expired(&s.sendtimer));
|
|
||||||
}
|
|
||||||
|
|
||||||
s.state = STATE_NONE;
|
|
||||||
|
|
||||||
/* process_post(PROCESS_BROADCAST, codeprop_event_quit, (process_data_t)NULL); */
|
|
||||||
}
|
|
||||||
PT_END(pt);
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------*/
|
|
||||||
static void
|
|
||||||
send_nack(struct codeprop_udphdr *uh, unsigned short addr)
|
|
||||||
{
|
|
||||||
uh->type = HTONS(TYPE_NACK);
|
|
||||||
uh->addr = htons(addr);
|
|
||||||
uip_udp_send(UDPHEADERSIZE);
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------*/
|
|
||||||
static
|
|
||||||
PT_THREAD(recv_udpthread(struct pt *pt))
|
|
||||||
{
|
|
||||||
int len;
|
|
||||||
struct codeprop_udphdr *uh = (struct codeprop_udphdr *)uip_appdata;
|
|
||||||
|
|
||||||
/* if(uip_newdata()) {
|
|
||||||
PRINTF(("recv_udpthread: id %d uh->id %d\n", s.id, htons(uh->id)));
|
|
||||||
}*/
|
|
||||||
|
|
||||||
PT_BEGIN(pt);
|
|
||||||
|
|
||||||
while(1) {
|
|
||||||
|
|
||||||
do {
|
|
||||||
PT_WAIT_UNTIL(pt, uip_newdata() &&
|
|
||||||
uh->type == HTONS(TYPE_DATA) &&
|
|
||||||
htons(uh->id) > s.id);
|
|
||||||
|
|
||||||
if(htons(uh->addr) != 0) {
|
|
||||||
s.addr = 0;
|
|
||||||
send_nack(uh, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
} while(htons(uh->addr) != 0);
|
|
||||||
|
|
||||||
/* leds_on(LEDS_YELLOW);
|
|
||||||
beep_down(10000);*/
|
|
||||||
|
|
||||||
s.addr = 0;
|
|
||||||
s.id = htons(uh->id);
|
|
||||||
s.len = htons(uh->len);
|
|
||||||
|
|
||||||
timer_set(&s.timer, CONNECTION_TIMEOUT);
|
|
||||||
/* process_post(PROCESS_BROADCAST, codeprop_event_quit, (process_data_t)NULL); */
|
|
||||||
|
|
||||||
while(s.addr < s.len) {
|
|
||||||
|
|
||||||
if(htons(uh->addr) == s.addr) {
|
|
||||||
/* leds_blink();*/
|
|
||||||
len = uip_datalen() - UDPHEADERSIZE;
|
|
||||||
if(len > 0) {
|
|
||||||
/* eeprom_write(EEPROMFS_ADDR_CODEPROP + s.addr,
|
|
||||||
&uh->data[0], len);*/
|
|
||||||
cfs_seek(fd, s.addr, CFS_SEEK_SET);
|
|
||||||
cfs_write(fd, (char*)&uh->data[0], len);
|
|
||||||
|
|
||||||
/* beep();*/
|
|
||||||
PRINTF(("Saved %d bytes at address %d, %d bytes left\n",
|
|
||||||
uip_datalen() - UDPHEADERSIZE, s.addr,
|
|
||||||
s.len - s.addr));
|
|
||||||
|
|
||||||
s.addr += len;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if(htons(uh->addr) > s.addr) {
|
|
||||||
PRINTF(("sending nack since 0x%x != 0x%x\n", htons(uh->addr), s.addr));
|
|
||||||
send_nack(uh, s.addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(s.addr < s.len) {
|
|
||||||
|
|
||||||
/* timer_set(&s.nacktimer, NACK_TIMEOUT);*/
|
|
||||||
|
|
||||||
do {
|
|
||||||
timer_set(&s.nacktimer, HIT_NACK_TIMEOUT);
|
|
||||||
PT_YIELD_UNTIL(pt, timer_expired(&s.nacktimer) ||
|
|
||||||
(uip_newdata() &&
|
|
||||||
uh->type == HTONS(TYPE_DATA) &&
|
|
||||||
htons(uh->id) == s.id));
|
|
||||||
if(timer_expired(&s.nacktimer)) {
|
|
||||||
send_nack(uh, s.addr);
|
|
||||||
}
|
|
||||||
} while(timer_expired(&s.nacktimer));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* leds_off(LEDS_YELLOW);
|
|
||||||
beep_quick(2);*/
|
|
||||||
/* printf("Received entire bunary over udr\n");*/
|
|
||||||
codeprop_start_program();
|
|
||||||
PT_EXIT(pt);
|
|
||||||
}
|
|
||||||
|
|
||||||
PT_END(pt);
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#define CODEPROP_TCPHDR_SIZE sizeof(struct codeprop_tcphdr)
|
|
||||||
|
|
||||||
static
|
|
||||||
PT_THREAD(recv_tcpthread(struct pt *pt))
|
|
||||||
{
|
|
||||||
struct codeprop_tcphdr *th;
|
|
||||||
int datalen = uip_datalen();
|
|
||||||
PT_BEGIN(pt);
|
|
||||||
|
|
||||||
while(1) {
|
|
||||||
|
|
||||||
PT_WAIT_UNTIL(pt, uip_connected());
|
|
||||||
|
|
||||||
codeprop_exit_program();
|
|
||||||
|
|
||||||
s.state = STATE_RECEIVING_TCPDATA;
|
|
||||||
|
|
||||||
s.addr = 0;
|
|
||||||
s.count = 0;
|
|
||||||
|
|
||||||
/* Read the header. */
|
|
||||||
PT_WAIT_UNTIL(pt, uip_newdata() && uip_datalen() > 0);
|
|
||||||
|
|
||||||
if(uip_datalen() < CODEPROP_TCPHDR_SIZE) {
|
|
||||||
PRINTF(("codeprop: header not found in first tcp segment\n"));
|
|
||||||
uip_abort();
|
|
||||||
}
|
|
||||||
th = (struct codeprop_tcphdr *)uip_appdata;
|
|
||||||
s.len = htons(th->len);
|
|
||||||
s.addr = 0;
|
|
||||||
uip_appdata += CODEPROP_TCPHDR_SIZE;
|
|
||||||
datalen -= CODEPROP_TCPHDR_SIZE;
|
|
||||||
|
|
||||||
/* Read the rest of the data. */
|
|
||||||
do {
|
|
||||||
if(datalen > 0) {
|
|
||||||
/* printf("Got %d bytes\n", datalen); */
|
|
||||||
|
|
||||||
if (cfs_seek(fd, s.addr, CFS_SEEK_SET) != s.addr) {
|
|
||||||
PRINTF(("codeprop: seek in buffer file failed\n"));
|
|
||||||
uip_abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cfs_write(fd, uip_appdata, datalen) != datalen) {
|
|
||||||
PRINTF(("codeprop: write to buffer file failed\n"));
|
|
||||||
uip_abort();
|
|
||||||
}
|
|
||||||
s.addr += datalen;
|
|
||||||
}
|
|
||||||
if(s.addr < s.len) {
|
|
||||||
PT_YIELD_UNTIL(pt, uip_newdata());
|
|
||||||
}
|
|
||||||
} while(s.addr < s.len);
|
|
||||||
#if 1
|
|
||||||
|
|
||||||
{
|
|
||||||
static int err;
|
|
||||||
|
|
||||||
err = codeprop_start_program();
|
|
||||||
|
|
||||||
/* Print out the "OK"/error message. */
|
|
||||||
do {
|
|
||||||
if (err >= 0 && err < sizeof(err_msgs)/sizeof(char*)) {
|
|
||||||
uip_send(err_msgs[err], strlen(err_msgs[err]));
|
|
||||||
} else {
|
|
||||||
uip_send("Unknown error\r\n", 15);
|
|
||||||
}
|
|
||||||
PT_WAIT_UNTIL(pt, uip_acked() || uip_rexmit() || uip_closed());
|
|
||||||
} while(uip_rexmit());
|
|
||||||
|
|
||||||
/* Close the connection. */
|
|
||||||
uip_close();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
++s.id;
|
|
||||||
s.state = STATE_SENDING_UDPDATA;
|
|
||||||
tcpip_poll_udp(udp_conn);
|
|
||||||
|
|
||||||
PT_WAIT_UNTIL(pt, s.state != STATE_SENDING_UDPDATA);
|
|
||||||
/* printf("recv_tcpthread: unblocked\n");*/
|
|
||||||
}
|
|
||||||
|
|
||||||
PT_END(pt);
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------*/
|
|
||||||
void
|
|
||||||
codeprop_start_broadcast(unsigned int len)
|
|
||||||
{
|
|
||||||
s.addr = 0;
|
|
||||||
s.len = len;
|
|
||||||
++s.id;
|
|
||||||
s.state = STATE_SENDING_UDPDATA;
|
|
||||||
tcpip_poll_udp(udp_conn);
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------*/
|
|
||||||
void
|
|
||||||
codeprop_exit_program(void)
|
|
||||||
{
|
|
||||||
if(elfloader_autostart_processes != NULL) {
|
|
||||||
autostart_exit(elfloader_autostart_processes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------*/
|
|
||||||
int
|
|
||||||
codeprop_start_program(void)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
codeprop_exit_program();
|
|
||||||
|
|
||||||
err = elfloader_load(fd, codeprop_output);
|
|
||||||
if(err == ELFLOADER_OK) {
|
|
||||||
PRINTF(("codeprop: starting %s\n",
|
|
||||||
elfloader_autostart_processes[0]->name));
|
|
||||||
autostart_start(elfloader_autostart_processes);
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------*/
|
|
||||||
static void
|
|
||||||
uipcall(void *state)
|
|
||||||
{
|
|
||||||
if(uip_udpconnection()) {
|
|
||||||
recv_udpthread(&s.recv_udpthread_pt);
|
|
||||||
send_udpthread(&s.udpthread_pt);
|
|
||||||
} else {
|
|
||||||
if(uip_conn->lport == HTONS(CODEPROP_DATA_PORT)) {
|
|
||||||
if(uip_connected()) {
|
|
||||||
|
|
||||||
if(state == NULL) {
|
|
||||||
s.addr = 0;
|
|
||||||
s.count = 0;
|
|
||||||
PT_INIT(&s.tcpthread_pt);
|
|
||||||
process_poll(&codeprop_process);
|
|
||||||
tcp_markconn(uip_conn, &s);
|
|
||||||
/* process_post(PROCESS_BROADCAST, codeprop_event_quit, */
|
|
||||||
/* (process_data_t)NULL); */
|
|
||||||
} else {
|
|
||||||
PRINTF(("codeprop: uip_connected() and state != NULL\n"));
|
|
||||||
uip_abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
recv_tcpthread(&s.tcpthread_pt);
|
|
||||||
|
|
||||||
|
|
||||||
if(uip_closed() || uip_aborted() || uip_timedout()) {
|
|
||||||
PRINTF(("codeprop: connection down\n"));
|
|
||||||
tcp_markconn(uip_conn, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------*/
|
|
||||||
/** @} */
|
|
|
@ -1,52 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2005, Swedish Institute of Computer Science
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the Institute nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the Contiki operating system.
|
|
||||||
*
|
|
||||||
* @(#)$Id: codeprop-otf.h,v 1.1 2007/03/07 16:07:26 ksb Exp $
|
|
||||||
*/
|
|
||||||
#ifndef __CODEPROP_H__
|
|
||||||
#define __CODEPROP_H__
|
|
||||||
|
|
||||||
#include "contiki.h"
|
|
||||||
|
|
||||||
#define CODEPROP_DATA_PORT 6510
|
|
||||||
|
|
||||||
PROCESS_NAME(codeprop_process);
|
|
||||||
|
|
||||||
void codeprop_set_rate(clock_time_t time);
|
|
||||||
void codeprop_start_broadcast(unsigned int len);
|
|
||||||
void codeprop_exit_program(void);
|
|
||||||
int codeprop_start_program(void);
|
|
||||||
|
|
||||||
/* Segment writing object */
|
|
||||||
extern struct elfloader_output *codeprop_output;
|
|
||||||
|
|
||||||
extern char *codeprop_filesystem;
|
|
||||||
|
|
||||||
#endif /* __CODEPROP_H__ */
|
|
|
@ -1,101 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2005, Swedish Institute of Computer Science
|
|
||||||
* Copyright (c) 2007, Simon Berg
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the Institute nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the Contiki operating system.
|
|
||||||
*
|
|
||||||
* @(#)$Id: elfloader-arch-otf.h,v 1.1 2007/03/07 16:07:26 ksb Exp $
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* \addtogroup elfloader
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \defgroup elfloaderarch Architecture specific functionality for the ELF loader.
|
|
||||||
*
|
|
||||||
* The architecture specific functionality for the Contiki ELF loader
|
|
||||||
* has to be implemented for each processor type Contiki runs on.
|
|
||||||
*
|
|
||||||
* Since the ELF format is slightly different for different processor
|
|
||||||
* types, the Contiki ELF loader is divided into two parts: the
|
|
||||||
* generic ELF loader module (\ref elfloader) and the architecture
|
|
||||||
* specific part (this module). The architecture specific part deals
|
|
||||||
* with memory allocation, code and data relocation, and writing the
|
|
||||||
* relocated ELF code into program memory.
|
|
||||||
*
|
|
||||||
* To port the Contiki ELF loader to a new processor type, this module
|
|
||||||
* has to be implemented for the new processor type.
|
|
||||||
*
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \file
|
|
||||||
* Header file for the architecture specific parts of the Contiki ELF loader.
|
|
||||||
*
|
|
||||||
* \author
|
|
||||||
* Adam Dunkels <adam@sics.se>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __ELFLOADER_ARCH_H__
|
|
||||||
#define __ELFLOADER_ARCH_H__
|
|
||||||
|
|
||||||
#include "elfloader-otf.h"
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Perform a relocation.
|
|
||||||
* \param output The output object for the segment.
|
|
||||||
* \param sectionoffset The file offset at which the relocation can be found.
|
|
||||||
* \param sectionaddr The section start address (absolute runtime).
|
|
||||||
* \param rela A pointer to an ELF32 rela structure (struct elf32_rela).
|
|
||||||
* \param addr The relocated address.
|
|
||||||
*
|
|
||||||
* This function is called from the Contiki ELF loader to
|
|
||||||
* perform a relocation on a piece of code or data. The
|
|
||||||
* relocated address is calculated by the Contiki ELF
|
|
||||||
* loader, based on information in the ELF file, and it is
|
|
||||||
* the responsibility of this function to patch the
|
|
||||||
* executable code. The Contiki ELF loader passes a
|
|
||||||
* pointer to an ELF32 rela structure (struct elf32_rela)
|
|
||||||
* that contains information about how to patch the
|
|
||||||
* code. This information is different from processor to
|
|
||||||
* processor.
|
|
||||||
*/
|
|
||||||
int elfloader_arch_relocate(int input_fd,
|
|
||||||
struct elfloader_output *output,
|
|
||||||
unsigned int sectionoffset,
|
|
||||||
char *sectionaddr,
|
|
||||||
struct elf32_rela *rela, char *addr);
|
|
||||||
|
|
||||||
#endif /* __ELFLOADER_ARCH_H__ */
|
|
||||||
|
|
||||||
/** @} */
|
|
||||||
/** @} */
|
|
|
@ -1,680 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2005, Swedish Institute of Computer Science
|
|
||||||
* Copyright (c) 2007, Simon Berg
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the Institute nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the Contiki operating system.
|
|
||||||
*
|
|
||||||
* @(#)$Id: elfloader-otf.c,v 1.2 2009/02/27 14:28:02 nvt-se Exp $
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "contiki.h"
|
|
||||||
|
|
||||||
#include "loader/elfloader-otf.h"
|
|
||||||
#include "loader/elfloader-arch-otf.h"
|
|
||||||
|
|
||||||
#include "cfs/cfs.h"
|
|
||||||
#include "loader/symtab.h"
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
#include <stdio.h>
|
|
||||||
#define PRINTF(...) printf(__VA_ARGS__)
|
|
||||||
#else
|
|
||||||
#define PRINTF(...) do {} while (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define EI_NIDENT 16
|
|
||||||
|
|
||||||
|
|
||||||
struct elf32_ehdr {
|
|
||||||
unsigned char e_ident[EI_NIDENT]; /* ident bytes */
|
|
||||||
elf32_half e_type; /* file type */
|
|
||||||
elf32_half e_machine; /* target machine */
|
|
||||||
elf32_word e_version; /* file version */
|
|
||||||
elf32_addr e_entry; /* start address */
|
|
||||||
elf32_off e_phoff; /* phdr file offset */
|
|
||||||
elf32_off e_shoff; /* shdr file offset */
|
|
||||||
elf32_word e_flags; /* file flags */
|
|
||||||
elf32_half e_ehsize; /* sizeof ehdr */
|
|
||||||
elf32_half e_phentsize; /* sizeof phdr */
|
|
||||||
elf32_half e_phnum; /* number phdrs */
|
|
||||||
elf32_half e_shentsize; /* sizeof shdr */
|
|
||||||
elf32_half e_shnum; /* number shdrs */
|
|
||||||
elf32_half e_shstrndx; /* shdr string index */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Values for e_type. */
|
|
||||||
#define ET_NONE 0 /* Unknown type. */
|
|
||||||
#define ET_REL 1 /* Relocatable. */
|
|
||||||
#define ET_EXEC 2 /* Executable. */
|
|
||||||
#define ET_DYN 3 /* Shared object. */
|
|
||||||
#define ET_CORE 4 /* Core file. */
|
|
||||||
|
|
||||||
struct elf32_shdr {
|
|
||||||
elf32_word sh_name; /* section name */
|
|
||||||
elf32_word sh_type; /* SHT_... */
|
|
||||||
elf32_word sh_flags; /* SHF_... */
|
|
||||||
elf32_addr sh_addr; /* virtual address */
|
|
||||||
elf32_off sh_offset; /* file offset */
|
|
||||||
elf32_word sh_size; /* section size */
|
|
||||||
elf32_word sh_link; /* misc info */
|
|
||||||
elf32_word sh_info; /* misc info */
|
|
||||||
elf32_word sh_addralign; /* memory alignment */
|
|
||||||
elf32_word sh_entsize; /* entry size if table */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* sh_type */
|
|
||||||
#define SHT_NULL 0 /* inactive */
|
|
||||||
#define SHT_PROGBITS 1 /* program defined information */
|
|
||||||
#define SHT_SYMTAB 2 /* symbol table section */
|
|
||||||
#define SHT_STRTAB 3 /* string table section */
|
|
||||||
#define SHT_RELA 4 /* relocation section with addends*/
|
|
||||||
#define SHT_HASH 5 /* symbol hash table section */
|
|
||||||
#define SHT_DYNAMIC 6 /* dynamic section */
|
|
||||||
#define SHT_NOTE 7 /* note section */
|
|
||||||
#define SHT_NOBITS 8 /* no space section */
|
|
||||||
#define SHT_REL 9 /* relation section without addends */
|
|
||||||
#define SHT_SHLIB 10 /* reserved - purpose unknown */
|
|
||||||
#define SHT_DYNSYM 11 /* dynamic symbol table section */
|
|
||||||
#define SHT_LOPROC 0x70000000 /* reserved range for processor */
|
|
||||||
#define SHT_HIPROC 0x7fffffff /* specific section header types */
|
|
||||||
#define SHT_LOUSER 0x80000000 /* reserved range for application */
|
|
||||||
#define SHT_HIUSER 0xffffffff /* specific indexes */
|
|
||||||
|
|
||||||
struct elf32_rel {
|
|
||||||
elf32_addr r_offset; /* Location to be relocated. */
|
|
||||||
elf32_word r_info; /* Relocation type and symbol index. */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct elf32_sym {
|
|
||||||
elf32_word st_name; /* String table index of name. */
|
|
||||||
elf32_addr st_value; /* Symbol value. */
|
|
||||||
elf32_word st_size; /* Size of associated object. */
|
|
||||||
unsigned char st_info; /* Type and binding information. */
|
|
||||||
unsigned char st_other; /* Reserved (not used). */
|
|
||||||
elf32_half st_shndx; /* Section index of symbol. */
|
|
||||||
};
|
|
||||||
|
|
||||||
#define ELF32_R_SYM(info) ((info) >> 8)
|
|
||||||
#define ELF32_R_TYPE(info) ((unsigned char)(info))
|
|
||||||
|
|
||||||
struct relevant_section {
|
|
||||||
unsigned char number;
|
|
||||||
unsigned int offset;
|
|
||||||
char *address;
|
|
||||||
};
|
|
||||||
|
|
||||||
char elfloader_unknown[30]; /* Name that caused link error. */
|
|
||||||
|
|
||||||
struct process **elfloader_autostart_processes;
|
|
||||||
|
|
||||||
static struct relevant_section bss, data, rodata, text;
|
|
||||||
|
|
||||||
const static unsigned char elf_magic_header[] =
|
|
||||||
{0x7f, 0x45, 0x4c, 0x46, /* 0x7f, 'E', 'L', 'F' */
|
|
||||||
0x01, /* Only 32-bit objects. */
|
|
||||||
0x01, /* Only LSB data. */
|
|
||||||
0x01, /* Only ELF version 1. */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Copy data from the elf file to a segment */
|
|
||||||
static int
|
|
||||||
copy_segment_data(int input_fd, unsigned int offset,
|
|
||||||
struct elfloader_output *output, unsigned int len)
|
|
||||||
{
|
|
||||||
char buffer[16];
|
|
||||||
int res;
|
|
||||||
if (cfs_seek(input_fd, offset, CFS_SEEK_SET) != offset) return ELFLOADER_INPUT_ERROR;
|
|
||||||
while(len > sizeof(buffer)) {
|
|
||||||
res = cfs_read(input_fd, buffer, sizeof(buffer));
|
|
||||||
if (res != sizeof(buffer)) return ELFLOADER_INPUT_ERROR;
|
|
||||||
res = elfloader_output_write_segment(output, buffer, sizeof(buffer));
|
|
||||||
if (res != sizeof(buffer)) return ELFLOADER_OUTPUT_ERROR;
|
|
||||||
len -= sizeof(buffer);
|
|
||||||
}
|
|
||||||
res = cfs_read(input_fd, buffer, len);
|
|
||||||
if (res != len) return ELFLOADER_INPUT_ERROR;
|
|
||||||
res = elfloader_output_write_segment(output, buffer, len);
|
|
||||||
if (res != len) return ELFLOADER_OUTPUT_ERROR;
|
|
||||||
return ELFLOADER_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
seek_read(int fd, unsigned int offset, char *buf, int len)
|
|
||||||
{
|
|
||||||
if (cfs_seek(fd, offset, CFS_SEEK_SET) != offset) return -1;
|
|
||||||
return cfs_read(fd, buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *
|
|
||||||
find_local_symbol(int input_fd, const char *symbol,
|
|
||||||
unsigned int symtab, unsigned short symtabsize,
|
|
||||||
unsigned int strtab)
|
|
||||||
{
|
|
||||||
struct elf32_sym s;
|
|
||||||
unsigned int a;
|
|
||||||
char name[30];
|
|
||||||
struct relevant_section *sect;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
for(a = symtab; a < symtab + symtabsize; a += sizeof(s)) {
|
|
||||||
ret = seek_read(input_fd, a, (char *)&s, sizeof(s));
|
|
||||||
if (ret < 0) return NULL;
|
|
||||||
|
|
||||||
if(s.st_name != 0) {
|
|
||||||
ret = seek_read(input_fd, strtab + s.st_name, name, sizeof(name));
|
|
||||||
if (ret < 0) return NULL;
|
|
||||||
|
|
||||||
if(strcmp(name, symbol) == 0) {
|
|
||||||
if(s.st_shndx == bss.number) {
|
|
||||||
sect = &bss;
|
|
||||||
} else if(s.st_shndx == data.number) {
|
|
||||||
sect = &data;
|
|
||||||
} else if(s.st_shndx == text.number) {
|
|
||||||
sect = &text;
|
|
||||||
} else {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return &(sect->address[s.st_value]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
static int
|
|
||||||
relocate_section(int input_fd,
|
|
||||||
struct elfloader_output *output,
|
|
||||||
unsigned int section, unsigned short size,
|
|
||||||
unsigned int sectionaddr,
|
|
||||||
char *sectionbase,
|
|
||||||
unsigned int strs,
|
|
||||||
unsigned int strtab,
|
|
||||||
unsigned int symtab, unsigned short symtabsize,
|
|
||||||
unsigned char using_relas)
|
|
||||||
{
|
|
||||||
/* sectionbase added; runtime start address of current section */
|
|
||||||
struct elf32_rela rela; /* Now used both for rel and rela data! */
|
|
||||||
int rel_size = 0;
|
|
||||||
struct elf32_sym s;
|
|
||||||
unsigned int a;
|
|
||||||
char name[30];
|
|
||||||
char *addr;
|
|
||||||
struct relevant_section *sect;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* determine correct relocation entry sizes */
|
|
||||||
if(using_relas) {
|
|
||||||
rel_size = sizeof(struct elf32_rela);
|
|
||||||
} else {
|
|
||||||
rel_size = sizeof(struct elf32_rel);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(a = section; a < section + size; a += rel_size) {
|
|
||||||
ret = seek_read(input_fd, a, (char *)&rela, rel_size);
|
|
||||||
if (ret < 0) return ELFLOADER_INPUT_ERROR;
|
|
||||||
ret = seek_read(input_fd,
|
|
||||||
(symtab +
|
|
||||||
sizeof(struct elf32_sym) * ELF32_R_SYM(rela.r_info)),
|
|
||||||
(char *)&s, sizeof(s));
|
|
||||||
if (ret < 0) return ELFLOADER_INPUT_ERROR;
|
|
||||||
if(s.st_name != 0) {
|
|
||||||
ret = seek_read(input_fd, strtab + s.st_name, name, sizeof(name));
|
|
||||||
if (ret < 0) return ELFLOADER_INPUT_ERROR;
|
|
||||||
PRINTF("name: %s\n", name);
|
|
||||||
addr = (char *)symtab_lookup(name);
|
|
||||||
/* ADDED */
|
|
||||||
if(addr == NULL) {
|
|
||||||
PRINTF("name not found in global: %s\n", name);
|
|
||||||
addr = find_local_symbol(input_fd, name, symtab, symtabsize, strtab);
|
|
||||||
PRINTF("found address %p\n", addr);
|
|
||||||
}
|
|
||||||
if(addr == NULL) {
|
|
||||||
if(s.st_shndx == bss.number) {
|
|
||||||
sect = &bss;
|
|
||||||
} else if(s.st_shndx == data.number) {
|
|
||||||
sect = &data;
|
|
||||||
} else if(s.st_shndx == rodata.number) {
|
|
||||||
sect = &rodata;
|
|
||||||
} else if(s.st_shndx == text.number) {
|
|
||||||
sect = &text;
|
|
||||||
} else {
|
|
||||||
PRINTF("elfloader unknown name: '%30s'\n", name);
|
|
||||||
memcpy(elfloader_unknown, name, sizeof(elfloader_unknown));
|
|
||||||
elfloader_unknown[sizeof(elfloader_unknown) - 1] = 0;
|
|
||||||
return ELFLOADER_SYMBOL_NOT_FOUND;
|
|
||||||
}
|
|
||||||
addr = sect->address;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(s.st_shndx == bss.number) {
|
|
||||||
sect = &bss;
|
|
||||||
} else if(s.st_shndx == data.number) {
|
|
||||||
sect = &data;
|
|
||||||
} else if(s.st_shndx == rodata.number) {
|
|
||||||
sect = &rodata;
|
|
||||||
} else if(s.st_shndx == text.number) {
|
|
||||||
sect = &text;
|
|
||||||
} else {
|
|
||||||
return ELFLOADER_SEGMENT_NOT_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
addr = sect->address;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0 /* We don't know how big the relocation is or even if we need to read it.
|
|
||||||
Let the architecture dependant code decide */
|
|
||||||
if (!using_relas) {
|
|
||||||
/* copy addend to rela structure */
|
|
||||||
ret = seek_read(fd, sectionaddr + rela.r_offset, &rela.r_addend, 4);
|
|
||||||
if (ret < 0) return ELFLOADER_INPUT_ERROR;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
/* Copy data up to the next relocation */
|
|
||||||
unsigned int offset = elfloader_output_segment_offset(output);
|
|
||||||
if (rela.r_offset < offset) {
|
|
||||||
PRINTF("elfloader relocation out of offset order\n");
|
|
||||||
|
|
||||||
}
|
|
||||||
if (rela.r_offset > offset) {
|
|
||||||
ret = copy_segment_data(input_fd, offset+sectionaddr, output,
|
|
||||||
rela.r_offset - offset);
|
|
||||||
if (ret != ELFLOADER_OK) return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ret = elfloader_arch_relocate(input_fd, output, sectionaddr, sectionbase,
|
|
||||||
&rela, addr);
|
|
||||||
if (ret != ELFLOADER_OK) return ret;
|
|
||||||
}
|
|
||||||
return ELFLOADER_OK;
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
static void *
|
|
||||||
find_program_processes(int input_fd,
|
|
||||||
unsigned int symtab, unsigned short size,
|
|
||||||
unsigned int strtab)
|
|
||||||
{
|
|
||||||
struct elf32_sym s;
|
|
||||||
unsigned int a;
|
|
||||||
char name[30];
|
|
||||||
|
|
||||||
for(a = symtab; a < symtab + size; a += sizeof(s)) {
|
|
||||||
seek_read(input_fd, a, (char *)&s, sizeof(s));
|
|
||||||
|
|
||||||
if(s.st_name != 0) {
|
|
||||||
seek_read(input_fd, strtab + s.st_name, name, sizeof(name));
|
|
||||||
if(strcmp(name, "autostart_processes") == 0) {
|
|
||||||
return &data.address[s.st_value];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
/* return find_local_symbol(fd, "autostart_processes", symtab, size, strtab); */
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
void
|
|
||||||
elfloader_init(void)
|
|
||||||
{
|
|
||||||
elfloader_autostart_processes = NULL;
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
#if 0
|
|
||||||
static void
|
|
||||||
print_chars(unsigned char *ptr, int num)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for(i = 0; i < num; ++i) {
|
|
||||||
PRINTF("%d", ptr[i]);
|
|
||||||
if(i == num - 1) {
|
|
||||||
PRINTF("\n");
|
|
||||||
} else {
|
|
||||||
PRINTF(", ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* 0 */
|
|
||||||
|
|
||||||
static int
|
|
||||||
copy_segment(int input_fd,
|
|
||||||
struct elfloader_output *output,
|
|
||||||
unsigned int section, unsigned short size,
|
|
||||||
unsigned int sectionaddr,
|
|
||||||
char *sectionbase,
|
|
||||||
unsigned int strs,
|
|
||||||
unsigned int strtab,
|
|
||||||
unsigned int symtab, unsigned short symtabsize,
|
|
||||||
unsigned char using_relas,
|
|
||||||
unsigned int seg_size, unsigned int seg_type)
|
|
||||||
{
|
|
||||||
unsigned int offset;
|
|
||||||
int ret;
|
|
||||||
ret = elfloader_output_start_segment(output, seg_type,sectionbase, seg_size);
|
|
||||||
if (ret != ELFLOADER_OK) return ret;
|
|
||||||
ret = relocate_section(input_fd, output,
|
|
||||||
section, size,
|
|
||||||
sectionaddr,
|
|
||||||
sectionbase,
|
|
||||||
strs,
|
|
||||||
strtab,
|
|
||||||
symtab, symtabsize, using_relas);
|
|
||||||
if (ret != ELFLOADER_OK) return ret;
|
|
||||||
offset = elfloader_output_segment_offset(output);
|
|
||||||
ret = copy_segment_data(input_fd, offset+sectionaddr, output,seg_size - offset);
|
|
||||||
if (ret != ELFLOADER_OK) return ret;
|
|
||||||
return elfloader_output_end_segment(output);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
||||||
int
|
|
||||||
elfloader_load(int input_fd, struct elfloader_output *output)
|
|
||||||
{
|
|
||||||
struct elf32_ehdr ehdr;
|
|
||||||
struct elf32_shdr shdr;
|
|
||||||
struct elf32_shdr strtable;
|
|
||||||
unsigned int strs;
|
|
||||||
unsigned int shdrptr;
|
|
||||||
unsigned int nameptr;
|
|
||||||
char name[12];
|
|
||||||
|
|
||||||
int i;
|
|
||||||
unsigned short shdrnum, shdrsize;
|
|
||||||
|
|
||||||
unsigned char using_relas = -1;
|
|
||||||
unsigned short textoff = 0, textsize, textrelaoff = 0, textrelasize;
|
|
||||||
unsigned short dataoff = 0, datasize, datarelaoff = 0, datarelasize;
|
|
||||||
unsigned short rodataoff = 0, rodatasize, rodatarelaoff = 0, rodatarelasize;
|
|
||||||
unsigned short symtaboff = 0, symtabsize;
|
|
||||||
unsigned short strtaboff = 0, strtabsize;
|
|
||||||
unsigned short bsssize = 0;
|
|
||||||
|
|
||||||
struct process **process;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
elfloader_unknown[0] = 0;
|
|
||||||
|
|
||||||
/* The ELF header is located at the start of the buffer. */
|
|
||||||
ret = seek_read(input_fd, 0, (char *)&ehdr, sizeof(ehdr));
|
|
||||||
if (ret != sizeof(ehdr)) return ELFLOADER_INPUT_ERROR;
|
|
||||||
|
|
||||||
/* print_chars(ehdr.e_ident, sizeof(elf_magic_header));
|
|
||||||
print_chars(elf_magic_header, sizeof(elf_magic_header));*/
|
|
||||||
/* Make sure that we have a correct and compatible ELF header. */
|
|
||||||
if(memcmp(ehdr.e_ident, elf_magic_header, sizeof(elf_magic_header)) != 0) {
|
|
||||||
PRINTF("ELF header problems\n");
|
|
||||||
return ELFLOADER_BAD_ELF_HEADER;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Grab the section header. */
|
|
||||||
shdrptr = ehdr.e_shoff;
|
|
||||||
ret = seek_read(input_fd, shdrptr, (char *)&shdr, sizeof(shdr));
|
|
||||||
if (ret != sizeof(shdr)) return ELFLOADER_INPUT_ERROR;
|
|
||||||
|
|
||||||
/* Get the size and number of entries of the section header. */
|
|
||||||
shdrsize = ehdr.e_shentsize;
|
|
||||||
shdrnum = ehdr.e_shnum;
|
|
||||||
|
|
||||||
/* The string table section: holds the names of the sections. */
|
|
||||||
ret = seek_read(input_fd, ehdr.e_shoff + shdrsize * ehdr.e_shstrndx,
|
|
||||||
(char *)&strtable, sizeof(strtable));
|
|
||||||
if (ret != sizeof(strtable)) return ELFLOADER_INPUT_ERROR;
|
|
||||||
|
|
||||||
/* Get a pointer to the actual table of strings. This table holds
|
|
||||||
the names of the sections, not the names of other symbols in the
|
|
||||||
file (these are in the sybtam section). */
|
|
||||||
strs = strtable.sh_offset;
|
|
||||||
|
|
||||||
/* Go through all sections and pick out the relevant ones. The
|
|
||||||
".text" segment holds the actual code from the ELF file, the
|
|
||||||
".data" segment contains initialized data, the ".rodata" segment
|
|
||||||
contains read-only data, the ".bss" segment holds the size of the
|
|
||||||
unitialized data segment. The ".rel[a].text" and ".rel[a].data"
|
|
||||||
segments contains relocation information for the contents of the
|
|
||||||
".text" and ".data" segments, respectively. The ".symtab" segment
|
|
||||||
contains the symbol table for this file. The ".strtab" segment
|
|
||||||
points to the actual string names used by the symbol table.
|
|
||||||
|
|
||||||
In addition to grabbing pointers to the relevant sections, we
|
|
||||||
also save the section number for resolving addresses in the
|
|
||||||
relocator code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/* Initialize the segment sizes to zero so that we can check if
|
|
||||||
their sections was found in the file or not. */
|
|
||||||
textsize = textrelasize = datasize = datarelasize =
|
|
||||||
rodatasize = rodatarelasize = symtabsize = strtabsize = 0;
|
|
||||||
|
|
||||||
bss.number = data.number = rodata.number = text.number = -1;
|
|
||||||
|
|
||||||
shdrptr = ehdr.e_shoff;
|
|
||||||
for(i = 0; i < shdrnum; ++i) {
|
|
||||||
|
|
||||||
ret = seek_read(input_fd, shdrptr, (char *)&shdr, sizeof(shdr));
|
|
||||||
if (ret != sizeof(shdr)) return ELFLOADER_INPUT_ERROR;
|
|
||||||
|
|
||||||
/* The name of the section is contained in the strings table. */
|
|
||||||
nameptr = strs + shdr.sh_name;
|
|
||||||
ret = seek_read(input_fd, nameptr, name, sizeof(name));
|
|
||||||
if (ret != sizeof(name)) return ELFLOADER_INPUT_ERROR;
|
|
||||||
|
|
||||||
/* Match the name of the section with a predefined set of names
|
|
||||||
(.text, .data, .bss, .rela.text, .rela.data, .symtab, and
|
|
||||||
.strtab). */
|
|
||||||
/* added support for .rodata, .rel.text and .rel.data). */
|
|
||||||
|
|
||||||
if(strncmp(name, ".text", 5) == 0) {
|
|
||||||
textoff = shdr.sh_offset;
|
|
||||||
textsize = shdr.sh_size;
|
|
||||||
text.number = i;
|
|
||||||
text.offset = textoff;
|
|
||||||
} else if(strncmp(name, ".rel.text", 9) == 0) {
|
|
||||||
using_relas = 0;
|
|
||||||
textrelaoff = shdr.sh_offset;
|
|
||||||
textrelasize = shdr.sh_size;
|
|
||||||
} else if(strncmp(name, ".rela.text", 10) == 0) {
|
|
||||||
using_relas = 1;
|
|
||||||
textrelaoff = shdr.sh_offset;
|
|
||||||
textrelasize = shdr.sh_size;
|
|
||||||
} else if(strncmp(name, ".data", 5) == 0) {
|
|
||||||
dataoff = shdr.sh_offset;
|
|
||||||
datasize = shdr.sh_size;
|
|
||||||
data.number = i;
|
|
||||||
data.offset = dataoff;
|
|
||||||
} else if(strncmp(name, ".rodata", 7) == 0) {
|
|
||||||
/* read-only data handled the same way as regular text section */
|
|
||||||
rodataoff = shdr.sh_offset;
|
|
||||||
rodatasize = shdr.sh_size;
|
|
||||||
rodata.number = i;
|
|
||||||
rodata.offset = rodataoff;
|
|
||||||
} else if(strncmp(name, ".rel.rodata", 11) == 0) {
|
|
||||||
/* using elf32_rel instead of rela */
|
|
||||||
using_relas = 0;
|
|
||||||
rodatarelaoff = shdr.sh_offset;
|
|
||||||
rodatarelasize = shdr.sh_size;
|
|
||||||
} else if(strncmp(name, ".rela.rodata", 12) == 0) {
|
|
||||||
using_relas = 1;
|
|
||||||
rodatarelaoff = shdr.sh_offset;
|
|
||||||
rodatarelasize = shdr.sh_size;
|
|
||||||
} else if(strncmp(name, ".rel.data", 9) == 0) {
|
|
||||||
/* using elf32_rel instead of rela */
|
|
||||||
using_relas = 0;
|
|
||||||
datarelaoff = shdr.sh_offset;
|
|
||||||
datarelasize = shdr.sh_size;
|
|
||||||
} else if(strncmp(name, ".rela.data", 10) == 0) {
|
|
||||||
using_relas = 1;
|
|
||||||
datarelaoff = shdr.sh_offset;
|
|
||||||
datarelasize = shdr.sh_size;
|
|
||||||
} else if(strncmp(name, ".symtab", 7) == 0) {
|
|
||||||
symtaboff = shdr.sh_offset;
|
|
||||||
symtabsize = shdr.sh_size;
|
|
||||||
} else if(strncmp(name, ".strtab", 7) == 0) {
|
|
||||||
strtaboff = shdr.sh_offset;
|
|
||||||
strtabsize = shdr.sh_size;
|
|
||||||
} else if(strncmp(name, ".bss", 4) == 0) {
|
|
||||||
bsssize = shdr.sh_size;
|
|
||||||
bss.number = i;
|
|
||||||
bss.offset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Move on to the next section header. */
|
|
||||||
shdrptr += shdrsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(symtabsize == 0) {
|
|
||||||
return ELFLOADER_NO_SYMTAB;
|
|
||||||
}
|
|
||||||
if(strtabsize == 0) {
|
|
||||||
return ELFLOADER_NO_STRTAB;
|
|
||||||
}
|
|
||||||
if(textsize == 0) {
|
|
||||||
return ELFLOADER_NO_TEXT;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (bsssize) {
|
|
||||||
bss.address = (char *)
|
|
||||||
elfloader_output_alloc_segment(output, ELFLOADER_SEG_BSS, bsssize);
|
|
||||||
if (!bss.address) return ELFLOADER_OUTPUT_ERROR;
|
|
||||||
}
|
|
||||||
if (datasize) {
|
|
||||||
data.address = (char *)
|
|
||||||
elfloader_output_alloc_segment(output,ELFLOADER_SEG_DATA,datasize);
|
|
||||||
if (!data.address) return ELFLOADER_OUTPUT_ERROR;
|
|
||||||
}
|
|
||||||
if (textsize) {
|
|
||||||
text.address = (char *)
|
|
||||||
elfloader_output_alloc_segment(output,ELFLOADER_SEG_TEXT,textsize);
|
|
||||||
if (!text.address) return ELFLOADER_OUTPUT_ERROR;
|
|
||||||
}
|
|
||||||
if (rodatasize) {
|
|
||||||
rodata.address = (char *)
|
|
||||||
elfloader_output_alloc_segment(output,ELFLOADER_SEG_RODATA,rodatasize);
|
|
||||||
if (!rodata.address) return ELFLOADER_OUTPUT_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* printf("bss base address: bss.address = 0x%08x\n", bss.address);
|
|
||||||
printf("data base address: data.address = 0x%08x\n", data.address);
|
|
||||||
printf("text base address: text.address = 0x%08x\n", text.address);
|
|
||||||
printf("rodata base address: rodata.address = 0x%08x\n", rodata.address); */
|
|
||||||
|
|
||||||
|
|
||||||
/* If we have text segment relocations, we process them. */
|
|
||||||
PRINTF("elfloader: relocate text\n");
|
|
||||||
if(textrelasize > 0) {
|
|
||||||
ret = copy_segment(input_fd, output,
|
|
||||||
textrelaoff, textrelasize,
|
|
||||||
textoff,
|
|
||||||
text.address,
|
|
||||||
strs,
|
|
||||||
strtaboff,
|
|
||||||
symtaboff, symtabsize, using_relas,
|
|
||||||
textsize, ELFLOADER_SEG_TEXT);
|
|
||||||
if(ret != ELFLOADER_OK) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we have any rodata segment relocations, we process them too. */
|
|
||||||
PRINTF("elfloader: relocate rodata\n");
|
|
||||||
if(rodatarelasize > 0) {
|
|
||||||
ret = copy_segment(input_fd, output,
|
|
||||||
rodatarelaoff, rodatarelasize,
|
|
||||||
rodataoff,
|
|
||||||
rodata.address,
|
|
||||||
strs,
|
|
||||||
strtaboff,
|
|
||||||
symtaboff, symtabsize, using_relas,
|
|
||||||
rodatasize, ELFLOADER_SEG_RODATA);
|
|
||||||
if(ret != ELFLOADER_OK) {
|
|
||||||
PRINTF("elfloader: data failed\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we have any data segment relocations, we process them too. */
|
|
||||||
PRINTF("elfloader: relocate data\n");
|
|
||||||
if(datarelasize > 0) {
|
|
||||||
ret = copy_segment(input_fd, output,
|
|
||||||
datarelaoff, datarelasize,
|
|
||||||
dataoff,
|
|
||||||
data.address,
|
|
||||||
strs,
|
|
||||||
strtaboff,
|
|
||||||
symtaboff, symtabsize, using_relas,
|
|
||||||
datasize, ELFLOADER_SEG_DATA);
|
|
||||||
if(ret != ELFLOADER_OK) {
|
|
||||||
PRINTF("elfloader: data failed\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
ret = elfloader_output_end_segment(output);
|
|
||||||
if (ret != ELFLOADER_OK) return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write text and rodata segment into flash and data segment into RAM. */
|
|
||||||
/* elfloader_arch_write_rom(fd, textoff, textsize, text.address); */
|
|
||||||
/* elfloader_arch_write_rom(fd, rodataoff, rodatasize, rodata.address); */
|
|
||||||
|
|
||||||
/* memset(bss.address, 0, bsssize); */
|
|
||||||
/* seek_read(fd, dataoff, data.address, datasize); */
|
|
||||||
|
|
||||||
{
|
|
||||||
/* Write zeros to bss segment */
|
|
||||||
unsigned int len = bsssize;
|
|
||||||
static const char zeros[16] = {0};
|
|
||||||
ret = elfloader_output_start_segment(output, ELFLOADER_SEG_BSS,
|
|
||||||
bss.address,bsssize);
|
|
||||||
if (ret != ELFLOADER_OK) return ret;
|
|
||||||
while(len > sizeof(zeros)) {
|
|
||||||
ret = elfloader_output_write_segment(output, zeros, sizeof(zeros));
|
|
||||||
if (ret != sizeof(zeros)) return ELFLOADER_OUTPUT_ERROR;
|
|
||||||
len -= sizeof(zeros);
|
|
||||||
}
|
|
||||||
ret = elfloader_output_write_segment(output, zeros, len);
|
|
||||||
if (ret != len) return ELFLOADER_OUTPUT_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
PRINTF("elfloader: autostart search\n");
|
|
||||||
process = find_local_symbol(input_fd, "autostart_processes", symtaboff, symtabsize, strtaboff);
|
|
||||||
if(process != NULL) {
|
|
||||||
PRINTF("elfloader: autostart found\n");
|
|
||||||
elfloader_autostart_processes = process;
|
|
||||||
return ELFLOADER_OK;
|
|
||||||
} else {
|
|
||||||
PRINTF("elfloader: no autostart\n");
|
|
||||||
process = find_program_processes(input_fd, symtaboff, symtabsize, strtaboff);
|
|
||||||
if(process != NULL) {
|
|
||||||
PRINTF("elfloader: FOUND PRG\n");
|
|
||||||
}
|
|
||||||
return ELFLOADER_NO_STARTPOINT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*---------------------------------------------------------------------------*/
|
|
|
@ -1,314 +0,0 @@
|
||||||
/**
|
|
||||||
* \addtogroup loader
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \defgroup elfloader The Contiki ELF loader
|
|
||||||
*
|
|
||||||
* The Contiki ELF loader links, relocates, and loads ELF
|
|
||||||
* (Executable Linkable Format) object files into a running Contiki
|
|
||||||
* system.
|
|
||||||
*
|
|
||||||
* ELF is a standard format for relocatable object code and executable
|
|
||||||
* files. ELF is the standard program format for Linux, Solaris, and
|
|
||||||
* other operating systems.
|
|
||||||
*
|
|
||||||
* An ELF file contains either a standalone executable program or a
|
|
||||||
* program module. The file contains both the program code, the
|
|
||||||
* program data, as well as information about how to link, relocate,
|
|
||||||
* and load the program into a running system.
|
|
||||||
*
|
|
||||||
* The ELF file is composed of a set of sections. The sections contain
|
|
||||||
* program code, data, or relocation information, but can also contain
|
|
||||||
* debugging information.
|
|
||||||
*
|
|
||||||
* To link and relocate an ELF file, the Contiki ELF loader first
|
|
||||||
* parses the ELF file structure to find the appropriate ELF
|
|
||||||
* sections. It then allocates memory for the program code and data in
|
|
||||||
* ROM and RAM, respectively. After allocating memory, the Contiki ELF
|
|
||||||
* loader starts relocating the code found in the ELF file.
|
|
||||||
*
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \file
|
|
||||||
* Header file for the Contiki ELF loader.
|
|
||||||
* \author
|
|
||||||
* Adam Dunkels <adam@sics.se>
|
|
||||||
* Simon Berg <ksb@users.sourceforge.net>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2005, Swedish Institute of Computer Science
|
|
||||||
* Copyright (c) 2007, Simon Berg
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. Neither the name of the Institute nor the names of its contributors
|
|
||||||
* may be used to endorse or promote products derived from this software
|
|
||||||
* without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
||||||
* SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the Contiki operating system.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __ELFLOADER_H__
|
|
||||||
#define __ELFLOADER_H__
|
|
||||||
|
|
||||||
#include "cfs/cfs.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return value from elfloader_load() indicating that loading worked.
|
|
||||||
*/
|
|
||||||
#define ELFLOADER_OK 0
|
|
||||||
/**
|
|
||||||
* Return value from elfloader_load() indicating that the ELF file had
|
|
||||||
* a bad header.
|
|
||||||
*/
|
|
||||||
#define ELFLOADER_BAD_ELF_HEADER 1
|
|
||||||
/**
|
|
||||||
* Return value from elfloader_load() indicating that no symbol table
|
|
||||||
* could be find in the ELF file.
|
|
||||||
*/
|
|
||||||
#define ELFLOADER_NO_SYMTAB 2
|
|
||||||
/**
|
|
||||||
* Return value from elfloader_load() indicating that no string table
|
|
||||||
* could be find in the ELF file.
|
|
||||||
*/
|
|
||||||
#define ELFLOADER_NO_STRTAB 3
|
|
||||||
/**
|
|
||||||
* Return value from elfloader_load() indicating that the size of the
|
|
||||||
* .text segment was zero.
|
|
||||||
*/
|
|
||||||
#define ELFLOADER_NO_TEXT 4
|
|
||||||
/**
|
|
||||||
* Return value from elfloader_load() indicating that a symbol
|
|
||||||
* specific symbol could not be found.
|
|
||||||
*
|
|
||||||
* If this value is returned from elfloader_load(), the symbol has
|
|
||||||
* been copied into the elfloader_unknown[] array.
|
|
||||||
*/
|
|
||||||
#define ELFLOADER_SYMBOL_NOT_FOUND 5
|
|
||||||
/**
|
|
||||||
* Return value from elfloader_load() indicating that one of the
|
|
||||||
* required segments (.data, .bss, or .text) could not be found.
|
|
||||||
*/
|
|
||||||
#define ELFLOADER_SEGMENT_NOT_FOUND 6
|
|
||||||
/**
|
|
||||||
* Return value from elfloader_load() indicating that no starting
|
|
||||||
* point could be found in the loaded module.
|
|
||||||
*/
|
|
||||||
#define ELFLOADER_NO_STARTPOINT 7
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return value from elfloader_load() indicating that the ELF file contained
|
|
||||||
* a relocation type that the implementation can't handle.
|
|
||||||
*/
|
|
||||||
#define ELFLOADER_UNHANDLED_RELOC 8
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return value from elfloader_load() indicating that the offset for
|
|
||||||
* a relative addressing mode was too big.
|
|
||||||
*/
|
|
||||||
#define ELFLOADER_OUTOF_RANGE 9
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return value from elfloader_load() indicating that the relocations
|
|
||||||
* where not sorted by offset
|
|
||||||
*/
|
|
||||||
#define ELFLOADER_RELOC_NOT_SORTED 10
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return value from elfloader_load() indicating that reading from the
|
|
||||||
* ELF file failed in some way.
|
|
||||||
*/
|
|
||||||
#define ELFLOADER_INPUT_ERROR 11
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return value from elfloader_load() indicating that writing to a segment
|
|
||||||
* failed.
|
|
||||||
*/
|
|
||||||
#define ELFLOADER_OUTPUT_ERROR 12
|
|
||||||
|
|
||||||
|
|
||||||
#define ELFLOADER_SEG_TEXT 1
|
|
||||||
#define ELFLOADER_SEG_RODATA 2
|
|
||||||
#define ELFLOADER_SEG_DATA 3
|
|
||||||
#define ELFLOADER_SEG_BSS 4
|
|
||||||
|
|
||||||
/**
|
|
||||||
* elfloader output object
|
|
||||||
*
|
|
||||||
* This object defines methods (callbacks) for writing the segments to memory.
|
|
||||||
* It can be extended by the user to include any necessary state.
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct elfloader_output {
|
|
||||||
const struct elfloader_output_ops *ops;
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* \brief Allocate a new segment
|
|
||||||
* \param input The output object
|
|
||||||
* \param type Type of segment
|
|
||||||
* \param size Size of segment in bytes
|
|
||||||
* \return A pointer to the start of the segment.
|
|
||||||
*
|
|
||||||
* The returned address doesn't need to correspond to any real memory,
|
|
||||||
* since it's only used for calculating the relocations.
|
|
||||||
*/
|
|
||||||
|
|
||||||
void *elfloader_allocate_segment(struct elfloader_output *output,
|
|
||||||
unsigned int type, int size);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Start writing to a new segment
|
|
||||||
* \param input The output object
|
|
||||||
* \param type Type of segment
|
|
||||||
* \param addr Address of segment from elfloader_allocate_segment
|
|
||||||
* \param size Size of segment in bytes
|
|
||||||
* \return Returns ELFLOADER_OK if successful, otherwise an error code
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
int elfloader_start_segment(struct elfloader_output *output,
|
|
||||||
unsigned int type, void *addr, int size);
|
|
||||||
/**
|
|
||||||
* \brief Mark end of segment
|
|
||||||
* \param input The output object
|
|
||||||
* \return Zero if successful
|
|
||||||
*/
|
|
||||||
|
|
||||||
int elfloader_end_segment(struct elfloader_output *output);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Write data to a segment
|
|
||||||
* \param input The output object
|
|
||||||
* \param buf Data to be written
|
|
||||||
* \param len Length of data
|
|
||||||
* \return The number of bytes actually written, or negative if failed.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int elfloader_write_segment(struct elfloader_output *output, const char *buf,
|
|
||||||
unsigned int len);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Get the current offset in the file where the next data will
|
|
||||||
* be written.
|
|
||||||
* \param input The output object
|
|
||||||
* \return The current offset.
|
|
||||||
*/
|
|
||||||
|
|
||||||
unsigned int elfloader_segment_offset(struct elfloader_output *output);
|
|
||||||
|
|
||||||
#define elfloader_output_alloc_segment(output, type, size) \
|
|
||||||
((output)->ops->allocate_segment(output, type, size))
|
|
||||||
|
|
||||||
#define elfloader_output_start_segment(output, type, addr, size) \
|
|
||||||
((output)->ops->start_segment(output, type, addr, size))
|
|
||||||
|
|
||||||
#define elfloader_output_end_segment(output) \
|
|
||||||
((output)->ops->end_segment(output))
|
|
||||||
|
|
||||||
#define elfloader_output_write_segment(output, buf, len) \
|
|
||||||
((output)->ops->write_segment(output, buf, len))
|
|
||||||
|
|
||||||
#define elfloader_output_segment_offset(output) \
|
|
||||||
((output)->ops->segment_offset(output))
|
|
||||||
|
|
||||||
|
|
||||||
struct elfloader_output_ops {
|
|
||||||
void * (*allocate_segment)(struct elfloader_output *output,
|
|
||||||
unsigned int type, int size);
|
|
||||||
int (*start_segment)(struct elfloader_output *output,
|
|
||||||
unsigned int type, void *addr, int size);
|
|
||||||
int (*end_segment)(struct elfloader_output *output);
|
|
||||||
int (*write_segment)(struct elfloader_output *output, const char *buf,
|
|
||||||
unsigned int len);
|
|
||||||
unsigned int (*segment_offset)(struct elfloader_output *output);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* elfloader initialization function.
|
|
||||||
*
|
|
||||||
* This function should be called at boot up to initilize the elfloader.
|
|
||||||
*/
|
|
||||||
void elfloader_init(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Load and relocate an ELF file.
|
|
||||||
* \param input Input object defining how to read from the ELF file
|
|
||||||
* \param output Output object defining how to create and write to seegments.
|
|
||||||
* \return ELFLOADER_OK if loading and relocation worked.
|
|
||||||
* Otherwise an error value.
|
|
||||||
*
|
|
||||||
* If the function is able to load the ELF file, a pointer
|
|
||||||
* to the process structure in the model is stored in the
|
|
||||||
* elfloader_loaded_process variable.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
int elfloader_load(int input_fd,
|
|
||||||
struct elfloader_output *output);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A pointer to the processes loaded with elfloader_load().
|
|
||||||
*/
|
|
||||||
extern struct process **elfloader_autostart_processes;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If elfloader_load() could not find a specific symbol, it is copied
|
|
||||||
* into this array.
|
|
||||||
*/
|
|
||||||
extern char elfloader_unknown[30];
|
|
||||||
|
|
||||||
#ifdef ELFLOADER_CONF_DATAMEMORY_SIZE
|
|
||||||
#define ELFLOADER_DATAMEMORY_SIZE ELFLOADER_CONF_DATAMEMORY_SIZE
|
|
||||||
#else
|
|
||||||
#define ELFLOADER_DATAMEMORY_SIZE 0x100
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef ELFLOADER_CONF_TEXTMEMORY_SIZE
|
|
||||||
#define ELFLOADER_TEXTMEMORY_SIZE ELFLOADER_CONF_TEXTMEMORY_SIZE
|
|
||||||
#else
|
|
||||||
#define ELFLOADER_TEXTMEMORY_SIZE 0x100
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef unsigned long elf32_word;
|
|
||||||
typedef signed long elf32_sword;
|
|
||||||
typedef unsigned short elf32_half;
|
|
||||||
typedef unsigned long elf32_off;
|
|
||||||
typedef unsigned long elf32_addr;
|
|
||||||
|
|
||||||
struct elf32_rela {
|
|
||||||
elf32_addr r_offset; /* Location to be relocated. */
|
|
||||||
elf32_word r_info; /* Relocation type and symbol index. */
|
|
||||||
elf32_sword r_addend; /* Addend. */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* __ELFLOADER_H__ */
|
|
||||||
|
|
||||||
/** @} */
|
|
||||||
/** @} */
|
|
|
@ -1,3 +0,0 @@
|
||||||
#include "symbols.h"
|
|
||||||
const int symbols_nelts = 0;
|
|
||||||
const struct symbols symbols[] = {{0,0}};
|
|
|
@ -1,140 +0,0 @@
|
||||||
#ifndef __RAM_SEGMENTS_C__1POIF5E8U4__
|
|
||||||
#define __RAM_SEGMENTS_C__1POIF5E8U4__
|
|
||||||
|
|
||||||
#include <loader/elfloader-otf.h>
|
|
||||||
#include <loader/codeprop-otf.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <lib/malloc.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
struct ram_output
|
|
||||||
{
|
|
||||||
struct elfloader_output output;
|
|
||||||
char *base;
|
|
||||||
unsigned int offset;
|
|
||||||
void *text;
|
|
||||||
void *rodata;
|
|
||||||
void *data;
|
|
||||||
void *bss;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void *
|
|
||||||
allocate_segment(struct elfloader_output * const output,
|
|
||||||
unsigned int type, int size)
|
|
||||||
{
|
|
||||||
struct ram_output * const ram = (struct ram_output *)output;
|
|
||||||
void *block = malloc(size);
|
|
||||||
if (!block) return NULL;
|
|
||||||
switch(type) {
|
|
||||||
case ELFLOADER_SEG_TEXT:
|
|
||||||
if (ram->text) free(ram->text);
|
|
||||||
ram->text = block;
|
|
||||||
break;
|
|
||||||
case ELFLOADER_SEG_RODATA:
|
|
||||||
if (ram->rodata) free(ram->rodata);
|
|
||||||
ram->rodata = block;
|
|
||||||
break;
|
|
||||||
case ELFLOADER_SEG_DATA:
|
|
||||||
if (ram->data) free(ram->data);
|
|
||||||
ram->data = block;
|
|
||||||
break;
|
|
||||||
case ELFLOADER_SEG_BSS:
|
|
||||||
if (ram->bss) free(ram->bss);
|
|
||||||
ram->bss = block;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
free(block);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return block;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
start_segment(struct elfloader_output *output,
|
|
||||||
unsigned int type, void *addr, int size)
|
|
||||||
{
|
|
||||||
((struct ram_output*)output)->base = addr;
|
|
||||||
((struct ram_output*)output)->offset = 0;
|
|
||||||
return ELFLOADER_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
end_segment(struct elfloader_output *output)
|
|
||||||
{
|
|
||||||
return ELFLOADER_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
write_segment(struct elfloader_output *output, const char *buf,
|
|
||||||
unsigned int len)
|
|
||||||
{
|
|
||||||
struct ram_output * const ram = (struct ram_output *)output;
|
|
||||||
memcpy(ram->base + ram->offset, buf, len);
|
|
||||||
ram->offset += len;
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int
|
|
||||||
segment_offset(struct elfloader_output *output)
|
|
||||||
{
|
|
||||||
return ((struct ram_output*)output)->offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct elfloader_output_ops elf_output_ops =
|
|
||||||
{
|
|
||||||
allocate_segment,
|
|
||||||
start_segment,
|
|
||||||
end_segment,
|
|
||||||
write_segment,
|
|
||||||
segment_offset
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static struct ram_output seg_output = {
|
|
||||||
{&elf_output_ops},
|
|
||||||
NULL,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
PROCESS(ram_segments_cleanup_process, "RAM segments cleanup process");
|
|
||||||
|
|
||||||
PROCESS_THREAD(ram_segments_cleanup_process, ev, data)
|
|
||||||
{
|
|
||||||
PROCESS_BEGIN();
|
|
||||||
while(1) {
|
|
||||||
PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_EXITED
|
|
||||||
|| ev == PROCESS_EVENT_EXIT);
|
|
||||||
if (ev == PROCESS_EVENT_EXIT) break;
|
|
||||||
if (elfloader_autostart_processes ||
|
|
||||||
elfloader_autostart_processes[0] == data) {
|
|
||||||
PROCESS_PAUSE(); /* Let the process exit */
|
|
||||||
if (seg_output.text) {
|
|
||||||
free(seg_output.text);
|
|
||||||
seg_output.text = NULL;
|
|
||||||
}
|
|
||||||
if (seg_output.rodata) {
|
|
||||||
free(seg_output.rodata);
|
|
||||||
seg_output.rodata = NULL;
|
|
||||||
}
|
|
||||||
if (seg_output.data) {
|
|
||||||
free(seg_output.data);
|
|
||||||
seg_output.data = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (seg_output.bss) {
|
|
||||||
free(seg_output.bss);
|
|
||||||
seg_output.bss = NULL;
|
|
||||||
}
|
|
||||||
elfloader_autostart_processes = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PROCESS_END();
|
|
||||||
}
|
|
||||||
struct elfloader_output *codeprop_output = &seg_output.output;
|
|
||||||
|
|
||||||
#endif /* __RAM_SEGMENTS_C__1POIF5E8U4__ */
|
|
|
@ -1,6 +0,0 @@
|
||||||
#ifndef __RAM_SEGMENTS_H__8EDB9N09UD__
|
|
||||||
#define __RAM_SEGMENTS_H__8EDB9N09UD__
|
|
||||||
|
|
||||||
PROCESS_NAME(ram_segments_cleanup_process);
|
|
||||||
|
|
||||||
#endif /* __RAM_SEGMENTS_H__8EDB9N09UD__ */
|
|
|
@ -1,8 +0,0 @@
|
||||||
SECTIONS
|
|
||||||
{
|
|
||||||
.text :
|
|
||||||
{
|
|
||||||
*(.text)
|
|
||||||
*(.rodata.* .rodata)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,124 +0,0 @@
|
||||||
#include <debug-uart.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
int
|
|
||||||
_open(const char *name, int flags, int mode) {
|
|
||||||
errno = ENOENT;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
_close(int file)
|
|
||||||
{
|
|
||||||
if (file == 1 || file == 2) {
|
|
||||||
dbg_drain();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
errno = EBADF;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
isatty(int file)
|
|
||||||
{
|
|
||||||
if (file >= 0 && file <= 2) return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
_read(int file, char *ptr, int len){
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
_write(int file, const char *ptr, int len){
|
|
||||||
int sent = -1;
|
|
||||||
if (file == 1 || file == 2) {
|
|
||||||
sent = dbg_send_bytes((const unsigned char*)ptr, len);
|
|
||||||
}
|
|
||||||
return sent;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
_lseek(int file, int ptr, int dir){
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
_fstat(int file, struct stat *st) {
|
|
||||||
if (file >= 0 && file <= 2) {
|
|
||||||
st->st_mode = S_IFCHR;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
errno = EBADF;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
_stat(char *file, struct stat *st) {
|
|
||||||
errno = ENOENT;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
caddr_t
|
|
||||||
_sbrk(int incr)
|
|
||||||
{
|
|
||||||
extern char __heap_start__; /* Defined by the linker */
|
|
||||||
extern char __heap_end__; /* Defined by the linker */
|
|
||||||
static char *heap_end = &__heap_start__;
|
|
||||||
char *prev_heap_end;
|
|
||||||
|
|
||||||
prev_heap_end = heap_end;
|
|
||||||
if (heap_end + incr > &__heap_end__) {
|
|
||||||
printf("Heap full (requested %d, available %d)\n",
|
|
||||||
incr, (int)(&__heap_end__ - heap_end));
|
|
||||||
errno = ENOMEM;
|
|
||||||
return (caddr_t)-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
heap_end += incr;
|
|
||||||
return (caddr_t) prev_heap_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
fsync(int fd)
|
|
||||||
{
|
|
||||||
if (fd == 1 || fd == 2) {
|
|
||||||
dbg_drain();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (fd == 0) return 0;
|
|
||||||
errno = EBADF;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
_exit(int status)
|
|
||||||
{
|
|
||||||
while(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
_abort()
|
|
||||||
{
|
|
||||||
while(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
_kill()
|
|
||||||
{
|
|
||||||
while(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
pid_t
|
|
||||||
_getpid(void)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const unsigned long
|
|
||||||
bkpt_instr = 0xe1200070;
|
|
|
@ -1 +0,0 @@
|
||||||
arm7_9 force_hw_bkpts enable
|
|
|
@ -1,30 +0,0 @@
|
||||||
#daemon configuration
|
|
||||||
telnet_port 4444
|
|
||||||
gdb_port 3333
|
|
||||||
|
|
||||||
#interface
|
|
||||||
interface parport
|
|
||||||
parport_port 0
|
|
||||||
parport_cable wiggler
|
|
||||||
jtag_speed 0
|
|
||||||
#use combined on interfaces or targets that can't set TRST/SRST separately
|
|
||||||
reset_config srst_only
|
|
||||||
|
|
||||||
#jtag scan chain
|
|
||||||
#format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE)
|
|
||||||
jtag_device 4 0x1 0xf 0xe
|
|
||||||
|
|
||||||
#target configuration
|
|
||||||
daemon_startup reset
|
|
||||||
#target <type> <startup mode>
|
|
||||||
#target arm7tdmi <reset mode> <chainpos> <endianness> <variant>
|
|
||||||
target arm7tdmi little run_and_init 0 arm7tdmi_r4
|
|
||||||
#target_script 0 reset h2294_init.script
|
|
||||||
target_script 0 reset AT91SAM7x_init.script
|
|
||||||
run_and_halt_time 0 30
|
|
||||||
working_area 0 0x40000000 0x4000 nobackup
|
|
||||||
|
|
||||||
#flash configuration
|
|
||||||
#flash bank lpc2000 0x0 0x40000 0 0 lpc2000_v1 0 14765 calc_checksum
|
|
||||||
#flash bank cfi 0x80000000 0x400000 2 2 0
|
|
||||||
flash bank at91sam7 0 0 0 0 0
|
|
|
@ -1,30 +0,0 @@
|
||||||
#daemon configuration
|
|
||||||
telnet_port 4444
|
|
||||||
gdb_port 3333
|
|
||||||
|
|
||||||
#interface
|
|
||||||
interface parport
|
|
||||||
parport_port 0
|
|
||||||
parport_cable wiggler
|
|
||||||
jtag_speed 0
|
|
||||||
#use combined on interfaces or targets that can't set TRST/SRST separately
|
|
||||||
reset_config srst_only
|
|
||||||
|
|
||||||
#jtag scan chain
|
|
||||||
#format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE)
|
|
||||||
jtag_device 4 0x1 0xf 0xe
|
|
||||||
|
|
||||||
#target configuration
|
|
||||||
daemon_startup reset
|
|
||||||
#target <type> <startup mode>
|
|
||||||
#target arm7tdmi <reset mode> <chainpos> <endianness> <variant>
|
|
||||||
target arm7tdmi little run_and_init 0 arm7tdmi_r4
|
|
||||||
#target_script 0 reset h2294_init.script
|
|
||||||
target_script 0 reset openocd_flash
|
|
||||||
run_and_halt_time 0 30
|
|
||||||
working_area 0 0x40000000 0x4000 nobackup
|
|
||||||
|
|
||||||
#flash configuration
|
|
||||||
#flash bank lpc2000 0x0 0x40000 0 0 lpc2000_v1 0 14765 calc_checksum
|
|
||||||
#flash bank cfi 0x80000000 0x400000 2 2 0
|
|
||||||
flash bank at91sam7 0 0 0 0 0
|
|
|
@ -1,30 +0,0 @@
|
||||||
#daemon configuration
|
|
||||||
telnet_port 4444
|
|
||||||
gdb_port 3333
|
|
||||||
|
|
||||||
#interface
|
|
||||||
interface parport
|
|
||||||
parport_port 0
|
|
||||||
parport_cable wiggler
|
|
||||||
jtag_speed 0
|
|
||||||
#use combined on interfaces or targets that can't set TRST/SRST separately
|
|
||||||
reset_config srst_only
|
|
||||||
|
|
||||||
#jtag scan chain
|
|
||||||
#format L IRC IRCM IDCODE (Length, IR Capture, IR Capture Mask, IDCODE)
|
|
||||||
jtag_device 4 0x1 0xf 0xe
|
|
||||||
|
|
||||||
#target configuration
|
|
||||||
daemon_startup reset
|
|
||||||
#target <type> <startup mode>
|
|
||||||
#target arm7tdmi <reset mode> <chainpos> <endianness> <variant>
|
|
||||||
target arm7tdmi little run_and_init 0 arm7tdmi_r4
|
|
||||||
#target_script 0 reset h2294_init.script
|
|
||||||
target_script 0 reset openocd_reset
|
|
||||||
run_and_halt_time 0 30
|
|
||||||
working_area 0 0x40000000 0x4000 nobackup
|
|
||||||
|
|
||||||
#flash configuration
|
|
||||||
#flash bank lpc2000 0x0 0x40000 0 0 lpc2000_v1 0 14765 calc_checksum
|
|
||||||
#flash bank cfi 0x80000000 0x400000 2 2 0
|
|
||||||
flash bank at91sam7 0 0 0 0 0
|
|
|
@ -1,10 +0,0 @@
|
||||||
poll
|
|
||||||
mww 0xffffff64 0x5a000004
|
|
||||||
sleep 250
|
|
||||||
mww 0xffffff64 0x5a002004
|
|
||||||
sleep 250
|
|
||||||
flash probe 0
|
|
||||||
flash write 0 /tmp/openocd_write.bin 0x0
|
|
||||||
reset run
|
|
||||||
sleep 500
|
|
||||||
shutdown
|
|
|
@ -1,4 +0,0 @@
|
||||||
poll
|
|
||||||
reset run
|
|
||||||
sleep 500
|
|
||||||
shutdown
|
|
|
@ -1,22 +0,0 @@
|
||||||
volatile unsigned int pit_count = 0;
|
|
||||||
|
|
||||||
static void NACKEDFUNC ATTR system_int (void) { /* System Interrupt Handler */
|
|
||||||
|
|
||||||
ISR_ENTRY();
|
|
||||||
|
|
||||||
if (*AT91C_PITC_PISR & AT91C_PITC_PITS) { /* Check PIT Interrupt */
|
|
||||||
pit_count++;
|
|
||||||
/*
|
|
||||||
if ((pit_count % 100) == 0) {
|
|
||||||
unsigned int led_state = (pit_count % 300) / 100;
|
|
||||||
*AT91C_PIOA_ODSR = ~(1<<led_state);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
*AT91C_AIC_EOICR = *AT91C_PITC_PIVR; /* Ack & End of Interrupt */
|
|
||||||
} else {
|
|
||||||
*AT91C_AIC_EOICR = 0; /* End of Interrupt */
|
|
||||||
}
|
|
||||||
|
|
||||||
ISR_EXIT();
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
#include "rtimer-arch-interrupt.h"
|
|
||||||
#include "rtimer-arch.h"
|
|
||||||
#include <interrupt-utils.h>
|
|
||||||
#include <AT91SAM7S64.h>
|
|
||||||
|
|
||||||
#define DEBUG 1
|
|
||||||
#if DEBUG
|
|
||||||
#include <stdio.h>
|
|
||||||
#define PRINTF(...) printf(__VA_ARGS__)
|
|
||||||
#else
|
|
||||||
#define PRINTF(...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Here we have a proper stack frame and can use local variables */
|
|
||||||
static void rtimer_int_safe() __attribute((noinline));
|
|
||||||
static void
|
|
||||||
rtimer_int_safe()
|
|
||||||
{
|
|
||||||
unsigned int status;
|
|
||||||
status = RTIMER_ARCH_TIMER_BASE->TC_SR;
|
|
||||||
if (status & AT91C_TC_CPAS) {
|
|
||||||
rtimer_run_next();
|
|
||||||
}
|
|
||||||
*AT91C_AIC_EOICR = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NACKEDFUNC
|
|
||||||
rtimer_interrupt (void) {
|
|
||||||
ISR_STORE();
|
|
||||||
ISR_ENABLE_NEST();
|
|
||||||
rtimer_int_safe();
|
|
||||||
ISR_DISABLE_NEST();
|
|
||||||
ISR_RESTORE();
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
#ifndef __RTIMER_ARCH_INTERRUPT_H__P0PXG70757__
|
|
||||||
#define __RTIMER_ARCH_INTERRUPT_H__P0PXG70757__
|
|
||||||
|
|
||||||
void rtimer_interrupt (void);
|
|
||||||
|
|
||||||
#endif /* __RTIMER_ARCH_INTERRUPT_H__P0PXG70757__ */
|
|
|
@ -1,49 +0,0 @@
|
||||||
#include "rtimer-arch.h"
|
|
||||||
#include <AT91SAM7S64.h>
|
|
||||||
#include "rtimer-arch-interrupt.h"
|
|
||||||
|
|
||||||
#define DEBUG 1
|
|
||||||
#if DEBUG
|
|
||||||
#include <stdio.h>
|
|
||||||
#define PRINTF(...) printf(__VA_ARGS__)
|
|
||||||
#else
|
|
||||||
#define PRINTF(...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static rtimer_clock_t offset;
|
|
||||||
|
|
||||||
void
|
|
||||||
rtimer_arch_init(void)
|
|
||||||
{
|
|
||||||
offset = 0;
|
|
||||||
RTIMER_ARCH_TIMER_BASE->TC_CMR =
|
|
||||||
(AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP | AT91C_TC_CLKS_TIMER_DIV5_CLOCK);
|
|
||||||
RTIMER_ARCH_TIMER_BASE->TC_RA = 0xffff;
|
|
||||||
RTIMER_ARCH_TIMER_BASE->TC_IER = AT91C_TC_CPAS;
|
|
||||||
*AT91C_PMC_PCER = (1 << RTIMER_ARCH_TIMER_ID);
|
|
||||||
AT91C_AIC_SMR[RTIMER_ARCH_TIMER_ID] =
|
|
||||||
AT91C_AIC_SRCTYPE_INT_POSITIVE_EDGE | 6;
|
|
||||||
AT91C_AIC_SVR[RTIMER_ARCH_TIMER_ID] = (unsigned long)rtimer_interrupt;
|
|
||||||
*AT91C_AIC_IECR = (1 << RTIMER_ARCH_TIMER_ID);
|
|
||||||
RTIMER_ARCH_TIMER_BASE->TC_CCR = AT91C_TC_SWTRG | AT91C_TC_CLKEN;
|
|
||||||
PRINTF("rtimer_arch_init: Done\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
rtimer_arch_schedule(rtimer_clock_t t)
|
|
||||||
{
|
|
||||||
RTIMER_ARCH_TIMER_BASE->TC_RA = t + offset;
|
|
||||||
PRINTF("rtimer_arch_schedule: %d\n",t);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
rtimer_arch_set(rtimer_clock_t t)
|
|
||||||
{
|
|
||||||
offset = t - RTIMER_ARCH_TIMER_BASE->TC_CV;
|
|
||||||
}
|
|
||||||
|
|
||||||
rtimer_clock_t
|
|
||||||
rtimer_arch_now(void)
|
|
||||||
{
|
|
||||||
return RTIMER_ARCH_TIMER_BASE->TC_CV + offset;
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
/**
|
|
||||||
* \file
|
|
||||||
* Header file for the AT91SAM7S-specific rtimer code
|
|
||||||
* \author
|
|
||||||
* Simon Berg <ksb@users.sourceforge.net>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __RTIMER_ARCH_H__
|
|
||||||
#define __RTIMER_ARCH_H__
|
|
||||||
|
|
||||||
#include "sys/rtimer.h"
|
|
||||||
|
|
||||||
#define RTIMER_ARCH_TIMER_ID AT91C_ID_TC1
|
|
||||||
#define RTIMER_ARCH_TIMER_BASE AT91C_BASE_TC1
|
|
||||||
|
|
||||||
#define RTIMER_ARCH_SECOND (MCK/1024)
|
|
||||||
|
|
||||||
void rtimer_arch_set(rtimer_clock_t t);
|
|
||||||
|
|
||||||
rtimer_clock_t rtimer_arch_now(void);
|
|
||||||
|
|
||||||
#endif /* __RTIMER_ARCH_H__ */
|
|
|
@ -1,517 +0,0 @@
|
||||||
/***********************************************************************/
|
|
||||||
/* */
|
|
||||||
/* startup_SAM7S.S: Startup file for Atmel AT91SAM7S device series */
|
|
||||||
/* */
|
|
||||||
/***********************************************************************/
|
|
||||||
/* ported to arm-elf-gcc / WinARM by Martin Thomas, KL, .de */
|
|
||||||
/* <eversmith@heizung-thomas.de> */
|
|
||||||
/* modifications Copyright Martin Thomas 2005 */
|
|
||||||
/* */
|
|
||||||
/* Based on a file that has been a part of the uVision/ARM */
|
|
||||||
/* development tools, Copyright KEIL ELEKTRONIK GmbH 2002-2004 */
|
|
||||||
/***********************************************************************/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Modifications by Martin Thomas:
|
|
||||||
- added handling of execption vectors in RAM ("ramfunc")
|
|
||||||
- added options to remap the interrupt vectors to RAM
|
|
||||||
(see makefile for switch-option)
|
|
||||||
- replaced all ";" and "#" for comments with // or / * * /
|
|
||||||
- added C++ ctor handling
|
|
||||||
- .text in RAM for debugging (RAM_RUN)
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
Modifications by Simon Berg
|
|
||||||
- added stack segment
|
|
||||||
- running program as system by defining RUN_AS_SYSTEM
|
|
||||||
*/
|
|
||||||
|
|
||||||
// mt: this file should not be used with the Configuration Wizard
|
|
||||||
// since a lot of changes have been done for the WinARM/gcc example
|
|
||||||
/*
|
|
||||||
// *** <<< Use Configuration Wizard in Context Menu >>> ***
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// *** Startup Code (executed after Reset) ***
|
|
||||||
|
|
||||||
|
|
||||||
// Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs
|
|
||||||
|
|
||||||
.equ Mode_USR, 0x10
|
|
||||||
.equ Mode_FIQ, 0x11
|
|
||||||
.equ Mode_IRQ, 0x12
|
|
||||||
.equ Mode_SVC, 0x13
|
|
||||||
.equ Mode_ABT, 0x17
|
|
||||||
.equ Mode_UND, 0x1B
|
|
||||||
.equ Mode_SYS, 0x1F
|
|
||||||
|
|
||||||
.equ I_Bit, 0x80 /* when I bit is set, IRQ is disabled */
|
|
||||||
.equ F_Bit, 0x40 /* when F bit is set, FIQ is disabled */
|
|
||||||
|
|
||||||
|
|
||||||
// Internal Memory Base Addresses
|
|
||||||
.equ FLASH_BASE, 0x00100000
|
|
||||||
.equ RAM_BASE, 0x00200000
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
// <h> Stack Configuration
|
|
||||||
// <o> Top of Stack Address <0x0-0xFFFFFFFF:4>
|
|
||||||
// <h> Stack Sizes (in Bytes)
|
|
||||||
// <o1> Undefined Mode <0x0-0xFFFFFFFF:4>
|
|
||||||
// <o2> Supervisor Mode <0x0-0xFFFFFFFF:4>
|
|
||||||
// <o3> Abort Mode <0x0-0xFFFFFFFF:4>
|
|
||||||
// <o4> Fast Interrupt Mode <0x0-0xFFFFFFFF:4>
|
|
||||||
// <o5> Interrupt Mode <0x0-0xFFFFFFFF:4>
|
|
||||||
// <o6> User/System Mode <0x0-0xFFFFFFFF:4>
|
|
||||||
// </h>
|
|
||||||
// </h>
|
|
||||||
*/
|
|
||||||
.equ Top_Stack, 0x00204000
|
|
||||||
.equ UND_Stack_Size, 0x00000004
|
|
||||||
.equ SVC_Stack_Size, 0x00000200
|
|
||||||
.equ ABT_Stack_Size, 0x00000004
|
|
||||||
.equ FIQ_Stack_Size, 0x00000004
|
|
||||||
.equ IRQ_Stack_Size, 0x00000400
|
|
||||||
.equ USR_Stack_Size, 0x00000400
|
|
||||||
|
|
||||||
|
|
||||||
.bss
|
|
||||||
.section .stack , "aw", %nobits
|
|
||||||
|
|
||||||
USR_Stack_Start:
|
|
||||||
.skip USR_Stack_Size
|
|
||||||
USR_Stack_End:
|
|
||||||
IRQ_Stack_Start:
|
|
||||||
.skip IRQ_Stack_Size
|
|
||||||
IRQ_Stack_End:
|
|
||||||
FIQ_Stack_Start:
|
|
||||||
.skip FIQ_Stack_Size
|
|
||||||
FIQ_Stack_End:
|
|
||||||
ABT_Stack_Start:
|
|
||||||
.skip ABT_Stack_Size
|
|
||||||
ABT_Stack_End:
|
|
||||||
SVC_Stack_Start:
|
|
||||||
.skip SVC_Stack_Size
|
|
||||||
SVC_Stack_End:
|
|
||||||
UND_Stack_Start:
|
|
||||||
.skip UND_Stack_Size
|
|
||||||
UND_Stack_End:
|
|
||||||
|
|
||||||
// Embedded Flash Controller (EFC) definitions
|
|
||||||
.equ EFC_BASE, 0xFFFFFF00 /* EFC Base Address */
|
|
||||||
.equ EFC_FMR, 0x60 /* EFC_FMR Offset */
|
|
||||||
|
|
||||||
/*
|
|
||||||
// <e> Embedded Flash Controller (EFC)
|
|
||||||
// <o1.16..23> FMCN: Flash Microsecond Cycle Number <0-255>
|
|
||||||
// <i> Number of Master Clock Cycles in 1us
|
|
||||||
// <o1.8..9> FWS: Flash Wait State
|
|
||||||
// <0=> Read: 1 cycle / Write: 2 cycles
|
|
||||||
// <1=> Read: 2 cycle / Write: 3 cycles
|
|
||||||
// <2=> Read: 3 cycle / Write: 4 cycles
|
|
||||||
// <3=> Read: 4 cycle / Write: 4 cycles
|
|
||||||
// </e>
|
|
||||||
*/
|
|
||||||
.equ EFC_SETUP, 1
|
|
||||||
.equ EFC_FMR_Val, 0x00320100
|
|
||||||
|
|
||||||
|
|
||||||
// Watchdog Timer (WDT) definitions
|
|
||||||
.equ WDT_BASE, 0xFFFFFD40 /* WDT Base Address */
|
|
||||||
.equ WDT_MR, 0x04 /* WDT_MR Offset */
|
|
||||||
|
|
||||||
/*
|
|
||||||
// <e> Watchdog Timer (WDT)
|
|
||||||
// <o1.0..11> WDV: Watchdog Counter Value <0-4095>
|
|
||||||
// <o1.16..27> WDD: Watchdog Delta Value <0-4095>
|
|
||||||
// <o1.12> WDFIEN: Watchdog Fault Interrupt Enable
|
|
||||||
// <o1.13> WDRSTEN: Watchdog Reset Enable
|
|
||||||
// <o1.14> WDRPROC: Watchdog Reset Processor
|
|
||||||
// <o1.28> WDDBGHLT: Watchdog Debug Halt
|
|
||||||
// <o1.29> WDIDLEHLT: Watchdog Idle Halt
|
|
||||||
// <o1.15> WDDIS: Watchdog Disable
|
|
||||||
// </e>
|
|
||||||
*/
|
|
||||||
.equ WDT_SETUP, 1
|
|
||||||
.equ WDT_MR_Val, 0x00008000 // Disable watchdog
|
|
||||||
|
|
||||||
|
|
||||||
// Power Mangement Controller (PMC) definitions
|
|
||||||
.equ PMC_BASE, 0xFFFFFC00 /* PMC Base Address */
|
|
||||||
.equ PMC_MOR, 0x20 /* PMC_MOR Offset */
|
|
||||||
.equ PMC_MCFR, 0x24 /* PMC_MCFR Offset */
|
|
||||||
.equ PMC_PLLR, 0x2C /* PMC_PLLR Offset */
|
|
||||||
.equ PMC_MCKR, 0x30 /* PMC_MCKR Offset */
|
|
||||||
.equ PMC_SR, 0x68 /* PMC_SR Offset */
|
|
||||||
.equ PMC_MOSCEN, (1<<0) /* Main Oscillator Enable */
|
|
||||||
.equ PMC_OSCBYPASS, (1<<1) /* Main Oscillator Bypass */
|
|
||||||
.equ PMC_OSCOUNT, (0xFF<<8) /* Main OScillator Start-up Time */
|
|
||||||
.equ PMC_DIV, (0xFF<<0) /* PLL Divider */
|
|
||||||
.equ PMC_PLLCOUNT, (0x3F<<8) /* PLL Lock Counter */
|
|
||||||
.equ PMC_OUT, (0x03<<14) /* PLL Clock Frequency Range */
|
|
||||||
.equ PMC_MUL, (0x7FF<<16) /* PLL Multiplier */
|
|
||||||
.equ PMC_USBDIV, (0x03<<28) /* USB Clock Divider */
|
|
||||||
.equ PMC_CSS, (3<<0) /* Clock Source Selection */
|
|
||||||
.equ PMC_PRES, (7<<2) /* Prescaler Selection */
|
|
||||||
.equ PMC_MOSCS, (1<<0) /* Main Oscillator Stable */
|
|
||||||
.equ PMC_LOCK, (1<<2) /* PLL Lock Status */
|
|
||||||
|
|
||||||
/*
|
|
||||||
// <e> Power Mangement Controller (PMC)
|
|
||||||
// <h> Main Oscillator
|
|
||||||
// <o1.0> MOSCEN: Main Oscillator Enable
|
|
||||||
// <o1.1> OSCBYPASS: Oscillator Bypass
|
|
||||||
// <o1.8..15> OSCCOUNT: Main Oscillator Startup Time <0-255>
|
|
||||||
// </h>
|
|
||||||
// <h> Phase Locked Loop (PLL)
|
|
||||||
// <o2.0..7> DIV: PLL Divider <0-255>
|
|
||||||
// <o2.16..26> MUL: PLL Multiplier <0-2047>
|
|
||||||
// <i> PLL Output is multiplied by MUL+1
|
|
||||||
// <o2.14..15> OUT: PLL Clock Frequency Range
|
|
||||||
// <0=> 80..160MHz <1=> Reserved
|
|
||||||
// <2=> 150..220MHz <3=> Reserved
|
|
||||||
// <o2.8..13> PLLCOUNT: PLL Lock Counter <0-63>
|
|
||||||
// <o2.28..29> USBDIV: USB Clock Divider
|
|
||||||
// <0=> None <1=> 2 <2=> 4 <3=> Reserved
|
|
||||||
// </h>
|
|
||||||
// <o3.0..1> CSS: Clock Source Selection
|
|
||||||
// <0=> Slow Clock
|
|
||||||
// <1=> Main Clock
|
|
||||||
// <2=> Reserved
|
|
||||||
// <3=> PLL Clock
|
|
||||||
// <o3.2..4> PRES: Prescaler
|
|
||||||
// <0=> None
|
|
||||||
// <1=> Clock / 2 <2=> Clock / 4
|
|
||||||
// <3=> Clock / 8 <4=> Clock / 16
|
|
||||||
// <5=> Clock / 32 <6=> Clock / 64
|
|
||||||
// <7=> Reserved
|
|
||||||
// </e>
|
|
||||||
*/
|
|
||||||
.equ PMC_SETUP, 1
|
|
||||||
.equ PMC_MOR_Val, 0x00000601 /* Enable main oscilator,
|
|
||||||
48 cycles startup */
|
|
||||||
.equ PMC_PLLR_Val, 0x00191C05 /* 28 cycles startup,
|
|
||||||
PLL = 5.2* * main clock */
|
|
||||||
.equ PMC_MCKR_Val, 0x0000000B /* MCK = PLL/4 */
|
|
||||||
|
|
||||||
/* Reset controller */
|
|
||||||
.equ RSTC_BASE, 0xfffffd00
|
|
||||||
.equ RSTC_CR, 0x00
|
|
||||||
.equ RSTC_SR, 0x04
|
|
||||||
.equ RSTC_MR, 0x08
|
|
||||||
|
|
||||||
.equ RSTC_SETUP, 1
|
|
||||||
.equ RSTC_MR_Val, 0xa5000001 /* Enable user reset */
|
|
||||||
|
|
||||||
|
|
||||||
/* Advanced interrupt controller */
|
|
||||||
.equ AIC_SETUP, 1
|
|
||||||
.equ AIC_BASE, 0xfffff000
|
|
||||||
.equ AIC_EOICR, 0x130
|
|
||||||
.equ AIC_SPU, 0x134
|
|
||||||
|
|
||||||
#if (defined(VECTORS_IN_RAM) && defined(ROM_RUN)) || defined(USE_SAMBA)
|
|
||||||
|
|
||||||
/*
|
|
||||||
Exception Vectors to be placed in RAM - added by mt
|
|
||||||
-> will be used after remapping in ROM_RUN
|
|
||||||
-> not needed for RAM_RUN
|
|
||||||
-> moved to address 0 after remapping
|
|
||||||
Mapped to Address 0 after remapping in ROM_RUN
|
|
||||||
Absolute addressing mode must be used.
|
|
||||||
Dummy Handlers are implemented as infinite loops which can be modified.
|
|
||||||
VECTORS_IN_RAM defined in makefile/by commandline
|
|
||||||
*/
|
|
||||||
.text
|
|
||||||
.arm
|
|
||||||
.section .vectram, "ax"
|
|
||||||
|
|
||||||
VectorsRAM: LDR PC,Reset_AddrR
|
|
||||||
LDR PC,Undef_AddrR
|
|
||||||
LDR PC,SWI_AddrR
|
|
||||||
LDR PC,PAbt_AddrR
|
|
||||||
LDR PC,DAbt_AddrR
|
|
||||||
NOP /* Reserved Vector */
|
|
||||||
LDR PC,[PC,#-0xF20] /* Vector From AIC_IVR */
|
|
||||||
LDR PC,[PC,#-0xF20] /* Vector From AIC_FVR */
|
|
||||||
|
|
||||||
Reset_AddrR: .word Reset_Handler
|
|
||||||
Undef_AddrR: .word Undef_HandlerR
|
|
||||||
SWI_AddrR: .word SWI_HandlerR
|
|
||||||
PAbt_AddrR: .word PAbt_HandlerR
|
|
||||||
DAbt_AddrR: .word DAbt_HandlerR
|
|
||||||
// .word 0xdeadbeef /* Test Reserved Address */
|
|
||||||
.word 0 /* Reserved Address */
|
|
||||||
IRQ_AddrR: .word IRQ_HandlerR
|
|
||||||
FIQ_AddrR: .word FIQ_HandlerR
|
|
||||||
|
|
||||||
Undef_HandlerR: B Undef_HandlerR
|
|
||||||
SWI_HandlerR: B SWI_HandlerR
|
|
||||||
PAbt_HandlerR: B PAbt_HandlerR
|
|
||||||
DAbt_HandlerR: B DAbt_HandlerR
|
|
||||||
IRQ_HandlerR: B IRQ_HandlerR
|
|
||||||
FIQ_HandlerR: B FIQ_HandlerR
|
|
||||||
|
|
||||||
VectorsRAM_end:
|
|
||||||
#endif /* VECTORS_IN_RAM && ROM_RUN */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef USE_SAMBA
|
|
||||||
|
|
||||||
/*
|
|
||||||
Exception Vectors
|
|
||||||
- for ROM_RUN: placed in 0x00000000
|
|
||||||
- for RAM_RUN: placed at 0x00200000 (on AT91SAM7S64)
|
|
||||||
- for USE_SAMBA: not used
|
|
||||||
-> will be used during startup before remapping with target ROM_RUN
|
|
||||||
-> will be used "always" in code without remapping or with target RAM_RUN
|
|
||||||
Mapped to Address relative address 0 of .text
|
|
||||||
Absolute addressing mode must be used.
|
|
||||||
Dummy Handlers are implemented as infinite loops which can be modified.
|
|
||||||
*/
|
|
||||||
.text
|
|
||||||
.arm
|
|
||||||
.section .vectrom, "ax"
|
|
||||||
|
|
||||||
Vectors: LDR PC,Reset_Addr
|
|
||||||
LDR PC,Undef_Addr
|
|
||||||
LDR PC,SWI_Addr
|
|
||||||
LDR PC,PAbt_Addr
|
|
||||||
LDR PC,DAbt_Addr
|
|
||||||
NOP /* Reserved Vector */
|
|
||||||
// LDR PC,IRQ_Addr
|
|
||||||
LDR PC,[PC,#-0xF20] /* Vector From AIC_IVR */
|
|
||||||
// LDR PC,FIQ_Addr
|
|
||||||
LDR PC,[PC,#-0xF20] /* Vector From AIC_FVR */
|
|
||||||
|
|
||||||
Reset_Addr: .word Reset_Handler
|
|
||||||
Undef_Addr: .word Undef_Handler
|
|
||||||
SWI_Addr: .word SWI_Handler
|
|
||||||
PAbt_Addr: .word PAbt_Handler
|
|
||||||
DAbt_Addr: .word DAbt_Handler
|
|
||||||
.word 0 /* Reserved Address */
|
|
||||||
IRQ_Addr: .word IRQ_Handler
|
|
||||||
FIQ_Addr: .word FIQ_Handler
|
|
||||||
|
|
||||||
Undef_Handler: B Undef_Handler
|
|
||||||
SWI_Handler: B SWI_Handler
|
|
||||||
PAbt_Handler: B PAbt_Handler
|
|
||||||
DAbt_Handler: B DAbt_Handler
|
|
||||||
IRQ_Handler: B IRQ_Handler
|
|
||||||
FIQ_Handler: B FIQ_Handler
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Spurious interrupt handler
|
|
||||||
SPU_Handler:
|
|
||||||
STMDB SP!, {R0}
|
|
||||||
LDR R0, =AIC_BASE
|
|
||||||
STR R0, [R0, #AIC_EOICR]
|
|
||||||
LDMIA SP!, {R0}
|
|
||||||
SUBS PC, LR, #4
|
|
||||||
|
|
||||||
|
|
||||||
// Starupt Code must be linked first at Address at which it expects to run.
|
|
||||||
|
|
||||||
.text
|
|
||||||
.arm
|
|
||||||
.section .init, "ax"
|
|
||||||
|
|
||||||
.global _startup
|
|
||||||
.func _startup
|
|
||||||
_startup:
|
|
||||||
|
|
||||||
|
|
||||||
// Reset Handler
|
|
||||||
LDR pc, =Reset_Handler
|
|
||||||
Reset_Handler:
|
|
||||||
|
|
||||||
// Setup EFC
|
|
||||||
.if EFC_SETUP
|
|
||||||
LDR R0, =EFC_BASE
|
|
||||||
LDR R1, =EFC_FMR_Val
|
|
||||||
STR R1, [R0, #EFC_FMR]
|
|
||||||
.endif
|
|
||||||
|
|
||||||
|
|
||||||
// Setup WDT
|
|
||||||
.if WDT_SETUP
|
|
||||||
LDR R0, =WDT_BASE
|
|
||||||
LDR R1, =WDT_MR_Val
|
|
||||||
STR R1, [R0, #WDT_MR]
|
|
||||||
.endif
|
|
||||||
|
|
||||||
// Setup reset controller
|
|
||||||
.if RSTC_SETUP
|
|
||||||
LDR R0, =RSTC_BASE
|
|
||||||
LDR R1, =RSTC_MR_Val
|
|
||||||
STR R1, [R0, #RSTC_MR]
|
|
||||||
.endif
|
|
||||||
|
|
||||||
// Setup PMC
|
|
||||||
.if PMC_SETUP
|
|
||||||
LDR R0, =PMC_BASE
|
|
||||||
|
|
||||||
// Setup Main Oscillator
|
|
||||||
LDR R1, =PMC_MOR_Val
|
|
||||||
STR R1, [R0, #PMC_MOR]
|
|
||||||
|
|
||||||
// Wait until Main Oscillator is stablilized
|
|
||||||
.if (PMC_MOR_Val & PMC_MOSCEN)
|
|
||||||
MOSCS_Loop: LDR R2, [R0, #PMC_SR]
|
|
||||||
ANDS R2, R2, #PMC_MOSCS
|
|
||||||
BEQ MOSCS_Loop
|
|
||||||
.endif
|
|
||||||
|
|
||||||
// Setup the PLL
|
|
||||||
.if (PMC_PLLR_Val & PMC_MUL)
|
|
||||||
LDR R1, =PMC_PLLR_Val
|
|
||||||
STR R1, [R0, #PMC_PLLR]
|
|
||||||
|
|
||||||
// Wait until PLL is stabilized
|
|
||||||
PLL_Loop: LDR R2, [R0, #PMC_SR]
|
|
||||||
ANDS R2, R2, #PMC_LOCK
|
|
||||||
BEQ PLL_Loop
|
|
||||||
.endif
|
|
||||||
|
|
||||||
// Select Clock
|
|
||||||
LDR R1, =PMC_MCKR_Val
|
|
||||||
STR R1, [R0, #PMC_MCKR]
|
|
||||||
.endif
|
|
||||||
|
|
||||||
|
|
||||||
// Setup Stack for each mode
|
|
||||||
|
|
||||||
LDR R0, =Top_Stack
|
|
||||||
|
|
||||||
// Enter Undefined Instruction Mode and set its Stack Pointer
|
|
||||||
MSR CPSR_c, #Mode_UND|I_Bit|F_Bit
|
|
||||||
LDR SP, =UND_Stack_End
|
|
||||||
|
|
||||||
// Enter Abort Mode and set its Stack Pointer
|
|
||||||
MSR CPSR_c, #Mode_ABT|I_Bit|F_Bit
|
|
||||||
LDR SP, =ABT_Stack_End
|
|
||||||
|
|
||||||
// Enter FIQ Mode and set its Stack Pointer
|
|
||||||
MSR CPSR_c, #Mode_FIQ|I_Bit|F_Bit
|
|
||||||
LDR SP, =FIQ_Stack_End
|
|
||||||
|
|
||||||
// Enter IRQ Mode and set its Stack Pointer
|
|
||||||
MSR CPSR_c, #Mode_IRQ|I_Bit|F_Bit
|
|
||||||
LDR SP, =IRQ_Stack_End
|
|
||||||
|
|
||||||
// Enter Supervisor Mode and set its Stack Pointer
|
|
||||||
MSR CPSR_c, #Mode_SVC|I_Bit|F_Bit
|
|
||||||
LDR SP, =SVC_Stack_End
|
|
||||||
|
|
||||||
// Enter User Mode and set its Stack Pointer
|
|
||||||
#ifdef RUN_AS_SYSTEM
|
|
||||||
MSR CPSR_c, #Mode_SYS
|
|
||||||
#else
|
|
||||||
MSR CPSR_c, #Mode_USR
|
|
||||||
#endif
|
|
||||||
LDR SP, =USR_Stack_End
|
|
||||||
|
|
||||||
// Setup a default Stack Limit (when compiled with "-mapcs-stack-check")
|
|
||||||
LDR SL, =USR_Stack_End
|
|
||||||
|
|
||||||
#ifdef ROM_RUN
|
|
||||||
// Relocate .data section (Copy from ROM to RAM)
|
|
||||||
LDR R1, =_etext
|
|
||||||
LDR R2, =_data
|
|
||||||
LDR R3, =_edata
|
|
||||||
LoopRel: CMP R2, R3
|
|
||||||
LDRLO R0, [R1], #4
|
|
||||||
STRLO R0, [R2], #4
|
|
||||||
BLO LoopRel
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// Clear .bss section (Zero init)
|
|
||||||
MOV R0, #0
|
|
||||||
LDR R1, =__bss_start__
|
|
||||||
LDR R2, =__bss_end__
|
|
||||||
LoopZI: CMP R1, R2
|
|
||||||
STRLO R0, [R1], #4
|
|
||||||
BLO LoopZI
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(VECTORS_IN_RAM) || defined(RAM_RUN)
|
|
||||||
/*
|
|
||||||
*** Remap ***
|
|
||||||
ROM_RUN: exception vectors for RAM have been already copied
|
|
||||||
to 0x00200000 by the .data copy-loop
|
|
||||||
RAM_RUN: exception vectors are already placed at 0x0020000 by
|
|
||||||
linker settings
|
|
||||||
*/
|
|
||||||
.equ MC_BASE,0xFFFFFF00 /* MC Base Address */
|
|
||||||
.equ MC_RCR, 0x00 /* MC_RCR Offset */
|
|
||||||
|
|
||||||
LDR R0, =MC_BASE
|
|
||||||
MOV R1, #1
|
|
||||||
STR R1, [R0, #MC_RCR] // Remap
|
|
||||||
#endif /* VECTORS_IN_RAM || RAM_RUN */
|
|
||||||
|
|
||||||
#ifdef USE_SAMBA
|
|
||||||
// Copy interrupt vectors to RAM, that has previously been mapped to 0
|
|
||||||
MOV R1, #0
|
|
||||||
LDR R2, = VectorsRAM
|
|
||||||
LDR R3, = VectorsRAM_end
|
|
||||||
LoopVectCopy: CMP R2, R3
|
|
||||||
LDRLO R0, [R2], #4
|
|
||||||
STRLO R0, [R1], #4
|
|
||||||
BLO LoopVectCopy
|
|
||||||
#endif
|
|
||||||
|
|
||||||
.if AIC_SETUP
|
|
||||||
LDR R1, =AIC_BASE
|
|
||||||
LDR R0, = SPU_Handler
|
|
||||||
STR R0, [R1, #AIC_SPU]
|
|
||||||
.endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
Call C++ constructors (for objects in "global scope")
|
|
||||||
added by Martin Thomas based on a Anglia Design
|
|
||||||
example-application for STR7 ARM
|
|
||||||
*/
|
|
||||||
|
|
||||||
LDR r0, =__ctors_start__
|
|
||||||
LDR r1, =__ctors_end__
|
|
||||||
ctor_loop:
|
|
||||||
CMP r0, r1
|
|
||||||
BEQ ctor_end
|
|
||||||
LDR r2, [r0], #4 /* this ctor's address */
|
|
||||||
STMFD sp!, {r0-r1} /* save loop counters */
|
|
||||||
MOV lr, pc /* set return address */
|
|
||||||
// MOV pc, r2
|
|
||||||
BX r2 /* call ctor */
|
|
||||||
LDMFD sp!, {r0-r1} /* restore loop counters */
|
|
||||||
B ctor_loop
|
|
||||||
ctor_end:
|
|
||||||
|
|
||||||
|
|
||||||
// Enter the C code
|
|
||||||
mov r0,#0 // no arguments (argc = 0)
|
|
||||||
mov r1,r0
|
|
||||||
mov r2,r0
|
|
||||||
mov fp,r0 // null frame pointer
|
|
||||||
mov r7,r0 // null frame pointer for thumb
|
|
||||||
ldr r10,=main
|
|
||||||
adr lr, __main_exit
|
|
||||||
bx r10 // enter main()
|
|
||||||
|
|
||||||
__main_exit: B __main_exit
|
|
||||||
|
|
||||||
|
|
||||||
.size _startup, . - _startup
|
|
||||||
.endfunc
|
|
||||||
|
|
||||||
.end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,100 +0,0 @@
|
||||||
#include <sys-interrupt.h>
|
|
||||||
#include <interrupt-utils.h>
|
|
||||||
#include <AT91SAM7S64.h>
|
|
||||||
|
|
||||||
#define ATTR
|
|
||||||
|
|
||||||
#ifndef NULL
|
|
||||||
#define NULL 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
static SystemInterruptHandler *handlers = NULL;
|
|
||||||
|
|
||||||
static void
|
|
||||||
system_int_safe (void) __attribute__((noinline));
|
|
||||||
|
|
||||||
static void
|
|
||||||
system_int_safe (void)
|
|
||||||
{
|
|
||||||
SystemInterruptHandler *h;
|
|
||||||
h = handlers;
|
|
||||||
while (h) {
|
|
||||||
if (h->handler()) break;
|
|
||||||
h = h->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void NACKEDFUNC ATTR
|
|
||||||
system_int (void) /* System Interrupt Handler */
|
|
||||||
{
|
|
||||||
ISR_ENTRY();
|
|
||||||
system_int_safe();
|
|
||||||
*AT91C_AIC_EOICR = 0; /* End of Interrupt */
|
|
||||||
ISR_EXIT();
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int enabled = 0; /* Number of times the system
|
|
||||||
interrupt has been enabled */
|
|
||||||
|
|
||||||
#define DIS_INT *AT91C_AIC_IDCR = (1 << AT91C_ID_SYS)
|
|
||||||
#define EN_INT if (enabled > 0) *AT91C_AIC_IECR = (1 << AT91C_ID_SYS)
|
|
||||||
|
|
||||||
void
|
|
||||||
sys_interrupt_enable()
|
|
||||||
{
|
|
||||||
if (enabled++ == 0) {
|
|
||||||
/* Level trigged at priority 5 */
|
|
||||||
AT91C_AIC_SMR[AT91C_ID_SYS] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | 5;
|
|
||||||
/* Interrupt vector */
|
|
||||||
AT91C_AIC_SVR[AT91C_ID_SYS] = (unsigned long) system_int;
|
|
||||||
/* Enable */
|
|
||||||
EN_INT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
sys_interrupt_disable()
|
|
||||||
{
|
|
||||||
if (--enabled == 0) {
|
|
||||||
DIS_INT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sys_interrupt_append_handler(SystemInterruptHandler *handler)
|
|
||||||
{
|
|
||||||
SystemInterruptHandler **h = &handlers;
|
|
||||||
while(*h) {
|
|
||||||
h = &(*h)->next;
|
|
||||||
}
|
|
||||||
DIS_INT;
|
|
||||||
*h = handler;
|
|
||||||
handler->next = NULL;
|
|
||||||
EN_INT;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sys_interrupt_prepend_handler(SystemInterruptHandler *handler)
|
|
||||||
{
|
|
||||||
DIS_INT;
|
|
||||||
handler->next = handlers;
|
|
||||||
handlers = handler;
|
|
||||||
EN_INT;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sys_interrupt_remove_handler(SystemInterruptHandler *handler)
|
|
||||||
{
|
|
||||||
SystemInterruptHandler **h = &handlers;
|
|
||||||
while(*h) {
|
|
||||||
if (*h == handler) {
|
|
||||||
DIS_INT;
|
|
||||||
*h = handler->next;
|
|
||||||
EN_INT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
h = &(*h)->next;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
#ifndef __SYS_INTERRUPT_H__QIHZ66NP8K__
|
|
||||||
#define __SYS_INTERRUPT_H__QIHZ66NP8K__
|
|
||||||
|
|
||||||
|
|
||||||
/* Returns true if it handled an activbe interrupt */
|
|
||||||
typedef int (*SystemInterruptFunc)();
|
|
||||||
|
|
||||||
typedef struct _SystemInterruptHandler SystemInterruptHandler;
|
|
||||||
struct _SystemInterruptHandler
|
|
||||||
{
|
|
||||||
SystemInterruptHandler *next;
|
|
||||||
SystemInterruptFunc handler;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
sys_interrupt_enable();
|
|
||||||
|
|
||||||
void
|
|
||||||
sys_interrupt_disable();
|
|
||||||
|
|
||||||
void
|
|
||||||
sys_interrupt_append_handler(SystemInterruptHandler *handler);
|
|
||||||
|
|
||||||
void
|
|
||||||
sys_interrupt_prepend_handler(SystemInterruptHandler *handler);
|
|
||||||
|
|
||||||
void
|
|
||||||
sys_interrupt_remove_handler(SystemInterruptHandler *handler);
|
|
||||||
|
|
||||||
#endif /* __SYS_INTERRUPT_H__QIHZ66NP8K__ */
|
|
|
@ -1,6 +0,0 @@
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
void uip_log(char *msg)
|
|
||||||
{
|
|
||||||
printf("uip: %s\n", msg);
|
|
||||||
}
|
|
|
@ -1,83 +0,0 @@
|
||||||
#include <cdc-acm.h>
|
|
||||||
#include <cdc.h>
|
|
||||||
#include <usb-proto.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
static unsigned int
|
|
||||||
handle_cdc_acm_requests()
|
|
||||||
{
|
|
||||||
printf("CDC request %02x %02x\n", usb_setup_buffer.bmRequestType, usb_setup_buffer.bRequest);
|
|
||||||
switch(usb_setup_buffer.bmRequestType) {
|
|
||||||
case 0x21: /* CDC interface OUT requests */
|
|
||||||
/* Check if it's the right interface */
|
|
||||||
if (usb_setup_buffer.wIndex != 0) return 0;
|
|
||||||
switch(usb_setup_buffer.bRequest) {
|
|
||||||
case SET_CONTROL_LINE_STATE:
|
|
||||||
if (usb_setup_buffer.wValue & 0x02) {
|
|
||||||
puts("Carrier on");
|
|
||||||
} else {
|
|
||||||
puts("Carrier off");
|
|
||||||
}
|
|
||||||
if (usb_setup_buffer.wValue & 0x01) {
|
|
||||||
puts("DTE on");
|
|
||||||
} else {
|
|
||||||
puts("DTE off");
|
|
||||||
}
|
|
||||||
usb_send_ctrl_status();
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
case SEND_ENCAPSULATED_COMMAND:
|
|
||||||
printf("Got CDC command: length %d\n", usb_ctrl_data_len);
|
|
||||||
usb_send_ctrl_status();
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
|
|
||||||
case SET_LINE_CODING:
|
|
||||||
if (usb_ctrl_data_len == 7) {
|
|
||||||
static const char parity_char[] = {'N', 'O', 'E', 'M', 'S'};
|
|
||||||
static const char *stop_bits_str[] = {"1","1.5","2"};
|
|
||||||
const struct usb_cdc_line_coding *coding =
|
|
||||||
(const struct usb_cdc_line_coding *)usb_ctrl_data_buffer;
|
|
||||||
char parity = ((coding->bParityType > 4)
|
|
||||||
? '?' : parity_char[coding->bParityType]);
|
|
||||||
const char *stop_bits = ((coding->bCharFormat > 2)
|
|
||||||
? "?" : stop_bits_str[coding->bCharFormat]);
|
|
||||||
printf("Got CDC line coding: %ld/%d/%c/%s\n",
|
|
||||||
coding->dwDTERate, coding->bDataBits, parity, stop_bits);
|
|
||||||
usb_send_ctrl_status();
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0xa1: /* CDC interface IN requests */
|
|
||||||
if (usb_setup_buffer.wIndex != 0) return 0;
|
|
||||||
switch(usb_setup_buffer.bRequest) {
|
|
||||||
case GET_ENCAPSULATED_RESPONSE:
|
|
||||||
printf("CDC response");
|
|
||||||
usb_send_ctrl_status();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct USBRequestHandler cdc_acm_request_handler =
|
|
||||||
{
|
|
||||||
0x21, 0x7f,
|
|
||||||
0x00, 0x00,
|
|
||||||
handle_cdc_acm_requests
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct USBRequestHandlerHook cdc_acm_request_hook =
|
|
||||||
{
|
|
||||||
NULL,
|
|
||||||
&cdc_acm_request_handler
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_cdc_acm_setup()
|
|
||||||
{
|
|
||||||
usb_register_request_handler(&cdc_acm_request_hook);
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
#ifndef __CDC_ACM_H__UFV6K50827__
|
|
||||||
#define __CDC_ACM_H__UFV6K50827__
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_cdc_acm_setup();
|
|
||||||
|
|
||||||
#endif /* __CDC_ACM_H__UFV6K50827__ */
|
|
|
@ -1,202 +0,0 @@
|
||||||
#ifndef __CDC_H__K1Q26ESJOC__
|
|
||||||
#define __CDC_H__K1Q26ESJOC__
|
|
||||||
#include <usb.h>
|
|
||||||
/* Communication Class */
|
|
||||||
/* Class code */
|
|
||||||
#define CDC 0x02
|
|
||||||
|
|
||||||
/* Interface subclass codes */
|
|
||||||
#define CDC_RESERVED 0x00
|
|
||||||
#define DIRECT_LINE_CONTROL_MODEL 0x01
|
|
||||||
#define ABSTRACT_CONTROL_MODEL 0x02
|
|
||||||
#define TELEPHONE_CONTROL_MODEL 0x03
|
|
||||||
#define MULTI_CHANNEL_CONTROL_MODEL 0x04
|
|
||||||
#define CAPI_CONTROL_MODEL 0x05
|
|
||||||
#define ETHERNET_NETWORKING_CONTROL_MODEL 0x06
|
|
||||||
#define ATM_NETWORKING_CONTROL_MODEL 0x07
|
|
||||||
|
|
||||||
/* Protocols */
|
|
||||||
#define V_25TER_PROTOCOL 0x01
|
|
||||||
|
|
||||||
/* Requests */
|
|
||||||
#define SEND_ENCAPSULATED_COMMAND 0x00
|
|
||||||
#define GET_ENCAPSULATED_RESPONSE 0x01
|
|
||||||
#define SET_COMM_FEATURE 0x02
|
|
||||||
#define GET_COMM_FEATURE 0x03
|
|
||||||
#define CLEAR_COMM_FEATURE 0x04
|
|
||||||
|
|
||||||
#define SET_AUX_LINE_STATE 0x10
|
|
||||||
#define SET_HOOK_STATE 0x11
|
|
||||||
#define PULSE_SETUP 0x12
|
|
||||||
#define SEND_PULSE 0x13
|
|
||||||
#define SET_PULSE_TIME 0x14
|
|
||||||
#define RING_AUX_JACK 0x15
|
|
||||||
|
|
||||||
#define SET_LINE_CODING 0x20
|
|
||||||
#define GET_LINE_CODING 0x21
|
|
||||||
#define SET_CONTROL_LINE_STATE 0x22
|
|
||||||
#define SEND_BREAK 0x23
|
|
||||||
|
|
||||||
#define SET_RINGER_PARMS 0x30
|
|
||||||
#define GET_RINGER_PARMS 0x31
|
|
||||||
#define SET_OPERATION_PARMS 0x32
|
|
||||||
#define GET_OPERATION_PARMS 0x33
|
|
||||||
#define SET_LINE_PARMS 0x34
|
|
||||||
#define GET_LINE_PARMS 0x35
|
|
||||||
#define DIAL_DIGITS 0x36
|
|
||||||
|
|
||||||
#define SET_UNIT_PARAMETER 0x37
|
|
||||||
#define GET_UNIT_PARAMETER 0x38
|
|
||||||
#define CLEAR_UNIT_PARAMETER 0x39
|
|
||||||
|
|
||||||
#define GET_PROFILE 0x3a
|
|
||||||
|
|
||||||
#define SET_ETHERNET_MULTICAST_FILTERS 0x40
|
|
||||||
#define GET_ETHERNET_MULTICAST_FILTERS 0x41
|
|
||||||
#define GET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER 0x42
|
|
||||||
#define SET_ETHERNET_POWER_MANAGEMENT_PATTERN_FILTER 0x43
|
|
||||||
#define GET_ETHERNET_STATISTIC 0x44
|
|
||||||
|
|
||||||
#define SET_ATM_D ATA_FORMAT 0x50
|
|
||||||
#define GET_ATM_DEVICE_STATISTICS 0x51
|
|
||||||
#define SET_ATM_DEFAULT_VC 0x52
|
|
||||||
#define GET_ATM_VC_STATISTICS 0x53
|
|
||||||
|
|
||||||
|
|
||||||
/* Notifications */
|
|
||||||
#define NETWORK_CONNECTION 0x00
|
|
||||||
#define RESPONSE_AVAILABLE 0x01
|
|
||||||
|
|
||||||
#define AUX_JACK_HOOK_STATE 0x08
|
|
||||||
#define RING_DETECT 0x09
|
|
||||||
|
|
||||||
#define SERIAL_STATE 0x20
|
|
||||||
|
|
||||||
#define CALL_STATE_CHANGE 0x28
|
|
||||||
#define LINE_STATE_CHANGE 0x29
|
|
||||||
#define CONNECTION_SPEED_CHANGE 0x2a
|
|
||||||
|
|
||||||
/* Data interface */
|
|
||||||
|
|
||||||
/* Class code */
|
|
||||||
#define CDC_DATA 0x0a
|
|
||||||
|
|
||||||
/* Protocols */
|
|
||||||
#define I_430_PROTOCOL 0x30
|
|
||||||
#define ISO_IEC_3_1993_PROTOCOL 0x31
|
|
||||||
#define TRANSPARENT_PROTOCOL 0x32
|
|
||||||
#define Q_921M_PROTOCOL 0x50
|
|
||||||
#define Q_921_PROTOCOL 0x51
|
|
||||||
#define Q_921TM_PROTOCOL 0x52
|
|
||||||
#define V_42BIS_PROTOCOL 0x90
|
|
||||||
#define Q_931_PROTOCOL 0x91
|
|
||||||
#define V_120_PROTOCOL 0x93
|
|
||||||
#define CDC_PROTOCOL 0xfe
|
|
||||||
|
|
||||||
/* Descriptor subtypes */
|
|
||||||
|
|
||||||
#define CDC_FUNC_DESCR_HEADER 0x00
|
|
||||||
#define CDC_FUNC_DESCR_CALL_MGMNT 0x01
|
|
||||||
#define CDC_FUNC_DESCR_ABSTRACT_CTRL_MGMNT 0x02
|
|
||||||
#define CDC_FUNC_DESCR_DIRECT_LINE_MGMNT 0x03
|
|
||||||
#define CDC_FUNC_DESCR_RINGER_MGMNT 0x04
|
|
||||||
#define CDC_FUNC_DESCR_TEL_STATE 0x05
|
|
||||||
#define CDC_FUNC_DESCR_UNION 0x06
|
|
||||||
#define CDC_FUNC_DESCR_COUNTRY 0x07
|
|
||||||
#define CDC_FUNC_DESCR_TEL_MODE 0x08
|
|
||||||
#define CDC_FUNC_DESCR_USB_TERM 0x09
|
|
||||||
#define CDC_FUNC_DESCR_NET_TERM 0x0a
|
|
||||||
#define CDC_FUNC_DESCR_PROTOCOL_UNIT 0x0b
|
|
||||||
#define CDC_FUNC_DESCR_EXTENSION_UNIT 0x0c
|
|
||||||
#define CDC_FUNC_DESCR_MULTICH_MGMNT 0x0d
|
|
||||||
#define CDC_FUNC_DESCR_CAPI_MGMNT 0x0e
|
|
||||||
#define CDC_FUNC_DESCR_ETHERNET 0x0f
|
|
||||||
#define CDC_FUNC_DESCR_ATM 0x10
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct usb_cdc_header_func_descriptor
|
|
||||||
{
|
|
||||||
Uchar bLength; /* Size of this descriptor in bytes */
|
|
||||||
Uchar bDescriptorType; /* CS_INTERFACE descriptor type */
|
|
||||||
Uchar bDescriptorSubtype; /* CDC_FUNC_DESCR_HEADER subtype */
|
|
||||||
Uint16 bcdCDC; /* Revision of class specification */
|
|
||||||
} BYTE_ALIGNED;
|
|
||||||
|
|
||||||
struct usb_cdc_call_mgmnt_func_descriptor
|
|
||||||
{
|
|
||||||
Uchar bLength; /* Size of this descriptor in bytes */
|
|
||||||
Uchar bDescriptorType; /* CS_INTERFACE descriptor type */
|
|
||||||
Uchar bDescriptorSubtype; /* CDC_FUNC_DESCR_CALL_MGMNT subtype */
|
|
||||||
Uchar bmCapabilities; /* Capabilities */
|
|
||||||
Uchar bDataInterface; /* Management data interface */
|
|
||||||
} BYTE_ALIGNED;
|
|
||||||
|
|
||||||
struct usb_cdc_abstract_ctrl_mgmnt_func_descriptor
|
|
||||||
{
|
|
||||||
Uchar bLength; /* Size of this descriptor in bytes */
|
|
||||||
Uchar bDescriptorType; /* CS_INTERFACE descriptor type */
|
|
||||||
Uchar bDescriptorSubtype; /* CDC_FUNC_DESCR_ABSTRACT_CTRL_MGMNT subtype*/
|
|
||||||
Uchar bmCapabilities; /* Capabilities */
|
|
||||||
} BYTE_ALIGNED;
|
|
||||||
|
|
||||||
struct usb_cdc_direct_line_mgmnt_func_descriptor
|
|
||||||
{
|
|
||||||
Uchar bLength; /* Size of this descriptor in bytes */
|
|
||||||
Uchar bDescriptorType; /* CS_INTERFACE descriptor type */
|
|
||||||
Uchar bDescriptorSubtype; /* CDC_FUNC_DESCR_DIRECT_LINE_MGMNT subtype*/
|
|
||||||
Uchar bmCapabilities; /* Capabilities */
|
|
||||||
} BYTE_ALIGNED;
|
|
||||||
|
|
||||||
struct usb_cdc_ringer_mgmnt_func_descriptor
|
|
||||||
{
|
|
||||||
Uchar bLength; /* Size of this descriptor in bytes */
|
|
||||||
Uchar bDescriptorType; /* CS_INTERFACE descriptor type */
|
|
||||||
Uchar bDescriptorSubtype; /* CDC_FUNC_DESCR_RINGER_MGMNT subtype*/
|
|
||||||
Uchar bRingerVolSteps; /* Ringer volume steps */
|
|
||||||
Uchar bNumRingerPatterns; /* Number of ringer patterns supported */
|
|
||||||
} BYTE_ALIGNED;
|
|
||||||
|
|
||||||
struct usb_cdc_tel_mode_func_descriptor
|
|
||||||
{
|
|
||||||
Uchar bLength; /* Size of this descriptor in bytes */
|
|
||||||
Uchar bDescriptorType; /* CS_INTERFACE descriptor type */
|
|
||||||
Uchar bDescriptorSubtype; /* CDC_FUNC_DESCR_TEL_MODE subtype*/
|
|
||||||
Uchar bmCapabilities; /* Capabilities */
|
|
||||||
} BYTE_ALIGNED;
|
|
||||||
|
|
||||||
struct usb_cdc_tel_state_func_descriptor
|
|
||||||
{
|
|
||||||
Uchar bLength; /* Size of this descriptor in bytes */
|
|
||||||
Uchar bDescriptorType; /* CS_INTERFACE descriptor type */
|
|
||||||
Uchar bDescriptorSubtype; /* CDC_FUNC_DESCR_TEL_STATE subtype*/
|
|
||||||
Uchar bmCapabilities; /* Capabilities */
|
|
||||||
} BYTE_ALIGNED;
|
|
||||||
|
|
||||||
struct usb_cdc_union_func_descriptor
|
|
||||||
{
|
|
||||||
Uchar bLength; /* Size of this descriptor in bytes */
|
|
||||||
Uchar bDescriptorType; /* CS_INTERFACE descriptor type */
|
|
||||||
Uchar bDescriptorSubtype; /* CDC_FUNC_DESCR_UNION subtype*/
|
|
||||||
Uchar bMasterInterface; /* Master interface for union */
|
|
||||||
Uchar bSlaveInterface[1]; /* Slave interfaces in union */
|
|
||||||
} BYTE_ALIGNED;
|
|
||||||
|
|
||||||
struct usb_cdc_country_func_descriptor
|
|
||||||
{
|
|
||||||
Uchar bLength; /* Size of this descriptor in bytes */
|
|
||||||
Uchar bDescriptorType; /* CS_INTERFACE descriptor type */
|
|
||||||
Uchar bDescriptorSubtype; /* CDC_FUNC_DESCR_COUNTRY subtype*/
|
|
||||||
Uchar iCountryCodeRelDate; /* Release date for country codes */
|
|
||||||
Uint16 wCountryCode[1]; /* Country codes */
|
|
||||||
} BYTE_ALIGNED;
|
|
||||||
|
|
||||||
struct usb_cdc_line_coding
|
|
||||||
{
|
|
||||||
Uint32 dwDTERate;
|
|
||||||
Uchar bCharFormat;
|
|
||||||
Uchar bParityType;
|
|
||||||
Uchar bDataBits;
|
|
||||||
} BYTE_ALIGNED;
|
|
||||||
|
|
||||||
#endif /* __CDC_H__K1Q26ESJOC__ */
|
|
|
@ -1,124 +0,0 @@
|
||||||
#include "descriptors.h"
|
|
||||||
#include <cdc.h>
|
|
||||||
|
|
||||||
const struct usb_st_device_descriptor device_descriptor =
|
|
||||||
{
|
|
||||||
sizeof(struct usb_st_device_descriptor),
|
|
||||||
DEVICE,
|
|
||||||
0x0210,
|
|
||||||
CDC,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
CTRL_EP_SIZE,
|
|
||||||
0xffff,
|
|
||||||
0xffff,
|
|
||||||
0x0030,
|
|
||||||
2,
|
|
||||||
1,
|
|
||||||
3,
|
|
||||||
1
|
|
||||||
};
|
|
||||||
|
|
||||||
const struct configuration_st {
|
|
||||||
struct usb_st_configuration_descriptor configuration;
|
|
||||||
struct usb_st_interface_descriptor comm;
|
|
||||||
struct usb_cdc_header_func_descriptor header;
|
|
||||||
struct usb_cdc_abstract_ctrl_mgmnt_func_descriptor abstract_ctrl;
|
|
||||||
struct usb_cdc_union_func_descriptor union_descr;
|
|
||||||
struct usb_cdc_call_mgmnt_func_descriptor call_mgmt;
|
|
||||||
#if 1
|
|
||||||
struct usb_st_endpoint_descriptor ep_notification;
|
|
||||||
#endif
|
|
||||||
struct usb_st_interface_descriptor data;
|
|
||||||
struct usb_st_endpoint_descriptor ep_in;
|
|
||||||
struct usb_st_endpoint_descriptor ep_out;
|
|
||||||
} BYTE_ALIGNED configuration_block =
|
|
||||||
{
|
|
||||||
/* Configuration */
|
|
||||||
{
|
|
||||||
sizeof(configuration_block.configuration),
|
|
||||||
CONFIGURATION,
|
|
||||||
sizeof(configuration_block),
|
|
||||||
2,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
0x80,
|
|
||||||
50
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sizeof(configuration_block.comm),
|
|
||||||
INTERFACE,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1,
|
|
||||||
CDC,
|
|
||||||
ABSTRACT_CONTROL_MODEL,
|
|
||||||
V_25TER_PROTOCOL,
|
|
||||||
0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sizeof(configuration_block.header),
|
|
||||||
CS_INTERFACE,
|
|
||||||
CDC_FUNC_DESCR_HEADER,
|
|
||||||
0x0110
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sizeof(configuration_block.abstract_ctrl),
|
|
||||||
CS_INTERFACE,
|
|
||||||
CDC_FUNC_DESCR_ABSTRACT_CTRL_MGMNT,
|
|
||||||
0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sizeof(configuration_block.union_descr),
|
|
||||||
CS_INTERFACE,
|
|
||||||
CDC_FUNC_DESCR_UNION,
|
|
||||||
0, /* Master */
|
|
||||||
{1} /* Slave */
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sizeof(configuration_block.call_mgmt),
|
|
||||||
CS_INTERFACE,
|
|
||||||
CDC_FUNC_DESCR_CALL_MGMNT,
|
|
||||||
0x02,
|
|
||||||
1 /* data interface */
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sizeof(configuration_block.ep_notification),
|
|
||||||
ENDPOINT,
|
|
||||||
0x83,
|
|
||||||
0x03,
|
|
||||||
8,
|
|
||||||
100
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sizeof(configuration_block.data),
|
|
||||||
INTERFACE,
|
|
||||||
1,
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
CDC_DATA,
|
|
||||||
0,
|
|
||||||
TRANSPARENT_PROTOCOL,
|
|
||||||
0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sizeof(configuration_block.ep_in),
|
|
||||||
ENDPOINT,
|
|
||||||
0x81,
|
|
||||||
0x02,
|
|
||||||
64,
|
|
||||||
0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sizeof(configuration_block.ep_out),
|
|
||||||
ENDPOINT,
|
|
||||||
0x02,
|
|
||||||
0x02,
|
|
||||||
64,
|
|
||||||
0
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
const struct usb_st_configuration_descriptor const *configuration_head =
|
|
||||||
(struct usb_st_configuration_descriptor const*)&configuration_block;
|
|
|
@ -1,9 +0,0 @@
|
||||||
#ifndef __DESCRIPTORS_H__RPFUB8O7OV__
|
|
||||||
#define __DESCRIPTORS_H__RPFUB8O7OV__
|
|
||||||
|
|
||||||
#include "usb.h"
|
|
||||||
#include <usb-config.h>
|
|
||||||
|
|
||||||
extern const struct usb_st_device_descriptor device_descriptor;
|
|
||||||
extern const struct usb_st_configuration_descriptor const *configuration_head;
|
|
||||||
#endif /* __DESCRIPTORS_H__RPFUB8O7OV__ */
|
|
|
@ -1,49 +0,0 @@
|
||||||
#include "string-descriptors.h"
|
|
||||||
static const struct {
|
|
||||||
struct usb_st_string_descriptor base;
|
|
||||||
Uint16 chars[15];
|
|
||||||
} string_descriptor_1_en= {{34, 3, {'S'}}, {
|
|
||||||
'e', 'r', 'i', 'a', 'l', ' ', 'i', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e'}};
|
|
||||||
static const struct {
|
|
||||||
struct usb_st_string_descriptor base;
|
|
||||||
Uint16 chars[8];
|
|
||||||
} string_descriptor_1_sv= {{20, 3, {'S'}}, {
|
|
||||||
'e', 'r', 'i', 'e', 'p', 'o', 'r', 't'}};
|
|
||||||
static const struct {
|
|
||||||
struct usb_st_string_descriptor base;
|
|
||||||
Uint16 chars[8];
|
|
||||||
} string_descriptor_2_all= {{20, 3, {'F'}}, {
|
|
||||||
'l', 'u', 'f', 'f', 'w', 'a', 'r', 'e'}};
|
|
||||||
static const struct {
|
|
||||||
struct usb_st_string_descriptor base;
|
|
||||||
Uint16 chars[3];
|
|
||||||
} string_descriptor_3_all= {{10, 3, {'0'}}, {
|
|
||||||
'.', '0', '1'}};
|
|
||||||
static const struct usb_st_string_descriptor * string_table_en[] =
|
|
||||||
{
|
|
||||||
&string_descriptor_1_en.base,
|
|
||||||
&string_descriptor_2_all.base,
|
|
||||||
&string_descriptor_3_all.base,
|
|
||||||
};
|
|
||||||
static const struct usb_st_string_descriptor * string_table_sv[] =
|
|
||||||
{
|
|
||||||
&string_descriptor_1_sv.base,
|
|
||||||
&string_descriptor_2_all.base,
|
|
||||||
&string_descriptor_3_all.base,
|
|
||||||
};
|
|
||||||
static const struct {
|
|
||||||
struct usb_st_language_descriptor base;
|
|
||||||
Uint16 langs[1];
|
|
||||||
} language_descriptor =
|
|
||||||
{
|
|
||||||
{6, 3, {0x0409}},
|
|
||||||
{0x041d, }};
|
|
||||||
static const struct {
|
|
||||||
struct usb_st_string_languages base;
|
|
||||||
struct usb_st_string_language_map map[1];
|
|
||||||
} string_languages_full={{2, 3, &language_descriptor.base,
|
|
||||||
{{0x0409, string_table_en}}}, {
|
|
||||||
{0x041d, string_table_sv},
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const struct usb_st_string_languages * const string_languages = &string_languages_full.base;
|
|
|
@ -1,15 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8" ?>
|
|
||||||
|
|
||||||
<!ELEMENT descriptors (languages, strings)>
|
|
||||||
|
|
||||||
<!ELEMENT languages (lang+) >
|
|
||||||
|
|
||||||
<!ELEMENT lang (#PCDATA) >
|
|
||||||
<!ATTLIST lang
|
|
||||||
id CDATA "all"
|
|
||||||
>
|
|
||||||
|
|
||||||
<!ELEMENT strings (string+) >
|
|
||||||
|
|
||||||
<!ELEMENT string (lang+) >
|
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
#include "usb.h"
|
|
||||||
struct usb_st_string_language_map
|
|
||||||
{
|
|
||||||
Uint16 lang_id;
|
|
||||||
const struct usb_st_string_descriptor * const *descriptors;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct usb_st_string_languages
|
|
||||||
{
|
|
||||||
Uchar num_lang;
|
|
||||||
Uchar max_index;
|
|
||||||
const struct usb_st_language_descriptor *lang_descr;
|
|
||||||
const struct usb_st_string_language_map map[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
extern const struct usb_st_string_languages * const string_languages;
|
|
|
@ -1,19 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8" ?>
|
|
||||||
<descriptors>
|
|
||||||
<languages>
|
|
||||||
<lang id="en">0x0409</lang>
|
|
||||||
<lang id="sv">0x041d</lang>
|
|
||||||
</languages>
|
|
||||||
<strings>
|
|
||||||
<string> <!-- 1 -->
|
|
||||||
<lang id="en">Serial interface</lang>
|
|
||||||
<lang id="sv">Serieport</lang>
|
|
||||||
</string>
|
|
||||||
<string> <!-- 2 -->
|
|
||||||
<lang>Fluffware</lang>
|
|
||||||
</string>
|
|
||||||
<string> <!-- 3 -->
|
|
||||||
<lang>0.01</lang>
|
|
||||||
</string>
|
|
||||||
</strings>
|
|
||||||
</descriptors>
|
|
|
@ -1,129 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8" ?>
|
|
||||||
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
|
|
||||||
<xsl:output method="text" encoding="iso-8859-1"/>
|
|
||||||
<xsl:template match="descriptors">
|
|
||||||
<xsl:variable name="num_lang" select="count(languages/lang)"/>
|
|
||||||
<xsl:text>#include "string-descriptors.h" </xsl:text>
|
|
||||||
|
|
||||||
<!-- string descriptors -->
|
|
||||||
<xsl:for-each select="strings/string/lang">
|
|
||||||
<xsl:text>static const struct { </xsl:text>
|
|
||||||
<xsl:text> struct usb_st_string_descriptor base; </xsl:text>
|
|
||||||
<xsl:text> Uint16 chars[</xsl:text>
|
|
||||||
<xsl:value-of select="string-length(text()) -1"/>
|
|
||||||
<xsl:text>]; </xsl:text>
|
|
||||||
<xsl:text>} string_descriptor_</xsl:text>
|
|
||||||
<xsl:number count="/descriptors/strings/string" format="1"/>
|
|
||||||
<xsl:text>_</xsl:text>
|
|
||||||
<xsl:choose>
|
|
||||||
<xsl:when test="@id">
|
|
||||||
<xsl:value-of select="@id"/>
|
|
||||||
</xsl:when>
|
|
||||||
<xsl:otherwise>
|
|
||||||
<xsl:text>all</xsl:text>
|
|
||||||
</xsl:otherwise>
|
|
||||||
</xsl:choose>
|
|
||||||
<xsl:text>= {{</xsl:text>
|
|
||||||
<xsl:value-of select="string-length(text())*2 + 2"/>
|
|
||||||
<xsl:text>, 3, {'</xsl:text>
|
|
||||||
<xsl:value-of select="substring(text(), 1,1)"/>
|
|
||||||
<xsl:text>'}}, { </xsl:text>
|
|
||||||
<xsl:call-template name="output-UCS2">
|
|
||||||
<xsl:with-param name="string" select="substring(text(), 2)"/>
|
|
||||||
</xsl:call-template>
|
|
||||||
<xsl:text>}}; </xsl:text>
|
|
||||||
</xsl:for-each>
|
|
||||||
|
|
||||||
<!-- string tables -->
|
|
||||||
<xsl:for-each select="/descriptors/languages/lang">
|
|
||||||
<xsl:variable name="id" select="@id"/>
|
|
||||||
<xsl:text>static const struct usb_st_string_descriptor * string_table_</xsl:text>
|
|
||||||
<xsl:value-of select="$id"/>
|
|
||||||
<xsl:text>[] = { </xsl:text>
|
|
||||||
<xsl:for-each select="/descriptors/strings/string">
|
|
||||||
<xsl:text> &string_descriptor_</xsl:text>
|
|
||||||
<xsl:number count="/descriptors/strings/string" format="1"/>
|
|
||||||
<xsl:text>_</xsl:text>
|
|
||||||
<xsl:choose>
|
|
||||||
<xsl:when test="lang[@id = $id]">
|
|
||||||
<xsl:value-of select="$id"/>
|
|
||||||
</xsl:when>
|
|
||||||
<xsl:when test="lang[@id = 'all' or count(@id) = 0]">
|
|
||||||
<xsl:text>all</xsl:text>
|
|
||||||
</xsl:when>
|
|
||||||
<xsl:otherwise>
|
|
||||||
<xsl:message terminate="yes">
|
|
||||||
<xsl:text>No string found for index </xsl:text>
|
|
||||||
<xsl:number count="/descriptors/strings/string" format="1"/>
|
|
||||||
<xsl:text> and language </xsl:text>
|
|
||||||
<xsl:value-of select="$id"/>
|
|
||||||
</xsl:message>
|
|
||||||
</xsl:otherwise>
|
|
||||||
</xsl:choose>
|
|
||||||
<xsl:text>.base, </xsl:text>
|
|
||||||
</xsl:for-each>
|
|
||||||
<xsl:text>}; </xsl:text>
|
|
||||||
</xsl:for-each>
|
|
||||||
|
|
||||||
<!-- language descriptor -->
|
|
||||||
<xsl:text>static const struct { </xsl:text>
|
|
||||||
<xsl:text> struct usb_st_language_descriptor base; </xsl:text>
|
|
||||||
<xsl:text> Uint16 langs[</xsl:text>
|
|
||||||
<xsl:value-of select="$num_lang -1"/>
|
|
||||||
<xsl:text>]; </xsl:text>
|
|
||||||
<xsl:text>} language_descriptor = { </xsl:text>
|
|
||||||
<xsl:text> {</xsl:text>
|
|
||||||
<xsl:value-of select="$num_lang*2 + 2"/>
|
|
||||||
<xsl:text>, 3, {</xsl:text>
|
|
||||||
<xsl:value-of select="languages/lang[1]/text()"/>
|
|
||||||
<xsl:text>}}, {</xsl:text>
|
|
||||||
<xsl:for-each select="languages/lang[position() > 1]">
|
|
||||||
<xsl:value-of select="text()"/>
|
|
||||||
<xsl:text>, </xsl:text>
|
|
||||||
</xsl:for-each>
|
|
||||||
<xsl:text>}}; </xsl:text>
|
|
||||||
|
|
||||||
<!-- language lookup table -->
|
|
||||||
<xsl:text>static const struct { </xsl:text>
|
|
||||||
<xsl:text> struct usb_st_string_languages base; </xsl:text>
|
|
||||||
<xsl:text> struct usb_st_string_language_map map[</xsl:text>
|
|
||||||
<xsl:value-of select="$num_lang - 1"/>
|
|
||||||
<xsl:text>]; } </xsl:text>
|
|
||||||
<xsl:text>string_languages_full={{</xsl:text>
|
|
||||||
<xsl:value-of select="$num_lang"/>
|
|
||||||
<xsl:text>, </xsl:text>
|
|
||||||
<xsl:value-of select="count(strings/string)"/>
|
|
||||||
<xsl:text>, &language_descriptor.base</xsl:text>
|
|
||||||
<xsl:text>, {{</xsl:text>
|
|
||||||
<xsl:value-of select="languages/lang[1]/text()"/>
|
|
||||||
<xsl:text>, string_table_</xsl:text>
|
|
||||||
<xsl:value-of select="languages/lang[1]/@id"/>
|
|
||||||
<xsl:text>}}}, { </xsl:text>
|
|
||||||
<xsl:for-each select="languages/lang[position() > 1]">
|
|
||||||
<xsl:text> {</xsl:text>
|
|
||||||
<xsl:value-of select="text()"/>
|
|
||||||
<xsl:text>, string_table_</xsl:text>
|
|
||||||
<xsl:value-of select="@id"/>
|
|
||||||
<xsl:text>}, </xsl:text>
|
|
||||||
</xsl:for-each>
|
|
||||||
<xsl:text> } }; </xsl:text>
|
|
||||||
<xsl:text>const struct usb_st_string_languages * const string_languages = &string_languages_full.base; </xsl:text>
|
|
||||||
</xsl:template>
|
|
||||||
|
|
||||||
<xsl:template name="output-UCS2">
|
|
||||||
<xsl:param name="string"/>
|
|
||||||
<xsl:if test="string-length($string) > 0">
|
|
||||||
<xsl:text>'</xsl:text>
|
|
||||||
<xsl:value-of select="substring($string, 1,1)"/>
|
|
||||||
<xsl:text>'</xsl:text>
|
|
||||||
<xsl:if test="string-length($string) > 1">
|
|
||||||
<xsl:text>, </xsl:text>
|
|
||||||
</xsl:if>
|
|
||||||
<xsl:call-template name="output-UCS2">
|
|
||||||
<xsl:with-param name="string" select="substring($string, 2)"/>
|
|
||||||
</xsl:call-template>
|
|
||||||
</xsl:if>
|
|
||||||
</xsl:template>
|
|
||||||
</xsl:stylesheet>
|
|
||||||
|
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
#ifndef __USB_API_H__SYN81IFYBN__
|
|
||||||
#define __USB_API_H__SYN81IFYBN__
|
|
||||||
|
|
||||||
#include <sys/process.h>
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_setup(void);
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_set_user_process(struct process *p);
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_setup_bulk_endpoint(unsigned char addr,
|
|
||||||
unsigned char *buffer, unsigned int buf_size);
|
|
||||||
void
|
|
||||||
usb_setup_interrupt_endpoint(unsigned char addr,
|
|
||||||
unsigned char *buffer, unsigned int buf_size);
|
|
||||||
|
|
||||||
/* Get a pointer to a buffer dat of length lenp.
|
|
||||||
To which USB data can be written. */
|
|
||||||
void
|
|
||||||
usb_send_buffer_get(unsigned char ep_addr, unsigned int offset,
|
|
||||||
unsigned char **dat, unsigned int *lenp);
|
|
||||||
|
|
||||||
/* Notify the USB subsystem that data has been written to the buffer returned
|
|
||||||
by usb_send_buffer_get. */
|
|
||||||
void
|
|
||||||
usb_send_buffer_commit(unsigned char ep_addr, unsigned int len);
|
|
||||||
|
|
||||||
unsigned int
|
|
||||||
usb_send_data(unsigned char ep_addr,
|
|
||||||
const unsigned char *dat, unsigned int len);
|
|
||||||
|
|
||||||
unsigned int
|
|
||||||
usb_recv_data(unsigned char ep_addr, unsigned char *dat, unsigned int len);
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_disable_endpoint(unsigned char addr);
|
|
||||||
|
|
||||||
/* Asynchronous */
|
|
||||||
#define USB_USER_MSG_TYPE_CONFIG 0x01
|
|
||||||
#define USB_USER_MSG_TYPE_SUSPEND 0x02
|
|
||||||
#define USB_USER_MSG_TYPE_RESUME 0x03
|
|
||||||
|
|
||||||
/* Synchronous, the supplied data is only valid during the event */
|
|
||||||
#define USB_USER_MSG_TYPE_EP_OUT(ep_addr) ((((ep_addr) & 0x7f)<<4) | 0x01)
|
|
||||||
#define USB_USER_MSG_TYPE_EP_IN(ep_addr) ((((ep_addr) & 0x7f)<<4) | 0x02)
|
|
||||||
|
|
||||||
struct usb_user_msg {
|
|
||||||
unsigned int type;
|
|
||||||
union {
|
|
||||||
/* For EPx_OUT */
|
|
||||||
unsigned short length;
|
|
||||||
/* For CONFIG */
|
|
||||||
unsigned char config;
|
|
||||||
} data;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* __USB_API_H__SYN81IFYBN__ */
|
|
|
@ -1,16 +0,0 @@
|
||||||
#ifndef __USB_CONFIG_H__LEIURX7H18__
|
|
||||||
#define __USB_CONFIG_H__LEIURX7H18__
|
|
||||||
|
|
||||||
#ifndef CTRL_EP_SIZE
|
|
||||||
#define CTRL_EP_SIZE 8
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef NON_CTRL_XFER_SIZE
|
|
||||||
#define NON_CTRL_XFER_SIZE 64
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef MAX_CTRL_DATA
|
|
||||||
#define MAX_CTRL_DATA 128
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __USB_CONFIG_H__LEIURX7H18__ */
|
|
|
@ -1,424 +0,0 @@
|
||||||
#include <AT91SAM7S64.h>
|
|
||||||
#include <interrupt-utils.h>
|
|
||||||
#include <usb-interrupt.h>
|
|
||||||
#include <usb-proto.h>
|
|
||||||
#include <usb-api.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <sys/process.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <descriptors.h>
|
|
||||||
#include <string-descriptors.h>
|
|
||||||
|
|
||||||
#define USB_PULLUP_PIN AT91C_PIO_PA16
|
|
||||||
|
|
||||||
static unsigned short usb_device_status;
|
|
||||||
static unsigned char usb_configuration_value;
|
|
||||||
|
|
||||||
static struct process * user_process = NULL;
|
|
||||||
|
|
||||||
static struct USBRequestHandlerHook *usb_request_handler_hooks = NULL;
|
|
||||||
|
|
||||||
static const unsigned char zero_byte = 0;
|
|
||||||
static const unsigned short zero_word = 0;
|
|
||||||
|
|
||||||
static void
|
|
||||||
notify_user(struct usb_user_msg* msg)
|
|
||||||
{
|
|
||||||
if (user_process) {
|
|
||||||
process_post(user_process, PROCESS_EVENT_MSG, msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_set_user_process(struct process *p)
|
|
||||||
{
|
|
||||||
user_process = p;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
get_device_descriptor()
|
|
||||||
{
|
|
||||||
usb_send_ctrl_response((unsigned char*)&device_descriptor, sizeof(device_descriptor));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
get_string_descriptor()
|
|
||||||
{
|
|
||||||
if (LOW_BYTE(usb_setup_buffer.wValue) == 0) {
|
|
||||||
usb_send_ctrl_response((const unsigned char*)string_languages->lang_descr,
|
|
||||||
string_languages->lang_descr->bLength);
|
|
||||||
} else {
|
|
||||||
unsigned char l;
|
|
||||||
const struct usb_st_string_descriptor *descriptor;
|
|
||||||
const struct usb_st_string_descriptor * const *table;
|
|
||||||
const struct usb_st_string_language_map *map;
|
|
||||||
if (LOW_BYTE(usb_setup_buffer.wValue) > string_languages->max_index) {
|
|
||||||
usb_error_stall();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
l = string_languages->num_lang;
|
|
||||||
map = string_languages->map;
|
|
||||||
table = map->descriptors; /* Use first table if language not found */
|
|
||||||
while (l > 0) {
|
|
||||||
if (map->lang_id == usb_setup_buffer.wIndex) {
|
|
||||||
table = map->descriptors;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
map++;
|
|
||||||
l--;
|
|
||||||
}
|
|
||||||
printf("Lang id %04x = table %p\n", usb_setup_buffer.wIndex, (void*)table);
|
|
||||||
descriptor = table[LOW_BYTE(usb_setup_buffer.wValue) - 1];
|
|
||||||
usb_send_ctrl_response((const unsigned char*)descriptor,
|
|
||||||
descriptor->bLength);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
get_configuration_descriptor()
|
|
||||||
{
|
|
||||||
usb_send_ctrl_response((unsigned char*)configuration_head,
|
|
||||||
configuration_head->wTotalLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
get_configuration()
|
|
||||||
{
|
|
||||||
usb_send_ctrl_response((unsigned char*)&usb_configuration_value,
|
|
||||||
sizeof(usb_configuration_value));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns true if the configuration value changed */
|
|
||||||
static int
|
|
||||||
set_configuration()
|
|
||||||
{
|
|
||||||
if (usb_configuration_value != LOW_BYTE(usb_setup_buffer.wValue)) {
|
|
||||||
usb_configuration_value = LOW_BYTE(usb_setup_buffer.wValue);
|
|
||||||
if (usb_configuration_value > 0) {
|
|
||||||
*AT91C_UDP_GLBSTATE |= AT91C_UDP_CONFG;
|
|
||||||
} else {
|
|
||||||
*AT91C_UDP_GLBSTATE &= ~AT91C_UDP_CONFG;
|
|
||||||
}
|
|
||||||
usb_send_ctrl_status();
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
usb_send_ctrl_status();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
get_device_status()
|
|
||||||
{
|
|
||||||
puts("get_device_status");
|
|
||||||
usb_send_ctrl_response((const unsigned char*)&usb_device_status,
|
|
||||||
sizeof(usb_device_status));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
get_endpoint_status()
|
|
||||||
{
|
|
||||||
puts("get_endpoint_status");
|
|
||||||
if ((usb_setup_buffer.wIndex & 0x7f) == 0) {
|
|
||||||
usb_send_ctrl_response((const unsigned char*)&zero_word,
|
|
||||||
sizeof(zero_word));
|
|
||||||
} else {
|
|
||||||
volatile USBEndpoint *ec;
|
|
||||||
ec = usb_find_endpoint(usb_setup_buffer.wIndex);
|
|
||||||
if (ec) {
|
|
||||||
usb_send_ctrl_response((const unsigned char*)&ec->status, sizeof(ec->status));
|
|
||||||
} else {
|
|
||||||
usb_error_stall();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
get_interface_status()
|
|
||||||
{
|
|
||||||
puts("get_interface_status");
|
|
||||||
usb_send_ctrl_response((const unsigned char*)&zero_word,
|
|
||||||
sizeof(zero_word));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
get_interface()
|
|
||||||
{
|
|
||||||
puts("get_interface");
|
|
||||||
if (usb_configuration_value == 0) usb_error_stall();
|
|
||||||
else {
|
|
||||||
usb_send_ctrl_response(&zero_byte,
|
|
||||||
sizeof(zero_byte));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct usb_user_msg config_msg = {USB_USER_MSG_TYPE_CONFIG};
|
|
||||||
static struct usb_user_msg io_msg[3];
|
|
||||||
|
|
||||||
static unsigned int
|
|
||||||
handle_standard_requests()
|
|
||||||
{
|
|
||||||
switch(usb_setup_buffer.bmRequestType) {
|
|
||||||
case 0x80: /* standard device IN requests */
|
|
||||||
switch(usb_setup_buffer.bRequest) {
|
|
||||||
case GET_DESCRIPTOR:
|
|
||||||
switch (HIGH_BYTE(usb_setup_buffer.wValue)) {
|
|
||||||
case DEVICE:
|
|
||||||
get_device_descriptor();
|
|
||||||
break;
|
|
||||||
case CONFIGURATION:
|
|
||||||
get_configuration_descriptor();
|
|
||||||
break;
|
|
||||||
case STRING:
|
|
||||||
get_string_descriptor();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* Unknown descriptor */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case GET_CONFIGURATION:
|
|
||||||
get_configuration();
|
|
||||||
break;
|
|
||||||
case GET_STATUS:
|
|
||||||
get_device_status();
|
|
||||||
break;
|
|
||||||
case GET_INTERFACE:
|
|
||||||
get_interface();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x81: /* standard interface IN requests */
|
|
||||||
switch(usb_setup_buffer.bRequest) {
|
|
||||||
case GET_STATUS:
|
|
||||||
get_interface_status();
|
|
||||||
break;
|
|
||||||
#ifdef HID_ENABLED
|
|
||||||
case GET_DESCRIPTOR:
|
|
||||||
switch (USB_setup_buffer.wValue.byte.high) {
|
|
||||||
case REPORT:
|
|
||||||
get_report_descriptor();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x82: /* standard endpoint IN requests */
|
|
||||||
switch(usb_setup_buffer.bRequest) {
|
|
||||||
case GET_STATUS:
|
|
||||||
get_endpoint_status();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x00: /* standard device OUT requests */
|
|
||||||
switch(usb_setup_buffer.bRequest) {
|
|
||||||
case SET_ADDRESS:
|
|
||||||
printf("Address: %d\n", LOW_BYTE(usb_setup_buffer.wValue));
|
|
||||||
usb_set_address();
|
|
||||||
usb_send_ctrl_status();
|
|
||||||
break;
|
|
||||||
#if SETABLE_STRING_DESCRIPTORS > 0
|
|
||||||
case SET_DESCRIPTOR:
|
|
||||||
if (usb_setup_buffer.wValue.byte.high == STRING) {
|
|
||||||
set_string_descriptor();
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
case SET_CONFIGURATION:
|
|
||||||
if (set_configuration()) {
|
|
||||||
config_msg.data.config = LOW_BYTE(usb_setup_buffer.wValue);
|
|
||||||
notify_user(&config_msg);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x02:
|
|
||||||
switch(usb_setup_buffer.bRequest) {
|
|
||||||
case SET_FEATURE:
|
|
||||||
case CLEAR_FEATURE:
|
|
||||||
if (usb_setup_buffer.wValue == ENDPOINT_HALT_FEATURE) {
|
|
||||||
volatile USBEndpoint *ep = usb_find_endpoint(usb_setup_buffer.wIndex);
|
|
||||||
if (ep) {
|
|
||||||
usb_halt_endpoint(ep->addr, usb_setup_buffer.bRequest== SET_FEATURE);
|
|
||||||
usb_send_ctrl_status();
|
|
||||||
} else {
|
|
||||||
usb_error_stall();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
usb_error_stall();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#ifdef HID_ENABLED
|
|
||||||
case 0xa1: /* class specific interface IN request*/
|
|
||||||
switch(USB_setup_buffer.bRequest) {
|
|
||||||
case GET_HID_REPORT:
|
|
||||||
puts("Get report\n");
|
|
||||||
send_ctrl_response((code u_int8_t*)&zero_byte,
|
|
||||||
sizeof(zero_byte));
|
|
||||||
break;
|
|
||||||
case GET_HID_IDLE:
|
|
||||||
puts("Get idle\n");
|
|
||||||
send_ctrl_response((code u_int8_t*)&zero_byte,
|
|
||||||
sizeof(zero_byte));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 0x21: /* class specific interface OUT request*/
|
|
||||||
switch(USB_setup_buffer.bRequest) {
|
|
||||||
case SET_HID_IDLE:
|
|
||||||
puts("Set idle\n");
|
|
||||||
send_ctrl_status();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct USBRequestHandler standard_request_handler =
|
|
||||||
{
|
|
||||||
0x00, 0x60,
|
|
||||||
0x00, 0x00,
|
|
||||||
handle_standard_requests
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct USBRequestHandlerHook standard_request_hook =
|
|
||||||
{
|
|
||||||
NULL,
|
|
||||||
&standard_request_handler
|
|
||||||
};
|
|
||||||
|
|
||||||
PROCESS(usb_process, "USB process");
|
|
||||||
|
|
||||||
PROCESS_THREAD(usb_process, ev , data)
|
|
||||||
{
|
|
||||||
PROCESS_BEGIN();
|
|
||||||
puts("USB process started");
|
|
||||||
while(1) {
|
|
||||||
PROCESS_WAIT_EVENT();
|
|
||||||
if (ev == PROCESS_EVENT_EXIT) break;
|
|
||||||
if (ev == PROCESS_EVENT_POLL) {
|
|
||||||
if (usb_events & USB_EVENT_RESET) {
|
|
||||||
printf("Reset\n");
|
|
||||||
usb_clear_events(USB_EVENT_RESET);
|
|
||||||
}
|
|
||||||
if (usb_events & USB_EVENT_EP(0)) {
|
|
||||||
/* puts("Endpoint 0"); */
|
|
||||||
if (usb_endpoint_events[0] & USB_EP_EVENT_SETUP) {
|
|
||||||
struct USBRequestHandlerHook *hook = usb_request_handler_hooks;
|
|
||||||
#if 0
|
|
||||||
puts("Setup");
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
for (i = 0; i< 8; i++) printf(" %02x", ((unsigned char*)&usb_setup_buffer)[i]);
|
|
||||||
putchar('\n');
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
while(hook) {
|
|
||||||
const struct USBRequestHandler *handler = hook->handler;
|
|
||||||
/* Check if the handler matches the request */
|
|
||||||
if (((handler->request_type ^ usb_setup_buffer.bmRequestType)
|
|
||||||
& handler->request_type_mask) == 0
|
|
||||||
&& ((handler->request ^ usb_setup_buffer.bRequest)
|
|
||||||
& handler->request_mask) == 0) {
|
|
||||||
if (handler->handler_func()) break;
|
|
||||||
}
|
|
||||||
hook = hook->next;
|
|
||||||
}
|
|
||||||
if (!hook) {
|
|
||||||
/* No handler found */
|
|
||||||
usb_error_stall();
|
|
||||||
}
|
|
||||||
usb_clear_ep_events(0, USB_EP_EVENT_SETUP);
|
|
||||||
}
|
|
||||||
usb_clear_events(USB_EVENT_EP(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
unsigned int e;
|
|
||||||
for (e = 1; e <= 3; e++) {
|
|
||||||
if (usb_events & USB_EVENT_EP(e)) {
|
|
||||||
if (usb_endpoint_events[e] & (USB_EP_EVENT_OUT|USB_EP_EVENT_IN)) {
|
|
||||||
volatile USBEndpoint *ep = usb_find_endpoint(e);
|
|
||||||
struct usb_user_msg *msg = &io_msg[e-1];
|
|
||||||
if (usb_endpoint_events[e] & USB_EP_EVENT_OUT) {
|
|
||||||
msg->type = USB_USER_MSG_TYPE_EP_OUT(e);
|
|
||||||
msg->data.length = ep->buf_len;
|
|
||||||
} else {
|
|
||||||
msg->type = USB_USER_MSG_TYPE_EP_IN(e);
|
|
||||||
msg->data.length = ep->buf_size_mask + 1 - ep->buf_len;
|
|
||||||
}
|
|
||||||
notify_user(msg);
|
|
||||||
usb_clear_ep_events(e, USB_EP_EVENT_OUT|USB_EP_EVENT_IN);
|
|
||||||
usb_clear_events(USB_EVENT_EP(ep->addr));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PROCESS_END();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_setup(void)
|
|
||||||
{
|
|
||||||
/* Assume 96MHz PLL frequency */
|
|
||||||
*AT91C_CKGR_PLLR = ((*AT91C_CKGR_PLLR & ~AT91C_CKGR_USBDIV)
|
|
||||||
| AT91C_CKGR_USBDIV_1);
|
|
||||||
/* Enable 48MHz USB clock */
|
|
||||||
*AT91C_PMC_SCER = AT91C_PMC_UDP;
|
|
||||||
/* Enable USB main clock */
|
|
||||||
*AT91C_PMC_PCER = (1 << AT91C_ID_UDP);
|
|
||||||
|
|
||||||
/* Enable pullup */
|
|
||||||
*AT91C_PIOA_PER = USB_PULLUP_PIN;
|
|
||||||
*AT91C_PIOA_OER = USB_PULLUP_PIN;
|
|
||||||
*AT91C_PIOA_CODR = USB_PULLUP_PIN;
|
|
||||||
|
|
||||||
usb_register_request_handler(&standard_request_hook);
|
|
||||||
process_start(&usb_process, NULL);
|
|
||||||
usb_handler_process = &usb_process;
|
|
||||||
|
|
||||||
/* Enable usb_interrupt */
|
|
||||||
AT91C_AIC_SMR[AT91C_ID_UDP] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | 4;
|
|
||||||
AT91C_AIC_SVR[AT91C_ID_UDP] = (unsigned long) usb_int;
|
|
||||||
*AT91C_AIC_IECR = (1 << AT91C_ID_UDP);
|
|
||||||
usb_init_endpoints();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_register_request_handler(struct USBRequestHandlerHook *hook)
|
|
||||||
{
|
|
||||||
struct USBRequestHandlerHook **prevp = &usb_request_handler_hooks;
|
|
||||||
/* Find last hook */
|
|
||||||
while(*prevp) {
|
|
||||||
prevp = &(*prevp)->next;
|
|
||||||
}
|
|
||||||
/* Add last */
|
|
||||||
*prevp = hook;
|
|
||||||
hook->next = NULL;
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
#include <AT91SAM7S64.h>
|
|
||||||
#include <interrupt-utils.h>
|
|
||||||
#include <usb-interrupt.h>
|
|
||||||
#include <usb-proto.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
static void
|
|
||||||
usb_int_safe (void) __attribute__((noinline));
|
|
||||||
|
|
||||||
static void
|
|
||||||
usb_int_safe (void)
|
|
||||||
{
|
|
||||||
unsigned int int_status;
|
|
||||||
/* putchar('*'); */
|
|
||||||
int_status = *AT91C_UDP_ISR & *AT91C_UDP_IMR;
|
|
||||||
|
|
||||||
if (int_status & (AT91C_UDP_EP1 | AT91C_UDP_EP2 | AT91C_UDP_EP3)) {
|
|
||||||
usb_epx_int();
|
|
||||||
} else if (int_status & AT91C_UDP_ENDBUSRES) {
|
|
||||||
usb_reset();
|
|
||||||
*AT91C_UDP_ICR = AT91C_UDP_ENDBUSRES;
|
|
||||||
} else if (int_status & AT91C_UDP_RXSUSP) {
|
|
||||||
/* puts("Suspend"); */
|
|
||||||
*AT91C_UDP_ICR = AT91C_UDP_RXSUSP;
|
|
||||||
} else if (int_status & AT91C_UDP_RXRSM) {
|
|
||||||
/* puts("Resume"); */
|
|
||||||
*AT91C_UDP_ICR = AT91C_UDP_RXRSM;
|
|
||||||
} else if (int_status & AT91C_UDP_SOFINT) {
|
|
||||||
/* puts("SOF"); */
|
|
||||||
*AT91C_UDP_ICR = AT91C_UDP_SOFINT;
|
|
||||||
} else if (int_status & AT91C_UDP_WAKEUP) {
|
|
||||||
/* puts("Wakeup"); */
|
|
||||||
*AT91C_UDP_ICR = AT91C_UDP_WAKEUP;
|
|
||||||
} else if (int_status & AT91C_UDP_EP0) {
|
|
||||||
usb_ep0_int();
|
|
||||||
} else {
|
|
||||||
puts("Other USB interrupt");
|
|
||||||
}
|
|
||||||
/* putchar('<'); */
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void NACKEDFUNC
|
|
||||||
usb_int (void)
|
|
||||||
{
|
|
||||||
ISR_STORE();
|
|
||||||
ISR_ENABLE_NEST();
|
|
||||||
usb_int_safe();
|
|
||||||
ISR_DISABLE_NEST();
|
|
||||||
*AT91C_AIC_EOICR = 0;
|
|
||||||
ISR_RESTORE();
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
#ifndef __USB_INTERRUPT_H__Z1DQCUBTAL__
|
|
||||||
#define __USB_INTERRUPT_H__Z1DQCUBTAL__
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_int (void);
|
|
||||||
|
|
||||||
#endif /* __USB_INTERRUPT_H__Z1DQCUBTAL__ */
|
|
|
@ -1,600 +0,0 @@
|
||||||
#include <AT91SAM7S64.h>
|
|
||||||
#include <usb-api.h>
|
|
||||||
#include <usb-proto.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/process.h>
|
|
||||||
#include<interrupt-utils.h>
|
|
||||||
|
|
||||||
#ifndef AT91C_UDP_STALLSENT
|
|
||||||
#define AT91C_UDP_STALLSENT AT91C_UDP_ISOERROR
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Bits that won't effect the state if they're written at a specific level.
|
|
||||||
*/
|
|
||||||
/* Bits that should be written as 1 */
|
|
||||||
#define NO_EFFECT_BITS (AT91C_UDP_TXCOMP | AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RXSETUP \
|
|
||||||
| AT91C_UDP_ISOERROR | AT91C_UDP_RX_DATA_BK1)
|
|
||||||
/* Also includes bits that should be written as 0 */
|
|
||||||
#define NO_EFFECT_MASK (NO_EFFECT_BITS | AT91C_UDP_TXPKTRDY)
|
|
||||||
|
|
||||||
#define RXBYTECNT(s) (((s)>>16)&0x7ff)
|
|
||||||
|
|
||||||
/* Index in endpoint array */
|
|
||||||
#define EP_INDEX(addr) (((addr) & 0x7f) - 1)
|
|
||||||
/* Number of hardware endpoint */
|
|
||||||
#define EP_HW_NUM(addr) ((addr) & 0x7f)
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
udp_set_ep_ctrl_flags(AT91_REG *reg, unsigned int flags,
|
|
||||||
unsigned int write_mask, unsigned int check_mask)
|
|
||||||
{
|
|
||||||
while ( (*reg & check_mask) != (flags & check_mask)) {
|
|
||||||
*reg = (*reg & ~write_mask) | flags;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define UDP_SET_EP_CTRL_FLAGS(reg, flags, mask) \
|
|
||||||
udp_set_ep_ctrl_flags((reg), \
|
|
||||||
(NO_EFFECT_BITS & ~(mask)) | ((flags) & (mask)), (mask) | NO_EFFECT_MASK,\
|
|
||||||
(mask))
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_error_stall()
|
|
||||||
{
|
|
||||||
/* Disable all USB events */
|
|
||||||
*AT91C_AIC_IDCR = (1 << AT91C_ID_UDP);
|
|
||||||
/* Set stall state */
|
|
||||||
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[0],
|
|
||||||
AT91C_UDP_FORCESTALL, AT91C_UDP_FORCESTALL);
|
|
||||||
/* Reenable interrupt */
|
|
||||||
*AT91C_AIC_IECR = (1 << AT91C_ID_UDP);
|
|
||||||
puts("Stalled");
|
|
||||||
}
|
|
||||||
|
|
||||||
volatile unsigned char usb_events = 0;
|
|
||||||
struct process *usb_handler_process = NULL;
|
|
||||||
|
|
||||||
#define NUM_EP 4
|
|
||||||
volatile unsigned char usb_endpoint_events[NUM_EP] = {0,0,0,0};
|
|
||||||
static volatile USBEndpoint usb_endpoints[NUM_EP - 1];
|
|
||||||
|
|
||||||
volatile unsigned char usb_flags = 0;
|
|
||||||
#define USB_FLAG_ADDRESS_PENDING 0x01
|
|
||||||
#define USB_FLAG_RECEIVING_CTRL 0x04
|
|
||||||
#define USB_FLAG_SEND_ZLP 0x08 /* If the last packet has max length,
|
|
||||||
then it needs to be followed by a
|
|
||||||
zero length packet to mark the
|
|
||||||
end. */
|
|
||||||
|
|
||||||
static unsigned short usb_ctrl_send_len = 0;
|
|
||||||
static const unsigned char *usb_ctrl_send_pos = NULL;
|
|
||||||
|
|
||||||
unsigned char usb_ctrl_data_buffer[MAX_CTRL_DATA];
|
|
||||||
unsigned short usb_ctrl_data_len = 0;
|
|
||||||
|
|
||||||
static void
|
|
||||||
write_endpoint(unsigned int hw_ep,
|
|
||||||
const unsigned char *buffer, unsigned short len)
|
|
||||||
{
|
|
||||||
AT91_REG *fdr = &AT91C_UDP_FDR[hw_ep];
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
unsigned int i;
|
|
||||||
printf("Sending: ");
|
|
||||||
for (i = 0; i< len; i++) printf(" %02x", buffer[i]);
|
|
||||||
putchar('\n');
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
while(len > 0) {
|
|
||||||
*fdr = *buffer++;
|
|
||||||
len--;
|
|
||||||
}
|
|
||||||
/* Start transmission */
|
|
||||||
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[hw_ep],
|
|
||||||
AT91C_UDP_TXPKTRDY, AT91C_UDP_TXPKTRDY);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
write_ctrl()
|
|
||||||
{
|
|
||||||
if (usb_ctrl_send_pos) {
|
|
||||||
unsigned int xfer_len = usb_ctrl_send_len;
|
|
||||||
/* Check if FIFO is ready */
|
|
||||||
if (AT91C_UDP_CSR[0] & AT91C_UDP_TXPKTRDY) return;
|
|
||||||
if (xfer_len > CTRL_EP_SIZE) xfer_len = CTRL_EP_SIZE;
|
|
||||||
write_endpoint(0, usb_ctrl_send_pos, xfer_len);
|
|
||||||
if (xfer_len < CTRL_EP_SIZE) {
|
|
||||||
/* Last packet, stop sending */
|
|
||||||
usb_ctrl_send_pos = NULL;
|
|
||||||
} else {
|
|
||||||
usb_ctrl_send_pos += xfer_len;
|
|
||||||
usb_ctrl_send_len -= xfer_len;
|
|
||||||
if (usb_ctrl_send_len == 0 && !(usb_flags & USB_FLAG_SEND_ZLP)) {
|
|
||||||
usb_ctrl_send_pos = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned char
|
|
||||||
read_buffered_endpoint(volatile USBEndpoint *ep)
|
|
||||||
{
|
|
||||||
unsigned char len;
|
|
||||||
unsigned char mask = ep->buf_size_mask;
|
|
||||||
unsigned char *buffer = ep->buffer;
|
|
||||||
unsigned char pos = (ep->buf_pos + ep->buf_len) & mask;
|
|
||||||
AT91_REG *fdr = &AT91C_UDP_FDR[EP_HW_NUM(ep->addr)];
|
|
||||||
len = RXBYTECNT(AT91C_UDP_CSR[EP_HW_NUM(ep->addr)]);
|
|
||||||
if (mask + 1 - ep->buf_len < len) return 0;
|
|
||||||
ep->buf_len += len;
|
|
||||||
while(len-- > 0) {
|
|
||||||
buffer[pos] = *fdr;
|
|
||||||
pos = (pos + 1) & mask;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int
|
|
||||||
usb_recv_data(unsigned char ep_addr, unsigned char *dat, unsigned int len)
|
|
||||||
{
|
|
||||||
volatile USBEndpoint *ep = &usb_endpoints[EP_INDEX(ep_addr)];
|
|
||||||
unsigned char mask = ep->buf_size_mask;
|
|
||||||
*AT91C_UDP_IDR = 1<<EP_HW_NUM(ep_addr);
|
|
||||||
{
|
|
||||||
unsigned char l;
|
|
||||||
unsigned char *to = ep->buffer;
|
|
||||||
unsigned char pos = ep->buf_pos;
|
|
||||||
if (ep->buf_len < len) len = ep->buf_len;
|
|
||||||
ep->buf_len -= len;
|
|
||||||
l = len;
|
|
||||||
while(l-- > 0) {
|
|
||||||
*dat++ = to[pos];
|
|
||||||
pos = (pos + 1) & mask;
|
|
||||||
}
|
|
||||||
ep->buf_pos = pos;
|
|
||||||
}
|
|
||||||
ep->flags &= ~USB_EP_FLAGS_RECV_BLOCKED;
|
|
||||||
*AT91C_UDP_IER = 1<<EP_HW_NUM(ep_addr);
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
write_buffered_endpoint(volatile USBEndpoint *ep)
|
|
||||||
{
|
|
||||||
unsigned int irq = disableIRQ();
|
|
||||||
{
|
|
||||||
unsigned int pos = ep->buf_pos;
|
|
||||||
unsigned int xfer_len = ep->buf_len;
|
|
||||||
unsigned int mask = ep->buf_size_mask;
|
|
||||||
const unsigned char *buf_tmp = ep->buffer;
|
|
||||||
AT91_REG *fdr = &AT91C_UDP_FDR[EP_HW_NUM(ep->addr)];
|
|
||||||
if (!(ep->flags & USB_EP_FLAGS_TRANSMITTING)
|
|
||||||
&& !(AT91C_UDP_CSR[EP_HW_NUM(ep->addr)] & AT91C_UDP_TXPKTRDY)) {
|
|
||||||
if (xfer_len > NON_CTRL_XFER_SIZE) xfer_len = NON_CTRL_XFER_SIZE;
|
|
||||||
ep->buf_len -= xfer_len;
|
|
||||||
/* printf("Writing %d to 0x%02x\n", xfer_len, ep->addr); */
|
|
||||||
while(xfer_len > 0) {
|
|
||||||
*fdr = buf_tmp[pos];
|
|
||||||
pos = (pos + 1) & mask;
|
|
||||||
xfer_len--;
|
|
||||||
}
|
|
||||||
|
|
||||||
ep->flags |= USB_EP_FLAGS_TRANSMITTING;
|
|
||||||
/* Start transmission */
|
|
||||||
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[EP_HW_NUM(ep->addr)],
|
|
||||||
AT91C_UDP_TXPKTRDY, AT91C_UDP_TXPKTRDY);
|
|
||||||
ep->buf_pos = pos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
restoreIRQ(irq);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
write_send_buffer(unsigned char *buffer, const unsigned char *dat,
|
|
||||||
unsigned int len)
|
|
||||||
{
|
|
||||||
while(len-- > 0) {
|
|
||||||
*buffer++ = *dat++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_send_buffer_get(unsigned char ep_addr, unsigned int offset,
|
|
||||||
unsigned char **dat, unsigned int *lenp)
|
|
||||||
{
|
|
||||||
unsigned int pos;
|
|
||||||
volatile USBEndpoint *ep = &usb_endpoints[EP_INDEX(ep_addr)];
|
|
||||||
unsigned int size = ep->buf_size_mask + 1;
|
|
||||||
unsigned int len;
|
|
||||||
*AT91C_UDP_IDR = 1<<EP_HW_NUM(ep_addr);
|
|
||||||
len = size - ep->buf_len;
|
|
||||||
pos = (ep->buf_pos + offset + ep->buf_len) & (size - 1);
|
|
||||||
*AT91C_UDP_IER = 1<<EP_HW_NUM(ep_addr);
|
|
||||||
if (offset >= len) {
|
|
||||||
len = 0;
|
|
||||||
} else {
|
|
||||||
len -= offset;
|
|
||||||
}
|
|
||||||
if (pos + len > size) len = size - pos;
|
|
||||||
*dat = &ep->buffer[pos];
|
|
||||||
*lenp = len;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_send_buffer_commit(unsigned char ep_addr, unsigned int len)
|
|
||||||
{
|
|
||||||
volatile USBEndpoint *ep = &usb_endpoints[EP_INDEX(ep_addr)];
|
|
||||||
*AT91C_UDP_IDR = 1<<EP_HW_NUM(ep_addr);
|
|
||||||
ep->buf_len += len;
|
|
||||||
write_buffered_endpoint(ep);
|
|
||||||
*AT91C_UDP_IER = 1<<EP_HW_NUM(ep_addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int
|
|
||||||
usb_send_data(unsigned char ep_addr, const unsigned char *dat, unsigned int len)
|
|
||||||
{
|
|
||||||
unsigned char *write_pos;
|
|
||||||
unsigned int write_len;
|
|
||||||
unsigned int full_len = len;
|
|
||||||
/* printf("usb_send_data %02x: IMR=%08x\n",ep_addr, *AT91C_UDP_IMR); */
|
|
||||||
while(len > 0) {
|
|
||||||
usb_send_buffer_get(ep_addr, 0, &write_pos, &write_len);
|
|
||||||
if (write_len == 0) break;
|
|
||||||
if (write_len > len) write_len = len;
|
|
||||||
write_send_buffer(write_pos, dat, write_len);
|
|
||||||
/* printf("Pos: %p, len %d\n", write_pos, write_len); */
|
|
||||||
usb_send_buffer_commit(ep_addr, write_len);
|
|
||||||
dat += write_len;
|
|
||||||
len -= write_len;
|
|
||||||
}
|
|
||||||
return full_len - len;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_send_ctrl_response(const unsigned char *buffer, unsigned short len)
|
|
||||||
{
|
|
||||||
if (AT91C_UDP_CSR[0] & AT91C_UDP_TXPKTRDY) return;
|
|
||||||
*AT91C_UDP_IDR = AT91C_UDP_EP0;
|
|
||||||
if (len >= usb_setup_buffer.wLength) {
|
|
||||||
len = usb_setup_buffer.wLength; /* Truncate if too long */
|
|
||||||
usb_flags &= ~USB_FLAG_SEND_ZLP;
|
|
||||||
} else {
|
|
||||||
/* Send ZLP if the response is shorter than requested */
|
|
||||||
usb_flags |= USB_FLAG_SEND_ZLP;
|
|
||||||
}
|
|
||||||
usb_ctrl_send_pos = buffer;
|
|
||||||
usb_ctrl_send_len = len;
|
|
||||||
write_ctrl();
|
|
||||||
*AT91C_UDP_IER = AT91C_UDP_EP0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_send_ctrl_status()
|
|
||||||
{
|
|
||||||
*AT91C_UDP_IDR = AT91C_UDP_EP0;
|
|
||||||
/* Start transmission */
|
|
||||||
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[0],
|
|
||||||
AT91C_UDP_TXPKTRDY, AT91C_UDP_TXPKTRDY);
|
|
||||||
*AT91C_UDP_IER = AT91C_UDP_EP0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
notify_process(unsigned char events)
|
|
||||||
{
|
|
||||||
usb_events |= events;
|
|
||||||
if (usb_handler_process) {
|
|
||||||
process_poll(usb_handler_process);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_reset()
|
|
||||||
{
|
|
||||||
/* Setup endpoint 0 */
|
|
||||||
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[0],
|
|
||||||
AT91C_UDP_EPTYPE_CTRL | AT91C_UDP_EPEDS,
|
|
||||||
AT91C_UDP_EPTYPE | AT91C_UDP_EPEDS);
|
|
||||||
|
|
||||||
/* Enable interrupt for control endpoint */
|
|
||||||
*AT91C_UDP_IER = AT91C_UDP_EP0;
|
|
||||||
notify_process(USB_EVENT_RESET);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct USB_request_st usb_setup_buffer;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
read_fifo0(unsigned char *buffer, unsigned int length)
|
|
||||||
{
|
|
||||||
unsigned int r;
|
|
||||||
for (r = 0; r < length; r++) {
|
|
||||||
*buffer++ = AT91C_UDP_FDR[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_ep0_int()
|
|
||||||
{
|
|
||||||
unsigned int status;
|
|
||||||
status = AT91C_UDP_CSR[0];
|
|
||||||
#if 0
|
|
||||||
printf("status: %08x\n", status);
|
|
||||||
#endif
|
|
||||||
if (status & AT91C_UDP_STALLSENT) {
|
|
||||||
/* Acknowledge */
|
|
||||||
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[0],0, AT91C_UDP_STALLSENT);
|
|
||||||
}
|
|
||||||
if (status & AT91C_UDP_RXSETUP) {
|
|
||||||
usb_ctrl_send_pos = NULL; /* Cancel any pending control data
|
|
||||||
transmission */
|
|
||||||
if (RXBYTECNT(status) == 8) {
|
|
||||||
read_fifo0((unsigned char*)&usb_setup_buffer, 8);
|
|
||||||
|
|
||||||
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[0],
|
|
||||||
((usb_setup_buffer.bmRequestType & 0x80)
|
|
||||||
? AT91C_UDP_DIR : 0),
|
|
||||||
AT91C_UDP_DIR);
|
|
||||||
usb_ctrl_data_len = 0;
|
|
||||||
if ((usb_setup_buffer.bmRequestType & 0x80) != 0
|
|
||||||
|| usb_setup_buffer.wLength == 0) {
|
|
||||||
usb_endpoint_events[0] |= USB_EP_EVENT_SETUP;
|
|
||||||
notify_process(USB_EVENT_EP(0));
|
|
||||||
} else {
|
|
||||||
if (usb_setup_buffer.wLength > MAX_CTRL_DATA) {
|
|
||||||
/* stall */
|
|
||||||
usb_error_stall();
|
|
||||||
} else {
|
|
||||||
usb_flags |= USB_FLAG_RECEIVING_CTRL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
usb_error_stall();
|
|
||||||
}
|
|
||||||
/* Acknowledge SETUP */
|
|
||||||
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[0],0, AT91C_UDP_RXSETUP);
|
|
||||||
} else if (status & (AT91C_UDP_RX_DATA_BK1 | AT91C_UDP_RX_DATA_BK0)) {
|
|
||||||
puts("IN");
|
|
||||||
if (usb_flags & USB_FLAG_RECEIVING_CTRL) {
|
|
||||||
unsigned int len;
|
|
||||||
unsigned int left = MAX_CTRL_DATA - usb_ctrl_data_len;
|
|
||||||
len = RXBYTECNT(status);
|
|
||||||
if (len > left) {
|
|
||||||
/* stall */
|
|
||||||
usb_error_stall();
|
|
||||||
} else {
|
|
||||||
unsigned char *buf_tmp = usb_ctrl_data_buffer + usb_ctrl_data_len;
|
|
||||||
usb_ctrl_data_len += len;
|
|
||||||
if (usb_ctrl_data_len == usb_setup_buffer.wLength
|
|
||||||
|| len < CTRL_EP_SIZE) {
|
|
||||||
usb_flags &= ~USB_FLAG_RECEIVING_CTRL;
|
|
||||||
usb_endpoint_events[0] |= USB_EP_EVENT_SETUP;
|
|
||||||
notify_process(USB_EVENT_EP(0));
|
|
||||||
}
|
|
||||||
while(len-- > 0) *buf_tmp++ = AT91C_UDP_FDR[0];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (RXBYTECNT(status) > 0) {
|
|
||||||
puts("Discarded input");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[0],0,
|
|
||||||
AT91C_UDP_RX_DATA_BK1 | AT91C_UDP_RX_DATA_BK0);
|
|
||||||
}
|
|
||||||
if (status & AT91C_UDP_TXCOMP) {
|
|
||||||
/* puts("TX complete"); */
|
|
||||||
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[0],0, AT91C_UDP_TXCOMP);
|
|
||||||
if (usb_flags & USB_FLAG_ADDRESS_PENDING) {
|
|
||||||
*AT91C_UDP_FADDR = AT91C_UDP_FEN | LOW_BYTE(usb_setup_buffer.wValue);
|
|
||||||
*AT91C_UDP_GLBSTATE |= AT91C_UDP_FADDEN;
|
|
||||||
usb_flags &= ~USB_FLAG_ADDRESS_PENDING;
|
|
||||||
printf("Address changed: %d\n", *AT91C_UDP_FADDR & 0x7f);
|
|
||||||
} else {
|
|
||||||
if(usb_ctrl_send_pos) {
|
|
||||||
write_ctrl();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_epx_int()
|
|
||||||
{
|
|
||||||
unsigned int ep_index;
|
|
||||||
/* Handle enabled interrupts */
|
|
||||||
unsigned int int_status = *AT91C_UDP_ISR & *AT91C_UDP_IMR;
|
|
||||||
for (ep_index = 0; ep_index < NUM_EP-1; ep_index++) {
|
|
||||||
volatile USBEndpoint *ep = &usb_endpoints[ep_index];
|
|
||||||
unsigned int ep_num = EP_HW_NUM(ep->addr);
|
|
||||||
unsigned int ep_mask;
|
|
||||||
if (ep->addr != 0) { /* skip if not configured */
|
|
||||||
ep_mask = 1<<ep_num;
|
|
||||||
if (int_status & ep_mask) {
|
|
||||||
unsigned int status;
|
|
||||||
status = AT91C_UDP_CSR[ep_num];
|
|
||||||
#if 0
|
|
||||||
printf("EP %d status: %08x\n", ep->addr, status);
|
|
||||||
#endif
|
|
||||||
if (status & AT91C_UDP_STALLSENT) {
|
|
||||||
/* Acknowledge */
|
|
||||||
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[ep_num],0, AT91C_UDP_STALLSENT);
|
|
||||||
}
|
|
||||||
if (status & AT91C_UDP_TXCOMP) {
|
|
||||||
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[ep_num],0, AT91C_UDP_TXCOMP);
|
|
||||||
ep->flags &= ~USB_EP_FLAGS_TRANSMITTING;
|
|
||||||
if (ep->buf_len > 0) {
|
|
||||||
write_buffered_endpoint(ep);
|
|
||||||
/* Tell the application that there's more room in the buffer */
|
|
||||||
usb_endpoint_events[ep_num] |= USB_EP_EVENT_IN;
|
|
||||||
notify_process(USB_EVENT_EP(ep_num));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (status & (AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1)) {
|
|
||||||
unsigned char read_cnt;
|
|
||||||
read_cnt = read_buffered_endpoint(ep);
|
|
||||||
if (read_cnt == 0) {
|
|
||||||
*AT91C_UDP_IDR = 1<<ep_num;
|
|
||||||
ep->flags |= USB_EP_FLAGS_RECV_BLOCKED;
|
|
||||||
} else {
|
|
||||||
if (status & AT91C_UDP_RX_DATA_BK1) {
|
|
||||||
/* Ping-pong */
|
|
||||||
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[ep_num],0,
|
|
||||||
(ep->flags & USB_EP_FLAGS_BANK_1_RECV_NEXT)
|
|
||||||
? AT91C_UDP_RX_DATA_BK1
|
|
||||||
: AT91C_UDP_RX_DATA_BK0);
|
|
||||||
ep->flags ^= USB_EP_FLAGS_BANK_1_RECV_NEXT;
|
|
||||||
} else {
|
|
||||||
/* Ping-pong or single buffer */
|
|
||||||
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[ep_num],0,
|
|
||||||
AT91C_UDP_RX_DATA_BK0);
|
|
||||||
ep->flags |= USB_EP_FLAGS_BANK_1_RECV_NEXT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
usb_endpoint_events[ep_num] |= USB_EP_EVENT_OUT;
|
|
||||||
notify_process(ep_mask);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Clear usb events from non-interrupt code */
|
|
||||||
void
|
|
||||||
usb_clear_events(unsigned events)
|
|
||||||
{
|
|
||||||
/* Disable allUSB events */
|
|
||||||
*AT91C_AIC_IDCR = (1 << AT91C_ID_UDP);
|
|
||||||
usb_events &= ~events;
|
|
||||||
/* Reenable interrupt */
|
|
||||||
*AT91C_AIC_IECR = (1 << AT91C_ID_UDP);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_clear_ep_events(unsigned int ep, unsigned int events)
|
|
||||||
{
|
|
||||||
/* Disable all USB events */
|
|
||||||
*AT91C_AIC_IDCR = (1 << AT91C_ID_UDP);
|
|
||||||
usb_endpoint_events[ep] &= ~events;
|
|
||||||
/* Reenable interrupt */
|
|
||||||
*AT91C_AIC_IECR = (1 << AT91C_ID_UDP);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_set_address()
|
|
||||||
{
|
|
||||||
usb_flags |= USB_FLAG_ADDRESS_PENDING;
|
|
||||||
/* The actual setting of the address is done when the status packet
|
|
||||||
is sent. */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
setup_endpoint(unsigned char addr,
|
|
||||||
unsigned char *buffer, unsigned int buf_size,
|
|
||||||
unsigned int type)
|
|
||||||
{
|
|
||||||
volatile USBEndpoint *ep;
|
|
||||||
/* Check if the address points to an existing endpoint */
|
|
||||||
if (EP_INDEX(addr) >= (sizeof(usb_endpoints)/sizeof(usb_endpoints[0]))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ep = &usb_endpoints[EP_INDEX(addr)];
|
|
||||||
ep->addr = addr;
|
|
||||||
ep->buf_size_mask = buf_size - 1;
|
|
||||||
ep->buffer = buffer;
|
|
||||||
ep->buf_len = 0;
|
|
||||||
ep->buf_pos = 0;
|
|
||||||
ep->status = 0;
|
|
||||||
*AT91C_UDP_IDR = 1<<EP_HW_NUM(addr);
|
|
||||||
{
|
|
||||||
unsigned int ep_num = EP_HW_NUM(addr);
|
|
||||||
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[ep_num],
|
|
||||||
type | AT91C_UDP_EPEDS,
|
|
||||||
AT91C_UDP_EPTYPE | AT91C_UDP_EPEDS);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
*AT91C_UDP_IER = 1<<EP_HW_NUM(addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_setup_bulk_endpoint(unsigned char addr,
|
|
||||||
unsigned char *buffer, unsigned int buf_size)
|
|
||||||
{
|
|
||||||
setup_endpoint(addr, buffer, buf_size,
|
|
||||||
(addr & 0x80) ? AT91C_UDP_EPTYPE_BULK_IN
|
|
||||||
:AT91C_UDP_EPTYPE_BULK_OUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_setup_interrupt_endpoint(unsigned char addr,
|
|
||||||
unsigned char *buffer, unsigned int buf_size)
|
|
||||||
{
|
|
||||||
setup_endpoint(addr, buffer, buf_size,
|
|
||||||
(addr & 0x80) ? AT91C_UDP_EPTYPE_INT_IN
|
|
||||||
:AT91C_UDP_EPTYPE_INT_OUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_disable_endpoint(unsigned char addr)
|
|
||||||
{
|
|
||||||
/* Check if the address points to an existing endpoint */
|
|
||||||
if (EP_INDEX(addr) >= (sizeof(usb_endpoints)/sizeof(usb_endpoints[0]))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
*AT91C_UDP_IDR = 1<<EP_HW_NUM(addr);
|
|
||||||
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[EP_HW_NUM(addr)], 0, AT91C_UDP_EPEDS);
|
|
||||||
usb_endpoints[EP_INDEX(addr)].addr = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
init_ep(volatile USBEndpoint *ctxt)
|
|
||||||
{
|
|
||||||
ctxt->addr = 0;
|
|
||||||
ctxt->buf_size_mask = 0;
|
|
||||||
ctxt->buf_len = 0;
|
|
||||||
ctxt->buf_pos = 0;
|
|
||||||
ctxt->buffer = 0;
|
|
||||||
ctxt->status = 0;
|
|
||||||
ctxt->flags = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_init_endpoints()
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
for (i = 0; i < NUM_EP-1; i++) {
|
|
||||||
init_ep(&usb_endpoints[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
volatile USBEndpoint*
|
|
||||||
usb_find_endpoint(unsigned char epaddr)
|
|
||||||
{
|
|
||||||
if (EP_INDEX(epaddr) >= NUM_EP - 1) return 0;
|
|
||||||
return &usb_endpoints[EP_INDEX(epaddr)];
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_halt_endpoint(unsigned char ep_addr, unsigned int halt)
|
|
||||||
{
|
|
||||||
*AT91C_UDP_IDR = 1<<EP_HW_NUM(ep_addr);
|
|
||||||
if (halt) {
|
|
||||||
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[EP_HW_NUM(ep_addr)],
|
|
||||||
AT91C_UDP_FORCESTALL, AT91C_UDP_FORCESTALL);
|
|
||||||
usb_endpoints[EP_INDEX(ep_addr)].status |= 0x01;
|
|
||||||
} else {
|
|
||||||
*AT91C_UDP_RSTEP = 1<<EP_HW_NUM(ep_addr);
|
|
||||||
usb_endpoints[EP_INDEX(ep_addr)].status &= ~0x01;
|
|
||||||
}
|
|
||||||
*AT91C_UDP_IER = 1<<EP_HW_NUM(ep_addr);
|
|
||||||
}
|
|
|
@ -1,118 +0,0 @@
|
||||||
#ifndef __USB_PROTO_H__RVJQ2JAGM4__
|
|
||||||
#define __USB_PROTO_H__RVJQ2JAGM4__
|
|
||||||
|
|
||||||
#include <usb.h>
|
|
||||||
#include <usb-config.h>
|
|
||||||
|
|
||||||
#ifndef NULL
|
|
||||||
#define NULL 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct _USBEndpoint USBEndpoint;
|
|
||||||
struct _USBEndpoint
|
|
||||||
{
|
|
||||||
unsigned char addr;
|
|
||||||
unsigned char buf_size_mask; /* mask for the buffer index. This implies
|
|
||||||
that the buffer size must be a power of
|
|
||||||
2 */
|
|
||||||
unsigned char buf_len;
|
|
||||||
unsigned char buf_pos;
|
|
||||||
unsigned char* buffer;
|
|
||||||
unsigned short status;
|
|
||||||
unsigned short flags;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define USB_EP_FLAGS_BANK_1_RECV_NEXT 0x01 /* The next packet received
|
|
||||||
should be read from bank 1
|
|
||||||
if possible */
|
|
||||||
|
|
||||||
#define USB_EP_FLAGS_RECV_BLOCKED 0x02 /* Recetpion is blocked.
|
|
||||||
Interrupt turned off */
|
|
||||||
|
|
||||||
#define USB_EP_FLAGS_TRANSMITTING 0x04 /* Waiting for TXCOMP before sending
|
|
||||||
more data */
|
|
||||||
|
|
||||||
/* Read only */
|
|
||||||
struct USBRequestHandler
|
|
||||||
{
|
|
||||||
unsigned char request_type;
|
|
||||||
unsigned char request_type_mask;
|
|
||||||
unsigned char request;
|
|
||||||
unsigned char request_mask;
|
|
||||||
/* Returns true if it handled the request, if false let another handler try*/
|
|
||||||
unsigned int (*handler_func)();
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Must be writeable */
|
|
||||||
struct USBRequestHandlerHook
|
|
||||||
{
|
|
||||||
struct USBRequestHandlerHook *next;
|
|
||||||
const struct USBRequestHandler * const handler;
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_register_request_handler(struct USBRequestHandlerHook *hook);
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_reset();
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_ep0_int();
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_epx_int();
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_clear_events(unsigned events);
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_clear_ep_events(unsigned int ep, unsigned int events);
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_error_stall();
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_send_ctrl_response(const unsigned char *buffer, unsigned short len);
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_send_ctrl_status();
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_set_address();
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_set_configuration_value(unsigned char c);
|
|
||||||
|
|
||||||
unsigned char
|
|
||||||
usb_get_configuration_value();
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_init_endpoints();
|
|
||||||
|
|
||||||
volatile USBEndpoint*
|
|
||||||
usb_find_endpoint(unsigned char epaddr);
|
|
||||||
|
|
||||||
void
|
|
||||||
usb_halt_endpoint(unsigned char ep_addr, unsigned int halt);
|
|
||||||
|
|
||||||
extern volatile unsigned char usb_events;
|
|
||||||
extern struct process *usb_handler_process;
|
|
||||||
extern struct USB_request_st usb_setup_buffer;
|
|
||||||
|
|
||||||
extern unsigned char usb_ctrl_data_buffer[];
|
|
||||||
extern unsigned short usb_ctrl_data_len;
|
|
||||||
|
|
||||||
#define USB_EVENT_EP(ep) (0x01<<(ep))
|
|
||||||
#define USB_EVENT_RESET 0x10
|
|
||||||
#define USB_EVENT_SUPEND 0x20
|
|
||||||
#define USB_EVENT_RESUME 0x40
|
|
||||||
#define USB_EVENT_CONFIG 0x08
|
|
||||||
|
|
||||||
extern volatile unsigned char usb_endpoint_events[];
|
|
||||||
|
|
||||||
#define USB_EP_EVENT_SETUP 0x01
|
|
||||||
#define USB_EP_EVENT_OUT 0x02
|
|
||||||
#define USB_EP_EVENT_IN 0x04
|
|
||||||
|
|
||||||
#endif /* __USB_PROTO_H__RVJQ2JAGM4__ */
|
|
|
@ -1,185 +0,0 @@
|
||||||
#ifndef __USB_H__6PFTDPIMZM__
|
|
||||||
#define __USB_H__6PFTDPIMZM__
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
/* Adapted from usb_kbd_enum.h in c5131-usb-kbd-light-1_0_2 package from
|
|
||||||
Atmel */
|
|
||||||
|
|
||||||
/* These definitions assume a little endian architecture */
|
|
||||||
|
|
||||||
#ifdef __GNUC__
|
|
||||||
#define BYTE_ALIGNED __attribute__ ((__packed__))
|
|
||||||
#else
|
|
||||||
#define BYTE_ALIGNED
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define LOW_BYTE(x) ((unsigned char)x)
|
|
||||||
#define HIGH_BYTE(x) ((unsigned char)(x>>8))
|
|
||||||
|
|
||||||
typedef uint8_t Uchar;
|
|
||||||
typedef uint16_t Uint16;
|
|
||||||
typedef uint32_t Uint32;
|
|
||||||
|
|
||||||
/*_____ S T A N D A R D R E Q U E S T S __________________________________*/
|
|
||||||
|
|
||||||
#define GET_STATUS 0x00
|
|
||||||
#define GET_DEVICE 0x01
|
|
||||||
#define CLEAR_FEATURE 0x01 /* see FEATURES below */
|
|
||||||
#define GET_STRING 0x03
|
|
||||||
#define SET_FEATURE 0x03 /* see FEATURES below */
|
|
||||||
#define SET_ADDRESS 0x05
|
|
||||||
#define GET_DESCRIPTOR 0x06
|
|
||||||
#define SET_DESCRIPTOR 0x07
|
|
||||||
#define GET_CONFIGURATION 0x08
|
|
||||||
#define SET_CONFIGURATION 0x09
|
|
||||||
#define GET_INTERFACE 0x0A
|
|
||||||
#define SET_INTERFACE 0x0B
|
|
||||||
#define SYNCH_FRAME 0x0C
|
|
||||||
|
|
||||||
#define GET_DEVICE_DESCRIPTOR 1
|
|
||||||
#define GET_CONFIGURATION_DESCRIPTOR 4
|
|
||||||
|
|
||||||
#define REQUEST_DEVICE_STATUS 0x80
|
|
||||||
#define REQUEST_INTERFACE_STATUS 0x81
|
|
||||||
#define REQUEST_ENDPOINT_STATUS 0x82
|
|
||||||
#define ZERO_TYPE 0x00
|
|
||||||
#define INTERFACE_TYPE 0x01
|
|
||||||
#define ENDPOINT_TYPE 0x02
|
|
||||||
|
|
||||||
/*_____ D E S C R I P T O R T Y P E S ____________________________________*/
|
|
||||||
|
|
||||||
#define DEVICE 0x01
|
|
||||||
#define CONFIGURATION 0x02
|
|
||||||
#define STRING 0x03
|
|
||||||
#define INTERFACE 0x04
|
|
||||||
#define ENDPOINT 0x05
|
|
||||||
|
|
||||||
/* HID specific */
|
|
||||||
#define HID 0x21
|
|
||||||
#define REPORT 0x22
|
|
||||||
/* *** */
|
|
||||||
|
|
||||||
/*_____ S T A N D A R D F E A T U R E S __________________________________*/
|
|
||||||
|
|
||||||
#define DEVICE_REMOTE_WAKEUP_FEATURE 0x01
|
|
||||||
#define ENDPOINT_HALT_FEATURE 0x00
|
|
||||||
|
|
||||||
/*_____ D E V I C E S T A T U S ___________________________________________*/
|
|
||||||
|
|
||||||
#define SELF_POWERED 1
|
|
||||||
|
|
||||||
/*_____ D E V I C E S T A T E _____________________________________________*/
|
|
||||||
|
|
||||||
#define ATTACHED 0
|
|
||||||
#define POWERED 1
|
|
||||||
#define DEFAULT 2
|
|
||||||
#define ADDRESSED 3
|
|
||||||
#define CONFIGURED 4
|
|
||||||
#define SUSPENDED 5
|
|
||||||
|
|
||||||
#define USB_CONFIG_BUSPOWERED 0x80
|
|
||||||
#define USB_CONFIG_SELFPOWERED 0x40
|
|
||||||
#define USB_CONFIG_REMOTEWAKEUP 0x20
|
|
||||||
|
|
||||||
/* Class specific */
|
|
||||||
#define CS_INTERFACE 0x24
|
|
||||||
#define CS_ENDPOINT 0x25
|
|
||||||
|
|
||||||
/*_________________________________________________________ S T R U C T _____*/
|
|
||||||
/*_____ U S B D E V I C E R E Q U E S T _________________________________*/
|
|
||||||
|
|
||||||
struct USB_request_st
|
|
||||||
{
|
|
||||||
Uchar bmRequestType; /* Characteristics of the request */
|
|
||||||
Uchar bRequest; /* Specific request */
|
|
||||||
Uint16 wValue;
|
|
||||||
Uint16 wIndex; /* field that varies according to request */
|
|
||||||
Uint16 wLength; /* Number of bytes to transfer if Data */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*_____ U S B D E V I C E D E S C R I P T O R ___________________________*/
|
|
||||||
|
|
||||||
struct usb_st_device_descriptor
|
|
||||||
{
|
|
||||||
Uchar bLength; /* Size of this descriptor in bytes */
|
|
||||||
Uchar bDescriptorType; /* DEVICE descriptor type */
|
|
||||||
Uint16 bscUSB; /* Binay Coded Decimal Spec. release */
|
|
||||||
Uchar bDeviceClass; /* Class code assigned by the USB */
|
|
||||||
Uchar bDeviceSubClass; /* Sub-class code assigned by the USB */
|
|
||||||
Uchar bDeviceProtocol; /* Protocol code assigned by the USB */
|
|
||||||
Uchar bMaxPacketSize0; /* Max packet size for EP0 */
|
|
||||||
Uint16 idVendor; /* Vendor ID. ATMEL = 0x03EB */
|
|
||||||
Uint16 idProduct; /* Product ID assigned by the manufacturer */
|
|
||||||
Uint16 bcdDevice; /* Device release number */
|
|
||||||
Uchar iManufacturer; /* Index of manu. string descriptor */
|
|
||||||
Uchar iProduct; /* Index of prod. string descriptor */
|
|
||||||
Uchar iSerialNumber; /* Index of S.N. string descriptor */
|
|
||||||
Uchar bNumConfigurations; /* Number of possible configurations */
|
|
||||||
} BYTE_ALIGNED;
|
|
||||||
|
|
||||||
|
|
||||||
/*_____ U S B C O N F I G U R A T I O N D E S C R I P T O R _____________*/
|
|
||||||
|
|
||||||
struct usb_st_configuration_descriptor
|
|
||||||
{
|
|
||||||
Uchar bLength; /* size of this descriptor in bytes */
|
|
||||||
Uchar bDescriptorType; /* CONFIGURATION descriptor type */
|
|
||||||
Uint16 wTotalLength; /* total length of data returned */
|
|
||||||
Uchar bNumInterfaces; /* number of interfaces for this conf. */
|
|
||||||
Uchar bConfigurationValue; /* value for SetConfiguration resquest */
|
|
||||||
Uchar iConfiguration; /* index of string descriptor */
|
|
||||||
Uchar bmAttibutes; /* Configuration characteristics */
|
|
||||||
Uchar MaxPower; /* maximum power consumption */
|
|
||||||
} BYTE_ALIGNED;
|
|
||||||
|
|
||||||
|
|
||||||
/*_____ U S B I N T E R F A C E D E S C R I P T O R _____________________*/
|
|
||||||
|
|
||||||
struct usb_st_interface_descriptor
|
|
||||||
{
|
|
||||||
Uchar bLength; /* size of this descriptor in bytes */
|
|
||||||
Uchar bDescriptorType; /* INTERFACE descriptor type */
|
|
||||||
Uchar bInterfaceNumber; /* Number of interface */
|
|
||||||
Uchar bAlternateSetting; /* value to select alternate setting */
|
|
||||||
Uchar bNumEndpoints; /* Number of EP except EP 0 */
|
|
||||||
Uchar bInterfaceClass; /* Class code assigned by the USB */
|
|
||||||
Uchar bInterfaceSubClass; /* Sub-class code assigned by the USB */
|
|
||||||
Uchar bInterfaceProtocol; /* Protocol code assigned by the USB */
|
|
||||||
Uchar iInterface; /* Index of string descriptor */
|
|
||||||
} BYTE_ALIGNED;
|
|
||||||
|
|
||||||
|
|
||||||
/*_____ U S B E N D P O I N T D E S C R I P T O R _______________________*/
|
|
||||||
|
|
||||||
struct usb_st_endpoint_descriptor
|
|
||||||
{
|
|
||||||
Uchar bLength; /* Size of this descriptor in bytes */
|
|
||||||
Uchar bDescriptorType; /* ENDPOINT descriptor type */
|
|
||||||
Uchar bEndpointAddress; /* Address of the endpoint */
|
|
||||||
Uchar bmAttributes; /* Endpoint's attributes */
|
|
||||||
Uint16 wMaxPacketSize; /* Maximum packet size for this EP */
|
|
||||||
Uchar bInterval; /* Interval for polling EP in ms */
|
|
||||||
/* Uchar bRefresh; */
|
|
||||||
/* Uchar bSynchAddress; */
|
|
||||||
} BYTE_ALIGNED;
|
|
||||||
|
|
||||||
|
|
||||||
/*_____ U S B S T R I N G D E S C R I P T O R _______________*/
|
|
||||||
|
|
||||||
struct usb_st_string_descriptor
|
|
||||||
{
|
|
||||||
Uchar bLength; /* size of this descriptor in bytes */
|
|
||||||
Uchar bDescriptorType; /* STRING descriptor type */
|
|
||||||
Uint16 wstring[1];/* unicode characters */
|
|
||||||
} BYTE_ALIGNED;
|
|
||||||
|
|
||||||
|
|
||||||
struct usb_st_language_descriptor
|
|
||||||
{
|
|
||||||
Uchar bLength; /* size of this descriptor in bytes */
|
|
||||||
Uchar bDescriptorType; /* STRING descriptor type */
|
|
||||||
Uint16 wlangid[1]; /* language id */
|
|
||||||
} BYTE_ALIGNED;
|
|
||||||
|
|
||||||
#endif /* __USB_H__6PFTDPIMZM__ */
|
|
Loading…
Add table
Reference in a new issue