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