[ALSA] This patch removes open_mutex from the ad1848-lib as
[deliverable/linux.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 module_param_array(port, long, NULL, 0444);
76 MODULE_PARM_DESC(port, "Port # for azt2320 driver.");
77 module_param_array(wss_port, long, NULL, 0444);
78 MODULE_PARM_DESC(wss_port, "WSS Port # for azt2320 driver.");
79 module_param_array(mpu_port, long, NULL, 0444);
80 MODULE_PARM_DESC(mpu_port, "MPU-401 port # for azt2320 driver.");
81 module_param_array(fm_port, long, NULL, 0444);
82 MODULE_PARM_DESC(fm_port, "FM port # for azt2320 driver.");
83 module_param_array(irq, int, NULL, 0444);
84 MODULE_PARM_DESC(irq, "IRQ # for azt2320 driver.");
85 module_param_array(mpu_irq, int, NULL, 0444);
86 MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for azt2320 driver.");
87 module_param_array(dma1, int, NULL, 0444);
88 MODULE_PARM_DESC(dma1, "1st DMA # for azt2320 driver.");
89 module_param_array(dma2, int, NULL, 0444);
90 MODULE_PARM_DESC(dma2, "2nd DMA # for azt2320 driver.");
91
92 struct snd_card_azt2320 {
93 int dev_no;
94 struct pnp_dev *dev;
95 struct pnp_dev *devmpu;
96 struct snd_cs4231 *chip;
97 };
98
99 static struct pnp_card_device_id snd_azt2320_pnpids[] = {
100 /* PRO16V */
101 { .id = "AZT1008", .devs = { { "AZT1008" }, { "AZT2001" }, } },
102 /* Aztech Sound Galaxy 16 */
103 { .id = "AZT2320", .devs = { { "AZT0001" }, { "AZT0002" }, } },
104 /* Packard Bell Sound III 336 AM/SP */
105 { .id = "AZT3000", .devs = { { "AZT1003" }, { "AZT2001" }, } },
106 /* AT3300 */
107 { .id = "AZT3002", .devs = { { "AZT1004" }, { "AZT2001" }, } },
108 /* --- */
109 { .id = "AZT3005", .devs = { { "AZT1003" }, { "AZT2001" }, } },
110 /* --- */
111 { .id = "AZT3011", .devs = { { "AZT1003" }, { "AZT2001" }, } },
112 { .id = "" } /* end */
113 };
114
115 MODULE_DEVICE_TABLE(pnp_card, snd_azt2320_pnpids);
116
117 #define DRIVER_NAME "snd-card-azt2320"
118
119 static int __devinit snd_card_azt2320_pnp(int dev, struct snd_card_azt2320 *acard,
120 struct pnp_card_link *card,
121 const struct pnp_card_device_id *id)
122 {
123 struct pnp_dev *pdev;
124 struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
125 int err;
126
127 if (!cfg)
128 return -ENOMEM;
129
130 acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
131 if (acard->dev == NULL) {
132 kfree(cfg);
133 return -ENODEV;
134 }
135
136 acard->devmpu = pnp_request_card_device(card, id->devs[1].id, NULL);
137
138 pdev = acard->dev;
139 pnp_init_resource_table(cfg);
140
141 /* override resources */
142 if (port[dev] != SNDRV_AUTO_PORT)
143 pnp_resource_change(&cfg->port_resource[0], port[dev], 16);
144 if (fm_port[dev] != SNDRV_AUTO_PORT)
145 pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4);
146 if (wss_port[dev] != SNDRV_AUTO_PORT)
147 pnp_resource_change(&cfg->port_resource[2], wss_port[dev], 4);
148 if (dma1[dev] != SNDRV_AUTO_DMA)
149 pnp_resource_change(&cfg->dma_resource[0], dma1[dev], 1);
150 if (dma2[dev] != SNDRV_AUTO_DMA)
151 pnp_resource_change(&cfg->dma_resource[1], dma2[dev], 1);
152 if (irq[dev] != SNDRV_AUTO_IRQ)
153 pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1);
154 if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
155 snd_printk(KERN_ERR PFX "AUDIO the requested resources are invalid, using auto config\n");
156
157 err = pnp_activate_dev(pdev);
158 if (err < 0) {
159 snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n");
160 kfree(cfg);
161 return err;
162 }
163 port[dev] = pnp_port_start(pdev, 0);
164 fm_port[dev] = pnp_port_start(pdev, 1);
165 wss_port[dev] = pnp_port_start(pdev, 2);
166 dma1[dev] = pnp_dma(pdev, 0);
167 dma2[dev] = pnp_dma(pdev, 1);
168 irq[dev] = pnp_irq(pdev, 0);
169
170 pdev = acard->devmpu;
171 if (pdev != NULL) {
172 pnp_init_resource_table(cfg);
173 if (mpu_port[dev] != SNDRV_AUTO_PORT)
174 pnp_resource_change(&cfg->port_resource[0], mpu_port[dev], 2);
175 if (mpu_irq[dev] != SNDRV_AUTO_IRQ)
176 pnp_resource_change(&cfg->irq_resource[0], mpu_irq[dev], 1);
177 if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0)
178 snd_printk(KERN_ERR PFX "MPU401 the requested resources are invalid, using auto config\n");
179 err = pnp_activate_dev(pdev);
180 if (err < 0)
181 goto __mpu_error;
182 mpu_port[dev] = pnp_port_start(pdev, 0);
183 mpu_irq[dev] = pnp_irq(pdev, 0);
184 } else {
185 __mpu_error:
186 if (pdev) {
187 pnp_release_card_device(pdev);
188 snd_printk(KERN_ERR PFX "MPU401 pnp configure failure, skipping\n");
189 }
190 acard->devmpu = NULL;
191 mpu_port[dev] = -1;
192 }
193
194 kfree (cfg);
195 return 0;
196 }
197
198 /* same of snd_sbdsp_command by Jaroslav Kysela */
199 static int __devinit snd_card_azt2320_command(unsigned long port, unsigned char val)
200 {
201 int i;
202 unsigned long limit;
203
204 limit = jiffies + HZ / 10;
205 for (i = 50000; i && time_after(limit, jiffies); i--)
206 if (!(inb(port + 0x0c) & 0x80)) {
207 outb(val, port + 0x0c);
208 return 0;
209 }
210 return -EBUSY;
211 }
212
213 static int __devinit snd_card_azt2320_enable_wss(unsigned long port)
214 {
215 int error;
216
217 if ((error = snd_card_azt2320_command(port, 0x09)))
218 return error;
219 if ((error = snd_card_azt2320_command(port, 0x00)))
220 return error;
221
222 mdelay(5);
223 return 0;
224 }
225
226 static int __devinit snd_card_azt2320_probe(int dev,
227 struct pnp_card_link *pcard,
228 const struct pnp_card_device_id *pid)
229 {
230 int error;
231 struct snd_card *card;
232 struct snd_card_azt2320 *acard;
233 struct snd_cs4231 *chip;
234 struct snd_opl3 *opl3;
235
236 if ((card = snd_card_new(index[dev], id[dev], THIS_MODULE,
237 sizeof(struct snd_card_azt2320))) == NULL)
238 return -ENOMEM;
239 acard = (struct snd_card_azt2320 *)card->private_data;
240
241 if ((error = snd_card_azt2320_pnp(dev, acard, pcard, pid))) {
242 snd_card_free(card);
243 return error;
244 }
245 snd_card_set_dev(card, &pcard->card->dev);
246
247 if ((error = snd_card_azt2320_enable_wss(port[dev]))) {
248 snd_card_free(card);
249 return error;
250 }
251
252 if ((error = snd_cs4231_create(card, wss_port[dev], -1,
253 irq[dev],
254 dma1[dev],
255 dma2[dev],
256 CS4231_HW_DETECT, 0, &chip)) < 0) {
257 snd_card_free(card);
258 return error;
259 }
260
261 strcpy(card->driver, "AZT2320");
262 strcpy(card->shortname, "Aztech AZT2320");
263 sprintf(card->longname, "%s, WSS at 0x%lx, irq %i, dma %i&%i",
264 card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]);
265
266 if ((error = snd_cs4231_pcm(chip, 0, NULL)) < 0) {
267 snd_card_free(card);
268 return error;
269 }
270 if ((error = snd_cs4231_mixer(chip)) < 0) {
271 snd_card_free(card);
272 return error;
273 }
274 if ((error = snd_cs4231_timer(chip, 0, NULL)) < 0) {
275 snd_card_free(card);
276 return error;
277 }
278
279 if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
280 if (snd_mpu401_uart_new(card, 0, MPU401_HW_AZT2320,
281 mpu_port[dev], 0,
282 mpu_irq[dev], IRQF_DISABLED,
283 NULL) < 0)
284 snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]);
285 }
286
287 if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
288 if (snd_opl3_create(card,
289 fm_port[dev], fm_port[dev] + 2,
290 OPL3_HW_AUTO, 0, &opl3) < 0) {
291 snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx\n",
292 fm_port[dev], fm_port[dev] + 2);
293 } else {
294 if ((error = snd_opl3_timer_new(opl3, 1, 2)) < 0) {
295 snd_card_free(card);
296 return error;
297 }
298 if ((error = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
299 snd_card_free(card);
300 return error;
301 }
302 }
303 }
304
305 if ((error = snd_card_register(card)) < 0) {
306 snd_card_free(card);
307 return error;
308 }
309 pnp_set_card_drvdata(pcard, card);
310 return 0;
311 }
312
313 static unsigned int __devinitdata azt2320_devices;
314
315 static int __devinit snd_azt2320_pnp_detect(struct pnp_card_link *card,
316 const struct pnp_card_device_id *id)
317 {
318 static int dev;
319 int res;
320
321 for ( ; dev < SNDRV_CARDS; dev++) {
322 if (!enable[dev])
323 continue;
324 res = snd_card_azt2320_probe(dev, card, id);
325 if (res < 0)
326 return res;
327 dev++;
328 azt2320_devices++;
329 return 0;
330 }
331 return -ENODEV;
332 }
333
334 static void __devexit snd_azt2320_pnp_remove(struct pnp_card_link * pcard)
335 {
336 snd_card_free(pnp_get_card_drvdata(pcard));
337 pnp_set_card_drvdata(pcard, NULL);
338 }
339
340 #ifdef CONFIG_PM
341 static int snd_azt2320_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state)
342 {
343 struct snd_card *card = pnp_get_card_drvdata(pcard);
344 struct snd_card_azt2320 *acard = card->private_data;
345 struct snd_cs4231 *chip = acard->chip;
346
347 snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
348 chip->suspend(chip);
349 return 0;
350 }
351
352 static int snd_azt2320_pnp_resume(struct pnp_card_link *pcard)
353 {
354 struct snd_card *card = pnp_get_card_drvdata(pcard);
355 struct snd_card_azt2320 *acard = card->private_data;
356 struct snd_cs4231 *chip = acard->chip;
357
358 chip->resume(chip);
359 snd_power_change_state(card, SNDRV_CTL_POWER_D0);
360 return 0;
361 }
362 #endif
363
364 static struct pnp_card_driver azt2320_pnpc_driver = {
365 .flags = PNP_DRIVER_RES_DISABLE,
366 .name = "azt2320",
367 .id_table = snd_azt2320_pnpids,
368 .probe = snd_azt2320_pnp_detect,
369 .remove = __devexit_p(snd_azt2320_pnp_remove),
370 #ifdef CONFIG_PM
371 .suspend = snd_azt2320_pnp_suspend,
372 .resume = snd_azt2320_pnp_resume,
373 #endif
374 };
375
376 static int __init alsa_card_azt2320_init(void)
377 {
378 int err;
379
380 err = pnp_register_card_driver(&azt2320_pnpc_driver);
381 if (err)
382 return err;
383
384 if (!azt2320_devices) {
385 pnp_unregister_card_driver(&azt2320_pnpc_driver);
386 #ifdef MODULE
387 snd_printk(KERN_ERR "no AZT2320 based soundcards found\n");
388 #endif
389 return -ENODEV;
390 }
391 return 0;
392 }
393
394 static void __exit alsa_card_azt2320_exit(void)
395 {
396 pnp_unregister_card_driver(&azt2320_pnpc_driver);
397 }
398
399 module_init(alsa_card_azt2320_init)
400 module_exit(alsa_card_azt2320_exit)
This page took 0.041906 seconds and 5 git commands to generate.