Linux-2.6.12-rc2
[linux-flexiantxendom0-natty.git] / sound / pci / cs46xx / dsp_spos.c
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 }