xref: /linux/sound/pci/cs46xx/dsp_spos_scb_lib.c (revision 05a54fa773284d1a7923cdfdd8f0c8dabb98bd26)
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 
25 struct proc_scb_info {
26 	struct dsp_scb_descriptor * scb_desc;
27 	struct snd_cs46xx *chip;
28 };
29 
30 static 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
57 static 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 
97 static 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 
147 static 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 
159 void 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
206 void 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 
223 void 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 		}
249 out:
250 		scb->proc_info = entry;
251 	}
252 }
253 #endif /* CONFIG_SND_PROC_FS */
254 
255 static 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 
329 static struct dsp_scb_descriptor *
330 cs46xx_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 
350 struct dsp_scb_descriptor *
351 cs46xx_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 
384 struct dsp_scb_descriptor *
385 cs46xx_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 
422 struct dsp_scb_descriptor *
423 cs46xx_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 
467 static struct dsp_scb_descriptor *
468 cs46xx_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 
571 struct dsp_scb_descriptor *
572 cs46xx_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 */
677 struct dsp_scb_descriptor *
678 cs46xx_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 
727 struct dsp_scb_descriptor *
728 cs46xx_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 
767 struct dsp_scb_descriptor *
768 cs46xx_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 
821 struct dsp_scb_descriptor *
822 cs46xx_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 
865 static struct dsp_scb_descriptor *
866 cs46xx_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 
908 static struct dsp_scb_descriptor *
909 cs46xx_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 
955 struct dsp_scb_descriptor *
956 cs46xx_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 */
1005 struct dsp_scb_descriptor *
1006 cs46xx_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 
1047 struct dsp_scb_descriptor *
1048 cs46xx_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 
1083 struct dsp_scb_descriptor *
1084 cs46xx_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 
1119 static struct dsp_scb_descriptor *
1120 find_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 
1135 static 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 
1170 static 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 
1187 static 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 
1204 struct dsp_pcm_channel_descriptor *
1205 cs46xx_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 
1368 int 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 
1408 int 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 
1447 void 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 
1479 int 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 
1497 int 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 
1531 struct dsp_scb_descriptor *
1532 cs46xx_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 
1558 int 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 
1572 int 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 
1598 int 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 
1649 int  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 
1686 int 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 
1719 int 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 }
1750