envy24.c revision 159689
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 159689 2006-06-17 15:11:36Z 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_PLAY && sc->adc[num] != NULL)
785		buff->info = ((struct envy24_delta_ak4524_codec *)sc->adc[num])->info;
786	else if (dir == PCMDIR_REC && 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	int i;
1595
1596#if(0)
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		else if (ch->blk == sc->blk[slot]) {
1671			sc->blk[slot] = ENVY24_SAMPLE_NUM / 2;
1672			for (i = 0; i < ENVY24_CHAN_NUM; i++) {
1673				if (sc->chan[i].dir == ch->dir &&
1674				    sc->chan[i].run == 1 &&
1675				    sc->chan[i].blk < sc->blk[slot])
1676					sc->blk[slot] = sc->chan[i].blk;
1677			}
1678			if (ch->blk != sc->blk[slot])
1679				envy24_updintr(sc, ch->dir);
1680		}
1681		break;
1682	}
1683	snd_mtxunlock(sc->lock);
1684
1685	return 0;
1686}
1687
1688static int
1689envy24chan_getptr(kobj_t obj, void *data)
1690{
1691	struct sc_chinfo *ch = data;
1692	struct sc_info *sc = ch->parent;
1693	u_int32_t ptr;
1694	int rtn;
1695
1696#if(0)
1697	device_printf(sc->dev, "envy24chan_getptr()\n");
1698#endif
1699	snd_mtxlock(sc->lock);
1700	ptr = envy24_gethwptr(sc, ch->dir);
1701	rtn = ptr * ch->unit;
1702	snd_mtxunlock(sc->lock);
1703
1704#if(0)
1705	device_printf(sc->dev, "envy24chan_getptr(): return %d\n",
1706	    rtn);
1707#endif
1708	return rtn;
1709}
1710
1711static struct pcmchan_caps *
1712envy24chan_getcaps(kobj_t obj, void *data)
1713{
1714	struct sc_chinfo *ch = data;
1715	struct sc_info *sc = ch->parent;
1716	struct pcmchan_caps *rtn;
1717
1718#if(0)
1719	device_printf(sc->dev, "envy24chan_getcaps()\n");
1720#endif
1721	snd_mtxlock(sc->lock);
1722	if (ch->dir == PCMDIR_PLAY) {
1723		if (sc->run[0] == 0)
1724			rtn = &envy24_playcaps;
1725		else
1726			rtn = &sc->caps[0];
1727	}
1728	else {
1729		if (sc->run[1] == 0)
1730			rtn = &envy24_reccaps;
1731		else
1732			rtn = &sc->caps[1];
1733	}
1734	snd_mtxunlock(sc->lock);
1735
1736	return rtn;
1737}
1738
1739static kobj_method_t envy24chan_methods[] = {
1740	KOBJMETHOD(channel_init,		envy24chan_init),
1741	KOBJMETHOD(channel_free,		envy24chan_free),
1742	KOBJMETHOD(channel_setformat,		envy24chan_setformat),
1743	KOBJMETHOD(channel_setspeed,		envy24chan_setspeed),
1744	KOBJMETHOD(channel_setblocksize,	envy24chan_setblocksize),
1745	KOBJMETHOD(channel_trigger,		envy24chan_trigger),
1746	KOBJMETHOD(channel_getptr,		envy24chan_getptr),
1747	KOBJMETHOD(channel_getcaps,		envy24chan_getcaps),
1748	{ 0, 0 }
1749};
1750CHANNEL_DECLARE(envy24chan);
1751
1752/* -------------------------------------------------------------------- */
1753
1754/* mixer interface */
1755
1756static int
1757envy24mixer_init(struct snd_mixer *m)
1758{
1759	struct sc_info *sc = mix_getdevinfo(m);
1760
1761#if(0)
1762	device_printf(sc->dev, "envy24mixer_init()\n");
1763#endif
1764	if (sc == NULL)
1765		return -1;
1766
1767	/* set volume control rate */
1768	snd_mtxlock(sc->lock);
1769	envy24_wrmt(sc, ENVY24_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */
1770
1771	mix_setdevs(m, ENVY24_MIX_MASK);
1772	mix_setrecdevs(m, ENVY24_MIX_REC_MASK);
1773	snd_mtxunlock(sc->lock);
1774
1775	return 0;
1776}
1777
1778static int
1779envy24mixer_reinit(struct snd_mixer *m)
1780{
1781	struct sc_info *sc = mix_getdevinfo(m);
1782
1783	if (sc == NULL)
1784		return -1;
1785#if(0)
1786	device_printf(sc->dev, "envy24mixer_reinit()\n");
1787#endif
1788
1789	return 0;
1790}
1791
1792static int
1793envy24mixer_uninit(struct snd_mixer *m)
1794{
1795	struct sc_info *sc = mix_getdevinfo(m);
1796
1797	if (sc == NULL)
1798		return -1;
1799#if(0)
1800	device_printf(sc->dev, "envy24mixer_uninit()\n");
1801#endif
1802
1803	return 0;
1804}
1805
1806static int
1807envy24mixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
1808{
1809	struct sc_info *sc = mix_getdevinfo(m);
1810	int ch = envy24_mixmap[dev];
1811	int hwch;
1812	int i;
1813
1814	if (sc == NULL)
1815		return -1;
1816	if (dev == 0 && sc->cfg->codec->setvolume == NULL)
1817		return -1;
1818	if (dev != 0 && ch == -1)
1819		return -1;
1820	hwch = envy24_chanmap[ch];
1821#if(0)
1822	device_printf(sc->dev, "envy24mixer_set(m, %d, %d, %d)\n",
1823	    dev, left, right);
1824#endif
1825
1826	snd_mtxlock(sc->lock);
1827	if (dev == 0) {
1828		for (i = 0; i < sc->dacn; i++) {
1829			sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right);
1830		}
1831	}
1832	else {
1833		/* set volume value for hardware */
1834		if ((sc->left[hwch] = 100 - left) > ENVY24_VOL_MIN)
1835			sc->left[hwch] = ENVY24_VOL_MUTE;
1836		if ((sc->right[hwch] = 100 - right) > ENVY24_VOL_MIN)
1837			sc->right[hwch] = ENVY24_VOL_MUTE;
1838
1839		/* set volume for record channel and running play channel */
1840		if (hwch > ENVY24_CHAN_PLAY_SPDIF || sc->chan[ch].run)
1841			envy24_setvolume(sc, hwch);
1842	}
1843	snd_mtxunlock(sc->lock);
1844
1845	return right << 8 | left;
1846}
1847
1848static u_int32_t
1849envy24mixer_setrecsrc(struct snd_mixer *m, u_int32_t src)
1850{
1851	struct sc_info *sc = mix_getdevinfo(m);
1852	int ch = envy24_mixmap[src];
1853#if(0)
1854	device_printf(sc->dev, "envy24mixer_setrecsrc(m, %d)\n", src);
1855#endif
1856
1857	if (ch > ENVY24_CHAN_PLAY_SPDIF)
1858		sc->src = ch;
1859	return src;
1860}
1861
1862static kobj_method_t envy24mixer_methods[] = {
1863	KOBJMETHOD(mixer_init,		envy24mixer_init),
1864	KOBJMETHOD(mixer_reinit,	envy24mixer_reinit),
1865	KOBJMETHOD(mixer_uninit,	envy24mixer_uninit),
1866	KOBJMETHOD(mixer_set,		envy24mixer_set),
1867	KOBJMETHOD(mixer_setrecsrc,	envy24mixer_setrecsrc),
1868	{ 0, 0 }
1869};
1870MIXER_DECLARE(envy24mixer);
1871
1872/* -------------------------------------------------------------------- */
1873
1874/* The interrupt handler */
1875static void
1876envy24_intr(void *p)
1877{
1878	struct sc_info *sc = (struct sc_info *)p;
1879	struct sc_chinfo *ch;
1880	u_int32_t ptr, dsize, feed;
1881	int i;
1882
1883#if(0)
1884	device_printf(sc->dev, "envy24_intr()\n");
1885#endif
1886	snd_mtxlock(sc->lock);
1887	if (envy24_checkintr(sc, PCMDIR_PLAY)) {
1888#if(0)
1889		device_printf(sc->dev, "envy24_intr(): play\n");
1890#endif
1891		dsize = sc->psize / 4;
1892		ptr = dsize - envy24_rdmt(sc, ENVY24_MT_PCNT, 2) - 1;
1893#if(0)
1894		device_printf(sc->dev, "envy24_intr(): ptr = %d-->", ptr);
1895#endif
1896		ptr -= ptr % sc->blk[0];
1897		feed = (ptr + dsize - sc->intr[0]) % dsize;
1898#if(0)
1899		printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed);
1900#endif
1901		for (i = ENVY24_CHAN_PLAY_DAC1; i <= ENVY24_CHAN_PLAY_SPDIF; i++) {
1902			ch = &sc->chan[i];
1903#if(0)
1904			if (ch->run)
1905				device_printf(sc->dev, "envy24_intr(): chan[%d].blk = %d\n", i, ch->blk);
1906#endif
1907			if (ch->run && ch->blk <= feed)
1908				chn_intr(ch->channel);
1909		}
1910		sc->intr[0] = ptr;
1911		envy24_updintr(sc, PCMDIR_PLAY);
1912	}
1913	if (envy24_checkintr(sc, PCMDIR_REC)) {
1914#if(0)
1915		device_printf(sc->dev, "envy24_intr(): rec\n");
1916#endif
1917		dsize = sc->rsize / 4;
1918		ptr = dsize - envy24_rdmt(sc, ENVY24_MT_RCNT, 2) - 1;
1919		ptr -= ptr % sc->blk[1];
1920		feed = (ptr + dsize - sc->intr[1]) % dsize;
1921		for (i = ENVY24_CHAN_REC_ADC1; i <= ENVY24_CHAN_REC_SPDIF; i++) {
1922			ch = &sc->chan[i];
1923			if (ch->run && ch->blk <= feed)
1924				chn_intr(ch->channel);
1925		}
1926		sc->intr[1] = ptr;
1927		envy24_updintr(sc, PCMDIR_REC);
1928	}
1929	snd_mtxunlock(sc->lock);
1930
1931	return;
1932}
1933
1934/*
1935 * Probe and attach the card
1936 */
1937
1938static int
1939envy24_pci_probe(device_t dev)
1940{
1941	u_int16_t sv, sd;
1942	int i;
1943
1944#if(0)
1945	printf("envy24_pci_probe()\n");
1946#endif
1947	if (pci_get_device(dev) == PCID_ENVY24 &&
1948	    pci_get_vendor(dev) == PCIV_ENVY24) {
1949		sv = pci_get_subvendor(dev);
1950		sd = pci_get_subdevice(dev);
1951		for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
1952			if (cfg_table[i].subvendor == sv &&
1953			    cfg_table[i].subdevice == sd) {
1954				break;
1955			}
1956		}
1957		device_set_desc(dev, cfg_table[i].name);
1958#if(0)
1959		printf("envy24_pci_probe(): return 0\n");
1960#endif
1961		return 0;
1962	}
1963	else {
1964#if(0)
1965		printf("envy24_pci_probe(): return ENXIO\n");
1966#endif
1967		return ENXIO;
1968	}
1969}
1970
1971static void
1972envy24_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
1973{
1974	struct sc_info *sc = (struct sc_info *)arg;
1975
1976#if(0)
1977	device_printf(sc->dev, "envy24_dmapsetmap()\n");
1978#endif
1979	if (bootverbose) {
1980		printf("envy24(play): setmap %lx, %lx; ",
1981		    (unsigned long)segs->ds_addr,
1982		    (unsigned long)segs->ds_len);
1983		printf("%p -> %lx\n", sc->pmap, (unsigned long)vtophys(sc->pmap));
1984	}
1985}
1986
1987static void
1988envy24_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
1989{
1990	struct sc_info *sc = (struct sc_info *)arg;
1991
1992#if(0)
1993	device_printf(sc->dev, "envy24_dmarsetmap()\n");
1994#endif
1995	if (bootverbose) {
1996		printf("envy24(record): setmap %lx, %lx; ",
1997		    (unsigned long)segs->ds_addr,
1998		    (unsigned long)segs->ds_len);
1999		printf("%p -> %lx\n", sc->rmap, (unsigned long)vtophys(sc->pmap));
2000	}
2001}
2002
2003static void
2004envy24_dmafree(struct sc_info *sc)
2005{
2006#if(0)
2007	device_printf(sc->dev, "envy24_dmafree():");
2008	if (sc->rmap) printf(" sc->rmap(0x%08x)", (u_int32_t)sc->rmap);
2009	else printf(" sc->rmap(null)");
2010	if (sc->pmap) printf(" sc->pmap(0x%08x)", (u_int32_t)sc->pmap);
2011	else printf(" sc->pmap(null)");
2012	if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf);
2013	else printf(" sc->rbuf(null)");
2014	if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf);
2015	else printf(" sc->pbuf(null)\n");
2016#endif
2017#if(0)
2018	if (sc->rmap)
2019		bus_dmamap_unload(sc->dmat, sc->rmap);
2020	if (sc->pmap)
2021		bus_dmamap_unload(sc->dmat, sc->pmap);
2022	if (sc->rbuf)
2023		bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2024	if (sc->pbuf)
2025		bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2026#else
2027	bus_dmamap_unload(sc->dmat, sc->rmap);
2028	bus_dmamap_unload(sc->dmat, sc->pmap);
2029	bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap);
2030	bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap);
2031#endif
2032
2033	sc->rmap = sc->pmap = NULL;
2034	sc->pbuf = NULL;
2035	sc->rbuf = NULL;
2036
2037	return;
2038}
2039
2040static int
2041envy24_dmainit(struct sc_info *sc)
2042{
2043	u_int32_t addr;
2044
2045#if(0)
2046	device_printf(sc->dev, "envy24_dmainit()\n");
2047#endif
2048	/* init values */
2049	sc->psize = ENVY24_PLAY_BUFUNIT * ENVY24_SAMPLE_NUM;
2050	sc->rsize = ENVY24_REC_BUFUNIT * ENVY24_SAMPLE_NUM;
2051	sc->pbuf = NULL;
2052	sc->rbuf = NULL;
2053	sc->pmap = sc->rmap = NULL;
2054	sc->blk[0] = sc->blk[1] = 0;
2055
2056	/* allocate DMA buffer */
2057#if(0)
2058	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->pbuf\n");
2059#endif
2060	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap))
2061		goto bad;
2062#if(0)
2063	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->rbuf\n");
2064#endif
2065	if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap))
2066		goto bad;
2067#if(0)
2068	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->pmap\n");
2069#endif
2070	if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24_dmapsetmap, sc, 0))
2071		goto bad;
2072#if(0)
2073	device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->rmap\n");
2074#endif
2075	if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24_dmarsetmap, sc, 0))
2076		goto bad;
2077	bzero(sc->pbuf, sc->psize);
2078	bzero(sc->rbuf, sc->rsize);
2079
2080	/* set values to register */
2081	addr = vtophys(sc->pbuf);
2082#if(0)
2083	device_printf(sc->dev, "pbuf(0x%08x)\n", addr);
2084#endif
2085	envy24_wrmt(sc, ENVY24_MT_PADDR, addr, 4);
2086#if(0)
2087	device_printf(sc->dev, "PADDR-->(0x%08x)\n", envy24_rdmt(sc, ENVY24_MT_PADDR, 4));
2088	device_printf(sc->dev, "psize(%ld)\n", sc->psize / 4 - 1);
2089#endif
2090	envy24_wrmt(sc, ENVY24_MT_PCNT, sc->psize / 4 - 1, 2);
2091#if(0)
2092	device_printf(sc->dev, "PCNT-->(%ld)\n", envy24_rdmt(sc, ENVY24_MT_PCNT, 2));
2093#endif
2094	addr = vtophys(sc->rbuf);
2095	envy24_wrmt(sc, ENVY24_MT_RADDR, addr, 4);
2096	envy24_wrmt(sc, ENVY24_MT_RCNT, sc->rsize / 4 - 1, 2);
2097
2098	return 0;
2099 bad:
2100	envy24_dmafree(sc);
2101	return ENOSPC;
2102}
2103
2104static void
2105envy24_putcfg(struct sc_info *sc)
2106{
2107	device_printf(sc->dev, "system configuration\n");
2108	printf("  SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n",
2109	    sc->cfg->subvendor, sc->cfg->subdevice);
2110	printf("  XIN2 Clock Source: ");
2111	switch (sc->cfg->scfg & PCIM_SCFG_XIN2) {
2112	case 0x00:
2113		printf("22.5792MHz(44.1kHz*512)\n");
2114		break;
2115	case 0x40:
2116		printf("16.9344MHz(44.1kHz*384)\n");
2117		break;
2118	case 0x80:
2119		printf("from external clock synthesizer chip\n");
2120		break;
2121	default:
2122		printf("illeagal system setting\n");
2123	}
2124	printf("  MPU-401 UART(s) #: ");
2125	if (sc->cfg->scfg & PCIM_SCFG_MPU)
2126		printf("2\n");
2127	else
2128		printf("1\n");
2129	printf("  AC'97 codec: ");
2130	if (sc->cfg->scfg & PCIM_SCFG_AC97)
2131		printf("not exist\n");
2132	else
2133		printf("exist\n");
2134	printf("  ADC #: ");
2135	printf("%d\n", sc->adcn);
2136	printf("  DAC #: ");
2137	printf("%d\n", sc->dacn);
2138	printf("  Multi-track converter type: ");
2139	if ((sc->cfg->acl & PCIM_ACL_MTC) == 0) {
2140		printf("AC'97(SDATA_OUT:");
2141		if (sc->cfg->acl & PCIM_ACL_OMODE)
2142			printf("packed");
2143		else
2144			printf("split");
2145		printf("|SDATA_IN:");
2146		if (sc->cfg->acl & PCIM_ACL_IMODE)
2147			printf("packed");
2148		else
2149			printf("split");
2150		printf(")\n");
2151	}
2152	else {
2153		printf("I2S(");
2154		if (sc->cfg->i2s & PCIM_I2S_VOL)
2155			printf("with volume, ");
2156		if (sc->cfg->i2s & PCIM_I2S_96KHZ)
2157			printf("96KHz support, ");
2158		switch (sc->cfg->i2s & PCIM_I2S_RES) {
2159		case PCIM_I2S_16BIT:
2160			printf("16bit resolution, ");
2161			break;
2162		case PCIM_I2S_18BIT:
2163			printf("18bit resolution, ");
2164			break;
2165		case PCIM_I2S_20BIT:
2166			printf("20bit resolution, ");
2167			break;
2168		case PCIM_I2S_24BIT:
2169			printf("24bit resolution, ");
2170			break;
2171		}
2172		printf("ID#0x%x)\n", sc->cfg->i2s & PCIM_I2S_ID);
2173	}
2174	printf("  S/PDIF(IN/OUT): ");
2175	if (sc->cfg->spdif & PCIM_SPDIF_IN)
2176		printf("1/");
2177	else
2178		printf("0/");
2179	if (sc->cfg->spdif & PCIM_SPDIF_OUT)
2180		printf("1 ");
2181	else
2182		printf("0 ");
2183	if (sc->cfg->spdif & (PCIM_SPDIF_IN | PCIM_SPDIF_OUT))
2184		printf("ID# 0x%02x\n", (sc->cfg->spdif & PCIM_SPDIF_ID) >> 2);
2185	printf("  GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n",
2186	    sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate);
2187}
2188
2189static int
2190envy24_init(struct sc_info *sc)
2191{
2192	u_int32_t data;
2193#if(0)
2194	int rtn;
2195#endif
2196	int i;
2197	u_int32_t sv, sd;
2198
2199
2200#if(0)
2201	device_printf(sc->dev, "envy24_init()\n");
2202#endif
2203
2204	/* reset chip */
2205	envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_RESET | ENVY24_CCS_CTL_NATIVE, 1);
2206	DELAY(200);
2207	envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_NATIVE, 1);
2208	DELAY(200);
2209
2210	/* legacy hardware disable */
2211	data = pci_read_config(sc->dev, PCIR_LAC, 2);
2212	data |= PCIM_LAC_DISABLE;
2213	pci_write_config(sc->dev, PCIR_LAC, data, 2);
2214
2215	/* check system configuration */
2216	sc->cfg = NULL;
2217	for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) {
2218		/* 1st: search configuration from table */
2219		sv = pci_get_subvendor(sc->dev);
2220		sd = pci_get_subdevice(sc->dev);
2221		if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) {
2222#if(0)
2223			device_printf(sc->dev, "Set configuration from table\n");
2224#endif
2225			sc->cfg = &cfg_table[i];
2226			break;
2227		}
2228	}
2229	if (sc->cfg == NULL) {
2230		/* 2nd: read configuration from table */
2231		sc->cfg = envy24_rom2cfg(sc);
2232	}
2233	sc->adcn = ((sc->cfg->scfg & PCIM_SCFG_ADC) >> 2) + 1;
2234	sc->dacn = (sc->cfg->scfg & PCIM_SCFG_DAC) + 1;
2235
2236	if (1 /* bootverbose */) {
2237		envy24_putcfg(sc);
2238	}
2239
2240	/* set system configuration */
2241	pci_write_config(sc->dev, PCIR_SCFG, sc->cfg->scfg, 1);
2242	pci_write_config(sc->dev, PCIR_ACL, sc->cfg->acl, 1);
2243	pci_write_config(sc->dev, PCIR_I2S, sc->cfg->i2s, 1);
2244	pci_write_config(sc->dev, PCIR_SPDIF, sc->cfg->spdif, 1);
2245	envy24_gpiosetmask(sc, sc->cfg->gpiomask);
2246	envy24_gpiosetdir(sc, sc->cfg->gpiodir);
2247	envy24_gpiowr(sc, sc->cfg->gpiostate);
2248	for (i = 0; i < sc->adcn; i++) {
2249		sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i);
2250		sc->cfg->codec->init(sc->adc[i]);
2251	}
2252	for (i = 0; i < sc->dacn; i++) {
2253		sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i);
2254		sc->cfg->codec->init(sc->dac[i]);
2255	}
2256
2257	/* initialize DMA buffer */
2258#if(0)
2259	device_printf(sc->dev, "envy24_init(): initialize DMA buffer\n");
2260#endif
2261	if (envy24_dmainit(sc))
2262		return ENOSPC;
2263
2264	/* initialize status */
2265	sc->run[0] = sc->run[1] = 0;
2266	sc->intr[0] = sc->intr[1] = 0;
2267	sc->speed = 0;
2268	sc->caps[0].fmtlist = envy24_playfmt;
2269	sc->caps[1].fmtlist = envy24_recfmt;
2270
2271	/* set channel router */
2272	envy24_route(sc, ENVY24_ROUTE_DAC_1, ENVY24_ROUTE_CLASS_MIX, 0, 0);
2273	envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_DMA, 0, 0);
2274	/* envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_MIX, 0, 0); */
2275
2276	/* set macro interrupt mask */
2277	data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1);
2278	envy24_wrcs(sc, ENVY24_CCS_IMASK, data & ~ENVY24_CCS_IMASK_PMT, 1);
2279	data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1);
2280#if(0)
2281	device_printf(sc->dev, "envy24_init(): CCS_IMASK-->0x%02x\n", data);
2282#endif
2283
2284	return 0;
2285}
2286
2287static int
2288envy24_alloc_resource(struct sc_info *sc)
2289{
2290	/* allocate I/O port resource */
2291	sc->csid = PCIR_CCS;
2292	sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2293	    &sc->csid, 0, ~0, 1, RF_ACTIVE);
2294	sc->ddmaid = PCIR_DDMA;
2295	sc->ddma = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2296	    &sc->ddmaid, 0, ~0, 1, RF_ACTIVE);
2297	sc->dsid = PCIR_DS;
2298	sc->ds = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2299	    &sc->dsid, 0, ~0, 1, RF_ACTIVE);
2300	sc->mtid = PCIR_MT;
2301	sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT,
2302	    &sc->mtid, 0, ~0, 1, RF_ACTIVE);
2303	if (!sc->cs || !sc->ddma || !sc->ds || !sc->mt) {
2304		device_printf(sc->dev, "unable to map IO port space\n");
2305		return ENXIO;
2306	}
2307	sc->cst = rman_get_bustag(sc->cs);
2308	sc->csh = rman_get_bushandle(sc->cs);
2309	sc->ddmat = rman_get_bustag(sc->ddma);
2310	sc->ddmah = rman_get_bushandle(sc->ddma);
2311	sc->dst = rman_get_bustag(sc->ds);
2312	sc->dsh = rman_get_bushandle(sc->ds);
2313	sc->mtt = rman_get_bustag(sc->mt);
2314	sc->mth = rman_get_bushandle(sc->mt);
2315#if(0)
2316	device_printf(sc->dev,
2317	    "IO port register values\nCCS: 0x%lx\nDDMA: 0x%lx\nDS: 0x%lx\nMT: 0x%lx\n",
2318	    pci_read_config(sc->dev, PCIR_CCS, 4),
2319	    pci_read_config(sc->dev, PCIR_DDMA, 4),
2320	    pci_read_config(sc->dev, PCIR_DS, 4),
2321	    pci_read_config(sc->dev, PCIR_MT, 4));
2322#endif
2323
2324	/* allocate interupt resource */
2325	sc->irqid = 0;
2326	sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid,
2327				 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
2328	if (!sc->irq ||
2329	    snd_setup_intr(sc->dev, sc->irq, INTR_MPSAFE, envy24_intr, sc, &sc->ih)) {
2330		device_printf(sc->dev, "unable to map interrupt\n");
2331		return ENXIO;
2332	}
2333
2334	/* allocate DMA resource */
2335	if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/4, /*boundary*/0,
2336	    /*lowaddr*/BUS_SPACE_MAXADDR_ENVY24,
2337	    /*highaddr*/BUS_SPACE_MAXADDR_ENVY24,
2338	    /*filter*/NULL, /*filterarg*/NULL,
2339	    /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24,
2340	    /*nsegments*/1, /*maxsegsz*/0x3ffff,
2341	    /*flags*/0, /*lockfunc*/busdma_lock_mutex,
2342	    /*lockarg*/&Giant, &sc->dmat) != 0) {
2343		device_printf(sc->dev, "unable to create dma tag\n");
2344		return ENXIO;
2345	}
2346
2347	return 0;
2348}
2349
2350static int
2351envy24_pci_attach(device_t dev)
2352{
2353	u_int32_t		data;
2354	struct sc_info 		*sc;
2355	char 			status[SND_STATUSLEN];
2356	char			name[ENVY24_NAMELEN];
2357	int			err = 0;
2358	int			i;
2359
2360#if(0)
2361	device_printf(dev, "envy24_pci_attach()\n");
2362#endif
2363	/* get sc_info data area */
2364	if ((sc = malloc(sizeof(*sc), M_ENVY24, M_NOWAIT)) == NULL) {
2365		device_printf(dev, "cannot allocate softc\n");
2366		return ENXIO;
2367	}
2368
2369	bzero(sc, sizeof(*sc));
2370	snprintf(name, ENVY24_NAMELEN, "%s:envy24", device_get_nameunit(dev));
2371	sc->lock = snd_mtxcreate(name, name);
2372	sc->dev = dev;
2373
2374	/* initialize PCI interface */
2375	data = pci_read_config(dev, PCIR_COMMAND, 2);
2376	data |= (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN);
2377	pci_write_config(dev, PCIR_COMMAND, data, 2);
2378	data = pci_read_config(dev, PCIR_COMMAND, 2);
2379
2380	/* allocate resources */
2381	err = envy24_alloc_resource(sc);
2382	if (err) {
2383		device_printf(dev, "unable to allocate system resources\n");
2384		goto bad;
2385	}
2386
2387	/* initialize card */
2388	err = envy24_init(sc);
2389	if (err) {
2390		device_printf(dev, "unable to initialize the card\n");
2391		goto bad;
2392	}
2393
2394	/* set multi track mixer */
2395	mixer_init(dev, &envy24mixer_class, sc);
2396
2397	/* set channel information */
2398	err = pcm_register(dev, sc, 5, 2 + sc->adcn);
2399	if (err)
2400		goto bad;
2401	sc->chnum = 0;
2402	for (i = 0; i < 5; i++) {
2403		pcm_addchan(dev, PCMDIR_PLAY, &envy24chan_class, sc);
2404		sc->chnum++;
2405	}
2406	for (i = 0; i < 2 + sc->adcn; i++) {
2407		pcm_addchan(dev, PCMDIR_REC, &envy24chan_class, sc);
2408		sc->chnum++;
2409	}
2410
2411	/* set status iformation */
2412	snprintf(status, SND_STATUSLEN,
2413	    "at io 0x%lx:%ld,0x%lx:%ld,0x%lx:%ld,0x%lx:%ld irq %ld",
2414	    rman_get_start(sc->cs),
2415	    rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1,
2416	    rman_get_start(sc->ddma),
2417	    rman_get_end(sc->ddma) - rman_get_start(sc->ddma) + 1,
2418	    rman_get_start(sc->ds),
2419	    rman_get_end(sc->ds) - rman_get_start(sc->ds) + 1,
2420	    rman_get_start(sc->mt),
2421	    rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1,
2422	    rman_get_start(sc->irq));
2423	pcm_setstatus(dev, status);
2424
2425	return 0;
2426
2427bad:
2428	if (sc->ih)
2429		bus_teardown_intr(dev, sc->irq, sc->ih);
2430	if (sc->irq)
2431		bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2432	envy24_dmafree(sc);
2433	if (sc->dmat)
2434		bus_dma_tag_destroy(sc->dmat);
2435	envy24_cfgfree(sc->cfg);
2436	if (sc->cs)
2437		bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2438	if (sc->ddma)
2439		bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma);
2440	if (sc->ds)
2441		bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds);
2442	if (sc->mt)
2443		bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2444	if (sc->lock)
2445		snd_mtxfree(sc->lock);
2446	free(sc, M_ENVY24);
2447	return err;
2448}
2449
2450static int
2451envy24_pci_detach(device_t dev)
2452{
2453	struct sc_info *sc;
2454	int r;
2455	int i;
2456
2457#if(0)
2458	device_printf(dev, "envy24_pci_detach()\n");
2459#endif
2460	sc = pcm_getdevinfo(dev);
2461	if (sc == NULL)
2462		return 0;
2463	r = pcm_unregister(dev);
2464	if (r)
2465		return r;
2466
2467	envy24_dmafree(sc);
2468	if (sc->cfg->codec->destroy != NULL) {
2469		for (i = 0; i < sc->adcn; i++)
2470			sc->cfg->codec->destroy(sc->adc[i]);
2471		for (i = 0; i < sc->dacn; i++)
2472			sc->cfg->codec->destroy(sc->dac[i]);
2473	}
2474	envy24_cfgfree(sc->cfg);
2475	bus_dma_tag_destroy(sc->dmat);
2476	bus_teardown_intr(dev, sc->irq, sc->ih);
2477	bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq);
2478	bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs);
2479	bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma);
2480	bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds);
2481	bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt);
2482	snd_mtxfree(sc->lock);
2483	free(sc, M_ENVY24);
2484	return 0;
2485}
2486
2487static device_method_t envy24_methods[] = {
2488	/* Device interface */
2489	DEVMETHOD(device_probe,		envy24_pci_probe),
2490	DEVMETHOD(device_attach,	envy24_pci_attach),
2491	DEVMETHOD(device_detach,	envy24_pci_detach),
2492	{ 0, 0 }
2493};
2494
2495static driver_t envy24_driver = {
2496	"pcm",
2497	envy24_methods,
2498#if __FreeBSD_version > 500000
2499	PCM_SOFTC_SIZE,
2500#else
2501	sizeof(struct snddev_info),
2502#endif
2503};
2504
2505DRIVER_MODULE(snd_envy24, pci, envy24_driver, pcm_devclass, 0, 0);
2506MODULE_DEPEND(snd_envy24, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
2507MODULE_DEPEND(snd_envy24, snd_ak452x, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER);
2508MODULE_VERSION(snd_envy24, 1);
2509