xref: /linux/sound/isa/sb/jazz16.c (revision 44eba3e82b35ae796826a65d8040001582adc10a)
1ad8decb7SKrzysztof Helt 
2ad8decb7SKrzysztof Helt /*
3ad8decb7SKrzysztof Helt  * jazz16.c - driver for Media Vision Jazz16 based soundcards.
4ad8decb7SKrzysztof Helt  * Copyright (C) 2009 Krzysztof Helt <krzysztof.h1@wp.pl>
5ad8decb7SKrzysztof Helt  * Based on patches posted by Rask Ingemann Lambertsen and Rene Herman.
6ad8decb7SKrzysztof Helt  * Based on OSS Sound Blaster driver.
7ad8decb7SKrzysztof Helt  *
8ad8decb7SKrzysztof Helt  * This file is subject to the terms and conditions of the GNU General Public
9ad8decb7SKrzysztof Helt  * License.  See the file COPYING in the main directory of this archive for
10ad8decb7SKrzysztof Helt  * more details.
11ad8decb7SKrzysztof Helt  *
12ad8decb7SKrzysztof Helt  */
13ad8decb7SKrzysztof Helt 
14ad8decb7SKrzysztof Helt #include <linux/init.h>
15ad8decb7SKrzysztof Helt #include <linux/module.h>
16ad8decb7SKrzysztof Helt #include <linux/io.h>
17ad8decb7SKrzysztof Helt #include <asm/dma.h>
18ad8decb7SKrzysztof Helt #include <linux/isa.h>
19ad8decb7SKrzysztof Helt #include <sound/core.h>
20ad8decb7SKrzysztof Helt #include <sound/mpu401.h>
21ad8decb7SKrzysztof Helt #include <sound/opl3.h>
22ad8decb7SKrzysztof Helt #include <sound/sb.h>
23ad8decb7SKrzysztof Helt #define SNDRV_LEGACY_FIND_FREE_IRQ
24ad8decb7SKrzysztof Helt #define SNDRV_LEGACY_FIND_FREE_DMA
25ad8decb7SKrzysztof Helt #include <sound/initval.h>
26ad8decb7SKrzysztof Helt 
27ad8decb7SKrzysztof Helt #define PFX "jazz16: "
28ad8decb7SKrzysztof Helt 
29ad8decb7SKrzysztof Helt MODULE_DESCRIPTION("Media Vision Jazz16");
30ad8decb7SKrzysztof Helt MODULE_SUPPORTED_DEVICE("{{Media Vision ??? },"
31ad8decb7SKrzysztof Helt 		"{RTL,RTL3000}}");
32ad8decb7SKrzysztof Helt 
33ad8decb7SKrzysztof Helt MODULE_AUTHOR("Krzysztof Helt <krzysztof.h1@wp.pl>");
34ad8decb7SKrzysztof Helt MODULE_LICENSE("GPL");
35ad8decb7SKrzysztof Helt 
36ad8decb7SKrzysztof Helt static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
37ad8decb7SKrzysztof Helt static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
38ad8decb7SKrzysztof Helt static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;	/* Enable this card */
39ad8decb7SKrzysztof Helt static unsigned long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
40ad8decb7SKrzysztof Helt static unsigned long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
41ad8decb7SKrzysztof Helt static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
42ad8decb7SKrzysztof Helt static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
43ad8decb7SKrzysztof Helt static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
44ad8decb7SKrzysztof Helt static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
45ad8decb7SKrzysztof Helt 
46ad8decb7SKrzysztof Helt module_param_array(index, int, NULL, 0444);
47ad8decb7SKrzysztof Helt MODULE_PARM_DESC(index, "Index value for Media Vision Jazz16 based soundcard.");
48ad8decb7SKrzysztof Helt module_param_array(id, charp, NULL, 0444);
49ad8decb7SKrzysztof Helt MODULE_PARM_DESC(id, "ID string for Media Vision Jazz16 based soundcard.");
50ad8decb7SKrzysztof Helt module_param_array(enable, bool, NULL, 0444);
51ad8decb7SKrzysztof Helt MODULE_PARM_DESC(enable, "Enable Media Vision Jazz16 based soundcard.");
52ad8decb7SKrzysztof Helt module_param_array(port, long, NULL, 0444);
53ad8decb7SKrzysztof Helt MODULE_PARM_DESC(port, "Port # for jazz16 driver.");
54ad8decb7SKrzysztof Helt module_param_array(mpu_port, long, NULL, 0444);
55ad8decb7SKrzysztof Helt MODULE_PARM_DESC(mpu_port, "MPU-401 port # for jazz16 driver.");
56ad8decb7SKrzysztof Helt module_param_array(irq, int, NULL, 0444);
57ad8decb7SKrzysztof Helt MODULE_PARM_DESC(irq, "IRQ # for jazz16 driver.");
58ad8decb7SKrzysztof Helt module_param_array(mpu_irq, int, NULL, 0444);
59ad8decb7SKrzysztof Helt MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for jazz16 driver.");
60ad8decb7SKrzysztof Helt module_param_array(dma8, int, NULL, 0444);
61ad8decb7SKrzysztof Helt MODULE_PARM_DESC(dma8, "DMA8 # for jazz16 driver.");
62ad8decb7SKrzysztof Helt module_param_array(dma16, int, NULL, 0444);
63ad8decb7SKrzysztof Helt MODULE_PARM_DESC(dma16, "DMA16 # for jazz16 driver.");
64ad8decb7SKrzysztof Helt 
65ad8decb7SKrzysztof Helt #define SB_JAZZ16_WAKEUP	0xaf
66ad8decb7SKrzysztof Helt #define SB_JAZZ16_SET_PORTS	0x50
67ad8decb7SKrzysztof Helt #define SB_DSP_GET_JAZZ_BRD_REV	0xfa
68ad8decb7SKrzysztof Helt #define SB_JAZZ16_SET_DMAINTR	0xfb
69ad8decb7SKrzysztof Helt #define SB_DSP_GET_JAZZ_MODEL	0xfe
70ad8decb7SKrzysztof Helt 
71ad8decb7SKrzysztof Helt struct snd_card_jazz16 {
72ad8decb7SKrzysztof Helt 	struct snd_sb *chip;
73ad8decb7SKrzysztof Helt };
74ad8decb7SKrzysztof Helt 
75ad8decb7SKrzysztof Helt static irqreturn_t jazz16_interrupt(int irq, void *chip)
76ad8decb7SKrzysztof Helt {
77ad8decb7SKrzysztof Helt 	return snd_sb8dsp_interrupt(chip);
78ad8decb7SKrzysztof Helt }
79ad8decb7SKrzysztof Helt 
80ad8decb7SKrzysztof Helt static int __devinit jazz16_configure_ports(unsigned long port,
81ad8decb7SKrzysztof Helt 					    unsigned long mpu_port, int idx)
82ad8decb7SKrzysztof Helt {
83ad8decb7SKrzysztof Helt 	unsigned char val;
84ad8decb7SKrzysztof Helt 
85ad8decb7SKrzysztof Helt 	if (!request_region(0x201, 1, "jazz16 config")) {
86ad8decb7SKrzysztof Helt 		snd_printk(KERN_ERR "config port region is already in use.\n");
87ad8decb7SKrzysztof Helt 		return -EBUSY;
88ad8decb7SKrzysztof Helt 	}
89ad8decb7SKrzysztof Helt 	outb(SB_JAZZ16_WAKEUP - idx, 0x201);
90ad8decb7SKrzysztof Helt 	udelay(100);
91ad8decb7SKrzysztof Helt 	outb(SB_JAZZ16_SET_PORTS + idx, 0x201);
92ad8decb7SKrzysztof Helt 	udelay(100);
93ad8decb7SKrzysztof Helt 	val = port & 0x70;
94ad8decb7SKrzysztof Helt 	val |= (mpu_port & 0x30) >> 4;
95ad8decb7SKrzysztof Helt 	outb(val, 0x201);
96ad8decb7SKrzysztof Helt 
97ad8decb7SKrzysztof Helt 	release_region(0x201, 1);
98ad8decb7SKrzysztof Helt 	return 0;
99ad8decb7SKrzysztof Helt }
100ad8decb7SKrzysztof Helt 
101ad8decb7SKrzysztof Helt static int __devinit jazz16_detect_board(unsigned long port,
102ad8decb7SKrzysztof Helt 					 unsigned long mpu_port)
103ad8decb7SKrzysztof Helt {
104ad8decb7SKrzysztof Helt 	int err;
105ad8decb7SKrzysztof Helt 	int val;
106ad8decb7SKrzysztof Helt 	struct snd_sb chip;
107ad8decb7SKrzysztof Helt 
108ad8decb7SKrzysztof Helt 	if (!request_region(port, 0x10, "jazz16")) {
109ad8decb7SKrzysztof Helt 		snd_printk(KERN_ERR "I/O port region is already in use.\n");
110ad8decb7SKrzysztof Helt 		return -EBUSY;
111ad8decb7SKrzysztof Helt 	}
112ad8decb7SKrzysztof Helt 	/* just to call snd_sbdsp_command/reset/get_byte() */
113ad8decb7SKrzysztof Helt 	chip.port = port;
114ad8decb7SKrzysztof Helt 
115ad8decb7SKrzysztof Helt 	err = snd_sbdsp_reset(&chip);
116ad8decb7SKrzysztof Helt 	if (err < 0)
117ad8decb7SKrzysztof Helt 		for (val = 0; val < 4; val++) {
118ad8decb7SKrzysztof Helt 			err = jazz16_configure_ports(port, mpu_port, val);
119ad8decb7SKrzysztof Helt 			if (err < 0)
120ad8decb7SKrzysztof Helt 				break;
121ad8decb7SKrzysztof Helt 
122ad8decb7SKrzysztof Helt 			err = snd_sbdsp_reset(&chip);
123ad8decb7SKrzysztof Helt 			if (!err)
124ad8decb7SKrzysztof Helt 				break;
125ad8decb7SKrzysztof Helt 		}
126ad8decb7SKrzysztof Helt 	if (err < 0) {
127ad8decb7SKrzysztof Helt 		err = -ENODEV;
128ad8decb7SKrzysztof Helt 		goto err_unmap;
129ad8decb7SKrzysztof Helt 	}
130ad8decb7SKrzysztof Helt 	if (!snd_sbdsp_command(&chip, SB_DSP_GET_JAZZ_BRD_REV)) {
131ad8decb7SKrzysztof Helt 		err = -EBUSY;
132ad8decb7SKrzysztof Helt 		goto err_unmap;
133ad8decb7SKrzysztof Helt 	}
134ad8decb7SKrzysztof Helt 	val = snd_sbdsp_get_byte(&chip);
135ad8decb7SKrzysztof Helt 	if (val >= 0x30)
136ad8decb7SKrzysztof Helt 		snd_sbdsp_get_byte(&chip);
137ad8decb7SKrzysztof Helt 
138ad8decb7SKrzysztof Helt 	if ((val & 0xf0) != 0x10) {
139ad8decb7SKrzysztof Helt 		err = -ENODEV;
140ad8decb7SKrzysztof Helt 		goto err_unmap;
141ad8decb7SKrzysztof Helt 	}
142ad8decb7SKrzysztof Helt 	if (!snd_sbdsp_command(&chip, SB_DSP_GET_JAZZ_MODEL)) {
143ad8decb7SKrzysztof Helt 		err = -EBUSY;
144ad8decb7SKrzysztof Helt 		goto err_unmap;
145ad8decb7SKrzysztof Helt 	}
146ad8decb7SKrzysztof Helt 	snd_sbdsp_get_byte(&chip);
147ad8decb7SKrzysztof Helt 	err = snd_sbdsp_get_byte(&chip);
148ad8decb7SKrzysztof Helt 	snd_printd("Media Vision Jazz16 board detected: rev 0x%x, model 0x%x\n",
149ad8decb7SKrzysztof Helt 		   val, err);
150ad8decb7SKrzysztof Helt 
151ad8decb7SKrzysztof Helt 	err = 0;
152ad8decb7SKrzysztof Helt 
153ad8decb7SKrzysztof Helt err_unmap:
154ad8decb7SKrzysztof Helt 	release_region(port, 0x10);
155ad8decb7SKrzysztof Helt 	return err;
156ad8decb7SKrzysztof Helt }
157ad8decb7SKrzysztof Helt 
158ad8decb7SKrzysztof Helt static int __devinit jazz16_configure_board(struct snd_sb *chip, int mpu_irq)
159ad8decb7SKrzysztof Helt {
160ad8decb7SKrzysztof Helt 	static unsigned char jazz_irq_bits[] = { 0, 0, 2, 3, 0, 1, 0, 4,
161ad8decb7SKrzysztof Helt 						 0, 2, 5, 0, 0, 0, 0, 6 };
162ad8decb7SKrzysztof Helt 	static unsigned char jazz_dma_bits[] = { 0, 1, 0, 2, 0, 3, 0, 4 };
163ad8decb7SKrzysztof Helt 
164ad8decb7SKrzysztof Helt 	if (jazz_dma_bits[chip->dma8] == 0 ||
165ad8decb7SKrzysztof Helt 	    jazz_dma_bits[chip->dma16] == 0 ||
166ad8decb7SKrzysztof Helt 	    jazz_irq_bits[chip->irq] == 0)
167ad8decb7SKrzysztof Helt 		return -EINVAL;
168ad8decb7SKrzysztof Helt 
169ad8decb7SKrzysztof Helt 	if (!snd_sbdsp_command(chip, SB_JAZZ16_SET_DMAINTR))
170ad8decb7SKrzysztof Helt 		return -EBUSY;
171ad8decb7SKrzysztof Helt 
172ad8decb7SKrzysztof Helt 	if (!snd_sbdsp_command(chip,
173ad8decb7SKrzysztof Helt 			       jazz_dma_bits[chip->dma8] |
174ad8decb7SKrzysztof Helt 			       (jazz_dma_bits[chip->dma16] << 4)))
175ad8decb7SKrzysztof Helt 		return -EBUSY;
176ad8decb7SKrzysztof Helt 
177ad8decb7SKrzysztof Helt 	if (!snd_sbdsp_command(chip,
178ad8decb7SKrzysztof Helt 			       jazz_irq_bits[chip->irq] |
179ad8decb7SKrzysztof Helt 			       (jazz_irq_bits[mpu_irq] << 4)))
180ad8decb7SKrzysztof Helt 		return -EBUSY;
181ad8decb7SKrzysztof Helt 
182ad8decb7SKrzysztof Helt 	return 0;
183ad8decb7SKrzysztof Helt }
184ad8decb7SKrzysztof Helt 
185ad8decb7SKrzysztof Helt static int __devinit snd_jazz16_match(struct device *devptr, unsigned int dev)
186ad8decb7SKrzysztof Helt {
187ad8decb7SKrzysztof Helt 	if (!enable[dev])
188ad8decb7SKrzysztof Helt 		return 0;
189ad8decb7SKrzysztof Helt 	if (port[dev] == SNDRV_AUTO_PORT) {
190ad8decb7SKrzysztof Helt 		snd_printk(KERN_ERR "please specify port\n");
191ad8decb7SKrzysztof Helt 		return 0;
192*44eba3e8SKrzysztof Helt 	} else if (port[dev] == 0x200 || (port[dev] & ~0x270)) {
193*44eba3e8SKrzysztof Helt 		snd_printk(KERN_ERR "incorrect port specified\n");
194*44eba3e8SKrzysztof Helt 		return 0;
195*44eba3e8SKrzysztof Helt 	}
196*44eba3e8SKrzysztof Helt 	if (dma8[dev] != SNDRV_AUTO_DMA &&
197*44eba3e8SKrzysztof Helt 	    dma8[dev] != 1 && dma8[dev] != 3) {
198*44eba3e8SKrzysztof Helt 		snd_printk(KERN_ERR "dma8 must be 1 or 3\n");
199*44eba3e8SKrzysztof Helt 		return 0;
200ad8decb7SKrzysztof Helt 	}
201ad8decb7SKrzysztof Helt 	if (dma16[dev] != SNDRV_AUTO_DMA &&
202ad8decb7SKrzysztof Helt 	    dma16[dev] != 5 && dma16[dev] != 7) {
203*44eba3e8SKrzysztof Helt 		snd_printk(KERN_ERR "dma16 must be 5 or 7\n");
204*44eba3e8SKrzysztof Helt 		return 0;
205*44eba3e8SKrzysztof Helt 	}
206*44eba3e8SKrzysztof Helt 	if (mpu_port[dev] != SNDRV_AUTO_PORT &&
207*44eba3e8SKrzysztof Helt 	    (mpu_port[dev] & ~0x030) != 0x300) {
208*44eba3e8SKrzysztof Helt 		snd_printk(KERN_ERR "incorrect mpu_port specified\n");
209*44eba3e8SKrzysztof Helt 		return 0;
210*44eba3e8SKrzysztof Helt 	}
211*44eba3e8SKrzysztof Helt 	if (mpu_irq[dev] != SNDRV_AUTO_DMA &&
212*44eba3e8SKrzysztof Helt 	    mpu_irq[dev] != 2 && mpu_irq[dev] != 3 &&
213*44eba3e8SKrzysztof Helt 	    mpu_irq[dev] != 5 && mpu_irq[dev] != 7) {
214*44eba3e8SKrzysztof Helt 		snd_printk(KERN_ERR "mpu_irq must be 2, 3, 5 or 7\n");
215ad8decb7SKrzysztof Helt 		return 0;
216ad8decb7SKrzysztof Helt 	}
217ad8decb7SKrzysztof Helt 	return 1;
218ad8decb7SKrzysztof Helt }
219ad8decb7SKrzysztof Helt 
220ad8decb7SKrzysztof Helt static int __devinit snd_jazz16_probe(struct device *devptr, unsigned int dev)
221ad8decb7SKrzysztof Helt {
222ad8decb7SKrzysztof Helt 	struct snd_card *card;
223ad8decb7SKrzysztof Helt 	struct snd_card_jazz16 *jazz16;
224ad8decb7SKrzysztof Helt 	struct snd_sb *chip;
225ad8decb7SKrzysztof Helt 	struct snd_opl3 *opl3;
226ad8decb7SKrzysztof Helt 	static int possible_irqs[] = {2, 3, 5, 7, 9, 10, 15, -1};
227ad8decb7SKrzysztof Helt 	static int possible_dmas8[] = {1, 3, -1};
228ad8decb7SKrzysztof Helt 	static int possible_dmas16[] = {5, 7, -1};
229ad8decb7SKrzysztof Helt 	int err, xirq, xdma8, xdma16, xmpu_port, xmpu_irq;
230ad8decb7SKrzysztof Helt 
231ad8decb7SKrzysztof Helt 	err = snd_card_create(index[dev], id[dev], THIS_MODULE,
232ad8decb7SKrzysztof Helt 			      sizeof(struct snd_card_jazz16), &card);
233ad8decb7SKrzysztof Helt 	if (err < 0)
234ad8decb7SKrzysztof Helt 		return err;
235ad8decb7SKrzysztof Helt 
236ad8decb7SKrzysztof Helt 	jazz16 = card->private_data;
237ad8decb7SKrzysztof Helt 
238ad8decb7SKrzysztof Helt 	xirq = irq[dev];
239ad8decb7SKrzysztof Helt 	if (xirq == SNDRV_AUTO_IRQ) {
240ad8decb7SKrzysztof Helt 		xirq = snd_legacy_find_free_irq(possible_irqs);
241ad8decb7SKrzysztof Helt 		if (xirq < 0) {
242ad8decb7SKrzysztof Helt 			snd_printk(KERN_ERR "unable to find a free IRQ\n");
243ad8decb7SKrzysztof Helt 			err = -EBUSY;
244ad8decb7SKrzysztof Helt 			goto err_free;
245ad8decb7SKrzysztof Helt 		}
246ad8decb7SKrzysztof Helt 	}
247ad8decb7SKrzysztof Helt 	xdma8 = dma8[dev];
248ad8decb7SKrzysztof Helt 	if (xdma8 == SNDRV_AUTO_DMA) {
249ad8decb7SKrzysztof Helt 		xdma8 = snd_legacy_find_free_dma(possible_dmas8);
250ad8decb7SKrzysztof Helt 		if (xdma8 < 0) {
251ad8decb7SKrzysztof Helt 			snd_printk(KERN_ERR "unable to find a free DMA8\n");
252ad8decb7SKrzysztof Helt 			err = -EBUSY;
253ad8decb7SKrzysztof Helt 			goto err_free;
254ad8decb7SKrzysztof Helt 		}
255ad8decb7SKrzysztof Helt 	}
256ad8decb7SKrzysztof Helt 	xdma16 = dma16[dev];
257ad8decb7SKrzysztof Helt 	if (xdma16 == SNDRV_AUTO_DMA) {
258ad8decb7SKrzysztof Helt 		xdma16 = snd_legacy_find_free_dma(possible_dmas16);
259ad8decb7SKrzysztof Helt 		if (xdma16 < 0) {
260ad8decb7SKrzysztof Helt 			snd_printk(KERN_ERR "unable to find a free DMA16\n");
261ad8decb7SKrzysztof Helt 			err = -EBUSY;
262ad8decb7SKrzysztof Helt 			goto err_free;
263ad8decb7SKrzysztof Helt 		}
264ad8decb7SKrzysztof Helt 	}
265ad8decb7SKrzysztof Helt 
266ad8decb7SKrzysztof Helt 	xmpu_port = mpu_port[dev];
267ad8decb7SKrzysztof Helt 	if (xmpu_port == SNDRV_AUTO_PORT)
268ad8decb7SKrzysztof Helt 		xmpu_port = 0;
269ad8decb7SKrzysztof Helt 	err = jazz16_detect_board(port[dev], xmpu_port);
270ad8decb7SKrzysztof Helt 	if (err < 0) {
271ad8decb7SKrzysztof Helt 		printk(KERN_ERR "Media Vision Jazz16 board not detected\n");
272ad8decb7SKrzysztof Helt 		goto err_free;
273ad8decb7SKrzysztof Helt 	}
274ad8decb7SKrzysztof Helt 	err = snd_sbdsp_create(card, port[dev], irq[dev],
275ad8decb7SKrzysztof Helt 			       jazz16_interrupt,
276ad8decb7SKrzysztof Helt 			       dma8[dev], dma16[dev],
277ad8decb7SKrzysztof Helt 			       SB_HW_JAZZ16,
278ad8decb7SKrzysztof Helt 			       &chip);
279ad8decb7SKrzysztof Helt 	if (err < 0)
280ad8decb7SKrzysztof Helt 		goto err_free;
281ad8decb7SKrzysztof Helt 
282ad8decb7SKrzysztof Helt 	xmpu_irq = mpu_irq[dev];
283ad8decb7SKrzysztof Helt 	if (xmpu_irq == SNDRV_AUTO_IRQ || mpu_port[dev] == SNDRV_AUTO_PORT)
284ad8decb7SKrzysztof Helt 		xmpu_irq = 0;
285ad8decb7SKrzysztof Helt 	err = jazz16_configure_board(chip, xmpu_irq);
286ad8decb7SKrzysztof Helt 	if (err < 0) {
287ad8decb7SKrzysztof Helt 		printk(KERN_ERR "Media Vision Jazz16 configuration failed\n");
288ad8decb7SKrzysztof Helt 		goto err_free;
289ad8decb7SKrzysztof Helt 	}
290ad8decb7SKrzysztof Helt 
291ad8decb7SKrzysztof Helt 	jazz16->chip = chip;
292ad8decb7SKrzysztof Helt 
293ad8decb7SKrzysztof Helt 	strcpy(card->driver, "jazz16");
294ad8decb7SKrzysztof Helt 	strcpy(card->shortname, "Media Vision Jazz16");
295ad8decb7SKrzysztof Helt 	sprintf(card->longname,
296ad8decb7SKrzysztof Helt 		"Media Vision Jazz16 at 0x%lx, irq %d, dma8 %d, dma16 %d",
297ad8decb7SKrzysztof Helt 		port[dev], xirq, xdma8, xdma16);
298ad8decb7SKrzysztof Helt 
299ad8decb7SKrzysztof Helt 	err = snd_sb8dsp_pcm(chip, 0, NULL);
300ad8decb7SKrzysztof Helt 	if (err < 0)
301ad8decb7SKrzysztof Helt 		goto err_free;
302ad8decb7SKrzysztof Helt 	err = snd_sbmixer_new(chip);
303ad8decb7SKrzysztof Helt 	if (err < 0)
304ad8decb7SKrzysztof Helt 		goto err_free;
305ad8decb7SKrzysztof Helt 
306ad8decb7SKrzysztof Helt 	err = snd_opl3_create(card, chip->port, chip->port + 2,
307ad8decb7SKrzysztof Helt 			      OPL3_HW_AUTO, 1, &opl3);
308ad8decb7SKrzysztof Helt 	if (err < 0)
309ad8decb7SKrzysztof Helt 		snd_printk(KERN_WARNING "no OPL device at 0x%lx-0x%lx\n",
310ad8decb7SKrzysztof Helt 			   chip->port, chip->port + 2);
311ad8decb7SKrzysztof Helt 	else {
312ad8decb7SKrzysztof Helt 		err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
313ad8decb7SKrzysztof Helt 		if (err < 0)
314ad8decb7SKrzysztof Helt 			goto err_free;
315ad8decb7SKrzysztof Helt 	}
316ad8decb7SKrzysztof Helt 	if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
317ad8decb7SKrzysztof Helt 		if (mpu_irq[dev] == SNDRV_AUTO_IRQ)
318ad8decb7SKrzysztof Helt 			mpu_irq[dev] = -1;
319ad8decb7SKrzysztof Helt 
320ad8decb7SKrzysztof Helt 		if (snd_mpu401_uart_new(card, 0,
321ad8decb7SKrzysztof Helt 					MPU401_HW_MPU401,
322ad8decb7SKrzysztof Helt 					mpu_port[dev], 0,
323ad8decb7SKrzysztof Helt 					mpu_irq[dev],
324ad8decb7SKrzysztof Helt 					mpu_irq[dev] >= 0 ? IRQF_DISABLED : 0,
325ad8decb7SKrzysztof Helt 					NULL) < 0)
326ad8decb7SKrzysztof Helt 			snd_printk(KERN_ERR "no MPU-401 device at 0x%lx\n",
327ad8decb7SKrzysztof Helt 					mpu_port[dev]);
328ad8decb7SKrzysztof Helt 	}
329ad8decb7SKrzysztof Helt 
330ad8decb7SKrzysztof Helt 	snd_card_set_dev(card, devptr);
331ad8decb7SKrzysztof Helt 
332ad8decb7SKrzysztof Helt 	err = snd_card_register(card);
333ad8decb7SKrzysztof Helt 	if (err < 0)
334ad8decb7SKrzysztof Helt 		goto err_free;
335ad8decb7SKrzysztof Helt 
336ad8decb7SKrzysztof Helt 	dev_set_drvdata(devptr, card);
337ad8decb7SKrzysztof Helt 	return 0;
338ad8decb7SKrzysztof Helt 
339ad8decb7SKrzysztof Helt err_free:
340ad8decb7SKrzysztof Helt 	snd_card_free(card);
341ad8decb7SKrzysztof Helt 	return err;
342ad8decb7SKrzysztof Helt }
343ad8decb7SKrzysztof Helt 
344ad8decb7SKrzysztof Helt static int __devexit snd_jazz16_remove(struct device *devptr, unsigned int dev)
345ad8decb7SKrzysztof Helt {
346ad8decb7SKrzysztof Helt 	struct snd_card *card = dev_get_drvdata(devptr);
347ad8decb7SKrzysztof Helt 
348ad8decb7SKrzysztof Helt 	dev_set_drvdata(devptr, NULL);
349ad8decb7SKrzysztof Helt 	snd_card_free(card);
350ad8decb7SKrzysztof Helt 	return 0;
351ad8decb7SKrzysztof Helt }
352ad8decb7SKrzysztof Helt 
353ad8decb7SKrzysztof Helt #ifdef CONFIG_PM
354ad8decb7SKrzysztof Helt static int snd_jazz16_suspend(struct device *pdev, unsigned int n,
355ad8decb7SKrzysztof Helt 			       pm_message_t state)
356ad8decb7SKrzysztof Helt {
357ad8decb7SKrzysztof Helt 	struct snd_card *card = dev_get_drvdata(pdev);
358ad8decb7SKrzysztof Helt 	struct snd_card_jazz16 *acard = card->private_data;
359ad8decb7SKrzysztof Helt 	struct snd_sb *chip = acard->chip;
360ad8decb7SKrzysztof Helt 
361ad8decb7SKrzysztof Helt 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
362ad8decb7SKrzysztof Helt 	snd_pcm_suspend_all(chip->pcm);
363ad8decb7SKrzysztof Helt 	snd_sbmixer_suspend(chip);
364ad8decb7SKrzysztof Helt 	return 0;
365ad8decb7SKrzysztof Helt }
366ad8decb7SKrzysztof Helt 
367ad8decb7SKrzysztof Helt static int snd_jazz16_resume(struct device *pdev, unsigned int n)
368ad8decb7SKrzysztof Helt {
369ad8decb7SKrzysztof Helt 	struct snd_card *card = dev_get_drvdata(pdev);
370ad8decb7SKrzysztof Helt 	struct snd_card_jazz16 *acard = card->private_data;
371ad8decb7SKrzysztof Helt 	struct snd_sb *chip = acard->chip;
372ad8decb7SKrzysztof Helt 
373ad8decb7SKrzysztof Helt 	snd_sbdsp_reset(chip);
374ad8decb7SKrzysztof Helt 	snd_sbmixer_resume(chip);
375ad8decb7SKrzysztof Helt 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
376ad8decb7SKrzysztof Helt 	return 0;
377ad8decb7SKrzysztof Helt }
378ad8decb7SKrzysztof Helt #endif
379ad8decb7SKrzysztof Helt 
380ad8decb7SKrzysztof Helt static struct isa_driver snd_jazz16_driver = {
381ad8decb7SKrzysztof Helt 	.match		= snd_jazz16_match,
382ad8decb7SKrzysztof Helt 	.probe		= snd_jazz16_probe,
383ad8decb7SKrzysztof Helt 	.remove		= __devexit_p(snd_jazz16_remove),
384ad8decb7SKrzysztof Helt #ifdef CONFIG_PM
385ad8decb7SKrzysztof Helt 	.suspend	= snd_jazz16_suspend,
386ad8decb7SKrzysztof Helt 	.resume		= snd_jazz16_resume,
387ad8decb7SKrzysztof Helt #endif
388ad8decb7SKrzysztof Helt 	.driver		= {
389ad8decb7SKrzysztof Helt 		.name	= "jazz16"
390ad8decb7SKrzysztof Helt 	},
391ad8decb7SKrzysztof Helt };
392ad8decb7SKrzysztof Helt 
393ad8decb7SKrzysztof Helt static int __init alsa_card_jazz16_init(void)
394ad8decb7SKrzysztof Helt {
395ad8decb7SKrzysztof Helt 	return isa_register_driver(&snd_jazz16_driver, SNDRV_CARDS);
396ad8decb7SKrzysztof Helt }
397ad8decb7SKrzysztof Helt 
398ad8decb7SKrzysztof Helt static void __exit alsa_card_jazz16_exit(void)
399ad8decb7SKrzysztof Helt {
400ad8decb7SKrzysztof Helt 	isa_unregister_driver(&snd_jazz16_driver);
401ad8decb7SKrzysztof Helt }
402ad8decb7SKrzysztof Helt 
403ad8decb7SKrzysztof Helt module_init(alsa_card_jazz16_init)
404ad8decb7SKrzysztof Helt module_exit(alsa_card_jazz16_exit)
405