staging: comedi: ni_labpc: clarify the cmd->start_arg validation
[linux-2.6/btrfs-unstable.git] / sound / pci / cs46xx / dsp_spos_scb_lib.c
blob8284bc9b585822a12ffba887a3233fd077af98b3
1 /*
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * 2002-07 Benny Sjostrand benny@hostmobility.com
24 #include <asm/io.h>
25 #include <linux/delay.h>
26 #include <linux/pm.h>
27 #include <linux/init.h>
28 #include <linux/slab.h>
29 #include <linux/mutex.h>
31 #include <sound/core.h>
32 #include <sound/control.h>
33 #include <sound/info.h>
34 #include "cs46xx.h"
36 #include "cs46xx_lib.h"
37 #include "dsp_spos.h"
39 struct proc_scb_info {
40 struct dsp_scb_descriptor * scb_desc;
41 struct snd_cs46xx *chip;
44 static void remove_symbol (struct snd_cs46xx * chip, struct dsp_symbol_entry * symbol)
46 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
47 int symbol_index = (int)(symbol - ins->symbol_table.symbols);
49 if (snd_BUG_ON(ins->symbol_table.nsymbols <= 0))
50 return;
51 if (snd_BUG_ON(symbol_index < 0 ||
52 symbol_index >= ins->symbol_table.nsymbols))
53 return;
55 ins->symbol_table.symbols[symbol_index].deleted = 1;
57 if (symbol_index < ins->symbol_table.highest_frag_index) {
58 ins->symbol_table.highest_frag_index = symbol_index;
61 if (symbol_index == ins->symbol_table.nsymbols - 1)
62 ins->symbol_table.nsymbols --;
64 if (ins->symbol_table.highest_frag_index > ins->symbol_table.nsymbols) {
65 ins->symbol_table.highest_frag_index = ins->symbol_table.nsymbols;
70 #ifdef CONFIG_PROC_FS
71 static void cs46xx_dsp_proc_scb_info_read (struct snd_info_entry *entry,
72 struct snd_info_buffer *buffer)
74 struct proc_scb_info * scb_info = entry->private_data;
75 struct dsp_scb_descriptor * scb = scb_info->scb_desc;
76 struct dsp_spos_instance * ins;
77 struct snd_cs46xx *chip = scb_info->chip;
78 int j,col;
79 void __iomem *dst = chip->region.idx[1].remap_addr + DSP_PARAMETER_BYTE_OFFSET;
81 ins = chip->dsp_spos_instance;
83 mutex_lock(&chip->spos_mutex);
84 snd_iprintf(buffer,"%04x %s:\n",scb->address,scb->scb_name);
86 for (col = 0,j = 0;j < 0x10; j++,col++) {
87 if (col == 4) {
88 snd_iprintf(buffer,"\n");
89 col = 0;
91 snd_iprintf(buffer,"%08x ",readl(dst + (scb->address + j) * sizeof(u32)));
94 snd_iprintf(buffer,"\n");
96 if (scb->parent_scb_ptr != NULL) {
97 snd_iprintf(buffer,"parent [%s:%04x] ",
98 scb->parent_scb_ptr->scb_name,
99 scb->parent_scb_ptr->address);
100 } else snd_iprintf(buffer,"parent [none] ");
102 snd_iprintf(buffer,"sub_list_ptr [%s:%04x]\nnext_scb_ptr [%s:%04x] task_entry [%s:%04x]\n",
103 scb->sub_list_ptr->scb_name,
104 scb->sub_list_ptr->address,
105 scb->next_scb_ptr->scb_name,
106 scb->next_scb_ptr->address,
107 scb->task_entry->symbol_name,
108 scb->task_entry->address);
110 snd_iprintf(buffer,"index [%d] ref_count [%d]\n",scb->index,scb->ref_count);
111 mutex_unlock(&chip->spos_mutex);
113 #endif
115 static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
117 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
119 if ( scb->parent_scb_ptr ) {
120 /* unlink parent SCB */
121 if (snd_BUG_ON(scb->parent_scb_ptr->sub_list_ptr != scb &&
122 scb->parent_scb_ptr->next_scb_ptr != scb))
123 return;
125 if (scb->parent_scb_ptr->sub_list_ptr == scb) {
127 if (scb->next_scb_ptr == ins->the_null_scb) {
128 /* last and only node in parent sublist */
129 scb->parent_scb_ptr->sub_list_ptr = scb->sub_list_ptr;
131 if (scb->sub_list_ptr != ins->the_null_scb) {
132 scb->sub_list_ptr->parent_scb_ptr = scb->parent_scb_ptr;
134 scb->sub_list_ptr = ins->the_null_scb;
135 } else {
136 /* first node in parent sublist */
137 scb->parent_scb_ptr->sub_list_ptr = scb->next_scb_ptr;
139 if (scb->next_scb_ptr != ins->the_null_scb) {
140 /* update next node parent ptr. */
141 scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
143 scb->next_scb_ptr = ins->the_null_scb;
145 } else {
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 /* update parent first entry in DSP RAM */
156 cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
158 /* then update entry in DSP RAM */
159 cs46xx_dsp_spos_update_scb(chip,scb);
161 scb->parent_scb_ptr = NULL;
165 static void _dsp_clear_sample_buffer (struct snd_cs46xx *chip, u32 sample_buffer_addr,
166 int dword_count)
168 void __iomem *dst = chip->region.idx[2].remap_addr + sample_buffer_addr;
169 int i;
171 for (i = 0; i < dword_count ; ++i ) {
172 writel(0, dst);
173 dst += 4;
177 void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
179 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
180 unsigned long flags;
182 /* check integrety */
183 if (snd_BUG_ON(scb->index < 0 ||
184 scb->index >= ins->nscb ||
185 (ins->scbs + scb->index) != scb))
186 return;
188 #if 0
189 /* can't remove a SCB with childs before
190 removing childs first */
191 if (snd_BUG_ON(scb->sub_list_ptr != ins->the_null_scb ||
192 scb->next_scb_ptr != ins->the_null_scb))
193 goto _end;
194 #endif
196 spin_lock_irqsave(&chip->reg_lock, flags);
197 _dsp_unlink_scb (chip,scb);
198 spin_unlock_irqrestore(&chip->reg_lock, flags);
200 cs46xx_dsp_proc_free_scb_desc(scb);
201 if (snd_BUG_ON(!scb->scb_symbol))
202 return;
203 remove_symbol (chip,scb->scb_symbol);
205 ins->scbs[scb->index].deleted = 1;
206 #ifdef CONFIG_PM_SLEEP
207 kfree(ins->scbs[scb->index].data);
208 ins->scbs[scb->index].data = NULL;
209 #endif
211 if (scb->index < ins->scb_highest_frag_index)
212 ins->scb_highest_frag_index = scb->index;
214 if (scb->index == ins->nscb - 1) {
215 ins->nscb --;
218 if (ins->scb_highest_frag_index > ins->nscb) {
219 ins->scb_highest_frag_index = ins->nscb;
222 #if 0
223 /* !!!! THIS IS A PIECE OF SHIT MADE BY ME !!! */
224 for(i = scb->index + 1;i < ins->nscb; ++i) {
225 ins->scbs[i - 1].index = i - 1;
227 #endif
231 #ifdef CONFIG_PROC_FS
232 void cs46xx_dsp_proc_free_scb_desc (struct dsp_scb_descriptor * scb)
234 if (scb->proc_info) {
235 struct proc_scb_info * scb_info = scb->proc_info->private_data;
236 struct snd_cs46xx *chip = scb_info->chip;
238 dev_dbg(chip->card->dev,
239 "cs46xx_dsp_proc_free_scb_desc: freeing %s\n",
240 scb->scb_name);
242 snd_info_free_entry(scb->proc_info);
243 scb->proc_info = NULL;
245 kfree (scb_info);
249 void cs46xx_dsp_proc_register_scb_desc (struct snd_cs46xx *chip,
250 struct dsp_scb_descriptor * scb)
252 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
253 struct snd_info_entry * entry;
254 struct proc_scb_info * scb_info;
256 /* register to proc */
257 if (ins->snd_card != NULL && ins->proc_dsp_dir != NULL &&
258 scb->proc_info == NULL) {
260 if ((entry = snd_info_create_card_entry(ins->snd_card, scb->scb_name,
261 ins->proc_dsp_dir)) != NULL) {
262 scb_info = kmalloc(sizeof(struct proc_scb_info), GFP_KERNEL);
263 if (!scb_info) {
264 snd_info_free_entry(entry);
265 entry = NULL;
266 goto out;
269 scb_info->chip = chip;
270 scb_info->scb_desc = scb;
272 entry->content = SNDRV_INFO_CONTENT_TEXT;
273 entry->private_data = scb_info;
274 entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
276 entry->c.text.read = cs46xx_dsp_proc_scb_info_read;
278 if (snd_info_register(entry) < 0) {
279 snd_info_free_entry(entry);
280 kfree (scb_info);
281 entry = NULL;
284 out:
285 scb->proc_info = entry;
288 #endif /* CONFIG_PROC_FS */
290 static struct dsp_scb_descriptor *
291 _dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32 dest,
292 struct dsp_symbol_entry * task_entry,
293 struct dsp_scb_descriptor * parent_scb,
294 int scb_child_type)
296 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
297 struct dsp_scb_descriptor * scb;
299 unsigned long flags;
301 if (snd_BUG_ON(!ins->the_null_scb))
302 return NULL;
304 /* fill the data that will be wroten to DSP */
305 scb_data[SCBsubListPtr] =
306 (ins->the_null_scb->address << 0x10) | ins->the_null_scb->address;
308 scb_data[SCBfuncEntryPtr] &= 0xFFFF0000;
309 scb_data[SCBfuncEntryPtr] |= task_entry->address;
311 dev_dbg(chip->card->dev, "dsp_spos: creating SCB <%s>\n", name);
313 scb = cs46xx_dsp_create_scb(chip,name,scb_data,dest);
316 scb->sub_list_ptr = ins->the_null_scb;
317 scb->next_scb_ptr = ins->the_null_scb;
319 scb->parent_scb_ptr = parent_scb;
320 scb->task_entry = task_entry;
323 /* update parent SCB */
324 if (scb->parent_scb_ptr) {
325 #if 0
326 dev_dbg(chip->card->dev,
327 "scb->parent_scb_ptr = %s\n",
328 scb->parent_scb_ptr->scb_name);
329 dev_dbg(chip->card->dev,
330 "scb->parent_scb_ptr->next_scb_ptr = %s\n",
331 scb->parent_scb_ptr->next_scb_ptr->scb_name);
332 dev_dbg(chip->card->dev,
333 "scb->parent_scb_ptr->sub_list_ptr = %s\n",
334 scb->parent_scb_ptr->sub_list_ptr->scb_name);
335 #endif
336 /* link to parent SCB */
337 if (scb_child_type == SCB_ON_PARENT_NEXT_SCB) {
338 if (snd_BUG_ON(scb->parent_scb_ptr->next_scb_ptr !=
339 ins->the_null_scb))
340 return NULL;
342 scb->parent_scb_ptr->next_scb_ptr = scb;
344 } else if (scb_child_type == SCB_ON_PARENT_SUBLIST_SCB) {
345 if (snd_BUG_ON(scb->parent_scb_ptr->sub_list_ptr !=
346 ins->the_null_scb))
347 return NULL;
349 scb->parent_scb_ptr->sub_list_ptr = scb;
350 } else {
351 snd_BUG();
354 spin_lock_irqsave(&chip->reg_lock, flags);
356 /* update entry in DSP RAM */
357 cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
359 spin_unlock_irqrestore(&chip->reg_lock, flags);
363 cs46xx_dsp_proc_register_scb_desc (chip,scb);
365 return scb;
368 static struct dsp_scb_descriptor *
369 cs46xx_dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data,
370 u32 dest, char * task_entry_name,
371 struct dsp_scb_descriptor * parent_scb,
372 int scb_child_type)
374 struct dsp_symbol_entry * task_entry;
376 task_entry = cs46xx_dsp_lookup_symbol (chip,task_entry_name,
377 SYMBOL_CODE);
379 if (task_entry == NULL) {
380 dev_err(chip->card->dev,
381 "dsp_spos: symbol %s not found\n", task_entry_name);
382 return NULL;
385 return _dsp_create_generic_scb (chip,name,scb_data,dest,task_entry,
386 parent_scb,scb_child_type);
389 struct dsp_scb_descriptor *
390 cs46xx_dsp_create_timing_master_scb (struct snd_cs46xx *chip)
392 struct dsp_scb_descriptor * scb;
394 struct dsp_timing_master_scb timing_master_scb = {
395 { 0,
400 { 0,
406 0,0,
407 0,NULL_SCB_ADDR,
408 0,0, /* extraSampleAccum:TMreserved */
409 0,0, /* codecFIFOptr:codecFIFOsyncd */
410 0x0001,0x8000, /* fracSampAccumQm1:TMfrmsLeftInGroup */
411 0x0001,0x0000, /* fracSampCorrectionQm1:TMfrmGroupLength */
412 0x00060000 /* nSampPerFrmQ15 */
415 scb = cs46xx_dsp_create_generic_scb(chip,"TimingMasterSCBInst",(u32 *)&timing_master_scb,
416 TIMINGMASTER_SCB_ADDR,
417 "TIMINGMASTER",NULL,SCB_NO_PARENT);
419 return scb;
423 struct dsp_scb_descriptor *
424 cs46xx_dsp_create_codec_out_scb(struct snd_cs46xx * chip, char * codec_name,
425 u16 channel_disp, u16 fifo_addr, u16 child_scb_addr,
426 u32 dest, struct dsp_scb_descriptor * parent_scb,
427 int scb_child_type)
429 struct dsp_scb_descriptor * scb;
431 struct dsp_codec_output_scb codec_out_scb = {
432 { 0,
444 0,0,
445 0,NULL_SCB_ADDR,
446 0, /* COstrmRsConfig */
447 0, /* COstrmBufPtr */
448 channel_disp,fifo_addr, /* leftChanBaseIOaddr:rightChanIOdisp */
449 0x0000,0x0080, /* (!AC97!) COexpVolChangeRate:COscaleShiftCount */
450 0,child_scb_addr /* COreserved - need child scb to work with rom code */
454 scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_out_scb,
455 dest,"S16_CODECOUTPUTTASK",parent_scb,
456 scb_child_type);
458 return scb;
461 struct dsp_scb_descriptor *
462 cs46xx_dsp_create_codec_in_scb(struct snd_cs46xx * chip, char * codec_name,
463 u16 channel_disp, u16 fifo_addr, u16 sample_buffer_addr,
464 u32 dest, struct dsp_scb_descriptor * parent_scb,
465 int scb_child_type)
468 struct dsp_scb_descriptor * scb;
469 struct dsp_codec_input_scb codec_input_scb = {
470 { 0,
483 #if 0 /* cs4620 */
484 SyncIOSCB,NULL_SCB_ADDR
485 #else
486 0 , 0,
487 #endif
488 0,0,
490 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64, /* strmRsConfig */
491 sample_buffer_addr << 0x10, /* strmBufPtr; defined as a dword ptr, used as a byte ptr */
492 channel_disp,fifo_addr, /* (!AC97!) leftChanBaseINaddr=AC97primary
493 link input slot 3 :rightChanINdisp=""slot 4 */
494 0x0000,0x0000, /* (!AC97!) ????:scaleShiftCount; no shift needed
495 because AC97 is already 20 bits */
496 0x80008000 /* ??clw cwcgame.scb has 0 */
499 scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_input_scb,
500 dest,"S16_CODECINPUTTASK",parent_scb,
501 scb_child_type);
502 return scb;
506 static struct dsp_scb_descriptor *
507 cs46xx_dsp_create_pcm_reader_scb(struct snd_cs46xx * chip, char * scb_name,
508 u16 sample_buffer_addr, u32 dest,
509 int virtual_channel, u32 playback_hw_addr,
510 struct dsp_scb_descriptor * parent_scb,
511 int scb_child_type)
513 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
514 struct dsp_scb_descriptor * scb;
516 struct dsp_generic_scb pcm_reader_scb = {
519 Play DMA Task xfers data from host buffer to SP buffer
520 init/runtime variables:
521 PlayAC: Play Audio Data Conversion - SCB loc: 2nd dword, mask: 0x0000F000L
522 DATA_FMT_16BIT_ST_LTLEND(0x00000000L) from 16-bit stereo, little-endian
523 DATA_FMT_8_BIT_ST_SIGNED(0x00001000L) from 8-bit stereo, signed
524 DATA_FMT_16BIT_MN_LTLEND(0x00002000L) from 16-bit mono, little-endian
525 DATA_FMT_8_BIT_MN_SIGNED(0x00003000L) from 8-bit mono, signed
526 DATA_FMT_16BIT_ST_BIGEND(0x00004000L) from 16-bit stereo, big-endian
527 DATA_FMT_16BIT_MN_BIGEND(0x00006000L) from 16-bit mono, big-endian
528 DATA_FMT_8_BIT_ST_UNSIGNED(0x00009000L) from 8-bit stereo, unsigned
529 DATA_FMT_8_BIT_MN_UNSIGNED(0x0000b000L) from 8-bit mono, unsigned
530 ? Other combinations possible from:
531 DMA_RQ_C2_AUDIO_CONVERT_MASK 0x0000F000L
532 DMA_RQ_C2_AC_NONE 0x00000000L
533 DMA_RQ_C2_AC_8_TO_16_BIT 0x00001000L
534 DMA_RQ_C2_AC_MONO_TO_STEREO 0x00002000L
535 DMA_RQ_C2_AC_ENDIAN_CONVERT 0x00004000L
536 DMA_RQ_C2_AC_SIGNED_CONVERT 0x00008000L
538 HostBuffAddr: Host Buffer Physical Byte Address - SCB loc:3rd dword, Mask: 0xFFFFFFFFL
539 aligned to dword boundary
541 /* Basic (non scatter/gather) DMA requestor (4 ints) */
542 { DMA_RQ_C1_SOURCE_ON_HOST + /* source buffer is on the host */
543 DMA_RQ_C1_SOURCE_MOD1024 + /* source buffer is 1024 dwords (4096 bytes) */
544 DMA_RQ_C1_DEST_MOD32 + /* dest buffer(PCMreaderBuf) is 32 dwords*/
545 DMA_RQ_C1_WRITEBACK_SRC_FLAG + /* ?? */
546 DMA_RQ_C1_WRITEBACK_DEST_FLAG + /* ?? */
547 15, /* DwordCount-1: picked 16 for DwordCount because Jim */
548 /* Barnette said that is what we should use since */
549 /* we are not running in optimized mode? */
550 DMA_RQ_C2_AC_NONE +
551 DMA_RQ_C2_SIGNAL_SOURCE_PINGPONG + /* set play interrupt (bit0) in HISR when source */
552 /* buffer (on host) crosses half-way point */
553 virtual_channel, /* Play DMA channel arbitrarily set to 0 */
554 playback_hw_addr, /* HostBuffAddr (source) */
555 DMA_RQ_SD_SP_SAMPLE_ADDR + /* destination buffer is in SP Sample Memory */
556 sample_buffer_addr /* SP Buffer Address (destination) */
558 /* Scatter/gather DMA requestor extension (5 ints) */
566 /* Sublist pointer & next stream control block (SCB) link. */
567 NULL_SCB_ADDR,NULL_SCB_ADDR,
568 /* Pointer to this tasks parameter block & stream function pointer */
569 0,NULL_SCB_ADDR,
570 /* rsConfig register for stream buffer (rsDMA reg. is loaded from basicReq.daw */
571 /* for incoming streams, or basicReq.saw, for outgoing streams) */
572 RSCONFIG_DMA_ENABLE + /* enable DMA */
573 (19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) + /* MAX_DMA_SIZE picked to be 19 since SPUD */
574 /* uses it for some reason */
575 ((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) + /* stream number = SCBaddr/16 */
576 RSCONFIG_SAMPLE_16STEREO +
577 RSCONFIG_MODULO_32, /* dest buffer(PCMreaderBuf) is 32 dwords (256 bytes) */
578 /* Stream sample pointer & MAC-unit mode for this stream */
579 (sample_buffer_addr << 0x10),
580 /* Fractional increment per output sample in the input sample buffer */
583 /* Standard stereo volume control
584 default muted */
585 0xffff,0xffff,
586 0xffff,0xffff
590 if (ins->null_algorithm == NULL) {
591 ins->null_algorithm = cs46xx_dsp_lookup_symbol (chip,"NULLALGORITHM",
592 SYMBOL_CODE);
594 if (ins->null_algorithm == NULL) {
595 dev_err(chip->card->dev,
596 "dsp_spos: symbol NULLALGORITHM not found\n");
597 return NULL;
601 scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_reader_scb,
602 dest,ins->null_algorithm,parent_scb,
603 scb_child_type);
605 return scb;
608 #define GOF_PER_SEC 200
610 struct dsp_scb_descriptor *
611 cs46xx_dsp_create_src_task_scb(struct snd_cs46xx * chip, char * scb_name,
612 int rate,
613 u16 src_buffer_addr,
614 u16 src_delay_buffer_addr, u32 dest,
615 struct dsp_scb_descriptor * parent_scb,
616 int scb_child_type,
617 int pass_through)
620 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
621 struct dsp_scb_descriptor * scb;
622 unsigned int tmp1, tmp2;
623 unsigned int phiIncr;
624 unsigned int correctionPerGOF, correctionPerSec;
626 dev_dbg(chip->card->dev, "dsp_spos: setting %s rate to %u\n",
627 scb_name, rate);
630 * Compute the values used to drive the actual sample rate conversion.
631 * The following formulas are being computed, using inline assembly
632 * since we need to use 64 bit arithmetic to compute the values:
634 * phiIncr = floor((Fs,in * 2^26) / Fs,out)
635 * correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) /
636 * GOF_PER_SEC)
637 * ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -M
638 * GOF_PER_SEC * correctionPerGOF
640 * i.e.
642 * phiIncr:other = dividend:remainder((Fs,in * 2^26) / Fs,out)
643 * correctionPerGOF:correctionPerSec =
644 * dividend:remainder(ulOther / GOF_PER_SEC)
646 tmp1 = rate << 16;
647 phiIncr = tmp1 / 48000;
648 tmp1 -= phiIncr * 48000;
649 tmp1 <<= 10;
650 phiIncr <<= 10;
651 tmp2 = tmp1 / 48000;
652 phiIncr += tmp2;
653 tmp1 -= tmp2 * 48000;
654 correctionPerGOF = tmp1 / GOF_PER_SEC;
655 tmp1 -= correctionPerGOF * GOF_PER_SEC;
656 correctionPerSec = tmp1;
659 struct dsp_src_task_scb src_task_scb = {
660 0x0028,0x00c8,
661 0x5555,0x0000,
662 0x0000,0x0000,
663 src_buffer_addr,1,
664 correctionPerGOF,correctionPerSec,
665 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
666 0x0000,src_delay_buffer_addr,
667 0x0,
668 0x080,(src_delay_buffer_addr + (24 * 4)),
669 0,0, /* next_scb, sub_list_ptr */
670 0,0, /* entry, this_spb */
671 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
672 src_buffer_addr << 0x10,
673 phiIncr,
675 0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left,
676 0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left
680 if (ins->s16_up == NULL) {
681 ins->s16_up = cs46xx_dsp_lookup_symbol (chip,"S16_UPSRC",
682 SYMBOL_CODE);
684 if (ins->s16_up == NULL) {
685 dev_err(chip->card->dev,
686 "dsp_spos: symbol S16_UPSRC not found\n");
687 return NULL;
691 /* clear buffers */
692 _dsp_clear_sample_buffer (chip,src_buffer_addr,8);
693 _dsp_clear_sample_buffer (chip,src_delay_buffer_addr,32);
695 if (pass_through) {
696 /* wont work with any other rate than
697 the native DSP rate */
698 snd_BUG_ON(rate != 48000);
700 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
701 dest,"DMAREADER",parent_scb,
702 scb_child_type);
703 } else {
704 scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
705 dest,ins->s16_up,parent_scb,
706 scb_child_type);
712 return scb;
715 #if 0 /* not used */
716 struct dsp_scb_descriptor *
717 cs46xx_dsp_create_filter_scb(struct snd_cs46xx * chip, char * scb_name,
718 u16 buffer_addr, u32 dest,
719 struct dsp_scb_descriptor * parent_scb,
720 int scb_child_type) {
721 struct dsp_scb_descriptor * scb;
723 struct dsp_filter_scb filter_scb = {
724 .a0_right = 0x41a9,
725 .a0_left = 0x41a9,
726 .a1_right = 0xb8e4,
727 .a1_left = 0xb8e4,
728 .a2_right = 0x3e55,
729 .a2_left = 0x3e55,
731 .filter_unused3 = 0x0000,
732 .filter_unused2 = 0x0000,
734 .output_buf_ptr = buffer_addr,
735 .init = 0x000,
737 .prev_sample_output1 = 0x00000000,
738 .prev_sample_output2 = 0x00000000,
740 .prev_sample_input1 = 0x00000000,
741 .prev_sample_input2 = 0x00000000,
743 .next_scb_ptr = 0x0000,
744 .sub_list_ptr = 0x0000,
746 .entry_point = 0x0000,
747 .spb_ptr = 0x0000,
749 .b0_right = 0x0e38,
750 .b0_left = 0x0e38,
751 .b1_right = 0x1c71,
752 .b1_left = 0x1c71,
753 .b2_right = 0x0e38,
754 .b2_left = 0x0e38,
758 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&filter_scb,
759 dest,"FILTERTASK",parent_scb,
760 scb_child_type);
762 return scb;
764 #endif /* not used */
766 struct dsp_scb_descriptor *
767 cs46xx_dsp_create_mix_only_scb(struct snd_cs46xx * chip, char * scb_name,
768 u16 mix_buffer_addr, u32 dest,
769 struct dsp_scb_descriptor * parent_scb,
770 int scb_child_type)
772 struct dsp_scb_descriptor * scb;
774 struct dsp_mix_only_scb master_mix_scb = {
775 /* 0 */ { 0,
776 /* 1 */ 0,
777 /* 2 */ mix_buffer_addr,
778 /* 3 */ 0
779 /* */ },
781 /* 4 */ 0,
782 /* 5 */ 0,
783 /* 6 */ 0,
784 /* 7 */ 0,
785 /* 8 */ 0x00000080
787 /* 9 */ 0,0,
788 /* A */ 0,0,
789 /* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
790 /* C */ (mix_buffer_addr + (16 * 4)) << 0x10,
791 /* D */ 0,
793 /* E */ 0x8000,0x8000,
794 /* F */ 0x8000,0x8000
799 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&master_mix_scb,
800 dest,"S16_MIX",parent_scb,
801 scb_child_type);
802 return scb;
806 struct dsp_scb_descriptor *
807 cs46xx_dsp_create_mix_to_ostream_scb(struct snd_cs46xx * chip, char * scb_name,
808 u16 mix_buffer_addr, u16 writeback_spb, u32 dest,
809 struct dsp_scb_descriptor * parent_scb,
810 int scb_child_type)
812 struct dsp_scb_descriptor * scb;
814 struct dsp_mix2_ostream_scb mix2_ostream_scb = {
815 /* Basic (non scatter/gather) DMA requestor (4 ints) */
817 DMA_RQ_C1_SOURCE_MOD64 +
818 DMA_RQ_C1_DEST_ON_HOST +
819 DMA_RQ_C1_DEST_MOD1024 +
820 DMA_RQ_C1_WRITEBACK_SRC_FLAG +
821 DMA_RQ_C1_WRITEBACK_DEST_FLAG +
822 15,
824 DMA_RQ_C2_AC_NONE +
825 DMA_RQ_C2_SIGNAL_DEST_PINGPONG +
827 CS46XX_DSP_CAPTURE_CHANNEL,
828 DMA_RQ_SD_SP_SAMPLE_ADDR +
829 mix_buffer_addr,
830 0x0
833 { 0, 0, 0, 0, 0, },
834 0,0,
835 0,writeback_spb,
837 RSCONFIG_DMA_ENABLE +
838 (19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) +
840 ((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) +
841 RSCONFIG_DMA_TO_HOST +
842 RSCONFIG_SAMPLE_16STEREO +
843 RSCONFIG_MODULO_64,
844 (mix_buffer_addr + (32 * 4)) << 0x10,
845 1,0,
846 0x0001,0x0080,
847 0xFFFF,0
851 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&mix2_ostream_scb,
853 dest,"S16_MIX_TO_OSTREAM",parent_scb,
854 scb_child_type);
856 return scb;
860 struct dsp_scb_descriptor *
861 cs46xx_dsp_create_vari_decimate_scb(struct snd_cs46xx * chip,char * scb_name,
862 u16 vari_buffer_addr0,
863 u16 vari_buffer_addr1,
864 u32 dest,
865 struct dsp_scb_descriptor * parent_scb,
866 int scb_child_type)
869 struct dsp_scb_descriptor * scb;
871 struct dsp_vari_decimate_scb vari_decimate_scb = {
872 0x0028,0x00c8,
873 0x5555,0x0000,
874 0x0000,0x0000,
875 vari_buffer_addr0,vari_buffer_addr1,
877 0x0028,0x00c8,
878 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256,
880 0xFF800000,
882 0x0080,vari_buffer_addr1 + (25 * 4),
884 0,0,
885 0,0,
887 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
888 vari_buffer_addr0 << 0x10,
889 0x04000000,
891 0x8000,0x8000,
892 0xFFFF,0xFFFF
896 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&vari_decimate_scb,
897 dest,"VARIDECIMATE",parent_scb,
898 scb_child_type);
900 return scb;
904 static struct dsp_scb_descriptor *
905 cs46xx_dsp_create_pcm_serial_input_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
906 struct dsp_scb_descriptor * input_scb,
907 struct dsp_scb_descriptor * parent_scb,
908 int scb_child_type)
911 struct dsp_scb_descriptor * scb;
914 struct dsp_pcm_serial_input_scb pcm_serial_input_scb = {
915 { 0,
928 0,0,
929 0,0,
931 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_16,
933 /* 0xD */ 0,input_scb->address,
935 /* 0xE */ 0x8000,0x8000,
936 /* 0xF */ 0x8000,0x8000
940 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_serial_input_scb,
941 dest,"PCMSERIALINPUTTASK",parent_scb,
942 scb_child_type);
943 return scb;
947 static struct dsp_scb_descriptor *
948 cs46xx_dsp_create_asynch_fg_tx_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
949 u16 hfg_scb_address,
950 u16 asynch_buffer_address,
951 struct dsp_scb_descriptor * parent_scb,
952 int scb_child_type)
955 struct dsp_scb_descriptor * scb;
957 struct dsp_asynch_fg_tx_scb asynch_fg_tx_scb = {
958 0xfc00,0x03ff, /* Prototype sample buffer size of 256 dwords */
959 0x0058,0x0028, /* Min Delta 7 dwords == 28 bytes */
960 /* : Max delta 25 dwords == 100 bytes */
961 0,hfg_scb_address, /* Point to HFG task SCB */
962 0,0, /* Initialize current Delta and Consumer ptr adjustment count */
963 0, /* Initialize accumulated Phi to 0 */
964 0,0x2aab, /* Const 1/3 */
967 0, /* Define the unused elements */
972 0,0,
973 0,dest + AFGTxAccumPhi,
975 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256, /* Stereo, 256 dword */
976 (asynch_buffer_address) << 0x10, /* This should be automagically synchronized
977 to the producer pointer */
979 /* There is no correct initial value, it will depend upon the detected
980 rate etc */
981 0x18000000, /* Phi increment for approx 32k operation */
982 0x8000,0x8000, /* Volume controls are unused at this time */
983 0x8000,0x8000
986 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_tx_scb,
987 dest,"ASYNCHFGTXCODE",parent_scb,
988 scb_child_type);
990 return scb;
994 struct dsp_scb_descriptor *
995 cs46xx_dsp_create_asynch_fg_rx_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
996 u16 hfg_scb_address,
997 u16 asynch_buffer_address,
998 struct dsp_scb_descriptor * parent_scb,
999 int scb_child_type)
1001 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1002 struct dsp_scb_descriptor * scb;
1004 struct dsp_asynch_fg_rx_scb asynch_fg_rx_scb = {
1005 0xfe00,0x01ff, /* Prototype sample buffer size of 128 dwords */
1006 0x0064,0x001c, /* Min Delta 7 dwords == 28 bytes */
1007 /* : Max delta 25 dwords == 100 bytes */
1008 0,hfg_scb_address, /* Point to HFG task SCB */
1009 0,0, /* Initialize current Delta and Consumer ptr adjustment count */
1011 0, /* Define the unused elements */
1018 0,0,
1019 0,dest,
1021 RSCONFIG_MODULO_128 |
1022 RSCONFIG_SAMPLE_16STEREO, /* Stereo, 128 dword */
1023 ( (asynch_buffer_address + (16 * 4)) << 0x10), /* This should be automagically
1024 synchrinized to the producer pointer */
1026 /* There is no correct initial value, it will depend upon the detected
1027 rate etc */
1028 0x18000000,
1030 /* Set IEC958 input volume */
1031 0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
1032 0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
1035 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_rx_scb,
1036 dest,"ASYNCHFGRXCODE",parent_scb,
1037 scb_child_type);
1039 return scb;
1043 #if 0 /* not used */
1044 struct dsp_scb_descriptor *
1045 cs46xx_dsp_create_output_snoop_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1046 u16 snoop_buffer_address,
1047 struct dsp_scb_descriptor * snoop_scb,
1048 struct dsp_scb_descriptor * parent_scb,
1049 int scb_child_type)
1052 struct dsp_scb_descriptor * scb;
1054 struct dsp_output_snoop_scb output_snoop_scb = {
1055 { 0, /* not used. Zero */
1061 0, /* not used. Zero */
1068 0,0,
1069 0,0,
1071 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
1072 snoop_buffer_address << 0x10,
1073 0,0,
1075 0,snoop_scb->address
1078 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&output_snoop_scb,
1079 dest,"OUTPUTSNOOP",parent_scb,
1080 scb_child_type);
1081 return scb;
1083 #endif /* not used */
1086 struct dsp_scb_descriptor *
1087 cs46xx_dsp_create_spio_write_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1088 struct dsp_scb_descriptor * parent_scb,
1089 int scb_child_type)
1091 struct dsp_scb_descriptor * scb;
1093 struct dsp_spio_write_scb spio_write_scb = {
1094 0,0, /* SPIOWAddress2:SPIOWAddress1; */
1095 0, /* SPIOWData1; */
1096 0, /* SPIOWData2; */
1097 0,0, /* SPIOWAddress4:SPIOWAddress3; */
1098 0, /* SPIOWData3; */
1099 0, /* SPIOWData4; */
1100 0,0, /* SPIOWDataPtr:Unused1; */
1101 { 0,0 }, /* Unused2[2]; */
1103 0,0, /* SPIOWChildPtr:SPIOWSiblingPtr; */
1104 0,0, /* SPIOWThisPtr:SPIOWEntryPoint; */
1111 0 /* Unused3[5]; */
1115 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&spio_write_scb,
1116 dest,"SPIOWRITE",parent_scb,
1117 scb_child_type);
1119 return scb;
1122 struct dsp_scb_descriptor *
1123 cs46xx_dsp_create_magic_snoop_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1124 u16 snoop_buffer_address,
1125 struct dsp_scb_descriptor * snoop_scb,
1126 struct dsp_scb_descriptor * parent_scb,
1127 int scb_child_type)
1129 struct dsp_scb_descriptor * scb;
1131 struct dsp_magic_snoop_task magic_snoop_scb = {
1132 /* 0 */ 0, /* i0 */
1133 /* 1 */ 0, /* i1 */
1134 /* 2 */ snoop_buffer_address << 0x10,
1135 /* 3 */ 0,snoop_scb->address,
1136 /* 4 */ 0, /* i3 */
1137 /* 5 */ 0, /* i4 */
1138 /* 6 */ 0, /* i5 */
1139 /* 7 */ 0, /* i6 */
1140 /* 8 */ 0, /* i7 */
1141 /* 9 */ 0,0, /* next_scb, sub_list_ptr */
1142 /* A */ 0,0, /* entry_point, this_ptr */
1143 /* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
1144 /* C */ snoop_buffer_address << 0x10,
1145 /* D */ 0,
1146 /* E */ { 0x8000,0x8000,
1147 /* F */ 0xffff,0xffff
1151 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&magic_snoop_scb,
1152 dest,"MAGICSNOOPTASK",parent_scb,
1153 scb_child_type);
1155 return scb;
1158 static struct dsp_scb_descriptor *
1159 find_next_free_scb (struct snd_cs46xx * chip, struct dsp_scb_descriptor * from)
1161 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1162 struct dsp_scb_descriptor * scb = from;
1164 while (scb->next_scb_ptr != ins->the_null_scb) {
1165 if (snd_BUG_ON(!scb->next_scb_ptr))
1166 return NULL;
1168 scb = scb->next_scb_ptr;
1171 return scb;
1174 static u32 pcm_reader_buffer_addr[DSP_MAX_PCM_CHANNELS] = {
1175 0x0600, /* 1 */
1176 0x1500, /* 2 */
1177 0x1580, /* 3 */
1178 0x1600, /* 4 */
1179 0x1680, /* 5 */
1180 0x1700, /* 6 */
1181 0x1780, /* 7 */
1182 0x1800, /* 8 */
1183 0x1880, /* 9 */
1184 0x1900, /* 10 */
1185 0x1980, /* 11 */
1186 0x1A00, /* 12 */
1187 0x1A80, /* 13 */
1188 0x1B00, /* 14 */
1189 0x1B80, /* 15 */
1190 0x1C00, /* 16 */
1191 0x1C80, /* 17 */
1192 0x1D00, /* 18 */
1193 0x1D80, /* 19 */
1194 0x1E00, /* 20 */
1195 0x1E80, /* 21 */
1196 0x1F00, /* 22 */
1197 0x1F80, /* 23 */
1198 0x2000, /* 24 */
1199 0x2080, /* 25 */
1200 0x2100, /* 26 */
1201 0x2180, /* 27 */
1202 0x2200, /* 28 */
1203 0x2280, /* 29 */
1204 0x2300, /* 30 */
1205 0x2380, /* 31 */
1206 0x2400, /* 32 */
1209 static u32 src_output_buffer_addr[DSP_MAX_SRC_NR] = {
1210 0x2B80,
1211 0x2BA0,
1212 0x2BC0,
1213 0x2BE0,
1214 0x2D00,
1215 0x2D20,
1216 0x2D40,
1217 0x2D60,
1218 0x2D80,
1219 0x2DA0,
1220 0x2DC0,
1221 0x2DE0,
1222 0x2E00,
1223 0x2E20
1226 static u32 src_delay_buffer_addr[DSP_MAX_SRC_NR] = {
1227 0x2480,
1228 0x2500,
1229 0x2580,
1230 0x2600,
1231 0x2680,
1232 0x2700,
1233 0x2780,
1234 0x2800,
1235 0x2880,
1236 0x2900,
1237 0x2980,
1238 0x2A00,
1239 0x2A80,
1240 0x2B00
1243 struct dsp_pcm_channel_descriptor *
1244 cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
1245 u32 sample_rate, void * private_data,
1246 u32 hw_dma_addr,
1247 int pcm_channel_id)
1249 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1250 struct dsp_scb_descriptor * src_scb = NULL, * pcm_scb, * mixer_scb = NULL;
1251 struct dsp_scb_descriptor * src_parent_scb = NULL;
1253 /* struct dsp_scb_descriptor * pcm_parent_scb; */
1254 char scb_name[DSP_MAX_SCB_NAME];
1255 int i, pcm_index = -1, insert_point, src_index = -1, pass_through = 0;
1256 unsigned long flags;
1258 switch (pcm_channel_id) {
1259 case DSP_PCM_MAIN_CHANNEL:
1260 mixer_scb = ins->master_mix_scb;
1261 break;
1262 case DSP_PCM_REAR_CHANNEL:
1263 mixer_scb = ins->rear_mix_scb;
1264 break;
1265 case DSP_PCM_CENTER_LFE_CHANNEL:
1266 mixer_scb = ins->center_lfe_mix_scb;
1267 break;
1268 case DSP_PCM_S71_CHANNEL:
1269 /* TODO */
1270 snd_BUG();
1271 break;
1272 case DSP_IEC958_CHANNEL:
1273 if (snd_BUG_ON(!ins->asynch_tx_scb))
1274 return NULL;
1275 mixer_scb = ins->asynch_tx_scb;
1277 /* if sample rate is set to 48khz we pass
1278 the Sample Rate Converted (which could
1279 alter the raw data stream ...) */
1280 if (sample_rate == 48000) {
1281 dev_dbg(chip->card->dev, "IEC958 pass through\n");
1282 /* Hack to bypass creating a new SRC */
1283 pass_through = 1;
1285 break;
1286 default:
1287 snd_BUG();
1288 return NULL;
1290 /* default sample rate is 44100 */
1291 if (!sample_rate) sample_rate = 44100;
1293 /* search for a already created SRC SCB with the same sample rate */
1294 for (i = 0; i < DSP_MAX_PCM_CHANNELS &&
1295 (pcm_index == -1 || src_scb == NULL); ++i) {
1297 /* virtual channel reserved
1298 for capture */
1299 if (i == CS46XX_DSP_CAPTURE_CHANNEL) continue;
1301 if (ins->pcm_channels[i].active) {
1302 if (!src_scb &&
1303 ins->pcm_channels[i].sample_rate == sample_rate &&
1304 ins->pcm_channels[i].mixer_scb == mixer_scb) {
1305 src_scb = ins->pcm_channels[i].src_scb;
1306 ins->pcm_channels[i].src_scb->ref_count ++;
1307 src_index = ins->pcm_channels[i].src_slot;
1309 } else if (pcm_index == -1) {
1310 pcm_index = i;
1314 if (pcm_index == -1) {
1315 dev_err(chip->card->dev, "dsp_spos: no free PCM channel\n");
1316 return NULL;
1319 if (src_scb == NULL) {
1320 if (ins->nsrc_scb >= DSP_MAX_SRC_NR) {
1321 dev_err(chip->card->dev,
1322 "dsp_spos: to many SRC instances\n!");
1323 return NULL;
1326 /* find a free slot */
1327 for (i = 0; i < DSP_MAX_SRC_NR; ++i) {
1328 if (ins->src_scb_slots[i] == 0) {
1329 src_index = i;
1330 ins->src_scb_slots[i] = 1;
1331 break;
1334 if (snd_BUG_ON(src_index == -1))
1335 return NULL;
1337 /* we need to create a new SRC SCB */
1338 if (mixer_scb->sub_list_ptr == ins->the_null_scb) {
1339 src_parent_scb = mixer_scb;
1340 insert_point = SCB_ON_PARENT_SUBLIST_SCB;
1341 } else {
1342 src_parent_scb = find_next_free_scb(chip,mixer_scb->sub_list_ptr);
1343 insert_point = SCB_ON_PARENT_NEXT_SCB;
1346 snprintf (scb_name,DSP_MAX_SCB_NAME,"SrcTask_SCB%d",src_index);
1348 dev_dbg(chip->card->dev,
1349 "dsp_spos: creating SRC \"%s\"\n", scb_name);
1350 src_scb = cs46xx_dsp_create_src_task_scb(chip,scb_name,
1351 sample_rate,
1352 src_output_buffer_addr[src_index],
1353 src_delay_buffer_addr[src_index],
1354 /* 0x400 - 0x600 source SCBs */
1355 0x400 + (src_index * 0x10) ,
1356 src_parent_scb,
1357 insert_point,
1358 pass_through);
1360 if (!src_scb) {
1361 dev_err(chip->card->dev,
1362 "dsp_spos: failed to create SRCtaskSCB\n");
1363 return NULL;
1366 /* cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate); */
1368 ins->nsrc_scb ++;
1372 snprintf (scb_name,DSP_MAX_SCB_NAME,"PCMReader_SCB%d",pcm_index);
1374 dev_dbg(chip->card->dev, "dsp_spos: creating PCM \"%s\" (%d)\n",
1375 scb_name, pcm_channel_id);
1377 pcm_scb = cs46xx_dsp_create_pcm_reader_scb(chip,scb_name,
1378 pcm_reader_buffer_addr[pcm_index],
1379 /* 0x200 - 400 PCMreader SCBs */
1380 (pcm_index * 0x10) + 0x200,
1381 pcm_index, /* virtual channel 0-31 */
1382 hw_dma_addr, /* pcm hw addr */
1383 NULL, /* parent SCB ptr */
1384 0 /* insert point */
1387 if (!pcm_scb) {
1388 dev_err(chip->card->dev,
1389 "dsp_spos: failed to create PCMreaderSCB\n");
1390 return NULL;
1393 spin_lock_irqsave(&chip->reg_lock, flags);
1394 ins->pcm_channels[pcm_index].sample_rate = sample_rate;
1395 ins->pcm_channels[pcm_index].pcm_reader_scb = pcm_scb;
1396 ins->pcm_channels[pcm_index].src_scb = src_scb;
1397 ins->pcm_channels[pcm_index].unlinked = 1;
1398 ins->pcm_channels[pcm_index].private_data = private_data;
1399 ins->pcm_channels[pcm_index].src_slot = src_index;
1400 ins->pcm_channels[pcm_index].active = 1;
1401 ins->pcm_channels[pcm_index].pcm_slot = pcm_index;
1402 ins->pcm_channels[pcm_index].mixer_scb = mixer_scb;
1403 ins->npcm_channels ++;
1404 spin_unlock_irqrestore(&chip->reg_lock, flags);
1406 return (ins->pcm_channels + pcm_index);
1409 int cs46xx_dsp_pcm_channel_set_period (struct snd_cs46xx * chip,
1410 struct dsp_pcm_channel_descriptor * pcm_channel,
1411 int period_size)
1413 u32 temp = snd_cs46xx_peek (chip,pcm_channel->pcm_reader_scb->address << 2);
1414 temp &= ~DMA_RQ_C1_SOURCE_SIZE_MASK;
1416 switch (period_size) {
1417 case 2048:
1418 temp |= DMA_RQ_C1_SOURCE_MOD1024;
1419 break;
1420 case 1024:
1421 temp |= DMA_RQ_C1_SOURCE_MOD512;
1422 break;
1423 case 512:
1424 temp |= DMA_RQ_C1_SOURCE_MOD256;
1425 break;
1426 case 256:
1427 temp |= DMA_RQ_C1_SOURCE_MOD128;
1428 break;
1429 case 128:
1430 temp |= DMA_RQ_C1_SOURCE_MOD64;
1431 break;
1432 case 64:
1433 temp |= DMA_RQ_C1_SOURCE_MOD32;
1434 break;
1435 case 32:
1436 temp |= DMA_RQ_C1_SOURCE_MOD16;
1437 break;
1438 default:
1439 dev_dbg(chip->card->dev,
1440 "period size (%d) not supported by HW\n", period_size);
1441 return -EINVAL;
1444 snd_cs46xx_poke (chip,pcm_channel->pcm_reader_scb->address << 2,temp);
1446 return 0;
1449 int cs46xx_dsp_pcm_ostream_set_period (struct snd_cs46xx * chip,
1450 int period_size)
1452 u32 temp = snd_cs46xx_peek (chip,WRITEBACK_SCB_ADDR << 2);
1453 temp &= ~DMA_RQ_C1_DEST_SIZE_MASK;
1455 switch (period_size) {
1456 case 2048:
1457 temp |= DMA_RQ_C1_DEST_MOD1024;
1458 break;
1459 case 1024:
1460 temp |= DMA_RQ_C1_DEST_MOD512;
1461 break;
1462 case 512:
1463 temp |= DMA_RQ_C1_DEST_MOD256;
1464 break;
1465 case 256:
1466 temp |= DMA_RQ_C1_DEST_MOD128;
1467 break;
1468 case 128:
1469 temp |= DMA_RQ_C1_DEST_MOD64;
1470 break;
1471 case 64:
1472 temp |= DMA_RQ_C1_DEST_MOD32;
1473 break;
1474 case 32:
1475 temp |= DMA_RQ_C1_DEST_MOD16;
1476 break;
1477 default:
1478 dev_dbg(chip->card->dev,
1479 "period size (%d) not supported by HW\n", period_size);
1480 return -EINVAL;
1483 snd_cs46xx_poke (chip,WRITEBACK_SCB_ADDR << 2,temp);
1485 return 0;
1488 void cs46xx_dsp_destroy_pcm_channel (struct snd_cs46xx * chip,
1489 struct dsp_pcm_channel_descriptor * pcm_channel)
1491 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1492 unsigned long flags;
1494 if (snd_BUG_ON(!pcm_channel->active ||
1495 ins->npcm_channels <= 0 ||
1496 pcm_channel->src_scb->ref_count <= 0))
1497 return;
1499 spin_lock_irqsave(&chip->reg_lock, flags);
1500 pcm_channel->unlinked = 1;
1501 pcm_channel->active = 0;
1502 pcm_channel->private_data = NULL;
1503 pcm_channel->src_scb->ref_count --;
1504 ins->npcm_channels --;
1505 spin_unlock_irqrestore(&chip->reg_lock, flags);
1507 cs46xx_dsp_remove_scb(chip,pcm_channel->pcm_reader_scb);
1509 if (!pcm_channel->src_scb->ref_count) {
1510 cs46xx_dsp_remove_scb(chip,pcm_channel->src_scb);
1512 if (snd_BUG_ON(pcm_channel->src_slot < 0 ||
1513 pcm_channel->src_slot >= DSP_MAX_SRC_NR))
1514 return;
1516 ins->src_scb_slots[pcm_channel->src_slot] = 0;
1517 ins->nsrc_scb --;
1521 int cs46xx_dsp_pcm_unlink (struct snd_cs46xx * chip,
1522 struct dsp_pcm_channel_descriptor * pcm_channel)
1524 unsigned long flags;
1526 if (snd_BUG_ON(!pcm_channel->active ||
1527 chip->dsp_spos_instance->npcm_channels <= 0))
1528 return -EIO;
1530 spin_lock_irqsave(&chip->reg_lock, flags);
1531 if (pcm_channel->unlinked) {
1532 spin_unlock_irqrestore(&chip->reg_lock, flags);
1533 return -EIO;
1536 pcm_channel->unlinked = 1;
1538 _dsp_unlink_scb (chip,pcm_channel->pcm_reader_scb);
1539 spin_unlock_irqrestore(&chip->reg_lock, flags);
1541 return 0;
1544 int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip,
1545 struct dsp_pcm_channel_descriptor * pcm_channel)
1547 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1548 struct dsp_scb_descriptor * parent_scb;
1549 struct dsp_scb_descriptor * src_scb = pcm_channel->src_scb;
1550 unsigned long flags;
1552 spin_lock_irqsave(&chip->reg_lock, flags);
1554 if (pcm_channel->unlinked == 0) {
1555 spin_unlock_irqrestore(&chip->reg_lock, flags);
1556 return -EIO;
1559 parent_scb = src_scb;
1561 if (src_scb->sub_list_ptr != ins->the_null_scb) {
1562 src_scb->sub_list_ptr->parent_scb_ptr = pcm_channel->pcm_reader_scb;
1563 pcm_channel->pcm_reader_scb->next_scb_ptr = src_scb->sub_list_ptr;
1566 src_scb->sub_list_ptr = pcm_channel->pcm_reader_scb;
1568 snd_BUG_ON(pcm_channel->pcm_reader_scb->parent_scb_ptr);
1569 pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb;
1571 /* update SCB entry in DSP RAM */
1572 cs46xx_dsp_spos_update_scb(chip,pcm_channel->pcm_reader_scb);
1574 /* update parent SCB entry */
1575 cs46xx_dsp_spos_update_scb(chip,parent_scb);
1577 pcm_channel->unlinked = 0;
1578 spin_unlock_irqrestore(&chip->reg_lock, flags);
1579 return 0;
1582 struct dsp_scb_descriptor *
1583 cs46xx_add_record_source (struct snd_cs46xx *chip, struct dsp_scb_descriptor * source,
1584 u16 addr, char * scb_name)
1586 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1587 struct dsp_scb_descriptor * parent;
1588 struct dsp_scb_descriptor * pcm_input;
1589 int insert_point;
1591 if (snd_BUG_ON(!ins->record_mixer_scb))
1592 return NULL;
1594 if (ins->record_mixer_scb->sub_list_ptr != ins->the_null_scb) {
1595 parent = find_next_free_scb (chip,ins->record_mixer_scb->sub_list_ptr);
1596 insert_point = SCB_ON_PARENT_NEXT_SCB;
1597 } else {
1598 parent = ins->record_mixer_scb;
1599 insert_point = SCB_ON_PARENT_SUBLIST_SCB;
1602 pcm_input = cs46xx_dsp_create_pcm_serial_input_scb(chip,scb_name,addr,
1603 source, parent,
1604 insert_point);
1606 return pcm_input;
1609 int cs46xx_src_unlink(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
1611 unsigned long flags;
1613 if (snd_BUG_ON(!src->parent_scb_ptr))
1614 return -EINVAL;
1616 /* mute SCB */
1617 cs46xx_dsp_scb_set_volume (chip,src,0,0);
1619 spin_lock_irqsave(&chip->reg_lock, flags);
1620 _dsp_unlink_scb (chip,src);
1621 spin_unlock_irqrestore(&chip->reg_lock, flags);
1623 return 0;
1626 int cs46xx_src_link(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
1628 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1629 struct dsp_scb_descriptor * parent_scb;
1631 if (snd_BUG_ON(src->parent_scb_ptr))
1632 return -EINVAL;
1633 if (snd_BUG_ON(!ins->master_mix_scb))
1634 return -EINVAL;
1636 if (ins->master_mix_scb->sub_list_ptr != ins->the_null_scb) {
1637 parent_scb = find_next_free_scb (chip,ins->master_mix_scb->sub_list_ptr);
1638 parent_scb->next_scb_ptr = src;
1639 } else {
1640 parent_scb = ins->master_mix_scb;
1641 parent_scb->sub_list_ptr = src;
1644 src->parent_scb_ptr = parent_scb;
1646 /* update entry in DSP RAM */
1647 cs46xx_dsp_spos_update_scb(chip,parent_scb);
1649 return 0;
1652 int cs46xx_dsp_enable_spdif_out (struct snd_cs46xx *chip)
1654 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1656 if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
1657 cs46xx_dsp_enable_spdif_hw (chip);
1660 /* dont touch anything if SPDIF is open */
1661 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
1662 /* when cs46xx_iec958_post_close(...) is called it
1663 will call this function if necessary depending on
1664 this bit */
1665 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1667 return -EBUSY;
1670 if (snd_BUG_ON(ins->asynch_tx_scb))
1671 return -EINVAL;
1672 if (snd_BUG_ON(ins->master_mix_scb->next_scb_ptr !=
1673 ins->the_null_scb))
1674 return -EINVAL;
1676 /* reset output snooper sample buffer pointer */
1677 snd_cs46xx_poke (chip, (ins->ref_snoop_scb->address + 2) << 2,
1678 (OUTPUT_SNOOP_BUFFER + 0x10) << 0x10 );
1680 /* The asynch. transfer task */
1681 ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
1682 SPDIFO_SCB_INST,
1683 SPDIFO_IP_OUTPUT_BUFFER1,
1684 ins->master_mix_scb,
1685 SCB_ON_PARENT_NEXT_SCB);
1686 if (!ins->asynch_tx_scb) return -ENOMEM;
1688 ins->spdif_pcm_input_scb = cs46xx_dsp_create_pcm_serial_input_scb(chip,"PCMSerialInput_II",
1689 PCMSERIALINII_SCB_ADDR,
1690 ins->ref_snoop_scb,
1691 ins->asynch_tx_scb,
1692 SCB_ON_PARENT_SUBLIST_SCB);
1695 if (!ins->spdif_pcm_input_scb) return -ENOMEM;
1697 /* monitor state */
1698 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1700 return 0;
1703 int cs46xx_dsp_disable_spdif_out (struct snd_cs46xx *chip)
1705 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1707 /* dont touch anything if SPDIF is open */
1708 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
1709 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1710 return -EBUSY;
1713 /* check integrety */
1714 if (snd_BUG_ON(!ins->asynch_tx_scb))
1715 return -EINVAL;
1716 if (snd_BUG_ON(!ins->spdif_pcm_input_scb))
1717 return -EINVAL;
1718 if (snd_BUG_ON(ins->master_mix_scb->next_scb_ptr != ins->asynch_tx_scb))
1719 return -EINVAL;
1720 if (snd_BUG_ON(ins->asynch_tx_scb->parent_scb_ptr !=
1721 ins->master_mix_scb))
1722 return -EINVAL;
1724 cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
1725 cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
1727 ins->spdif_pcm_input_scb = NULL;
1728 ins->asynch_tx_scb = NULL;
1730 /* clear buffer to prevent any undesired noise */
1731 _dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
1733 /* monitor state */
1734 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1737 return 0;
1740 int cs46xx_iec958_pre_open (struct snd_cs46xx *chip)
1742 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1744 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
1745 /* remove AsynchFGTxSCB and and PCMSerialInput_II */
1746 cs46xx_dsp_disable_spdif_out (chip);
1748 /* save state */
1749 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1752 /* if not enabled already */
1753 if ( !(ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
1754 cs46xx_dsp_enable_spdif_hw (chip);
1757 /* Create the asynch. transfer task for playback */
1758 ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
1759 SPDIFO_SCB_INST,
1760 SPDIFO_IP_OUTPUT_BUFFER1,
1761 ins->master_mix_scb,
1762 SCB_ON_PARENT_NEXT_SCB);
1765 /* set spdif channel status value for streaming */
1766 cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_stream);
1768 ins->spdif_status_out |= DSP_SPDIF_STATUS_PLAYBACK_OPEN;
1770 return 0;
1773 int cs46xx_iec958_post_close (struct snd_cs46xx *chip)
1775 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1777 if (snd_BUG_ON(!ins->asynch_tx_scb))
1778 return -EINVAL;
1780 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_PLAYBACK_OPEN;
1782 /* restore settings */
1783 cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);
1785 /* deallocate stuff */
1786 if (ins->spdif_pcm_input_scb != NULL) {
1787 cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
1788 ins->spdif_pcm_input_scb = NULL;
1791 cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
1792 ins->asynch_tx_scb = NULL;
1794 /* clear buffer to prevent any undesired noise */
1795 _dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
1797 /* restore state */
1798 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
1799 cs46xx_dsp_enable_spdif_out (chip);
1802 return 0;