xref: /openbmc/linux/sound/pci/cs46xx/dsp_spos_scb_lib.c (revision 4b4193256c8d3bc3a5397b5cd9494c2ad386317d)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  */
41da177e4SLinus Torvalds 
51da177e4SLinus Torvalds /*
61da177e4SLinus Torvalds  * 2002-07 Benny Sjostrand benny@hostmobility.com
71da177e4SLinus Torvalds  */
81da177e4SLinus Torvalds 
91da177e4SLinus Torvalds 
106cbbfe1cSTakashi Iwai #include <linux/io.h>
111da177e4SLinus Torvalds #include <linux/delay.h>
121da177e4SLinus Torvalds #include <linux/pm.h>
131da177e4SLinus Torvalds #include <linux/init.h>
141da177e4SLinus Torvalds #include <linux/slab.h>
1562932df8SIngo Molnar #include <linux/mutex.h>
1662932df8SIngo Molnar 
171da177e4SLinus Torvalds #include <sound/core.h>
181da177e4SLinus Torvalds #include <sound/control.h>
191da177e4SLinus Torvalds #include <sound/info.h>
2081fcb170STakashi Iwai #include "cs46xx.h"
211da177e4SLinus Torvalds 
221da177e4SLinus Torvalds #include "cs46xx_lib.h"
231da177e4SLinus Torvalds #include "dsp_spos.h"
241da177e4SLinus Torvalds 
253d19f804STakashi Iwai struct proc_scb_info {
263d19f804STakashi Iwai 	struct dsp_scb_descriptor * scb_desc;
273d19f804STakashi Iwai 	struct snd_cs46xx *chip;
283d19f804STakashi Iwai };
291da177e4SLinus Torvalds 
remove_symbol(struct snd_cs46xx * chip,struct dsp_symbol_entry * symbol)303d19f804STakashi Iwai static void remove_symbol (struct snd_cs46xx * chip, struct dsp_symbol_entry * symbol)
311da177e4SLinus Torvalds {
323d19f804STakashi Iwai 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
331da177e4SLinus Torvalds 	int symbol_index = (int)(symbol - ins->symbol_table.symbols);
341da177e4SLinus Torvalds 
35da3cec35STakashi Iwai 	if (snd_BUG_ON(ins->symbol_table.nsymbols <= 0))
36da3cec35STakashi Iwai 		return;
37da3cec35STakashi Iwai 	if (snd_BUG_ON(symbol_index < 0 ||
38da3cec35STakashi Iwai 		       symbol_index >= ins->symbol_table.nsymbols))
39da3cec35STakashi Iwai 		return;
401da177e4SLinus Torvalds 
411da177e4SLinus Torvalds 	ins->symbol_table.symbols[symbol_index].deleted = 1;
421da177e4SLinus Torvalds 
431da177e4SLinus Torvalds 	if (symbol_index < ins->symbol_table.highest_frag_index) {
441da177e4SLinus Torvalds 		ins->symbol_table.highest_frag_index = symbol_index;
451da177e4SLinus Torvalds 	}
461da177e4SLinus Torvalds 
471da177e4SLinus Torvalds 	if (symbol_index == ins->symbol_table.nsymbols - 1)
481da177e4SLinus Torvalds 		ins->symbol_table.nsymbols --;
491da177e4SLinus Torvalds 
501da177e4SLinus Torvalds 	if (ins->symbol_table.highest_frag_index > ins->symbol_table.nsymbols) {
511da177e4SLinus Torvalds 		ins->symbol_table.highest_frag_index = ins->symbol_table.nsymbols;
521da177e4SLinus Torvalds 	}
531da177e4SLinus Torvalds 
541da177e4SLinus Torvalds }
551da177e4SLinus Torvalds 
5695bb6258STakashi Iwai #ifdef CONFIG_SND_PROC_FS
cs46xx_dsp_proc_scb_info_read(struct snd_info_entry * entry,struct snd_info_buffer * buffer)573d19f804STakashi Iwai static void cs46xx_dsp_proc_scb_info_read (struct snd_info_entry *entry,
583d19f804STakashi Iwai 					   struct snd_info_buffer *buffer)
591da177e4SLinus Torvalds {
603d19f804STakashi Iwai 	struct proc_scb_info * scb_info  = entry->private_data;
613d19f804STakashi Iwai 	struct dsp_scb_descriptor * scb = scb_info->scb_desc;
623d19f804STakashi Iwai 	struct snd_cs46xx *chip = scb_info->chip;
631da177e4SLinus Torvalds 	int j,col;
641da177e4SLinus Torvalds 	void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
651da177e4SLinus Torvalds 
6662932df8SIngo Molnar 	mutex_lock(&chip->spos_mutex);
671da177e4SLinus Torvalds 	snd_iprintf(buffer,"%04x %s:\n",scb->address,scb->scb_name);
681da177e4SLinus Torvalds 
691da177e4SLinus Torvalds 	for (col = 0,j = 0;j < 0x10; j++,col++) {
701da177e4SLinus Torvalds 		if (col == 4) {
711da177e4SLinus Torvalds 			snd_iprintf(buffer,"\n");
721da177e4SLinus Torvalds 			col = 0;
731da177e4SLinus Torvalds 		}
741da177e4SLinus Torvalds 		snd_iprintf(buffer,"%08x ",readl(dst + (scb->address + j) * sizeof(u32)));
751da177e4SLinus Torvalds 	}
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds 	snd_iprintf(buffer,"\n");
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds 	if (scb->parent_scb_ptr != NULL) {
801da177e4SLinus Torvalds 		snd_iprintf(buffer,"parent [%s:%04x] ",
811da177e4SLinus Torvalds 			    scb->parent_scb_ptr->scb_name,
821da177e4SLinus Torvalds 			    scb->parent_scb_ptr->address);
831da177e4SLinus Torvalds 	} else snd_iprintf(buffer,"parent [none] ");
841da177e4SLinus Torvalds 
851da177e4SLinus Torvalds 	snd_iprintf(buffer,"sub_list_ptr [%s:%04x]\nnext_scb_ptr [%s:%04x]  task_entry [%s:%04x]\n",
861da177e4SLinus Torvalds 		    scb->sub_list_ptr->scb_name,
871da177e4SLinus Torvalds 		    scb->sub_list_ptr->address,
881da177e4SLinus Torvalds 		    scb->next_scb_ptr->scb_name,
891da177e4SLinus Torvalds 		    scb->next_scb_ptr->address,
901da177e4SLinus Torvalds 		    scb->task_entry->symbol_name,
911da177e4SLinus Torvalds 		    scb->task_entry->address);
921da177e4SLinus Torvalds 
931da177e4SLinus Torvalds 	snd_iprintf(buffer,"index [%d] ref_count [%d]\n",scb->index,scb->ref_count);
9462932df8SIngo Molnar 	mutex_unlock(&chip->spos_mutex);
951da177e4SLinus Torvalds }
96adf1b3d2STakashi Iwai #endif
971da177e4SLinus Torvalds 
_dsp_unlink_scb(struct snd_cs46xx * chip,struct dsp_scb_descriptor * scb)983d19f804STakashi Iwai static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
991da177e4SLinus Torvalds {
1003d19f804STakashi Iwai 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1011da177e4SLinus Torvalds 
1021da177e4SLinus Torvalds 	if ( scb->parent_scb_ptr ) {
1031da177e4SLinus Torvalds 		/* unlink parent SCB */
104da3cec35STakashi Iwai 		if (snd_BUG_ON(scb->parent_scb_ptr->sub_list_ptr != scb &&
105da3cec35STakashi Iwai 			       scb->parent_scb_ptr->next_scb_ptr != scb))
106da3cec35STakashi Iwai 			return;
1071da177e4SLinus Torvalds 
1081da177e4SLinus Torvalds 		if (scb->parent_scb_ptr->sub_list_ptr == scb) {
1091da177e4SLinus Torvalds 
1101da177e4SLinus Torvalds 			if (scb->next_scb_ptr == ins->the_null_scb) {
1111da177e4SLinus Torvalds 				/* last and only node in parent sublist */
1121da177e4SLinus Torvalds 				scb->parent_scb_ptr->sub_list_ptr = scb->sub_list_ptr;
1131da177e4SLinus Torvalds 
1141da177e4SLinus Torvalds 				if (scb->sub_list_ptr != ins->the_null_scb) {
1151da177e4SLinus Torvalds 					scb->sub_list_ptr->parent_scb_ptr = scb->parent_scb_ptr;
1161da177e4SLinus Torvalds 				}
1171da177e4SLinus Torvalds 				scb->sub_list_ptr = ins->the_null_scb;
1181da177e4SLinus Torvalds 			} else {
1191da177e4SLinus Torvalds 				/* first node in parent sublist */
1201da177e4SLinus Torvalds 				scb->parent_scb_ptr->sub_list_ptr = scb->next_scb_ptr;
1211da177e4SLinus Torvalds 
1221da177e4SLinus Torvalds 				if (scb->next_scb_ptr != ins->the_null_scb) {
1231da177e4SLinus Torvalds 					/* update next node parent ptr. */
1241da177e4SLinus Torvalds 					scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
1251da177e4SLinus Torvalds 				}
1261da177e4SLinus Torvalds 				scb->next_scb_ptr = ins->the_null_scb;
1271da177e4SLinus Torvalds 			}
1281da177e4SLinus Torvalds 		} else {
1291da177e4SLinus Torvalds 			scb->parent_scb_ptr->next_scb_ptr = scb->next_scb_ptr;
1301da177e4SLinus Torvalds 
1311da177e4SLinus Torvalds 			if (scb->next_scb_ptr != ins->the_null_scb) {
1321da177e4SLinus Torvalds 				/* update next node parent ptr. */
1331da177e4SLinus Torvalds 				scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
1341da177e4SLinus Torvalds 			}
1351da177e4SLinus Torvalds 			scb->next_scb_ptr = ins->the_null_scb;
1361da177e4SLinus Torvalds 		}
1371da177e4SLinus Torvalds 
1381da177e4SLinus Torvalds 		/* update parent first entry in DSP RAM */
1391da177e4SLinus Torvalds 		cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
1401da177e4SLinus Torvalds 
1411da177e4SLinus Torvalds 		/* then update entry in DSP RAM */
1421da177e4SLinus Torvalds 		cs46xx_dsp_spos_update_scb(chip,scb);
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds 		scb->parent_scb_ptr = NULL;
1451da177e4SLinus Torvalds 	}
1461da177e4SLinus Torvalds }
1471da177e4SLinus Torvalds 
_dsp_clear_sample_buffer(struct snd_cs46xx * chip,u32 sample_buffer_addr,int dword_count)1483d19f804STakashi Iwai static void _dsp_clear_sample_buffer (struct snd_cs46xx *chip, u32 sample_buffer_addr,
1493d19f804STakashi Iwai 				      int dword_count)
1501da177e4SLinus Torvalds {
1511da177e4SLinus Torvalds 	void __iomem *dst = chip->region.idx[2].remap_addr + sample_buffer_addr;
1521da177e4SLinus Torvalds 	int i;
1531da177e4SLinus Torvalds 
1541da177e4SLinus Torvalds 	for (i = 0; i < dword_count ; ++i ) {
1551da177e4SLinus Torvalds 		writel(0, dst);
1561da177e4SLinus Torvalds 		dst += 4;
1571da177e4SLinus Torvalds 	}
1581da177e4SLinus Torvalds }
1591da177e4SLinus Torvalds 
cs46xx_dsp_remove_scb(struct snd_cs46xx * chip,struct dsp_scb_descriptor * scb)1603d19f804STakashi Iwai void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
1611da177e4SLinus Torvalds {
1623d19f804STakashi Iwai 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
163c6482ddeSArjan van de Ven 	unsigned long flags;
1641da177e4SLinus Torvalds 
1651da177e4SLinus Torvalds 	/* check integrety */
166da3cec35STakashi Iwai 	if (snd_BUG_ON(scb->index < 0 ||
167da3cec35STakashi Iwai 		       scb->index >= ins->nscb ||
168da3cec35STakashi Iwai 		       (ins->scbs + scb->index) != scb))
169da3cec35STakashi Iwai 		return;
1701da177e4SLinus Torvalds 
1711da177e4SLinus Torvalds #if 0
1721da177e4SLinus Torvalds 	/* can't remove a SCB with childs before
1731da177e4SLinus Torvalds 	   removing childs first  */
174da3cec35STakashi Iwai 	if (snd_BUG_ON(scb->sub_list_ptr != ins->the_null_scb ||
175da3cec35STakashi Iwai 		       scb->next_scb_ptr != ins->the_null_scb))
176da3cec35STakashi Iwai 		goto _end;
1771da177e4SLinus Torvalds #endif
1781da177e4SLinus Torvalds 
17941116e92STakashi Iwai 	spin_lock_irqsave(&chip->reg_lock, flags);
1801da177e4SLinus Torvalds 	_dsp_unlink_scb (chip,scb);
18141116e92STakashi Iwai 	spin_unlock_irqrestore(&chip->reg_lock, flags);
1821da177e4SLinus Torvalds 
1831da177e4SLinus Torvalds 	cs46xx_dsp_proc_free_scb_desc(scb);
184da3cec35STakashi Iwai 	if (snd_BUG_ON(!scb->scb_symbol))
185da3cec35STakashi Iwai 		return;
1861da177e4SLinus Torvalds 	remove_symbol (chip,scb->scb_symbol);
1871da177e4SLinus Torvalds 
1881da177e4SLinus Torvalds 	ins->scbs[scb->index].deleted = 1;
189c7561cd8STakashi Iwai #ifdef CONFIG_PM_SLEEP
19041116e92STakashi Iwai 	kfree(ins->scbs[scb->index].data);
19141116e92STakashi Iwai 	ins->scbs[scb->index].data = NULL;
19241116e92STakashi Iwai #endif
1931da177e4SLinus Torvalds 
1941da177e4SLinus Torvalds 	if (scb->index < ins->scb_highest_frag_index)
1951da177e4SLinus Torvalds 		ins->scb_highest_frag_index = scb->index;
1961da177e4SLinus Torvalds 
1971da177e4SLinus Torvalds 	if (scb->index == ins->nscb - 1) {
1981da177e4SLinus Torvalds 		ins->nscb --;
1991da177e4SLinus Torvalds 	}
2001da177e4SLinus Torvalds 
2011da177e4SLinus Torvalds 	if (ins->scb_highest_frag_index > ins->nscb) {
2021da177e4SLinus Torvalds 		ins->scb_highest_frag_index = ins->nscb;
2031da177e4SLinus Torvalds 	}
2041da177e4SLinus Torvalds 
2051da177e4SLinus Torvalds #if 0
2061da177e4SLinus Torvalds 	/* !!!! THIS IS A PIECE OF SHIT MADE BY ME !!! */
2071da177e4SLinus Torvalds 	for(i = scb->index + 1;i < ins->nscb; ++i) {
2081da177e4SLinus Torvalds 		ins->scbs[i - 1].index = i - 1;
2091da177e4SLinus Torvalds 	}
2101da177e4SLinus Torvalds #endif
2111da177e4SLinus Torvalds }
2121da177e4SLinus Torvalds 
2131da177e4SLinus Torvalds 
21495bb6258STakashi Iwai #ifdef CONFIG_SND_PROC_FS
cs46xx_dsp_proc_free_scb_desc(struct dsp_scb_descriptor * scb)2153d19f804STakashi Iwai void cs46xx_dsp_proc_free_scb_desc (struct dsp_scb_descriptor * scb)
2161da177e4SLinus Torvalds {
2171da177e4SLinus Torvalds 	if (scb->proc_info) {
2183d19f804STakashi Iwai 		struct proc_scb_info * scb_info = scb->proc_info->private_data;
2192b96a7f1STakashi Iwai 		struct snd_cs46xx *chip = scb_info->chip;
2201da177e4SLinus Torvalds 
2212b96a7f1STakashi Iwai 		dev_dbg(chip->card->dev,
2222b96a7f1STakashi Iwai 			"cs46xx_dsp_proc_free_scb_desc: freeing %s\n",
2232b96a7f1STakashi Iwai 			scb->scb_name);
2241da177e4SLinus Torvalds 
225746d4a02STakashi Iwai 		snd_info_free_entry(scb->proc_info);
2261da177e4SLinus Torvalds 		scb->proc_info = NULL;
2271da177e4SLinus Torvalds 
2281da177e4SLinus Torvalds 		kfree (scb_info);
2291da177e4SLinus Torvalds 	}
2301da177e4SLinus Torvalds }
2311da177e4SLinus Torvalds 
cs46xx_dsp_proc_register_scb_desc(struct snd_cs46xx * chip,struct dsp_scb_descriptor * scb)2323d19f804STakashi Iwai void cs46xx_dsp_proc_register_scb_desc (struct snd_cs46xx *chip,
2333d19f804STakashi Iwai 					struct dsp_scb_descriptor * scb)
2341da177e4SLinus Torvalds {
2353d19f804STakashi Iwai 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
2363d19f804STakashi Iwai 	struct snd_info_entry * entry;
2373d19f804STakashi Iwai 	struct proc_scb_info * scb_info;
2381da177e4SLinus Torvalds 
2391da177e4SLinus Torvalds 	/* register to proc */
2401da177e4SLinus Torvalds 	if (ins->snd_card != NULL && ins->proc_dsp_dir != NULL &&
2411da177e4SLinus Torvalds 	    scb->proc_info == NULL) {
2421da177e4SLinus Torvalds 
2430b2338a9STakashi Iwai 		entry = snd_info_create_card_entry(ins->snd_card, scb->scb_name,
2440b2338a9STakashi Iwai 						   ins->proc_dsp_dir);
2450b2338a9STakashi Iwai 		if (entry) {
2463d19f804STakashi Iwai 			scb_info = kmalloc(sizeof(struct proc_scb_info), GFP_KERNEL);
2471da177e4SLinus Torvalds 			if (!scb_info) {
2481da177e4SLinus Torvalds 				snd_info_free_entry(entry);
2491da177e4SLinus Torvalds 				entry = NULL;
2501da177e4SLinus Torvalds 				goto out;
2511da177e4SLinus Torvalds 			}
2521da177e4SLinus Torvalds 
2531da177e4SLinus Torvalds 			scb_info->chip = chip;
2541da177e4SLinus Torvalds 			scb_info->scb_desc = scb;
2550b2338a9STakashi Iwai 			snd_info_set_text_ops(entry, scb_info,
2560b2338a9STakashi Iwai 					      cs46xx_dsp_proc_scb_info_read);
2571da177e4SLinus Torvalds 		}
2581da177e4SLinus Torvalds out:
2591da177e4SLinus Torvalds 		scb->proc_info = entry;
2601da177e4SLinus Torvalds 	}
2611da177e4SLinus Torvalds }
26295bb6258STakashi Iwai #endif /* CONFIG_SND_PROC_FS */
2631da177e4SLinus Torvalds 
2643d19f804STakashi Iwai static struct dsp_scb_descriptor *
_dsp_create_generic_scb(struct snd_cs46xx * chip,char * name,u32 * scb_data,u32 dest,struct dsp_symbol_entry * task_entry,struct dsp_scb_descriptor * parent_scb,int scb_child_type)2653d19f804STakashi Iwai _dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32 dest,
2663d19f804STakashi Iwai                          struct dsp_symbol_entry * task_entry,
2673d19f804STakashi Iwai                          struct dsp_scb_descriptor * parent_scb,
2681da177e4SLinus Torvalds                          int scb_child_type)
2691da177e4SLinus Torvalds {
2703d19f804STakashi Iwai 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
2713d19f804STakashi Iwai 	struct dsp_scb_descriptor * scb;
2721da177e4SLinus Torvalds 
2731da177e4SLinus Torvalds 	unsigned long flags;
2741da177e4SLinus Torvalds 
275da3cec35STakashi Iwai 	if (snd_BUG_ON(!ins->the_null_scb))
276da3cec35STakashi Iwai 		return NULL;
2771da177e4SLinus Torvalds 
2781da177e4SLinus Torvalds 	/* fill the data that will be wroten to DSP */
2791da177e4SLinus Torvalds 	scb_data[SCBsubListPtr] =
2801da177e4SLinus Torvalds 		(ins->the_null_scb->address << 0x10) | ins->the_null_scb->address;
2811da177e4SLinus Torvalds 
2821da177e4SLinus Torvalds 	scb_data[SCBfuncEntryPtr] &= 0xFFFF0000;
2831da177e4SLinus Torvalds 	scb_data[SCBfuncEntryPtr] |= task_entry->address;
2841da177e4SLinus Torvalds 
2852b96a7f1STakashi Iwai 	dev_dbg(chip->card->dev, "dsp_spos: creating SCB <%s>\n", name);
2861da177e4SLinus Torvalds 
2871da177e4SLinus Torvalds 	scb = cs46xx_dsp_create_scb(chip,name,scb_data,dest);
2881da177e4SLinus Torvalds 
2891da177e4SLinus Torvalds 
2901da177e4SLinus Torvalds 	scb->sub_list_ptr = ins->the_null_scb;
2911da177e4SLinus Torvalds 	scb->next_scb_ptr = ins->the_null_scb;
2921da177e4SLinus Torvalds 
2931da177e4SLinus Torvalds 	scb->parent_scb_ptr = parent_scb;
2941da177e4SLinus Torvalds 	scb->task_entry = task_entry;
2951da177e4SLinus Torvalds 
2961da177e4SLinus Torvalds 
2971da177e4SLinus Torvalds 	/* update parent SCB */
2981da177e4SLinus Torvalds 	if (scb->parent_scb_ptr) {
2991da177e4SLinus Torvalds #if 0
3002b96a7f1STakashi Iwai 		dev_dbg(chip->card->dev,
3012b96a7f1STakashi Iwai 			"scb->parent_scb_ptr = %s\n",
3022b96a7f1STakashi Iwai 			scb->parent_scb_ptr->scb_name);
3032b96a7f1STakashi Iwai 		dev_dbg(chip->card->dev,
3042b96a7f1STakashi Iwai 			"scb->parent_scb_ptr->next_scb_ptr = %s\n",
3052b96a7f1STakashi Iwai 			scb->parent_scb_ptr->next_scb_ptr->scb_name);
3062b96a7f1STakashi Iwai 		dev_dbg(chip->card->dev,
3072b96a7f1STakashi Iwai 			"scb->parent_scb_ptr->sub_list_ptr = %s\n",
3082b96a7f1STakashi Iwai 			scb->parent_scb_ptr->sub_list_ptr->scb_name);
3091da177e4SLinus Torvalds #endif
3101da177e4SLinus Torvalds 		/* link to  parent SCB */
3111da177e4SLinus Torvalds 		if (scb_child_type == SCB_ON_PARENT_NEXT_SCB) {
312da3cec35STakashi Iwai 			if (snd_BUG_ON(scb->parent_scb_ptr->next_scb_ptr !=
313da3cec35STakashi Iwai 				       ins->the_null_scb))
314da3cec35STakashi Iwai 				return NULL;
3151da177e4SLinus Torvalds 
3161da177e4SLinus Torvalds 			scb->parent_scb_ptr->next_scb_ptr = scb;
3171da177e4SLinus Torvalds 
3181da177e4SLinus Torvalds 		} else if (scb_child_type == SCB_ON_PARENT_SUBLIST_SCB) {
319da3cec35STakashi Iwai 			if (snd_BUG_ON(scb->parent_scb_ptr->sub_list_ptr !=
320da3cec35STakashi Iwai 				       ins->the_null_scb))
321da3cec35STakashi Iwai 				return NULL;
3221da177e4SLinus Torvalds 
3231da177e4SLinus Torvalds 			scb->parent_scb_ptr->sub_list_ptr = scb;
3241da177e4SLinus Torvalds 		} else {
325da3cec35STakashi Iwai 			snd_BUG();
3261da177e4SLinus Torvalds 		}
3271da177e4SLinus Torvalds 
3281da177e4SLinus Torvalds 		spin_lock_irqsave(&chip->reg_lock, flags);
3291da177e4SLinus Torvalds 
3301da177e4SLinus Torvalds 		/* update entry in DSP RAM */
3311da177e4SLinus Torvalds 		cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
3321da177e4SLinus Torvalds 
3331da177e4SLinus Torvalds 		spin_unlock_irqrestore(&chip->reg_lock, flags);
3341da177e4SLinus Torvalds 	}
3351da177e4SLinus Torvalds 
3361da177e4SLinus Torvalds 
3371da177e4SLinus Torvalds 	cs46xx_dsp_proc_register_scb_desc (chip,scb);
3381da177e4SLinus Torvalds 
3391da177e4SLinus Torvalds 	return scb;
3401da177e4SLinus Torvalds }
3411da177e4SLinus Torvalds 
3423d19f804STakashi Iwai static struct dsp_scb_descriptor *
cs46xx_dsp_create_generic_scb(struct snd_cs46xx * chip,char * name,u32 * scb_data,u32 dest,char * task_entry_name,struct dsp_scb_descriptor * parent_scb,int scb_child_type)3433d19f804STakashi Iwai cs46xx_dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data,
3443d19f804STakashi Iwai 			       u32 dest, char * task_entry_name,
3453d19f804STakashi Iwai                                struct dsp_scb_descriptor * parent_scb,
3461da177e4SLinus Torvalds                                int scb_child_type)
3471da177e4SLinus Torvalds {
3483d19f804STakashi Iwai 	struct dsp_symbol_entry * task_entry;
3491da177e4SLinus Torvalds 
3501da177e4SLinus Torvalds 	task_entry = cs46xx_dsp_lookup_symbol (chip,task_entry_name,
3511da177e4SLinus Torvalds 					       SYMBOL_CODE);
3521da177e4SLinus Torvalds 
3531da177e4SLinus Torvalds 	if (task_entry == NULL) {
3542b96a7f1STakashi Iwai 		dev_err(chip->card->dev,
3552b96a7f1STakashi Iwai 			"dsp_spos: symbol %s not found\n", task_entry_name);
3561da177e4SLinus Torvalds 		return NULL;
3571da177e4SLinus Torvalds 	}
3581da177e4SLinus Torvalds 
3591da177e4SLinus Torvalds 	return _dsp_create_generic_scb (chip,name,scb_data,dest,task_entry,
3601da177e4SLinus Torvalds 					parent_scb,scb_child_type);
3611da177e4SLinus Torvalds }
3621da177e4SLinus Torvalds 
3633d19f804STakashi Iwai struct dsp_scb_descriptor *
cs46xx_dsp_create_timing_master_scb(struct snd_cs46xx * chip)3643d19f804STakashi Iwai cs46xx_dsp_create_timing_master_scb (struct snd_cs46xx *chip)
3651da177e4SLinus Torvalds {
3663d19f804STakashi Iwai 	struct dsp_scb_descriptor * scb;
3671da177e4SLinus Torvalds 
3683d19f804STakashi Iwai 	struct dsp_timing_master_scb timing_master_scb = {
3691da177e4SLinus Torvalds 		{ 0,
3701da177e4SLinus Torvalds 		  0,
3711da177e4SLinus Torvalds 		  0,
3721da177e4SLinus Torvalds 		  0
3731da177e4SLinus Torvalds 		},
3741da177e4SLinus Torvalds 		{ 0,
3751da177e4SLinus Torvalds 		  0,
3761da177e4SLinus Torvalds 		  0,
3771da177e4SLinus Torvalds 		  0,
3781da177e4SLinus Torvalds 		  0
3791da177e4SLinus Torvalds 		},
3801da177e4SLinus Torvalds 		0,0,
3811da177e4SLinus Torvalds 		0,NULL_SCB_ADDR,
3821da177e4SLinus Torvalds 		0,0,             /* extraSampleAccum:TMreserved */
3831da177e4SLinus Torvalds 		0,0,             /* codecFIFOptr:codecFIFOsyncd */
3841da177e4SLinus Torvalds 		0x0001,0x8000,   /* fracSampAccumQm1:TMfrmsLeftInGroup */
3851da177e4SLinus Torvalds 		0x0001,0x0000,   /* fracSampCorrectionQm1:TMfrmGroupLength */
3861da177e4SLinus Torvalds 		0x00060000       /* nSampPerFrmQ15 */
3871da177e4SLinus Torvalds 	};
3881da177e4SLinus Torvalds 
3891da177e4SLinus Torvalds 	scb = cs46xx_dsp_create_generic_scb(chip,"TimingMasterSCBInst",(u32 *)&timing_master_scb,
3901da177e4SLinus Torvalds 					    TIMINGMASTER_SCB_ADDR,
3911da177e4SLinus Torvalds 					    "TIMINGMASTER",NULL,SCB_NO_PARENT);
3921da177e4SLinus Torvalds 
3931da177e4SLinus Torvalds 	return scb;
3941da177e4SLinus Torvalds }
3951da177e4SLinus Torvalds 
3961da177e4SLinus Torvalds 
3973d19f804STakashi Iwai struct dsp_scb_descriptor *
cs46xx_dsp_create_codec_out_scb(struct snd_cs46xx * chip,char * codec_name,u16 channel_disp,u16 fifo_addr,u16 child_scb_addr,u32 dest,struct dsp_scb_descriptor * parent_scb,int scb_child_type)3983d19f804STakashi Iwai cs46xx_dsp_create_codec_out_scb(struct snd_cs46xx * chip, char * codec_name,
3993d19f804STakashi Iwai                                 u16 channel_disp, u16 fifo_addr, u16 child_scb_addr,
4003d19f804STakashi Iwai                                 u32 dest, struct dsp_scb_descriptor * parent_scb,
4011da177e4SLinus Torvalds                                 int scb_child_type)
4021da177e4SLinus Torvalds {
4033d19f804STakashi Iwai 	struct dsp_scb_descriptor * scb;
4041da177e4SLinus Torvalds 
4053d19f804STakashi Iwai 	struct dsp_codec_output_scb codec_out_scb = {
4061da177e4SLinus Torvalds 		{ 0,
4071da177e4SLinus Torvalds 		  0,
4081da177e4SLinus Torvalds 		  0,
4091da177e4SLinus Torvalds 		  0
4101da177e4SLinus Torvalds 		},
4111da177e4SLinus Torvalds 		{
4121da177e4SLinus Torvalds 			0,
4131da177e4SLinus Torvalds 			0,
4141da177e4SLinus Torvalds 			0,
4151da177e4SLinus Torvalds 			0,
4161da177e4SLinus Torvalds 			0
4171da177e4SLinus Torvalds 		},
4181da177e4SLinus Torvalds 		0,0,
4191da177e4SLinus Torvalds 		0,NULL_SCB_ADDR,
4201da177e4SLinus Torvalds 		0,                      /* COstrmRsConfig */
4211da177e4SLinus Torvalds 		0,                      /* COstrmBufPtr */
4221da177e4SLinus Torvalds 		channel_disp,fifo_addr, /* leftChanBaseIOaddr:rightChanIOdisp */
4231da177e4SLinus Torvalds 		0x0000,0x0080,          /* (!AC97!) COexpVolChangeRate:COscaleShiftCount */
4241da177e4SLinus Torvalds 		0,child_scb_addr        /* COreserved - need child scb to work with rom code */
4251da177e4SLinus Torvalds 	};
4261da177e4SLinus Torvalds 
4271da177e4SLinus Torvalds 
4281da177e4SLinus Torvalds 	scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_out_scb,
4291da177e4SLinus Torvalds 					    dest,"S16_CODECOUTPUTTASK",parent_scb,
4301da177e4SLinus Torvalds 					    scb_child_type);
4311da177e4SLinus Torvalds 
4321da177e4SLinus Torvalds 	return scb;
4331da177e4SLinus Torvalds }
4341da177e4SLinus Torvalds 
4353d19f804STakashi Iwai struct dsp_scb_descriptor *
cs46xx_dsp_create_codec_in_scb(struct snd_cs46xx * chip,char * codec_name,u16 channel_disp,u16 fifo_addr,u16 sample_buffer_addr,u32 dest,struct dsp_scb_descriptor * parent_scb,int scb_child_type)4363d19f804STakashi Iwai cs46xx_dsp_create_codec_in_scb(struct snd_cs46xx * chip, char * codec_name,
4373d19f804STakashi Iwai 			       u16 channel_disp, u16 fifo_addr, u16 sample_buffer_addr,
4383d19f804STakashi Iwai 			       u32 dest, struct dsp_scb_descriptor * parent_scb,
4391da177e4SLinus Torvalds 			       int scb_child_type)
4401da177e4SLinus Torvalds {
4411da177e4SLinus Torvalds 
4423d19f804STakashi Iwai 	struct dsp_scb_descriptor * scb;
4433d19f804STakashi Iwai 	struct dsp_codec_input_scb codec_input_scb = {
4441da177e4SLinus Torvalds 		{ 0,
4451da177e4SLinus Torvalds 		  0,
4461da177e4SLinus Torvalds 		  0,
4471da177e4SLinus Torvalds 		  0
4481da177e4SLinus Torvalds 		},
4491da177e4SLinus Torvalds 		{
4501da177e4SLinus Torvalds 			0,
4511da177e4SLinus Torvalds 			0,
4521da177e4SLinus Torvalds 			0,
4531da177e4SLinus Torvalds 			0,
4541da177e4SLinus Torvalds 			0
4551da177e4SLinus Torvalds 		},
4561da177e4SLinus Torvalds 
4571da177e4SLinus Torvalds #if 0  /* cs4620 */
4581da177e4SLinus Torvalds 		SyncIOSCB,NULL_SCB_ADDR
4591da177e4SLinus Torvalds #else
4601da177e4SLinus Torvalds 		0 , 0,
4611da177e4SLinus Torvalds #endif
4621da177e4SLinus Torvalds 		0,0,
4631da177e4SLinus Torvalds 
4641da177e4SLinus Torvalds 		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,  /* strmRsConfig */
4651da177e4SLinus Torvalds 		sample_buffer_addr << 0x10,       /* strmBufPtr; defined as a dword ptr, used as a byte ptr */
4661da177e4SLinus Torvalds 		channel_disp,fifo_addr,           /* (!AC97!) leftChanBaseINaddr=AC97primary
4671da177e4SLinus Torvalds 						     link input slot 3 :rightChanINdisp=""slot 4 */
4681da177e4SLinus Torvalds 		0x0000,0x0000,                    /* (!AC97!) ????:scaleShiftCount; no shift needed
4691da177e4SLinus Torvalds 						     because AC97 is already 20 bits */
4701da177e4SLinus Torvalds 		0x80008000                        /* ??clw cwcgame.scb has 0 */
4711da177e4SLinus Torvalds 	};
4721da177e4SLinus Torvalds 
4731da177e4SLinus Torvalds 	scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_input_scb,
4741da177e4SLinus Torvalds 					    dest,"S16_CODECINPUTTASK",parent_scb,
4751da177e4SLinus Torvalds 					    scb_child_type);
4761da177e4SLinus Torvalds 	return scb;
4771da177e4SLinus Torvalds }
4781da177e4SLinus Torvalds 
4791da177e4SLinus Torvalds 
4803d19f804STakashi Iwai static struct dsp_scb_descriptor *
cs46xx_dsp_create_pcm_reader_scb(struct snd_cs46xx * chip,char * scb_name,u16 sample_buffer_addr,u32 dest,int virtual_channel,u32 playback_hw_addr,struct dsp_scb_descriptor * parent_scb,int scb_child_type)4813d19f804STakashi Iwai cs46xx_dsp_create_pcm_reader_scb(struct snd_cs46xx * chip, char * scb_name,
4821da177e4SLinus Torvalds                                  u16 sample_buffer_addr, u32 dest,
4831da177e4SLinus Torvalds                                  int virtual_channel, u32 playback_hw_addr,
4843d19f804STakashi Iwai                                  struct dsp_scb_descriptor * parent_scb,
4851da177e4SLinus Torvalds                                  int scb_child_type)
4861da177e4SLinus Torvalds {
4873d19f804STakashi Iwai 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
4883d19f804STakashi Iwai 	struct dsp_scb_descriptor * scb;
4891da177e4SLinus Torvalds 
4903d19f804STakashi Iwai 	struct dsp_generic_scb pcm_reader_scb = {
4911da177e4SLinus Torvalds 
4921da177e4SLinus Torvalds 		/*
4931da177e4SLinus Torvalds 		  Play DMA Task xfers data from host buffer to SP buffer
4941da177e4SLinus Torvalds 		  init/runtime variables:
4951da177e4SLinus Torvalds 		  PlayAC: Play Audio Data Conversion - SCB loc: 2nd dword, mask: 0x0000F000L
4961da177e4SLinus Torvalds 		  DATA_FMT_16BIT_ST_LTLEND(0x00000000L)   from 16-bit stereo, little-endian
4971da177e4SLinus Torvalds 		  DATA_FMT_8_BIT_ST_SIGNED(0x00001000L)   from 8-bit stereo, signed
4981da177e4SLinus Torvalds 		  DATA_FMT_16BIT_MN_LTLEND(0x00002000L)   from 16-bit mono, little-endian
4991da177e4SLinus Torvalds 		  DATA_FMT_8_BIT_MN_SIGNED(0x00003000L)   from 8-bit mono, signed
5001da177e4SLinus Torvalds 		  DATA_FMT_16BIT_ST_BIGEND(0x00004000L)   from 16-bit stereo, big-endian
5011da177e4SLinus Torvalds 		  DATA_FMT_16BIT_MN_BIGEND(0x00006000L)   from 16-bit mono, big-endian
5021da177e4SLinus Torvalds 		  DATA_FMT_8_BIT_ST_UNSIGNED(0x00009000L) from 8-bit stereo, unsigned
5031da177e4SLinus Torvalds 		  DATA_FMT_8_BIT_MN_UNSIGNED(0x0000b000L) from 8-bit mono, unsigned
5041da177e4SLinus Torvalds 		  ? Other combinations possible from:
5051da177e4SLinus Torvalds 		  DMA_RQ_C2_AUDIO_CONVERT_MASK    0x0000F000L
5061da177e4SLinus Torvalds 		  DMA_RQ_C2_AC_NONE               0x00000000L
5071da177e4SLinus Torvalds 		  DMA_RQ_C2_AC_8_TO_16_BIT        0x00001000L
5081da177e4SLinus Torvalds 		  DMA_RQ_C2_AC_MONO_TO_STEREO     0x00002000L
5091da177e4SLinus Torvalds 		  DMA_RQ_C2_AC_ENDIAN_CONVERT     0x00004000L
5101da177e4SLinus Torvalds 		  DMA_RQ_C2_AC_SIGNED_CONVERT     0x00008000L
5111da177e4SLinus Torvalds 
5121da177e4SLinus Torvalds 		  HostBuffAddr: Host Buffer Physical Byte Address - SCB loc:3rd dword, Mask: 0xFFFFFFFFL
5131da177e4SLinus Torvalds 		  aligned to dword boundary
5141da177e4SLinus Torvalds 		*/
5151da177e4SLinus Torvalds 		/* Basic (non scatter/gather) DMA requestor (4 ints) */
5161da177e4SLinus Torvalds 		{ DMA_RQ_C1_SOURCE_ON_HOST +        /* source buffer is on the host */
5171da177e4SLinus Torvalds 		  DMA_RQ_C1_SOURCE_MOD1024 +        /* source buffer is 1024 dwords (4096 bytes) */
5181da177e4SLinus Torvalds 		  DMA_RQ_C1_DEST_MOD32 +            /* dest buffer(PCMreaderBuf) is 32 dwords*/
5191da177e4SLinus Torvalds 		  DMA_RQ_C1_WRITEBACK_SRC_FLAG +    /* ?? */
5201da177e4SLinus Torvalds 		  DMA_RQ_C1_WRITEBACK_DEST_FLAG +   /* ?? */
5211da177e4SLinus Torvalds 		  15,                             /* DwordCount-1: picked 16 for DwordCount because Jim */
5221da177e4SLinus Torvalds 		  /*        Barnette said that is what we should use since */
5231da177e4SLinus Torvalds 		  /*        we are not running in optimized mode? */
5241da177e4SLinus Torvalds 		  DMA_RQ_C2_AC_NONE +
5251da177e4SLinus Torvalds 		  DMA_RQ_C2_SIGNAL_SOURCE_PINGPONG + /* set play interrupt (bit0) in HISR when source */
5261da177e4SLinus Torvalds 		  /*   buffer (on host) crosses half-way point */
5271da177e4SLinus Torvalds 		  virtual_channel,                   /* Play DMA channel arbitrarily set to 0 */
5281da177e4SLinus Torvalds 		  playback_hw_addr,                  /* HostBuffAddr (source) */
5291da177e4SLinus Torvalds 		  DMA_RQ_SD_SP_SAMPLE_ADDR +         /* destination buffer is in SP Sample Memory */
5301da177e4SLinus Torvalds 		  sample_buffer_addr                 /* SP Buffer Address (destination) */
5311da177e4SLinus Torvalds 		},
5321da177e4SLinus Torvalds 		/* Scatter/gather DMA requestor extension   (5 ints) */
5331da177e4SLinus Torvalds 		{
5341da177e4SLinus Torvalds 			0,
5351da177e4SLinus Torvalds 			0,
5361da177e4SLinus Torvalds 			0,
5371da177e4SLinus Torvalds 			0,
5381da177e4SLinus Torvalds 			0
5391da177e4SLinus Torvalds 		},
5401da177e4SLinus Torvalds 		/* Sublist pointer & next stream control block (SCB) link. */
5411da177e4SLinus Torvalds 		NULL_SCB_ADDR,NULL_SCB_ADDR,
5421da177e4SLinus Torvalds 		/* Pointer to this tasks parameter block & stream function pointer */
5431da177e4SLinus Torvalds 		0,NULL_SCB_ADDR,
5441da177e4SLinus Torvalds 		/* rsConfig register for stream buffer (rsDMA reg. is loaded from basicReq.daw */
5451da177e4SLinus Torvalds 		/*   for incoming streams, or basicReq.saw, for outgoing streams) */
5461da177e4SLinus Torvalds 		RSCONFIG_DMA_ENABLE +                 /* enable DMA */
5471da177e4SLinus Torvalds 		(19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) + /* MAX_DMA_SIZE picked to be 19 since SPUD  */
5481da177e4SLinus Torvalds 		/*  uses it for some reason */
5491da177e4SLinus Torvalds 		((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) + /* stream number = SCBaddr/16 */
5501da177e4SLinus Torvalds 		RSCONFIG_SAMPLE_16STEREO +
5511da177e4SLinus Torvalds 		RSCONFIG_MODULO_32,             /* dest buffer(PCMreaderBuf) is 32 dwords (256 bytes) */
5521da177e4SLinus Torvalds 		/* Stream sample pointer & MAC-unit mode for this stream */
5531da177e4SLinus Torvalds 		(sample_buffer_addr << 0x10),
5541da177e4SLinus Torvalds 		/* Fractional increment per output sample in the input sample buffer */
5551da177e4SLinus Torvalds 		0,
5561da177e4SLinus Torvalds 		{
5571da177e4SLinus Torvalds 			/* Standard stereo volume control
5581da177e4SLinus Torvalds 			   default muted */
5591da177e4SLinus Torvalds 			0xffff,0xffff,
5601da177e4SLinus Torvalds 			0xffff,0xffff
5611da177e4SLinus Torvalds 		}
5621da177e4SLinus Torvalds 	};
5631da177e4SLinus Torvalds 
5641da177e4SLinus Torvalds 	if (ins->null_algorithm == NULL) {
5651da177e4SLinus Torvalds 		ins->null_algorithm =  cs46xx_dsp_lookup_symbol (chip,"NULLALGORITHM",
5661da177e4SLinus Torvalds 								 SYMBOL_CODE);
5671da177e4SLinus Torvalds 
5681da177e4SLinus Torvalds 		if (ins->null_algorithm == NULL) {
5692b96a7f1STakashi Iwai 			dev_err(chip->card->dev,
5702b96a7f1STakashi Iwai 				"dsp_spos: symbol NULLALGORITHM not found\n");
5711da177e4SLinus Torvalds 			return NULL;
5721da177e4SLinus Torvalds 		}
5731da177e4SLinus Torvalds 	}
5741da177e4SLinus Torvalds 
5751da177e4SLinus Torvalds 	scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_reader_scb,
5761da177e4SLinus Torvalds 				      dest,ins->null_algorithm,parent_scb,
5771da177e4SLinus Torvalds 				      scb_child_type);
5781da177e4SLinus Torvalds 
5791da177e4SLinus Torvalds 	return scb;
5801da177e4SLinus Torvalds }
5811da177e4SLinus Torvalds 
5821da177e4SLinus Torvalds #define GOF_PER_SEC 200
5831da177e4SLinus Torvalds 
5843d19f804STakashi Iwai struct dsp_scb_descriptor *
cs46xx_dsp_create_src_task_scb(struct snd_cs46xx * chip,char * scb_name,int rate,u16 src_buffer_addr,u16 src_delay_buffer_addr,u32 dest,struct dsp_scb_descriptor * parent_scb,int scb_child_type,int pass_through)5853d19f804STakashi Iwai cs46xx_dsp_create_src_task_scb(struct snd_cs46xx * chip, char * scb_name,
5861da177e4SLinus Torvalds 			       int rate,
5871da177e4SLinus Torvalds                                u16 src_buffer_addr,
5881da177e4SLinus Torvalds                                u16 src_delay_buffer_addr, u32 dest,
5893d19f804STakashi Iwai                                struct dsp_scb_descriptor * parent_scb,
5901da177e4SLinus Torvalds                                int scb_child_type,
5911da177e4SLinus Torvalds 	                       int pass_through)
5921da177e4SLinus Torvalds {
5931da177e4SLinus Torvalds 
5943d19f804STakashi Iwai 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
5953d19f804STakashi Iwai 	struct dsp_scb_descriptor * scb;
5961da177e4SLinus Torvalds 	unsigned int tmp1, tmp2;
5971da177e4SLinus Torvalds 	unsigned int phiIncr;
5981da177e4SLinus Torvalds 	unsigned int correctionPerGOF, correctionPerSec;
5991da177e4SLinus Torvalds 
6002b96a7f1STakashi Iwai 	dev_dbg(chip->card->dev, "dsp_spos: setting %s rate to %u\n",
6012b96a7f1STakashi Iwai 		scb_name, rate);
6021da177e4SLinus Torvalds 
6031da177e4SLinus Torvalds 	/*
6041da177e4SLinus Torvalds 	 *  Compute the values used to drive the actual sample rate conversion.
6051da177e4SLinus Torvalds 	 *  The following formulas are being computed, using inline assembly
6061da177e4SLinus Torvalds 	 *  since we need to use 64 bit arithmetic to compute the values:
6071da177e4SLinus Torvalds 	 *
6081da177e4SLinus Torvalds 	 *  phiIncr = floor((Fs,in * 2^26) / Fs,out)
6091da177e4SLinus Torvalds 	 *  correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) /
6101da177e4SLinus Torvalds 	 *                                   GOF_PER_SEC)
6111da177e4SLinus Torvalds 	 *  ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -M
6121da177e4SLinus Torvalds 	 *                       GOF_PER_SEC * correctionPerGOF
6131da177e4SLinus Torvalds 	 *
6141da177e4SLinus Torvalds 	 *  i.e.
6151da177e4SLinus Torvalds 	 *
6161da177e4SLinus Torvalds 	 *  phiIncr:other = dividend:remainder((Fs,in * 2^26) / Fs,out)
6171da177e4SLinus Torvalds 	 *  correctionPerGOF:correctionPerSec =
6181da177e4SLinus Torvalds 	 *      dividend:remainder(ulOther / GOF_PER_SEC)
6191da177e4SLinus Torvalds 	 */
6201da177e4SLinus Torvalds 	tmp1 = rate << 16;
6211da177e4SLinus Torvalds 	phiIncr = tmp1 / 48000;
6221da177e4SLinus Torvalds 	tmp1 -= phiIncr * 48000;
6231da177e4SLinus Torvalds 	tmp1 <<= 10;
6241da177e4SLinus Torvalds 	phiIncr <<= 10;
6251da177e4SLinus Torvalds 	tmp2 = tmp1 / 48000;
6261da177e4SLinus Torvalds 	phiIncr += tmp2;
6271da177e4SLinus Torvalds 	tmp1 -= tmp2 * 48000;
6281da177e4SLinus Torvalds 	correctionPerGOF = tmp1 / GOF_PER_SEC;
6291da177e4SLinus Torvalds 	tmp1 -= correctionPerGOF * GOF_PER_SEC;
6301da177e4SLinus Torvalds 	correctionPerSec = tmp1;
6311da177e4SLinus Torvalds 
6321da177e4SLinus Torvalds 	{
6333d19f804STakashi Iwai 		struct dsp_src_task_scb src_task_scb = {
6341da177e4SLinus Torvalds 			0x0028,0x00c8,
6351da177e4SLinus Torvalds 			0x5555,0x0000,
6361da177e4SLinus Torvalds 			0x0000,0x0000,
6371da177e4SLinus Torvalds 			src_buffer_addr,1,
6381da177e4SLinus Torvalds 			correctionPerGOF,correctionPerSec,
6391da177e4SLinus Torvalds 			RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
6401da177e4SLinus Torvalds 			0x0000,src_delay_buffer_addr,
6411da177e4SLinus Torvalds 			0x0,
6421da177e4SLinus Torvalds 			0x080,(src_delay_buffer_addr + (24 * 4)),
6431da177e4SLinus Torvalds 			0,0, /* next_scb, sub_list_ptr */
6441da177e4SLinus Torvalds 			0,0, /* entry, this_spb */
6451da177e4SLinus Torvalds 			RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
6461da177e4SLinus Torvalds 			src_buffer_addr << 0x10,
6471da177e4SLinus Torvalds 			phiIncr,
6481da177e4SLinus Torvalds 			{
6491da177e4SLinus Torvalds 				0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left,
6501da177e4SLinus Torvalds 				0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left
6511da177e4SLinus Torvalds 			}
6521da177e4SLinus Torvalds 		};
6531da177e4SLinus Torvalds 
6541da177e4SLinus Torvalds 		if (ins->s16_up == NULL) {
6551da177e4SLinus Torvalds 			ins->s16_up =  cs46xx_dsp_lookup_symbol (chip,"S16_UPSRC",
6561da177e4SLinus Torvalds 								 SYMBOL_CODE);
6571da177e4SLinus Torvalds 
6581da177e4SLinus Torvalds 			if (ins->s16_up == NULL) {
6592b96a7f1STakashi Iwai 				dev_err(chip->card->dev,
6602b96a7f1STakashi Iwai 					"dsp_spos: symbol S16_UPSRC not found\n");
6611da177e4SLinus Torvalds 				return NULL;
6621da177e4SLinus Torvalds 			}
6631da177e4SLinus Torvalds 		}
6641da177e4SLinus Torvalds 
6651da177e4SLinus Torvalds 		/* clear buffers */
6661da177e4SLinus Torvalds 		_dsp_clear_sample_buffer (chip,src_buffer_addr,8);
6671da177e4SLinus Torvalds 		_dsp_clear_sample_buffer (chip,src_delay_buffer_addr,32);
6681da177e4SLinus Torvalds 
6691da177e4SLinus Torvalds 		if (pass_through) {
6701da177e4SLinus Torvalds 			/* wont work with any other rate than
6711da177e4SLinus Torvalds 			   the native DSP rate */
672da3cec35STakashi Iwai 			snd_BUG_ON(rate != 48000);
6731da177e4SLinus Torvalds 
6741da177e4SLinus Torvalds 			scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
6751da177e4SLinus Torvalds 							    dest,"DMAREADER",parent_scb,
6761da177e4SLinus Torvalds 							    scb_child_type);
6771da177e4SLinus Torvalds 		} else {
6781da177e4SLinus Torvalds 			scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
6791da177e4SLinus Torvalds 						      dest,ins->s16_up,parent_scb,
6801da177e4SLinus Torvalds 						      scb_child_type);
6811da177e4SLinus Torvalds 		}
6821da177e4SLinus Torvalds 
6831da177e4SLinus Torvalds 
6841da177e4SLinus Torvalds 	}
6851da177e4SLinus Torvalds 
6861da177e4SLinus Torvalds 	return scb;
6871da177e4SLinus Torvalds }
6881da177e4SLinus Torvalds 
6891da177e4SLinus Torvalds #if 0 /* not used */
6903d19f804STakashi Iwai struct dsp_scb_descriptor *
6913d19f804STakashi Iwai cs46xx_dsp_create_filter_scb(struct snd_cs46xx * chip, char * scb_name,
6921da177e4SLinus Torvalds 			     u16 buffer_addr, u32 dest,
6933d19f804STakashi Iwai 			     struct dsp_scb_descriptor * parent_scb,
6941da177e4SLinus Torvalds 			     int scb_child_type) {
6953d19f804STakashi Iwai 	struct dsp_scb_descriptor * scb;
6961da177e4SLinus Torvalds 
6973d19f804STakashi Iwai 	struct dsp_filter_scb filter_scb = {
6981da177e4SLinus Torvalds 		.a0_right            = 0x41a9,
6991da177e4SLinus Torvalds 		.a0_left             = 0x41a9,
7001da177e4SLinus Torvalds 		.a1_right            = 0xb8e4,
7011da177e4SLinus Torvalds 		.a1_left             = 0xb8e4,
7021da177e4SLinus Torvalds 		.a2_right            = 0x3e55,
7031da177e4SLinus Torvalds 		.a2_left             = 0x3e55,
7041da177e4SLinus Torvalds 
7051da177e4SLinus Torvalds 		.filter_unused3      = 0x0000,
7061da177e4SLinus Torvalds 		.filter_unused2      = 0x0000,
7071da177e4SLinus Torvalds 
7081da177e4SLinus Torvalds 		.output_buf_ptr      = buffer_addr,
7091da177e4SLinus Torvalds 		.init                = 0x000,
7101da177e4SLinus Torvalds 
7111da177e4SLinus Torvalds 		.prev_sample_output1 = 0x00000000,
7121da177e4SLinus Torvalds 		.prev_sample_output2 = 0x00000000,
7131da177e4SLinus Torvalds 
7141da177e4SLinus Torvalds 		.prev_sample_input1  = 0x00000000,
7151da177e4SLinus Torvalds 		.prev_sample_input2  = 0x00000000,
7161da177e4SLinus Torvalds 
7171da177e4SLinus Torvalds 		.next_scb_ptr        = 0x0000,
7181da177e4SLinus Torvalds 		.sub_list_ptr        = 0x0000,
7191da177e4SLinus Torvalds 
7201da177e4SLinus Torvalds 		.entry_point         = 0x0000,
7211da177e4SLinus Torvalds 		.spb_ptr             = 0x0000,
7221da177e4SLinus Torvalds 
7231da177e4SLinus Torvalds 		.b0_right            = 0x0e38,
7241da177e4SLinus Torvalds 		.b0_left             = 0x0e38,
7251da177e4SLinus Torvalds 		.b1_right            = 0x1c71,
7261da177e4SLinus Torvalds 		.b1_left             = 0x1c71,
7271da177e4SLinus Torvalds 		.b2_right            = 0x0e38,
7281da177e4SLinus Torvalds 		.b2_left             = 0x0e38,
7291da177e4SLinus Torvalds 	};
7301da177e4SLinus Torvalds 
7311da177e4SLinus Torvalds 
7321da177e4SLinus Torvalds 	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&filter_scb,
7331da177e4SLinus Torvalds 					    dest,"FILTERTASK",parent_scb,
7341da177e4SLinus Torvalds 					    scb_child_type);
7351da177e4SLinus Torvalds 
7361da177e4SLinus Torvalds  	return scb;
7371da177e4SLinus Torvalds }
7381da177e4SLinus Torvalds #endif /* not used */
7391da177e4SLinus Torvalds 
7403d19f804STakashi Iwai struct dsp_scb_descriptor *
cs46xx_dsp_create_mix_only_scb(struct snd_cs46xx * chip,char * scb_name,u16 mix_buffer_addr,u32 dest,struct dsp_scb_descriptor * parent_scb,int scb_child_type)7413d19f804STakashi Iwai cs46xx_dsp_create_mix_only_scb(struct snd_cs46xx * chip, char * scb_name,
7421da177e4SLinus Torvalds                                u16 mix_buffer_addr, u32 dest,
7433d19f804STakashi Iwai                                struct dsp_scb_descriptor * parent_scb,
7441da177e4SLinus Torvalds                                int scb_child_type)
7451da177e4SLinus Torvalds {
7463d19f804STakashi Iwai 	struct dsp_scb_descriptor * scb;
7471da177e4SLinus Torvalds 
7483d19f804STakashi Iwai 	struct dsp_mix_only_scb master_mix_scb = {
7491da177e4SLinus Torvalds 		/* 0 */ { 0,
7501da177e4SLinus Torvalds 			  /* 1 */   0,
7511da177e4SLinus Torvalds 			  /* 2 */  mix_buffer_addr,
7521da177e4SLinus Torvalds 			  /* 3 */  0
7531da177e4SLinus Torvalds 			  /*   */ },
7541da177e4SLinus Torvalds 		{
7551da177e4SLinus Torvalds 			/* 4 */  0,
7561da177e4SLinus Torvalds 			/* 5 */  0,
7571da177e4SLinus Torvalds 			/* 6 */  0,
7581da177e4SLinus Torvalds 			/* 7 */  0,
7591da177e4SLinus Torvalds 			/* 8 */  0x00000080
7601da177e4SLinus Torvalds 		},
7611da177e4SLinus Torvalds 		/* 9 */ 0,0,
7621da177e4SLinus Torvalds 		/* A */ 0,0,
7631da177e4SLinus Torvalds 		/* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
7641da177e4SLinus Torvalds 		/* C */ (mix_buffer_addr  + (16 * 4)) << 0x10,
7651da177e4SLinus Torvalds 		/* D */ 0,
7661da177e4SLinus Torvalds 		{
7671da177e4SLinus Torvalds 			/* E */ 0x8000,0x8000,
7681da177e4SLinus Torvalds 			/* F */ 0x8000,0x8000
7691da177e4SLinus Torvalds 		}
7701da177e4SLinus Torvalds 	};
7711da177e4SLinus Torvalds 
7721da177e4SLinus Torvalds 
7731da177e4SLinus Torvalds 	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&master_mix_scb,
7741da177e4SLinus Torvalds 					    dest,"S16_MIX",parent_scb,
7751da177e4SLinus Torvalds 					    scb_child_type);
7761da177e4SLinus Torvalds 	return scb;
7771da177e4SLinus Torvalds }
7781da177e4SLinus Torvalds 
7791da177e4SLinus Torvalds 
7803d19f804STakashi Iwai struct dsp_scb_descriptor *
cs46xx_dsp_create_mix_to_ostream_scb(struct snd_cs46xx * chip,char * scb_name,u16 mix_buffer_addr,u16 writeback_spb,u32 dest,struct dsp_scb_descriptor * parent_scb,int scb_child_type)7813d19f804STakashi Iwai cs46xx_dsp_create_mix_to_ostream_scb(struct snd_cs46xx * chip, char * scb_name,
7821da177e4SLinus Torvalds                                      u16 mix_buffer_addr, u16 writeback_spb, u32 dest,
7833d19f804STakashi Iwai                                      struct dsp_scb_descriptor * parent_scb,
7841da177e4SLinus Torvalds                                      int scb_child_type)
7851da177e4SLinus Torvalds {
7863d19f804STakashi Iwai 	struct dsp_scb_descriptor * scb;
7871da177e4SLinus Torvalds 
7883d19f804STakashi Iwai 	struct dsp_mix2_ostream_scb mix2_ostream_scb = {
7891da177e4SLinus Torvalds 		/* Basic (non scatter/gather) DMA requestor (4 ints) */
7901da177e4SLinus Torvalds 		{
7911da177e4SLinus Torvalds 			DMA_RQ_C1_SOURCE_MOD64 +
7921da177e4SLinus Torvalds 			DMA_RQ_C1_DEST_ON_HOST +
7931da177e4SLinus Torvalds 			DMA_RQ_C1_DEST_MOD1024 +
7941da177e4SLinus Torvalds 			DMA_RQ_C1_WRITEBACK_SRC_FLAG +
7951da177e4SLinus Torvalds 			DMA_RQ_C1_WRITEBACK_DEST_FLAG +
7961da177e4SLinus Torvalds 			15,
7971da177e4SLinus Torvalds 
7981da177e4SLinus Torvalds 			DMA_RQ_C2_AC_NONE +
7991da177e4SLinus Torvalds 			DMA_RQ_C2_SIGNAL_DEST_PINGPONG +
8001da177e4SLinus Torvalds 
8011da177e4SLinus Torvalds 			CS46XX_DSP_CAPTURE_CHANNEL,
8021da177e4SLinus Torvalds 			DMA_RQ_SD_SP_SAMPLE_ADDR +
8031da177e4SLinus Torvalds 			mix_buffer_addr,
8041da177e4SLinus Torvalds 			0x0
8051da177e4SLinus Torvalds 		},
8061da177e4SLinus Torvalds 
8071da177e4SLinus Torvalds 		{ 0, 0, 0, 0, 0, },
8081da177e4SLinus Torvalds 		0,0,
8091da177e4SLinus Torvalds 		0,writeback_spb,
8101da177e4SLinus Torvalds 
8111da177e4SLinus Torvalds 		RSCONFIG_DMA_ENABLE +
8121da177e4SLinus Torvalds 		(19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) +
8131da177e4SLinus Torvalds 
8141da177e4SLinus Torvalds 		((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) +
8151da177e4SLinus Torvalds 		RSCONFIG_DMA_TO_HOST +
8161da177e4SLinus Torvalds 		RSCONFIG_SAMPLE_16STEREO +
8171da177e4SLinus Torvalds 		RSCONFIG_MODULO_64,
8181da177e4SLinus Torvalds 		(mix_buffer_addr + (32 * 4)) << 0x10,
8191da177e4SLinus Torvalds 		1,0,
8201da177e4SLinus Torvalds 		0x0001,0x0080,
8211da177e4SLinus Torvalds 		0xFFFF,0
8221da177e4SLinus Torvalds 	};
8231da177e4SLinus Torvalds 
8241da177e4SLinus Torvalds 
8251da177e4SLinus Torvalds 	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&mix2_ostream_scb,
8261da177e4SLinus Torvalds 
8271da177e4SLinus Torvalds 	    dest,"S16_MIX_TO_OSTREAM",parent_scb,
8281da177e4SLinus Torvalds 					    scb_child_type);
8291da177e4SLinus Torvalds 
8301da177e4SLinus Torvalds 	return scb;
8311da177e4SLinus Torvalds }
8321da177e4SLinus Torvalds 
8331da177e4SLinus Torvalds 
8343d19f804STakashi Iwai struct dsp_scb_descriptor *
cs46xx_dsp_create_vari_decimate_scb(struct snd_cs46xx * chip,char * scb_name,u16 vari_buffer_addr0,u16 vari_buffer_addr1,u32 dest,struct dsp_scb_descriptor * parent_scb,int scb_child_type)8353d19f804STakashi Iwai cs46xx_dsp_create_vari_decimate_scb(struct snd_cs46xx * chip,char * scb_name,
8361da177e4SLinus Torvalds                                     u16 vari_buffer_addr0,
8371da177e4SLinus Torvalds                                     u16 vari_buffer_addr1,
8381da177e4SLinus Torvalds                                     u32 dest,
8393d19f804STakashi Iwai                                     struct dsp_scb_descriptor * parent_scb,
8401da177e4SLinus Torvalds                                     int scb_child_type)
8411da177e4SLinus Torvalds {
8421da177e4SLinus Torvalds 
8433d19f804STakashi Iwai 	struct dsp_scb_descriptor * scb;
8441da177e4SLinus Torvalds 
8453d19f804STakashi Iwai 	struct dsp_vari_decimate_scb vari_decimate_scb = {
8461da177e4SLinus Torvalds 		0x0028,0x00c8,
8471da177e4SLinus Torvalds 		0x5555,0x0000,
8481da177e4SLinus Torvalds 		0x0000,0x0000,
8491da177e4SLinus Torvalds 		vari_buffer_addr0,vari_buffer_addr1,
8501da177e4SLinus Torvalds 
8511da177e4SLinus Torvalds 		0x0028,0x00c8,
8521da177e4SLinus Torvalds 		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256,
8531da177e4SLinus Torvalds 
8541da177e4SLinus Torvalds 		0xFF800000,
8551da177e4SLinus Torvalds 		0,
8561da177e4SLinus Torvalds 		0x0080,vari_buffer_addr1 + (25 * 4),
8571da177e4SLinus Torvalds 
8581da177e4SLinus Torvalds 		0,0,
8591da177e4SLinus Torvalds 		0,0,
8601da177e4SLinus Torvalds 
8611da177e4SLinus Torvalds 		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
8621da177e4SLinus Torvalds 		vari_buffer_addr0 << 0x10,
8631da177e4SLinus Torvalds 		0x04000000,
8641da177e4SLinus Torvalds 		{
8651da177e4SLinus Torvalds 			0x8000,0x8000,
8661da177e4SLinus Torvalds 			0xFFFF,0xFFFF
8671da177e4SLinus Torvalds 		}
8681da177e4SLinus Torvalds 	};
8691da177e4SLinus Torvalds 
8701da177e4SLinus Torvalds 	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&vari_decimate_scb,
8711da177e4SLinus Torvalds 					    dest,"VARIDECIMATE",parent_scb,
8721da177e4SLinus Torvalds 					    scb_child_type);
8731da177e4SLinus Torvalds 
8741da177e4SLinus Torvalds 	return scb;
8751da177e4SLinus Torvalds }
8761da177e4SLinus Torvalds 
8771da177e4SLinus Torvalds 
8783d19f804STakashi Iwai static struct dsp_scb_descriptor *
cs46xx_dsp_create_pcm_serial_input_scb(struct snd_cs46xx * chip,char * scb_name,u32 dest,struct dsp_scb_descriptor * input_scb,struct dsp_scb_descriptor * parent_scb,int scb_child_type)8793d19f804STakashi Iwai cs46xx_dsp_create_pcm_serial_input_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
8803d19f804STakashi Iwai                                        struct dsp_scb_descriptor * input_scb,
8813d19f804STakashi Iwai                                        struct dsp_scb_descriptor * parent_scb,
8821da177e4SLinus Torvalds                                        int scb_child_type)
8831da177e4SLinus Torvalds {
8841da177e4SLinus Torvalds 
8853d19f804STakashi Iwai 	struct dsp_scb_descriptor * scb;
8861da177e4SLinus Torvalds 
8871da177e4SLinus Torvalds 
8883d19f804STakashi Iwai 	struct dsp_pcm_serial_input_scb pcm_serial_input_scb = {
8891da177e4SLinus Torvalds 		{ 0,
8901da177e4SLinus Torvalds 		  0,
8911da177e4SLinus Torvalds 		  0,
8921da177e4SLinus Torvalds 		  0
8931da177e4SLinus Torvalds 		},
8941da177e4SLinus Torvalds 		{
8951da177e4SLinus Torvalds 			0,
8961da177e4SLinus Torvalds 			0,
8971da177e4SLinus Torvalds 			0,
8981da177e4SLinus Torvalds 			0,
8991da177e4SLinus Torvalds 			0
9001da177e4SLinus Torvalds 		},
9011da177e4SLinus Torvalds 
9021da177e4SLinus Torvalds 		0,0,
9031da177e4SLinus Torvalds 		0,0,
9041da177e4SLinus Torvalds 
9051da177e4SLinus Torvalds 		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_16,
9061da177e4SLinus Torvalds 		0,
9071da177e4SLinus Torvalds       /* 0xD */ 0,input_scb->address,
9081da177e4SLinus Torvalds 		{
9091da177e4SLinus Torvalds       /* 0xE */   0x8000,0x8000,
9101da177e4SLinus Torvalds       /* 0xF */	  0x8000,0x8000
9111da177e4SLinus Torvalds 		}
9121da177e4SLinus Torvalds 	};
9131da177e4SLinus Torvalds 
9141da177e4SLinus Torvalds 	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_serial_input_scb,
9151da177e4SLinus Torvalds 					    dest,"PCMSERIALINPUTTASK",parent_scb,
9161da177e4SLinus Torvalds 					    scb_child_type);
9171da177e4SLinus Torvalds 	return scb;
9181da177e4SLinus Torvalds }
9191da177e4SLinus Torvalds 
9201da177e4SLinus Torvalds 
9213d19f804STakashi Iwai static struct dsp_scb_descriptor *
cs46xx_dsp_create_asynch_fg_tx_scb(struct snd_cs46xx * chip,char * scb_name,u32 dest,u16 hfg_scb_address,u16 asynch_buffer_address,struct dsp_scb_descriptor * parent_scb,int scb_child_type)9223d19f804STakashi Iwai cs46xx_dsp_create_asynch_fg_tx_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
9231da177e4SLinus Torvalds                                    u16 hfg_scb_address,
9241da177e4SLinus Torvalds                                    u16 asynch_buffer_address,
9253d19f804STakashi Iwai                                    struct dsp_scb_descriptor * parent_scb,
9261da177e4SLinus Torvalds                                    int scb_child_type)
9271da177e4SLinus Torvalds {
9281da177e4SLinus Torvalds 
9293d19f804STakashi Iwai 	struct dsp_scb_descriptor * scb;
9301da177e4SLinus Torvalds 
9313d19f804STakashi Iwai 	struct dsp_asynch_fg_tx_scb asynch_fg_tx_scb = {
9321da177e4SLinus Torvalds 		0xfc00,0x03ff,      /*  Prototype sample buffer size of 256 dwords */
9331da177e4SLinus Torvalds 		0x0058,0x0028,      /* Min Delta 7 dwords == 28 bytes */
9341da177e4SLinus Torvalds 		/* : Max delta 25 dwords == 100 bytes */
9351da177e4SLinus Torvalds 		0,hfg_scb_address,  /* Point to HFG task SCB */
9361da177e4SLinus Torvalds 		0,0,		    /* Initialize current Delta and Consumer ptr adjustment count */
9371da177e4SLinus Torvalds 		0,                  /* Initialize accumulated Phi to 0 */
9381da177e4SLinus Torvalds 		0,0x2aab,           /* Const 1/3 */
9391da177e4SLinus Torvalds 
9401da177e4SLinus Torvalds 		{
9411da177e4SLinus Torvalds 			0,         /* Define the unused elements */
9421da177e4SLinus Torvalds 			0,
9431da177e4SLinus Torvalds 			0
9441da177e4SLinus Torvalds 		},
9451da177e4SLinus Torvalds 
9461da177e4SLinus Torvalds 		0,0,
9471da177e4SLinus Torvalds 		0,dest + AFGTxAccumPhi,
9481da177e4SLinus Torvalds 
9491da177e4SLinus Torvalds 		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256, /* Stereo, 256 dword */
9501da177e4SLinus Torvalds 		(asynch_buffer_address) << 0x10,  /* This should be automagically synchronized
9511da177e4SLinus Torvalds                                                      to the producer pointer */
9521da177e4SLinus Torvalds 
9531da177e4SLinus Torvalds 		/* There is no correct initial value, it will depend upon the detected
9541da177e4SLinus Torvalds 		   rate etc  */
9551da177e4SLinus Torvalds 		0x18000000,                     /* Phi increment for approx 32k operation */
9561da177e4SLinus Torvalds 		0x8000,0x8000,                  /* Volume controls are unused at this time */
9571da177e4SLinus Torvalds 		0x8000,0x8000
9581da177e4SLinus Torvalds 	};
9591da177e4SLinus Torvalds 
9601da177e4SLinus Torvalds 	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_tx_scb,
9611da177e4SLinus Torvalds 					    dest,"ASYNCHFGTXCODE",parent_scb,
9621da177e4SLinus Torvalds 					    scb_child_type);
9631da177e4SLinus Torvalds 
9641da177e4SLinus Torvalds 	return scb;
9651da177e4SLinus Torvalds }
9661da177e4SLinus Torvalds 
9671da177e4SLinus Torvalds 
9683d19f804STakashi Iwai struct dsp_scb_descriptor *
cs46xx_dsp_create_asynch_fg_rx_scb(struct snd_cs46xx * chip,char * scb_name,u32 dest,u16 hfg_scb_address,u16 asynch_buffer_address,struct dsp_scb_descriptor * parent_scb,int scb_child_type)9693d19f804STakashi Iwai cs46xx_dsp_create_asynch_fg_rx_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
9701da177e4SLinus Torvalds                                    u16 hfg_scb_address,
9711da177e4SLinus Torvalds                                    u16 asynch_buffer_address,
9723d19f804STakashi Iwai                                    struct dsp_scb_descriptor * parent_scb,
9731da177e4SLinus Torvalds                                    int scb_child_type)
9741da177e4SLinus Torvalds {
9753d19f804STakashi Iwai 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
9763d19f804STakashi Iwai 	struct dsp_scb_descriptor * scb;
9771da177e4SLinus Torvalds 
9783d19f804STakashi Iwai 	struct dsp_asynch_fg_rx_scb asynch_fg_rx_scb = {
9791da177e4SLinus Torvalds 		0xfe00,0x01ff,      /*  Prototype sample buffer size of 128 dwords */
9801da177e4SLinus Torvalds 		0x0064,0x001c,      /* Min Delta 7 dwords == 28 bytes */
9811da177e4SLinus Torvalds 		                    /* : Max delta 25 dwords == 100 bytes */
9821da177e4SLinus Torvalds 		0,hfg_scb_address,  /* Point to HFG task SCB */
9831da177e4SLinus Torvalds 		0,0,				/* Initialize current Delta and Consumer ptr adjustment count */
9841da177e4SLinus Torvalds 		{
9851da177e4SLinus Torvalds 			0,                /* Define the unused elements */
9861da177e4SLinus Torvalds 			0,
9871da177e4SLinus Torvalds 			0,
9881da177e4SLinus Torvalds 			0,
9891da177e4SLinus Torvalds 			0
9901da177e4SLinus Torvalds 		},
9911da177e4SLinus Torvalds 
9921da177e4SLinus Torvalds 		0,0,
9931da177e4SLinus Torvalds 		0,dest,
9941da177e4SLinus Torvalds 
9951da177e4SLinus Torvalds 		RSCONFIG_MODULO_128 |
9961da177e4SLinus Torvalds         RSCONFIG_SAMPLE_16STEREO,                         /* Stereo, 128 dword */
9971da177e4SLinus Torvalds 		( (asynch_buffer_address + (16 * 4))  << 0x10),   /* This should be automagically
9981da177e4SLinus Torvalds 							                                  synchrinized to the producer pointer */
9991da177e4SLinus Torvalds 
10001da177e4SLinus Torvalds 		/* There is no correct initial value, it will depend upon the detected
10011da177e4SLinus Torvalds 		   rate etc  */
10021da177e4SLinus Torvalds 		0x18000000,
10031da177e4SLinus Torvalds 
10041da177e4SLinus Torvalds 		/* Set IEC958 input volume */
10051da177e4SLinus Torvalds 		0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
10061da177e4SLinus Torvalds 		0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
10071da177e4SLinus Torvalds 	};
10081da177e4SLinus Torvalds 
10091da177e4SLinus Torvalds 	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_rx_scb,
10101da177e4SLinus Torvalds 					    dest,"ASYNCHFGRXCODE",parent_scb,
10111da177e4SLinus Torvalds 					    scb_child_type);
10121da177e4SLinus Torvalds 
10131da177e4SLinus Torvalds 	return scb;
10141da177e4SLinus Torvalds }
10151da177e4SLinus Torvalds 
10161da177e4SLinus Torvalds 
10171da177e4SLinus Torvalds #if 0 /* not used */
10183d19f804STakashi Iwai struct dsp_scb_descriptor *
10193d19f804STakashi Iwai cs46xx_dsp_create_output_snoop_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
10201da177e4SLinus Torvalds                                    u16 snoop_buffer_address,
10213d19f804STakashi Iwai                                    struct dsp_scb_descriptor * snoop_scb,
10223d19f804STakashi Iwai                                    struct dsp_scb_descriptor * parent_scb,
10231da177e4SLinus Torvalds                                    int scb_child_type)
10241da177e4SLinus Torvalds {
10251da177e4SLinus Torvalds 
10263d19f804STakashi Iwai 	struct dsp_scb_descriptor * scb;
10271da177e4SLinus Torvalds 
10283d19f804STakashi Iwai 	struct dsp_output_snoop_scb output_snoop_scb = {
10291da177e4SLinus Torvalds 		{ 0,	/*  not used.  Zero */
10301da177e4SLinus Torvalds 		  0,
10311da177e4SLinus Torvalds 		  0,
10321da177e4SLinus Torvalds 		  0,
10331da177e4SLinus Torvalds 		},
10341da177e4SLinus Torvalds 		{
10351da177e4SLinus Torvalds 			0, /* not used.  Zero */
10361da177e4SLinus Torvalds 			0,
10371da177e4SLinus Torvalds 			0,
10381da177e4SLinus Torvalds 			0,
10391da177e4SLinus Torvalds 			0
10401da177e4SLinus Torvalds 		},
10411da177e4SLinus Torvalds 
10421da177e4SLinus Torvalds 		0,0,
10431da177e4SLinus Torvalds 		0,0,
10441da177e4SLinus Torvalds 
10451da177e4SLinus Torvalds 		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
10461da177e4SLinus Torvalds 		snoop_buffer_address << 0x10,
10471da177e4SLinus Torvalds 		0,0,
10481da177e4SLinus Torvalds 		0,
10491da177e4SLinus Torvalds 		0,snoop_scb->address
10501da177e4SLinus Torvalds 	};
10511da177e4SLinus Torvalds 
10521da177e4SLinus Torvalds 	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&output_snoop_scb,
10531da177e4SLinus Torvalds 					    dest,"OUTPUTSNOOP",parent_scb,
10541da177e4SLinus Torvalds 					    scb_child_type);
10551da177e4SLinus Torvalds 	return scb;
10561da177e4SLinus Torvalds }
10571da177e4SLinus Torvalds #endif /* not used */
10581da177e4SLinus Torvalds 
10591da177e4SLinus Torvalds 
10603d19f804STakashi Iwai struct dsp_scb_descriptor *
cs46xx_dsp_create_spio_write_scb(struct snd_cs46xx * chip,char * scb_name,u32 dest,struct dsp_scb_descriptor * parent_scb,int scb_child_type)10613d19f804STakashi Iwai cs46xx_dsp_create_spio_write_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
10623d19f804STakashi Iwai                                  struct dsp_scb_descriptor * parent_scb,
10631da177e4SLinus Torvalds                                  int scb_child_type)
10641da177e4SLinus Torvalds {
10653d19f804STakashi Iwai 	struct dsp_scb_descriptor * scb;
10661da177e4SLinus Torvalds 
10673d19f804STakashi Iwai 	struct dsp_spio_write_scb spio_write_scb = {
10681da177e4SLinus Torvalds 		0,0,         /*   SPIOWAddress2:SPIOWAddress1; */
10691da177e4SLinus Torvalds 		0,           /*   SPIOWData1; */
10701da177e4SLinus Torvalds 		0,           /*   SPIOWData2; */
10711da177e4SLinus Torvalds 		0,0,         /*   SPIOWAddress4:SPIOWAddress3; */
10721da177e4SLinus Torvalds 		0,           /*   SPIOWData3; */
10731da177e4SLinus Torvalds 		0,           /*   SPIOWData4; */
10741da177e4SLinus Torvalds 		0,0,         /*   SPIOWDataPtr:Unused1; */
10751da177e4SLinus Torvalds 		{ 0,0 },     /*   Unused2[2]; */
10761da177e4SLinus Torvalds 
10771da177e4SLinus Torvalds 		0,0,	     /*   SPIOWChildPtr:SPIOWSiblingPtr; */
10781da177e4SLinus Torvalds 		0,0,         /*   SPIOWThisPtr:SPIOWEntryPoint; */
10791da177e4SLinus Torvalds 
10801da177e4SLinus Torvalds 		{
10811da177e4SLinus Torvalds 			0,
10821da177e4SLinus Torvalds 			0,
10831da177e4SLinus Torvalds 			0,
10841da177e4SLinus Torvalds 			0,
10851da177e4SLinus Torvalds 			0          /*   Unused3[5];  */
10861da177e4SLinus Torvalds 		}
10871da177e4SLinus Torvalds 	};
10881da177e4SLinus Torvalds 
10891da177e4SLinus Torvalds 	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&spio_write_scb,
10901da177e4SLinus Torvalds 					    dest,"SPIOWRITE",parent_scb,
10911da177e4SLinus Torvalds 					    scb_child_type);
10921da177e4SLinus Torvalds 
10931da177e4SLinus Torvalds 	return scb;
10941da177e4SLinus Torvalds }
10951da177e4SLinus Torvalds 
10963d19f804STakashi Iwai struct dsp_scb_descriptor *
cs46xx_dsp_create_magic_snoop_scb(struct snd_cs46xx * chip,char * scb_name,u32 dest,u16 snoop_buffer_address,struct dsp_scb_descriptor * snoop_scb,struct dsp_scb_descriptor * parent_scb,int scb_child_type)10973d19f804STakashi Iwai cs46xx_dsp_create_magic_snoop_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
10981da177e4SLinus Torvalds 				  u16 snoop_buffer_address,
10993d19f804STakashi Iwai 				  struct dsp_scb_descriptor * snoop_scb,
11003d19f804STakashi Iwai 				  struct dsp_scb_descriptor * parent_scb,
11011da177e4SLinus Torvalds 				  int scb_child_type)
11021da177e4SLinus Torvalds {
11033d19f804STakashi Iwai 	struct dsp_scb_descriptor * scb;
11041da177e4SLinus Torvalds 
11053d19f804STakashi Iwai 	struct dsp_magic_snoop_task magic_snoop_scb = {
11061da177e4SLinus Torvalds 		/* 0 */ 0, /* i0 */
11071da177e4SLinus Torvalds 		/* 1 */ 0, /* i1 */
11081da177e4SLinus Torvalds 		/* 2 */ snoop_buffer_address << 0x10,
11091da177e4SLinus Torvalds 		/* 3 */ 0,snoop_scb->address,
11101da177e4SLinus Torvalds 		/* 4 */ 0, /* i3 */
11111da177e4SLinus Torvalds 		/* 5 */ 0, /* i4 */
11121da177e4SLinus Torvalds 		/* 6 */ 0, /* i5 */
11131da177e4SLinus Torvalds 		/* 7 */ 0, /* i6 */
11141da177e4SLinus Torvalds 		/* 8 */ 0, /* i7 */
11151da177e4SLinus Torvalds 		/* 9 */ 0,0, /* next_scb, sub_list_ptr */
11161da177e4SLinus Torvalds 		/* A */ 0,0, /* entry_point, this_ptr */
11171da177e4SLinus Torvalds 		/* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
11181da177e4SLinus Torvalds 		/* C */ snoop_buffer_address  << 0x10,
11191da177e4SLinus Torvalds 		/* D */ 0,
11201da177e4SLinus Torvalds 		/* E */ { 0x8000,0x8000,
11211da177e4SLinus Torvalds 	        /* F */   0xffff,0xffff
11221da177e4SLinus Torvalds 		}
11231da177e4SLinus Torvalds 	};
11241da177e4SLinus Torvalds 
11251da177e4SLinus Torvalds 	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&magic_snoop_scb,
11261da177e4SLinus Torvalds 					    dest,"MAGICSNOOPTASK",parent_scb,
11271da177e4SLinus Torvalds 					    scb_child_type);
11281da177e4SLinus Torvalds 
11291da177e4SLinus Torvalds 	return scb;
11301da177e4SLinus Torvalds }
11311da177e4SLinus Torvalds 
11323d19f804STakashi Iwai static struct dsp_scb_descriptor *
find_next_free_scb(struct snd_cs46xx * chip,struct dsp_scb_descriptor * from)11333d19f804STakashi Iwai find_next_free_scb (struct snd_cs46xx * chip, struct dsp_scb_descriptor * from)
11341da177e4SLinus Torvalds {
11353d19f804STakashi Iwai 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
11363d19f804STakashi Iwai 	struct dsp_scb_descriptor * scb = from;
11371da177e4SLinus Torvalds 
11381da177e4SLinus Torvalds 	while (scb->next_scb_ptr != ins->the_null_scb) {
1139da3cec35STakashi Iwai 		if (snd_BUG_ON(!scb->next_scb_ptr))
1140da3cec35STakashi Iwai 			return NULL;
11411da177e4SLinus Torvalds 
11421da177e4SLinus Torvalds 		scb = scb->next_scb_ptr;
11431da177e4SLinus Torvalds 	}
11441da177e4SLinus Torvalds 
11451da177e4SLinus Torvalds 	return scb;
11461da177e4SLinus Torvalds }
11471da177e4SLinus Torvalds 
1148ba09f5d8STakashi Iwai static const u32 pcm_reader_buffer_addr[DSP_MAX_PCM_CHANNELS] = {
11491da177e4SLinus Torvalds 	0x0600, /* 1 */
11501da177e4SLinus Torvalds 	0x1500, /* 2 */
11511da177e4SLinus Torvalds 	0x1580, /* 3 */
11521da177e4SLinus Torvalds 	0x1600, /* 4 */
11531da177e4SLinus Torvalds 	0x1680, /* 5 */
11541da177e4SLinus Torvalds 	0x1700, /* 6 */
11551da177e4SLinus Torvalds 	0x1780, /* 7 */
11561da177e4SLinus Torvalds 	0x1800, /* 8 */
11571da177e4SLinus Torvalds 	0x1880, /* 9 */
11581da177e4SLinus Torvalds 	0x1900, /* 10 */
11591da177e4SLinus Torvalds 	0x1980, /* 11 */
11601da177e4SLinus Torvalds 	0x1A00, /* 12 */
11611da177e4SLinus Torvalds 	0x1A80, /* 13 */
11621da177e4SLinus Torvalds 	0x1B00, /* 14 */
11631da177e4SLinus Torvalds 	0x1B80, /* 15 */
11641da177e4SLinus Torvalds 	0x1C00, /* 16 */
11651da177e4SLinus Torvalds 	0x1C80, /* 17 */
11661da177e4SLinus Torvalds 	0x1D00, /* 18 */
11671da177e4SLinus Torvalds 	0x1D80, /* 19 */
11681da177e4SLinus Torvalds 	0x1E00, /* 20 */
11691da177e4SLinus Torvalds 	0x1E80, /* 21 */
11701da177e4SLinus Torvalds 	0x1F00, /* 22 */
11711da177e4SLinus Torvalds 	0x1F80, /* 23 */
11721da177e4SLinus Torvalds 	0x2000, /* 24 */
11731da177e4SLinus Torvalds 	0x2080, /* 25 */
11741da177e4SLinus Torvalds 	0x2100, /* 26 */
11751da177e4SLinus Torvalds 	0x2180, /* 27 */
11761da177e4SLinus Torvalds 	0x2200, /* 28 */
11771da177e4SLinus Torvalds 	0x2280, /* 29 */
11781da177e4SLinus Torvalds 	0x2300, /* 30 */
11791da177e4SLinus Torvalds 	0x2380, /* 31 */
11801da177e4SLinus Torvalds 	0x2400, /* 32 */
11811da177e4SLinus Torvalds };
11821da177e4SLinus Torvalds 
1183ba09f5d8STakashi Iwai static const u32 src_output_buffer_addr[DSP_MAX_SRC_NR] = {
11841da177e4SLinus Torvalds 	0x2B80,
11851da177e4SLinus Torvalds 	0x2BA0,
11861da177e4SLinus Torvalds 	0x2BC0,
11871da177e4SLinus Torvalds 	0x2BE0,
11881da177e4SLinus Torvalds 	0x2D00,
11891da177e4SLinus Torvalds 	0x2D20,
11901da177e4SLinus Torvalds 	0x2D40,
11911da177e4SLinus Torvalds 	0x2D60,
11921da177e4SLinus Torvalds 	0x2D80,
11931da177e4SLinus Torvalds 	0x2DA0,
11941da177e4SLinus Torvalds 	0x2DC0,
11951da177e4SLinus Torvalds 	0x2DE0,
11961da177e4SLinus Torvalds 	0x2E00,
11971da177e4SLinus Torvalds 	0x2E20
11981da177e4SLinus Torvalds };
11991da177e4SLinus Torvalds 
1200ba09f5d8STakashi Iwai static const u32 src_delay_buffer_addr[DSP_MAX_SRC_NR] = {
12011da177e4SLinus Torvalds 	0x2480,
12021da177e4SLinus Torvalds 	0x2500,
12031da177e4SLinus Torvalds 	0x2580,
12041da177e4SLinus Torvalds 	0x2600,
12051da177e4SLinus Torvalds 	0x2680,
12061da177e4SLinus Torvalds 	0x2700,
12071da177e4SLinus Torvalds 	0x2780,
12081da177e4SLinus Torvalds 	0x2800,
12091da177e4SLinus Torvalds 	0x2880,
12101da177e4SLinus Torvalds 	0x2900,
12111da177e4SLinus Torvalds 	0x2980,
12121da177e4SLinus Torvalds 	0x2A00,
12131da177e4SLinus Torvalds 	0x2A80,
12141da177e4SLinus Torvalds 	0x2B00
12151da177e4SLinus Torvalds };
12161da177e4SLinus Torvalds 
12173d19f804STakashi Iwai struct dsp_pcm_channel_descriptor *
cs46xx_dsp_create_pcm_channel(struct snd_cs46xx * chip,u32 sample_rate,void * private_data,u32 hw_dma_addr,int pcm_channel_id)12183d19f804STakashi Iwai cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
12191da177e4SLinus Torvalds 			       u32 sample_rate, void * private_data,
12201da177e4SLinus Torvalds 			       u32 hw_dma_addr,
12211da177e4SLinus Torvalds 			       int pcm_channel_id)
12221da177e4SLinus Torvalds {
12233d19f804STakashi Iwai 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
12243d19f804STakashi Iwai 	struct dsp_scb_descriptor * src_scb = NULL, * pcm_scb, * mixer_scb = NULL;
12253d19f804STakashi Iwai 	struct dsp_scb_descriptor * src_parent_scb = NULL;
12261da177e4SLinus Torvalds 
12273d19f804STakashi Iwai 	/* struct dsp_scb_descriptor * pcm_parent_scb; */
12281da177e4SLinus Torvalds 	char scb_name[DSP_MAX_SCB_NAME];
12291da177e4SLinus Torvalds 	int i, pcm_index = -1, insert_point, src_index = -1, pass_through = 0;
12301da177e4SLinus Torvalds 	unsigned long flags;
12311da177e4SLinus Torvalds 
12321da177e4SLinus Torvalds 	switch (pcm_channel_id) {
12331da177e4SLinus Torvalds 	case DSP_PCM_MAIN_CHANNEL:
12341da177e4SLinus Torvalds 		mixer_scb = ins->master_mix_scb;
12351da177e4SLinus Torvalds 		break;
12361da177e4SLinus Torvalds 	case DSP_PCM_REAR_CHANNEL:
12371da177e4SLinus Torvalds 		mixer_scb = ins->rear_mix_scb;
12381da177e4SLinus Torvalds 		break;
12391da177e4SLinus Torvalds 	case DSP_PCM_CENTER_LFE_CHANNEL:
12401da177e4SLinus Torvalds 		mixer_scb = ins->center_lfe_mix_scb;
12411da177e4SLinus Torvalds 		break;
12421da177e4SLinus Torvalds 	case DSP_PCM_S71_CHANNEL:
12431da177e4SLinus Torvalds 		/* TODO */
1244da3cec35STakashi Iwai 		snd_BUG();
12451da177e4SLinus Torvalds 		break;
12461da177e4SLinus Torvalds 	case DSP_IEC958_CHANNEL:
1247da3cec35STakashi Iwai 		if (snd_BUG_ON(!ins->asynch_tx_scb))
1248da3cec35STakashi Iwai 			return NULL;
12491da177e4SLinus Torvalds 		mixer_scb = ins->asynch_tx_scb;
12501da177e4SLinus Torvalds 
12511da177e4SLinus Torvalds 		/* if sample rate is set to 48khz we pass
12521da177e4SLinus Torvalds 		   the Sample Rate Converted (which could
12531da177e4SLinus Torvalds 		   alter the raw data stream ...) */
12541da177e4SLinus Torvalds 		if (sample_rate == 48000) {
12552b96a7f1STakashi Iwai 			dev_dbg(chip->card->dev, "IEC958 pass through\n");
12561da177e4SLinus Torvalds 			/* Hack to bypass creating a new SRC */
12571da177e4SLinus Torvalds 			pass_through = 1;
12581da177e4SLinus Torvalds 		}
12591da177e4SLinus Torvalds 		break;
12601da177e4SLinus Torvalds 	default:
1261da3cec35STakashi Iwai 		snd_BUG();
12621da177e4SLinus Torvalds 		return NULL;
12631da177e4SLinus Torvalds 	}
12641da177e4SLinus Torvalds 	/* default sample rate is 44100 */
12651da177e4SLinus Torvalds 	if (!sample_rate) sample_rate = 44100;
12661da177e4SLinus Torvalds 
12671da177e4SLinus Torvalds 	/* search for a already created SRC SCB with the same sample rate */
12681da177e4SLinus Torvalds 	for (i = 0; i < DSP_MAX_PCM_CHANNELS &&
12691da177e4SLinus Torvalds 		     (pcm_index == -1 || src_scb == NULL); ++i) {
12701da177e4SLinus Torvalds 
12711da177e4SLinus Torvalds 		/* virtual channel reserved
12721da177e4SLinus Torvalds 		   for capture */
12731da177e4SLinus Torvalds 		if (i == CS46XX_DSP_CAPTURE_CHANNEL) continue;
12741da177e4SLinus Torvalds 
12751da177e4SLinus Torvalds 		if (ins->pcm_channels[i].active) {
12761da177e4SLinus Torvalds 			if (!src_scb &&
12771da177e4SLinus Torvalds 			    ins->pcm_channels[i].sample_rate == sample_rate &&
12781da177e4SLinus Torvalds 			    ins->pcm_channels[i].mixer_scb == mixer_scb) {
12791da177e4SLinus Torvalds 				src_scb = ins->pcm_channels[i].src_scb;
12801da177e4SLinus Torvalds 				ins->pcm_channels[i].src_scb->ref_count ++;
12811da177e4SLinus Torvalds 				src_index = ins->pcm_channels[i].src_slot;
12821da177e4SLinus Torvalds 			}
12831da177e4SLinus Torvalds 		} else if (pcm_index == -1) {
12841da177e4SLinus Torvalds 			pcm_index = i;
12851da177e4SLinus Torvalds 		}
12861da177e4SLinus Torvalds 	}
12871da177e4SLinus Torvalds 
12881da177e4SLinus Torvalds 	if (pcm_index == -1) {
12892b96a7f1STakashi Iwai 		dev_err(chip->card->dev, "dsp_spos: no free PCM channel\n");
12901da177e4SLinus Torvalds 		return NULL;
12911da177e4SLinus Torvalds 	}
12921da177e4SLinus Torvalds 
12931da177e4SLinus Torvalds 	if (src_scb == NULL) {
12941da177e4SLinus Torvalds 		if (ins->nsrc_scb >= DSP_MAX_SRC_NR) {
12952b96a7f1STakashi Iwai 			dev_err(chip->card->dev,
12965396c4bdSColin Ian King 				"dsp_spos: too many SRC instances\n!");
12971da177e4SLinus Torvalds 			return NULL;
12981da177e4SLinus Torvalds 		}
12991da177e4SLinus Torvalds 
13001da177e4SLinus Torvalds 		/* find a free slot */
13011da177e4SLinus Torvalds 		for (i = 0; i < DSP_MAX_SRC_NR; ++i) {
13021da177e4SLinus Torvalds 			if (ins->src_scb_slots[i] == 0) {
13031da177e4SLinus Torvalds 				src_index = i;
13041da177e4SLinus Torvalds 				ins->src_scb_slots[i] = 1;
13051da177e4SLinus Torvalds 				break;
13061da177e4SLinus Torvalds 			}
13071da177e4SLinus Torvalds 		}
1308da3cec35STakashi Iwai 		if (snd_BUG_ON(src_index == -1))
1309da3cec35STakashi Iwai 			return NULL;
13101da177e4SLinus Torvalds 
13111da177e4SLinus Torvalds 		/* we need to create a new SRC SCB */
13121da177e4SLinus Torvalds 		if (mixer_scb->sub_list_ptr == ins->the_null_scb) {
13131da177e4SLinus Torvalds 			src_parent_scb = mixer_scb;
13141da177e4SLinus Torvalds 			insert_point = SCB_ON_PARENT_SUBLIST_SCB;
13151da177e4SLinus Torvalds 		} else {
13161da177e4SLinus Torvalds 			src_parent_scb = find_next_free_scb(chip,mixer_scb->sub_list_ptr);
13171da177e4SLinus Torvalds 			insert_point = SCB_ON_PARENT_NEXT_SCB;
13181da177e4SLinus Torvalds 		}
13191da177e4SLinus Torvalds 
13201da177e4SLinus Torvalds 		snprintf (scb_name,DSP_MAX_SCB_NAME,"SrcTask_SCB%d",src_index);
13211da177e4SLinus Torvalds 
13222b96a7f1STakashi Iwai 		dev_dbg(chip->card->dev,
13232b96a7f1STakashi Iwai 			"dsp_spos: creating SRC \"%s\"\n", scb_name);
13241da177e4SLinus Torvalds 		src_scb = cs46xx_dsp_create_src_task_scb(chip,scb_name,
13251da177e4SLinus Torvalds 							 sample_rate,
13261da177e4SLinus Torvalds 							 src_output_buffer_addr[src_index],
13271da177e4SLinus Torvalds 							 src_delay_buffer_addr[src_index],
13281da177e4SLinus Torvalds 							 /* 0x400 - 0x600 source SCBs */
13291da177e4SLinus Torvalds 							 0x400 + (src_index * 0x10) ,
13301da177e4SLinus Torvalds 							 src_parent_scb,
13311da177e4SLinus Torvalds 							 insert_point,
13321da177e4SLinus Torvalds 							 pass_through);
13331da177e4SLinus Torvalds 
13341da177e4SLinus Torvalds 		if (!src_scb) {
13352b96a7f1STakashi Iwai 			dev_err(chip->card->dev,
13362b96a7f1STakashi Iwai 				"dsp_spos: failed to create SRCtaskSCB\n");
13371da177e4SLinus Torvalds 			return NULL;
13381da177e4SLinus Torvalds 		}
13391da177e4SLinus Torvalds 
13401da177e4SLinus Torvalds 		/* cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate); */
13411da177e4SLinus Torvalds 
13421da177e4SLinus Torvalds 		ins->nsrc_scb ++;
13431da177e4SLinus Torvalds 	}
13441da177e4SLinus Torvalds 
13451da177e4SLinus Torvalds 
13461da177e4SLinus Torvalds 	snprintf (scb_name,DSP_MAX_SCB_NAME,"PCMReader_SCB%d",pcm_index);
13471da177e4SLinus Torvalds 
13482b96a7f1STakashi Iwai 	dev_dbg(chip->card->dev, "dsp_spos: creating PCM \"%s\" (%d)\n",
13492b96a7f1STakashi Iwai 		scb_name, pcm_channel_id);
13501da177e4SLinus Torvalds 
13511da177e4SLinus Torvalds 	pcm_scb = cs46xx_dsp_create_pcm_reader_scb(chip,scb_name,
13521da177e4SLinus Torvalds 						   pcm_reader_buffer_addr[pcm_index],
13531da177e4SLinus Torvalds 						   /* 0x200 - 400 PCMreader SCBs */
13541da177e4SLinus Torvalds 						   (pcm_index * 0x10) + 0x200,
13551da177e4SLinus Torvalds 						   pcm_index,    /* virtual channel 0-31 */
13561da177e4SLinus Torvalds 						   hw_dma_addr,  /* pcm hw addr */
13571da177e4SLinus Torvalds                            NULL,         /* parent SCB ptr */
13581da177e4SLinus Torvalds                            0             /* insert point */
13591da177e4SLinus Torvalds                            );
13601da177e4SLinus Torvalds 
13611da177e4SLinus Torvalds 	if (!pcm_scb) {
13622b96a7f1STakashi Iwai 		dev_err(chip->card->dev,
13632b96a7f1STakashi Iwai 			"dsp_spos: failed to create PCMreaderSCB\n");
13641da177e4SLinus Torvalds 		return NULL;
13651da177e4SLinus Torvalds 	}
13661da177e4SLinus Torvalds 
13671da177e4SLinus Torvalds 	spin_lock_irqsave(&chip->reg_lock, flags);
13681da177e4SLinus Torvalds 	ins->pcm_channels[pcm_index].sample_rate = sample_rate;
13691da177e4SLinus Torvalds 	ins->pcm_channels[pcm_index].pcm_reader_scb = pcm_scb;
13701da177e4SLinus Torvalds 	ins->pcm_channels[pcm_index].src_scb = src_scb;
13711da177e4SLinus Torvalds 	ins->pcm_channels[pcm_index].unlinked = 1;
13721da177e4SLinus Torvalds 	ins->pcm_channels[pcm_index].private_data = private_data;
13731da177e4SLinus Torvalds 	ins->pcm_channels[pcm_index].src_slot = src_index;
13741da177e4SLinus Torvalds 	ins->pcm_channels[pcm_index].active = 1;
13751da177e4SLinus Torvalds 	ins->pcm_channels[pcm_index].pcm_slot = pcm_index;
13761da177e4SLinus Torvalds 	ins->pcm_channels[pcm_index].mixer_scb = mixer_scb;
13771da177e4SLinus Torvalds 	ins->npcm_channels ++;
13781da177e4SLinus Torvalds 	spin_unlock_irqrestore(&chip->reg_lock, flags);
13791da177e4SLinus Torvalds 
13801da177e4SLinus Torvalds 	return (ins->pcm_channels + pcm_index);
13811da177e4SLinus Torvalds }
13821da177e4SLinus Torvalds 
cs46xx_dsp_pcm_channel_set_period(struct snd_cs46xx * chip,struct dsp_pcm_channel_descriptor * pcm_channel,int period_size)13833d19f804STakashi Iwai int cs46xx_dsp_pcm_channel_set_period (struct snd_cs46xx * chip,
13843d19f804STakashi Iwai 				       struct dsp_pcm_channel_descriptor * pcm_channel,
13851da177e4SLinus Torvalds 				       int period_size)
13861da177e4SLinus Torvalds {
13871da177e4SLinus Torvalds 	u32 temp = snd_cs46xx_peek (chip,pcm_channel->pcm_reader_scb->address << 2);
13881da177e4SLinus Torvalds 	temp &= ~DMA_RQ_C1_SOURCE_SIZE_MASK;
13891da177e4SLinus Torvalds 
13901da177e4SLinus Torvalds 	switch (period_size) {
13911da177e4SLinus Torvalds 	case 2048:
13921da177e4SLinus Torvalds 		temp |= DMA_RQ_C1_SOURCE_MOD1024;
13931da177e4SLinus Torvalds 		break;
13941da177e4SLinus Torvalds 	case 1024:
13951da177e4SLinus Torvalds 		temp |= DMA_RQ_C1_SOURCE_MOD512;
13961da177e4SLinus Torvalds 		break;
13971da177e4SLinus Torvalds 	case 512:
13981da177e4SLinus Torvalds 		temp |= DMA_RQ_C1_SOURCE_MOD256;
13991da177e4SLinus Torvalds 		break;
14001da177e4SLinus Torvalds 	case 256:
14011da177e4SLinus Torvalds 		temp |= DMA_RQ_C1_SOURCE_MOD128;
14021da177e4SLinus Torvalds 		break;
14031da177e4SLinus Torvalds 	case 128:
14041da177e4SLinus Torvalds 		temp |= DMA_RQ_C1_SOURCE_MOD64;
14051da177e4SLinus Torvalds 		break;
14061da177e4SLinus Torvalds 	case 64:
14071da177e4SLinus Torvalds 		temp |= DMA_RQ_C1_SOURCE_MOD32;
14081da177e4SLinus Torvalds 		break;
14091da177e4SLinus Torvalds 	case 32:
14101da177e4SLinus Torvalds 		temp |= DMA_RQ_C1_SOURCE_MOD16;
14111da177e4SLinus Torvalds 		break;
14121da177e4SLinus Torvalds 	default:
14132b96a7f1STakashi Iwai 		dev_dbg(chip->card->dev,
14142b96a7f1STakashi Iwai 			"period size (%d) not supported by HW\n", period_size);
14151da177e4SLinus Torvalds 		return -EINVAL;
14161da177e4SLinus Torvalds 	}
14171da177e4SLinus Torvalds 
14181da177e4SLinus Torvalds 	snd_cs46xx_poke (chip,pcm_channel->pcm_reader_scb->address << 2,temp);
14191da177e4SLinus Torvalds 
14201da177e4SLinus Torvalds 	return 0;
14211da177e4SLinus Torvalds }
14221da177e4SLinus Torvalds 
cs46xx_dsp_pcm_ostream_set_period(struct snd_cs46xx * chip,int period_size)14233d19f804STakashi Iwai int cs46xx_dsp_pcm_ostream_set_period (struct snd_cs46xx * chip,
14241da177e4SLinus Torvalds 				       int period_size)
14251da177e4SLinus Torvalds {
14261da177e4SLinus Torvalds 	u32 temp = snd_cs46xx_peek (chip,WRITEBACK_SCB_ADDR << 2);
14271da177e4SLinus Torvalds 	temp &= ~DMA_RQ_C1_DEST_SIZE_MASK;
14281da177e4SLinus Torvalds 
14291da177e4SLinus Torvalds 	switch (period_size) {
14301da177e4SLinus Torvalds 	case 2048:
14311da177e4SLinus Torvalds 		temp |= DMA_RQ_C1_DEST_MOD1024;
14321da177e4SLinus Torvalds 		break;
14331da177e4SLinus Torvalds 	case 1024:
14341da177e4SLinus Torvalds 		temp |= DMA_RQ_C1_DEST_MOD512;
14351da177e4SLinus Torvalds 		break;
14361da177e4SLinus Torvalds 	case 512:
14371da177e4SLinus Torvalds 		temp |= DMA_RQ_C1_DEST_MOD256;
14381da177e4SLinus Torvalds 		break;
14391da177e4SLinus Torvalds 	case 256:
14401da177e4SLinus Torvalds 		temp |= DMA_RQ_C1_DEST_MOD128;
14411da177e4SLinus Torvalds 		break;
14421da177e4SLinus Torvalds 	case 128:
14431da177e4SLinus Torvalds 		temp |= DMA_RQ_C1_DEST_MOD64;
14441da177e4SLinus Torvalds 		break;
14451da177e4SLinus Torvalds 	case 64:
14461da177e4SLinus Torvalds 		temp |= DMA_RQ_C1_DEST_MOD32;
14471da177e4SLinus Torvalds 		break;
14481da177e4SLinus Torvalds 	case 32:
14491da177e4SLinus Torvalds 		temp |= DMA_RQ_C1_DEST_MOD16;
14501da177e4SLinus Torvalds 		break;
14511da177e4SLinus Torvalds 	default:
14522b96a7f1STakashi Iwai 		dev_dbg(chip->card->dev,
14532b96a7f1STakashi Iwai 			"period size (%d) not supported by HW\n", period_size);
14541da177e4SLinus Torvalds 		return -EINVAL;
14551da177e4SLinus Torvalds 	}
14561da177e4SLinus Torvalds 
14571da177e4SLinus Torvalds 	snd_cs46xx_poke (chip,WRITEBACK_SCB_ADDR << 2,temp);
14581da177e4SLinus Torvalds 
14591da177e4SLinus Torvalds 	return 0;
14601da177e4SLinus Torvalds }
14611da177e4SLinus Torvalds 
cs46xx_dsp_destroy_pcm_channel(struct snd_cs46xx * chip,struct dsp_pcm_channel_descriptor * pcm_channel)14623d19f804STakashi Iwai void cs46xx_dsp_destroy_pcm_channel (struct snd_cs46xx * chip,
14633d19f804STakashi Iwai 				     struct dsp_pcm_channel_descriptor * pcm_channel)
14641da177e4SLinus Torvalds {
14653d19f804STakashi Iwai 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
14661da177e4SLinus Torvalds 	unsigned long flags;
14671da177e4SLinus Torvalds 
1468da3cec35STakashi Iwai 	if (snd_BUG_ON(!pcm_channel->active ||
1469da3cec35STakashi Iwai 		       ins->npcm_channels <= 0 ||
1470da3cec35STakashi Iwai 		       pcm_channel->src_scb->ref_count <= 0))
1471da3cec35STakashi Iwai 		return;
14721da177e4SLinus Torvalds 
14731da177e4SLinus Torvalds 	spin_lock_irqsave(&chip->reg_lock, flags);
14741da177e4SLinus Torvalds 	pcm_channel->unlinked = 1;
14751da177e4SLinus Torvalds 	pcm_channel->active = 0;
14761da177e4SLinus Torvalds 	pcm_channel->private_data = NULL;
14771da177e4SLinus Torvalds 	pcm_channel->src_scb->ref_count --;
14781da177e4SLinus Torvalds 	ins->npcm_channels --;
14791da177e4SLinus Torvalds 	spin_unlock_irqrestore(&chip->reg_lock, flags);
14801da177e4SLinus Torvalds 
14811da177e4SLinus Torvalds 	cs46xx_dsp_remove_scb(chip,pcm_channel->pcm_reader_scb);
14821da177e4SLinus Torvalds 
14831da177e4SLinus Torvalds 	if (!pcm_channel->src_scb->ref_count) {
14841da177e4SLinus Torvalds 		cs46xx_dsp_remove_scb(chip,pcm_channel->src_scb);
14851da177e4SLinus Torvalds 
1486da3cec35STakashi Iwai 		if (snd_BUG_ON(pcm_channel->src_slot < 0 ||
1487da3cec35STakashi Iwai 			       pcm_channel->src_slot >= DSP_MAX_SRC_NR))
1488da3cec35STakashi Iwai 			return;
14891da177e4SLinus Torvalds 
14901da177e4SLinus Torvalds 		ins->src_scb_slots[pcm_channel->src_slot] = 0;
14911da177e4SLinus Torvalds 		ins->nsrc_scb --;
14921da177e4SLinus Torvalds 	}
14931da177e4SLinus Torvalds }
14941da177e4SLinus Torvalds 
cs46xx_dsp_pcm_unlink(struct snd_cs46xx * chip,struct dsp_pcm_channel_descriptor * pcm_channel)14953d19f804STakashi Iwai int cs46xx_dsp_pcm_unlink (struct snd_cs46xx * chip,
14963d19f804STakashi Iwai 			   struct dsp_pcm_channel_descriptor * pcm_channel)
14971da177e4SLinus Torvalds {
14981da177e4SLinus Torvalds 	unsigned long flags;
14991da177e4SLinus Torvalds 
1500da3cec35STakashi Iwai 	if (snd_BUG_ON(!pcm_channel->active ||
1501da3cec35STakashi Iwai 		       chip->dsp_spos_instance->npcm_channels <= 0))
1502da3cec35STakashi Iwai 		return -EIO;
15031da177e4SLinus Torvalds 
150441116e92STakashi Iwai 	spin_lock_irqsave(&chip->reg_lock, flags);
15051da177e4SLinus Torvalds 	if (pcm_channel->unlinked) {
150641116e92STakashi Iwai 		spin_unlock_irqrestore(&chip->reg_lock, flags);
15071da177e4SLinus Torvalds 		return -EIO;
15081da177e4SLinus Torvalds 	}
15091da177e4SLinus Torvalds 
15101da177e4SLinus Torvalds 	pcm_channel->unlinked = 1;
15111da177e4SLinus Torvalds 
15121da177e4SLinus Torvalds 	_dsp_unlink_scb (chip,pcm_channel->pcm_reader_scb);
151341116e92STakashi Iwai 	spin_unlock_irqrestore(&chip->reg_lock, flags);
15141da177e4SLinus Torvalds 
15151da177e4SLinus Torvalds 	return 0;
15161da177e4SLinus Torvalds }
15171da177e4SLinus Torvalds 
cs46xx_dsp_pcm_link(struct snd_cs46xx * chip,struct dsp_pcm_channel_descriptor * pcm_channel)15183d19f804STakashi Iwai int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip,
15193d19f804STakashi Iwai 			 struct dsp_pcm_channel_descriptor * pcm_channel)
15201da177e4SLinus Torvalds {
15213d19f804STakashi Iwai 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
15223d19f804STakashi Iwai 	struct dsp_scb_descriptor * parent_scb;
15233d19f804STakashi Iwai 	struct dsp_scb_descriptor * src_scb = pcm_channel->src_scb;
15241da177e4SLinus Torvalds 	unsigned long flags;
15251da177e4SLinus Torvalds 
152641116e92STakashi Iwai 	spin_lock_irqsave(&chip->reg_lock, flags);
15271da177e4SLinus Torvalds 
15281da177e4SLinus Torvalds 	if (pcm_channel->unlinked == 0) {
152941116e92STakashi Iwai 		spin_unlock_irqrestore(&chip->reg_lock, flags);
15301da177e4SLinus Torvalds 		return -EIO;
15311da177e4SLinus Torvalds 	}
15321da177e4SLinus Torvalds 
15331da177e4SLinus Torvalds 	parent_scb = src_scb;
15341da177e4SLinus Torvalds 
15351da177e4SLinus Torvalds 	if (src_scb->sub_list_ptr != ins->the_null_scb) {
15361da177e4SLinus Torvalds 		src_scb->sub_list_ptr->parent_scb_ptr = pcm_channel->pcm_reader_scb;
15371da177e4SLinus Torvalds 		pcm_channel->pcm_reader_scb->next_scb_ptr = src_scb->sub_list_ptr;
15381da177e4SLinus Torvalds 	}
15391da177e4SLinus Torvalds 
15401da177e4SLinus Torvalds 	src_scb->sub_list_ptr = pcm_channel->pcm_reader_scb;
15411da177e4SLinus Torvalds 
1542da3cec35STakashi Iwai 	snd_BUG_ON(pcm_channel->pcm_reader_scb->parent_scb_ptr);
15431da177e4SLinus Torvalds 	pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb;
15441da177e4SLinus Torvalds 
15451da177e4SLinus Torvalds 	/* update SCB entry in DSP RAM */
15461da177e4SLinus Torvalds 	cs46xx_dsp_spos_update_scb(chip,pcm_channel->pcm_reader_scb);
15471da177e4SLinus Torvalds 
15481da177e4SLinus Torvalds 	/* update parent SCB entry */
15491da177e4SLinus Torvalds 	cs46xx_dsp_spos_update_scb(chip,parent_scb);
15501da177e4SLinus Torvalds 
15511da177e4SLinus Torvalds 	pcm_channel->unlinked = 0;
15521da177e4SLinus Torvalds 	spin_unlock_irqrestore(&chip->reg_lock, flags);
15531da177e4SLinus Torvalds 	return 0;
15541da177e4SLinus Torvalds }
15551da177e4SLinus Torvalds 
15563d19f804STakashi Iwai struct dsp_scb_descriptor *
cs46xx_add_record_source(struct snd_cs46xx * chip,struct dsp_scb_descriptor * source,u16 addr,char * scb_name)15573d19f804STakashi Iwai cs46xx_add_record_source (struct snd_cs46xx *chip, struct dsp_scb_descriptor * source,
15581da177e4SLinus Torvalds 			  u16 addr, char * scb_name)
15591da177e4SLinus Torvalds {
15603d19f804STakashi Iwai   	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
15613d19f804STakashi Iwai 	struct dsp_scb_descriptor * parent;
15623d19f804STakashi Iwai 	struct dsp_scb_descriptor * pcm_input;
15631da177e4SLinus Torvalds 	int insert_point;
15641da177e4SLinus Torvalds 
1565da3cec35STakashi Iwai 	if (snd_BUG_ON(!ins->record_mixer_scb))
1566da3cec35STakashi Iwai 		return NULL;
15671da177e4SLinus Torvalds 
15681da177e4SLinus Torvalds 	if (ins->record_mixer_scb->sub_list_ptr != ins->the_null_scb) {
15691da177e4SLinus Torvalds 		parent = find_next_free_scb (chip,ins->record_mixer_scb->sub_list_ptr);
15701da177e4SLinus Torvalds 		insert_point = SCB_ON_PARENT_NEXT_SCB;
15711da177e4SLinus Torvalds 	} else {
15721da177e4SLinus Torvalds 		parent = ins->record_mixer_scb;
15731da177e4SLinus Torvalds 		insert_point = SCB_ON_PARENT_SUBLIST_SCB;
15741da177e4SLinus Torvalds 	}
15751da177e4SLinus Torvalds 
15761da177e4SLinus Torvalds 	pcm_input = cs46xx_dsp_create_pcm_serial_input_scb(chip,scb_name,addr,
15771da177e4SLinus Torvalds 							   source, parent,
15781da177e4SLinus Torvalds 							   insert_point);
15791da177e4SLinus Torvalds 
15801da177e4SLinus Torvalds 	return pcm_input;
15811da177e4SLinus Torvalds }
15821da177e4SLinus Torvalds 
cs46xx_src_unlink(struct snd_cs46xx * chip,struct dsp_scb_descriptor * src)15833d19f804STakashi Iwai int cs46xx_src_unlink(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
15841da177e4SLinus Torvalds {
158541116e92STakashi Iwai 	unsigned long flags;
158641116e92STakashi Iwai 
1587da3cec35STakashi Iwai 	if (snd_BUG_ON(!src->parent_scb_ptr))
1588da3cec35STakashi Iwai 		return -EINVAL;
15891da177e4SLinus Torvalds 
15901da177e4SLinus Torvalds 	/* mute SCB */
15911da177e4SLinus Torvalds 	cs46xx_dsp_scb_set_volume (chip,src,0,0);
15921da177e4SLinus Torvalds 
159341116e92STakashi Iwai 	spin_lock_irqsave(&chip->reg_lock, flags);
15941da177e4SLinus Torvalds 	_dsp_unlink_scb (chip,src);
159541116e92STakashi Iwai 	spin_unlock_irqrestore(&chip->reg_lock, flags);
15961da177e4SLinus Torvalds 
15971da177e4SLinus Torvalds 	return 0;
15981da177e4SLinus Torvalds }
15991da177e4SLinus Torvalds 
cs46xx_src_link(struct snd_cs46xx * chip,struct dsp_scb_descriptor * src)16003d19f804STakashi Iwai int cs46xx_src_link(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
16011da177e4SLinus Torvalds {
16023d19f804STakashi Iwai 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
16033d19f804STakashi Iwai 	struct dsp_scb_descriptor * parent_scb;
16041da177e4SLinus Torvalds 
1605da3cec35STakashi Iwai 	if (snd_BUG_ON(src->parent_scb_ptr))
1606da3cec35STakashi Iwai 		return -EINVAL;
1607da3cec35STakashi Iwai 	if (snd_BUG_ON(!ins->master_mix_scb))
1608da3cec35STakashi Iwai 		return -EINVAL;
16091da177e4SLinus Torvalds 
16101da177e4SLinus Torvalds 	if (ins->master_mix_scb->sub_list_ptr != ins->the_null_scb) {
16111da177e4SLinus Torvalds 		parent_scb = find_next_free_scb (chip,ins->master_mix_scb->sub_list_ptr);
16121da177e4SLinus Torvalds 		parent_scb->next_scb_ptr = src;
16131da177e4SLinus Torvalds 	} else {
16141da177e4SLinus Torvalds 		parent_scb = ins->master_mix_scb;
16151da177e4SLinus Torvalds 		parent_scb->sub_list_ptr = src;
16161da177e4SLinus Torvalds 	}
16171da177e4SLinus Torvalds 
16181da177e4SLinus Torvalds 	src->parent_scb_ptr = parent_scb;
16191da177e4SLinus Torvalds 
16201da177e4SLinus Torvalds 	/* update entry in DSP RAM */
16211da177e4SLinus Torvalds 	cs46xx_dsp_spos_update_scb(chip,parent_scb);
16221da177e4SLinus Torvalds 
16231da177e4SLinus Torvalds 	return 0;
16241da177e4SLinus Torvalds }
16251da177e4SLinus Torvalds 
cs46xx_dsp_enable_spdif_out(struct snd_cs46xx * chip)16263d19f804STakashi Iwai int cs46xx_dsp_enable_spdif_out (struct snd_cs46xx *chip)
16271da177e4SLinus Torvalds {
16283d19f804STakashi Iwai 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
16291da177e4SLinus Torvalds 
16301da177e4SLinus Torvalds 	if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
16311da177e4SLinus Torvalds 		cs46xx_dsp_enable_spdif_hw (chip);
16321da177e4SLinus Torvalds 	}
16331da177e4SLinus Torvalds 
16341da177e4SLinus Torvalds 	/* dont touch anything if SPDIF is open */
16351da177e4SLinus Torvalds 	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
16361da177e4SLinus Torvalds 		/* when cs46xx_iec958_post_close(...) is called it
16371da177e4SLinus Torvalds 		   will call this function if necessary depending on
16381da177e4SLinus Torvalds 		   this bit */
16391da177e4SLinus Torvalds 		ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
16401da177e4SLinus Torvalds 
16411da177e4SLinus Torvalds 		return -EBUSY;
16421da177e4SLinus Torvalds 	}
16431da177e4SLinus Torvalds 
1644da3cec35STakashi Iwai 	if (snd_BUG_ON(ins->asynch_tx_scb))
1645da3cec35STakashi Iwai 		return -EINVAL;
1646da3cec35STakashi Iwai 	if (snd_BUG_ON(ins->master_mix_scb->next_scb_ptr !=
1647da3cec35STakashi Iwai 		       ins->the_null_scb))
1648da3cec35STakashi Iwai 		return -EINVAL;
16491da177e4SLinus Torvalds 
16501da177e4SLinus Torvalds 	/* reset output snooper sample buffer pointer */
16511da177e4SLinus Torvalds 	snd_cs46xx_poke (chip, (ins->ref_snoop_scb->address + 2) << 2,
16521da177e4SLinus Torvalds 			 (OUTPUT_SNOOP_BUFFER + 0x10) << 0x10 );
16531da177e4SLinus Torvalds 
16541da177e4SLinus Torvalds 	/* The asynch. transfer task */
16551da177e4SLinus Torvalds 	ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
16561da177e4SLinus Torvalds 								SPDIFO_SCB_INST,
16571da177e4SLinus Torvalds 								SPDIFO_IP_OUTPUT_BUFFER1,
16581da177e4SLinus Torvalds 								ins->master_mix_scb,
16591da177e4SLinus Torvalds 								SCB_ON_PARENT_NEXT_SCB);
16601da177e4SLinus Torvalds 	if (!ins->asynch_tx_scb) return -ENOMEM;
16611da177e4SLinus Torvalds 
16621da177e4SLinus Torvalds 	ins->spdif_pcm_input_scb = cs46xx_dsp_create_pcm_serial_input_scb(chip,"PCMSerialInput_II",
16631da177e4SLinus Torvalds 									  PCMSERIALINII_SCB_ADDR,
16641da177e4SLinus Torvalds 									  ins->ref_snoop_scb,
16651da177e4SLinus Torvalds 									  ins->asynch_tx_scb,
16661da177e4SLinus Torvalds 									  SCB_ON_PARENT_SUBLIST_SCB);
16671da177e4SLinus Torvalds 
16681da177e4SLinus Torvalds 
16691da177e4SLinus Torvalds 	if (!ins->spdif_pcm_input_scb) return -ENOMEM;
16701da177e4SLinus Torvalds 
16711da177e4SLinus Torvalds 	/* monitor state */
16721da177e4SLinus Torvalds 	ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
16731da177e4SLinus Torvalds 
16741da177e4SLinus Torvalds 	return 0;
16751da177e4SLinus Torvalds }
16761da177e4SLinus Torvalds 
cs46xx_dsp_disable_spdif_out(struct snd_cs46xx * chip)16773d19f804STakashi Iwai int  cs46xx_dsp_disable_spdif_out (struct snd_cs46xx *chip)
16781da177e4SLinus Torvalds {
16793d19f804STakashi Iwai 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
16801da177e4SLinus Torvalds 
16811da177e4SLinus Torvalds 	/* dont touch anything if SPDIF is open */
16821da177e4SLinus Torvalds 	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
16831da177e4SLinus Torvalds 		ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
16841da177e4SLinus Torvalds 		return -EBUSY;
16851da177e4SLinus Torvalds 	}
16861da177e4SLinus Torvalds 
16871da177e4SLinus Torvalds 	/* check integrety */
1688da3cec35STakashi Iwai 	if (snd_BUG_ON(!ins->asynch_tx_scb))
1689da3cec35STakashi Iwai 		return -EINVAL;
1690da3cec35STakashi Iwai 	if (snd_BUG_ON(!ins->spdif_pcm_input_scb))
1691da3cec35STakashi Iwai 		return -EINVAL;
1692da3cec35STakashi Iwai 	if (snd_BUG_ON(ins->master_mix_scb->next_scb_ptr != ins->asynch_tx_scb))
1693da3cec35STakashi Iwai 		return -EINVAL;
1694da3cec35STakashi Iwai 	if (snd_BUG_ON(ins->asynch_tx_scb->parent_scb_ptr !=
1695da3cec35STakashi Iwai 		       ins->master_mix_scb))
1696da3cec35STakashi Iwai 		return -EINVAL;
16971da177e4SLinus Torvalds 
16981da177e4SLinus Torvalds 	cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
16991da177e4SLinus Torvalds 	cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
17001da177e4SLinus Torvalds 
17011da177e4SLinus Torvalds 	ins->spdif_pcm_input_scb = NULL;
17021da177e4SLinus Torvalds 	ins->asynch_tx_scb = NULL;
17031da177e4SLinus Torvalds 
17041da177e4SLinus Torvalds 	/* clear buffer to prevent any undesired noise */
17051da177e4SLinus Torvalds 	_dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
17061da177e4SLinus Torvalds 
17071da177e4SLinus Torvalds 	/* monitor state */
17081da177e4SLinus Torvalds 	ins->spdif_status_out  &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
17091da177e4SLinus Torvalds 
17101da177e4SLinus Torvalds 
17111da177e4SLinus Torvalds 	return 0;
17121da177e4SLinus Torvalds }
17131da177e4SLinus Torvalds 
cs46xx_iec958_pre_open(struct snd_cs46xx * chip)17143d19f804STakashi Iwai int cs46xx_iec958_pre_open (struct snd_cs46xx *chip)
17151da177e4SLinus Torvalds {
17163d19f804STakashi Iwai 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
17171da177e4SLinus Torvalds 
17181da177e4SLinus Torvalds 	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
1719*c7fabbc5SRandy Dunlap 		/* remove AsynchFGTxSCB and PCMSerialInput_II */
17201da177e4SLinus Torvalds 		cs46xx_dsp_disable_spdif_out (chip);
17211da177e4SLinus Torvalds 
17221da177e4SLinus Torvalds 		/* save state */
17231da177e4SLinus Torvalds 		ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
17241da177e4SLinus Torvalds 	}
17251da177e4SLinus Torvalds 
17261da177e4SLinus Torvalds 	/* if not enabled already */
17271da177e4SLinus Torvalds 	if ( !(ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
17281da177e4SLinus Torvalds 		cs46xx_dsp_enable_spdif_hw (chip);
17291da177e4SLinus Torvalds 	}
17301da177e4SLinus Torvalds 
17311da177e4SLinus Torvalds 	/* Create the asynch. transfer task  for playback */
17321da177e4SLinus Torvalds 	ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
17331da177e4SLinus Torvalds 								SPDIFO_SCB_INST,
17341da177e4SLinus Torvalds 								SPDIFO_IP_OUTPUT_BUFFER1,
17351da177e4SLinus Torvalds 								ins->master_mix_scb,
17361da177e4SLinus Torvalds 								SCB_ON_PARENT_NEXT_SCB);
17371da177e4SLinus Torvalds 
17381da177e4SLinus Torvalds 
17391da177e4SLinus Torvalds 	/* set spdif channel status value for streaming */
17401da177e4SLinus Torvalds 	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_stream);
17411da177e4SLinus Torvalds 
17421da177e4SLinus Torvalds 	ins->spdif_status_out  |= DSP_SPDIF_STATUS_PLAYBACK_OPEN;
17431da177e4SLinus Torvalds 
17441da177e4SLinus Torvalds 	return 0;
17451da177e4SLinus Torvalds }
17461da177e4SLinus Torvalds 
cs46xx_iec958_post_close(struct snd_cs46xx * chip)17473d19f804STakashi Iwai int cs46xx_iec958_post_close (struct snd_cs46xx *chip)
17481da177e4SLinus Torvalds {
17493d19f804STakashi Iwai 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
17501da177e4SLinus Torvalds 
1751da3cec35STakashi Iwai 	if (snd_BUG_ON(!ins->asynch_tx_scb))
1752da3cec35STakashi Iwai 		return -EINVAL;
17531da177e4SLinus Torvalds 
17541da177e4SLinus Torvalds 	ins->spdif_status_out  &= ~DSP_SPDIF_STATUS_PLAYBACK_OPEN;
17551da177e4SLinus Torvalds 
17561da177e4SLinus Torvalds 	/* restore settings */
17571da177e4SLinus Torvalds 	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);
17581da177e4SLinus Torvalds 
17591da177e4SLinus Torvalds 	/* deallocate stuff */
17601da177e4SLinus Torvalds 	if (ins->spdif_pcm_input_scb != NULL) {
17611da177e4SLinus Torvalds 		cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
17621da177e4SLinus Torvalds 		ins->spdif_pcm_input_scb = NULL;
17631da177e4SLinus Torvalds 	}
17641da177e4SLinus Torvalds 
17651da177e4SLinus Torvalds 	cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
17661da177e4SLinus Torvalds 	ins->asynch_tx_scb = NULL;
17671da177e4SLinus Torvalds 
17681da177e4SLinus Torvalds 	/* clear buffer to prevent any undesired noise */
17691da177e4SLinus Torvalds 	_dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
17701da177e4SLinus Torvalds 
17711da177e4SLinus Torvalds 	/* restore state */
17721da177e4SLinus Torvalds 	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
17731da177e4SLinus Torvalds 		cs46xx_dsp_enable_spdif_out (chip);
17741da177e4SLinus Torvalds 	}
17751da177e4SLinus Torvalds 
17761da177e4SLinus Torvalds 	return 0;
17771da177e4SLinus Torvalds }
1778