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