📄 emufx.c
字号:
static int snd_emu10k1_fx8010_playback_close(snd_pcm_substream_t * substream){ emu10k1_t *emu = snd_pcm_substream_chip(substream); snd_emu10k1_fx8010_pcm_t *pcm = &emu->fx8010.pcm[substream->number]; spin_lock(&emu->reg_lock); pcm->opened = 0; spin_unlock(&emu->reg_lock); return 0;}static snd_pcm_ops_t snd_emu10k1_fx8010_playback_ops = { open: snd_emu10k1_fx8010_playback_open, close: snd_emu10k1_fx8010_playback_close, ioctl: snd_pcm_lib_ioctl, hw_params: snd_emu10k1_fx8010_playback_hw_params, hw_free: snd_emu10k1_fx8010_playback_hw_free, prepare: snd_emu10k1_fx8010_playback_prepare, trigger: snd_emu10k1_fx8010_playback_trigger, copy: snd_emu10k1_fx8010_playback_copy, pointer: snd_emu10k1_fx8010_playback_pointer,};static void snd_emu10k1_fx8010_pcm_free(snd_pcm_t *pcm){ emu10k1_t *emu = snd_magic_cast(emu10k1_t, pcm->private_data, return); emu->pcm_fx8010 = NULL; snd_pcm_lib_preallocate_free_for_all(pcm);}int snd_emu10k1_fx8010_pcm(emu10k1_t * emu, int device, snd_pcm_t ** rpcm){ snd_pcm_t *pcm; int err; if (rpcm) *rpcm = NULL; if ((err = snd_pcm_new(emu->card, "emu10k1", device, 8, 0, &pcm)) < 0) return err; pcm->private_data = emu; pcm->private_free = snd_emu10k1_fx8010_pcm_free; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_emu10k1_fx8010_playback_ops); pcm->info_flags = 0; strcpy(pcm->name, "EMU10K1 FX8010"); emu->pcm_fx8010 = pcm; snd_pcm_lib_preallocate_pci_pages_for_all(emu->pci, pcm, 64*1024, 0); if (rpcm) *rpcm = pcm; return 0;}/************************************************************************* * EMU10K1 effect manager *************************************************************************/static void snd_emu10k1_write_op(emu10k1_fx8010_code_t *icode, unsigned int *ptr, u32 op, u32 r, u32 a, u32 x, u32 y){ snd_assert(*ptr < 512, return); set_bit(*ptr, &icode->code_valid); icode->code[*ptr ][0] = ((x & 0x3ff) << 10) | (y & 0x3ff); icode->code[(*ptr)++][1] = ((op & 0x0f) << 20) | ((r & 0x3ff) << 10) | (a & 0x3ff);}#define OP(icode, ptr, op, r, a, x, y) \ snd_emu10k1_write_op(icode, ptr, op, r, a, x, y)static void snd_emu10k1_audigy_write_op(emu10k1_fx8010_code_t *icode, unsigned int *ptr, u32 op, u32 r, u32 a, u32 x, u32 y){ snd_assert(*ptr < 512, return); set_bit(*ptr, &icode->code_valid); icode->code[*ptr ][0] = ((x & 0x7ff) << 12) | (y & 0x7ff); icode->code[(*ptr)++][1] = ((op & 0x0f) << 24) | ((r & 0x7ff) << 12) | (a & 0x7ff);}#define A_OP(icode, ptr, op, r, a, x, y) \ snd_emu10k1_audigy_write_op(icode, ptr, op, r, a, x, y)void snd_emu10k1_efx_write(emu10k1_t *emu, unsigned int pc, unsigned int data){ pc += emu->audigy ? A_MICROCODEBASE : MICROCODEBASE; snd_emu10k1_ptr_write(emu, pc, 0, data);}unsigned int snd_emu10k1_efx_read(emu10k1_t *emu, unsigned int pc){ pc += emu->audigy ? A_MICROCODEBASE : MICROCODEBASE; return snd_emu10k1_ptr_read(emu, pc, 0);}static void snd_emu10k1_gpr_poke(emu10k1_t *emu, emu10k1_fx8010_code_t *icode){ int gpr; for (gpr = 0; gpr < 0x100; gpr++) { if (!test_bit(gpr, &icode->gpr_valid)) continue; snd_emu10k1_ptr_write(emu, emu->gpr_base + gpr, 0, icode->gpr_map[gpr]); }}static void snd_emu10k1_gpr_peek(emu10k1_t *emu, emu10k1_fx8010_code_t *icode){ int gpr; for (gpr = 0; gpr < 0x100; gpr++) { set_bit(gpr, &icode->gpr_valid); icode->gpr_map[gpr] = snd_emu10k1_ptr_read(emu, emu->gpr_base + gpr, 0); }}static void snd_emu10k1_tram_poke(emu10k1_t *emu, emu10k1_fx8010_code_t *icode){ int tram; for (tram = 0; tram < 0xa0; tram++) { if (!test_bit(tram, &icode->tram_valid)) continue; snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + tram, 0, icode->tram_data_map[tram]); snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, icode->tram_addr_map[tram]); }}static void snd_emu10k1_tram_peek(emu10k1_t *emu, emu10k1_fx8010_code_t *icode){ int tram; for (tram = 0; tram < 0xa0; tram++) { set_bit(tram, &icode->tram_valid); icode->tram_data_map[tram] = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + tram, 0); icode->tram_addr_map[tram] = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0); }}static void snd_emu10k1_code_poke(emu10k1_t *emu, emu10k1_fx8010_code_t *icode){ u32 pc; for (pc = 0; pc < 512; pc++) { if (!test_bit(pc, &icode->code_valid)) continue; snd_emu10k1_efx_write(emu, pc * 2, icode->code[pc][0]); snd_emu10k1_efx_write(emu, pc * 2 + 1, icode->code[pc][1]); }}static void snd_emu10k1_code_peek(emu10k1_t *emu, emu10k1_fx8010_code_t *icode){ u32 pc; for (pc = 0; pc < 512; pc++) { set_bit(pc, &icode->code_valid); icode->code[pc][0] = snd_emu10k1_efx_read(emu, pc * 2); icode->code[pc][1] = snd_emu10k1_efx_read(emu, pc * 2 + 1); }}static snd_emu10k1_fx8010_ctl_t *snd_emu10k1_look_for_ctl(emu10k1_t *emu, snd_ctl_elem_id_t *id){ snd_emu10k1_fx8010_ctl_t *ctl; snd_kcontrol_t *kcontrol; struct list_head *list; list_for_each(list, &emu->fx8010.gpr_ctl) { ctl = emu10k1_gpr_ctl(list); kcontrol = ctl->kcontrol; if (kcontrol->id.iface == id->iface && !strcmp(kcontrol->id.name, id->name) && kcontrol->id.index == id->index) return ctl; } return NULL;}static int snd_emu10k1_verify_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icode){ int i; snd_ctl_elem_id_t *_id, id; emu10k1_fx8010_control_gpr_t *_gctl, gctl; for (i = 0, _id = icode->gpr_del_controls; i < icode->gpr_del_control_count; i++, _id++) { if (copy_from_user(&id, _id, sizeof(id))) return -EFAULT; if (snd_emu10k1_look_for_ctl(emu, &id) == NULL) return -ENOENT; } for (i = 0, _gctl = icode->gpr_add_controls; i < icode->gpr_add_control_count; i++) { if (copy_from_user(&gctl, _gctl, sizeof(gctl))) return -EFAULT; if (snd_emu10k1_look_for_ctl(emu, &gctl.id)) continue; if (snd_ctl_find_id(emu->card, &gctl.id) != NULL) return -EEXIST; if (gctl.id.iface != SNDRV_CTL_ELEM_IFACE_MIXER && gctl.id.iface != SNDRV_CTL_ELEM_IFACE_PCM) return -EINVAL; } return 0;}static void snd_emu10k1_ctl_private_free(snd_kcontrol_t *kctl){ snd_emu10k1_fx8010_ctl_t *ctl; ctl = (snd_emu10k1_fx8010_ctl_t *)kctl->private_value; kctl->private_value = 0; list_del(&ctl->list); kfree(ctl);}static void snd_emu10k1_add_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icode){ int i, j; emu10k1_fx8010_control_gpr_t *_gctl, gctl; snd_emu10k1_fx8010_ctl_t *ctl, nctl; snd_kcontrol_new_t knew; snd_kcontrol_t *kctl; snd_ctl_elem_value_t val; for (i = 0, _gctl = icode->gpr_add_controls; i < icode->gpr_add_control_count; i++, _gctl++) { if (copy_from_user(&gctl, _gctl, sizeof(gctl))) return; snd_runtime_check(gctl.id.iface == SNDRV_CTL_ELEM_IFACE_MIXER || gctl.id.iface == SNDRV_CTL_ELEM_IFACE_PCM, continue); snd_runtime_check(gctl.id.name[0] != '\0', continue); 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.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]; 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 (snd_ctl_add(emu->card, kctl = snd_ctl_new1(&knew, emu)) < 0) { kfree(ctl); continue; } 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); }}static void snd_emu10k1_del_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icode){ int i; snd_ctl_elem_id_t *_id, id; snd_emu10k1_fx8010_ctl_t *ctl; 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, continue); ctl = snd_emu10k1_look_for_ctl(emu, &id); snd_runtime_check(ctl == NULL, continue); snd_ctl_remove(emu->card, ctl->kcontrol); }}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; strncpy(emu->fx8010.name, icode->name, sizeof(emu->fx8010.name)-1); emu->fx8010.name[sizeof(emu->fx8010.name)-1] = '\0'; /* 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 */ snd_emu10k1_del_controls(emu, icode); snd_emu10k1_gpr_poke(emu, icode); snd_emu10k1_tram_poke(emu, icode); snd_emu10k1_code_poke(emu, icode); snd_emu10k1_add_controls(emu, icode); /* 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){ down(&emu->fx8010.lock); strncpy(icode->name, emu->fx8010.name, sizeof(icode->name)-1); emu->fx8010.name[sizeof(emu->fx8010.name)-1] = '\0'; /* ok, do the main job */ snd_emu10k1_gpr_peek(emu, icode); snd_emu10k1_tram_peek(emu, icode); snd_emu10k1_code_peek(emu, icode); up(&emu->fx8010.lock); return 0;}static int snd_emu10k1_ipcm_poke(emu10k1_t *emu, emu10k1_fx8010_pcm_t *ipcm){ int err = 0, i; 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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -