linux/sound/synth/emux/emux.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 *  Copyright (C) 2000 Takashi Iwai <tiwai@suse.de>
   4 *
   5 *  Routines for control of EMU WaveTable chip
   6 */
   7
   8#include <linux/wait.h>
   9#include <linux/slab.h>
  10#include <linux/string.h>
  11#include <sound/core.h>
  12#include <sound/emux_synth.h>
  13#include <linux/init.h>
  14#include <linux/module.h>
  15#include "emux_voice.h"
  16
  17MODULE_AUTHOR("Takashi Iwai");
  18MODULE_DESCRIPTION("Routines for control of EMU WaveTable chip");
  19MODULE_LICENSE("GPL");
  20
  21/*
  22 * create a new hardware dependent device for Emu8000/Emu10k1
  23 */
  24int snd_emux_new(struct snd_emux **remu)
  25{
  26        struct snd_emux *emu;
  27
  28        *remu = NULL;
  29        emu = kzalloc(sizeof(*emu), GFP_KERNEL);
  30        if (emu == NULL)
  31                return -ENOMEM;
  32
  33        spin_lock_init(&emu->voice_lock);
  34        mutex_init(&emu->register_mutex);
  35
  36        emu->client = -1;
  37#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS)
  38        emu->oss_synth = NULL;
  39#endif
  40        emu->max_voices = 0;
  41        emu->use_time = 0;
  42
  43        timer_setup(&emu->tlist, snd_emux_timer_callback, 0);
  44        emu->timer_active = 0;
  45
  46        *remu = emu;
  47        return 0;
  48}
  49
  50EXPORT_SYMBOL(snd_emux_new);
  51
  52/*
  53 */
  54static int sf_sample_new(void *private_data, struct snd_sf_sample *sp,
  55                                  struct snd_util_memhdr *hdr,
  56                                  const void __user *buf, long count)
  57{
  58        struct snd_emux *emu = private_data;
  59        return emu->ops.sample_new(emu, sp, hdr, buf, count);
  60        
  61}
  62
  63static int sf_sample_free(void *private_data, struct snd_sf_sample *sp,
  64                                   struct snd_util_memhdr *hdr)
  65{
  66        struct snd_emux *emu = private_data;
  67        return emu->ops.sample_free(emu, sp, hdr);
  68        
  69}
  70
  71static void sf_sample_reset(void *private_data)
  72{
  73        struct snd_emux *emu = private_data;
  74        emu->ops.sample_reset(emu);
  75}
  76
  77int snd_emux_register(struct snd_emux *emu, struct snd_card *card, int index, char *name)
  78{
  79        int err;
  80        struct snd_sf_callback sf_cb;
  81
  82        if (snd_BUG_ON(!emu->hw || emu->max_voices <= 0))
  83                return -EINVAL;
  84        if (snd_BUG_ON(!card || !name))
  85                return -EINVAL;
  86
  87        emu->card = card;
  88        emu->name = kstrdup(name, GFP_KERNEL);
  89        emu->voices = kcalloc(emu->max_voices, sizeof(struct snd_emux_voice),
  90                              GFP_KERNEL);
  91        if (emu->voices == NULL)
  92                return -ENOMEM;
  93
  94        /* create soundfont list */
  95        memset(&sf_cb, 0, sizeof(sf_cb));
  96        sf_cb.private_data = emu;
  97        if (emu->ops.sample_new)
  98                sf_cb.sample_new = sf_sample_new;
  99        if (emu->ops.sample_free)
 100                sf_cb.sample_free = sf_sample_free;
 101        if (emu->ops.sample_reset)
 102                sf_cb.sample_reset = sf_sample_reset;
 103        emu->sflist = snd_sf_new(&sf_cb, emu->memhdr);
 104        if (emu->sflist == NULL)
 105                return -ENOMEM;
 106
 107        err = snd_emux_init_hwdep(emu);
 108        if (err < 0)
 109                return err;
 110
 111        snd_emux_init_voices(emu);
 112
 113        snd_emux_init_seq(emu, card, index);
 114#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS)
 115        snd_emux_init_seq_oss(emu);
 116#endif
 117        snd_emux_init_virmidi(emu, card);
 118
 119        snd_emux_proc_init(emu, card, index);
 120        return 0;
 121}
 122
 123EXPORT_SYMBOL(snd_emux_register);
 124
 125/*
 126 */
 127int snd_emux_free(struct snd_emux *emu)
 128{
 129        unsigned long flags;
 130
 131        if (! emu)
 132                return -EINVAL;
 133
 134        spin_lock_irqsave(&emu->voice_lock, flags);
 135        if (emu->timer_active)
 136                del_timer(&emu->tlist);
 137        spin_unlock_irqrestore(&emu->voice_lock, flags);
 138
 139        snd_emux_proc_free(emu);
 140        snd_emux_delete_virmidi(emu);
 141#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS)
 142        snd_emux_detach_seq_oss(emu);
 143#endif
 144        snd_emux_detach_seq(emu);
 145        snd_emux_delete_hwdep(emu);
 146        snd_sf_free(emu->sflist);
 147        kfree(emu->voices);
 148        kfree(emu->name);
 149        kfree(emu);
 150        return 0;
 151}
 152
 153EXPORT_SYMBOL(snd_emux_free);
 154