root/sound/synth/emux/emux_oss.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. snd_emux_init_seq_oss
  2. snd_emux_detach_seq_oss
  3. snd_emux_open_seq_oss
  4. reset_port_mode
  5. snd_emux_close_seq_oss
  6. snd_emux_load_patch_seq_oss
  7. snd_emux_ioctl_seq_oss
  8. snd_emux_reset_seq_oss
  9. snd_emux_event_oss_input
  10. emuspec_control
  11. gusspec_control
  12. fake_event

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

/* [<][>][^][v][top][bottom][index][help] */