Release 4.11 sound/synth/emux/emux_oss.c
/*
* Interface for OSS sequencer emulation
*
* Copyright (C) 1999 Takashi Iwai <tiwai@suse.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Changes
* 19990227 Steve Ratcliffe Made separate file and merged in latest
* midi emulation.
*/
#ifdef CONFIG_SND_SEQUENCER_OSS
#include <linux/export.h>
#include <linux/uaccess.h>
#include <sound/core.h>
#include "emux_voice.h"
#include <sound/asoundef.h>
static int snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure);
static int snd_emux_close_seq_oss(struct snd_seq_oss_arg *arg);
static int snd_emux_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd,
unsigned long ioarg);
static int snd_emux_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format,
const char __user *buf, int offs, int count);
static int snd_emux_reset_seq_oss(struct snd_seq_oss_arg *arg);
static int snd_emux_event_oss_input(struct snd_seq_event *ev, int direct,
void *private, int atomic, int hop);
static void reset_port_mode(struct snd_emux_port *port, int midi_mode);
static void emuspec_control(struct snd_emux *emu, struct snd_emux_port *port,
int cmd, unsigned char *event, int atomic, int hop);
static void gusspec_control(struct snd_emux *emu, struct snd_emux_port *port,
int cmd, unsigned char *event, int atomic, int hop);
static void fake_event(struct snd_emux *emu, struct snd_emux_port *port,
int ch, int param, int val, int atomic, int hop);
/* operators */
static struct snd_seq_oss_callback oss_callback = {
.owner = THIS_MODULE,
.open = snd_emux_open_seq_oss,
.close = snd_emux_close_seq_oss,
.ioctl = snd_emux_ioctl_seq_oss,
.load_patch = snd_emux_load_patch_seq_oss,
.reset = snd_emux_reset_seq_oss,
};
/*
* register OSS synth
*/
void
snd_emux_init_seq_oss(struct snd_emux *emu)
{
struct snd_seq_oss_reg *arg;
struct snd_seq_device *dev;
/* using device#1 here for avoiding conflicts with OPL3 */
if (snd_seq_device_new(emu->card, 1, SNDRV_SEQ_DEV_ID_OSS,
sizeof(struct snd_seq_oss_reg), &dev) < 0)
return;
emu->oss_synth = dev;
strcpy(dev->name, emu->name);
arg = SNDRV_SEQ_DEVICE_ARGPTR(dev);
arg->type = SYNTH_TYPE_SAMPLE;
arg->subtype = SAMPLE_TYPE_AWE32;
arg->nvoices = emu->max_voices;
arg->oper = oss_callback;
arg->private_data = emu;
/* register to OSS synth table */
snd_device_register(emu->card, dev);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jaroslav Kysela | 102 | 91.07% | 1 | 33.33% |
Takashi Iwai | 10 | 8.93% | 2 | 66.67% |
Total | 112 | 100.00% | 3 | 100.00% |
/*
* unregister
*/
void
snd_emux_detach_seq_oss(struct snd_emux *emu)
{
if (emu->oss_synth) {
snd_device_free(emu->card, emu->oss_synth);
emu->oss_synth = NULL;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jaroslav Kysela | 33 | 94.29% | 1 | 50.00% |
Takashi Iwai | 2 | 5.71% | 1 | 50.00% |
Total | 35 | 100.00% | 2 | 100.00% |
/* use port number as a unique soundfont client number */
#define SF_CLIENT_NO(p) ((p) + 0x1000)
/*
* open port for OSS sequencer
*/
static int
snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure)
{
struct snd_emux *emu;
struct snd_emux_port *p;
struct snd_seq_port_callback callback;
char tmpname[64];
emu = closure;
if (snd_BUG_ON(!arg || !emu))
return -ENXIO;
if (!snd_emux_inc_count(emu))
return -EFAULT;
memset(&callback, 0, sizeof(callback));
callback.owner = THIS_MODULE;
callback.event_input = snd_emux_event_oss_input;
sprintf(tmpname, "%s OSS Port", emu->name);
p = snd_emux_create_port(emu, tmpname, 32,
1, &callback);
if (p == NULL) {
snd_printk(KERN_ERR "can't create port\n");
snd_emux_dec_count(emu);
return -ENOMEM;
}
/* fill the argument data */
arg->private_data = p;
arg->addr.client = p->chset.client;
arg->addr.port = p->chset.port;
p->oss_arg = arg;
reset_port_mode(p, arg->seq_mode);
snd_emux_reset_port(p);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jaroslav Kysela | 173 | 88.72% | 2 | 40.00% |
Takashi Iwai | 22 | 11.28% | 3 | 60.00% |
Total | 195 | 100.00% | 5 | 100.00% |
#define DEFAULT_DRUM_FLAGS ((1<<9) | (1<<25))
/*
* reset port mode
*/
static void
reset_port_mode(struct snd_emux_port *port, int midi_mode)
{
if (midi_mode) {
port->port_mode = SNDRV_EMUX_PORT_MODE_OSS_MIDI;
port->drum_flags = DEFAULT_DRUM_FLAGS;
port->volume_atten = 0;
port->oss_arg->event_passing = SNDRV_SEQ_OSS_PROCESS_KEYPRESS;
} else {
port->port_mode = SNDRV_EMUX_PORT_MODE_OSS_SYNTH;
port->drum_flags = 0;
port->volume_atten = 32;
port->oss_arg->event_passing = SNDRV_SEQ_OSS_PROCESS_EVENTS;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jaroslav Kysela | 73 | 97.33% | 1 | 50.00% |
Takashi Iwai | 2 | 2.67% | 1 | 50.00% |
Total | 75 | 100.00% | 2 | 100.00% |
/*
* close port
*/
static int
snd_emux_close_seq_oss(struct snd_seq_oss_arg *arg)
{
struct snd_emux *emu;
struct snd_emux_port *p;
if (snd_BUG_ON(!arg))
return -ENXIO;
p = arg->private_data;
if (snd_BUG_ON(!p))
return -ENXIO;
emu = p->emu;
if (snd_BUG_ON(!emu))
return -ENXIO;
snd_emux_sounds_off_all(p);
snd_soundfont_close_check(emu->sflist, SF_CLIENT_NO(p->chset.port));
snd_seq_event_port_detach(p->chset.client, p->chset.port);
snd_emux_dec_count(emu);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jaroslav Kysela | 77 | 68.14% | 2 | 50.00% |
Takashi Iwai | 36 | 31.86% | 2 | 50.00% |
Total | 113 | 100.00% | 4 | 100.00% |
/*
* load patch
*/
static int
snd_emux_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format,
const char __user *buf, int offs, int count)
{
struct snd_emux *emu;
struct snd_emux_port *p;
int rc;
if (snd_BUG_ON(!arg))
return -ENXIO;
p = arg->private_data;
if (snd_BUG_ON(!p))
return -ENXIO;
emu = p->emu;
if (snd_BUG_ON(!emu))
return -ENXIO;
if (format == GUS_PATCH)
rc = snd_soundfont_load_guspatch(emu->sflist, buf, count,
SF_CLIENT_NO(p->chset.port));
else if (format == SNDRV_OSS_SOUNDFONT_PATCH) {
struct soundfont_patch_info patch;
if (count < (int)sizeof(patch))
rc = -EINVAL;
if (copy_from_user(&patch, buf, sizeof(patch)))
rc = -EFAULT;
if (patch.type >= SNDRV_SFNT_LOAD_INFO &&
patch.type <= SNDRV_SFNT_PROBE_DATA)
rc = snd_soundfont_load(emu->sflist, buf, count, SF_CLIENT_NO(p->chset.port));
else {
if (emu->ops.load_fx)
rc = emu->ops.load_fx(emu, patch.type, patch.optarg, buf, count);
else
rc = -EINVAL;
}
} else
rc = 0;
return rc;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jaroslav Kysela | 210 | 84.34% | 3 | 50.00% |
Takashi Iwai | 38 | 15.26% | 2 | 33.33% |
Al Viro | 1 | 0.40% | 1 | 16.67% |
Total | 249 | 100.00% | 6 | 100.00% |
/*
* ioctl
*/
static int
snd_emux_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd, unsigned long ioarg)
{
struct snd_emux_port *p;
struct snd_emux *emu;
if (snd_BUG_ON(!arg))
return -ENXIO;
p = arg->private_data;
if (snd_BUG_ON(!p))
return -ENXIO;
emu = p->emu;
if (snd_BUG_ON(!emu))
return -ENXIO;
switch (cmd) {
case SNDCTL_SEQ_RESETSAMPLES:
snd_soundfont_remove_samples(emu->sflist);
return 0;
case SNDCTL_SYNTH_MEMAVL:
if (emu->memhdr)
return snd_util_mem_avail(emu->memhdr);
return 0;
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jaroslav Kysela | 83 | 69.75% | 2 | 50.00% |
Takashi Iwai | 36 | 30.25% | 2 | 50.00% |
Total | 119 | 100.00% | 4 | 100.00% |
/*
* reset device
*/
static int
snd_emux_reset_seq_oss(struct snd_seq_oss_arg *arg)
{
struct snd_emux_port *p;
if (snd_BUG_ON(!arg))
return -ENXIO;
p = arg->private_data;
if (snd_BUG_ON(!p))
return -ENXIO;
snd_emux_reset_port(p);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jaroslav Kysela | 30 | 55.56% | 2 | 50.00% |
Takashi Iwai | 24 | 44.44% | 2 | 50.00% |
Total | 54 | 100.00% | 4 | 100.00% |
/*
* receive raw events: only SEQ_PRIVATE is accepted.
*/
static int
snd_emux_event_oss_input(struct snd_seq_event *ev, int direct, void *private_data,
int atomic, int hop)
{
struct snd_emux *emu;
struct snd_emux_port *p;
unsigned char cmd, *data;
p = private_data;
if (snd_BUG_ON(!p))
return -EINVAL;
emu = p->emu;
if (snd_BUG_ON(!emu))
return -EINVAL;
if (ev->type != SNDRV_SEQ_EVENT_OSS)
return snd_emux_event_input(ev, direct, private_data, atomic, hop);
data = ev->data.raw8.d;
/* only SEQ_PRIVATE is accepted */
if (data[0] != 0xfe)
return 0;
cmd = data[2] & _EMUX_OSS_MODE_VALUE_MASK;
if (data[2] & _EMUX_OSS_MODE_FLAG)
emuspec_control(emu, p, cmd, data, atomic, hop);
else
gusspec_control(emu, p, cmd, data, atomic, hop);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jaroslav Kysela | 146 | 84.88% | 2 | 50.00% |
Takashi Iwai | 26 | 15.12% | 2 | 50.00% |
Total | 172 | 100.00% | 4 | 100.00% |
/*
* OSS/AWE driver specific h/w controls
*/
static void
emuspec_control(struct snd_emux *emu, struct snd_emux_port *port, int cmd,
unsigned char *event, int atomic, int hop)
{
int voice;
unsigned short p1;
short p2;
int i;
struct snd_midi_channel *chan;
voice = event[3];
if (voice < 0 || voice >= port->chset.max_channels)
chan = NULL;
else
chan = &port->chset.channels[voice];
p1 = *(unsigned short *) &event[4];
p2 = *(short *) &event[6];
switch (cmd) {
#if 0 /* don't do this atomically */
case _EMUX_OSS_REMOVE_LAST_SAMPLES:
snd_soundfont_remove_unlocked(emu->sflist);
break;
#endif
case _EMUX_OSS_SEND_EFFECT:
if (chan)
snd_emux_send_effect_oss(port, chan, p1, p2);
break;
case _EMUX_OSS_TERMINATE_ALL:
snd_emux_terminate_all(emu);
break;
case _EMUX_OSS_TERMINATE_CHANNEL:
/*snd_emux_mute_channel(emu, chan);*/
break;
case _EMUX_OSS_RESET_CHANNEL:
/*snd_emux_channel_init(chset, chan);*/
break;
case _EMUX_OSS_RELEASE_ALL:
fake_event(emu, port, voice, MIDI_CTL_ALL_NOTES_OFF, 0, atomic, hop);
break;
case _EMUX_OSS_NOTEOFF_ALL:
fake_event(emu, port, voice, MIDI_CTL_ALL_SOUNDS_OFF, 0, atomic, hop);
break;
case _EMUX_OSS_INITIAL_VOLUME:
if (p2) {
port->volume_atten = (short)p1;
snd_emux_update_port(port, SNDRV_EMUX_UPDATE_VOLUME);
}
break;
case _EMUX_OSS_CHN_PRESSURE:
if (chan) {
chan->midi_pressure = p1;
snd_emux_update_channel(port, chan, SNDRV_EMUX_UPDATE_FMMOD|SNDRV_EMUX_UPDATE_FM2FRQ2);
}
break;
case _EMUX_OSS_CHANNEL_MODE:
reset_port_mode(port, p1);
snd_emux_reset_port(port);
break;
case _EMUX_OSS_DRUM_CHANNELS:
port->drum_flags = *(unsigned int*)&event[4];
for (i = 0; i < port->chset.max_channels; i++) {
chan = &port->chset.channels[i];
chan->drum_channel = ((port->drum_flags >> i) & 1) ? 1 : 0;
}
break;
case _EMUX_OSS_MISC_MODE:
if (p1 < EMUX_MD_END)
port->ctrls[p1] = p2;
break;
case _EMUX_OSS_DEBUG_MODE:
break;
default:
if (emu->ops.oss_ioctl)
emu->ops.oss_ioctl(emu, cmd, p1, p2);
break;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jaroslav Kysela | 388 | 98.48% | 2 | 66.67% |
Takashi Iwai | 6 | 1.52% | 1 | 33.33% |
Total | 394 | 100.00% | 3 | 100.00% |
/*
* GUS specific h/w controls
*/
#include <linux/ultrasound.h>
static void
gusspec_control(struct snd_emux *emu, struct snd_emux_port *port, int cmd,
unsigned char *event, int atomic, int hop)
{
int voice;
unsigned short p1;
short p2;
int plong;
struct snd_midi_channel *chan;
if (port->port_mode != SNDRV_EMUX_PORT_MODE_OSS_SYNTH)
return;
if (cmd == _GUS_NUMVOICES)
return;
voice = event[3];
if (voice < 0 || voice >= port->chset.max_channels)
return;
chan = &port->chset.channels[voice];
p1 = *(unsigned short *) &event[4];
p2 = *(short *) &event[6];
plong = *(int*) &event[4];
switch (cmd) {
case _GUS_VOICESAMPLE:
chan->midi_program = p1;
return;
case _GUS_VOICEBALA:
/* 0 to 15 --> 0 to 127 */
chan->control[MIDI_CTL_MSB_PAN] = (int)p1 << 3;
snd_emux_update_channel(port, chan, SNDRV_EMUX_UPDATE_PAN);
return;
case _GUS_VOICEVOL:
case _GUS_VOICEVOL2:
/* not supported yet */
return;
case _GUS_RAMPRANGE:
case _GUS_RAMPRATE:
case _GUS_RAMPMODE:
case _GUS_RAMPON:
case _GUS_RAMPOFF:
/* volume ramping not supported */
return;
case _GUS_VOLUME_SCALE:
return;
case _GUS_VOICE_POS:
#ifdef SNDRV_EMUX_USE_RAW_EFFECT
snd_emux_send_effect(port, chan, EMUX_FX_SAMPLE_START,
(short)(plong & 0x7fff),
EMUX_FX_FLAG_SET);
snd_emux_send_effect(port, chan, EMUX_FX_COARSE_SAMPLE_START,
(plong >> 15) & 0xffff,
EMUX_FX_FLAG_SET);
#endif
return;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jaroslav Kysela | 253 | 97.68% | 1 | 50.00% |
Takashi Iwai | 6 | 2.32% | 1 | 50.00% |
Total | 259 | 100.00% | 2 | 100.00% |
/*
* send an event to midi emulation
*/
static void
fake_event(struct snd_emux *emu, struct snd_emux_port *port, int ch, int param, int val, int atomic, int hop)
{
struct snd_seq_event ev;
memset(&ev, 0, sizeof(ev));
ev.type = SNDRV_SEQ_EVENT_CONTROLLER;
ev.data.control.channel = ch;
ev.data.control.param = param;
ev.data.control.value = val;
snd_emux_event_input(&ev, 0, port, atomic, hop);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jaroslav Kysela | 92 | 93.88% | 1 | 50.00% |
Takashi Iwai | 6 | 6.12% | 1 | 50.00% |
Total | 98 | 100.00% | 2 | 100.00% |
#endif /* CONFIG_SND_SEQUENCER_OSS */
Overall Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jaroslav Kysela | 1915 | 88.53% | 6 | 46.15% |
Takashi Iwai | 243 | 11.23% | 5 | 38.46% |
Paul Gortmaker | 3 | 0.14% | 1 | 7.69% |
Al Viro | 2 | 0.09% | 1 | 7.69% |
Total | 2163 | 100.00% | 13 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.