Linux 2.6.31.8
[linux/fpc-iii.git] / sound / pci / cs46xx / dsp_spos_scb_lib.c
blobdd7c41b037b45e0700c55db9e32851a04e34ef55
1 /*
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.
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.
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
20 * 2002-07 Benny Sjostrand benny@hostmobility.com
24 #include <asm/io.h>
25 #include <linux/delay.h>
26 #include <linux/pm.h>
27 #include <linux/init.h>
28 #include <linux/slab.h>
29 #include <linux/mutex.h>
31 #include <sound/core.h>
32 #include <sound/control.h>
33 #include <sound/info.h>
34 #include <sound/cs46xx.h>
36 #include "cs46xx_lib.h"
37 #include "dsp_spos.h"
39 struct proc_scb_info {
40 struct dsp_scb_descriptor * scb_desc;
41 struct snd_cs46xx *chip;
44 static void remove_symbol (struct snd_cs46xx * chip, struct dsp_symbol_entry * symbol)
46 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
47 int symbol_index = (int)(symbol - ins->symbol_table.symbols);
49 if (snd_BUG_ON(ins->symbol_table.nsymbols <= 0))
50 return;
51 if (snd_BUG_ON(symbol_index < 0 ||
52 symbol_index >= ins->symbol_table.nsymbols))
53 return;
55 ins->symbol_table.symbols[symbol_index].deleted = 1;
57 if (symbol_index < ins->symbol_table.highest_frag_index) {
58 ins->symbol_table.highest_frag_index = symbol_index;
61 if (symbol_index == ins->symbol_table.nsymbols - 1)
62 ins->symbol_table.nsymbols --;
64 if (ins->symbol_table.highest_frag_index > ins->symbol_table.nsymbols) {
65 ins->symbol_table.highest_frag_index = ins->symbol_table.nsymbols;
70 #ifdef CONFIG_PROC_FS
71 static void cs46xx_dsp_proc_scb_info_read (struct snd_info_entry *entry,
72 struct snd_info_buffer *buffer)
74 struct proc_scb_info * scb_info = entry->private_data;
75 struct dsp_scb_descriptor * scb = scb_info->scb_desc;
76 struct dsp_spos_instance * ins;
77 struct snd_cs46xx *chip = scb_info->chip;
78 int j,col;
79 void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
81 ins = chip->dsp_spos_instance;
83 mutex_lock(&chip->spos_mutex);
84 snd_iprintf(buffer,"%04x %s:\n",scb->address,scb->scb_name);
86 for (col = 0,j = 0;j < 0x10; j++,col++) {
87 if (col == 4) {
88 snd_iprintf(buffer,"\n");
89 col = 0;
91 snd_iprintf(buffer,"%08x ",readl(dst + (scb->address + j) * sizeof(u32)));
94 snd_iprintf(buffer,"\n");
96 if (scb->parent_scb_ptr != NULL) {
97 snd_iprintf(buffer,"parent [%s:%04x] ",
98 scb->parent_scb_ptr->scb_name,
99 scb->parent_scb_ptr->address);
100 } else snd_iprintf(buffer,"parent [none] ");
102 snd_iprintf(buffer,"sub_list_ptr [%s:%04x]\nnext_scb_ptr [%s:%04x] task_entry [%s:%04x]\n",
103 scb->sub_list_ptr->scb_name,
104 scb->sub_list_ptr->address,
105 scb->next_scb_ptr->scb_name,
106 scb->next_scb_ptr->address,
107 scb->task_entry->symbol_name,
108 scb->task_entry->address);
110 snd_iprintf(buffer,"index [%d] ref_count [%d]\n",scb->index,scb->ref_count);
111 mutex_unlock(&chip->spos_mutex);
113 #endif
115 static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
117 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
118 unsigned long flags;
120 if ( scb->parent_scb_ptr ) {
121 /* unlink parent SCB */
122 if (snd_BUG_ON(scb->parent_scb_ptr->sub_list_ptr != scb &&
123 scb->parent_scb_ptr->next_scb_ptr != scb))
124 return;
126 if (scb->parent_scb_ptr->sub_list_ptr == scb) {
128 if (scb->next_scb_ptr == ins->the_null_scb) {
129 /* last and only node in parent sublist */
130 scb->parent_scb_ptr->sub_list_ptr = scb->sub_list_ptr;
132 if (scb->sub_list_ptr != ins->the_null_scb) {
133 scb->sub_list_ptr->parent_scb_ptr = scb->parent_scb_ptr;
135 scb->sub_list_ptr = ins->the_null_scb;
136 } else {
137 /* first node in parent sublist */
138 scb->parent_scb_ptr->sub_list_ptr = scb->next_scb_ptr;
140 if (scb->next_scb_ptr != ins->the_null_scb) {
141 /* update next node parent ptr. */
142 scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
144 scb->next_scb_ptr = ins->the_null_scb;
146 } else {
147 scb->parent_scb_ptr->next_scb_ptr = scb->next_scb_ptr;
149 if (scb->next_scb_ptr != ins->the_null_scb) {
150 /* update next node parent ptr. */
151 scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
153 scb->next_scb_ptr = ins->the_null_scb;
156 spin_lock_irqsave(&chip->reg_lock, flags);
158 /* update parent first entry in DSP RAM */
159 cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
161 /* then update entry in DSP RAM */
162 cs46xx_dsp_spos_update_scb(chip,scb);
164 scb->parent_scb_ptr = NULL;
165 spin_unlock_irqrestore(&chip->reg_lock, flags);
169 static void _dsp_clear_sample_buffer (struct snd_cs46xx *chip, u32 sample_buffer_addr,
170 int dword_count)
172 void __iomem *dst = chip->region.idx[2].remap_addr + sample_buffer_addr;
173 int i;
175 for (i = 0; i < dword_count ; ++i ) {
176 writel(0, dst);
177 dst += 4;
181 void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
183 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
184 unsigned long flags;
186 /* check integrety */
187 if (snd_BUG_ON(scb->index < 0 ||
188 scb->index >= ins->nscb ||
189 (ins->scbs + scb->index) != scb))
190 return;
192 #if 0
193 /* can't remove a SCB with childs before
194 removing childs first */
195 if (snd_BUG_ON(scb->sub_list_ptr != ins->the_null_scb ||
196 scb->next_scb_ptr != ins->the_null_scb))
197 goto _end;
198 #endif
200 spin_lock_irqsave(&scb->lock, flags);
201 _dsp_unlink_scb (chip,scb);
202 spin_unlock_irqrestore(&scb->lock, flags);
204 cs46xx_dsp_proc_free_scb_desc(scb);
205 if (snd_BUG_ON(!scb->scb_symbol))
206 return;
207 remove_symbol (chip,scb->scb_symbol);
209 ins->scbs[scb->index].deleted = 1;
211 if (scb->index < ins->scb_highest_frag_index)
212 ins->scb_highest_frag_index = scb->index;
214 if (scb->index == ins->nscb - 1) {
215 ins->nscb --;
218 if (ins->scb_highest_frag_index > ins->nscb) {
219 ins->scb_highest_frag_index = ins->nscb;
222 #if 0
223 /* !!!! THIS IS A PIECE OF SHIT MADE BY ME !!! */
224 for(i = scb->index + 1;i < ins->nscb; ++i) {
225 ins->scbs[i - 1].index = i - 1;
227 #endif
231 #ifdef CONFIG_PROC_FS
232 void cs46xx_dsp_proc_free_scb_desc (struct dsp_scb_descriptor * scb)
234 if (scb->proc_info) {
235 struct proc_scb_info * scb_info = scb->proc_info->private_data;
237 snd_printdd("cs46xx_dsp_proc_free_scb_desc: freeing %s\n",scb->scb_name);
239 snd_info_free_entry(scb->proc_info);
240 scb->proc_info = NULL;
242 kfree (scb_info);
246 void cs46xx_dsp_proc_register_scb_desc (struct snd_cs46xx *chip,
247 struct dsp_scb_descriptor * scb)
249 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
250 struct snd_info_entry * entry;
251 struct proc_scb_info * scb_info;
253 /* register to proc */
254 if (ins->snd_card != NULL && ins->proc_dsp_dir != NULL &&
255 scb->proc_info == NULL) {
257 if ((entry = snd_info_create_card_entry(ins->snd_card, scb->scb_name,
258 ins->proc_dsp_dir)) != NULL) {
259 scb_info = kmalloc(sizeof(struct proc_scb_info), GFP_KERNEL);
260 if (!scb_info) {
261 snd_info_free_entry(entry);
262 entry = NULL;
263 goto out;
266 scb_info->chip = chip;
267 scb_info->scb_desc = scb;
269 entry->content = SNDRV_INFO_CONTENT_TEXT;
270 entry->private_data = scb_info;
271 entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
273 entry->c.text.read = cs46xx_dsp_proc_scb_info_read;
275 if (snd_info_register(entry) < 0) {
276 snd_info_free_entry(entry);
277 kfree (scb_info);
278 entry = NULL;
281 out:
282 scb->proc_info = entry;
285 #endif /* CONFIG_PROC_FS */
287 static struct dsp_scb_descriptor *
288 _dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32 dest,
289 struct dsp_symbol_entry * task_entry,
290 struct dsp_scb_descriptor * parent_scb,
291 int scb_child_type)
293 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
294 struct dsp_scb_descriptor * scb;
296 unsigned long flags;
298 if (snd_BUG_ON(!ins->the_null_scb))
299 return NULL;
301 /* fill the data that will be wroten to DSP */
302 scb_data[SCBsubListPtr] =
303 (ins->the_null_scb->address << 0x10) | ins->the_null_scb->address;
305 scb_data[SCBfuncEntryPtr] &= 0xFFFF0000;
306 scb_data[SCBfuncEntryPtr] |= task_entry->address;
308 snd_printdd("dsp_spos: creating SCB <%s>\n",name);
310 scb = cs46xx_dsp_create_scb(chip,name,scb_data,dest);
313 scb->sub_list_ptr = ins->the_null_scb;
314 scb->next_scb_ptr = ins->the_null_scb;
316 scb->parent_scb_ptr = parent_scb;
317 scb->task_entry = task_entry;
320 /* update parent SCB */
321 if (scb->parent_scb_ptr) {
322 #if 0
323 printk ("scb->parent_scb_ptr = %s\n",scb->parent_scb_ptr->scb_name);
324 printk ("scb->parent_scb_ptr->next_scb_ptr = %s\n",scb->parent_scb_ptr->next_scb_ptr->scb_name);
325 printk ("scb->parent_scb_ptr->sub_list_ptr = %s\n",scb->parent_scb_ptr->sub_list_ptr->scb_name);
326 #endif
327 /* link to parent SCB */
328 if (scb_child_type == SCB_ON_PARENT_NEXT_SCB) {
329 if (snd_BUG_ON(scb->parent_scb_ptr->next_scb_ptr !=
330 ins->the_null_scb))
331 return NULL;
333 scb->parent_scb_ptr->next_scb_ptr = scb;
335 } else if (scb_child_type == SCB_ON_PARENT_SUBLIST_SCB) {
336 if (snd_BUG_ON(scb->parent_scb_ptr->sub_list_ptr !=
337 ins->the_null_scb))
338 return NULL;
340 scb->parent_scb_ptr->sub_list_ptr = scb;
341 } else {
342 snd_BUG();
345 spin_lock_irqsave(&chip->reg_lock, flags);
347 /* update entry in DSP RAM */
348 cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
350 spin_unlock_irqrestore(&chip->reg_lock, flags);
354 cs46xx_dsp_proc_register_scb_desc (chip,scb);
356 return scb;
359 static struct dsp_scb_descriptor *
360 cs46xx_dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data,
361 u32 dest, char * task_entry_name,
362 struct dsp_scb_descriptor * parent_scb,
363 int scb_child_type)
365 struct dsp_symbol_entry * task_entry;
367 task_entry = cs46xx_dsp_lookup_symbol (chip,task_entry_name,
368 SYMBOL_CODE);
370 if (task_entry == NULL) {
371 snd_printk (KERN_ERR "dsp_spos: symbol %s not found\n",task_entry_name);
372 return NULL;
375 return _dsp_create_generic_scb (chip,name,scb_data,dest,task_entry,
376 parent_scb,scb_child_type);
379 struct dsp_scb_descriptor *
380 cs46xx_dsp_create_timing_master_scb (struct snd_cs46xx *chip)
382 struct dsp_scb_descriptor * scb;
384 struct dsp_timing_master_scb timing_master_scb = {
385 { 0,
390 { 0,
396 0,0,
397 0,NULL_SCB_ADDR,
398 0,0, /* extraSampleAccum:TMreserved */
399 0,0, /* codecFIFOptr:codecFIFOsyncd */
400 0x0001,0x8000, /* fracSampAccumQm1:TMfrmsLeftInGroup */
401 0x0001,0x0000, /* fracSampCorrectionQm1:TMfrmGroupLength */
402 0x00060000 /* nSampPerFrmQ15 */
405 scb = cs46xx_dsp_create_generic_scb(chip,"TimingMasterSCBInst",(u32 *)&timing_master_scb,
406 TIMINGMASTER_SCB_ADDR,
407 "TIMINGMASTER",NULL,SCB_NO_PARENT);
409 return scb;
413 struct dsp_scb_descriptor *
414 cs46xx_dsp_create_codec_out_scb(struct snd_cs46xx * chip, char * codec_name,
415 u16 channel_disp, u16 fifo_addr, u16 child_scb_addr,
416 u32 dest, struct dsp_scb_descriptor * parent_scb,
417 int scb_child_type)
419 struct dsp_scb_descriptor * scb;
421 struct dsp_codec_output_scb codec_out_scb = {
422 { 0,
434 0,0,
435 0,NULL_SCB_ADDR,
436 0, /* COstrmRsConfig */
437 0, /* COstrmBufPtr */
438 channel_disp,fifo_addr, /* leftChanBaseIOaddr:rightChanIOdisp */
439 0x0000,0x0080, /* (!AC97!) COexpVolChangeRate:COscaleShiftCount */
440 0,child_scb_addr /* COreserved - need child scb to work with rom code */
444 scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_out_scb,
445 dest,"S16_CODECOUTPUTTASK",parent_scb,
446 scb_child_type);
448 return scb;
451 struct dsp_scb_descriptor *
452 cs46xx_dsp_create_codec_in_scb(struct snd_cs46xx * chip, char * codec_name,
453 u16 channel_disp, u16 fifo_addr, u16 sample_buffer_addr,
454 u32 dest, struct dsp_scb_descriptor * parent_scb,
455 int scb_child_type)
458 struct dsp_scb_descriptor * scb;
459 struct dsp_codec_input_scb codec_input_scb = {
460 { 0,
473 #if 0 /* cs4620 */
474 SyncIOSCB,NULL_SCB_ADDR
475 #else
476 0 , 0,
477 #endif
478 0,0,
480 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64, /* strmRsConfig */
481 sample_buffer_addr << 0x10, /* strmBufPtr; defined as a dword ptr, used as a byte ptr */
482 channel_disp,fifo_addr, /* (!AC97!) leftChanBaseINaddr=AC97primary
483 link input slot 3 :rightChanINdisp=""slot 4 */
484 0x0000,0x0000, /* (!AC97!) ????:scaleShiftCount; no shift needed
485 because AC97 is already 20 bits */
486 0x80008000 /* ??clw cwcgame.scb has 0 */
489 scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_input_scb,
490 dest,"S16_CODECINPUTTASK",parent_scb,
491 scb_child_type);
492 return scb;
496 static struct dsp_scb_descriptor *
497 cs46xx_dsp_create_pcm_reader_scb(struct snd_cs46xx * chip, char * scb_name,
498 u16 sample_buffer_addr, u32 dest,
499 int virtual_channel, u32 playback_hw_addr,
500 struct dsp_scb_descriptor * parent_scb,
501 int scb_child_type)
503 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
504 struct dsp_scb_descriptor * scb;
506 struct dsp_generic_scb pcm_reader_scb = {
509 Play DMA Task xfers data from host buffer to SP buffer
510 init/runtime variables:
511 PlayAC: Play Audio Data Conversion - SCB loc: 2nd dword, mask: 0x0000F000L
512 DATA_FMT_16BIT_ST_LTLEND(0x00000000L) from 16-bit stereo, little-endian
513 DATA_FMT_8_BIT_ST_SIGNED(0x00001000L) from 8-bit stereo, signed
514 DATA_FMT_16BIT_MN_LTLEND(0x00002000L) from 16-bit mono, little-endian
515 DATA_FMT_8_BIT_MN_SIGNED(0x00003000L) from 8-bit mono, signed
516 DATA_FMT_16BIT_ST_BIGEND(0x00004000L) from 16-bit stereo, big-endian
517 DATA_FMT_16BIT_MN_BIGEND(0x00006000L) from 16-bit mono, big-endian
518 DATA_FMT_8_BIT_ST_UNSIGNED(0x00009000L) from 8-bit stereo, unsigned
519 DATA_FMT_8_BIT_MN_UNSIGNED(0x0000b000L) from 8-bit mono, unsigned
520 ? Other combinations possible from:
521 DMA_RQ_C2_AUDIO_CONVERT_MASK 0x0000F000L
522 DMA_RQ_C2_AC_NONE 0x00000000L
523 DMA_RQ_C2_AC_8_TO_16_BIT 0x00001000L
524 DMA_RQ_C2_AC_MONO_TO_STEREO 0x00002000L
525 DMA_RQ_C2_AC_ENDIAN_CONVERT 0x00004000L
526 DMA_RQ_C2_AC_SIGNED_CONVERT 0x00008000L
528 HostBuffAddr: Host Buffer Physical Byte Address - SCB loc:3rd dword, Mask: 0xFFFFFFFFL
529 aligned to dword boundary
531 /* Basic (non scatter/gather) DMA requestor (4 ints) */
532 { DMA_RQ_C1_SOURCE_ON_HOST + /* source buffer is on the host */
533 DMA_RQ_C1_SOURCE_MOD1024 + /* source buffer is 1024 dwords (4096 bytes) */
534 DMA_RQ_C1_DEST_MOD32 + /* dest buffer(PCMreaderBuf) is 32 dwords*/
535 DMA_RQ_C1_WRITEBACK_SRC_FLAG + /* ?? */
536 DMA_RQ_C1_WRITEBACK_DEST_FLAG + /* ?? */
537 15, /* DwordCount-1: picked 16 for DwordCount because Jim */
538 /* Barnette said that is what we should use since */
539 /* we are not running in optimized mode? */
540 DMA_RQ_C2_AC_NONE +
541 DMA_RQ_C2_SIGNAL_SOURCE_PINGPONG + /* set play interrupt (bit0) in HISR when source */
542 /* buffer (on host) crosses half-way point */
543 virtual_channel, /* Play DMA channel arbitrarily set to 0 */
544 playback_hw_addr, /* HostBuffAddr (source) */
545 DMA_RQ_SD_SP_SAMPLE_ADDR + /* destination buffer is in SP Sample Memory */
546 sample_buffer_addr /* SP Buffer Address (destination) */
548 /* Scatter/gather DMA requestor extension (5 ints) */
556 /* Sublist pointer & next stream control block (SCB) link. */
557 NULL_SCB_ADDR,NULL_SCB_ADDR,
558 /* Pointer to this tasks parameter block & stream function pointer */
559 0,NULL_SCB_ADDR,
560 /* rsConfig register for stream buffer (rsDMA reg. is loaded from basicReq.daw */
561 /* for incoming streams, or basicReq.saw, for outgoing streams) */
562 RSCONFIG_DMA_ENABLE + /* enable DMA */
563 (19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) + /* MAX_DMA_SIZE picked to be 19 since SPUD */
564 /* uses it for some reason */
565 ((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) + /* stream number = SCBaddr/16 */
566 RSCONFIG_SAMPLE_16STEREO +
567 RSCONFIG_MODULO_32, /* dest buffer(PCMreaderBuf) is 32 dwords (256 bytes) */
568 /* Stream sample pointer & MAC-unit mode for this stream */
569 (sample_buffer_addr << 0x10),
570 /* Fractional increment per output sample in the input sample buffer */
573 /* Standard stereo volume control
574 default muted */
575 0xffff,0xffff,
576 0xffff,0xffff
580 if (ins->null_algorithm == NULL) {
581 ins->null_algorithm = cs46xx_dsp_lookup_symbol (chip,"NULLALGORITHM",
582 SYMBOL_CODE);
584 if (ins->null_algorithm == NULL) {
585 snd_printk (KERN_ERR "dsp_spos: symbol NULLALGORITHM not found\n");
586 return NULL;
590 scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_reader_scb,
591 dest,ins->null_algorithm,parent_scb,
592 scb_child_type);
594 return scb;
597 #define GOF_PER_SEC 200
599 struct dsp_scb_descriptor *
600 cs46xx_dsp_create_src_task_scb(struct snd_cs46xx * chip, char * scb_name,
601 int rate,
602 u16 src_buffer_addr,
603 u16 src_delay_buffer_addr, u32 dest,
604 struct dsp_scb_descriptor * parent_scb,
605 int scb_child_type,
606 int pass_through)
609 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
610 struct dsp_scb_descriptor * scb;
611 unsigned int tmp1, tmp2;
612 unsigned int phiIncr;
613 unsigned int correctionPerGOF, correctionPerSec;
615 snd_printdd( "dsp_spos: setting %s rate to %u\n",scb_name,rate);
618 * Compute the values used to drive the actual sample rate conversion.
619 * The following formulas are being computed, using inline assembly
620 * since we need to use 64 bit arithmetic to compute the values:
622 * phiIncr = floor((Fs,in * 2^26) / Fs,out)
623 * correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) /
624 * GOF_PER_SEC)
625 * ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -M
626 * GOF_PER_SEC * correctionPerGOF
628 * i.e.
630 * phiIncr:other = dividend:remainder((Fs,in * 2^26) / Fs,out)
631 * correctionPerGOF:correctionPerSec =
632 * dividend:remainder(ulOther / GOF_PER_SEC)
634 tmp1 = rate << 16;
635 phiIncr = tmp1 / 48000;
636 tmp1 -= phiIncr * 48000;
637 tmp1 <<= 10;
638 phiIncr <<= 10;
639 tmp2 = tmp1 / 48000;
640 phiIncr += tmp2;
641 tmp1 -= tmp2 * 48000;
642 correctionPerGOF = tmp1 / GOF_PER_SEC;
643 tmp1 -= correctionPerGOF * GOF_PER_SEC;
644 correctionPerSec = tmp1;
647 struct dsp_src_task_scb src_task_scb = {
648 0x0028,0x00c8,
649 0x5555,0x0000,
650 0x0000,0x0000,
651 src_buffer_addr,1,
652 correctionPerGOF,correctionPerSec,
653 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
654 0x0000,src_delay_buffer_addr,
655 0x0,
656 0x080,(src_delay_buffer_addr + (24 * 4)),
657 0,0, /* next_scb, sub_list_ptr */
658 0,0, /* entry, this_spb */
659 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
660 src_buffer_addr << 0x10,
661 phiIncr,
663 0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left,
664 0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left
668 if (ins->s16_up == NULL) {
669 ins->s16_up = cs46xx_dsp_lookup_symbol (chip,"S16_UPSRC",
670 SYMBOL_CODE);
672 if (ins->s16_up == NULL) {
673 snd_printk (KERN_ERR "dsp_spos: symbol S16_UPSRC not found\n");
674 return NULL;
678 /* clear buffers */
679 _dsp_clear_sample_buffer (chip,src_buffer_addr,8);
680 _dsp_clear_sample_buffer (chip,src_delay_buffer_addr,32);
682 if (pass_through) {
683 /* wont work with any other rate than
684 the native DSP rate */
685 snd_BUG_ON(rate != 48000);
687 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
688 dest,"DMAREADER",parent_scb,
689 scb_child_type);
690 } else {
691 scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
692 dest,ins->s16_up,parent_scb,
693 scb_child_type);
699 return scb;
702 #if 0 /* not used */
703 struct dsp_scb_descriptor *
704 cs46xx_dsp_create_filter_scb(struct snd_cs46xx * chip, char * scb_name,
705 u16 buffer_addr, u32 dest,
706 struct dsp_scb_descriptor * parent_scb,
707 int scb_child_type) {
708 struct dsp_scb_descriptor * scb;
710 struct dsp_filter_scb filter_scb = {
711 .a0_right = 0x41a9,
712 .a0_left = 0x41a9,
713 .a1_right = 0xb8e4,
714 .a1_left = 0xb8e4,
715 .a2_right = 0x3e55,
716 .a2_left = 0x3e55,
718 .filter_unused3 = 0x0000,
719 .filter_unused2 = 0x0000,
721 .output_buf_ptr = buffer_addr,
722 .init = 0x000,
724 .prev_sample_output1 = 0x00000000,
725 .prev_sample_output2 = 0x00000000,
727 .prev_sample_input1 = 0x00000000,
728 .prev_sample_input2 = 0x00000000,
730 .next_scb_ptr = 0x0000,
731 .sub_list_ptr = 0x0000,
733 .entry_point = 0x0000,
734 .spb_ptr = 0x0000,
736 .b0_right = 0x0e38,
737 .b0_left = 0x0e38,
738 .b1_right = 0x1c71,
739 .b1_left = 0x1c71,
740 .b2_right = 0x0e38,
741 .b2_left = 0x0e38,
745 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&filter_scb,
746 dest,"FILTERTASK",parent_scb,
747 scb_child_type);
749 return scb;
751 #endif /* not used */
753 struct dsp_scb_descriptor *
754 cs46xx_dsp_create_mix_only_scb(struct snd_cs46xx * chip, char * scb_name,
755 u16 mix_buffer_addr, u32 dest,
756 struct dsp_scb_descriptor * parent_scb,
757 int scb_child_type)
759 struct dsp_scb_descriptor * scb;
761 struct dsp_mix_only_scb master_mix_scb = {
762 /* 0 */ { 0,
763 /* 1 */ 0,
764 /* 2 */ mix_buffer_addr,
765 /* 3 */ 0
766 /* */ },
768 /* 4 */ 0,
769 /* 5 */ 0,
770 /* 6 */ 0,
771 /* 7 */ 0,
772 /* 8 */ 0x00000080
774 /* 9 */ 0,0,
775 /* A */ 0,0,
776 /* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
777 /* C */ (mix_buffer_addr + (16 * 4)) << 0x10,
778 /* D */ 0,
780 /* E */ 0x8000,0x8000,
781 /* F */ 0x8000,0x8000
786 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&master_mix_scb,
787 dest,"S16_MIX",parent_scb,
788 scb_child_type);
789 return scb;
793 struct dsp_scb_descriptor *
794 cs46xx_dsp_create_mix_to_ostream_scb(struct snd_cs46xx * chip, char * scb_name,
795 u16 mix_buffer_addr, u16 writeback_spb, u32 dest,
796 struct dsp_scb_descriptor * parent_scb,
797 int scb_child_type)
799 struct dsp_scb_descriptor * scb;
801 struct dsp_mix2_ostream_scb mix2_ostream_scb = {
802 /* Basic (non scatter/gather) DMA requestor (4 ints) */
804 DMA_RQ_C1_SOURCE_MOD64 +
805 DMA_RQ_C1_DEST_ON_HOST +
806 DMA_RQ_C1_DEST_MOD1024 +
807 DMA_RQ_C1_WRITEBACK_SRC_FLAG +
808 DMA_RQ_C1_WRITEBACK_DEST_FLAG +
809 15,
811 DMA_RQ_C2_AC_NONE +
812 DMA_RQ_C2_SIGNAL_DEST_PINGPONG +
814 CS46XX_DSP_CAPTURE_CHANNEL,
815 DMA_RQ_SD_SP_SAMPLE_ADDR +
816 mix_buffer_addr,
817 0x0
820 { 0, 0, 0, 0, 0, },
821 0,0,
822 0,writeback_spb,
824 RSCONFIG_DMA_ENABLE +
825 (19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) +
827 ((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) +
828 RSCONFIG_DMA_TO_HOST +
829 RSCONFIG_SAMPLE_16STEREO +
830 RSCONFIG_MODULO_64,
831 (mix_buffer_addr + (32 * 4)) << 0x10,
832 1,0,
833 0x0001,0x0080,
834 0xFFFF,0
838 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&mix2_ostream_scb,
840 dest,"S16_MIX_TO_OSTREAM",parent_scb,
841 scb_child_type);
843 return scb;
847 struct dsp_scb_descriptor *
848 cs46xx_dsp_create_vari_decimate_scb(struct snd_cs46xx * chip,char * scb_name,
849 u16 vari_buffer_addr0,
850 u16 vari_buffer_addr1,
851 u32 dest,
852 struct dsp_scb_descriptor * parent_scb,
853 int scb_child_type)
856 struct dsp_scb_descriptor * scb;
858 struct dsp_vari_decimate_scb vari_decimate_scb = {
859 0x0028,0x00c8,
860 0x5555,0x0000,
861 0x0000,0x0000,
862 vari_buffer_addr0,vari_buffer_addr1,
864 0x0028,0x00c8,
865 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256,
867 0xFF800000,
869 0x0080,vari_buffer_addr1 + (25 * 4),
871 0,0,
872 0,0,
874 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
875 vari_buffer_addr0 << 0x10,
876 0x04000000,
878 0x8000,0x8000,
879 0xFFFF,0xFFFF
883 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&vari_decimate_scb,
884 dest,"VARIDECIMATE",parent_scb,
885 scb_child_type);
887 return scb;
891 static struct dsp_scb_descriptor *
892 cs46xx_dsp_create_pcm_serial_input_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
893 struct dsp_scb_descriptor * input_scb,
894 struct dsp_scb_descriptor * parent_scb,
895 int scb_child_type)
898 struct dsp_scb_descriptor * scb;
901 struct dsp_pcm_serial_input_scb pcm_serial_input_scb = {
902 { 0,
915 0,0,
916 0,0,
918 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_16,
920 /* 0xD */ 0,input_scb->address,
922 /* 0xE */ 0x8000,0x8000,
923 /* 0xF */ 0x8000,0x8000
927 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_serial_input_scb,
928 dest,"PCMSERIALINPUTTASK",parent_scb,
929 scb_child_type);
930 return scb;
934 static struct dsp_scb_descriptor *
935 cs46xx_dsp_create_asynch_fg_tx_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
936 u16 hfg_scb_address,
937 u16 asynch_buffer_address,
938 struct dsp_scb_descriptor * parent_scb,
939 int scb_child_type)
942 struct dsp_scb_descriptor * scb;
944 struct dsp_asynch_fg_tx_scb asynch_fg_tx_scb = {
945 0xfc00,0x03ff, /* Prototype sample buffer size of 256 dwords */
946 0x0058,0x0028, /* Min Delta 7 dwords == 28 bytes */
947 /* : Max delta 25 dwords == 100 bytes */
948 0,hfg_scb_address, /* Point to HFG task SCB */
949 0,0, /* Initialize current Delta and Consumer ptr adjustment count */
950 0, /* Initialize accumulated Phi to 0 */
951 0,0x2aab, /* Const 1/3 */
954 0, /* Define the unused elements */
959 0,0,
960 0,dest + AFGTxAccumPhi,
962 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256, /* Stereo, 256 dword */
963 (asynch_buffer_address) << 0x10, /* This should be automagically synchronized
964 to the producer pointer */
966 /* There is no correct initial value, it will depend upon the detected
967 rate etc */
968 0x18000000, /* Phi increment for approx 32k operation */
969 0x8000,0x8000, /* Volume controls are unused at this time */
970 0x8000,0x8000
973 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_tx_scb,
974 dest,"ASYNCHFGTXCODE",parent_scb,
975 scb_child_type);
977 return scb;
981 struct dsp_scb_descriptor *
982 cs46xx_dsp_create_asynch_fg_rx_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
983 u16 hfg_scb_address,
984 u16 asynch_buffer_address,
985 struct dsp_scb_descriptor * parent_scb,
986 int scb_child_type)
988 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
989 struct dsp_scb_descriptor * scb;
991 struct dsp_asynch_fg_rx_scb asynch_fg_rx_scb = {
992 0xfe00,0x01ff, /* Prototype sample buffer size of 128 dwords */
993 0x0064,0x001c, /* Min Delta 7 dwords == 28 bytes */
994 /* : Max delta 25 dwords == 100 bytes */
995 0,hfg_scb_address, /* Point to HFG task SCB */
996 0,0, /* Initialize current Delta and Consumer ptr adjustment count */
998 0, /* Define the unused elements */
1005 0,0,
1006 0,dest,
1008 RSCONFIG_MODULO_128 |
1009 RSCONFIG_SAMPLE_16STEREO, /* Stereo, 128 dword */
1010 ( (asynch_buffer_address + (16 * 4)) << 0x10), /* This should be automagically
1011 synchrinized to the producer pointer */
1013 /* There is no correct initial value, it will depend upon the detected
1014 rate etc */
1015 0x18000000,
1017 /* Set IEC958 input volume */
1018 0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
1019 0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
1022 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_rx_scb,
1023 dest,"ASYNCHFGRXCODE",parent_scb,
1024 scb_child_type);
1026 return scb;
1030 #if 0 /* not used */
1031 struct dsp_scb_descriptor *
1032 cs46xx_dsp_create_output_snoop_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1033 u16 snoop_buffer_address,
1034 struct dsp_scb_descriptor * snoop_scb,
1035 struct dsp_scb_descriptor * parent_scb,
1036 int scb_child_type)
1039 struct dsp_scb_descriptor * scb;
1041 struct dsp_output_snoop_scb output_snoop_scb = {
1042 { 0, /* not used. Zero */
1048 0, /* not used. Zero */
1055 0,0,
1056 0,0,
1058 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
1059 snoop_buffer_address << 0x10,
1060 0,0,
1062 0,snoop_scb->address
1065 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&output_snoop_scb,
1066 dest,"OUTPUTSNOOP",parent_scb,
1067 scb_child_type);
1068 return scb;
1070 #endif /* not used */
1073 struct dsp_scb_descriptor *
1074 cs46xx_dsp_create_spio_write_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1075 struct dsp_scb_descriptor * parent_scb,
1076 int scb_child_type)
1078 struct dsp_scb_descriptor * scb;
1080 struct dsp_spio_write_scb spio_write_scb = {
1081 0,0, /* SPIOWAddress2:SPIOWAddress1; */
1082 0, /* SPIOWData1; */
1083 0, /* SPIOWData2; */
1084 0,0, /* SPIOWAddress4:SPIOWAddress3; */
1085 0, /* SPIOWData3; */
1086 0, /* SPIOWData4; */
1087 0,0, /* SPIOWDataPtr:Unused1; */
1088 { 0,0 }, /* Unused2[2]; */
1090 0,0, /* SPIOWChildPtr:SPIOWSiblingPtr; */
1091 0,0, /* SPIOWThisPtr:SPIOWEntryPoint; */
1098 0 /* Unused3[5]; */
1102 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&spio_write_scb,
1103 dest,"SPIOWRITE",parent_scb,
1104 scb_child_type);
1106 return scb;
1109 struct dsp_scb_descriptor *
1110 cs46xx_dsp_create_magic_snoop_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1111 u16 snoop_buffer_address,
1112 struct dsp_scb_descriptor * snoop_scb,
1113 struct dsp_scb_descriptor * parent_scb,
1114 int scb_child_type)
1116 struct dsp_scb_descriptor * scb;
1118 struct dsp_magic_snoop_task magic_snoop_scb = {
1119 /* 0 */ 0, /* i0 */
1120 /* 1 */ 0, /* i1 */
1121 /* 2 */ snoop_buffer_address << 0x10,
1122 /* 3 */ 0,snoop_scb->address,
1123 /* 4 */ 0, /* i3 */
1124 /* 5 */ 0, /* i4 */
1125 /* 6 */ 0, /* i5 */
1126 /* 7 */ 0, /* i6 */
1127 /* 8 */ 0, /* i7 */
1128 /* 9 */ 0,0, /* next_scb, sub_list_ptr */
1129 /* A */ 0,0, /* entry_point, this_ptr */
1130 /* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
1131 /* C */ snoop_buffer_address << 0x10,
1132 /* D */ 0,
1133 /* E */ { 0x8000,0x8000,
1134 /* F */ 0xffff,0xffff
1138 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&magic_snoop_scb,
1139 dest,"MAGICSNOOPTASK",parent_scb,
1140 scb_child_type);
1142 return scb;
1145 static struct dsp_scb_descriptor *
1146 find_next_free_scb (struct snd_cs46xx * chip, struct dsp_scb_descriptor * from)
1148 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1149 struct dsp_scb_descriptor * scb = from;
1151 while (scb->next_scb_ptr != ins->the_null_scb) {
1152 if (snd_BUG_ON(!scb->next_scb_ptr))
1153 return NULL;
1155 scb = scb->next_scb_ptr;
1158 return scb;
1161 static u32 pcm_reader_buffer_addr[DSP_MAX_PCM_CHANNELS] = {
1162 0x0600, /* 1 */
1163 0x1500, /* 2 */
1164 0x1580, /* 3 */
1165 0x1600, /* 4 */
1166 0x1680, /* 5 */
1167 0x1700, /* 6 */
1168 0x1780, /* 7 */
1169 0x1800, /* 8 */
1170 0x1880, /* 9 */
1171 0x1900, /* 10 */
1172 0x1980, /* 11 */
1173 0x1A00, /* 12 */
1174 0x1A80, /* 13 */
1175 0x1B00, /* 14 */
1176 0x1B80, /* 15 */
1177 0x1C00, /* 16 */
1178 0x1C80, /* 17 */
1179 0x1D00, /* 18 */
1180 0x1D80, /* 19 */
1181 0x1E00, /* 20 */
1182 0x1E80, /* 21 */
1183 0x1F00, /* 22 */
1184 0x1F80, /* 23 */
1185 0x2000, /* 24 */
1186 0x2080, /* 25 */
1187 0x2100, /* 26 */
1188 0x2180, /* 27 */
1189 0x2200, /* 28 */
1190 0x2280, /* 29 */
1191 0x2300, /* 30 */
1192 0x2380, /* 31 */
1193 0x2400, /* 32 */
1196 static u32 src_output_buffer_addr[DSP_MAX_SRC_NR] = {
1197 0x2B80,
1198 0x2BA0,
1199 0x2BC0,
1200 0x2BE0,
1201 0x2D00,
1202 0x2D20,
1203 0x2D40,
1204 0x2D60,
1205 0x2D80,
1206 0x2DA0,
1207 0x2DC0,
1208 0x2DE0,
1209 0x2E00,
1210 0x2E20
1213 static u32 src_delay_buffer_addr[DSP_MAX_SRC_NR] = {
1214 0x2480,
1215 0x2500,
1216 0x2580,
1217 0x2600,
1218 0x2680,
1219 0x2700,
1220 0x2780,
1221 0x2800,
1222 0x2880,
1223 0x2900,
1224 0x2980,
1225 0x2A00,
1226 0x2A80,
1227 0x2B00
1230 struct dsp_pcm_channel_descriptor *
1231 cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
1232 u32 sample_rate, void * private_data,
1233 u32 hw_dma_addr,
1234 int pcm_channel_id)
1236 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1237 struct dsp_scb_descriptor * src_scb = NULL, * pcm_scb, * mixer_scb = NULL;
1238 struct dsp_scb_descriptor * src_parent_scb = NULL;
1240 /* struct dsp_scb_descriptor * pcm_parent_scb; */
1241 char scb_name[DSP_MAX_SCB_NAME];
1242 int i, pcm_index = -1, insert_point, src_index = -1, pass_through = 0;
1243 unsigned long flags;
1245 switch (pcm_channel_id) {
1246 case DSP_PCM_MAIN_CHANNEL:
1247 mixer_scb = ins->master_mix_scb;
1248 break;
1249 case DSP_PCM_REAR_CHANNEL:
1250 mixer_scb = ins->rear_mix_scb;
1251 break;
1252 case DSP_PCM_CENTER_LFE_CHANNEL:
1253 mixer_scb = ins->center_lfe_mix_scb;
1254 break;
1255 case DSP_PCM_S71_CHANNEL:
1256 /* TODO */
1257 snd_BUG();
1258 break;
1259 case DSP_IEC958_CHANNEL:
1260 if (snd_BUG_ON(!ins->asynch_tx_scb))
1261 return NULL;
1262 mixer_scb = ins->asynch_tx_scb;
1264 /* if sample rate is set to 48khz we pass
1265 the Sample Rate Converted (which could
1266 alter the raw data stream ...) */
1267 if (sample_rate == 48000) {
1268 snd_printdd ("IEC958 pass through\n");
1269 /* Hack to bypass creating a new SRC */
1270 pass_through = 1;
1272 break;
1273 default:
1274 snd_BUG();
1275 return NULL;
1277 /* default sample rate is 44100 */
1278 if (!sample_rate) sample_rate = 44100;
1280 /* search for a already created SRC SCB with the same sample rate */
1281 for (i = 0; i < DSP_MAX_PCM_CHANNELS &&
1282 (pcm_index == -1 || src_scb == NULL); ++i) {
1284 /* virtual channel reserved
1285 for capture */
1286 if (i == CS46XX_DSP_CAPTURE_CHANNEL) continue;
1288 if (ins->pcm_channels[i].active) {
1289 if (!src_scb &&
1290 ins->pcm_channels[i].sample_rate == sample_rate &&
1291 ins->pcm_channels[i].mixer_scb == mixer_scb) {
1292 src_scb = ins->pcm_channels[i].src_scb;
1293 ins->pcm_channels[i].src_scb->ref_count ++;
1294 src_index = ins->pcm_channels[i].src_slot;
1296 } else if (pcm_index == -1) {
1297 pcm_index = i;
1301 if (pcm_index == -1) {
1302 snd_printk (KERN_ERR "dsp_spos: no free PCM channel\n");
1303 return NULL;
1306 if (src_scb == NULL) {
1307 if (ins->nsrc_scb >= DSP_MAX_SRC_NR) {
1308 snd_printk(KERN_ERR "dsp_spos: to many SRC instances\n!");
1309 return NULL;
1312 /* find a free slot */
1313 for (i = 0; i < DSP_MAX_SRC_NR; ++i) {
1314 if (ins->src_scb_slots[i] == 0) {
1315 src_index = i;
1316 ins->src_scb_slots[i] = 1;
1317 break;
1320 if (snd_BUG_ON(src_index == -1))
1321 return NULL;
1323 /* we need to create a new SRC SCB */
1324 if (mixer_scb->sub_list_ptr == ins->the_null_scb) {
1325 src_parent_scb = mixer_scb;
1326 insert_point = SCB_ON_PARENT_SUBLIST_SCB;
1327 } else {
1328 src_parent_scb = find_next_free_scb(chip,mixer_scb->sub_list_ptr);
1329 insert_point = SCB_ON_PARENT_NEXT_SCB;
1332 snprintf (scb_name,DSP_MAX_SCB_NAME,"SrcTask_SCB%d",src_index);
1334 snd_printdd( "dsp_spos: creating SRC \"%s\"\n",scb_name);
1335 src_scb = cs46xx_dsp_create_src_task_scb(chip,scb_name,
1336 sample_rate,
1337 src_output_buffer_addr[src_index],
1338 src_delay_buffer_addr[src_index],
1339 /* 0x400 - 0x600 source SCBs */
1340 0x400 + (src_index * 0x10) ,
1341 src_parent_scb,
1342 insert_point,
1343 pass_through);
1345 if (!src_scb) {
1346 snd_printk (KERN_ERR "dsp_spos: failed to create SRCtaskSCB\n");
1347 return NULL;
1350 /* cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate); */
1352 ins->nsrc_scb ++;
1356 snprintf (scb_name,DSP_MAX_SCB_NAME,"PCMReader_SCB%d",pcm_index);
1358 snd_printdd( "dsp_spos: creating PCM \"%s\" (%d)\n",scb_name,
1359 pcm_channel_id);
1361 pcm_scb = cs46xx_dsp_create_pcm_reader_scb(chip,scb_name,
1362 pcm_reader_buffer_addr[pcm_index],
1363 /* 0x200 - 400 PCMreader SCBs */
1364 (pcm_index * 0x10) + 0x200,
1365 pcm_index, /* virtual channel 0-31 */
1366 hw_dma_addr, /* pcm hw addr */
1367 NULL, /* parent SCB ptr */
1368 0 /* insert point */
1371 if (!pcm_scb) {
1372 snd_printk (KERN_ERR "dsp_spos: failed to create PCMreaderSCB\n");
1373 return NULL;
1376 spin_lock_irqsave(&chip->reg_lock, flags);
1377 ins->pcm_channels[pcm_index].sample_rate = sample_rate;
1378 ins->pcm_channels[pcm_index].pcm_reader_scb = pcm_scb;
1379 ins->pcm_channels[pcm_index].src_scb = src_scb;
1380 ins->pcm_channels[pcm_index].unlinked = 1;
1381 ins->pcm_channels[pcm_index].private_data = private_data;
1382 ins->pcm_channels[pcm_index].src_slot = src_index;
1383 ins->pcm_channels[pcm_index].active = 1;
1384 ins->pcm_channels[pcm_index].pcm_slot = pcm_index;
1385 ins->pcm_channels[pcm_index].mixer_scb = mixer_scb;
1386 ins->npcm_channels ++;
1387 spin_unlock_irqrestore(&chip->reg_lock, flags);
1389 return (ins->pcm_channels + pcm_index);
1392 int cs46xx_dsp_pcm_channel_set_period (struct snd_cs46xx * chip,
1393 struct dsp_pcm_channel_descriptor * pcm_channel,
1394 int period_size)
1396 u32 temp = snd_cs46xx_peek (chip,pcm_channel->pcm_reader_scb->address << 2);
1397 temp &= ~DMA_RQ_C1_SOURCE_SIZE_MASK;
1399 switch (period_size) {
1400 case 2048:
1401 temp |= DMA_RQ_C1_SOURCE_MOD1024;
1402 break;
1403 case 1024:
1404 temp |= DMA_RQ_C1_SOURCE_MOD512;
1405 break;
1406 case 512:
1407 temp |= DMA_RQ_C1_SOURCE_MOD256;
1408 break;
1409 case 256:
1410 temp |= DMA_RQ_C1_SOURCE_MOD128;
1411 break;
1412 case 128:
1413 temp |= DMA_RQ_C1_SOURCE_MOD64;
1414 break;
1415 case 64:
1416 temp |= DMA_RQ_C1_SOURCE_MOD32;
1417 break;
1418 case 32:
1419 temp |= DMA_RQ_C1_SOURCE_MOD16;
1420 break;
1421 default:
1422 snd_printdd ("period size (%d) not supported by HW\n", period_size);
1423 return -EINVAL;
1426 snd_cs46xx_poke (chip,pcm_channel->pcm_reader_scb->address << 2,temp);
1428 return 0;
1431 int cs46xx_dsp_pcm_ostream_set_period (struct snd_cs46xx * chip,
1432 int period_size)
1434 u32 temp = snd_cs46xx_peek (chip,WRITEBACK_SCB_ADDR << 2);
1435 temp &= ~DMA_RQ_C1_DEST_SIZE_MASK;
1437 switch (period_size) {
1438 case 2048:
1439 temp |= DMA_RQ_C1_DEST_MOD1024;
1440 break;
1441 case 1024:
1442 temp |= DMA_RQ_C1_DEST_MOD512;
1443 break;
1444 case 512:
1445 temp |= DMA_RQ_C1_DEST_MOD256;
1446 break;
1447 case 256:
1448 temp |= DMA_RQ_C1_DEST_MOD128;
1449 break;
1450 case 128:
1451 temp |= DMA_RQ_C1_DEST_MOD64;
1452 break;
1453 case 64:
1454 temp |= DMA_RQ_C1_DEST_MOD32;
1455 break;
1456 case 32:
1457 temp |= DMA_RQ_C1_DEST_MOD16;
1458 break;
1459 default:
1460 snd_printdd ("period size (%d) not supported by HW\n", period_size);
1461 return -EINVAL;
1464 snd_cs46xx_poke (chip,WRITEBACK_SCB_ADDR << 2,temp);
1466 return 0;
1469 void cs46xx_dsp_destroy_pcm_channel (struct snd_cs46xx * chip,
1470 struct dsp_pcm_channel_descriptor * pcm_channel)
1472 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1473 unsigned long flags;
1475 if (snd_BUG_ON(!pcm_channel->active ||
1476 ins->npcm_channels <= 0 ||
1477 pcm_channel->src_scb->ref_count <= 0))
1478 return;
1480 spin_lock_irqsave(&chip->reg_lock, flags);
1481 pcm_channel->unlinked = 1;
1482 pcm_channel->active = 0;
1483 pcm_channel->private_data = NULL;
1484 pcm_channel->src_scb->ref_count --;
1485 ins->npcm_channels --;
1486 spin_unlock_irqrestore(&chip->reg_lock, flags);
1488 cs46xx_dsp_remove_scb(chip,pcm_channel->pcm_reader_scb);
1490 if (!pcm_channel->src_scb->ref_count) {
1491 cs46xx_dsp_remove_scb(chip,pcm_channel->src_scb);
1493 if (snd_BUG_ON(pcm_channel->src_slot < 0 ||
1494 pcm_channel->src_slot >= DSP_MAX_SRC_NR))
1495 return;
1497 ins->src_scb_slots[pcm_channel->src_slot] = 0;
1498 ins->nsrc_scb --;
1502 int cs46xx_dsp_pcm_unlink (struct snd_cs46xx * chip,
1503 struct dsp_pcm_channel_descriptor * pcm_channel)
1505 unsigned long flags;
1507 if (snd_BUG_ON(!pcm_channel->active ||
1508 chip->dsp_spos_instance->npcm_channels <= 0))
1509 return -EIO;
1511 spin_lock(&pcm_channel->src_scb->lock);
1513 if (pcm_channel->unlinked) {
1514 spin_unlock(&pcm_channel->src_scb->lock);
1515 return -EIO;
1518 spin_lock_irqsave(&chip->reg_lock, flags);
1519 pcm_channel->unlinked = 1;
1520 spin_unlock_irqrestore(&chip->reg_lock, flags);
1522 _dsp_unlink_scb (chip,pcm_channel->pcm_reader_scb);
1524 spin_unlock(&pcm_channel->src_scb->lock);
1525 return 0;
1528 int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip,
1529 struct dsp_pcm_channel_descriptor * pcm_channel)
1531 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1532 struct dsp_scb_descriptor * parent_scb;
1533 struct dsp_scb_descriptor * src_scb = pcm_channel->src_scb;
1534 unsigned long flags;
1536 spin_lock(&pcm_channel->src_scb->lock);
1538 if (pcm_channel->unlinked == 0) {
1539 spin_unlock(&pcm_channel->src_scb->lock);
1540 return -EIO;
1543 parent_scb = src_scb;
1545 if (src_scb->sub_list_ptr != ins->the_null_scb) {
1546 src_scb->sub_list_ptr->parent_scb_ptr = pcm_channel->pcm_reader_scb;
1547 pcm_channel->pcm_reader_scb->next_scb_ptr = src_scb->sub_list_ptr;
1550 src_scb->sub_list_ptr = pcm_channel->pcm_reader_scb;
1552 snd_BUG_ON(pcm_channel->pcm_reader_scb->parent_scb_ptr);
1553 pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb;
1555 spin_lock_irqsave(&chip->reg_lock, flags);
1557 /* update SCB entry in DSP RAM */
1558 cs46xx_dsp_spos_update_scb(chip,pcm_channel->pcm_reader_scb);
1560 /* update parent SCB entry */
1561 cs46xx_dsp_spos_update_scb(chip,parent_scb);
1563 pcm_channel->unlinked = 0;
1564 spin_unlock_irqrestore(&chip->reg_lock, flags);
1566 spin_unlock(&pcm_channel->src_scb->lock);
1567 return 0;
1570 struct dsp_scb_descriptor *
1571 cs46xx_add_record_source (struct snd_cs46xx *chip, struct dsp_scb_descriptor * source,
1572 u16 addr, char * scb_name)
1574 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1575 struct dsp_scb_descriptor * parent;
1576 struct dsp_scb_descriptor * pcm_input;
1577 int insert_point;
1579 if (snd_BUG_ON(!ins->record_mixer_scb))
1580 return NULL;
1582 if (ins->record_mixer_scb->sub_list_ptr != ins->the_null_scb) {
1583 parent = find_next_free_scb (chip,ins->record_mixer_scb->sub_list_ptr);
1584 insert_point = SCB_ON_PARENT_NEXT_SCB;
1585 } else {
1586 parent = ins->record_mixer_scb;
1587 insert_point = SCB_ON_PARENT_SUBLIST_SCB;
1590 pcm_input = cs46xx_dsp_create_pcm_serial_input_scb(chip,scb_name,addr,
1591 source, parent,
1592 insert_point);
1594 return pcm_input;
1597 int cs46xx_src_unlink(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
1599 if (snd_BUG_ON(!src->parent_scb_ptr))
1600 return -EINVAL;
1602 /* mute SCB */
1603 cs46xx_dsp_scb_set_volume (chip,src,0,0);
1605 _dsp_unlink_scb (chip,src);
1607 return 0;
1610 int cs46xx_src_link(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
1612 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1613 struct dsp_scb_descriptor * parent_scb;
1615 if (snd_BUG_ON(src->parent_scb_ptr))
1616 return -EINVAL;
1617 if (snd_BUG_ON(!ins->master_mix_scb))
1618 return -EINVAL;
1620 if (ins->master_mix_scb->sub_list_ptr != ins->the_null_scb) {
1621 parent_scb = find_next_free_scb (chip,ins->master_mix_scb->sub_list_ptr);
1622 parent_scb->next_scb_ptr = src;
1623 } else {
1624 parent_scb = ins->master_mix_scb;
1625 parent_scb->sub_list_ptr = src;
1628 src->parent_scb_ptr = parent_scb;
1630 /* update entry in DSP RAM */
1631 cs46xx_dsp_spos_update_scb(chip,parent_scb);
1633 return 0;
1636 int cs46xx_dsp_enable_spdif_out (struct snd_cs46xx *chip)
1638 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1640 if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
1641 cs46xx_dsp_enable_spdif_hw (chip);
1644 /* dont touch anything if SPDIF is open */
1645 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
1646 /* when cs46xx_iec958_post_close(...) is called it
1647 will call this function if necessary depending on
1648 this bit */
1649 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1651 return -EBUSY;
1654 if (snd_BUG_ON(ins->asynch_tx_scb))
1655 return -EINVAL;
1656 if (snd_BUG_ON(ins->master_mix_scb->next_scb_ptr !=
1657 ins->the_null_scb))
1658 return -EINVAL;
1660 /* reset output snooper sample buffer pointer */
1661 snd_cs46xx_poke (chip, (ins->ref_snoop_scb->address + 2) << 2,
1662 (OUTPUT_SNOOP_BUFFER + 0x10) << 0x10 );
1664 /* The asynch. transfer task */
1665 ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
1666 SPDIFO_SCB_INST,
1667 SPDIFO_IP_OUTPUT_BUFFER1,
1668 ins->master_mix_scb,
1669 SCB_ON_PARENT_NEXT_SCB);
1670 if (!ins->asynch_tx_scb) return -ENOMEM;
1672 ins->spdif_pcm_input_scb = cs46xx_dsp_create_pcm_serial_input_scb(chip,"PCMSerialInput_II",
1673 PCMSERIALINII_SCB_ADDR,
1674 ins->ref_snoop_scb,
1675 ins->asynch_tx_scb,
1676 SCB_ON_PARENT_SUBLIST_SCB);
1679 if (!ins->spdif_pcm_input_scb) return -ENOMEM;
1681 /* monitor state */
1682 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1684 return 0;
1687 int cs46xx_dsp_disable_spdif_out (struct snd_cs46xx *chip)
1689 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1691 /* dont touch anything if SPDIF is open */
1692 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
1693 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1694 return -EBUSY;
1697 /* check integrety */
1698 if (snd_BUG_ON(!ins->asynch_tx_scb))
1699 return -EINVAL;
1700 if (snd_BUG_ON(!ins->spdif_pcm_input_scb))
1701 return -EINVAL;
1702 if (snd_BUG_ON(ins->master_mix_scb->next_scb_ptr != ins->asynch_tx_scb))
1703 return -EINVAL;
1704 if (snd_BUG_ON(ins->asynch_tx_scb->parent_scb_ptr !=
1705 ins->master_mix_scb))
1706 return -EINVAL;
1708 cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
1709 cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
1711 ins->spdif_pcm_input_scb = NULL;
1712 ins->asynch_tx_scb = NULL;
1714 /* clear buffer to prevent any undesired noise */
1715 _dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
1717 /* monitor state */
1718 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1721 return 0;
1724 int cs46xx_iec958_pre_open (struct snd_cs46xx *chip)
1726 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1728 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
1729 /* remove AsynchFGTxSCB and and PCMSerialInput_II */
1730 cs46xx_dsp_disable_spdif_out (chip);
1732 /* save state */
1733 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1736 /* if not enabled already */
1737 if ( !(ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
1738 cs46xx_dsp_enable_spdif_hw (chip);
1741 /* Create the asynch. transfer task for playback */
1742 ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
1743 SPDIFO_SCB_INST,
1744 SPDIFO_IP_OUTPUT_BUFFER1,
1745 ins->master_mix_scb,
1746 SCB_ON_PARENT_NEXT_SCB);
1749 /* set spdif channel status value for streaming */
1750 cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_stream);
1752 ins->spdif_status_out |= DSP_SPDIF_STATUS_PLAYBACK_OPEN;
1754 return 0;
1757 int cs46xx_iec958_post_close (struct snd_cs46xx *chip)
1759 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1761 if (snd_BUG_ON(!ins->asynch_tx_scb))
1762 return -EINVAL;
1764 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_PLAYBACK_OPEN;
1766 /* restore settings */
1767 cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);
1769 /* deallocate stuff */
1770 if (ins->spdif_pcm_input_scb != NULL) {
1771 cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
1772 ins->spdif_pcm_input_scb = NULL;
1775 cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
1776 ins->asynch_tx_scb = NULL;
1778 /* clear buffer to prevent any undesired noise */
1779 _dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
1781 /* restore state */
1782 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
1783 cs46xx_dsp_enable_spdif_out (chip);
1786 return 0;