Committer: Michael Beasley <mike@snafu.setup>
[mikesnafu-overlay.git] / sound / pci / cs46xx / dsp_spos_scb_lib.c
blob2873cfe48c331605f50d23f84350ba4865ce9750
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 snd_assert(ins->symbol_table.nsymbols > 0,return);
50 snd_assert(symbol_index >= 0 && symbol_index < ins->symbol_table.nsymbols, return);
52 ins->symbol_table.symbols[symbol_index].deleted = 1;
54 if (symbol_index < ins->symbol_table.highest_frag_index) {
55 ins->symbol_table.highest_frag_index = symbol_index;
58 if (symbol_index == ins->symbol_table.nsymbols - 1)
59 ins->symbol_table.nsymbols --;
61 if (ins->symbol_table.highest_frag_index > ins->symbol_table.nsymbols) {
62 ins->symbol_table.highest_frag_index = ins->symbol_table.nsymbols;
67 #ifdef CONFIG_PROC_FS
68 static void cs46xx_dsp_proc_scb_info_read (struct snd_info_entry *entry,
69 struct snd_info_buffer *buffer)
71 struct proc_scb_info * scb_info = entry->private_data;
72 struct dsp_scb_descriptor * scb = scb_info->scb_desc;
73 struct dsp_spos_instance * ins;
74 struct snd_cs46xx *chip = scb_info->chip;
75 int j,col;
76 void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
78 ins = chip->dsp_spos_instance;
80 mutex_lock(&chip->spos_mutex);
81 snd_iprintf(buffer,"%04x %s:\n",scb->address,scb->scb_name);
83 for (col = 0,j = 0;j < 0x10; j++,col++) {
84 if (col == 4) {
85 snd_iprintf(buffer,"\n");
86 col = 0;
88 snd_iprintf(buffer,"%08x ",readl(dst + (scb->address + j) * sizeof(u32)));
91 snd_iprintf(buffer,"\n");
93 if (scb->parent_scb_ptr != NULL) {
94 snd_iprintf(buffer,"parent [%s:%04x] ",
95 scb->parent_scb_ptr->scb_name,
96 scb->parent_scb_ptr->address);
97 } else snd_iprintf(buffer,"parent [none] ");
99 snd_iprintf(buffer,"sub_list_ptr [%s:%04x]\nnext_scb_ptr [%s:%04x] task_entry [%s:%04x]\n",
100 scb->sub_list_ptr->scb_name,
101 scb->sub_list_ptr->address,
102 scb->next_scb_ptr->scb_name,
103 scb->next_scb_ptr->address,
104 scb->task_entry->symbol_name,
105 scb->task_entry->address);
107 snd_iprintf(buffer,"index [%d] ref_count [%d]\n",scb->index,scb->ref_count);
108 mutex_unlock(&chip->spos_mutex);
110 #endif
112 static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
114 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
115 unsigned long flags;
117 if ( scb->parent_scb_ptr ) {
118 /* unlink parent SCB */
119 snd_assert ((scb->parent_scb_ptr->sub_list_ptr == scb ||
120 scb->parent_scb_ptr->next_scb_ptr == scb),return);
122 if (scb->parent_scb_ptr->sub_list_ptr == scb) {
124 if (scb->next_scb_ptr == ins->the_null_scb) {
125 /* last and only node in parent sublist */
126 scb->parent_scb_ptr->sub_list_ptr = scb->sub_list_ptr;
128 if (scb->sub_list_ptr != ins->the_null_scb) {
129 scb->sub_list_ptr->parent_scb_ptr = scb->parent_scb_ptr;
131 scb->sub_list_ptr = ins->the_null_scb;
132 } else {
133 /* first node in parent sublist */
134 scb->parent_scb_ptr->sub_list_ptr = scb->next_scb_ptr;
136 if (scb->next_scb_ptr != ins->the_null_scb) {
137 /* update next node parent ptr. */
138 scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
140 scb->next_scb_ptr = ins->the_null_scb;
142 } else {
143 /* snd_assert ( (scb->sub_list_ptr == ins->the_null_scb), return); */
144 scb->parent_scb_ptr->next_scb_ptr = scb->next_scb_ptr;
146 if (scb->next_scb_ptr != ins->the_null_scb) {
147 /* update next node parent ptr. */
148 scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
150 scb->next_scb_ptr = ins->the_null_scb;
153 spin_lock_irqsave(&chip->reg_lock, flags);
155 /* update parent first entry in DSP RAM */
156 cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
158 /* then update entry in DSP RAM */
159 cs46xx_dsp_spos_update_scb(chip,scb);
161 scb->parent_scb_ptr = NULL;
162 spin_unlock_irqrestore(&chip->reg_lock, flags);
166 static void _dsp_clear_sample_buffer (struct snd_cs46xx *chip, u32 sample_buffer_addr,
167 int dword_count)
169 void __iomem *dst = chip->region.idx[2].remap_addr + sample_buffer_addr;
170 int i;
172 for (i = 0; i < dword_count ; ++i ) {
173 writel(0, dst);
174 dst += 4;
178 void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
180 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
181 unsigned long flags;
183 /* check integrety */
184 snd_assert ( (scb->index >= 0 &&
185 scb->index < ins->nscb &&
186 (ins->scbs + scb->index) == scb), return );
188 #if 0
189 /* can't remove a SCB with childs before
190 removing childs first */
191 snd_assert ( (scb->sub_list_ptr == ins->the_null_scb &&
192 scb->next_scb_ptr == ins->the_null_scb),
193 goto _end);
194 #endif
196 spin_lock_irqsave(&scb->lock, flags);
197 _dsp_unlink_scb (chip,scb);
198 spin_unlock_irqrestore(&scb->lock, flags);
200 cs46xx_dsp_proc_free_scb_desc(scb);
201 snd_assert (scb->scb_symbol != NULL, return );
202 remove_symbol (chip,scb->scb_symbol);
204 ins->scbs[scb->index].deleted = 1;
206 if (scb->index < ins->scb_highest_frag_index)
207 ins->scb_highest_frag_index = scb->index;
209 if (scb->index == ins->nscb - 1) {
210 ins->nscb --;
213 if (ins->scb_highest_frag_index > ins->nscb) {
214 ins->scb_highest_frag_index = ins->nscb;
217 #if 0
218 /* !!!! THIS IS A PIECE OF SHIT MADE BY ME !!! */
219 for(i = scb->index + 1;i < ins->nscb; ++i) {
220 ins->scbs[i - 1].index = i - 1;
222 #endif
226 #ifdef CONFIG_PROC_FS
227 void cs46xx_dsp_proc_free_scb_desc (struct dsp_scb_descriptor * scb)
229 if (scb->proc_info) {
230 struct proc_scb_info * scb_info = scb->proc_info->private_data;
232 snd_printdd("cs46xx_dsp_proc_free_scb_desc: freeing %s\n",scb->scb_name);
234 snd_info_free_entry(scb->proc_info);
235 scb->proc_info = NULL;
237 snd_assert (scb_info != NULL, return);
238 kfree (scb_info);
242 void cs46xx_dsp_proc_register_scb_desc (struct snd_cs46xx *chip,
243 struct dsp_scb_descriptor * scb)
245 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
246 struct snd_info_entry * entry;
247 struct proc_scb_info * scb_info;
249 /* register to proc */
250 if (ins->snd_card != NULL && ins->proc_dsp_dir != NULL &&
251 scb->proc_info == NULL) {
253 if ((entry = snd_info_create_card_entry(ins->snd_card, scb->scb_name,
254 ins->proc_dsp_dir)) != NULL) {
255 scb_info = kmalloc(sizeof(struct proc_scb_info), GFP_KERNEL);
256 if (!scb_info) {
257 snd_info_free_entry(entry);
258 entry = NULL;
259 goto out;
262 scb_info->chip = chip;
263 scb_info->scb_desc = scb;
265 entry->content = SNDRV_INFO_CONTENT_TEXT;
266 entry->private_data = scb_info;
267 entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
269 entry->c.text.read = cs46xx_dsp_proc_scb_info_read;
271 if (snd_info_register(entry) < 0) {
272 snd_info_free_entry(entry);
273 kfree (scb_info);
274 entry = NULL;
277 out:
278 scb->proc_info = entry;
281 #endif /* CONFIG_PROC_FS */
283 static struct dsp_scb_descriptor *
284 _dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32 dest,
285 struct dsp_symbol_entry * task_entry,
286 struct dsp_scb_descriptor * parent_scb,
287 int scb_child_type)
289 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
290 struct dsp_scb_descriptor * scb;
292 unsigned long flags;
294 snd_assert (ins->the_null_scb != NULL,return NULL);
296 /* fill the data that will be wroten to DSP */
297 scb_data[SCBsubListPtr] =
298 (ins->the_null_scb->address << 0x10) | ins->the_null_scb->address;
300 scb_data[SCBfuncEntryPtr] &= 0xFFFF0000;
301 scb_data[SCBfuncEntryPtr] |= task_entry->address;
303 snd_printdd("dsp_spos: creating SCB <%s>\n",name);
305 scb = cs46xx_dsp_create_scb(chip,name,scb_data,dest);
308 scb->sub_list_ptr = ins->the_null_scb;
309 scb->next_scb_ptr = ins->the_null_scb;
311 scb->parent_scb_ptr = parent_scb;
312 scb->task_entry = task_entry;
315 /* update parent SCB */
316 if (scb->parent_scb_ptr) {
317 #if 0
318 printk ("scb->parent_scb_ptr = %s\n",scb->parent_scb_ptr->scb_name);
319 printk ("scb->parent_scb_ptr->next_scb_ptr = %s\n",scb->parent_scb_ptr->next_scb_ptr->scb_name);
320 printk ("scb->parent_scb_ptr->sub_list_ptr = %s\n",scb->parent_scb_ptr->sub_list_ptr->scb_name);
321 #endif
322 /* link to parent SCB */
323 if (scb_child_type == SCB_ON_PARENT_NEXT_SCB) {
324 snd_assert ( (scb->parent_scb_ptr->next_scb_ptr == ins->the_null_scb),
325 return NULL);
327 scb->parent_scb_ptr->next_scb_ptr = scb;
329 } else if (scb_child_type == SCB_ON_PARENT_SUBLIST_SCB) {
330 snd_assert ( (scb->parent_scb_ptr->sub_list_ptr == ins->the_null_scb),
331 return NULL);
333 scb->parent_scb_ptr->sub_list_ptr = scb;
334 } else {
335 snd_assert (0,return NULL);
338 spin_lock_irqsave(&chip->reg_lock, flags);
340 /* update entry in DSP RAM */
341 cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
343 spin_unlock_irqrestore(&chip->reg_lock, flags);
347 cs46xx_dsp_proc_register_scb_desc (chip,scb);
349 return scb;
352 static struct dsp_scb_descriptor *
353 cs46xx_dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data,
354 u32 dest, char * task_entry_name,
355 struct dsp_scb_descriptor * parent_scb,
356 int scb_child_type)
358 struct dsp_symbol_entry * task_entry;
360 task_entry = cs46xx_dsp_lookup_symbol (chip,task_entry_name,
361 SYMBOL_CODE);
363 if (task_entry == NULL) {
364 snd_printk (KERN_ERR "dsp_spos: symbol %s not found\n",task_entry_name);
365 return NULL;
368 return _dsp_create_generic_scb (chip,name,scb_data,dest,task_entry,
369 parent_scb,scb_child_type);
372 struct dsp_scb_descriptor *
373 cs46xx_dsp_create_timing_master_scb (struct snd_cs46xx *chip)
375 struct dsp_scb_descriptor * scb;
377 struct dsp_timing_master_scb timing_master_scb = {
378 { 0,
383 { 0,
389 0,0,
390 0,NULL_SCB_ADDR,
391 0,0, /* extraSampleAccum:TMreserved */
392 0,0, /* codecFIFOptr:codecFIFOsyncd */
393 0x0001,0x8000, /* fracSampAccumQm1:TMfrmsLeftInGroup */
394 0x0001,0x0000, /* fracSampCorrectionQm1:TMfrmGroupLength */
395 0x00060000 /* nSampPerFrmQ15 */
398 scb = cs46xx_dsp_create_generic_scb(chip,"TimingMasterSCBInst",(u32 *)&timing_master_scb,
399 TIMINGMASTER_SCB_ADDR,
400 "TIMINGMASTER",NULL,SCB_NO_PARENT);
402 return scb;
406 struct dsp_scb_descriptor *
407 cs46xx_dsp_create_codec_out_scb(struct snd_cs46xx * chip, char * codec_name,
408 u16 channel_disp, u16 fifo_addr, u16 child_scb_addr,
409 u32 dest, struct dsp_scb_descriptor * parent_scb,
410 int scb_child_type)
412 struct dsp_scb_descriptor * scb;
414 struct dsp_codec_output_scb codec_out_scb = {
415 { 0,
427 0,0,
428 0,NULL_SCB_ADDR,
429 0, /* COstrmRsConfig */
430 0, /* COstrmBufPtr */
431 channel_disp,fifo_addr, /* leftChanBaseIOaddr:rightChanIOdisp */
432 0x0000,0x0080, /* (!AC97!) COexpVolChangeRate:COscaleShiftCount */
433 0,child_scb_addr /* COreserved - need child scb to work with rom code */
437 scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_out_scb,
438 dest,"S16_CODECOUTPUTTASK",parent_scb,
439 scb_child_type);
441 return scb;
444 struct dsp_scb_descriptor *
445 cs46xx_dsp_create_codec_in_scb(struct snd_cs46xx * chip, char * codec_name,
446 u16 channel_disp, u16 fifo_addr, u16 sample_buffer_addr,
447 u32 dest, struct dsp_scb_descriptor * parent_scb,
448 int scb_child_type)
451 struct dsp_scb_descriptor * scb;
452 struct dsp_codec_input_scb codec_input_scb = {
453 { 0,
466 #if 0 /* cs4620 */
467 SyncIOSCB,NULL_SCB_ADDR
468 #else
469 0 , 0,
470 #endif
471 0,0,
473 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64, /* strmRsConfig */
474 sample_buffer_addr << 0x10, /* strmBufPtr; defined as a dword ptr, used as a byte ptr */
475 channel_disp,fifo_addr, /* (!AC97!) leftChanBaseINaddr=AC97primary
476 link input slot 3 :rightChanINdisp=""slot 4 */
477 0x0000,0x0000, /* (!AC97!) ????:scaleShiftCount; no shift needed
478 because AC97 is already 20 bits */
479 0x80008000 /* ??clw cwcgame.scb has 0 */
482 scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_input_scb,
483 dest,"S16_CODECINPUTTASK",parent_scb,
484 scb_child_type);
485 return scb;
489 static struct dsp_scb_descriptor *
490 cs46xx_dsp_create_pcm_reader_scb(struct snd_cs46xx * chip, char * scb_name,
491 u16 sample_buffer_addr, u32 dest,
492 int virtual_channel, u32 playback_hw_addr,
493 struct dsp_scb_descriptor * parent_scb,
494 int scb_child_type)
496 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
497 struct dsp_scb_descriptor * scb;
499 struct dsp_generic_scb pcm_reader_scb = {
502 Play DMA Task xfers data from host buffer to SP buffer
503 init/runtime variables:
504 PlayAC: Play Audio Data Conversion - SCB loc: 2nd dword, mask: 0x0000F000L
505 DATA_FMT_16BIT_ST_LTLEND(0x00000000L) from 16-bit stereo, little-endian
506 DATA_FMT_8_BIT_ST_SIGNED(0x00001000L) from 8-bit stereo, signed
507 DATA_FMT_16BIT_MN_LTLEND(0x00002000L) from 16-bit mono, little-endian
508 DATA_FMT_8_BIT_MN_SIGNED(0x00003000L) from 8-bit mono, signed
509 DATA_FMT_16BIT_ST_BIGEND(0x00004000L) from 16-bit stereo, big-endian
510 DATA_FMT_16BIT_MN_BIGEND(0x00006000L) from 16-bit mono, big-endian
511 DATA_FMT_8_BIT_ST_UNSIGNED(0x00009000L) from 8-bit stereo, unsigned
512 DATA_FMT_8_BIT_MN_UNSIGNED(0x0000b000L) from 8-bit mono, unsigned
513 ? Other combinations possible from:
514 DMA_RQ_C2_AUDIO_CONVERT_MASK 0x0000F000L
515 DMA_RQ_C2_AC_NONE 0x00000000L
516 DMA_RQ_C2_AC_8_TO_16_BIT 0x00001000L
517 DMA_RQ_C2_AC_MONO_TO_STEREO 0x00002000L
518 DMA_RQ_C2_AC_ENDIAN_CONVERT 0x00004000L
519 DMA_RQ_C2_AC_SIGNED_CONVERT 0x00008000L
521 HostBuffAddr: Host Buffer Physical Byte Address - SCB loc:3rd dword, Mask: 0xFFFFFFFFL
522 aligned to dword boundary
524 /* Basic (non scatter/gather) DMA requestor (4 ints) */
525 { DMA_RQ_C1_SOURCE_ON_HOST + /* source buffer is on the host */
526 DMA_RQ_C1_SOURCE_MOD1024 + /* source buffer is 1024 dwords (4096 bytes) */
527 DMA_RQ_C1_DEST_MOD32 + /* dest buffer(PCMreaderBuf) is 32 dwords*/
528 DMA_RQ_C1_WRITEBACK_SRC_FLAG + /* ?? */
529 DMA_RQ_C1_WRITEBACK_DEST_FLAG + /* ?? */
530 15, /* DwordCount-1: picked 16 for DwordCount because Jim */
531 /* Barnette said that is what we should use since */
532 /* we are not running in optimized mode? */
533 DMA_RQ_C2_AC_NONE +
534 DMA_RQ_C2_SIGNAL_SOURCE_PINGPONG + /* set play interrupt (bit0) in HISR when source */
535 /* buffer (on host) crosses half-way point */
536 virtual_channel, /* Play DMA channel arbitrarily set to 0 */
537 playback_hw_addr, /* HostBuffAddr (source) */
538 DMA_RQ_SD_SP_SAMPLE_ADDR + /* destination buffer is in SP Sample Memory */
539 sample_buffer_addr /* SP Buffer Address (destination) */
541 /* Scatter/gather DMA requestor extension (5 ints) */
549 /* Sublist pointer & next stream control block (SCB) link. */
550 NULL_SCB_ADDR,NULL_SCB_ADDR,
551 /* Pointer to this tasks parameter block & stream function pointer */
552 0,NULL_SCB_ADDR,
553 /* rsConfig register for stream buffer (rsDMA reg. is loaded from basicReq.daw */
554 /* for incoming streams, or basicReq.saw, for outgoing streams) */
555 RSCONFIG_DMA_ENABLE + /* enable DMA */
556 (19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) + /* MAX_DMA_SIZE picked to be 19 since SPUD */
557 /* uses it for some reason */
558 ((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) + /* stream number = SCBaddr/16 */
559 RSCONFIG_SAMPLE_16STEREO +
560 RSCONFIG_MODULO_32, /* dest buffer(PCMreaderBuf) is 32 dwords (256 bytes) */
561 /* Stream sample pointer & MAC-unit mode for this stream */
562 (sample_buffer_addr << 0x10),
563 /* Fractional increment per output sample in the input sample buffer */
566 /* Standard stereo volume control
567 default muted */
568 0xffff,0xffff,
569 0xffff,0xffff
573 if (ins->null_algorithm == NULL) {
574 ins->null_algorithm = cs46xx_dsp_lookup_symbol (chip,"NULLALGORITHM",
575 SYMBOL_CODE);
577 if (ins->null_algorithm == NULL) {
578 snd_printk (KERN_ERR "dsp_spos: symbol NULLALGORITHM not found\n");
579 return NULL;
583 scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_reader_scb,
584 dest,ins->null_algorithm,parent_scb,
585 scb_child_type);
587 return scb;
590 #define GOF_PER_SEC 200
592 struct dsp_scb_descriptor *
593 cs46xx_dsp_create_src_task_scb(struct snd_cs46xx * chip, char * scb_name,
594 int rate,
595 u16 src_buffer_addr,
596 u16 src_delay_buffer_addr, u32 dest,
597 struct dsp_scb_descriptor * parent_scb,
598 int scb_child_type,
599 int pass_through)
602 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
603 struct dsp_scb_descriptor * scb;
604 unsigned int tmp1, tmp2;
605 unsigned int phiIncr;
606 unsigned int correctionPerGOF, correctionPerSec;
608 snd_printdd( "dsp_spos: setting %s rate to %u\n",scb_name,rate);
611 * Compute the values used to drive the actual sample rate conversion.
612 * The following formulas are being computed, using inline assembly
613 * since we need to use 64 bit arithmetic to compute the values:
615 * phiIncr = floor((Fs,in * 2^26) / Fs,out)
616 * correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) /
617 * GOF_PER_SEC)
618 * ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -M
619 * GOF_PER_SEC * correctionPerGOF
621 * i.e.
623 * phiIncr:other = dividend:remainder((Fs,in * 2^26) / Fs,out)
624 * correctionPerGOF:correctionPerSec =
625 * dividend:remainder(ulOther / GOF_PER_SEC)
627 tmp1 = rate << 16;
628 phiIncr = tmp1 / 48000;
629 tmp1 -= phiIncr * 48000;
630 tmp1 <<= 10;
631 phiIncr <<= 10;
632 tmp2 = tmp1 / 48000;
633 phiIncr += tmp2;
634 tmp1 -= tmp2 * 48000;
635 correctionPerGOF = tmp1 / GOF_PER_SEC;
636 tmp1 -= correctionPerGOF * GOF_PER_SEC;
637 correctionPerSec = tmp1;
640 struct dsp_src_task_scb src_task_scb = {
641 0x0028,0x00c8,
642 0x5555,0x0000,
643 0x0000,0x0000,
644 src_buffer_addr,1,
645 correctionPerGOF,correctionPerSec,
646 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
647 0x0000,src_delay_buffer_addr,
648 0x0,
649 0x080,(src_delay_buffer_addr + (24 * 4)),
650 0,0, /* next_scb, sub_list_ptr */
651 0,0, /* entry, this_spb */
652 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
653 src_buffer_addr << 0x10,
654 phiIncr,
656 0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left,
657 0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left
661 if (ins->s16_up == NULL) {
662 ins->s16_up = cs46xx_dsp_lookup_symbol (chip,"S16_UPSRC",
663 SYMBOL_CODE);
665 if (ins->s16_up == NULL) {
666 snd_printk (KERN_ERR "dsp_spos: symbol S16_UPSRC not found\n");
667 return NULL;
671 /* clear buffers */
672 _dsp_clear_sample_buffer (chip,src_buffer_addr,8);
673 _dsp_clear_sample_buffer (chip,src_delay_buffer_addr,32);
675 if (pass_through) {
676 /* wont work with any other rate than
677 the native DSP rate */
678 snd_assert (rate == 48000);
680 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
681 dest,"DMAREADER",parent_scb,
682 scb_child_type);
683 } else {
684 scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
685 dest,ins->s16_up,parent_scb,
686 scb_child_type);
692 return scb;
695 #if 0 /* not used */
696 struct dsp_scb_descriptor *
697 cs46xx_dsp_create_filter_scb(struct snd_cs46xx * chip, char * scb_name,
698 u16 buffer_addr, u32 dest,
699 struct dsp_scb_descriptor * parent_scb,
700 int scb_child_type) {
701 struct dsp_scb_descriptor * scb;
703 struct dsp_filter_scb filter_scb = {
704 .a0_right = 0x41a9,
705 .a0_left = 0x41a9,
706 .a1_right = 0xb8e4,
707 .a1_left = 0xb8e4,
708 .a2_right = 0x3e55,
709 .a2_left = 0x3e55,
711 .filter_unused3 = 0x0000,
712 .filter_unused2 = 0x0000,
714 .output_buf_ptr = buffer_addr,
715 .init = 0x000,
717 .prev_sample_output1 = 0x00000000,
718 .prev_sample_output2 = 0x00000000,
720 .prev_sample_input1 = 0x00000000,
721 .prev_sample_input2 = 0x00000000,
723 .next_scb_ptr = 0x0000,
724 .sub_list_ptr = 0x0000,
726 .entry_point = 0x0000,
727 .spb_ptr = 0x0000,
729 .b0_right = 0x0e38,
730 .b0_left = 0x0e38,
731 .b1_right = 0x1c71,
732 .b1_left = 0x1c71,
733 .b2_right = 0x0e38,
734 .b2_left = 0x0e38,
738 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&filter_scb,
739 dest,"FILTERTASK",parent_scb,
740 scb_child_type);
742 return scb;
744 #endif /* not used */
746 struct dsp_scb_descriptor *
747 cs46xx_dsp_create_mix_only_scb(struct snd_cs46xx * chip, char * scb_name,
748 u16 mix_buffer_addr, u32 dest,
749 struct dsp_scb_descriptor * parent_scb,
750 int scb_child_type)
752 struct dsp_scb_descriptor * scb;
754 struct dsp_mix_only_scb master_mix_scb = {
755 /* 0 */ { 0,
756 /* 1 */ 0,
757 /* 2 */ mix_buffer_addr,
758 /* 3 */ 0
759 /* */ },
761 /* 4 */ 0,
762 /* 5 */ 0,
763 /* 6 */ 0,
764 /* 7 */ 0,
765 /* 8 */ 0x00000080
767 /* 9 */ 0,0,
768 /* A */ 0,0,
769 /* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
770 /* C */ (mix_buffer_addr + (16 * 4)) << 0x10,
771 /* D */ 0,
773 /* E */ 0x8000,0x8000,
774 /* F */ 0x8000,0x8000
779 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&master_mix_scb,
780 dest,"S16_MIX",parent_scb,
781 scb_child_type);
782 return scb;
786 struct dsp_scb_descriptor *
787 cs46xx_dsp_create_mix_to_ostream_scb(struct snd_cs46xx * chip, char * scb_name,
788 u16 mix_buffer_addr, u16 writeback_spb, u32 dest,
789 struct dsp_scb_descriptor * parent_scb,
790 int scb_child_type)
792 struct dsp_scb_descriptor * scb;
794 struct dsp_mix2_ostream_scb mix2_ostream_scb = {
795 /* Basic (non scatter/gather) DMA requestor (4 ints) */
797 DMA_RQ_C1_SOURCE_MOD64 +
798 DMA_RQ_C1_DEST_ON_HOST +
799 DMA_RQ_C1_DEST_MOD1024 +
800 DMA_RQ_C1_WRITEBACK_SRC_FLAG +
801 DMA_RQ_C1_WRITEBACK_DEST_FLAG +
802 15,
804 DMA_RQ_C2_AC_NONE +
805 DMA_RQ_C2_SIGNAL_DEST_PINGPONG +
807 CS46XX_DSP_CAPTURE_CHANNEL,
808 DMA_RQ_SD_SP_SAMPLE_ADDR +
809 mix_buffer_addr,
810 0x0
813 { 0, 0, 0, 0, 0, },
814 0,0,
815 0,writeback_spb,
817 RSCONFIG_DMA_ENABLE +
818 (19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) +
820 ((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) +
821 RSCONFIG_DMA_TO_HOST +
822 RSCONFIG_SAMPLE_16STEREO +
823 RSCONFIG_MODULO_64,
824 (mix_buffer_addr + (32 * 4)) << 0x10,
825 1,0,
826 0x0001,0x0080,
827 0xFFFF,0
831 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&mix2_ostream_scb,
833 dest,"S16_MIX_TO_OSTREAM",parent_scb,
834 scb_child_type);
836 return scb;
840 struct dsp_scb_descriptor *
841 cs46xx_dsp_create_vari_decimate_scb(struct snd_cs46xx * chip,char * scb_name,
842 u16 vari_buffer_addr0,
843 u16 vari_buffer_addr1,
844 u32 dest,
845 struct dsp_scb_descriptor * parent_scb,
846 int scb_child_type)
849 struct dsp_scb_descriptor * scb;
851 struct dsp_vari_decimate_scb vari_decimate_scb = {
852 0x0028,0x00c8,
853 0x5555,0x0000,
854 0x0000,0x0000,
855 vari_buffer_addr0,vari_buffer_addr1,
857 0x0028,0x00c8,
858 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256,
860 0xFF800000,
862 0x0080,vari_buffer_addr1 + (25 * 4),
864 0,0,
865 0,0,
867 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
868 vari_buffer_addr0 << 0x10,
869 0x04000000,
871 0x8000,0x8000,
872 0xFFFF,0xFFFF
876 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&vari_decimate_scb,
877 dest,"VARIDECIMATE",parent_scb,
878 scb_child_type);
880 return scb;
884 static struct dsp_scb_descriptor *
885 cs46xx_dsp_create_pcm_serial_input_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
886 struct dsp_scb_descriptor * input_scb,
887 struct dsp_scb_descriptor * parent_scb,
888 int scb_child_type)
891 struct dsp_scb_descriptor * scb;
894 struct dsp_pcm_serial_input_scb pcm_serial_input_scb = {
895 { 0,
908 0,0,
909 0,0,
911 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_16,
913 /* 0xD */ 0,input_scb->address,
915 /* 0xE */ 0x8000,0x8000,
916 /* 0xF */ 0x8000,0x8000
920 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_serial_input_scb,
921 dest,"PCMSERIALINPUTTASK",parent_scb,
922 scb_child_type);
923 return scb;
927 static struct dsp_scb_descriptor *
928 cs46xx_dsp_create_asynch_fg_tx_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
929 u16 hfg_scb_address,
930 u16 asynch_buffer_address,
931 struct dsp_scb_descriptor * parent_scb,
932 int scb_child_type)
935 struct dsp_scb_descriptor * scb;
937 struct dsp_asynch_fg_tx_scb asynch_fg_tx_scb = {
938 0xfc00,0x03ff, /* Prototype sample buffer size of 256 dwords */
939 0x0058,0x0028, /* Min Delta 7 dwords == 28 bytes */
940 /* : Max delta 25 dwords == 100 bytes */
941 0,hfg_scb_address, /* Point to HFG task SCB */
942 0,0, /* Initialize current Delta and Consumer ptr adjustment count */
943 0, /* Initialize accumulated Phi to 0 */
944 0,0x2aab, /* Const 1/3 */
947 0, /* Define the unused elements */
952 0,0,
953 0,dest + AFGTxAccumPhi,
955 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256, /* Stereo, 256 dword */
956 (asynch_buffer_address) << 0x10, /* This should be automagically synchronized
957 to the producer pointer */
959 /* There is no correct initial value, it will depend upon the detected
960 rate etc */
961 0x18000000, /* Phi increment for approx 32k operation */
962 0x8000,0x8000, /* Volume controls are unused at this time */
963 0x8000,0x8000
966 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_tx_scb,
967 dest,"ASYNCHFGTXCODE",parent_scb,
968 scb_child_type);
970 return scb;
974 struct dsp_scb_descriptor *
975 cs46xx_dsp_create_asynch_fg_rx_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
976 u16 hfg_scb_address,
977 u16 asynch_buffer_address,
978 struct dsp_scb_descriptor * parent_scb,
979 int scb_child_type)
981 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
982 struct dsp_scb_descriptor * scb;
984 struct dsp_asynch_fg_rx_scb asynch_fg_rx_scb = {
985 0xfe00,0x01ff, /* Prototype sample buffer size of 128 dwords */
986 0x0064,0x001c, /* Min Delta 7 dwords == 28 bytes */
987 /* : Max delta 25 dwords == 100 bytes */
988 0,hfg_scb_address, /* Point to HFG task SCB */
989 0,0, /* Initialize current Delta and Consumer ptr adjustment count */
991 0, /* Define the unused elements */
998 0,0,
999 0,dest,
1001 RSCONFIG_MODULO_128 |
1002 RSCONFIG_SAMPLE_16STEREO, /* Stereo, 128 dword */
1003 ( (asynch_buffer_address + (16 * 4)) << 0x10), /* This should be automagically
1004 synchrinized to the producer pointer */
1006 /* There is no correct initial value, it will depend upon the detected
1007 rate etc */
1008 0x18000000,
1010 /* Set IEC958 input volume */
1011 0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
1012 0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
1015 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_rx_scb,
1016 dest,"ASYNCHFGRXCODE",parent_scb,
1017 scb_child_type);
1019 return scb;
1023 #if 0 /* not used */
1024 struct dsp_scb_descriptor *
1025 cs46xx_dsp_create_output_snoop_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1026 u16 snoop_buffer_address,
1027 struct dsp_scb_descriptor * snoop_scb,
1028 struct dsp_scb_descriptor * parent_scb,
1029 int scb_child_type)
1032 struct dsp_scb_descriptor * scb;
1034 struct dsp_output_snoop_scb output_snoop_scb = {
1035 { 0, /* not used. Zero */
1041 0, /* not used. Zero */
1048 0,0,
1049 0,0,
1051 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
1052 snoop_buffer_address << 0x10,
1053 0,0,
1055 0,snoop_scb->address
1058 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&output_snoop_scb,
1059 dest,"OUTPUTSNOOP",parent_scb,
1060 scb_child_type);
1061 return scb;
1063 #endif /* not used */
1066 struct dsp_scb_descriptor *
1067 cs46xx_dsp_create_spio_write_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1068 struct dsp_scb_descriptor * parent_scb,
1069 int scb_child_type)
1071 struct dsp_scb_descriptor * scb;
1073 struct dsp_spio_write_scb spio_write_scb = {
1074 0,0, /* SPIOWAddress2:SPIOWAddress1; */
1075 0, /* SPIOWData1; */
1076 0, /* SPIOWData2; */
1077 0,0, /* SPIOWAddress4:SPIOWAddress3; */
1078 0, /* SPIOWData3; */
1079 0, /* SPIOWData4; */
1080 0,0, /* SPIOWDataPtr:Unused1; */
1081 { 0,0 }, /* Unused2[2]; */
1083 0,0, /* SPIOWChildPtr:SPIOWSiblingPtr; */
1084 0,0, /* SPIOWThisPtr:SPIOWEntryPoint; */
1091 0 /* Unused3[5]; */
1095 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&spio_write_scb,
1096 dest,"SPIOWRITE",parent_scb,
1097 scb_child_type);
1099 return scb;
1102 struct dsp_scb_descriptor *
1103 cs46xx_dsp_create_magic_snoop_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1104 u16 snoop_buffer_address,
1105 struct dsp_scb_descriptor * snoop_scb,
1106 struct dsp_scb_descriptor * parent_scb,
1107 int scb_child_type)
1109 struct dsp_scb_descriptor * scb;
1111 struct dsp_magic_snoop_task magic_snoop_scb = {
1112 /* 0 */ 0, /* i0 */
1113 /* 1 */ 0, /* i1 */
1114 /* 2 */ snoop_buffer_address << 0x10,
1115 /* 3 */ 0,snoop_scb->address,
1116 /* 4 */ 0, /* i3 */
1117 /* 5 */ 0, /* i4 */
1118 /* 6 */ 0, /* i5 */
1119 /* 7 */ 0, /* i6 */
1120 /* 8 */ 0, /* i7 */
1121 /* 9 */ 0,0, /* next_scb, sub_list_ptr */
1122 /* A */ 0,0, /* entry_point, this_ptr */
1123 /* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
1124 /* C */ snoop_buffer_address << 0x10,
1125 /* D */ 0,
1126 /* E */ { 0x8000,0x8000,
1127 /* F */ 0xffff,0xffff
1131 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&magic_snoop_scb,
1132 dest,"MAGICSNOOPTASK",parent_scb,
1133 scb_child_type);
1135 return scb;
1138 static struct dsp_scb_descriptor *
1139 find_next_free_scb (struct snd_cs46xx * chip, struct dsp_scb_descriptor * from)
1141 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1142 struct dsp_scb_descriptor * scb = from;
1144 while (scb->next_scb_ptr != ins->the_null_scb) {
1145 snd_assert (scb->next_scb_ptr != NULL, return NULL);
1147 scb = scb->next_scb_ptr;
1150 return scb;
1153 static u32 pcm_reader_buffer_addr[DSP_MAX_PCM_CHANNELS] = {
1154 0x0600, /* 1 */
1155 0x1500, /* 2 */
1156 0x1580, /* 3 */
1157 0x1600, /* 4 */
1158 0x1680, /* 5 */
1159 0x1700, /* 6 */
1160 0x1780, /* 7 */
1161 0x1800, /* 8 */
1162 0x1880, /* 9 */
1163 0x1900, /* 10 */
1164 0x1980, /* 11 */
1165 0x1A00, /* 12 */
1166 0x1A80, /* 13 */
1167 0x1B00, /* 14 */
1168 0x1B80, /* 15 */
1169 0x1C00, /* 16 */
1170 0x1C80, /* 17 */
1171 0x1D00, /* 18 */
1172 0x1D80, /* 19 */
1173 0x1E00, /* 20 */
1174 0x1E80, /* 21 */
1175 0x1F00, /* 22 */
1176 0x1F80, /* 23 */
1177 0x2000, /* 24 */
1178 0x2080, /* 25 */
1179 0x2100, /* 26 */
1180 0x2180, /* 27 */
1181 0x2200, /* 28 */
1182 0x2280, /* 29 */
1183 0x2300, /* 30 */
1184 0x2380, /* 31 */
1185 0x2400, /* 32 */
1188 static u32 src_output_buffer_addr[DSP_MAX_SRC_NR] = {
1189 0x2B80,
1190 0x2BA0,
1191 0x2BC0,
1192 0x2BE0,
1193 0x2D00,
1194 0x2D20,
1195 0x2D40,
1196 0x2D60,
1197 0x2D80,
1198 0x2DA0,
1199 0x2DC0,
1200 0x2DE0,
1201 0x2E00,
1202 0x2E20
1205 static u32 src_delay_buffer_addr[DSP_MAX_SRC_NR] = {
1206 0x2480,
1207 0x2500,
1208 0x2580,
1209 0x2600,
1210 0x2680,
1211 0x2700,
1212 0x2780,
1213 0x2800,
1214 0x2880,
1215 0x2900,
1216 0x2980,
1217 0x2A00,
1218 0x2A80,
1219 0x2B00
1222 struct dsp_pcm_channel_descriptor *
1223 cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
1224 u32 sample_rate, void * private_data,
1225 u32 hw_dma_addr,
1226 int pcm_channel_id)
1228 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1229 struct dsp_scb_descriptor * src_scb = NULL, * pcm_scb, * mixer_scb = NULL;
1230 struct dsp_scb_descriptor * src_parent_scb = NULL;
1232 /* struct dsp_scb_descriptor * pcm_parent_scb; */
1233 char scb_name[DSP_MAX_SCB_NAME];
1234 int i, pcm_index = -1, insert_point, src_index = -1, pass_through = 0;
1235 unsigned long flags;
1237 switch (pcm_channel_id) {
1238 case DSP_PCM_MAIN_CHANNEL:
1239 mixer_scb = ins->master_mix_scb;
1240 break;
1241 case DSP_PCM_REAR_CHANNEL:
1242 mixer_scb = ins->rear_mix_scb;
1243 break;
1244 case DSP_PCM_CENTER_LFE_CHANNEL:
1245 mixer_scb = ins->center_lfe_mix_scb;
1246 break;
1247 case DSP_PCM_S71_CHANNEL:
1248 /* TODO */
1249 snd_assert(0);
1250 break;
1251 case DSP_IEC958_CHANNEL:
1252 snd_assert (ins->asynch_tx_scb != NULL, return NULL);
1253 mixer_scb = ins->asynch_tx_scb;
1255 /* if sample rate is set to 48khz we pass
1256 the Sample Rate Converted (which could
1257 alter the raw data stream ...) */
1258 if (sample_rate == 48000) {
1259 snd_printdd ("IEC958 pass through\n");
1260 /* Hack to bypass creating a new SRC */
1261 pass_through = 1;
1263 break;
1264 default:
1265 snd_assert (0);
1266 return NULL;
1268 /* default sample rate is 44100 */
1269 if (!sample_rate) sample_rate = 44100;
1271 /* search for a already created SRC SCB with the same sample rate */
1272 for (i = 0; i < DSP_MAX_PCM_CHANNELS &&
1273 (pcm_index == -1 || src_scb == NULL); ++i) {
1275 /* virtual channel reserved
1276 for capture */
1277 if (i == CS46XX_DSP_CAPTURE_CHANNEL) continue;
1279 if (ins->pcm_channels[i].active) {
1280 if (!src_scb &&
1281 ins->pcm_channels[i].sample_rate == sample_rate &&
1282 ins->pcm_channels[i].mixer_scb == mixer_scb) {
1283 src_scb = ins->pcm_channels[i].src_scb;
1284 ins->pcm_channels[i].src_scb->ref_count ++;
1285 src_index = ins->pcm_channels[i].src_slot;
1287 } else if (pcm_index == -1) {
1288 pcm_index = i;
1292 if (pcm_index == -1) {
1293 snd_printk (KERN_ERR "dsp_spos: no free PCM channel\n");
1294 return NULL;
1297 if (src_scb == NULL) {
1298 if (ins->nsrc_scb >= DSP_MAX_SRC_NR) {
1299 snd_printk(KERN_ERR "dsp_spos: to many SRC instances\n!");
1300 return NULL;
1303 /* find a free slot */
1304 for (i = 0; i < DSP_MAX_SRC_NR; ++i) {
1305 if (ins->src_scb_slots[i] == 0) {
1306 src_index = i;
1307 ins->src_scb_slots[i] = 1;
1308 break;
1311 snd_assert (src_index != -1,return NULL);
1313 /* we need to create a new SRC SCB */
1314 if (mixer_scb->sub_list_ptr == ins->the_null_scb) {
1315 src_parent_scb = mixer_scb;
1316 insert_point = SCB_ON_PARENT_SUBLIST_SCB;
1317 } else {
1318 src_parent_scb = find_next_free_scb(chip,mixer_scb->sub_list_ptr);
1319 insert_point = SCB_ON_PARENT_NEXT_SCB;
1322 snprintf (scb_name,DSP_MAX_SCB_NAME,"SrcTask_SCB%d",src_index);
1324 snd_printdd( "dsp_spos: creating SRC \"%s\"\n",scb_name);
1325 src_scb = cs46xx_dsp_create_src_task_scb(chip,scb_name,
1326 sample_rate,
1327 src_output_buffer_addr[src_index],
1328 src_delay_buffer_addr[src_index],
1329 /* 0x400 - 0x600 source SCBs */
1330 0x400 + (src_index * 0x10) ,
1331 src_parent_scb,
1332 insert_point,
1333 pass_through);
1335 if (!src_scb) {
1336 snd_printk (KERN_ERR "dsp_spos: failed to create SRCtaskSCB\n");
1337 return NULL;
1340 /* cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate); */
1342 ins->nsrc_scb ++;
1346 snprintf (scb_name,DSP_MAX_SCB_NAME,"PCMReader_SCB%d",pcm_index);
1348 snd_printdd( "dsp_spos: creating PCM \"%s\" (%d)\n",scb_name,
1349 pcm_channel_id);
1351 pcm_scb = cs46xx_dsp_create_pcm_reader_scb(chip,scb_name,
1352 pcm_reader_buffer_addr[pcm_index],
1353 /* 0x200 - 400 PCMreader SCBs */
1354 (pcm_index * 0x10) + 0x200,
1355 pcm_index, /* virtual channel 0-31 */
1356 hw_dma_addr, /* pcm hw addr */
1357 NULL, /* parent SCB ptr */
1358 0 /* insert point */
1361 if (!pcm_scb) {
1362 snd_printk (KERN_ERR "dsp_spos: failed to create PCMreaderSCB\n");
1363 return NULL;
1366 spin_lock_irqsave(&chip->reg_lock, flags);
1367 ins->pcm_channels[pcm_index].sample_rate = sample_rate;
1368 ins->pcm_channels[pcm_index].pcm_reader_scb = pcm_scb;
1369 ins->pcm_channels[pcm_index].src_scb = src_scb;
1370 ins->pcm_channels[pcm_index].unlinked = 1;
1371 ins->pcm_channels[pcm_index].private_data = private_data;
1372 ins->pcm_channels[pcm_index].src_slot = src_index;
1373 ins->pcm_channels[pcm_index].active = 1;
1374 ins->pcm_channels[pcm_index].pcm_slot = pcm_index;
1375 ins->pcm_channels[pcm_index].mixer_scb = mixer_scb;
1376 ins->npcm_channels ++;
1377 spin_unlock_irqrestore(&chip->reg_lock, flags);
1379 return (ins->pcm_channels + pcm_index);
1382 int cs46xx_dsp_pcm_channel_set_period (struct snd_cs46xx * chip,
1383 struct dsp_pcm_channel_descriptor * pcm_channel,
1384 int period_size)
1386 u32 temp = snd_cs46xx_peek (chip,pcm_channel->pcm_reader_scb->address << 2);
1387 temp &= ~DMA_RQ_C1_SOURCE_SIZE_MASK;
1389 switch (period_size) {
1390 case 2048:
1391 temp |= DMA_RQ_C1_SOURCE_MOD1024;
1392 break;
1393 case 1024:
1394 temp |= DMA_RQ_C1_SOURCE_MOD512;
1395 break;
1396 case 512:
1397 temp |= DMA_RQ_C1_SOURCE_MOD256;
1398 break;
1399 case 256:
1400 temp |= DMA_RQ_C1_SOURCE_MOD128;
1401 break;
1402 case 128:
1403 temp |= DMA_RQ_C1_SOURCE_MOD64;
1404 break;
1405 case 64:
1406 temp |= DMA_RQ_C1_SOURCE_MOD32;
1407 break;
1408 case 32:
1409 temp |= DMA_RQ_C1_SOURCE_MOD16;
1410 break;
1411 default:
1412 snd_printdd ("period size (%d) not supported by HW\n", period_size);
1413 return -EINVAL;
1416 snd_cs46xx_poke (chip,pcm_channel->pcm_reader_scb->address << 2,temp);
1418 return 0;
1421 int cs46xx_dsp_pcm_ostream_set_period (struct snd_cs46xx * chip,
1422 int period_size)
1424 u32 temp = snd_cs46xx_peek (chip,WRITEBACK_SCB_ADDR << 2);
1425 temp &= ~DMA_RQ_C1_DEST_SIZE_MASK;
1427 switch (period_size) {
1428 case 2048:
1429 temp |= DMA_RQ_C1_DEST_MOD1024;
1430 break;
1431 case 1024:
1432 temp |= DMA_RQ_C1_DEST_MOD512;
1433 break;
1434 case 512:
1435 temp |= DMA_RQ_C1_DEST_MOD256;
1436 break;
1437 case 256:
1438 temp |= DMA_RQ_C1_DEST_MOD128;
1439 break;
1440 case 128:
1441 temp |= DMA_RQ_C1_DEST_MOD64;
1442 break;
1443 case 64:
1444 temp |= DMA_RQ_C1_DEST_MOD32;
1445 break;
1446 case 32:
1447 temp |= DMA_RQ_C1_DEST_MOD16;
1448 break;
1449 default:
1450 snd_printdd ("period size (%d) not supported by HW\n", period_size);
1451 return -EINVAL;
1454 snd_cs46xx_poke (chip,WRITEBACK_SCB_ADDR << 2,temp);
1456 return 0;
1459 void cs46xx_dsp_destroy_pcm_channel (struct snd_cs46xx * chip,
1460 struct dsp_pcm_channel_descriptor * pcm_channel)
1462 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1463 unsigned long flags;
1465 snd_assert(pcm_channel->active, return );
1466 snd_assert(ins->npcm_channels > 0, return );
1467 snd_assert(pcm_channel->src_scb->ref_count > 0, return );
1469 spin_lock_irqsave(&chip->reg_lock, flags);
1470 pcm_channel->unlinked = 1;
1471 pcm_channel->active = 0;
1472 pcm_channel->private_data = NULL;
1473 pcm_channel->src_scb->ref_count --;
1474 ins->npcm_channels --;
1475 spin_unlock_irqrestore(&chip->reg_lock, flags);
1477 cs46xx_dsp_remove_scb(chip,pcm_channel->pcm_reader_scb);
1479 if (!pcm_channel->src_scb->ref_count) {
1480 cs46xx_dsp_remove_scb(chip,pcm_channel->src_scb);
1482 snd_assert (pcm_channel->src_slot >= 0 && pcm_channel->src_slot < DSP_MAX_SRC_NR,
1483 return );
1485 ins->src_scb_slots[pcm_channel->src_slot] = 0;
1486 ins->nsrc_scb --;
1490 int cs46xx_dsp_pcm_unlink (struct snd_cs46xx * chip,
1491 struct dsp_pcm_channel_descriptor * pcm_channel)
1493 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1494 unsigned long flags;
1496 snd_assert(pcm_channel->active,return -EIO);
1497 snd_assert(ins->npcm_channels > 0,return -EIO);
1499 spin_lock(&pcm_channel->src_scb->lock);
1501 if (pcm_channel->unlinked) {
1502 spin_unlock(&pcm_channel->src_scb->lock);
1503 return -EIO;
1506 spin_lock_irqsave(&chip->reg_lock, flags);
1507 pcm_channel->unlinked = 1;
1508 spin_unlock_irqrestore(&chip->reg_lock, flags);
1510 _dsp_unlink_scb (chip,pcm_channel->pcm_reader_scb);
1512 spin_unlock(&pcm_channel->src_scb->lock);
1513 return 0;
1516 int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip,
1517 struct dsp_pcm_channel_descriptor * pcm_channel)
1519 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1520 struct dsp_scb_descriptor * parent_scb;
1521 struct dsp_scb_descriptor * src_scb = pcm_channel->src_scb;
1522 unsigned long flags;
1524 spin_lock(&pcm_channel->src_scb->lock);
1526 if (pcm_channel->unlinked == 0) {
1527 spin_unlock(&pcm_channel->src_scb->lock);
1528 return -EIO;
1531 parent_scb = src_scb;
1533 if (src_scb->sub_list_ptr != ins->the_null_scb) {
1534 src_scb->sub_list_ptr->parent_scb_ptr = pcm_channel->pcm_reader_scb;
1535 pcm_channel->pcm_reader_scb->next_scb_ptr = src_scb->sub_list_ptr;
1538 src_scb->sub_list_ptr = pcm_channel->pcm_reader_scb;
1540 snd_assert (pcm_channel->pcm_reader_scb->parent_scb_ptr == NULL, ; );
1541 pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb;
1543 spin_lock_irqsave(&chip->reg_lock, flags);
1545 /* update SCB entry in DSP RAM */
1546 cs46xx_dsp_spos_update_scb(chip,pcm_channel->pcm_reader_scb);
1548 /* update parent SCB entry */
1549 cs46xx_dsp_spos_update_scb(chip,parent_scb);
1551 pcm_channel->unlinked = 0;
1552 spin_unlock_irqrestore(&chip->reg_lock, flags);
1554 spin_unlock(&pcm_channel->src_scb->lock);
1555 return 0;
1558 struct dsp_scb_descriptor *
1559 cs46xx_add_record_source (struct snd_cs46xx *chip, struct dsp_scb_descriptor * source,
1560 u16 addr, char * scb_name)
1562 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1563 struct dsp_scb_descriptor * parent;
1564 struct dsp_scb_descriptor * pcm_input;
1565 int insert_point;
1567 snd_assert (ins->record_mixer_scb != NULL,return NULL);
1569 if (ins->record_mixer_scb->sub_list_ptr != ins->the_null_scb) {
1570 parent = find_next_free_scb (chip,ins->record_mixer_scb->sub_list_ptr);
1571 insert_point = SCB_ON_PARENT_NEXT_SCB;
1572 } else {
1573 parent = ins->record_mixer_scb;
1574 insert_point = SCB_ON_PARENT_SUBLIST_SCB;
1577 pcm_input = cs46xx_dsp_create_pcm_serial_input_scb(chip,scb_name,addr,
1578 source, parent,
1579 insert_point);
1581 return pcm_input;
1584 int cs46xx_src_unlink(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
1586 snd_assert (src->parent_scb_ptr != NULL, return -EINVAL );
1588 /* mute SCB */
1589 cs46xx_dsp_scb_set_volume (chip,src,0,0);
1591 _dsp_unlink_scb (chip,src);
1593 return 0;
1596 int cs46xx_src_link(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
1598 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1599 struct dsp_scb_descriptor * parent_scb;
1601 snd_assert (src->parent_scb_ptr == NULL, return -EINVAL );
1602 snd_assert(ins->master_mix_scb !=NULL, return -EINVAL );
1604 if (ins->master_mix_scb->sub_list_ptr != ins->the_null_scb) {
1605 parent_scb = find_next_free_scb (chip,ins->master_mix_scb->sub_list_ptr);
1606 parent_scb->next_scb_ptr = src;
1607 } else {
1608 parent_scb = ins->master_mix_scb;
1609 parent_scb->sub_list_ptr = src;
1612 src->parent_scb_ptr = parent_scb;
1614 /* update entry in DSP RAM */
1615 cs46xx_dsp_spos_update_scb(chip,parent_scb);
1617 return 0;
1620 int cs46xx_dsp_enable_spdif_out (struct snd_cs46xx *chip)
1622 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1624 if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
1625 cs46xx_dsp_enable_spdif_hw (chip);
1628 /* dont touch anything if SPDIF is open */
1629 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
1630 /* when cs46xx_iec958_post_close(...) is called it
1631 will call this function if necessary depending on
1632 this bit */
1633 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1635 return -EBUSY;
1638 snd_assert (ins->asynch_tx_scb == NULL, return -EINVAL);
1639 snd_assert (ins->master_mix_scb->next_scb_ptr == ins->the_null_scb, return -EINVAL);
1641 /* reset output snooper sample buffer pointer */
1642 snd_cs46xx_poke (chip, (ins->ref_snoop_scb->address + 2) << 2,
1643 (OUTPUT_SNOOP_BUFFER + 0x10) << 0x10 );
1645 /* The asynch. transfer task */
1646 ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
1647 SPDIFO_SCB_INST,
1648 SPDIFO_IP_OUTPUT_BUFFER1,
1649 ins->master_mix_scb,
1650 SCB_ON_PARENT_NEXT_SCB);
1651 if (!ins->asynch_tx_scb) return -ENOMEM;
1653 ins->spdif_pcm_input_scb = cs46xx_dsp_create_pcm_serial_input_scb(chip,"PCMSerialInput_II",
1654 PCMSERIALINII_SCB_ADDR,
1655 ins->ref_snoop_scb,
1656 ins->asynch_tx_scb,
1657 SCB_ON_PARENT_SUBLIST_SCB);
1660 if (!ins->spdif_pcm_input_scb) return -ENOMEM;
1662 /* monitor state */
1663 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1665 return 0;
1668 int cs46xx_dsp_disable_spdif_out (struct snd_cs46xx *chip)
1670 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1672 /* dont touch anything if SPDIF is open */
1673 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
1674 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1675 return -EBUSY;
1678 /* check integrety */
1679 snd_assert (ins->asynch_tx_scb != NULL, return -EINVAL);
1680 snd_assert (ins->spdif_pcm_input_scb != NULL,return -EINVAL);
1681 snd_assert (ins->master_mix_scb->next_scb_ptr == ins->asynch_tx_scb, return -EINVAL);
1682 snd_assert (ins->asynch_tx_scb->parent_scb_ptr == ins->master_mix_scb, return -EINVAL);
1684 cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
1685 cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
1687 ins->spdif_pcm_input_scb = NULL;
1688 ins->asynch_tx_scb = NULL;
1690 /* clear buffer to prevent any undesired noise */
1691 _dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
1693 /* monitor state */
1694 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1697 return 0;
1700 int cs46xx_iec958_pre_open (struct snd_cs46xx *chip)
1702 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1704 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
1705 /* remove AsynchFGTxSCB and and PCMSerialInput_II */
1706 cs46xx_dsp_disable_spdif_out (chip);
1708 /* save state */
1709 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1712 /* if not enabled already */
1713 if ( !(ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
1714 cs46xx_dsp_enable_spdif_hw (chip);
1717 /* Create the asynch. transfer task for playback */
1718 ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
1719 SPDIFO_SCB_INST,
1720 SPDIFO_IP_OUTPUT_BUFFER1,
1721 ins->master_mix_scb,
1722 SCB_ON_PARENT_NEXT_SCB);
1725 /* set spdif channel status value for streaming */
1726 cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_stream);
1728 ins->spdif_status_out |= DSP_SPDIF_STATUS_PLAYBACK_OPEN;
1730 return 0;
1733 int cs46xx_iec958_post_close (struct snd_cs46xx *chip)
1735 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1737 snd_assert (ins->asynch_tx_scb != NULL, return -EINVAL);
1739 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_PLAYBACK_OPEN;
1741 /* restore settings */
1742 cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);
1744 /* deallocate stuff */
1745 if (ins->spdif_pcm_input_scb != NULL) {
1746 cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
1747 ins->spdif_pcm_input_scb = NULL;
1750 cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
1751 ins->asynch_tx_scb = NULL;
1753 /* clear buffer to prevent any undesired noise */
1754 _dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
1756 /* restore state */
1757 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
1758 cs46xx_dsp_enable_spdif_out (chip);
1761 return 0;