initial commit with v2.6.9
[linux-2.6.9-moxart.git] / sound / pci / cs46xx / dsp_spos_scb_lib.c
blob4bf170bdab7f1ecea64032e8cbd4d549b5746ccb
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/pci.h>
28 #include <linux/pm.h>
29 #include <linux/init.h>
30 #include <linux/slab.h>
31 #include <sound/core.h>
32 #include <sound/control.h>
33 #include <sound/info.h>
34 #include <sound/cs46xx.h>
36 #include "cs46xx_lib.h"
37 #include "dsp_spos.h"
39 typedef struct _proc_scb_info_t {
40 dsp_scb_descriptor_t * scb_desc;
41 cs46xx_t *chip;
42 } proc_scb_info_t;
44 static void remove_symbol (cs46xx_t * chip,symbol_entry_t * symbol)
46 dsp_spos_instance_t * 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 static void cs46xx_dsp_proc_scb_info_read (snd_info_entry_t *entry, snd_info_buffer_t * buffer)
69 proc_scb_info_t * scb_info = (proc_scb_info_t *)entry->private_data;
70 dsp_scb_descriptor_t * scb = scb_info->scb_desc;
71 dsp_spos_instance_t * ins;
72 cs46xx_t *chip = scb_info->chip;
73 int j,col;
74 unsigned long dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
76 ins = chip->dsp_spos_instance;
78 down(&chip->spos_mutex);
79 snd_iprintf(buffer,"%04x %s:\n",scb->address,scb->scb_name);
81 for (col = 0,j = 0;j < 0x10; j++,col++) {
82 if (col == 4) {
83 snd_iprintf(buffer,"\n");
84 col = 0;
86 snd_iprintf(buffer,"%08x ",readl(dst + (scb->address + j) * sizeof(u32)));
89 snd_iprintf(buffer,"\n");
91 if (scb->parent_scb_ptr != NULL) {
92 snd_iprintf(buffer,"parent [%s:%04x] ",
93 scb->parent_scb_ptr->scb_name,
94 scb->parent_scb_ptr->address);
95 } else snd_iprintf(buffer,"parent [none] ");
97 snd_iprintf(buffer,"sub_list_ptr [%s:%04x]\nnext_scb_ptr [%s:%04x] task_entry [%s:%04x]\n",
98 scb->sub_list_ptr->scb_name,
99 scb->sub_list_ptr->address,
100 scb->next_scb_ptr->scb_name,
101 scb->next_scb_ptr->address,
102 scb->task_entry->symbol_name,
103 scb->task_entry->address);
105 snd_iprintf(buffer,"index [%d] ref_count [%d]\n",scb->index,scb->ref_count);
106 up(&chip->spos_mutex);
109 static void _dsp_unlink_scb (cs46xx_t *chip,dsp_scb_descriptor_t * scb)
111 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
112 unsigned long flags;
114 if ( scb->parent_scb_ptr ) {
115 /* unlink parent SCB */
116 snd_assert ((scb->parent_scb_ptr->sub_list_ptr == scb ||
117 scb->parent_scb_ptr->next_scb_ptr == scb),return);
119 if (scb->parent_scb_ptr->sub_list_ptr == scb) {
121 if (scb->next_scb_ptr == ins->the_null_scb) {
122 /* last and only node in parent sublist */
123 scb->parent_scb_ptr->sub_list_ptr = scb->sub_list_ptr;
125 if (scb->sub_list_ptr != ins->the_null_scb) {
126 scb->sub_list_ptr->parent_scb_ptr = scb->parent_scb_ptr;
128 scb->sub_list_ptr = ins->the_null_scb;
129 } else {
130 /* first node in parent sublist */
131 scb->parent_scb_ptr->sub_list_ptr = scb->next_scb_ptr;
133 if (scb->next_scb_ptr != ins->the_null_scb) {
134 /* update next node parent ptr. */
135 scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
137 scb->next_scb_ptr = ins->the_null_scb;
139 } else {
140 /* snd_assert ( (scb->sub_list_ptr == ins->the_null_scb), return); */
141 scb->parent_scb_ptr->next_scb_ptr = scb->next_scb_ptr;
143 if (scb->next_scb_ptr != ins->the_null_scb) {
144 /* update next node parent ptr. */
145 scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
147 scb->next_scb_ptr = ins->the_null_scb;
150 spin_lock_irqsave(&chip->reg_lock, flags);
152 /* update parent first entry in DSP RAM */
153 cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
155 /* then update entry in DSP RAM */
156 cs46xx_dsp_spos_update_scb(chip,scb);
158 scb->parent_scb_ptr = NULL;
159 spin_unlock_irqrestore(&chip->reg_lock, flags);
163 static void _dsp_clear_sample_buffer (cs46xx_t *chip, u32 sample_buffer_addr, int dword_count)
165 unsigned long dst = chip->region.idx[2].remap_addr + sample_buffer_addr;
166 int i;
168 for (i = 0; i < dword_count ; ++i ) {
169 writel(0, dst);
170 dst += 4;
174 void cs46xx_dsp_remove_scb (cs46xx_t *chip, dsp_scb_descriptor_t * scb)
176 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
178 /* check integrety */
179 snd_assert ( (scb->index >= 0 &&
180 scb->index < ins->nscb &&
181 (ins->scbs + scb->index) == scb), return );
183 #if 0
184 /* can't remove a SCB with childs before
185 removing childs first */
186 snd_assert ( (scb->sub_list_ptr == ins->the_null_scb &&
187 scb->next_scb_ptr == ins->the_null_scb),
188 goto _end);
189 #endif
191 spin_lock(&scb->lock);
192 _dsp_unlink_scb (chip,scb);
193 spin_unlock(&scb->lock);
195 cs46xx_dsp_proc_free_scb_desc(scb);
196 snd_assert (scb->scb_symbol != NULL, return );
197 remove_symbol (chip,scb->scb_symbol);
199 ins->scbs[scb->index].deleted = 1;
201 if (scb->index < ins->scb_highest_frag_index)
202 ins->scb_highest_frag_index = scb->index;
204 if (scb->index == ins->nscb - 1) {
205 ins->nscb --;
208 if (ins->scb_highest_frag_index > ins->nscb) {
209 ins->scb_highest_frag_index = ins->nscb;
212 #if 0
213 /* !!!! THIS IS A PIECE OF SHIT MADE BY ME !!! */
214 for(i = scb->index + 1;i < ins->nscb; ++i) {
215 ins->scbs[i - 1].index = i - 1;
217 #endif
221 void cs46xx_dsp_proc_free_scb_desc (dsp_scb_descriptor_t * scb)
223 if (scb->proc_info) {
224 proc_scb_info_t * scb_info = (proc_scb_info_t *)scb->proc_info->private_data;
226 snd_printdd("cs46xx_dsp_proc_free_scb_desc: freeing %s\n",scb->scb_name);
228 snd_info_unregister(scb->proc_info);
229 scb->proc_info = NULL;
231 snd_assert (scb_info != NULL, return);
232 kfree (scb_info);
236 void cs46xx_dsp_proc_register_scb_desc (cs46xx_t *chip,dsp_scb_descriptor_t * scb)
238 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
239 snd_info_entry_t * entry;
240 proc_scb_info_t * scb_info;
242 /* register to proc */
243 if (ins->snd_card != NULL && ins->proc_dsp_dir != NULL &&
244 scb->proc_info == NULL) {
246 if ((entry = snd_info_create_card_entry(ins->snd_card, scb->scb_name,
247 ins->proc_dsp_dir)) != NULL) {
248 scb_info = kmalloc(sizeof(proc_scb_info_t), GFP_KERNEL);
249 if (!scb_info) {
250 snd_info_free_entry(entry);
251 entry = NULL;
252 goto out;
255 scb_info->chip = chip;
256 scb_info->scb_desc = scb;
258 entry->content = SNDRV_INFO_CONTENT_TEXT;
259 entry->private_data = scb_info;
260 entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
262 entry->c.text.read_size = 512;
263 entry->c.text.read = cs46xx_dsp_proc_scb_info_read;
265 if (snd_info_register(entry) < 0) {
266 snd_info_free_entry(entry);
267 kfree (scb_info);
268 entry = NULL;
271 out:
272 scb->proc_info = entry;
276 static dsp_scb_descriptor_t *
277 _dsp_create_generic_scb (cs46xx_t *chip,char * name, u32 * scb_data,u32 dest,
278 symbol_entry_t * task_entry,
279 dsp_scb_descriptor_t * parent_scb,
280 int scb_child_type)
282 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
283 dsp_scb_descriptor_t * scb;
285 unsigned long flags;
287 snd_assert (ins->the_null_scb != NULL,return NULL);
289 /* fill the data that will be wroten to DSP */
290 scb_data[SCBsubListPtr] =
291 (ins->the_null_scb->address << 0x10) | ins->the_null_scb->address;
293 scb_data[SCBfuncEntryPtr] &= 0xFFFF0000;
294 scb_data[SCBfuncEntryPtr] |= task_entry->address;
296 snd_printdd("dsp_spos: creating SCB <%s>\n",name);
298 scb = cs46xx_dsp_create_scb(chip,name,scb_data,dest);
301 scb->sub_list_ptr = ins->the_null_scb;
302 scb->next_scb_ptr = ins->the_null_scb;
304 scb->parent_scb_ptr = parent_scb;
305 scb->task_entry = task_entry;
308 /* update parent SCB */
309 if (scb->parent_scb_ptr) {
310 #if 0
311 printk ("scb->parent_scb_ptr = %s\n",scb->parent_scb_ptr->scb_name);
312 printk ("scb->parent_scb_ptr->next_scb_ptr = %s\n",scb->parent_scb_ptr->next_scb_ptr->scb_name);
313 printk ("scb->parent_scb_ptr->sub_list_ptr = %s\n",scb->parent_scb_ptr->sub_list_ptr->scb_name);
314 #endif
315 /* link to parent SCB */
316 if (scb_child_type == SCB_ON_PARENT_NEXT_SCB) {
317 snd_assert ( (scb->parent_scb_ptr->next_scb_ptr == ins->the_null_scb),
318 return NULL);
320 scb->parent_scb_ptr->next_scb_ptr = scb;
322 } else if (scb_child_type == SCB_ON_PARENT_SUBLIST_SCB) {
323 snd_assert ( (scb->parent_scb_ptr->sub_list_ptr == ins->the_null_scb),
324 return NULL);
326 scb->parent_scb_ptr->sub_list_ptr = scb;
327 } else {
328 snd_assert (0,return NULL);
331 spin_lock_irqsave(&chip->reg_lock, flags);
333 /* update entry in DSP RAM */
334 cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
336 spin_unlock_irqrestore(&chip->reg_lock, flags);
340 cs46xx_dsp_proc_register_scb_desc (chip,scb);
342 return scb;
345 dsp_scb_descriptor_t *
346 cs46xx_dsp_create_generic_scb (cs46xx_t *chip,char * name, u32 * scb_data,u32 dest,
347 char * task_entry_name,
348 dsp_scb_descriptor_t * parent_scb,
349 int scb_child_type)
351 symbol_entry_t * task_entry;
353 task_entry = cs46xx_dsp_lookup_symbol (chip,task_entry_name,
354 SYMBOL_CODE);
356 if (task_entry == NULL) {
357 snd_printk (KERN_ERR "dsp_spos: symbol %s not found\n",task_entry_name);
358 return NULL;
361 return _dsp_create_generic_scb (chip,name,scb_data,dest,task_entry,
362 parent_scb,scb_child_type);
365 dsp_scb_descriptor_t *
366 cs46xx_dsp_create_timing_master_scb (cs46xx_t *chip)
368 dsp_scb_descriptor_t * scb;
370 timing_master_scb_t timing_master_scb = {
371 { 0,
376 { 0,
382 0,0,
383 0,NULL_SCB_ADDR,
384 0,0, /* extraSampleAccum:TMreserved */
385 0,0, /* codecFIFOptr:codecFIFOsyncd */
386 0x0001,0x8000, /* fracSampAccumQm1:TMfrmsLeftInGroup */
387 0x0001,0x0000, /* fracSampCorrectionQm1:TMfrmGroupLength */
388 0x00060000 /* nSampPerFrmQ15 */
391 scb = cs46xx_dsp_create_generic_scb(chip,"TimingMasterSCBInst",(u32 *)&timing_master_scb,
392 TIMINGMASTER_SCB_ADDR,
393 "TIMINGMASTER",NULL,SCB_NO_PARENT);
395 return scb;
399 dsp_scb_descriptor_t *
400 cs46xx_dsp_create_codec_out_scb(cs46xx_t * chip,char * codec_name,
401 u16 channel_disp,u16 fifo_addr,
402 u16 child_scb_addr,
403 u32 dest,dsp_scb_descriptor_t * parent_scb,
404 int scb_child_type)
406 dsp_scb_descriptor_t * scb;
408 codec_output_scb_t codec_out_scb = {
409 { 0,
421 0,0,
422 0,NULL_SCB_ADDR,
423 0, /* COstrmRsConfig */
424 0, /* COstrmBufPtr */
425 channel_disp,fifo_addr, /* leftChanBaseIOaddr:rightChanIOdisp */
426 0x0000,0x0080, /* (!AC97!) COexpVolChangeRate:COscaleShiftCount */
427 0,child_scb_addr /* COreserved - need child scb to work with rom code */
431 scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_out_scb,
432 dest,"S16_CODECOUTPUTTASK",parent_scb,
433 scb_child_type);
435 return scb;
438 dsp_scb_descriptor_t *
439 cs46xx_dsp_create_codec_in_scb(cs46xx_t * chip,char * codec_name,
440 u16 channel_disp,u16 fifo_addr,
441 u16 sample_buffer_addr,
442 u32 dest,dsp_scb_descriptor_t * parent_scb,
443 int scb_child_type)
446 dsp_scb_descriptor_t * scb;
447 codec_input_scb_t codec_input_scb = {
448 { 0,
461 #if 0 /* cs4620 */
462 SyncIOSCB,NULL_SCB_ADDR
463 #else
464 0 , 0,
465 #endif
466 0,0,
468 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64, /* strmRsConfig */
469 sample_buffer_addr << 0x10, /* strmBufPtr; defined as a dword ptr, used as a byte ptr */
470 channel_disp,fifo_addr, /* (!AC97!) leftChanBaseINaddr=AC97primary
471 link input slot 3 :rightChanINdisp=""slot 4 */
472 0x0000,0x0000, /* (!AC97!) ????:scaleShiftCount; no shift needed
473 because AC97 is already 20 bits */
474 0x80008000 /* ??clw cwcgame.scb has 0 */
477 scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_input_scb,
478 dest,"S16_CODECINPUTTASK",parent_scb,
479 scb_child_type);
480 return scb;
484 dsp_scb_descriptor_t *
485 cs46xx_dsp_create_pcm_reader_scb(cs46xx_t * chip,char * scb_name,
486 u16 sample_buffer_addr,u32 dest,
487 int virtual_channel, u32 playback_hw_addr,
488 dsp_scb_descriptor_t * parent_scb,
489 int scb_child_type)
491 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
492 dsp_scb_descriptor_t * scb;
494 generic_scb_t pcm_reader_scb = {
497 Play DMA Task xfers data from host buffer to SP buffer
498 init/runtime variables:
499 PlayAC: Play Audio Data Conversion - SCB loc: 2nd dword, mask: 0x0000F000L
500 DATA_FMT_16BIT_ST_LTLEND(0x00000000L) from 16-bit stereo, little-endian
501 DATA_FMT_8_BIT_ST_SIGNED(0x00001000L) from 8-bit stereo, signed
502 DATA_FMT_16BIT_MN_LTLEND(0x00002000L) from 16-bit mono, little-endian
503 DATA_FMT_8_BIT_MN_SIGNED(0x00003000L) from 8-bit mono, signed
504 DATA_FMT_16BIT_ST_BIGEND(0x00004000L) from 16-bit stereo, big-endian
505 DATA_FMT_16BIT_MN_BIGEND(0x00006000L) from 16-bit mono, big-endian
506 DATA_FMT_8_BIT_ST_UNSIGNED(0x00009000L) from 8-bit stereo, unsigned
507 DATA_FMT_8_BIT_MN_UNSIGNED(0x0000b000L) from 8-bit mono, unsigned
508 ? Other combinations possible from:
509 DMA_RQ_C2_AUDIO_CONVERT_MASK 0x0000F000L
510 DMA_RQ_C2_AC_NONE 0x00000000L
511 DMA_RQ_C2_AC_8_TO_16_BIT 0x00001000L
512 DMA_RQ_C2_AC_MONO_TO_STEREO 0x00002000L
513 DMA_RQ_C2_AC_ENDIAN_CONVERT 0x00004000L
514 DMA_RQ_C2_AC_SIGNED_CONVERT 0x00008000L
516 HostBuffAddr: Host Buffer Physical Byte Address - SCB loc:3rd dword, Mask: 0xFFFFFFFFL
517 aligned to dword boundary
519 /* Basic (non scatter/gather) DMA requestor (4 ints) */
520 { DMA_RQ_C1_SOURCE_ON_HOST + /* source buffer is on the host */
521 DMA_RQ_C1_SOURCE_MOD1024 + /* source buffer is 1024 dwords (4096 bytes) */
522 DMA_RQ_C1_DEST_MOD32 + /* dest buffer(PCMreaderBuf) is 32 dwords*/
523 DMA_RQ_C1_WRITEBACK_SRC_FLAG + /* ?? */
524 DMA_RQ_C1_WRITEBACK_DEST_FLAG + /* ?? */
525 15, /* DwordCount-1: picked 16 for DwordCount because Jim */
526 /* Barnette said that is what we should use since */
527 /* we are not running in optimized mode? */
528 DMA_RQ_C2_AC_NONE +
529 DMA_RQ_C2_SIGNAL_SOURCE_PINGPONG + /* set play interrupt (bit0) in HISR when source */
530 /* buffer (on host) crosses half-way point */
531 virtual_channel, /* Play DMA channel arbitrarily set to 0 */
532 playback_hw_addr, /* HostBuffAddr (source) */
533 DMA_RQ_SD_SP_SAMPLE_ADDR + /* destination buffer is in SP Sample Memory */
534 sample_buffer_addr /* SP Buffer Address (destination) */
536 /* Scatter/gather DMA requestor extension (5 ints) */
544 /* Sublist pointer & next stream control block (SCB) link. */
545 NULL_SCB_ADDR,NULL_SCB_ADDR,
546 /* Pointer to this tasks parameter block & stream function pointer */
547 0,NULL_SCB_ADDR,
548 /* rsConfig register for stream buffer (rsDMA reg. is loaded from basicReq.daw */
549 /* for incoming streams, or basicReq.saw, for outgoing streams) */
550 RSCONFIG_DMA_ENABLE + /* enable DMA */
551 (19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) + /* MAX_DMA_SIZE picked to be 19 since SPUD */
552 /* uses it for some reason */
553 ((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) + /* stream number = SCBaddr/16 */
554 RSCONFIG_SAMPLE_16STEREO +
555 RSCONFIG_MODULO_32, /* dest buffer(PCMreaderBuf) is 32 dwords (256 bytes) */
556 /* Stream sample pointer & MAC-unit mode for this stream */
557 (sample_buffer_addr << 0x10),
558 /* Fractional increment per output sample in the input sample buffer */
561 /* Standard stereo volume control
562 default muted */
563 0xffff,0xffff,
564 0xffff,0xffff
568 if (ins->null_algorithm == NULL) {
569 ins->null_algorithm = cs46xx_dsp_lookup_symbol (chip,"NULLALGORITHM",
570 SYMBOL_CODE);
572 if (ins->null_algorithm == NULL) {
573 snd_printk (KERN_ERR "dsp_spos: symbol NULLALGORITHM not found\n");
574 return NULL;
578 scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_reader_scb,
579 dest,ins->null_algorithm,parent_scb,
580 scb_child_type);
582 return scb;
585 #define GOF_PER_SEC 200
587 dsp_scb_descriptor_t *
588 cs46xx_dsp_create_src_task_scb(cs46xx_t * chip,char * scb_name,
589 int rate,
590 u16 src_buffer_addr,
591 u16 src_delay_buffer_addr,u32 dest,
592 dsp_scb_descriptor_t * parent_scb,
593 int scb_child_type,
594 int pass_through)
597 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
598 dsp_scb_descriptor_t * scb;
599 unsigned int tmp1, tmp2;
600 unsigned int phiIncr;
601 unsigned int correctionPerGOF, correctionPerSec;
603 snd_printdd( "dsp_spos: setting %s rate to %u\n",scb_name,rate);
606 * Compute the values used to drive the actual sample rate conversion.
607 * The following formulas are being computed, using inline assembly
608 * since we need to use 64 bit arithmetic to compute the values:
610 * phiIncr = floor((Fs,in * 2^26) / Fs,out)
611 * correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) /
612 * GOF_PER_SEC)
613 * ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -M
614 * GOF_PER_SEC * correctionPerGOF
616 * i.e.
618 * phiIncr:other = dividend:remainder((Fs,in * 2^26) / Fs,out)
619 * correctionPerGOF:correctionPerSec =
620 * dividend:remainder(ulOther / GOF_PER_SEC)
622 tmp1 = rate << 16;
623 phiIncr = tmp1 / 48000;
624 tmp1 -= phiIncr * 48000;
625 tmp1 <<= 10;
626 phiIncr <<= 10;
627 tmp2 = tmp1 / 48000;
628 phiIncr += tmp2;
629 tmp1 -= tmp2 * 48000;
630 correctionPerGOF = tmp1 / GOF_PER_SEC;
631 tmp1 -= correctionPerGOF * GOF_PER_SEC;
632 correctionPerSec = tmp1;
635 src_task_scb_t src_task_scb = {
636 0x0028,0x00c8,
637 0x5555,0x0000,
638 0x0000,0x0000,
639 src_buffer_addr,1,
640 correctionPerGOF,correctionPerSec,
641 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
642 0x0000,src_delay_buffer_addr,
643 0x0,
644 0x080,(src_delay_buffer_addr + (24 * 4)),
645 0,0, /* next_scb, sub_list_ptr */
646 0,0, /* entry, this_spb */
647 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
648 src_buffer_addr << 0x10,
649 phiIncr,
651 0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left,
652 0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left
656 if (ins->s16_up == NULL) {
657 ins->s16_up = cs46xx_dsp_lookup_symbol (chip,"S16_UPSRC",
658 SYMBOL_CODE);
660 if (ins->s16_up == NULL) {
661 snd_printk (KERN_ERR "dsp_spos: symbol S16_UPSRC not found\n");
662 return NULL;
666 /* clear buffers */
667 _dsp_clear_sample_buffer (chip,src_buffer_addr,8);
668 _dsp_clear_sample_buffer (chip,src_delay_buffer_addr,32);
670 if (pass_through) {
671 /* wont work with any other rate than
672 the native DSP rate */
673 snd_assert (rate = 48000);
675 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
676 dest,"DMAREADER",parent_scb,
677 scb_child_type);
678 } else {
679 scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
680 dest,ins->s16_up,parent_scb,
681 scb_child_type);
687 return scb;
690 dsp_scb_descriptor_t *
691 cs46xx_dsp_create_filter_scb(cs46xx_t * chip,char * scb_name,
692 u16 buffer_addr,u32 dest,
693 dsp_scb_descriptor_t * parent_scb,
694 int scb_child_type) {
695 dsp_scb_descriptor_t * scb;
697 filter_scb_t filter_scb = {
698 .a0_right = 0x41a9,
699 .a0_left = 0x41a9,
700 .a1_right = 0xb8e4,
701 .a1_left = 0xb8e4,
702 .a2_right = 0x3e55,
703 .a2_left = 0x3e55,
705 .filter_unused3 = 0x0000,
706 .filter_unused2 = 0x0000,
708 .output_buf_ptr = buffer_addr,
709 .init = 0x000,
711 .prev_sample_output1 = 0x00000000,
712 .prev_sample_output2 = 0x00000000,
714 .prev_sample_input1 = 0x00000000,
715 .prev_sample_input2 = 0x00000000,
717 .next_scb_ptr = 0x0000,
718 .sub_list_ptr = 0x0000,
720 .entry_point = 0x0000,
721 .spb_ptr = 0x0000,
723 .b0_right = 0x0e38,
724 .b0_left = 0x0e38,
725 .b1_right = 0x1c71,
726 .b1_left = 0x1c71,
727 .b2_right = 0x0e38,
728 .b2_left = 0x0e38,
732 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&filter_scb,
733 dest,"FILTERTASK",parent_scb,
734 scb_child_type);
736 return scb;
739 dsp_scb_descriptor_t *
740 cs46xx_dsp_create_mix_only_scb(cs46xx_t * chip,char * scb_name,
741 u16 mix_buffer_addr,u32 dest,
742 dsp_scb_descriptor_t * parent_scb,
743 int scb_child_type)
745 dsp_scb_descriptor_t * scb;
747 mix_only_scb_t master_mix_scb = {
748 /* 0 */ { 0,
749 /* 1 */ 0,
750 /* 2 */ mix_buffer_addr,
751 /* 3 */ 0
752 /* */ },
754 /* 4 */ 0,
755 /* 5 */ 0,
756 /* 6 */ 0,
757 /* 7 */ 0,
758 /* 8 */ 0x00000080
760 /* 9 */ 0,0,
761 /* A */ 0,0,
762 /* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
763 /* C */ (mix_buffer_addr + (16 * 4)) << 0x10,
764 /* D */ 0,
766 /* E */ 0x8000,0x8000,
767 /* F */ 0x8000,0x8000
772 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&master_mix_scb,
773 dest,"S16_MIX",parent_scb,
774 scb_child_type);
775 return scb;
779 dsp_scb_descriptor_t *
780 cs46xx_dsp_create_mix_to_ostream_scb(cs46xx_t * chip,char * scb_name,
781 u16 mix_buffer_addr,u16 writeback_spb,u32 dest,
782 dsp_scb_descriptor_t * parent_scb,
783 int scb_child_type)
785 dsp_scb_descriptor_t * scb;
787 mix2_ostream_scb_t mix2_ostream_scb = {
788 /* Basic (non scatter/gather) DMA requestor (4 ints) */
790 DMA_RQ_C1_SOURCE_MOD64 +
791 DMA_RQ_C1_DEST_ON_HOST +
792 DMA_RQ_C1_DEST_MOD1024 +
793 DMA_RQ_C1_WRITEBACK_SRC_FLAG +
794 DMA_RQ_C1_WRITEBACK_DEST_FLAG +
795 15,
797 DMA_RQ_C2_AC_NONE +
798 DMA_RQ_C2_SIGNAL_DEST_PINGPONG +
800 CS46XX_DSP_CAPTURE_CHANNEL,
801 DMA_RQ_SD_SP_SAMPLE_ADDR +
802 mix_buffer_addr,
803 0x0
806 { 0, 0, 0, 0, 0, },
807 0,0,
808 0,writeback_spb,
810 RSCONFIG_DMA_ENABLE +
811 (19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) +
813 ((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) +
814 RSCONFIG_DMA_TO_HOST +
815 RSCONFIG_SAMPLE_16STEREO +
816 RSCONFIG_MODULO_64,
817 (mix_buffer_addr + (32 * 4)) << 0x10,
818 1,0,
819 0x0001,0x0080,
820 0xFFFF,0
824 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&mix2_ostream_scb,
826 dest,"S16_MIX_TO_OSTREAM",parent_scb,
827 scb_child_type);
829 return scb;
833 dsp_scb_descriptor_t *
834 cs46xx_dsp_create_vari_decimate_scb(cs46xx_t * chip,char * scb_name,
835 u16 vari_buffer_addr0,
836 u16 vari_buffer_addr1,
837 u32 dest,
838 dsp_scb_descriptor_t * parent_scb,
839 int scb_child_type)
842 dsp_scb_descriptor_t * scb;
844 vari_decimate_scb_t vari_decimate_scb = {
845 0x0028,0x00c8,
846 0x5555,0x0000,
847 0x0000,0x0000,
848 vari_buffer_addr0,vari_buffer_addr1,
850 0x0028,0x00c8,
851 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256,
853 0xFF800000,
855 0x0080,vari_buffer_addr1 + (25 * 4),
857 0,0,
858 0,0,
860 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
861 vari_buffer_addr0 << 0x10,
862 0x04000000,
864 0x8000,0x8000,
865 0xFFFF,0xFFFF
869 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&vari_decimate_scb,
870 dest,"VARIDECIMATE",parent_scb,
871 scb_child_type);
873 return scb;
877 dsp_scb_descriptor_t *
878 cs46xx_dsp_create_pcm_serial_input_scb(cs46xx_t * chip,char * scb_name,u32 dest,
879 dsp_scb_descriptor_t * input_scb,
880 dsp_scb_descriptor_t * parent_scb,
881 int scb_child_type)
884 dsp_scb_descriptor_t * scb;
887 pcm_serial_input_scb_t pcm_serial_input_scb = {
888 { 0,
901 0,0,
902 0,0,
904 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_16,
906 /* 0xD */ 0,input_scb->address,
908 /* 0xE */ 0x8000,0x8000,
909 /* 0xF */ 0x8000,0x8000
913 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_serial_input_scb,
914 dest,"PCMSERIALINPUTTASK",parent_scb,
915 scb_child_type);
916 return scb;
920 dsp_scb_descriptor_t *
921 cs46xx_dsp_create_asynch_fg_tx_scb(cs46xx_t * chip,char * scb_name,u32 dest,
922 u16 hfg_scb_address,
923 u16 asynch_buffer_address,
924 dsp_scb_descriptor_t * parent_scb,
925 int scb_child_type)
928 dsp_scb_descriptor_t * scb;
930 asynch_fg_tx_scb_t asynch_fg_tx_scb = {
931 0xfc00,0x03ff, /* Prototype sample buffer size of 256 dwords */
932 0x0058,0x0028, /* Min Delta 7 dwords == 28 bytes */
933 /* : Max delta 25 dwords == 100 bytes */
934 0,hfg_scb_address, /* Point to HFG task SCB */
935 0,0, /* Initialize current Delta and Consumer ptr adjustment count */
936 0, /* Initialize accumulated Phi to 0 */
937 0,0x2aab, /* Const 1/3 */
940 0, /* Define the unused elements */
945 0,0,
946 0,dest + AFGTxAccumPhi,
948 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256, /* Stereo, 256 dword */
949 (asynch_buffer_address) << 0x10, /* This should be automagically synchronized
950 to the producer pointer */
952 /* There is no correct initial value, it will depend upon the detected
953 rate etc */
954 0x18000000, /* Phi increment for approx 32k operation */
955 0x8000,0x8000, /* Volume controls are unused at this time */
956 0x8000,0x8000
959 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_tx_scb,
960 dest,"ASYNCHFGTXCODE",parent_scb,
961 scb_child_type);
963 return scb;
967 dsp_scb_descriptor_t *
968 cs46xx_dsp_create_asynch_fg_rx_scb(cs46xx_t * chip,char * scb_name,u32 dest,
969 u16 hfg_scb_address,
970 u16 asynch_buffer_address,
971 dsp_scb_descriptor_t * parent_scb,
972 int scb_child_type)
974 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
975 dsp_scb_descriptor_t * scb;
977 asynch_fg_rx_scb_t asynch_fg_rx_scb = {
978 0xfe00,0x01ff, /* Prototype sample buffer size of 128 dwords */
979 0x0064,0x001c, /* Min Delta 7 dwords == 28 bytes */
980 /* : Max delta 25 dwords == 100 bytes */
981 0,hfg_scb_address, /* Point to HFG task SCB */
982 0,0, /* Initialize current Delta and Consumer ptr adjustment count */
984 0, /* Define the unused elements */
991 0,0,
992 0,dest,
994 RSCONFIG_MODULO_128 |
995 RSCONFIG_SAMPLE_16STEREO, /* Stereo, 128 dword */
996 ( (asynch_buffer_address + (16 * 4)) << 0x10), /* This should be automagically
997 synchrinized to the producer pointer */
999 /* There is no correct initial value, it will depend upon the detected
1000 rate etc */
1001 0x18000000,
1003 /* Set IEC958 input volume */
1004 0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
1005 0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
1008 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_rx_scb,
1009 dest,"ASYNCHFGRXCODE",parent_scb,
1010 scb_child_type);
1012 return scb;
1016 dsp_scb_descriptor_t *
1017 cs46xx_dsp_create_output_snoop_scb(cs46xx_t * chip,char * scb_name,u32 dest,
1018 u16 snoop_buffer_address,
1019 dsp_scb_descriptor_t * snoop_scb,
1020 dsp_scb_descriptor_t * parent_scb,
1021 int scb_child_type)
1024 dsp_scb_descriptor_t * scb;
1026 output_snoop_scb_t output_snoop_scb = {
1027 { 0, /* not used. Zero */
1033 0, /* not used. Zero */
1040 0,0,
1041 0,0,
1043 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
1044 snoop_buffer_address << 0x10,
1045 0,0,
1047 0,snoop_scb->address
1050 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&output_snoop_scb,
1051 dest,"OUTPUTSNOOP",parent_scb,
1052 scb_child_type);
1053 return scb;
1057 dsp_scb_descriptor_t *
1058 cs46xx_dsp_create_spio_write_scb(cs46xx_t * chip,char * scb_name,u32 dest,
1059 dsp_scb_descriptor_t * parent_scb,
1060 int scb_child_type)
1062 dsp_scb_descriptor_t * scb;
1064 spio_write_scb_t spio_write_scb = {
1065 0,0, /* SPIOWAddress2:SPIOWAddress1; */
1066 0, /* SPIOWData1; */
1067 0, /* SPIOWData2; */
1068 0,0, /* SPIOWAddress4:SPIOWAddress3; */
1069 0, /* SPIOWData3; */
1070 0, /* SPIOWData4; */
1071 0,0, /* SPIOWDataPtr:Unused1; */
1072 { 0,0 }, /* Unused2[2]; */
1074 0,0, /* SPIOWChildPtr:SPIOWSiblingPtr; */
1075 0,0, /* SPIOWThisPtr:SPIOWEntryPoint; */
1082 0 /* Unused3[5]; */
1086 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&spio_write_scb,
1087 dest,"SPIOWRITE",parent_scb,
1088 scb_child_type);
1090 return scb;
1093 dsp_scb_descriptor_t * cs46xx_dsp_create_magic_snoop_scb(cs46xx_t * chip,char * scb_name,u32 dest,
1094 u16 snoop_buffer_address,
1095 dsp_scb_descriptor_t * snoop_scb,
1096 dsp_scb_descriptor_t * parent_scb,
1097 int scb_child_type)
1099 dsp_scb_descriptor_t * scb;
1101 magic_snoop_task_t magic_snoop_scb = {
1102 /* 0 */ 0, /* i0 */
1103 /* 1 */ 0, /* i1 */
1104 /* 2 */ snoop_buffer_address << 0x10,
1105 /* 3 */ 0,snoop_scb->address,
1106 /* 4 */ 0, /* i3 */
1107 /* 5 */ 0, /* i4 */
1108 /* 6 */ 0, /* i5 */
1109 /* 7 */ 0, /* i6 */
1110 /* 8 */ 0, /* i7 */
1111 /* 9 */ 0,0, /* next_scb, sub_list_ptr */
1112 /* A */ 0,0, /* entry_point, this_ptr */
1113 /* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
1114 /* C */ snoop_buffer_address << 0x10,
1115 /* D */ 0,
1116 /* E */ { 0x8000,0x8000,
1117 /* F */ 0xffff,0xffff
1121 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&magic_snoop_scb,
1122 dest,"MAGICSNOOPTASK",parent_scb,
1123 scb_child_type);
1125 return scb;
1128 static dsp_scb_descriptor_t * find_next_free_scb (cs46xx_t * chip,dsp_scb_descriptor_t * from)
1130 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1131 dsp_scb_descriptor_t * scb = from;
1133 while (scb->next_scb_ptr != ins->the_null_scb) {
1134 snd_assert (scb->next_scb_ptr != NULL, return NULL);
1136 scb = scb->next_scb_ptr;
1139 return scb;
1142 static u32 pcm_reader_buffer_addr[DSP_MAX_PCM_CHANNELS] = {
1143 0x0600, /* 1 */
1144 0x1500, /* 2 */
1145 0x1580, /* 3 */
1146 0x1600, /* 4 */
1147 0x1680, /* 5 */
1148 0x1700, /* 6 */
1149 0x1780, /* 7 */
1150 0x1800, /* 8 */
1151 0x1880, /* 9 */
1152 0x1900, /* 10 */
1153 0x1980, /* 11 */
1154 0x1A00, /* 12 */
1155 0x1A80, /* 13 */
1156 0x1B00, /* 14 */
1157 0x1B80, /* 15 */
1158 0x1C00, /* 16 */
1159 0x1C80, /* 17 */
1160 0x1D00, /* 18 */
1161 0x1D80, /* 19 */
1162 0x1E00, /* 20 */
1163 0x1E80, /* 21 */
1164 0x1F00, /* 22 */
1165 0x1F80, /* 23 */
1166 0x2000, /* 24 */
1167 0x2080, /* 25 */
1168 0x2100, /* 26 */
1169 0x2180, /* 27 */
1170 0x2200, /* 28 */
1171 0x2280, /* 29 */
1172 0x2300, /* 30 */
1173 0x2380, /* 31 */
1174 0x2400, /* 32 */
1177 static u32 src_output_buffer_addr[DSP_MAX_SRC_NR] = {
1178 0x2B80,
1179 0x2BA0,
1180 0x2BC0,
1181 0x2BE0,
1182 0x2D00,
1183 0x2D20,
1184 0x2D40,
1185 0x2D60,
1186 0x2D80,
1187 0x2DA0,
1188 0x2DC0,
1189 0x2DE0,
1190 0x2E00,
1191 0x2E20
1194 static u32 src_delay_buffer_addr[DSP_MAX_SRC_NR] = {
1195 0x2480,
1196 0x2500,
1197 0x2580,
1198 0x2600,
1199 0x2680,
1200 0x2700,
1201 0x2780,
1202 0x2800,
1203 0x2880,
1204 0x2900,
1205 0x2980,
1206 0x2A00,
1207 0x2A80,
1208 0x2B00
1211 pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,
1212 u32 sample_rate, void * private_data,
1213 u32 hw_dma_addr,
1214 int pcm_channel_id)
1216 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1217 dsp_scb_descriptor_t * src_scb = NULL,* pcm_scb, * mixer_scb = NULL;
1218 dsp_scb_descriptor_t * src_parent_scb = NULL;
1220 /* dsp_scb_descriptor_t * pcm_parent_scb; */
1221 char scb_name[DSP_MAX_SCB_NAME];
1222 int i,pcm_index = -1, insert_point, src_index = -1,pass_through = 0;
1223 unsigned long flags;
1225 switch (pcm_channel_id) {
1226 case DSP_PCM_MAIN_CHANNEL:
1227 mixer_scb = ins->master_mix_scb;
1228 break;
1229 case DSP_PCM_REAR_CHANNEL:
1230 mixer_scb = ins->rear_mix_scb;
1231 break;
1232 case DSP_PCM_CENTER_LFE_CHANNEL:
1233 mixer_scb = ins->center_lfe_mix_scb;
1234 break;
1235 case DSP_PCM_S71_CHANNEL:
1236 /* TODO */
1237 snd_assert(0);
1238 break;
1239 case DSP_IEC958_CHANNEL:
1240 snd_assert (ins->asynch_tx_scb != NULL, return NULL);
1241 mixer_scb = ins->asynch_tx_scb;
1243 /* if sample rate is set to 48khz we pass
1244 the Sample Rate Converted (which could
1245 alter the raw data stream ...) */
1246 if (sample_rate == 48000) {
1247 snd_printdd ("IEC958 pass through\n");
1248 /* Hack to bypass creating a new SRC */
1249 pass_through = 1;
1251 break;
1252 default:
1253 snd_assert (0);
1254 return NULL;
1256 /* default sample rate is 44100 */
1257 if (!sample_rate) sample_rate = 44100;
1259 /* search for a already created SRC SCB with the same sample rate */
1260 for (i = 0; i < DSP_MAX_PCM_CHANNELS &&
1261 (pcm_index == -1 || src_scb == NULL); ++i) {
1263 /* virtual channel reserved
1264 for capture */
1265 if (i == CS46XX_DSP_CAPTURE_CHANNEL) continue;
1267 if (ins->pcm_channels[i].active) {
1268 if (!src_scb &&
1269 ins->pcm_channels[i].sample_rate == sample_rate &&
1270 ins->pcm_channels[i].mixer_scb == mixer_scb) {
1271 src_scb = ins->pcm_channels[i].src_scb;
1272 ins->pcm_channels[i].src_scb->ref_count ++;
1273 src_index = ins->pcm_channels[i].src_slot;
1275 } else if (pcm_index == -1) {
1276 pcm_index = i;
1280 if (pcm_index == -1) {
1281 snd_printk (KERN_ERR "dsp_spos: no free PCM channel\n");
1282 return NULL;
1285 if (src_scb == NULL) {
1286 if (ins->nsrc_scb >= DSP_MAX_SRC_NR) {
1287 snd_printk(KERN_ERR "dsp_spos: to many SRC instances\n!");
1288 return NULL;
1291 /* find a free slot */
1292 for (i = 0; i < DSP_MAX_SRC_NR; ++i) {
1293 if (ins->src_scb_slots[i] == 0) {
1294 src_index = i;
1295 ins->src_scb_slots[i] = 1;
1296 break;
1299 snd_assert (src_index != -1,return NULL);
1301 /* we need to create a new SRC SCB */
1302 if (mixer_scb->sub_list_ptr == ins->the_null_scb) {
1303 src_parent_scb = mixer_scb;
1304 insert_point = SCB_ON_PARENT_SUBLIST_SCB;
1305 } else {
1306 src_parent_scb = find_next_free_scb(chip,mixer_scb->sub_list_ptr);
1307 insert_point = SCB_ON_PARENT_NEXT_SCB;
1310 snprintf (scb_name,DSP_MAX_SCB_NAME,"SrcTask_SCB%d",src_index);
1312 snd_printdd( "dsp_spos: creating SRC \"%s\"\n",scb_name);
1313 src_scb = cs46xx_dsp_create_src_task_scb(chip,scb_name,
1314 sample_rate,
1315 src_output_buffer_addr[src_index],
1316 src_delay_buffer_addr[src_index],
1317 /* 0x400 - 0x600 source SCBs */
1318 0x400 + (src_index * 0x10) ,
1319 src_parent_scb,
1320 insert_point,
1321 pass_through);
1323 if (!src_scb) {
1324 snd_printk (KERN_ERR "dsp_spos: failed to create SRCtaskSCB\n");
1325 return NULL;
1328 /* cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate); */
1330 ins->nsrc_scb ++;
1334 snprintf (scb_name,DSP_MAX_SCB_NAME,"PCMReader_SCB%d",pcm_index);
1336 snd_printdd( "dsp_spos: creating PCM \"%s\" (%d)\n",scb_name,
1337 pcm_channel_id);
1339 pcm_scb = cs46xx_dsp_create_pcm_reader_scb(chip,scb_name,
1340 pcm_reader_buffer_addr[pcm_index],
1341 /* 0x200 - 400 PCMreader SCBs */
1342 (pcm_index * 0x10) + 0x200,
1343 pcm_index, /* virtual channel 0-31 */
1344 hw_dma_addr, /* pcm hw addr */
1345 NULL, /* parent SCB ptr */
1346 0 /* insert point */
1349 if (!pcm_scb) {
1350 snd_printk (KERN_ERR "dsp_spos: failed to create PCMreaderSCB\n");
1351 return NULL;
1354 spin_lock_irqsave(&chip->reg_lock, flags);
1355 ins->pcm_channels[pcm_index].sample_rate = sample_rate;
1356 ins->pcm_channels[pcm_index].pcm_reader_scb = pcm_scb;
1357 ins->pcm_channels[pcm_index].src_scb = src_scb;
1358 ins->pcm_channels[pcm_index].unlinked = 1;
1359 ins->pcm_channels[pcm_index].private_data = private_data;
1360 ins->pcm_channels[pcm_index].src_slot = src_index;
1361 ins->pcm_channels[pcm_index].active = 1;
1362 ins->pcm_channels[pcm_index].pcm_slot = pcm_index;
1363 ins->pcm_channels[pcm_index].mixer_scb = mixer_scb;
1364 ins->npcm_channels ++;
1365 spin_unlock_irqrestore(&chip->reg_lock, flags);
1367 return (ins->pcm_channels + pcm_index);
1370 int cs46xx_dsp_pcm_channel_set_period (cs46xx_t * chip,
1371 pcm_channel_descriptor_t * pcm_channel,
1372 int period_size)
1374 u32 temp = snd_cs46xx_peek (chip,pcm_channel->pcm_reader_scb->address << 2);
1375 temp &= ~DMA_RQ_C1_SOURCE_SIZE_MASK;
1377 switch (period_size) {
1378 case 2048:
1379 temp |= DMA_RQ_C1_SOURCE_MOD1024;
1380 break;
1381 case 1024:
1382 temp |= DMA_RQ_C1_SOURCE_MOD512;
1383 break;
1384 case 512:
1385 temp |= DMA_RQ_C1_SOURCE_MOD256;
1386 break;
1387 case 256:
1388 temp |= DMA_RQ_C1_SOURCE_MOD128;
1389 break;
1390 case 128:
1391 temp |= DMA_RQ_C1_SOURCE_MOD64;
1392 break;
1393 case 64:
1394 temp |= DMA_RQ_C1_SOURCE_MOD32;
1395 break;
1396 case 32:
1397 temp |= DMA_RQ_C1_SOURCE_MOD16;
1398 break;
1399 default:
1400 snd_printdd ("period size (%d) not supported by HW\n", period_size);
1401 return -EINVAL;
1404 snd_cs46xx_poke (chip,pcm_channel->pcm_reader_scb->address << 2,temp);
1406 return 0;
1409 int cs46xx_dsp_pcm_ostream_set_period (cs46xx_t * chip,
1410 int period_size)
1412 u32 temp = snd_cs46xx_peek (chip,WRITEBACK_SCB_ADDR << 2);
1413 temp &= ~DMA_RQ_C1_DEST_SIZE_MASK;
1415 switch (period_size) {
1416 case 2048:
1417 temp |= DMA_RQ_C1_DEST_MOD1024;
1418 break;
1419 case 1024:
1420 temp |= DMA_RQ_C1_DEST_MOD512;
1421 break;
1422 case 512:
1423 temp |= DMA_RQ_C1_DEST_MOD256;
1424 break;
1425 case 256:
1426 temp |= DMA_RQ_C1_DEST_MOD128;
1427 break;
1428 case 128:
1429 temp |= DMA_RQ_C1_DEST_MOD64;
1430 break;
1431 case 64:
1432 temp |= DMA_RQ_C1_DEST_MOD32;
1433 break;
1434 case 32:
1435 temp |= DMA_RQ_C1_DEST_MOD16;
1436 break;
1437 default:
1438 snd_printdd ("period size (%d) not supported by HW\n", period_size);
1439 return -EINVAL;
1442 snd_cs46xx_poke (chip,WRITEBACK_SCB_ADDR << 2,temp);
1444 return 0;
1447 void cs46xx_dsp_destroy_pcm_channel (cs46xx_t * chip,pcm_channel_descriptor_t * pcm_channel)
1449 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1450 unsigned long flags;
1452 snd_assert(pcm_channel->active, return );
1453 snd_assert(ins->npcm_channels > 0, return );
1454 snd_assert(pcm_channel->src_scb->ref_count > 0, return );
1456 spin_lock_irqsave(&chip->reg_lock, flags);
1457 pcm_channel->unlinked = 1;
1458 pcm_channel->active = 0;
1459 pcm_channel->private_data = NULL;
1460 pcm_channel->src_scb->ref_count --;
1461 ins->npcm_channels --;
1462 spin_unlock_irqrestore(&chip->reg_lock, flags);
1464 cs46xx_dsp_remove_scb(chip,pcm_channel->pcm_reader_scb);
1466 if (!pcm_channel->src_scb->ref_count) {
1467 cs46xx_dsp_remove_scb(chip,pcm_channel->src_scb);
1469 snd_assert (pcm_channel->src_slot >= 0 && pcm_channel->src_slot <= DSP_MAX_SRC_NR,
1470 return );
1472 ins->src_scb_slots[pcm_channel->src_slot] = 0;
1473 ins->nsrc_scb --;
1477 int cs46xx_dsp_pcm_unlink (cs46xx_t * chip,pcm_channel_descriptor_t * pcm_channel)
1479 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1480 unsigned long flags;
1482 snd_assert(pcm_channel->active,return -EIO);
1483 snd_assert(ins->npcm_channels > 0,return -EIO);
1485 spin_lock(&pcm_channel->src_scb->lock);
1487 if (pcm_channel->unlinked) {
1488 spin_unlock(&pcm_channel->src_scb->lock);
1489 return -EIO;
1492 spin_lock_irqsave(&chip->reg_lock, flags);
1493 pcm_channel->unlinked = 1;
1494 spin_unlock_irqrestore(&chip->reg_lock, flags);
1496 _dsp_unlink_scb (chip,pcm_channel->pcm_reader_scb);
1498 spin_unlock(&pcm_channel->src_scb->lock);
1499 return 0;
1502 int cs46xx_dsp_pcm_link (cs46xx_t * chip,pcm_channel_descriptor_t * pcm_channel)
1504 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1505 dsp_scb_descriptor_t * parent_scb;
1506 dsp_scb_descriptor_t * src_scb = pcm_channel->src_scb;
1507 unsigned long flags;
1509 spin_lock(&pcm_channel->src_scb->lock);
1511 if (pcm_channel->unlinked == 0) {
1512 spin_unlock(&pcm_channel->src_scb->lock);
1513 return -EIO;
1516 parent_scb = src_scb;
1518 if (src_scb->sub_list_ptr != ins->the_null_scb) {
1519 src_scb->sub_list_ptr->parent_scb_ptr = pcm_channel->pcm_reader_scb;
1520 pcm_channel->pcm_reader_scb->next_scb_ptr = src_scb->sub_list_ptr;
1523 src_scb->sub_list_ptr = pcm_channel->pcm_reader_scb;
1525 snd_assert (pcm_channel->pcm_reader_scb->parent_scb_ptr == NULL, ; );
1526 pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb;
1528 spin_lock_irqsave(&chip->reg_lock, flags);
1530 /* update SCB entry in DSP RAM */
1531 cs46xx_dsp_spos_update_scb(chip,pcm_channel->pcm_reader_scb);
1533 /* update parent SCB entry */
1534 cs46xx_dsp_spos_update_scb(chip,parent_scb);
1536 pcm_channel->unlinked = 0;
1537 spin_unlock_irqrestore(&chip->reg_lock, flags);
1539 spin_unlock(&pcm_channel->src_scb->lock);
1540 return 0;
1543 dsp_scb_descriptor_t * cs46xx_add_record_source (cs46xx_t *chip,dsp_scb_descriptor_t * source,
1544 u16 addr,char * scb_name)
1546 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1547 dsp_scb_descriptor_t * parent;
1548 dsp_scb_descriptor_t * pcm_input;
1549 int insert_point;
1551 snd_assert (ins->record_mixer_scb != NULL,return NULL);
1553 if (ins->record_mixer_scb->sub_list_ptr != ins->the_null_scb) {
1554 parent = find_next_free_scb (chip,ins->record_mixer_scb->sub_list_ptr);
1555 insert_point = SCB_ON_PARENT_NEXT_SCB;
1556 } else {
1557 parent = ins->record_mixer_scb;
1558 insert_point = SCB_ON_PARENT_SUBLIST_SCB;
1561 pcm_input = cs46xx_dsp_create_pcm_serial_input_scb(chip,scb_name,addr,
1562 source, parent,
1563 insert_point);
1565 return pcm_input;
1568 int cs46xx_src_unlink(cs46xx_t *chip,dsp_scb_descriptor_t * src)
1570 snd_assert (src->parent_scb_ptr != NULL, return -EINVAL );
1572 /* mute SCB */
1573 cs46xx_dsp_scb_set_volume (chip,src,0,0);
1575 _dsp_unlink_scb (chip,src);
1577 return 0;
1580 int cs46xx_src_link(cs46xx_t *chip,dsp_scb_descriptor_t * src)
1582 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1583 dsp_scb_descriptor_t * parent_scb;
1585 snd_assert (src->parent_scb_ptr == NULL, return -EINVAL );
1586 snd_assert(ins->master_mix_scb !=NULL, return -EINVAL );
1588 if (ins->master_mix_scb->sub_list_ptr != ins->the_null_scb) {
1589 parent_scb = find_next_free_scb (chip,ins->master_mix_scb->sub_list_ptr);
1590 parent_scb->next_scb_ptr = src;
1591 } else {
1592 parent_scb = ins->master_mix_scb;
1593 parent_scb->sub_list_ptr = src;
1596 src->parent_scb_ptr = parent_scb;
1598 /* update entry in DSP RAM */
1599 cs46xx_dsp_spos_update_scb(chip,parent_scb);
1601 return 0;
1604 int cs46xx_dsp_enable_spdif_out (cs46xx_t *chip)
1606 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1608 if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
1609 cs46xx_dsp_enable_spdif_hw (chip);
1612 /* dont touch anything if SPDIF is open */
1613 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
1614 /* when cs46xx_iec958_post_close(...) is called it
1615 will call this function if necessary depending on
1616 this bit */
1617 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1619 return -EBUSY;
1622 snd_assert (ins->asynch_tx_scb == NULL, return -EINVAL);
1623 snd_assert (ins->master_mix_scb->next_scb_ptr == ins->the_null_scb, return -EINVAL);
1625 /* reset output snooper sample buffer pointer */
1626 snd_cs46xx_poke (chip, (ins->ref_snoop_scb->address + 2) << 2,
1627 (OUTPUT_SNOOP_BUFFER + 0x10) << 0x10 );
1629 /* The asynch. transfer task */
1630 ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
1631 SPDIFO_SCB_INST,
1632 SPDIFO_IP_OUTPUT_BUFFER1,
1633 ins->master_mix_scb,
1634 SCB_ON_PARENT_NEXT_SCB);
1635 if (!ins->asynch_tx_scb) return -ENOMEM;
1637 ins->spdif_pcm_input_scb = cs46xx_dsp_create_pcm_serial_input_scb(chip,"PCMSerialInput_II",
1638 PCMSERIALINII_SCB_ADDR,
1639 ins->ref_snoop_scb,
1640 ins->asynch_tx_scb,
1641 SCB_ON_PARENT_SUBLIST_SCB);
1644 if (!ins->spdif_pcm_input_scb) return -ENOMEM;
1646 /* monitor state */
1647 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1649 return 0;
1652 int cs46xx_dsp_disable_spdif_out (cs46xx_t *chip)
1654 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1656 /* dont touch anything if SPDIF is open */
1657 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
1658 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1659 return -EBUSY;
1662 /* check integrety */
1663 snd_assert (ins->asynch_tx_scb != NULL, return -EINVAL);
1664 snd_assert (ins->spdif_pcm_input_scb != NULL,return -EINVAL);
1665 snd_assert (ins->master_mix_scb->next_scb_ptr == ins->asynch_tx_scb, return -EINVAL);
1666 snd_assert (ins->asynch_tx_scb->parent_scb_ptr == ins->master_mix_scb, return -EINVAL);
1668 cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
1669 cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
1671 ins->spdif_pcm_input_scb = NULL;
1672 ins->asynch_tx_scb = NULL;
1674 /* clear buffer to prevent any undesired noise */
1675 _dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
1677 /* monitor state */
1678 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1681 return 0;
1684 int cs46xx_iec958_pre_open (cs46xx_t *chip)
1686 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1688 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
1689 /* remove AsynchFGTxSCB and and PCMSerialInput_II */
1690 cs46xx_dsp_disable_spdif_out (chip);
1692 /* save state */
1693 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1696 /* if not enabled already */
1697 if ( !(ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
1698 cs46xx_dsp_enable_spdif_hw (chip);
1701 /* Create the asynch. transfer task for playback */
1702 ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
1703 SPDIFO_SCB_INST,
1704 SPDIFO_IP_OUTPUT_BUFFER1,
1705 ins->master_mix_scb,
1706 SCB_ON_PARENT_NEXT_SCB);
1709 /* set spdif channel status value for streaming */
1710 cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_stream);
1712 ins->spdif_status_out |= DSP_SPDIF_STATUS_PLAYBACK_OPEN;
1714 return 0;
1717 int cs46xx_iec958_post_close (cs46xx_t *chip)
1719 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1721 snd_assert (ins->asynch_tx_scb != NULL, return -EINVAL);
1723 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_PLAYBACK_OPEN;
1725 /* restore settings */
1726 cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);
1728 /* deallocate stuff */
1729 if (ins->spdif_pcm_input_scb != NULL) {
1730 cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
1731 ins->spdif_pcm_input_scb = NULL;
1734 cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
1735 ins->asynch_tx_scb = NULL;
1737 /* clear buffer to prevent any undesired noise */
1738 _dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
1740 /* restore state */
1741 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
1742 cs46xx_dsp_enable_spdif_out (chip);
1745 return 0;