📄 emufx.c
字号:
goto __error; } snd_runtime_check(gctl.id.iface == SNDRV_CTL_ELEM_IFACE_MIXER || gctl.id.iface == SNDRV_CTL_ELEM_IFACE_PCM, err = -EINVAL; goto __error); snd_runtime_check(gctl.id.name[0] != '\0', err = -EINVAL; goto __error); ctl = snd_emu10k1_look_for_ctl(emu, &gctl.id); memset(&knew, 0, sizeof(knew)); knew.iface = gctl.id.iface; knew.name = gctl.id.name; knew.index = gctl.id.index; knew.device = gctl.id.device; knew.subdevice = gctl.id.subdevice; knew.info = snd_emu10k1_gpr_ctl_info; knew.get = snd_emu10k1_gpr_ctl_get; knew.put = snd_emu10k1_gpr_ctl_put; memset(&nctl, 0, sizeof(nctl)); nctl.vcount = gctl.vcount; nctl.count = gctl.count; for (j = 0; j < 32; j++) { nctl.gpr[j] = gctl.gpr[j]; nctl.value[j] = ~gctl.value[j]; /* inverted, we want to write new value in gpr_ctl_put() */ val->value.integer.value[j] = gctl.value[j]; } nctl.min = gctl.min; nctl.max = gctl.max; nctl.translation = gctl.translation; if (ctl == NULL) { ctl = (snd_emu10k1_fx8010_ctl_t *)kmalloc(sizeof(*ctl), GFP_KERNEL); if (ctl == NULL) continue; knew.private_value = (unsigned long)ctl; memcpy(ctl, &nctl, sizeof(nctl)); if ((err = snd_ctl_add(emu->card, kctl = snd_ctl_new1(&knew, emu))) < 0) { kfree(ctl); goto __error; } kctl->private_free = snd_emu10k1_ctl_private_free; ctl->kcontrol = kctl; list_add_tail(&ctl->list, &emu->fx8010.gpr_ctl); } else { /* overwrite */ nctl.list = ctl->list; nctl.kcontrol = ctl->kcontrol; memcpy(ctl, &nctl, sizeof(nctl)); snd_ctl_notify(emu->card, SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO, &ctl->kcontrol->id); } snd_emu10k1_gpr_ctl_put(ctl->kcontrol, val); } __error: kfree(val); return err;}static int snd_emu10k1_del_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icode){ unsigned int i; snd_ctl_elem_id_t id; snd_ctl_elem_id_t __user *_id; snd_emu10k1_fx8010_ctl_t *ctl; snd_card_t *card = emu->card; for (i = 0, _id = icode->gpr_del_controls; i < icode->gpr_del_control_count; i++, _id++) { snd_runtime_check(copy_from_user(&id, _id, sizeof(id)) == 0, return -EFAULT); down_write(&card->controls_rwsem); ctl = snd_emu10k1_look_for_ctl(emu, &id); if (ctl) snd_ctl_remove(card, ctl->kcontrol); up_write(&card->controls_rwsem); } return 0;}static int snd_emu10k1_list_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icode){ unsigned int i = 0, j; unsigned int total = 0; emu10k1_fx8010_control_gpr_t gctl; emu10k1_fx8010_control_gpr_t __user *_gctl; snd_emu10k1_fx8010_ctl_t *ctl; snd_ctl_elem_id_t *id; struct list_head *list; _gctl = icode->gpr_list_controls; list_for_each(list, &emu->fx8010.gpr_ctl) { ctl = emu10k1_gpr_ctl(list); total++; if (_gctl && i < icode->gpr_list_control_count) { memset(&gctl, 0, sizeof(gctl)); id = &ctl->kcontrol->id; gctl.id.iface = id->iface; strlcpy(gctl.id.name, id->name, sizeof(gctl.id.name)); gctl.id.index = id->index; gctl.id.device = id->device; gctl.id.subdevice = id->subdevice; gctl.vcount = ctl->vcount; gctl.count = ctl->count; for (j = 0; j < 32; j++) { gctl.gpr[j] = ctl->gpr[j]; gctl.value[j] = ctl->value[j]; } gctl.min = ctl->min; gctl.max = ctl->max; gctl.translation = ctl->translation; if (copy_to_user(_gctl, &gctl, sizeof(gctl))) return -EFAULT; _gctl++; i++; } } icode->gpr_list_control_total = total; return 0;}static int snd_emu10k1_icode_poke(emu10k1_t *emu, emu10k1_fx8010_code_t *icode){ int err = 0; down(&emu->fx8010.lock); if ((err = snd_emu10k1_verify_controls(emu, icode)) < 0) goto __error; strlcpy(emu->fx8010.name, icode->name, sizeof(emu->fx8010.name)); /* stop FX processor - this may be dangerous, but it's better to miss some samples than generate wrong ones - [jk] */ if (emu->audigy) snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP); else snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP); /* ok, do the main job */ if ((err = snd_emu10k1_del_controls(emu, icode)) < 0 || (err = snd_emu10k1_gpr_poke(emu, icode)) < 0 || (err = snd_emu10k1_tram_poke(emu, icode)) < 0 || (err = snd_emu10k1_code_poke(emu, icode)) < 0 || (err = snd_emu10k1_add_controls(emu, icode)) < 0) goto __error; /* start FX processor when the DSP code is updated */ if (emu->audigy) snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg); else snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg); __error: up(&emu->fx8010.lock); return err;}static int snd_emu10k1_icode_peek(emu10k1_t *emu, emu10k1_fx8010_code_t *icode){ int err; down(&emu->fx8010.lock); strlcpy(icode->name, emu->fx8010.name, sizeof(icode->name)); /* ok, do the main job */ err = snd_emu10k1_gpr_peek(emu, icode); if (err >= 0) err = snd_emu10k1_tram_peek(emu, icode); if (err >= 0) err = snd_emu10k1_code_peek(emu, icode); if (err >= 0) err = snd_emu10k1_list_controls(emu, icode); up(&emu->fx8010.lock); return err;}static int snd_emu10k1_ipcm_poke(emu10k1_t *emu, emu10k1_fx8010_pcm_t *ipcm){ unsigned int i; int err = 0; snd_emu10k1_fx8010_pcm_t *pcm; if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT) return -EINVAL; if (ipcm->channels > 32) return -EINVAL; pcm = &emu->fx8010.pcm[ipcm->substream]; down(&emu->fx8010.lock); spin_lock_irq(&emu->reg_lock); if (pcm->opened) { err = -EBUSY; goto __error; } if (ipcm->channels == 0) { /* remove */ pcm->valid = 0; } else { /* FIXME: we need to add universal code to the PCM transfer routine */ if (ipcm->channels != 2) { err = -EINVAL; goto __error; } pcm->valid = 1; pcm->opened = 0; pcm->channels = ipcm->channels; pcm->tram_start = ipcm->tram_start; pcm->buffer_size = ipcm->buffer_size; pcm->gpr_size = ipcm->gpr_size; pcm->gpr_count = ipcm->gpr_count; pcm->gpr_tmpcount = ipcm->gpr_tmpcount; pcm->gpr_ptr = ipcm->gpr_ptr; pcm->gpr_trigger = ipcm->gpr_trigger; pcm->gpr_running = ipcm->gpr_running; for (i = 0; i < pcm->channels; i++) pcm->etram[i] = ipcm->etram[i]; } __error: spin_unlock_irq(&emu->reg_lock); up(&emu->fx8010.lock); return err;}static int snd_emu10k1_ipcm_peek(emu10k1_t *emu, emu10k1_fx8010_pcm_t *ipcm){ unsigned int i; int err = 0; snd_emu10k1_fx8010_pcm_t *pcm; if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT) return -EINVAL; pcm = &emu->fx8010.pcm[ipcm->substream]; down(&emu->fx8010.lock); spin_lock_irq(&emu->reg_lock); ipcm->channels = pcm->channels; ipcm->tram_start = pcm->tram_start; ipcm->buffer_size = pcm->buffer_size; ipcm->gpr_size = pcm->gpr_size; ipcm->gpr_ptr = pcm->gpr_ptr; ipcm->gpr_count = pcm->gpr_count; ipcm->gpr_tmpcount = pcm->gpr_tmpcount; ipcm->gpr_trigger = pcm->gpr_trigger; ipcm->gpr_running = pcm->gpr_running; for (i = 0; i < pcm->channels; i++) ipcm->etram[i] = pcm->etram[i]; ipcm->res1 = ipcm->res2 = 0; ipcm->pad = 0; spin_unlock_irq(&emu->reg_lock); up(&emu->fx8010.lock); return err;}#define SND_EMU10K1_GPR_CONTROLS 41#define SND_EMU10K1_INPUTS 10#define SND_EMU10K1_PLAYBACK_CHANNELS 8#define SND_EMU10K1_CAPTURE_CHANNELS 4static void __devinit snd_emu10k1_init_mono_control(emu10k1_fx8010_control_gpr_t *ctl, const char *name, int gpr, int defval){ ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; strcpy(ctl->id.name, name); ctl->vcount = ctl->count = 1; ctl->gpr[0] = gpr + 0; ctl->value[0] = defval; ctl->min = 0; ctl->max = 100; ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100; }static void __devinit snd_emu10k1_init_stereo_control(emu10k1_fx8010_control_gpr_t *ctl, const char *name, int gpr, int defval){ ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; strcpy(ctl->id.name, name); ctl->vcount = ctl->count = 2; ctl->gpr[0] = gpr + 0; ctl->value[0] = defval; ctl->gpr[1] = gpr + 1; ctl->value[1] = defval; ctl->min = 0; ctl->max = 100; ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;}static void __devinit snd_emu10k1_init_mono_onoff_control(emu10k1_fx8010_control_gpr_t *ctl, const char *name, int gpr, int defval){ ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; strcpy(ctl->id.name, name); ctl->vcount = ctl->count = 1; ctl->gpr[0] = gpr + 0; ctl->value[0] = defval; ctl->min = 0; ctl->max = 1; ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;}static void __devinit snd_emu10k1_init_stereo_onoff_control(emu10k1_fx8010_control_gpr_t *ctl, const char *name, int gpr, int defval){ ctl->id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; strcpy(ctl->id.name, name); ctl->vcount = ctl->count = 2; ctl->gpr[0] = gpr + 0; ctl->value[0] = defval; ctl->gpr[1] = gpr + 1; ctl->value[1] = defval; ctl->min = 0; ctl->max = 1; ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF;}/* * initial DSP configuration for Audigy */static int __devinit _snd_emu10k1_audigy_init_efx(emu10k1_t *emu){ int err, i, z, gpr, nctl; const int playback = 10; const int capture = playback + (SND_EMU10K1_PLAYBACK_CHANNELS * 2); /* we reserve 10 voices */ const int stereo_mix = capture + 2; const int tmp = 0x88; u32 ptr; emu10k1_fx8010_code_t *icode = NULL; emu10k1_fx8010_control_gpr_t *controls = NULL, *ctl; mm_segment_t seg; spin_lock_init(&emu->fx8010.irq_lock); INIT_LIST_HEAD(&emu->fx8010.gpr_ctl); if ((icode = kcalloc(1, sizeof(*icode), GFP_KERNEL)) == NULL || (icode->gpr_map = kcalloc(512 + 256 + 256 + 2 * 1024, sizeof(u_int32_t), GFP_KERNEL)) == NULL || (controls = kcalloc(SND_EMU10K1_GPR_CONTROLS, sizeof(*controls), GFP_KERNEL)) == NULL) { err = -ENOMEM; goto __err; } icode->tram_data_map = icode->gpr_map + 512; icode->tram_addr_map = icode->tram_data_map + 256; icode->code = icode->tram_addr_map + 256; /* clear free GPRs */ for (i = 0; i < 512; i++) set_bit(i, icode->gpr_valid); /* clear TRAM data & address lines */ for (i = 0; i < 256; i++) set_bit(i, icode->tram_valid); strcpy(icode->name, "Audigy DSP code for ALSA"); ptr = 0; nctl = 0; gpr = stereo_mix + 10; /* stop FX processor */ snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP); /* PCM front Playback Volume (independent from stereo mix) */ A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT)); A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT)); snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Front Playback Volume", gpr, 100); gpr += 2; /* PCM Surround Playback (independent from stereo mix) */ A_OP(icode, &ptr, iMAC0, A_GPR(playback+2), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_REAR)); A_OP(icode, &ptr, iMAC0, A_GPR(playback+3), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_REAR)); snd_emu10k1_init_stereo_control(&controls[nctl++], "PCM Surround Playback Volume", gpr, 100);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -