162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci */
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci/*
662306a36Sopenharmony_ci * 2002-07 Benny Sjostrand benny@hostmobility.com
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/io.h>
1162306a36Sopenharmony_ci#include <linux/delay.h>
1262306a36Sopenharmony_ci#include <linux/pm.h>
1362306a36Sopenharmony_ci#include <linux/init.h>
1462306a36Sopenharmony_ci#include <linux/slab.h>
1562306a36Sopenharmony_ci#include <linux/mutex.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <sound/core.h>
1862306a36Sopenharmony_ci#include <sound/control.h>
1962306a36Sopenharmony_ci#include <sound/info.h>
2062306a36Sopenharmony_ci#include "cs46xx.h"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include "cs46xx_lib.h"
2362306a36Sopenharmony_ci#include "dsp_spos.h"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistruct proc_scb_info {
2662306a36Sopenharmony_ci	struct dsp_scb_descriptor * scb_desc;
2762306a36Sopenharmony_ci	struct snd_cs46xx *chip;
2862306a36Sopenharmony_ci};
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic void remove_symbol (struct snd_cs46xx * chip, struct dsp_symbol_entry * symbol)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
3362306a36Sopenharmony_ci	int symbol_index = (int)(symbol - ins->symbol_table.symbols);
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	if (snd_BUG_ON(ins->symbol_table.nsymbols <= 0))
3662306a36Sopenharmony_ci		return;
3762306a36Sopenharmony_ci	if (snd_BUG_ON(symbol_index < 0 ||
3862306a36Sopenharmony_ci		       symbol_index >= ins->symbol_table.nsymbols))
3962306a36Sopenharmony_ci		return;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	ins->symbol_table.symbols[symbol_index].deleted = 1;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	if (symbol_index < ins->symbol_table.highest_frag_index) {
4462306a36Sopenharmony_ci		ins->symbol_table.highest_frag_index = symbol_index;
4562306a36Sopenharmony_ci	}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	if (symbol_index == ins->symbol_table.nsymbols - 1)
4862306a36Sopenharmony_ci		ins->symbol_table.nsymbols --;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	if (ins->symbol_table.highest_frag_index > ins->symbol_table.nsymbols) {
5162306a36Sopenharmony_ci		ins->symbol_table.highest_frag_index = ins->symbol_table.nsymbols;
5262306a36Sopenharmony_ci	}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci#ifdef CONFIG_SND_PROC_FS
5762306a36Sopenharmony_cistatic void cs46xx_dsp_proc_scb_info_read (struct snd_info_entry *entry,
5862306a36Sopenharmony_ci					   struct snd_info_buffer *buffer)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	struct proc_scb_info * scb_info  = entry->private_data;
6162306a36Sopenharmony_ci	struct dsp_scb_descriptor * scb = scb_info->scb_desc;
6262306a36Sopenharmony_ci	struct snd_cs46xx *chip = scb_info->chip;
6362306a36Sopenharmony_ci	int j,col;
6462306a36Sopenharmony_ci	void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	mutex_lock(&chip->spos_mutex);
6762306a36Sopenharmony_ci	snd_iprintf(buffer,"%04x %s:\n",scb->address,scb->scb_name);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	for (col = 0,j = 0;j < 0x10; j++,col++) {
7062306a36Sopenharmony_ci		if (col == 4) {
7162306a36Sopenharmony_ci			snd_iprintf(buffer,"\n");
7262306a36Sopenharmony_ci			col = 0;
7362306a36Sopenharmony_ci		}
7462306a36Sopenharmony_ci		snd_iprintf(buffer,"%08x ",readl(dst + (scb->address + j) * sizeof(u32)));
7562306a36Sopenharmony_ci	}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	snd_iprintf(buffer,"\n");
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	if (scb->parent_scb_ptr != NULL) {
8062306a36Sopenharmony_ci		snd_iprintf(buffer,"parent [%s:%04x] ",
8162306a36Sopenharmony_ci			    scb->parent_scb_ptr->scb_name,
8262306a36Sopenharmony_ci			    scb->parent_scb_ptr->address);
8362306a36Sopenharmony_ci	} else snd_iprintf(buffer,"parent [none] ");
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	snd_iprintf(buffer,"sub_list_ptr [%s:%04x]\nnext_scb_ptr [%s:%04x]  task_entry [%s:%04x]\n",
8662306a36Sopenharmony_ci		    scb->sub_list_ptr->scb_name,
8762306a36Sopenharmony_ci		    scb->sub_list_ptr->address,
8862306a36Sopenharmony_ci		    scb->next_scb_ptr->scb_name,
8962306a36Sopenharmony_ci		    scb->next_scb_ptr->address,
9062306a36Sopenharmony_ci		    scb->task_entry->symbol_name,
9162306a36Sopenharmony_ci		    scb->task_entry->address);
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	snd_iprintf(buffer,"index [%d] ref_count [%d]\n",scb->index,scb->ref_count);
9462306a36Sopenharmony_ci	mutex_unlock(&chip->spos_mutex);
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci#endif
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistatic void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	if ( scb->parent_scb_ptr ) {
10362306a36Sopenharmony_ci		/* unlink parent SCB */
10462306a36Sopenharmony_ci		if (snd_BUG_ON(scb->parent_scb_ptr->sub_list_ptr != scb &&
10562306a36Sopenharmony_ci			       scb->parent_scb_ptr->next_scb_ptr != scb))
10662306a36Sopenharmony_ci			return;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci		if (scb->parent_scb_ptr->sub_list_ptr == scb) {
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci			if (scb->next_scb_ptr == ins->the_null_scb) {
11162306a36Sopenharmony_ci				/* last and only node in parent sublist */
11262306a36Sopenharmony_ci				scb->parent_scb_ptr->sub_list_ptr = scb->sub_list_ptr;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci				if (scb->sub_list_ptr != ins->the_null_scb) {
11562306a36Sopenharmony_ci					scb->sub_list_ptr->parent_scb_ptr = scb->parent_scb_ptr;
11662306a36Sopenharmony_ci				}
11762306a36Sopenharmony_ci				scb->sub_list_ptr = ins->the_null_scb;
11862306a36Sopenharmony_ci			} else {
11962306a36Sopenharmony_ci				/* first node in parent sublist */
12062306a36Sopenharmony_ci				scb->parent_scb_ptr->sub_list_ptr = scb->next_scb_ptr;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci				if (scb->next_scb_ptr != ins->the_null_scb) {
12362306a36Sopenharmony_ci					/* update next node parent ptr. */
12462306a36Sopenharmony_ci					scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
12562306a36Sopenharmony_ci				}
12662306a36Sopenharmony_ci				scb->next_scb_ptr = ins->the_null_scb;
12762306a36Sopenharmony_ci			}
12862306a36Sopenharmony_ci		} else {
12962306a36Sopenharmony_ci			scb->parent_scb_ptr->next_scb_ptr = scb->next_scb_ptr;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci			if (scb->next_scb_ptr != ins->the_null_scb) {
13262306a36Sopenharmony_ci				/* update next node parent ptr. */
13362306a36Sopenharmony_ci				scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
13462306a36Sopenharmony_ci			}
13562306a36Sopenharmony_ci			scb->next_scb_ptr = ins->the_null_scb;
13662306a36Sopenharmony_ci		}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci		/* update parent first entry in DSP RAM */
13962306a36Sopenharmony_ci		cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci		/* then update entry in DSP RAM */
14262306a36Sopenharmony_ci		cs46xx_dsp_spos_update_scb(chip,scb);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci		scb->parent_scb_ptr = NULL;
14562306a36Sopenharmony_ci	}
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic void _dsp_clear_sample_buffer (struct snd_cs46xx *chip, u32 sample_buffer_addr,
14962306a36Sopenharmony_ci				      int dword_count)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	void __iomem *dst = chip->region.idx[2].remap_addr + sample_buffer_addr;
15262306a36Sopenharmony_ci	int i;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	for (i = 0; i < dword_count ; ++i ) {
15562306a36Sopenharmony_ci		writel(0, dst);
15662306a36Sopenharmony_ci		dst += 4;
15762306a36Sopenharmony_ci	}
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_civoid cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
16362306a36Sopenharmony_ci	unsigned long flags;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	/* check integrety */
16662306a36Sopenharmony_ci	if (snd_BUG_ON(scb->index < 0 ||
16762306a36Sopenharmony_ci		       scb->index >= ins->nscb ||
16862306a36Sopenharmony_ci		       (ins->scbs + scb->index) != scb))
16962306a36Sopenharmony_ci		return;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci#if 0
17262306a36Sopenharmony_ci	/* can't remove a SCB with childs before
17362306a36Sopenharmony_ci	   removing childs first  */
17462306a36Sopenharmony_ci	if (snd_BUG_ON(scb->sub_list_ptr != ins->the_null_scb ||
17562306a36Sopenharmony_ci		       scb->next_scb_ptr != ins->the_null_scb))
17662306a36Sopenharmony_ci		goto _end;
17762306a36Sopenharmony_ci#endif
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	spin_lock_irqsave(&chip->reg_lock, flags);
18062306a36Sopenharmony_ci	_dsp_unlink_scb (chip,scb);
18162306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->reg_lock, flags);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	cs46xx_dsp_proc_free_scb_desc(scb);
18462306a36Sopenharmony_ci	if (snd_BUG_ON(!scb->scb_symbol))
18562306a36Sopenharmony_ci		return;
18662306a36Sopenharmony_ci	remove_symbol (chip,scb->scb_symbol);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	ins->scbs[scb->index].deleted = 1;
18962306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
19062306a36Sopenharmony_ci	kfree(ins->scbs[scb->index].data);
19162306a36Sopenharmony_ci	ins->scbs[scb->index].data = NULL;
19262306a36Sopenharmony_ci#endif
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	if (scb->index < ins->scb_highest_frag_index)
19562306a36Sopenharmony_ci		ins->scb_highest_frag_index = scb->index;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	if (scb->index == ins->nscb - 1) {
19862306a36Sopenharmony_ci		ins->nscb --;
19962306a36Sopenharmony_ci	}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	if (ins->scb_highest_frag_index > ins->nscb) {
20262306a36Sopenharmony_ci		ins->scb_highest_frag_index = ins->nscb;
20362306a36Sopenharmony_ci	}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci#if 0
20662306a36Sopenharmony_ci	/* !!!! THIS IS A PIECE OF SHIT MADE BY ME !!! */
20762306a36Sopenharmony_ci	for(i = scb->index + 1;i < ins->nscb; ++i) {
20862306a36Sopenharmony_ci		ins->scbs[i - 1].index = i - 1;
20962306a36Sopenharmony_ci	}
21062306a36Sopenharmony_ci#endif
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci#ifdef CONFIG_SND_PROC_FS
21562306a36Sopenharmony_civoid cs46xx_dsp_proc_free_scb_desc (struct dsp_scb_descriptor * scb)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	if (scb->proc_info) {
21862306a36Sopenharmony_ci		struct proc_scb_info * scb_info = scb->proc_info->private_data;
21962306a36Sopenharmony_ci		struct snd_cs46xx *chip = scb_info->chip;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci		dev_dbg(chip->card->dev,
22262306a36Sopenharmony_ci			"cs46xx_dsp_proc_free_scb_desc: freeing %s\n",
22362306a36Sopenharmony_ci			scb->scb_name);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci		snd_info_free_entry(scb->proc_info);
22662306a36Sopenharmony_ci		scb->proc_info = NULL;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci		kfree (scb_info);
22962306a36Sopenharmony_ci	}
23062306a36Sopenharmony_ci}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_civoid cs46xx_dsp_proc_register_scb_desc (struct snd_cs46xx *chip,
23362306a36Sopenharmony_ci					struct dsp_scb_descriptor * scb)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
23662306a36Sopenharmony_ci	struct snd_info_entry * entry;
23762306a36Sopenharmony_ci	struct proc_scb_info * scb_info;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	/* register to proc */
24062306a36Sopenharmony_ci	if (ins->snd_card != NULL && ins->proc_dsp_dir != NULL &&
24162306a36Sopenharmony_ci	    scb->proc_info == NULL) {
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci		entry = snd_info_create_card_entry(ins->snd_card, scb->scb_name,
24462306a36Sopenharmony_ci						   ins->proc_dsp_dir);
24562306a36Sopenharmony_ci		if (entry) {
24662306a36Sopenharmony_ci			scb_info = kmalloc(sizeof(struct proc_scb_info), GFP_KERNEL);
24762306a36Sopenharmony_ci			if (!scb_info) {
24862306a36Sopenharmony_ci				snd_info_free_entry(entry);
24962306a36Sopenharmony_ci				entry = NULL;
25062306a36Sopenharmony_ci				goto out;
25162306a36Sopenharmony_ci			}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci			scb_info->chip = chip;
25462306a36Sopenharmony_ci			scb_info->scb_desc = scb;
25562306a36Sopenharmony_ci			snd_info_set_text_ops(entry, scb_info,
25662306a36Sopenharmony_ci					      cs46xx_dsp_proc_scb_info_read);
25762306a36Sopenharmony_ci		}
25862306a36Sopenharmony_ciout:
25962306a36Sopenharmony_ci		scb->proc_info = entry;
26062306a36Sopenharmony_ci	}
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci#endif /* CONFIG_SND_PROC_FS */
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_cistatic struct dsp_scb_descriptor *
26562306a36Sopenharmony_ci_dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32 dest,
26662306a36Sopenharmony_ci                         struct dsp_symbol_entry * task_entry,
26762306a36Sopenharmony_ci                         struct dsp_scb_descriptor * parent_scb,
26862306a36Sopenharmony_ci                         int scb_child_type)
26962306a36Sopenharmony_ci{
27062306a36Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
27162306a36Sopenharmony_ci	struct dsp_scb_descriptor * scb;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	unsigned long flags;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	if (snd_BUG_ON(!ins->the_null_scb))
27662306a36Sopenharmony_ci		return NULL;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	/* fill the data that will be wroten to DSP */
27962306a36Sopenharmony_ci	scb_data[SCBsubListPtr] =
28062306a36Sopenharmony_ci		(ins->the_null_scb->address << 0x10) | ins->the_null_scb->address;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	scb_data[SCBfuncEntryPtr] &= 0xFFFF0000;
28362306a36Sopenharmony_ci	scb_data[SCBfuncEntryPtr] |= task_entry->address;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	dev_dbg(chip->card->dev, "dsp_spos: creating SCB <%s>\n", name);
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	scb = cs46xx_dsp_create_scb(chip,name,scb_data,dest);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	scb->sub_list_ptr = ins->the_null_scb;
29162306a36Sopenharmony_ci	scb->next_scb_ptr = ins->the_null_scb;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	scb->parent_scb_ptr = parent_scb;
29462306a36Sopenharmony_ci	scb->task_entry = task_entry;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	/* update parent SCB */
29862306a36Sopenharmony_ci	if (scb->parent_scb_ptr) {
29962306a36Sopenharmony_ci#if 0
30062306a36Sopenharmony_ci		dev_dbg(chip->card->dev,
30162306a36Sopenharmony_ci			"scb->parent_scb_ptr = %s\n",
30262306a36Sopenharmony_ci			scb->parent_scb_ptr->scb_name);
30362306a36Sopenharmony_ci		dev_dbg(chip->card->dev,
30462306a36Sopenharmony_ci			"scb->parent_scb_ptr->next_scb_ptr = %s\n",
30562306a36Sopenharmony_ci			scb->parent_scb_ptr->next_scb_ptr->scb_name);
30662306a36Sopenharmony_ci		dev_dbg(chip->card->dev,
30762306a36Sopenharmony_ci			"scb->parent_scb_ptr->sub_list_ptr = %s\n",
30862306a36Sopenharmony_ci			scb->parent_scb_ptr->sub_list_ptr->scb_name);
30962306a36Sopenharmony_ci#endif
31062306a36Sopenharmony_ci		/* link to  parent SCB */
31162306a36Sopenharmony_ci		if (scb_child_type == SCB_ON_PARENT_NEXT_SCB) {
31262306a36Sopenharmony_ci			if (snd_BUG_ON(scb->parent_scb_ptr->next_scb_ptr !=
31362306a36Sopenharmony_ci				       ins->the_null_scb))
31462306a36Sopenharmony_ci				return NULL;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci			scb->parent_scb_ptr->next_scb_ptr = scb;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci		} else if (scb_child_type == SCB_ON_PARENT_SUBLIST_SCB) {
31962306a36Sopenharmony_ci			if (snd_BUG_ON(scb->parent_scb_ptr->sub_list_ptr !=
32062306a36Sopenharmony_ci				       ins->the_null_scb))
32162306a36Sopenharmony_ci				return NULL;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci			scb->parent_scb_ptr->sub_list_ptr = scb;
32462306a36Sopenharmony_ci		} else {
32562306a36Sopenharmony_ci			snd_BUG();
32662306a36Sopenharmony_ci		}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci		spin_lock_irqsave(&chip->reg_lock, flags);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci		/* update entry in DSP RAM */
33162306a36Sopenharmony_ci		cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci		spin_unlock_irqrestore(&chip->reg_lock, flags);
33462306a36Sopenharmony_ci	}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	cs46xx_dsp_proc_register_scb_desc (chip,scb);
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	return scb;
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_cistatic struct dsp_scb_descriptor *
34362306a36Sopenharmony_cics46xx_dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data,
34462306a36Sopenharmony_ci			       u32 dest, char * task_entry_name,
34562306a36Sopenharmony_ci                               struct dsp_scb_descriptor * parent_scb,
34662306a36Sopenharmony_ci                               int scb_child_type)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	struct dsp_symbol_entry * task_entry;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	task_entry = cs46xx_dsp_lookup_symbol (chip,task_entry_name,
35162306a36Sopenharmony_ci					       SYMBOL_CODE);
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	if (task_entry == NULL) {
35462306a36Sopenharmony_ci		dev_err(chip->card->dev,
35562306a36Sopenharmony_ci			"dsp_spos: symbol %s not found\n", task_entry_name);
35662306a36Sopenharmony_ci		return NULL;
35762306a36Sopenharmony_ci	}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	return _dsp_create_generic_scb (chip,name,scb_data,dest,task_entry,
36062306a36Sopenharmony_ci					parent_scb,scb_child_type);
36162306a36Sopenharmony_ci}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_cistruct dsp_scb_descriptor *
36462306a36Sopenharmony_cics46xx_dsp_create_timing_master_scb (struct snd_cs46xx *chip)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	struct dsp_scb_descriptor * scb;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	struct dsp_timing_master_scb timing_master_scb = {
36962306a36Sopenharmony_ci		{ 0,
37062306a36Sopenharmony_ci		  0,
37162306a36Sopenharmony_ci		  0,
37262306a36Sopenharmony_ci		  0
37362306a36Sopenharmony_ci		},
37462306a36Sopenharmony_ci		{ 0,
37562306a36Sopenharmony_ci		  0,
37662306a36Sopenharmony_ci		  0,
37762306a36Sopenharmony_ci		  0,
37862306a36Sopenharmony_ci		  0
37962306a36Sopenharmony_ci		},
38062306a36Sopenharmony_ci		0,0,
38162306a36Sopenharmony_ci		0,NULL_SCB_ADDR,
38262306a36Sopenharmony_ci		0,0,             /* extraSampleAccum:TMreserved */
38362306a36Sopenharmony_ci		0,0,             /* codecFIFOptr:codecFIFOsyncd */
38462306a36Sopenharmony_ci		0x0001,0x8000,   /* fracSampAccumQm1:TMfrmsLeftInGroup */
38562306a36Sopenharmony_ci		0x0001,0x0000,   /* fracSampCorrectionQm1:TMfrmGroupLength */
38662306a36Sopenharmony_ci		0x00060000       /* nSampPerFrmQ15 */
38762306a36Sopenharmony_ci	};
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	scb = cs46xx_dsp_create_generic_scb(chip,"TimingMasterSCBInst",(u32 *)&timing_master_scb,
39062306a36Sopenharmony_ci					    TIMINGMASTER_SCB_ADDR,
39162306a36Sopenharmony_ci					    "TIMINGMASTER",NULL,SCB_NO_PARENT);
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	return scb;
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_cistruct dsp_scb_descriptor *
39862306a36Sopenharmony_cics46xx_dsp_create_codec_out_scb(struct snd_cs46xx * chip, char * codec_name,
39962306a36Sopenharmony_ci                                u16 channel_disp, u16 fifo_addr, u16 child_scb_addr,
40062306a36Sopenharmony_ci                                u32 dest, struct dsp_scb_descriptor * parent_scb,
40162306a36Sopenharmony_ci                                int scb_child_type)
40262306a36Sopenharmony_ci{
40362306a36Sopenharmony_ci	struct dsp_scb_descriptor * scb;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	struct dsp_codec_output_scb codec_out_scb = {
40662306a36Sopenharmony_ci		{ 0,
40762306a36Sopenharmony_ci		  0,
40862306a36Sopenharmony_ci		  0,
40962306a36Sopenharmony_ci		  0
41062306a36Sopenharmony_ci		},
41162306a36Sopenharmony_ci		{
41262306a36Sopenharmony_ci			0,
41362306a36Sopenharmony_ci			0,
41462306a36Sopenharmony_ci			0,
41562306a36Sopenharmony_ci			0,
41662306a36Sopenharmony_ci			0
41762306a36Sopenharmony_ci		},
41862306a36Sopenharmony_ci		0,0,
41962306a36Sopenharmony_ci		0,NULL_SCB_ADDR,
42062306a36Sopenharmony_ci		0,                      /* COstrmRsConfig */
42162306a36Sopenharmony_ci		0,                      /* COstrmBufPtr */
42262306a36Sopenharmony_ci		channel_disp,fifo_addr, /* leftChanBaseIOaddr:rightChanIOdisp */
42362306a36Sopenharmony_ci		0x0000,0x0080,          /* (!AC97!) COexpVolChangeRate:COscaleShiftCount */
42462306a36Sopenharmony_ci		0,child_scb_addr        /* COreserved - need child scb to work with rom code */
42562306a36Sopenharmony_ci	};
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_out_scb,
42962306a36Sopenharmony_ci					    dest,"S16_CODECOUTPUTTASK",parent_scb,
43062306a36Sopenharmony_ci					    scb_child_type);
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	return scb;
43362306a36Sopenharmony_ci}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_cistruct dsp_scb_descriptor *
43662306a36Sopenharmony_cics46xx_dsp_create_codec_in_scb(struct snd_cs46xx * chip, char * codec_name,
43762306a36Sopenharmony_ci			       u16 channel_disp, u16 fifo_addr, u16 sample_buffer_addr,
43862306a36Sopenharmony_ci			       u32 dest, struct dsp_scb_descriptor * parent_scb,
43962306a36Sopenharmony_ci			       int scb_child_type)
44062306a36Sopenharmony_ci{
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	struct dsp_scb_descriptor * scb;
44362306a36Sopenharmony_ci	struct dsp_codec_input_scb codec_input_scb = {
44462306a36Sopenharmony_ci		{ 0,
44562306a36Sopenharmony_ci		  0,
44662306a36Sopenharmony_ci		  0,
44762306a36Sopenharmony_ci		  0
44862306a36Sopenharmony_ci		},
44962306a36Sopenharmony_ci		{
45062306a36Sopenharmony_ci			0,
45162306a36Sopenharmony_ci			0,
45262306a36Sopenharmony_ci			0,
45362306a36Sopenharmony_ci			0,
45462306a36Sopenharmony_ci			0
45562306a36Sopenharmony_ci		},
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci#if 0  /* cs4620 */
45862306a36Sopenharmony_ci		SyncIOSCB,NULL_SCB_ADDR
45962306a36Sopenharmony_ci#else
46062306a36Sopenharmony_ci		0 , 0,
46162306a36Sopenharmony_ci#endif
46262306a36Sopenharmony_ci		0,0,
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,  /* strmRsConfig */
46562306a36Sopenharmony_ci		sample_buffer_addr << 0x10,       /* strmBufPtr; defined as a dword ptr, used as a byte ptr */
46662306a36Sopenharmony_ci		channel_disp,fifo_addr,           /* (!AC97!) leftChanBaseINaddr=AC97primary
46762306a36Sopenharmony_ci						     link input slot 3 :rightChanINdisp=""slot 4 */
46862306a36Sopenharmony_ci		0x0000,0x0000,                    /* (!AC97!) ????:scaleShiftCount; no shift needed
46962306a36Sopenharmony_ci						     because AC97 is already 20 bits */
47062306a36Sopenharmony_ci		0x80008000                        /* ??clw cwcgame.scb has 0 */
47162306a36Sopenharmony_ci	};
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_input_scb,
47462306a36Sopenharmony_ci					    dest,"S16_CODECINPUTTASK",parent_scb,
47562306a36Sopenharmony_ci					    scb_child_type);
47662306a36Sopenharmony_ci	return scb;
47762306a36Sopenharmony_ci}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_cistatic struct dsp_scb_descriptor *
48162306a36Sopenharmony_cics46xx_dsp_create_pcm_reader_scb(struct snd_cs46xx * chip, char * scb_name,
48262306a36Sopenharmony_ci                                 u16 sample_buffer_addr, u32 dest,
48362306a36Sopenharmony_ci                                 int virtual_channel, u32 playback_hw_addr,
48462306a36Sopenharmony_ci                                 struct dsp_scb_descriptor * parent_scb,
48562306a36Sopenharmony_ci                                 int scb_child_type)
48662306a36Sopenharmony_ci{
48762306a36Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
48862306a36Sopenharmony_ci	struct dsp_scb_descriptor * scb;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	struct dsp_generic_scb pcm_reader_scb = {
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci		/*
49362306a36Sopenharmony_ci		  Play DMA Task xfers data from host buffer to SP buffer
49462306a36Sopenharmony_ci		  init/runtime variables:
49562306a36Sopenharmony_ci		  PlayAC: Play Audio Data Conversion - SCB loc: 2nd dword, mask: 0x0000F000L
49662306a36Sopenharmony_ci		  DATA_FMT_16BIT_ST_LTLEND(0x00000000L)   from 16-bit stereo, little-endian
49762306a36Sopenharmony_ci		  DATA_FMT_8_BIT_ST_SIGNED(0x00001000L)   from 8-bit stereo, signed
49862306a36Sopenharmony_ci		  DATA_FMT_16BIT_MN_LTLEND(0x00002000L)   from 16-bit mono, little-endian
49962306a36Sopenharmony_ci		  DATA_FMT_8_BIT_MN_SIGNED(0x00003000L)   from 8-bit mono, signed
50062306a36Sopenharmony_ci		  DATA_FMT_16BIT_ST_BIGEND(0x00004000L)   from 16-bit stereo, big-endian
50162306a36Sopenharmony_ci		  DATA_FMT_16BIT_MN_BIGEND(0x00006000L)   from 16-bit mono, big-endian
50262306a36Sopenharmony_ci		  DATA_FMT_8_BIT_ST_UNSIGNED(0x00009000L) from 8-bit stereo, unsigned
50362306a36Sopenharmony_ci		  DATA_FMT_8_BIT_MN_UNSIGNED(0x0000b000L) from 8-bit mono, unsigned
50462306a36Sopenharmony_ci		  ? Other combinations possible from:
50562306a36Sopenharmony_ci		  DMA_RQ_C2_AUDIO_CONVERT_MASK    0x0000F000L
50662306a36Sopenharmony_ci		  DMA_RQ_C2_AC_NONE               0x00000000L
50762306a36Sopenharmony_ci		  DMA_RQ_C2_AC_8_TO_16_BIT        0x00001000L
50862306a36Sopenharmony_ci		  DMA_RQ_C2_AC_MONO_TO_STEREO     0x00002000L
50962306a36Sopenharmony_ci		  DMA_RQ_C2_AC_ENDIAN_CONVERT     0x00004000L
51062306a36Sopenharmony_ci		  DMA_RQ_C2_AC_SIGNED_CONVERT     0x00008000L
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci		  HostBuffAddr: Host Buffer Physical Byte Address - SCB loc:3rd dword, Mask: 0xFFFFFFFFL
51362306a36Sopenharmony_ci		  aligned to dword boundary
51462306a36Sopenharmony_ci		*/
51562306a36Sopenharmony_ci		/* Basic (non scatter/gather) DMA requestor (4 ints) */
51662306a36Sopenharmony_ci		{ DMA_RQ_C1_SOURCE_ON_HOST +        /* source buffer is on the host */
51762306a36Sopenharmony_ci		  DMA_RQ_C1_SOURCE_MOD1024 +        /* source buffer is 1024 dwords (4096 bytes) */
51862306a36Sopenharmony_ci		  DMA_RQ_C1_DEST_MOD32 +            /* dest buffer(PCMreaderBuf) is 32 dwords*/
51962306a36Sopenharmony_ci		  DMA_RQ_C1_WRITEBACK_SRC_FLAG +    /* ?? */
52062306a36Sopenharmony_ci		  DMA_RQ_C1_WRITEBACK_DEST_FLAG +   /* ?? */
52162306a36Sopenharmony_ci		  15,                             /* DwordCount-1: picked 16 for DwordCount because Jim */
52262306a36Sopenharmony_ci		  /*        Barnette said that is what we should use since */
52362306a36Sopenharmony_ci		  /*        we are not running in optimized mode? */
52462306a36Sopenharmony_ci		  DMA_RQ_C2_AC_NONE +
52562306a36Sopenharmony_ci		  DMA_RQ_C2_SIGNAL_SOURCE_PINGPONG + /* set play interrupt (bit0) in HISR when source */
52662306a36Sopenharmony_ci		  /*   buffer (on host) crosses half-way point */
52762306a36Sopenharmony_ci		  virtual_channel,                   /* Play DMA channel arbitrarily set to 0 */
52862306a36Sopenharmony_ci		  playback_hw_addr,                  /* HostBuffAddr (source) */
52962306a36Sopenharmony_ci		  DMA_RQ_SD_SP_SAMPLE_ADDR +         /* destination buffer is in SP Sample Memory */
53062306a36Sopenharmony_ci		  sample_buffer_addr                 /* SP Buffer Address (destination) */
53162306a36Sopenharmony_ci		},
53262306a36Sopenharmony_ci		/* Scatter/gather DMA requestor extension   (5 ints) */
53362306a36Sopenharmony_ci		{
53462306a36Sopenharmony_ci			0,
53562306a36Sopenharmony_ci			0,
53662306a36Sopenharmony_ci			0,
53762306a36Sopenharmony_ci			0,
53862306a36Sopenharmony_ci			0
53962306a36Sopenharmony_ci		},
54062306a36Sopenharmony_ci		/* Sublist pointer & next stream control block (SCB) link. */
54162306a36Sopenharmony_ci		NULL_SCB_ADDR,NULL_SCB_ADDR,
54262306a36Sopenharmony_ci		/* Pointer to this tasks parameter block & stream function pointer */
54362306a36Sopenharmony_ci		0,NULL_SCB_ADDR,
54462306a36Sopenharmony_ci		/* rsConfig register for stream buffer (rsDMA reg. is loaded from basicReq.daw */
54562306a36Sopenharmony_ci		/*   for incoming streams, or basicReq.saw, for outgoing streams) */
54662306a36Sopenharmony_ci		RSCONFIG_DMA_ENABLE +                 /* enable DMA */
54762306a36Sopenharmony_ci		(19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) + /* MAX_DMA_SIZE picked to be 19 since SPUD  */
54862306a36Sopenharmony_ci		/*  uses it for some reason */
54962306a36Sopenharmony_ci		((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) + /* stream number = SCBaddr/16 */
55062306a36Sopenharmony_ci		RSCONFIG_SAMPLE_16STEREO +
55162306a36Sopenharmony_ci		RSCONFIG_MODULO_32,             /* dest buffer(PCMreaderBuf) is 32 dwords (256 bytes) */
55262306a36Sopenharmony_ci		/* Stream sample pointer & MAC-unit mode for this stream */
55362306a36Sopenharmony_ci		(sample_buffer_addr << 0x10),
55462306a36Sopenharmony_ci		/* Fractional increment per output sample in the input sample buffer */
55562306a36Sopenharmony_ci		0,
55662306a36Sopenharmony_ci		{
55762306a36Sopenharmony_ci			/* Standard stereo volume control
55862306a36Sopenharmony_ci			   default muted */
55962306a36Sopenharmony_ci			0xffff,0xffff,
56062306a36Sopenharmony_ci			0xffff,0xffff
56162306a36Sopenharmony_ci		}
56262306a36Sopenharmony_ci	};
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	if (ins->null_algorithm == NULL) {
56562306a36Sopenharmony_ci		ins->null_algorithm =  cs46xx_dsp_lookup_symbol (chip,"NULLALGORITHM",
56662306a36Sopenharmony_ci								 SYMBOL_CODE);
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci		if (ins->null_algorithm == NULL) {
56962306a36Sopenharmony_ci			dev_err(chip->card->dev,
57062306a36Sopenharmony_ci				"dsp_spos: symbol NULLALGORITHM not found\n");
57162306a36Sopenharmony_ci			return NULL;
57262306a36Sopenharmony_ci		}
57362306a36Sopenharmony_ci	}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_reader_scb,
57662306a36Sopenharmony_ci				      dest,ins->null_algorithm,parent_scb,
57762306a36Sopenharmony_ci				      scb_child_type);
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	return scb;
58062306a36Sopenharmony_ci}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci#define GOF_PER_SEC 200
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_cistruct dsp_scb_descriptor *
58562306a36Sopenharmony_cics46xx_dsp_create_src_task_scb(struct snd_cs46xx * chip, char * scb_name,
58662306a36Sopenharmony_ci			       int rate,
58762306a36Sopenharmony_ci                               u16 src_buffer_addr,
58862306a36Sopenharmony_ci                               u16 src_delay_buffer_addr, u32 dest,
58962306a36Sopenharmony_ci                               struct dsp_scb_descriptor * parent_scb,
59062306a36Sopenharmony_ci                               int scb_child_type,
59162306a36Sopenharmony_ci	                       int pass_through)
59262306a36Sopenharmony_ci{
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
59562306a36Sopenharmony_ci	struct dsp_scb_descriptor * scb;
59662306a36Sopenharmony_ci	unsigned int tmp1, tmp2;
59762306a36Sopenharmony_ci	unsigned int phiIncr;
59862306a36Sopenharmony_ci	unsigned int correctionPerGOF, correctionPerSec;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	dev_dbg(chip->card->dev, "dsp_spos: setting %s rate to %u\n",
60162306a36Sopenharmony_ci		scb_name, rate);
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	/*
60462306a36Sopenharmony_ci	 *  Compute the values used to drive the actual sample rate conversion.
60562306a36Sopenharmony_ci	 *  The following formulas are being computed, using inline assembly
60662306a36Sopenharmony_ci	 *  since we need to use 64 bit arithmetic to compute the values:
60762306a36Sopenharmony_ci	 *
60862306a36Sopenharmony_ci	 *  phiIncr = floor((Fs,in * 2^26) / Fs,out)
60962306a36Sopenharmony_ci	 *  correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) /
61062306a36Sopenharmony_ci	 *                                   GOF_PER_SEC)
61162306a36Sopenharmony_ci	 *  ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -M
61262306a36Sopenharmony_ci	 *                       GOF_PER_SEC * correctionPerGOF
61362306a36Sopenharmony_ci	 *
61462306a36Sopenharmony_ci	 *  i.e.
61562306a36Sopenharmony_ci	 *
61662306a36Sopenharmony_ci	 *  phiIncr:other = dividend:remainder((Fs,in * 2^26) / Fs,out)
61762306a36Sopenharmony_ci	 *  correctionPerGOF:correctionPerSec =
61862306a36Sopenharmony_ci	 *      dividend:remainder(ulOther / GOF_PER_SEC)
61962306a36Sopenharmony_ci	 */
62062306a36Sopenharmony_ci	tmp1 = rate << 16;
62162306a36Sopenharmony_ci	phiIncr = tmp1 / 48000;
62262306a36Sopenharmony_ci	tmp1 -= phiIncr * 48000;
62362306a36Sopenharmony_ci	tmp1 <<= 10;
62462306a36Sopenharmony_ci	phiIncr <<= 10;
62562306a36Sopenharmony_ci	tmp2 = tmp1 / 48000;
62662306a36Sopenharmony_ci	phiIncr += tmp2;
62762306a36Sopenharmony_ci	tmp1 -= tmp2 * 48000;
62862306a36Sopenharmony_ci	correctionPerGOF = tmp1 / GOF_PER_SEC;
62962306a36Sopenharmony_ci	tmp1 -= correctionPerGOF * GOF_PER_SEC;
63062306a36Sopenharmony_ci	correctionPerSec = tmp1;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	{
63362306a36Sopenharmony_ci		struct dsp_src_task_scb src_task_scb = {
63462306a36Sopenharmony_ci			0x0028,0x00c8,
63562306a36Sopenharmony_ci			0x5555,0x0000,
63662306a36Sopenharmony_ci			0x0000,0x0000,
63762306a36Sopenharmony_ci			src_buffer_addr,1,
63862306a36Sopenharmony_ci			correctionPerGOF,correctionPerSec,
63962306a36Sopenharmony_ci			RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
64062306a36Sopenharmony_ci			0x0000,src_delay_buffer_addr,
64162306a36Sopenharmony_ci			0x0,
64262306a36Sopenharmony_ci			0x080,(src_delay_buffer_addr + (24 * 4)),
64362306a36Sopenharmony_ci			0,0, /* next_scb, sub_list_ptr */
64462306a36Sopenharmony_ci			0,0, /* entry, this_spb */
64562306a36Sopenharmony_ci			RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
64662306a36Sopenharmony_ci			src_buffer_addr << 0x10,
64762306a36Sopenharmony_ci			phiIncr,
64862306a36Sopenharmony_ci			{
64962306a36Sopenharmony_ci				0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left,
65062306a36Sopenharmony_ci				0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left
65162306a36Sopenharmony_ci			}
65262306a36Sopenharmony_ci		};
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci		if (ins->s16_up == NULL) {
65562306a36Sopenharmony_ci			ins->s16_up =  cs46xx_dsp_lookup_symbol (chip,"S16_UPSRC",
65662306a36Sopenharmony_ci								 SYMBOL_CODE);
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci			if (ins->s16_up == NULL) {
65962306a36Sopenharmony_ci				dev_err(chip->card->dev,
66062306a36Sopenharmony_ci					"dsp_spos: symbol S16_UPSRC not found\n");
66162306a36Sopenharmony_ci				return NULL;
66262306a36Sopenharmony_ci			}
66362306a36Sopenharmony_ci		}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci		/* clear buffers */
66662306a36Sopenharmony_ci		_dsp_clear_sample_buffer (chip,src_buffer_addr,8);
66762306a36Sopenharmony_ci		_dsp_clear_sample_buffer (chip,src_delay_buffer_addr,32);
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci		if (pass_through) {
67062306a36Sopenharmony_ci			/* wont work with any other rate than
67162306a36Sopenharmony_ci			   the native DSP rate */
67262306a36Sopenharmony_ci			snd_BUG_ON(rate != 48000);
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci			scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
67562306a36Sopenharmony_ci							    dest,"DMAREADER",parent_scb,
67662306a36Sopenharmony_ci							    scb_child_type);
67762306a36Sopenharmony_ci		} else {
67862306a36Sopenharmony_ci			scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
67962306a36Sopenharmony_ci						      dest,ins->s16_up,parent_scb,
68062306a36Sopenharmony_ci						      scb_child_type);
68162306a36Sopenharmony_ci		}
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	}
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	return scb;
68762306a36Sopenharmony_ci}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci#if 0 /* not used */
69062306a36Sopenharmony_cistruct dsp_scb_descriptor *
69162306a36Sopenharmony_cics46xx_dsp_create_filter_scb(struct snd_cs46xx * chip, char * scb_name,
69262306a36Sopenharmony_ci			     u16 buffer_addr, u32 dest,
69362306a36Sopenharmony_ci			     struct dsp_scb_descriptor * parent_scb,
69462306a36Sopenharmony_ci			     int scb_child_type) {
69562306a36Sopenharmony_ci	struct dsp_scb_descriptor * scb;
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	struct dsp_filter_scb filter_scb = {
69862306a36Sopenharmony_ci		.a0_right            = 0x41a9,
69962306a36Sopenharmony_ci		.a0_left             = 0x41a9,
70062306a36Sopenharmony_ci		.a1_right            = 0xb8e4,
70162306a36Sopenharmony_ci		.a1_left             = 0xb8e4,
70262306a36Sopenharmony_ci		.a2_right            = 0x3e55,
70362306a36Sopenharmony_ci		.a2_left             = 0x3e55,
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci		.filter_unused3      = 0x0000,
70662306a36Sopenharmony_ci		.filter_unused2      = 0x0000,
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci		.output_buf_ptr      = buffer_addr,
70962306a36Sopenharmony_ci		.init                = 0x000,
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci		.prev_sample_output1 = 0x00000000,
71262306a36Sopenharmony_ci		.prev_sample_output2 = 0x00000000,
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci		.prev_sample_input1  = 0x00000000,
71562306a36Sopenharmony_ci		.prev_sample_input2  = 0x00000000,
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci		.next_scb_ptr        = 0x0000,
71862306a36Sopenharmony_ci		.sub_list_ptr        = 0x0000,
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci		.entry_point         = 0x0000,
72162306a36Sopenharmony_ci		.spb_ptr             = 0x0000,
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci		.b0_right            = 0x0e38,
72462306a36Sopenharmony_ci		.b0_left             = 0x0e38,
72562306a36Sopenharmony_ci		.b1_right            = 0x1c71,
72662306a36Sopenharmony_ci		.b1_left             = 0x1c71,
72762306a36Sopenharmony_ci		.b2_right            = 0x0e38,
72862306a36Sopenharmony_ci		.b2_left             = 0x0e38,
72962306a36Sopenharmony_ci	};
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&filter_scb,
73362306a36Sopenharmony_ci					    dest,"FILTERTASK",parent_scb,
73462306a36Sopenharmony_ci					    scb_child_type);
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci 	return scb;
73762306a36Sopenharmony_ci}
73862306a36Sopenharmony_ci#endif /* not used */
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_cistruct dsp_scb_descriptor *
74162306a36Sopenharmony_cics46xx_dsp_create_mix_only_scb(struct snd_cs46xx * chip, char * scb_name,
74262306a36Sopenharmony_ci                               u16 mix_buffer_addr, u32 dest,
74362306a36Sopenharmony_ci                               struct dsp_scb_descriptor * parent_scb,
74462306a36Sopenharmony_ci                               int scb_child_type)
74562306a36Sopenharmony_ci{
74662306a36Sopenharmony_ci	struct dsp_scb_descriptor * scb;
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	struct dsp_mix_only_scb master_mix_scb = {
74962306a36Sopenharmony_ci		/* 0 */ { 0,
75062306a36Sopenharmony_ci			  /* 1 */   0,
75162306a36Sopenharmony_ci			  /* 2 */  mix_buffer_addr,
75262306a36Sopenharmony_ci			  /* 3 */  0
75362306a36Sopenharmony_ci			  /*   */ },
75462306a36Sopenharmony_ci		{
75562306a36Sopenharmony_ci			/* 4 */  0,
75662306a36Sopenharmony_ci			/* 5 */  0,
75762306a36Sopenharmony_ci			/* 6 */  0,
75862306a36Sopenharmony_ci			/* 7 */  0,
75962306a36Sopenharmony_ci			/* 8 */  0x00000080
76062306a36Sopenharmony_ci		},
76162306a36Sopenharmony_ci		/* 9 */ 0,0,
76262306a36Sopenharmony_ci		/* A */ 0,0,
76362306a36Sopenharmony_ci		/* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
76462306a36Sopenharmony_ci		/* C */ (mix_buffer_addr  + (16 * 4)) << 0x10,
76562306a36Sopenharmony_ci		/* D */ 0,
76662306a36Sopenharmony_ci		{
76762306a36Sopenharmony_ci			/* E */ 0x8000,0x8000,
76862306a36Sopenharmony_ci			/* F */ 0x8000,0x8000
76962306a36Sopenharmony_ci		}
77062306a36Sopenharmony_ci	};
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&master_mix_scb,
77462306a36Sopenharmony_ci					    dest,"S16_MIX",parent_scb,
77562306a36Sopenharmony_ci					    scb_child_type);
77662306a36Sopenharmony_ci	return scb;
77762306a36Sopenharmony_ci}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_cistruct dsp_scb_descriptor *
78162306a36Sopenharmony_cics46xx_dsp_create_mix_to_ostream_scb(struct snd_cs46xx * chip, char * scb_name,
78262306a36Sopenharmony_ci                                     u16 mix_buffer_addr, u16 writeback_spb, u32 dest,
78362306a36Sopenharmony_ci                                     struct dsp_scb_descriptor * parent_scb,
78462306a36Sopenharmony_ci                                     int scb_child_type)
78562306a36Sopenharmony_ci{
78662306a36Sopenharmony_ci	struct dsp_scb_descriptor * scb;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	struct dsp_mix2_ostream_scb mix2_ostream_scb = {
78962306a36Sopenharmony_ci		/* Basic (non scatter/gather) DMA requestor (4 ints) */
79062306a36Sopenharmony_ci		{
79162306a36Sopenharmony_ci			DMA_RQ_C1_SOURCE_MOD64 +
79262306a36Sopenharmony_ci			DMA_RQ_C1_DEST_ON_HOST +
79362306a36Sopenharmony_ci			DMA_RQ_C1_DEST_MOD1024 +
79462306a36Sopenharmony_ci			DMA_RQ_C1_WRITEBACK_SRC_FLAG +
79562306a36Sopenharmony_ci			DMA_RQ_C1_WRITEBACK_DEST_FLAG +
79662306a36Sopenharmony_ci			15,
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci			DMA_RQ_C2_AC_NONE +
79962306a36Sopenharmony_ci			DMA_RQ_C2_SIGNAL_DEST_PINGPONG +
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci			CS46XX_DSP_CAPTURE_CHANNEL,
80262306a36Sopenharmony_ci			DMA_RQ_SD_SP_SAMPLE_ADDR +
80362306a36Sopenharmony_ci			mix_buffer_addr,
80462306a36Sopenharmony_ci			0x0
80562306a36Sopenharmony_ci		},
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci		{ 0, 0, 0, 0, 0, },
80862306a36Sopenharmony_ci		0,0,
80962306a36Sopenharmony_ci		0,writeback_spb,
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci		RSCONFIG_DMA_ENABLE +
81262306a36Sopenharmony_ci		(19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) +
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci		((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) +
81562306a36Sopenharmony_ci		RSCONFIG_DMA_TO_HOST +
81662306a36Sopenharmony_ci		RSCONFIG_SAMPLE_16STEREO +
81762306a36Sopenharmony_ci		RSCONFIG_MODULO_64,
81862306a36Sopenharmony_ci		(mix_buffer_addr + (32 * 4)) << 0x10,
81962306a36Sopenharmony_ci		1,0,
82062306a36Sopenharmony_ci		0x0001,0x0080,
82162306a36Sopenharmony_ci		0xFFFF,0
82262306a36Sopenharmony_ci	};
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&mix2_ostream_scb,
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	    dest,"S16_MIX_TO_OSTREAM",parent_scb,
82862306a36Sopenharmony_ci					    scb_child_type);
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	return scb;
83162306a36Sopenharmony_ci}
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_cistruct dsp_scb_descriptor *
83562306a36Sopenharmony_cics46xx_dsp_create_vari_decimate_scb(struct snd_cs46xx * chip,char * scb_name,
83662306a36Sopenharmony_ci                                    u16 vari_buffer_addr0,
83762306a36Sopenharmony_ci                                    u16 vari_buffer_addr1,
83862306a36Sopenharmony_ci                                    u32 dest,
83962306a36Sopenharmony_ci                                    struct dsp_scb_descriptor * parent_scb,
84062306a36Sopenharmony_ci                                    int scb_child_type)
84162306a36Sopenharmony_ci{
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	struct dsp_scb_descriptor * scb;
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	struct dsp_vari_decimate_scb vari_decimate_scb = {
84662306a36Sopenharmony_ci		0x0028,0x00c8,
84762306a36Sopenharmony_ci		0x5555,0x0000,
84862306a36Sopenharmony_ci		0x0000,0x0000,
84962306a36Sopenharmony_ci		vari_buffer_addr0,vari_buffer_addr1,
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci		0x0028,0x00c8,
85262306a36Sopenharmony_ci		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256,
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci		0xFF800000,
85562306a36Sopenharmony_ci		0,
85662306a36Sopenharmony_ci		0x0080,vari_buffer_addr1 + (25 * 4),
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci		0,0,
85962306a36Sopenharmony_ci		0,0,
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
86262306a36Sopenharmony_ci		vari_buffer_addr0 << 0x10,
86362306a36Sopenharmony_ci		0x04000000,
86462306a36Sopenharmony_ci		{
86562306a36Sopenharmony_ci			0x8000,0x8000,
86662306a36Sopenharmony_ci			0xFFFF,0xFFFF
86762306a36Sopenharmony_ci		}
86862306a36Sopenharmony_ci	};
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&vari_decimate_scb,
87162306a36Sopenharmony_ci					    dest,"VARIDECIMATE",parent_scb,
87262306a36Sopenharmony_ci					    scb_child_type);
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	return scb;
87562306a36Sopenharmony_ci}
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_cistatic struct dsp_scb_descriptor *
87962306a36Sopenharmony_cics46xx_dsp_create_pcm_serial_input_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
88062306a36Sopenharmony_ci                                       struct dsp_scb_descriptor * input_scb,
88162306a36Sopenharmony_ci                                       struct dsp_scb_descriptor * parent_scb,
88262306a36Sopenharmony_ci                                       int scb_child_type)
88362306a36Sopenharmony_ci{
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	struct dsp_scb_descriptor * scb;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	struct dsp_pcm_serial_input_scb pcm_serial_input_scb = {
88962306a36Sopenharmony_ci		{ 0,
89062306a36Sopenharmony_ci		  0,
89162306a36Sopenharmony_ci		  0,
89262306a36Sopenharmony_ci		  0
89362306a36Sopenharmony_ci		},
89462306a36Sopenharmony_ci		{
89562306a36Sopenharmony_ci			0,
89662306a36Sopenharmony_ci			0,
89762306a36Sopenharmony_ci			0,
89862306a36Sopenharmony_ci			0,
89962306a36Sopenharmony_ci			0
90062306a36Sopenharmony_ci		},
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci		0,0,
90362306a36Sopenharmony_ci		0,0,
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_16,
90662306a36Sopenharmony_ci		0,
90762306a36Sopenharmony_ci      /* 0xD */ 0,input_scb->address,
90862306a36Sopenharmony_ci		{
90962306a36Sopenharmony_ci      /* 0xE */   0x8000,0x8000,
91062306a36Sopenharmony_ci      /* 0xF */	  0x8000,0x8000
91162306a36Sopenharmony_ci		}
91262306a36Sopenharmony_ci	};
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_serial_input_scb,
91562306a36Sopenharmony_ci					    dest,"PCMSERIALINPUTTASK",parent_scb,
91662306a36Sopenharmony_ci					    scb_child_type);
91762306a36Sopenharmony_ci	return scb;
91862306a36Sopenharmony_ci}
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_cistatic struct dsp_scb_descriptor *
92262306a36Sopenharmony_cics46xx_dsp_create_asynch_fg_tx_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
92362306a36Sopenharmony_ci                                   u16 hfg_scb_address,
92462306a36Sopenharmony_ci                                   u16 asynch_buffer_address,
92562306a36Sopenharmony_ci                                   struct dsp_scb_descriptor * parent_scb,
92662306a36Sopenharmony_ci                                   int scb_child_type)
92762306a36Sopenharmony_ci{
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	struct dsp_scb_descriptor * scb;
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	struct dsp_asynch_fg_tx_scb asynch_fg_tx_scb = {
93262306a36Sopenharmony_ci		0xfc00,0x03ff,      /*  Prototype sample buffer size of 256 dwords */
93362306a36Sopenharmony_ci		0x0058,0x0028,      /* Min Delta 7 dwords == 28 bytes */
93462306a36Sopenharmony_ci		/* : Max delta 25 dwords == 100 bytes */
93562306a36Sopenharmony_ci		0,hfg_scb_address,  /* Point to HFG task SCB */
93662306a36Sopenharmony_ci		0,0,		    /* Initialize current Delta and Consumer ptr adjustment count */
93762306a36Sopenharmony_ci		0,                  /* Initialize accumulated Phi to 0 */
93862306a36Sopenharmony_ci		0,0x2aab,           /* Const 1/3 */
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci		{
94162306a36Sopenharmony_ci			0,         /* Define the unused elements */
94262306a36Sopenharmony_ci			0,
94362306a36Sopenharmony_ci			0
94462306a36Sopenharmony_ci		},
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci		0,0,
94762306a36Sopenharmony_ci		0,dest + AFGTxAccumPhi,
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256, /* Stereo, 256 dword */
95062306a36Sopenharmony_ci		(asynch_buffer_address) << 0x10,  /* This should be automagically synchronized
95162306a36Sopenharmony_ci                                                     to the producer pointer */
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci		/* There is no correct initial value, it will depend upon the detected
95462306a36Sopenharmony_ci		   rate etc  */
95562306a36Sopenharmony_ci		0x18000000,                     /* Phi increment for approx 32k operation */
95662306a36Sopenharmony_ci		0x8000,0x8000,                  /* Volume controls are unused at this time */
95762306a36Sopenharmony_ci		0x8000,0x8000
95862306a36Sopenharmony_ci	};
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_tx_scb,
96162306a36Sopenharmony_ci					    dest,"ASYNCHFGTXCODE",parent_scb,
96262306a36Sopenharmony_ci					    scb_child_type);
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	return scb;
96562306a36Sopenharmony_ci}
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_cistruct dsp_scb_descriptor *
96962306a36Sopenharmony_cics46xx_dsp_create_asynch_fg_rx_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
97062306a36Sopenharmony_ci                                   u16 hfg_scb_address,
97162306a36Sopenharmony_ci                                   u16 asynch_buffer_address,
97262306a36Sopenharmony_ci                                   struct dsp_scb_descriptor * parent_scb,
97362306a36Sopenharmony_ci                                   int scb_child_type)
97462306a36Sopenharmony_ci{
97562306a36Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
97662306a36Sopenharmony_ci	struct dsp_scb_descriptor * scb;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	struct dsp_asynch_fg_rx_scb asynch_fg_rx_scb = {
97962306a36Sopenharmony_ci		0xfe00,0x01ff,      /*  Prototype sample buffer size of 128 dwords */
98062306a36Sopenharmony_ci		0x0064,0x001c,      /* Min Delta 7 dwords == 28 bytes */
98162306a36Sopenharmony_ci		                    /* : Max delta 25 dwords == 100 bytes */
98262306a36Sopenharmony_ci		0,hfg_scb_address,  /* Point to HFG task SCB */
98362306a36Sopenharmony_ci		0,0,				/* Initialize current Delta and Consumer ptr adjustment count */
98462306a36Sopenharmony_ci		{
98562306a36Sopenharmony_ci			0,                /* Define the unused elements */
98662306a36Sopenharmony_ci			0,
98762306a36Sopenharmony_ci			0,
98862306a36Sopenharmony_ci			0,
98962306a36Sopenharmony_ci			0
99062306a36Sopenharmony_ci		},
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci		0,0,
99362306a36Sopenharmony_ci		0,dest,
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci		RSCONFIG_MODULO_128 |
99662306a36Sopenharmony_ci        RSCONFIG_SAMPLE_16STEREO,                         /* Stereo, 128 dword */
99762306a36Sopenharmony_ci		( (asynch_buffer_address + (16 * 4))  << 0x10),   /* This should be automagically
99862306a36Sopenharmony_ci							                                  synchrinized to the producer pointer */
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci		/* There is no correct initial value, it will depend upon the detected
100162306a36Sopenharmony_ci		   rate etc  */
100262306a36Sopenharmony_ci		0x18000000,
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci		/* Set IEC958 input volume */
100562306a36Sopenharmony_ci		0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
100662306a36Sopenharmony_ci		0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
100762306a36Sopenharmony_ci	};
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_rx_scb,
101062306a36Sopenharmony_ci					    dest,"ASYNCHFGRXCODE",parent_scb,
101162306a36Sopenharmony_ci					    scb_child_type);
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	return scb;
101462306a36Sopenharmony_ci}
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci#if 0 /* not used */
101862306a36Sopenharmony_cistruct dsp_scb_descriptor *
101962306a36Sopenharmony_cics46xx_dsp_create_output_snoop_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
102062306a36Sopenharmony_ci                                   u16 snoop_buffer_address,
102162306a36Sopenharmony_ci                                   struct dsp_scb_descriptor * snoop_scb,
102262306a36Sopenharmony_ci                                   struct dsp_scb_descriptor * parent_scb,
102362306a36Sopenharmony_ci                                   int scb_child_type)
102462306a36Sopenharmony_ci{
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	struct dsp_scb_descriptor * scb;
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	struct dsp_output_snoop_scb output_snoop_scb = {
102962306a36Sopenharmony_ci		{ 0,	/*  not used.  Zero */
103062306a36Sopenharmony_ci		  0,
103162306a36Sopenharmony_ci		  0,
103262306a36Sopenharmony_ci		  0,
103362306a36Sopenharmony_ci		},
103462306a36Sopenharmony_ci		{
103562306a36Sopenharmony_ci			0, /* not used.  Zero */
103662306a36Sopenharmony_ci			0,
103762306a36Sopenharmony_ci			0,
103862306a36Sopenharmony_ci			0,
103962306a36Sopenharmony_ci			0
104062306a36Sopenharmony_ci		},
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci		0,0,
104362306a36Sopenharmony_ci		0,0,
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
104662306a36Sopenharmony_ci		snoop_buffer_address << 0x10,
104762306a36Sopenharmony_ci		0,0,
104862306a36Sopenharmony_ci		0,
104962306a36Sopenharmony_ci		0,snoop_scb->address
105062306a36Sopenharmony_ci	};
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&output_snoop_scb,
105362306a36Sopenharmony_ci					    dest,"OUTPUTSNOOP",parent_scb,
105462306a36Sopenharmony_ci					    scb_child_type);
105562306a36Sopenharmony_ci	return scb;
105662306a36Sopenharmony_ci}
105762306a36Sopenharmony_ci#endif /* not used */
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_cistruct dsp_scb_descriptor *
106162306a36Sopenharmony_cics46xx_dsp_create_spio_write_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
106262306a36Sopenharmony_ci                                 struct dsp_scb_descriptor * parent_scb,
106362306a36Sopenharmony_ci                                 int scb_child_type)
106462306a36Sopenharmony_ci{
106562306a36Sopenharmony_ci	struct dsp_scb_descriptor * scb;
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	struct dsp_spio_write_scb spio_write_scb = {
106862306a36Sopenharmony_ci		0,0,         /*   SPIOWAddress2:SPIOWAddress1; */
106962306a36Sopenharmony_ci		0,           /*   SPIOWData1; */
107062306a36Sopenharmony_ci		0,           /*   SPIOWData2; */
107162306a36Sopenharmony_ci		0,0,         /*   SPIOWAddress4:SPIOWAddress3; */
107262306a36Sopenharmony_ci		0,           /*   SPIOWData3; */
107362306a36Sopenharmony_ci		0,           /*   SPIOWData4; */
107462306a36Sopenharmony_ci		0,0,         /*   SPIOWDataPtr:Unused1; */
107562306a36Sopenharmony_ci		{ 0,0 },     /*   Unused2[2]; */
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci		0,0,	     /*   SPIOWChildPtr:SPIOWSiblingPtr; */
107862306a36Sopenharmony_ci		0,0,         /*   SPIOWThisPtr:SPIOWEntryPoint; */
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci		{
108162306a36Sopenharmony_ci			0,
108262306a36Sopenharmony_ci			0,
108362306a36Sopenharmony_ci			0,
108462306a36Sopenharmony_ci			0,
108562306a36Sopenharmony_ci			0          /*   Unused3[5];  */
108662306a36Sopenharmony_ci		}
108762306a36Sopenharmony_ci	};
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&spio_write_scb,
109062306a36Sopenharmony_ci					    dest,"SPIOWRITE",parent_scb,
109162306a36Sopenharmony_ci					    scb_child_type);
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	return scb;
109462306a36Sopenharmony_ci}
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_cistruct dsp_scb_descriptor *
109762306a36Sopenharmony_cics46xx_dsp_create_magic_snoop_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
109862306a36Sopenharmony_ci				  u16 snoop_buffer_address,
109962306a36Sopenharmony_ci				  struct dsp_scb_descriptor * snoop_scb,
110062306a36Sopenharmony_ci				  struct dsp_scb_descriptor * parent_scb,
110162306a36Sopenharmony_ci				  int scb_child_type)
110262306a36Sopenharmony_ci{
110362306a36Sopenharmony_ci	struct dsp_scb_descriptor * scb;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	struct dsp_magic_snoop_task magic_snoop_scb = {
110662306a36Sopenharmony_ci		/* 0 */ 0, /* i0 */
110762306a36Sopenharmony_ci		/* 1 */ 0, /* i1 */
110862306a36Sopenharmony_ci		/* 2 */ snoop_buffer_address << 0x10,
110962306a36Sopenharmony_ci		/* 3 */ 0,snoop_scb->address,
111062306a36Sopenharmony_ci		/* 4 */ 0, /* i3 */
111162306a36Sopenharmony_ci		/* 5 */ 0, /* i4 */
111262306a36Sopenharmony_ci		/* 6 */ 0, /* i5 */
111362306a36Sopenharmony_ci		/* 7 */ 0, /* i6 */
111462306a36Sopenharmony_ci		/* 8 */ 0, /* i7 */
111562306a36Sopenharmony_ci		/* 9 */ 0,0, /* next_scb, sub_list_ptr */
111662306a36Sopenharmony_ci		/* A */ 0,0, /* entry_point, this_ptr */
111762306a36Sopenharmony_ci		/* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
111862306a36Sopenharmony_ci		/* C */ snoop_buffer_address  << 0x10,
111962306a36Sopenharmony_ci		/* D */ 0,
112062306a36Sopenharmony_ci		/* E */ { 0x8000,0x8000,
112162306a36Sopenharmony_ci	        /* F */   0xffff,0xffff
112262306a36Sopenharmony_ci		}
112362306a36Sopenharmony_ci	};
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&magic_snoop_scb,
112662306a36Sopenharmony_ci					    dest,"MAGICSNOOPTASK",parent_scb,
112762306a36Sopenharmony_ci					    scb_child_type);
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	return scb;
113062306a36Sopenharmony_ci}
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_cistatic struct dsp_scb_descriptor *
113362306a36Sopenharmony_cifind_next_free_scb (struct snd_cs46xx * chip, struct dsp_scb_descriptor * from)
113462306a36Sopenharmony_ci{
113562306a36Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
113662306a36Sopenharmony_ci	struct dsp_scb_descriptor * scb = from;
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	while (scb->next_scb_ptr != ins->the_null_scb) {
113962306a36Sopenharmony_ci		if (snd_BUG_ON(!scb->next_scb_ptr))
114062306a36Sopenharmony_ci			return NULL;
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci		scb = scb->next_scb_ptr;
114362306a36Sopenharmony_ci	}
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	return scb;
114662306a36Sopenharmony_ci}
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_cistatic const u32 pcm_reader_buffer_addr[DSP_MAX_PCM_CHANNELS] = {
114962306a36Sopenharmony_ci	0x0600, /* 1 */
115062306a36Sopenharmony_ci	0x1500, /* 2 */
115162306a36Sopenharmony_ci	0x1580, /* 3 */
115262306a36Sopenharmony_ci	0x1600, /* 4 */
115362306a36Sopenharmony_ci	0x1680, /* 5 */
115462306a36Sopenharmony_ci	0x1700, /* 6 */
115562306a36Sopenharmony_ci	0x1780, /* 7 */
115662306a36Sopenharmony_ci	0x1800, /* 8 */
115762306a36Sopenharmony_ci	0x1880, /* 9 */
115862306a36Sopenharmony_ci	0x1900, /* 10 */
115962306a36Sopenharmony_ci	0x1980, /* 11 */
116062306a36Sopenharmony_ci	0x1A00, /* 12 */
116162306a36Sopenharmony_ci	0x1A80, /* 13 */
116262306a36Sopenharmony_ci	0x1B00, /* 14 */
116362306a36Sopenharmony_ci	0x1B80, /* 15 */
116462306a36Sopenharmony_ci	0x1C00, /* 16 */
116562306a36Sopenharmony_ci	0x1C80, /* 17 */
116662306a36Sopenharmony_ci	0x1D00, /* 18 */
116762306a36Sopenharmony_ci	0x1D80, /* 19 */
116862306a36Sopenharmony_ci	0x1E00, /* 20 */
116962306a36Sopenharmony_ci	0x1E80, /* 21 */
117062306a36Sopenharmony_ci	0x1F00, /* 22 */
117162306a36Sopenharmony_ci	0x1F80, /* 23 */
117262306a36Sopenharmony_ci	0x2000, /* 24 */
117362306a36Sopenharmony_ci	0x2080, /* 25 */
117462306a36Sopenharmony_ci	0x2100, /* 26 */
117562306a36Sopenharmony_ci	0x2180, /* 27 */
117662306a36Sopenharmony_ci	0x2200, /* 28 */
117762306a36Sopenharmony_ci	0x2280, /* 29 */
117862306a36Sopenharmony_ci	0x2300, /* 30 */
117962306a36Sopenharmony_ci	0x2380, /* 31 */
118062306a36Sopenharmony_ci	0x2400, /* 32 */
118162306a36Sopenharmony_ci};
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_cistatic const u32 src_output_buffer_addr[DSP_MAX_SRC_NR] = {
118462306a36Sopenharmony_ci	0x2B80,
118562306a36Sopenharmony_ci	0x2BA0,
118662306a36Sopenharmony_ci	0x2BC0,
118762306a36Sopenharmony_ci	0x2BE0,
118862306a36Sopenharmony_ci	0x2D00,
118962306a36Sopenharmony_ci	0x2D20,
119062306a36Sopenharmony_ci	0x2D40,
119162306a36Sopenharmony_ci	0x2D60,
119262306a36Sopenharmony_ci	0x2D80,
119362306a36Sopenharmony_ci	0x2DA0,
119462306a36Sopenharmony_ci	0x2DC0,
119562306a36Sopenharmony_ci	0x2DE0,
119662306a36Sopenharmony_ci	0x2E00,
119762306a36Sopenharmony_ci	0x2E20
119862306a36Sopenharmony_ci};
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_cistatic const u32 src_delay_buffer_addr[DSP_MAX_SRC_NR] = {
120162306a36Sopenharmony_ci	0x2480,
120262306a36Sopenharmony_ci	0x2500,
120362306a36Sopenharmony_ci	0x2580,
120462306a36Sopenharmony_ci	0x2600,
120562306a36Sopenharmony_ci	0x2680,
120662306a36Sopenharmony_ci	0x2700,
120762306a36Sopenharmony_ci	0x2780,
120862306a36Sopenharmony_ci	0x2800,
120962306a36Sopenharmony_ci	0x2880,
121062306a36Sopenharmony_ci	0x2900,
121162306a36Sopenharmony_ci	0x2980,
121262306a36Sopenharmony_ci	0x2A00,
121362306a36Sopenharmony_ci	0x2A80,
121462306a36Sopenharmony_ci	0x2B00
121562306a36Sopenharmony_ci};
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_cistruct dsp_pcm_channel_descriptor *
121862306a36Sopenharmony_cics46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
121962306a36Sopenharmony_ci			       u32 sample_rate, void * private_data,
122062306a36Sopenharmony_ci			       u32 hw_dma_addr,
122162306a36Sopenharmony_ci			       int pcm_channel_id)
122262306a36Sopenharmony_ci{
122362306a36Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
122462306a36Sopenharmony_ci	struct dsp_scb_descriptor * src_scb = NULL, * pcm_scb, * mixer_scb = NULL;
122562306a36Sopenharmony_ci	struct dsp_scb_descriptor * src_parent_scb = NULL;
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci	/* struct dsp_scb_descriptor * pcm_parent_scb; */
122862306a36Sopenharmony_ci	char scb_name[DSP_MAX_SCB_NAME];
122962306a36Sopenharmony_ci	int i, pcm_index = -1, insert_point, src_index = -1, pass_through = 0;
123062306a36Sopenharmony_ci	unsigned long flags;
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	switch (pcm_channel_id) {
123362306a36Sopenharmony_ci	case DSP_PCM_MAIN_CHANNEL:
123462306a36Sopenharmony_ci		mixer_scb = ins->master_mix_scb;
123562306a36Sopenharmony_ci		break;
123662306a36Sopenharmony_ci	case DSP_PCM_REAR_CHANNEL:
123762306a36Sopenharmony_ci		mixer_scb = ins->rear_mix_scb;
123862306a36Sopenharmony_ci		break;
123962306a36Sopenharmony_ci	case DSP_PCM_CENTER_LFE_CHANNEL:
124062306a36Sopenharmony_ci		mixer_scb = ins->center_lfe_mix_scb;
124162306a36Sopenharmony_ci		break;
124262306a36Sopenharmony_ci	case DSP_PCM_S71_CHANNEL:
124362306a36Sopenharmony_ci		/* TODO */
124462306a36Sopenharmony_ci		snd_BUG();
124562306a36Sopenharmony_ci		break;
124662306a36Sopenharmony_ci	case DSP_IEC958_CHANNEL:
124762306a36Sopenharmony_ci		if (snd_BUG_ON(!ins->asynch_tx_scb))
124862306a36Sopenharmony_ci			return NULL;
124962306a36Sopenharmony_ci		mixer_scb = ins->asynch_tx_scb;
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci		/* if sample rate is set to 48khz we pass
125262306a36Sopenharmony_ci		   the Sample Rate Converted (which could
125362306a36Sopenharmony_ci		   alter the raw data stream ...) */
125462306a36Sopenharmony_ci		if (sample_rate == 48000) {
125562306a36Sopenharmony_ci			dev_dbg(chip->card->dev, "IEC958 pass through\n");
125662306a36Sopenharmony_ci			/* Hack to bypass creating a new SRC */
125762306a36Sopenharmony_ci			pass_through = 1;
125862306a36Sopenharmony_ci		}
125962306a36Sopenharmony_ci		break;
126062306a36Sopenharmony_ci	default:
126162306a36Sopenharmony_ci		snd_BUG();
126262306a36Sopenharmony_ci		return NULL;
126362306a36Sopenharmony_ci	}
126462306a36Sopenharmony_ci	/* default sample rate is 44100 */
126562306a36Sopenharmony_ci	if (!sample_rate) sample_rate = 44100;
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci	/* search for a already created SRC SCB with the same sample rate */
126862306a36Sopenharmony_ci	for (i = 0; i < DSP_MAX_PCM_CHANNELS &&
126962306a36Sopenharmony_ci		     (pcm_index == -1 || src_scb == NULL); ++i) {
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci		/* virtual channel reserved
127262306a36Sopenharmony_ci		   for capture */
127362306a36Sopenharmony_ci		if (i == CS46XX_DSP_CAPTURE_CHANNEL) continue;
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci		if (ins->pcm_channels[i].active) {
127662306a36Sopenharmony_ci			if (!src_scb &&
127762306a36Sopenharmony_ci			    ins->pcm_channels[i].sample_rate == sample_rate &&
127862306a36Sopenharmony_ci			    ins->pcm_channels[i].mixer_scb == mixer_scb) {
127962306a36Sopenharmony_ci				src_scb = ins->pcm_channels[i].src_scb;
128062306a36Sopenharmony_ci				ins->pcm_channels[i].src_scb->ref_count ++;
128162306a36Sopenharmony_ci				src_index = ins->pcm_channels[i].src_slot;
128262306a36Sopenharmony_ci			}
128362306a36Sopenharmony_ci		} else if (pcm_index == -1) {
128462306a36Sopenharmony_ci			pcm_index = i;
128562306a36Sopenharmony_ci		}
128662306a36Sopenharmony_ci	}
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	if (pcm_index == -1) {
128962306a36Sopenharmony_ci		dev_err(chip->card->dev, "dsp_spos: no free PCM channel\n");
129062306a36Sopenharmony_ci		return NULL;
129162306a36Sopenharmony_ci	}
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	if (src_scb == NULL) {
129462306a36Sopenharmony_ci		if (ins->nsrc_scb >= DSP_MAX_SRC_NR) {
129562306a36Sopenharmony_ci			dev_err(chip->card->dev,
129662306a36Sopenharmony_ci				"dsp_spos: too many SRC instances\n!");
129762306a36Sopenharmony_ci			return NULL;
129862306a36Sopenharmony_ci		}
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci		/* find a free slot */
130162306a36Sopenharmony_ci		for (i = 0; i < DSP_MAX_SRC_NR; ++i) {
130262306a36Sopenharmony_ci			if (ins->src_scb_slots[i] == 0) {
130362306a36Sopenharmony_ci				src_index = i;
130462306a36Sopenharmony_ci				ins->src_scb_slots[i] = 1;
130562306a36Sopenharmony_ci				break;
130662306a36Sopenharmony_ci			}
130762306a36Sopenharmony_ci		}
130862306a36Sopenharmony_ci		if (snd_BUG_ON(src_index == -1))
130962306a36Sopenharmony_ci			return NULL;
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci		/* we need to create a new SRC SCB */
131262306a36Sopenharmony_ci		if (mixer_scb->sub_list_ptr == ins->the_null_scb) {
131362306a36Sopenharmony_ci			src_parent_scb = mixer_scb;
131462306a36Sopenharmony_ci			insert_point = SCB_ON_PARENT_SUBLIST_SCB;
131562306a36Sopenharmony_ci		} else {
131662306a36Sopenharmony_ci			src_parent_scb = find_next_free_scb(chip,mixer_scb->sub_list_ptr);
131762306a36Sopenharmony_ci			insert_point = SCB_ON_PARENT_NEXT_SCB;
131862306a36Sopenharmony_ci		}
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci		snprintf (scb_name,DSP_MAX_SCB_NAME,"SrcTask_SCB%d",src_index);
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci		dev_dbg(chip->card->dev,
132362306a36Sopenharmony_ci			"dsp_spos: creating SRC \"%s\"\n", scb_name);
132462306a36Sopenharmony_ci		src_scb = cs46xx_dsp_create_src_task_scb(chip,scb_name,
132562306a36Sopenharmony_ci							 sample_rate,
132662306a36Sopenharmony_ci							 src_output_buffer_addr[src_index],
132762306a36Sopenharmony_ci							 src_delay_buffer_addr[src_index],
132862306a36Sopenharmony_ci							 /* 0x400 - 0x600 source SCBs */
132962306a36Sopenharmony_ci							 0x400 + (src_index * 0x10) ,
133062306a36Sopenharmony_ci							 src_parent_scb,
133162306a36Sopenharmony_ci							 insert_point,
133262306a36Sopenharmony_ci							 pass_through);
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci		if (!src_scb) {
133562306a36Sopenharmony_ci			dev_err(chip->card->dev,
133662306a36Sopenharmony_ci				"dsp_spos: failed to create SRCtaskSCB\n");
133762306a36Sopenharmony_ci			return NULL;
133862306a36Sopenharmony_ci		}
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci		/* cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate); */
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci		ins->nsrc_scb ++;
134362306a36Sopenharmony_ci	}
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	snprintf (scb_name,DSP_MAX_SCB_NAME,"PCMReader_SCB%d",pcm_index);
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci	dev_dbg(chip->card->dev, "dsp_spos: creating PCM \"%s\" (%d)\n",
134962306a36Sopenharmony_ci		scb_name, pcm_channel_id);
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	pcm_scb = cs46xx_dsp_create_pcm_reader_scb(chip,scb_name,
135262306a36Sopenharmony_ci						   pcm_reader_buffer_addr[pcm_index],
135362306a36Sopenharmony_ci						   /* 0x200 - 400 PCMreader SCBs */
135462306a36Sopenharmony_ci						   (pcm_index * 0x10) + 0x200,
135562306a36Sopenharmony_ci						   pcm_index,    /* virtual channel 0-31 */
135662306a36Sopenharmony_ci						   hw_dma_addr,  /* pcm hw addr */
135762306a36Sopenharmony_ci                           NULL,         /* parent SCB ptr */
135862306a36Sopenharmony_ci                           0             /* insert point */
135962306a36Sopenharmony_ci                           );
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci	if (!pcm_scb) {
136262306a36Sopenharmony_ci		dev_err(chip->card->dev,
136362306a36Sopenharmony_ci			"dsp_spos: failed to create PCMreaderSCB\n");
136462306a36Sopenharmony_ci		return NULL;
136562306a36Sopenharmony_ci	}
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	spin_lock_irqsave(&chip->reg_lock, flags);
136862306a36Sopenharmony_ci	ins->pcm_channels[pcm_index].sample_rate = sample_rate;
136962306a36Sopenharmony_ci	ins->pcm_channels[pcm_index].pcm_reader_scb = pcm_scb;
137062306a36Sopenharmony_ci	ins->pcm_channels[pcm_index].src_scb = src_scb;
137162306a36Sopenharmony_ci	ins->pcm_channels[pcm_index].unlinked = 1;
137262306a36Sopenharmony_ci	ins->pcm_channels[pcm_index].private_data = private_data;
137362306a36Sopenharmony_ci	ins->pcm_channels[pcm_index].src_slot = src_index;
137462306a36Sopenharmony_ci	ins->pcm_channels[pcm_index].active = 1;
137562306a36Sopenharmony_ci	ins->pcm_channels[pcm_index].pcm_slot = pcm_index;
137662306a36Sopenharmony_ci	ins->pcm_channels[pcm_index].mixer_scb = mixer_scb;
137762306a36Sopenharmony_ci	ins->npcm_channels ++;
137862306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->reg_lock, flags);
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci	return (ins->pcm_channels + pcm_index);
138162306a36Sopenharmony_ci}
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ciint cs46xx_dsp_pcm_channel_set_period (struct snd_cs46xx * chip,
138462306a36Sopenharmony_ci				       struct dsp_pcm_channel_descriptor * pcm_channel,
138562306a36Sopenharmony_ci				       int period_size)
138662306a36Sopenharmony_ci{
138762306a36Sopenharmony_ci	u32 temp = snd_cs46xx_peek (chip,pcm_channel->pcm_reader_scb->address << 2);
138862306a36Sopenharmony_ci	temp &= ~DMA_RQ_C1_SOURCE_SIZE_MASK;
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci	switch (period_size) {
139162306a36Sopenharmony_ci	case 2048:
139262306a36Sopenharmony_ci		temp |= DMA_RQ_C1_SOURCE_MOD1024;
139362306a36Sopenharmony_ci		break;
139462306a36Sopenharmony_ci	case 1024:
139562306a36Sopenharmony_ci		temp |= DMA_RQ_C1_SOURCE_MOD512;
139662306a36Sopenharmony_ci		break;
139762306a36Sopenharmony_ci	case 512:
139862306a36Sopenharmony_ci		temp |= DMA_RQ_C1_SOURCE_MOD256;
139962306a36Sopenharmony_ci		break;
140062306a36Sopenharmony_ci	case 256:
140162306a36Sopenharmony_ci		temp |= DMA_RQ_C1_SOURCE_MOD128;
140262306a36Sopenharmony_ci		break;
140362306a36Sopenharmony_ci	case 128:
140462306a36Sopenharmony_ci		temp |= DMA_RQ_C1_SOURCE_MOD64;
140562306a36Sopenharmony_ci		break;
140662306a36Sopenharmony_ci	case 64:
140762306a36Sopenharmony_ci		temp |= DMA_RQ_C1_SOURCE_MOD32;
140862306a36Sopenharmony_ci		break;
140962306a36Sopenharmony_ci	case 32:
141062306a36Sopenharmony_ci		temp |= DMA_RQ_C1_SOURCE_MOD16;
141162306a36Sopenharmony_ci		break;
141262306a36Sopenharmony_ci	default:
141362306a36Sopenharmony_ci		dev_dbg(chip->card->dev,
141462306a36Sopenharmony_ci			"period size (%d) not supported by HW\n", period_size);
141562306a36Sopenharmony_ci		return -EINVAL;
141662306a36Sopenharmony_ci	}
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci	snd_cs46xx_poke (chip,pcm_channel->pcm_reader_scb->address << 2,temp);
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci	return 0;
142162306a36Sopenharmony_ci}
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ciint cs46xx_dsp_pcm_ostream_set_period (struct snd_cs46xx * chip,
142462306a36Sopenharmony_ci				       int period_size)
142562306a36Sopenharmony_ci{
142662306a36Sopenharmony_ci	u32 temp = snd_cs46xx_peek (chip,WRITEBACK_SCB_ADDR << 2);
142762306a36Sopenharmony_ci	temp &= ~DMA_RQ_C1_DEST_SIZE_MASK;
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	switch (period_size) {
143062306a36Sopenharmony_ci	case 2048:
143162306a36Sopenharmony_ci		temp |= DMA_RQ_C1_DEST_MOD1024;
143262306a36Sopenharmony_ci		break;
143362306a36Sopenharmony_ci	case 1024:
143462306a36Sopenharmony_ci		temp |= DMA_RQ_C1_DEST_MOD512;
143562306a36Sopenharmony_ci		break;
143662306a36Sopenharmony_ci	case 512:
143762306a36Sopenharmony_ci		temp |= DMA_RQ_C1_DEST_MOD256;
143862306a36Sopenharmony_ci		break;
143962306a36Sopenharmony_ci	case 256:
144062306a36Sopenharmony_ci		temp |= DMA_RQ_C1_DEST_MOD128;
144162306a36Sopenharmony_ci		break;
144262306a36Sopenharmony_ci	case 128:
144362306a36Sopenharmony_ci		temp |= DMA_RQ_C1_DEST_MOD64;
144462306a36Sopenharmony_ci		break;
144562306a36Sopenharmony_ci	case 64:
144662306a36Sopenharmony_ci		temp |= DMA_RQ_C1_DEST_MOD32;
144762306a36Sopenharmony_ci		break;
144862306a36Sopenharmony_ci	case 32:
144962306a36Sopenharmony_ci		temp |= DMA_RQ_C1_DEST_MOD16;
145062306a36Sopenharmony_ci		break;
145162306a36Sopenharmony_ci	default:
145262306a36Sopenharmony_ci		dev_dbg(chip->card->dev,
145362306a36Sopenharmony_ci			"period size (%d) not supported by HW\n", period_size);
145462306a36Sopenharmony_ci		return -EINVAL;
145562306a36Sopenharmony_ci	}
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci	snd_cs46xx_poke (chip,WRITEBACK_SCB_ADDR << 2,temp);
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci	return 0;
146062306a36Sopenharmony_ci}
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_civoid cs46xx_dsp_destroy_pcm_channel (struct snd_cs46xx * chip,
146362306a36Sopenharmony_ci				     struct dsp_pcm_channel_descriptor * pcm_channel)
146462306a36Sopenharmony_ci{
146562306a36Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
146662306a36Sopenharmony_ci	unsigned long flags;
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci	if (snd_BUG_ON(!pcm_channel->active ||
146962306a36Sopenharmony_ci		       ins->npcm_channels <= 0 ||
147062306a36Sopenharmony_ci		       pcm_channel->src_scb->ref_count <= 0))
147162306a36Sopenharmony_ci		return;
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci	spin_lock_irqsave(&chip->reg_lock, flags);
147462306a36Sopenharmony_ci	pcm_channel->unlinked = 1;
147562306a36Sopenharmony_ci	pcm_channel->active = 0;
147662306a36Sopenharmony_ci	pcm_channel->private_data = NULL;
147762306a36Sopenharmony_ci	pcm_channel->src_scb->ref_count --;
147862306a36Sopenharmony_ci	ins->npcm_channels --;
147962306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->reg_lock, flags);
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	cs46xx_dsp_remove_scb(chip,pcm_channel->pcm_reader_scb);
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	if (!pcm_channel->src_scb->ref_count) {
148462306a36Sopenharmony_ci		cs46xx_dsp_remove_scb(chip,pcm_channel->src_scb);
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci		if (snd_BUG_ON(pcm_channel->src_slot < 0 ||
148762306a36Sopenharmony_ci			       pcm_channel->src_slot >= DSP_MAX_SRC_NR))
148862306a36Sopenharmony_ci			return;
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci		ins->src_scb_slots[pcm_channel->src_slot] = 0;
149162306a36Sopenharmony_ci		ins->nsrc_scb --;
149262306a36Sopenharmony_ci	}
149362306a36Sopenharmony_ci}
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ciint cs46xx_dsp_pcm_unlink (struct snd_cs46xx * chip,
149662306a36Sopenharmony_ci			   struct dsp_pcm_channel_descriptor * pcm_channel)
149762306a36Sopenharmony_ci{
149862306a36Sopenharmony_ci	unsigned long flags;
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	if (snd_BUG_ON(!pcm_channel->active ||
150162306a36Sopenharmony_ci		       chip->dsp_spos_instance->npcm_channels <= 0))
150262306a36Sopenharmony_ci		return -EIO;
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci	spin_lock_irqsave(&chip->reg_lock, flags);
150562306a36Sopenharmony_ci	if (pcm_channel->unlinked) {
150662306a36Sopenharmony_ci		spin_unlock_irqrestore(&chip->reg_lock, flags);
150762306a36Sopenharmony_ci		return -EIO;
150862306a36Sopenharmony_ci	}
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci	pcm_channel->unlinked = 1;
151162306a36Sopenharmony_ci
151262306a36Sopenharmony_ci	_dsp_unlink_scb (chip,pcm_channel->pcm_reader_scb);
151362306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->reg_lock, flags);
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci	return 0;
151662306a36Sopenharmony_ci}
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ciint cs46xx_dsp_pcm_link (struct snd_cs46xx * chip,
151962306a36Sopenharmony_ci			 struct dsp_pcm_channel_descriptor * pcm_channel)
152062306a36Sopenharmony_ci{
152162306a36Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
152262306a36Sopenharmony_ci	struct dsp_scb_descriptor * parent_scb;
152362306a36Sopenharmony_ci	struct dsp_scb_descriptor * src_scb = pcm_channel->src_scb;
152462306a36Sopenharmony_ci	unsigned long flags;
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	spin_lock_irqsave(&chip->reg_lock, flags);
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	if (pcm_channel->unlinked == 0) {
152962306a36Sopenharmony_ci		spin_unlock_irqrestore(&chip->reg_lock, flags);
153062306a36Sopenharmony_ci		return -EIO;
153162306a36Sopenharmony_ci	}
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	parent_scb = src_scb;
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci	if (src_scb->sub_list_ptr != ins->the_null_scb) {
153662306a36Sopenharmony_ci		src_scb->sub_list_ptr->parent_scb_ptr = pcm_channel->pcm_reader_scb;
153762306a36Sopenharmony_ci		pcm_channel->pcm_reader_scb->next_scb_ptr = src_scb->sub_list_ptr;
153862306a36Sopenharmony_ci	}
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci	src_scb->sub_list_ptr = pcm_channel->pcm_reader_scb;
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	snd_BUG_ON(pcm_channel->pcm_reader_scb->parent_scb_ptr);
154362306a36Sopenharmony_ci	pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb;
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci	/* update SCB entry in DSP RAM */
154662306a36Sopenharmony_ci	cs46xx_dsp_spos_update_scb(chip,pcm_channel->pcm_reader_scb);
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci	/* update parent SCB entry */
154962306a36Sopenharmony_ci	cs46xx_dsp_spos_update_scb(chip,parent_scb);
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci	pcm_channel->unlinked = 0;
155262306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->reg_lock, flags);
155362306a36Sopenharmony_ci	return 0;
155462306a36Sopenharmony_ci}
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_cistruct dsp_scb_descriptor *
155762306a36Sopenharmony_cics46xx_add_record_source (struct snd_cs46xx *chip, struct dsp_scb_descriptor * source,
155862306a36Sopenharmony_ci			  u16 addr, char * scb_name)
155962306a36Sopenharmony_ci{
156062306a36Sopenharmony_ci  	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
156162306a36Sopenharmony_ci	struct dsp_scb_descriptor * parent;
156262306a36Sopenharmony_ci	struct dsp_scb_descriptor * pcm_input;
156362306a36Sopenharmony_ci	int insert_point;
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci	if (snd_BUG_ON(!ins->record_mixer_scb))
156662306a36Sopenharmony_ci		return NULL;
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci	if (ins->record_mixer_scb->sub_list_ptr != ins->the_null_scb) {
156962306a36Sopenharmony_ci		parent = find_next_free_scb (chip,ins->record_mixer_scb->sub_list_ptr);
157062306a36Sopenharmony_ci		insert_point = SCB_ON_PARENT_NEXT_SCB;
157162306a36Sopenharmony_ci	} else {
157262306a36Sopenharmony_ci		parent = ins->record_mixer_scb;
157362306a36Sopenharmony_ci		insert_point = SCB_ON_PARENT_SUBLIST_SCB;
157462306a36Sopenharmony_ci	}
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	pcm_input = cs46xx_dsp_create_pcm_serial_input_scb(chip,scb_name,addr,
157762306a36Sopenharmony_ci							   source, parent,
157862306a36Sopenharmony_ci							   insert_point);
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci	return pcm_input;
158162306a36Sopenharmony_ci}
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_ciint cs46xx_src_unlink(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
158462306a36Sopenharmony_ci{
158562306a36Sopenharmony_ci	unsigned long flags;
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci	if (snd_BUG_ON(!src->parent_scb_ptr))
158862306a36Sopenharmony_ci		return -EINVAL;
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci	/* mute SCB */
159162306a36Sopenharmony_ci	cs46xx_dsp_scb_set_volume (chip,src,0,0);
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci	spin_lock_irqsave(&chip->reg_lock, flags);
159462306a36Sopenharmony_ci	_dsp_unlink_scb (chip,src);
159562306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->reg_lock, flags);
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ci	return 0;
159862306a36Sopenharmony_ci}
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ciint cs46xx_src_link(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
160162306a36Sopenharmony_ci{
160262306a36Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
160362306a36Sopenharmony_ci	struct dsp_scb_descriptor * parent_scb;
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci	if (snd_BUG_ON(src->parent_scb_ptr))
160662306a36Sopenharmony_ci		return -EINVAL;
160762306a36Sopenharmony_ci	if (snd_BUG_ON(!ins->master_mix_scb))
160862306a36Sopenharmony_ci		return -EINVAL;
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci	if (ins->master_mix_scb->sub_list_ptr != ins->the_null_scb) {
161162306a36Sopenharmony_ci		parent_scb = find_next_free_scb (chip,ins->master_mix_scb->sub_list_ptr);
161262306a36Sopenharmony_ci		parent_scb->next_scb_ptr = src;
161362306a36Sopenharmony_ci	} else {
161462306a36Sopenharmony_ci		parent_scb = ins->master_mix_scb;
161562306a36Sopenharmony_ci		parent_scb->sub_list_ptr = src;
161662306a36Sopenharmony_ci	}
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci	src->parent_scb_ptr = parent_scb;
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	/* update entry in DSP RAM */
162162306a36Sopenharmony_ci	cs46xx_dsp_spos_update_scb(chip,parent_scb);
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	return 0;
162462306a36Sopenharmony_ci}
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_ciint cs46xx_dsp_enable_spdif_out (struct snd_cs46xx *chip)
162762306a36Sopenharmony_ci{
162862306a36Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci	if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
163162306a36Sopenharmony_ci		cs46xx_dsp_enable_spdif_hw (chip);
163262306a36Sopenharmony_ci	}
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci	/* dont touch anything if SPDIF is open */
163562306a36Sopenharmony_ci	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
163662306a36Sopenharmony_ci		/* when cs46xx_iec958_post_close(...) is called it
163762306a36Sopenharmony_ci		   will call this function if necessary depending on
163862306a36Sopenharmony_ci		   this bit */
163962306a36Sopenharmony_ci		ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_ci		return -EBUSY;
164262306a36Sopenharmony_ci	}
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci	if (snd_BUG_ON(ins->asynch_tx_scb))
164562306a36Sopenharmony_ci		return -EINVAL;
164662306a36Sopenharmony_ci	if (snd_BUG_ON(ins->master_mix_scb->next_scb_ptr !=
164762306a36Sopenharmony_ci		       ins->the_null_scb))
164862306a36Sopenharmony_ci		return -EINVAL;
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci	/* reset output snooper sample buffer pointer */
165162306a36Sopenharmony_ci	snd_cs46xx_poke (chip, (ins->ref_snoop_scb->address + 2) << 2,
165262306a36Sopenharmony_ci			 (OUTPUT_SNOOP_BUFFER + 0x10) << 0x10 );
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci	/* The asynch. transfer task */
165562306a36Sopenharmony_ci	ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
165662306a36Sopenharmony_ci								SPDIFO_SCB_INST,
165762306a36Sopenharmony_ci								SPDIFO_IP_OUTPUT_BUFFER1,
165862306a36Sopenharmony_ci								ins->master_mix_scb,
165962306a36Sopenharmony_ci								SCB_ON_PARENT_NEXT_SCB);
166062306a36Sopenharmony_ci	if (!ins->asynch_tx_scb) return -ENOMEM;
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ci	ins->spdif_pcm_input_scb = cs46xx_dsp_create_pcm_serial_input_scb(chip,"PCMSerialInput_II",
166362306a36Sopenharmony_ci									  PCMSERIALINII_SCB_ADDR,
166462306a36Sopenharmony_ci									  ins->ref_snoop_scb,
166562306a36Sopenharmony_ci									  ins->asynch_tx_scb,
166662306a36Sopenharmony_ci									  SCB_ON_PARENT_SUBLIST_SCB);
166762306a36Sopenharmony_ci
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci	if (!ins->spdif_pcm_input_scb) return -ENOMEM;
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci	/* monitor state */
167262306a36Sopenharmony_ci	ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
167362306a36Sopenharmony_ci
167462306a36Sopenharmony_ci	return 0;
167562306a36Sopenharmony_ci}
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ciint  cs46xx_dsp_disable_spdif_out (struct snd_cs46xx *chip)
167862306a36Sopenharmony_ci{
167962306a36Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci	/* dont touch anything if SPDIF is open */
168262306a36Sopenharmony_ci	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
168362306a36Sopenharmony_ci		ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
168462306a36Sopenharmony_ci		return -EBUSY;
168562306a36Sopenharmony_ci	}
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci	/* check integrety */
168862306a36Sopenharmony_ci	if (snd_BUG_ON(!ins->asynch_tx_scb))
168962306a36Sopenharmony_ci		return -EINVAL;
169062306a36Sopenharmony_ci	if (snd_BUG_ON(!ins->spdif_pcm_input_scb))
169162306a36Sopenharmony_ci		return -EINVAL;
169262306a36Sopenharmony_ci	if (snd_BUG_ON(ins->master_mix_scb->next_scb_ptr != ins->asynch_tx_scb))
169362306a36Sopenharmony_ci		return -EINVAL;
169462306a36Sopenharmony_ci	if (snd_BUG_ON(ins->asynch_tx_scb->parent_scb_ptr !=
169562306a36Sopenharmony_ci		       ins->master_mix_scb))
169662306a36Sopenharmony_ci		return -EINVAL;
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_ci	cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
169962306a36Sopenharmony_ci	cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci	ins->spdif_pcm_input_scb = NULL;
170262306a36Sopenharmony_ci	ins->asynch_tx_scb = NULL;
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci	/* clear buffer to prevent any undesired noise */
170562306a36Sopenharmony_ci	_dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
170662306a36Sopenharmony_ci
170762306a36Sopenharmony_ci	/* monitor state */
170862306a36Sopenharmony_ci	ins->spdif_status_out  &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_ci
171162306a36Sopenharmony_ci	return 0;
171262306a36Sopenharmony_ci}
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_ciint cs46xx_iec958_pre_open (struct snd_cs46xx *chip)
171562306a36Sopenharmony_ci{
171662306a36Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
171962306a36Sopenharmony_ci		/* remove AsynchFGTxSCB and PCMSerialInput_II */
172062306a36Sopenharmony_ci		cs46xx_dsp_disable_spdif_out (chip);
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci		/* save state */
172362306a36Sopenharmony_ci		ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
172462306a36Sopenharmony_ci	}
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	/* if not enabled already */
172762306a36Sopenharmony_ci	if ( !(ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
172862306a36Sopenharmony_ci		cs46xx_dsp_enable_spdif_hw (chip);
172962306a36Sopenharmony_ci	}
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci	/* Create the asynch. transfer task  for playback */
173262306a36Sopenharmony_ci	ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
173362306a36Sopenharmony_ci								SPDIFO_SCB_INST,
173462306a36Sopenharmony_ci								SPDIFO_IP_OUTPUT_BUFFER1,
173562306a36Sopenharmony_ci								ins->master_mix_scb,
173662306a36Sopenharmony_ci								SCB_ON_PARENT_NEXT_SCB);
173762306a36Sopenharmony_ci
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci	/* set spdif channel status value for streaming */
174062306a36Sopenharmony_ci	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_stream);
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ci	ins->spdif_status_out  |= DSP_SPDIF_STATUS_PLAYBACK_OPEN;
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_ci	return 0;
174562306a36Sopenharmony_ci}
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ciint cs46xx_iec958_post_close (struct snd_cs46xx *chip)
174862306a36Sopenharmony_ci{
174962306a36Sopenharmony_ci	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci	if (snd_BUG_ON(!ins->asynch_tx_scb))
175262306a36Sopenharmony_ci		return -EINVAL;
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci	ins->spdif_status_out  &= ~DSP_SPDIF_STATUS_PLAYBACK_OPEN;
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci	/* restore settings */
175762306a36Sopenharmony_ci	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_ci	/* deallocate stuff */
176062306a36Sopenharmony_ci	if (ins->spdif_pcm_input_scb != NULL) {
176162306a36Sopenharmony_ci		cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
176262306a36Sopenharmony_ci		ins->spdif_pcm_input_scb = NULL;
176362306a36Sopenharmony_ci	}
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci	cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
176662306a36Sopenharmony_ci	ins->asynch_tx_scb = NULL;
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_ci	/* clear buffer to prevent any undesired noise */
176962306a36Sopenharmony_ci	_dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	/* restore state */
177262306a36Sopenharmony_ci	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
177362306a36Sopenharmony_ci		cs46xx_dsp_enable_spdif_out (chip);
177462306a36Sopenharmony_ci	}
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci	return 0;
177762306a36Sopenharmony_ci}
1778