xref: /openbmc/linux/sound/pci/cs46xx/dsp_spos.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1 /*
2  *   This program is free software; you can redistribute it and/or modify
3  *   it under the terms of the GNU General Public License as published by
4  *   the Free Software Foundation; either version 2 of the License, or
5  *   (at your option) any later version.
6  *
7  *   This program is distributed in the hope that it will be useful,
8  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *   GNU General Public License for more details.
11  *
12  *   You should have received a copy of the GNU General Public License
13  *   along with this program; if not, write to the Free Software
14  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
15  *
16  */
17 
18 /*
19  * 2002-07 Benny Sjostrand benny@hostmobility.com
20  */
21 
22 
23 #include <sound/driver.h>
24 #include <asm/io.h>
25 #include <linux/delay.h>
26 #include <linux/pci.h>
27 #include <linux/pm.h>
28 #include <linux/init.h>
29 #include <linux/slab.h>
30 #include <linux/vmalloc.h>
31 #include <sound/core.h>
32 #include <sound/control.h>
33 #include <sound/info.h>
34 #include <sound/asoundef.h>
35 #include <sound/cs46xx.h>
36 
37 #include "cs46xx_lib.h"
38 #include "dsp_spos.h"
39 
40 static int cs46xx_dsp_async_init (cs46xx_t *chip, dsp_scb_descriptor_t * fg_entry);
41 
42 static wide_opcode_t wide_opcodes[] = {
43 	WIDE_FOR_BEGIN_LOOP,
44 	WIDE_FOR_BEGIN_LOOP2,
45 	WIDE_COND_GOTO_ADDR,
46 	WIDE_COND_GOTO_CALL,
47 	WIDE_TBEQ_COND_GOTO_ADDR,
48 	WIDE_TBEQ_COND_CALL_ADDR,
49 	WIDE_TBEQ_NCOND_GOTO_ADDR,
50 	WIDE_TBEQ_NCOND_CALL_ADDR,
51 	WIDE_TBEQ_COND_GOTO1_ADDR,
52 	WIDE_TBEQ_COND_CALL1_ADDR,
53 	WIDE_TBEQ_NCOND_GOTOI_ADDR,
54 	WIDE_TBEQ_NCOND_CALL1_ADDR
55 };
56 
57 static int shadow_and_reallocate_code (cs46xx_t * chip,u32 * data,u32 size, u32 overlay_begin_address)
58 {
59 	unsigned int i = 0, j, nreallocated = 0;
60 	u32 hival,loval,address;
61 	u32 mop_operands,mop_type,wide_op;
62 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
63 
64 	snd_assert( ((size % 2) == 0), return -EINVAL);
65 
66 	while (i < size) {
67 		loval = data[i++];
68 		hival = data[i++];
69 
70 		if (ins->code.offset > 0) {
71 			mop_operands = (hival >> 6) & 0x03fff;
72 			mop_type = mop_operands >> 10;
73 
74 			/* check for wide type instruction */
75 			if (mop_type == 0 &&
76 			    (mop_operands & WIDE_LADD_INSTR_MASK) == 0 &&
77 			    (mop_operands & WIDE_INSTR_MASK) != 0) {
78 				wide_op = loval & 0x7f;
79 				for (j = 0;j < ARRAY_SIZE(wide_opcodes); ++j) {
80 					if (wide_opcodes[j] == wide_op) {
81 						/* need to reallocate instruction */
82 						address  = (hival & 0x00FFF) << 5;
83 						address |=  loval >> 15;
84 
85 						snd_printdd("handle_wideop[1]: %05x:%05x addr %04x\n",hival,loval,address);
86 
87 						if ( !(address & 0x8000) ) {
88 							address += (ins->code.offset / 2) - overlay_begin_address;
89 						} else {
90 							snd_printdd("handle_wideop[1]: ROM symbol not reallocated\n");
91 						}
92 
93 						hival &= 0xFF000;
94 						loval &= 0x07FFF;
95 
96 						hival |= ( (address >> 5)  & 0x00FFF);
97 						loval |= ( (address << 15) & 0xF8000);
98 
99 						address  = (hival & 0x00FFF) << 5;
100 						address |=  loval >> 15;
101 
102 						snd_printdd("handle_wideop:[2] %05x:%05x addr %04x\n",hival,loval,address);
103 						nreallocated ++;
104 					} /* wide_opcodes[j] == wide_op */
105 				} /* for */
106 			} /* mod_type == 0 ... */
107 		} /* ins->code.offset > 0 */
108 
109 		ins->code.data[ins->code.size++] = loval;
110 		ins->code.data[ins->code.size++] = hival;
111 	}
112 
113 	snd_printdd("dsp_spos: %d instructions reallocated\n",nreallocated);
114 	return nreallocated;
115 }
116 
117 static segment_desc_t * get_segment_desc (dsp_module_desc_t * module, int seg_type)
118 {
119 	int i;
120 	for (i = 0;i < module->nsegments; ++i) {
121 		if (module->segments[i].segment_type == seg_type) {
122 			return (module->segments + i);
123 		}
124 	}
125 
126 	return NULL;
127 };
128 
129 static int find_free_symbol_index (dsp_spos_instance_t * ins)
130 {
131 	int index = ins->symbol_table.nsymbols,i;
132 
133 	for (i = ins->symbol_table.highest_frag_index; i < ins->symbol_table.nsymbols; ++i) {
134 		if (ins->symbol_table.symbols[i].deleted) {
135 			index = i;
136 			break;
137 		}
138 	}
139 
140 	return index;
141 }
142 
143 static int add_symbols (cs46xx_t * chip, dsp_module_desc_t * module)
144 {
145 	int i;
146 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
147 
148 	if (module->symbol_table.nsymbols > 0) {
149 		if (!strcmp(module->symbol_table.symbols[0].symbol_name, "OVERLAYBEGINADDRESS") &&
150 		    module->symbol_table.symbols[0].symbol_type == SYMBOL_CONSTANT ) {
151 			module->overlay_begin_address = module->symbol_table.symbols[0].address;
152 		}
153 	}
154 
155 	for (i = 0;i < module->symbol_table.nsymbols; ++i) {
156 		if (ins->symbol_table.nsymbols == (DSP_MAX_SYMBOLS - 1)) {
157 			snd_printk(KERN_ERR "dsp_spos: symbol table is full\n");
158 			return -ENOMEM;
159 		}
160 
161 
162 		if (cs46xx_dsp_lookup_symbol(chip,
163 					     module->symbol_table.symbols[i].symbol_name,
164 					     module->symbol_table.symbols[i].symbol_type) == NULL) {
165 
166 			ins->symbol_table.symbols[ins->symbol_table.nsymbols] = module->symbol_table.symbols[i];
167 			ins->symbol_table.symbols[ins->symbol_table.nsymbols].address += ((ins->code.offset / 2) - module->overlay_begin_address);
168 			ins->symbol_table.symbols[ins->symbol_table.nsymbols].module = module;
169 			ins->symbol_table.symbols[ins->symbol_table.nsymbols].deleted = 0;
170 
171 			if (ins->symbol_table.nsymbols > ins->symbol_table.highest_frag_index)
172 				ins->symbol_table.highest_frag_index = ins->symbol_table.nsymbols;
173 
174 			ins->symbol_table.nsymbols++;
175 		} else {
176           /* if (0) printk ("dsp_spos: symbol <%s> duplicated, probably nothing wrong with that (Cirrus?)\n",
177                              module->symbol_table.symbols[i].symbol_name); */
178 		}
179 	}
180 
181 	return 0;
182 }
183 
184 static symbol_entry_t * add_symbol (cs46xx_t * chip, char * symbol_name, u32 address, int type)
185 {
186 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
187 	symbol_entry_t * symbol = NULL;
188 	int index;
189 
190 	if (ins->symbol_table.nsymbols == (DSP_MAX_SYMBOLS - 1)) {
191 		snd_printk(KERN_ERR "dsp_spos: symbol table is full\n");
192 		return NULL;
193 	}
194 
195 	if (cs46xx_dsp_lookup_symbol(chip,
196 				     symbol_name,
197 				     type) != NULL) {
198 		snd_printk(KERN_ERR "dsp_spos: symbol <%s> duplicated\n", symbol_name);
199 		return NULL;
200 	}
201 
202 	index = find_free_symbol_index (ins);
203 
204 	strcpy (ins->symbol_table.symbols[index].symbol_name, symbol_name);
205 	ins->symbol_table.symbols[index].address = address;
206 	ins->symbol_table.symbols[index].symbol_type = type;
207 	ins->symbol_table.symbols[index].module = NULL;
208 	ins->symbol_table.symbols[index].deleted = 0;
209 	symbol = (ins->symbol_table.symbols + index);
210 
211 	if (index > ins->symbol_table.highest_frag_index)
212 		ins->symbol_table.highest_frag_index = index;
213 
214 	if (index == ins->symbol_table.nsymbols)
215 		ins->symbol_table.nsymbols++; /* no frag. in list */
216 
217 	return symbol;
218 }
219 
220 dsp_spos_instance_t *  cs46xx_dsp_spos_create (cs46xx_t * chip)
221 {
222 	dsp_spos_instance_t * ins = kmalloc(sizeof(dsp_spos_instance_t), GFP_KERNEL);
223 
224 	if (ins == NULL)
225 		return NULL;
226 	memset(ins, 0, sizeof(*ins));
227 
228 	/* better to use vmalloc for this big table */
229 	ins->symbol_table.nsymbols = 0;
230 	ins->symbol_table.symbols = vmalloc(sizeof(symbol_entry_t) * DSP_MAX_SYMBOLS);
231 	ins->symbol_table.highest_frag_index = 0;
232 
233 	if (ins->symbol_table.symbols == NULL) {
234 		cs46xx_dsp_spos_destroy(chip);
235 		return NULL;
236 	}
237 
238 	ins->code.offset = 0;
239 	ins->code.size = 0;
240 	ins->code.data = kmalloc(DSP_CODE_BYTE_SIZE, GFP_KERNEL);
241 
242 	if (ins->code.data == NULL) {
243 		cs46xx_dsp_spos_destroy(chip);
244 		return NULL;
245 	}
246 
247 	ins->nscb = 0;
248 	ins->ntask = 0;
249 
250 	ins->nmodules = 0;
251 	ins->modules = kmalloc(sizeof(dsp_module_desc_t) * DSP_MAX_MODULES, GFP_KERNEL);
252 
253 	if (ins->modules == NULL) {
254 		cs46xx_dsp_spos_destroy(chip);
255 		return NULL;
256 	}
257 
258 	/* default SPDIF input sample rate
259 	   to 48000 khz */
260 	ins->spdif_in_sample_rate = 48000;
261 
262 	/* maximize volume */
263 	ins->dac_volume_right = 0x8000;
264 	ins->dac_volume_left = 0x8000;
265 	ins->spdif_input_volume_right = 0x8000;
266 	ins->spdif_input_volume_left = 0x8000;
267 
268 	/* set left and right validity bits and
269 	   default channel status */
270 	ins->spdif_csuv_default =
271 		ins->spdif_csuv_stream =
272 	 /* byte 0 */  ((unsigned int)_wrap_all_bits(  (SNDRV_PCM_DEFAULT_CON_SPDIF        & 0xff)) << 24) |
273 	 /* byte 1 */  ((unsigned int)_wrap_all_bits( ((SNDRV_PCM_DEFAULT_CON_SPDIF >> 8) & 0xff)) << 16) |
274 	 /* byte 3 */   (unsigned int)_wrap_all_bits(  (SNDRV_PCM_DEFAULT_CON_SPDIF >> 24) & 0xff) |
275 	 /* left and right validity bits */ (1 << 13) | (1 << 12);
276 
277 	return ins;
278 }
279 
280 void  cs46xx_dsp_spos_destroy (cs46xx_t * chip)
281 {
282 	int i;
283 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
284 
285 	snd_assert(ins != NULL, return);
286 
287 	down(&chip->spos_mutex);
288 	for (i = 0; i < ins->nscb; ++i) {
289 		if (ins->scbs[i].deleted) continue;
290 
291 		cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) );
292 	}
293 
294 	kfree(ins->code.data);
295 	vfree(ins->symbol_table.symbols);
296 	kfree(ins->modules);
297 	kfree(ins);
298 	up(&chip->spos_mutex);
299 }
300 
301 int cs46xx_dsp_load_module (cs46xx_t * chip, dsp_module_desc_t * module)
302 {
303 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
304 	segment_desc_t * code = get_segment_desc (module,SEGTYPE_SP_PROGRAM);
305 	segment_desc_t * parameter = get_segment_desc (module,SEGTYPE_SP_PARAMETER);
306 	segment_desc_t * sample = get_segment_desc (module,SEGTYPE_SP_SAMPLE);
307 	u32 doffset, dsize;
308 
309 	if (ins->nmodules == DSP_MAX_MODULES - 1) {
310 		snd_printk(KERN_ERR "dsp_spos: to many modules loaded into DSP\n");
311 		return -ENOMEM;
312 	}
313 
314 	snd_printdd("dsp_spos: loading module %s into DSP\n", module->module_name);
315 
316 	if (ins->nmodules == 0) {
317 		snd_printdd("dsp_spos: clearing parameter area\n");
318 		snd_cs46xx_clear_BA1(chip, DSP_PARAMETER_BYTE_OFFSET, DSP_PARAMETER_BYTE_SIZE);
319 	}
320 
321 	if (parameter == NULL) {
322 		snd_printdd("dsp_spos: module got no parameter segment\n");
323 	} else {
324 		if (ins->nmodules > 0) {
325 			snd_printk(KERN_WARNING "dsp_spos: WARNING current parameter data may be overwriten!\n");
326 		}
327 
328 		doffset = (parameter->offset * 4 + DSP_PARAMETER_BYTE_OFFSET);
329 		dsize   = parameter->size * 4;
330 
331 		snd_printdd("dsp_spos: downloading parameter data to chip (%08x-%08x)\n",
332 			    doffset,doffset + dsize);
333 
334 		if (snd_cs46xx_download (chip, parameter->data, doffset, dsize)) {
335 			snd_printk(KERN_ERR "dsp_spos: failed to download parameter data to DSP\n");
336 			return -EINVAL;
337 		}
338 	}
339 
340 	if (ins->nmodules == 0) {
341 		snd_printdd("dsp_spos: clearing sample area\n");
342 		snd_cs46xx_clear_BA1(chip, DSP_SAMPLE_BYTE_OFFSET, DSP_SAMPLE_BYTE_SIZE);
343 	}
344 
345 	if (sample == NULL) {
346 		snd_printdd("dsp_spos: module got no sample segment\n");
347 	} else {
348 		if (ins->nmodules > 0) {
349 			snd_printk(KERN_WARNING "dsp_spos: WARNING current sample data may be overwriten\n");
350 		}
351 
352 		doffset = (sample->offset * 4  + DSP_SAMPLE_BYTE_OFFSET);
353 		dsize   =  sample->size * 4;
354 
355 		snd_printdd("dsp_spos: downloading sample data to chip (%08x-%08x)\n",
356 			    doffset,doffset + dsize);
357 
358 		if (snd_cs46xx_download (chip,sample->data,doffset,dsize)) {
359 			snd_printk(KERN_ERR "dsp_spos: failed to sample data to DSP\n");
360 			return -EINVAL;
361 		}
362 	}
363 
364 
365 	if (ins->nmodules == 0) {
366 		snd_printdd("dsp_spos: clearing code area\n");
367 		snd_cs46xx_clear_BA1(chip, DSP_CODE_BYTE_OFFSET, DSP_CODE_BYTE_SIZE);
368 	}
369 
370 	if (code == NULL) {
371 		snd_printdd("dsp_spos: module got no code segment\n");
372 	} else {
373 		if (ins->code.offset + code->size > DSP_CODE_BYTE_SIZE) {
374 			snd_printk(KERN_ERR "dsp_spos: no space available in DSP\n");
375 			return -ENOMEM;
376 		}
377 
378 		module->load_address = ins->code.offset;
379 		module->overlay_begin_address = 0x000;
380 
381 		/* if module has a code segment it must have
382 		   symbol table */
383 		snd_assert(module->symbol_table.symbols != NULL ,return -ENOMEM);
384 		if (add_symbols(chip,module)) {
385 			snd_printk(KERN_ERR "dsp_spos: failed to load symbol table\n");
386 			return -ENOMEM;
387 		}
388 
389 		doffset = (code->offset * 4 + ins->code.offset * 4 + DSP_CODE_BYTE_OFFSET);
390 		dsize   = code->size * 4;
391 		snd_printdd("dsp_spos: downloading code to chip (%08x-%08x)\n",
392 			    doffset,doffset + dsize);
393 
394 		module->nfixups = shadow_and_reallocate_code(chip,code->data,code->size,module->overlay_begin_address);
395 
396 		if (snd_cs46xx_download (chip,(ins->code.data + ins->code.offset),doffset,dsize)) {
397 			snd_printk(KERN_ERR "dsp_spos: failed to download code to DSP\n");
398 			return -EINVAL;
399 		}
400 
401 		ins->code.offset += code->size;
402 	}
403 
404 	/* NOTE: module segments and symbol table must be
405 	   statically allocated. Case that module data is
406 	   not generated by the ospparser */
407 	ins->modules[ins->nmodules] = *module;
408 	ins->nmodules++;
409 
410 	return 0;
411 }
412 
413 symbol_entry_t * cs46xx_dsp_lookup_symbol (cs46xx_t * chip, char * symbol_name, int symbol_type)
414 {
415 	int i;
416 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
417 
418 	for ( i = 0; i < ins->symbol_table.nsymbols; ++i ) {
419 
420 		if (ins->symbol_table.symbols[i].deleted)
421 			continue;
422 
423 		if (!strcmp(ins->symbol_table.symbols[i].symbol_name,symbol_name) &&
424 		    ins->symbol_table.symbols[i].symbol_type == symbol_type) {
425 			return (ins->symbol_table.symbols + i);
426 		}
427 	}
428 
429 #if 0
430 	printk ("dsp_spos: symbol <%s> type %02x not found\n",
431 		symbol_name,symbol_type);
432 #endif
433 
434 	return NULL;
435 }
436 
437 
438 static symbol_entry_t * cs46xx_dsp_lookup_symbol_addr (cs46xx_t * chip, u32 address, int symbol_type)
439 {
440 	int i;
441 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
442 
443 	for ( i = 0; i < ins->symbol_table.nsymbols; ++i ) {
444 
445 		if (ins->symbol_table.symbols[i].deleted)
446 			continue;
447 
448 		if (ins->symbol_table.symbols[i].address == address &&
449 		    ins->symbol_table.symbols[i].symbol_type == symbol_type) {
450 			return (ins->symbol_table.symbols + i);
451 		}
452 	}
453 
454 
455 	return NULL;
456 }
457 
458 
459 static void cs46xx_dsp_proc_symbol_table_read (snd_info_entry_t *entry, snd_info_buffer_t * buffer)
460 {
461 	cs46xx_t *chip = entry->private_data;
462 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
463 	int i;
464 
465 	snd_iprintf(buffer, "SYMBOLS:\n");
466 	for ( i = 0; i < ins->symbol_table.nsymbols; ++i ) {
467 		char *module_str = "system";
468 
469 		if (ins->symbol_table.symbols[i].deleted)
470 			continue;
471 
472 		if (ins->symbol_table.symbols[i].module != NULL) {
473 			module_str = ins->symbol_table.symbols[i].module->module_name;
474 		}
475 
476 
477 		snd_iprintf(buffer, "%04X <%02X> %s [%s]\n",
478 			    ins->symbol_table.symbols[i].address,
479 			    ins->symbol_table.symbols[i].symbol_type,
480 			    ins->symbol_table.symbols[i].symbol_name,
481 			    module_str);
482 	}
483 }
484 
485 
486 static void cs46xx_dsp_proc_modules_read (snd_info_entry_t *entry, snd_info_buffer_t * buffer)
487 {
488 	cs46xx_t *chip = entry->private_data;
489 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
490 	int i,j;
491 
492 	down(&chip->spos_mutex);
493 	snd_iprintf(buffer, "MODULES:\n");
494 	for ( i = 0; i < ins->nmodules; ++i ) {
495 		snd_iprintf(buffer, "\n%s:\n", ins->modules[i].module_name);
496 		snd_iprintf(buffer, "   %d symbols\n", ins->modules[i].symbol_table.nsymbols);
497 		snd_iprintf(buffer, "   %d fixups\n", ins->modules[i].nfixups);
498 
499 		for (j = 0; j < ins->modules[i].nsegments; ++ j) {
500 			segment_desc_t * desc = (ins->modules[i].segments + j);
501 			snd_iprintf(buffer, "   segment %02x offset %08x size %08x\n",
502 				    desc->segment_type,desc->offset, desc->size);
503 		}
504 	}
505 	up(&chip->spos_mutex);
506 }
507 
508 static void cs46xx_dsp_proc_task_tree_read (snd_info_entry_t *entry, snd_info_buffer_t * buffer)
509 {
510 	cs46xx_t *chip = entry->private_data;
511 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
512 	int i,j,col;
513 	void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
514 
515 	down(&chip->spos_mutex);
516 	snd_iprintf(buffer, "TASK TREES:\n");
517 	for ( i = 0; i < ins->ntask; ++i) {
518 		snd_iprintf(buffer,"\n%04x %s:\n",ins->tasks[i].address,ins->tasks[i].task_name);
519 
520 		for (col = 0,j = 0;j < ins->tasks[i].size; j++,col++) {
521 			u32 val;
522 			if (col == 4) {
523 				snd_iprintf(buffer,"\n");
524 				col = 0;
525 			}
526 			val = readl(dst + (ins->tasks[i].address + j) * sizeof(u32));
527 			snd_iprintf(buffer,"%08x ",val);
528 		}
529 	}
530 
531 	snd_iprintf(buffer,"\n");
532 	up(&chip->spos_mutex);
533 }
534 
535 static void cs46xx_dsp_proc_scb_read (snd_info_entry_t *entry, snd_info_buffer_t * buffer)
536 {
537 	cs46xx_t *chip = entry->private_data;
538 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
539 	int i;
540 
541 	down(&chip->spos_mutex);
542 	snd_iprintf(buffer, "SCB's:\n");
543 	for ( i = 0; i < ins->nscb; ++i) {
544 		if (ins->scbs[i].deleted)
545 			continue;
546 		snd_iprintf(buffer,"\n%04x %s:\n\n",ins->scbs[i].address,ins->scbs[i].scb_name);
547 
548 		if (ins->scbs[i].parent_scb_ptr != NULL) {
549 			snd_iprintf(buffer,"parent [%s:%04x] ",
550 				    ins->scbs[i].parent_scb_ptr->scb_name,
551 				    ins->scbs[i].parent_scb_ptr->address);
552 		} else snd_iprintf(buffer,"parent [none] ");
553 
554 		snd_iprintf(buffer,"sub_list_ptr [%s:%04x]\nnext_scb_ptr [%s:%04x]  task_entry [%s:%04x]\n",
555 			    ins->scbs[i].sub_list_ptr->scb_name,
556 			    ins->scbs[i].sub_list_ptr->address,
557 			    ins->scbs[i].next_scb_ptr->scb_name,
558 			    ins->scbs[i].next_scb_ptr->address,
559 			    ins->scbs[i].task_entry->symbol_name,
560 			    ins->scbs[i].task_entry->address);
561 	}
562 
563 	snd_iprintf(buffer,"\n");
564 	up(&chip->spos_mutex);
565 }
566 
567 static void cs46xx_dsp_proc_parameter_dump_read (snd_info_entry_t *entry, snd_info_buffer_t * buffer)
568 {
569 	cs46xx_t *chip = entry->private_data;
570 	/*dsp_spos_instance_t * ins = chip->dsp_spos_instance; */
571 	unsigned int i,col = 0;
572 	void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
573 	symbol_entry_t * symbol;
574 
575 	for (i = 0;i < DSP_PARAMETER_BYTE_SIZE; i += sizeof(u32),col ++) {
576 		if (col == 4) {
577 			snd_iprintf(buffer,"\n");
578 			col = 0;
579 		}
580 
581 		if ( (symbol = cs46xx_dsp_lookup_symbol_addr (chip,i / sizeof(u32), SYMBOL_PARAMETER)) != NULL) {
582 			col = 0;
583 			snd_iprintf (buffer,"\n%s:\n",symbol->symbol_name);
584 		}
585 
586 		if (col == 0) {
587 			snd_iprintf(buffer, "%04X ", i / (unsigned int)sizeof(u32));
588 		}
589 
590 		snd_iprintf(buffer,"%08X ",readl(dst + i));
591 	}
592 }
593 
594 static void cs46xx_dsp_proc_sample_dump_read (snd_info_entry_t *entry, snd_info_buffer_t * buffer)
595 {
596 	cs46xx_t *chip = entry->private_data;
597 	int i,col = 0;
598 	void __iomem *dst = chip->region.idx[2].remap_addr;
599 
600 	snd_iprintf(buffer,"PCMREADER:\n");
601 	for (i = PCM_READER_BUF1;i < PCM_READER_BUF1 + 0x30; i += sizeof(u32),col ++) {
602 		if (col == 4) {
603 			snd_iprintf(buffer,"\n");
604 			col = 0;
605 		}
606 
607 		if (col == 0) {
608 			snd_iprintf(buffer, "%04X ",i);
609 		}
610 
611 		snd_iprintf(buffer,"%08X ",readl(dst + i));
612 	}
613 
614 	snd_iprintf(buffer,"\nMIX_SAMPLE_BUF1:\n");
615 
616 	col = 0;
617 	for (i = MIX_SAMPLE_BUF1;i < MIX_SAMPLE_BUF1 + 0x40; i += sizeof(u32),col ++) {
618 		if (col == 4) {
619 			snd_iprintf(buffer,"\n");
620 			col = 0;
621 		}
622 
623 		if (col == 0) {
624 			snd_iprintf(buffer, "%04X ",i);
625 		}
626 
627 		snd_iprintf(buffer,"%08X ",readl(dst + i));
628 	}
629 
630 	snd_iprintf(buffer,"\nSRC_TASK_SCB1:\n");
631 	col = 0;
632 	for (i = 0x2480 ; i < 0x2480 + 0x40 ; i += sizeof(u32),col ++) {
633 		if (col == 4) {
634 			snd_iprintf(buffer,"\n");
635 			col = 0;
636 		}
637 
638 		if (col == 0) {
639 			snd_iprintf(buffer, "%04X ",i);
640 		}
641 
642 		snd_iprintf(buffer,"%08X ",readl(dst + i));
643 	}
644 
645 
646 	snd_iprintf(buffer,"\nSPDIFO_BUFFER:\n");
647 	col = 0;
648 	for (i = SPDIFO_IP_OUTPUT_BUFFER1;i < SPDIFO_IP_OUTPUT_BUFFER1 + 0x30; i += sizeof(u32),col ++) {
649 		if (col == 4) {
650 			snd_iprintf(buffer,"\n");
651 			col = 0;
652 		}
653 
654 		if (col == 0) {
655 			snd_iprintf(buffer, "%04X ",i);
656 		}
657 
658 		snd_iprintf(buffer,"%08X ",readl(dst + i));
659 	}
660 
661 	snd_iprintf(buffer,"\n...\n");
662 	col = 0;
663 
664 	for (i = SPDIFO_IP_OUTPUT_BUFFER1+0xD0;i < SPDIFO_IP_OUTPUT_BUFFER1 + 0x110; i += sizeof(u32),col ++) {
665 		if (col == 4) {
666 			snd_iprintf(buffer,"\n");
667 			col = 0;
668 		}
669 
670 		if (col == 0) {
671 			snd_iprintf(buffer, "%04X ",i);
672 		}
673 
674 		snd_iprintf(buffer,"%08X ",readl(dst + i));
675 	}
676 
677 
678 	snd_iprintf(buffer,"\nOUTPUT_SNOOP:\n");
679 	col = 0;
680 	for (i = OUTPUT_SNOOP_BUFFER;i < OUTPUT_SNOOP_BUFFER + 0x40; i += sizeof(u32),col ++) {
681 		if (col == 4) {
682 			snd_iprintf(buffer,"\n");
683 			col = 0;
684 		}
685 
686 		if (col == 0) {
687 			snd_iprintf(buffer, "%04X ",i);
688 		}
689 
690 		snd_iprintf(buffer,"%08X ",readl(dst + i));
691 	}
692 
693 	snd_iprintf(buffer,"\nCODEC_INPUT_BUF1: \n");
694 	col = 0;
695 	for (i = CODEC_INPUT_BUF1;i < CODEC_INPUT_BUF1 + 0x40; i += sizeof(u32),col ++) {
696 		if (col == 4) {
697 			snd_iprintf(buffer,"\n");
698 			col = 0;
699 		}
700 
701 		if (col == 0) {
702 			snd_iprintf(buffer, "%04X ",i);
703 		}
704 
705 		snd_iprintf(buffer,"%08X ",readl(dst + i));
706 	}
707 #if 0
708 	snd_iprintf(buffer,"\nWRITE_BACK_BUF1: \n");
709 	col = 0;
710 	for (i = WRITE_BACK_BUF1;i < WRITE_BACK_BUF1 + 0x40; i += sizeof(u32),col ++) {
711 		if (col == 4) {
712 			snd_iprintf(buffer,"\n");
713 			col = 0;
714 		}
715 
716 		if (col == 0) {
717 			snd_iprintf(buffer, "%04X ",i);
718 		}
719 
720 		snd_iprintf(buffer,"%08X ",readl(dst + i));
721 	}
722 #endif
723 
724 	snd_iprintf(buffer,"\nSPDIFI_IP_OUTPUT_BUFFER1: \n");
725 	col = 0;
726 	for (i = SPDIFI_IP_OUTPUT_BUFFER1;i < SPDIFI_IP_OUTPUT_BUFFER1 + 0x80; i += sizeof(u32),col ++) {
727 		if (col == 4) {
728 			snd_iprintf(buffer,"\n");
729 			col = 0;
730 		}
731 
732 		if (col == 0) {
733 			snd_iprintf(buffer, "%04X ",i);
734 		}
735 
736 		snd_iprintf(buffer,"%08X ",readl(dst + i));
737 	}
738 	snd_iprintf(buffer,"\n");
739 }
740 
741 int cs46xx_dsp_proc_init (snd_card_t * card, cs46xx_t *chip)
742 {
743 	snd_info_entry_t *entry;
744 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
745 	int i;
746 
747 	ins->snd_card = card;
748 
749 	if ((entry = snd_info_create_card_entry(card, "dsp", card->proc_root)) != NULL) {
750 		entry->content = SNDRV_INFO_CONTENT_TEXT;
751 		entry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
752 		entry->c.text.read_size = 512;
753 
754 		if (snd_info_register(entry) < 0) {
755 			snd_info_free_entry(entry);
756 			entry = NULL;
757 		}
758 	}
759 
760 	ins->proc_dsp_dir = entry;
761 
762 	if (!ins->proc_dsp_dir)
763 		return -ENOMEM;
764 
765 	if ((entry = snd_info_create_card_entry(card, "spos_symbols", ins->proc_dsp_dir)) != NULL) {
766 		entry->content = SNDRV_INFO_CONTENT_TEXT;
767 		entry->private_data = chip;
768 		entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
769 		entry->c.text.read_size = 512;
770 		entry->c.text.read = cs46xx_dsp_proc_symbol_table_read;
771 		if (snd_info_register(entry) < 0) {
772 			snd_info_free_entry(entry);
773 			entry = NULL;
774 		}
775 	}
776 	ins->proc_sym_info_entry = entry;
777 
778 	if ((entry = snd_info_create_card_entry(card, "spos_modules", ins->proc_dsp_dir)) != NULL) {
779 		entry->content = SNDRV_INFO_CONTENT_TEXT;
780 		entry->private_data = chip;
781 		entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
782 		entry->c.text.read_size = 512;
783 		entry->c.text.read = cs46xx_dsp_proc_modules_read;
784 		if (snd_info_register(entry) < 0) {
785 			snd_info_free_entry(entry);
786 			entry = NULL;
787 		}
788 	}
789 	ins->proc_modules_info_entry = entry;
790 
791 	if ((entry = snd_info_create_card_entry(card, "parameter", ins->proc_dsp_dir)) != NULL) {
792 		entry->content = SNDRV_INFO_CONTENT_TEXT;
793 		entry->private_data = chip;
794 		entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
795 		entry->c.text.read_size = 512;
796 		entry->c.text.read = cs46xx_dsp_proc_parameter_dump_read;
797 		if (snd_info_register(entry) < 0) {
798 			snd_info_free_entry(entry);
799 			entry = NULL;
800 		}
801 	}
802 	ins->proc_parameter_dump_info_entry = entry;
803 
804 	if ((entry = snd_info_create_card_entry(card, "sample", ins->proc_dsp_dir)) != NULL) {
805 		entry->content = SNDRV_INFO_CONTENT_TEXT;
806 		entry->private_data = chip;
807 		entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
808 		entry->c.text.read_size = 512;
809 		entry->c.text.read = cs46xx_dsp_proc_sample_dump_read;
810 		if (snd_info_register(entry) < 0) {
811 			snd_info_free_entry(entry);
812 			entry = NULL;
813 		}
814 	}
815 	ins->proc_sample_dump_info_entry = entry;
816 
817 	if ((entry = snd_info_create_card_entry(card, "task_tree", ins->proc_dsp_dir)) != NULL) {
818 		entry->content = SNDRV_INFO_CONTENT_TEXT;
819 		entry->private_data = chip;
820 		entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
821 		entry->c.text.read_size = 512;
822 		entry->c.text.read = cs46xx_dsp_proc_task_tree_read;
823 		if (snd_info_register(entry) < 0) {
824 			snd_info_free_entry(entry);
825 			entry = NULL;
826 		}
827 	}
828 	ins->proc_task_info_entry = entry;
829 
830 	if ((entry = snd_info_create_card_entry(card, "scb_info", ins->proc_dsp_dir)) != NULL) {
831 		entry->content = SNDRV_INFO_CONTENT_TEXT;
832 		entry->private_data = chip;
833 		entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
834 		entry->c.text.read_size = 1024;
835 		entry->c.text.read = cs46xx_dsp_proc_scb_read;
836 		if (snd_info_register(entry) < 0) {
837 			snd_info_free_entry(entry);
838 			entry = NULL;
839 		}
840 	}
841 	ins->proc_scb_info_entry = entry;
842 
843 	down(&chip->spos_mutex);
844 	/* register/update SCB's entries on proc */
845 	for (i = 0; i < ins->nscb; ++i) {
846 		if (ins->scbs[i].deleted) continue;
847 
848 		cs46xx_dsp_proc_register_scb_desc (chip, (ins->scbs + i));
849 	}
850 	up(&chip->spos_mutex);
851 
852 	return 0;
853 }
854 
855 int cs46xx_dsp_proc_done (cs46xx_t *chip)
856 {
857 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
858 	int i;
859 
860 	if (ins->proc_sym_info_entry) {
861 		snd_info_unregister(ins->proc_sym_info_entry);
862 		ins->proc_sym_info_entry = NULL;
863 	}
864 
865 	if (ins->proc_modules_info_entry) {
866 		snd_info_unregister(ins->proc_modules_info_entry);
867 		ins->proc_modules_info_entry = NULL;
868 	}
869 
870 	if (ins->proc_parameter_dump_info_entry) {
871 		snd_info_unregister(ins->proc_parameter_dump_info_entry);
872 		ins->proc_parameter_dump_info_entry = NULL;
873 	}
874 
875 	if (ins->proc_sample_dump_info_entry) {
876 		snd_info_unregister(ins->proc_sample_dump_info_entry);
877 		ins->proc_sample_dump_info_entry = NULL;
878 	}
879 
880 	if (ins->proc_scb_info_entry) {
881 		snd_info_unregister(ins->proc_scb_info_entry);
882 		ins->proc_scb_info_entry = NULL;
883 	}
884 
885 	if (ins->proc_task_info_entry) {
886 		snd_info_unregister(ins->proc_task_info_entry);
887 		ins->proc_task_info_entry = NULL;
888 	}
889 
890 	down(&chip->spos_mutex);
891 	for (i = 0; i < ins->nscb; ++i) {
892 		if (ins->scbs[i].deleted) continue;
893 		cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) );
894 	}
895 	up(&chip->spos_mutex);
896 
897 	if (ins->proc_dsp_dir) {
898 		snd_info_unregister (ins->proc_dsp_dir);
899 		ins->proc_dsp_dir = NULL;
900 	}
901 
902 	return 0;
903 }
904 
905 static int debug_tree;
906 static void _dsp_create_task_tree (cs46xx_t *chip,u32 * task_data, u32  dest, int size)
907 {
908 	void __iomem *spdst = chip->region.idx[1].remap_addr +
909 		DSP_PARAMETER_BYTE_OFFSET + dest * sizeof(u32);
910 	int i;
911 
912 	for (i = 0; i < size; ++i) {
913 		if (debug_tree) printk ("addr %p, val %08x\n",spdst,task_data[i]);
914 		writel(task_data[i],spdst);
915 		spdst += sizeof(u32);
916 	}
917 }
918 
919 static int debug_scb;
920 static void _dsp_create_scb (cs46xx_t *chip,u32 * scb_data, u32  dest)
921 {
922 	void __iomem *spdst = chip->region.idx[1].remap_addr +
923 		DSP_PARAMETER_BYTE_OFFSET + dest * sizeof(u32);
924 	int i;
925 
926 	for (i = 0; i < 0x10; ++i) {
927 		if (debug_scb) printk ("addr %p, val %08x\n",spdst,scb_data[i]);
928 		writel(scb_data[i],spdst);
929 		spdst += sizeof(u32);
930 	}
931 }
932 
933 static int find_free_scb_index (dsp_spos_instance_t * ins)
934 {
935 	int index = ins->nscb, i;
936 
937 	for (i = ins->scb_highest_frag_index; i < ins->nscb; ++i) {
938 		if (ins->scbs[i].deleted) {
939 			index = i;
940 			break;
941 		}
942 	}
943 
944 	return index;
945 }
946 
947 static dsp_scb_descriptor_t * _map_scb (cs46xx_t *chip,char * name,u32 dest)
948 {
949 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
950 	dsp_scb_descriptor_t * desc = NULL;
951 	int index;
952 
953 	if (ins->nscb == DSP_MAX_SCB_DESC - 1) {
954 		snd_printk(KERN_ERR "dsp_spos: got no place for other SCB\n");
955 		return NULL;
956 	}
957 
958 	index = find_free_scb_index (ins);
959 
960 	strcpy(ins->scbs[index].scb_name, name);
961 	ins->scbs[index].address = dest;
962 	ins->scbs[index].index = index;
963 	ins->scbs[index].proc_info = NULL;
964 	ins->scbs[index].ref_count = 1;
965 	ins->scbs[index].deleted = 0;
966 	spin_lock_init(&ins->scbs[index].lock);
967 
968 	desc = (ins->scbs + index);
969 	ins->scbs[index].scb_symbol = add_symbol (chip, name, dest, SYMBOL_PARAMETER);
970 
971 	if (index > ins->scb_highest_frag_index)
972 		ins->scb_highest_frag_index = index;
973 
974 	if (index == ins->nscb)
975 		ins->nscb++;
976 
977 	return desc;
978 }
979 
980 static dsp_task_descriptor_t * _map_task_tree (cs46xx_t *chip,char * name,u32 dest,u32 size)
981 {
982 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
983 	dsp_task_descriptor_t * desc = NULL;
984 
985 	if (ins->ntask == DSP_MAX_TASK_DESC - 1) {
986 		snd_printk(KERN_ERR "dsp_spos: got no place for other TASK\n");
987 		return NULL;
988 	}
989 
990 	strcpy(ins->tasks[ins->ntask].task_name,name);
991 	ins->tasks[ins->ntask].address = dest;
992 	ins->tasks[ins->ntask].size = size;
993 
994 	/* quick find in list */
995 	ins->tasks[ins->ntask].index = ins->ntask;
996 	desc = (ins->tasks + ins->ntask);
997 	ins->ntask++;
998 
999 	add_symbol (chip,name,dest,SYMBOL_PARAMETER);
1000 	return desc;
1001 }
1002 
1003 dsp_scb_descriptor_t * cs46xx_dsp_create_scb (cs46xx_t *chip,char * name, u32 * scb_data,u32 dest)
1004 {
1005 	dsp_scb_descriptor_t * desc;
1006 
1007 	desc = _map_scb (chip,name,dest);
1008 	if (desc) {
1009 		_dsp_create_scb(chip,scb_data,dest);
1010 	} else {
1011 		snd_printk(KERN_ERR "dsp_spos: failed to map SCB\n");
1012 	}
1013 
1014 	return desc;
1015 }
1016 
1017 
1018 static dsp_task_descriptor_t *  cs46xx_dsp_create_task_tree (cs46xx_t *chip,char * name, u32 * task_data,u32 dest,int size)
1019 {
1020 	dsp_task_descriptor_t * desc;
1021 
1022 	desc = _map_task_tree (chip,name,dest,size);
1023 	if (desc) {
1024 		_dsp_create_task_tree(chip,task_data,dest,size);
1025 	} else {
1026 		snd_printk(KERN_ERR "dsp_spos: failed to map TASK\n");
1027 	}
1028 
1029 	return desc;
1030 }
1031 
1032 int cs46xx_dsp_scb_and_task_init (cs46xx_t *chip)
1033 {
1034 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1035 	symbol_entry_t * fg_task_tree_header_code;
1036 	symbol_entry_t * task_tree_header_code;
1037 	symbol_entry_t * task_tree_thread;
1038 	symbol_entry_t * null_algorithm;
1039 	symbol_entry_t * magic_snoop_task;
1040 
1041 	dsp_scb_descriptor_t * timing_master_scb;
1042 	dsp_scb_descriptor_t * codec_out_scb;
1043 	dsp_scb_descriptor_t * codec_in_scb;
1044 	dsp_scb_descriptor_t * src_task_scb;
1045 	dsp_scb_descriptor_t * master_mix_scb;
1046 	dsp_scb_descriptor_t * rear_mix_scb;
1047 	dsp_scb_descriptor_t * record_mix_scb;
1048 	dsp_scb_descriptor_t * write_back_scb;
1049 	dsp_scb_descriptor_t * vari_decimate_scb;
1050 	dsp_scb_descriptor_t * rear_codec_out_scb;
1051 	dsp_scb_descriptor_t * clfe_codec_out_scb;
1052 	dsp_scb_descriptor_t * magic_snoop_scb;
1053 
1054 	int fifo_addr,fifo_span,valid_slots;
1055 
1056 	static spos_control_block_t sposcb = {
1057 		/* 0 */ HFG_TREE_SCB,HFG_STACK,
1058 		/* 1 */ SPOSCB_ADDR,BG_TREE_SCB_ADDR,
1059 		/* 2 */ DSP_SPOS_DC,0,
1060 		/* 3 */ DSP_SPOS_DC,DSP_SPOS_DC,
1061 		/* 4 */ 0,0,
1062 		/* 5 */ DSP_SPOS_UU,0,
1063 		/* 6 */ FG_TASK_HEADER_ADDR,0,
1064 		/* 7 */ 0,0,
1065 		/* 8 */ DSP_SPOS_UU,DSP_SPOS_DC,
1066 		/* 9 */ 0,
1067 		/* A */ 0,HFG_FIRST_EXECUTE_MODE,
1068 		/* B */ DSP_SPOS_UU,DSP_SPOS_UU,
1069 		/* C */ DSP_SPOS_DC_DC,
1070 		/* D */ DSP_SPOS_DC_DC,
1071 		/* E */ DSP_SPOS_DC_DC,
1072 		/* F */ DSP_SPOS_DC_DC
1073 	};
1074 
1075 	cs46xx_dsp_create_task_tree(chip, "sposCB", (u32 *)&sposcb, SPOSCB_ADDR, 0x10);
1076 
1077 	null_algorithm  = cs46xx_dsp_lookup_symbol(chip, "NULLALGORITHM", SYMBOL_CODE);
1078 	if (null_algorithm == NULL) {
1079 		snd_printk(KERN_ERR "dsp_spos: symbol NULLALGORITHM not found\n");
1080 		return -EIO;
1081 	}
1082 
1083 	fg_task_tree_header_code = cs46xx_dsp_lookup_symbol(chip, "FGTASKTREEHEADERCODE", SYMBOL_CODE);
1084 	if (fg_task_tree_header_code == NULL) {
1085 		snd_printk(KERN_ERR "dsp_spos: symbol FGTASKTREEHEADERCODE not found\n");
1086 		return -EIO;
1087 	}
1088 
1089 	task_tree_header_code = cs46xx_dsp_lookup_symbol(chip, "TASKTREEHEADERCODE", SYMBOL_CODE);
1090 	if (task_tree_header_code == NULL) {
1091 		snd_printk(KERN_ERR "dsp_spos: symbol TASKTREEHEADERCODE not found\n");
1092 		return -EIO;
1093 	}
1094 
1095 	task_tree_thread = cs46xx_dsp_lookup_symbol(chip, "TASKTREETHREAD", SYMBOL_CODE);
1096 	if (task_tree_thread == NULL) {
1097 		snd_printk(KERN_ERR "dsp_spos: symbol TASKTREETHREAD not found\n");
1098 		return -EIO;
1099 	}
1100 
1101 	magic_snoop_task = cs46xx_dsp_lookup_symbol(chip, "MAGICSNOOPTASK", SYMBOL_CODE);
1102 	if (magic_snoop_task == NULL) {
1103 		snd_printk(KERN_ERR "dsp_spos: symbol MAGICSNOOPTASK not found\n");
1104 		return -EIO;
1105 	}
1106 
1107 	{
1108 		/* create the null SCB */
1109 		static generic_scb_t null_scb = {
1110 			{ 0, 0, 0, 0 },
1111 			{ 0, 0, 0, 0, 0 },
1112 			NULL_SCB_ADDR, NULL_SCB_ADDR,
1113 			0, 0, 0, 0, 0,
1114 			{
1115 				0,0,
1116 				0,0,
1117 			}
1118 		};
1119 
1120 		null_scb.entry_point = null_algorithm->address;
1121 		ins->the_null_scb = cs46xx_dsp_create_scb(chip, "nullSCB", (u32 *)&null_scb, NULL_SCB_ADDR);
1122 		ins->the_null_scb->task_entry = null_algorithm;
1123 		ins->the_null_scb->sub_list_ptr = ins->the_null_scb;
1124 		ins->the_null_scb->next_scb_ptr = ins->the_null_scb;
1125 		ins->the_null_scb->parent_scb_ptr = NULL;
1126 		cs46xx_dsp_proc_register_scb_desc (chip,ins->the_null_scb);
1127 	}
1128 
1129 	{
1130 		/* setup foreground task tree */
1131 		static task_tree_control_block_t fg_task_tree_hdr =  {
1132 			{ FG_TASK_HEADER_ADDR | (DSP_SPOS_DC << 0x10),
1133 			  DSP_SPOS_DC_DC,
1134 			  DSP_SPOS_DC_DC,
1135 			  0x0000,DSP_SPOS_DC,
1136 			  DSP_SPOS_DC, DSP_SPOS_DC,
1137 			  DSP_SPOS_DC_DC,
1138 			  DSP_SPOS_DC_DC,
1139 			  DSP_SPOS_DC_DC,
1140 			  DSP_SPOS_DC,DSP_SPOS_DC },
1141 
1142 			{
1143 				BG_TREE_SCB_ADDR,TIMINGMASTER_SCB_ADDR,
1144 				0,
1145 				FG_TASK_HEADER_ADDR + TCBData,
1146 			},
1147 
1148 			{
1149 				4,0,
1150 				1,0,
1151 				2,SPOSCB_ADDR + HFGFlags,
1152 				0,0,
1153 				FG_TASK_HEADER_ADDR + TCBContextBlk,FG_STACK
1154 			},
1155 
1156 			{
1157 				DSP_SPOS_DC,0,
1158 				DSP_SPOS_DC,DSP_SPOS_DC,
1159 				DSP_SPOS_DC,DSP_SPOS_DC,
1160 				DSP_SPOS_DC,DSP_SPOS_DC,
1161 				DSP_SPOS_DC,DSP_SPOS_DC,
1162 				DSP_SPOS_DCDC,
1163 				DSP_SPOS_UU,1,
1164 				DSP_SPOS_DCDC,
1165 				DSP_SPOS_DCDC,
1166 				DSP_SPOS_DCDC,
1167 				DSP_SPOS_DCDC,
1168 				DSP_SPOS_DCDC,
1169 				DSP_SPOS_DCDC,
1170 				DSP_SPOS_DCDC,
1171 				DSP_SPOS_DCDC,
1172 				DSP_SPOS_DCDC,
1173 				DSP_SPOS_DCDC,
1174 				DSP_SPOS_DCDC,
1175 				DSP_SPOS_DCDC,
1176 				DSP_SPOS_DCDC,
1177 				DSP_SPOS_DCDC,
1178 				DSP_SPOS_DCDC,
1179 				DSP_SPOS_DCDC,
1180 				DSP_SPOS_DCDC,
1181 				DSP_SPOS_DCDC,
1182 				DSP_SPOS_DCDC,
1183 				DSP_SPOS_DCDC,
1184 				DSP_SPOS_DCDC,
1185 				DSP_SPOS_DCDC,
1186 				DSP_SPOS_DCDC,
1187 				DSP_SPOS_DCDC,
1188 				DSP_SPOS_DCDC,
1189 				DSP_SPOS_DCDC,
1190 				DSP_SPOS_DCDC,
1191 				DSP_SPOS_DCDC
1192 			},
1193 			{
1194 				FG_INTERVAL_TIMER_PERIOD,DSP_SPOS_UU,
1195 				0,0
1196 			}
1197 		};
1198 
1199 		fg_task_tree_hdr.links.entry_point = fg_task_tree_header_code->address;
1200 		fg_task_tree_hdr.context_blk.stack0 = task_tree_thread->address;
1201 		cs46xx_dsp_create_task_tree(chip,"FGtaskTreeHdr",(u32 *)&fg_task_tree_hdr,FG_TASK_HEADER_ADDR,0x35);
1202 	}
1203 
1204 
1205 	{
1206 		/* setup foreground task tree */
1207 		static task_tree_control_block_t bg_task_tree_hdr =  {
1208 			{ DSP_SPOS_DC_DC,
1209 			  DSP_SPOS_DC_DC,
1210 			  DSP_SPOS_DC_DC,
1211 			  DSP_SPOS_DC, DSP_SPOS_DC,
1212 			  DSP_SPOS_DC, DSP_SPOS_DC,
1213 			  DSP_SPOS_DC_DC,
1214 			  DSP_SPOS_DC_DC,
1215 			  DSP_SPOS_DC_DC,
1216 			  DSP_SPOS_DC,DSP_SPOS_DC },
1217 
1218 			{
1219 				NULL_SCB_ADDR,NULL_SCB_ADDR,  /* Set up the background to do nothing */
1220 				0,
1221 				BG_TREE_SCB_ADDR + TCBData,
1222 			},
1223 
1224 			{
1225 				9999,0,
1226 				0,1,
1227 				0,SPOSCB_ADDR + HFGFlags,
1228 				0,0,
1229 				BG_TREE_SCB_ADDR + TCBContextBlk,BG_STACK
1230 			},
1231 
1232 			{
1233 				DSP_SPOS_DC,0,
1234 				DSP_SPOS_DC,DSP_SPOS_DC,
1235 				DSP_SPOS_DC,DSP_SPOS_DC,
1236 				DSP_SPOS_DC,DSP_SPOS_DC,
1237 				DSP_SPOS_DC,DSP_SPOS_DC,
1238 				DSP_SPOS_DCDC,
1239 				DSP_SPOS_UU,1,
1240 				DSP_SPOS_DCDC,
1241 				DSP_SPOS_DCDC,
1242 				DSP_SPOS_DCDC,
1243 				DSP_SPOS_DCDC,
1244 				DSP_SPOS_DCDC,
1245 				DSP_SPOS_DCDC,
1246 				DSP_SPOS_DCDC,
1247 				DSP_SPOS_DCDC,
1248 				DSP_SPOS_DCDC,
1249 				DSP_SPOS_DCDC,
1250 				DSP_SPOS_DCDC,
1251 				DSP_SPOS_DCDC,
1252 				DSP_SPOS_DCDC,
1253 				DSP_SPOS_DCDC,
1254 				DSP_SPOS_DCDC,
1255 				DSP_SPOS_DCDC,
1256 				DSP_SPOS_DCDC,
1257 				DSP_SPOS_DCDC,
1258 				DSP_SPOS_DCDC,
1259 				DSP_SPOS_DCDC,
1260 				DSP_SPOS_DCDC,
1261 				DSP_SPOS_DCDC,
1262 				DSP_SPOS_DCDC,
1263 				DSP_SPOS_DCDC,
1264 				DSP_SPOS_DCDC,
1265 				DSP_SPOS_DCDC,
1266 				DSP_SPOS_DCDC,
1267 				DSP_SPOS_DCDC
1268 			},
1269 			{
1270 				BG_INTERVAL_TIMER_PERIOD,DSP_SPOS_UU,
1271 				0,0
1272 			}
1273 		};
1274 
1275 		bg_task_tree_hdr.links.entry_point = task_tree_header_code->address;
1276 		bg_task_tree_hdr.context_blk.stack0 = task_tree_thread->address;
1277 		cs46xx_dsp_create_task_tree(chip,"BGtaskTreeHdr",(u32 *)&bg_task_tree_hdr,BG_TREE_SCB_ADDR,0x35);
1278 	}
1279 
1280 	/* create timing master SCB */
1281 	timing_master_scb = cs46xx_dsp_create_timing_master_scb(chip);
1282 
1283 	/* create the CODEC output task */
1284 	codec_out_scb = cs46xx_dsp_create_codec_out_scb(chip,"CodecOutSCB_I",0x0010,0x0000,
1285 							MASTERMIX_SCB_ADDR,
1286 							CODECOUT_SCB_ADDR,timing_master_scb,
1287 							SCB_ON_PARENT_SUBLIST_SCB);
1288 
1289 	if (!codec_out_scb) goto _fail_end;
1290 	/* create the master mix SCB */
1291 	master_mix_scb = cs46xx_dsp_create_mix_only_scb(chip,"MasterMixSCB",
1292 							MIX_SAMPLE_BUF1,MASTERMIX_SCB_ADDR,
1293 							codec_out_scb,
1294 							SCB_ON_PARENT_SUBLIST_SCB);
1295 	ins->master_mix_scb = master_mix_scb;
1296 
1297 	if (!master_mix_scb) goto _fail_end;
1298 
1299 	/* create codec in */
1300 	codec_in_scb = cs46xx_dsp_create_codec_in_scb(chip,"CodecInSCB",0x0010,0x00A0,
1301 						      CODEC_INPUT_BUF1,
1302 						      CODECIN_SCB_ADDR,codec_out_scb,
1303 						      SCB_ON_PARENT_NEXT_SCB);
1304 	if (!codec_in_scb) goto _fail_end;
1305 	ins->codec_in_scb = codec_in_scb;
1306 
1307 	/* create write back scb */
1308 	write_back_scb = cs46xx_dsp_create_mix_to_ostream_scb(chip,"WriteBackSCB",
1309 							      WRITE_BACK_BUF1,WRITE_BACK_SPB,
1310 							      WRITEBACK_SCB_ADDR,
1311 							      timing_master_scb,
1312 							      SCB_ON_PARENT_NEXT_SCB);
1313 	if (!write_back_scb) goto _fail_end;
1314 
1315 	{
1316 		static mix2_ostream_spb_t mix2_ostream_spb = {
1317 			0x00020000,
1318 			0x0000ffff
1319 		};
1320 
1321 		/* dirty hack ... */
1322 		_dsp_create_task_tree (chip,(u32 *)&mix2_ostream_spb,WRITE_BACK_SPB,2);
1323 	}
1324 
1325 	/* input sample converter */
1326 	vari_decimate_scb = cs46xx_dsp_create_vari_decimate_scb(chip,"VariDecimateSCB",
1327 								VARI_DECIMATE_BUF0,
1328 								VARI_DECIMATE_BUF1,
1329 								VARIDECIMATE_SCB_ADDR,
1330 								write_back_scb,
1331 								SCB_ON_PARENT_SUBLIST_SCB);
1332 	if (!vari_decimate_scb) goto _fail_end;
1333 
1334 	/* create the record mixer SCB */
1335 	record_mix_scb = cs46xx_dsp_create_mix_only_scb(chip,"RecordMixerSCB",
1336 							MIX_SAMPLE_BUF2,
1337 							RECORD_MIXER_SCB_ADDR,
1338 							vari_decimate_scb,
1339 							SCB_ON_PARENT_SUBLIST_SCB);
1340 	ins->record_mixer_scb = record_mix_scb;
1341 
1342 	if (!record_mix_scb) goto _fail_end;
1343 
1344 	valid_slots = snd_cs46xx_peekBA0(chip, BA0_ACOSV);
1345 
1346 	snd_assert (chip->nr_ac97_codecs == 1 || chip->nr_ac97_codecs == 2);
1347 
1348 	if (chip->nr_ac97_codecs == 1) {
1349 		/* output on slot 5 and 11
1350 		   on primary CODEC */
1351 		fifo_addr = 0x20;
1352 		fifo_span = 0x60;
1353 
1354 		/* enable slot 5 and 11 */
1355 		valid_slots |= ACOSV_SLV5 | ACOSV_SLV11;
1356 	} else {
1357 		/* output on slot 7 and 8
1358 		   on secondary CODEC */
1359 		fifo_addr = 0x40;
1360 		fifo_span = 0x10;
1361 
1362 		/* enable slot 7 and 8 */
1363 		valid_slots |= ACOSV_SLV7 | ACOSV_SLV8;
1364 	}
1365 	/* create CODEC tasklet for rear speakers output*/
1366 	rear_codec_out_scb = cs46xx_dsp_create_codec_out_scb(chip,"CodecOutSCB_Rear",fifo_span,fifo_addr,
1367 							     REAR_MIXER_SCB_ADDR,
1368 							     REAR_CODECOUT_SCB_ADDR,codec_in_scb,
1369 							     SCB_ON_PARENT_NEXT_SCB);
1370 	if (!rear_codec_out_scb) goto _fail_end;
1371 
1372 
1373 	/* create the rear PCM channel  mixer SCB */
1374 	rear_mix_scb = cs46xx_dsp_create_mix_only_scb(chip,"RearMixerSCB",
1375 						      MIX_SAMPLE_BUF3,
1376 						      REAR_MIXER_SCB_ADDR,
1377 						      rear_codec_out_scb,
1378 						      SCB_ON_PARENT_SUBLIST_SCB);
1379 	ins->rear_mix_scb = rear_mix_scb;
1380 	if (!rear_mix_scb) goto _fail_end;
1381 
1382 	if (chip->nr_ac97_codecs == 2) {
1383 		/* create CODEC tasklet for rear Center/LFE output
1384 		   slot 6 and 9 on seconadry CODEC */
1385 		clfe_codec_out_scb = cs46xx_dsp_create_codec_out_scb(chip,"CodecOutSCB_CLFE",0x0030,0x0030,
1386 								     CLFE_MIXER_SCB_ADDR,
1387 								     CLFE_CODEC_SCB_ADDR,
1388 								     rear_codec_out_scb,
1389 								     SCB_ON_PARENT_NEXT_SCB);
1390 		if (!clfe_codec_out_scb) goto _fail_end;
1391 
1392 
1393 		/* create the rear PCM channel  mixer SCB */
1394 		ins->center_lfe_mix_scb = cs46xx_dsp_create_mix_only_scb(chip,"CLFEMixerSCB",
1395 									 MIX_SAMPLE_BUF4,
1396 									 CLFE_MIXER_SCB_ADDR,
1397 									 clfe_codec_out_scb,
1398 									 SCB_ON_PARENT_SUBLIST_SCB);
1399 		if (!ins->center_lfe_mix_scb) goto _fail_end;
1400 
1401 		/* enable slot 6 and 9 */
1402 		valid_slots |= ACOSV_SLV6 | ACOSV_SLV9;
1403 	} else {
1404 		clfe_codec_out_scb = rear_codec_out_scb;
1405 		ins->center_lfe_mix_scb = rear_mix_scb;
1406 	}
1407 
1408 	/* enable slots depending on CODEC configuration */
1409 	snd_cs46xx_pokeBA0(chip, BA0_ACOSV, valid_slots);
1410 
1411 	/* the magic snooper */
1412 	magic_snoop_scb = cs46xx_dsp_create_magic_snoop_scb (chip,"MagicSnoopSCB_I",OUTPUTSNOOP_SCB_ADDR,
1413 							     OUTPUT_SNOOP_BUFFER,
1414 							     codec_out_scb,
1415 							     clfe_codec_out_scb,
1416 							     SCB_ON_PARENT_NEXT_SCB);
1417 
1418 
1419 	if (!magic_snoop_scb) goto _fail_end;
1420 	ins->ref_snoop_scb = magic_snoop_scb;
1421 
1422 	/* SP IO access */
1423 	if (!cs46xx_dsp_create_spio_write_scb(chip,"SPIOWriteSCB",SPIOWRITE_SCB_ADDR,
1424 					      magic_snoop_scb,
1425 					      SCB_ON_PARENT_NEXT_SCB))
1426 		goto _fail_end;
1427 
1428 	/* SPDIF input sampel rate converter */
1429 	src_task_scb = cs46xx_dsp_create_src_task_scb(chip,"SrcTaskSCB_SPDIFI",
1430 						      ins->spdif_in_sample_rate,
1431 						      SRC_OUTPUT_BUF1,
1432 						      SRC_DELAY_BUF1,SRCTASK_SCB_ADDR,
1433 						      master_mix_scb,
1434 						      SCB_ON_PARENT_SUBLIST_SCB,1);
1435 
1436 	if (!src_task_scb) goto _fail_end;
1437 	cs46xx_src_unlink(chip,src_task_scb);
1438 
1439 	/* NOTE: when we now how to detect the SPDIF input
1440 	   sample rate we will use this SRC to adjust it */
1441 	ins->spdif_in_src = src_task_scb;
1442 
1443 	cs46xx_dsp_async_init(chip,timing_master_scb);
1444 	return 0;
1445 
1446  _fail_end:
1447 	snd_printk(KERN_ERR "dsp_spos: failed to setup SCB's in DSP\n");
1448 	return -EINVAL;
1449 }
1450 
1451 static int cs46xx_dsp_async_init (cs46xx_t *chip, dsp_scb_descriptor_t * fg_entry)
1452 {
1453 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1454 	symbol_entry_t * s16_async_codec_input_task;
1455 	symbol_entry_t * spdifo_task;
1456 	symbol_entry_t * spdifi_task;
1457 	dsp_scb_descriptor_t * spdifi_scb_desc,* spdifo_scb_desc,* async_codec_scb_desc;
1458 
1459 	s16_async_codec_input_task = cs46xx_dsp_lookup_symbol(chip, "S16_ASYNCCODECINPUTTASK", SYMBOL_CODE);
1460 	if (s16_async_codec_input_task == NULL) {
1461 		snd_printk(KERN_ERR "dsp_spos: symbol S16_ASYNCCODECINPUTTASK not found\n");
1462 		return -EIO;
1463 	}
1464 	spdifo_task = cs46xx_dsp_lookup_symbol(chip, "SPDIFOTASK", SYMBOL_CODE);
1465 	if (spdifo_task == NULL) {
1466 		snd_printk(KERN_ERR "dsp_spos: symbol SPDIFOTASK not found\n");
1467 		return -EIO;
1468 	}
1469 
1470 	spdifi_task = cs46xx_dsp_lookup_symbol(chip, "SPDIFITASK", SYMBOL_CODE);
1471 	if (spdifi_task == NULL) {
1472 		snd_printk(KERN_ERR "dsp_spos: symbol SPDIFITASK not found\n");
1473 		return -EIO;
1474 	}
1475 
1476 	{
1477 		/* 0xBC0 */
1478 		spdifoscb_t spdifo_scb = {
1479 			/* 0 */ DSP_SPOS_UUUU,
1480 			{
1481 				/* 1 */ 0xb0,
1482 				/* 2 */ 0,
1483 				/* 3 */ 0,
1484 				/* 4 */ 0,
1485 			},
1486 			/* NOTE: the SPDIF output task read samples in mono
1487 			   format, the AsynchFGTxSCB task writes to buffer
1488 			   in stereo format
1489 			*/
1490 			/* 5 */ RSCONFIG_SAMPLE_16MONO + RSCONFIG_MODULO_256,
1491 			/* 6 */ ( SPDIFO_IP_OUTPUT_BUFFER1 << 0x10 )  |  0xFFFC,
1492 			/* 7 */ 0,0,
1493 			/* 8 */ 0,
1494 			/* 9 */ FG_TASK_HEADER_ADDR, NULL_SCB_ADDR,
1495 			/* A */ spdifo_task->address,
1496 			SPDIFO_SCB_INST + SPDIFOFIFOPointer,
1497 			{
1498 				/* B */ 0x0040, /*DSP_SPOS_UUUU,*/
1499 				/* C */ 0x20ff, /*DSP_SPOS_UUUU,*/
1500 			},
1501 			/* D */ 0x804c,0,							  /* SPDIFOFIFOPointer:SPDIFOStatRegAddr; */
1502 			/* E */ 0x0108,0x0001,					  /* SPDIFOStMoFormat:SPDIFOFIFOBaseAddr; */
1503 			/* F */ DSP_SPOS_UUUU	  			          /* SPDIFOFree; */
1504 		};
1505 
1506 		/* 0xBB0 */
1507 		spdifiscb_t spdifi_scb = {
1508 			/* 0 */ DSP_SPOS_UULO,DSP_SPOS_UUHI,
1509 			/* 1 */ 0,
1510 			/* 2 */ 0,
1511 			/* 3 */ 1,4000,        /* SPDIFICountLimit SPDIFICount */
1512 			/* 4 */ DSP_SPOS_UUUU, /* SPDIFIStatusData */
1513 			/* 5 */ 0,DSP_SPOS_UUHI, /* StatusData, Free4 */
1514 			/* 6 */ DSP_SPOS_UUUU,  /* Free3 */
1515 			/* 7 */ DSP_SPOS_UU,DSP_SPOS_DC,  /* Free2 BitCount*/
1516 			/* 8 */ DSP_SPOS_UUUU,	/* TempStatus */
1517 			/* 9 */ SPDIFO_SCB_INST, NULL_SCB_ADDR,
1518 			/* A */ spdifi_task->address,
1519 			SPDIFI_SCB_INST + SPDIFIFIFOPointer,
1520 			/* NOTE: The SPDIF input task write the sample in mono
1521 			   format from the HW FIFO, the AsynchFGRxSCB task  reads
1522 			   them in stereo
1523 			*/
1524 			/* B */ RSCONFIG_SAMPLE_16MONO + RSCONFIG_MODULO_128,
1525 			/* C */ (SPDIFI_IP_OUTPUT_BUFFER1 << 0x10) | 0xFFFC,
1526 			/* D */ 0x8048,0,
1527 			/* E */ 0x01f0,0x0001,
1528 			/* F */ DSP_SPOS_UUUU /* SPDIN_STATUS monitor */
1529 		};
1530 
1531 		/* 0xBA0 */
1532 		async_codec_input_scb_t async_codec_input_scb = {
1533 			/* 0 */ DSP_SPOS_UUUU,
1534 			/* 1 */ 0,
1535 			/* 2 */ 0,
1536 			/* 3 */ 1,4000,
1537 			/* 4 */ 0x0118,0x0001,
1538 			/* 5 */ RSCONFIG_SAMPLE_16MONO + RSCONFIG_MODULO_64,
1539 			/* 6 */ (ASYNC_IP_OUTPUT_BUFFER1 << 0x10) | 0xFFFC,
1540 			/* 7 */ DSP_SPOS_UU,0x3,
1541 			/* 8 */ DSP_SPOS_UUUU,
1542 			/* 9 */ SPDIFI_SCB_INST,NULL_SCB_ADDR,
1543 			/* A */ s16_async_codec_input_task->address,
1544 			HFG_TREE_SCB + AsyncCIOFIFOPointer,
1545 
1546 			/* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
1547 			/* C */ (ASYNC_IP_OUTPUT_BUFFER1 << 0x10),  /*(ASYNC_IP_OUTPUT_BUFFER1 << 0x10) | 0xFFFC,*/
1548 
1549 #ifdef UseASER1Input
1550 			/* short AsyncCIFIFOPointer:AsyncCIStatRegAddr;
1551 			   Init. 0000:8042: for ASER1
1552 			   0000:8044: for ASER2 */
1553 			/* D */ 0x8042,0,
1554 
1555 			/* short AsyncCIStMoFormat:AsyncCIFIFOBaseAddr;
1556 			   Init 1 stero:8050 ASER1
1557 			   Init 0  mono:8070 ASER2
1558 			   Init 1 Stereo : 0100 ASER1 (Set by script) */
1559 			/* E */ 0x0100,0x0001,
1560 
1561 #endif
1562 
1563 #ifdef UseASER2Input
1564 			/* short AsyncCIFIFOPointer:AsyncCIStatRegAddr;
1565 			   Init. 0000:8042: for ASER1
1566 			   0000:8044: for ASER2 */
1567 			/* D */ 0x8044,0,
1568 
1569 			/* short AsyncCIStMoFormat:AsyncCIFIFOBaseAddr;
1570 			   Init 1 stero:8050 ASER1
1571 			   Init 0  mono:8070 ASER2
1572 			   Init 1 Stereo : 0100 ASER1 (Set by script) */
1573 			/* E */ 0x0110,0x0001,
1574 
1575 #endif
1576 
1577 			/* short AsyncCIOutputBufModulo:AsyncCIFree;
1578 			   AsyncCIOutputBufModulo: The modulo size for
1579 			   the output buffer of this task */
1580 			/* F */ 0, /* DSP_SPOS_UUUU */
1581 		};
1582 
1583 		spdifo_scb_desc = cs46xx_dsp_create_scb(chip,"SPDIFOSCB",(u32 *)&spdifo_scb,SPDIFO_SCB_INST);
1584 
1585 		snd_assert(spdifo_scb_desc, return -EIO);
1586 		spdifi_scb_desc = cs46xx_dsp_create_scb(chip,"SPDIFISCB",(u32 *)&spdifi_scb,SPDIFI_SCB_INST);
1587 		snd_assert(spdifi_scb_desc, return -EIO);
1588 		async_codec_scb_desc = cs46xx_dsp_create_scb(chip,"AsynCodecInputSCB",(u32 *)&async_codec_input_scb, HFG_TREE_SCB);
1589 		snd_assert(async_codec_scb_desc, return -EIO);
1590 
1591 		async_codec_scb_desc->parent_scb_ptr = NULL;
1592 		async_codec_scb_desc->next_scb_ptr = spdifi_scb_desc;
1593 		async_codec_scb_desc->sub_list_ptr = ins->the_null_scb;
1594 		async_codec_scb_desc->task_entry = s16_async_codec_input_task;
1595 
1596 		spdifi_scb_desc->parent_scb_ptr = async_codec_scb_desc;
1597 		spdifi_scb_desc->next_scb_ptr = spdifo_scb_desc;
1598 		spdifi_scb_desc->sub_list_ptr = ins->the_null_scb;
1599 		spdifi_scb_desc->task_entry = spdifi_task;
1600 
1601 		spdifo_scb_desc->parent_scb_ptr = spdifi_scb_desc;
1602 		spdifo_scb_desc->next_scb_ptr = fg_entry;
1603 		spdifo_scb_desc->sub_list_ptr = ins->the_null_scb;
1604 		spdifo_scb_desc->task_entry = spdifo_task;
1605 
1606 		/* this one is faked, as the parnet of SPDIFO task
1607 		   is the FG task tree */
1608 		fg_entry->parent_scb_ptr = spdifo_scb_desc;
1609 
1610 		/* for proc fs */
1611 		cs46xx_dsp_proc_register_scb_desc (chip,spdifo_scb_desc);
1612 		cs46xx_dsp_proc_register_scb_desc (chip,spdifi_scb_desc);
1613 		cs46xx_dsp_proc_register_scb_desc (chip,async_codec_scb_desc);
1614 
1615 		/* Async MASTER ENABLE, affects both SPDIF input and output */
1616 		snd_cs46xx_pokeBA0(chip, BA0_ASER_MASTER, 0x1 );
1617 	}
1618 
1619 	return 0;
1620 }
1621 
1622 
1623 static void cs46xx_dsp_disable_spdif_hw (cs46xx_t *chip)
1624 {
1625 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1626 
1627 	/* set SPDIF output FIFO slot */
1628 	snd_cs46xx_pokeBA0(chip, BA0_ASER_FADDR, 0);
1629 
1630 	/* SPDIF output MASTER ENABLE */
1631 	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CONTROL, 0);
1632 
1633 	/* right and left validate bit */
1634 	/*cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);*/
1635 	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, 0x0);
1636 
1637 	/* clear fifo pointer */
1638 	cs46xx_poke_via_dsp (chip,SP_SPDIN_FIFOPTR, 0x0);
1639 
1640 	/* monitor state */
1641 	ins->spdif_status_out &= ~DSP_SPDIF_STATUS_HW_ENABLED;
1642 }
1643 
1644 int cs46xx_dsp_enable_spdif_hw (cs46xx_t *chip)
1645 {
1646 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1647 
1648 	/* if hw-ctrl already enabled, turn off to reset logic ... */
1649 	cs46xx_dsp_disable_spdif_hw (chip);
1650 	udelay(50);
1651 
1652 	/* set SPDIF output FIFO slot */
1653 	snd_cs46xx_pokeBA0(chip, BA0_ASER_FADDR, ( 0x8000 | ((SP_SPDOUT_FIFO >> 4) << 4) ));
1654 
1655 	/* SPDIF output MASTER ENABLE */
1656 	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CONTROL, 0x80000000);
1657 
1658 	/* right and left validate bit */
1659 	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);
1660 
1661 	/* monitor state */
1662 	ins->spdif_status_out |= DSP_SPDIF_STATUS_HW_ENABLED;
1663 
1664 	return 0;
1665 }
1666 
1667 int cs46xx_dsp_enable_spdif_in (cs46xx_t *chip)
1668 {
1669 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1670 
1671 	/* turn on amplifier */
1672 	chip->active_ctrl(chip, 1);
1673 	chip->amplifier_ctrl(chip, 1);
1674 
1675 	snd_assert (ins->asynch_rx_scb == NULL,return -EINVAL);
1676 	snd_assert (ins->spdif_in_src != NULL,return -EINVAL);
1677 
1678 	down(&chip->spos_mutex);
1679 
1680 	if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_INPUT_CTRL_ENABLED) ) {
1681 		/* time countdown enable */
1682 		cs46xx_poke_via_dsp (chip,SP_ASER_COUNTDOWN, 0x80000005);
1683 		/* NOTE: 80000005 value is just magic. With all values
1684 		   that I've tested this one seem to give the best result.
1685 		   Got no explication why. (Benny) */
1686 
1687 		/* SPDIF input MASTER ENABLE */
1688 		cs46xx_poke_via_dsp (chip,SP_SPDIN_CONTROL, 0x800003ff);
1689 
1690 		ins->spdif_status_out |= DSP_SPDIF_STATUS_INPUT_CTRL_ENABLED;
1691 	}
1692 
1693 	/* create and start the asynchronous receiver SCB */
1694 	ins->asynch_rx_scb = cs46xx_dsp_create_asynch_fg_rx_scb(chip,"AsynchFGRxSCB",
1695 								ASYNCRX_SCB_ADDR,
1696 								SPDIFI_SCB_INST,
1697 								SPDIFI_IP_OUTPUT_BUFFER1,
1698 								ins->spdif_in_src,
1699 								SCB_ON_PARENT_SUBLIST_SCB);
1700 
1701 	spin_lock_irq(&chip->reg_lock);
1702 
1703 	/* reset SPDIF input sample buffer pointer */
1704 	/*snd_cs46xx_poke (chip, (SPDIFI_SCB_INST + 0x0c) << 2,
1705 	  (SPDIFI_IP_OUTPUT_BUFFER1 << 0x10) | 0xFFFC);*/
1706 
1707 	/* reset FIFO ptr */
1708 	/*cs46xx_poke_via_dsp (chip,SP_SPDIN_FIFOPTR, 0x0);*/
1709 	cs46xx_src_link(chip,ins->spdif_in_src);
1710 
1711 	/* unmute SRC volume */
1712 	cs46xx_dsp_scb_set_volume (chip,ins->spdif_in_src,0x7fff,0x7fff);
1713 
1714 	spin_unlock_irq(&chip->reg_lock);
1715 
1716 	/* set SPDIF input sample rate and unmute
1717 	   NOTE: only 48khz support for SPDIF input this time */
1718 	/* cs46xx_dsp_set_src_sample_rate(chip,ins->spdif_in_src,48000); */
1719 
1720 	/* monitor state */
1721 	ins->spdif_status_in = 1;
1722 	up(&chip->spos_mutex);
1723 
1724 	return 0;
1725 }
1726 
1727 int cs46xx_dsp_disable_spdif_in (cs46xx_t *chip)
1728 {
1729 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1730 
1731 	snd_assert (ins->asynch_rx_scb != NULL, return -EINVAL);
1732 	snd_assert (ins->spdif_in_src != NULL,return -EINVAL);
1733 
1734 	down(&chip->spos_mutex);
1735 
1736 	/* Remove the asynchronous receiver SCB */
1737 	cs46xx_dsp_remove_scb (chip,ins->asynch_rx_scb);
1738 	ins->asynch_rx_scb = NULL;
1739 
1740 	cs46xx_src_unlink(chip,ins->spdif_in_src);
1741 
1742 	/* monitor state */
1743 	ins->spdif_status_in = 0;
1744 	up(&chip->spos_mutex);
1745 
1746 	/* restore amplifier */
1747 	chip->active_ctrl(chip, -1);
1748 	chip->amplifier_ctrl(chip, -1);
1749 
1750 	return 0;
1751 }
1752 
1753 int cs46xx_dsp_enable_pcm_capture (cs46xx_t *chip)
1754 {
1755 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1756 
1757 	snd_assert (ins->pcm_input == NULL,return -EINVAL);
1758 	snd_assert (ins->ref_snoop_scb != NULL,return -EINVAL);
1759 
1760 	down(&chip->spos_mutex);
1761 	ins->pcm_input = cs46xx_add_record_source(chip,ins->ref_snoop_scb,PCMSERIALIN_PCM_SCB_ADDR,
1762                                                   "PCMSerialInput_Wave");
1763 	up(&chip->spos_mutex);
1764 
1765 	return 0;
1766 }
1767 
1768 int cs46xx_dsp_disable_pcm_capture (cs46xx_t *chip)
1769 {
1770 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1771 
1772 	snd_assert (ins->pcm_input != NULL,return -EINVAL);
1773 
1774 	down(&chip->spos_mutex);
1775 	cs46xx_dsp_remove_scb (chip,ins->pcm_input);
1776 	ins->pcm_input = NULL;
1777 	up(&chip->spos_mutex);
1778 
1779 	return 0;
1780 }
1781 
1782 int cs46xx_dsp_enable_adc_capture (cs46xx_t *chip)
1783 {
1784 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1785 
1786 	snd_assert (ins->adc_input == NULL,return -EINVAL);
1787 	snd_assert (ins->codec_in_scb != NULL,return -EINVAL);
1788 
1789 	down(&chip->spos_mutex);
1790 	ins->adc_input = cs46xx_add_record_source(chip,ins->codec_in_scb,PCMSERIALIN_SCB_ADDR,
1791 						  "PCMSerialInput_ADC");
1792 	up(&chip->spos_mutex);
1793 
1794 	return 0;
1795 }
1796 
1797 int cs46xx_dsp_disable_adc_capture (cs46xx_t *chip)
1798 {
1799 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1800 
1801 	snd_assert (ins->adc_input != NULL,return -EINVAL);
1802 
1803 	down(&chip->spos_mutex);
1804 	cs46xx_dsp_remove_scb (chip,ins->adc_input);
1805 	ins->adc_input = NULL;
1806 	up(&chip->spos_mutex);
1807 
1808 	return 0;
1809 }
1810 
1811 int cs46xx_poke_via_dsp (cs46xx_t *chip,u32 address,u32 data)
1812 {
1813 	u32 temp;
1814 	int  i;
1815 
1816 	/* santiy check the parameters.  (These numbers are not 100% correct.  They are
1817 	   a rough guess from looking at the controller spec.) */
1818 	if (address < 0x8000 || address >= 0x9000)
1819 		return -EINVAL;
1820 
1821 	/* initialize the SP_IO_WRITE SCB with the data. */
1822 	temp = ( address << 16 ) | ( address & 0x0000FFFF);   /* offset 0 <-- address2 : address1 */
1823 
1824 	snd_cs46xx_poke(chip,( SPIOWRITE_SCB_ADDR      << 2), temp);
1825 	snd_cs46xx_poke(chip,((SPIOWRITE_SCB_ADDR + 1) << 2), data); /* offset 1 <-- data1 */
1826 	snd_cs46xx_poke(chip,((SPIOWRITE_SCB_ADDR + 2) << 2), data); /* offset 1 <-- data2 */
1827 
1828 	/* Poke this location to tell the task to start */
1829 	snd_cs46xx_poke(chip,((SPIOWRITE_SCB_ADDR + 6) << 2), SPIOWRITE_SCB_ADDR << 0x10);
1830 
1831 	/* Verify that the task ran */
1832 	for (i=0; i<25; i++) {
1833 		udelay(125);
1834 
1835 		temp =  snd_cs46xx_peek(chip,((SPIOWRITE_SCB_ADDR + 6) << 2));
1836 		if (temp == 0x00000000)
1837 			break;
1838 	}
1839 
1840 	if (i == 25) {
1841 		snd_printk(KERN_ERR "dsp_spos: SPIOWriteTask not responding\n");
1842 		return -EBUSY;
1843 	}
1844 
1845 	return 0;
1846 }
1847 
1848 int cs46xx_dsp_set_dac_volume (cs46xx_t * chip,u16 left,u16 right)
1849 {
1850 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1851 	dsp_scb_descriptor_t * scb;
1852 
1853 	down(&chip->spos_mutex);
1854 
1855 	/* main output */
1856 	scb = ins->master_mix_scb->sub_list_ptr;
1857 	while (scb != ins->the_null_scb) {
1858 		cs46xx_dsp_scb_set_volume (chip,scb,left,right);
1859 		scb = scb->next_scb_ptr;
1860 	}
1861 
1862 	/* rear output */
1863 	scb = ins->rear_mix_scb->sub_list_ptr;
1864 	while (scb != ins->the_null_scb) {
1865 		cs46xx_dsp_scb_set_volume (chip,scb,left,right);
1866 		scb = scb->next_scb_ptr;
1867 	}
1868 
1869 	ins->dac_volume_left = left;
1870 	ins->dac_volume_right = right;
1871 
1872 	up(&chip->spos_mutex);
1873 
1874 	return 0;
1875 }
1876 
1877 int cs46xx_dsp_set_iec958_volume (cs46xx_t * chip,u16 left,u16 right) {
1878 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1879 
1880 	down(&chip->spos_mutex);
1881 
1882 	if (ins->asynch_rx_scb != NULL)
1883 		cs46xx_dsp_scb_set_volume (chip,ins->asynch_rx_scb,
1884 					   left,right);
1885 
1886 	ins->spdif_input_volume_left = left;
1887 	ins->spdif_input_volume_right = right;
1888 
1889 	up(&chip->spos_mutex);
1890 
1891 	return 0;
1892 }
1893