162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Copyright (C) 2000 Takashi Iwai <tiwai@suse.de>
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Routines for control of EMU10K1 WaveTable synth
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "emu10k1_synth_local.h"
962306a36Sopenharmony_ci#include <linux/init.h>
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ciMODULE_AUTHOR("Takashi Iwai");
1362306a36Sopenharmony_ciMODULE_DESCRIPTION("Routines for control of EMU10K1 WaveTable synth");
1462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci/*
1762306a36Sopenharmony_ci * create a new hardware dependent device for Emu10k1
1862306a36Sopenharmony_ci */
1962306a36Sopenharmony_cistatic int snd_emu10k1_synth_probe(struct device *_dev)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	struct snd_seq_device *dev = to_seq_dev(_dev);
2262306a36Sopenharmony_ci	struct snd_emux *emux;
2362306a36Sopenharmony_ci	struct snd_emu10k1 *hw;
2462306a36Sopenharmony_ci	struct snd_emu10k1_synth_arg *arg;
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci	arg = SNDRV_SEQ_DEVICE_ARGPTR(dev);
2762306a36Sopenharmony_ci	if (arg == NULL)
2862306a36Sopenharmony_ci		return -EINVAL;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	if (arg->seq_ports <= 0)
3162306a36Sopenharmony_ci		return 0; /* nothing */
3262306a36Sopenharmony_ci	if (arg->max_voices < 1)
3362306a36Sopenharmony_ci		arg->max_voices = 1;
3462306a36Sopenharmony_ci	else if (arg->max_voices > 64)
3562306a36Sopenharmony_ci		arg->max_voices = 64;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	if (snd_emux_new(&emux) < 0)
3862306a36Sopenharmony_ci		return -ENOMEM;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	snd_emu10k1_ops_setup(emux);
4162306a36Sopenharmony_ci	hw = arg->hwptr;
4262306a36Sopenharmony_ci	emux->hw = hw;
4362306a36Sopenharmony_ci	emux->max_voices = arg->max_voices;
4462306a36Sopenharmony_ci	emux->num_ports = arg->seq_ports;
4562306a36Sopenharmony_ci	emux->memhdr = hw->memhdr;
4662306a36Sopenharmony_ci	/* maximum two ports */
4762306a36Sopenharmony_ci	emux->midi_ports = arg->seq_ports < 2 ? arg->seq_ports : 2;
4862306a36Sopenharmony_ci	/* audigy has two external midis */
4962306a36Sopenharmony_ci	emux->midi_devidx = hw->audigy ? 2 : 1;
5062306a36Sopenharmony_ci	emux->linear_panning = 0;
5162306a36Sopenharmony_ci	emux->hwdep_idx = 2; /* FIXED */
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	if (snd_emux_register(emux, dev->card, arg->index, "Emu10k1") < 0) {
5462306a36Sopenharmony_ci		snd_emux_free(emux);
5562306a36Sopenharmony_ci		return -ENOMEM;
5662306a36Sopenharmony_ci	}
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	spin_lock_irq(&hw->voice_lock);
5962306a36Sopenharmony_ci	hw->synth = emux;
6062306a36Sopenharmony_ci	hw->get_synth_voice = snd_emu10k1_synth_get_voice;
6162306a36Sopenharmony_ci	spin_unlock_irq(&hw->voice_lock);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	dev->driver_data = emux;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	return 0;
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic int snd_emu10k1_synth_remove(struct device *_dev)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	struct snd_seq_device *dev = to_seq_dev(_dev);
7162306a36Sopenharmony_ci	struct snd_emux *emux;
7262306a36Sopenharmony_ci	struct snd_emu10k1 *hw;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	if (dev->driver_data == NULL)
7562306a36Sopenharmony_ci		return 0; /* not registered actually */
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	emux = dev->driver_data;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	hw = emux->hw;
8062306a36Sopenharmony_ci	spin_lock_irq(&hw->voice_lock);
8162306a36Sopenharmony_ci	hw->synth = NULL;
8262306a36Sopenharmony_ci	hw->get_synth_voice = NULL;
8362306a36Sopenharmony_ci	spin_unlock_irq(&hw->voice_lock);
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	snd_emux_free(emux);
8662306a36Sopenharmony_ci	return 0;
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci/*
9062306a36Sopenharmony_ci *  INIT part
9162306a36Sopenharmony_ci */
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic struct snd_seq_driver emu10k1_synth_driver = {
9462306a36Sopenharmony_ci	.driver = {
9562306a36Sopenharmony_ci		.name = KBUILD_MODNAME,
9662306a36Sopenharmony_ci		.probe = snd_emu10k1_synth_probe,
9762306a36Sopenharmony_ci		.remove = snd_emu10k1_synth_remove,
9862306a36Sopenharmony_ci	},
9962306a36Sopenharmony_ci	.id = SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH,
10062306a36Sopenharmony_ci	.argsize = sizeof(struct snd_emu10k1_synth_arg),
10162306a36Sopenharmony_ci};
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cimodule_snd_seq_driver(emu10k1_synth_driver);
104