1 /* 2 * Interface for hwdep device 3 * 4 * Copyright (C) 2004 Takashi Iwai <tiwai@suse.de> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 */ 21 22 #include <sound/core.h> 23 #include <sound/hwdep.h> 24 #include <asm/uaccess.h> 25 #include "emux_voice.h" 26 27 /* 28 * open the hwdep device 29 */ 30 static int 31 snd_emux_hwdep_open(struct snd_hwdep *hw, struct file *file) 32 { 33 return 0; 34 } 35 36 37 /* 38 * close the device 39 */ 40 static int 41 snd_emux_hwdep_release(struct snd_hwdep *hw, struct file *file) 42 { 43 return 0; 44 } 45 46 47 #define TMP_CLIENT_ID 0x1001 48 49 /* 50 * load patch 51 */ 52 static int 53 snd_emux_hwdep_load_patch(struct snd_emux *emu, void __user *arg) 54 { 55 int err; 56 struct soundfont_patch_info patch; 57 58 if (copy_from_user(&patch, arg, sizeof(patch))) 59 return -EFAULT; 60 61 if (patch.type >= SNDRV_SFNT_LOAD_INFO && 62 patch.type <= SNDRV_SFNT_PROBE_DATA) { 63 err = snd_soundfont_load(emu->sflist, arg, patch.len + sizeof(patch), TMP_CLIENT_ID); 64 if (err < 0) 65 return err; 66 } else { 67 if (emu->ops.load_fx) 68 return emu->ops.load_fx(emu, patch.type, patch.optarg, arg, patch.len + sizeof(patch)); 69 else 70 return -EINVAL; 71 } 72 return 0; 73 } 74 75 /* 76 * set misc mode 77 */ 78 static int 79 snd_emux_hwdep_misc_mode(struct snd_emux *emu, void __user *arg) 80 { 81 struct snd_emux_misc_mode info; 82 int i; 83 84 if (copy_from_user(&info, arg, sizeof(info))) 85 return -EFAULT; 86 if (info.mode < 0 || info.mode >= EMUX_MD_END) 87 return -EINVAL; 88 89 if (info.port < 0) { 90 for (i = 0; i < emu->num_ports; i++) 91 emu->portptrs[i]->ctrls[info.mode] = info.value; 92 } else { 93 if (info.port < emu->num_ports) 94 emu->portptrs[info.port]->ctrls[info.mode] = info.value; 95 } 96 return 0; 97 } 98 99 100 /* 101 * ioctl 102 */ 103 static int 104 snd_emux_hwdep_ioctl(struct snd_hwdep * hw, struct file *file, 105 unsigned int cmd, unsigned long arg) 106 { 107 struct snd_emux *emu = hw->private_data; 108 109 switch (cmd) { 110 case SNDRV_EMUX_IOCTL_VERSION: 111 return put_user(SNDRV_EMUX_VERSION, (unsigned int __user *)arg); 112 case SNDRV_EMUX_IOCTL_LOAD_PATCH: 113 return snd_emux_hwdep_load_patch(emu, (void __user *)arg); 114 case SNDRV_EMUX_IOCTL_RESET_SAMPLES: 115 snd_soundfont_remove_samples(emu->sflist); 116 break; 117 case SNDRV_EMUX_IOCTL_REMOVE_LAST_SAMPLES: 118 snd_soundfont_remove_unlocked(emu->sflist); 119 break; 120 case SNDRV_EMUX_IOCTL_MEM_AVAIL: 121 if (emu->memhdr) { 122 int size = snd_util_mem_avail(emu->memhdr); 123 return put_user(size, (unsigned int __user *)arg); 124 } 125 break; 126 case SNDRV_EMUX_IOCTL_MISC_MODE: 127 return snd_emux_hwdep_misc_mode(emu, (void __user *)arg); 128 } 129 130 return 0; 131 } 132 133 134 /* 135 * register hwdep device 136 */ 137 138 int 139 snd_emux_init_hwdep(struct snd_emux *emu) 140 { 141 struct snd_hwdep *hw; 142 int err; 143 144 if ((err = snd_hwdep_new(emu->card, SNDRV_EMUX_HWDEP_NAME, emu->hwdep_idx, &hw)) < 0) 145 return err; 146 emu->hwdep = hw; 147 strcpy(hw->name, SNDRV_EMUX_HWDEP_NAME); 148 hw->iface = SNDRV_HWDEP_IFACE_EMUX_WAVETABLE; 149 hw->ops.open = snd_emux_hwdep_open; 150 hw->ops.release = snd_emux_hwdep_release; 151 hw->ops.ioctl = snd_emux_hwdep_ioctl; 152 hw->exclusive = 1; 153 hw->private_data = emu; 154 if ((err = snd_card_register(emu->card)) < 0) 155 return err; 156 157 return 0; 158 } 159 160 161 /* 162 * unregister 163 */ 164 void 165 snd_emux_delete_hwdep(struct snd_emux *emu) 166 { 167 if (emu->hwdep) { 168 snd_device_free(emu->card, emu->hwdep); 169 emu->hwdep = NULL; 170 } 171 } 172