view src/cs/drivers/drv_app/ffs/board/task.c @ 636:57e67ca2e1cb

pcmdata.c: default +CGMI to "FreeCalypso" and +CGMM to model The present change has no effect whatsoever on Falconia-made and Openmoko-made devices on which /pcm/CGMI and /pcm/CGMM files have been programmed in FFS with sensible ID strings by the respective factories, but what should AT+CGMI and AT+CGMM queries return when the device is a Huawei GTM900 or Tango modem that has been converted to FreeCalypso with a firmware change? Before the present change they would return compiled-in defaults of "<manufacturer>" and "<model>", respectively; with the present change the firmware will self-identify as "FreeCalypso GTM900-FC" or "FreeCalypso Tango" on the two respective targets. This firmware identification will become important if someone incorporates an FC-converted GTM900 or Tango modem into a ZeroPhone-style smartphone where some high-level software like ofono will be talking to the modem and will need to properly identify this modem as FreeCalypso, as opposed to some other AT command modem flavor with different quirks. In technical terms, the compiled-in default for the AT+CGMI query (which will always be overridden by the /pcm/CGMI file in FFS if one is present) is now "FreeCalypso" in all configs on all targets; the compiled-in default for the AT+CGMM query (likewise always overridden by /pcm/CGMM if present) is "GTM900-FC" if CONFIG_TARGET_GTM900 or "Tango" if CONFIG_TARGET_TANGO or the original default of "<model>" otherwise.
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 19 Jan 2020 20:14:58 +0000
parents 945cf7f506b2
children
line wrap: on
line source

/******************************************************************************
 * 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_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;

extern struct ffs_blocking_s;

/******************************************************************************
 * 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
  
    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;

#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);

    // Register FFS to ETM database
    error = etm_ffs_init();

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