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