Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/isa/galaxy/galaxy.c
26424 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Aztech AZT1605/AZT2316 Driver
4
* Copyright (C) 2007,2010 Rene Herman
5
*/
6
7
#include <linux/kernel.h>
8
#include <linux/module.h>
9
#include <linux/isa.h>
10
#include <linux/delay.h>
11
#include <linux/io.h>
12
#include <asm/processor.h>
13
#include <sound/core.h>
14
#include <sound/initval.h>
15
#include <sound/wss.h>
16
#include <sound/mpu401.h>
17
#include <sound/opl3.h>
18
19
MODULE_DESCRIPTION(CRD_NAME);
20
MODULE_AUTHOR("Rene Herman");
21
MODULE_LICENSE("GPL");
22
23
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
24
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
25
static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
26
27
module_param_array(index, int, NULL, 0444);
28
MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
29
module_param_array(id, charp, NULL, 0444);
30
MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard.");
31
module_param_array(enable, bool, NULL, 0444);
32
MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard.");
33
34
static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
35
static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
36
static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
37
static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
38
static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
39
static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
40
static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
41
static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
42
43
module_param_hw_array(port, long, ioport, NULL, 0444);
44
MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
45
module_param_hw_array(wss_port, long, ioport, NULL, 0444);
46
MODULE_PARM_DESC(wss_port, "WSS port # for " CRD_NAME " driver.");
47
module_param_hw_array(mpu_port, long, ioport, NULL, 0444);
48
MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " CRD_NAME " driver.");
49
module_param_hw_array(fm_port, long, ioport, NULL, 0444);
50
MODULE_PARM_DESC(fm_port, "FM port # for " CRD_NAME " driver.");
51
module_param_hw_array(irq, int, irq, NULL, 0444);
52
MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver.");
53
module_param_hw_array(mpu_irq, int, irq, NULL, 0444);
54
MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver.");
55
module_param_hw_array(dma1, int, dma, NULL, 0444);
56
MODULE_PARM_DESC(dma1, "Playback DMA # for " CRD_NAME " driver.");
57
module_param_hw_array(dma2, int, dma, NULL, 0444);
58
MODULE_PARM_DESC(dma2, "Capture DMA # for " CRD_NAME " driver.");
59
60
/*
61
* Generic SB DSP support routines
62
*/
63
64
#define DSP_PORT_RESET 0x6
65
#define DSP_PORT_READ 0xa
66
#define DSP_PORT_COMMAND 0xc
67
#define DSP_PORT_STATUS 0xc
68
#define DSP_PORT_DATA_AVAIL 0xe
69
70
#define DSP_SIGNATURE 0xaa
71
72
#define DSP_COMMAND_GET_VERSION 0xe1
73
74
static int dsp_get_byte(void __iomem *port, u8 *val)
75
{
76
int loops = 1000;
77
78
while (!(ioread8(port + DSP_PORT_DATA_AVAIL) & 0x80)) {
79
if (!loops--)
80
return -EIO;
81
cpu_relax();
82
}
83
*val = ioread8(port + DSP_PORT_READ);
84
return 0;
85
}
86
87
static int dsp_reset(void __iomem *port)
88
{
89
u8 val;
90
91
iowrite8(1, port + DSP_PORT_RESET);
92
udelay(10);
93
iowrite8(0, port + DSP_PORT_RESET);
94
95
if (dsp_get_byte(port, &val) < 0 || val != DSP_SIGNATURE)
96
return -ENODEV;
97
98
return 0;
99
}
100
101
static int dsp_command(void __iomem *port, u8 cmd)
102
{
103
int loops = 1000;
104
105
while (ioread8(port + DSP_PORT_STATUS) & 0x80) {
106
if (!loops--)
107
return -EIO;
108
cpu_relax();
109
}
110
iowrite8(cmd, port + DSP_PORT_COMMAND);
111
return 0;
112
}
113
114
static int dsp_get_version(void __iomem *port, u8 *major, u8 *minor)
115
{
116
int err;
117
118
err = dsp_command(port, DSP_COMMAND_GET_VERSION);
119
if (err < 0)
120
return err;
121
122
err = dsp_get_byte(port, major);
123
if (err < 0)
124
return err;
125
126
err = dsp_get_byte(port, minor);
127
if (err < 0)
128
return err;
129
130
return 0;
131
}
132
133
/*
134
* Generic WSS support routines
135
*/
136
137
#define WSS_CONFIG_DMA_0 (1 << 0)
138
#define WSS_CONFIG_DMA_1 (2 << 0)
139
#define WSS_CONFIG_DMA_3 (3 << 0)
140
#define WSS_CONFIG_DUPLEX (1 << 2)
141
#define WSS_CONFIG_IRQ_7 (1 << 3)
142
#define WSS_CONFIG_IRQ_9 (2 << 3)
143
#define WSS_CONFIG_IRQ_10 (3 << 3)
144
#define WSS_CONFIG_IRQ_11 (4 << 3)
145
146
#define WSS_PORT_CONFIG 0
147
#define WSS_PORT_SIGNATURE 3
148
149
#define WSS_SIGNATURE 4
150
151
static int wss_detect(void __iomem *wss_port)
152
{
153
if ((ioread8(wss_port + WSS_PORT_SIGNATURE) & 0x3f) != WSS_SIGNATURE)
154
return -ENODEV;
155
156
return 0;
157
}
158
159
static void wss_set_config(void __iomem *wss_port, u8 wss_config)
160
{
161
iowrite8(wss_config, wss_port + WSS_PORT_CONFIG);
162
}
163
164
/*
165
* Aztech Sound Galaxy specifics
166
*/
167
168
#define GALAXY_PORT_CONFIG 1024
169
#define CONFIG_PORT_SET 4
170
171
#define DSP_COMMAND_GALAXY_8 8
172
#define GALAXY_COMMAND_GET_TYPE 5
173
174
#define DSP_COMMAND_GALAXY_9 9
175
#define GALAXY_COMMAND_WSSMODE 0
176
#define GALAXY_COMMAND_SB8MODE 1
177
178
#define GALAXY_MODE_WSS GALAXY_COMMAND_WSSMODE
179
#define GALAXY_MODE_SB8 GALAXY_COMMAND_SB8MODE
180
181
struct snd_galaxy {
182
void __iomem *port;
183
void __iomem *config_port;
184
void __iomem *wss_port;
185
u32 config;
186
struct resource *res_port;
187
struct resource *res_config_port;
188
struct resource *res_wss_port;
189
};
190
191
static u32 config[SNDRV_CARDS];
192
static u8 wss_config[SNDRV_CARDS];
193
194
static int snd_galaxy_match(struct device *dev, unsigned int n)
195
{
196
if (!enable[n])
197
return 0;
198
199
switch (port[n]) {
200
case SNDRV_AUTO_PORT:
201
dev_err(dev, "please specify port\n");
202
return 0;
203
case 0x220:
204
config[n] |= GALAXY_CONFIG_SBA_220;
205
break;
206
case 0x240:
207
config[n] |= GALAXY_CONFIG_SBA_240;
208
break;
209
case 0x260:
210
config[n] |= GALAXY_CONFIG_SBA_260;
211
break;
212
case 0x280:
213
config[n] |= GALAXY_CONFIG_SBA_280;
214
break;
215
default:
216
dev_err(dev, "invalid port %#lx\n", port[n]);
217
return 0;
218
}
219
220
switch (wss_port[n]) {
221
case SNDRV_AUTO_PORT:
222
dev_err(dev, "please specify wss_port\n");
223
return 0;
224
case 0x530:
225
config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_530;
226
break;
227
case 0x604:
228
config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_604;
229
break;
230
case 0xe80:
231
config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_E80;
232
break;
233
case 0xf40:
234
config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_F40;
235
break;
236
default:
237
dev_err(dev, "invalid WSS port %#lx\n", wss_port[n]);
238
return 0;
239
}
240
241
switch (irq[n]) {
242
case SNDRV_AUTO_IRQ:
243
dev_err(dev, "please specify irq\n");
244
return 0;
245
case 7:
246
wss_config[n] |= WSS_CONFIG_IRQ_7;
247
break;
248
case 2:
249
irq[n] = 9;
250
fallthrough;
251
case 9:
252
wss_config[n] |= WSS_CONFIG_IRQ_9;
253
break;
254
case 10:
255
wss_config[n] |= WSS_CONFIG_IRQ_10;
256
break;
257
case 11:
258
wss_config[n] |= WSS_CONFIG_IRQ_11;
259
break;
260
default:
261
dev_err(dev, "invalid IRQ %d\n", irq[n]);
262
return 0;
263
}
264
265
switch (dma1[n]) {
266
case SNDRV_AUTO_DMA:
267
dev_err(dev, "please specify dma1\n");
268
return 0;
269
case 0:
270
wss_config[n] |= WSS_CONFIG_DMA_0;
271
break;
272
case 1:
273
wss_config[n] |= WSS_CONFIG_DMA_1;
274
break;
275
case 3:
276
wss_config[n] |= WSS_CONFIG_DMA_3;
277
break;
278
default:
279
dev_err(dev, "invalid playback DMA %d\n", dma1[n]);
280
return 0;
281
}
282
283
if (dma2[n] == SNDRV_AUTO_DMA || dma2[n] == dma1[n]) {
284
dma2[n] = -1;
285
goto mpu;
286
}
287
288
wss_config[n] |= WSS_CONFIG_DUPLEX;
289
switch (dma2[n]) {
290
case 0:
291
break;
292
case 1:
293
if (dma1[n] == 0)
294
break;
295
fallthrough;
296
default:
297
dev_err(dev, "invalid capture DMA %d\n", dma2[n]);
298
return 0;
299
}
300
301
mpu:
302
switch (mpu_port[n]) {
303
case SNDRV_AUTO_PORT:
304
dev_warn(dev, "mpu_port not specified; not using MPU-401\n");
305
mpu_port[n] = -1;
306
goto fm;
307
case 0x300:
308
config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_300;
309
break;
310
case 0x330:
311
config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_330;
312
break;
313
default:
314
dev_err(dev, "invalid MPU port %#lx\n", mpu_port[n]);
315
return 0;
316
}
317
318
switch (mpu_irq[n]) {
319
case SNDRV_AUTO_IRQ:
320
dev_warn(dev, "mpu_irq not specified: using polling mode\n");
321
mpu_irq[n] = -1;
322
break;
323
case 2:
324
mpu_irq[n] = 9;
325
fallthrough;
326
case 9:
327
config[n] |= GALAXY_CONFIG_MPUIRQ_2;
328
break;
329
#ifdef AZT1605
330
case 3:
331
config[n] |= GALAXY_CONFIG_MPUIRQ_3;
332
break;
333
#endif
334
case 5:
335
config[n] |= GALAXY_CONFIG_MPUIRQ_5;
336
break;
337
case 7:
338
config[n] |= GALAXY_CONFIG_MPUIRQ_7;
339
break;
340
#ifdef AZT2316
341
case 10:
342
config[n] |= GALAXY_CONFIG_MPUIRQ_10;
343
break;
344
#endif
345
default:
346
dev_err(dev, "invalid MPU IRQ %d\n", mpu_irq[n]);
347
return 0;
348
}
349
350
if (mpu_irq[n] == irq[n]) {
351
dev_err(dev, "cannot share IRQ between WSS and MPU-401\n");
352
return 0;
353
}
354
355
fm:
356
switch (fm_port[n]) {
357
case SNDRV_AUTO_PORT:
358
dev_warn(dev, "fm_port not specified: not using OPL3\n");
359
fm_port[n] = -1;
360
break;
361
case 0x388:
362
break;
363
default:
364
dev_err(dev, "illegal FM port %#lx\n", fm_port[n]);
365
return 0;
366
}
367
368
config[n] |= GALAXY_CONFIG_GAME_ENABLE;
369
return 1;
370
}
371
372
static int galaxy_init(struct snd_galaxy *galaxy, u8 *type)
373
{
374
u8 major;
375
u8 minor;
376
int err;
377
378
err = dsp_reset(galaxy->port);
379
if (err < 0)
380
return err;
381
382
err = dsp_get_version(galaxy->port, &major, &minor);
383
if (err < 0)
384
return err;
385
386
if (major != GALAXY_DSP_MAJOR || minor != GALAXY_DSP_MINOR)
387
return -ENODEV;
388
389
err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_8);
390
if (err < 0)
391
return err;
392
393
err = dsp_command(galaxy->port, GALAXY_COMMAND_GET_TYPE);
394
if (err < 0)
395
return err;
396
397
err = dsp_get_byte(galaxy->port, type);
398
if (err < 0)
399
return err;
400
401
return 0;
402
}
403
404
static int galaxy_set_mode(struct snd_galaxy *galaxy, u8 mode)
405
{
406
int err;
407
408
err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_9);
409
if (err < 0)
410
return err;
411
412
err = dsp_command(galaxy->port, mode);
413
if (err < 0)
414
return err;
415
416
#ifdef AZT1605
417
/*
418
* Needed for MPU IRQ on AZT1605, but AZT2316 loses WSS again
419
*/
420
err = dsp_reset(galaxy->port);
421
if (err < 0)
422
return err;
423
#endif
424
425
return 0;
426
}
427
428
static void galaxy_set_config(struct snd_galaxy *galaxy, u32 config)
429
{
430
u8 tmp = ioread8(galaxy->config_port + CONFIG_PORT_SET);
431
int i;
432
433
iowrite8(tmp | 0x80, galaxy->config_port + CONFIG_PORT_SET);
434
for (i = 0; i < GALAXY_CONFIG_SIZE; i++) {
435
iowrite8(config, galaxy->config_port + i);
436
config >>= 8;
437
}
438
iowrite8(tmp & 0x7f, galaxy->config_port + CONFIG_PORT_SET);
439
msleep(10);
440
}
441
442
static void galaxy_config(struct snd_galaxy *galaxy, u32 config)
443
{
444
int i;
445
446
for (i = GALAXY_CONFIG_SIZE; i; i--) {
447
u8 tmp = ioread8(galaxy->config_port + i - 1);
448
galaxy->config = (galaxy->config << 8) | tmp;
449
}
450
config |= galaxy->config & GALAXY_CONFIG_MASK;
451
galaxy_set_config(galaxy, config);
452
}
453
454
static int galaxy_wss_config(struct snd_galaxy *galaxy, u8 wss_config)
455
{
456
int err;
457
458
err = wss_detect(galaxy->wss_port);
459
if (err < 0)
460
return err;
461
462
wss_set_config(galaxy->wss_port, wss_config);
463
464
err = galaxy_set_mode(galaxy, GALAXY_MODE_WSS);
465
if (err < 0)
466
return err;
467
468
return 0;
469
}
470
471
static void snd_galaxy_free(struct snd_card *card)
472
{
473
struct snd_galaxy *galaxy = card->private_data;
474
475
if (galaxy->wss_port)
476
wss_set_config(galaxy->wss_port, 0);
477
if (galaxy->config_port)
478
galaxy_set_config(galaxy, galaxy->config);
479
}
480
481
static int __snd_galaxy_probe(struct device *dev, unsigned int n)
482
{
483
struct snd_galaxy *galaxy;
484
struct snd_wss *chip;
485
struct snd_card *card;
486
u8 type;
487
int err;
488
489
err = snd_devm_card_new(dev, index[n], id[n], THIS_MODULE,
490
sizeof(*galaxy), &card);
491
if (err < 0)
492
return err;
493
494
card->private_free = snd_galaxy_free;
495
galaxy = card->private_data;
496
497
galaxy->res_port = devm_request_region(dev, port[n], 16, DRV_NAME);
498
if (!galaxy->res_port) {
499
dev_err(dev, "could not grab ports %#lx-%#lx\n", port[n],
500
port[n] + 15);
501
return -EBUSY;
502
}
503
galaxy->port = devm_ioport_map(dev, port[n], 16);
504
if (!galaxy->port)
505
return -ENOMEM;
506
507
err = galaxy_init(galaxy, &type);
508
if (err < 0) {
509
dev_err(dev, "did not find a Sound Galaxy at %#lx\n", port[n]);
510
return err;
511
}
512
dev_info(dev, "Sound Galaxy (type %d) found at %#lx\n", type, port[n]);
513
514
galaxy->res_config_port =
515
devm_request_region(dev, port[n] + GALAXY_PORT_CONFIG, 16,
516
DRV_NAME);
517
if (!galaxy->res_config_port) {
518
dev_err(dev, "could not grab ports %#lx-%#lx\n",
519
port[n] + GALAXY_PORT_CONFIG,
520
port[n] + GALAXY_PORT_CONFIG + 15);
521
return -EBUSY;
522
}
523
galaxy->config_port =
524
devm_ioport_map(dev, port[n] + GALAXY_PORT_CONFIG, 16);
525
if (!galaxy->config_port)
526
return -ENOMEM;
527
galaxy_config(galaxy, config[n]);
528
529
galaxy->res_wss_port = devm_request_region(dev, wss_port[n], 4, DRV_NAME);
530
if (!galaxy->res_wss_port) {
531
dev_err(dev, "could not grab ports %#lx-%#lx\n", wss_port[n],
532
wss_port[n] + 3);
533
return -EBUSY;
534
}
535
galaxy->wss_port = devm_ioport_map(dev, wss_port[n], 4);
536
if (!galaxy->wss_port)
537
return -ENOMEM;
538
539
err = galaxy_wss_config(galaxy, wss_config[n]);
540
if (err < 0) {
541
dev_err(dev, "could not configure WSS\n");
542
return err;
543
}
544
545
strscpy(card->driver, DRV_NAME);
546
strscpy(card->shortname, DRV_NAME);
547
sprintf(card->longname, "%s at %#lx/%#lx, irq %d, dma %d/%d",
548
card->shortname, port[n], wss_port[n], irq[n], dma1[n],
549
dma2[n]);
550
551
err = snd_wss_create(card, wss_port[n] + 4, -1, irq[n], dma1[n],
552
dma2[n], WSS_HW_DETECT, 0, &chip);
553
if (err < 0)
554
return err;
555
556
err = snd_wss_pcm(chip, 0);
557
if (err < 0)
558
return err;
559
560
err = snd_wss_mixer(chip);
561
if (err < 0)
562
return err;
563
564
err = snd_wss_timer(chip, 0);
565
if (err < 0)
566
return err;
567
568
if (mpu_port[n] >= 0) {
569
err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
570
mpu_port[n], 0, mpu_irq[n], NULL);
571
if (err < 0)
572
return err;
573
}
574
575
if (fm_port[n] >= 0) {
576
struct snd_opl3 *opl3;
577
578
err = snd_opl3_create(card, fm_port[n], fm_port[n] + 2,
579
OPL3_HW_AUTO, 0, &opl3);
580
if (err < 0) {
581
dev_err(dev, "no OPL device at %#lx\n", fm_port[n]);
582
return err;
583
}
584
err = snd_opl3_timer_new(opl3, 1, 2);
585
if (err < 0)
586
return err;
587
588
err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
589
if (err < 0)
590
return err;
591
}
592
593
err = snd_card_register(card);
594
if (err < 0)
595
return err;
596
597
dev_set_drvdata(dev, card);
598
return 0;
599
}
600
601
static int snd_galaxy_probe(struct device *dev, unsigned int n)
602
{
603
return snd_card_free_on_error(dev, __snd_galaxy_probe(dev, n));
604
}
605
606
static struct isa_driver snd_galaxy_driver = {
607
.match = snd_galaxy_match,
608
.probe = snd_galaxy_probe,
609
610
.driver = {
611
.name = DEV_NAME
612
}
613
};
614
615
module_isa_driver(snd_galaxy_driver, SNDRV_CARDS);
616
617