Moved and updated code for AT91SAM7S
This commit is contained in:
parent
1658d6b42c
commit
1f72d3ea32
32 changed files with 9799 additions and 0 deletions
175
cpu/arm/at91sam7s/AT91SAM7S-ROM.ld
Normal file
175
cpu/arm/at91sam7s/AT91SAM7S-ROM.ld
Normal file
|
@ -0,0 +1,175 @@
|
|||
/***********************************************************************/
|
||||
/* */
|
||||
/* 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 */
|
||||
/***********************************************************************/
|
||||
|
||||
|
||||
|
||||
/* Section Definitions */
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
|
||||
/* first section is .text which is used for code */
|
||||
|
||||
.vectrom :
|
||||
{
|
||||
KEEP(*(.vectrom))
|
||||
} >CODE =0
|
||||
.text :
|
||||
{
|
||||
/* *startup.o (.text) */ /* Startup code */
|
||||
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 = .);
|
||||
|
||||
|
||||
UND_Stack_Size = 0x00000004;
|
||||
SVC_Stack_Size = 0x00000200;
|
||||
ABT_Stack_Size = 0x00000004;
|
||||
FIQ_Stack_Size = 0x00000100;
|
||||
IRQ_Stack_Size = 0x00000300;
|
||||
USR_Stack_Size = 0x00000400;
|
||||
|
||||
Stack_Size = UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + FIQ_Stack_Size + IRQ_Stack_Size + USR_Stack_Size;
|
||||
.stack ORIGIN(DATA) + LENGTH(DATA) - Stack_Size :
|
||||
{
|
||||
__stack_start__ = . ;
|
||||
USR_Stack_Start = . ;
|
||||
. += USR_Stack_Size;
|
||||
USR_Stack_End = . ;
|
||||
IRQ_Stack_Start = . ;
|
||||
. += IRQ_Stack_Size;
|
||||
IRQ_Stack_End = . ;
|
||||
FIQ_Stack_Start = . ;
|
||||
. += FIQ_Stack_Size;
|
||||
FIQ_Stack_End = . ;
|
||||
ABT_Stack_Start = . ;
|
||||
. += ABT_Stack_Size;
|
||||
ABT_Stack_End = . ;
|
||||
SVC_Stack_Start = . ;
|
||||
. += SVC_Stack_Size;
|
||||
SVC_Stack_End = . ;
|
||||
UND_Stack_Start = . ;
|
||||
. += UND_Stack_Size;
|
||||
UND_Stack_End = . ;
|
||||
. = ALIGN(4);
|
||||
__stack_end__ = . ;
|
||||
Top_Stack = .;
|
||||
} >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) }
|
||||
}
|
9
cpu/arm/at91sam7s/AT91SAM7S128-ROM.ld
Normal file
9
cpu/arm/at91sam7s/AT91SAM7S128-ROM.ld
Normal file
|
@ -0,0 +1,9 @@
|
|||
/* Memory Definitions */
|
||||
|
||||
MEMORY
|
||||
{
|
||||
CODE (rx) : ORIGIN = 0x00100000, LENGTH = 128K
|
||||
DATA (rw) : ORIGIN = 0x00200000, LENGTH = 32K
|
||||
}
|
||||
|
||||
INCLUDE AT91SAM7S-ROM.ld
|
2229
cpu/arm/at91sam7s/AT91SAM7S128.h
Normal file
2229
cpu/arm/at91sam7s/AT91SAM7S128.h
Normal file
File diff suppressed because it is too large
Load diff
2229
cpu/arm/at91sam7s/AT91SAM7S256.h
Normal file
2229
cpu/arm/at91sam7s/AT91SAM7S256.h
Normal file
File diff suppressed because it is too large
Load diff
9
cpu/arm/at91sam7s/AT91SAM7S64-ROM.ld
Normal file
9
cpu/arm/at91sam7s/AT91SAM7S64-ROM.ld
Normal file
|
@ -0,0 +1,9 @@
|
|||
/* Memory Definitions */
|
||||
|
||||
MEMORY
|
||||
{
|
||||
CODE (rx) : ORIGIN = 0x00100000, LENGTH = 64K
|
||||
DATA (rw) : ORIGIN = 0x00200000, LENGTH = 16K
|
||||
}
|
||||
INCLUDE AT91SAM7S-ROM.ld
|
||||
|
2229
cpu/arm/at91sam7s/AT91SAM7S64.h
Normal file
2229
cpu/arm/at91sam7s/AT91SAM7S64.h
Normal file
File diff suppressed because it is too large
Load diff
4
cpu/arm/at91sam7s/builtins.awk
Normal file
4
cpu/arm/at91sam7s/builtins.awk
Normal file
|
@ -0,0 +1,4 @@
|
|||
BEGIN {
|
||||
builtin["_exit"] = "void _exit()";
|
||||
builtin["strlen"] = "unsigned long strlen()";
|
||||
}
|
183
cpu/arm/at91sam7s/cfs-sdcard-arch.c
Normal file
183
cpu/arm/at91sam7s/cfs-sdcard-arch.c
Normal file
|
@ -0,0 +1,183 @@
|
|||
#include <efs-sdcard.h>
|
||||
#include <sys/process.h>
|
||||
#include <sys/etimer.h>
|
||||
#include <cfs/cfs.h>
|
||||
#include <debug-uart.h>
|
||||
#include <efs.h>
|
||||
#include <ls.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
|
||||
process_event_t sdcard_inserted_event;
|
||||
|
||||
process_event_t sdcard_removed_event;
|
||||
|
||||
static struct process *event_process = NULL;
|
||||
|
||||
|
||||
#define MAX_FDS 4
|
||||
|
||||
static File file_descriptors[MAX_FDS];
|
||||
|
||||
static int
|
||||
find_free_fd()
|
||||
{
|
||||
int fd;
|
||||
for (fd = 0; fd < MAX_FDS; fd++) {
|
||||
if (!file_getAttr(&file_descriptors[fd], FILE_STATUS_OPEN)) {
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static File *
|
||||
get_file(int fd)
|
||||
{
|
||||
if (!sdcard_ready()) return 0;
|
||||
if (fd >= MAX_FDS || fd < 0) return NULL;
|
||||
if (!file_getAttr(&file_descriptors[fd], FILE_STATUS_OPEN)) return NULL;
|
||||
return &file_descriptors[fd];
|
||||
}
|
||||
|
||||
int
|
||||
cfs_open (const char *name, int flags)
|
||||
{
|
||||
eint8 mode;
|
||||
int fd;
|
||||
if (!sdcard_ready()) return -1;
|
||||
fd = find_free_fd();
|
||||
if (fd < 0) return -1;
|
||||
if (flags == CFS_READ) {
|
||||
mode = MODE_READ;
|
||||
} else {
|
||||
mode = MODE_APPEND;
|
||||
}
|
||||
if (file_fopen(&file_descriptors[fd], &sdcard_efs.myFs,
|
||||
(char*)name, mode) < 0) {
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
void
|
||||
cfs_close(int fd)
|
||||
{
|
||||
File *file = get_file(fd);
|
||||
if (!file) return;
|
||||
file_fclose(file);
|
||||
fs_flushFs(efs_sdcard_get_fs());
|
||||
}
|
||||
|
||||
int
|
||||
cfs_read (int fd, void *buf, unsigned int len)
|
||||
{
|
||||
File *file = get_file(fd);
|
||||
if (!file) return 0;
|
||||
return file_read(file, len, (euint8*)buf);
|
||||
}
|
||||
|
||||
int
|
||||
cfs_write (int fd, const void *buf, unsigned int len)
|
||||
{
|
||||
File *file = get_file(fd);
|
||||
if (!file) return 0;
|
||||
return file_write(file, len, (euint8*)buf);
|
||||
}
|
||||
|
||||
cfs_offset_t
|
||||
cfs_seek (int fd, cfs_offset_t offset, int whence)
|
||||
{
|
||||
File *file;
|
||||
if (whence != CFS_SEEK_SET) return -1;
|
||||
file = get_file(fd);
|
||||
if (!file) return 0;
|
||||
if (file_setpos(file, offset) != 0) return -1;
|
||||
return file->FilePtr;
|
||||
}
|
||||
|
||||
|
||||
/* Cause a compile time error if expr is false */
|
||||
#ifdef __GNUC__
|
||||
#define COMPILE_TIME_CHECK(expr) \
|
||||
(void) (__builtin_choose_expr ((expr), 0, ((void)0))+3)
|
||||
#else
|
||||
#define COMPILE_TIME_CHECK(expr)
|
||||
#endif
|
||||
|
||||
#define MAX_DIR_LISTS 4
|
||||
DirList dir_lists[MAX_DIR_LISTS];
|
||||
|
||||
static DirList *
|
||||
find_free_dir_list()
|
||||
{
|
||||
unsigned int l;
|
||||
for(l = 0; l < MAX_DIR_LISTS; l++) {
|
||||
if (dir_lists[l].fs == NULL) {
|
||||
return &dir_lists[l];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
cfs_opendir (struct cfs_dir *dirp, const char *name)
|
||||
{
|
||||
DirList *dirs;
|
||||
COMPILE_TIME_CHECK(sizeof(DirList*) <= sizeof(struct cfs_dir));
|
||||
if (!sdcard_ready()) return -1;
|
||||
dirs = find_free_dir_list();
|
||||
if (!dirs) return -1;
|
||||
if (ls_openDir(dirs, efs_sdcard_get_fs(), (eint8*)name) != 0) {
|
||||
dirs->fs = NULL;
|
||||
return -1;
|
||||
}
|
||||
*(DirList**)dirp = dirs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
cfs_readdir (struct cfs_dir *dirp, struct cfs_dirent *dirent)
|
||||
{
|
||||
euint8 *start;
|
||||
euint8 *end;
|
||||
char *to = dirent->name;
|
||||
DirList *dirs = *(DirList**)dirp;
|
||||
if (!sdcard_ready()) return 1;
|
||||
if (ls_getNext(dirs) != 0) return 1;
|
||||
start = dirs->currentEntry.FileName;
|
||||
end = start + 7;
|
||||
while(end > start) {
|
||||
if (*end > ' ') {
|
||||
end++;
|
||||
break;
|
||||
}
|
||||
end--;
|
||||
}
|
||||
while(start < end) {
|
||||
*to++ = *start++;
|
||||
}
|
||||
start = dirs->currentEntry.FileName + 8;
|
||||
end = start + 3;
|
||||
if (*start > ' ') {
|
||||
*to++ = '.';
|
||||
*to++ = *start++;
|
||||
while(start < end && *start > ' ') {
|
||||
*to++ = *start++;
|
||||
}
|
||||
}
|
||||
*to = '\0';
|
||||
if (dirs->currentEntry.Attribute & ATTR_DIRECTORY) {
|
||||
dirent->size = 0;
|
||||
} else {
|
||||
dirent->size = dirs->currentEntry.FileSize;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
cfs_closedir (struct cfs_dir *dirp)
|
||||
{
|
||||
(*(DirList**)dirp)->fs = NULL;
|
||||
}
|
74
cpu/arm/at91sam7s/clock.c
Normal file
74
cpu/arm/at91sam7s/clock.c
Normal file
|
@ -0,0 +1,74 @@
|
|||
#include <sys/clock.h>
|
||||
#include <sys/cc.h>
|
||||
#include <sys/etimer.h>
|
||||
#include <debug-uart.h>
|
||||
|
||||
#include <AT91SAM7S64.h>
|
||||
#include <sys-interrupt.h>
|
||||
|
||||
#define PIV ((MCK/CLOCK_SECOND/16)-1)
|
||||
|
||||
static volatile clock_time_t current_clock = 0;
|
||||
static volatile unsigned long current_seconds = 0;
|
||||
static unsigned int second_countdown = CLOCK_SECOND;
|
||||
|
||||
|
||||
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 ()); */
|
||||
|
||||
}
|
||||
if (--second_countdown == 0) {
|
||||
current_seconds++;
|
||||
second_countdown = CLOCK_SECOND;
|
||||
}
|
||||
(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
|
||||
}
|
||||
|
||||
unsigned long
|
||||
clock_seconds(void)
|
||||
{
|
||||
return current_seconds;
|
||||
}
|
||||
#endif /* __MAKING_DEPS__ */
|
196
cpu/arm/at91sam7s/debug-uart.c
Normal file
196
cpu/arm/at91sam7s/debug-uart.c
Normal file
|
@ -0,0 +1,196 @@
|
|||
#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 3024
|
||||
#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));
|
||||
}
|
33
cpu/arm/at91sam7s/debug-uart.h
Normal file
33
cpu/arm/at91sam7s/debug-uart.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#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__ */
|
195
cpu/arm/at91sam7s/efs-sdcard-arch.c
Normal file
195
cpu/arm/at91sam7s/efs-sdcard-arch.c
Normal file
|
@ -0,0 +1,195 @@
|
|||
#include <AT91SAM7S64.h>
|
||||
#include <interfaces/sd.h>
|
||||
#include <efs-sdcard.h>
|
||||
#include <sys/etimer.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define SPI_SPEED 10000000 /* 10MHz clock*/
|
||||
|
||||
#define SPI_TRANSFER (AT91C_PA12_MISO | AT91C_PA13_MOSI | AT91C_PA14_SPCK)
|
||||
|
||||
#define SPI_CS (AT91C_PA11_NPCS0)
|
||||
|
||||
static struct process *event_process = NULL;
|
||||
|
||||
static void
|
||||
init_spi()
|
||||
{
|
||||
*AT91C_SPI_CR = AT91C_SPI_SPIDIS | AT91C_SPI_SWRST;
|
||||
*AT91C_PMC_PCER = (1 << AT91C_ID_SPI);
|
||||
*AT91C_PIOA_ASR = SPI_TRANSFER | SPI_CS;
|
||||
*AT91C_PIOA_PDR = SPI_TRANSFER | SPI_CS;
|
||||
*AT91C_PIOA_PPUER = AT91C_PA12_MISO | SPI_CS;
|
||||
*AT91C_SPI_MR = (AT91C_SPI_MSTR | AT91C_SPI_PS_FIXED
|
||||
| AT91C_SPI_MODFDIS);
|
||||
|
||||
/* It seems necessary to set the clock speed for chip select 0
|
||||
even if it's not used. */
|
||||
|
||||
AT91C_SPI_CSR[0] =
|
||||
((((MCK+SPI_SPEED/2)/SPI_SPEED)<<8) | AT91C_SPI_CPOL
|
||||
| AT91C_SPI_BITS_8 | AT91C_SPI_CSAAT);
|
||||
*AT91C_SPI_CR = AT91C_SPI_SPIEN;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
if_spiInit(hwInterface *iface)
|
||||
{
|
||||
unsigned int i;
|
||||
*AT91C_PIOA_SODR = AT91C_PA11_NPCS0;
|
||||
*AT91C_PIOA_PER = AT91C_PA11_NPCS0;
|
||||
for(i=0;i<20;i++) {
|
||||
if_spiSend(iface, 0xff);
|
||||
}
|
||||
*AT91C_PIOA_PDR = AT91C_PA11_NPCS0;
|
||||
}
|
||||
|
||||
/* Borrowed from at91_spi.c (c)2006 Martin Thomas */
|
||||
|
||||
esint8
|
||||
if_initInterface(hwInterface* file, eint8* opts)
|
||||
{
|
||||
euint32 sc;
|
||||
|
||||
if_spiInit(file);
|
||||
if(sd_Init(file)<0) {
|
||||
DBG((TXT("Card failed to init, breaking up...\n")));
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if(sd_State(file)<0){
|
||||
DBG((TXT("Card didn't return the ready state, breaking up...\n")
|
||||
));
|
||||
return(-2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
sd_getDriveSize(file, &sc);
|
||||
file->sectorCount = sc/512;
|
||||
if( (sc%512) != 0) {
|
||||
file->sectorCount--;
|
||||
}
|
||||
DBG((TXT("Card Capacity is %lu Bytes (%lu Sectors)\n"), sc, file->sectorCount));
|
||||
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Borrowed from lpc2000_spi.c (c)2005 Martin Thomas */
|
||||
|
||||
esint8
|
||||
if_readBuf(hwInterface* file,euint32 address,euint8* buf)
|
||||
{
|
||||
return(sd_readSector(file,address,buf,512));
|
||||
}
|
||||
|
||||
esint8
|
||||
if_writeBuf(hwInterface* file,euint32 address,euint8* buf)
|
||||
{
|
||||
return(sd_writeSector(file,address, buf));
|
||||
}
|
||||
|
||||
esint8
|
||||
if_setPos(hwInterface* file,euint32 address)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
euint8
|
||||
if_spiSend(hwInterface *iface, euint8 outgoing)
|
||||
{
|
||||
euint8 ingoing;
|
||||
*AT91C_SPI_TDR = outgoing;
|
||||
while(!(*AT91C_SPI_SR & AT91C_SPI_RDRF));
|
||||
ingoing = *AT91C_SPI_RDR;
|
||||
/* printf(">%02x <%02x\n", outgoing, ingoing); */
|
||||
return ingoing;
|
||||
}
|
||||
|
||||
static EmbeddedFileSystem sdcard_efs;
|
||||
|
||||
PROCESS(sdcard_process, "SD card process");
|
||||
|
||||
PROCESS_THREAD(sdcard_process, ev , data)
|
||||
{
|
||||
static struct etimer timer;
|
||||
PROCESS_BEGIN();
|
||||
*AT91C_PIOA_PER = AT91C_PIO_PA20 | AT91C_PIO_PA1;
|
||||
*AT91C_PIOA_ODR = AT91C_PIO_PA20 | AT91C_PIO_PA1;
|
||||
|
||||
|
||||
/* Card not inserted */
|
||||
sdcard_efs.myCard.sectorCount = 0;
|
||||
init_spi();
|
||||
|
||||
while(1) {
|
||||
if (!(*AT91C_PIOA_PDSR & AT91C_PA20_IRQ0)) {
|
||||
if (sdcard_efs.myCard.sectorCount == 0) {
|
||||
if (efs_init(&sdcard_efs,0) == 0) {
|
||||
if (event_process) {
|
||||
process_post(event_process, sdcard_inserted_event, NULL);
|
||||
}
|
||||
printf("SD card inserted\n");
|
||||
} else {
|
||||
printf("SD card insertion failed\n");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (sdcard_efs.myCard.sectorCount != 0) {
|
||||
/* Card removed */
|
||||
fs_umount(&sdcard_efs.myFs);
|
||||
sdcard_efs.myCard.sectorCount = 0;
|
||||
if (event_process) {
|
||||
process_post(event_process, sdcard_removed_event, NULL);
|
||||
}
|
||||
printf("SD card removed\n");
|
||||
}
|
||||
}
|
||||
|
||||
etimer_set(&timer, CLOCK_SECOND);
|
||||
PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_EXIT ||
|
||||
ev == PROCESS_EVENT_TIMER);
|
||||
if (ev == PROCESS_EVENT_EXIT) break;
|
||||
if (!(*AT91C_PIOA_PDSR & AT91C_PA20_IRQ0)) {
|
||||
/* Wait for card to be preperly inserted */
|
||||
etimer_set(&timer,CLOCK_SECOND/2);
|
||||
PROCESS_WAIT_EVENT_UNTIL(ev== PROCESS_EVENT_TIMER);
|
||||
}
|
||||
|
||||
}
|
||||
PROCESS_END();
|
||||
}
|
||||
|
||||
FileSystem *
|
||||
efs_sdcard_get_fs()
|
||||
{
|
||||
efs_sdcard_init();
|
||||
return &sdcard_efs.myFs;
|
||||
}
|
||||
|
||||
void
|
||||
efs_sdcard_init()
|
||||
{
|
||||
static int initialized = 0;
|
||||
if (!initialized) {
|
||||
sdcard_inserted_event = process_alloc_event();
|
||||
sdcard_removed_event = process_alloc_event();
|
||||
process_start(&sdcard_process, NULL);
|
||||
initialized = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
sdcard_ready()
|
||||
{
|
||||
return sdcard_efs.myCard.sectorCount > 0;
|
||||
}
|
||||
|
||||
void
|
||||
sdcard_event_process(struct process *p)
|
||||
{
|
||||
event_process = p;
|
||||
}
|
96
cpu/arm/at91sam7s/elfloader-arm.c
Normal file
96
cpu/arm/at91sam7s/elfloader-arm.c
Normal file
|
@ -0,0 +1,96 @@
|
|||
#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;
|
||||
}
|
84
cpu/arm/at91sam7s/interrupt-utils.c
Normal file
84
cpu/arm/at91sam7s/interrupt-utils.c
Normal file
|
@ -0,0 +1,84 @@
|
|||
/******************************************************************************
|
||||
*
|
||||
* $RCSfile: interrupt-utils.c,v $
|
||||
* $Revision: 1.1 $
|
||||
*
|
||||
* 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;
|
||||
}
|
272
cpu/arm/at91sam7s/interrupt-utils.h
Normal file
272
cpu/arm/at91sam7s/interrupt-utils.h
Normal file
|
@ -0,0 +1,272 @@
|
|||
/*
|
||||
* 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
|
||||
|
15
cpu/arm/at91sam7s/io.h
Normal file
15
cpu/arm/at91sam7s/io.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#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__ */
|
8
cpu/arm/at91sam7s/merge-rodata.ld
Normal file
8
cpu/arm/at91sam7s/merge-rodata.ld
Normal file
|
@ -0,0 +1,8 @@
|
|||
SECTIONS
|
||||
{
|
||||
.text :
|
||||
{
|
||||
*(.text)
|
||||
*(.rodata.* .rodata)
|
||||
}
|
||||
}
|
124
cpu/arm/at91sam7s/newlib-syscalls.c
Normal file
124
cpu/arm/at91sam7s/newlib-syscalls.c
Normal file
|
@ -0,0 +1,124 @@
|
|||
#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;
|
22
cpu/arm/at91sam7s/pit-interrupt.h
Normal file
22
cpu/arm/at91sam7s/pit-interrupt.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
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();
|
||||
}
|
34
cpu/arm/at91sam7s/rtimer-arch-interrupt.c
Normal file
34
cpu/arm/at91sam7s/rtimer-arch-interrupt.c
Normal file
|
@ -0,0 +1,34 @@
|
|||
#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();
|
||||
}
|
6
cpu/arm/at91sam7s/rtimer-arch-interrupt.h
Normal file
6
cpu/arm/at91sam7s/rtimer-arch-interrupt.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef __RTIMER_ARCH_INTERRUPT_H__P0PXG70757__
|
||||
#define __RTIMER_ARCH_INTERRUPT_H__P0PXG70757__
|
||||
|
||||
void rtimer_interrupt (void);
|
||||
|
||||
#endif /* __RTIMER_ARCH_INTERRUPT_H__P0PXG70757__ */
|
49
cpu/arm/at91sam7s/rtimer-arch.c
Normal file
49
cpu/arm/at91sam7s/rtimer-arch.c
Normal file
|
@ -0,0 +1,49 @@
|
|||
#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;
|
||||
}
|
22
cpu/arm/at91sam7s/rtimer-arch.h
Normal file
22
cpu/arm/at91sam7s/rtimer-arch.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
/**
|
||||
* \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__ */
|
183
cpu/arm/at91sam7s/sdcard-arch.c
Normal file
183
cpu/arm/at91sam7s/sdcard-arch.c
Normal file
|
@ -0,0 +1,183 @@
|
|||
#include <efs-sdcard.h>
|
||||
#include <sys/process.h>
|
||||
#include <sys/etimer.h>
|
||||
#include <cfs/cfs.h>
|
||||
#include <debug-uart.h>
|
||||
#include <efs.h>
|
||||
#include <ls.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
|
||||
process_event_t sdcard_inserted_event;
|
||||
|
||||
process_event_t sdcard_removed_event;
|
||||
|
||||
static struct process *event_process = NULL;
|
||||
|
||||
|
||||
#define MAX_FDS 4
|
||||
|
||||
static File file_descriptors[MAX_FDS];
|
||||
|
||||
static int
|
||||
find_free_fd()
|
||||
{
|
||||
int fd;
|
||||
for (fd = 0; fd < MAX_FDS; fd++) {
|
||||
if (!file_getAttr(&file_descriptors[fd], FILE_STATUS_OPEN)) {
|
||||
return fd;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static File *
|
||||
get_file(int fd)
|
||||
{
|
||||
if (!sdcard_ready()) return 0;
|
||||
if (fd >= MAX_FDS || fd < 0) return NULL;
|
||||
if (!file_getAttr(&file_descriptors[fd], FILE_STATUS_OPEN)) return NULL;
|
||||
return &file_descriptors[fd];
|
||||
}
|
||||
|
||||
int
|
||||
cfs_open (const char *name, int flags)
|
||||
{
|
||||
eint8 mode;
|
||||
int fd;
|
||||
if (!sdcard_ready()) return -1;
|
||||
fd = find_free_fd();
|
||||
if (fd < 0) return -1;
|
||||
if (flags == CFS_READ) {
|
||||
mode = MODE_READ;
|
||||
} else {
|
||||
mode = MODE_APPEND;
|
||||
}
|
||||
if (file_fopen(&file_descriptors[fd], &sdcard_efs.myFs,
|
||||
(char*)name, mode) < 0) {
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
void
|
||||
cfs_close(int fd)
|
||||
{
|
||||
File *file = get_file(fd);
|
||||
if (!file) return;
|
||||
file_fclose(file);
|
||||
fs_flushFs(efs_sdcard_get_fs());
|
||||
}
|
||||
|
||||
int
|
||||
cfs_read (int fd, void *buf, unsigned int len)
|
||||
{
|
||||
File *file = get_file(fd);
|
||||
if (!file) return 0;
|
||||
return file_read(file, len, (euint8*)buf);
|
||||
}
|
||||
|
||||
int
|
||||
cfs_write (int fd, const void *buf, unsigned int len)
|
||||
{
|
||||
File *file = get_file(fd);
|
||||
if (!file) return 0;
|
||||
return file_write(file, len, (euint8*)buf);
|
||||
}
|
||||
|
||||
cfs_offset_t
|
||||
cfs_seek (int fd, cfs_offset_t offset, int whence)
|
||||
{
|
||||
File *file;
|
||||
if (whence != CFS_SEEK_SET) return -1;
|
||||
file = get_file(fd);
|
||||
if (!file) return 0;
|
||||
if (file_setpos(file, offset) != 0) return -1;
|
||||
return file->FilePtr;
|
||||
}
|
||||
|
||||
|
||||
/* Cause a compile time error if expr is false */
|
||||
#ifdef __GNUC__
|
||||
#define COMPILE_TIME_CHECK(expr) \
|
||||
(void) (__builtin_choose_expr ((expr), 0, ((void)0))+3)
|
||||
#else
|
||||
#define COMPILE_TIME_CHECK(expr)
|
||||
#endif
|
||||
|
||||
#define MAX_DIR_LISTS 4
|
||||
DirList dir_lists[MAX_DIR_LISTS];
|
||||
|
||||
static DirList *
|
||||
find_free_dir_list()
|
||||
{
|
||||
unsigned int l;
|
||||
for(l = 0; l < MAX_DIR_LISTS; l++) {
|
||||
if (dir_lists[l].fs == NULL) {
|
||||
return &dir_lists[l];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
cfs_opendir (struct cfs_dir *dirp, const char *name)
|
||||
{
|
||||
DirList *dirs;
|
||||
COMPILE_TIME_CHECK(sizeof(DirList*) <= sizeof(struct cfs_dir));
|
||||
if (!sdcard_ready()) return -1;
|
||||
dirs = find_free_dir_list();
|
||||
if (!dirs) return -1;
|
||||
if (ls_openDir(dirs, efs_sdcard_get_fs(), (eint8*)name) != 0) {
|
||||
dirs->fs = NULL;
|
||||
return -1;
|
||||
}
|
||||
*(DirList**)dirp = dirs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
cfs_readdir (struct cfs_dir *dirp, struct cfs_dirent *dirent)
|
||||
{
|
||||
euint8 *start;
|
||||
euint8 *end;
|
||||
char *to = dirent->name;
|
||||
DirList *dirs = *(DirList**)dirp;
|
||||
if (!sdcard_ready()) return 1;
|
||||
if (ls_getNext(dirs) != 0) return 1;
|
||||
start = dirs->currentEntry.FileName;
|
||||
end = start + 7;
|
||||
while(end > start) {
|
||||
if (*end > ' ') {
|
||||
end++;
|
||||
break;
|
||||
}
|
||||
end--;
|
||||
}
|
||||
while(start < end) {
|
||||
*to++ = *start++;
|
||||
}
|
||||
start = dirs->currentEntry.FileName + 8;
|
||||
end = start + 3;
|
||||
if (*start > ' ') {
|
||||
*to++ = '.';
|
||||
*to++ = *start++;
|
||||
while(start < end && *start > ' ') {
|
||||
*to++ = *start++;
|
||||
}
|
||||
}
|
||||
*to = '\0';
|
||||
if (dirs->currentEntry.Attribute & ATTR_DIRECTORY) {
|
||||
dirent->size = 0;
|
||||
} else {
|
||||
dirent->size = dirs->currentEntry.FileSize;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
cfs_closedir (struct cfs_dir *dirp)
|
||||
{
|
||||
(*(DirList**)dirp)->fs = NULL;
|
||||
}
|
233
cpu/arm/at91sam7s/startup-SAM7S-arm.c
Normal file
233
cpu/arm/at91sam7s/startup-SAM7S-arm.c
Normal file
|
@ -0,0 +1,233 @@
|
|||
#include <AT91SAM7S64.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define USED __attribute__((used))
|
||||
#define USED_NAKED __attribute__((used,naked))
|
||||
#define USED_INT(type) __attribute__((used,interrupt(#type)))
|
||||
#if MCK > 30000000
|
||||
#define FLASH_CYCLES AT91C_MC_FWS_1FWS
|
||||
#else
|
||||
#define FLASH_CYCLES AT91C_MC_FWS_0FWS
|
||||
#endif
|
||||
|
||||
#ifndef MAIN_OSC_FREQ
|
||||
#define MAIN_OSC_FREQ 18432000
|
||||
#endif
|
||||
|
||||
#if MAIN_OSC_FREQ != 18432000
|
||||
#error Unsupported main oscilator frequency
|
||||
#endif
|
||||
|
||||
#if MCK == 23961600
|
||||
#define PLL_DIV 5
|
||||
#define PLL_MUL 26
|
||||
#define PLL_USBDIV_EXP 1
|
||||
#define MCK_DIV_EXP 2
|
||||
#elif MCK == 47923200
|
||||
#define PLL_DIV 5
|
||||
#define PLL_MUL 26
|
||||
#define PLL_USBDIV_EXP 1
|
||||
#define MCK_DIV_EXP 1
|
||||
#else
|
||||
#error "Unsupported main clock frequency"
|
||||
#endif
|
||||
|
||||
#define PLL_FREQ ((MAIN_OSC_FREQ * PLL_MUL) / PLL_DIV)
|
||||
|
||||
#if PLL_FREQ > 180000000
|
||||
#error "PLL frequency too high"
|
||||
#elif PLL_FREQ < 80000000
|
||||
#error "PLL frequency too low"
|
||||
#endif
|
||||
|
||||
#if PLL_FREQ > 155000000
|
||||
#define PLL_RANGE AT91C_CKGR_OUT_2
|
||||
#else
|
||||
#define PLL_RANGE AT91C_CKGR_OUT_0
|
||||
#endif
|
||||
|
||||
#if PLL_USBDIV > 2
|
||||
#error "PLL frequency too high for USB"
|
||||
#endif
|
||||
|
||||
#define USB_FREQ (PLL_FREQ / (1<<PLL_USBDIV_EXP))
|
||||
#if USB_FREQ > 48120000 || USB_FREQ < 47880000
|
||||
#warning "USB frequency outside limits"
|
||||
#endif
|
||||
|
||||
#if MCK * (1<<MCK_DIV_EXP) != PLL_FREQ
|
||||
#error PLL frequency is not a the correct multiple of the main clock
|
||||
#endif
|
||||
|
||||
/* CPU modes */
|
||||
#define Mode_USR 0x10
|
||||
#define Mode_FIQ 0x11
|
||||
#define Mode_IRQ 0x12
|
||||
#define Mode_SVC 0x13
|
||||
#define Mode_ABT 0x17
|
||||
#define Mode_UND 0x1B
|
||||
#define Mode_SYS 0x1F
|
||||
|
||||
/* IRQ disable bit */
|
||||
#define I_Bit 0x80
|
||||
/* FIQ disable bit */
|
||||
#define F_Bit 0x40
|
||||
|
||||
#define SET_MODE_STACK(mode, stack_end) \
|
||||
asm("msr CPSR_c, %0\nldr sp, =" #stack_end "\n" ::"i" ((mode)|I_Bit|F_Bit))
|
||||
|
||||
#define ENABLE_INTS() \
|
||||
asm("mrs r0, cpsr\nand r0, %0\nmsr cpsr_c, r0\n"::"i" (~(I_Bit|F_Bit)):"r0")
|
||||
|
||||
|
||||
extern void *USR_Stack_End;
|
||||
extern void *UND_Stack_End;
|
||||
extern void *ABT_Stack_End;
|
||||
extern void *FIQ_Stack_End;
|
||||
extern void *IRQ_Stack_End;
|
||||
extern void *SVC_Stack_End;
|
||||
|
||||
extern uint8_t _data[];
|
||||
extern uint8_t _etext[];
|
||||
extern uint8_t _edata[];
|
||||
|
||||
extern uint8_t __bss_start[];
|
||||
extern uint8_t __bss_end[];
|
||||
|
||||
extern int
|
||||
main(int argc, char *argv[]);
|
||||
|
||||
static void
|
||||
copy_initialized(void)
|
||||
{
|
||||
uint8_t *ram = _data;
|
||||
uint8_t *rom = _etext;
|
||||
while(ram < _edata) {
|
||||
*ram++ = *rom++;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
clear_bss(void)
|
||||
{
|
||||
uint8_t *m = __bss_start;
|
||||
while(m < __bss_end) {
|
||||
*m++ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
Reset_handler(void) USED_NAKED;
|
||||
|
||||
static void
|
||||
SPU_handler(void) __attribute__((interrupt("IRQ")));
|
||||
|
||||
static void
|
||||
Reset_handler(void)
|
||||
{
|
||||
/* Setup flash timing */
|
||||
*AT91C_MC_FMR = FLASH_CYCLES | (MCK / 666666 + 1);
|
||||
|
||||
/* Disable watchdog */
|
||||
*AT91C_WDTC_WDMR = AT91C_WDTC_WDDIS;
|
||||
|
||||
/* Setup reset controller */
|
||||
*AT91C_RSTC_RMR = (0xa5<<24) | AT91C_RSTC_URSTS;
|
||||
|
||||
/* Start main oscilator */
|
||||
*AT91C_CKGR_MOR = AT91C_CKGR_MOSCEN | (6<<8);
|
||||
|
||||
/* Wait for oscillator to start */
|
||||
while(!(*AT91C_PMC_SR & AT91C_PMC_MOSCS));
|
||||
|
||||
/* Setup PLL */
|
||||
*AT91C_CKGR_PLLR = ((PLL_USBDIV_EXP << 28) | ((PLL_MUL-1)<<16) | PLL_RANGE
|
||||
| (28<<8) | PLL_DIV);
|
||||
|
||||
/* Wait for PLL to lock */
|
||||
while(!(*AT91C_PMC_SR & AT91C_PMC_LOCK));
|
||||
|
||||
*AT91C_PMC_MCKR = (MCK_DIV_EXP << 2);
|
||||
while(!(*AT91C_PMC_SR & AT91C_PMC_MCKRDY));
|
||||
*AT91C_PMC_MCKR |= AT91C_PMC_CSS_PLL_CLK;
|
||||
while(!(*AT91C_PMC_SR & AT91C_PMC_MCKRDY));
|
||||
SET_MODE_STACK(Mode_UND, UND_Stack_End);
|
||||
SET_MODE_STACK(Mode_ABT, ABT_Stack_End);
|
||||
SET_MODE_STACK(Mode_FIQ, FIQ_Stack_End);
|
||||
SET_MODE_STACK(Mode_IRQ, IRQ_Stack_End);
|
||||
SET_MODE_STACK(Mode_SVC, SVC_Stack_End);
|
||||
#ifdef RUN_AS_SYSTEM
|
||||
SET_MODE_STACK(Mode_SYS, USR_Stack_End);
|
||||
#else
|
||||
SET_MODE_STACK(Mode_USR, USR_Stack_End);
|
||||
#endif
|
||||
copy_initialized();
|
||||
clear_bss();
|
||||
|
||||
*AT91C_AIC_SPU = (uint32_t)SPU_handler;
|
||||
ENABLE_INTS();
|
||||
main(0,0);
|
||||
while(1);
|
||||
}
|
||||
|
||||
static void
|
||||
Undef_handler(void) USED_INT(UNDEF);
|
||||
|
||||
static void
|
||||
Undef_handler(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
SWI_handler(void) USED_INT(SWI);
|
||||
|
||||
static void
|
||||
SWI_handler(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
PAbt_handler(void) USED_INT(ABORT);
|
||||
|
||||
static void
|
||||
PAbt_handler(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
DAbt_handler(void) USED_INT(ABORT);
|
||||
|
||||
static void
|
||||
DAbt_handler(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
SPU_handler(void)
|
||||
{
|
||||
*AT91C_AIC_EOICR = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
Vectors(void) __attribute__ ((naked, section(".vectrom")));
|
||||
|
||||
static void
|
||||
Vectors(void)
|
||||
{
|
||||
asm("ldr pc, =Reset_handler\n");
|
||||
asm("ldr pc, =Undef_handler\n");
|
||||
asm("ldr pc, =SWI_handler\n");
|
||||
asm("ldr pc, =PAbt_handler\n");
|
||||
asm("ldr pc, =DAbt_handler\n");
|
||||
asm("nop\n");
|
||||
asm("ldr pc,[pc,#-0xf20]\n"); /* Vector From AIC_IVR */
|
||||
asm("ldr pc,[pc,#-0xf20]\n"); /* Vector From AIC_FVR */
|
||||
}
|
||||
|
||||
|
||||
|
||||
void foo_dummy()
|
||||
{
|
||||
Vectors();
|
||||
}
|
21
cpu/arm/at91sam7s/startup-SAM7S.c
Normal file
21
cpu/arm/at91sam7s/startup-SAM7S.c
Normal file
|
@ -0,0 +1,21 @@
|
|||
void
|
||||
Reset(void)
|
||||
{
|
||||
volatile int dummy =0;
|
||||
}
|
||||
|
||||
static void
|
||||
Vectors(void) __attribute__ ((naked, section(".vectrom")));
|
||||
|
||||
static void
|
||||
Vectors(void)
|
||||
{
|
||||
asm("ldr pc, %0\n"::"r" (Reset));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void foo_dummy()
|
||||
{
|
||||
Vectors();
|
||||
}
|
100
cpu/arm/at91sam7s/sys-interrupt.c
Normal file
100
cpu/arm/at91sam7s/sys-interrupt.c
Normal file
|
@ -0,0 +1,100 @@
|
|||
#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;
|
||||
}
|
||||
}
|
31
cpu/arm/at91sam7s/sys-interrupt.h
Normal file
31
cpu/arm/at91sam7s/sys-interrupt.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#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__ */
|
6
cpu/arm/at91sam7s/uip-log.c
Normal file
6
cpu/arm/at91sam7s/uip-log.c
Normal file
|
@ -0,0 +1,6 @@
|
|||
#include <stdio.h>
|
||||
|
||||
void uip_log(char *msg)
|
||||
{
|
||||
printf("uip: %s\n", msg);
|
||||
}
|
848
cpu/arm/at91sam7s/usb-arch.c
Normal file
848
cpu/arm/at91sam7s/usb-arch.c
Normal file
|
@ -0,0 +1,848 @@
|
|||
#include <usb-arch.h>
|
||||
#include <usb-interrupt.h>
|
||||
#include <AT91SAM7S64.h>
|
||||
#include <stdio.h>
|
||||
#include <debug-uart.h>
|
||||
|
||||
|
||||
/* #define DEBUG */
|
||||
#ifdef DEBUG
|
||||
#define PRINTF(...) printf(__VA_ARGS__)
|
||||
#else
|
||||
#define PRINTF(...)
|
||||
#endif
|
||||
|
||||
#define USB_PULLUP_PIN AT91C_PIO_PA16
|
||||
|
||||
#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)
|
||||
|
||||
|
||||
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))
|
||||
|
||||
|
||||
#define USB_DISABLE_INT *AT91C_AIC_IDCR = (1 << AT91C_ID_UDP)
|
||||
#define USB_ENABLE_INT *AT91C_AIC_IECR = (1 << AT91C_ID_UDP)
|
||||
|
||||
#define USB_DISABLE_EP_INT(hw_ep) *AT91C_UDP_IDR = (1 << (hw_ep))
|
||||
#define USB_ENABLE_EP_INT(hw_ep) *AT91C_UDP_IER = (1 << (hw_ep))
|
||||
|
||||
#if CTRL_EP_SIZE > 8
|
||||
#error Control endpoint size too big
|
||||
#endif
|
||||
|
||||
#if USB_EP1_SIZE > 64
|
||||
#error Endpoint 1 size too big
|
||||
#endif
|
||||
|
||||
#if USB_EP2_SIZE > 64
|
||||
#error Endpoint 2 size too big
|
||||
#endif
|
||||
|
||||
#if USB_EP3_SIZE > 64
|
||||
#error Endpoint 3 size too big
|
||||
#endif
|
||||
|
||||
static const uint16_t ep_xfer_size[8] =
|
||||
{
|
||||
CTRL_EP_SIZE,
|
||||
USB_EP1_SIZE,
|
||||
USB_EP2_SIZE,
|
||||
USB_EP3_SIZE
|
||||
};
|
||||
|
||||
#define USB_EP_XFER_SIZE(ep) ep_xfer_size[ep]
|
||||
|
||||
typedef struct _USBEndpoint USBEndpoint;
|
||||
struct _USBEndpoint
|
||||
{
|
||||
uint16_t status;
|
||||
uint8_t addr;
|
||||
uint8_t flags;
|
||||
USBBuffer *buffer; /* NULL if no current buffer */
|
||||
struct process *event_process;
|
||||
unsigned int events;
|
||||
uint16_t xfer_size;
|
||||
};
|
||||
|
||||
#define USB_EP_FLAGS_TYPE_MASK 0x03
|
||||
#define USB_EP_FLAGS_TYPE_BULK 0x00
|
||||
#define USB_EP_FLAGS_TYPE_CONTROL 0x01
|
||||
#define USB_EP_FLAGS_TYPE_ISO 0x02
|
||||
#define USB_EP_FLAGS_TYPE_INTERRUPT 0x03
|
||||
|
||||
#define EP_TYPE(ep) ((ep)->flags & USB_EP_FLAGS_TYPE_MASK)
|
||||
#define IS_EP_TYPE(ep, type) (EP_TYPE(ep) == (type))
|
||||
#define IS_CONTROL_EP(ep) IS_EP_TYPE(ep, USB_EP_FLAGS_TYPE_CONTROL)
|
||||
#define IS_BULK_EP(ep) IS_EP_TYPE(ep, USB_EP_FLAGS_TYPE_BULK)
|
||||
|
||||
#define USB_EP_FLAGS_ENABLED 0x04
|
||||
|
||||
/* A packet has been received but the data is still in hardware buffer */
|
||||
#define USB_EP_FLAGS_RECV_PENDING 0x08
|
||||
/* The pending packet is a SETUP packet */
|
||||
#define USB_EP_FLAGS_SETUP_PENDING 0x10
|
||||
|
||||
/* The data in the hardware buffer is being transmitted */
|
||||
#define USB_EP_FLAGS_TRANSMITTING 0x20
|
||||
|
||||
/* The receiver is waiting for a packet */
|
||||
#define USB_EP_FLAGS_RECEIVING 0x40
|
||||
|
||||
/* For bulk endpoints. Both buffers are busy are in use, either by
|
||||
hardware or software. */
|
||||
#define USB_EP_FLAGS_DOUBLE 0x80
|
||||
|
||||
/* The next packet received should be read from bank 1 if possible */
|
||||
#define USB_EP_FLAGS_BANK_1_RECV_NEXT 0x10
|
||||
|
||||
/* States for double buffered reception:
|
||||
|
||||
Packets being received 0 1 2 1 0 0
|
||||
Packets pending 0 0 0 1 2 1
|
||||
|
||||
RECVING 0 1 1 1 0 0
|
||||
RECV_PENDING 0 0 0 1 1 1
|
||||
DOUBLE 0 0 1 0 1 0
|
||||
*/
|
||||
|
||||
/* States for double buffered transmission:
|
||||
|
||||
Packets being transmitted 0 1 2
|
||||
|
||||
TRANSMITTING 0 1 1
|
||||
DOUBLE 0 0 1
|
||||
*/
|
||||
|
||||
/* Index in endpoint array */
|
||||
#define EP_INDEX(addr) ((addr) & 0x7f)
|
||||
|
||||
/* Get address of endpoint struct */
|
||||
#define EP_STRUCT(addr) &usb_endpoints[EP_INDEX(addr)];
|
||||
|
||||
/* Number of hardware endpoint */
|
||||
#define EP_HW_NUM(addr) ((addr) & 0x7f)
|
||||
|
||||
|
||||
static USBEndpoint usb_endpoints[USB_MAX_ENDPOINTS];
|
||||
struct process *event_process = 0;
|
||||
volatile unsigned int events = 0;
|
||||
|
||||
static void
|
||||
notify_process(unsigned int e)
|
||||
{
|
||||
events |= e;
|
||||
if (event_process) {
|
||||
process_poll(event_process);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
notify_ep_process(USBEndpoint *ep, unsigned int e)
|
||||
{
|
||||
ep->events |= e;
|
||||
if (ep->event_process) {
|
||||
process_poll(ep->event_process);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
usb_arch_reset(void)
|
||||
{
|
||||
unsigned int e;
|
||||
for (e = 0; e < USB_MAX_ENDPOINTS; e++) {
|
||||
if (usb_endpoints[e].flags &USB_EP_FLAGS_ENABLED) {
|
||||
USBBuffer *buffer = usb_endpoints[e].buffer;
|
||||
usb_endpoints[e].flags = 0;
|
||||
usb_disable_endpoint(e);
|
||||
while(buffer) {
|
||||
buffer->flags &= ~USB_BUFFER_SUBMITTED;
|
||||
buffer = buffer->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
usb_arch_setup_control_endpoint(0);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
usb_arch_setup(void)
|
||||
{
|
||||
unsigned int i;
|
||||
/* 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;
|
||||
|
||||
for(i = 0; i < USB_MAX_ENDPOINTS; i++) {
|
||||
usb_endpoints[i].flags = 0;
|
||||
usb_endpoints[i].event_process = 0;
|
||||
}
|
||||
|
||||
usb_arch_reset();
|
||||
/* 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);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
usb_arch_setup_endpoint(unsigned char addr, unsigned int hw_type)
|
||||
{
|
||||
unsigned int ei = EP_HW_NUM(addr);
|
||||
USBEndpoint *ep = EP_STRUCT(addr);
|
||||
ep->status = 0;
|
||||
ep->flags = USB_EP_FLAGS_ENABLED;
|
||||
ep->buffer = 0;
|
||||
ep->addr = addr;
|
||||
ep->events = 0;
|
||||
ep->xfer_size = 0;
|
||||
|
||||
*AT91C_UDP_IDR = 1<<ei;
|
||||
|
||||
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[ei], hw_type | AT91C_UDP_EPEDS,
|
||||
AT91C_UDP_EPTYPE | AT91C_UDP_EPEDS);
|
||||
|
||||
*AT91C_UDP_IER = 1<<ei;
|
||||
};
|
||||
|
||||
void
|
||||
usb_arch_setup_control_endpoint(unsigned char addr)
|
||||
{
|
||||
unsigned int ei = EP_HW_NUM(addr);
|
||||
USBEndpoint *ep = EP_STRUCT(addr);
|
||||
usb_arch_setup_endpoint(addr, AT91C_UDP_EPTYPE_CTRL);
|
||||
ep->flags |= USB_EP_FLAGS_TYPE_CONTROL;
|
||||
ep->xfer_size = ep_xfer_size[ei];
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
usb_arch_setup_bulk_endpoint(unsigned char addr)
|
||||
{
|
||||
unsigned int ei = EP_HW_NUM(addr);
|
||||
USBEndpoint *ep = EP_STRUCT(addr);
|
||||
usb_arch_setup_endpoint(addr, ((addr & 0x80)
|
||||
? AT91C_UDP_EPTYPE_BULK_IN
|
||||
: AT91C_UDP_EPTYPE_BULK_OUT));
|
||||
ep->flags |= USB_EP_FLAGS_TYPE_BULK;
|
||||
ep->xfer_size = ep_xfer_size[ei];
|
||||
}
|
||||
|
||||
void
|
||||
usb_arch_setup_interrupt_endpoint(unsigned char addr)
|
||||
{
|
||||
unsigned int ei = EP_HW_NUM(addr);
|
||||
USBEndpoint *ep = EP_STRUCT(addr);
|
||||
usb_arch_setup_endpoint(addr, ((addr & 0x80)
|
||||
? AT91C_UDP_EPTYPE_INT_IN
|
||||
: AT91C_UDP_EPTYPE_INT_OUT));
|
||||
ep->flags |= USB_EP_FLAGS_TYPE_BULK;
|
||||
ep->xfer_size = ep_xfer_size[ei];
|
||||
}
|
||||
|
||||
void
|
||||
usb_arch_disable_endpoint(uint8_t addr)
|
||||
{
|
||||
USBEndpoint *ep = EP_STRUCT(addr);
|
||||
ep->flags &= ~USB_EP_FLAGS_ENABLED;
|
||||
|
||||
*AT91C_UDP_IDR = 1<<EP_HW_NUM(addr);
|
||||
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[EP_HW_NUM(addr)], 0, AT91C_UDP_EPEDS);
|
||||
}
|
||||
|
||||
|
||||
#define USB_READ_BLOCK 0x01 /* The currently submitted buffers
|
||||
can't hold the received data, wait
|
||||
for more buffers. No data was read
|
||||
from the hardware buffer */
|
||||
#define USB_READ_NOTIFY 0x02 /* Some buffers that had the
|
||||
USB_BUFFER_NOTIFY flags set were
|
||||
released */
|
||||
#define USB_READ_FAIL 0x04 /* The received data doesn't match the
|
||||
submitted buffers. The hardware
|
||||
buffer is discarded. */
|
||||
|
||||
/* Skip buffers until mask and flags matches*/
|
||||
static USBBuffer *
|
||||
skip_buffers_until(USBBuffer *buffer, unsigned int mask, unsigned int flags,
|
||||
unsigned int *resp)
|
||||
{
|
||||
while(buffer && !((buffer->flags & mask) == flags)) {
|
||||
USBBuffer *next = buffer->next;
|
||||
buffer->flags &= ~USB_BUFFER_SUBMITTED ;
|
||||
buffer->flags |= USB_BUFFER_FAILED;
|
||||
if (buffer->flags & USB_BUFFER_NOTIFY) *resp |= USB_READ_NOTIFY;
|
||||
buffer = next;
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static void
|
||||
read_hw_buffer(uint8_t *data, unsigned int hw_ep, unsigned int len)
|
||||
{
|
||||
AT91_REG *fdr;
|
||||
fdr = &AT91C_UDP_FDR[hw_ep];
|
||||
while(len-- > 0) {
|
||||
*data++ = *fdr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define USB_WRITE_BLOCK 0x01
|
||||
#define USB_WRITE_NOTIFY 0x02
|
||||
|
||||
void
|
||||
write_hw_buffer(const uint8_t *data, unsigned int hw_ep, unsigned int len)
|
||||
{
|
||||
AT91_REG *fdr;
|
||||
fdr = &AT91C_UDP_FDR[hw_ep];
|
||||
/* PRINTF("Write %d\n", len); */
|
||||
while(len-- > 0) {
|
||||
*fdr = *data++;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
get_receive_capacity(USBBuffer *buffer)
|
||||
{
|
||||
unsigned int capacity = 0;
|
||||
while(buffer && !(buffer->flags & (USB_BUFFER_IN| USB_BUFFER_SETUP))) {
|
||||
capacity += buffer->left;
|
||||
buffer = buffer->next;
|
||||
}
|
||||
return capacity;
|
||||
}
|
||||
|
||||
static int
|
||||
handle_pending_receive(USBEndpoint *ep)
|
||||
{
|
||||
int short_packet;
|
||||
unsigned int len;
|
||||
unsigned int copy;
|
||||
unsigned int res = 0;
|
||||
unsigned int hw_ep = EP_HW_NUM(ep->addr);
|
||||
USBBuffer *buffer = ep->buffer;
|
||||
uint8_t *setup_data = NULL;
|
||||
unsigned int flags = ep->flags;
|
||||
if (!(flags & USB_EP_FLAGS_ENABLED) || !buffer) return USB_READ_BLOCK;
|
||||
len = RXBYTECNT(AT91C_UDP_CSR[hw_ep]);
|
||||
PRINTF("handle_pending_receive: %d\n", len);
|
||||
switch(flags & USB_EP_FLAGS_TYPE_MASK) {
|
||||
case USB_EP_FLAGS_TYPE_CONTROL:
|
||||
if (flags & USB_EP_FLAGS_SETUP_PENDING) {
|
||||
/* Discard buffers until we find a SETUP buffer */
|
||||
buffer =
|
||||
skip_buffers_until(buffer, USB_BUFFER_SETUP, USB_BUFFER_SETUP, &res);
|
||||
ep->buffer = buffer;
|
||||
if (!buffer || buffer->left < len) {
|
||||
res |= USB_READ_BLOCK;
|
||||
return res;
|
||||
}
|
||||
/* SETUP packet must fit in a single buffer */
|
||||
if (buffer->left < len) {
|
||||
buffer->flags |= USB_BUFFER_FAILED;
|
||||
buffer->flags &= ~USB_BUFFER_SUBMITTED ;
|
||||
if (buffer->flags & USB_BUFFER_NOTIFY) res |= USB_READ_NOTIFY;
|
||||
ep->buffer = buffer->next;
|
||||
res |= USB_READ_FAIL;
|
||||
return res;
|
||||
}
|
||||
setup_data = buffer->data;
|
||||
} else {
|
||||
if (buffer->flags & (USB_BUFFER_SETUP|USB_BUFFER_IN)) {
|
||||
buffer->flags |= USB_BUFFER_FAILED;
|
||||
|
||||
buffer->flags &= ~USB_BUFFER_SUBMITTED ;
|
||||
if (buffer->flags & USB_BUFFER_NOTIFY) res |= USB_READ_NOTIFY;
|
||||
ep->buffer = buffer->next;
|
||||
res |= USB_READ_FAIL;
|
||||
return res;
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
/* Status OUT */
|
||||
if (buffer->left > 0) {
|
||||
buffer->flags |= USB_BUFFER_FAILED;
|
||||
res |= USB_READ_FAIL;
|
||||
}
|
||||
buffer->flags &= ~USB_BUFFER_SUBMITTED ;
|
||||
if (buffer->flags & USB_BUFFER_NOTIFY) res |= USB_READ_NOTIFY;
|
||||
ep->buffer = buffer->next;
|
||||
return res;
|
||||
}
|
||||
if (get_receive_capacity(buffer) < len) return USB_READ_BLOCK;
|
||||
}
|
||||
break;
|
||||
case USB_EP_FLAGS_TYPE_INTERRUPT:
|
||||
case USB_EP_FLAGS_TYPE_BULK:
|
||||
case USB_EP_FLAGS_TYPE_ISO:
|
||||
if (get_receive_capacity(buffer) < len) {
|
||||
return USB_READ_BLOCK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
short_packet = len < ep->xfer_size;
|
||||
|
||||
do {
|
||||
if (buffer->left < len) {
|
||||
copy = buffer->left;
|
||||
} else {
|
||||
copy = len;
|
||||
}
|
||||
len -= copy;
|
||||
buffer->left -= copy;
|
||||
read_hw_buffer(buffer->data, hw_ep, copy);
|
||||
buffer->data += copy;
|
||||
|
||||
if (len == 0) break;
|
||||
|
||||
/* Release buffer */
|
||||
buffer->flags &= ~(USB_BUFFER_SUBMITTED | USB_BUFFER_SHORT_PACKET);
|
||||
if (buffer->flags & USB_BUFFER_NOTIFY) res |= USB_READ_NOTIFY;
|
||||
/* Use next buffer. */
|
||||
buffer = buffer->next;
|
||||
} while(1);
|
||||
|
||||
if (short_packet) {
|
||||
buffer->flags |= USB_BUFFER_SHORT_PACKET;
|
||||
}
|
||||
|
||||
if ((buffer->left == 0)
|
||||
|| (buffer->flags & USB_BUFFER_PACKET_END)
|
||||
|| (short_packet && (buffer->flags & USB_BUFFER_SHORT_END))) {
|
||||
/* Release buffer */
|
||||
buffer->flags &= ~USB_BUFFER_SUBMITTED;
|
||||
if (buffer->flags & USB_BUFFER_NOTIFY) res |= USB_READ_NOTIFY;
|
||||
/* Use next buffer. */
|
||||
buffer = buffer->next;
|
||||
}
|
||||
|
||||
ep->buffer = buffer;
|
||||
if (setup_data) {
|
||||
/* Set direction according to request */
|
||||
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[0],
|
||||
((setup_data[0] & 0x80)
|
||||
? AT91C_UDP_DIR : 0), AT91C_UDP_DIR);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
start_receive(USBEndpoint *ep)
|
||||
{
|
||||
ep->flags |= USB_EP_FLAGS_RECEIVING;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static unsigned int
|
||||
get_transmit_length(USBBuffer *buffer)
|
||||
{
|
||||
unsigned int length = 0;
|
||||
while(buffer && (buffer->flags & USB_BUFFER_IN)) {
|
||||
length += buffer->left;
|
||||
buffer = buffer->next;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
start_transmit(USBEndpoint *ep)
|
||||
{
|
||||
unsigned int res = 0;
|
||||
USBBuffer *buffer = ep->buffer;
|
||||
unsigned int len;
|
||||
unsigned int hw_ep = EP_HW_NUM(ep->addr);
|
||||
unsigned int ep_flags = ep->flags;
|
||||
len = ep->xfer_size;
|
||||
if (!(ep_flags & USB_EP_FLAGS_ENABLED) || !buffer) return USB_WRITE_BLOCK;
|
||||
switch(ep_flags & USB_EP_FLAGS_TYPE_MASK) {
|
||||
case USB_EP_FLAGS_TYPE_BULK:
|
||||
case USB_EP_FLAGS_TYPE_ISO:
|
||||
if (!(ep->flags & USB_EP_FLAGS_TRANSMITTING)) {
|
||||
if (AT91C_UDP_CSR[hw_ep] & AT91C_UDP_TXPKTRDY) return USB_WRITE_BLOCK;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (AT91C_UDP_CSR[hw_ep] & AT91C_UDP_TXPKTRDY) return USB_WRITE_BLOCK;
|
||||
}
|
||||
|
||||
|
||||
while (buffer) {
|
||||
unsigned int copy;
|
||||
if (buffer->left < len) {
|
||||
copy = buffer->left;
|
||||
} else {
|
||||
copy = len;
|
||||
}
|
||||
len -= copy;
|
||||
buffer->left -= copy;
|
||||
write_hw_buffer(buffer->data, hw_ep, copy);
|
||||
buffer->data += copy;
|
||||
if (buffer->left == 0) {
|
||||
if (buffer->flags & USB_BUFFER_SHORT_END) {
|
||||
if (len == 0) {
|
||||
/* Avoid endless loop */
|
||||
buffer->flags &= ~USB_BUFFER_SHORT_END;
|
||||
/* Send zero length packet. */
|
||||
break;
|
||||
} else {
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
/* Release buffer */
|
||||
buffer->flags &= ~USB_BUFFER_SUBMITTED;
|
||||
if (buffer->flags & USB_BUFFER_NOTIFY) res = USB_WRITE_NOTIFY;
|
||||
/* Use next buffer. */
|
||||
buffer = buffer->next;
|
||||
}
|
||||
if (len == 0) break;
|
||||
}
|
||||
ep->buffer = buffer;
|
||||
if (ep->flags & USB_EP_FLAGS_TRANSMITTING) {
|
||||
ep->flags |= USB_EP_FLAGS_DOUBLE;
|
||||
} else {
|
||||
ep->flags |= USB_EP_FLAGS_TRANSMITTING;
|
||||
}
|
||||
|
||||
PRINTF("start_transmit: sent %08x\n",AT91C_UDP_CSR[hw_ep]);
|
||||
/* Start transmission */
|
||||
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[hw_ep],
|
||||
AT91C_UDP_TXPKTRDY, AT91C_UDP_TXPKTRDY);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
start_transfer(USBEndpoint *ep)
|
||||
{
|
||||
unsigned int hw_ep = EP_HW_NUM(ep->addr);
|
||||
int res;
|
||||
while (ep->flags & USB_EP_FLAGS_RECV_PENDING) {
|
||||
res = handle_pending_receive(ep);
|
||||
if (res & USB_READ_NOTIFY) {
|
||||
notify_ep_process(ep, USB_EP_EVENT_NOTIFICATION);
|
||||
}
|
||||
PRINTF("received res = %d\n", res);
|
||||
if (res & USB_READ_BLOCK) {
|
||||
*AT91C_UDP_IDR = 1<<hw_ep;
|
||||
return;
|
||||
}
|
||||
if (AT91C_UDP_CSR[hw_ep] & AT91C_UDP_RXSETUP) {
|
||||
/* Acknowledge SETUP */
|
||||
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[hw_ep],0, AT91C_UDP_RXSETUP);
|
||||
} else if (AT91C_UDP_CSR[hw_ep] & (AT91C_UDP_RX_DATA_BK1)) {
|
||||
/* Ping-pong */
|
||||
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[hw_ep],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[hw_ep],0,
|
||||
AT91C_UDP_RX_DATA_BK0);
|
||||
ep->flags |= USB_EP_FLAGS_BANK_1_RECV_NEXT;
|
||||
}
|
||||
|
||||
if (ep->flags & USB_EP_FLAGS_DOUBLE) {
|
||||
ep->flags &= ~USB_EP_FLAGS_DOUBLE;
|
||||
} else if IS_CONTROL_EP(ep) {
|
||||
ep->flags &= ~(USB_EP_FLAGS_RECV_PENDING|USB_EP_FLAGS_SETUP_PENDING);
|
||||
} else {
|
||||
ep->flags &= ~USB_EP_FLAGS_RECV_PENDING;
|
||||
}
|
||||
if (res & USB_READ_FAIL) {
|
||||
/* Only fails for control endpoints */
|
||||
usb_arch_control_stall(ep->addr);
|
||||
return;
|
||||
}
|
||||
*AT91C_UDP_IER = 1<<hw_ep;
|
||||
}
|
||||
if (ep->flags & (USB_EP_FLAGS_TRANSMITTING | USB_EP_FLAGS_RECEIVING)) {
|
||||
#if 0
|
||||
if (!IS_BULK_EP(ep) || (ep->flags & USB_EP_FLAGS_DOUBLE)) {
|
||||
#else
|
||||
if(1) {
|
||||
#endif
|
||||
PRINTF("Busy\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (ep->status & 0x01) return; /* Don't start transfer if halted */
|
||||
if (ep->buffer) {
|
||||
if (ep->buffer->flags & USB_BUFFER_IN) {
|
||||
res = start_transmit(ep);
|
||||
if (res & USB_READ_NOTIFY) {
|
||||
notify_ep_process(ep, USB_EP_EVENT_NOTIFICATION);
|
||||
}
|
||||
} else {
|
||||
start_receive(ep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
usb_arch_transfer_complete(unsigned int hw_ep)
|
||||
{
|
||||
unsigned int status = AT91C_UDP_CSR[hw_ep];
|
||||
USBEndpoint *ep = &usb_endpoints[hw_ep];
|
||||
PRINTF("transfer_complete: %d\n", hw_ep);
|
||||
if (status & AT91C_UDP_STALLSENT) {
|
||||
/* Acknowledge */
|
||||
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[hw_ep],0, AT91C_UDP_STALLSENT);
|
||||
}
|
||||
if (status & (AT91C_UDP_RXSETUP
|
||||
| AT91C_UDP_RX_DATA_BK1 | AT91C_UDP_RX_DATA_BK0)) {
|
||||
if (status & AT91C_UDP_RXSETUP) {
|
||||
PRINTF("SETUP\n");
|
||||
ep->flags |= USB_EP_FLAGS_SETUP_PENDING;
|
||||
}
|
||||
if (ep->flags & USB_EP_FLAGS_DOUBLE) {
|
||||
ep->flags &= ~USB_EP_FLAGS_DOUBLE;
|
||||
} else {
|
||||
ep->flags &= ~USB_EP_FLAGS_RECEIVING;
|
||||
}
|
||||
if ( ep->flags & USB_EP_FLAGS_RECV_PENDING) {
|
||||
ep->flags |= USB_EP_FLAGS_DOUBLE;
|
||||
} else {
|
||||
ep->flags |= USB_EP_FLAGS_RECV_PENDING;
|
||||
}
|
||||
start_transfer(ep);
|
||||
}
|
||||
if (status & AT91C_UDP_TXCOMP) {
|
||||
PRINTF("Sent packet\n");
|
||||
if (ep->flags & USB_EP_FLAGS_DOUBLE) {
|
||||
ep->flags &= ~USB_EP_FLAGS_DOUBLE;
|
||||
} else {
|
||||
ep->flags &= ~USB_EP_FLAGS_TRANSMITTING;
|
||||
}
|
||||
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[hw_ep],0, AT91C_UDP_TXCOMP);
|
||||
if (ep->status & 0x01) {
|
||||
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[hw_ep],
|
||||
AT91C_UDP_FORCESTALL, AT91C_UDP_FORCESTALL);
|
||||
} else {
|
||||
start_transfer(ep);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
usb_set_ep_event_process(unsigned char addr, struct process *p)
|
||||
{
|
||||
USBEndpoint *ep = &usb_endpoints[EP_INDEX(addr)];
|
||||
ep->event_process = p;
|
||||
}
|
||||
|
||||
/* Select what process should be polled when a global event occurs */
|
||||
void
|
||||
usb_arch_set_global_event_process(struct process *p)
|
||||
{
|
||||
event_process = p;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
usb_arch_get_global_events(void)
|
||||
{
|
||||
unsigned int e;
|
||||
USB_DISABLE_INT;
|
||||
e = events;
|
||||
events = 0;
|
||||
USB_ENABLE_INT;
|
||||
return e;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
usb_get_ep_events(unsigned char addr)
|
||||
{
|
||||
unsigned int e;
|
||||
unsigned int ei = EP_HW_NUM(addr);
|
||||
USB_DISABLE_INT;
|
||||
e = usb_endpoints[ei].events;
|
||||
usb_endpoints[ei].events = 0;
|
||||
USB_ENABLE_INT;
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
usb_submit_recv_buffer(unsigned char ep_addr, USBBuffer *buffer)
|
||||
{
|
||||
USBBuffer **tailp;
|
||||
USBEndpoint *ep = &usb_endpoints[EP_INDEX(ep_addr)];
|
||||
if (!(ep->flags & USB_EP_FLAGS_ENABLED)) return;
|
||||
/* PRINTF("buffer: %p\n", ep->buffer); */
|
||||
/* dbg_drain(); */
|
||||
USB_DISABLE_INT;
|
||||
tailp = (USBBuffer**)&ep->buffer;
|
||||
while(*tailp) {
|
||||
tailp = &(*tailp)->next;
|
||||
}
|
||||
*tailp = buffer;
|
||||
while(buffer) {
|
||||
buffer->flags |= USB_BUFFER_SUBMITTED;
|
||||
buffer = buffer->next;
|
||||
}
|
||||
start_transfer(ep);
|
||||
|
||||
USB_ENABLE_INT;
|
||||
}
|
||||
|
||||
void
|
||||
usb_submit_xmit_buffer(unsigned char ep_addr, USBBuffer *buffer)
|
||||
{
|
||||
USBBuffer **tailp;
|
||||
USBEndpoint *ep = &usb_endpoints[EP_INDEX(ep_addr)];
|
||||
if (!(ep->flags & USB_EP_FLAGS_ENABLED)) return;
|
||||
/* PRINTF("usb_submit_xmit_buffer %d\n", buffer->left); */
|
||||
USB_DISABLE_INT;
|
||||
tailp = (USBBuffer**)&ep->buffer;
|
||||
while(*tailp) {
|
||||
tailp = &(*tailp)->next;
|
||||
}
|
||||
*tailp = buffer;
|
||||
while(buffer) {
|
||||
buffer->flags |= USB_BUFFER_SUBMITTED | USB_BUFFER_IN;
|
||||
buffer = buffer->next;
|
||||
}
|
||||
start_transfer(ep);
|
||||
USB_ENABLE_INT;
|
||||
}
|
||||
|
||||
void
|
||||
usb_arch_discard_all_buffers(unsigned char ep_addr)
|
||||
{
|
||||
USBBuffer *buffer;
|
||||
volatile USBEndpoint *ep = &usb_endpoints[EP_INDEX(ep_addr)];
|
||||
USB_DISABLE_EP_INT(EP_HW_NUM(ep_addr));
|
||||
buffer = ep->buffer;
|
||||
ep->buffer = NULL;
|
||||
|
||||
USB_ENABLE_EP_INT(EP_HW_NUM(ep_addr));
|
||||
while(buffer) {
|
||||
buffer->flags &= ~USB_BUFFER_SUBMITTED;
|
||||
buffer = buffer->next;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t
|
||||
usb_arch_get_ep_status(uint8_t addr)
|
||||
{
|
||||
if (EP_INDEX(addr) > USB_MAX_ENDPOINTS) return 0;
|
||||
return usb_endpoints[EP_INDEX(addr)].status;
|
||||
}
|
||||
|
||||
void
|
||||
usb_arch_set_configuration(uint8_t usb_configuration_value)
|
||||
{
|
||||
/* Nothing needs to be done */
|
||||
}
|
||||
|
||||
void
|
||||
usb_arch_control_stall(unsigned char addr)
|
||||
{
|
||||
if (EP_INDEX(addr) > USB_MAX_ENDPOINTS) return;
|
||||
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[EP_HW_NUM(addr)],
|
||||
AT91C_UDP_FORCESTALL, AT91C_UDP_FORCESTALL);
|
||||
}
|
||||
|
||||
/* Not for control endpoints */
|
||||
void
|
||||
usb_arch_halt_endpoint(unsigned char ep_addr, int halt)
|
||||
{
|
||||
if (EP_INDEX(ep_addr) > USB_MAX_ENDPOINTS) return;
|
||||
if (!usb_endpoints[EP_INDEX(ep_addr)].flags & USB_EP_FLAGS_ENABLED) return;
|
||||
*AT91C_UDP_IDR = 1<<EP_HW_NUM(ep_addr);
|
||||
if (halt) {
|
||||
usb_endpoints[EP_INDEX(ep_addr)].status |= 0x01;
|
||||
/* Delay stall if a transmission is i progress */
|
||||
if (!(usb_endpoints[EP_INDEX(ep_addr)].flags & USB_EP_FLAGS_TRANSMITTING)){
|
||||
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[EP_HW_NUM(ep_addr)],
|
||||
AT91C_UDP_FORCESTALL, AT91C_UDP_FORCESTALL);
|
||||
}
|
||||
} else {
|
||||
USBEndpoint *ep = &usb_endpoints[EP_INDEX(ep_addr)];
|
||||
ep->status &= ~0x01;
|
||||
*AT91C_UDP_IDR = 1<<EP_HW_NUM(ep_addr);
|
||||
UDP_SET_EP_CTRL_FLAGS(&AT91C_UDP_CSR[EP_HW_NUM(ep_addr)],
|
||||
0, AT91C_UDP_FORCESTALL);
|
||||
*AT91C_UDP_RSTEP = 1<<EP_HW_NUM(ep_addr);
|
||||
*AT91C_UDP_RSTEP = 0;
|
||||
|
||||
/* Restart transmission */
|
||||
start_transfer(&usb_endpoints[EP_INDEX(ep_addr)]);
|
||||
}
|
||||
*AT91C_UDP_IER = 1<<EP_HW_NUM(ep_addr);
|
||||
}
|
||||
|
||||
int
|
||||
usb_arch_send_pending(uint8_t ep_addr)
|
||||
{
|
||||
return usb_endpoints[EP_INDEX(ep_addr)].flags & USB_EP_FLAGS_TRANSMITTING;
|
||||
}
|
||||
|
||||
void
|
||||
usb_arch_set_address(unsigned char addr)
|
||||
{
|
||||
*AT91C_UDP_FADDR = AT91C_UDP_FEN | addr;
|
||||
*AT91C_UDP_GLBSTATE |= AT91C_UDP_FADDEN;
|
||||
}
|
||||
|
||||
void
|
||||
usb_arch_reset_int()
|
||||
{
|
||||
usb_arch_reset();
|
||||
notify_process(USB_EVENT_RESET);
|
||||
}
|
||||
|
||||
void
|
||||
usb_arch_suspend_int()
|
||||
{
|
||||
notify_process(USB_EVENT_SUSPEND);
|
||||
}
|
||||
|
||||
void
|
||||
usb_arch_resume_int()
|
||||
{
|
||||
notify_process(USB_EVENT_RESUME);
|
||||
}
|
||||
|
59
cpu/arm/at91sam7s/usb-interrupt.c
Normal file
59
cpu/arm/at91sam7s/usb-interrupt.c
Normal file
|
@ -0,0 +1,59 @@
|
|||
#include <AT91SAM7S64.h>
|
||||
#include <interrupt-utils.h>
|
||||
#include <usb-interrupt.h>
|
||||
#include <usb-api.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_EP0 | AT91C_UDP_EP1 | AT91C_UDP_EP2
|
||||
| AT91C_UDP_EP3)) {
|
||||
unsigned int ep_index;
|
||||
/* Handle enabled interrupts */
|
||||
for (ep_index = 0; ep_index < 4; ep_index++) {
|
||||
if (int_status & (1<<ep_index)) {
|
||||
usb_arch_transfer_complete(ep_index);
|
||||
}
|
||||
}
|
||||
} else if (int_status & AT91C_UDP_ENDBUSRES) {
|
||||
*AT91C_UDP_ICR = AT91C_UDP_ENDBUSRES;
|
||||
usb_arch_reset_int();
|
||||
} else if (int_status & AT91C_UDP_RXSUSP) {
|
||||
/* puts("Suspend"); */
|
||||
*AT91C_UDP_ICR = AT91C_UDP_RXSUSP;
|
||||
usb_arch_suspend_int();
|
||||
} else if (int_status & AT91C_UDP_RXRSM) {
|
||||
/* puts("Resume"); */
|
||||
*AT91C_UDP_ICR = AT91C_UDP_RXRSM;
|
||||
usb_arch_resume_int();
|
||||
} 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 {
|
||||
puts("Other USB interrupt");
|
||||
}
|
||||
/* dbg_putchar('<'); */
|
||||
|
||||
}
|
||||
|
||||
void NACKEDFUNC
|
||||
usb_int (void)
|
||||
{
|
||||
ISR_STORE();
|
||||
ISR_ENABLE_NEST();
|
||||
usb_int_safe();
|
||||
ISR_DISABLE_NEST();
|
||||
*AT91C_AIC_EOICR = 0;
|
||||
ISR_RESTORE();
|
||||
}
|
21
cpu/arm/at91sam7s/usb-interrupt.h
Normal file
21
cpu/arm/at91sam7s/usb-interrupt.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#ifndef __USB_INTERRUPT_H__0HRIPZ5SIA__
|
||||
#define __USB_INTERRUPT_H__0HRIPZ5SIA__
|
||||
|
||||
void
|
||||
usb_int (void);
|
||||
|
||||
void
|
||||
usb_arch_transfer_complete(unsigned int hw_ep);
|
||||
|
||||
void
|
||||
usb_arch_transfer_complete(unsigned int hw_ep);
|
||||
void
|
||||
usb_arch_reset_int();
|
||||
|
||||
void
|
||||
usb_arch_suspend_int();
|
||||
|
||||
void
|
||||
usb_arch_resume_int();
|
||||
|
||||
#endif /* __USB_INTERRUPT_H__0HRIPZ5SIA__ */
|
Loading…
Reference in a new issue