Linux-2.6.12-rc2
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / sound / pci / cs46xx / dsp_spos_scb_lib.c
blob92849e1340bbfbfe18644ecf3bbfbbc83f27887a
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 void __iomem *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 void __iomem *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 static 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 static 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 #if 0 /* not used */
691 dsp_scb_descriptor_t *
692 cs46xx_dsp_create_filter_scb(cs46xx_t * chip,char * scb_name,
693 u16 buffer_addr,u32 dest,
694 dsp_scb_descriptor_t * parent_scb,
695 int scb_child_type) {
696 dsp_scb_descriptor_t * scb;
698 filter_scb_t filter_scb = {
699 .a0_right = 0x41a9,
700 .a0_left = 0x41a9,
701 .a1_right = 0xb8e4,
702 .a1_left = 0xb8e4,
703 .a2_right = 0x3e55,
704 .a2_left = 0x3e55,
706 .filter_unused3 = 0x0000,
707 .filter_unused2 = 0x0000,
709 .output_buf_ptr = buffer_addr,
710 .init = 0x000,
712 .prev_sample_output1 = 0x00000000,
713 .prev_sample_output2 = 0x00000000,
715 .prev_sample_input1 = 0x00000000,
716 .prev_sample_input2 = 0x00000000,
718 .next_scb_ptr = 0x0000,
719 .sub_list_ptr = 0x0000,
721 .entry_point = 0x0000,
722 .spb_ptr = 0x0000,
724 .b0_right = 0x0e38,
725 .b0_left = 0x0e38,
726 .b1_right = 0x1c71,
727 .b1_left = 0x1c71,
728 .b2_right = 0x0e38,
729 .b2_left = 0x0e38,
733 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&filter_scb,
734 dest,"FILTERTASK",parent_scb,
735 scb_child_type);
737 return scb;
739 #endif /* not used */
741 dsp_scb_descriptor_t *
742 cs46xx_dsp_create_mix_only_scb(cs46xx_t * chip,char * scb_name,
743 u16 mix_buffer_addr,u32 dest,
744 dsp_scb_descriptor_t * parent_scb,
745 int scb_child_type)
747 dsp_scb_descriptor_t * scb;
749 mix_only_scb_t master_mix_scb = {
750 /* 0 */ { 0,
751 /* 1 */ 0,
752 /* 2 */ mix_buffer_addr,
753 /* 3 */ 0
754 /* */ },
756 /* 4 */ 0,
757 /* 5 */ 0,
758 /* 6 */ 0,
759 /* 7 */ 0,
760 /* 8 */ 0x00000080
762 /* 9 */ 0,0,
763 /* A */ 0,0,
764 /* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
765 /* C */ (mix_buffer_addr + (16 * 4)) << 0x10,
766 /* D */ 0,
768 /* E */ 0x8000,0x8000,
769 /* F */ 0x8000,0x8000
774 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&master_mix_scb,
775 dest,"S16_MIX",parent_scb,
776 scb_child_type);
777 return scb;
781 dsp_scb_descriptor_t *
782 cs46xx_dsp_create_mix_to_ostream_scb(cs46xx_t * chip,char * scb_name,
783 u16 mix_buffer_addr,u16 writeback_spb,u32 dest,
784 dsp_scb_descriptor_t * parent_scb,
785 int scb_child_type)
787 dsp_scb_descriptor_t * scb;
789 mix2_ostream_scb_t mix2_ostream_scb = {
790 /* Basic (non scatter/gather) DMA requestor (4 ints) */
792 DMA_RQ_C1_SOURCE_MOD64 +
793 DMA_RQ_C1_DEST_ON_HOST +
794 DMA_RQ_C1_DEST_MOD1024 +
795 DMA_RQ_C1_WRITEBACK_SRC_FLAG +
796 DMA_RQ_C1_WRITEBACK_DEST_FLAG +
797 15,
799 DMA_RQ_C2_AC_NONE +
800 DMA_RQ_C2_SIGNAL_DEST_PINGPONG +
802 CS46XX_DSP_CAPTURE_CHANNEL,
803 DMA_RQ_SD_SP_SAMPLE_ADDR +
804 mix_buffer_addr,
805 0x0
808 { 0, 0, 0, 0, 0, },
809 0,0,
810 0,writeback_spb,
812 RSCONFIG_DMA_ENABLE +
813 (19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) +
815 ((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) +
816 RSCONFIG_DMA_TO_HOST +
817 RSCONFIG_SAMPLE_16STEREO +
818 RSCONFIG_MODULO_64,
819 (mix_buffer_addr + (32 * 4)) << 0x10,
820 1,0,
821 0x0001,0x0080,
822 0xFFFF,0
826 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&mix2_ostream_scb,
828 dest,"S16_MIX_TO_OSTREAM",parent_scb,
829 scb_child_type);
831 return scb;
835 dsp_scb_descriptor_t *
836 cs46xx_dsp_create_vari_decimate_scb(cs46xx_t * chip,char * scb_name,
837 u16 vari_buffer_addr0,
838 u16 vari_buffer_addr1,
839 u32 dest,
840 dsp_scb_descriptor_t * parent_scb,
841 int scb_child_type)
844 dsp_scb_descriptor_t * scb;
846 vari_decimate_scb_t vari_decimate_scb = {
847 0x0028,0x00c8,
848 0x5555,0x0000,
849 0x0000,0x0000,
850 vari_buffer_addr0,vari_buffer_addr1,
852 0x0028,0x00c8,
853 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256,
855 0xFF800000,
857 0x0080,vari_buffer_addr1 + (25 * 4),
859 0,0,
860 0,0,
862 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
863 vari_buffer_addr0 << 0x10,
864 0x04000000,
866 0x8000,0x8000,
867 0xFFFF,0xFFFF
871 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&vari_decimate_scb,
872 dest,"VARIDECIMATE",parent_scb,
873 scb_child_type);
875 return scb;
879 static dsp_scb_descriptor_t *
880 cs46xx_dsp_create_pcm_serial_input_scb(cs46xx_t * chip,char * scb_name,u32 dest,
881 dsp_scb_descriptor_t * input_scb,
882 dsp_scb_descriptor_t * parent_scb,
883 int scb_child_type)
886 dsp_scb_descriptor_t * scb;
889 pcm_serial_input_scb_t pcm_serial_input_scb = {
890 { 0,
903 0,0,
904 0,0,
906 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_16,
908 /* 0xD */ 0,input_scb->address,
910 /* 0xE */ 0x8000,0x8000,
911 /* 0xF */ 0x8000,0x8000
915 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_serial_input_scb,
916 dest,"PCMSERIALINPUTTASK",parent_scb,
917 scb_child_type);
918 return scb;
922 static dsp_scb_descriptor_t *
923 cs46xx_dsp_create_asynch_fg_tx_scb(cs46xx_t * chip,char * scb_name,u32 dest,
924 u16 hfg_scb_address,
925 u16 asynch_buffer_address,
926 dsp_scb_descriptor_t * parent_scb,
927 int scb_child_type)
930 dsp_scb_descriptor_t * scb;
932 asynch_fg_tx_scb_t asynch_fg_tx_scb = {
933 0xfc00,0x03ff, /* Prototype sample buffer size of 256 dwords */
934 0x0058,0x0028, /* Min Delta 7 dwords == 28 bytes */
935 /* : Max delta 25 dwords == 100 bytes */
936 0,hfg_scb_address, /* Point to HFG task SCB */
937 0,0, /* Initialize current Delta and Consumer ptr adjustment count */
938 0, /* Initialize accumulated Phi to 0 */
939 0,0x2aab, /* Const 1/3 */
942 0, /* Define the unused elements */
947 0,0,
948 0,dest + AFGTxAccumPhi,
950 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256, /* Stereo, 256 dword */
951 (asynch_buffer_address) << 0x10, /* This should be automagically synchronized
952 to the producer pointer */
954 /* There is no correct initial value, it will depend upon the detected
955 rate etc */
956 0x18000000, /* Phi increment for approx 32k operation */
957 0x8000,0x8000, /* Volume controls are unused at this time */
958 0x8000,0x8000
961 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_tx_scb,
962 dest,"ASYNCHFGTXCODE",parent_scb,
963 scb_child_type);
965 return scb;
969 dsp_scb_descriptor_t *
970 cs46xx_dsp_create_asynch_fg_rx_scb(cs46xx_t * chip,char * scb_name,u32 dest,
971 u16 hfg_scb_address,
972 u16 asynch_buffer_address,
973 dsp_scb_descriptor_t * parent_scb,
974 int scb_child_type)
976 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
977 dsp_scb_descriptor_t * scb;
979 asynch_fg_rx_scb_t asynch_fg_rx_scb = {
980 0xfe00,0x01ff, /* Prototype sample buffer size of 128 dwords */
981 0x0064,0x001c, /* Min Delta 7 dwords == 28 bytes */
982 /* : Max delta 25 dwords == 100 bytes */
983 0,hfg_scb_address, /* Point to HFG task SCB */
984 0,0, /* Initialize current Delta and Consumer ptr adjustment count */
986 0, /* Define the unused elements */
993 0,0,
994 0,dest,
996 RSCONFIG_MODULO_128 |
997 RSCONFIG_SAMPLE_16STEREO, /* Stereo, 128 dword */
998 ( (asynch_buffer_address + (16 * 4)) << 0x10), /* This should be automagically
999 synchrinized to the producer pointer */
1001 /* There is no correct initial value, it will depend upon the detected
1002 rate etc */
1003 0x18000000,
1005 /* Set IEC958 input volume */
1006 0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
1007 0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
1010 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_rx_scb,
1011 dest,"ASYNCHFGRXCODE",parent_scb,
1012 scb_child_type);
1014 return scb;
1018 #if 0 /* not used */
1019 dsp_scb_descriptor_t *
1020 cs46xx_dsp_create_output_snoop_scb(cs46xx_t * chip,char * scb_name,u32 dest,
1021 u16 snoop_buffer_address,
1022 dsp_scb_descriptor_t * snoop_scb,
1023 dsp_scb_descriptor_t * parent_scb,
1024 int scb_child_type)
1027 dsp_scb_descriptor_t * scb;
1029 output_snoop_scb_t output_snoop_scb = {
1030 { 0, /* not used. Zero */
1036 0, /* not used. Zero */
1043 0,0,
1044 0,0,
1046 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
1047 snoop_buffer_address << 0x10,
1048 0,0,
1050 0,snoop_scb->address
1053 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&output_snoop_scb,
1054 dest,"OUTPUTSNOOP",parent_scb,
1055 scb_child_type);
1056 return scb;
1058 #endif /* not used */
1061 dsp_scb_descriptor_t *
1062 cs46xx_dsp_create_spio_write_scb(cs46xx_t * chip,char * scb_name,u32 dest,
1063 dsp_scb_descriptor_t * parent_scb,
1064 int scb_child_type)
1066 dsp_scb_descriptor_t * scb;
1068 spio_write_scb_t spio_write_scb = {
1069 0,0, /* SPIOWAddress2:SPIOWAddress1; */
1070 0, /* SPIOWData1; */
1071 0, /* SPIOWData2; */
1072 0,0, /* SPIOWAddress4:SPIOWAddress3; */
1073 0, /* SPIOWData3; */
1074 0, /* SPIOWData4; */
1075 0,0, /* SPIOWDataPtr:Unused1; */
1076 { 0,0 }, /* Unused2[2]; */
1078 0,0, /* SPIOWChildPtr:SPIOWSiblingPtr; */
1079 0,0, /* SPIOWThisPtr:SPIOWEntryPoint; */
1086 0 /* Unused3[5]; */
1090 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&spio_write_scb,
1091 dest,"SPIOWRITE",parent_scb,
1092 scb_child_type);
1094 return scb;
1097 dsp_scb_descriptor_t * cs46xx_dsp_create_magic_snoop_scb(cs46xx_t * chip,char * scb_name,u32 dest,
1098 u16 snoop_buffer_address,
1099 dsp_scb_descriptor_t * snoop_scb,
1100 dsp_scb_descriptor_t * parent_scb,
1101 int scb_child_type)
1103 dsp_scb_descriptor_t * scb;
1105 magic_snoop_task_t magic_snoop_scb = {
1106 /* 0 */ 0, /* i0 */
1107 /* 1 */ 0, /* i1 */
1108 /* 2 */ snoop_buffer_address << 0x10,
1109 /* 3 */ 0,snoop_scb->address,
1110 /* 4 */ 0, /* i3 */
1111 /* 5 */ 0, /* i4 */
1112 /* 6 */ 0, /* i5 */
1113 /* 7 */ 0, /* i6 */
1114 /* 8 */ 0, /* i7 */
1115 /* 9 */ 0,0, /* next_scb, sub_list_ptr */
1116 /* A */ 0,0, /* entry_point, this_ptr */
1117 /* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
1118 /* C */ snoop_buffer_address << 0x10,
1119 /* D */ 0,
1120 /* E */ { 0x8000,0x8000,
1121 /* F */ 0xffff,0xffff
1125 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&magic_snoop_scb,
1126 dest,"MAGICSNOOPTASK",parent_scb,
1127 scb_child_type);
1129 return scb;
1132 static dsp_scb_descriptor_t * find_next_free_scb (cs46xx_t * chip,dsp_scb_descriptor_t * from)
1134 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1135 dsp_scb_descriptor_t * scb = from;
1137 while (scb->next_scb_ptr != ins->the_null_scb) {
1138 snd_assert (scb->next_scb_ptr != NULL, return NULL);
1140 scb = scb->next_scb_ptr;
1143 return scb;
1146 static u32 pcm_reader_buffer_addr[DSP_MAX_PCM_CHANNELS] = {
1147 0x0600, /* 1 */
1148 0x1500, /* 2 */
1149 0x1580, /* 3 */
1150 0x1600, /* 4 */
1151 0x1680, /* 5 */
1152 0x1700, /* 6 */
1153 0x1780, /* 7 */
1154 0x1800, /* 8 */
1155 0x1880, /* 9 */
1156 0x1900, /* 10 */
1157 0x1980, /* 11 */
1158 0x1A00, /* 12 */
1159 0x1A80, /* 13 */
1160 0x1B00, /* 14 */
1161 0x1B80, /* 15 */
1162 0x1C00, /* 16 */
1163 0x1C80, /* 17 */
1164 0x1D00, /* 18 */
1165 0x1D80, /* 19 */
1166 0x1E00, /* 20 */
1167 0x1E80, /* 21 */
1168 0x1F00, /* 22 */
1169 0x1F80, /* 23 */
1170 0x2000, /* 24 */
1171 0x2080, /* 25 */
1172 0x2100, /* 26 */
1173 0x2180, /* 27 */
1174 0x2200, /* 28 */
1175 0x2280, /* 29 */
1176 0x2300, /* 30 */
1177 0x2380, /* 31 */
1178 0x2400, /* 32 */
1181 static u32 src_output_buffer_addr[DSP_MAX_SRC_NR] = {
1182 0x2B80,
1183 0x2BA0,
1184 0x2BC0,
1185 0x2BE0,
1186 0x2D00,
1187 0x2D20,
1188 0x2D40,
1189 0x2D60,
1190 0x2D80,
1191 0x2DA0,
1192 0x2DC0,
1193 0x2DE0,
1194 0x2E00,
1195 0x2E20
1198 static u32 src_delay_buffer_addr[DSP_MAX_SRC_NR] = {
1199 0x2480,
1200 0x2500,
1201 0x2580,
1202 0x2600,
1203 0x2680,
1204 0x2700,
1205 0x2780,
1206 0x2800,
1207 0x2880,
1208 0x2900,
1209 0x2980,
1210 0x2A00,
1211 0x2A80,
1212 0x2B00
1215 pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,
1216 u32 sample_rate, void * private_data,
1217 u32 hw_dma_addr,
1218 int pcm_channel_id)
1220 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1221 dsp_scb_descriptor_t * src_scb = NULL,* pcm_scb, * mixer_scb = NULL;
1222 dsp_scb_descriptor_t * src_parent_scb = NULL;
1224 /* dsp_scb_descriptor_t * pcm_parent_scb; */
1225 char scb_name[DSP_MAX_SCB_NAME];
1226 int i,pcm_index = -1, insert_point, src_index = -1,pass_through = 0;
1227 unsigned long flags;
1229 switch (pcm_channel_id) {
1230 case DSP_PCM_MAIN_CHANNEL:
1231 mixer_scb = ins->master_mix_scb;
1232 break;
1233 case DSP_PCM_REAR_CHANNEL:
1234 mixer_scb = ins->rear_mix_scb;
1235 break;
1236 case DSP_PCM_CENTER_LFE_CHANNEL:
1237 mixer_scb = ins->center_lfe_mix_scb;
1238 break;
1239 case DSP_PCM_S71_CHANNEL:
1240 /* TODO */
1241 snd_assert(0);
1242 break;
1243 case DSP_IEC958_CHANNEL:
1244 snd_assert (ins->asynch_tx_scb != NULL, return NULL);
1245 mixer_scb = ins->asynch_tx_scb;
1247 /* if sample rate is set to 48khz we pass
1248 the Sample Rate Converted (which could
1249 alter the raw data stream ...) */
1250 if (sample_rate == 48000) {
1251 snd_printdd ("IEC958 pass through\n");
1252 /* Hack to bypass creating a new SRC */
1253 pass_through = 1;
1255 break;
1256 default:
1257 snd_assert (0);
1258 return NULL;
1260 /* default sample rate is 44100 */
1261 if (!sample_rate) sample_rate = 44100;
1263 /* search for a already created SRC SCB with the same sample rate */
1264 for (i = 0; i < DSP_MAX_PCM_CHANNELS &&
1265 (pcm_index == -1 || src_scb == NULL); ++i) {
1267 /* virtual channel reserved
1268 for capture */
1269 if (i == CS46XX_DSP_CAPTURE_CHANNEL) continue;
1271 if (ins->pcm_channels[i].active) {
1272 if (!src_scb &&
1273 ins->pcm_channels[i].sample_rate == sample_rate &&
1274 ins->pcm_channels[i].mixer_scb == mixer_scb) {
1275 src_scb = ins->pcm_channels[i].src_scb;
1276 ins->pcm_channels[i].src_scb->ref_count ++;
1277 src_index = ins->pcm_channels[i].src_slot;
1279 } else if (pcm_index == -1) {
1280 pcm_index = i;
1284 if (pcm_index == -1) {
1285 snd_printk (KERN_ERR "dsp_spos: no free PCM channel\n");
1286 return NULL;
1289 if (src_scb == NULL) {
1290 if (ins->nsrc_scb >= DSP_MAX_SRC_NR) {
1291 snd_printk(KERN_ERR "dsp_spos: to many SRC instances\n!");
1292 return NULL;
1295 /* find a free slot */
1296 for (i = 0; i < DSP_MAX_SRC_NR; ++i) {
1297 if (ins->src_scb_slots[i] == 0) {
1298 src_index = i;
1299 ins->src_scb_slots[i] = 1;
1300 break;
1303 snd_assert (src_index != -1,return NULL);
1305 /* we need to create a new SRC SCB */
1306 if (mixer_scb->sub_list_ptr == ins->the_null_scb) {
1307 src_parent_scb = mixer_scb;
1308 insert_point = SCB_ON_PARENT_SUBLIST_SCB;
1309 } else {
1310 src_parent_scb = find_next_free_scb(chip,mixer_scb->sub_list_ptr);
1311 insert_point = SCB_ON_PARENT_NEXT_SCB;
1314 snprintf (scb_name,DSP_MAX_SCB_NAME,"SrcTask_SCB%d",src_index);
1316 snd_printdd( "dsp_spos: creating SRC \"%s\"\n",scb_name);
1317 src_scb = cs46xx_dsp_create_src_task_scb(chip,scb_name,
1318 sample_rate,
1319 src_output_buffer_addr[src_index],
1320 src_delay_buffer_addr[src_index],
1321 /* 0x400 - 0x600 source SCBs */
1322 0x400 + (src_index * 0x10) ,
1323 src_parent_scb,
1324 insert_point,
1325 pass_through);
1327 if (!src_scb) {
1328 snd_printk (KERN_ERR "dsp_spos: failed to create SRCtaskSCB\n");
1329 return NULL;
1332 /* cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate); */
1334 ins->nsrc_scb ++;
1338 snprintf (scb_name,DSP_MAX_SCB_NAME,"PCMReader_SCB%d",pcm_index);
1340 snd_printdd( "dsp_spos: creating PCM \"%s\" (%d)\n",scb_name,
1341 pcm_channel_id);
1343 pcm_scb = cs46xx_dsp_create_pcm_reader_scb(chip,scb_name,
1344 pcm_reader_buffer_addr[pcm_index],
1345 /* 0x200 - 400 PCMreader SCBs */
1346 (pcm_index * 0x10) + 0x200,
1347 pcm_index, /* virtual channel 0-31 */
1348 hw_dma_addr, /* pcm hw addr */
1349 NULL, /* parent SCB ptr */
1350 0 /* insert point */
1353 if (!pcm_scb) {
1354 snd_printk (KERN_ERR "dsp_spos: failed to create PCMreaderSCB\n");
1355 return NULL;
1358 spin_lock_irqsave(&chip->reg_lock, flags);
1359 ins->pcm_channels[pcm_index].sample_rate = sample_rate;
1360 ins->pcm_channels[pcm_index].pcm_reader_scb = pcm_scb;
1361 ins->pcm_channels[pcm_index].src_scb = src_scb;
1362 ins->pcm_channels[pcm_index].unlinked = 1;
1363 ins->pcm_channels[pcm_index].private_data = private_data;
1364 ins->pcm_channels[pcm_index].src_slot = src_index;
1365 ins->pcm_channels[pcm_index].active = 1;
1366 ins->pcm_channels[pcm_index].pcm_slot = pcm_index;
1367 ins->pcm_channels[pcm_index].mixer_scb = mixer_scb;
1368 ins->npcm_channels ++;
1369 spin_unlock_irqrestore(&chip->reg_lock, flags);
1371 return (ins->pcm_channels + pcm_index);
1374 int cs46xx_dsp_pcm_channel_set_period (cs46xx_t * chip,
1375 pcm_channel_descriptor_t * pcm_channel,
1376 int period_size)
1378 u32 temp = snd_cs46xx_peek (chip,pcm_channel->pcm_reader_scb->address << 2);
1379 temp &= ~DMA_RQ_C1_SOURCE_SIZE_MASK;
1381 switch (period_size) {
1382 case 2048:
1383 temp |= DMA_RQ_C1_SOURCE_MOD1024;
1384 break;
1385 case 1024:
1386 temp |= DMA_RQ_C1_SOURCE_MOD512;
1387 break;
1388 case 512:
1389 temp |= DMA_RQ_C1_SOURCE_MOD256;
1390 break;
1391 case 256:
1392 temp |= DMA_RQ_C1_SOURCE_MOD128;
1393 break;
1394 case 128:
1395 temp |= DMA_RQ_C1_SOURCE_MOD64;
1396 break;
1397 case 64:
1398 temp |= DMA_RQ_C1_SOURCE_MOD32;
1399 break;
1400 case 32:
1401 temp |= DMA_RQ_C1_SOURCE_MOD16;
1402 break;
1403 default:
1404 snd_printdd ("period size (%d) not supported by HW\n", period_size);
1405 return -EINVAL;
1408 snd_cs46xx_poke (chip,pcm_channel->pcm_reader_scb->address << 2,temp);
1410 return 0;
1413 int cs46xx_dsp_pcm_ostream_set_period (cs46xx_t * chip,
1414 int period_size)
1416 u32 temp = snd_cs46xx_peek (chip,WRITEBACK_SCB_ADDR << 2);
1417 temp &= ~DMA_RQ_C1_DEST_SIZE_MASK;
1419 switch (period_size) {
1420 case 2048:
1421 temp |= DMA_RQ_C1_DEST_MOD1024;
1422 break;
1423 case 1024:
1424 temp |= DMA_RQ_C1_DEST_MOD512;
1425 break;
1426 case 512:
1427 temp |= DMA_RQ_C1_DEST_MOD256;
1428 break;
1429 case 256:
1430 temp |= DMA_RQ_C1_DEST_MOD128;
1431 break;
1432 case 128:
1433 temp |= DMA_RQ_C1_DEST_MOD64;
1434 break;
1435 case 64:
1436 temp |= DMA_RQ_C1_DEST_MOD32;
1437 break;
1438 case 32:
1439 temp |= DMA_RQ_C1_DEST_MOD16;
1440 break;
1441 default:
1442 snd_printdd ("period size (%d) not supported by HW\n", period_size);
1443 return -EINVAL;
1446 snd_cs46xx_poke (chip,WRITEBACK_SCB_ADDR << 2,temp);
1448 return 0;
1451 void cs46xx_dsp_destroy_pcm_channel (cs46xx_t * chip,pcm_channel_descriptor_t * pcm_channel)
1453 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1454 unsigned long flags;
1456 snd_assert(pcm_channel->active, return );
1457 snd_assert(ins->npcm_channels > 0, return );
1458 snd_assert(pcm_channel->src_scb->ref_count > 0, return );
1460 spin_lock_irqsave(&chip->reg_lock, flags);
1461 pcm_channel->unlinked = 1;
1462 pcm_channel->active = 0;
1463 pcm_channel->private_data = NULL;
1464 pcm_channel->src_scb->ref_count --;
1465 ins->npcm_channels --;
1466 spin_unlock_irqrestore(&chip->reg_lock, flags);
1468 cs46xx_dsp_remove_scb(chip,pcm_channel->pcm_reader_scb);
1470 if (!pcm_channel->src_scb->ref_count) {
1471 cs46xx_dsp_remove_scb(chip,pcm_channel->src_scb);
1473 snd_assert (pcm_channel->src_slot >= 0 && pcm_channel->src_slot <= DSP_MAX_SRC_NR,
1474 return );
1476 ins->src_scb_slots[pcm_channel->src_slot] = 0;
1477 ins->nsrc_scb --;
1481 int cs46xx_dsp_pcm_unlink (cs46xx_t * chip,pcm_channel_descriptor_t * pcm_channel)
1483 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1484 unsigned long flags;
1486 snd_assert(pcm_channel->active,return -EIO);
1487 snd_assert(ins->npcm_channels > 0,return -EIO);
1489 spin_lock(&pcm_channel->src_scb->lock);
1491 if (pcm_channel->unlinked) {
1492 spin_unlock(&pcm_channel->src_scb->lock);
1493 return -EIO;
1496 spin_lock_irqsave(&chip->reg_lock, flags);
1497 pcm_channel->unlinked = 1;
1498 spin_unlock_irqrestore(&chip->reg_lock, flags);
1500 _dsp_unlink_scb (chip,pcm_channel->pcm_reader_scb);
1502 spin_unlock(&pcm_channel->src_scb->lock);
1503 return 0;
1506 int cs46xx_dsp_pcm_link (cs46xx_t * chip,pcm_channel_descriptor_t * pcm_channel)
1508 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1509 dsp_scb_descriptor_t * parent_scb;
1510 dsp_scb_descriptor_t * src_scb = pcm_channel->src_scb;
1511 unsigned long flags;
1513 spin_lock(&pcm_channel->src_scb->lock);
1515 if (pcm_channel->unlinked == 0) {
1516 spin_unlock(&pcm_channel->src_scb->lock);
1517 return -EIO;
1520 parent_scb = src_scb;
1522 if (src_scb->sub_list_ptr != ins->the_null_scb) {
1523 src_scb->sub_list_ptr->parent_scb_ptr = pcm_channel->pcm_reader_scb;
1524 pcm_channel->pcm_reader_scb->next_scb_ptr = src_scb->sub_list_ptr;
1527 src_scb->sub_list_ptr = pcm_channel->pcm_reader_scb;
1529 snd_assert (pcm_channel->pcm_reader_scb->parent_scb_ptr == NULL, ; );
1530 pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb;
1532 spin_lock_irqsave(&chip->reg_lock, flags);
1534 /* update SCB entry in DSP RAM */
1535 cs46xx_dsp_spos_update_scb(chip,pcm_channel->pcm_reader_scb);
1537 /* update parent SCB entry */
1538 cs46xx_dsp_spos_update_scb(chip,parent_scb);
1540 pcm_channel->unlinked = 0;
1541 spin_unlock_irqrestore(&chip->reg_lock, flags);
1543 spin_unlock(&pcm_channel->src_scb->lock);
1544 return 0;
1547 dsp_scb_descriptor_t * cs46xx_add_record_source (cs46xx_t *chip,dsp_scb_descriptor_t * source,
1548 u16 addr,char * scb_name)
1550 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1551 dsp_scb_descriptor_t * parent;
1552 dsp_scb_descriptor_t * pcm_input;
1553 int insert_point;
1555 snd_assert (ins->record_mixer_scb != NULL,return NULL);
1557 if (ins->record_mixer_scb->sub_list_ptr != ins->the_null_scb) {
1558 parent = find_next_free_scb (chip,ins->record_mixer_scb->sub_list_ptr);
1559 insert_point = SCB_ON_PARENT_NEXT_SCB;
1560 } else {
1561 parent = ins->record_mixer_scb;
1562 insert_point = SCB_ON_PARENT_SUBLIST_SCB;
1565 pcm_input = cs46xx_dsp_create_pcm_serial_input_scb(chip,scb_name,addr,
1566 source, parent,
1567 insert_point);
1569 return pcm_input;
1572 int cs46xx_src_unlink(cs46xx_t *chip,dsp_scb_descriptor_t * src)
1574 snd_assert (src->parent_scb_ptr != NULL, return -EINVAL );
1576 /* mute SCB */
1577 cs46xx_dsp_scb_set_volume (chip,src,0,0);
1579 _dsp_unlink_scb (chip,src);
1581 return 0;
1584 int cs46xx_src_link(cs46xx_t *chip,dsp_scb_descriptor_t * src)
1586 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1587 dsp_scb_descriptor_t * parent_scb;
1589 snd_assert (src->parent_scb_ptr == NULL, return -EINVAL );
1590 snd_assert(ins->master_mix_scb !=NULL, return -EINVAL );
1592 if (ins->master_mix_scb->sub_list_ptr != ins->the_null_scb) {
1593 parent_scb = find_next_free_scb (chip,ins->master_mix_scb->sub_list_ptr);
1594 parent_scb->next_scb_ptr = src;
1595 } else {
1596 parent_scb = ins->master_mix_scb;
1597 parent_scb->sub_list_ptr = src;
1600 src->parent_scb_ptr = parent_scb;
1602 /* update entry in DSP RAM */
1603 cs46xx_dsp_spos_update_scb(chip,parent_scb);
1605 return 0;
1608 int cs46xx_dsp_enable_spdif_out (cs46xx_t *chip)
1610 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1612 if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
1613 cs46xx_dsp_enable_spdif_hw (chip);
1616 /* dont touch anything if SPDIF is open */
1617 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
1618 /* when cs46xx_iec958_post_close(...) is called it
1619 will call this function if necessary depending on
1620 this bit */
1621 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1623 return -EBUSY;
1626 snd_assert (ins->asynch_tx_scb == NULL, return -EINVAL);
1627 snd_assert (ins->master_mix_scb->next_scb_ptr == ins->the_null_scb, return -EINVAL);
1629 /* reset output snooper sample buffer pointer */
1630 snd_cs46xx_poke (chip, (ins->ref_snoop_scb->address + 2) << 2,
1631 (OUTPUT_SNOOP_BUFFER + 0x10) << 0x10 );
1633 /* The asynch. transfer task */
1634 ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
1635 SPDIFO_SCB_INST,
1636 SPDIFO_IP_OUTPUT_BUFFER1,
1637 ins->master_mix_scb,
1638 SCB_ON_PARENT_NEXT_SCB);
1639 if (!ins->asynch_tx_scb) return -ENOMEM;
1641 ins->spdif_pcm_input_scb = cs46xx_dsp_create_pcm_serial_input_scb(chip,"PCMSerialInput_II",
1642 PCMSERIALINII_SCB_ADDR,
1643 ins->ref_snoop_scb,
1644 ins->asynch_tx_scb,
1645 SCB_ON_PARENT_SUBLIST_SCB);
1648 if (!ins->spdif_pcm_input_scb) return -ENOMEM;
1650 /* monitor state */
1651 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1653 return 0;
1656 int cs46xx_dsp_disable_spdif_out (cs46xx_t *chip)
1658 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1660 /* dont touch anything if SPDIF is open */
1661 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
1662 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1663 return -EBUSY;
1666 /* check integrety */
1667 snd_assert (ins->asynch_tx_scb != NULL, return -EINVAL);
1668 snd_assert (ins->spdif_pcm_input_scb != NULL,return -EINVAL);
1669 snd_assert (ins->master_mix_scb->next_scb_ptr == ins->asynch_tx_scb, return -EINVAL);
1670 snd_assert (ins->asynch_tx_scb->parent_scb_ptr == ins->master_mix_scb, return -EINVAL);
1672 cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
1673 cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
1675 ins->spdif_pcm_input_scb = NULL;
1676 ins->asynch_tx_scb = NULL;
1678 /* clear buffer to prevent any undesired noise */
1679 _dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
1681 /* monitor state */
1682 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1685 return 0;
1688 int cs46xx_iec958_pre_open (cs46xx_t *chip)
1690 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1692 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
1693 /* remove AsynchFGTxSCB and and PCMSerialInput_II */
1694 cs46xx_dsp_disable_spdif_out (chip);
1696 /* save state */
1697 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1700 /* if not enabled already */
1701 if ( !(ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
1702 cs46xx_dsp_enable_spdif_hw (chip);
1705 /* Create the asynch. transfer task for playback */
1706 ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
1707 SPDIFO_SCB_INST,
1708 SPDIFO_IP_OUTPUT_BUFFER1,
1709 ins->master_mix_scb,
1710 SCB_ON_PARENT_NEXT_SCB);
1713 /* set spdif channel status value for streaming */
1714 cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_stream);
1716 ins->spdif_status_out |= DSP_SPDIF_STATUS_PLAYBACK_OPEN;
1718 return 0;
1721 int cs46xx_iec958_post_close (cs46xx_t *chip)
1723 dsp_spos_instance_t * ins = chip->dsp_spos_instance;
1725 snd_assert (ins->asynch_tx_scb != NULL, return -EINVAL);
1727 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_PLAYBACK_OPEN;
1729 /* restore settings */
1730 cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);
1732 /* deallocate stuff */
1733 if (ins->spdif_pcm_input_scb != NULL) {
1734 cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
1735 ins->spdif_pcm_input_scb = NULL;
1738 cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
1739 ins->asynch_tx_scb = NULL;
1741 /* clear buffer to prevent any undesired noise */
1742 _dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
1744 /* restore state */
1745 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
1746 cs46xx_dsp_enable_spdif_out (chip);
1749 return 0;