Moved and updated code for AT91SAM7S

This commit is contained in:
ksb 2009-07-11 14:22:45 +00:00
parent 1658d6b42c
commit 1f72d3ea32
32 changed files with 9799 additions and 0 deletions

View 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) }
}

View file

@ -0,0 +1,9 @@
/* Memory Definitions */
MEMORY
{
CODE (rx) : ORIGIN = 0x00100000, LENGTH = 128K
DATA (rw) : ORIGIN = 0x00200000, LENGTH = 32K
}
INCLUDE AT91SAM7S-ROM.ld

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,9 @@
/* Memory Definitions */
MEMORY
{
CODE (rx) : ORIGIN = 0x00100000, LENGTH = 64K
DATA (rw) : ORIGIN = 0x00200000, LENGTH = 16K
}
INCLUDE AT91SAM7S-ROM.ld

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,4 @@
BEGIN {
builtin["_exit"] = "void _exit()";
builtin["strlen"] = "unsigned long strlen()";
}

View 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
View 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__ */

View 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));
}

View 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__ */

View 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;
}

View 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;
}

View 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;
}

View 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
View 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__ */

View file

@ -0,0 +1,8 @@
SECTIONS
{
.text :
{
*(.text)
*(.rodata.* .rodata)
}
}

View 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;

View 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();
}

View 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();
}

View 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__ */

View 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;
}

View 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__ */

View 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;
}

View 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();
}

View 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();
}

View 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;
}
}

View 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__ */

View file

@ -0,0 +1,6 @@
#include <stdio.h>
void uip_log(char *msg)
{
printf("uip: %s\n", msg);
}

View 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);
}

View 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();
}

View 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__ */