Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/isa/sb/sb16.c
29266 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Driver for SoundBlaster 16/AWE32/AWE64 soundcards
4
* Copyright (c) by Jaroslav Kysela <[email protected]>
5
*/
6
7
#include <asm/dma.h>
8
#include <linux/init.h>
9
#include <linux/pnp.h>
10
#include <linux/err.h>
11
#include <linux/isa.h>
12
#include <linux/module.h>
13
#include <linux/string.h>
14
#include <sound/core.h>
15
#include <sound/sb.h>
16
#include <sound/sb16_csp.h>
17
#include <sound/mpu401.h>
18
#include <sound/opl3.h>
19
#include <sound/emu8000.h>
20
#include <sound/seq_device.h>
21
#define SNDRV_LEGACY_FIND_FREE_IRQ
22
#define SNDRV_LEGACY_FIND_FREE_DMA
23
#include <sound/initval.h>
24
25
MODULE_AUTHOR("Jaroslav Kysela <[email protected]>");
26
MODULE_LICENSE("GPL");
27
#ifndef SNDRV_SBAWE
28
MODULE_DESCRIPTION("Sound Blaster 16");
29
#else
30
MODULE_DESCRIPTION("Sound Blaster AWE");
31
#endif
32
33
#if 0
34
#define SNDRV_DEBUG_IRQ
35
#endif
36
37
#if defined(SNDRV_SBAWE) && IS_ENABLED(CONFIG_SND_SEQUENCER)
38
#define SNDRV_SBAWE_EMU8000
39
#endif
40
41
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
42
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
43
static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
44
#ifdef CONFIG_PNP
45
static bool isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
46
#endif
47
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240,0x260,0x280 */
48
static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x330,0x300 */
49
static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
50
#ifdef SNDRV_SBAWE_EMU8000
51
static long awe_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
52
#endif
53
static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* 5,7,9,10 */
54
static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 0,1,3 */
55
static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* 5,6,7 */
56
static int mic_agc[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
57
#ifdef CONFIG_SND_SB16_CSP
58
static int csp[SNDRV_CARDS];
59
#endif
60
#ifdef SNDRV_SBAWE_EMU8000
61
static int seq_ports[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 4};
62
#endif
63
64
module_param_array(index, int, NULL, 0444);
65
MODULE_PARM_DESC(index, "Index value for SoundBlaster 16 soundcard.");
66
module_param_array(id, charp, NULL, 0444);
67
MODULE_PARM_DESC(id, "ID string for SoundBlaster 16 soundcard.");
68
module_param_array(enable, bool, NULL, 0444);
69
MODULE_PARM_DESC(enable, "Enable SoundBlaster 16 soundcard.");
70
#ifdef CONFIG_PNP
71
module_param_array(isapnp, bool, NULL, 0444);
72
MODULE_PARM_DESC(isapnp, "PnP detection for specified soundcard.");
73
#endif
74
module_param_hw_array(port, long, ioport, NULL, 0444);
75
MODULE_PARM_DESC(port, "Port # for SB16 driver.");
76
module_param_hw_array(mpu_port, long, ioport, NULL, 0444);
77
MODULE_PARM_DESC(mpu_port, "MPU-401 port # for SB16 driver.");
78
module_param_hw_array(fm_port, long, ioport, NULL, 0444);
79
MODULE_PARM_DESC(fm_port, "FM port # for SB16 PnP driver.");
80
#ifdef SNDRV_SBAWE_EMU8000
81
module_param_hw_array(awe_port, long, ioport, NULL, 0444);
82
MODULE_PARM_DESC(awe_port, "AWE port # for SB16 PnP driver.");
83
#endif
84
module_param_hw_array(irq, int, irq, NULL, 0444);
85
MODULE_PARM_DESC(irq, "IRQ # for SB16 driver.");
86
module_param_hw_array(dma8, int, dma, NULL, 0444);
87
MODULE_PARM_DESC(dma8, "8-bit DMA # for SB16 driver.");
88
module_param_hw_array(dma16, int, dma, NULL, 0444);
89
MODULE_PARM_DESC(dma16, "16-bit DMA # for SB16 driver.");
90
module_param_array(mic_agc, int, NULL, 0444);
91
MODULE_PARM_DESC(mic_agc, "Mic Auto-Gain-Control switch.");
92
#ifdef CONFIG_SND_SB16_CSP
93
module_param_array(csp, int, NULL, 0444);
94
MODULE_PARM_DESC(csp, "ASP/CSP chip support.");
95
#endif
96
#ifdef SNDRV_SBAWE_EMU8000
97
module_param_array(seq_ports, int, NULL, 0444);
98
MODULE_PARM_DESC(seq_ports, "Number of sequencer ports for WaveTable synth.");
99
#endif
100
101
#ifdef CONFIG_PNP
102
static int isa_registered;
103
static int pnp_registered;
104
#endif
105
106
struct snd_card_sb16 {
107
struct resource *fm_res; /* used to block FM i/o region for legacy cards */
108
struct snd_sb *chip;
109
#ifdef CONFIG_PNP
110
int dev_no;
111
struct pnp_dev *dev;
112
#ifdef SNDRV_SBAWE_EMU8000
113
struct pnp_dev *devwt;
114
#endif
115
#endif
116
};
117
118
#ifdef CONFIG_PNP
119
120
static const struct pnp_card_device_id snd_sb16_pnpids[] = {
121
#ifndef SNDRV_SBAWE
122
/* Sound Blaster 16 PnP */
123
{ .id = "CTL0024", .devs = { { "CTL0031" } } },
124
/* Sound Blaster 16 PnP */
125
{ .id = "CTL0025", .devs = { { "CTL0031" } } },
126
/* Sound Blaster 16 PnP */
127
{ .id = "CTL0026", .devs = { { "CTL0031" } } },
128
/* Sound Blaster 16 PnP */
129
{ .id = "CTL0027", .devs = { { "CTL0031" } } },
130
/* Sound Blaster 16 PnP */
131
{ .id = "CTL0028", .devs = { { "CTL0031" } } },
132
/* Sound Blaster 16 PnP */
133
{ .id = "CTL0029", .devs = { { "CTL0031" } } },
134
/* Sound Blaster 16 PnP */
135
{ .id = "CTL002a", .devs = { { "CTL0031" } } },
136
/* Sound Blaster 16 PnP */
137
/* Note: This card has also a CTL0051:StereoEnhance device!!! */
138
{ .id = "CTL002b", .devs = { { "CTL0031" } } },
139
/* Sound Blaster 16 PnP */
140
{ .id = "CTL002c", .devs = { { "CTL0031" } } },
141
/* Sound Blaster Vibra16S */
142
{ .id = "CTL0051", .devs = { { "CTL0001" } } },
143
/* Sound Blaster Vibra16C */
144
{ .id = "CTL0070", .devs = { { "CTL0001" } } },
145
/* Sound Blaster Vibra16CL - added by [email protected] */
146
{ .id = "CTL0080", .devs = { { "CTL0041" } } },
147
/* Sound Blaster 16 'value' PnP. It says model ct4130 on the pcb, */
148
/* but ct4131 on a sticker on the board.. */
149
{ .id = "CTL0086", .devs = { { "CTL0041" } } },
150
/* Sound Blaster Vibra16X */
151
{ .id = "CTL00f0", .devs = { { "CTL0043" } } },
152
/* Sound Blaster 16 (Virtual PC 2004) */
153
{ .id = "tBA03b0", .devs = { {.id="PNPb003" } } },
154
#else /* SNDRV_SBAWE defined */
155
/* Sound Blaster AWE 32 PnP */
156
{ .id = "CTL0035", .devs = { { "CTL0031" }, { "CTL0021" } } },
157
/* Sound Blaster AWE 32 PnP */
158
{ .id = "CTL0039", .devs = { { "CTL0031" }, { "CTL0021" } } },
159
/* Sound Blaster AWE 32 PnP */
160
{ .id = "CTL0042", .devs = { { "CTL0031" }, { "CTL0021" } } },
161
/* Sound Blaster AWE 32 PnP */
162
{ .id = "CTL0043", .devs = { { "CTL0031" }, { "CTL0021" } } },
163
/* Sound Blaster AWE 32 PnP */
164
/* Note: This card has also a CTL0051:StereoEnhance device!!! */
165
{ .id = "CTL0044", .devs = { { "CTL0031" }, { "CTL0021" } } },
166
/* Sound Blaster AWE 32 PnP */
167
/* Note: This card has also a CTL0051:StereoEnhance device!!! */
168
{ .id = "CTL0045", .devs = { { "CTL0031" }, { "CTL0021" } } },
169
/* Sound Blaster AWE 32 PnP */
170
{ .id = "CTL0046", .devs = { { "CTL0031" }, { "CTL0021" } } },
171
/* Sound Blaster AWE 32 PnP */
172
{ .id = "CTL0047", .devs = { { "CTL0031" }, { "CTL0021" } } },
173
/* Sound Blaster AWE 32 PnP */
174
{ .id = "CTL0048", .devs = { { "CTL0031" }, { "CTL0021" } } },
175
/* Sound Blaster AWE 32 PnP */
176
{ .id = "CTL0054", .devs = { { "CTL0031" }, { "CTL0021" } } },
177
/* Sound Blaster AWE 32 PnP */
178
{ .id = "CTL009a", .devs = { { "CTL0041" }, { "CTL0021" } } },
179
/* Sound Blaster AWE 32 PnP */
180
{ .id = "CTL009c", .devs = { { "CTL0041" }, { "CTL0021" } } },
181
/* Sound Blaster 32 PnP */
182
{ .id = "CTL009f", .devs = { { "CTL0041" }, { "CTL0021" } } },
183
/* Sound Blaster AWE 64 PnP */
184
{ .id = "CTL009d", .devs = { { "CTL0042" }, { "CTL0022" } } },
185
/* Sound Blaster AWE 64 PnP Gold */
186
{ .id = "CTL009e", .devs = { { "CTL0044" }, { "CTL0023" } } },
187
/* Sound Blaster AWE 64 PnP Gold */
188
{ .id = "CTL00b2", .devs = { { "CTL0044" }, { "CTL0023" } } },
189
/* Sound Blaster AWE 64 PnP */
190
{ .id = "CTL00c1", .devs = { { "CTL0042" }, { "CTL0022" } } },
191
/* Sound Blaster AWE 64 PnP */
192
{ .id = "CTL00c3", .devs = { { "CTL0045" }, { "CTL0022" } } },
193
/* Sound Blaster AWE 64 PnP */
194
{ .id = "CTL00c5", .devs = { { "CTL0045" }, { "CTL0022" } } },
195
/* Sound Blaster AWE 64 PnP */
196
{ .id = "CTL00c7", .devs = { { "CTL0045" }, { "CTL0022" } } },
197
/* Sound Blaster AWE 64 PnP */
198
{ .id = "CTL00e4", .devs = { { "CTL0045" }, { "CTL0022" } } },
199
/* Sound Blaster AWE 64 PnP */
200
{ .id = "CTL00e9", .devs = { { "CTL0045" }, { "CTL0022" } } },
201
/* Sound Blaster 16 PnP (AWE) */
202
{ .id = "CTL00ed", .devs = { { "CTL0041" }, { "CTL0070" } } },
203
/* Generic entries */
204
{ .id = "CTLXXXX" , .devs = { { "CTL0031" }, { "CTL0021" } } },
205
{ .id = "CTLXXXX" , .devs = { { "CTL0041" }, { "CTL0021" } } },
206
{ .id = "CTLXXXX" , .devs = { { "CTL0042" }, { "CTL0022" } } },
207
{ .id = "CTLXXXX" , .devs = { { "CTL0044" }, { "CTL0023" } } },
208
{ .id = "CTLXXXX" , .devs = { { "CTL0045" }, { "CTL0022" } } },
209
#endif /* SNDRV_SBAWE */
210
{ .id = "", }
211
};
212
213
MODULE_DEVICE_TABLE(pnp_card, snd_sb16_pnpids);
214
215
#endif /* CONFIG_PNP */
216
217
#ifdef SNDRV_SBAWE_EMU8000
218
#define DRIVER_NAME "snd-card-sbawe"
219
#else
220
#define DRIVER_NAME "snd-card-sb16"
221
#endif
222
223
#ifdef CONFIG_PNP
224
225
static int snd_card_sb16_pnp(int dev, struct snd_card_sb16 *acard,
226
struct pnp_card_link *card,
227
const struct pnp_card_device_id *id)
228
{
229
struct pnp_dev *pdev;
230
int err;
231
232
acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
233
if (acard->dev == NULL)
234
return -ENODEV;
235
236
#ifdef SNDRV_SBAWE_EMU8000
237
acard->devwt = pnp_request_card_device(card, id->devs[1].id, acard->dev);
238
#endif
239
/* Audio initialization */
240
pdev = acard->dev;
241
242
err = pnp_activate_dev(pdev);
243
if (err < 0) {
244
dev_err(&pdev->dev, "AUDIO pnp configure failure\n");
245
return err;
246
}
247
port[dev] = pnp_port_start(pdev, 0);
248
mpu_port[dev] = pnp_port_start(pdev, 1);
249
fm_port[dev] = pnp_port_start(pdev, 2);
250
dma8[dev] = pnp_dma(pdev, 0);
251
dma16[dev] = pnp_dma(pdev, 1);
252
irq[dev] = pnp_irq(pdev, 0);
253
dev_dbg(&pdev->dev, "pnp SB16: port=0x%lx, mpu port=0x%lx, fm port=0x%lx\n",
254
port[dev], mpu_port[dev], fm_port[dev]);
255
dev_dbg(&pdev->dev, "pnp SB16: dma1=%i, dma2=%i, irq=%i\n",
256
dma8[dev], dma16[dev], irq[dev]);
257
#ifdef SNDRV_SBAWE_EMU8000
258
/* WaveTable initialization */
259
pdev = acard->devwt;
260
if (pdev != NULL) {
261
err = pnp_activate_dev(pdev);
262
if (err < 0) {
263
goto __wt_error;
264
}
265
awe_port[dev] = pnp_port_start(pdev, 0);
266
dev_dbg(&pdev->dev, "pnp SB16: wavetable port=0x%llx\n",
267
(unsigned long long)pnp_port_start(pdev, 0));
268
} else {
269
__wt_error:
270
if (pdev) {
271
pnp_release_card_device(pdev);
272
dev_err(&pdev->dev, "WaveTable pnp configure failure\n");
273
}
274
acard->devwt = NULL;
275
awe_port[dev] = -1;
276
}
277
#endif
278
return 0;
279
}
280
281
#endif /* CONFIG_PNP */
282
283
#ifdef CONFIG_PNP
284
#define is_isapnp_selected(dev) isapnp[dev]
285
#else
286
#define is_isapnp_selected(dev) 0
287
#endif
288
289
static int snd_sb16_card_new(struct device *devptr, int dev,
290
struct snd_card **cardp)
291
{
292
struct snd_card *card;
293
int err;
294
295
err = snd_devm_card_new(devptr, index[dev], id[dev], THIS_MODULE,
296
sizeof(struct snd_card_sb16), &card);
297
if (err < 0)
298
return err;
299
*cardp = card;
300
return 0;
301
}
302
303
static int snd_sb16_probe(struct snd_card *card, int dev)
304
{
305
int xirq, xdma8, xdma16;
306
struct snd_sb *chip;
307
struct snd_card_sb16 *acard = card->private_data;
308
struct snd_opl3 *opl3;
309
struct snd_hwdep *synth = NULL;
310
#ifdef CONFIG_SND_SB16_CSP
311
struct snd_hwdep *xcsp = NULL;
312
#endif
313
int err;
314
315
xirq = irq[dev];
316
xdma8 = dma8[dev];
317
xdma16 = dma16[dev];
318
319
err = snd_sbdsp_create(card, port[dev], xirq, snd_sb16dsp_interrupt,
320
xdma8, xdma16, SB_HW_AUTO, &chip);
321
if (err < 0)
322
return err;
323
324
acard->chip = chip;
325
if (chip->hardware != SB_HW_16) {
326
dev_err(card->dev, "SB 16 chip was not detected at 0x%lx\n", port[dev]);
327
return -ENODEV;
328
}
329
chip->mpu_port = mpu_port[dev];
330
if (!is_isapnp_selected(dev)) {
331
err = snd_sb16dsp_configure(chip);
332
if (err < 0)
333
return err;
334
}
335
336
err = snd_sb16dsp_pcm(chip, 0);
337
if (err < 0)
338
return err;
339
340
strscpy(card->driver,
341
#ifdef SNDRV_SBAWE_EMU8000
342
awe_port[dev] > 0 ? "SB AWE" :
343
#endif
344
"SB16");
345
strscpy(card->shortname, chip->name);
346
sprintf(card->longname, "%s at 0x%lx, irq %i, dma ",
347
chip->name,
348
chip->port,
349
xirq);
350
if (xdma8 >= 0)
351
sprintf(card->longname + strlen(card->longname), "%d", xdma8);
352
if (xdma16 >= 0)
353
sprintf(card->longname + strlen(card->longname), "%s%d",
354
xdma8 >= 0 ? "&" : "", xdma16);
355
356
if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) {
357
err = snd_mpu401_uart_new(card, 0, MPU401_HW_SB,
358
chip->mpu_port,
359
MPU401_INFO_IRQ_HOOK, -1,
360
&chip->rmidi);
361
if (err < 0)
362
return err;
363
chip->rmidi_callback = snd_mpu401_uart_interrupt;
364
}
365
366
#ifdef SNDRV_SBAWE_EMU8000
367
if (awe_port[dev] == SNDRV_AUTO_PORT)
368
awe_port[dev] = 0; /* disable */
369
#endif
370
371
if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
372
if (snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2,
373
OPL3_HW_OPL3,
374
acard->fm_res != NULL || fm_port[dev] == port[dev],
375
&opl3) < 0) {
376
dev_err(card->dev, "no OPL device at 0x%lx-0x%lx\n",
377
fm_port[dev], fm_port[dev] + 2);
378
} else {
379
#ifdef SNDRV_SBAWE_EMU8000
380
int seqdev = awe_port[dev] > 0 ? 2 : 1;
381
#else
382
int seqdev = 1;
383
#endif
384
err = snd_opl3_hwdep_new(opl3, 0, seqdev, &synth);
385
if (err < 0)
386
return err;
387
}
388
}
389
390
err = snd_sbmixer_new(chip);
391
if (err < 0)
392
return err;
393
394
#ifdef CONFIG_SND_SB16_CSP
395
/* CSP chip on SB16ASP/AWE32 */
396
if ((chip->hardware == SB_HW_16) && csp[dev]) {
397
snd_sb_csp_new(chip, synth != NULL ? 1 : 0, &xcsp);
398
if (xcsp) {
399
chip->csp = xcsp->private_data;
400
chip->hardware = SB_HW_16CSP;
401
} else {
402
dev_info(card->dev,
403
"warning - CSP chip not detected on soundcard #%i\n",
404
dev + 1);
405
}
406
}
407
#endif
408
#ifdef SNDRV_SBAWE_EMU8000
409
if (awe_port[dev] > 0) {
410
err = snd_emu8000_new(card, 1, awe_port[dev],
411
seq_ports[dev], NULL);
412
if (err < 0) {
413
dev_err(card->dev,
414
"fatal error - EMU-8000 synthesizer not detected at 0x%lx\n",
415
awe_port[dev]);
416
417
return err;
418
}
419
}
420
#endif
421
422
/* setup Mic AGC */
423
scoped_guard(spinlock_irqsave, &chip->mixer_lock) {
424
snd_sbmixer_write(chip, SB_DSP4_MIC_AGC,
425
(snd_sbmixer_read(chip, SB_DSP4_MIC_AGC) & 0x01) |
426
(mic_agc[dev] ? 0x00 : 0x01));
427
}
428
429
err = snd_card_register(card);
430
if (err < 0)
431
return err;
432
433
return 0;
434
}
435
436
#ifdef CONFIG_PM
437
static int snd_sb16_suspend(struct snd_card *card, pm_message_t state)
438
{
439
struct snd_card_sb16 *acard = card->private_data;
440
struct snd_sb *chip = acard->chip;
441
442
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
443
snd_sbmixer_suspend(chip);
444
return 0;
445
}
446
447
static int snd_sb16_resume(struct snd_card *card)
448
{
449
struct snd_card_sb16 *acard = card->private_data;
450
struct snd_sb *chip = acard->chip;
451
452
snd_sbdsp_reset(chip);
453
snd_sbmixer_resume(chip);
454
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
455
return 0;
456
}
457
#endif
458
459
static int snd_sb16_isa_probe1(int dev, struct device *pdev)
460
{
461
struct snd_card_sb16 *acard;
462
struct snd_card *card;
463
int err;
464
465
err = snd_sb16_card_new(pdev, dev, &card);
466
if (err < 0)
467
return err;
468
469
acard = card->private_data;
470
/* non-PnP FM port address is hardwired with base port address */
471
fm_port[dev] = port[dev];
472
/* block the 0x388 port to avoid PnP conflicts */
473
acard->fm_res = devm_request_region(card->dev, 0x388, 4,
474
"SoundBlaster FM");
475
#ifdef SNDRV_SBAWE_EMU8000
476
/* non-PnP AWE port address is hardwired with base port address */
477
awe_port[dev] = port[dev] + 0x400;
478
#endif
479
480
err = snd_sb16_probe(card, dev);
481
if (err < 0)
482
return err;
483
dev_set_drvdata(pdev, card);
484
return 0;
485
}
486
487
488
static int snd_sb16_isa_match(struct device *pdev, unsigned int dev)
489
{
490
return enable[dev] && !is_isapnp_selected(dev);
491
}
492
493
static int snd_sb16_isa_probe(struct device *pdev, unsigned int dev)
494
{
495
int err;
496
static const int possible_irqs[] = {5, 9, 10, 7, -1};
497
static const int possible_dmas8[] = {1, 3, 0, -1};
498
static const int possible_dmas16[] = {5, 6, 7, -1};
499
500
if (irq[dev] == SNDRV_AUTO_IRQ) {
501
irq[dev] = snd_legacy_find_free_irq(possible_irqs);
502
if (irq[dev] < 0) {
503
dev_err(pdev, "unable to find a free IRQ\n");
504
return -EBUSY;
505
}
506
}
507
if (dma8[dev] == SNDRV_AUTO_DMA) {
508
dma8[dev] = snd_legacy_find_free_dma(possible_dmas8);
509
if (dma8[dev] < 0) {
510
dev_err(pdev, "unable to find a free 8-bit DMA\n");
511
return -EBUSY;
512
}
513
}
514
if (dma16[dev] == SNDRV_AUTO_DMA) {
515
dma16[dev] = snd_legacy_find_free_dma(possible_dmas16);
516
if (dma16[dev] < 0) {
517
dev_err(pdev, "unable to find a free 16-bit DMA\n");
518
return -EBUSY;
519
}
520
}
521
522
if (port[dev] != SNDRV_AUTO_PORT)
523
return snd_sb16_isa_probe1(dev, pdev);
524
else {
525
static const int possible_ports[] = {0x220, 0x240, 0x260, 0x280};
526
int i;
527
for (i = 0; i < ARRAY_SIZE(possible_ports); i++) {
528
port[dev] = possible_ports[i];
529
err = snd_sb16_isa_probe1(dev, pdev);
530
if (! err)
531
return 0;
532
}
533
return err;
534
}
535
}
536
537
#ifdef CONFIG_PM
538
static int snd_sb16_isa_suspend(struct device *dev, unsigned int n,
539
pm_message_t state)
540
{
541
return snd_sb16_suspend(dev_get_drvdata(dev), state);
542
}
543
544
static int snd_sb16_isa_resume(struct device *dev, unsigned int n)
545
{
546
return snd_sb16_resume(dev_get_drvdata(dev));
547
}
548
#endif
549
550
#ifdef SNDRV_SBAWE
551
#define DEV_NAME "sbawe"
552
#else
553
#define DEV_NAME "sb16"
554
#endif
555
556
static struct isa_driver snd_sb16_isa_driver = {
557
.match = snd_sb16_isa_match,
558
.probe = snd_sb16_isa_probe,
559
#ifdef CONFIG_PM
560
.suspend = snd_sb16_isa_suspend,
561
.resume = snd_sb16_isa_resume,
562
#endif
563
.driver = {
564
.name = DEV_NAME
565
},
566
};
567
568
569
#ifdef CONFIG_PNP
570
static int snd_sb16_pnp_detect(struct pnp_card_link *pcard,
571
const struct pnp_card_device_id *pid)
572
{
573
static int dev;
574
struct snd_card *card;
575
int res;
576
577
for ( ; dev < SNDRV_CARDS; dev++) {
578
if (!enable[dev] || !isapnp[dev])
579
continue;
580
res = snd_sb16_card_new(&pcard->card->dev, dev, &card);
581
if (res < 0)
582
return res;
583
res = snd_card_sb16_pnp(dev, card->private_data, pcard, pid);
584
if (res < 0)
585
return res;
586
res = snd_sb16_probe(card, dev);
587
if (res < 0)
588
return res;
589
pnp_set_card_drvdata(pcard, card);
590
dev++;
591
return 0;
592
}
593
594
return -ENODEV;
595
}
596
597
#ifdef CONFIG_PM
598
static int snd_sb16_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state)
599
{
600
return snd_sb16_suspend(pnp_get_card_drvdata(pcard), state);
601
}
602
static int snd_sb16_pnp_resume(struct pnp_card_link *pcard)
603
{
604
return snd_sb16_resume(pnp_get_card_drvdata(pcard));
605
}
606
#endif
607
608
static struct pnp_card_driver sb16_pnpc_driver = {
609
.flags = PNP_DRIVER_RES_DISABLE,
610
#ifdef SNDRV_SBAWE
611
.name = "sbawe",
612
#else
613
.name = "sb16",
614
#endif
615
.id_table = snd_sb16_pnpids,
616
.probe = snd_sb16_pnp_detect,
617
#ifdef CONFIG_PM
618
.suspend = snd_sb16_pnp_suspend,
619
.resume = snd_sb16_pnp_resume,
620
#endif
621
};
622
623
#endif /* CONFIG_PNP */
624
625
static int __init alsa_card_sb16_init(void)
626
{
627
int err;
628
629
err = isa_register_driver(&snd_sb16_isa_driver, SNDRV_CARDS);
630
#ifdef CONFIG_PNP
631
if (!err)
632
isa_registered = 1;
633
634
err = pnp_register_card_driver(&sb16_pnpc_driver);
635
if (!err)
636
pnp_registered = 1;
637
638
if (isa_registered)
639
err = 0;
640
#endif
641
return err;
642
}
643
644
static void __exit alsa_card_sb16_exit(void)
645
{
646
#ifdef CONFIG_PNP
647
if (pnp_registered)
648
pnp_unregister_card_driver(&sb16_pnpc_driver);
649
if (isa_registered)
650
#endif
651
isa_unregister_driver(&snd_sb16_isa_driver);
652
}
653
654
module_init(alsa_card_sb16_init)
655
module_exit(alsa_card_sb16_exit)
656
657