/*
 * Copyright 2015 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

/* Include */
#include "ecst.h"

/* Global Variables */
enum verbose_level g_verbose;
char input_file_name[NAME_SIZE];
char output_file_name[NAME_SIZE];
char arg_file_name[NAME_SIZE];
char g_hdr_input_name[NAME_SIZE];
char hdr_args[MAX_ARGS][ARG_SIZE];
char tmp_hdr_args[MAX_ARGS][ARG_SIZE];
FILE *input_file_pointer;
FILE *g_hfd_pointer;
FILE *arg_file_pointer;
FILE *api_file_pointer;
FILE *g_hdr_pointer;
void *gh_console;
unsigned short	g_text_atrib;
unsigned short	g_bg_atrib;
enum calc_type	g_calc_type;
unsigned int	ptr_fw_addr;
unsigned int	fw_offset;
int		is_ptr_merge;
unsigned int	g_ram_start_address;
unsigned int	g_ram_size;
unsigned int	api_file_size_bytes;

/* Chips information, RAM start address and RAM size. */
struct chip_info chip_info[] = {{NPCX5M5G_RAM_ADDR, NPCX5M5G_RAM_SIZE},
				{NPCX5M6G_RAM_ADDR, NPCX5M6G_RAM_SIZE} };

static unsigned int calc_api_csum_bin(void);
static unsigned int initialize_crc_32(void);
static unsigned int update_crc_32(unsigned int crc, char c);
static unsigned int finalize_crc_32(unsigned int crc);

/*
 *----------------------------------------------------------------------
 * Function:	main()
 * Parameters:	argc, argv
 * Return:		0
 * Description:	Parse the arguments
 *		Chose manipulation routine according to arguments
 *
 *		In case of bin, save optional parameters given by user
 *----------------------------------------------------------------------
 */
int main(int argc, char *argv[])

{

	int mode_choose = FALSE;
	/* Do we get a bin File? */
	int main_fw_hdr_flag = FALSE;
	/* Do we get a API bin File? */
	int main_api_flag = FALSE;
	/* Do we need to create a BootLoader Header file? */
	int main_hdr_flag = FALSE;

	/* Following variables: common to all modes */
	int main_status = TRUE;
	unsigned int  main_temp = 0L;
	char		   main_str_temp[TMP_STR_SIZE];

	int arg_num;
	int arg_ind;
	int tmp_ind;
	int tmp_arg_num;
	int cur_arg_index;
	FILE *tmp_file;

	/* Following variables are used when bin file is provided */
	struct tbinparams bin_params;
	bin_params.bin_params = 0;

	input_file_name[0]	= '\0';
	memset(input_file_name, 0, NAME_SIZE);
	output_file_name[0]	  = '\0';
	memset(output_file_name, 0, NAME_SIZE);
	arg_file_name[0]	  = '\0';
	memset(arg_file_name, 0, NAME_SIZE);
	g_hdr_input_name[0] = '\0';
	memset(g_hdr_input_name, 0, NAME_SIZE);

	/* Initialize Global variables */
	g_verbose = NO_VERBOSE;

	g_ram_start_address = chip_info[NPCX5M5G].ram_addr;
	g_ram_size	    = chip_info[NPCX5M5G].ram_size;

	/* Set default values */
	g_calc_type = CALC_TYPE_NONE;
	bin_params.spi_max_clk = SPI_MAX_CLOCK_DEFAULT;
	bin_params.spi_read_mode = SPI_READ_MODE_DEFAULT;
	bin_params.fw_load_addr =
				chip_info[NPCX5M5G].ram_addr;
	bin_params.fw_ep =
				chip_info[NPCX5M5G].ram_addr;
	bin_params.fw_err_detec_s_addr = FW_CRC_START_ADDR;
	bin_params.fw_err_detec_e_addr = FW_CRC_START_ADDR;
	bin_params.flash_size = FLASH_SIZE_DEFAULT;
	bin_params.fw_hdr_offset = 0;

	ptr_fw_addr = 0x00000000;
	fw_offset = 0x00000000;
	is_ptr_merge = FALSE;

	/* Get Standard Output Handler */

	/* Wrong Number of Arguments ? No problem */
	if (argc < 3)
		exit_with_usage();

	/* Read all arguments to local array. */
	for (arg_num = 0; arg_num < argc; arg_num++)
		strncpy(hdr_args[arg_num], argv[arg_num], ARG_SIZE);

	/* Loop all arguments. */
	/* Parse the Arguments - supports ecrp and bin */
	for (arg_ind = 1; arg_ind < arg_num; arg_ind++) {
		/* -h display help screen */
		if (str_cmp_no_case(hdr_args[arg_ind], "-h") == 0)
			exit_with_usage();

		/* -v verbose */
		else if (str_cmp_no_case(hdr_args[arg_ind], "-v") == 0)
			g_verbose = REGULAR_VERBOSE;

		/* Super verbose. */
		else if (str_cmp_no_case(hdr_args[arg_ind], "-vv") == 0)
			g_verbose = SUPER_VERBOSE;

		else if (str_cmp_no_case(hdr_args[arg_ind],
							"-mode") == 0) {
			mode_choose = TRUE;
			arg_ind++;
			if ((hdr_args[arg_ind] == NULL) ||
				(sscanf(hdr_args[arg_ind],
					"%s", main_str_temp) != 1)) {
				my_printf(TERR, "\nCannot read operation mode");
				my_printf(TERR, ", bt, bh or api. !\n");
				main_status = FALSE;
			} else {
				/* bt, bh and api should not coexist */
				if (main_fw_hdr_flag ||
				    main_api_flag ||
				    main_hdr_flag) {
					my_printf(TERR, "\nOperation modes bt");
					my_printf(TERR, ", bh, and api should");
					my_printf(TERR, " not coexist.\n");
					main_status = FALSE;
				}

				if (str_cmp_no_case(main_str_temp, "bt") == 0)
					main_fw_hdr_flag = TRUE;
				else if (str_cmp_no_case(main_str_temp,
							 "bh") == 0)
					main_hdr_flag = TRUE;
				else if (str_cmp_no_case(main_str_temp,
							 "api") == 0)
					main_api_flag = TRUE;
				else {
					my_printf(TERR,
						  "\nInvalid operation mode ");
					my_printf(TERR,
						  "(%s)\n", main_str_temp);
					main_status = FALSE;
				}
			}
		}

		else if (str_cmp_no_case(hdr_args[arg_ind], "-chip") == 0) {
			arg_ind++;
			if ((hdr_args[arg_ind] == NULL) ||
				(sscanf(hdr_args[arg_ind],
					"%s",
					main_str_temp) != 1)) {
				my_printf(TERR, "\nCannot read chip name, ");
				my_printf(TERR,	"npcx5m5g or npcx5m6g.\n");
				main_status = FALSE;
			} else {
				if (str_cmp_no_case(main_str_temp,
						    "npcx5m5g") == 0) {
					if ((bin_params.bin_params
						& BIN_FW_LOAD_START_ADDR) ==
								0x00000000)
						bin_params.fw_load_addr =
						   chip_info[NPCX5M5G].ram_addr;

					if ((bin_params.bin_params &
					     BIN_FW_ENTRY_POINT) == 0x00000000)
						bin_params.fw_ep =
						   chip_info[NPCX5M5G].ram_addr;

					g_ram_start_address =
						chip_info[NPCX5M5G].ram_addr;
					g_ram_size =
						chip_info[NPCX5M5G].ram_size;
				} else if (str_cmp_no_case(main_str_temp,
							   "npcx5m6g") == 0) {
					if ((bin_params.bin_params &
						BIN_FW_LOAD_START_ADDR) ==
								0x00000000)
						bin_params.fw_load_addr =
						   chip_info[NPCX5M6G].ram_addr;

					if ((bin_params.bin_params &
						BIN_FW_ENTRY_POINT) ==
								0x00000000)
						bin_params.fw_ep =
						   chip_info[NPCX5M6G].ram_addr;

					g_ram_start_address =
						chip_info[NPCX5M6G].ram_addr;
					g_ram_size =
						chip_info[NPCX5M6G].ram_size;

				} else {
					my_printf(TERR,
						  "\nInvalid chip name (%s) ",
						  main_str_temp);
					my_printf(TERR, "should be npcx5m5g ");
					my_printf(TERR, "or npcx5m6g.\n");
						  main_status = FALSE;
				}

			}
		  /* -argfile Read argument file. File name must be after it.*/
		} else if (str_cmp_no_case(hdr_args[arg_ind],
					   "-argfile") == 0) {
			arg_ind++;
			if (arg_ind < arg_num) {
				strncpy(arg_file_name,
						hdr_args[arg_ind],
						sizeof(arg_file_name));
				arg_file_pointer = fopen(arg_file_name, "rt");
				if (arg_file_pointer == NULL) {
					my_printf(TERR,
						  "\n\nCannot open %s\n\n",
						  arg_file_name);
					main_status = FALSE;
				} else {
					cur_arg_index = arg_ind;

					/* Copy the arguments to temp array. */
					for (tmp_ind = 0;
					     (tmp_ind + arg_ind + 1) < arg_num;
					     tmp_ind++)
						strncpy(tmp_hdr_args[tmp_ind],
							hdr_args
							   [tmp_ind+arg_ind+1],
							ARG_SIZE);

					tmp_arg_num = tmp_ind;

					/* Read arguments from file to array */
					for (arg_ind++;
					     fscanf(arg_file_pointer,
						    "%s",
						    hdr_args[arg_ind]) == 1;
					     arg_ind++)
						;

					fclose(arg_file_pointer);
					arg_file_pointer = NULL;

					/* Copy back the restored arguments. */
					for (tmp_ind = 0;
						 tmp_ind < tmp_arg_num;
						 tmp_ind++) {
						strncpy(hdr_args[arg_ind++],
							tmp_hdr_args[tmp_ind],
							ARG_SIZE);
					}
					arg_num = arg_ind;
					arg_ind = cur_arg_index;
				}

			} else {
				my_printf(TERR,
					  "\nMissing Argument File Name\n");
				main_status = FALSE;
			}
			/* -i get input file name. */
		} else if (str_cmp_no_case(hdr_args[arg_ind], "-i") == 0) {
			arg_ind++;
			if (arg_ind < arg_num) {
				strncpy(input_file_name,
				hdr_args[arg_ind],
				sizeof(input_file_name));
			} else {
				my_printf(TERR, "\nMissing Input File Name\n");
				main_status = FALSE;
			}
		  /* -o Get output file name. */
		} else if (str_cmp_no_case(hdr_args[arg_ind], "-o") == 0) {
			arg_ind++;
			if (arg_ind < arg_num) {
				strncpy(output_file_name,
					hdr_args[arg_ind],
					sizeof(output_file_name));
			} else {
				my_printf(TERR,
					  "\nMissing Output File Name.\n");
				main_status = FALSE;
			}
		  /* -usearmrst	get FW entry point from FW image offset 4.*/
		} else if (str_cmp_no_case(hdr_args[arg_ind],
					   "-usearmrst") == 0) {
			if ((bin_params.bin_params &
			     BIN_FW_ENTRY_POINT) != 0x00000000) {
				my_printf(TERR, "\n-usearmrst not allowed, ");
				my_printf(TERR, "FW entry point already set ");
				my_printf(TERR, "using -fwep !\n");
				main_status = FALSE;
			} else
				bin_params.bin_params |=
							BIN_FW_USER_ARM_RESET;
		/* -nohcrs	disable header CRC*/
		} else if (str_cmp_no_case(hdr_args[arg_ind], "-nohcrc") == 0)
			bin_params.bin_params |=
							BIN_FW_HDR_CRC_DISABLE;
		/* -ph merg header in BIN file. */
		else if (str_cmp_no_case(hdr_args[arg_ind], "-ph") == 0) {
			bin_params.bin_params |=
							BIN_FW_HDR_OFFSET;
			if ((strlen(hdr_args[arg_ind+1]) == 0) ||
				(sscanf(hdr_args[arg_ind+1],
					"%x",
					&main_temp) != 1))
				bin_params.fw_hdr_offset = 0;
			else {
				arg_ind++;
				bin_params.fw_hdr_offset = main_temp;
			}
		  /* -spimacclk  Get SPI flash mac clock. */
		} else if (str_cmp_no_case(hdr_args[arg_ind],
					   "-spimaxclk") == 0) {
			arg_ind++;
			if ((hdr_args[arg_ind] == NULL) ||
				(sscanf(hdr_args[arg_ind],
					"%d", &main_temp) != 1)) {
				my_printf(TERR, "\nCannot read SPI Flash Max");
				my_printf(TERR, " Clock !\n");
				main_status = FALSE;
			} else
				bin_params.spi_max_clk =
						(unsigned char)main_temp;
		  /* spireadmode	get SPI read mode. */
		} else if (str_cmp_no_case(hdr_args[arg_ind],
					   "-spireadmode") == 0) {
			arg_ind++;
			if ((hdr_args[arg_ind] == NULL) ||
				(sscanf(hdr_args[arg_ind],
						"%20s",
						main_str_temp) != 1)) {
				my_printf(TERR, "\nCannot read SPI Flash");
				my_printf(TERR, " Read Mode !\n");
				main_status = FALSE;
			} else {
				if (str_cmp_no_case(main_str_temp,
						SPI_NORMAL_MODE_VAL) == 0)
					bin_params.spi_read_mode =
					(unsigned char) SPI_NORMAL_MODE;
				else if (str_cmp_no_case(main_str_temp,
					 SPI_SINGLE_MODE_VAL) == 0)
					bin_params.spi_read_mode =
						(unsigned char)
						SPI_SINGLE_MODE;
				else if (str_cmp_no_case(main_str_temp,
					 SPI_DUAL_MODE_VAL) == 0)
					bin_params.spi_read_mode =
						(unsigned char)
						SPI_DUAL_MODE;
				else if (str_cmp_no_case(main_str_temp,
					SPI_QUAD_MODE_VAL) == 0)
					bin_params.spi_read_mode =
						(unsigned char)
						SPI_QUAD_MODE;
				else {
					my_printf(TERR,
						  "\nInvalid SPI Flash Read "
						  "Mode (%s), it should be "
						  "normal, singleMode, "
						  "dualMode or quadMode !\n",
						  main_str_temp);
					main_status = FALSE;
				}
			}
		  /* -nofcrc	disable FW CRC. */
		} else if (str_cmp_no_case(hdr_args[arg_ind], "-nofcrc") == 0)
			bin_params.bin_params |=
							BIN_FW_CRC_DISABLE;

		/* -fwloadaddr,	 Get the FW load address. */
		else if (str_cmp_no_case(hdr_args[arg_ind],
					 "-fwloadaddr") == 0) {
			arg_ind++;
			if ((hdr_args[arg_ind] == NULL) ||
				(sscanf(hdr_args[arg_ind],
					"%x",
					&main_temp) != 1)) {
				my_printf(TERR, "\nCannot read FW Load ");
				my_printf(TERR, "\nstart address !\n");
				main_status = FALSE;
			} else {
				/* Check that the address is 16-bytes aligned */
				if ((main_temp &
					ADDR_16_BYTES_ALIGNED_MASK) != 0) {
					my_printf(TERR,
						  "\nFW load address start "
						  "address (0x%08X) is not "
						  "16-bytes aligned !\n",
						  main_temp);
					main_status = FALSE;
				} else {
					bin_params.fw_load_addr =
								     main_temp;
					bin_params.bin_params |=
							BIN_FW_LOAD_START_ADDR;
				}
			}
		  /* -fwep, Get the FW entry point. */
		} else if (str_cmp_no_case(hdr_args[arg_ind], "-fwep") == 0) {
			if ((bin_params.bin_params & BIN_FW_USER_ARM_RESET)
								!= 0x00000000) {
				my_printf(TERR,
					  "\n-fwep not allowed, FW entry point"
					  " already set using -usearmrst!\n");
				main_status = FALSE;
			} else {
				arg_ind++;
				if ((hdr_args[arg_ind] == NULL) ||
					(sscanf(hdr_args[arg_ind],
						"%x",
						&main_temp) != 1)) {
					my_printf(TERR,
						  "\nCan't read FW E-Point\n");
					main_status = FALSE;
				} else {
					bin_params.fw_ep =
								main_temp;
					bin_params.bin_params |=
							BIN_FW_ENTRY_POINT;
				}
			}
		  /*
		   * -crcstart, Get the address from where to calculate
		   * the FW CRC.
		   */
		} else if (str_cmp_no_case(hdr_args[arg_ind],
					   "-crcstart") == 0) {
			arg_ind++;
			if ((hdr_args[arg_ind] == NULL) ||
				(sscanf(hdr_args[arg_ind],
					"%x",
					&main_temp) != 1)) {
						my_printf(TERR,
						  "\nCannot read FW CRC"
						  " start address !\n");
				main_status = FALSE;
			} else {
				bin_params.fw_err_detec_e_addr =
					bin_params.fw_err_detec_e_addr -
					bin_params.fw_err_detec_s_addr
					+ main_temp;
				bin_params.fw_err_detec_s_addr =
								main_temp;
				bin_params.bin_params |= BIN_FW_CKS_START;
			}
		  /* -crcsize,  Get the area size that need to be CRCed. */
		} else if (str_cmp_no_case(hdr_args[arg_ind],
					   "-crcsize") == 0) {
			arg_ind++;
			if ((hdr_args[arg_ind] == NULL) ||
				(sscanf(hdr_args[arg_ind], "%x", &main_temp)
									!= 1)) {
				my_printf(TERR, "\nCannot read FW CRC ");
				my_printf(TERR, "\area size !\n");
				main_status = FALSE;
			} else {
				bin_params.fw_err_detec_e_addr =
					bin_params.fw_err_detec_s_addr
					+ main_temp - 1;
				bin_params.bin_params |= BIN_FW_CKS_SIZE;
			}
		}
		/* -fwlen, Get the FW length. */
		else if (str_cmp_no_case(hdr_args[arg_ind], "-fwlen") == 0) {
			arg_ind++;
			if ((hdr_args[arg_ind] == NULL) ||
				(sscanf(hdr_args[arg_ind],
					"%x",
					&main_temp) != 1)) {
				my_printf(TERR, "\nCannot read FW length !\n");
				main_status = FALSE;
			} else {
				bin_params.fw_len = main_temp;
				bin_params.bin_params |= BIN_FW_LENGTH;
			}
		}
		/* flashsize, Get the flash size. */
		else if (str_cmp_no_case(hdr_args[arg_ind],
					 "-flashsize") == 0) {
			arg_ind++;
			if ((hdr_args[arg_ind] == NULL) ||
				(sscanf(hdr_args[arg_ind],
					"%d",
					&main_temp) != 1)) {
				my_printf(TERR, "\nCannot read Flash size !\n");
				main_status = FALSE;
			} else
				bin_params.flash_size = main_temp;
		  /* -apisign, Get the method for error detect calculation. */
		} else if (str_cmp_no_case(hdr_args[arg_ind],
					   "-apisign") == 0) {
			arg_ind++;
			if ((hdr_args[arg_ind] == NULL) ||
				(sscanf(hdr_args[arg_ind],
					"%s",
					main_str_temp) != 1)) {
				my_printf(TERR, "\nCannot read API sign, CRC,");
				my_printf(TERR, " CheckSum or None. !\n");
				main_status = FALSE;
			} else {
				if (!main_api_flag) {
					my_printf(TERR, "\n-apisign is valid ");
					my_printf(TERR, "-only with -api.\n");
					main_status = FALSE;
				}

				if (str_cmp_no_case(main_str_temp, "crc") == 0)
					g_calc_type = CALC_TYPE_CRC;

				else if (str_cmp_no_case(main_str_temp,
							 "checksum") == 0)
					g_calc_type = CALC_TYPE_CHECKSUM;

				else {
					my_printf(TERR,
						  "\nInvalid API sign (%s)\n",
						  main_str_temp);
					main_status = FALSE;
				}

			}
		  /* -pointer,  Get the FW image address. */
		} else if (str_cmp_no_case(hdr_args[arg_ind],
					   "-pointer") == 0) {
			arg_ind++;
			if ((hdr_args[arg_ind] == NULL) ||
				(sscanf(hdr_args[arg_ind],
					"%x",
					&main_temp) != 1)) {
				my_printf(TERR,
					  "\nCannot read FW Image address !\n");
				main_status = FALSE;
			} else {
				/* Check that the address is 16-bytes aligned */
				if ((main_temp & ADDR_16_BYTES_ALIGNED_MASK)
									!= 0) {
					my_printf(TERR,
						  "\nFW Image address (0x%08X)"
						  " isn't 16-bytes aligned !\n",
						  main_temp);
					main_status = FALSE;
				}

				if (main_temp > MAX_FLASH_SIZE) {
					my_printf(TERR,
						  "\nPointer address (0x%08X) ",
						  main_temp);
					my_printf(TERR,
						  "is higher from flash size");
					my_printf(TERR,
						  " (0x%08X) !\n",
						  MAX_FLASH_SIZE);
					main_status = FALSE;
				} else {
					ptr_fw_addr = main_temp;
					is_ptr_merge = FALSE;
				}
			}
		}
		/* -bhoffset,  BootLoader Header Offset (BH location in BT). */
		else if (str_cmp_no_case(hdr_args[arg_ind], "-bhoffset") == 0) {
			arg_ind++;
			if ((hdr_args[arg_ind] == NULL) ||
				(sscanf(hdr_args[arg_ind], "%x", &main_temp)
									!= 1)) {
				my_printf(TERR, "\nCannot read BootLoader");
				my_printf(TERR, " Header Offset !\n");
				main_status = FALSE;
			} else {
				/* Check that the address is 16-bytes aligned */
				if ((main_temp & ADDR_16_BYTES_ALIGNED_MASK)
									!= 0) {
					my_printf(TERR,
						  "\nFW Image address (0x%08X) "
						  "is not 16-bytes aligned !\n",
						  main_temp);
					main_status = FALSE;
				}

				if (main_temp > MAX_FLASH_SIZE) {
					my_printf(TERR,
						  "\nFW Image address (0x%08X)"
						  " is higher from flash size "
						  "(0x%08X) !\n",
						  main_temp,
						  MAX_FLASH_SIZE);
					main_status = FALSE;
				} else {
					fw_offset = main_temp;
					is_ptr_merge = TRUE;
				}
			}
		} else {
			my_printf(TERR,
				  "\nUnknown flag: %s\n",
				  hdr_args[arg_ind]);
			main_status = FALSE;
		}
	}

	/*
	* If the input and output file have the same name then exit with error.
	*/
	if (strcmp(output_file_name, input_file_name) == 0) {
		my_printf(TINF,
			"Input file name (%s) should be differed from\n",
			input_file_name);
		my_printf(TINF, "Output file name (%s).\n", output_file_name);
		main_status = FALSE;
	}

	/* No problems reading argv? So go on... */
	if (main_status) {

		/* if output file already exist, then delete it. */
		tmp_file = fopen(output_file_name, "w");
		if (tmp_file != NULL)
			fclose(tmp_file);

		/* If no mode choose than "bt" is the default mode.*/
		if (mode_choose == FALSE)
			main_fw_hdr_flag = TRUE;

		/* Chose manipulation routine according to arguments */
		if (main_fw_hdr_flag)
			main_status = main_bin(bin_params);
		else if (main_api_flag)
			main_status = main_api();
		else if (main_hdr_flag)
			main_status = main_hdr();
		else
			exit_with_usage();
	}



	/* Be sure there's no open file before you leave */
	if (input_file_pointer)
		fclose(input_file_pointer);
	if (g_hfd_pointer)
		fclose(g_hfd_pointer);
	if (api_file_pointer)
		fclose(api_file_pointer);

	/* Delete temprary header file. */
	remove(g_hdr_input_name);

	/* Say Bye Bye */
	if (main_status) {
		my_printf(TPAS, "\n\n******************************");
		my_printf(TPAS,	  "\n***	SUCCESS		***");
		my_printf(TPAS,	  "\n******************************\n");

		exit(EXIT_SUCCESS);
	} else {
		my_printf(TERR, "\n\n******************************");
		my_printf(TERR,	  "\n***	FAILED		***");
		my_printf(TERR,	  "\n******************************\n");

		exit(EXIT_FAILURE);
	}

}


/*
 *-----------------------------------------------------------------------
 * Function:	exit_with_usage()
 * Parameters:	none
 * Return:		none
 * Description: No Words...
 *-----------------------------------------------------------------------
 */
void exit_with_usage(void)
{
	my_printf(TUSG,
		  "\nECST, Embedded Controller Sign Tool, version %d.%d.%d",
		  T_VER, T_REV_MAJOR, T_REV_MINOR);
	my_printf(TUSG, "\n");
	my_printf(TUSG, "\nUsage:");
	my_printf(TUSG, "\n ");
	my_printf(TUSG, "\n ECST -mode <bt|bh|api> -i <filename> [Flags]");
	my_printf(TUSG, "\n ");
	my_printf(TUSG, "\nOperation Modes: ");
	my_printf(TUSG, "\n bt	- BootLoader Table");
	my_printf(TUSG, "\n bh	- BootLoader Header");
	my_printf(TUSG, "\n api	- Download from Flash API");
	my_printf(TUSG, "\n ");
	my_printf(TUSG, "\nCommon flags:");
	my_printf(TUSG, "\n -mode <type>		- Operation mode: ");
	my_printf(TUSG, "bt|bh|api (default is bt)");
	my_printf(TUSG, "\n -i <filename>		- Input file name; ");
	my_printf(TUSG, "must differ from the output file name");
	my_printf(TUSG, "\n -o <filename>		- Output file name ");
	my_printf(TUSG, "(default is out_<input_filename>.bin)");
	my_printf(TUSG, "\n -argfile <filename>	- Arguments file name; ");
	my_printf(TUSG, "includes multiple flags");
	my_printf(TUSG, "\n -chip <name>		- EC Chip Name: ");
	my_printf(TUSG, "npcx5m5g|npcx5m6g (default is npcx5m5g)");
	my_printf(TUSG,	"\n -v			- Verbose; prints ");
	my_printf(TUSG,	"information messages");
	my_printf(TUSG, "\n -vv			- Super Verbose; prints ");
	my_printf(TUSG, "intermediate calculations");
	my_printf(TUSG, "\n -h			- Show this help screen");
	my_printf(TUSG, "\n ");
	my_printf(TUSG, "\nBootLoader Table mode flags:");
	my_printf(TUSG, "\n -nohcrc		- Disable CRC on header ");
	my_printf(TUSG, "(default is ON)");
	my_printf(TUSG, "\n -nofcrc		- Disable CRC on firmware ");
	my_printf(TUSG, "(default is ON)");
	my_printf(TUSG, "\n -spimaxclk <val>	- SPI Flash Maximum Clock, in");
	my_printf(TUSG, " MHz: 20|25|33|40|50 (default is 20)");
	my_printf(TUSG, "\n -spireadmode <type>	- SPI Flash Read Mode: ");
	my_printf(TUSG, "normal|fast|dual|quad (default is normal)");
	my_printf(TUSG, "\n -fwloadaddr <addr>	- Firmware load start ");
	my_printf(TUSG, "address (default is Start-of-RAM)");
	my_printf(TUSG, "\n			  Located in code RAM, ");
	my_printf(TUSG, "16-bytes aligned, hex format");
	my_printf(TUSG, "\n -usearmrst		- Use the ARM reset table ");
	my_printf(TUSG, "entry as the Firmware Entry Point");
	my_printf(TUSG, "\n			  Can't be used with -fwep");
	my_printf(TUSG, "\n -fwep <addr>		- Firmware entry ");
	my_printf(TUSG, "point (default is Firmware Entry Point)");
	my_printf(TUSG, "\n			  Located in firmware area,");
	my_printf(TUSG, " hex format");
	my_printf(TUSG, "\n -crcstart <offset>	- Firmware CRC start offset ");
	my_printf(TUSG, "(default is 00000000)");
	my_printf(TUSG, "\n			  Offset from firmware image,");
	my_printf(TUSG, " 4B-aligned, for partial CRC, hex format");
	my_printf(TUSG, "\n -crcsize <val>		- Firmware CRC size ");
	my_printf(TUSG, "(default is entire firmware size)");
	my_printf(TUSG, "\n			  4B-aligned, for partial ");
	my_printf(TUSG, "CRC, hex format");
	my_printf(TUSG, "\n -fwlen <val>		- Firmware length, ");
	my_printf(TUSG, "16B-aligned, hex format (default is file size).");
	my_printf(TUSG, "\n -flashsize <val>	- Flash size, in MB: ");
	my_printf(TUSG, "1|2|4|8|16 (default is 16)");
	my_printf(TUSG, "\n -ph <offset>		- Paste the Firmware ");
	my_printf(TUSG, "Header in the input file copy at the selected");
	my_printf(TUSG, "\n			  offset ");
	my_printf(TUSG, "(default is 00000000), hex format.");
	my_printf(TUSG, "\n			  The firmware itself is ");
	my_printf(TUSG, "expected to start at offset + 64 bytes.");
	my_printf(TUSG, "\n ");
	my_printf(TUSG, "\nBootLoader Header mode flags:");
	my_printf(TUSG, "\n -pointer <offset>	- BootLoader Table location");
	my_printf(TUSG, " in the flash, hex format");
	my_printf(TUSG, "\n -bhoffset <offset>	- BootLoader Header Offset");
	my_printf(TUSG, " in file, hex format (BH location in BT)");
	my_printf(TUSG, "\n ");
	my_printf(TUSG, "\nAPI mode flags:");
	my_printf(TUSG, "\n -apisign <type>	- Signature type: ");
	my_printf(TUSG, "crc|checksum (default is OFF)");
	my_printf(TUSG, "\n\n");

	exit(EXIT_FAILURE);
}

/*
 *--------------------------------------------------------------------------
 * Function:	copy_file_to_file()
 * Parameters:	dst_file_name	- Destination file name.
 *		src_file_name	- Source file name.
 *		offset		- number of bytes from the origin.
 *		origin		- From where to seek, START, END, or CURRENT of
 *				  file.
 * Return: Number of copied bytes
 * Description: Copy the source file to the end of the destination file.
 *--------------------------------------------------------------------------
 */
int copy_file_to_file(char *dst_file_name,
		      char *src_file_name,
		      int offset,
		      int  origin)
{

	int		index;
	int		result = 0;
	unsigned char	local_val;
	int		src_file_size;
	FILE		*dst_file;
	FILE		*src_file;

	/* Open the destination file for append. */
	dst_file = fopen(dst_file_name, "r+b");
	if (dst_file == NULL) {
		/* destination file not exist, create it. */
		dst_file = fopen(dst_file_name, "ab");
		if (dst_file == NULL)
			return 0;
	}

	/* Open the source file for read. */
	src_file = fopen(src_file_name, "rb");
	if (src_file == NULL)
		return 0;

	/* Get the source file length in bytes. */
	src_file_size = get_file_length(src_file);

	/* Point to the end of the destination file, and to the start	*/
	/* of the source file.						*/
	fseek(dst_file, offset, origin);
	fseek(src_file, 0, SEEK_SET);

	/* Loop over all destination file and write it to the source file.*/
	for (index = 0; index < src_file_size; index++) {
		/* Read byte from source file. */
		result = (int)(fread(&local_val, 1, 1, src_file));

		/* If byte reading pass than write it to the destination, */
		/* else exit from the reading loop.			  */
		if (result)
			/* Read pass, so write it to destination file.*/
			result = fwrite(&local_val, 1, 1, dst_file);
		else
			/* Read failed, return with the copied bytes number. */
			break;
	}

	/* Close the files. */
	fclose(dst_file);
	fclose(src_file);

	/* Copy ended, return with the number of bytes that were copied. */
	return index;

}

/*
 *--------------------------------------------------------------------------
 * Function:	my_printf()
 * Parameters:	as in printf + error level
 * Return:		none
 * Description: No Words...
 *--------------------------------------------------------------------------
 */
void my_printf(int error_level, char *fmt, ...)
{
	char buffer[256];
	va_list argptr;
	va_start(argptr, fmt);
	vsprintf(buffer, fmt, argptr);
	va_end(argptr);

	if ((g_verbose == NO_VERBOSE) && (error_level == TINF))
		return;

	if ((error_level == TDBG) && (g_verbose != SUPER_VERBOSE))
		return;

	if (error_level == TERR)
		fprintf(stderr, "%s", buffer);
	else
		printf("%s", buffer);
}

/*
 *--------------------------------------------------------------------------
 * Function:	 write_to_file
 * Parameters:	 TBD
 * Return:		 TBD
 * Description:	 Writes to ELF or BIN files - whateves is open
 *--------------------------------------------------------------------------
 */
int write_to_file(unsigned int write_value,
		  unsigned int offset,
		  unsigned char num_of_bytes,
		  char		*print_string)
{

	int result = 0;
	int index;
	unsigned int localValue4;
	unsigned short localValue2;
	unsigned char localValue1;

	fseek(g_hfd_pointer, 0L, SEEK_SET);
	fseek(g_hfd_pointer, offset, SEEK_SET);

	switch (num_of_bytes) {
	case(1):
		localValue1 = (unsigned char)write_value;
		result = (int)(fwrite(&localValue1, 1,
							  1, g_hfd_pointer));
	break;
	case(2):
		localValue2 = (unsigned short)write_value;
		result = (int)(fwrite(&localValue2,
				      2,
				      1,
				      g_hfd_pointer));
		break;
	case(4):
		localValue4 = write_value;
		result = (int)(fwrite(&localValue4,
				      4,
				      1,
				      g_hfd_pointer));
		break;
	default:
		/* Pad the same value N times. */
		localValue1 = (unsigned char)write_value;
		for (index = 0; index < num_of_bytes; index++)
			result = (int)(fwrite(&localValue1,
					      1,
					      1,
					      g_hfd_pointer));
		break;
	}

	my_printf(TINF, "\nIn write_to_file	 - %s", print_string);

	if (result) {
		my_printf(TINF,
			" - Offset %2d - value 0x%x",
			offset, write_value);
	} else {
		my_printf(TERR,
			"\n\nCouldn't write %x to file at %x\n\n",
			write_value, offset);
		return FALSE;
	}

	return TRUE;

}

/*
 *--------------------------------------------------------------------------
 * Function:	 read_from_file
 * Parameters:	 TBD
 * Return : TBD
 * Description : Reads from open BIN file
 *--------------------------------------------------------------------------
 */
int read_from_file(unsigned int	offset,
				   unsigned char	size_to_read,
				   unsigned int	*read_value,
				   char				*print_string)
{
	int result;
	unsigned int localValue4;
	unsigned short localValue2;
	unsigned char localValue1;

	fseek(input_file_pointer, 0L, SEEK_SET);
	fseek(input_file_pointer, offset, SEEK_SET);

	switch (size_to_read) {
	case(1):
		result = (int)(fread(&localValue1,
				     1,
				     1,
				     input_file_pointer));
		*read_value = localValue1;
		break;
	case(2):
		result = (int)(fread(&localValue2,
				     2,
				     1,
				     input_file_pointer));
		*read_value = localValue2;
		break;
	case(4):
		result = (int)(fread(&localValue4,
				     4,
				     1,
				     input_file_pointer));
		*read_value = localValue4;
		break;
	default:
		my_printf(TERR, "\nIn read_from_file - %s", print_string);
		my_printf(TERR, "\n\nInvalid call to read_from_file\n\n");
		return FALSE;
		break;
	}

	my_printf(TINF, "\nIn read_from_file - %s", print_string);

	if (result) {
		my_printf(TINF,
			" - Offset %d - value %x",
			offset, *read_value);
	} else {
		my_printf(TERR,
			"\n\nCouldn't read from file at %x\n\n",
			offset);
		return FALSE;
	}

	return TRUE;
}

/*
 *--------------------------------------------------------------------------
 * Function:	init_calculation
 * Parameters:	unsigned int check_sum_crc (I\O)
 * Return:
 * Description:	Initialize the variable according to the selected
 *				calculation
 *--------------------------------------------------------------------------
 */
void init_calculation(unsigned int *check_sum_crc)
{
	switch (g_calc_type) {
	case CALC_TYPE_NONE:
	case CALC_TYPE_CHECKSUM:
		*check_sum_crc = 0;
		break;
	case CALC_TYPE_CRC:
		*check_sum_crc = initialize_crc_32();
		break;
	}
}

/*
 *--------------------------------------------------------------------------
 * Function:	 finalize_calculation
 * Parameters:	 unsigned int check_sum_crc (I\O)
 * Return:
 * Description:	Finalize the variable according to the selected calculation
 *--------------------------------------------------------------------------
 */
void finalize_calculation(unsigned int *check_sum_crc)
{
	switch (g_calc_type) {
	case CALC_TYPE_NONE:
	case CALC_TYPE_CHECKSUM:
		/* Do nothing */
		break;
	case CALC_TYPE_CRC:
		*check_sum_crc = finalize_crc_32(*check_sum_crc);
		break;
	}
}

/*--------------------------------------------------------------------------
 * Function:	 update_calculation
 * Parameters:	 unsigned int check_sum_crc (I\O)
 *		 unsigned int byte_to_add (I)
 * Return:
 * Description:	 Calculate a new checksum\crc with the new byte_to_add
 *		 given the previous checksum\crc
 *--------------------------------------------------------------------------
 */
void update_calculation(unsigned int *check_sum_crc,
						unsigned char byte_to_add)
{
	switch (g_calc_type) {
	case CALC_TYPE_NONE:
			/* Do nothing */
		break;
	case CALC_TYPE_CHECKSUM:
		*check_sum_crc += byte_to_add;
		break;
	case CALC_TYPE_CRC:
		*check_sum_crc = update_crc_32(*check_sum_crc, byte_to_add);
		break;
	}
}

/*
 *--------------------------------------------------------------------------
 * Function:	 str_cmp_no_case
 * Parameters:	 s1, s2: Strings to compare.
 * Return:	 function returns an integer less than, equal to, or
 *		 greater than zero if s1 (or the first n bytes thereof) is
 *		 found, respectively, to be less than, to match, or be
 *		 greater than s2.
 * Description:	 Compare two string without case sensitive.
 *--------------------------------------------------------------------------
 */
int str_cmp_no_case(const char *s1, const char *s2)
{
	return strcasecmp(s1, s2);
}

/*
 *--------------------------------------------------------------------------
 * Function:	 get_file_lengt
 * Parameters:	 stream - Pointer to a FILE objec
 * Return:		 File length in bytes
 * Description:	 Gets the file length in bytes.
 *--------------------------------------------------------------------------
 */
int get_file_length(FILE *stream)
{
	int	curent_position;
	int	file_len;

	/* Store current position. */
	curent_position = ftell(stream);

	/* End position of the file is its length. */
	fseek(stream, 0, SEEK_END); /* seek to end of file */
	file_len = ftell(stream);

	/* Restore the original position. */
	fseek(stream, curent_position, SEEK_SET);

	/* return file length. */
	return file_len;
}

/*
 ***************************************************************************
 *							"bt" mode Handler
 ***************************************************************************
 */

/*
 ***************************************************************************
 * Function:	 main_bin
 * Parameters:	 TBD
 * Return:		 True for success
 * Description:
 *	 TBD
 ***************************************************************************
 */
int main_bin(struct tbinparams binary_params)
{
	char dir_name[NAME_SIZE];
	char *file_name_ptr = NULL;
	char *tmp_str_ptr;
	int	  dir_name_len;
	unsigned int bin_file_size_bytes;
	unsigned int bin_fw_offset = 0;
	unsigned int tmp_param;
	FILE *output_file_pointer;

	/* If input file was not declared, then print error message. */
	if (strlen(input_file_name) == 0) {
		my_printf(TERR, "\n\nDefine input file, using -i flag\n\n");
		return FALSE;
	}

	/* Open input file */
	input_file_pointer = fopen(input_file_name, "r+b");
	if (input_file_pointer == NULL) {
		my_printf(TERR, "\n\nCannot open %s\n\n", input_file_name);
		return FALSE;
	}

	/*
	 * Check Binary file size, this file contain the image itself,
	 * without any header.
	 */
	bin_file_size_bytes = get_file_length(input_file_pointer);
	if (bin_file_size_bytes == 0) {
		my_printf(TINF,
			  "\nBIN Input file name %s is empty (size is %d)\n",
			  input_file_name, bin_file_size_bytes);
		return FALSE;
	}

	/*
	 * If the binary file contains also place for the header, then the FW
	 * size is the length of the file minus the header length
	 */
	if ((binary_params.bin_params & BIN_FW_HDR_OFFSET) != 0)
		bin_fw_offset = binary_params.fw_hdr_offset + HEADER_SIZE;

	my_printf(TINF, "\nBIN file:  %s, size: %d (0x%x) bytes\n",
			  input_file_name,
			  bin_file_size_bytes,
			  bin_file_size_bytes);

	/* Check validity of FW header offset. */
	if (((int)binary_params.fw_hdr_offset < 0) ||
		(binary_params.fw_hdr_offset > bin_file_size_bytes)) {
		my_printf(TERR,
			  "\nFW header offset 0x%08x (%d) should be in the"
			  " range of 0 and file size (%d).\n",
			  binary_params.fw_hdr_offset,
			  binary_params.fw_hdr_offset,
			  bin_file_size_bytes);
		return FALSE;
	}

	/* Get the input directory and input file name. */
	file_name_ptr = input_file_name;
	for (tmp_str_ptr = input_file_name; tmp_str_ptr != NULL;) {
		tmp_str_ptr = strstr(tmp_str_ptr, DIR_DELIMITER_STR);
		if (tmp_str_ptr != NULL) {
			file_name_ptr = tmp_str_ptr + strlen(DIR_DELIMITER_STR);
			tmp_str_ptr = file_name_ptr;
		}
	}

	dir_name_len = strlen(input_file_name) - strlen(file_name_ptr);
	strncpy(dir_name, input_file_name, dir_name_len);
	dir_name[dir_name_len] = '\0';

	/* Create the header file in the same directory as the input file. */
	sprintf(g_hdr_input_name, "%shdr_%s", dir_name, file_name_ptr);
	g_hfd_pointer = fopen(g_hdr_input_name, "w+b");
	if (g_hfd_pointer == NULL) {
		my_printf(TERR, "\n\nCannot open %s\n\n", g_hdr_input_name);
		return FALSE;
	}

	if (strlen(output_file_name) == 0)
		sprintf(output_file_name, "%sout_%s", dir_name, file_name_ptr);

	my_printf(TINF, "Output file name: %s\n", output_file_name);

	/*
	 *********************************************************************
	 * Set the ANCHOR & Extended-ANCHOR
	 *********************************************************************
	 */
	/* Write the ancore. */
	if (!write_to_file(FW_HDR_ANCHOR,
			   HDR_ANCHOR_OFFSET,
			   4,
			   "HDR - FW Header ANCHOR		  "))
		return FALSE;

	/* Write the extended anchor. */
	if (binary_params.bin_params & BIN_FW_HDR_CRC_DISABLE) {

		/* Write the ancore and the extended anchor. */
		if (!write_to_file(FW_HDR_EXT_ANCHOR_DISABLE,
				   HDR_EXTENDED_ANCHOR_OFFSET, 2,
				   "HDR - Header EXTENDED ANCHOR "))
			return FALSE;
	} else {
		/* Write the anchor and the extended anchor. */
		if (!write_to_file(FW_HDR_EXT_ANCHOR_ENABLE,
				   HDR_EXTENDED_ANCHOR_OFFSET, 2,
				   "HDR - Header EXTENDED ANCHOR "))
			return FALSE;
	}

	/* Write the SPI flash MAX clock. */
	switch (binary_params.spi_max_clk) {
	case SPI_MAX_CLOCK_20_MHZ_VAL:
		tmp_param = SPI_MAX_CLOCK_20_MHZ;
		break;
	case SPI_MAX_CLOCK_25_MHZ_VAL:
		tmp_param = SPI_MAX_CLOCK_25_MHZ;
		break;
	case SPI_MAX_CLOCK_33_MHZ_VAL:
		tmp_param = SPI_MAX_CLOCK_33_MHZ;
		break;
	case SPI_MAX_CLOCK_40_MHZ_VAL:
		tmp_param = SPI_MAX_CLOCK_40_MHZ;
		break;
	case SPI_MAX_CLOCK_50_MHZ_VAL:
		tmp_param = SPI_MAX_CLOCK_50_MHZ;
		break;
	default:
		my_printf(TERR, "\n\nInvalid SPI Flash MAX clock (%d MHz) ",
				  binary_params.spi_max_clk);
		my_printf(TERR, "- it should be 20, 25, 33, 40 or 50 MHz");
		return FALSE;
		break;
	}

	if (!write_to_file(tmp_param, HDR_SPI_MAX_CLK_OFFSET, 1,
					   "HDR - SPI flash MAX Clock	  "))
		return FALSE;

	/* Write the SPI flash Read Mode. */
	if (!write_to_file(binary_params.spi_read_mode,
					   HDR_SPI_READ_MODE_OFFSET, 1,
					   "HDR - SPI flash Read Mode	   "))
		return FALSE;

	/* Write the error detection configuration. */
	if (binary_params.bin_params & BIN_FW_CRC_DISABLE) {
		if (!write_to_file(FW_CRC_DISABLE,
				   HDR_ERR_DETECTION_CONF_OFFSET,
				   1,
				   "HDR - FW CRC Disabled		   "))
			return FALSE;
	} else {
		/* Write the ancore and the extended anchor. */
		if (!write_to_file(FW_CRC_ENABLE,
				   HDR_ERR_DETECTION_CONF_OFFSET, 1,
				   "HDR - FW CRC Enabled		  "))
			return FALSE;
	}

	/* FW entry point should be between the FW load address and RAM size */
	if ((binary_params.fw_load_addr >
					(g_ram_start_address + g_ram_size)) ||
		(binary_params.fw_load_addr < g_ram_start_address)) {
		my_printf(TERR,
			  "\nFW load address (0x%08x) should be between "
			  "start (0x%08x) and end (0x%08x) of RAM ).",
			  binary_params.fw_load_addr,
			  g_ram_start_address,
			  (g_ram_start_address + g_ram_size));
		return FALSE;
	}

	/* Write the FW load start address */
	if (!write_to_file(binary_params.fw_load_addr,
					   HDR_FW_LOAD_START_ADDR_OFFSET, 4,
					   "HDR - FW load start address	 "))
		return FALSE;

	/*
	 * Write the FW length. (MUST BE SET BEFORE fw_err_detec_e_addr)
	 */
	if ((binary_params.bin_params & BIN_FW_LENGTH) == 0x00000000) {
		/*
		 * In case the FW length was not set, then the FW length is the
		 * size of the binary file minus the offset of the start of the
		 * FW.
		 */
		binary_params.fw_len = bin_file_size_bytes-bin_fw_offset;
	}

	if ((int)binary_params.fw_len < 0) {
		my_printf(TERR,
			  "\nFW length %d (0x%08x) should be greater than 0x0.",
			  binary_params.fw_len,
			  binary_params.fw_len);
		return FALSE;
	}

	if (((int)binary_params.fw_len >
				(bin_file_size_bytes - bin_fw_offset)) ||
		((int)binary_params.fw_len > g_ram_size)) {
		my_printf(TERR,
			  "\nFW length %d (0x%08x) should be within the",
			  binary_params.fw_len, binary_params.fw_len);
		my_printf(TERR,
			  " input-file (related to the FW offset)");
		my_printf(TERR,
			  "\n (0x%08x) and within the RAM (RAM size: 0x%08x).",
			  (bin_file_size_bytes - bin_fw_offset), g_ram_size);
		return FALSE;
	}

	if ((binary_params.bin_params & BIN_FW_USER_ARM_RESET) != 0x00000000) {
		read_from_file((bin_fw_offset + ARM_FW_ENTRY_POINT_OFFSET),
			4,
			&binary_params.fw_ep,
			"read FW entry point for FW image ");

		if ((binary_params.fw_ep <
				binary_params.fw_load_addr) ||
			(binary_params.fw_ep >
				(binary_params.fw_load_addr +
						binary_params.fw_len))) {
			my_printf(TERR,
				  "\nFW entry point (0x%08x) should be between",
				  binary_params.fw_ep);
			my_printf(TERR,
				  " the FW load address (0x%08x) ",
				  binary_params.fw_load_addr);
			my_printf(TERR,
				  "and FW length (0x%08x).\n",
				  (binary_params.fw_load_addr +
							binary_params.fw_len));
			return FALSE;
		}
	}

	/* FW entry point should be between the FW load address and RAM size */
	if ((binary_params.fw_ep <
				binary_params.fw_load_addr) ||
		(binary_params.fw_ep >
				(binary_params.fw_load_addr +
						binary_params.fw_len))) {
		if (((binary_params.bin_params & BIN_FW_ENTRY_POINT) ==
								0x00000000) &&
			((binary_params.bin_params &
			  BIN_FW_LOAD_START_ADDR) != 0x00000000)) {
			binary_params.fw_ep =
					binary_params.fw_load_addr;
		} else {
			my_printf(TERR,
				  "\nFW entry point (0x%08x) should be ",
				  binary_params.fw_ep);
			my_printf(TERR,
				  "\between the FW load address (0x%08x)",
				  binary_params.fw_load_addr);
			my_printf(TERR,
				  " and FW length (0x%08x).\n",
				  (binary_params.fw_load_addr +
							binary_params.fw_len));
			return FALSE;
		}
	}

	/* Write the FW entry point */
	if (!write_to_file(binary_params.fw_ep,
			   HDR_FW_ENTRY_POINT_OFFSET,
			   4,
			   "HDR - FW Entry point		 "))
		return FALSE;

	/* Calculate the CRC end address. */
	if ((binary_params.bin_params & BIN_FW_CKS_SIZE) == 0x00000000) {
		/*
		 * In case the size was not set, then CRC end address is
		 * the size of the binary file.
		 */
		binary_params.fw_err_detec_e_addr =
						binary_params.fw_len - 1;
	} else {
		/* CRC end address should be less than FW length. */
		if (binary_params.fw_err_detec_e_addr >
					(binary_params.fw_len - 1)) {
			my_printf(TERR,
				  "\nCRC end address (0x%08x) should be less ",
				  binary_params.fw_err_detec_e_addr);
			my_printf(TERR,
				  "than the FW length %d (0x%08x)",
				  (binary_params.fw_len - 1),
				  (binary_params.fw_len - 1));
			return FALSE;
		}
	}

	/* Check CRC start and end addresses. */
	if (binary_params.fw_err_detec_s_addr >
					binary_params.fw_err_detec_e_addr) {
		my_printf(TERR,
			  "\nCRC start address (0x%08x) should be less or ",
			  binary_params.fw_err_detec_s_addr);
		my_printf(TERR,
			  "equal to CRC end address (0x%08x)\nPlease check ",
			  binary_params.fw_err_detec_e_addr);
		my_printf(TERR,
			  "CRC start address and CRC size arguments.");
		return FALSE;
	}

	/* CRC start addr should be between the FW load address and RAM size */
	if (binary_params.fw_err_detec_s_addr >
				binary_params.fw_len) {
		my_printf(TERR, "\nCRC start address (0x%08x) should ",
			  binary_params.fw_err_detec_s_addr);
		my_printf(TERR, "be FW length (0x%08x).",
			  binary_params.fw_len);
		return FALSE;
	}

	/* Write the CRC start address */
	if (!write_to_file(binary_params.fw_err_detec_s_addr,
			   HDR_FW_ERR_DETECT_START_ADDR_OFFSET,
			   4,
			   "HDR - FW CRC Start			 "))
		return FALSE;

	/* CRC end addr should be between the CRC start address and RAM size */
	if ((binary_params.fw_err_detec_e_addr <
				binary_params.fw_err_detec_s_addr) ||
		(binary_params.fw_err_detec_e_addr >
				binary_params.fw_len)) {
		my_printf(TERR,
			  "\nCRC end address (0x%08x) should be between the ",
			  binary_params.fw_err_detec_e_addr);
		my_printf(TERR,
			  "CRC start address (0x%08x) and FW length (0x%08x).",
			  binary_params.fw_err_detec_s_addr,
			  binary_params.fw_len);
		return FALSE;
	}

	/* Write the CRC end address */
	if (!write_to_file(binary_params.fw_err_detec_e_addr,
			   HDR_FW_ERR_DETECT_END_ADDR_OFFSET,
			   4,
			   "HDR - FW CRC End			 "))
		return FALSE;

	/* Let the FW length to be aligned to 16 */
	tmp_param = binary_params.fw_len % 16;
	if (tmp_param)
		binary_params.fw_len += (16 - tmp_param);

	/* FW load address + FW length should be less than the RAM size. */
	if ((binary_params.fw_load_addr +
			binary_params.fw_len) >
					(g_ram_start_address + g_ram_size)) {
		my_printf(TERR,
			  "\nFW load address + FW length should (0x%08x) be ",
			  (binary_params.fw_load_addr + binary_params.fw_len));
		my_printf(TERR,
			  "less than the RAM size (0x%08x).",
			  (g_ram_start_address + g_ram_size));
		return FALSE;
	}

	/* Write the FW length */
	if (!write_to_file(binary_params.fw_len,
			   HDR_FW_LENGTH_OFFSET,
			   4,
			   "HDR - FW Length			   "))
		return FALSE;

	/* Write the SPI flash MAX clock. */
	switch (binary_params.flash_size) {
	case FLASH_SIZE_1_MBYTES_VAL:
		tmp_param = FLASH_SIZE_1_MBYTES;
		break;
	case FLASH_SIZE_2_MBYTES_VAL:
		tmp_param = FLASH_SIZE_2_MBYTES;
		break;
	case FLASH_SIZE_4_MBYTES_VAL:
		tmp_param = FLASH_SIZE_4_MBYTES;
		break;
	case FLASH_SIZE_8_MBYTES_VAL:
		tmp_param = FLASH_SIZE_8_MBYTES;
		break;
	case FLASH_SIZE_16_MBYTES_VAL:
		tmp_param = FLASH_SIZE_16_MBYTES;
		break;
	default:
		my_printf(TERR, "\n\nInvalid Flash size (%d MBytes) -",
				  binary_params.flash_size);
		my_printf(TERR, " it should be 1, 2, 4, 8 or 16 MBytes\n");
		return FALSE;
		break;
	}
	if (!write_to_file(tmp_param,
			   HDR_FLASH_SIZE_OFFSET,
			   1,
			   "HDR - Flash size			 "))

		return FALSE;

	/* Write the reserved bytes. */
	if (!write_to_file(PAD_VALUE, HDR_RESERVED, 26,
					   "HDR - Reserved (26 bytes)	  "))
		return FALSE;


	/* Refresh the FW header bin file in order to calculate CRC */
	if (g_hfd_pointer) {
		fclose(g_hfd_pointer);
		g_hfd_pointer = fopen(g_hdr_input_name, "r+b");
		if (g_hfd_pointer == NULL) {
			my_printf(TERR,
				  "\n\nCannot open %s\n\n",
				  input_file_name);
			return FALSE;
		}
	}

	/* Calculate the FW header CRC */
	if ((binary_params.bin_params & BIN_FW_HDR_CRC_DISABLE) == 0) {
		/* Calculate ... */
		g_calc_type = CALC_TYPE_CRC;
		if (!calc_header_crc_bin(&binary_params.hdr_crc))
			return FALSE;

		g_calc_type = CALC_TYPE_NONE;
	} else
		binary_params.hdr_crc = 0;

	/* Write FW header CRC to header file */
	if (!write_to_file(binary_params.hdr_crc,
			   HDR_FW_HEADER_SIG_OFFSET,
			   4,
			   "HDR - Header CRC				"))
		return FALSE;

	/* Calculate the FW	 CRC */
	if ((binary_params.bin_params & BIN_FW_CRC_DISABLE) == 0) {
		/* Calculate ... */
		g_calc_type = CALC_TYPE_CRC;
		if (!calc_firmware_csum_bin(&binary_params.fw_crc,
			(bin_fw_offset +
				binary_params.fw_err_detec_s_addr),
			(binary_params.fw_err_detec_e_addr -
				binary_params.fw_err_detec_s_addr+1)))
			return FALSE;

		g_calc_type = CALC_TYPE_NONE;
	} else
		binary_params.fw_crc = 0;

	/* Write the FW CRC into file header file */
	if (!write_to_file(binary_params.fw_crc,
			   HDR_FW_IMAGE_SIG_OFFSET,
			   4,
			   "HDR - FW CRC				   "))
		return FALSE;

	/* Close if needed... */
	if (input_file_pointer) {
		fclose(input_file_pointer);
		input_file_pointer = NULL;
	}

	if (g_hfd_pointer) {
		fclose(g_hfd_pointer);
		g_hfd_pointer = NULL;
	}

	/* Create empty output file. */
	output_file_pointer = fopen(output_file_name, "wb");
	if (output_file_pointer)
		fclose(output_file_pointer);

	if ((binary_params.bin_params & BIN_FW_HDR_OFFSET) != 0) {
		copy_file_to_file(output_file_name,
				  input_file_name,
				  0,
				  SEEK_SET);
		copy_file_to_file(output_file_name,
				  g_hdr_input_name,
				  binary_params.fw_hdr_offset,
				  SEEK_SET);
	} else {
		copy_file_to_file(output_file_name,
				  g_hdr_input_name,
				  0,
				  SEEK_END);
		copy_file_to_file(output_file_name,
				  input_file_name,
				  0,
				  SEEK_END);
	}

	my_printf(TINF, "\n\n");

	return TRUE;
}

/*******************************************************************
 * Function:	calc_header_crc_bin
 * Parameters:	unsigned short header checksum (O)
 *		unsigned int header offset from first byte in
 *		the binary (I)
 * Return:
 * Description:	 Go thru bin file and calculate checksum
 *******************************************************************
 */
int calc_header_crc_bin(unsigned int *p_cksum)
{
	int i;
	unsigned int calc_header_checksum_crc = 0;
	unsigned char g_header_array[HEADER_SIZE];
	int line_print_size = 32;

	init_calculation(&calc_header_checksum_crc);

	/* Go thru the BIN File and calculate the Checksum */
	fseek(g_hfd_pointer, 0x00000000, SEEK_SET);
	if (fread(g_header_array,
		  1,
		  HEADER_SIZE,
		  g_hfd_pointer) == 0)
		return 0;

	for (i = 0; i < (HEADER_SIZE - HEADER_CRC_FIELDS_SIZE); i++) {

		/*
		 * I had once the Verbose check inside the my_printf, but
		 * it made ECST run sloooowwwwwly....
		 */
		if (g_verbose == SUPER_VERBOSE) {
			if (i%line_print_size == 0)
				my_printf(TDBG,
					  "\n[%.4x]: ",
					  g_header_array + i);

			my_printf(TDBG, "%.2x ", g_header_array[i]);
		}

		update_calculation(&calc_header_checksum_crc,
				   g_header_array[i]);

		if (g_verbose == SUPER_VERBOSE) {
			if ((i + 1) % line_print_size == 0)
				my_printf(TDBG,
					  "FW Header ChecksumCRC = %.8x",
					   calc_header_checksum_crc);

		}
	}

	finalize_calculation(&calc_header_checksum_crc);
	*p_cksum = calc_header_checksum_crc;

	return TRUE;
}

/*
 *******************************************************************
 * Function:	 calc_firmware_csum_bin
 * Parameters:	 unsigned int fwStart (I)
 *				 unsigned int firmware size in words (I)
 *				 unsigned int - firmware checksum (O)
 * Return:
 * Description:	 TBD
 *******************************************************************
 */
int calc_firmware_csum_bin(unsigned int *p_cksum,
						   unsigned int fw_offset,
						   unsigned int fw_length)
{

	unsigned int i;
	unsigned int calc_read_bytes;
	unsigned int calc_num_of_bytes_to_read;
	unsigned int calc_curr_position;
	unsigned int calc_fw_checksum_crc = 0;
	unsigned char g_fw_array[BUFF_SIZE];
	int line_print_size = 32;


	calc_num_of_bytes_to_read = fw_length;
	calc_curr_position = fw_offset;

	if (g_verbose == REGULAR_VERBOSE) {
		my_printf(TINF,
			  "\nFW Error Detect Start Dddress: 0x%08x",
			  calc_curr_position);
		my_printf(TINF,
			  "\nFW Error Detect End Dddress:	  0x%08x",
			  calc_curr_position + calc_num_of_bytes_to_read - 1);
		my_printf(TINF,
			  "\nFW Error Detect Size:  %d (0x%X)",
			  calc_num_of_bytes_to_read,
			  calc_num_of_bytes_to_read);
	}

	init_calculation(&calc_fw_checksum_crc);

	while (calc_num_of_bytes_to_read > 0) {
		if (calc_num_of_bytes_to_read > BUFF_SIZE)
			calc_read_bytes = BUFF_SIZE;
		else
			calc_read_bytes = calc_num_of_bytes_to_read;

		fseek(input_file_pointer, 0L, SEEK_SET);
		fseek(input_file_pointer, calc_curr_position, SEEK_SET);
		if (fread(g_fw_array,
			  1,
			  calc_read_bytes,
			  input_file_pointer) == 0)
			return 0;

		for (i = 0; i < calc_read_bytes; i++) {
			/*
			 * I had once the Verbose check inside the my_printf,
			 * but it made ECST run sloooowwwwwly....
			 */
			if (g_verbose == SUPER_VERBOSE) {
				if (i%line_print_size == 0)
					my_printf(TDBG,
						  "\n[%.4x]: ",
						  calc_curr_position + i);

				my_printf(TDBG, "%.2x ", g_fw_array[i]);
			}

			update_calculation(&calc_fw_checksum_crc,
					   g_fw_array[i]);

			if (g_verbose == SUPER_VERBOSE) {
				if ((i + 1) % line_print_size == 0)
					my_printf(TDBG,
						  "FW Checksum= %.8x",
						  calc_fw_checksum_crc);
			}
		}
		calc_num_of_bytes_to_read -= calc_read_bytes;
		calc_curr_position += calc_read_bytes;
	} /* end of while(calc_num_of_bytes_to_read > 0) */

	finalize_calculation(&calc_fw_checksum_crc);
	*p_cksum = calc_fw_checksum_crc;

	return TRUE;
}

/*
 ***************************************************************************
 *			"bh" mode Handler
 ***************************************************************************
 */

/*
 *******************************************************************
 * Function:	 main_hdr
 * Parameters:	 TBD
 * Return:	 True for success
 * Description:
 *******************************************************************
 */
int main_hdr(void)
{
	int result = 0;
	char tmp_file_name[NAME_SIZE];
	unsigned int	tmp_long_val;
	unsigned int	bin_file_size_bytes;

	if (is_ptr_merge) {
		if (strlen(input_file_name) == 0) {
			my_printf(TERR, "\n\nNo input BIN file selected for");
			my_printf(TERR, " BootLoader header file.\n\n");
			return FALSE;
		}

		if (strlen(output_file_name) == 0)
			strncpy(tmp_file_name,
				input_file_name,
				sizeof(tmp_file_name));
		else {
			copy_file_to_file(output_file_name,
					  input_file_name,
					  0,
					  SEEK_END);
			strncpy(tmp_file_name,
				output_file_name,
				sizeof(tmp_file_name));
		}

		/* Open Header file */
		g_hdr_pointer = fopen(tmp_file_name, "r+b");
		if (g_hdr_pointer == NULL) {
			my_printf(TERR,
				  "\n\nCannot open %s file.\n\n",
				  tmp_file_name);
			return FALSE;
		}

		bin_file_size_bytes = get_file_length(g_hdr_pointer);

		/* Offset should be less than file size. */
		if (fw_offset > bin_file_size_bytes) {
			my_printf(TERR,
				  "\n\nFW offset 0x%08x should be less than ",
				  fw_offset);
			my_printf(TERR,
				  "file size 0x%x (%d).\n\n",
				  bin_file_size_bytes, bin_file_size_bytes);
			 return FALSE;
		}

		/* FW table should be less than file size. */
		if (ptr_fw_addr > bin_file_size_bytes) {
			my_printf(TERR, "\n\nFW table 0x%08x should be less ",
				  ptr_fw_addr);
			my_printf(TERR, "than file size 0x%x (%d).\n\n",
				bin_file_size_bytes, bin_file_size_bytes);
			return FALSE;
		}

		fseek(g_hdr_pointer, 0L, SEEK_SET);
		fseek(g_hdr_pointer, fw_offset, SEEK_SET);

		tmp_long_val = HDR_PTR_SIGNATURE;
		result = (int)(fwrite(&tmp_long_val,
				      4,
				      1,
				      g_hdr_pointer));
		result |= (int)(fwrite(&ptr_fw_addr,
				       4,
				       1,
				       g_hdr_pointer));

		if (result) {
			my_printf(TINF,
				  "\nBootLoader Header file: %s\n",
				  tmp_file_name);
			my_printf(TINF,
				  "	Offset: 0x%08X,	 Signature: 0x%08X,",
				  fw_offset, HDR_PTR_SIGNATURE);
			my_printf(TINF,
				  "	 Pointer: 0x%08X\n",
				  ptr_fw_addr);
		} else {
			my_printf(TERR,
				  "\n\nCouldn't write signature (%x) and ",
				  tmp_long_val);
			my_printf(TERR,
				  "pointer to BootLoader header file (%s)\n\n",
				  ptr_fw_addr, tmp_file_name);
			return FALSE;
		}

	} else {

		if (strlen(output_file_name) == 0) {
			my_printf(TERR, "\n\nNo output file selected ");
			my_printf(TERR, "for BootLoader header file.\n\n");
			return FALSE;
		}

		/* Open Output file */
		g_hdr_pointer = fopen(output_file_name, "w+b");
		if (g_hdr_pointer == NULL) {
			my_printf(TERR,
				  "\n\nCannot open %s file.\n\n",
				  output_file_name);
			return FALSE;
		}

		fseek(g_hdr_pointer, 0L, SEEK_SET);

		tmp_long_val = HDR_PTR_SIGNATURE;
		result = (int)(fwrite(&tmp_long_val,
				      4,
				      1,
				      g_hdr_pointer));
		result |= (int)(fwrite(&ptr_fw_addr,
				       4,
				       1,
				       g_hdr_pointer));

		if (result) {
			my_printf(TINF,
				  "\nBootLoader Header file: %s\n",
				  output_file_name);
			my_printf(TINF,
				  "     Signature: 0x%08X,   Pointer: 0x%08X\n",
				  HDR_PTR_SIGNATURE,
				  ptr_fw_addr);
		} else {
			my_printf(TERR,
				  "\n\nCouldn't write signature (%x) and ",
				  tmp_long_val);
			my_printf(TERR,
				  "pointer to BootLoader header file (%s)\n\n",
				  output_file_name);
			return FALSE;
		}

	}

	/* Close if needed... */
	if (g_hdr_pointer) {
		fclose(g_hdr_pointer);
		g_hdr_pointer = NULL;
	}

	return TRUE;
}

/*
 ***************************************************************************
 *		"api" mode Handler
 ***************************************************************************
 */

/*
 *******************************************************************
 * Function:		main_api
 * Parameters:		TBD
 * Return:			True for success
 * Description:
 *	TBD
 *******************************************************************
 */
int main_api(void)
{

	char	dir_name[NAME_SIZE];
	char	*file_name_ptr = NULL;
	char	*tmp_str_ptr;
	int		dir_name_len;
	char	tmp_file_name[NAME_SIZE];
	int		result = 0;
	unsigned int crc_checksum;

	api_file_size_bytes = 0;

	/* If API input file was not declared, then print error message. */
	if (strlen(input_file_name) == 0) {
		my_printf(TERR,
			"\n\nNeed to define API input file, using -i flag\n\n");
		return FALSE;

	}

	if (strlen(output_file_name) == 0) {
		/* Get the input directory and input file name. */
		file_name_ptr = input_file_name;
		for (tmp_str_ptr = input_file_name; tmp_str_ptr != NULL;) {
			tmp_str_ptr = strstr(tmp_str_ptr, DIR_DELIMITER_STR);
			if (tmp_str_ptr != NULL) {
				file_name_ptr =
					tmp_str_ptr + strlen(DIR_DELIMITER_STR);
				tmp_str_ptr = file_name_ptr;
			}

		}

		dir_name_len = strlen(input_file_name) - strlen(file_name_ptr);
		strncpy(dir_name, input_file_name, dir_name_len);
		dir_name[dir_name_len] = '\0';

		sprintf(tmp_file_name, "%sapi_%s", dir_name, file_name_ptr);

	} else
		strncpy(tmp_file_name, output_file_name, sizeof(tmp_file_name));

	/* Make sure that new empty file is created. */
	api_file_pointer = fopen(tmp_file_name, "w");
	if (api_file_pointer == NULL) {
		my_printf(TERR, "\n\nCannot open %s\n\n", tmp_file_name);
		return FALSE;
	}
	fclose(api_file_pointer);

	copy_file_to_file(tmp_file_name, input_file_name, 0, SEEK_END);

	/* Open API input file */
	api_file_pointer = fopen(tmp_file_name, "r+b");
	if (api_file_pointer == NULL) {
		my_printf(TERR, "\n\nCannot open %s\n\n", tmp_file_name);
		return FALSE;
	}

	/*
	 * Check Binary file size, this file contain the image itself,
	 * without any header.
	 */
	api_file_size_bytes = get_file_length(api_file_pointer);
	my_printf(TINF,
		  "\nAPI file: %s, size: %d bytes (0x%x)\n",
		  tmp_file_name,
		  api_file_size_bytes,
		  api_file_size_bytes);


	crc_checksum = calc_api_csum_bin();

	fseek(api_file_pointer, 0L, SEEK_SET);
	fseek(api_file_pointer, api_file_size_bytes, SEEK_SET);

	result = (int)(fwrite(&crc_checksum,
			      4,
			      1,
			      api_file_pointer));

	if (result)
		my_printf(TINF,
			  "\nIn API BIN file - Offset 0x%08X - value 0x%08X",
			  api_file_size_bytes,
			  crc_checksum);
	else {
		my_printf(TERR,
			  "\n\nCouldn't write %x to API BIN file at %08x\n\n",
			  crc_checksum, api_file_size_bytes);
		return FALSE;
	}

	/* Close if needed... */
	if (api_file_pointer) {
		fclose(api_file_pointer);
		api_file_pointer = NULL;
	}

	return TRUE;
}



/*
 *******************************************************************
 * Function: calc_api_csum_bin
 * Parameters:
 *
 * Return: Return the CRC \ checksum, or "0" in case of fail.
 * Description:	 TBD
 *******************************************************************
*/
unsigned int calc_api_csum_bin(void)
{

	unsigned int i;
	unsigned int calc_read_bytes;
	unsigned int calc_num_of_bytes_to_read;
	unsigned int calc_curr_position;
	unsigned int calc_fw_checksum_crc = 0;
	unsigned char g_fw_array[BUFF_SIZE];
	int line_print_size = 32;


	calc_num_of_bytes_to_read = api_file_size_bytes;
	calc_curr_position = 0;

	if (g_verbose == SUPER_VERBOSE) {
		my_printf(TDBG,
			  "\nAPI CRC \\ Checksum First Byte Address: 0x%08x",
			  calc_curr_position);
		my_printf(TDBG,
			  "\nAPI CRC \\ Checksum Size:  %d (0x%X)",
			  calc_num_of_bytes_to_read,
			  calc_num_of_bytes_to_read);
	}

	init_calculation(&calc_fw_checksum_crc);

	while (calc_num_of_bytes_to_read > 0) {
		if (calc_num_of_bytes_to_read > BUFF_SIZE)
			calc_read_bytes = BUFF_SIZE;
		else
			calc_read_bytes = calc_num_of_bytes_to_read;

		fseek(api_file_pointer, 0L, SEEK_SET);
		fseek(api_file_pointer, calc_curr_position, SEEK_SET);
		if (fread(g_fw_array,
			  1,
			  calc_read_bytes,
			  api_file_pointer) == 0)
			return 0;

		for (i = 0; i < calc_read_bytes; i++) {
			/*
			 * I had once the Verbose check inside the my_printf,
			 * but it made ecst run sloooowwwwwly....
			 */
			if (g_verbose == SUPER_VERBOSE) {
				if (i%line_print_size == 0)
					my_printf(TDBG,
					"\n[%.4x]: ",
					calc_curr_position + i);

				my_printf(TDBG, "%.2x ", g_fw_array[i]);
			}

			update_calculation(&calc_fw_checksum_crc,
					   g_fw_array[i]);

			if (g_verbose == SUPER_VERBOSE) {
				if ((i + 1) % line_print_size == 0)
					my_printf(TDBG,
						  "FW Checksum= %.8x",
						  calc_fw_checksum_crc);
			}
		}
		calc_num_of_bytes_to_read -= calc_read_bytes;
		calc_curr_position += calc_read_bytes;
	} /* end of while(calc_num_of_bytes_to_read > 0) */

	finalize_calculation(&calc_fw_checksum_crc);

	return calc_fw_checksum_crc;

}


/*
 **************************************************************************
 *			CRC Handler
 **************************************************************************
*/

/*
 *******************************************************************
 *
 * #define P_xxxx
 *
 * The CRC's are computed using polynomials. The  coefficients
 * for the algorithms are defined by the following constants.
 *
 *******************************************************************
 */

#define	P_32		0xEDB88320L

/*
 *******************************************************************
 *
 *	static int crc_tab...init
 *	static unsigned ... crc_tab...[]
 *
 *	The algorithms use tables with pre-calculated  values.  This
 *	speeds	up	the calculation dramatically. The first time the
 *	CRC function is called, the table for that specific	 calcu-
 *	lation	is set up. The ...init variables are used to deter-
 *	mine if the initialization has taken place. The	 calculated
 *	values are stored in the crc_tab... arrays.
 *
 *	The variables are declared static. This makes them invisible
 *	for other modules of the program.
 *
 *******************************************************************
 */
static int		crc_tab32_init = FALSE;
static unsigned int	crc_tab32[256];

/*
 ********************************************************************
 *
 *	static void init_crc...tab();
 *
 *	Three local functions are used to initialize the tables
 *	with values for the algorithm.
 *
 *******************************************************************
 */

static void	init_crc32_tab(void);

/*
 *******************************************************************
 *
 * unsigned int initialize_crc_32( void );
 *
 * The function update_crc_32 calculates a	 new  CRC-32  value
 * based  on  the	previous value of the CRC and the next byte
 * of the data to be checked.
 *
 *******************************************************************
 */

unsigned int initialize_crc_32(void)
{
	return 0xffffffffL;
}  /* initialize_crc_32 */


/*
 *******************************************************************
 *
 * unsigned int update_crc_32( unsigned int crc, char c );
 *
 * The function update_crc_32 calculates a	 new  CRC-32  value
 * based  on  the	previous value of the CRC and the next byte
 * of the data to be checked.
 *
 *******************************************************************
 */

unsigned int update_crc_32(unsigned int crc, char c)
{

	unsigned int tmp, long_c;

	long_c = 0x000000ffL & (unsigned int)c;

	if (!crc_tab32_init)
		init_crc32_tab();

	tmp = crc ^ long_c;
	crc = (crc >> 8) ^ crc_tab32[tmp & 0xff];

	return crc;

}  /* update_crc_32 */



/*
 *******************************************************************
 *
 *	static void init_crc32_tab( void );
 *
 *	The function init_crc32_tab() is used  to  fill	 the  array
 *	for calculation of the CRC-32 with values.
 *
 *******************************************************************
 */
static void init_crc32_tab(void)
{

	int i, j;
	unsigned int crc;

	for (i = 0; i < 256; i++) {

		crc = (unsigned int)i;

		for (j = 0; j < 8; j++) {

			if (crc & 0x00000001L)
				crc = (crc >> 1) ^ P_32;
			else
				crc = crc >> 1;
		}

		crc_tab32[i] = crc;
	}

	crc_tab32_init = TRUE;

}  /* init_crc32_tab */

/*
 *******************************************************************
 *
 * unsigned int finalize_crc_32( unsigned int crc );
 *
 * The function finalize_crc_32 finalizes a  CRC-32 calculation
 * by performing a bit convolution (bit 0 is bit 31, etc').
 *
 *******************************************************************
 */

unsigned int finalize_crc_32(unsigned int crc)
{

	int i;
	unsigned int result = 0;

	for (i = 0; i < NUM_OF_BYTES; i++)
		SET_VAR_BIT(result, NUM_OF_BYTES - (i+1), READ_VAR_BIT(crc, i));

	return result;

}  /* finalize_crc_32 */

