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