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