]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - sound/isa/azt2320.c
x86_64: prepare shared lib/rwlock.S
[mirror_ubuntu-zesty-kernel.git] / sound / isa / azt2320.c
CommitLineData
1da177e4
LT
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
48MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
49MODULE_DESCRIPTION("Aztech Systems AZT2320");
50MODULE_LICENSE("GPL");
51MODULE_SUPPORTED_DEVICE("{{Aztech Systems,PRO16V},"
52 "{Aztech Systems,AZT2320},"
53 "{Aztech Systems,AZT3300},"
54 "{Aztech Systems,AZT2320},"
55 "{Aztech Systems,AZT3000}}");
56
57static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
58static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
59static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
60static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
61static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
62static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
63static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
64static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* Pnp setup */
65static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* Pnp setup */
66static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */
67static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */
68
69module_param_array(index, int, NULL, 0444);
70MODULE_PARM_DESC(index, "Index value for azt2320 based soundcard.");
71module_param_array(id, charp, NULL, 0444);
72MODULE_PARM_DESC(id, "ID string for azt2320 based soundcard.");
73module_param_array(enable, bool, NULL, 0444);
74MODULE_PARM_DESC(enable, "Enable azt2320 based soundcard.");
75module_param_array(port, long, NULL, 0444);
76MODULE_PARM_DESC(port, "Port # for azt2320 driver.");
77module_param_array(wss_port, long, NULL, 0444);
78MODULE_PARM_DESC(wss_port, "WSS Port # for azt2320 driver.");
79module_param_array(mpu_port, long, NULL, 0444);
80MODULE_PARM_DESC(mpu_port, "MPU-401 port # for azt2320 driver.");
81module_param_array(fm_port, long, NULL, 0444);
82MODULE_PARM_DESC(fm_port, "FM port # for azt2320 driver.");
83module_param_array(irq, int, NULL, 0444);
84MODULE_PARM_DESC(irq, "IRQ # for azt2320 driver.");
85module_param_array(mpu_irq, int, NULL, 0444);
86MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for azt2320 driver.");
87module_param_array(dma1, int, NULL, 0444);
88MODULE_PARM_DESC(dma1, "1st DMA # for azt2320 driver.");
89module_param_array(dma2, int, NULL, 0444);
90MODULE_PARM_DESC(dma2, "2nd DMA # for azt2320 driver.");
91
92struct snd_card_azt2320 {
93 int dev_no;
94 struct pnp_dev *dev;
95 struct pnp_dev *devmpu;
b6cc25ca 96 struct snd_cs4231 *chip;
1da177e4
LT
97};
98
99static 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
115MODULE_DEVICE_TABLE(pnp_card, snd_azt2320_pnpids);
116
117#define DRIVER_NAME "snd-card-azt2320"
118
119static 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 */
199static 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
213static 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
226static 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;
11ff5c62 231 struct snd_card *card;
1da177e4 232 struct snd_card_azt2320 *acard;
11ff5c62
TI
233 struct snd_cs4231 *chip;
234 struct snd_opl3 *opl3;
1da177e4
LT
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,
65ca68b3 282 mpu_irq[dev], IRQF_DISABLED,
1da177e4
LT
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
db2735eb
BH
313static unsigned int __devinitdata azt2320_devices;
314
1da177e4
LT
315static 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++;
db2735eb 328 azt2320_devices++;
1da177e4
LT
329 return 0;
330 }
331 return -ENODEV;
332}
333
334static void __devexit snd_azt2320_pnp_remove(struct pnp_card_link * pcard)
335{
b6cc25ca
TI
336 snd_card_free(pnp_get_card_drvdata(pcard));
337 pnp_set_card_drvdata(pcard, NULL);
338}
339
340#ifdef CONFIG_PM
341static 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
352static 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;
1da177e4 357
b6cc25ca
TI
358 chip->resume(chip);
359 snd_power_change_state(card, SNDRV_CTL_POWER_D0);
360 return 0;
1da177e4 361}
b6cc25ca 362#endif
1da177e4
LT
363
364static 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),
b6cc25ca
TI
370#ifdef CONFIG_PM
371 .suspend = snd_azt2320_pnp_suspend,
372 .resume = snd_azt2320_pnp_resume,
373#endif
1da177e4
LT
374};
375
376static int __init alsa_card_azt2320_init(void)
377{
db2735eb
BH
378 int err;
379
380 err = pnp_register_card_driver(&azt2320_pnpc_driver);
381 if (err)
382 return err;
1da177e4 383
db2735eb 384 if (!azt2320_devices) {
1da177e4 385 pnp_unregister_card_driver(&azt2320_pnpc_driver);
b6cc25ca 386#ifdef MODULE
1da177e4 387 snd_printk(KERN_ERR "no AZT2320 based soundcards found\n");
1da177e4 388#endif
b6cc25ca
TI
389 return -ENODEV;
390 }
391 return 0;
1da177e4
LT
392}
393
394static void __exit alsa_card_azt2320_exit(void)
395{
396 pnp_unregister_card_driver(&azt2320_pnpc_driver);
397}
398
399module_init(alsa_card_azt2320_init)
400module_exit(alsa_card_azt2320_exit)