/*
 * Copyright (c) 2004-2005 Endace Technology Ltd, Hamilton, New Zealand.
 * All rights reserved.
 *
 * This source code is proprietary to Endace Technology Limited and no part
 * of it may be redistributed, published or disclosed except as outlined in
 * the written contract supplied with this product.
 *
 * $Id: dagrom.c 13965 2011-02-24 21:14:20Z sfd $
 */

/* Endace headers. */
#include "dagapi.h"
#include "dagclarg.h"
#include "dagimg.h"
#include "dagnew.h"
#include "dagreg.h"
#include "dag_romutil.h"
#include "dagswid.h"
#include "dagutil.h"
#include "dagema.h"
#include "d37t_i2c.h"
#include <sys/stat.h>

/* CVS Header. */
static const char* const kCvsHeader __attribute__ ((unused)) = "$Id: dagrom.c 13965 2011-02-24 21:14:20Z sfd $";
static const char* const kRevisionString = "$Revision: 13965 $";
/*
 * The order in this structure is important, it defines the priority of operations executed sequentially.
 */
enum
{
	FUNC_DEFAULT = 0x000,
	FUNC_START = 0x001,
	FUNC_MINOR = 0x001, /* Modify this at a later stage for FUNC_INFO */
	FUNC_IMPORT = 0x002,
	FUNC_READ = 0x004,
	FUNC_CHECK = 0x008,
	FUNC_ERASE = 0x010,
	FUNC_WRITE = 0x020,
	FUNC_VERIFY = 0x040,
	FUNC_EXPORT = 0x080,
	FUNC_PROGRAM = 0x100,
	FUNC_XIMGTBL = 0x200,
	FUNC_XREV = 0x400,
	FUNC_XUPDATE = 0x800,
	FUNC_END = 0x1000
};

/* HACK, for minor processing, given the major action above. */
enum
{
	FUNC_MINOR_START = 0x001,
	FUNC_MINOR_SWID_WRITE = 0x002,
	FUNC_MINOR_SWID_READ = 0x004,
	FUNC_MINOR_SWID_ERASE = 0x008,
	FUNC_MINOR_RESERVED = 0x010,
	FUNC_MINOR_SWID_WRITEKEY = 0x020,
	FUNC_MINOR_SWID_CHECKKEY = 0x040,
	FUNC_MINOR_SWID_WRITEAPI = 0x080,
	FUNC_MINOR_SWID_READAPI = 0x100,
	FUNC_MINOR_SWID_ISKEY = 0x200,
	FUNC_MINOR_END = 0x800
};

enum
{
	SRC_NONE = 0,
	SRC_ONES = 1,
	SRC_ZERO = 2,
	SRC_FILE = 3,
	SRC_INCR = 4,
	HALF_CURRENT = 0,
	HALF_STABLE = 1,
	HALF_BOTH = 2
};

#define FILENAME_BUF_BYTES 256
#define SWID_KEY_BUF_BYTES 256
#define SWID_BUF_BYTES 256
#define STABLE_KEY_BUF_BYTES 32


static unsigned int uKey;
static unsigned int uWritebackSwid = 0; /* Have we erased the SWID? if so write it back. */

int image_number = 1;
static uint8_t* uInBuffer;
static unsigned int uInBufferLength;
static uint8_t* uOutBuffer;
static unsigned int uOutBufferLength;

static int uForce = 0;
static int uUnknown = 0;

static char uSwidBuffer[DAGSERIAL_SIZE + 1]; /* Store the user supplied SWID. */
static const char uBigSwid[] = "start of swid ----------------------------------------------------------------------------------------------------- end of swid";
static unsigned int uHoldPbiBus = 0; /* Boolean: hold XScale PBI bus? */
static unsigned int uHaltIxpProc = 0; /* Boolean: halt the IXP process? */

static uint32_t uUserSwidKey; /* The user SWID key. */
static uint32_t uUserSwidBytes; /* Set when the user specifies the number of bytes to be read from the SWID. */
static int target_processor_region = 0;

/* Internal routines. */
static void print_version(void);
static void print_usage(ClArgPtr clarg);
static int process_minors(unsigned int func, romtab_t* rp, int dagfd);
static void where(void);
static void* readfile(FILE * fp, unsigned int maxlen, unsigned int* lenp);
static void check_image(int rom_number, daginf_t* daginfo, int dagfd);

/* Implementation of internal routines. */
static void
print_version(void)
{
	printf("dagrom (DAG %s) %s\n", kDagReleaseVersion, kRevisionString);
}


static void
print_usage(ClArgPtr clarg)
{
	print_version();
	printf("dagrom - read/write/erase EEPROM/SWID (software ID) on Endace DAG cards.\n");
	printf("Usage: dagrom [options]\n");
	dagclarg_display_usage(clarg, stdout);
	printf("\nIf no options are specified then the Xilinx image revision strings are displayed.\n"
			"All commands apply to the current image portion of the ROM,\n"
			"unless one of the options -a, -A, -c is specified.\n\n");
}


static int
process_minors(unsigned int func, romtab_t* rp, int dagfd)
{
	uint8_t swidbuf[DAGSERIAL_SIZE + 1];
	int mask;
	int ierr;
	int ret;
	uint32_t addr;

	memset(swidbuf, 0, (DAGSERIAL_SIZE + 1));

	/* Given the minor action number we can process the actions by bitshifting a mask. */
	for (mask = FUNC_MINOR_START; mask < FUNC_MINOR_END; mask <<= 1)
	{
		switch (func & mask)
		{
			case 0:
				continue;

			case FUNC_MINOR_SWID_WRITE:
				/* check if a software id is programmed and if so the supplied key is correct */
				if ( dagswid_isswid(rp) == 0 )
				{
					if (dagswid_checkkey(rp, uUserSwidKey) != 0)
					{
						printf("SWID stored key does NOT match user supplied key %d \n", uUserSwidKey);
						return -7;
					}
				}

				/* write the new software ID and key */
				if (dagswid_write(rp, (uint8_t*) uSwidBuffer, strlen(uSwidBuffer), uUserSwidKey) < 0)
				{
					if (1 == uHoldPbiBus)
					{
						dagrom_pbirelease(rp);
					}
					dagutil_panic("SWID write failed, errno : %d\n", errno);
				}
				break;

			case FUNC_MINOR_SWID_READ:
				ierr = dagswid_read(rp, swidbuf, DAGSERIAL_SIZE);
				if (ierr < 0)
				{
					if (1 == uHoldPbiBus)
					{
						dagrom_pbirelease(rp);
					}
					dagutil_panic("SWID read failed, errno : %d\n", errno);
				}

				else
				{
					/* Replace any non-printable characters with spaces */
					for (addr = 0; addr < uUserSwidBytes; addr++)
					{
						if (swidbuf[addr])
						{
							if (!isgraph(swidbuf[addr])) swidbuf[addr] = ' ';
						}
					}
			
					/* Null terminate it just in case */
					swidbuf[DAGSERIAL_SIZE] = '\0';
					
					/* Print out the SWID, the SWID has a null terminating character to terminate the string. */
					printf("SWID len %ld, str : %s\n", (long int) strlen((char*) swidbuf), swidbuf);
				}
				break;

			case FUNC_MINOR_SWID_ERASE:
				/* check if a software id is programmed and if so the supplied key is correct */
				if ( dagswid_isswid(rp) == 0 )
				{
					if (dagswid_checkkey(rp, uUserSwidKey) != 0)
					{
						printf("SWID stored key does NOT match user supplied key %d \n", uUserSwidKey);
						return -7;
					}
				}

				if (dagswid_erase(rp) < 0)
				{
					if (1 == uHoldPbiBus)
					{
						dagrom_pbirelease(rp);
					}
					dagutil_panic("SWID erase failed, errno : %d\n", errno);
				}
				break;

			case FUNC_MINOR_SWID_CHECKKEY:
				if (dagswid_checkkey(rp, uUserSwidKey) == 0)
				{
					printf("SWID stored key matches the user supplied key %d \n", uUserSwidKey);
				}
				else
				{
					printf("SWID stored key does NOT match user supplied key %d \n", uUserSwidKey);
					return -7;
				}
				break;
				
			case FUNC_MINOR_SWID_WRITEAPI:
				ret = d37t_write_software_id(dagfd, strlen(uSwidBuffer), (uint8_t*) uSwidBuffer, uUserSwidKey);
				if (ret < 0)
				{
					switch (ret)
					{
						case -1:
							printf("SWID write failed, invalid number of bytes specified\n");
							break;
							
						case -2:
							printf("SWID write failed, firmware error writing to the dag card\n");
							break;
							
						case -3:
							printf("SWID write failed, timeout communicating with the XScale\n");
							break;
							
						case -4:
							printf("SWID write failed, stored key does NOT match user supplied key\n");
							break;
							
						default:
							printf("SWID write failed\n");
							ret = -4;
							break;
					}
					
					return ret;
				}
				break;

			case FUNC_MINOR_SWID_READAPI:
				ierr = d37t_read_software_id(dagfd, uUserSwidBytes, swidbuf);
				if (ierr < 0)
				{
					switch (ierr)
					{
						case -1:
							printf("SWID read failed, invalid number of bytes specified\n");
							break;
							
						case -2:
							printf("SWID read failed, firmware error reading from dag card\n");
							break;
							
						case -3:
							printf("SWID read failed, timeout communicating with the XScale\n");
							break;
							
						default:
							printf("SWID read failed\n");
							break;
					}
				}
				else
				{
					/* Replace any non-printable characters with spaces */
					for (addr = 0; addr < uUserSwidBytes; addr++)
					{
						if (swidbuf[addr])
						{
							if (!isgraph(swidbuf[addr])) swidbuf[addr] = ' ';
						}
					}
			
					/* Null terminate it just in case */
					swidbuf[uUserSwidBytes] = 0;
					printf("SWID len %d, str : %s \n", uUserSwidBytes, swidbuf);
				}
				
				if (ierr < 0)
				{
					return ierr;
				}
				break;
				
			case FUNC_MINOR_SWID_ISKEY:
				ierr = dagswid_isswid(rp);
				if (ierr == 0)
				{
					printf("SWID swid is present\n");
				}
				else
				{
					printf("SWID no swid present\n");
				}
				
				return ierr;
		}
	}

	return 0;
}


/*
 * Our private verbose memcmp(3).
 */
static void
where(void)
{
	int i = 0;
	int e;

	if (dagutil_get_verbosity() < 3)
		return;

	for (e = dagutil_min(uInBufferLength, uOutBufferLength); i < e; i++)
	{
		if (uInBuffer[i] != uOutBuffer[i])
		{
			dagutil_verbose("byte %u differs: expecting 0x%.2x read 0x%.2x\n", i, uInBuffer[i], uOutBuffer[i]);
		}
	}
}


static void*
readfile(FILE * fp, unsigned int maxlen, unsigned int* lenp)
{
#if defined(__FreeBSD__) || defined(__linux__) || (defined(__SVR4) && defined(__sun)) || (defined(__APPLE__) && defined(__ppc__))

	void *p = NULL;
	void *wp = NULL;

#elif defined(_WIN32)

	char *p = NULL;
	char *wp = NULL;

#endif /* Platform-specific code. */

	unsigned int len;
	int rlen;
	off_t off;

	*lenp = 0;
	for (len = BUFSIZ; len <= maxlen; len += BUFSIZ)
	{
		off = wp - p;
		p = realloc(p, len);
		if (wp == NULL)
		{
			wp = p;
		}
		else
		{
			wp = p + off + BUFSIZ;
		}
		
		rlen = fread(wp, 1, BUFSIZ, fp);
		*lenp += rlen;
		if (rlen < BUFSIZ)
			break;
	}

	if (0 != ferror(fp))
	{
		dagutil_free(p);
		p = NULL;
		*lenp = 0;
	}

	return p;
}


/*
 * Check image to be loaded is okay for this device.
 */
static void
check_image(int rom_number, daginf_t* daginfo, int dagfd)
{
	int img_idx;
	int img_type;
	coprocessor_t copro_id;
	uint8_t* iom;
	
	/* Check image is correct for location */
	/* find location */
	img_idx = dag_get_img_idx(daginfo->device_code, rom_number);
	dagutil_verbose("dag%d dev 0x%04x pos %d got idx %d\n", daginfo->id, daginfo->device_code, rom_number, img_idx);

	/* find copro_id */
	iom = dag_iom(dagfd);
	copro_id = dagutil_detect_coprocessor(iom);
	/*Checking the copro region for Dag 9.1 cards. copro id will be zero.if we write to Tx FPGA (Copro) we assign copro_id = 1 to differentiate between PCI image and Copro image.*/
	if (copro_id == 0)
		if(target_processor_region == COPRO_REGION)
		copro_id = 1;	
	/* check against image */
	if (img_idx < 0)
	{
		/* Didn't find the device in the table listing which images can go where. */
		if (1 == uUnknown)
		{
			fprintf(stderr, "Warning, forced loading on unknown hardware!\n");
		}
		else
		{
			dagutil_panic("Unknown hardware, not loading!\nOverride with --unknown only if you are sure, damage may occur.\n");
		}
	}
	else
	{
		/* Found the device in the table listing which images can go where. */
		switch (dag_check_img_ptr(img_idx, (int)copro_id, (char*) uInBuffer, uInBufferLength, daginfo->brd_rev))
		{
			case 0:
				/* A-record (image prefix) and B-record (device type) both matched. */
				break;
			
			case 1:
				/* B-record (device type) matched only. */
				if (uForce)
				{
					fprintf(stderr, "Warning, forcing load to non-matching image type!\n");
				}
				else
				{
					dagutil_panic("*** IMAGE TYPE MISMATCH, not loading! ***\nEnsure you are loading the correct firmware for this device.\nOverride with --force only if you are sure, damage may occur.\n");
				}
				break;
			
			case 2:
				/* No B-record match. */
				dagutil_panic("*** DEVICE MISMATCH, not loading! ***\nEnsure you are loading the correct firmware for this device.\n");
				break;
			
			case -1:
				/* Could not find A-record (image prefix) or B-record (device type) in the image. */
				break;
			
			default:
				assert(0);
				dagutil_panic("internal error line %d", __LINE__);
		}
		/* Dag5.2: check the target region of ROM to be overwritten following the verification of image file */
		if (copro_id == (int)kCoprocessorBuiltin) 
		{
			img_type = dag_check_img_type(img_idx, (int)copro_id, (char*) uInBuffer, uInBufferLength, daginfo->brd_rev);
			/* coprocessor image, but carrier region */
			if ( (img_type > 0) && (target_processor_region != COPRO_REGION) ) 
			{
				dagutil_panic("*** IMAGE FILE MISMATCH, not loading! ***\nEnsure you are loading the correct image file.\n");
			}
			/* carrier image, but coprocessor region */
			if ((img_type == -1) && (target_processor_region == COPRO_REGION)) 
			{
				dagutil_panic("*** IMAGE FILE MISMATCH, not loading! ***\nEnsure you are loading the coprocessor image file.\n");
			}
		}
	}
}

static int
dagrom_safe_erase(romtab_t* rp, uint32_t saddr, uint32_t eaddr)
{
    int iret;

    /* Before we erase determine if there is a SWID, if there is then preserve it
    * and the key and write it back on after we finish all the operations.  SWID 
    * functions only need to occur if the PCI firmware is eing erased (not other
    * cpu regions for IXP or Xscale)
    */
    if (dagswid_isswid(rp) < 0 || (eaddr != (DAGROM_BSTART + DAGROM_BSIZE)))
    {
        iret = dagrom_erase(rp, saddr, eaddr);
    }
    else
    {
        if(rp->device_code == 0x430e)  /* DAG4.3ge */
        {
            /* Read the key and SWID */
            iret = dagswid_read(rp, (uint8_t*) uSwidBuffer, DAGSERIAL_SIZE);
            if (iret < 0)
            {
                if (1 == uHoldPbiBus)
                    dagrom_pbirelease(rp);
                dagutil_panic("In erase, SWID read failed, errno : %d\n", iret);
            }

            iret = dagswid_readkey(rp, &uKey);
            if (iret < 0)
            {
                if (1 == uHoldPbiBus)
                    dagrom_pbirelease(rp);
                dagutil_panic("In erase, SWID read key failed, errno : %d\n", iret);
            }

            uWritebackSwid = 1;
			printf("%x %x\n", saddr, eaddr);

	    /* Now we can safely perform the erase operation. The last sector is not
            * erased at this stage as this will be erased immediately before the swid
            * is written back*/
            iret = dagrom_erase(rp, saddr, eaddr);

            /*write the swid back straight away, in case programming fails */
            dagswid_write(rp, (uint8_t*) uSwidBuffer, DAGSERIAL_SIZE, uKey);

        } 
        else 
        {
            iret = dagrom_erase(rp, saddr, eaddr - DAGROM_SECTOR);

        }
    }

    return iret;
}


/* Commandline argument codes. */
enum
{
	/* General options. */
	CLA_37T_HOLD_BUS,
	CLA_71S_HALT_PROC,
	CLA_ALTERNATE_HALF,
	CLA_CPU_REGION,
	CLA_DEVICE,
	CLA_DISABLE_CFI_FAST,
	CLA_ENTIRE_ROM,
	CLA_ERASE,
	CLA_FILE,
	CLA_FORCE,
	CLA_HELP,
	CLA_LIST_XILINX_REVISION,
	CLA_PROGRAM_CURRENT_IMAGE,
	CLA_REPROGRAM,
	CLA_IMAGE_SELECTION_FPGA,
	CLA_IMAGE_SELECTION_FPGA2,
	CLA_REPROGRAM_METHOD,
	CLA_IMAGE_NUMBER,
	CLA_IMAGE_NUMBER2,
	CLA_IMAGE_NUMBER3,
	CLA_ROM_NUMBER,
	CLA_STABLE_HALF,
	CLA_UNKNOWN,
	CLA_VERBOSE,
	CLA_VERIFY,
	CLA_VERSION,
	CLA_WRITE,
	CLA_ZERO,
	CLA_INCR,
	CLA_FILEOUT,
    	CLA_ERR_CONT,
	
	/* General SWID options. */
	CLA_SWID_KEY,
	CLA_SWID_READ_BYTES,
	/* deprecated: CLA_SWID_USE_CONSOLE,  */
	CLA_SWID_WRITE,
	
	/* SWID ROM options. */
	CLA_SWID_ROM_CHECK_KEY,
	CLA_SWID_ROM_CHECK,
	CLA_SWID_ROM_ERASE,
	CLA_SWID_ROM_READ,
	CLA_SWID_ROM_WRITE
};


/* Check the Key if accessing the stable half
 * Panic and exit if key is invalid and target is stable half
 */
void dagrom_access_v2( romtab_t* rp,
	int rom_number,
	int func,
	unsigned int end_address);

void
dagrom_access(
	romtab_t* rp,
	int rom_number,
	int func,
	unsigned int end_address)
{
	if(rp->rom_version == 2) 
{		dagrom_access_v2( rp,	rom_number, func, end_address);
		return;

}
	
	if ((rom_number == 0) &&  ((func & FUNC_ERASE)||(func & FUNC_WRITE)) && (end_address > DAGROM_TSTART))
	{
		if (uKey == 0)
		{
			if (1 == uHoldPbiBus)
			{
				dagrom_pbirelease(rp);
			}
			dagutil_panic("no access to the stable part of the ROM without the correct key\n");
		}
		dagrom_keywreg(rp, uKey);
		if (0 == (dagrom_romreg(rp) & BIT31))
		{
			if (1 == uHoldPbiBus)
			{
				dagrom_pbirelease(rp);
			}
			dagutil_panic("Life is hard.\n");
		}
	}
}
void
dagrom_access_v2(
	romtab_t* rp,
	int rom_number,
	int func,
	unsigned int end_address)
{
	if ((rom_number == 0) &&  ((func & FUNC_ERASE)||(func & FUNC_WRITE)) && (end_address > rp->itable.atable[0].start_address))
	{
		if (uKey == 0)
		{
			if (1 == uHoldPbiBus)
			{
				dagrom_pbirelease(rp);
			}
			dagutil_panic("no access to the stable part of the ROM without the correct key\n");
		}
		dagrom_keywreg(rp, uKey);
		if (0 == (dagrom_romreg(rp) & BIT31))
		{
			if (1 == uHoldPbiBus)
			{
				dagrom_pbirelease(rp);
			}
			dagutil_panic("Life is hard.\n");
		}
	}
}
int
dagrom_main(int argc, const char *argv[])
{
	ClArgPtr clarg = NULL;
	FILE* errorfile = NULL;
	int rom_number = 0; /* ROM to access */
	int rom_number_user = 0; /* boolean: Did the user specify the ROM number? */
	int func = FUNC_DEFAULT;
	int src = SRC_NONE;
	int half = HALF_CURRENT;
	int clarg_result = 0;
	int argindex = 0;
	int code = 0;
    int err_continue = 1;
	int index = 0;
	int dagfd = -1;
	int dagstream = 0;
	char filename_buf[FILENAME_BUF_BYTES] = "";
	char fileout_buf[FILENAME_BUF_BYTES] = "";
	char swid_key_buf[SWID_KEY_BUF_BYTES] = "";
	char swid_check_key_buf[SWID_KEY_BUF_BYTES] = "";
	char swid_write_buf[SWID_BUF_BYTES] = "";
	char swid_rom_write_buf[SWID_BUF_BYTES] = "";
	char dagname_buffer[DAGNAME_BUFSIZE] = "dag0";
	char dagname[DAGNAME_BUFSIZE] = "";
	char stable_key_buf[STABLE_KEY_BUF_BYTES] = "";
	char* source_filename = NULL;
	uint8_t cpu_region = 0;
	int swid_bytes = 0;
	int ilen = 0;
	int iret = 0; 
	int mask = 0;
	unsigned int start_address = 0;
	unsigned int end_address = 0;
	romtab_t* rp = NULL;
	int verbosity=0;
	int reprogram_method = 3;
	int image_number = 1;
	FILE* out_file = NULL;
	struct stat filestat;
	daginf_t* daginfo = NULL;
	int sign_field_size = 0;
	int image_table_fpga = 0;
		

#if defined (_WIN32)
	uint8_t finp_reqd = 0;
	uint8_t finp_given = 0;
#endif /* _WIN32 */


	dagutil_set_progname("dagrom");

	/* Set up default DAG device. */
	if (-1 == dag_parse_name(dagname_buffer, dagname, DAGNAME_BUFSIZE, &dagstream))
	{
		dagutil_panic("dag_parse_name(%s): %s\n", dagname_buffer, strerror(errno));
	}
	/* Set up the command line options. */
	clarg = dagclarg_init(argc, argv);

	/* General options. */
	dagclarg_add(clarg, "Hold PBI bus from XScale (DAG 3.7T only).", "--hold-bus", 'l', CLA_37T_HOLD_BUS);
	dagclarg_add(clarg, "Halt the embedded IXP Processor (DAG 7.1S only).", "--halt-ixp", 'i', CLA_71S_HALT_PROC);
	dagclarg_add(clarg, "Use alternate (stable) half. [Default is current half.]", "--alternate-half", 'a', CLA_ALTERNATE_HALF);
	dagclarg_add_char(clarg, "Access CPU region: c=copro, b=boot, k=kernel, f=filesystem a=all.", "--cpu-region", 'c', "region", &cpu_region, CLA_CPU_REGION);
	dagclarg_add_string(clarg, "DAG device to use.", "--device", 'd', "device", dagname_buffer, DAGNAME_BUFSIZE, CLA_DEVICE);
	dagclarg_add(clarg, "Disable fast program option for CFI mode.", "--disable-cfi-fast", 'F', CLA_DISABLE_CFI_FAST);
	dagclarg_add(clarg, "Entire ROM.  [Default is current half only.]", "--entire-rom", 'A', CLA_ENTIRE_ROM);
	dagclarg_add(clarg, "Erase ROM.", "--erase", 'e', CLA_ERASE);
	dagclarg_add_string(clarg, "File to be read when programming ROM.", "--file", 'f', "filename", filename_buf, FILENAME_BUF_BYTES, CLA_FILE);
	dagclarg_add(clarg, "Force loading firmware.  Dangerous.", "--force", 0, CLA_FORCE);
	dagclarg_add(clarg, "This page.", "--help", 'h', CLA_HELP);
	dagclarg_add_long_option(clarg, CLA_HELP, "--usage");
	dagclarg_add_short_option(clarg, CLA_HELP, '?');
	dagclarg_add(clarg, "Display Xilinx revision strings (the default if no arguments are given).", "--list-revisions", 'x', CLA_LIST_XILINX_REVISION);
	dagclarg_add(clarg, "Program current Xilinx image into FPGA.", "--program-current", 'p', CLA_PROGRAM_CURRENT_IMAGE);
	dagclarg_add(clarg, "Reprogram ROM (may imply erase and write).", "--reprogram", 'r', CLA_REPROGRAM);
	dagclarg_add_int(clarg, "Access specified ROM controller.  [Default is 0.]", "--rom-number", 'g', "rom", &rom_number, CLA_ROM_NUMBER);
	dagclarg_add_string(clarg, "Write the contents of the ROM to a file.", "--write-out", 0, "filename", fileout_buf, FILENAME_BUF_BYTES, CLA_FILEOUT);
	
	/* Deliberately undocumented. */
	dagclarg_add_string(clarg, "Program stable half.", "--stable-half", 'S', "key", stable_key_buf, STABLE_KEY_BUF_BYTES, CLA_STABLE_HALF);
	dagclarg_suppress_display(clarg, CLA_STABLE_HALF);
	dagclarg_add_int(clarg, "Specify the method to reprogram the card.[1.Immediate / Rude Reprogram 2.Negotiated Link Disable, Reprogram, Retrain 3.Negotiated Bus Hot Reset, Reprogram (default)]","--reset-method",0,"reprogram method",&reprogram_method,CLA_REPROGRAM_METHOD);

	dagclarg_add_int(clarg, "Specify the image number for operations (w,r,y,e). Also sets image number to load on power cycle [0.factory image 1.user image - 1 2.user image - 2 3.user image - 3]","--image-number",'q',"image number",&image_number,CLA_IMAGE_NUMBER);
	dagclarg_add_int(clarg,"specify the Power On Image Selection table Image number","--image-table-image",0,"image table image",&image_number,CLA_IMAGE_NUMBER2);
	dagclarg_suppress_display(clarg, CLA_IMAGE_NUMBER2);
 	dagclarg_add_int(clarg,"specify the which image to load into the FPGA on next power cycle.By default it is user image 1.","--boot-number", 0,"BOOT number",&image_number,CLA_IMAGE_NUMBER3);
	dagclarg_suppress_display(clarg, CLA_IMAGE_NUMBER3);

	dagclarg_add_int(clarg,"specify which FPGA the specified image is loaded into, on next power cycle. DAG cards with multiple FPGAs are indexed (0, 1, ...). Default is 0.","--fpga-number",'n',"FPGA number",&image_table_fpga,CLA_IMAGE_SELECTION_FPGA);
	dagclarg_add_int(clarg,"specify the Power On Image Selection table FPGA number","--image-table-fpga",0,"image table fpga",&image_table_fpga,CLA_IMAGE_SELECTION_FPGA2);
	dagclarg_suppress_display(clarg, CLA_IMAGE_SELECTION_FPGA2);

	dagclarg_add(clarg, "Force loading firmware.  Dangerous.", "--unknown", 0, CLA_UNKNOWN);
	dagclarg_add(clarg, "Continue on erase error.", "--continue", 0, CLA_ERR_CONT);
	dagclarg_add(clarg, "Increase verbosity.", "--verbose", 'v', CLA_VERBOSE);
	dagclarg_add(clarg, "Verify write to ROM.", "--verify", 'y', CLA_VERIFY);
	dagclarg_add(clarg, "Display version information.", "--version", 'V', CLA_VERSION);
	dagclarg_add(clarg, "Write data to EEPROM (this implies erase).", "--write", 'w', CLA_WRITE);
	dagclarg_add(clarg, "Write zeros to the EEPROM (this implies erase).", "--zero", 'z', CLA_ZERO);
	dagclarg_add(clarg, "Write an incremented value to ROM (this implies erase). Use only on the advice of Endace.", "--incr", 'I', CLA_INCR);
	
	/* General SWID options. */
	dagclarg_add_string(clarg, "Hexadecimal key for writing the Software ID (aka SWID).", "--swid-key", 'm', "key", swid_key_buf, SWID_KEY_BUF_BYTES, CLA_SWID_KEY);
	dagclarg_add_int(clarg, "D37T Read <bytes> of SWID, requires a valid running XScale ROM image", "--swid-read-bytes", 't', "bytes", &swid_bytes, CLA_SWID_READ_BYTES);
	/* depreciated: dagclarg_add(clarg, "Use console to read/write SWID to the DAG 3.7T.  [Default is to use the DRB.]", "--swid-console", 'n', CLA_SWID_USE_CONSOLE); */ 
	dagclarg_add_string(clarg, "D37T Write given SWID.  The key must be supplied with the -m option, requires a valid running XScale ROM Image", "--swid-write",0,"swid", swid_write_buf, SWID_BUF_BYTES, CLA_SWID_WRITE);
	
	/* SWID ROM options. */
	dagclarg_add_string(clarg, "Check the ROM SWID key with the one supplied.", "--swid-rom-check-key", 'j', "key", swid_check_key_buf, SWID_KEY_BUF_BYTES, CLA_SWID_ROM_CHECK_KEY);
	dagclarg_add(clarg, "Check if there is a SWID on the ROM.", "--swid-rom-check", 'b', CLA_SWID_ROM_CHECK);
	dagclarg_add(clarg, "Erase SWID from ROM.", "--swid-erase", 'u', CLA_SWID_ROM_ERASE);
	dagclarg_add(clarg, "Read SWID from ROM.", "--swid-rom-read", 'o', CLA_SWID_ROM_READ);
	dagclarg_add_string(clarg, "Write given SWID to ROM.  The key must be supplied with the -m option.", "--swid-rom-write", 's', "swid", swid_rom_write_buf, SWID_BUF_BYTES, CLA_SWID_ROM_WRITE);


	/* Parse the command line options. */
	clarg_result = dagclarg_parse(clarg, errorfile, &argindex, &code);
	while (1 == clarg_result)
	{
		switch (code)
		{
			/* General options. */
			case CLA_37T_HOLD_BUS:
				uHoldPbiBus = 1;
				dagutil_verbose("holding bus (DAG 3.7T)\n");
				break;
			
			case CLA_71S_HALT_PROC:
				uHaltIxpProc = 1;
				dagutil_verbose("halting IXP processor (DAG 7.1S)\n");
				break;
				
	
			case CLA_ALTERNATE_HALF:
				half = HALF_STABLE;
				image_number = 0;
				dagutil_verbose("using alternate half\n");
				break;
	
			case CLA_CPU_REGION:
				dagutil_verbose("cpu/CP region was '%c'\n", cpu_region);
				if ('b' == cpu_region)
				{
					/* Boot block */
					target_processor_region = BOOT_REGION;
				}
				else if ('k' == cpu_region)
				{
					/* Kernel block */
					target_processor_region = KERNEL_REGION;
				}
				else if ('f' == cpu_region)
				{
					/* File system block */
					target_processor_region = FS_REGION;
				}
				else if ('a' == cpu_region)
				{
					/* File system block */
					target_processor_region = EMBEDDED_REGION;
				}
				else if ('c' == cpu_region)
				{
					/* Addeded support for copro images */
					target_processor_region = COPRO_REGION;
				}
				else
				{
					dagutil_panic("Invalid -c region '%c' specified.  Must be b, k, or f\n", cpu_region);
				}
				break;
			case CLA_REPROGRAM_METHOD:
				dagrom_set_program_method(reprogram_method);
				break;
			case CLA_IMAGE_SELECTION_FPGA:
			case CLA_IMAGE_SELECTION_FPGA2:
				func |= (FUNC_XIMGTBL | FUNC_XREV);
				break;
			case CLA_IMAGE_NUMBER:
			case CLA_IMAGE_NUMBER2:
			case CLA_IMAGE_NUMBER3:
				func |=( FUNC_XIMGTBL | FUNC_XREV);
				dagrom_set_image_number(image_number);
				break;
			case CLA_DEVICE:
				if (-1 == dag_parse_name(dagname_buffer, dagname, DAGNAME_BUFSIZE, &dagstream))
				{
					dagutil_panic("dag_parse_name(%s): %s\n", dagname_buffer, strerror(errno));
				}
				dagutil_verbose("device=%s\n", dagname);
				break;
	
			case CLA_DISABLE_CFI_FAST:
				dagrom_set_fast_cfi_mode(0);
				dagutil_verbose("CFI fast mode disabled\n");
				break;
	
			case CLA_ENTIRE_ROM:
				half = HALF_BOTH;
				dagutil_verbose("programming entire ROM\n");
				break;
	
			case CLA_ERASE:
				func |= FUNC_ERASE;
				if (src < SRC_ONES)
				{
					src = SRC_ONES;
				}
				break;
	
			case CLA_FILE:
				source_filename = filename_buf;
#if defined (_WIN32)
				finp_given = 1;
#endif /* _WIN32 */
				break;
	
			case CLA_FORCE:
				uForce = 1;
				dagutil_verbose("forcing ROM load (potentially dangerous)\n");
				break;
	
			case CLA_HELP:
				print_usage(clarg);
				return EXIT_SUCCESS;
				break;
	
			case CLA_LIST_XILINX_REVISION:
				func |= FUNC_XREV;
				break;
	
			case CLA_PROGRAM_CURRENT_IMAGE:
				func |= (FUNC_PROGRAM | FUNC_XREV);
				break;
	
			case CLA_REPROGRAM:
				func |= (FUNC_IMPORT | FUNC_READ | FUNC_CHECK | FUNC_XREV);
				if (src < SRC_FILE)
				{
					src = SRC_FILE;
				}
#if defined (_WIN32)
				finp_reqd = 1;
#endif /* _WIN32 */
				break;
	
			case CLA_FILEOUT:
				func |= (FUNC_READ | FUNC_EXPORT);
				break;
	
			case CLA_ROM_NUMBER:
				dagutil_verbose("will program ROM %d\n", rom_number);
				rom_number_user = 1;
				break;
	
			/* Deliberately undocumented. */
			case CLA_STABLE_HALF:
				if (half == HALF_CURRENT)
				{
					half = HALF_STABLE;
				}
				uKey = strtoul(stable_key_buf, NULL, 0);
				dagutil_verbose("will program stable half with key 0x%08x\n", uKey);
				break;
	
			case CLA_UNKNOWN:
				uUnknown = 1;
				dagutil_verbose("forcing ROM load (potentially dangerous)\n");
				break;
	
			case CLA_VERBOSE:
				if(dagutil_get_verbosity() == 0)
				{
					dagutil_inc_verbosity();
				}	
				dagutil_inc_verbosity();
				errorfile = stderr;
				break;
	
			case CLA_VERIFY:
				func |= (FUNC_IMPORT | FUNC_VERIFY);
				break;
	
			case CLA_VERSION:
				print_version();
				return EXIT_SUCCESS;
				break;
	
			case CLA_WRITE:
				func |= (FUNC_IMPORT | FUNC_WRITE | FUNC_XREV);
				if (src < SRC_FILE)
				{
					src = SRC_FILE;
				}
				
#if defined (_WIN32)
				finp_reqd = 1;
#endif /* _WIN32 */
				break;
	
			case CLA_ZERO:
				func |= (FUNC_IMPORT | FUNC_ERASE | FUNC_WRITE);
				if (src < SRC_ZERO)
				{
					src = SRC_ZERO;
				}
				break;
			case CLA_INCR:
				func |= (FUNC_IMPORT | FUNC_ERASE | FUNC_WRITE);
				src = SRC_INCR;
				break;
	
			/* General SWID options. */
			case CLA_SWID_KEY:
				uUserSwidKey = strtol(swid_key_buf, NULL, 16);
				dagutil_verbose("SWID: key is 0x%08x (%d)\n", uUserSwidKey, uUserSwidKey);
				break;
	
			case CLA_SWID_READ_BYTES:
				func = FUNC_MINOR_SWID_READAPI | FUNC_MINOR;
				uUserSwidBytes = swid_bytes;
				dagutil_verbose("SWID: will read %d bytes\n", swid_bytes);
				break;

            		case CLA_ERR_CONT:
		                err_continue = 0;
                		break;
	
			/* Deprecated
			case CLA_SWID_USE_CONSOLE:
				use_console = 1;
				dagutil_verbose("SWID: will use console\n");
				break;
			*/
			
			case CLA_SWID_WRITE:
				func = FUNC_MINOR_SWID_WRITEAPI | FUNC_MINOR;
	
				if (strcmp(swid_write_buf, "test128") == 0)
				{
					memcpy(uSwidBuffer, uBigSwid, strlen(uBigSwid));
				}
				else
				{
					ilen = dagutil_min(strlen(swid_write_buf), DAGSERIAL_SIZE);
					memset(uSwidBuffer, 0, DAGSERIAL_SIZE + 1);
					memcpy(uSwidBuffer, swid_write_buf, ilen);
	
					dagutil_verbose("SWID: swid from cmdline. len: %d, value: '%s'\n", ilen, uSwidBuffer);
				}
				break;
	
			/* SWID ROM options. */
			case CLA_SWID_ROM_CHECK_KEY:
				func = FUNC_MINOR_SWID_CHECKKEY | FUNC_MINOR;
				uUserSwidKey = strtol(swid_check_key_buf, NULL, 16);
				dagutil_verbose("SWID: key is 0x%08x (%d)\n", uUserSwidKey, uUserSwidKey);
				break;
	
			case CLA_SWID_ROM_CHECK:
				func = FUNC_MINOR_SWID_ISKEY | FUNC_MINOR;
				break;
	
			case CLA_SWID_ROM_ERASE:
				func = FUNC_MINOR_SWID_ERASE | FUNC_MINOR;
				break;
	
			case CLA_SWID_ROM_READ:
				func = FUNC_MINOR_SWID_READ | FUNC_MINOR;
				break;
	
			case CLA_SWID_ROM_WRITE:
				func = FUNC_MINOR_SWID_WRITE | FUNC_MINOR;
	
				/* If the user supplied SWID is 'test128' generate a 128 byte long null-terminated SWID. */
				if (strcmp(swid_rom_write_buf, "test128") == 0)
				{
					memcpy(uSwidBuffer, uBigSwid, strlen(uBigSwid));
				}
				else
				{
					ilen = dagutil_min(strlen(swid_rom_write_buf), DAGSERIAL_SIZE);
					memset(uSwidBuffer, 0, DAGSERIAL_SIZE + 1);
					memcpy(uSwidBuffer, swid_rom_write_buf, ilen);
	
					dagutil_verbose("SWID: swid from cmdline. len: %d, value: '%s'\n", ilen, uSwidBuffer);
				}
				break;
	
			default:
				if (argv[argindex][0] == '-')
				{
					/* Unknown option. */
					dagutil_error("unknown option %s\n", argv[argindex]);
					print_usage(clarg);
					return EXIT_FAILURE;
				}
				break;
		}

		clarg_result = dagclarg_parse(clarg, errorfile, &argindex, &code);
	}

	if (-1 == clarg_result)
	{
		if (argindex < argc)
		{
			dagutil_error("while processing option %s\n", argv[argindex]);
		}
		dagclarg_display_usage(clarg, stderr);
		return EXIT_FAILURE;
	}
	
	verbosity = dagutil_get_verbosity();
	
	/* Display unprocessed arguments if verbose flag was given. */
	argv = (const char**) dagclarg_get_unprocessed_args(clarg, &argc);
	if ((NULL != argv) && (0 < argc) && (0 < verbosity))
	{
		for (index = 0; index < argc; index++)
		{
			dagutil_verbose("unprocessed argument: '%s'\n", argv[index]);
		}
	}

#if ENDACE_LAB
	uForce = 1;
#endif /* ENDACE_LAB */

	dagfd = dag_open(dagname);
	if (dagfd < 0)
	{
		dagutil_panic("cannot dag_open %s: %s\n", dagname, strerror(errno));
	}

	daginfo = dag_info(dagfd);
	
	
	
	
	if ((func & (FUNC_WRITE | FUNC_EXPORT)) == (FUNC_WRITE | FUNC_EXPORT) && (0 == (func & FUNC_MINOR)))
	{
		dagutil_panic("conflicting read and write options\n");
	}
	
	if ((func & (FUNC_ERASE | FUNC_WRITE | FUNC_VERIFY)) == FUNC_VERIFY && (0 == (func & FUNC_MINOR)))
	{
		/* imply write as with -wy */
		func |= (FUNC_IMPORT | FUNC_WRITE);
		src = SRC_FILE;
	}

	if (func == FUNC_DEFAULT)
		func = (FUNC_READ | FUNC_XREV);

	rp = dagrom_init(dagfd, rom_number, uHoldPbiBus);
	if( NULL == rp )
	{
		dagutil_panic("No ROM controller found on this device\n");
	}

	/* Halt the IXP processor if asked to */
	if ( uHaltIxpProc == 1 )
	{
		/* sanity check that if the IXP is to be halted we have an actual 7.1s */
		if (daginfo->device_code != PCI_DEVICE_ID_DAG7_10)
		{
			dagutil_panic("request the IXP processor to be halted on a non-DAG7.1s card\n");
		}
		
		/* halt the processor */
		if ( dagema_halt_processor(dagfd) != 0 )
		{
			switch (dagema_get_last_error())
			{
				case EEXIST:
					dagutil_panic("failed to halt IXP processor because an open EMA connection exits\n");
					break;
				case ELOCKED:
					dagutil_panic("failed to halt IXP processor because an EMA connection is locked\n");
					break;
				default:
				case ECARDNOTSUPPORTED:
					dagutil_panic("failed to halt IXP processor due to an unknown error\n");
					break;
			}
		}
	}

	
	
	
	/* Are we writing to a processor region? */
	if ((rp->mpu_id != DAG_MPU_NONE) && (target_processor_region))
	{
		/* See if we used the correct ROM number for the processor. */
		if (rp->mpu_rom != rom_number)
		{
			dagutil_verbose("Switching to rom number %d for processor/Copro write\n", rp->mpu_rom);
			rom_number = rp->mpu_rom;
			rp = dagrom_init(dagfd, rom_number, uHoldPbiBus);
		}
	}

	if ((rp->mpu_id == DAG_MPU_COPRO_SMALL) || (rp->mpu_id == DAG_MPU_COPRO_BIG))
	{
		
		if( target_processor_region) 
		{
			dagutil_verbose("!ROM.%d %s. Copro %s (%d), region=%s (%d), half=%d \n",
				rom_number, rp->ident,
				dagrom_mpuname(rp->mpu_id), rp->mpu_id,
				/* For the copro we have one target_prccesor_region split by the current/stable half */
				dagrom_procname(rp->mpu_id, 1), target_processor_region,half);
		}
		else 
			dagutil_verbose("!ROM.%d %s.\n", rom_number, rp->ident);
	}
	else if (rp->mpu_id != DAG_MPU_NONE)
	{
		dagutil_verbose("ROM.%d %s. Processor %s (%d), region=%s (%d)\n",
				rom_number, rp->ident,
				dagrom_mpuname(rp->mpu_id), rp->mpu_id,
				dagrom_procname(rp->mpu_id, target_processor_region), target_processor_region);
	}
	else
	{
		dagutil_verbose("ROM.%d %s.\n", rom_number, rp->ident);
	}

#ifndef NDEBUG
	/* Check that the ROM table is properly initialized. */
	dagutil_verbose("romid %d \n", rp->romid);
	dagutil_verbose("base %d \n", rp->base);
	dagutil_verbose("rom_version %d \n", rp->rom_version);
	dagutil_verbose("device_code 0x%04x \n", rp->device_code);
	dagutil_verbose("ident %s\n", rp->ident);
	dagutil_verbose("size %d \n", rp->size);
	dagutil_verbose("sector %d \n", rp->sector);
	dagutil_verbose("bstart %d \n", rp->bstart);
	dagutil_verbose("bsize %d \n", rp->bsize);
	dagutil_verbose("tstart %d \n", rp->tstart);
	dagutil_verbose("tsize %d \n", rp->tsize);
	dagutil_verbose("pstart %d \n", rp->pstart);
	dagutil_verbose("psize %d \n", rp->psize);
	dagutil_verbose("mpu_id %d \n", rp->mpu_id);
	dagutil_verbose("mpu_rom %d \n", rp->mpu_rom);
#endif /* NDEBUG */

	if (rp->romid == 0x0000)
	{
		if (1 == uHoldPbiBus)
		{
			dagrom_pbirelease(rp);
		}
		dagutil_panic("0x%.4x unknown flash ROM type\n", rom_number);
	}

	/* added support for the copro on the accelerated cards*/
	if( ((rp->mpu_id == DAG_MPU_COPRO_SMALL)||(rp->mpu_id == DAG_MPU_COPRO_BIG)) && (target_processor_region == COPRO_REGION) && (rp->rom_version != 0x2))
	{
		switch (half)
		{
			case HALF_CURRENT:
				start_address = COPRO_CURRENT_START_BIG;
				end_address = start_address + COPRO_CURRENT_SIZE_BIG;
				uOutBufferLength = COPRO_CURRENT_SIZE_BIG;
				uInBufferLength = COPRO_CURRENT_SIZE_BIG;
				uOutBuffer = dagutil_malloc(uOutBufferLength);
				uInBuffer = dagutil_malloc(uInBufferLength);
				break;
				
			case HALF_STABLE:
				start_address = COPRO_STABLE_START_BIG;
				end_address = start_address + COPRO_STABLE_SIZE_BIG;
				uOutBufferLength = COPRO_STABLE_SIZE_BIG;
				uInBufferLength = COPRO_STABLE_SIZE_BIG;
				uOutBuffer = dagutil_malloc(uOutBufferLength);
				uInBuffer = dagutil_malloc(uInBufferLength);
				break;
				
			case HALF_BOTH:
				dagutil_panic("We do not support loading the two coprocessor halves on the accelerated cards "\
                    "being loaded at the same time.  Please load the halves individually.  Error in %s line %u\n", __FILE__, __LINE__);
				break;
				
			default:
				if (1 == uHoldPbiBus)
					dagrom_pbirelease(rp);
				dagutil_panic("internal error at %s line %u\n", __FILE__, __LINE__);
		}
	}
	else if ((rp->mpu_id != DAG_MPU_NONE) && (target_processor_region) && (rp->rom_version != 2))
	{
		if (verbosity > 1) 
		{
			dagutil_verbose("MPU: devid 0x%04x, MPU %d, ROM %d\n",rp->device_code, rp->mpu_id, rp->mpu_rom);
			dagutil_verbose("MPU: XSTART 0x%x, XSIZE %x, procstart 0x%x, procsize 0x%x, region %s\n", 
					DAGROM_XSTART,
					DAGROM_XSIZE,
					dagrom_procstart(rp->mpu_id, target_processor_region),
					dagrom_procsize(rp->mpu_id, target_processor_region),
					dagrom_procname(rp->mpu_id, target_processor_region));
		}

		/* Does this flash have a processor section defined? */
		if (DAGROM_XSIZE == 0)
		{
			if (1 == uHoldPbiBus)
				dagrom_pbirelease(rp);
			dagutil_panic("error -c option not supported by board\n");
		}

		start_address = DAGROM_XSTART + dagrom_procstart(rp->mpu_id, target_processor_region);

		/* Size is region size */
		end_address = start_address + dagrom_procsize(rp->mpu_id, target_processor_region);
		uOutBufferLength = dagrom_procsize(rp->mpu_id, target_processor_region);
		uInBufferLength = dagrom_procsize(rp->mpu_id, target_processor_region);
		uInBuffer = dagutil_malloc(uInBufferLength);
		uOutBuffer = dagutil_malloc(uOutBufferLength);

		if (verbosity > 1)
		{
			dagutil_verbose("MPU %s saddr: 0x%08x eaddr: 0x%08x, len 0x%x\n",
					dagrom_procname(rp->mpu_id, target_processor_region), start_address, end_address, DAGROM_XSIZE);
		}
	}
	else
	{
			if(rp->rom_version == 2)
			{
				if( (image_number < 0 ) || ( image_number > 3 )) 
					dagutil_panic(" Inorrect Image number %d\n",image_number); 	
					
					if( target_processor_region == COPRO_REGION ) 
					{
						image_number =  (image_number + 4);
					}
				 	
				//note image number 0-3 are FPGA 0 
				//note image number 4-7 are FPGA 1 
				//note image number 8-11 are FPGA 0 
				//note image number 12-15 are FPGA 1 
					
					start_address = rp->itable.atable[image_number].start_address;
					end_address = rp->itable.atable[image_number].end_address;
					uOutBufferLength = end_address - start_address;
					uInBufferLength = end_address - start_address;
					dagutil_verbose("Image0-16: %d CURRENT start address %x end address %x buffer length %x\n",image_number, start_address,end_address,uOutBufferLength);
					uOutBuffer = dagutil_malloc(uOutBufferLength);
					uInBuffer = dagutil_malloc(uInBufferLength);
				
			}
			else
			{
				switch (half)
				{
					case HALF_CURRENT:
						start_address = DAGROM_BSTART;
						end_address = start_address + DAGROM_BSIZE;
						uOutBufferLength = DAGROM_BSIZE;
						uInBufferLength = DAGROM_BSIZE;
						uOutBuffer = dagutil_malloc(uOutBufferLength);
						uInBuffer = dagutil_malloc(uInBufferLength);
						break;
					case HALF_STABLE:
						start_address = DAGROM_TSTART;
						end_address = start_address + DAGROM_TSIZE;
						uOutBufferLength = DAGROM_TSIZE;
						uInBufferLength = DAGROM_TSIZE;
						uOutBuffer = dagutil_malloc(uOutBufferLength);
						uInBuffer = dagutil_malloc(uInBufferLength);
						break;
				
					case HALF_BOTH:
						start_address = DAGROM_BSTART;
						end_address = start_address + DAGROM_SIZE;
						uOutBufferLength = DAGROM_SIZE;
						uInBufferLength = DAGROM_SIZE;
						uOutBuffer = dagutil_malloc(uOutBufferLength);
						uInBuffer = dagutil_malloc(uInBufferLength);
						break;
				
				default:
					if (1 == uHoldPbiBus)
						dagrom_pbirelease(rp);
					dagutil_panic("internal error at %s line %u\n", __FILE__, __LINE__);
			}
		}
	}

	/* Check for key if accessing stable half of first ROM */
	dagrom_access(rp, rom_number, func, end_address);

	for (mask = FUNC_START; mask < FUNC_END; mask <<= 1)
	{
		switch (func & mask)
		{
			case 0:
				/* no match */
				continue;

			case FUNC_MINOR:
				iret = process_minors(func, rp, dagfd);
				if (iret < 0)
				{
					if (1 == uHoldPbiBus)
					{
						dagrom_pbirelease(rp);
					}
					return iret;
				}
				
				func = FUNC_DEFAULT;
				break;

			case FUNC_IMPORT:
				switch (src)
				{
					case SRC_NONE:
						if (1 == uHoldPbiBus)
						{
							dagrom_pbirelease(rp);
						}
						dagutil_panic("import no source, this should never happen\n");
						/* never returns */
						break;
	
					case SRC_INCR:
					case SRC_ONES:
					case SRC_ZERO:
						uInBufferLength = DAGROM_TSIZE;
						uInBuffer = dagutil_malloc(uInBufferLength);
						dagutil_verbose("SIZE of the rom:  %d \n", uInBufferLength);
						if (uInBuffer == NULL)
						{
							if (1 == uHoldPbiBus)
							{
								dagrom_pbirelease(rp);
							}
							dagutil_panic("malloc(%u): %s\n", uInBufferLength, strerror(errno));
						}
						
						if (src == SRC_ZERO)
						{
							printf("INIT THE ZERO BUFFER \n");
							memset(uInBuffer, 0x00, uInBufferLength);
						} else if (src == SRC_ONES)
						{
							printf("INIT THE ONES BUFFER \n");
							memset(uInBuffer, 0xFF, uInBufferLength);
						} else
						{
						int i;
							printf("INIT THE INCREMENTAL BUFFER 32bit \n");
							for(i=0; i< uInBufferLength; i+=4)
							{
								*(uint32_t *)(uInBuffer +i) = i;
							}
						}
						break;
	
					case SRC_FILE:
						if (NULL != source_filename)
						{
							FILE* ifile;
	
							ifile = fopen(source_filename, "rb");
							if (ifile == NULL)
							{
								dagutil_panic("unable to open input file");
							}
							else
							{
								/*	Check if the input file is greater then the input buffer  */
								stat(source_filename, &filestat);
								if(uInBufferLength < ((uint32_t)filestat.st_size))
								{	/* Note this was commented out so the pretection of the file size not to be able to be overwriiten 
									so not posiible to write begger files in  asmaller area 
									if( uForce == 1 )
									dagutil_warning("input file (size: %d) is greater in size than the target ROM location (size: %d)\n", 
									((uint32_t)filestat.st_size), uInBufferLength );
									else */ 
									if(uInBufferLength == 0)
									{
										dagutil_panic("trying to load a firmware image into an undefined firmware slot.\n");
										
									}else
									{

										dagutil_panic("input file (size: %d) is greater in size than the target ROM location (size: %d)\n", 
									((uint32_t)filestat.st_size), uInBufferLength);
									}
								}
								
								uInBuffer = readfile(ifile, uInBufferLength, &uInBufferLength);
								if(uInBuffer == NULL)
								{
									dagutil_panic("fread from stdin: %s\n", strerror(errno));
								}
	
								/* Print the size of the file */
								dagutil_verbose("Size of image (bytes) : %d\n", uInBufferLength);
							}
	
							fclose(ifile);
							break;
						}
#if defined(__FreeBSD__) || defined(__linux__) || (defined(__SVR4) && defined(__sun)) || (defined(__APPLE__) && defined(__ppc__))
#ifdef TEST_FLASH
						uInBuffer = readfile(stdin, uInBufferLength, &uInBufferLength);
						if (uInBuffer == NULL)
						{
							if (1 == uHoldPbiBus)
							{
								dagrom_pbirelease(rp);
							}
							dagutil_panic("fread from stdin: %s\n", strerror(errno));
						}
#else
						uInBuffer = readfile(stdin, uInBufferLength, &uInBufferLength);
						if (uInBuffer == NULL)
						{
							if (1 == uHoldPbiBus)
							{
								dagrom_pbirelease(rp);
							}
							dagutil_panic("fread from stdin: %s\n", strerror(errno));
						}
#endif /* TEST_FLASH */
#endif /* Platform-specific code. */
						break;
	
					default:
						if (1 == uHoldPbiBus)
						{
							dagrom_pbirelease(rp);
						}
						dagutil_panic("internal error at %s line %u\n", __FILE__, __LINE__);
				}
				break;

			case FUNC_READ:
				if (dagrom_read(rp, uOutBuffer, start_address, end_address) < 0)
				{
					if (1 == uHoldPbiBus)
					{
						dagrom_pbirelease(rp);
					}
					dagutil_panic("dagrom_read failed \n");
				}
				break;

			case FUNC_CHECK:
				if(rp->rom_version == 0x2)
				{
					sign_field_size = 4;
				}else
				{
					sign_field_size = 0;
				}
				if ((uInBufferLength > 0) &&(0 == memcmp(uInBuffer, (uOutBuffer + sign_field_size),dagutil_min(uInBufferLength, uOutBufferLength))))
				{
					dagutil_verbose("reprog ok\n");
					func &= ~(FUNC_ERASE | FUNC_WRITE | FUNC_VERIFY);
				}
				else
				{
					where();
					func |= (FUNC_WRITE);
					dagutil_verbose("prog required\n");

					/* Check for key if accessing stable half of first ROM */
					dagrom_access(rp, rom_number, func, end_address);
				}
				break;

			case FUNC_ERASE:
				if(dagrom_safe_erase(rp, start_address, end_address) != 0 && !err_continue )
				return EXIT_FAILURE;
                    		//exit(1);
				break;

			case FUNC_WRITE:
				if(uInBufferLength == 0)
				{
					dagutil_panic("Trying to program an image of size 0 Bytes \n");
				}
				else if ((src != SRC_ONES))
				{
					// added support if a copro is presented 
					if ( (rp->mpu_id == DAG_MPU_NONE) || ((rp->mpu_id == DAG_MPU_COPRO_SMALL) || (rp->mpu_id == DAG_MPU_COPRO_BIG)))
					{		
						check_image(rom_number, daginfo, dagfd);
					}
					
					//dagutil_verbose("SOURCE :%d %p\n",src,uInBuffer);
					/* source image okay, check size of source image fits into target ROM, if so, then erase and write */
					if(dagrom_safe_erase(rp, start_address, end_address) != 0 && !err_continue)
						return (EXIT_FAILURE);
                        		//exit(1);
					dagrom_program(rp, uInBuffer, uInBufferLength, start_address, end_address);
				}
				break;

			case FUNC_VERIFY:
				/* In case the virification failes 
					returns error no other function will be performed which implies that -y should be used by itself or last
					operation when FUNC_VERIFY implied 
				*/
				if (dagrom_verify(rp, uInBuffer, uInBufferLength, uOutBuffer, uOutBufferLength, start_address, end_address) != 0 )
					return EXIT_FAILURE;
				break;

			case FUNC_EXPORT:
				if ((NULL == fileout_buf) || (0 == strlen(fileout_buf)))
				{
					dagutil_panic("No output file specified.\n");
				}
				
				out_file = fopen(fileout_buf, "w+");
				if (out_file == NULL)
				{
					dagutil_panic("fopen('%s'): %s\n", fileout_buf, strerror(errno));
				}
				
				if (fwrite(uOutBuffer, 1, uOutBufferLength, out_file) != uOutBufferLength)
				{
					if (1 == uHoldPbiBus)
					{
						dagrom_pbirelease(rp);
					}
					dagutil_panic("fwrite: %s\n", strerror(errno));
				}
				break;

			case FUNC_PROGRAM:
				if((1 == (uint8_t)programming_supported(daginfo)) || (uForce == 1))
				{
					if(uForce == 1)
						fprintf(stderr,"forcing dagrom -p.This my produce some unexpected results on some motherboards.\n");
					dagrom_loadcurrent(dagfd, rp);
				}
				else	
				{
					dagutil_warning("dagrom -p not supported on this card.Please use the power on image programming table.\n");
				}
				/*special case for Dag9.1x we have to restore the configuration space of the second core.*/	
				if (daginfo->device_code == PCI_DEVICE_ID_DAG_9_1x2Rx)
				{
                    int magic = DAGRESET_REBOOT;
#if defined(__FreeBSD__) || defined(__linux__) || defined (__NetBSD__) || (defined(__SVR4) && defined(__sun)) || (defined(__APPLE__) && defined(__ppc__))
					int dag_core2_fd = dag91x_open_2nd_core(dagname);
                    			if (dag_core2_fd <= 0)
					{
						dagutil_warning("Failed to open 2nd core of the 9.1x\n");
						break;
					}
					
					if (ioctl(dag_core2_fd, DAGIOCRESET, &magic) < 0)
					{
						dagutil_warning("Failed to reset 2nd core of the 9.1x\n");
					}
					close(dag_core2_fd);
#elif defined(_WIN32) /* _WIN32 */
                   
		    DWORD BytesTransferred = 0;
                    HANDLE dag_core2_fd = dag91x_open_2nd_core(dagname);
                    if (dag_core2_fd == NULL)
                    {
                        dagutil_warning("Failed to reset the 2nd core of the 9.1x\n");
                        break;
                    }
                    if (DeviceIoControl(dag_core2_fd, IOCTL_RESET, NULL, 0, NULL, 0, &BytesTransferred, NULL) == FALSE)
		                dagutil_panic("loadcurrent DAGIOCRESET DAGRESET_REBOOT\n");
                    
		
#else
#error Compiling on an unsupported platform - please contact <support@endace.com> for assistance.
#endif /* Platform-specific code. */
				}
				

				/* special case for the 8.2x. Because it uses a bridge chip that uses 2 PCI slots
				 * we need to reset the 2nd core as well.
				 */
				if (daginfo->device_code == PCI_DEVICE_ID_DAG8_20E)
				{
                    int magic = DAGRESET_REBOOT;
#if defined(__FreeBSD__) || defined(__linux__) || defined (__NetBSD__) || (defined(__SVR4) && defined(__sun)) || (defined(__APPLE__) && defined(__ppc__))
					int dag_core2_fd = dag82x_open_2nd_core(dagname);
                    if (dag_core2_fd <= 0)
					{
						dagutil_warning("Failed to open 2nd core of the 8.2x\n");
						break;
					}
					
					if (ioctl(dag_core2_fd, DAGIOCRESET, &magic) < 0)
					{
						dagutil_warning("Failed to reset 2nd core of the 8.2x\n");
					}
					close(dag_core2_fd);
#elif defined(_WIN32) /* _WIN32 */
                    DWORD BytesTransferred = 0;
                    HANDLE dag_core2_fd = dag82x_open_2nd_core(dagname);
                    if (dag_core2_fd == NULL)
                    {
                        dagutil_warning("Failed to reset the 2nd core of the 8.2x\n");
                        break;
                    }
                    if (DeviceIoControl(dag_core2_fd, IOCTL_RESET, NULL, 0, NULL, 0, &BytesTransferred, NULL) == FALSE)
		                dagutil_panic("loadcurrent DAGIOCRESET DAGRESET_REBOOT\n");
                    
#else
#error Compiling on an unsupported platform - please contact <support@endace.com> for assistance.
#endif /* Platform-specific code. */
				}
				usleep( 500 * 1000 );
				if (rp != NULL) {
					dagrom_free(rp);
				}
				rp = dagrom_init(dagfd, rom_number, uHoldPbiBus);
				break;

			case FUNC_XIMGTBL:
				set_power_on_img_selection_table(rp,image_number,image_table_fpga);
				break;
			case FUNC_XREV:
				if ((target_processor_region != BOOT_REGION) && (target_processor_region != KERNEL_REGION) && (target_processor_region != FS_REGION))
                		{
					dagrom_xrev(rp);
                		}
				
				if(rp->rom_version == 0x2)
				{
					if(dagrom_check_for_copro(rp))
						dagrom_xrev_copro(rp);
				}
				else
				{
					if ((rp->mpu_id == DAG_MPU_COPRO_SMALL) || (rp->mpu_id == DAG_MPU_COPRO_BIG)) 
					{
						dagrom_xrev_copro(rp) ;
					}
				}
				func &= ~FUNC_XUPDATE;
				break;
			default:
				if (1 == uHoldPbiBus)
				{
					dagrom_pbirelease(rp);
				}
				dagutil_panic("internal error at %s line %u\n", __FILE__, __LINE__);
				break;
		}
	}

	/* In case we did a complete ROM cleanout. */
	if (1 == uWritebackSwid)
	{
		iret = dagswid_write(rp, (uint8_t*) uSwidBuffer, DAGSERIAL_SIZE, uKey);
		if (iret < 0)
		{
			dagutil_panic("failed to write back SWID after ROM erase: %d\n", iret);
		}
	}
	
	if (1 == uHoldPbiBus)
	{
		dagrom_pbirelease(rp);
	}

	dagutil_free(uOutBuffer);
	dagutil_free(uInBuffer);
	dagrom_free(rp);
	dag_close(dagfd);

	return EXIT_SUCCESS;
}


#ifndef ENDACE_UNIT_TEST
int
main(int argc, const char* const * argv)
{
	return dagrom_main(argc, (const char**) argv);
}
#endif /* ENDACE_UNIT_TEST */
