
#include "etherboot.h"
#include "tftp.h"


//extern etherlink elink;

int mach_boot(register unsigned long entry_point)
{
	void (*fnc)(void) = (void *) entry_point;
	// r0 = 0
	// r1 = 625 (machine nr. MACH_TYPE_P2001)
	(*fnc)();

	return 0; /* We should never reach this point ! */
}

/* Look for paterns in BIOS, for identification purpose */

int check_bios_pattern(char *data,int len,char *patern,int patern_len)
{
	int i,j,k=0;

	for (i=0;i<len;i++) {
		for (j=0;j<patern_len;j++)
			if (data[i+j] != patern[j])
				break;
			if (patern_len == j)
				return 1;
			
	}
	
	return 0;

}

int nand_download_block(unsigned char *data, unsigned int block, unsigned int len, int eof)
{
	static unsigned char *sector_data = NULL;
	static unsigned int blockidx;
	static unsigned int sectoridx=0;

	static int state = 0;
	static int c, s, h;
	static int heads=0, sectors=0, cylinders=0,drive=0,partial_cylinders =0;
	unsigned int i=0,ret,again=1;

	while (again) {
		switch (state) {
			case 0:
				/* Reset write index */
				c=0;h=0;s=1;
				blockidx = 0;
				sectoridx = 0;
				heads=0; sectors=0; cylinders=0; drive=0;partial_cylinders =0; 
				
				drive = nand_flash_find();
				if (drive > 0x85 || drive < 0x80){
					printf ("Nand flash not found. You should enable it in bios.\n");
					return 0;
				}

				/*	Retrieve Nand flash parameters  */
				nand_get_geometry (drive, &cylinders, &heads, &sectors);
				
				printf ("Starting nand image download.\n");
				printf ("Nand flash found on unit %XH.\n", (int)drive);
				printf ("Nand geometry parameters: C/H/S = %d/%d/%d.\n", cylinders, heads, sectors);

				if (heads == 0 || cylinders == 0 || sectors == 0){
					printf ("Invalid disk geometry. Please reformat Nand flash.\n");
					return 0;
				}
				
				/* Update cylinders according to image limit */
				if ((elink.download_config.nand_end / (heads * sectors)) < cylinders)
					partial_cylinders = elink.download_config.nand_end / (heads * sectors);
				else 
					partial_cylinders = cylinders;

				if (elink.download_config.nand_end > cylinders*heads*sectors)
					elink.download_config.nand_end = cylinders*heads*sectors -1;
					
				blockidx = elink.download_config.nand_start;
				c = blockidx / (sectors*heads);
				h = (blockidx % (sectors*heads))/sectors;
				s = (blockidx % (sectors*heads))%sectors+1;


				//printf ("start= %x,end= %x,c = %d, h=%d, s=%d\n",blockidx,elink.download_config.nand_end,c,h,s);
				//getchar();

				/* Allocating data buffer in Low memory for nand_flah_read */
				sector_data = ((char *)phys_to_virt(LOW_MEM_BUFFER));

				/*  Disable data flush by timer interrupt  */
				nand_flash_ioctl(drive,2);

				state = 1;
			case 1:
				if (len < SECTOR_SIZE)
					memset (sector_data+sectoridx*SECTOR_SIZE,0xff,SECTOR_SIZE);
				else
					memcpy (sector_data+sectoridx*SECTOR_SIZE,data,len);

				
				if (eof) {
					state =2;
					continue;
				}

				/* We write only if our index is between start and end sector */
				if (blockidx <=elink.download_config.nand_end){
					if (sectoridx +1 == SECTORS_TO_WRITE){
						ret = nand_flash_write (drive,c,h,s-sectoridx,SECTORS_TO_WRITE,sector_data);
						//printf ("1:write idx=%d, c=%d, h=%d, s=%d,sectoridx=%d.\n",blockidx,c,h,s,sectoridx);
						//printf ("1:write buf0=%d buf1=%d.\n",sector_data[0],(sector_data+512)[0]);
						sectoridx = 0;
					}else
						sectoridx ++;

				}
				else {
					state = 2;
					continue;
				}

				//printf ("Nand read status=%d\n",ret);
			
			/*	for (i=0;i<8;i++)
					printf(" %x",sector_data[i]);
		
			*/
				//printf ("Read idx=%d, c=%d, h=%d, s=%d.\n",blockidx,c,h,s);
				blockidx++;
				s++;
				if (s == sectors+1){
					if (sectors % SECTORS_TO_WRITE != 0) {
						ret = nand_flash_write (drive,c,h,s-sectoridx,sectoridx,sector_data);
						//printf ("2:write idx=%d, c=%d, h=%d, s=%d,sectoridx=%d.\n",blockidx,c,h,s,sectoridx);
						sectoridx = 0;
						
					}
					s = 1;
					h++;
					//getchar();
				}
				
				if (h == heads){
					h = 0;
					c++;
					//printf ("\rProcessing cylinder %d of %d. (blockidx= %d) ", c, cylinders,blockidx);
					printf ("\rProcessing cylinder %d of %d.", c, partial_cylinders);
				}
				
				//printf ("Updated  idx=%d, c=%d, h=%d, s=%d.\n",blockidx,c,h,s);
				/*
				if (blockidx >=10000)
					state =2;
				*/
				break;
			case 2:
				printf ("\nFlush all data.\n");

				if (sectoridx >0 ) {
					ret = nand_flash_write (drive,c,h,s-sectoridx,sectoridx,sector_data);
					sectoridx = 0; 
				}

				/*  Sync data flush */
				nand_flash_ioctl(drive,1);
				/*  Enable data flush by timer interrupt  */
				nand_flash_ioctl(drive,3);
				state	= 0;
				/* Return that we've already finished due to image size limit*/
				if (blockidx >elink.download_config.nand_end)
					return 0xff;
				break;
		}
		again =0;
	}

	//printf ("blockodx=%d, block=%d, eof=%d, len=%d\n",blockidx,*block,*eof,*len);
	return 1;
}


int nand_upload_block(unsigned char **data, unsigned int *block, unsigned int *len,int *eof)
{
	static unsigned char *sector_data = NULL;
	static unsigned int blockidx = 0;
	static unsigned int sectoridx=0,num_of_cached_sectors=0;

	static int state = 0;
	static int c, s, h;
	static int heads=0, sectors=0, cylinders=0,drive=0,partial_cylinders =0;
	int i=0,ret,again=1;

	while(again) {
		switch (state) {
			case 0:
				/* Reset read index */
				c=0;h=0;s=1;
				blockidx = 0;
				sectoridx=0;num_of_cached_sectors=0;

				heads=0; sectors=0; cylinders=0; drive=0;partial_cylinders =0;
				
				drive = nand_flash_find();
				if (drive == 0xff){
					printf ("Nand flash not found. You should enable it in bios\n");
					return 0;
				}
				else if (drive > 0x85){
					printf ("Nand flash is found, but it's initialization failed. Reformat it.\n");
					return 0;
				}

				/*	Retrieve Nand flash parameters  */
				nand_get_geometry (drive, &cylinders, &heads, &sectors);
				
				printf ("Starting nand image upload.\n");
				printf ("Nand flash found on unit %XH.\n", (int)drive);
				printf ("Nand geometry parameters: C/H/S = %d/%d/%d.\n", cylinders, heads, sectors);

				if (heads == 0 || cylinders == 0 || sectors == 0){
					printf ("Invalid disk geometry. Please reformat Nand flash.\n");
					return 0;
				}
				
				/* Update cylinders according to image limit */
				if ((elink.upload_config.nand_end / (heads * sectors)) < cylinders)
					partial_cylinders = elink.upload_config.nand_end / (heads * sectors);
				else 
					partial_cylinders = cylinders;

				
				blockidx = elink.upload_config.nand_start;
				
				c = blockidx / (sectors*heads);
				h = (blockidx % (sectors*heads))/sectors;
				s = ((blockidx % (sectors*heads))%sectors) +1;

				//printf ("start= %x,c = %d, h=%d, s=%d\n",blockidx,c,h,s);

				/* Allocating data buffer in Low memory for nand_flah_read */
				sector_data = ((char *)phys_to_virt(LOW_MEM_BUFFER));
				/*  Disable data flush by timer interrupt  */
				nand_flash_ioctl(drive,2);

				state = 1;
			case 1:

				if (sectoridx == 0){
					if (blockidx + SECTORS_TO_READ-1 <=elink.upload_config.nand_end && s + SECTORS_TO_READ <= sectors+1) {
						ret = nand_flash_read (drive,c,h,s,SECTORS_TO_READ,sector_data);
						num_of_cached_sectors = SECTORS_TO_READ;
						//printf ("Read idx=%d, c=%d, h=%d, s=%d ,num=%d.\n",blockidx,c,h,s,num_of_cached_sectors );
					}
					else if (s + SECTORS_TO_READ > sectors+1) {
						num_of_cached_sectors = sectors-s+1;
						if (num_of_cached_sectors >0) {
							ret = nand_flash_read (drive,c,h,s,num_of_cached_sectors,sector_data);
							//printf ("Read idx=%d, c=%d, h=%d, s=%d ,num=%d.\n",blockidx,c,h,s,num_of_cached_sectors );
						}
					}else {
						num_of_cached_sectors = elink.upload_config.nand_end - blockidx +1 ;
						if (num_of_cached_sectors >0){
							ret = nand_flash_read (drive,c,h,s,num_of_cached_sectors,sector_data);
							//printf ("Read idx=%d, c=%d, h=%d, s=%d ,num=%d.\n",blockidx,c,h,s,num_of_cached_sectors );
						}
						state = 2;
						continue;
					}
				}

				/* We read only if our index is between start and end sector */
				/*
				if (blockidx <=elink.upload_config.nand_end)
					ret = nand_flash_read (drive,c,h,s,sector_data);
				else {
					state = 2;
					continue;
				}
				*/
				//printf ("Nand read status=%d\n",ret);
				
//				printf ("Read idx=%d, c=%d, h=%d, s=%d ,secidx=%d.\n",blockidx,c,h,s,sectoridx );
				*data	= sector_data + sectoridx*SECTOR_SIZE;
				*block  = blockidx % 0x10000 ; 
				*eof	= 0;
				*len	= SECTOR_SIZE;
				sectoridx ++;
				

				if (sectoridx == num_of_cached_sectors ){
					sectoridx = 0;
					num_of_cached_sectors = 0;
				}

/*
				for (i=0;i<8;i++)
					printf(" %x",(*data)[i]);
*/		
			
				//printf ("Read idx=%d, c=%d, h=%d, s=%d.\n",blockidx,c,h,s);
				blockidx++;
				s++;
				if (s == sectors+1){
					s = 1;
					h++;
				}
				
				if (h == heads){
					h = 0;
					c++;
					//printf ("\rProcessing cylinder %d of %d. (blockidx= %d) ", c, cylinders,blockidx);
					printf ("\rProcessing cylinder %d of %d.", c, partial_cylinders);
				}

				if (c == cylinders )
					state = 2;
				
				//printf ("Updated  idx=%d, c=%d, h=%d, s=%d.\n",blockidx,c,h,s);
				/*
				if (blockidx >=10000)
					state =2;
				*/
				break;
			case 2:
				
				if (sectoridx < num_of_cached_sectors && num_of_cached_sectors >0){				
					*data	= sector_data +sectoridx*SECTOR_SIZE;
					*block  = blockidx % 0x10000 ; 
					*eof	= 0;
					*len	= SECTOR_SIZE; 
					sectoridx++;
					blockidx++;
					break;
				}else {

					*data	= sector_data;
					*block  = blockidx % 0x10000 ; 
					*eof	= 1;
					*len	= 0; 

					state	= 0;
				}

				printf ("\nFlush all data.\n");
				/*  Sync data flush */
				nand_flash_ioctl(drive,1);
				/*  Enable data flush by timer interrupt  */
				nand_flash_ioctl(drive,3);

				
		}
		again = 0;
	}

	//printf ("blockodx=%d, block=%d, eof=%d, len=%d\n",blockidx,*block,*eof,*len);
	return 1;
}

#define CONFIG_SIZE 0x10000
#define BIOS_SIZE	0x80000
#define NOR_RETRY_COUNT 5
#define NOR_ERASUE_STEP_SIZE 0x1000

int nor_download_block(int function,unsigned char *data, unsigned int block, unsigned int len, int eof)
{
	static unsigned char *block_data = NULL;
	static unsigned int size_1 = 0;
	static unsigned int size_2 = 0;

	static unsigned char *bios_image_1 = NULL;
	static unsigned char *bios_image_2 = NULL;

	static int state	= 0;
	static unsigned int img_size = 0;
	static char img_name_bios[] = "bios";
	static char img_name_config[] = "configuration block";
	static char *img_name = NULL;


	unsigned int i=0,ret,again=1;
	unsigned int j=0,k=0;

	while (again) {
		switch (state) {
			case 0:

				if (function == 1){
					img_size = BIOS_SIZE;
					img_name = img_name_bios;
				}
				else if (function == 2){
					img_size = CONFIG_SIZE;
					img_name = img_name_config;
				}

				
				/* Allocating space for bios image */
				/* from 0xfff80000 - 0xffffffff */
				bios_image_1 = ((char *)phys_to_virt(EXT_MEM_BUFFER_1)); /* Allocating from 2MB and upper */ 
				printf ("Starting %s download (pass 1)\n",img_name);
				size_1 = 0;
				state = 1;

			case 1:

				memcpy (bios_image_1+size_1,data,len);
				size_1 += len;

				if (eof) {
					state =2;
					if (size_1 != img_size){
						state = 0;
						printf ("Error: Downloaded %s image is not %d KB. Aborting ...\n",img_name,img_size/1024);
						printf ("size_1=%d\n",size_1);
						return 0;
					}
				}
				break;
			case 2:

				size_2 = 0;
				/* Allocating space for bios image */
				/* from 0xfff80000 - 0xffffffff */
				bios_image_2 = ((char *)phys_to_virt(EXT_MEM_BUFFER_2)); /* Allocating from 3MB and upper */ ; 
				printf ("Starting %s download (pass 2)\n",img_name);

					/* Allocating data buffer in Low memory for tftp transfer unit */
				block_data = ((char *)phys_to_virt(LOW_MEM_BUFFER));

				state	= 3;
			case 3:

				memcpy (bios_image_2+size_2,data,len);
				size_2 += len;

				if (eof) {
					state = 4;
					continue;
				}

				
				break;

			case 4:

				state =0;	

				if (size_2 != img_size){
					printf ("Error: Downloaded %s image is not %d KB. Aborting ...\n",img_name,img_size/1024);
					return 0;
				}

				// Compare 2 RAM images
				if (memcmp(bios_image_1,bios_image_2,size_1) != 0)
				{
					printf ("Error: %s image download error. Please restart download.\n",img_name);
					return 0;
				}

				
				//printf ("patern1=%d\n",check_bios_pattern(bios_image_1,size_1,BIOS_PATERN_1,strlen(BIOS_PATERN_1)));
				//printf ("patern2=%d\n",check_bios_pattern(bios_image_1,size_1,BIOS_PATERN_2,strlen(BIOS_PATERN_2)));

				// If we are sure in downloaded image, proceed with update:

				// Unlock the bios area.
				nor_flash_unlock();
				// Perform write test in case of bios update
				if (function == 1) {

					/* Check for valid bios signature */
					if (!check_bios_pattern(bios_image_1,size_1,BIOS_PATERN_1,strlen(BIOS_PATERN_1)) && 
						!check_bios_pattern(bios_image_1,size_1,BIOS_PATERN_2,strlen(BIOS_PATERN_2))	)
					{
						printf ("Error: Downloaded image doesn't contain valid bios signature.\n");
						return 0;
					}

					printf ("Trying to write Test block...\n");
					// Step1: Erase Test block
					nor_flash_ioctl(1,0xfff80000,0x2000,block_data);
					memset(block_data,0x00,0x2000);
					// Step2: Write Test block
					ret = nor_flash_ioctl(3,0xfff80000,0x2000,block_data);
					if (ret == 0){
						printf ("bios can't be writed. Please try again...\n");
						return 0;
					}

					// Step3: Read and Compare Test block
					ret = nor_flash_ioctl(2,0xfff80000,0x2000,block_data);
					if (ret == 0){
						printf ("bios can't be readed. Please try again...\n");		
						return 0;
					}
					for (i=0;i<0x2000;i++)
						if (block_data[i] !=0){
							printf ("bios can't be writed. Please try again...\n");
							return 0;
						}

					//Step3.5: Read configuration block */
		
					nor_flash_ioctl(2,ETHRLINK_CONFIG,0x8000,block_data);
					memcpy(bios_image_1 + (ETHRLINK_CONFIG - 0xfff80000),block_data,0x8000);
				#ifdef CM_IVC3
					nor_flash_ioctl(2,ETHRLINK_CONFIG+0x8000,0x8000,block_data);
					memcpy(bios_image_1 + (ETHRLINK_CONFIG - 0xfff80000) + 0x8000,block_data,0x8000);
				#endif 

				#ifdef CM_IGLX
					nor_flash_ioctl(2,ETHRLINK_CONFIG+0x8000,0x8000,block_data);
					memcpy(bios_image_1 + (ETHRLINK_CONFIG - 0xfff80000) + 0x8000,block_data,0x8000);
				#endif 

					printf ("Erasing bios blocks...\n");
					// Step4: Erase flash (the erasure is performes in 4K steps for each block) 
					for (k = 0xfff80000; k <= 0xffff0000 && k>0; k+=0x10000)
					{
						printf ("\rErasing bios block %d of 8.",(k-0xfff80000)/0x10000 +1 );
						for (i=0;i<0x10000;i+= NOR_ERASUE_STEP_SIZE) 
							for (j=0; j < NOR_RETRY_COUNT; j++)
								if (nor_flash_ioctl(1,k + i,NOR_ERASUE_STEP_SIZE,block_data))
									break;
								else if (j == NOR_RETRY_COUNT -1)
								{
									printf ("Error: Can't erase NOR at 0x%x\n",k + i);
									return 0;
								}
					}
	
					// Step5: Update

					for (i=0; i<0x80000;i+= 0x8000) {
						printf ("\rWriting bios block %d of 16.",i/0x8000 +1);

						memcpy(block_data,bios_image_1+i,0x8000); 
						for (j=0; j < NOR_RETRY_COUNT; j++)
							if (nor_flash_ioctl(3,0xfff80000+i,0x8000,block_data))
								break;
							else if (j == NOR_RETRY_COUNT -1)
							{
								printf ("Error: Can't write NOR at 0x%x.\n",0xfff80000+i);
								return 0;
							}

						//nor_flash_ioctl(3,0xfff80000+i,0x8000,block_data);
						
					}
					putchar('\n');

				}else if (function == 2) {

					printf ("Updating configuration block...\n");

				#ifdef CM_I986
					//Step0: Read configuration block from 0x8000 offset*/
					nor_flash_ioctl(2,ETHRLINK_CONFIG+0x8000,0x8000,block_data);
					memcpy(bios_image_2,block_data,0x8000);
				#endif 

					//Step1: Erase flash
					nor_flash_ioctl(1,ETHRLINK_CONFIG,0x10000,block_data);
					//Step2: Update block
					memcpy(block_data,bios_image_1,0x8000);
					nor_flash_ioctl(3,ETHRLINK_CONFIG,0x8000,block_data);

				#ifdef CM_IVC3
					memcpy(block_data,bios_image_1+0x8000,0x8000);
					nor_flash_ioctl(3,ETHRLINK_CONFIG+0x8000,0x8000,block_data);
				#endif

				#ifdef CM_IGLX
					memcpy(block_data,bios_image_1+0x8000,0x8000);
					nor_flash_ioctl(3,ETHRLINK_CONFIG+0x8000,0x8000,block_data);
				#endif

				#ifdef CM_I986
					memcpy(block_data,bios_image_2,0x8000);
					nor_flash_ioctl(3,ETHRLINK_CONFIG+0x8000,0x8000,block_data);
				#endif
				}

				//Step6: Cleanup
				bios_image_1 = NULL;
				bios_image_2 = NULL;	



		}
		again =0;
	}

	//printf ("blockodx=%d, block=%d, eof=%d, len=%d\n",blockidx,*block,*eof,*len);
	return 1;
}

int nor_download_block_bios(unsigned char *data, unsigned int block, unsigned int len, int eof)
{
	return nor_download_block(1,data,block,len,eof);
}

int nor_download_block_config(unsigned char *data, unsigned int block, unsigned int len, int eof)
{
	return nor_download_block(2,data,block,len,eof);
}


int nor_upload_block(int function,unsigned char **data, unsigned int *block, unsigned int *len, int *eof)
{
	static unsigned char *block_data = NULL;
	static unsigned char *bios_image_1 = NULL;

	static int state	= 0;
	static unsigned int img_size = 0;
	static char img_name_bios[] = "bios";
	static char img_name_config[] = "configuration block";
	static char *img_name = NULL;
	static int blockidx = 0;


	unsigned int i=0,ret,again=1;

	while (again) {
		switch (state) {
			case 0:

				if (function == 1){
					img_size = BIOS_SIZE;
					img_name = img_name_bios;
				}
				else if (function == 2){
					img_size = CONFIG_SIZE;
					img_name = img_name_config;
				}

				/* Allocating space for bios image */
				bios_image_1 = ((char *)phys_to_virt(EXT_MEM_BUFFER_1)); /* Allocating from 2MB and upper */
				/* Allocating data buffer in Low memory for tftp transfer unit */
				block_data = ((char *)phys_to_virt(LOW_MEM_BUFFER));

				if (function ==1) {
					for (i=0; i<0x80000;i+= 0x8000) {
						nor_flash_ioctl(2,0xfff80000+i,0x8000,block_data);
						memcpy(bios_image_1+i,block_data,0x8000); 
					}
				}
				else if (function == 2){
					nor_flash_ioctl(2,ETHRLINK_CONFIG,0x8000,block_data);
					memcpy(bios_image_1,block_data,0x8000);
					nor_flash_ioctl(2,ETHRLINK_CONFIG+0x8000,0x8000,block_data);
					memcpy(bios_image_1+0x8000,block_data,0x8000);
				}


				printf ("Starting %s upload.\n",img_name);
				blockidx = 0;
				state = 1;

			case 1:

				*data = bios_image_1 + blockidx * SECTOR_SIZE;
				*block = blockidx++;
				*len = SECTOR_SIZE;
				*eof = 0;

				if (blockidx * SECTOR_SIZE == img_size){
					*eof = 0;
					state =2;
				}
				break;
			case 2:

				*data = bios_image_1 + blockidx * SECTOR_SIZE ; ;
				*block = blockidx;
				*len = 0;
				*eof = 1;

				memcpy(block_data,*data,SECTOR_SIZE);

				forget(bios_image_1);
				state =0 ;
				
		}
		again =0;
	}

	//printf ("blockodx=%d, block=%d, eof=%d, len=%d\n",blockidx,*block,*eof,*len);
	return 1;
}

int nor_upload_block_config(unsigned char **data, unsigned int *block, unsigned int *len, int *eof)
{
	return nor_upload_block(2,data,block,len,eof);
}

int nor_upload_block_bios(unsigned char **data, unsigned int *block, unsigned int *len, int *eof)
{
	return nor_upload_block(1,data,block,len,eof);
}

int save_etherlink_config(etherlink *elink)
{
	static unsigned char *block_data = NULL;
	static unsigned char *config = NULL;
	static unsigned char signature[] = {0x55,0x55};
	int i=0;

	config = ((unsigned char *)phys_to_virt(EXT_MEM_BUFFER_1)); /* Allocating from 2MB and upper */

	/* Allocating data buffer in Low memory for tftp transfer unit */
	block_data = ((char *)phys_to_virt(LOW_MEM_BUFFER));

	/* Read configuration block */
	
	nor_flash_ioctl(2,ETHRLINK_CONFIG,0x8000,block_data);
	memcpy(config,block_data,0x8000);
	nor_flash_ioctl(2,ETHRLINK_CONFIG+0x8000,0x8000,block_data);
	memcpy(config+0x8000,block_data,0x8000);
	

	/* Update configuration block */
	memcpy(config+ETHRLINK_CONFIG_OFFSET,signature,2);
	memcpy(config+ETHRLINK_CONFIG_OFFSET+2,elink,sizeof(etherlink));

	/* Unlock configuration block */
	nor_flash_unlock();

	/* Erase configuration block */
	nor_flash_ioctl(1,ETHRLINK_CONFIG,0x10000,block_data);

	/* Writeback configuration block */

	memcpy(block_data,config,0x8000);
	nor_flash_ioctl(3,ETHRLINK_CONFIG,0x8000,block_data);
	memcpy(block_data,config+0x8000,0x8000);
	nor_flash_ioctl(3,ETHRLINK_CONFIG+0x8000,0x8000,block_data);
	
	return 1;
}

int load_etherlink_config(etherlink *elink)
{
	unsigned char *block_data = NULL;
	unsigned char *config = NULL;
	//unsigned char config[512];
	unsigned char signature[] = {0x55,0x55};
	int size = sizeof(etherlink)+2;
	int ret;

	config = ((unsigned char *)phys_to_virt(EXT_MEM_BUFFER_1)); /* Allocating from 2MB and upper */

	/* Allocating data buffer in Low memory for tftp transfer unit */
	block_data = ((char *)phys_to_virt(LOW_MEM_BUFFER));

	/* Read configuration block */
	nor_flash_ioctl(2,ETHRLINK_CONFIG+ETHRLINK_CONFIG_OFFSET,size,block_data);

	memcpy(config,block_data,size);
	
	/* Compare signature */
	if (memcmp(config,signature,2)!= 0) {
		/*printf ("%x %x\n",config[0],config[1]);
		getchar();
		*/
		printf ("Wrong signature. Failed to read Etherlink settings\n");

		//elink->net_config.device_ip.s_addr = htonl(0x0a010153);
		elink->net_config.device_ip.s_addr = htonl(0x00000000);
		elink->net_config.device_subnet_mask.s_addr = htonl(0xffffff00);
		elink->net_config.use_dhcp = 1;

		//elink->server_config.server_ip.s_addr = htonl(0x0a0101ba);
		elink->server_config.server_ip.s_addr = htonl(0x00000000);
		memcpy(elink->server_config.nand_fname,"disk.dat",8);
		memcpy(elink->server_config.nor_fname,"bios.raw",8);
		memcpy(elink->server_config.config_fname,"config.raw",10);
		elink->server_config.nand_fname[9] = '\0';
		elink->server_config.nor_fname[9] = '\0';
		elink->server_config.config_fname[11] = '\0';
		elink->auto_config.enable_nand = 0;
		elink->auto_config.enable_nor = 0;
		elink->auto_config.enable_config = 0;
		elink->download_config.nand_start = 0;
		elink->download_config.nand_end = 0xffffffff;
		elink->upload_config.nand_start = 0;
		elink->upload_config.nand_end = 0xffffffff;

		elink->drive = 'C';
	
		return 0;
	}
	memcpy(elink,config+2,sizeof(etherlink));

	/* Check the automative mode */
	config = ((unsigned char *)phys_to_virt(AUTO_BUFFER_ADDR)); /* Bios indicates auto mode in this address.*/
	if (config[0] == AUTO_BUFFER_VALUE)
		auto_mode = 1;
	else 
		auto_mode = 0;
 
	//forget(config);
	return 1;
}

static os_download_t flash_probe(unsigned char *data __unused, unsigned int len __unused)
{
	printf("(FLASH");
	// probe something here...
	printf(")... \n");

	//raw_load_addr = phys_to_virt(_end);
	//raw_load_addr = RAWADDR;
	//printf("Writing image to 0x%x\n", raw_load_addr);
	//return nand_download_block;
	return NULL;
}