source: GPL/alsa-kernel/pci/sonicvibes.c@ 18

Last change on this file since 18 was 18, checked in by vladest, 20 years ago

initial import

File size: 58.3 KB
Line 
1/*
2 * Driver for S3 SonicVibes soundcard
3 * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
4 *
5 * BUGS:
6 * It looks like 86c617 rev 3 doesn't supports DDMA buffers above 16MB?
7 * Driver sometimes hangs... Nobody knows why at this moment...
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 */
24
25#define SNDRV_MAIN_OBJECT_FILE
26#include <sound/driver.h>
27#include <sound/pcm.h>
28#include <sound/info.h>
29#include <sound/control.h>
30#include <sound/mpu401.h>
31#include <sound/opl3.h>
32#define SNDRV_GET_ID
33#include <sound/initval.h>
34
35EXPORT_NO_SYMBOLS;
36MODULE_DESCRIPTION("S3 SonicVibes PCI");
37MODULE_CLASSES("{sound}");
38MODULE_DEVICES("{{S3,SonicVibes PCI}}");
39
40#ifndef PCI_VENDOR_ID_S3
41#define PCI_VENDOR_ID_S3 0x5333
42#endif
43#ifndef PCI_DEVICE_ID_S3_SONICVIBES
44#define PCI_DEVICE_ID_S3_SONICVIBES 0xca00
45#endif
46
47static int snd_index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
48static char *snd_id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
49static int snd_enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
50#ifdef TARGET_OS2
51static int snd_reverb[SNDRV_CARDS] = {0,0,0,0,0,0,0,0};
52static int snd_mge[SNDRV_CARDS] = {0,0,0,0,0,0,0,0};
53#else
54static int snd_reverb[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
55static int snd_mge[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0};
56#endif
57static unsigned int snd_dmaio = 0x7a00; /* DDMA i/o address */
58
59MODULE_PARM(snd_index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
60MODULE_PARM_DESC(snd_index, "Index value for S3 SonicVibes soundcard.");
61MODULE_PARM_SYNTAX(snd_index, SNDRV_INDEX_DESC);
62MODULE_PARM(snd_id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
63MODULE_PARM_DESC(snd_id, "ID string for S3 SonicVibes soundcard.");
64MODULE_PARM_SYNTAX(snd_id, SNDRV_ID_DESC);
65MODULE_PARM(snd_enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
66MODULE_PARM_DESC(snd_enable, "Enable S3 SonicVibes soundcard.");
67MODULE_PARM_SYNTAX(snd_enable, SNDRV_ENABLE_DESC);
68MODULE_PARM(snd_reverb, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
69MODULE_PARM_DESC(snd_reverb, "Enable reverb (SRAM is present) for S3 SonicVibes soundcard.");
70MODULE_PARM_SYNTAX(snd_reverb, SNDRV_ENABLED "," SNDRV_ENABLE_DESC);
71MODULE_PARM(snd_mge, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
72MODULE_PARM_DESC(snd_mge, "MIC Gain Enable for S3 SonicVibes soundcard.");
73MODULE_PARM_SYNTAX(snd_mge, SNDRV_ENABLED "," SNDRV_ENABLE_DESC);
74MODULE_PARM(snd_dmaio, "i");
75MODULE_PARM_DESC(snd_dmaio, "DDMA i/o base address for S3 SonicVibes soundcard.");
76MODULE_PARM_SYNTAX(snd_dmaio, "global," SNDRV_PORT_DESC);
77
78/*
79 * Enhanced port direct registers
80 */
81
82#define SV_REG(sonic, x) ((sonic)->enh_port + SV_REG_##x)
83
84#define SV_REG_CONTROL 0x00 /* R/W: CODEC/Mixer control register */
85#define SV_ENHANCED 0x01 /* audio mode select - enhanced mode */
86#define SV_TEST 0x02 /* test bit */
87#define SV_REVERB 0x04 /* reverb enable */
88#define SV_WAVETABLE 0x08 /* wavetable active / FM active if not set */
89#define SV_INTA 0x20 /* INTA driving - should be always 1 */
90#define SV_RESET 0x80 /* reset chip */
91#define SV_REG_IRQMASK 0x01 /* R/W: CODEC/Mixer interrupt mask register */
92#define SV_DMAA_MASK 0x01 /* mask DMA-A interrupt */
93#define SV_DMAC_MASK 0x04 /* mask DMA-C interrupt */
94#define SV_SPEC_MASK 0x08 /* special interrupt mask - should be always masked */
95#define SV_UD_MASK 0x40 /* Up/Down button interrupt mask */
96#define SV_MIDI_MASK 0x80 /* mask MIDI interrupt */
97#define SV_REG_STATUS 0x02 /* R/O: CODEC/Mixer status register */
98#define SV_DMAA_IRQ 0x01 /* DMA-A interrupt */
99#define SV_DMAC_IRQ 0x04 /* DMA-C interrupt */
100#define SV_SPEC_IRQ 0x08 /* special interrupt */
101#define SV_UD_IRQ 0x40 /* Up/Down interrupt */
102#define SV_MIDI_IRQ 0x80 /* MIDI interrupt */
103#define SV_REG_INDEX 0x04 /* R/W: CODEC/Mixer index address register */
104#define SV_MCE 0x40 /* mode change enable */
105#define SV_TRD 0x80 /* DMA transfer request disabled */
106#define SV_REG_DATA 0x05 /* R/W: CODEC/Mixer index data register */
107
108/*
109 * Enhanced port indirect registers
110 */
111
112#define SV_IREG_LEFT_ADC 0x00 /* Left ADC Input Control */
113#define SV_IREG_RIGHT_ADC 0x01 /* Right ADC Input Control */
114#define SV_IREG_LEFT_AUX1 0x02 /* Left AUX1 Input Control */
115#define SV_IREG_RIGHT_AUX1 0x03 /* Right AUX1 Input Control */
116#define SV_IREG_LEFT_CD 0x04 /* Left CD Input Control */
117#define SV_IREG_RIGHT_CD 0x05 /* Right CD Input Control */
118#define SV_IREG_LEFT_LINE 0x06 /* Left Line Input Control */
119#define SV_IREG_RIGHT_LINE 0x07 /* Right Line Input Control */
120#define SV_IREG_MIC 0x08 /* MIC Input Control */
121#define SV_IREG_GAME_PORT 0x09 /* Game Port Control */
122#define SV_IREG_LEFT_SYNTH 0x0a /* Left Synth Input Control */
123#define SV_IREG_RIGHT_SYNTH 0x0b /* Right Synth Input Control */
124#define SV_IREG_LEFT_AUX2 0x0c /* Left AUX2 Input Control */
125#define SV_IREG_RIGHT_AUX2 0x0d /* Right AUX2 Input Control */
126#define SV_IREG_LEFT_ANALOG 0x0e /* Left Analog Mixer Output Control */
127#define SV_IREG_RIGHT_ANALOG 0x0f /* Right Analog Mixer Output Control */
128#define SV_IREG_LEFT_PCM 0x10 /* Left PCM Input Control */
129#define SV_IREG_RIGHT_PCM 0x11 /* Right PCM Input Control */
130#define SV_IREG_DMA_DATA_FMT 0x12 /* DMA Data Format */
131#define SV_IREG_PC_ENABLE 0x13 /* Playback/Capture Enable Register */
132#define SV_IREG_UD_BUTTON 0x14 /* Up/Down Button Register */
133#define SV_IREG_REVISION 0x15 /* Revision */
134#define SV_IREG_ADC_OUTPUT_CTRL 0x16 /* ADC Output Control */
135#define SV_IREG_DMA_A_UPPER 0x18 /* DMA A Upper Base Count */
136#define SV_IREG_DMA_A_LOWER 0x19 /* DMA A Lower Base Count */
137#define SV_IREG_DMA_C_UPPER 0x1c /* DMA C Upper Base Count */
138#define SV_IREG_DMA_C_LOWER 0x1d /* DMA C Lower Base Count */
139#define SV_IREG_PCM_RATE_LOW 0x1e /* PCM Sampling Rate Low Byte */
140#define SV_IREG_PCM_RATE_HIGH 0x1f /* PCM Sampling Rate High Byte */
141#define SV_IREG_SYNTH_RATE_LOW 0x20 /* Synthesizer Sampling Rate Low Byte */
142#define SV_IREG_SYNTH_RATE_HIGH 0x21 /* Synthesizer Sampling Rate High Byte */
143#define SV_IREG_ADC_CLOCK 0x22 /* ADC Clock Source Selection */
144#define SV_IREG_ADC_ALT_RATE 0x23 /* ADC Alternative Sampling Rate Selection */
145#define SV_IREG_ADC_PLL_M 0x24 /* ADC PLL M Register */
146#define SV_IREG_ADC_PLL_N 0x25 /* ADC PLL N Register */
147#define SV_IREG_SYNTH_PLL_M 0x26 /* Synthesizer PLL M Register */
148#define SV_IREG_SYNTH_PLL_N 0x27 /* Synthesizer PLL N Register */
149#define SV_IREG_MPU401 0x2a /* MPU-401 UART Operation */
150#define SV_IREG_DRIVE_CTRL 0x2b /* Drive Control */
151#define SV_IREG_SRS_SPACE 0x2c /* SRS Space Control */
152#define SV_IREG_SRS_CENTER 0x2d /* SRS Center Control */
153#define SV_IREG_WAVE_SOURCE 0x2e /* Wavetable Sample Source Select */
154#define SV_IREG_ANALOG_POWER 0x30 /* Analog Power Down Control */
155#define SV_IREG_DIGITAL_POWER 0x31 /* Digital Power Down Control */
156
157#define SV_IREG_ADC_PLL SV_IREG_ADC_PLL_M
158#define SV_IREG_SYNTH_PLL SV_IREG_SYNTH_PLL_M
159
160/*
161 * DMA registers
162 */
163
164#define SV_DMA_ADDR0 0x00
165#define SV_DMA_ADDR1 0x01
166#define SV_DMA_ADDR2 0x02
167#define SV_DMA_ADDR3 0x03
168#define SV_DMA_COUNT0 0x04
169#define SV_DMA_COUNT1 0x05
170#define SV_DMA_COUNT2 0x06
171#define SV_DMA_MODE 0x0b
172#define SV_DMA_RESET 0x0d
173#define SV_DMA_MASK 0x0f
174
175/*
176 * Record sources
177 */
178
179#define SV_RECSRC_RESERVED (0x00<<5)
180#define SV_RECSRC_CD (0x01<<5)
181#define SV_RECSRC_DAC (0x02<<5)
182#define SV_RECSRC_AUX2 (0x03<<5)
183#define SV_RECSRC_LINE (0x04<<5)
184#define SV_RECSRC_AUX1 (0x05<<5)
185#define SV_RECSRC_MIC (0x06<<5)
186#define SV_RECSRC_OUT (0x07<<5)
187
188/*
189 * constants
190 */
191
192#define SV_FULLRATE 48000
193#define SV_REFFREQUENCY 24576000
194#define SV_ADCMULT 512
195
196#define SV_MODE_PLAY 1
197#define SV_MODE_CAPTURE 2
198
199/*
200
201 */
202
203typedef struct _snd_sonicvibes sonicvibes_t;
204#define chip_t sonicvibes_t
205
206struct _snd_sonicvibes {
207 unsigned long dma1size;
208 unsigned long dma2size;
209 int irq;
210
211 unsigned long sb_port;
212 struct resource *res_sb_port;
213 unsigned long enh_port;
214 struct resource *res_enh_port;
215 unsigned long synth_port;
216 struct resource *res_synth_port;
217 unsigned long midi_port;
218 struct resource *res_midi_port;
219 unsigned long game_port;
220 unsigned int dmaa_port;
221 struct resource *res_dmaa;
222 unsigned int dmac_port;
223 struct resource *res_dmac;
224
225 unsigned char enable;
226 unsigned char irqmask;
227 unsigned char revision;
228 unsigned char format;
229 unsigned char srs_space;
230 unsigned char srs_center;
231 unsigned char mpu_switch;
232 unsigned char wave_source;
233
234 unsigned int mode;
235
236 struct pci_dev *pci;
237 snd_card_t *card;
238 snd_pcm_t *pcm;
239 snd_pcm_substream_t *playback_substream;
240 snd_pcm_substream_t *capture_substream;
241 snd_rawmidi_t *rmidi;
242 snd_hwdep_t *fmsynth; /* S3FM */
243
244 spinlock_t reg_lock;
245 snd_info_entry_t *proc_entry;
246
247 unsigned int p_dma_size;
248 unsigned int c_dma_size;
249
250 snd_kcontrol_t *master_mute;
251 snd_kcontrol_t *master_volume;
252};
253
254static struct pci_device_id snd_sonic_ids[] __devinitdata = {
255 { 0x5333, 0xca00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
256 { 0, }
257};
258
259MODULE_DEVICE_TABLE(pci, snd_sonic_ids);
260
261#ifdef TARGET_OS2
262static ratden_t sonicvibes_adc_clock = {
263 4000 * 65536,
264 48000UL * 65536,
265 1,
266 65536,
267};
268static snd_pcm_hw_constraint_ratdens_t snd_sonicvibes_hw_constraints_adc_clock = {
269 1,
270 &sonicvibes_adc_clock,
271};
272#else
273static ratden_t sonicvibes_adc_clock = {
274 num_min: 4000 * 65536,
275 num_max: 48000UL * 65536,
276 num_step: 1,
277 den: 65536,
278};
279static snd_pcm_hw_constraint_ratdens_t snd_sonicvibes_hw_constraints_adc_clock = {
280 nrats: 1,
281 rats: &sonicvibes_adc_clock,
282};
283#endif
284
285/*
286 * common I/O routines
287 */
288
289static inline void snd_sonicvibes_setdmaa(sonicvibes_t * sonic,
290 unsigned int addr,
291 unsigned int count)
292{
293 count--;
294 outl(addr, sonic->dmaa_port + SV_DMA_ADDR0);
295 outl(count, sonic->dmaa_port + SV_DMA_COUNT0);
296 outb(0x18, sonic->dmaa_port + SV_DMA_MODE);
297#if 0
298 printk("program dmaa: addr = 0x%x, paddr = 0x%x\n", addr, inl(sonic->dmaa_port + SV_DMA_ADDR0));
299#endif
300}
301
302static inline void snd_sonicvibes_setdmac(sonicvibes_t * sonic,
303 unsigned int addr,
304 unsigned int count)
305{
306 /* note: dmac is working in word mode!!! */
307 count >>= 1;
308 count--;
309 outl(addr, sonic->dmac_port + SV_DMA_ADDR0);
310 outl(count, sonic->dmac_port + SV_DMA_COUNT0);
311 outb(0x14, sonic->dmac_port + SV_DMA_MODE);
312#if 0
313 printk("program dmac: addr = 0x%x, paddr = 0x%x\n", addr, inl(sonic->dmac_port + SV_DMA_ADDR0));
314#endif
315}
316
317static inline unsigned int snd_sonicvibes_getdmaa(sonicvibes_t * sonic)
318{
319 return (inl(sonic->dmaa_port + SV_DMA_COUNT0) & 0xffffff) + 1;
320}
321
322static inline unsigned int snd_sonicvibes_getdmac(sonicvibes_t * sonic)
323{
324 /* note: dmac is working in word mode!!! */
325 return ((inl(sonic->dmac_port + SV_DMA_COUNT0) & 0xffffff) + 1) << 1;
326}
327
328static void snd_sonicvibes_out1(sonicvibes_t * sonic,
329 unsigned char reg,
330 unsigned char value)
331{
332 outb(reg, SV_REG(sonic, INDEX));
333 udelay(10);
334 outb(value, SV_REG(sonic, DATA));
335 udelay(10);
336}
337
338static void snd_sonicvibes_out(sonicvibes_t * sonic,
339 unsigned char reg,
340 unsigned char value)
341{
342 unsigned long flags;
343
344 spin_lock_irqsave(&sonic->reg_lock, flags);
345 outb(reg, SV_REG(sonic, INDEX));
346 udelay(10);
347 outb(value, SV_REG(sonic, DATA));
348 udelay(10);
349 spin_unlock_irqrestore(&sonic->reg_lock, flags);
350}
351
352static unsigned char snd_sonicvibes_in1(sonicvibes_t * sonic, unsigned char reg)
353{
354 unsigned char value;
355
356 outb(reg, SV_REG(sonic, INDEX));
357 udelay(10);
358 value = inb(SV_REG(sonic, DATA));
359 udelay(10);
360 return value;
361}
362
363static unsigned char snd_sonicvibes_in(sonicvibes_t * sonic, unsigned char reg)
364{
365 unsigned long flags;
366 unsigned char value;
367
368 spin_lock_irqsave(&sonic->reg_lock, flags);
369 outb(reg, SV_REG(sonic, INDEX));
370 udelay(10);
371 value = inb(SV_REG(sonic, DATA));
372 udelay(10);
373 spin_unlock_irqrestore(&sonic->reg_lock, flags);
374 return value;
375}
376
377#ifdef CONFIG_SND_DEBUG
378void snd_sonicvibes_debug(sonicvibes_t * sonic)
379{
380 printk("SV REGS: INDEX = 0x%02x ", inb(SV_REG(sonic, INDEX)));
381 printk(" STATUS = 0x%02x\n", inb(SV_REG(sonic, STATUS)));
382 printk(" 0x00: left input = 0x%02x ", snd_sonicvibes_in(sonic, 0x00));
383 printk(" 0x20: synth rate low = 0x%02x\n", snd_sonicvibes_in(sonic, 0x20));
384 printk(" 0x01: right input = 0x%02x ", snd_sonicvibes_in(sonic, 0x01));
385 printk(" 0x21: synth rate high = 0x%02x\n", snd_sonicvibes_in(sonic, 0x21));
386 printk(" 0x02: left AUX1 = 0x%02x ", snd_sonicvibes_in(sonic, 0x02));
387 printk(" 0x22: ADC clock = 0x%02x\n", snd_sonicvibes_in(sonic, 0x22));
388 printk(" 0x03: right AUX1 = 0x%02x ", snd_sonicvibes_in(sonic, 0x03));
389 printk(" 0x23: ADC alt rate = 0x%02x\n", snd_sonicvibes_in(sonic, 0x23));
390 printk(" 0x04: left CD = 0x%02x ", snd_sonicvibes_in(sonic, 0x04));
391 printk(" 0x24: ADC pll M = 0x%02x\n", snd_sonicvibes_in(sonic, 0x24));
392 printk(" 0x05: right CD = 0x%02x ", snd_sonicvibes_in(sonic, 0x05));
393 printk(" 0x25: ADC pll N = 0x%02x\n", snd_sonicvibes_in(sonic, 0x25));
394 printk(" 0x06: left line = 0x%02x ", snd_sonicvibes_in(sonic, 0x06));
395 printk(" 0x26: Synth pll M = 0x%02x\n", snd_sonicvibes_in(sonic, 0x26));
396 printk(" 0x07: right line = 0x%02x ", snd_sonicvibes_in(sonic, 0x07));
397 printk(" 0x27: Synth pll N = 0x%02x\n", snd_sonicvibes_in(sonic, 0x27));
398 printk(" 0x08: MIC = 0x%02x ", snd_sonicvibes_in(sonic, 0x08));
399 printk(" 0x28: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x28));
400 printk(" 0x09: Game port = 0x%02x ", snd_sonicvibes_in(sonic, 0x09));
401 printk(" 0x29: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x29));
402 printk(" 0x0a: left synth = 0x%02x ", snd_sonicvibes_in(sonic, 0x0a));
403 printk(" 0x2a: MPU401 = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2a));
404 printk(" 0x0b: right synth = 0x%02x ", snd_sonicvibes_in(sonic, 0x0b));
405 printk(" 0x2b: drive ctrl = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2b));
406 printk(" 0x0c: left AUX2 = 0x%02x ", snd_sonicvibes_in(sonic, 0x0c));
407 printk(" 0x2c: SRS space = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2c));
408 printk(" 0x0d: right AUX2 = 0x%02x ", snd_sonicvibes_in(sonic, 0x0d));
409 printk(" 0x2d: SRS center = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2d));
410 printk(" 0x0e: left analog = 0x%02x ", snd_sonicvibes_in(sonic, 0x0e));
411 printk(" 0x2e: wave source = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2e));
412 printk(" 0x0f: right analog = 0x%02x ", snd_sonicvibes_in(sonic, 0x0f));
413 printk(" 0x2f: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2f));
414 printk(" 0x10: left PCM = 0x%02x ", snd_sonicvibes_in(sonic, 0x10));
415 printk(" 0x30: analog power = 0x%02x\n", snd_sonicvibes_in(sonic, 0x30));
416 printk(" 0x11: right PCM = 0x%02x ", snd_sonicvibes_in(sonic, 0x11));
417 printk(" 0x31: analog power = 0x%02x\n", snd_sonicvibes_in(sonic, 0x31));
418 printk(" 0x12: DMA data format = 0x%02x ", snd_sonicvibes_in(sonic, 0x12));
419 printk(" 0x32: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x32));
420 printk(" 0x13: P/C enable = 0x%02x ", snd_sonicvibes_in(sonic, 0x13));
421 printk(" 0x33: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x33));
422 printk(" 0x14: U/D button = 0x%02x ", snd_sonicvibes_in(sonic, 0x14));
423 printk(" 0x34: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x34));
424 printk(" 0x15: revision = 0x%02x ", snd_sonicvibes_in(sonic, 0x15));
425 printk(" 0x35: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x35));
426 printk(" 0x16: ADC output ctrl = 0x%02x ", snd_sonicvibes_in(sonic, 0x16));
427 printk(" 0x36: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x36));
428 printk(" 0x17: --- = 0x%02x ", snd_sonicvibes_in(sonic, 0x17));
429 printk(" 0x37: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x37));
430 printk(" 0x18: DMA A upper cnt = 0x%02x ", snd_sonicvibes_in(sonic, 0x18));
431 printk(" 0x38: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x38));
432 printk(" 0x19: DMA A lower cnt = 0x%02x ", snd_sonicvibes_in(sonic, 0x19));
433 printk(" 0x39: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x39));
434 printk(" 0x1a: --- = 0x%02x ", snd_sonicvibes_in(sonic, 0x1a));
435 printk(" 0x3a: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3a));
436 printk(" 0x1b: --- = 0x%02x ", snd_sonicvibes_in(sonic, 0x1b));
437 printk(" 0x3b: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3b));
438 printk(" 0x1c: DMA C upper cnt = 0x%02x ", snd_sonicvibes_in(sonic, 0x1c));
439 printk(" 0x3c: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3c));
440 printk(" 0x1d: DMA C upper cnt = 0x%02x ", snd_sonicvibes_in(sonic, 0x1d));
441 printk(" 0x3d: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3d));
442 printk(" 0x1e: PCM rate low = 0x%02x ", snd_sonicvibes_in(sonic, 0x1e));
443 printk(" 0x3e: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3e));
444 printk(" 0x1f: PCM rate high = 0x%02x ", snd_sonicvibes_in(sonic, 0x1f));
445 printk(" 0x3f: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3f));
446}
447
448#endif
449
450static void snd_sonicvibes_setfmt(sonicvibes_t * sonic,
451 unsigned char mask,
452 unsigned char value)
453{
454 unsigned long flags;
455
456 spin_lock_irqsave(&sonic->reg_lock, flags);
457 outb(SV_MCE | SV_IREG_DMA_DATA_FMT, SV_REG(sonic, INDEX));
458 if (mask) {
459 sonic->format = inb(SV_REG(sonic, DATA));
460 udelay(10);
461 }
462 sonic->format = (sonic->format & mask) | value;
463 outb(sonic->format, SV_REG(sonic, DATA));
464 udelay(10);
465 outb(0, SV_REG(sonic, INDEX));
466 udelay(10);
467 spin_unlock_irqrestore(&sonic->reg_lock, flags);
468}
469
470static void snd_sonicvibes_pll(unsigned int rate,
471 unsigned int *res_r,
472 unsigned int *res_m,
473 unsigned int *res_n)
474{
475 unsigned int r, m = 0, n = 0;
476 unsigned int xm, xn, xr, xd, metric = ~0U;
477
478 if (rate < 625000 / SV_ADCMULT)
479 rate = 625000 / SV_ADCMULT;
480 if (rate > 150000000 / SV_ADCMULT)
481 rate = 150000000 / SV_ADCMULT;
482 /* slight violation of specs, needed for continuous sampling rates */
483 for (r = 0; rate < 75000000 / SV_ADCMULT; r += 0x20, rate <<= 1);
484 for (xn = 3; xn < 33; xn++) /* 35 */
485 for (xm = 3; xm < 257; xm++) {
486 xr = ((SV_REFFREQUENCY / SV_ADCMULT) * xm) / xn;
487 if (xr >= rate)
488 xd = xr - rate;
489 else
490 xd = rate - xr;
491 if (xd < metric) {
492 metric = xd;
493 m = xm - 2;
494 n = xn - 2;
495 }
496 }
497 *res_r = r;
498 *res_m = m;
499 *res_n = n;
500#if 0
501 printk("metric = %i, xm = %i, xn = %i\n", metric, xm, xn);
502 printk("pll: m = 0x%x, r = 0x%x, n = 0x%x\n", reg, m, r, n);
503#endif
504}
505
506static void snd_sonicvibes_setpll(sonicvibes_t * sonic,
507 unsigned char reg,
508 unsigned int rate)
509{
510 unsigned long flags;
511 unsigned int r, m, n;
512
513 snd_sonicvibes_pll(rate, &r, &m, &n);
514 if (sonic != NULL) {
515 spin_lock_irqsave(&sonic->reg_lock, flags);
516 snd_sonicvibes_out1(sonic, reg, m);
517 snd_sonicvibes_out1(sonic, reg + 1, r | n);
518 spin_unlock_irqrestore(&sonic->reg_lock, flags);
519 }
520}
521
522static void snd_sonicvibes_set_adc_rate(sonicvibes_t * sonic, unsigned int rate)
523{
524 unsigned long flags;
525 unsigned int div;
526 unsigned char clock;
527
528 div = 48000 / rate;
529 if (div > 8)
530 div = 8;
531 if ((48000 / div) == rate) { /* use the alternate clock */
532 clock = 0x10;
533 } else { /* use the PLL source */
534 clock = 0x00;
535 snd_sonicvibes_setpll(sonic, SV_IREG_ADC_PLL, rate);
536 }
537 spin_lock_irqsave(&sonic->reg_lock, flags);
538 snd_sonicvibes_out1(sonic, SV_IREG_ADC_ALT_RATE, (div - 1) << 4);
539 snd_sonicvibes_out1(sonic, SV_IREG_ADC_CLOCK, clock);
540 spin_unlock_irqrestore(&sonic->reg_lock, flags);
541}
542
543static int snd_sonicvibes_hw_constraint_dac_rate(snd_pcm_hw_params_t *params,
544 snd_pcm_hw_rule_t *rule)
545{
546 unsigned int rate, div, r, m, n;
547
548 if (hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min ==
549 hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->max) {
550 rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE)->min;
551 div = 48000 / rate;
552 if (div > 8)
553 div = 8;
554 if ((48000 / div) == rate) {
555 params->rate_num = rate;
556 params->rate_den = 1;
557 } else {
558 snd_sonicvibes_pll(rate, &r, &m, &n);
559 snd_assert((SV_REFFREQUENCY % 16) == 0, return -EINVAL);
560 snd_assert((SV_ADCMULT % 512) == 0, return -EINVAL);
561 params->rate_num = (SV_REFFREQUENCY/16) * (n+2) * r;
562 params->rate_den = (SV_ADCMULT/512) * (m+2);
563 }
564 }
565 return 0;
566}
567
568static void snd_sonicvibes_set_dac_rate(sonicvibes_t * sonic, unsigned int rate)
569{
570 unsigned int div;
571 unsigned long flags;
572
573 div = (rate * 65536 + SV_FULLRATE / 2) / SV_FULLRATE;
574 if (div > 65535)
575 div = 65535;
576 spin_lock_irqsave(&sonic->reg_lock, flags);
577 snd_sonicvibes_out1(sonic, SV_IREG_PCM_RATE_HIGH, div >> 8);
578 snd_sonicvibes_out1(sonic, SV_IREG_PCM_RATE_LOW, div);
579 spin_unlock_irqrestore(&sonic->reg_lock, flags);
580}
581
582static int snd_sonicvibes_trigger(sonicvibes_t * sonic, int what, int cmd)
583{
584 int result = 0;
585
586 spin_lock(&sonic->reg_lock);
587 if (cmd == SNDRV_PCM_TRIGGER_START) {
588 if (!(sonic->enable & what)) {
589 sonic->enable |= what;
590 snd_sonicvibes_out1(sonic, SV_IREG_PC_ENABLE, sonic->enable);
591 }
592 } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
593 if (sonic->enable & what) {
594 sonic->enable &= ~what;
595 snd_sonicvibes_out1(sonic, SV_IREG_PC_ENABLE, sonic->enable);
596 }
597 } else {
598 result = -EINVAL;
599 }
600 spin_unlock(&sonic->reg_lock);
601 return result;
602}
603
604static void snd_sonicvibes_interrupt(int irq, void *dev_id, struct pt_regs *regs)
605{
606 sonicvibes_t *sonic = snd_magic_cast(sonicvibes_t, dev_id, return);
607 unsigned char status;
608
609 status = inb(SV_REG(sonic, STATUS));
610 if (!(status & (SV_DMAA_IRQ | SV_DMAC_IRQ | SV_MIDI_IRQ)))
611 return;
612 if (status == 0xff) { /* failure */
613 outb(sonic->irqmask = ~0, SV_REG(sonic, IRQMASK));
614 snd_printk("IRQ failure - interrupts disabled!!\n");
615 return;
616 }
617 if (sonic->pcm) {
618 if (status & SV_DMAA_IRQ)
619 snd_pcm_period_elapsed(sonic->playback_substream);
620 if (status & SV_DMAC_IRQ)
621 snd_pcm_period_elapsed(sonic->capture_substream);
622 }
623 if (sonic->rmidi) {
624 if (status & SV_MIDI_IRQ)
625 snd_mpu401_uart_interrupt(irq, sonic->rmidi->private_data, regs);
626 }
627 if (status & SV_UD_IRQ) {
628 unsigned char udreg;
629 int vol, oleft, oright, mleft, mright;
630
631 spin_lock(&sonic->reg_lock);
632 udreg = snd_sonicvibes_in1(sonic, SV_IREG_UD_BUTTON);
633 vol = udreg & 0x3f;
634 if (!(udreg & 0x40))
635 vol = -vol;
636 oleft = mleft = snd_sonicvibes_in1(sonic, SV_IREG_LEFT_ANALOG);
637 oright = mright = snd_sonicvibes_in1(sonic, SV_IREG_RIGHT_ANALOG);
638 oleft &= 0x1f;
639 oright &= 0x1f;
640 oleft += vol;
641 if (oleft < 0)
642 oleft = 0;
643 if (oleft > 0x1f)
644 oleft = 0x1f;
645 oright += vol;
646 if (oright < 0)
647 oright = 0;
648 if (oright > 0x1f)
649 oright = 0x1f;
650 if (udreg & 0x80) {
651 mleft ^= 0x80;
652 mright ^= 0x80;
653 }
654 oleft |= mleft & 0x80;
655 oright |= mright & 0x80;
656 snd_sonicvibes_out1(sonic, SV_IREG_LEFT_ANALOG, oleft);
657 snd_sonicvibes_out1(sonic, SV_IREG_RIGHT_ANALOG, oright);
658 spin_unlock(&sonic->reg_lock);
659 snd_ctl_notify(sonic->card, SNDRV_CTL_EVENT_MASK_VALUE, &sonic->master_mute->id);
660 snd_ctl_notify(sonic->card, SNDRV_CTL_EVENT_MASK_VALUE, &sonic->master_volume->id);
661 }
662}
663
664/*
665 * PCM part
666 */
667
668static int snd_sonicvibes_playback_trigger(snd_pcm_substream_t * substream,
669 int cmd)
670{
671 sonicvibes_t *sonic = snd_pcm_substream_chip(substream);
672 return snd_sonicvibes_trigger(sonic, 1, cmd);
673}
674
675static int snd_sonicvibes_capture_trigger(snd_pcm_substream_t * substream,
676 int cmd)
677{
678 sonicvibes_t *sonic = snd_pcm_substream_chip(substream);
679 return snd_sonicvibes_trigger(sonic, 2, cmd);
680}
681
682static int snd_sonicvibes_hw_params(snd_pcm_substream_t * substream,
683 snd_pcm_hw_params_t * hw_params)
684{
685 return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
686}
687
688static int snd_sonicvibes_hw_free(snd_pcm_substream_t * substream)
689{
690 return snd_pcm_lib_free_pages(substream);
691}
692
693static int snd_sonicvibes_playback_prepare(snd_pcm_substream_t * substream)
694{
695 unsigned long flags;
696 sonicvibes_t *sonic = snd_pcm_substream_chip(substream);
697 snd_pcm_runtime_t *runtime = substream->runtime;
698 unsigned char fmt = 0;
699 unsigned int size = snd_pcm_lib_buffer_bytes(substream);
700 unsigned int count = snd_pcm_lib_period_bytes(substream);
701
702 sonic->p_dma_size = size;
703 count--;
704 if (runtime->channels > 1)
705 fmt |= 1;
706 if (snd_pcm_format_width(runtime->format) == 16)
707 fmt |= 2;
708 snd_sonicvibes_setfmt(sonic, ~3, fmt);
709 snd_sonicvibes_set_dac_rate(sonic, runtime->rate);
710 spin_lock_irqsave(&sonic->reg_lock, flags);
711 snd_sonicvibes_setdmaa(sonic, runtime->dma_addr, size);
712 snd_sonicvibes_out1(sonic, SV_IREG_DMA_A_UPPER, count >> 8);
713 snd_sonicvibes_out1(sonic, SV_IREG_DMA_A_LOWER, count);
714 spin_unlock_irqrestore(&sonic->reg_lock, flags);
715 return 0;
716}
717
718static int snd_sonicvibes_capture_prepare(snd_pcm_substream_t * substream)
719{
720 unsigned long flags;
721 sonicvibes_t *sonic = snd_pcm_substream_chip(substream);
722 snd_pcm_runtime_t *runtime = substream->runtime;
723 unsigned char fmt = 0;
724 unsigned int size = snd_pcm_lib_buffer_bytes(substream);
725 unsigned int count = snd_pcm_lib_period_bytes(substream);
726
727 sonic->c_dma_size = size;
728 count >>= 1;
729 count--;
730 if (runtime->channels > 1)
731 fmt |= 0x10;
732 if (snd_pcm_format_width(runtime->format) == 16)
733 fmt |= 0x20;
734 snd_sonicvibes_setfmt(sonic, ~0x30, fmt);
735 snd_sonicvibes_set_adc_rate(sonic, runtime->rate);
736 spin_lock_irqsave(&sonic->reg_lock, flags);
737 snd_sonicvibes_setdmac(sonic, runtime->dma_addr, size);
738 snd_sonicvibes_out1(sonic, SV_IREG_DMA_C_UPPER, count >> 8);
739 snd_sonicvibes_out1(sonic, SV_IREG_DMA_C_LOWER, count);
740 spin_unlock_irqrestore(&sonic->reg_lock, flags);
741 return 0;
742}
743
744static snd_pcm_uframes_t snd_sonicvibes_playback_pointer(snd_pcm_substream_t * substream)
745{
746 sonicvibes_t *sonic = snd_pcm_substream_chip(substream);
747 size_t ptr;
748
749 if (!(sonic->enable & 1))
750 return 0;
751 ptr = sonic->p_dma_size - snd_sonicvibes_getdmaa(sonic);
752 return bytes_to_frames(substream->runtime, ptr);
753}
754
755static snd_pcm_uframes_t snd_sonicvibes_capture_pointer(snd_pcm_substream_t * substream)
756{
757 sonicvibes_t *sonic = snd_pcm_substream_chip(substream);
758 size_t ptr;
759 if (!(sonic->enable & 2))
760 return 0;
761 ptr = sonic->c_dma_size - snd_sonicvibes_getdmac(sonic);
762 return bytes_to_frames(substream->runtime, ptr);
763}
764
765#ifdef TARGET_OS2
766static snd_pcm_hardware_t snd_sonicvibes_playback =
767{
768/* info: */ (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
769 SNDRV_PCM_INFO_BLOCK_TRANSFER |
770 SNDRV_PCM_INFO_MMAP_VALID),
771/* formats: */ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
772/* rates: */ SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
773/* rate_min: */ 4000,
774/* rate_max: */ 48000,
775/* channels_min: */ 1,
776/* channels_max: */ 2,
777/* buffer_bytes_max: */ (128*1024),
778/* period_bytes_min: */ 32,
779/* period_bytes_max: */ (128*1024),
780/* periods_min: */ 1,
781/* periods_max: */ 1024,
782/* fifo_size: */ 0,
783};
784
785static snd_pcm_hardware_t snd_sonicvibes_capture =
786{
787/* info: */ (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
788 SNDRV_PCM_INFO_BLOCK_TRANSFER |
789 SNDRV_PCM_INFO_MMAP_VALID),
790/* formats: */ SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
791/* rates: */ SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
792/* rate_min: */ 4000,
793/* rate_max: */ 48000,
794/* channels_min: */ 1,
795/* channels_max: */ 2,
796/* buffer_bytes_max: */ (128*1024),
797/* period_bytes_min: */ 32,
798/* period_bytes_max: */ (128*1024),
799/* periods_min: */ 1,
800/* periods_max: */ 1024,
801/* fifo_size: */ 0,
802};
803#else
804static snd_pcm_hardware_t snd_sonicvibes_playback =
805{
806 info: (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
807 SNDRV_PCM_INFO_BLOCK_TRANSFER |
808 SNDRV_PCM_INFO_MMAP_VALID),
809 formats: SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
810 rates: SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
811 rate_min: 4000,
812 rate_max: 48000,
813 channels_min: 1,
814 channels_max: 2,
815 buffer_bytes_max: (128*1024),
816 period_bytes_min: 32,
817 period_bytes_max: (128*1024),
818 periods_min: 1,
819 periods_max: 1024,
820 fifo_size: 0,
821};
822
823static snd_pcm_hardware_t snd_sonicvibes_capture =
824{
825 info: (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
826 SNDRV_PCM_INFO_BLOCK_TRANSFER |
827 SNDRV_PCM_INFO_MMAP_VALID),
828 formats: SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
829 rates: SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
830 rate_min: 4000,
831 rate_max: 48000,
832 channels_min: 1,
833 channels_max: 2,
834 buffer_bytes_max: (128*1024),
835 period_bytes_min: 32,
836 period_bytes_max: (128*1024),
837 periods_min: 1,
838 periods_max: 1024,
839 fifo_size: 0,
840};
841#endif
842
843static int snd_sonicvibes_playback_open(snd_pcm_substream_t * substream)
844{
845 sonicvibes_t *sonic = snd_pcm_substream_chip(substream);
846 snd_pcm_runtime_t *runtime = substream->runtime;
847
848 sonic->mode |= SV_MODE_PLAY;
849 sonic->playback_substream = substream;
850 runtime->hw = snd_sonicvibes_playback;
851 snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, snd_sonicvibes_hw_constraint_dac_rate, 0, SNDRV_PCM_HW_PARAM_RATE, -1);
852 return 0;
853}
854
855static int snd_sonicvibes_capture_open(snd_pcm_substream_t * substream)
856{
857 sonicvibes_t *sonic = snd_pcm_substream_chip(substream);
858 snd_pcm_runtime_t *runtime = substream->runtime;
859
860 sonic->mode |= SV_MODE_CAPTURE;
861 sonic->capture_substream = substream;
862 runtime->hw = snd_sonicvibes_capture;
863 snd_pcm_hw_constraint_ratdens(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
864 &snd_sonicvibes_hw_constraints_adc_clock);
865 return 0;
866}
867
868static int snd_sonicvibes_playback_close(snd_pcm_substream_t * substream)
869{
870 sonicvibes_t *sonic = snd_pcm_substream_chip(substream);
871
872 sonic->playback_substream = NULL;
873 sonic->mode &= ~SV_MODE_PLAY;
874 return 0;
875}
876
877static int snd_sonicvibes_capture_close(snd_pcm_substream_t * substream)
878{
879 sonicvibes_t *sonic = snd_pcm_substream_chip(substream);
880
881 sonic->capture_substream = NULL;
882 sonic->mode &= ~SV_MODE_CAPTURE;
883 return 0;
884}
885
886
887#ifdef TARGET_OS2
888static snd_pcm_ops_t snd_sonicvibes_playback_ops = {
889/* open: */ snd_sonicvibes_playback_open,
890/* close: */ snd_sonicvibes_playback_close,
891/* ioctl: */ snd_pcm_lib_ioctl,
892/* hw_params:*/ snd_sonicvibes_hw_params,
893/* hw_free: */ snd_sonicvibes_hw_free,
894/* prepare: */ snd_sonicvibes_playback_prepare,
895/* trigger: */ snd_sonicvibes_playback_trigger,
896/* pointer: */ snd_sonicvibes_playback_pointer,
897 0, 0
898};
899
900static snd_pcm_ops_t snd_sonicvibes_capture_ops = {
901/* open: */ snd_sonicvibes_capture_open,
902/* close: */ snd_sonicvibes_capture_close,
903/* ioctl: */ snd_pcm_lib_ioctl,
904/* hw_params:*/ snd_sonicvibes_hw_params,
905/* hw_free: */ snd_sonicvibes_hw_free,
906/* prepare: */ snd_sonicvibes_capture_prepare,
907/* trigger: */ snd_sonicvibes_capture_trigger,
908/* pointer: */ snd_sonicvibes_capture_pointer,
909 0, 0
910};
911#else
912static snd_pcm_ops_t snd_sonicvibes_playback_ops = {
913 open: snd_sonicvibes_playback_open,
914 close: snd_sonicvibes_playback_close,
915 ioctl: snd_pcm_lib_ioctl,
916 hw_params: snd_sonicvibes_hw_params,
917 hw_free: snd_sonicvibes_hw_free,
918 prepare: snd_sonicvibes_playback_prepare,
919 trigger: snd_sonicvibes_playback_trigger,
920 pointer: snd_sonicvibes_playback_pointer,
921};
922
923static snd_pcm_ops_t snd_sonicvibes_capture_ops = {
924 open: snd_sonicvibes_capture_open,
925 close: snd_sonicvibes_capture_close,
926 ioctl: snd_pcm_lib_ioctl,
927 hw_params: snd_sonicvibes_hw_params,
928 hw_free: snd_sonicvibes_hw_free,
929 prepare: snd_sonicvibes_capture_prepare,
930 trigger: snd_sonicvibes_capture_trigger,
931 pointer: snd_sonicvibes_capture_pointer,
932};
933#endif
934
935static void snd_sonicvibes_pcm_free(snd_pcm_t *pcm)
936{
937 sonicvibes_t *sonic = snd_magic_cast(sonicvibes_t, pcm->private_data, return);
938 sonic->pcm = NULL;
939 snd_pcm_lib_preallocate_free_for_all(pcm);
940}
941
942static int __init snd_sonicvibes_pcm(sonicvibes_t * sonic, int device, snd_pcm_t ** rpcm)
943{
944 snd_pcm_t *pcm;
945 int err;
946
947 if ((err = snd_pcm_new(sonic->card, "s3_86c617", device, 1, 1, &pcm)) < 0)
948 return err;
949 snd_assert(pcm != NULL, return -EINVAL);
950 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sonicvibes_playback_ops);
951 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sonicvibes_capture_ops);
952
953 pcm->private_data = sonic;
954 pcm->private_free = snd_sonicvibes_pcm_free;
955 pcm->info_flags = 0;
956 strcpy(pcm->name, "S3 SonicVibes");
957 sonic->pcm = pcm;
958
959 snd_pcm_lib_preallocate_pci_pages_for_all(sonic->pci, pcm, 64*1024, 128*1024);
960
961 if (rpcm)
962 *rpcm = pcm;
963 return 0;
964}
965
966/*
967 * Mixer part
968 */
969
970#ifdef TARGET_OS2
971#define SONICVIBES_MUX(xname, xindex) \
972{ SNDRV_CTL_ELEM_IFACE_MIXER, 0, 0, xname, xindex, \
973 0, 0,snd_sonicvibes_info_mux, \
974 snd_sonicvibes_get_mux, snd_sonicvibes_put_mux, 0}
975#else
976#define SONICVIBES_MUX(xname, xindex) \
977{ iface: SNDRV_CTL_ELEM_IFACE_MIXER, name: xname, index: xindex, \
978 info: snd_sonicvibes_info_mux, \
979 get: snd_sonicvibes_get_mux, put: snd_sonicvibes_put_mux }
980#endif
981
982static int snd_sonicvibes_info_mux(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
983{
984 static char *texts[7] = {
985 "CD", "PCM", "Aux1", "Line", "Aux0", "Mic", "Mix"
986 };
987
988 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
989 uinfo->count = 2;
990 uinfo->value.enumerated.items = 7;
991 if (uinfo->value.enumerated.item >= 7)
992 uinfo->value.enumerated.item = 6;
993 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
994 return 0;
995}
996
997static int snd_sonicvibes_get_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
998{
999 sonicvibes_t *sonic = snd_kcontrol_chip(kcontrol);
1000 unsigned long flags;
1001
1002 spin_lock_irqsave(&sonic->reg_lock, flags);
1003 ucontrol->value.enumerated.item[0] = ((snd_sonicvibes_in1(sonic, SV_IREG_LEFT_ADC) & SV_RECSRC_OUT) >> 5) - 1;
1004 ucontrol->value.enumerated.item[1] = ((snd_sonicvibes_in1(sonic, SV_IREG_RIGHT_ADC) & SV_RECSRC_OUT) >> 5) - 1;
1005 spin_unlock_irqrestore(&sonic->reg_lock, flags);
1006 return 0;
1007}
1008
1009static int snd_sonicvibes_put_mux(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
1010{
1011 sonicvibes_t *sonic = snd_kcontrol_chip(kcontrol);
1012 unsigned long flags;
1013 unsigned short left, right, oval1, oval2;
1014 int change;
1015
1016 if (ucontrol->value.enumerated.item[0] >= 7 ||
1017 ucontrol->value.enumerated.item[1] >= 7)
1018 return -EINVAL;
1019 left = (ucontrol->value.enumerated.item[0] + 1) << 5;
1020 right = (ucontrol->value.enumerated.item[1] + 1) << 5;
1021 spin_lock_irqsave(&sonic->reg_lock, flags);
1022 oval1 = snd_sonicvibes_in1(sonic, SV_IREG_LEFT_ADC);
1023 oval2 = snd_sonicvibes_in1(sonic, SV_IREG_RIGHT_ADC);
1024 left = (oval1 & ~SV_RECSRC_OUT) | left;
1025 right = (oval2 & ~SV_RECSRC_OUT) | right;
1026 change = left != oval1 || right != oval2;
1027 snd_sonicvibes_out1(sonic, SV_IREG_LEFT_ADC, left);
1028 snd_sonicvibes_out1(sonic, SV_IREG_RIGHT_ADC, right);
1029 spin_unlock_irqrestore(&sonic->reg_lock, flags);
1030 return change;
1031}
1032
1033#ifdef TARGET_OS2
1034#define SONICVIBES_SINGLE(xname, xindex, reg, shift, mask, invert) \
1035{ SNDRV_CTL_ELEM_IFACE_MIXER, 0, 0, xname, xindex, \
1036 0, 0, snd_sonicvibes_info_single, \
1037 snd_sonicvibes_get_single, snd_sonicvibes_put_single, \
1038 reg | (shift << 8) | (mask << 16) | (invert << 24) }
1039#else
1040#define SONICVIBES_SINGLE(xname, xindex, reg, shift, mask, invert) \
1041{ iface: SNDRV_CTL_ELEM_IFACE_MIXER, name: xname, index: xindex, \
1042 info: snd_sonicvibes_info_single, \
1043 get: snd_sonicvibes_get_single, put: snd_sonicvibes_put_single, \
1044 private_value: reg | (shift << 8) | (mask << 16) | (invert << 24) }
1045#endif
1046
1047static int snd_sonicvibes_info_single(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
1048{
1049 int mask = (kcontrol->private_value >> 16) & 0xff;
1050
1051 uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
1052 uinfo->count = 1;
1053 uinfo->value.integer.min = 0;
1054 uinfo->value.integer.max = mask;
1055 return 0;
1056}
1057
1058static int snd_sonicvibes_get_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
1059{
1060 sonicvibes_t *sonic = snd_kcontrol_chip(kcontrol);
1061 unsigned long flags;
1062 int reg = kcontrol->private_value & 0xff;
1063 int shift = (kcontrol->private_value >> 8) & 0xff;
1064 int mask = (kcontrol->private_value >> 16) & 0xff;
1065 int invert = (kcontrol->private_value >> 24) & 0xff;
1066
1067 spin_lock_irqsave(&sonic->reg_lock, flags);
1068 ucontrol->value.integer.value[0] = (snd_sonicvibes_in1(sonic, reg)>> shift) & mask;
1069 spin_unlock_irqrestore(&sonic->reg_lock, flags);
1070 if (invert)
1071 ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
1072 return 0;
1073}
1074
1075static int snd_sonicvibes_put_single(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
1076{
1077 sonicvibes_t *sonic = snd_kcontrol_chip(kcontrol);
1078 unsigned long flags;
1079 int reg = kcontrol->private_value & 0xff;
1080 int shift = (kcontrol->private_value >> 8) & 0xff;
1081 int mask = (kcontrol->private_value >> 16) & 0xff;
1082 int invert = (kcontrol->private_value >> 24) & 0xff;
1083 int change;
1084 unsigned short val, oval;
1085
1086 val = (ucontrol->value.integer.value[0] & mask);
1087 if (invert)
1088 val = mask - val;
1089 val <<= shift;
1090 spin_lock_irqsave(&sonic->reg_lock, flags);
1091 oval = snd_sonicvibes_in1(sonic, reg);
1092 val = (oval & ~(mask << shift)) | val;
1093 change = val != oval;
1094 snd_sonicvibes_out1(sonic, reg, val);
1095 spin_unlock_irqrestore(&sonic->reg_lock, flags);
1096 return change;
1097}
1098
1099#ifdef TARGET_OS2
1100#define SONICVIBES_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
1101{ SNDRV_CTL_ELEM_IFACE_MIXER, 0, 0, xname, xindex, \
1102 0, 0, snd_sonicvibes_info_double, \
1103 snd_sonicvibes_get_double, snd_sonicvibes_put_double, \
1104 left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
1105#else
1106#define SONICVIBES_DOUBLE(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \
1107{ iface: SNDRV_CTL_ELEM_IFACE_MIXER, name: xname, index: xindex, \
1108 info: snd_sonicvibes_info_double, \
1109 get: snd_sonicvibes_get_double, put: snd_sonicvibes_put_double, \
1110 private_value: left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) }
1111#endif
1112
1113static int snd_sonicvibes_info_double(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
1114{
1115 int mask = (kcontrol->private_value >> 24) & 0xff;
1116
1117 uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
1118 uinfo->count = 2;
1119 uinfo->value.integer.min = 0;
1120 uinfo->value.integer.max = mask;
1121 return 0;
1122}
1123
1124static int snd_sonicvibes_get_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
1125{
1126 sonicvibes_t *sonic = snd_kcontrol_chip(kcontrol);
1127 unsigned long flags;
1128 int left_reg = kcontrol->private_value & 0xff;
1129 int right_reg = (kcontrol->private_value >> 8) & 0xff;
1130 int shift_left = (kcontrol->private_value >> 16) & 0x07;
1131 int shift_right = (kcontrol->private_value >> 19) & 0x07;
1132 int mask = (kcontrol->private_value >> 24) & 0xff;
1133 int invert = (kcontrol->private_value >> 22) & 1;
1134
1135 spin_lock_irqsave(&sonic->reg_lock, flags);
1136 ucontrol->value.integer.value[0] = (snd_sonicvibes_in1(sonic, left_reg) >> shift_left) & mask;
1137 ucontrol->value.integer.value[1] = (snd_sonicvibes_in1(sonic, right_reg) >> shift_right) & mask;
1138 spin_unlock_irqrestore(&sonic->reg_lock, flags);
1139 if (invert) {
1140 ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
1141 ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
1142 }
1143 return 0;
1144}
1145
1146static int snd_sonicvibes_put_double(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
1147{
1148 sonicvibes_t *sonic = snd_kcontrol_chip(kcontrol);
1149 unsigned long flags;
1150 int left_reg = kcontrol->private_value & 0xff;
1151 int right_reg = (kcontrol->private_value >> 8) & 0xff;
1152 int shift_left = (kcontrol->private_value >> 16) & 0x07;
1153 int shift_right = (kcontrol->private_value >> 19) & 0x07;
1154 int mask = (kcontrol->private_value >> 24) & 0xff;
1155 int invert = (kcontrol->private_value >> 22) & 1;
1156 int change;
1157 unsigned short val1, val2, oval1, oval2;
1158
1159 val1 = ucontrol->value.integer.value[0] & mask;
1160 val2 = ucontrol->value.integer.value[1] & mask;
1161 if (invert) {
1162 val1 = mask - val1;
1163 val2 = mask - val2;
1164 }
1165 val1 <<= shift_left;
1166 val2 <<= shift_right;
1167 spin_lock_irqsave(&sonic->reg_lock, flags);
1168 oval1 = snd_sonicvibes_in1(sonic, left_reg);
1169 oval2 = snd_sonicvibes_in1(sonic, right_reg);
1170 val1 = (oval1 & ~(mask << shift_left)) | val1;
1171 val2 = (oval2 & ~(mask << shift_right)) | val2;
1172 change = val1 != oval1 || val2 != oval2;
1173 snd_sonicvibes_out1(sonic, left_reg, val1);
1174 snd_sonicvibes_out1(sonic, right_reg, val2);
1175 spin_unlock_irqrestore(&sonic->reg_lock, flags);
1176 return change;
1177}
1178
1179#define SONICVIBES_CONTROLS (sizeof(snd_sonicvibes_controls)/sizeof(snd_kcontrol_new_t))
1180
1181static snd_kcontrol_new_t snd_sonicvibes_controls[] = {
1182SONICVIBES_DOUBLE("Capture Volume", 0, SV_IREG_LEFT_ADC, SV_IREG_RIGHT_ADC, 0, 0, 15, 0),
1183SONICVIBES_DOUBLE("Aux Playback Switch", 0, SV_IREG_LEFT_AUX1, SV_IREG_RIGHT_AUX1, 7, 7, 1, 1),
1184SONICVIBES_DOUBLE("Aux Playback Volume", 0, SV_IREG_LEFT_AUX1, SV_IREG_RIGHT_AUX1, 0, 0, 31, 1),
1185SONICVIBES_DOUBLE("CD Playback Switch", 0, SV_IREG_LEFT_CD, SV_IREG_RIGHT_CD, 7, 7, 1, 1),
1186SONICVIBES_DOUBLE("CD Playback Volume", 0, SV_IREG_LEFT_CD, SV_IREG_RIGHT_CD, 0, 0, 31, 1),
1187SONICVIBES_DOUBLE("Line Playback Switch", 0, SV_IREG_LEFT_LINE, SV_IREG_RIGHT_LINE, 7, 7, 1, 1),
1188SONICVIBES_DOUBLE("Line Playback Volume", 0, SV_IREG_LEFT_LINE, SV_IREG_RIGHT_LINE, 0, 0, 31, 1),
1189SONICVIBES_SINGLE("Mic Playback Switch", 0, SV_IREG_MIC, 7, 1, 1),
1190SONICVIBES_SINGLE("Mic Playback Volume", 0, SV_IREG_MIC, 0, 15, 1),
1191SONICVIBES_SINGLE("Mic Boost", 0, SV_IREG_LEFT_ADC, 4, 1, 0),
1192SONICVIBES_DOUBLE("Synth Playback Switch", 0, SV_IREG_LEFT_SYNTH, SV_IREG_RIGHT_SYNTH, 7, 7, 1, 1),
1193SONICVIBES_DOUBLE("Synth Playback Volume", 0, SV_IREG_LEFT_SYNTH, SV_IREG_RIGHT_SYNTH, 0, 0, 31, 1),
1194SONICVIBES_DOUBLE("Aux Playback Switch", 1, SV_IREG_LEFT_AUX2, SV_IREG_RIGHT_AUX2, 7, 7, 1, 1),
1195SONICVIBES_DOUBLE("Aux Playback Volume", 1, SV_IREG_LEFT_AUX2, SV_IREG_RIGHT_AUX2, 0, 0, 31, 1),
1196SONICVIBES_DOUBLE("Master Playback Switch", 0, SV_IREG_LEFT_ANALOG, SV_IREG_RIGHT_ANALOG, 7, 7, 1, 1),
1197SONICVIBES_DOUBLE("Master Playback Volume", 0, SV_IREG_LEFT_ANALOG, SV_IREG_RIGHT_ANALOG, 0, 0, 31, 1),
1198SONICVIBES_DOUBLE("PCM Playback Switch", 0, SV_IREG_LEFT_PCM, SV_IREG_RIGHT_PCM, 7, 7, 1, 1),
1199SONICVIBES_DOUBLE("PCM Playback Volume", 0, SV_IREG_LEFT_PCM, SV_IREG_RIGHT_PCM, 0, 0, 63, 1),
1200SONICVIBES_SINGLE("Loopback Capture Switch", 0, SV_IREG_ADC_OUTPUT_CTRL, 0, 1, 0),
1201SONICVIBES_SINGLE("Loopback Capture Volume", 0, SV_IREG_ADC_OUTPUT_CTRL, 2, 63, 1),
1202SONICVIBES_MUX("Capture Source", 0)
1203};
1204
1205static void snd_sonicvibes_master_free(snd_kcontrol_t *kcontrol)
1206{
1207 sonicvibes_t *sonic = snd_magic_cast(sonicvibes_t, _snd_kcontrol_chip(kcontrol), return);
1208 sonic->master_mute = NULL;
1209 sonic->master_volume = NULL;
1210}
1211
1212static int __init snd_sonicvibes_mixer(sonicvibes_t * sonic)
1213{
1214 snd_card_t *card;
1215 snd_kcontrol_t *kctl;
1216 int idx, err;
1217
1218 snd_assert(sonic != NULL && sonic->card != NULL, return -EINVAL);
1219 card = sonic->card;
1220 strcpy(card->mixername, "S3 SonicVibes");
1221
1222 for (idx = 0; idx < SONICVIBES_CONTROLS; idx++) {
1223 if ((err = snd_ctl_add(card, kctl = snd_ctl_new1(&snd_sonicvibes_controls[idx], sonic))) < 0)
1224 return err;
1225 switch (idx) {
1226 case 0:
1227 case 1: kctl->private_free = snd_sonicvibes_master_free; break;
1228 }
1229 }
1230 return 0;
1231}
1232
1233/*
1234
1235 */
1236
1237static void snd_sonicvibes_proc_read(snd_info_entry_t *entry,
1238 snd_info_buffer_t * buffer)
1239{
1240 sonicvibes_t *sonic = snd_magic_cast(sonicvibes_t, entry->private_data, return);
1241 unsigned char tmp;
1242
1243 tmp = sonic->srs_space & 0x0f;
1244 snd_iprintf(buffer, "SRS 3D : %s\n",
1245 sonic->srs_space & 0x80 ? "off" : "on");
1246 snd_iprintf(buffer, "SRS Space : %s\n",
1247 tmp == 0x00 ? "100%" :
1248 tmp == 0x01 ? "75%" :
1249 tmp == 0x02 ? "50%" :
1250 tmp == 0x03 ? "25%" : "0%");
1251 tmp = sonic->srs_center & 0x0f;
1252 snd_iprintf(buffer, "SRS Center : %s\n",
1253 tmp == 0x00 ? "100%" :
1254 tmp == 0x01 ? "75%" :
1255 tmp == 0x02 ? "50%" :
1256 tmp == 0x03 ? "25%" : "0%");
1257 tmp = sonic->wave_source & 0x03;
1258 snd_iprintf(buffer, "WaveTable Source : %s\n",
1259 tmp == 0x00 ? "on-board ROM" :
1260 tmp == 0x01 ? "PCI bus" : "on-board ROM + PCI bus");
1261 tmp = sonic->mpu_switch;
1262 snd_iprintf(buffer, "Onboard synth : %s\n", tmp & 0x01 ? "on" : "off");
1263 snd_iprintf(buffer, "Ext. Rx to synth : %s\n", tmp & 0x02 ? "on" : "off");
1264 snd_iprintf(buffer, "MIDI to ext. Tx : %s\n", tmp & 0x04 ? "on" : "off");
1265}
1266
1267static void __init snd_sonicvibes_proc_init(sonicvibes_t * sonic)
1268{
1269 snd_info_entry_t *entry;
1270
1271 if ((entry = snd_info_create_card_entry(sonic->card, "sonicvibes", sonic->card->proc_root)) != NULL) {
1272 entry->content = SNDRV_INFO_CONTENT_TEXT;
1273 entry->private_data = sonic;
1274 entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
1275 entry->c.text.read_size = 256;
1276 entry->c.text.read = snd_sonicvibes_proc_read;
1277 if (snd_info_register(entry) < 0) {
1278 snd_info_free_entry(entry);
1279 entry = NULL;
1280 }
1281 }
1282 sonic->proc_entry = entry;
1283}
1284
1285static void snd_sonicvibes_proc_done(sonicvibes_t * sonic)
1286{
1287 if (sonic->proc_entry) {
1288 snd_info_unregister(sonic->proc_entry);
1289 sonic->proc_entry = NULL;
1290 }
1291}
1292
1293/*
1294
1295 */
1296
1297static snd_kcontrol_new_t snd_sonicvibes_game_control =
1298SONICVIBES_SINGLE("Joystick Speed", 0, SV_IREG_GAME_PORT, 1, 15, 0);
1299
1300static int snd_sonicvibes_free(sonicvibes_t *sonic)
1301{
1302 snd_sonicvibes_proc_done(sonic);
1303 pci_write_config_dword(sonic->pci, 0x40, sonic->dmaa_port);
1304 pci_write_config_dword(sonic->pci, 0x48, sonic->dmac_port);
1305 if (sonic->res_sb_port)
1306 release_resource(sonic->res_sb_port);
1307 if (sonic->res_enh_port)
1308 release_resource(sonic->res_enh_port);
1309 if (sonic->res_synth_port)
1310 release_resource(sonic->res_synth_port);
1311 if (sonic->res_midi_port)
1312 release_resource(sonic->res_midi_port);
1313 if (sonic->res_dmaa)
1314 release_resource(sonic->res_dmaa);
1315 if (sonic->res_dmac)
1316 release_resource(sonic->res_dmac);
1317 if (sonic->irq >= 0)
1318 free_irq(sonic->irq, (void *)sonic);
1319 snd_magic_kfree(sonic);
1320 return 0;
1321}
1322
1323static int snd_sonicvibes_dev_free(snd_device_t *device)
1324{
1325 sonicvibes_t *sonic = snd_magic_cast(sonicvibes_t, device->device_data, return -ENXIO);
1326 return snd_sonicvibes_free(sonic);
1327}
1328
1329static int __init snd_sonicvibes_create(snd_card_t * card,
1330 struct pci_dev *pci,
1331 int reverb,
1332 int mge,
1333 sonicvibes_t ** rsonic)
1334{
1335 sonicvibes_t *sonic;
1336 unsigned int dmaa, dmac;
1337 int err;
1338#ifdef TARGET_OS2
1339 static snd_device_ops_t ops = {
1340 snd_sonicvibes_dev_free,0,0,0
1341 };
1342#else
1343 static snd_device_ops_t ops = {
1344 dev_free: snd_sonicvibes_dev_free,
1345 };
1346#endif
1347
1348 *rsonic = NULL;
1349 /* enable PCI device */
1350 if ((err = pci_enable_device(pci)) < 0)
1351 return err;
1352 /* check, if we can restrict PCI DMA transfers to 24 bits */
1353 if (!pci_dma_supported(pci, 0x00ffffff)) {
1354 snd_printk("architecture does not support 24bit PCI busmaster DMA\n");
1355 return -ENXIO;
1356 }
1357 pci_set_dma_mask(pci, 0x00ffffff);
1358
1359 sonic = snd_magic_kcalloc(sonicvibes_t, 0, GFP_KERNEL);
1360 if (sonic == NULL)
1361 return -ENOMEM;
1362 spin_lock_init(&sonic->reg_lock);
1363 sonic->card = card;
1364 sonic->pci = pci;
1365 sonic->irq = -1;
1366 sonic->sb_port = pci_resource_start(pci, 0);
1367 if ((sonic->res_sb_port = request_region(sonic->sb_port, 0x10, "S3 SonicVibes SB")) == NULL) {
1368 snd_sonicvibes_free(sonic);
1369 snd_printk("unable to grab SB port at 0x%lx-0x%lx\n", sonic->sb_port, sonic->sb_port + 0x10 - 1);
1370 return -EBUSY;
1371 }
1372 sonic->enh_port = pci_resource_start(pci, 1);
1373 if ((sonic->res_enh_port = request_region(sonic->enh_port, 0x10, "S3 SonicVibes Enhanced")) == NULL) {
1374 snd_sonicvibes_free(sonic);
1375 snd_printk("unable to grab PCM port at 0x%lx-0x%lx\n", sonic->enh_port, sonic->enh_port + 0x10 - 1);
1376 return -EBUSY;
1377 }
1378 sonic->synth_port = pci_resource_start(pci, 2);
1379 if ((sonic->res_synth_port = request_region(sonic->synth_port, 4, "S3 SonicVibes Synth")) == NULL) {
1380 snd_sonicvibes_free(sonic);
1381 snd_printk("unable to grab synth port at 0x%lx-0x%lx\n", sonic->synth_port, sonic->synth_port + 4 - 1);
1382 return -EBUSY;
1383 }
1384 sonic->midi_port = pci_resource_start(pci, 3);
1385 if ((sonic->res_midi_port = request_region(sonic->midi_port, 4, "S3 SonicVibes Midi")) == NULL) {
1386 snd_sonicvibes_free(sonic);
1387 snd_printk("unable to grab MIDI port at 0x%lx-0x%lx\n", sonic->midi_port, sonic->midi_port + 4 - 1);
1388 return -EBUSY;
1389 }
1390 sonic->game_port = pci_resource_start(pci, 4);
1391 if (request_irq(pci->irq, snd_sonicvibes_interrupt, SA_INTERRUPT|SA_SHIRQ, "S3 SonicVibes", (void *)sonic)) {
1392 snd_magic_kfree(sonic);
1393 snd_printk("unable to grab IRQ %d\n", pci->irq);
1394 return -EBUSY;
1395 }
1396 sonic->irq = pci->irq;
1397
1398 pci_read_config_dword(pci, 0x40, &dmaa);
1399 pci_read_config_dword(pci, 0x48, &dmac);
1400 snd_dmaio &= ~0x0f;
1401 dmaa &= ~0x0f;
1402 dmac &= ~0x0f;
1403 if (!dmaa) {
1404 dmaa = snd_dmaio;
1405 snd_dmaio += 0x10;
1406 snd_printk("BIOS did not allocate DDMA channel A i/o, allocated at 0x%x\n", dmaa);
1407 }
1408 if (!dmac) {
1409 dmac = snd_dmaio;
1410 snd_dmaio += 0x10;
1411 snd_printk("BIOS did not allocate DDMA channel C i/o, allocated at 0x%x\n", dmac);
1412 }
1413 pci_write_config_dword(pci, 0x40, dmaa);
1414 pci_write_config_dword(pci, 0x48, dmac);
1415
1416 if ((sonic->res_dmaa = request_region(dmaa, 0x10, "S3 SonicVibes DDMA-A")) == NULL) {
1417 snd_sonicvibes_free(sonic);
1418 snd_printk("unable to grab DDMA-A port at 0x%x-0x%x\n", dmaa, dmaa + 0x10 - 1);
1419 return -EBUSY;
1420 }
1421 if ((sonic->res_dmac = request_region(dmac, 0x10, "S3 SonicVibes DDMA-C")) == NULL) {
1422 snd_sonicvibes_free(sonic);
1423 snd_printk("unable to grab DDMA-C port at 0x%x-0x%x\n", dmac, dmac + 0x10 - 1);
1424 return -EBUSY;
1425 }
1426
1427 pci_read_config_dword(pci, 0x40, &sonic->dmaa_port);
1428 pci_read_config_dword(pci, 0x48, &sonic->dmac_port);
1429 sonic->dmaa_port &= ~0x0f;
1430 sonic->dmac_port &= ~0x0f;
1431 pci_write_config_dword(pci, 0x40, sonic->dmaa_port | 9); /* enable + enhanced */
1432 pci_write_config_dword(pci, 0x48, sonic->dmac_port | 9); /* enable */
1433 /* ok.. initialize S3 SonicVibes chip */
1434 outb(SV_RESET, SV_REG(sonic, CONTROL)); /* reset chip */
1435 udelay(100);
1436 outb(0, SV_REG(sonic, CONTROL)); /* release reset */
1437 udelay(100);
1438 outb(SV_ENHANCED | SV_INTA | (reverb ? SV_REVERB : 0), SV_REG(sonic, CONTROL));
1439 inb(SV_REG(sonic, STATUS)); /* clear IRQs */
1440#if 1
1441 snd_sonicvibes_out(sonic, SV_IREG_DRIVE_CTRL, 0); /* drive current 16mA */
1442#else
1443 snd_sonicvibes_out(sonic, SV_IREG_DRIVE_CTRL, 0x40); /* drive current 8mA */
1444#endif
1445 snd_sonicvibes_out(sonic, SV_IREG_PC_ENABLE, sonic->enable = 0); /* disable playback & capture */
1446 outb(sonic->irqmask = ~(SV_DMAA_MASK | SV_DMAC_MASK | SV_UD_MASK), SV_REG(sonic, IRQMASK));
1447 inb(SV_REG(sonic, STATUS)); /* clear IRQs */
1448 snd_sonicvibes_out(sonic, SV_IREG_ADC_CLOCK, 0); /* use PLL as clock source */
1449 snd_sonicvibes_out(sonic, SV_IREG_ANALOG_POWER, 0); /* power up analog parts */
1450 snd_sonicvibes_out(sonic, SV_IREG_DIGITAL_POWER, 0); /* power up digital parts */
1451 snd_sonicvibes_setpll(sonic, SV_IREG_ADC_PLL, 8000);
1452 snd_sonicvibes_out(sonic, SV_IREG_SRS_SPACE, sonic->srs_space = 0x80); /* SRS space off */
1453 snd_sonicvibes_out(sonic, SV_IREG_SRS_CENTER, sonic->srs_center = 0x00);/* SRS center off */
1454 snd_sonicvibes_out(sonic, SV_IREG_MPU401, sonic->mpu_switch = 0x05); /* MPU-401 switch */
1455 snd_sonicvibes_out(sonic, SV_IREG_WAVE_SOURCE, sonic->wave_source = 0x00); /* onboard ROM */
1456 snd_sonicvibes_out(sonic, SV_IREG_PCM_RATE_LOW, (8000 * 65536 / SV_FULLRATE) & 0xff);
1457 snd_sonicvibes_out(sonic, SV_IREG_PCM_RATE_HIGH, ((8000 * 65536 / SV_FULLRATE) >> 8) & 0xff);
1458 snd_sonicvibes_out(sonic, SV_IREG_LEFT_ADC, mge ? 0xd0 : 0xc0);
1459 snd_sonicvibes_out(sonic, SV_IREG_RIGHT_ADC, 0xc0);
1460 snd_sonicvibes_out(sonic, SV_IREG_LEFT_AUX1, 0x9f);
1461 snd_sonicvibes_out(sonic, SV_IREG_RIGHT_AUX1, 0x9f);
1462 snd_sonicvibes_out(sonic, SV_IREG_LEFT_CD, 0x9f);
1463 snd_sonicvibes_out(sonic, SV_IREG_RIGHT_CD, 0x9f);
1464 snd_sonicvibes_out(sonic, SV_IREG_LEFT_LINE, 0x9f);
1465 snd_sonicvibes_out(sonic, SV_IREG_RIGHT_LINE, 0x9f);
1466 snd_sonicvibes_out(sonic, SV_IREG_MIC, 0x8f);
1467 snd_sonicvibes_out(sonic, SV_IREG_LEFT_SYNTH, 0x9f);
1468 snd_sonicvibes_out(sonic, SV_IREG_RIGHT_SYNTH, 0x9f);
1469 snd_sonicvibes_out(sonic, SV_IREG_LEFT_AUX2, 0x9f);
1470 snd_sonicvibes_out(sonic, SV_IREG_RIGHT_AUX2, 0x9f);
1471 snd_sonicvibes_out(sonic, SV_IREG_LEFT_ANALOG, 0x9f);
1472 snd_sonicvibes_out(sonic, SV_IREG_RIGHT_ANALOG, 0x9f);
1473 snd_sonicvibes_out(sonic, SV_IREG_LEFT_PCM, 0xbf);
1474 snd_sonicvibes_out(sonic, SV_IREG_RIGHT_PCM, 0xbf);
1475 snd_sonicvibes_out(sonic, SV_IREG_ADC_OUTPUT_CTRL, 0xfc);
1476#if 0
1477 snd_sonicvibes_debug(sonic);
1478#endif
1479 sonic->revision = snd_sonicvibes_in(sonic, SV_IREG_REVISION);
1480 snd_ctl_add(card, snd_ctl_new1(&snd_sonicvibes_game_control, sonic));
1481 snd_sonicvibes_proc_init(sonic);
1482
1483 if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, sonic, &ops)) < 0) {
1484 snd_sonicvibes_free(sonic);
1485 return err;
1486 }
1487
1488 *rsonic = sonic;
1489 return 0;
1490}
1491
1492/*
1493 * MIDI section
1494 */
1495
1496#define SONICVIBES_MIDI_CONTROLS (sizeof(snd_sonicvibes_midi_controls)/sizeof(snd_kcontrol_new_t))
1497
1498static snd_kcontrol_new_t snd_sonicvibes_midi_controls[] = {
1499SONICVIBES_SINGLE("SonicVibes Wave Source RAM", 0, SV_IREG_WAVE_SOURCE, 0, 1, 0),
1500SONICVIBES_SINGLE("SonicVibes Wave Source RAM+ROM", 0, SV_IREG_WAVE_SOURCE, 1, 1, 0),
1501SONICVIBES_SINGLE("SonicVibes Onboard Synth", 0, SV_IREG_MPU401, 0, 1, 0),
1502SONICVIBES_SINGLE("SonicVibes External Rx to Synth", 0, SV_IREG_MPU401, 1, 1, 0),
1503SONICVIBES_SINGLE("SonicVibes External Tx", 0, SV_IREG_MPU401, 2, 1, 0)
1504};
1505
1506static void snd_sonicvibes_midi_input_open(mpu401_t * mpu)
1507{
1508 sonicvibes_t *sonic = snd_magic_cast(sonicvibes_t, mpu->private_data, return);
1509 outb(sonic->irqmask &= ~SV_MIDI_MASK, SV_REG(sonic, IRQMASK));
1510}
1511
1512static void snd_sonicvibes_midi_input_close(mpu401_t * mpu)
1513{
1514 sonicvibes_t *sonic = snd_magic_cast(sonicvibes_t, mpu->private_data, return);
1515 outb(sonic->irqmask |= SV_MIDI_MASK, SV_REG(sonic, IRQMASK));
1516}
1517
1518static int snd_sonicvibes_midi(sonicvibes_t * sonic, snd_rawmidi_t * rmidi)
1519{
1520 mpu401_t * mpu = snd_magic_cast(mpu401_t, rmidi->private_data, return -ENXIO);
1521 snd_card_t *card = sonic->card;
1522 snd_rawmidi_str_t *dir;
1523 int idx, err;
1524
1525 mpu->private_data = sonic;
1526 mpu->open_input = snd_sonicvibes_midi_input_open;
1527 mpu->close_input = snd_sonicvibes_midi_input_close;
1528 dir = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
1529 for (idx = 0; idx < SONICVIBES_MIDI_CONTROLS; idx++)
1530 if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_sonicvibes_midi_controls[idx], sonic))) < 0)
1531 return err;
1532 return 0;
1533}
1534
1535static int __init snd_sonic_probe(struct pci_dev *pci,
1536 const struct pci_device_id *id)
1537{
1538 static int dev = 0;
1539 snd_card_t *card;
1540 sonicvibes_t *sonic;
1541 snd_rawmidi_t *midi_uart;
1542 opl3_t *opl3;
1543 int idx, err;
1544
1545 for ( ; dev < SNDRV_CARDS; dev++) {
1546 if (!snd_enable[dev]) {
1547 dev++;
1548 return -ENOENT;
1549 }
1550 break;
1551 }
1552 if (dev >= SNDRV_CARDS)
1553 return -ENODEV;
1554
1555 card = snd_card_new(snd_index[dev], snd_id[dev], THIS_MODULE, 0);
1556 if (card == NULL)
1557 return -ENOMEM;
1558 for (idx = 0; idx < 5; idx++) {
1559 if (pci_resource_start(pci, idx) == 0 ||
1560 !(pci_resource_flags(pci, idx) & IORESOURCE_IO)) {
1561 snd_card_free(card);
1562 return -ENODEV;
1563 }
1564 }
1565 if ((err = snd_sonicvibes_create(card, pci,
1566 snd_reverb[dev] ? 1 : 0,
1567 snd_mge[dev] ? 1 : 0,
1568 &sonic)) < 0) {
1569 snd_card_free(card);
1570 return err;
1571 }
1572 if ((err = snd_sonicvibes_pcm(sonic, 0, NULL)) < 0) {
1573 snd_card_free(card);
1574 return err;
1575 }
1576 if ((err = snd_sonicvibes_mixer(sonic)) < 0) {
1577 snd_card_free(card);
1578 return err;
1579 }
1580 if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_SONICVIBES,
1581 sonic->midi_port, 1,
1582 sonic->irq, 0,
1583 &midi_uart)) < 0) {
1584 snd_card_free(card);
1585 return err;
1586 }
1587 snd_sonicvibes_midi(sonic, midi_uart);
1588 if ((err = snd_opl3_create(card, sonic->synth_port,
1589 sonic->synth_port + 2,
1590 OPL3_HW_OPL3_SV, 1, &opl3)) < 0) {
1591 snd_card_free(card);
1592 return err;
1593 }
1594 if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
1595 snd_card_free(card);
1596 return err;
1597 }
1598 strcpy(card->driver, "SonicVibes");
1599 strcpy(card->shortname, "S3 SonicVibes");
1600 sprintf(card->longname, "%s rev %i at 0x%lx, irq %i",
1601 card->shortname,
1602 sonic->revision,
1603 pci_resource_start(pci, 1),
1604 sonic->irq);
1605
1606 if ((err = snd_card_register(card)) < 0) {
1607 snd_card_free(card);
1608 return err;
1609 }
1610
1611 PCI_SET_DRIVER_DATA(pci, card);
1612 dev++;
1613 return 0;
1614}
1615
1616static void __exit snd_sonic_remove(struct pci_dev *pci)
1617{
1618 snd_card_free(PCI_GET_DRIVER_DATA(pci));
1619 PCI_SET_DRIVER_DATA(pci, NULL);
1620}
1621
1622static struct pci_driver driver = {
1623#ifdef TARGET_OS2
1624 0, 0, 0,
1625 "S3 SonicVibes",
1626 snd_sonic_ids,
1627 snd_sonic_probe,
1628 snd_sonic_remove,
1629 0, 0
1630#else
1631 name: "S3 SonicVibes",
1632 id_table: snd_sonic_ids,
1633 probe: snd_sonic_probe,
1634 remove: snd_sonic_remove,
1635#endif
1636};
1637
1638static int __init alsa_card_sonicvibes_init(void)
1639{
1640 int err;
1641
1642 if ((err = pci_module_init(&driver)) < 0) {
1643#ifdef MODULE
1644// snd_printk("S3 SonicVibes soundcard not found or device busy\n");
1645#endif
1646 return err;
1647 }
1648 return 0;
1649}
1650
1651static void __exit alsa_card_sonicvibes_exit(void)
1652{
1653 pci_unregister_driver(&driver);
1654}
1655
1656module_init(alsa_card_sonicvibes_init)
1657module_exit(alsa_card_sonicvibes_exit)
1658
1659#ifndef MODULE
1660
1661/* format is: snd-card-sonicvibes=snd_enable,snd_index,snd_id,
1662 snd_reverb,snd_mge,snd_dmaio */
1663
1664static int __init alsa_card_sonicvibes_setup(char *str)
1665{
1666 static unsigned __initdata nr_dev = 0;
1667
1668 if (nr_dev >= SNDRV_CARDS)
1669 return 0;
1670 (void)(get_option(&str,&snd_enable[nr_dev]) == 2 &&
1671 get_option(&str,&snd_index[nr_dev]) == 2 &&
1672 get_id(&str,&snd_id[nr_dev]) == 2 &&
1673 get_option(&str,&snd_reverb[nr_dev]) == 2 &&
1674 get_option(&str,&snd_mge[nr_dev]) == 2 &&
1675 get_option(&str,(int *)&snd_dmaio) == 2);
1676 nr_dev++;
1677 return 1;
1678}
1679
1680__setup("snd-card-sonicvibes=", alsa_card_sonicvibes_setup);
1681
1682#endif /* ifndef MODULE */
Note: See TracBrowser for help on using the repository browser.