162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Driver for SoundBlaster 16/AWE32/AWE64 soundcards
462306a36Sopenharmony_ci *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <asm/dma.h>
862306a36Sopenharmony_ci#include <linux/init.h>
962306a36Sopenharmony_ci#include <linux/pnp.h>
1062306a36Sopenharmony_ci#include <linux/err.h>
1162306a36Sopenharmony_ci#include <linux/isa.h>
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci#include <sound/core.h>
1462306a36Sopenharmony_ci#include <sound/sb.h>
1562306a36Sopenharmony_ci#include <sound/sb16_csp.h>
1662306a36Sopenharmony_ci#include <sound/mpu401.h>
1762306a36Sopenharmony_ci#include <sound/opl3.h>
1862306a36Sopenharmony_ci#include <sound/emu8000.h>
1962306a36Sopenharmony_ci#include <sound/seq_device.h>
2062306a36Sopenharmony_ci#define SNDRV_LEGACY_FIND_FREE_IRQ
2162306a36Sopenharmony_ci#define SNDRV_LEGACY_FIND_FREE_DMA
2262306a36Sopenharmony_ci#include <sound/initval.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#ifdef SNDRV_SBAWE
2562306a36Sopenharmony_ci#define PFX "sbawe: "
2662306a36Sopenharmony_ci#else
2762306a36Sopenharmony_ci#define PFX "sb16: "
2862306a36Sopenharmony_ci#endif
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ciMODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
3162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
3262306a36Sopenharmony_ci#ifndef SNDRV_SBAWE
3362306a36Sopenharmony_ciMODULE_DESCRIPTION("Sound Blaster 16");
3462306a36Sopenharmony_ci#else
3562306a36Sopenharmony_ciMODULE_DESCRIPTION("Sound Blaster AWE");
3662306a36Sopenharmony_ci#endif
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#if 0
3962306a36Sopenharmony_ci#define SNDRV_DEBUG_IRQ
4062306a36Sopenharmony_ci#endif
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#if defined(SNDRV_SBAWE) && IS_ENABLED(CONFIG_SND_SEQUENCER)
4362306a36Sopenharmony_ci#define SNDRV_SBAWE_EMU8000
4462306a36Sopenharmony_ci#endif
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
4762306a36Sopenharmony_cistatic char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
4862306a36Sopenharmony_cistatic bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
4962306a36Sopenharmony_ci#ifdef CONFIG_PNP
5062306a36Sopenharmony_cistatic bool isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
5162306a36Sopenharmony_ci#endif
5262306a36Sopenharmony_cistatic long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* 0x220,0x240,0x260,0x280 */
5362306a36Sopenharmony_cistatic long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* 0x330,0x300 */
5462306a36Sopenharmony_cistatic long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
5562306a36Sopenharmony_ci#ifdef SNDRV_SBAWE_EMU8000
5662306a36Sopenharmony_cistatic long awe_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
5762306a36Sopenharmony_ci#endif
5862306a36Sopenharmony_cistatic int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* 5,7,9,10 */
5962306a36Sopenharmony_cistatic int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* 0,1,3 */
6062306a36Sopenharmony_cistatic int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* 5,6,7 */
6162306a36Sopenharmony_cistatic int mic_agc[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
6262306a36Sopenharmony_ci#ifdef CONFIG_SND_SB16_CSP
6362306a36Sopenharmony_cistatic int csp[SNDRV_CARDS];
6462306a36Sopenharmony_ci#endif
6562306a36Sopenharmony_ci#ifdef SNDRV_SBAWE_EMU8000
6662306a36Sopenharmony_cistatic int seq_ports[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 4};
6762306a36Sopenharmony_ci#endif
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cimodule_param_array(index, int, NULL, 0444);
7062306a36Sopenharmony_ciMODULE_PARM_DESC(index, "Index value for SoundBlaster 16 soundcard.");
7162306a36Sopenharmony_cimodule_param_array(id, charp, NULL, 0444);
7262306a36Sopenharmony_ciMODULE_PARM_DESC(id, "ID string for SoundBlaster 16 soundcard.");
7362306a36Sopenharmony_cimodule_param_array(enable, bool, NULL, 0444);
7462306a36Sopenharmony_ciMODULE_PARM_DESC(enable, "Enable SoundBlaster 16 soundcard.");
7562306a36Sopenharmony_ci#ifdef CONFIG_PNP
7662306a36Sopenharmony_cimodule_param_array(isapnp, bool, NULL, 0444);
7762306a36Sopenharmony_ciMODULE_PARM_DESC(isapnp, "PnP detection for specified soundcard.");
7862306a36Sopenharmony_ci#endif
7962306a36Sopenharmony_cimodule_param_hw_array(port, long, ioport, NULL, 0444);
8062306a36Sopenharmony_ciMODULE_PARM_DESC(port, "Port # for SB16 driver.");
8162306a36Sopenharmony_cimodule_param_hw_array(mpu_port, long, ioport, NULL, 0444);
8262306a36Sopenharmony_ciMODULE_PARM_DESC(mpu_port, "MPU-401 port # for SB16 driver.");
8362306a36Sopenharmony_cimodule_param_hw_array(fm_port, long, ioport, NULL, 0444);
8462306a36Sopenharmony_ciMODULE_PARM_DESC(fm_port, "FM port # for SB16 PnP driver.");
8562306a36Sopenharmony_ci#ifdef SNDRV_SBAWE_EMU8000
8662306a36Sopenharmony_cimodule_param_hw_array(awe_port, long, ioport, NULL, 0444);
8762306a36Sopenharmony_ciMODULE_PARM_DESC(awe_port, "AWE port # for SB16 PnP driver.");
8862306a36Sopenharmony_ci#endif
8962306a36Sopenharmony_cimodule_param_hw_array(irq, int, irq, NULL, 0444);
9062306a36Sopenharmony_ciMODULE_PARM_DESC(irq, "IRQ # for SB16 driver.");
9162306a36Sopenharmony_cimodule_param_hw_array(dma8, int, dma, NULL, 0444);
9262306a36Sopenharmony_ciMODULE_PARM_DESC(dma8, "8-bit DMA # for SB16 driver.");
9362306a36Sopenharmony_cimodule_param_hw_array(dma16, int, dma, NULL, 0444);
9462306a36Sopenharmony_ciMODULE_PARM_DESC(dma16, "16-bit DMA # for SB16 driver.");
9562306a36Sopenharmony_cimodule_param_array(mic_agc, int, NULL, 0444);
9662306a36Sopenharmony_ciMODULE_PARM_DESC(mic_agc, "Mic Auto-Gain-Control switch.");
9762306a36Sopenharmony_ci#ifdef CONFIG_SND_SB16_CSP
9862306a36Sopenharmony_cimodule_param_array(csp, int, NULL, 0444);
9962306a36Sopenharmony_ciMODULE_PARM_DESC(csp, "ASP/CSP chip support.");
10062306a36Sopenharmony_ci#endif
10162306a36Sopenharmony_ci#ifdef SNDRV_SBAWE_EMU8000
10262306a36Sopenharmony_cimodule_param_array(seq_ports, int, NULL, 0444);
10362306a36Sopenharmony_ciMODULE_PARM_DESC(seq_ports, "Number of sequencer ports for WaveTable synth.");
10462306a36Sopenharmony_ci#endif
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci#ifdef CONFIG_PNP
10762306a36Sopenharmony_cistatic int isa_registered;
10862306a36Sopenharmony_cistatic int pnp_registered;
10962306a36Sopenharmony_ci#endif
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistruct snd_card_sb16 {
11262306a36Sopenharmony_ci	struct resource *fm_res;	/* used to block FM i/o region for legacy cards */
11362306a36Sopenharmony_ci	struct snd_sb *chip;
11462306a36Sopenharmony_ci#ifdef CONFIG_PNP
11562306a36Sopenharmony_ci	int dev_no;
11662306a36Sopenharmony_ci	struct pnp_dev *dev;
11762306a36Sopenharmony_ci#ifdef SNDRV_SBAWE_EMU8000
11862306a36Sopenharmony_ci	struct pnp_dev *devwt;
11962306a36Sopenharmony_ci#endif
12062306a36Sopenharmony_ci#endif
12162306a36Sopenharmony_ci};
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci#ifdef CONFIG_PNP
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic const struct pnp_card_device_id snd_sb16_pnpids[] = {
12662306a36Sopenharmony_ci#ifndef SNDRV_SBAWE
12762306a36Sopenharmony_ci	/* Sound Blaster 16 PnP */
12862306a36Sopenharmony_ci	{ .id = "CTL0024", .devs = { { "CTL0031" } } },
12962306a36Sopenharmony_ci	/* Sound Blaster 16 PnP */
13062306a36Sopenharmony_ci	{ .id = "CTL0025", .devs = { { "CTL0031" } } },
13162306a36Sopenharmony_ci	/* Sound Blaster 16 PnP */
13262306a36Sopenharmony_ci	{ .id = "CTL0026", .devs = { { "CTL0031" } } },
13362306a36Sopenharmony_ci	/* Sound Blaster 16 PnP */
13462306a36Sopenharmony_ci	{ .id = "CTL0027", .devs = { { "CTL0031" } } },
13562306a36Sopenharmony_ci	/* Sound Blaster 16 PnP */
13662306a36Sopenharmony_ci	{ .id = "CTL0028", .devs = { { "CTL0031" } } },
13762306a36Sopenharmony_ci	/* Sound Blaster 16 PnP */
13862306a36Sopenharmony_ci	{ .id = "CTL0029", .devs = { { "CTL0031" } } },
13962306a36Sopenharmony_ci	/* Sound Blaster 16 PnP */
14062306a36Sopenharmony_ci	{ .id = "CTL002a", .devs = { { "CTL0031" } } },
14162306a36Sopenharmony_ci	/* Sound Blaster 16 PnP */
14262306a36Sopenharmony_ci	/* Note: This card has also a CTL0051:StereoEnhance device!!! */
14362306a36Sopenharmony_ci	{ .id = "CTL002b", .devs = { { "CTL0031" } } },
14462306a36Sopenharmony_ci	/* Sound Blaster 16 PnP */
14562306a36Sopenharmony_ci	{ .id = "CTL002c", .devs = { { "CTL0031" } } },
14662306a36Sopenharmony_ci	/* Sound Blaster Vibra16S */
14762306a36Sopenharmony_ci	{ .id = "CTL0051", .devs = { { "CTL0001" } } },
14862306a36Sopenharmony_ci	/* Sound Blaster Vibra16C */
14962306a36Sopenharmony_ci	{ .id = "CTL0070", .devs = { { "CTL0001" } } },
15062306a36Sopenharmony_ci	/* Sound Blaster Vibra16CL - added by ctm@ardi.com */
15162306a36Sopenharmony_ci	{ .id = "CTL0080", .devs = { { "CTL0041" } } },
15262306a36Sopenharmony_ci	/* Sound Blaster 16 'value' PnP. It says model ct4130 on the pcb, */
15362306a36Sopenharmony_ci	/* but ct4131 on a sticker on the board.. */
15462306a36Sopenharmony_ci	{ .id = "CTL0086", .devs = { { "CTL0041" } } },
15562306a36Sopenharmony_ci	/* Sound Blaster Vibra16X */
15662306a36Sopenharmony_ci	{ .id = "CTL00f0", .devs = { { "CTL0043" } } },
15762306a36Sopenharmony_ci	/* Sound Blaster 16 (Virtual PC 2004) */
15862306a36Sopenharmony_ci	{ .id = "tBA03b0", .devs = { {.id="PNPb003" } } },
15962306a36Sopenharmony_ci#else  /* SNDRV_SBAWE defined */
16062306a36Sopenharmony_ci	/* Sound Blaster AWE 32 PnP */
16162306a36Sopenharmony_ci	{ .id = "CTL0035", .devs = { { "CTL0031" }, { "CTL0021" } } },
16262306a36Sopenharmony_ci	/* Sound Blaster AWE 32 PnP */
16362306a36Sopenharmony_ci	{ .id = "CTL0039", .devs = { { "CTL0031" }, { "CTL0021" } } },
16462306a36Sopenharmony_ci	/* Sound Blaster AWE 32 PnP */
16562306a36Sopenharmony_ci	{ .id = "CTL0042", .devs = { { "CTL0031" }, { "CTL0021" } } },
16662306a36Sopenharmony_ci	/* Sound Blaster AWE 32 PnP */
16762306a36Sopenharmony_ci	{ .id = "CTL0043", .devs = { { "CTL0031" }, { "CTL0021" } } },
16862306a36Sopenharmony_ci	/* Sound Blaster AWE 32 PnP */
16962306a36Sopenharmony_ci	/* Note: This card has also a CTL0051:StereoEnhance device!!! */
17062306a36Sopenharmony_ci	{ .id = "CTL0044", .devs = { { "CTL0031" }, { "CTL0021" } } },
17162306a36Sopenharmony_ci	/* Sound Blaster AWE 32 PnP */
17262306a36Sopenharmony_ci	/* Note: This card has also a CTL0051:StereoEnhance device!!! */
17362306a36Sopenharmony_ci	{ .id = "CTL0045", .devs = { { "CTL0031" }, { "CTL0021" } } },
17462306a36Sopenharmony_ci	/* Sound Blaster AWE 32 PnP */
17562306a36Sopenharmony_ci	{ .id = "CTL0046", .devs = { { "CTL0031" }, { "CTL0021" } } },
17662306a36Sopenharmony_ci	/* Sound Blaster AWE 32 PnP */
17762306a36Sopenharmony_ci	{ .id = "CTL0047", .devs = { { "CTL0031" }, { "CTL0021" } } },
17862306a36Sopenharmony_ci	/* Sound Blaster AWE 32 PnP */
17962306a36Sopenharmony_ci	{ .id = "CTL0048", .devs = { { "CTL0031" }, { "CTL0021" } } },
18062306a36Sopenharmony_ci	/* Sound Blaster AWE 32 PnP */
18162306a36Sopenharmony_ci	{ .id = "CTL0054", .devs = { { "CTL0031" }, { "CTL0021" } } },
18262306a36Sopenharmony_ci	/* Sound Blaster AWE 32 PnP */
18362306a36Sopenharmony_ci	{ .id = "CTL009a", .devs = { { "CTL0041" }, { "CTL0021" } } },
18462306a36Sopenharmony_ci	/* Sound Blaster AWE 32 PnP */
18562306a36Sopenharmony_ci	{ .id = "CTL009c", .devs = { { "CTL0041" }, { "CTL0021" } } },
18662306a36Sopenharmony_ci	/* Sound Blaster 32 PnP */
18762306a36Sopenharmony_ci	{ .id = "CTL009f", .devs = { { "CTL0041" }, { "CTL0021" } } },
18862306a36Sopenharmony_ci	/* Sound Blaster AWE 64 PnP */
18962306a36Sopenharmony_ci	{ .id = "CTL009d", .devs = { { "CTL0042" }, { "CTL0022" } } },
19062306a36Sopenharmony_ci	/* Sound Blaster AWE 64 PnP Gold */
19162306a36Sopenharmony_ci	{ .id = "CTL009e", .devs = { { "CTL0044" }, { "CTL0023" } } },
19262306a36Sopenharmony_ci	/* Sound Blaster AWE 64 PnP Gold */
19362306a36Sopenharmony_ci	{ .id = "CTL00b2", .devs = { { "CTL0044" }, { "CTL0023" } } },
19462306a36Sopenharmony_ci	/* Sound Blaster AWE 64 PnP */
19562306a36Sopenharmony_ci	{ .id = "CTL00c1", .devs = { { "CTL0042" }, { "CTL0022" } } },
19662306a36Sopenharmony_ci	/* Sound Blaster AWE 64 PnP */
19762306a36Sopenharmony_ci	{ .id = "CTL00c3", .devs = { { "CTL0045" }, { "CTL0022" } } },
19862306a36Sopenharmony_ci	/* Sound Blaster AWE 64 PnP */
19962306a36Sopenharmony_ci	{ .id = "CTL00c5", .devs = { { "CTL0045" }, { "CTL0022" } } },
20062306a36Sopenharmony_ci	/* Sound Blaster AWE 64 PnP */
20162306a36Sopenharmony_ci	{ .id = "CTL00c7", .devs = { { "CTL0045" }, { "CTL0022" } } },
20262306a36Sopenharmony_ci	/* Sound Blaster AWE 64 PnP */
20362306a36Sopenharmony_ci	{ .id = "CTL00e4", .devs = { { "CTL0045" }, { "CTL0022" } } },
20462306a36Sopenharmony_ci	/* Sound Blaster AWE 64 PnP */
20562306a36Sopenharmony_ci	{ .id = "CTL00e9", .devs = { { "CTL0045" }, { "CTL0022" } } },
20662306a36Sopenharmony_ci	/* Sound Blaster 16 PnP (AWE) */
20762306a36Sopenharmony_ci	{ .id = "CTL00ed", .devs = { { "CTL0041" }, { "CTL0070" } } },
20862306a36Sopenharmony_ci	/* Generic entries */
20962306a36Sopenharmony_ci	{ .id = "CTLXXXX" , .devs = { { "CTL0031" }, { "CTL0021" } } },
21062306a36Sopenharmony_ci	{ .id = "CTLXXXX" , .devs = { { "CTL0041" }, { "CTL0021" } } },
21162306a36Sopenharmony_ci	{ .id = "CTLXXXX" , .devs = { { "CTL0042" }, { "CTL0022" } } },
21262306a36Sopenharmony_ci	{ .id = "CTLXXXX" , .devs = { { "CTL0044" }, { "CTL0023" } } },
21362306a36Sopenharmony_ci	{ .id = "CTLXXXX" , .devs = { { "CTL0045" }, { "CTL0022" } } },
21462306a36Sopenharmony_ci#endif /* SNDRV_SBAWE */
21562306a36Sopenharmony_ci	{ .id = "", }
21662306a36Sopenharmony_ci};
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pnp_card, snd_sb16_pnpids);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci#endif /* CONFIG_PNP */
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci#ifdef SNDRV_SBAWE_EMU8000
22362306a36Sopenharmony_ci#define DRIVER_NAME	"snd-card-sbawe"
22462306a36Sopenharmony_ci#else
22562306a36Sopenharmony_ci#define DRIVER_NAME	"snd-card-sb16"
22662306a36Sopenharmony_ci#endif
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci#ifdef CONFIG_PNP
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic int snd_card_sb16_pnp(int dev, struct snd_card_sb16 *acard,
23162306a36Sopenharmony_ci			     struct pnp_card_link *card,
23262306a36Sopenharmony_ci			     const struct pnp_card_device_id *id)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	struct pnp_dev *pdev;
23562306a36Sopenharmony_ci	int err;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
23862306a36Sopenharmony_ci	if (acard->dev == NULL)
23962306a36Sopenharmony_ci		return -ENODEV;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci#ifdef SNDRV_SBAWE_EMU8000
24262306a36Sopenharmony_ci	acard->devwt = pnp_request_card_device(card, id->devs[1].id, acard->dev);
24362306a36Sopenharmony_ci#endif
24462306a36Sopenharmony_ci	/* Audio initialization */
24562306a36Sopenharmony_ci	pdev = acard->dev;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	err = pnp_activate_dev(pdev);
24862306a36Sopenharmony_ci	if (err < 0) {
24962306a36Sopenharmony_ci		snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n");
25062306a36Sopenharmony_ci		return err;
25162306a36Sopenharmony_ci	}
25262306a36Sopenharmony_ci	port[dev] = pnp_port_start(pdev, 0);
25362306a36Sopenharmony_ci	mpu_port[dev] = pnp_port_start(pdev, 1);
25462306a36Sopenharmony_ci	fm_port[dev] = pnp_port_start(pdev, 2);
25562306a36Sopenharmony_ci	dma8[dev] = pnp_dma(pdev, 0);
25662306a36Sopenharmony_ci	dma16[dev] = pnp_dma(pdev, 1);
25762306a36Sopenharmony_ci	irq[dev] = pnp_irq(pdev, 0);
25862306a36Sopenharmony_ci	snd_printdd("pnp SB16: port=0x%lx, mpu port=0x%lx, fm port=0x%lx\n",
25962306a36Sopenharmony_ci			port[dev], mpu_port[dev], fm_port[dev]);
26062306a36Sopenharmony_ci	snd_printdd("pnp SB16: dma1=%i, dma2=%i, irq=%i\n",
26162306a36Sopenharmony_ci			dma8[dev], dma16[dev], irq[dev]);
26262306a36Sopenharmony_ci#ifdef SNDRV_SBAWE_EMU8000
26362306a36Sopenharmony_ci	/* WaveTable initialization */
26462306a36Sopenharmony_ci	pdev = acard->devwt;
26562306a36Sopenharmony_ci	if (pdev != NULL) {
26662306a36Sopenharmony_ci		err = pnp_activate_dev(pdev);
26762306a36Sopenharmony_ci		if (err < 0) {
26862306a36Sopenharmony_ci			goto __wt_error;
26962306a36Sopenharmony_ci		}
27062306a36Sopenharmony_ci		awe_port[dev] = pnp_port_start(pdev, 0);
27162306a36Sopenharmony_ci		snd_printdd("pnp SB16: wavetable port=0x%llx\n",
27262306a36Sopenharmony_ci				(unsigned long long)pnp_port_start(pdev, 0));
27362306a36Sopenharmony_ci	} else {
27462306a36Sopenharmony_ci__wt_error:
27562306a36Sopenharmony_ci		if (pdev) {
27662306a36Sopenharmony_ci			pnp_release_card_device(pdev);
27762306a36Sopenharmony_ci			snd_printk(KERN_ERR PFX "WaveTable pnp configure failure\n");
27862306a36Sopenharmony_ci		}
27962306a36Sopenharmony_ci		acard->devwt = NULL;
28062306a36Sopenharmony_ci		awe_port[dev] = -1;
28162306a36Sopenharmony_ci	}
28262306a36Sopenharmony_ci#endif
28362306a36Sopenharmony_ci	return 0;
28462306a36Sopenharmony_ci}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci#endif /* CONFIG_PNP */
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci#ifdef CONFIG_PNP
28962306a36Sopenharmony_ci#define is_isapnp_selected(dev)		isapnp[dev]
29062306a36Sopenharmony_ci#else
29162306a36Sopenharmony_ci#define is_isapnp_selected(dev)		0
29262306a36Sopenharmony_ci#endif
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic int snd_sb16_card_new(struct device *devptr, int dev,
29562306a36Sopenharmony_ci			     struct snd_card **cardp)
29662306a36Sopenharmony_ci{
29762306a36Sopenharmony_ci	struct snd_card *card;
29862306a36Sopenharmony_ci	int err;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	err = snd_devm_card_new(devptr, index[dev], id[dev], THIS_MODULE,
30162306a36Sopenharmony_ci				sizeof(struct snd_card_sb16), &card);
30262306a36Sopenharmony_ci	if (err < 0)
30362306a36Sopenharmony_ci		return err;
30462306a36Sopenharmony_ci	*cardp = card;
30562306a36Sopenharmony_ci	return 0;
30662306a36Sopenharmony_ci}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_cistatic int snd_sb16_probe(struct snd_card *card, int dev)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci	int xirq, xdma8, xdma16;
31162306a36Sopenharmony_ci	struct snd_sb *chip;
31262306a36Sopenharmony_ci	struct snd_card_sb16 *acard = card->private_data;
31362306a36Sopenharmony_ci	struct snd_opl3 *opl3;
31462306a36Sopenharmony_ci	struct snd_hwdep *synth = NULL;
31562306a36Sopenharmony_ci#ifdef CONFIG_SND_SB16_CSP
31662306a36Sopenharmony_ci	struct snd_hwdep *xcsp = NULL;
31762306a36Sopenharmony_ci#endif
31862306a36Sopenharmony_ci	unsigned long flags;
31962306a36Sopenharmony_ci	int err;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	xirq = irq[dev];
32262306a36Sopenharmony_ci	xdma8 = dma8[dev];
32362306a36Sopenharmony_ci	xdma16 = dma16[dev];
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	err = snd_sbdsp_create(card, port[dev], xirq, snd_sb16dsp_interrupt,
32662306a36Sopenharmony_ci			       xdma8, xdma16, SB_HW_AUTO, &chip);
32762306a36Sopenharmony_ci	if (err < 0)
32862306a36Sopenharmony_ci		return err;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	acard->chip = chip;
33162306a36Sopenharmony_ci	if (chip->hardware != SB_HW_16) {
33262306a36Sopenharmony_ci		snd_printk(KERN_ERR PFX "SB 16 chip was not detected at 0x%lx\n", port[dev]);
33362306a36Sopenharmony_ci		return -ENODEV;
33462306a36Sopenharmony_ci	}
33562306a36Sopenharmony_ci	chip->mpu_port = mpu_port[dev];
33662306a36Sopenharmony_ci	if (!is_isapnp_selected(dev)) {
33762306a36Sopenharmony_ci		err = snd_sb16dsp_configure(chip);
33862306a36Sopenharmony_ci		if (err < 0)
33962306a36Sopenharmony_ci			return err;
34062306a36Sopenharmony_ci	}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	err = snd_sb16dsp_pcm(chip, 0);
34362306a36Sopenharmony_ci	if (err < 0)
34462306a36Sopenharmony_ci		return err;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	strcpy(card->driver,
34762306a36Sopenharmony_ci#ifdef SNDRV_SBAWE_EMU8000
34862306a36Sopenharmony_ci			awe_port[dev] > 0 ? "SB AWE" :
34962306a36Sopenharmony_ci#endif
35062306a36Sopenharmony_ci			"SB16");
35162306a36Sopenharmony_ci	strcpy(card->shortname, chip->name);
35262306a36Sopenharmony_ci	sprintf(card->longname, "%s at 0x%lx, irq %i, dma ",
35362306a36Sopenharmony_ci		chip->name,
35462306a36Sopenharmony_ci		chip->port,
35562306a36Sopenharmony_ci		xirq);
35662306a36Sopenharmony_ci	if (xdma8 >= 0)
35762306a36Sopenharmony_ci		sprintf(card->longname + strlen(card->longname), "%d", xdma8);
35862306a36Sopenharmony_ci	if (xdma16 >= 0)
35962306a36Sopenharmony_ci		sprintf(card->longname + strlen(card->longname), "%s%d",
36062306a36Sopenharmony_ci			xdma8 >= 0 ? "&" : "", xdma16);
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) {
36362306a36Sopenharmony_ci		err = snd_mpu401_uart_new(card, 0, MPU401_HW_SB,
36462306a36Sopenharmony_ci					  chip->mpu_port,
36562306a36Sopenharmony_ci					  MPU401_INFO_IRQ_HOOK, -1,
36662306a36Sopenharmony_ci					  &chip->rmidi);
36762306a36Sopenharmony_ci		if (err < 0)
36862306a36Sopenharmony_ci			return err;
36962306a36Sopenharmony_ci		chip->rmidi_callback = snd_mpu401_uart_interrupt;
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci#ifdef SNDRV_SBAWE_EMU8000
37362306a36Sopenharmony_ci	if (awe_port[dev] == SNDRV_AUTO_PORT)
37462306a36Sopenharmony_ci		awe_port[dev] = 0; /* disable */
37562306a36Sopenharmony_ci#endif
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
37862306a36Sopenharmony_ci		if (snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2,
37962306a36Sopenharmony_ci				    OPL3_HW_OPL3,
38062306a36Sopenharmony_ci				    acard->fm_res != NULL || fm_port[dev] == port[dev],
38162306a36Sopenharmony_ci				    &opl3) < 0) {
38262306a36Sopenharmony_ci			snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx\n",
38362306a36Sopenharmony_ci				   fm_port[dev], fm_port[dev] + 2);
38462306a36Sopenharmony_ci		} else {
38562306a36Sopenharmony_ci#ifdef SNDRV_SBAWE_EMU8000
38662306a36Sopenharmony_ci			int seqdev = awe_port[dev] > 0 ? 2 : 1;
38762306a36Sopenharmony_ci#else
38862306a36Sopenharmony_ci			int seqdev = 1;
38962306a36Sopenharmony_ci#endif
39062306a36Sopenharmony_ci			err = snd_opl3_hwdep_new(opl3, 0, seqdev, &synth);
39162306a36Sopenharmony_ci			if (err < 0)
39262306a36Sopenharmony_ci				return err;
39362306a36Sopenharmony_ci		}
39462306a36Sopenharmony_ci	}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	err = snd_sbmixer_new(chip);
39762306a36Sopenharmony_ci	if (err < 0)
39862306a36Sopenharmony_ci		return err;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci#ifdef CONFIG_SND_SB16_CSP
40162306a36Sopenharmony_ci	/* CSP chip on SB16ASP/AWE32 */
40262306a36Sopenharmony_ci	if ((chip->hardware == SB_HW_16) && csp[dev]) {
40362306a36Sopenharmony_ci		snd_sb_csp_new(chip, synth != NULL ? 1 : 0, &xcsp);
40462306a36Sopenharmony_ci		if (xcsp) {
40562306a36Sopenharmony_ci			chip->csp = xcsp->private_data;
40662306a36Sopenharmony_ci			chip->hardware = SB_HW_16CSP;
40762306a36Sopenharmony_ci		} else {
40862306a36Sopenharmony_ci			snd_printk(KERN_INFO PFX "warning - CSP chip not detected on soundcard #%i\n", dev + 1);
40962306a36Sopenharmony_ci		}
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci#endif
41262306a36Sopenharmony_ci#ifdef SNDRV_SBAWE_EMU8000
41362306a36Sopenharmony_ci	if (awe_port[dev] > 0) {
41462306a36Sopenharmony_ci		err = snd_emu8000_new(card, 1, awe_port[dev],
41562306a36Sopenharmony_ci				      seq_ports[dev], NULL);
41662306a36Sopenharmony_ci		if (err < 0) {
41762306a36Sopenharmony_ci			snd_printk(KERN_ERR PFX "fatal error - EMU-8000 synthesizer not detected at 0x%lx\n", awe_port[dev]);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci			return err;
42062306a36Sopenharmony_ci		}
42162306a36Sopenharmony_ci	}
42262306a36Sopenharmony_ci#endif
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	/* setup Mic AGC */
42562306a36Sopenharmony_ci	spin_lock_irqsave(&chip->mixer_lock, flags);
42662306a36Sopenharmony_ci	snd_sbmixer_write(chip, SB_DSP4_MIC_AGC,
42762306a36Sopenharmony_ci		(snd_sbmixer_read(chip, SB_DSP4_MIC_AGC) & 0x01) |
42862306a36Sopenharmony_ci		(mic_agc[dev] ? 0x00 : 0x01));
42962306a36Sopenharmony_ci	spin_unlock_irqrestore(&chip->mixer_lock, flags);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	err = snd_card_register(card);
43262306a36Sopenharmony_ci	if (err < 0)
43362306a36Sopenharmony_ci		return err;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	return 0;
43662306a36Sopenharmony_ci}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci#ifdef CONFIG_PM
43962306a36Sopenharmony_cistatic int snd_sb16_suspend(struct snd_card *card, pm_message_t state)
44062306a36Sopenharmony_ci{
44162306a36Sopenharmony_ci	struct snd_card_sb16 *acard = card->private_data;
44262306a36Sopenharmony_ci	struct snd_sb *chip = acard->chip;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
44562306a36Sopenharmony_ci	snd_sbmixer_suspend(chip);
44662306a36Sopenharmony_ci	return 0;
44762306a36Sopenharmony_ci}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_cistatic int snd_sb16_resume(struct snd_card *card)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	struct snd_card_sb16 *acard = card->private_data;
45262306a36Sopenharmony_ci	struct snd_sb *chip = acard->chip;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	snd_sbdsp_reset(chip);
45562306a36Sopenharmony_ci	snd_sbmixer_resume(chip);
45662306a36Sopenharmony_ci	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
45762306a36Sopenharmony_ci	return 0;
45862306a36Sopenharmony_ci}
45962306a36Sopenharmony_ci#endif
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_cistatic int snd_sb16_isa_probe1(int dev, struct device *pdev)
46262306a36Sopenharmony_ci{
46362306a36Sopenharmony_ci	struct snd_card_sb16 *acard;
46462306a36Sopenharmony_ci	struct snd_card *card;
46562306a36Sopenharmony_ci	int err;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	err = snd_sb16_card_new(pdev, dev, &card);
46862306a36Sopenharmony_ci	if (err < 0)
46962306a36Sopenharmony_ci		return err;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	acard = card->private_data;
47262306a36Sopenharmony_ci	/* non-PnP FM port address is hardwired with base port address */
47362306a36Sopenharmony_ci	fm_port[dev] = port[dev];
47462306a36Sopenharmony_ci	/* block the 0x388 port to avoid PnP conflicts */
47562306a36Sopenharmony_ci	acard->fm_res = devm_request_region(card->dev, 0x388, 4,
47662306a36Sopenharmony_ci					    "SoundBlaster FM");
47762306a36Sopenharmony_ci#ifdef SNDRV_SBAWE_EMU8000
47862306a36Sopenharmony_ci	/* non-PnP AWE port address is hardwired with base port address */
47962306a36Sopenharmony_ci	awe_port[dev] = port[dev] + 0x400;
48062306a36Sopenharmony_ci#endif
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	err = snd_sb16_probe(card, dev);
48362306a36Sopenharmony_ci	if (err < 0)
48462306a36Sopenharmony_ci		return err;
48562306a36Sopenharmony_ci	dev_set_drvdata(pdev, card);
48662306a36Sopenharmony_ci	return 0;
48762306a36Sopenharmony_ci}
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_cistatic int snd_sb16_isa_match(struct device *pdev, unsigned int dev)
49162306a36Sopenharmony_ci{
49262306a36Sopenharmony_ci	return enable[dev] && !is_isapnp_selected(dev);
49362306a36Sopenharmony_ci}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_cistatic int snd_sb16_isa_probe(struct device *pdev, unsigned int dev)
49662306a36Sopenharmony_ci{
49762306a36Sopenharmony_ci	int err;
49862306a36Sopenharmony_ci	static const int possible_irqs[] = {5, 9, 10, 7, -1};
49962306a36Sopenharmony_ci	static const int possible_dmas8[] = {1, 3, 0, -1};
50062306a36Sopenharmony_ci	static const int possible_dmas16[] = {5, 6, 7, -1};
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	if (irq[dev] == SNDRV_AUTO_IRQ) {
50362306a36Sopenharmony_ci		irq[dev] = snd_legacy_find_free_irq(possible_irqs);
50462306a36Sopenharmony_ci		if (irq[dev] < 0) {
50562306a36Sopenharmony_ci			snd_printk(KERN_ERR PFX "unable to find a free IRQ\n");
50662306a36Sopenharmony_ci			return -EBUSY;
50762306a36Sopenharmony_ci		}
50862306a36Sopenharmony_ci	}
50962306a36Sopenharmony_ci	if (dma8[dev] == SNDRV_AUTO_DMA) {
51062306a36Sopenharmony_ci		dma8[dev] = snd_legacy_find_free_dma(possible_dmas8);
51162306a36Sopenharmony_ci		if (dma8[dev] < 0) {
51262306a36Sopenharmony_ci			snd_printk(KERN_ERR PFX "unable to find a free 8-bit DMA\n");
51362306a36Sopenharmony_ci			return -EBUSY;
51462306a36Sopenharmony_ci		}
51562306a36Sopenharmony_ci	}
51662306a36Sopenharmony_ci	if (dma16[dev] == SNDRV_AUTO_DMA) {
51762306a36Sopenharmony_ci		dma16[dev] = snd_legacy_find_free_dma(possible_dmas16);
51862306a36Sopenharmony_ci		if (dma16[dev] < 0) {
51962306a36Sopenharmony_ci			snd_printk(KERN_ERR PFX "unable to find a free 16-bit DMA\n");
52062306a36Sopenharmony_ci			return -EBUSY;
52162306a36Sopenharmony_ci		}
52262306a36Sopenharmony_ci	}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	if (port[dev] != SNDRV_AUTO_PORT)
52562306a36Sopenharmony_ci		return snd_sb16_isa_probe1(dev, pdev);
52662306a36Sopenharmony_ci	else {
52762306a36Sopenharmony_ci		static const int possible_ports[] = {0x220, 0x240, 0x260, 0x280};
52862306a36Sopenharmony_ci		int i;
52962306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(possible_ports); i++) {
53062306a36Sopenharmony_ci			port[dev] = possible_ports[i];
53162306a36Sopenharmony_ci			err = snd_sb16_isa_probe1(dev, pdev);
53262306a36Sopenharmony_ci			if (! err)
53362306a36Sopenharmony_ci				return 0;
53462306a36Sopenharmony_ci		}
53562306a36Sopenharmony_ci		return err;
53662306a36Sopenharmony_ci	}
53762306a36Sopenharmony_ci}
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci#ifdef CONFIG_PM
54062306a36Sopenharmony_cistatic int snd_sb16_isa_suspend(struct device *dev, unsigned int n,
54162306a36Sopenharmony_ci				pm_message_t state)
54262306a36Sopenharmony_ci{
54362306a36Sopenharmony_ci	return snd_sb16_suspend(dev_get_drvdata(dev), state);
54462306a36Sopenharmony_ci}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_cistatic int snd_sb16_isa_resume(struct device *dev, unsigned int n)
54762306a36Sopenharmony_ci{
54862306a36Sopenharmony_ci	return snd_sb16_resume(dev_get_drvdata(dev));
54962306a36Sopenharmony_ci}
55062306a36Sopenharmony_ci#endif
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci#ifdef SNDRV_SBAWE
55362306a36Sopenharmony_ci#define DEV_NAME "sbawe"
55462306a36Sopenharmony_ci#else
55562306a36Sopenharmony_ci#define DEV_NAME "sb16"
55662306a36Sopenharmony_ci#endif
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_cistatic struct isa_driver snd_sb16_isa_driver = {
55962306a36Sopenharmony_ci	.match		= snd_sb16_isa_match,
56062306a36Sopenharmony_ci	.probe		= snd_sb16_isa_probe,
56162306a36Sopenharmony_ci#ifdef CONFIG_PM
56262306a36Sopenharmony_ci	.suspend	= snd_sb16_isa_suspend,
56362306a36Sopenharmony_ci	.resume		= snd_sb16_isa_resume,
56462306a36Sopenharmony_ci#endif
56562306a36Sopenharmony_ci	.driver		= {
56662306a36Sopenharmony_ci		.name	= DEV_NAME
56762306a36Sopenharmony_ci	},
56862306a36Sopenharmony_ci};
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci#ifdef CONFIG_PNP
57262306a36Sopenharmony_cistatic int snd_sb16_pnp_detect(struct pnp_card_link *pcard,
57362306a36Sopenharmony_ci			       const struct pnp_card_device_id *pid)
57462306a36Sopenharmony_ci{
57562306a36Sopenharmony_ci	static int dev;
57662306a36Sopenharmony_ci	struct snd_card *card;
57762306a36Sopenharmony_ci	int res;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	for ( ; dev < SNDRV_CARDS; dev++) {
58062306a36Sopenharmony_ci		if (!enable[dev] || !isapnp[dev])
58162306a36Sopenharmony_ci			continue;
58262306a36Sopenharmony_ci		res = snd_sb16_card_new(&pcard->card->dev, dev, &card);
58362306a36Sopenharmony_ci		if (res < 0)
58462306a36Sopenharmony_ci			return res;
58562306a36Sopenharmony_ci		res = snd_card_sb16_pnp(dev, card->private_data, pcard, pid);
58662306a36Sopenharmony_ci		if (res < 0)
58762306a36Sopenharmony_ci			return res;
58862306a36Sopenharmony_ci		res = snd_sb16_probe(card, dev);
58962306a36Sopenharmony_ci		if (res < 0)
59062306a36Sopenharmony_ci			return res;
59162306a36Sopenharmony_ci		pnp_set_card_drvdata(pcard, card);
59262306a36Sopenharmony_ci		dev++;
59362306a36Sopenharmony_ci		return 0;
59462306a36Sopenharmony_ci	}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	return -ENODEV;
59762306a36Sopenharmony_ci}
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci#ifdef CONFIG_PM
60062306a36Sopenharmony_cistatic int snd_sb16_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state)
60162306a36Sopenharmony_ci{
60262306a36Sopenharmony_ci	return snd_sb16_suspend(pnp_get_card_drvdata(pcard), state);
60362306a36Sopenharmony_ci}
60462306a36Sopenharmony_cistatic int snd_sb16_pnp_resume(struct pnp_card_link *pcard)
60562306a36Sopenharmony_ci{
60662306a36Sopenharmony_ci	return snd_sb16_resume(pnp_get_card_drvdata(pcard));
60762306a36Sopenharmony_ci}
60862306a36Sopenharmony_ci#endif
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_cistatic struct pnp_card_driver sb16_pnpc_driver = {
61162306a36Sopenharmony_ci	.flags = PNP_DRIVER_RES_DISABLE,
61262306a36Sopenharmony_ci#ifdef SNDRV_SBAWE
61362306a36Sopenharmony_ci	.name = "sbawe",
61462306a36Sopenharmony_ci#else
61562306a36Sopenharmony_ci	.name = "sb16",
61662306a36Sopenharmony_ci#endif
61762306a36Sopenharmony_ci	.id_table = snd_sb16_pnpids,
61862306a36Sopenharmony_ci	.probe = snd_sb16_pnp_detect,
61962306a36Sopenharmony_ci#ifdef CONFIG_PM
62062306a36Sopenharmony_ci	.suspend = snd_sb16_pnp_suspend,
62162306a36Sopenharmony_ci	.resume = snd_sb16_pnp_resume,
62262306a36Sopenharmony_ci#endif
62362306a36Sopenharmony_ci};
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci#endif /* CONFIG_PNP */
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_cistatic int __init alsa_card_sb16_init(void)
62862306a36Sopenharmony_ci{
62962306a36Sopenharmony_ci	int err;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	err = isa_register_driver(&snd_sb16_isa_driver, SNDRV_CARDS);
63262306a36Sopenharmony_ci#ifdef CONFIG_PNP
63362306a36Sopenharmony_ci	if (!err)
63462306a36Sopenharmony_ci		isa_registered = 1;
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	err = pnp_register_card_driver(&sb16_pnpc_driver);
63762306a36Sopenharmony_ci	if (!err)
63862306a36Sopenharmony_ci		pnp_registered = 1;
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	if (isa_registered)
64162306a36Sopenharmony_ci		err = 0;
64262306a36Sopenharmony_ci#endif
64362306a36Sopenharmony_ci	return err;
64462306a36Sopenharmony_ci}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_cistatic void __exit alsa_card_sb16_exit(void)
64762306a36Sopenharmony_ci{
64862306a36Sopenharmony_ci#ifdef CONFIG_PNP
64962306a36Sopenharmony_ci	if (pnp_registered)
65062306a36Sopenharmony_ci		pnp_unregister_card_driver(&sb16_pnpc_driver);
65162306a36Sopenharmony_ci	if (isa_registered)
65262306a36Sopenharmony_ci#endif
65362306a36Sopenharmony_ci		isa_unregister_driver(&snd_sb16_isa_driver);
65462306a36Sopenharmony_ci}
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_cimodule_init(alsa_card_sb16_init)
65762306a36Sopenharmony_cimodule_exit(alsa_card_sb16_exit)
658