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