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