aboutsummaryrefslogtreecommitdiffstats
path: root/sound/drivers/opl3/opl3_synth.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_synth.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_synth.c')
-rw-r--r--sound/drivers/opl3/opl3_synth.c168
1 files changed, 168 insertions, 0 deletions
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)