Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Interface for OSS sequencer emulation
0004  *
0005  *  Copyright (C) 1999 Takashi Iwai <tiwai@suse.de>
0006  *
0007  * Changes
0008  * 19990227   Steve Ratcliffe   Made separate file and merged in latest
0009  *              midi emulation.
0010  */
0011 
0012 
0013 #include <linux/export.h>
0014 #include <linux/uaccess.h>
0015 #include <sound/core.h>
0016 #include "emux_voice.h"
0017 #include <sound/asoundef.h>
0018 
0019 static int snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure);
0020 static int snd_emux_close_seq_oss(struct snd_seq_oss_arg *arg);
0021 static int snd_emux_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd,
0022                   unsigned long ioarg);
0023 static int snd_emux_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format,
0024                        const char __user *buf, int offs, int count);
0025 static int snd_emux_reset_seq_oss(struct snd_seq_oss_arg *arg);
0026 static int snd_emux_event_oss_input(struct snd_seq_event *ev, int direct,
0027                     void *private, int atomic, int hop);
0028 static void reset_port_mode(struct snd_emux_port *port, int midi_mode);
0029 static void emuspec_control(struct snd_emux *emu, struct snd_emux_port *port,
0030                 int cmd, unsigned char *event, int atomic, int hop);
0031 static void gusspec_control(struct snd_emux *emu, struct snd_emux_port *port,
0032                 int cmd, unsigned char *event, int atomic, int hop);
0033 static void fake_event(struct snd_emux *emu, struct snd_emux_port *port,
0034                int ch, int param, int val, int atomic, int hop);
0035 
0036 /* operators */
0037 static const struct snd_seq_oss_callback oss_callback = {
0038     .owner = THIS_MODULE,
0039     .open = snd_emux_open_seq_oss,
0040     .close = snd_emux_close_seq_oss,
0041     .ioctl = snd_emux_ioctl_seq_oss,
0042     .load_patch = snd_emux_load_patch_seq_oss,
0043     .reset = snd_emux_reset_seq_oss,
0044 };
0045 
0046 
0047 /*
0048  * register OSS synth
0049  */
0050 
0051 void
0052 snd_emux_init_seq_oss(struct snd_emux *emu)
0053 {
0054     struct snd_seq_oss_reg *arg;
0055     struct snd_seq_device *dev;
0056 
0057     /* using device#1 here for avoiding conflicts with OPL3 */
0058     if (snd_seq_device_new(emu->card, 1, SNDRV_SEQ_DEV_ID_OSS,
0059                    sizeof(struct snd_seq_oss_reg), &dev) < 0)
0060         return;
0061 
0062     emu->oss_synth = dev;
0063     strcpy(dev->name, emu->name);
0064     arg = SNDRV_SEQ_DEVICE_ARGPTR(dev);
0065     arg->type = SYNTH_TYPE_SAMPLE;
0066     arg->subtype = SAMPLE_TYPE_AWE32;
0067     arg->nvoices = emu->max_voices;
0068     arg->oper = oss_callback;
0069     arg->private_data = emu;
0070 
0071     /* register to OSS synth table */
0072     snd_device_register(emu->card, dev);
0073 }
0074 
0075 
0076 /*
0077  * unregister
0078  */
0079 void
0080 snd_emux_detach_seq_oss(struct snd_emux *emu)
0081 {
0082     if (emu->oss_synth) {
0083         snd_device_free(emu->card, emu->oss_synth);
0084         emu->oss_synth = NULL;
0085     }
0086 }
0087 
0088 
0089 /* use port number as a unique soundfont client number */
0090 #define SF_CLIENT_NO(p) ((p) + 0x1000)
0091 
0092 /*
0093  * open port for OSS sequencer
0094  */
0095 static int
0096 snd_emux_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure)
0097 {
0098     struct snd_emux *emu;
0099     struct snd_emux_port *p;
0100     struct snd_seq_port_callback callback;
0101     char tmpname[64];
0102 
0103     emu = closure;
0104     if (snd_BUG_ON(!arg || !emu))
0105         return -ENXIO;
0106 
0107     if (!snd_emux_inc_count(emu))
0108         return -EFAULT;
0109 
0110     memset(&callback, 0, sizeof(callback));
0111     callback.owner = THIS_MODULE;
0112     callback.event_input = snd_emux_event_oss_input;
0113 
0114     sprintf(tmpname, "%s OSS Port", emu->name);
0115     p = snd_emux_create_port(emu, tmpname, 32,
0116                  1, &callback);
0117     if (p == NULL) {
0118         snd_printk(KERN_ERR "can't create port\n");
0119         snd_emux_dec_count(emu);
0120         return -ENOMEM;
0121     }
0122 
0123     /* fill the argument data */
0124     arg->private_data = p;
0125     arg->addr.client = p->chset.client;
0126     arg->addr.port = p->chset.port;
0127     p->oss_arg = arg;
0128 
0129     reset_port_mode(p, arg->seq_mode);
0130 
0131     snd_emux_reset_port(p);
0132     return 0;
0133 }
0134 
0135 
0136 #define DEFAULT_DRUM_FLAGS  ((1<<9) | (1<<25))
0137 
0138 /*
0139  * reset port mode
0140  */
0141 static void
0142 reset_port_mode(struct snd_emux_port *port, int midi_mode)
0143 {
0144     if (midi_mode) {
0145         port->port_mode = SNDRV_EMUX_PORT_MODE_OSS_MIDI;
0146         port->drum_flags = DEFAULT_DRUM_FLAGS;
0147         port->volume_atten = 0;
0148         port->oss_arg->event_passing = SNDRV_SEQ_OSS_PROCESS_KEYPRESS;
0149     } else {
0150         port->port_mode = SNDRV_EMUX_PORT_MODE_OSS_SYNTH;
0151         port->drum_flags = 0;
0152         port->volume_atten = 32;
0153         port->oss_arg->event_passing = SNDRV_SEQ_OSS_PROCESS_EVENTS;
0154     }
0155 }
0156 
0157 
0158 /*
0159  * close port
0160  */
0161 static int
0162 snd_emux_close_seq_oss(struct snd_seq_oss_arg *arg)
0163 {
0164     struct snd_emux *emu;
0165     struct snd_emux_port *p;
0166 
0167     if (snd_BUG_ON(!arg))
0168         return -ENXIO;
0169     p = arg->private_data;
0170     if (snd_BUG_ON(!p))
0171         return -ENXIO;
0172 
0173     emu = p->emu;
0174     if (snd_BUG_ON(!emu))
0175         return -ENXIO;
0176 
0177     snd_emux_sounds_off_all(p);
0178     snd_soundfont_close_check(emu->sflist, SF_CLIENT_NO(p->chset.port));
0179     snd_seq_event_port_detach(p->chset.client, p->chset.port);
0180     snd_emux_dec_count(emu);
0181 
0182     return 0;
0183 }
0184 
0185 
0186 /*
0187  * load patch
0188  */
0189 static int
0190 snd_emux_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format,
0191                 const char __user *buf, int offs, int count)
0192 {
0193     struct snd_emux *emu;
0194     struct snd_emux_port *p;
0195     int rc;
0196 
0197     if (snd_BUG_ON(!arg))
0198         return -ENXIO;
0199     p = arg->private_data;
0200     if (snd_BUG_ON(!p))
0201         return -ENXIO;
0202 
0203     emu = p->emu;
0204     if (snd_BUG_ON(!emu))
0205         return -ENXIO;
0206 
0207     if (format == GUS_PATCH)
0208         rc = snd_soundfont_load_guspatch(emu->sflist, buf, count,
0209                          SF_CLIENT_NO(p->chset.port));
0210     else if (format == SNDRV_OSS_SOUNDFONT_PATCH) {
0211         struct soundfont_patch_info patch;
0212         if (count < (int)sizeof(patch))
0213             return -EINVAL;
0214         if (copy_from_user(&patch, buf, sizeof(patch)))
0215             return -EFAULT;
0216         if (patch.type >= SNDRV_SFNT_LOAD_INFO &&
0217             patch.type <= SNDRV_SFNT_PROBE_DATA)
0218             rc = snd_soundfont_load(emu->sflist, buf, count, SF_CLIENT_NO(p->chset.port));
0219         else {
0220             if (emu->ops.load_fx)
0221                 rc = emu->ops.load_fx(emu, patch.type, patch.optarg, buf, count);
0222             else
0223                 rc = -EINVAL;
0224         }
0225     } else
0226         rc = 0;
0227     return rc;
0228 }
0229 
0230 
0231 /*
0232  * ioctl
0233  */
0234 static int
0235 snd_emux_ioctl_seq_oss(struct snd_seq_oss_arg *arg, unsigned int cmd, unsigned long ioarg)
0236 {
0237     struct snd_emux_port *p;
0238     struct snd_emux *emu;
0239 
0240     if (snd_BUG_ON(!arg))
0241         return -ENXIO;
0242     p = arg->private_data;
0243     if (snd_BUG_ON(!p))
0244         return -ENXIO;
0245 
0246     emu = p->emu;
0247     if (snd_BUG_ON(!emu))
0248         return -ENXIO;
0249 
0250     switch (cmd) {
0251     case SNDCTL_SEQ_RESETSAMPLES:
0252         snd_soundfont_remove_samples(emu->sflist);
0253         return 0;
0254             
0255     case SNDCTL_SYNTH_MEMAVL:
0256         if (emu->memhdr)
0257             return snd_util_mem_avail(emu->memhdr);
0258         return 0;
0259     }
0260 
0261     return 0;
0262 }
0263 
0264 
0265 /*
0266  * reset device
0267  */
0268 static int
0269 snd_emux_reset_seq_oss(struct snd_seq_oss_arg *arg)
0270 {
0271     struct snd_emux_port *p;
0272 
0273     if (snd_BUG_ON(!arg))
0274         return -ENXIO;
0275     p = arg->private_data;
0276     if (snd_BUG_ON(!p))
0277         return -ENXIO;
0278     snd_emux_reset_port(p);
0279     return 0;
0280 }
0281 
0282 
0283 /*
0284  * receive raw events: only SEQ_PRIVATE is accepted.
0285  */
0286 static int
0287 snd_emux_event_oss_input(struct snd_seq_event *ev, int direct, void *private_data,
0288              int atomic, int hop)
0289 {
0290     struct snd_emux *emu;
0291     struct snd_emux_port *p;
0292     unsigned char cmd, *data;
0293 
0294     p = private_data;
0295     if (snd_BUG_ON(!p))
0296         return -EINVAL;
0297     emu = p->emu;
0298     if (snd_BUG_ON(!emu))
0299         return -EINVAL;
0300     if (ev->type != SNDRV_SEQ_EVENT_OSS)
0301         return snd_emux_event_input(ev, direct, private_data, atomic, hop);
0302 
0303     data = ev->data.raw8.d;
0304     /* only SEQ_PRIVATE is accepted */
0305     if (data[0] != 0xfe)
0306         return 0;
0307     cmd = data[2] & _EMUX_OSS_MODE_VALUE_MASK;
0308     if (data[2] & _EMUX_OSS_MODE_FLAG)
0309         emuspec_control(emu, p, cmd, data, atomic, hop);
0310     else
0311         gusspec_control(emu, p, cmd, data, atomic, hop);
0312     return 0;
0313 }
0314 
0315 
0316 /*
0317  * OSS/AWE driver specific h/w controls
0318  */
0319 static void
0320 emuspec_control(struct snd_emux *emu, struct snd_emux_port *port, int cmd,
0321         unsigned char *event, int atomic, int hop)
0322 {
0323     int voice;
0324     unsigned short p1;
0325     short p2;
0326     int i;
0327     struct snd_midi_channel *chan;
0328 
0329     voice = event[3];
0330     if (voice < 0 || voice >= port->chset.max_channels)
0331         chan = NULL;
0332     else
0333         chan = &port->chset.channels[voice];
0334 
0335     p1 = *(unsigned short *) &event[4];
0336     p2 = *(short *) &event[6];
0337 
0338     switch (cmd) {
0339 #if 0 /* don't do this atomically */
0340     case _EMUX_OSS_REMOVE_LAST_SAMPLES:
0341         snd_soundfont_remove_unlocked(emu->sflist);
0342         break;
0343 #endif
0344     case _EMUX_OSS_SEND_EFFECT:
0345         if (chan)
0346             snd_emux_send_effect_oss(port, chan, p1, p2);
0347         break;
0348         
0349     case _EMUX_OSS_TERMINATE_ALL:
0350         snd_emux_terminate_all(emu);
0351         break;
0352 
0353     case _EMUX_OSS_TERMINATE_CHANNEL:
0354         /*snd_emux_mute_channel(emu, chan);*/
0355         break;
0356     case _EMUX_OSS_RESET_CHANNEL:
0357         /*snd_emux_channel_init(chset, chan);*/
0358         break;
0359 
0360     case _EMUX_OSS_RELEASE_ALL:
0361         fake_event(emu, port, voice, MIDI_CTL_ALL_NOTES_OFF, 0, atomic, hop);
0362         break;
0363     case _EMUX_OSS_NOTEOFF_ALL:
0364         fake_event(emu, port, voice, MIDI_CTL_ALL_SOUNDS_OFF, 0, atomic, hop);
0365         break;
0366 
0367     case _EMUX_OSS_INITIAL_VOLUME:
0368         if (p2) {
0369             port->volume_atten = (short)p1;
0370             snd_emux_update_port(port, SNDRV_EMUX_UPDATE_VOLUME);
0371         }
0372         break;
0373 
0374     case _EMUX_OSS_CHN_PRESSURE:
0375         if (chan) {
0376             chan->midi_pressure = p1;
0377             snd_emux_update_channel(port, chan, SNDRV_EMUX_UPDATE_FMMOD|SNDRV_EMUX_UPDATE_FM2FRQ2);
0378         }
0379         break;
0380 
0381     case _EMUX_OSS_CHANNEL_MODE:
0382         reset_port_mode(port, p1);
0383         snd_emux_reset_port(port);
0384         break;
0385 
0386     case _EMUX_OSS_DRUM_CHANNELS:
0387         port->drum_flags = *(unsigned int*)&event[4];
0388         for (i = 0; i < port->chset.max_channels; i++) {
0389             chan = &port->chset.channels[i];
0390             chan->drum_channel = ((port->drum_flags >> i) & 1) ? 1 : 0;
0391         }
0392         break;
0393 
0394     case _EMUX_OSS_MISC_MODE:
0395         if (p1 < EMUX_MD_END)
0396             port->ctrls[p1] = p2;
0397         break;
0398     case _EMUX_OSS_DEBUG_MODE:
0399         break;
0400 
0401     default:
0402         if (emu->ops.oss_ioctl)
0403             emu->ops.oss_ioctl(emu, cmd, p1, p2);
0404         break;
0405     }
0406 }
0407 
0408 /*
0409  * GUS specific h/w controls
0410  */
0411 
0412 #include <linux/ultrasound.h>
0413 
0414 static void
0415 gusspec_control(struct snd_emux *emu, struct snd_emux_port *port, int cmd,
0416         unsigned char *event, int atomic, int hop)
0417 {
0418     int voice;
0419     unsigned short p1;
0420     int plong;
0421     struct snd_midi_channel *chan;
0422 
0423     if (port->port_mode != SNDRV_EMUX_PORT_MODE_OSS_SYNTH)
0424         return;
0425     if (cmd == _GUS_NUMVOICES)
0426         return;
0427     voice = event[3];
0428     if (voice < 0 || voice >= port->chset.max_channels)
0429         return;
0430 
0431     chan = &port->chset.channels[voice];
0432 
0433     p1 = *(unsigned short *) &event[4];
0434     plong = *(int*) &event[4];
0435 
0436     switch (cmd) {
0437     case _GUS_VOICESAMPLE:
0438         chan->midi_program = p1;
0439         return;
0440 
0441     case _GUS_VOICEBALA:
0442         /* 0 to 15 --> 0 to 127 */
0443         chan->control[MIDI_CTL_MSB_PAN] = (int)p1 << 3;
0444         snd_emux_update_channel(port, chan, SNDRV_EMUX_UPDATE_PAN);
0445         return;
0446 
0447     case _GUS_VOICEVOL:
0448     case _GUS_VOICEVOL2:
0449         /* not supported yet */
0450         return;
0451 
0452     case _GUS_RAMPRANGE:
0453     case _GUS_RAMPRATE:
0454     case _GUS_RAMPMODE:
0455     case _GUS_RAMPON:
0456     case _GUS_RAMPOFF:
0457         /* volume ramping not supported */
0458         return;
0459 
0460     case _GUS_VOLUME_SCALE:
0461         return;
0462 
0463     case _GUS_VOICE_POS:
0464 #ifdef SNDRV_EMUX_USE_RAW_EFFECT
0465         snd_emux_send_effect(port, chan, EMUX_FX_SAMPLE_START,
0466                      (short)(plong & 0x7fff),
0467                      EMUX_FX_FLAG_SET);
0468         snd_emux_send_effect(port, chan, EMUX_FX_COARSE_SAMPLE_START,
0469                      (plong >> 15) & 0xffff,
0470                      EMUX_FX_FLAG_SET);
0471 #endif
0472         return;
0473     }
0474 }
0475 
0476 
0477 /*
0478  * send an event to midi emulation
0479  */
0480 static void
0481 fake_event(struct snd_emux *emu, struct snd_emux_port *port, int ch, int param, int val, int atomic, int hop)
0482 {
0483     struct snd_seq_event ev;
0484     memset(&ev, 0, sizeof(ev));
0485     ev.type = SNDRV_SEQ_EVENT_CONTROLLER;
0486     ev.data.control.channel = ch;
0487     ev.data.control.param = param;
0488     ev.data.control.value = val;
0489     snd_emux_event_input(&ev, 0, port, atomic, hop);
0490 }