Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/pci/cs5530.c
26378 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* cs5530.c - Initialisation code for Cyrix/NatSemi VSA1 softaudio
4
*
5
* (C) Copyright 2007 Ash Willis <[email protected]>
6
* (C) Copyright 2003 Red Hat Inc <[email protected]>
7
*
8
* This driver was ported (shamelessly ripped ;) from oss/kahlua.c but I did
9
* mess with it a bit. The chip seems to have to have trouble with full duplex
10
* mode. If we're recording in 8bit 8000kHz, say, and we then attempt to
11
* simultaneously play back audio at 16bit 44100kHz, the device actually plays
12
* back in the same format in which it is capturing. By forcing the chip to
13
* always play/capture in 16/44100, we can let alsa-lib convert the samples and
14
* that way we can hack up some full duplex audio.
15
*
16
* XpressAudio(tm) is used on the Cyrix MediaGX (now NatSemi Geode) systems.
17
* The older version (VSA1) provides fairly good soundblaster emulation
18
* although there are a couple of bugs: large DMA buffers break record,
19
* and the MPU event handling seems suspect. VSA2 allows the native driver
20
* to control the AC97 audio engine directly and requires a different driver.
21
*
22
* Thanks to National Semiconductor for providing the needed information
23
* on the XpressAudio(tm) internals.
24
*
25
* TO DO:
26
* Investigate whether we can portably support Cognac (5520) in the
27
* same manner.
28
*/
29
30
#include <linux/delay.h>
31
#include <linux/module.h>
32
#include <linux/pci.h>
33
#include <linux/slab.h>
34
#include <sound/core.h>
35
#include <sound/sb.h>
36
#include <sound/initval.h>
37
38
MODULE_AUTHOR("Ash Willis");
39
MODULE_DESCRIPTION("CS5530 Audio");
40
MODULE_LICENSE("GPL");
41
42
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
43
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
44
static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
45
46
module_param_array(index, int, NULL, 0444);
47
MODULE_PARM_DESC(index, "Index value for CS5530 Audio driver.");
48
module_param_array(id, charp, NULL, 0444);
49
MODULE_PARM_DESC(id, "ID string for CS5530 Audio driver.");
50
module_param_array(enable, bool, NULL, 0444);
51
MODULE_PARM_DESC(enable, "Enable CS5530 Audio driver.");
52
53
struct snd_cs5530 {
54
struct snd_card *card;
55
struct pci_dev *pci;
56
struct snd_sb *sb;
57
unsigned long pci_base;
58
};
59
60
static const struct pci_device_id snd_cs5530_ids[] = {
61
{PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO, PCI_ANY_ID,
62
PCI_ANY_ID, 0, 0},
63
{0,}
64
};
65
66
MODULE_DEVICE_TABLE(pci, snd_cs5530_ids);
67
68
static u8 snd_cs5530_mixer_read(unsigned long io, u8 reg)
69
{
70
outb(reg, io + 4);
71
udelay(20);
72
reg = inb(io + 5);
73
udelay(20);
74
return reg;
75
}
76
77
static int snd_cs5530_create(struct snd_card *card,
78
struct pci_dev *pci)
79
{
80
struct snd_cs5530 *chip = card->private_data;
81
unsigned long sb_base;
82
u8 irq, dma8, dma16 = 0;
83
u16 map;
84
void __iomem *mem;
85
int err;
86
87
err = pcim_enable_device(pci);
88
if (err < 0)
89
return err;
90
91
chip->card = card;
92
chip->pci = pci;
93
94
mem = pcim_iomap_region(pci, 0, "CS5530");
95
if (IS_ERR(mem))
96
return PTR_ERR(mem);
97
chip->pci_base = pci_resource_start(pci, 0);
98
map = readw(mem + 0x18);
99
100
/* Map bits
101
0:1 * 0x20 + 0x200 = sb base
102
2 sb enable
103
3 adlib enable
104
5 MPU enable 0x330
105
6 MPU enable 0x300
106
107
The other bits may be used internally so must be masked */
108
109
sb_base = 0x220 + 0x20 * (map & 3);
110
111
if (map & (1<<2))
112
dev_info(card->dev, "XpressAudio at 0x%lx\n", sb_base);
113
else {
114
dev_err(card->dev, "Could not find XpressAudio!\n");
115
return -ENODEV;
116
}
117
118
if (map & (1<<5))
119
dev_info(card->dev, "MPU at 0x300\n");
120
else if (map & (1<<6))
121
dev_info(card->dev, "MPU at 0x330\n");
122
123
irq = snd_cs5530_mixer_read(sb_base, 0x80) & 0x0F;
124
dma8 = snd_cs5530_mixer_read(sb_base, 0x81);
125
126
if (dma8 & 0x20)
127
dma16 = 5;
128
else if (dma8 & 0x40)
129
dma16 = 6;
130
else if (dma8 & 0x80)
131
dma16 = 7;
132
else {
133
dev_err(card->dev, "No 16bit DMA enabled\n");
134
return -ENODEV;
135
}
136
137
if (dma8 & 0x01)
138
dma8 = 0;
139
else if (dma8 & 02)
140
dma8 = 1;
141
else if (dma8 & 0x08)
142
dma8 = 3;
143
else {
144
dev_err(card->dev, "No 8bit DMA enabled\n");
145
return -ENODEV;
146
}
147
148
if (irq & 1)
149
irq = 9;
150
else if (irq & 2)
151
irq = 5;
152
else if (irq & 4)
153
irq = 7;
154
else if (irq & 8)
155
irq = 10;
156
else {
157
dev_err(card->dev, "SoundBlaster IRQ not set\n");
158
return -ENODEV;
159
}
160
161
dev_info(card->dev, "IRQ: %d DMA8: %d DMA16: %d\n", irq, dma8, dma16);
162
163
err = snd_sbdsp_create(card, sb_base, irq, snd_sb16dsp_interrupt, dma8,
164
dma16, SB_HW_CS5530, &chip->sb);
165
if (err < 0) {
166
dev_err(card->dev, "Could not create SoundBlaster\n");
167
return err;
168
}
169
170
err = snd_sb16dsp_pcm(chip->sb, 0);
171
if (err < 0) {
172
dev_err(card->dev, "Could not create PCM\n");
173
return err;
174
}
175
176
err = snd_sbmixer_new(chip->sb);
177
if (err < 0) {
178
dev_err(card->dev, "Could not create Mixer\n");
179
return err;
180
}
181
182
return 0;
183
}
184
185
static int snd_cs5530_probe(struct pci_dev *pci,
186
const struct pci_device_id *pci_id)
187
{
188
static int dev;
189
struct snd_card *card;
190
struct snd_cs5530 *chip;
191
int err;
192
193
if (dev >= SNDRV_CARDS)
194
return -ENODEV;
195
if (!enable[dev]) {
196
dev++;
197
return -ENOENT;
198
}
199
200
err = snd_devm_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
201
sizeof(*chip), &card);
202
if (err < 0)
203
return err;
204
chip = card->private_data;
205
206
err = snd_cs5530_create(card, pci);
207
if (err < 0)
208
return err;
209
210
strscpy(card->driver, "CS5530");
211
strscpy(card->shortname, "CS5530 Audio");
212
sprintf(card->longname, "%s at 0x%lx", card->shortname, chip->pci_base);
213
214
err = snd_card_register(card);
215
if (err < 0)
216
return err;
217
pci_set_drvdata(pci, card);
218
dev++;
219
return 0;
220
}
221
222
static struct pci_driver cs5530_driver = {
223
.name = KBUILD_MODNAME,
224
.id_table = snd_cs5530_ids,
225
.probe = snd_cs5530_probe,
226
};
227
228
module_pci_driver(cs5530_driver);
229
230