www.pudn.com > drivers.rar > task.c


/****************************************************************************** 
 * 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 "board.cfg" 
 
#include "ffs/ffs.h" 
#include "ffs/board/core.h" 
#include "ffs/board/task.h" 
#include "ffs/board/ffstrace.h"  
 
#include "rvm/rvm_gen.h" 
#include "rvm/rvm_use_id_list.h" 
 
#include  
 
#include "swconfig.cfg" 
 
/****************************************************************************** 
 * 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; 
 
extern struct ffs_blocking_s; 
 
OS_MUTEX ffs_write_mutex; 
 
/****************************************************************************** 
 * 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(buf != NULL) 
   { 
      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); 
//	ttr_init(TTrAll); 
    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 
   
    pcm_init(); // We have to call pcm_init() before G23 starts. 
} 
 
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; 
} 
 
extern char ffs_initerror[5]; 
void ffs_task() 
{ 
    extern int etm_ffs_init(void); 
#if (LINEAR_FILE_SYSTEM) 
    extern int etm_lfs_init(void); 
#endif 
    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; 
 
	OS_INIT_MUTEX(&ffs_write_mutex); 
 
#if ((OP_WCP == 1) || (VIRTIO==1)) 
    // Non formatted FFS should be formatted 
    // So we don't have to use PCTM to format it 
    if (fs.initerror == EFFS_NOFORMAT) 
    { 
        ffs_preformat_nb(0xDEAD, 0); 
        ffs_format_nb("/", 0x2BAD, 0); 
    } 
 
    ffs_InitRFCap(); 
    ffs_InitSerialCfg(); 
#endif 
//fangcj revised in 2006-09-19 
    if (fs.initerror == EFFS_NOFORMAT) 
    { 
        ffs_preformat_nb(0xDEAD, 0); 
        ffs_format_nb("/", 0x2BAD, 0); 
    } 
//fangcj end 
    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); 
 
    ttr(TTrFatal, "**___**ffs_initerror:0x%x, 0x%x, 0x%x, 0x%x, 0x%x" NL,  
		ffs_initerror[0], ffs_initerror[1], ffs_initerror[2], ffs_initerror[3], ffs_initerror[4]); 
	// If some blocks has been marked for reclaim, reclaim them now... 
    if (fs.initerror >= 0) 
    	{ 
	ttr(TTrFatal, "blocks_reclaim() start........"); 
        blocks_reclaim(); 
	ttr(TTrFatal, "blocks_reclaim() end."); 
    	} 
 	else 
		ttr(TTrFatal, "else: fs.initerror = %d", fs.initerror); 
 
    // If there exist any replacement inodes, run inode reclaim as this 
    // reclaim removes the replacement inodes and we only have space for a 
    // limited number of replacement inodes 
    if (fs.repi_table[0] != 0) 
        inodes_reclaim(); 
 
    // We can only mkdir("pcm") *after* our mailbox has been allocated 
    // otherwise mkdir("pcm") will fail. 
    error = ffs_mkdir_nb("/pcm", 0); 
 
    // Register FFS and LFS to ETM database 
    error = etm_ffs_init(); 
#if (LINEAR_FILE_SYSTEM) 
    error = etm_lfs_init(); 
#endif 
//    ttr(TTrTask, "Start TFFS task" NL NL); 
//    rv_start_swe_and_check(TFFS_USE_ID, "TFFS"); // Note tested 
 
    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; 
#if (LINEAR_FILE_SYSTEM) 
        case LFS_OPEN:  error = task_lfs_open(request);  break; 
        case LFS_WRITE:  error = task_lfs_write(request);  break; 
        case LFS_CLOSE:  error = task_lfs_close(request);  break; 
        case LFS_REMOVE:  error = task_lfs_remove(request);  break; 
#endif 
        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) {  
            T_RV_RETURN mycp; 
            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   
 
            // Save cp and id before we reuse the mail mem. 
            memcpy(&mycp, request->cp, sizeof(mycp)); 
            temp_id = request->request_id;   
 
            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 (mycp.callback_func) { 
                    mycp.callback_func((T_FFS_STREAM_CNF *) confirm_stream); 
                } 
                else if (mycp.addr_id) { 
                    os_error = OS_MAIL_SEND(mycp.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 (mycp.callback_func) { 
                    mycp.callback_func((T_FFS_FILE_CNF *) confirm_file); 
                }    
 
                else if (mycp.addr_id) { 
                    os_error = OS_MAIL_SEND(mycp.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(); 
    } 
    OS_DELETE_MUTEX(&ffs_write_mutex); 
} 
 
#if (WITH_TFFS == 1) 
/****************************************************************************** 
 * FFS Test Task - Defines, globals and function prototypes 
 ******************************************************************************/ 
 
/// The size of the stack required to run the TFFS SWE. 
#define TFFS_STACK_SIZE         (1024) 
 
/// The size of the primary memory bank. 
#define TFFS_MB_PRIM_SIZE       (1024 * 65) 
 
/// The watermark of the primary memory bank. 
#define TFFS_MB_PRIM_WATERMARK  (TFFS_MB_PRIM_SIZE - 128) 
 
/// The total of memory required by the TFFS SWE. 
#define TFFS_POOL_SIZE  (TFFS_STACK_SIZE + TFFS_MB_PRIM_SIZE) 
 
#define TFFS_TASK_PRIORITY 248 
 
// NOTEME move the below 3 lines to one structure? 
T_RVF_ADDR_ID tffs_addr_id; 
T_OS_MB_ID    tffs_mb_id; 
char ffs_test_string[128]; 
 
void ffs_test_task(void); 
void test_init(int keepgoing); 
int  test_run(char *testname); 
UINT32 rvf_get_tick_count(void); 
 
/****************************************************************************** 
 * FFS Test Task 
 ****************************************************************************** 
 
 The following steps are needed to get the FFS test task running:  
 
 1. Type the following line in rvm_use_id_list.h: 
     #define  TFFS_USE_ID	BUILD_USE_ID( 0, TEST_USE_ID_CLUSTER_1, 0x0004) 
 
 2. Add the below lines in create_RVtask.c: 
     #ifdef RVM_FFS_SWE 
        rv_start_swe_and_check (TFFS_USE_ID, "TFFS"); 
     #endif 
 
 3. Add the below 2 line in the used xxx.mak file  
     export TFFS_STATE=1 
     TFFS_SOURCE=1 
 
 4. In ffs.mak: WITH_TFFS should be 1 and tffs.c, tcases.c and tdata.c 
    should be compiled in. 
 
 5. Compile and run the tests by typing 'tffs [test string]' in the TMSH shell. 
 
******************************************************************************/ 
 
// Delay for  milliseconds 
void tffs_delay(int delay) 
{ 
    delay = 14 * delay / 64; // approx. same as division by 60/13 
    OS_DELAY(delay); 
} 
 
// 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 *tffs_malloc(unsigned int size) 
{ 
    char *buf; 
 
    if ((rvf_get_buf(tffs_mb_id, size, (T_RVF_BUFFER*) &buf)) == RVF_RED) 
        return 0; 
    else 
        return buf; 
} 
 
T_RVM_RETURN tffs_start(void) 
{ 
    effs_t error; 
 
    OS_DELAY(217); // wait approx. 1000ms 
 
    ttw(str(TTrTest, "ffs_test_task() running" 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)); 
        } 
    } 
 
	return RVM_OK; 
} 
 
T_RVM_RETURN tffs_set_info(T_RVF_ADDR_ID    addr_id, 
						  T_RV_RETURN_PATH return_path[],  
						  T_RVF_MB_ID      bk_id_table[], 
						  T_RVM_CB_FUNC    call_back_error_ft) 
{ 
    tffs_addr_id = addr_id; 
    tffs_mb_id = bk_id_table[0]; 
    return RVM_OK; 
} 
 
T_RVM_RETURN tffs_null(void)  
{	 
    return RVM_OK; 
} 
 
T_RVM_RETURN tffs_get_info(T_RVM_INFO_SWE * swe_info) 
{ 
	/* The SWE is a Type 4 SWE */ 
	swe_info->swe_type = RVM_SWE_TYPE_4; 
 
	/* Used for info */ 
	memcpy(swe_info->type_info.type4.swe_name, "TFFS", sizeof("TFFS")); 
	swe_info->type_info.type4.version = BUILD_VERSION_NUMBER(0,1,0); 
 
	/* 
	 * This is the real way to indentify a SWE. 
	 * Look in: 
	 * - rvm_use_id_list.h if the SWE is part of the standard SDK. 
	 * - rvm_ext_use_id_list.h for custom/under development SWEs. 
	 */ 
	swe_info->type_info.type4.swe_use_id = TFFS_USE_ID; 
 
	/* Active SWE specific info */ 
	swe_info->type_info.type4.stack_size = TFFS_STACK_SIZE; 
	swe_info->type_info.type4.priority   = TFFS_TASK_PRIORITY; 
	/* End of specific */ 
 
	/* Memory bank info */ 
	swe_info->type_info.type4.nb_mem_bank = 1; 
	memcpy(swe_info->type_info.type4.mem_bank[0].bank_name, "TFFS_PRIM", sizeof("TFFS_PRIM")); 
	swe_info->type_info.type4.mem_bank[0].initial_params.size		= TFFS_MB_PRIM_SIZE; 
	swe_info->type_info.type4.mem_bank[0].initial_params.watermark	= TFFS_MB_PRIM_WATERMARK; 
	 
	swe_info->type_info.type4.nb_linked_swe = 0; 
 
	/* Set the return path: NOT USED. */ 
	swe_info->type_info.type4.return_path.callback_func	= NULL; 
	swe_info->type_info.type4.return_path.addr_id		= 0; 
 
	/* Generic functions */ 
	swe_info->type_info.type4.set_info		= tffs_set_info; 
	swe_info->type_info.type4.init			= tffs_null; 
	swe_info->type_info.type4.stop			= tffs_null; 
	swe_info->type_info.type4.kill			= tffs_null; 
	 
	/* Type 4 specific generic functions */ 
	swe_info->type_info.type4.core			= tffs_start; 
	/* End of specific */ 
 
	return RVM_OK; 
} 
 
#endif // End of WITH_TFFS