1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Interface for OSS sequencer emulation
5 * Copyright (C) 1999 Takashi Iwai <tiwai@suse.de>
8 * 19990227 Steve Ratcliffe Made separate file and merged in latest
13 #include <linux/export.h>
14 #include <linux/uaccess.h>
15 #include <sound/core.h>
16 #include "emux_voice.h"
17 #include <sound/asoundef.h>
19 static int snd_emux_open_seq_oss(struct snd_seq_oss_arg
*arg
, void *closure
);
20 static int snd_emux_close_seq_oss(struct snd_seq_oss_arg
*arg
);
21 static int snd_emux_ioctl_seq_oss(struct snd_seq_oss_arg
*arg
, unsigned int cmd
,
23 static int snd_emux_load_patch_seq_oss(struct snd_seq_oss_arg
*arg
, int format
,
24 const char __user
*buf
, int offs
, int count
);
25 static int snd_emux_reset_seq_oss(struct snd_seq_oss_arg
*arg
);
26 static int snd_emux_event_oss_input(struct snd_seq_event
*ev
, int direct
,
27 void *private, int atomic
, int hop
);
28 static void reset_port_mode(struct snd_emux_port
*port
, int midi_mode
);
29 static void emuspec_control(struct snd_emux
*emu
, struct snd_emux_port
*port
,
30 int cmd
, unsigned char *event
, int atomic
, int hop
);
31 static void gusspec_control(struct snd_emux
*emu
, struct snd_emux_port
*port
,
32 int cmd
, unsigned char *event
, int atomic
, int hop
);
33 static void fake_event(struct snd_emux
*emu
, struct snd_emux_port
*port
,
34 int ch
, int param
, int val
, int atomic
, int hop
);
37 static const struct snd_seq_oss_callback oss_callback
= {
39 .open
= snd_emux_open_seq_oss
,
40 .close
= snd_emux_close_seq_oss
,
41 .ioctl
= snd_emux_ioctl_seq_oss
,
42 .load_patch
= snd_emux_load_patch_seq_oss
,
43 .reset
= snd_emux_reset_seq_oss
,
52 snd_emux_init_seq_oss(struct snd_emux
*emu
)
54 struct snd_seq_oss_reg
*arg
;
55 struct snd_seq_device
*dev
;
57 /* using device#1 here for avoiding conflicts with OPL3 */
58 if (snd_seq_device_new(emu
->card
, 1, SNDRV_SEQ_DEV_ID_OSS
,
59 sizeof(struct snd_seq_oss_reg
), &dev
) < 0)
63 strcpy(dev
->name
, emu
->name
);
64 arg
= SNDRV_SEQ_DEVICE_ARGPTR(dev
);
65 arg
->type
= SYNTH_TYPE_SAMPLE
;
66 arg
->subtype
= SAMPLE_TYPE_AWE32
;
67 arg
->nvoices
= emu
->max_voices
;
68 arg
->oper
= oss_callback
;
69 arg
->private_data
= emu
;
71 /* register to OSS synth table */
72 snd_device_register(emu
->card
, dev
);
80 snd_emux_detach_seq_oss(struct snd_emux
*emu
)
83 snd_device_free(emu
->card
, emu
->oss_synth
);
84 emu
->oss_synth
= NULL
;
89 /* use port number as a unique soundfont client number */
90 #define SF_CLIENT_NO(p) ((p) + 0x1000)
93 * open port for OSS sequencer
96 snd_emux_open_seq_oss(struct snd_seq_oss_arg
*arg
, void *closure
)
99 struct snd_emux_port
*p
;
100 struct snd_seq_port_callback callback
;
104 if (snd_BUG_ON(!arg
|| !emu
))
107 if (!snd_emux_inc_count(emu
))
110 memset(&callback
, 0, sizeof(callback
));
111 callback
.owner
= THIS_MODULE
;
112 callback
.event_input
= snd_emux_event_oss_input
;
114 sprintf(tmpname
, "%s OSS Port", emu
->name
);
115 p
= snd_emux_create_port(emu
, tmpname
, 32,
118 snd_printk(KERN_ERR
"can't create port\n");
119 snd_emux_dec_count(emu
);
123 /* fill the argument data */
124 arg
->private_data
= p
;
125 arg
->addr
.client
= p
->chset
.client
;
126 arg
->addr
.port
= p
->chset
.port
;
129 reset_port_mode(p
, arg
->seq_mode
);
131 snd_emux_reset_port(p
);
136 #define DEFAULT_DRUM_FLAGS ((1<<9) | (1<<25))
142 reset_port_mode(struct snd_emux_port
*port
, int midi_mode
)
145 port
->port_mode
= SNDRV_EMUX_PORT_MODE_OSS_MIDI
;
146 port
->drum_flags
= DEFAULT_DRUM_FLAGS
;
147 port
->volume_atten
= 0;
148 port
->oss_arg
->event_passing
= SNDRV_SEQ_OSS_PROCESS_KEYPRESS
;
150 port
->port_mode
= SNDRV_EMUX_PORT_MODE_OSS_SYNTH
;
151 port
->drum_flags
= 0;
152 port
->volume_atten
= 32;
153 port
->oss_arg
->event_passing
= SNDRV_SEQ_OSS_PROCESS_EVENTS
;
162 snd_emux_close_seq_oss(struct snd_seq_oss_arg
*arg
)
164 struct snd_emux
*emu
;
165 struct snd_emux_port
*p
;
167 if (snd_BUG_ON(!arg
))
169 p
= arg
->private_data
;
174 if (snd_BUG_ON(!emu
))
177 snd_emux_sounds_off_all(p
);
178 snd_soundfont_close_check(emu
->sflist
, SF_CLIENT_NO(p
->chset
.port
));
179 snd_seq_event_port_detach(p
->chset
.client
, p
->chset
.port
);
180 snd_emux_dec_count(emu
);
190 snd_emux_load_patch_seq_oss(struct snd_seq_oss_arg
*arg
, int format
,
191 const char __user
*buf
, int offs
, int count
)
193 struct snd_emux
*emu
;
194 struct snd_emux_port
*p
;
197 if (snd_BUG_ON(!arg
))
199 p
= arg
->private_data
;
204 if (snd_BUG_ON(!emu
))
207 if (format
== GUS_PATCH
)
208 rc
= snd_soundfont_load_guspatch(emu
->sflist
, buf
, count
,
209 SF_CLIENT_NO(p
->chset
.port
));
210 else if (format
== SNDRV_OSS_SOUNDFONT_PATCH
) {
211 struct soundfont_patch_info patch
;
212 if (count
< (int)sizeof(patch
))
214 if (copy_from_user(&patch
, buf
, sizeof(patch
)))
216 if (patch
.type
>= SNDRV_SFNT_LOAD_INFO
&&
217 patch
.type
<= SNDRV_SFNT_PROBE_DATA
)
218 rc
= snd_soundfont_load(emu
->sflist
, buf
, count
, SF_CLIENT_NO(p
->chset
.port
));
220 if (emu
->ops
.load_fx
)
221 rc
= emu
->ops
.load_fx(emu
, patch
.type
, patch
.optarg
, buf
, count
);
235 snd_emux_ioctl_seq_oss(struct snd_seq_oss_arg
*arg
, unsigned int cmd
, unsigned long ioarg
)
237 struct snd_emux_port
*p
;
238 struct snd_emux
*emu
;
240 if (snd_BUG_ON(!arg
))
242 p
= arg
->private_data
;
247 if (snd_BUG_ON(!emu
))
251 case SNDCTL_SEQ_RESETSAMPLES
:
252 snd_soundfont_remove_samples(emu
->sflist
);
255 case SNDCTL_SYNTH_MEMAVL
:
257 return snd_util_mem_avail(emu
->memhdr
);
269 snd_emux_reset_seq_oss(struct snd_seq_oss_arg
*arg
)
271 struct snd_emux_port
*p
;
273 if (snd_BUG_ON(!arg
))
275 p
= arg
->private_data
;
278 snd_emux_reset_port(p
);
284 * receive raw events: only SEQ_PRIVATE is accepted.
287 snd_emux_event_oss_input(struct snd_seq_event
*ev
, int direct
, void *private_data
,
290 struct snd_emux
*emu
;
291 struct snd_emux_port
*p
;
292 unsigned char cmd
, *data
;
298 if (snd_BUG_ON(!emu
))
300 if (ev
->type
!= SNDRV_SEQ_EVENT_OSS
)
301 return snd_emux_event_input(ev
, direct
, private_data
, atomic
, hop
);
303 data
= ev
->data
.raw8
.d
;
304 /* only SEQ_PRIVATE is accepted */
307 cmd
= data
[2] & _EMUX_OSS_MODE_VALUE_MASK
;
308 if (data
[2] & _EMUX_OSS_MODE_FLAG
)
309 emuspec_control(emu
, p
, cmd
, data
, atomic
, hop
);
311 gusspec_control(emu
, p
, cmd
, data
, atomic
, hop
);
317 * OSS/AWE driver specific h/w controls
320 emuspec_control(struct snd_emux
*emu
, struct snd_emux_port
*port
, int cmd
,
321 unsigned char *event
, int atomic
, int hop
)
327 struct snd_midi_channel
*chan
;
330 if (voice
< 0 || voice
>= port
->chset
.max_channels
)
333 chan
= &port
->chset
.channels
[voice
];
335 p1
= *(unsigned short *) &event
[4];
336 p2
= *(short *) &event
[6];
339 #if 0 /* don't do this atomically */
340 case _EMUX_OSS_REMOVE_LAST_SAMPLES
:
341 snd_soundfont_remove_unlocked(emu
->sflist
);
344 case _EMUX_OSS_SEND_EFFECT
:
346 snd_emux_send_effect_oss(port
, chan
, p1
, p2
);
349 case _EMUX_OSS_TERMINATE_ALL
:
350 snd_emux_terminate_all(emu
);
353 case _EMUX_OSS_TERMINATE_CHANNEL
:
354 /*snd_emux_mute_channel(emu, chan);*/
356 case _EMUX_OSS_RESET_CHANNEL
:
357 /*snd_emux_channel_init(chset, chan);*/
360 case _EMUX_OSS_RELEASE_ALL
:
361 fake_event(emu
, port
, voice
, MIDI_CTL_ALL_NOTES_OFF
, 0, atomic
, hop
);
363 case _EMUX_OSS_NOTEOFF_ALL
:
364 fake_event(emu
, port
, voice
, MIDI_CTL_ALL_SOUNDS_OFF
, 0, atomic
, hop
);
367 case _EMUX_OSS_INITIAL_VOLUME
:
369 port
->volume_atten
= (short)p1
;
370 snd_emux_update_port(port
, SNDRV_EMUX_UPDATE_VOLUME
);
374 case _EMUX_OSS_CHN_PRESSURE
:
376 chan
->midi_pressure
= p1
;
377 snd_emux_update_channel(port
, chan
, SNDRV_EMUX_UPDATE_FMMOD
|SNDRV_EMUX_UPDATE_FM2FRQ2
);
381 case _EMUX_OSS_CHANNEL_MODE
:
382 reset_port_mode(port
, p1
);
383 snd_emux_reset_port(port
);
386 case _EMUX_OSS_DRUM_CHANNELS
:
387 port
->drum_flags
= *(unsigned int*)&event
[4];
388 for (i
= 0; i
< port
->chset
.max_channels
; i
++) {
389 chan
= &port
->chset
.channels
[i
];
390 chan
->drum_channel
= ((port
->drum_flags
>> i
) & 1) ? 1 : 0;
394 case _EMUX_OSS_MISC_MODE
:
395 if (p1
< EMUX_MD_END
)
396 port
->ctrls
[p1
] = p2
;
398 case _EMUX_OSS_DEBUG_MODE
:
402 if (emu
->ops
.oss_ioctl
)
403 emu
->ops
.oss_ioctl(emu
, cmd
, p1
, p2
);
409 * GUS specific h/w controls
412 #include <linux/ultrasound.h>
415 gusspec_control(struct snd_emux
*emu
, struct snd_emux_port
*port
, int cmd
,
416 unsigned char *event
, int atomic
, int hop
)
421 struct snd_midi_channel
*chan
;
423 if (port
->port_mode
!= SNDRV_EMUX_PORT_MODE_OSS_SYNTH
)
425 if (cmd
== _GUS_NUMVOICES
)
428 if (voice
< 0 || voice
>= port
->chset
.max_channels
)
431 chan
= &port
->chset
.channels
[voice
];
433 p1
= *(unsigned short *) &event
[4];
434 plong
= *(int*) &event
[4];
437 case _GUS_VOICESAMPLE
:
438 chan
->midi_program
= p1
;
442 /* 0 to 15 --> 0 to 127 */
443 chan
->control
[MIDI_CTL_MSB_PAN
] = (int)p1
<< 3;
444 snd_emux_update_channel(port
, chan
, SNDRV_EMUX_UPDATE_PAN
);
449 /* not supported yet */
457 /* volume ramping not supported */
460 case _GUS_VOLUME_SCALE
:
464 #ifdef SNDRV_EMUX_USE_RAW_EFFECT
465 snd_emux_send_effect(port
, chan
, EMUX_FX_SAMPLE_START
,
466 (short)(plong
& 0x7fff),
468 snd_emux_send_effect(port
, chan
, EMUX_FX_COARSE_SAMPLE_START
,
469 (plong
>> 15) & 0xffff,
478 * send an event to midi emulation
481 fake_event(struct snd_emux
*emu
, struct snd_emux_port
*port
, int ch
, int param
, int val
, int atomic
, int hop
)
483 struct snd_seq_event ev
;
484 memset(&ev
, 0, sizeof(ev
));
485 ev
.type
= SNDRV_SEQ_EVENT_CONTROLLER
;
486 ev
.data
.control
.channel
= ch
;
487 ev
.data
.control
.param
= param
;
488 ev
.data
.control
.value
= val
;
489 snd_emux_event_input(&ev
, 0, port
, atomic
, hop
);