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