summaryrefslogtreecommitdiffstats
path: root/sound/drivers/opl3/opl3_oss.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2007-10-30 11:49:22 +0100
committerJaroslav Kysela <perex@perex.cz>2008-01-31 17:29:13 +0100
commit224a033252bba46c5c8b5df625f5e781ca138f48 (patch)
tree11bb0ad9a3bab736091c73bb46b79d42ee0ff34d /sound/drivers/opl3/opl3_oss.c
parent[ALSA] Dreamcast AICA sound - Get rid of annoying compiler warning (diff)
downloadlinux-224a033252bba46c5c8b5df625f5e781ca138f48.tar.xz
linux-224a033252bba46c5c8b5df625f5e781ca138f48.zip
[ALSA] opl3 - Use hwdep for patch loading
Use the hwdep device for loading OPL2/3 patch data instead of the messy sequencer instrument layer. Due to this change, the sbiload program should be updated, too. Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound/drivers/opl3/opl3_oss.c')
-rw-r--r--sound/drivers/opl3/opl3_oss.c135
1 files changed, 27 insertions, 108 deletions
diff --git a/sound/drivers/opl3/opl3_oss.c b/sound/drivers/opl3/opl3_oss.c
index 5fd3a4c95626..239347f26154 100644
--- a/sound/drivers/opl3/opl3_oss.c
+++ b/sound/drivers/opl3/opl3_oss.c
@@ -195,17 +195,6 @@ static int snd_opl3_close_seq_oss(struct snd_seq_oss_arg *arg)
/* load patch */
-/* offsets for SBI params */
-#define AM_VIB 0
-#define KSL_LEVEL 2
-#define ATTACK_DECAY 4
-#define SUSTAIN_RELEASE 6
-#define WAVE_SELECT 8
-
-/* offset for SBI instrument */
-#define CONNECTION 10
-#define OFFSET_4OP 11
-
/* from sound_config.h */
#define SBFM_MAXINSTR 256
@@ -213,112 +202,42 @@ static int snd_opl3_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format,
const char __user *buf, int offs, int count)
{
struct snd_opl3 *opl3;
- int err = -EINVAL;
+ struct sbi_instrument sbi;
+ char name[32];
+ int err, type;
snd_assert(arg != NULL, return -ENXIO);
opl3 = arg->private_data;
- if ((format == FM_PATCH) || (format == OPL3_PATCH)) {
- struct sbi_instrument sbi;
+ if (format == FM_PATCH)
+ type = FM_PATCH_OPL2;
+ else if (format == OPL3_PATCH)
+ type = FM_PATCH_OPL3;
+ else
+ return -EINVAL;
- size_t size;
- struct snd_seq_instr_header *put;
- struct snd_seq_instr_data *data;
- struct fm_xinstrument *xinstr;
+ if (count < (int)sizeof(sbi)) {
+ snd_printk("FM Error: Patch record too short\n");
+ return -EINVAL;
+ }
+ if (copy_from_user(&sbi, buf, sizeof(sbi)))
+ return -EFAULT;
- struct snd_seq_event ev;
- int i;
+ if (sbi.channel < 0 || sbi.channel >= SBFM_MAXINSTR) {
+ snd_printk("FM Error: Invalid instrument number %d\n",
+ sbi.channel);
+ return -EINVAL;
+ }
- mm_segment_t fs;
+ memset(name, 0, sizeof(name));
+ sprintf(name, "Chan%d", sbi.channel);
- if (count < (int)sizeof(sbi)) {
- snd_printk("FM Error: Patch record too short\n");
- return -EINVAL;
- }
- if (copy_from_user(&sbi, buf, sizeof(sbi)))
- return -EFAULT;
+ err = snd_opl3_load_patch(opl3, sbi.channel, 127, type, name, NULL,
+ sbi.operators);
+ if (err < 0)
+ return err;
- if (sbi.channel < 0 || sbi.channel >= SBFM_MAXINSTR) {
- snd_printk("FM Error: Invalid instrument number %d\n", sbi.channel);
- return -EINVAL;
- }
-
- size = sizeof(*put) + sizeof(struct fm_xinstrument);
- put = kzalloc(size, GFP_KERNEL);
- if (put == NULL)
- return -ENOMEM;
- /* build header */
- data = &put->data;
- data->type = SNDRV_SEQ_INSTR_ATYPE_DATA;
- strcpy(data->data.format, SNDRV_SEQ_INSTR_ID_OPL2_3);
- /* build data section */
- xinstr = (struct fm_xinstrument *)(data + 1);
- xinstr->stype = FM_STRU_INSTR;
-
- for (i = 0; i < 2; i++) {
- xinstr->op[i].am_vib = sbi.operators[AM_VIB + i];
- xinstr->op[i].ksl_level = sbi.operators[KSL_LEVEL + i];
- xinstr->op[i].attack_decay = sbi.operators[ATTACK_DECAY + i];
- xinstr->op[i].sustain_release = sbi.operators[SUSTAIN_RELEASE + i];
- xinstr->op[i].wave_select = sbi.operators[WAVE_SELECT + i];
- }
- xinstr->feedback_connection[0] = sbi.operators[CONNECTION];
-
- if (format == OPL3_PATCH) {
- xinstr->type = FM_PATCH_OPL3;
- for (i = 0; i < 2; i++) {
- xinstr->op[i+2].am_vib = sbi.operators[OFFSET_4OP + AM_VIB + i];
- xinstr->op[i+2].ksl_level = sbi.operators[OFFSET_4OP + KSL_LEVEL + i];
- xinstr->op[i+2].attack_decay = sbi.operators[OFFSET_4OP + ATTACK_DECAY + i];
- xinstr->op[i+2].sustain_release = sbi.operators[OFFSET_4OP + SUSTAIN_RELEASE + i];
- xinstr->op[i+2].wave_select = sbi.operators[OFFSET_4OP + WAVE_SELECT + i];
- }
- xinstr->feedback_connection[1] = sbi.operators[OFFSET_4OP + CONNECTION];
- } else {
- xinstr->type = FM_PATCH_OPL2;
- }
-
- put->id.instr.std = SNDRV_SEQ_INSTR_TYPE2_OPL2_3;
- put->id.instr.bank = 127;
- put->id.instr.prg = sbi.channel;
- put->cmd = SNDRV_SEQ_INSTR_PUT_CMD_CREATE;
-
- memset (&ev, 0, sizeof(ev));
- ev.source.client = SNDRV_SEQ_CLIENT_OSS;
- ev.dest = arg->addr;
-
- ev.flags = SNDRV_SEQ_EVENT_LENGTH_VARUSR;
- ev.queue = SNDRV_SEQ_QUEUE_DIRECT;
-
- fs = snd_enter_user();
- __again:
- ev.type = SNDRV_SEQ_EVENT_INSTR_PUT;
- ev.data.ext.len = size;
- ev.data.ext.ptr = put;
-
- err = snd_seq_instr_event(&opl3->fm_ops, opl3->ilist, &ev,
- opl3->seq_client, 0, 0);
- if (err == -EBUSY) {
- struct snd_seq_instr_header remove;
-
- memset (&remove, 0, sizeof(remove));
- remove.cmd = SNDRV_SEQ_INSTR_FREE_CMD_SINGLE;
- remove.id.instr = put->id.instr;
-
- /* remove instrument */
- ev.type = SNDRV_SEQ_EVENT_INSTR_FREE;
- ev.data.ext.len = sizeof(remove);
- ev.data.ext.ptr = &remove;
-
- snd_seq_instr_event(&opl3->fm_ops, opl3->ilist, &ev,
- opl3->seq_client, 0, 0);
- goto __again;
- }
- snd_leave_user(fs);
-
- kfree(put);
- }
- return err;
+ return sizeof(sbi);
}
/* ioctl */