1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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>
30
31#include <sound/core.h>
32#include <sound/control.h>
33#include <sound/info.h>
34#include <sound/cs46xx.h>
35
36#include "cs46xx_lib.h"
37#include "dsp_spos.h"
38
39struct proc_scb_info {
40 struct dsp_scb_descriptor * scb_desc;
41 struct snd_cs46xx *chip;
42};
43
44static void remove_symbol (struct snd_cs46xx * chip, struct dsp_symbol_entry * symbol)
45{
46 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
47 int symbol_index = (int)(symbol - ins->symbol_table.symbols);
48
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;
54
55 ins->symbol_table.symbols[symbol_index].deleted = 1;
56
57 if (symbol_index < ins->symbol_table.highest_frag_index) {
58 ins->symbol_table.highest_frag_index = symbol_index;
59 }
60
61 if (symbol_index == ins->symbol_table.nsymbols - 1)
62 ins->symbol_table.nsymbols --;
63
64 if (ins->symbol_table.highest_frag_index > ins->symbol_table.nsymbols) {
65 ins->symbol_table.highest_frag_index = ins->symbol_table.nsymbols;
66 }
67
68}
69
70#ifdef CONFIG_PROC_FS
71static void cs46xx_dsp_proc_scb_info_read (struct snd_info_entry *entry,
72 struct snd_info_buffer *buffer)
73{
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;
80
81 ins = chip->dsp_spos_instance;
82
83 mutex_lock(&chip->spos_mutex);
84 snd_iprintf(buffer,"%04x %s:\n",scb->address,scb->scb_name);
85
86 for (col = 0,j = 0;j < 0x10; j++,col++) {
87 if (col == 4) {
88 snd_iprintf(buffer,"\n");
89 col = 0;
90 }
91 snd_iprintf(buffer,"%08x ",readl(dst + (scb->address + j) * sizeof(u32)));
92 }
93
94 snd_iprintf(buffer,"\n");
95
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] ");
101
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);
109
110 snd_iprintf(buffer,"index [%d] ref_count [%d]\n",scb->index,scb->ref_count);
111 mutex_unlock(&chip->spos_mutex);
112}
113#endif
114
115static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
116{
117 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
118
119 if ( scb->parent_scb_ptr ) {
120
121 if (snd_BUG_ON(scb->parent_scb_ptr->sub_list_ptr != scb &&
122 scb->parent_scb_ptr->next_scb_ptr != scb))
123 return;
124
125 if (scb->parent_scb_ptr->sub_list_ptr == scb) {
126
127 if (scb->next_scb_ptr == ins->the_null_scb) {
128
129 scb->parent_scb_ptr->sub_list_ptr = scb->sub_list_ptr;
130
131 if (scb->sub_list_ptr != ins->the_null_scb) {
132 scb->sub_list_ptr->parent_scb_ptr = scb->parent_scb_ptr;
133 }
134 scb->sub_list_ptr = ins->the_null_scb;
135 } else {
136
137 scb->parent_scb_ptr->sub_list_ptr = scb->next_scb_ptr;
138
139 if (scb->next_scb_ptr != ins->the_null_scb) {
140
141 scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
142 }
143 scb->next_scb_ptr = ins->the_null_scb;
144 }
145 } else {
146 scb->parent_scb_ptr->next_scb_ptr = scb->next_scb_ptr;
147
148 if (scb->next_scb_ptr != ins->the_null_scb) {
149
150 scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
151 }
152 scb->next_scb_ptr = ins->the_null_scb;
153 }
154
155
156 cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
157
158
159 cs46xx_dsp_spos_update_scb(chip,scb);
160
161 scb->parent_scb_ptr = NULL;
162 }
163}
164
165static void _dsp_clear_sample_buffer (struct snd_cs46xx *chip, u32 sample_buffer_addr,
166 int dword_count)
167{
168 void __iomem *dst = chip->region.idx[2].remap_addr + sample_buffer_addr;
169 int i;
170
171 for (i = 0; i < dword_count ; ++i ) {
172 writel(0, dst);
173 dst += 4;
174 }
175}
176
177void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
178{
179 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
180 unsigned long flags;
181
182
183 if (snd_BUG_ON(scb->index < 0 ||
184 scb->index >= ins->nscb ||
185 (ins->scbs + scb->index) != scb))
186 return;
187
188#if 0
189
190
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
195
196 spin_lock_irqsave(&chip->reg_lock, flags);
197 _dsp_unlink_scb (chip,scb);
198 spin_unlock_irqrestore(&chip->reg_lock, flags);
199
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);
204
205 ins->scbs[scb->index].deleted = 1;
206#ifdef CONFIG_PM
207 kfree(ins->scbs[scb->index].data);
208 ins->scbs[scb->index].data = NULL;
209#endif
210
211 if (scb->index < ins->scb_highest_frag_index)
212 ins->scb_highest_frag_index = scb->index;
213
214 if (scb->index == ins->nscb - 1) {
215 ins->nscb --;
216 }
217
218 if (ins->scb_highest_frag_index > ins->nscb) {
219 ins->scb_highest_frag_index = ins->nscb;
220 }
221
222#if 0
223
224 for(i = scb->index + 1;i < ins->nscb; ++i) {
225 ins->scbs[i - 1].index = i - 1;
226 }
227#endif
228}
229
230
231#ifdef CONFIG_PROC_FS
232void cs46xx_dsp_proc_free_scb_desc (struct dsp_scb_descriptor * scb)
233{
234 if (scb->proc_info) {
235 struct proc_scb_info * scb_info = scb->proc_info->private_data;
236
237 snd_printdd("cs46xx_dsp_proc_free_scb_desc: freeing %s\n",scb->scb_name);
238
239 snd_info_free_entry(scb->proc_info);
240 scb->proc_info = NULL;
241
242 kfree (scb_info);
243 }
244}
245
246void cs46xx_dsp_proc_register_scb_desc (struct snd_cs46xx *chip,
247 struct dsp_scb_descriptor * scb)
248{
249 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
250 struct snd_info_entry * entry;
251 struct proc_scb_info * scb_info;
252
253
254 if (ins->snd_card != NULL && ins->proc_dsp_dir != NULL &&
255 scb->proc_info == NULL) {
256
257 if ((entry = snd_info_create_card_entry(ins->snd_card, scb->scb_name,
258 ins->proc_dsp_dir)) != NULL) {
259 scb_info = kmalloc(sizeof(struct proc_scb_info), GFP_KERNEL);
260 if (!scb_info) {
261 snd_info_free_entry(entry);
262 entry = NULL;
263 goto out;
264 }
265
266 scb_info->chip = chip;
267 scb_info->scb_desc = scb;
268
269 entry->content = SNDRV_INFO_CONTENT_TEXT;
270 entry->private_data = scb_info;
271 entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
272
273 entry->c.text.read = cs46xx_dsp_proc_scb_info_read;
274
275 if (snd_info_register(entry) < 0) {
276 snd_info_free_entry(entry);
277 kfree (scb_info);
278 entry = NULL;
279 }
280 }
281out:
282 scb->proc_info = entry;
283 }
284}
285#endif
286
287static struct dsp_scb_descriptor *
288_dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32 dest,
289 struct dsp_symbol_entry * task_entry,
290 struct dsp_scb_descriptor * parent_scb,
291 int scb_child_type)
292{
293 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
294 struct dsp_scb_descriptor * scb;
295
296 unsigned long flags;
297
298 if (snd_BUG_ON(!ins->the_null_scb))
299 return NULL;
300
301
302 scb_data[SCBsubListPtr] =
303 (ins->the_null_scb->address << 0x10) | ins->the_null_scb->address;
304
305 scb_data[SCBfuncEntryPtr] &= 0xFFFF0000;
306 scb_data[SCBfuncEntryPtr] |= task_entry->address;
307
308 snd_printdd("dsp_spos: creating SCB <%s>\n",name);
309
310 scb = cs46xx_dsp_create_scb(chip,name,scb_data,dest);
311
312
313 scb->sub_list_ptr = ins->the_null_scb;
314 scb->next_scb_ptr = ins->the_null_scb;
315
316 scb->parent_scb_ptr = parent_scb;
317 scb->task_entry = task_entry;
318
319
320
321 if (scb->parent_scb_ptr) {
322#if 0
323 printk ("scb->parent_scb_ptr = %s\n",scb->parent_scb_ptr->scb_name);
324 printk ("scb->parent_scb_ptr->next_scb_ptr = %s\n",scb->parent_scb_ptr->next_scb_ptr->scb_name);
325 printk ("scb->parent_scb_ptr->sub_list_ptr = %s\n",scb->parent_scb_ptr->sub_list_ptr->scb_name);
326#endif
327
328 if (scb_child_type == SCB_ON_PARENT_NEXT_SCB) {
329 if (snd_BUG_ON(scb->parent_scb_ptr->next_scb_ptr !=
330 ins->the_null_scb))
331 return NULL;
332
333 scb->parent_scb_ptr->next_scb_ptr = scb;
334
335 } else if (scb_child_type == SCB_ON_PARENT_SUBLIST_SCB) {
336 if (snd_BUG_ON(scb->parent_scb_ptr->sub_list_ptr !=
337 ins->the_null_scb))
338 return NULL;
339
340 scb->parent_scb_ptr->sub_list_ptr = scb;
341 } else {
342 snd_BUG();
343 }
344
345 spin_lock_irqsave(&chip->reg_lock, flags);
346
347
348 cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
349
350 spin_unlock_irqrestore(&chip->reg_lock, flags);
351 }
352
353
354 cs46xx_dsp_proc_register_scb_desc (chip,scb);
355
356 return scb;
357}
358
359static struct dsp_scb_descriptor *
360cs46xx_dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data,
361 u32 dest, char * task_entry_name,
362 struct dsp_scb_descriptor * parent_scb,
363 int scb_child_type)
364{
365 struct dsp_symbol_entry * task_entry;
366
367 task_entry = cs46xx_dsp_lookup_symbol (chip,task_entry_name,
368 SYMBOL_CODE);
369
370 if (task_entry == NULL) {
371 snd_printk (KERN_ERR "dsp_spos: symbol %s not found\n",task_entry_name);
372 return NULL;
373 }
374
375 return _dsp_create_generic_scb (chip,name,scb_data,dest,task_entry,
376 parent_scb,scb_child_type);
377}
378
379struct dsp_scb_descriptor *
380cs46xx_dsp_create_timing_master_scb (struct snd_cs46xx *chip)
381{
382 struct dsp_scb_descriptor * scb;
383
384 struct dsp_timing_master_scb timing_master_scb = {
385 { 0,
386 0,
387 0,
388 0
389 },
390 { 0,
391 0,
392 0,
393 0,
394 0
395 },
396 0,0,
397 0,NULL_SCB_ADDR,
398 0,0,
399 0,0,
400 0x0001,0x8000,
401 0x0001,0x0000,
402 0x00060000
403 };
404
405 scb = cs46xx_dsp_create_generic_scb(chip,"TimingMasterSCBInst",(u32 *)&timing_master_scb,
406 TIMINGMASTER_SCB_ADDR,
407 "TIMINGMASTER",NULL,SCB_NO_PARENT);
408
409 return scb;
410}
411
412
413struct dsp_scb_descriptor *
414cs46xx_dsp_create_codec_out_scb(struct snd_cs46xx * chip, char * codec_name,
415 u16 channel_disp, u16 fifo_addr, u16 child_scb_addr,
416 u32 dest, struct dsp_scb_descriptor * parent_scb,
417 int scb_child_type)
418{
419 struct dsp_scb_descriptor * scb;
420
421 struct dsp_codec_output_scb codec_out_scb = {
422 { 0,
423 0,
424 0,
425 0
426 },
427 {
428 0,
429 0,
430 0,
431 0,
432 0
433 },
434 0,0,
435 0,NULL_SCB_ADDR,
436 0,
437 0,
438 channel_disp,fifo_addr,
439 0x0000,0x0080,
440 0,child_scb_addr
441 };
442
443
444 scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_out_scb,
445 dest,"S16_CODECOUTPUTTASK",parent_scb,
446 scb_child_type);
447
448 return scb;
449}
450
451struct dsp_scb_descriptor *
452cs46xx_dsp_create_codec_in_scb(struct snd_cs46xx * chip, char * codec_name,
453 u16 channel_disp, u16 fifo_addr, u16 sample_buffer_addr,
454 u32 dest, struct dsp_scb_descriptor * parent_scb,
455 int scb_child_type)
456{
457
458 struct dsp_scb_descriptor * scb;
459 struct dsp_codec_input_scb codec_input_scb = {
460 { 0,
461 0,
462 0,
463 0
464 },
465 {
466 0,
467 0,
468 0,
469 0,
470 0
471 },
472
473#if 0
474 SyncIOSCB,NULL_SCB_ADDR
475#else
476 0 , 0,
477#endif
478 0,0,
479
480 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
481 sample_buffer_addr << 0x10,
482 channel_disp,fifo_addr,
483
484 0x0000,0x0000,
485
486 0x80008000
487 };
488
489 scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_input_scb,
490 dest,"S16_CODECINPUTTASK",parent_scb,
491 scb_child_type);
492 return scb;
493}
494
495
496static struct dsp_scb_descriptor *
497cs46xx_dsp_create_pcm_reader_scb(struct snd_cs46xx * chip, char * scb_name,
498 u16 sample_buffer_addr, u32 dest,
499 int virtual_channel, u32 playback_hw_addr,
500 struct dsp_scb_descriptor * parent_scb,
501 int scb_child_type)
502{
503 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
504 struct dsp_scb_descriptor * scb;
505
506 struct dsp_generic_scb pcm_reader_scb = {
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532 { DMA_RQ_C1_SOURCE_ON_HOST +
533 DMA_RQ_C1_SOURCE_MOD1024 +
534 DMA_RQ_C1_DEST_MOD32 +
535 DMA_RQ_C1_WRITEBACK_SRC_FLAG +
536 DMA_RQ_C1_WRITEBACK_DEST_FLAG +
537 15,
538
539
540 DMA_RQ_C2_AC_NONE +
541 DMA_RQ_C2_SIGNAL_SOURCE_PINGPONG +
542
543 virtual_channel,
544 playback_hw_addr,
545 DMA_RQ_SD_SP_SAMPLE_ADDR +
546 sample_buffer_addr
547 },
548
549 {
550 0,
551 0,
552 0,
553 0,
554 0
555 },
556
557 NULL_SCB_ADDR,NULL_SCB_ADDR,
558
559 0,NULL_SCB_ADDR,
560
561
562 RSCONFIG_DMA_ENABLE +
563 (19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) +
564
565 ((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) +
566 RSCONFIG_SAMPLE_16STEREO +
567 RSCONFIG_MODULO_32,
568
569 (sample_buffer_addr << 0x10),
570
571 0,
572 {
573
574
575 0xffff,0xffff,
576 0xffff,0xffff
577 }
578 };
579
580 if (ins->null_algorithm == NULL) {
581 ins->null_algorithm = cs46xx_dsp_lookup_symbol (chip,"NULLALGORITHM",
582 SYMBOL_CODE);
583
584 if (ins->null_algorithm == NULL) {
585 snd_printk (KERN_ERR "dsp_spos: symbol NULLALGORITHM not found\n");
586 return NULL;
587 }
588 }
589
590 scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_reader_scb,
591 dest,ins->null_algorithm,parent_scb,
592 scb_child_type);
593
594 return scb;
595}
596
597#define GOF_PER_SEC 200
598
599struct dsp_scb_descriptor *
600cs46xx_dsp_create_src_task_scb(struct snd_cs46xx * chip, char * scb_name,
601 int rate,
602 u16 src_buffer_addr,
603 u16 src_delay_buffer_addr, u32 dest,
604 struct dsp_scb_descriptor * parent_scb,
605 int scb_child_type,
606 int pass_through)
607{
608
609 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
610 struct dsp_scb_descriptor * scb;
611 unsigned int tmp1, tmp2;
612 unsigned int phiIncr;
613 unsigned int correctionPerGOF, correctionPerSec;
614
615 snd_printdd( "dsp_spos: setting %s rate to %u\n",scb_name,rate);
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634 tmp1 = rate << 16;
635 phiIncr = tmp1 / 48000;
636 tmp1 -= phiIncr * 48000;
637 tmp1 <<= 10;
638 phiIncr <<= 10;
639 tmp2 = tmp1 / 48000;
640 phiIncr += tmp2;
641 tmp1 -= tmp2 * 48000;
642 correctionPerGOF = tmp1 / GOF_PER_SEC;
643 tmp1 -= correctionPerGOF * GOF_PER_SEC;
644 correctionPerSec = tmp1;
645
646 {
647 struct dsp_src_task_scb src_task_scb = {
648 0x0028,0x00c8,
649 0x5555,0x0000,
650 0x0000,0x0000,
651 src_buffer_addr,1,
652 correctionPerGOF,correctionPerSec,
653 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
654 0x0000,src_delay_buffer_addr,
655 0x0,
656 0x080,(src_delay_buffer_addr + (24 * 4)),
657 0,0,
658 0,0,
659 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
660 src_buffer_addr << 0x10,
661 phiIncr,
662 {
663 0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left,
664 0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left
665 }
666 };
667
668 if (ins->s16_up == NULL) {
669 ins->s16_up = cs46xx_dsp_lookup_symbol (chip,"S16_UPSRC",
670 SYMBOL_CODE);
671
672 if (ins->s16_up == NULL) {
673 snd_printk (KERN_ERR "dsp_spos: symbol S16_UPSRC not found\n");
674 return NULL;
675 }
676 }
677
678
679 _dsp_clear_sample_buffer (chip,src_buffer_addr,8);
680 _dsp_clear_sample_buffer (chip,src_delay_buffer_addr,32);
681
682 if (pass_through) {
683
684
685 snd_BUG_ON(rate != 48000);
686
687 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
688 dest,"DMAREADER",parent_scb,
689 scb_child_type);
690 } else {
691 scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
692 dest,ins->s16_up,parent_scb,
693 scb_child_type);
694 }
695
696
697 }
698
699 return scb;
700}
701
702#if 0
703struct dsp_scb_descriptor *
704cs46xx_dsp_create_filter_scb(struct snd_cs46xx * chip, char * scb_name,
705 u16 buffer_addr, u32 dest,
706 struct dsp_scb_descriptor * parent_scb,
707 int scb_child_type) {
708 struct dsp_scb_descriptor * scb;
709
710 struct dsp_filter_scb filter_scb = {
711 .a0_right = 0x41a9,
712 .a0_left = 0x41a9,
713 .a1_right = 0xb8e4,
714 .a1_left = 0xb8e4,
715 .a2_right = 0x3e55,
716 .a2_left = 0x3e55,
717
718 .filter_unused3 = 0x0000,
719 .filter_unused2 = 0x0000,
720
721 .output_buf_ptr = buffer_addr,
722 .init = 0x000,
723
724 .prev_sample_output1 = 0x00000000,
725 .prev_sample_output2 = 0x00000000,
726
727 .prev_sample_input1 = 0x00000000,
728 .prev_sample_input2 = 0x00000000,
729
730 .next_scb_ptr = 0x0000,
731 .sub_list_ptr = 0x0000,
732
733 .entry_point = 0x0000,
734 .spb_ptr = 0x0000,
735
736 .b0_right = 0x0e38,
737 .b0_left = 0x0e38,
738 .b1_right = 0x1c71,
739 .b1_left = 0x1c71,
740 .b2_right = 0x0e38,
741 .b2_left = 0x0e38,
742 };
743
744
745 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&filter_scb,
746 dest,"FILTERTASK",parent_scb,
747 scb_child_type);
748
749 return scb;
750}
751#endif
752
753struct dsp_scb_descriptor *
754cs46xx_dsp_create_mix_only_scb(struct snd_cs46xx * chip, char * scb_name,
755 u16 mix_buffer_addr, u32 dest,
756 struct dsp_scb_descriptor * parent_scb,
757 int scb_child_type)
758{
759 struct dsp_scb_descriptor * scb;
760
761 struct dsp_mix_only_scb master_mix_scb = {
762 { 0,
763 0,
764 mix_buffer_addr,
765 0
766 },
767 {
768 0,
769 0,
770 0,
771 0,
772 0x00000080
773 },
774 0,0,
775 0,0,
776 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
777 (mix_buffer_addr + (16 * 4)) << 0x10,
778 0,
779 {
780 0x8000,0x8000,
781 0x8000,0x8000
782 }
783 };
784
785
786 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&master_mix_scb,
787 dest,"S16_MIX",parent_scb,
788 scb_child_type);
789 return scb;
790}
791
792
793struct dsp_scb_descriptor *
794cs46xx_dsp_create_mix_to_ostream_scb(struct snd_cs46xx * chip, char * scb_name,
795 u16 mix_buffer_addr, u16 writeback_spb, u32 dest,
796 struct dsp_scb_descriptor * parent_scb,
797 int scb_child_type)
798{
799 struct dsp_scb_descriptor * scb;
800
801 struct dsp_mix2_ostream_scb mix2_ostream_scb = {
802
803 {
804 DMA_RQ_C1_SOURCE_MOD64 +
805 DMA_RQ_C1_DEST_ON_HOST +
806 DMA_RQ_C1_DEST_MOD1024 +
807 DMA_RQ_C1_WRITEBACK_SRC_FLAG +
808 DMA_RQ_C1_WRITEBACK_DEST_FLAG +
809 15,
810
811 DMA_RQ_C2_AC_NONE +
812 DMA_RQ_C2_SIGNAL_DEST_PINGPONG +
813
814 CS46XX_DSP_CAPTURE_CHANNEL,
815 DMA_RQ_SD_SP_SAMPLE_ADDR +
816 mix_buffer_addr,
817 0x0
818 },
819
820 { 0, 0, 0, 0, 0, },
821 0,0,
822 0,writeback_spb,
823
824 RSCONFIG_DMA_ENABLE +
825 (19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) +
826
827 ((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) +
828 RSCONFIG_DMA_TO_HOST +
829 RSCONFIG_SAMPLE_16STEREO +
830 RSCONFIG_MODULO_64,
831 (mix_buffer_addr + (32 * 4)) << 0x10,
832 1,0,
833 0x0001,0x0080,
834 0xFFFF,0
835 };
836
837
838 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&mix2_ostream_scb,
839
840 dest,"S16_MIX_TO_OSTREAM",parent_scb,
841 scb_child_type);
842
843 return scb;
844}
845
846
847struct dsp_scb_descriptor *
848cs46xx_dsp_create_vari_decimate_scb(struct snd_cs46xx * chip,char * scb_name,
849 u16 vari_buffer_addr0,
850 u16 vari_buffer_addr1,
851 u32 dest,
852 struct dsp_scb_descriptor * parent_scb,
853 int scb_child_type)
854{
855
856 struct dsp_scb_descriptor * scb;
857
858 struct dsp_vari_decimate_scb vari_decimate_scb = {
859 0x0028,0x00c8,
860 0x5555,0x0000,
861 0x0000,0x0000,
862 vari_buffer_addr0,vari_buffer_addr1,
863
864 0x0028,0x00c8,
865 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256,
866
867 0xFF800000,
868 0,
869 0x0080,vari_buffer_addr1 + (25 * 4),
870
871 0,0,
872 0,0,
873
874 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
875 vari_buffer_addr0 << 0x10,
876 0x04000000,
877 {
878 0x8000,0x8000,
879 0xFFFF,0xFFFF
880 }
881 };
882
883 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&vari_decimate_scb,
884 dest,"VARIDECIMATE",parent_scb,
885 scb_child_type);
886
887 return scb;
888}
889
890
891static struct dsp_scb_descriptor *
892cs46xx_dsp_create_pcm_serial_input_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
893 struct dsp_scb_descriptor * input_scb,
894 struct dsp_scb_descriptor * parent_scb,
895 int scb_child_type)
896{
897
898 struct dsp_scb_descriptor * scb;
899
900
901 struct dsp_pcm_serial_input_scb pcm_serial_input_scb = {
902 { 0,
903 0,
904 0,
905 0
906 },
907 {
908 0,
909 0,
910 0,
911 0,
912 0
913 },
914
915 0,0,
916 0,0,
917
918 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_16,
919 0,
920 0,input_scb->address,
921 {
922 0x8000,0x8000,
923 0x8000,0x8000
924 }
925 };
926
927 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_serial_input_scb,
928 dest,"PCMSERIALINPUTTASK",parent_scb,
929 scb_child_type);
930 return scb;
931}
932
933
934static struct dsp_scb_descriptor *
935cs46xx_dsp_create_asynch_fg_tx_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
936 u16 hfg_scb_address,
937 u16 asynch_buffer_address,
938 struct dsp_scb_descriptor * parent_scb,
939 int scb_child_type)
940{
941
942 struct dsp_scb_descriptor * scb;
943
944 struct dsp_asynch_fg_tx_scb asynch_fg_tx_scb = {
945 0xfc00,0x03ff,
946 0x0058,0x0028,
947
948 0,hfg_scb_address,
949 0,0,
950 0,
951 0,0x2aab,
952
953 {
954 0,
955 0,
956 0
957 },
958
959 0,0,
960 0,dest + AFGTxAccumPhi,
961
962 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256,
963 (asynch_buffer_address) << 0x10,
964
965
966
967
968 0x18000000,
969 0x8000,0x8000,
970 0x8000,0x8000
971 };
972
973 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_tx_scb,
974 dest,"ASYNCHFGTXCODE",parent_scb,
975 scb_child_type);
976
977 return scb;
978}
979
980
981struct dsp_scb_descriptor *
982cs46xx_dsp_create_asynch_fg_rx_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
983 u16 hfg_scb_address,
984 u16 asynch_buffer_address,
985 struct dsp_scb_descriptor * parent_scb,
986 int scb_child_type)
987{
988 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
989 struct dsp_scb_descriptor * scb;
990
991 struct dsp_asynch_fg_rx_scb asynch_fg_rx_scb = {
992 0xfe00,0x01ff,
993 0x0064,0x001c,
994
995 0,hfg_scb_address,
996 0,0,
997 {
998 0,
999 0,
1000 0,
1001 0,
1002 0
1003 },
1004
1005 0,0,
1006 0,dest,
1007
1008 RSCONFIG_MODULO_128 |
1009 RSCONFIG_SAMPLE_16STEREO,
1010 ( (asynch_buffer_address + (16 * 4)) << 0x10),
1011
1012
1013
1014
1015 0x18000000,
1016
1017
1018 0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
1019 0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
1020 };
1021
1022 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_rx_scb,
1023 dest,"ASYNCHFGRXCODE",parent_scb,
1024 scb_child_type);
1025
1026 return scb;
1027}
1028
1029
1030#if 0
1031struct dsp_scb_descriptor *
1032cs46xx_dsp_create_output_snoop_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1033 u16 snoop_buffer_address,
1034 struct dsp_scb_descriptor * snoop_scb,
1035 struct dsp_scb_descriptor * parent_scb,
1036 int scb_child_type)
1037{
1038
1039 struct dsp_scb_descriptor * scb;
1040
1041 struct dsp_output_snoop_scb output_snoop_scb = {
1042 { 0,
1043 0,
1044 0,
1045 0,
1046 },
1047 {
1048 0,
1049 0,
1050 0,
1051 0,
1052 0
1053 },
1054
1055 0,0,
1056 0,0,
1057
1058 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
1059 snoop_buffer_address << 0x10,
1060 0,0,
1061 0,
1062 0,snoop_scb->address
1063 };
1064
1065 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&output_snoop_scb,
1066 dest,"OUTPUTSNOOP",parent_scb,
1067 scb_child_type);
1068 return scb;
1069}
1070#endif
1071
1072
1073struct dsp_scb_descriptor *
1074cs46xx_dsp_create_spio_write_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1075 struct dsp_scb_descriptor * parent_scb,
1076 int scb_child_type)
1077{
1078 struct dsp_scb_descriptor * scb;
1079
1080 struct dsp_spio_write_scb spio_write_scb = {
1081 0,0,
1082 0,
1083 0,
1084 0,0,
1085 0,
1086 0,
1087 0,0,
1088 { 0,0 },
1089
1090 0,0,
1091 0,0,
1092
1093 {
1094 0,
1095 0,
1096 0,
1097 0,
1098 0
1099 }
1100 };
1101
1102 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&spio_write_scb,
1103 dest,"SPIOWRITE",parent_scb,
1104 scb_child_type);
1105
1106 return scb;
1107}
1108
1109struct dsp_scb_descriptor *
1110cs46xx_dsp_create_magic_snoop_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1111 u16 snoop_buffer_address,
1112 struct dsp_scb_descriptor * snoop_scb,
1113 struct dsp_scb_descriptor * parent_scb,
1114 int scb_child_type)
1115{
1116 struct dsp_scb_descriptor * scb;
1117
1118 struct dsp_magic_snoop_task magic_snoop_scb = {
1119 0,
1120 0,
1121 snoop_buffer_address << 0x10,
1122 0,snoop_scb->address,
1123 0,
1124 0,
1125 0,
1126 0,
1127 0,
1128 0,0,
1129 0,0,
1130 RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
1131 snoop_buffer_address << 0x10,
1132 0,
1133 { 0x8000,0x8000,
1134 0xffff,0xffff
1135 }
1136 };
1137
1138 scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&magic_snoop_scb,
1139 dest,"MAGICSNOOPTASK",parent_scb,
1140 scb_child_type);
1141
1142 return scb;
1143}
1144
1145static struct dsp_scb_descriptor *
1146find_next_free_scb (struct snd_cs46xx * chip, struct dsp_scb_descriptor * from)
1147{
1148 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1149 struct dsp_scb_descriptor * scb = from;
1150
1151 while (scb->next_scb_ptr != ins->the_null_scb) {
1152 if (snd_BUG_ON(!scb->next_scb_ptr))
1153 return NULL;
1154
1155 scb = scb->next_scb_ptr;
1156 }
1157
1158 return scb;
1159}
1160
1161static u32 pcm_reader_buffer_addr[DSP_MAX_PCM_CHANNELS] = {
1162 0x0600,
1163 0x1500,
1164 0x1580,
1165 0x1600,
1166 0x1680,
1167 0x1700,
1168 0x1780,
1169 0x1800,
1170 0x1880,
1171 0x1900,
1172 0x1980,
1173 0x1A00,
1174 0x1A80,
1175 0x1B00,
1176 0x1B80,
1177 0x1C00,
1178 0x1C80,
1179 0x1D00,
1180 0x1D80,
1181 0x1E00,
1182 0x1E80,
1183 0x1F00,
1184 0x1F80,
1185 0x2000,
1186 0x2080,
1187 0x2100,
1188 0x2180,
1189 0x2200,
1190 0x2280,
1191 0x2300,
1192 0x2380,
1193 0x2400,
1194};
1195
1196static u32 src_output_buffer_addr[DSP_MAX_SRC_NR] = {
1197 0x2B80,
1198 0x2BA0,
1199 0x2BC0,
1200 0x2BE0,
1201 0x2D00,
1202 0x2D20,
1203 0x2D40,
1204 0x2D60,
1205 0x2D80,
1206 0x2DA0,
1207 0x2DC0,
1208 0x2DE0,
1209 0x2E00,
1210 0x2E20
1211};
1212
1213static u32 src_delay_buffer_addr[DSP_MAX_SRC_NR] = {
1214 0x2480,
1215 0x2500,
1216 0x2580,
1217 0x2600,
1218 0x2680,
1219 0x2700,
1220 0x2780,
1221 0x2800,
1222 0x2880,
1223 0x2900,
1224 0x2980,
1225 0x2A00,
1226 0x2A80,
1227 0x2B00
1228};
1229
1230struct dsp_pcm_channel_descriptor *
1231cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
1232 u32 sample_rate, void * private_data,
1233 u32 hw_dma_addr,
1234 int pcm_channel_id)
1235{
1236 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1237 struct dsp_scb_descriptor * src_scb = NULL, * pcm_scb, * mixer_scb = NULL;
1238 struct dsp_scb_descriptor * src_parent_scb = NULL;
1239
1240
1241 char scb_name[DSP_MAX_SCB_NAME];
1242 int i, pcm_index = -1, insert_point, src_index = -1, pass_through = 0;
1243 unsigned long flags;
1244
1245 switch (pcm_channel_id) {
1246 case DSP_PCM_MAIN_CHANNEL:
1247 mixer_scb = ins->master_mix_scb;
1248 break;
1249 case DSP_PCM_REAR_CHANNEL:
1250 mixer_scb = ins->rear_mix_scb;
1251 break;
1252 case DSP_PCM_CENTER_LFE_CHANNEL:
1253 mixer_scb = ins->center_lfe_mix_scb;
1254 break;
1255 case DSP_PCM_S71_CHANNEL:
1256
1257 snd_BUG();
1258 break;
1259 case DSP_IEC958_CHANNEL:
1260 if (snd_BUG_ON(!ins->asynch_tx_scb))
1261 return NULL;
1262 mixer_scb = ins->asynch_tx_scb;
1263
1264
1265
1266
1267 if (sample_rate == 48000) {
1268 snd_printdd ("IEC958 pass through\n");
1269
1270 pass_through = 1;
1271 }
1272 break;
1273 default:
1274 snd_BUG();
1275 return NULL;
1276 }
1277
1278 if (!sample_rate) sample_rate = 44100;
1279
1280
1281 for (i = 0; i < DSP_MAX_PCM_CHANNELS &&
1282 (pcm_index == -1 || src_scb == NULL); ++i) {
1283
1284
1285
1286 if (i == CS46XX_DSP_CAPTURE_CHANNEL) continue;
1287
1288 if (ins->pcm_channels[i].active) {
1289 if (!src_scb &&
1290 ins->pcm_channels[i].sample_rate == sample_rate &&
1291 ins->pcm_channels[i].mixer_scb == mixer_scb) {
1292 src_scb = ins->pcm_channels[i].src_scb;
1293 ins->pcm_channels[i].src_scb->ref_count ++;
1294 src_index = ins->pcm_channels[i].src_slot;
1295 }
1296 } else if (pcm_index == -1) {
1297 pcm_index = i;
1298 }
1299 }
1300
1301 if (pcm_index == -1) {
1302 snd_printk (KERN_ERR "dsp_spos: no free PCM channel\n");
1303 return NULL;
1304 }
1305
1306 if (src_scb == NULL) {
1307 if (ins->nsrc_scb >= DSP_MAX_SRC_NR) {
1308 snd_printk(KERN_ERR "dsp_spos: to many SRC instances\n!");
1309 return NULL;
1310 }
1311
1312
1313 for (i = 0; i < DSP_MAX_SRC_NR; ++i) {
1314 if (ins->src_scb_slots[i] == 0) {
1315 src_index = i;
1316 ins->src_scb_slots[i] = 1;
1317 break;
1318 }
1319 }
1320 if (snd_BUG_ON(src_index == -1))
1321 return NULL;
1322
1323
1324 if (mixer_scb->sub_list_ptr == ins->the_null_scb) {
1325 src_parent_scb = mixer_scb;
1326 insert_point = SCB_ON_PARENT_SUBLIST_SCB;
1327 } else {
1328 src_parent_scb = find_next_free_scb(chip,mixer_scb->sub_list_ptr);
1329 insert_point = SCB_ON_PARENT_NEXT_SCB;
1330 }
1331
1332 snprintf (scb_name,DSP_MAX_SCB_NAME,"SrcTask_SCB%d",src_index);
1333
1334 snd_printdd( "dsp_spos: creating SRC \"%s\"\n",scb_name);
1335 src_scb = cs46xx_dsp_create_src_task_scb(chip,scb_name,
1336 sample_rate,
1337 src_output_buffer_addr[src_index],
1338 src_delay_buffer_addr[src_index],
1339
1340 0x400 + (src_index * 0x10) ,
1341 src_parent_scb,
1342 insert_point,
1343 pass_through);
1344
1345 if (!src_scb) {
1346 snd_printk (KERN_ERR "dsp_spos: failed to create SRCtaskSCB\n");
1347 return NULL;
1348 }
1349
1350
1351
1352 ins->nsrc_scb ++;
1353 }
1354
1355
1356 snprintf (scb_name,DSP_MAX_SCB_NAME,"PCMReader_SCB%d",pcm_index);
1357
1358 snd_printdd( "dsp_spos: creating PCM \"%s\" (%d)\n",scb_name,
1359 pcm_channel_id);
1360
1361 pcm_scb = cs46xx_dsp_create_pcm_reader_scb(chip,scb_name,
1362 pcm_reader_buffer_addr[pcm_index],
1363
1364 (pcm_index * 0x10) + 0x200,
1365 pcm_index,
1366 hw_dma_addr,
1367 NULL,
1368 0
1369 );
1370
1371 if (!pcm_scb) {
1372 snd_printk (KERN_ERR "dsp_spos: failed to create PCMreaderSCB\n");
1373 return NULL;
1374 }
1375
1376 spin_lock_irqsave(&chip->reg_lock, flags);
1377 ins->pcm_channels[pcm_index].sample_rate = sample_rate;
1378 ins->pcm_channels[pcm_index].pcm_reader_scb = pcm_scb;
1379 ins->pcm_channels[pcm_index].src_scb = src_scb;
1380 ins->pcm_channels[pcm_index].unlinked = 1;
1381 ins->pcm_channels[pcm_index].private_data = private_data;
1382 ins->pcm_channels[pcm_index].src_slot = src_index;
1383 ins->pcm_channels[pcm_index].active = 1;
1384 ins->pcm_channels[pcm_index].pcm_slot = pcm_index;
1385 ins->pcm_channels[pcm_index].mixer_scb = mixer_scb;
1386 ins->npcm_channels ++;
1387 spin_unlock_irqrestore(&chip->reg_lock, flags);
1388
1389 return (ins->pcm_channels + pcm_index);
1390}
1391
1392int cs46xx_dsp_pcm_channel_set_period (struct snd_cs46xx * chip,
1393 struct dsp_pcm_channel_descriptor * pcm_channel,
1394 int period_size)
1395{
1396 u32 temp = snd_cs46xx_peek (chip,pcm_channel->pcm_reader_scb->address << 2);
1397 temp &= ~DMA_RQ_C1_SOURCE_SIZE_MASK;
1398
1399 switch (period_size) {
1400 case 2048:
1401 temp |= DMA_RQ_C1_SOURCE_MOD1024;
1402 break;
1403 case 1024:
1404 temp |= DMA_RQ_C1_SOURCE_MOD512;
1405 break;
1406 case 512:
1407 temp |= DMA_RQ_C1_SOURCE_MOD256;
1408 break;
1409 case 256:
1410 temp |= DMA_RQ_C1_SOURCE_MOD128;
1411 break;
1412 case 128:
1413 temp |= DMA_RQ_C1_SOURCE_MOD64;
1414 break;
1415 case 64:
1416 temp |= DMA_RQ_C1_SOURCE_MOD32;
1417 break;
1418 case 32:
1419 temp |= DMA_RQ_C1_SOURCE_MOD16;
1420 break;
1421 default:
1422 snd_printdd ("period size (%d) not supported by HW\n", period_size);
1423 return -EINVAL;
1424 }
1425
1426 snd_cs46xx_poke (chip,pcm_channel->pcm_reader_scb->address << 2,temp);
1427
1428 return 0;
1429}
1430
1431int cs46xx_dsp_pcm_ostream_set_period (struct snd_cs46xx * chip,
1432 int period_size)
1433{
1434 u32 temp = snd_cs46xx_peek (chip,WRITEBACK_SCB_ADDR << 2);
1435 temp &= ~DMA_RQ_C1_DEST_SIZE_MASK;
1436
1437 switch (period_size) {
1438 case 2048:
1439 temp |= DMA_RQ_C1_DEST_MOD1024;
1440 break;
1441 case 1024:
1442 temp |= DMA_RQ_C1_DEST_MOD512;
1443 break;
1444 case 512:
1445 temp |= DMA_RQ_C1_DEST_MOD256;
1446 break;
1447 case 256:
1448 temp |= DMA_RQ_C1_DEST_MOD128;
1449 break;
1450 case 128:
1451 temp |= DMA_RQ_C1_DEST_MOD64;
1452 break;
1453 case 64:
1454 temp |= DMA_RQ_C1_DEST_MOD32;
1455 break;
1456 case 32:
1457 temp |= DMA_RQ_C1_DEST_MOD16;
1458 break;
1459 default:
1460 snd_printdd ("period size (%d) not supported by HW\n", period_size);
1461 return -EINVAL;
1462 }
1463
1464 snd_cs46xx_poke (chip,WRITEBACK_SCB_ADDR << 2,temp);
1465
1466 return 0;
1467}
1468
1469void cs46xx_dsp_destroy_pcm_channel (struct snd_cs46xx * chip,
1470 struct dsp_pcm_channel_descriptor * pcm_channel)
1471{
1472 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1473 unsigned long flags;
1474
1475 if (snd_BUG_ON(!pcm_channel->active ||
1476 ins->npcm_channels <= 0 ||
1477 pcm_channel->src_scb->ref_count <= 0))
1478 return;
1479
1480 spin_lock_irqsave(&chip->reg_lock, flags);
1481 pcm_channel->unlinked = 1;
1482 pcm_channel->active = 0;
1483 pcm_channel->private_data = NULL;
1484 pcm_channel->src_scb->ref_count --;
1485 ins->npcm_channels --;
1486 spin_unlock_irqrestore(&chip->reg_lock, flags);
1487
1488 cs46xx_dsp_remove_scb(chip,pcm_channel->pcm_reader_scb);
1489
1490 if (!pcm_channel->src_scb->ref_count) {
1491 cs46xx_dsp_remove_scb(chip,pcm_channel->src_scb);
1492
1493 if (snd_BUG_ON(pcm_channel->src_slot < 0 ||
1494 pcm_channel->src_slot >= DSP_MAX_SRC_NR))
1495 return;
1496
1497 ins->src_scb_slots[pcm_channel->src_slot] = 0;
1498 ins->nsrc_scb --;
1499 }
1500}
1501
1502int cs46xx_dsp_pcm_unlink (struct snd_cs46xx * chip,
1503 struct dsp_pcm_channel_descriptor * pcm_channel)
1504{
1505 unsigned long flags;
1506
1507 if (snd_BUG_ON(!pcm_channel->active ||
1508 chip->dsp_spos_instance->npcm_channels <= 0))
1509 return -EIO;
1510
1511 spin_lock_irqsave(&chip->reg_lock, flags);
1512 if (pcm_channel->unlinked) {
1513 spin_unlock_irqrestore(&chip->reg_lock, flags);
1514 return -EIO;
1515 }
1516
1517 pcm_channel->unlinked = 1;
1518
1519 _dsp_unlink_scb (chip,pcm_channel->pcm_reader_scb);
1520 spin_unlock_irqrestore(&chip->reg_lock, flags);
1521
1522 return 0;
1523}
1524
1525int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip,
1526 struct dsp_pcm_channel_descriptor * pcm_channel)
1527{
1528 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1529 struct dsp_scb_descriptor * parent_scb;
1530 struct dsp_scb_descriptor * src_scb = pcm_channel->src_scb;
1531 unsigned long flags;
1532
1533 spin_lock_irqsave(&chip->reg_lock, flags);
1534
1535 if (pcm_channel->unlinked == 0) {
1536 spin_unlock_irqrestore(&chip->reg_lock, flags);
1537 return -EIO;
1538 }
1539
1540 parent_scb = src_scb;
1541
1542 if (src_scb->sub_list_ptr != ins->the_null_scb) {
1543 src_scb->sub_list_ptr->parent_scb_ptr = pcm_channel->pcm_reader_scb;
1544 pcm_channel->pcm_reader_scb->next_scb_ptr = src_scb->sub_list_ptr;
1545 }
1546
1547 src_scb->sub_list_ptr = pcm_channel->pcm_reader_scb;
1548
1549 snd_BUG_ON(pcm_channel->pcm_reader_scb->parent_scb_ptr);
1550 pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb;
1551
1552
1553 cs46xx_dsp_spos_update_scb(chip,pcm_channel->pcm_reader_scb);
1554
1555
1556 cs46xx_dsp_spos_update_scb(chip,parent_scb);
1557
1558 pcm_channel->unlinked = 0;
1559 spin_unlock_irqrestore(&chip->reg_lock, flags);
1560 return 0;
1561}
1562
1563struct dsp_scb_descriptor *
1564cs46xx_add_record_source (struct snd_cs46xx *chip, struct dsp_scb_descriptor * source,
1565 u16 addr, char * scb_name)
1566{
1567 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1568 struct dsp_scb_descriptor * parent;
1569 struct dsp_scb_descriptor * pcm_input;
1570 int insert_point;
1571
1572 if (snd_BUG_ON(!ins->record_mixer_scb))
1573 return NULL;
1574
1575 if (ins->record_mixer_scb->sub_list_ptr != ins->the_null_scb) {
1576 parent = find_next_free_scb (chip,ins->record_mixer_scb->sub_list_ptr);
1577 insert_point = SCB_ON_PARENT_NEXT_SCB;
1578 } else {
1579 parent = ins->record_mixer_scb;
1580 insert_point = SCB_ON_PARENT_SUBLIST_SCB;
1581 }
1582
1583 pcm_input = cs46xx_dsp_create_pcm_serial_input_scb(chip,scb_name,addr,
1584 source, parent,
1585 insert_point);
1586
1587 return pcm_input;
1588}
1589
1590int cs46xx_src_unlink(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
1591{
1592 unsigned long flags;
1593
1594 if (snd_BUG_ON(!src->parent_scb_ptr))
1595 return -EINVAL;
1596
1597
1598 cs46xx_dsp_scb_set_volume (chip,src,0,0);
1599
1600 spin_lock_irqsave(&chip->reg_lock, flags);
1601 _dsp_unlink_scb (chip,src);
1602 spin_unlock_irqrestore(&chip->reg_lock, flags);
1603
1604 return 0;
1605}
1606
1607int cs46xx_src_link(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
1608{
1609 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1610 struct dsp_scb_descriptor * parent_scb;
1611
1612 if (snd_BUG_ON(src->parent_scb_ptr))
1613 return -EINVAL;
1614 if (snd_BUG_ON(!ins->master_mix_scb))
1615 return -EINVAL;
1616
1617 if (ins->master_mix_scb->sub_list_ptr != ins->the_null_scb) {
1618 parent_scb = find_next_free_scb (chip,ins->master_mix_scb->sub_list_ptr);
1619 parent_scb->next_scb_ptr = src;
1620 } else {
1621 parent_scb = ins->master_mix_scb;
1622 parent_scb->sub_list_ptr = src;
1623 }
1624
1625 src->parent_scb_ptr = parent_scb;
1626
1627
1628 cs46xx_dsp_spos_update_scb(chip,parent_scb);
1629
1630 return 0;
1631}
1632
1633int cs46xx_dsp_enable_spdif_out (struct snd_cs46xx *chip)
1634{
1635 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1636
1637 if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
1638 cs46xx_dsp_enable_spdif_hw (chip);
1639 }
1640
1641
1642 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
1643
1644
1645
1646 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1647
1648 return -EBUSY;
1649 }
1650
1651 if (snd_BUG_ON(ins->asynch_tx_scb))
1652 return -EINVAL;
1653 if (snd_BUG_ON(ins->master_mix_scb->next_scb_ptr !=
1654 ins->the_null_scb))
1655 return -EINVAL;
1656
1657
1658 snd_cs46xx_poke (chip, (ins->ref_snoop_scb->address + 2) << 2,
1659 (OUTPUT_SNOOP_BUFFER + 0x10) << 0x10 );
1660
1661
1662 ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
1663 SPDIFO_SCB_INST,
1664 SPDIFO_IP_OUTPUT_BUFFER1,
1665 ins->master_mix_scb,
1666 SCB_ON_PARENT_NEXT_SCB);
1667 if (!ins->asynch_tx_scb) return -ENOMEM;
1668
1669 ins->spdif_pcm_input_scb = cs46xx_dsp_create_pcm_serial_input_scb(chip,"PCMSerialInput_II",
1670 PCMSERIALINII_SCB_ADDR,
1671 ins->ref_snoop_scb,
1672 ins->asynch_tx_scb,
1673 SCB_ON_PARENT_SUBLIST_SCB);
1674
1675
1676 if (!ins->spdif_pcm_input_scb) return -ENOMEM;
1677
1678
1679 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1680
1681 return 0;
1682}
1683
1684int cs46xx_dsp_disable_spdif_out (struct snd_cs46xx *chip)
1685{
1686 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1687
1688
1689 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
1690 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1691 return -EBUSY;
1692 }
1693
1694
1695 if (snd_BUG_ON(!ins->asynch_tx_scb))
1696 return -EINVAL;
1697 if (snd_BUG_ON(!ins->spdif_pcm_input_scb))
1698 return -EINVAL;
1699 if (snd_BUG_ON(ins->master_mix_scb->next_scb_ptr != ins->asynch_tx_scb))
1700 return -EINVAL;
1701 if (snd_BUG_ON(ins->asynch_tx_scb->parent_scb_ptr !=
1702 ins->master_mix_scb))
1703 return -EINVAL;
1704
1705 cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
1706 cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
1707
1708 ins->spdif_pcm_input_scb = NULL;
1709 ins->asynch_tx_scb = NULL;
1710
1711
1712 _dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
1713
1714
1715 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1716
1717
1718 return 0;
1719}
1720
1721int cs46xx_iec958_pre_open (struct snd_cs46xx *chip)
1722{
1723 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1724
1725 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
1726
1727 cs46xx_dsp_disable_spdif_out (chip);
1728
1729
1730 ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1731 }
1732
1733
1734 if ( !(ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
1735 cs46xx_dsp_enable_spdif_hw (chip);
1736 }
1737
1738
1739 ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
1740 SPDIFO_SCB_INST,
1741 SPDIFO_IP_OUTPUT_BUFFER1,
1742 ins->master_mix_scb,
1743 SCB_ON_PARENT_NEXT_SCB);
1744
1745
1746
1747 cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_stream);
1748
1749 ins->spdif_status_out |= DSP_SPDIF_STATUS_PLAYBACK_OPEN;
1750
1751 return 0;
1752}
1753
1754int cs46xx_iec958_post_close (struct snd_cs46xx *chip)
1755{
1756 struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1757
1758 if (snd_BUG_ON(!ins->asynch_tx_scb))
1759 return -EINVAL;
1760
1761 ins->spdif_status_out &= ~DSP_SPDIF_STATUS_PLAYBACK_OPEN;
1762
1763
1764 cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);
1765
1766
1767 if (ins->spdif_pcm_input_scb != NULL) {
1768 cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
1769 ins->spdif_pcm_input_scb = NULL;
1770 }
1771
1772 cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
1773 ins->asynch_tx_scb = NULL;
1774
1775
1776 _dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
1777
1778
1779 if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
1780 cs46xx_dsp_enable_spdif_out (chip);
1781 }
1782
1783 return 0;
1784}
1785