view src/cs/drivers/drv_app/ffs/board/tmffs.c @ 624:012028896cfb

FFS dev.c, Leonardo target: Fujitsu MB84VF5F5F4J2 #if 0'ed out The FFS code we got from TI/Openmoko had a stanza for "Fujitsu MB84VF5F5F4J2 stacked device", using a fake device ID code that would need to be patched manually into cfgffs.c (suppressing and overriding autodetection) and using an FFS base address in the nCS2 bank, indicating that this FFS config was probably meant for the MCP version of Leonardo which allows for 16 MiB flash with a second bank on nCS2. We previously had this FFS config stanza conditionalized under CONFIG_TARGET_LEONARDO because the base address contained therein is invalid for other targets, but now that we actually have a Leonardo build target in FC Magnetite, I realize that the better approach is to #if 0 out this stanza altogether: it is already non-functional because it uses a fake device ID code, thus it is does not add support for more Leonardo board variants, instead it is just noise.
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 22 Dec 2019 21:24:29 +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 testmode interface
 *
 * $Id: tmffs.c 1.51 Thu, 18 Dec 2003 10:50:52 +0100 tsj $
 *
 ******************************************************************************/

#ifndef TARGET
#include "ffs.cfg"
#endif

#if (TARGET == 1)
#include "etm/etm.h"
#include "etm/etm_api.h"
#include "ffs/board/task.h"
#endif

#include "ffs/board/ffstrace.h"
#include "ffs/board/tmffs.h"
#include "ffs/ffs.h"
#include "ffs/pcm.h"

#include <string.h>

/******************************************************************************
 * Local globals for all protocols
 ******************************************************************************/

static int32 bufsize, tmpsize;
static uint8 stringsize;

effs_t ffs_initialize(void);
effs_t ffs_exit(void);

#define tmffs_put8(x)   *outp++ = x;
#define tmffs_put16(x) *outp++ = (x & 0xff); *outp++ = (x>>8);

#if (TARGET == 1)
int etm_ffs2(T_ETM_PKT *pkt, unsigned char *inp, int insize);

// Not in use
//#define tmffs_put32(x) tmffs_put16(x); tmffs_put16(x >> 16);


/******************************************************************************
 * TM FFS registration to ETM database
 *****************************************************************************/
/* Callback function registered in ETM database */
int etm_ffs1_pkt_receive(uint8 *data, int size)
{
    int mid;
    T_ETM_PKT *pkt;  

    ttw(ttr(TTrTmffs, "etm_ffs1_pkt_receive(*, %d)" NL, size)); 
    
    /* Create TestMode return Packet */
    if ((pkt = (T_ETM_PKT *) target_malloc(sizeof(T_ETM_PKT))) == NULL) {
        ttw(ttr(TTrTmffs, "etm_ffs1_pkt_receive(): Limit of memory bank reached" NL)); 
        return ETM_NOMEM;
    }
 
    // Max packet size for TM3 is 128 bytes
    size = tm_ffs(pkt->data, TM3_PACKET_SIZE, data, size);

    pkt->size   = size;
    pkt->status = ETM_OK;
    pkt->mid    = ETM_FFS1;
    
    etm_pkt_send(pkt);
    target_free(pkt);

    return ETM_OK;
}

/* Callback function registered in ETM database */
int etm_ffs2_pkt_receive(uint8 *data, int size)
{
    int status;
    T_ETM_PKT *pkt = NULL;  

    ttw(ttr(TTrTmffs, "etm_ffs2_pkt_receive(*, %d)" NL, size)); 

    /* Create TestMode return Packet */
    if ((pkt = (T_ETM_PKT *) target_malloc(sizeof(T_ETM_PKT))) == NULL) {
        ttw(ttr(TTrTmffs, "etm_ffs2_pkt_receive(): Limit of memory bank reached" NL)); 
        return ETM_NOMEM;
    } 
    
    status = etm_ffs2(pkt, data, size);
    return status;
}

/* Init of FFS in the ETM database */
int etm_ffs_init(void)
{
    int status;
    
    status = etm_register("FFS1", ETM_FFS1, 0, 0, etm_ffs1_pkt_receive);
    status = etm_register("FFS2", ETM_FFS2, 0, 0, etm_ffs2_pkt_receive);
    return status;
} 
#endif // (TARGET == 1)

/******************************************************************************
 * FFS1 Protocol 
 ******************************************************************************/

#ifndef TMFFS1 

int tm_ffs(unsigned char *outp, int outsize, unsigned char *inp, int insize)
{
	return -1;   // FIXME handle error better 
}

// Note these functions must be presented because ffs_query() use them but
// they are only valid if FFS1_PROTOCOL is used.
int tmffs_bufsize(void)
{
    return EFFS_NOSYS;
}

unsigned char *tmffs_bufaddr(void)
{
    return 0;
}

#else

#if (GSMLITE == 1)
#define TMFFS1_BUFFER_SIZE 4000 //previously 8192
#else
#define TMFFS1_BUFFER_SIZE 8192
#endif

#define TMFFS1_STRING_SIZE 127

/******************************************************************************
 * Macros
 ******************************************************************************/

#define tmffs1_putdata(outp, src, size) \
    tmffs_put8(FPI_DATA); \
    tmffs_put16(size); \
    memcpy(outp, src, size); \
    outp += size;

/******************************************************************************
 * Local globals
 ******************************************************************************/

static unsigned char buffer[TMFFS1_BUFFER_SIZE];
static bufindex;

static char string[TMFFS1_STRING_SIZE];

static effs_t tm_ffs_overflowck(void)
{
    if (bufsize    > TMFFS1_BUFFER_SIZE ||
        stringsize > TMFFS1_STRING_SIZE)
        return EFFS_TOOBIG;

    return EFFS_OK;
}


/******************************************************************************
 * tm_ffs
 ******************************************************************************/

/**
 * NOTEME: This has been introduced when the ffs 1MB device limit was
 * broken. This made location_t go from uint16 to uint32, messing up
 * with PCTM.  
 *
 * This makes the xstat_s look the same to PCTM PC side, though
 * location will be forced to 0.
 */
void hack_xstat_2_look_like_old_xstat(struct xstat_s *xstat)
{
  int i;
  char *location;

  xstat->location = 0;
  
  for (location = (char *) &(xstat->location) + 2; location <= (char *) &(xstat->sequence); location++)
    *location = location[2];
}

// Parse input message and execute function. Then fill output buffer with
// return values from the called function and transmit the message.  Return
// number of bytes inserted into output buffer. If return value is negative,
// it represents an error code.
int tm_ffs(unsigned char *outp, int outsize, unsigned char *inp, int insize)
{
    int error;
    tmffs_cid_t fid;

    unsigned char *outp_start = outp;
    unsigned char *inp_start  = inp;

    static uint8   i8[2]; static uint16 i8i;
    static uint16 i16[2]; static uint16 i16i;
    static uint32 i32[2]; static uint16 i32i;

    tw(tr(TR_BEGIN, TrTmffs, "TMFFS:\n"));

    while((fid = *inp++) != FPI_END)
    {
        switch(fid)
        {
            /**********************************************************
             * Generic Protocol Functions
             **********************************************************/

        case FPI_BEGIN:
            // for (i8i = 0; i8i < TMFFS1_STRING_SIZE; i8i++) // DEBUG
            //     string[i8i] = '#';
            // for (i8i = 0; i8i < TMFFS1_BUFFER_SIZE; i8i++) // DEBUG
            //     buffer[i8i] = '$';
            i8i = i16i = i32i = bufsize = stringsize = 0;
            bufindex = 0;
             i8[0] =  i8[1] = 0;
            i16[0] = i16[1] = 0;
            i32[0] = i32[1] = 0;
            string[0] = buffer[0] = 0;
            tw(tr(TR_FUNC, TrTmffs, "FPI_BEGIN\n"));
            ttw(ttr(TTrTmffs, "tm1" NL));
            break;
        case FPI_TMFFS_VERSION:
            // NULL -> UINT16
            tmffs_put16(TMFFS1_VERSION);
            break;

        case FPI_INT8:
            i8[i8i++] = inp[0]; inp += 1;
            tw(tr(TR_FUNC, TrTmffs, "FPI_INT8(%d/0x%x)\n",
                  i8[i8i-1], i8[i8i-1]));
            ttw(ttr(TTrTmffs, "tm_i8" NL));
            break;
        case FPI_INT16:
            i16[i16i++] = (inp[0]) | (inp[1] << 8); inp += 2;
            tw(tr(TR_FUNC, TrTmffs, "FPI_INT16(%d/0x%x)\n",
                  i16[i16i-1], i16[i16i-1]));
            ttw(ttr(TTrTmffs, "tm_i16" NL));
            break;
        case FPI_INT32:
            i32[i32i++] = inp[0] | (inp[1] << 8)
                | (inp[2] << 16) | (inp[3] << 24);
            inp += 4;
            tw(tr(TR_FUNC, TrTmffs, "FPI_INT32(%d/0x%x)\n",
                  i32[i32i-1], i32[i32i-1]));
            ttw(ttr(TTrTmffs, "tm_i32" NL));
            break;
        case FPI_BUFFER:
            bufsize = inp[0] | (inp[1] << 8); inp += 2;
            tw(tr(TR_FUNC, TrTmffs, "FPI_BUFFER(%d)\n", bufsize));
            ttw(ttr(TTrTmffs, "tm_buf" NL));
            break;
        case FPI_DATA:
            bufsize = inp[0] | (inp[1] << 8); inp += 2;
            memcpy(buffer, inp, bufsize); inp += bufsize;
            tw(tr(TR_FUNC, TrTmffs, "FPI_DATA(%d)\n", bufsize));
            ttw(ttr(TTrTmffs, "tm_data" NL));
            break;
        case FPI_STRBUF:
            // string buffer size MUST include null-terminator!
            stringsize = inp[0]; inp += 1;
            tw(tr(TR_FUNC, TrTmffs, "FPI_STRBUF(%d)\n", stringsize));
            ttw(ttr(TTrTmffs, "tm_sbuf" NL));
            break;
        case FPI_STRING:
            // stringsize MUST include null-terminator!
            // <INT8>, <BYTES> -> NULL (or ERROR)
            stringsize = inp[0]; inp += 1;
            if (stringsize <= TMFFS1_STRING_SIZE)
                memcpy(string, inp, stringsize);
            inp += stringsize;
            tw(tr(TR_FUNC, TrTmffs, "FPI_STRING(%d,'%s')\n",
                  stringsize, string));
            ttw(ttr(TTrTmffs, "tm_s" NL));
            break;

        case FPI_BUFREAD:
            // <INT16> -> DATA
            tmpsize = inp[0] | (inp[1] << 8); inp += 2;
            tw(tr(TR_FUNC, TrTmffs, "FPI_BUF_READ(%d)\n", tmpsize));
            tmffs1_putdata(outp, &buffer[bufindex], tmpsize);
            bufindex += tmpsize;
            ttw(ttr(TTrTmffs, "tm_bufrd" NL));
            break;
        case FPI_BUFWRITE:
            // <INT16>, <BYTES> -> NULL (or ERROR)
            tmpsize = inp[0] | (inp[1] << 8); inp += 2;
            tw(tr(TR_FUNC, TrTmffs, "FPI_BUF_WRITE(%d)\n", tmpsize));
            if (bufsize + tmpsize <= TMFFS1_BUFFER_SIZE)
                memcpy(&buffer[bufsize], inp, tmpsize);
            inp += tmpsize;
            bufsize += tmpsize;
            ttw(ttr(TTrTmffs, "tm_bufwr" NL));
            break;
        case FPI_BUFSET:
            bufindex = inp[0] | (inp[1] << 8); inp += 2;
            tw(tr(TR_FUNC, TrTmffs, "FPI_BUF_SET(%d)\n", bufindex));
            ttw(ttr(TTrTmffs, "tm_bufset" NL));
            break;

            /**********************************************************
             * FFS Functions
             **********************************************************/

        case FPI_PREFORMAT:
            // NULL -> ERROR
            if ((error = tm_ffs_overflowck()) == EFFS_OK)
                error = ffs_preformat_nb(i16[0], 0);
            if (error > 0) 
                error = 0;  // ignore request id
            tmffs_put8(error);
            tw(tr(TR_FUNC, TrTmffs, "FPI_PREFORMAT(0x%x)\n", i16[0]));
            ttw(ttr(TTrTmffs, "tm_pfmt" NL));
            break;
        case FPI_FORMAT:
            // STRING -> ERROR
            if ((error = tm_ffs_overflowck()) == EFFS_OK)
                error = ffs_format_nb(&string[0], i16[0], 0);
            if (error > 0) 
                error = 0;  // ignore request id
            tmffs_put8(error);
            tw(tr(TR_FUNC, TrTmffs, "FPI_FORMAT(0x%x)\n", i16[0]));
            ttw(ttr(TTrTmffs, "tm_fmt" NL));
            break;


        case FPI_FCREATE:
            // STRING, DATA -> ERROR
            if ((error = tm_ffs_overflowck()) == EFFS_OK)
                error = ffs_fcreate_nb(string, buffer, bufsize, 0);
            if (error > 0) 
                error = 0;  // ignore request id
            tmffs_put8(error);
            tw(tr(TR_FUNC, TrTmffs, "FPI_FCREATE('%s', 0x%x, %d/0x%x)\n",
                  string, buffer, bufsize, bufsize));
            ttw(ttr(TTrTmffs, "tm_fcr" NL));
            break;
        case FPI_FUPDATE:
            // STRING, DATA -> ERROR
            if ((error = tm_ffs_overflowck()) == EFFS_OK)
                error = ffs_fupdate_nb(string, buffer, bufsize, 0);
            if (error > 0) 
                error = 0;  // ignore request id
            tmffs_put8(error);
            tw(tr(TR_FUNC, TrTmffs, "FPI_FUPDATE('%s', 0x%x, %d/0x%x)\n",
                  string, buffer, bufsize, bufsize));
            ttw(ttr(TTrTmffs, "tm_fup" NL));
            break;
        case FPI_FWRITE:
            // STRING, DATA -> ERROR
            if ((error = tm_ffs_overflowck()) == EFFS_OK)
                error = ffs_fwrite_nb(string, buffer, bufsize, 0);
            if (error > 0) 
                error = 0;  // ignore request id
            tmffs_put8(error);
            tw(tr(TR_FUNC, TrTmffs, "FPI_FWRITE('%s', 0x%x, %d/0x%x)\n",
                  string, buffer, bufsize, bufsize));
            ttw(ttr(TTrTmffs, "tm_fwr" NL));
            break;
        case FPI_FREAD:
            // STRING, BUFFER -> ERROR
            if ((error = tm_ffs_overflowck()) == EFFS_OK)
                error = ffs_file_read(string, buffer, TMFFS1_BUFFER_SIZE);
            // Because a 32-bit integer is returned, we have to saturate it
            // into an 8-bit value.
            if (error >= 0)
                error = 0;
            tmffs_put8(error);
            tw(tr(TR_FUNC, TrTmffs, "FPI_FREAD('%s', 0x%x, %d/0x%x)\n",
                  string, buffer, bufsize, bufsize));
            ttw(ttr(TTrTmffs, "tm_frd" NL));
            break;
        case FPI_REMOVE:
            // STRING -> ERROR
            if ((error = tm_ffs_overflowck()) == EFFS_OK)
                error = ffs_remove_nb(string, 0);
            if (error > 0) 
                error = 0;  // ignore request id
            tmffs_put8(error);
            tw(tr(TR_FUNC, TrTmffs, "FPI_REMOVE()\n"));
            ttw(ttr(TTrTmffs, "tm_rm" NL));
            break;


        case FPI_MKDIR:
            // STRING -> ERROR
            if ((error = tm_ffs_overflowck()) == EFFS_OK)
                error = ffs_mkdir_nb(string, 0);
            if (error > 0) 
                error = 0;  // ignore request id
            tmffs_put8(error);
            tw(tr(TR_FUNC, TrTmffs, "FPI_MKDIR()\n"));
            ttw(ttr(TTrTmffs, "tm_mkd" NL));
            break;
        case FPI_OPENDIR:
            // STRING, BUFFER -> ERROR, DATA
            if ((error = tm_ffs_overflowck()) == EFFS_OK)
                error = ffs_opendir(string, (struct dir_s *) buffer);
            // Because a 32-bit integer is returned, we have to saturate it
            // into an 8-bit value.
            if (error >= 0)
                error = 0;
            tmffs_put8(error);
            tmffs1_putdata(outp, buffer, sizeof(struct dir_s));
            tw(tr(TR_FUNC, TrTmffs, "FPI_OPENDIR()\n"));
            ttw(ttr(TTrTmffs, "tm_od" NL));
            break;
        case FPI_READDIR:
            // DATA, STRBUF -> ERROR, DATA, STRING
            string[0] = 0;
            if ((error = tm_ffs_overflowck()) == EFFS_OK)
                error = ffs_readdir((struct dir_s *) buffer, string, stringsize);

			// Saturate error(i) in order to let it fit in type int8.
			if (error > 127)
				error = 127;
            tmffs_put8(error);
            tmffs1_putdata(outp, buffer, sizeof(struct dir_s));
            stringsize = strlen(string) + 1;
            tmffs_put8(FPI_STRING); // put directory entry's name...
            tmffs_put8(stringsize);
            memcpy(outp, string, stringsize);
            outp += stringsize;
            tw(tr(TR_FUNC, TrTmffs, "FPI_READDIR()\n"));
            ttw(ttr(TTrTmffs, "tm_rdd" NL));
            break;


        case FPI_STAT:
            // STRING, BUFFER -> ERROR, DATA 
            if ((error = tm_ffs_overflowck()) == EFFS_OK)
                error = ffs_stat(&string[0], (struct stat_s *) buffer);
            tmffs_put8(error);
            tmffs1_putdata(outp, buffer, sizeof(struct stat_s));
            tw(tr(TR_FUNC, TrTmffs, "FPI_STAT()\n"));
            ttw(ttr(TTrTmffs, "tm_st" NL));
            break;
        case FPI_LINKSTAT:
            // STRING, BUFFER -> ERROR, DATA
            if ((error = tm_ffs_overflowck()) == EFFS_OK)
                error = ffs_xlstat(&string[0], (struct xstat_s *) buffer);
            tmffs_put8(error);

            hack_xstat_2_look_like_old_xstat((struct xstat_s *) buffer);

            tmffs1_putdata(outp, buffer, sizeof(struct xstat_s) - 2);
            tw(tr(TR_FUNC, TrTmffs, "FPI_()\n"));
            ttw(ttr(TTrTmffs, "tm_lst" NL));
            break;


        case FPI_SYMLINK:
            // STRING, DATA -> ERROR
            if ((error = tm_ffs_overflowck()) == EFFS_OK)
                error = ffs_symlink_nb(string, (char *) buffer, 0);
            if (error > 0) 
                error = 0;  // ignore request id
            tmffs_put8(error);
            tw(tr(TR_FUNC, TrTmffs, "FPI_SYMLINK()\n"));
            ttw(ttr(TTrTmffs, "tm_sym" NL));
            break;
        case FPI_READLINK:
            // STRING, BUFFER -> ERROR, DATA
            if ((error = tm_ffs_overflowck()) == EFFS_OK)
                error = ffs_readlink(string, (char *) buffer, TMFFS1_BUFFER_SIZE);
            // Because a 32-bit integer is returned, we have to saturate it
            // into an 8-bit value.
            if (error >= 0)
                error = 0;
            tmffs_put8(error);
            tmffs1_putdata(outp, buffer, bufsize); // put link contents
            tw(tr(TR_FUNC, TrTmffs, "FPI_READLINK()\n"));
            ttw(ttr(TTrTmffs, "tm_rdl" NL));
            break;


        case FPI_QUERY:
            // INT8 -> ERROR, DATA
            error = ffs_query(i8[0], buffer);
            tmffs_put8(error);
            tmffs1_putdata(outp, buffer, 16);
            tw(tr(TR_FUNC, TrTmffs, "FPI_QUERY()\n"));
            ttw(ttr(TTrTmffs, "tm_q" NL));
            break;
        case FPI_FCONTROL:
            // STRING INT8 INT32 -> ERROR
            if ((error = tm_ffs_overflowck()) == EFFS_OK)
                error = ffs_fcontrol_nb(string, i8[0], i32[0], 0);
            if (error > 0) 
                error = 0;  // ignore request id
            tmffs_put8(error);
            tw(tr(TR_FUNC, TrTmffs, "FPI_FCONTROL()\n"));
            ttw(ttr(TTrTmffs, "tm_fc" NL));
            break;

        case FPI_INIT:
            // NULL -> ERROR
            error =ffs_initialize();
            tmffs_put8(error);
            tw(tr(TR_FUNC, TrTmffs, "FPI_INIT()\n"));
            ttw(ttr(TTrTmffs, "tm_init" NL));
            break;
        case FPI_EXIT:
            // NULL -> ERROR
            error = ffs_exit();
            tmffs_put8(error);
            tw(tr(TR_FUNC, TrTmffs, "FPI_EXIT()\n"));
            ttw(ttr(TTrTmffs, "tm_exit" NL));
            break;


        case FPI_TFFS:
        {
            // STRING -> ERROR
#if (WITH_TFFS == 1)
            extern char ffs_test_string[]; // defined in task.c

            memcpy(ffs_test_string, string, stringsize);
            tw(tr(TR_FUNC, TrTmffs, "FPI_TFFS()\n"));
            ttw(ttr(TTrTmffs, "tm_tffs" NL));
#else
            tmffs_put8(EFFS_NOSYS);
#endif            
            break;
        }
        default:
            tw(tr(TR_FUNC, TrTmffs, "ERROR: Unknown tmffs protocol code\n"));
            ttw(ttr(TTrTmffs, "tm?" NL));
            break;
        }
        // check if we read beyond buffer end
        if (inp > inp_start + insize) {
            tw(tr(TR_FUNC, TrTmffs, "ERROR: Read beyond end of input buffer\n"));
            ttw(ttr(TTrTmffs, "tm_fatal" NL));
            // NOTEME: We really should reset output buffer and put a return
            // code that tells us what went wrong!
            return 0;
        }
    }

    tw(tr(TR_END, TrTmffs, ""));

    return outp - outp_start;
}

int tmffs_bufsize(void)
{
    return TMFFS1_BUFFER_SIZE;
}

unsigned char *tmffs_bufaddr(void)
{
    return buffer;
}

#endif // TMFFS1 

/******************************************************************************
 * FFS2 protocol  
 ******************************************************************************/

#ifndef TMFFS2

#if (TARGET == 1)

int etm_ffs2(T_ETM_PKT *pkt, unsigned char *inp, int insize)
{
	int error;

	tw(tr(TR_BEGIN, TrTmffs, "FFS2 protocol not represented in target\n"));
	error = -1;  // FIXME other error?

#if 0  // Note we can only use this if etm is in target
	// We return a packet instead of waiting for timeout.
	pkt->size =  0;
    pkt->status = -error;       
    pkt->mid = ETM_FFS2;
    etm_pkt_send(pkt);
#endif

    target_free(pkt);
    tw(tr(TR_END, TrTmffs, ""));

	return error;
}

#endif // (TARGET == 1)

#else

#define TMFFS_BUFFER_SIZE 256   // FIXME change to packet size
#define TMFFS_STRING_SIZE 127

/******************************************************************************
 * Macros
 ******************************************************************************/

#define tmffs_get8() inp[0]; inp += 1; 
#define tmffs_get16() (inp[0]) | (inp[1] << 8); inp += 2; 
#define tmffs_get32()  inp[0] | (inp[1] << 8) | (inp[2] << 16)\
                       | (inp[3] << 24); inp += 4; 

#define tmffs_getdata()    bufsize = inp[0]; inp += 1; \
                           memcpy(buffer, inp, bufsize); inp += bufsize;


/******************************************************************************
 * Helper function
 ******************************************************************************/

// If size is less than zero it is because of a error and we dont have to put any
// data if size is returned in status.
int tmffs_putdata(unsigned char **buf, unsigned char *src, int size) 
{
 	unsigned char *p = *buf;

	if (size > 0) {
		*p++ = size;
		memcpy(p, src, size); 
		*buf += 1 + size;
	}
	return size;
}

int tmffs_putstring(unsigned char **buf, char *src, int size) 
{
	unsigned char *p = *buf;

	if (size > 0) {
		*p++ = size;
		memcpy(p, src, size); 
		*buf += 1 + size;
	}
	return size;
}

int tmffs_getstring(unsigned char ** buf, char *string)
{
	unsigned char *p = *buf;
	
	stringsize = *p++;

	if (stringsize > TMFFS_STRING_SIZE) 
		return EFFS_TOOBIG;

	memcpy(string, p, stringsize);
	*buf += 1 + stringsize;

	return stringsize;
}

/******************************************************************************
 * tm_ffs
 ******************************************************************************/

// Parse input message and execute function. Then fill output buffer with
// return values from the called function and transmit the message.  Return
// number of bytes inserted into output buffer. If return value is negative,
// it represents an error code.
int etm_ffs2(T_ETM_PKT *pkt, unsigned char *inp, int insize)
{
	tmffs2_cid_t fid;
	unsigned char buffer[TMFFS_BUFFER_SIZE];
	char string[TMFFS_STRING_SIZE];

    unsigned char *outp_start;
    unsigned char *inp_start  = inp;
	unsigned char *outp;

	int error = 0, i, fdi, size, param, flags;
	uint8 type;

	bufsize = stringsize = tmpsize = 0;

	tw(tr(TR_BEGIN, TrTmffs, "TmFFS2\n"));
    
	outp_start = outp = pkt->data;
	
	fid = *inp++;
	ttw(ttr(TTrTmffs, "etm_ffs2 0x%x" NL, fid));
	switch(fid)
	{
		/**********************************************************
		 * Generic Protocol Functions
		 **********************************************************/

	case TMFFS_VERSION:
		tmffs_put16(TMFFS2_VERSION);
		break;

		/**********************************************************
		 * FFS Functions
		 **********************************************************/

	case TMFFS_PREFORMAT:
		param = tmffs_get16();
		error = ffs_preformat(param);	
		tw(tr(TR_FUNC, TrTmffs, "TMFFS_PREFORMAT(0x%x)\n", param));
		ttw(ttr(TTrTmffs, "tm_pfmt" NL));
		break;
	case TMFFS_FORMAT: 
		error = tmffs_getstring(&inp, string);
		param = tmffs_get16();
		if (error >= 0)
			error = ffs_format(&string[0], param);	
		tw(tr(TR_FUNC, TrTmffs, "TMFFS_FORMAT(0x%x)\n", param));
		ttw(ttr(TTrTmffs, "tm_fmt" NL));	
		break;

		
	case TMFFS_FILE_WRITE:
		error = tmffs_getstring(&inp, string);
		tmffs_getdata();
		flags = tmffs_get8();
		if (error >= 0)
			error = ffs_file_write(string, buffer, bufsize, flags);
		ttw(ttr(TTrTmffs, "tm_fwr" NL));
		break;


	case TMFFS_FILE_READ:
		error = tmffs_getstring(&inp, string);
		bufsize = tmffs_get8();
		if (error >= 0)
			size = ffs_file_read(string, buffer, bufsize);
		error = tmffs_putdata(&outp, &buffer[0], size);
		tw(tr(TR_FUNC, TrTmffs, "TMFFS_FREAD('%s', 0x%x, %d/0x%x)\n",
			  string, buffer, bufsize, bufsize));
		ttw(ttr(TTrTmffs, "tm_frd" NL));
		break;
	case TMFFS_REMOVE:
		error = tmffs_getstring(&inp, string);
		if (error >= 0)
			error = ffs_remove(string);
		tw(tr(TR_FUNC, TrTmffs, "TMFFS_REMOVE()\n"));
		ttw(ttr(TTrTmffs, "tm_rm" NL));
		break;


	case TMFFS_OPEN:
		error = tmffs_getstring(&inp, string);
		flags = tmffs_get8();
		if (error >= 0)
			error = ffs_open(string, flags);
		tmffs_put8(error); // fdi
		tw(tr(TR_FUNC, TrTmffs, "TMFFS_OPEN('%s', %d)\n", string, flags));
		ttw(ttr(TTrTmffs, "tm_open" NL));
		break;
	case TMFFS_CLOSE:
		fdi = tmffs_get8(); 
		error = ffs_close(fdi);
		tw(tr(TR_FUNC, TrTmffs, "TMFFS_CLOSE(%d)\n", fdi));
		ttw(ttr(TTrTmffs, "tm_close" NL));
		break;
	case TMFFS_WRITE:
		fdi = tmffs_get8(); 
		tmffs_getdata(); 
		error = ffs_write(fdi, buffer, bufsize);
		tmffs_put8(error); // put size
		tw(tr(TR_FUNC, TrTmffs, "TMFFS_WRITE(%d, %d)\n", fdi, bufsize));
		ttw(ttr(TTrTmffs, "tm_write" NL));
		break;
	case TMFFS_READ:
		fdi = tmffs_get8(); 
		size = tmffs_get8();
		size = ffs_read(fdi, &buffer[0], size);
		error =	tmffs_putdata(&outp, &buffer[0], size);
		tw(tr(TR_FUNC, TrTmffs, "TMFFS_READ(%d, %d)\n", fdi, size));
		ttw(ttr(TTrTmffs, "tm_read" NL));
		break;


	case TMFFS_MKDIR:
		error = tmffs_getstring(&inp, string);
		if (error >= 0)
			error = ffs_mkdir(string);
		tw(tr(TR_FUNC, TrTmffs, "TMFFS_MKDIR()\n"));
		ttw(ttr(TTrTmffs, "tm_mkd" NL));
		break;
	case TMFFS_OPENDIR:
		error = tmffs_getstring(&inp, string);
		if (error >= 0) { 
			error = ffs_opendir(string, (struct dir_s *) buffer);
			tmffs_put8(error); // Note: we must put error/number of objects.
		}
		if (error >= 0)
			tmffs_putdata(&outp, buffer, sizeof(struct dir_s));
		
		tw(tr(TR_FUNC, TrTmffs, "TMFFS_OPENDIR()\n"));
		ttw(ttr(TTrTmffs, "tm_od" NL));
		break;
	case TMFFS_READDIR:
		tmffs_getdata();
		stringsize = tmffs_get8();		
		error = ffs_readdir((struct dir_s *) buffer, string, stringsize);
		tmffs_put8(error); // Note: we have to return bytes read.
		if (error >= 0) {
			tmffs_putdata(&outp, buffer, sizeof(struct dir_s));
			stringsize = strlen(string) + 1;			
			tmffs_putstring(&outp, string, stringsize);
		}
		tw(tr(TR_FUNC, TrTmffs, "TMFFS_READDIR()\n"));
		ttw(ttr(TTrTmffs, "tm_rdd" NL));
		break;

	case TMFFS_STAT:
		error = tmffs_getstring(&inp, string);
		if (error >= 0) 
			error = ffs_stat(string, (struct stat_s *) buffer);
		if (error >= 0)
			tmffs_putdata(&outp, buffer, sizeof(struct stat_s));
		
		tw(tr(TR_FUNC, TrTmffs, "TMFFS_STAT()\n"));
		ttw(ttr(TTrTmffs, "tm_st" NL));
		break;
	case TMFFS_XLSTAT:
		error = tmffs_getstring(&inp, string);
		if (error >= 0)
			error = ffs_xlstat(&string[0], (struct xstat_s *) buffer);
		if (error >= 0)
			tmffs_putdata(&outp, buffer, sizeof(struct xstat_s));
		tw(tr(TR_FUNC, TrTmffs, "TMFFS_()\n"));
		ttw(ttr(TTrTmffs, "tm_xlst" NL));
		break;


	case TMFFS_SYMLINK:
		error = tmffs_getstring(&inp, string);
		tmffs_getdata();
		if (error >= 0)
			error = ffs_symlink(string, (char *) buffer);
		tw(tr(TR_FUNC, TrTmffs, "TMFFS_SYMLINK()\n"));
		ttw(ttr(TTrTmffs, "tm_sym" NL));
		break;
	case TMFFS_READLINK:
		error = tmffs_getstring(&inp, string);
		tmffs_getdata();
		if (error >= 0) {
			size = ffs_readlink(string, (char *) buffer, TMFFS_BUFFER_SIZE);
			error = tmffs_putdata(&outp, buffer, size); // put link contents
		}
		tw(tr(TR_FUNC, TrTmffs, "TMFFS_READLINK()\n"));
		ttw(ttr(TTrTmffs, "tm_rdl" NL));
		break;


	case TMFFS_QUERY:
		param = tmffs_get8();
		error = ffs_query(param, buffer);
		if (error >= 0)
			tmffs_putdata(&outp, buffer, 16);
		tw(tr(TR_FUNC, TrTmffs, "TMFFS_QUERY(%d)\n", param));
		ttw(ttr(TTrTmffs, "tm_q" NL));
		break;
	case TMFFS_FCONTROL:
		error = tmffs_getstring(&inp, string);
		type = tmffs_get8();
		param = tmffs_get32();
		if (error >= 0)
			error = ffs_fcontrol(string, type, param);
		tw(tr(TR_FUNC, TrTmffs, "TMFFS_FCONTROL()\n"));
		ttw(ttr(TTrTmffs, "tm_fc" NL));
		break;

	case TMFFS_TFFS:
	{
#if (WITH_TFFS == 1)
		extern char ffs_test_string[]; // defined in task.c
		error = tmffs_getstring(&inp, string);
		memcpy(ffs_test_string, string, stringsize);
		tw(tr(TR_FUNC, TrTmffs, "TMFFS_TFFS()\n"));
		ttw(ttr(TTrTmffs, "tm_tffs" NL));
		tmffs_put8(EFFS_OK);
#else
		tmffs_put8(EFFS_NOSYS);
#endif            
		break;
	}
	default:
		error = EFFS_NOSYS;
		tmffs_put8(EFFS_NOSYS);
		tw(tr(TR_FUNC, TrTmffs, "ERROR: Unknown tmffs protocol code\n"));
		ttw(ttr(TTrTmffs, "tm?" NL));
		break;
	}
	
	// check if we read beyond buffer end
	if (inp > inp_start + insize) {
		tw(tr(TR_FUNC, TrTmffs, "ERROR: Read beyond end of input buffer\n"));
		ttw(ttr(TTrTmffs, "tm_fatal" NL));
		ttw(ttr(TTrTmffs, "insize: %d, diff: %d" NL, insize, 
				inp - (inp_start + insize)));
		// NOTEME: We really should reset output buffer and put a return
		// code that tells us what went wrong!
		error = ETM_PACKET;  // FIXME find another error 
	}

	ttw(ttr(TTrTmffs, "error %d" NL, error));
	if (error > 0)
		error = 0;

    pkt->mid    = ETM_FFS2;
	pkt->size   = outp - outp_start;
    pkt->status = -error;

    etm_pkt_send(pkt);
    etm_free(pkt);

    tw(tr(TR_END, TrTmffs, ""));

    return ETM_OK;
}

#endif // TMFFS2