FreeCalypso > hg > freecalypso-sw
diff gsm-fw/services/ffs/task.c @ 212:3ebe6409e8bc
gsm-fw/services/ffs: task.c integrated
author | Michael Spacefalcon <msokolov@ivan.Harhan.ORG> |
---|---|
date | Mon, 06 Jan 2014 04:15:30 +0000 |
parents | |
children | fee45482aa2a |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gsm-fw/services/ffs/task.c Mon Jan 06 04:15:30 2014 +0000 @@ -0,0 +1,434 @@ +/****************************************************************************** + * Flash File System (ffs) + * Idea, design and coding by Mads Meisner-Jensen, mmj@ti.com + * + * FFS task. ONLY for target! + * + * $Id: task.c 1.48.1.1.1.24 Thu, 18 Dec 2003 10:50:52 +0100 tsj $ + * + ******************************************************************************/ + +#include "../../include/config.h" +#include "ffs.h" +#include "core.h" +#include "task.h" +#include "ffstrace.h" +#include "../../riviera/rvm/rvm_use_id_list.h" + +/****************************************************************************** + * Globals and function prototypes + ******************************************************************************/ + +extern UINT8 pcm_init(void); +void ffs_task(void); + +static effs_t ffs_init_status; +req_id_t request_id_last = 0; + +T_OS_MB_ID ffs_mb_id; +UINT16 ffs_addr_id; + +/****************************************************************************** + * FFS Test Task + ******************************************************************************/ + +// For this to work, change: +// 1. MAX_RVF_TASKS define in rvf_target.h + +// Note that the FFS_TEST_TASK_ID is set one too low! We assume we are lucky +// that no other task has the same ID... + +#if (WITH_TFFS == 1) + +#define FFS_TEST_STACK_SIZE 1024 + +#define FFS_TEST_TASK_ID (MAX_RVF_TASKS - 1 - 1) + +void ffs_test_task(void); +void test_init(int keepgoing); +int test_run(char *testname); + +static uint8 ffs_test_stack[FFS_TEST_STACK_SIZE]; + +// This is the string of test cases to run by calling test_run(). This +// string as written to from tmffs module. +char ffs_test_string[128]; + +// Delay for <delay> milliseconds +void tffs_delay(int delay) +{ + delay = 14 * delay / 64; // approx. same as division by 60/13 + OS_DELAY(delay); +} + +UINT32 rvf_get_tick_count(void); +// Timer functions for benchmarking +UINT32 tffs_timer_begin(void) +{ + return rvf_get_tick_count(); +} + +UINT32 tffs_timer_end(UINT32 time_begin) +{ + // return current time minus time_begin + UINT32 ticks; + + ticks = rvf_get_tick_count(); + + return (ticks - time_begin) * 60 / 13; +} + +void ffs_test_task(void) +{ + effs_t error; + + OS_DELAY(217); // wait approx. 1000ms + + ttw(str(TTrTest, "ffs_test_task()" NL)); + + while (1) { + OS_DELAY(217); // wait approx. 1000ms + + // Poll to see if we have tests to run... We know that the writer of + // ffs_test_string has a higher priority than us, so it is properly + // written when we reach here. + if (*ffs_test_string) { + test_init(0); + error = test_run(ffs_test_string); + *ffs_test_string = 0; + + if (error == 0) + ttw(str(TTrTest, "TEST succeeded" NL)); + else + ttw(ttr(TTrTest, "TEST cases failed: %d" NL, error)); + } + } +} + +#endif // End of WITH_TFFS + +/****************************************************************************** + * Target Platform Abstraction Functions + ******************************************************************************/ + +req_id_t request_id_get(void) +{ + extern uint32 int_disable(void); + extern void int_enable(uint32 tmp); + uint32 cprs; + + // We disable interrupt to avoid any other tasks to get the same id. + cprs = int_disable(); + request_id_last++; + + if (request_id_last < 0) + request_id_last = 0; + + int_enable(cprs); + + return request_id_last; +} + +void *target_malloc(unsigned int size) +{ + char *buf; + +#if (_RVF == 1) + if ((rvf_get_buf(ffs_mb_id, size, (T_RVF_BUFFER*) &buf)) == RVF_RED) + return 0; + else + return buf; +#else + return 0; +#endif +} + +void target_free(void *buf) +{ + int error; + +#if (_RVF == 1) + if ((error = OS_FREE(buf)) != OS_OK) + ttw(ttr(TTrFatal, "target_free() %d (FAILED)" NL, error)); +#endif +} + + +/****************************************************************************** + * FFS Blocking Call Handling + ******************************************************************************/ + +effs_t ffs_b_begin(struct ffs_blocking_s *fb, T_RVF_MUTEX *mutex, int *result) +{ + effs_t error; + + if ((error = rvf_initialize_mutex(mutex)) < 0) + return error; + + if ((error = rvf_lock_mutex(mutex)) < 0) // This will succeed + return error; + + fb->result = result; + fb->mutex = mutex; + + return EFFS_OK; +} + +effs_t ffs_b_end(T_RVF_MUTEX *mutex, int result) +{ + effs_t error; + + // Do not lock the mutex if the message send operation failed + if (result >= 0) + // This will block the task until the mutex has been released + if ((error = rvf_lock_mutex(mutex)) < 0) + return error; + + if ((error = rvf_unlock_mutex(mutex)) < 0) + return error; + + if ((error = rvf_delete_mutex(mutex)) < 0) + return error; + + return EFFS_OK; +} + +/****************************************************************************** + * FFS Task + ******************************************************************************/ +/* The below access to the intenal Nucleus variable "TCD_Interrupt_Level" is + * a workaround for a known Nucleus BUG (see CQ SWI-FIX-17560) */ + +void ffs_main_init() +{ + extern int TCD_Interrupt_Level; + int tmp_int_level; + ttr_init(TTrTask|TTrTest|TTrTestInfo); + //ttr_init(TTrTask|TTrTest|TTrTestInfo|TTrDrvErase|TTrDrvWrite|TTrTaskLow|TTrApi); + + tmp_int_level = TCD_Interrupt_Level; // Backup Int level + TCD_Interrupt_Level = 0xC0; // The Interrups are not yet enabled... + ffs_init_status = ffs_initialize(); + TCD_Interrupt_Level = tmp_int_level; // Restore Int level + +#if 0 + pcm_init(); // We have to call pcm_init() before G23 starts. +#endif +} + +void ffs_task_init(T_OS_MB_ID mbid, T_RVF_ADDR_ID addr_id) +{ + int error; + + ffs_mb_id = mbid; + ffs_addr_id = addr_id; + +#if (WITH_TFFS == 1) + error = + OS_CREATE_TASK((TASKPTR) ffs_test_task, FFS_TEST_TASK_ID, "TFFS", + ffs_test_stack, FFS_TEST_STACK_SIZE, + 249, // priority + 4, // ET4_TASK type + 0, // no time slicing + RUNNING); // start state + + ttw(ttr(TTrTask, "os_create_task('TFFS') %d" NL, error)); +#endif +} + +void ffs_task() +{ + extern int etm_ffs_init(void); + struct ffs_req_s *request; + T_FFS_FILE_CNF *confirm_file; + T_FFS_STREAM_CNF *confirm_stream; + T_RVF_MUTEX *mutex_p; + int error, free_mail, os_error = OS_OK; + uint16 revision, manufacturer_id, device_id; + uint32 base; + fd_t fdi; + char *temp_path; + req_id_t temp_id; + +#if (BOARD == 34) + // Non formatted FFS should be formatted + // So we don't have to use PCTM to format it + if (fs.initerror == EFFS_NOFORMAT) + { + ffs_format_nb("/", 0x2BAD, 0); + } + + ffs_InitRFCap(); +#endif + + ttr(TTrTask, "ffs_init() %d" NL, ffs_init_status); + + ffs_query(Q_FFS_REVISION, &revision); + ttr(TTrTask,"FFS revision: 0x%x" NL, revision); + + ffs_query(Q_DEV_MANUFACTURER, &manufacturer_id); + ffs_query(Q_DEV_DEVICE, &device_id); + ffs_query(Q_DEV_DRIVER, &revision); + ttr(TTrTask,"FFS device, driver: 0x%02x, 0x%04x, %d" NL, + manufacturer_id, device_id, revision); + + ffs_query(Q_DEV_BASE, &base); + ffs_query(Q_DEV_BLOCKS, &revision); + ttr(TTrTask,"FFS base, blocks: 0x%x, %d" NL, base, revision); + + ffs_query(Q_FFS_FORMAT_READ, &manufacturer_id); + ffs_query(Q_FFS_FORMAT_WRITE, &device_id); + ttr(TTrTask,"FFS format read, write: 0x%x, 0x%x" NL NL, + manufacturer_id, device_id); + + // If some blocks has been marked for reclaim, reclaim them now... + blocks_reclaim(); + + // We can only mkdir("pcm") *after* our mailbox has been allocated + // otherwise mkdir("pcm") will fail. + error = ffs_mkdir_nb("/pcm", 0); + +#if 0 + // Register FFS to ETM database + error = etm_ffs_init(); +#endif + + while (1) + { + OS_MAIL_WAIT(OS_MAIL_EVENT_MASK); + request = (struct ffs_req_s *) OS_MAIL_READ(); + + ttw(ttr(TTrTaskLow, "ffs_task(%d):" NL, request->cmd)); + switch (request->cmd) { + case WRITE: case SEEK: case CLOSE: case FTRUNC: case FDATASYNC: + ttw(ttr(TTrTaskLow, " fdi = %d" NL, request->fdi)); + // Save a local copy of fdi because the task we call later can + // modify it and we have to use the fdi if a callback is used + fdi = (fd_t)request->fdi; + break; + default: + ttw(ttr(TTrTaskLow, " name = %s" NL, request->path)); + break; + } + ttw(ttr(TTrTaskLow, " src = 0x%x" NL, request->src)); + ttw(ttr(TTrTaskLow, " size = %d" NL, request->size)); + + if (tr_query(TTrTaskDelays)) + OS_DELAY(5); + + switch (request->cmd) { + case NOP: error = EFFS_OK; break; + case FILE_WRITE: error = task_file_write(request); break; + case SYMLINK: error = task_symlink(request); break; + case MKDIR: error = task_mkdir(request); break; + case REMOVE: error = task_remove(request); break; + case RENAME: error = task_rename(request); break; + case FCONTROL: error = task_fcontrol(request); break; + case PREFORMAT: error = task_preformat(request); break; + case FORMAT: error = task_format(request); break; + case OPEN: error = task_open(request); break; + case WRITE: error = task_write(request); break; + case SEEK: error = task_seek(request); break; + case CLOSE: error = task_close(request); break; + case TRUNC: error = task_trunc(request); break; + case FTRUNC: error = task_ftrunc(request); break; + case FDATASYNC: error = task_fdatasync(request); break; + default: + ttr(TTrFatal, "FFS FATAL: bad request: %d" NL, request->cmd); + break; + } + + ttw(ttr(TTrTaskLow, "ffs_task(%d) %d" NL, request->cmd, error)); + if (tr_query(TTrTaskDelays)) + OS_DELAY(5); + + // Call-back to caller + mutex_p = 0; + if (request->cp) { + free_mail = 0; // don't free mail we will reuse it + // We reuse the mail we received for our call-back. Due to + // this reuse, we must be careful with the order of + // assignments. If this is a stream modify function use + // ffs_stream_cnf else use ffs_file_cnf + + temp_id = request->request_id; // Save id before we reuse the mail mem. + switch (request->cmd) { + case WRITE: case SEEK: case CLOSE: case FTRUNC: case FDATASYNC: + confirm_stream = (T_FFS_STREAM_CNF *) request; + confirm_stream->error = error; + confirm_stream->request_id = temp_id; + confirm_stream->fdi = fdi; + confirm_stream->header.msg_id = FFS_MESSAGE_OFFSET; + + if (request->cp->callback_func) { + request->cp->callback_func((T_FFS_STREAM_CNF *) + confirm_stream); + } + else if (request->cp->addr_id) { + os_error = OS_MAIL_SEND(request->cp->addr_id, + confirm_stream); + } + else { + ttr(TTrFatal, "FFS WARNING: empty return path" NL); + free_mail = 1; // free mail + } + break; + default: + temp_path = (char *) request->path; + confirm_file = (T_FFS_FILE_CNF *) request; + confirm_file->error = error; + confirm_file->request_id = temp_id; + confirm_file->path = temp_path; + confirm_file->header.msg_id = FFS_MESSAGE_OFFSET; + + if (request->cp->callback_func) { + request->cp->callback_func((T_FFS_FILE_CNF *) confirm_file); + } + + else if (request->cp->addr_id) { + os_error = OS_MAIL_SEND(request->cp->addr_id, + confirm_file); + } + else { + ttr(TTrFatal, "FFS WARNING: empty return path" NL); + free_mail = 1; // free mail + } + break; + } + + if (os_error != OS_OK) + ttr(TTrFatal, "FFS FATAL: os_send_msg() %d" NL, os_error); + } + + // Blocking handling / unlocking mutex + else if (request->fb) { + // Save the pointer to the mutex and the error value (allocated + // on the stack by the macro FFS_BLOCKING_BEGIN) + mutex_p = request->fb->mutex; + *request->fb->result = error; + free_mail = 1; // free mail + } + + else { + // The task must have been a non blocking without any callback + free_mail = 1; // free mail + } + + // Free the mail memory. Note that we always free it, except when we + // have successfully reused it for sending a mail call-back. + if (free_mail == 1) { + os_error = OS_FREE(request); + if (os_error != OS_OK) + ttr(TTrFatal, "FFS FATAL: os_free() %d" NL, os_error); + } + + // Blocking handling / unlocking mutex + if (mutex_p) { + // Wake up the caller task + if ((os_error = rvf_unlock_mutex(mutex_p)) < 0) + ttr(TTrFatal, "FFS FATAL: rvf_unlock_mutex() %d" NL, os_error); + } + + tr_bstat(); + } +}