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