📄 dsp_spos.c
字号:
if (!cs46xx_dsp_create_spio_write_scb(chip,"SPIOWriteSCB",SPIOWRITE_SCB_ADDR, magic_snoop_scb, SCB_ON_PARENT_NEXT_SCB)) goto _fail_end; /* SPDIF input sampel rate converter */ src_task_scb = cs46xx_dsp_create_src_task_scb(chip,"SrcTaskSCB_SPDIFI", ins->spdif_in_sample_rate, SRC_OUTPUT_BUF1, SRC_DELAY_BUF1,SRCTASK_SCB_ADDR, master_mix_scb, SCB_ON_PARENT_SUBLIST_SCB,1); if (!src_task_scb) goto _fail_end; cs46xx_src_unlink(chip,src_task_scb); /* NOTE: when we now how to detect the SPDIF input sample rate we will use this SRC to adjust it */ ins->spdif_in_src = src_task_scb; cs46xx_dsp_async_init(chip,timing_master_scb); return 0; _fail_end: snd_printk(KERN_ERR "dsp_spos: failed to setup SCB's in DSP\n"); return -EINVAL;}static int cs46xx_dsp_async_init (cs46xx_t *chip, dsp_scb_descriptor_t * fg_entry){ dsp_spos_instance_t * ins = chip->dsp_spos_instance; symbol_entry_t * s16_async_codec_input_task; symbol_entry_t * spdifo_task; symbol_entry_t * spdifi_task; dsp_scb_descriptor_t * spdifi_scb_desc,* spdifo_scb_desc,* async_codec_scb_desc; s16_async_codec_input_task = cs46xx_dsp_lookup_symbol(chip, "S16_ASYNCCODECINPUTTASK", SYMBOL_CODE); if (s16_async_codec_input_task == NULL) { snd_printk(KERN_ERR "dsp_spos: symbol S16_ASYNCCODECINPUTTASK not found\n"); return -EIO; } spdifo_task = cs46xx_dsp_lookup_symbol(chip, "SPDIFOTASK", SYMBOL_CODE); if (spdifo_task == NULL) { snd_printk(KERN_ERR "dsp_spos: symbol SPDIFOTASK not found\n"); return -EIO; } spdifi_task = cs46xx_dsp_lookup_symbol(chip, "SPDIFITASK", SYMBOL_CODE); if (spdifi_task == NULL) { snd_printk(KERN_ERR "dsp_spos: symbol SPDIFITASK not found\n"); return -EIO; } { /* 0xBC0 */ spdifoscb_t spdifo_scb = { /* 0 */ DSP_SPOS_UUUU, { /* 1 */ 0xb0, /* 2 */ 0, /* 3 */ 0, /* 4 */ 0, }, /* NOTE: the SPDIF output task read samples in mono format, the AsynchFGTxSCB task writes to buffer in stereo format */ /* 5 */ RSCONFIG_SAMPLE_16MONO + RSCONFIG_MODULO_256, /* 6 */ ( SPDIFO_IP_OUTPUT_BUFFER1 << 0x10 ) | 0xFFFC, /* 7 */ 0,0, /* 8 */ 0, /* 9 */ FG_TASK_HEADER_ADDR, NULL_SCB_ADDR, /* A */ spdifo_task->address, SPDIFO_SCB_INST + SPDIFOFIFOPointer, { /* B */ 0x0040, /*DSP_SPOS_UUUU,*/ /* C */ 0x20ff, /*DSP_SPOS_UUUU,*/ }, /* D */ 0x804c,0, /* SPDIFOFIFOPointer:SPDIFOStatRegAddr; */ /* E */ 0x0108,0x0001, /* SPDIFOStMoFormat:SPDIFOFIFOBaseAddr; */ /* F */ DSP_SPOS_UUUU /* SPDIFOFree; */ }; /* 0xBB0 */ spdifiscb_t spdifi_scb = { /* 0 */ DSP_SPOS_UULO,DSP_SPOS_UUHI, /* 1 */ 0, /* 2 */ 0, /* 3 */ 1,4000, /* SPDIFICountLimit SPDIFICount */ /* 4 */ DSP_SPOS_UUUU, /* SPDIFIStatusData */ /* 5 */ 0,DSP_SPOS_UUHI, /* StatusData, Free4 */ /* 6 */ DSP_SPOS_UUUU, /* Free3 */ /* 7 */ DSP_SPOS_UU,DSP_SPOS_DC, /* Free2 BitCount*/ /* 8 */ DSP_SPOS_UUUU, /* TempStatus */ /* 9 */ SPDIFO_SCB_INST, NULL_SCB_ADDR, /* A */ spdifi_task->address, SPDIFI_SCB_INST + SPDIFIFIFOPointer, /* NOTE: The SPDIF input task write the sample in mono format from the HW FIFO, the AsynchFGRxSCB task reads them in stereo */ /* B */ RSCONFIG_SAMPLE_16MONO + RSCONFIG_MODULO_128, /* C */ (SPDIFI_IP_OUTPUT_BUFFER1 << 0x10) | 0xFFFC, /* D */ 0x8048,0, /* E */ 0x01f0,0x0001, /* F */ DSP_SPOS_UUUU /* SPDIN_STATUS monitor */ }; /* 0xBA0 */ async_codec_input_scb_t async_codec_input_scb = { /* 0 */ DSP_SPOS_UUUU, /* 1 */ 0, /* 2 */ 0, /* 3 */ 1,4000, /* 4 */ 0x0118,0x0001, /* 5 */ RSCONFIG_SAMPLE_16MONO + RSCONFIG_MODULO_64, /* 6 */ (ASYNC_IP_OUTPUT_BUFFER1 << 0x10) | 0xFFFC, /* 7 */ DSP_SPOS_UU,0x3, /* 8 */ DSP_SPOS_UUUU, /* 9 */ SPDIFI_SCB_INST,NULL_SCB_ADDR, /* A */ s16_async_codec_input_task->address, HFG_TREE_SCB + AsyncCIOFIFOPointer, /* B */ RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_64, /* C */ (ASYNC_IP_OUTPUT_BUFFER1 << 0x10), /*(ASYNC_IP_OUTPUT_BUFFER1 << 0x10) | 0xFFFC,*/ #ifdef UseASER1Input /* short AsyncCIFIFOPointer:AsyncCIStatRegAddr; Init. 0000:8042: for ASER1 0000:8044: for ASER2 */ /* D */ 0x8042,0, /* short AsyncCIStMoFormat:AsyncCIFIFOBaseAddr; Init 1 stero:8050 ASER1 Init 0 mono:8070 ASER2 Init 1 Stereo : 0100 ASER1 (Set by script) */ /* E */ 0x0100,0x0001, #endif #ifdef UseASER2Input /* short AsyncCIFIFOPointer:AsyncCIStatRegAddr; Init. 0000:8042: for ASER1 0000:8044: for ASER2 */ /* D */ 0x8044,0, /* short AsyncCIStMoFormat:AsyncCIFIFOBaseAddr; Init 1 stero:8050 ASER1 Init 0 mono:8070 ASER2 Init 1 Stereo : 0100 ASER1 (Set by script) */ /* E */ 0x0110,0x0001, #endif /* short AsyncCIOutputBufModulo:AsyncCIFree; AsyncCIOutputBufModulo: The modulo size for the output buffer of this task */ /* F */ 0, /* DSP_SPOS_UUUU */ }; spdifo_scb_desc = cs46xx_dsp_create_scb(chip,"SPDIFOSCB",(u32 *)&spdifo_scb,SPDIFO_SCB_INST); snd_assert(spdifo_scb_desc, return -EIO); spdifi_scb_desc = cs46xx_dsp_create_scb(chip,"SPDIFISCB",(u32 *)&spdifi_scb,SPDIFI_SCB_INST); snd_assert(spdifi_scb_desc, return -EIO); async_codec_scb_desc = cs46xx_dsp_create_scb(chip,"AsynCodecInputSCB",(u32 *)&async_codec_input_scb, HFG_TREE_SCB); snd_assert(async_codec_scb_desc, return -EIO); async_codec_scb_desc->parent_scb_ptr = NULL; async_codec_scb_desc->next_scb_ptr = spdifi_scb_desc; async_codec_scb_desc->sub_list_ptr = ins->the_null_scb; async_codec_scb_desc->task_entry = s16_async_codec_input_task; spdifi_scb_desc->parent_scb_ptr = async_codec_scb_desc; spdifi_scb_desc->next_scb_ptr = spdifo_scb_desc; spdifi_scb_desc->sub_list_ptr = ins->the_null_scb; spdifi_scb_desc->task_entry = spdifi_task; spdifo_scb_desc->parent_scb_ptr = spdifi_scb_desc; spdifo_scb_desc->next_scb_ptr = fg_entry; spdifo_scb_desc->sub_list_ptr = ins->the_null_scb; spdifo_scb_desc->task_entry = spdifo_task; /* this one is faked, as the parnet of SPDIFO task is the FG task tree */ fg_entry->parent_scb_ptr = spdifo_scb_desc; /* for proc fs */ cs46xx_dsp_proc_register_scb_desc (chip,spdifo_scb_desc); cs46xx_dsp_proc_register_scb_desc (chip,spdifi_scb_desc); cs46xx_dsp_proc_register_scb_desc (chip,async_codec_scb_desc); /* Async MASTER ENABLE, affects both SPDIF input and output */ snd_cs46xx_pokeBA0(chip, BA0_ASER_MASTER, 0x1 ); } return 0;}static void cs46xx_dsp_disable_spdif_hw (cs46xx_t *chip){ dsp_spos_instance_t * ins = chip->dsp_spos_instance; /* set SPDIF output FIFO slot */ snd_cs46xx_pokeBA0(chip, BA0_ASER_FADDR, 0); /* SPDIF output MASTER ENABLE */ cs46xx_poke_via_dsp (chip,SP_SPDOUT_CONTROL, 0); /* right and left validate bit */ /*cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default);*/ cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, 0x0); /* clear fifo pointer */ cs46xx_poke_via_dsp (chip,SP_SPDIN_FIFOPTR, 0x0); /* monitor state */ ins->spdif_status_out &= ~DSP_SPDIF_STATUS_HW_ENABLED;}int cs46xx_dsp_enable_spdif_hw (cs46xx_t *chip){ dsp_spos_instance_t * ins = chip->dsp_spos_instance; /* if hw-ctrl already enabled, turn off to reset logic ... */ cs46xx_dsp_disable_spdif_hw (chip); udelay(50); /* set SPDIF output FIFO slot */ snd_cs46xx_pokeBA0(chip, BA0_ASER_FADDR, ( 0x8000 | ((SP_SPDOUT_FIFO >> 4) << 4) )); /* SPDIF output MASTER ENABLE */ cs46xx_poke_via_dsp (chip,SP_SPDOUT_CONTROL, 0x80000000); /* right and left validate bit */ cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, ins->spdif_csuv_default); /* monitor state */ ins->spdif_status_out |= DSP_SPDIF_STATUS_HW_ENABLED; return 0;}int cs46xx_dsp_enable_spdif_in (cs46xx_t *chip){ dsp_spos_instance_t * ins = chip->dsp_spos_instance; /* turn on amplifier */ chip->active_ctrl(chip, 1); chip->amplifier_ctrl(chip, 1); snd_assert (ins->asynch_rx_scb == NULL,return -EINVAL); snd_assert (ins->spdif_in_src != NULL,return -EINVAL); down(&chip->spos_mutex); if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_INPUT_CTRL_ENABLED) ) { /* time countdown enable */ cs46xx_poke_via_dsp (chip,SP_ASER_COUNTDOWN, 0x80000005); /* NOTE: 80000005 value is just magic. With all values that I've tested this one seem to give the best result. Got no explication why. (Benny) */ /* SPDIF input MASTER ENABLE */ cs46xx_poke_via_dsp (chip,SP_SPDIN_CONTROL, 0x800003ff); ins->spdif_status_out |= DSP_SPDIF_STATUS_INPUT_CTRL_ENABLED; } /* create and start the asynchronous receiver SCB */ ins->asynch_rx_scb = cs46xx_dsp_create_asynch_fg_rx_scb(chip,"AsynchFGRxSCB", ASYNCRX_SCB_ADDR, SPDIFI_SCB_INST, SPDIFI_IP_OUTPUT_BUFFER1, ins->spdif_in_src, SCB_ON_PARENT_SUBLIST_SCB); spin_lock_irq(&chip->reg_lock); /* reset SPDIF input sample buffer pointer */ /*snd_cs46xx_poke (chip, (SPDIFI_SCB_INST + 0x0c) << 2, (SPDIFI_IP_OUTPUT_BUFFER1 << 0x10) | 0xFFFC);*/ /* reset FIFO ptr */ /*cs46xx_poke_via_dsp (chip,SP_SPDIN_FIFOPTR, 0x0);*/ cs46xx_src_link(chip,ins->spdif_in_src); /* unmute SRC volume */ cs46xx_dsp_scb_set_volume (chip,ins->spdif_in_src,0x7fff,0x7fff); spin_unlock_irq(&chip->reg_lock); /* set SPDIF input sample rate and unmute NOTE: only 48khz support for SPDIF input this time */ /* cs46xx_dsp_set_src_sample_rate(chip,ins->spdif_in_src,48000); */ /* monitor state */ ins->spdif_status_in = 1; up(&chip->spos_mutex); return 0;}int cs46xx_dsp_disable_spdif_in (cs46xx_t *chip){ dsp_spos_instance_t * ins = chip->dsp_spos_instance; snd_assert (ins->asynch_rx_scb != NULL, return -EINVAL); snd_assert (ins->spdif_in_src != NULL,return -EINVAL); down(&chip->spos_mutex); /* Remove the asynchronous receiver SCB */ cs46xx_dsp_remove_scb (chip,ins->asynch_rx_scb); ins->asynch_rx_scb = NULL; cs46xx_src_unlink(chip,ins->spdif_in_src); /* monitor state */ ins->spdif_status_in = 0; up(&chip->spos_mutex); /* restore amplifier */ chip->active_ctrl(chip, -1); chip->amplifier_ctrl(chip, -1); return 0;}int cs46xx_dsp_enable_pcm_capture (cs46xx_t *chip){ dsp_spos_instance_t * ins = chip->dsp_spos_instance; snd_assert (ins->pcm_input == NULL,return -EINVAL); snd_assert (ins->ref_snoop_scb != NULL,return -EINVAL); down(&chip->spos_mutex); ins->pcm_input = cs46xx_add_record_source(chip,ins->ref_snoop_scb,PCMSERIALIN_PCM_SCB_ADDR, "PCMSerialInput_Wave"); up(&chip->spos_mutex); return 0;}int cs46xx_dsp_disable_pcm_capture (cs46xx_t *chip){ dsp_spos_instance_t * ins = chip->dsp_spos_instance; snd_assert (ins->pcm_input != NULL,return -EINVAL); down(&chip->spos_mutex); cs46xx_dsp_remove_scb (chip,ins->pcm_input); ins->pcm_input = NULL; up(&chip->spos_mutex); return 0;}int cs46xx_dsp_enable_adc_capture (cs46xx_t *chip){ dsp_spos_instance_t * ins = chip->dsp_spos_instance; snd_assert (ins->adc_input == NULL,return -EINVAL); snd_assert (ins->codec_in_scb != NULL,return -EINVAL); down(&chip->spos_mutex); ins->adc_input = cs46xx_add_record_source(chip,ins->codec_in_scb,PCMSERIALIN_SCB_ADDR, "PCMSerialInput_ADC"); up(&chip->spos_mutex); return 0;}int cs46xx_dsp_disable_adc_capture (cs46xx_t *chip){ dsp_spos_instance_t * ins = chip->dsp_spos_instance; snd_assert (ins->adc_input != NULL,return -EINVAL); down(&chip->spos_mutex); cs46xx_dsp_remove_scb (chip,ins->adc_input); ins->adc_input = NULL; up(&chip->spos_mutex); return 0;}int cs46xx_poke_via_dsp (cs46xx_t *chip,u32 address,u32 data){ u32 temp; int i; /* santiy check the parameters. (These numbers are not 100% correct. They are a rough guess from looking at the controller spec.) */ if (address < 0x8000 || address >= 0x9000) return -EINVAL; /* initialize the SP_IO_WRITE SCB with the data. */ temp = ( address << 16 ) | ( address & 0x0000FFFF); /* offset 0 <-- address2 : address1 */ snd_cs46xx_poke(chip,( SPIOWRITE_SCB_ADDR << 2), temp); snd_cs46xx_poke(chip,((SPIOWRITE_SCB_ADDR + 1) << 2), data); /* offset 1 <-- data1 */ snd_cs46xx_poke(chip,((SPIOWRITE_SCB_ADDR + 2) << 2), data); /* offset 1 <-- data2 */ /* Poke this location to tell the task to start */ snd_cs46xx_poke(chip,((SPIOWRITE_SCB_ADDR + 6) << 2), SPIOWRITE_SCB_ADDR << 0x10); /* Verify that the task ran */ for (i=0; i<25; i++) { udelay(125); temp = snd_cs46xx_peek(chip,((SPIOWRITE_SCB_ADDR + 6) << 2)); if (temp == 0x00000000) break; } if (i == 25) { snd_printk(KERN_ERR "dsp_spos: SPIOWriteTask not responding\n"); return -EBUSY; } return 0;}int cs46xx_dsp_set_dac_volume (cs46xx_t * chip,u16 left,u16 right){ dsp_spos_instance_t * ins = chip->dsp_spos_instance; dsp_scb_descriptor_t * scb; down(&chip->spos_mutex); /* main output */ scb = ins->master_mix_scb->sub_list_ptr; while (scb != ins->the_null_scb) { cs46xx_dsp_scb_set_volume (chip,scb,left,right); scb = scb->next_scb_ptr; } /* rear output */ scb = ins->rear_mix_scb->sub_list_ptr; while (scb != ins->the_null_scb) { cs46xx_dsp_scb_set_volume (chip,scb,left,right); scb = scb->next_scb_ptr; } ins->dac_volume_left = left; ins->dac_volume_right = right; up(&chip->spos_mutex); return 0;}int cs46xx_dsp_set_iec958_volume (cs46xx_t * chip,u16 left,u16 right) { dsp_spos_instance_t * ins = chip->dsp_spos_instance; down(&chip->spos_mutex); if (ins->asynch_rx_scb != NULL) cs46xx_dsp_scb_set_volume (chip,ins->asynch_rx_scb, left,right); ins->spdif_input_volume_left = left; ins->spdif_input_volume_right = right; up(&chip->spos_mutex); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -