2 * Interface for OSS sequencer emulation
4 * Copyright (C) 1999 Takashi Iwai <tiwai@suse.de>
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.
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.
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
21 * 19990227 Steve Ratcliffe Made separate file and merged in latest
25 #include <sound/driver.h>
27 #ifdef CONFIG_SND_SEQUENCER_OSS
29 #include <asm/uaccess.h>
30 #include <sound/core.h>
31 #include "emux_voice.h"
32 #include <sound/asoundef.h>
34 static int snd_emux_open_seq_oss(snd_seq_oss_arg_t
*arg
, void *closure
);
35 static int snd_emux_close_seq_oss(snd_seq_oss_arg_t
*arg
);
36 static int snd_emux_ioctl_seq_oss(snd_seq_oss_arg_t
*arg
, unsigned int cmd
, unsigned long ioarg
);
37 static int snd_emux_load_patch_seq_oss(snd_seq_oss_arg_t
*arg
, int format
, const char __user
*buf
, int offs
, int count
);
38 static int snd_emux_reset_seq_oss(snd_seq_oss_arg_t
*arg
);
39 static int snd_emux_event_oss_input(snd_seq_event_t
*ev
, int direct
, void *private, int atomic
, int hop
);
40 static void reset_port_mode(snd_emux_port_t
*port
, int midi_mode
);
41 static void emuspec_control(snd_emux_t
*emu
, snd_emux_port_t
*port
, int cmd
, unsigned char *event
, int atomic
, int hop
);
42 static void gusspec_control(snd_emux_t
*emu
, snd_emux_port_t
*port
, int cmd
, unsigned char *event
, int atomic
, int hop
);
43 static void fake_event(snd_emux_t
*emu
, snd_emux_port_t
*port
, int ch
, int param
, int val
, int atomic
, int hop
);
46 static snd_seq_oss_callback_t oss_callback
= {
48 .open
= snd_emux_open_seq_oss
,
49 .close
= snd_emux_close_seq_oss
,
50 .ioctl
= snd_emux_ioctl_seq_oss
,
51 .load_patch
= snd_emux_load_patch_seq_oss
,
52 .reset
= snd_emux_reset_seq_oss
,
61 snd_emux_init_seq_oss(snd_emux_t
*emu
)
63 snd_seq_oss_reg_t
*arg
;
64 snd_seq_device_t
*dev
;
66 if (snd_seq_device_new(emu
->card
, 0, SNDRV_SEQ_DEV_ID_OSS
,
67 sizeof(snd_seq_oss_reg_t
), &dev
) < 0)
71 strcpy(dev
->name
, emu
->name
);
72 arg
= SNDRV_SEQ_DEVICE_ARGPTR(dev
);
73 arg
->type
= SYNTH_TYPE_SAMPLE
;
74 arg
->subtype
= SAMPLE_TYPE_AWE32
;
75 arg
->nvoices
= emu
->max_voices
;
76 arg
->oper
= oss_callback
;
77 arg
->private_data
= emu
;
79 /* register to OSS synth table */
80 snd_device_register(emu
->card
, dev
);
88 snd_emux_detach_seq_oss(snd_emux_t
*emu
)
91 snd_device_free(emu
->card
, emu
->oss_synth
);
92 emu
->oss_synth
= NULL
;
97 /* use port number as a unique soundfont client number */
98 #define SF_CLIENT_NO(p) ((p) + 0x1000)
101 * open port for OSS sequencer
104 snd_emux_open_seq_oss(snd_seq_oss_arg_t
*arg
, void *closure
)
108 snd_seq_port_callback_t callback
;
112 snd_assert(arg
!= NULL
&& emu
!= NULL
, return -ENXIO
);
114 down(&emu
->register_mutex
);
116 if (!snd_emux_inc_count(emu
)) {
117 up(&emu
->register_mutex
);
121 memset(&callback
, 0, sizeof(callback
));
122 callback
.owner
= THIS_MODULE
;
123 callback
.event_input
= snd_emux_event_oss_input
;
125 sprintf(tmpname
, "%s OSS Port", emu
->name
);
126 p
= snd_emux_create_port(emu
, tmpname
, 32,
129 snd_printk("can't create port\n");
130 snd_emux_dec_count(emu
);
131 up(&emu
->register_mutex
);
135 /* fill the argument data */
136 arg
->private_data
= p
;
137 arg
->addr
.client
= p
->chset
.client
;
138 arg
->addr
.port
= p
->chset
.port
;
141 reset_port_mode(p
, arg
->seq_mode
);
143 snd_emux_reset_port(p
);
145 up(&emu
->register_mutex
);
150 #define DEFAULT_DRUM_FLAGS ((1<<9) | (1<<25))
156 reset_port_mode(snd_emux_port_t
*port
, int 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
;
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
;
176 snd_emux_close_seq_oss(snd_seq_oss_arg_t
*arg
)
181 snd_assert(arg
!= NULL
, return -ENXIO
);
182 p
= arg
->private_data
;
183 snd_assert(p
!= NULL
, return -ENXIO
);
186 snd_assert(emu
!= NULL
, return -ENXIO
);
188 down(&emu
->register_mutex
);
189 snd_emux_sounds_off_all(p
);
190 snd_soundfont_close_check(emu
->sflist
, SF_CLIENT_NO(p
->chset
.port
));
191 snd_seq_event_port_detach(p
->chset
.client
, p
->chset
.port
);
192 snd_emux_dec_count(emu
);
194 up(&emu
->register_mutex
);
203 snd_emux_load_patch_seq_oss(snd_seq_oss_arg_t
*arg
, int format
,
204 const char __user
*buf
, int offs
, int count
)
210 snd_assert(arg
!= NULL
, return -ENXIO
);
211 p
= arg
->private_data
;
212 snd_assert(p
!= NULL
, return -ENXIO
);
215 snd_assert(emu
!= NULL
, return -ENXIO
);
217 if (format
== GUS_PATCH
)
218 rc
= snd_soundfont_load_guspatch(emu
->sflist
, buf
, count
,
219 SF_CLIENT_NO(p
->chset
.port
));
220 else if (format
== SNDRV_OSS_SOUNDFONT_PATCH
) {
221 soundfont_patch_info_t patch
;
222 if (count
< (int)sizeof(patch
))
224 if (copy_from_user(&patch
, buf
, sizeof(patch
)))
226 if (patch
.type
>= SNDRV_SFNT_LOAD_INFO
&&
227 patch
.type
<= SNDRV_SFNT_PROBE_DATA
)
228 rc
= snd_soundfont_load(emu
->sflist
, buf
, count
, SF_CLIENT_NO(p
->chset
.port
));
230 if (emu
->ops
.load_fx
)
231 rc
= emu
->ops
.load_fx(emu
, patch
.type
, patch
.optarg
, buf
, count
);
245 snd_emux_ioctl_seq_oss(snd_seq_oss_arg_t
*arg
, unsigned int cmd
, unsigned long ioarg
)
250 snd_assert(arg
!= NULL
, return -ENXIO
);
251 p
= arg
->private_data
;
252 snd_assert(p
!= NULL
, return -ENXIO
);
255 snd_assert(emu
!= NULL
, return -ENXIO
);
258 case SNDCTL_SEQ_RESETSAMPLES
:
259 snd_soundfont_remove_samples(emu
->sflist
);
262 case SNDCTL_SYNTH_MEMAVL
:
264 return snd_util_mem_avail(emu
->memhdr
);
276 snd_emux_reset_seq_oss(snd_seq_oss_arg_t
*arg
)
280 snd_assert(arg
!= NULL
, return -ENXIO
);
281 p
= arg
->private_data
;
282 snd_assert(p
!= NULL
, return -ENXIO
);
283 snd_emux_reset_port(p
);
289 * receive raw events: only SEQ_PRIVATE is accepted.
292 snd_emux_event_oss_input(snd_seq_event_t
*ev
, int direct
, void *private_data
,
297 unsigned char cmd
, *data
;
300 snd_assert(p
!= NULL
, return -EINVAL
);
302 snd_assert(emu
!= NULL
, return -EINVAL
);
303 if (ev
->type
!= SNDRV_SEQ_EVENT_OSS
)
304 return snd_emux_event_input(ev
, direct
, private_data
, atomic
, hop
);
306 data
= ev
->data
.raw8
.d
;
307 /* only SEQ_PRIVATE is accepted */
310 cmd
= data
[2] & _EMUX_OSS_MODE_VALUE_MASK
;
311 if (data
[2] & _EMUX_OSS_MODE_FLAG
)
312 emuspec_control(emu
, p
, cmd
, data
, atomic
, hop
);
314 gusspec_control(emu
, p
, cmd
, data
, atomic
, hop
);
320 * OSS/AWE driver specific h/w controls
323 emuspec_control(snd_emux_t
*emu
, snd_emux_port_t
*port
, int cmd
,
324 unsigned char *event
, int atomic
, int hop
)
330 snd_midi_channel_t
*chan
;
333 if (voice
< 0 || voice
>= port
->chset
.max_channels
)
336 chan
= &port
->chset
.channels
[voice
];
338 p1
= *(unsigned short *) &event
[4];
339 p2
= *(short *) &event
[6];
342 #if 0 /* don't do this atomically */
343 case _EMUX_OSS_REMOVE_LAST_SAMPLES
:
344 snd_soundfont_remove_unlocked(emu
->sflist
);
347 case _EMUX_OSS_SEND_EFFECT
:
349 snd_emux_send_effect_oss(port
, chan
, p1
, p2
);
352 case _EMUX_OSS_TERMINATE_ALL
:
353 snd_emux_terminate_all(emu
);
356 case _EMUX_OSS_TERMINATE_CHANNEL
:
357 /*snd_emux_mute_channel(emu, chan);*/
359 case _EMUX_OSS_RESET_CHANNEL
:
360 /*snd_emux_channel_init(chset, chan);*/
363 case _EMUX_OSS_RELEASE_ALL
:
364 fake_event(emu
, port
, voice
, MIDI_CTL_ALL_NOTES_OFF
, 0, atomic
, hop
);
366 case _EMUX_OSS_NOTEOFF_ALL
:
367 fake_event(emu
, port
, voice
, MIDI_CTL_ALL_SOUNDS_OFF
, 0, atomic
, hop
);
370 case _EMUX_OSS_INITIAL_VOLUME
:
372 port
->volume_atten
= (short)p1
;
373 snd_emux_update_port(port
, SNDRV_EMUX_UPDATE_VOLUME
);
377 case _EMUX_OSS_CHN_PRESSURE
:
379 chan
->midi_pressure
= p1
;
380 snd_emux_update_channel(port
, chan
, SNDRV_EMUX_UPDATE_FMMOD
|SNDRV_EMUX_UPDATE_FM2FRQ2
);
384 case _EMUX_OSS_CHANNEL_MODE
:
385 reset_port_mode(port
, p1
);
386 snd_emux_reset_port(port
);
389 case _EMUX_OSS_DRUM_CHANNELS
:
390 port
->drum_flags
= *(unsigned int*)&event
[4];
391 for (i
= 0; i
< port
->chset
.max_channels
; i
++) {
392 chan
= &port
->chset
.channels
[i
];
393 chan
->drum_channel
= ((port
->drum_flags
>> i
) & 1) ? 1 : 0;
397 case _EMUX_OSS_MISC_MODE
:
398 if (p1
< EMUX_MD_END
)
399 port
->ctrls
[p1
] = p2
;
401 case _EMUX_OSS_DEBUG_MODE
:
405 if (emu
->ops
.oss_ioctl
)
406 emu
->ops
.oss_ioctl(emu
, cmd
, p1
, p2
);
412 * GUS specific h/w controls
415 #include <linux/ultrasound.h>
418 gusspec_control(snd_emux_t
*emu
, snd_emux_port_t
*port
, int cmd
,
419 unsigned char *event
, int atomic
, int hop
)
425 snd_midi_channel_t
*chan
;
427 if (port
->port_mode
!= SNDRV_EMUX_PORT_MODE_OSS_SYNTH
)
429 if (cmd
== _GUS_NUMVOICES
)
432 if (voice
< 0 || voice
>= port
->chset
.max_channels
)
435 chan
= &port
->chset
.channels
[voice
];
437 p1
= *(unsigned short *) &event
[4];
438 p2
= *(short *) &event
[6];
439 plong
= *(int*) &event
[4];
442 case _GUS_VOICESAMPLE
:
443 chan
->midi_program
= p1
;
447 /* 0 to 15 --> 0 to 127 */
448 chan
->control
[MIDI_CTL_MSB_PAN
] = (int)p1
<< 3;
449 snd_emux_update_channel(port
, chan
, SNDRV_EMUX_UPDATE_PAN
);
454 /* not supported yet */
462 /* volume ramping not supported */
465 case _GUS_VOLUME_SCALE
:
469 #ifdef SNDRV_EMUX_USE_RAW_EFFECT
470 snd_emux_send_effect(port
, chan
, EMUX_FX_SAMPLE_START
,
471 (short)(plong
& 0x7fff),
473 snd_emux_send_effect(port
, chan
, EMUX_FX_COARSE_SAMPLE_START
,
474 (plong
>> 15) & 0xffff,
483 * send an event to midi emulation
486 fake_event(snd_emux_t
*emu
, snd_emux_port_t
*port
, int ch
, int param
, int val
, int atomic
, int hop
)
489 memset(&ev
, 0, sizeof(ev
));
490 ev
.type
= SNDRV_SEQ_EVENT_CONTROLLER
;
491 ev
.data
.control
.channel
= ch
;
492 ev
.data
.control
.param
= param
;
493 ev
.data
.control
.value
= val
;
494 snd_emux_event_input(&ev
, 0, port
, atomic
, hop
);
497 #endif /* CONFIG_SND_SEQUENCER_OSS */