11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Driver for SoundBlaster 16/AWE32/AWE64 soundcards 3c1017a4cSJaroslav Kysela * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 71da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 81da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 91da177e4SLinus Torvalds * (at your option) any later version. 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 121da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 131da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 141da177e4SLinus Torvalds * GNU General Public License for more details. 151da177e4SLinus Torvalds * 161da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 171da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 181da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 191da177e4SLinus Torvalds * 201da177e4SLinus Torvalds */ 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds #include <asm/dma.h> 231da177e4SLinus Torvalds #include <linux/init.h> 241da177e4SLinus Torvalds #include <linux/pnp.h> 256f045616STakashi Iwai #include <linux/err.h> 265e24c1c1STakashi Iwai #include <linux/isa.h> 2765a77217SPaul Gortmaker #include <linux/module.h> 281da177e4SLinus Torvalds #include <sound/core.h> 291da177e4SLinus Torvalds #include <sound/sb.h> 301da177e4SLinus Torvalds #include <sound/sb16_csp.h> 311da177e4SLinus Torvalds #include <sound/mpu401.h> 321da177e4SLinus Torvalds #include <sound/opl3.h> 331da177e4SLinus Torvalds #include <sound/emu8000.h> 341da177e4SLinus Torvalds #include <sound/seq_device.h> 351da177e4SLinus Torvalds #define SNDRV_LEGACY_FIND_FREE_IRQ 361da177e4SLinus Torvalds #define SNDRV_LEGACY_FIND_FREE_DMA 371da177e4SLinus Torvalds #include <sound/initval.h> 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds #ifdef SNDRV_SBAWE 401da177e4SLinus Torvalds #define PFX "sbawe: " 411da177e4SLinus Torvalds #else 421da177e4SLinus Torvalds #define PFX "sb16: " 431da177e4SLinus Torvalds #endif 441da177e4SLinus Torvalds 45c1017a4cSJaroslav Kysela MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); 461da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 471da177e4SLinus Torvalds #ifndef SNDRV_SBAWE 481da177e4SLinus Torvalds MODULE_DESCRIPTION("Sound Blaster 16"); 491da177e4SLinus Torvalds MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB 16}," 501da177e4SLinus Torvalds "{Creative Labs,SB Vibra16S}," 511da177e4SLinus Torvalds "{Creative Labs,SB Vibra16C}," 521da177e4SLinus Torvalds "{Creative Labs,SB Vibra16CL}," 531da177e4SLinus Torvalds "{Creative Labs,SB Vibra16X}}"); 541da177e4SLinus Torvalds #else 551da177e4SLinus Torvalds MODULE_DESCRIPTION("Sound Blaster AWE"); 561da177e4SLinus Torvalds MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB AWE 32}," 571da177e4SLinus Torvalds "{Creative Labs,SB AWE 64}," 581da177e4SLinus Torvalds "{Creative Labs,SB AWE 64 Gold}}"); 591da177e4SLinus Torvalds #endif 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds #if 0 621da177e4SLinus Torvalds #define SNDRV_DEBUG_IRQ 631da177e4SLinus Torvalds #endif 641da177e4SLinus Torvalds 65111b0cdbSTakashi Iwai #if defined(SNDRV_SBAWE) && IS_ENABLED(CONFIG_SND_SEQUENCER) 661da177e4SLinus Torvalds #define SNDRV_SBAWE_EMU8000 671da177e4SLinus Torvalds #endif 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ 701da177e4SLinus Torvalds static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ 71a67ff6a5SRusty Russell static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */ 721da177e4SLinus Torvalds #ifdef CONFIG_PNP 73a67ff6a5SRusty Russell static bool isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; 741da177e4SLinus Torvalds #endif 751da177e4SLinus Torvalds static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240,0x260,0x280 */ 761da177e4SLinus Torvalds static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x330,0x300 */ 771da177e4SLinus Torvalds static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; 781da177e4SLinus Torvalds #ifdef SNDRV_SBAWE_EMU8000 791da177e4SLinus Torvalds static long awe_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; 801da177e4SLinus Torvalds #endif 811da177e4SLinus Torvalds static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5,7,9,10 */ 821da177e4SLinus Torvalds static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3 */ 831da177e4SLinus Torvalds static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 5,6,7 */ 841da177e4SLinus Torvalds static int mic_agc[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; 851da177e4SLinus Torvalds #ifdef CONFIG_SND_SB16_CSP 866581f4e7STakashi Iwai static int csp[SNDRV_CARDS]; 871da177e4SLinus Torvalds #endif 881da177e4SLinus Torvalds #ifdef SNDRV_SBAWE_EMU8000 891da177e4SLinus Torvalds static int seq_ports[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 4}; 901da177e4SLinus Torvalds #endif 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds module_param_array(index, int, NULL, 0444); 931da177e4SLinus Torvalds MODULE_PARM_DESC(index, "Index value for SoundBlaster 16 soundcard."); 941da177e4SLinus Torvalds module_param_array(id, charp, NULL, 0444); 951da177e4SLinus Torvalds MODULE_PARM_DESC(id, "ID string for SoundBlaster 16 soundcard."); 961da177e4SLinus Torvalds module_param_array(enable, bool, NULL, 0444); 971da177e4SLinus Torvalds MODULE_PARM_DESC(enable, "Enable SoundBlaster 16 soundcard."); 981da177e4SLinus Torvalds #ifdef CONFIG_PNP 991da177e4SLinus Torvalds module_param_array(isapnp, bool, NULL, 0444); 1001da177e4SLinus Torvalds MODULE_PARM_DESC(isapnp, "PnP detection for specified soundcard."); 1011da177e4SLinus Torvalds #endif 102e992ef57SDavid Howells module_param_hw_array(port, long, ioport, NULL, 0444); 1031da177e4SLinus Torvalds MODULE_PARM_DESC(port, "Port # for SB16 driver."); 104e992ef57SDavid Howells module_param_hw_array(mpu_port, long, ioport, NULL, 0444); 1051da177e4SLinus Torvalds MODULE_PARM_DESC(mpu_port, "MPU-401 port # for SB16 driver."); 106e992ef57SDavid Howells module_param_hw_array(fm_port, long, ioport, NULL, 0444); 1071da177e4SLinus Torvalds MODULE_PARM_DESC(fm_port, "FM port # for SB16 PnP driver."); 1081da177e4SLinus Torvalds #ifdef SNDRV_SBAWE_EMU8000 109e992ef57SDavid Howells module_param_hw_array(awe_port, long, ioport, NULL, 0444); 1101da177e4SLinus Torvalds MODULE_PARM_DESC(awe_port, "AWE port # for SB16 PnP driver."); 1111da177e4SLinus Torvalds #endif 112e992ef57SDavid Howells module_param_hw_array(irq, int, irq, NULL, 0444); 1131da177e4SLinus Torvalds MODULE_PARM_DESC(irq, "IRQ # for SB16 driver."); 114e992ef57SDavid Howells module_param_hw_array(dma8, int, dma, NULL, 0444); 1151da177e4SLinus Torvalds MODULE_PARM_DESC(dma8, "8-bit DMA # for SB16 driver."); 116e992ef57SDavid Howells module_param_hw_array(dma16, int, dma, NULL, 0444); 1171da177e4SLinus Torvalds MODULE_PARM_DESC(dma16, "16-bit DMA # for SB16 driver."); 1181da177e4SLinus Torvalds module_param_array(mic_agc, int, NULL, 0444); 1191da177e4SLinus Torvalds MODULE_PARM_DESC(mic_agc, "Mic Auto-Gain-Control switch."); 1201da177e4SLinus Torvalds #ifdef CONFIG_SND_SB16_CSP 1211da177e4SLinus Torvalds module_param_array(csp, int, NULL, 0444); 1221da177e4SLinus Torvalds MODULE_PARM_DESC(csp, "ASP/CSP chip support."); 1231da177e4SLinus Torvalds #endif 1241da177e4SLinus Torvalds #ifdef SNDRV_SBAWE_EMU8000 1251da177e4SLinus Torvalds module_param_array(seq_ports, int, NULL, 0444); 1261da177e4SLinus Torvalds MODULE_PARM_DESC(seq_ports, "Number of sequencer ports for WaveTable synth."); 1271da177e4SLinus Torvalds #endif 1281da177e4SLinus Torvalds 129f7a9275dSClemens Ladisch #ifdef CONFIG_PNP 130609d7694SRene Herman static int isa_registered; 131f7a9275dSClemens Ladisch static int pnp_registered; 132f7a9275dSClemens Ladisch #endif 133f7a9275dSClemens Ladisch 1341da177e4SLinus Torvalds struct snd_card_sb16 { 1351da177e4SLinus Torvalds struct resource *fm_res; /* used to block FM i/o region for legacy cards */ 1366f045616STakashi Iwai struct snd_sb *chip; 1371da177e4SLinus Torvalds #ifdef CONFIG_PNP 1381da177e4SLinus Torvalds int dev_no; 1391da177e4SLinus Torvalds struct pnp_dev *dev; 1401da177e4SLinus Torvalds #ifdef SNDRV_SBAWE_EMU8000 1411da177e4SLinus Torvalds struct pnp_dev *devwt; 1421da177e4SLinus Torvalds #endif 1431da177e4SLinus Torvalds #endif 1441da177e4SLinus Torvalds }; 1451da177e4SLinus Torvalds 1461da177e4SLinus Torvalds #ifdef CONFIG_PNP 1471da177e4SLinus Torvalds 148*e6a76e2fSArvind Yadav static const struct pnp_card_device_id snd_sb16_pnpids[] = { 1491da177e4SLinus Torvalds #ifndef SNDRV_SBAWE 1501da177e4SLinus Torvalds /* Sound Blaster 16 PnP */ 1511da177e4SLinus Torvalds { .id = "CTL0024", .devs = { { "CTL0031" } } }, 1521da177e4SLinus Torvalds /* Sound Blaster 16 PnP */ 1531da177e4SLinus Torvalds { .id = "CTL0025", .devs = { { "CTL0031" } } }, 1541da177e4SLinus Torvalds /* Sound Blaster 16 PnP */ 1551da177e4SLinus Torvalds { .id = "CTL0026", .devs = { { "CTL0031" } } }, 1561da177e4SLinus Torvalds /* Sound Blaster 16 PnP */ 1571da177e4SLinus Torvalds { .id = "CTL0027", .devs = { { "CTL0031" } } }, 1581da177e4SLinus Torvalds /* Sound Blaster 16 PnP */ 1591da177e4SLinus Torvalds { .id = "CTL0028", .devs = { { "CTL0031" } } }, 1601da177e4SLinus Torvalds /* Sound Blaster 16 PnP */ 1611da177e4SLinus Torvalds { .id = "CTL0029", .devs = { { "CTL0031" } } }, 1621da177e4SLinus Torvalds /* Sound Blaster 16 PnP */ 1631da177e4SLinus Torvalds { .id = "CTL002a", .devs = { { "CTL0031" } } }, 1641da177e4SLinus Torvalds /* Sound Blaster 16 PnP */ 1651da177e4SLinus Torvalds /* Note: This card has also a CTL0051:StereoEnhance device!!! */ 1661da177e4SLinus Torvalds { .id = "CTL002b", .devs = { { "CTL0031" } } }, 1671da177e4SLinus Torvalds /* Sound Blaster 16 PnP */ 1681da177e4SLinus Torvalds { .id = "CTL002c", .devs = { { "CTL0031" } } }, 1691da177e4SLinus Torvalds /* Sound Blaster Vibra16S */ 1701da177e4SLinus Torvalds { .id = "CTL0051", .devs = { { "CTL0001" } } }, 1711da177e4SLinus Torvalds /* Sound Blaster Vibra16C */ 1721da177e4SLinus Torvalds { .id = "CTL0070", .devs = { { "CTL0001" } } }, 1731da177e4SLinus Torvalds /* Sound Blaster Vibra16CL - added by ctm@ardi.com */ 1741da177e4SLinus Torvalds { .id = "CTL0080", .devs = { { "CTL0041" } } }, 1751da177e4SLinus Torvalds /* Sound Blaster 16 'value' PnP. It says model ct4130 on the pcb, */ 1761da177e4SLinus Torvalds /* but ct4131 on a sticker on the board.. */ 1771da177e4SLinus Torvalds { .id = "CTL0086", .devs = { { "CTL0041" } } }, 1781da177e4SLinus Torvalds /* Sound Blaster Vibra16X */ 1791da177e4SLinus Torvalds { .id = "CTL00f0", .devs = { { "CTL0043" } } }, 18080faf041STakashi Iwai /* Sound Blaster 16 (Virtual PC 2004) */ 18180faf041STakashi Iwai { .id = "tBA03b0", .devs = { {.id="PNPb003" } } }, 1821da177e4SLinus Torvalds #else /* SNDRV_SBAWE defined */ 1831da177e4SLinus Torvalds /* Sound Blaster AWE 32 PnP */ 1841da177e4SLinus Torvalds { .id = "CTL0035", .devs = { { "CTL0031" }, { "CTL0021" } } }, 1851da177e4SLinus Torvalds /* Sound Blaster AWE 32 PnP */ 1861da177e4SLinus Torvalds { .id = "CTL0039", .devs = { { "CTL0031" }, { "CTL0021" } } }, 1871da177e4SLinus Torvalds /* Sound Blaster AWE 32 PnP */ 1881da177e4SLinus Torvalds { .id = "CTL0042", .devs = { { "CTL0031" }, { "CTL0021" } } }, 1891da177e4SLinus Torvalds /* Sound Blaster AWE 32 PnP */ 1901da177e4SLinus Torvalds { .id = "CTL0043", .devs = { { "CTL0031" }, { "CTL0021" } } }, 1911da177e4SLinus Torvalds /* Sound Blaster AWE 32 PnP */ 1921da177e4SLinus Torvalds /* Note: This card has also a CTL0051:StereoEnhance device!!! */ 1931da177e4SLinus Torvalds { .id = "CTL0044", .devs = { { "CTL0031" }, { "CTL0021" } } }, 1941da177e4SLinus Torvalds /* Sound Blaster AWE 32 PnP */ 1951da177e4SLinus Torvalds /* Note: This card has also a CTL0051:StereoEnhance device!!! */ 1961da177e4SLinus Torvalds { .id = "CTL0045", .devs = { { "CTL0031" }, { "CTL0021" } } }, 1971da177e4SLinus Torvalds /* Sound Blaster AWE 32 PnP */ 1981da177e4SLinus Torvalds { .id = "CTL0046", .devs = { { "CTL0031" }, { "CTL0021" } } }, 1991da177e4SLinus Torvalds /* Sound Blaster AWE 32 PnP */ 2001da177e4SLinus Torvalds { .id = "CTL0047", .devs = { { "CTL0031" }, { "CTL0021" } } }, 2011da177e4SLinus Torvalds /* Sound Blaster AWE 32 PnP */ 2021da177e4SLinus Torvalds { .id = "CTL0048", .devs = { { "CTL0031" }, { "CTL0021" } } }, 2031da177e4SLinus Torvalds /* Sound Blaster AWE 32 PnP */ 2041da177e4SLinus Torvalds { .id = "CTL0054", .devs = { { "CTL0031" }, { "CTL0021" } } }, 2051da177e4SLinus Torvalds /* Sound Blaster AWE 32 PnP */ 2061da177e4SLinus Torvalds { .id = "CTL009a", .devs = { { "CTL0041" }, { "CTL0021" } } }, 2071da177e4SLinus Torvalds /* Sound Blaster AWE 32 PnP */ 2081da177e4SLinus Torvalds { .id = "CTL009c", .devs = { { "CTL0041" }, { "CTL0021" } } }, 2091da177e4SLinus Torvalds /* Sound Blaster 32 PnP */ 2101da177e4SLinus Torvalds { .id = "CTL009f", .devs = { { "CTL0041" }, { "CTL0021" } } }, 2111da177e4SLinus Torvalds /* Sound Blaster AWE 64 PnP */ 2121da177e4SLinus Torvalds { .id = "CTL009d", .devs = { { "CTL0042" }, { "CTL0022" } } }, 2131da177e4SLinus Torvalds /* Sound Blaster AWE 64 PnP Gold */ 2141da177e4SLinus Torvalds { .id = "CTL009e", .devs = { { "CTL0044" }, { "CTL0023" } } }, 2151da177e4SLinus Torvalds /* Sound Blaster AWE 64 PnP Gold */ 2161da177e4SLinus Torvalds { .id = "CTL00b2", .devs = { { "CTL0044" }, { "CTL0023" } } }, 2171da177e4SLinus Torvalds /* Sound Blaster AWE 64 PnP */ 2181da177e4SLinus Torvalds { .id = "CTL00c1", .devs = { { "CTL0042" }, { "CTL0022" } } }, 2191da177e4SLinus Torvalds /* Sound Blaster AWE 64 PnP */ 2201da177e4SLinus Torvalds { .id = "CTL00c3", .devs = { { "CTL0045" }, { "CTL0022" } } }, 2211da177e4SLinus Torvalds /* Sound Blaster AWE 64 PnP */ 2221da177e4SLinus Torvalds { .id = "CTL00c5", .devs = { { "CTL0045" }, { "CTL0022" } } }, 2231da177e4SLinus Torvalds /* Sound Blaster AWE 64 PnP */ 2241da177e4SLinus Torvalds { .id = "CTL00c7", .devs = { { "CTL0045" }, { "CTL0022" } } }, 2251da177e4SLinus Torvalds /* Sound Blaster AWE 64 PnP */ 2261da177e4SLinus Torvalds { .id = "CTL00e4", .devs = { { "CTL0045" }, { "CTL0022" } } }, 2271da177e4SLinus Torvalds /* Sound Blaster AWE 64 PnP */ 2281da177e4SLinus Torvalds { .id = "CTL00e9", .devs = { { "CTL0045" }, { "CTL0022" } } }, 2291da177e4SLinus Torvalds /* Sound Blaster 16 PnP (AWE) */ 2301da177e4SLinus Torvalds { .id = "CTL00ed", .devs = { { "CTL0041" }, { "CTL0070" } } }, 2311da177e4SLinus Torvalds /* Generic entries */ 2321da177e4SLinus Torvalds { .id = "CTLXXXX" , .devs = { { "CTL0031" }, { "CTL0021" } } }, 2331da177e4SLinus Torvalds { .id = "CTLXXXX" , .devs = { { "CTL0041" }, { "CTL0021" } } }, 2341da177e4SLinus Torvalds { .id = "CTLXXXX" , .devs = { { "CTL0042" }, { "CTL0022" } } }, 2351da177e4SLinus Torvalds { .id = "CTLXXXX" , .devs = { { "CTL0044" }, { "CTL0023" } } }, 2361da177e4SLinus Torvalds { .id = "CTLXXXX" , .devs = { { "CTL0045" }, { "CTL0022" } } }, 2371da177e4SLinus Torvalds #endif /* SNDRV_SBAWE */ 2381da177e4SLinus Torvalds { .id = "", } 2391da177e4SLinus Torvalds }; 2401da177e4SLinus Torvalds 2411da177e4SLinus Torvalds MODULE_DEVICE_TABLE(pnp_card, snd_sb16_pnpids); 2421da177e4SLinus Torvalds 2431da177e4SLinus Torvalds #endif /* CONFIG_PNP */ 2441da177e4SLinus Torvalds 2451da177e4SLinus Torvalds #ifdef SNDRV_SBAWE_EMU8000 2461da177e4SLinus Torvalds #define DRIVER_NAME "snd-card-sbawe" 2471da177e4SLinus Torvalds #else 2481da177e4SLinus Torvalds #define DRIVER_NAME "snd-card-sb16" 2491da177e4SLinus Torvalds #endif 2501da177e4SLinus Torvalds 2511da177e4SLinus Torvalds #ifdef CONFIG_PNP 2521da177e4SLinus Torvalds 2531bff292eSBill Pemberton static int snd_card_sb16_pnp(int dev, struct snd_card_sb16 *acard, 2541da177e4SLinus Torvalds struct pnp_card_link *card, 2551da177e4SLinus Torvalds const struct pnp_card_device_id *id) 2561da177e4SLinus Torvalds { 2571da177e4SLinus Torvalds struct pnp_dev *pdev; 2581da177e4SLinus Torvalds int err; 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvalds acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL); 261109c53f8SRene Herman if (acard->dev == NULL) 2621da177e4SLinus Torvalds return -ENODEV; 263109c53f8SRene Herman 2641da177e4SLinus Torvalds #ifdef SNDRV_SBAWE_EMU8000 2651da177e4SLinus Torvalds acard->devwt = pnp_request_card_device(card, id->devs[1].id, acard->dev); 2661da177e4SLinus Torvalds #endif 2671da177e4SLinus Torvalds /* Audio initialization */ 2681da177e4SLinus Torvalds pdev = acard->dev; 2691da177e4SLinus Torvalds 2701da177e4SLinus Torvalds err = pnp_activate_dev(pdev); 2711da177e4SLinus Torvalds if (err < 0) { 2721da177e4SLinus Torvalds snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n"); 2731da177e4SLinus Torvalds return err; 2741da177e4SLinus Torvalds } 2751da177e4SLinus Torvalds port[dev] = pnp_port_start(pdev, 0); 2761da177e4SLinus Torvalds mpu_port[dev] = pnp_port_start(pdev, 1); 2771da177e4SLinus Torvalds fm_port[dev] = pnp_port_start(pdev, 2); 2781da177e4SLinus Torvalds dma8[dev] = pnp_dma(pdev, 0); 2791da177e4SLinus Torvalds dma16[dev] = pnp_dma(pdev, 1); 2801da177e4SLinus Torvalds irq[dev] = pnp_irq(pdev, 0); 2811da177e4SLinus Torvalds snd_printdd("pnp SB16: port=0x%lx, mpu port=0x%lx, fm port=0x%lx\n", 2821da177e4SLinus Torvalds port[dev], mpu_port[dev], fm_port[dev]); 2831da177e4SLinus Torvalds snd_printdd("pnp SB16: dma1=%i, dma2=%i, irq=%i\n", 2841da177e4SLinus Torvalds dma8[dev], dma16[dev], irq[dev]); 2851da177e4SLinus Torvalds #ifdef SNDRV_SBAWE_EMU8000 2861da177e4SLinus Torvalds /* WaveTable initialization */ 2871da177e4SLinus Torvalds pdev = acard->devwt; 2881da177e4SLinus Torvalds if (pdev != NULL) { 2891da177e4SLinus Torvalds err = pnp_activate_dev(pdev); 2901da177e4SLinus Torvalds if (err < 0) { 2911da177e4SLinus Torvalds goto __wt_error; 2921da177e4SLinus Torvalds } 2931da177e4SLinus Torvalds awe_port[dev] = pnp_port_start(pdev, 0); 294aa0a2ddcSGreg Kroah-Hartman snd_printdd("pnp SB16: wavetable port=0x%llx\n", 295aa0a2ddcSGreg Kroah-Hartman (unsigned long long)pnp_port_start(pdev, 0)); 2961da177e4SLinus Torvalds } else { 2971da177e4SLinus Torvalds __wt_error: 2981da177e4SLinus Torvalds if (pdev) { 2991da177e4SLinus Torvalds pnp_release_card_device(pdev); 3001da177e4SLinus Torvalds snd_printk(KERN_ERR PFX "WaveTable pnp configure failure\n"); 3011da177e4SLinus Torvalds } 3021da177e4SLinus Torvalds acard->devwt = NULL; 3031da177e4SLinus Torvalds awe_port[dev] = -1; 3041da177e4SLinus Torvalds } 3051da177e4SLinus Torvalds #endif 3061da177e4SLinus Torvalds return 0; 3071da177e4SLinus Torvalds } 3081da177e4SLinus Torvalds 3091da177e4SLinus Torvalds #endif /* CONFIG_PNP */ 3101da177e4SLinus Torvalds 311029d64b0STakashi Iwai static void snd_sb16_free(struct snd_card *card) 3121da177e4SLinus Torvalds { 3136f045616STakashi Iwai struct snd_card_sb16 *acard = card->private_data; 3141da177e4SLinus Torvalds 3151da177e4SLinus Torvalds if (acard == NULL) 3161da177e4SLinus Torvalds return; 317b1d5776dSTakashi Iwai release_and_free_resource(acard->fm_res); 3181da177e4SLinus Torvalds } 3191da177e4SLinus Torvalds 32043bcd973STakashi Iwai #ifdef CONFIG_PNP 32143bcd973STakashi Iwai #define is_isapnp_selected(dev) isapnp[dev] 32243bcd973STakashi Iwai #else 32343bcd973STakashi Iwai #define is_isapnp_selected(dev) 0 32443bcd973STakashi Iwai #endif 32543bcd973STakashi Iwai 3264323cc4dSTakashi Iwai static int snd_sb16_card_new(struct device *devptr, int dev, 3274323cc4dSTakashi Iwai struct snd_card **cardp) 3281da177e4SLinus Torvalds { 329c95eadd2STakashi Iwai struct snd_card *card; 330c95eadd2STakashi Iwai int err; 331c95eadd2STakashi Iwai 3324323cc4dSTakashi Iwai err = snd_card_new(devptr, index[dev], id[dev], THIS_MODULE, 333c95eadd2STakashi Iwai sizeof(struct snd_card_sb16), &card); 334c95eadd2STakashi Iwai if (err < 0) 3353e7fb9f7STakashi Iwai return err; 3366f045616STakashi Iwai card->private_free = snd_sb16_free; 3373e7fb9f7STakashi Iwai *cardp = card; 3383e7fb9f7STakashi Iwai return 0; 3396f045616STakashi Iwai } 3406f045616STakashi Iwai 3411bff292eSBill Pemberton static int snd_sb16_probe(struct snd_card *card, int dev) 3426f045616STakashi Iwai { 3431da177e4SLinus Torvalds int xirq, xdma8, xdma16; 344029d64b0STakashi Iwai struct snd_sb *chip; 3456f045616STakashi Iwai struct snd_card_sb16 *acard = card->private_data; 346029d64b0STakashi Iwai struct snd_opl3 *opl3; 347029d64b0STakashi Iwai struct snd_hwdep *synth = NULL; 3481da177e4SLinus Torvalds #ifdef CONFIG_SND_SB16_CSP 349029d64b0STakashi Iwai struct snd_hwdep *xcsp = NULL; 3501da177e4SLinus Torvalds #endif 3511da177e4SLinus Torvalds unsigned long flags; 3521da177e4SLinus Torvalds int err; 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds xirq = irq[dev]; 3551da177e4SLinus Torvalds xdma8 = dma8[dev]; 3561da177e4SLinus Torvalds xdma16 = dma16[dev]; 3571da177e4SLinus Torvalds 3581da177e4SLinus Torvalds if ((err = snd_sbdsp_create(card, 3591da177e4SLinus Torvalds port[dev], 3601da177e4SLinus Torvalds xirq, 3611da177e4SLinus Torvalds snd_sb16dsp_interrupt, 3621da177e4SLinus Torvalds xdma8, 3631da177e4SLinus Torvalds xdma16, 3641da177e4SLinus Torvalds SB_HW_AUTO, 36543bcd973STakashi Iwai &chip)) < 0) 3666f045616STakashi Iwai return err; 36743bcd973STakashi Iwai 3686f045616STakashi Iwai acard->chip = chip; 3691da177e4SLinus Torvalds if (chip->hardware != SB_HW_16) { 37043bcd973STakashi Iwai snd_printk(KERN_ERR PFX "SB 16 chip was not detected at 0x%lx\n", port[dev]); 3716f045616STakashi Iwai return -ENODEV; 3721da177e4SLinus Torvalds } 3731da177e4SLinus Torvalds chip->mpu_port = mpu_port[dev]; 37443bcd973STakashi Iwai if (! is_isapnp_selected(dev) && (err = snd_sb16dsp_configure(chip)) < 0) 3756f045616STakashi Iwai return err; 37643bcd973STakashi Iwai 37792533f18SLars-Peter Clausen if ((err = snd_sb16dsp_pcm(chip, 0)) < 0) 3786f045616STakashi Iwai return err; 3791da177e4SLinus Torvalds 3801da177e4SLinus Torvalds strcpy(card->driver, 3811da177e4SLinus Torvalds #ifdef SNDRV_SBAWE_EMU8000 3821da177e4SLinus Torvalds awe_port[dev] > 0 ? "SB AWE" : 3831da177e4SLinus Torvalds #endif 3841da177e4SLinus Torvalds "SB16"); 3851da177e4SLinus Torvalds strcpy(card->shortname, chip->name); 3861da177e4SLinus Torvalds sprintf(card->longname, "%s at 0x%lx, irq %i, dma ", 3871da177e4SLinus Torvalds chip->name, 3881da177e4SLinus Torvalds chip->port, 3891da177e4SLinus Torvalds xirq); 3901da177e4SLinus Torvalds if (xdma8 >= 0) 3911da177e4SLinus Torvalds sprintf(card->longname + strlen(card->longname), "%d", xdma8); 3921da177e4SLinus Torvalds if (xdma16 >= 0) 3931da177e4SLinus Torvalds sprintf(card->longname + strlen(card->longname), "%s%d", 3941da177e4SLinus Torvalds xdma8 >= 0 ? "&" : "", xdma16); 3951da177e4SLinus Torvalds 3961da177e4SLinus Torvalds if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) { 3971da177e4SLinus Torvalds if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_SB, 398dba8b469SClemens Ladisch chip->mpu_port, 399dba8b469SClemens Ladisch MPU401_INFO_IRQ_HOOK, -1, 400dba8b469SClemens Ladisch &chip->rmidi)) < 0) 4016f045616STakashi Iwai return err; 4021da177e4SLinus Torvalds chip->rmidi_callback = snd_mpu401_uart_interrupt; 4031da177e4SLinus Torvalds } 4041da177e4SLinus Torvalds 4051da177e4SLinus Torvalds #ifdef SNDRV_SBAWE_EMU8000 4061da177e4SLinus Torvalds if (awe_port[dev] == SNDRV_AUTO_PORT) 4071da177e4SLinus Torvalds awe_port[dev] = 0; /* disable */ 4081da177e4SLinus Torvalds #endif 4091da177e4SLinus Torvalds 4101da177e4SLinus Torvalds if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) { 4111da177e4SLinus Torvalds if (snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2, 4121da177e4SLinus Torvalds OPL3_HW_OPL3, 4131da177e4SLinus Torvalds acard->fm_res != NULL || fm_port[dev] == port[dev], 4141da177e4SLinus Torvalds &opl3) < 0) { 4151da177e4SLinus Torvalds snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx\n", 4161da177e4SLinus Torvalds fm_port[dev], fm_port[dev] + 2); 4171da177e4SLinus Torvalds } else { 4181da177e4SLinus Torvalds #ifdef SNDRV_SBAWE_EMU8000 4191da177e4SLinus Torvalds int seqdev = awe_port[dev] > 0 ? 2 : 1; 4201da177e4SLinus Torvalds #else 4211da177e4SLinus Torvalds int seqdev = 1; 4221da177e4SLinus Torvalds #endif 42343bcd973STakashi Iwai if ((err = snd_opl3_hwdep_new(opl3, 0, seqdev, &synth)) < 0) 4246f045616STakashi Iwai return err; 4251da177e4SLinus Torvalds } 4261da177e4SLinus Torvalds } 4271da177e4SLinus Torvalds 42843bcd973STakashi Iwai if ((err = snd_sbmixer_new(chip)) < 0) 4296f045616STakashi Iwai return err; 4301da177e4SLinus Torvalds 4311da177e4SLinus Torvalds #ifdef CONFIG_SND_SB16_CSP 4321da177e4SLinus Torvalds /* CSP chip on SB16ASP/AWE32 */ 4331da177e4SLinus Torvalds if ((chip->hardware == SB_HW_16) && csp[dev]) { 4341da177e4SLinus Torvalds snd_sb_csp_new(chip, synth != NULL ? 1 : 0, &xcsp); 4351da177e4SLinus Torvalds if (xcsp) { 4361da177e4SLinus Torvalds chip->csp = xcsp->private_data; 4371da177e4SLinus Torvalds chip->hardware = SB_HW_16CSP; 4381da177e4SLinus Torvalds } else { 4391da177e4SLinus Torvalds snd_printk(KERN_INFO PFX "warning - CSP chip not detected on soundcard #%i\n", dev + 1); 4401da177e4SLinus Torvalds } 4411da177e4SLinus Torvalds } 4421da177e4SLinus Torvalds #endif 4431da177e4SLinus Torvalds #ifdef SNDRV_SBAWE_EMU8000 4441da177e4SLinus Torvalds if (awe_port[dev] > 0) { 44543bcd973STakashi Iwai if ((err = snd_emu8000_new(card, 1, awe_port[dev], 44643bcd973STakashi Iwai seq_ports[dev], NULL)) < 0) { 4471da177e4SLinus Torvalds snd_printk(KERN_ERR PFX "fatal error - EMU-8000 synthesizer not detected at 0x%lx\n", awe_port[dev]); 44843bcd973STakashi Iwai 4496f045616STakashi Iwai return err; 4501da177e4SLinus Torvalds } 4511da177e4SLinus Torvalds } 4521da177e4SLinus Torvalds #endif 4531da177e4SLinus Torvalds 4541da177e4SLinus Torvalds /* setup Mic AGC */ 4551da177e4SLinus Torvalds spin_lock_irqsave(&chip->mixer_lock, flags); 4561da177e4SLinus Torvalds snd_sbmixer_write(chip, SB_DSP4_MIC_AGC, 4571da177e4SLinus Torvalds (snd_sbmixer_read(chip, SB_DSP4_MIC_AGC) & 0x01) | 4581da177e4SLinus Torvalds (mic_agc[dev] ? 0x00 : 0x01)); 4591da177e4SLinus Torvalds spin_unlock_irqrestore(&chip->mixer_lock, flags); 4601da177e4SLinus Torvalds 46143bcd973STakashi Iwai if ((err = snd_card_register(card)) < 0) 4626f045616STakashi Iwai return err; 46343bcd973STakashi Iwai 4641da177e4SLinus Torvalds return 0; 4656f045616STakashi Iwai } 46643bcd973STakashi Iwai 4676f045616STakashi Iwai #ifdef CONFIG_PM 4686f045616STakashi Iwai static int snd_sb16_suspend(struct snd_card *card, pm_message_t state) 4696f045616STakashi Iwai { 4706f045616STakashi Iwai struct snd_card_sb16 *acard = card->private_data; 4716f045616STakashi Iwai struct snd_sb *chip = acard->chip; 4726f045616STakashi Iwai 4736f045616STakashi Iwai snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); 4746f045616STakashi Iwai snd_pcm_suspend_all(chip->pcm); 4756f045616STakashi Iwai snd_sbmixer_suspend(chip); 4766f045616STakashi Iwai return 0; 4776f045616STakashi Iwai } 4786f045616STakashi Iwai 4796f045616STakashi Iwai static int snd_sb16_resume(struct snd_card *card) 4806f045616STakashi Iwai { 4816f045616STakashi Iwai struct snd_card_sb16 *acard = card->private_data; 4826f045616STakashi Iwai struct snd_sb *chip = acard->chip; 4836f045616STakashi Iwai 4846f045616STakashi Iwai snd_sbdsp_reset(chip); 4856f045616STakashi Iwai snd_sbmixer_resume(chip); 4866f045616STakashi Iwai snd_power_change_state(card, SNDRV_CTL_POWER_D0); 4876f045616STakashi Iwai return 0; 4886f045616STakashi Iwai } 4896f045616STakashi Iwai #endif 4906f045616STakashi Iwai 4911bff292eSBill Pemberton static int snd_sb16_isa_probe1(int dev, struct device *pdev) 4926f045616STakashi Iwai { 4936f045616STakashi Iwai struct snd_card_sb16 *acard; 4946f045616STakashi Iwai struct snd_card *card; 4956f045616STakashi Iwai int err; 4966f045616STakashi Iwai 4974323cc4dSTakashi Iwai err = snd_sb16_card_new(pdev, dev, &card); 4983e7fb9f7STakashi Iwai if (err < 0) 4993e7fb9f7STakashi Iwai return err; 5006f045616STakashi Iwai 5016f045616STakashi Iwai acard = card->private_data; 5026f045616STakashi Iwai /* non-PnP FM port address is hardwired with base port address */ 5036f045616STakashi Iwai fm_port[dev] = port[dev]; 5046f045616STakashi Iwai /* block the 0x388 port to avoid PnP conflicts */ 5056f045616STakashi Iwai acard->fm_res = request_region(0x388, 4, "SoundBlaster FM"); 5066f045616STakashi Iwai #ifdef SNDRV_SBAWE_EMU8000 5076f045616STakashi Iwai /* non-PnP AWE port address is hardwired with base port address */ 5086f045616STakashi Iwai awe_port[dev] = port[dev] + 0x400; 5096f045616STakashi Iwai #endif 5106f045616STakashi Iwai 5116f045616STakashi Iwai if ((err = snd_sb16_probe(card, dev)) < 0) { 51243bcd973STakashi Iwai snd_card_free(card); 51343bcd973STakashi Iwai return err; 5141da177e4SLinus Torvalds } 5155e24c1c1STakashi Iwai dev_set_drvdata(pdev, card); 5166f045616STakashi Iwai return 0; 5176f045616STakashi Iwai } 5181da177e4SLinus Torvalds 5196f045616STakashi Iwai 5201bff292eSBill Pemberton static int snd_sb16_isa_match(struct device *pdev, unsigned int dev) 5211da177e4SLinus Torvalds { 5225e24c1c1STakashi Iwai return enable[dev] && !is_isapnp_selected(dev); 5235e24c1c1STakashi Iwai } 5245e24c1c1STakashi Iwai 5251bff292eSBill Pemberton static int snd_sb16_isa_probe(struct device *pdev, unsigned int dev) 5265e24c1c1STakashi Iwai { 5276f045616STakashi Iwai int err; 5286f045616STakashi Iwai static int possible_irqs[] = {5, 9, 10, 7, -1}; 5296f045616STakashi Iwai static int possible_dmas8[] = {1, 3, 0, -1}; 5306f045616STakashi Iwai static int possible_dmas16[] = {5, 6, 7, -1}; 5311da177e4SLinus Torvalds 5326f045616STakashi Iwai if (irq[dev] == SNDRV_AUTO_IRQ) { 5336f045616STakashi Iwai if ((irq[dev] = snd_legacy_find_free_irq(possible_irqs)) < 0) { 5346f045616STakashi Iwai snd_printk(KERN_ERR PFX "unable to find a free IRQ\n"); 5356f045616STakashi Iwai return -EBUSY; 5361da177e4SLinus Torvalds } 5371da177e4SLinus Torvalds } 5386f045616STakashi Iwai if (dma8[dev] == SNDRV_AUTO_DMA) { 5396f045616STakashi Iwai if ((dma8[dev] = snd_legacy_find_free_dma(possible_dmas8)) < 0) { 5406f045616STakashi Iwai snd_printk(KERN_ERR PFX "unable to find a free 8-bit DMA\n"); 5416f045616STakashi Iwai return -EBUSY; 5426f045616STakashi Iwai } 5436f045616STakashi Iwai } 5446f045616STakashi Iwai if (dma16[dev] == SNDRV_AUTO_DMA) { 5456f045616STakashi Iwai if ((dma16[dev] = snd_legacy_find_free_dma(possible_dmas16)) < 0) { 5466f045616STakashi Iwai snd_printk(KERN_ERR PFX "unable to find a free 16-bit DMA\n"); 5476f045616STakashi Iwai return -EBUSY; 5486f045616STakashi Iwai } 5496f045616STakashi Iwai } 5506f045616STakashi Iwai 5516f045616STakashi Iwai if (port[dev] != SNDRV_AUTO_PORT) 5525e24c1c1STakashi Iwai return snd_sb16_isa_probe1(dev, pdev); 5536f045616STakashi Iwai else { 5546f045616STakashi Iwai static int possible_ports[] = {0x220, 0x240, 0x260, 0x280}; 5556f045616STakashi Iwai int i; 5566f045616STakashi Iwai for (i = 0; i < ARRAY_SIZE(possible_ports); i++) { 5576f045616STakashi Iwai port[dev] = possible_ports[i]; 5585e24c1c1STakashi Iwai err = snd_sb16_isa_probe1(dev, pdev); 5596f045616STakashi Iwai if (! err) 5606f045616STakashi Iwai return 0; 5616f045616STakashi Iwai } 5626f045616STakashi Iwai return err; 5636f045616STakashi Iwai } 5646f045616STakashi Iwai } 5656f045616STakashi Iwai 5661bff292eSBill Pemberton static int snd_sb16_isa_remove(struct device *pdev, unsigned int dev) 5676f045616STakashi Iwai { 5685e24c1c1STakashi Iwai snd_card_free(dev_get_drvdata(pdev)); 5696f045616STakashi Iwai return 0; 5706f045616STakashi Iwai } 5716f045616STakashi Iwai 5726f045616STakashi Iwai #ifdef CONFIG_PM 5735e24c1c1STakashi Iwai static int snd_sb16_isa_suspend(struct device *dev, unsigned int n, 5745e24c1c1STakashi Iwai pm_message_t state) 5756f045616STakashi Iwai { 5765e24c1c1STakashi Iwai return snd_sb16_suspend(dev_get_drvdata(dev), state); 5776f045616STakashi Iwai } 5786f045616STakashi Iwai 5795e24c1c1STakashi Iwai static int snd_sb16_isa_resume(struct device *dev, unsigned int n) 5806f045616STakashi Iwai { 5815e24c1c1STakashi Iwai return snd_sb16_resume(dev_get_drvdata(dev)); 5826f045616STakashi Iwai } 5836f045616STakashi Iwai #endif 5846f045616STakashi Iwai 5856f045616STakashi Iwai #ifdef SNDRV_SBAWE 58683c51c0aSRene Herman #define DEV_NAME "sbawe" 5876f045616STakashi Iwai #else 58883c51c0aSRene Herman #define DEV_NAME "sb16" 5896f045616STakashi Iwai #endif 5906f045616STakashi Iwai 5915e24c1c1STakashi Iwai static struct isa_driver snd_sb16_isa_driver = { 5925e24c1c1STakashi Iwai .match = snd_sb16_isa_match, 5935e24c1c1STakashi Iwai .probe = snd_sb16_isa_probe, 5941bff292eSBill Pemberton .remove = snd_sb16_isa_remove, 5956f045616STakashi Iwai #ifdef CONFIG_PM 5965e24c1c1STakashi Iwai .suspend = snd_sb16_isa_suspend, 5975e24c1c1STakashi Iwai .resume = snd_sb16_isa_resume, 5986f045616STakashi Iwai #endif 5996f045616STakashi Iwai .driver = { 60083c51c0aSRene Herman .name = DEV_NAME 6016f045616STakashi Iwai }, 6026f045616STakashi Iwai }; 6036f045616STakashi Iwai 6041da177e4SLinus Torvalds 6051da177e4SLinus Torvalds #ifdef CONFIG_PNP 6061bff292eSBill Pemberton static int snd_sb16_pnp_detect(struct pnp_card_link *pcard, 6076f045616STakashi Iwai const struct pnp_card_device_id *pid) 6081da177e4SLinus Torvalds { 6091da177e4SLinus Torvalds static int dev; 6106f045616STakashi Iwai struct snd_card *card; 6111da177e4SLinus Torvalds int res; 6121da177e4SLinus Torvalds 6131da177e4SLinus Torvalds for ( ; dev < SNDRV_CARDS; dev++) { 6141da177e4SLinus Torvalds if (!enable[dev] || !isapnp[dev]) 6151da177e4SLinus Torvalds continue; 6164323cc4dSTakashi Iwai res = snd_sb16_card_new(&pcard->card->dev, dev, &card); 6173e7fb9f7STakashi Iwai if (res < 0) 6183e7fb9f7STakashi Iwai return res; 6196f045616STakashi Iwai if ((res = snd_card_sb16_pnp(dev, card->private_data, pcard, pid)) < 0 || 6206f045616STakashi Iwai (res = snd_sb16_probe(card, dev)) < 0) { 6216f045616STakashi Iwai snd_card_free(card); 6221da177e4SLinus Torvalds return res; 6236f045616STakashi Iwai } 6246f045616STakashi Iwai pnp_set_card_drvdata(pcard, card); 6251da177e4SLinus Torvalds dev++; 6261da177e4SLinus Torvalds return 0; 6271da177e4SLinus Torvalds } 6281da177e4SLinus Torvalds 6291da177e4SLinus Torvalds return -ENODEV; 6301da177e4SLinus Torvalds } 6311da177e4SLinus Torvalds 6321bff292eSBill Pemberton static void snd_sb16_pnp_remove(struct pnp_card_link *pcard) 6331da177e4SLinus Torvalds { 6346f045616STakashi Iwai snd_card_free(pnp_get_card_drvdata(pcard)); 6356f045616STakashi Iwai pnp_set_card_drvdata(pcard, NULL); 6361da177e4SLinus Torvalds } 6371da177e4SLinus Torvalds 6386f045616STakashi Iwai #ifdef CONFIG_PM 6396f045616STakashi Iwai static int snd_sb16_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state) 6406f045616STakashi Iwai { 6416f045616STakashi Iwai return snd_sb16_suspend(pnp_get_card_drvdata(pcard), state); 6426f045616STakashi Iwai } 6436f045616STakashi Iwai static int snd_sb16_pnp_resume(struct pnp_card_link *pcard) 6446f045616STakashi Iwai { 6456f045616STakashi Iwai return snd_sb16_resume(pnp_get_card_drvdata(pcard)); 6466f045616STakashi Iwai } 6476f045616STakashi Iwai #endif 6486f045616STakashi Iwai 6491da177e4SLinus Torvalds static struct pnp_card_driver sb16_pnpc_driver = { 6501da177e4SLinus Torvalds .flags = PNP_DRIVER_RES_DISABLE, 6516f045616STakashi Iwai #ifdef SNDRV_SBAWE 6526f045616STakashi Iwai .name = "sbawe", 6536f045616STakashi Iwai #else 6541da177e4SLinus Torvalds .name = "sb16", 6556f045616STakashi Iwai #endif 6561da177e4SLinus Torvalds .id_table = snd_sb16_pnpids, 6571da177e4SLinus Torvalds .probe = snd_sb16_pnp_detect, 6581bff292eSBill Pemberton .remove = snd_sb16_pnp_remove, 6596f045616STakashi Iwai #ifdef CONFIG_PM 6606f045616STakashi Iwai .suspend = snd_sb16_pnp_suspend, 6616f045616STakashi Iwai .resume = snd_sb16_pnp_resume, 6626f045616STakashi Iwai #endif 6631da177e4SLinus Torvalds }; 6641da177e4SLinus Torvalds 6651da177e4SLinus Torvalds #endif /* CONFIG_PNP */ 6661da177e4SLinus Torvalds 6671da177e4SLinus Torvalds static int __init alsa_card_sb16_init(void) 6681da177e4SLinus Torvalds { 6695e24c1c1STakashi Iwai int err; 6701da177e4SLinus Torvalds 6715e24c1c1STakashi Iwai err = isa_register_driver(&snd_sb16_isa_driver, SNDRV_CARDS); 6721da177e4SLinus Torvalds #ifdef CONFIG_PNP 673609d7694SRene Herman if (!err) 674609d7694SRene Herman isa_registered = 1; 675609d7694SRene Herman 676312fef30SBjorn Helgaas err = pnp_register_card_driver(&sb16_pnpc_driver); 6775e24c1c1STakashi Iwai if (!err) 678f7a9275dSClemens Ladisch pnp_registered = 1; 679609d7694SRene Herman 680609d7694SRene Herman if (isa_registered) 681609d7694SRene Herman err = 0; 6821da177e4SLinus Torvalds #endif 683609d7694SRene Herman return err; 6841da177e4SLinus Torvalds } 6851da177e4SLinus Torvalds 6861da177e4SLinus Torvalds static void __exit alsa_card_sb16_exit(void) 6871da177e4SLinus Torvalds { 6885e24c1c1STakashi Iwai #ifdef CONFIG_PNP 6895e24c1c1STakashi Iwai if (pnp_registered) 6905e24c1c1STakashi Iwai pnp_unregister_card_driver(&sb16_pnpc_driver); 691609d7694SRene Herman if (isa_registered) 6925e24c1c1STakashi Iwai #endif 6935e24c1c1STakashi Iwai isa_unregister_driver(&snd_sb16_isa_driver); 6941da177e4SLinus Torvalds } 6951da177e4SLinus Torvalds 6961da177e4SLinus Torvalds module_init(alsa_card_sb16_init) 6971da177e4SLinus Torvalds module_exit(alsa_card_sb16_exit) 698