patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / sound / isa / azt2320.c
1 /*
2     card-azt2320.c - driver for Aztech Systems AZT2320 based soundcards.
3     Copyright (C) 1999-2000 by Massimo Piccioni <dafastidio@libero.it>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18 */
19
20 /*
21     This driver should provide support for most Aztech AZT2320 based cards.
22     Several AZT2316 chips are also supported/tested, but autoprobe doesn't
23     work: all module option have to be set.
24
25     No docs available for us at Aztech headquarters !!!   Unbelievable ...
26     No other help obtained.
27
28     Thanks to Rainer Wiesner <rainer.wiesner@01019freenet.de> for the WSS
29     activation method (full-duplex audio!).
30 */
31
32 #include <sound/driver.h>
33 #include <asm/io.h>
34 #include <linux/delay.h>
35 #include <linux/init.h>
36 #include <linux/time.h>
37 #include <linux/wait.h>
38 #include <linux/pnp.h>
39 #include <linux/moduleparam.h>
40 #include <sound/core.h>
41 #include <sound/initval.h>
42 #include <sound/cs4231.h>
43 #include <sound/mpu401.h>
44 #include <sound/opl3.h>
45
46 #define chip_t cs4231_t
47
48 #define PFX "azt2320: "
49
50 MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
51 MODULE_DESCRIPTION("Aztech Systems AZT2320");
52 MODULE_LICENSE("GPL");
53 MODULE_CLASSES("{sound}");
54 MODULE_DEVICES("{{Aztech Systems,PRO16V},"
55                 "{Aztech Systems,AZT2320},"
56                 "{Aztech Systems,AZT3300},"
57                 "{Aztech Systems,AZT2320},"
58                 "{Aztech Systems,AZT3000}}");
59
60 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;      /* Index 0-MAX */
61 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;       /* ID for this card */
62 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
63 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;     /* PnP setup */
64 static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
65 static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
66 static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;  /* PnP setup */
67 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;        /* Pnp setup */
68 static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;    /* Pnp setup */
69 static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;       /* PnP setup */
70 static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;       /* PnP setup */
71 static int boot_devs;
72
73 module_param_array(index, int, boot_devs, 0444);
74 MODULE_PARM_DESC(index, "Index value for azt2320 based soundcard.");
75 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
76 module_param_array(id, charp, boot_devs, 0444);
77 MODULE_PARM_DESC(id, "ID string for azt2320 based soundcard.");
78 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
79 module_param_array(enable, bool, boot_devs, 0444);
80 MODULE_PARM_DESC(enable, "Enable azt2320 based soundcard.");
81 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
82 module_param_array(port, long, boot_devs, 0444);
83 MODULE_PARM_DESC(port, "Port # for azt2320 driver.");
84 MODULE_PARM_SYNTAX(port, SNDRV_PORT12_DESC);
85 module_param_array(wss_port, long, boot_devs, 0444);
86 MODULE_PARM_DESC(wss_port, "WSS Port # for azt2320 driver.");
87 MODULE_PARM_SYNTAX(wss_port, SNDRV_PORT12_DESC);
88 module_param_array(mpu_port, long, boot_devs, 0444);
89 MODULE_PARM_DESC(mpu_port, "MPU-401 port # for azt2320 driver.");
90 MODULE_PARM_SYNTAX(mpu_port, SNDRV_PORT12_DESC);
91 module_param_array(fm_port, long, boot_devs, 0444);
92 MODULE_PARM_DESC(fm_port, "FM port # for azt2320 driver.");
93 MODULE_PARM_SYNTAX(fm_port, SNDRV_PORT12_DESC);
94 module_param_array(irq, int, boot_devs, 0444);
95 MODULE_PARM_DESC(irq, "IRQ # for azt2320 driver.");
96 MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC);
97 module_param_array(mpu_irq, int, boot_devs, 0444);
98 MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for azt2320 driver.");
99 MODULE_PARM_SYNTAX(mpu_irq, SNDRV_IRQ_DESC);
100 module_param_array(dma1, int, boot_devs, 0444);
101 MODULE_PARM_DESC(dma1, "1st DMA # for azt2320 driver.");
102 MODULE_PARM_SYNTAX(dma1, SNDRV_DMA_DESC);
103 module_param_array(dma2, int, boot_devs, 0444);
104 MODULE_PARM_DESC(dma2, "2nd DMA # for azt2320 driver.");
105 MODULE_PARM_SYNTAX(dma2, SNDRV_DMA_DESC);
106
107 struct snd_card_azt2320 {
108         int dev_no;
109         struct pnp_dev *dev;
110         struct pnp_dev *devmpu;
111 };
112
113 static struct pnp_card_device_id snd_azt2320_pnpids[] = {
114         /* PRO16V */
115         { .id = "AZT1008", .devs = { { "AZT1008" }, { "AZT2001" }, } },
116         /* Aztech Sound Galaxy 16 */
117         { .id = "AZT2320", .devs = { { "AZT0001" }, { "AZT0002" }, } },
118         /* Packard Bell Sound III 336 AM/SP */
119         { .id = "AZT3000", .devs = { { "AZT1003" }, { "AZT2001" }, } },
120         /* AT3300 */
121         { .id = "AZT3002", .devs = { { "AZT1004" }, { "AZT2001" }, } },
122         /* --- */
123         { .id = "AZT3005", .devs = { { "AZT1003" }, { "AZT2001" }, } },
124         /* --- */
125         { .id = "AZT3011", .devs = { { "AZT1003" }, { "AZT2001" }, } },
126         { .id = "" }    /* end */
127 };
128
129 MODULE_DEVICE_TABLE(pnp_card, snd_azt2320_pnpids);
130
131 #define DRIVER_NAME     "snd-card-azt2320"
132
133 static int __devinit snd_card_azt2320_pnp(int dev, struct snd_card_azt2320 *acard,
134                                           struct pnp_card_link *card,
135                                           const struct pnp_card_device_id *id)
136 {
137         struct pnp_dev *pdev;
138         struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
139         int err;
140
141         if (!cfg)
142                 return -ENOMEM;
143
144         acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
145         if (acard->dev == NULL) {
146                 kfree(cfg);
147                 return -ENODEV;
148         }
149
150         acard->devmpu = pnp_request_card_device(card, id->devs[1].id, NULL);
151
152         pdev = acard->dev;
153         pnp_init_resource_table(cfg);
154
155         /* override resources */
156         if (port[dev] != SNDRV_AUTO_PORT)
157                 pnp_resource_change(&cfg->port_resource[0], port[dev], 16);
158         if (fm_port[dev] != SNDRV_AUTO_PORT)
159                 pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4);
160         if (wss_port[dev] != SNDRV_AUTO_PORT)
161                 pnp_resource_change(&cfg->port_resource[2], wss_port[dev], 4);
162         if (dma1[dev] != SNDRV_AUTO_DMA)
163                 pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1);
164         if (dma2[dev] != SNDRV_AUTO_DMA)
165                 pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1);
166         if (irq[dev] != SNDRV_AUTO_IRQ)
167                 pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
168         if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
169                 snd_printk(KERN_ERR PFX "AUDIO the requested resources are invalid, using auto config\n");
170
171         err = pnp_activate_dev(pdev);
172         if (err < 0) {
173                 snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n");
174                 kfree(cfg);
175                 return err;
176         }
177         port[dev] = pnp_port_start(pdev, 0);
178         fm_port[dev] = pnp_port_start(pdev, 1);
179         wss_port[dev] = pnp_port_start(pdev, 2);
180         dma1[dev] = pnp_dma(pdev, 0);
181         dma2[dev] = pnp_dma(pdev, 1);
182         irq[dev] = pnp_irq(pdev, 0);
183
184         pdev = acard->devmpu;
185         if (pdev != NULL) {
186                 pnp_init_resource_table(cfg);
187                 if (mpu_port[dev] != SNDRV_AUTO_PORT)
188                         pnp_resource_change(&cfg->port_resource[0], mpu_port[dev], 2);
189                 if (mpu_irq[dev] != SNDRV_AUTO_IRQ)
190                         pnp_resource_change(&cfg->irq_resource[0], mpu_irq[dev], 1);
191                 if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
192                         snd_printk(KERN_ERR PFX "MPU401 the requested resources are invalid, using auto config\n");
193                 err = pnp_activate_dev(pdev);
194                 if (err < 0)
195                         goto __mpu_error;
196                 mpu_port[dev] = pnp_port_start(pdev, 0);
197                 mpu_irq[dev] = pnp_irq(pdev, 0);
198         } else {
199              __mpu_error:
200                 if (pdev) {
201                         pnp_release_card_device(pdev);
202                         snd_printk(KERN_ERR PFX "MPU401 pnp configure failure, skipping\n");
203                 }
204                 acard->devmpu = NULL;
205                 mpu_port[dev] = -1;
206         }
207
208         kfree (cfg);
209         return 0;
210 }
211
212 /* same of snd_sbdsp_command by Jaroslav Kysela */
213 static int __devinit snd_card_azt2320_command(unsigned long port, unsigned char val)
214 {
215         int i;
216         unsigned long limit;
217
218         limit = jiffies + HZ / 10;
219         for (i = 50000; i && time_after(limit, jiffies); i--)
220                 if (!(inb(port + 0x0c) & 0x80)) {
221                         outb(val, port + 0x0c);
222                         return 0;
223                 }
224         return -EBUSY;
225 }
226
227 static int __devinit snd_card_azt2320_enable_wss(unsigned long port)
228 {
229         int error;
230
231         if ((error = snd_card_azt2320_command(port, 0x09)))
232                 return error;
233         if ((error = snd_card_azt2320_command(port, 0x00)))
234                 return error;
235
236         mdelay(5);
237         return 0;
238 }
239
240 static int __devinit snd_card_azt2320_probe(int dev,
241                                             struct pnp_card_link *pcard,
242                                             const struct pnp_card_device_id *pid)
243 {
244         int error;
245         snd_card_t *card;
246         struct snd_card_azt2320 *acard;
247         cs4231_t *chip;
248         opl3_t *opl3;
249
250         if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
251                                  sizeof(struct snd_card_azt2320))) == NULL)
252                 return -ENOMEM;
253         acard = (struct snd_card_azt2320 *)card->private_data;
254
255         if ((error = snd_card_azt2320_pnp(dev, acard, pcard, pid))) {
256                 snd_card_free(card);
257                 return error;
258         }
259         snd_card_set_dev(card, &pcard->card->dev);
260
261         if ((error = snd_card_azt2320_enable_wss(port[dev]))) {
262                 snd_card_free(card);
263                 return error;
264         }
265
266         if ((error = snd_cs4231_create(card, wss_port[dev], -1,
267                                        irq[dev],
268                                        dma1[dev],
269                                        dma2[dev],
270                                        CS4231_HW_DETECT, 0, &chip)) < 0) {
271                 snd_card_free(card);
272                 return error;
273         }
274
275         strcpy(card->driver, "AZT2320");
276         strcpy(card->shortname, "Aztech AZT2320");
277         sprintf(card->longname, "%s, WSS at 0x%lx, irq %i, dma %i&%i",
278                 card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]);
279
280         if ((error = snd_cs4231_pcm(chip, 0, NULL)) < 0) {
281                 snd_card_free(card);
282                 return error;
283         }
284         if ((error = snd_cs4231_mixer(chip)) < 0) {
285                 snd_card_free(card);
286                 return error;
287         }
288         if ((error = snd_cs4231_timer(chip, 0, NULL)) < 0) {
289                 snd_card_free(card);
290                 return error;
291         }
292
293         if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
294                 if (snd_mpu401_uart_new(card, 0, MPU401_HW_AZT2320,
295                                 mpu_port[dev], 0,
296                                 mpu_irq[dev], SA_INTERRUPT,
297                                 NULL) < 0)
298                         snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]);
299         }
300
301         if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
302                 if (snd_opl3_create(card,
303                                     fm_port[dev], fm_port[dev] + 2,
304                                     OPL3_HW_AUTO, 0, &opl3) < 0) {
305                         snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx\n",
306                                    fm_port[dev], fm_port[dev] + 2);
307                 } else {
308                         if ((error = snd_opl3_timer_new(opl3, 1, 2)) < 0) {
309                                 snd_card_free(card);
310                                 return error;
311                         }
312                         if ((error = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
313                                 snd_card_free(card);
314                                 return error;
315                         }
316                 }
317         }
318
319         if ((error = snd_card_register(card)) < 0) {
320                 snd_card_free(card);
321                 return error;
322         }
323         pnp_set_card_drvdata(pcard, card);
324         return 0;
325 }
326
327 static int __devinit snd_azt2320_pnp_detect(struct pnp_card_link *card,
328                                             const struct pnp_card_device_id *id)
329 {
330         static int dev;
331         int res;
332
333         for ( ; dev < SNDRV_CARDS; dev++) {
334                 if (!enable[dev])
335                         continue;
336                 res = snd_card_azt2320_probe(dev, card, id);
337                 if (res < 0)
338                         return res;
339                 dev++;
340                 return 0;
341         }
342         return -ENODEV;
343 }
344
345 static void __devexit snd_azt2320_pnp_remove(struct pnp_card_link * pcard)
346 {
347         snd_card_t *card = (snd_card_t *) pnp_get_card_drvdata(pcard);
348
349         snd_card_disconnect(card);
350         snd_card_free_in_thread(card);
351 }
352
353 static struct pnp_card_driver azt2320_pnpc_driver = {
354         .flags          = PNP_DRIVER_RES_DISABLE,
355         .name           = "azt2320",
356         .id_table       = snd_azt2320_pnpids,
357         .probe          = snd_azt2320_pnp_detect,
358         .remove         = __devexit_p(snd_azt2320_pnp_remove),
359 };
360
361 static int __init alsa_card_azt2320_init(void)
362 {
363         int cards = 0;
364
365         cards += pnp_register_card_driver(&azt2320_pnpc_driver);
366 #ifdef MODULE
367         if (!cards) {
368                 pnp_unregister_card_driver(&azt2320_pnpc_driver);
369                 snd_printk(KERN_ERR "no AZT2320 based soundcards found\n");
370         }
371 #endif
372         return cards ? 0 : -ENODEV;
373 }
374
375 static void __exit alsa_card_azt2320_exit(void)
376 {
377         pnp_unregister_card_driver(&azt2320_pnpc_driver);
378 }
379
380 module_init(alsa_card_azt2320_init)
381 module_exit(alsa_card_azt2320_exit)