162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  The driver for the EMU10K1 (SB Live!) based soundcards
462306a36Sopenharmony_ci *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
562306a36Sopenharmony_ci *                   James Courtier-Dutton <James@superbug.co.uk>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/init.h>
962306a36Sopenharmony_ci#include <linux/pci.h>
1062306a36Sopenharmony_ci#include <linux/time.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <sound/core.h>
1362306a36Sopenharmony_ci#include <sound/emu10k1.h>
1462306a36Sopenharmony_ci#include <sound/initval.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ciMODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
1762306a36Sopenharmony_ciMODULE_DESCRIPTION("EMU10K1");
1862306a36Sopenharmony_ciMODULE_LICENSE("GPL");
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SEQUENCER)
2162306a36Sopenharmony_ci#define ENABLE_SYNTH
2262306a36Sopenharmony_ci#include <sound/emu10k1_synth.h>
2362306a36Sopenharmony_ci#endif
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
2662306a36Sopenharmony_cistatic char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
2762306a36Sopenharmony_cistatic bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;	/* Enable this card */
2862306a36Sopenharmony_cistatic int extin[SNDRV_CARDS];
2962306a36Sopenharmony_cistatic int extout[SNDRV_CARDS];
3062306a36Sopenharmony_cistatic int seq_ports[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 4};
3162306a36Sopenharmony_cistatic int max_synth_voices[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 64};
3262306a36Sopenharmony_cistatic int max_buffer_size[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 128};
3362306a36Sopenharmony_cistatic bool enable_ir[SNDRV_CARDS];
3462306a36Sopenharmony_cistatic uint subsystem[SNDRV_CARDS]; /* Force card subsystem model */
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cimodule_param_array(index, int, NULL, 0444);
3762306a36Sopenharmony_ciMODULE_PARM_DESC(index, "Index value for the EMU10K1 soundcard.");
3862306a36Sopenharmony_cimodule_param_array(id, charp, NULL, 0444);
3962306a36Sopenharmony_ciMODULE_PARM_DESC(id, "ID string for the EMU10K1 soundcard.");
4062306a36Sopenharmony_cimodule_param_array(enable, bool, NULL, 0444);
4162306a36Sopenharmony_ciMODULE_PARM_DESC(enable, "Enable the EMU10K1 soundcard.");
4262306a36Sopenharmony_cimodule_param_array(extin, int, NULL, 0444);
4362306a36Sopenharmony_ciMODULE_PARM_DESC(extin, "Available external inputs for FX8010. Zero=default.");
4462306a36Sopenharmony_cimodule_param_array(extout, int, NULL, 0444);
4562306a36Sopenharmony_ciMODULE_PARM_DESC(extout, "Available external outputs for FX8010. Zero=default.");
4662306a36Sopenharmony_cimodule_param_array(seq_ports, int, NULL, 0444);
4762306a36Sopenharmony_ciMODULE_PARM_DESC(seq_ports, "Allocated sequencer ports for internal synthesizer.");
4862306a36Sopenharmony_cimodule_param_array(max_synth_voices, int, NULL, 0444);
4962306a36Sopenharmony_ciMODULE_PARM_DESC(max_synth_voices, "Maximum number of voices for WaveTable.");
5062306a36Sopenharmony_cimodule_param_array(max_buffer_size, int, NULL, 0444);
5162306a36Sopenharmony_ciMODULE_PARM_DESC(max_buffer_size, "Maximum sample buffer size in MB.");
5262306a36Sopenharmony_cimodule_param_array(enable_ir, bool, NULL, 0444);
5362306a36Sopenharmony_ciMODULE_PARM_DESC(enable_ir, "Enable IR.");
5462306a36Sopenharmony_cimodule_param_array(subsystem, uint, NULL, 0444);
5562306a36Sopenharmony_ciMODULE_PARM_DESC(subsystem, "Force card subsystem model.");
5662306a36Sopenharmony_ci/*
5762306a36Sopenharmony_ci * Class 0401: 1102:0008 (rev 00) Subsystem: 1102:1001 -> Audigy2 Value  Model:SB0400
5862306a36Sopenharmony_ci */
5962306a36Sopenharmony_cistatic const struct pci_device_id snd_emu10k1_ids[] = {
6062306a36Sopenharmony_ci	{ PCI_VDEVICE(CREATIVE, 0x0002), 0 },	/* EMU10K1 */
6162306a36Sopenharmony_ci	{ PCI_VDEVICE(CREATIVE, 0x0004), 1 },	/* Audigy */
6262306a36Sopenharmony_ci	{ PCI_VDEVICE(CREATIVE, 0x0008), 1 },	/* Audigy 2 Value SB0400 */
6362306a36Sopenharmony_ci	{ 0, }
6462306a36Sopenharmony_ci};
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, snd_emu10k1_ids);
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic int snd_card_emu10k1_probe(struct pci_dev *pci,
6962306a36Sopenharmony_ci				  const struct pci_device_id *pci_id)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	static int dev;
7262306a36Sopenharmony_ci	struct snd_card *card;
7362306a36Sopenharmony_ci	struct snd_emu10k1 *emu;
7462306a36Sopenharmony_ci#ifdef ENABLE_SYNTH
7562306a36Sopenharmony_ci	struct snd_seq_device *wave = NULL;
7662306a36Sopenharmony_ci#endif
7762306a36Sopenharmony_ci	int err;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	if (dev >= SNDRV_CARDS)
8062306a36Sopenharmony_ci        	return -ENODEV;
8162306a36Sopenharmony_ci	if (!enable[dev]) {
8262306a36Sopenharmony_ci		dev++;
8362306a36Sopenharmony_ci		return -ENOENT;
8462306a36Sopenharmony_ci	}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	err = snd_devm_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
8762306a36Sopenharmony_ci				sizeof(*emu), &card);
8862306a36Sopenharmony_ci	if (err < 0)
8962306a36Sopenharmony_ci		return err;
9062306a36Sopenharmony_ci	emu = card->private_data;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	if (max_buffer_size[dev] < 32)
9362306a36Sopenharmony_ci		max_buffer_size[dev] = 32;
9462306a36Sopenharmony_ci	else if (max_buffer_size[dev] > 1024)
9562306a36Sopenharmony_ci		max_buffer_size[dev] = 1024;
9662306a36Sopenharmony_ci	err = snd_emu10k1_create(card, pci, extin[dev], extout[dev],
9762306a36Sopenharmony_ci				 (long)max_buffer_size[dev] * 1024 * 1024,
9862306a36Sopenharmony_ci				 enable_ir[dev], subsystem[dev]);
9962306a36Sopenharmony_ci	if (err < 0)
10062306a36Sopenharmony_ci		return err;
10162306a36Sopenharmony_ci	err = snd_emu10k1_pcm(emu, 0);
10262306a36Sopenharmony_ci	if (err < 0)
10362306a36Sopenharmony_ci		return err;
10462306a36Sopenharmony_ci	if (emu->card_capabilities->ac97_chip) {
10562306a36Sopenharmony_ci		err = snd_emu10k1_pcm_mic(emu, 1);
10662306a36Sopenharmony_ci		if (err < 0)
10762306a36Sopenharmony_ci			return err;
10862306a36Sopenharmony_ci	}
10962306a36Sopenharmony_ci	err = snd_emu10k1_pcm_efx(emu, 2);
11062306a36Sopenharmony_ci	if (err < 0)
11162306a36Sopenharmony_ci		return err;
11262306a36Sopenharmony_ci	/* This stores the periods table. */
11362306a36Sopenharmony_ci	if (emu->card_capabilities->ca0151_chip) { /* P16V */
11462306a36Sopenharmony_ci		emu->p16v_buffer =
11562306a36Sopenharmony_ci			snd_devm_alloc_pages(&pci->dev, SNDRV_DMA_TYPE_DEV, 1024);
11662306a36Sopenharmony_ci		if (!emu->p16v_buffer)
11762306a36Sopenharmony_ci			return -ENOMEM;
11862306a36Sopenharmony_ci	}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	err = snd_emu10k1_mixer(emu, 0, 3);
12162306a36Sopenharmony_ci	if (err < 0)
12262306a36Sopenharmony_ci		return err;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	err = snd_emu10k1_timer(emu, 0);
12562306a36Sopenharmony_ci	if (err < 0)
12662306a36Sopenharmony_ci		return err;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	err = snd_emu10k1_pcm_multi(emu, 3);
12962306a36Sopenharmony_ci	if (err < 0)
13062306a36Sopenharmony_ci		return err;
13162306a36Sopenharmony_ci	if (emu->card_capabilities->ca0151_chip) { /* P16V */
13262306a36Sopenharmony_ci		err = snd_p16v_pcm(emu, 4);
13362306a36Sopenharmony_ci		if (err < 0)
13462306a36Sopenharmony_ci			return err;
13562306a36Sopenharmony_ci	}
13662306a36Sopenharmony_ci	if (emu->audigy) {
13762306a36Sopenharmony_ci		err = snd_emu10k1_audigy_midi(emu);
13862306a36Sopenharmony_ci		if (err < 0)
13962306a36Sopenharmony_ci			return err;
14062306a36Sopenharmony_ci	} else {
14162306a36Sopenharmony_ci		err = snd_emu10k1_midi(emu);
14262306a36Sopenharmony_ci		if (err < 0)
14362306a36Sopenharmony_ci			return err;
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci	err = snd_emu10k1_fx8010_new(emu, 0);
14662306a36Sopenharmony_ci	if (err < 0)
14762306a36Sopenharmony_ci		return err;
14862306a36Sopenharmony_ci#ifdef ENABLE_SYNTH
14962306a36Sopenharmony_ci	if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH,
15062306a36Sopenharmony_ci			       sizeof(struct snd_emu10k1_synth_arg), &wave) < 0 ||
15162306a36Sopenharmony_ci	    wave == NULL) {
15262306a36Sopenharmony_ci		dev_warn(emu->card->dev,
15362306a36Sopenharmony_ci			 "can't initialize Emu10k1 wavetable synth\n");
15462306a36Sopenharmony_ci	} else {
15562306a36Sopenharmony_ci		struct snd_emu10k1_synth_arg *arg;
15662306a36Sopenharmony_ci		arg = SNDRV_SEQ_DEVICE_ARGPTR(wave);
15762306a36Sopenharmony_ci		strcpy(wave->name, "Emu-10k1 Synth");
15862306a36Sopenharmony_ci		arg->hwptr = emu;
15962306a36Sopenharmony_ci		arg->index = 1;
16062306a36Sopenharmony_ci		arg->seq_ports = seq_ports[dev];
16162306a36Sopenharmony_ci		arg->max_voices = max_synth_voices[dev];
16262306a36Sopenharmony_ci	}
16362306a36Sopenharmony_ci#endif
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	strscpy(card->driver, emu->card_capabilities->driver,
16662306a36Sopenharmony_ci		sizeof(card->driver));
16762306a36Sopenharmony_ci	strscpy(card->shortname, emu->card_capabilities->name,
16862306a36Sopenharmony_ci		sizeof(card->shortname));
16962306a36Sopenharmony_ci	snprintf(card->longname, sizeof(card->longname),
17062306a36Sopenharmony_ci		 "%s (rev.%d, serial:0x%x) at 0x%lx, irq %i",
17162306a36Sopenharmony_ci		 card->shortname, emu->revision, emu->serial, emu->port, emu->irq);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	err = snd_card_register(card);
17462306a36Sopenharmony_ci	if (err < 0)
17562306a36Sopenharmony_ci		return err;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	pci_set_drvdata(pci, card);
17862306a36Sopenharmony_ci	dev++;
17962306a36Sopenharmony_ci	return 0;
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
18362306a36Sopenharmony_cistatic int snd_emu10k1_suspend(struct device *dev)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	struct snd_card *card = dev_get_drvdata(dev);
18662306a36Sopenharmony_ci	struct snd_emu10k1 *emu = card->private_data;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	emu->suspend = 1;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	cancel_work_sync(&emu->emu1010.firmware_work);
19362306a36Sopenharmony_ci	cancel_work_sync(&emu->emu1010.clock_work);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	snd_ac97_suspend(emu->ac97);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	snd_emu10k1_efx_suspend(emu);
19862306a36Sopenharmony_ci	snd_emu10k1_suspend_regs(emu);
19962306a36Sopenharmony_ci	if (emu->card_capabilities->ca0151_chip)
20062306a36Sopenharmony_ci		snd_p16v_suspend(emu);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	snd_emu10k1_done(emu);
20362306a36Sopenharmony_ci	return 0;
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_cistatic int snd_emu10k1_resume(struct device *dev)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	struct snd_card *card = dev_get_drvdata(dev);
20962306a36Sopenharmony_ci	struct snd_emu10k1 *emu = card->private_data;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	snd_emu10k1_resume_init(emu);
21262306a36Sopenharmony_ci	snd_emu10k1_efx_resume(emu);
21362306a36Sopenharmony_ci	snd_ac97_resume(emu->ac97);
21462306a36Sopenharmony_ci	snd_emu10k1_resume_regs(emu);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	if (emu->card_capabilities->ca0151_chip)
21762306a36Sopenharmony_ci		snd_p16v_resume(emu);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	emu->suspend = 0;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	return 0;
22462306a36Sopenharmony_ci}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(snd_emu10k1_pm, snd_emu10k1_suspend, snd_emu10k1_resume);
22762306a36Sopenharmony_ci#define SND_EMU10K1_PM_OPS	&snd_emu10k1_pm
22862306a36Sopenharmony_ci#else
22962306a36Sopenharmony_ci#define SND_EMU10K1_PM_OPS	NULL
23062306a36Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cistatic struct pci_driver emu10k1_driver = {
23362306a36Sopenharmony_ci	.name = KBUILD_MODNAME,
23462306a36Sopenharmony_ci	.id_table = snd_emu10k1_ids,
23562306a36Sopenharmony_ci	.probe = snd_card_emu10k1_probe,
23662306a36Sopenharmony_ci	.driver = {
23762306a36Sopenharmony_ci		.pm = SND_EMU10K1_PM_OPS,
23862306a36Sopenharmony_ci	},
23962306a36Sopenharmony_ci};
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cimodule_pci_driver(emu10k1_driver);
242