envy24.c revision 188480
1/*
2 * Copyright (c) 2001 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 */
27
28#include <dev/sound/pcm/sound.h>
29#include <dev/sound/pcm/ac97.h>
30#include <dev/sound/pci/spicds.h>
31#include <dev/sound/pci/envy24.h>
32
33#include <dev/pci/pcireg.h>
34#include <dev/pci/pcivar.h>
35
36#include "mixer_if.h"
37
38SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/envy24.c 188480 2009-02-11 10:29:45Z netchild $");
39
40MALLOC_DEFINE(M_ENVY24, "envy24", "envy24 audio");
41
42/* -------------------------------------------------------------------- */
43
44struct sc_info;
45
46#define ENVY24_PLAY_CHNUM 10
47#define ENVY24_REC_CHNUM 12
48#define ENVY24_PLAY_BUFUNIT (4 /* byte/sample */ * 10 /* channel */)
49#define ENVY24_REC_BUFUNIT  (4 /* byte/sample */ * 12 /* channel */)
50#define ENVY24_SAMPLE_NUM   4096
51
52#define ENVY24_TIMEOUT 1000
53
54#define ENVY24_DEFAULT_FORMAT (AFMT_STEREO | AFMT_S16_LE)
55
56#define ENVY24_NAMELEN 32
57
58#define SDA_GPIO 0x10
59#define SCL_GPIO 0x20
60
61struct envy24_sample {
62        volatile u_int32_t buffer;
63};
64
65typedef struct envy24_sample sample32_t;
66
67/* channel registers */
68struct sc_chinfo {
69	struct snd_dbuf		*buffer;
70	struct pcm_channel	*channel;
71	struct sc_info		*parent;
72	int			dir;
73	unsigned		num; /* hw channel number */
74
75	/* channel information */
76	u_int32_t		format;
77	u_int32_t		speed;
78	u_int32_t		blk; /* hw block size(dword) */
79
80	/* format conversion structure */
81	u_int8_t		*data;
82	unsigned int		size; /* data buffer size(byte) */
83	int			unit; /* sample size(byte) */
84	unsigned int		offset; /* samples number offset */
85	void			(*emldma)(struct sc_chinfo *);
86
87	/* flags */
88	int			run;
89};
90
91/* codec interface entrys */
92struct codec_entry {
93	void *(*create)(device_t dev, void *devinfo, int dir, int num);
94	void (*destroy)(void *codec);
95	void (*init)(void *codec);
96	void (*reinit)(void *codec);
97	void (*setvolume)(void *codec, int dir, unsigned int left, unsigned int right);
98	void (*setrate)(void *codec, int which, int rate);
99};
100
101/* system configuration information */
102struct cfg_info {
103	char *name;
104	u_int16_t subvendor, subdevice;
105	u_int8_t scfg, acl, i2s, spdif;
106	u_int8_t gpiomask, gpiostate, gpiodir;
107	u_int8_t cdti, cclk, cs, cif, type;
108	u_int8_t free;
109	struct codec_entry *codec;
110};
111
112/* device private data */
113struct sc_info {
114	device_t	dev;
115	struct mtx	*lock;
116
117	/* Control/Status registor */
118	struct resource *cs;
119	int		csid;
120	bus_space_tag_t cst;
121	bus_space_handle_t csh;
122	/* DDMA registor */
123	struct resource *ddma;
124	int		ddmaid;
125	bus_space_tag_t ddmat;
126	bus_space_handle_t ddmah;
127	/* Consumer Section DMA Channel Registers */
128	struct resource *ds;
129	int		dsid;
130	bus_space_tag_t dst;
131	bus_space_handle_t dsh;
132	/* MultiTrack registor */
133	struct resource *mt;
134	int		mtid;
135	bus_space_tag_t mtt;
136	bus_space_handle_t mth;
137	/* DMA tag */
138	bus_dma_tag_t dmat;
139	/* IRQ resource */
140	struct resource *irq;
141	int		irqid;
142	void		*ih;
143
144	/* system configuration data */
145	struct cfg_info *cfg;
146
147	/* ADC/DAC number and info */
148	int		adcn, dacn;
149	void		*adc[4], *dac[4];
150
151	/* mixer control data */
152	u_int32_t	src;
153	u_int8_t	left[ENVY24_CHAN_NUM];
154	u_int8_t	right[ENVY24_CHAN_NUM];
155
156	/* Play/Record DMA fifo */
157	sample32_t	*pbuf;
158	sample32_t	*rbuf;
159	u_int32_t	psize, rsize; /* DMA buffer size(byte) */
160	u_int16_t	blk[2]; /* transfer check blocksize(dword) */
161	bus_dmamap_t	pmap, rmap;
162
163	/* current status */
164	u_int32_t	speed;
165	int		run[2];
166	u_int16_t	intr[2];
167	struct pcmchan_caps	caps[2];
168
169	/* channel info table */
170	unsigned	chnum;
171	struct sc_chinfo chan[11];
172};
173
174/* -------------------------------------------------------------------- */
175
176/*
177 * prototypes
178 */
179
180/* DMA emulator */
181static void envy24_p8u(struct sc_chinfo *);
182static void envy24_p16sl(struct sc_chinfo *);
183static void envy24_p32sl(struct sc_chinfo *);
184static void envy24_r16sl(struct sc_chinfo *);
185static void envy24_r32sl(struct sc_chinfo *);
186
187/* channel interface */
188static void *envy24chan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int);
189static int envy24chan_setformat(kobj_t, void *, u_int32_t);
190static int envy24chan_setspeed(kobj_t, void *, u_int32_t);
191static int envy24chan_setblocksize(kobj_t, void *, u_int32_t);
192static int envy24chan_trigger(kobj_t, void *, int);
193static int envy24chan_getptr(kobj_t, void *);
194static struct pcmchan_caps *envy24chan_getcaps(kobj_t, void *);
195
196/* mixer interface */
197static int envy24mixer_init(struct snd_mixer *);
198static int envy24mixer_reinit(struct snd_mixer *);
199static int envy24mixer_uninit(struct snd_mixer *);
200static int envy24mixer_set(struct snd_mixer *, unsigned, unsigned, unsigned);
201static u_int32_t envy24mixer_setrecsrc(struct snd_mixer *, u_int32_t);
202
203/* M-Audio Delta series AK4524 access interface */
204static void *envy24_delta_ak4524_create(device_t, void *, int, int);
205static void envy24_delta_ak4524_destroy(void *);
206static void envy24_delta_ak4524_init(void *);
207static void envy24_delta_ak4524_reinit(void *);
208static void envy24_delta_ak4524_setvolume(void *, int, unsigned int, unsigned int);
209
210/* -------------------------------------------------------------------- */
211
212/*
213  system constant tables
214*/
215
216/* API -> hardware channel map */
217static unsigned envy24_chanmap[ENVY24_CHAN_NUM] = {
218	ENVY24_CHAN_PLAY_SPDIF, /* 0 */
219	ENVY24_CHAN_PLAY_DAC1,  /* 1 */
220	ENVY24_CHAN_PLAY_DAC2,  /* 2 */
221	ENVY24_CHAN_PLAY_DAC3,  /* 3 */
222	ENVY24_CHAN_PLAY_DAC4,  /* 4 */
223	ENVY24_CHAN_REC_MIX,    /* 5 */
224	ENVY24_CHAN_REC_SPDIF,  /* 6 */
225	ENVY24_CHAN_REC_ADC1,   /* 7 */
226	ENVY24_CHAN_REC_ADC2,   /* 8 */
227	ENVY24_CHAN_REC_ADC3,   /* 9 */
228	ENVY24_CHAN_REC_ADC4,   /* 10 */
229};
230
231/* mixer -> API channel map. see above */
232static int envy24_mixmap[] = {
233	-1, /* Master output level. It is depend on codec support */
234	-1, /* Treble level of all output channels */
235	-1, /* Bass level of all output channels */
236	-1, /* Volume of synthesier input */
237	0,  /* Output level for the audio device */
238	-1, /* Output level for the PC speaker */
239	7,  /* line in jack */
240	-1, /* microphone jack */
241	-1, /* CD audio input */
242	-1, /* Recording monitor */
243	1,  /* alternative codec */
244	-1, /* global recording level */
245	-1, /* Input gain */
246	-1, /* Output gain */
247	8,  /* Input source 1 */
248	9,  /* Input source 2 */
249	10, /* Input source 3 */
250	6,  /* Digital (input) 1 */
251	-1, /* Digital (input) 2 */
252	-1, /* Digital (input) 3 */
253	-1, /* Phone input */
254	-1, /* Phone output */
255	-1, /* Video/TV (audio) in */
256	-1, /* Radio in */
257	-1, /* Monitor volume */
258};
259
260/* variable rate audio */
261static u_int32_t envy24_speed[] = {
262    96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000,
263    12000, 11025, 9600, 8000, 0
264};
265
266/* known boards configuration */
267static struct codec_entry delta_codec = {
268	envy24_delta_ak4524_create,
269	envy24_delta_ak4524_destroy,
270	envy24_delta_ak4524_init,
271	envy24_delta_ak4524_reinit,
272	envy24_delta_ak4524_setvolume,
273	NULL, /* setrate */
274};
275
276static struct cfg_info cfg_table[] = {
277	{
278		"Envy24 audio (M Audio Delta Dio 2496)",
279		0x1412, 0xd631,
280		0x10, 0x80, 0xf0, 0x03,
281		0x02, 0xc0, 0xfd,
282		0x10, 0x20, 0x40, 0x00, 0x00,
283		0x00,
284		&delta_codec,
285	},
286	{
287		"Envy24 audio (Terratec DMX 6fire)",
288		0x153b, 0x1138,
289		0x2f, 0x80, 0xf0, 0x03,
290		0xc0, 0xff, 0x7f,
291		0x10, 0x20, 0x01, 0x01, 0x00,
292		0x00,
293 		&delta_codec,
294 	},
295	{
296		"Envy24 audio (M Audio Audiophile 2496)",
297		0x1412, 0xd634,
298		0x10, 0x80, 0x72, 0x03,
299		0x04, 0xfe, 0xfb,
300		0x08, 0x02, 0x20, 0x00, 0x01,
301		0x00,
302 		&delta_codec,
303 	},
304        {
305                "Envy24 audio (M Audio Delta 66)",
306                0x1412, 0xd632,
307                0x15, 0x80, 0xf0, 0x03,
308                0x02, 0xc0, 0xfd,
309                0x10, 0x20, 0x40, 0x00, 0x00,
310                0x00,
311                &delta_codec,
312        },
313        {
314                "Envy24 audio (M Audio Delta 44)",
315                0x1412, 0xd633,
316                0x15, 0x80, 0xf0, 0x00,
317                0x02, 0xc0, 0xfd,
318                0x10, 0x20, 0x40, 0x00, 0x00,
319                0x00,
320                &delta_codec,
321        },
322        {
323                "Envy24 audio (M Audio Delta 1010)",
324                0x1412, 0xd630,
325                0x1f, 0x80, 0xf0, 0x03,
326                0x22, 0xd0, 0xdd,
327                0x10, 0x20, 0x40, 0x00, 0x00,
328                0x00,
329                &delta_codec,
330        },
331        {
332                "Envy24 audio (M Audio Delta 1010LT)",
333                0x1412, 0xd63b,
334                0x1f, 0x80, 0x72, 0x03,
335                0x04, 0x7e, 0xfb,
336                0x08, 0x02, 0x70, 0x00, 0x00,
337                0x00,
338                &delta_codec,
339        },
340        {
341                "Envy24 audio (Terratec EWX 2496)",
342                0x153b, 0x1130,
343                0x10, 0x80, 0xf0, 0x03,
344                0xc0, 0x3f, 0x3f,
345                0x10, 0x20, 0x01, 0x01, 0x00,
346                0x00,
347                &delta_codec,
348        },
349	{
350		"Envy24 audio (Generic)",
351		0, 0,
352		0x0f, 0x00, 0x01, 0x03,
353		0xff, 0x00, 0x00,
354		0x10, 0x20, 0x40, 0x00, 0x00,
355		0x00,
356		&delta_codec, /* default codec routines */
357	}
358};
359
360static u_int32_t envy24_recfmt[] = {
361	AFMT_STEREO | AFMT_S16_LE,
362	AFMT_STEREO | AFMT_S32_LE,
363	0
364};
365static struct pcmchan_caps envy24_reccaps = {8000, 96000, envy24_recfmt, 0};
366
367static u_int32_t envy24_playfmt[] = {
368	AFMT_STEREO | AFMT_U8,
369	AFMT_STEREO | AFMT_S16_LE,
370	AFMT_STEREO | AFMT_S32_LE,
371	0
372};
373
374static struct pcmchan_caps envy24_playcaps = {8000, 96000, envy24_playfmt, 0};
375
376struct envy24_emldma {
377	u_int32_t	format;
378	void		(*emldma)(struct sc_chinfo *);
379	int		unit;
380};
381
382static struct envy24_emldma envy24_pemltab[] = {
383	{AFMT_STEREO | AFMT_U8, envy24_p8u, 2},
384	{AFMT_STEREO | AFMT_S16_LE, envy24_p16sl, 4},
385	{AFMT_STEREO | AFMT_S32_LE, envy24_p32sl, 8},
386	{0, NULL, 0}
387};
388
389static struct envy24_emldma envy24_remltab[] = {
390	{AFMT_STEREO | AFMT_S16_LE, envy24_r16sl, 4},
391	{AFMT_STEREO | AFMT_S32_LE, envy24_r32sl, 8},
392	{0, NULL, 0}
393};
394
395/* -------------------------------------------------------------------- */
396
397/* common routines */
398static u_int32_t
399envy24_rdcs(struct sc_info *sc, int regno, int size)
400{
401	switch (size) {
402	case 1:
403		return bus_space_read_1(sc->cst, sc->csh, regno);
404	case 2:
405		return bus_space_read_2(sc->cst, sc->csh, regno);
406	case 4:
407		return bus_space_read_4(sc->cst, sc->csh, regno);
408	default:
409		return 0xffffffff;
410	}
411}
412
413static void
414envy24_wrcs(struct sc_info *sc, int regno, u_int32_t data, int size)
415{
416	switch (size) {
417	case 1:
418		bus_space_write_1(sc->cst, sc->csh, regno, data);
419		break;
420	case 2:
421		bus_space_write_2(sc->cst, sc->csh, regno, data);
422		break;
423	case 4:
424		bus_space_write_4(sc->cst, sc->csh, regno, data);
425		break;
426	}
427}
428
429static u_int32_t
430envy24_rdmt(struct sc_info *sc, int regno, int size)
431{
432	switch (size) {
433	case 1:
434		return bus_space_read_1(sc->mtt, sc->mth, regno);
435	case 2:
436		return bus_space_read_2(sc->mtt, sc->mth, regno);
437	case 4:
438		return bus_space_read_4(sc->mtt, sc->mth, regno);
439	default:
440		return 0xffffffff;
441	}
442}
443
444static void
445envy24_wrmt(struct sc_info *sc, int regno, u_int32_t data, int size)
446{
447	switch (size) {
448	case 1:
449		bus_space_write_1(sc->mtt, sc->mth, regno, data);
450		break;
451	case 2:
452		bus_space_write_2(sc->mtt, sc->mth, regno, data);
453		break;
454	case 4:
455		bus_space_write_4(sc->mtt, sc->mth, regno, data);
456		break;
457	}
458}
459
460static u_int32_t
461envy24_rdci(struct sc_info *sc, int regno)
462{
463	envy24_wrcs(sc, ENVY24_CCS_INDEX, regno, 1);
464	return envy24_rdcs(sc, ENVY24_CCS_DATA, 1);
465}
466
467static void
468envy24_wrci(struct sc_info *sc, int regno, u_int32_t data)
469{
470	envy24_wrcs(sc, ENVY24_CCS_INDEX, regno, 1);
471	envy24_wrcs(sc, ENVY24_CCS_DATA, data, 1);
472}
473
474/* -------------------------------------------------------------------- */
475
476/* I2C port/E2PROM access routines */
477
478static int
479envy24_rdi2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr)
480{
481	u_int32_t data;
482	int i;
483
484#if(0)
485	device_printf(sc->dev, "envy24_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
486#endif
487	for (i = 0; i < ENVY24_TIMEOUT; i++) {
488		data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
489		if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0)
490			break;
491		DELAY(32); /* 31.25kHz */
492	}
493	if (i == ENVY24_TIMEOUT) {
494		return -1;
495	}
496	envy24_wrcs(sc, ENVY24_CCS_I2CADDR, addr, 1);
497	envy24_wrcs(sc, ENVY24_CCS_I2CDEV,
498	    (dev & ENVY24_CCS_I2CDEV_ADDR) | ENVY24_CCS_I2CDEV_RD, 1);
499	for (i = 0; i < ENVY24_TIMEOUT; i++) {
500		data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
501		if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0)
502			break;
503		DELAY(32); /* 31.25kHz */
504	}
505	if (i == ENVY24_TIMEOUT) {
506		return -1;
507	}
508	data = envy24_rdcs(sc, ENVY24_CCS_I2CDATA, 1);
509
510#if(0)
511	device_printf(sc->dev, "envy24_rdi2c(): return 0x%x\n", data);
512#endif
513	return (int)data;
514}
515
516#if 0
517static int
518envy24_wri2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr, u_int32_t data)
519{
520	u_int32_t tmp;
521	int i;
522
523#if(0)
524	device_printf(sc->dev, "envy24_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr);
525#endif
526	for (i = 0; i < ENVY24_TIMEOUT; i++) {
527		tmp = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
528		if ((tmp & ENVY24_CCS_I2CSTAT_BSY) == 0)
529			break;
530		DELAY(32); /* 31.25kHz */
531	}
532	if (i == ENVY24_TIMEOUT) {
533		return -1;
534	}
535	envy24_wrcs(sc, ENVY24_CCS_I2CADDR, addr, 1);
536	envy24_wrcs(sc, ENVY24_CCS_I2CDATA, data, 1);
537	envy24_wrcs(sc, ENVY24_CCS_I2CDEV,
538	    (dev & ENVY24_CCS_I2CDEV_ADDR) | ENVY24_CCS_I2CDEV_WR, 1);
539	for (i = 0; i < ENVY24_TIMEOUT; i++) {
540		data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
541		if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0)
542			break;
543		DELAY(32); /* 31.25kHz */
544	}
545	if (i == ENVY24_TIMEOUT) {
546		return -1;
547	}
548
549	return 0;
550}
551#endif
552
553static int
554envy24_rdrom(struct sc_info *sc, u_int32_t addr)
555{
556	u_int32_t data;
557
558#if(0)
559	device_printf(sc->dev, "envy24_rdrom(sc, 0x%02x)\n", addr);
560#endif
561	data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1);
562	if ((data & ENVY24_CCS_I2CSTAT_ROM) == 0) {
563#if(0)
564		device_printf(sc->dev, "envy24_rdrom(): E2PROM not presented\n");
565#endif
566		return -1;
567	}
568
569	return envy24_rdi2c(sc, ENVY24_CCS_I2CDEV_ROM, addr);
570}
571
572static struct cfg_info *
573envy24_rom2cfg(struct sc_info *sc)
574{
575	struct cfg_info *buff;
576	int size;
577	int i;
578
579#if(0)
580	device_printf(sc->dev, "envy24_rom2cfg(sc)\n");
581#endif
582	size = envy24_rdrom(sc, ENVY24_E2PROM_SIZE);
583	if (size < ENVY24_E2PROM_GPIODIR + 1) {
584#if(0)
585		device_printf(sc->dev, "envy24_rom2cfg(): ENVY24_E2PROM_SIZE-->%d\n", size);
586#endif
587		return NULL;
588	}
589	buff = malloc(sizeof(*buff), M_ENVY24, M_NOWAIT);
590	if (buff == NULL) {
591#if(0)
592		device_printf(sc->dev, "envy24_rom2cfg(): malloc()\n");
593#endif
594		return NULL;
595	}
596	buff->free = 1;
597
598	buff->subvendor = envy24_rdrom(sc, ENVY24_E2PROM_SUBVENDOR) << 8;
599	buff->subvendor += envy24_rdrom(sc, ENVY24_E2PROM_SUBVENDOR + 1);
600	buff->subdevice = envy24_rdrom(sc, ENVY24_E2PROM_SUBDEVICE) << 8;
601	buff->subdevice += envy24_rdrom(sc, ENVY24_E2PROM_SUBDEVICE + 1);
602	buff->scfg = envy24_rdrom(sc, ENVY24_E2PROM_SCFG);
603	buff->acl = envy24_rdrom(sc, ENVY24_E2PROM_ACL);
604	buff->i2s = envy24_rdrom(sc, ENVY24_E2PROM_I2S);
605	buff->spdif = envy24_rdrom(sc, ENVY24_E2PROM_SPDIF);
606	buff->gpiomask = envy24_rdrom(sc, ENVY24_E2PROM_GPIOMASK);
607	buff->gpiostate = envy24_rdrom(sc, ENVY24_E2PROM_GPIOSTATE);
608	buff->gpiodir = envy24_rdrom(sc, ENVY24_E2PROM_GPIODIR);
609
610	for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++)
611		if (cfg_table[i].subvendor == buff->subvendor &&
612		    cfg_table[i].subdevice == buff->subdevice)
613			break;
614	buff->name = cfg_table[i].name;
615	buff->codec = cfg_table[i].codec;
616
617	return buff;
618}
619
620static void
621envy24_cfgfree(struct cfg_info *cfg) {
622	if (cfg == NULL)
623		return;
624	if (cfg->free)
625		free(cfg, M_ENVY24);
626	return;
627}
628
629/* -------------------------------------------------------------------- */
630
631/* AC'97 codec access routines */
632
633#if 0
634static int
635envy24_coldcd(struct sc_info *sc)
636{
637	u_int32_t data;
638	int i;
639
640#if(0)
641	device_printf(sc->dev, "envy24_coldcd()\n");
642#endif
643	envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_CLD, 1);
644	DELAY(10);
645	envy24_wrmt(sc, ENVY24_MT_AC97CMD, 0, 1);
646	DELAY(1000);
647	for (i = 0; i < ENVY24_TIMEOUT; i++) {
648		data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
649		if (data & ENVY24_MT_AC97CMD_RDY) {
650			return 0;
651		}
652	}
653
654	return -1;
655}
656#endif
657
658static int
659envy24_slavecd(struct sc_info *sc)
660{
661	u_int32_t data;
662	int i;
663
664#if(0)
665	device_printf(sc->dev, "envy24_slavecd()\n");
666#endif
667	envy24_wrmt(sc, ENVY24_MT_AC97CMD,
668	    ENVY24_MT_AC97CMD_CLD | ENVY24_MT_AC97CMD_WRM, 1);
669	DELAY(10);
670	envy24_wrmt(sc, ENVY24_MT_AC97CMD, 0, 1);
671	DELAY(1000);
672	for (i = 0; i < ENVY24_TIMEOUT; i++) {
673		data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
674		if (data & ENVY24_MT_AC97CMD_RDY) {
675			return 0;
676		}
677	}
678
679	return -1;
680}
681
682#if 0
683static int
684envy24_rdcd(kobj_t obj, void *devinfo, int regno)
685{
686	struct sc_info *sc = (struct sc_info *)devinfo;
687	u_int32_t data;
688	int i;
689
690#if(0)
691	device_printf(sc->dev, "envy24_rdcd(obj, sc, 0x%02x)\n", regno);
692#endif
693	envy24_wrmt(sc, ENVY24_MT_AC97IDX, (u_int32_t)regno, 1);
694	envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_RD, 1);
695	for (i = 0; i < ENVY24_TIMEOUT; i++) {
696		data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
697		if ((data & ENVY24_MT_AC97CMD_RD) == 0)
698			break;
699	}
700	data = envy24_rdmt(sc, ENVY24_MT_AC97DLO, 2);
701
702#if(0)
703	device_printf(sc->dev, "envy24_rdcd(): return 0x%x\n", data);
704#endif
705	return (int)data;
706}
707
708static int
709envy24_wrcd(kobj_t obj, void *devinfo, int regno, u_int16_t data)
710{
711	struct sc_info *sc = (struct sc_info *)devinfo;
712	u_int32_t cmd;
713	int i;
714
715#if(0)
716	device_printf(sc->dev, "envy24_wrcd(obj, sc, 0x%02x, 0x%04x)\n", regno, data);
717#endif
718	envy24_wrmt(sc, ENVY24_MT_AC97IDX, (u_int32_t)regno, 1);
719	envy24_wrmt(sc, ENVY24_MT_AC97DLO, (u_int32_t)data, 2);
720	envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_WR, 1);
721	for (i = 0; i < ENVY24_TIMEOUT; i++) {
722		cmd = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1);
723		if ((cmd & ENVY24_MT_AC97CMD_WR) == 0)
724			break;
725	}
726
727	return 0;
728}
729
730static kobj_method_t envy24_ac97_methods[] = {
731	KOBJMETHOD(ac97_read,	envy24_rdcd),
732	KOBJMETHOD(ac97_write,	envy24_wrcd),
733	{0, 0}
734};
735AC97_DECLARE(envy24_ac97);
736#endif
737
738/* -------------------------------------------------------------------- */
739
740/* GPIO access routines */
741
742static u_int32_t
743envy24_gpiord(struct sc_info *sc)
744{
745	return envy24_rdci(sc, ENVY24_CCI_GPIODAT);
746}
747
748static void
749envy24_gpiowr(struct sc_info *sc, u_int32_t data)
750{
751#if(0)
752	device_printf(sc->dev, "envy24_gpiowr(sc, 0x%02x)\n", data & 0xff);
753	return;
754#endif
755	envy24_wrci(sc, ENVY24_CCI_GPIODAT, data);
756	return;
757}
758
759#if 0
760static u_int32_t
761envy24_gpiogetmask(struct sc_info *sc)
762{
763	return envy24_rdci(sc, ENVY24_CCI_GPIOMASK);
764}
765#endif
766
767static void
768envy24_gpiosetmask(struct sc_info *sc, u_int32_t mask)
769{
770	envy24_wrci(sc, ENVY24_CCI_GPIOMASK, mask);
771	return;
772}
773
774#if 0
775static u_int32_t
776envy24_gpiogetdir(struct sc_info *sc)
777{
778	return envy24_rdci(sc, ENVY24_CCI_GPIOCTL);
779}
780#endif
781
782static void
783envy24_gpiosetdir(struct sc_info *sc, u_int32_t dir)
784{
785	envy24_wrci(sc, ENVY24_CCI_GPIOCTL, dir);
786	return;
787}
788
789/* -------------------------------------------------------------------- */
790
791/* Envy24 I2C through GPIO bit-banging */
792
793struct envy24_delta_ak4524_codec {
794	struct spicds_info *info;
795	struct sc_info *parent;
796	int dir;
797	int num;
798	int cs, cclk, cdti;
799};
800
801static void
802envy24_gpio_i2c_ctl(void *codec, unsigned int scl, unsigned int sda)
803{
804        u_int32_t data = 0;
805        struct envy24_delta_ak4524_codec *ptr = codec;
806#if(0)
807        device_printf(ptr->parent->dev, "--> %d, %d\n", scl, sda);
808#endif
809        data = envy24_gpiord(ptr->parent);
810        data &= ~(SDA_GPIO | SCL_GPIO);
811        if (scl) data += SCL_GPIO;
812        if (sda) data += SDA_GPIO;
813        envy24_gpiowr(ptr->parent, data);
814        return;
815}
816
817static void
818i2c_wrbit(void *codec, void (*ctrl)(void*, unsigned int, unsigned int), int bit)
819{
820        struct envy24_delta_ak4524_codec *ptr = codec;
821        unsigned int sda;
822
823        if (bit)
824                sda = 1;
825        else
826                sda = 0;
827
828        ctrl(ptr, 0, sda);
829        DELAY(I2C_DELAY);
830        ctrl(ptr, 1, sda);
831        DELAY(I2C_DELAY);
832        ctrl(ptr, 0, sda);
833        DELAY(I2C_DELAY);
834}
835
836static void
837i2c_start(void *codec, void (*ctrl)(void*, unsigned int, unsigned int))
838{
839        struct envy24_delta_ak4524_codec *ptr = codec;
840
841        ctrl(ptr, 1, 1);
842        DELAY(I2C_DELAY);
843        ctrl(ptr, 1, 0);
844        DELAY(I2C_DELAY);
845        ctrl(ptr, 0, 0);
846        DELAY(I2C_DELAY);
847}
848
849static void
850i2c_stop(void *codec, void (*ctrl)(void*, unsigned int, unsigned int))
851{
852        struct envy24_delta_ak4524_codec *ptr = codec;
853
854        ctrl(ptr, 0, 0);
855        DELAY(I2C_DELAY);
856        ctrl(ptr, 1, 0);
857        DELAY(I2C_DELAY);
858        ctrl(ptr, 1, 1);
859        DELAY(I2C_DELAY);
860}
861
862static void
863i2c_ack(void *codec, void (*ctrl)(void*, unsigned int, unsigned int))
864{
865        struct envy24_delta_ak4524_codec *ptr = codec;
866
867        ctrl(ptr, 0, 1);
868        DELAY(I2C_DELAY);
869        ctrl(ptr, 1, 1);
870        DELAY(I2C_DELAY);
871        /* dummy, need routine to change gpio direction */
872        ctrl(ptr, 0, 1);
873        DELAY(I2C_DELAY);
874}
875
876static void
877i2c_wr(void *codec,  void (*ctrl)(void*, unsigned int, unsigned int), u_int32_t dev, int reg, u_int8_t val)
878{
879        struct envy24_delta_ak4524_codec *ptr = codec;
880        int mask;
881
882        i2c_start(ptr, ctrl);
883
884        for (mask = 0x80; mask != 0; mask >>= 1)
885                i2c_wrbit(ptr, ctrl, dev & mask);
886        i2c_ack(ptr, ctrl);
887
888        if (reg != 0xff) {
889        for (mask = 0x80; mask != 0; mask >>= 1)
890                i2c_wrbit(ptr, ctrl, reg & mask);
891        i2c_ack(ptr, ctrl);
892        }
893
894        for (mask = 0x80; mask != 0; mask >>= 1)
895                i2c_wrbit(ptr, ctrl, val & mask);
896        i2c_ack(ptr, ctrl);
897
898        i2c_stop(ptr, ctrl);
899}
900
901/* -------------------------------------------------------------------- */
902
903/* M-Audio Delta series AK4524 access interface routine */
904
905static void
906envy24_delta_ak4524_ctl(void *codec, unsigned int cs, unsigned int cclk, unsigned int cdti)
907{
908	u_int32_t data = 0;
909	struct envy24_delta_ak4524_codec *ptr = codec;
910
911#if(0)
912	device_printf(ptr->parent->dev, "--> %d, %d, %d\n", cs, cclk, cdti);
913#endif
914	data = envy24_gpiord(ptr->parent);
915	data &= ~(ptr->cs | ptr->cclk | ptr->cdti);
916	if (cs) data += ptr->cs;
917	if (cclk) data += ptr->cclk;
918	if (cdti) data += ptr->cdti;
919	envy24_gpiowr(ptr->parent, data);
920	return;
921}
922
923static void *
924envy24_delta_ak4524_create(device_t dev, void *info, int dir, int num)
925{
926	struct sc_info *sc = info;
927	struct envy24_delta_ak4524_codec *buff = NULL;
928
929#if(0)
930	device_printf(sc->dev, "envy24_delta_ak4524_create(dev, sc, %d, %d)\n", dir, num);
931#endif
932
933	buff = malloc(sizeof(*buff), M_ENVY24, M_NOWAIT);
934	if (buff == NULL)
935		return NULL;
936
937	if (dir == PCMDIR_REC && sc->adc[num] != NULL)
938		buff->info = ((struct envy24_delta_ak4524_codec *)sc->adc[num])->info;
939	else if (dir == PCMDIR_PLAY && sc->dac[num] != NULL)
940		buff->info = ((struct envy24_delta_ak4524_codec *)sc->dac[num])->info;
941	else
942		buff->info = spicds_create(dev, buff, num, envy24_delta_ak4524_ctl);
943	if (buff->info == NULL) {
944		free(buff, M_ENVY24);
945		return NULL;
946	}
947
948	buff->parent = sc;
949	buff->dir = dir;
950	buff->num = num;
951
952	return (void *)buff;
953}
954
955static void
956envy24_delta_ak4524_destroy(void *codec)
957{
958	struct envy24_delta_ak4524_codec *ptr = codec;
959	if (ptr == NULL)
960		return;
961#if(0)
962	device_printf(ptr->parent->dev, "envy24_delta_ak4524_destroy()\n");
963#endif
964
965	if (ptr->dir == PCMDIR_PLAY) {
966		if (ptr->parent->dac[ptr->num] != NULL)
967			spicds_destroy(ptr->info);
968	}
969	else {
970		if (ptr->parent->adc[ptr->num] != NULL)
971			spicds_destroy(ptr->info);
972	}
973
974	free(codec, M_ENVY24);
975}
976
977static void
978envy24_delta_ak4524_init(void *codec)
979{
980#if 0
981	u_int32_t gpiomask, gpiodir;
982#endif
983	struct envy24_delta_ak4524_codec *ptr = codec;
984	if (ptr == NULL)
985		return;
986#if(0)
987	device_printf(ptr->parent->dev, "envy24_delta_ak4524_init()\n");
988#endif
989
990	/*
991	gpiomask = envy24_gpiogetmask(ptr->parent);
992	gpiomask &= ~(ENVY24_GPIO_AK4524_CDTI | ENVY24_GPIO_AK4524_CCLK | ENVY24_GPIO_AK4524_CS0 | ENVY24_GPIO_AK4524_CS1);
993	envy24_gpiosetmask(ptr->parent, gpiomask);
994	gpiodir = envy24_gpiogetdir(ptr->parent);
995	gpiodir |= ENVY24_GPIO_AK4524_CDTI | ENVY24_GPIO_AK4524_CCLK | ENVY24_GPIO_AK4524_CS0 | ENVY24_GPIO_AK4524_CS1;
996	envy24_gpiosetdir(ptr->parent, gpiodir);
997	*/
998	ptr->cs = ptr->parent->cfg->cs;
999#if 0
1000	envy24_gpiosetmask(ptr->parent, ENVY24_GPIO_CS8414_STATUS);
1001	envy24_gpiosetdir(ptr->parent, ~ENVY24_GPIO_CS8414_STATUS);
1002	if (ptr->num == 0)
1003		ptr->cs = ENVY24_GPIO_AK4524_CS0;
1004	else
1005		ptr->cs = ENVY24_GPIO_AK4524_CS1;
1006	ptr->cclk = ENVY24_GPIO_AK4524_CCLK;
1007#endif
1008	ptr->cclk = ptr->parent->cfg->cclk;
1009	ptr->cdti = ptr->parent->cfg->cdti;
1010	spicds_settype(ptr->info,  ptr->parent->cfg->type);
1011	spicds_setcif(ptr->info, ptr->parent->cfg->cif);
1012	spicds_setformat(ptr->info,
1013	    AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X);
1014	spicds_setdvc(ptr->info, AK452X_DVC_DEMOFF);
1015	/* for the time being, init only first codec */
1016	if (ptr->num == 0)
1017		spicds_init(ptr->info);
1018
1019        /* 6fire rear input init test, set ptr->num to 1 for test */
1020        if (ptr->parent->cfg->subvendor == 0x153b && \
1021                ptr->parent->cfg->subdevice == 0x1138 && ptr->num == 100) {
1022                ptr->cs = 0x02;
1023                spicds_init(ptr->info);
1024                device_printf(ptr->parent->dev, "6fire rear input init\n");
1025                i2c_wr(ptr, envy24_gpio_i2c_ctl, \
1026                        PCA9554_I2CDEV, PCA9554_DIR, 0x80);
1027                i2c_wr(ptr, envy24_gpio_i2c_ctl, \
1028                        PCA9554_I2CDEV, PCA9554_OUT, 0x02);
1029        }
1030}
1031
1032static void
1033envy24_delta_ak4524_reinit(void *codec)
1034{
1035	struct envy24_delta_ak4524_codec *ptr = codec;
1036	if (ptr == NULL)
1037		return;
1038#if(0)
1039	device_printf(ptr->parent->dev, "envy24_delta_ak4524_reinit()\n");
1040#endif
1041
1042	spicds_reinit(ptr->info);
1043}
1044
1045static void
1046envy24_delta_ak4524_setvolume(void *codec, int dir, unsigned int left, unsigned int right)
1047{
1048	struct envy24_delta_ak4524_codec *ptr = codec;
1049	if (ptr == NULL)
1050		return;
1051#if(0)
1052	device_printf(ptr->parent->dev, "envy24_delta_ak4524_set()\n");
1053#endif
1054
1055	spicds_set(ptr->info, dir, left, right);
1056}
1057
1058/*
1059  There is no need for AK452[48] codec to set sample rate
1060  static void
1061  envy24_delta_ak4524_setrate(struct envy24_delta_ak4524_codec *codec, int which, int rate)
1062  {
1063  }
1064*/
1065
1066/* -------------------------------------------------------------------- */
1067
1068/* hardware access routeines */
1069
1070static struct {
1071	u_int32_t speed;
1072	u_int32_t code;
1073} envy24_speedtab[] = {
1074	{48000, ENVY24_MT_RATE_48000},
1075	{24000, ENVY24_MT_RATE_24000},
1076	{12000, ENVY24_MT_RATE_12000},
1077	{9600, ENVY24_MT_RATE_9600},
1078	{32000, ENVY24_MT_RATE_32000},
1079	{16000, ENVY24_MT_RATE_16000},
1080	{8000, ENVY24_MT_RATE_8000},
1081	{96000, ENVY24_MT_RATE_96000},
1082	{64000, ENVY24_MT_RATE_64000},
1083	{44100, ENVY24_MT_RATE_44100},
1084	{22050, ENVY24_MT_RATE_22050},
1085	{11025, ENVY24_MT_RATE_11025},
1086	{88200, ENVY24_MT_RATE_88200},
1087	{0, 0x10}
1088};
1089
1090static int
1091envy24_setspeed(struct sc_info *sc, u_int32_t speed) {
1092	u_int32_t code;
1093	int i = 0;
1094
1095#if(0)
1096	device_printf(sc->dev, "envy24_setspeed(sc, %d)\n", speed);
1097#endif
1098	if (speed == 0) {
1099		code = ENVY24_MT_RATE_SPDIF; /* external master clock */
1100		envy24_slavecd(sc);
1101	}
1102	else {
1103		for (i = 0; envy24_speedtab[i].speed != 0; i++) {
1104			if (envy24_speedtab[i].speed == speed)
1105				break;
1106		}
1107		code = envy24_speedtab[i].code;
1108	}
1109#if(0)
1110	device_printf(sc->dev, "envy24_setspeed(): speed %d/code 0x%04x\n", envy24_speedtab[i].speed, code);
1111#endif
1112	if (code < 0x10) {
1113		envy24_wrmt(sc, ENVY24_MT_RATE, code, 1);
1114		code = envy24_rdmt(sc, ENVY24_MT_RATE, 1);
1115		code &= ENVY24_MT_RATE_MASK;
1116		for (i = 0; envy24_speedtab[i].code < 0x10; i++) {
1117			if (envy24_speedtab[i].code == code)
1118				break;
1119		}
1120		speed = envy24_speedtab[i].speed;
1121	}
1122	else
1123		speed = 0;
1124
1125#if(0)
1126	device_printf(sc->dev, "envy24_setspeed(): return %d\n", speed);
1127#endif
1128	return speed;
1129}
1130
1131static void
1132envy24_setvolume(struct sc_info *sc, unsigned ch)
1133{
1134#if(0)
1135	device_printf(sc->dev, "envy24_setvolume(sc, %d)\n", ch);
1136#endif
1137if (sc->cfg->subvendor==0x153b  && sc->cfg->subdevice==0x1138 ) {
1138        envy24_wrmt(sc, ENVY24_MT_VOLIDX, 16, 1);
1139        envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f7f, 2);
1140        envy24_wrmt(sc, ENVY24_MT_VOLIDX, 17, 1);
1141        envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f7f, 2);
1142	}
1143
1144	envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2, 1);
1145	envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f00 | sc->left[ch], 2);
1146	envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2 + 1, 1);
1147	envy24_wrmt(sc, ENVY24_MT_VOLUME, (sc->right[ch] << 8) | 0x7f, 2);
1148}
1149
1150static void
1151envy24_mutevolume(struct sc_info *sc, unsigned ch)
1152{
1153	u_int32_t vol;
1154
1155#if(0)
1156	device_printf(sc->dev, "envy24_mutevolume(sc, %d)\n", ch);
1157#endif
1158	vol = ENVY24_VOL_MUTE << 8 | ENVY24_VOL_MUTE;
1159	envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2, 1);
1160	envy24_wrmt(sc, ENVY24_MT_VOLUME, vol, 2);
1161	envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2 + 1, 1);
1162	envy24_wrmt(sc, ENVY24_MT_VOLUME, vol, 2);
1163}
1164
1165static u_int32_t
1166envy24_gethwptr(struct sc_info *sc, int dir)
1167{
1168	int unit, regno;
1169	u_int32_t ptr, rtn;
1170
1171#if(0)
1172	device_printf(sc->dev, "envy24_gethwptr(sc, %d)\n", dir);
1173#endif
1174	if (dir == PCMDIR_PLAY) {
1175		rtn = sc->psize / 4;
1176		unit = ENVY24_PLAY_BUFUNIT / 4;
1177		regno = ENVY24_MT_PCNT;
1178	}
1179	else {
1180		rtn = sc->rsize / 4;
1181		unit = ENVY24_REC_BUFUNIT / 4;
1182		regno = ENVY24_MT_RCNT;
1183	}
1184
1185	ptr = envy24_rdmt(sc, regno, 2);
1186	rtn -= (ptr + 1);
1187	rtn /= unit;
1188
1189#if(0)
1190	device_printf(sc->dev, "envy24_gethwptr(): return %d\n", rtn);
1191#endif
1192	return rtn;
1193}
1194
1195static void
1196envy24_updintr(struct sc_info *sc, int dir)
1197{
1198	int regptr, regintr;
1199	u_int32_t mask, intr;
1200	u_int32_t ptr, size, cnt;
1201	u_int16_t blk;
1202
1203#if(0)
1204	device_printf(sc->dev, "envy24_updintr(sc, %d)\n", dir);
1205#endif
1206	if (dir == PCMDIR_PLAY) {
1207		blk = sc->blk[0];
1208		size = sc->psize / 4;
1209		regptr = ENVY24_MT_PCNT;
1210		regintr = ENVY24_MT_PTERM;
1211		mask = ~ENVY24_MT_INT_PMASK;
1212	}
1213	else {
1214		blk = sc->blk[1];
1215		size = sc->rsize / 4;
1216		regptr = ENVY24_MT_RCNT;
1217		regintr = ENVY24_MT_RTERM;
1218		mask = ~ENVY24_MT_INT_RMASK;
1219	}
1220
1221	ptr = size - envy24_rdmt(sc, regptr, 2) - 1;
1222	/*
1223	cnt = blk - ptr % blk - 1;
1224	if (cnt == 0)
1225		cnt = blk - 1;
1226	*/
1227	cnt = blk - 1;
1228#if(0)
1229	device_printf(sc->dev, "envy24_updintr():ptr = %d, blk = %d, cnt = %d\n", ptr, blk, cnt);
1230#endif
1231	envy24_wrmt(sc, regintr, cnt, 2);
1232	intr = envy24_rdmt(sc, ENVY24_MT_INT, 1);
1233#if(0)
1234	device_printf(sc->dev, "envy24_updintr():intr = 0x%02x, mask = 0x%02x\n", intr, mask);
1235#endif
1236	envy24_wrmt(sc, ENVY24_MT_INT, intr & mask, 1);
1237#if(0)
1238	device_printf(sc->dev, "envy24_updintr():INT-->0x%02x\n",
1239		      envy24_rdmt(sc, ENVY24_MT_INT, 1));
1240#endif
1241
1242	return;
1243}
1244
1245#if 0
1246static void
1247envy24_maskintr(struct sc_info *sc, int dir)
1248{
1249	u_int32_t mask, intr;
1250
1251#if(0)
1252	device_printf(sc->dev, "envy24_maskintr(sc, %d)\n", dir);
1253#endif
1254	if (dir == PCMDIR_PLAY)
1255		mask = ENVY24_MT_INT_PMASK;
1256	else
1257		mask = ENVY24_MT_INT_RMASK;
1258	intr = envy24_rdmt(sc, ENVY24_MT_INT, 1);
1259	envy24_wrmt(sc, ENVY24_MT_INT, intr | mask, 1);
1260
1261	return;
1262}
1263#endif
1264
1265static int
1266envy24_checkintr(struct sc_info *sc, int dir)
1267{
1268	u_int32_t mask, stat, intr, rtn;
1269
1270#if(0)
1271	device_printf(sc->dev, "envy24_checkintr(sc, %d)\n", dir);
1272#endif
1273	intr = envy24_rdmt(sc, ENVY24_MT_INT, 1);
1274	if (dir == PCMDIR_PLAY) {
1275		if ((rtn = intr & ENVY24_MT_INT_PSTAT) != 0) {
1276			mask = ~ENVY24_MT_INT_RSTAT;
1277			stat = ENVY24_MT_INT_PSTAT | ENVY24_MT_INT_PMASK;
1278			envy24_wrmt(sc, ENVY24_MT_INT, (intr & mask) | stat, 1);
1279		}
1280	}
1281	else {
1282		if ((rtn = intr & ENVY24_MT_INT_RSTAT) != 0) {
1283			mask = ~ENVY24_MT_INT_PSTAT;
1284			stat = ENVY24_MT_INT_RSTAT | ENVY24_MT_INT_RMASK;
1285			envy24_wrmt(sc, ENVY24_MT_INT, (intr & mask) | stat, 1);
1286		}
1287	}
1288
1289	return rtn;
1290}
1291
1292static void
1293envy24_start(struct sc_info *sc, int dir)
1294{
1295	u_int32_t stat, sw;
1296
1297#if(0)
1298	device_printf(sc->dev, "envy24_start(sc, %d)\n", dir);
1299#endif
1300	if (dir == PCMDIR_PLAY)
1301		sw = ENVY24_MT_PCTL_PSTART;
1302	else
1303		sw = ENVY24_MT_PCTL_RSTART;
1304
1305	stat = envy24_rdmt(sc, ENVY24_MT_PCTL, 1);
1306	envy24_wrmt(sc, ENVY24_MT_PCTL, stat | sw, 1);
1307#if(0)
1308	DELAY(100);
1309	device_printf(sc->dev, "PADDR:0x%08x\n", envy24_rdmt(sc, ENVY24_MT_PADDR, 4));
1310	device_printf(sc->dev, "PCNT:%ld\n", envy24_rdmt(sc, ENVY24_MT_PCNT, 2));
1311#endif
1312
1313	return;
1314}
1315
1316static void
1317envy24_stop(struct sc_info *sc, int dir)
1318{
1319	u_int32_t stat, sw;
1320
1321#if(0)
1322	device_printf(sc->dev, "envy24_stop(sc, %d)\n", dir);
1323#endif
1324	if (dir == PCMDIR_PLAY)
1325		sw = ~ENVY24_MT_PCTL_PSTART;
1326	else
1327		sw = ~ENVY24_MT_PCTL_RSTART;
1328
1329	stat = envy24_rdmt(sc, ENVY24_MT_PCTL, 1);
1330	envy24_wrmt(sc, ENVY24_MT_PCTL, stat & sw, 1);
1331
1332	return;
1333}
1334
1335static int
1336envy24_route(struct sc_info *sc, int dac, int class, int adc, int rev)
1337{
1338	u_int32_t reg, mask;
1339	u_int32_t left, right;
1340
1341#if(0)
1342	device_printf(sc->dev, "envy24_route(sc, %d, %d, %d, %d)\n",
1343	    dac, class, adc, rev);
1344#endif
1345	/* parameter pattern check */
1346	if (dac < 0 || ENVY24_ROUTE_DAC_SPDIF < dac)
1347		return -1;
1348	if (class == ENVY24_ROUTE_CLASS_MIX &&
1349	    (dac != ENVY24_ROUTE_DAC_1 && dac != ENVY24_ROUTE_DAC_SPDIF))
1350		return -1;
1351	if (rev) {
1352		left = ENVY24_ROUTE_RIGHT;
1353		right = ENVY24_ROUTE_LEFT;
1354	}
1355	else {
1356		left = ENVY24_ROUTE_LEFT;
1357		right = ENVY24_ROUTE_RIGHT;
1358	}
1359
1360	if (dac == ENVY24_ROUTE_DAC_SPDIF) {
1361		reg = class | class << 2 |
1362			((adc << 1 | left) | left << 3) << 8 |
1363			((adc << 1 | right) | right << 3) << 12;
1364#if(0)
1365		device_printf(sc->dev, "envy24_route(): MT_SPDOUT-->0x%04x\n", reg);
1366#endif
1367		envy24_wrmt(sc, ENVY24_MT_SPDOUT, reg, 2);
1368	}
1369	else {
1370		mask = ~(0x0303 << dac * 2);
1371		reg = envy24_rdmt(sc, ENVY24_MT_PSDOUT, 2);
1372		reg = (reg & mask) | ((class | class << 8) << dac * 2);
1373#if(0)
1374		device_printf(sc->dev, "envy24_route(): MT_PSDOUT-->0x%04x\n", reg);
1375#endif
1376		envy24_wrmt(sc, ENVY24_MT_PSDOUT, reg, 2);
1377		mask = ~(0xff << dac * 8);
1378		reg = envy24_rdmt(sc, ENVY24_MT_RECORD, 4);
1379		reg = (reg & mask) |
1380			(((adc << 1 | left) | left << 3) |
1381			 ((adc << 1 | right) | right << 3) << 4) << dac * 8;
1382#if(0)
1383		device_printf(sc->dev, "envy24_route(): MT_RECORD-->0x%08x\n", reg);
1384#endif
1385		envy24_wrmt(sc, ENVY24_MT_RECORD, reg, 4);
1386
1387		/* 6fire rear input init test */
1388		envy24_wrmt(sc, ENVY24_MT_RECORD, 0x00, 4);
1389	}
1390
1391	return 0;
1392}
1393
1394/* -------------------------------------------------------------------- */
1395
1396/* buffer copy routines */
1397static void
1398envy24_p32sl(struct sc_chinfo *ch)
1399{
1400	int length;
1401	sample32_t *dmabuf;
1402	u_int32_t *data;
1403	int src, dst, ssize, dsize, slot;
1404	int i;
1405
1406	length = sndbuf_getready(ch->buffer) / 8;
1407	dmabuf = ch->parent->pbuf;
1408	data = (u_int32_t *)ch->data;
1409	src = sndbuf_getreadyptr(ch->buffer) / 4;
1410	dst = src / 2 + ch->offset;
1411	ssize = ch->size / 4;
1412	dsize = ch->size / 8;
1413	slot = ch->num * 2;
1414
1415	for (i = 0; i < length; i++) {
1416		dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = data[src];
1417		dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = data[src + 1];
1418		dst++;
1419		dst %= dsize;
1420		src += 2;
1421		src %= ssize;
1422	}
1423
1424	return;
1425}
1426
1427static void
1428envy24_p16sl(struct sc_chinfo *ch)
1429{
1430	int length;
1431	sample32_t *dmabuf;
1432	u_int16_t *data;
1433	int src, dst, ssize, dsize, slot;
1434	int i;
1435
1436#if(0)
1437	device_printf(ch->parent->dev, "envy24_p16sl()\n");
1438#endif
1439	length = sndbuf_getready(ch->buffer) / 4;
1440	dmabuf = ch->parent->pbuf;
1441	data = (u_int16_t *)ch->data;
1442	src = sndbuf_getreadyptr(ch->buffer) / 2;
1443	dst = src / 2 + ch->offset;
1444	ssize = ch->size / 2;
1445	dsize = ch->size / 4;
1446	slot = ch->num * 2;
1447#if(0)
1448	device_printf(ch->parent->dev, "envy24_p16sl():%lu-->%lu(%lu)\n", src, dst, length);
1449#endif
1450
1451	for (i = 0; i < length; i++) {
1452		dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = (u_int32_t)data[src] << 16;
1453		dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = (u_int32_t)data[src + 1] << 16;
1454#if(0)
1455		if (i < 16) {
1456			printf("%08x", dmabuf[dst * ENVY24_PLAY_CHNUM + slot]);
1457			printf("%08x", dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1]);
1458		}
1459#endif
1460		dst++;
1461		dst %= dsize;
1462		src += 2;
1463		src %= ssize;
1464	}
1465#if(0)
1466	printf("\n");
1467#endif
1468
1469	return;
1470}
1471
1472static void
1473envy24_p8u(struct sc_chinfo *ch)
1474{
1475	int length;
1476	sample32_t *dmabuf;
1477	u_int8_t *data;
1478	int src, dst, ssize, dsize, slot;
1479	int i;
1480
1481	length = sndbuf_getready(ch->buffer) / 2;
1482	dmabuf = ch->parent->pbuf;
1483	data = (u_int8_t *)ch->data;
1484	src = sndbuf_getreadyptr(ch->buffer);
1485	dst = src / 2 + ch->offset;
1486	ssize = ch->size;
1487	dsize = ch->size / 4;
1488	slot = ch->num * 2;
1489
1490	for (i = 0; i < length; i++) {
1491		dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = ((u_int32_t)data[src] ^ 0x80) << 24;
1492		dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = ((u_int32_t)data[src + 1] ^ 0x80) << 24;
1493		dst++;
1494		dst %= dsize;
1495		src += 2;
1496		src %= ssize;
1497	}
1498
1499	return;
1500}
1501
1502static void
1503envy24_r32sl(struct sc_chinfo *ch)
1504{
1505	int length;
1506	sample32_t *dmabuf;
1507	u_int32_t *data;
1508	int src, dst, ssize, dsize, slot;
1509	int i;
1510
1511	length = sndbuf_getfree(ch->buffer) / 8;
1512	dmabuf = ch->parent->rbuf;
1513	data = (u_int32_t *)ch->data;
1514	dst = sndbuf_getfreeptr(ch->buffer) / 4;
1515	src = dst / 2 + ch->offset;
1516	dsize = ch->size / 4;
1517	ssize = ch->size / 8;
1518	slot = (ch->num - ENVY24_CHAN_REC_ADC1) * 2;
1519
1520	for (i = 0; i < length; i++) {
1521		data[dst] = dmabuf[src * ENVY24_REC_CHNUM + slot].buffer;
1522		data[dst + 1] = dmabuf[src * ENVY24_REC_CHNUM + slot + 1].buffer;
1523		dst += 2;
1524		dst %= dsize;
1525		src++;
1526		src %= ssize;
1527	}
1528
1529	return;
1530}
1531
1532static void
1533envy24_r16sl(struct sc_chinfo *ch)
1534{
1535	int length;
1536	sample32_t *dmabuf;
1537	u_int16_t *data;
1538	int src, dst, ssize, dsize, slot;
1539	int i;
1540
1541	length = sndbuf_getfree(ch->buffer) / 4;
1542	dmabuf = ch->parent->rbuf;
1543	data = (u_int16_t *)ch->data;
1544	dst = sndbuf_getfreeptr(ch->buffer) / 2;
1545	src = dst / 2 + ch->offset;
1546	dsize = ch->size / 2;
1547	ssize = ch->size / 8;
1548	slot = (ch->num - ENVY24_CHAN_REC_ADC1) * 2;
1549
1550	for (i = 0; i < length; i++) {
1551		data[dst] = dmabuf[src * ENVY24_REC_CHNUM + slot].buffer;
1552		data[dst + 1] = dmabuf[src * ENVY24_REC_CHNUM + slot + 1].buffer;
1553		dst += 2;
1554		dst %= dsize;
1555		src++;
1556		src %= ssize;
1557	}
1558
1559	return;
1560}
1561
1562/* -------------------------------------------------------------------- */
1563
1564/* channel interface */
1565static void *
1566envy24chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
1567{
1568	struct sc_info	*sc = (struct sc_info *)devinfo;
1569	struct sc_chinfo *ch;
1570	unsigned num;
1571
1572#if(0)
1573	device_printf(sc->dev, "envy24chan_init(obj, devinfo, b, c, %d)\n", dir);
1574#endif
1575	snd_mtxlock(sc->lock);
1576	if ((sc->chnum > ENVY24_CHAN_PLAY_SPDIF && dir != PCMDIR_REC) ||
1577	    (sc->chnum < ENVY24_CHAN_REC_ADC1 && dir != PCMDIR_PLAY)) {
1578		snd_mtxunlock(sc->lock);
1579		return NULL;
1580	}
1581	num = sc->chnum;
1582
1583	ch = &sc->chan[num];
1584	ch->size = 8 * ENVY24_SAMPLE_NUM;
1585	ch->data = malloc(ch->size, M_ENVY24, M_NOWAIT);
1586	if (ch->data == NULL) {
1587		ch->size = 0;
1588		ch = NULL;
1589	}
1590	else {
1591		ch->buffer = b;
1592		ch->channel = c;
1593		ch->parent = sc;
1594		ch->dir = dir;
1595		/* set channel map */
1596		ch->num = envy24_chanmap[num];
1597		snd_mtxunlock(sc->lock);
1598		sndbuf_setup(ch->buffer, ch->data, ch->size);
1599		snd_mtxlock(sc->lock);
1600		/* these 2 values are dummy */
1601		ch->unit = 4;
1602		ch->blk = 10240;
1603	}
1604	snd_mtxunlock(sc->lock);
1605
1606	return ch;
1607}
1608
1609static int
1610envy24chan_free(kobj_t obj, void *data)
1611{
1612	struct sc_chinfo *ch = data;
1613	struct sc_info *sc = ch->parent;
1614
1615#if(0)
1616	device_printf(sc->dev, "envy24chan_free()\n");
1617#endif
1618	snd_mtxlock(sc->lock);
1619	if (ch->data != NULL) {
1620		free(ch->data, M_ENVY24);
1621		ch->data = NULL;
1622	}
1623	snd_mtxunlock(sc->lock);
1624
1625	return 0;
1626}
1627
1628static int
1629envy24chan_setformat(kobj_t obj, void *data, u_int32_t format)
1630{
1631	struct sc_chinfo *ch = data;
1632	struct sc_info *sc = ch->parent;
1633	struct envy24_emldma *emltab;
1634	/* unsigned int bcnt, bsize; */
1635	int i;
1636
1637#if(0)
1638	device_printf(sc->dev, "envy24chan_setformat(obj, data, 0x%08x)\n", format);
1639#endif
1640	snd_mtxlock(sc->lock);
1641	/* check and get format related information */
1642	if (ch->dir == PCMDIR_PLAY)
1643		emltab = envy24_pemltab;
1644	else
1645		emltab = envy24_remltab;
1646	if (emltab == NULL) {
1647		snd_mtxunlock(sc->lock);
1648		return -1;
1649	}
1650	for (i = 0; emltab[i].format != 0; i++)
1651		if (emltab[i].format == format)
1652			break;
1653	if (emltab[i].format == 0) {
1654		snd_mtxunlock(sc->lock);
1655		return -1;
1656	}
1657
1658	/* set format information */
1659	ch->format = format;
1660	ch->emldma = emltab[i].emldma;
1661	if (ch->unit > emltab[i].unit)
1662		ch->blk *= ch->unit / emltab[i].unit;
1663	else
1664		ch->blk /= emltab[i].unit / ch->unit;
1665	ch->unit = emltab[i].unit;
1666
1667	/* set channel buffer information */
1668	ch->size = ch->unit * ENVY24_SAMPLE_NUM;
1669#if 0
1670	if (ch->dir == PCMDIR_PLAY)
1671		bsize = ch->blk * 4 / ENVY24_PLAY_BUFUNIT;
1672	else
1673		bsize = ch->blk * 4 / ENVY24_REC_BUFUNIT;
1674	bsize *= ch->unit;
1675	bcnt = ch->size / bsize;
1676	sndbuf_resize(ch->buffer, bcnt, bsize);
1677#endif
1678	snd_mtxunlock(sc->lock);
1679
1680#if(0)
1681	device_printf(sc->dev, "envy24chan_setformat(): return 0x%08x\n", 0);
1682#endif
1683	return 0;
1684}
1685
1686/*
1687  IMPLEMENT NOTICE: In this driver, setspeed function only do setting
1688  of speed information value. And real hardware speed setting is done
1689  at start triggered(see envy24chan_trigger()). So, at this function
1690  is called, any value that ENVY24 can use is able to set. But, at
1691  start triggerd, some other channel is running, and that channel's
1692  speed isn't same with, then trigger function will fail.
1693*/
1694static int
1695envy24chan_setspeed(kobj_t obj, void *data, u_int32_t speed)
1696{
1697	struct sc_chinfo *ch = data;
1698	u_int32_t val, prev;
1699	int i;
1700
1701#if(0)
1702	device_printf(ch->parent->dev, "envy24chan_setspeed(obj, data, %d)\n", speed);
1703#endif
1704	prev = 0x7fffffff;
1705	for (i = 0; (val = envy24_speed[i]) != 0; i++) {
1706		if (abs(val - speed) < abs(prev - speed))
1707			prev = val;
1708		else
1709			break;
1710	}
1711	ch->speed = prev;
1712
1713#if(0)
1714	device_printf(ch->parent->dev, "envy24chan_setspeed(): return %d\n", ch->speed);
1715#endif
1716	return ch->speed;
1717}
1718
1719static int
1720envy24chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
1721{
1722	struct sc_chinfo *ch = data;
1723	/* struct sc_info *sc = ch->parent; */
1724	u_int32_t size, prev;
1725        unsigned int bcnt, bsize;
1726
1727#if(0)
1728	device_printf(sc->dev, "envy24chan_setblocksize(obj, data, %d)\n", blocksize);
1729#endif
1730	prev = 0x7fffffff;
1731	/* snd_mtxlock(sc->lock); */
1732	for (size = ch->size / 2; size > 0; size /= 2) {
1733		if (abs(size - blocksize) < abs(prev - blocksize))
1734			prev = size;
1735		else
1736			break;
1737	}
1738
1739	ch->blk = prev / ch->unit;
1740	if (ch->dir == PCMDIR_PLAY)
1741		ch->blk *= ENVY24_PLAY_BUFUNIT / 4;
1742	else
1743		ch->blk *= ENVY24_REC_BUFUNIT / 4;
1744	/* set channel buffer information */
1745	/* ch->size = ch->unit * ENVY24_SAMPLE_NUM; */
1746        if (ch->dir == PCMDIR_PLAY)
1747                bsize = ch->blk * 4 / ENVY24_PLAY_BUFUNIT;
1748        else
1749                bsize = ch->blk * 4 / ENVY24_REC_BUFUNIT;
1750        bsize *= ch->unit;
1751        bcnt = ch->size / bsize;
1752        sndbuf_resize(ch->buffer, bcnt, bsize);
1753	/* snd_mtxunlock(sc->lock); */
1754
1755#if(0)
1756	device_printf(sc->dev, "envy24chan_setblocksize(): return %d\n", prev);
1757#endif
1758	return prev;
1759}
1760
1761/* semantic note: must start at beginning of buffer */
1762static int
1763envy24chan_trigger(kobj_t obj, void *data, int go)
1764{
1765	struct sc_chinfo *ch = data;
1766	struct sc_info *sc = ch->parent;
1767	u_int32_t ptr;
1768	int slot;
1769#if 0
1770	int i;
1771
1772	device_printf(sc->dev, "envy24chan_trigger(obj, data, %d)\n", go);
1773#endif
1774	snd_mtxlock(sc->lock);
1775	if (ch->dir == PCMDIR_PLAY)
1776		slot = 0;
1777	else
1778		slot = 1;
1779	switch (go) {
1780	case PCMTRIG_START:
1781#if(0)
1782		device_printf(sc->dev, "envy24chan_trigger(): start\n");
1783#endif
1784		/* check or set channel speed */
1785		if (sc->run[0] == 0 && sc->run[1] == 0) {
1786			sc->speed = envy24_setspeed(sc, ch->speed);
1787			sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed;
1788			sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed;
1789		}
1790		else if (ch->speed != 0 && ch->speed != sc->speed)
1791			return -1;
1792		if (ch->speed == 0)
1793			ch->channel->speed = sc->speed;
1794		/* start or enable channel */
1795		sc->run[slot]++;
1796		if (sc->run[slot] == 1) {
1797			/* first channel */
1798			ch->offset = 0;
1799			sc->blk[slot] = ch->blk;
1800		}
1801		else {
1802			ptr = envy24_gethwptr(sc, ch->dir);
1803			ch->offset = ((ptr / ch->blk + 1) * ch->blk %
1804			    (ch->size / 4)) * 4 / ch->unit;
1805			if (ch->blk < sc->blk[slot])
1806				sc->blk[slot] = ch->blk;
1807		}
1808		if (ch->dir == PCMDIR_PLAY) {
1809			ch->emldma(ch);
1810			envy24_setvolume(sc, ch->num);
1811		}
1812		envy24_updintr(sc, ch->dir);
1813		if (sc->run[slot] == 1)
1814			envy24_start(sc, ch->dir);
1815		ch->run = 1;
1816		break;
1817	case PCMTRIG_EMLDMAWR:
1818#if(0)
1819		device_printf(sc->dev, "envy24chan_trigger(): emldmawr\n");
1820#endif
1821		if (ch->run != 1)
1822			return -1;
1823		ch->emldma(ch);
1824		break;
1825	case PCMTRIG_EMLDMARD:
1826#if(0)
1827		device_printf(sc->dev, "envy24chan_trigger(): emldmard\n");
1828#endif
1829		if (ch->run != 1)
1830			return -1;
1831		ch->emldma(ch);
1832		break;
1833	case PCMTRIG_ABORT:
1834		if (ch->run) {
1835#if(0)
1836		device_printf(sc->dev, "envy24chan_trigger(): abort\n");
1837#endif
1838		ch->run = 0;
1839		sc->run[slot]--;
1840		if (ch->dir == PCMDIR_PLAY)
1841			envy24_mutevolume(sc, ch->num);
1842		if (sc->run[slot] == 0) {
1843			envy24_stop(sc, ch->dir);
1844			sc->intr[slot] = 0;
1845		}
1846#if 0
1847		else if (ch->blk == sc->blk[slot]) {
1848			sc->blk[slot] = ENVY24_SAMPLE_NUM / 2;
1849			for (i = 0; i < ENVY24_CHAN_NUM; i++) {
1850				if (sc->chan[i].dir == ch->dir &&
1851				    sc->chan[i].run == 1 &&
1852				    sc->chan[i].blk < sc->blk[slot])
1853					sc->blk[slot] = sc->chan[i].blk;
1854			}
1855			if (ch->blk != sc->blk[slot])
1856				envy24_updintr(sc, ch->dir);
1857		}
1858#endif
1859		}
1860		break;
1861	}
1862	snd_mtxunlock(sc->lock);
1863
1864	return 0;
1865}
1866
1867static int
1868envy24chan_getptr(kobj_t obj, void *data)
1869{
1870	struct sc_chinfo *ch = data;
1871	struct sc_info *sc = ch->parent;
1872	u_int32_t ptr;
1873	int rtn;
1874
1875#if(0)
1876	device_printf(sc->dev, "envy24chan_getptr()\n");
1877#endif
1878	snd_mtxlock(sc->lock);
1879	ptr = envy24_gethwptr(sc, ch->dir);
1880	rtn = ptr * ch->unit;
1881	snd_mtxunlock(sc->lock);
1882
1883#if(0)
1884	device_printf(sc->dev, "envy24chan_getptr(): return %d\n",
1885	    rtn);
1886#endif
1887	return rtn;
1888}
1889
1890static struct pcmchan_caps *
1891envy24chan_getcaps(kobj_t obj, void *data)
1892{
1893	struct sc_chinfo *ch = data;
1894	struct sc_info *sc = ch->parent;
1895	struct pcmchan_caps *rtn;
1896
1897#if(0)
1898	device_printf(sc->dev, "envy24chan_getcaps()\n");
1899#endif
1900	snd_mtxlock(sc->lock);
1901	if (ch->dir == PCMDIR_PLAY) {
1902		if (sc->run[0] == 0)
1903			rtn = &envy24_playcaps;
1904		else
1905			rtn = &sc->caps[0];
1906	}
1907	else {
1908		if (sc->run[1] == 0)
1909			rtn = &envy24_reccaps;
1910		else
1911			rtn = &sc->caps[1];
1912	}
1913	snd_mtxunlock(sc->lock);
1914
1915	return rtn;
1916}
1917
1918static kobj_method_t envy24chan_methods[] = {
1919	KOBJMETHOD(channel_init,		envy24chan_init),
1920	KOBJMETHOD(channel_free,		envy24chan_free),
1921	KOBJMETHOD(channel_setformat,		envy24chan_setformat),
1922	KOBJMETHOD(channel_setspeed,		envy24chan_setspeed),
1923	KOBJMETHOD(channel_setblocksize,	envy24chan_setblocksize),
1924	KOBJMETHOD(channel_trigger,		envy24chan_trigger),
1925	KOBJMETHOD(channel_getptr,		envy24chan_getptr),
1926	KOBJMETHOD(channel_getcaps,		envy24chan_getcaps),
1927	{ 0, 0 }
1928};
1929CHANNEL_DECLARE(envy24chan);
1930
1931/* -------------------------------------------------------------------- */
1932
1933/* mixer interface */
1934
1935static int
1936envy24mixer_init(struct snd_mixer *m)
1937{
1938	struct sc_info *sc = mix_getdevinfo(m);
1939
1940#if(0)
1941	device_printf(sc->dev, "envy24mixer_init()\n");
1942#endif
1943	if (sc == NULL)
1944		return -1;
1945
1946	/* set volume control rate */
1947	snd_mtxlock(sc->lock);
1948	envy24_wrmt(sc, ENVY24_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */
1949
1950	mix_setdevs(m, ENVY24_MIX_MASK);
1951	mix_setrecdevs(m, ENVY24_MIX_REC_MASK);
1952	snd_mtxunlock(sc->lock);
1953
1954	return 0;
1955}
1956
1957static int
1958envy24mixer_reinit(struct snd_mixer *m)
1959{
1960	struct sc_info *sc = mix_getdevinfo(m);
1961
1962	if (sc == NULL)
1963		return -1;
1964#if(0)
1965	device_printf(sc->dev, "envy24mixer_reinit()\n");
1966#endif
1967
1968	return 0;
1969}
1970
1971static int
1972envy24mixer_uninit(struct snd_mixer *m)
1973{
1974	struct sc_info *sc = mix_getdevinfo(m);
1975
1976	if (sc == NULL)
1977		return -1;
1978#if(0)
1979	device_printf(sc->dev, "envy24mixer_uninit()\n");
1980#endif
1981
1982	return 0;
1983}
1984
1985static int
1986envy24mixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1987{
1988	struct sc_info *sc = mix_getdevinfo(m);
1989	int ch = envy24_mixmap[dev];
1990	int hwch;
1991	int i;
1992
1993	if (sc == NULL)
1994		return -1;
1995	if (dev == 0 && sc->cfg->codec->setvolume == NULL)
1996		return -1;
1997	if (dev != 0 && ch == -1)
1998		return -1;
1999	hwch = envy24_chanmap[ch];
2000#if(0)
2001	device_printf(sc->dev, "envy24mixer_set(m, %d, %d, %d)\n",
2002	    dev, left, right);
2003#endif
2004
2005	snd_mtxlock(sc->lock);
2006	if (dev == 0) {
2007		for (i = 0; i < sc->dacn; i++) {
2008			sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right);
2009		}
2010	}
2011	else {
2012		/* set volume value for hardware */
2013		if ((sc->left[hwch] = 100 - left) > ENVY24_VOL_MIN)
2014			sc->left[hwch] = ENVY24_VOL_MUTE;
2015		if ((sc->right[hwch] = 100 - right) > ENVY24_VOL_MIN)
2016			sc->right[hwch] = ENVY24_VOL_MUTE;
2017
2018		/* set volume for record channel and running play channel */
2019		if (hwch > ENVY24_CHAN_PLAY_SPDIF || sc->chan[ch].run)
2020			envy24_setvolume(sc, hwch);
2021	}
2022	snd_mtxunlock(sc->lock);
2023
2024	return right << 8 | left;
2025}
2026
2027static u_int32_t
2028envy24mixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
2029{
2030	struct sc_info *sc = mix_getdevinfo(m);
2031	int ch = envy24_mixmap[src];
2032#if(0)
2033	device_printf(sc->dev, "envy24mixer_setrecsrc(m, %d)\n", src);
2034#endif
2035
2036	if (ch > ENVY24_CHAN_PLAY_SPDIF)
2037		sc->src = ch;
2038	return src;
2039}
2040
2041static kobj_method_t envy24mixer_methods[] = {
2042	KOBJMETHOD(mixer_init,		envy24mixer_init),
2043	KOBJMETHOD(mixer_reinit,	envy24mixer_reinit),
2044	KOBJMETHOD(mixer_uninit,	envy24mixer_uninit),
2045	KOBJMETHOD(mixer_set,		envy24mixer_set),
2046	KOBJMETHOD(mixer_setrecsrc,	envy24mixer_setrecsrc),
2047	{ 0, 0 }
2048};
2049MIXER_DECLARE(envy24mixer);
2050
2051/* -------------------------------------------------------------------- */
2052
2053/* The interrupt handler */
2054static void
2055envy24_intr(void *p)
2056{
2057	struct sc_info *sc = (struct sc_info *)p;
2058	struct sc_chinfo *ch;
2059	u_int32_t ptr, dsize, feed;
2060	int i;
2061
2062#if(0)
2063	device_printf(sc->dev, "envy24_intr()\n");
2064#endif
2065	snd_mtxlock(sc->lock);
2066	if (envy24_checkintr(sc, PCMDIR_PLAY)) {
2067#if(0)
2068		device_printf(sc->dev, "envy24_intr(): play\n");
2069#endif
2070		dsize = sc->psize / 4;
2071		ptr = dsize - envy24_rdmt(sc, ENVY24_MT_PCNT, 2) - 1;
2072#if(0)
2073		device_printf(sc->dev, "envy24_intr(): ptr = %d-->", ptr);
2074#endif
2075		ptr -= ptr % sc->blk[0];
2076		feed = (ptr + dsize - sc->intr[0]) % dsize;
2077#if(0)
2078		printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed);
2079#endif
2080		for (i = ENVY24_CHAN_PLAY_DAC1; i <= ENVY24_CHAN_PLAY_SPDIF; i++) {
2081			ch = &sc->chan[i];
2082#if(0)
2083			if (ch->run)
2084				device_printf(sc->dev, "envy24_intr(): chan[%d].blk = %d\n", i, ch->blk);
2085#endif
2086			if (ch->run && ch->blk <= feed) {
2087				snd_mtxunlock(sc->lock);
2088				chn_intr(ch->channel);
2089				snd_mtxlock(sc->lock);
2090			}
2091		}
2092		sc->intr[0] = ptr;
2093		envy24_updintr(sc, PCMDIR_PLAY);
2094	}
2095	if (envy24_checkintr(sc, PCMDIR_REC)) {
2096#if(0)
2097		device_printf(sc->dev, "envy24_intr(): rec\n");
2098#endif
2099		dsize = sc->rsize / 4;
2100		ptr = dsize - envy24_rdmt(sc, ENVY24_MT_RCNT, 2) - 1;
2101		ptr -= ptr % sc->blk[1];
2102		feed = (ptr + dsize - sc->intr[1]) % dsize;
2103		for (i = ENVY24_CHAN_REC_ADC1; i <= ENVY24_CHAN_REC_SPDIF; i++) {
2104			ch = &sc->chan[i];
2105			if (ch->run && ch->blk <= feed) {
2106				snd_mtxunlock(sc->lock);
2107				chn_intr(ch->channel);
2108				snd_mtxlock(sc->lock);
2109			}
2110		}
2111		sc->intr[1] = ptr;
2112		envy24_updintr(sc, PCMDIR_REC);
2113	}
2114	snd_mtxunlock(sc->lock);
2115
2116	return;
2117}
2118
2119/*
2120 * Probe and attach the card
2121 */
2122
2123static int
2124envy24_pci_probe(device_t dev)
2125{
2126	u_int16_t sv, sd;
2127	int i;
2128
2129#if(0)
2130	printf("envy24_pci_probe()\n");
2131#endif
2132	if (pci_get_device(dev) == PCID_ENVY24 &&
2133	    pci_get_vendor(dev) == PCIV_ENVY24) {
2134		sv = pci_get_subvendor(dev);
2135		sd = pci_get_subdevice(dev);
2136		for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2137			if (cfg_table[i].subvendor == sv &&
2138			    cfg_table[i].subdevice == sd) {
2139				break;
2140			}
2141		}
2142		device_set_desc(dev, cfg_table[i].name);
2143#if(0)
2144		printf("envy24_pci_probe(): return 0\n");
2145#endif
2146		return 0;
2147	}
2148	else {
2149#if(0)
2150		printf("envy24_pci_probe(): return ENXIO\n");
2151#endif
2152		return ENXIO;
2153	}
2154}
2155
2156static void
2157envy24_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2158{
2159	/* struct sc_info *sc = (struct sc_info *)arg; */
2160
2161#if(0)
2162	device_printf(sc->dev, "envy24_dmapsetmap()\n");
2163	if (bootverbose) {
2164		printf("envy24(play): setmap %lx, %lx; ",
2165		    (unsigned long)segs->ds_addr,
2166		    (unsigned long)segs->ds_len);
2167		printf("%p -> %lx\n", sc->pmap, (unsigned long)vtophys(sc->pmap));
2168	}
2169#endif
2170}
2171
2172static void
2173envy24_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2174{
2175	/* struct sc_info *sc = (struct sc_info *)arg; */
2176
2177#if(0)
2178	device_printf(sc->dev, "envy24_dmarsetmap()\n");
2179	if (bootverbose) {
2180		printf("envy24(record): setmap %lx, %lx; ",
2181		    (unsigned long)segs->ds_addr,
2182		    (unsigned long)segs->ds_len);
2183		printf("%p -> %lx\n", sc->rmap, (unsigned long)vtophys(sc->pmap));
2184	}
2185#endif
2186}
2187
2188static void
2189envy24_dmafree(struct sc_info *sc)
2190{
2191#if(0)
2192	device_printf(sc->dev, "envy24_dmafree():");
2193	if (sc->rmap) printf(" sc->rmap(0x%08x)", (u_int32_t)sc->rmap);
2194	else printf(" sc->rmap(null)");
2195	if (sc->pmap) printf(" sc->pmap(0x%08x)", (u_int32_t)sc->pmap);
2196	else printf(" sc->pmap(null)");
2197	if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf);
2198	else printf(" sc->rbuf(null)");
2199	if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf);
2200	else printf(" sc->pbuf(null)\n");
2201#endif
2202#if(0)
2203	if (sc->rmap)
2204		bus_dmamap_unload(sc->dmat, sc->rmap);
2205	if (sc->pmap)
2206		bus_dmamap_unload(sc->dmat, sc->pmap);
2207	if (sc->rbuf)
2208		bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2209	if (sc->pbuf)
2210		bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2211#else
2212	bus_dmamap_unload(sc->dmat, sc->rmap);
2213	bus_dmamap_unload(sc->dmat, sc->pmap);
2214	bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2215	bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2216#endif
2217
2218	sc->rmap = sc->pmap = NULL;
2219	sc->pbuf = NULL;
2220	sc->rbuf = NULL;
2221
2222	return;
2223}
2224
2225static int
2226envy24_dmainit(struct sc_info *sc)
2227{
2228	u_int32_t addr;
2229
2230#if(0)
2231	device_printf(sc->dev, "envy24_dmainit()\n");
2232#endif
2233	/* init values */
2234	sc->psize = ENVY24_PLAY_BUFUNIT * ENVY24_SAMPLE_NUM;
2235	sc->rsize = ENVY24_REC_BUFUNIT * ENVY24_SAMPLE_NUM;
2236	sc->pbuf = NULL;
2237	sc->rbuf = NULL;
2238	sc->pmap = sc->rmap = NULL;
2239	sc->blk[0] = sc->blk[1] = 0;
2240
2241	/* allocate DMA buffer */
2242#if(0)
2243	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->pbuf\n");
2244#endif
2245	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap))
2246		goto bad;
2247#if(0)
2248	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->rbuf\n");
2249#endif
2250	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap))
2251		goto bad;
2252#if(0)
2253	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->pmap\n");
2254#endif
2255	if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24_dmapsetmap, sc, 0))
2256		goto bad;
2257#if(0)
2258	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->rmap\n");
2259#endif
2260	if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24_dmarsetmap, sc, 0))
2261		goto bad;
2262	bzero(sc->pbuf, sc->psize);
2263	bzero(sc->rbuf, sc->rsize);
2264
2265	/* set values to register */
2266	addr = vtophys(sc->pbuf);
2267#if(0)
2268	device_printf(sc->dev, "pbuf(0x%08x)\n", addr);
2269#endif
2270	envy24_wrmt(sc, ENVY24_MT_PADDR, addr, 4);
2271#if(0)
2272	device_printf(sc->dev, "PADDR-->(0x%08x)\n", envy24_rdmt(sc, ENVY24_MT_PADDR, 4));
2273	device_printf(sc->dev, "psize(%ld)\n", sc->psize / 4 - 1);
2274#endif
2275	envy24_wrmt(sc, ENVY24_MT_PCNT, sc->psize / 4 - 1, 2);
2276#if(0)
2277	device_printf(sc->dev, "PCNT-->(%ld)\n", envy24_rdmt(sc, ENVY24_MT_PCNT, 2));
2278#endif
2279	addr = vtophys(sc->rbuf);
2280	envy24_wrmt(sc, ENVY24_MT_RADDR, addr, 4);
2281	envy24_wrmt(sc, ENVY24_MT_RCNT, sc->rsize / 4 - 1, 2);
2282
2283	return 0;
2284 bad:
2285	envy24_dmafree(sc);
2286	return ENOSPC;
2287}
2288
2289static void
2290envy24_putcfg(struct sc_info *sc)
2291{
2292	device_printf(sc->dev, "system configuration\n");
2293	printf("  SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n",
2294	    sc->cfg->subvendor, sc->cfg->subdevice);
2295	printf("  XIN2 Clock Source: ");
2296	switch (sc->cfg->scfg & PCIM_SCFG_XIN2) {
2297	case 0x00:
2298		printf("22.5792MHz(44.1kHz*512)\n");
2299		break;
2300	case 0x40:
2301		printf("16.9344MHz(44.1kHz*384)\n");
2302		break;
2303	case 0x80:
2304		printf("from external clock synthesizer chip\n");
2305		break;
2306	default:
2307		printf("illeagal system setting\n");
2308	}
2309	printf("  MPU-401 UART(s) #: ");
2310	if (sc->cfg->scfg & PCIM_SCFG_MPU)
2311		printf("2\n");
2312	else
2313		printf("1\n");
2314	printf("  AC'97 codec: ");
2315	if (sc->cfg->scfg & PCIM_SCFG_AC97)
2316		printf("not exist\n");
2317	else
2318		printf("exist\n");
2319	printf("  ADC #: ");
2320	printf("%d\n", sc->adcn);
2321	printf("  DAC #: ");
2322	printf("%d\n", sc->dacn);
2323	printf("  Multi-track converter type: ");
2324	if ((sc->cfg->acl & PCIM_ACL_MTC) == 0) {
2325		printf("AC'97(SDATA_OUT:");
2326		if (sc->cfg->acl & PCIM_ACL_OMODE)
2327			printf("packed");
2328		else
2329			printf("split");
2330		printf("|SDATA_IN:");
2331		if (sc->cfg->acl & PCIM_ACL_IMODE)
2332			printf("packed");
2333		else
2334			printf("split");
2335		printf(")\n");
2336	}
2337	else {
2338		printf("I2S(");
2339		if (sc->cfg->i2s & PCIM_I2S_VOL)
2340			printf("with volume, ");
2341		if (sc->cfg->i2s & PCIM_I2S_96KHZ)
2342			printf("96KHz support, ");
2343		switch (sc->cfg->i2s & PCIM_I2S_RES) {
2344		case PCIM_I2S_16BIT:
2345			printf("16bit resolution, ");
2346			break;
2347		case PCIM_I2S_18BIT:
2348			printf("18bit resolution, ");
2349			break;
2350		case PCIM_I2S_20BIT:
2351			printf("20bit resolution, ");
2352			break;
2353		case PCIM_I2S_24BIT:
2354			printf("24bit resolution, ");
2355			break;
2356		}
2357		printf("ID#0x%x)\n", sc->cfg->i2s & PCIM_I2S_ID);
2358	}
2359	printf("  S/PDIF(IN/OUT): ");
2360	if (sc->cfg->spdif & PCIM_SPDIF_IN)
2361		printf("1/");
2362	else
2363		printf("0/");
2364	if (sc->cfg->spdif & PCIM_SPDIF_OUT)
2365		printf("1 ");
2366	else
2367		printf("0 ");
2368	if (sc->cfg->spdif & (PCIM_SPDIF_IN | PCIM_SPDIF_OUT))
2369		printf("ID# 0x%02x\n", (sc->cfg->spdif & PCIM_SPDIF_ID) >> 2);
2370	printf("  GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n",
2371	    sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate);
2372}
2373
2374static int
2375envy24_init(struct sc_info *sc)
2376{
2377	u_int32_t data;
2378#if(0)
2379	int rtn;
2380#endif
2381	int i;
2382	u_int32_t sv, sd;
2383
2384
2385#if(0)
2386	device_printf(sc->dev, "envy24_init()\n");
2387#endif
2388
2389	/* reset chip */
2390	envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_RESET | ENVY24_CCS_CTL_NATIVE, 1);
2391	DELAY(200);
2392	envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_NATIVE, 1);
2393	DELAY(200);
2394
2395	/* legacy hardware disable */
2396	data = pci_read_config(sc->dev, PCIR_LAC, 2);
2397	data |= PCIM_LAC_DISABLE;
2398	pci_write_config(sc->dev, PCIR_LAC, data, 2);
2399
2400	/* check system configuration */
2401	sc->cfg = NULL;
2402	for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2403		/* 1st: search configuration from table */
2404		sv = pci_get_subvendor(sc->dev);
2405		sd = pci_get_subdevice(sc->dev);
2406		if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) {
2407#if(0)
2408			device_printf(sc->dev, "Set configuration from table\n");
2409#endif
2410			sc->cfg = &cfg_table[i];
2411			break;
2412		}
2413	}
2414	if (sc->cfg == NULL) {
2415		/* 2nd: read configuration from table */
2416		sc->cfg = envy24_rom2cfg(sc);
2417	}
2418	sc->adcn = ((sc->cfg->scfg & PCIM_SCFG_ADC) >> 2) + 1;
2419	sc->dacn = (sc->cfg->scfg & PCIM_SCFG_DAC) + 1;
2420
2421	if (1 /* bootverbose */) {
2422		envy24_putcfg(sc);
2423	}
2424
2425	/* set system configuration */
2426	pci_write_config(sc->dev, PCIR_SCFG, sc->cfg->scfg, 1);
2427	pci_write_config(sc->dev, PCIR_ACL, sc->cfg->acl, 1);
2428	pci_write_config(sc->dev, PCIR_I2S, sc->cfg->i2s, 1);
2429	pci_write_config(sc->dev, PCIR_SPDIF, sc->cfg->spdif, 1);
2430	envy24_gpiosetmask(sc, sc->cfg->gpiomask);
2431	envy24_gpiosetdir(sc, sc->cfg->gpiodir);
2432	envy24_gpiowr(sc, sc->cfg->gpiostate);
2433	for (i = 0; i < sc->adcn; i++) {
2434		sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i);
2435		sc->cfg->codec->init(sc->adc[i]);
2436	}
2437	for (i = 0; i < sc->dacn; i++) {
2438		sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i);
2439		sc->cfg->codec->init(sc->dac[i]);
2440	}
2441
2442	/* initialize DMA buffer */
2443#if(0)
2444	device_printf(sc->dev, "envy24_init(): initialize DMA buffer\n");
2445#endif
2446	if (envy24_dmainit(sc))
2447		return ENOSPC;
2448
2449	/* initialize status */
2450	sc->run[0] = sc->run[1] = 0;
2451	sc->intr[0] = sc->intr[1] = 0;
2452	sc->speed = 0;
2453	sc->caps[0].fmtlist = envy24_playfmt;
2454	sc->caps[1].fmtlist = envy24_recfmt;
2455
2456	/* set channel router */
2457	envy24_route(sc, ENVY24_ROUTE_DAC_1, ENVY24_ROUTE_CLASS_MIX, 0, 0);
2458	envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_DMA, 0, 0);
2459	/* envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_MIX, 0, 0); */
2460
2461	/* set macro interrupt mask */
2462	data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1);
2463	envy24_wrcs(sc, ENVY24_CCS_IMASK, data & ~ENVY24_CCS_IMASK_PMT, 1);
2464	data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1);
2465#if(0)
2466	device_printf(sc->dev, "envy24_init(): CCS_IMASK-->0x%02x\n", data);
2467#endif
2468
2469	return 0;
2470}
2471
2472static int
2473envy24_alloc_resource(struct sc_info *sc)
2474{
2475	/* allocate I/O port resource */
2476	sc->csid = PCIR_CCS;
2477	sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2478	    &sc->csid, 0, ~0, 1, RF_ACTIVE);
2479	sc->ddmaid = PCIR_DDMA;
2480	sc->ddma = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2481	    &sc->ddmaid, 0, ~0, 1, RF_ACTIVE);
2482	sc->dsid = PCIR_DS;
2483	sc->ds = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2484	    &sc->dsid, 0, ~0, 1, RF_ACTIVE);
2485	sc->mtid = PCIR_MT;
2486	sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2487	    &sc->mtid, 0, ~0, 1, RF_ACTIVE);
2488	if (!sc->cs || !sc->ddma || !sc->ds || !sc->mt) {
2489		device_printf(sc->dev, "unable to map IO port space\n");
2490		return ENXIO;
2491	}
2492	sc->cst = rman_get_bustag(sc->cs);
2493	sc->csh = rman_get_bushandle(sc->cs);
2494	sc->ddmat = rman_get_bustag(sc->ddma);
2495	sc->ddmah = rman_get_bushandle(sc->ddma);
2496	sc->dst = rman_get_bustag(sc->ds);
2497	sc->dsh = rman_get_bushandle(sc->ds);
2498	sc->mtt = rman_get_bustag(sc->mt);
2499	sc->mth = rman_get_bushandle(sc->mt);
2500#if(0)
2501	device_printf(sc->dev,
2502	    "IO port register values\nCCS: 0x%lx\nDDMA: 0x%lx\nDS: 0x%lx\nMT: 0x%lx\n",
2503	    pci_read_config(sc->dev, PCIR_CCS, 4),
2504	    pci_read_config(sc->dev, PCIR_DDMA, 4),
2505	    pci_read_config(sc->dev, PCIR_DS, 4),
2506	    pci_read_config(sc->dev, PCIR_MT, 4));
2507#endif
2508
2509	/* allocate interrupt resource */
2510	sc->irqid = 0;
2511	sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid,
2512				 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
2513	if (!sc->irq ||
2514	    snd_setup_intr(sc->dev, sc->irq, INTR_MPSAFE, envy24_intr, sc, &sc->ih)) {
2515		device_printf(sc->dev, "unable to map interrupt\n");
2516		return ENXIO;
2517	}
2518
2519	/* allocate DMA resource */
2520	if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev),
2521	    /*alignment*/4,
2522	    /*boundary*/0,
2523	    /*lowaddr*/BUS_SPACE_MAXADDR_ENVY24,
2524	    /*highaddr*/BUS_SPACE_MAXADDR_ENVY24,
2525	    /*filter*/NULL, /*filterarg*/NULL,
2526	    /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24,
2527	    /*nsegments*/1, /*maxsegsz*/0x3ffff,
2528	    /*flags*/0, /*lockfunc*/busdma_lock_mutex,
2529	    /*lockarg*/&Giant, &sc->dmat) != 0) {
2530		device_printf(sc->dev, "unable to create dma tag\n");
2531		return ENXIO;
2532	}
2533
2534	return 0;
2535}
2536
2537static int
2538envy24_pci_attach(device_t dev)
2539{
2540	u_int32_t		data;
2541	struct sc_info 		*sc;
2542	char 			status[SND_STATUSLEN];
2543	int			err = 0;
2544	int			i;
2545
2546#if(0)
2547	device_printf(dev, "envy24_pci_attach()\n");
2548#endif
2549	/* get sc_info data area */
2550	if ((sc = malloc(sizeof(*sc), M_ENVY24, M_NOWAIT)) == NULL) {
2551		device_printf(dev, "cannot allocate softc\n");
2552		return ENXIO;
2553	}
2554
2555	bzero(sc, sizeof(*sc));
2556	sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_envy24 softc");
2557	sc->dev = dev;
2558
2559	/* initialize PCI interface */
2560	data = pci_read_config(dev, PCIR_COMMAND, 2);
2561	data |= (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN);
2562	pci_write_config(dev, PCIR_COMMAND, data, 2);
2563	data = pci_read_config(dev, PCIR_COMMAND, 2);
2564
2565	/* allocate resources */
2566	err = envy24_alloc_resource(sc);
2567	if (err) {
2568		device_printf(dev, "unable to allocate system resources\n");
2569		goto bad;
2570	}
2571
2572	/* initialize card */
2573	err = envy24_init(sc);
2574	if (err) {
2575		device_printf(dev, "unable to initialize the card\n");
2576		goto bad;
2577	}
2578
2579	/* set multi track mixer */
2580	mixer_init(dev, &envy24mixer_class, sc);
2581
2582	/* set channel information */
2583	err = pcm_register(dev, sc, 5, 2 + sc->adcn);
2584	if (err)
2585		goto bad;
2586	sc->chnum = 0;
2587	for (i = 0; i < 5; i++) {
2588		pcm_addchan(dev, PCMDIR_PLAY, &envy24chan_class, sc);
2589		sc->chnum++;
2590	}
2591	for (i = 0; i < 2 + sc->adcn; i++) {
2592		pcm_addchan(dev, PCMDIR_REC, &envy24chan_class, sc);
2593		sc->chnum++;
2594	}
2595
2596	/* set status iformation */
2597	snprintf(status, SND_STATUSLEN,
2598	    "at io 0x%lx:%ld,0x%lx:%ld,0x%lx:%ld,0x%lx:%ld irq %ld",
2599	    rman_get_start(sc->cs),
2600	    rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1,
2601	    rman_get_start(sc->ddma),
2602	    rman_get_end(sc->ddma) - rman_get_start(sc->ddma) + 1,
2603	    rman_get_start(sc->ds),
2604	    rman_get_end(sc->ds) - rman_get_start(sc->ds) + 1,
2605	    rman_get_start(sc->mt),
2606	    rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1,
2607	    rman_get_start(sc->irq));
2608	pcm_setstatus(dev, status);
2609
2610	return 0;
2611
2612bad:
2613	if (sc->ih)
2614		bus_teardown_intr(dev, sc->irq, sc->ih);
2615	if (sc->irq)
2616		bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2617	envy24_dmafree(sc);
2618	if (sc->dmat)
2619		bus_dma_tag_destroy(sc->dmat);
2620	if (sc->cfg->codec->destroy != NULL) {
2621                for (i = 0; i < sc->adcn; i++)
2622                        sc->cfg->codec->destroy(sc->adc[i]);
2623                for (i = 0; i < sc->dacn; i++)
2624                        sc->cfg->codec->destroy(sc->dac[i]);
2625        }
2626	envy24_cfgfree(sc->cfg);
2627	if (sc->cs)
2628		bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2629	if (sc->ddma)
2630		bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma);
2631	if (sc->ds)
2632		bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds);
2633	if (sc->mt)
2634		bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2635	if (sc->lock)
2636		snd_mtxfree(sc->lock);
2637	free(sc, M_ENVY24);
2638	return err;
2639}
2640
2641static int
2642envy24_pci_detach(device_t dev)
2643{
2644	struct sc_info *sc;
2645	int r;
2646	int i;
2647
2648#if(0)
2649	device_printf(dev, "envy24_pci_detach()\n");
2650#endif
2651	sc = pcm_getdevinfo(dev);
2652	if (sc == NULL)
2653		return 0;
2654	r = pcm_unregister(dev);
2655	if (r)
2656		return r;
2657
2658	envy24_dmafree(sc);
2659	if (sc->cfg->codec->destroy != NULL) {
2660		for (i = 0; i < sc->adcn; i++)
2661			sc->cfg->codec->destroy(sc->adc[i]);
2662		for (i = 0; i < sc->dacn; i++)
2663			sc->cfg->codec->destroy(sc->dac[i]);
2664	}
2665	envy24_cfgfree(sc->cfg);
2666	bus_dma_tag_destroy(sc->dmat);
2667	bus_teardown_intr(dev, sc->irq, sc->ih);
2668	bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2669	bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2670	bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma);
2671	bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds);
2672	bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2673	snd_mtxfree(sc->lock);
2674	free(sc, M_ENVY24);
2675	return 0;
2676}
2677
2678static device_method_t envy24_methods[] = {
2679	/* Device interface */
2680	DEVMETHOD(device_probe,		envy24_pci_probe),
2681	DEVMETHOD(device_attach,	envy24_pci_attach),
2682	DEVMETHOD(device_detach,	envy24_pci_detach),
2683	{ 0, 0 }
2684};
2685
2686static driver_t envy24_driver = {
2687	"pcm",
2688	envy24_methods,
2689#if __FreeBSD_version > 500000
2690	PCM_SOFTC_SIZE,
2691#else
2692	sizeof(struct snddev_info),
2693#endif
2694};
2695
2696DRIVER_MODULE(snd_envy24, pci, envy24_driver, pcm_devclass, 0, 0);
2697MODULE_DEPEND(snd_envy24, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
2698MODULE_DEPEND(snd_envy24, snd_spicds, 1, 1, 1);
2699MODULE_VERSION(snd_envy24, 1);
2700