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