xref: /linux/sound/isa/opti9xx/opti92x-ad1848.c (revision 5f60e496083efb01893a899b6885828330db971f)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds     card-opti92x-ad1848.c - driver for OPTi 82c92x based soundcards.
31da177e4SLinus Torvalds     Copyright (C) 1998-2000 by Massimo Piccioni <dafastidio@libero.it>
41da177e4SLinus Torvalds 
51da177e4SLinus Torvalds     Part of this code was developed at the Italian Ministry of Air Defence,
61da177e4SLinus Torvalds     Sixth Division (oh, che pace ...), Rome.
71da177e4SLinus Torvalds 
81da177e4SLinus Torvalds     Thanks to Maria Grazia Pollarini, Salvatore Vassallo.
91da177e4SLinus Torvalds 
101da177e4SLinus Torvalds     This program is free software; you can redistribute it and/or modify
111da177e4SLinus Torvalds     it under the terms of the GNU General Public License as published by
121da177e4SLinus Torvalds     the Free Software Foundation; either version 2 of the License, or
131da177e4SLinus Torvalds     (at your option) any later version.
141da177e4SLinus Torvalds 
151da177e4SLinus Torvalds     This program is distributed in the hope that it will be useful,
161da177e4SLinus Torvalds     but WITHOUT ANY WARRANTY; without even the implied warranty of
171da177e4SLinus Torvalds     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
181da177e4SLinus Torvalds     GNU General Public License for more details.
191da177e4SLinus Torvalds 
201da177e4SLinus Torvalds     You should have received a copy of the GNU General Public License
211da177e4SLinus Torvalds     along with this program; if not, write to the Free Software
221da177e4SLinus Torvalds     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
231da177e4SLinus Torvalds */
241da177e4SLinus Torvalds 
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds #include <linux/init.h>
2799a0b768STakashi Iwai #include <linux/err.h>
285e24c1c1STakashi Iwai #include <linux/isa.h>
2999a0b768STakashi Iwai #include <linux/delay.h>
301da177e4SLinus Torvalds #include <linux/slab.h>
311da177e4SLinus Torvalds #include <linux/pnp.h>
321da177e4SLinus Torvalds #include <linux/moduleparam.h>
3399a0b768STakashi Iwai #include <asm/io.h>
3499a0b768STakashi Iwai #include <asm/dma.h>
351da177e4SLinus Torvalds #include <sound/core.h>
3661ef19d7SKrzysztof Helt #include <sound/wss.h>
371da177e4SLinus Torvalds #include <sound/mpu401.h>
381da177e4SLinus Torvalds #include <sound/opl3.h>
391da177e4SLinus Torvalds #ifndef OPTi93X
401da177e4SLinus Torvalds #include <sound/opl4.h>
411da177e4SLinus Torvalds #endif
421da177e4SLinus Torvalds #define SNDRV_LEGACY_FIND_FREE_IRQ
431da177e4SLinus Torvalds #define SNDRV_LEGACY_FIND_FREE_DMA
441da177e4SLinus Torvalds #include <sound/initval.h>
451da177e4SLinus Torvalds 
461da177e4SLinus Torvalds MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
471da177e4SLinus Torvalds MODULE_LICENSE("GPL");
481da177e4SLinus Torvalds #ifdef OPTi93X
491da177e4SLinus Torvalds MODULE_DESCRIPTION("OPTi93X");
501da177e4SLinus Torvalds MODULE_SUPPORTED_DEVICE("{{OPTi,82C931/3}}");
511da177e4SLinus Torvalds #else	/* OPTi93X */
521da177e4SLinus Torvalds #ifdef CS4231
531da177e4SLinus Torvalds MODULE_DESCRIPTION("OPTi92X - CS4231");
541da177e4SLinus Torvalds MODULE_SUPPORTED_DEVICE("{{OPTi,82C924 (CS4231)},"
551da177e4SLinus Torvalds 		"{OPTi,82C925 (CS4231)}}");
561da177e4SLinus Torvalds #else	/* CS4231 */
571da177e4SLinus Torvalds MODULE_DESCRIPTION("OPTi92X - AD1848");
581da177e4SLinus Torvalds MODULE_SUPPORTED_DEVICE("{{OPTi,82C924 (AD1848)},"
591da177e4SLinus Torvalds 		"{OPTi,82C925 (AD1848)},"
601da177e4SLinus Torvalds 	        "{OAK,Mozart}}");
611da177e4SLinus Torvalds #endif	/* CS4231 */
621da177e4SLinus Torvalds #endif	/* OPTi93X */
631da177e4SLinus Torvalds 
641da177e4SLinus Torvalds static int index = SNDRV_DEFAULT_IDX1;	/* Index 0-MAX */
651da177e4SLinus Torvalds static char *id = SNDRV_DEFAULT_STR1;		/* ID for this card */
661da177e4SLinus Torvalds //static int enable = SNDRV_DEFAULT_ENABLE1;	/* Enable this card */
6751f6baadSRene Herman #ifdef CONFIG_PNP
681da177e4SLinus Torvalds static int isapnp = 1;			/* Enable ISA PnP detection */
6951f6baadSRene Herman #endif
701da177e4SLinus Torvalds static long port = SNDRV_DEFAULT_PORT1; 	/* 0x530,0xe80,0xf40,0x604 */
711da177e4SLinus Torvalds static long mpu_port = SNDRV_DEFAULT_PORT1;	/* 0x300,0x310,0x320,0x330 */
721da177e4SLinus Torvalds static long fm_port = SNDRV_DEFAULT_PORT1;	/* 0x388 */
731da177e4SLinus Torvalds static int irq = SNDRV_DEFAULT_IRQ1;		/* 5,7,9,10,11 */
741da177e4SLinus Torvalds static int mpu_irq = SNDRV_DEFAULT_IRQ1;	/* 5,7,9,10 */
751da177e4SLinus Torvalds static int dma1 = SNDRV_DEFAULT_DMA1;		/* 0,1,3 */
761da177e4SLinus Torvalds #if defined(CS4231) || defined(OPTi93X)
771da177e4SLinus Torvalds static int dma2 = SNDRV_DEFAULT_DMA1;		/* 0,1,3 */
781da177e4SLinus Torvalds #endif	/* CS4231 || OPTi93X */
791da177e4SLinus Torvalds 
801da177e4SLinus Torvalds module_param(index, int, 0444);
811da177e4SLinus Torvalds MODULE_PARM_DESC(index, "Index value for opti9xx based soundcard.");
821da177e4SLinus Torvalds module_param(id, charp, 0444);
831da177e4SLinus Torvalds MODULE_PARM_DESC(id, "ID string for opti9xx based soundcard.");
841da177e4SLinus Torvalds //module_param(enable, bool, 0444);
851da177e4SLinus Torvalds //MODULE_PARM_DESC(enable, "Enable opti9xx soundcard.");
8651f6baadSRene Herman #ifdef CONFIG_PNP
871da177e4SLinus Torvalds module_param(isapnp, bool, 0444);
881da177e4SLinus Torvalds MODULE_PARM_DESC(isapnp, "Enable ISA PnP detection for specified soundcard.");
8951f6baadSRene Herman #endif
901da177e4SLinus Torvalds module_param(port, long, 0444);
911da177e4SLinus Torvalds MODULE_PARM_DESC(port, "WSS port # for opti9xx driver.");
921da177e4SLinus Torvalds module_param(mpu_port, long, 0444);
931da177e4SLinus Torvalds MODULE_PARM_DESC(mpu_port, "MPU-401 port # for opti9xx driver.");
941da177e4SLinus Torvalds module_param(fm_port, long, 0444);
951da177e4SLinus Torvalds MODULE_PARM_DESC(fm_port, "FM port # for opti9xx driver.");
961da177e4SLinus Torvalds module_param(irq, int, 0444);
971da177e4SLinus Torvalds MODULE_PARM_DESC(irq, "WSS irq # for opti9xx driver.");
981da177e4SLinus Torvalds module_param(mpu_irq, int, 0444);
991da177e4SLinus Torvalds MODULE_PARM_DESC(mpu_irq, "MPU-401 irq # for opti9xx driver.");
1001da177e4SLinus Torvalds module_param(dma1, int, 0444);
1011da177e4SLinus Torvalds MODULE_PARM_DESC(dma1, "1st dma # for opti9xx driver.");
1021da177e4SLinus Torvalds #if defined(CS4231) || defined(OPTi93X)
1031da177e4SLinus Torvalds module_param(dma2, int, 0444);
1041da177e4SLinus Torvalds MODULE_PARM_DESC(dma2, "2nd dma # for opti9xx driver.");
1051da177e4SLinus Torvalds #endif	/* CS4231 || OPTi93X */
1061da177e4SLinus Torvalds 
1071da177e4SLinus Torvalds #define OPTi9XX_HW_82C928	1
1081da177e4SLinus Torvalds #define OPTi9XX_HW_82C929	2
1091da177e4SLinus Torvalds #define OPTi9XX_HW_82C924	3
1101da177e4SLinus Torvalds #define OPTi9XX_HW_82C925	4
1111da177e4SLinus Torvalds #define OPTi9XX_HW_82C930	5
1121da177e4SLinus Torvalds #define OPTi9XX_HW_82C931	6
1131da177e4SLinus Torvalds #define OPTi9XX_HW_82C933	7
1141da177e4SLinus Torvalds #define OPTi9XX_HW_LAST		OPTi9XX_HW_82C933
1151da177e4SLinus Torvalds 
1161da177e4SLinus Torvalds #define OPTi9XX_MC_REG(n)	n
1171da177e4SLinus Torvalds 
1181da177e4SLinus Torvalds #ifdef OPTi93X
1191da177e4SLinus Torvalds 
1201da177e4SLinus Torvalds #define OPTi93X_STATUS			0x02
1211da177e4SLinus Torvalds #define OPTi93X_PORT(chip, r)		((chip)->port + OPTi93X_##r)
1221da177e4SLinus Torvalds 
1231da177e4SLinus Torvalds #define OPTi93X_IRQ_PLAYBACK		0x04
1241da177e4SLinus Torvalds #define OPTi93X_IRQ_CAPTURE		0x08
1251da177e4SLinus Torvalds 
1261da177e4SLinus Torvalds #endif /* OPTi93X */
1271da177e4SLinus Torvalds 
128346c7a68STakashi Iwai struct snd_opti9xx {
1291da177e4SLinus Torvalds 	unsigned short hardware;
1301da177e4SLinus Torvalds 	unsigned char password;
1311da177e4SLinus Torvalds 	char name[7];
1321da177e4SLinus Torvalds 
1331da177e4SLinus Torvalds 	unsigned long mc_base;
1341da177e4SLinus Torvalds 	struct resource *res_mc_base;
1351da177e4SLinus Torvalds 	unsigned long mc_base_size;
1361da177e4SLinus Torvalds #ifdef OPTi93X
1371da177e4SLinus Torvalds 	unsigned long mc_indir_index;
138e6960e19SKrzysztof Helt 	unsigned long mc_indir_size;
139e6960e19SKrzysztof Helt 	struct resource *res_mc_indir;
1407779f75fSKrzysztof Helt 	struct snd_wss *codec;
1411da177e4SLinus Torvalds #endif	/* OPTi93X */
1421da177e4SLinus Torvalds 	unsigned long pwd_reg;
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds 	spinlock_t lock;
1451da177e4SLinus Torvalds 
1461da177e4SLinus Torvalds 	int irq;
1471da177e4SLinus Torvalds 
1481da177e4SLinus Torvalds #ifdef CONFIG_PNP
1491da177e4SLinus Torvalds 	struct pnp_dev *dev;
1501da177e4SLinus Torvalds 	struct pnp_dev *devmpu;
1511da177e4SLinus Torvalds #endif	/* CONFIG_PNP */
1521da177e4SLinus Torvalds };
1531da177e4SLinus Torvalds 
15499a0b768STakashi Iwai static int snd_opti9xx_pnp_is_probed;
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds #ifdef CONFIG_PNP
1571da177e4SLinus Torvalds 
1581da177e4SLinus Torvalds static struct pnp_card_device_id snd_opti9xx_pnpids[] = {
1591da177e4SLinus Torvalds #ifndef OPTi93X
1601da177e4SLinus Torvalds 	/* OPTi 82C924 */
1611da177e4SLinus Torvalds 	{ .id = "OPT0924", .devs = { { "OPT0000" }, { "OPT0002" } }, .driver_data = 0x0924 },
1621da177e4SLinus Torvalds 	/* OPTi 82C925 */
1631da177e4SLinus Torvalds 	{ .id = "OPT0925", .devs = { { "OPT9250" }, { "OPT0002" } }, .driver_data = 0x0925 },
1641da177e4SLinus Torvalds #else
1651da177e4SLinus Torvalds 	/* OPTi 82C931/3 */
1661da177e4SLinus Torvalds 	{ .id = "OPT0931", .devs = { { "OPT9310" }, { "OPT0002" } }, .driver_data = 0x0931 },
1671da177e4SLinus Torvalds #endif	/* OPTi93X */
1681da177e4SLinus Torvalds 	{ .id = "" }
1691da177e4SLinus Torvalds };
1701da177e4SLinus Torvalds 
1711da177e4SLinus Torvalds MODULE_DEVICE_TABLE(pnp_card, snd_opti9xx_pnpids);
1721da177e4SLinus Torvalds 
1731da177e4SLinus Torvalds #endif	/* CONFIG_PNP */
1741da177e4SLinus Torvalds 
1751da177e4SLinus Torvalds #ifdef OPTi93X
17683c51c0aSRene Herman #define DEV_NAME "opti93x"
1771da177e4SLinus Torvalds #else
17883c51c0aSRene Herman #define DEV_NAME "opti92x"
17983c51c0aSRene Herman #endif
1801da177e4SLinus Torvalds 
1811da177e4SLinus Torvalds static char * snd_opti9xx_names[] = {
1821da177e4SLinus Torvalds 	"unkown",
1831da177e4SLinus Torvalds 	"82C928",	"82C929",
1841da177e4SLinus Torvalds 	"82C924",	"82C925",
1851da177e4SLinus Torvalds 	"82C930",	"82C931",	"82C933"
1861da177e4SLinus Torvalds };
1871da177e4SLinus Torvalds 
1881da177e4SLinus Torvalds 
1895e24c1c1STakashi Iwai static long __devinit snd_legacy_find_free_ioport(long *port_table, long size)
1901da177e4SLinus Torvalds {
1911da177e4SLinus Torvalds 	while (*port_table != -1) {
192b1d5776dSTakashi Iwai 		if (request_region(*port_table, size, "ALSA test")) {
193b1d5776dSTakashi Iwai 			release_region(*port_table, size);
1941da177e4SLinus Torvalds 			return *port_table;
1951da177e4SLinus Torvalds 		}
1961da177e4SLinus Torvalds 		port_table++;
1971da177e4SLinus Torvalds 	}
1981da177e4SLinus Torvalds 	return -1;
1991da177e4SLinus Torvalds }
2001da177e4SLinus Torvalds 
2015e24c1c1STakashi Iwai static int __devinit snd_opti9xx_init(struct snd_opti9xx *chip,
2025e24c1c1STakashi Iwai 				      unsigned short hardware)
2031da177e4SLinus Torvalds {
2041da177e4SLinus Torvalds 	static int opti9xx_mc_size[] = {7, 7, 10, 10, 2, 2, 2};
2051da177e4SLinus Torvalds 
2061da177e4SLinus Torvalds 	chip->hardware = hardware;
2071da177e4SLinus Torvalds 	strcpy(chip->name, snd_opti9xx_names[hardware]);
2081da177e4SLinus Torvalds 
2091da177e4SLinus Torvalds 	chip->mc_base_size = opti9xx_mc_size[hardware];
2101da177e4SLinus Torvalds 
2111da177e4SLinus Torvalds 	spin_lock_init(&chip->lock);
2121da177e4SLinus Torvalds 
2131da177e4SLinus Torvalds 	chip->irq = -1;
2141da177e4SLinus Torvalds 
2151da177e4SLinus Torvalds 	switch (hardware) {
2161da177e4SLinus Torvalds #ifndef OPTi93X
2171da177e4SLinus Torvalds 	case OPTi9XX_HW_82C928:
2181da177e4SLinus Torvalds 	case OPTi9XX_HW_82C929:
2191da177e4SLinus Torvalds 		chip->mc_base = 0xf8c;
2201da177e4SLinus Torvalds 		chip->password = (hardware == OPTi9XX_HW_82C928) ? 0xe2 : 0xe3;
2211da177e4SLinus Torvalds 		chip->pwd_reg = 3;
2221da177e4SLinus Torvalds 		break;
2231da177e4SLinus Torvalds 
2241da177e4SLinus Torvalds 	case OPTi9XX_HW_82C924:
2251da177e4SLinus Torvalds 	case OPTi9XX_HW_82C925:
2261da177e4SLinus Torvalds 		chip->mc_base = 0xf8c;
2271da177e4SLinus Torvalds 		chip->password = 0xe5;
2281da177e4SLinus Torvalds 		chip->pwd_reg = 3;
2291da177e4SLinus Torvalds 		break;
2301da177e4SLinus Torvalds #else	/* OPTi93X */
2311da177e4SLinus Torvalds 
2321da177e4SLinus Torvalds 	case OPTi9XX_HW_82C930:
2331da177e4SLinus Torvalds 	case OPTi9XX_HW_82C931:
2341da177e4SLinus Torvalds 	case OPTi9XX_HW_82C933:
2351da177e4SLinus Torvalds 		chip->mc_base = (hardware == OPTi9XX_HW_82C930) ? 0xf8f : 0xf8d;
236e6960e19SKrzysztof Helt 		if (!chip->mc_indir_index) {
2371da177e4SLinus Torvalds 			chip->mc_indir_index = 0xe0e;
238e6960e19SKrzysztof Helt 			chip->mc_indir_size = 2;
239e6960e19SKrzysztof Helt 		}
2401da177e4SLinus Torvalds 		chip->password = 0xe4;
2411da177e4SLinus Torvalds 		chip->pwd_reg = 0;
2421da177e4SLinus Torvalds 		break;
2431da177e4SLinus Torvalds #endif	/* OPTi93X */
2441da177e4SLinus Torvalds 
2451da177e4SLinus Torvalds 	default:
2464c9f1d3eSTakashi Iwai 		snd_printk(KERN_ERR "chip %d not supported\n", hardware);
2471da177e4SLinus Torvalds 		return -ENODEV;
2481da177e4SLinus Torvalds 	}
2491da177e4SLinus Torvalds 	return 0;
2501da177e4SLinus Torvalds }
2511da177e4SLinus Torvalds 
252346c7a68STakashi Iwai static unsigned char snd_opti9xx_read(struct snd_opti9xx *chip,
2531da177e4SLinus Torvalds 				      unsigned char reg)
2541da177e4SLinus Torvalds {
2551da177e4SLinus Torvalds 	unsigned long flags;
2561da177e4SLinus Torvalds 	unsigned char retval = 0xff;
2571da177e4SLinus Torvalds 
2581da177e4SLinus Torvalds 	spin_lock_irqsave(&chip->lock, flags);
2591da177e4SLinus Torvalds 	outb(chip->password, chip->mc_base + chip->pwd_reg);
2601da177e4SLinus Torvalds 
2611da177e4SLinus Torvalds 	switch (chip->hardware) {
2621da177e4SLinus Torvalds #ifndef OPTi93X
2631da177e4SLinus Torvalds 	case OPTi9XX_HW_82C924:
2641da177e4SLinus Torvalds 	case OPTi9XX_HW_82C925:
2651da177e4SLinus Torvalds 		if (reg > 7) {
2661da177e4SLinus Torvalds 			outb(reg, chip->mc_base + 8);
2671da177e4SLinus Torvalds 			outb(chip->password, chip->mc_base + chip->pwd_reg);
2681da177e4SLinus Torvalds 			retval = inb(chip->mc_base + 9);
2691da177e4SLinus Torvalds 			break;
2701da177e4SLinus Torvalds 		}
2711da177e4SLinus Torvalds 
2721da177e4SLinus Torvalds 	case OPTi9XX_HW_82C928:
2731da177e4SLinus Torvalds 	case OPTi9XX_HW_82C929:
2741da177e4SLinus Torvalds 		retval = inb(chip->mc_base + reg);
2751da177e4SLinus Torvalds 		break;
2761da177e4SLinus Torvalds #else	/* OPTi93X */
2771da177e4SLinus Torvalds 
2781da177e4SLinus Torvalds 	case OPTi9XX_HW_82C930:
2791da177e4SLinus Torvalds 	case OPTi9XX_HW_82C931:
2801da177e4SLinus Torvalds 	case OPTi9XX_HW_82C933:
2811da177e4SLinus Torvalds 		outb(reg, chip->mc_indir_index);
2821da177e4SLinus Torvalds 		outb(chip->password, chip->mc_base + chip->pwd_reg);
2831da177e4SLinus Torvalds 		retval = inb(chip->mc_indir_index + 1);
2841da177e4SLinus Torvalds 		break;
2851da177e4SLinus Torvalds #endif	/* OPTi93X */
2861da177e4SLinus Torvalds 
2871da177e4SLinus Torvalds 	default:
2884c9f1d3eSTakashi Iwai 		snd_printk(KERN_ERR "chip %d not supported\n", chip->hardware);
2891da177e4SLinus Torvalds 	}
2901da177e4SLinus Torvalds 
2911da177e4SLinus Torvalds 	spin_unlock_irqrestore(&chip->lock, flags);
2921da177e4SLinus Torvalds 	return retval;
2931da177e4SLinus Torvalds }
2941da177e4SLinus Torvalds 
295346c7a68STakashi Iwai static void snd_opti9xx_write(struct snd_opti9xx *chip, unsigned char reg,
2961da177e4SLinus Torvalds 			      unsigned char value)
2971da177e4SLinus Torvalds {
2981da177e4SLinus Torvalds 	unsigned long flags;
2991da177e4SLinus Torvalds 
3001da177e4SLinus Torvalds 	spin_lock_irqsave(&chip->lock, flags);
3011da177e4SLinus Torvalds 	outb(chip->password, chip->mc_base + chip->pwd_reg);
3021da177e4SLinus Torvalds 
3031da177e4SLinus Torvalds 	switch (chip->hardware) {
3041da177e4SLinus Torvalds #ifndef OPTi93X
3051da177e4SLinus Torvalds 	case OPTi9XX_HW_82C924:
3061da177e4SLinus Torvalds 	case OPTi9XX_HW_82C925:
3071da177e4SLinus Torvalds 		if (reg > 7) {
3081da177e4SLinus Torvalds 			outb(reg, chip->mc_base + 8);
3091da177e4SLinus Torvalds 			outb(chip->password, chip->mc_base + chip->pwd_reg);
3101da177e4SLinus Torvalds 			outb(value, chip->mc_base + 9);
3111da177e4SLinus Torvalds 			break;
3121da177e4SLinus Torvalds 		}
3131da177e4SLinus Torvalds 
3141da177e4SLinus Torvalds 	case OPTi9XX_HW_82C928:
3151da177e4SLinus Torvalds 	case OPTi9XX_HW_82C929:
3161da177e4SLinus Torvalds 		outb(value, chip->mc_base + reg);
3171da177e4SLinus Torvalds 		break;
3181da177e4SLinus Torvalds #else	/* OPTi93X */
3191da177e4SLinus Torvalds 
3201da177e4SLinus Torvalds 	case OPTi9XX_HW_82C930:
3211da177e4SLinus Torvalds 	case OPTi9XX_HW_82C931:
3221da177e4SLinus Torvalds 	case OPTi9XX_HW_82C933:
3231da177e4SLinus Torvalds 		outb(reg, chip->mc_indir_index);
3241da177e4SLinus Torvalds 		outb(chip->password, chip->mc_base + chip->pwd_reg);
3251da177e4SLinus Torvalds 		outb(value, chip->mc_indir_index + 1);
3261da177e4SLinus Torvalds 		break;
3271da177e4SLinus Torvalds #endif	/* OPTi93X */
3281da177e4SLinus Torvalds 
3291da177e4SLinus Torvalds 	default:
3304c9f1d3eSTakashi Iwai 		snd_printk(KERN_ERR "chip %d not supported\n", chip->hardware);
3311da177e4SLinus Torvalds 	}
3321da177e4SLinus Torvalds 
3331da177e4SLinus Torvalds 	spin_unlock_irqrestore(&chip->lock, flags);
3341da177e4SLinus Torvalds }
3351da177e4SLinus Torvalds 
3361da177e4SLinus Torvalds 
3371da177e4SLinus Torvalds #define snd_opti9xx_write_mask(chip, reg, value, mask)	\
3381da177e4SLinus Torvalds 	snd_opti9xx_write(chip, reg,			\
3391da177e4SLinus Torvalds 		(snd_opti9xx_read(chip, reg) & ~(mask)) | ((value) & (mask)))
3401da177e4SLinus Torvalds 
3411da177e4SLinus Torvalds 
342d8ea2393SKrzysztof Helt static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip,
343d8ea2393SKrzysztof Helt 					   long wss_base,
344d8ea2393SKrzysztof Helt 					   int irq, int dma1, int dma2,
345d8ea2393SKrzysztof Helt 					   long mpu_port, int mpu_irq)
3461da177e4SLinus Torvalds {
3471da177e4SLinus Torvalds 	unsigned char wss_base_bits;
3481da177e4SLinus Torvalds 	unsigned char irq_bits;
3491da177e4SLinus Torvalds 	unsigned char dma_bits;
3501da177e4SLinus Torvalds 	unsigned char mpu_port_bits = 0;
3511da177e4SLinus Torvalds 	unsigned char mpu_irq_bits;
3521da177e4SLinus Torvalds 
3531da177e4SLinus Torvalds 	switch (chip->hardware) {
3541da177e4SLinus Torvalds #ifndef OPTi93X
3551da177e4SLinus Torvalds 	case OPTi9XX_HW_82C924:
3561da177e4SLinus Torvalds 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(4), 0xf0, 0xfc);
3571da177e4SLinus Torvalds 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x02);
3581da177e4SLinus Torvalds 
3591da177e4SLinus Torvalds 	case OPTi9XX_HW_82C925:
3601da177e4SLinus Torvalds 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80);
3611da177e4SLinus Torvalds 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(2), 0x00, 0x20);
3621da177e4SLinus Torvalds 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(3), 0xf0, 0xff);
3631da177e4SLinus Torvalds #ifdef CS4231
3641da177e4SLinus Torvalds 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(5), 0x02, 0x02);
3651da177e4SLinus Torvalds #else
3661da177e4SLinus Torvalds 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(5), 0x00, 0x02);
3671da177e4SLinus Torvalds #endif	/* CS4231 */
3681da177e4SLinus Torvalds 		break;
3691da177e4SLinus Torvalds 
3701da177e4SLinus Torvalds 	case OPTi9XX_HW_82C928:
3711da177e4SLinus Torvalds 	case OPTi9XX_HW_82C929:
3721da177e4SLinus Torvalds 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80);
3731da177e4SLinus Torvalds 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(2), 0x00, 0x20);
3741da177e4SLinus Torvalds 		/*
3751da177e4SLinus Torvalds 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(3), 0xa2, 0xae);
3761da177e4SLinus Torvalds 		*/
3771da177e4SLinus Torvalds 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(4), 0x00, 0x0c);
3781da177e4SLinus Torvalds #ifdef CS4231
3791da177e4SLinus Torvalds 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(5), 0x02, 0x02);
3801da177e4SLinus Torvalds #else
3811da177e4SLinus Torvalds 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(5), 0x00, 0x02);
3821da177e4SLinus Torvalds #endif	/* CS4231 */
3831da177e4SLinus Torvalds 		break;
3841da177e4SLinus Torvalds 
3851da177e4SLinus Torvalds #else	/* OPTi93X */
3861da177e4SLinus Torvalds 	case OPTi9XX_HW_82C931:
3871da177e4SLinus Torvalds 	case OPTi9XX_HW_82C933:
388f81b953dSKrzysztof Helt 		/*
389f81b953dSKrzysztof Helt 		 * The BTC 1817DW has QS1000 wavetable which is connected
390f81b953dSKrzysztof Helt 		 * to the serial digital input of the OPTI931.
391f81b953dSKrzysztof Helt 		 */
392f81b953dSKrzysztof Helt 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(21), 0x82, 0xff);
393f81b953dSKrzysztof Helt 		/*
394f81b953dSKrzysztof Helt 		 * This bit sets OPTI931 to automaticaly select FM
395f81b953dSKrzysztof Helt 		 * or digital input signal.
396f81b953dSKrzysztof Helt 		 */
397f81b953dSKrzysztof Helt 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(26), 0x01, 0x01);
3983ae5f36aSKrzysztof Helt 	case OPTi9XX_HW_82C930: /* FALL THROUGH */
3993ae5f36aSKrzysztof Helt 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x03);
4003ae5f36aSKrzysztof Helt 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(3), 0x00, 0xff);
4013ae5f36aSKrzysztof Helt 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(4), 0x10 |
4023ae5f36aSKrzysztof Helt 			(chip->hardware == OPTi9XX_HW_82C930 ? 0x00 : 0x04),
4033ae5f36aSKrzysztof Helt 			0x34);
4043ae5f36aSKrzysztof Helt 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(5), 0x20, 0xbf);
4051da177e4SLinus Torvalds 		break;
4061da177e4SLinus Torvalds #endif	/* OPTi93X */
4071da177e4SLinus Torvalds 
4081da177e4SLinus Torvalds 	default:
4094c9f1d3eSTakashi Iwai 		snd_printk(KERN_ERR "chip %d not supported\n", chip->hardware);
4101da177e4SLinus Torvalds 		return -EINVAL;
4111da177e4SLinus Torvalds 	}
4121da177e4SLinus Torvalds 
413d8ea2393SKrzysztof Helt 	switch (wss_base) {
4141da177e4SLinus Torvalds 	case 0x530:
4151da177e4SLinus Torvalds 		wss_base_bits = 0x00;
4161da177e4SLinus Torvalds 		break;
4171da177e4SLinus Torvalds 	case 0x604:
4181da177e4SLinus Torvalds 		wss_base_bits = 0x03;
4191da177e4SLinus Torvalds 		break;
4201da177e4SLinus Torvalds 	case 0xe80:
4211da177e4SLinus Torvalds 		wss_base_bits = 0x01;
4221da177e4SLinus Torvalds 		break;
4231da177e4SLinus Torvalds 	case 0xf40:
4241da177e4SLinus Torvalds 		wss_base_bits = 0x02;
4251da177e4SLinus Torvalds 		break;
4261da177e4SLinus Torvalds 	default:
427d8ea2393SKrzysztof Helt 		snd_printk(KERN_WARNING "WSS port 0x%lx not valid\n", wss_base);
4281da177e4SLinus Torvalds 		goto __skip_base;
4291da177e4SLinus Torvalds 	}
4301da177e4SLinus Torvalds 	snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(1), wss_base_bits << 4, 0x30);
4311da177e4SLinus Torvalds 
4321da177e4SLinus Torvalds __skip_base:
433d8ea2393SKrzysztof Helt 	switch (irq) {
4341da177e4SLinus Torvalds //#ifdef OPTi93X
4351da177e4SLinus Torvalds 	case 5:
4361da177e4SLinus Torvalds 		irq_bits = 0x05;
4371da177e4SLinus Torvalds 		break;
4381da177e4SLinus Torvalds //#endif	/* OPTi93X */
4391da177e4SLinus Torvalds 	case 7:
4401da177e4SLinus Torvalds 		irq_bits = 0x01;
4411da177e4SLinus Torvalds 		break;
4421da177e4SLinus Torvalds 	case 9:
4431da177e4SLinus Torvalds 		irq_bits = 0x02;
4441da177e4SLinus Torvalds 		break;
4451da177e4SLinus Torvalds 	case 10:
4461da177e4SLinus Torvalds 		irq_bits = 0x03;
4471da177e4SLinus Torvalds 		break;
4481da177e4SLinus Torvalds 	case 11:
4491da177e4SLinus Torvalds 		irq_bits = 0x04;
4501da177e4SLinus Torvalds 		break;
4511da177e4SLinus Torvalds 	default:
452d8ea2393SKrzysztof Helt 		snd_printk(KERN_WARNING "WSS irq # %d not valid\n", irq);
4531da177e4SLinus Torvalds 		goto __skip_resources;
4541da177e4SLinus Torvalds 	}
4551da177e4SLinus Torvalds 
456d8ea2393SKrzysztof Helt 	switch (dma1) {
4571da177e4SLinus Torvalds 	case 0:
4581da177e4SLinus Torvalds 		dma_bits = 0x01;
4591da177e4SLinus Torvalds 		break;
4601da177e4SLinus Torvalds 	case 1:
4611da177e4SLinus Torvalds 		dma_bits = 0x02;
4621da177e4SLinus Torvalds 		break;
4631da177e4SLinus Torvalds 	case 3:
4641da177e4SLinus Torvalds 		dma_bits = 0x03;
4651da177e4SLinus Torvalds 		break;
4661da177e4SLinus Torvalds 	default:
467d8ea2393SKrzysztof Helt 		snd_printk(KERN_WARNING "WSS dma1 # %d not valid\n", dma1);
4681da177e4SLinus Torvalds 		goto __skip_resources;
4691da177e4SLinus Torvalds 	}
4701da177e4SLinus Torvalds 
4711da177e4SLinus Torvalds #if defined(CS4231) || defined(OPTi93X)
472d8ea2393SKrzysztof Helt 	if (dma1 == dma2) {
4734c9f1d3eSTakashi Iwai 		snd_printk(KERN_ERR "don't want to share dmas\n");
4741da177e4SLinus Torvalds 		return -EBUSY;
4751da177e4SLinus Torvalds 	}
4761da177e4SLinus Torvalds 
477d8ea2393SKrzysztof Helt 	switch (dma2) {
4781da177e4SLinus Torvalds 	case 0:
4791da177e4SLinus Torvalds 	case 1:
4801da177e4SLinus Torvalds 		break;
4811da177e4SLinus Torvalds 	default:
482d8ea2393SKrzysztof Helt 		snd_printk(KERN_WARNING "WSS dma2 # %d not valid\n", dma2);
4831da177e4SLinus Torvalds 		goto __skip_resources;
4841da177e4SLinus Torvalds 	}
4851da177e4SLinus Torvalds 	dma_bits |= 0x04;
4861da177e4SLinus Torvalds #endif	/* CS4231 || OPTi93X */
4871da177e4SLinus Torvalds 
4881da177e4SLinus Torvalds #ifndef OPTi93X
489d8ea2393SKrzysztof Helt 	 outb(irq_bits << 3 | dma_bits, wss_base);
4901da177e4SLinus Torvalds #else /* OPTi93X */
4911da177e4SLinus Torvalds 	snd_opti9xx_write(chip, OPTi9XX_MC_REG(3), (irq_bits << 3 | dma_bits));
4921da177e4SLinus Torvalds #endif /* OPTi93X */
4931da177e4SLinus Torvalds 
4941da177e4SLinus Torvalds __skip_resources:
4951da177e4SLinus Torvalds 	if (chip->hardware > OPTi9XX_HW_82C928) {
496d8ea2393SKrzysztof Helt 		switch (mpu_port) {
4971da177e4SLinus Torvalds 		case 0:
4981da177e4SLinus Torvalds 		case -1:
4991da177e4SLinus Torvalds 			break;
5001da177e4SLinus Torvalds 		case 0x300:
5011da177e4SLinus Torvalds 			mpu_port_bits = 0x03;
5021da177e4SLinus Torvalds 			break;
5031da177e4SLinus Torvalds 		case 0x310:
5041da177e4SLinus Torvalds 			mpu_port_bits = 0x02;
5051da177e4SLinus Torvalds 			break;
5061da177e4SLinus Torvalds 		case 0x320:
5071da177e4SLinus Torvalds 			mpu_port_bits = 0x01;
5081da177e4SLinus Torvalds 			break;
5091da177e4SLinus Torvalds 		case 0x330:
5101da177e4SLinus Torvalds 			mpu_port_bits = 0x00;
5111da177e4SLinus Torvalds 			break;
5121da177e4SLinus Torvalds 		default:
5134c9f1d3eSTakashi Iwai 			snd_printk(KERN_WARNING
514d8ea2393SKrzysztof Helt 				   "MPU-401 port 0x%lx not valid\n", mpu_port);
5151da177e4SLinus Torvalds 			goto __skip_mpu;
5161da177e4SLinus Torvalds 		}
5171da177e4SLinus Torvalds 
518d8ea2393SKrzysztof Helt 		switch (mpu_irq) {
5191da177e4SLinus Torvalds 		case 5:
5201da177e4SLinus Torvalds 			mpu_irq_bits = 0x02;
5211da177e4SLinus Torvalds 			break;
5221da177e4SLinus Torvalds 		case 7:
5231da177e4SLinus Torvalds 			mpu_irq_bits = 0x03;
5241da177e4SLinus Torvalds 			break;
5251da177e4SLinus Torvalds 		case 9:
5261da177e4SLinus Torvalds 			mpu_irq_bits = 0x00;
5271da177e4SLinus Torvalds 			break;
5281da177e4SLinus Torvalds 		case 10:
5291da177e4SLinus Torvalds 			mpu_irq_bits = 0x01;
5301da177e4SLinus Torvalds 			break;
5311da177e4SLinus Torvalds 		default:
5324c9f1d3eSTakashi Iwai 			snd_printk(KERN_WARNING "MPU-401 irq # %d not valid\n",
533d8ea2393SKrzysztof Helt 				mpu_irq);
5341da177e4SLinus Torvalds 			goto __skip_mpu;
5351da177e4SLinus Torvalds 		}
5361da177e4SLinus Torvalds 
5371da177e4SLinus Torvalds 		snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6),
538d8ea2393SKrzysztof Helt 			(mpu_port <= 0) ? 0x00 :
5391da177e4SLinus Torvalds 				0x80 | mpu_port_bits << 5 | mpu_irq_bits << 3,
5401da177e4SLinus Torvalds 			0xf8);
5411da177e4SLinus Torvalds 	}
5421da177e4SLinus Torvalds __skip_mpu:
5431da177e4SLinus Torvalds 
5441da177e4SLinus Torvalds 	return 0;
5451da177e4SLinus Torvalds }
5461da177e4SLinus Torvalds 
5471da177e4SLinus Torvalds #ifdef OPTi93X
5481da177e4SLinus Torvalds 
5497d12e780SDavid Howells static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id)
5501da177e4SLinus Torvalds {
551*5f60e496SKrzysztof Helt 	struct snd_opti9xx *chip = dev_id;
552*5f60e496SKrzysztof Helt 	struct snd_wss *codec = chip->codec;
5531da177e4SLinus Torvalds 	unsigned char status;
5541da177e4SLinus Torvalds 
555*5f60e496SKrzysztof Helt 	if (!codec)
556*5f60e496SKrzysztof Helt 		return IRQ_HANDLED;
557*5f60e496SKrzysztof Helt 
5589f240a55SKrzysztof Helt 	status = snd_opti9xx_read(chip, OPTi9XX_MC_REG(11));
5591da177e4SLinus Torvalds 	if ((status & OPTi93X_IRQ_PLAYBACK) && codec->playback_substream)
5601da177e4SLinus Torvalds 		snd_pcm_period_elapsed(codec->playback_substream);
5611da177e4SLinus Torvalds 	if ((status & OPTi93X_IRQ_CAPTURE) && codec->capture_substream) {
5627779f75fSKrzysztof Helt 		snd_wss_overrange(codec);
5631da177e4SLinus Torvalds 		snd_pcm_period_elapsed(codec->capture_substream);
5641da177e4SLinus Torvalds 	}
5651da177e4SLinus Torvalds 	outb(0x00, OPTi93X_PORT(codec, STATUS));
5661da177e4SLinus Torvalds 	return IRQ_HANDLED;
5671da177e4SLinus Torvalds }
5681da177e4SLinus Torvalds 
5691da177e4SLinus Torvalds #endif /* OPTi93X */
5701da177e4SLinus Torvalds 
571e6960e19SKrzysztof Helt static int __devinit snd_opti9xx_read_check(struct snd_opti9xx *chip)
572e6960e19SKrzysztof Helt {
573e6960e19SKrzysztof Helt 	unsigned char value;
574e6960e19SKrzysztof Helt #ifdef OPTi93X
575e6960e19SKrzysztof Helt 	unsigned long flags;
576e6960e19SKrzysztof Helt #endif
577e6960e19SKrzysztof Helt 
578e6960e19SKrzysztof Helt 	chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size,
579e6960e19SKrzysztof Helt 					   "OPTi9xx MC");
580e6960e19SKrzysztof Helt 	if (chip->res_mc_base == NULL)
581e6960e19SKrzysztof Helt 		return -EBUSY;
582e6960e19SKrzysztof Helt #ifndef OPTi93X
583e6960e19SKrzysztof Helt 	value = snd_opti9xx_read(chip, OPTi9XX_MC_REG(1));
584e6960e19SKrzysztof Helt 	if (value != 0xff && value != inb(chip->mc_base + OPTi9XX_MC_REG(1)))
585e6960e19SKrzysztof Helt 		if (value == snd_opti9xx_read(chip, OPTi9XX_MC_REG(1)))
586e6960e19SKrzysztof Helt 			return 0;
587e6960e19SKrzysztof Helt #else	/* OPTi93X */
588e6960e19SKrzysztof Helt 	chip->res_mc_indir = request_region(chip->mc_indir_index,
589e6960e19SKrzysztof Helt 					    chip->mc_indir_size,
590e6960e19SKrzysztof Helt 					    "OPTi93x MC");
591e6960e19SKrzysztof Helt 	if (chip->res_mc_indir == NULL)
592e6960e19SKrzysztof Helt 		return -EBUSY;
593e6960e19SKrzysztof Helt 
594e6960e19SKrzysztof Helt 	spin_lock_irqsave(&chip->lock, flags);
595e6960e19SKrzysztof Helt 	outb(chip->password, chip->mc_base + chip->pwd_reg);
596e6960e19SKrzysztof Helt 	outb(((chip->mc_indir_index & 0x1f0) >> 4), chip->mc_base);
597e6960e19SKrzysztof Helt 	spin_unlock_irqrestore(&chip->lock, flags);
598e6960e19SKrzysztof Helt 
599e6960e19SKrzysztof Helt 	value = snd_opti9xx_read(chip, OPTi9XX_MC_REG(7));
600e6960e19SKrzysztof Helt 	snd_opti9xx_write(chip, OPTi9XX_MC_REG(7), 0xff - value);
601e6960e19SKrzysztof Helt 	if (snd_opti9xx_read(chip, OPTi9XX_MC_REG(7)) == 0xff - value)
602e6960e19SKrzysztof Helt 		return 0;
603e6960e19SKrzysztof Helt 
604e6960e19SKrzysztof Helt 	release_and_free_resource(chip->res_mc_indir);
605e6960e19SKrzysztof Helt 	chip->res_mc_indir = NULL;
606e6960e19SKrzysztof Helt #endif	/* OPTi93X */
607e6960e19SKrzysztof Helt 	release_and_free_resource(chip->res_mc_base);
608e6960e19SKrzysztof Helt 	chip->res_mc_base = NULL;
609e6960e19SKrzysztof Helt 
610e6960e19SKrzysztof Helt 	return -ENODEV;
611e6960e19SKrzysztof Helt }
612e6960e19SKrzysztof Helt 
6135e24c1c1STakashi Iwai static int __devinit snd_card_opti9xx_detect(struct snd_card *card,
6145e24c1c1STakashi Iwai 					     struct snd_opti9xx *chip)
6151da177e4SLinus Torvalds {
6161da177e4SLinus Torvalds 	int i, err;
6171da177e4SLinus Torvalds 
6181da177e4SLinus Torvalds #ifndef OPTi93X
6191da177e4SLinus Torvalds 	for (i = OPTi9XX_HW_82C928; i < OPTi9XX_HW_82C930; i++) {
620e6960e19SKrzysztof Helt #else
6211da177e4SLinus Torvalds 	for (i = OPTi9XX_HW_82C931; i >= OPTi9XX_HW_82C930; i--) {
622e6960e19SKrzysztof Helt #endif
623e6960e19SKrzysztof Helt 		err = snd_opti9xx_init(chip, i);
624e6960e19SKrzysztof Helt 		if (err < 0)
6251da177e4SLinus Torvalds 			return err;
6261da177e4SLinus Torvalds 
627e6960e19SKrzysztof Helt 		err = snd_opti9xx_read_check(chip);
628e6960e19SKrzysztof Helt 		if (err == 0)
6291da177e4SLinus Torvalds 			return 1;
630e6960e19SKrzysztof Helt #ifdef OPTi93X
631e6960e19SKrzysztof Helt 		chip->mc_indir_index = 0;
632e6960e19SKrzysztof Helt #endif
6331da177e4SLinus Torvalds 	}
6341da177e4SLinus Torvalds 	return -ENODEV;
6351da177e4SLinus Torvalds }
6361da177e4SLinus Torvalds 
6371da177e4SLinus Torvalds #ifdef CONFIG_PNP
6385e24c1c1STakashi Iwai static int __devinit snd_card_opti9xx_pnp(struct snd_opti9xx *chip,
6395e24c1c1STakashi Iwai 					  struct pnp_card_link *card,
6401da177e4SLinus Torvalds 					  const struct pnp_card_device_id *pid)
6411da177e4SLinus Torvalds {
6421da177e4SLinus Torvalds 	struct pnp_dev *pdev;
6431da177e4SLinus Torvalds 	int err;
6441da177e4SLinus Torvalds 
6451da177e4SLinus Torvalds 	chip->dev = pnp_request_card_device(card, pid->devs[0].id, NULL);
646109c53f8SRene Herman 	if (chip->dev == NULL)
6471da177e4SLinus Torvalds 		return -EBUSY;
648109c53f8SRene Herman 
6491da177e4SLinus Torvalds 	chip->devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL);
6501da177e4SLinus Torvalds 
6511da177e4SLinus Torvalds 	pdev = chip->dev;
6521da177e4SLinus Torvalds 
6531da177e4SLinus Torvalds 	err = pnp_activate_dev(pdev);
6541da177e4SLinus Torvalds 	if (err < 0) {
6551da177e4SLinus Torvalds 		snd_printk(KERN_ERR "AUDIO pnp configure failure: %d\n", err);
6561da177e4SLinus Torvalds 		return err;
6571da177e4SLinus Torvalds 	}
6581da177e4SLinus Torvalds 
6591da177e4SLinus Torvalds #ifdef OPTi93X
6601da177e4SLinus Torvalds 	port = pnp_port_start(pdev, 0) - 4;
6611ea73412STakashi Iwai 	fm_port = pnp_port_start(pdev, 1) + 8;
662e6960e19SKrzysztof Helt 	chip->mc_indir_index = pnp_port_start(pdev, 3) + 2;
663e6960e19SKrzysztof Helt 	chip->mc_indir_size = pnp_port_len(pdev, 3) - 2;
6641da177e4SLinus Torvalds #else
6651da177e4SLinus Torvalds 	if (pid->driver_data != 0x0924)
6661da177e4SLinus Torvalds 		port = pnp_port_start(pdev, 1);
6671ea73412STakashi Iwai 	fm_port = pnp_port_start(pdev, 2) + 8;
6681da177e4SLinus Torvalds #endif	/* OPTi93X */
6691da177e4SLinus Torvalds 	irq = pnp_irq(pdev, 0);
6701da177e4SLinus Torvalds 	dma1 = pnp_dma(pdev, 0);
6711da177e4SLinus Torvalds #if defined(CS4231) || defined(OPTi93X)
6721da177e4SLinus Torvalds 	dma2 = pnp_dma(pdev, 1);
6731da177e4SLinus Torvalds #endif	/* CS4231 || OPTi93X */
6741da177e4SLinus Torvalds 
6751da177e4SLinus Torvalds 	pdev = chip->devmpu;
6761da177e4SLinus Torvalds 	if (pdev && mpu_port > 0) {
6771da177e4SLinus Torvalds 		err = pnp_activate_dev(pdev);
6781da177e4SLinus Torvalds 		if (err < 0) {
6791da177e4SLinus Torvalds 			snd_printk(KERN_ERR "AUDIO pnp configure failure\n");
6801da177e4SLinus Torvalds 			mpu_port = -1;
6811da177e4SLinus Torvalds 			chip->devmpu = NULL;
6821da177e4SLinus Torvalds 		} else {
6831da177e4SLinus Torvalds 			mpu_port = pnp_port_start(pdev, 0);
6841da177e4SLinus Torvalds 			mpu_irq = pnp_irq(pdev, 0);
6851da177e4SLinus Torvalds 		}
6861da177e4SLinus Torvalds 	}
6871da177e4SLinus Torvalds 	return pid->driver_data;
6881da177e4SLinus Torvalds }
6891da177e4SLinus Torvalds #endif	/* CONFIG_PNP */
6901da177e4SLinus Torvalds 
691346c7a68STakashi Iwai static void snd_card_opti9xx_free(struct snd_card *card)
6921da177e4SLinus Torvalds {
69399a0b768STakashi Iwai 	struct snd_opti9xx *chip = card->private_data;
6941da177e4SLinus Torvalds 
6959f240a55SKrzysztof Helt 	if (chip) {
6969f240a55SKrzysztof Helt #ifdef OPTi93X
697*5f60e496SKrzysztof Helt 		if (chip->irq > 0) {
698*5f60e496SKrzysztof Helt 			disable_irq(chip->irq);
699*5f60e496SKrzysztof Helt 			free_irq(chip->irq, chip);
7009f240a55SKrzysztof Helt 		}
701e6960e19SKrzysztof Helt 		release_and_free_resource(chip->res_mc_indir);
7029f240a55SKrzysztof Helt #endif
703b1d5776dSTakashi Iwai 		release_and_free_resource(chip->res_mc_base);
7041da177e4SLinus Torvalds 	}
7059f240a55SKrzysztof Helt }
7061da177e4SLinus Torvalds 
7075e24c1c1STakashi Iwai static int __devinit snd_opti9xx_probe(struct snd_card *card)
7081da177e4SLinus Torvalds {
7091da177e4SLinus Torvalds 	static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1};
7101da177e4SLinus Torvalds 	int error;
711d8ea2393SKrzysztof Helt 	int xdma2;
71299a0b768STakashi Iwai 	struct snd_opti9xx *chip = card->private_data;
7137779f75fSKrzysztof Helt 	struct snd_wss *codec;
7149f240a55SKrzysztof Helt #ifdef CS4231
715346c7a68STakashi Iwai 	struct snd_timer *timer;
7169f240a55SKrzysztof Helt #endif
717346c7a68STakashi Iwai 	struct snd_pcm *pcm;
718346c7a68STakashi Iwai 	struct snd_rawmidi *rmidi;
719346c7a68STakashi Iwai 	struct snd_hwdep *synth;
7201da177e4SLinus Torvalds 
7211da177e4SLinus Torvalds #if defined(CS4231) || defined(OPTi93X)
722d8ea2393SKrzysztof Helt 	xdma2 = dma2;
723a0d9274cSRene Herman #else
724d8ea2393SKrzysztof Helt 	xdma2 = -1;
7251da177e4SLinus Torvalds #endif
7261da177e4SLinus Torvalds 
727d8ea2393SKrzysztof Helt 	if (port == SNDRV_AUTO_PORT) {
728d8ea2393SKrzysztof Helt 		port = snd_legacy_find_free_ioport(possible_ports, 4);
729d8ea2393SKrzysztof Helt 		if (port < 0) {
7304c9f1d3eSTakashi Iwai 			snd_printk(KERN_ERR "unable to find a free WSS port\n");
7311da177e4SLinus Torvalds 			return -EBUSY;
7321da177e4SLinus Torvalds 		}
7331da177e4SLinus Torvalds 	}
734d8ea2393SKrzysztof Helt 	error = snd_opti9xx_configure(chip, port, irq, dma1, xdma2,
735d8ea2393SKrzysztof Helt 				      mpu_port, mpu_irq);
7367779f75fSKrzysztof Helt 	if (error)
7371da177e4SLinus Torvalds 		return error;
7381da177e4SLinus Torvalds 
739d8ea2393SKrzysztof Helt 	error = snd_wss_create(card, port + 4, -1, irq, dma1, xdma2,
740a0d9274cSRene Herman #ifdef OPTi93X
7417779f75fSKrzysztof Helt 			       WSS_HW_OPTI93X, WSS_HWSHARE_IRQ,
742a0d9274cSRene Herman #else
743a0d9274cSRene Herman 			       WSS_HW_DETECT, 0,
7449f240a55SKrzysztof Helt #endif
7457779f75fSKrzysztof Helt 			       &codec);
7467779f75fSKrzysztof Helt 	if (error < 0)
7471da177e4SLinus Torvalds 		return error;
7489f240a55SKrzysztof Helt #ifdef OPTi93X
7499f240a55SKrzysztof Helt 	chip->codec = codec;
7509f240a55SKrzysztof Helt #endif
751ead893c0SKrzysztof Helt 	error = snd_wss_pcm(codec, 0, &pcm);
7525664daa1SKrzysztof Helt 	if (error < 0)
7535664daa1SKrzysztof Helt 		return error;
7547779f75fSKrzysztof Helt 	error = snd_wss_mixer(codec);
7557779f75fSKrzysztof Helt 	if (error < 0)
7561da177e4SLinus Torvalds 		return error;
7579f240a55SKrzysztof Helt #ifdef CS4231
7587779f75fSKrzysztof Helt 	error = snd_wss_timer(codec, 0, &timer);
7597779f75fSKrzysztof Helt 	if (error < 0)
7601da177e4SLinus Torvalds 		return error;
7615664daa1SKrzysztof Helt #endif
7625664daa1SKrzysztof Helt #ifdef OPTi93X
763d8ea2393SKrzysztof Helt 	error = request_irq(irq, snd_opti93x_interrupt,
764*5f60e496SKrzysztof Helt 			    IRQF_DISABLED, DEV_NAME" - WSS", chip);
7659f240a55SKrzysztof Helt 	if (error < 0) {
766*5f60e496SKrzysztof Helt 		snd_printk(KERN_ERR "opti9xx: can't grab IRQ %d\n", irq);
7679f240a55SKrzysztof Helt 		return error;
7689f240a55SKrzysztof Helt 	}
7699f240a55SKrzysztof Helt #endif
770d8ea2393SKrzysztof Helt 	chip->irq = irq;
7711da177e4SLinus Torvalds 	strcpy(card->driver, chip->name);
7721da177e4SLinus Torvalds 	sprintf(card->shortname, "OPTi %s", card->driver);
7731da177e4SLinus Torvalds #if defined(CS4231) || defined(OPTi93X)
7741da177e4SLinus Torvalds 	sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d",
775d8ea2393SKrzysztof Helt 		card->shortname, pcm->name, port + 4, irq, dma1, xdma2);
7761da177e4SLinus Torvalds #else
7771da177e4SLinus Torvalds 	sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d",
778d8ea2393SKrzysztof Helt 		card->shortname, pcm->name, port + 4, irq, dma1);
7791da177e4SLinus Torvalds #endif	/* CS4231 || OPTi93X */
7801da177e4SLinus Torvalds 
781d8ea2393SKrzysztof Helt 	if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT)
7821da177e4SLinus Torvalds 		rmidi = NULL;
783d8ea2393SKrzysztof Helt 	else {
784d8ea2393SKrzysztof Helt 		error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
785d8ea2393SKrzysztof Helt 				mpu_port, 0, mpu_irq, IRQF_DISABLED, &rmidi);
786d8ea2393SKrzysztof Helt 		if (error)
78799a0b768STakashi Iwai 			snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n",
788d8ea2393SKrzysztof Helt 				   mpu_port);
789d8ea2393SKrzysztof Helt 	}
7901da177e4SLinus Torvalds 
791d8ea2393SKrzysztof Helt 	if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) {
792346c7a68STakashi Iwai 		struct snd_opl3 *opl3 = NULL;
7931da177e4SLinus Torvalds #ifndef OPTi93X
7941da177e4SLinus Torvalds 		if (chip->hardware == OPTi9XX_HW_82C928 ||
7951da177e4SLinus Torvalds 		    chip->hardware == OPTi9XX_HW_82C929 ||
7961da177e4SLinus Torvalds 		    chip->hardware == OPTi9XX_HW_82C924) {
797346c7a68STakashi Iwai 			struct snd_opl4 *opl4;
7981da177e4SLinus Torvalds 			/* assume we have an OPL4 */
7991da177e4SLinus Torvalds 			snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(2),
8001da177e4SLinus Torvalds 					       0x20, 0x20);
801d8ea2393SKrzysztof Helt 			if (snd_opl4_create(card, fm_port, fm_port - 8,
8021da177e4SLinus Torvalds 					    2, &opl3, &opl4) < 0) {
8031da177e4SLinus Torvalds 				/* no luck, use OPL3 instead */
8041da177e4SLinus Torvalds 				snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(2),
8051da177e4SLinus Torvalds 						       0x00, 0x20);
8061da177e4SLinus Torvalds 			}
8071da177e4SLinus Torvalds 		}
8081da177e4SLinus Torvalds #endif	/* !OPTi93X */
809d8ea2393SKrzysztof Helt 		if (!opl3 && snd_opl3_create(card, fm_port, fm_port + 2,
8101da177e4SLinus Torvalds 					     OPL3_HW_AUTO, 0, &opl3) < 0) {
81199a0b768STakashi Iwai 			snd_printk(KERN_WARNING "no OPL device at 0x%lx-0x%lx\n",
812d8ea2393SKrzysztof Helt 				   fm_port, fm_port + 4 - 1);
8131da177e4SLinus Torvalds 		}
8141da177e4SLinus Torvalds 		if (opl3) {
815aa9c293aSKrzysztof Helt 			error = snd_opl3_hwdep_new(opl3, 0, 1, &synth);
816aa9c293aSKrzysztof Helt 			if (error < 0)
8171da177e4SLinus Torvalds 				return error;
8181da177e4SLinus Torvalds 		}
8191da177e4SLinus Torvalds 	}
8201da177e4SLinus Torvalds 
82199a0b768STakashi Iwai 	return snd_card_register(card);
82299a0b768STakashi Iwai }
82399a0b768STakashi Iwai 
8243e7fb9f7STakashi Iwai static int snd_opti9xx_card_new(struct snd_card **cardp)
82599a0b768STakashi Iwai {
82699a0b768STakashi Iwai 	struct snd_card *card;
827b1a0aac0STakashi Iwai 	int err;
82899a0b768STakashi Iwai 
829c95eadd2STakashi Iwai 	err = snd_card_create(index, id, THIS_MODULE,
830c95eadd2STakashi Iwai 			      sizeof(struct snd_opti9xx), &card);
831c95eadd2STakashi Iwai 	if (err < 0)
8323e7fb9f7STakashi Iwai 		return err;
83399a0b768STakashi Iwai 	card->private_free = snd_card_opti9xx_free;
8343e7fb9f7STakashi Iwai 	*cardp = card;
8353e7fb9f7STakashi Iwai 	return 0;
83699a0b768STakashi Iwai }
83799a0b768STakashi Iwai 
8385e24c1c1STakashi Iwai static int __devinit snd_opti9xx_isa_match(struct device *devptr,
8395e24c1c1STakashi Iwai 					   unsigned int dev)
8405e24c1c1STakashi Iwai {
841101f6f4bSTakashi Iwai #ifdef CONFIG_PNP
8425e24c1c1STakashi Iwai 	if (snd_opti9xx_pnp_is_probed)
8435e24c1c1STakashi Iwai 		return 0;
8445e24c1c1STakashi Iwai 	if (isapnp)
8455e24c1c1STakashi Iwai 		return 0;
846101f6f4bSTakashi Iwai #endif
8475e24c1c1STakashi Iwai 	return 1;
8485e24c1c1STakashi Iwai }
8495e24c1c1STakashi Iwai 
8505e24c1c1STakashi Iwai static int __devinit snd_opti9xx_isa_probe(struct device *devptr,
8515e24c1c1STakashi Iwai 					   unsigned int dev)
85299a0b768STakashi Iwai {
85399a0b768STakashi Iwai 	struct snd_card *card;
85499a0b768STakashi Iwai 	int error;
85599a0b768STakashi Iwai 	static long possible_mpu_ports[] = {0x300, 0x310, 0x320, 0x330, -1};
85699a0b768STakashi Iwai #ifdef OPTi93X
85799a0b768STakashi Iwai 	static int possible_irqs[] = {5, 9, 10, 11, 7, -1};
85899a0b768STakashi Iwai #else
85999a0b768STakashi Iwai 	static int possible_irqs[] = {9, 10, 11, 7, -1};
86099a0b768STakashi Iwai #endif	/* OPTi93X */
86199a0b768STakashi Iwai 	static int possible_mpu_irqs[] = {5, 9, 10, 7, -1};
86299a0b768STakashi Iwai 	static int possible_dma1s[] = {3, 1, 0, -1};
86399a0b768STakashi Iwai #if defined(CS4231) || defined(OPTi93X)
86499a0b768STakashi Iwai 	static int possible_dma2s[][2] = {{1,-1}, {0,-1}, {-1,-1}, {0,-1}};
86599a0b768STakashi Iwai #endif	/* CS4231 || OPTi93X */
86699a0b768STakashi Iwai 
86799a0b768STakashi Iwai 	if (mpu_port == SNDRV_AUTO_PORT) {
86899a0b768STakashi Iwai 		if ((mpu_port = snd_legacy_find_free_ioport(possible_mpu_ports, 2)) < 0) {
86999a0b768STakashi Iwai 			snd_printk(KERN_ERR "unable to find a free MPU401 port\n");
87099a0b768STakashi Iwai 			return -EBUSY;
87199a0b768STakashi Iwai 		}
87299a0b768STakashi Iwai 	}
87399a0b768STakashi Iwai 	if (irq == SNDRV_AUTO_IRQ) {
87499a0b768STakashi Iwai 		if ((irq = snd_legacy_find_free_irq(possible_irqs)) < 0) {
87599a0b768STakashi Iwai 			snd_printk(KERN_ERR "unable to find a free IRQ\n");
87699a0b768STakashi Iwai 			return -EBUSY;
87799a0b768STakashi Iwai 		}
87899a0b768STakashi Iwai 	}
87999a0b768STakashi Iwai 	if (mpu_irq == SNDRV_AUTO_IRQ) {
88099a0b768STakashi Iwai 		if ((mpu_irq = snd_legacy_find_free_irq(possible_mpu_irqs)) < 0) {
88199a0b768STakashi Iwai 			snd_printk(KERN_ERR "unable to find a free MPU401 IRQ\n");
88299a0b768STakashi Iwai 			return -EBUSY;
88399a0b768STakashi Iwai 		}
88499a0b768STakashi Iwai 	}
88599a0b768STakashi Iwai 	if (dma1 == SNDRV_AUTO_DMA) {
88699a0b768STakashi Iwai 		if ((dma1 = snd_legacy_find_free_dma(possible_dma1s)) < 0) {
88799a0b768STakashi Iwai 			snd_printk(KERN_ERR "unable to find a free DMA1\n");
88899a0b768STakashi Iwai 			return -EBUSY;
88999a0b768STakashi Iwai 		}
89099a0b768STakashi Iwai 	}
89199a0b768STakashi Iwai #if defined(CS4231) || defined(OPTi93X)
89299a0b768STakashi Iwai 	if (dma2 == SNDRV_AUTO_DMA) {
89399a0b768STakashi Iwai 		if ((dma2 = snd_legacy_find_free_dma(possible_dma2s[dma1 % 4])) < 0) {
8944c9f1d3eSTakashi Iwai 			snd_printk(KERN_ERR "unable to find a free DMA2\n");
89599a0b768STakashi Iwai 			return -EBUSY;
89699a0b768STakashi Iwai 		}
89799a0b768STakashi Iwai 	}
89899a0b768STakashi Iwai #endif
89999a0b768STakashi Iwai 
9003e7fb9f7STakashi Iwai 	error = snd_opti9xx_card_new(&card);
9013e7fb9f7STakashi Iwai 	if (error < 0)
9023e7fb9f7STakashi Iwai 		return error;
90399a0b768STakashi Iwai 
90499a0b768STakashi Iwai 	if ((error = snd_card_opti9xx_detect(card, card->private_data)) < 0) {
9051da177e4SLinus Torvalds 		snd_card_free(card);
9061da177e4SLinus Torvalds 		return error;
9071da177e4SLinus Torvalds 	}
9085e24c1c1STakashi Iwai 	snd_card_set_dev(card, devptr);
90999a0b768STakashi Iwai 	if ((error = snd_opti9xx_probe(card)) < 0) {
91099a0b768STakashi Iwai 		snd_card_free(card);
91199a0b768STakashi Iwai 		return error;
91299a0b768STakashi Iwai 	}
9135e24c1c1STakashi Iwai 	dev_set_drvdata(devptr, card);
9141da177e4SLinus Torvalds 	return 0;
9151da177e4SLinus Torvalds }
9161da177e4SLinus Torvalds 
9175e24c1c1STakashi Iwai static int __devexit snd_opti9xx_isa_remove(struct device *devptr,
9185e24c1c1STakashi Iwai 					    unsigned int dev)
91999a0b768STakashi Iwai {
9205e24c1c1STakashi Iwai 	snd_card_free(dev_get_drvdata(devptr));
9215e24c1c1STakashi Iwai 	dev_set_drvdata(devptr, NULL);
92299a0b768STakashi Iwai 	return 0;
92399a0b768STakashi Iwai }
92499a0b768STakashi Iwai 
9255e24c1c1STakashi Iwai static struct isa_driver snd_opti9xx_driver = {
9265e24c1c1STakashi Iwai 	.match		= snd_opti9xx_isa_match,
9275e24c1c1STakashi Iwai 	.probe		= snd_opti9xx_isa_probe,
9285e24c1c1STakashi Iwai 	.remove		= __devexit_p(snd_opti9xx_isa_remove),
92999a0b768STakashi Iwai 	/* FIXME: suspend/resume */
93099a0b768STakashi Iwai 	.driver		= {
93183c51c0aSRene Herman 		.name	= DEV_NAME
93299a0b768STakashi Iwai 	},
93399a0b768STakashi Iwai };
93499a0b768STakashi Iwai 
9351da177e4SLinus Torvalds #ifdef CONFIG_PNP
9365e24c1c1STakashi Iwai static int __devinit snd_opti9xx_pnp_probe(struct pnp_card_link *pcard,
93799a0b768STakashi Iwai 					   const struct pnp_card_device_id *pid)
93899a0b768STakashi Iwai {
93999a0b768STakashi Iwai 	struct snd_card *card;
94099a0b768STakashi Iwai 	int error, hw;
94199a0b768STakashi Iwai 	struct snd_opti9xx *chip;
94299a0b768STakashi Iwai 
94399a0b768STakashi Iwai 	if (snd_opti9xx_pnp_is_probed)
94499a0b768STakashi Iwai 		return -EBUSY;
94599a0b768STakashi Iwai 	if (! isapnp)
94699a0b768STakashi Iwai 		return -ENODEV;
9473e7fb9f7STakashi Iwai 	error = snd_opti9xx_card_new(&card);
9483e7fb9f7STakashi Iwai 	if (error < 0)
9493e7fb9f7STakashi Iwai 		return error;
95099a0b768STakashi Iwai 	chip = card->private_data;
95199a0b768STakashi Iwai 
95299a0b768STakashi Iwai 	hw = snd_card_opti9xx_pnp(chip, pcard, pid);
95399a0b768STakashi Iwai 	switch (hw) {
95499a0b768STakashi Iwai 	case 0x0924:
95599a0b768STakashi Iwai 		hw = OPTi9XX_HW_82C924;
95699a0b768STakashi Iwai 		break;
95799a0b768STakashi Iwai 	case 0x0925:
95899a0b768STakashi Iwai 		hw = OPTi9XX_HW_82C925;
95999a0b768STakashi Iwai 		break;
96099a0b768STakashi Iwai 	case 0x0931:
96199a0b768STakashi Iwai 		hw = OPTi9XX_HW_82C931;
96299a0b768STakashi Iwai 		break;
96399a0b768STakashi Iwai 	default:
96499a0b768STakashi Iwai 		snd_card_free(card);
96599a0b768STakashi Iwai 		return -ENODEV;
96699a0b768STakashi Iwai 	}
96799a0b768STakashi Iwai 
96899a0b768STakashi Iwai 	if ((error = snd_opti9xx_init(chip, hw))) {
96999a0b768STakashi Iwai 		snd_card_free(card);
97099a0b768STakashi Iwai 		return error;
97199a0b768STakashi Iwai 	}
97299a0b768STakashi Iwai 	if (hw <= OPTi9XX_HW_82C930)
97399a0b768STakashi Iwai 		chip->mc_base -= 0x80;
974e6960e19SKrzysztof Helt 
975e6960e19SKrzysztof Helt 	error = snd_opti9xx_read_check(chip);
976e6960e19SKrzysztof Helt 	if (error) {
977e6960e19SKrzysztof Helt 		snd_printk(KERN_ERR "OPTI chip not found\n");
978e6960e19SKrzysztof Helt 		snd_card_free(card);
979e6960e19SKrzysztof Helt 		return error;
980e6960e19SKrzysztof Helt 	}
98199a0b768STakashi Iwai 	snd_card_set_dev(card, &pcard->card->dev);
98299a0b768STakashi Iwai 	if ((error = snd_opti9xx_probe(card)) < 0) {
98399a0b768STakashi Iwai 		snd_card_free(card);
98499a0b768STakashi Iwai 		return error;
98599a0b768STakashi Iwai 	}
98699a0b768STakashi Iwai 	pnp_set_card_drvdata(pcard, card);
98799a0b768STakashi Iwai 	snd_opti9xx_pnp_is_probed = 1;
98899a0b768STakashi Iwai 	return 0;
98999a0b768STakashi Iwai }
99099a0b768STakashi Iwai 
9911da177e4SLinus Torvalds static void __devexit snd_opti9xx_pnp_remove(struct pnp_card_link * pcard)
9921da177e4SLinus Torvalds {
99399a0b768STakashi Iwai 	snd_card_free(pnp_get_card_drvdata(pcard));
99499a0b768STakashi Iwai 	pnp_set_card_drvdata(pcard, NULL);
99599a0b768STakashi Iwai 	snd_opti9xx_pnp_is_probed = 0;
9961da177e4SLinus Torvalds }
9971da177e4SLinus Torvalds 
9981da177e4SLinus Torvalds static struct pnp_card_driver opti9xx_pnpc_driver = {
9991da177e4SLinus Torvalds 	.flags		= PNP_DRIVER_RES_DISABLE,
10001da177e4SLinus Torvalds 	.name		= "opti9xx",
10011da177e4SLinus Torvalds 	.id_table	= snd_opti9xx_pnpids,
100299a0b768STakashi Iwai 	.probe		= snd_opti9xx_pnp_probe,
10031da177e4SLinus Torvalds 	.remove		= __devexit_p(snd_opti9xx_pnp_remove),
10041da177e4SLinus Torvalds };
10051da177e4SLinus Torvalds #endif
10061da177e4SLinus Torvalds 
100799a0b768STakashi Iwai #ifdef OPTi93X
100899a0b768STakashi Iwai #define CHIP_NAME	"82C93x"
100999a0b768STakashi Iwai #else
101099a0b768STakashi Iwai #define CHIP_NAME	"82C92x"
101199a0b768STakashi Iwai #endif
101299a0b768STakashi Iwai 
10131da177e4SLinus Torvalds static int __init alsa_card_opti9xx_init(void)
10141da177e4SLinus Torvalds {
10150bbbc4caSTakashi Iwai #ifdef CONFIG_PNP
101699a0b768STakashi Iwai 	pnp_register_card_driver(&opti9xx_pnpc_driver);
101799a0b768STakashi Iwai 	if (snd_opti9xx_pnp_is_probed)
10181da177e4SLinus Torvalds 		return 0;
1019101f6f4bSTakashi Iwai 	pnp_unregister_card_driver(&opti9xx_pnpc_driver);
10200bbbc4caSTakashi Iwai #endif
10215e24c1c1STakashi Iwai 	return isa_register_driver(&snd_opti9xx_driver, 1);
10221da177e4SLinus Torvalds }
10231da177e4SLinus Torvalds 
10241da177e4SLinus Torvalds static void __exit alsa_card_opti9xx_exit(void)
10251da177e4SLinus Torvalds {
1026f7a9275dSClemens Ladisch 	if (!snd_opti9xx_pnp_is_probed) {
10275e24c1c1STakashi Iwai 		isa_unregister_driver(&snd_opti9xx_driver);
10285e24c1c1STakashi Iwai 		return;
1029f7a9275dSClemens Ladisch 	}
10300bbbc4caSTakashi Iwai #ifdef CONFIG_PNP
10311da177e4SLinus Torvalds 	pnp_unregister_card_driver(&opti9xx_pnpc_driver);
10320bbbc4caSTakashi Iwai #endif
10331da177e4SLinus Torvalds }
10341da177e4SLinus Torvalds 
10351da177e4SLinus Torvalds module_init(alsa_card_opti9xx_init)
10361da177e4SLinus Torvalds module_exit(alsa_card_opti9xx_exit)
1037