aboutsummaryrefslogtreecommitdiffstats
path: root/sound/drivers/opl3/opl3_oss.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2007-10-30 06:49:22 -0400
committerJaroslav Kysela <perex@perex.cz>2008-01-31 11:29:13 -0500
commit224a033252bba46c5c8b5df625f5e781ca138f48 (patch)
tree11bb0ad9a3bab736091c73bb46b79d42ee0ff34d /sound/drivers/opl3/opl3_oss.c
parentceac4bf34e14d9040d16b35fd97a92d6e951ccf4 (diff)
[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)
195 195
196/* load patch */ 196/* load patch */
197 197
198/* offsets for SBI params */
199#define AM_VIB 0
200#define KSL_LEVEL 2
201#define ATTACK_DECAY 4
202#define SUSTAIN_RELEASE 6
203#define WAVE_SELECT 8
204
205/* offset for SBI instrument */
206#define CONNECTION 10
207#define OFFSET_4OP 11
208
209/* from sound_config.h */ 198/* from sound_config.h */
210#define SBFM_MAXINSTR 256 199#define SBFM_MAXINSTR 256
211 200
@@ -213,112 +202,42 @@ static int snd_opl3_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format,
213 const char __user *buf, int offs, int count) 202 const char __user *buf, int offs, int count)
214{ 203{
215 struct snd_opl3 *opl3; 204 struct snd_opl3 *opl3;
216 int err = -EINVAL; 205 struct sbi_instrument sbi;
206 char name[32];
207 int err, type;
217 208
218 snd_assert(arg != NULL, return -ENXIO); 209 snd_assert(arg != NULL, return -ENXIO);
219 opl3 = arg->private_data; 210 opl3 = arg->private_data;
220 211
221 if ((format == FM_PATCH) || (format == OPL3_PATCH)) { 212 if (format == FM_PATCH)
222 struct sbi_instrument sbi; 213 type = FM_PATCH_OPL2;
214 else if (format == OPL3_PATCH)
215 type = FM_PATCH_OPL3;
216 else
217 return -EINVAL;
223 218
224 size_t size; 219 if (count < (int)sizeof(sbi)) {
225 struct snd_seq_instr_header *put; 220 snd_printk("FM Error: Patch record too short\n");
226 struct snd_seq_instr_data *data; 221 return -EINVAL;
227 struct fm_xinstrument *xinstr; 222 }
223 if (copy_from_user(&sbi, buf, sizeof(sbi)))
224 return -EFAULT;
228 225
229 struct snd_seq_event ev; 226 if (sbi.channel < 0 || sbi.channel >= SBFM_MAXINSTR) {
230 int i; 227 snd_printk("FM Error: Invalid instrument number %d\n",
228 sbi.channel);
229 return -EINVAL;
230 }
231 231
232 mm_segment_t fs; 232 memset(name, 0, sizeof(name));
233 sprintf(name, "Chan%d", sbi.channel);
233 234
234 if (count < (int)sizeof(sbi)) { 235 err = snd_opl3_load_patch(opl3, sbi.channel, 127, type, name, NULL,
235 snd_printk("FM Error: Patch record too short\n"); 236 sbi.operators);
236 return -EINVAL; 237 if (err < 0)
237 } 238 return err;
238 if (copy_from_user(&sbi, buf, sizeof(sbi)))
239 return -EFAULT;
240 239
241 if (sbi.channel < 0 || sbi.channel >= SBFM_MAXINSTR) { 240 return sizeof(sbi);
242 snd_printk("FM Error: Invalid instrument number %d\n", sbi.channel);
243 return -EINVAL;
244 }
245
246 size = sizeof(*put) + sizeof(struct fm_xinstrument);
247 put = kzalloc(size, GFP_KERNEL);
248 if (put == NULL)
249 return -ENOMEM;
250 /* build header */
251 data = &put->data;
252 data->type = SNDRV_SEQ_INSTR_ATYPE_DATA;
253 strcpy(data->data.format, SNDRV_SEQ_INSTR_ID_OPL2_3);
254 /* build data section */
255 xinstr = (struct fm_xinstrument *)(data + 1);
256 xinstr->stype = FM_STRU_INSTR;
257
258 for (i = 0; i < 2; i++) {
259 xinstr->op[i].am_vib = sbi.operators[AM_VIB + i];
260 xinstr->op[i].ksl_level = sbi.operators[KSL_LEVEL + i];
261 xinstr->op[i].attack_decay = sbi.operators[ATTACK_DECAY + i];
262 xinstr->op[i].sustain_release = sbi.operators[SUSTAIN_RELEASE + i];
263 xinstr->op[i].wave_select = sbi.operators[WAVE_SELECT + i];
264 }
265 xinstr->feedback_connection[0] = sbi.operators[CONNECTION];
266
267 if (format == OPL3_PATCH) {
268 xinstr->type = FM_PATCH_OPL3;
269 for (i = 0; i < 2; i++) {
270 xinstr->op[i+2].am_vib = sbi.operators[OFFSET_4OP + AM_VIB + i];
271 xinstr->op[i+2].ksl_level = sbi.operators[OFFSET_4OP + KSL_LEVEL + i];
272 xinstr->op[i+2].attack_decay = sbi.operators[OFFSET_4OP + ATTACK_DECAY + i];
273 xinstr->op[i+2].sustain_release = sbi.operators[OFFSET_4OP + SUSTAIN_RELEASE + i];
274 xinstr->op[i+2].wave_select = sbi.operators[OFFSET_4OP + WAVE_SELECT + i];
275 }
276 xinstr->feedback_connection[1] = sbi.operators[OFFSET_4OP + CONNECTION];
277 } else {
278 xinstr->type = FM_PATCH_OPL2;
279 }
280
281 put->id.instr.std = SNDRV_SEQ_INSTR_TYPE2_OPL2_3;
282 put->id.instr.bank = 127;
283 put->id.instr.prg = sbi.channel;
284 put->cmd = SNDRV_SEQ_INSTR_PUT_CMD_CREATE;
285
286 memset (&ev, 0, sizeof(ev));
287 ev.source.client = SNDRV_SEQ_CLIENT_OSS;
288 ev.dest = arg->addr;
289
290 ev.flags = SNDRV_SEQ_EVENT_LENGTH_VARUSR;
291 ev.queue = SNDRV_SEQ_QUEUE_DIRECT;
292
293 fs = snd_enter_user();
294 __again:
295 ev.type = SNDRV_SEQ_EVENT_INSTR_PUT;
296 ev.data.ext.len = size;
297 ev.data.ext.ptr = put;
298
299 err = snd_seq_instr_event(&opl3->fm_ops, opl3->ilist, &ev,
300 opl3->seq_client, 0, 0);
301 if (err == -EBUSY) {
302 struct snd_seq_instr_header remove;
303
304 memset (&remove, 0, sizeof(remove));
305 remove.cmd = SNDRV_SEQ_INSTR_FREE_CMD_SINGLE;
306 remove.id.instr = put->id.instr;
307
308 /* remove instrument */
309 ev.type = SNDRV_SEQ_EVENT_INSTR_FREE;
310 ev.data.ext.len = sizeof(remove);
311 ev.data.ext.ptr = &remove;
312
313 snd_seq_instr_event(&opl3->fm_ops, opl3->ilist, &ev,
314 opl3->seq_client, 0, 0);
315 goto __again;
316 }
317 snd_leave_user(fs);
318
319 kfree(put);
320 }
321 return err;
322} 241}
323 242
324/* ioctl */ 243/* ioctl */