162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 462306a36Sopenharmony_ci * and (c) 1999 Steve Ratcliffe <steve@parabola.demon.co.uk> 562306a36Sopenharmony_ci * Copyright (C) 1999-2000 Takashi Iwai <tiwai@suse.de> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Emu8000 synth plug-in routine 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "emu8000_local.h" 1162306a36Sopenharmony_ci#include <linux/init.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <sound/initval.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ciMODULE_AUTHOR("Takashi Iwai, Steve Ratcliffe"); 1662306a36Sopenharmony_ciMODULE_DESCRIPTION("Emu8000 synth plug-in routine"); 1762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/*----------------------------------------------------------------*/ 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* 2262306a36Sopenharmony_ci * create a new hardware dependent device for Emu8000 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_cistatic int snd_emu8000_probe(struct device *_dev) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci struct snd_seq_device *dev = to_seq_dev(_dev); 2762306a36Sopenharmony_ci struct snd_emu8000 *hw; 2862306a36Sopenharmony_ci struct snd_emux *emu; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci hw = *(struct snd_emu8000**)SNDRV_SEQ_DEVICE_ARGPTR(dev); 3162306a36Sopenharmony_ci if (hw == NULL) 3262306a36Sopenharmony_ci return -EINVAL; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci if (hw->emu) 3562306a36Sopenharmony_ci return -EBUSY; /* already exists..? */ 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci if (snd_emux_new(&emu) < 0) 3862306a36Sopenharmony_ci return -ENOMEM; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci hw->emu = emu; 4162306a36Sopenharmony_ci snd_emu8000_ops_setup(hw); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci emu->hw = hw; 4462306a36Sopenharmony_ci emu->max_voices = EMU8000_DRAM_VOICES; 4562306a36Sopenharmony_ci emu->num_ports = hw->seq_ports; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci if (hw->memhdr) { 4862306a36Sopenharmony_ci snd_printk(KERN_ERR "memhdr is already initialized!?\n"); 4962306a36Sopenharmony_ci snd_util_memhdr_free(hw->memhdr); 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci hw->memhdr = snd_util_memhdr_new(hw->mem_size); 5262306a36Sopenharmony_ci if (hw->memhdr == NULL) { 5362306a36Sopenharmony_ci snd_emux_free(emu); 5462306a36Sopenharmony_ci hw->emu = NULL; 5562306a36Sopenharmony_ci return -ENOMEM; 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci emu->memhdr = hw->memhdr; 5962306a36Sopenharmony_ci emu->midi_ports = hw->seq_ports < 2 ? hw->seq_ports : 2; /* number of virmidi ports */ 6062306a36Sopenharmony_ci emu->midi_devidx = 1; 6162306a36Sopenharmony_ci emu->linear_panning = 1; 6262306a36Sopenharmony_ci emu->hwdep_idx = 2; /* FIXED */ 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci if (snd_emux_register(emu, dev->card, hw->index, "Emu8000") < 0) { 6562306a36Sopenharmony_ci snd_emux_free(emu); 6662306a36Sopenharmony_ci snd_util_memhdr_free(hw->memhdr); 6762306a36Sopenharmony_ci hw->emu = NULL; 6862306a36Sopenharmony_ci hw->memhdr = NULL; 6962306a36Sopenharmony_ci return -ENOMEM; 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if (hw->mem_size > 0) 7362306a36Sopenharmony_ci snd_emu8000_pcm_new(dev->card, hw, 1); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci dev->driver_data = hw; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci return 0; 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* 8262306a36Sopenharmony_ci * free all resources 8362306a36Sopenharmony_ci */ 8462306a36Sopenharmony_cistatic int snd_emu8000_remove(struct device *_dev) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci struct snd_seq_device *dev = to_seq_dev(_dev); 8762306a36Sopenharmony_ci struct snd_emu8000 *hw; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (dev->driver_data == NULL) 9062306a36Sopenharmony_ci return 0; /* no synth was allocated actually */ 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci hw = dev->driver_data; 9362306a36Sopenharmony_ci if (hw->pcm) 9462306a36Sopenharmony_ci snd_device_free(dev->card, hw->pcm); 9562306a36Sopenharmony_ci snd_emux_free(hw->emu); 9662306a36Sopenharmony_ci snd_util_memhdr_free(hw->memhdr); 9762306a36Sopenharmony_ci hw->emu = NULL; 9862306a36Sopenharmony_ci hw->memhdr = NULL; 9962306a36Sopenharmony_ci return 0; 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci/* 10362306a36Sopenharmony_ci * INIT part 10462306a36Sopenharmony_ci */ 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic struct snd_seq_driver emu8000_driver = { 10762306a36Sopenharmony_ci .driver = { 10862306a36Sopenharmony_ci .name = KBUILD_MODNAME, 10962306a36Sopenharmony_ci .probe = snd_emu8000_probe, 11062306a36Sopenharmony_ci .remove = snd_emu8000_remove, 11162306a36Sopenharmony_ci }, 11262306a36Sopenharmony_ci .id = SNDRV_SEQ_DEV_ID_EMU8000, 11362306a36Sopenharmony_ci .argsize = sizeof(struct snd_emu8000 *), 11462306a36Sopenharmony_ci}; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cimodule_snd_seq_driver(emu8000_driver); 117