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