[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>
This commit is contained in:
Takashi Iwai
2007-10-30 11:49:22 +01:00
committed by Jaroslav Kysela
parent ceac4bf34e
commit 224a033252
7 changed files with 292 additions and 159 deletions

View File

@@ -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;
struct snd_seq_event ev;
int i;
mm_segment_t fs;
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;
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);
if (count < (int)sizeof(sbi)) {
snd_printk("FM Error: Patch record too short\n");
return -EINVAL;
}
return err;
if (copy_from_user(&sbi, buf, sizeof(sbi)))
return -EFAULT;
if (sbi.channel < 0 || sbi.channel >= SBFM_MAXINSTR) {
snd_printk("FM Error: Invalid instrument number %d\n",
sbi.channel);
return -EINVAL;
}
memset(name, 0, sizeof(name));
sprintf(name, "Chan%d", sbi.channel);
err = snd_opl3_load_patch(opl3, sbi.channel, 127, type, name, NULL,
sbi.operators);
if (err < 0)
return err;
return sizeof(sbi);
}
/* ioctl */