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