📄 emufx.c
字号:
int change = 0; spin_lock_irqsave(&emu->reg_lock, flags); for (i = 0; i < ctl->vcount; i++) { nval = ucontrol->value.integer.value[i]; if (nval < ctl->min) nval = ctl->min; if (nval > ctl->max) nval = ctl->max; if (nval != ctl->value[i]) change = 1; val = ctl->value[i] = nval; switch (ctl->translation) { case EMU10K1_GPR_TRANSLATION_NONE: snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, val); break; case EMU10K1_GPR_TRANSLATION_TABLE100: snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, db_table[val]); break; case EMU10K1_GPR_TRANSLATION_BASS: snd_runtime_check((ctl->count % 5) == 0 && (ctl->count / 5) == ctl->vcount, change = -EIO; goto __error); for (j = 0; j < 5; j++) snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[j * ctl->vcount + i], 0, bass_table[val][j]); break; case EMU10K1_GPR_TRANSLATION_TREBLE: snd_runtime_check((ctl->count % 5) == 0 && (ctl->count / 5) == ctl->vcount, change = -EIO; goto __error); for (j = 0; j < 5; j++) snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[j * ctl->vcount + i], 0, treble_table[val][j]); break; case EMU10K1_GPR_TRANSLATION_ONOFF: snd_emu10k1_ptr_write(emu, emu->gpr_base + ctl->gpr[i], 0, onoff_table[val]); break; } } __error: spin_unlock_irqrestore(&emu->reg_lock, flags); return change;}/* * Interrupt handler */static void snd_emu10k1_fx8010_interrupt(emu10k1_t *emu){ snd_emu10k1_fx8010_irq_t *irq, *nirq; irq = emu->fx8010.irq_handlers; while (irq) { nirq = irq->next; /* irq ptr can be removed from list */ if (snd_emu10k1_ptr_read(emu, emu->gpr_base + irq->gpr_running, 0) & 0xffff0000) { if (irq->handler) irq->handler(emu, irq->private_data); snd_emu10k1_ptr_write(emu, emu->gpr_base + irq->gpr_running, 0, 1); } irq = nirq; }}int snd_emu10k1_fx8010_register_irq_handler(emu10k1_t *emu, snd_fx8010_irq_handler_t *handler, unsigned char gpr_running, void *private_data, snd_emu10k1_fx8010_irq_t **r_irq){ snd_emu10k1_fx8010_irq_t *irq; unsigned long flags; snd_runtime_check(emu, return -EINVAL); snd_runtime_check(handler, return -EINVAL); irq = kmalloc(sizeof(*irq), GFP_ATOMIC); if (irq == NULL) return -ENOMEM; irq->handler = handler; irq->gpr_running = gpr_running; irq->private_data = private_data; irq->next = NULL; spin_lock_irqsave(&emu->fx8010.irq_lock, flags); if (emu->fx8010.irq_handlers == NULL) { emu->fx8010.irq_handlers = irq; emu->dsp_interrupt = snd_emu10k1_fx8010_interrupt; snd_emu10k1_intr_enable(emu, INTE_FXDSPENABLE); } else { irq->next = emu->fx8010.irq_handlers; emu->fx8010.irq_handlers = irq; } spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags); if (r_irq) *r_irq = irq; return 0;}int snd_emu10k1_fx8010_unregister_irq_handler(emu10k1_t *emu, snd_emu10k1_fx8010_irq_t *irq){ snd_emu10k1_fx8010_irq_t *tmp; unsigned long flags; snd_runtime_check(irq, return -EINVAL); spin_lock_irqsave(&emu->fx8010.irq_lock, flags); if ((tmp = emu->fx8010.irq_handlers) == irq) { emu->fx8010.irq_handlers = tmp->next; if (emu->fx8010.irq_handlers == NULL) { snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE); emu->dsp_interrupt = NULL; } } else { while (tmp && tmp->next != irq) tmp = tmp->next; if (tmp) tmp->next = tmp->next->next; } spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags); kfree(irq); 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) * 2 + 0] = ((x & 0x3ff) << 10) | (y & 0x3ff); icode->code[(*ptr)++ * 2 + 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 < 1024, return); set_bit(*ptr, icode->code_valid); icode->code[(*ptr) * 2 + 0] = ((x & 0x7ff) << 12) | (y & 0x7ff); icode->code[(*ptr)++ * 2 + 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)static 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 int snd_emu10k1_gpr_poke(emu10k1_t *emu, emu10k1_fx8010_code_t *icode){ int gpr; u32 val; for (gpr = 0; gpr < (emu->audigy ? 0x200 : 0x100); gpr++) { if (!test_bit(gpr, icode->gpr_valid)) continue; if (get_user(val, &icode->gpr_map[gpr])) return -EFAULT; snd_emu10k1_ptr_write(emu, emu->gpr_base + gpr, 0, val); } return 0;}static int snd_emu10k1_gpr_peek(emu10k1_t *emu, emu10k1_fx8010_code_t *icode){ int gpr; u32 val; for (gpr = 0; gpr < (emu->audigy ? 0x200 : 0x100); gpr++) { set_bit(gpr, icode->gpr_valid); val = snd_emu10k1_ptr_read(emu, emu->gpr_base + gpr, 0); if (put_user(val, &icode->gpr_map[gpr])) return -EFAULT; } return 0;}static int snd_emu10k1_tram_poke(emu10k1_t *emu, emu10k1_fx8010_code_t *icode){ int tram; u32 addr, val; for (tram = 0; tram < (emu->audigy ? 0x100 : 0xa0); tram++) { if (!test_bit(tram, icode->tram_valid)) continue; if (get_user(val, &icode->tram_data_map[tram]) || get_user(addr, &icode->tram_addr_map[tram])) return -EFAULT; snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + tram, 0, val); if (!emu->audigy) { snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, addr); } else { snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, addr << 12); snd_emu10k1_ptr_write(emu, A_TANKMEMCTLREGBASE + tram, 0, addr >> 20); } } return 0;}static int snd_emu10k1_tram_peek(emu10k1_t *emu, emu10k1_fx8010_code_t *icode){ int tram; u32 val, addr; memset(icode->tram_valid, 0, sizeof(icode->tram_valid)); for (tram = 0; tram < (emu->audigy ? 0x100 : 0xa0); tram++) { set_bit(tram, icode->tram_valid); val = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + tram, 0); if (!emu->audigy) { addr = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0); } else { addr = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0) >> 12; addr |= snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + tram, 0) << 20; } if (put_user(val, &icode->tram_data_map[tram]) || put_user(addr, &icode->tram_addr_map[tram])) return -EFAULT; } return 0;}static int snd_emu10k1_code_poke(emu10k1_t *emu, emu10k1_fx8010_code_t *icode){ u32 pc, lo, hi; for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) { if (!test_bit(pc / 2, icode->code_valid)) continue; if (get_user(lo, &icode->code[pc + 0]) || get_user(hi, &icode->code[pc + 1])) return -EFAULT; snd_emu10k1_efx_write(emu, pc + 0, lo); snd_emu10k1_efx_write(emu, pc + 1, hi); } return 0;}static int snd_emu10k1_code_peek(emu10k1_t *emu, emu10k1_fx8010_code_t *icode){ u32 pc; memset(icode->code_valid, 0, sizeof(icode->code_valid)); for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) { set_bit(pc / 2, icode->code_valid); if (put_user(snd_emu10k1_efx_read(emu, pc + 0), &icode->code[pc + 0])) return -EFAULT; if (put_user(snd_emu10k1_efx_read(emu, pc + 1), &icode->code[pc + 1])) return -EFAULT; } return 0;}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){ unsigned int i; snd_ctl_elem_id_t __user *_id; snd_ctl_elem_id_t id; emu10k1_fx8010_control_gpr_t __user *_gctl; emu10k1_fx8010_control_gpr_t 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++, _gctl++) { if (copy_from_user(&gctl, _gctl, sizeof(gctl))) return -EFAULT; if (snd_emu10k1_look_for_ctl(emu, &gctl.id)) continue; down_read(&emu->card->controls_rwsem); if (snd_ctl_find_id(emu->card, &gctl.id) != NULL) { up_read(&emu->card->controls_rwsem); return -EEXIST; } up_read(&emu->card->controls_rwsem); if (gctl.id.iface != SNDRV_CTL_ELEM_IFACE_MIXER && gctl.id.iface != SNDRV_CTL_ELEM_IFACE_PCM) return -EINVAL; } for (i = 0, _gctl = icode->gpr_list_controls; i < icode->gpr_list_control_count; i++, _gctl++) { /* FIXME: we need to check the WRITE access */ if (copy_from_user(&gctl, _gctl, sizeof(gctl))) return -EFAULT; } 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 int snd_emu10k1_add_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icode){ unsigned int i, j; emu10k1_fx8010_control_gpr_t __user *_gctl; emu10k1_fx8010_control_gpr_t gctl; snd_emu10k1_fx8010_ctl_t *ctl, nctl; snd_kcontrol_new_t knew; snd_kcontrol_t *kctl; snd_ctl_elem_value_t *val; int err = 0; val = (snd_ctl_elem_value_t *)kmalloc(sizeof(*val), GFP_KERNEL); if (!val) return -ENOMEM; for (i = 0, _gctl = icode->gpr_add_controls; i < icode->gpr_add_control_count; i++, _gctl++) { if (copy_from_user(&gctl, _gctl, sizeof(gctl))) { err = -EFAULT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -