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