]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - sound/isa/azt2320.c
[ALSA] sound/isa: kill pnp_resource_change
[linux-2.6-omap-h63xx.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 PFX "azt2320: "
47
48 MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
49 MODULE_DESCRIPTION("Aztech Systems AZT2320");
50 MODULE_LICENSE("GPL");
51 MODULE_SUPPORTED_DEVICE("{{Aztech Systems,PRO16V},"
52                 "{Aztech Systems,AZT2320},"
53                 "{Aztech Systems,AZT3300},"
54                 "{Aztech Systems,AZT2320},"
55                 "{Aztech Systems,AZT3000}}");
56
57 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;      /* Index 0-MAX */
58 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;       /* ID for this card */
59 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
60 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;     /* PnP setup */
61 static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
62 static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
63 static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;  /* PnP setup */
64 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;        /* Pnp setup */
65 static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;    /* Pnp setup */
66 static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;       /* PnP setup */
67 static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;       /* PnP setup */
68
69 module_param_array(index, int, NULL, 0444);
70 MODULE_PARM_DESC(index, "Index value for azt2320 based soundcard.");
71 module_param_array(id, charp, NULL, 0444);
72 MODULE_PARM_DESC(id, "ID string for azt2320 based soundcard.");
73 module_param_array(enable, bool, NULL, 0444);
74 MODULE_PARM_DESC(enable, "Enable azt2320 based soundcard.");
75
76 struct snd_card_azt2320 {
77         int dev_no;
78         struct pnp_dev *dev;
79         struct pnp_dev *devmpu;
80         struct snd_cs4231 *chip;
81 };
82
83 static struct pnp_card_device_id snd_azt2320_pnpids[] = {
84         /* PRO16V */
85         { .id = "AZT1008", .devs = { { "AZT1008" }, { "AZT2001" }, } },
86         /* Aztech Sound Galaxy 16 */
87         { .id = "AZT2320", .devs = { { "AZT0001" }, { "AZT0002" }, } },
88         /* Packard Bell Sound III 336 AM/SP */
89         { .id = "AZT3000", .devs = { { "AZT1003" }, { "AZT2001" }, } },
90         /* AT3300 */
91         { .id = "AZT3002", .devs = { { "AZT1004" }, { "AZT2001" }, } },
92         /* --- */
93         { .id = "AZT3005", .devs = { { "AZT1003" }, { "AZT2001" }, } },
94         /* --- */
95         { .id = "AZT3011", .devs = { { "AZT1003" }, { "AZT2001" }, } },
96         { .id = "" }    /* end */
97 };
98
99 MODULE_DEVICE_TABLE(pnp_card, snd_azt2320_pnpids);
100
101 #define DRIVER_NAME     "snd-card-azt2320"
102
103 static int __devinit snd_card_azt2320_pnp(int dev, struct snd_card_azt2320 *acard,
104                                           struct pnp_card_link *card,
105                                           const struct pnp_card_device_id *id)
106 {
107         struct pnp_dev *pdev;
108         int err;
109
110         acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
111         if (acard->dev == NULL)
112                 return -ENODEV;
113
114         acard->devmpu = pnp_request_card_device(card, id->devs[1].id, NULL);
115
116         pdev = acard->dev;
117
118         err = pnp_activate_dev(pdev);
119         if (err < 0) {
120                 snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n");
121                 return err;
122         }
123         port[dev] = pnp_port_start(pdev, 0);
124         fm_port[dev] = pnp_port_start(pdev, 1);
125         wss_port[dev] = pnp_port_start(pdev, 2);
126         dma1[dev] = pnp_dma(pdev, 0);
127         dma2[dev] = pnp_dma(pdev, 1);
128         irq[dev] = pnp_irq(pdev, 0);
129
130         pdev = acard->devmpu;
131         if (pdev != NULL) {
132                 err = pnp_activate_dev(pdev);
133                 if (err < 0)
134                         goto __mpu_error;
135                 mpu_port[dev] = pnp_port_start(pdev, 0);
136                 mpu_irq[dev] = pnp_irq(pdev, 0);
137         } else {
138              __mpu_error:
139                 if (pdev) {
140                         pnp_release_card_device(pdev);
141                         snd_printk(KERN_ERR PFX "MPU401 pnp configure failure, skipping\n");
142                 }
143                 acard->devmpu = NULL;
144                 mpu_port[dev] = -1;
145         }
146
147         return 0;
148 }
149
150 /* same of snd_sbdsp_command by Jaroslav Kysela */
151 static int __devinit snd_card_azt2320_command(unsigned long port, unsigned char val)
152 {
153         int i;
154         unsigned long limit;
155
156         limit = jiffies + HZ / 10;
157         for (i = 50000; i && time_after(limit, jiffies); i--)
158                 if (!(inb(port + 0x0c) & 0x80)) {
159                         outb(val, port + 0x0c);
160                         return 0;
161                 }
162         return -EBUSY;
163 }
164
165 static int __devinit snd_card_azt2320_enable_wss(unsigned long port)
166 {
167         int error;
168
169         if ((error = snd_card_azt2320_command(port, 0x09)))
170                 return error;
171         if ((error = snd_card_azt2320_command(port, 0x00)))
172                 return error;
173
174         mdelay(5);
175         return 0;
176 }
177
178 static int __devinit snd_card_azt2320_probe(int dev,
179                                             struct pnp_card_link *pcard,
180                                             const struct pnp_card_device_id *pid)
181 {
182         int error;
183         struct snd_card *card;
184         struct snd_card_azt2320 *acard;
185         struct snd_cs4231 *chip;
186         struct snd_opl3 *opl3;
187
188         if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
189                                  sizeof(struct snd_card_azt2320))) == NULL)
190                 return -ENOMEM;
191         acard = (struct snd_card_azt2320 *)card->private_data;
192
193         if ((error = snd_card_azt2320_pnp(dev, acard, pcard, pid))) {
194                 snd_card_free(card);
195                 return error;
196         }
197         snd_card_set_dev(card, &pcard->card->dev);
198
199         if ((error = snd_card_azt2320_enable_wss(port[dev]))) {
200                 snd_card_free(card);
201                 return error;
202         }
203
204         if ((error = snd_cs4231_create(card, wss_port[dev], -1,
205                                        irq[dev],
206                                        dma1[dev],
207                                        dma2[dev],
208                                        CS4231_HW_DETECT, 0, &chip)) < 0) {
209                 snd_card_free(card);
210                 return error;
211         }
212
213         strcpy(card->driver, "AZT2320");
214         strcpy(card->shortname, "Aztech AZT2320");
215         sprintf(card->longname, "%s, WSS at 0x%lx, irq %i, dma %i&%i",
216                 card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]);
217
218         if ((error = snd_cs4231_pcm(chip, 0, NULL)) < 0) {
219                 snd_card_free(card);
220                 return error;
221         }
222         if ((error = snd_cs4231_mixer(chip)) < 0) {
223                 snd_card_free(card);
224                 return error;
225         }
226         if ((error = snd_cs4231_timer(chip, 0, NULL)) < 0) {
227                 snd_card_free(card);
228                 return error;
229         }
230
231         if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
232                 if (snd_mpu401_uart_new(card, 0, MPU401_HW_AZT2320,
233                                 mpu_port[dev], 0,
234                                 mpu_irq[dev], IRQF_DISABLED,
235                                 NULL) < 0)
236                         snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]);
237         }
238
239         if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
240                 if (snd_opl3_create(card,
241                                     fm_port[dev], fm_port[dev] + 2,
242                                     OPL3_HW_AUTO, 0, &opl3) < 0) {
243                         snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx\n",
244                                    fm_port[dev], fm_port[dev] + 2);
245                 } else {
246                         if ((error = snd_opl3_timer_new(opl3, 1, 2)) < 0) {
247                                 snd_card_free(card);
248                                 return error;
249                         }
250                         if ((error = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
251                                 snd_card_free(card);
252                                 return error;
253                         }
254                 }
255         }
256
257         if ((error = snd_card_register(card)) < 0) {
258                 snd_card_free(card);
259                 return error;
260         }
261         pnp_set_card_drvdata(pcard, card);
262         return 0;
263 }
264
265 static unsigned int __devinitdata azt2320_devices;
266
267 static int __devinit snd_azt2320_pnp_detect(struct pnp_card_link *card,
268                                             const struct pnp_card_device_id *id)
269 {
270         static int dev;
271         int res;
272
273         for ( ; dev < SNDRV_CARDS; dev++) {
274                 if (!enable[dev])
275                         continue;
276                 res = snd_card_azt2320_probe(dev, card, id);
277                 if (res < 0)
278                         return res;
279                 dev++;
280                 azt2320_devices++;
281                 return 0;
282         }
283         return -ENODEV;
284 }
285
286 static void __devexit snd_azt2320_pnp_remove(struct pnp_card_link * pcard)
287 {
288         snd_card_free(pnp_get_card_drvdata(pcard));
289         pnp_set_card_drvdata(pcard, NULL);
290 }
291
292 #ifdef CONFIG_PM
293 static int snd_azt2320_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state)
294 {
295         struct snd_card *card = pnp_get_card_drvdata(pcard);
296         struct snd_card_azt2320 *acard = card->private_data;
297         struct snd_cs4231 *chip = acard->chip;
298
299         snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
300         chip->suspend(chip);
301         return 0;
302 }
303
304 static int snd_azt2320_pnp_resume(struct pnp_card_link *pcard)
305 {
306         struct snd_card *card = pnp_get_card_drvdata(pcard);
307         struct snd_card_azt2320 *acard = card->private_data;
308         struct snd_cs4231 *chip = acard->chip;
309
310         chip->resume(chip);
311         snd_power_change_state(card, SNDRV_CTL_POWER_D0);
312         return 0;
313 }
314 #endif
315
316 static struct pnp_card_driver azt2320_pnpc_driver = {
317         .flags          = PNP_DRIVER_RES_DISABLE,
318         .name           = "azt2320",
319         .id_table       = snd_azt2320_pnpids,
320         .probe          = snd_azt2320_pnp_detect,
321         .remove         = __devexit_p(snd_azt2320_pnp_remove),
322 #ifdef CONFIG_PM
323         .suspend        = snd_azt2320_pnp_suspend,
324         .resume         = snd_azt2320_pnp_resume,
325 #endif
326 };
327
328 static int __init alsa_card_azt2320_init(void)
329 {
330         int err;
331
332         err = pnp_register_card_driver(&azt2320_pnpc_driver);
333         if (err)
334                 return err;
335
336         if (!azt2320_devices) {
337                 pnp_unregister_card_driver(&azt2320_pnpc_driver);
338 #ifdef MODULE
339                 snd_printk(KERN_ERR "no AZT2320 based soundcards found\n");
340 #endif
341                 return -ENODEV;
342         }
343         return 0;
344 }
345
346 static void __exit alsa_card_azt2320_exit(void)
347 {
348         pnp_unregister_card_driver(&azt2320_pnpc_driver);
349 }
350
351 module_init(alsa_card_azt2320_init)
352 module_exit(alsa_card_azt2320_exit)