📄 dsp_spos_scb_lib.c
字号:
/* * * 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 <sound/core.h>#include <sound/control.h>#include <sound/info.h>#include <sound/cs46xx.h>#include "cs46xx_lib.h"#include "dsp_spos.h"typedef struct _proc_scb_info_t { dsp_scb_descriptor_t * scb_desc; cs46xx_t *chip;} proc_scb_info_t;static void remove_symbol (cs46xx_t * chip,symbol_entry_t * symbol){ dsp_spos_instance_t * ins = chip->dsp_spos_instance; int symbol_index = (int)(symbol - ins->symbol_table.symbols); snd_assert(ins->symbol_table.nsymbols > 0,return); snd_assert(symbol_index >= 0 && symbol_index < ins->symbol_table.nsymbols, return); ins->symbol_table.symbols[symbol_index].deleted = 1; if (symbol_index < ins->symbol_table.highest_frag_index) { ins->symbol_table.highest_frag_index = symbol_index; } if (symbol_index == ins->symbol_table.nsymbols - 1) ins->symbol_table.nsymbols --; if (ins->symbol_table.highest_frag_index > ins->symbol_table.nsymbols) { ins->symbol_table.highest_frag_index = ins->symbol_table.nsymbols; }}static void cs46xx_dsp_proc_scb_info_read (snd_info_entry_t *entry, snd_info_buffer_t * buffer){ proc_scb_info_t * scb_info = (proc_scb_info_t *)entry->private_data; dsp_scb_descriptor_t * scb = scb_info->scb_desc; dsp_spos_instance_t * ins; cs46xx_t *chip = scb_info->chip; int j,col; void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET; ins = chip->dsp_spos_instance; down(&chip->spos_mutex); snd_iprintf(buffer,"%04x %s:\n",scb->address,scb->scb_name); for (col = 0,j = 0;j < 0x10; j++,col++) { if (col == 4) { snd_iprintf(buffer,"\n"); col = 0; } snd_iprintf(buffer,"%08x ",readl(dst + (scb->address + j) * sizeof(u32))); } snd_iprintf(buffer,"\n"); if (scb->parent_scb_ptr != NULL) { snd_iprintf(buffer,"parent [%s:%04x] ", scb->parent_scb_ptr->scb_name, scb->parent_scb_ptr->address); } else snd_iprintf(buffer,"parent [none] "); snd_iprintf(buffer,"sub_list_ptr [%s:%04x]\nnext_scb_ptr [%s:%04x] task_entry [%s:%04x]\n", scb->sub_list_ptr->scb_name, scb->sub_list_ptr->address, scb->next_scb_ptr->scb_name, scb->next_scb_ptr->address, scb->task_entry->symbol_name, scb->task_entry->address); snd_iprintf(buffer,"index [%d] ref_count [%d]\n",scb->index,scb->ref_count); up(&chip->spos_mutex);}static void _dsp_unlink_scb (cs46xx_t *chip,dsp_scb_descriptor_t * scb){ dsp_spos_instance_t * ins = chip->dsp_spos_instance; unsigned long flags; if ( scb->parent_scb_ptr ) { /* unlink parent SCB */ snd_assert ((scb->parent_scb_ptr->sub_list_ptr == scb || scb->parent_scb_ptr->next_scb_ptr == scb),return); if (scb->parent_scb_ptr->sub_list_ptr == scb) { if (scb->next_scb_ptr == ins->the_null_scb) { /* last and only node in parent sublist */ scb->parent_scb_ptr->sub_list_ptr = scb->sub_list_ptr; if (scb->sub_list_ptr != ins->the_null_scb) { scb->sub_list_ptr->parent_scb_ptr = scb->parent_scb_ptr; } scb->sub_list_ptr = ins->the_null_scb; } else { /* first node in parent sublist */ scb->parent_scb_ptr->sub_list_ptr = scb->next_scb_ptr; if (scb->next_scb_ptr != ins->the_null_scb) { /* update next node parent ptr. */ scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr; } scb->next_scb_ptr = ins->the_null_scb; } } else { /* snd_assert ( (scb->sub_list_ptr == ins->the_null_scb), return); */ scb->parent_scb_ptr->next_scb_ptr = scb->next_scb_ptr; if (scb->next_scb_ptr != ins->the_null_scb) { /* update next node parent ptr. */ scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr; } scb->next_scb_ptr = ins->the_null_scb; } spin_lock_irqsave(&chip->reg_lock, flags); /* update parent first entry in DSP RAM */ cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr); /* then update entry in DSP RAM */ cs46xx_dsp_spos_update_scb(chip,scb); scb->parent_scb_ptr = NULL; spin_unlock_irqrestore(&chip->reg_lock, flags); }}static void _dsp_clear_sample_buffer (cs46xx_t *chip, u32 sample_buffer_addr, int dword_count) { void __iomem *dst = chip->region.idx[2].remap_addr + sample_buffer_addr; int i; for (i = 0; i < dword_count ; ++i ) { writel(0, dst); dst += 4; } }void cs46xx_dsp_remove_scb (cs46xx_t *chip, dsp_scb_descriptor_t * scb){ dsp_spos_instance_t * ins = chip->dsp_spos_instance; /* check integrety */ snd_assert ( (scb->index >= 0 && scb->index < ins->nscb && (ins->scbs + scb->index) == scb), return );#if 0 /* can't remove a SCB with childs before removing childs first */ snd_assert ( (scb->sub_list_ptr == ins->the_null_scb && scb->next_scb_ptr == ins->the_null_scb), goto _end);#endif spin_lock(&scb->lock); _dsp_unlink_scb (chip,scb); spin_unlock(&scb->lock); cs46xx_dsp_proc_free_scb_desc(scb); snd_assert (scb->scb_symbol != NULL, return ); remove_symbol (chip,scb->scb_symbol); ins->scbs[scb->index].deleted = 1; if (scb->index < ins->scb_highest_frag_index) ins->scb_highest_frag_index = scb->index; if (scb->index == ins->nscb - 1) { ins->nscb --; } if (ins->scb_highest_frag_index > ins->nscb) { ins->scb_highest_frag_index = ins->nscb; }#if 0 /* !!!! THIS IS A PIECE OF SHIT MADE BY ME !!! */ for(i = scb->index + 1;i < ins->nscb; ++i) { ins->scbs[i - 1].index = i - 1; }#endif}void cs46xx_dsp_proc_free_scb_desc (dsp_scb_descriptor_t * scb){ if (scb->proc_info) { proc_scb_info_t * scb_info = (proc_scb_info_t *)scb->proc_info->private_data; snd_printdd("cs46xx_dsp_proc_free_scb_desc: freeing %s\n",scb->scb_name); snd_info_unregister(scb->proc_info); scb->proc_info = NULL; snd_assert (scb_info != NULL, return); kfree (scb_info); }}void cs46xx_dsp_proc_register_scb_desc (cs46xx_t *chip,dsp_scb_descriptor_t * scb){ dsp_spos_instance_t * ins = chip->dsp_spos_instance; snd_info_entry_t * entry; proc_scb_info_t * scb_info; /* register to proc */ if (ins->snd_card != NULL && ins->proc_dsp_dir != NULL && scb->proc_info == NULL) { if ((entry = snd_info_create_card_entry(ins->snd_card, scb->scb_name, ins->proc_dsp_dir)) != NULL) { scb_info = kmalloc(sizeof(proc_scb_info_t), GFP_KERNEL); if (!scb_info) { snd_info_free_entry(entry); entry = NULL; goto out; } scb_info->chip = chip; scb_info->scb_desc = scb; entry->content = SNDRV_INFO_CONTENT_TEXT; entry->private_data = scb_info; entry->mode = S_IFREG | S_IRUGO | S_IWUSR; entry->c.text.read_size = 512; entry->c.text.read = cs46xx_dsp_proc_scb_info_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); kfree (scb_info); entry = NULL; } }out: scb->proc_info = entry; }}static dsp_scb_descriptor_t * _dsp_create_generic_scb (cs46xx_t *chip,char * name, u32 * scb_data,u32 dest, symbol_entry_t * task_entry, dsp_scb_descriptor_t * parent_scb, int scb_child_type){ dsp_spos_instance_t * ins = chip->dsp_spos_instance; dsp_scb_descriptor_t * scb; unsigned long flags; snd_assert (ins->the_null_scb != NULL,return NULL); /* fill the data that will be wroten to DSP */ scb_data[SCBsubListPtr] = (ins->the_null_scb->address << 0x10) | ins->the_null_scb->address; scb_data[SCBfuncEntryPtr] &= 0xFFFF0000; scb_data[SCBfuncEntryPtr] |= task_entry->address; snd_printdd("dsp_spos: creating SCB <%s>\n",name); scb = cs46xx_dsp_create_scb(chip,name,scb_data,dest); scb->sub_list_ptr = ins->the_null_scb; scb->next_scb_ptr = ins->the_null_scb; scb->parent_scb_ptr = parent_scb; scb->task_entry = task_entry; /* update parent SCB */ if (scb->parent_scb_ptr) {#if 0 printk ("scb->parent_scb_ptr = %s\n",scb->parent_scb_ptr->scb_name); printk ("scb->parent_scb_ptr->next_scb_ptr = %s\n",scb->parent_scb_ptr->next_scb_ptr->scb_name); printk ("scb->parent_scb_ptr->sub_list_ptr = %s\n",scb->parent_scb_ptr->sub_list_ptr->scb_name);#endif /* link to parent SCB */ if (scb_child_type == SCB_ON_PARENT_NEXT_SCB) { snd_assert ( (scb->parent_scb_ptr->next_scb_ptr == ins->the_null_scb), return NULL); scb->parent_scb_ptr->next_scb_ptr = scb; } else if (scb_child_type == SCB_ON_PARENT_SUBLIST_SCB) { snd_assert ( (scb->parent_scb_ptr->sub_list_ptr == ins->the_null_scb), return NULL); scb->parent_scb_ptr->sub_list_ptr = scb; } else { snd_assert (0,return NULL); } spin_lock_irqsave(&chip->reg_lock, flags); /* update entry in DSP RAM */ cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr); spin_unlock_irqrestore(&chip->reg_lock, flags); } cs46xx_dsp_proc_register_scb_desc (chip,scb); return scb;}static dsp_scb_descriptor_t * cs46xx_dsp_create_generic_scb (cs46xx_t *chip,char * name, u32 * scb_data,u32 dest, char * task_entry_name, dsp_scb_descriptor_t * parent_scb, int scb_child_type){ symbol_entry_t * task_entry; task_entry = cs46xx_dsp_lookup_symbol (chip,task_entry_name, SYMBOL_CODE); if (task_entry == NULL) { snd_printk (KERN_ERR "dsp_spos: symbol %s not found\n",task_entry_name); return NULL; } return _dsp_create_generic_scb (chip,name,scb_data,dest,task_entry, parent_scb,scb_child_type);}dsp_scb_descriptor_t * cs46xx_dsp_create_timing_master_scb (cs46xx_t *chip){ dsp_scb_descriptor_t * scb; timing_master_scb_t timing_master_scb = { { 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, 0,0, 0,NULL_SCB_ADDR, 0,0, /* extraSampleAccum:TMreserved */ 0,0, /* codecFIFOptr:codecFIFOsyncd */ 0x0001,0x8000, /* fracSampAccumQm1:TMfrmsLeftInGroup */ 0x0001,0x0000, /* fracSampCorrectionQm1:TMfrmGroupLength */ 0x00060000 /* nSampPerFrmQ15 */ }; scb = cs46xx_dsp_create_generic_scb(chip,"TimingMasterSCBInst",(u32 *)&timing_master_scb, TIMINGMASTER_SCB_ADDR, "TIMINGMASTER",NULL,SCB_NO_PARENT); return scb;}dsp_scb_descriptor_t * cs46xx_dsp_create_codec_out_scb(cs46xx_t * chip,char * codec_name, u16 channel_disp,u16 fifo_addr, u16 child_scb_addr, u32 dest,dsp_scb_descriptor_t * parent_scb, int scb_child_type){ dsp_scb_descriptor_t * scb; codec_output_scb_t codec_out_scb = { { 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 }, 0,0, 0,NULL_SCB_ADDR, 0, /* COstrmRsConfig */ 0, /* COstrmBufPtr */ channel_disp,fifo_addr, /* leftChanBaseIOaddr:rightChanIOdisp */ 0x0000,0x0080, /* (!AC97!) COexpVolChangeRate:COscaleShiftCount */ 0,child_scb_addr /* COreserved - need child scb to work with rom code */ }; scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_out_scb, dest,"S16_CODECOUTPUTTASK",parent_scb, scb_child_type); return scb;}dsp_scb_descriptor_t *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -