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