Linux 2.6.24.5
[linux/fpc-iii.git] / sound / pci / cs46xx / dsp_spos_scb_lib.c
blobeded4dfeba1210fe307d7f526e39d3c1f0856ed1
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 <sound/driver.h>
25 #include <asm/io.h>
26 #include <linux/delay.h>
27 #include <linux/pm.h>
28 #include <linux/init.h>
29 #include <linux/slab.h>
30 #include <linux/mutex.h>
32 #include <sound/core.h>
33 #include <sound/control.h>
34 #include <sound/info.h>
35 #include <sound/cs46xx.h>
37 #include "cs46xx_lib.h"
38 #include "dsp_spos.h"
40 struct proc_scb_info {
41 struct dsp_scb_descriptor * scb_desc;
42 struct snd_cs46xx *chip;
45 static void remove_symbol (struct snd_cs46xx * chip, struct dsp_symbol_entry * symbol)
47 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
48 int symbol_index = (int)(symbol - ins->symbol_table.symbols);
50 snd_assert(ins->symbol_table.nsymbols > 0,return);
51 snd_assert(symbol_index >= 0 && symbol_index < ins->symbol_table.nsymbols, return);
53 ins->symbol_table.symbols[symbol_index].deleted = 1;
55 if (symbol_index < ins->symbol_table.highest_frag_index) {
56 ins->symbol_table.highest_frag_index = symbol_index;
59 if (symbol_index == ins->symbol_table.nsymbols - 1)
60 ins->symbol_table.nsymbols --;
62 if (ins->symbol_table.highest_frag_index > ins->symbol_table.nsymbols) {
63 ins->symbol_table.highest_frag_index = ins->symbol_table.nsymbols;
68 #ifdef CONFIG_PROC_FS
69 static void cs46xx_dsp_proc_scb_info_read (struct snd_info_entry *entry,
70 struct snd_info_buffer *buffer)
72 struct proc_scb_info * scb_info = entry->private_data;
73 struct dsp_scb_descriptor * scb = scb_info->scb_desc;
74 struct dsp_spos_instance * ins;
75 struct snd_cs46xx *chip = scb_info->chip;
76 int j,col;
77 void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
79 ins = chip->dsp_spos_instance;
81 mutex_lock(&chip->spos_mutex);
82 snd_iprintf(buffer,"%04x %s:\n",scb->address,scb->scb_name);
84 for (col = 0,j = 0;j < 0x10; j++,col++) {
85 if (col == 4) {
86 snd_iprintf(buffer,"\n");
87 col = 0;
89 snd_iprintf(buffer,"%08x ",readl(dst + (scb->address + j) * sizeof(u32)));
92 snd_iprintf(buffer,"\n");
94 if (scb->parent_scb_ptr != NULL) {
95 snd_iprintf(buffer,"parent [%s:%04x] ",
96 scb->parent_scb_ptr->scb_name,
97 scb->parent_scb_ptr->address);
98 } else snd_iprintf(buffer,"parent [none] ");
100 snd_iprintf(buffer,"sub_list_ptr [%s:%04x]\nnext_scb_ptr [%s:%04x] task_entry [%s:%04x]\n",
101 scb->sub_list_ptr->scb_name,
102 scb->sub_list_ptr->address,
103 scb->next_scb_ptr->scb_name,
104 scb->next_scb_ptr->address,
105 scb->task_entry->symbol_name,
106 scb->task_entry->address);
108 snd_iprintf(buffer,"index [%d] ref_count [%d]\n",scb->index,scb->ref_count);
109 mutex_unlock(&chip->spos_mutex);
111 #endif
113 static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
115 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
116 unsigned long flags;
118 if ( scb->parent_scb_ptr ) {
119 /* unlink parent SCB */
120 snd_assert ((scb->parent_scb_ptr->sub_list_ptr == scb ||
121 scb->parent_scb_ptr->next_scb_ptr == scb),return);
123 if (scb->parent_scb_ptr->sub_list_ptr == scb) {
125 if (scb->next_scb_ptr == ins->the_null_scb) {
126 /* last and only node in parent sublist */
127 scb->parent_scb_ptr->sub_list_ptr = scb->sub_list_ptr;
129 if (scb->sub_list_ptr != ins->the_null_scb) {
130 scb->sub_list_ptr->parent_scb_ptr = scb->parent_scb_ptr;
132 scb->sub_list_ptr = ins->the_null_scb;
133 } else {
134 /* first node in parent sublist */
135 scb->parent_scb_ptr->sub_list_ptr = scb->next_scb_ptr;
137 if (scb->next_scb_ptr != ins->the_null_scb) {
138 /* update next node parent ptr. */
139 scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
141 scb->next_scb_ptr = ins->the_null_scb;
143 } else {
144 /* snd_assert ( (scb->sub_list_ptr == ins->the_null_scb), return); */
145 scb->parent_scb_ptr->next_scb_ptr = scb->next_scb_ptr;
147 if (scb->next_scb_ptr != ins->the_null_scb) {
148 /* update next node parent ptr. */
149 scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
151 scb->next_scb_ptr = ins->the_null_scb;
154 spin_lock_irqsave(&chip->reg_lock, flags);
156 /* update parent first entry in DSP RAM */
157 cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
159 /* then update entry in DSP RAM */
160 cs46xx_dsp_spos_update_scb(chip,scb);
162 scb->parent_scb_ptr = NULL;
163 spin_unlock_irqrestore(&chip->reg_lock, flags);
167 static void _dsp_clear_sample_buffer (struct snd_cs46xx *chip, u32 sample_buffer_addr,
168 int dword_count)
170 void __iomem *dst = chip->region.idx[2].remap_addr + sample_buffer_addr;
171 int i;
173 for (i = 0; i < dword_count ; ++i ) {
174 writel(0, dst);
175 dst += 4;
179 void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
181 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
182 unsigned long flags;
184 /* check integrety */
185 snd_assert ( (scb->index >= 0 &&
186 scb->index < ins->nscb &&
187 (ins->scbs + scb->index) == scb), return );
189 #if 0
190 /* can't remove a SCB with childs before
191 removing childs first */
192 snd_assert ( (scb->sub_list_ptr == ins->the_null_scb &&
193 scb->next_scb_ptr == ins->the_null_scb),
194 goto _end);
195 #endif
197 spin_lock_irqsave(&scb->lock, flags);
198 _dsp_unlink_scb (chip,scb);
199 spin_unlock_irqrestore(&scb->lock, flags);
201 cs46xx_dsp_proc_free_scb_desc(scb);
202 snd_assert (scb->scb_symbol != NULL, return );
203 remove_symbol (chip,scb->scb_symbol);
205 ins->scbs[scb->index].deleted = 1;
207 if (scb->index < ins->scb_highest_frag_index)
208 ins->scb_highest_frag_index = scb->index;
210 if (scb->index == ins->nscb - 1) {
211 ins->nscb --;
214 if (ins->scb_highest_frag_index > ins->nscb) {
215 ins->scb_highest_frag_index = ins->nscb;
218 #if 0
219 /* !!!! THIS IS A PIECE OF SHIT MADE BY ME !!! */
220 for(i = scb->index + 1;i < ins->nscb; ++i) {
221 ins->scbs[i - 1].index = i - 1;
223 #endif
227 #ifdef CONFIG_PROC_FS
228 void cs46xx_dsp_proc_free_scb_desc (struct dsp_scb_descriptor * scb)
230 if (scb->proc_info) {
231 struct proc_scb_info * scb_info = scb->proc_info->private_data;
233 snd_printdd("cs46xx_dsp_proc_free_scb_desc: freeing %s\n",scb->scb_name);
235 snd_info_free_entry(scb->proc_info);
236 scb->proc_info = NULL;
238 snd_assert (scb_info != NULL, return);
239 kfree (scb_info);
243 void cs46xx_dsp_proc_register_scb_desc (struct snd_cs46xx *chip,
244 struct dsp_scb_descriptor * scb)
246 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
247 struct snd_info_entry * entry;
248 struct proc_scb_info * scb_info;
250 /* register to proc */
251 if (ins->snd_card != NULL && ins->proc_dsp_dir != NULL &&
252 scb->proc_info == NULL) {
254 if ((entry = snd_info_create_card_entry(ins->snd_card, scb->scb_name,
255 ins->proc_dsp_dir)) != NULL) {
256 scb_info = kmalloc(sizeof(struct proc_scb_info), GFP_KERNEL);
257 if (!scb_info) {
258 snd_info_free_entry(entry);
259 entry = NULL;
260 goto out;
263 scb_info->chip = chip;
264 scb_info->scb_desc = scb;
266 entry->content = SNDRV_INFO_CONTENT_TEXT;
267 entry->private_data = scb_info;
268 entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
270 entry->c.text.read = cs46xx_dsp_proc_scb_info_read;
272 if (snd_info_register(entry) < 0) {
273 snd_info_free_entry(entry);
274 kfree (scb_info);
275 entry = NULL;
278 out:
279 scb->proc_info = entry;
282 #endif /* CONFIG_PROC_FS */
284 static struct dsp_scb_descriptor *
285 _dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32 dest,
286 struct dsp_symbol_entry * task_entry,
287 struct dsp_scb_descriptor * parent_scb,
288 int scb_child_type)
290 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
291 struct dsp_scb_descriptor * scb;
293 unsigned long flags;
295 snd_assert (ins->the_null_scb != NULL,return NULL);
297 /* fill the data that will be wroten to DSP */
298 scb_data[SCBsubListPtr] =
299 (ins->the_null_scb->address << 0x10) | ins->the_null_scb->address;
301 scb_data[SCBfuncEntryPtr] &= 0xFFFF0000;
302 scb_data[SCBfuncEntryPtr] |= task_entry->address;
304 snd_printdd("dsp_spos: creating SCB <%s>\n",name);
306 scb = cs46xx_dsp_create_scb(chip,name,scb_data,dest);
309 scb->sub_list_ptr = ins->the_null_scb;
310 scb->next_scb_ptr = ins->the_null_scb;
312 scb->parent_scb_ptr = parent_scb;
313 scb->task_entry = task_entry;
316 /* update parent SCB */
317 if (scb->parent_scb_ptr) {
318 #if 0
319 printk ("scb->parent_scb_ptr = %s\n",scb->parent_scb_ptr->scb_name);
320 printk ("scb->parent_scb_ptr->next_scb_ptr = %s\n",scb->parent_scb_ptr->next_scb_ptr->scb_name);
321 printk ("scb->parent_scb_ptr->sub_list_ptr = %s\n",scb->parent_scb_ptr->sub_list_ptr->scb_name);
322 #endif
323 /* link to parent SCB */
324 if (scb_child_type == SCB_ON_PARENT_NEXT_SCB) {
325 snd_assert ( (scb->parent_scb_ptr->next_scb_ptr == ins->the_null_scb),
326 return NULL);
328 scb->parent_scb_ptr->next_scb_ptr = scb;
330 } else if (scb_child_type == SCB_ON_PARENT_SUBLIST_SCB) {
331 snd_assert ( (scb->parent_scb_ptr->sub_list_ptr == ins->the_null_scb),
332 return NULL);
334 scb->parent_scb_ptr->sub_list_ptr = scb;
335 } else {
336 snd_assert (0,return NULL);
339 spin_lock_irqsave(&chip->reg_lock, flags);
341 /* update entry in DSP RAM */
342 cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
344 spin_unlock_irqrestore(&chip->reg_lock, flags);
348 cs46xx_dsp_proc_register_scb_desc (chip,scb);
350 return scb;
353 static struct dsp_scb_descriptor *
354 cs46xx_dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data,
355 u32 dest, char * task_entry_name,
356 struct dsp_scb_descriptor * parent_scb,
357 int scb_child_type)
359 struct dsp_symbol_entry * task_entry;
361 task_entry = cs46xx_dsp_lookup_symbol (chip,task_entry_name,
362 SYMBOL_CODE);
364 if (task_entry == NULL) {
365 snd_printk (KERN_ERR "dsp_spos: symbol %s not found\n",task_entry_name);
366 return NULL;
369 return _dsp_create_generic_scb (chip,name,scb_data,dest,task_entry,
370 parent_scb,scb_child_type);
373 struct dsp_scb_descriptor *
374 cs46xx_dsp_create_timing_master_scb (struct snd_cs46xx *chip)
376 struct dsp_scb_descriptor * scb;
378 struct dsp_timing_master_scb timing_master_scb = {
379 { 0,
384 { 0,
390 0,0,
391 0,NULL_SCB_ADDR,
392 0,0, /* extraSampleAccum:TMreserved */
393 0,0, /* codecFIFOptr:codecFIFOsyncd */
394 0x0001,0x8000, /* fracSampAccumQm1:TMfrmsLeftInGroup */
395 0x0001,0x0000, /* fracSampCorrectionQm1:TMfrmGroupLength */
396 0x00060000 /* nSampPerFrmQ15 */
399 scb = cs46xx_dsp_create_generic_scb(chip,"TimingMasterSCBInst",(u32 *)&timing_master_scb,
400 TIMINGMASTER_SCB_ADDR,
401 "TIMINGMASTER",NULL,SCB_NO_PARENT);
403 return scb;
407 struct dsp_scb_descriptor *
408 cs46xx_dsp_create_codec_out_scb(struct snd_cs46xx * chip, char * codec_name,
409 u16 channel_disp, u16 fifo_addr, u16 child_scb_addr,
410 u32 dest, struct dsp_scb_descriptor * parent_scb,
411 int scb_child_type)
413 struct dsp_scb_descriptor * scb;
415 struct dsp_codec_output_scb codec_out_scb = {
416 { 0,
428 0,0,
429 0,NULL_SCB_ADDR,
430 0, /* COstrmRsConfig */
431 0, /* COstrmBufPtr */
432 channel_disp,fifo_addr, /* leftChanBaseIOaddr:rightChanIOdisp */
433 0x0000,0x0080, /* (!AC97!) COexpVolChangeRate:COscaleShiftCount */
434 0,child_scb_addr /* COreserved - need child scb to work with rom code */
438 scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_out_scb,
439 dest,"S16_CODECOUTPUTTASK",parent_scb,
440 scb_child_type);
442 return scb;
445 struct dsp_scb_descriptor *
446 cs46xx_dsp_create_codec_in_scb(struct snd_cs46xx * chip, char * codec_name,
447 u16 channel_disp, u16 fifo_addr, u16 sample_buffer_addr,
448 u32 dest, struct dsp_scb_descriptor * parent_scb,
449 int scb_child_type)
452 struct dsp_scb_descriptor * scb;
453 struct dsp_codec_input_scb codec_input_scb = {
454 { 0,
467 #if 0 /* cs4620 */
468 SyncIOSCB,NULL_SCB_ADDR
469 #else
470 0 , 0,
471 #endif
472 0,0,
474 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64, /* strmRsConfig */
475 sample_buffer_addr << 0x10, /* strmBufPtr; defined as a dword ptr, used as a byte ptr */
476 channel_disp,fifo_addr, /* (!AC97!) leftChanBaseINaddr=AC97primary
477 link input slot 3 :rightChanINdisp=""slot 4 */
478 0x0000,0x0000, /* (!AC97!) ????:scaleShiftCount; no shift needed
479 because AC97 is already 20 bits */
480 0x80008000 /* ??clw cwcgame.scb has 0 */
483 scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_input_scb,
484 dest,"S16_CODECINPUTTASK",parent_scb,
485 scb_child_type);
486 return scb;
490 static struct dsp_scb_descriptor *
491 cs46xx_dsp_create_pcm_reader_scb(struct snd_cs46xx * chip, char * scb_name,
492 u16 sample_buffer_addr, u32 dest,
493 int virtual_channel, u32 playback_hw_addr,
494 struct dsp_scb_descriptor * parent_scb,
495 int scb_child_type)
497 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
498 struct dsp_scb_descriptor * scb;
500 struct dsp_generic_scb pcm_reader_scb = {
503 Play DMA Task xfers data from host buffer to SP buffer
504 init/runtime variables:
505 PlayAC: Play Audio Data Conversion - SCB loc: 2nd dword, mask: 0x0000F000L
506 DATA_FMT_16BIT_ST_LTLEND(0x00000000L) from 16-bit stereo, little-endian
507 DATA_FMT_8_BIT_ST_SIGNED(0x00001000L) from 8-bit stereo, signed
508 DATA_FMT_16BIT_MN_LTLEND(0x00002000L) from 16-bit mono, little-endian
509 DATA_FMT_8_BIT_MN_SIGNED(0x00003000L) from 8-bit mono, signed
510 DATA_FMT_16BIT_ST_BIGEND(0x00004000L) from 16-bit stereo, big-endian
511 DATA_FMT_16BIT_MN_BIGEND(0x00006000L) from 16-bit mono, big-endian
512 DATA_FMT_8_BIT_ST_UNSIGNED(0x00009000L) from 8-bit stereo, unsigned
513 DATA_FMT_8_BIT_MN_UNSIGNED(0x0000b000L) from 8-bit mono, unsigned
514 ? Other combinations possible from:
515 DMA_RQ_C2_AUDIO_CONVERT_MASK 0x0000F000L
516 DMA_RQ_C2_AC_NONE 0x00000000L
517 DMA_RQ_C2_AC_8_TO_16_BIT 0x00001000L
518 DMA_RQ_C2_AC_MONO_TO_STEREO 0x00002000L
519 DMA_RQ_C2_AC_ENDIAN_CONVERT 0x00004000L
520 DMA_RQ_C2_AC_SIGNED_CONVERT 0x00008000L
522 HostBuffAddr: Host Buffer Physical Byte Address - SCB loc:3rd dword, Mask: 0xFFFFFFFFL
523 aligned to dword boundary
525 /* Basic (non scatter/gather) DMA requestor (4 ints) */
526 { DMA_RQ_C1_SOURCE_ON_HOST + /* source buffer is on the host */
527 DMA_RQ_C1_SOURCE_MOD1024 + /* source buffer is 1024 dwords (4096 bytes) */
528 DMA_RQ_C1_DEST_MOD32 + /* dest buffer(PCMreaderBuf) is 32 dwords*/
529 DMA_RQ_C1_WRITEBACK_SRC_FLAG + /* ?? */
530 DMA_RQ_C1_WRITEBACK_DEST_FLAG + /* ?? */
531 15, /* DwordCount-1: picked 16 for DwordCount because Jim */
532 /* Barnette said that is what we should use since */
533 /* we are not running in optimized mode? */
534 DMA_RQ_C2_AC_NONE +
535 DMA_RQ_C2_SIGNAL_SOURCE_PINGPONG + /* set play interrupt (bit0) in HISR when source */
536 /* buffer (on host) crosses half-way point */
537 virtual_channel, /* Play DMA channel arbitrarily set to 0 */
538 playback_hw_addr, /* HostBuffAddr (source) */
539 DMA_RQ_SD_SP_SAMPLE_ADDR + /* destination buffer is in SP Sample Memory */
540 sample_buffer_addr /* SP Buffer Address (destination) */
542 /* Scatter/gather DMA requestor extension (5 ints) */
550 /* Sublist pointer & next stream control block (SCB) link. */
551 NULL_SCB_ADDR,NULL_SCB_ADDR,
552 /* Pointer to this tasks parameter block & stream function pointer */
553 0,NULL_SCB_ADDR,
554 /* rsConfig register for stream buffer (rsDMA reg. is loaded from basicReq.daw */
555 /* for incoming streams, or basicReq.saw, for outgoing streams) */
556 RSCONFIG_DMA_ENABLE + /* enable DMA */
557 (19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) + /* MAX_DMA_SIZE picked to be 19 since SPUD */
558 /* uses it for some reason */
559 ((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) + /* stream number = SCBaddr/16 */
560 RSCONFIG_SAMPLE_16STEREO +
561 RSCONFIG_MODULO_32, /* dest buffer(PCMreaderBuf) is 32 dwords (256 bytes) */
562 /* Stream sample pointer & MAC-unit mode for this stream */
563 (sample_buffer_addr << 0x10),
564 /* Fractional increment per output sample in the input sample buffer */
567 /* Standard stereo volume control
568 default muted */
569 0xffff,0xffff,
570 0xffff,0xffff
574 if (ins->null_algorithm == NULL) {
575 ins->null_algorithm = cs46xx_dsp_lookup_symbol (chip,"NULLALGORITHM",
576 SYMBOL_CODE);
578 if (ins->null_algorithm == NULL) {
579 snd_printk (KERN_ERR "dsp_spos: symbol NULLALGORITHM not found\n");
580 return NULL;
584 scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_reader_scb,
585 dest,ins->null_algorithm,parent_scb,
586 scb_child_type);
588 return scb;
591 #define GOF_PER_SEC 200
593 struct dsp_scb_descriptor *
594 cs46xx_dsp_create_src_task_scb(struct snd_cs46xx * chip, char * scb_name,
595 int rate,
596 u16 src_buffer_addr,
597 u16 src_delay_buffer_addr, u32 dest,
598 struct dsp_scb_descriptor * parent_scb,
599 int scb_child_type,
600 int pass_through)
603 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
604 struct dsp_scb_descriptor * scb;
605 unsigned int tmp1, tmp2;
606 unsigned int phiIncr;
607 unsigned int correctionPerGOF, correctionPerSec;
609 snd_printdd( "dsp_spos: setting %s rate to %u\n",scb_name,rate);
612 * Compute the values used to drive the actual sample rate conversion.
613 * The following formulas are being computed, using inline assembly
614 * since we need to use 64 bit arithmetic to compute the values:
616 * phiIncr = floor((Fs,in * 2^26) / Fs,out)
617 * correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) /
618 * GOF_PER_SEC)
619 * ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -M
620 * GOF_PER_SEC * correctionPerGOF
622 * i.e.
624 * phiIncr:other = dividend:remainder((Fs,in * 2^26) / Fs,out)
625 * correctionPerGOF:correctionPerSec =
626 * dividend:remainder(ulOther / GOF_PER_SEC)
628 tmp1 = rate << 16;
629 phiIncr = tmp1 / 48000;
630 tmp1 -= phiIncr * 48000;
631 tmp1 <<= 10;
632 phiIncr <<= 10;
633 tmp2 = tmp1 / 48000;
634 phiIncr += tmp2;
635 tmp1 -= tmp2 * 48000;
636 correctionPerGOF = tmp1 / GOF_PER_SEC;
637 tmp1 -= correctionPerGOF * GOF_PER_SEC;
638 correctionPerSec = tmp1;
641 struct dsp_src_task_scb src_task_scb = {
642 0x0028,0x00c8,
643 0x5555,0x0000,
644 0x0000,0x0000,
645 src_buffer_addr,1,
646 correctionPerGOF,correctionPerSec,
647 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
648 0x0000,src_delay_buffer_addr,
649 0x0,
650 0x080,(src_delay_buffer_addr + (24 * 4)),
651 0,0, /* next_scb, sub_list_ptr */
652 0,0, /* entry, this_spb */
653 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
654 src_buffer_addr << 0x10,
655 phiIncr,
657 0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left,
658 0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left
662 if (ins->s16_up == NULL) {
663 ins->s16_up = cs46xx_dsp_lookup_symbol (chip,"S16_UPSRC",
664 SYMBOL_CODE);
666 if (ins->s16_up == NULL) {
667 snd_printk (KERN_ERR "dsp_spos: symbol S16_UPSRC not found\n");
668 return NULL;
672 /* clear buffers */
673 _dsp_clear_sample_buffer (chip,src_buffer_addr,8);
674 _dsp_clear_sample_buffer (chip,src_delay_buffer_addr,32);
676 if (pass_through) {
677 /* wont work with any other rate than
678 the native DSP rate */
679 snd_assert (rate == 48000);
681 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
682 dest,"DMAREADER",parent_scb,
683 scb_child_type);
684 } else {
685 scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
686 dest,ins->s16_up,parent_scb,
687 scb_child_type);
693 return scb;
696 #if 0 /* not used */
697 struct dsp_scb_descriptor *
698 cs46xx_dsp_create_filter_scb(struct snd_cs46xx * chip, char * scb_name,
699 u16 buffer_addr, u32 dest,
700 struct dsp_scb_descriptor * parent_scb,
701 int scb_child_type) {
702 struct dsp_scb_descriptor * scb;
704 struct dsp_filter_scb filter_scb = {
705 .a0_right = 0x41a9,
706 .a0_left = 0x41a9,
707 .a1_right = 0xb8e4,
708 .a1_left = 0xb8e4,
709 .a2_right = 0x3e55,
710 .a2_left = 0x3e55,
712 .filter_unused3 = 0x0000,
713 .filter_unused2 = 0x0000,
715 .output_buf_ptr = buffer_addr,
716 .init = 0x000,
718 .prev_sample_output1 = 0x00000000,
719 .prev_sample_output2 = 0x00000000,
721 .prev_sample_input1 = 0x00000000,
722 .prev_sample_input2 = 0x00000000,
724 .next_scb_ptr = 0x0000,
725 .sub_list_ptr = 0x0000,
727 .entry_point = 0x0000,
728 .spb_ptr = 0x0000,
730 .b0_right = 0x0e38,
731 .b0_left = 0x0e38,
732 .b1_right = 0x1c71,
733 .b1_left = 0x1c71,
734 .b2_right = 0x0e38,
735 .b2_left = 0x0e38,
739 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&filter_scb,
740 dest,"FILTERTASK",parent_scb,
741 scb_child_type);
743 return scb;
745 #endif /* not used */
747 struct dsp_scb_descriptor *
748 cs46xx_dsp_create_mix_only_scb(struct snd_cs46xx * chip, char * scb_name,
749 u16 mix_buffer_addr, u32 dest,
750 struct dsp_scb_descriptor * parent_scb,
751 int scb_child_type)
753 struct dsp_scb_descriptor * scb;
755 struct dsp_mix_only_scb master_mix_scb = {
756 /* 0 */ { 0,
757 /* 1 */ 0,
758 /* 2 */ mix_buffer_addr,
759 /* 3 */ 0
760 /* */ },
762 /* 4 */ 0,
763 /* 5 */ 0,
764 /* 6 */ 0,
765 /* 7 */ 0,
766 /* 8 */ 0x00000080
768 /* 9 */ 0,0,
769 /* A */ 0,0,
770 /* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
771 /* C */ (mix_buffer_addr + (16 * 4)) << 0x10,
772 /* D */ 0,
774 /* E */ 0x8000,0x8000,
775 /* F */ 0x8000,0x8000
780 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&master_mix_scb,
781 dest,"S16_MIX",parent_scb,
782 scb_child_type);
783 return scb;
787 struct dsp_scb_descriptor *
788 cs46xx_dsp_create_mix_to_ostream_scb(struct snd_cs46xx * chip, char * scb_name,
789 u16 mix_buffer_addr, u16 writeback_spb, u32 dest,
790 struct dsp_scb_descriptor * parent_scb,
791 int scb_child_type)
793 struct dsp_scb_descriptor * scb;
795 struct dsp_mix2_ostream_scb mix2_ostream_scb = {
796 /* Basic (non scatter/gather) DMA requestor (4 ints) */
798 DMA_RQ_C1_SOURCE_MOD64 +
799 DMA_RQ_C1_DEST_ON_HOST +
800 DMA_RQ_C1_DEST_MOD1024 +
801 DMA_RQ_C1_WRITEBACK_SRC_FLAG +
802 DMA_RQ_C1_WRITEBACK_DEST_FLAG +
803 15,
805 DMA_RQ_C2_AC_NONE +
806 DMA_RQ_C2_SIGNAL_DEST_PINGPONG +
808 CS46XX_DSP_CAPTURE_CHANNEL,
809 DMA_RQ_SD_SP_SAMPLE_ADDR +
810 mix_buffer_addr,
811 0x0
814 { 0, 0, 0, 0, 0, },
815 0,0,
816 0,writeback_spb,
818 RSCONFIG_DMA_ENABLE +
819 (19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) +
821 ((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) +
822 RSCONFIG_DMA_TO_HOST +
823 RSCONFIG_SAMPLE_16STEREO +
824 RSCONFIG_MODULO_64,
825 (mix_buffer_addr + (32 * 4)) << 0x10,
826 1,0,
827 0x0001,0x0080,
828 0xFFFF,0
832 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&mix2_ostream_scb,
834 dest,"S16_MIX_TO_OSTREAM",parent_scb,
835 scb_child_type);
837 return scb;
841 struct dsp_scb_descriptor *
842 cs46xx_dsp_create_vari_decimate_scb(struct snd_cs46xx * chip,char * scb_name,
843 u16 vari_buffer_addr0,
844 u16 vari_buffer_addr1,
845 u32 dest,
846 struct dsp_scb_descriptor * parent_scb,
847 int scb_child_type)
850 struct dsp_scb_descriptor * scb;
852 struct dsp_vari_decimate_scb vari_decimate_scb = {
853 0x0028,0x00c8,
854 0x5555,0x0000,
855 0x0000,0x0000,
856 vari_buffer_addr0,vari_buffer_addr1,
858 0x0028,0x00c8,
859 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256,
861 0xFF800000,
863 0x0080,vari_buffer_addr1 + (25 * 4),
865 0,0,
866 0,0,
868 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
869 vari_buffer_addr0 << 0x10,
870 0x04000000,
872 0x8000,0x8000,
873 0xFFFF,0xFFFF
877 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&vari_decimate_scb,
878 dest,"VARIDECIMATE",parent_scb,
879 scb_child_type);
881 return scb;
885 static struct dsp_scb_descriptor *
886 cs46xx_dsp_create_pcm_serial_input_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
887 struct dsp_scb_descriptor * input_scb,
888 struct dsp_scb_descriptor * parent_scb,
889 int scb_child_type)
892 struct dsp_scb_descriptor * scb;
895 struct dsp_pcm_serial_input_scb pcm_serial_input_scb = {
896 { 0,
909 0,0,
910 0,0,
912 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_16,
914 /* 0xD */ 0,input_scb->address,
916 /* 0xE */ 0x8000,0x8000,
917 /* 0xF */ 0x8000,0x8000
921 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_serial_input_scb,
922 dest,"PCMSERIALINPUTTASK",parent_scb,
923 scb_child_type);
924 return scb;
928 static struct dsp_scb_descriptor *
929 cs46xx_dsp_create_asynch_fg_tx_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
930 u16 hfg_scb_address,
931 u16 asynch_buffer_address,
932 struct dsp_scb_descriptor * parent_scb,
933 int scb_child_type)
936 struct dsp_scb_descriptor * scb;
938 struct dsp_asynch_fg_tx_scb asynch_fg_tx_scb = {
939 0xfc00,0x03ff, /* Prototype sample buffer size of 256 dwords */
940 0x0058,0x0028, /* Min Delta 7 dwords == 28 bytes */
941 /* : Max delta 25 dwords == 100 bytes */
942 0,hfg_scb_address, /* Point to HFG task SCB */
943 0,0, /* Initialize current Delta and Consumer ptr adjustment count */
944 0, /* Initialize accumulated Phi to 0 */
945 0,0x2aab, /* Const 1/3 */
948 0, /* Define the unused elements */
953 0,0,
954 0,dest + AFGTxAccumPhi,
956 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256, /* Stereo, 256 dword */
957 (asynch_buffer_address) << 0x10, /* This should be automagically synchronized
958 to the producer pointer */
960 /* There is no correct initial value, it will depend upon the detected
961 rate etc */
962 0x18000000, /* Phi increment for approx 32k operation */
963 0x8000,0x8000, /* Volume controls are unused at this time */
964 0x8000,0x8000
967 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_tx_scb,
968 dest,"ASYNCHFGTXCODE",parent_scb,
969 scb_child_type);
971 return scb;
975 struct dsp_scb_descriptor *
976 cs46xx_dsp_create_asynch_fg_rx_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
977 u16 hfg_scb_address,
978 u16 asynch_buffer_address,
979 struct dsp_scb_descriptor * parent_scb,
980 int scb_child_type)
982 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
983 struct dsp_scb_descriptor * scb;
985 struct dsp_asynch_fg_rx_scb asynch_fg_rx_scb = {
986 0xfe00,0x01ff, /* Prototype sample buffer size of 128 dwords */
987 0x0064,0x001c, /* Min Delta 7 dwords == 28 bytes */
988 /* : Max delta 25 dwords == 100 bytes */
989 0,hfg_scb_address, /* Point to HFG task SCB */
990 0,0, /* Initialize current Delta and Consumer ptr adjustment count */
992 0, /* Define the unused elements */
999 0,0,
1000 0,dest,
1002 RSCONFIG_MODULO_128 |
1003 RSCONFIG_SAMPLE_16STEREO, /* Stereo, 128 dword */
1004 ( (asynch_buffer_address + (16 * 4)) << 0x10), /* This should be automagically
1005 synchrinized to the producer pointer */
1007 /* There is no correct initial value, it will depend upon the detected
1008 rate etc */
1009 0x18000000,
1011 /* Set IEC958 input volume */
1012 0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
1013 0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
1016 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_rx_scb,
1017 dest,"ASYNCHFGRXCODE",parent_scb,
1018 scb_child_type);
1020 return scb;
1024 #if 0 /* not used */
1025 struct dsp_scb_descriptor *
1026 cs46xx_dsp_create_output_snoop_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1027 u16 snoop_buffer_address,
1028 struct dsp_scb_descriptor * snoop_scb,
1029 struct dsp_scb_descriptor * parent_scb,
1030 int scb_child_type)
1033 struct dsp_scb_descriptor * scb;
1035 struct dsp_output_snoop_scb output_snoop_scb = {
1036 { 0, /* not used. Zero */
1042 0, /* not used. Zero */
1049 0,0,
1050 0,0,
1052 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
1053 snoop_buffer_address << 0x10,
1054 0,0,
1056 0,snoop_scb->address
1059 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&output_snoop_scb,
1060 dest,"OUTPUTSNOOP",parent_scb,
1061 scb_child_type);
1062 return scb;
1064 #endif /* not used */
1067 struct dsp_scb_descriptor *
1068 cs46xx_dsp_create_spio_write_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1069 struct dsp_scb_descriptor * parent_scb,
1070 int scb_child_type)
1072 struct dsp_scb_descriptor * scb;
1074 struct dsp_spio_write_scb spio_write_scb = {
1075 0,0, /* SPIOWAddress2:SPIOWAddress1; */
1076 0, /* SPIOWData1; */
1077 0, /* SPIOWData2; */
1078 0,0, /* SPIOWAddress4:SPIOWAddress3; */
1079 0, /* SPIOWData3; */
1080 0, /* SPIOWData4; */
1081 0,0, /* SPIOWDataPtr:Unused1; */
1082 { 0,0 }, /* Unused2[2]; */
1084 0,0, /* SPIOWChildPtr:SPIOWSiblingPtr; */
1085 0,0, /* SPIOWThisPtr:SPIOWEntryPoint; */
1092 0 /* Unused3[5]; */
1096 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&spio_write_scb,
1097 dest,"SPIOWRITE",parent_scb,
1098 scb_child_type);
1100 return scb;
1103 struct dsp_scb_descriptor *
1104 cs46xx_dsp_create_magic_snoop_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1105 u16 snoop_buffer_address,
1106 struct dsp_scb_descriptor * snoop_scb,
1107 struct dsp_scb_descriptor * parent_scb,
1108 int scb_child_type)
1110 struct dsp_scb_descriptor * scb;
1112 struct dsp_magic_snoop_task magic_snoop_scb = {
1113 /* 0 */ 0, /* i0 */
1114 /* 1 */ 0, /* i1 */
1115 /* 2 */ snoop_buffer_address << 0x10,
1116 /* 3 */ 0,snoop_scb->address,
1117 /* 4 */ 0, /* i3 */
1118 /* 5 */ 0, /* i4 */
1119 /* 6 */ 0, /* i5 */
1120 /* 7 */ 0, /* i6 */
1121 /* 8 */ 0, /* i7 */
1122 /* 9 */ 0,0, /* next_scb, sub_list_ptr */
1123 /* A */ 0,0, /* entry_point, this_ptr */
1124 /* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
1125 /* C */ snoop_buffer_address << 0x10,
1126 /* D */ 0,
1127 /* E */ { 0x8000,0x8000,
1128 /* F */ 0xffff,0xffff
1132 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&magic_snoop_scb,
1133 dest,"MAGICSNOOPTASK",parent_scb,
1134 scb_child_type);
1136 return scb;
1139 static struct dsp_scb_descriptor *
1140 find_next_free_scb (struct snd_cs46xx * chip, struct dsp_scb_descriptor * from)
1142 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1143 struct dsp_scb_descriptor * scb = from;
1145 while (scb->next_scb_ptr != ins->the_null_scb) {
1146 snd_assert (scb->next_scb_ptr != NULL, return NULL);
1148 scb = scb->next_scb_ptr;
1151 return scb;
1154 static u32 pcm_reader_buffer_addr[DSP_MAX_PCM_CHANNELS] = {
1155 0x0600, /* 1 */
1156 0x1500, /* 2 */
1157 0x1580, /* 3 */
1158 0x1600, /* 4 */
1159 0x1680, /* 5 */
1160 0x1700, /* 6 */
1161 0x1780, /* 7 */
1162 0x1800, /* 8 */
1163 0x1880, /* 9 */
1164 0x1900, /* 10 */
1165 0x1980, /* 11 */
1166 0x1A00, /* 12 */
1167 0x1A80, /* 13 */
1168 0x1B00, /* 14 */
1169 0x1B80, /* 15 */
1170 0x1C00, /* 16 */
1171 0x1C80, /* 17 */
1172 0x1D00, /* 18 */
1173 0x1D80, /* 19 */
1174 0x1E00, /* 20 */
1175 0x1E80, /* 21 */
1176 0x1F00, /* 22 */
1177 0x1F80, /* 23 */
1178 0x2000, /* 24 */
1179 0x2080, /* 25 */
1180 0x2100, /* 26 */
1181 0x2180, /* 27 */
1182 0x2200, /* 28 */
1183 0x2280, /* 29 */
1184 0x2300, /* 30 */
1185 0x2380, /* 31 */
1186 0x2400, /* 32 */
1189 static u32 src_output_buffer_addr[DSP_MAX_SRC_NR] = {
1190 0x2B80,
1191 0x2BA0,
1192 0x2BC0,
1193 0x2BE0,
1194 0x2D00,
1195 0x2D20,
1196 0x2D40,
1197 0x2D60,
1198 0x2D80,
1199 0x2DA0,
1200 0x2DC0,
1201 0x2DE0,
1202 0x2E00,
1203 0x2E20
1206 static u32 src_delay_buffer_addr[DSP_MAX_SRC_NR] = {
1207 0x2480,
1208 0x2500,
1209 0x2580,
1210 0x2600,
1211 0x2680,
1212 0x2700,
1213 0x2780,
1214 0x2800,
1215 0x2880,
1216 0x2900,
1217 0x2980,
1218 0x2A00,
1219 0x2A80,
1220 0x2B00
1223 struct dsp_pcm_channel_descriptor *
1224 cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
1225 u32 sample_rate, void * private_data,
1226 u32 hw_dma_addr,
1227 int pcm_channel_id)
1229 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1230 struct dsp_scb_descriptor * src_scb = NULL, * pcm_scb, * mixer_scb = NULL;
1231 struct dsp_scb_descriptor * src_parent_scb = NULL;
1233 /* struct dsp_scb_descriptor * pcm_parent_scb; */
1234 char scb_name[DSP_MAX_SCB_NAME];
1235 int i, pcm_index = -1, insert_point, src_index = -1, pass_through = 0;
1236 unsigned long flags;
1238 switch (pcm_channel_id) {
1239 case DSP_PCM_MAIN_CHANNEL:
1240 mixer_scb = ins->master_mix_scb;
1241 break;
1242 case DSP_PCM_REAR_CHANNEL:
1243 mixer_scb = ins->rear_mix_scb;
1244 break;
1245 case DSP_PCM_CENTER_LFE_CHANNEL:
1246 mixer_scb = ins->center_lfe_mix_scb;
1247 break;
1248 case DSP_PCM_S71_CHANNEL:
1249 /* TODO */
1250 snd_assert(0);
1251 break;
1252 case DSP_IEC958_CHANNEL:
1253 snd_assert (ins->asynch_tx_scb != NULL, return NULL);
1254 mixer_scb = ins->asynch_tx_scb;
1256 /* if sample rate is set to 48khz we pass
1257 the Sample Rate Converted (which could
1258 alter the raw data stream ...) */
1259 if (sample_rate == 48000) {
1260 snd_printdd ("IEC958 pass through\n");
1261 /* Hack to bypass creating a new SRC */
1262 pass_through = 1;
1264 break;
1265 default:
1266 snd_assert (0);
1267 return NULL;
1269 /* default sample rate is 44100 */
1270 if (!sample_rate) sample_rate = 44100;
1272 /* search for a already created SRC SCB with the same sample rate */
1273 for (i = 0; i < DSP_MAX_PCM_CHANNELS &&
1274 (pcm_index == -1 || src_scb == NULL); ++i) {
1276 /* virtual channel reserved
1277 for capture */
1278 if (i == CS46XX_DSP_CAPTURE_CHANNEL) continue;
1280 if (ins->pcm_channels[i].active) {
1281 if (!src_scb &&
1282 ins->pcm_channels[i].sample_rate == sample_rate &&
1283 ins->pcm_channels[i].mixer_scb == mixer_scb) {
1284 src_scb = ins->pcm_channels[i].src_scb;
1285 ins->pcm_channels[i].src_scb->ref_count ++;
1286 src_index = ins->pcm_channels[i].src_slot;
1288 } else if (pcm_index == -1) {
1289 pcm_index = i;
1293 if (pcm_index == -1) {
1294 snd_printk (KERN_ERR "dsp_spos: no free PCM channel\n");
1295 return NULL;
1298 if (src_scb == NULL) {
1299 if (ins->nsrc_scb >= DSP_MAX_SRC_NR) {
1300 snd_printk(KERN_ERR "dsp_spos: to many SRC instances\n!");
1301 return NULL;
1304 /* find a free slot */
1305 for (i = 0; i < DSP_MAX_SRC_NR; ++i) {
1306 if (ins->src_scb_slots[i] == 0) {
1307 src_index = i;
1308 ins->src_scb_slots[i] = 1;
1309 break;
1312 snd_assert (src_index != -1,return NULL);
1314 /* we need to create a new SRC SCB */
1315 if (mixer_scb->sub_list_ptr == ins->the_null_scb) {
1316 src_parent_scb = mixer_scb;
1317 insert_point = SCB_ON_PARENT_SUBLIST_SCB;
1318 } else {
1319 src_parent_scb = find_next_free_scb(chip,mixer_scb->sub_list_ptr);
1320 insert_point = SCB_ON_PARENT_NEXT_SCB;
1323 snprintf (scb_name,DSP_MAX_SCB_NAME,"SrcTask_SCB%d",src_index);
1325 snd_printdd( "dsp_spos: creating SRC \"%s\"\n",scb_name);
1326 src_scb = cs46xx_dsp_create_src_task_scb(chip,scb_name,
1327 sample_rate,
1328 src_output_buffer_addr[src_index],
1329 src_delay_buffer_addr[src_index],
1330 /* 0x400 - 0x600 source SCBs */
1331 0x400 + (src_index * 0x10) ,
1332 src_parent_scb,
1333 insert_point,
1334 pass_through);
1336 if (!src_scb) {
1337 snd_printk (KERN_ERR "dsp_spos: failed to create SRCtaskSCB\n");
1338 return NULL;
1341 /* cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate); */
1343 ins->nsrc_scb ++;
1347 snprintf (scb_name,DSP_MAX_SCB_NAME,"PCMReader_SCB%d",pcm_index);
1349 snd_printdd( "dsp_spos: creating PCM \"%s\" (%d)\n",scb_name,
1350 pcm_channel_id);
1352 pcm_scb = cs46xx_dsp_create_pcm_reader_scb(chip,scb_name,
1353 pcm_reader_buffer_addr[pcm_index],
1354 /* 0x200 - 400 PCMreader SCBs */
1355 (pcm_index * 0x10) + 0x200,
1356 pcm_index, /* virtual channel 0-31 */
1357 hw_dma_addr, /* pcm hw addr */
1358 NULL, /* parent SCB ptr */
1359 0 /* insert point */
1362 if (!pcm_scb) {
1363 snd_printk (KERN_ERR "dsp_spos: failed to create PCMreaderSCB\n");
1364 return NULL;
1367 spin_lock_irqsave(&chip->reg_lock, flags);
1368 ins->pcm_channels[pcm_index].sample_rate = sample_rate;
1369 ins->pcm_channels[pcm_index].pcm_reader_scb = pcm_scb;
1370 ins->pcm_channels[pcm_index].src_scb = src_scb;
1371 ins->pcm_channels[pcm_index].unlinked = 1;
1372 ins->pcm_channels[pcm_index].private_data = private_data;
1373 ins->pcm_channels[pcm_index].src_slot = src_index;
1374 ins->pcm_channels[pcm_index].active = 1;
1375 ins->pcm_channels[pcm_index].pcm_slot = pcm_index;
1376 ins->pcm_channels[pcm_index].mixer_scb = mixer_scb;
1377 ins->npcm_channels ++;
1378 spin_unlock_irqrestore(&chip->reg_lock, flags);
1380 return (ins->pcm_channels + pcm_index);
1383 int cs46xx_dsp_pcm_channel_set_period (struct snd_cs46xx * chip,
1384 struct dsp_pcm_channel_descriptor * pcm_channel,
1385 int period_size)
1387 u32 temp = snd_cs46xx_peek (chip,pcm_channel->pcm_reader_scb->address << 2);
1388 temp &= ~DMA_RQ_C1_SOURCE_SIZE_MASK;
1390 switch (period_size) {
1391 case 2048:
1392 temp |= DMA_RQ_C1_SOURCE_MOD1024;
1393 break;
1394 case 1024:
1395 temp |= DMA_RQ_C1_SOURCE_MOD512;
1396 break;
1397 case 512:
1398 temp |= DMA_RQ_C1_SOURCE_MOD256;
1399 break;
1400 case 256:
1401 temp |= DMA_RQ_C1_SOURCE_MOD128;
1402 break;
1403 case 128:
1404 temp |= DMA_RQ_C1_SOURCE_MOD64;
1405 break;
1406 case 64:
1407 temp |= DMA_RQ_C1_SOURCE_MOD32;
1408 break;
1409 case 32:
1410 temp |= DMA_RQ_C1_SOURCE_MOD16;
1411 break;
1412 default:
1413 snd_printdd ("period size (%d) not supported by HW\n", period_size);
1414 return -EINVAL;
1417 snd_cs46xx_poke (chip,pcm_channel->pcm_reader_scb->address << 2,temp);
1419 return 0;
1422 int cs46xx_dsp_pcm_ostream_set_period (struct snd_cs46xx * chip,
1423 int period_size)
1425 u32 temp = snd_cs46xx_peek (chip,WRITEBACK_SCB_ADDR << 2);
1426 temp &= ~DMA_RQ_C1_DEST_SIZE_MASK;
1428 switch (period_size) {
1429 case 2048:
1430 temp |= DMA_RQ_C1_DEST_MOD1024;
1431 break;
1432 case 1024:
1433 temp |= DMA_RQ_C1_DEST_MOD512;
1434 break;
1435 case 512:
1436 temp |= DMA_RQ_C1_DEST_MOD256;
1437 break;
1438 case 256:
1439 temp |= DMA_RQ_C1_DEST_MOD128;
1440 break;
1441 case 128:
1442 temp |= DMA_RQ_C1_DEST_MOD64;
1443 break;
1444 case 64:
1445 temp |= DMA_RQ_C1_DEST_MOD32;
1446 break;
1447 case 32:
1448 temp |= DMA_RQ_C1_DEST_MOD16;
1449 break;
1450 default:
1451 snd_printdd ("period size (%d) not supported by HW\n", period_size);
1452 return -EINVAL;
1455 snd_cs46xx_poke (chip,WRITEBACK_SCB_ADDR << 2,temp);
1457 return 0;
1460 void cs46xx_dsp_destroy_pcm_channel (struct snd_cs46xx * chip,
1461 struct dsp_pcm_channel_descriptor * pcm_channel)
1463 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1464 unsigned long flags;
1466 snd_assert(pcm_channel->active, return );
1467 snd_assert(ins->npcm_channels > 0, return );
1468 snd_assert(pcm_channel->src_scb->ref_count > 0, return );
1470 spin_lock_irqsave(&chip->reg_lock, flags);
1471 pcm_channel->unlinked = 1;
1472 pcm_channel->active = 0;
1473 pcm_channel->private_data = NULL;
1474 pcm_channel->src_scb->ref_count --;
1475 ins->npcm_channels --;
1476 spin_unlock_irqrestore(&chip->reg_lock, flags);
1478 cs46xx_dsp_remove_scb(chip,pcm_channel->pcm_reader_scb);
1480 if (!pcm_channel->src_scb->ref_count) {
1481 cs46xx_dsp_remove_scb(chip,pcm_channel->src_scb);
1483 snd_assert (pcm_channel->src_slot >= 0 && pcm_channel->src_slot < DSP_MAX_SRC_NR,
1484 return );
1486 ins->src_scb_slots[pcm_channel->src_slot] = 0;
1487 ins->nsrc_scb --;
1491 int cs46xx_dsp_pcm_unlink (struct snd_cs46xx * chip,
1492 struct dsp_pcm_channel_descriptor * pcm_channel)
1494 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1495 unsigned long flags;
1497 snd_assert(pcm_channel->active,return -EIO);
1498 snd_assert(ins->npcm_channels > 0,return -EIO);
1500 spin_lock(&pcm_channel->src_scb->lock);
1502 if (pcm_channel->unlinked) {
1503 spin_unlock(&pcm_channel->src_scb->lock);
1504 return -EIO;
1507 spin_lock_irqsave(&chip->reg_lock, flags);
1508 pcm_channel->unlinked = 1;
1509 spin_unlock_irqrestore(&chip->reg_lock, flags);
1511 _dsp_unlink_scb (chip,pcm_channel->pcm_reader_scb);
1513 spin_unlock(&pcm_channel->src_scb->lock);
1514 return 0;
1517 int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip,
1518 struct dsp_pcm_channel_descriptor * pcm_channel)
1520 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1521 struct dsp_scb_descriptor * parent_scb;
1522 struct dsp_scb_descriptor * src_scb = pcm_channel->src_scb;
1523 unsigned long flags;
1525 spin_lock(&pcm_channel->src_scb->lock);
1527 if (pcm_channel->unlinked == 0) {
1528 spin_unlock(&pcm_channel->src_scb->lock);
1529 return -EIO;
1532 parent_scb = src_scb;
1534 if (src_scb->sub_list_ptr != ins->the_null_scb) {
1535 src_scb->sub_list_ptr->parent_scb_ptr = pcm_channel->pcm_reader_scb;
1536 pcm_channel->pcm_reader_scb->next_scb_ptr = src_scb->sub_list_ptr;
1539 src_scb->sub_list_ptr = pcm_channel->pcm_reader_scb;
1541 snd_assert (pcm_channel->pcm_reader_scb->parent_scb_ptr == NULL, ; );
1542 pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb;
1544 spin_lock_irqsave(&chip->reg_lock, flags);
1546 /* update SCB entry in DSP RAM */
1547 cs46xx_dsp_spos_update_scb(chip,pcm_channel->pcm_reader_scb);
1549 /* update parent SCB entry */
1550 cs46xx_dsp_spos_update_scb(chip,parent_scb);
1552 pcm_channel->unlinked = 0;
1553 spin_unlock_irqrestore(&chip->reg_lock, flags);
1555 spin_unlock(&pcm_channel->src_scb->lock);
1556 return 0;
1559 struct dsp_scb_descriptor *
1560 cs46xx_add_record_source (struct snd_cs46xx *chip, struct dsp_scb_descriptor * source,
1561 u16 addr, char * scb_name)
1563 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1564 struct dsp_scb_descriptor * parent;
1565 struct dsp_scb_descriptor * pcm_input;
1566 int insert_point;
1568 snd_assert (ins->record_mixer_scb != NULL,return NULL);
1570 if (ins->record_mixer_scb->sub_list_ptr != ins->the_null_scb) {
1571 parent = find_next_free_scb (chip,ins->record_mixer_scb->sub_list_ptr);
1572 insert_point = SCB_ON_PARENT_NEXT_SCB;
1573 } else {
1574 parent = ins->record_mixer_scb;
1575 insert_point = SCB_ON_PARENT_SUBLIST_SCB;
1578 pcm_input = cs46xx_dsp_create_pcm_serial_input_scb(chip,scb_name,addr,
1579 source, parent,
1580 insert_point);
1582 return pcm_input;
1585 int cs46xx_src_unlink(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
1587 snd_assert (src->parent_scb_ptr != NULL, return -EINVAL );
1589 /* mute SCB */
1590 cs46xx_dsp_scb_set_volume (chip,src,0,0);
1592 _dsp_unlink_scb (chip,src);
1594 return 0;
1597 int cs46xx_src_link(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
1599 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1600 struct dsp_scb_descriptor * parent_scb;
1602 snd_assert (src->parent_scb_ptr == NULL, return -EINVAL );
1603 snd_assert(ins->master_mix_scb !=NULL, return -EINVAL );
1605 if (ins->master_mix_scb->sub_list_ptr != ins->the_null_scb) {
1606 parent_scb = find_next_free_scb (chip,ins->master_mix_scb->sub_list_ptr);
1607 parent_scb->next_scb_ptr = src;
1608 } else {
1609 parent_scb = ins->master_mix_scb;
1610 parent_scb->sub_list_ptr = src;
1613 src->parent_scb_ptr = parent_scb;
1615 /* update entry in DSP RAM */
1616 cs46xx_dsp_spos_update_scb(chip,parent_scb);
1618 return 0;
1621 int cs46xx_dsp_enable_spdif_out (struct snd_cs46xx *chip)
1623 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1625 if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
1626 cs46xx_dsp_enable_spdif_hw (chip);
1629 /* dont touch anything if SPDIF is open */
1630 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
1631 /* when cs46xx_iec958_post_close(...) is called it
1632 will call this function if necessary depending on
1633 this bit */
1634 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1636 return -EBUSY;
1639 snd_assert (ins->asynch_tx_scb == NULL, return -EINVAL);
1640 snd_assert (ins->master_mix_scb->next_scb_ptr == ins->the_null_scb, return -EINVAL);
1642 /* reset output snooper sample buffer pointer */
1643 snd_cs46xx_poke (chip, (ins->ref_snoop_scb->address + 2) << 2,
1644 (OUTPUT_SNOOP_BUFFER + 0x10) << 0x10 );
1646 /* The asynch. transfer task */
1647 ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
1648 SPDIFO_SCB_INST,
1649 SPDIFO_IP_OUTPUT_BUFFER1,
1650 ins->master_mix_scb,
1651 SCB_ON_PARENT_NEXT_SCB);
1652 if (!ins->asynch_tx_scb) return -ENOMEM;
1654 ins->spdif_pcm_input_scb = cs46xx_dsp_create_pcm_serial_input_scb(chip,"PCMSerialInput_II",
1655 PCMSERIALINII_SCB_ADDR,
1656 ins->ref_snoop_scb,
1657 ins->asynch_tx_scb,
1658 SCB_ON_PARENT_SUBLIST_SCB);
1661 if (!ins->spdif_pcm_input_scb) return -ENOMEM;
1663 /* monitor state */
1664 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1666 return 0;
1669 int cs46xx_dsp_disable_spdif_out (struct snd_cs46xx *chip)
1671 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1673 /* dont touch anything if SPDIF is open */
1674 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
1675 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1676 return -EBUSY;
1679 /* check integrety */
1680 snd_assert (ins->asynch_tx_scb != NULL, return -EINVAL);
1681 snd_assert (ins->spdif_pcm_input_scb != NULL,return -EINVAL);
1682 snd_assert (ins->master_mix_scb->next_scb_ptr == ins->asynch_tx_scb, return -EINVAL);
1683 snd_assert (ins->asynch_tx_scb->parent_scb_ptr == ins->master_mix_scb, return -EINVAL);
1685 cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
1686 cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
1688 ins->spdif_pcm_input_scb = NULL;
1689 ins->asynch_tx_scb = NULL;
1691 /* clear buffer to prevent any undesired noise */
1692 _dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
1694 /* monitor state */
1695 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1698 return 0;
1701 int cs46xx_iec958_pre_open (struct snd_cs46xx *chip)
1703 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1705 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
1706 /* remove AsynchFGTxSCB and and PCMSerialInput_II */
1707 cs46xx_dsp_disable_spdif_out (chip);
1709 /* save state */
1710 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1713 /* if not enabled already */
1714 if ( !(ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
1715 cs46xx_dsp_enable_spdif_hw (chip);
1718 /* Create the asynch. transfer task for playback */
1719 ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
1720 SPDIFO_SCB_INST,
1721 SPDIFO_IP_OUTPUT_BUFFER1,
1722 ins->master_mix_scb,
1723 SCB_ON_PARENT_NEXT_SCB);
1726 /* set spdif channel status value for streaming */
1727 cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_stream);
1729 ins->spdif_status_out |= DSP_SPDIF_STATUS_PLAYBACK_OPEN;
1731 return 0;
1734 int cs46xx_iec958_post_close (struct snd_cs46xx *chip)
1736 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1738 snd_assert (ins->asynch_tx_scb != NULL, return -EINVAL);
1740 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_PLAYBACK_OPEN;
1742 /* restore settings */
1743 cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);
1745 /* deallocate stuff */
1746 if (ins->spdif_pcm_input_scb != NULL) {
1747 cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
1748 ins->spdif_pcm_input_scb = NULL;
1751 cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
1752 ins->asynch_tx_scb = NULL;
1754 /* clear buffer to prevent any undesired noise */
1755 _dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
1757 /* restore state */
1758 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
1759 cs46xx_dsp_enable_spdif_out (chip);
1762 return 0;