isdn4k-utils/eicon/divautil/lindownload.c

865 lines
23 KiB
C

/*
*
* 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);
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; 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;
}