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

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

initial import

File size: 12.9 KB
Line 
1
2/*
3 card-als100.c - driver for Avance Logic ALS100 based soundcards.
4 Copyright (C) 1999-2000 by Massimo Piccioni <dafastidio@libero.it>
5
6 Thanks to Pierfrancesco 'qM2' Passerini.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21*/
22
23#define SNDRV_MAIN_OBJECT_FILE
24#include <sound/driver.h>
25#define SNDRV_GET_ID
26#include <sound/initval.h>
27#include <sound/mpu401.h>
28#include <sound/opl3.h>
29#include <sound/sb.h>
30
31#define chip_t sb_t
32
33EXPORT_NO_SYMBOLS;
34MODULE_DESCRIPTION("Avance Logic ALS1X0");
35MODULE_CLASSES("{sound}");
36MODULE_DEVICES("{{Avance Logic,ALS100 - PRO16PNP},"
37 "{Avance Logic,ALS110},"
38 "{3D Melody,MF1000},"
39 "{Digimate,3D Sound},"
40 "{Avance Logic,ALS120},"
41 "{RTL,RTL3000}}");
42
43static int snd_index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
44static char *snd_id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
45static int snd_enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
46static long snd_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
47static long snd_mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
48static long snd_fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
49static int snd_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* PnP setup */
50static int snd_mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* PnP setup */
51static int snd_dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */
52static int snd_dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */
53
54MODULE_PARM(snd_index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
55MODULE_PARM_DESC(snd_index, "Index value for als100 based soundcard.");
56MODULE_PARM_SYNTAX(snd_index, SNDRV_INDEX_DESC);
57MODULE_PARM(snd_id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
58MODULE_PARM_DESC(snd_id, "ID string for als100 based soundcard.");
59MODULE_PARM_SYNTAX(snd_id, SNDRV_ID_DESC);
60MODULE_PARM(snd_enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
61MODULE_PARM_DESC(snd_enable, "Enable als100 based soundcard.");
62MODULE_PARM_SYNTAX(snd_enable, SNDRV_ENABLE_DESC);
63MODULE_PARM(snd_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
64MODULE_PARM_DESC(snd_port, "Port # for als100 driver.");
65MODULE_PARM_SYNTAX(snd_port, SNDRV_PORT12_DESC);
66MODULE_PARM(snd_mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
67MODULE_PARM_DESC(snd_mpu_port, "MPU-401 port # for als100 driver.");
68MODULE_PARM_SYNTAX(snd_mpu_port, SNDRV_PORT12_DESC);
69MODULE_PARM(snd_fm_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
70MODULE_PARM_DESC(snd_fm_port, "FM port # for als100 driver.");
71MODULE_PARM_SYNTAX(snd_fm_port, SNDRV_PORT12_DESC);
72MODULE_PARM(snd_irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
73MODULE_PARM_DESC(snd_irq, "IRQ # for als100 driver.");
74MODULE_PARM_SYNTAX(snd_irq, SNDRV_IRQ_DESC);
75MODULE_PARM(snd_mpu_irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
76MODULE_PARM_DESC(snd_mpu_irq, "MPU-401 IRQ # for als100 driver.");
77MODULE_PARM_SYNTAX(snd_mpu_irq, SNDRV_IRQ_DESC);
78MODULE_PARM(snd_dma8, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
79MODULE_PARM_DESC(snd_dma8, "8-bit DMA # for als100 driver.");
80MODULE_PARM_SYNTAX(snd_dma8, SNDRV_DMA8_DESC);
81MODULE_PARM(snd_dma16, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
82MODULE_PARM_DESC(snd_dma16, "16-bit DMA # for als100 driver.");
83MODULE_PARM_SYNTAX(snd_dma16, SNDRV_DMA16_DESC);
84
85struct snd_card_als100 {
86#ifdef __ISAPNP__
87 struct isapnp_dev *dev;
88 struct isapnp_dev *devmpu;
89 struct isapnp_dev *devopl;
90#endif /* __ISAPNP__ */
91};
92
93static snd_card_t *snd_als100_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
94
95#ifdef __ISAPNP__
96static struct isapnp_card *snd_als100_isapnp_cards[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PTR;
97static const struct isapnp_card_id *snd_als100_isapnp_id[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PTR;
98
99#ifdef TARGET_OS2
100#define ISAPNP_ALS100(_va, _vb, _vc, _device, _audio, _mpu401, _opl) \
101 { \
102 0, ISAPNP_CARD_ID(_va, _vb, _vc, _device), \
103 { ISAPNP_DEVICE_ID('@', '@', '@', _audio), \
104 ISAPNP_DEVICE_ID('@', 'X', '@', _mpu401), \
105 ISAPNP_DEVICE_ID('@', 'H', '@', _opl) } \
106 }
107#else
108#define ISAPNP_ALS100(_va, _vb, _vc, _device, _audio, _mpu401, _opl) \
109 { \
110 ISAPNP_CARD_ID(_va, _vb, _vc, _device), \
111 devs : { ISAPNP_DEVICE_ID('@', '@', '@', _audio), \
112 ISAPNP_DEVICE_ID('@', 'X', '@', _mpu401), \
113 ISAPNP_DEVICE_ID('@', 'H', '@', _opl) } \
114 }
115#endif
116
117static struct isapnp_card_id snd_als100_pnpids[] __devinitdata = {
118 /* ALS100 - PRO16PNP */
119 ISAPNP_ALS100('A','L','S',0x0001,0x0001,0x0001,0x0001),
120 /* ALS110 - MF1000 - Digimate 3D Sound */
121 ISAPNP_ALS100('A','L','S',0x0110,0x1001,0x1001,0x1001),
122 /* ALS120 */
123 ISAPNP_ALS100('A','L','S',0x0120,0x2001,0x2001,0x2001),
124 /* RTL3000 */
125 ISAPNP_ALS100('R','T','L',0x3000,0x2001,0x2001,0x2001),
126 { ISAPNP_CARD_END, }
127};
128
129ISAPNP_CARD_TABLE(snd_als100_pnpids);
130
131#endif /* __ISAPNP__ */
132
133#define DRIVER_NAME "snd-card-als100"
134
135
136#ifdef __ISAPNP__
137static int __init snd_card_als100_isapnp(int dev, struct snd_card_als100 *acard)
138{
139 const struct isapnp_card_id *id = snd_als100_isapnp_id[dev];
140 struct isapnp_card *card = snd_als100_isapnp_cards[dev];
141 struct isapnp_dev *pdev;
142
143 acard->dev = isapnp_find_dev(card, id->devs[0].vendor, id->devs[0].function, NULL);
144 if (acard->dev->active) {
145 acard->dev = NULL;
146 return -EBUSY;
147 }
148 acard->devmpu = isapnp_find_dev(card, id->devs[1].vendor, id->devs[1].function, NULL);
149 if (acard->devmpu->active) {
150 acard->dev = acard->devmpu = NULL;
151 return -EBUSY;
152 }
153 acard->devopl = isapnp_find_dev(card, id->devs[2].vendor, id->devs[2].function, NULL);
154 if (acard->devopl->active) {
155 acard->dev = acard->devmpu = acard->devopl = NULL;
156 return -EBUSY;
157 }
158
159 pdev = acard->dev;
160 if (pdev->prepare(pdev)<0)
161 return -EAGAIN;
162
163 if (snd_port[dev] != SNDRV_AUTO_PORT)
164 isapnp_resource_change(&pdev->resource[0], snd_port[dev], 16);
165 if (snd_dma8[dev] != SNDRV_AUTO_DMA)
166 isapnp_resource_change(&pdev->dma_resource[0], snd_dma8[dev],
167 1);
168 if (snd_dma16[dev] != SNDRV_AUTO_DMA)
169 isapnp_resource_change(&pdev->dma_resource[1], snd_dma16[dev],
170 1);
171 if (snd_irq[dev] != SNDRV_AUTO_IRQ)
172 isapnp_resource_change(&pdev->irq_resource[0], snd_irq[dev], 1);
173
174 if (pdev->activate(pdev)<0) {
175 snd_printk("AUDIO isapnp configure failure\n");
176 return -EBUSY;
177 }
178
179 snd_port[dev] = pdev->resource[0].start;
180 snd_dma8[dev] = pdev->dma_resource[1].start;
181 snd_dma16[dev] = pdev->dma_resource[0].start;
182 snd_irq[dev] = pdev->irq_resource[0].start;
183
184 pdev = acard->devmpu;
185 if (pdev == NULL || pdev->prepare(pdev)<0) {
186 snd_mpu_port[dev] = -1;
187 return 0;
188 }
189
190 if (snd_mpu_port[dev] != SNDRV_AUTO_PORT)
191 isapnp_resource_change(&pdev->resource[0], snd_mpu_port[dev],
192 2);
193 if (snd_mpu_irq[dev] != SNDRV_AUTO_IRQ)
194 isapnp_resource_change(&pdev->irq_resource[0], snd_mpu_irq[dev],
195 1);
196
197 if (pdev->activate(pdev)<0) {
198 snd_printk("MPU-401 isapnp configure failure\n");
199 snd_mpu_port[dev] = -1;
200 acard->devmpu = NULL;
201 } else {
202 snd_mpu_port[dev] = pdev->resource[0].start;
203 snd_mpu_irq[dev] = pdev->irq_resource[0].start;
204 }
205
206 pdev = acard->devopl;
207 if (pdev == NULL || pdev->prepare(pdev)<0) {
208 snd_fm_port[dev] = -1;
209 return 0;
210 }
211
212 if (snd_fm_port[dev] != SNDRV_AUTO_PORT)
213 isapnp_resource_change(&pdev->resource[0], snd_fm_port[dev], 4);
214
215 if (pdev->activate(pdev)<0) {
216 snd_printk("OPL isapnp configure failure\n");
217 snd_fm_port[dev] = -1;
218 acard->devopl = NULL;
219 } else {
220 snd_fm_port[dev] = pdev->resource[0].start;
221 }
222
223 return 0;
224}
225
226static void snd_card_als100_deactivate(struct snd_card_als100 *acard)
227{
228 if (acard->dev) {
229 acard->dev->deactivate(acard->dev);
230 acard->dev = NULL;
231 }
232 if (acard->devmpu) {
233 acard->devmpu->deactivate(acard->devmpu);
234 acard->devmpu = NULL;
235 }
236 if (acard->devopl) {
237 acard->devopl->deactivate(acard->devopl);
238 acard->devopl = NULL;
239 }
240}
241#endif /* __ISAPNP__ */
242
243static void snd_card_als100_free(snd_card_t *card)
244{
245 struct snd_card_als100 *acard = (struct snd_card_als100 *)card->private_data;
246
247 if (acard) {
248#ifdef __ISAPNP__
249 snd_card_als100_deactivate(acard);
250#endif /* __ISAPNP__ */
251 }
252}
253
254static int __init snd_card_als100_probe(int dev)
255{
256 int error;
257 sb_t *chip;
258 snd_card_t *card;
259 struct snd_card_als100 *acard;
260 opl3_t *opl3;
261
262 if ((card = snd_card_new(snd_index[dev], snd_id[dev], THIS_MODULE,
263 sizeof(struct snd_card_als100))) == NULL)
264 return -ENOMEM;
265 acard = (struct snd_card_als100 *)card->private_data;
266 card->private_free = snd_card_als100_free;
267
268#ifdef __ISAPNP__
269 if ((error = snd_card_als100_isapnp(dev, acard))) {
270 snd_card_free(card);
271 return error;
272 }
273#else
274 snd_printk("you have to enable PnP support ...\n");
275 snd_card_free(card);
276 return -ENOSYS;
277#endif /* __ISAPNP__ */
278
279 if ((error = snd_sbdsp_create(card, snd_port[dev],
280 snd_irq[dev],
281 snd_sb16dsp_interrupt,
282 snd_dma8[dev],
283 snd_dma16[dev],
284 SB_HW_ALS100, &chip)) < 0) {
285 snd_card_free(card);
286 return error;
287 }
288
289 if ((error = snd_sb16dsp_pcm(chip, 0, NULL)) < 0) {
290 snd_card_free(card);
291 return error;
292 }
293
294 if ((error = snd_sbmixer_new(chip)) < 0) {
295 snd_card_free(card);
296 return error;
297 }
298
299 if (snd_mpu_port[dev] > 0) {
300 if (snd_mpu401_uart_new(card, 0, MPU401_HW_ALS100,
301 snd_mpu_port[dev], 0,
302 snd_mpu_irq[dev], SA_INTERRUPT,
303 NULL) < 0)
304 snd_printk("no MPU-401 device at 0x%lx\n", snd_mpu_port[dev]);
305 }
306
307 if (snd_fm_port[dev] > 0) {
308 if (snd_opl3_create(card,
309 snd_fm_port[dev], snd_fm_port[dev] + 2,
310 OPL3_HW_AUTO, 0, &opl3) < 0) {
311 snd_printk("no OPL device at 0x%lx-0x%lx\n",
312 snd_fm_port[dev], snd_fm_port[dev] + 2);
313 } else {
314 if ((error = snd_opl3_timer_new(opl3, 0, 1)) < 0) {
315 snd_card_free(card);
316 return error;
317 }
318 if ((error = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
319 snd_card_free(card);
320 return error;
321 }
322 }
323 }
324
325 strcpy(card->driver, "ALS100");
326 strcpy(card->shortname, "Avance Logic ALS100");
327 sprintf(card->longname, "%s soundcard, %s at 0x%lx, irq %d, dma %d&%d",
328 card->shortname, chip->name, chip->port,
329 snd_irq[dev], snd_dma8[dev], snd_dma16[dev]);
330 if ((error = snd_card_register(card)) < 0) {
331 snd_card_free(card);
332 return error;
333 }
334 snd_als100_cards[dev] = card;
335 return 0;
336}
337
338#ifdef __ISAPNP__
339static int __init snd_als100_isapnp_detect(struct isapnp_card *card,
340 const struct isapnp_card_id *id)
341{
342 static int dev = 0;
343 int res;
344
345 for ( ; dev < SNDRV_CARDS; dev++) {
346 if (!snd_enable[dev])
347 continue;
348 snd_als100_isapnp_cards[dev] = card;
349 snd_als100_isapnp_id[dev] = id;
350 res = snd_card_als100_probe(dev);
351 if (res < 0)
352 return res;
353 dev++;
354 return 0;
355 }
356 return -ENODEV;
357}
358#endif
359
360static int __init alsa_card_als100_init(void)
361{
362 int cards = 0;
363
364#ifdef __ISAPNP__
365 cards += isapnp_probe_cards(snd_als100_pnpids, snd_als100_isapnp_detect);
366#else
367 snd_printk("you have to enable ISA PnP support.\n");
368#endif
369#ifdef MODULE
370 if (!cards)
371 snd_printk("no ALS100 based soundcards found\n");
372#endif
373 return cards ? 0 : -ENODEV;
374}
375
376static void __exit alsa_card_als100_exit(void)
377{
378 int dev;
379
380 for (dev = 0; dev < SNDRV_CARDS; dev++)
381 snd_card_free(snd_als100_cards[dev]);
382}
383
384module_init(alsa_card_als100_init)
385module_exit(alsa_card_als100_exit)
386
387#ifndef MODULE
388
389/* format is: snd-card-als100=snd_enable,snd_index,snd_id,snd_port,
390 snd_mpu_port,snd_fm_port,snd_irq,snd_mpu_irq,
391 snd_dma8,snd_dma16 */
392
393static int __init alsa_card_als100_setup(char *str)
394{
395 static unsigned __initdata nr_dev = 0;
396
397 if (nr_dev >= SNDRV_CARDS)
398 return 0;
399 (void)(get_option(&str,&snd_enable[nr_dev]) == 2 &&
400 get_option(&str,&snd_index[nr_dev]) == 2 &&
401 get_id(&str,&snd_id[nr_dev]) == 2 &&
402 get_option(&str,(int *)&snd_port[nr_dev]) == 2 &&
403 get_option(&str,(int *)&snd_mpu_port[nr_dev]) == 2 &&
404 get_option(&str,(int *)&snd_fm_port[nr_dev]) == 2 &&
405 get_option(&str,&snd_irq[nr_dev]) == 2 &&
406 get_option(&str,&snd_mpu_irq[nr_dev]) == 2 &&
407 get_option(&str,&snd_dma8[nr_dev]) == 2 &&
408 get_option(&str,&snd_dma16[nr_dev]) == 2);
409 nr_dev++;
410 return 1;
411}
412
413__setup("snd-card-als100=", alsa_card_als100_setup);
414
415#endif /* ifndef MODULE */
Note: See TracBrowser for help on using the repository browser.