⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dsp_spos.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
/* *   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 * *//* * 2002-07 Benny Sjostrand benny@hostmobility.com */#include <sound/driver.h>#include <asm/io.h>#include <linux/delay.h>#include <linux/pci.h>#include <linux/pm.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <sound/core.h>#include <sound/control.h>#include <sound/info.h>#include <sound/asoundef.h>#include <sound/cs46xx.h>#include "cs46xx_lib.h"#include "dsp_spos.h"static int cs46xx_dsp_async_init (cs46xx_t *chip, dsp_scb_descriptor_t * fg_entry);static wide_opcode_t wide_opcodes[] = { 	WIDE_FOR_BEGIN_LOOP,	WIDE_FOR_BEGIN_LOOP2,	WIDE_COND_GOTO_ADDR,	WIDE_COND_GOTO_CALL,	WIDE_TBEQ_COND_GOTO_ADDR,	WIDE_TBEQ_COND_CALL_ADDR,	WIDE_TBEQ_NCOND_GOTO_ADDR,	WIDE_TBEQ_NCOND_CALL_ADDR,	WIDE_TBEQ_COND_GOTO1_ADDR,	WIDE_TBEQ_COND_CALL1_ADDR,	WIDE_TBEQ_NCOND_GOTOI_ADDR,	WIDE_TBEQ_NCOND_CALL1_ADDR};static int shadow_and_reallocate_code (cs46xx_t * chip,u32 * data,u32 size, u32 overlay_begin_address){	unsigned int i = 0, j, nreallocated = 0;	u32 hival,loval,address;	u32 mop_operands,mop_type,wide_op;	dsp_spos_instance_t * ins = chip->dsp_spos_instance;	snd_assert( ((size % 2) == 0), return -EINVAL);  	while (i < size) {		loval = data[i++];		hival = data[i++];		if (ins->code.offset > 0) {			mop_operands = (hival >> 6) & 0x03fff;			mop_type = mop_operands >> 10;      			/* check for wide type instruction */			if (mop_type == 0 &&			    (mop_operands & WIDE_LADD_INSTR_MASK) == 0 &&			    (mop_operands & WIDE_INSTR_MASK) != 0) {				wide_op = loval & 0x7f;				for (j = 0;j < ARRAY_SIZE(wide_opcodes); ++j) {					if (wide_opcodes[j] == wide_op) {						/* need to reallocate instruction */						address  = (hival & 0x00FFF) << 5;						address |=  loval >> 15;            						snd_printdd("handle_wideop[1]: %05x:%05x addr %04x\n",hival,loval,address);            						if ( !(address & 0x8000) ) {							address += (ins->code.offset / 2) - overlay_begin_address;						} else {							snd_printdd("handle_wideop[1]: ROM symbol not reallocated\n");						}            						hival &= 0xFF000;						loval &= 0x07FFF;            						hival |= ( (address >> 5)  & 0x00FFF);						loval |= ( (address << 15) & 0xF8000);            						address  = (hival & 0x00FFF) << 5;						address |=  loval >> 15;            						snd_printdd("handle_wideop:[2] %05x:%05x addr %04x\n",hival,loval,address);            						nreallocated ++;					} /* wide_opcodes[j] == wide_op */				} /* for */			} /* mod_type == 0 ... */		} /* ins->code.offset > 0 */		ins->code.data[ins->code.size++] = loval;		ins->code.data[ins->code.size++] = hival;	}	snd_printdd("dsp_spos: %d instructions reallocated\n",nreallocated);	return nreallocated;}static segment_desc_t * get_segment_desc (dsp_module_desc_t * module, int seg_type){	int i;	for (i = 0;i < module->nsegments; ++i) {		if (module->segments[i].segment_type == seg_type) {			return (module->segments + i);		}	}	return NULL;};static int find_free_symbol_index (dsp_spos_instance_t * ins){	int index = ins->symbol_table.nsymbols,i;	for (i = ins->symbol_table.highest_frag_index; i < ins->symbol_table.nsymbols; ++i) {		if (ins->symbol_table.symbols[i].deleted) {			index = i;			break;		}	}	return index;}static int add_symbols (cs46xx_t * chip, dsp_module_desc_t * module){	int i;	dsp_spos_instance_t * ins = chip->dsp_spos_instance;	if (module->symbol_table.nsymbols > 0) {		if (!strcmp(module->symbol_table.symbols[0].symbol_name, "OVERLAYBEGINADDRESS") &&		    module->symbol_table.symbols[0].symbol_type == SYMBOL_CONSTANT ) {			module->overlay_begin_address = module->symbol_table.symbols[0].address;		}	}	for (i = 0;i < module->symbol_table.nsymbols; ++i) {		if (ins->symbol_table.nsymbols == (DSP_MAX_SYMBOLS - 1)) {			snd_printk(KERN_ERR "dsp_spos: symbol table is full\n");			return -ENOMEM;		}		if (cs46xx_dsp_lookup_symbol(chip,					     module->symbol_table.symbols[i].symbol_name,					     module->symbol_table.symbols[i].symbol_type) == NULL) {			ins->symbol_table.symbols[ins->symbol_table.nsymbols] = module->symbol_table.symbols[i];			ins->symbol_table.symbols[ins->symbol_table.nsymbols].address += ((ins->code.offset / 2) - module->overlay_begin_address);			ins->symbol_table.symbols[ins->symbol_table.nsymbols].module = module;			ins->symbol_table.symbols[ins->symbol_table.nsymbols].deleted = 0;			if (ins->symbol_table.nsymbols > ins->symbol_table.highest_frag_index) 				ins->symbol_table.highest_frag_index = ins->symbol_table.nsymbols;			ins->symbol_table.nsymbols++;		} else {          /* if (0) printk ("dsp_spos: symbol <%s> duplicated, probably nothing wrong with that (Cirrus?)\n",                             module->symbol_table.symbols[i].symbol_name); */		}	}	return 0;}static symbol_entry_t * add_symbol (cs46xx_t * chip, char * symbol_name, u32 address, int type){	dsp_spos_instance_t * ins = chip->dsp_spos_instance;	symbol_entry_t * symbol = NULL;	int index;	if (ins->symbol_table.nsymbols == (DSP_MAX_SYMBOLS - 1)) {		snd_printk(KERN_ERR "dsp_spos: symbol table is full\n");		return NULL;	}  	if (cs46xx_dsp_lookup_symbol(chip,				     symbol_name,				     type) != NULL) {		snd_printk(KERN_ERR "dsp_spos: symbol <%s> duplicated\n", symbol_name);		return NULL;	}	index = find_free_symbol_index (ins);	strcpy (ins->symbol_table.symbols[index].symbol_name, symbol_name);	ins->symbol_table.symbols[index].address = address;	ins->symbol_table.symbols[index].symbol_type = type;	ins->symbol_table.symbols[index].module = NULL;	ins->symbol_table.symbols[index].deleted = 0;	symbol = (ins->symbol_table.symbols + index);	if (index > ins->symbol_table.highest_frag_index) 		ins->symbol_table.highest_frag_index = index;	if (index == ins->symbol_table.nsymbols)		ins->symbol_table.nsymbols++; /* no frag. in list */	return symbol;}dsp_spos_instance_t *  cs46xx_dsp_spos_create (cs46xx_t * chip){	dsp_spos_instance_t * ins = kmalloc(sizeof(dsp_spos_instance_t), GFP_KERNEL);	if (ins == NULL) 		return NULL;	memset(ins, 0, sizeof(*ins));	/* better to use vmalloc for this big table */	ins->symbol_table.nsymbols = 0;	ins->symbol_table.symbols = vmalloc(sizeof(symbol_entry_t) * DSP_MAX_SYMBOLS);	ins->symbol_table.highest_frag_index = 0;	if (ins->symbol_table.symbols == NULL) {		cs46xx_dsp_spos_destroy(chip);		return NULL;	}	ins->code.offset = 0;	ins->code.size = 0;	ins->code.data = kmalloc(DSP_CODE_BYTE_SIZE, GFP_KERNEL);	if (ins->code.data == NULL) {		cs46xx_dsp_spos_destroy(chip);		return NULL;	}	ins->nscb = 0;	ins->ntask = 0;	ins->nmodules = 0;	ins->modules = kmalloc(sizeof(dsp_module_desc_t) * DSP_MAX_MODULES, GFP_KERNEL);	if (ins->modules == NULL) {		cs46xx_dsp_spos_destroy(chip);		return NULL;	}	/* default SPDIF input sample rate	   to 48000 khz */	ins->spdif_in_sample_rate = 48000;	/* maximize volume */	ins->dac_volume_right = 0x8000;	ins->dac_volume_left = 0x8000;	ins->spdif_input_volume_right = 0x8000;	ins->spdif_input_volume_left = 0x8000;	/* set left and right validity bits and	   default channel status */	ins->spdif_csuv_default = 		ins->spdif_csuv_stream =  	 /* byte 0 */  ((unsigned int)_wrap_all_bits(  (SNDRV_PCM_DEFAULT_CON_SPDIF        & 0xff)) << 24) |	 /* byte 1 */  ((unsigned int)_wrap_all_bits( ((SNDRV_PCM_DEFAULT_CON_SPDIF >> 8) & 0xff)) << 16) |	 /* byte 3 */   (unsigned int)_wrap_all_bits(  (SNDRV_PCM_DEFAULT_CON_SPDIF >> 24) & 0xff) |	 /* left and right validity bits */ (1 << 13) | (1 << 12);	return ins;}void  cs46xx_dsp_spos_destroy (cs46xx_t * chip){	int i;	dsp_spos_instance_t * ins = chip->dsp_spos_instance;	snd_assert(ins != NULL, return);	down(&chip->spos_mutex);	for (i = 0; i < ins->nscb; ++i) {		if (ins->scbs[i].deleted) continue;		cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) );	}	kfree(ins->code.data);	vfree(ins->symbol_table.symbols);	kfree(ins->modules);	kfree(ins);	up(&chip->spos_mutex);}int cs46xx_dsp_load_module (cs46xx_t * chip, dsp_module_desc_t * module){	dsp_spos_instance_t * ins = chip->dsp_spos_instance;	segment_desc_t * code = get_segment_desc (module,SEGTYPE_SP_PROGRAM);	segment_desc_t * parameter = get_segment_desc (module,SEGTYPE_SP_PARAMETER);	segment_desc_t * sample = get_segment_desc (module,SEGTYPE_SP_SAMPLE);	u32 doffset, dsize;	if (ins->nmodules == DSP_MAX_MODULES - 1) {		snd_printk(KERN_ERR "dsp_spos: to many modules loaded into DSP\n");		return -ENOMEM;	}	snd_printdd("dsp_spos: loading module %s into DSP\n", module->module_name);  	if (ins->nmodules == 0) {		snd_printdd("dsp_spos: clearing parameter area\n");		snd_cs46xx_clear_BA1(chip, DSP_PARAMETER_BYTE_OFFSET, DSP_PARAMETER_BYTE_SIZE);	}  	if (parameter == NULL) {		snd_printdd("dsp_spos: module got no parameter segment\n");	} else {		if (ins->nmodules > 0) {			snd_printk(KERN_WARNING "dsp_spos: WARNING current parameter data may be overwriten!\n");		}		doffset = (parameter->offset * 4 + DSP_PARAMETER_BYTE_OFFSET);		dsize   = parameter->size * 4;		snd_printdd("dsp_spos: downloading parameter data to chip (%08x-%08x)\n",			    doffset,doffset + dsize);		if (snd_cs46xx_download (chip, parameter->data, doffset, dsize)) {			snd_printk(KERN_ERR "dsp_spos: failed to download parameter data to DSP\n");			return -EINVAL;		}	}	if (ins->nmodules == 0) {		snd_printdd("dsp_spos: clearing sample area\n");		snd_cs46xx_clear_BA1(chip, DSP_SAMPLE_BYTE_OFFSET, DSP_SAMPLE_BYTE_SIZE);	}	if (sample == NULL) {		snd_printdd("dsp_spos: module got no sample segment\n");	} else {		if (ins->nmodules > 0) {			snd_printk(KERN_WARNING "dsp_spos: WARNING current sample data may be overwriten\n");		}		doffset = (sample->offset * 4  + DSP_SAMPLE_BYTE_OFFSET);		dsize   =  sample->size * 4;		snd_printdd("dsp_spos: downloading sample data to chip (%08x-%08x)\n",			    doffset,doffset + dsize);		if (snd_cs46xx_download (chip,sample->data,doffset,dsize)) {			snd_printk(KERN_ERR "dsp_spos: failed to sample data to DSP\n");			return -EINVAL;		}	}	if (ins->nmodules == 0) {		snd_printdd("dsp_spos: clearing code area\n");		snd_cs46xx_clear_BA1(chip, DSP_CODE_BYTE_OFFSET, DSP_CODE_BYTE_SIZE);	}	if (code == NULL) {		snd_printdd("dsp_spos: module got no code segment\n");	} else {		if (ins->code.offset + code->size > DSP_CODE_BYTE_SIZE) {			snd_printk(KERN_ERR "dsp_spos: no space available in DSP\n");			return -ENOMEM;		}		module->load_address = ins->code.offset;		module->overlay_begin_address = 0x000;		/* if module has a code segment it must have		   symbol table */		snd_assert(module->symbol_table.symbols != NULL ,return -ENOMEM);		if (add_symbols(chip,module)) {			snd_printk(KERN_ERR "dsp_spos: failed to load symbol table\n");			return -ENOMEM;		}    		doffset = (code->offset * 4 + ins->code.offset * 4 + DSP_CODE_BYTE_OFFSET);		dsize   = code->size * 4;		snd_printdd("dsp_spos: downloading code to chip (%08x-%08x)\n",			    doffset,doffset + dsize);   		module->nfixups = shadow_and_reallocate_code(chip,code->data,code->size,module->overlay_begin_address);		if (snd_cs46xx_download (chip,(ins->code.data + ins->code.offset),doffset,dsize)) {			snd_printk(KERN_ERR "dsp_spos: failed to download code to DSP\n");			return -EINVAL;		}		ins->code.offset += code->size;	}	/* NOTE: module segments and symbol table must be	   statically allocated. Case that module data is	   not generated by the ospparser */	ins->modules[ins->nmodules] = *module;	ins->nmodules++;	return 0;}symbol_entry_t * cs46xx_dsp_lookup_symbol (cs46xx_t * chip, char * symbol_name, int symbol_type){	int i;	dsp_spos_instance_t * ins = chip->dsp_spos_instance;	for ( i = 0; i < ins->symbol_table.nsymbols; ++i ) {		if (ins->symbol_table.symbols[i].deleted)			continue;		if (!strcmp(ins->symbol_table.symbols[i].symbol_name,symbol_name) &&		    ins->symbol_table.symbols[i].symbol_type == symbol_type) {			return (ins->symbol_table.symbols + i);		}	}#if 0	printk ("dsp_spos: symbol <%s> type %02x not found\n",		symbol_name,symbol_type);#endif	return NULL;}static symbol_entry_t * cs46xx_dsp_lookup_symbol_addr (cs46xx_t * chip, u32 address, int symbol_type){	int i;	dsp_spos_instance_t * ins = chip->dsp_spos_instance;	for ( i = 0; i < ins->symbol_table.nsymbols; ++i ) {		if (ins->symbol_table.symbols[i].deleted)			continue;		if (ins->symbol_table.symbols[i].address == address &&		    ins->symbol_table.symbols[i].symbol_type == symbol_type) {			return (ins->symbol_table.symbols + i);		}	}	return NULL;}static void cs46xx_dsp_proc_symbol_table_read (snd_info_entry_t *entry, snd_info_buffer_t * buffer){	cs46xx_t *chip = entry->private_data;	dsp_spos_instance_t * ins = chip->dsp_spos_instance;	int i;	snd_iprintf(buffer, "SYMBOLS:\n");	for ( i = 0; i < ins->symbol_table.nsymbols; ++i ) {		char *module_str = "system";		if (ins->symbol_table.symbols[i].deleted)			continue;		if (ins->symbol_table.symbols[i].module != NULL) {			module_str = ins->symbol_table.symbols[i].module->module_name;		}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -