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