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