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