Blame view

sound/pci/cs5530.c 6.6 KB
3e0a4e858   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
621887aee   Takashi Iwai   [ALSA] Add suppor...
2
3
4
5
  /*
   * cs5530.c - Initialisation code for Cyrix/NatSemi VSA1 softaudio
   *
   * 	(C) Copyright 2007 Ash Willis <ashwillis@programmer.net>
2f1e593d4   Alan Cox   sound: use a comm...
6
   *	(C) Copyright 2003 Red Hat Inc <alan@lxorguk.ukuu.org.uk>
621887aee   Takashi Iwai   [ALSA] Add suppor...
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
   *
   * This driver was ported (shamelessly ripped ;) from oss/kahlua.c but I did
   * mess with it a bit. The chip seems to have to have trouble with full duplex
   * mode. If we're recording in 8bit 8000kHz, say, and we then attempt to
   * simultaneously play back audio at 16bit 44100kHz, the device actually plays
   * back in the same format in which it is capturing. By forcing the chip to
   * always play/capture in 16/44100, we can let alsa-lib convert the samples and
   * that way we can hack up some full duplex audio. 
   * 
   * XpressAudio(tm) is used on the Cyrix MediaGX (now NatSemi Geode) systems.
   * The older version (VSA1) provides fairly good soundblaster emulation
   * although there are a couple of bugs: large DMA buffers break record,
   * and the MPU event handling seems suspect. VSA2 allows the native driver
   * to control the AC97 audio engine directly and requires a different driver.
   *
   * Thanks to National Semiconductor for providing the needed information
   * on the XpressAudio(tm) internals.
   *
621887aee   Takashi Iwai   [ALSA] Add suppor...
25
26
27
28
   * TO DO:
   *	Investigate whether we can portably support Cognac (5520) in the
   *	same manner.
   */
621887aee   Takashi Iwai   [ALSA] Add suppor...
29
  #include <linux/delay.h>
65a772172   Paul Gortmaker   sound: fix driver...
30
  #include <linux/module.h>
621887aee   Takashi Iwai   [ALSA] Add suppor...
31
  #include <linux/pci.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
32
  #include <linux/slab.h>
621887aee   Takashi Iwai   [ALSA] Add suppor...
33
34
35
36
37
38
39
40
41
42
  #include <sound/core.h>
  #include <sound/sb.h>
  #include <sound/initval.h>
  
  MODULE_AUTHOR("Ash Willis");
  MODULE_DESCRIPTION("CS5530 Audio");
  MODULE_LICENSE("GPL");
  
  static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
  static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
cde944803   Takashi Iwai   ALSA: Add missing...
43
44
45
46
47
48
49
50
  static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
  
  module_param_array(index, int, NULL, 0444);
  MODULE_PARM_DESC(index, "Index value for CS5530 Audio driver.");
  module_param_array(id, charp, NULL, 0444);
  MODULE_PARM_DESC(id, "ID string for CS5530 Audio driver.");
  module_param_array(enable, bool, NULL, 0444);
  MODULE_PARM_DESC(enable, "Enable CS5530 Audio driver.");
621887aee   Takashi Iwai   [ALSA] Add suppor...
51
52
53
54
55
56
57
  
  struct snd_cs5530 {
  	struct snd_card *card;
  	struct pci_dev *pci;
  	struct snd_sb *sb;
  	unsigned long pci_base;
  };
9baa3c34a   Benoit Taine   PCI: Remove DEFIN...
58
  static const struct pci_device_id snd_cs5530_ids[] = {
621887aee   Takashi Iwai   [ALSA] Add suppor...
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
  	{PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO, PCI_ANY_ID,
  							PCI_ANY_ID, 0, 0},
  	{0,}
  };
  
  MODULE_DEVICE_TABLE(pci, snd_cs5530_ids);
  
  static int snd_cs5530_free(struct snd_cs5530 *chip)
  {
  	pci_release_regions(chip->pci);
  	pci_disable_device(chip->pci);
  	kfree(chip);
  	return 0;
  }
  
  static int snd_cs5530_dev_free(struct snd_device *device)
  {
  	struct snd_cs5530 *chip = device->device_data;
  	return snd_cs5530_free(chip);
  }
e23e7a143   Bill Pemberton   ALSA: pci: remove...
79
  static void snd_cs5530_remove(struct pci_dev *pci)
621887aee   Takashi Iwai   [ALSA] Add suppor...
80
81
  {
  	snd_card_free(pci_get_drvdata(pci));
621887aee   Takashi Iwai   [ALSA] Add suppor...
82
  }
e23e7a143   Bill Pemberton   ALSA: pci: remove...
83
  static u8 snd_cs5530_mixer_read(unsigned long io, u8 reg)
621887aee   Takashi Iwai   [ALSA] Add suppor...
84
85
86
87
88
89
90
  {
  	outb(reg, io + 4);
  	udelay(20);
  	reg = inb(io + 5);
  	udelay(20);
  	return reg;
  }
e23e7a143   Bill Pemberton   ALSA: pci: remove...
91
92
93
  static int snd_cs5530_create(struct snd_card *card,
  			     struct pci_dev *pci,
  			     struct snd_cs5530 **rchip)
621887aee   Takashi Iwai   [ALSA] Add suppor...
94
95
96
97
98
99
100
  {
  	struct snd_cs5530 *chip;
  	unsigned long sb_base;
  	u8 irq, dma8, dma16 = 0;
  	u16 map;
  	void __iomem *mem;
  	int err;
efb0ad25d   Takashi Iwai   ALSA: pci: Consti...
101
  	static const struct snd_device_ops ops = {
621887aee   Takashi Iwai   [ALSA] Add suppor...
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
  		.dev_free = snd_cs5530_dev_free,
  	};
  	*rchip = NULL;
  
  	err = pci_enable_device(pci);
   	if (err < 0)
  		return err;
  
  	chip = kzalloc(sizeof(*chip), GFP_KERNEL);
  	if (chip == NULL) {
  		pci_disable_device(pci);
  		return -ENOMEM;
  	}
  
  	chip->card = card;
  	chip->pci = pci;
  
  	err = pci_request_regions(pci, "CS5530");
  	if (err < 0) {
  		kfree(chip); 
  		pci_disable_device(pci);
  		return err;
  	}
  	chip->pci_base = pci_resource_start(pci, 0);
2f5ad54ea   Arjan van de Ven   pci: use pci_iore...
126
  	mem = pci_ioremap_bar(pci, 0);
621887aee   Takashi Iwai   [ALSA] Add suppor...
127
  	if (mem == NULL) {
5a798394c   Takashi Iwai   ALSA: cs5530: Fix...
128
  		snd_cs5530_free(chip);
621887aee   Takashi Iwai   [ALSA] Add suppor...
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
  		return -EBUSY;
  	}
  
  	map = readw(mem + 0x18);
  	iounmap(mem);
  
  	/* Map bits
  		0:1	* 0x20 + 0x200 = sb base
  		2	sb enable
  		3	adlib enable
  		5	MPU enable 0x330
  		6	MPU enable 0x300
  
  	   The other bits may be used internally so must be masked */
  
  	sb_base = 0x220 + 0x20 * (map & 3);
  
  	if (map & (1<<2))
132b3873d   Takashi Iwai   ALSA: cs5530: Use...
147
148
  		dev_info(card->dev, "XpressAudio at 0x%lx
  ", sb_base);
621887aee   Takashi Iwai   [ALSA] Add suppor...
149
  	else {
132b3873d   Takashi Iwai   ALSA: cs5530: Use...
150
151
  		dev_err(card->dev, "Could not find XpressAudio!
  ");
621887aee   Takashi Iwai   [ALSA] Add suppor...
152
153
154
155
156
  		snd_cs5530_free(chip);
  		return -ENODEV;
  	}
  
  	if (map & (1<<5))
132b3873d   Takashi Iwai   ALSA: cs5530: Use...
157
158
  		dev_info(card->dev, "MPU at 0x300
  ");
621887aee   Takashi Iwai   [ALSA] Add suppor...
159
  	else if (map & (1<<6))
132b3873d   Takashi Iwai   ALSA: cs5530: Use...
160
161
  		dev_info(card->dev, "MPU at 0x330
  ");
621887aee   Takashi Iwai   [ALSA] Add suppor...
162
163
164
165
166
167
168
169
170
171
172
  
  	irq = snd_cs5530_mixer_read(sb_base, 0x80) & 0x0F;
  	dma8 = snd_cs5530_mixer_read(sb_base, 0x81);
  
  	if (dma8 & 0x20)
  		dma16 = 5;
  	else if (dma8 & 0x40)
  		dma16 = 6;
  	else if (dma8 & 0x80)
  		dma16 = 7;
  	else {
132b3873d   Takashi Iwai   ALSA: cs5530: Use...
173
174
  		dev_err(card->dev, "No 16bit DMA enabled
  ");
621887aee   Takashi Iwai   [ALSA] Add suppor...
175
176
177
178
179
180
181
182
183
184
185
  		snd_cs5530_free(chip);
  		return -ENODEV;
  	}
  
  	if (dma8 & 0x01)
  		dma8 = 0;
  	else if (dma8 & 02)
  		dma8 = 1;
  	else if (dma8 & 0x08)
  		dma8 = 3;
  	else {
132b3873d   Takashi Iwai   ALSA: cs5530: Use...
186
187
  		dev_err(card->dev, "No 8bit DMA enabled
  ");
621887aee   Takashi Iwai   [ALSA] Add suppor...
188
189
190
191
192
193
194
195
196
197
198
199
200
  		snd_cs5530_free(chip);
  		return -ENODEV;
  	}
  
  	if (irq & 1)
  		irq = 9;
  	else if (irq & 2)
  		irq = 5;
  	else if (irq & 4)
  		irq = 7;
  	else if (irq & 8)
  		irq = 10;
  	else {
132b3873d   Takashi Iwai   ALSA: cs5530: Use...
201
202
  		dev_err(card->dev, "SoundBlaster IRQ not set
  ");
621887aee   Takashi Iwai   [ALSA] Add suppor...
203
204
205
  		snd_cs5530_free(chip);
  		return -ENODEV;
  	}
132b3873d   Takashi Iwai   ALSA: cs5530: Use...
206
207
  	dev_info(card->dev, "IRQ: %d DMA8: %d DMA16: %d
  ", irq, dma8, dma16);
621887aee   Takashi Iwai   [ALSA] Add suppor...
208
209
210
211
  
  	err = snd_sbdsp_create(card, sb_base, irq, snd_sb16dsp_interrupt, dma8,
  						dma16, SB_HW_CS5530, &chip->sb);
  	if (err < 0) {
132b3873d   Takashi Iwai   ALSA: cs5530: Use...
212
213
  		dev_err(card->dev, "Could not create SoundBlaster
  ");
621887aee   Takashi Iwai   [ALSA] Add suppor...
214
215
216
  		snd_cs5530_free(chip);
  		return err;
  	}
92533f188   Lars-Peter Clausen   ASoC: sb16: Simpl...
217
  	err = snd_sb16dsp_pcm(chip->sb, 0);
621887aee   Takashi Iwai   [ALSA] Add suppor...
218
  	if (err < 0) {
132b3873d   Takashi Iwai   ALSA: cs5530: Use...
219
220
  		dev_err(card->dev, "Could not create PCM
  ");
621887aee   Takashi Iwai   [ALSA] Add suppor...
221
222
223
224
225
226
  		snd_cs5530_free(chip);
  		return err;
  	}
  
  	err = snd_sbmixer_new(chip->sb);
  	if (err < 0) {
132b3873d   Takashi Iwai   ALSA: cs5530: Use...
227
228
  		dev_err(card->dev, "Could not create Mixer
  ");
621887aee   Takashi Iwai   [ALSA] Add suppor...
229
230
231
232
233
234
235
236
237
  		snd_cs5530_free(chip);
  		return err;
  	}
  
  	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
  	if (err < 0) {
  		snd_cs5530_free(chip);
  		return err;
  	}
621887aee   Takashi Iwai   [ALSA] Add suppor...
238
239
240
  	*rchip = chip;
  	return 0;
  }
e23e7a143   Bill Pemberton   ALSA: pci: remove...
241
242
  static int snd_cs5530_probe(struct pci_dev *pci,
  			    const struct pci_device_id *pci_id)
621887aee   Takashi Iwai   [ALSA] Add suppor...
243
244
245
246
247
248
249
250
251
252
253
254
  {
  	static int dev;
  	struct snd_card *card;
  	struct snd_cs5530 *chip = NULL;
  	int err;
  
  	if (dev >= SNDRV_CARDS)
  		return -ENODEV;
  	if (!enable[dev]) {
  		dev++;
  		return -ENOENT;
  	}
60c5772b5   Takashi Iwai   ALSA: pci: Conver...
255
256
  	err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
  			   0, &card);
621887aee   Takashi Iwai   [ALSA] Add suppor...
257

e58de7baf   Takashi Iwai   ALSA: Convert to ...
258
259
  	if (err < 0)
  		return err;
621887aee   Takashi Iwai   [ALSA] Add suppor...
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
  
  	err = snd_cs5530_create(card, pci, &chip);
  	if (err < 0) {
  		snd_card_free(card);
  		return err;
  	}
  
  	strcpy(card->driver, "CS5530");
  	strcpy(card->shortname, "CS5530 Audio");
  	sprintf(card->longname, "%s at 0x%lx", card->shortname, chip->pci_base);
  
  	err = snd_card_register(card);
  	if (err < 0) {
  		snd_card_free(card);
  		return err;
  	}
  	pci_set_drvdata(pci, card);
  	dev++;
  	return 0;
  }
e9f66d9b9   Takashi Iwai   ALSA: pci: clean ...
280
  static struct pci_driver cs5530_driver = {
3733e424c   Takashi Iwai   ALSA: Use KBUILD_...
281
  	.name = KBUILD_MODNAME,
621887aee   Takashi Iwai   [ALSA] Add suppor...
282
283
  	.id_table = snd_cs5530_ids,
  	.probe = snd_cs5530_probe,
e23e7a143   Bill Pemberton   ALSA: pci: remove...
284
  	.remove = snd_cs5530_remove,
621887aee   Takashi Iwai   [ALSA] Add suppor...
285
  };
e9f66d9b9   Takashi Iwai   ALSA: pci: clean ...
286
  module_pci_driver(cs5530_driver);