[ALSA] semaphore -> mutex (PCI part)
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / sound / pci / cs46xx / dsp_spos_scb_lib.c
blob2c4ee45fe10c3f894ff0c8b9323c5835a11a5ae2
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 <linux/mutex.h>
33 #include <sound/core.h>
34 #include <sound/control.h>
35 #include <sound/info.h>
36 #include <sound/cs46xx.h>
38 #include "cs46xx_lib.h"
39 #include "dsp_spos.h"
41 struct proc_scb_info {
42 struct dsp_scb_descriptor * scb_desc;
43 struct snd_cs46xx *chip;
46 static void remove_symbol (struct snd_cs46xx * chip, struct dsp_symbol_entry * symbol)
48 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
49 int symbol_index = (int)(symbol - ins->symbol_table.symbols);
51 snd_assert(ins->symbol_table.nsymbols > 0,return);
52 snd_assert(symbol_index >= 0 && symbol_index < ins->symbol_table.nsymbols, return);
54 ins->symbol_table.symbols[symbol_index].deleted = 1;
56 if (symbol_index < ins->symbol_table.highest_frag_index) {
57 ins->symbol_table.highest_frag_index = symbol_index;
60 if (symbol_index == ins->symbol_table.nsymbols - 1)
61 ins->symbol_table.nsymbols --;
63 if (ins->symbol_table.highest_frag_index > ins->symbol_table.nsymbols) {
64 ins->symbol_table.highest_frag_index = ins->symbol_table.nsymbols;
69 #ifdef CONFIG_PROC_FS
70 static void cs46xx_dsp_proc_scb_info_read (struct snd_info_entry *entry,
71 struct snd_info_buffer *buffer)
73 struct proc_scb_info * scb_info = entry->private_data;
74 struct dsp_scb_descriptor * scb = scb_info->scb_desc;
75 struct dsp_spos_instance * ins;
76 struct snd_cs46xx *chip = scb_info->chip;
77 int j,col;
78 void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
80 ins = chip->dsp_spos_instance;
82 mutex_lock(&chip->spos_mutex);
83 snd_iprintf(buffer,"%04x %s:\n",scb->address,scb->scb_name);
85 for (col = 0,j = 0;j < 0x10; j++,col++) {
86 if (col == 4) {
87 snd_iprintf(buffer,"\n");
88 col = 0;
90 snd_iprintf(buffer,"%08x ",readl(dst + (scb->address + j) * sizeof(u32)));
93 snd_iprintf(buffer,"\n");
95 if (scb->parent_scb_ptr != NULL) {
96 snd_iprintf(buffer,"parent [%s:%04x] ",
97 scb->parent_scb_ptr->scb_name,
98 scb->parent_scb_ptr->address);
99 } else snd_iprintf(buffer,"parent [none] ");
101 snd_iprintf(buffer,"sub_list_ptr [%s:%04x]\nnext_scb_ptr [%s:%04x] task_entry [%s:%04x]\n",
102 scb->sub_list_ptr->scb_name,
103 scb->sub_list_ptr->address,
104 scb->next_scb_ptr->scb_name,
105 scb->next_scb_ptr->address,
106 scb->task_entry->symbol_name,
107 scb->task_entry->address);
109 snd_iprintf(buffer,"index [%d] ref_count [%d]\n",scb->index,scb->ref_count);
110 mutex_unlock(&chip->spos_mutex);
112 #endif
114 static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
116 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
117 unsigned long flags;
119 if ( scb->parent_scb_ptr ) {
120 /* unlink parent SCB */
121 snd_assert ((scb->parent_scb_ptr->sub_list_ptr == scb ||
122 scb->parent_scb_ptr->next_scb_ptr == scb),return);
124 if (scb->parent_scb_ptr->sub_list_ptr == scb) {
126 if (scb->next_scb_ptr == ins->the_null_scb) {
127 /* last and only node in parent sublist */
128 scb->parent_scb_ptr->sub_list_ptr = scb->sub_list_ptr;
130 if (scb->sub_list_ptr != ins->the_null_scb) {
131 scb->sub_list_ptr->parent_scb_ptr = scb->parent_scb_ptr;
133 scb->sub_list_ptr = ins->the_null_scb;
134 } else {
135 /* first node in parent sublist */
136 scb->parent_scb_ptr->sub_list_ptr = scb->next_scb_ptr;
138 if (scb->next_scb_ptr != ins->the_null_scb) {
139 /* update next node parent ptr. */
140 scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
142 scb->next_scb_ptr = ins->the_null_scb;
144 } else {
145 /* snd_assert ( (scb->sub_list_ptr == ins->the_null_scb), return); */
146 scb->parent_scb_ptr->next_scb_ptr = scb->next_scb_ptr;
148 if (scb->next_scb_ptr != ins->the_null_scb) {
149 /* update next node parent ptr. */
150 scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
152 scb->next_scb_ptr = ins->the_null_scb;
155 spin_lock_irqsave(&chip->reg_lock, flags);
157 /* update parent first entry in DSP RAM */
158 cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
160 /* then update entry in DSP RAM */
161 cs46xx_dsp_spos_update_scb(chip,scb);
163 scb->parent_scb_ptr = NULL;
164 spin_unlock_irqrestore(&chip->reg_lock, flags);
168 static void _dsp_clear_sample_buffer (struct snd_cs46xx *chip, u32 sample_buffer_addr,
169 int dword_count)
171 void __iomem *dst = chip->region.idx[2].remap_addr + sample_buffer_addr;
172 int i;
174 for (i = 0; i < dword_count ; ++i ) {
175 writel(0, dst);
176 dst += 4;
180 void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
182 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
184 /* check integrety */
185 snd_assert ( (scb->index >= 0 &&
186 scb->index < ins->nscb &&
187 (ins->scbs + scb->index) == scb), return );
189 #if 0
190 /* can't remove a SCB with childs before
191 removing childs first */
192 snd_assert ( (scb->sub_list_ptr == ins->the_null_scb &&
193 scb->next_scb_ptr == ins->the_null_scb),
194 goto _end);
195 #endif
197 spin_lock(&scb->lock);
198 _dsp_unlink_scb (chip,scb);
199 spin_unlock(&scb->lock);
201 cs46xx_dsp_proc_free_scb_desc(scb);
202 snd_assert (scb->scb_symbol != NULL, return );
203 remove_symbol (chip,scb->scb_symbol);
205 ins->scbs[scb->index].deleted = 1;
207 if (scb->index < ins->scb_highest_frag_index)
208 ins->scb_highest_frag_index = scb->index;
210 if (scb->index == ins->nscb - 1) {
211 ins->nscb --;
214 if (ins->scb_highest_frag_index > ins->nscb) {
215 ins->scb_highest_frag_index = ins->nscb;
218 #if 0
219 /* !!!! THIS IS A PIECE OF SHIT MADE BY ME !!! */
220 for(i = scb->index + 1;i < ins->nscb; ++i) {
221 ins->scbs[i - 1].index = i - 1;
223 #endif
227 #ifdef CONFIG_PROC_FS
228 void cs46xx_dsp_proc_free_scb_desc (struct dsp_scb_descriptor * scb)
230 if (scb->proc_info) {
231 struct proc_scb_info * scb_info = scb->proc_info->private_data;
233 snd_printdd("cs46xx_dsp_proc_free_scb_desc: freeing %s\n",scb->scb_name);
235 snd_info_unregister(scb->proc_info);
236 scb->proc_info = NULL;
238 snd_assert (scb_info != NULL, return);
239 kfree (scb_info);
243 void cs46xx_dsp_proc_register_scb_desc (struct snd_cs46xx *chip,
244 struct dsp_scb_descriptor * scb)
246 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
247 struct snd_info_entry * entry;
248 struct proc_scb_info * scb_info;
250 /* register to proc */
251 if (ins->snd_card != NULL && ins->proc_dsp_dir != NULL &&
252 scb->proc_info == NULL) {
254 if ((entry = snd_info_create_card_entry(ins->snd_card, scb->scb_name,
255 ins->proc_dsp_dir)) != NULL) {
256 scb_info = kmalloc(sizeof(struct proc_scb_info), GFP_KERNEL);
257 if (!scb_info) {
258 snd_info_free_entry(entry);
259 entry = NULL;
260 goto out;
263 scb_info->chip = chip;
264 scb_info->scb_desc = scb;
266 entry->content = SNDRV_INFO_CONTENT_TEXT;
267 entry->private_data = scb_info;
268 entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
270 entry->c.text.read_size = 512;
271 entry->c.text.read = cs46xx_dsp_proc_scb_info_read;
273 if (snd_info_register(entry) < 0) {
274 snd_info_free_entry(entry);
275 kfree (scb_info);
276 entry = NULL;
279 out:
280 scb->proc_info = entry;
283 #endif /* CONFIG_PROC_FS */
285 static struct dsp_scb_descriptor *
286 _dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32 dest,
287 struct dsp_symbol_entry * task_entry,
288 struct dsp_scb_descriptor * parent_scb,
289 int scb_child_type)
291 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
292 struct dsp_scb_descriptor * scb;
294 unsigned long flags;
296 snd_assert (ins->the_null_scb != NULL,return NULL);
298 /* fill the data that will be wroten to DSP */
299 scb_data[SCBsubListPtr] =
300 (ins->the_null_scb->address << 0x10) | ins->the_null_scb->address;
302 scb_data[SCBfuncEntryPtr] &= 0xFFFF0000;
303 scb_data[SCBfuncEntryPtr] |= task_entry->address;
305 snd_printdd("dsp_spos: creating SCB <%s>\n",name);
307 scb = cs46xx_dsp_create_scb(chip,name,scb_data,dest);
310 scb->sub_list_ptr = ins->the_null_scb;
311 scb->next_scb_ptr = ins->the_null_scb;
313 scb->parent_scb_ptr = parent_scb;
314 scb->task_entry = task_entry;
317 /* update parent SCB */
318 if (scb->parent_scb_ptr) {
319 #if 0
320 printk ("scb->parent_scb_ptr = %s\n",scb->parent_scb_ptr->scb_name);
321 printk ("scb->parent_scb_ptr->next_scb_ptr = %s\n",scb->parent_scb_ptr->next_scb_ptr->scb_name);
322 printk ("scb->parent_scb_ptr->sub_list_ptr = %s\n",scb->parent_scb_ptr->sub_list_ptr->scb_name);
323 #endif
324 /* link to parent SCB */
325 if (scb_child_type == SCB_ON_PARENT_NEXT_SCB) {
326 snd_assert ( (scb->parent_scb_ptr->next_scb_ptr == ins->the_null_scb),
327 return NULL);
329 scb->parent_scb_ptr->next_scb_ptr = scb;
331 } else if (scb_child_type == SCB_ON_PARENT_SUBLIST_SCB) {
332 snd_assert ( (scb->parent_scb_ptr->sub_list_ptr == ins->the_null_scb),
333 return NULL);
335 scb->parent_scb_ptr->sub_list_ptr = scb;
336 } else {
337 snd_assert (0,return NULL);
340 spin_lock_irqsave(&chip->reg_lock, flags);
342 /* update entry in DSP RAM */
343 cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
345 spin_unlock_irqrestore(&chip->reg_lock, flags);
349 cs46xx_dsp_proc_register_scb_desc (chip,scb);
351 return scb;
354 static struct dsp_scb_descriptor *
355 cs46xx_dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data,
356 u32 dest, char * task_entry_name,
357 struct dsp_scb_descriptor * parent_scb,
358 int scb_child_type)
360 struct dsp_symbol_entry * task_entry;
362 task_entry = cs46xx_dsp_lookup_symbol (chip,task_entry_name,
363 SYMBOL_CODE);
365 if (task_entry == NULL) {
366 snd_printk (KERN_ERR "dsp_spos: symbol %s not found\n",task_entry_name);
367 return NULL;
370 return _dsp_create_generic_scb (chip,name,scb_data,dest,task_entry,
371 parent_scb,scb_child_type);
374 struct dsp_scb_descriptor *
375 cs46xx_dsp_create_timing_master_scb (struct snd_cs46xx *chip)
377 struct dsp_scb_descriptor * scb;
379 struct dsp_timing_master_scb timing_master_scb = {
380 { 0,
385 { 0,
391 0,0,
392 0,NULL_SCB_ADDR,
393 0,0, /* extraSampleAccum:TMreserved */
394 0,0, /* codecFIFOptr:codecFIFOsyncd */
395 0x0001,0x8000, /* fracSampAccumQm1:TMfrmsLeftInGroup */
396 0x0001,0x0000, /* fracSampCorrectionQm1:TMfrmGroupLength */
397 0x00060000 /* nSampPerFrmQ15 */
400 scb = cs46xx_dsp_create_generic_scb(chip,"TimingMasterSCBInst",(u32 *)&timing_master_scb,
401 TIMINGMASTER_SCB_ADDR,
402 "TIMINGMASTER",NULL,SCB_NO_PARENT);
404 return scb;
408 struct dsp_scb_descriptor *
409 cs46xx_dsp_create_codec_out_scb(struct snd_cs46xx * chip, char * codec_name,
410 u16 channel_disp, u16 fifo_addr, u16 child_scb_addr,
411 u32 dest, struct dsp_scb_descriptor * parent_scb,
412 int scb_child_type)
414 struct dsp_scb_descriptor * scb;
416 struct dsp_codec_output_scb codec_out_scb = {
417 { 0,
429 0,0,
430 0,NULL_SCB_ADDR,
431 0, /* COstrmRsConfig */
432 0, /* COstrmBufPtr */
433 channel_disp,fifo_addr, /* leftChanBaseIOaddr:rightChanIOdisp */
434 0x0000,0x0080, /* (!AC97!) COexpVolChangeRate:COscaleShiftCount */
435 0,child_scb_addr /* COreserved - need child scb to work with rom code */
439 scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_out_scb,
440 dest,"S16_CODECOUTPUTTASK",parent_scb,
441 scb_child_type);
443 return scb;
446 struct dsp_scb_descriptor *
447 cs46xx_dsp_create_codec_in_scb(struct snd_cs46xx * chip, char * codec_name,
448 u16 channel_disp, u16 fifo_addr, u16 sample_buffer_addr,
449 u32 dest, struct dsp_scb_descriptor * parent_scb,
450 int scb_child_type)
453 struct dsp_scb_descriptor * scb;
454 struct dsp_codec_input_scb codec_input_scb = {
455 { 0,
468 #if 0 /* cs4620 */
469 SyncIOSCB,NULL_SCB_ADDR
470 #else
471 0 , 0,
472 #endif
473 0,0,
475 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64, /* strmRsConfig */
476 sample_buffer_addr << 0x10, /* strmBufPtr; defined as a dword ptr, used as a byte ptr */
477 channel_disp,fifo_addr, /* (!AC97!) leftChanBaseINaddr=AC97primary
478 link input slot 3 :rightChanINdisp=""slot 4 */
479 0x0000,0x0000, /* (!AC97!) ????:scaleShiftCount; no shift needed
480 because AC97 is already 20 bits */
481 0x80008000 /* ??clw cwcgame.scb has 0 */
484 scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_input_scb,
485 dest,"S16_CODECINPUTTASK",parent_scb,
486 scb_child_type);
487 return scb;
491 static struct dsp_scb_descriptor *
492 cs46xx_dsp_create_pcm_reader_scb(struct snd_cs46xx * chip, char * scb_name,
493 u16 sample_buffer_addr, u32 dest,
494 int virtual_channel, u32 playback_hw_addr,
495 struct dsp_scb_descriptor * parent_scb,
496 int scb_child_type)
498 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
499 struct dsp_scb_descriptor * scb;
501 struct dsp_generic_scb pcm_reader_scb = {
504 Play DMA Task xfers data from host buffer to SP buffer
505 init/runtime variables:
506 PlayAC: Play Audio Data Conversion - SCB loc: 2nd dword, mask: 0x0000F000L
507 DATA_FMT_16BIT_ST_LTLEND(0x00000000L) from 16-bit stereo, little-endian
508 DATA_FMT_8_BIT_ST_SIGNED(0x00001000L) from 8-bit stereo, signed
509 DATA_FMT_16BIT_MN_LTLEND(0x00002000L) from 16-bit mono, little-endian
510 DATA_FMT_8_BIT_MN_SIGNED(0x00003000L) from 8-bit mono, signed
511 DATA_FMT_16BIT_ST_BIGEND(0x00004000L) from 16-bit stereo, big-endian
512 DATA_FMT_16BIT_MN_BIGEND(0x00006000L) from 16-bit mono, big-endian
513 DATA_FMT_8_BIT_ST_UNSIGNED(0x00009000L) from 8-bit stereo, unsigned
514 DATA_FMT_8_BIT_MN_UNSIGNED(0x0000b000L) from 8-bit mono, unsigned
515 ? Other combinations possible from:
516 DMA_RQ_C2_AUDIO_CONVERT_MASK 0x0000F000L
517 DMA_RQ_C2_AC_NONE 0x00000000L
518 DMA_RQ_C2_AC_8_TO_16_BIT 0x00001000L
519 DMA_RQ_C2_AC_MONO_TO_STEREO 0x00002000L
520 DMA_RQ_C2_AC_ENDIAN_CONVERT 0x00004000L
521 DMA_RQ_C2_AC_SIGNED_CONVERT 0x00008000L
523 HostBuffAddr: Host Buffer Physical Byte Address - SCB loc:3rd dword, Mask: 0xFFFFFFFFL
524 aligned to dword boundary
526 /* Basic (non scatter/gather) DMA requestor (4 ints) */
527 { DMA_RQ_C1_SOURCE_ON_HOST + /* source buffer is on the host */
528 DMA_RQ_C1_SOURCE_MOD1024 + /* source buffer is 1024 dwords (4096 bytes) */
529 DMA_RQ_C1_DEST_MOD32 + /* dest buffer(PCMreaderBuf) is 32 dwords*/
530 DMA_RQ_C1_WRITEBACK_SRC_FLAG + /* ?? */
531 DMA_RQ_C1_WRITEBACK_DEST_FLAG + /* ?? */
532 15, /* DwordCount-1: picked 16 for DwordCount because Jim */
533 /* Barnette said that is what we should use since */
534 /* we are not running in optimized mode? */
535 DMA_RQ_C2_AC_NONE +
536 DMA_RQ_C2_SIGNAL_SOURCE_PINGPONG + /* set play interrupt (bit0) in HISR when source */
537 /* buffer (on host) crosses half-way point */
538 virtual_channel, /* Play DMA channel arbitrarily set to 0 */
539 playback_hw_addr, /* HostBuffAddr (source) */
540 DMA_RQ_SD_SP_SAMPLE_ADDR + /* destination buffer is in SP Sample Memory */
541 sample_buffer_addr /* SP Buffer Address (destination) */
543 /* Scatter/gather DMA requestor extension (5 ints) */
551 /* Sublist pointer & next stream control block (SCB) link. */
552 NULL_SCB_ADDR,NULL_SCB_ADDR,
553 /* Pointer to this tasks parameter block & stream function pointer */
554 0,NULL_SCB_ADDR,
555 /* rsConfig register for stream buffer (rsDMA reg. is loaded from basicReq.daw */
556 /* for incoming streams, or basicReq.saw, for outgoing streams) */
557 RSCONFIG_DMA_ENABLE + /* enable DMA */
558 (19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) + /* MAX_DMA_SIZE picked to be 19 since SPUD */
559 /* uses it for some reason */
560 ((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) + /* stream number = SCBaddr/16 */
561 RSCONFIG_SAMPLE_16STEREO +
562 RSCONFIG_MODULO_32, /* dest buffer(PCMreaderBuf) is 32 dwords (256 bytes) */
563 /* Stream sample pointer & MAC-unit mode for this stream */
564 (sample_buffer_addr << 0x10),
565 /* Fractional increment per output sample in the input sample buffer */
568 /* Standard stereo volume control
569 default muted */
570 0xffff,0xffff,
571 0xffff,0xffff
575 if (ins->null_algorithm == NULL) {
576 ins->null_algorithm = cs46xx_dsp_lookup_symbol (chip,"NULLALGORITHM",
577 SYMBOL_CODE);
579 if (ins->null_algorithm == NULL) {
580 snd_printk (KERN_ERR "dsp_spos: symbol NULLALGORITHM not found\n");
581 return NULL;
585 scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_reader_scb,
586 dest,ins->null_algorithm,parent_scb,
587 scb_child_type);
589 return scb;
592 #define GOF_PER_SEC 200
594 struct dsp_scb_descriptor *
595 cs46xx_dsp_create_src_task_scb(struct snd_cs46xx * chip, char * scb_name,
596 int rate,
597 u16 src_buffer_addr,
598 u16 src_delay_buffer_addr, u32 dest,
599 struct dsp_scb_descriptor * parent_scb,
600 int scb_child_type,
601 int pass_through)
604 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
605 struct dsp_scb_descriptor * scb;
606 unsigned int tmp1, tmp2;
607 unsigned int phiIncr;
608 unsigned int correctionPerGOF, correctionPerSec;
610 snd_printdd( "dsp_spos: setting %s rate to %u\n",scb_name,rate);
613 * Compute the values used to drive the actual sample rate conversion.
614 * The following formulas are being computed, using inline assembly
615 * since we need to use 64 bit arithmetic to compute the values:
617 * phiIncr = floor((Fs,in * 2^26) / Fs,out)
618 * correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) /
619 * GOF_PER_SEC)
620 * ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -M
621 * GOF_PER_SEC * correctionPerGOF
623 * i.e.
625 * phiIncr:other = dividend:remainder((Fs,in * 2^26) / Fs,out)
626 * correctionPerGOF:correctionPerSec =
627 * dividend:remainder(ulOther / GOF_PER_SEC)
629 tmp1 = rate << 16;
630 phiIncr = tmp1 / 48000;
631 tmp1 -= phiIncr * 48000;
632 tmp1 <<= 10;
633 phiIncr <<= 10;
634 tmp2 = tmp1 / 48000;
635 phiIncr += tmp2;
636 tmp1 -= tmp2 * 48000;
637 correctionPerGOF = tmp1 / GOF_PER_SEC;
638 tmp1 -= correctionPerGOF * GOF_PER_SEC;
639 correctionPerSec = tmp1;
642 struct dsp_src_task_scb src_task_scb = {
643 0x0028,0x00c8,
644 0x5555,0x0000,
645 0x0000,0x0000,
646 src_buffer_addr,1,
647 correctionPerGOF,correctionPerSec,
648 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
649 0x0000,src_delay_buffer_addr,
650 0x0,
651 0x080,(src_delay_buffer_addr + (24 * 4)),
652 0,0, /* next_scb, sub_list_ptr */
653 0,0, /* entry, this_spb */
654 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
655 src_buffer_addr << 0x10,
656 phiIncr,
658 0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left,
659 0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left
663 if (ins->s16_up == NULL) {
664 ins->s16_up = cs46xx_dsp_lookup_symbol (chip,"S16_UPSRC",
665 SYMBOL_CODE);
667 if (ins->s16_up == NULL) {
668 snd_printk (KERN_ERR "dsp_spos: symbol S16_UPSRC not found\n");
669 return NULL;
673 /* clear buffers */
674 _dsp_clear_sample_buffer (chip,src_buffer_addr,8);
675 _dsp_clear_sample_buffer (chip,src_delay_buffer_addr,32);
677 if (pass_through) {
678 /* wont work with any other rate than
679 the native DSP rate */
680 snd_assert (rate == 48000);
682 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
683 dest,"DMAREADER",parent_scb,
684 scb_child_type);
685 } else {
686 scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
687 dest,ins->s16_up,parent_scb,
688 scb_child_type);
694 return scb;
697 #if 0 /* not used */
698 struct dsp_scb_descriptor *
699 cs46xx_dsp_create_filter_scb(struct snd_cs46xx * chip, char * scb_name,
700 u16 buffer_addr, u32 dest,
701 struct dsp_scb_descriptor * parent_scb,
702 int scb_child_type) {
703 struct dsp_scb_descriptor * scb;
705 struct dsp_filter_scb filter_scb = {
706 .a0_right = 0x41a9,
707 .a0_left = 0x41a9,
708 .a1_right = 0xb8e4,
709 .a1_left = 0xb8e4,
710 .a2_right = 0x3e55,
711 .a2_left = 0x3e55,
713 .filter_unused3 = 0x0000,
714 .filter_unused2 = 0x0000,
716 .output_buf_ptr = buffer_addr,
717 .init = 0x000,
719 .prev_sample_output1 = 0x00000000,
720 .prev_sample_output2 = 0x00000000,
722 .prev_sample_input1 = 0x00000000,
723 .prev_sample_input2 = 0x00000000,
725 .next_scb_ptr = 0x0000,
726 .sub_list_ptr = 0x0000,
728 .entry_point = 0x0000,
729 .spb_ptr = 0x0000,
731 .b0_right = 0x0e38,
732 .b0_left = 0x0e38,
733 .b1_right = 0x1c71,
734 .b1_left = 0x1c71,
735 .b2_right = 0x0e38,
736 .b2_left = 0x0e38,
740 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&filter_scb,
741 dest,"FILTERTASK",parent_scb,
742 scb_child_type);
744 return scb;
746 #endif /* not used */
748 struct dsp_scb_descriptor *
749 cs46xx_dsp_create_mix_only_scb(struct snd_cs46xx * chip, char * scb_name,
750 u16 mix_buffer_addr, u32 dest,
751 struct dsp_scb_descriptor * parent_scb,
752 int scb_child_type)
754 struct dsp_scb_descriptor * scb;
756 struct dsp_mix_only_scb master_mix_scb = {
757 /* 0 */ { 0,
758 /* 1 */ 0,
759 /* 2 */ mix_buffer_addr,
760 /* 3 */ 0
761 /* */ },
763 /* 4 */ 0,
764 /* 5 */ 0,
765 /* 6 */ 0,
766 /* 7 */ 0,
767 /* 8 */ 0x00000080
769 /* 9 */ 0,0,
770 /* A */ 0,0,
771 /* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
772 /* C */ (mix_buffer_addr + (16 * 4)) << 0x10,
773 /* D */ 0,
775 /* E */ 0x8000,0x8000,
776 /* F */ 0x8000,0x8000
781 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&master_mix_scb,
782 dest,"S16_MIX",parent_scb,
783 scb_child_type);
784 return scb;
788 struct dsp_scb_descriptor *
789 cs46xx_dsp_create_mix_to_ostream_scb(struct snd_cs46xx * chip, char * scb_name,
790 u16 mix_buffer_addr, u16 writeback_spb, u32 dest,
791 struct dsp_scb_descriptor * parent_scb,
792 int scb_child_type)
794 struct dsp_scb_descriptor * scb;
796 struct dsp_mix2_ostream_scb mix2_ostream_scb = {
797 /* Basic (non scatter/gather) DMA requestor (4 ints) */
799 DMA_RQ_C1_SOURCE_MOD64 +
800 DMA_RQ_C1_DEST_ON_HOST +
801 DMA_RQ_C1_DEST_MOD1024 +
802 DMA_RQ_C1_WRITEBACK_SRC_FLAG +
803 DMA_RQ_C1_WRITEBACK_DEST_FLAG +
804 15,
806 DMA_RQ_C2_AC_NONE +
807 DMA_RQ_C2_SIGNAL_DEST_PINGPONG +
809 CS46XX_DSP_CAPTURE_CHANNEL,
810 DMA_RQ_SD_SP_SAMPLE_ADDR +
811 mix_buffer_addr,
812 0x0
815 { 0, 0, 0, 0, 0, },
816 0,0,
817 0,writeback_spb,
819 RSCONFIG_DMA_ENABLE +
820 (19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) +
822 ((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) +
823 RSCONFIG_DMA_TO_HOST +
824 RSCONFIG_SAMPLE_16STEREO +
825 RSCONFIG_MODULO_64,
826 (mix_buffer_addr + (32 * 4)) << 0x10,
827 1,0,
828 0x0001,0x0080,
829 0xFFFF,0
833 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&mix2_ostream_scb,
835 dest,"S16_MIX_TO_OSTREAM",parent_scb,
836 scb_child_type);
838 return scb;
842 struct dsp_scb_descriptor *
843 cs46xx_dsp_create_vari_decimate_scb(struct snd_cs46xx * chip,char * scb_name,
844 u16 vari_buffer_addr0,
845 u16 vari_buffer_addr1,
846 u32 dest,
847 struct dsp_scb_descriptor * parent_scb,
848 int scb_child_type)
851 struct dsp_scb_descriptor * scb;
853 struct dsp_vari_decimate_scb vari_decimate_scb = {
854 0x0028,0x00c8,
855 0x5555,0x0000,
856 0x0000,0x0000,
857 vari_buffer_addr0,vari_buffer_addr1,
859 0x0028,0x00c8,
860 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256,
862 0xFF800000,
864 0x0080,vari_buffer_addr1 + (25 * 4),
866 0,0,
867 0,0,
869 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
870 vari_buffer_addr0 << 0x10,
871 0x04000000,
873 0x8000,0x8000,
874 0xFFFF,0xFFFF
878 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&vari_decimate_scb,
879 dest,"VARIDECIMATE",parent_scb,
880 scb_child_type);
882 return scb;
886 static struct dsp_scb_descriptor *
887 cs46xx_dsp_create_pcm_serial_input_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
888 struct dsp_scb_descriptor * input_scb,
889 struct dsp_scb_descriptor * parent_scb,
890 int scb_child_type)
893 struct dsp_scb_descriptor * scb;
896 struct dsp_pcm_serial_input_scb pcm_serial_input_scb = {
897 { 0,
910 0,0,
911 0,0,
913 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_16,
915 /* 0xD */ 0,input_scb->address,
917 /* 0xE */ 0x8000,0x8000,
918 /* 0xF */ 0x8000,0x8000
922 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_serial_input_scb,
923 dest,"PCMSERIALINPUTTASK",parent_scb,
924 scb_child_type);
925 return scb;
929 static struct dsp_scb_descriptor *
930 cs46xx_dsp_create_asynch_fg_tx_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
931 u16 hfg_scb_address,
932 u16 asynch_buffer_address,
933 struct dsp_scb_descriptor * parent_scb,
934 int scb_child_type)
937 struct dsp_scb_descriptor * scb;
939 struct dsp_asynch_fg_tx_scb asynch_fg_tx_scb = {
940 0xfc00,0x03ff, /* Prototype sample buffer size of 256 dwords */
941 0x0058,0x0028, /* Min Delta 7 dwords == 28 bytes */
942 /* : Max delta 25 dwords == 100 bytes */
943 0,hfg_scb_address, /* Point to HFG task SCB */
944 0,0, /* Initialize current Delta and Consumer ptr adjustment count */
945 0, /* Initialize accumulated Phi to 0 */
946 0,0x2aab, /* Const 1/3 */
949 0, /* Define the unused elements */
954 0,0,
955 0,dest + AFGTxAccumPhi,
957 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256, /* Stereo, 256 dword */
958 (asynch_buffer_address) << 0x10, /* This should be automagically synchronized
959 to the producer pointer */
961 /* There is no correct initial value, it will depend upon the detected
962 rate etc */
963 0x18000000, /* Phi increment for approx 32k operation */
964 0x8000,0x8000, /* Volume controls are unused at this time */
965 0x8000,0x8000
968 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_tx_scb,
969 dest,"ASYNCHFGTXCODE",parent_scb,
970 scb_child_type);
972 return scb;
976 struct dsp_scb_descriptor *
977 cs46xx_dsp_create_asynch_fg_rx_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
978 u16 hfg_scb_address,
979 u16 asynch_buffer_address,
980 struct dsp_scb_descriptor * parent_scb,
981 int scb_child_type)
983 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
984 struct dsp_scb_descriptor * scb;
986 struct dsp_asynch_fg_rx_scb asynch_fg_rx_scb = {
987 0xfe00,0x01ff, /* Prototype sample buffer size of 128 dwords */
988 0x0064,0x001c, /* Min Delta 7 dwords == 28 bytes */
989 /* : Max delta 25 dwords == 100 bytes */
990 0,hfg_scb_address, /* Point to HFG task SCB */
991 0,0, /* Initialize current Delta and Consumer ptr adjustment count */
993 0, /* Define the unused elements */
1000 0,0,
1001 0,dest,
1003 RSCONFIG_MODULO_128 |
1004 RSCONFIG_SAMPLE_16STEREO, /* Stereo, 128 dword */
1005 ( (asynch_buffer_address + (16 * 4)) << 0x10), /* This should be automagically
1006 synchrinized to the producer pointer */
1008 /* There is no correct initial value, it will depend upon the detected
1009 rate etc */
1010 0x18000000,
1012 /* Set IEC958 input volume */
1013 0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
1014 0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
1017 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_rx_scb,
1018 dest,"ASYNCHFGRXCODE",parent_scb,
1019 scb_child_type);
1021 return scb;
1025 #if 0 /* not used */
1026 struct dsp_scb_descriptor *
1027 cs46xx_dsp_create_output_snoop_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1028 u16 snoop_buffer_address,
1029 struct dsp_scb_descriptor * snoop_scb,
1030 struct dsp_scb_descriptor * parent_scb,
1031 int scb_child_type)
1034 struct dsp_scb_descriptor * scb;
1036 struct dsp_output_snoop_scb output_snoop_scb = {
1037 { 0, /* not used. Zero */
1043 0, /* not used. Zero */
1050 0,0,
1051 0,0,
1053 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
1054 snoop_buffer_address << 0x10,
1055 0,0,
1057 0,snoop_scb->address
1060 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&output_snoop_scb,
1061 dest,"OUTPUTSNOOP",parent_scb,
1062 scb_child_type);
1063 return scb;
1065 #endif /* not used */
1068 struct dsp_scb_descriptor *
1069 cs46xx_dsp_create_spio_write_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1070 struct dsp_scb_descriptor * parent_scb,
1071 int scb_child_type)
1073 struct dsp_scb_descriptor * scb;
1075 struct dsp_spio_write_scb spio_write_scb = {
1076 0,0, /* SPIOWAddress2:SPIOWAddress1; */
1077 0, /* SPIOWData1; */
1078 0, /* SPIOWData2; */
1079 0,0, /* SPIOWAddress4:SPIOWAddress3; */
1080 0, /* SPIOWData3; */
1081 0, /* SPIOWData4; */
1082 0,0, /* SPIOWDataPtr:Unused1; */
1083 { 0,0 }, /* Unused2[2]; */
1085 0,0, /* SPIOWChildPtr:SPIOWSiblingPtr; */
1086 0,0, /* SPIOWThisPtr:SPIOWEntryPoint; */
1093 0 /* Unused3[5]; */
1097 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&spio_write_scb,
1098 dest,"SPIOWRITE",parent_scb,
1099 scb_child_type);
1101 return scb;
1104 struct dsp_scb_descriptor *
1105 cs46xx_dsp_create_magic_snoop_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1106 u16 snoop_buffer_address,
1107 struct dsp_scb_descriptor * snoop_scb,
1108 struct dsp_scb_descriptor * parent_scb,
1109 int scb_child_type)
1111 struct dsp_scb_descriptor * scb;
1113 struct dsp_magic_snoop_task magic_snoop_scb = {
1114 /* 0 */ 0, /* i0 */
1115 /* 1 */ 0, /* i1 */
1116 /* 2 */ snoop_buffer_address << 0x10,
1117 /* 3 */ 0,snoop_scb->address,
1118 /* 4 */ 0, /* i3 */
1119 /* 5 */ 0, /* i4 */
1120 /* 6 */ 0, /* i5 */
1121 /* 7 */ 0, /* i6 */
1122 /* 8 */ 0, /* i7 */
1123 /* 9 */ 0,0, /* next_scb, sub_list_ptr */
1124 /* A */ 0,0, /* entry_point, this_ptr */
1125 /* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
1126 /* C */ snoop_buffer_address << 0x10,
1127 /* D */ 0,
1128 /* E */ { 0x8000,0x8000,
1129 /* F */ 0xffff,0xffff
1133 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&magic_snoop_scb,
1134 dest,"MAGICSNOOPTASK",parent_scb,
1135 scb_child_type);
1137 return scb;
1140 static struct dsp_scb_descriptor *
1141 find_next_free_scb (struct snd_cs46xx * chip, struct dsp_scb_descriptor * from)
1143 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1144 struct dsp_scb_descriptor * scb = from;
1146 while (scb->next_scb_ptr != ins->the_null_scb) {
1147 snd_assert (scb->next_scb_ptr != NULL, return NULL);
1149 scb = scb->next_scb_ptr;
1152 return scb;
1155 static u32 pcm_reader_buffer_addr[DSP_MAX_PCM_CHANNELS] = {
1156 0x0600, /* 1 */
1157 0x1500, /* 2 */
1158 0x1580, /* 3 */
1159 0x1600, /* 4 */
1160 0x1680, /* 5 */
1161 0x1700, /* 6 */
1162 0x1780, /* 7 */
1163 0x1800, /* 8 */
1164 0x1880, /* 9 */
1165 0x1900, /* 10 */
1166 0x1980, /* 11 */
1167 0x1A00, /* 12 */
1168 0x1A80, /* 13 */
1169 0x1B00, /* 14 */
1170 0x1B80, /* 15 */
1171 0x1C00, /* 16 */
1172 0x1C80, /* 17 */
1173 0x1D00, /* 18 */
1174 0x1D80, /* 19 */
1175 0x1E00, /* 20 */
1176 0x1E80, /* 21 */
1177 0x1F00, /* 22 */
1178 0x1F80, /* 23 */
1179 0x2000, /* 24 */
1180 0x2080, /* 25 */
1181 0x2100, /* 26 */
1182 0x2180, /* 27 */
1183 0x2200, /* 28 */
1184 0x2280, /* 29 */
1185 0x2300, /* 30 */
1186 0x2380, /* 31 */
1187 0x2400, /* 32 */
1190 static u32 src_output_buffer_addr[DSP_MAX_SRC_NR] = {
1191 0x2B80,
1192 0x2BA0,
1193 0x2BC0,
1194 0x2BE0,
1195 0x2D00,
1196 0x2D20,
1197 0x2D40,
1198 0x2D60,
1199 0x2D80,
1200 0x2DA0,
1201 0x2DC0,
1202 0x2DE0,
1203 0x2E00,
1204 0x2E20
1207 static u32 src_delay_buffer_addr[DSP_MAX_SRC_NR] = {
1208 0x2480,
1209 0x2500,
1210 0x2580,
1211 0x2600,
1212 0x2680,
1213 0x2700,
1214 0x2780,
1215 0x2800,
1216 0x2880,
1217 0x2900,
1218 0x2980,
1219 0x2A00,
1220 0x2A80,
1221 0x2B00
1224 struct dsp_pcm_channel_descriptor *
1225 cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
1226 u32 sample_rate, void * private_data,
1227 u32 hw_dma_addr,
1228 int pcm_channel_id)
1230 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1231 struct dsp_scb_descriptor * src_scb = NULL, * pcm_scb, * mixer_scb = NULL;
1232 struct dsp_scb_descriptor * src_parent_scb = NULL;
1234 /* struct dsp_scb_descriptor * pcm_parent_scb; */
1235 char scb_name[DSP_MAX_SCB_NAME];
1236 int i, pcm_index = -1, insert_point, src_index = -1, pass_through = 0;
1237 unsigned long flags;
1239 switch (pcm_channel_id) {
1240 case DSP_PCM_MAIN_CHANNEL:
1241 mixer_scb = ins->master_mix_scb;
1242 break;
1243 case DSP_PCM_REAR_CHANNEL:
1244 mixer_scb = ins->rear_mix_scb;
1245 break;
1246 case DSP_PCM_CENTER_LFE_CHANNEL:
1247 mixer_scb = ins->center_lfe_mix_scb;
1248 break;
1249 case DSP_PCM_S71_CHANNEL:
1250 /* TODO */
1251 snd_assert(0);
1252 break;
1253 case DSP_IEC958_CHANNEL:
1254 snd_assert (ins->asynch_tx_scb != NULL, return NULL);
1255 mixer_scb = ins->asynch_tx_scb;
1257 /* if sample rate is set to 48khz we pass
1258 the Sample Rate Converted (which could
1259 alter the raw data stream ...) */
1260 if (sample_rate == 48000) {
1261 snd_printdd ("IEC958 pass through\n");
1262 /* Hack to bypass creating a new SRC */
1263 pass_through = 1;
1265 break;
1266 default:
1267 snd_assert (0);
1268 return NULL;
1270 /* default sample rate is 44100 */
1271 if (!sample_rate) sample_rate = 44100;
1273 /* search for a already created SRC SCB with the same sample rate */
1274 for (i = 0; i < DSP_MAX_PCM_CHANNELS &&
1275 (pcm_index == -1 || src_scb == NULL); ++i) {
1277 /* virtual channel reserved
1278 for capture */
1279 if (i == CS46XX_DSP_CAPTURE_CHANNEL) continue;
1281 if (ins->pcm_channels[i].active) {
1282 if (!src_scb &&
1283 ins->pcm_channels[i].sample_rate == sample_rate &&
1284 ins->pcm_channels[i].mixer_scb == mixer_scb) {
1285 src_scb = ins->pcm_channels[i].src_scb;
1286 ins->pcm_channels[i].src_scb->ref_count ++;
1287 src_index = ins->pcm_channels[i].src_slot;
1289 } else if (pcm_index == -1) {
1290 pcm_index = i;
1294 if (pcm_index == -1) {
1295 snd_printk (KERN_ERR "dsp_spos: no free PCM channel\n");
1296 return NULL;
1299 if (src_scb == NULL) {
1300 if (ins->nsrc_scb >= DSP_MAX_SRC_NR) {
1301 snd_printk(KERN_ERR "dsp_spos: to many SRC instances\n!");
1302 return NULL;
1305 /* find a free slot */
1306 for (i = 0; i < DSP_MAX_SRC_NR; ++i) {
1307 if (ins->src_scb_slots[i] == 0) {
1308 src_index = i;
1309 ins->src_scb_slots[i] = 1;
1310 break;
1313 snd_assert (src_index != -1,return NULL);
1315 /* we need to create a new SRC SCB */
1316 if (mixer_scb->sub_list_ptr == ins->the_null_scb) {
1317 src_parent_scb = mixer_scb;
1318 insert_point = SCB_ON_PARENT_SUBLIST_SCB;
1319 } else {
1320 src_parent_scb = find_next_free_scb(chip,mixer_scb->sub_list_ptr);
1321 insert_point = SCB_ON_PARENT_NEXT_SCB;
1324 snprintf (scb_name,DSP_MAX_SCB_NAME,"SrcTask_SCB%d",src_index);
1326 snd_printdd( "dsp_spos: creating SRC \"%s\"\n",scb_name);
1327 src_scb = cs46xx_dsp_create_src_task_scb(chip,scb_name,
1328 sample_rate,
1329 src_output_buffer_addr[src_index],
1330 src_delay_buffer_addr[src_index],
1331 /* 0x400 - 0x600 source SCBs */
1332 0x400 + (src_index * 0x10) ,
1333 src_parent_scb,
1334 insert_point,
1335 pass_through);
1337 if (!src_scb) {
1338 snd_printk (KERN_ERR "dsp_spos: failed to create SRCtaskSCB\n");
1339 return NULL;
1342 /* cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate); */
1344 ins->nsrc_scb ++;
1348 snprintf (scb_name,DSP_MAX_SCB_NAME,"PCMReader_SCB%d",pcm_index);
1350 snd_printdd( "dsp_spos: creating PCM \"%s\" (%d)\n",scb_name,
1351 pcm_channel_id);
1353 pcm_scb = cs46xx_dsp_create_pcm_reader_scb(chip,scb_name,
1354 pcm_reader_buffer_addr[pcm_index],
1355 /* 0x200 - 400 PCMreader SCBs */
1356 (pcm_index * 0x10) + 0x200,
1357 pcm_index, /* virtual channel 0-31 */
1358 hw_dma_addr, /* pcm hw addr */
1359 NULL, /* parent SCB ptr */
1360 0 /* insert point */
1363 if (!pcm_scb) {
1364 snd_printk (KERN_ERR "dsp_spos: failed to create PCMreaderSCB\n");
1365 return NULL;
1368 spin_lock_irqsave(&chip->reg_lock, flags);
1369 ins->pcm_channels[pcm_index].sample_rate = sample_rate;
1370 ins->pcm_channels[pcm_index].pcm_reader_scb = pcm_scb;
1371 ins->pcm_channels[pcm_index].src_scb = src_scb;
1372 ins->pcm_channels[pcm_index].unlinked = 1;
1373 ins->pcm_channels[pcm_index].private_data = private_data;
1374 ins->pcm_channels[pcm_index].src_slot = src_index;
1375 ins->pcm_channels[pcm_index].active = 1;
1376 ins->pcm_channels[pcm_index].pcm_slot = pcm_index;
1377 ins->pcm_channels[pcm_index].mixer_scb = mixer_scb;
1378 ins->npcm_channels ++;
1379 spin_unlock_irqrestore(&chip->reg_lock, flags);
1381 return (ins->pcm_channels + pcm_index);
1384 int cs46xx_dsp_pcm_channel_set_period (struct snd_cs46xx * chip,
1385 struct dsp_pcm_channel_descriptor * pcm_channel,
1386 int period_size)
1388 u32 temp = snd_cs46xx_peek (chip,pcm_channel->pcm_reader_scb->address << 2);
1389 temp &= ~DMA_RQ_C1_SOURCE_SIZE_MASK;
1391 switch (period_size) {
1392 case 2048:
1393 temp |= DMA_RQ_C1_SOURCE_MOD1024;
1394 break;
1395 case 1024:
1396 temp |= DMA_RQ_C1_SOURCE_MOD512;
1397 break;
1398 case 512:
1399 temp |= DMA_RQ_C1_SOURCE_MOD256;
1400 break;
1401 case 256:
1402 temp |= DMA_RQ_C1_SOURCE_MOD128;
1403 break;
1404 case 128:
1405 temp |= DMA_RQ_C1_SOURCE_MOD64;
1406 break;
1407 case 64:
1408 temp |= DMA_RQ_C1_SOURCE_MOD32;
1409 break;
1410 case 32:
1411 temp |= DMA_RQ_C1_SOURCE_MOD16;
1412 break;
1413 default:
1414 snd_printdd ("period size (%d) not supported by HW\n", period_size);
1415 return -EINVAL;
1418 snd_cs46xx_poke (chip,pcm_channel->pcm_reader_scb->address << 2,temp);
1420 return 0;
1423 int cs46xx_dsp_pcm_ostream_set_period (struct snd_cs46xx * chip,
1424 int period_size)
1426 u32 temp = snd_cs46xx_peek (chip,WRITEBACK_SCB_ADDR << 2);
1427 temp &= ~DMA_RQ_C1_DEST_SIZE_MASK;
1429 switch (period_size) {
1430 case 2048:
1431 temp |= DMA_RQ_C1_DEST_MOD1024;
1432 break;
1433 case 1024:
1434 temp |= DMA_RQ_C1_DEST_MOD512;
1435 break;
1436 case 512:
1437 temp |= DMA_RQ_C1_DEST_MOD256;
1438 break;
1439 case 256:
1440 temp |= DMA_RQ_C1_DEST_MOD128;
1441 break;
1442 case 128:
1443 temp |= DMA_RQ_C1_DEST_MOD64;
1444 break;
1445 case 64:
1446 temp |= DMA_RQ_C1_DEST_MOD32;
1447 break;
1448 case 32:
1449 temp |= DMA_RQ_C1_DEST_MOD16;
1450 break;
1451 default:
1452 snd_printdd ("period size (%d) not supported by HW\n", period_size);
1453 return -EINVAL;
1456 snd_cs46xx_poke (chip,WRITEBACK_SCB_ADDR << 2,temp);
1458 return 0;
1461 void cs46xx_dsp_destroy_pcm_channel (struct snd_cs46xx * chip,
1462 struct dsp_pcm_channel_descriptor * pcm_channel)
1464 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1465 unsigned long flags;
1467 snd_assert(pcm_channel->active, return );
1468 snd_assert(ins->npcm_channels > 0, return );
1469 snd_assert(pcm_channel->src_scb->ref_count > 0, return );
1471 spin_lock_irqsave(&chip->reg_lock, flags);
1472 pcm_channel->unlinked = 1;
1473 pcm_channel->active = 0;
1474 pcm_channel->private_data = NULL;
1475 pcm_channel->src_scb->ref_count --;
1476 ins->npcm_channels --;
1477 spin_unlock_irqrestore(&chip->reg_lock, flags);
1479 cs46xx_dsp_remove_scb(chip,pcm_channel->pcm_reader_scb);
1481 if (!pcm_channel->src_scb->ref_count) {
1482 cs46xx_dsp_remove_scb(chip,pcm_channel->src_scb);
1484 snd_assert (pcm_channel->src_slot >= 0 && pcm_channel->src_slot <= DSP_MAX_SRC_NR,
1485 return );
1487 ins->src_scb_slots[pcm_channel->src_slot] = 0;
1488 ins->nsrc_scb --;
1492 int cs46xx_dsp_pcm_unlink (struct snd_cs46xx * chip,
1493 struct dsp_pcm_channel_descriptor * pcm_channel)
1495 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1496 unsigned long flags;
1498 snd_assert(pcm_channel->active,return -EIO);
1499 snd_assert(ins->npcm_channels > 0,return -EIO);
1501 spin_lock(&pcm_channel->src_scb->lock);
1503 if (pcm_channel->unlinked) {
1504 spin_unlock(&pcm_channel->src_scb->lock);
1505 return -EIO;
1508 spin_lock_irqsave(&chip->reg_lock, flags);
1509 pcm_channel->unlinked = 1;
1510 spin_unlock_irqrestore(&chip->reg_lock, flags);
1512 _dsp_unlink_scb (chip,pcm_channel->pcm_reader_scb);
1514 spin_unlock(&pcm_channel->src_scb->lock);
1515 return 0;
1518 int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip,
1519 struct dsp_pcm_channel_descriptor * pcm_channel)
1521 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1522 struct dsp_scb_descriptor * parent_scb;
1523 struct dsp_scb_descriptor * src_scb = pcm_channel->src_scb;
1524 unsigned long flags;
1526 spin_lock(&pcm_channel->src_scb->lock);
1528 if (pcm_channel->unlinked == 0) {
1529 spin_unlock(&pcm_channel->src_scb->lock);
1530 return -EIO;
1533 parent_scb = src_scb;
1535 if (src_scb->sub_list_ptr != ins->the_null_scb) {
1536 src_scb->sub_list_ptr->parent_scb_ptr = pcm_channel->pcm_reader_scb;
1537 pcm_channel->pcm_reader_scb->next_scb_ptr = src_scb->sub_list_ptr;
1540 src_scb->sub_list_ptr = pcm_channel->pcm_reader_scb;
1542 snd_assert (pcm_channel->pcm_reader_scb->parent_scb_ptr == NULL, ; );
1543 pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb;
1545 spin_lock_irqsave(&chip->reg_lock, flags);
1547 /* update SCB entry in DSP RAM */
1548 cs46xx_dsp_spos_update_scb(chip,pcm_channel->pcm_reader_scb);
1550 /* update parent SCB entry */
1551 cs46xx_dsp_spos_update_scb(chip,parent_scb);
1553 pcm_channel->unlinked = 0;
1554 spin_unlock_irqrestore(&chip->reg_lock, flags);
1556 spin_unlock(&pcm_channel->src_scb->lock);
1557 return 0;
1560 struct dsp_scb_descriptor *
1561 cs46xx_add_record_source (struct snd_cs46xx *chip, struct dsp_scb_descriptor * source,
1562 u16 addr, char * scb_name)
1564 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1565 struct dsp_scb_descriptor * parent;
1566 struct dsp_scb_descriptor * pcm_input;
1567 int insert_point;
1569 snd_assert (ins->record_mixer_scb != NULL,return NULL);
1571 if (ins->record_mixer_scb->sub_list_ptr != ins->the_null_scb) {
1572 parent = find_next_free_scb (chip,ins->record_mixer_scb->sub_list_ptr);
1573 insert_point = SCB_ON_PARENT_NEXT_SCB;
1574 } else {
1575 parent = ins->record_mixer_scb;
1576 insert_point = SCB_ON_PARENT_SUBLIST_SCB;
1579 pcm_input = cs46xx_dsp_create_pcm_serial_input_scb(chip,scb_name,addr,
1580 source, parent,
1581 insert_point);
1583 return pcm_input;
1586 int cs46xx_src_unlink(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
1588 snd_assert (src->parent_scb_ptr != NULL, return -EINVAL );
1590 /* mute SCB */
1591 cs46xx_dsp_scb_set_volume (chip,src,0,0);
1593 _dsp_unlink_scb (chip,src);
1595 return 0;
1598 int cs46xx_src_link(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
1600 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1601 struct dsp_scb_descriptor * parent_scb;
1603 snd_assert (src->parent_scb_ptr == NULL, return -EINVAL );
1604 snd_assert(ins->master_mix_scb !=NULL, return -EINVAL );
1606 if (ins->master_mix_scb->sub_list_ptr != ins->the_null_scb) {
1607 parent_scb = find_next_free_scb (chip,ins->master_mix_scb->sub_list_ptr);
1608 parent_scb->next_scb_ptr = src;
1609 } else {
1610 parent_scb = ins->master_mix_scb;
1611 parent_scb->sub_list_ptr = src;
1614 src->parent_scb_ptr = parent_scb;
1616 /* update entry in DSP RAM */
1617 cs46xx_dsp_spos_update_scb(chip,parent_scb);
1619 return 0;
1622 int cs46xx_dsp_enable_spdif_out (struct snd_cs46xx *chip)
1624 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1626 if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
1627 cs46xx_dsp_enable_spdif_hw (chip);
1630 /* dont touch anything if SPDIF is open */
1631 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
1632 /* when cs46xx_iec958_post_close(...) is called it
1633 will call this function if necessary depending on
1634 this bit */
1635 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1637 return -EBUSY;
1640 snd_assert (ins->asynch_tx_scb == NULL, return -EINVAL);
1641 snd_assert (ins->master_mix_scb->next_scb_ptr == ins->the_null_scb, return -EINVAL);
1643 /* reset output snooper sample buffer pointer */
1644 snd_cs46xx_poke (chip, (ins->ref_snoop_scb->address + 2) << 2,
1645 (OUTPUT_SNOOP_BUFFER + 0x10) << 0x10 );
1647 /* The asynch. transfer task */
1648 ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
1649 SPDIFO_SCB_INST,
1650 SPDIFO_IP_OUTPUT_BUFFER1,
1651 ins->master_mix_scb,
1652 SCB_ON_PARENT_NEXT_SCB);
1653 if (!ins->asynch_tx_scb) return -ENOMEM;
1655 ins->spdif_pcm_input_scb = cs46xx_dsp_create_pcm_serial_input_scb(chip,"PCMSerialInput_II",
1656 PCMSERIALINII_SCB_ADDR,
1657 ins->ref_snoop_scb,
1658 ins->asynch_tx_scb,
1659 SCB_ON_PARENT_SUBLIST_SCB);
1662 if (!ins->spdif_pcm_input_scb) return -ENOMEM;
1664 /* monitor state */
1665 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1667 return 0;
1670 int cs46xx_dsp_disable_spdif_out (struct snd_cs46xx *chip)
1672 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1674 /* dont touch anything if SPDIF is open */
1675 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
1676 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1677 return -EBUSY;
1680 /* check integrety */
1681 snd_assert (ins->asynch_tx_scb != NULL, return -EINVAL);
1682 snd_assert (ins->spdif_pcm_input_scb != NULL,return -EINVAL);
1683 snd_assert (ins->master_mix_scb->next_scb_ptr == ins->asynch_tx_scb, return -EINVAL);
1684 snd_assert (ins->asynch_tx_scb->parent_scb_ptr == ins->master_mix_scb, return -EINVAL);
1686 cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
1687 cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
1689 ins->spdif_pcm_input_scb = NULL;
1690 ins->asynch_tx_scb = NULL;
1692 /* clear buffer to prevent any undesired noise */
1693 _dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
1695 /* monitor state */
1696 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1699 return 0;
1702 int cs46xx_iec958_pre_open (struct snd_cs46xx *chip)
1704 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1706 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
1707 /* remove AsynchFGTxSCB and and PCMSerialInput_II */
1708 cs46xx_dsp_disable_spdif_out (chip);
1710 /* save state */
1711 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1714 /* if not enabled already */
1715 if ( !(ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
1716 cs46xx_dsp_enable_spdif_hw (chip);
1719 /* Create the asynch. transfer task for playback */
1720 ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
1721 SPDIFO_SCB_INST,
1722 SPDIFO_IP_OUTPUT_BUFFER1,
1723 ins->master_mix_scb,
1724 SCB_ON_PARENT_NEXT_SCB);
1727 /* set spdif channel status value for streaming */
1728 cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_stream);
1730 ins->spdif_status_out |= DSP_SPDIF_STATUS_PLAYBACK_OPEN;
1732 return 0;
1735 int cs46xx_iec958_post_close (struct snd_cs46xx *chip)
1737 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1739 snd_assert (ins->asynch_tx_scb != NULL, return -EINVAL);
1741 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_PLAYBACK_OPEN;
1743 /* restore settings */
1744 cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);
1746 /* deallocate stuff */
1747 if (ins->spdif_pcm_input_scb != NULL) {
1748 cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
1749 ins->spdif_pcm_input_scb = NULL;
1752 cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
1753 ins->asynch_tx_scb = NULL;
1755 /* clear buffer to prevent any undesired noise */
1756 _dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
1758 /* restore state */
1759 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
1760 cs46xx_dsp_enable_spdif_out (chip);
1763 return 0;