
/*
 *
 * Copyright (C) Eicon Technology Corporation, 2000.
 *
 * This source file is supplied for the exclusive use with Eicon
 * Technology Corporation's range of DIVA Server Adapters.
 *
 * Eicon File Revision :    1.7  
 *
 * 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, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY 
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */


/* Includes */

#include <stdio.h>
#include <unistd.h>
#include "sys.h" /* platform specific stuff */
#include "dsp_defs.h" /* combifile structures and definitions */
#include "cardtype.h" /* containd defines for card type ordinals */
#include "divas.h" /* defines for IOCTLs */
#include "constant.h"

#include "linux.h" /* Linux specific download stuff */
#include <sys/ioctl.h>
#include  <sys/types.h> /* for file info */
#include  <sys/stat.h> 
#include  <fcntl.h> 

#include <stdlib.h> /* For dynamic memory allocation */
#include <memory.h> /* For memcpy stuff */

#include <errno.h> /* For error checking stuff */

#include "linuxcfg.h"

/* Definitions */
/*
static char dsp_combifile_format_identification[DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE] =
{
  'E', 'i', 'c', 'o', 'n', '.', 'D', 'i',
  'e', 'h', 'l', ' ', 'D', 'S', 'P', ' ',
  'D', 'o', 'w', 'n', 'l', 'o', 'a', 'd',
  ' ', 'C', 'o', 'm', 'b', 'i', 'f', 'i',
  'l', 'e', '\0','\0','\0','\0','\0','\0',
  '\0','\0','\0','\0','\0','\0','\0','\0'
};

static char dsp_file_format_identification[DSP_FILE_FORMAT_IDENTIFICATION_SIZE] =
{
  'E', 'i', 'c', 'o', 'n', '.', 'D', 'i',
  'e', 'h', 'l', ' ', 'D', 'S', 'P', ' ',
  'D', 'o', 'w', 'n', 'l', 'o', 'a', 'd',
  '\0','F', 'i', 'l', 'e','\0','\0','\0',
  '\0','\0','\0','\0','\0','\0','\0','\0',
  '\0','\0','\0','\0','\0','\0','\0','\0'
};
*/
#define COMBIFILE DATADIR "/dspdload.bin"

/*These files will contain the binaries wriiten to card*/
#ifdef DEBUG
#define DSPFILE   DATADIR "/debug_dsp"
#define TABLEFILE DATADIR "/debug_tablefile"
#endif

/* External references */

extern int num_directory_entries;
extern int usage_mask_size;
extern int download_count;
extern int directory_size;

extern int usage_bit;
extern int usage_byte;

extern int card_id;
static int first_load = TRUE;


int set_download_pos(int card_type, word wFeatures);

/* Forward references */
t_dsp_combifile_directory_entry *display_combifile_details(char *details);
dword get_download(char *download_block, char *usage_mask_ptr);
dword store_download(char *data, word size, char *store);
int set_alignment_mask(int card_type);
int download(char *block, dword size, int code);


/*--------------------------------------------------------------------------
 * load_combifile() function
 * 
 * opens combifile, reads into buffer and calls fn to display info.
 * It then parses the directory for the fileset required for the
 * specified card. It the calls a function to determine the amount of memory 
 * required for the download and calls it again to get the download required.
 * Finally it downloads the data from the combi file and a table of addresses.
 *
 * Parameters: cardtype = Card ordinal as specified in cardtype.h
 *--------------------------------------------------------------------------*/

void load_combifile(int card_type, word wFeatures)
{
	int fd;
	int count;
	int file_set_number=0;
	struct stat file_info;
	char *combifile_start;
	char *usage_mask_ptr;
	char *download_block;
	t_dsp_combifile_directory_entry *directory;
	t_dsp_combifile_directory_entry *tmp_directory;
	dword download_size;
  
#ifdef DEBUG 
	int dsp_fd;
    int table_fd;
#endif
	if(!set_alignment_mask(card_type))
	{
		return;
	}

	if(!set_download_pos(card_type, wFeatures))
	{
		return;
	}

	if ((fd = open(COMBIFILE, O_RDONLY, 0)) == -1)
	{
		perror("Error opening Eicon combifile");
		return;
	}

	if (fstat(fd, &file_info))
	{
		perror("Error geting file details of Eicon combifile");
		close(fd);
		return;
	}

	if ( file_info.st_size <= 0 )
	{
		perror("Invalid file length in Eicon combifile");
		close(fd);
		return;
	}

	combifile_start = malloc(file_info.st_size);

	if(!combifile_start)
	{
		perror("Error allocating memory for Eicon combifile");
		close(fd);
		return;
	}

#ifdef DEBUG
		printf("File mapped to address 0x%x\n", combifile_start);
#endif

	if((read(fd, combifile_start, file_info.st_size)) != file_info.st_size)
	{
		perror("Error reading Eicon combifile into memory");
		free(combifile_start);
		close(fd);
		return;
	}

	close(fd); /* We're done with the file */

	directory = display_combifile_details(combifile_start);

#ifdef DEBUG
	printf("Directory mapped to address 0x%x, offset = 0x%x\n", directory,
						((unsigned int)directory - (unsigned int)combifile_start));
#endif

	tmp_directory = directory;

	for(count = 0; count < num_directory_entries; count++)
	{
		if(BYTE_SWAP_WORD(tmp_directory->card_type_number) == card_type)
		{
#ifdef DEBUG
			printf("Found entry in directory slot %d\n", count);
		printf("File set number is %d\n", 
						BYTE_SWAP_WORD(tmp_directory->file_set_number));
            printf("Matched Card %d is %d. Fileset number is %d\n", count,
                        BYTE_SWAP_WORD(tmp_directory->card_type_number),
                        BYTE_SWAP_WORD(tmp_directory->file_set_number));

#endif
			file_set_number = BYTE_SWAP_WORD(tmp_directory->file_set_number);
			break;
		}
#ifdef DEBUG
		printf("Card %d is %d. Fileset number is %d\n", count,
						BYTE_SWAP_WORD(tmp_directory->card_type_number),
						BYTE_SWAP_WORD(tmp_directory->file_set_number));
#endif
		tmp_directory++;
	}

	if(count == num_directory_entries)
	{
		printf("Card not found in directory\n");
		free(combifile_start);
		return;
	}

	usage_bit = file_set_number%8;
	usage_byte= file_set_number/8;

#ifdef DEBUG
	printf("Bit field is bit %d in byte %d of the usage mask\n", 
				usage_bit,
				usage_byte);
#endif

	usage_mask_ptr = (char *)(directory);
	usage_mask_ptr += directory_size;

#ifdef DEBUG
	printf("First mask at address 0x%x, offset = 0x%x\n", usage_mask_ptr,
						(usage_mask_ptr - combifile_start));
#endif
    
	no_of_tables = malloc((sizeof(dword)));
	download_size = get_download(NULL, usage_mask_ptr);

#ifdef DEBUG
	printf("Initial size of download_size is 0x%x\n",download_size);
#endif

	if(!download_size)
	{
		printf("Error getting details on DSP downloads\n");
		free(combifile_start);
		return;
	}

	/* Allocate the amount of space to hold the details from the 
	 * combifile plus an additional amount to allow for alignment
	 * on dword boundary. (Max. shift is 3 bytes for each download)
	 */
     
    
	download_block = malloc((download_size + (no_of_downloads * 100)));

#ifdef DEBUG
	printf("download_block size = (download_size + alignments) is: 0x%x\n",(download_size + (no_of_downloads * 100)));
#endif


	if(!download_block)
	{
		printf("Error allocating memory for download\n");
		free(combifile_start);
		return;
	}

#ifdef DEBUG
	printf("Calling get_download to write into download_block\n");
#endif

	if(!(get_download(download_block, usage_mask_ptr)))
	{
		printf("Error getting data for DSP download\n");
		free(download_block);
		free(combifile_start);
        free(no_of_tables);
		return;
	}

#ifdef DEBUG
    printf("Downloading data using IOCTLs to Card\n");
#endif

    
#ifdef DEBUG

	if ((dsp_fd = open(DSPFILE, O_RDWR)) == -1)
	{
		perror("Error opening Eicon dsp_file");
		return;
	}

	if ((!(write(dsp_fd,download_block,total_bytes_in_download))))
	{
		perror("Error writing to Eicon dsp_file");
        return;
    }

    close(dsp_fd);

#endif


	if(!(download(download_block, total_bytes_in_download, DIA_DSP_CODE)))
	{
		printf("Error downloading Combifile details\n");
		free(download_block);
		free(combifile_start);
        free(no_of_tables);
		return;
	}
     

    	 
	if(!(download(no_of_tables,sizeof(table_count), DIA_DLOAD_CNT)))
	{
		printf("Error downloading number of downloads to load\n");
		free(download_block);
		free(combifile_start);
		free(no_of_tables);
		return;
	}
	
#ifdef DEBUG
	
	if ((table_fd = open(TABLEFILE, O_RDWR)) == -1)
	{
		perror("Error opening Eicon table_file");
		return;
	}
	
	if ((!(write(table_fd,(char *)p_download_table,sizeof(p_download_table)))))
	{
		perror("Error writing to Eicon table_file");
        return;
    }

     close(table_fd);

#endif

	if(!(download((char *)p_download_table,sizeof(p_download_table), DIA_TABLE_CODE)))
	{
		printf("Error downloading Combifile details\n");
		free(download_block);
		free(combifile_start);
        free(no_of_tables);
		return;
	}
	
    


	free(download_block);
	free(combifile_start);
    free(no_of_tables);
	return;

}


/*--------------------------------------------------------------
 * display_combifile_details()
 *
 * Displays the information in the combifile header
 * Arguments: Pointer to the combifile structure in memory
 * Returns:   The address of the begining of directory which is
 *            directly after the file description.
 *-------------------------------------------------------------*/

t_dsp_combifile_directory_entry *display_combifile_details(char *details)
{
	dword offset=0;
	t_dsp_combifile_header *file_header;
	char *description;
	t_dsp_combifile_directory_entry *return_ptr = NULL;

	file_header = (t_dsp_combifile_header *)details;

#ifdef DEBUG
	printf("%s\n", file_header->format_identification);
	printf("\tFormat Version: 0x%.4x\n", 
						BYTE_SWAP_WORD(file_header->format_version_bcd));
	printf("\tNumber of directory entries : %d\n", 
						BYTE_SWAP_WORD(file_header->directory_entries));
	printf("\tDownload count: %d\n", BYTE_SWAP_WORD(file_header->download_count));
#endif

	description = (char *)file_header + BYTE_SWAP_WORD((file_header->header_size));

	printf("%s\n", description);

	num_directory_entries = BYTE_SWAP_WORD(file_header->directory_entries);
	usage_mask_size = BYTE_SWAP_WORD(file_header->usage_mask_size);
	download_count = BYTE_SWAP_WORD(file_header->download_count);
	directory_size = BYTE_SWAP_WORD(file_header->directory_size);

	return_ptr = (t_dsp_combifile_directory_entry *) (unsigned int)file_header ;
	offset 	+= (BYTE_SWAP_WORD((file_header->header_size)));
	offset	+= (BYTE_SWAP_WORD((file_header->combifile_description_size)));
	offset += (dword)return_ptr;

	return (t_dsp_combifile_directory_entry *)offset;
	
}


/*-----------------------------------------------------------------------
 * get_download ()
 *
 * Loops for each download in the combifile, reading the usage mask to
 * determine if this DSP code is required for the current file set.
 * If a memory address is specified for download_area, the code is stored
 * there.
 * Arguments:ptr to download_block to store code,ptr to first usage_mask in 
 *           combifile which has been read into memory     
 * Returns:  length of download required
 *-----------------------------------------------------------------------*/


dword get_download(char *download_block, char *download_area)
{
	int n;
	char *usage_mask;
	char test_byte=0;
	dword length=0;
	dword addr;
    unsigned int table_index;
	t_dsp_file_header *file_header;
	t_dsp_download_desc *p_download_desc;
	char *data;

#ifdef DEBUG
	int i;
#endif

	no_of_downloads = 0;

	test_byte = 0x01;

	test_byte <<= usage_bit;
	
	usage_mask = malloc(usage_mask_size);

	if(!usage_mask)
	{
		printf("Error allocating memory for usage mask");
		return 0;
	}

	bzero(usage_mask, usage_mask_size);

	for(n = 0; n < download_count; n++)
	{
	
		memcpy(usage_mask, download_area, usage_mask_size);
#ifdef DEBUG
        printf("  \n");
		printf("Usage mask = 0x%.2x ", usage_mask[0]);
		if(usage_mask_size > 1)
		{
			for(i=1; i<usage_mask_size; i++)
			{
				printf("0x%.2x ", usage_mask[i]);
			}
		}
#endif

		download_area += usage_mask_size;

		file_header = (t_dsp_file_header *)download_area;
#ifdef DEBUG 
		printf("%s %d\n", file_header->format_identification,n);
#endif

		if( test_byte & usage_mask[usage_byte] )
		{
			
		no_of_downloads++;
        table_index = (no_of_downloads - 1);

#ifdef DEBUG
			printf("*****DSP DOWNLOAD %d REQUIRED******\n", n);
            printf("download required count is now %d\n",no_of_downloads);
            printf("   \n");
#endif
     

/*This is the lenth of the memory to malloc */ 

			length += ((dword)((word)(BYTE_SWAP_WORD(file_header->header_size) 
						- sizeof(t_dsp_file_header))))
			+ ((dword)BYTE_SWAP_WORD((file_header->download_description_size)))
			+ ((dword)BYTE_SWAP_WORD((file_header->memory_block_table_size)))
			+ ((dword)BYTE_SWAP_WORD((file_header->segment_table_size)))
			+ ((dword)BYTE_SWAP_WORD((file_header->symbol_table_size)))
			+ ((dword)BYTE_SWAP_WORD((file_header->total_data_size_dm)))
			+ ((dword)BYTE_SWAP_WORD((file_header->total_data_size_pm)));


			if(download_block)
			{
			
			data = (char *)file_header;
			data += ((dword)(BYTE_SWAP_WORD(file_header->header_size))); 
			
				p_download_desc = &(p_download_table[table_index]);
				p_download_desc->download_id = file_header->download_id;
				p_download_desc->download_flags = file_header->download_flags;
				p_download_desc->required_processing_power = file_header->required_processing_power;
				p_download_desc->interface_channel_count = file_header->interface_channel_count;
				p_download_desc->excess_header_size = BYTE_SWAP_WORD((word)(BYTE_SWAP_WORD(file_header->header_size) - (word)sizeof(t_dsp_file_header)));
				p_download_desc->memory_block_count = file_header->memory_block_count;
				p_download_desc->segment_count = file_header->segment_count;
				p_download_desc->symbol_count = file_header->symbol_count;
				p_download_desc->data_block_count_dm = file_header->data_block_count_dm;
				p_download_desc->data_block_count_pm = file_header->data_block_count_pm;

				p_download_desc->p_excess_header_data = NULL;
				if ((BYTE_SWAP_WORD (p_download_desc->excess_header_size) != 0))
				{
#ifdef DEBUG
			printf("1.store_download called from get_download\n");
			
#endif
					addr = store_download(data, p_download_desc->excess_header_size,
											download_block);
					p_download_desc->p_excess_header_data = (byte *)addr;
					data += (BYTE_SWAP_WORD(p_download_desc->excess_header_size)); 
				}
				p_download_desc->p_download_description = NULL;
				if ((BYTE_SWAP_WORD(file_header->download_description_size) != 0))
				{
#ifdef DEBUG
			printf("2.store_download called from get_download\n");
#endif
					addr = store_download(data, file_header->download_description_size,
											download_block);
					p_download_desc->p_download_description = (char *)addr;
					data += (BYTE_SWAP_WORD(file_header->download_description_size)); 
				}
				p_download_desc->p_memory_block_table = NULL;
				if ((BYTE_SWAP_WORD(file_header->memory_block_table_size) != 0))
				{
#ifdef DEBUG
			printf("3.store_download called from get_download\n");
#endif
					addr = store_download(data, file_header->memory_block_table_size,
											download_block);
					p_download_desc->p_memory_block_table = (t_dsp_memory_block_desc *)addr;
					data += (BYTE_SWAP_WORD(file_header->memory_block_table_size)); 
				}
				p_download_desc->p_segment_table = NULL;
				if ((BYTE_SWAP_WORD(file_header->segment_table_size) != 0))
				{
#ifdef DEBUG
			printf("4.store_download called from get_download\n");
#endif
					addr = store_download(data, file_header->segment_table_size,
											download_block);
					p_download_desc->p_segment_table = (t_dsp_segment_desc *)addr;
					data += (BYTE_SWAP_WORD(file_header->segment_table_size)); 
				}
				p_download_desc->p_symbol_table = NULL;
				if ((BYTE_SWAP_WORD(file_header->symbol_table_size) != 0))
				{
#ifdef DEBUG
			printf("5.store_download called from get_download\n");
#endif
					addr = store_download(data, file_header->symbol_table_size,
											download_block);
					p_download_desc->p_symbol_table = (t_dsp_symbol_desc *)addr;
					data += (BYTE_SWAP_WORD(file_header->symbol_table_size)); 
				}
				p_download_desc->p_data_blocks_dm = NULL;
				if ((BYTE_SWAP_WORD(file_header->total_data_size_dm) != 0))
				{
#ifdef DEBUG
			printf("6.store_download called from get_download\n");
#endif
					addr = store_download(data, file_header->total_data_size_dm,
											download_block);
					p_download_desc->p_data_blocks_dm = (word *)addr;
					data += (BYTE_SWAP_WORD(file_header->total_data_size_dm)); 
				}
				p_download_desc->p_data_blocks_pm = NULL;
				if ((BYTE_SWAP_WORD(file_header->total_data_size_pm) != 0))
				{
#ifdef DEBUG
			printf("7.store_download called from get_download\n");
#endif
					addr = store_download(data, file_header->total_data_size_pm,
											download_block);
					p_download_desc->p_data_blocks_pm = (word *)addr;
					data += (BYTE_SWAP_WORD(file_header->total_data_size_pm)); 
				}

			}

		}

		download_area += ((dword)((word)(BYTE_SWAP_WORD(file_header->header_size)))); 
	 	download_area +=((dword)BYTE_SWAP_WORD((file_header->download_description_size)));
		download_area += ((dword)BYTE_SWAP_WORD((file_header->memory_block_table_size)));
		download_area += ((dword)BYTE_SWAP_WORD((file_header->segment_table_size)));
		download_area += ((dword)BYTE_SWAP_WORD((file_header->symbol_table_size)));
		download_area += ((dword)BYTE_SWAP_WORD((file_header->total_data_size_dm)));
		download_area += ((dword)BYTE_SWAP_WORD((file_header->total_data_size_pm)));


	}
	
	table_count=BYTE_SWAP_DWORD(no_of_downloads);
    /**no_of_tables=table_count;*/ 
    bzero(no_of_tables,sizeof(dword));
    memcpy(no_of_tables,&table_count,sizeof(dword));
	
#ifdef DEBUG
	printf("***0x%x bytes of memory required for %d downloads***\n", length, no_of_downloads);
    printf("BYTE_SWAP_DWORD table_count is:%d\n",table_count);
    printf("      \n");
#endif


	free(usage_mask);

        first_load = TRUE; 
       
	return length;

}


/*----------------------------------------------------------------------
 * store_download()
 *
 * Stores the size bytes of DSP code from data into dynamicaly
 * allocated memory block.
 * Arguments: pointer to data, length, pointer to begining of mem block
 * Returns the address to be put in download table
 *----------------------------------------------------------------------*/

dword store_download(char *data, word size, char *store)
{
	word real_size;
	static char* position;
	static char* initial;
	static dword addr;
	dword data_start_addr;
	dword align;

#ifdef DEBUG
	printf("Writing Data to memory block\n");
#endif

		
		if(first_load)
		{
		addr = download_pos;
		position = initial = (char *)store;
   
   		first_load = FALSE;
		}
  	
/*Starting address to where the data is written in the download_block*/    
    data_start_addr = addr;

	real_size = BYTE_SWAP_WORD(size);

	align = ((addr + (real_size + ~ALIGNMENT_MASK)) & ALIGNMENT_MASK) - 
			(addr + real_size);

	memcpy(position, data, real_size);

	position += real_size;
	addr += real_size;

	bzero(position, align);

	position += align;
	addr += align;

	total_bytes_in_download = position - initial;

#ifdef DEBUG
	printf("total_bytes written so far is 0x%x\n",total_bytes_in_download);
    printf("align value for this download is: %d\n",align);
#endif

/* We return (data_start_addr) because we want to point to start of data
   However for next write to download_block the starting postion addr is saved*/

	  return BYTE_SWAP_DWORD(data_start_addr);
	/*return BYTE_SWAP_DWORD(addr);*/
}

/*-------------------------------------------------------------------------
 * set_alignment_mask()
 *
 * Sets the alignment mask for the specified card type. This
 * allows us to allign the data in the download block correctly
 * Arguments: A int representing the card type
 * Returns TRUE if the card is supported, otherwise returns FALSE.
 *------------------------------------------------------------------------*/
int set_alignment_mask(int card_type)
{
	int ret;
	
	switch(card_type)
	{

		case CARDTYPE_MAESTRA_PCI:
        case CARDTYPE_DIVASRV_P_9M_PCI:
		case CARDTYPE_DIVASRV_Q_8M_PCI:
			ALIGNMENT_MASK = ALIGNMENT_MASK_MAESTRA;
			ret = TRUE;
			break;

		default:
			printf("Card not supported\n");
			ret = FALSE;
			break;
	}

	return ret;
}


/*-----------------------------------------------------------------------
 * set_download_position()
 * 
 * Sets the address to where the DSP code goes on the card
 * Arguments: Card number
 * Returns TRUE if card is supported
 *----------------------------------------------------------------------*/

int set_download_pos(int card_type, word wFeatures)
{
	int ret;
	
	switch(card_type)
	{

		case CARDTYPE_MAESTRA_PCI:
			if (wFeatures &  0x8)
			{
				download_pos = V90D_DSP_CODE_BASE;
			}
			else
			{
				download_pos = ORG_DSP_CODE_BASE;
			}

			download_pos += (((sizeof(dword) +
				sizeof(p_download_table)) + 3) 
				& 0xFFFFFFFC);
			ret = TRUE;
			break;

		case CARDTYPE_DIVASRV_P_9M_PCI:
		download_pos = MP_DSP_CODE_BASE	+ (((sizeof(dword) 
												+ sizeof(p_download_table)) 
												+ ~ALIGNMENT_MASK_MAESTRA) 
												& ALIGNMENT_MASK_MAESTRA);

            ret = TRUE;
            break;
												 

		case CARDTYPE_DIVASRV_Q_8M_PCI:
		if (wFeatures &  PROTCAP_V90D)
		{
			download_pos = MQ_V90D_DSP_CODE_BASE;
		}
		else
		{
			download_pos = MQ_ORG_DSP_CODE_BASE;
		}
		download_pos += (((sizeof(dword) +
			sizeof(p_download_table)) + 3) 
			& 0xFFFFFFFC);
		ret = TRUE;
		break;

		default:
			printf("Card not supported\n");
			ret = FALSE;
			break;
	}

	return ret;
}


/*-----------------------------------------------------------------------------
 * download()
 *
 * Does an IOCTL to download size bytes from block with code 
 * type set to code
 *
 * Arguments: Pointer to data, length of data , code type
 * Returns TRUE on success, other wise returns FALSE
 *----------------------------------------------------------------------------*/

int download(char *block, dword size, int code)
{
	dia_load_t load;
	int fd;

#ifdef DEBUG
	printf("Downloading to Card 0x%x bytes\n", size);
#endif

    load.card_id = card_id;

    /* open the Divas device */
	if ((fd = open(DIVAS_DEVICE_DFS, O_RDONLY, 0)) < 0)
	if ((fd = open(DIVAS_DEVICE, O_RDONLY, 0)) == -1)
	{
		perror("Error opening DIVA Server device");
		return(FALSE);
	}

	load.code_type = code;

	load.code = (unsigned char *)block;

	load.length = size;

    if((ioctl(fd, DIA_IOCTL_LOAD, &load)) == -1)
    {
		perror("IOCTL error on DIVA Servers");
        (void)close(fd);
        return FALSE;
    }

	(void)close(fd);

	return TRUE;
}
