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/driver.h> 23 #include <sound/core.h> 24 #include <sound/hwdep.h> 25 #include <asm/uaccess.h> 26 #include "emux_voice.h" 27 28 /* 29 * open the hwdep device 30 */ 31 static int 32 snd_emux_hwdep_open(struct snd_hwdep *hw, struct file *file) 33 { 34 return 0; 35 } 36 37 38 /* 39 * close the device 40 */ 41 static int 42 snd_emux_hwdep_release(struct snd_hwdep *hw, struct file *file) 43 { 44 return 0; 45 } 46 47 48 #define TMP_CLIENT_ID 0x1001 49 50 /* 51 * load patch 52 */ 53 static int 54 snd_emux_hwdep_load_patch(struct snd_emux *emu, void __user *arg) 55 { 56 int err; 57 struct soundfont_patch_info patch; 58 59 if (copy_from_user(&patch, arg, sizeof(patch))) 60 return -EFAULT; 61 62 if (patch.type >= SNDRV_SFNT_LOAD_INFO && 63 patch.type <= SNDRV_SFNT_PROBE_DATA) { 64 err = snd_soundfont_load(emu->sflist, arg, patch.len + sizeof(patch), TMP_CLIENT_ID); 65 if (err < 0) 66 return err; 67 } else { 68 if (emu->ops.load_fx) 69 return emu->ops.load_fx(emu, patch.type, patch.optarg, arg, patch.len + sizeof(patch)); 70 else 71 return -EINVAL; 72 } 73 return 0; 74 } 75 76 /* 77 * set misc mode 78 */ 79 static int 80 snd_emux_hwdep_misc_mode(struct snd_emux *emu, void __user *arg) 81 { 82 struct snd_emux_misc_mode info; 83 int i; 84 85 if (copy_from_user(&info, arg, sizeof(info))) 86 return -EFAULT; 87 if (info.mode < 0 || info.mode >= EMUX_MD_END) 88 return -EINVAL; 89 90 if (info.port < 0) { 91 for (i = 0; i < emu->num_ports; i++) 92 emu->portptrs[i]->ctrls[info.mode] = info.value; 93 } else { 94 if (info.port < emu->num_ports) 95 emu->portptrs[info.port]->ctrls[info.mode] = info.value; 96 } 97 return 0; 98 } 99 100 101 /* 102 * ioctl 103 */ 104 static int 105 snd_emux_hwdep_ioctl(struct snd_hwdep * hw, struct file *file, 106 unsigned int cmd, unsigned long arg) 107 { 108 struct snd_emux *emu = hw->private_data; 109 110 switch (cmd) { 111 case SNDRV_EMUX_IOCTL_VERSION: 112 return put_user(SNDRV_EMUX_VERSION, (unsigned int __user *)arg); 113 case SNDRV_EMUX_IOCTL_LOAD_PATCH: 114 return snd_emux_hwdep_load_patch(emu, (void __user *)arg); 115 case SNDRV_EMUX_IOCTL_RESET_SAMPLES: 116 snd_soundfont_remove_samples(emu->sflist); 117 break; 118 case SNDRV_EMUX_IOCTL_REMOVE_LAST_SAMPLES: 119 snd_soundfont_remove_unlocked(emu->sflist); 120 break; 121 case SNDRV_EMUX_IOCTL_MEM_AVAIL: 122 if (emu->memhdr) { 123 int size = snd_util_mem_avail(emu->memhdr); 124 return put_user(size, (unsigned int __user *)arg); 125 } 126 break; 127 case SNDRV_EMUX_IOCTL_MISC_MODE: 128 return snd_emux_hwdep_misc_mode(emu, (void __user *)arg); 129 } 130 131 return 0; 132 } 133 134 135 /* 136 * register hwdep device 137 */ 138 139 int 140 snd_emux_init_hwdep(struct snd_emux *emu) 141 { 142 struct snd_hwdep *hw; 143 int err; 144 145 if ((err = snd_hwdep_new(emu->card, SNDRV_EMUX_HWDEP_NAME, emu->hwdep_idx, &hw)) < 0) 146 return err; 147 emu->hwdep = hw; 148 strcpy(hw->name, SNDRV_EMUX_HWDEP_NAME); 149 hw->iface = SNDRV_HWDEP_IFACE_EMUX_WAVETABLE; 150 hw->ops.open = snd_emux_hwdep_open; 151 hw->ops.release = snd_emux_hwdep_release; 152 hw->ops.ioctl = snd_emux_hwdep_ioctl; 153 hw->exclusive = 1; 154 hw->private_data = emu; 155 if ((err = snd_card_register(emu->card)) < 0) 156 return err; 157 158 return 0; 159 } 160 161 162 /* 163 * unregister 164 */ 165 void 166 snd_emux_delete_hwdep(struct snd_emux *emu) 167 { 168 if (emu->hwdep) { 169 snd_device_free(emu->card, emu->hwdep); 170 emu->hwdep = NULL; 171 } 172 } 173