source: GPL/alsa-kernel/isa/azt2320.c@ 18

Last change on this file since 18 was 18, checked in by vladest, 20 years ago

initial import

File size: 13.7 KB
Line 
1
2/*
3 card-azt2320.c - driver for Aztech Systems AZT2320 based soundcards.
4 Copyright (C) 1999-2000 by Massimo Piccioni <dafastidio@libero.it>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20
21/*
22 This driver should provide support for most Aztech AZT2320 based cards.
23 Several AZT2316 chips are also supported/tested, but autoprobe doesn't
24 work: all module option have to be set.
25
26 No docs available for us at Aztech headquarters !!! Unbelievable ...
27 No other help obtained.
28
29 Thanks to Rainer Wiesner <rainer.wiesner@01019freenet.de> for the WSS
30 activation method (full-duplex audio!).
31*/
32
33#define SNDRV_MAIN_OBJECT_FILE
34#include <sound/driver.h>
35#define SNDRV_GET_ID
36#include <sound/initval.h>
37#include <sound/cs4231.h>
38#include <sound/mpu401.h>
39#include <sound/opl3.h>
40
41#define chip_t cs4231_t
42
43EXPORT_NO_SYMBOLS;
44MODULE_DESCRIPTION("Aztech Systems AZT2320");
45MODULE_CLASSES("{sound}");
46MODULE_DEVICES("{{Aztech Systems,PRO16V},"
47 "{Aztech Systems,AZT2320},"
48 "{Aztech Systems,AZT3300},"
49 "{Aztech Systems,AZT2320},"
50 "{Aztech Systems,AZT3000}}");
51
52static int snd_index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
53static char *snd_id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
54static int snd_enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
55static long snd_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
56static long snd_wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
57static long snd_mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
58static long snd_fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
59static int snd_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* Pnp setup */
60static int snd_mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* Pnp setup */
61static int snd_dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */
62static int snd_dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */
63
64MODULE_PARM(snd_index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
65MODULE_PARM_DESC(snd_index, "Index value for azt2320 based soundcard.");
66MODULE_PARM_SYNTAX(snd_index, SNDRV_INDEX_DESC);
67MODULE_PARM(snd_id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
68MODULE_PARM_DESC(snd_id, "ID string for azt2320 based soundcard.");
69MODULE_PARM_SYNTAX(snd_id, SNDRV_ID_DESC);
70MODULE_PARM(snd_enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
71MODULE_PARM_DESC(snd_enable, "Enable azt2320 based soundcard.");
72MODULE_PARM_SYNTAX(snd_enable, SNDRV_ENABLE_DESC);
73MODULE_PARM(snd_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
74MODULE_PARM_DESC(snd_port, "Port # for azt2320 driver.");
75MODULE_PARM_SYNTAX(snd_port, SNDRV_PORT12_DESC);
76MODULE_PARM(snd_wss_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
77MODULE_PARM_DESC(snd_wss_port, "WSS Port # for azt2320 driver.");
78MODULE_PARM_SYNTAX(snd_wss_port, SNDRV_PORT12_DESC);
79MODULE_PARM(snd_mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
80MODULE_PARM_DESC(snd_mpu_port, "MPU-401 port # for azt2320 driver.");
81MODULE_PARM_SYNTAX(snd_mpu_port, SNDRV_PORT12_DESC);
82MODULE_PARM(snd_fm_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
83MODULE_PARM_DESC(snd_fm_port, "FM port # for azt2320 driver.");
84MODULE_PARM_SYNTAX(snd_fm_port, SNDRV_PORT12_DESC);
85MODULE_PARM(snd_irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
86MODULE_PARM_DESC(snd_irq, "IRQ # for azt2320 driver.");
87MODULE_PARM_SYNTAX(snd_irq, SNDRV_IRQ_DESC);
88MODULE_PARM(snd_mpu_irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
89MODULE_PARM_DESC(snd_mpu_irq, "MPU-401 IRQ # for azt2320 driver.");
90MODULE_PARM_SYNTAX(snd_mpu_irq, SNDRV_IRQ_DESC);
91MODULE_PARM(snd_dma1, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
92MODULE_PARM_DESC(snd_dma1, "1st DMA # for azt2320 driver.");
93MODULE_PARM_SYNTAX(snd_dma1, SNDRV_DMA_DESC);
94MODULE_PARM(snd_dma2, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
95MODULE_PARM_DESC(snd_dma2, "2nd DMA # for azt2320 driver.");
96MODULE_PARM_SYNTAX(snd_dma2, SNDRV_DMA_DESC);
97
98struct snd_card_azt2320 {
99#ifdef __ISAPNP__
100 struct isapnp_dev *dev;
101 struct isapnp_dev *devmpu;
102#endif /* __ISAPNP__ */
103};
104
105static snd_card_t *snd_azt2320_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
106
107#ifdef __ISAPNP__
108
109static struct isapnp_card *snd_azt2320_isapnp_cards[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PTR;
110static const struct isapnp_card_id *snd_azt2320_isapnp_id[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PTR;
111
112#ifdef TARGET_OS2
113#define ISAPNP_AZT2320(_va, _vb, _vc, _device, _audio, _mpu401) \
114 { \
115 0, ISAPNP_CARD_ID(_va, _vb, _vc, _device), \
116 { ISAPNP_DEVICE_ID(_va, _vb, _vc, _audio), \
117 ISAPNP_DEVICE_ID(_va, _vb, _vc, _mpu401), } \
118 }
119#else
120#define ISAPNP_AZT2320(_va, _vb, _vc, _device, _audio, _mpu401) \
121 { \
122 ISAPNP_CARD_ID(_va, _vb, _vc, _device), \
123 devs : { ISAPNP_DEVICE_ID(_va, _vb, _vc, _audio), \
124 ISAPNP_DEVICE_ID(_va, _vb, _vc, _mpu401), } \
125 }
126#endif
127
128static struct isapnp_card_id snd_azt2320_pnpids[] __devinitdata = {
129 /* PRO16V */
130 ISAPNP_AZT2320('A','Z','T',0x1008,0x1008,0x2001),
131 /* --- */
132 ISAPNP_AZT2320('A','Z','T',0x2320,0x0001,0x0002),
133 /* Packard Bell Sound III 336 AM/SP */
134 ISAPNP_AZT2320('A','Z','T',0x3000,0x1003,0x2001),
135 /* AT3300 */
136 ISAPNP_AZT2320('A','Z','T',0x3002,0x1004,0x2001),
137 /* --- */
138 ISAPNP_AZT2320('A','Z','T',0x3005,0x1003,0x2001),
139 /* --- */
140 ISAPNP_AZT2320('A','Z','T',0x3011,0x1003,0x2001),
141 { ISAPNP_CARD_END, } /* end */
142};
143
144ISAPNP_CARD_TABLE(snd_azt2320_pnpids);
145
146#endif /* __ISAPNP__ */
147
148#define DRIVER_NAME "snd-card-azt2320"
149
150
151#ifdef __ISAPNP__
152static int __init snd_card_azt2320_isapnp(int dev, struct snd_card_azt2320 *acard)
153{
154 const struct isapnp_card_id *id = snd_azt2320_isapnp_id[dev];
155 struct isapnp_card *card = snd_azt2320_isapnp_cards[dev];
156 struct isapnp_dev *pdev;
157
158 acard->dev = isapnp_find_dev(card, id->devs[0].vendor, id->devs[0].function, NULL);
159 if (acard->dev->active) {
160 acard->dev = NULL;
161 return -EBUSY;
162 }
163 acard->devmpu = isapnp_find_dev(card, id->devs[1].vendor, id->devs[1].function, NULL);
164 if (acard->devmpu->active) {
165 acard->dev = acard->devmpu = NULL;
166 return -EBUSY;
167 }
168
169 pdev = acard->dev;
170 if (pdev->prepare(pdev) < 0)
171 return -EAGAIN;
172
173 if (snd_port[dev] != SNDRV_AUTO_PORT)
174 isapnp_resource_change(&pdev->resource[0], snd_port[dev], 16);
175 if (snd_fm_port[dev] != SNDRV_AUTO_PORT)
176 isapnp_resource_change(&pdev->resource[1], snd_fm_port[dev], 4);
177 if (snd_wss_port[dev] != SNDRV_AUTO_PORT)
178 isapnp_resource_change(&pdev->resource[2], snd_wss_port[dev],
179 4);
180 if (snd_dma1[dev] != SNDRV_AUTO_DMA)
181 isapnp_resource_change(&pdev->dma_resource[0], snd_dma1[dev],
182 1);
183 if (snd_dma2[dev] != SNDRV_AUTO_DMA)
184 isapnp_resource_change(&pdev->dma_resource[1], snd_dma2[dev],
185 1);
186 if (snd_irq[dev] != SNDRV_AUTO_IRQ)
187 isapnp_resource_change(&pdev->irq_resource[0], snd_irq[dev], 1);
188
189 if (pdev->activate(pdev) < 0) {
190 snd_printk("AUDIO isapnp configure failure\n");
191 return -EBUSY;
192 }
193
194 snd_port[dev] = pdev->resource[0].start;
195 snd_fm_port[dev] = pdev->resource[1].start;
196 snd_wss_port[dev] = pdev->resource[2].start;
197 snd_dma1[dev] = pdev->dma_resource[0].start;
198 snd_dma2[dev] = pdev->dma_resource[1].start;
199 snd_irq[dev] = pdev->irq_resource[0].start;
200
201 pdev = acard->devmpu;
202 if (pdev == NULL || pdev->prepare(pdev) < 0) {
203 snd_mpu_port[dev] = -1;
204 return 0;
205 }
206
207 if (snd_mpu_port[dev] != SNDRV_AUTO_PORT)
208 isapnp_resource_change(&pdev->resource[0], snd_mpu_port[dev],
209 2);
210 if (snd_mpu_irq[dev] != SNDRV_AUTO_IRQ)
211 isapnp_resource_change(&pdev->irq_resource[0], snd_mpu_irq[dev],
212 1);
213
214 if (pdev->activate(pdev) < 0) {
215 /* not fatal error */
216 snd_printk("MPU-401 isapnp configure failure\n");
217 snd_mpu_port[dev] = -1;
218 acard->devmpu = NULL;
219 } else {
220 snd_mpu_port[dev] = pdev->resource[0].start;
221 snd_mpu_irq[dev] = pdev->irq_resource[0].start;
222 }
223
224 return 0;
225}
226
227static void snd_card_azt2320_deactivate(struct snd_card_azt2320 *acard)
228{
229 if (acard->dev)
230 acard->dev->deactivate(acard->dev);
231 if (acard->devmpu)
232 acard->devmpu->deactivate(acard->devmpu);
233}
234#endif /* __ISAPNP__ */
235
236/* same of snd_sbdsp_command by Jaroslav Kysela */
237static int __init snd_card_azt2320_command(unsigned long port, unsigned char val)
238{
239 int i;
240 unsigned long limit;
241
242 limit = jiffies + HZ / 10;
243 for (i = 50000; i && (limit - jiffies) > 0; i--)
244 if (!(inb(port + 0x0c) & 0x80)) {
245 outb(val, port + 0x0c);
246 return 0;
247 }
248 return -EBUSY;
249}
250
251static int __init snd_card_azt2320_enable_wss(unsigned long port)
252{
253 int error;
254
255 if ((error = snd_card_azt2320_command(port, 0x09)))
256 return error;
257 if ((error = snd_card_azt2320_command(port, 0x00)))
258 return error;
259
260 mdelay(5);
261 return 0;
262}
263
264static void snd_card_azt2320_free(snd_card_t *card)
265{
266 struct snd_card_azt2320 *acard = (struct snd_card_azt2320 *)card->private_data;
267
268 if (acard) {
269#ifdef __ISAPNP__
270 snd_card_azt2320_deactivate(acard);
271#endif /* __ISAPNP__ */
272 }
273}
274
275static int __init snd_card_azt2320_probe(int dev)
276{
277 int error;
278 snd_card_t *card;
279 struct snd_card_azt2320 *acard;
280 cs4231_t *chip;
281 opl3_t *opl3;
282
283 if ((card = snd_card_new(snd_index[dev], snd_id[dev], THIS_MODULE,
284 sizeof(struct snd_card_azt2320))) == NULL)
285 return -ENOMEM;
286 acard = (struct snd_card_azt2320 *)card->private_data;
287 card->private_free = snd_card_azt2320_free;
288
289#ifdef __ISAPNP__
290 if ((error = snd_card_azt2320_isapnp(dev, acard))) {
291 snd_card_free(card);
292 return error;
293 }
294#endif /* __ISAPNP__ */
295
296 if ((error = snd_card_azt2320_enable_wss(snd_port[dev]))) {
297 snd_card_free(card);
298 return error;
299 }
300
301 if ((error = snd_cs4231_create(card, snd_wss_port[dev], -1,
302 snd_irq[dev],
303 snd_dma1[dev],
304 snd_dma2[dev],
305 CS4231_HW_DETECT, 0, &chip)) < 0) {
306 snd_card_free(card);
307 return error;
308 }
309
310 if ((error = snd_cs4231_pcm(chip, 0, NULL)) < 0) {
311 snd_card_free(card);
312 return error;
313 }
314 if ((error = snd_cs4231_mixer(chip)) < 0) {
315 snd_card_free(card);
316 return error;
317 }
318 if ((error = snd_cs4231_timer(chip, 0, NULL)) < 0) {
319 snd_card_free(card);
320 return error;
321 }
322
323 if (snd_mpu_port[dev] > 0) {
324 if (snd_mpu401_uart_new(card, 0, MPU401_HW_AZT2320,
325 snd_mpu_port[dev], 0,
326 snd_mpu_irq[dev], SA_INTERRUPT,
327 NULL) < 0)
328 snd_printk("no MPU-401 device at 0x%lx\n",
329 snd_mpu_port[dev]);
330 }
331
332 if (snd_fm_port[dev] > 0) {
333 if (snd_opl3_create(card,
334 snd_fm_port[dev], snd_fm_port[dev] + 2,
335 OPL3_HW_AUTO, 0, &opl3) < 0) {
336 snd_printk("no OPL device at 0x%lx-0x%lx\n",
337 snd_fm_port[dev], snd_fm_port[dev] + 2);
338 } else {
339 if ((error = snd_opl3_timer_new(opl3, 1, 2)) < 0) {
340 snd_card_free(card);
341 return error;
342 }
343 if ((error = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
344 snd_card_free(card);
345 return error;
346 }
347 }
348 }
349
350 strcpy(card->driver, "AZT2320");
351 strcpy(card->shortname, "Aztech AZT2320");
352 sprintf(card->longname, "%s soundcard, WSS at 0x%lx, irq %i, dma %i&%i",
353 card->shortname, chip->port, snd_irq[dev], snd_dma1[dev], snd_dma2[dev]);
354
355 if ((error = snd_card_register(card)) < 0) {
356 snd_card_free(card);
357 return error;
358 }
359 snd_azt2320_cards[dev] = card;
360 return 0;
361}
362
363#ifdef __ISAPNP__
364static int __init snd_azt2320_isapnp_detect(struct isapnp_card *card,
365 const struct isapnp_card_id *id)
366{
367 static int dev = 0;
368 int res;
369
370 for ( ; dev < SNDRV_CARDS; dev++) {
371 if (!snd_enable[dev])
372 continue;
373 snd_azt2320_isapnp_cards[dev] = card;
374 snd_azt2320_isapnp_id[dev] = id;
375 res = snd_card_azt2320_probe(dev);
376 if (res < 0)
377 return res;
378 dev++;
379 return 0;
380 }
381 return -ENODEV;
382}
383#endif
384
385static int __init alsa_card_azt2320_init(void)
386{
387 int cards = 0;
388
389#ifdef __ISAPNP__
390 cards += isapnp_probe_cards(snd_azt2320_pnpids, snd_azt2320_isapnp_detect);
391#else
392 snd_printk("you have to enable ISA PnP support.\n");
393#endif
394#ifdef MODULE
395 if (!cards)
396 snd_printk("no AZT2320 based soundcards found\n");
397#endif
398 return cards ? 0 : -ENODEV;
399}
400
401static void __exit alsa_card_azt2320_exit(void)
402{
403 int dev;
404
405 for (dev = 0; dev < SNDRV_CARDS; dev++)
406 snd_card_free(snd_azt2320_cards[dev]);
407}
408
409module_init(alsa_card_azt2320_init)
410module_exit(alsa_card_azt2320_exit)
411
412#ifndef MODULE
413
414/* format is: snd-card-azt2320=snd_enable,snd_index,snd_id,snd_port,
415 snd_wss_port,snd_mpu_port,snd_fm_port,
416 snd_irq,snd_mpu_irq,snd_dma1,snd_dma2 */
417
418static int __init alsa_card_azt2320_setup(char *str)
419{
420 static unsigned __initdata nr_dev = 0;
421
422 if (nr_dev >= SNDRV_CARDS)
423 return 0;
424 (void)(get_option(&str,&snd_enable[nr_dev]) == 2 &&
425 get_option(&str,&snd_index[nr_dev]) == 2 &&
426 get_id(&str,&snd_id[nr_dev]) == 2 &&
427 get_option(&str,(int *)&snd_port[nr_dev]) == 2 &&
428 get_option(&str,(int *)&snd_wss_port[nr_dev]) == 2 &&
429 get_option(&str,(int *)&snd_mpu_port[nr_dev]) == 2 &&
430 get_option(&str,&snd_irq[nr_dev]) == 2 &&
431 get_option(&str,&snd_mpu_irq[nr_dev]) == 2 &&
432 get_option(&str,&snd_dma1[nr_dev]) == 2 &&
433 get_option(&str,&snd_dma2[nr_dev]) == 2);
434 nr_dev++;
435 return 1;
436}
437
438__setup("snd-card-azt2320=", alsa_card_azt2320_setup);
439
440#endif /* ifndef MODULE */
Note: See TracBrowser for help on using the repository browser.