162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Driver for generic CS4232/CS4235/CS4236/CS4236B/CS4237B/CS4238B/CS4239 chips
462306a36Sopenharmony_ci *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/init.h>
862306a36Sopenharmony_ci#include <linux/err.h>
962306a36Sopenharmony_ci#include <linux/isa.h>
1062306a36Sopenharmony_ci#include <linux/pnp.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <sound/core.h>
1362306a36Sopenharmony_ci#include <sound/wss.h>
1462306a36Sopenharmony_ci#include <sound/mpu401.h>
1562306a36Sopenharmony_ci#include <sound/opl3.h>
1662306a36Sopenharmony_ci#include <sound/initval.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ciMODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
1962306a36Sopenharmony_ciMODULE_LICENSE("GPL");
2062306a36Sopenharmony_ciMODULE_DESCRIPTION("Cirrus Logic CS4232-9");
2162306a36Sopenharmony_ciMODULE_ALIAS("snd_cs4232");
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define IDENT "CS4232+"
2462306a36Sopenharmony_ci#define DEV_NAME "cs4232+"
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
2762306a36Sopenharmony_cistatic char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
2862306a36Sopenharmony_cistatic bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
2962306a36Sopenharmony_ci#ifdef CONFIG_PNP
3062306a36Sopenharmony_cistatic bool isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
3162306a36Sopenharmony_ci#endif
3262306a36Sopenharmony_cistatic long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */
3362306a36Sopenharmony_cistatic long cport[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */
3462306a36Sopenharmony_cistatic long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;/* PnP setup */
3562306a36Sopenharmony_cistatic long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */
3662306a36Sopenharmony_cistatic long sb_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;	/* PnP setup */
3762306a36Sopenharmony_cistatic int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* 5,7,9,11,12,15 */
3862306a36Sopenharmony_cistatic int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;	/* 9,11,12,15 */
3962306a36Sopenharmony_cistatic int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* 0,1,3,5,6,7 */
4062306a36Sopenharmony_cistatic int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;	/* 0,1,3,5,6,7 */
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_cimodule_param_array(index, int, NULL, 0444);
4362306a36Sopenharmony_ciMODULE_PARM_DESC(index, "Index value for " IDENT " soundcard.");
4462306a36Sopenharmony_cimodule_param_array(id, charp, NULL, 0444);
4562306a36Sopenharmony_ciMODULE_PARM_DESC(id, "ID string for " IDENT " soundcard.");
4662306a36Sopenharmony_cimodule_param_array(enable, bool, NULL, 0444);
4762306a36Sopenharmony_ciMODULE_PARM_DESC(enable, "Enable " IDENT " soundcard.");
4862306a36Sopenharmony_ci#ifdef CONFIG_PNP
4962306a36Sopenharmony_cimodule_param_array(isapnp, bool, NULL, 0444);
5062306a36Sopenharmony_ciMODULE_PARM_DESC(isapnp, "ISA PnP detection for specified soundcard.");
5162306a36Sopenharmony_ci#endif
5262306a36Sopenharmony_cimodule_param_hw_array(port, long, ioport, NULL, 0444);
5362306a36Sopenharmony_ciMODULE_PARM_DESC(port, "Port # for " IDENT " driver.");
5462306a36Sopenharmony_cimodule_param_hw_array(cport, long, ioport, NULL, 0444);
5562306a36Sopenharmony_ciMODULE_PARM_DESC(cport, "Control port # for " IDENT " driver.");
5662306a36Sopenharmony_cimodule_param_hw_array(mpu_port, long, ioport, NULL, 0444);
5762306a36Sopenharmony_ciMODULE_PARM_DESC(mpu_port, "MPU-401 port # for " IDENT " driver.");
5862306a36Sopenharmony_cimodule_param_hw_array(fm_port, long, ioport, NULL, 0444);
5962306a36Sopenharmony_ciMODULE_PARM_DESC(fm_port, "FM port # for " IDENT " driver.");
6062306a36Sopenharmony_cimodule_param_hw_array(sb_port, long, ioport, NULL, 0444);
6162306a36Sopenharmony_ciMODULE_PARM_DESC(sb_port, "SB port # for " IDENT " driver (optional).");
6262306a36Sopenharmony_cimodule_param_hw_array(irq, int, irq, NULL, 0444);
6362306a36Sopenharmony_ciMODULE_PARM_DESC(irq, "IRQ # for " IDENT " driver.");
6462306a36Sopenharmony_cimodule_param_hw_array(mpu_irq, int, irq, NULL, 0444);
6562306a36Sopenharmony_ciMODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " IDENT " driver.");
6662306a36Sopenharmony_cimodule_param_hw_array(dma1, int, dma, NULL, 0444);
6762306a36Sopenharmony_ciMODULE_PARM_DESC(dma1, "DMA1 # for " IDENT " driver.");
6862306a36Sopenharmony_cimodule_param_hw_array(dma2, int, dma, NULL, 0444);
6962306a36Sopenharmony_ciMODULE_PARM_DESC(dma2, "DMA2 # for " IDENT " driver.");
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci#ifdef CONFIG_PNP
7262306a36Sopenharmony_cistatic int isa_registered;
7362306a36Sopenharmony_cistatic int pnpc_registered;
7462306a36Sopenharmony_cistatic int pnp_registered;
7562306a36Sopenharmony_ci#endif /* CONFIG_PNP */
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistruct snd_card_cs4236 {
7862306a36Sopenharmony_ci	struct snd_wss *chip;
7962306a36Sopenharmony_ci#ifdef CONFIG_PNP
8062306a36Sopenharmony_ci	struct pnp_dev *wss;
8162306a36Sopenharmony_ci	struct pnp_dev *ctrl;
8262306a36Sopenharmony_ci	struct pnp_dev *mpu;
8362306a36Sopenharmony_ci#endif
8462306a36Sopenharmony_ci};
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci#ifdef CONFIG_PNP
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci/*
8962306a36Sopenharmony_ci * PNP BIOS
9062306a36Sopenharmony_ci */
9162306a36Sopenharmony_cistatic const struct pnp_device_id snd_cs423x_pnpbiosids[] = {
9262306a36Sopenharmony_ci	{ .id = "CSC0100" },
9362306a36Sopenharmony_ci	{ .id = "CSC0000" },
9462306a36Sopenharmony_ci	/* Guillemot Turtlebeach something appears to be cs4232 compatible
9562306a36Sopenharmony_ci	 * (untested) */
9662306a36Sopenharmony_ci	{ .id = "GIM0100" },
9762306a36Sopenharmony_ci	{ .id = "" }
9862306a36Sopenharmony_ci};
9962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pnp, snd_cs423x_pnpbiosids);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci#define CS423X_ISAPNP_DRIVER	"cs4232_isapnp"
10262306a36Sopenharmony_cistatic const struct pnp_card_device_id snd_cs423x_pnpids[] = {
10362306a36Sopenharmony_ci	/* Philips PCA70PS */
10462306a36Sopenharmony_ci	{ .id = "CSC0d32", .devs = { { "CSC0000" }, { "CSC0010" }, { "PNPb006" } } },
10562306a36Sopenharmony_ci	/* TerraTec Maestro 32/96 (CS4232) */
10662306a36Sopenharmony_ci	{ .id = "CSC1a32", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
10762306a36Sopenharmony_ci	/* HP Omnibook 5500 onboard */
10862306a36Sopenharmony_ci	{ .id = "CSC4232", .devs = { { "CSC0000" }, { "CSC0002" }, { "CSC0003" } } },
10962306a36Sopenharmony_ci	/* Unnamed CS4236 card (Made in Taiwan) */
11062306a36Sopenharmony_ci	{ .id = "CSC4236", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
11162306a36Sopenharmony_ci	/* Turtle Beach TBS-2000 (CS4232) */
11262306a36Sopenharmony_ci	{ .id = "CSC7532", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSCb006" } } },
11362306a36Sopenharmony_ci	/* Turtle Beach Tropez Plus (CS4232) */
11462306a36Sopenharmony_ci	{ .id = "CSC7632", .devs = { { "CSC0000" }, { "CSC0010" }, { "PNPb006" } } },
11562306a36Sopenharmony_ci	/* SIC CrystalWave 32 (CS4232) */
11662306a36Sopenharmony_ci	{ .id = "CSCf032", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
11762306a36Sopenharmony_ci	/* Netfinity 3000 on-board soundcard */
11862306a36Sopenharmony_ci	{ .id = "CSCe825", .devs = { { "CSC0100" }, { "CSC0110" }, { "CSC010f" } } },
11962306a36Sopenharmony_ci	/* Intel Marlin Spike Motherboard - CS4235 */
12062306a36Sopenharmony_ci	{ .id = "CSC0225", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
12162306a36Sopenharmony_ci	/* Intel Marlin Spike Motherboard (#2) - CS4235 */
12262306a36Sopenharmony_ci	{ .id = "CSC0225", .devs = { { "CSC0100" }, { "CSC0110" }, { "CSC0103" } } },
12362306a36Sopenharmony_ci	/* Unknown Intel mainboard - CS4235 */
12462306a36Sopenharmony_ci	{ .id = "CSC0225", .devs = { { "CSC0100" }, { "CSC0110" } } },
12562306a36Sopenharmony_ci	/* Genius Sound Maker 3DJ - CS4237B */
12662306a36Sopenharmony_ci	{ .id = "CSC0437", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
12762306a36Sopenharmony_ci	/* Digital PC 5000 Onboard - CS4236B */
12862306a36Sopenharmony_ci	{ .id = "CSC0735", .devs = { { "CSC0000" }, { "CSC0010" } } },
12962306a36Sopenharmony_ci	/* some unknown CS4236B */
13062306a36Sopenharmony_ci	{ .id = "CSC0b35", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
13162306a36Sopenharmony_ci	/* Intel PR440FX Onboard sound */
13262306a36Sopenharmony_ci	{ .id = "CSC0b36", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
13362306a36Sopenharmony_ci	/* CS4235 on mainboard without MPU */
13462306a36Sopenharmony_ci	{ .id = "CSC1425", .devs = { { "CSC0100" }, { "CSC0110" } } },
13562306a36Sopenharmony_ci	/* Gateway E1000 Onboard CS4236B */
13662306a36Sopenharmony_ci	{ .id = "CSC1335", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
13762306a36Sopenharmony_ci	/* HP 6330 Onboard sound */
13862306a36Sopenharmony_ci	{ .id = "CSC1525", .devs = { { "CSC0100" }, { "CSC0110" }, { "CSC0103" } } },
13962306a36Sopenharmony_ci	/* Crystal Computer TidalWave128 */
14062306a36Sopenharmony_ci	{ .id = "CSC1e37", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
14162306a36Sopenharmony_ci	/* ACER AW37 - CS4235 */
14262306a36Sopenharmony_ci	{ .id = "CSC4236", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
14362306a36Sopenharmony_ci	/* build-in soundcard in EliteGroup P5TX-LA motherboard - CS4237B */
14462306a36Sopenharmony_ci	{ .id = "CSC4237", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
14562306a36Sopenharmony_ci	/* Crystal 3D - CS4237B */
14662306a36Sopenharmony_ci	{ .id = "CSC4336", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
14762306a36Sopenharmony_ci	/* Typhoon Soundsystem PnP - CS4236B */
14862306a36Sopenharmony_ci	{ .id = "CSC4536", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
14962306a36Sopenharmony_ci	/* Crystal CX4235-XQ3 EP - CS4235 */
15062306a36Sopenharmony_ci	{ .id = "CSC4625", .devs = { { "CSC0100" }, { "CSC0110" }, { "CSC0103" } } },
15162306a36Sopenharmony_ci	/* Crystal Semiconductors CS4237B */
15262306a36Sopenharmony_ci	{ .id = "CSC4637", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
15362306a36Sopenharmony_ci	/* NewClear 3D - CX4237B-XQ3 */
15462306a36Sopenharmony_ci	{ .id = "CSC4837", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
15562306a36Sopenharmony_ci	/* Dell Optiplex GX1 - CS4236B */
15662306a36Sopenharmony_ci	{ .id = "CSC6835", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
15762306a36Sopenharmony_ci	/* Dell P410 motherboard - CS4236B */
15862306a36Sopenharmony_ci	{ .id = "CSC6835", .devs = { { "CSC0000" }, { "CSC0010" } } },
15962306a36Sopenharmony_ci	/* Dell Workstation 400 Onboard - CS4236B */
16062306a36Sopenharmony_ci	{ .id = "CSC6836", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
16162306a36Sopenharmony_ci	/* Turtle Beach Malibu - CS4237B */
16262306a36Sopenharmony_ci	{ .id = "CSC7537", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
16362306a36Sopenharmony_ci	/* CS4235 - onboard */
16462306a36Sopenharmony_ci	{ .id = "CSC8025", .devs = { { "CSC0100" }, { "CSC0110" }, { "CSC0103" } } },
16562306a36Sopenharmony_ci	/* IBM Aptiva 2137 E24 Onboard - CS4237B */
16662306a36Sopenharmony_ci	{ .id = "CSC8037", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
16762306a36Sopenharmony_ci	/* IBM IntelliStation M Pro motherboard */
16862306a36Sopenharmony_ci	{ .id = "CSCc835", .devs = { { "CSC0000" }, { "CSC0010" } } },
16962306a36Sopenharmony_ci	/* Guillemot MaxiSound 16 PnP - CS4236B */
17062306a36Sopenharmony_ci	{ .id = "CSC9836", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
17162306a36Sopenharmony_ci	/* Gallant SC-70P */
17262306a36Sopenharmony_ci	{ .id = "CSC9837", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
17362306a36Sopenharmony_ci	/* Techmakers MF-4236PW */
17462306a36Sopenharmony_ci	{ .id = "CSCa736", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
17562306a36Sopenharmony_ci	/* TerraTec AudioSystem EWS64XL - CS4236B */
17662306a36Sopenharmony_ci	{ .id = "CSCa836", .devs = { { "CSCa800" }, { "CSCa810" }, { "CSCa803" } } },
17762306a36Sopenharmony_ci	/* TerraTec AudioSystem EWS64XL - CS4236B */
17862306a36Sopenharmony_ci	{ .id = "CSCa836", .devs = { { "CSCa800" }, { "CSCa810" } } },
17962306a36Sopenharmony_ci	/* ACER AW37/Pro - CS4235 */
18062306a36Sopenharmony_ci	{ .id = "CSCd925", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
18162306a36Sopenharmony_ci	/* ACER AW35/Pro - CS4237B */
18262306a36Sopenharmony_ci	{ .id = "CSCd937", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
18362306a36Sopenharmony_ci	/* CS4235 without MPU401 */
18462306a36Sopenharmony_ci	{ .id = "CSCe825", .devs = { { "CSC0100" }, { "CSC0110" } } },
18562306a36Sopenharmony_ci	/* Unknown SiS530 - CS4235 */
18662306a36Sopenharmony_ci	{ .id = "CSC4825", .devs = { { "CSC0100" }, { "CSC0110" } } },
18762306a36Sopenharmony_ci	/* IBM IntelliStation M Pro 6898 11U - CS4236B */
18862306a36Sopenharmony_ci	{ .id = "CSCe835", .devs = { { "CSC0000" }, { "CSC0010" } } },
18962306a36Sopenharmony_ci	/* IBM PC 300PL Onboard - CS4236B */
19062306a36Sopenharmony_ci	{ .id = "CSCe836", .devs = { { "CSC0000" }, { "CSC0010" } } },
19162306a36Sopenharmony_ci	/* Some noname CS4236 based card */
19262306a36Sopenharmony_ci	{ .id = "CSCe936", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
19362306a36Sopenharmony_ci	/* CS4236B */
19462306a36Sopenharmony_ci	{ .id = "CSCf235", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
19562306a36Sopenharmony_ci	/* CS4236B */
19662306a36Sopenharmony_ci	{ .id = "CSCf238", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } },
19762306a36Sopenharmony_ci	/* --- */
19862306a36Sopenharmony_ci	{ .id = "" }	/* end */
19962306a36Sopenharmony_ci};
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pnp_card, snd_cs423x_pnpids);
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci/* WSS initialization */
20462306a36Sopenharmony_cistatic int snd_cs423x_pnp_init_wss(int dev, struct pnp_dev *pdev)
20562306a36Sopenharmony_ci{
20662306a36Sopenharmony_ci	if (pnp_activate_dev(pdev) < 0) {
20762306a36Sopenharmony_ci		printk(KERN_ERR IDENT " WSS PnP configure failed for WSS (out of resources?)\n");
20862306a36Sopenharmony_ci		return -EBUSY;
20962306a36Sopenharmony_ci	}
21062306a36Sopenharmony_ci	port[dev] = pnp_port_start(pdev, 0);
21162306a36Sopenharmony_ci	if (fm_port[dev] > 0)
21262306a36Sopenharmony_ci		fm_port[dev] = pnp_port_start(pdev, 1);
21362306a36Sopenharmony_ci	sb_port[dev] = pnp_port_start(pdev, 2);
21462306a36Sopenharmony_ci	irq[dev] = pnp_irq(pdev, 0);
21562306a36Sopenharmony_ci	dma1[dev] = pnp_dma(pdev, 0);
21662306a36Sopenharmony_ci	dma2[dev] = pnp_dma(pdev, 1) == 4 ? -1 : (int)pnp_dma(pdev, 1);
21762306a36Sopenharmony_ci	snd_printdd("isapnp WSS: wss port=0x%lx, fm port=0x%lx, sb port=0x%lx\n",
21862306a36Sopenharmony_ci			port[dev], fm_port[dev], sb_port[dev]);
21962306a36Sopenharmony_ci	snd_printdd("isapnp WSS: irq=%i, dma1=%i, dma2=%i\n",
22062306a36Sopenharmony_ci			irq[dev], dma1[dev], dma2[dev]);
22162306a36Sopenharmony_ci	return 0;
22262306a36Sopenharmony_ci}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci/* CTRL initialization */
22562306a36Sopenharmony_cistatic int snd_cs423x_pnp_init_ctrl(int dev, struct pnp_dev *pdev)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	if (pnp_activate_dev(pdev) < 0) {
22862306a36Sopenharmony_ci		printk(KERN_ERR IDENT " CTRL PnP configure failed for WSS (out of resources?)\n");
22962306a36Sopenharmony_ci		return -EBUSY;
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci	cport[dev] = pnp_port_start(pdev, 0);
23262306a36Sopenharmony_ci	snd_printdd("isapnp CTRL: control port=0x%lx\n", cport[dev]);
23362306a36Sopenharmony_ci	return 0;
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci/* MPU initialization */
23762306a36Sopenharmony_cistatic int snd_cs423x_pnp_init_mpu(int dev, struct pnp_dev *pdev)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci	if (pnp_activate_dev(pdev) < 0) {
24062306a36Sopenharmony_ci		printk(KERN_ERR IDENT " MPU401 PnP configure failed for WSS (out of resources?)\n");
24162306a36Sopenharmony_ci		mpu_port[dev] = SNDRV_AUTO_PORT;
24262306a36Sopenharmony_ci		mpu_irq[dev] = SNDRV_AUTO_IRQ;
24362306a36Sopenharmony_ci	} else {
24462306a36Sopenharmony_ci		mpu_port[dev] = pnp_port_start(pdev, 0);
24562306a36Sopenharmony_ci		if (mpu_irq[dev] >= 0 &&
24662306a36Sopenharmony_ci		    pnp_irq_valid(pdev, 0) &&
24762306a36Sopenharmony_ci		    pnp_irq(pdev, 0) != (resource_size_t)-1) {
24862306a36Sopenharmony_ci			mpu_irq[dev] = pnp_irq(pdev, 0);
24962306a36Sopenharmony_ci		} else {
25062306a36Sopenharmony_ci			mpu_irq[dev] = -1;	/* disable interrupt */
25162306a36Sopenharmony_ci		}
25262306a36Sopenharmony_ci	}
25362306a36Sopenharmony_ci	snd_printdd("isapnp MPU: port=0x%lx, irq=%i\n", mpu_port[dev], mpu_irq[dev]);
25462306a36Sopenharmony_ci	return 0;
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_cistatic int snd_card_cs423x_pnp(int dev, struct snd_card_cs4236 *acard,
25862306a36Sopenharmony_ci			       struct pnp_dev *pdev,
25962306a36Sopenharmony_ci			       struct pnp_dev *cdev)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	acard->wss = pdev;
26262306a36Sopenharmony_ci	if (snd_cs423x_pnp_init_wss(dev, acard->wss) < 0)
26362306a36Sopenharmony_ci		return -EBUSY;
26462306a36Sopenharmony_ci	if (cdev)
26562306a36Sopenharmony_ci		cport[dev] = pnp_port_start(cdev, 0);
26662306a36Sopenharmony_ci	else
26762306a36Sopenharmony_ci		cport[dev] = -1;
26862306a36Sopenharmony_ci	return 0;
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic int snd_card_cs423x_pnpc(int dev, struct snd_card_cs4236 *acard,
27262306a36Sopenharmony_ci				struct pnp_card_link *card,
27362306a36Sopenharmony_ci				const struct pnp_card_device_id *id)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	acard->wss = pnp_request_card_device(card, id->devs[0].id, NULL);
27662306a36Sopenharmony_ci	if (acard->wss == NULL)
27762306a36Sopenharmony_ci		return -EBUSY;
27862306a36Sopenharmony_ci	acard->ctrl = pnp_request_card_device(card, id->devs[1].id, NULL);
27962306a36Sopenharmony_ci	if (acard->ctrl == NULL)
28062306a36Sopenharmony_ci		return -EBUSY;
28162306a36Sopenharmony_ci	if (id->devs[2].id[0]) {
28262306a36Sopenharmony_ci		acard->mpu = pnp_request_card_device(card, id->devs[2].id, NULL);
28362306a36Sopenharmony_ci		if (acard->mpu == NULL)
28462306a36Sopenharmony_ci			return -EBUSY;
28562306a36Sopenharmony_ci	}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	/* WSS initialization */
28862306a36Sopenharmony_ci	if (snd_cs423x_pnp_init_wss(dev, acard->wss) < 0)
28962306a36Sopenharmony_ci		return -EBUSY;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	/* CTRL initialization */
29262306a36Sopenharmony_ci	if (acard->ctrl && cport[dev] > 0) {
29362306a36Sopenharmony_ci		if (snd_cs423x_pnp_init_ctrl(dev, acard->ctrl) < 0)
29462306a36Sopenharmony_ci			return -EBUSY;
29562306a36Sopenharmony_ci	}
29662306a36Sopenharmony_ci	/* MPU initialization */
29762306a36Sopenharmony_ci	if (acard->mpu && mpu_port[dev] > 0) {
29862306a36Sopenharmony_ci		if (snd_cs423x_pnp_init_mpu(dev, acard->mpu) < 0)
29962306a36Sopenharmony_ci			return -EBUSY;
30062306a36Sopenharmony_ci	}
30162306a36Sopenharmony_ci	return 0;
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci#endif /* CONFIG_PNP */
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci#ifdef CONFIG_PNP
30662306a36Sopenharmony_ci#define is_isapnp_selected(dev)		isapnp[dev]
30762306a36Sopenharmony_ci#else
30862306a36Sopenharmony_ci#define is_isapnp_selected(dev)		0
30962306a36Sopenharmony_ci#endif
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic int snd_cs423x_card_new(struct device *pdev, int dev,
31262306a36Sopenharmony_ci			       struct snd_card **cardp)
31362306a36Sopenharmony_ci{
31462306a36Sopenharmony_ci	struct snd_card *card;
31562306a36Sopenharmony_ci	int err;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	err = snd_devm_card_new(pdev, index[dev], id[dev], THIS_MODULE,
31862306a36Sopenharmony_ci				sizeof(struct snd_card_cs4236), &card);
31962306a36Sopenharmony_ci	if (err < 0)
32062306a36Sopenharmony_ci		return err;
32162306a36Sopenharmony_ci	*cardp = card;
32262306a36Sopenharmony_ci	return 0;
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_cistatic int snd_cs423x_probe(struct snd_card *card, int dev)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci	struct snd_card_cs4236 *acard;
32862306a36Sopenharmony_ci	struct snd_wss *chip;
32962306a36Sopenharmony_ci	struct snd_opl3 *opl3;
33062306a36Sopenharmony_ci	int err;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	acard = card->private_data;
33362306a36Sopenharmony_ci	if (sb_port[dev] > 0 && sb_port[dev] != SNDRV_AUTO_PORT) {
33462306a36Sopenharmony_ci		if (!devm_request_region(card->dev, sb_port[dev], 16,
33562306a36Sopenharmony_ci					 IDENT " SB")) {
33662306a36Sopenharmony_ci			printk(KERN_ERR IDENT ": unable to register SB port at 0x%lx\n", sb_port[dev]);
33762306a36Sopenharmony_ci			return -EBUSY;
33862306a36Sopenharmony_ci		}
33962306a36Sopenharmony_ci	}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	err = snd_cs4236_create(card, port[dev], cport[dev],
34262306a36Sopenharmony_ci			     irq[dev],
34362306a36Sopenharmony_ci			     dma1[dev], dma2[dev],
34462306a36Sopenharmony_ci			     WSS_HW_DETECT3, 0, &chip);
34562306a36Sopenharmony_ci	if (err < 0)
34662306a36Sopenharmony_ci		return err;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	acard->chip = chip;
34962306a36Sopenharmony_ci	if (chip->hardware & WSS_HW_CS4236B_MASK) {
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci		err = snd_cs4236_pcm(chip, 0);
35262306a36Sopenharmony_ci		if (err < 0)
35362306a36Sopenharmony_ci			return err;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci		err = snd_cs4236_mixer(chip);
35662306a36Sopenharmony_ci		if (err < 0)
35762306a36Sopenharmony_ci			return err;
35862306a36Sopenharmony_ci	} else {
35962306a36Sopenharmony_ci		err = snd_wss_pcm(chip, 0);
36062306a36Sopenharmony_ci		if (err < 0)
36162306a36Sopenharmony_ci			return err;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci		err = snd_wss_mixer(chip);
36462306a36Sopenharmony_ci		if (err < 0)
36562306a36Sopenharmony_ci			return err;
36662306a36Sopenharmony_ci	}
36762306a36Sopenharmony_ci	strscpy(card->driver, chip->pcm->name, sizeof(card->driver));
36862306a36Sopenharmony_ci	strscpy(card->shortname, chip->pcm->name, sizeof(card->shortname));
36962306a36Sopenharmony_ci	if (dma2[dev] < 0)
37062306a36Sopenharmony_ci		scnprintf(card->longname, sizeof(card->longname),
37162306a36Sopenharmony_ci			  "%s at 0x%lx, irq %i, dma %i",
37262306a36Sopenharmony_ci			  chip->pcm->name, chip->port, irq[dev], dma1[dev]);
37362306a36Sopenharmony_ci	else
37462306a36Sopenharmony_ci		scnprintf(card->longname, sizeof(card->longname),
37562306a36Sopenharmony_ci			  "%s at 0x%lx, irq %i, dma %i&%d",
37662306a36Sopenharmony_ci			  chip->pcm->name, chip->port, irq[dev], dma1[dev],
37762306a36Sopenharmony_ci			  dma2[dev]);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	err = snd_wss_timer(chip, 0);
38062306a36Sopenharmony_ci	if (err < 0)
38162306a36Sopenharmony_ci		return err;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
38462306a36Sopenharmony_ci		if (snd_opl3_create(card,
38562306a36Sopenharmony_ci				    fm_port[dev], fm_port[dev] + 2,
38662306a36Sopenharmony_ci				    OPL3_HW_OPL3_CS, 0, &opl3) < 0) {
38762306a36Sopenharmony_ci			printk(KERN_WARNING IDENT ": OPL3 not detected\n");
38862306a36Sopenharmony_ci		} else {
38962306a36Sopenharmony_ci			err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
39062306a36Sopenharmony_ci			if (err < 0)
39162306a36Sopenharmony_ci				return err;
39262306a36Sopenharmony_ci		}
39362306a36Sopenharmony_ci	}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
39662306a36Sopenharmony_ci		if (mpu_irq[dev] == SNDRV_AUTO_IRQ)
39762306a36Sopenharmony_ci			mpu_irq[dev] = -1;
39862306a36Sopenharmony_ci		if (snd_mpu401_uart_new(card, 0, MPU401_HW_CS4232,
39962306a36Sopenharmony_ci					mpu_port[dev], 0,
40062306a36Sopenharmony_ci					mpu_irq[dev], NULL) < 0)
40162306a36Sopenharmony_ci			printk(KERN_WARNING IDENT ": MPU401 not detected\n");
40262306a36Sopenharmony_ci	}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	return snd_card_register(card);
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_cistatic int snd_cs423x_isa_match(struct device *pdev,
40862306a36Sopenharmony_ci				unsigned int dev)
40962306a36Sopenharmony_ci{
41062306a36Sopenharmony_ci	if (!enable[dev] || is_isapnp_selected(dev))
41162306a36Sopenharmony_ci		return 0;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	if (port[dev] == SNDRV_AUTO_PORT) {
41462306a36Sopenharmony_ci		dev_err(pdev, "please specify port\n");
41562306a36Sopenharmony_ci		return 0;
41662306a36Sopenharmony_ci	}
41762306a36Sopenharmony_ci	if (cport[dev] == SNDRV_AUTO_PORT) {
41862306a36Sopenharmony_ci		dev_err(pdev, "please specify cport\n");
41962306a36Sopenharmony_ci		return 0;
42062306a36Sopenharmony_ci	}
42162306a36Sopenharmony_ci	if (irq[dev] == SNDRV_AUTO_IRQ) {
42262306a36Sopenharmony_ci		dev_err(pdev, "please specify irq\n");
42362306a36Sopenharmony_ci		return 0;
42462306a36Sopenharmony_ci	}
42562306a36Sopenharmony_ci	if (dma1[dev] == SNDRV_AUTO_DMA) {
42662306a36Sopenharmony_ci		dev_err(pdev, "please specify dma1\n");
42762306a36Sopenharmony_ci		return 0;
42862306a36Sopenharmony_ci	}
42962306a36Sopenharmony_ci	return 1;
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_cistatic int snd_cs423x_isa_probe(struct device *pdev,
43362306a36Sopenharmony_ci				unsigned int dev)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	struct snd_card *card;
43662306a36Sopenharmony_ci	int err;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	err = snd_cs423x_card_new(pdev, dev, &card);
43962306a36Sopenharmony_ci	if (err < 0)
44062306a36Sopenharmony_ci		return err;
44162306a36Sopenharmony_ci	err = snd_cs423x_probe(card, dev);
44262306a36Sopenharmony_ci	if (err < 0)
44362306a36Sopenharmony_ci		return err;
44462306a36Sopenharmony_ci	dev_set_drvdata(pdev, card);
44562306a36Sopenharmony_ci	return 0;
44662306a36Sopenharmony_ci}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci#ifdef CONFIG_PM
44962306a36Sopenharmony_cistatic int snd_cs423x_suspend(struct snd_card *card)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	struct snd_card_cs4236 *acard = card->private_data;
45262306a36Sopenharmony_ci	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
45362306a36Sopenharmony_ci	acard->chip->suspend(acard->chip);
45462306a36Sopenharmony_ci	return 0;
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_cistatic int snd_cs423x_resume(struct snd_card *card)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	struct snd_card_cs4236 *acard = card->private_data;
46062306a36Sopenharmony_ci	acard->chip->resume(acard->chip);
46162306a36Sopenharmony_ci	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
46262306a36Sopenharmony_ci	return 0;
46362306a36Sopenharmony_ci}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_cistatic int snd_cs423x_isa_suspend(struct device *dev, unsigned int n,
46662306a36Sopenharmony_ci				  pm_message_t state)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	return snd_cs423x_suspend(dev_get_drvdata(dev));
46962306a36Sopenharmony_ci}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_cistatic int snd_cs423x_isa_resume(struct device *dev, unsigned int n)
47262306a36Sopenharmony_ci{
47362306a36Sopenharmony_ci	return snd_cs423x_resume(dev_get_drvdata(dev));
47462306a36Sopenharmony_ci}
47562306a36Sopenharmony_ci#endif
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_cistatic struct isa_driver cs423x_isa_driver = {
47862306a36Sopenharmony_ci	.match		= snd_cs423x_isa_match,
47962306a36Sopenharmony_ci	.probe		= snd_cs423x_isa_probe,
48062306a36Sopenharmony_ci#ifdef CONFIG_PM
48162306a36Sopenharmony_ci	.suspend	= snd_cs423x_isa_suspend,
48262306a36Sopenharmony_ci	.resume		= snd_cs423x_isa_resume,
48362306a36Sopenharmony_ci#endif
48462306a36Sopenharmony_ci	.driver		= {
48562306a36Sopenharmony_ci		.name	= DEV_NAME
48662306a36Sopenharmony_ci	},
48762306a36Sopenharmony_ci};
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci#ifdef CONFIG_PNP
49162306a36Sopenharmony_cistatic int snd_cs423x_pnpbios_detect(struct pnp_dev *pdev,
49262306a36Sopenharmony_ci				     const struct pnp_device_id *id)
49362306a36Sopenharmony_ci{
49462306a36Sopenharmony_ci	static int dev;
49562306a36Sopenharmony_ci	int err;
49662306a36Sopenharmony_ci	struct snd_card *card;
49762306a36Sopenharmony_ci	struct pnp_dev *cdev, *iter;
49862306a36Sopenharmony_ci	char cid[PNP_ID_LEN];
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	if (pnp_device_is_isapnp(pdev))
50162306a36Sopenharmony_ci		return -ENOENT;	/* we have another procedure - card */
50262306a36Sopenharmony_ci	for (; dev < SNDRV_CARDS; dev++) {
50362306a36Sopenharmony_ci		if (enable[dev] && isapnp[dev])
50462306a36Sopenharmony_ci			break;
50562306a36Sopenharmony_ci	}
50662306a36Sopenharmony_ci	if (dev >= SNDRV_CARDS)
50762306a36Sopenharmony_ci		return -ENODEV;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	/* prepare second id */
51062306a36Sopenharmony_ci	strcpy(cid, pdev->id[0].id);
51162306a36Sopenharmony_ci	cid[5] = '1';
51262306a36Sopenharmony_ci	cdev = NULL;
51362306a36Sopenharmony_ci	list_for_each_entry(iter, &(pdev->protocol->devices), protocol_list) {
51462306a36Sopenharmony_ci		if (!strcmp(iter->id[0].id, cid)) {
51562306a36Sopenharmony_ci			cdev = iter;
51662306a36Sopenharmony_ci			break;
51762306a36Sopenharmony_ci		}
51862306a36Sopenharmony_ci	}
51962306a36Sopenharmony_ci	err = snd_cs423x_card_new(&pdev->dev, dev, &card);
52062306a36Sopenharmony_ci	if (err < 0)
52162306a36Sopenharmony_ci		return err;
52262306a36Sopenharmony_ci	err = snd_card_cs423x_pnp(dev, card->private_data, pdev, cdev);
52362306a36Sopenharmony_ci	if (err < 0) {
52462306a36Sopenharmony_ci		printk(KERN_ERR "PnP BIOS detection failed for " IDENT "\n");
52562306a36Sopenharmony_ci		return err;
52662306a36Sopenharmony_ci	}
52762306a36Sopenharmony_ci	err = snd_cs423x_probe(card, dev);
52862306a36Sopenharmony_ci	if (err < 0)
52962306a36Sopenharmony_ci		return err;
53062306a36Sopenharmony_ci	pnp_set_drvdata(pdev, card);
53162306a36Sopenharmony_ci	dev++;
53262306a36Sopenharmony_ci	return 0;
53362306a36Sopenharmony_ci}
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci#ifdef CONFIG_PM
53662306a36Sopenharmony_cistatic int snd_cs423x_pnp_suspend(struct pnp_dev *pdev, pm_message_t state)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	return snd_cs423x_suspend(pnp_get_drvdata(pdev));
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cistatic int snd_cs423x_pnp_resume(struct pnp_dev *pdev)
54262306a36Sopenharmony_ci{
54362306a36Sopenharmony_ci	return snd_cs423x_resume(pnp_get_drvdata(pdev));
54462306a36Sopenharmony_ci}
54562306a36Sopenharmony_ci#endif
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_cistatic struct pnp_driver cs423x_pnp_driver = {
54862306a36Sopenharmony_ci	.name = "cs423x-pnpbios",
54962306a36Sopenharmony_ci	.id_table = snd_cs423x_pnpbiosids,
55062306a36Sopenharmony_ci	.probe = snd_cs423x_pnpbios_detect,
55162306a36Sopenharmony_ci#ifdef CONFIG_PM
55262306a36Sopenharmony_ci	.suspend	= snd_cs423x_pnp_suspend,
55362306a36Sopenharmony_ci	.resume		= snd_cs423x_pnp_resume,
55462306a36Sopenharmony_ci#endif
55562306a36Sopenharmony_ci};
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_cistatic int snd_cs423x_pnpc_detect(struct pnp_card_link *pcard,
55862306a36Sopenharmony_ci				  const struct pnp_card_device_id *pid)
55962306a36Sopenharmony_ci{
56062306a36Sopenharmony_ci	static int dev;
56162306a36Sopenharmony_ci	struct snd_card *card;
56262306a36Sopenharmony_ci	int res;
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	for ( ; dev < SNDRV_CARDS; dev++) {
56562306a36Sopenharmony_ci		if (enable[dev] && isapnp[dev])
56662306a36Sopenharmony_ci			break;
56762306a36Sopenharmony_ci	}
56862306a36Sopenharmony_ci	if (dev >= SNDRV_CARDS)
56962306a36Sopenharmony_ci		return -ENODEV;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	res = snd_cs423x_card_new(&pcard->card->dev, dev, &card);
57262306a36Sopenharmony_ci	if (res < 0)
57362306a36Sopenharmony_ci		return res;
57462306a36Sopenharmony_ci	res = snd_card_cs423x_pnpc(dev, card->private_data, pcard, pid);
57562306a36Sopenharmony_ci	if (res < 0) {
57662306a36Sopenharmony_ci		printk(KERN_ERR "isapnp detection failed and probing for " IDENT
57762306a36Sopenharmony_ci		       " is not supported\n");
57862306a36Sopenharmony_ci		return res;
57962306a36Sopenharmony_ci	}
58062306a36Sopenharmony_ci	res = snd_cs423x_probe(card, dev);
58162306a36Sopenharmony_ci	if (res < 0)
58262306a36Sopenharmony_ci		return res;
58362306a36Sopenharmony_ci	pnp_set_card_drvdata(pcard, card);
58462306a36Sopenharmony_ci	dev++;
58562306a36Sopenharmony_ci	return 0;
58662306a36Sopenharmony_ci}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci#ifdef CONFIG_PM
58962306a36Sopenharmony_cistatic int snd_cs423x_pnpc_suspend(struct pnp_card_link *pcard, pm_message_t state)
59062306a36Sopenharmony_ci{
59162306a36Sopenharmony_ci	return snd_cs423x_suspend(pnp_get_card_drvdata(pcard));
59262306a36Sopenharmony_ci}
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_cistatic int snd_cs423x_pnpc_resume(struct pnp_card_link *pcard)
59562306a36Sopenharmony_ci{
59662306a36Sopenharmony_ci	return snd_cs423x_resume(pnp_get_card_drvdata(pcard));
59762306a36Sopenharmony_ci}
59862306a36Sopenharmony_ci#endif
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_cistatic struct pnp_card_driver cs423x_pnpc_driver = {
60162306a36Sopenharmony_ci	.flags = PNP_DRIVER_RES_DISABLE,
60262306a36Sopenharmony_ci	.name = CS423X_ISAPNP_DRIVER,
60362306a36Sopenharmony_ci	.id_table = snd_cs423x_pnpids,
60462306a36Sopenharmony_ci	.probe = snd_cs423x_pnpc_detect,
60562306a36Sopenharmony_ci#ifdef CONFIG_PM
60662306a36Sopenharmony_ci	.suspend	= snd_cs423x_pnpc_suspend,
60762306a36Sopenharmony_ci	.resume		= snd_cs423x_pnpc_resume,
60862306a36Sopenharmony_ci#endif
60962306a36Sopenharmony_ci};
61062306a36Sopenharmony_ci#endif /* CONFIG_PNP */
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_cistatic int __init alsa_card_cs423x_init(void)
61362306a36Sopenharmony_ci{
61462306a36Sopenharmony_ci	int err;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	err = isa_register_driver(&cs423x_isa_driver, SNDRV_CARDS);
61762306a36Sopenharmony_ci#ifdef CONFIG_PNP
61862306a36Sopenharmony_ci	if (!err)
61962306a36Sopenharmony_ci		isa_registered = 1;
62062306a36Sopenharmony_ci	err = pnp_register_driver(&cs423x_pnp_driver);
62162306a36Sopenharmony_ci	if (!err)
62262306a36Sopenharmony_ci		pnp_registered = 1;
62362306a36Sopenharmony_ci	err = pnp_register_card_driver(&cs423x_pnpc_driver);
62462306a36Sopenharmony_ci	if (!err)
62562306a36Sopenharmony_ci		pnpc_registered = 1;
62662306a36Sopenharmony_ci	if (pnp_registered)
62762306a36Sopenharmony_ci		err = 0;
62862306a36Sopenharmony_ci	if (isa_registered)
62962306a36Sopenharmony_ci		err = 0;
63062306a36Sopenharmony_ci#endif
63162306a36Sopenharmony_ci	return err;
63262306a36Sopenharmony_ci}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_cistatic void __exit alsa_card_cs423x_exit(void)
63562306a36Sopenharmony_ci{
63662306a36Sopenharmony_ci#ifdef CONFIG_PNP
63762306a36Sopenharmony_ci	if (pnpc_registered)
63862306a36Sopenharmony_ci		pnp_unregister_card_driver(&cs423x_pnpc_driver);
63962306a36Sopenharmony_ci	if (pnp_registered)
64062306a36Sopenharmony_ci		pnp_unregister_driver(&cs423x_pnp_driver);
64162306a36Sopenharmony_ci	if (isa_registered)
64262306a36Sopenharmony_ci#endif
64362306a36Sopenharmony_ci		isa_unregister_driver(&cs423x_isa_driver);
64462306a36Sopenharmony_ci}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_cimodule_init(alsa_card_cs423x_init)
64762306a36Sopenharmony_cimodule_exit(alsa_card_cs423x_exit)
648