diff options
author | Takashi Iwai <tiwai@suse.de> | 2007-10-30 06:49:22 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2008-01-31 11:29:13 -0500 |
commit | 224a033252bba46c5c8b5df625f5e781ca138f48 (patch) | |
tree | 11bb0ad9a3bab736091c73bb46b79d42ee0ff34d /sound/drivers/opl3/opl3_oss.c | |
parent | ceac4bf34e14d9040d16b35fd97a92d6e951ccf4 (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.c | 135 |
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 */ |