1205859Sjoel/*-
2159687Snetchild * Copyright (c) 2001 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp>
3159687Snetchild * All rights reserved.
4159687Snetchild *
5159687Snetchild * Redistribution and use in source and binary forms, with or without
6159687Snetchild * modification, are permitted provided that the following conditions
7159687Snetchild * are met:
8159687Snetchild * 1. Redistributions of source code must retain the above copyright
9159687Snetchild *    notice, this list of conditions and the following disclaimer.
10159687Snetchild * 2. Redistributions in binary form must reproduce the above copyright
11159687Snetchild *    notice, this list of conditions and the following disclaimer in the
12159687Snetchild *    documentation and/or other materials provided with the distribution.
13159687Snetchild *
14159687Snetchild * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15159687Snetchild * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16159687Snetchild * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17159687Snetchild * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18159687Snetchild * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19159687Snetchild * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20159687Snetchild * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21159687Snetchild * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
22159687Snetchild * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23188480Snetchild * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24159687Snetchild * SUCH DAMAGE.
25159687Snetchild *
26159687Snetchild */
27159687Snetchild
28193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS
29193640Sariff#include "opt_snd.h"
30193640Sariff#endif
31193640Sariff
32159687Snetchild#include <dev/sound/pcm/sound.h>
33159687Snetchild#include <dev/sound/pcm/ac97.h>
34162876Snetchild#include <dev/sound/pci/spicds.h>
35159687Snetchild#include <dev/sound/pci/envy24.h>
36159687Snetchild
37159689Snetchild#include <dev/pci/pcireg.h>
38159689Snetchild#include <dev/pci/pcivar.h>
39159687Snetchild
40159687Snetchild#include "mixer_if.h"
41159687Snetchild
42165306SariffSND_DECLARE_FILE("$FreeBSD$");
43165306Sariff
44227293Sedstatic MALLOC_DEFINE(M_ENVY24, "envy24", "envy24 audio");
45159687Snetchild
46159687Snetchild/* -------------------------------------------------------------------- */
47159687Snetchild
48159687Snetchildstruct sc_info;
49159687Snetchild
50159687Snetchild#define ENVY24_PLAY_CHNUM 10
51159687Snetchild#define ENVY24_REC_CHNUM 12
52159687Snetchild#define ENVY24_PLAY_BUFUNIT (4 /* byte/sample */ * 10 /* channel */)
53159687Snetchild#define ENVY24_REC_BUFUNIT  (4 /* byte/sample */ * 12 /* channel */)
54159687Snetchild#define ENVY24_SAMPLE_NUM   4096
55159687Snetchild
56159687Snetchild#define ENVY24_TIMEOUT 1000
57159687Snetchild
58193640Sariff#define ENVY24_DEFAULT_FORMAT	SND_FORMAT(AFMT_S16_LE, 2, 0)
59159687Snetchild
60159687Snetchild#define ENVY24_NAMELEN 32
61159687Snetchild
62170031Sjoel#define SDA_GPIO 0x10
63170031Sjoel#define SCL_GPIO 0x20
64170031Sjoel
65159689Snetchildstruct envy24_sample {
66159689Snetchild        volatile u_int32_t buffer;
67159689Snetchild};
68159687Snetchild
69159689Snetchildtypedef struct envy24_sample sample32_t;
70159689Snetchild
71159687Snetchild/* channel registers */
72159687Snetchildstruct sc_chinfo {
73159687Snetchild	struct snd_dbuf		*buffer;
74159687Snetchild	struct pcm_channel	*channel;
75159687Snetchild	struct sc_info		*parent;
76159687Snetchild	int			dir;
77159687Snetchild	unsigned		num; /* hw channel number */
78159687Snetchild
79159687Snetchild	/* channel information */
80159687Snetchild	u_int32_t		format;
81159687Snetchild	u_int32_t		speed;
82159687Snetchild	u_int32_t		blk; /* hw block size(dword) */
83159687Snetchild
84159687Snetchild	/* format conversion structure */
85159687Snetchild	u_int8_t		*data;
86159687Snetchild	unsigned int		size; /* data buffer size(byte) */
87159687Snetchild	int			unit; /* sample size(byte) */
88159687Snetchild	unsigned int		offset; /* samples number offset */
89159687Snetchild	void			(*emldma)(struct sc_chinfo *);
90159687Snetchild
91159687Snetchild	/* flags */
92159687Snetchild	int			run;
93159687Snetchild};
94159687Snetchild
95159687Snetchild/* codec interface entrys */
96159687Snetchildstruct codec_entry {
97159687Snetchild	void *(*create)(device_t dev, void *devinfo, int dir, int num);
98159687Snetchild	void (*destroy)(void *codec);
99159687Snetchild	void (*init)(void *codec);
100159687Snetchild	void (*reinit)(void *codec);
101159687Snetchild	void (*setvolume)(void *codec, int dir, unsigned int left, unsigned int right);
102159687Snetchild	void (*setrate)(void *codec, int which, int rate);
103159687Snetchild};
104159687Snetchild
105159687Snetchild/* system configuration information */
106159687Snetchildstruct cfg_info {
107159687Snetchild	char *name;
108159687Snetchild	u_int16_t subvendor, subdevice;
109159687Snetchild	u_int8_t scfg, acl, i2s, spdif;
110159687Snetchild	u_int8_t gpiomask, gpiostate, gpiodir;
111159689Snetchild	u_int8_t cdti, cclk, cs, cif, type;
112159687Snetchild	u_int8_t free;
113159687Snetchild	struct codec_entry *codec;
114159687Snetchild};
115159687Snetchild
116159687Snetchild/* device private data */
117159687Snetchildstruct sc_info {
118159687Snetchild	device_t	dev;
119166713Sariff	struct mtx	*lock;
120159687Snetchild
121159687Snetchild	/* Control/Status registor */
122159687Snetchild	struct resource *cs;
123159687Snetchild	int		csid;
124159687Snetchild	bus_space_tag_t cst;
125159687Snetchild	bus_space_handle_t csh;
126159687Snetchild	/* DDMA registor */
127159687Snetchild	struct resource *ddma;
128159687Snetchild	int		ddmaid;
129159687Snetchild	bus_space_tag_t ddmat;
130159687Snetchild	bus_space_handle_t ddmah;
131159687Snetchild	/* Consumer Section DMA Channel Registers */
132159687Snetchild	struct resource *ds;
133159687Snetchild	int		dsid;
134159687Snetchild	bus_space_tag_t dst;
135159687Snetchild	bus_space_handle_t dsh;
136159687Snetchild	/* MultiTrack registor */
137159687Snetchild	struct resource *mt;
138159687Snetchild	int		mtid;
139159687Snetchild	bus_space_tag_t mtt;
140159687Snetchild	bus_space_handle_t mth;
141159687Snetchild	/* DMA tag */
142159687Snetchild	bus_dma_tag_t dmat;
143159687Snetchild	/* IRQ resource */
144159687Snetchild	struct resource *irq;
145159687Snetchild	int		irqid;
146159687Snetchild	void		*ih;
147159687Snetchild
148159687Snetchild	/* system configuration data */
149159687Snetchild	struct cfg_info *cfg;
150159687Snetchild
151159687Snetchild	/* ADC/DAC number and info */
152159687Snetchild	int		adcn, dacn;
153159687Snetchild	void		*adc[4], *dac[4];
154159687Snetchild
155159687Snetchild	/* mixer control data */
156159687Snetchild	u_int32_t	src;
157159687Snetchild	u_int8_t	left[ENVY24_CHAN_NUM];
158159687Snetchild	u_int8_t	right[ENVY24_CHAN_NUM];
159159687Snetchild
160159687Snetchild	/* Play/Record DMA fifo */
161159687Snetchild	sample32_t	*pbuf;
162159687Snetchild	sample32_t	*rbuf;
163159687Snetchild	u_int32_t	psize, rsize; /* DMA buffer size(byte) */
164159687Snetchild	u_int16_t	blk[2]; /* transfer check blocksize(dword) */
165159687Snetchild	bus_dmamap_t	pmap, rmap;
166159687Snetchild
167159687Snetchild	/* current status */
168159687Snetchild	u_int32_t	speed;
169159687Snetchild	int		run[2];
170159687Snetchild	u_int16_t	intr[2];
171159687Snetchild	struct pcmchan_caps	caps[2];
172159687Snetchild
173159687Snetchild	/* channel info table */
174159687Snetchild	unsigned	chnum;
175159687Snetchild	struct sc_chinfo chan[11];
176159687Snetchild};
177159687Snetchild
178159687Snetchild/* -------------------------------------------------------------------- */
179159687Snetchild
180159687Snetchild/*
181159687Snetchild * prototypes
182159687Snetchild */
183159687Snetchild
184159687Snetchild/* DMA emulator */
185159687Snetchildstatic void envy24_p8u(struct sc_chinfo *);
186159687Snetchildstatic void envy24_p16sl(struct sc_chinfo *);
187159687Snetchildstatic void envy24_p32sl(struct sc_chinfo *);
188159687Snetchildstatic void envy24_r16sl(struct sc_chinfo *);
189159687Snetchildstatic void envy24_r32sl(struct sc_chinfo *);
190159687Snetchild
191159687Snetchild/* channel interface */
192159687Snetchildstatic void *envy24chan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int);
193159687Snetchildstatic int envy24chan_setformat(kobj_t, void *, u_int32_t);
194193640Sariffstatic u_int32_t envy24chan_setspeed(kobj_t, void *, u_int32_t);
195193640Sariffstatic u_int32_t envy24chan_setblocksize(kobj_t, void *, u_int32_t);
196159687Snetchildstatic int envy24chan_trigger(kobj_t, void *, int);
197193640Sariffstatic u_int32_t envy24chan_getptr(kobj_t, void *);
198159687Snetchildstatic struct pcmchan_caps *envy24chan_getcaps(kobj_t, void *);
199159687Snetchild
200159687Snetchild/* mixer interface */
201159687Snetchildstatic int envy24mixer_init(struct snd_mixer *);
202159687Snetchildstatic int envy24mixer_reinit(struct snd_mixer *);
203159687Snetchildstatic int envy24mixer_uninit(struct snd_mixer *);
204159687Snetchildstatic int envy24mixer_set(struct snd_mixer *, unsigned, unsigned, unsigned);
205159687Snetchildstatic u_int32_t envy24mixer_setrecsrc(struct snd_mixer *, u_int32_t);
206159687Snetchild
207159687Snetchild/* M-Audio Delta series AK4524 access interface */
208159687Snetchildstatic void *envy24_delta_ak4524_create(device_t, void *, int, int);
209159687Snetchildstatic void envy24_delta_ak4524_destroy(void *);
210159687Snetchildstatic void envy24_delta_ak4524_init(void *);
211159687Snetchildstatic void envy24_delta_ak4524_reinit(void *);
212159687Snetchildstatic void envy24_delta_ak4524_setvolume(void *, int, unsigned int, unsigned int);
213159687Snetchild
214159687Snetchild/* -------------------------------------------------------------------- */
215159687Snetchild
216159687Snetchild/*
217159687Snetchild  system constant tables
218159687Snetchild*/
219159687Snetchild
220159687Snetchild/* API -> hardware channel map */
221159687Snetchildstatic unsigned envy24_chanmap[ENVY24_CHAN_NUM] = {
222159687Snetchild	ENVY24_CHAN_PLAY_SPDIF, /* 0 */
223159687Snetchild	ENVY24_CHAN_PLAY_DAC1,  /* 1 */
224159687Snetchild	ENVY24_CHAN_PLAY_DAC2,  /* 2 */
225159687Snetchild	ENVY24_CHAN_PLAY_DAC3,  /* 3 */
226159687Snetchild	ENVY24_CHAN_PLAY_DAC4,  /* 4 */
227159687Snetchild	ENVY24_CHAN_REC_MIX,    /* 5 */
228159687Snetchild	ENVY24_CHAN_REC_SPDIF,  /* 6 */
229159687Snetchild	ENVY24_CHAN_REC_ADC1,   /* 7 */
230159687Snetchild	ENVY24_CHAN_REC_ADC2,   /* 8 */
231159687Snetchild	ENVY24_CHAN_REC_ADC3,   /* 9 */
232159687Snetchild	ENVY24_CHAN_REC_ADC4,   /* 10 */
233159687Snetchild};
234159687Snetchild
235159687Snetchild/* mixer -> API channel map. see above */
236159687Snetchildstatic int envy24_mixmap[] = {
237159687Snetchild	-1, /* Master output level. It is depend on codec support */
238159687Snetchild	-1, /* Treble level of all output channels */
239159687Snetchild	-1, /* Bass level of all output channels */
240159687Snetchild	-1, /* Volume of synthesier input */
241159687Snetchild	0,  /* Output level for the audio device */
242159687Snetchild	-1, /* Output level for the PC speaker */
243159687Snetchild	7,  /* line in jack */
244159687Snetchild	-1, /* microphone jack */
245159687Snetchild	-1, /* CD audio input */
246159687Snetchild	-1, /* Recording monitor */
247159687Snetchild	1,  /* alternative codec */
248159687Snetchild	-1, /* global recording level */
249159687Snetchild	-1, /* Input gain */
250159687Snetchild	-1, /* Output gain */
251159687Snetchild	8,  /* Input source 1 */
252159687Snetchild	9,  /* Input source 2 */
253159687Snetchild	10, /* Input source 3 */
254159687Snetchild	6,  /* Digital (input) 1 */
255159687Snetchild	-1, /* Digital (input) 2 */
256159687Snetchild	-1, /* Digital (input) 3 */
257159687Snetchild	-1, /* Phone input */
258159687Snetchild	-1, /* Phone output */
259159687Snetchild	-1, /* Video/TV (audio) in */
260159687Snetchild	-1, /* Radio in */
261159687Snetchild	-1, /* Monitor volume */
262159687Snetchild};
263159687Snetchild
264159687Snetchild/* variable rate audio */
265159687Snetchildstatic u_int32_t envy24_speed[] = {
266159687Snetchild    96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000,
267159687Snetchild    12000, 11025, 9600, 8000, 0
268159687Snetchild};
269159687Snetchild
270159687Snetchild/* known boards configuration */
271159687Snetchildstatic struct codec_entry delta_codec = {
272159687Snetchild	envy24_delta_ak4524_create,
273159687Snetchild	envy24_delta_ak4524_destroy,
274159687Snetchild	envy24_delta_ak4524_init,
275159687Snetchild	envy24_delta_ak4524_reinit,
276159687Snetchild	envy24_delta_ak4524_setvolume,
277159687Snetchild	NULL, /* setrate */
278159687Snetchild};
279159687Snetchild
280159687Snetchildstatic struct cfg_info cfg_table[] = {
281159687Snetchild	{
282159689Snetchild		"Envy24 audio (M Audio Delta Dio 2496)",
283159687Snetchild		0x1412, 0xd631,
284159687Snetchild		0x10, 0x80, 0xf0, 0x03,
285188480Snetchild		0x02, 0xc0, 0xfd,
286159689Snetchild		0x10, 0x20, 0x40, 0x00, 0x00,
287159689Snetchild		0x00,
288159687Snetchild		&delta_codec,
289159687Snetchild	},
290159687Snetchild	{
291159689Snetchild		"Envy24 audio (Terratec DMX 6fire)",
292159689Snetchild		0x153b, 0x1138,
293159689Snetchild		0x2f, 0x80, 0xf0, 0x03,
294159689Snetchild		0xc0, 0xff, 0x7f,
295159689Snetchild		0x10, 0x20, 0x01, 0x01, 0x00,
296159689Snetchild		0x00,
297159689Snetchild 		&delta_codec,
298159689Snetchild 	},
299159689Snetchild	{
300159689Snetchild		"Envy24 audio (M Audio Audiophile 2496)",
301159689Snetchild		0x1412, 0xd634,
302159689Snetchild		0x10, 0x80, 0x72, 0x03,
303159689Snetchild		0x04, 0xfe, 0xfb,
304159689Snetchild		0x08, 0x02, 0x20, 0x00, 0x01,
305159689Snetchild		0x00,
306159689Snetchild 		&delta_codec,
307159689Snetchild 	},
308188480Snetchild        {
309188480Snetchild                "Envy24 audio (M Audio Delta 66)",
310188480Snetchild                0x1412, 0xd632,
311188480Snetchild                0x15, 0x80, 0xf0, 0x03,
312188480Snetchild                0x02, 0xc0, 0xfd,
313188480Snetchild                0x10, 0x20, 0x40, 0x00, 0x00,
314188480Snetchild                0x00,
315188480Snetchild                &delta_codec,
316188480Snetchild        },
317188480Snetchild        {
318188480Snetchild                "Envy24 audio (M Audio Delta 44)",
319188480Snetchild                0x1412, 0xd633,
320188480Snetchild                0x15, 0x80, 0xf0, 0x00,
321188480Snetchild                0x02, 0xc0, 0xfd,
322188480Snetchild                0x10, 0x20, 0x40, 0x00, 0x00,
323188480Snetchild                0x00,
324188480Snetchild                &delta_codec,
325188480Snetchild        },
326188480Snetchild        {
327188480Snetchild                "Envy24 audio (M Audio Delta 1010)",
328188480Snetchild                0x1412, 0xd630,
329188480Snetchild                0x1f, 0x80, 0xf0, 0x03,
330188480Snetchild                0x22, 0xd0, 0xdd,
331188480Snetchild                0x10, 0x20, 0x40, 0x00, 0x00,
332188480Snetchild                0x00,
333188480Snetchild                &delta_codec,
334188480Snetchild        },
335188480Snetchild        {
336188480Snetchild                "Envy24 audio (M Audio Delta 1010LT)",
337188480Snetchild                0x1412, 0xd63b,
338188480Snetchild                0x1f, 0x80, 0x72, 0x03,
339188480Snetchild                0x04, 0x7e, 0xfb,
340188480Snetchild                0x08, 0x02, 0x70, 0x00, 0x00,
341188480Snetchild                0x00,
342188480Snetchild                &delta_codec,
343188480Snetchild        },
344188480Snetchild        {
345188480Snetchild                "Envy24 audio (Terratec EWX 2496)",
346188480Snetchild                0x153b, 0x1130,
347188480Snetchild                0x10, 0x80, 0xf0, 0x03,
348188480Snetchild                0xc0, 0x3f, 0x3f,
349188480Snetchild                0x10, 0x20, 0x01, 0x01, 0x00,
350188480Snetchild                0x00,
351188480Snetchild                &delta_codec,
352188480Snetchild        },
353159689Snetchild	{
354159689Snetchild		"Envy24 audio (Generic)",
355159687Snetchild		0, 0,
356159687Snetchild		0x0f, 0x00, 0x01, 0x03,
357159687Snetchild		0xff, 0x00, 0x00,
358159689Snetchild		0x10, 0x20, 0x40, 0x00, 0x00,
359159689Snetchild		0x00,
360159687Snetchild		&delta_codec, /* default codec routines */
361159687Snetchild	}
362159687Snetchild};
363159687Snetchild
364159687Snetchildstatic u_int32_t envy24_recfmt[] = {
365193640Sariff	SND_FORMAT(AFMT_S16_LE, 2, 0),
366193640Sariff	SND_FORMAT(AFMT_S32_LE, 2, 0),
367159687Snetchild	0
368159687Snetchild};
369159687Snetchildstatic struct pcmchan_caps envy24_reccaps = {8000, 96000, envy24_recfmt, 0};
370159687Snetchild
371159687Snetchildstatic u_int32_t envy24_playfmt[] = {
372193640Sariff	SND_FORMAT(AFMT_U8, 2, 0),
373193640Sariff	SND_FORMAT(AFMT_S16_LE, 2, 0),
374193640Sariff	SND_FORMAT(AFMT_S32_LE, 2, 0),
375159687Snetchild	0
376159687Snetchild};
377159687Snetchild
378159687Snetchildstatic struct pcmchan_caps envy24_playcaps = {8000, 96000, envy24_playfmt, 0};
379159687Snetchild
380159687Snetchildstruct envy24_emldma {
381159687Snetchild	u_int32_t	format;
382159687Snetchild	void		(*emldma)(struct sc_chinfo *);
383159687Snetchild	int		unit;
384159687Snetchild};
385159687Snetchild
386159687Snetchildstatic struct envy24_emldma envy24_pemltab[] = {
387193640Sariff	{SND_FORMAT(AFMT_U8, 2, 0), envy24_p8u, 2},
388193640Sariff	{SND_FORMAT(AFMT_S16_LE, 2, 0), envy24_p16sl, 4},
389193640Sariff	{SND_FORMAT(AFMT_S32_LE, 2, 0), envy24_p32sl, 8},
390159687Snetchild	{0, NULL, 0}
391159687Snetchild};
392159687Snetchild
393159687Snetchildstatic struct envy24_emldma envy24_remltab[] = {
394193640Sariff	{SND_FORMAT(AFMT_S16_LE, 2, 0), envy24_r16sl, 4},
395193640Sariff	{SND_FORMAT(AFMT_S32_LE, 2, 0), envy24_r32sl, 8},
396159687Snetchild	{0, NULL, 0}
397159687Snetchild};
398159687Snetchild
399159687Snetchild/* -------------------------------------------------------------------- */
400159687Snetchild
401159687Snetchild/* common routines */
402159687Snetchildstatic u_int32_t
403159687Snetchildenvy24_rdcs(struct sc_info *sc, int regno, int size)
404159687Snetchild{
405159687Snetchild	switch (size) {
406159687Snetchild	case 1:
407159687Snetchild		return bus_space_read_1(sc->cst, sc->csh, regno);
408159687Snetchild	case 2:
409159687Snetchild		return bus_space_read_2(sc->cst, sc->csh, regno);
410159687Snetchild	case 4:
411159687Snetchild		return bus_space_read_4(sc->cst, sc->csh, regno);
412159687Snetchild	default:
413159687Snetchild		return 0xffffffff;
414159687Snetchild	}
415159687Snetchild}
416159687Snetchild
417159687Snetchildstatic void
418159687Snetchildenvy24_wrcs(struct sc_info *sc, int regno, u_int32_t data, int size)
419159687Snetchild{
420159687Snetchild	switch (size) {
421159687Snetchild	case 1:
422159687Snetchild		bus_space_write_1(sc->cst, sc->csh, regno, data);
423159687Snetchild		break;
424159687Snetchild	case 2:
425159687Snetchild		bus_space_write_2(sc->cst, sc->csh, regno, data);
426159687Snetchild		break;
427159687Snetchild	case 4:
428159687Snetchild		bus_space_write_4(sc->cst, sc->csh, regno, data);
429159687Snetchild		break;
430159687Snetchild	}
431159687Snetchild}
432159687Snetchild
433159687Snetchildstatic u_int32_t
434159687Snetchildenvy24_rdmt(struct sc_info *sc, int regno, int size)
435159687Snetchild{
436159687Snetchild	switch (size) {
437159687Snetchild	case 1:
438159687Snetchild		return bus_space_read_1(sc->mtt, sc->mth, regno);
439159687Snetchild	case 2:
440159687Snetchild		return bus_space_read_2(sc->mtt, sc->mth, regno);
441159687Snetchild	case 4:
442159687Snetchild		return bus_space_read_4(sc->mtt, sc->mth, regno);
443159687Snetchild	default:
444159687Snetchild		return 0xffffffff;
445159687Snetchild	}
446159687Snetchild}
447159687Snetchild
448159687Snetchildstatic void
449159687Snetchildenvy24_wrmt(struct sc_info *sc, int regno, u_int32_t data, int size)
450159687Snetchild{
451159687Snetchild	switch (size) {
452159687Snetchild	case 1:
453159687Snetchild		bus_space_write_1(sc->mtt, sc->mth, regno, data);
454159687Snetchild		break;
455159687Snetchild	case 2:
456159687Snetchild		bus_space_write_2(sc->mtt, sc->mth, regno, data);
457159687Snetchild		break;
458159687Snetchild	case 4:
459159687Snetchild		bus_space_write_4(sc->mtt, sc->mth, regno, data);
460159687Snetchild		break;
461159687Snetchild	}
462159687Snetchild}
463159687Snetchild
464159687Snetchildstatic u_int32_t
465159687Snetchildenvy24_rdci(struct sc_info *sc, int regno)
466159687Snetchild{
467159687Snetchild	envy24_wrcs(sc, ENVY24_CCS_INDEX, regno, 1);
468159687Snetchild	return envy24_rdcs(sc, ENVY24_CCS_DATA, 1);
469159687Snetchild}
470159687Snetchild
471159687Snetchildstatic void
472159687Snetchildenvy24_wrci(struct sc_info *sc, int regno, u_int32_t data)
473159687Snetchild{
474159687Snetchild	envy24_wrcs(sc, ENVY24_CCS_INDEX, regno, 1);
475159687Snetchild	envy24_wrcs(sc, ENVY24_CCS_DATA, data, 1);
476159687Snetchild}
477159687Snetchild
478159687Snetchild/* -------------------------------------------------------------------- */
479159687Snetchild
480159687Snetchild/* I2C port/E2PROM access routines */
481159687Snetchild
482159687Snetchildstatic int
483159687Snetchildenvy24_rdi2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr)
484159687Snetchild{
485159687Snetchild	u_int32_t data;
486159687Snetchild	int i;
487159687Snetchild
488159687Snetchild#if(0)
489159687Snetchild	device_printf(sc->dev, "envy24_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
490159687Snetchild#endif
491159687Snetchild	for (i = 0; i < ENVY24_TIMEOUT; i++) {
492159687Snetchild		data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
493159687Snetchild		if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0)
494159687Snetchild			break;
495159687Snetchild		DELAY(32); /* 31.25kHz */
496159687Snetchild	}
497159687Snetchild	if (i == ENVY24_TIMEOUT) {
498159687Snetchild		return -1;
499159687Snetchild	}
500159687Snetchild	envy24_wrcs(sc, ENVY24_CCS_I2CADDR, addr, 1);
501159687Snetchild	envy24_wrcs(sc, ENVY24_CCS_I2CDEV,
502159687Snetchild	    (dev & ENVY24_CCS_I2CDEV_ADDR) | ENVY24_CCS_I2CDEV_RD, 1);
503159687Snetchild	for (i = 0; i < ENVY24_TIMEOUT; i++) {
504159687Snetchild		data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
505159687Snetchild		if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0)
506159687Snetchild			break;
507159687Snetchild		DELAY(32); /* 31.25kHz */
508159687Snetchild	}
509159687Snetchild	if (i == ENVY24_TIMEOUT) {
510159687Snetchild		return -1;
511159687Snetchild	}
512159687Snetchild	data = envy24_rdcs(sc, ENVY24_CCS_I2CDATA, 1);
513159687Snetchild
514159687Snetchild#if(0)
515159687Snetchild	device_printf(sc->dev, "envy24_rdi2c(): return 0x%x\n", data);
516159687Snetchild#endif
517159687Snetchild	return (int)data;
518159687Snetchild}
519159687Snetchild
520159689Snetchild#if 0
521159687Snetchildstatic int
522159687Snetchildenvy24_wri2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr, u_int32_t data)
523159687Snetchild{
524159687Snetchild	u_int32_t tmp;
525159687Snetchild	int i;
526159687Snetchild
527159687Snetchild#if(0)
528159687Snetchild	device_printf(sc->dev, "envy24_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
529159687Snetchild#endif
530159687Snetchild	for (i = 0; i < ENVY24_TIMEOUT; i++) {
531159687Snetchild		tmp = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
532159687Snetchild		if ((tmp & ENVY24_CCS_I2CSTAT_BSY) == 0)
533159687Snetchild			break;
534159687Snetchild		DELAY(32); /* 31.25kHz */
535159687Snetchild	}
536159687Snetchild	if (i == ENVY24_TIMEOUT) {
537159687Snetchild		return -1;
538159687Snetchild	}
539159687Snetchild	envy24_wrcs(sc, ENVY24_CCS_I2CADDR, addr, 1);
540159687Snetchild	envy24_wrcs(sc, ENVY24_CCS_I2CDATA, data, 1);
541159687Snetchild	envy24_wrcs(sc, ENVY24_CCS_I2CDEV,
542159687Snetchild	    (dev & ENVY24_CCS_I2CDEV_ADDR) | ENVY24_CCS_I2CDEV_WR, 1);
543159687Snetchild	for (i = 0; i < ENVY24_TIMEOUT; i++) {
544159687Snetchild		data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
545159687Snetchild		if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0)
546159687Snetchild			break;
547159687Snetchild		DELAY(32); /* 31.25kHz */
548159687Snetchild	}
549159687Snetchild	if (i == ENVY24_TIMEOUT) {
550159687Snetchild		return -1;
551159687Snetchild	}
552159687Snetchild
553159687Snetchild	return 0;
554159687Snetchild}
555159689Snetchild#endif
556159687Snetchild
557159687Snetchildstatic int
558159687Snetchildenvy24_rdrom(struct sc_info *sc, u_int32_t addr)
559159687Snetchild{
560159687Snetchild	u_int32_t data;
561159687Snetchild
562159687Snetchild#if(0)
563159687Snetchild	device_printf(sc->dev, "envy24_rdrom(sc, 0x%02x)\n", addr);
564159687Snetchild#endif
565159687Snetchild	data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
566159687Snetchild	if ((data & ENVY24_CCS_I2CSTAT_ROM) == 0) {
567159687Snetchild#if(0)
568159687Snetchild		device_printf(sc->dev, "envy24_rdrom(): E2PROM not presented\n");
569159687Snetchild#endif
570159687Snetchild		return -1;
571159687Snetchild	}
572159687Snetchild
573159687Snetchild	return envy24_rdi2c(sc, ENVY24_CCS_I2CDEV_ROM, addr);
574159687Snetchild}
575159687Snetchild
576159687Snetchildstatic struct cfg_info *
577159687Snetchildenvy24_rom2cfg(struct sc_info *sc)
578159687Snetchild{
579159687Snetchild	struct cfg_info *buff;
580159687Snetchild	int size;
581159687Snetchild	int i;
582159687Snetchild
583159687Snetchild#if(0)
584159687Snetchild	device_printf(sc->dev, "envy24_rom2cfg(sc)\n");
585159687Snetchild#endif
586159687Snetchild	size = envy24_rdrom(sc, ENVY24_E2PROM_SIZE);
587159687Snetchild	if (size < ENVY24_E2PROM_GPIODIR + 1) {
588159687Snetchild#if(0)
589159687Snetchild		device_printf(sc->dev, "envy24_rom2cfg(): ENVY24_E2PROM_SIZE-->%d\n", size);
590159687Snetchild#endif
591159687Snetchild		return NULL;
592159687Snetchild	}
593159687Snetchild	buff = malloc(sizeof(*buff), M_ENVY24, M_NOWAIT);
594159687Snetchild	if (buff == NULL) {
595159687Snetchild#if(0)
596159687Snetchild		device_printf(sc->dev, "envy24_rom2cfg(): malloc()\n");
597159687Snetchild#endif
598159687Snetchild		return NULL;
599159687Snetchild	}
600159687Snetchild	buff->free = 1;
601159687Snetchild
602159687Snetchild	buff->subvendor = envy24_rdrom(sc, ENVY24_E2PROM_SUBVENDOR) << 8;
603159687Snetchild	buff->subvendor += envy24_rdrom(sc, ENVY24_E2PROM_SUBVENDOR + 1);
604159687Snetchild	buff->subdevice = envy24_rdrom(sc, ENVY24_E2PROM_SUBDEVICE) << 8;
605159687Snetchild	buff->subdevice += envy24_rdrom(sc, ENVY24_E2PROM_SUBDEVICE + 1);
606159687Snetchild	buff->scfg = envy24_rdrom(sc, ENVY24_E2PROM_SCFG);
607159687Snetchild	buff->acl = envy24_rdrom(sc, ENVY24_E2PROM_ACL);
608159687Snetchild	buff->i2s = envy24_rdrom(sc, ENVY24_E2PROM_I2S);
609159687Snetchild	buff->spdif = envy24_rdrom(sc, ENVY24_E2PROM_SPDIF);
610159687Snetchild	buff->gpiomask = envy24_rdrom(sc, ENVY24_E2PROM_GPIOMASK);
611159687Snetchild	buff->gpiostate = envy24_rdrom(sc, ENVY24_E2PROM_GPIOSTATE);
612159687Snetchild	buff->gpiodir = envy24_rdrom(sc, ENVY24_E2PROM_GPIODIR);
613159687Snetchild
614159687Snetchild	for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++)
615159687Snetchild		if (cfg_table[i].subvendor == buff->subvendor &&
616159687Snetchild		    cfg_table[i].subdevice == buff->subdevice)
617159687Snetchild			break;
618159687Snetchild	buff->name = cfg_table[i].name;
619159687Snetchild	buff->codec = cfg_table[i].codec;
620159687Snetchild
621159687Snetchild	return buff;
622159687Snetchild}
623159687Snetchild
624159687Snetchildstatic void
625159687Snetchildenvy24_cfgfree(struct cfg_info *cfg) {
626159687Snetchild	if (cfg == NULL)
627159687Snetchild		return;
628159687Snetchild	if (cfg->free)
629159687Snetchild		free(cfg, M_ENVY24);
630159687Snetchild	return;
631159687Snetchild}
632159687Snetchild
633159687Snetchild/* -------------------------------------------------------------------- */
634159687Snetchild
635159687Snetchild/* AC'97 codec access routines */
636159687Snetchild
637159689Snetchild#if 0
638159687Snetchildstatic int
639159687Snetchildenvy24_coldcd(struct sc_info *sc)
640159687Snetchild{
641159687Snetchild	u_int32_t data;
642159687Snetchild	int i;
643159687Snetchild
644159687Snetchild#if(0)
645159687Snetchild	device_printf(sc->dev, "envy24_coldcd()\n");
646159687Snetchild#endif
647159687Snetchild	envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_CLD, 1);
648159687Snetchild	DELAY(10);
649159687Snetchild	envy24_wrmt(sc, ENVY24_MT_AC97CMD, 0, 1);
650159687Snetchild	DELAY(1000);
651159687Snetchild	for (i = 0; i < ENVY24_TIMEOUT; i++) {
652159687Snetchild		data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
653159687Snetchild		if (data & ENVY24_MT_AC97CMD_RDY) {
654159687Snetchild			return 0;
655159687Snetchild		}
656159687Snetchild	}
657159687Snetchild
658159687Snetchild	return -1;
659159687Snetchild}
660159689Snetchild#endif
661159687Snetchild
662159687Snetchildstatic int
663159687Snetchildenvy24_slavecd(struct sc_info *sc)
664159687Snetchild{
665159687Snetchild	u_int32_t data;
666159687Snetchild	int i;
667159687Snetchild
668159687Snetchild#if(0)
669159687Snetchild	device_printf(sc->dev, "envy24_slavecd()\n");
670159687Snetchild#endif
671159687Snetchild	envy24_wrmt(sc, ENVY24_MT_AC97CMD,
672159687Snetchild	    ENVY24_MT_AC97CMD_CLD | ENVY24_MT_AC97CMD_WRM, 1);
673159687Snetchild	DELAY(10);
674159687Snetchild	envy24_wrmt(sc, ENVY24_MT_AC97CMD, 0, 1);
675159687Snetchild	DELAY(1000);
676159687Snetchild	for (i = 0; i < ENVY24_TIMEOUT; i++) {
677159687Snetchild		data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
678159687Snetchild		if (data & ENVY24_MT_AC97CMD_RDY) {
679159687Snetchild			return 0;
680159687Snetchild		}
681159687Snetchild	}
682159687Snetchild
683159687Snetchild	return -1;
684159687Snetchild}
685159687Snetchild
686159689Snetchild#if 0
687159687Snetchildstatic int
688159687Snetchildenvy24_rdcd(kobj_t obj, void *devinfo, int regno)
689159687Snetchild{
690159687Snetchild	struct sc_info *sc = (struct sc_info *)devinfo;
691159687Snetchild	u_int32_t data;
692159687Snetchild	int i;
693159687Snetchild
694159687Snetchild#if(0)
695159687Snetchild	device_printf(sc->dev, "envy24_rdcd(obj, sc, 0x%02x)\n", regno);
696159687Snetchild#endif
697159687Snetchild	envy24_wrmt(sc, ENVY24_MT_AC97IDX, (u_int32_t)regno, 1);
698159687Snetchild	envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_RD, 1);
699159687Snetchild	for (i = 0; i < ENVY24_TIMEOUT; i++) {
700159687Snetchild		data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
701159687Snetchild		if ((data & ENVY24_MT_AC97CMD_RD) == 0)
702159687Snetchild			break;
703159687Snetchild	}
704159687Snetchild	data = envy24_rdmt(sc, ENVY24_MT_AC97DLO, 2);
705159687Snetchild
706159687Snetchild#if(0)
707159687Snetchild	device_printf(sc->dev, "envy24_rdcd(): return 0x%x\n", data);
708159687Snetchild#endif
709159687Snetchild	return (int)data;
710159687Snetchild}
711159687Snetchild
712159687Snetchildstatic int
713159687Snetchildenvy24_wrcd(kobj_t obj, void *devinfo, int regno, u_int16_t data)
714159687Snetchild{
715159687Snetchild	struct sc_info *sc = (struct sc_info *)devinfo;
716159687Snetchild	u_int32_t cmd;
717159687Snetchild	int i;
718159687Snetchild
719159687Snetchild#if(0)
720159687Snetchild	device_printf(sc->dev, "envy24_wrcd(obj, sc, 0x%02x, 0x%04x)\n", regno, data);
721159687Snetchild#endif
722159687Snetchild	envy24_wrmt(sc, ENVY24_MT_AC97IDX, (u_int32_t)regno, 1);
723159687Snetchild	envy24_wrmt(sc, ENVY24_MT_AC97DLO, (u_int32_t)data, 2);
724159687Snetchild	envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_WR, 1);
725159687Snetchild	for (i = 0; i < ENVY24_TIMEOUT; i++) {
726159687Snetchild		cmd = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
727159687Snetchild		if ((cmd & ENVY24_MT_AC97CMD_WR) == 0)
728159687Snetchild			break;
729159687Snetchild	}
730159687Snetchild
731159687Snetchild	return 0;
732159687Snetchild}
733159687Snetchild
734159687Snetchildstatic kobj_method_t envy24_ac97_methods[] = {
735159687Snetchild	KOBJMETHOD(ac97_read,	envy24_rdcd),
736159687Snetchild	KOBJMETHOD(ac97_write,	envy24_wrcd),
737193640Sariff	KOBJMETHOD_END
738159687Snetchild};
739159687SnetchildAC97_DECLARE(envy24_ac97);
740159689Snetchild#endif
741159687Snetchild
742159687Snetchild/* -------------------------------------------------------------------- */
743159687Snetchild
744159687Snetchild/* GPIO access routines */
745159687Snetchild
746159687Snetchildstatic u_int32_t
747159687Snetchildenvy24_gpiord(struct sc_info *sc)
748159687Snetchild{
749159687Snetchild	return envy24_rdci(sc, ENVY24_CCI_GPIODAT);
750159687Snetchild}
751159687Snetchild
752159687Snetchildstatic void
753159687Snetchildenvy24_gpiowr(struct sc_info *sc, u_int32_t data)
754159687Snetchild{
755159687Snetchild#if(0)
756159687Snetchild	device_printf(sc->dev, "envy24_gpiowr(sc, 0x%02x)\n", data & 0xff);
757159687Snetchild	return;
758159687Snetchild#endif
759159687Snetchild	envy24_wrci(sc, ENVY24_CCI_GPIODAT, data);
760159687Snetchild	return;
761159687Snetchild}
762159687Snetchild
763159689Snetchild#if 0
764159687Snetchildstatic u_int32_t
765159687Snetchildenvy24_gpiogetmask(struct sc_info *sc)
766159687Snetchild{
767159687Snetchild	return envy24_rdci(sc, ENVY24_CCI_GPIOMASK);
768159687Snetchild}
769159689Snetchild#endif
770159687Snetchild
771159687Snetchildstatic void
772159687Snetchildenvy24_gpiosetmask(struct sc_info *sc, u_int32_t mask)
773159687Snetchild{
774159687Snetchild	envy24_wrci(sc, ENVY24_CCI_GPIOMASK, mask);
775159687Snetchild	return;
776159687Snetchild}
777159687Snetchild
778159689Snetchild#if 0
779159687Snetchildstatic u_int32_t
780159687Snetchildenvy24_gpiogetdir(struct sc_info *sc)
781159687Snetchild{
782159687Snetchild	return envy24_rdci(sc, ENVY24_CCI_GPIOCTL);
783159687Snetchild}
784159689Snetchild#endif
785159687Snetchild
786159687Snetchildstatic void
787159687Snetchildenvy24_gpiosetdir(struct sc_info *sc, u_int32_t dir)
788159687Snetchild{
789159687Snetchild	envy24_wrci(sc, ENVY24_CCI_GPIOCTL, dir);
790159687Snetchild	return;
791159687Snetchild}
792159687Snetchild
793159687Snetchild/* -------------------------------------------------------------------- */
794159687Snetchild
795170031Sjoel/* Envy24 I2C through GPIO bit-banging */
796159687Snetchild
797159687Snetchildstruct envy24_delta_ak4524_codec {
798162876Snetchild	struct spicds_info *info;
799159687Snetchild	struct sc_info *parent;
800159687Snetchild	int dir;
801159687Snetchild	int num;
802159687Snetchild	int cs, cclk, cdti;
803159687Snetchild};
804159687Snetchild
805159687Snetchildstatic void
806170031Sjoelenvy24_gpio_i2c_ctl(void *codec, unsigned int scl, unsigned int sda)
807170031Sjoel{
808170031Sjoel        u_int32_t data = 0;
809170031Sjoel        struct envy24_delta_ak4524_codec *ptr = codec;
810170031Sjoel#if(0)
811170031Sjoel        device_printf(ptr->parent->dev, "--> %d, %d\n", scl, sda);
812170031Sjoel#endif
813170031Sjoel        data = envy24_gpiord(ptr->parent);
814170031Sjoel        data &= ~(SDA_GPIO | SCL_GPIO);
815170031Sjoel        if (scl) data += SCL_GPIO;
816170031Sjoel        if (sda) data += SDA_GPIO;
817170031Sjoel        envy24_gpiowr(ptr->parent, data);
818170031Sjoel        return;
819170031Sjoel}
820170031Sjoel
821170031Sjoelstatic void
822170031Sjoeli2c_wrbit(void *codec, void (*ctrl)(void*, unsigned int, unsigned int), int bit)
823170031Sjoel{
824170031Sjoel        struct envy24_delta_ak4524_codec *ptr = codec;
825170031Sjoel        unsigned int sda;
826170031Sjoel
827170031Sjoel        if (bit)
828170031Sjoel                sda = 1;
829170031Sjoel        else
830170031Sjoel                sda = 0;
831170031Sjoel
832170031Sjoel        ctrl(ptr, 0, sda);
833170031Sjoel        DELAY(I2C_DELAY);
834170031Sjoel        ctrl(ptr, 1, sda);
835170031Sjoel        DELAY(I2C_DELAY);
836170031Sjoel        ctrl(ptr, 0, sda);
837170031Sjoel        DELAY(I2C_DELAY);
838170031Sjoel}
839170031Sjoel
840170031Sjoelstatic void
841170031Sjoeli2c_start(void *codec, void (*ctrl)(void*, unsigned int, unsigned int))
842170031Sjoel{
843170031Sjoel        struct envy24_delta_ak4524_codec *ptr = codec;
844170031Sjoel
845170031Sjoel        ctrl(ptr, 1, 1);
846170031Sjoel        DELAY(I2C_DELAY);
847170031Sjoel        ctrl(ptr, 1, 0);
848170031Sjoel        DELAY(I2C_DELAY);
849170031Sjoel        ctrl(ptr, 0, 0);
850170031Sjoel        DELAY(I2C_DELAY);
851170031Sjoel}
852170031Sjoel
853170031Sjoelstatic void
854170031Sjoeli2c_stop(void *codec, void (*ctrl)(void*, unsigned int, unsigned int))
855170031Sjoel{
856170031Sjoel        struct envy24_delta_ak4524_codec *ptr = codec;
857170031Sjoel
858170031Sjoel        ctrl(ptr, 0, 0);
859170031Sjoel        DELAY(I2C_DELAY);
860170031Sjoel        ctrl(ptr, 1, 0);
861170031Sjoel        DELAY(I2C_DELAY);
862170031Sjoel        ctrl(ptr, 1, 1);
863170031Sjoel        DELAY(I2C_DELAY);
864170031Sjoel}
865170031Sjoel
866170031Sjoelstatic void
867170031Sjoeli2c_ack(void *codec, void (*ctrl)(void*, unsigned int, unsigned int))
868170031Sjoel{
869170031Sjoel        struct envy24_delta_ak4524_codec *ptr = codec;
870170031Sjoel
871170031Sjoel        ctrl(ptr, 0, 1);
872170031Sjoel        DELAY(I2C_DELAY);
873170031Sjoel        ctrl(ptr, 1, 1);
874170031Sjoel        DELAY(I2C_DELAY);
875170031Sjoel        /* dummy, need routine to change gpio direction */
876170031Sjoel        ctrl(ptr, 0, 1);
877170031Sjoel        DELAY(I2C_DELAY);
878170031Sjoel}
879170031Sjoel
880170031Sjoelstatic void
881170031Sjoeli2c_wr(void *codec,  void (*ctrl)(void*, unsigned int, unsigned int), u_int32_t dev, int reg, u_int8_t val)
882170031Sjoel{
883170031Sjoel        struct envy24_delta_ak4524_codec *ptr = codec;
884170031Sjoel        int mask;
885170031Sjoel
886170031Sjoel        i2c_start(ptr, ctrl);
887170031Sjoel
888170031Sjoel        for (mask = 0x80; mask != 0; mask >>= 1)
889170031Sjoel                i2c_wrbit(ptr, ctrl, dev & mask);
890170031Sjoel        i2c_ack(ptr, ctrl);
891170031Sjoel
892170031Sjoel        if (reg != 0xff) {
893170031Sjoel        for (mask = 0x80; mask != 0; mask >>= 1)
894170031Sjoel                i2c_wrbit(ptr, ctrl, reg & mask);
895170031Sjoel        i2c_ack(ptr, ctrl);
896170031Sjoel        }
897170031Sjoel
898170031Sjoel        for (mask = 0x80; mask != 0; mask >>= 1)
899170031Sjoel                i2c_wrbit(ptr, ctrl, val & mask);
900170031Sjoel        i2c_ack(ptr, ctrl);
901170031Sjoel
902170031Sjoel        i2c_stop(ptr, ctrl);
903170031Sjoel}
904170031Sjoel
905170031Sjoel/* -------------------------------------------------------------------- */
906170031Sjoel
907170031Sjoel/* M-Audio Delta series AK4524 access interface routine */
908170031Sjoel
909170031Sjoelstatic void
910159687Snetchildenvy24_delta_ak4524_ctl(void *codec, unsigned int cs, unsigned int cclk, unsigned int cdti)
911159687Snetchild{
912159687Snetchild	u_int32_t data = 0;
913159687Snetchild	struct envy24_delta_ak4524_codec *ptr = codec;
914159687Snetchild
915159687Snetchild#if(0)
916159687Snetchild	device_printf(ptr->parent->dev, "--> %d, %d, %d\n", cs, cclk, cdti);
917159687Snetchild#endif
918159687Snetchild	data = envy24_gpiord(ptr->parent);
919159687Snetchild	data &= ~(ptr->cs | ptr->cclk | ptr->cdti);
920159687Snetchild	if (cs) data += ptr->cs;
921159687Snetchild	if (cclk) data += ptr->cclk;
922159687Snetchild	if (cdti) data += ptr->cdti;
923159687Snetchild	envy24_gpiowr(ptr->parent, data);
924159687Snetchild	return;
925159687Snetchild}
926159687Snetchild
927159687Snetchildstatic void *
928159687Snetchildenvy24_delta_ak4524_create(device_t dev, void *info, int dir, int num)
929159687Snetchild{
930159687Snetchild	struct sc_info *sc = info;
931159687Snetchild	struct envy24_delta_ak4524_codec *buff = NULL;
932159687Snetchild
933159687Snetchild#if(0)
934159687Snetchild	device_printf(sc->dev, "envy24_delta_ak4524_create(dev, sc, %d, %d)\n", dir, num);
935159687Snetchild#endif
936159687Snetchild
937159687Snetchild	buff = malloc(sizeof(*buff), M_ENVY24, M_NOWAIT);
938159687Snetchild	if (buff == NULL)
939159687Snetchild		return NULL;
940159687Snetchild
941160796Snetchild	if (dir == PCMDIR_REC && sc->adc[num] != NULL)
942159687Snetchild		buff->info = ((struct envy24_delta_ak4524_codec *)sc->adc[num])->info;
943160796Snetchild	else if (dir == PCMDIR_PLAY && sc->dac[num] != NULL)
944159687Snetchild		buff->info = ((struct envy24_delta_ak4524_codec *)sc->dac[num])->info;
945159687Snetchild	else
946162876Snetchild		buff->info = spicds_create(dev, buff, num, envy24_delta_ak4524_ctl);
947159687Snetchild	if (buff->info == NULL) {
948159687Snetchild		free(buff, M_ENVY24);
949159687Snetchild		return NULL;
950159687Snetchild	}
951159687Snetchild
952159687Snetchild	buff->parent = sc;
953159687Snetchild	buff->dir = dir;
954159687Snetchild	buff->num = num;
955159687Snetchild
956159687Snetchild	return (void *)buff;
957159687Snetchild}
958159687Snetchild
959159687Snetchildstatic void
960159687Snetchildenvy24_delta_ak4524_destroy(void *codec)
961159687Snetchild{
962159687Snetchild	struct envy24_delta_ak4524_codec *ptr = codec;
963159687Snetchild	if (ptr == NULL)
964159687Snetchild		return;
965159687Snetchild#if(0)
966159687Snetchild	device_printf(ptr->parent->dev, "envy24_delta_ak4524_destroy()\n");
967159687Snetchild#endif
968159687Snetchild
969159687Snetchild	if (ptr->dir == PCMDIR_PLAY) {
970162876Snetchild		if (ptr->parent->dac[ptr->num] != NULL)
971162876Snetchild			spicds_destroy(ptr->info);
972159687Snetchild	}
973159687Snetchild	else {
974162876Snetchild		if (ptr->parent->adc[ptr->num] != NULL)
975162876Snetchild			spicds_destroy(ptr->info);
976159687Snetchild	}
977159687Snetchild
978159687Snetchild	free(codec, M_ENVY24);
979159687Snetchild}
980159687Snetchild
981159687Snetchildstatic void
982159687Snetchildenvy24_delta_ak4524_init(void *codec)
983159687Snetchild{
984159689Snetchild#if 0
985159687Snetchild	u_int32_t gpiomask, gpiodir;
986159689Snetchild#endif
987159687Snetchild	struct envy24_delta_ak4524_codec *ptr = codec;
988159687Snetchild	if (ptr == NULL)
989159687Snetchild		return;
990159687Snetchild#if(0)
991159687Snetchild	device_printf(ptr->parent->dev, "envy24_delta_ak4524_init()\n");
992159687Snetchild#endif
993159687Snetchild
994159687Snetchild	/*
995159687Snetchild	gpiomask = envy24_gpiogetmask(ptr->parent);
996159687Snetchild	gpiomask &= ~(ENVY24_GPIO_AK4524_CDTI | ENVY24_GPIO_AK4524_CCLK | ENVY24_GPIO_AK4524_CS0 | ENVY24_GPIO_AK4524_CS1);
997159687Snetchild	envy24_gpiosetmask(ptr->parent, gpiomask);
998159687Snetchild	gpiodir = envy24_gpiogetdir(ptr->parent);
999159687Snetchild	gpiodir |= ENVY24_GPIO_AK4524_CDTI | ENVY24_GPIO_AK4524_CCLK | ENVY24_GPIO_AK4524_CS0 | ENVY24_GPIO_AK4524_CS1;
1000159687Snetchild	envy24_gpiosetdir(ptr->parent, gpiodir);
1001159687Snetchild	*/
1002159689Snetchild	ptr->cs = ptr->parent->cfg->cs;
1003159689Snetchild#if 0
1004159687Snetchild	envy24_gpiosetmask(ptr->parent, ENVY24_GPIO_CS8414_STATUS);
1005159687Snetchild	envy24_gpiosetdir(ptr->parent, ~ENVY24_GPIO_CS8414_STATUS);
1006159687Snetchild	if (ptr->num == 0)
1007159687Snetchild		ptr->cs = ENVY24_GPIO_AK4524_CS0;
1008159687Snetchild	else
1009159687Snetchild		ptr->cs = ENVY24_GPIO_AK4524_CS1;
1010159687Snetchild	ptr->cclk = ENVY24_GPIO_AK4524_CCLK;
1011159689Snetchild#endif
1012159689Snetchild	ptr->cclk = ptr->parent->cfg->cclk;
1013159689Snetchild	ptr->cdti = ptr->parent->cfg->cdti;
1014162876Snetchild	spicds_settype(ptr->info,  ptr->parent->cfg->type);
1015162876Snetchild	spicds_setcif(ptr->info, ptr->parent->cfg->cif);
1016162876Snetchild	spicds_setformat(ptr->info,
1017159687Snetchild	    AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X);
1018169745Sjoel	spicds_setdvc(ptr->info, AK452X_DVC_DEMOFF);
1019162876Snetchild	/* for the time being, init only first codec */
1020162876Snetchild	if (ptr->num == 0)
1021162876Snetchild		spicds_init(ptr->info);
1022170031Sjoel
1023170031Sjoel        /* 6fire rear input init test, set ptr->num to 1 for test */
1024170031Sjoel        if (ptr->parent->cfg->subvendor == 0x153b && \
1025170031Sjoel                ptr->parent->cfg->subdevice == 0x1138 && ptr->num == 100) {
1026170031Sjoel                ptr->cs = 0x02;
1027170031Sjoel                spicds_init(ptr->info);
1028170031Sjoel                device_printf(ptr->parent->dev, "6fire rear input init\n");
1029170031Sjoel                i2c_wr(ptr, envy24_gpio_i2c_ctl, \
1030170031Sjoel                        PCA9554_I2CDEV, PCA9554_DIR, 0x80);
1031170031Sjoel                i2c_wr(ptr, envy24_gpio_i2c_ctl, \
1032170031Sjoel                        PCA9554_I2CDEV, PCA9554_OUT, 0x02);
1033170031Sjoel        }
1034159687Snetchild}
1035159687Snetchild
1036159687Snetchildstatic void
1037159687Snetchildenvy24_delta_ak4524_reinit(void *codec)
1038159687Snetchild{
1039159687Snetchild	struct envy24_delta_ak4524_codec *ptr = codec;
1040159687Snetchild	if (ptr == NULL)
1041159687Snetchild		return;
1042159687Snetchild#if(0)
1043159687Snetchild	device_printf(ptr->parent->dev, "envy24_delta_ak4524_reinit()\n");
1044159687Snetchild#endif
1045159687Snetchild
1046162876Snetchild	spicds_reinit(ptr->info);
1047159687Snetchild}
1048159687Snetchild
1049159687Snetchildstatic void
1050159687Snetchildenvy24_delta_ak4524_setvolume(void *codec, int dir, unsigned int left, unsigned int right)
1051159687Snetchild{
1052159687Snetchild	struct envy24_delta_ak4524_codec *ptr = codec;
1053159687Snetchild	if (ptr == NULL)
1054159687Snetchild		return;
1055159687Snetchild#if(0)
1056159687Snetchild	device_printf(ptr->parent->dev, "envy24_delta_ak4524_set()\n");
1057159687Snetchild#endif
1058159687Snetchild
1059162876Snetchild	spicds_set(ptr->info, dir, left, right);
1060159687Snetchild}
1061159687Snetchild
1062159687Snetchild/*
1063159687Snetchild  There is no need for AK452[48] codec to set sample rate
1064159687Snetchild  static void
1065159687Snetchild  envy24_delta_ak4524_setrate(struct envy24_delta_ak4524_codec *codec, int which, int rate)
1066159687Snetchild  {
1067159687Snetchild  }
1068159687Snetchild*/
1069159687Snetchild
1070159687Snetchild/* -------------------------------------------------------------------- */
1071159687Snetchild
1072159687Snetchild/* hardware access routeines */
1073159687Snetchild
1074159687Snetchildstatic struct {
1075159687Snetchild	u_int32_t speed;
1076159687Snetchild	u_int32_t code;
1077159687Snetchild} envy24_speedtab[] = {
1078159687Snetchild	{48000, ENVY24_MT_RATE_48000},
1079159687Snetchild	{24000, ENVY24_MT_RATE_24000},
1080159687Snetchild	{12000, ENVY24_MT_RATE_12000},
1081159687Snetchild	{9600, ENVY24_MT_RATE_9600},
1082159687Snetchild	{32000, ENVY24_MT_RATE_32000},
1083159687Snetchild	{16000, ENVY24_MT_RATE_16000},
1084159687Snetchild	{8000, ENVY24_MT_RATE_8000},
1085159687Snetchild	{96000, ENVY24_MT_RATE_96000},
1086159687Snetchild	{64000, ENVY24_MT_RATE_64000},
1087159687Snetchild	{44100, ENVY24_MT_RATE_44100},
1088159687Snetchild	{22050, ENVY24_MT_RATE_22050},
1089159687Snetchild	{11025, ENVY24_MT_RATE_11025},
1090159687Snetchild	{88200, ENVY24_MT_RATE_88200},
1091159687Snetchild	{0, 0x10}
1092159687Snetchild};
1093159687Snetchild
1094193640Sariffstatic u_int32_t
1095159687Snetchildenvy24_setspeed(struct sc_info *sc, u_int32_t speed) {
1096159687Snetchild	u_int32_t code;
1097159687Snetchild	int i = 0;
1098159687Snetchild
1099159687Snetchild#if(0)
1100159687Snetchild	device_printf(sc->dev, "envy24_setspeed(sc, %d)\n", speed);
1101159687Snetchild#endif
1102159687Snetchild	if (speed == 0) {
1103159687Snetchild		code = ENVY24_MT_RATE_SPDIF; /* external master clock */
1104159687Snetchild		envy24_slavecd(sc);
1105159687Snetchild	}
1106159687Snetchild	else {
1107159687Snetchild		for (i = 0; envy24_speedtab[i].speed != 0; i++) {
1108159687Snetchild			if (envy24_speedtab[i].speed == speed)
1109159687Snetchild				break;
1110159687Snetchild		}
1111159687Snetchild		code = envy24_speedtab[i].code;
1112159687Snetchild	}
1113159687Snetchild#if(0)
1114159687Snetchild	device_printf(sc->dev, "envy24_setspeed(): speed %d/code 0x%04x\n", envy24_speedtab[i].speed, code);
1115159687Snetchild#endif
1116159687Snetchild	if (code < 0x10) {
1117159687Snetchild		envy24_wrmt(sc, ENVY24_MT_RATE, code, 1);
1118159687Snetchild		code = envy24_rdmt(sc, ENVY24_MT_RATE, 1);
1119159687Snetchild		code &= ENVY24_MT_RATE_MASK;
1120159687Snetchild		for (i = 0; envy24_speedtab[i].code < 0x10; i++) {
1121159687Snetchild			if (envy24_speedtab[i].code == code)
1122159687Snetchild				break;
1123159687Snetchild		}
1124159687Snetchild		speed = envy24_speedtab[i].speed;
1125159687Snetchild	}
1126159687Snetchild	else
1127159687Snetchild		speed = 0;
1128159687Snetchild
1129159687Snetchild#if(0)
1130159687Snetchild	device_printf(sc->dev, "envy24_setspeed(): return %d\n", speed);
1131159687Snetchild#endif
1132159687Snetchild	return speed;
1133159687Snetchild}
1134159687Snetchild
1135159687Snetchildstatic void
1136159687Snetchildenvy24_setvolume(struct sc_info *sc, unsigned ch)
1137159687Snetchild{
1138159687Snetchild#if(0)
1139159687Snetchild	device_printf(sc->dev, "envy24_setvolume(sc, %d)\n", ch);
1140159687Snetchild#endif
1141159689Snetchildif (sc->cfg->subvendor==0x153b  && sc->cfg->subdevice==0x1138 ) {
1142159689Snetchild        envy24_wrmt(sc, ENVY24_MT_VOLIDX, 16, 1);
1143159689Snetchild        envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f7f, 2);
1144159689Snetchild        envy24_wrmt(sc, ENVY24_MT_VOLIDX, 17, 1);
1145159689Snetchild        envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f7f, 2);
1146159689Snetchild	}
1147159689Snetchild
1148159687Snetchild	envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2, 1);
1149159687Snetchild	envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f00 | sc->left[ch], 2);
1150159687Snetchild	envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2 + 1, 1);
1151159687Snetchild	envy24_wrmt(sc, ENVY24_MT_VOLUME, (sc->right[ch] << 8) | 0x7f, 2);
1152159687Snetchild}
1153159687Snetchild
1154159687Snetchildstatic void
1155159687Snetchildenvy24_mutevolume(struct sc_info *sc, unsigned ch)
1156159687Snetchild{
1157159687Snetchild	u_int32_t vol;
1158159687Snetchild
1159159687Snetchild#if(0)
1160159687Snetchild	device_printf(sc->dev, "envy24_mutevolume(sc, %d)\n", ch);
1161159687Snetchild#endif
1162159687Snetchild	vol = ENVY24_VOL_MUTE << 8 | ENVY24_VOL_MUTE;
1163159687Snetchild	envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2, 1);
1164159687Snetchild	envy24_wrmt(sc, ENVY24_MT_VOLUME, vol, 2);
1165159687Snetchild	envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2 + 1, 1);
1166159687Snetchild	envy24_wrmt(sc, ENVY24_MT_VOLUME, vol, 2);
1167159687Snetchild}
1168159687Snetchild
1169159687Snetchildstatic u_int32_t
1170159687Snetchildenvy24_gethwptr(struct sc_info *sc, int dir)
1171159687Snetchild{
1172159687Snetchild	int unit, regno;
1173159687Snetchild	u_int32_t ptr, rtn;
1174159687Snetchild
1175159687Snetchild#if(0)
1176159687Snetchild	device_printf(sc->dev, "envy24_gethwptr(sc, %d)\n", dir);
1177159687Snetchild#endif
1178159687Snetchild	if (dir == PCMDIR_PLAY) {
1179159687Snetchild		rtn = sc->psize / 4;
1180159687Snetchild		unit = ENVY24_PLAY_BUFUNIT / 4;
1181159687Snetchild		regno = ENVY24_MT_PCNT;
1182159687Snetchild	}
1183159687Snetchild	else {
1184159687Snetchild		rtn = sc->rsize / 4;
1185159687Snetchild		unit = ENVY24_REC_BUFUNIT / 4;
1186159687Snetchild		regno = ENVY24_MT_RCNT;
1187159687Snetchild	}
1188159687Snetchild
1189159687Snetchild	ptr = envy24_rdmt(sc, regno, 2);
1190159687Snetchild	rtn -= (ptr + 1);
1191159687Snetchild	rtn /= unit;
1192159687Snetchild
1193159687Snetchild#if(0)
1194159687Snetchild	device_printf(sc->dev, "envy24_gethwptr(): return %d\n", rtn);
1195159687Snetchild#endif
1196159687Snetchild	return rtn;
1197159687Snetchild}
1198159687Snetchild
1199159687Snetchildstatic void
1200159687Snetchildenvy24_updintr(struct sc_info *sc, int dir)
1201159687Snetchild{
1202159687Snetchild	int regptr, regintr;
1203159687Snetchild	u_int32_t mask, intr;
1204159687Snetchild	u_int32_t ptr, size, cnt;
1205159687Snetchild	u_int16_t blk;
1206159687Snetchild
1207159687Snetchild#if(0)
1208159687Snetchild	device_printf(sc->dev, "envy24_updintr(sc, %d)\n", dir);
1209159687Snetchild#endif
1210159687Snetchild	if (dir == PCMDIR_PLAY) {
1211159687Snetchild		blk = sc->blk[0];
1212159687Snetchild		size = sc->psize / 4;
1213159687Snetchild		regptr = ENVY24_MT_PCNT;
1214159687Snetchild		regintr = ENVY24_MT_PTERM;
1215159687Snetchild		mask = ~ENVY24_MT_INT_PMASK;
1216159687Snetchild	}
1217159687Snetchild	else {
1218159687Snetchild		blk = sc->blk[1];
1219159687Snetchild		size = sc->rsize / 4;
1220159687Snetchild		regptr = ENVY24_MT_RCNT;
1221159687Snetchild		regintr = ENVY24_MT_RTERM;
1222159687Snetchild		mask = ~ENVY24_MT_INT_RMASK;
1223159687Snetchild	}
1224159687Snetchild
1225159687Snetchild	ptr = size - envy24_rdmt(sc, regptr, 2) - 1;
1226159687Snetchild	/*
1227159687Snetchild	cnt = blk - ptr % blk - 1;
1228159687Snetchild	if (cnt == 0)
1229159687Snetchild		cnt = blk - 1;
1230159687Snetchild	*/
1231159687Snetchild	cnt = blk - 1;
1232159687Snetchild#if(0)
1233159687Snetchild	device_printf(sc->dev, "envy24_updintr():ptr = %d, blk = %d, cnt = %d\n", ptr, blk, cnt);
1234159687Snetchild#endif
1235159687Snetchild	envy24_wrmt(sc, regintr, cnt, 2);
1236159687Snetchild	intr = envy24_rdmt(sc, ENVY24_MT_INT, 1);
1237159687Snetchild#if(0)
1238159687Snetchild	device_printf(sc->dev, "envy24_updintr():intr = 0x%02x, mask = 0x%02x\n", intr, mask);
1239159687Snetchild#endif
1240159687Snetchild	envy24_wrmt(sc, ENVY24_MT_INT, intr & mask, 1);
1241159687Snetchild#if(0)
1242159687Snetchild	device_printf(sc->dev, "envy24_updintr():INT-->0x%02x\n",
1243159687Snetchild		      envy24_rdmt(sc, ENVY24_MT_INT, 1));
1244159687Snetchild#endif
1245159687Snetchild
1246159687Snetchild	return;
1247159687Snetchild}
1248159687Snetchild
1249159689Snetchild#if 0
1250159687Snetchildstatic void
1251159687Snetchildenvy24_maskintr(struct sc_info *sc, int dir)
1252159687Snetchild{
1253159687Snetchild	u_int32_t mask, intr;
1254159687Snetchild
1255159687Snetchild#if(0)
1256159687Snetchild	device_printf(sc->dev, "envy24_maskintr(sc, %d)\n", dir);
1257159687Snetchild#endif
1258159687Snetchild	if (dir == PCMDIR_PLAY)
1259159687Snetchild		mask = ENVY24_MT_INT_PMASK;
1260159687Snetchild	else
1261159687Snetchild		mask = ENVY24_MT_INT_RMASK;
1262159687Snetchild	intr = envy24_rdmt(sc, ENVY24_MT_INT, 1);
1263159687Snetchild	envy24_wrmt(sc, ENVY24_MT_INT, intr | mask, 1);
1264159687Snetchild
1265159687Snetchild	return;
1266159687Snetchild}
1267159689Snetchild#endif
1268159687Snetchild
1269159687Snetchildstatic int
1270159687Snetchildenvy24_checkintr(struct sc_info *sc, int dir)
1271159687Snetchild{
1272159687Snetchild	u_int32_t mask, stat, intr, rtn;
1273159687Snetchild
1274159687Snetchild#if(0)
1275159687Snetchild	device_printf(sc->dev, "envy24_checkintr(sc, %d)\n", dir);
1276159687Snetchild#endif
1277159687Snetchild	intr = envy24_rdmt(sc, ENVY24_MT_INT, 1);
1278159687Snetchild	if (dir == PCMDIR_PLAY) {
1279159687Snetchild		if ((rtn = intr & ENVY24_MT_INT_PSTAT) != 0) {
1280159687Snetchild			mask = ~ENVY24_MT_INT_RSTAT;
1281159687Snetchild			stat = ENVY24_MT_INT_PSTAT | ENVY24_MT_INT_PMASK;
1282159687Snetchild			envy24_wrmt(sc, ENVY24_MT_INT, (intr & mask) | stat, 1);
1283159687Snetchild		}
1284159687Snetchild	}
1285159687Snetchild	else {
1286159687Snetchild		if ((rtn = intr & ENVY24_MT_INT_RSTAT) != 0) {
1287159687Snetchild			mask = ~ENVY24_MT_INT_PSTAT;
1288159687Snetchild			stat = ENVY24_MT_INT_RSTAT | ENVY24_MT_INT_RMASK;
1289159687Snetchild			envy24_wrmt(sc, ENVY24_MT_INT, (intr & mask) | stat, 1);
1290159687Snetchild		}
1291159687Snetchild	}
1292159687Snetchild
1293159687Snetchild	return rtn;
1294159687Snetchild}
1295159687Snetchild
1296159687Snetchildstatic void
1297159687Snetchildenvy24_start(struct sc_info *sc, int dir)
1298159687Snetchild{
1299159687Snetchild	u_int32_t stat, sw;
1300159687Snetchild
1301159687Snetchild#if(0)
1302159687Snetchild	device_printf(sc->dev, "envy24_start(sc, %d)\n", dir);
1303159687Snetchild#endif
1304159687Snetchild	if (dir == PCMDIR_PLAY)
1305159687Snetchild		sw = ENVY24_MT_PCTL_PSTART;
1306159687Snetchild	else
1307159687Snetchild		sw = ENVY24_MT_PCTL_RSTART;
1308159687Snetchild
1309159687Snetchild	stat = envy24_rdmt(sc, ENVY24_MT_PCTL, 1);
1310159687Snetchild	envy24_wrmt(sc, ENVY24_MT_PCTL, stat | sw, 1);
1311159687Snetchild#if(0)
1312159687Snetchild	DELAY(100);
1313159687Snetchild	device_printf(sc->dev, "PADDR:0x%08x\n", envy24_rdmt(sc, ENVY24_MT_PADDR, 4));
1314159687Snetchild	device_printf(sc->dev, "PCNT:%ld\n", envy24_rdmt(sc, ENVY24_MT_PCNT, 2));
1315159687Snetchild#endif
1316159687Snetchild
1317159687Snetchild	return;
1318159687Snetchild}
1319159687Snetchild
1320159687Snetchildstatic void
1321159687Snetchildenvy24_stop(struct sc_info *sc, int dir)
1322159687Snetchild{
1323159687Snetchild	u_int32_t stat, sw;
1324159687Snetchild
1325159687Snetchild#if(0)
1326159687Snetchild	device_printf(sc->dev, "envy24_stop(sc, %d)\n", dir);
1327159687Snetchild#endif
1328159687Snetchild	if (dir == PCMDIR_PLAY)
1329159687Snetchild		sw = ~ENVY24_MT_PCTL_PSTART;
1330159687Snetchild	else
1331159687Snetchild		sw = ~ENVY24_MT_PCTL_RSTART;
1332159687Snetchild
1333159687Snetchild	stat = envy24_rdmt(sc, ENVY24_MT_PCTL, 1);
1334159687Snetchild	envy24_wrmt(sc, ENVY24_MT_PCTL, stat & sw, 1);
1335159687Snetchild
1336159687Snetchild	return;
1337159687Snetchild}
1338159687Snetchild
1339159687Snetchildstatic int
1340159687Snetchildenvy24_route(struct sc_info *sc, int dac, int class, int adc, int rev)
1341159687Snetchild{
1342159687Snetchild	u_int32_t reg, mask;
1343159687Snetchild	u_int32_t left, right;
1344159687Snetchild
1345159687Snetchild#if(0)
1346159687Snetchild	device_printf(sc->dev, "envy24_route(sc, %d, %d, %d, %d)\n",
1347159687Snetchild	    dac, class, adc, rev);
1348159687Snetchild#endif
1349159687Snetchild	/* parameter pattern check */
1350159687Snetchild	if (dac < 0 || ENVY24_ROUTE_DAC_SPDIF < dac)
1351159687Snetchild		return -1;
1352159687Snetchild	if (class == ENVY24_ROUTE_CLASS_MIX &&
1353159687Snetchild	    (dac != ENVY24_ROUTE_DAC_1 && dac != ENVY24_ROUTE_DAC_SPDIF))
1354159687Snetchild		return -1;
1355159687Snetchild	if (rev) {
1356159687Snetchild		left = ENVY24_ROUTE_RIGHT;
1357159687Snetchild		right = ENVY24_ROUTE_LEFT;
1358159687Snetchild	}
1359159687Snetchild	else {
1360159687Snetchild		left = ENVY24_ROUTE_LEFT;
1361159687Snetchild		right = ENVY24_ROUTE_RIGHT;
1362159687Snetchild	}
1363159687Snetchild
1364159687Snetchild	if (dac == ENVY24_ROUTE_DAC_SPDIF) {
1365159687Snetchild		reg = class | class << 2 |
1366159687Snetchild			((adc << 1 | left) | left << 3) << 8 |
1367159687Snetchild			((adc << 1 | right) | right << 3) << 12;
1368159687Snetchild#if(0)
1369159687Snetchild		device_printf(sc->dev, "envy24_route(): MT_SPDOUT-->0x%04x\n", reg);
1370159687Snetchild#endif
1371159687Snetchild		envy24_wrmt(sc, ENVY24_MT_SPDOUT, reg, 2);
1372159687Snetchild	}
1373159687Snetchild	else {
1374159687Snetchild		mask = ~(0x0303 << dac * 2);
1375159687Snetchild		reg = envy24_rdmt(sc, ENVY24_MT_PSDOUT, 2);
1376159687Snetchild		reg = (reg & mask) | ((class | class << 8) << dac * 2);
1377159687Snetchild#if(0)
1378159687Snetchild		device_printf(sc->dev, "envy24_route(): MT_PSDOUT-->0x%04x\n", reg);
1379159687Snetchild#endif
1380159687Snetchild		envy24_wrmt(sc, ENVY24_MT_PSDOUT, reg, 2);
1381159687Snetchild		mask = ~(0xff << dac * 8);
1382159687Snetchild		reg = envy24_rdmt(sc, ENVY24_MT_RECORD, 4);
1383159687Snetchild		reg = (reg & mask) |
1384159687Snetchild			(((adc << 1 | left) | left << 3) |
1385159687Snetchild			 ((adc << 1 | right) | right << 3) << 4) << dac * 8;
1386159687Snetchild#if(0)
1387159687Snetchild		device_printf(sc->dev, "envy24_route(): MT_RECORD-->0x%08x\n", reg);
1388159687Snetchild#endif
1389159687Snetchild		envy24_wrmt(sc, ENVY24_MT_RECORD, reg, 4);
1390170031Sjoel
1391170031Sjoel		/* 6fire rear input init test */
1392170031Sjoel		envy24_wrmt(sc, ENVY24_MT_RECORD, 0x00, 4);
1393159687Snetchild	}
1394159687Snetchild
1395159687Snetchild	return 0;
1396159687Snetchild}
1397159687Snetchild
1398159687Snetchild/* -------------------------------------------------------------------- */
1399159687Snetchild
1400159687Snetchild/* buffer copy routines */
1401159687Snetchildstatic void
1402159687Snetchildenvy24_p32sl(struct sc_chinfo *ch)
1403159687Snetchild{
1404159687Snetchild	int length;
1405159687Snetchild	sample32_t *dmabuf;
1406159687Snetchild	u_int32_t *data;
1407159687Snetchild	int src, dst, ssize, dsize, slot;
1408159687Snetchild	int i;
1409159687Snetchild
1410159687Snetchild	length = sndbuf_getready(ch->buffer) / 8;
1411159687Snetchild	dmabuf = ch->parent->pbuf;
1412159687Snetchild	data = (u_int32_t *)ch->data;
1413159687Snetchild	src = sndbuf_getreadyptr(ch->buffer) / 4;
1414159687Snetchild	dst = src / 2 + ch->offset;
1415159687Snetchild	ssize = ch->size / 4;
1416159687Snetchild	dsize = ch->size / 8;
1417159687Snetchild	slot = ch->num * 2;
1418159687Snetchild
1419159687Snetchild	for (i = 0; i < length; i++) {
1420159689Snetchild		dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = data[src];
1421159689Snetchild		dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = data[src + 1];
1422159687Snetchild		dst++;
1423159687Snetchild		dst %= dsize;
1424159687Snetchild		src += 2;
1425159687Snetchild		src %= ssize;
1426159687Snetchild	}
1427159687Snetchild
1428159687Snetchild	return;
1429159687Snetchild}
1430159687Snetchild
1431159687Snetchildstatic void
1432159687Snetchildenvy24_p16sl(struct sc_chinfo *ch)
1433159687Snetchild{
1434159687Snetchild	int length;
1435159687Snetchild	sample32_t *dmabuf;
1436159687Snetchild	u_int16_t *data;
1437159687Snetchild	int src, dst, ssize, dsize, slot;
1438159687Snetchild	int i;
1439159687Snetchild
1440159687Snetchild#if(0)
1441159687Snetchild	device_printf(ch->parent->dev, "envy24_p16sl()\n");
1442159687Snetchild#endif
1443159687Snetchild	length = sndbuf_getready(ch->buffer) / 4;
1444159687Snetchild	dmabuf = ch->parent->pbuf;
1445159687Snetchild	data = (u_int16_t *)ch->data;
1446159687Snetchild	src = sndbuf_getreadyptr(ch->buffer) / 2;
1447159687Snetchild	dst = src / 2 + ch->offset;
1448159687Snetchild	ssize = ch->size / 2;
1449159687Snetchild	dsize = ch->size / 4;
1450159687Snetchild	slot = ch->num * 2;
1451159687Snetchild#if(0)
1452159687Snetchild	device_printf(ch->parent->dev, "envy24_p16sl():%lu-->%lu(%lu)\n", src, dst, length);
1453159687Snetchild#endif
1454159687Snetchild
1455159687Snetchild	for (i = 0; i < length; i++) {
1456159689Snetchild		dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = (u_int32_t)data[src] << 16;
1457159689Snetchild		dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = (u_int32_t)data[src + 1] << 16;
1458159687Snetchild#if(0)
1459159687Snetchild		if (i < 16) {
1460159687Snetchild			printf("%08x", dmabuf[dst * ENVY24_PLAY_CHNUM + slot]);
1461159687Snetchild			printf("%08x", dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1]);
1462159687Snetchild		}
1463159687Snetchild#endif
1464159687Snetchild		dst++;
1465159687Snetchild		dst %= dsize;
1466159687Snetchild		src += 2;
1467159687Snetchild		src %= ssize;
1468159687Snetchild	}
1469159687Snetchild#if(0)
1470159687Snetchild	printf("\n");
1471159687Snetchild#endif
1472159687Snetchild
1473159687Snetchild	return;
1474159687Snetchild}
1475159687Snetchild
1476159687Snetchildstatic void
1477159687Snetchildenvy24_p8u(struct sc_chinfo *ch)
1478159687Snetchild{
1479159687Snetchild	int length;
1480159687Snetchild	sample32_t *dmabuf;
1481159687Snetchild	u_int8_t *data;
1482159687Snetchild	int src, dst, ssize, dsize, slot;
1483159687Snetchild	int i;
1484159687Snetchild
1485159687Snetchild	length = sndbuf_getready(ch->buffer) / 2;
1486159687Snetchild	dmabuf = ch->parent->pbuf;
1487159687Snetchild	data = (u_int8_t *)ch->data;
1488159687Snetchild	src = sndbuf_getreadyptr(ch->buffer);
1489159687Snetchild	dst = src / 2 + ch->offset;
1490159687Snetchild	ssize = ch->size;
1491159687Snetchild	dsize = ch->size / 4;
1492159687Snetchild	slot = ch->num * 2;
1493159687Snetchild
1494159687Snetchild	for (i = 0; i < length; i++) {
1495159689Snetchild		dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = ((u_int32_t)data[src] ^ 0x80) << 24;
1496159689Snetchild		dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = ((u_int32_t)data[src + 1] ^ 0x80) << 24;
1497159687Snetchild		dst++;
1498159687Snetchild		dst %= dsize;
1499159687Snetchild		src += 2;
1500159687Snetchild		src %= ssize;
1501159687Snetchild	}
1502159687Snetchild
1503159687Snetchild	return;
1504159687Snetchild}
1505159687Snetchild
1506159687Snetchildstatic void
1507159687Snetchildenvy24_r32sl(struct sc_chinfo *ch)
1508159687Snetchild{
1509159687Snetchild	int length;
1510159687Snetchild	sample32_t *dmabuf;
1511159687Snetchild	u_int32_t *data;
1512159687Snetchild	int src, dst, ssize, dsize, slot;
1513159687Snetchild	int i;
1514159687Snetchild
1515159687Snetchild	length = sndbuf_getfree(ch->buffer) / 8;
1516159687Snetchild	dmabuf = ch->parent->rbuf;
1517159687Snetchild	data = (u_int32_t *)ch->data;
1518159687Snetchild	dst = sndbuf_getfreeptr(ch->buffer) / 4;
1519159687Snetchild	src = dst / 2 + ch->offset;
1520159687Snetchild	dsize = ch->size / 4;
1521159687Snetchild	ssize = ch->size / 8;
1522159687Snetchild	slot = (ch->num - ENVY24_CHAN_REC_ADC1) * 2;
1523159687Snetchild
1524159687Snetchild	for (i = 0; i < length; i++) {
1525159689Snetchild		data[dst] = dmabuf[src * ENVY24_REC_CHNUM + slot].buffer;
1526159689Snetchild		data[dst + 1] = dmabuf[src * ENVY24_REC_CHNUM + slot + 1].buffer;
1527159687Snetchild		dst += 2;
1528159687Snetchild		dst %= dsize;
1529159687Snetchild		src++;
1530159687Snetchild		src %= ssize;
1531159687Snetchild	}
1532159687Snetchild
1533159687Snetchild	return;
1534159687Snetchild}
1535159687Snetchild
1536159687Snetchildstatic void
1537159687Snetchildenvy24_r16sl(struct sc_chinfo *ch)
1538159687Snetchild{
1539159687Snetchild	int length;
1540159687Snetchild	sample32_t *dmabuf;
1541159689Snetchild	u_int16_t *data;
1542159687Snetchild	int src, dst, ssize, dsize, slot;
1543159687Snetchild	int i;
1544159687Snetchild
1545159687Snetchild	length = sndbuf_getfree(ch->buffer) / 4;
1546159687Snetchild	dmabuf = ch->parent->rbuf;
1547159687Snetchild	data = (u_int16_t *)ch->data;
1548159687Snetchild	dst = sndbuf_getfreeptr(ch->buffer) / 2;
1549159687Snetchild	src = dst / 2 + ch->offset;
1550159687Snetchild	dsize = ch->size / 2;
1551159687Snetchild	ssize = ch->size / 8;
1552159687Snetchild	slot = (ch->num - ENVY24_CHAN_REC_ADC1) * 2;
1553159687Snetchild
1554159687Snetchild	for (i = 0; i < length; i++) {
1555159689Snetchild		data[dst] = dmabuf[src * ENVY24_REC_CHNUM + slot].buffer;
1556159689Snetchild		data[dst + 1] = dmabuf[src * ENVY24_REC_CHNUM + slot + 1].buffer;
1557159687Snetchild		dst += 2;
1558159687Snetchild		dst %= dsize;
1559159687Snetchild		src++;
1560159687Snetchild		src %= ssize;
1561159687Snetchild	}
1562159687Snetchild
1563159687Snetchild	return;
1564159687Snetchild}
1565159687Snetchild
1566159687Snetchild/* -------------------------------------------------------------------- */
1567159687Snetchild
1568159687Snetchild/* channel interface */
1569159687Snetchildstatic void *
1570159687Snetchildenvy24chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
1571159687Snetchild{
1572159687Snetchild	struct sc_info	*sc = (struct sc_info *)devinfo;
1573159687Snetchild	struct sc_chinfo *ch;
1574159687Snetchild	unsigned num;
1575159687Snetchild
1576159687Snetchild#if(0)
1577159687Snetchild	device_printf(sc->dev, "envy24chan_init(obj, devinfo, b, c, %d)\n", dir);
1578159687Snetchild#endif
1579159687Snetchild	snd_mtxlock(sc->lock);
1580159687Snetchild	if ((sc->chnum > ENVY24_CHAN_PLAY_SPDIF && dir != PCMDIR_REC) ||
1581159687Snetchild	    (sc->chnum < ENVY24_CHAN_REC_ADC1 && dir != PCMDIR_PLAY)) {
1582159687Snetchild		snd_mtxunlock(sc->lock);
1583159687Snetchild		return NULL;
1584159687Snetchild	}
1585159687Snetchild	num = sc->chnum;
1586159687Snetchild
1587159687Snetchild	ch = &sc->chan[num];
1588159687Snetchild	ch->size = 8 * ENVY24_SAMPLE_NUM;
1589159687Snetchild	ch->data = malloc(ch->size, M_ENVY24, M_NOWAIT);
1590159687Snetchild	if (ch->data == NULL) {
1591159687Snetchild		ch->size = 0;
1592159687Snetchild		ch = NULL;
1593159687Snetchild	}
1594159687Snetchild	else {
1595159687Snetchild		ch->buffer = b;
1596159687Snetchild		ch->channel = c;
1597159687Snetchild		ch->parent = sc;
1598159687Snetchild		ch->dir = dir;
1599159687Snetchild		/* set channel map */
1600159687Snetchild		ch->num = envy24_chanmap[num];
1601165306Sariff		snd_mtxunlock(sc->lock);
1602159687Snetchild		sndbuf_setup(ch->buffer, ch->data, ch->size);
1603165306Sariff		snd_mtxlock(sc->lock);
1604159687Snetchild		/* these 2 values are dummy */
1605159687Snetchild		ch->unit = 4;
1606159687Snetchild		ch->blk = 10240;
1607159687Snetchild	}
1608159687Snetchild	snd_mtxunlock(sc->lock);
1609159687Snetchild
1610159687Snetchild	return ch;
1611159687Snetchild}
1612159687Snetchild
1613159687Snetchildstatic int
1614159687Snetchildenvy24chan_free(kobj_t obj, void *data)
1615159687Snetchild{
1616159687Snetchild	struct sc_chinfo *ch = data;
1617159687Snetchild	struct sc_info *sc = ch->parent;
1618159687Snetchild
1619159687Snetchild#if(0)
1620159687Snetchild	device_printf(sc->dev, "envy24chan_free()\n");
1621159687Snetchild#endif
1622159687Snetchild	snd_mtxlock(sc->lock);
1623159687Snetchild	if (ch->data != NULL) {
1624159687Snetchild		free(ch->data, M_ENVY24);
1625159687Snetchild		ch->data = NULL;
1626159687Snetchild	}
1627159687Snetchild	snd_mtxunlock(sc->lock);
1628159687Snetchild
1629159687Snetchild	return 0;
1630159687Snetchild}
1631159687Snetchild
1632159687Snetchildstatic int
1633159687Snetchildenvy24chan_setformat(kobj_t obj, void *data, u_int32_t format)
1634159687Snetchild{
1635159687Snetchild	struct sc_chinfo *ch = data;
1636159687Snetchild	struct sc_info *sc = ch->parent;
1637159687Snetchild	struct envy24_emldma *emltab;
1638165306Sariff	/* unsigned int bcnt, bsize; */
1639159687Snetchild	int i;
1640159687Snetchild
1641159687Snetchild#if(0)
1642159687Snetchild	device_printf(sc->dev, "envy24chan_setformat(obj, data, 0x%08x)\n", format);
1643159687Snetchild#endif
1644159687Snetchild	snd_mtxlock(sc->lock);
1645159687Snetchild	/* check and get format related information */
1646159687Snetchild	if (ch->dir == PCMDIR_PLAY)
1647159687Snetchild		emltab = envy24_pemltab;
1648159687Snetchild	else
1649159687Snetchild		emltab = envy24_remltab;
1650159687Snetchild	if (emltab == NULL) {
1651159687Snetchild		snd_mtxunlock(sc->lock);
1652159687Snetchild		return -1;
1653159687Snetchild	}
1654159687Snetchild	for (i = 0; emltab[i].format != 0; i++)
1655159687Snetchild		if (emltab[i].format == format)
1656159687Snetchild			break;
1657159687Snetchild	if (emltab[i].format == 0) {
1658159687Snetchild		snd_mtxunlock(sc->lock);
1659159687Snetchild		return -1;
1660159687Snetchild	}
1661159687Snetchild
1662159687Snetchild	/* set format information */
1663159687Snetchild	ch->format = format;
1664159687Snetchild	ch->emldma = emltab[i].emldma;
1665159687Snetchild	if (ch->unit > emltab[i].unit)
1666159687Snetchild		ch->blk *= ch->unit / emltab[i].unit;
1667159687Snetchild	else
1668159687Snetchild		ch->blk /= emltab[i].unit / ch->unit;
1669159687Snetchild	ch->unit = emltab[i].unit;
1670159687Snetchild
1671159687Snetchild	/* set channel buffer information */
1672159687Snetchild	ch->size = ch->unit * ENVY24_SAMPLE_NUM;
1673165306Sariff#if 0
1674159687Snetchild	if (ch->dir == PCMDIR_PLAY)
1675159687Snetchild		bsize = ch->blk * 4 / ENVY24_PLAY_BUFUNIT;
1676159687Snetchild	else
1677159687Snetchild		bsize = ch->blk * 4 / ENVY24_REC_BUFUNIT;
1678159687Snetchild	bsize *= ch->unit;
1679159687Snetchild	bcnt = ch->size / bsize;
1680159687Snetchild	sndbuf_resize(ch->buffer, bcnt, bsize);
1681165306Sariff#endif
1682159687Snetchild	snd_mtxunlock(sc->lock);
1683159687Snetchild
1684159687Snetchild#if(0)
1685159687Snetchild	device_printf(sc->dev, "envy24chan_setformat(): return 0x%08x\n", 0);
1686159687Snetchild#endif
1687159687Snetchild	return 0;
1688159687Snetchild}
1689159687Snetchild
1690159687Snetchild/*
1691159687Snetchild  IMPLEMENT NOTICE: In this driver, setspeed function only do setting
1692159687Snetchild  of speed information value. And real hardware speed setting is done
1693159687Snetchild  at start triggered(see envy24chan_trigger()). So, at this function
1694159687Snetchild  is called, any value that ENVY24 can use is able to set. But, at
1695159687Snetchild  start triggerd, some other channel is running, and that channel's
1696159687Snetchild  speed isn't same with, then trigger function will fail.
1697159687Snetchild*/
1698193640Sariffstatic u_int32_t
1699159687Snetchildenvy24chan_setspeed(kobj_t obj, void *data, u_int32_t speed)
1700159687Snetchild{
1701159687Snetchild	struct sc_chinfo *ch = data;
1702159687Snetchild	u_int32_t val, prev;
1703159687Snetchild	int i;
1704159687Snetchild
1705159687Snetchild#if(0)
1706159687Snetchild	device_printf(ch->parent->dev, "envy24chan_setspeed(obj, data, %d)\n", speed);
1707159687Snetchild#endif
1708159687Snetchild	prev = 0x7fffffff;
1709159687Snetchild	for (i = 0; (val = envy24_speed[i]) != 0; i++) {
1710159687Snetchild		if (abs(val - speed) < abs(prev - speed))
1711159687Snetchild			prev = val;
1712159687Snetchild		else
1713159687Snetchild			break;
1714159687Snetchild	}
1715159687Snetchild	ch->speed = prev;
1716159687Snetchild
1717159687Snetchild#if(0)
1718159687Snetchild	device_printf(ch->parent->dev, "envy24chan_setspeed(): return %d\n", ch->speed);
1719159687Snetchild#endif
1720159687Snetchild	return ch->speed;
1721159687Snetchild}
1722159687Snetchild
1723193640Sariffstatic u_int32_t
1724159687Snetchildenvy24chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
1725159687Snetchild{
1726159687Snetchild	struct sc_chinfo *ch = data;
1727165306Sariff	/* struct sc_info *sc = ch->parent; */
1728159687Snetchild	u_int32_t size, prev;
1729165306Sariff        unsigned int bcnt, bsize;
1730159687Snetchild
1731159687Snetchild#if(0)
1732159687Snetchild	device_printf(sc->dev, "envy24chan_setblocksize(obj, data, %d)\n", blocksize);
1733159687Snetchild#endif
1734159687Snetchild	prev = 0x7fffffff;
1735165306Sariff	/* snd_mtxlock(sc->lock); */
1736159687Snetchild	for (size = ch->size / 2; size > 0; size /= 2) {
1737159687Snetchild		if (abs(size - blocksize) < abs(prev - blocksize))
1738159687Snetchild			prev = size;
1739159687Snetchild		else
1740159687Snetchild			break;
1741159687Snetchild	}
1742159687Snetchild
1743159687Snetchild	ch->blk = prev / ch->unit;
1744159687Snetchild	if (ch->dir == PCMDIR_PLAY)
1745159687Snetchild		ch->blk *= ENVY24_PLAY_BUFUNIT / 4;
1746159687Snetchild	else
1747159687Snetchild		ch->blk *= ENVY24_REC_BUFUNIT / 4;
1748165306Sariff	/* set channel buffer information */
1749165306Sariff	/* ch->size = ch->unit * ENVY24_SAMPLE_NUM; */
1750165306Sariff        if (ch->dir == PCMDIR_PLAY)
1751165306Sariff                bsize = ch->blk * 4 / ENVY24_PLAY_BUFUNIT;
1752165306Sariff        else
1753165306Sariff                bsize = ch->blk * 4 / ENVY24_REC_BUFUNIT;
1754165306Sariff        bsize *= ch->unit;
1755165306Sariff        bcnt = ch->size / bsize;
1756165306Sariff        sndbuf_resize(ch->buffer, bcnt, bsize);
1757165306Sariff	/* snd_mtxunlock(sc->lock); */
1758159687Snetchild
1759159687Snetchild#if(0)
1760159687Snetchild	device_printf(sc->dev, "envy24chan_setblocksize(): return %d\n", prev);
1761159687Snetchild#endif
1762159687Snetchild	return prev;
1763159687Snetchild}
1764159687Snetchild
1765159687Snetchild/* semantic note: must start at beginning of buffer */
1766159687Snetchildstatic int
1767159687Snetchildenvy24chan_trigger(kobj_t obj, void *data, int go)
1768159687Snetchild{
1769159687Snetchild	struct sc_chinfo *ch = data;
1770159687Snetchild	struct sc_info *sc = ch->parent;
1771159687Snetchild	u_int32_t ptr;
1772159687Snetchild	int slot;
1773191308Sstas	int error = 0;
1774160796Snetchild#if 0
1775159687Snetchild	int i;
1776159687Snetchild
1777159687Snetchild	device_printf(sc->dev, "envy24chan_trigger(obj, data, %d)\n", go);
1778159687Snetchild#endif
1779159687Snetchild	snd_mtxlock(sc->lock);
1780159687Snetchild	if (ch->dir == PCMDIR_PLAY)
1781159687Snetchild		slot = 0;
1782159687Snetchild	else
1783159687Snetchild		slot = 1;
1784159687Snetchild	switch (go) {
1785159687Snetchild	case PCMTRIG_START:
1786159687Snetchild#if(0)
1787159687Snetchild		device_printf(sc->dev, "envy24chan_trigger(): start\n");
1788159687Snetchild#endif
1789159687Snetchild		/* check or set channel speed */
1790159687Snetchild		if (sc->run[0] == 0 && sc->run[1] == 0) {
1791159687Snetchild			sc->speed = envy24_setspeed(sc, ch->speed);
1792159687Snetchild			sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed;
1793159687Snetchild			sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed;
1794159687Snetchild		}
1795191308Sstas		else if (ch->speed != 0 && ch->speed != sc->speed) {
1796191308Sstas			error = -1;
1797191308Sstas			goto fail;
1798191308Sstas		}
1799159687Snetchild		if (ch->speed == 0)
1800159687Snetchild			ch->channel->speed = sc->speed;
1801159687Snetchild		/* start or enable channel */
1802159687Snetchild		sc->run[slot]++;
1803159687Snetchild		if (sc->run[slot] == 1) {
1804159687Snetchild			/* first channel */
1805159687Snetchild			ch->offset = 0;
1806159687Snetchild			sc->blk[slot] = ch->blk;
1807159687Snetchild		}
1808159687Snetchild		else {
1809159687Snetchild			ptr = envy24_gethwptr(sc, ch->dir);
1810159687Snetchild			ch->offset = ((ptr / ch->blk + 1) * ch->blk %
1811159687Snetchild			    (ch->size / 4)) * 4 / ch->unit;
1812159687Snetchild			if (ch->blk < sc->blk[slot])
1813159687Snetchild				sc->blk[slot] = ch->blk;
1814159687Snetchild		}
1815159687Snetchild		if (ch->dir == PCMDIR_PLAY) {
1816159687Snetchild			ch->emldma(ch);
1817159687Snetchild			envy24_setvolume(sc, ch->num);
1818159687Snetchild		}
1819159687Snetchild		envy24_updintr(sc, ch->dir);
1820159687Snetchild		if (sc->run[slot] == 1)
1821159687Snetchild			envy24_start(sc, ch->dir);
1822159687Snetchild		ch->run = 1;
1823159687Snetchild		break;
1824159687Snetchild	case PCMTRIG_EMLDMAWR:
1825159687Snetchild#if(0)
1826159687Snetchild		device_printf(sc->dev, "envy24chan_trigger(): emldmawr\n");
1827159687Snetchild#endif
1828191308Sstas		if (ch->run != 1) {
1829191308Sstas			error = -1;
1830191308Sstas			goto fail;
1831191308Sstas		}
1832159687Snetchild		ch->emldma(ch);
1833159687Snetchild		break;
1834159687Snetchild	case PCMTRIG_EMLDMARD:
1835159687Snetchild#if(0)
1836159687Snetchild		device_printf(sc->dev, "envy24chan_trigger(): emldmard\n");
1837159687Snetchild#endif
1838191308Sstas		if (ch->run != 1) {
1839191308Sstas			error = -1;
1840191308Sstas			goto fail;
1841191308Sstas		}
1842159687Snetchild		ch->emldma(ch);
1843159687Snetchild		break;
1844159687Snetchild	case PCMTRIG_ABORT:
1845170031Sjoel		if (ch->run) {
1846159687Snetchild#if(0)
1847159687Snetchild		device_printf(sc->dev, "envy24chan_trigger(): abort\n");
1848159687Snetchild#endif
1849159687Snetchild		ch->run = 0;
1850159687Snetchild		sc->run[slot]--;
1851159687Snetchild		if (ch->dir == PCMDIR_PLAY)
1852159687Snetchild			envy24_mutevolume(sc, ch->num);
1853159687Snetchild		if (sc->run[slot] == 0) {
1854159687Snetchild			envy24_stop(sc, ch->dir);
1855159687Snetchild			sc->intr[slot] = 0;
1856159687Snetchild		}
1857160796Snetchild#if 0
1858159687Snetchild		else if (ch->blk == sc->blk[slot]) {
1859159687Snetchild			sc->blk[slot] = ENVY24_SAMPLE_NUM / 2;
1860159687Snetchild			for (i = 0; i < ENVY24_CHAN_NUM; i++) {
1861159687Snetchild				if (sc->chan[i].dir == ch->dir &&
1862159687Snetchild				    sc->chan[i].run == 1 &&
1863159687Snetchild				    sc->chan[i].blk < sc->blk[slot])
1864159687Snetchild					sc->blk[slot] = sc->chan[i].blk;
1865159687Snetchild			}
1866159687Snetchild			if (ch->blk != sc->blk[slot])
1867159687Snetchild				envy24_updintr(sc, ch->dir);
1868159687Snetchild		}
1869160796Snetchild#endif
1870170031Sjoel		}
1871159687Snetchild		break;
1872159687Snetchild	}
1873191308Sstasfail:
1874159687Snetchild	snd_mtxunlock(sc->lock);
1875191308Sstas	return (error);
1876159687Snetchild}
1877159687Snetchild
1878193640Sariffstatic u_int32_t
1879159687Snetchildenvy24chan_getptr(kobj_t obj, void *data)
1880159687Snetchild{
1881159687Snetchild	struct sc_chinfo *ch = data;
1882159687Snetchild	struct sc_info *sc = ch->parent;
1883193640Sariff	u_int32_t ptr, rtn;
1884159687Snetchild
1885159687Snetchild#if(0)
1886159687Snetchild	device_printf(sc->dev, "envy24chan_getptr()\n");
1887159687Snetchild#endif
1888159687Snetchild	snd_mtxlock(sc->lock);
1889159687Snetchild	ptr = envy24_gethwptr(sc, ch->dir);
1890159687Snetchild	rtn = ptr * ch->unit;
1891159687Snetchild	snd_mtxunlock(sc->lock);
1892159687Snetchild
1893159687Snetchild#if(0)
1894159687Snetchild	device_printf(sc->dev, "envy24chan_getptr(): return %d\n",
1895159687Snetchild	    rtn);
1896159687Snetchild#endif
1897159687Snetchild	return rtn;
1898159687Snetchild}
1899159687Snetchild
1900159687Snetchildstatic struct pcmchan_caps *
1901159687Snetchildenvy24chan_getcaps(kobj_t obj, void *data)
1902159687Snetchild{
1903159687Snetchild	struct sc_chinfo *ch = data;
1904159687Snetchild	struct sc_info *sc = ch->parent;
1905159687Snetchild	struct pcmchan_caps *rtn;
1906159687Snetchild
1907159687Snetchild#if(0)
1908159687Snetchild	device_printf(sc->dev, "envy24chan_getcaps()\n");
1909159687Snetchild#endif
1910159687Snetchild	snd_mtxlock(sc->lock);
1911159687Snetchild	if (ch->dir == PCMDIR_PLAY) {
1912159687Snetchild		if (sc->run[0] == 0)
1913159687Snetchild			rtn = &envy24_playcaps;
1914159687Snetchild		else
1915159687Snetchild			rtn = &sc->caps[0];
1916159687Snetchild	}
1917159687Snetchild	else {
1918159687Snetchild		if (sc->run[1] == 0)
1919159687Snetchild			rtn = &envy24_reccaps;
1920159687Snetchild		else
1921159687Snetchild			rtn = &sc->caps[1];
1922159687Snetchild	}
1923159687Snetchild	snd_mtxunlock(sc->lock);
1924159687Snetchild
1925159687Snetchild	return rtn;
1926159687Snetchild}
1927159687Snetchild
1928159687Snetchildstatic kobj_method_t envy24chan_methods[] = {
1929159687Snetchild	KOBJMETHOD(channel_init,		envy24chan_init),
1930159687Snetchild	KOBJMETHOD(channel_free,		envy24chan_free),
1931159687Snetchild	KOBJMETHOD(channel_setformat,		envy24chan_setformat),
1932159687Snetchild	KOBJMETHOD(channel_setspeed,		envy24chan_setspeed),
1933159687Snetchild	KOBJMETHOD(channel_setblocksize,	envy24chan_setblocksize),
1934159687Snetchild	KOBJMETHOD(channel_trigger,		envy24chan_trigger),
1935159687Snetchild	KOBJMETHOD(channel_getptr,		envy24chan_getptr),
1936159687Snetchild	KOBJMETHOD(channel_getcaps,		envy24chan_getcaps),
1937193640Sariff	KOBJMETHOD_END
1938159687Snetchild};
1939159687SnetchildCHANNEL_DECLARE(envy24chan);
1940159687Snetchild
1941159687Snetchild/* -------------------------------------------------------------------- */
1942159687Snetchild
1943159687Snetchild/* mixer interface */
1944159687Snetchild
1945159687Snetchildstatic int
1946159687Snetchildenvy24mixer_init(struct snd_mixer *m)
1947159687Snetchild{
1948159687Snetchild	struct sc_info *sc = mix_getdevinfo(m);
1949159687Snetchild
1950159687Snetchild#if(0)
1951159687Snetchild	device_printf(sc->dev, "envy24mixer_init()\n");
1952159687Snetchild#endif
1953159687Snetchild	if (sc == NULL)
1954159687Snetchild		return -1;
1955159687Snetchild
1956159687Snetchild	/* set volume control rate */
1957159687Snetchild	snd_mtxlock(sc->lock);
1958159687Snetchild	envy24_wrmt(sc, ENVY24_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */
1959159687Snetchild
1960159687Snetchild	mix_setdevs(m, ENVY24_MIX_MASK);
1961159687Snetchild	mix_setrecdevs(m, ENVY24_MIX_REC_MASK);
1962159687Snetchild	snd_mtxunlock(sc->lock);
1963159687Snetchild
1964159687Snetchild	return 0;
1965159687Snetchild}
1966159687Snetchild
1967159687Snetchildstatic int
1968159687Snetchildenvy24mixer_reinit(struct snd_mixer *m)
1969159687Snetchild{
1970159687Snetchild	struct sc_info *sc = mix_getdevinfo(m);
1971159687Snetchild
1972159687Snetchild	if (sc == NULL)
1973159687Snetchild		return -1;
1974159687Snetchild#if(0)
1975159687Snetchild	device_printf(sc->dev, "envy24mixer_reinit()\n");
1976159687Snetchild#endif
1977159687Snetchild
1978159687Snetchild	return 0;
1979159687Snetchild}
1980159687Snetchild
1981159687Snetchildstatic int
1982159687Snetchildenvy24mixer_uninit(struct snd_mixer *m)
1983159687Snetchild{
1984159687Snetchild	struct sc_info *sc = mix_getdevinfo(m);
1985159687Snetchild
1986159687Snetchild	if (sc == NULL)
1987159687Snetchild		return -1;
1988159687Snetchild#if(0)
1989159687Snetchild	device_printf(sc->dev, "envy24mixer_uninit()\n");
1990159687Snetchild#endif
1991159687Snetchild
1992159687Snetchild	return 0;
1993159687Snetchild}
1994159687Snetchild
1995159687Snetchildstatic int
1996159687Snetchildenvy24mixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1997159687Snetchild{
1998159687Snetchild	struct sc_info *sc = mix_getdevinfo(m);
1999159687Snetchild	int ch = envy24_mixmap[dev];
2000159687Snetchild	int hwch;
2001159687Snetchild	int i;
2002159687Snetchild
2003159687Snetchild	if (sc == NULL)
2004159687Snetchild		return -1;
2005159687Snetchild	if (dev == 0 && sc->cfg->codec->setvolume == NULL)
2006159687Snetchild		return -1;
2007159687Snetchild	if (dev != 0 && ch == -1)
2008159687Snetchild		return -1;
2009159687Snetchild	hwch = envy24_chanmap[ch];
2010159687Snetchild#if(0)
2011159687Snetchild	device_printf(sc->dev, "envy24mixer_set(m, %d, %d, %d)\n",
2012159687Snetchild	    dev, left, right);
2013159687Snetchild#endif
2014159687Snetchild
2015159687Snetchild	snd_mtxlock(sc->lock);
2016159687Snetchild	if (dev == 0) {
2017159687Snetchild		for (i = 0; i < sc->dacn; i++) {
2018159687Snetchild			sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right);
2019159687Snetchild		}
2020159687Snetchild	}
2021159687Snetchild	else {
2022159687Snetchild		/* set volume value for hardware */
2023159687Snetchild		if ((sc->left[hwch] = 100 - left) > ENVY24_VOL_MIN)
2024159687Snetchild			sc->left[hwch] = ENVY24_VOL_MUTE;
2025159687Snetchild		if ((sc->right[hwch] = 100 - right) > ENVY24_VOL_MIN)
2026159687Snetchild			sc->right[hwch] = ENVY24_VOL_MUTE;
2027159687Snetchild
2028159687Snetchild		/* set volume for record channel and running play channel */
2029159687Snetchild		if (hwch > ENVY24_CHAN_PLAY_SPDIF || sc->chan[ch].run)
2030159687Snetchild			envy24_setvolume(sc, hwch);
2031159687Snetchild	}
2032159687Snetchild	snd_mtxunlock(sc->lock);
2033159687Snetchild
2034159687Snetchild	return right << 8 | left;
2035159687Snetchild}
2036159687Snetchild
2037159687Snetchildstatic u_int32_t
2038159687Snetchildenvy24mixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
2039159687Snetchild{
2040159687Snetchild	struct sc_info *sc = mix_getdevinfo(m);
2041159687Snetchild	int ch = envy24_mixmap[src];
2042159687Snetchild#if(0)
2043159687Snetchild	device_printf(sc->dev, "envy24mixer_setrecsrc(m, %d)\n", src);
2044159687Snetchild#endif
2045159687Snetchild
2046159687Snetchild	if (ch > ENVY24_CHAN_PLAY_SPDIF)
2047159687Snetchild		sc->src = ch;
2048159687Snetchild	return src;
2049159687Snetchild}
2050159687Snetchild
2051159687Snetchildstatic kobj_method_t envy24mixer_methods[] = {
2052159687Snetchild	KOBJMETHOD(mixer_init,		envy24mixer_init),
2053159687Snetchild	KOBJMETHOD(mixer_reinit,	envy24mixer_reinit),
2054159687Snetchild	KOBJMETHOD(mixer_uninit,	envy24mixer_uninit),
2055159687Snetchild	KOBJMETHOD(mixer_set,		envy24mixer_set),
2056159687Snetchild	KOBJMETHOD(mixer_setrecsrc,	envy24mixer_setrecsrc),
2057193640Sariff	KOBJMETHOD_END
2058159687Snetchild};
2059159687SnetchildMIXER_DECLARE(envy24mixer);
2060159687Snetchild
2061159687Snetchild/* -------------------------------------------------------------------- */
2062159687Snetchild
2063159687Snetchild/* The interrupt handler */
2064159687Snetchildstatic void
2065159687Snetchildenvy24_intr(void *p)
2066159687Snetchild{
2067159687Snetchild	struct sc_info *sc = (struct sc_info *)p;
2068159687Snetchild	struct sc_chinfo *ch;
2069159687Snetchild	u_int32_t ptr, dsize, feed;
2070159687Snetchild	int i;
2071159687Snetchild
2072159687Snetchild#if(0)
2073159687Snetchild	device_printf(sc->dev, "envy24_intr()\n");
2074159687Snetchild#endif
2075159687Snetchild	snd_mtxlock(sc->lock);
2076159687Snetchild	if (envy24_checkintr(sc, PCMDIR_PLAY)) {
2077159687Snetchild#if(0)
2078159687Snetchild		device_printf(sc->dev, "envy24_intr(): play\n");
2079159687Snetchild#endif
2080159687Snetchild		dsize = sc->psize / 4;
2081159687Snetchild		ptr = dsize - envy24_rdmt(sc, ENVY24_MT_PCNT, 2) - 1;
2082159687Snetchild#if(0)
2083159687Snetchild		device_printf(sc->dev, "envy24_intr(): ptr = %d-->", ptr);
2084159687Snetchild#endif
2085159687Snetchild		ptr -= ptr % sc->blk[0];
2086159687Snetchild		feed = (ptr + dsize - sc->intr[0]) % dsize;
2087159687Snetchild#if(0)
2088159687Snetchild		printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed);
2089159687Snetchild#endif
2090159687Snetchild		for (i = ENVY24_CHAN_PLAY_DAC1; i <= ENVY24_CHAN_PLAY_SPDIF; i++) {
2091159687Snetchild			ch = &sc->chan[i];
2092159687Snetchild#if(0)
2093159687Snetchild			if (ch->run)
2094159687Snetchild				device_printf(sc->dev, "envy24_intr(): chan[%d].blk = %d\n", i, ch->blk);
2095159687Snetchild#endif
2096165306Sariff			if (ch->run && ch->blk <= feed) {
2097165306Sariff				snd_mtxunlock(sc->lock);
2098159687Snetchild				chn_intr(ch->channel);
2099165306Sariff				snd_mtxlock(sc->lock);
2100165306Sariff			}
2101159687Snetchild		}
2102159687Snetchild		sc->intr[0] = ptr;
2103159687Snetchild		envy24_updintr(sc, PCMDIR_PLAY);
2104159687Snetchild	}
2105159687Snetchild	if (envy24_checkintr(sc, PCMDIR_REC)) {
2106159687Snetchild#if(0)
2107159687Snetchild		device_printf(sc->dev, "envy24_intr(): rec\n");
2108159687Snetchild#endif
2109159687Snetchild		dsize = sc->rsize / 4;
2110159687Snetchild		ptr = dsize - envy24_rdmt(sc, ENVY24_MT_RCNT, 2) - 1;
2111159687Snetchild		ptr -= ptr % sc->blk[1];
2112159687Snetchild		feed = (ptr + dsize - sc->intr[1]) % dsize;
2113159687Snetchild		for (i = ENVY24_CHAN_REC_ADC1; i <= ENVY24_CHAN_REC_SPDIF; i++) {
2114159687Snetchild			ch = &sc->chan[i];
2115165306Sariff			if (ch->run && ch->blk <= feed) {
2116165306Sariff				snd_mtxunlock(sc->lock);
2117159687Snetchild				chn_intr(ch->channel);
2118165306Sariff				snd_mtxlock(sc->lock);
2119165306Sariff			}
2120159687Snetchild		}
2121159687Snetchild		sc->intr[1] = ptr;
2122159687Snetchild		envy24_updintr(sc, PCMDIR_REC);
2123159687Snetchild	}
2124159687Snetchild	snd_mtxunlock(sc->lock);
2125159687Snetchild
2126159687Snetchild	return;
2127159687Snetchild}
2128159687Snetchild
2129159687Snetchild/*
2130159687Snetchild * Probe and attach the card
2131159687Snetchild */
2132159687Snetchild
2133159687Snetchildstatic int
2134159687Snetchildenvy24_pci_probe(device_t dev)
2135159687Snetchild{
2136159687Snetchild	u_int16_t sv, sd;
2137159687Snetchild	int i;
2138159687Snetchild
2139159687Snetchild#if(0)
2140159687Snetchild	printf("envy24_pci_probe()\n");
2141159687Snetchild#endif
2142159687Snetchild	if (pci_get_device(dev) == PCID_ENVY24 &&
2143159687Snetchild	    pci_get_vendor(dev) == PCIV_ENVY24) {
2144159687Snetchild		sv = pci_get_subvendor(dev);
2145159687Snetchild		sd = pci_get_subdevice(dev);
2146159687Snetchild		for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2147159687Snetchild			if (cfg_table[i].subvendor == sv &&
2148159687Snetchild			    cfg_table[i].subdevice == sd) {
2149159687Snetchild				break;
2150159687Snetchild			}
2151159687Snetchild		}
2152159687Snetchild		device_set_desc(dev, cfg_table[i].name);
2153159687Snetchild#if(0)
2154159687Snetchild		printf("envy24_pci_probe(): return 0\n");
2155159687Snetchild#endif
2156159687Snetchild		return 0;
2157159687Snetchild	}
2158159687Snetchild	else {
2159159687Snetchild#if(0)
2160159687Snetchild		printf("envy24_pci_probe(): return ENXIO\n");
2161159687Snetchild#endif
2162159687Snetchild		return ENXIO;
2163159687Snetchild	}
2164159687Snetchild}
2165159687Snetchild
2166159687Snetchildstatic void
2167159687Snetchildenvy24_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2168159687Snetchild{
2169165306Sariff	/* struct sc_info *sc = (struct sc_info *)arg; */
2170159687Snetchild
2171159687Snetchild#if(0)
2172159687Snetchild	device_printf(sc->dev, "envy24_dmapsetmap()\n");
2173159687Snetchild	if (bootverbose) {
2174159687Snetchild		printf("envy24(play): setmap %lx, %lx; ",
2175159687Snetchild		    (unsigned long)segs->ds_addr,
2176159687Snetchild		    (unsigned long)segs->ds_len);
2177159687Snetchild		printf("%p -> %lx\n", sc->pmap, (unsigned long)vtophys(sc->pmap));
2178159687Snetchild	}
2179165306Sariff#endif
2180159687Snetchild}
2181159687Snetchild
2182159687Snetchildstatic void
2183159687Snetchildenvy24_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2184159687Snetchild{
2185165306Sariff	/* struct sc_info *sc = (struct sc_info *)arg; */
2186159687Snetchild
2187159687Snetchild#if(0)
2188159687Snetchild	device_printf(sc->dev, "envy24_dmarsetmap()\n");
2189159687Snetchild	if (bootverbose) {
2190159687Snetchild		printf("envy24(record): setmap %lx, %lx; ",
2191159687Snetchild		    (unsigned long)segs->ds_addr,
2192159687Snetchild		    (unsigned long)segs->ds_len);
2193159687Snetchild		printf("%p -> %lx\n", sc->rmap, (unsigned long)vtophys(sc->pmap));
2194159687Snetchild	}
2195165306Sariff#endif
2196159687Snetchild}
2197159687Snetchild
2198159687Snetchildstatic void
2199159687Snetchildenvy24_dmafree(struct sc_info *sc)
2200159687Snetchild{
2201159687Snetchild#if(0)
2202159687Snetchild	device_printf(sc->dev, "envy24_dmafree():");
2203159687Snetchild	if (sc->rmap) printf(" sc->rmap(0x%08x)", (u_int32_t)sc->rmap);
2204159687Snetchild	else printf(" sc->rmap(null)");
2205159687Snetchild	if (sc->pmap) printf(" sc->pmap(0x%08x)", (u_int32_t)sc->pmap);
2206159687Snetchild	else printf(" sc->pmap(null)");
2207159687Snetchild	if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf);
2208159687Snetchild	else printf(" sc->rbuf(null)");
2209159687Snetchild	if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf);
2210159687Snetchild	else printf(" sc->pbuf(null)\n");
2211159687Snetchild#endif
2212159687Snetchild#if(0)
2213159687Snetchild	if (sc->rmap)
2214159687Snetchild		bus_dmamap_unload(sc->dmat, sc->rmap);
2215159687Snetchild	if (sc->pmap)
2216159687Snetchild		bus_dmamap_unload(sc->dmat, sc->pmap);
2217159687Snetchild	if (sc->rbuf)
2218159687Snetchild		bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2219159687Snetchild	if (sc->pbuf)
2220159687Snetchild		bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2221159687Snetchild#else
2222159687Snetchild	bus_dmamap_unload(sc->dmat, sc->rmap);
2223159687Snetchild	bus_dmamap_unload(sc->dmat, sc->pmap);
2224159687Snetchild	bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2225159687Snetchild	bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2226159687Snetchild#endif
2227159687Snetchild
2228159687Snetchild	sc->rmap = sc->pmap = NULL;
2229159687Snetchild	sc->pbuf = NULL;
2230159687Snetchild	sc->rbuf = NULL;
2231159687Snetchild
2232159687Snetchild	return;
2233159687Snetchild}
2234159687Snetchild
2235159687Snetchildstatic int
2236159687Snetchildenvy24_dmainit(struct sc_info *sc)
2237159687Snetchild{
2238159687Snetchild	u_int32_t addr;
2239159687Snetchild
2240159687Snetchild#if(0)
2241159687Snetchild	device_printf(sc->dev, "envy24_dmainit()\n");
2242159687Snetchild#endif
2243159687Snetchild	/* init values */
2244159687Snetchild	sc->psize = ENVY24_PLAY_BUFUNIT * ENVY24_SAMPLE_NUM;
2245159687Snetchild	sc->rsize = ENVY24_REC_BUFUNIT * ENVY24_SAMPLE_NUM;
2246159687Snetchild	sc->pbuf = NULL;
2247159687Snetchild	sc->rbuf = NULL;
2248159687Snetchild	sc->pmap = sc->rmap = NULL;
2249159687Snetchild	sc->blk[0] = sc->blk[1] = 0;
2250159687Snetchild
2251159687Snetchild	/* allocate DMA buffer */
2252159687Snetchild#if(0)
2253159687Snetchild	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->pbuf\n");
2254159687Snetchild#endif
2255159687Snetchild	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap))
2256159687Snetchild		goto bad;
2257159687Snetchild#if(0)
2258159687Snetchild	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->rbuf\n");
2259159687Snetchild#endif
2260159687Snetchild	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap))
2261159687Snetchild		goto bad;
2262159687Snetchild#if(0)
2263159687Snetchild	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->pmap\n");
2264159687Snetchild#endif
2265159687Snetchild	if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24_dmapsetmap, sc, 0))
2266159687Snetchild		goto bad;
2267159687Snetchild#if(0)
2268159687Snetchild	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->rmap\n");
2269159687Snetchild#endif
2270159687Snetchild	if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24_dmarsetmap, sc, 0))
2271159687Snetchild		goto bad;
2272159687Snetchild	bzero(sc->pbuf, sc->psize);
2273159687Snetchild	bzero(sc->rbuf, sc->rsize);
2274159687Snetchild
2275159687Snetchild	/* set values to register */
2276159687Snetchild	addr = vtophys(sc->pbuf);
2277159687Snetchild#if(0)
2278159687Snetchild	device_printf(sc->dev, "pbuf(0x%08x)\n", addr);
2279159687Snetchild#endif
2280159687Snetchild	envy24_wrmt(sc, ENVY24_MT_PADDR, addr, 4);
2281159687Snetchild#if(0)
2282159687Snetchild	device_printf(sc->dev, "PADDR-->(0x%08x)\n", envy24_rdmt(sc, ENVY24_MT_PADDR, 4));
2283159687Snetchild	device_printf(sc->dev, "psize(%ld)\n", sc->psize / 4 - 1);
2284159687Snetchild#endif
2285159687Snetchild	envy24_wrmt(sc, ENVY24_MT_PCNT, sc->psize / 4 - 1, 2);
2286159687Snetchild#if(0)
2287159687Snetchild	device_printf(sc->dev, "PCNT-->(%ld)\n", envy24_rdmt(sc, ENVY24_MT_PCNT, 2));
2288159687Snetchild#endif
2289159687Snetchild	addr = vtophys(sc->rbuf);
2290159687Snetchild	envy24_wrmt(sc, ENVY24_MT_RADDR, addr, 4);
2291159687Snetchild	envy24_wrmt(sc, ENVY24_MT_RCNT, sc->rsize / 4 - 1, 2);
2292159687Snetchild
2293159687Snetchild	return 0;
2294159687Snetchild bad:
2295159687Snetchild	envy24_dmafree(sc);
2296159687Snetchild	return ENOSPC;
2297159687Snetchild}
2298159687Snetchild
2299159687Snetchildstatic void
2300159687Snetchildenvy24_putcfg(struct sc_info *sc)
2301159687Snetchild{
2302159689Snetchild	device_printf(sc->dev, "system configuration\n");
2303159687Snetchild	printf("  SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n",
2304159687Snetchild	    sc->cfg->subvendor, sc->cfg->subdevice);
2305159687Snetchild	printf("  XIN2 Clock Source: ");
2306159687Snetchild	switch (sc->cfg->scfg & PCIM_SCFG_XIN2) {
2307159687Snetchild	case 0x00:
2308159687Snetchild		printf("22.5792MHz(44.1kHz*512)\n");
2309159687Snetchild		break;
2310159687Snetchild	case 0x40:
2311159687Snetchild		printf("16.9344MHz(44.1kHz*384)\n");
2312159687Snetchild		break;
2313159687Snetchild	case 0x80:
2314159687Snetchild		printf("from external clock synthesizer chip\n");
2315159687Snetchild		break;
2316159687Snetchild	default:
2317159687Snetchild		printf("illeagal system setting\n");
2318159687Snetchild	}
2319159687Snetchild	printf("  MPU-401 UART(s) #: ");
2320159687Snetchild	if (sc->cfg->scfg & PCIM_SCFG_MPU)
2321159687Snetchild		printf("2\n");
2322159687Snetchild	else
2323159687Snetchild		printf("1\n");
2324159687Snetchild	printf("  AC'97 codec: ");
2325159687Snetchild	if (sc->cfg->scfg & PCIM_SCFG_AC97)
2326159687Snetchild		printf("not exist\n");
2327159687Snetchild	else
2328159687Snetchild		printf("exist\n");
2329159687Snetchild	printf("  ADC #: ");
2330159687Snetchild	printf("%d\n", sc->adcn);
2331159687Snetchild	printf("  DAC #: ");
2332159687Snetchild	printf("%d\n", sc->dacn);
2333159687Snetchild	printf("  Multi-track converter type: ");
2334159687Snetchild	if ((sc->cfg->acl & PCIM_ACL_MTC) == 0) {
2335159687Snetchild		printf("AC'97(SDATA_OUT:");
2336159687Snetchild		if (sc->cfg->acl & PCIM_ACL_OMODE)
2337159687Snetchild			printf("packed");
2338159687Snetchild		else
2339159687Snetchild			printf("split");
2340159687Snetchild		printf("|SDATA_IN:");
2341159687Snetchild		if (sc->cfg->acl & PCIM_ACL_IMODE)
2342159687Snetchild			printf("packed");
2343159687Snetchild		else
2344159687Snetchild			printf("split");
2345159687Snetchild		printf(")\n");
2346159687Snetchild	}
2347159687Snetchild	else {
2348159687Snetchild		printf("I2S(");
2349159687Snetchild		if (sc->cfg->i2s & PCIM_I2S_VOL)
2350159687Snetchild			printf("with volume, ");
2351159687Snetchild		if (sc->cfg->i2s & PCIM_I2S_96KHZ)
2352159687Snetchild			printf("96KHz support, ");
2353159687Snetchild		switch (sc->cfg->i2s & PCIM_I2S_RES) {
2354159687Snetchild		case PCIM_I2S_16BIT:
2355159687Snetchild			printf("16bit resolution, ");
2356159687Snetchild			break;
2357159687Snetchild		case PCIM_I2S_18BIT:
2358159687Snetchild			printf("18bit resolution, ");
2359159687Snetchild			break;
2360159687Snetchild		case PCIM_I2S_20BIT:
2361159687Snetchild			printf("20bit resolution, ");
2362159687Snetchild			break;
2363159687Snetchild		case PCIM_I2S_24BIT:
2364159687Snetchild			printf("24bit resolution, ");
2365159687Snetchild			break;
2366159687Snetchild		}
2367159687Snetchild		printf("ID#0x%x)\n", sc->cfg->i2s & PCIM_I2S_ID);
2368159687Snetchild	}
2369159687Snetchild	printf("  S/PDIF(IN/OUT): ");
2370159687Snetchild	if (sc->cfg->spdif & PCIM_SPDIF_IN)
2371159687Snetchild		printf("1/");
2372159687Snetchild	else
2373159687Snetchild		printf("0/");
2374159687Snetchild	if (sc->cfg->spdif & PCIM_SPDIF_OUT)
2375159687Snetchild		printf("1 ");
2376159687Snetchild	else
2377159687Snetchild		printf("0 ");
2378159687Snetchild	if (sc->cfg->spdif & (PCIM_SPDIF_IN | PCIM_SPDIF_OUT))
2379159687Snetchild		printf("ID# 0x%02x\n", (sc->cfg->spdif & PCIM_SPDIF_ID) >> 2);
2380159687Snetchild	printf("  GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n",
2381159687Snetchild	    sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate);
2382159687Snetchild}
2383159687Snetchild
2384159687Snetchildstatic int
2385159687Snetchildenvy24_init(struct sc_info *sc)
2386159687Snetchild{
2387159687Snetchild	u_int32_t data;
2388159687Snetchild#if(0)
2389159687Snetchild	int rtn;
2390159687Snetchild#endif
2391159687Snetchild	int i;
2392159687Snetchild	u_int32_t sv, sd;
2393159687Snetchild
2394159687Snetchild
2395159687Snetchild#if(0)
2396159687Snetchild	device_printf(sc->dev, "envy24_init()\n");
2397159687Snetchild#endif
2398159687Snetchild
2399159687Snetchild	/* reset chip */
2400159687Snetchild	envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_RESET | ENVY24_CCS_CTL_NATIVE, 1);
2401159687Snetchild	DELAY(200);
2402159687Snetchild	envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_NATIVE, 1);
2403159687Snetchild	DELAY(200);
2404159687Snetchild
2405159687Snetchild	/* legacy hardware disable */
2406159687Snetchild	data = pci_read_config(sc->dev, PCIR_LAC, 2);
2407159687Snetchild	data |= PCIM_LAC_DISABLE;
2408159687Snetchild	pci_write_config(sc->dev, PCIR_LAC, data, 2);
2409159687Snetchild
2410159687Snetchild	/* check system configuration */
2411159687Snetchild	sc->cfg = NULL;
2412159687Snetchild	for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2413159687Snetchild		/* 1st: search configuration from table */
2414159687Snetchild		sv = pci_get_subvendor(sc->dev);
2415159687Snetchild		sd = pci_get_subdevice(sc->dev);
2416159687Snetchild		if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) {
2417159687Snetchild#if(0)
2418159687Snetchild			device_printf(sc->dev, "Set configuration from table\n");
2419159687Snetchild#endif
2420159687Snetchild			sc->cfg = &cfg_table[i];
2421159687Snetchild			break;
2422159687Snetchild		}
2423159687Snetchild	}
2424159687Snetchild	if (sc->cfg == NULL) {
2425159687Snetchild		/* 2nd: read configuration from table */
2426159687Snetchild		sc->cfg = envy24_rom2cfg(sc);
2427159687Snetchild	}
2428159687Snetchild	sc->adcn = ((sc->cfg->scfg & PCIM_SCFG_ADC) >> 2) + 1;
2429159687Snetchild	sc->dacn = (sc->cfg->scfg & PCIM_SCFG_DAC) + 1;
2430159687Snetchild
2431159687Snetchild	if (1 /* bootverbose */) {
2432159687Snetchild		envy24_putcfg(sc);
2433159687Snetchild	}
2434159687Snetchild
2435159687Snetchild	/* set system configuration */
2436159687Snetchild	pci_write_config(sc->dev, PCIR_SCFG, sc->cfg->scfg, 1);
2437159687Snetchild	pci_write_config(sc->dev, PCIR_ACL, sc->cfg->acl, 1);
2438159687Snetchild	pci_write_config(sc->dev, PCIR_I2S, sc->cfg->i2s, 1);
2439159687Snetchild	pci_write_config(sc->dev, PCIR_SPDIF, sc->cfg->spdif, 1);
2440159687Snetchild	envy24_gpiosetmask(sc, sc->cfg->gpiomask);
2441159687Snetchild	envy24_gpiosetdir(sc, sc->cfg->gpiodir);
2442159687Snetchild	envy24_gpiowr(sc, sc->cfg->gpiostate);
2443159687Snetchild	for (i = 0; i < sc->adcn; i++) {
2444159687Snetchild		sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i);
2445159687Snetchild		sc->cfg->codec->init(sc->adc[i]);
2446159687Snetchild	}
2447159687Snetchild	for (i = 0; i < sc->dacn; i++) {
2448159687Snetchild		sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i);
2449159687Snetchild		sc->cfg->codec->init(sc->dac[i]);
2450159687Snetchild	}
2451159687Snetchild
2452159687Snetchild	/* initialize DMA buffer */
2453159687Snetchild#if(0)
2454159687Snetchild	device_printf(sc->dev, "envy24_init(): initialize DMA buffer\n");
2455159687Snetchild#endif
2456159687Snetchild	if (envy24_dmainit(sc))
2457159687Snetchild		return ENOSPC;
2458159687Snetchild
2459159687Snetchild	/* initialize status */
2460159687Snetchild	sc->run[0] = sc->run[1] = 0;
2461159687Snetchild	sc->intr[0] = sc->intr[1] = 0;
2462159687Snetchild	sc->speed = 0;
2463159687Snetchild	sc->caps[0].fmtlist = envy24_playfmt;
2464159687Snetchild	sc->caps[1].fmtlist = envy24_recfmt;
2465159687Snetchild
2466159687Snetchild	/* set channel router */
2467159687Snetchild	envy24_route(sc, ENVY24_ROUTE_DAC_1, ENVY24_ROUTE_CLASS_MIX, 0, 0);
2468159687Snetchild	envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_DMA, 0, 0);
2469159687Snetchild	/* envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_MIX, 0, 0); */
2470159687Snetchild
2471159687Snetchild	/* set macro interrupt mask */
2472159687Snetchild	data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1);
2473159687Snetchild	envy24_wrcs(sc, ENVY24_CCS_IMASK, data & ~ENVY24_CCS_IMASK_PMT, 1);
2474159687Snetchild	data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1);
2475159687Snetchild#if(0)
2476159687Snetchild	device_printf(sc->dev, "envy24_init(): CCS_IMASK-->0x%02x\n", data);
2477159687Snetchild#endif
2478159687Snetchild
2479159687Snetchild	return 0;
2480159687Snetchild}
2481159687Snetchild
2482159687Snetchildstatic int
2483166919Sariffenvy24_alloc_resource(struct sc_info *sc)
2484159687Snetchild{
2485159687Snetchild	/* allocate I/O port resource */
2486159687Snetchild	sc->csid = PCIR_CCS;
2487159687Snetchild	sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2488159687Snetchild	    &sc->csid, 0, ~0, 1, RF_ACTIVE);
2489159687Snetchild	sc->ddmaid = PCIR_DDMA;
2490159687Snetchild	sc->ddma = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2491159687Snetchild	    &sc->ddmaid, 0, ~0, 1, RF_ACTIVE);
2492159687Snetchild	sc->dsid = PCIR_DS;
2493159687Snetchild	sc->ds = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2494159687Snetchild	    &sc->dsid, 0, ~0, 1, RF_ACTIVE);
2495159687Snetchild	sc->mtid = PCIR_MT;
2496159687Snetchild	sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2497159687Snetchild	    &sc->mtid, 0, ~0, 1, RF_ACTIVE);
2498159687Snetchild	if (!sc->cs || !sc->ddma || !sc->ds || !sc->mt) {
2499159687Snetchild		device_printf(sc->dev, "unable to map IO port space\n");
2500159687Snetchild		return ENXIO;
2501159687Snetchild	}
2502159687Snetchild	sc->cst = rman_get_bustag(sc->cs);
2503159687Snetchild	sc->csh = rman_get_bushandle(sc->cs);
2504159687Snetchild	sc->ddmat = rman_get_bustag(sc->ddma);
2505159687Snetchild	sc->ddmah = rman_get_bushandle(sc->ddma);
2506159687Snetchild	sc->dst = rman_get_bustag(sc->ds);
2507159687Snetchild	sc->dsh = rman_get_bushandle(sc->ds);
2508159687Snetchild	sc->mtt = rman_get_bustag(sc->mt);
2509159687Snetchild	sc->mth = rman_get_bushandle(sc->mt);
2510159687Snetchild#if(0)
2511159687Snetchild	device_printf(sc->dev,
2512159687Snetchild	    "IO port register values\nCCS: 0x%lx\nDDMA: 0x%lx\nDS: 0x%lx\nMT: 0x%lx\n",
2513159687Snetchild	    pci_read_config(sc->dev, PCIR_CCS, 4),
2514159687Snetchild	    pci_read_config(sc->dev, PCIR_DDMA, 4),
2515159687Snetchild	    pci_read_config(sc->dev, PCIR_DS, 4),
2516159687Snetchild	    pci_read_config(sc->dev, PCIR_MT, 4));
2517159687Snetchild#endif
2518159687Snetchild
2519172568Skevlo	/* allocate interrupt resource */
2520159687Snetchild	sc->irqid = 0;
2521159687Snetchild	sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid,
2522159687Snetchild				 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
2523159687Snetchild	if (!sc->irq ||
2524159687Snetchild	    snd_setup_intr(sc->dev, sc->irq, INTR_MPSAFE, envy24_intr, sc, &sc->ih)) {
2525159687Snetchild		device_printf(sc->dev, "unable to map interrupt\n");
2526159687Snetchild		return ENXIO;
2527159687Snetchild	}
2528159687Snetchild
2529159687Snetchild	/* allocate DMA resource */
2530166919Sariff	if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev),
2531166919Sariff	    /*alignment*/4,
2532166904Snetchild	    /*boundary*/0,
2533159687Snetchild	    /*lowaddr*/BUS_SPACE_MAXADDR_ENVY24,
2534159687Snetchild	    /*highaddr*/BUS_SPACE_MAXADDR_ENVY24,
2535159687Snetchild	    /*filter*/NULL, /*filterarg*/NULL,
2536159687Snetchild	    /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24,
2537159687Snetchild	    /*nsegments*/1, /*maxsegsz*/0x3ffff,
2538159689Snetchild	    /*flags*/0, /*lockfunc*/busdma_lock_mutex,
2539159689Snetchild	    /*lockarg*/&Giant, &sc->dmat) != 0) {
2540159687Snetchild		device_printf(sc->dev, "unable to create dma tag\n");
2541159687Snetchild		return ENXIO;
2542159687Snetchild	}
2543159687Snetchild
2544159687Snetchild	return 0;
2545159687Snetchild}
2546159687Snetchild
2547159687Snetchildstatic int
2548159687Snetchildenvy24_pci_attach(device_t dev)
2549159687Snetchild{
2550159687Snetchild	struct sc_info 		*sc;
2551159687Snetchild	char 			status[SND_STATUSLEN];
2552159687Snetchild	int			err = 0;
2553159687Snetchild	int			i;
2554159687Snetchild
2555159687Snetchild#if(0)
2556159687Snetchild	device_printf(dev, "envy24_pci_attach()\n");
2557159687Snetchild#endif
2558159687Snetchild	/* get sc_info data area */
2559159687Snetchild	if ((sc = malloc(sizeof(*sc), M_ENVY24, M_NOWAIT)) == NULL) {
2560159687Snetchild		device_printf(dev, "cannot allocate softc\n");
2561159687Snetchild		return ENXIO;
2562159687Snetchild	}
2563159687Snetchild
2564159687Snetchild	bzero(sc, sizeof(*sc));
2565167608Sariff	sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_envy24 softc");
2566159687Snetchild	sc->dev = dev;
2567159687Snetchild
2568159687Snetchild	/* initialize PCI interface */
2569254263Sscottl	pci_enable_busmaster(dev);
2570159687Snetchild
2571159687Snetchild	/* allocate resources */
2572166919Sariff	err = envy24_alloc_resource(sc);
2573159689Snetchild	if (err) {
2574159687Snetchild		device_printf(dev, "unable to allocate system resources\n");
2575159687Snetchild		goto bad;
2576159687Snetchild	}
2577159687Snetchild
2578159687Snetchild	/* initialize card */
2579159689Snetchild	err = envy24_init(sc);
2580159689Snetchild	if (err) {
2581159687Snetchild		device_printf(dev, "unable to initialize the card\n");
2582159687Snetchild		goto bad;
2583159687Snetchild	}
2584159687Snetchild
2585159687Snetchild	/* set multi track mixer */
2586159687Snetchild	mixer_init(dev, &envy24mixer_class, sc);
2587159687Snetchild
2588159687Snetchild	/* set channel information */
2589170031Sjoel	err = pcm_register(dev, sc, 5, 2 + sc->adcn);
2590159689Snetchild	if (err)
2591159687Snetchild		goto bad;
2592170031Sjoel	sc->chnum = 0;
2593170031Sjoel	for (i = 0; i < 5; i++) {
2594159687Snetchild		pcm_addchan(dev, PCMDIR_PLAY, &envy24chan_class, sc);
2595159687Snetchild		sc->chnum++;
2596159687Snetchild	}
2597170031Sjoel	for (i = 0; i < 2 + sc->adcn; i++) {
2598159687Snetchild		pcm_addchan(dev, PCMDIR_REC, &envy24chan_class, sc);
2599159687Snetchild		sc->chnum++;
2600159687Snetchild	}
2601159687Snetchild
2602159687Snetchild	/* set status iformation */
2603159687Snetchild	snprintf(status, SND_STATUSLEN,
2604159687Snetchild	    "at io 0x%lx:%ld,0x%lx:%ld,0x%lx:%ld,0x%lx:%ld irq %ld",
2605159687Snetchild	    rman_get_start(sc->cs),
2606159687Snetchild	    rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1,
2607159687Snetchild	    rman_get_start(sc->ddma),
2608159687Snetchild	    rman_get_end(sc->ddma) - rman_get_start(sc->ddma) + 1,
2609159687Snetchild	    rman_get_start(sc->ds),
2610159687Snetchild	    rman_get_end(sc->ds) - rman_get_start(sc->ds) + 1,
2611159687Snetchild	    rman_get_start(sc->mt),
2612159687Snetchild	    rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1,
2613159687Snetchild	    rman_get_start(sc->irq));
2614159687Snetchild	pcm_setstatus(dev, status);
2615159687Snetchild
2616159687Snetchild	return 0;
2617159687Snetchild
2618159687Snetchildbad:
2619159687Snetchild	if (sc->ih)
2620159687Snetchild		bus_teardown_intr(dev, sc->irq, sc->ih);
2621159687Snetchild	if (sc->irq)
2622159687Snetchild		bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2623159687Snetchild	envy24_dmafree(sc);
2624159687Snetchild	if (sc->dmat)
2625159687Snetchild		bus_dma_tag_destroy(sc->dmat);
2626160796Snetchild	if (sc->cfg->codec->destroy != NULL) {
2627160796Snetchild                for (i = 0; i < sc->adcn; i++)
2628160796Snetchild                        sc->cfg->codec->destroy(sc->adc[i]);
2629160796Snetchild                for (i = 0; i < sc->dacn; i++)
2630160796Snetchild                        sc->cfg->codec->destroy(sc->dac[i]);
2631160796Snetchild        }
2632159687Snetchild	envy24_cfgfree(sc->cfg);
2633159687Snetchild	if (sc->cs)
2634159687Snetchild		bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2635159687Snetchild	if (sc->ddma)
2636159687Snetchild		bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma);
2637159687Snetchild	if (sc->ds)
2638159687Snetchild		bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds);
2639159687Snetchild	if (sc->mt)
2640159687Snetchild		bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2641159687Snetchild	if (sc->lock)
2642159687Snetchild		snd_mtxfree(sc->lock);
2643159687Snetchild	free(sc, M_ENVY24);
2644159687Snetchild	return err;
2645159687Snetchild}
2646159687Snetchild
2647159687Snetchildstatic int
2648159687Snetchildenvy24_pci_detach(device_t dev)
2649159687Snetchild{
2650159687Snetchild	struct sc_info *sc;
2651159687Snetchild	int r;
2652159687Snetchild	int i;
2653159687Snetchild
2654159687Snetchild#if(0)
2655159687Snetchild	device_printf(dev, "envy24_pci_detach()\n");
2656159687Snetchild#endif
2657159687Snetchild	sc = pcm_getdevinfo(dev);
2658159687Snetchild	if (sc == NULL)
2659159687Snetchild		return 0;
2660159687Snetchild	r = pcm_unregister(dev);
2661159687Snetchild	if (r)
2662159687Snetchild		return r;
2663159687Snetchild
2664159687Snetchild	envy24_dmafree(sc);
2665159687Snetchild	if (sc->cfg->codec->destroy != NULL) {
2666159687Snetchild		for (i = 0; i < sc->adcn; i++)
2667159687Snetchild			sc->cfg->codec->destroy(sc->adc[i]);
2668159687Snetchild		for (i = 0; i < sc->dacn; i++)
2669159687Snetchild			sc->cfg->codec->destroy(sc->dac[i]);
2670159687Snetchild	}
2671159687Snetchild	envy24_cfgfree(sc->cfg);
2672159687Snetchild	bus_dma_tag_destroy(sc->dmat);
2673159687Snetchild	bus_teardown_intr(dev, sc->irq, sc->ih);
2674159687Snetchild	bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2675159687Snetchild	bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2676159687Snetchild	bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma);
2677159687Snetchild	bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds);
2678159687Snetchild	bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2679159687Snetchild	snd_mtxfree(sc->lock);
2680159687Snetchild	free(sc, M_ENVY24);
2681159687Snetchild	return 0;
2682159687Snetchild}
2683159687Snetchild
2684159687Snetchildstatic device_method_t envy24_methods[] = {
2685159687Snetchild	/* Device interface */
2686159687Snetchild	DEVMETHOD(device_probe,		envy24_pci_probe),
2687159687Snetchild	DEVMETHOD(device_attach,	envy24_pci_attach),
2688159687Snetchild	DEVMETHOD(device_detach,	envy24_pci_detach),
2689159687Snetchild	{ 0, 0 }
2690159687Snetchild};
2691159687Snetchild
2692159687Snetchildstatic driver_t envy24_driver = {
2693159687Snetchild	"pcm",
2694159687Snetchild	envy24_methods,
2695159687Snetchild#if __FreeBSD_version > 500000
2696159687Snetchild	PCM_SOFTC_SIZE,
2697159687Snetchild#else
2698159687Snetchild	sizeof(struct snddev_info),
2699159687Snetchild#endif
2700159687Snetchild};
2701159687Snetchild
2702159687SnetchildDRIVER_MODULE(snd_envy24, pci, envy24_driver, pcm_devclass, 0, 0);
2703159689SnetchildMODULE_DEPEND(snd_envy24, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
2704168883SariffMODULE_DEPEND(snd_envy24, snd_spicds, 1, 1, 1);
2705159687SnetchildMODULE_VERSION(snd_envy24, 1);
2706