/* * * 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 #include #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 #include /* for file info */ #include #include #include /* For dynamic memory allocation */ #include /* For memcpy stuff */ #include /* 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); extern char* selected_protocol_code_directory; extern int selected_bri_code_version; /*-------------------------------------------------------------------------- * 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 bri_card) { 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; char COMBIFILE[1024]; strcpy (COMBIFILE, selected_protocol_code_directory); strcat (COMBIFILE, "dspdload.bin"); if ((bri_card == 1) && (selected_bri_code_version)) { strcpy (COMBIFILE, selected_protocol_code_directory); strcat (COMBIFILE, "dspdload.s6"); } //printf ("I: DSP FILE:<%s>\n", COMBIFILE); #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; iformat_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; }