0001
0002
0003
0004
0005
0006
0007
0008 #include <sound/core.h>
0009 #include <sound/hwdep.h>
0010 #include <linux/uaccess.h>
0011 #include <linux/nospec.h>
0012 #include "emux_voice.h"
0013
0014 #define TMP_CLIENT_ID 0x1001
0015
0016
0017
0018
0019 static int
0020 snd_emux_hwdep_load_patch(struct snd_emux *emu, void __user *arg)
0021 {
0022 int err;
0023 struct soundfont_patch_info patch;
0024
0025 if (copy_from_user(&patch, arg, sizeof(patch)))
0026 return -EFAULT;
0027
0028 if (patch.key == GUS_PATCH)
0029 return snd_soundfont_load_guspatch(emu->sflist, arg,
0030 patch.len + sizeof(patch),
0031 TMP_CLIENT_ID);
0032
0033 if (patch.type >= SNDRV_SFNT_LOAD_INFO &&
0034 patch.type <= SNDRV_SFNT_PROBE_DATA) {
0035 err = snd_soundfont_load(emu->sflist, arg, patch.len + sizeof(patch), TMP_CLIENT_ID);
0036 if (err < 0)
0037 return err;
0038 } else {
0039 if (emu->ops.load_fx)
0040 return emu->ops.load_fx(emu, patch.type, patch.optarg, arg, patch.len + sizeof(patch));
0041 else
0042 return -EINVAL;
0043 }
0044 return 0;
0045 }
0046
0047
0048
0049
0050 static int
0051 snd_emux_hwdep_misc_mode(struct snd_emux *emu, void __user *arg)
0052 {
0053 struct snd_emux_misc_mode info;
0054 int i;
0055
0056 if (copy_from_user(&info, arg, sizeof(info)))
0057 return -EFAULT;
0058 if (info.mode < 0 || info.mode >= EMUX_MD_END)
0059 return -EINVAL;
0060 info.mode = array_index_nospec(info.mode, EMUX_MD_END);
0061
0062 if (info.port < 0) {
0063 for (i = 0; i < emu->num_ports; i++)
0064 emu->portptrs[i]->ctrls[info.mode] = info.value;
0065 } else {
0066 if (info.port < emu->num_ports) {
0067 info.port = array_index_nospec(info.port, emu->num_ports);
0068 emu->portptrs[info.port]->ctrls[info.mode] = info.value;
0069 }
0070 }
0071 return 0;
0072 }
0073
0074
0075
0076
0077
0078 static int
0079 snd_emux_hwdep_ioctl(struct snd_hwdep * hw, struct file *file,
0080 unsigned int cmd, unsigned long arg)
0081 {
0082 struct snd_emux *emu = hw->private_data;
0083
0084 switch (cmd) {
0085 case SNDRV_EMUX_IOCTL_VERSION:
0086 return put_user(SNDRV_EMUX_VERSION, (unsigned int __user *)arg);
0087 case SNDRV_EMUX_IOCTL_LOAD_PATCH:
0088 return snd_emux_hwdep_load_patch(emu, (void __user *)arg);
0089 case SNDRV_EMUX_IOCTL_RESET_SAMPLES:
0090 snd_soundfont_remove_samples(emu->sflist);
0091 break;
0092 case SNDRV_EMUX_IOCTL_REMOVE_LAST_SAMPLES:
0093 snd_soundfont_remove_unlocked(emu->sflist);
0094 break;
0095 case SNDRV_EMUX_IOCTL_MEM_AVAIL:
0096 if (emu->memhdr) {
0097 int size = snd_util_mem_avail(emu->memhdr);
0098 return put_user(size, (unsigned int __user *)arg);
0099 }
0100 break;
0101 case SNDRV_EMUX_IOCTL_MISC_MODE:
0102 return snd_emux_hwdep_misc_mode(emu, (void __user *)arg);
0103 }
0104
0105 return 0;
0106 }
0107
0108
0109
0110
0111
0112
0113 int
0114 snd_emux_init_hwdep(struct snd_emux *emu)
0115 {
0116 struct snd_hwdep *hw;
0117 int err;
0118
0119 err = snd_hwdep_new(emu->card, SNDRV_EMUX_HWDEP_NAME, emu->hwdep_idx, &hw);
0120 if (err < 0)
0121 return err;
0122 emu->hwdep = hw;
0123 strcpy(hw->name, SNDRV_EMUX_HWDEP_NAME);
0124 hw->iface = SNDRV_HWDEP_IFACE_EMUX_WAVETABLE;
0125 hw->ops.ioctl = snd_emux_hwdep_ioctl;
0126
0127
0128 hw->ops.ioctl_compat = snd_emux_hwdep_ioctl;
0129 hw->exclusive = 1;
0130 hw->private_data = emu;
0131 err = snd_card_register(emu->card);
0132 if (err < 0)
0133 return err;
0134
0135 return 0;
0136 }
0137
0138
0139
0140
0141
0142 void
0143 snd_emux_delete_hwdep(struct snd_emux *emu)
0144 {
0145 if (emu->hwdep) {
0146 snd_device_free(emu->card, emu->hwdep);
0147 emu->hwdep = NULL;
0148 }
0149 }