File Index
Files and directories
Sign in
FILE

dsp_spos_scb_lib.c

File preview with syntax highlighting.

linux-6.19.14/sound/pci/cs46xx/dsp_spos_scb_lib.c C
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 */
   4
   5/*
   6 * 2002-07 Benny Sjostrand benny@hostmobility.com
   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	guard(mutex)(&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}
  95#endif
  96
  97static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
  98{
  99	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 100
 101	if ( scb->parent_scb_ptr ) {
 102		/* unlink parent SCB */
 103		if (snd_BUG_ON(scb->parent_scb_ptr->sub_list_ptr != scb &&
 104			       scb->parent_scb_ptr->next_scb_ptr != scb))
 105			return;
 106  
 107		if (scb->parent_scb_ptr->sub_list_ptr == scb) {
 108
 109			if (scb->next_scb_ptr == ins->the_null_scb) {
 110				/* last and only node in parent sublist */
 111				scb->parent_scb_ptr->sub_list_ptr = scb->sub_list_ptr;
 112
 113				if (scb->sub_list_ptr != ins->the_null_scb) {
 114					scb->sub_list_ptr->parent_scb_ptr = scb->parent_scb_ptr;
 115				}
 116				scb->sub_list_ptr = ins->the_null_scb;
 117			} else {
 118				/* first node in parent sublist */
 119				scb->parent_scb_ptr->sub_list_ptr = scb->next_scb_ptr;
 120
 121				if (scb->next_scb_ptr != ins->the_null_scb) {
 122					/* update next node parent ptr. */
 123					scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
 124				}
 125				scb->next_scb_ptr = ins->the_null_scb;
 126			}
 127		} else {
 128			scb->parent_scb_ptr->next_scb_ptr = scb->next_scb_ptr;
 129
 130			if (scb->next_scb_ptr != ins->the_null_scb) {
 131				/* update next node parent ptr. */
 132				scb->next_scb_ptr->parent_scb_ptr = scb->parent_scb_ptr;
 133			}
 134			scb->next_scb_ptr = ins->the_null_scb;
 135		}
 136
 137		/* update parent first entry in DSP RAM */
 138		cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
 139
 140		/* then update entry in DSP RAM */
 141		cs46xx_dsp_spos_update_scb(chip,scb);
 142
 143		scb->parent_scb_ptr = NULL;
 144	}
 145}
 146
 147static void _dsp_clear_sample_buffer (struct snd_cs46xx *chip, u32 sample_buffer_addr,
 148				      int dword_count) 
 149{
 150	void __iomem *dst = chip->region.idx[2].remap_addr + sample_buffer_addr;
 151	int i;
 152  
 153	for (i = 0; i < dword_count ; ++i ) {
 154		writel(0, dst);
 155		dst += 4;
 156	}  
 157}
 158
 159void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb)
 160{
 161	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 162
 163	/* check integrety */
 164	if (snd_BUG_ON(scb->index < 0 ||
 165		       scb->index >= ins->nscb ||
 166		       (ins->scbs + scb->index) != scb))
 167		return;
 168
 169#if 0
 170	/* can't remove a SCB with childs before 
 171	   removing childs first  */
 172	if (snd_BUG_ON(scb->sub_list_ptr != ins->the_null_scb ||
 173		       scb->next_scb_ptr != ins->the_null_scb))
 174		goto _end;
 175#endif
 176
 177	scoped_guard(spinlock_irqsave, &chip->reg_lock) {
 178		_dsp_unlink_scb(chip, scb);
 179	}
 180
 181	cs46xx_dsp_proc_free_scb_desc(scb);
 182	if (snd_BUG_ON(!scb->scb_symbol))
 183		return;
 184	remove_symbol (chip,scb->scb_symbol);
 185
 186	ins->scbs[scb->index].deleted = 1;
 187#ifdef CONFIG_PM_SLEEP
 188	kfree(ins->scbs[scb->index].data);
 189	ins->scbs[scb->index].data = NULL;
 190#endif
 191
 192	if (scb->index < ins->scb_highest_frag_index)
 193		ins->scb_highest_frag_index = scb->index;
 194
 195	if (scb->index == ins->nscb - 1) {
 196		ins->nscb --;
 197	}
 198
 199	if (ins->scb_highest_frag_index > ins->nscb) {
 200		ins->scb_highest_frag_index = ins->nscb;
 201	}
 202}
 203
 204
 205#ifdef CONFIG_SND_PROC_FS
 206void cs46xx_dsp_proc_free_scb_desc (struct dsp_scb_descriptor * scb)
 207{
 208	if (scb->proc_info) {
 209		struct proc_scb_info * scb_info = scb->proc_info->private_data;
 210		struct snd_cs46xx *chip = scb_info->chip;
 211
 212		dev_dbg(chip->card->dev,
 213			"cs46xx_dsp_proc_free_scb_desc: freeing %s\n",
 214			scb->scb_name);
 215
 216		snd_info_free_entry(scb->proc_info);
 217		scb->proc_info = NULL;
 218
 219		kfree (scb_info);
 220	}
 221}
 222
 223void cs46xx_dsp_proc_register_scb_desc (struct snd_cs46xx *chip,
 224					struct dsp_scb_descriptor * scb)
 225{
 226	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 227	struct snd_info_entry * entry;
 228	struct proc_scb_info * scb_info;
 229
 230	/* register to proc */
 231	if (ins->snd_card != NULL && ins->proc_dsp_dir != NULL &&
 232	    scb->proc_info == NULL) {
 233  
 234		entry = snd_info_create_card_entry(ins->snd_card, scb->scb_name,
 235						   ins->proc_dsp_dir);
 236		if (entry) {
 237			scb_info = kmalloc(sizeof(struct proc_scb_info), GFP_KERNEL);
 238			if (!scb_info) {
 239				snd_info_free_entry(entry);
 240				entry = NULL;
 241				goto out;
 242			}
 243
 244			scb_info->chip = chip;
 245			scb_info->scb_desc = scb;
 246			snd_info_set_text_ops(entry, scb_info,
 247					      cs46xx_dsp_proc_scb_info_read);
 248		}
 249out:
 250		scb->proc_info = entry;
 251	}
 252}
 253#endif /* CONFIG_SND_PROC_FS */
 254
 255static struct dsp_scb_descriptor * 
 256_dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32 dest,
 257                         struct dsp_symbol_entry * task_entry,
 258                         struct dsp_scb_descriptor * parent_scb,
 259                         int scb_child_type)
 260{
 261	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 262	struct dsp_scb_descriptor * scb;
 263  
 264	if (snd_BUG_ON(!ins->the_null_scb))
 265		return NULL;
 266
 267	/* fill the data that will be wroten to DSP */
 268	scb_data[SCBsubListPtr] = 
 269		(ins->the_null_scb->address << 0x10) | ins->the_null_scb->address;
 270
 271	scb_data[SCBfuncEntryPtr] &= 0xFFFF0000;
 272	scb_data[SCBfuncEntryPtr] |= task_entry->address;
 273
 274	dev_dbg(chip->card->dev, "dsp_spos: creating SCB <%s>\n", name);
 275
 276	scb = cs46xx_dsp_create_scb(chip,name,scb_data,dest);
 277
 278
 279	scb->sub_list_ptr = ins->the_null_scb;
 280	scb->next_scb_ptr = ins->the_null_scb;
 281
 282	scb->parent_scb_ptr = parent_scb;
 283	scb->task_entry = task_entry;
 284
 285  
 286	/* update parent SCB */
 287	if (scb->parent_scb_ptr) {
 288#if 0
 289		dev_dbg(chip->card->dev,
 290			"scb->parent_scb_ptr = %s\n",
 291			scb->parent_scb_ptr->scb_name);
 292		dev_dbg(chip->card->dev,
 293			"scb->parent_scb_ptr->next_scb_ptr = %s\n",
 294			scb->parent_scb_ptr->next_scb_ptr->scb_name);
 295		dev_dbg(chip->card->dev,
 296			"scb->parent_scb_ptr->sub_list_ptr = %s\n",
 297			scb->parent_scb_ptr->sub_list_ptr->scb_name);
 298#endif
 299		/* link to  parent SCB */
 300		if (scb_child_type == SCB_ON_PARENT_NEXT_SCB) {
 301			if (snd_BUG_ON(scb->parent_scb_ptr->next_scb_ptr !=
 302				       ins->the_null_scb))
 303				return NULL;
 304
 305			scb->parent_scb_ptr->next_scb_ptr = scb;
 306
 307		} else if (scb_child_type == SCB_ON_PARENT_SUBLIST_SCB) {
 308			if (snd_BUG_ON(scb->parent_scb_ptr->sub_list_ptr !=
 309				       ins->the_null_scb))
 310				return NULL;
 311
 312			scb->parent_scb_ptr->sub_list_ptr = scb;
 313		} else {
 314			snd_BUG();
 315		}
 316
 317		scoped_guard(spinlock_irqsave, &chip->reg_lock) {
 318			/* update entry in DSP RAM */
 319			cs46xx_dsp_spos_update_scb(chip, scb->parent_scb_ptr);
 320		}
 321	}
 322
 323
 324	cs46xx_dsp_proc_register_scb_desc (chip,scb);
 325
 326	return scb;
 327}
 328
 329static struct dsp_scb_descriptor * 
 330cs46xx_dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data,
 331			       u32 dest, char * task_entry_name,
 332                               struct dsp_scb_descriptor * parent_scb,
 333                               int scb_child_type)
 334{
 335	struct dsp_symbol_entry * task_entry;
 336
 337	task_entry = cs46xx_dsp_lookup_symbol (chip,task_entry_name,
 338					       SYMBOL_CODE);
 339  
 340	if (task_entry == NULL) {
 341		dev_err(chip->card->dev,
 342			"dsp_spos: symbol %s not found\n", task_entry_name);
 343		return NULL;
 344	}
 345  
 346	return _dsp_create_generic_scb (chip,name,scb_data,dest,task_entry,
 347					parent_scb,scb_child_type);
 348}
 349
 350struct dsp_scb_descriptor * 
 351cs46xx_dsp_create_timing_master_scb (struct snd_cs46xx *chip)
 352{
 353	struct dsp_scb_descriptor * scb;
 354  
 355	struct dsp_timing_master_scb timing_master_scb = {
 356		{ 0,
 357		  0,
 358		  0,
 359		  0
 360		},
 361		{ 0,
 362		  0,
 363		  0,
 364		  0,
 365		  0
 366		},
 367		0,0,
 368		0,NULL_SCB_ADDR,
 369		0,0,             /* extraSampleAccum:TMreserved */
 370		0,0,             /* codecFIFOptr:codecFIFOsyncd */
 371		0x0001,0x8000,   /* fracSampAccumQm1:TMfrmsLeftInGroup */
 372		0x0001,0x0000,   /* fracSampCorrectionQm1:TMfrmGroupLength */
 373		0x00060000       /* nSampPerFrmQ15 */
 374	};    
 375  
 376	scb = cs46xx_dsp_create_generic_scb(chip,"TimingMasterSCBInst",(u32 *)&timing_master_scb,
 377					    TIMINGMASTER_SCB_ADDR,
 378					    "TIMINGMASTER",NULL,SCB_NO_PARENT);
 379
 380	return scb;
 381}
 382
 383
 384struct dsp_scb_descriptor * 
 385cs46xx_dsp_create_codec_out_scb(struct snd_cs46xx * chip, char * codec_name,
 386                                u16 channel_disp, u16 fifo_addr, u16 child_scb_addr,
 387                                u32 dest, struct dsp_scb_descriptor * parent_scb,
 388                                int scb_child_type)
 389{
 390	struct dsp_scb_descriptor * scb;
 391  
 392	struct dsp_codec_output_scb codec_out_scb = {
 393		{ 0,
 394		  0,
 395		  0,
 396		  0
 397		},
 398		{
 399			0,
 400			0,
 401			0,
 402			0,
 403			0
 404		},
 405		0,0,
 406		0,NULL_SCB_ADDR,
 407		0,                      /* COstrmRsConfig */
 408		0,                      /* COstrmBufPtr */
 409		channel_disp,fifo_addr, /* leftChanBaseIOaddr:rightChanIOdisp */
 410		0x0000,0x0080,          /* (!AC97!) COexpVolChangeRate:COscaleShiftCount */
 411		0,child_scb_addr        /* COreserved - need child scb to work with rom code */
 412	};
 413  
 414  
 415	scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_out_scb,
 416					    dest,"S16_CODECOUTPUTTASK",parent_scb,
 417					    scb_child_type);
 418  
 419	return scb;
 420}
 421
 422struct dsp_scb_descriptor * 
 423cs46xx_dsp_create_codec_in_scb(struct snd_cs46xx * chip, char * codec_name,
 424			       u16 channel_disp, u16 fifo_addr, u16 sample_buffer_addr,
 425			       u32 dest, struct dsp_scb_descriptor * parent_scb,
 426			       int scb_child_type)
 427{
 428
 429	struct dsp_scb_descriptor * scb;
 430	struct dsp_codec_input_scb codec_input_scb = {
 431		{ 0,
 432		  0,
 433		  0,
 434		  0
 435		},
 436		{
 437			0,
 438			0,
 439			0,
 440			0,
 441			0
 442		},
 443    
 444#if 0  /* cs4620 */
 445		SyncIOSCB,NULL_SCB_ADDR
 446#else
 447		0 , 0,
 448#endif
 449		0,0,
 450
 451		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,  /* strmRsConfig */
 452		sample_buffer_addr << 0x10,       /* strmBufPtr; defined as a dword ptr, used as a byte ptr */
 453		channel_disp,fifo_addr,           /* (!AC97!) leftChanBaseINaddr=AC97primary 
 454						     link input slot 3 :rightChanINdisp=""slot 4 */
 455		0x0000,0x0000,                    /* (!AC97!) ????:scaleShiftCount; no shift needed 
 456						     because AC97 is already 20 bits */
 457		0x80008000                        /* ??clw cwcgame.scb has 0 */
 458	};
 459  
 460	scb = cs46xx_dsp_create_generic_scb(chip,codec_name,(u32 *)&codec_input_scb,
 461					    dest,"S16_CODECINPUTTASK",parent_scb,
 462					    scb_child_type);
 463	return scb;
 464}
 465
 466
 467static struct dsp_scb_descriptor * 
 468cs46xx_dsp_create_pcm_reader_scb(struct snd_cs46xx * chip, char * scb_name,
 469                                 u16 sample_buffer_addr, u32 dest,
 470                                 int virtual_channel, u32 playback_hw_addr,
 471                                 struct dsp_scb_descriptor * parent_scb,
 472                                 int scb_child_type)
 473{
 474	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 475	struct dsp_scb_descriptor * scb;
 476  
 477	struct dsp_generic_scb pcm_reader_scb = {
 478    
 479		/*
 480		  Play DMA Task xfers data from host buffer to SP buffer
 481		  init/runtime variables:
 482		  PlayAC: Play Audio Data Conversion - SCB loc: 2nd dword, mask: 0x0000F000L
 483		  DATA_FMT_16BIT_ST_LTLEND(0x00000000L)   from 16-bit stereo, little-endian
 484		  DATA_FMT_8_BIT_ST_SIGNED(0x00001000L)   from 8-bit stereo, signed
 485		  DATA_FMT_16BIT_MN_LTLEND(0x00002000L)   from 16-bit mono, little-endian
 486		  DATA_FMT_8_BIT_MN_SIGNED(0x00003000L)   from 8-bit mono, signed
 487		  DATA_FMT_16BIT_ST_BIGEND(0x00004000L)   from 16-bit stereo, big-endian
 488		  DATA_FMT_16BIT_MN_BIGEND(0x00006000L)   from 16-bit mono, big-endian
 489		  DATA_FMT_8_BIT_ST_UNSIGNED(0x00009000L) from 8-bit stereo, unsigned
 490		  DATA_FMT_8_BIT_MN_UNSIGNED(0x0000b000L) from 8-bit mono, unsigned
 491		  ? Other combinations possible from:
 492		  DMA_RQ_C2_AUDIO_CONVERT_MASK    0x0000F000L
 493		  DMA_RQ_C2_AC_NONE               0x00000000L
 494		  DMA_RQ_C2_AC_8_TO_16_BIT        0x00001000L
 495		  DMA_RQ_C2_AC_MONO_TO_STEREO     0x00002000L
 496		  DMA_RQ_C2_AC_ENDIAN_CONVERT     0x00004000L
 497		  DMA_RQ_C2_AC_SIGNED_CONVERT     0x00008000L
 498        
 499		  HostBuffAddr: Host Buffer Physical Byte Address - SCB loc:3rd dword, Mask: 0xFFFFFFFFL
 500		  aligned to dword boundary
 501		*/
 502		/* Basic (non scatter/gather) DMA requestor (4 ints) */
 503		{ DMA_RQ_C1_SOURCE_ON_HOST +        /* source buffer is on the host */
 504		  DMA_RQ_C1_SOURCE_MOD1024 +        /* source buffer is 1024 dwords (4096 bytes) */
 505		  DMA_RQ_C1_DEST_MOD32 +            /* dest buffer(PCMreaderBuf) is 32 dwords*/
 506		  DMA_RQ_C1_WRITEBACK_SRC_FLAG +    /* ?? */
 507		  DMA_RQ_C1_WRITEBACK_DEST_FLAG +   /* ?? */
 508		  15,                             /* DwordCount-1: picked 16 for DwordCount because Jim */
 509		  /*        Barnette said that is what we should use since */
 510		  /*        we are not running in optimized mode? */
 511		  DMA_RQ_C2_AC_NONE +
 512		  DMA_RQ_C2_SIGNAL_SOURCE_PINGPONG + /* set play interrupt (bit0) in HISR when source */
 513		  /*   buffer (on host) crosses half-way point */
 514		  virtual_channel,                   /* Play DMA channel arbitrarily set to 0 */
 515		  playback_hw_addr,                  /* HostBuffAddr (source) */
 516		  DMA_RQ_SD_SP_SAMPLE_ADDR +         /* destination buffer is in SP Sample Memory */
 517		  sample_buffer_addr                 /* SP Buffer Address (destination) */
 518		},
 519		/* Scatter/gather DMA requestor extension   (5 ints) */
 520		{
 521			0,
 522			0,
 523			0,
 524			0,
 525			0 
 526		},
 527		/* Sublist pointer & next stream control block (SCB) link. */
 528		NULL_SCB_ADDR,NULL_SCB_ADDR,
 529		/* Pointer to this tasks parameter block & stream function pointer */
 530		0,NULL_SCB_ADDR,
 531		/* rsConfig register for stream buffer (rsDMA reg. is loaded from basicReq.daw */
 532		/*   for incoming streams, or basicReq.saw, for outgoing streams) */
 533		RSCONFIG_DMA_ENABLE +                 /* enable DMA */
 534		(19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) + /* MAX_DMA_SIZE picked to be 19 since SPUD  */
 535		/*  uses it for some reason */
 536		((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) + /* stream number = SCBaddr/16 */
 537		RSCONFIG_SAMPLE_16STEREO +
 538		RSCONFIG_MODULO_32,             /* dest buffer(PCMreaderBuf) is 32 dwords (256 bytes) */
 539		/* Stream sample pointer & MAC-unit mode for this stream */
 540		(sample_buffer_addr << 0x10),
 541		/* Fractional increment per output sample in the input sample buffer */
 542		0, 
 543		{
 544			/* Standard stereo volume control
 545			   default muted */
 546			0xffff,0xffff,
 547			0xffff,0xffff
 548		}
 549	};
 550
 551	if (ins->null_algorithm == NULL) {
 552		ins->null_algorithm =  cs46xx_dsp_lookup_symbol (chip,"NULLALGORITHM",
 553								 SYMBOL_CODE);
 554    
 555		if (ins->null_algorithm == NULL) {
 556			dev_err(chip->card->dev,
 557				"dsp_spos: symbol NULLALGORITHM not found\n");
 558			return NULL;
 559		}    
 560	}
 561
 562	scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_reader_scb,
 563				      dest,ins->null_algorithm,parent_scb,
 564				      scb_child_type);
 565  
 566	return scb;
 567}
 568
 569#define GOF_PER_SEC 200
 570
 571struct dsp_scb_descriptor * 
 572cs46xx_dsp_create_src_task_scb(struct snd_cs46xx * chip, char * scb_name,
 573			       int rate,
 574                               u16 src_buffer_addr,
 575                               u16 src_delay_buffer_addr, u32 dest,
 576                               struct dsp_scb_descriptor * parent_scb,
 577                               int scb_child_type,
 578	                       int pass_through)
 579{
 580
 581	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 582	struct dsp_scb_descriptor * scb;
 583	unsigned int tmp1, tmp2;
 584	unsigned int phiIncr;
 585	unsigned int correctionPerGOF, correctionPerSec;
 586
 587	dev_dbg(chip->card->dev, "dsp_spos: setting %s rate to %u\n",
 588		scb_name, rate);
 589
 590	/*
 591	 *  Compute the values used to drive the actual sample rate conversion.
 592	 *  The following formulas are being computed, using inline assembly
 593	 *  since we need to use 64 bit arithmetic to compute the values:
 594	 *
 595	 *  phiIncr = floor((Fs,in * 2^26) / Fs,out)
 596	 *  correctionPerGOF = floor((Fs,in * 2^26 - Fs,out * phiIncr) /
 597	 *                                   GOF_PER_SEC)
 598	 *  ulCorrectionPerSec = Fs,in * 2^26 - Fs,out * phiIncr -M
 599	 *                       GOF_PER_SEC * correctionPerGOF
 600	 *
 601	 *  i.e.
 602	 *
 603	 *  phiIncr:other = dividend:remainder((Fs,in * 2^26) / Fs,out)
 604	 *  correctionPerGOF:correctionPerSec =
 605	 *      dividend:remainder(ulOther / GOF_PER_SEC)
 606	 */
 607	tmp1 = rate << 16;
 608	phiIncr = tmp1 / 48000;
 609	tmp1 -= phiIncr * 48000;
 610	tmp1 <<= 10;
 611	phiIncr <<= 10;
 612	tmp2 = tmp1 / 48000;
 613	phiIncr += tmp2;
 614	tmp1 -= tmp2 * 48000;
 615	correctionPerGOF = tmp1 / GOF_PER_SEC;
 616	tmp1 -= correctionPerGOF * GOF_PER_SEC;
 617	correctionPerSec = tmp1;
 618
 619	{
 620		struct dsp_src_task_scb src_task_scb = {
 621			0x0028,0x00c8,
 622			0x5555,0x0000,
 623			0x0000,0x0000,
 624			src_buffer_addr,1,
 625			correctionPerGOF,correctionPerSec,
 626			RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,  
 627			0x0000,src_delay_buffer_addr,                  
 628			0x0,                                            
 629			0x080,(src_delay_buffer_addr + (24 * 4)),
 630			0,0, /* next_scb, sub_list_ptr */
 631			0,0, /* entry, this_spb */
 632			RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
 633			src_buffer_addr << 0x10,
 634			phiIncr,
 635			{ 
 636				0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left,
 637				0xffff - ins->dac_volume_right,0xffff - ins->dac_volume_left
 638			}
 639		};
 640		
 641		if (ins->s16_up == NULL) {
 642			ins->s16_up =  cs46xx_dsp_lookup_symbol (chip,"S16_UPSRC",
 643								 SYMBOL_CODE);
 644			
 645			if (ins->s16_up == NULL) {
 646				dev_err(chip->card->dev,
 647					"dsp_spos: symbol S16_UPSRC not found\n");
 648				return NULL;
 649			}    
 650		}
 651		
 652		/* clear buffers */
 653		_dsp_clear_sample_buffer (chip,src_buffer_addr,8);
 654		_dsp_clear_sample_buffer (chip,src_delay_buffer_addr,32);
 655				
 656		if (pass_through) {
 657			/* wont work with any other rate than
 658			   the native DSP rate */
 659			snd_BUG_ON(rate != 48000);
 660
 661			scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
 662							    dest,"DMAREADER",parent_scb,
 663							    scb_child_type);
 664		} else {
 665			scb = _dsp_create_generic_scb(chip,scb_name,(u32 *)&src_task_scb,
 666						      dest,ins->s16_up,parent_scb,
 667						      scb_child_type);
 668		}
 669
 670
 671	}
 672
 673	return scb;
 674}
 675
 676#if 0 /* not used */
 677struct dsp_scb_descriptor * 
 678cs46xx_dsp_create_filter_scb(struct snd_cs46xx * chip, char * scb_name,
 679			     u16 buffer_addr, u32 dest,
 680			     struct dsp_scb_descriptor * parent_scb,
 681			     int scb_child_type) {
 682	struct dsp_scb_descriptor * scb;
 683	
 684	struct dsp_filter_scb filter_scb = {
 685		.a0_right            = 0x41a9,
 686		.a0_left             = 0x41a9,
 687		.a1_right            = 0xb8e4,
 688		.a1_left             = 0xb8e4,
 689		.a2_right            = 0x3e55,
 690		.a2_left             = 0x3e55,
 691		
 692		.filter_unused3      = 0x0000,
 693		.filter_unused2      = 0x0000,
 694
 695		.output_buf_ptr      = buffer_addr,
 696		.init                = 0x000,
 697
 698		.prev_sample_output1 = 0x00000000,
 699		.prev_sample_output2 = 0x00000000,
 700
 701		.prev_sample_input1  = 0x00000000,
 702		.prev_sample_input2  = 0x00000000,
 703
 704		.next_scb_ptr        = 0x0000,
 705		.sub_list_ptr        = 0x0000,
 706
 707		.entry_point         = 0x0000,
 708		.spb_ptr             = 0x0000,
 709
 710		.b0_right            = 0x0e38,
 711		.b0_left             = 0x0e38,
 712		.b1_right            = 0x1c71,
 713		.b1_left             = 0x1c71,
 714		.b2_right            = 0x0e38,
 715		.b2_left             = 0x0e38,
 716	};
 717
 718
 719	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&filter_scb,
 720					    dest,"FILTERTASK",parent_scb,
 721					    scb_child_type);
 722
 723 	return scb;
 724}
 725#endif /* not used */
 726
 727struct dsp_scb_descriptor * 
 728cs46xx_dsp_create_mix_only_scb(struct snd_cs46xx * chip, char * scb_name,
 729                               u16 mix_buffer_addr, u32 dest,
 730                               struct dsp_scb_descriptor * parent_scb,
 731                               int scb_child_type)
 732{
 733	struct dsp_scb_descriptor * scb;
 734  
 735	struct dsp_mix_only_scb master_mix_scb = {
 736		/* 0 */ { 0,
 737			  /* 1 */   0,
 738			  /* 2 */  mix_buffer_addr,
 739			  /* 3 */  0
 740			  /*   */ },
 741		{
 742			/* 4 */  0,
 743			/* 5 */  0,
 744			/* 6 */  0,
 745			/* 7 */  0,
 746			/* 8 */  0x00000080
 747		},
 748		/* 9 */ 0,0,
 749		/* A */ 0,0,
 750		/* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_32,
 751		/* C */ (mix_buffer_addr  + (16 * 4)) << 0x10, 
 752		/* D */ 0,
 753		{
 754			/* E */ 0x8000,0x8000,
 755			/* F */ 0x8000,0x8000
 756		}
 757	};
 758
 759
 760	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&master_mix_scb,
 761					    dest,"S16_MIX",parent_scb,
 762					    scb_child_type);
 763	return scb;
 764}
 765
 766
 767struct dsp_scb_descriptor * 
 768cs46xx_dsp_create_mix_to_ostream_scb(struct snd_cs46xx * chip, char * scb_name,
 769                                     u16 mix_buffer_addr, u16 writeback_spb, u32 dest,
 770                                     struct dsp_scb_descriptor * parent_scb,
 771                                     int scb_child_type)
 772{
 773	struct dsp_scb_descriptor * scb;
 774
 775	struct dsp_mix2_ostream_scb mix2_ostream_scb = {
 776		/* Basic (non scatter/gather) DMA requestor (4 ints) */
 777		{ 
 778			DMA_RQ_C1_SOURCE_MOD64 +
 779			DMA_RQ_C1_DEST_ON_HOST +
 780			DMA_RQ_C1_DEST_MOD1024 +
 781			DMA_RQ_C1_WRITEBACK_SRC_FLAG + 
 782			DMA_RQ_C1_WRITEBACK_DEST_FLAG +
 783			15,                            
 784      
 785			DMA_RQ_C2_AC_NONE +
 786			DMA_RQ_C2_SIGNAL_DEST_PINGPONG + 
 787      
 788			CS46XX_DSP_CAPTURE_CHANNEL,                                 
 789			DMA_RQ_SD_SP_SAMPLE_ADDR + 
 790			mix_buffer_addr, 
 791			0x0                   
 792		},
 793    
 794		{ 0, 0, 0, 0, 0, },
 795		0,0,
 796		0,writeback_spb,
 797    
 798		RSCONFIG_DMA_ENABLE + 
 799		(19 << RSCONFIG_MAX_DMA_SIZE_SHIFT) + 
 800    
 801		((dest >> 4) << RSCONFIG_STREAM_NUM_SHIFT) +
 802		RSCONFIG_DMA_TO_HOST + 
 803		RSCONFIG_SAMPLE_16STEREO +
 804		RSCONFIG_MODULO_64,    
 805		(mix_buffer_addr + (32 * 4)) << 0x10,
 806		1,0,            
 807		0x0001,0x0080,
 808		0xFFFF,0
 809	};
 810
 811
 812	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&mix2_ostream_scb,
 813				
 814	    dest,"S16_MIX_TO_OSTREAM",parent_scb,
 815					    scb_child_type);
 816  
 817	return scb;
 818}
 819
 820
 821struct dsp_scb_descriptor * 
 822cs46xx_dsp_create_vari_decimate_scb(struct snd_cs46xx * chip,char * scb_name,
 823                                    u16 vari_buffer_addr0,
 824                                    u16 vari_buffer_addr1,
 825                                    u32 dest,
 826                                    struct dsp_scb_descriptor * parent_scb,
 827                                    int scb_child_type)
 828{
 829
 830	struct dsp_scb_descriptor * scb;
 831  
 832	struct dsp_vari_decimate_scb vari_decimate_scb = {
 833		0x0028,0x00c8,
 834		0x5555,0x0000,
 835		0x0000,0x0000,
 836		vari_buffer_addr0,vari_buffer_addr1,
 837    
 838		0x0028,0x00c8,
 839		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256, 
 840    
 841		0xFF800000,   
 842		0,
 843		0x0080,vari_buffer_addr1 + (25 * 4), 
 844    
 845		0,0, 
 846		0,0,
 847
 848		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_8,
 849		vari_buffer_addr0 << 0x10,   
 850		0x04000000,                   
 851		{
 852			0x8000,0x8000, 
 853			0xFFFF,0xFFFF
 854		}
 855	};
 856
 857	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&vari_decimate_scb,
 858					    dest,"VARIDECIMATE",parent_scb,
 859					    scb_child_type);
 860  
 861	return scb;
 862}
 863
 864
 865static struct dsp_scb_descriptor * 
 866cs46xx_dsp_create_pcm_serial_input_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
 867                                       struct dsp_scb_descriptor * input_scb,
 868                                       struct dsp_scb_descriptor * parent_scb,
 869                                       int scb_child_type)
 870{
 871
 872	struct dsp_scb_descriptor * scb;
 873
 874
 875	struct dsp_pcm_serial_input_scb pcm_serial_input_scb = {
 876		{ 0,
 877		  0,
 878		  0,
 879		  0
 880		},
 881		{
 882			0,
 883			0,
 884			0,
 885			0,
 886			0
 887		},
 888
 889		0,0,
 890		0,0,
 891
 892		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_16,
 893		0,
 894      /* 0xD */ 0,input_scb->address,
 895		{
 896      /* 0xE */   0x8000,0x8000,
 897      /* 0xF */	  0x8000,0x8000
 898		}
 899	};
 900
 901	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&pcm_serial_input_scb,
 902					    dest,"PCMSERIALINPUTTASK",parent_scb,
 903					    scb_child_type);
 904	return scb;
 905}
 906
 907
 908static struct dsp_scb_descriptor * 
 909cs46xx_dsp_create_asynch_fg_tx_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
 910                                   u16 hfg_scb_address,
 911                                   u16 asynch_buffer_address,
 912                                   struct dsp_scb_descriptor * parent_scb,
 913                                   int scb_child_type)
 914{
 915
 916	struct dsp_scb_descriptor * scb;
 917
 918	struct dsp_asynch_fg_tx_scb asynch_fg_tx_scb = {
 919		0xfc00,0x03ff,      /*  Prototype sample buffer size of 256 dwords */
 920		0x0058,0x0028,      /* Min Delta 7 dwords == 28 bytes */
 921		/* : Max delta 25 dwords == 100 bytes */
 922		0,hfg_scb_address,  /* Point to HFG task SCB */
 923		0,0,		    /* Initialize current Delta and Consumer ptr adjustment count */
 924		0,                  /* Initialize accumulated Phi to 0 */
 925		0,0x2aab,           /* Const 1/3 */
 926    
 927		{
 928			0,         /* Define the unused elements */
 929			0,
 930			0
 931		},
 932    
 933		0,0,
 934		0,dest + AFGTxAccumPhi,
 935    
 936		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256, /* Stereo, 256 dword */
 937		(asynch_buffer_address) << 0x10,  /* This should be automagically synchronized
 938                                                     to the producer pointer */
 939    
 940		/* There is no correct initial value, it will depend upon the detected
 941		   rate etc  */
 942		0x18000000,                     /* Phi increment for approx 32k operation */
 943		0x8000,0x8000,                  /* Volume controls are unused at this time */
 944		0x8000,0x8000
 945	};
 946  
 947	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_tx_scb,
 948					    dest,"ASYNCHFGTXCODE",parent_scb,
 949					    scb_child_type);
 950
 951	return scb;
 952}
 953
 954
 955struct dsp_scb_descriptor * 
 956cs46xx_dsp_create_asynch_fg_rx_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
 957                                   u16 hfg_scb_address,
 958                                   u16 asynch_buffer_address,
 959                                   struct dsp_scb_descriptor * parent_scb,
 960                                   int scb_child_type)
 961{
 962	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
 963	struct dsp_scb_descriptor * scb;
 964
 965	struct dsp_asynch_fg_rx_scb asynch_fg_rx_scb = {
 966		0xfe00,0x01ff,      /*  Prototype sample buffer size of 128 dwords */
 967		0x0064,0x001c,      /* Min Delta 7 dwords == 28 bytes */
 968		                    /* : Max delta 25 dwords == 100 bytes */
 969		0,hfg_scb_address,  /* Point to HFG task SCB */
 970		0,0,				/* Initialize current Delta and Consumer ptr adjustment count */
 971		{
 972			0,                /* Define the unused elements */
 973			0,
 974			0,
 975			0,
 976			0
 977		},
 978      
 979		0,0,
 980		0,dest,
 981    
 982		RSCONFIG_MODULO_128 |
 983        RSCONFIG_SAMPLE_16STEREO,                         /* Stereo, 128 dword */
 984		( (asynch_buffer_address + (16 * 4))  << 0x10),   /* This should be automagically 
 985							                                  synchrinized to the producer pointer */
 986    
 987		/* There is no correct initial value, it will depend upon the detected
 988		   rate etc  */
 989		0x18000000,         
 990
 991		/* Set IEC958 input volume */
 992		0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
 993		0xffff - ins->spdif_input_volume_right,0xffff - ins->spdif_input_volume_left,
 994	};
 995
 996	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_rx_scb,
 997					    dest,"ASYNCHFGRXCODE",parent_scb,
 998					    scb_child_type);
 999
1000	return scb;
1001}
1002
1003
1004#if 0 /* not used */
1005struct dsp_scb_descriptor * 
1006cs46xx_dsp_create_output_snoop_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1007                                   u16 snoop_buffer_address,
1008                                   struct dsp_scb_descriptor * snoop_scb,
1009                                   struct dsp_scb_descriptor * parent_scb,
1010                                   int scb_child_type)
1011{
1012
1013	struct dsp_scb_descriptor * scb;
1014  
1015	struct dsp_output_snoop_scb output_snoop_scb = {
1016		{ 0,	/*  not used.  Zero */
1017		  0,
1018		  0,
1019		  0,
1020		},
1021		{
1022			0, /* not used.  Zero */
1023			0,
1024			0,
1025			0,
1026			0
1027		},
1028    
1029		0,0,
1030		0,0,
1031    
1032		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
1033		snoop_buffer_address << 0x10,  
1034		0,0,
1035		0,
1036		0,snoop_scb->address
1037	};
1038  
1039	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&output_snoop_scb,
1040					    dest,"OUTPUTSNOOP",parent_scb,
1041					    scb_child_type);
1042	return scb;
1043}
1044#endif /* not used */
1045
1046
1047struct dsp_scb_descriptor * 
1048cs46xx_dsp_create_spio_write_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1049                                 struct dsp_scb_descriptor * parent_scb,
1050                                 int scb_child_type)
1051{
1052	struct dsp_scb_descriptor * scb;
1053  
1054	struct dsp_spio_write_scb spio_write_scb = {
1055		0,0,         /*   SPIOWAddress2:SPIOWAddress1; */
1056		0,           /*   SPIOWData1; */
1057		0,           /*   SPIOWData2; */
1058		0,0,         /*   SPIOWAddress4:SPIOWAddress3; */
1059		0,           /*   SPIOWData3; */
1060		0,           /*   SPIOWData4; */
1061		0,0,         /*   SPIOWDataPtr:Unused1; */
1062		{ 0,0 },     /*   Unused2[2]; */
1063    
1064		0,0,	     /*   SPIOWChildPtr:SPIOWSiblingPtr; */
1065		0,0,         /*   SPIOWThisPtr:SPIOWEntryPoint; */
1066    
1067		{ 
1068			0,
1069			0,
1070			0,
1071			0,
1072			0          /*   Unused3[5];  */
1073		}
1074	};
1075
1076	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&spio_write_scb,
1077					    dest,"SPIOWRITE",parent_scb,
1078					    scb_child_type);
1079
1080	return scb;
1081}
1082
1083struct dsp_scb_descriptor *
1084cs46xx_dsp_create_magic_snoop_scb(struct snd_cs46xx * chip, char * scb_name, u32 dest,
1085				  u16 snoop_buffer_address,
1086				  struct dsp_scb_descriptor * snoop_scb,
1087				  struct dsp_scb_descriptor * parent_scb,
1088				  int scb_child_type)
1089{
1090	struct dsp_scb_descriptor * scb;
1091  
1092	struct dsp_magic_snoop_task magic_snoop_scb = {
1093		/* 0 */ 0, /* i0 */
1094		/* 1 */ 0, /* i1 */
1095		/* 2 */ snoop_buffer_address << 0x10,
1096		/* 3 */ 0,snoop_scb->address,
1097		/* 4 */ 0, /* i3 */
1098		/* 5 */ 0, /* i4 */
1099		/* 6 */ 0, /* i5 */
1100		/* 7 */ 0, /* i6 */
1101		/* 8 */ 0, /* i7 */
1102		/* 9 */ 0,0, /* next_scb, sub_list_ptr */
1103		/* A */ 0,0, /* entry_point, this_ptr */
1104		/* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64,
1105		/* C */ snoop_buffer_address  << 0x10,
1106		/* D */ 0,
1107		/* E */ { 0x8000,0x8000,
1108	        /* F */   0xffff,0xffff
1109		}
1110	};
1111
1112	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&magic_snoop_scb,
1113					    dest,"MAGICSNOOPTASK",parent_scb,
1114					    scb_child_type);
1115
1116	return scb;
1117}
1118
1119static struct dsp_scb_descriptor *
1120find_next_free_scb (struct snd_cs46xx * chip, struct dsp_scb_descriptor * from)
1121{
1122	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1123	struct dsp_scb_descriptor * scb = from;
1124
1125	while (scb->next_scb_ptr != ins->the_null_scb) {
1126		if (snd_BUG_ON(!scb->next_scb_ptr))
1127			return NULL;
1128
1129		scb = scb->next_scb_ptr;
1130	}
1131
1132	return scb;
1133}
1134
1135static const u32 pcm_reader_buffer_addr[DSP_MAX_PCM_CHANNELS] = {
1136	0x0600, /* 1 */
1137	0x1500, /* 2 */
1138	0x1580, /* 3 */
1139	0x1600, /* 4 */
1140	0x1680, /* 5 */
1141	0x1700, /* 6 */
1142	0x1780, /* 7 */
1143	0x1800, /* 8 */
1144	0x1880, /* 9 */
1145	0x1900, /* 10 */
1146	0x1980, /* 11 */
1147	0x1A00, /* 12 */
1148	0x1A80, /* 13 */
1149	0x1B00, /* 14 */
1150	0x1B80, /* 15 */
1151	0x1C00, /* 16 */
1152	0x1C80, /* 17 */
1153	0x1D00, /* 18 */
1154	0x1D80, /* 19 */
1155	0x1E00, /* 20 */
1156	0x1E80, /* 21 */
1157	0x1F00, /* 22 */
1158	0x1F80, /* 23 */
1159	0x2000, /* 24 */
1160	0x2080, /* 25 */
1161	0x2100, /* 26 */
1162	0x2180, /* 27 */
1163	0x2200, /* 28 */
1164	0x2280, /* 29 */
1165	0x2300, /* 30 */
1166	0x2380, /* 31 */
1167	0x2400, /* 32 */
1168};
1169
1170static const u32 src_output_buffer_addr[DSP_MAX_SRC_NR] = {
1171	0x2B80,
1172	0x2BA0,
1173	0x2BC0,
1174	0x2BE0,
1175	0x2D00,  
1176	0x2D20,  
1177	0x2D40,  
1178	0x2D60,
1179	0x2D80,
1180	0x2DA0,
1181	0x2DC0,
1182	0x2DE0,
1183	0x2E00,
1184	0x2E20
1185};
1186
1187static const u32 src_delay_buffer_addr[DSP_MAX_SRC_NR] = {
1188	0x2480,
1189	0x2500,
1190	0x2580,
1191	0x2600,
1192	0x2680,
1193	0x2700,
1194	0x2780,
1195	0x2800,
1196	0x2880,
1197	0x2900,
1198	0x2980,
1199	0x2A00,
1200	0x2A80,
1201	0x2B00
1202};
1203
1204struct dsp_pcm_channel_descriptor *
1205cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip,
1206			       u32 sample_rate, void * private_data, 
1207			       u32 hw_dma_addr,
1208			       int pcm_channel_id)
1209{
1210	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1211	struct dsp_scb_descriptor * src_scb = NULL, * pcm_scb, * mixer_scb = NULL;
1212	struct dsp_scb_descriptor * src_parent_scb = NULL;
1213
1214	/* struct dsp_scb_descriptor * pcm_parent_scb; */
1215	char scb_name[DSP_MAX_SCB_NAME];
1216	int i, pcm_index = -1, insert_point, src_index = -1, pass_through = 0;
1217
1218	switch (pcm_channel_id) {
1219	case DSP_PCM_MAIN_CHANNEL:
1220		mixer_scb = ins->master_mix_scb;
1221		break;
1222	case DSP_PCM_REAR_CHANNEL:
1223		mixer_scb = ins->rear_mix_scb;
1224		break;
1225	case DSP_PCM_CENTER_LFE_CHANNEL:
1226		mixer_scb = ins->center_lfe_mix_scb;
1227		break;
1228	case DSP_PCM_S71_CHANNEL:
1229		/* TODO */
1230		snd_BUG();
1231		break;
1232	case DSP_IEC958_CHANNEL:
1233		if (snd_BUG_ON(!ins->asynch_tx_scb))
1234			return NULL;
1235		mixer_scb = ins->asynch_tx_scb;
1236
1237		/* if sample rate is set to 48khz we pass
1238		   the Sample Rate Converted (which could
1239		   alter the raw data stream ...) */
1240		if (sample_rate == 48000) {
1241			dev_dbg(chip->card->dev, "IEC958 pass through\n");
1242			/* Hack to bypass creating a new SRC */
1243			pass_through = 1;
1244		}
1245		break;
1246	default:
1247		snd_BUG();
1248		return NULL;
1249	}
1250	/* default sample rate is 44100 */
1251	if (!sample_rate) sample_rate = 44100;
1252
1253	/* search for a already created SRC SCB with the same sample rate */
1254	for (i = 0; i < DSP_MAX_PCM_CHANNELS && 
1255		     (pcm_index == -1 || src_scb == NULL); ++i) {
1256
1257		/* virtual channel reserved 
1258		   for capture */
1259		if (i == CS46XX_DSP_CAPTURE_CHANNEL) continue;
1260
1261		if (ins->pcm_channels[i].active) {
1262			if (!src_scb && 
1263			    ins->pcm_channels[i].sample_rate == sample_rate &&
1264			    ins->pcm_channels[i].mixer_scb == mixer_scb) {
1265				src_scb = ins->pcm_channels[i].src_scb;
1266				ins->pcm_channels[i].src_scb->ref_count ++;
1267				src_index = ins->pcm_channels[i].src_slot;
1268			}
1269		} else if (pcm_index == -1) {
1270			pcm_index = i;
1271		}
1272	}
1273
1274	if (pcm_index == -1) {
1275		dev_err(chip->card->dev, "dsp_spos: no free PCM channel\n");
1276		return NULL;
1277	}
1278
1279	if (src_scb == NULL) {
1280		if (ins->nsrc_scb >= DSP_MAX_SRC_NR) {
1281			dev_err(chip->card->dev,
1282				"dsp_spos: too many SRC instances\n!");
1283			return NULL;
1284		}
1285
1286		/* find a free slot */
1287		for (i = 0; i < DSP_MAX_SRC_NR; ++i) {
1288			if (ins->src_scb_slots[i] == 0) {
1289				src_index = i;
1290				ins->src_scb_slots[i] = 1;
1291				break;
1292			}
1293		}
1294		if (snd_BUG_ON(src_index == -1))
1295			return NULL;
1296
1297		/* we need to create a new SRC SCB */
1298		if (mixer_scb->sub_list_ptr == ins->the_null_scb) {
1299			src_parent_scb = mixer_scb;
1300			insert_point = SCB_ON_PARENT_SUBLIST_SCB;
1301		} else {
1302			src_parent_scb = find_next_free_scb(chip,mixer_scb->sub_list_ptr);
1303			insert_point = SCB_ON_PARENT_NEXT_SCB;
1304		}
1305
1306		snprintf (scb_name,DSP_MAX_SCB_NAME,"SrcTask_SCB%d",src_index);
1307		
1308		dev_dbg(chip->card->dev,
1309			"dsp_spos: creating SRC \"%s\"\n", scb_name);
1310		src_scb = cs46xx_dsp_create_src_task_scb(chip,scb_name,
1311							 sample_rate,
1312							 src_output_buffer_addr[src_index],
1313							 src_delay_buffer_addr[src_index],
1314							 /* 0x400 - 0x600 source SCBs */
1315							 0x400 + (src_index * 0x10) ,
1316							 src_parent_scb,
1317							 insert_point,
1318							 pass_through);
1319
1320		if (!src_scb) {
1321			dev_err(chip->card->dev,
1322				"dsp_spos: failed to create SRCtaskSCB\n");
1323			return NULL;
1324		}
1325
1326		/* cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate); */
1327
1328		ins->nsrc_scb ++;
1329	} 
1330  
1331  
1332	snprintf (scb_name,DSP_MAX_SCB_NAME,"PCMReader_SCB%d",pcm_index);
1333
1334	dev_dbg(chip->card->dev, "dsp_spos: creating PCM \"%s\" (%d)\n",
1335		scb_name, pcm_channel_id);
1336
1337	pcm_scb = cs46xx_dsp_create_pcm_reader_scb(chip,scb_name,
1338						   pcm_reader_buffer_addr[pcm_index],
1339						   /* 0x200 - 400 PCMreader SCBs */
1340						   (pcm_index * 0x10) + 0x200,
1341						   pcm_index,    /* virtual channel 0-31 */
1342						   hw_dma_addr,  /* pcm hw addr */
1343                           NULL,         /* parent SCB ptr */
1344                           0             /* insert point */ 
1345                           );
1346
1347	if (!pcm_scb) {
1348		dev_err(chip->card->dev,
1349			"dsp_spos: failed to create PCMreaderSCB\n");
1350		return NULL;
1351	}
1352	
1353	guard(spinlock_irqsave)(&chip->reg_lock);
1354	ins->pcm_channels[pcm_index].sample_rate = sample_rate;
1355	ins->pcm_channels[pcm_index].pcm_reader_scb = pcm_scb;
1356	ins->pcm_channels[pcm_index].src_scb = src_scb;
1357	ins->pcm_channels[pcm_index].unlinked = 1;
1358	ins->pcm_channels[pcm_index].private_data = private_data;
1359	ins->pcm_channels[pcm_index].src_slot = src_index;
1360	ins->pcm_channels[pcm_index].active = 1;
1361	ins->pcm_channels[pcm_index].pcm_slot = pcm_index;
1362	ins->pcm_channels[pcm_index].mixer_scb = mixer_scb;
1363	ins->npcm_channels ++;
1364
1365	return (ins->pcm_channels + pcm_index);
1366}
1367
1368int cs46xx_dsp_pcm_channel_set_period (struct snd_cs46xx * chip,
1369				       struct dsp_pcm_channel_descriptor * pcm_channel,
1370				       int period_size)
1371{
1372	u32 temp = snd_cs46xx_peek (chip,pcm_channel->pcm_reader_scb->address << 2);
1373	temp &= ~DMA_RQ_C1_SOURCE_SIZE_MASK;
1374
1375	switch (period_size) {
1376	case 2048:
1377		temp |= DMA_RQ_C1_SOURCE_MOD1024;
1378		break;
1379	case 1024:
1380		temp |= DMA_RQ_C1_SOURCE_MOD512;
1381		break;
1382	case 512:
1383		temp |= DMA_RQ_C1_SOURCE_MOD256;
1384		break;
1385	case 256:
1386		temp |= DMA_RQ_C1_SOURCE_MOD128;
1387		break;
1388	case 128:
1389		temp |= DMA_RQ_C1_SOURCE_MOD64;
1390		break;
1391	case 64:
1392		temp |= DMA_RQ_C1_SOURCE_MOD32;
1393		break;		      
1394	case 32:
1395		temp |= DMA_RQ_C1_SOURCE_MOD16;
1396		break; 
1397	default:
1398		dev_dbg(chip->card->dev,
1399			"period size (%d) not supported by HW\n", period_size);
1400		return -EINVAL;
1401	}
1402
1403	snd_cs46xx_poke (chip,pcm_channel->pcm_reader_scb->address << 2,temp);
1404
1405	return 0;
1406}
1407
1408int cs46xx_dsp_pcm_ostream_set_period (struct snd_cs46xx * chip,
1409				       int period_size)
1410{
1411	u32 temp = snd_cs46xx_peek (chip,WRITEBACK_SCB_ADDR << 2);
1412	temp &= ~DMA_RQ_C1_DEST_SIZE_MASK;
1413
1414	switch (period_size) {
1415	case 2048:
1416		temp |= DMA_RQ_C1_DEST_MOD1024;
1417		break;
1418	case 1024:
1419		temp |= DMA_RQ_C1_DEST_MOD512;
1420		break;
1421	case 512:
1422		temp |= DMA_RQ_C1_DEST_MOD256;
1423		break;
1424	case 256:
1425		temp |= DMA_RQ_C1_DEST_MOD128;
1426		break;
1427	case 128:
1428		temp |= DMA_RQ_C1_DEST_MOD64;
1429		break;
1430	case 64:
1431		temp |= DMA_RQ_C1_DEST_MOD32;
1432		break;		      
1433	case 32:
1434		temp |= DMA_RQ_C1_DEST_MOD16;
1435		break; 
1436	default:
1437		dev_dbg(chip->card->dev,
1438			"period size (%d) not supported by HW\n", period_size);
1439		return -EINVAL;
1440	}
1441
1442	snd_cs46xx_poke (chip,WRITEBACK_SCB_ADDR << 2,temp);
1443
1444	return 0;
1445}
1446
1447void cs46xx_dsp_destroy_pcm_channel (struct snd_cs46xx * chip,
1448				     struct dsp_pcm_channel_descriptor * pcm_channel)
1449{
1450	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1451
1452	if (snd_BUG_ON(!pcm_channel->active ||
1453		       ins->npcm_channels <= 0 ||
1454		       pcm_channel->src_scb->ref_count <= 0))
1455		return;
1456
1457	scoped_guard(spinlock_irqsave, &chip->reg_lock) {
1458		pcm_channel->unlinked = 1;
1459		pcm_channel->active = 0;
1460		pcm_channel->private_data = NULL;
1461		pcm_channel->src_scb->ref_count--;
1462		ins->npcm_channels--;
1463	}
1464
1465	cs46xx_dsp_remove_scb(chip,pcm_channel->pcm_reader_scb);
1466
1467	if (!pcm_channel->src_scb->ref_count) {
1468		cs46xx_dsp_remove_scb(chip,pcm_channel->src_scb);
1469
1470		if (snd_BUG_ON(pcm_channel->src_slot < 0 ||
1471			       pcm_channel->src_slot >= DSP_MAX_SRC_NR))
1472			return;
1473
1474		ins->src_scb_slots[pcm_channel->src_slot] = 0;
1475		ins->nsrc_scb --;
1476	}
1477}
1478
1479int cs46xx_dsp_pcm_unlink (struct snd_cs46xx * chip,
1480			   struct dsp_pcm_channel_descriptor * pcm_channel)
1481{
1482	if (snd_BUG_ON(!pcm_channel->active ||
1483		       chip->dsp_spos_instance->npcm_channels <= 0))
1484		return -EIO;
1485
1486	guard(spinlock_irqsave)(&chip->reg_lock);
1487	if (pcm_channel->unlinked)
1488		return -EIO;
1489
1490	pcm_channel->unlinked = 1;
1491
1492	_dsp_unlink_scb (chip,pcm_channel->pcm_reader_scb);
1493
1494	return 0;
1495}
1496
1497int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip,
1498			 struct dsp_pcm_channel_descriptor * pcm_channel)
1499{
1500	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1501	struct dsp_scb_descriptor * parent_scb;
1502	struct dsp_scb_descriptor * src_scb = pcm_channel->src_scb;
1503
1504	guard(spinlock_irqsave)(&chip->reg_lock);
1505
1506	if (pcm_channel->unlinked == 0)
1507		return -EIO;
1508
1509	parent_scb = src_scb;
1510
1511	if (src_scb->sub_list_ptr != ins->the_null_scb) {
1512		src_scb->sub_list_ptr->parent_scb_ptr = pcm_channel->pcm_reader_scb;
1513		pcm_channel->pcm_reader_scb->next_scb_ptr = src_scb->sub_list_ptr;
1514	}
1515
1516	src_scb->sub_list_ptr = pcm_channel->pcm_reader_scb;
1517
1518	snd_BUG_ON(pcm_channel->pcm_reader_scb->parent_scb_ptr);
1519	pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb;
1520
1521	/* update SCB entry in DSP RAM */
1522	cs46xx_dsp_spos_update_scb(chip,pcm_channel->pcm_reader_scb);
1523
1524	/* update parent SCB entry */
1525	cs46xx_dsp_spos_update_scb(chip,parent_scb);
1526
1527	pcm_channel->unlinked = 0;
1528	return 0;
1529}
1530
1531struct dsp_scb_descriptor *
1532cs46xx_add_record_source (struct snd_cs46xx *chip, struct dsp_scb_descriptor * source,
1533			  u16 addr, char * scb_name)
1534{
1535  	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1536	struct dsp_scb_descriptor * parent;
1537	struct dsp_scb_descriptor * pcm_input;
1538	int insert_point;
1539
1540	if (snd_BUG_ON(!ins->record_mixer_scb))
1541		return NULL;
1542
1543	if (ins->record_mixer_scb->sub_list_ptr != ins->the_null_scb) {
1544		parent = find_next_free_scb (chip,ins->record_mixer_scb->sub_list_ptr);
1545		insert_point = SCB_ON_PARENT_NEXT_SCB;
1546	} else {
1547		parent = ins->record_mixer_scb;
1548		insert_point = SCB_ON_PARENT_SUBLIST_SCB;
1549	}
1550
1551	pcm_input = cs46xx_dsp_create_pcm_serial_input_scb(chip,scb_name,addr,
1552							   source, parent,
1553							   insert_point);
1554
1555	return pcm_input;
1556}
1557
1558int cs46xx_src_unlink(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
1559{
1560	if (snd_BUG_ON(!src->parent_scb_ptr))
1561		return -EINVAL;
1562
1563	/* mute SCB */
1564	cs46xx_dsp_scb_set_volume (chip,src,0,0);
1565
1566	guard(spinlock_irqsave)(&chip->reg_lock);
1567	_dsp_unlink_scb (chip,src);
1568
1569	return 0;
1570}
1571
1572int cs46xx_src_link(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src)
1573{
1574	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1575	struct dsp_scb_descriptor * parent_scb;
1576
1577	if (snd_BUG_ON(src->parent_scb_ptr))
1578		return -EINVAL;
1579	if (snd_BUG_ON(!ins->master_mix_scb))
1580		return -EINVAL;
1581
1582	if (ins->master_mix_scb->sub_list_ptr != ins->the_null_scb) {
1583		parent_scb = find_next_free_scb (chip,ins->master_mix_scb->sub_list_ptr);
1584		parent_scb->next_scb_ptr = src;
1585	} else {
1586		parent_scb = ins->master_mix_scb;
1587		parent_scb->sub_list_ptr = src;
1588	}
1589
1590	src->parent_scb_ptr = parent_scb;
1591
1592	/* update entry in DSP RAM */
1593	cs46xx_dsp_spos_update_scb(chip,parent_scb);
1594  
1595	return 0;
1596}
1597
1598int cs46xx_dsp_enable_spdif_out (struct snd_cs46xx *chip)
1599{
1600	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1601
1602	if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
1603		cs46xx_dsp_enable_spdif_hw (chip);
1604	}
1605
1606	/* dont touch anything if SPDIF is open */
1607	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
1608		/* when cs46xx_iec958_post_close(...) is called it
1609		   will call this function if necessary depending on
1610		   this bit */
1611		ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1612
1613		return -EBUSY;
1614	}
1615
1616	if (snd_BUG_ON(ins->asynch_tx_scb))
1617		return -EINVAL;
1618	if (snd_BUG_ON(ins->master_mix_scb->next_scb_ptr !=
1619		       ins->the_null_scb))
1620		return -EINVAL;
1621
1622	/* reset output snooper sample buffer pointer */
1623	snd_cs46xx_poke (chip, (ins->ref_snoop_scb->address + 2) << 2,
1624			 (OUTPUT_SNOOP_BUFFER + 0x10) << 0x10 );
1625	
1626	/* The asynch. transfer task */
1627	ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
1628								SPDIFO_SCB_INST,
1629								SPDIFO_IP_OUTPUT_BUFFER1,
1630								ins->master_mix_scb,
1631								SCB_ON_PARENT_NEXT_SCB);
1632	if (!ins->asynch_tx_scb) return -ENOMEM;
1633
1634	ins->spdif_pcm_input_scb = cs46xx_dsp_create_pcm_serial_input_scb(chip,"PCMSerialInput_II",
1635									  PCMSERIALINII_SCB_ADDR,
1636									  ins->ref_snoop_scb,
1637									  ins->asynch_tx_scb,
1638									  SCB_ON_PARENT_SUBLIST_SCB);
1639  
1640	
1641	if (!ins->spdif_pcm_input_scb) return -ENOMEM;
1642
1643	/* monitor state */
1644	ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1645
1646	return 0;
1647}
1648
1649int  cs46xx_dsp_disable_spdif_out (struct snd_cs46xx *chip)
1650{
1651	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1652
1653	/* dont touch anything if SPDIF is open */
1654	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
1655		ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1656		return -EBUSY;
1657	}
1658
1659	/* check integrety */
1660	if (snd_BUG_ON(!ins->asynch_tx_scb))
1661		return -EINVAL;
1662	if (snd_BUG_ON(!ins->spdif_pcm_input_scb))
1663		return -EINVAL;
1664	if (snd_BUG_ON(ins->master_mix_scb->next_scb_ptr != ins->asynch_tx_scb))
1665		return -EINVAL;
1666	if (snd_BUG_ON(ins->asynch_tx_scb->parent_scb_ptr !=
1667		       ins->master_mix_scb))
1668		return -EINVAL;
1669
1670	cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
1671	cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
1672
1673	ins->spdif_pcm_input_scb = NULL;
1674	ins->asynch_tx_scb = NULL;
1675
1676	/* clear buffer to prevent any undesired noise */
1677	_dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
1678
1679	/* monitor state */
1680	ins->spdif_status_out  &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1681
1682
1683	return 0;
1684}
1685
1686int cs46xx_iec958_pre_open (struct snd_cs46xx *chip)
1687{
1688	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1689
1690	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
1691		/* remove AsynchFGTxSCB and PCMSerialInput_II */
1692		cs46xx_dsp_disable_spdif_out (chip);
1693
1694		/* save state */
1695		ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
1696	}
1697	
1698	/* if not enabled already */
1699	if ( !(ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
1700		cs46xx_dsp_enable_spdif_hw (chip);
1701	}
1702
1703	/* Create the asynch. transfer task  for playback */
1704	ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
1705								SPDIFO_SCB_INST,
1706								SPDIFO_IP_OUTPUT_BUFFER1,
1707								ins->master_mix_scb,
1708								SCB_ON_PARENT_NEXT_SCB);
1709
1710
1711	/* set spdif channel status value for streaming */
1712	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_stream);
1713
1714	ins->spdif_status_out  |= DSP_SPDIF_STATUS_PLAYBACK_OPEN;
1715
1716	return 0;
1717}
1718
1719int cs46xx_iec958_post_close (struct snd_cs46xx *chip)
1720{
1721	struct dsp_spos_instance * ins = chip->dsp_spos_instance;
1722
1723	if (snd_BUG_ON(!ins->asynch_tx_scb))
1724		return -EINVAL;
1725
1726	ins->spdif_status_out  &= ~DSP_SPDIF_STATUS_PLAYBACK_OPEN;
1727
1728	/* restore settings */
1729	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);
1730	
1731	/* deallocate stuff */
1732	if (ins->spdif_pcm_input_scb != NULL) {
1733		cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
1734		ins->spdif_pcm_input_scb = NULL;
1735	}
1736
1737	cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
1738	ins->asynch_tx_scb = NULL;
1739
1740	/* clear buffer to prevent any undesired noise */
1741	_dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
1742
1743	/* restore state */
1744	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
1745		cs46xx_dsp_enable_spdif_out (chip);
1746	}
1747	
1748	return 0;
1749}
~/ Read-only file preview.