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