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