envy24ht.c revision 213779
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: head/sys/dev/sound/pci/envy24ht.c 213779 2010-10-13 14:39:54Z rpaulo $");
55
56MALLOC_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 = (struct sc_info *)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		printf("%p -> %lx\n", sc->pmap, (unsigned long)vtophys(sc->pmap));
2092	}
2093#endif
2094}
2095
2096static void
2097envy24ht_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
2098{
2099	/* struct sc_info *sc = (struct sc_info *)arg; */
2100
2101#if(0)
2102	device_printf(sc->dev, "envy24ht_dmarsetmap()\n");
2103	if (bootverbose) {
2104		printf("envy24ht(record): setmap %lx, %lx; ",
2105		    (unsigned long)segs->ds_addr,
2106		    (unsigned long)segs->ds_len);
2107		printf("%p -> %lx\n", sc->rmap, (unsigned long)vtophys(sc->pmap));
2108	}
2109#endif
2110}
2111
2112static void
2113envy24ht_dmafree(struct sc_info *sc)
2114{
2115#if(0)
2116	device_printf(sc->dev, "envy24ht_dmafree():");
2117	if (sc->rmap) printf(" sc->rmap(0x%08x)", (u_int32_t)sc->rmap);
2118	else printf(" sc->rmap(null)");
2119	if (sc->pmap) printf(" sc->pmap(0x%08x)", (u_int32_t)sc->pmap);
2120	else printf(" sc->pmap(null)");
2121	if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf);
2122	else printf(" sc->rbuf(null)");
2123	if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf);
2124	else printf(" sc->pbuf(null)\n");
2125#endif
2126#if(0)
2127	if (sc->rmap)
2128		bus_dmamap_unload(sc->dmat, sc->rmap);
2129	if (sc->pmap)
2130		bus_dmamap_unload(sc->dmat, sc->pmap);
2131	if (sc->rbuf)
2132		bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2133	if (sc->pbuf)
2134		bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2135#else
2136	bus_dmamap_unload(sc->dmat, sc->rmap);
2137	bus_dmamap_unload(sc->dmat, sc->pmap);
2138	bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2139	bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2140#endif
2141
2142	sc->rmap = sc->pmap = NULL;
2143	sc->pbuf = NULL;
2144	sc->rbuf = NULL;
2145
2146	return;
2147}
2148
2149static int
2150envy24ht_dmainit(struct sc_info *sc)
2151{
2152	u_int32_t addr;
2153
2154#if(0)
2155	device_printf(sc->dev, "envy24ht_dmainit()\n");
2156#endif
2157	/* init values */
2158	sc->psize = ENVY24HT_PLAY_BUFUNIT * ENVY24HT_SAMPLE_NUM;
2159	sc->rsize = ENVY24HT_REC_BUFUNIT * ENVY24HT_SAMPLE_NUM;
2160	sc->pbuf = NULL;
2161	sc->rbuf = NULL;
2162	sc->pmap = sc->rmap = NULL;
2163	sc->blk[0] = sc->blk[1] = 0;
2164
2165	/* allocate DMA buffer */
2166#if(0)
2167	device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->pbuf\n");
2168#endif
2169	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap))
2170		goto bad;
2171#if(0)
2172	device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_alloc(): sc->rbuf\n");
2173#endif
2174	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap))
2175		goto bad;
2176#if(0)
2177	device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->pmap\n");
2178#endif
2179	if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24ht_dmapsetmap, sc, 0))
2180		goto bad;
2181#if(0)
2182	device_printf(sc->dev, "envy24ht_dmainit(): bus_dmamem_load(): sc->rmap\n");
2183#endif
2184	if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24ht_dmarsetmap, sc, 0))
2185		goto bad;
2186	bzero(sc->pbuf, sc->psize);
2187	bzero(sc->rbuf, sc->rsize);
2188
2189	/* set values to register */
2190	addr = vtophys(sc->pbuf);
2191#if(0)
2192	device_printf(sc->dev, "pbuf(0x%08x)\n", addr);
2193#endif
2194	envy24ht_wrmt(sc, ENVY24HT_MT_PADDR, addr, 4);
2195#if(0)
2196	device_printf(sc->dev, "PADDR-->(0x%08x)\n", envy24ht_rdmt(sc, ENVY24HT_MT_PADDR, 4));
2197	device_printf(sc->dev, "psize(%ld)\n", sc->psize / 4 - 1);
2198#endif
2199	envy24ht_wrmt(sc, ENVY24HT_MT_PCNT, sc->psize / 4 - 1, 2);
2200#if(0)
2201	device_printf(sc->dev, "PCNT-->(%ld)\n", envy24ht_rdmt(sc, ENVY24HT_MT_PCNT, 2));
2202#endif
2203	addr = vtophys(sc->rbuf);
2204	envy24ht_wrmt(sc, ENVY24HT_MT_RADDR, addr, 4);
2205	envy24ht_wrmt(sc, ENVY24HT_MT_RCNT, sc->rsize / 4 - 1, 2);
2206
2207	return 0;
2208 bad:
2209	envy24ht_dmafree(sc);
2210	return ENOSPC;
2211}
2212
2213static void
2214envy24ht_putcfg(struct sc_info *sc)
2215{
2216	device_printf(sc->dev, "system configuration\n");
2217	printf("  SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n",
2218	    sc->cfg->subvendor, sc->cfg->subdevice);
2219	printf("  XIN2 Clock Source: ");
2220	switch (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) {
2221	case 0x00:
2222		printf("24.576MHz(96kHz*256)\n");
2223		break;
2224	case 0x40:
2225		printf("49.152MHz(192kHz*256)\n");
2226		break;
2227	case 0x80:
2228		printf("reserved\n");
2229		break;
2230	default:
2231		printf("illeagal system setting\n");
2232	}
2233	printf("  MPU-401 UART(s) #: ");
2234	if (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_MPU)
2235		printf("1\n");
2236	else
2237		printf("not implemented\n");
2238        switch (sc->adcn) {
2239        case 0x01:
2240	case 0x02:
2241                printf("  ADC #: ");
2242                printf("%d\n", sc->adcn);
2243                break;
2244        case 0x03:
2245                printf("  ADC #: ");
2246                printf("%d", 1);
2247                printf(" and SPDIF receiver connected\n");
2248                break;
2249        default:
2250                printf("  no physical inputs\n");
2251        }
2252	printf("  DAC #: ");
2253	printf("%d\n", sc->dacn);
2254	printf("  Multi-track converter type: ");
2255	if ((sc->cfg->acl & ENVY24HT_CCSM_ACL_MTC) == 0) {
2256		printf("AC'97(SDATA_OUT:");
2257		if (sc->cfg->acl & ENVY24HT_CCSM_ACL_OMODE)
2258			printf("packed");
2259		else
2260			printf("split");
2261		printf(")\n");
2262	}
2263	else {
2264		printf("I2S(");
2265		if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_VOL)
2266			printf("with volume, ");
2267                if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_192KHZ)
2268                        printf("192KHz support, ");
2269                else
2270                if (sc->cfg->i2s & ENVY24HT_CCSM_I2S_96KHZ)
2271                        printf("192KHz support, ");
2272                else
2273                        printf("48KHz support, ");
2274		switch (sc->cfg->i2s & ENVY24HT_CCSM_I2S_RES) {
2275		case ENVY24HT_CCSM_I2S_16BIT:
2276			printf("16bit resolution, ");
2277			break;
2278		case ENVY24HT_CCSM_I2S_18BIT:
2279			printf("18bit resolution, ");
2280			break;
2281		case ENVY24HT_CCSM_I2S_20BIT:
2282			printf("20bit resolution, ");
2283			break;
2284		case ENVY24HT_CCSM_I2S_24BIT:
2285			printf("24bit resolution, ");
2286			break;
2287		}
2288		printf("ID#0x%x)\n", sc->cfg->i2s & ENVY24HT_CCSM_I2S_ID);
2289	}
2290	printf("  S/PDIF(IN/OUT): ");
2291	if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_IN)
2292		printf("1/");
2293	else
2294		printf("0/");
2295	if (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_OUT)
2296		printf("1 ");
2297	else
2298		printf("0 ");
2299	if (sc->cfg->spdif & (ENVY24HT_CCSM_SPDIF_IN | ENVY24HT_CCSM_SPDIF_OUT))
2300		printf("ID# 0x%02x\n", (sc->cfg->spdif & ENVY24HT_CCSM_SPDIF_ID) >> 2);
2301	printf("  GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n",
2302	    sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate);
2303}
2304
2305static int
2306envy24ht_init(struct sc_info *sc)
2307{
2308	u_int32_t data;
2309#if(0)
2310	int rtn;
2311#endif
2312	int i;
2313	u_int32_t sv, sd;
2314
2315
2316#if(0)
2317	device_printf(sc->dev, "envy24ht_init()\n");
2318#endif
2319
2320	/* reset chip */
2321#if 0
2322	envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_RESET, 1);
2323	DELAY(200);
2324	envy24ht_wrcs(sc, ENVY24HT_CCS_CTL, ENVY24HT_CCS_CTL_NATIVE, 1);
2325	DELAY(200);
2326
2327	/* legacy hardware disable */
2328	data = pci_read_config(sc->dev, PCIR_LAC, 2);
2329	data |= PCIM_LAC_DISABLE;
2330	pci_write_config(sc->dev, PCIR_LAC, data, 2);
2331#endif
2332
2333	/* check system configuration */
2334	sc->cfg = NULL;
2335	for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2336		/* 1st: search configuration from table */
2337		sv = pci_get_subvendor(sc->dev);
2338		sd = pci_get_subdevice(sc->dev);
2339		if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) {
2340#if(0)
2341			device_printf(sc->dev, "Set configuration from table\n");
2342#endif
2343			sc->cfg = &cfg_table[i];
2344			break;
2345		}
2346	}
2347	if (sc->cfg == NULL) {
2348		/* 2nd: read configuration from table */
2349		sc->cfg = envy24ht_rom2cfg(sc);
2350	}
2351	sc->adcn = ((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_ADC) >> 2) + 1; /* need to be fixed */
2352	sc->dacn = (sc->cfg->scfg & ENVY24HT_CCSM_SCFG_DAC) + 1;
2353
2354	if (1 /* bootverbose */) {
2355		envy24ht_putcfg(sc);
2356	}
2357
2358	/* set system configuration */
2359	envy24ht_wrcs(sc, ENVY24HT_CCS_SCFG, sc->cfg->scfg, 1);
2360	envy24ht_wrcs(sc, ENVY24HT_CCS_ACL, sc->cfg->acl, 1);
2361	envy24ht_wrcs(sc, ENVY24HT_CCS_I2S, sc->cfg->i2s, 1);
2362	envy24ht_wrcs(sc, ENVY24HT_CCS_SPDIF, sc->cfg->spdif, 1);
2363	envy24ht_gpiosetmask(sc, sc->cfg->gpiomask);
2364	envy24ht_gpiosetdir(sc, sc->cfg->gpiodir);
2365	envy24ht_gpiowr(sc, sc->cfg->gpiostate);
2366
2367	if ((sc->cfg->subvendor == 0x3031) && (sc->cfg->subdevice == 0x4553)) {
2368		envy24ht_wri2c(sc, 0x22, 0x00, 0x07);
2369		envy24ht_wri2c(sc, 0x22, 0x04, 0x5f | 0x80);
2370		envy24ht_wri2c(sc, 0x22, 0x05, 0x5f | 0x80);
2371	}
2372
2373	for (i = 0; i < sc->adcn; i++) {
2374		sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i);
2375		sc->cfg->codec->init(sc->adc[i]);
2376	}
2377	for (i = 0; i < sc->dacn; i++) {
2378		sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i);
2379		sc->cfg->codec->init(sc->dac[i]);
2380	}
2381
2382	/* initialize DMA buffer */
2383#if(0)
2384	device_printf(sc->dev, "envy24ht_init(): initialize DMA buffer\n");
2385#endif
2386	if (envy24ht_dmainit(sc))
2387		return ENOSPC;
2388
2389	/* initialize status */
2390	sc->run[0] = sc->run[1] = 0;
2391	sc->intr[0] = sc->intr[1] = 0;
2392	sc->speed = 0;
2393	sc->caps[0].fmtlist = envy24ht_playfmt;
2394	sc->caps[1].fmtlist = envy24ht_recfmt;
2395
2396	/* set channel router */
2397#if 0
2398	envy24ht_route(sc, ENVY24HT_ROUTE_DAC_1, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
2399	envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_DMA, 0, 0);
2400	envy24ht_route(sc, ENVY24HT_ROUTE_DAC_SPDIF, ENVY24HT_ROUTE_CLASS_MIX, 0, 0);
2401#endif
2402
2403	/* set macro interrupt mask */
2404	data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
2405	envy24ht_wrcs(sc, ENVY24HT_CCS_IMASK, data & ~ENVY24HT_CCS_IMASK_PMT, 1);
2406	data = envy24ht_rdcs(sc, ENVY24HT_CCS_IMASK, 1);
2407#if(0)
2408	device_printf(sc->dev, "envy24ht_init(): CCS_IMASK-->0x%02x\n", data);
2409#endif
2410
2411	return 0;
2412}
2413
2414static int
2415envy24ht_alloc_resource(struct sc_info *sc)
2416{
2417	/* allocate I/O port resource */
2418	sc->csid = PCIR_CCS;
2419	sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2420	    &sc->csid, 0, ~0, 1, RF_ACTIVE);
2421	sc->mtid = ENVY24HT_PCIR_MT;
2422	sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2423	    &sc->mtid, 0, ~0, 1, RF_ACTIVE);
2424	if (!sc->cs || !sc->mt) {
2425		device_printf(sc->dev, "unable to map IO port space\n");
2426		return ENXIO;
2427	}
2428	sc->cst = rman_get_bustag(sc->cs);
2429	sc->csh = rman_get_bushandle(sc->cs);
2430	sc->mtt = rman_get_bustag(sc->mt);
2431	sc->mth = rman_get_bushandle(sc->mt);
2432#if(0)
2433	device_printf(sc->dev,
2434	    "IO port register values\nCCS: 0x%lx\nMT: 0x%lx\n",
2435	    pci_read_config(sc->dev, PCIR_CCS, 4),
2436	    pci_read_config(sc->dev, PCIR_MT, 4));
2437#endif
2438
2439	/* allocate interrupt resource */
2440	sc->irqid = 0;
2441	sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid,
2442				 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
2443	if (!sc->irq ||
2444	    snd_setup_intr(sc->dev, sc->irq, 0, envy24ht_intr, sc, &sc->ih)) {
2445		device_printf(sc->dev, "unable to map interrupt\n");
2446		return ENXIO;
2447	}
2448
2449	/* allocate DMA resource */
2450	if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev),
2451	    /*alignment*/4,
2452	    /*boundary*/0,
2453	    /*lowaddr*/BUS_SPACE_MAXADDR_ENVY24,
2454	    /*highaddr*/BUS_SPACE_MAXADDR_ENVY24,
2455	    /*filter*/NULL, /*filterarg*/NULL,
2456	    /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24,
2457	    /*nsegments*/1, /*maxsegsz*/0x3ffff,
2458	    /*flags*/0, /*lockfunc*/busdma_lock_mutex,
2459	    /*lockarg*/&Giant, &sc->dmat) != 0) {
2460		device_printf(sc->dev, "unable to create dma tag\n");
2461		return ENXIO;
2462	}
2463
2464	return 0;
2465}
2466
2467static int
2468envy24ht_pci_attach(device_t dev)
2469{
2470	u_int32_t		data;
2471	struct sc_info 		*sc;
2472	char 			status[SND_STATUSLEN];
2473	int			err = 0;
2474	int			i;
2475
2476#if(0)
2477	device_printf(dev, "envy24ht_pci_attach()\n");
2478#endif
2479	/* get sc_info data area */
2480	if ((sc = malloc(sizeof(*sc), M_ENVY24HT, M_NOWAIT)) == NULL) {
2481		device_printf(dev, "cannot allocate softc\n");
2482		return ENXIO;
2483	}
2484
2485	bzero(sc, sizeof(*sc));
2486	sc->lock = snd_mtxcreate(device_get_nameunit(dev),
2487	    "snd_envy24ht softc");
2488	sc->dev = dev;
2489
2490	/* initialize PCI interface */
2491	data = pci_read_config(dev, PCIR_COMMAND, 2);
2492	data |= (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN);
2493	pci_write_config(dev, PCIR_COMMAND, data, 2);
2494	data = pci_read_config(dev, PCIR_COMMAND, 2);
2495
2496	/* allocate resources */
2497	err = envy24ht_alloc_resource(sc);
2498	if (err) {
2499		device_printf(dev, "unable to allocate system resources\n");
2500		goto bad;
2501	}
2502
2503	/* initialize card */
2504	err = envy24ht_init(sc);
2505	if (err) {
2506		device_printf(dev, "unable to initialize the card\n");
2507		goto bad;
2508	}
2509
2510	/* set multi track mixer */
2511	mixer_init(dev, &envy24htmixer_class, sc);
2512
2513	/* set channel information */
2514	/* err = pcm_register(dev, sc, 5, 2 + sc->adcn); */
2515	err = pcm_register(dev, sc, 1, 2 + sc->adcn);
2516	if (err)
2517		goto bad;
2518	sc->chnum = 0;
2519	/* for (i = 0; i < 5; i++) { */
2520		pcm_addchan(dev, PCMDIR_PLAY, &envy24htchan_class, sc);
2521		sc->chnum++;
2522	/* } */
2523	for (i = 0; i < 2 + sc->adcn; i++) {
2524		pcm_addchan(dev, PCMDIR_REC, &envy24htchan_class, sc);
2525		sc->chnum++;
2526	}
2527
2528	/* set status iformation */
2529	snprintf(status, SND_STATUSLEN,
2530	    "at io 0x%lx:%ld,0x%lx:%ld irq %ld",
2531	    rman_get_start(sc->cs),
2532	    rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1,
2533	    rman_get_start(sc->mt),
2534	    rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1,
2535	    rman_get_start(sc->irq));
2536	pcm_setstatus(dev, status);
2537
2538	return 0;
2539
2540bad:
2541	if (sc->ih)
2542		bus_teardown_intr(dev, sc->irq, sc->ih);
2543	if (sc->irq)
2544		bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2545	envy24ht_dmafree(sc);
2546	if (sc->dmat)
2547		bus_dma_tag_destroy(sc->dmat);
2548        if (sc->cfg->codec->destroy != NULL) {
2549                for (i = 0; i < sc->adcn; i++)
2550                        sc->cfg->codec->destroy(sc->adc[i]);
2551                for (i = 0; i < sc->dacn; i++)
2552                        sc->cfg->codec->destroy(sc->dac[i]);
2553        }
2554	envy24ht_cfgfree(sc->cfg);
2555	if (sc->cs)
2556		bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2557	if (sc->mt)
2558		bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2559	if (sc->lock)
2560		snd_mtxfree(sc->lock);
2561	free(sc, M_ENVY24HT);
2562	return err;
2563}
2564
2565static int
2566envy24ht_pci_detach(device_t dev)
2567{
2568	struct sc_info *sc;
2569	int r;
2570	int i;
2571
2572#if(0)
2573	device_printf(dev, "envy24ht_pci_detach()\n");
2574#endif
2575	sc = pcm_getdevinfo(dev);
2576	if (sc == NULL)
2577		return 0;
2578	r = pcm_unregister(dev);
2579	if (r)
2580		return r;
2581
2582	envy24ht_dmafree(sc);
2583	if (sc->cfg->codec->destroy != NULL) {
2584		for (i = 0; i < sc->adcn; i++)
2585			sc->cfg->codec->destroy(sc->adc[i]);
2586		for (i = 0; i < sc->dacn; i++)
2587			sc->cfg->codec->destroy(sc->dac[i]);
2588	}
2589	envy24ht_cfgfree(sc->cfg);
2590	bus_dma_tag_destroy(sc->dmat);
2591	bus_teardown_intr(dev, sc->irq, sc->ih);
2592	bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2593	bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2594	bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2595	snd_mtxfree(sc->lock);
2596	free(sc, M_ENVY24HT);
2597	return 0;
2598}
2599
2600static device_method_t envy24ht_methods[] = {
2601	/* Device interface */
2602	DEVMETHOD(device_probe,		envy24ht_pci_probe),
2603	DEVMETHOD(device_attach,	envy24ht_pci_attach),
2604	DEVMETHOD(device_detach,	envy24ht_pci_detach),
2605	{ 0, 0 }
2606};
2607
2608static driver_t envy24ht_driver = {
2609	"pcm",
2610	envy24ht_methods,
2611#if __FreeBSD_version > 500000
2612	PCM_SOFTC_SIZE,
2613#else
2614	sizeof(struct snddev_info),
2615#endif
2616};
2617
2618DRIVER_MODULE(snd_envy24ht, pci, envy24ht_driver, pcm_devclass, 0, 0);
2619MODULE_DEPEND(snd_envy24ht, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
2620MODULE_DEPEND(snd_envy24ht, snd_spicds, 1, 1, 1);
2621MODULE_VERSION(snd_envy24ht, 1);
2622