aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core/seq/instr/ainstr_fm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core/seq/instr/ainstr_fm.c')
-rw-r--r--sound/core/seq/instr/ainstr_fm.c156
1 files changed, 156 insertions, 0 deletions
diff --git a/sound/core/seq/instr/ainstr_fm.c b/sound/core/seq/instr/ainstr_fm.c
new file mode 100644
index 000000000000..5c671e69884f
--- /dev/null
+++ b/sound/core/seq/instr/ainstr_fm.c
@@ -0,0 +1,156 @@
+/*
+ * FM (OPL2/3) Instrument routines
+ * Copyright (c) 2000 Uros Bizjak <uros@kss-loka.si>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <sound/driver.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <sound/core.h>
+#include <sound/ainstr_fm.h>
+#include <sound/initval.h>
+#include <asm/uaccess.h>
+
+MODULE_AUTHOR("Uros Bizjak <uros@kss-loka.si>");
+MODULE_DESCRIPTION("Advanced Linux Sound Architecture FM Instrument support.");
+MODULE_LICENSE("GPL");
+
+static int snd_seq_fm_put(void *private_data, snd_seq_kinstr_t *instr,
+ char __user *instr_data, long len, int atomic, int cmd)
+{
+ fm_instrument_t *ip;
+ fm_xinstrument_t ix;
+ int idx;
+
+ if (cmd != SNDRV_SEQ_INSTR_PUT_CMD_CREATE)
+ return -EINVAL;
+ /* copy instrument data */
+ if (len < (long)sizeof(ix))
+ return -EINVAL;
+ if (copy_from_user(&ix, instr_data, sizeof(ix)))
+ return -EFAULT;
+ if (ix.stype != FM_STRU_INSTR)
+ return -EINVAL;
+ ip = (fm_instrument_t *)KINSTR_DATA(instr);
+ ip->share_id[0] = le32_to_cpu(ix.share_id[0]);
+ ip->share_id[1] = le32_to_cpu(ix.share_id[1]);
+ ip->share_id[2] = le32_to_cpu(ix.share_id[2]);
+ ip->share_id[3] = le32_to_cpu(ix.share_id[3]);
+ ip->type = ix.type;
+ for (idx = 0; idx < 4; idx++) {
+ ip->op[idx].am_vib = ix.op[idx].am_vib;
+ ip->op[idx].ksl_level = ix.op[idx].ksl_level;
+ ip->op[idx].attack_decay = ix.op[idx].attack_decay;
+ ip->op[idx].sustain_release = ix.op[idx].sustain_release;
+ ip->op[idx].wave_select = ix.op[idx].wave_select;
+ }
+ for (idx = 0; idx < 2; idx++) {
+ ip->feedback_connection[idx] = ix.feedback_connection[idx];
+ }
+ ip->echo_delay = ix.echo_delay;
+ ip->echo_atten = ix.echo_atten;
+ ip->chorus_spread = ix.chorus_spread;
+ ip->trnsps = ix.trnsps;
+ ip->fix_dur = ix.fix_dur;
+ ip->modes = ix.modes;
+ ip->fix_key = ix.fix_key;
+ return 0;
+}
+
+static int snd_seq_fm_get(void *private_data, snd_seq_kinstr_t *instr,
+ char __user *instr_data, long len, int atomic,
+ int cmd)
+{
+ fm_instrument_t *ip;
+ fm_xinstrument_t ix;
+ int idx;
+
+ if (cmd != SNDRV_SEQ_INSTR_GET_CMD_FULL)
+ return -EINVAL;
+ if (len < (long)sizeof(ix))
+ return -ENOMEM;
+ memset(&ix, 0, sizeof(ix));
+ ip = (fm_instrument_t *)KINSTR_DATA(instr);
+ ix.stype = FM_STRU_INSTR;
+ ix.share_id[0] = cpu_to_le32(ip->share_id[0]);
+ ix.share_id[1] = cpu_to_le32(ip->share_id[1]);
+ ix.share_id[2] = cpu_to_le32(ip->share_id[2]);
+ ix.share_id[3] = cpu_to_le32(ip->share_id[3]);
+ ix.type = ip->type;
+ for (idx = 0; idx < 4; idx++) {
+ ix.op[idx].am_vib = ip->op[idx].am_vib;
+ ix.op[idx].ksl_level = ip->op[idx].ksl_level;
+ ix.op[idx].attack_decay = ip->op[idx].attack_decay;
+ ix.op[idx].sustain_release = ip->op[idx].sustain_release;
+ ix.op[idx].wave_select = ip->op[idx].wave_select;
+ }
+ for (idx = 0; idx < 2; idx++) {
+ ix.feedback_connection[idx] = ip->feedback_connection[idx];
+ }
+ if (copy_to_user(instr_data, &ix, sizeof(ix)))
+ return -EFAULT;
+ ix.echo_delay = ip->echo_delay;
+ ix.echo_atten = ip->echo_atten;
+ ix.chorus_spread = ip->chorus_spread;
+ ix.trnsps = ip->trnsps;
+ ix.fix_dur = ip->fix_dur;
+ ix.modes = ip->modes;
+ ix.fix_key = ip->fix_key;
+ return 0;
+}
+
+static int snd_seq_fm_get_size(void *private_data, snd_seq_kinstr_t *instr,
+ long *size)
+{
+ *size = sizeof(fm_xinstrument_t);
+ return 0;
+}
+
+int snd_seq_fm_init(snd_seq_kinstr_ops_t *ops,
+ snd_seq_kinstr_ops_t *next)
+{
+ memset(ops, 0, sizeof(*ops));
+ // ops->private_data = private_data;
+ ops->add_len = sizeof(fm_instrument_t);
+ ops->instr_type = SNDRV_SEQ_INSTR_ID_OPL2_3;
+ ops->put = snd_seq_fm_put;
+ ops->get = snd_seq_fm_get;
+ ops->get_size = snd_seq_fm_get_size;
+ // ops->remove = snd_seq_fm_remove;
+ // ops->notify = snd_seq_fm_notify;
+ ops->next = next;
+ return 0;
+}
+
+/*
+ * Init part
+ */
+
+static int __init alsa_ainstr_fm_init(void)
+{
+ return 0;
+}
+
+static void __exit alsa_ainstr_fm_exit(void)
+{
+}
+
+module_init(alsa_ainstr_fm_init)
+module_exit(alsa_ainstr_fm_exit)
+
+EXPORT_SYMBOL(snd_seq_fm_init);