vibes.c revision 82180
1/*
2 * Copyright (c) 2001 Orion Hodson <O.Hodson@cs.ucl.ac.uk>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * This card has the annoying habit of "clicking" when attached and
27 * detached, haven't been able to remedy this with any combination of
28 * muting.
29 */
30
31#include <dev/sound/pcm/sound.h>
32#include <dev/sound/pci/vibes.h>
33
34#include <pci/pcireg.h>
35#include <pci/pcivar.h>
36
37#include "mixer_if.h"
38
39SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/vibes.c 82180 2001-08-23 11:30:52Z cg $");
40
41/* ------------------------------------------------------------------------- */
42/* Constants */
43
44#define SV_PCI_ID		0xca005333
45#define SV_MAX_BUFFER		8192
46#define SV_MIN_BUFFER		128
47#define SV_INTR_PER_BUFFER	2
48
49#ifndef DEB
50#define DEB(x) /* (x) */
51#endif
52
53/* ------------------------------------------------------------------------- */
54/* Structures */
55
56struct sc_info;
57
58struct sc_chinfo {
59	struct sc_info	*parent;
60	struct pcm_channel	*channel;
61	struct snd_dbuf	*buffer;
62	u_int32_t	fmt, spd;
63	int		dir;
64	int		dma_active, dma_was_active;
65};
66
67struct sc_info {
68	device_t		dev;
69
70	/* DMA buffer allocator */
71	bus_dma_tag_t		parent_dmat;
72
73	/* Enhanced register resources */
74	struct resource 	*enh_reg;
75	bus_space_tag_t		enh_st;
76	bus_space_handle_t	enh_sh;
77	int			enh_type;
78	int			enh_rid;
79
80	/* DMA configuration */
81	struct resource		*dmaa_reg, *dmac_reg;
82	bus_space_tag_t		dmaa_st, dmac_st;
83	bus_space_handle_t	dmaa_sh, dmac_sh;
84	int			dmaa_type, dmac_type;
85	int			dmaa_rid, dmac_rid;
86
87	/* Interrupt resources */
88	struct resource 	*irq;
89	int			irqid;
90	void			*ih;
91
92	struct sc_chinfo	rch, pch;
93	u_int8_t		rev;
94};
95
96static u_int32_t sc_fmt[] = {
97	AFMT_U8,
98	AFMT_U8 | AFMT_STEREO,
99	AFMT_S16_LE,
100	AFMT_S16_LE | AFMT_STEREO,
101	0
102};
103
104static struct pcmchan_caps sc_caps = {8000, 48000, sc_fmt, 0};
105
106/* ------------------------------------------------------------------------- */
107/* Register Manipulations */
108
109#define sv_direct_set(x, y, z) _sv_direct_set(x, y, z, __LINE__)
110
111static u_int8_t
112sv_direct_get(struct sc_info *sc, u_int8_t reg)
113{
114	return bus_space_read_1(sc->enh_st, sc->enh_sh, reg);
115}
116
117static void
118_sv_direct_set(struct sc_info *sc, u_int8_t reg, u_int8_t val, int line)
119{
120	u_int8_t n;
121	bus_space_write_1(sc->enh_st, sc->enh_sh, reg, val);
122
123	n = sv_direct_get(sc, reg);
124	if (n != val) {
125		device_printf(sc->dev, "sv_direct_set register 0x%02x %d != %d from line %d\n", reg, n, val, line);
126	}
127}
128
129static u_int8_t
130sv_indirect_get(struct sc_info *sc, u_int8_t reg)
131{
132	if (reg == SV_REG_FORMAT || reg == SV_REG_ANALOG_PWR)
133		reg |= SV_CM_INDEX_MCE;
134
135	bus_space_write_1(sc->enh_st, sc->enh_sh, SV_CM_INDEX, reg);
136	return bus_space_read_1(sc->enh_st, sc->enh_sh, SV_CM_DATA);
137}
138
139#define sv_indirect_set(x, y, z) _sv_indirect_set(x, y, z, __LINE__)
140
141static void
142_sv_indirect_set(struct sc_info *sc, u_int8_t reg, u_int8_t val, int line)
143{
144	if (reg == SV_REG_FORMAT || reg == SV_REG_ANALOG_PWR)
145		reg |= SV_CM_INDEX_MCE;
146
147	bus_space_write_1(sc->enh_st, sc->enh_sh, SV_CM_INDEX, reg);
148	bus_space_write_1(sc->enh_st, sc->enh_sh, SV_CM_DATA, val);
149
150	reg &= ~SV_CM_INDEX_MCE;
151	if (reg != SV_REG_ADC_PLLM) {
152		u_int8_t n;
153		n = sv_indirect_get(sc, reg);
154		if (n != val) {
155			device_printf(sc->dev, "sv_indirect_set register 0x%02x %d != %d line %d\n", reg, n, val, line);
156		}
157	}
158}
159
160static void
161sv_dma_set_config(bus_space_tag_t st, bus_space_handle_t sh,
162		  u_int32_t base, u_int32_t count, u_int8_t mode)
163{
164	bus_space_write_4(st, sh, SV_DMA_ADDR, base);
165	bus_space_write_4(st, sh, SV_DMA_COUNT, count & 0xffffff);
166	bus_space_write_1(st, sh, SV_DMA_MODE, mode);
167
168	DEB(printf("base 0x%08x count %5d mode 0x%02x\n",
169		   base, count, mode));
170}
171
172static u_int32_t
173sv_dma_get_count(bus_space_tag_t st, bus_space_handle_t sh)
174{
175	return bus_space_read_4(st, sh, SV_DMA_COUNT) & 0xffffff;
176}
177
178/* ------------------------------------------------------------------------- */
179/* Play / Record Common Interface */
180
181static void *
182svchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
183{
184	struct sc_info		*sc = devinfo;
185	struct sc_chinfo	*ch;
186	ch = (dir == PCMDIR_PLAY) ? &sc->pch : &sc->rch;
187
188	ch->parent = sc;
189	ch->channel = c;
190	ch->dir = dir;
191
192	if (sndbuf_alloc(b, sc->parent_dmat, SV_MAX_BUFFER) != 0) {
193		DEB(printf("svchan_init failed\n"));
194		return NULL;
195	}
196	ch->buffer = b;
197	ch->fmt = AFMT_U8;
198	ch->spd = DSP_DEFAULT_SPEED;
199	ch->dma_active = ch->dma_was_active = 0;
200
201	return ch;
202}
203
204static struct pcmchan_caps *
205svchan_getcaps(kobj_t obj, void *data)
206{
207        return &sc_caps;
208}
209
210static int
211svchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
212{
213	struct sc_chinfo *ch = data;
214
215        /* user has requested interrupts every blocksize bytes */
216	RANGE(blocksize, SV_MIN_BUFFER, SV_MAX_BUFFER / SV_INTR_PER_BUFFER);
217	sndbuf_resize(ch->buffer, SV_INTR_PER_BUFFER, blocksize);
218	DEB(printf("svchan_setblocksize: %d\n", blocksize));
219	return sndbuf_getsize(ch->buffer);
220}
221
222static int
223svchan_setformat(kobj_t obj, void *data, u_int32_t format)
224{
225	struct sc_chinfo *ch = data;
226	/* NB Just note format here as setting format register
227	 * generates noise if dma channel is inactive. */
228	ch->fmt  = (format & AFMT_STEREO) ? SV_AFMT_STEREO : SV_AFMT_MONO;
229	ch->fmt |= (format & AFMT_16BIT) ? SV_AFMT_S16 : SV_AFMT_U8;
230	return 0;
231}
232
233static int
234svchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
235{
236	struct sc_chinfo *ch = data;
237	RANGE(speed, 8000, 48000);
238	ch->spd = speed;
239	return speed;
240}
241
242/* ------------------------------------------------------------------------- */
243/* Recording interface */
244
245static int
246sv_set_recspeed(struct sc_info *sc, u_int32_t speed)
247{
248	u_int32_t	f_out, f_actual;
249	u_int32_t	rs, re, r, best_r = 0, r2, t, n, best_n = 0;
250	int32_t		m, best_m = 0, ms, me, err, min_err;
251
252	/* This algorithm is a variant described in sonicvibes.pdf
253	 * appendix A.  This search is marginally more extensive and
254	 * results in (nominally) better sample rate matching. */
255
256	f_out = SV_F_SCALE * speed;
257	min_err = 0x7fffffff;
258
259	/* Find bounds of r to examine, rs <= r <= re */
260	t = 80000000 / f_out;
261	for (rs = 1; (1 << rs) < t; rs++);
262
263	t = 150000000 / f_out;
264	for (re = 1; (2 << re) < t; re++);
265	if (re > 7) re = 7;
266
267	/* Search over r, n, m */
268	for (r = rs; r <= re; r++) {
269		r2 = (1 << r);
270		for (n = 3; n < 34; n++) {
271			m = f_out * n / (SV_F_REF / r2);
272			ms = (m > 3) ? (m - 1) : 3;
273			me = (m < 129) ? (m + 1) : 129;
274			for (m = ms; m <= me; m++) {
275				f_actual = m * SV_F_REF / (n * r2);
276				if (f_actual > f_out) {
277					err = f_actual - f_out;
278				} else {
279					err = f_out - f_actual;
280				}
281				if (err < min_err) {
282					best_r = r;
283					best_m = m - 2;
284					best_n = n - 2;
285					min_err = err;
286					if (err == 0) break;
287				}
288			}
289		}
290	}
291
292	sv_indirect_set(sc, SV_REG_ADC_PLLM, best_m);
293	sv_indirect_set(sc, SV_REG_ADC_PLLN,
294			SV_ADC_PLLN(best_n) | SV_ADC_PLLR(best_r));
295	DEB(printf("svrchan_setspeed: %d -> PLLM 0x%02x PLLNR 0x%08x\n",
296		   speed,
297		   sv_indirect_get(sc, SV_REG_ADC_PLLM),
298		   sv_indirect_get(sc, SV_REG_ADC_PLLN)));
299	return 0;
300}
301
302static int
303svrchan_trigger(kobj_t obj, void *data, int go)
304{
305	struct sc_chinfo	*ch = data;
306	struct sc_info 		*sc = ch->parent;
307	u_int32_t		count, enable;
308	u_int8_t		v;
309
310	switch(go) {
311	case PCMTRIG_START:
312		/* Set speed */
313		sv_set_recspeed(sc, ch->spd);
314
315		/* Set format */
316		v  = sv_indirect_get(sc, SV_REG_FORMAT) & ~SV_AFMT_DMAC_MSK;
317		v |= SV_AFMT_DMAC(ch->fmt);
318		sv_indirect_set(sc, SV_REG_FORMAT, v);
319
320		/* Program DMA */
321		count = sndbuf_getsize(ch->buffer) / 2; /* DMAC uses words */
322		sv_dma_set_config(sc->dmac_st, sc->dmac_sh,
323				  vtophys(sndbuf_getbuf(ch->buffer)),
324				  count - 1,
325				  SV_DMA_MODE_AUTO | SV_DMA_MODE_RD);
326		count = count / SV_INTR_PER_BUFFER - 1;
327		sv_indirect_set(sc, SV_REG_DMAC_COUNT_HI, count >> 8);
328		sv_indirect_set(sc, SV_REG_DMAC_COUNT_LO, count & 0xff);
329
330		/* Enable DMA */
331		enable = sv_indirect_get(sc, SV_REG_ENABLE) | SV_RECORD_ENABLE;
332		sv_indirect_set(sc, SV_REG_ENABLE, enable);
333		ch->dma_active = 1;
334		break;
335	case PCMTRIG_ABORT:
336		enable = sv_indirect_get(sc, SV_REG_ENABLE) & ~SV_RECORD_ENABLE;
337		sv_indirect_set(sc, SV_REG_ENABLE, enable);
338		ch->dma_active = 0;
339		break;
340	}
341
342	return 0;
343}
344
345static int
346svrchan_getptr(kobj_t obj, void *data)
347{
348	struct sc_chinfo	*ch = data;
349	struct sc_info 		*sc = ch->parent;
350	u_int32_t sz, remain;
351
352	sz = sndbuf_getsize(ch->buffer);
353	/* DMAC uses words */
354	remain = (sv_dma_get_count(sc->dmac_st, sc->dmac_sh) + 1) * 2;
355	return sz - remain;
356}
357
358static kobj_method_t svrchan_methods[] = {
359        KOBJMETHOD(channel_init,                svchan_init),
360        KOBJMETHOD(channel_setformat,           svchan_setformat),
361        KOBJMETHOD(channel_setspeed,            svchan_setspeed),
362        KOBJMETHOD(channel_setblocksize,        svchan_setblocksize),
363        KOBJMETHOD(channel_trigger,             svrchan_trigger),
364        KOBJMETHOD(channel_getptr,              svrchan_getptr),
365        KOBJMETHOD(channel_getcaps,             svchan_getcaps),
366        { 0, 0 }
367};
368CHANNEL_DECLARE(svrchan);
369
370/* ------------------------------------------------------------------------- */
371/* Playback interface */
372
373static int
374svpchan_trigger(kobj_t obj, void *data, int go)
375{
376	struct sc_chinfo	*ch = data;
377	struct sc_info		*sc = ch->parent;
378	u_int32_t		count, enable, speed;
379	u_int8_t		v;
380
381	switch(go) {
382	case PCMTRIG_START:
383		/* Set speed */
384		speed = (ch->spd * 65536) / 48000;
385		if (speed > 65535)
386			speed = 65535;
387		sv_indirect_set(sc, SV_REG_PCM_SAMPLING_HI, speed >> 8);
388		sv_indirect_set(sc, SV_REG_PCM_SAMPLING_LO, speed & 0xff);
389
390		/* Set format */
391		v  = sv_indirect_get(sc, SV_REG_FORMAT) & ~SV_AFMT_DMAA_MSK;
392		v |= SV_AFMT_DMAA(ch->fmt);
393		sv_indirect_set(sc, SV_REG_FORMAT, v);
394
395		/* Program DMA */
396		count = sndbuf_getsize(ch->buffer);
397		sv_dma_set_config(sc->dmaa_st, sc->dmaa_sh,
398				  vtophys(sndbuf_getbuf(ch->buffer)),
399				  count - 1,
400				  SV_DMA_MODE_AUTO | SV_DMA_MODE_WR);
401		count = count / SV_INTR_PER_BUFFER - 1;
402		sv_indirect_set(sc, SV_REG_DMAA_COUNT_HI, count >> 8);
403		sv_indirect_set(sc, SV_REG_DMAA_COUNT_LO, count & 0xff);
404
405		/* Enable DMA */
406		enable = sv_indirect_get(sc, SV_REG_ENABLE);
407		enable = (enable | SV_PLAY_ENABLE) & ~SV_PLAYBACK_PAUSE;
408		sv_indirect_set(sc, SV_REG_ENABLE, enable);
409		ch->dma_active = 1;
410		break;
411	case PCMTRIG_ABORT:
412		enable = sv_indirect_get(sc, SV_REG_ENABLE) & ~SV_PLAY_ENABLE;
413		sv_indirect_set(sc, SV_REG_ENABLE, enable);
414		ch->dma_active = 0;
415		break;
416	}
417
418	return 0;
419}
420
421static int
422svpchan_getptr(kobj_t obj, void *data)
423{
424	struct sc_chinfo	*ch = data;
425	struct sc_info 		*sc = ch->parent;
426	u_int32_t sz, remain;
427
428	sz = sndbuf_getsize(ch->buffer);
429	/* DMAA uses bytes */
430	remain = sv_dma_get_count(sc->dmaa_st, sc->dmaa_sh) + 1;
431	return (sz - remain);
432}
433
434static kobj_method_t svpchan_methods[] = {
435        KOBJMETHOD(channel_init,                svchan_init),
436        KOBJMETHOD(channel_setformat,           svchan_setformat),
437        KOBJMETHOD(channel_setspeed,            svchan_setspeed),
438        KOBJMETHOD(channel_setblocksize,        svchan_setblocksize),
439        KOBJMETHOD(channel_trigger,             svpchan_trigger),
440        KOBJMETHOD(channel_getptr,              svpchan_getptr),
441        KOBJMETHOD(channel_getcaps,             svchan_getcaps),
442        { 0, 0 }
443};
444CHANNEL_DECLARE(svpchan);
445
446/* ------------------------------------------------------------------------- */
447/* Mixer support */
448
449struct sv_mix_props {
450	u_int8_t	reg;		/* Register */
451	u_int8_t	stereo:1;	/* Supports 2 channels */
452	u_int8_t	mute:1;		/* Supports muting */
453	u_int8_t	neg:1;		/* Negative gain */
454	u_int8_t	max;		/* Max gain */
455	u_int8_t	iselect;	/* Input selector */
456} static const mt [SOUND_MIXER_NRDEVICES] = {
457	[SOUND_MIXER_LINE1]  = {SV_REG_AUX1,      1, 1, 1, SV_DEFAULT_MAX, SV_INPUT_AUX1},
458	[SOUND_MIXER_CD]     = {SV_REG_CD,        1, 1, 1, SV_DEFAULT_MAX, SV_INPUT_CD},
459	[SOUND_MIXER_LINE]   = {SV_REG_LINE,      1, 1, 1, SV_DEFAULT_MAX, SV_INPUT_LINE},
460	[SOUND_MIXER_MIC]    = {SV_REG_MIC,       0, 1, 1, SV_MIC_MAX,     SV_INPUT_MIC},
461	[SOUND_MIXER_SYNTH]  = {SV_REG_SYNTH,     0, 1, 1, SV_DEFAULT_MAX, 0},
462	[SOUND_MIXER_LINE2]  = {SV_REG_AUX2,      1, 1, 1, SV_DEFAULT_MAX, SV_INPUT_AUX2},
463	[SOUND_MIXER_VOLUME] = {SV_REG_MIX,       1, 1, 1, SV_DEFAULT_MAX, 0},
464	[SOUND_MIXER_PCM]    = {SV_REG_PCM,       1, 1, 1, SV_PCM_MAX,     0},
465	[SOUND_MIXER_RECLEV] = {SV_REG_ADC_INPUT, 1, 0, 0, SV_ADC_MAX, 0},
466};
467
468static void
469sv_channel_gain(struct sc_info *sc, u_int32_t dev, u_int32_t gain, u_int32_t channel)
470{
471	u_int8_t	v;
472	int32_t		g;
473
474	g = mt[dev].max * gain / 100;
475	if (mt[dev].neg)
476		g = mt[dev].max - g;
477	v  = sv_indirect_get(sc, mt[dev].reg + channel) & ~mt[dev].max;
478	v |= g;
479
480	if (mt[dev].mute) {
481		if (gain == 0) {
482			v |= SV_MUTE;
483		} else {
484			v &= ~SV_MUTE;
485		}
486	}
487	sv_indirect_set(sc, mt[dev].reg + channel, v);
488}
489
490static int
491sv_gain(struct sc_info *sc, u_int32_t dev, u_int32_t left, u_int32_t right)
492{
493	sv_channel_gain(sc, dev, left, 0);
494	if (mt[dev].stereo)
495		sv_channel_gain(sc, dev, right, 1);
496	return 0;
497}
498
499static void
500sv_mix_mute_all(struct sc_info *sc)
501{
502	int32_t i;
503	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
504		if (mt[i].reg) sv_gain(sc, i, 0, 0);
505	}
506}
507
508static int
509sv_mix_init(struct snd_mixer *m)
510{
511	u_int32_t 	i, v;
512
513	for(i = v = 0; i < SOUND_MIXER_NRDEVICES; i++) {
514		if (mt[i].max) v |= (1 << i);
515	}
516	mix_setdevs(m, v);
517
518	for(i = v = 0; i < SOUND_MIXER_NRDEVICES; i++) {
519		if (mt[i].iselect) v |= (1 << i);
520	}
521	mix_setrecdevs(m, v);
522
523	return 0;
524}
525
526static int
527sv_mix_set(struct snd_mixer *m, u_int32_t dev, u_int32_t left, u_int32_t right)
528{
529	struct sc_info	*sc = mix_getdevinfo(m);
530	return sv_gain(sc, dev, left, right);
531}
532
533static int
534sv_mix_setrecsrc(struct snd_mixer *m, u_int32_t mask)
535{
536	struct sc_info	*sc = mix_getdevinfo(m);
537	u_int32_t	i, v;
538
539	v = sv_indirect_get(sc, SV_REG_ADC_INPUT) & SV_INPUT_GAIN_MASK;
540	for(i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
541		if ((1 << i) & mask) {
542			v |= mt[i].iselect;
543		}
544	}
545	DEB(printf("sv_mix_setrecsrc: mask 0x%08x adc_input 0x%02x\n", mask, v));
546	return mask;
547}
548
549static kobj_method_t sv_mixer_methods[] = {
550        KOBJMETHOD(mixer_init,		sv_mix_init),
551        KOBJMETHOD(mixer_set,		sv_mix_set),
552        KOBJMETHOD(mixer_setrecsrc,	sv_mix_setrecsrc),
553        { 0, 0 }
554};
555MIXER_DECLARE(sv_mixer);
556
557/* ------------------------------------------------------------------------- */
558/* Power management and reset */
559
560static void
561sv_power(struct sc_info *sc, int state)
562{
563	u_int8_t v;
564
565        switch (state) {
566        case 0:
567		/* power on */
568		v = sv_indirect_get(sc, SV_REG_ANALOG_PWR) &~ SV_ANALOG_OFF;
569		v |= SV_ANALOG_OFF_SRS | SV_ANALOG_OFF_SPLL;
570		sv_indirect_set(sc, SV_REG_ANALOG_PWR, v);
571		v = sv_indirect_get(sc, SV_REG_DIGITAL_PWR) &~ SV_DIGITAL_OFF;
572		v |= SV_DIGITAL_OFF_SYN | SV_DIGITAL_OFF_MU | SV_DIGITAL_OFF_GP;
573		sv_indirect_set(sc, SV_REG_DIGITAL_PWR, v);
574                break;
575        default:
576		/* power off */
577		v = sv_indirect_get(sc, SV_REG_ANALOG_PWR) | SV_ANALOG_OFF;
578		sv_indirect_set(sc, SV_REG_ANALOG_PWR, v);
579		v = sv_indirect_get(sc, SV_REG_DIGITAL_PWR) | SV_DIGITAL_OFF;
580		sv_indirect_set(sc, SV_REG_DIGITAL_PWR, SV_DIGITAL_OFF);
581                break;
582        }
583        DEB(printf("Power state %d\n", state));
584}
585
586static int
587sv_init(struct sc_info *sc)
588{
589	u_int8_t	v;
590
591	/* Effect reset */
592	v  = sv_direct_get(sc, SV_CM_CONTROL) & ~SV_CM_CONTROL_ENHANCED;
593	v |= SV_CM_CONTROL_RESET;
594	sv_direct_set(sc, SV_CM_CONTROL, v);
595	DELAY(50);
596
597	v = sv_direct_get(sc, SV_CM_CONTROL) & ~SV_CM_CONTROL_RESET;
598	sv_direct_set(sc, SV_CM_CONTROL, v);
599	DELAY(50);
600
601	/* Set in enhanced mode */
602	v = sv_direct_get(sc, SV_CM_CONTROL);
603	v |= SV_CM_CONTROL_ENHANCED;
604	sv_direct_set(sc, SV_CM_CONTROL, v);
605
606	/* Enable interrupts (UDM and MIDM are superfluous) */
607	v = sv_direct_get(sc, SV_CM_IMR);
608	v &= ~(SV_CM_IMR_AMSK | SV_CM_IMR_CMSK | SV_CM_IMR_SMSK);
609	sv_direct_set(sc, SV_CM_IMR, v);
610
611	/* Select ADC PLL for ADC clock */
612	v = sv_indirect_get(sc, SV_REG_CLOCK_SOURCE) & ~SV_CLOCK_ALTERNATE;
613	sv_indirect_set(sc, SV_REG_CLOCK_SOURCE, v);
614
615	/* Disable loopback - binds ADC and DAC rates */
616	v = sv_indirect_get(sc, SV_REG_LOOPBACK) & ~SV_LOOPBACK_ENABLE;
617	sv_indirect_set(sc, SV_REG_LOOPBACK, v);
618
619	/* Disable SRS */
620	v = sv_indirect_get(sc, SV_REG_SRS_SPACE) | SV_SRS_DISABLED;
621	sv_indirect_set(sc, SV_REG_SRS_SPACE, v);
622
623	/* Get revision */
624	sc->rev = sv_indirect_get(sc, SV_REG_REVISION);
625
626	return 0;
627}
628
629static int
630sv_suspend(device_t dev)
631{
632	struct sc_info	*sc = pcm_getdevinfo(dev);
633
634	sc->rch.dma_was_active = sc->rch.dma_active;
635	svrchan_trigger(NULL, &sc->rch, PCMTRIG_ABORT);
636
637	sc->pch.dma_was_active = sc->pch.dma_active;
638	svrchan_trigger(NULL, &sc->pch, PCMTRIG_ABORT);
639
640	sv_mix_mute_all(sc);
641	sv_power(sc, 3);
642
643	return 0;
644}
645
646static int
647sv_resume(device_t dev)
648{
649	struct sc_info	*sc = pcm_getdevinfo(dev);
650
651	sv_mix_mute_all(sc);
652	sv_power(sc, 0);
653	if (sv_init(sc) == -1) {
654		device_printf(dev, "unable to reinitialize the card\n");
655		return ENXIO;
656	}
657
658	if (mixer_reinit(dev) == -1) {
659		device_printf(dev, "unable to reinitialize the mixer\n");
660                return ENXIO;
661        }
662
663	if (sc->rch.dma_was_active) {
664		svrchan_trigger(0, &sc->rch, PCMTRIG_START);
665	}
666
667	if (sc->pch.dma_was_active) {
668		svpchan_trigger(0, &sc->pch, PCMTRIG_START);
669	}
670
671	return 0;
672}
673
674/* ------------------------------------------------------------------------- */
675/* Resource related */
676
677static void
678sv_intr(void *data)
679{
680	struct sc_info	*sc = data;
681	u_int8_t	status;
682
683	status = sv_direct_get(sc, SV_CM_STATUS);
684	if (status & SV_CM_STATUS_AINT)
685		chn_intr(sc->pch.channel);
686
687	if (status & SV_CM_STATUS_CINT)
688		chn_intr(sc->rch.channel);
689
690	status &= ~(SV_CM_STATUS_AINT|SV_CM_STATUS_CINT);
691	DEB(if (status) printf("intr 0x%02x ?\n", status));
692
693	return;
694}
695
696static int
697sv_probe(device_t dev)
698{
699	switch(pci_get_devid(dev)) {
700	case SV_PCI_ID:
701		device_set_desc(dev, "S3 Sonicvibes");
702		return 0;
703	default:
704		return ENXIO;
705	}
706}
707
708static int
709sv_attach(device_t dev) {
710	struct snddev_info	*d;
711	struct sc_info	*sc;
712	u_int32_t	data;
713	char		status[SND_STATUSLEN];
714	u_long		midi_start, games_start, count, sdmaa, sdmac;
715
716	d = device_get_softc(dev);
717
718	sc = malloc(sizeof(struct sc_info), M_DEVBUF, M_NOWAIT | M_ZERO);
719	if (sc == NULL) {
720		device_printf(dev, "cannot allocate softc");
721		return ENXIO;
722	}
723	sc->dev = dev;
724
725	data = pci_read_config(dev, PCIR_COMMAND, 2);
726	data |= (PCIM_CMD_PORTEN|PCIM_CMD_BUSMASTEREN);
727	pci_write_config(dev, PCIR_COMMAND, data, 2);
728	data = pci_read_config(dev, PCIR_COMMAND, 2);
729
730#if __FreeBSD_version > 500000
731        if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
732                device_printf(dev, "chip is in D%d power mode "
733                              "-- setting to D0\n", pci_get_powerstate(dev));
734                pci_set_powerstate(dev, PCI_POWERSTATE_D0);
735        }
736#endif
737	sc->enh_rid  = SV_PCI_ENHANCED;
738	sc->enh_type = SYS_RES_IOPORT;
739	sc->enh_reg  = bus_alloc_resource(dev, sc->enh_type,
740					  &sc->enh_rid, 0, ~0,
741					  SV_PCI_ENHANCED_SIZE, RF_ACTIVE);
742	if (sc->enh_reg == NULL) {
743		device_printf(dev, "sv_attach: cannot allocate enh\n");
744		return ENXIO;
745	}
746	sc->enh_st = rman_get_bustag(sc->enh_reg);
747	sc->enh_sh = rman_get_bushandle(sc->enh_reg);
748
749	data = pci_read_config(dev, SV_PCI_DMAA, 4);
750	DEB(printf("sv_attach: initial dmaa 0x%08x\n", data));
751	data = pci_read_config(dev, SV_PCI_DMAC, 4);
752	DEB(printf("sv_attach: initial dmac 0x%08x\n", data));
753
754	/* Initialize DMA_A and DMA_C */
755	pci_write_config(dev, SV_PCI_DMAA, SV_PCI_DMA_EXTENDED, 4);
756	pci_write_config(dev, SV_PCI_DMAC, 0, 4);
757
758	/* Register IRQ handler */
759	sc->irqid = 0;
760        sc->irq   = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irqid,
761				       0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
762        if (!sc->irq ||
763	    bus_setup_intr(dev, sc->irq, INTR_TYPE_AV, sv_intr, sc, &sc->ih)) {
764                device_printf(dev, "sv_attach: Unable to map interrupt\n");
765                goto fail;
766        }
767
768        if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
769                               /*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
770                               /*highaddr*/BUS_SPACE_MAXADDR,
771                               /*filter*/NULL, /*filterarg*/NULL,
772                               /*maxsize*/SV_MAX_BUFFER, /*nsegments*/1,
773                               /*maxsegz*/0x3ffff, /*flags*/0,
774                               &sc->parent_dmat) != 0) {
775                device_printf(dev, "sv_attach: Unable to create dma tag\n");
776                goto fail;
777        }
778
779	/* Power up and initialize */
780	sv_mix_mute_all(sc);
781	sv_power(sc, 0);
782	sv_init(sc);
783
784	if (mixer_init(dev, &sv_mixer_class, sc) != 0) {
785		device_printf(dev, "sv_attach: Mixer failed to initialize\n");
786		goto fail;
787	}
788
789	/* XXX This is a hack, and it's ugly.  Okay, the deal is this
790	 * card has two more io regions that available for automatic
791	 * configuration by the pci code.  These need to be allocated
792	 * to used as control registers for the DMA engines.
793	 * Unfortunately FBSD has no bus_space_foo() functions so we
794	 * have to grab port space in region of existing resources.  Go
795	 * for space between midi and game ports.
796	 */
797	bus_get_resource(dev, SYS_RES_IOPORT, SV_PCI_MIDI, &midi_start, &count);
798	bus_get_resource(dev, SYS_RES_IOPORT, SV_PCI_GAMES, &games_start, &count);
799
800	/* Check assumptions about space availability and alignment. */
801	if ((midi_start - games_start != 0x200) || midi_start & 0xff) {
802		device_printf(dev, "sv_attach: resource assumptions not met\n");
803		goto fail;
804	}
805
806	sdmaa = games_start + 0x40;
807	sdmac = sdmaa + 0x40;
808
809	/* Add resources to list of pci resources for this device - from here on
810	 * they look like normal pci resources. */
811	bus_set_resource(dev, SYS_RES_IOPORT, SV_PCI_DMAA, sdmaa, SV_PCI_DMAA_SIZE);
812	bus_set_resource(dev, SYS_RES_IOPORT, SV_PCI_DMAC, sdmac, SV_PCI_DMAC_SIZE);
813
814	/* Cache resource short-cuts for dma_a */
815	sc->dmaa_rid = SV_PCI_DMAA;
816	sc->dmaa_type = SYS_RES_IOPORT;
817	sc->dmaa_reg  = bus_alloc_resource(dev, sc->dmaa_type,
818					   &sc->dmaa_rid, 0, ~0,
819					   SV_PCI_ENHANCED_SIZE, RF_ACTIVE);
820	if (sc->dmaa_reg == NULL) {
821		device_printf(dev, "sv_attach: cannot allocate dmaa\n");
822		goto fail;
823	}
824	sc->dmaa_st = rman_get_bustag(sc->dmaa_reg);
825	sc->dmaa_sh = rman_get_bushandle(sc->dmaa_reg);
826
827	/* Poke port into dma_a configuration, nb bit flags to enable dma */
828	data = pci_read_config(dev, SV_PCI_DMAA, 4) | SV_PCI_DMA_ENABLE | SV_PCI_DMA_EXTENDED;
829	data = ((u_int32_t)sdmaa & 0xfffffff0) | (data & 0x0f);
830	pci_write_config(dev, SV_PCI_DMAA, data, 4);
831	DEB(printf("dmaa: 0x%x 0x%x\n", data, pci_read_config(dev, SV_PCI_DMAA, 4)));
832
833	/* Cache resource short-cuts for dma_c */
834	sc->dmac_rid = SV_PCI_DMAC;
835	sc->dmac_type = SYS_RES_IOPORT;
836	sc->dmac_reg  = bus_alloc_resource(dev, sc->dmac_type,
837					   &sc->dmac_rid, 0, ~0,
838					   SV_PCI_ENHANCED_SIZE, RF_ACTIVE);
839	if (sc->dmac_reg == NULL) {
840		device_printf(dev, "sv_attach: cannot allocate dmac\n");
841		goto fail;
842	}
843	sc->dmac_st = rman_get_bustag(sc->dmac_reg);
844	sc->dmac_sh = rman_get_bushandle(sc->dmac_reg);
845
846	/* Poke port into dma_c configuration, nb bit flags to enable dma */
847	data = pci_read_config(dev, SV_PCI_DMAC, 4) | SV_PCI_DMA_ENABLE | SV_PCI_DMA_EXTENDED;
848	data = ((u_int32_t)sdmac & 0xfffffff0) | (data & 0x0f);
849	pci_write_config(dev, SV_PCI_DMAC, data, 4);
850	DEB(printf("dmac: 0x%x 0x%x\n", data, pci_read_config(dev, SV_PCI_DMAC, 4)));
851
852	if (bootverbose)
853		printf("Sonicvibes: revision %d.\n", sc->rev);
854
855        if (pcm_register(dev, sc, 1, 1)) {
856		device_printf(dev, "sv_attach: pcm_register fail\n");
857                goto fail;
858	}
859
860        pcm_addchan(dev, PCMDIR_PLAY, &svpchan_class, sc);
861        pcm_addchan(dev, PCMDIR_REC,  &svrchan_class, sc);
862
863        snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld",
864                 rman_get_start(sc->enh_reg),  rman_get_start(sc->irq));
865        pcm_setstatus(dev, status);
866
867        DEB(printf("sv_attach: succeeded\n"));
868
869	return 0;
870
871 fail:
872	if (sc->parent_dmat)
873		bus_dma_tag_destroy(sc->parent_dmat);
874        if (sc->ih)
875		bus_teardown_intr(dev, sc->irq, sc->ih);
876        if (sc->irq)
877		bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
878	if (sc->enh_reg)
879		bus_release_resource(dev, sc->enh_type, sc->enh_rid, sc->enh_reg);
880	if (sc->dmaa_reg)
881		bus_release_resource(dev, sc->dmaa_type, sc->dmaa_rid, sc->dmaa_reg);
882	if (sc->dmac_reg)
883		bus_release_resource(dev, sc->dmac_type, sc->dmac_rid, sc->dmac_reg);
884	return ENXIO;
885}
886
887static int
888sv_detach(device_t dev) {
889	struct sc_info	*sc;
890	int		r;
891
892	r = pcm_unregister(dev);
893	if (r) return r;
894
895	sc = pcm_getdevinfo(dev);
896	sv_mix_mute_all(sc);
897	sv_power(sc, 3);
898
899	bus_dma_tag_destroy(sc->parent_dmat);
900	bus_teardown_intr(dev, sc->irq, sc->ih);
901	bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
902	bus_release_resource(dev, sc->enh_type, sc->enh_rid, sc->enh_reg);
903	bus_release_resource(dev, sc->dmaa_type, sc->dmaa_rid, sc->dmaa_reg);
904	bus_release_resource(dev, sc->dmac_type, sc->dmac_rid, sc->dmac_reg);
905
906	free(sc, M_DEVBUF);
907
908	return 0;
909}
910
911static device_method_t sc_methods[] = {
912        DEVMETHOD(device_probe,         sv_probe),
913        DEVMETHOD(device_attach,        sv_attach),
914        DEVMETHOD(device_detach,        sv_detach),
915        DEVMETHOD(device_resume,        sv_resume),
916        DEVMETHOD(device_suspend,       sv_suspend),
917        { 0, 0 }
918};
919
920static driver_t sonicvibes_driver = {
921        "pcm",
922        sc_methods,
923        PCM_SOFTC_SIZE
924};
925
926DRIVER_MODULE(snd_sonicvibes, pci, sonicvibes_driver, pcm_devclass, 0, 0);
927MODULE_DEPEND(snd_sonicvibes, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER);
928MODULE_VERSION(snd_sonicvibes, 1);
929