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