Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/isa/azt2320.c
26378 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
card-azt2320.c - driver for Aztech Systems AZT2320 based soundcards.
4
Copyright (C) 1999-2000 by Massimo Piccioni <[email protected]>
5
6
*/
7
8
/*
9
This driver should provide support for most Aztech AZT2320 based cards.
10
Several AZT2316 chips are also supported/tested, but autoprobe doesn't
11
work: all module option have to be set.
12
13
No docs available for us at Aztech headquarters !!! Unbelievable ...
14
No other help obtained.
15
16
Thanks to Rainer Wiesner <[email protected]> for the WSS
17
activation method (full-duplex audio!).
18
*/
19
20
#include <linux/io.h>
21
#include <linux/delay.h>
22
#include <linux/init.h>
23
#include <linux/time.h>
24
#include <linux/wait.h>
25
#include <linux/pnp.h>
26
#include <linux/module.h>
27
#include <sound/core.h>
28
#include <sound/initval.h>
29
#include <sound/wss.h>
30
#include <sound/mpu401.h>
31
#include <sound/opl3.h>
32
33
MODULE_AUTHOR("Massimo Piccioni <[email protected]>");
34
MODULE_DESCRIPTION("Aztech Systems AZT2320");
35
MODULE_LICENSE("GPL");
36
37
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
38
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
39
static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
40
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
41
static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
42
static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
43
static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
44
static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* Pnp setup */
45
static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* Pnp setup */
46
static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */
47
static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */
48
49
module_param_array(index, int, NULL, 0444);
50
MODULE_PARM_DESC(index, "Index value for azt2320 based soundcard.");
51
module_param_array(id, charp, NULL, 0444);
52
MODULE_PARM_DESC(id, "ID string for azt2320 based soundcard.");
53
module_param_array(enable, bool, NULL, 0444);
54
MODULE_PARM_DESC(enable, "Enable azt2320 based soundcard.");
55
56
struct snd_card_azt2320 {
57
int dev_no;
58
struct pnp_dev *dev;
59
struct pnp_dev *devmpu;
60
struct snd_wss *chip;
61
};
62
63
static const struct pnp_card_device_id snd_azt2320_pnpids[] = {
64
/* PRO16V */
65
{ .id = "AZT1008", .devs = { { "AZT1008" }, { "AZT2001" }, } },
66
/* Aztech Sound Galaxy 16 */
67
{ .id = "AZT2320", .devs = { { "AZT0001" }, { "AZT0002" }, } },
68
/* Packard Bell Sound III 336 AM/SP */
69
{ .id = "AZT3000", .devs = { { "AZT1003" }, { "AZT2001" }, } },
70
/* AT3300 */
71
{ .id = "AZT3002", .devs = { { "AZT1004" }, { "AZT2001" }, } },
72
/* --- */
73
{ .id = "AZT3005", .devs = { { "AZT1003" }, { "AZT2001" }, } },
74
/* --- */
75
{ .id = "AZT3011", .devs = { { "AZT1003" }, { "AZT2001" }, } },
76
{ .id = "" } /* end */
77
};
78
79
MODULE_DEVICE_TABLE(pnp_card, snd_azt2320_pnpids);
80
81
#define DRIVER_NAME "snd-card-azt2320"
82
83
static int snd_card_azt2320_pnp(int dev, struct snd_card_azt2320 *acard,
84
struct pnp_card_link *card,
85
const struct pnp_card_device_id *id)
86
{
87
struct pnp_dev *pdev;
88
int err;
89
90
acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
91
if (acard->dev == NULL)
92
return -ENODEV;
93
94
acard->devmpu = pnp_request_card_device(card, id->devs[1].id, NULL);
95
96
pdev = acard->dev;
97
98
err = pnp_activate_dev(pdev);
99
if (err < 0) {
100
dev_err(&pdev->dev, "AUDIO pnp configure failure\n");
101
return err;
102
}
103
port[dev] = pnp_port_start(pdev, 0);
104
fm_port[dev] = pnp_port_start(pdev, 1);
105
wss_port[dev] = pnp_port_start(pdev, 2);
106
dma1[dev] = pnp_dma(pdev, 0);
107
dma2[dev] = pnp_dma(pdev, 1);
108
irq[dev] = pnp_irq(pdev, 0);
109
110
pdev = acard->devmpu;
111
if (pdev != NULL) {
112
err = pnp_activate_dev(pdev);
113
if (err < 0)
114
goto __mpu_error;
115
mpu_port[dev] = pnp_port_start(pdev, 0);
116
mpu_irq[dev] = pnp_irq(pdev, 0);
117
} else {
118
__mpu_error:
119
if (pdev) {
120
pnp_release_card_device(pdev);
121
dev_err(&pdev->dev, "MPU401 pnp configure failure, skipping\n");
122
}
123
acard->devmpu = NULL;
124
mpu_port[dev] = -1;
125
}
126
127
return 0;
128
}
129
130
/* same of snd_sbdsp_command by Jaroslav Kysela */
131
static int snd_card_azt2320_command(unsigned long port, unsigned char val)
132
{
133
int i;
134
unsigned long limit;
135
136
limit = jiffies + HZ / 10;
137
for (i = 50000; i && time_after(limit, jiffies); i--)
138
if (!(inb(port + 0x0c) & 0x80)) {
139
outb(val, port + 0x0c);
140
return 0;
141
}
142
return -EBUSY;
143
}
144
145
static int snd_card_azt2320_enable_wss(unsigned long port)
146
{
147
int error;
148
149
error = snd_card_azt2320_command(port, 0x09);
150
if (error)
151
return error;
152
error = snd_card_azt2320_command(port, 0x00);
153
if (error)
154
return error;
155
156
mdelay(5);
157
return 0;
158
}
159
160
static int snd_card_azt2320_probe(int dev,
161
struct pnp_card_link *pcard,
162
const struct pnp_card_device_id *pid)
163
{
164
int error;
165
struct snd_card *card;
166
struct snd_card_azt2320 *acard;
167
struct snd_wss *chip;
168
struct snd_opl3 *opl3;
169
170
error = snd_devm_card_new(&pcard->card->dev,
171
index[dev], id[dev], THIS_MODULE,
172
sizeof(struct snd_card_azt2320), &card);
173
if (error < 0)
174
return error;
175
acard = card->private_data;
176
177
error = snd_card_azt2320_pnp(dev, acard, pcard, pid);
178
if (error)
179
return error;
180
181
error = snd_card_azt2320_enable_wss(port[dev]);
182
if (error)
183
return error;
184
185
error = snd_wss_create(card, wss_port[dev], -1,
186
irq[dev],
187
dma1[dev], dma2[dev],
188
WSS_HW_DETECT, 0, &chip);
189
if (error < 0)
190
return error;
191
192
strscpy(card->driver, "AZT2320");
193
strscpy(card->shortname, "Aztech AZT2320");
194
sprintf(card->longname, "%s, WSS at 0x%lx, irq %i, dma %i&%i",
195
card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]);
196
197
error = snd_wss_pcm(chip, 0);
198
if (error < 0)
199
return error;
200
error = snd_wss_mixer(chip);
201
if (error < 0)
202
return error;
203
error = snd_wss_timer(chip, 0);
204
if (error < 0)
205
return error;
206
207
if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
208
if (snd_mpu401_uart_new(card, 0, MPU401_HW_AZT2320,
209
mpu_port[dev], 0,
210
mpu_irq[dev], NULL) < 0)
211
dev_err(card->dev, "no MPU-401 device at 0x%lx\n", mpu_port[dev]);
212
}
213
214
if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
215
if (snd_opl3_create(card,
216
fm_port[dev], fm_port[dev] + 2,
217
OPL3_HW_AUTO, 0, &opl3) < 0) {
218
dev_err(card->dev, "no OPL device at 0x%lx-0x%lx\n",
219
fm_port[dev], fm_port[dev] + 2);
220
} else {
221
error = snd_opl3_timer_new(opl3, 1, 2);
222
if (error < 0)
223
return error;
224
error = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
225
if (error < 0)
226
return error;
227
}
228
}
229
230
error = snd_card_register(card);
231
if (error < 0)
232
return error;
233
pnp_set_card_drvdata(pcard, card);
234
return 0;
235
}
236
237
static unsigned int azt2320_devices;
238
239
static int snd_azt2320_pnp_detect(struct pnp_card_link *card,
240
const struct pnp_card_device_id *id)
241
{
242
static int dev;
243
int res;
244
245
for ( ; dev < SNDRV_CARDS; dev++) {
246
if (!enable[dev])
247
continue;
248
res = snd_card_azt2320_probe(dev, card, id);
249
if (res < 0)
250
return res;
251
dev++;
252
azt2320_devices++;
253
return 0;
254
}
255
return -ENODEV;
256
}
257
258
#ifdef CONFIG_PM
259
static int snd_azt2320_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state)
260
{
261
struct snd_card *card = pnp_get_card_drvdata(pcard);
262
struct snd_card_azt2320 *acard = card->private_data;
263
struct snd_wss *chip = acard->chip;
264
265
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
266
chip->suspend(chip);
267
return 0;
268
}
269
270
static int snd_azt2320_pnp_resume(struct pnp_card_link *pcard)
271
{
272
struct snd_card *card = pnp_get_card_drvdata(pcard);
273
struct snd_card_azt2320 *acard = card->private_data;
274
struct snd_wss *chip = acard->chip;
275
276
chip->resume(chip);
277
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
278
return 0;
279
}
280
#endif
281
282
static struct pnp_card_driver azt2320_pnpc_driver = {
283
.flags = PNP_DRIVER_RES_DISABLE,
284
.name = "azt2320",
285
.id_table = snd_azt2320_pnpids,
286
.probe = snd_azt2320_pnp_detect,
287
#ifdef CONFIG_PM
288
.suspend = snd_azt2320_pnp_suspend,
289
.resume = snd_azt2320_pnp_resume,
290
#endif
291
};
292
293
static int __init alsa_card_azt2320_init(void)
294
{
295
int err;
296
297
err = pnp_register_card_driver(&azt2320_pnpc_driver);
298
if (err)
299
return err;
300
301
if (!azt2320_devices) {
302
pnp_unregister_card_driver(&azt2320_pnpc_driver);
303
#ifdef MODULE
304
pr_err("no AZT2320 based soundcards found\n");
305
#endif
306
return -ENODEV;
307
}
308
return 0;
309
}
310
311
static void __exit alsa_card_azt2320_exit(void)
312
{
313
pnp_unregister_card_driver(&azt2320_pnpc_driver);
314
}
315
316
module_init(alsa_card_azt2320_init)
317
module_exit(alsa_card_azt2320_exit)
318
319