/*
	skyeye_options.c - skyeye config file options' functions
	Copyright (C) 2003 Skyeye Develop Group
	for help please send mail to <skyeye-developer@lists.sf.linuxforum.net> 
	
	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 
*/
/* 08/20/2003   add log option function
				chenyu
   4/02/2003	add net option function
 * 				walimis <walimi@peoplemail.com.cn>
 * 3/22/2003 	add cpu, mem_num, mem_bank, arch, dummy option function
 *				walimis <walimi@peoplemail.com.cn> 		
 * */
//teawater add for arm2x86 2005.03.18-------------------------------------------
//"skyeye_config.h" is already include in the file "armdefs.h"
//#include "skyeye_config.h"
//AJ2D--------------------------------------------------------------------------
#include "armdefs.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


extern FILE * skyeye_logfd;

extern void at91_mach_init();
extern void ep7312_mach_init();
extern void lh79520_mach_init();
extern void ep9312_mach_init();
extern void s3c4510b_mach_init();
extern void s3c44b0_mach_init();
extern void sa1100_mach_init();
extern void pxa_mach_init();
extern void cs89712_mach_init();
extern void at91rm92_mach_init();
extern void s3c2410x_mach_init();
extern void s3c2440_mach_init();
extern void shp_mach_init();
extern void lpc_mach_init();
//chy 2003-08-11: the cpu_id can be found in linux/arch/arm/boot/compressed/head.S
cpu_config_t arm_cpu[] = {
      {"armv3", "arm710",   0x41007100, 0xfff8ff00, DATACACHE},
      {"armv3", "arm7tdmi", 0x41007700, 0xfff8ff00, NONCACHE},
      {"armv4", "arm720t",  0x41807200, 0xffffff00, DATACACHE},
      {"armv4", "sa1110",       SA1110, 0xfffffff0, INSTCACHE},
      {"armv4", "sa1100",       SA1100, 0xffffffe0, INSTCACHE},
      {"armv4", "arm920t",  0x41009200, 0xff00fff0, INSTCACHE},
      {"xscale", "xscale",  	PXA250, 0xfffffff0, INSTCACHE} 
};

machine_config_t arm_machines[] = {
      /*machine define for cpu without mmu */
      /* ATMEL AT91X40 */
      {"at91", 		at91_mach_init,         NULL, NULL, NULL},
      /* PHILIPS LPC2xxxx*/
      {"lpc",    	lpc_mach_init,         NULL, NULL, NULL},
      /*Samsung s3c4510b*/
      {"s3c4510b",    	s3c4510b_mach_init,     NULL, NULL, NULL},
      /*Samsung s3c44b0*/
      {"s3c44b0",    	s3c44b0_mach_init,      NULL, NULL, NULL},
      /*machine define for cpu with mmu*/
      /* Cirrus Logic EP7312*/
      {"ep7312",	ep7312_mach_init,       NULL, NULL, NULL},
      /* sharp LH79520*/
      {"lh79520",     	lh79520_mach_init,     	NULL, NULL, NULL},
      /* Cirrus Logic EP9312*/
      {"ep9312",	ep9312_mach_init,       NULL, NULL, NULL},
      /*machine define for cs89712 */
      {"cs89712",      cs89712_mach_init,       NULL, NULL, NULL},
      /*machine define for sa1100*/
      {"sa1100", 	sa1100_mach_init,       NULL, NULL, NULL},
      /*machine define for xscale pxa250 lubbock developboard*/
      {"pxa_lubbock", 	pxa_mach_init,          NULL, NULL, NULL},
      /*machine define for at91RM9200*/
      {"at91rm92",     at91rm92_mach_init,       NULL, NULL, NULL},
      /*machine define for s3c2410x*/
      {"s3c2410x",      s3c2410x_mach_init,       NULL, NULL, NULL},
      /*machine define for s3c2440*/
      {"s3c2440",      s3c2440_mach_init,       NULL, NULL, NULL},
      /*machine define for sharp lh7a400 developboard*/
      {"sharp_lh7a400", shp_mach_init,          NULL, NULL, NULL}

};


extern int skyeye_net_on;
extern ARMword skyeye_cachetype;

int split_param(const char *param, char *name, char *value)
{
	const char *src = param;
	char *dst = name;

	while (*src && (*src != '='))
		*dst++ = *src++;
	*dst = '\0';

	if (*src == '\0') {
		value = '\0';
		return -1;
	}

	strcpy(value, src+1);
	return 0;
}

	
/* we need init some options before read the option file.
 * now put them here.
 * */
//chy 2004-12-05 for eclipse
//#define SKYEYE4ECLIPSE
#ifdef SKYEYE4ECLIPSE
extern char *inferior_io_terminal;
int nouart;
#endif
//------------------------------
int skyeye_option_init(skyeye_config_t *config)
{
//chy 2004-12-05 for eclipse
#ifdef SKYEYE4ECLIPSE
	int fd;
#endif
//------------------------------			

	config->uart.fd_in = 0;		/*stdin*/
	config->uart.fd_out = 1;	/*stdout*/
	/*chy 2004-03-13*/
	config->no_lcd	    =1;        /*default, lcd is off*/
	
	/*ywc 2005-04-01*/
	config->no_dbct	    =1;        /*default, dbct is off*/

//chy 2004-12-05 for eclipse
#ifdef SKYEYE4ECLIPSE
	nouart=0;
	if(inferior_io_terminal!=NULL){
		nouart=1;
		printf("SKYEYE: inferior_io_terminal is %s \n",inferior_io_terminal);
		if ((fd = open(inferior_io_terminal, O_RDWR))==-1)
		       SKYEYE_DBG("Error when open device %s", inferior_io_terminal);
		skyeye_config.uart.fd_in =fd ;
		skyeye_config.uart.fd_out=fd ;
	}
#endif
//------------------------------			

}
int do_dummy_option(skyeye_option_t *this_option, int num_params, const char *params[])
{
	return 0;
};
int do_cpu_option(skyeye_option_t *this_option, int num_params, const char *params[])
{
	int i;
	cpu_config_t *cpu = skyeye_config.cpu;
	for(i = 0; i < (sizeof(arm_cpu) / sizeof(cpu_config_t)); i++){
		if (!strncmp(params[0], arm_cpu[i].cpu_name, MAX_PARAM_NAME)){
			skyeye_config.cpu = &arm_cpu[i];
			SKYEYE_INFO("cpu info: %s, %s, %x, %x, %x \n",\
			 	    skyeye_config.cpu->cpu_arch_name, skyeye_config.cpu->cpu_name, \
			            skyeye_config.cpu->cpu_val, skyeye_config.cpu->cpu_mask, skyeye_config.cpu->cachetype);
			skyeye_cachetype=skyeye_config.cpu->cachetype;
			return 0;
		}
	}
	SKYEYE_ERR("Error: Unkonw cpu name \"%s\"\n", params[0]);	
	return -1;
}

int do_mach_option(skyeye_option_t *this_option, int num_params, const char *params[])
{
	int i;
	for(i = 0; i < (sizeof(arm_machines) / sizeof(machine_config_t)); i++){
	
	if (!strncmp(params[0], arm_machines[i].machine_name, MAX_PARAM_NAME)){
		skyeye_config.mach = &arm_machines[i];
		SKYEYE_INFO("mach info: name %s, mach_init addr %p\n", 
		skyeye_config.mach->machine_name, skyeye_config.mach->mach_init);
		return 0;
		}
	}
	SKYEYE_ERR("Error: Unkonw mach name \"%s\"\n", params[0]);  
	
	return -1;
}

/*mem bank*/
extern ARMword	real_read_word(ARMul_State *state, ARMword addr);
extern void	real_write_word(ARMul_State *state, ARMword addr, ARMword data);
extern ARMword	io_read_word(ARMul_State *state, ARMword addr);
extern void	io_write_word(ARMul_State *state, ARMword addr, ARMword data);

/*ywc 2005-03-30*/
extern ARMword  flash_read_byte(ARMul_State *state, ARMword addr);
extern void     flash_write_byte(ARMul_State *state, ARMword addr, ARMword data);
extern ARMword  flash_read_halfword(ARMul_State *state, ARMword addr);
extern void     flash_write_halfword(ARMul_State *state, ARMword addr, ARMword data);
extern ARMword  flash_read_word(ARMul_State *state, ARMword addr);
extern void     flash_write_word(ARMul_State *state, ARMword addr, ARMword data);

int do_mem_bank_option(skyeye_option_t *this_option, int num_params, const char *params[])
{
	char name[MAX_PARAM_NAME], value[MAX_PARAM_NAME];
	int i, num;
//chy 2003-09-12, now support more io bank
//	static int io_bank_num=0;

	mem_config_t *mc = &skyeye_config.mem;
	mem_bank_t   *mb = mc->mem_banks;
	
	mc->bank_num = mc->current_num++;
	
	num = mc->current_num - 1;/*mem_banks should begin from 0.*/
	mb[num].filename[0] = '\0';
	for(i = 0; i < num_params; i++){
		if (split_param(params[i], name, value) < 0)
			SKYEYE_ERR("Error: mem_bank %d has wrong parameter \"%s\".\n", 	num, name);

		if (!strncmp("map", name, strlen(name))){	
			if (!strncmp("M", value, strlen(value))){
				mb[num].read_byte = real_read_byte;
				mb[num].write_byte = real_write_byte;
				mb[num].read_halfword = real_read_halfword;
				mb[num].write_halfword = real_write_halfword;
				mb[num].read_word = real_read_word;
				mb[num].write_word = real_write_word;
				mb[num].type=MEMTYPE_RAM;
			}else if (!strncmp("I", value, strlen(value))){
				mb[num].read_byte = io_read_byte;
				mb[num].write_byte = io_write_byte;
				mb[num].read_halfword = io_read_halfword;
				mb[num].write_halfword = io_write_halfword;
				mb[num].read_word = io_read_word;
				mb[num].write_word = io_write_word;
				mb[num].type=MEMTYPE_IO;

                        /*ywc 2005-03-30*/ 
			}else if (!strncmp("F", value, strlen(value))){
				mb[num].read_byte = flash_read_byte;
				mb[num].write_byte = flash_write_byte;
				mb[num].read_halfword = flash_read_halfword;
				mb[num].write_halfword = flash_write_halfword;
				mb[num].read_word = flash_read_word;
				mb[num].write_word = flash_write_word;
				mb[num].type=MEMTYPE_FLASH;

//chy 2003-09-12, now support more io banks
#if 0
				io_bank_num++;
				if (io_bank_num>1){ 
					SKYEYE_ERR("Error: Now skyeye only support one contiguous address bank. Check skyeye.config\n");
					return -1;
			        }else if(io_bank_num==1){
					skyeye_config.ioaddr.addr_begin=mb[num].addr;
					skyeye_config.ioaddr.addr_end=(mb[num].len-1)+mb[num].addr;
					//printf("do_mem_bank_optin: iobegin 0X%x, ioend 0X%x\n",skyeye_config.ioaddr.addr_begin,skyeye_config.ioaddr.addr_end);
				}
#endif 
			}else{
				SKYEYE_ERR("Error: mem_bank %d \"%s\" parameter has wrong value \"%s\"\n", 
								num, name, value);
			}
		}else if (!strncmp("type", name, strlen(name))){
		//chy 2003-09-21: process type
		        if(!strncmp("R",value,strlen(value))){	
				if(mb[num].type==MEMTYPE_RAM)
					mb[num].type=MEMTYPE_ROM;
					mb[num].write_byte=warn_write_byte;
					mb[num].write_halfword=warn_write_halfword;
					mb[num].write_word=warn_write_word;
			}
		}else if (!strncmp("addr", name, strlen(name))){
				
			if( value[0] == '0' && value[1] == 'x')
				mb[num].addr = strtoul(value, NULL, 16);
			else
				mb[num].addr = strtoul(value, NULL, 10);

		}else if (!strncmp("size", name, strlen(name))){
				
			if( value[0] == '0' && value[1] == 'x')
				mb[num].len = strtoul(value, NULL, 16);
			else
				mb[num].len = strtoul(value, NULL, 10);
			
		}else if (!strncmp("file", name, strlen(name))){
			strncpy(mb[num].filename, value, strlen(value) + 1); 
		}else if (!strncmp("boot", name, strlen(name))){
			/*this must be the last parameter.*/
			if(!strncmp("yes",value, strlen(value)))
				skyeye_config.start_address = mb[num].addr; 
		}else{
			SKYEYE_ERR("Error: mem_bank %d has unknow parameter \"%s\".\n", 
							num, name);
		}
	}

	return 0;
}
int do_net_option(skyeye_option_t *this_option, int num_params, const char *params[])
{
	char name[MAX_PARAM_NAME], value[MAX_PARAM_NAME];
	int i;
	static int nic_number=0;
	unsigned char mac_addr[6];
	unsigned char hip[4];
	unsigned char *maddr,*ip;
	
	if(nic_number>=NET_MAXNICNUM_PER_HOST){
	   SKYEYE_ERR("Error: nic number exceed %d\n",NET_MAXNICNUM_PER_HOST);
	   return -1;
	}
	
	for(i = 0; i < num_params; i++){
		if (split_param(params[i], name, value) < 0){
		   SKYEYE_ERR("Error: %s has wrong parameter \"%s\".\n", 
								this_option->name, name);
		   return -1;
		}
		if (!strncmp("state", name, strlen(name))){
		   	if (!strncmp("on", value, strlen(value))){
				skyeye_config.net[nic_number].state=1;
				skyeye_net_on=1;
			}else
				skyeye_config.net[nic_number].state=0;
		}else if (!strncmp("mac", name, strlen(name))){	
			sscanf(value,"%x:%x:%x:%x:%x:%x",&mac_addr[0],&mac_addr[1],&mac_addr[2],&mac_addr[3],&mac_addr[4],&mac_addr[5]);
			memcpy(skyeye_config.net[nic_number].macaddr,mac_addr,6);
			
		}else if (!strncmp("hostip", name, strlen(name))){	
			sscanf(value,"%d.%d.%d.%d",&hip[0],&hip[1],&hip[2],&hip[3]);
			memcpy(skyeye_config.net[nic_number].hostip,hip,4);
			
		}else if (!strncmp("ethmod", name, strlen(name))){
			if (!strncmp("linux", value, strlen(value))){		
				skyeye_config.net[nic_number].ethmod = NET_MOD_LINUX;
				
			}else if (!strncmp("tuntap", value, strlen(value))){
				skyeye_config.net[nic_number].ethmod = NET_MOD_TUNTAP;
				skyeye_config.net[nic_number].net_init  =tapif_init;
				skyeye_config.net[nic_number].net_input =tapif_input;
				skyeye_config.net[nic_number].net_output=tapif_output;
				
			}else if (!strncmp("win", value, strlen(value))){
				skyeye_config.net[nic_number].ethmod = NET_MOD_WIN;
				
			}else if (!strncmp("vnet", value, strlen(value))){
				skyeye_config.net[nic_number].ethmod = NET_MOD_VNET;
				skyeye_config.net[nic_number].net_init  =vnetif_init;
				skyeye_config.net[nic_number].net_input =tapif_input;
				skyeye_config.net[nic_number].net_output=tapif_output;
		        }
		}
	}
	maddr=skyeye_config.net[nic_number].macaddr;
	ip=skyeye_config.net[nic_number].hostip;
	SKYEYE_INFO("nic[%d] info: state=%d, ethmod num=%d, mac addr=%x:%x:%x:%x:%x:%x, hostip=%d.%d.%d.%d\n",\
	            nic_number, skyeye_config.net[nic_number].state,skyeye_config.net[nic_number].ethmod,\
		    maddr[0],maddr[1],maddr[2],maddr[3],maddr[4],maddr[5],\
		    ip[0],ip[1],ip[2],ip[3]);
	
	nic_number++;
	return 0;
}
/*added by ksh in 2004-11-26 ,energy option*/
int do_energy_option(skyeye_option_t *this_option, int num_params, const char *params[])
{
	char name[MAX_PARAM_NAME], value[MAX_PARAM_NAME];
	int i, fd;

	for(i = 0; i < num_params; i++){
		if (split_param(params[i], name, value) < 0)
			SKYEYE_ERR("Error: energy has wrong parameter \"%s\".\n", name);
		if (!strncmp("state", name, strlen(name))){
		  if (!strncmp("on", value, strlen(value))){
				skyeye_config.energy.energy_prof = 1;
				SKYEYE_INFO("energy info: turn on energy!\n");
			}else {
        skyeye_config.energy.energy_prof = 0;
        SKYEYE_INFO("energy info: turn off energy!\n");
			}
		}
		else if (!strncmp("filename", name, strlen(name))){
			  strcpy(skyeye_config.energy.filename, value);
				skyeye_config.energy.filename[strlen(value)] = '\0';
			}
		else if (!strncmp("logfile", name, strlen(name))){
				strcpy(skyeye_config.energy.logfile, value);
				skyeye_config.energy.logfile[strlen(value)] = '\0';
		}	
	}
	return 0;

}



/*uart option*/
int do_uart_option(skyeye_option_t *this_option, int num_params, const char *params[])
{
	char name[MAX_PARAM_NAME], value[MAX_PARAM_NAME];
	int i, fd;
	
//chy 2004-12-05 for eclipse
#ifdef SKYEYE4ECLIPSE
        if(nouart) return 0;
#endif
//----------------------------
	for(i = 0; i < num_params; i++){
		if (split_param(params[i], name, value) < 0)
			SKYEYE_ERR("Error: uart has wrong parameter \"%s\".\n", name);
		if (!strncmp("fd_in", name, strlen(name))){
			if ((fd = open(value, O_RDWR))==-1)
				SKYEYE_DBG("Error when open device %s", value);
			skyeye_config.uart.fd_in = fd;
			SKYEYE_INFO("uart info: input device is %s, fd is %d.\n", value, fd); 
		}else if(!strncmp("fd_out", name, strlen(name))){
			if ((fd = open(value, O_RDWR))==-1)
				SKYEYE_DBG("Error when open device %s", value);
			skyeye_config.uart.fd_out = fd;
			SKYEYE_INFO("uart info: output device is %s, fd is %d.\n", value, fd); 
		}
	}
	return 0;

}
/*chy 2004-03-11 lcd option*/
int do_lcd_option(skyeye_option_t *this_option, int num_params, const char *params[])
{
	char name[MAX_PARAM_NAME], value[MAX_PARAM_NAME];
	int i, fd;
	
	for(i=0; i < num_params; i++){
		if (split_param(params[i], name, value) < 0)
                        SKYEYE_ERR("Error: uart has wrong parameter \"%s\".\n", name);
		if (!strncmp("state", name, strlen(name))){
		   	if (!strncmp("on", value, strlen(value))){
				skyeye_config.no_lcd=0;
				SKYEYE_INFO("lcd info: turn on lcd!\n");
			}else {
                        	skyeye_config.no_lcd=1;
                        	SKYEYE_INFO("lcd info: turn off lcd!\n");
			}
		}
	} 
}

/*ywc 2005-04-01 dbct option*/
int do_dbct_option(skyeye_option_t *this_option, int num_params, const char *params[])
{
	char name[MAX_PARAM_NAME], value[MAX_PARAM_NAME];
	int i, fd;
	
	for(i=0; i < num_params; i++){
		if (split_param(params[i], name, value) < 0)
                        SKYEYE_ERR("Error: uart has wrong parameter \"%s\".\n", name);
		if (!strncmp("state", name, strlen(name))){
		   	if (!strncmp("on", value, strlen(value))){
				skyeye_config.no_dbct=0;
				SKYEYE_INFO("dbct info: turn on dbct!\n");
			}else {
                        	skyeye_config.no_dbct=1;
                        	SKYEYE_INFO("lcd info: turn off lcd!\n");
			}
		}
	} 
}

//chy:2003-08-20 do_log option
int do_log_option(skyeye_option_t *this_option, int num_params, const char *params[])
{
	char name[MAX_PARAM_NAME], value[MAX_PARAM_NAME];
	int i, fd, logon;
	unsigned long long start,end,length;
	/*2004-08-09 chy init skyeye_config.log*/
	skyeye_config.log.log_fd=0;
	skyeye_config.log.logon=0;
	skyeye_config.log.start=0;
	skyeye_config.log.end=0;
	skyeye_config.log.length=0;

	for(i = 0; i < num_params; i++){
		if (split_param(params[i], name, value) < 0)
			SKYEYE_ERR("log_info: Error: log has wrong parameter \"%s\".\n", name);
		if (!strncmp("logon", name, strlen(name))){
 			sscanf(value,"%d", &logon);
			if(logon!=0&&logon!=1)
				SKYEYE_ERR("log_info: Error logon value %d\n",logon);
			if(logon==1){
				SKYEYE_INFO("log_info: log is on.\n");
			} else {
				SKYEYE_INFO("log_info: log is off.\n");
			}
			skyeye_config.log.logon=logon;
		}else if (!strncmp("logfile", name, strlen(name))){
			if ((skyeye_logfd = fopen(value, "w+"))==NULL){
				//SKYEYE_DBG("SkyEye Error when open log file %s\n", value);
				perror("SkyEye: Error when open log file:  ");
				exit(-1);
			}
			skyeye_config.log.log_fd = skyeye_logfd;
			SKYEYE_INFO("log_info:log file is %s, fd is 0x%x\n", value, skyeye_logfd); 
		}else if(!strncmp("start", name, strlen(name))){
			start = strtoul(value, NULL, 0);
			skyeye_config.log.start=start;
			SKYEYE_INFO("log_info: log start clock %llu\n",start);
		}else if(!strncmp("end", name, strlen(name))){
			end = strtoul(value, NULL, 0);
			skyeye_config.log.end=end;
			SKYEYE_INFO("log_info: log end clock %llu\n",end);
		}else if(!strncmp("length",name,strlen(name))){
			sscanf(value,"%llu",&length);
			skyeye_config.log.length=length;
			SKYEYE_INFO("log_info: log instr length %llu\n",length);
		}
	}
	return 0;
}


/*
 * we can add this option using:
 * step_disassemble:on[ON|1] for open this option
 * step_disassemble:off[OFF|0] for disable this option 
 * oyangjian add here
 */
int do_step_disassemble_option(skyeye_option_t *this_option, int num_params, const char *params[])
{
	int i;

	  for(i = 0; i < num_params; i ++)
		 {
		  printf("step_disassemble state:%s\n", params[0]);
			if(!params[0])
		     {
			    SKYEYE_ERR("Error :usage: step_disassemble:on[off]");
			    return -1;
			  }
		  if(!strncmp(params[0], "on", 2) || !strncmp(params[0], "ON", 2))
			{
        skyeye_config.can_step_disassemble = 1;
	      return 0;			
			}
		 else if(!strncmp(params[0], "off", 3) || !strncmp(params[0], "OFF", 3))
	   {
		  
        skyeye_config.can_step_disassemble = 0;
				return 0;
		 }
		 
	}
	SKYEYE_ERR("Error: Unkonw cpu name \"%s\"\n", params[0]);	
	return -1;
}

