xref: /openbmc/linux/sound/synth/emux/emux_oss.c (revision 827634ad)
1 /*
2  *  Interface for OSS sequencer emulation
3  *
4  *  Copyright (C) 1999 Takashi Iwai <tiwai@suse.de>
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19  *
20  * Changes
21  * 19990227   Steve Ratcliffe   Made separate file and merged in latest
22  * 				midi emulation.
23  */
24 
25 
26 #ifdef CONFIG_SND_SEQUENCER_OSS
27 
28 #include <linux/export.h>
29 #include <linux/uaccess.h>
30 #include <sound/core.h>
31 #include "emux_voice.h"
32 #include <sound/asoundef.h>
33 
34 static int snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure);
35 static int snd_emux_close_seq_oss(struct snd_seq_oss_arg *arg);
36 static int snd_emux_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd,
37 				  unsigned long ioarg);
38 static int snd_emux_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format,
39 				       const char __user *buf, int offs, int count);
40 static int snd_emux_reset_seq_oss(struct snd_seq_oss_arg *arg);
41 static int snd_emux_event_oss_input(struct snd_seq_event *ev, int direct,
42 				    void *private, int atomic, int hop);
43 static void reset_port_mode(struct snd_emux_port *port, int midi_mode);
44 static void emuspec_control(struct snd_emux *emu, struct snd_emux_port *port,
45 			    int cmd, unsigned char *event, int atomic, int hop);
46 static void gusspec_control(struct snd_emux *emu, struct snd_emux_port *port,
47 			    int cmd, unsigned char *event, int atomic, int hop);
48 static void fake_event(struct snd_emux *emu, struct snd_emux_port *port,
49 		       int ch, int param, int val, int atomic, int hop);
50 
51 /* operators */
52 static struct snd_seq_oss_callback oss_callback = {
53 	.owner = THIS_MODULE,
54 	.open = snd_emux_open_seq_oss,
55 	.close = snd_emux_close_seq_oss,
56 	.ioctl = snd_emux_ioctl_seq_oss,
57 	.load_patch = snd_emux_load_patch_seq_oss,
58 	.reset = snd_emux_reset_seq_oss,
59 };
60 
61 
62 /*
63  * register OSS synth
64  */
65 
66 void
67 snd_emux_init_seq_oss(struct snd_emux *emu)
68 {
69 	struct snd_seq_oss_reg *arg;
70 	struct snd_seq_device *dev;
71 
72 	if (snd_seq_device_new(emu->card, 0, SNDRV_SEQ_DEV_ID_OSS,
73 			       sizeof(struct snd_seq_oss_reg), &dev) < 0)
74 		return;
75 
76 	emu->oss_synth = dev;
77 	strcpy(dev->name, emu->name);
78 	arg = SNDRV_SEQ_DEVICE_ARGPTR(dev);
79 	arg->type = SYNTH_TYPE_SAMPLE;
80 	arg->subtype = SAMPLE_TYPE_AWE32;
81 	arg->nvoices = emu->max_voices;
82 	arg->oper = oss_callback;
83 	arg->private_data = emu;
84 
85 	/* register to OSS synth table */
86 	snd_device_register(emu->card, dev);
87 }
88 
89 
90 /*
91  * unregister
92  */
93 void
94 snd_emux_detach_seq_oss(struct snd_emux *emu)
95 {
96 	if (emu->oss_synth) {
97 		snd_device_free(emu->card, emu->oss_synth);
98 		emu->oss_synth = NULL;
99 	}
100 }
101 
102 
103 /* use port number as a unique soundfont client number */
104 #define SF_CLIENT_NO(p)	((p) + 0x1000)
105 
106 /*
107  * open port for OSS sequencer
108  */
109 static int
110 snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure)
111 {
112 	struct snd_emux *emu;
113 	struct snd_emux_port *p;
114 	struct snd_seq_port_callback callback;
115 	char tmpname[64];
116 
117 	emu = closure;
118 	if (snd_BUG_ON(!arg || !emu))
119 		return -ENXIO;
120 
121 	if (!snd_emux_inc_count(emu))
122 		return -EFAULT;
123 
124 	memset(&callback, 0, sizeof(callback));
125 	callback.owner = THIS_MODULE;
126 	callback.event_input = snd_emux_event_oss_input;
127 
128 	sprintf(tmpname, "%s OSS Port", emu->name);
129 	p = snd_emux_create_port(emu, tmpname, 32,
130 				 1, &callback);
131 	if (p == NULL) {
132 		snd_printk(KERN_ERR "can't create port\n");
133 		snd_emux_dec_count(emu);
134 		return -ENOMEM;
135 	}
136 
137 	/* fill the argument data */
138 	arg->private_data = p;
139 	arg->addr.client = p->chset.client;
140 	arg->addr.port = p->chset.port;
141 	p->oss_arg = arg;
142 
143 	reset_port_mode(p, arg->seq_mode);
144 
145 	snd_emux_reset_port(p);
146 	return 0;
147 }
148 
149 
150 #define DEFAULT_DRUM_FLAGS	((1<<9) | (1<<25))
151 
152 /*
153  * reset port mode
154  */
155 static void
156 reset_port_mode(struct snd_emux_port *port, int midi_mode)
157 {
158 	if (midi_mode) {
159 		port->port_mode = SNDRV_EMUX_PORT_MODE_OSS_MIDI;
160 		port->drum_flags = DEFAULT_DRUM_FLAGS;
161 		port->volume_atten = 0;
162 		port->oss_arg->event_passing = SNDRV_SEQ_OSS_PROCESS_KEYPRESS;
163 	} else {
164 		port->port_mode = SNDRV_EMUX_PORT_MODE_OSS_SYNTH;
165 		port->drum_flags = 0;
166 		port->volume_atten = 32;
167 		port->oss_arg->event_passing = SNDRV_SEQ_OSS_PROCESS_EVENTS;
168 	}
169 }
170 
171 
172 /*
173  * close port
174  */
175 static int
176 snd_emux_close_seq_oss(struct snd_seq_oss_arg *arg)
177 {
178 	struct snd_emux *emu;
179 	struct snd_emux_port *p;
180 
181 	if (snd_BUG_ON(!arg))
182 		return -ENXIO;
183 	p = arg->private_data;
184 	if (snd_BUG_ON(!p))
185 		return -ENXIO;
186 
187 	emu = p->emu;
188 	if (snd_BUG_ON(!emu))
189 		return -ENXIO;
190 
191 	snd_emux_sounds_off_all(p);
192 	snd_soundfont_close_check(emu->sflist, SF_CLIENT_NO(p->chset.port));
193 	snd_seq_event_port_detach(p->chset.client, p->chset.port);
194 	snd_emux_dec_count(emu);
195 
196 	return 0;
197 }
198 
199 
200 /*
201  * load patch
202  */
203 static int
204 snd_emux_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format,
205 			    const char __user *buf, int offs, int count)
206 {
207 	struct snd_emux *emu;
208 	struct snd_emux_port *p;
209 	int rc;
210 
211 	if (snd_BUG_ON(!arg))
212 		return -ENXIO;
213 	p = arg->private_data;
214 	if (snd_BUG_ON(!p))
215 		return -ENXIO;
216 
217 	emu = p->emu;
218 	if (snd_BUG_ON(!emu))
219 		return -ENXIO;
220 
221 	if (format == GUS_PATCH)
222 		rc = snd_soundfont_load_guspatch(emu->sflist, buf, count,
223 						 SF_CLIENT_NO(p->chset.port));
224 	else if (format == SNDRV_OSS_SOUNDFONT_PATCH) {
225 		struct soundfont_patch_info patch;
226 		if (count < (int)sizeof(patch))
227 			rc = -EINVAL;
228 		if (copy_from_user(&patch, buf, sizeof(patch)))
229 			rc = -EFAULT;
230 		if (patch.type >= SNDRV_SFNT_LOAD_INFO &&
231 		    patch.type <= SNDRV_SFNT_PROBE_DATA)
232 			rc = snd_soundfont_load(emu->sflist, buf, count, SF_CLIENT_NO(p->chset.port));
233 		else {
234 			if (emu->ops.load_fx)
235 				rc = emu->ops.load_fx(emu, patch.type, patch.optarg, buf, count);
236 			else
237 				rc = -EINVAL;
238 		}
239 	} else
240 		rc = 0;
241 	return rc;
242 }
243 
244 
245 /*
246  * ioctl
247  */
248 static int
249 snd_emux_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd, unsigned long ioarg)
250 {
251 	struct snd_emux_port *p;
252 	struct snd_emux *emu;
253 
254 	if (snd_BUG_ON(!arg))
255 		return -ENXIO;
256 	p = arg->private_data;
257 	if (snd_BUG_ON(!p))
258 		return -ENXIO;
259 
260 	emu = p->emu;
261 	if (snd_BUG_ON(!emu))
262 		return -ENXIO;
263 
264 	switch (cmd) {
265 	case SNDCTL_SEQ_RESETSAMPLES:
266 		snd_soundfont_remove_samples(emu->sflist);
267 		return 0;
268 
269 	case SNDCTL_SYNTH_MEMAVL:
270 		if (emu->memhdr)
271 			return snd_util_mem_avail(emu->memhdr);
272 		return 0;
273 	}
274 
275 	return 0;
276 }
277 
278 
279 /*
280  * reset device
281  */
282 static int
283 snd_emux_reset_seq_oss(struct snd_seq_oss_arg *arg)
284 {
285 	struct snd_emux_port *p;
286 
287 	if (snd_BUG_ON(!arg))
288 		return -ENXIO;
289 	p = arg->private_data;
290 	if (snd_BUG_ON(!p))
291 		return -ENXIO;
292 	snd_emux_reset_port(p);
293 	return 0;
294 }
295 
296 
297 /*
298  * receive raw events: only SEQ_PRIVATE is accepted.
299  */
300 static int
301 snd_emux_event_oss_input(struct snd_seq_event *ev, int direct, void *private_data,
302 			 int atomic, int hop)
303 {
304 	struct snd_emux *emu;
305 	struct snd_emux_port *p;
306 	unsigned char cmd, *data;
307 
308 	p = private_data;
309 	if (snd_BUG_ON(!p))
310 		return -EINVAL;
311 	emu = p->emu;
312 	if (snd_BUG_ON(!emu))
313 		return -EINVAL;
314 	if (ev->type != SNDRV_SEQ_EVENT_OSS)
315 		return snd_emux_event_input(ev, direct, private_data, atomic, hop);
316 
317 	data = ev->data.raw8.d;
318 	/* only SEQ_PRIVATE is accepted */
319 	if (data[0] != 0xfe)
320 		return 0;
321 	cmd = data[2] & _EMUX_OSS_MODE_VALUE_MASK;
322 	if (data[2] & _EMUX_OSS_MODE_FLAG)
323 		emuspec_control(emu, p, cmd, data, atomic, hop);
324 	else
325 		gusspec_control(emu, p, cmd, data, atomic, hop);
326 	return 0;
327 }
328 
329 
330 /*
331  * OSS/AWE driver specific h/w controls
332  */
333 static void
334 emuspec_control(struct snd_emux *emu, struct snd_emux_port *port, int cmd,
335 		unsigned char *event, int atomic, int hop)
336 {
337 	int voice;
338 	unsigned short p1;
339 	short p2;
340 	int i;
341 	struct snd_midi_channel *chan;
342 
343 	voice = event[3];
344 	if (voice < 0 || voice >= port->chset.max_channels)
345 		chan = NULL;
346 	else
347 		chan = &port->chset.channels[voice];
348 
349 	p1 = *(unsigned short *) &event[4];
350 	p2 = *(short *) &event[6];
351 
352 	switch (cmd) {
353 #if 0 /* don't do this atomically */
354 	case _EMUX_OSS_REMOVE_LAST_SAMPLES:
355 		snd_soundfont_remove_unlocked(emu->sflist);
356 		break;
357 #endif
358 	case _EMUX_OSS_SEND_EFFECT:
359 		if (chan)
360 			snd_emux_send_effect_oss(port, chan, p1, p2);
361 		break;
362 
363 	case _EMUX_OSS_TERMINATE_ALL:
364 		snd_emux_terminate_all(emu);
365 		break;
366 
367 	case _EMUX_OSS_TERMINATE_CHANNEL:
368 		/*snd_emux_mute_channel(emu, chan);*/
369 		break;
370 	case _EMUX_OSS_RESET_CHANNEL:
371 		/*snd_emux_channel_init(chset, chan);*/
372 		break;
373 
374 	case _EMUX_OSS_RELEASE_ALL:
375 		fake_event(emu, port, voice, MIDI_CTL_ALL_NOTES_OFF, 0, atomic, hop);
376 		break;
377 	case _EMUX_OSS_NOTEOFF_ALL:
378 		fake_event(emu, port, voice, MIDI_CTL_ALL_SOUNDS_OFF, 0, atomic, hop);
379 		break;
380 
381 	case _EMUX_OSS_INITIAL_VOLUME:
382 		if (p2) {
383 			port->volume_atten = (short)p1;
384 			snd_emux_update_port(port, SNDRV_EMUX_UPDATE_VOLUME);
385 		}
386 		break;
387 
388 	case _EMUX_OSS_CHN_PRESSURE:
389 		if (chan) {
390 			chan->midi_pressure = p1;
391 			snd_emux_update_channel(port, chan, SNDRV_EMUX_UPDATE_FMMOD|SNDRV_EMUX_UPDATE_FM2FRQ2);
392 		}
393 		break;
394 
395 	case _EMUX_OSS_CHANNEL_MODE:
396 		reset_port_mode(port, p1);
397 		snd_emux_reset_port(port);
398 		break;
399 
400 	case _EMUX_OSS_DRUM_CHANNELS:
401 		port->drum_flags = *(unsigned int*)&event[4];
402 		for (i = 0; i < port->chset.max_channels; i++) {
403 			chan = &port->chset.channels[i];
404 			chan->drum_channel = ((port->drum_flags >> i) & 1) ? 1 : 0;
405 		}
406 		break;
407 
408 	case _EMUX_OSS_MISC_MODE:
409 		if (p1 < EMUX_MD_END)
410 			port->ctrls[p1] = p2;
411 		break;
412 	case _EMUX_OSS_DEBUG_MODE:
413 		break;
414 
415 	default:
416 		if (emu->ops.oss_ioctl)
417 			emu->ops.oss_ioctl(emu, cmd, p1, p2);
418 		break;
419 	}
420 }
421 
422 /*
423  * GUS specific h/w controls
424  */
425 
426 #include <linux/ultrasound.h>
427 
428 static void
429 gusspec_control(struct snd_emux *emu, struct snd_emux_port *port, int cmd,
430 		unsigned char *event, int atomic, int hop)
431 {
432 	int voice;
433 	unsigned short p1;
434 	short p2;
435 	int plong;
436 	struct snd_midi_channel *chan;
437 
438 	if (port->port_mode != SNDRV_EMUX_PORT_MODE_OSS_SYNTH)
439 		return;
440 	if (cmd == _GUS_NUMVOICES)
441 		return;
442 	voice = event[3];
443 	if (voice < 0 || voice >= port->chset.max_channels)
444 		return;
445 
446 	chan = &port->chset.channels[voice];
447 
448 	p1 = *(unsigned short *) &event[4];
449 	p2 = *(short *) &event[6];
450 	plong = *(int*) &event[4];
451 
452 	switch (cmd) {
453 	case _GUS_VOICESAMPLE:
454 		chan->midi_program = p1;
455 		return;
456 
457 	case _GUS_VOICEBALA:
458 		/* 0 to 15 --> 0 to 127 */
459 		chan->control[MIDI_CTL_MSB_PAN] = (int)p1 << 3;
460 		snd_emux_update_channel(port, chan, SNDRV_EMUX_UPDATE_PAN);
461 		return;
462 
463 	case _GUS_VOICEVOL:
464 	case _GUS_VOICEVOL2:
465 		/* not supported yet */
466 		return;
467 
468 	case _GUS_RAMPRANGE:
469 	case _GUS_RAMPRATE:
470 	case _GUS_RAMPMODE:
471 	case _GUS_RAMPON:
472 	case _GUS_RAMPOFF:
473 		/* volume ramping not supported */
474 		return;
475 
476 	case _GUS_VOLUME_SCALE:
477 		return;
478 
479 	case _GUS_VOICE_POS:
480 #ifdef SNDRV_EMUX_USE_RAW_EFFECT
481 		snd_emux_send_effect(port, chan, EMUX_FX_SAMPLE_START,
482 				     (short)(plong & 0x7fff),
483 				     EMUX_FX_FLAG_SET);
484 		snd_emux_send_effect(port, chan, EMUX_FX_COARSE_SAMPLE_START,
485 				     (plong >> 15) & 0xffff,
486 				     EMUX_FX_FLAG_SET);
487 #endif
488 		return;
489 	}
490 }
491 
492 
493 /*
494  * send an event to midi emulation
495  */
496 static void
497 fake_event(struct snd_emux *emu, struct snd_emux_port *port, int ch, int param, int val, int atomic, int hop)
498 {
499 	struct snd_seq_event ev;
500 	memset(&ev, 0, sizeof(ev));
501 	ev.type = SNDRV_SEQ_EVENT_CONTROLLER;
502 	ev.data.control.channel = ch;
503 	ev.data.control.param = param;
504 	ev.data.control.value = val;
505 	snd_emux_event_input(&ev, 0, port, atomic, hop);
506 }
507 
508 #endif /* CONFIG_SND_SEQUENCER_OSS */
509