aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--include/sound/asound_fm.h19
-rw-r--r--include/sound/opl3.h58
-rw-r--r--sound/drivers/opl3/opl3_lib.c2
-rw-r--r--sound/drivers/opl3/opl3_midi.c41
-rw-r--r--sound/drivers/opl3/opl3_oss.c135
-rw-r--r--sound/drivers/opl3/opl3_seq.c22
-rw-r--r--sound/drivers/opl3/opl3_synth.c168
7 files changed, 289 insertions, 156 deletions
diff --git a/include/sound/asound_fm.h b/include/sound/asound_fm.h
index 8fbcab7cc73b..c2a4b967d5be 100644
--- a/include/sound/asound_fm.h
+++ b/include/sound/asound_fm.h
@@ -104,6 +104,8 @@ struct snd_dm_fm_params {
104#define SNDRV_DM_FM_IOCTL_SET_MODE _IOW('H', 0x25, int) 104#define SNDRV_DM_FM_IOCTL_SET_MODE _IOW('H', 0x25, int)
105/* for OPL3 only */ 105/* for OPL3 only */
106#define SNDRV_DM_FM_IOCTL_SET_CONNECTION _IOW('H', 0x26, int) 106#define SNDRV_DM_FM_IOCTL_SET_CONNECTION _IOW('H', 0x26, int)
107/* SBI patch management */
108#define SNDRV_DM_FM_IOCTL_CLEAR_PATCHES _IO ('H', 0x40)
107 109
108#define SNDRV_DM_FM_OSS_IOCTL_RESET 0x20 110#define SNDRV_DM_FM_OSS_IOCTL_RESET 0x20
109#define SNDRV_DM_FM_OSS_IOCTL_PLAY_NOTE 0x21 111#define SNDRV_DM_FM_OSS_IOCTL_PLAY_NOTE 0x21
@@ -112,4 +114,21 @@ struct snd_dm_fm_params {
112#define SNDRV_DM_FM_OSS_IOCTL_SET_MODE 0x24 114#define SNDRV_DM_FM_OSS_IOCTL_SET_MODE 0x24
113#define SNDRV_DM_FM_OSS_IOCTL_SET_OPL 0x25 115#define SNDRV_DM_FM_OSS_IOCTL_SET_OPL 0x25
114 116
117/*
118 * Patch Record - fixed size for write
119 */
120
121#define FM_KEY_SBI "SBI\032"
122#define FM_KEY_2OP "2OP\032"
123#define FM_KEY_4OP "4OP\032"
124
125struct sbi_patch {
126 unsigned char prog;
127 unsigned char bank;
128 char key[4];
129 char name[25];
130 char extension[7];
131 unsigned char data[32];
132};
133
115#endif /* __SOUND_ASOUND_FM_H */ 134#endif /* __SOUND_ASOUND_FM_H */
diff --git a/include/sound/opl3.h b/include/sound/opl3.h
index 1d14b3f82393..7ee865d6236f 100644
--- a/include/sound/opl3.h
+++ b/include/sound/opl3.h
@@ -63,7 +63,7 @@
63#include "seq_oss_legacy.h" 63#include "seq_oss_legacy.h"
64#endif 64#endif
65#include "seq_device.h" 65#include "seq_device.h"
66#include "ainstr_fm.h" 66#include "asound_fm.h"
67 67
68/* 68/*
69 * Register numbers for the global registers 69 * Register numbers for the global registers
@@ -240,6 +240,47 @@
240struct snd_opl3; 240struct snd_opl3;
241 241
242/* 242/*
243 * Instrument record, aka "Patch"
244 */
245
246/* FM operator */
247struct fm_operator {
248 unsigned char am_vib;
249 unsigned char ksl_level;
250 unsigned char attack_decay;
251 unsigned char sustain_release;
252 unsigned char wave_select;
253} __attribute__((packed));
254
255/* Instrument data */
256struct fm_instrument {
257 struct fm_operator op[4];
258 unsigned char feedback_connection[2];
259 unsigned char echo_delay;
260 unsigned char echo_atten;
261 unsigned char chorus_spread;
262 unsigned char trnsps;
263 unsigned char fix_dur;
264 unsigned char modes;
265 unsigned char fix_key;
266};
267
268/* type */
269#define FM_PATCH_OPL2 0x01 /* OPL2 2 operators FM instrument */
270#define FM_PATCH_OPL3 0x02 /* OPL3 4 operators FM instrument */
271
272/* Instrument record */
273struct fm_patch {
274 unsigned char prog;
275 unsigned char bank;
276 unsigned char type;
277 struct fm_instrument inst;
278 char name[24];
279 struct fm_patch *next;
280};
281
282
283/*
243 * A structure to keep track of each hardware voice 284 * A structure to keep track of each hardware voice
244 */ 285 */
245struct snd_opl3_voice { 286struct snd_opl3_voice {
@@ -297,8 +338,8 @@ struct snd_opl3 {
297 struct snd_midi_channel_set * oss_chset; 338 struct snd_midi_channel_set * oss_chset;
298#endif 339#endif
299 340
300 struct snd_seq_kinstr_ops fm_ops; 341#define OPL3_PATCH_HASH_SIZE 32
301 struct snd_seq_kinstr_list *ilist; 342 struct fm_patch *patch_table[OPL3_PATCH_HASH_SIZE];
302 343
303 struct snd_opl3_voice voices[MAX_OPL3_VOICES]; /* Voices (OPL3 'channel') */ 344 struct snd_opl3_voice voices[MAX_OPL3_VOICES]; /* Voices (OPL3 'channel') */
304 int use_time; /* allocation counter */ 345 int use_time; /* allocation counter */
@@ -333,8 +374,19 @@ int snd_opl3_hwdep_new(struct snd_opl3 * opl3, int device, int seq_device,
333int snd_opl3_open(struct snd_hwdep * hw, struct file *file); 374int snd_opl3_open(struct snd_hwdep * hw, struct file *file);
334int snd_opl3_ioctl(struct snd_hwdep * hw, struct file *file, 375int snd_opl3_ioctl(struct snd_hwdep * hw, struct file *file,
335 unsigned int cmd, unsigned long arg); 376 unsigned int cmd, unsigned long arg);
377long snd_opl3_write(struct snd_hwdep *hw, const char __user *buf, long count,
378 loff_t *offset);
336int snd_opl3_release(struct snd_hwdep * hw, struct file *file); 379int snd_opl3_release(struct snd_hwdep * hw, struct file *file);
337 380
338void snd_opl3_reset(struct snd_opl3 * opl3); 381void snd_opl3_reset(struct snd_opl3 * opl3);
339 382
383int snd_opl3_load_patch(struct snd_opl3 *opl3,
384 int prog, int bank, int type,
385 const char *name,
386 const unsigned char *ext,
387 const unsigned char *data);
388struct fm_patch *snd_opl3_find_patch(struct snd_opl3 *opl3, int prog, int bank,
389 int create_patch);
390void snd_opl3_clear_patches(struct snd_opl3 *opl3);
391
340#endif /* __SOUND_OPL3_H */ 392#endif /* __SOUND_OPL3_H */
diff --git a/sound/drivers/opl3/opl3_lib.c b/sound/drivers/opl3/opl3_lib.c
index a2b9ce060295..a657da922b4d 100644
--- a/sound/drivers/opl3/opl3_lib.c
+++ b/sound/drivers/opl3/opl3_lib.c
@@ -327,6 +327,7 @@ static int snd_opl3_free(struct snd_opl3 *opl3)
327 snd_assert(opl3 != NULL, return -ENXIO); 327 snd_assert(opl3 != NULL, return -ENXIO);
328 if (opl3->private_free) 328 if (opl3->private_free)
329 opl3->private_free(opl3); 329 opl3->private_free(opl3);
330 snd_opl3_clear_patches(opl3);
330 release_and_free_resource(opl3->res_l_port); 331 release_and_free_resource(opl3->res_l_port);
331 release_and_free_resource(opl3->res_r_port); 332 release_and_free_resource(opl3->res_r_port);
332 kfree(opl3); 333 kfree(opl3);
@@ -521,6 +522,7 @@ int snd_opl3_hwdep_new(struct snd_opl3 * opl3,
521 /* operators - only ioctl */ 522 /* operators - only ioctl */
522 hw->ops.open = snd_opl3_open; 523 hw->ops.open = snd_opl3_open;
523 hw->ops.ioctl = snd_opl3_ioctl; 524 hw->ops.ioctl = snd_opl3_ioctl;
525 hw->ops.write = snd_opl3_write;
524 hw->ops.release = snd_opl3_release; 526 hw->ops.release = snd_opl3_release;
525 527
526 opl3->seq_dev_num = seq_device; 528 opl3->seq_dev_num = seq_device;
diff --git a/sound/drivers/opl3/opl3_midi.c b/sound/drivers/opl3/opl3_midi.c
index 3557b6e20eb5..cebcb8b78acb 100644
--- a/sound/drivers/opl3/opl3_midi.c
+++ b/sound/drivers/opl3/opl3_midi.c
@@ -289,8 +289,6 @@ static int snd_opl3_oss_map[MAX_OPL3_VOICES] = {
289void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan) 289void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
290{ 290{
291 struct snd_opl3 *opl3; 291 struct snd_opl3 *opl3;
292 struct snd_seq_instr wanted;
293 struct snd_seq_kinstr *kinstr;
294 int instr_4op; 292 int instr_4op;
295 293
296 int voice; 294 int voice;
@@ -306,11 +304,13 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
306 unsigned char voice_offset; 304 unsigned char voice_offset;
307 unsigned short opl3_reg; 305 unsigned short opl3_reg;
308 unsigned char reg_val; 306 unsigned char reg_val;
307 unsigned char prg, bank;
309 308
310 int key = note; 309 int key = note;
311 unsigned char fnum, blocknum; 310 unsigned char fnum, blocknum;
312 int i; 311 int i;
313 312
313 struct fm_patch *patch;
314 struct fm_instrument *fm; 314 struct fm_instrument *fm;
315 unsigned long flags; 315 unsigned long flags;
316 316
@@ -320,19 +320,17 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
320 snd_printk("Note on, ch %i, inst %i, note %i, vel %i\n", 320 snd_printk("Note on, ch %i, inst %i, note %i, vel %i\n",
321 chan->number, chan->midi_program, note, vel); 321 chan->number, chan->midi_program, note, vel);
322#endif 322#endif
323 wanted.cluster = 0;
324 wanted.std = SNDRV_SEQ_INSTR_TYPE2_OPL2_3;
325 323
326 /* in SYNTH mode, application takes care of voices */ 324 /* in SYNTH mode, application takes care of voices */
327 /* in SEQ mode, drum voice numbers are notes on drum channel */ 325 /* in SEQ mode, drum voice numbers are notes on drum channel */
328 if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) { 326 if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) {
329 if (chan->drum_channel) { 327 if (chan->drum_channel) {
330 /* percussion instruments are located in bank 128 */ 328 /* percussion instruments are located in bank 128 */
331 wanted.bank = 128; 329 bank = 128;
332 wanted.prg = note; 330 prg = note;
333 } else { 331 } else {
334 wanted.bank = chan->gm_bank_select; 332 bank = chan->gm_bank_select;
335 wanted.prg = chan->midi_program; 333 prg = chan->midi_program;
336 } 334 }
337 } else { 335 } else {
338 /* Prepare for OSS mode */ 336 /* Prepare for OSS mode */
@@ -340,8 +338,8 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
340 return; 338 return;
341 339
342 /* OSS instruments are located in bank 127 */ 340 /* OSS instruments are located in bank 127 */
343 wanted.bank = 127; 341 bank = 127;
344 wanted.prg = chan->midi_program; 342 prg = chan->midi_program;
345 } 343 }
346 344
347 spin_lock_irqsave(&opl3->voice_lock, flags); 345 spin_lock_irqsave(&opl3->voice_lock, flags);
@@ -353,15 +351,14 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
353 } 351 }
354 352
355 __extra_prg: 353 __extra_prg:
356 kinstr = snd_seq_instr_find(opl3->ilist, &wanted, 1, 0); 354 patch = snd_opl3_find_patch(opl3, prg, bank, 0);
357 if (kinstr == NULL) { 355 if (!patch) {
358 spin_unlock_irqrestore(&opl3->voice_lock, flags); 356 spin_unlock_irqrestore(&opl3->voice_lock, flags);
359 return; 357 return;
360 } 358 }
361 359
362 fm = KINSTR_DATA(kinstr); 360 fm = &patch->inst;
363 361 switch (patch->type) {
364 switch (fm->type) {
365 case FM_PATCH_OPL2: 362 case FM_PATCH_OPL2:
366 instr_4op = 0; 363 instr_4op = 0;
367 break; 364 break;
@@ -371,14 +368,12 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
371 break; 368 break;
372 } 369 }
373 default: 370 default:
374 snd_seq_instr_free_use(opl3->ilist, kinstr);
375 spin_unlock_irqrestore(&opl3->voice_lock, flags); 371 spin_unlock_irqrestore(&opl3->voice_lock, flags);
376 return; 372 return;
377 } 373 }
378
379#ifdef DEBUG_MIDI 374#ifdef DEBUG_MIDI
380 snd_printk(" --> OPL%i instrument: %s\n", 375 snd_printk(" --> OPL%i instrument: %s\n",
381 instr_4op ? 3 : 2, kinstr->name); 376 instr_4op ? 3 : 2, patch->name);
382#endif 377#endif
383 /* in SYNTH mode, application takes care of voices */ 378 /* in SYNTH mode, application takes care of voices */
384 /* in SEQ mode, allocate voice on free OPL3 channel */ 379 /* in SEQ mode, allocate voice on free OPL3 channel */
@@ -569,8 +564,6 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
569 /* get extra pgm, but avoid possible loops */ 564 /* get extra pgm, but avoid possible loops */
570 extra_prg = (extra_prg) ? 0 : fm->modes; 565 extra_prg = (extra_prg) ? 0 : fm->modes;
571 566
572 snd_seq_instr_free_use(opl3->ilist, kinstr);
573
574 /* do the bookkeeping */ 567 /* do the bookkeeping */
575 vp->time = opl3->use_time++; 568 vp->time = opl3->use_time++;
576 vp->note = key; 569 vp->note = key;
@@ -601,12 +594,12 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
601 /* allocate extra program if specified in patch library */ 594 /* allocate extra program if specified in patch library */
602 if (extra_prg) { 595 if (extra_prg) {
603 if (extra_prg > 128) { 596 if (extra_prg > 128) {
604 wanted.bank = 128; 597 bank = 128;
605 /* percussions start at 35 */ 598 /* percussions start at 35 */
606 wanted.prg = extra_prg - 128 + 35 - 1; 599 prg = extra_prg - 128 + 35 - 1;
607 } else { 600 } else {
608 wanted.bank = 0; 601 bank = 0;
609 wanted.prg = extra_prg - 1; 602 prg = extra_prg - 1;
610 } 603 }
611#ifdef DEBUG_MIDI 604#ifdef DEBUG_MIDI
612 snd_printk(" *** allocating extra program\n"); 605 snd_printk(" *** allocating extra program\n");
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 */
diff --git a/sound/drivers/opl3/opl3_seq.c b/sound/drivers/opl3/opl3_seq.c
index 96762c9d4855..ff6da16b9178 100644
--- a/sound/drivers/opl3/opl3_seq.c
+++ b/sound/drivers/opl3/opl3_seq.c
@@ -152,15 +152,7 @@ static int snd_opl3_synth_event_input(struct snd_seq_event * ev, int direct,
152{ 152{
153 struct snd_opl3 *opl3 = private_data; 153 struct snd_opl3 *opl3 = private_data;
154 154
155 if (ev->type >= SNDRV_SEQ_EVENT_INSTR_BEGIN && 155 snd_midi_process_event(&opl3_ops, ev, opl3->chset);
156 ev->type <= SNDRV_SEQ_EVENT_INSTR_CHANGE) {
157 if (direct) {
158 snd_seq_instr_event(&opl3->fm_ops, opl3->ilist, ev,
159 opl3->seq_client, atomic, hop);
160 }
161 } else {
162 snd_midi_process_event(&opl3_ops, ev, opl3->chset);
163 }
164 return 0; 156 return 0;
165} 157}
166 158
@@ -249,16 +241,6 @@ static int snd_opl3_seq_new_device(struct snd_seq_device *dev)
249 return err; 241 return err;
250 } 242 }
251 243
252 /* initialize instrument list */
253 opl3->ilist = snd_seq_instr_list_new();
254 if (opl3->ilist == NULL) {
255 snd_seq_delete_kernel_client(client);
256 opl3->seq_client = -1;
257 return -ENOMEM;
258 }
259 opl3->ilist->flags = SNDRV_SEQ_INSTR_FLG_DIRECT;
260 snd_seq_fm_init(&opl3->fm_ops, NULL);
261
262 /* setup system timer */ 244 /* setup system timer */
263 init_timer(&opl3->tlist); 245 init_timer(&opl3->tlist);
264 opl3->tlist.function = snd_opl3_timer_func; 246 opl3->tlist.function = snd_opl3_timer_func;
@@ -287,8 +269,6 @@ static int snd_opl3_seq_delete_device(struct snd_seq_device *dev)
287 snd_seq_delete_kernel_client(opl3->seq_client); 269 snd_seq_delete_kernel_client(opl3->seq_client);
288 opl3->seq_client = -1; 270 opl3->seq_client = -1;
289 } 271 }
290 if (opl3->ilist)
291 snd_seq_instr_list_free(&opl3->ilist);
292 return 0; 272 return 0;
293} 273}
294 274
diff --git a/sound/drivers/opl3/opl3_synth.c b/sound/drivers/opl3/opl3_synth.c
index a4b3543a7118..d55eefce44c1 100644
--- a/sound/drivers/opl3/opl3_synth.c
+++ b/sound/drivers/opl3/opl3_synth.c
@@ -165,6 +165,10 @@ int snd_opl3_ioctl(struct snd_hwdep * hw, struct file *file,
165#endif 165#endif
166 return snd_opl3_set_connection(opl3, (int) arg); 166 return snd_opl3_set_connection(opl3, (int) arg);
167 167
168 case SNDRV_DM_FM_IOCTL_CLEAR_PATCHES:
169 snd_opl3_clear_patches(opl3);
170 return 0;
171
168#ifdef CONFIG_SND_DEBUG 172#ifdef CONFIG_SND_DEBUG
169 default: 173 default:
170 snd_printk("unknown IOCTL: 0x%x\n", cmd); 174 snd_printk("unknown IOCTL: 0x%x\n", cmd);
@@ -188,6 +192,170 @@ int snd_opl3_release(struct snd_hwdep * hw, struct file *file)
188 return 0; 192 return 0;
189} 193}
190 194
195/*
196 * write the device - load patches
197 */
198long snd_opl3_write(struct snd_hwdep *hw, const char __user *buf, long count,
199 loff_t *offset)
200{
201 struct snd_opl3 *opl3 = hw->private_data;
202 long result = 0;
203 int err = 0;
204 struct sbi_patch inst;
205
206 while (count >= sizeof(inst)) {
207 unsigned char type;
208 if (copy_from_user(&inst, buf, sizeof(inst)))
209 return -EFAULT;
210 if (!memcmp(inst.key, FM_KEY_SBI, 4) ||
211 !memcmp(inst.key, FM_KEY_2OP, 4))
212 type = FM_PATCH_OPL2;
213 else if (!memcmp(inst.key, FM_KEY_4OP, 4))
214 type = FM_PATCH_OPL3;
215 else /* invalid type */
216 break;
217 err = snd_opl3_load_patch(opl3, inst.prog, inst.bank, type,
218 inst.name, inst.extension,
219 inst.data);
220 if (err < 0)
221 break;
222 result += sizeof(inst);
223 count -= sizeof(inst);
224 }
225 return result > 0 ? result : err;
226}
227
228
229/*
230 * Patch management
231 */
232
233/* offsets for SBI params */
234#define AM_VIB 0
235#define KSL_LEVEL 2
236#define ATTACK_DECAY 4
237#define SUSTAIN_RELEASE 6
238#define WAVE_SELECT 8
239
240/* offset for SBI instrument */
241#define CONNECTION 10
242#define OFFSET_4OP 11
243
244/*
245 * load a patch, obviously.
246 *
247 * loaded on the given program and bank numbers with the given type
248 * (FM_PATCH_OPLx).
249 * data is the pointer of SBI record _without_ header (key and name).
250 * name is the name string of the patch.
251 * ext is the extension data of 7 bytes long (stored in name of SBI
252 * data up to offset 25), or NULL to skip.
253 * return 0 if successful or a negative error code.
254 */
255int snd_opl3_load_patch(struct snd_opl3 *opl3,
256 int prog, int bank, int type,
257 const char *name,
258 const unsigned char *ext,
259 const unsigned char *data)
260{
261 struct fm_patch *patch;
262 int i;
263
264 patch = snd_opl3_find_patch(opl3, prog, bank, 1);
265 if (!patch)
266 return -ENOMEM;
267
268 patch->type = type;
269
270 for (i = 0; i < 2; i++) {
271 patch->inst.op[i].am_vib = data[AM_VIB + i];
272 patch->inst.op[i].ksl_level = data[KSL_LEVEL + i];
273 patch->inst.op[i].attack_decay = data[ATTACK_DECAY + i];
274 patch->inst.op[i].sustain_release = data[SUSTAIN_RELEASE + i];
275 patch->inst.op[i].wave_select = data[WAVE_SELECT + i];
276 }
277 patch->inst.feedback_connection[0] = data[CONNECTION];
278
279 if (type == FM_PATCH_OPL3) {
280 for (i = 0; i < 2; i++) {
281 patch->inst.op[i+2].am_vib =
282 data[OFFSET_4OP + AM_VIB + i];
283 patch->inst.op[i+2].ksl_level =
284 data[OFFSET_4OP + KSL_LEVEL + i];
285 patch->inst.op[i+2].attack_decay =
286 data[OFFSET_4OP + ATTACK_DECAY + i];
287 patch->inst.op[i+2].sustain_release =
288 data[OFFSET_4OP + SUSTAIN_RELEASE + i];
289 patch->inst.op[i+2].wave_select =
290 data[OFFSET_4OP + WAVE_SELECT + i];
291 }
292 patch->inst.feedback_connection[1] =
293 data[OFFSET_4OP + CONNECTION];
294 }
295
296 if (ext) {
297 patch->inst.echo_delay = ext[0];
298 patch->inst.echo_atten = ext[1];
299 patch->inst.chorus_spread = ext[2];
300 patch->inst.trnsps = ext[3];
301 patch->inst.fix_dur = ext[4];
302 patch->inst.modes = ext[5];
303 patch->inst.fix_key = ext[6];
304 }
305
306 if (name)
307 strlcpy(patch->name, name, sizeof(patch->name));
308
309 return 0;
310}
311EXPORT_SYMBOL(snd_opl3_load_patch);
312
313/*
314 * find a patch with the given program and bank numbers, returns its pointer
315 * if no matching patch is found and create_patch is set, it creates a
316 * new patch object.
317 */
318struct fm_patch *snd_opl3_find_patch(struct snd_opl3 *opl3, int prog, int bank,
319 int create_patch)
320{
321 /* pretty dumb hash key */
322 unsigned int key = (prog + bank) % OPL3_PATCH_HASH_SIZE;
323 struct fm_patch *patch;
324
325 for (patch = opl3->patch_table[key]; patch; patch = patch->next) {
326 if (patch->prog == prog && patch->bank == bank)
327 return patch;
328 }
329 if (!create_patch)
330 return NULL;
331
332 patch = kzalloc(sizeof(*patch), GFP_KERNEL);
333 if (!patch)
334 return NULL;
335 patch->prog = prog;
336 patch->bank = bank;
337 patch->next = opl3->patch_table[key];
338 opl3->patch_table[key] = patch;
339 return patch;
340}
341EXPORT_SYMBOL(snd_opl3_find_patch);
342
343/*
344 * Clear all patches of the given OPL3 instance
345 */
346void snd_opl3_clear_patches(struct snd_opl3 *opl3)
347{
348 int i;
349 for (i = 0; i < OPL3_PATCH_HASH_SIZE; i++) {
350 struct fm_patch *patch, *next;
351 for (patch = opl3->patch_table[i]; patch; patch = next) {
352 next = patch->next;
353 kfree(patch);
354 }
355 }
356 memset(opl3->patch_table, 0, sizeof(opl3->patch_table));
357}
358
191/* ------------------------------ */ 359/* ------------------------------ */
192 360
193void snd_opl3_reset(struct snd_opl3 * opl3) 361void snd_opl3_reset(struct snd_opl3 * opl3)