xref: /openbmc/linux/sound/isa/sb/jazz16.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
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>
1750152dfaSMeelis Roos #include <linux/delay.h>
18ad8decb7SKrzysztof Helt #include <asm/dma.h>
19ad8decb7SKrzysztof Helt #include <linux/isa.h>
20ad8decb7SKrzysztof Helt #include <sound/core.h>
21ad8decb7SKrzysztof Helt #include <sound/mpu401.h>
22ad8decb7SKrzysztof Helt #include <sound/opl3.h>
23ad8decb7SKrzysztof Helt #include <sound/sb.h>
24ad8decb7SKrzysztof Helt #define SNDRV_LEGACY_FIND_FREE_IRQ
25ad8decb7SKrzysztof Helt #define SNDRV_LEGACY_FIND_FREE_DMA
26ad8decb7SKrzysztof Helt #include <sound/initval.h>
27ad8decb7SKrzysztof Helt 
28ad8decb7SKrzysztof Helt #define PFX "jazz16: "
29ad8decb7SKrzysztof Helt 
30ad8decb7SKrzysztof Helt MODULE_DESCRIPTION("Media Vision Jazz16");
31ad8decb7SKrzysztof Helt MODULE_AUTHOR("Krzysztof Helt <krzysztof.h1@wp.pl>");
32ad8decb7SKrzysztof Helt MODULE_LICENSE("GPL");
33ad8decb7SKrzysztof Helt 
34ad8decb7SKrzysztof Helt static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
35ad8decb7SKrzysztof Helt static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
36a67ff6a5SRusty Russell static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;	/* Enable this card */
37ad8decb7SKrzysztof Helt static unsigned long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
38ad8decb7SKrzysztof Helt static unsigned long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
39ad8decb7SKrzysztof Helt static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
40ad8decb7SKrzysztof Helt static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
41ad8decb7SKrzysztof Helt static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
42ad8decb7SKrzysztof Helt static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
43ad8decb7SKrzysztof Helt 
44ad8decb7SKrzysztof Helt module_param_array(index, int, NULL, 0444);
45ad8decb7SKrzysztof Helt MODULE_PARM_DESC(index, "Index value for Media Vision Jazz16 based soundcard.");
46ad8decb7SKrzysztof Helt module_param_array(id, charp, NULL, 0444);
47ad8decb7SKrzysztof Helt MODULE_PARM_DESC(id, "ID string for Media Vision Jazz16 based soundcard.");
48ad8decb7SKrzysztof Helt module_param_array(enable, bool, NULL, 0444);
49ad8decb7SKrzysztof Helt MODULE_PARM_DESC(enable, "Enable Media Vision Jazz16 based soundcard.");
50e992ef57SDavid Howells module_param_hw_array(port, long, ioport, NULL, 0444);
51ad8decb7SKrzysztof Helt MODULE_PARM_DESC(port, "Port # for jazz16 driver.");
52e992ef57SDavid Howells module_param_hw_array(mpu_port, long, ioport, NULL, 0444);
53ad8decb7SKrzysztof Helt MODULE_PARM_DESC(mpu_port, "MPU-401 port # for jazz16 driver.");
54e992ef57SDavid Howells module_param_hw_array(irq, int, irq, NULL, 0444);
55ad8decb7SKrzysztof Helt MODULE_PARM_DESC(irq, "IRQ # for jazz16 driver.");
56e992ef57SDavid Howells module_param_hw_array(mpu_irq, int, irq, NULL, 0444);
57ad8decb7SKrzysztof Helt MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for jazz16 driver.");
58e992ef57SDavid Howells module_param_hw_array(dma8, int, dma, NULL, 0444);
59ad8decb7SKrzysztof Helt MODULE_PARM_DESC(dma8, "DMA8 # for jazz16 driver.");
60e992ef57SDavid Howells module_param_hw_array(dma16, int, dma, NULL, 0444);
61ad8decb7SKrzysztof Helt MODULE_PARM_DESC(dma16, "DMA16 # for jazz16 driver.");
62ad8decb7SKrzysztof Helt 
63ad8decb7SKrzysztof Helt #define SB_JAZZ16_WAKEUP	0xaf
64ad8decb7SKrzysztof Helt #define SB_JAZZ16_SET_PORTS	0x50
65ad8decb7SKrzysztof Helt #define SB_DSP_GET_JAZZ_BRD_REV	0xfa
66ad8decb7SKrzysztof Helt #define SB_JAZZ16_SET_DMAINTR	0xfb
67ad8decb7SKrzysztof Helt #define SB_DSP_GET_JAZZ_MODEL	0xfe
68ad8decb7SKrzysztof Helt 
69ad8decb7SKrzysztof Helt struct snd_card_jazz16 {
70ad8decb7SKrzysztof Helt 	struct snd_sb *chip;
71ad8decb7SKrzysztof Helt };
72ad8decb7SKrzysztof Helt 
jazz16_interrupt(int irq,void * chip)73ad8decb7SKrzysztof Helt static irqreturn_t jazz16_interrupt(int irq, void *chip)
74ad8decb7SKrzysztof Helt {
75ad8decb7SKrzysztof Helt 	return snd_sb8dsp_interrupt(chip);
76ad8decb7SKrzysztof Helt }
77ad8decb7SKrzysztof Helt 
jazz16_configure_ports(unsigned long port,unsigned long mpu_port,int idx)781bff292eSBill Pemberton static int jazz16_configure_ports(unsigned long port,
79ad8decb7SKrzysztof Helt 				  unsigned long mpu_port, int idx)
80ad8decb7SKrzysztof Helt {
81ad8decb7SKrzysztof Helt 	unsigned char val;
82ad8decb7SKrzysztof Helt 
83ad8decb7SKrzysztof Helt 	if (!request_region(0x201, 1, "jazz16 config")) {
84ad8decb7SKrzysztof Helt 		snd_printk(KERN_ERR "config port region is already in use.\n");
85ad8decb7SKrzysztof Helt 		return -EBUSY;
86ad8decb7SKrzysztof Helt 	}
87ad8decb7SKrzysztof Helt 	outb(SB_JAZZ16_WAKEUP - idx, 0x201);
88ad8decb7SKrzysztof Helt 	udelay(100);
89ad8decb7SKrzysztof Helt 	outb(SB_JAZZ16_SET_PORTS + idx, 0x201);
90ad8decb7SKrzysztof Helt 	udelay(100);
91ad8decb7SKrzysztof Helt 	val = port & 0x70;
92ad8decb7SKrzysztof Helt 	val |= (mpu_port & 0x30) >> 4;
93ad8decb7SKrzysztof Helt 	outb(val, 0x201);
94ad8decb7SKrzysztof Helt 
95ad8decb7SKrzysztof Helt 	release_region(0x201, 1);
96ad8decb7SKrzysztof Helt 	return 0;
97ad8decb7SKrzysztof Helt }
98ad8decb7SKrzysztof Helt 
jazz16_detect_board(unsigned long port,unsigned long mpu_port)991bff292eSBill Pemberton static int jazz16_detect_board(unsigned long port,
100ad8decb7SKrzysztof Helt 			       unsigned long mpu_port)
101ad8decb7SKrzysztof Helt {
102ad8decb7SKrzysztof Helt 	int err;
103ad8decb7SKrzysztof Helt 	int val;
104ad8decb7SKrzysztof Helt 	struct snd_sb chip;
105ad8decb7SKrzysztof Helt 
106ad8decb7SKrzysztof Helt 	if (!request_region(port, 0x10, "jazz16")) {
107ad8decb7SKrzysztof Helt 		snd_printk(KERN_ERR "I/O port region is already in use.\n");
108ad8decb7SKrzysztof Helt 		return -EBUSY;
109ad8decb7SKrzysztof Helt 	}
110ad8decb7SKrzysztof Helt 	/* just to call snd_sbdsp_command/reset/get_byte() */
111ad8decb7SKrzysztof Helt 	chip.port = port;
112ad8decb7SKrzysztof Helt 
113ad8decb7SKrzysztof Helt 	err = snd_sbdsp_reset(&chip);
114ad8decb7SKrzysztof Helt 	if (err < 0)
115ad8decb7SKrzysztof Helt 		for (val = 0; val < 4; val++) {
116ad8decb7SKrzysztof Helt 			err = jazz16_configure_ports(port, mpu_port, val);
117ad8decb7SKrzysztof Helt 			if (err < 0)
118ad8decb7SKrzysztof Helt 				break;
119ad8decb7SKrzysztof Helt 
120ad8decb7SKrzysztof Helt 			err = snd_sbdsp_reset(&chip);
121ad8decb7SKrzysztof Helt 			if (!err)
122ad8decb7SKrzysztof Helt 				break;
123ad8decb7SKrzysztof Helt 		}
124ad8decb7SKrzysztof Helt 	if (err < 0) {
125ad8decb7SKrzysztof Helt 		err = -ENODEV;
126ad8decb7SKrzysztof Helt 		goto err_unmap;
127ad8decb7SKrzysztof Helt 	}
128ad8decb7SKrzysztof Helt 	if (!snd_sbdsp_command(&chip, SB_DSP_GET_JAZZ_BRD_REV)) {
129ad8decb7SKrzysztof Helt 		err = -EBUSY;
130ad8decb7SKrzysztof Helt 		goto err_unmap;
131ad8decb7SKrzysztof Helt 	}
132ad8decb7SKrzysztof Helt 	val = snd_sbdsp_get_byte(&chip);
133ad8decb7SKrzysztof Helt 	if (val >= 0x30)
134ad8decb7SKrzysztof Helt 		snd_sbdsp_get_byte(&chip);
135ad8decb7SKrzysztof Helt 
136ad8decb7SKrzysztof Helt 	if ((val & 0xf0) != 0x10) {
137ad8decb7SKrzysztof Helt 		err = -ENODEV;
138ad8decb7SKrzysztof Helt 		goto err_unmap;
139ad8decb7SKrzysztof Helt 	}
140ad8decb7SKrzysztof Helt 	if (!snd_sbdsp_command(&chip, SB_DSP_GET_JAZZ_MODEL)) {
141ad8decb7SKrzysztof Helt 		err = -EBUSY;
142ad8decb7SKrzysztof Helt 		goto err_unmap;
143ad8decb7SKrzysztof Helt 	}
144ad8decb7SKrzysztof Helt 	snd_sbdsp_get_byte(&chip);
145ad8decb7SKrzysztof Helt 	err = snd_sbdsp_get_byte(&chip);
146ad8decb7SKrzysztof Helt 	snd_printd("Media Vision Jazz16 board detected: rev 0x%x, model 0x%x\n",
147ad8decb7SKrzysztof Helt 		   val, err);
148ad8decb7SKrzysztof Helt 
149ad8decb7SKrzysztof Helt 	err = 0;
150ad8decb7SKrzysztof Helt 
151ad8decb7SKrzysztof Helt err_unmap:
152ad8decb7SKrzysztof Helt 	release_region(port, 0x10);
153ad8decb7SKrzysztof Helt 	return err;
154ad8decb7SKrzysztof Helt }
155ad8decb7SKrzysztof Helt 
jazz16_configure_board(struct snd_sb * chip,int mpu_irq)1561bff292eSBill Pemberton static int jazz16_configure_board(struct snd_sb *chip, int mpu_irq)
157ad8decb7SKrzysztof Helt {
1582a076d0aSTakashi Iwai 	static const unsigned char jazz_irq_bits[] = { 0, 0, 2, 3, 0, 1, 0, 4,
159ad8decb7SKrzysztof Helt 						 0, 2, 5, 0, 0, 0, 0, 6 };
1602a076d0aSTakashi Iwai 	static const unsigned char jazz_dma_bits[] = { 0, 1, 0, 2, 0, 3, 0, 4 };
161ad8decb7SKrzysztof Helt 
162ad8decb7SKrzysztof Helt 	if (jazz_dma_bits[chip->dma8] == 0 ||
163ad8decb7SKrzysztof Helt 	    jazz_dma_bits[chip->dma16] == 0 ||
164ad8decb7SKrzysztof Helt 	    jazz_irq_bits[chip->irq] == 0)
165ad8decb7SKrzysztof Helt 		return -EINVAL;
166ad8decb7SKrzysztof Helt 
167ad8decb7SKrzysztof Helt 	if (!snd_sbdsp_command(chip, SB_JAZZ16_SET_DMAINTR))
168ad8decb7SKrzysztof Helt 		return -EBUSY;
169ad8decb7SKrzysztof Helt 
170ad8decb7SKrzysztof Helt 	if (!snd_sbdsp_command(chip,
171ad8decb7SKrzysztof Helt 			       jazz_dma_bits[chip->dma8] |
172ad8decb7SKrzysztof Helt 			       (jazz_dma_bits[chip->dma16] << 4)))
173ad8decb7SKrzysztof Helt 		return -EBUSY;
174ad8decb7SKrzysztof Helt 
175ad8decb7SKrzysztof Helt 	if (!snd_sbdsp_command(chip,
176ad8decb7SKrzysztof Helt 			       jazz_irq_bits[chip->irq] |
177ad8decb7SKrzysztof Helt 			       (jazz_irq_bits[mpu_irq] << 4)))
178ad8decb7SKrzysztof Helt 		return -EBUSY;
179ad8decb7SKrzysztof Helt 
180ad8decb7SKrzysztof Helt 	return 0;
181ad8decb7SKrzysztof Helt }
182ad8decb7SKrzysztof Helt 
snd_jazz16_match(struct device * devptr,unsigned int dev)1831bff292eSBill Pemberton static int snd_jazz16_match(struct device *devptr, unsigned int dev)
184ad8decb7SKrzysztof Helt {
185ad8decb7SKrzysztof Helt 	if (!enable[dev])
186ad8decb7SKrzysztof Helt 		return 0;
187ad8decb7SKrzysztof Helt 	if (port[dev] == SNDRV_AUTO_PORT) {
188ad8decb7SKrzysztof Helt 		snd_printk(KERN_ERR "please specify port\n");
189ad8decb7SKrzysztof Helt 		return 0;
19044eba3e8SKrzysztof Helt 	} else if (port[dev] == 0x200 || (port[dev] & ~0x270)) {
19144eba3e8SKrzysztof Helt 		snd_printk(KERN_ERR "incorrect port specified\n");
19244eba3e8SKrzysztof Helt 		return 0;
19344eba3e8SKrzysztof Helt 	}
19444eba3e8SKrzysztof Helt 	if (dma8[dev] != SNDRV_AUTO_DMA &&
19544eba3e8SKrzysztof Helt 	    dma8[dev] != 1 && dma8[dev] != 3) {
19644eba3e8SKrzysztof Helt 		snd_printk(KERN_ERR "dma8 must be 1 or 3\n");
19744eba3e8SKrzysztof Helt 		return 0;
198ad8decb7SKrzysztof Helt 	}
199ad8decb7SKrzysztof Helt 	if (dma16[dev] != SNDRV_AUTO_DMA &&
200ad8decb7SKrzysztof Helt 	    dma16[dev] != 5 && dma16[dev] != 7) {
20144eba3e8SKrzysztof Helt 		snd_printk(KERN_ERR "dma16 must be 5 or 7\n");
20244eba3e8SKrzysztof Helt 		return 0;
20344eba3e8SKrzysztof Helt 	}
20444eba3e8SKrzysztof Helt 	if (mpu_port[dev] != SNDRV_AUTO_PORT &&
20544eba3e8SKrzysztof Helt 	    (mpu_port[dev] & ~0x030) != 0x300) {
20644eba3e8SKrzysztof Helt 		snd_printk(KERN_ERR "incorrect mpu_port specified\n");
20744eba3e8SKrzysztof Helt 		return 0;
20844eba3e8SKrzysztof Helt 	}
20944eba3e8SKrzysztof Helt 	if (mpu_irq[dev] != SNDRV_AUTO_DMA &&
21044eba3e8SKrzysztof Helt 	    mpu_irq[dev] != 2 && mpu_irq[dev] != 3 &&
21144eba3e8SKrzysztof Helt 	    mpu_irq[dev] != 5 && mpu_irq[dev] != 7) {
21244eba3e8SKrzysztof Helt 		snd_printk(KERN_ERR "mpu_irq must be 2, 3, 5 or 7\n");
213ad8decb7SKrzysztof Helt 		return 0;
214ad8decb7SKrzysztof Helt 	}
215ad8decb7SKrzysztof Helt 	return 1;
216ad8decb7SKrzysztof Helt }
217ad8decb7SKrzysztof Helt 
snd_jazz16_probe(struct device * devptr,unsigned int dev)2181bff292eSBill Pemberton static int snd_jazz16_probe(struct device *devptr, unsigned int dev)
219ad8decb7SKrzysztof Helt {
220ad8decb7SKrzysztof Helt 	struct snd_card *card;
221ad8decb7SKrzysztof Helt 	struct snd_card_jazz16 *jazz16;
222ad8decb7SKrzysztof Helt 	struct snd_sb *chip;
223ad8decb7SKrzysztof Helt 	struct snd_opl3 *opl3;
2242a076d0aSTakashi Iwai 	static const int possible_irqs[] = {2, 3, 5, 7, 9, 10, 15, -1};
2252a076d0aSTakashi Iwai 	static const int possible_dmas8[] = {1, 3, -1};
2262a076d0aSTakashi Iwai 	static const int possible_dmas16[] = {5, 7, -1};
227ad8decb7SKrzysztof Helt 	int err, xirq, xdma8, xdma16, xmpu_port, xmpu_irq;
228ad8decb7SKrzysztof Helt 
229*5eab6cb0STakashi Iwai 	err = snd_devm_card_new(devptr, index[dev], id[dev], THIS_MODULE,
230ad8decb7SKrzysztof Helt 				sizeof(struct snd_card_jazz16), &card);
231ad8decb7SKrzysztof Helt 	if (err < 0)
232ad8decb7SKrzysztof Helt 		return err;
233ad8decb7SKrzysztof Helt 
234ad8decb7SKrzysztof Helt 	jazz16 = card->private_data;
235ad8decb7SKrzysztof Helt 
236ad8decb7SKrzysztof Helt 	xirq = irq[dev];
237ad8decb7SKrzysztof Helt 	if (xirq == SNDRV_AUTO_IRQ) {
238ad8decb7SKrzysztof Helt 		xirq = snd_legacy_find_free_irq(possible_irqs);
239ad8decb7SKrzysztof Helt 		if (xirq < 0) {
240ad8decb7SKrzysztof Helt 			snd_printk(KERN_ERR "unable to find a free IRQ\n");
241*5eab6cb0STakashi Iwai 			return -EBUSY;
242ad8decb7SKrzysztof Helt 		}
243ad8decb7SKrzysztof Helt 	}
244ad8decb7SKrzysztof Helt 	xdma8 = dma8[dev];
245ad8decb7SKrzysztof Helt 	if (xdma8 == SNDRV_AUTO_DMA) {
246ad8decb7SKrzysztof Helt 		xdma8 = snd_legacy_find_free_dma(possible_dmas8);
247ad8decb7SKrzysztof Helt 		if (xdma8 < 0) {
248ad8decb7SKrzysztof Helt 			snd_printk(KERN_ERR "unable to find a free DMA8\n");
249*5eab6cb0STakashi Iwai 			return -EBUSY;
250ad8decb7SKrzysztof Helt 		}
251ad8decb7SKrzysztof Helt 	}
252ad8decb7SKrzysztof Helt 	xdma16 = dma16[dev];
253ad8decb7SKrzysztof Helt 	if (xdma16 == SNDRV_AUTO_DMA) {
254ad8decb7SKrzysztof Helt 		xdma16 = snd_legacy_find_free_dma(possible_dmas16);
255ad8decb7SKrzysztof Helt 		if (xdma16 < 0) {
256ad8decb7SKrzysztof Helt 			snd_printk(KERN_ERR "unable to find a free DMA16\n");
257*5eab6cb0STakashi Iwai 			return -EBUSY;
258ad8decb7SKrzysztof Helt 		}
259ad8decb7SKrzysztof Helt 	}
260ad8decb7SKrzysztof Helt 
261ad8decb7SKrzysztof Helt 	xmpu_port = mpu_port[dev];
262ad8decb7SKrzysztof Helt 	if (xmpu_port == SNDRV_AUTO_PORT)
263ad8decb7SKrzysztof Helt 		xmpu_port = 0;
264ad8decb7SKrzysztof Helt 	err = jazz16_detect_board(port[dev], xmpu_port);
265ad8decb7SKrzysztof Helt 	if (err < 0) {
266ad8decb7SKrzysztof Helt 		printk(KERN_ERR "Media Vision Jazz16 board not detected\n");
267*5eab6cb0STakashi Iwai 		return err;
268ad8decb7SKrzysztof Helt 	}
269ad8decb7SKrzysztof Helt 	err = snd_sbdsp_create(card, port[dev], irq[dev],
270ad8decb7SKrzysztof Helt 			       jazz16_interrupt,
271ad8decb7SKrzysztof Helt 			       dma8[dev], dma16[dev],
272ad8decb7SKrzysztof Helt 			       SB_HW_JAZZ16,
273ad8decb7SKrzysztof Helt 			       &chip);
274ad8decb7SKrzysztof Helt 	if (err < 0)
275*5eab6cb0STakashi Iwai 		return err;
276ad8decb7SKrzysztof Helt 
277ad8decb7SKrzysztof Helt 	xmpu_irq = mpu_irq[dev];
278ad8decb7SKrzysztof Helt 	if (xmpu_irq == SNDRV_AUTO_IRQ || mpu_port[dev] == SNDRV_AUTO_PORT)
279ad8decb7SKrzysztof Helt 		xmpu_irq = 0;
280ad8decb7SKrzysztof Helt 	err = jazz16_configure_board(chip, xmpu_irq);
281ad8decb7SKrzysztof Helt 	if (err < 0) {
282ad8decb7SKrzysztof Helt 		printk(KERN_ERR "Media Vision Jazz16 configuration failed\n");
283*5eab6cb0STakashi Iwai 		return err;
284ad8decb7SKrzysztof Helt 	}
285ad8decb7SKrzysztof Helt 
286ad8decb7SKrzysztof Helt 	jazz16->chip = chip;
287ad8decb7SKrzysztof Helt 
288ad8decb7SKrzysztof Helt 	strcpy(card->driver, "jazz16");
289ad8decb7SKrzysztof Helt 	strcpy(card->shortname, "Media Vision Jazz16");
290ad8decb7SKrzysztof Helt 	sprintf(card->longname,
291ad8decb7SKrzysztof Helt 		"Media Vision Jazz16 at 0x%lx, irq %d, dma8 %d, dma16 %d",
292ad8decb7SKrzysztof Helt 		port[dev], xirq, xdma8, xdma16);
293ad8decb7SKrzysztof Helt 
2948c776299SLars-Peter Clausen 	err = snd_sb8dsp_pcm(chip, 0);
295ad8decb7SKrzysztof Helt 	if (err < 0)
296*5eab6cb0STakashi Iwai 		return err;
297ad8decb7SKrzysztof Helt 	err = snd_sbmixer_new(chip);
298ad8decb7SKrzysztof Helt 	if (err < 0)
299*5eab6cb0STakashi Iwai 		return err;
300ad8decb7SKrzysztof Helt 
301ad8decb7SKrzysztof Helt 	err = snd_opl3_create(card, chip->port, chip->port + 2,
302ad8decb7SKrzysztof Helt 			      OPL3_HW_AUTO, 1, &opl3);
303ad8decb7SKrzysztof Helt 	if (err < 0)
304ad8decb7SKrzysztof Helt 		snd_printk(KERN_WARNING "no OPL device at 0x%lx-0x%lx\n",
305ad8decb7SKrzysztof Helt 			   chip->port, chip->port + 2);
306ad8decb7SKrzysztof Helt 	else {
307ad8decb7SKrzysztof Helt 		err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
308ad8decb7SKrzysztof Helt 		if (err < 0)
309*5eab6cb0STakashi Iwai 			return err;
310ad8decb7SKrzysztof Helt 	}
311ad8decb7SKrzysztof Helt 	if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
312ad8decb7SKrzysztof Helt 		if (mpu_irq[dev] == SNDRV_AUTO_IRQ)
313ad8decb7SKrzysztof Helt 			mpu_irq[dev] = -1;
314ad8decb7SKrzysztof Helt 
315ad8decb7SKrzysztof Helt 		if (snd_mpu401_uart_new(card, 0,
316ad8decb7SKrzysztof Helt 					MPU401_HW_MPU401,
317ad8decb7SKrzysztof Helt 					mpu_port[dev], 0,
318ad8decb7SKrzysztof Helt 					mpu_irq[dev],
319ad8decb7SKrzysztof Helt 					NULL) < 0)
320ad8decb7SKrzysztof Helt 			snd_printk(KERN_ERR "no MPU-401 device at 0x%lx\n",
321ad8decb7SKrzysztof Helt 					mpu_port[dev]);
322ad8decb7SKrzysztof Helt 	}
323ad8decb7SKrzysztof Helt 
324ad8decb7SKrzysztof Helt 	err = snd_card_register(card);
325ad8decb7SKrzysztof Helt 	if (err < 0)
326*5eab6cb0STakashi Iwai 		return err;
327ad8decb7SKrzysztof Helt 
328ad8decb7SKrzysztof Helt 	dev_set_drvdata(devptr, card);
329ad8decb7SKrzysztof Helt 	return 0;
330ad8decb7SKrzysztof Helt }
331ad8decb7SKrzysztof Helt 
332ad8decb7SKrzysztof Helt #ifdef CONFIG_PM
snd_jazz16_suspend(struct device * pdev,unsigned int n,pm_message_t state)333ad8decb7SKrzysztof Helt static int snd_jazz16_suspend(struct device *pdev, unsigned int n,
334ad8decb7SKrzysztof Helt 			       pm_message_t state)
335ad8decb7SKrzysztof Helt {
336ad8decb7SKrzysztof Helt 	struct snd_card *card = dev_get_drvdata(pdev);
337ad8decb7SKrzysztof Helt 	struct snd_card_jazz16 *acard = card->private_data;
338ad8decb7SKrzysztof Helt 	struct snd_sb *chip = acard->chip;
339ad8decb7SKrzysztof Helt 
340ad8decb7SKrzysztof Helt 	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
341ad8decb7SKrzysztof Helt 	snd_sbmixer_suspend(chip);
342ad8decb7SKrzysztof Helt 	return 0;
343ad8decb7SKrzysztof Helt }
344ad8decb7SKrzysztof Helt 
snd_jazz16_resume(struct device * pdev,unsigned int n)345ad8decb7SKrzysztof Helt static int snd_jazz16_resume(struct device *pdev, unsigned int n)
346ad8decb7SKrzysztof Helt {
347ad8decb7SKrzysztof Helt 	struct snd_card *card = dev_get_drvdata(pdev);
348ad8decb7SKrzysztof Helt 	struct snd_card_jazz16 *acard = card->private_data;
349ad8decb7SKrzysztof Helt 	struct snd_sb *chip = acard->chip;
350ad8decb7SKrzysztof Helt 
351ad8decb7SKrzysztof Helt 	snd_sbdsp_reset(chip);
352ad8decb7SKrzysztof Helt 	snd_sbmixer_resume(chip);
353ad8decb7SKrzysztof Helt 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
354ad8decb7SKrzysztof Helt 	return 0;
355ad8decb7SKrzysztof Helt }
356ad8decb7SKrzysztof Helt #endif
357ad8decb7SKrzysztof Helt 
358ad8decb7SKrzysztof Helt static struct isa_driver snd_jazz16_driver = {
359ad8decb7SKrzysztof Helt 	.match		= snd_jazz16_match,
360ad8decb7SKrzysztof Helt 	.probe		= snd_jazz16_probe,
361ad8decb7SKrzysztof Helt #ifdef CONFIG_PM
362ad8decb7SKrzysztof Helt 	.suspend	= snd_jazz16_suspend,
363ad8decb7SKrzysztof Helt 	.resume		= snd_jazz16_resume,
364ad8decb7SKrzysztof Helt #endif
365ad8decb7SKrzysztof Helt 	.driver		= {
366ad8decb7SKrzysztof Helt 		.name	= "jazz16"
367ad8decb7SKrzysztof Helt 	},
368ad8decb7SKrzysztof Helt };
369ad8decb7SKrzysztof Helt 
370fc733cf9SWilliam Breathitt Gray module_isa_driver(snd_jazz16_driver, SNDRV_CARDS);
371