1 /*
2  *
3  *   This program is free software; you can redistribute it and/or modify
4  *   it under the terms of the GNU General Public License as published by
5  *   the Free Software Foundation; either version 2 of the License, or
6  *   (at your option) any later version.
7  *
8  *   This program is distributed in the hope that it will be useful,
9  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *   GNU General Public License for more details.
12  *
13  *   You should have received a copy of the GNU General Public License
14  *   along with this program; if not, write to the Free Software
15  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16  *
17  */
18 
19 /*
20  * 2002-07 Benny Sjostrand benny@hostmobility.com
21  */
22 
23 
24 #include <linux/io.h>
25 #include <linux/delay.h>
26 #include <linux/pm.h>
27 #include <linux/init.h>
28 #include <linux/slab.h>
29 #include <linux/mutex.h>
30 
31 #include <sound/core.h>
32 #include <sound/control.h>
33 #include <sound/info.h>
34 #include "cs46xx.h"
35 
36 #include "cs46xx_lib.h"
37 #include "dsp_spos.h"
38 
39 struct proc_scb_info {
40 	struct dsp_scb_descriptor * scb_desc;
41 	struct snd_cs46xx *chip;
42 };
43 
44 static void remove_symbol (struct snd_cs46xx * chip, struct dsp_symbol_entry * symbol)
45 {
46 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
47 	int symbol_index = (int)(symbol - ins->symbol_table.symbols);
48 
49 	if (snd_BUG_ON(ins->symbol_table.nsymbols <= 0))
50 		return;
51 	if (snd_BUG_ON(symbol_index < 0 ||
52 		       symbol_index >= ins->symbol_table.nsymbols))
53 		return;
54 
55 	ins->symbol_table.symbols[symbol_index].deleted = 1;
56 
57 	if (symbol_index < ins->symbol_table.highest_frag_index) {
58 		ins->symbol_table.highest_frag_index = symbol_index;
59 	}
60 
61 	if (symbol_index == ins->symbol_table.nsymbols - 1)
62 		ins->symbol_table.nsymbols --;
63 
64 	if (ins->symbol_table.highest_frag_index > ins->symbol_table.nsymbols) {
65 		ins->symbol_table.highest_frag_index = ins->symbol_table.nsymbols;
66 	}
67 
68 }
69 
70 #ifdef CONFIG_SND_PROC_FS
71 static void cs46xx_dsp_proc_scb_info_read (struct snd_info_entry *entry,
72 					   struct snd_info_buffer *buffer)
73 {
74 	struct proc_scb_info * scb_info  = entry->private_data;
75 	struct dsp_scb_descriptor * scb = scb_info->scb_desc;
76 	struct snd_cs46xx *chip = scb_info->chip;
77 	int j,col;
78 	void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
79 
80 	mutex_lock(&chip->spos_mutex);
81 	snd_iprintf(buffer,"%04x %s:\n",scb->address,scb->scb_name);
82 
83 	for (col = 0,j = 0;j < 0x10; j++,col++) {
84 		if (col == 4) {
85 			snd_iprintf(buffer,"\n");
86 			col = 0;
87 		}
88 		snd_iprintf(buffer,"%08x ",readl(dst + (scb->address + j) * sizeof(u32)));
89 	}
90 
91 	snd_iprintf(buffer,"\n");
92 
93 	if (scb->parent_scb_ptr != NULL) {
94 		snd_iprintf(buffer,"parent [%s:%04x] ",
95 			    scb->parent_scb_ptr->scb_name,
96 			    scb->parent_scb_ptr->address);
97 	} else snd_iprintf(buffer,"parent [none] ");
98 
99 	snd_iprintf(buffer,"sub_list_ptr [%s:%04x]\nnext_scb_ptr [%s:%04x]  task_entry [%s:%04x]\n",
100 		    scb->sub_list_ptr->scb_name,
101 		    scb->sub_list_ptr->address,
102 		    scb->next_scb_ptr->scb_name,
103 		    scb->next_scb_ptr->address,
104 		    scb->task_entry->symbol_name,
105 		    scb->task_entry->address);
106 
107 	snd_iprintf(buffer,"index [%d] ref_count [%d]\n",scb->index,scb->ref_count);
108 	mutex_unlock(&chip->spos_mutex);
109 }
110 #endif
111 
112 static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
113 {
114 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
115 
116 	if ( scb->parent_scb_ptr ) {
117 		/* unlink parent SCB */
118 		if (snd_BUG_ON(scb->parent_scb_ptr->sub_list_ptr != scb &&
119 			       scb->parent_scb_ptr->next_scb_ptr != scb))
120 			return;
121 
122 		if (scb->parent_scb_ptr->sub_list_ptr == scb) {
123 
124 			if (scb->next_scb_ptr == ins->the_null_scb) {
125 				/* last and only node in parent sublist */
126 				scb->parent_scb_ptr->sub_list_ptr = scb->sub_list_ptr;
127 
128 				if (scb->sub_list_ptr != ins->the_null_scb) {
129 					scb->sub_list_ptr->parent_scb_ptr = scb->parent_scb_ptr;
130 				}
131 				scb->sub_list_ptr = ins->the_null_scb;
132 			} else {
133 				/* first node in parent sublist */
134 				scb->parent_scb_ptr->sub_list_ptr = scb->next_scb_ptr;
135 
136 				if (scb->next_scb_ptr != ins->the_null_scb) {
137 					/* update next node parent ptr. */
138 					scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
139 				}
140 				scb->next_scb_ptr = ins->the_null_scb;
141 			}
142 		} else {
143 			scb->parent_scb_ptr->next_scb_ptr = scb->next_scb_ptr;
144 
145 			if (scb->next_scb_ptr != ins->the_null_scb) {
146 				/* update next node parent ptr. */
147 				scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
148 			}
149 			scb->next_scb_ptr = ins->the_null_scb;
150 		}
151 
152 		/* update parent first entry in DSP RAM */
153 		cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
154 
155 		/* then update entry in DSP RAM */
156 		cs46xx_dsp_spos_update_scb(chip,scb);
157 
158 		scb->parent_scb_ptr = NULL;
159 	}
160 }
161 
162 static void _dsp_clear_sample_buffer (struct snd_cs46xx *chip, u32 sample_buffer_addr,
163 				      int dword_count)
164 {
165 	void __iomem *dst = chip->region.idx[2].remap_addr + sample_buffer_addr;
166 	int i;
167 
168 	for (i = 0; i < dword_count ; ++i ) {
169 		writel(0, dst);
170 		dst += 4;
171 	}
172 }
173 
174 void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
175 {
176 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
177 	unsigned long flags;
178 
179 	/* check integrety */
180 	if (snd_BUG_ON(scb->index < 0 ||
181 		       scb->index >= ins->nscb ||
182 		       (ins->scbs + scb->index) != scb))
183 		return;
184 
185 #if 0
186 	/* can't remove a SCB with childs before
187 	   removing childs first  */
188 	if (snd_BUG_ON(scb->sub_list_ptr != ins->the_null_scb ||
189 		       scb->next_scb_ptr != ins->the_null_scb))
190 		goto _end;
191 #endif
192 
193 	spin_lock_irqsave(&chip->reg_lock, flags);
194 	_dsp_unlink_scb (chip,scb);
195 	spin_unlock_irqrestore(&chip->reg_lock, flags);
196 
197 	cs46xx_dsp_proc_free_scb_desc(scb);
198 	if (snd_BUG_ON(!scb->scb_symbol))
199 		return;
200 	remove_symbol (chip,scb->scb_symbol);
201 
202 	ins->scbs[scb->index].deleted = 1;
203 #ifdef CONFIG_PM_SLEEP
204 	kfree(ins->scbs[scb->index].data);
205 	ins->scbs[scb->index].data = NULL;
206 #endif
207 
208 	if (scb->index < ins->scb_highest_frag_index)
209 		ins->scb_highest_frag_index = scb->index;
210 
211 	if (scb->index == ins->nscb - 1) {
212 		ins->nscb --;
213 	}
214 
215 	if (ins->scb_highest_frag_index > ins->nscb) {
216 		ins->scb_highest_frag_index = ins->nscb;
217 	}
218 
219 #if 0
220 	/* !!!! THIS IS A PIECE OF SHIT MADE BY ME !!! */
221 	for(i = scb->index + 1;i < ins->nscb; ++i) {
222 		ins->scbs[i - 1].index = i - 1;
223 	}
224 #endif
225 }
226 
227 
228 #ifdef CONFIG_SND_PROC_FS
229 void cs46xx_dsp_proc_free_scb_desc (struct dsp_scb_descriptor * scb)
230 {
231 	if (scb->proc_info) {
232 		struct proc_scb_info * scb_info = scb->proc_info->private_data;
233 		struct snd_cs46xx *chip = scb_info->chip;
234 
235 		dev_dbg(chip->card->dev,
236 			"cs46xx_dsp_proc_free_scb_desc: freeing %s\n",
237 			scb->scb_name);
238 
239 		snd_info_free_entry(scb->proc_info);
240 		scb->proc_info = NULL;
241 
242 		kfree (scb_info);
243 	}
244 }
245 
246 void cs46xx_dsp_proc_register_scb_desc (struct snd_cs46xx *chip,
247 					struct dsp_scb_descriptor * scb)
248 {
249 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
250 	struct snd_info_entry * entry;
251 	struct proc_scb_info * scb_info;
252 
253 	/* register to proc */
254 	if (ins->snd_card != NULL && ins->proc_dsp_dir != NULL &&
255 	    scb->proc_info == NULL) {
256 
257 		entry = snd_info_create_card_entry(ins->snd_card, scb->scb_name,
258 						   ins->proc_dsp_dir);
259 		if (entry) {
260 			scb_info = kmalloc(sizeof(struct proc_scb_info), GFP_KERNEL);
261 			if (!scb_info) {
262 				snd_info_free_entry(entry);
263 				entry = NULL;
264 				goto out;
265 			}
266 
267 			scb_info->chip = chip;
268 			scb_info->scb_desc = scb;
269 			snd_info_set_text_ops(entry, scb_info,
270 					      cs46xx_dsp_proc_scb_info_read);
271 		}
272 out:
273 		scb->proc_info = entry;
274 	}
275 }
276 #endif /* CONFIG_SND_PROC_FS */
277 
278 static struct dsp_scb_descriptor *
279 _dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32 dest,
280                          struct dsp_symbol_entry * task_entry,
281                          struct dsp_scb_descriptor * parent_scb,
282                          int scb_child_type)
283 {
284 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
285 	struct dsp_scb_descriptor * scb;
286 
287 	unsigned long flags;
288 
289 	if (snd_BUG_ON(!ins->the_null_scb))
290 		return NULL;
291 
292 	/* fill the data that will be wroten to DSP */
293 	scb_data[SCBsubListPtr] =
294 		(ins->the_null_scb->address << 0x10) | ins->the_null_scb->address;
295 
296 	scb_data[SCBfuncEntryPtr] &= 0xFFFF0000;
297 	scb_data[SCBfuncEntryPtr] |= task_entry->address;
298 
299 	dev_dbg(chip->card->dev, "dsp_spos: creating SCB <%s>\n", name);
300 
301 	scb = cs46xx_dsp_create_scb(chip,name,scb_data,dest);
302 
303 
304 	scb->sub_list_ptr = ins->the_null_scb;
305 	scb->next_scb_ptr = ins->the_null_scb;
306 
307 	scb->parent_scb_ptr = parent_scb;
308 	scb->task_entry = task_entry;
309 
310 
311 	/* update parent SCB */
312 	if (scb->parent_scb_ptr) {
313 #if 0
314 		dev_dbg(chip->card->dev,
315 			"scb->parent_scb_ptr = %s\n",
316 			scb->parent_scb_ptr->scb_name);
317 		dev_dbg(chip->card->dev,
318 			"scb->parent_scb_ptr->next_scb_ptr = %s\n",
319 			scb->parent_scb_ptr->next_scb_ptr->scb_name);
320 		dev_dbg(chip->card->dev,
321 			"scb->parent_scb_ptr->sub_list_ptr = %s\n",
322 			scb->parent_scb_ptr->sub_list_ptr->scb_name);
323 #endif
324 		/* link to  parent SCB */
325 		if (scb_child_type == SCB_ON_PARENT_NEXT_SCB) {
326 			if (snd_BUG_ON(scb->parent_scb_ptr->next_scb_ptr !=
327 				       ins->the_null_scb))
328 				return NULL;
329 
330 			scb->parent_scb_ptr->next_scb_ptr = scb;
331 
332 		} else if (scb_child_type == SCB_ON_PARENT_SUBLIST_SCB) {
333 			if (snd_BUG_ON(scb->parent_scb_ptr->sub_list_ptr !=
334 				       ins->the_null_scb))
335 				return NULL;
336 
337 			scb->parent_scb_ptr->sub_list_ptr = scb;
338 		} else {
339 			snd_BUG();
340 		}
341 
342 		spin_lock_irqsave(&chip->reg_lock, flags);
343 
344 		/* update entry in DSP RAM */
345 		cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
346 
347 		spin_unlock_irqrestore(&chip->reg_lock, flags);
348 	}
349 
350 
351 	cs46xx_dsp_proc_register_scb_desc (chip,scb);
352 
353 	return scb;
354 }
355 
356 static struct dsp_scb_descriptor *
357 cs46xx_dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data,
358 			       u32 dest, char * task_entry_name,
359                                struct dsp_scb_descriptor * parent_scb,
360                                int scb_child_type)
361 {
362 	struct dsp_symbol_entry * task_entry;
363 
364 	task_entry = cs46xx_dsp_lookup_symbol (chip,task_entry_name,
365 					       SYMBOL_CODE);
366 
367 	if (task_entry == NULL) {
368 		dev_err(chip->card->dev,
369 			"dsp_spos: symbol %s not found\n", task_entry_name);
370 		return NULL;
371 	}
372 
373 	return _dsp_create_generic_scb (chip,name,scb_data,dest,task_entry,
374 					parent_scb,scb_child_type);
375 }
376 
377 struct dsp_scb_descriptor *
378 cs46xx_dsp_create_timing_master_scb (struct snd_cs46xx *chip)
379 {
380 	struct dsp_scb_descriptor * scb;
381 
382 	struct dsp_timing_master_scb timing_master_scb = {
383 		{ 0,
384 		  0,
385 		  0,
386 		  0
387 		},
388 		{ 0,
389 		  0,
390 		  0,
391 		  0,
392 		  0
393 		},
394 		0,0,
395 		0,NULL_SCB_ADDR,
396 		0,0,             /* extraSampleAccum:TMreserved */
397 		0,0,             /* codecFIFOptr:codecFIFOsyncd */
398 		0x0001,0x8000,   /* fracSampAccumQm1:TMfrmsLeftInGroup */
399 		0x0001,0x0000,   /* fracSampCorrectionQm1:TMfrmGroupLength */
400 		0x00060000       /* nSampPerFrmQ15 */
401 	};
402 
403 	scb = cs46xx_dsp_create_generic_scb(chip,"TimingMasterSCBInst",(u32 *)&timing_master_scb,
404 					    TIMINGMASTER_SCB_ADDR,
405 					    "TIMINGMASTER",NULL,SCB_NO_PARENT);
406 
407 	return scb;
408 }
409 
410 
411 struct dsp_scb_descriptor *
412 cs46xx_dsp_create_codec_out_scb(struct snd_cs46xx * chip, char * codec_name,
413                                 u16 channel_disp, u16 fifo_addr, u16 child_scb_addr,
414                                 u32 dest, struct dsp_scb_descriptor * parent_scb,
415                                 int scb_child_type)
416 {
417 	struct dsp_scb_descriptor * scb;
418 
419 	struct dsp_codec_output_scb codec_out_scb = {
420 		{ 0,
421 		  0,
422 		  0,
423 		  0
424 		},
425 		{
426 			0,
427 			0,
428 			0,
429 			0,
430 			0
431 		},
432 		0,0,
433 		0,NULL_SCB_ADDR,
434 		0,                      /* COstrmRsConfig */
435 		0,                      /* COstrmBufPtr */
436 		channel_disp,fifo_addr, /* leftChanBaseIOaddr:rightChanIOdisp */
437 		0x0000,0x0080,          /* (!AC97!) COexpVolChangeRate:COscaleShiftCount */
438 		0,child_scb_addr        /* COreserved - need child scb to work with rom code */
439 	};
440 
441 
442 	scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_out_scb,
443 					    dest,"S16_CODECOUTPUTTASK",parent_scb,
444 					    scb_child_type);
445 
446 	return scb;
447 }
448 
449 struct dsp_scb_descriptor *
450 cs46xx_dsp_create_codec_in_scb(struct snd_cs46xx * chip, char * codec_name,
451 			       u16 channel_disp, u16 fifo_addr, u16 sample_buffer_addr,
452 			       u32 dest, struct dsp_scb_descriptor * parent_scb,
453 			       int scb_child_type)
454 {
455 
456 	struct dsp_scb_descriptor * scb;
457 	struct dsp_codec_input_scb codec_input_scb = {
458 		{ 0,
459 		  0,
460 		  0,
461 		  0
462 		},
463 		{
464 			0,
465 			0,
466 			0,
467 			0,
468 			0
469 		},
470 
471 #if 0  /* cs4620 */
472 		SyncIOSCB,NULL_SCB_ADDR
473 #else
474 		0 , 0,
475 #endif
476 		0,0,
477 
478 		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,  /* strmRsConfig */
479 		sample_buffer_addr << 0x10,       /* strmBufPtr; defined as a dword ptr, used as a byte ptr */
480 		channel_disp,fifo_addr,           /* (!AC97!) leftChanBaseINaddr=AC97primary
481 						     link input slot 3 :rightChanINdisp=""slot 4 */
482 		0x0000,0x0000,                    /* (!AC97!) ????:scaleShiftCount; no shift needed
483 						     because AC97 is already 20 bits */
484 		0x80008000                        /* ??clw cwcgame.scb has 0 */
485 	};
486 
487 	scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_input_scb,
488 					    dest,"S16_CODECINPUTTASK",parent_scb,
489 					    scb_child_type);
490 	return scb;
491 }
492 
493 
494 static struct dsp_scb_descriptor *
495 cs46xx_dsp_create_pcm_reader_scb(struct snd_cs46xx * chip, char * scb_name,
496                                  u16 sample_buffer_addr, u32 dest,
497                                  int virtual_channel, u32 playback_hw_addr,
498                                  struct dsp_scb_descriptor * parent_scb,
499                                  int scb_child_type)
500 {
501 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
502 	struct dsp_scb_descriptor * scb;
503 
504 	struct dsp_generic_scb pcm_reader_scb = {
505 
506 		/*
507 		  Play DMA Task xfers data from host buffer to SP buffer
508 		  init/runtime variables:
509 		  PlayAC: Play Audio Data Conversion - SCB loc: 2nd dword, mask: 0x0000F000L
510 		  DATA_FMT_16BIT_ST_LTLEND(0x00000000L)   from 16-bit stereo, little-endian
511 		  DATA_FMT_8_BIT_ST_SIGNED(0x00001000L)   from 8-bit stereo, signed
512 		  DATA_FMT_16BIT_MN_LTLEND(0x00002000L)   from 16-bit mono, little-endian
513 		  DATA_FMT_8_BIT_MN_SIGNED(0x00003000L)   from 8-bit mono, signed
514 		  DATA_FMT_16BIT_ST_BIGEND(0x00004000L)   from 16-bit stereo, big-endian
515 		  DATA_FMT_16BIT_MN_BIGEND(0x00006000L)   from 16-bit mono, big-endian
516 		  DATA_FMT_8_BIT_ST_UNSIGNED(0x00009000L) from 8-bit stereo, unsigned
517 		  DATA_FMT_8_BIT_MN_UNSIGNED(0x0000b000L) from 8-bit mono, unsigned
518 		  ? Other combinations possible from:
519 		  DMA_RQ_C2_AUDIO_CONVERT_MASK    0x0000F000L
520 		  DMA_RQ_C2_AC_NONE               0x00000000L
521 		  DMA_RQ_C2_AC_8_TO_16_BIT        0x00001000L
522 		  DMA_RQ_C2_AC_MONO_TO_STEREO     0x00002000L
523 		  DMA_RQ_C2_AC_ENDIAN_CONVERT     0x00004000L
524 		  DMA_RQ_C2_AC_SIGNED_CONVERT     0x00008000L
525 
526 		  HostBuffAddr: Host Buffer Physical Byte Address - SCB loc:3rd dword, Mask: 0xFFFFFFFFL
527 		  aligned to dword boundary
528 		*/
529 		/* Basic (non scatter/gather) DMA requestor (4 ints) */
530 		{ DMA_RQ_C1_SOURCE_ON_HOST +        /* source buffer is on the host */
531 		  DMA_RQ_C1_SOURCE_MOD1024 +        /* source buffer is 1024 dwords (4096 bytes) */
532 		  DMA_RQ_C1_DEST_MOD32 +            /* dest buffer(PCMreaderBuf) is 32 dwords*/
533 		  DMA_RQ_C1_WRITEBACK_SRC_FLAG +    /* ?? */
534 		  DMA_RQ_C1_WRITEBACK_DEST_FLAG +   /* ?? */
535 		  15,                             /* DwordCount-1: picked 16 for DwordCount because Jim */
536 		  /*        Barnette said that is what we should use since */
537 		  /*        we are not running in optimized mode? */
538 		  DMA_RQ_C2_AC_NONE +
539 		  DMA_RQ_C2_SIGNAL_SOURCE_PINGPONG + /* set play interrupt (bit0) in HISR when source */
540 		  /*   buffer (on host) crosses half-way point */
541 		  virtual_channel,                   /* Play DMA channel arbitrarily set to 0 */
542 		  playback_hw_addr,                  /* HostBuffAddr (source) */
543 		  DMA_RQ_SD_SP_SAMPLE_ADDR +         /* destination buffer is in SP Sample Memory */
544 		  sample_buffer_addr                 /* SP Buffer Address (destination) */
545 		},
546 		/* Scatter/gather DMA requestor extension   (5 ints) */
547 		{
548 			0,
549 			0,
550 			0,
551 			0,
552 			0
553 		},
554 		/* Sublist pointer & next stream control block (SCB) link. */
555 		NULL_SCB_ADDR,NULL_SCB_ADDR,
556 		/* Pointer to this tasks parameter block & stream function pointer */
557 		0,NULL_SCB_ADDR,
558 		/* rsConfig register for stream buffer (rsDMA reg. is loaded from basicReq.daw */
559 		/*   for incoming streams, or basicReq.saw, for outgoing streams) */
560 		RSCONFIG_DMA_ENABLE +                 /* enable DMA */
561 		(19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) + /* MAX_DMA_SIZE picked to be 19 since SPUD  */
562 		/*  uses it for some reason */
563 		((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) + /* stream number = SCBaddr/16 */
564 		RSCONFIG_SAMPLE_16STEREO +
565 		RSCONFIG_MODULO_32,             /* dest buffer(PCMreaderBuf) is 32 dwords (256 bytes) */
566 		/* Stream sample pointer & MAC-unit mode for this stream */
567 		(sample_buffer_addr << 0x10),
568 		/* Fractional increment per output sample in the input sample buffer */
569 		0,
570 		{
571 			/* Standard stereo volume control
572 			   default muted */
573 			0xffff,0xffff,
574 			0xffff,0xffff
575 		}
576 	};
577 
578 	if (ins->null_algorithm == NULL) {
579 		ins->null_algorithm =  cs46xx_dsp_lookup_symbol (chip,"NULLALGORITHM",
580 								 SYMBOL_CODE);
581 
582 		if (ins->null_algorithm == NULL) {
583 			dev_err(chip->card->dev,
584 				"dsp_spos: symbol NULLALGORITHM not found\n");
585 			return NULL;
586 		}
587 	}
588 
589 	scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_reader_scb,
590 				      dest,ins->null_algorithm,parent_scb,
591 				      scb_child_type);
592 
593 	return scb;
594 }
595 
596 #define GOF_PER_SEC 200
597 
598 struct dsp_scb_descriptor *
599 cs46xx_dsp_create_src_task_scb(struct snd_cs46xx * chip, char * scb_name,
600 			       int rate,
601                                u16 src_buffer_addr,
602                                u16 src_delay_buffer_addr, u32 dest,
603                                struct dsp_scb_descriptor * parent_scb,
604                                int scb_child_type,
605 	                       int pass_through)
606 {
607 
608 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
609 	struct dsp_scb_descriptor * scb;
610 	unsigned int tmp1, tmp2;
611 	unsigned int phiIncr;
612 	unsigned int correctionPerGOF, correctionPerSec;
613 
614 	dev_dbg(chip->card->dev, "dsp_spos: setting %s rate to %u\n",
615 		scb_name, rate);
616 
617 	/*
618 	 *  Compute the values used to drive the actual sample rate conversion.
619 	 *  The following formulas are being computed, using inline assembly
620 	 *  since we need to use 64 bit arithmetic to compute the values:
621 	 *
622 	 *  phiIncr = floor((Fs,in * 2^26) / Fs,out)
623 	 *  correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) /
624 	 *                                   GOF_PER_SEC)
625 	 *  ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -M
626 	 *                       GOF_PER_SEC * correctionPerGOF
627 	 *
628 	 *  i.e.
629 	 *
630 	 *  phiIncr:other = dividend:remainder((Fs,in * 2^26) / Fs,out)
631 	 *  correctionPerGOF:correctionPerSec =
632 	 *      dividend:remainder(ulOther / GOF_PER_SEC)
633 	 */
634 	tmp1 = rate << 16;
635 	phiIncr = tmp1 / 48000;
636 	tmp1 -= phiIncr * 48000;
637 	tmp1 <<= 10;
638 	phiIncr <<= 10;
639 	tmp2 = tmp1 / 48000;
640 	phiIncr += tmp2;
641 	tmp1 -= tmp2 * 48000;
642 	correctionPerGOF = tmp1 / GOF_PER_SEC;
643 	tmp1 -= correctionPerGOF * GOF_PER_SEC;
644 	correctionPerSec = tmp1;
645 
646 	{
647 		struct dsp_src_task_scb src_task_scb = {
648 			0x0028,0x00c8,
649 			0x5555,0x0000,
650 			0x0000,0x0000,
651 			src_buffer_addr,1,
652 			correctionPerGOF,correctionPerSec,
653 			RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
654 			0x0000,src_delay_buffer_addr,
655 			0x0,
656 			0x080,(src_delay_buffer_addr + (24 * 4)),
657 			0,0, /* next_scb, sub_list_ptr */
658 			0,0, /* entry, this_spb */
659 			RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
660 			src_buffer_addr << 0x10,
661 			phiIncr,
662 			{
663 				0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left,
664 				0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left
665 			}
666 		};
667 
668 		if (ins->s16_up == NULL) {
669 			ins->s16_up =  cs46xx_dsp_lookup_symbol (chip,"S16_UPSRC",
670 								 SYMBOL_CODE);
671 
672 			if (ins->s16_up == NULL) {
673 				dev_err(chip->card->dev,
674 					"dsp_spos: symbol S16_UPSRC not found\n");
675 				return NULL;
676 			}
677 		}
678 
679 		/* clear buffers */
680 		_dsp_clear_sample_buffer (chip,src_buffer_addr,8);
681 		_dsp_clear_sample_buffer (chip,src_delay_buffer_addr,32);
682 
683 		if (pass_through) {
684 			/* wont work with any other rate than
685 			   the native DSP rate */
686 			snd_BUG_ON(rate != 48000);
687 
688 			scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
689 							    dest,"DMAREADER",parent_scb,
690 							    scb_child_type);
691 		} else {
692 			scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
693 						      dest,ins->s16_up,parent_scb,
694 						      scb_child_type);
695 		}
696 
697 
698 	}
699 
700 	return scb;
701 }
702 
703 #if 0 /* not used */
704 struct dsp_scb_descriptor *
705 cs46xx_dsp_create_filter_scb(struct snd_cs46xx * chip, char * scb_name,
706 			     u16 buffer_addr, u32 dest,
707 			     struct dsp_scb_descriptor * parent_scb,
708 			     int scb_child_type) {
709 	struct dsp_scb_descriptor * scb;
710 
711 	struct dsp_filter_scb filter_scb = {
712 		.a0_right            = 0x41a9,
713 		.a0_left             = 0x41a9,
714 		.a1_right            = 0xb8e4,
715 		.a1_left             = 0xb8e4,
716 		.a2_right            = 0x3e55,
717 		.a2_left             = 0x3e55,
718 
719 		.filter_unused3      = 0x0000,
720 		.filter_unused2      = 0x0000,
721 
722 		.output_buf_ptr      = buffer_addr,
723 		.init                = 0x000,
724 
725 		.prev_sample_output1 = 0x00000000,
726 		.prev_sample_output2 = 0x00000000,
727 
728 		.prev_sample_input1  = 0x00000000,
729 		.prev_sample_input2  = 0x00000000,
730 
731 		.next_scb_ptr        = 0x0000,
732 		.sub_list_ptr        = 0x0000,
733 
734 		.entry_point         = 0x0000,
735 		.spb_ptr             = 0x0000,
736 
737 		.b0_right            = 0x0e38,
738 		.b0_left             = 0x0e38,
739 		.b1_right            = 0x1c71,
740 		.b1_left             = 0x1c71,
741 		.b2_right            = 0x0e38,
742 		.b2_left             = 0x0e38,
743 	};
744 
745 
746 	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&filter_scb,
747 					    dest,"FILTERTASK",parent_scb,
748 					    scb_child_type);
749 
750  	return scb;
751 }
752 #endif /* not used */
753 
754 struct dsp_scb_descriptor *
755 cs46xx_dsp_create_mix_only_scb(struct snd_cs46xx * chip, char * scb_name,
756                                u16 mix_buffer_addr, u32 dest,
757                                struct dsp_scb_descriptor * parent_scb,
758                                int scb_child_type)
759 {
760 	struct dsp_scb_descriptor * scb;
761 
762 	struct dsp_mix_only_scb master_mix_scb = {
763 		/* 0 */ { 0,
764 			  /* 1 */   0,
765 			  /* 2 */  mix_buffer_addr,
766 			  /* 3 */  0
767 			  /*   */ },
768 		{
769 			/* 4 */  0,
770 			/* 5 */  0,
771 			/* 6 */  0,
772 			/* 7 */  0,
773 			/* 8 */  0x00000080
774 		},
775 		/* 9 */ 0,0,
776 		/* A */ 0,0,
777 		/* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
778 		/* C */ (mix_buffer_addr  + (16 * 4)) << 0x10,
779 		/* D */ 0,
780 		{
781 			/* E */ 0x8000,0x8000,
782 			/* F */ 0x8000,0x8000
783 		}
784 	};
785 
786 
787 	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&master_mix_scb,
788 					    dest,"S16_MIX",parent_scb,
789 					    scb_child_type);
790 	return scb;
791 }
792 
793 
794 struct dsp_scb_descriptor *
795 cs46xx_dsp_create_mix_to_ostream_scb(struct snd_cs46xx * chip, char * scb_name,
796                                      u16 mix_buffer_addr, u16 writeback_spb, u32 dest,
797                                      struct dsp_scb_descriptor * parent_scb,
798                                      int scb_child_type)
799 {
800 	struct dsp_scb_descriptor * scb;
801 
802 	struct dsp_mix2_ostream_scb mix2_ostream_scb = {
803 		/* Basic (non scatter/gather) DMA requestor (4 ints) */
804 		{
805 			DMA_RQ_C1_SOURCE_MOD64 +
806 			DMA_RQ_C1_DEST_ON_HOST +
807 			DMA_RQ_C1_DEST_MOD1024 +
808 			DMA_RQ_C1_WRITEBACK_SRC_FLAG +
809 			DMA_RQ_C1_WRITEBACK_DEST_FLAG +
810 			15,
811 
812 			DMA_RQ_C2_AC_NONE +
813 			DMA_RQ_C2_SIGNAL_DEST_PINGPONG +
814 
815 			CS46XX_DSP_CAPTURE_CHANNEL,
816 			DMA_RQ_SD_SP_SAMPLE_ADDR +
817 			mix_buffer_addr,
818 			0x0
819 		},
820 
821 		{ 0, 0, 0, 0, 0, },
822 		0,0,
823 		0,writeback_spb,
824 
825 		RSCONFIG_DMA_ENABLE +
826 		(19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) +
827 
828 		((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) +
829 		RSCONFIG_DMA_TO_HOST +
830 		RSCONFIG_SAMPLE_16STEREO +
831 		RSCONFIG_MODULO_64,
832 		(mix_buffer_addr + (32 * 4)) << 0x10,
833 		1,0,
834 		0x0001,0x0080,
835 		0xFFFF,0
836 	};
837 
838 
839 	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&mix2_ostream_scb,
840 
841 	    dest,"S16_MIX_TO_OSTREAM",parent_scb,
842 					    scb_child_type);
843 
844 	return scb;
845 }
846 
847 
848 struct dsp_scb_descriptor *
849 cs46xx_dsp_create_vari_decimate_scb(struct snd_cs46xx * chip,char * scb_name,
850                                     u16 vari_buffer_addr0,
851                                     u16 vari_buffer_addr1,
852                                     u32 dest,
853                                     struct dsp_scb_descriptor * parent_scb,
854                                     int scb_child_type)
855 {
856 
857 	struct dsp_scb_descriptor * scb;
858 
859 	struct dsp_vari_decimate_scb vari_decimate_scb = {
860 		0x0028,0x00c8,
861 		0x5555,0x0000,
862 		0x0000,0x0000,
863 		vari_buffer_addr0,vari_buffer_addr1,
864 
865 		0x0028,0x00c8,
866 		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256,
867 
868 		0xFF800000,
869 		0,
870 		0x0080,vari_buffer_addr1 + (25 * 4),
871 
872 		0,0,
873 		0,0,
874 
875 		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
876 		vari_buffer_addr0 << 0x10,
877 		0x04000000,
878 		{
879 			0x8000,0x8000,
880 			0xFFFF,0xFFFF
881 		}
882 	};
883 
884 	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&vari_decimate_scb,
885 					    dest,"VARIDECIMATE",parent_scb,
886 					    scb_child_type);
887 
888 	return scb;
889 }
890 
891 
892 static struct dsp_scb_descriptor *
893 cs46xx_dsp_create_pcm_serial_input_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
894                                        struct dsp_scb_descriptor * input_scb,
895                                        struct dsp_scb_descriptor * parent_scb,
896                                        int scb_child_type)
897 {
898 
899 	struct dsp_scb_descriptor * scb;
900 
901 
902 	struct dsp_pcm_serial_input_scb pcm_serial_input_scb = {
903 		{ 0,
904 		  0,
905 		  0,
906 		  0
907 		},
908 		{
909 			0,
910 			0,
911 			0,
912 			0,
913 			0
914 		},
915 
916 		0,0,
917 		0,0,
918 
919 		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_16,
920 		0,
921       /* 0xD */ 0,input_scb->address,
922 		{
923       /* 0xE */   0x8000,0x8000,
924       /* 0xF */	  0x8000,0x8000
925 		}
926 	};
927 
928 	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_serial_input_scb,
929 					    dest,"PCMSERIALINPUTTASK",parent_scb,
930 					    scb_child_type);
931 	return scb;
932 }
933 
934 
935 static struct dsp_scb_descriptor *
936 cs46xx_dsp_create_asynch_fg_tx_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
937                                    u16 hfg_scb_address,
938                                    u16 asynch_buffer_address,
939                                    struct dsp_scb_descriptor * parent_scb,
940                                    int scb_child_type)
941 {
942 
943 	struct dsp_scb_descriptor * scb;
944 
945 	struct dsp_asynch_fg_tx_scb asynch_fg_tx_scb = {
946 		0xfc00,0x03ff,      /*  Prototype sample buffer size of 256 dwords */
947 		0x0058,0x0028,      /* Min Delta 7 dwords == 28 bytes */
948 		/* : Max delta 25 dwords == 100 bytes */
949 		0,hfg_scb_address,  /* Point to HFG task SCB */
950 		0,0,		    /* Initialize current Delta and Consumer ptr adjustment count */
951 		0,                  /* Initialize accumulated Phi to 0 */
952 		0,0x2aab,           /* Const 1/3 */
953 
954 		{
955 			0,         /* Define the unused elements */
956 			0,
957 			0
958 		},
959 
960 		0,0,
961 		0,dest + AFGTxAccumPhi,
962 
963 		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256, /* Stereo, 256 dword */
964 		(asynch_buffer_address) << 0x10,  /* This should be automagically synchronized
965                                                      to the producer pointer */
966 
967 		/* There is no correct initial value, it will depend upon the detected
968 		   rate etc  */
969 		0x18000000,                     /* Phi increment for approx 32k operation */
970 		0x8000,0x8000,                  /* Volume controls are unused at this time */
971 		0x8000,0x8000
972 	};
973 
974 	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_tx_scb,
975 					    dest,"ASYNCHFGTXCODE",parent_scb,
976 					    scb_child_type);
977 
978 	return scb;
979 }
980 
981 
982 struct dsp_scb_descriptor *
983 cs46xx_dsp_create_asynch_fg_rx_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
984                                    u16 hfg_scb_address,
985                                    u16 asynch_buffer_address,
986                                    struct dsp_scb_descriptor * parent_scb,
987                                    int scb_child_type)
988 {
989 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
990 	struct dsp_scb_descriptor * scb;
991 
992 	struct dsp_asynch_fg_rx_scb asynch_fg_rx_scb = {
993 		0xfe00,0x01ff,      /*  Prototype sample buffer size of 128 dwords */
994 		0x0064,0x001c,      /* Min Delta 7 dwords == 28 bytes */
995 		                    /* : Max delta 25 dwords == 100 bytes */
996 		0,hfg_scb_address,  /* Point to HFG task SCB */
997 		0,0,				/* Initialize current Delta and Consumer ptr adjustment count */
998 		{
999 			0,                /* Define the unused elements */
1000 			0,
1001 			0,
1002 			0,
1003 			0
1004 		},
1005 
1006 		0,0,
1007 		0,dest,
1008 
1009 		RSCONFIG_MODULO_128 |
1010         RSCONFIG_SAMPLE_16STEREO,                         /* Stereo, 128 dword */
1011 		( (asynch_buffer_address + (16 * 4))  << 0x10),   /* This should be automagically
1012 							                                  synchrinized to the producer pointer */
1013 
1014 		/* There is no correct initial value, it will depend upon the detected
1015 		   rate etc  */
1016 		0x18000000,
1017 
1018 		/* Set IEC958 input volume */
1019 		0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
1020 		0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
1021 	};
1022 
1023 	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_rx_scb,
1024 					    dest,"ASYNCHFGRXCODE",parent_scb,
1025 					    scb_child_type);
1026 
1027 	return scb;
1028 }
1029 
1030 
1031 #if 0 /* not used */
1032 struct dsp_scb_descriptor *
1033 cs46xx_dsp_create_output_snoop_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1034                                    u16 snoop_buffer_address,
1035                                    struct dsp_scb_descriptor * snoop_scb,
1036                                    struct dsp_scb_descriptor * parent_scb,
1037                                    int scb_child_type)
1038 {
1039 
1040 	struct dsp_scb_descriptor * scb;
1041 
1042 	struct dsp_output_snoop_scb output_snoop_scb = {
1043 		{ 0,	/*  not used.  Zero */
1044 		  0,
1045 		  0,
1046 		  0,
1047 		},
1048 		{
1049 			0, /* not used.  Zero */
1050 			0,
1051 			0,
1052 			0,
1053 			0
1054 		},
1055 
1056 		0,0,
1057 		0,0,
1058 
1059 		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
1060 		snoop_buffer_address << 0x10,
1061 		0,0,
1062 		0,
1063 		0,snoop_scb->address
1064 	};
1065 
1066 	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&output_snoop_scb,
1067 					    dest,"OUTPUTSNOOP",parent_scb,
1068 					    scb_child_type);
1069 	return scb;
1070 }
1071 #endif /* not used */
1072 
1073 
1074 struct dsp_scb_descriptor *
1075 cs46xx_dsp_create_spio_write_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1076                                  struct dsp_scb_descriptor * parent_scb,
1077                                  int scb_child_type)
1078 {
1079 	struct dsp_scb_descriptor * scb;
1080 
1081 	struct dsp_spio_write_scb spio_write_scb = {
1082 		0,0,         /*   SPIOWAddress2:SPIOWAddress1; */
1083 		0,           /*   SPIOWData1; */
1084 		0,           /*   SPIOWData2; */
1085 		0,0,         /*   SPIOWAddress4:SPIOWAddress3; */
1086 		0,           /*   SPIOWData3; */
1087 		0,           /*   SPIOWData4; */
1088 		0,0,         /*   SPIOWDataPtr:Unused1; */
1089 		{ 0,0 },     /*   Unused2[2]; */
1090 
1091 		0,0,	     /*   SPIOWChildPtr:SPIOWSiblingPtr; */
1092 		0,0,         /*   SPIOWThisPtr:SPIOWEntryPoint; */
1093 
1094 		{
1095 			0,
1096 			0,
1097 			0,
1098 			0,
1099 			0          /*   Unused3[5];  */
1100 		}
1101 	};
1102 
1103 	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&spio_write_scb,
1104 					    dest,"SPIOWRITE",parent_scb,
1105 					    scb_child_type);
1106 
1107 	return scb;
1108 }
1109 
1110 struct dsp_scb_descriptor *
1111 cs46xx_dsp_create_magic_snoop_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1112 				  u16 snoop_buffer_address,
1113 				  struct dsp_scb_descriptor * snoop_scb,
1114 				  struct dsp_scb_descriptor * parent_scb,
1115 				  int scb_child_type)
1116 {
1117 	struct dsp_scb_descriptor * scb;
1118 
1119 	struct dsp_magic_snoop_task magic_snoop_scb = {
1120 		/* 0 */ 0, /* i0 */
1121 		/* 1 */ 0, /* i1 */
1122 		/* 2 */ snoop_buffer_address << 0x10,
1123 		/* 3 */ 0,snoop_scb->address,
1124 		/* 4 */ 0, /* i3 */
1125 		/* 5 */ 0, /* i4 */
1126 		/* 6 */ 0, /* i5 */
1127 		/* 7 */ 0, /* i6 */
1128 		/* 8 */ 0, /* i7 */
1129 		/* 9 */ 0,0, /* next_scb, sub_list_ptr */
1130 		/* A */ 0,0, /* entry_point, this_ptr */
1131 		/* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
1132 		/* C */ snoop_buffer_address  << 0x10,
1133 		/* D */ 0,
1134 		/* E */ { 0x8000,0x8000,
1135 	        /* F */   0xffff,0xffff
1136 		}
1137 	};
1138 
1139 	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&magic_snoop_scb,
1140 					    dest,"MAGICSNOOPTASK",parent_scb,
1141 					    scb_child_type);
1142 
1143 	return scb;
1144 }
1145 
1146 static struct dsp_scb_descriptor *
1147 find_next_free_scb (struct snd_cs46xx * chip, struct dsp_scb_descriptor * from)
1148 {
1149 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1150 	struct dsp_scb_descriptor * scb = from;
1151 
1152 	while (scb->next_scb_ptr != ins->the_null_scb) {
1153 		if (snd_BUG_ON(!scb->next_scb_ptr))
1154 			return NULL;
1155 
1156 		scb = scb->next_scb_ptr;
1157 	}
1158 
1159 	return scb;
1160 }
1161 
1162 static u32 pcm_reader_buffer_addr[DSP_MAX_PCM_CHANNELS] = {
1163 	0x0600, /* 1 */
1164 	0x1500, /* 2 */
1165 	0x1580, /* 3 */
1166 	0x1600, /* 4 */
1167 	0x1680, /* 5 */
1168 	0x1700, /* 6 */
1169 	0x1780, /* 7 */
1170 	0x1800, /* 8 */
1171 	0x1880, /* 9 */
1172 	0x1900, /* 10 */
1173 	0x1980, /* 11 */
1174 	0x1A00, /* 12 */
1175 	0x1A80, /* 13 */
1176 	0x1B00, /* 14 */
1177 	0x1B80, /* 15 */
1178 	0x1C00, /* 16 */
1179 	0x1C80, /* 17 */
1180 	0x1D00, /* 18 */
1181 	0x1D80, /* 19 */
1182 	0x1E00, /* 20 */
1183 	0x1E80, /* 21 */
1184 	0x1F00, /* 22 */
1185 	0x1F80, /* 23 */
1186 	0x2000, /* 24 */
1187 	0x2080, /* 25 */
1188 	0x2100, /* 26 */
1189 	0x2180, /* 27 */
1190 	0x2200, /* 28 */
1191 	0x2280, /* 29 */
1192 	0x2300, /* 30 */
1193 	0x2380, /* 31 */
1194 	0x2400, /* 32 */
1195 };
1196 
1197 static u32 src_output_buffer_addr[DSP_MAX_SRC_NR] = {
1198 	0x2B80,
1199 	0x2BA0,
1200 	0x2BC0,
1201 	0x2BE0,
1202 	0x2D00,
1203 	0x2D20,
1204 	0x2D40,
1205 	0x2D60,
1206 	0x2D80,
1207 	0x2DA0,
1208 	0x2DC0,
1209 	0x2DE0,
1210 	0x2E00,
1211 	0x2E20
1212 };
1213 
1214 static u32 src_delay_buffer_addr[DSP_MAX_SRC_NR] = {
1215 	0x2480,
1216 	0x2500,
1217 	0x2580,
1218 	0x2600,
1219 	0x2680,
1220 	0x2700,
1221 	0x2780,
1222 	0x2800,
1223 	0x2880,
1224 	0x2900,
1225 	0x2980,
1226 	0x2A00,
1227 	0x2A80,
1228 	0x2B00
1229 };
1230 
1231 struct dsp_pcm_channel_descriptor *
1232 cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
1233 			       u32 sample_rate, void * private_data,
1234 			       u32 hw_dma_addr,
1235 			       int pcm_channel_id)
1236 {
1237 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1238 	struct dsp_scb_descriptor * src_scb = NULL, * pcm_scb, * mixer_scb = NULL;
1239 	struct dsp_scb_descriptor * src_parent_scb = NULL;
1240 
1241 	/* struct dsp_scb_descriptor * pcm_parent_scb; */
1242 	char scb_name[DSP_MAX_SCB_NAME];
1243 	int i, pcm_index = -1, insert_point, src_index = -1, pass_through = 0;
1244 	unsigned long flags;
1245 
1246 	switch (pcm_channel_id) {
1247 	case DSP_PCM_MAIN_CHANNEL:
1248 		mixer_scb = ins->master_mix_scb;
1249 		break;
1250 	case DSP_PCM_REAR_CHANNEL:
1251 		mixer_scb = ins->rear_mix_scb;
1252 		break;
1253 	case DSP_PCM_CENTER_LFE_CHANNEL:
1254 		mixer_scb = ins->center_lfe_mix_scb;
1255 		break;
1256 	case DSP_PCM_S71_CHANNEL:
1257 		/* TODO */
1258 		snd_BUG();
1259 		break;
1260 	case DSP_IEC958_CHANNEL:
1261 		if (snd_BUG_ON(!ins->asynch_tx_scb))
1262 			return NULL;
1263 		mixer_scb = ins->asynch_tx_scb;
1264 
1265 		/* if sample rate is set to 48khz we pass
1266 		   the Sample Rate Converted (which could
1267 		   alter the raw data stream ...) */
1268 		if (sample_rate == 48000) {
1269 			dev_dbg(chip->card->dev, "IEC958 pass through\n");
1270 			/* Hack to bypass creating a new SRC */
1271 			pass_through = 1;
1272 		}
1273 		break;
1274 	default:
1275 		snd_BUG();
1276 		return NULL;
1277 	}
1278 	/* default sample rate is 44100 */
1279 	if (!sample_rate) sample_rate = 44100;
1280 
1281 	/* search for a already created SRC SCB with the same sample rate */
1282 	for (i = 0; i < DSP_MAX_PCM_CHANNELS &&
1283 		     (pcm_index == -1 || src_scb == NULL); ++i) {
1284 
1285 		/* virtual channel reserved
1286 		   for capture */
1287 		if (i == CS46XX_DSP_CAPTURE_CHANNEL) continue;
1288 
1289 		if (ins->pcm_channels[i].active) {
1290 			if (!src_scb &&
1291 			    ins->pcm_channels[i].sample_rate == sample_rate &&
1292 			    ins->pcm_channels[i].mixer_scb == mixer_scb) {
1293 				src_scb = ins->pcm_channels[i].src_scb;
1294 				ins->pcm_channels[i].src_scb->ref_count ++;
1295 				src_index = ins->pcm_channels[i].src_slot;
1296 			}
1297 		} else if (pcm_index == -1) {
1298 			pcm_index = i;
1299 		}
1300 	}
1301 
1302 	if (pcm_index == -1) {
1303 		dev_err(chip->card->dev, "dsp_spos: no free PCM channel\n");
1304 		return NULL;
1305 	}
1306 
1307 	if (src_scb == NULL) {
1308 		if (ins->nsrc_scb >= DSP_MAX_SRC_NR) {
1309 			dev_err(chip->card->dev,
1310 				"dsp_spos: to many SRC instances\n!");
1311 			return NULL;
1312 		}
1313 
1314 		/* find a free slot */
1315 		for (i = 0; i < DSP_MAX_SRC_NR; ++i) {
1316 			if (ins->src_scb_slots[i] == 0) {
1317 				src_index = i;
1318 				ins->src_scb_slots[i] = 1;
1319 				break;
1320 			}
1321 		}
1322 		if (snd_BUG_ON(src_index == -1))
1323 			return NULL;
1324 
1325 		/* we need to create a new SRC SCB */
1326 		if (mixer_scb->sub_list_ptr == ins->the_null_scb) {
1327 			src_parent_scb = mixer_scb;
1328 			insert_point = SCB_ON_PARENT_SUBLIST_SCB;
1329 		} else {
1330 			src_parent_scb = find_next_free_scb(chip,mixer_scb->sub_list_ptr);
1331 			insert_point = SCB_ON_PARENT_NEXT_SCB;
1332 		}
1333 
1334 		snprintf (scb_name,DSP_MAX_SCB_NAME,"SrcTask_SCB%d",src_index);
1335 
1336 		dev_dbg(chip->card->dev,
1337 			"dsp_spos: creating SRC \"%s\"\n", scb_name);
1338 		src_scb = cs46xx_dsp_create_src_task_scb(chip,scb_name,
1339 							 sample_rate,
1340 							 src_output_buffer_addr[src_index],
1341 							 src_delay_buffer_addr[src_index],
1342 							 /* 0x400 - 0x600 source SCBs */
1343 							 0x400 + (src_index * 0x10) ,
1344 							 src_parent_scb,
1345 							 insert_point,
1346 							 pass_through);
1347 
1348 		if (!src_scb) {
1349 			dev_err(chip->card->dev,
1350 				"dsp_spos: failed to create SRCtaskSCB\n");
1351 			return NULL;
1352 		}
1353 
1354 		/* cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate); */
1355 
1356 		ins->nsrc_scb ++;
1357 	}
1358 
1359 
1360 	snprintf (scb_name,DSP_MAX_SCB_NAME,"PCMReader_SCB%d",pcm_index);
1361 
1362 	dev_dbg(chip->card->dev, "dsp_spos: creating PCM \"%s\" (%d)\n",
1363 		scb_name, pcm_channel_id);
1364 
1365 	pcm_scb = cs46xx_dsp_create_pcm_reader_scb(chip,scb_name,
1366 						   pcm_reader_buffer_addr[pcm_index],
1367 						   /* 0x200 - 400 PCMreader SCBs */
1368 						   (pcm_index * 0x10) + 0x200,
1369 						   pcm_index,    /* virtual channel 0-31 */
1370 						   hw_dma_addr,  /* pcm hw addr */
1371                            NULL,         /* parent SCB ptr */
1372                            0             /* insert point */
1373                            );
1374 
1375 	if (!pcm_scb) {
1376 		dev_err(chip->card->dev,
1377 			"dsp_spos: failed to create PCMreaderSCB\n");
1378 		return NULL;
1379 	}
1380 
1381 	spin_lock_irqsave(&chip->reg_lock, flags);
1382 	ins->pcm_channels[pcm_index].sample_rate = sample_rate;
1383 	ins->pcm_channels[pcm_index].pcm_reader_scb = pcm_scb;
1384 	ins->pcm_channels[pcm_index].src_scb = src_scb;
1385 	ins->pcm_channels[pcm_index].unlinked = 1;
1386 	ins->pcm_channels[pcm_index].private_data = private_data;
1387 	ins->pcm_channels[pcm_index].src_slot = src_index;
1388 	ins->pcm_channels[pcm_index].active = 1;
1389 	ins->pcm_channels[pcm_index].pcm_slot = pcm_index;
1390 	ins->pcm_channels[pcm_index].mixer_scb = mixer_scb;
1391 	ins->npcm_channels ++;
1392 	spin_unlock_irqrestore(&chip->reg_lock, flags);
1393 
1394 	return (ins->pcm_channels + pcm_index);
1395 }
1396 
1397 int cs46xx_dsp_pcm_channel_set_period (struct snd_cs46xx * chip,
1398 				       struct dsp_pcm_channel_descriptor * pcm_channel,
1399 				       int period_size)
1400 {
1401 	u32 temp = snd_cs46xx_peek (chip,pcm_channel->pcm_reader_scb->address << 2);
1402 	temp &= ~DMA_RQ_C1_SOURCE_SIZE_MASK;
1403 
1404 	switch (period_size) {
1405 	case 2048:
1406 		temp |= DMA_RQ_C1_SOURCE_MOD1024;
1407 		break;
1408 	case 1024:
1409 		temp |= DMA_RQ_C1_SOURCE_MOD512;
1410 		break;
1411 	case 512:
1412 		temp |= DMA_RQ_C1_SOURCE_MOD256;
1413 		break;
1414 	case 256:
1415 		temp |= DMA_RQ_C1_SOURCE_MOD128;
1416 		break;
1417 	case 128:
1418 		temp |= DMA_RQ_C1_SOURCE_MOD64;
1419 		break;
1420 	case 64:
1421 		temp |= DMA_RQ_C1_SOURCE_MOD32;
1422 		break;
1423 	case 32:
1424 		temp |= DMA_RQ_C1_SOURCE_MOD16;
1425 		break;
1426 	default:
1427 		dev_dbg(chip->card->dev,
1428 			"period size (%d) not supported by HW\n", period_size);
1429 		return -EINVAL;
1430 	}
1431 
1432 	snd_cs46xx_poke (chip,pcm_channel->pcm_reader_scb->address << 2,temp);
1433 
1434 	return 0;
1435 }
1436 
1437 int cs46xx_dsp_pcm_ostream_set_period (struct snd_cs46xx * chip,
1438 				       int period_size)
1439 {
1440 	u32 temp = snd_cs46xx_peek (chip,WRITEBACK_SCB_ADDR << 2);
1441 	temp &= ~DMA_RQ_C1_DEST_SIZE_MASK;
1442 
1443 	switch (period_size) {
1444 	case 2048:
1445 		temp |= DMA_RQ_C1_DEST_MOD1024;
1446 		break;
1447 	case 1024:
1448 		temp |= DMA_RQ_C1_DEST_MOD512;
1449 		break;
1450 	case 512:
1451 		temp |= DMA_RQ_C1_DEST_MOD256;
1452 		break;
1453 	case 256:
1454 		temp |= DMA_RQ_C1_DEST_MOD128;
1455 		break;
1456 	case 128:
1457 		temp |= DMA_RQ_C1_DEST_MOD64;
1458 		break;
1459 	case 64:
1460 		temp |= DMA_RQ_C1_DEST_MOD32;
1461 		break;
1462 	case 32:
1463 		temp |= DMA_RQ_C1_DEST_MOD16;
1464 		break;
1465 	default:
1466 		dev_dbg(chip->card->dev,
1467 			"period size (%d) not supported by HW\n", period_size);
1468 		return -EINVAL;
1469 	}
1470 
1471 	snd_cs46xx_poke (chip,WRITEBACK_SCB_ADDR << 2,temp);
1472 
1473 	return 0;
1474 }
1475 
1476 void cs46xx_dsp_destroy_pcm_channel (struct snd_cs46xx * chip,
1477 				     struct dsp_pcm_channel_descriptor * pcm_channel)
1478 {
1479 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1480 	unsigned long flags;
1481 
1482 	if (snd_BUG_ON(!pcm_channel->active ||
1483 		       ins->npcm_channels <= 0 ||
1484 		       pcm_channel->src_scb->ref_count <= 0))
1485 		return;
1486 
1487 	spin_lock_irqsave(&chip->reg_lock, flags);
1488 	pcm_channel->unlinked = 1;
1489 	pcm_channel->active = 0;
1490 	pcm_channel->private_data = NULL;
1491 	pcm_channel->src_scb->ref_count --;
1492 	ins->npcm_channels --;
1493 	spin_unlock_irqrestore(&chip->reg_lock, flags);
1494 
1495 	cs46xx_dsp_remove_scb(chip,pcm_channel->pcm_reader_scb);
1496 
1497 	if (!pcm_channel->src_scb->ref_count) {
1498 		cs46xx_dsp_remove_scb(chip,pcm_channel->src_scb);
1499 
1500 		if (snd_BUG_ON(pcm_channel->src_slot < 0 ||
1501 			       pcm_channel->src_slot >= DSP_MAX_SRC_NR))
1502 			return;
1503 
1504 		ins->src_scb_slots[pcm_channel->src_slot] = 0;
1505 		ins->nsrc_scb --;
1506 	}
1507 }
1508 
1509 int cs46xx_dsp_pcm_unlink (struct snd_cs46xx * chip,
1510 			   struct dsp_pcm_channel_descriptor * pcm_channel)
1511 {
1512 	unsigned long flags;
1513 
1514 	if (snd_BUG_ON(!pcm_channel->active ||
1515 		       chip->dsp_spos_instance->npcm_channels <= 0))
1516 		return -EIO;
1517 
1518 	spin_lock_irqsave(&chip->reg_lock, flags);
1519 	if (pcm_channel->unlinked) {
1520 		spin_unlock_irqrestore(&chip->reg_lock, flags);
1521 		return -EIO;
1522 	}
1523 
1524 	pcm_channel->unlinked = 1;
1525 
1526 	_dsp_unlink_scb (chip,pcm_channel->pcm_reader_scb);
1527 	spin_unlock_irqrestore(&chip->reg_lock, flags);
1528 
1529 	return 0;
1530 }
1531 
1532 int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip,
1533 			 struct dsp_pcm_channel_descriptor * pcm_channel)
1534 {
1535 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1536 	struct dsp_scb_descriptor * parent_scb;
1537 	struct dsp_scb_descriptor * src_scb = pcm_channel->src_scb;
1538 	unsigned long flags;
1539 
1540 	spin_lock_irqsave(&chip->reg_lock, flags);
1541 
1542 	if (pcm_channel->unlinked == 0) {
1543 		spin_unlock_irqrestore(&chip->reg_lock, flags);
1544 		return -EIO;
1545 	}
1546 
1547 	parent_scb = src_scb;
1548 
1549 	if (src_scb->sub_list_ptr != ins->the_null_scb) {
1550 		src_scb->sub_list_ptr->parent_scb_ptr = pcm_channel->pcm_reader_scb;
1551 		pcm_channel->pcm_reader_scb->next_scb_ptr = src_scb->sub_list_ptr;
1552 	}
1553 
1554 	src_scb->sub_list_ptr = pcm_channel->pcm_reader_scb;
1555 
1556 	snd_BUG_ON(pcm_channel->pcm_reader_scb->parent_scb_ptr);
1557 	pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb;
1558 
1559 	/* update SCB entry in DSP RAM */
1560 	cs46xx_dsp_spos_update_scb(chip,pcm_channel->pcm_reader_scb);
1561 
1562 	/* update parent SCB entry */
1563 	cs46xx_dsp_spos_update_scb(chip,parent_scb);
1564 
1565 	pcm_channel->unlinked = 0;
1566 	spin_unlock_irqrestore(&chip->reg_lock, flags);
1567 	return 0;
1568 }
1569 
1570 struct dsp_scb_descriptor *
1571 cs46xx_add_record_source (struct snd_cs46xx *chip, struct dsp_scb_descriptor * source,
1572 			  u16 addr, char * scb_name)
1573 {
1574   	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1575 	struct dsp_scb_descriptor * parent;
1576 	struct dsp_scb_descriptor * pcm_input;
1577 	int insert_point;
1578 
1579 	if (snd_BUG_ON(!ins->record_mixer_scb))
1580 		return NULL;
1581 
1582 	if (ins->record_mixer_scb->sub_list_ptr != ins->the_null_scb) {
1583 		parent = find_next_free_scb (chip,ins->record_mixer_scb->sub_list_ptr);
1584 		insert_point = SCB_ON_PARENT_NEXT_SCB;
1585 	} else {
1586 		parent = ins->record_mixer_scb;
1587 		insert_point = SCB_ON_PARENT_SUBLIST_SCB;
1588 	}
1589 
1590 	pcm_input = cs46xx_dsp_create_pcm_serial_input_scb(chip,scb_name,addr,
1591 							   source, parent,
1592 							   insert_point);
1593 
1594 	return pcm_input;
1595 }
1596 
1597 int cs46xx_src_unlink(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
1598 {
1599 	unsigned long flags;
1600 
1601 	if (snd_BUG_ON(!src->parent_scb_ptr))
1602 		return -EINVAL;
1603 
1604 	/* mute SCB */
1605 	cs46xx_dsp_scb_set_volume (chip,src,0,0);
1606 
1607 	spin_lock_irqsave(&chip->reg_lock, flags);
1608 	_dsp_unlink_scb (chip,src);
1609 	spin_unlock_irqrestore(&chip->reg_lock, flags);
1610 
1611 	return 0;
1612 }
1613 
1614 int cs46xx_src_link(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
1615 {
1616 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1617 	struct dsp_scb_descriptor * parent_scb;
1618 
1619 	if (snd_BUG_ON(src->parent_scb_ptr))
1620 		return -EINVAL;
1621 	if (snd_BUG_ON(!ins->master_mix_scb))
1622 		return -EINVAL;
1623 
1624 	if (ins->master_mix_scb->sub_list_ptr != ins->the_null_scb) {
1625 		parent_scb = find_next_free_scb (chip,ins->master_mix_scb->sub_list_ptr);
1626 		parent_scb->next_scb_ptr = src;
1627 	} else {
1628 		parent_scb = ins->master_mix_scb;
1629 		parent_scb->sub_list_ptr = src;
1630 	}
1631 
1632 	src->parent_scb_ptr = parent_scb;
1633 
1634 	/* update entry in DSP RAM */
1635 	cs46xx_dsp_spos_update_scb(chip,parent_scb);
1636 
1637 	return 0;
1638 }
1639 
1640 int cs46xx_dsp_enable_spdif_out (struct snd_cs46xx *chip)
1641 {
1642 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1643 
1644 	if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
1645 		cs46xx_dsp_enable_spdif_hw (chip);
1646 	}
1647 
1648 	/* dont touch anything if SPDIF is open */
1649 	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
1650 		/* when cs46xx_iec958_post_close(...) is called it
1651 		   will call this function if necessary depending on
1652 		   this bit */
1653 		ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1654 
1655 		return -EBUSY;
1656 	}
1657 
1658 	if (snd_BUG_ON(ins->asynch_tx_scb))
1659 		return -EINVAL;
1660 	if (snd_BUG_ON(ins->master_mix_scb->next_scb_ptr !=
1661 		       ins->the_null_scb))
1662 		return -EINVAL;
1663 
1664 	/* reset output snooper sample buffer pointer */
1665 	snd_cs46xx_poke (chip, (ins->ref_snoop_scb->address + 2) << 2,
1666 			 (OUTPUT_SNOOP_BUFFER + 0x10) << 0x10 );
1667 
1668 	/* The asynch. transfer task */
1669 	ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
1670 								SPDIFO_SCB_INST,
1671 								SPDIFO_IP_OUTPUT_BUFFER1,
1672 								ins->master_mix_scb,
1673 								SCB_ON_PARENT_NEXT_SCB);
1674 	if (!ins->asynch_tx_scb) return -ENOMEM;
1675 
1676 	ins->spdif_pcm_input_scb = cs46xx_dsp_create_pcm_serial_input_scb(chip,"PCMSerialInput_II",
1677 									  PCMSERIALINII_SCB_ADDR,
1678 									  ins->ref_snoop_scb,
1679 									  ins->asynch_tx_scb,
1680 									  SCB_ON_PARENT_SUBLIST_SCB);
1681 
1682 
1683 	if (!ins->spdif_pcm_input_scb) return -ENOMEM;
1684 
1685 	/* monitor state */
1686 	ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1687 
1688 	return 0;
1689 }
1690 
1691 int  cs46xx_dsp_disable_spdif_out (struct snd_cs46xx *chip)
1692 {
1693 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1694 
1695 	/* dont touch anything if SPDIF is open */
1696 	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
1697 		ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1698 		return -EBUSY;
1699 	}
1700 
1701 	/* check integrety */
1702 	if (snd_BUG_ON(!ins->asynch_tx_scb))
1703 		return -EINVAL;
1704 	if (snd_BUG_ON(!ins->spdif_pcm_input_scb))
1705 		return -EINVAL;
1706 	if (snd_BUG_ON(ins->master_mix_scb->next_scb_ptr != ins->asynch_tx_scb))
1707 		return -EINVAL;
1708 	if (snd_BUG_ON(ins->asynch_tx_scb->parent_scb_ptr !=
1709 		       ins->master_mix_scb))
1710 		return -EINVAL;
1711 
1712 	cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
1713 	cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
1714 
1715 	ins->spdif_pcm_input_scb = NULL;
1716 	ins->asynch_tx_scb = NULL;
1717 
1718 	/* clear buffer to prevent any undesired noise */
1719 	_dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
1720 
1721 	/* monitor state */
1722 	ins->spdif_status_out  &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1723 
1724 
1725 	return 0;
1726 }
1727 
1728 int cs46xx_iec958_pre_open (struct snd_cs46xx *chip)
1729 {
1730 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1731 
1732 	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
1733 		/* remove AsynchFGTxSCB and and PCMSerialInput_II */
1734 		cs46xx_dsp_disable_spdif_out (chip);
1735 
1736 		/* save state */
1737 		ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1738 	}
1739 
1740 	/* if not enabled already */
1741 	if ( !(ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
1742 		cs46xx_dsp_enable_spdif_hw (chip);
1743 	}
1744 
1745 	/* Create the asynch. transfer task  for playback */
1746 	ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
1747 								SPDIFO_SCB_INST,
1748 								SPDIFO_IP_OUTPUT_BUFFER1,
1749 								ins->master_mix_scb,
1750 								SCB_ON_PARENT_NEXT_SCB);
1751 
1752 
1753 	/* set spdif channel status value for streaming */
1754 	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_stream);
1755 
1756 	ins->spdif_status_out  |= DSP_SPDIF_STATUS_PLAYBACK_OPEN;
1757 
1758 	return 0;
1759 }
1760 
1761 int cs46xx_iec958_post_close (struct snd_cs46xx *chip)
1762 {
1763 	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1764 
1765 	if (snd_BUG_ON(!ins->asynch_tx_scb))
1766 		return -EINVAL;
1767 
1768 	ins->spdif_status_out  &= ~DSP_SPDIF_STATUS_PLAYBACK_OPEN;
1769 
1770 	/* restore settings */
1771 	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);
1772 
1773 	/* deallocate stuff */
1774 	if (ins->spdif_pcm_input_scb != NULL) {
1775 		cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
1776 		ins->spdif_pcm_input_scb = NULL;
1777 	}
1778 
1779 	cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
1780 	ins->asynch_tx_scb = NULL;
1781 
1782 	/* clear buffer to prevent any undesired noise */
1783 	_dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
1784 
1785 	/* restore state */
1786 	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
1787 		cs46xx_dsp_enable_spdif_out (chip);
1788 	}
1789 
1790 	return 0;
1791 }
1792