11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Interface for hwdep device 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 2004 Takashi Iwai <tiwai@suse.de> 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 71da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 81da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 91da177e4SLinus Torvalds * (at your option) any later version. 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 121da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 131da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 141da177e4SLinus Torvalds * GNU General Public License for more details. 151da177e4SLinus Torvalds * 161da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 171da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 181da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 191da177e4SLinus Torvalds * 201da177e4SLinus Torvalds */ 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds #include <sound/driver.h> 231da177e4SLinus Torvalds #include <sound/core.h> 241da177e4SLinus Torvalds #include <sound/hwdep.h> 251da177e4SLinus Torvalds #include <asm/uaccess.h> 261da177e4SLinus Torvalds #include "emux_voice.h" 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds /* 291da177e4SLinus Torvalds * open the hwdep device 301da177e4SLinus Torvalds */ 311da177e4SLinus Torvalds static int 321da177e4SLinus Torvalds snd_emux_hwdep_open(snd_hwdep_t *hw, struct file *file) 331da177e4SLinus Torvalds { 341da177e4SLinus Torvalds return 0; 351da177e4SLinus Torvalds } 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds /* 391da177e4SLinus Torvalds * close the device 401da177e4SLinus Torvalds */ 411da177e4SLinus Torvalds static int 421da177e4SLinus Torvalds snd_emux_hwdep_release(snd_hwdep_t *hw, struct file *file) 431da177e4SLinus Torvalds { 441da177e4SLinus Torvalds return 0; 451da177e4SLinus Torvalds } 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds #define TMP_CLIENT_ID 0x1001 491da177e4SLinus Torvalds 501da177e4SLinus Torvalds /* 511da177e4SLinus Torvalds * load patch 521da177e4SLinus Torvalds */ 531da177e4SLinus Torvalds static int 541da177e4SLinus Torvalds snd_emux_hwdep_load_patch(snd_emux_t *emu, void __user *arg) 551da177e4SLinus Torvalds { 561da177e4SLinus Torvalds int err; 571da177e4SLinus Torvalds soundfont_patch_info_t patch; 581da177e4SLinus Torvalds 591da177e4SLinus Torvalds if (copy_from_user(&patch, arg, sizeof(patch))) 601da177e4SLinus Torvalds return -EFAULT; 611da177e4SLinus Torvalds 621da177e4SLinus Torvalds if (patch.type >= SNDRV_SFNT_LOAD_INFO && 631da177e4SLinus Torvalds patch.type <= SNDRV_SFNT_PROBE_DATA) { 641da177e4SLinus Torvalds err = snd_soundfont_load(emu->sflist, arg, patch.len + sizeof(patch), TMP_CLIENT_ID); 651da177e4SLinus Torvalds if (err < 0) 661da177e4SLinus Torvalds return err; 671da177e4SLinus Torvalds } else { 681da177e4SLinus Torvalds if (emu->ops.load_fx) 691da177e4SLinus Torvalds return emu->ops.load_fx(emu, patch.type, patch.optarg, arg, patch.len + sizeof(patch)); 701da177e4SLinus Torvalds else 711da177e4SLinus Torvalds return -EINVAL; 721da177e4SLinus Torvalds } 731da177e4SLinus Torvalds return 0; 741da177e4SLinus Torvalds } 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds /* 771da177e4SLinus Torvalds * set misc mode 781da177e4SLinus Torvalds */ 791da177e4SLinus Torvalds static int 801da177e4SLinus Torvalds snd_emux_hwdep_misc_mode(snd_emux_t *emu, void __user *arg) 811da177e4SLinus Torvalds { 821da177e4SLinus Torvalds struct sndrv_emux_misc_mode info; 831da177e4SLinus Torvalds int i; 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds if (copy_from_user(&info, arg, sizeof(info))) 861da177e4SLinus Torvalds return -EFAULT; 871da177e4SLinus Torvalds if (info.mode < 0 || info.mode >= EMUX_MD_END) 881da177e4SLinus Torvalds return -EINVAL; 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds if (info.port < 0) { 911da177e4SLinus Torvalds for (i = 0; i < emu->num_ports; i++) 921da177e4SLinus Torvalds emu->portptrs[i]->ctrls[info.mode] = info.value; 931da177e4SLinus Torvalds } else { 941da177e4SLinus Torvalds if (info.port < emu->num_ports) 951da177e4SLinus Torvalds emu->portptrs[info.port]->ctrls[info.mode] = info.value; 961da177e4SLinus Torvalds } 971da177e4SLinus Torvalds return 0; 981da177e4SLinus Torvalds } 991da177e4SLinus Torvalds 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds /* 1021da177e4SLinus Torvalds * ioctl 1031da177e4SLinus Torvalds */ 1041da177e4SLinus Torvalds static int 1051da177e4SLinus Torvalds snd_emux_hwdep_ioctl(snd_hwdep_t * hw, struct file *file, unsigned int cmd, unsigned long arg) 1061da177e4SLinus Torvalds { 1071da177e4SLinus Torvalds snd_emux_t *emu = hw->private_data; 1081da177e4SLinus Torvalds 1091da177e4SLinus Torvalds switch (cmd) { 1101da177e4SLinus Torvalds case SNDRV_EMUX_IOCTL_VERSION: 1111da177e4SLinus Torvalds return put_user(SNDRV_EMUX_VERSION, (unsigned int __user *)arg); 1121da177e4SLinus Torvalds case SNDRV_EMUX_IOCTL_LOAD_PATCH: 1131da177e4SLinus Torvalds return snd_emux_hwdep_load_patch(emu, (void __user *)arg); 1141da177e4SLinus Torvalds case SNDRV_EMUX_IOCTL_RESET_SAMPLES: 1151da177e4SLinus Torvalds snd_soundfont_remove_samples(emu->sflist); 1161da177e4SLinus Torvalds break; 1171da177e4SLinus Torvalds case SNDRV_EMUX_IOCTL_REMOVE_LAST_SAMPLES: 1181da177e4SLinus Torvalds snd_soundfont_remove_unlocked(emu->sflist); 1191da177e4SLinus Torvalds break; 1201da177e4SLinus Torvalds case SNDRV_EMUX_IOCTL_MEM_AVAIL: 1211da177e4SLinus Torvalds if (emu->memhdr) { 1221da177e4SLinus Torvalds int size = snd_util_mem_avail(emu->memhdr); 1231da177e4SLinus Torvalds return put_user(size, (unsigned int __user *)arg); 1241da177e4SLinus Torvalds } 1251da177e4SLinus Torvalds break; 1261da177e4SLinus Torvalds case SNDRV_EMUX_IOCTL_MISC_MODE: 1271da177e4SLinus Torvalds return snd_emux_hwdep_misc_mode(emu, (void __user *)arg); 1281da177e4SLinus Torvalds } 1291da177e4SLinus Torvalds 1301da177e4SLinus Torvalds return 0; 1311da177e4SLinus Torvalds } 1321da177e4SLinus Torvalds 1331da177e4SLinus Torvalds 1341da177e4SLinus Torvalds /* 1351da177e4SLinus Torvalds * register hwdep device 1361da177e4SLinus Torvalds */ 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds int 1391da177e4SLinus Torvalds snd_emux_init_hwdep(snd_emux_t *emu) 1401da177e4SLinus Torvalds { 1411da177e4SLinus Torvalds snd_hwdep_t *hw; 1421da177e4SLinus Torvalds int err; 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds if ((err = snd_hwdep_new(emu->card, SNDRV_EMUX_HWDEP_NAME, emu->hwdep_idx, &hw)) < 0) 1451da177e4SLinus Torvalds return err; 1461da177e4SLinus Torvalds emu->hwdep = hw; 1471da177e4SLinus Torvalds strcpy(hw->name, SNDRV_EMUX_HWDEP_NAME); 1481da177e4SLinus Torvalds hw->iface = SNDRV_HWDEP_IFACE_EMUX_WAVETABLE; 1491da177e4SLinus Torvalds hw->ops.open = snd_emux_hwdep_open; 1501da177e4SLinus Torvalds hw->ops.release = snd_emux_hwdep_release; 1511da177e4SLinus Torvalds hw->ops.ioctl = snd_emux_hwdep_ioctl; 1521da177e4SLinus Torvalds hw->exclusive = 1; 1531da177e4SLinus Torvalds hw->private_data = emu; 1541da177e4SLinus Torvalds if ((err = snd_card_register(emu->card)) < 0) 1551da177e4SLinus Torvalds return err; 1561da177e4SLinus Torvalds 1571da177e4SLinus Torvalds return 0; 1581da177e4SLinus Torvalds } 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds /* 1621da177e4SLinus Torvalds * unregister 1631da177e4SLinus Torvalds */ 1641da177e4SLinus Torvalds void 1651da177e4SLinus Torvalds snd_emux_delete_hwdep(snd_emux_t *emu) 1661da177e4SLinus Torvalds { 1671da177e4SLinus Torvalds if (emu->hwdep) { 1681da177e4SLinus Torvalds snd_device_free(emu->card, emu->hwdep); 1691da177e4SLinus Torvalds emu->hwdep = NULL; 1701da177e4SLinus Torvalds } 1711da177e4SLinus Torvalds } 172