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