diff options
author | Jaroslav Kysela <perex@suse.cz> | 2004-10-29 21:40:37 +0200 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2004-10-29 21:40:37 +0200 |
commit | 5f306baab24b1e8c587a5baa43de33d1ad19acdb (patch) | |
tree | d49a6fd7b2ac8c5eb0ea53fd328fedcd1ce37951 /sound | |
parent | 065b78922b0c883efbe8db82e4c9a5c2a477a379 (diff) | |
download | history-5f306baab24b1e8c587a5baa43de33d1ad19acdb.tar.gz |
[ALSA] fixed emu10k1_fx8010_code_t structure to be less than 8192 bytes
EMU10K1/EMU10K2 driver
This patch fixes emu10k1_fx8010_code_t structure using indirect pointers
to be less than 8192 bytes to follow the ioctl semantics.
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/emu10k1/emufx.c | 155 |
1 files changed, 100 insertions, 55 deletions
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index cc651b087e0aa7..00a7585b818d23 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -437,7 +437,7 @@ int snd_emu10k1_fx8010_register_irq_handler(emu10k1_t *emu, } int snd_emu10k1_fx8010_unregister_irq_handler(emu10k1_t *emu, - snd_emu10k1_fx8010_irq_t *irq) + snd_emu10k1_fx8010_irq_t *irq) { snd_emu10k1_fx8010_irq_t *tmp; unsigned long flags; @@ -465,25 +465,35 @@ int snd_emu10k1_fx8010_unregister_irq_handler(emu10k1_t *emu, * 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) +static int 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); + x = ((x & 0x3ff) << 10) | (y & 0x3ff); + y = ((op & 0x0f) << 20) | ((r & 0x3ff) << 10) | (a & 0x3ff); + a = *ptr++ * 2; + if (put_user(x, &icode->code[a + 0]) || + put_user(y, &icode->code[a + 1])) + return -EFAULT; + return 0; } #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) +static int 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 ][0] = ((x & 0x7ff) << 12) | (y & 0x7ff); - icode->code[(*ptr)++][1] = ((op & 0x0f) << 24) | ((r & 0x7ff) << 12) | (a & 0x7ff); + x = ((x & 0x7ff) << 12) | (y & 0x7ff); + y = ((op & 0x0f) << 24) | ((r & 0x7ff) << 12) | (a & 0x7ff); + a = *ptr++ * 2; + if (put_user(x, &icode->code[a + 0]) || + put_user(y, &icode->code[a + 1])) + return -EFAULT; + return 0; } #define A_OP(icode, ptr, op, r, a, x, y) \ @@ -501,83 +511,108 @@ unsigned int snd_emu10k1_efx_read(emu10k1_t *emu, unsigned int pc) return snd_emu10k1_ptr_read(emu, pc, 0); } -static void snd_emu10k1_gpr_poke(emu10k1_t *emu, emu10k1_fx8010_code_t *icode) +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; - snd_emu10k1_ptr_write(emu, emu->gpr_base + gpr, 0, icode->gpr_map[gpr]); + if (get_user(val, &icode->gpr_map[gpr])) + return -EFAULT; + snd_emu10k1_ptr_write(emu, emu->gpr_base + gpr, 0, val); } + return 0; } -static void snd_emu10k1_gpr_peek(emu10k1_t *emu, emu10k1_fx8010_code_t *icode) +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); - icode->gpr_map[gpr] = snd_emu10k1_ptr_read(emu, emu->gpr_base + gpr, 0); + val = snd_emu10k1_ptr_read(emu, emu->gpr_base + gpr, 0); + if (put_user(val, &icode->gpr_map[gpr])) + return -EFAULT; } + return 0; } -static void snd_emu10k1_tram_poke(emu10k1_t *emu, emu10k1_fx8010_code_t *icode) +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; - snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + tram, 0, icode->tram_data_map[tram]); - if (!emu->audigy) - snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, icode->tram_addr_map[tram]); - else { - snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + tram, 0, icode->tram_addr_map[tram] << 12); - snd_emu10k1_ptr_write(emu, A_TANKMEMCTLREGBASE + tram, 0, icode->tram_addr_map[tram] >> 20); + 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 void snd_emu10k1_tram_peek(emu10k1_t *emu, emu10k1_fx8010_code_t *icode) +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); - icode->tram_data_map[tram] = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + tram, 0); - if (!emu->audigy) - icode->tram_addr_map[tram] = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0); - else { - icode->tram_addr_map[tram] = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + tram, 0) >> 12; - icode->tram_addr_map[tram] |= snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + tram, 0) << 20; + 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 void snd_emu10k1_code_poke(emu10k1_t *emu, emu10k1_fx8010_code_t *icode) +static int snd_emu10k1_code_poke(emu10k1_t *emu, emu10k1_fx8010_code_t *icode) { - u32 pc; + u32 pc, lo, hi; - for (pc = 0; pc < (emu->audigy ? 1024 : 512); pc++) { + for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) { 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]); + 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 void snd_emu10k1_code_peek(emu10k1_t *emu, emu10k1_fx8010_code_t *icode) +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 ? 1024 : 512); pc++) { + for (pc = 0; pc < (emu->audigy ? 2*1024 : 2*512); pc += 2) { 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); + 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) @@ -647,7 +682,7 @@ static void snd_emu10k1_ctl_private_free(snd_kcontrol_t *kctl) kfree(ctl); } -static void snd_emu10k1_add_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icode) +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; @@ -656,17 +691,20 @@ static void snd_emu10k1_add_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icod 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; + 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))) - break; + if (copy_from_user(&gctl, _gctl, sizeof(gctl))) { + err = -EFAULT; + goto __error; + } 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); + 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; @@ -694,9 +732,9 @@ static void snd_emu10k1_add_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icod 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) { + if ((err = snd_ctl_add(emu->card, kctl = snd_ctl_new1(&knew, emu))) < 0) { kfree(ctl); - continue; + goto __error; } kctl->private_free = snd_emu10k1_ctl_private_free; ctl->kcontrol = kctl; @@ -711,10 +749,12 @@ static void snd_emu10k1_add_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icod } snd_emu10k1_gpr_ctl_put(ctl->kcontrol, val); } + __error: kfree(val); + return err; } -static void snd_emu10k1_del_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icode) +static int snd_emu10k1_del_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icode) { unsigned int i; snd_ctl_elem_id_t id; @@ -724,13 +764,14 @@ static void snd_emu10k1_del_controls(emu10k1_t *emu, emu10k1_fx8010_code_t *icod 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); + 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) @@ -789,11 +830,12 @@ static int snd_emu10k1_icode_poke(emu10k1_t *emu, emu10k1_fx8010_code_t *icode) 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); + 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); @@ -811,10 +853,13 @@ static int snd_emu10k1_icode_peek(emu10k1_t *emu, emu10k1_fx8010_code_t *icode) down(&emu->fx8010.lock); strlcpy(icode->name, emu->fx8010.name, sizeof(icode->name)); /* ok, do the main job */ - snd_emu10k1_gpr_peek(emu, icode); - snd_emu10k1_tram_peek(emu, icode); - snd_emu10k1_code_peek(emu, icode); - err = snd_emu10k1_list_controls(emu, icode); + 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; } |