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