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